index.vue 19 KB

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