detail.vue 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640
  1. <template>
  2. <view class="content">
  3. <view class="title"> 项目详情 </view>
  4. <view class="main">
  5. <view class="list">
  6. <view class="detail">
  7. <span class="subTitle">项目名称:</span>
  8. <span class="detailContent">{{ currentProject.project_name }}</span>
  9. </view>
  10. <view class="detail" v-if="currentProject.TypeInfo">
  11. <span class="subTitle">项目类别:</span>
  12. <span class="detailContent">{{ currentProject.TypeInfo.name }}</span>
  13. </view>
  14. <view class="detail" v-if="currentProject.IndustryInfo">
  15. <span class="subTitle">行业名称:</span>
  16. <span class="detailContent">
  17. {{ currentProject.IndustryInfo.name }}
  18. </span>
  19. </view>
  20. <view class="detail">
  21. <span class="subTitle">流程:</span>
  22. <span class="detailContent">{{ currentProject.FlowInfo.name }}</span>
  23. </view>
  24. <view class="detail">
  25. <span class="subTitle">状态:</span>
  26. <span class="detailContent">
  27. {{ status[currentProject.project_status] }}
  28. </span>
  29. </view>
  30. <view class="detail">
  31. <span class="subTitle">节点:</span>
  32. <span class="detailContent">
  33. {{ `${currentProject.NodeInfo.node}(` }}
  34. <span v-if="currentProject.audit_status == 0">待提交</span>
  35. <span
  36. v-if="currentProject.audit_status == 1"
  37. :style="{ color: '#1890ff' }"
  38. >
  39. 审核中
  40. </span>
  41. <span
  42. v-if="currentProject.audit_status == 2"
  43. :style="{ color: '#f5222d' }"
  44. >
  45. 审核拒绝
  46. </span>
  47. <span
  48. v-if="currentProject.audit_status == 3"
  49. :style="{ color: '#a0d911' }"
  50. >
  51. 审核通过
  52. </span>
  53. <span>)</span>
  54. </span>
  55. </view>
  56. <view class="detail" v-if="currentProject.audit_status == 2">
  57. <span class="subTitle">拒绝原因:</span>
  58. <span class="detailContent">
  59. {{ currentProject.audit_comment }}
  60. </span>
  61. </view>
  62. <view class="detail" v-if="currentProject.location">
  63. <span class="subTitle">项目地区:</span>
  64. <span class="detailContent">
  65. {{ `${currentProject.location}(${currentProject.location_code})` }}
  66. </span>
  67. </view>
  68. <view class="detail" v-if="currentProject.name">
  69. <span class="subTitle">项目简称:</span>
  70. <span class="detailContent">{{ currentProject.name }}</span>
  71. </view>
  72. <view class="detail" v-if="currentProject.version">
  73. <span class="subTitle">项目批次:</span>
  74. <span class="detailContent">{{ currentProject.version }}期</span>
  75. </view>
  76. <view class="detail" v-if="currentProject.AuthorUser">
  77. <span class="subTitle">创建人:</span>
  78. <span class="detailContent">{{
  79. currentProject.AuthorUser.CName
  80. }}</span>
  81. </view>
  82. <view class="detail" v-if="currentProject.AuthorDepInfo">
  83. <span class="subTitle">所属部门:</span>
  84. <span class="detailContent">
  85. {{ currentProject.AuthorDepInfo.Name }}
  86. </span>
  87. </view>
  88. <view class="detail">
  89. <span class="subTitle">项目编号:</span>
  90. <span class="detailContent">
  91. {{ currentProject.project_full_code }}
  92. </span>
  93. </view>
  94. </view>
  95. <view class="title">审核详情 </view>
  96. <view class="list">
  97. <uni-steps
  98. :options="nodeList.list"
  99. :active="nodeList.currentIndex"
  100. direction="column"
  101. />
  102. </view>
  103. <uni-card title="操作" v-if="!this.auth">
  104. <view class="editBtns" slot="actions">
  105. <view class="edit" v-if="canEdit(0)" @click="onEdit()">编辑</view>
  106. <view class="edit" v-if="canEdit(0)" @click="onDelete()">删除</view>
  107. <view class="edit" v-if="canEdit(0)" @click="onSubmitAuth()">
  108. 提交审核
  109. </view>
  110. <view class="edit" v-if="canEdit(1)" @click="onMember()"
  111. >成员管理
  112. </view>
  113. <view class="edit" v-if="canEdit(2)" @click="onExecute()">
  114. 转执行
  115. </view>
  116. <view class="edit" v-if="canEdit(3)" @click="onWarranty()">
  117. 转质保
  118. </view>
  119. <view class="edit" v-if="canEdit(3)" @click="onOperate()">
  120. 转运营
  121. </view>
  122. </view>
  123. </uni-card>
  124. </view>
  125. <view class="group" v-if="this.auth && canAuth()">
  126. <button @click="onHandleAudit(0)" class="commit">审核拒绝</button>
  127. <button @click="onHandleAudit(1)" type="primary" class="commit">
  128. 审核通过
  129. </button>
  130. </view>
  131. <uni-popup ref="exePopup" type="dialog">
  132. <uni-popup-dialog title="转执行" type="info" before-close>
  133. <uni-forms
  134. ref="exe"
  135. :modelValue="formData"
  136. label-position="left"
  137. :rules="exeRules"
  138. >
  139. <uni-forms-item required label="执行经理:" name="manager">
  140. <uni-data-picker
  141. class="depSelect"
  142. placeholder="请选择执行经理"
  143. :localdata="depUserTree"
  144. @change="changeManager"
  145. />
  146. </uni-forms-item>
  147. </uni-forms>
  148. </uni-popup-dialog>
  149. </uni-popup>
  150. <uni-popup ref="wtyPopup" type="dialog">
  151. <uni-popup-dialog
  152. title="转质保"
  153. type="info"
  154. @confirm="submitWarranty"
  155. @close="onCancel"
  156. before-close
  157. >
  158. <uni-forms
  159. ref="wty"
  160. :modelValue="formData"
  161. label-position="left"
  162. :rules="wtyRules"
  163. >
  164. <uni-forms-item required label="质保经理:" name="manager">
  165. <uni-data-picker
  166. class="depSelect"
  167. placeholder="请选择质保经理"
  168. :localdata="depUserTree"
  169. @change="changeManager"
  170. />
  171. </uni-forms-item>
  172. </uni-forms>
  173. </uni-popup-dialog>
  174. </uni-popup>
  175. <uni-popup ref="optPopup" type="dialog">
  176. <uni-popup-dialog
  177. title="转运营"
  178. type="info"
  179. @confirm="submitOperate"
  180. @close="onCancel"
  181. before-close
  182. >
  183. <uni-forms
  184. ref="opt"
  185. :modelValue="formData"
  186. label-position="left"
  187. :rules="optRules"
  188. >
  189. <uni-forms-item required label="运营经理:" name="manager">
  190. <uni-data-picker
  191. class="depSelect"
  192. placeholder="请选择运营经理"
  193. :localdata="depUserTree"
  194. @change="changeManager"
  195. />
  196. </uni-forms-item>
  197. </uni-forms>
  198. </uni-popup-dialog>
  199. </uni-popup>
  200. </view>
  201. </template>
  202. <script>
  203. import { mapState } from "vuex";
  204. import {
  205. queryFlow,
  206. deleteApproval,
  207. submitAudit,
  208. queryUserDetail,
  209. authApproval,
  210. startExecution,
  211. startWarranty,
  212. startOperate,
  213. } from "@/services/project";
  214. import uniFormsItem from "../../uni_modules/uni-forms/components/uni-forms-item/uni-forms-item.vue";
  215. export default {
  216. components: { uniFormsItem },
  217. data() {
  218. return {
  219. auth: false,
  220. status: ["售前", "转执行", "转运营", "转质保"],
  221. flowList: [],
  222. depRole: [],
  223. user: {},
  224. manager: "",
  225. formData: {
  226. manager: "",
  227. contract: 0,
  228. },
  229. exeRules: {
  230. manager: {
  231. rules: [{ required: true, errorMessage: "请选择质保经理" }],
  232. },
  233. },
  234. wtyRules: {
  235. manager: {
  236. rules: [{ required: true, errorMessage: "请选择质保经理" }],
  237. },
  238. },
  239. optRules: {
  240. manager: {
  241. rules: [{ required: true, errorMessage: "请选择运营经理" }],
  242. },
  243. },
  244. };
  245. },
  246. computed: {
  247. ...mapState(["currentProject", "depUserTree"]),
  248. nodeList() {
  249. if (!this.flowList) return [];
  250. let flowInfo = this.flowList.find(
  251. (item) => item.id == this.currentProject.flow_id
  252. );
  253. if (!flowInfo) return [];
  254. let currentIndex = flowInfo.Nodes.findIndex(
  255. (item) => item.id == this.currentProject.node_id
  256. );
  257. return {
  258. currentIndex,
  259. list: flowInfo.Nodes.map((item) => ({
  260. title: item.node,
  261. desc: `审批人:${this.getAudits(item)}`,
  262. })),
  263. };
  264. },
  265. },
  266. onLoad(options) {
  267. this.auth = Boolean(options.auth);
  268. this.init();
  269. },
  270. methods: {
  271. async init() {
  272. this.user = uni.getStorageSync("user");
  273. let res;
  274. res = await queryFlow();
  275. this.flowList = res.data;
  276. res = await queryUserDetail(this.user);
  277. let depId = this.user.DepId;
  278. let dep = res.data.Dep.find((item) => item.ID == depId);
  279. this.depRole = dep.Role;
  280. },
  281. canAuth() {
  282. let { NodeInfo, audit_status, project_status } = this.currentProject;
  283. if (!NodeInfo || this.flowList.length == 0 || this.depRole.length == 0)
  284. return false;
  285. if (audit_status != 1) return false;
  286. if (project_status == 2)
  287. return this.currentProject.opt_manager_id == this.user.ID;
  288. if (project_status == 3)
  289. return this.currentProject.wty_manager_id == this.user.ID;
  290. let flow = this.flowList.find((item) => item.id == NodeInfo.flow_id);
  291. if (!flow) return false;
  292. let { NodeAudits } = flow.Nodes.find((item) => item.id == NodeInfo.id);
  293. const role = this.depRole.find((item) =>
  294. NodeAudits.find((audit) => audit.audit_role == item.ID)
  295. );
  296. return Boolean(role);
  297. },
  298. onHandleAudit(value) {
  299. if (value) {
  300. uni.showModal({
  301. title: "审批通过",
  302. content: "是否确认通过审批",
  303. confirmText: "通过",
  304. success: async (res) => {
  305. if (res.confirm) {
  306. let payload = {
  307. id: this.currentProject.id,
  308. project_full_code: this.currentProject.project_full_code,
  309. flow_id: this.currentProject.flow_id,
  310. node_id: this.currentProject.node_id,
  311. audit_status: 3,
  312. audit_comment: "",
  313. };
  314. await authApproval(payload);
  315. uni.showToast({
  316. title: "审核成功",
  317. });
  318. setTimeout(function () {
  319. uni.hideToast();
  320. uni.navigateTo({
  321. url: "./auth",
  322. });
  323. }, 1800);
  324. }
  325. },
  326. });
  327. } else {
  328. uni.showModal({
  329. title: "是否确认拒绝",
  330. content: "拒绝理由",
  331. editable: true,
  332. success: async (res) => {
  333. if (res.confirm) {
  334. let payload = {
  335. id: this.currentProject.id,
  336. project_full_code: this.currentProject.project_full_code,
  337. flow_id: this.currentProject.flow_id,
  338. node_id: this.currentProject.node_id,
  339. audit_status: 2,
  340. audit_comment: res.content,
  341. };
  342. await authApproval(payload);
  343. uni.showToast({
  344. title: "已拒绝",
  345. });
  346. setTimeout(function () {
  347. uni.hideToast();
  348. uni.navigateTo({
  349. url: "./auth",
  350. });
  351. }, 1800);
  352. }
  353. },
  354. });
  355. }
  356. },
  357. getAudits(nodeInfo) {
  358. switch (nodeInfo.id) {
  359. case 11:
  360. return "执行项目经理";
  361. case 12:
  362. return "运营经理";
  363. case 13:
  364. return "执行项目经理";
  365. case 14:
  366. return "质保经理";
  367. default:
  368. return (nodeInfo.NodeAudits || [])
  369. .map((item) => item.AuthorRoleInfo.Name)
  370. .join(",");
  371. }
  372. },
  373. canEdit(index) {
  374. let {
  375. audit_status,
  376. project_status,
  377. author,
  378. LeaderId,
  379. opt_manager_id,
  380. wty_manager_id,
  381. } = this.currentProject;
  382. //audit_status: 0未提审1审核中2审核拒绝3审核通过
  383. //project_status: 0售前1执行2转运营3转质保
  384. switch (index) {
  385. //编辑删除提审
  386. case 0:
  387. //售前阶段,未提审/审核被拒,创建人/管理员
  388. return (
  389. project_status == 0 &&
  390. (audit_status == 0 || audit_status == 2) &&
  391. (this.user.ID == author || this.user.IsSuper)
  392. );
  393. //成员管理
  394. case 1:
  395. //售前/执行/运营/质保,审核通过,项目经理/管理员
  396. let manager;
  397. switch (project_status) {
  398. case 0:
  399. manager = author;
  400. break;
  401. case 1:
  402. manager = LeaderId;
  403. break;
  404. case 2:
  405. manager = opt_manager_id;
  406. break;
  407. case 3:
  408. manager = wty_manager_id;
  409. break;
  410. }
  411. return (
  412. audit_status == 3 && (this.user.ID == manager || this.user.IsSuper)
  413. );
  414. //转执行
  415. case 2:
  416. //售前,审核通过,售前经理/管理员
  417. return (
  418. project_status == 0 &&
  419. audit_status == 3 &&
  420. (this.user.ID == author || this.user.IsSuper)
  421. );
  422. //转质保运营
  423. case 3:
  424. //执行,审核通过,执行经理/管理员
  425. return (
  426. project_status == 1 &&
  427. audit_status == 3 &&
  428. (this.user.ID == LeaderId || this.user.IsSuper)
  429. );
  430. }
  431. },
  432. onEdit() {
  433. uni.navigateTo({
  434. url: `./add?project_id=${this.currentProject.id}`,
  435. });
  436. },
  437. onDelete() {
  438. uni.showModal({
  439. title: "删除项目",
  440. content: "是否确认删除该项目",
  441. confirmText: "删除",
  442. confirmColor: "#ff7875",
  443. success: async (res) => {
  444. if (res.confirm) {
  445. await deleteApproval(this.currentProject);
  446. uni.showToast({
  447. title: "删除成功",
  448. });
  449. setTimeout(function () {
  450. uni.hideToast();
  451. uni.navigateTo({
  452. url: "./list",
  453. });
  454. }, 1800);
  455. }
  456. },
  457. });
  458. },
  459. onSubmitAuth() {
  460. uni.showModal({
  461. title: "提交审核",
  462. content: "是否确认提交审核",
  463. confirmText: "提审",
  464. success: async (res) => {
  465. if (res.confirm) {
  466. let payload = {
  467. id: this.currentProject.id,
  468. flow_id: this.currentProject.flow_id,
  469. node_id: this.currentProject.node_id,
  470. };
  471. await submitAudit(payload);
  472. uni.showToast({
  473. title: "提审成功",
  474. });
  475. setTimeout(function () {
  476. uni.hideToast();
  477. uni.navigateTo({
  478. url: "./list",
  479. });
  480. }, 1800);
  481. }
  482. },
  483. });
  484. },
  485. onMember() {
  486. uni.navigateTo({
  487. url: "./member",
  488. });
  489. },
  490. changeManager(e) {
  491. this.formData.manager = e.detail.value[e.detail.value.length - 1].value;
  492. },
  493. onExecute() {
  494. this.$refs.exePopup.open();
  495. return;
  496. },
  497. onWarranty() {
  498. this.$refs.wtyPopup.open();
  499. return;
  500. },
  501. async submitWarranty() {
  502. this.$refs.wty.validate(async (err) => {
  503. if (!err) {
  504. const [dep_id, manager_id] = this.formData.manager.split("-");
  505. let payload = {
  506. project_code_id: this.currentProject.id,
  507. dep_id: Number(dep_id),
  508. wty_manager_id: Number(manager_id),
  509. };
  510. await startWarranty(payload);
  511. this.$refs.wtyPopup.close();
  512. uni.showToast({
  513. title: "转质保送审成功",
  514. });
  515. setTimeout(function () {
  516. uni.hideToast();
  517. uni.navigateTo({
  518. url: "./list",
  519. });
  520. }, 1800);
  521. }
  522. });
  523. },
  524. onOperate() {
  525. this.$refs.optPopup.open();
  526. return;
  527. },
  528. async submitOperate() {
  529. this.$refs.opt.validate(async (err) => {
  530. if (!err) {
  531. const [dep_id, manager_id] = this.formData.manager.split("-");
  532. let payload = {
  533. project_code_id: this.currentProject.id,
  534. dep_id: Number(dep_id),
  535. opt_manager_id: Number(manager_id),
  536. };
  537. await startOperate(payload);
  538. this.$refs.optPopup.close();
  539. uni.showToast({
  540. title: "转运营送审成功",
  541. });
  542. setTimeout(function () {
  543. uni.hideToast();
  544. uni.navigateTo({
  545. url: "./list",
  546. });
  547. }, 1800);
  548. }
  549. });
  550. },
  551. onCancel() {
  552. this.$refs.exePopup.close();
  553. this.$refs.wtyPopup.close();
  554. this.$refs.optPopup.close();
  555. },
  556. },
  557. };
  558. </script>
  559. <style lang="less" scoped>
  560. .content {
  561. display: flex;
  562. flex-wrap: wrap;
  563. }
  564. .main {
  565. width: 100%;
  566. padding-bottom: 60px;
  567. }
  568. .title {
  569. width: 100%;
  570. padding: 0 20px 20px 20px;
  571. font: 24px bold;
  572. }
  573. .list {
  574. margin: 0 10% 20px 10%;
  575. }
  576. .detail {
  577. width: 100%;
  578. padding: 15px 0;
  579. font-size: 18px;
  580. display: flex;
  581. justify-items: space-between;
  582. .subTitle {
  583. width: 30%;
  584. }
  585. .detailContent {
  586. width: 70%;
  587. }
  588. }
  589. ::v-deep {
  590. .uni-steps__column-title {
  591. font-size: 18px;
  592. line-height: 24px;
  593. }
  594. .uni-steps__column-desc {
  595. font-size: 14px;
  596. line-height: 18px;
  597. }
  598. }
  599. .editBtns {
  600. display: flex;
  601. justify-content: space-around;
  602. flex-wrap: wrap;
  603. margin: 0 5%;
  604. .edit {
  605. width: 30%;
  606. margin-bottom: 20px;
  607. font-size: 16px;
  608. text-align: center;
  609. }
  610. }
  611. .group {
  612. width: 100%;
  613. display: flex;
  614. position: fixed;
  615. flex-wrap: wrap;
  616. justify-content: flex-start;
  617. bottom: 0;
  618. left: 0;
  619. .commit {
  620. width: 50%;
  621. border-radius: 0;
  622. margin: inherit;
  623. }
  624. }
  625. .depSelect {
  626. width: 200px;
  627. }
  628. </style>