detail.vue 19 KB

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