index.vue 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627
  1. <template>
  2. <el-dialog
  3. title="处理"
  4. :before-close="handleClose"
  5. :visible.sync="dialogVisible"
  6. :close-on-click-modal="false"
  7. :append-to-body="true"
  8. width="80%"
  9. >
  10. <div class="app-container">
  11. <!-- 申请信息 -->
  12. <el-card class="box-card" v-loading="processInstanceLoading">
  13. <div slot="header" class="clearfix">
  14. <span class="el-icon-document"
  15. >申请信息【{{ processInstance.name }}】 申请人:【{{
  16. processInstance.startUser?.nickname
  17. }}】</span
  18. >
  19. </div>
  20. <div v-if="processInstance.processDefinition">
  21. <async-biz-form-component
  22. :taskId="listData?.taskId"
  23. :businessId="listData?.businessId"
  24. :id="listData?.id"
  25. :taskDefinitionKey="listData?.taskDefinitionKey"
  26. @activeCompChange="activeCompChange"
  27. @handleClose="handleClose"
  28. ref="bziRef"
  29. ></async-biz-form-component>
  30. </div>
  31. </el-card>
  32. <!-- 审批信息 -->
  33. <el-card
  34. class="box-card"
  35. v-loading="processInstanceLoading"
  36. v-for="(item, index) in runningTasks"
  37. :key="index"
  38. >
  39. <div slot="header" class="clearfix">
  40. <span class="el-icon-picture-outline">审批任务</span>
  41. </div>
  42. <div v-if="processInstance.processDefinition">
  43. <async-sub-form-component
  44. :taskId="listData?.taskId"
  45. :businessId="listData?.businessId"
  46. :id="listData?.id"
  47. :taskDefinitionKey="listData?.taskDefinitionKey"
  48. @handleAudit="handleAudit"
  49. @getTableValue="getTableValue"
  50. @getReturnStorage="getReturnStorage"
  51. @handleUpdateAssignee="handleUpdateAssignee(item)"
  52. @handleBackList="handleBackList(item)"
  53. @submit="submit"
  54. ref="subForm"
  55. ></async-sub-form-component>
  56. </div>
  57. <!-- <el-col :span="16" :offset="6">
  58. <el-form
  59. :ref="'form' + index"
  60. :model="auditForms[index]"
  61. :rules="auditRule"
  62. label-width="100px"
  63. >
  64. <el-form-item
  65. label="审批建议"
  66. prop="reason"
  67. style="margin-bottom: 20px"
  68. >
  69. <el-input
  70. type="textarea"
  71. v-model="auditForms[index].reason"
  72. placeholder="请输入审批建议"
  73. />
  74. </el-form-item>
  75. </el-form>
  76. <div style="margin-left: 10%; margin-bottom: 20px; font-size: 14px">
  77. <el-button
  78. icon="el-icon-edit-outline"
  79. type="success"
  80. size="mini"
  81. @click="handleAudit(item, true)"
  82. >通过
  83. </el-button>
  84. <el-button
  85. icon="el-icon-circle-close"
  86. type="danger"
  87. size="mini"
  88. @click="handleAudit(item, false)"
  89. >不通过
  90. </el-button>
  91. <el-button
  92. icon="el-icon-edit-outline"
  93. type="primary"
  94. size="mini"
  95. @click="handleUpdateAssignee(item)"
  96. >转办
  97. </el-button>
  98. <el-button
  99. icon="el-icon-edit-outline"
  100. type="primary"
  101. size="mini"
  102. @click="handleDelegate(item)"
  103. >委派
  104. </el-button>
  105. <el-button
  106. icon="el-icon-refresh-left"
  107. type="warning"
  108. size="mini"
  109. @click="handleBackList(item)"
  110. >退回
  111. </el-button>
  112. </div>
  113. </el-col> -->
  114. </el-card>
  115. <!-- 对话框(转办审批人) -->
  116. <el-dialog
  117. title="转办审批人"
  118. :visible.sync="updateAssignee.open"
  119. width="500px"
  120. append-to-body
  121. >
  122. <el-form
  123. ref="updateAssigneeForm"
  124. :model="updateAssignee.form"
  125. :rules="updateAssignee.rules"
  126. label-width="110px"
  127. >
  128. <el-form-item label="新审批人" prop="assigneeUserId">
  129. <el-select
  130. v-model="updateAssignee.form.assigneeUserId"
  131. clearable
  132. style="width: 100%"
  133. :filterable="true"
  134. >
  135. <el-option
  136. v-for="item in userOptions"
  137. :key="item.id"
  138. :label="item.name"
  139. :value="item.id"
  140. />
  141. </el-select>
  142. </el-form-item>
  143. </el-form>
  144. <div slot="footer" class="dialog-footer">
  145. <el-button type="primary" @click="submitUpdateAssigneeForm"
  146. >确 定</el-button
  147. >
  148. <el-button @click="cancelUpdateAssigneeForm">取 消</el-button>
  149. </div>
  150. </el-dialog>
  151. <!-- 对话框(委派审批人) -->
  152. <el-dialog
  153. title="委派审批人"
  154. :visible.sync="updateDelegate.open"
  155. width="500px"
  156. append-to-body
  157. >
  158. <el-form
  159. ref="updateDelegateForm"
  160. :model="updateDelegate.form"
  161. :rules="updateDelegate.rules"
  162. label-width="110px"
  163. >
  164. <el-form-item label="新审批人" prop="assigneeUserId">
  165. <el-select
  166. v-model="updateDelegate.form.delegateUserId"
  167. clearable
  168. style="width: 100%"
  169. :filterable="true"
  170. >
  171. <el-option
  172. v-for="item in userOptions"
  173. :key="item.id"
  174. :label="item.name"
  175. :value="item.id"
  176. />
  177. </el-select>
  178. </el-form-item>
  179. <el-form-item label="委派理由" prop="reason">
  180. <el-input
  181. v-model="updateDelegate.form.reason"
  182. clearable
  183. placeholder="请输入委派理由"
  184. />
  185. </el-form-item>
  186. </el-form>
  187. <div slot="footer" class="dialog-footer">
  188. <el-button type="primary" @click="submitUpdateDelegateForm"
  189. >确 定</el-button
  190. >
  191. <el-button @click="cancelUpdateDelegateForm">取 消</el-button>
  192. </div>
  193. </el-dialog>
  194. <!--退回流程-->
  195. <el-dialog
  196. title="退回流程"
  197. :visible.sync="returnOpen"
  198. width="40%"
  199. append-to-body
  200. >
  201. <el-form
  202. ref="formRef"
  203. v-loading="formLoading"
  204. :model="formData"
  205. :rules="formRules"
  206. label-width="110px"
  207. >
  208. <el-form-item label="退回节点" prop="targetDefinitionKey">
  209. <el-select
  210. v-model="formData.targetDefinitionKey"
  211. clearable
  212. style="width: 100%"
  213. >
  214. <el-option
  215. v-for="item in returnList"
  216. :key="item.definitionKey"
  217. :label="item.name"
  218. :value="item.definitionKey"
  219. />
  220. </el-select>
  221. </el-form-item>
  222. <el-form-item label="回退理由" prop="reason">
  223. <el-input
  224. v-model="formData.reason"
  225. clearable
  226. placeholder="请输入回退理由"
  227. />
  228. </el-form-item>
  229. </el-form>
  230. <span slot="footer" class="dialog-footer">
  231. <el-button @click="returnOpen = false">取 消</el-button>
  232. <el-button
  233. :disabled="formLoading"
  234. type="primary"
  235. @click="submitReturn"
  236. >确 定</el-button
  237. >
  238. </span>
  239. </el-dialog>
  240. </div>
  241. </el-dialog>
  242. </template>
  243. <script>
  244. // import { getProcessDefinitionBpmnXML } from '@/api/bpm/definition';
  245. import store from '@/store';
  246. // import {decodeFields} from "@/utils/formGenerator";
  247. // import Parser from '@/components/parser/Parser'
  248. import { getProcessInstance } from '@/api/bpm/processInstance';
  249. import { listAllUserBind } from '@/api/system/organization';
  250. import Vue from 'vue';
  251. import {
  252. approveTask,
  253. delegateTask,
  254. getReturnList,
  255. getTaskListByProcessInstanceId,
  256. rejectTask,
  257. returnTask,
  258. updateTaskAssignee
  259. } from '@/api/bpm/task';
  260. // import { getDate } from '@/utils/dateUtils';
  261. // 流程实例的详情页,可用于审批
  262. export default {
  263. name: 'ProcessInstanceDetail',
  264. components: {
  265. // Parser
  266. },
  267. data() {
  268. return {
  269. // 遮罩层
  270. processInstanceLoading: true,
  271. dialogVisible: false,
  272. // 流程实例
  273. listData: {
  274. id: undefined, // 流程实例的编号
  275. pcHandleRouter: '',
  276. pcViewRouter: '',
  277. businessId: '', // 业务id
  278. taskDefinitionKey: '',
  279. taskId: '' //任务编码
  280. },
  281. processInstance: {},
  282. formLoading: false,
  283. // 流程表单详情
  284. detailForm: {
  285. fields: []
  286. },
  287. //回退列表数据
  288. returnList: [],
  289. formData: {
  290. id: '',
  291. targetDefinitionKey: undefined,
  292. reason: ''
  293. },
  294. formRules: {
  295. targetDefinitionKey: [
  296. { required: true, message: '必须选择回退节点', trigger: 'change' }
  297. ],
  298. reason: [
  299. { required: true, message: '回退理由不能为空', trigger: 'blur' }
  300. ]
  301. },
  302. returnOpen: false,
  303. activityList: [],
  304. tasks: [],
  305. // 审批表单
  306. runningTasks: [],
  307. auditForms: [],
  308. auditRule: {
  309. reason: [
  310. { required: true, message: '审批建议不能为空', trigger: 'blur' }
  311. ]
  312. },
  313. // 转派审批人
  314. userOptions: [],
  315. updateAssignee: {
  316. open: false,
  317. form: {
  318. assigneeUserId: undefined
  319. },
  320. rules: {
  321. assigneeUserId: [
  322. { required: true, message: '新审批人不能为空', trigger: 'change' }
  323. ]
  324. }
  325. },
  326. updateDelegate: {
  327. open: false,
  328. form: {
  329. delegateUserId: undefined,
  330. reason: ''
  331. },
  332. rules: {
  333. delegateUserId: [
  334. { required: true, message: '新审批人不能为空', trigger: 'change' }
  335. ],
  336. reason: [
  337. { required: true, message: '委派理由不能为空', trigger: 'blur' }
  338. ]
  339. }
  340. }
  341. };
  342. },
  343. created() {
  344. // this.id = this.$route.query.id;
  345. // if (!this.id) {
  346. // this.$message.error('未传递 id 参数,无法查看流程信息');
  347. // return;
  348. // }
  349. // this.getDetail();
  350. // 获得用户列表
  351. this.userOptions = [];
  352. listAllUserBind().then((data) => {
  353. this.userOptions.push(...data);
  354. });
  355. },
  356. methods: {
  357. submit(data) {
  358. this.$refs.bziRef.save(data);
  359. },
  360. open(data) {
  361. this.listData = data;
  362. console.log('实例流程~~~~~~', data);
  363. this.dialogVisible = true;
  364. this.getDetail();
  365. },
  366. activeCompChange(activeComp) {
  367. console.log(activeComp);
  368. this.$refs.subForm[0].activeCompChange(activeComp);
  369. },
  370. /** 获得流程实例 */
  371. getDetail() {
  372. // 获得流程实例相关
  373. this.processInstanceLoading = true;
  374. getProcessInstance(this.listData.id).then((response) => {
  375. if (!response) {
  376. this.$message.error('查询不到流程信息!');
  377. return;
  378. }
  379. // 设置流程信息
  380. console.log('==', response);
  381. console.log('==', this.listData);
  382. this.processInstance = response;
  383. // //将业务表单,注册为动态组件
  384. // let formCustomCreatePath = JSON.parse(
  385. // this.processInstance.processDefinition.formCustomCreatePath
  386. // );
  387. // const bizpath = formCustomCreatePath.pcView;
  388. // const subpath = formCustomCreatePath.pcHandle;
  389. Vue.component('async-biz-form-component', (resolve) => {
  390. require([`@/views${this.listData.pcViewRouter}`], resolve);
  391. });
  392. Vue.component('async-sub-form-component', (resolve) => {
  393. require([`@/views${this.listData.pcHandleRouter}`], resolve);
  394. });
  395. // // 设置表单信息
  396. // if (this.processInstance.processDefinition.formType === 10) {
  397. // this.detailForm = {
  398. // ...JSON.parse(this.processInstance.processDefinition.formConf),
  399. // disabled: true, // 表单禁用
  400. // formBtns: false, // 按钮隐藏
  401. // fields: decodeFields(this.processInstance.processDefinition.formFields)
  402. // }
  403. // // 设置表单的值
  404. // this.detailForm.fields.forEach(item => {
  405. // const val = this.processInstance.formVariables[item.__vModel__]
  406. // if (val) {
  407. // item.__config__.defaultValue = val
  408. // }
  409. // });
  410. // }
  411. // 取消加载中
  412. this.processInstanceLoading = false;
  413. });
  414. this.runningTasks = [];
  415. this.auditForms = [];
  416. getTaskListByProcessInstanceId(this.listData.id).then((response) => {
  417. console.log(response, 'response');
  418. // 审批记录
  419. this.tasks = [];
  420. // 移除已取消的审批
  421. response.forEach((task) => {
  422. if (task.result !== 4) {
  423. this.tasks.push(task);
  424. }
  425. });
  426. // 排序,将未完成的排在前面,已完成的排在后面;
  427. this.tasks.sort((a, b) => {
  428. // 有已完成的情况,按照完成时间倒序
  429. if (a.endTime && b.endTime) {
  430. return b.endTime - a.endTime;
  431. } else if (a.endTime) {
  432. return 1;
  433. } else if (b.endTime) {
  434. return -1;
  435. // 都是未完成,按照创建时间倒序
  436. } else {
  437. return b.createTime - a.createTime;
  438. }
  439. });
  440. // 需要审核的记录
  441. const userId = store.getters.user.info.userId;
  442. this.tasks.forEach((task) => {
  443. if (task.result !== 1 && task.result !== 6) {
  444. // 只有待处理才需要
  445. return;
  446. }
  447. if (!task.assigneeUser || task.assigneeUser.id !== userId) {
  448. // 自己不是处理人
  449. return;
  450. }
  451. this.runningTasks.push({ ...task });
  452. console.log(this.runningTasks, ' this.runningTasks');
  453. this.auditForms.push({
  454. reason: ''
  455. });
  456. });
  457. });
  458. },
  459. /** 处理审批通过和不通过的操作 */
  460. handleAudit(data) {
  461. let text = data.status === 1 ? '通过' : '不通过';
  462. this.$message.success(`审批${data.title || text}成功!`);
  463. this.handleClose(); // 获得最新详情
  464. // const index = this.runningTasks.indexOf(task);
  465. // this.$refs['form' + index][0].validate((valid) => {
  466. // if (!valid) {
  467. // return;
  468. // }
  469. // const data = {
  470. // id: task.id,
  471. // reason: this.auditForms[index].reason
  472. // };
  473. // if (pass) {
  474. // approveTask(data).then((response) => {
  475. // this.$message.success('审批通过成功!');
  476. // this.handleClose(); // 获得最新详情
  477. // });
  478. // } else {
  479. // rejectTask(data).then((response) => {
  480. // this.$message.success('审批不通过成功!');
  481. // this.handleClose(); // 获得最新详情
  482. // });
  483. // }
  484. // });
  485. },
  486. /** 处理转办审批人 */
  487. handleUpdateAssignee(task) {
  488. // 设置表单
  489. this.resetUpdateAssigneeForm();
  490. this.updateAssignee.form.id = task.id;
  491. // 设置为打开
  492. this.updateAssignee.open = true;
  493. },
  494. /** 提交转办审批人 */
  495. submitUpdateAssigneeForm() {
  496. this.$refs['updateAssigneeForm'].validate((valid) => {
  497. if (!valid) {
  498. return;
  499. }
  500. updateTaskAssignee(this.updateAssignee.form).then((response) => {
  501. this.$message.success('转办任务成功!');
  502. this.updateAssignee.open = false;
  503. this.handleClose(); // 获得最新详情
  504. });
  505. });
  506. },
  507. /** 取消转办审批人 */
  508. cancelUpdateAssigneeForm() {
  509. this.updateAssignee.open = false;
  510. this.resetUpdateAssigneeForm();
  511. },
  512. /** 重置转办审批人 */
  513. resetUpdateAssigneeForm() {
  514. this.updateAssignee.form = {
  515. id: undefined,
  516. assigneeUserId: undefined
  517. };
  518. this.resetForm('updateAssigneeForm');
  519. },
  520. /** 处理审批委派的操作 */
  521. handleDelegate(task) {
  522. //this.$modal.msgError("暂不支持【委派】功能,可以使用【转派】替代!");
  523. this.resetUpdateDelegateForm();
  524. this.updateDelegate.form.id = task.id;
  525. // 设置为打开
  526. this.updateDelegate.open = true;
  527. },
  528. /** 提交委派审批人 */
  529. submitUpdateDelegateForm() {
  530. this.$refs['updateDelegateForm'].validate((valid) => {
  531. if (!valid) {
  532. return;
  533. }
  534. delegateTask(this.updateDelegate.form).then((response) => {
  535. this.$message.success('委派任务成功!');
  536. this.updateDelegate.open = false;
  537. this.handleClose(); // 获得最新详情
  538. });
  539. });
  540. },
  541. /** 取消委派审批人 */
  542. cancelUpdateDelegateForm() {
  543. this.updateDelegate.open = false;
  544. this.resetUpdateDelegateForm();
  545. },
  546. /** 重置委派审批人 */
  547. resetUpdateDelegateForm() {
  548. this.updateDelegate.form = {
  549. id: undefined,
  550. delegateUserId: undefined
  551. };
  552. this.resetForm('updateDelegateForm');
  553. },
  554. /** 处理审批退回的操作 */
  555. /** 返回退回节点列表 */
  556. handleBackList(task) {
  557. // 可参考 http://blog.wya1.com/article/636697030/details/7296
  558. getReturnList(task.id).then((response) => {
  559. this.returnList = response.data.data;
  560. if (this.returnList.length == 0) {
  561. this.$message.error('当前没有可回退的节点!');
  562. return;
  563. }
  564. this.formData.id = task.id;
  565. this.returnOpen = true;
  566. });
  567. },
  568. /** 提交退回任务 */
  569. submitReturn() {
  570. if (!this.formData.targetDefinitionKey) {
  571. this.$message.error('请选择退回节点!');
  572. }
  573. this.$refs['formRef'].validate((valid) => {
  574. if (!valid) {
  575. return;
  576. }
  577. returnTask(this.formData).then((res) => {
  578. if (res.data) {
  579. this.$message.success('回退成功!');
  580. this.returnOpen = false;
  581. this.handleClose(); // 获得最新详情
  582. }
  583. });
  584. });
  585. },
  586. handleClose() {
  587. this.$emit('reload');
  588. this.dialogVisible = false;
  589. },
  590. getTableValue(fn) {
  591. fn(this.$refs.bziRef.getTableValue());
  592. },
  593. // 获取销售退货仓管入库数据
  594. getReturnStorage(fn) {
  595. fn(this.$refs.bziRef.getReturnStorage());
  596. }
  597. }
  598. };
  599. </script>
  600. <style lang="scss">
  601. .my-process-designer {
  602. height: calc(100vh - 200px);
  603. }
  604. .box-card {
  605. width: 100%;
  606. margin-bottom: 20px;
  607. }
  608. </style>