From a1d7e81859f554f3a53680cc35f0f49bf1f77098 Mon Sep 17 00:00:00 2001
From: wwf <1971391498@qq.com>
Date: 星期四, 14 五月 2026 14:37:02 +0800
Subject: [PATCH] 导入项目
---
src/views/bpm/processInstance/create/ProcessDefinitionDetail.vue | 357 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 357 insertions(+), 0 deletions(-)
diff --git a/src/views/bpm/processInstance/create/ProcessDefinitionDetail.vue b/src/views/bpm/processInstance/create/ProcessDefinitionDetail.vue
new file mode 100644
index 0000000..c1ad017
--- /dev/null
+++ b/src/views/bpm/processInstance/create/ProcessDefinitionDetail.vue
@@ -0,0 +1,357 @@
+<template>
+ <ContentWrap :bodyStyle="{ padding: '10px 20px 0' }">
+ <div class="processInstance-wrap-main">
+ <el-scrollbar>
+ <div class="text-#878c93 h-15px">娴佺▼锛歿{ selectProcessDefinition.name }}</div>
+ <el-divider class="!my-8px" />
+
+ <!-- 涓棿涓昏鍐呭 tab 鏍� -->
+ <el-tabs v-model="activeTab">
+ <!-- 琛ㄥ崟淇℃伅 -->
+ <el-tab-pane label="琛ㄥ崟濉啓" name="form">
+ <div class="form-scroll-area" v-loading="processInstanceStartLoading">
+ <el-scrollbar>
+ <el-row>
+ <el-col :span="17">
+ <form-create
+ :rule="detailForm.rule"
+ v-model:api="fApi"
+ v-model="detailForm.value"
+ :option="detailForm.option"
+ @submit="submitForm"
+ />
+ </el-col>
+
+ <el-col :span="6" :offset="1">
+ <!-- 娴佺▼鏃堕棿绾� -->
+ <ProcessInstanceTimeline
+ ref="timelineRef"
+ :activity-nodes="activityNodes"
+ :show-status-icon="false"
+ @select-user-confirm="selectUserConfirm"
+ />
+ </el-col>
+ </el-row>
+ </el-scrollbar>
+ </div>
+ </el-tab-pane>
+ <!-- 娴佺▼鍥� -->
+ <el-tab-pane label="娴佺▼鍥�" name="diagram">
+ <div class="form-scroll-area">
+ <!-- BPMN 娴佺▼鍥鹃瑙� -->
+ <ProcessInstanceBpmnViewer
+ :bpmn-xml="bpmnXML"
+ v-if="BpmModelType.BPMN === selectProcessDefinition.modelType"
+ />
+
+ <!-- Simple 娴佺▼鍥鹃瑙� -->
+ <ProcessInstanceSimpleViewer
+ :simple-json="simpleJson"
+ v-if="BpmModelType.SIMPLE === selectProcessDefinition.modelType"
+ />
+ </div>
+ </el-tab-pane>
+ </el-tabs>
+
+ <!-- 搴曢儴鎿嶄綔鏍� -->
+ <div class="b-t-solid border-t-1px border-[var(--el-border-color)]">
+ <!-- 鎿嶄綔鏍忔寜閽� -->
+ <div
+ v-if="activeTab === 'form'"
+ class="h-50px bottom-10 text-14px flex items-center color-#32373c dark:color-#fff font-bold btn-container"
+ >
+ <el-button plain type="success" @click="submitForm">
+ <Icon icon="ep:select" /> 鍙戣捣
+ </el-button>
+ <el-button plain type="danger" @click="handleCancel">
+ <Icon icon="ep:close" /> 鍙栨秷
+ </el-button>
+ </div>
+ </div>
+ </el-scrollbar>
+ </div>
+ </ContentWrap>
+</template>
+<script lang="ts" setup>
+import { decodeFields, setConfAndFields2 } from '@/utils/formCreate'
+import { BpmModelType, BpmModelFormType } from '@/utils/constants'
+import {
+ CandidateStrategy,
+ NodeId,
+ FieldPermissionType
+} from '@/components/SimpleProcessDesignerV2/src/consts'
+import ProcessInstanceBpmnViewer from '../detail/ProcessInstanceBpmnViewer.vue'
+import ProcessInstanceSimpleViewer from '../detail/ProcessInstanceSimpleViewer.vue'
+import ProcessInstanceTimeline from '../detail/ProcessInstanceTimeline.vue'
+import type { ApiAttrs } from '@form-create/element-ui/types/config'
+import { useTagsViewStore } from '@/store/modules/tagsView'
+import * as ProcessInstanceApi from '@/api/bpm/processInstance'
+import * as DefinitionApi from '@/api/bpm/definition'
+import { ApprovalNodeInfo } from '@/api/bpm/processInstance'
+import formCreate from '@form-create/element-ui'
+
+defineOptions({ name: 'ProcessDefinitionDetail' })
+const props = defineProps<{
+ selectProcessDefinition: any
+}>()
+const emit = defineEmits(['cancel'])
+const processInstanceStartLoading = ref(false) // 娴佺▼瀹炰緥鍙戣捣涓�
+const { push, currentRoute } = useRouter() // 璺敱
+const message = useMessage() // 娑堟伅寮圭獥
+const { delView } = useTagsViewStore() // 瑙嗗浘鎿嶄綔
+
+const detailForm: any = ref({
+ rule: [],
+ option: {},
+ value: {}
+}) // 娴佺▼琛ㄥ崟璇︽儏
+const fApi = ref<ApiAttrs>()
+// 鎸囧畾瀹℃壒浜�
+const startUserSelectTasks: any = ref([]) // 鍙戣捣浜洪渶瑕侀�夋嫨瀹℃壒浜烘垨鎶勯�佷汉鐨勪换鍔″垪琛�
+const startUserSelectAssignees = ref({}) // 鍙戣捣浜洪�夋嫨瀹℃壒浜虹殑鏁版嵁
+const tempStartUserSelectAssignees = ref({}) // 鍘嗗彶鍙戣捣浜洪�夋嫨瀹℃壒浜虹殑鏁版嵁锛岀敤浜庢瘡娆¤〃鍗曞彉鏇存椂锛屼复鏃朵繚瀛�
+const bpmnXML: any = ref(null) // BPMN 鏁版嵁
+const simpleJson = ref<string | undefined>() // Simple 璁捐鍣ㄦ暟鎹� json 鏍煎紡
+
+const activeTab = ref('form') // 褰撳墠鐨� Tab
+const activityNodes = ref<ProcessInstanceApi.ApprovalNodeInfo[]>([]) // 瀹℃壒鑺傜偣淇℃伅
+
+/** 璁剧疆琛ㄥ崟淇℃伅銆佽幏鍙栨祦绋嬪浘鏁版嵁 **/
+const initProcessInfo = async (row: any, formVariables?: any) => {
+ // 閲嶇疆鎸囧畾瀹℃壒浜�
+ startUserSelectTasks.value = []
+ startUserSelectAssignees.value = {}
+
+ // 鎯呭喌涓�锛氭祦绋嬭〃鍗�
+ if (row.formType == BpmModelFormType.NORMAL) {
+ // 璁剧疆琛ㄥ崟
+ // 娉ㄦ剰锛氶渶瑕佷粠 formVariables 涓紝绉婚櫎涓嶅湪 row.formFields 鐨勫�笺��
+ // 鍘熷洜鏄細鍚庣杩斿洖鐨� formVariables 閲岄潰锛屼細鏈変竴浜涢潪琛ㄥ崟鐨勪俊鎭�備緥濡傝锛屾煇涓祦绋嬭妭鐐圭殑瀹℃壒浜恒��
+ // 杩欐牱锛屽氨鍙兘瀵艰嚧涓�涓祦绋嬭瀹℃壒涓嶉�氳繃鍚庯紝閲嶆柊鍙戣捣鏃讹紝浼氱洿鎺ュ悗绔姤閿欙紒锛侊紒
+ const formApi = formCreate.create(decodeFields(row.formFields))
+ const allowedFields = formApi.fields()
+ for (const key in formVariables) {
+ if (!allowedFields.includes(key)) {
+ delete formVariables[key]
+ }
+ }
+ setConfAndFields2(detailForm, row.formConf, row.formFields, formVariables)
+
+ await nextTick()
+ fApi.value?.btn.show(false) // 闅愯棌鎻愪氦鎸夐挳
+
+ // 鑾峰彇娴佺▼瀹℃壒淇℃伅,褰撳啀娆″彂璧锋椂锛屾祦绋嬪鎵硅妭鐐硅鏍规嵁鍘熷琛ㄥ崟鍙傛暟棰勬祴鍑烘潵
+ await getApprovalDetail({
+ id: row.id,
+ processVariablesStr: JSON.stringify(formVariables)
+ })
+
+ // 鍔犺浇娴佺▼鍥�
+ const processDefinitionDetail = await DefinitionApi.getProcessDefinition(row.id)
+ if (processDefinitionDetail) {
+ bpmnXML.value = processDefinitionDetail.bpmnXml
+ simpleJson.value = processDefinitionDetail.simpleModel
+ }
+ // 鎯呭喌浜岋細涓氬姟琛ㄥ崟
+ } else if (row.formCustomCreatePath) {
+ await push({
+ path: row.formCustomCreatePath
+ })
+ // 杩欓噷鏆傛椂鏃犻渶鍔犺浇娴佺▼鍥撅紝鍥犱负璺冲嚭鍒板彟澶栦釜 Tab锛�
+ }
+}
+
+/** 棰勬祴娴佺▼鑺傜偣浼氬洜涓鸿緭鍏ョ殑鍙傛暟鍊艰�屼骇鐢熸柊鐨勯娴嬬粨鏋滃�硷紝鎵�浠ラ渶閲嶆柊棰勬祴涓�娆� */
+watch(
+ detailForm.value,
+ (newValue) => {
+ if (newValue && Object.keys(newValue.value).length > 0) {
+ // 璁板綍涔嬪墠鐨勮妭鐐瑰鎵逛汉
+ tempStartUserSelectAssignees.value = startUserSelectAssignees.value
+ startUserSelectAssignees.value = {}
+ // 鍔犺浇鏈�鏂扮殑瀹℃壒璇︽儏
+ getApprovalDetail({
+ id: props.selectProcessDefinition.id,
+ processVariablesStr: JSON.stringify(newValue.value) // 瑙e喅 GET 鏃犳硶浼犻�掑璞$殑闂锛屽悗绔� String 鍐嶈浆 JSON
+ })
+ }
+ },
+ {
+ immediate: true
+ }
+)
+
+/** 鑾峰彇瀹℃壒璇︽儏 */
+const getApprovalDetail = async (row: any) => {
+ try {
+ // TODO 鑾峰彇瀹℃壒璇︽儏锛岃缃� activityId 涓哄彂璧蜂汉鑺傜偣锛堜负浜嗚幏鍙栧瓧娈垫潈闄愩�傛殏鏃跺彧瀵� Simple 璁捐鍣ㄦ湁鏁堬級锛汙jason锛氳繖閲屽彲浠ュ幓鎺� activityId 涔堬紵
+ const data = await ProcessInstanceApi.getApprovalDetail({
+ processDefinitionId: row.id,
+ activityId: NodeId.START_USER_NODE_ID,
+ processVariablesStr: row.processVariablesStr // 瑙e喅 GET 鏃犳硶浼犻�掑璞$殑闂锛屽悗绔� String 鍐嶈浆 JSON
+ })
+
+ if (!data) {
+ message.error('鏌ヨ涓嶅埌瀹℃壒璇︽儏淇℃伅锛�')
+ return
+ }
+ // 鑾峰彇瀹℃壒鑺傜偣锛屾樉绀� Timeline 鐨勬暟鎹�
+ activityNodes.value = data.activityNodes
+
+ // 鑾峰彇鍙戣捣浜鸿嚜閫夌殑浠诲姟
+ startUserSelectTasks.value = data.activityNodes?.filter(
+ (node: ApprovalNodeInfo) => CandidateStrategy.START_USER_SELECT === node.candidateStrategy
+ )
+ // 鎭㈠涔嬪墠鐨勯�夋嫨瀹℃壒浜�
+ if (startUserSelectTasks.value?.length > 0) {
+ for (const node of startUserSelectTasks.value) {
+ if (
+ tempStartUserSelectAssignees.value[node.id] &&
+ tempStartUserSelectAssignees.value[node.id].length > 0
+ ) {
+ startUserSelectAssignees.value[node.id] = tempStartUserSelectAssignees.value[node.id]
+ } else {
+ startUserSelectAssignees.value[node.id] = []
+ }
+ }
+ }
+
+ // 鑾峰彇琛ㄥ崟瀛楁鏉冮檺
+ const formFieldsPermission = data.formFieldsPermission
+ // 璁剧疆琛ㄥ崟瀛楁鏉冮檺
+ if (formFieldsPermission) {
+ Object.keys(formFieldsPermission).forEach((item) => {
+ setFieldPermission(item, formFieldsPermission[item])
+ })
+ }
+ } finally {
+ }
+}
+
+/**
+ * 璁剧疆琛ㄥ崟鏉冮檺
+ */
+const setFieldPermission = (field: string, permission: string) => {
+ if (permission === FieldPermissionType.READ) {
+ // 1. 璁剧疆瀛楁涓哄彧璇�
+ //@ts-ignore
+ fApi.value?.disabled(true, field)
+ // 2. 鍙瀛楁锛� 鍘绘帀楠岃瘉瑙勫垯
+ // fApi.value?.updateValidate(field, []); 杩欎釜鏂规硶璨屼技涓嶈捣浣滅敤锛�
+ try {
+ //@ts-ignore
+ const rule = fApi.value?.getRule(field)
+ if (rule) {
+ // 蹇呭~楠岃瘉璁剧疆涓篺alse
+ rule.$required = false
+ // 娓呯┖鎵�鏈夐獙璇佽鍒�
+ if (rule.validate) {
+ rule.validate = []
+ }
+ }
+ } catch (error) {
+ console.warn('淇敼瀛楁楠岃瘉瑙勫垯澶辫触:', error)
+ }
+ }
+ if (permission === FieldPermissionType.WRITE) {
+ //@ts-ignore
+ fApi.value?.disabled(false, field)
+ }
+ if (permission === FieldPermissionType.NONE) {
+ //@ts-ignore
+ fApi.value?.hidden(true, field)
+ }
+}
+
+/** 鎻愪氦鎸夐挳 */
+const submitForm = async () => {
+ if (!fApi.value || !props.selectProcessDefinition) {
+ return
+ }
+
+ try {
+ // 娴佺▼琛ㄥ崟鏍¢獙
+ await fApi.value.validate()
+ } catch (error) {
+ // 濡傛灉楠岃瘉澶辫触锛屾鏌ユ槸鍚︽槸鍙瀛楁鐨勯獙璇侀敊璇�
+ console.warn('琛ㄥ崟楠岃瘉澶辫触:', error)
+ return
+ }
+ // 濡傛灉鏈夋寚瀹氬鎵逛汉锛岄渶瑕佹牎楠�
+ if (startUserSelectTasks.value?.length > 0) {
+ for (const userTask of startUserSelectTasks.value) {
+ if (
+ Array.isArray(startUserSelectAssignees.value[userTask.id]) &&
+ startUserSelectAssignees.value[userTask.id].length === 0
+ )
+ return message.warning(`璇烽�夋嫨${userTask.name}鐨勫�欓�変汉`)
+ }
+ }
+
+ // 鎻愪氦璇锋眰
+ processInstanceStartLoading.value = true
+ try {
+ await ProcessInstanceApi.createProcessInstance({
+ processDefinitionId: props.selectProcessDefinition.id,
+ variables: detailForm.value.value,
+ startUserSelectAssignees: startUserSelectAssignees.value
+ })
+ // 鎻愮ず
+ message.success('鍙戣捣娴佺▼鎴愬姛')
+ // 璺宠浆鍥炲幓
+ delView(unref(currentRoute))
+ await push({
+ name: 'BpmProcessInstanceMy'
+ })
+ } finally {
+ processInstanceStartLoading.value = false
+ }
+}
+
+/** 鍙栨秷鍙戣捣瀹℃壒 */
+const handleCancel = () => {
+ emit('cancel')
+}
+
+/** 閫夋嫨鍙戣捣浜� */
+const selectUserConfirm = (id: string, userList: any[]) => {
+ startUserSelectAssignees.value[id] = userList?.map((item: any) => item.id)
+}
+
+defineExpose({ initProcessInfo })
+</script>
+
+<style lang="scss" scoped>
+$wrap-padding-height: 20px;
+$wrap-margin-height: 15px;
+$button-height: 51px;
+$process-header-height: 105px;
+
+.processInstance-wrap-main {
+ height: calc(
+ 100vh - var(--top-tool-height) - var(--tags-view-height) - var(--app-footer-height) - 35px
+ );
+ max-height: calc(
+ 100vh - var(--top-tool-height) - var(--tags-view-height) - var(--app-footer-height) - 35px
+ );
+ overflow: auto;
+
+ .form-scroll-area {
+ height: calc(
+ 100vh - var(--top-tool-height) - var(--tags-view-height) - var(--app-footer-height) - 35px -
+ $process-header-height - 40px
+ );
+ max-height: calc(
+ 100vh - var(--top-tool-height) - var(--tags-view-height) - var(--app-footer-height) - 35px -
+ $process-header-height - 40px
+ );
+ overflow: auto;
+ }
+}
+
+.form-box {
+ :deep(.el-card) {
+ border: none;
+ }
+}
+</style>
--
Gitblit v1.8.0