index.vue 19 KB

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