summary.vue 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321
  1. <template>
  2. <div class="form">
  3. <el-form :model="form" label-width="130px" ref="ruleFormRef">
  4. <el-form-item label="节点名称" prop="name" :rules="[{ required: true, message: '请输入节点名称', trigger: 'blur' }]">
  5. <el-input v-model="form.name" placeholder="请输入节点名称" clearable></el-input>
  6. </el-form-item>
  7. <el-form-item label="节点编码" prop="code" :rules="[{ required: true, message: '请输入节点编码', trigger: 'blur' }]">
  8. <el-input v-model="form.code" disabled placeholder="请输入节点编码" clearable></el-input>
  9. </el-form-item>
  10. <el-form-item label="处理人" prop="handlerType" :rules="[{ required: true, message: '请选择处理人', trigger: 'change' }]">
  11. <el-select v-model="form.handlerType" class="w100" placeholder="请选择处理人" @change="changeOptions">
  12. <el-option v-for="item in handlerTypeOptions" :key="item.value" :label="item.label" :value="item.value" />
  13. </el-select>
  14. </el-form-item>
  15. <!-- 选择其他 -->
  16. <el-form-item
  17. v-if="[0, 1, 2].includes(form.handlerType)"
  18. :label="itemName"
  19. prop="handlerClassifiesOrgin"
  20. :rules="[{ required: true, message: `请选择${itemName}`, trigger: 'change' }]"
  21. >
  22. <el-select v-model="form.handlerClassifiesOrgin" multiple filterable class="w100" @change="getSelectValue" value-key="id">
  23. <el-option v-for="item in selectList" :key="item.id" :label="item.name" :value="item" />
  24. </el-select>
  25. </el-form-item>
  26. <!-- 选择用户 -->
  27. <el-form-item
  28. v-if="[3].includes(form.handlerType)"
  29. :label="itemName"
  30. prop="handlerClassifiesOrgin"
  31. :rules="[{ required: true, message: `请选择${itemName}`, trigger: 'change' }]"
  32. >
  33. <el-select
  34. v-model="form.handlerClassifiesOrgin"
  35. multiple
  36. filterable
  37. remote
  38. class="w100"
  39. reserve-keyword
  40. placeholder="请输入用户名称"
  41. remote-show-suffix
  42. :remote-method="remoteMethod"
  43. :loading="loading"
  44. @change="getSelectValue"
  45. value-key="id"
  46. >
  47. <el-option v-for="item in userList" :key="item.id" :label="item.name" :value="item" />
  48. </el-select>
  49. </el-form-item>
  50. <!-- 部门 -->
  51. <el-form-item
  52. v-if="[4].includes(form.handlerType)"
  53. :label="itemName"
  54. prop="handlerClassifiesOrgin"
  55. :rules="[{ required: true, message: `请选择${itemName}`, trigger: 'change' }]"
  56. >
  57. <el-tree-select
  58. :props="{ label: 'orgName' }"
  59. node-key="orgCode"
  60. class="w100"
  61. ref="treeSelectRef"
  62. v-model="form.handlerClassifiesOrgin"
  63. :data="orgData"
  64. multiple
  65. :render-after-expand="false"
  66. show-checkbox
  67. @check-change="checkChange"
  68. check-strictly
  69. default-expand-all
  70. filterable
  71. />
  72. </el-form-item>
  73. <el-form-item label="节点属性" prop="businessProperty" :rules="[{ required: true, message: '请选择节点属性', trigger: 'change' }]">
  74. <el-select v-model="form.businessProperty" class="w100" placeholder="请选择节点属性">
  75. <el-option v-for="item in businessPropertyOptions" :key="item.value" :label="item.label" :value="item.value" />
  76. </el-select>
  77. </el-form-item>
  78. <el-form-item label="会签" prop="countersignMode" :rules="[{ required: true, message: '请选择会签', trigger: 'change' }]">
  79. <el-select v-model="form.countersignMode" class="w100" placeholder="请选择会签">
  80. <el-option v-for="item in countersignModeList" :key="item.value" :label="item.label" :value="item.value" />
  81. </el-select>
  82. </el-form-item>
  83. <el-form-item label="节点过滤策略" prop="pathPolicy" :rules="[{ required: true, message: '请选择节点过滤策略', trigger: 'change' }]">
  84. <el-select v-model="form.pathPolicy" class="w100" placeholder="请选择节点过滤策略">
  85. <el-option v-for="item in pathPolicyOptions" :key="item.key" :label="item.value" :value="item.key" />
  86. </el-select>
  87. </el-form-item>
  88. <el-form-item label="会签发起节点" prop="CountersignStartCode" :rules="[{ required: false, message: '请选择会签发起节点', trigger: 'change' }]">
  89. <el-select v-model="form.CountersignStartCode" class="w100" placeholder="请选择会签发起节点" @change="chanStartCode">
  90. <el-option v-for="item in nodesOptions" :key="item.id" :label="item.text.value" :value="item.id" />
  91. </el-select>
  92. </el-form-item>
  93. <el-form-item label="组件配置" prop="components" :rules="[{ required: false, message: '请选择组件配置', trigger: 'change' }]">
  94. <el-checkbox-group v-model="form.components">
  95. <el-checkbox :label="item.dicDataValue" v-for="item in stepPropertiesOptions" :key="item.id">{{item.dicDataName}}</el-checkbox>
  96. </el-checkbox-group>
  97. </el-form-item>
  98. </el-form>
  99. </div>
  100. </template>
  101. <script lang="ts" setup name="flowNode">
  102. import { reactive, watch, onMounted, ref } from 'vue';
  103. import { ElMessageBox } from 'element-plus';
  104. import { removeDuplicate } from '/@/utils/arrayOperation';
  105. import { baseData, getSelectList,queryUser } from '/@/api/system/workflow';
  106. import { getCanUseOrg } from '/@/api/system/user';
  107. const ruleFormRef = ref<RefType>();
  108. // 定义属性
  109. const props = defineProps<{
  110. modelValue: any;
  111. }>();
  112. // 注意:ref不能与model一样,相同的话表单双向绑定将会失效
  113. const form = reactive<any>({
  114. ...props.modelValue, // 传入的数据
  115. handlerClassifiesOrgin: [], // 选择的数据
  116. handlerClassifies: [], // 选择的数据
  117. handlerType: '', // 处理人类型
  118. businessProperty: '', // 节点属性
  119. countersignMode: '', // 会签
  120. CountersignStartCode: '', // 会签发起节点
  121. CountersignEndCode: '', // 会签结束节点
  122. pathPolicy: '', // 节点过滤策略
  123. });
  124. const emits = defineEmits(['update:modelValue', 'countersignStartCode']); // 定义事件
  125. //
  126. const loading = ref(false); // 加载
  127. const nodesOptions = ref([] as any); // 节点
  128. watch(
  129. () => form,
  130. () => {
  131. emits('update:modelValue', Object.assign(props.modelValue, form));
  132. },
  133. { deep: true }
  134. );
  135. // 选择处理人获取数据
  136. // 处理人
  137. const handlerTypeOptions = ref<EmptyArrayType>() as any;
  138. // 下拉内容
  139. const selectList = ref<EmptyArrayType>() as any;
  140. // 会签
  141. const itemName = ref<EmptyArrayType>();
  142. const changeOptions = (e: any) => {
  143. form.handlerClassifiesOrgin = [];
  144. form.handlerClassifies = '[]';
  145. itemName.value = handlerTypeOptions.value[e].label;
  146. if ([0, 1, 2].includes(e)) {
  147. getSelectList(e).then((res: any) => {
  148. selectList.value = res.result ?? [];
  149. selectList.value = selectList.value.map((item: any) => ({
  150. id: item.key,
  151. name: item.value,
  152. }));
  153. });
  154. }
  155. if (e === 4) {
  156. getOrgListFn();
  157. }
  158. };
  159. // 获取可用组织
  160. const getOrgListFn = () => {
  161. getCanUseOrg().then((res: any) => {
  162. orgData.value = res?.result ?? [];
  163. });
  164. };
  165. const treeSelectRef = ref<RefType>();
  166. // 选择部门
  167. const checkChange = () => {
  168. const data = treeSelectRef.value.getCheckedNodes();
  169. let arr: EmptyArrayType;
  170. arr = data.map((v: any) => {
  171. return {
  172. id: v.orgCode,
  173. name: v.orgName,
  174. };
  175. });
  176. // 使用模板字符串
  177. form.handlerClassifies = `${JSON.stringify(arr)}`;
  178. };
  179. // 远程搜索用户名称
  180. // 指定用户列表
  181. const userList = ref<EmptyArrayType>();
  182. const remoteMethod = (query: string) => {
  183. if (query !== '') {
  184. loading.value = true;
  185. queryUser({ name: query }).then((res: any) => {
  186. loading.value = false;
  187. const newUsers = res.result.map((item: any) => {
  188. return {
  189. ...item,
  190. name: !item.name.includes('-') ? item.name + '-' + item.organization.orgName : item.name
  191. };
  192. });
  193. userList.value = removeDuplicate([ ...newUsers,...userList.value], 'id');
  194. });
  195. }
  196. };
  197. // 获取选择对象
  198. const getSelectValue = (query: any) => {
  199. let arr: EmptyArrayType;
  200. arr = query.map((item: any) => ({ name: item.name, id: item.id }));
  201. // 使用模板字符串
  202. form.handlerClassifies = `${JSON.stringify(arr)}`;
  203. };
  204. // 选择会签发起节点
  205. const chanStartCode = (val: string) => {
  206. form.CountersignEndCode = form.code;
  207. const currentItem = form.nodes.find((v: any) => v.id === val); //拿到当前选中的节点
  208. if (currentItem) {
  209. if (currentItem.properties?.CountersignStartCode) {
  210. // 如果选中的会签发起节点有关联其他汇总节点
  211. ElMessageBox.alert(`该节点已关联其他汇总节点,覆盖当前配置`, '提示', {
  212. confirmButtonText: '确认',
  213. type: 'warning',
  214. draggable: true,
  215. cancelButtonClass: 'default-button',
  216. showClose: false,
  217. autofocus: false,
  218. }).then(() => {
  219. const beforeChangeItem = form.nodes.find((v: any) => v.properties?.CountersignEndCode === form.CountersignEndCode);
  220. // 先找到修改前关联的流程节点并清空
  221. beforeChangeItem.properties.CountersignStartCode = '';
  222. beforeChangeItem.properties.CountersignEndCode = '';
  223. beforeChangeItem.properties.type = beforeChangeItem.type.replace('hotline:', '');
  224. beforeChangeItem.properties.id = beforeChangeItem.id;
  225. emits('countersignStartCode', beforeChangeItem.properties);
  226. // 再找到修改前的汇总节点并清空
  227. const afterChangeItem = form.summaryNodes.find((v: any) => v.id === currentItem.properties.CountersignEndCode);
  228. afterChangeItem.properties.CountersignStartCode = '';
  229. afterChangeItem.properties.CountersignEndCode = '';
  230. afterChangeItem.properties.type = afterChangeItem.type.replace('hotline:', '');
  231. afterChangeItem.properties.id = afterChangeItem.id;
  232. emits('countersignStartCode', afterChangeItem.properties);
  233. // 再重新赋值 当前节点
  234. currentItem.properties.CountersignStartCode = val;
  235. currentItem.properties.CountersignEndCode = form.code;
  236. currentItem.properties.type = currentItem.type.replace('hotline:', '');
  237. currentItem.properties.id = currentItem.id;
  238. emits('countersignStartCode', currentItem.properties);
  239. });
  240. } else {
  241. currentItem.properties.CountersignStartCode = val;
  242. currentItem.properties.CountersignEndCode = form.code;
  243. currentItem.properties.type = currentItem.type.replace('hotline:', '');
  244. currentItem.properties.id = currentItem.id;
  245. emits('countersignStartCode', currentItem.properties);
  246. }
  247. }
  248. };
  249. // 会签
  250. const countersignModeList = ref<EmptyArrayType>() as any;
  251. // 节点属性
  252. const businessPropertyOptions = ref<EmptyArrayType>() as any;
  253. // 部门
  254. const orgData = ref<EmptyArrayType>() as any;
  255. // 组件
  256. const stepPropertiesOptions = ref<EmptyArrayType>() as any;
  257. //
  258. const pathPolicyOptions = ref<EmptyArrayType>() as any;
  259. onMounted(async () => {
  260. // 获取页面基础数据
  261. const res: any = await baseData();
  262. handlerTypeOptions.value = res.result?.handlerTypeOptions ?? [];
  263. handlerTypeOptions.value = handlerTypeOptions.value.map((item: any) => ({
  264. value: item.key,
  265. label: item.value,
  266. }));
  267. countersignModeList.value = res.result?.countersignMode ?? [];
  268. countersignModeList.value = countersignModeList.value.map((item: any) => ({
  269. value: item.key,
  270. label: item.value,
  271. }));
  272. businessPropertyOptions.value = res.result?.businessPropertyOptions ?? [];
  273. businessPropertyOptions.value = businessPropertyOptions.value.map((item: any) => ({
  274. value: item.key,
  275. label: item.value,
  276. }));
  277. pathPolicyOptions.value = res.result?.pathPolicyOptions ?? [];
  278. stepPropertiesOptions.value = res.result?.stepPropertiesOptions ?? [];
  279. // 合并表单
  280. Object.assign(form, props.modelValue);
  281. if (form.handlerClassifies.includes('[')) {
  282. switch (form.handlerType) {
  283. case 0:
  284. case 1:
  285. case 2:
  286. form.handlerClassifiesOrgin = JSON.parse(form.handlerClassifies);
  287. break;
  288. case 3:
  289. userList.value = form.handlerClassifiesOrgin = JSON.parse(form.handlerClassifies);
  290. break;
  291. case 4:
  292. form.handlerClassifiesOrgin = JSON.parse(form.handlerClassifies).map((v: any) => v.id);
  293. break;
  294. default:
  295. break;
  296. }
  297. }
  298. if ([0, 1, 2].includes(form.handlerType)) {
  299. const res: any = await getSelectList(form.handlerType);
  300. selectList.value = res.result ?? [];
  301. selectList.value = selectList.value.map((item: any) => ({
  302. id: item.key,
  303. name: item.value,
  304. }));
  305. if (handlerTypeOptions.value.length) itemName.value = handlerTypeOptions.value[form.handlerType].label;
  306. } else if ([3].includes(form.handlerType)) {
  307. if (handlerTypeOptions.value.length) itemName.value = handlerTypeOptions.value[form.handlerType].label;
  308. } else if ([4].includes(form.handlerType)) {
  309. if (handlerTypeOptions.value.length) itemName.value = handlerTypeOptions.value[form.handlerType].label;
  310. getOrgListFn();
  311. }
  312. nodesOptions.value = form.nodes ?? [];
  313. });
  314. // 导入属性及方法给外部调用
  315. defineExpose({
  316. ruleFormRef,
  317. });
  318. </script>