processSubmitDialog.vue 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554
  1. <template>
  2. <ele-modal
  3. custom-class="ele-dialog-form long-dialog-form"
  4. :centered="true"
  5. :visible="processSubmitDialogFlag"
  6. :title="title"
  7. append-to-body
  8. :close-on-click-modal="false"
  9. :width="isRight ? '800px' : '450px'"
  10. :before-close="cancel"
  11. :maxable="true"
  12. :resizable="true"
  13. >
  14. <div style="display: flex; height: 100%; justify-content: space-between">
  15. <div class="form-box">
  16. <fm-generate-form
  17. :data="formSchema"
  18. :value="form.valueJson"
  19. :remote="remoteFuncs"
  20. ref="generateForm"
  21. class="el-form-box"
  22. >
  23. <template v-slot:manage_workorder="scope">
  24. <div class="manage_workorder">
  25. <el-input
  26. v-model="scope.model.manage_workorder.code"
  27. style="width: 100%"
  28. @click.native="addWorkOrder('manage_workorder')"
  29. placeholder="点击选择关联工单"
  30. ></el-input>
  31. </div> </template
  32. ></fm-generate-form>
  33. </div>
  34. <div
  35. style="
  36. align-self: center;
  37. display: flex;
  38. color: #1890ff;
  39. cursor: pointer;
  40. width: 15px;
  41. "
  42. @click="() => (isRight = !isRight)"
  43. >
  44. <span
  45. style="align-self: center; transform: scale(1.5)"
  46. :class="isRight ? 'el-icon-caret-left' : 'el-icon-caret-right'"
  47. ></span>
  48. <span style="writing-mode: vertical-rl">选择流程</span>
  49. </div>
  50. <div style="flex: 1" v-if="isRight">
  51. <el-form
  52. ref="processForm"
  53. class="el-form-box"
  54. :model="form"
  55. label-width="80px"
  56. >
  57. <el-row>
  58. <el-col :span="12">
  59. <el-form-item label="流程分类">
  60. <ele-tree-select
  61. @change="changeLCFL"
  62. clearable
  63. ref="processTypeRef"
  64. filterable
  65. :data="LCFLList"
  66. v-model="form.LCFL"
  67. childrenKey="children"
  68. valueKey="id"
  69. labelKey="name"
  70. placeholder="请选择"
  71. default-expand-all
  72. />
  73. </el-form-item>
  74. </el-col>
  75. <el-col :span="12">
  76. <el-form-item label="发起流程">
  77. <el-select
  78. filterable
  79. v-model="form.FQLC"
  80. @change="changeFQLC"
  81. style="width: 100%"
  82. >
  83. <el-option
  84. v-for="item in processList"
  85. :key="item.id"
  86. :value="item.id"
  87. :label="item.name"
  88. ></el-option>
  89. </el-select>
  90. </el-form-item>
  91. </el-col>
  92. </el-row>
  93. <el-row>
  94. <el-col :span="12">
  95. <el-form-item label="流程名称">
  96. <el-input v-model="form.name" clearable></el-input>
  97. </el-form-item>
  98. </el-col>
  99. <el-col :span="12">
  100. <el-form-item label="流程标识">
  101. <el-input v-model="form.key" disabled></el-input>
  102. </el-form-item>
  103. </el-col>
  104. </el-row>
  105. <headerTitle
  106. title="流程执行人/流程图"
  107. style="margin-top: 30px"
  108. ></headerTitle>
  109. <el-table
  110. :data="datasource"
  111. height="150px"
  112. border
  113. style="margin-bottom: 10px"
  114. >
  115. <el-table-column
  116. label="任务节点"
  117. align="center"
  118. prop="taskDefinitionName"
  119. width="140"
  120. fixed
  121. />
  122. <el-table-column
  123. label="执行人"
  124. align="center"
  125. prop="options"
  126. min-width="140px"
  127. >
  128. <template v-slot="scope">
  129. <div
  130. v-if="
  131. scope.row.type !== 60 &&
  132. scope.row.type !== 70 &&
  133. scope.row.type !== 80 &&
  134. scope.row.options.length > 0
  135. "
  136. >
  137. <el-tag
  138. size="medium"
  139. :key="option"
  140. v-for="option in scope.row.options"
  141. >
  142. {{ getAssignRuleOptionName(scope.row, option) }}
  143. </el-tag>
  144. </div>
  145. <el-tag
  146. size="medium"
  147. v-if="
  148. scope.row.type === 60 ||
  149. scope.row.type === 70 ||
  150. scope.row.type === 80
  151. "
  152. >
  153. {{ getAssignRuleOptionName(scope.row) }}
  154. </el-tag>
  155. </template>
  156. </el-table-column>
  157. </el-table>
  158. <my-process-viewer
  159. style="min-width: 100%; height: 200px"
  160. key="designer"
  161. v-model="bpmnXML"
  162. />
  163. </el-form>
  164. </div>
  165. </div>
  166. <div slot="footer">
  167. <el-button type="primary" size="small" @click="submit">提交</el-button>
  168. <el-button size="small" @click="cancel">关闭</el-button>
  169. </div>
  170. <SHGDListDialog
  171. ref="SHGDListDialogRef"
  172. @changeParent="getSHGDData"
  173. ></SHGDListDialog>
  174. </ele-modal>
  175. </template>
  176. <script>
  177. import {
  178. getModelPage,
  179. getProcessDefinitionBpmnXML,
  180. getTaskAssignRuleList,
  181. listAllUserBind,
  182. listSimpleUserGroups,
  183. getModel,
  184. savePieCarMonad
  185. } from './api';
  186. import { treeClassifyCodeEnum } from '@/enum/dict';
  187. import { listRoles } from '@/api/system/role';
  188. import { listOrganizations } from '@/api/system/organization';
  189. import dictMixins from '@/mixins/dictMixins';
  190. import { getByCode } from '@/api/system/dictionary-data';
  191. import { getProduceTreeByCode } from '@/api/main';
  192. import { topLevel1, topLevel2, topLevel3 } from '@/enum/dict';
  193. import { getToken } from '@/utils/token-util';
  194. import { mapGetters } from 'vuex';
  195. import SHGDListDialog from '@/views/salesServiceManagement/workOrder/components/drawer.vue';
  196. export default {
  197. name: 'processSubmitDialog',
  198. mixins: [dictMixins],
  199. components: {
  200. SHGDListDialog
  201. },
  202. props: {
  203. processSubmitDialogFlag: {
  204. type: Boolean,
  205. default: false
  206. },
  207. formSchema: {
  208. type: Object,
  209. default: () => ({})
  210. },
  211. carByTemplate: {
  212. type: Object,
  213. default: () => ({})
  214. },
  215. workOrderData: {
  216. type: Object,
  217. default: () => ({ id: '', code: '', name: '' })
  218. }
  219. },
  220. data() {
  221. return {
  222. title: '用车',
  223. isRight: false,
  224. remoteFuncs: {},
  225. form: {
  226. LCFL: '',
  227. FQLC: '',
  228. processDefinitionId: '',
  229. name: '',
  230. key: 'TYCSLC',
  231. valueJson: {
  232. manage_workorder: {
  233. code: '',
  234. id: '',
  235. name: ''
  236. }
  237. },
  238. processModelId: ''
  239. },
  240. LCFLList: [],
  241. processList: [],
  242. datasource: [],
  243. bpmnXML: null,
  244. roleOptions: [],
  245. deptOptions: [],
  246. userOptions: [],
  247. userGroupOptions: [],
  248. dictList: {}
  249. };
  250. },
  251. watch: {
  252. processSubmitDialogFlag(newVal) {
  253. if (newVal) {
  254. this.initDefaultProcessByKey('TYCSLC');
  255. if (this.workOrderData.id) {
  256. this.form.valueJson.manage_workorder = {
  257. id: this.workOrderData.id,
  258. code: this.workOrderData.code,
  259. name: this.workOrderData.name
  260. };
  261. if (this.$refs.generateForm) {
  262. this.$refs.generateForm.setData({
  263. manage_workorder: this.form.valueJson.manage_workorder
  264. });
  265. }
  266. }
  267. }
  268. }
  269. },
  270. computed: {
  271. ...mapGetters(['user'])
  272. },
  273. async created() {
  274. await this.initProcessBaseData();
  275. await this.initDefaultProcessByKey('TYCSLC');
  276. },
  277. methods: {
  278. getSHGDData(workOrder) {
  279. if (!workOrder?.code) {
  280. this.$message.warning('选中的工单缺少编码,请重新选择');
  281. return;
  282. }
  283. this.$refs.generateForm.getData(false).then((currentFormData) => {
  284. currentFormData.manage_workorder = {
  285. code: workOrder.code,
  286. id: workOrder.id || '',
  287. name: workOrder.name || ''
  288. };
  289. this.$refs.generateForm.setData({
  290. manage_workorder: currentFormData.manage_workorder
  291. });
  292. this.form.valueJson.manage_workorder = currentFormData.manage_workorder;
  293. });
  294. },
  295. addWorkOrder() {
  296. this.$refs.SHGDListDialogRef.open();
  297. },
  298. async initProcessBaseData() {
  299. const typeObj = await getProduceTreeByCode(
  300. treeClassifyCodeEnum['PROCESSTYPE']
  301. );
  302. this.LCFLList = typeObj[0]?.children || [];
  303. await this.initBaseOptions();
  304. },
  305. async initBaseOptions() {
  306. const roleRes = await listRoles({ current: 1, size: 9999 });
  307. this.roleOptions = roleRes.list || [];
  308. const deptRes = await listOrganizations();
  309. this.deptOptions = deptRes || [];
  310. const userRes = await listAllUserBind();
  311. this.userOptions = userRes || [];
  312. const userGroupRes = await listSimpleUserGroups();
  313. this.userGroupOptions = userGroupRes || [];
  314. await this.getDictList(this.dictEnum['工作流任务分配自定义脚本']);
  315. await this.getDictList(this.dictEnum['工种类型']);
  316. },
  317. async initDefaultProcessByKey(targetKey) {
  318. try {
  319. const { list } = await getModelPage({
  320. pageNo: 1,
  321. pageSize: 1,
  322. key: targetKey
  323. });
  324. if (list.length === 0) {
  325. this.$message.warning(
  326. `未找到标识为【${targetKey}】的流程模型,请检查配置`
  327. );
  328. return;
  329. }
  330. const defaultModel = list[0];
  331. this.form.LCFL = defaultModel.category;
  332. this.form.FQLC = defaultModel.id;
  333. this.form.name = defaultModel.name;
  334. this.form.processModelId = defaultModel.id;
  335. await this.getProcessList(defaultModel.category);
  336. await this.changeFQLC(defaultModel.id);
  337. } catch (error) {
  338. console.error(error);
  339. this.$message.error('默认流程加载失败,请手动选择流程');
  340. }
  341. },
  342. async changeLCFL(val) {
  343. this.bpmnXML = null;
  344. this.form.processDefinitionId = '';
  345. this.form.FQLC = '';
  346. await this.getProcessList(val);
  347. },
  348. async getProcessList(processTypeId) {
  349. const { list } = await getModelPage({
  350. pageNo: 1,
  351. pageSize: 999,
  352. processTypeId
  353. });
  354. this.processList = list.filter((item) => item.processDefinition);
  355. },
  356. async changeFQLC(val) {
  357. if (!val) return;
  358. const selectedProcess =
  359. this.processList.find((item) => item.id === val) || {};
  360. const processDef = selectedProcess.processDefinition || {};
  361. this.form.name = selectedProcess.name || this.title;
  362. this.form.key = selectedProcess.key || 'TYCSLC';
  363. this.form.processDefinitionId = processDef.id || '';
  364. this.form.processModelId = val;
  365. await this.getProcessDefinitionBpmnXMLInfo(val);
  366. await this.getTaskAssignRuleListInfo({
  367. modelId: val,
  368. processDefinitionId: processDef.id
  369. });
  370. },
  371. async getProcessDefinitionBpmnXMLInfo(modelId) {
  372. const res = await getModel(modelId);
  373. this.bpmnXML = res.bpmnXml;
  374. },
  375. async getTaskAssignRuleListInfo(params) {
  376. this.datasource = await getTaskAssignRuleList(params);
  377. },
  378. getAssignRuleOptionName(row, option) {
  379. if (row.type === 10) {
  380. const role = this.roleOptions.find((item) => item.id === option);
  381. return role?.name || `未知角色(${option})`;
  382. } else if (row.type === 20 || row.type === 21) {
  383. const dept = this.deptOptions.find((item) => item.id === option);
  384. return dept?.name || `未知部门(${option})`;
  385. } else if (row.type === 22) {
  386. return (
  387. this.getDictV(this.dictEnum['工种类型'], option + '') ||
  388. `未知工种(${option})`
  389. );
  390. } else if (row.type === 30 || row.type === 31 || row.type === 32) {
  391. const user = this.userOptions.find((item) => item.id === option);
  392. return user?.nickname || user?.name || `未知用户(${option})`;
  393. } else if (row.type === 40) {
  394. const group = this.userGroupOptions.find((item) => item.id === option);
  395. return group?.name || `未知用户组(${option})`;
  396. } else if (row.type === 50) {
  397. return (
  398. this.getDictV(
  399. this.dictEnum['工作流任务分配自定义脚本'],
  400. option + ''
  401. ) || `未知脚本(${option})`
  402. );
  403. } else if (row.type === 60) {
  404. return row.variableName || '变量执行人';
  405. } else if (row.type === 70) {
  406. const data = JSON.parse(row.variableName || '{}');
  407. const levelList = data.direction === 1 ? topLevel2 : topLevel1;
  408. return (
  409. levelList.find((item) => item.value === data.topLevel)?.label ||
  410. '未知层级'
  411. );
  412. } else if (row.type === 80) {
  413. const data = JSON.parse(row.variableName || '{}');
  414. return (
  415. topLevel3.find((item) => item.value === data.topLevel)?.label ||
  416. '未知层级'
  417. );
  418. }
  419. return `未知类型(${option || '无'})`;
  420. },
  421. getDictV(dictCode, val) {
  422. if (!this.dictList[dictCode]) return '';
  423. return (
  424. this.dictList[dictCode].find((item) => item.value === val)?.label || ''
  425. );
  426. },
  427. async getDictList(dictCode) {
  428. const { data: res } = await getByCode(dictCode);
  429. this.dictList[dictCode] = res.map((item) => {
  430. const keys = Object.keys(item);
  431. return { value: keys[0], label: item[keys[0]] };
  432. });
  433. },
  434. generateFormValid(validate = true) {
  435. return this.$refs.generateForm.getData(validate).then((data) => data);
  436. },
  437. // async submit() {
  438. // try {
  439. // this.form.valueJson = await this.generateFormValid();
  440. // const submitData = {
  441. // ...this.form,
  442. // ...this.carByTemplate,
  443. // processType: '1',
  444. // variables: { ...this.form.valueJson }
  445. // };
  446. // console.log(submitData.formJson.makingJson)
  447. // this.$emit('formSubmit', submitData);
  448. // await savePieCarMonad(submitData);
  449. // this.cancel();
  450. // } catch (error) {
  451. // console.error(error);
  452. // this.$message.warning('表单验证失败,请检查填写内容');
  453. // }
  454. // },
  455. async submit() {
  456. try {
  457. const formValue = await this.generateFormValid();
  458. this.form.valueJson = formValue;
  459. const workOrderId = this.form.valueJson.manage_workorder.id;
  460. if (!workOrderId) {
  461. this.$message.warning('请先选择关联工单');
  462. return;
  463. }
  464. const submitData = {
  465. ...this.form,
  466. ...this.carByTemplate,
  467. processType: '1',
  468. variables: { ...this.form.valueJson }
  469. };
  470. const submitParams = {
  471. id: workOrderId,
  472. formJson: submitData
  473. };
  474. this.loading = true;
  475. await savePieCarMonad(submitParams);
  476. this.$message.success('提交成功');
  477. this.cancel();
  478. } catch (error) {
  479. console.error('提交失败:', error);
  480. this.$message.error('提交失败,请重试');
  481. } finally {
  482. this.loading = false;
  483. }
  484. },
  485. cancel() {
  486. this.$emit('update:processSubmitDialogFlag', false);
  487. this.isRight = false;
  488. this.bpmnXML = null;
  489. this.datasource = [];
  490. this.form = {
  491. ...this.form,
  492. FQLC: '',
  493. processDefinitionId: '',
  494. name: '',
  495. processModelId: '',
  496. valueJson: {
  497. ...this.form.valueJson,
  498. manage_workorder: { code: '', id: '', name: '' }
  499. }
  500. };
  501. if (this.$refs.generateForm) this.$refs.generateForm.reset();
  502. if (this.$refs.processForm) this.$refs.processForm.resetFields();
  503. this.remoteFuncs = {};
  504. }
  505. }
  506. };
  507. </script>
  508. <style scoped lang="scss">
  509. .form-box {
  510. min-width: 400px;
  511. overflow: auto;
  512. background: #4298fd0d;
  513. }
  514. ::v-deep .el-dialog {
  515. min-width: 400px;
  516. .el-dialog__header {
  517. background: #1890ffd6;
  518. }
  519. .el-dialog__title,
  520. .el-dialog__close {
  521. color: #ffffff;
  522. }
  523. }
  524. ::v-deep .el-table {
  525. margin-top: 10px;
  526. .el-table__header th {
  527. background: #f5f7fa;
  528. }
  529. }
  530. ::v-deep .bpmn-viewer {
  531. border: 1px solid #e5e7eb;
  532. border-radius: 4px;
  533. }
  534. </style>