提交 | 用户 | 时间
|
3e359e
|
1 |
<template> |
H |
2 |
|
|
3 |
<!-- 第一步,通过流程定义的列表,选择对应的流程 --> |
|
4 |
<ContentWrap v-if="!selectProcessDefinition" v-loading="loading"> |
|
5 |
<el-tabs tab-position="left" v-model="categoryActive"> |
|
6 |
<el-tab-pane |
|
7 |
:label="category.name" |
|
8 |
:name="category.code" |
|
9 |
:key="category.code" |
|
10 |
v-for="category in categoryList" |
|
11 |
> |
|
12 |
<el-row :gutter="20"> |
|
13 |
<el-col |
|
14 |
:lg="6" |
|
15 |
:sm="12" |
|
16 |
:xs="24" |
|
17 |
v-for="definition in categoryProcessDefinitionList" |
|
18 |
:key="definition.id" |
|
19 |
> |
|
20 |
<el-card |
|
21 |
shadow="hover" |
|
22 |
class="mb-20px cursor-pointer" |
|
23 |
@click="handleSelect(definition)" |
|
24 |
> |
|
25 |
<template #default> |
|
26 |
<div class="flex"> |
|
27 |
<el-image :src="definition.icon" class="w-32px h-32px" /> |
|
28 |
<el-text class="!ml-10px" size="large">{{ definition.name }}</el-text> |
|
29 |
</div> |
|
30 |
</template> |
|
31 |
</el-card> |
|
32 |
</el-col> |
|
33 |
</el-row> |
|
34 |
</el-tab-pane> |
|
35 |
</el-tabs> |
|
36 |
</ContentWrap> |
|
37 |
|
|
38 |
<!-- 第二步,填写表单,进行流程的提交 --> |
|
39 |
<ContentWrap v-else> |
|
40 |
<el-card class="box-card"> |
|
41 |
<div class="clearfix"> |
|
42 |
<span class="el-icon-document">申请信息【{{ selectProcessDefinition.name }}】</span> |
|
43 |
<el-button style="float: right" type="primary" @click="selectProcessDefinition = undefined"> |
|
44 |
<Icon icon="ep:delete" /> 选择其它流程 |
|
45 |
</el-button> |
|
46 |
</div> |
|
47 |
<el-col :span="16" :offset="6" style="margin-top: 20px"> |
|
48 |
<form-create |
|
49 |
:rule="detailForm.rule" |
|
50 |
v-model:api="fApi" |
|
51 |
v-model="detailForm.value" |
|
52 |
:option="detailForm.option" |
|
53 |
@submit="submitForm" |
|
54 |
> |
|
55 |
<template #type-startUserSelect> |
|
56 |
<el-col :span="24"> |
|
57 |
<el-card class="mb-10px"> |
|
58 |
<template #header>指定审批人</template> |
|
59 |
<el-form |
|
60 |
:model="startUserSelectAssignees" |
|
61 |
:rules="startUserSelectAssigneesFormRules" |
|
62 |
ref="startUserSelectAssigneesFormRef" |
|
63 |
> |
|
64 |
<el-form-item |
|
65 |
v-for="userTask in startUserSelectTasks" |
|
66 |
:key="userTask.id" |
|
67 |
:label="`任务【${userTask.name}】`" |
|
68 |
:prop="userTask.id" |
|
69 |
> |
|
70 |
<el-select |
|
71 |
v-model="startUserSelectAssignees[userTask.id]" |
|
72 |
multiple |
|
73 |
placeholder="请选择审批人" |
|
74 |
> |
|
75 |
<el-option |
|
76 |
v-for="user in userList" |
|
77 |
:key="user.id" |
|
78 |
:label="user.nickname" |
|
79 |
:value="user.id" |
|
80 |
/> |
|
81 |
</el-select> |
|
82 |
</el-form-item> |
|
83 |
</el-form> |
|
84 |
</el-card> |
|
85 |
</el-col> |
|
86 |
</template> |
|
87 |
</form-create> |
|
88 |
</el-col> |
|
89 |
</el-card> |
|
90 |
<!-- 流程图预览 --> |
|
91 |
<ProcessInstanceBpmnViewer :bpmn-xml="bpmnXML as any" /> |
|
92 |
</ContentWrap> |
|
93 |
</template> |
|
94 |
<script lang="ts" setup> |
|
95 |
import * as DefinitionApi from '@/api/bpm/definition' |
|
96 |
import * as ProcessInstanceApi from '@/api/bpm/processInstance' |
|
97 |
import { decodeFields, setConfAndFields2 } from '@/utils/formCreate' |
|
98 |
import type { ApiAttrs } from '@form-create/element-ui/types/config' |
|
99 |
import ProcessInstanceBpmnViewer from '../detail/ProcessInstanceBpmnViewer.vue' |
|
100 |
import { CategoryApi } from '@/api/bpm/category' |
|
101 |
import { useTagsViewStore } from '@/store/modules/tagsView' |
|
102 |
import * as UserApi from '@/api/system/user' |
|
103 |
|
|
104 |
defineOptions({ name: 'BpmProcessInstanceCreate' }) |
|
105 |
|
|
106 |
const route = useRoute() // 路由 |
|
107 |
const { push, currentRoute } = useRouter() // 路由 |
|
108 |
const message = useMessage() // 消息 |
|
109 |
const { delView } = useTagsViewStore() // 视图操作 |
|
110 |
|
|
111 |
const processInstanceId = route.query.processInstanceId |
|
112 |
const loading = ref(true) // 加载中 |
|
113 |
const categoryList = ref([]) // 分类的列表 |
|
114 |
const categoryActive = ref('') // 选中的分类 |
|
115 |
const processDefinitionList = ref([]) // 流程定义的列表 |
|
116 |
|
|
117 |
/** 查询列表 */ |
|
118 |
const getList = async () => { |
|
119 |
loading.value = true |
|
120 |
try { |
|
121 |
// 流程分类 |
|
122 |
categoryList.value = await CategoryApi.getCategorySimpleList() |
|
123 |
if (categoryList.value.length > 0) { |
|
124 |
categoryActive.value = categoryList.value[0].code |
|
125 |
} |
|
126 |
// 流程定义 |
|
127 |
processDefinitionList.value = await DefinitionApi.getProcessDefinitionList({ |
|
128 |
suspensionState: 1 |
|
129 |
}) |
|
130 |
|
|
131 |
// 如果 processInstanceId 非空,说明是重新发起 |
|
132 |
if (processInstanceId?.length > 0) { |
|
133 |
const processInstance = await ProcessInstanceApi.getProcessInstance(processInstanceId) |
|
134 |
if (!processInstance) { |
|
135 |
message.error('重新发起流程失败,原因:流程实例不存在') |
|
136 |
return |
|
137 |
} |
|
138 |
const processDefinition = processDefinitionList.value.find( |
|
139 |
(item) => item.key == processInstance.processDefinition?.key |
|
140 |
) |
|
141 |
if (!processDefinition) { |
|
142 |
message.error('重新发起流程失败,原因:流程定义不存在') |
|
143 |
return |
|
144 |
} |
|
145 |
await handleSelect(processDefinition, processInstance.formVariables) |
|
146 |
} |
|
147 |
} finally { |
|
148 |
loading.value = false |
|
149 |
} |
|
150 |
} |
|
151 |
|
|
152 |
/** 选中分类对应的流程定义列表 */ |
|
153 |
const categoryProcessDefinitionList = computed(() => { |
|
154 |
return processDefinitionList.value.filter((item) => item.category == categoryActive.value) |
|
155 |
}) |
|
156 |
|
|
157 |
// ========== 表单相关 ========== |
|
158 |
const fApi = ref<ApiAttrs>() |
|
159 |
const detailForm = ref({ |
|
160 |
rule: [], |
|
161 |
option: {}, |
|
162 |
value: {} |
|
163 |
}) // 流程表单详情 |
|
164 |
const selectProcessDefinition = ref() // 选择的流程定义 |
|
165 |
|
|
166 |
// 指定审批人 |
|
167 |
const bpmnXML = ref(null) // BPMN 数据 |
|
168 |
const startUserSelectTasks = ref([]) // 发起人需要选择审批人的用户任务列表 |
|
169 |
const startUserSelectAssignees = ref({}) // 发起人选择审批人的数据 |
|
170 |
const startUserSelectAssigneesFormRef = ref() // 发起人选择审批人的表单 Ref |
|
171 |
const startUserSelectAssigneesFormRules = ref({}) // 发起人选择审批人的表单 Rules |
|
172 |
const userList = ref<any[]>([]) // 用户列表 |
|
173 |
|
|
174 |
/** 处理选择流程的按钮操作 **/ |
|
175 |
const handleSelect = async (row, formVariables) => { |
|
176 |
// 设置选择的流程 |
|
177 |
selectProcessDefinition.value = row |
|
178 |
|
|
179 |
// 重置指定审批人 |
|
180 |
startUserSelectTasks.value = [] |
|
181 |
startUserSelectAssignees.value = {} |
|
182 |
startUserSelectAssigneesFormRules.value = {} |
|
183 |
|
|
184 |
// 情况一:流程表单 |
|
185 |
if (row.formType == 10) { |
|
186 |
// 设置表单 |
|
187 |
// 注意:需要从 formVariables 中,移除不在 row.formFields 的值。 |
|
188 |
// 原因是:后端返回的 formVariables 里面,会有一些非表单的信息。例如说,某个流程节点的审批人。 |
|
189 |
// 这样,就可能导致一个流程被审批不通过后,重新发起时,会直接后端报错!!! |
|
190 |
const allowedFields = decodeFields(row.formFields).map((fieldObj: any) => fieldObj.field) |
|
191 |
for (const key in formVariables) { |
|
192 |
if (!allowedFields.includes(key)) { |
|
193 |
delete formVariables[key] |
|
194 |
} |
|
195 |
} |
|
196 |
setConfAndFields2(detailForm, row.formConf, row.formFields, formVariables) |
|
197 |
|
|
198 |
// 加载流程图 |
|
199 |
const processDefinitionDetail = await DefinitionApi.getProcessDefinition(row.id) |
|
200 |
if (processDefinitionDetail) { |
|
201 |
bpmnXML.value = processDefinitionDetail.bpmnXml |
|
202 |
startUserSelectTasks.value = processDefinitionDetail.startUserSelectTasks |
|
203 |
|
|
204 |
// 设置指定审批人 |
|
205 |
if (startUserSelectTasks.value?.length > 0) { |
|
206 |
detailForm.value.rule.push({ |
|
207 |
type: 'startUserSelect', |
|
208 |
props: { |
|
209 |
title: '指定审批人' |
|
210 |
} |
|
211 |
}) |
|
212 |
// 设置校验规则 |
|
213 |
for (const userTask of startUserSelectTasks.value) { |
|
214 |
startUserSelectAssignees.value[userTask.id] = [] |
|
215 |
startUserSelectAssigneesFormRules.value[userTask.id] = [ |
|
216 |
{ required: true, message: '请选择审批人', trigger: 'blur' } |
|
217 |
] |
|
218 |
} |
|
219 |
// 加载用户列表 |
|
220 |
userList.value = await UserApi.getSimpleUserList() |
|
221 |
} |
|
222 |
} |
|
223 |
// 情况二:业务表单 |
|
224 |
} else if (row.formCustomCreatePath) { |
|
225 |
await push({ |
|
226 |
path: row.formCustomCreatePath |
|
227 |
}) |
|
228 |
// 这里暂时无需加载流程图,因为跳出到另外个 Tab; |
|
229 |
} |
|
230 |
} |
|
231 |
|
|
232 |
/** 提交按钮 */ |
|
233 |
const submitForm = async (formData) => { |
|
234 |
if (!fApi.value || !selectProcessDefinition.value) { |
|
235 |
return |
|
236 |
} |
|
237 |
// 如果有指定审批人,需要校验 |
|
238 |
if (startUserSelectTasks.value?.length > 0) { |
|
239 |
await startUserSelectAssigneesFormRef.value.validate() |
|
240 |
} |
|
241 |
|
|
242 |
// 提交请求 |
|
243 |
fApi.value.btn.loading(true) |
|
244 |
try { |
|
245 |
await ProcessInstanceApi.createProcessInstance({ |
|
246 |
processDefinitionId: selectProcessDefinition.value.id, |
|
247 |
variables: formData, |
|
248 |
startUserSelectAssignees: startUserSelectAssignees.value |
|
249 |
}) |
|
250 |
// 提示 |
|
251 |
message.success('发起流程成功') |
|
252 |
// 跳转回去 |
|
253 |
delView(unref(currentRoute)) |
|
254 |
await push({ |
|
255 |
name: 'BpmProcessInstanceMy' |
|
256 |
}) |
|
257 |
} finally { |
|
258 |
fApi.value.btn.loading(false) |
|
259 |
} |
|
260 |
} |
|
261 |
|
|
262 |
/** 初始化 */ |
|
263 |
onMounted(() => { |
|
264 |
getList() |
|
265 |
}) |
|
266 |
</script> |