|
| 1 | +<template> |
| 2 | + <ContentWrap :bodyStyle="{ padding: '10px 20px 0' }"> |
| 3 | + <div class="processInstance-wrap-main"> |
| 4 | + <el-scrollbar> |
| 5 | + <div class="text-#878c93 h-15px">编号:{{ selectProcessDefinition.id }}</div> |
| 6 | + <el-divider class="!my-8px" /> |
| 7 | + |
| 8 | + <div class="flex items-center justify-between gap-5 mb-10px h-40px"> |
| 9 | + <div class="text-26px font-bold mb-5px">{{ selectProcessDefinition.name }}</div> |
| 10 | + <el-button style="float: right" type="primary" @click="handleCancel"> |
| 11 | + <Icon icon="ep:delete" /> 选择其它流程 |
| 12 | + </el-button> |
| 13 | + </div> |
| 14 | + <!-- 中间主要内容tab栏 --> |
| 15 | + <el-tabs v-model="activeTab"> |
| 16 | + <!-- 表单信息 --> |
| 17 | + <el-tab-pane label="表单填写" name="form"> |
| 18 | + <div class="form-scroll-area"> |
| 19 | + <el-scrollbar> |
| 20 | + <el-row> |
| 21 | + <el-col :span="17"> |
| 22 | + <form-create |
| 23 | + :rule="detailForm.rule" |
| 24 | + v-model:api="fApi" |
| 25 | + v-model="detailForm.value" |
| 26 | + :option="detailForm.option" |
| 27 | + @submit="submitForm" |
| 28 | + > |
| 29 | + <template #type-startUserSelect> |
| 30 | + <el-col :span="24"> |
| 31 | + <el-card class="mb-10px"> |
| 32 | + <template #header>指定审批人</template> |
| 33 | + <el-form |
| 34 | + :model="startUserSelectAssignees" |
| 35 | + :rules="startUserSelectAssigneesFormRules" |
| 36 | + ref="startUserSelectAssigneesFormRef" |
| 37 | + > |
| 38 | + <el-form-item |
| 39 | + v-for="userTask in startUserSelectTasks" |
| 40 | + :key="userTask.id" |
| 41 | + :label="`任务【${userTask.name}】`" |
| 42 | + :prop="userTask.id" |
| 43 | + > |
| 44 | + <el-select |
| 45 | + v-model="startUserSelectAssignees[userTask.id]" |
| 46 | + multiple |
| 47 | + placeholder="请选择审批人" |
| 48 | + > |
| 49 | + <el-option |
| 50 | + v-for="user in userList" |
| 51 | + :key="user.id" |
| 52 | + :label="user.nickname" |
| 53 | + :value="user.id" |
| 54 | + /> |
| 55 | + </el-select> |
| 56 | + </el-form-item> |
| 57 | + </el-form> |
| 58 | + </el-card> |
| 59 | + </el-col> |
| 60 | + </template> |
| 61 | + </form-create> |
| 62 | + </el-col> |
| 63 | + |
| 64 | + <el-col :span="6" :offset="1"> |
| 65 | + <!-- 流程时间线 --> |
| 66 | + <ProcessInstanceTimeline |
| 67 | + ref="timelineRef" |
| 68 | + :approve-nodes="approveNodes" |
| 69 | + :show-status-icon="false" |
| 70 | + candidateField="candidateUserList" |
| 71 | + /> |
| 72 | + </el-col> |
| 73 | + </el-row> |
| 74 | + </el-scrollbar> |
| 75 | + </div> |
| 76 | + </el-tab-pane> |
| 77 | + <!-- 流程图 --> |
| 78 | + <el-tab-pane label="流程图" name="diagram"> |
| 79 | + <div class="form-scroll-area"> |
| 80 | + <!-- 流程图预览 --> |
| 81 | + <ProcessInstanceBpmnViewer :bpmn-xml="bpmnXML" /> |
| 82 | + </div> |
| 83 | + </el-tab-pane> |
| 84 | + </el-tabs> |
| 85 | + |
| 86 | + <!-- 底部操作栏 --> |
| 87 | + <div class="b-t-solid border-t-1px border-[var(--el-border-color)]"> |
| 88 | + <!-- 操作栏按钮 --> |
| 89 | + <div |
| 90 | + v-if="activeTab === 'form'" |
| 91 | + class="h-50px bottom-10 text-14px flex items-center color-#32373c dark:color-#fff font-bold btn-container" |
| 92 | + > |
| 93 | + <el-button plain type="success" @click="submitForm"> |
| 94 | + <Icon icon="ep:select" /> 发起 |
| 95 | + </el-button> |
| 96 | + <el-button plain type="danger" @click="handleCancel"> |
| 97 | + <Icon icon="ep:close" /> 取消 |
| 98 | + </el-button> |
| 99 | + </div> |
| 100 | + </div> |
| 101 | + </el-scrollbar> |
| 102 | + </div> |
| 103 | + </ContentWrap> |
| 104 | +</template> |
| 105 | +<script lang="ts" setup> |
| 106 | +import { setConfAndFields2 } from '@/utils/formCreate' |
| 107 | +import ProcessInstanceBpmnViewer from '../detail/ProcessInstanceBpmnViewer.vue' |
| 108 | +import ProcessInstanceTimeline from '../detail/ProcessInstanceTimeline.vue' |
| 109 | +import type { ApiAttrs } from '@form-create/element-ui/types/config' |
| 110 | +import { useTagsViewStore } from '@/store/modules/tagsView' |
| 111 | +import * as ProcessInstanceApi from '@/api/bpm/processInstance' |
| 112 | +import * as DefinitionApi from '@/api/bpm/definition' |
| 113 | +import * as UserApi from '@/api/system/user' |
| 114 | +
|
| 115 | +defineOptions({ name: 'ProcessDefinitionDetail' }) |
| 116 | +const props = defineProps<{ |
| 117 | + selectProcessDefinition: any |
| 118 | +}>() |
| 119 | +const { push, currentRoute } = useRouter() // 路由 |
| 120 | +const message = useMessage() // 消息弹窗 |
| 121 | +const { delView } = useTagsViewStore() // 视图操作 |
| 122 | +
|
| 123 | +const detailForm: any = ref({ |
| 124 | + rule: [], |
| 125 | + option: {}, |
| 126 | + value: {} |
| 127 | +}) // 流程表单详情 |
| 128 | +const fApi = ref<ApiAttrs>() |
| 129 | +// 指定审批人 |
| 130 | +const startUserSelectAssigneesFormRef = ref() // 发起人选择审批人的表单 Ref |
| 131 | +const startUserSelectTasks: any = ref([]) // 发起人需要选择审批人的用户任务列表 |
| 132 | +const startUserSelectAssignees = ref({}) // 发起人选择审批人的数据 |
| 133 | +const startUserSelectAssigneesFormRules = ref({}) // 发起人选择审批人的表单 Rules |
| 134 | +const userList = ref<any[]>([]) // 用户列表 |
| 135 | +const bpmnXML: any = ref(null) // BPMN 数据 |
| 136 | +/** 当前的Tab */ |
| 137 | +const activeTab = ref('form') |
| 138 | +const emit = defineEmits(['cancel']) |
| 139 | +// 审批节点信息 |
| 140 | +const approveNodes = ref<ProcessInstanceApi.ApprovalNodeInfo[]>([]) |
| 141 | +
|
| 142 | +/** 设置表单信息、获取流程图数据 **/ |
| 143 | +const initProcessInfo = async (row, formVariables?) => { |
| 144 | + // 重置指定审批人 |
| 145 | + startUserSelectTasks.value = [] |
| 146 | + startUserSelectAssignees.value = {} |
| 147 | + startUserSelectAssigneesFormRules.value = {} |
| 148 | +
|
| 149 | + // 情况一:流程表单 |
| 150 | + if (row.formType == 10) { |
| 151 | + // 设置表单 |
| 152 | + setConfAndFields2(detailForm, row.formConf, row.formFields, formVariables) |
| 153 | + await nextTick() |
| 154 | + fApi.value?.btn.show(false) // 隐藏提交按钮 |
| 155 | + // 获取流程审批信息 |
| 156 | + getApprovalDetail(row) |
| 157 | +
|
| 158 | + // 加载流程图 |
| 159 | + const processDefinitionDetail = await DefinitionApi.getProcessDefinition(row.id) |
| 160 | + if (processDefinitionDetail) { |
| 161 | + bpmnXML.value = processDefinitionDetail.bpmnXml |
| 162 | + startUserSelectTasks.value = processDefinitionDetail.startUserSelectTasks |
| 163 | +
|
| 164 | + // 设置指定审批人 |
| 165 | + if (startUserSelectTasks.value?.length > 0) { |
| 166 | + detailForm.value.rule.push({ |
| 167 | + type: 'startUserSelect', |
| 168 | + props: { |
| 169 | + title: '指定审批人' |
| 170 | + } |
| 171 | + }) |
| 172 | + // 设置校验规则 |
| 173 | + for (const userTask of startUserSelectTasks.value) { |
| 174 | + startUserSelectAssignees.value[userTask.id] = [] |
| 175 | + startUserSelectAssigneesFormRules.value[userTask.id] = [ |
| 176 | + { required: true, message: '请选择审批人', trigger: 'blur' } |
| 177 | + ] |
| 178 | + } |
| 179 | + // 加载用户列表 |
| 180 | + userList.value = await UserApi.getSimpleUserList() |
| 181 | + } |
| 182 | + } |
| 183 | + // 情况二:业务表单 |
| 184 | + } else if (row.formCustomCreatePath) { |
| 185 | + await push({ |
| 186 | + path: row.formCustomCreatePath |
| 187 | + }) |
| 188 | + // 这里暂时无需加载流程图,因为跳出到另外个 Tab; |
| 189 | + } |
| 190 | +} |
| 191 | +
|
| 192 | +/** 获取审批详情 */ |
| 193 | +const getApprovalDetail = async (row) => { |
| 194 | + try { |
| 195 | + const param = { |
| 196 | + processDefinitionId: row.id |
| 197 | + } |
| 198 | + const data = await ProcessInstanceApi.getApprovalDetail(param) |
| 199 | + if (!data) { |
| 200 | + message.error('查询不到审批详情信息!') |
| 201 | + return |
| 202 | + } |
| 203 | + // 获取审批节点,显示 Timeline 的数据 |
| 204 | + approveNodes.value = data.approveNodes |
| 205 | + } finally { |
| 206 | + } |
| 207 | +} |
| 208 | +/** 提交按钮 */ |
| 209 | +const submitForm = async (formData) => { |
| 210 | + if (!fApi.value || props.selectProcessDefinition) { |
| 211 | + return |
| 212 | + } |
| 213 | + // 如果有指定审批人,需要校验 |
| 214 | + if (startUserSelectTasks.value?.length > 0) { |
| 215 | + await startUserSelectAssigneesFormRef.value.validate() |
| 216 | + } |
| 217 | +
|
| 218 | + // 提交请求 |
| 219 | + fApi.value.btn.loading(true) |
| 220 | + try { |
| 221 | + await ProcessInstanceApi.createProcessInstance({ |
| 222 | + processDefinitionId: props.selectProcessDefinition.id, |
| 223 | + variables: formData || detailForm.value.value, |
| 224 | + startUserSelectAssignees: startUserSelectAssignees.value |
| 225 | + }) |
| 226 | + // 提示 |
| 227 | + message.success('发起流程成功') |
| 228 | + // 跳转回去 |
| 229 | + delView(unref(currentRoute)) |
| 230 | + await push({ |
| 231 | + name: 'BpmProcessInstanceMy' |
| 232 | + }) |
| 233 | + } finally { |
| 234 | + fApi.value.btn.loading(false) |
| 235 | + } |
| 236 | +} |
| 237 | +
|
| 238 | +const handleCancel = () => { |
| 239 | + emit('cancel') |
| 240 | +} |
| 241 | +
|
| 242 | +defineExpose({ initProcessInfo }) |
| 243 | +</script> |
| 244 | + |
| 245 | +<style lang="scss" scoped> |
| 246 | +$wrap-padding-height: 20px; |
| 247 | +$wrap-margin-height: 15px; |
| 248 | +$button-height: 51px; |
| 249 | +$process-header-height: 194px; |
| 250 | +
|
| 251 | +.processInstance-wrap-main { |
| 252 | + height: calc( |
| 253 | + 100vh - var(--top-tool-height) - var(--tags-view-height) - var(--app-footer-height) - 35px |
| 254 | + ); |
| 255 | + max-height: calc( |
| 256 | + 100vh - var(--top-tool-height) - var(--tags-view-height) - var(--app-footer-height) - 35px |
| 257 | + ); |
| 258 | + overflow: auto; |
| 259 | +
|
| 260 | + .form-scroll-area { |
| 261 | + height: calc( |
| 262 | + 100vh - var(--top-tool-height) - var(--tags-view-height) - var(--app-footer-height) - 35px - |
| 263 | + $process-header-height - 40px |
| 264 | + ); |
| 265 | + max-height: calc( |
| 266 | + 100vh - var(--top-tool-height) - var(--tags-view-height) - var(--app-footer-height) - 35px - |
| 267 | + $process-header-height - 40px |
| 268 | + ); |
| 269 | + overflow: auto; |
| 270 | + } |
| 271 | +} |
| 272 | +
|
| 273 | +.form-box { |
| 274 | + :deep(.el-card) { |
| 275 | + border: none; |
| 276 | + } |
| 277 | +} |
| 278 | +</style> |
0 commit comments