detail.vue 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683
  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
  133. title="转执行"
  134. type="info"
  135. @confirm="submitExecute"
  136. @close="onCancel"
  137. before-close
  138. >
  139. <uni-forms
  140. ref="exe"
  141. :modelValue="formData"
  142. label-position="left"
  143. :rules="exeRules"
  144. >
  145. <uni-forms-item required label="执行经理:" name="manager">
  146. <uni-data-picker
  147. class="depSelect"
  148. placeholder="请选择执行经理"
  149. :localdata="depUserTree"
  150. @change="changeManager"
  151. />
  152. </uni-forms-item>
  153. <uni-forms-item required label="合同状态:" name="contract">
  154. <picker
  155. @change="changeContract"
  156. :range="contracts"
  157. :value="formData.contract"
  158. >
  159. <view class="select">{{ contracts[formData.contract] }}</view>
  160. </picker>
  161. </uni-forms-item>
  162. </uni-forms>
  163. </uni-popup-dialog>
  164. </uni-popup>
  165. <uni-popup ref="wtyPopup" type="dialog">
  166. <uni-popup-dialog
  167. title="转质保"
  168. type="info"
  169. @confirm="submitWarranty"
  170. @close="onCancel"
  171. before-close
  172. >
  173. <uni-forms
  174. ref="wty"
  175. :modelValue="formData"
  176. label-position="left"
  177. :rules="wtyRules"
  178. >
  179. <uni-forms-item required label="质保经理:" name="manager">
  180. <uni-data-picker
  181. class="depSelect"
  182. placeholder="请选择质保经理"
  183. :localdata="depUserTree"
  184. @change="changeManager"
  185. />
  186. </uni-forms-item>
  187. </uni-forms>
  188. </uni-popup-dialog>
  189. </uni-popup>
  190. <uni-popup ref="optPopup" type="dialog">
  191. <uni-popup-dialog
  192. title="转运营"
  193. type="info"
  194. @confirm="submitOperate"
  195. @close="onCancel"
  196. before-close
  197. >
  198. <uni-forms
  199. ref="opt"
  200. :modelValue="formData"
  201. label-position="left"
  202. :rules="optRules"
  203. >
  204. <uni-forms-item required label="运营经理:" name="manager">
  205. <uni-data-picker
  206. class="depSelect"
  207. placeholder="请选择运营经理"
  208. :localdata="depUserTree"
  209. @change="changeManager"
  210. />
  211. </uni-forms-item>
  212. </uni-forms>
  213. </uni-popup-dialog>
  214. </uni-popup>
  215. </view>
  216. </template>
  217. <script>
  218. import { mapState } from "vuex";
  219. import {
  220. queryFlow,
  221. deleteApproval,
  222. submitAudit,
  223. queryUserDetail,
  224. authApproval,
  225. startExecution,
  226. startWarranty,
  227. startOperate,
  228. } from "@/services/project";
  229. import uniFormsItem from "../../uni_modules/uni-forms/components/uni-forms-item/uni-forms-item.vue";
  230. const contracts = ["无合同", "有合同"];
  231. export default {
  232. components: { uniFormsItem },
  233. data() {
  234. return {
  235. auth: false,
  236. status: ["售前", "转执行", "转运营", "转质保"],
  237. flowList: [],
  238. depRole: [],
  239. user: {},
  240. manager: "",
  241. contracts,
  242. formData: {
  243. manager: "",
  244. contract: null,
  245. },
  246. exeRules: {
  247. manager: {
  248. rules: [{ required: true, errorMessage: "请选择质保经理" }],
  249. },
  250. contract: {
  251. rules: [{ required: true, errorMessage: "请选择合同状态" }],
  252. },
  253. },
  254. wtyRules: {
  255. manager: {
  256. rules: [{ required: true, errorMessage: "请选择质保经理" }],
  257. },
  258. },
  259. optRules: {
  260. manager: {
  261. rules: [{ required: true, errorMessage: "请选择运营经理" }],
  262. },
  263. },
  264. };
  265. },
  266. computed: {
  267. ...mapState(["currentProject", "depUserTree"]),
  268. nodeList() {
  269. if (!this.flowList) return [];
  270. let flowInfo = this.flowList.find(
  271. (item) => item.id == this.currentProject.flow_id
  272. );
  273. if (!flowInfo) return [];
  274. let currentIndex = flowInfo.Nodes.findIndex(
  275. (item) => item.id == this.currentProject.node_id
  276. );
  277. return {
  278. currentIndex,
  279. list: flowInfo.Nodes.map((item) => ({
  280. title: item.node,
  281. desc: `审批人:${this.getAudits(item)}`,
  282. })),
  283. };
  284. },
  285. },
  286. onLoad(options) {
  287. this.auth = Boolean(options.auth);
  288. this.init();
  289. },
  290. methods: {
  291. async init() {
  292. this.user = uni.getStorageSync("user");
  293. let res;
  294. res = await queryFlow();
  295. this.flowList = res.data;
  296. res = await queryUserDetail(this.user);
  297. let depId = this.user.DepId;
  298. let dep = res.data.Dep.find((item) => item.ID == depId);
  299. this.depRole = dep.Role;
  300. },
  301. canAuth() {
  302. let { NodeInfo, audit_status, project_status } = this.currentProject;
  303. if (!NodeInfo || this.flowList.length == 0 || this.depRole.length == 0)
  304. return false;
  305. if (audit_status != 1) return false;
  306. if (project_status == 2)
  307. return this.currentProject.opt_manager_id == this.user.ID;
  308. if (project_status == 3)
  309. return this.currentProject.wty_manager_id == this.user.ID;
  310. let flow = this.flowList.find((item) => item.id == NodeInfo.flow_id);
  311. if (!flow) return false;
  312. let { NodeAudits } = flow.Nodes.find((item) => item.id == NodeInfo.id);
  313. const role = this.depRole.find((item) =>
  314. NodeAudits.find((audit) => audit.audit_role == item.ID)
  315. );
  316. return Boolean(role);
  317. },
  318. onHandleAudit(value) {
  319. if (value) {
  320. uni.showModal({
  321. title: "审批通过",
  322. content: "是否确认通过审批",
  323. confirmText: "通过",
  324. success: async (res) => {
  325. if (res.confirm) {
  326. let payload = {
  327. id: this.currentProject.id,
  328. project_full_code: this.currentProject.project_full_code,
  329. flow_id: this.currentProject.flow_id,
  330. node_id: this.currentProject.node_id,
  331. audit_status: 3,
  332. audit_comment: "",
  333. };
  334. await authApproval(payload);
  335. uni.showToast({
  336. title: "审核成功",
  337. });
  338. setTimeout(function () {
  339. uni.hideToast();
  340. uni.navigateBack();
  341. }, 1800);
  342. }
  343. },
  344. });
  345. } else {
  346. uni.showModal({
  347. title: "是否确认拒绝",
  348. content: "拒绝理由",
  349. editable: true,
  350. success: async (res) => {
  351. if (res.confirm) {
  352. let payload = {
  353. id: this.currentProject.id,
  354. project_full_code: this.currentProject.project_full_code,
  355. flow_id: this.currentProject.flow_id,
  356. node_id: this.currentProject.node_id,
  357. audit_status: 2,
  358. audit_comment: res.content,
  359. };
  360. await authApproval(payload);
  361. uni.showToast({
  362. title: "已拒绝",
  363. });
  364. setTimeout(function () {
  365. uni.hideToast();
  366. uni.navigateBack();
  367. }, 1800);
  368. }
  369. },
  370. });
  371. }
  372. },
  373. getAudits(nodeInfo) {
  374. switch (nodeInfo.id) {
  375. case 11:
  376. return "执行项目经理";
  377. case 12:
  378. return "运营经理";
  379. case 13:
  380. return "执行项目经理";
  381. case 14:
  382. return "质保经理";
  383. default:
  384. return (nodeInfo.NodeAudits || [])
  385. .map((item) => item.AuthorRoleInfo.Name)
  386. .join(",");
  387. }
  388. },
  389. canEdit(index) {
  390. let {
  391. audit_status,
  392. project_status,
  393. author,
  394. LeaderId,
  395. opt_manager_id,
  396. wty_manager_id,
  397. } = this.currentProject;
  398. //audit_status: 0未提审1审核中2审核拒绝3审核通过
  399. //project_status: 0售前1执行2转运营3转质保
  400. switch (index) {
  401. //编辑删除提审
  402. case 0:
  403. //售前阶段,未提审/审核被拒,创建人/管理员
  404. return (
  405. project_status == 0 &&
  406. (audit_status == 0 || audit_status == 2) &&
  407. (this.user.ID == author || this.user.IsSuper)
  408. );
  409. //成员管理
  410. case 1:
  411. //售前/执行/运营/质保,审核通过,项目经理/管理员
  412. let manager;
  413. switch (project_status) {
  414. case 0:
  415. manager == author;
  416. break;
  417. case 1:
  418. manager == LeaderId;
  419. break;
  420. case 2:
  421. manager == LeaderId || manager == opt_manager_id;
  422. break;
  423. case 3:
  424. manager == LeaderId || manager == wty_manager_id;
  425. break;
  426. }
  427. return (
  428. audit_status == 3 && (this.user.ID == manager || this.user.IsSuper)
  429. );
  430. //转执行
  431. case 2:
  432. //售前,审核通过,售前经理/管理员
  433. return (
  434. project_status == 0 &&
  435. audit_status == 3 &&
  436. (this.user.ID == author || this.user.IsSuper)
  437. );
  438. //转质保运营
  439. case 3:
  440. //执行,审核通过,执行经理/管理员
  441. return (
  442. project_status == 1 &&
  443. audit_status == 3 &&
  444. (this.user.ID == LeaderId || this.user.IsSuper)
  445. );
  446. }
  447. },
  448. onEdit() {
  449. uni.navigateTo({
  450. url: `./add?project_id=${this.currentProject.id}`,
  451. });
  452. },
  453. onDelete() {
  454. uni.showModal({
  455. title: "删除项目",
  456. content: "是否确认删除该项目",
  457. confirmText: "删除",
  458. confirmColor: "#ff7875",
  459. success: async (res) => {
  460. if (res.confirm) {
  461. await deleteApproval(this.currentProject);
  462. uni.showToast({
  463. title: "删除成功",
  464. });
  465. setTimeout(function () {
  466. uni.hideToast();
  467. uni.navigateBack();
  468. }, 1800);
  469. }
  470. },
  471. });
  472. },
  473. onSubmitAuth() {
  474. uni.showModal({
  475. title: "提交审核",
  476. content: "是否确认提交审核",
  477. confirmText: "提审",
  478. success: async (res) => {
  479. if (res.confirm) {
  480. let payload = {
  481. id: this.currentProject.id,
  482. flow_id: this.currentProject.flow_id,
  483. node_id: this.currentProject.node_id,
  484. };
  485. await submitAudit(payload);
  486. uni.showToast({
  487. title: "提审成功",
  488. });
  489. setTimeout(function () {
  490. uni.hideToast();
  491. uni.navigateBack();
  492. }, 1800);
  493. }
  494. },
  495. });
  496. },
  497. onMember() {
  498. uni.navigateTo({
  499. url: "./member",
  500. });
  501. },
  502. changeManager(e) {
  503. if (e.detail.value.length > 0)
  504. this.formData.manager = e.detail.value[e.detail.value.length - 1].value;
  505. else this.formData.manager = "";
  506. },
  507. onExecute() {
  508. this.$refs.exePopup.open();
  509. },
  510. changeContract(e) {
  511. this.formData.contract = e.detail.value;
  512. },
  513. async submitExecute() {
  514. this.$refs.exe.validate(async (err) => {
  515. if (!err) {
  516. const [dep_id, manager_id] = this.formData.manager.split("-");
  517. let payload = {
  518. project_code_id: this.currentProject.id,
  519. with_contract: Number(this.formData.contract),
  520. dep_id: Number(dep_id),
  521. exe_manager_id: Number(manager_id),
  522. };
  523. await startExecution(payload);
  524. this.$refs.exePopup.close();
  525. uni.showToast({
  526. title: "转执行送审成功",
  527. });
  528. setTimeout(function () {
  529. uni.hideToast();
  530. uni.navigateBack();
  531. }, 1800);
  532. }
  533. });
  534. },
  535. onWarranty() {
  536. this.$refs.wtyPopup.open();
  537. },
  538. async submitWarranty() {
  539. this.$refs.wty.validate(async (err) => {
  540. if (!err) {
  541. const [dep_id, manager_id] = this.formData.manager.split("-");
  542. let payload = {
  543. project_code_id: this.currentProject.id,
  544. dep_id: Number(dep_id),
  545. wty_manager_id: Number(manager_id),
  546. };
  547. await startWarranty(payload);
  548. this.$refs.wtyPopup.close();
  549. uni.showToast({
  550. title: "转质保送审成功",
  551. });
  552. setTimeout(function () {
  553. uni.hideToast();
  554. uni.navigateBack();
  555. }, 1800);
  556. }
  557. });
  558. },
  559. onOperate() {
  560. this.$refs.optPopup.open();
  561. },
  562. async submitOperate() {
  563. this.$refs.opt.validate(async (err) => {
  564. if (!err) {
  565. const [dep_id, manager_id] = this.formData.manager.split("-");
  566. let payload = {
  567. project_code_id: this.currentProject.id,
  568. dep_id: Number(dep_id),
  569. opt_manager_id: Number(manager_id),
  570. };
  571. await startOperate(payload);
  572. this.$refs.optPopup.close();
  573. uni.showToast({
  574. title: "转运营送审成功",
  575. });
  576. setTimeout(function () {
  577. uni.hideToast();
  578. uni.navigateBack();
  579. }, 1800);
  580. }
  581. });
  582. },
  583. onCancel() {
  584. this.$refs.exePopup.close();
  585. this.$refs.wtyPopup.close();
  586. this.$refs.optPopup.close();
  587. this.formData = {
  588. manager: "",
  589. contract: null,
  590. };
  591. },
  592. },
  593. };
  594. </script>
  595. <style lang="less" scoped>
  596. .content {
  597. display: flex;
  598. flex-wrap: wrap;
  599. }
  600. .main {
  601. width: 100%;
  602. padding-bottom: 60px;
  603. }
  604. .title {
  605. width: 100%;
  606. padding: 0 20px 20px 20px;
  607. font: 24px bold;
  608. }
  609. .list {
  610. margin: 0 10% 20px 10%;
  611. }
  612. .detail {
  613. width: 100%;
  614. padding: 15px 0;
  615. font-size: 18px;
  616. display: flex;
  617. justify-items: space-between;
  618. .subTitle {
  619. width: 30%;
  620. }
  621. .detailContent {
  622. width: 70%;
  623. }
  624. }
  625. .select {
  626. width: 100%;
  627. height: 72rpx;
  628. line-height: 70rpx;
  629. border: 1px solid #666;
  630. padding-left: 20rpx;
  631. }
  632. ::v-deep {
  633. .uni-steps__column-title {
  634. font-size: 18px;
  635. line-height: 24px;
  636. }
  637. .uni-steps__column-desc {
  638. font-size: 14px;
  639. line-height: 18px;
  640. }
  641. }
  642. .editBtns {
  643. display: flex;
  644. justify-content: space-around;
  645. flex-wrap: wrap;
  646. margin: 0 5%;
  647. .edit {
  648. width: 30%;
  649. margin-bottom: 20px;
  650. font-size: 16px;
  651. text-align: center;
  652. }
  653. }
  654. .group {
  655. width: 100%;
  656. display: flex;
  657. position: fixed;
  658. flex-wrap: wrap;
  659. justify-content: flex-start;
  660. bottom: 0;
  661. left: 0;
  662. .commit {
  663. width: 50%;
  664. border-radius: 0;
  665. margin: inherit;
  666. }
  667. }
  668. .depSelect {
  669. width: 200px;
  670. }
  671. </style>