edit.vue 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525
  1. <template>
  2. <view>
  3. <view class="card-wrapper" v-if="showEdit()">
  4. <uni-card title="操作">
  5. <view class="editBtns" slot="actions">
  6. <view class="edit" v-if="!isDetail" @click="onClickProject">
  7. 项目详情
  8. </view>
  9. <view class="edit" v-if="canEdit(0)" @click="onEdit">编辑</view>
  10. <view class="edit" v-if="canEdit(0)" @click="onDelete">删除</view>
  11. <view class="edit" @click="onDaily">项目日志</view>
  12. <view class="edit" v-if="canEdit(0)" @click="onSubmitAuth">
  13. 提交审核
  14. </view>
  15. <view class="edit" v-if="canEdit(1)" @click="onMember">
  16. 成员管理
  17. </view>
  18. <view class="edit" v-if="canEdit(2)" @click="onExecute">
  19. 转执行
  20. </view>
  21. <view class="edit" v-if="canEdit(3)" @click="onWarranty">
  22. 转质保
  23. </view>
  24. <view class="edit" v-if="canEdit(3)" @click="onOperate">
  25. 转运营
  26. </view>
  27. <view class="edit" v-if="canAuth()" @click="onHandleAudit(1)">
  28. 审核通过
  29. </view>
  30. <view class="edit" v-if="canAuth()" @click="onHandleAudit(0)">
  31. 审核拒绝
  32. </view>
  33. <view class="edit empty">
  34. </view>
  35. <view class="edit empty">
  36. </view>
  37. </view>
  38. </uni-card>
  39. </view>
  40. <uni-popup ref="exePopup" type="dialog">
  41. <uni-popup-dialog
  42. title="转执行"
  43. type="info"
  44. @confirm="submitExecute"
  45. @close="onCancel"
  46. before-close
  47. >
  48. <uni-forms
  49. ref="exe"
  50. :modelValue="formData"
  51. label-position="left"
  52. :rules="exeRules"
  53. >
  54. <uni-forms-item required label="执行经理:" name="manager">
  55. <uni-data-picker
  56. class="depSelect"
  57. placeholder="请选择执行经理"
  58. :localdata="depUserTree"
  59. @change="changeManager"
  60. />
  61. </uni-forms-item>
  62. <uni-forms-item required label="合同状态:" name="contract">
  63. <picker
  64. @change="changeContract"
  65. :range="contracts"
  66. :value="formData.contract"
  67. >
  68. <view class="select">{{ contracts[formData.contract] }}</view>
  69. </picker>
  70. </uni-forms-item>
  71. </uni-forms>
  72. </uni-popup-dialog>
  73. </uni-popup>
  74. <uni-popup ref="wtyPopup" type="dialog">
  75. <uni-popup-dialog
  76. title="转质保"
  77. type="info"
  78. @confirm="submitWarranty"
  79. @close="onCancel"
  80. before-close
  81. >
  82. <uni-forms
  83. ref="wty"
  84. :modelValue="formData"
  85. label-position="left"
  86. :rules="wtyRules"
  87. >
  88. <uni-forms-item required label="质保经理:" name="manager">
  89. <uni-data-picker
  90. class="depSelect"
  91. placeholder="请选择质保经理"
  92. :localdata="depUserTree"
  93. @change="changeManager"
  94. />
  95. </uni-forms-item>
  96. </uni-forms>
  97. </uni-popup-dialog>
  98. </uni-popup>
  99. <uni-popup ref="optPopup" type="dialog">
  100. <uni-popup-dialog
  101. title="转运营"
  102. type="info"
  103. @confirm="submitOperate"
  104. @close="onCancel"
  105. before-close
  106. >
  107. <uni-forms
  108. ref="opt"
  109. :modelValue="formData"
  110. label-position="left"
  111. :rules="optRules"
  112. >
  113. <uni-forms-item required label="运营经理:" name="manager">
  114. <uni-data-picker
  115. class="depSelect"
  116. placeholder="请选择运营经理"
  117. :localdata="depUserTree"
  118. @change="changeManager"
  119. />
  120. </uni-forms-item>
  121. </uni-forms>
  122. </uni-popup-dialog>
  123. </uni-popup>
  124. </view>
  125. </template>
  126. <script>
  127. import { mapState } from "vuex";
  128. import {
  129. deleteApproval,
  130. submitAudit,
  131. startExecution,
  132. startWarranty,
  133. startOperate,
  134. authApproval,
  135. } from "@/services/project";
  136. export default {
  137. props: ["project", "user", "auth", "flowList", "depRole", "isDetail"],
  138. computed: {
  139. ...mapState(["depUserTree", "showSearch"]),
  140. },
  141. data() {
  142. return {
  143. contracts: ["无合同", "有合同"],
  144. formData: {
  145. manager: "",
  146. contract: null,
  147. },
  148. exeRules: {
  149. manager: {
  150. rules: [{ required: true, errorMessage: "请选择质保经理" }],
  151. },
  152. contract: {
  153. rules: [{ required: true, errorMessage: "请选择合同状态" }],
  154. },
  155. },
  156. wtyRules: {
  157. manager: {
  158. rules: [{ required: true, errorMessage: "请选择质保经理" }],
  159. },
  160. },
  161. optRules: {
  162. manager: {
  163. rules: [{ required: true, errorMessage: "请选择运营经理" }],
  164. },
  165. },
  166. };
  167. },
  168. methods: {
  169. showEdit() {
  170. let toRet =
  171. !this.isDetail ||
  172. this.canEdit(0) ||
  173. this.canEdit(1) ||
  174. this.canEdit(2) ||
  175. this.canEdit(3) ||
  176. this.canAuth();
  177. this.$emit("canEdit", toRet);
  178. return toRet;
  179. },
  180. onDaily() {
  181. uni.navigateTo({
  182. url: `/pages/daily/projectDaily?project_id=${this.project.id}`,
  183. });
  184. },
  185. hideHelper() {
  186. setTimeout(() => {
  187. uni.hideToast();
  188. if (this.isDetail) uni.navigateBack();
  189. else location.reload();
  190. }, 1800);
  191. },
  192. async onClickProject() {
  193. await this.$store.commit("setCurrentProject", this.project);
  194. uni.navigateTo({
  195. url: `./detail?id=${this.project.id}${this.auth ? "&auth=true" : ""}`,
  196. });
  197. },
  198. canEdit(index) {
  199. if (this.auth) return false;
  200. let {
  201. audit_status,
  202. project_status,
  203. author,
  204. LeaderId,
  205. opt_manager_id,
  206. wty_manager_id,
  207. } = this.project;
  208. //audit_status: 0未提审1审核中2审核拒绝3审核通过
  209. //project_status: 0售前1执行2转运营3转质保
  210. switch (index) {
  211. //编辑删除提审
  212. case 0:
  213. //售前阶段,未提审/审核被拒,创建人/管理员
  214. return (
  215. project_status == 0 &&
  216. (audit_status == 0 || audit_status == 2) &&
  217. (this.user.ID == author || this.user.IsSuper)
  218. );
  219. //成员管理
  220. case 1:
  221. //售前/执行/运营/质保,审核通过,项目经理/管理员
  222. let manager;
  223. switch (project_status) {
  224. case 0:
  225. manager = this.user.ID == author;
  226. break;
  227. case 1:
  228. manager = this.user.ID == LeaderId;
  229. break;
  230. case 2:
  231. manager =
  232. this.user.ID == LeaderId || this.user.ID == opt_manager_id;
  233. break;
  234. case 3:
  235. manager =
  236. this.user.ID == LeaderId || this.user.ID == wty_manager_id;
  237. break;
  238. }
  239. return audit_status == 3 && (manager || this.user.IsSuper);
  240. //转执行
  241. case 2:
  242. //售前,审核通过,售前经理/管理员
  243. return (
  244. project_status == 0 &&
  245. audit_status == 3 &&
  246. (this.user.ID == author || this.user.IsSuper)
  247. );
  248. //转质保运营
  249. case 3:
  250. //执行,审核通过,执行经理/管理员
  251. return (
  252. project_status == 1 &&
  253. audit_status == 3 &&
  254. (this.user.ID == LeaderId || this.user.IsSuper)
  255. );
  256. }
  257. },
  258. async onEdit() {
  259. await this.$store.commit("setCurrentProject", this.project);
  260. uni.navigateTo({
  261. url: `./add?project_id=${this.project.id}`,
  262. });
  263. },
  264. onDelete() {
  265. uni.showModal({
  266. title: "删除项目",
  267. content: "是否确认删除该项目",
  268. confirmText: "删除",
  269. confirmColor: "#ff7875",
  270. success: async (res) => {
  271. if (res.confirm) {
  272. await deleteApproval(this.project);
  273. uni.showToast({
  274. title: "删除成功",
  275. });
  276. this.hideHelper();
  277. }
  278. },
  279. });
  280. },
  281. onSubmitAuth() {
  282. uni.showModal({
  283. title: "提交审核",
  284. content: "是否确认提交审核",
  285. confirmText: "提审",
  286. success: async (res) => {
  287. if (res.confirm) {
  288. let payload = {
  289. id: this.project.id,
  290. flow_id: this.project.flow_id,
  291. node_id: this.project.node_id,
  292. };
  293. await submitAudit(payload);
  294. uni.showToast({
  295. title: "提审成功",
  296. });
  297. this.hideHelper();
  298. }
  299. },
  300. });
  301. },
  302. async onMember() {
  303. await this.$store.commit("setCurrentProject", this.project);
  304. uni.navigateTo({
  305. url: "./member",
  306. });
  307. },
  308. async submitHelper(payload = {}, type) {
  309. const [dep_id, manager_id] = this.formData.manager.split("-");
  310. payload = {
  311. ...payload,
  312. project_code_id: this.project.id,
  313. dep_id: Number(dep_id),
  314. };
  315. switch (type) {
  316. case "exe":
  317. await startExecution(payload);
  318. this.$refs.exePopup.close();
  319. uni.showToast({
  320. title: "转执行送审成功",
  321. });
  322. break;
  323. case "wty":
  324. await startWarranty(payload);
  325. this.$refs.wtyPopup.close();
  326. uni.showToast({
  327. title: "转质保送审成功",
  328. });
  329. break;
  330. case "opt":
  331. await startOperate(payload);
  332. this.$refs.optPopup.close();
  333. uni.showToast({
  334. title: "转运营送审成功",
  335. });
  336. break;
  337. }
  338. this.hideHelper();
  339. },
  340. changeManager(e) {
  341. if (e.detail.value.length > 0)
  342. this.formData.manager = e.detail.value[e.detail.value.length - 1].value;
  343. else this.formData.manager = "";
  344. },
  345. async onExecute() {
  346. await this.$store.commit("setShowSearch", false);
  347. this.$refs.exePopup.open();
  348. },
  349. changeContract(e) {
  350. this.formData.contract = e.detail.value;
  351. },
  352. submitExecute() {
  353. this.$refs.exe.validate((err) => {
  354. if (!err) {
  355. const [dep_id, manager_id] = this.formData.manager.split("-");
  356. let payload = {
  357. with_contract: Number(this.formData.contract),
  358. exe_manager_id: Number(manager_id),
  359. };
  360. this.submitHelper(payload, "exe");
  361. }
  362. });
  363. },
  364. async onWarranty() {
  365. await this.$store.commit("setShowSearch", false);
  366. this.$refs.wtyPopup.open();
  367. },
  368. submitWarranty() {
  369. this.$refs.wty.validate((err) => {
  370. if (!err) {
  371. const [dep_id, manager_id] = this.formData.manager.split("-");
  372. let payload = {
  373. wty_manager_id: Number(manager_id),
  374. };
  375. this.submitHelper(payload, "wty");
  376. }
  377. });
  378. },
  379. async onOperate() {
  380. await this.$store.commit("setShowSearch", false);
  381. this.$refs.optPopup.open();
  382. },
  383. submitOperate() {
  384. this.$refs.opt.validate((err) => {
  385. if (!err) {
  386. const [dep_id, manager_id] = this.formData.manager.split("-");
  387. let payload = {
  388. opt_manager_id: Number(manager_id),
  389. };
  390. this.submitHelper(payload, "opt");
  391. }
  392. });
  393. },
  394. async onCancel() {
  395. await this.$store.commit("setShowSearch", true);
  396. this.$refs.exePopup.close();
  397. this.$refs.wtyPopup.close();
  398. this.$refs.optPopup.close();
  399. this.formData = {
  400. manager: "",
  401. contract: null,
  402. };
  403. },
  404. canAuth() {
  405. if (!this.auth) return false;
  406. let { NodeInfo, audit_status, project_status } = this.project;
  407. if (!NodeInfo || this.flowList.length == 0 || this.depRole.length == 0)
  408. return false;
  409. if (audit_status != 1) return false;
  410. if (project_status == 2)
  411. return this.project.opt_manager_id == this.user.ID;
  412. if (project_status == 3)
  413. return this.project.wty_manager_id == this.user.ID;
  414. let flow = this.flowList.find((item) => item.id == NodeInfo.flow_id);
  415. if (!flow) return false;
  416. let { NodeAudits } = flow.Nodes.find((item) => item.id == NodeInfo.id);
  417. const role = this.depRole.find((item) =>
  418. NodeAudits.find((audit) => audit.audit_role == item.ID)
  419. );
  420. return Boolean(role);
  421. },
  422. onHandleAudit(value) {
  423. if (value) {
  424. uni.showModal({
  425. title: "审批通过",
  426. content: "是否确认通过审批",
  427. confirmText: "通过",
  428. success: async (res) => {
  429. if (res.confirm) {
  430. let payload = {
  431. id: this.project.id,
  432. project_full_code: this.project.project_full_code,
  433. flow_id: this.project.flow_id,
  434. node_id: this.project.node_id,
  435. audit_status: 3,
  436. audit_comment: "",
  437. };
  438. await authApproval(payload);
  439. uni.showToast({
  440. title: "审核成功",
  441. });
  442. this.hideHelper();
  443. }
  444. },
  445. });
  446. } else {
  447. uni.showModal({
  448. title: "是否确认拒绝",
  449. content: "拒绝理由",
  450. editable: true,
  451. success: async (res) => {
  452. if (res.confirm) {
  453. let payload = {
  454. id: this.project.id,
  455. project_full_code: this.project.project_full_code,
  456. flow_id: this.project.flow_id,
  457. node_id: this.project.node_id,
  458. audit_status: 2,
  459. audit_comment: res.content,
  460. };
  461. await authApproval(payload);
  462. uni.showToast({
  463. title: "已拒绝",
  464. });
  465. this.hideHelper();
  466. }
  467. },
  468. });
  469. }
  470. },
  471. },
  472. };
  473. </script>
  474. <style lang="less" scoped>
  475. .editBtns {
  476. display: flex;
  477. justify-content: space-around;
  478. flex-wrap: wrap;
  479. margin: 0 5%;
  480. .edit {
  481. width: 30%;
  482. margin-bottom: 20px;
  483. font-size: 28rpx;
  484. text-align: center;
  485. border-radius: 10rpx;
  486. box-shadow: 0 2rpx 2rpx #666;
  487. &.empty {
  488. visibility: hidden;
  489. height: 1;
  490. margin: 0;
  491. opacity: 0;
  492. }
  493. }
  494. }
  495. .card-wrapper {
  496. padding-bottom: 60rpx;
  497. }
  498. .select {
  499. width: 100%;
  500. height: 72rpx;
  501. line-height: 70rpx;
  502. border: 1px solid #666;
  503. padding-left: 20rpx;
  504. }
  505. ::v-deep {
  506. .uni-steps__column-title {
  507. font-size: 18px;
  508. line-height: 24px;
  509. }
  510. .uni-steps__column-desc {
  511. font-size: 14px;
  512. line-height: 18px;
  513. }
  514. }
  515. .depSelect {
  516. width: 200px;
  517. }
  518. </style>