end.vue 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357
  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="stepType" :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="stepTypeName" :rules="[{ required: true, message: '请选择节点类型', trigger: 'change' }]">
  11. <el-input v-model="form.stepTypeName" disabled></el-input>
  12. </el-form-item>
  13. <el-form-item label="业务类型" prop="businessType" :rules="[{ required: true, message: '请选择业务类型', trigger: 'change' }]">
  14. <el-select v-model="form.businessType" class="w100" placeholder="请选择业务类型">
  15. <el-option v-for="item in baseData.businessTypeOptions" :key="item.key" :label="item.value" :value="item.key" />
  16. </el-select>
  17. </el-form-item>
  18. <el-form-item label="办理者类型" prop="handlerType" :rules="[{ required: true, message: '请选择办理者类型', trigger: 'change' }]">
  19. <el-select v-model="form.handlerType" class="w100" placeholder="请选择办理者类型" @change="changeOptions">
  20. <el-option v-for="item in baseData.handlerTypeOptions" :key="item.value" :label="item.label" :value="item.value" />
  21. </el-select>
  22. </el-form-item>
  23. <!-- 选择其他 -->
  24. <el-form-item
  25. v-if="[0, 1, 2].includes(form.handlerType)"
  26. :label="itemName"
  27. prop="handlerTypeItemsOrigin"
  28. :rules="[{ required: true, message: `请选择${itemName}`, trigger: 'change' }]"
  29. >
  30. <el-select
  31. v-model="form.handlerTypeItemsOrigin"
  32. multiple
  33. filterable
  34. class="w100"
  35. @change="getSelectValue"
  36. value-key="key"
  37. collapse-tags
  38. collapse-tags-tooltip
  39. >
  40. <el-option v-for="item in selectList" :key="item.key" :label="item.value" :value="item" />
  41. </el-select>
  42. </el-form-item>
  43. <!-- 选择用户 -->
  44. <el-form-item
  45. v-if="[3].includes(form.handlerType)"
  46. :label="itemName"
  47. prop="handlerTypeItemsOrigin"
  48. :rules="[{ required: true, message: `请选择${itemName}`, trigger: 'change' }]"
  49. >
  50. <el-select
  51. v-model="form.handlerTypeItemsOrigin"
  52. multiple
  53. filterable
  54. remote
  55. class="w100"
  56. reserve-keyword
  57. placeholder="请填写用户名称"
  58. remote-show-suffix
  59. :remote-method="remoteMethod"
  60. :loading="loading"
  61. @change="getSelectValue"
  62. value-key="id"
  63. collapse-tags
  64. collapse-tags-tooltip
  65. >
  66. <el-option v-for="item in userList" :key="item.id" :label="item.name" :value="item" />
  67. </el-select>
  68. </el-form-item>
  69. <!-- 部门 -->
  70. <el-form-item
  71. v-if="[4].includes(form.handlerType)"
  72. :label="itemName"
  73. prop="handlerTypeItemsOrigin"
  74. :rules="[{ required: true, message: `请选择${itemName}`, trigger: 'change' }]"
  75. >
  76. <VTreeDrop
  77. :data="orgData"
  78. checkable
  79. keyField="id"
  80. titleField="name"
  81. v-model="form.handlerTypeItemsOrigin"
  82. @checked-change="selectOrg1"
  83. dropPlaceholder="指定部门"
  84. dropdownWidthFixed
  85. clearable
  86. searchPlaceholder="指定部门名称"
  87. checkedButtonText="查看已选"
  88. :cascade="false"
  89. />
  90. <!-- <el-tree-select
  91. :props="{ label: 'name' }"
  92. node-key="id"
  93. class="w100"
  94. ref="treeSelectRef"
  95. v-model="form.handlerTypeItemsOrigin"
  96. :data="orgData"
  97. multiple
  98. :render-after-expand="false"
  99. show-checkbox
  100. check-strictly
  101. default-expand-all
  102. filterable
  103. @check="selectOrg"
  104. collapse-tags
  105. collapse-tags-tooltip
  106. />-->
  107. </el-form-item>
  108. <el-form-item label="否决按钮" prop="canReject">
  109. <el-switch v-model="form.canReject" inline-prompt active-text="启用" inactive-text="禁用" />
  110. </el-form-item>
  111. <el-form-item label="执行模式" prop="executeMode" :rules="[{ required: true, message: '请选择执行模式', trigger: 'change' }]">
  112. <el-select v-model="form.executeMode" class="w100" placeholder="请选择执行模式">
  113. <el-option v-for="item in baseData.executeModeOptions" :key="item.key" :label="item.value" :value="item.key" />
  114. </el-select>
  115. </el-form-item>
  116. <el-form-item label="支持会签" prop="canStartCountersign">
  117. <el-switch v-model="form.canStartCountersign" inline-prompt active-text="支持" inactive-text="不支持" />
  118. </el-form-item>
  119. <el-form-item
  120. label="会签策略"
  121. prop="countersignPolicy"
  122. :rules="[{ required: true, message: '请选择会签策略', trigger: 'change' }]"
  123. v-if="form.canStartCountersign"
  124. >
  125. <el-select v-model="form.countersignPolicy" class="w100" placeholder="请选择会签策略">
  126. <el-option v-for="item in baseData.dynamicPolicyOptions" :key="item.key" :label="item.value" :value="item.key" />
  127. </el-select>
  128. </el-form-item>
  129. <el-form-item label="实例化模式" prop="instanceMode" :rules="[{ required: true, message: '请选择实例化模式', trigger: 'change' }]">
  130. <el-select v-model="form.instanceMode" class="w100" placeholder="请选择实例化模式">
  131. <el-option v-for="item in baseData.instanceModeOptions" :key="item.key" :label="item.value" :value="item.key" />
  132. </el-select>
  133. </el-form-item>
  134. <el-form-item
  135. label="动态策略"
  136. prop="instancePolicy"
  137. :rules="[{ required: true, message: '请选择动态策略', trigger: 'change' }]"
  138. v-if="form.instanceMode === 1"
  139. >
  140. <el-select v-model="form.instancePolicy" class="w100" placeholder="请选择动态策略" @change="selectInstancePolicy">
  141. <el-option v-for="item in baseData.dynamicPolicyOptions" :key="item.key" :label="item.value" :value="item.key" />
  142. </el-select>
  143. </el-form-item>
  144. <el-form-item
  145. label="动态终止标识"
  146. prop="terminalDynamicMark"
  147. :rules="[{ required: true, message: '请选择动态终止标识', trigger: 'change' }]"
  148. v-if="form.instanceMode === 1"
  149. >
  150. <el-select v-model="form.terminalDynamicMark" class="w100" placeholder="请选择动态终止标识">
  151. <el-option v-for="item in baseData.dynamicStrategyOptions" :key="item.key" :label="item.value" :value="item.key" />
  152. </el-select>
  153. </el-form-item>
  154. <el-form-item label="标识" prop="tag" :rules="[{ required: false, message: '请填写标识', trigger: 'blur' }]">
  155. <el-input v-model="form.tag" placeholder="请填写标识" type="textarea" :autosize="{ minRows: 4, maxRows: 8 }"></el-input>
  156. </el-form-item>
  157. </el-form>
  158. </div>
  159. </template>
  160. <script lang="ts" setup name="flowNodeEnd">
  161. import { onMounted, reactive, ref, watch } from 'vue';
  162. import { getSelectList, queryUser } from '@/api/system/workflow';
  163. import { getCanUseOrg } from '@/api/system/user';
  164. import { removeDuplicate } from '@/utils/arrayOperation';
  165. import { VTreeDrop } from '@wsfe/vue-tree';
  166. // 定义属性
  167. const props = defineProps({
  168. modelValue: {
  169. type: Object,
  170. default: () => {},
  171. },
  172. baseData: {
  173. type: Object,
  174. default: () => {},
  175. },
  176. });
  177. // 注意:ref不能与model一样,相同的话表单双向绑定将会失效
  178. const form = reactive<Record<string, any>>({
  179. ...props.modelValue, // 传入的数据
  180. stepTypeName: '结束节点',
  181. stepType: 2, // 节点类型(开始1 结束2)
  182. businessType: null, // 业务类型
  183. handlerType: null, // 办理者类型
  184. handlerTypeItemsOrigin: [], // 办理者类型
  185. handlerTypeItems: '[]', // 办理者类型
  186. canReject: false, // 否决按钮
  187. executeMode: null, // 执行模式
  188. canStartCountersign: false, // 支持会签
  189. countersignPolicy: null, // 会签策略
  190. instanceMode: null, // 实例化模式
  191. instancePolicy: null, // 动态策略
  192. terminalDynamicMark: null, // 动态终止标识
  193. tag: '', // 标识
  194. });
  195. const emits = defineEmits(['update:modelValue']); // 定义事件
  196. const loading = ref(false); // 加载
  197. watch(
  198. () => form,
  199. () => {
  200. form.stepTypeName = form.name + '节点';
  201. emits('update:modelValue', Object.assign(props.modelValue, form));
  202. },
  203. { deep: true }
  204. );
  205. // 选择处理人获取数据
  206. // 下拉内容
  207. const selectList = ref<EmptyArrayType>() as any;
  208. // 会签
  209. const itemName = ref<string>('');
  210. const changeOptions = (e: any) => {
  211. form.handlerTypeItemsOrigin = [];
  212. form.handlerTypeItems = '[]';
  213. itemName.value = baseData.handlerTypeOptions[e].label;
  214. if ([0, 1, 2].includes(e)) {
  215. getSelectList(e).then((res: any) => {
  216. selectList.value = res.result ?? [];
  217. });
  218. }
  219. if (e === 4) {
  220. getOrgListFn();
  221. }
  222. };
  223. // 远程搜索用户名称
  224. // 指定用户列表
  225. const userList = ref<EmptyArrayType>([]);
  226. const remoteMethod = (query: string) => {
  227. if (query !== '') {
  228. loading.value = true;
  229. queryUser({ name: query }).then((res: any) => {
  230. loading.value = false;
  231. const newUsers = res.result.map((item: any) => {
  232. return {
  233. ...item,
  234. name: !item.name.includes('-') ? item.name + '-' + item.organization.name : item.name,
  235. };
  236. });
  237. userList.value = removeDuplicate([...newUsers, ...userList.value], 'id');
  238. });
  239. }
  240. };
  241. // 获取可用组织
  242. const orgData = ref<EmptyArrayType>([]);
  243. const getOrgListFn = () => {
  244. getCanUseOrg().then((res: any) => {
  245. orgData.value = res?.result ?? [];
  246. });
  247. };
  248. // 获取选择对象
  249. const getSelectValue = (query: any[]) => {
  250. let arr: EmptyArrayType = [];
  251. if ([0, 1, 2].includes(form.handlerType)) {
  252. arr = query;
  253. } else if ([3].includes(form.handlerType)) {
  254. arr = query.map((item: any) => ({ key: item.id, value: item.name }));
  255. }
  256. // 使用模板字符串
  257. form.handlerTypeItems = `${JSON.stringify(arr)}`;
  258. };
  259. // 选择部门
  260. const treeSelectRef = ref<RefType>();
  261. const selectOrg = () => {
  262. const currentNode = treeSelectRef.value.getCheckedNodes();
  263. let arr = currentNode.map((item: any) => ({ key: item.id, value: item.name }));
  264. // 使用模板字符串
  265. form.handlerTypeItems = `${JSON.stringify(arr)}`;
  266. };
  267. const selectOrg1 = (value:any)=>{
  268. let arr = value.map((item: any) => ({ key: item.id, value: item.name }));
  269. // 使用模板字符串
  270. form.handlerTypeItems = `${JSON.stringify(arr)}`;
  271. form.handlerTypeItemsOrigin = value.map((item: any) => item.id);
  272. ruleFormRef.value.validateField('handlerTypeItemsOrigin')
  273. }
  274. // 选择动态策略
  275. const ruleFormRef = ref<RefType>();
  276. const selectInstancePolicy = (val: string | number) => {
  277. let item = baseData.dynamicPolicyOptions.filter((item: any) => item.key === val)[0];
  278. if (item.items && item.items.length) {
  279. baseData.dynamicStrategyOptions = item.items;
  280. }
  281. ruleFormRef.value.resetFields('terminalDynamicMark');
  282. form.terminalDynamicMark = null;
  283. };
  284. const baseData = reactive<any>({
  285. businessTypeOptions: <EmptyArrayType>[], // 业务类型
  286. countersignMode: <EmptyArrayType>[], // 会签
  287. handlerTypeOptions: <EmptyArrayType>[], // 办理者类型
  288. dynamicStrategyOptions: <EmptyArrayType>[], // 动态策略
  289. executeModeOptions: <EmptyArrayType>[], // 执行模式
  290. dynamicPolicyOptions: <EmptyArrayType>[], // 会签策略
  291. instanceModeOptions: <EmptyArrayType>[], // 实例化模式
  292. });
  293. onMounted(async () => {
  294. const { stepTypeOptions, businessTypeOptions, handlerTypeOptions, countersignMode, dynamicPolicyOptions, executeModeOptions, instanceModeOptions } =
  295. props.baseData;
  296. baseData.businessTypeOptions = businessTypeOptions; // 业务类型
  297. baseData.stepTypeOptions = stepTypeOptions; // 节点类型
  298. baseData.handlerTypeOptions = handlerTypeOptions.map((item: any) => ({
  299. // 办理者类型
  300. value: item.key,
  301. label: item.value,
  302. }));
  303. baseData.executeModeOptions = executeModeOptions; // 执行模式
  304. baseData.countersignMode = countersignMode; // 支持发起会签
  305. baseData.dynamicPolicyOptions = dynamicPolicyOptions; // 会签策略
  306. baseData.instanceModeOptions = instanceModeOptions; // 实例模式
  307. // 合并表单
  308. Object.assign(form, props.modelValue);
  309. if (form.handlerTypeItems.includes('[')) {
  310. switch (form.handlerType) {
  311. case 0:
  312. case 1:
  313. case 2:
  314. form.handlerTypeItemsOrigin = JSON.parse(form.handlerTypeItems);
  315. break;
  316. case 3:
  317. const users = JSON.parse(form.handlerTypeItems);
  318. userList.value = form.handlerTypeItemsOrigin = users.map((item: any) => ({ id: item.key, name: item.value }));
  319. break;
  320. case 4:
  321. form.handlerTypeItemsOrigin = JSON.parse(form.handlerTypeItems).map((v: any) => v.key);
  322. break;
  323. default:
  324. break;
  325. }
  326. }
  327. if ([0, 1, 2].includes(form.handlerType)) {
  328. const res: any = await getSelectList(form.handlerType);
  329. selectList.value = res.result ?? [];
  330. if (baseData.handlerTypeOptions.length) itemName.value = baseData.handlerTypeOptions[form.handlerType].label;
  331. } else if ([3].includes(form.handlerType)) {
  332. if (baseData.handlerTypeOptions.length) itemName.value = baseData.handlerTypeOptions[form.handlerType].label;
  333. } else if ([4].includes(form.handlerType)) {
  334. if (baseData.handlerTypeOptions.length) itemName.value = baseData.handlerTypeOptions[form.handlerType].label;
  335. getOrgListFn();
  336. }
  337. if (form.instancePolicy || form.instancePolicy === 0) {
  338. let item = baseData.dynamicPolicyOptions.filter((item: any) => item.key === form.instancePolicy)[0];
  339. if (item.items && item.items.length) {
  340. baseData.dynamicStrategyOptions = item.items;
  341. }
  342. }
  343. });
  344. // 导入属性及方法给外部调用
  345. defineExpose({
  346. ruleFormRef,
  347. });
  348. </script>
  349. <style lang="scss">
  350. .vtree-tree-drop__wrapper {
  351. width: 100%;
  352. }
  353. </style>