From 6b988bd582bfcd17fee48c476a5a6e5cc172b0d5 Mon Sep 17 00:00:00 2001 From: baoshiwei <baoshiwei@shlanbao.cn> Date: 星期三, 12 三月 2025 10:08:33 +0800 Subject: [PATCH] dev-2 --- src/bpmn/panel/TaskPanel.vue | 491 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 491 insertions(+), 0 deletions(-) diff --git a/src/bpmn/panel/TaskPanel.vue b/src/bpmn/panel/TaskPanel.vue new file mode 100644 index 0000000..a42de8a --- /dev/null +++ b/src/bpmn/panel/TaskPanel.vue @@ -0,0 +1,491 @@ +<template> + <div> + <el-form ref="formRef" size="default" :model="formData" :rules="formRules" label-width="100px"> + <el-collapse v-model="currentCollapseItem"> + <el-collapse-item name="1"> + <template #title> + <div class="collapse__title"> + <el-icon> + <InfoFilled /> + </el-icon> + 甯歌 + </div> + </template> + <div> + <el-form-item prop="id" label="鑺傜偣 ID"> + <el-input v-model="formData.id" @change="idChange"> </el-input> + </el-form-item> + <el-form-item prop="name" label="鑺傜偣鍚嶇О"> + <el-input v-model="formData.name" @change="nameChange"> </el-input> + </el-form-item> + <el-form-item v-if="showConfig.skipExpression" prop="skipExpression" label="璺宠繃琛ㄨ揪寮�"> + <el-input v-model="formData.skipExpression" @change="skipExpressionChange"> </el-input> + </el-form-item> + <el-form-item v-loading="formManageListLoading" prop="formKey" label="琛ㄥ崟鍦板潃"> + <el-select v-model="formData.formKey" clearable filterable placeholder="璇烽�夋嫨琛ㄥ崟" style="width: 260px" @change="formKeyChange"> + <el-option + v-for="item in formManageList" + :key="item.id" + :label="item.formTypeName + ':' + item.formName" + :value="item.formType + ':' + item.id" + /> + </el-select> + </el-form-item> + </div> + </el-collapse-item> + <el-collapse-item name="2"> + <template #title> + <div class="collapse__title"> + <el-icon> + <Checked /> + </el-icon> + 浠诲姟 + </div> + </template> + <div> + <el-form-item v-if="showConfig.async" prop="sync" label="鏄惁寮傛"> + <el-switch v-model="formData.async" inline-prompt active-text="鏄�" inactive-text="鍚�" @change="syncChange" /> + </el-form-item> + + <el-tabs tab-position="left" class="demo-tabs"> + <el-tab-pane label="韬唤瀛樺偍"> + <el-form-item label="鍒嗛厤浜哄憳"> + <el-input v-model="formData.assignee" @blur="blurAssignee(formData.assignee)"> + <template #append> + <el-button icon="Search" type="primary" @click="openSingleUserSelect" /> + </template> + </el-input> + </el-form-item> + <el-form-item label="鍊欓�変汉鍛�"> + <el-badge :value="selectUserLength" :max="99"> + <el-button size="small" type="primary" @click="openUserSelect">閫夋嫨浜哄憳</el-button> + </el-badge> + </el-form-item> + <el-form-item label="鍊欓�夌粍"> + <el-badge :value="selectRoleLength" :max="99"> + <el-button size="small" type="primary" @click="openRoleSelect">閫夋嫨缁�</el-button> + </el-badge> + </el-form-item> + </el-tab-pane> + + <!-- <el-tab-pane label="鍥哄畾鍊�"> + <el-form-item prop="auditUserType" label="鍒嗛厤绫诲瀷"> + <el-select v-model="formData.allocationType"> + <el-option v-for="item in AllocationTypeSelect" :key="item.id" :value="item.value" :label="item.label"> </el-option> + </el-select> + </el-form-item> + <el-form-item v-if="formData.allocationType === AllocationTypeEnum.USER" label="鍒嗛厤浜哄憳"> + <el-input v-model="formData.assignee"> + <template #append> + <el-button icon="Search" type="primary" @click="openSingleUserSelect" /> + </template> + </el-input> + </el-form-item> + <div v-if="formData.allocationType === AllocationTypeEnum.CANDIDATE"> + <el-form-item label="鍊欓�変汉鍛�"> + <el-badge :value="selectUserLength" :max="99"> + <el-button size="small" type="primary" @click="openUserSelect">閫夋嫨浜哄憳</el-button> + </el-badge> + </el-form-item> + <el-form-item label="鍊欓�夌粍"> + <el-badge :value="selectRoleLength" :max="99"> + <el-button size="small" type="primary" @click="openRoleSelect">閫夋嫨缁�</el-button> + </el-badge> + </el-form-item> + </div> + <el-form-item v-if="formData.allocationType === AllocationTypeEnum.SPECIFY && showConfig.specifyDesc" style=""> + <el-radio-group v-model="formData.specifyDesc" class="ml-4"> + <el-radio v-for="item in SpecifyDesc" :key="item.id" :value="item.value" size="large">{{ item.label }}</el-radio> + </el-radio-group> + </el-form-item> + </el-tab-pane> --> + </el-tabs> + + <el-form-item v-if="showConfig.dueDate" prop="dueDate" label="鍒版湡鏃堕棿"> + <el-input v-model="formData.dueDate" clearable @change="dueDateChange" @click="openDueDate"> + <template #append> + <el-button icon="Search" type="primary" @click="openDueDate" /> + </template> + </el-input> + </el-form-item> + <el-form-item v-if="showConfig.priority" prop="priority" label="浼樺厛绾�"> + <el-input-number v-model="formData.priority" :min="0" @change="priorityChange"> </el-input-number> + </el-form-item> + </div> + </el-collapse-item> + <el-collapse-item name="3"> + <template #title> + <div class="collapse__title"> + <el-icon> + <HelpFilled /> + </el-icon> + 澶氬疄渚� + </div> + </template> + <div> + <el-form-item label="澶氬疄渚嬬被鍨�"> + <el-select v-model="formData.multiInstanceType" @change="multiInstanceTypeChange"> + <el-option v-for="item in constant.MultiInstanceType" :key="item.id" :value="item.value" :label="item.label"> </el-option> + </el-select> + </el-form-item> + + <div v-if="formData.multiInstanceType !== MultiInstanceTypeEnum.NONE"> + <el-form-item label="闆嗗悎"> + <template #label> + <span> + 闆嗗悎 + <el-tooltip placement="top"> + <el-icon><QuestionFilled /></el-icon> + <template #content> + 灞炴�т細浣滀负琛ㄨ揪寮忚繘琛岃В鏋愩�傚鏋滆〃杈惧紡瑙f瀽涓哄瓧绗︿覆鑰屼笉鏄竴涓泦鍚堬紝<br /> + 涓嶈鏄洜涓烘湰韬厤缃殑灏辨槸闈欐�佸瓧绗︿覆鍊硷紝杩樻槸琛ㄨ揪寮忚绠楃粨鏋滀负瀛楃涓诧紝<br /> + 杩欎釜瀛楃涓查兘浼氳褰撳仛鍙橀噺鍚嶏紝骞朵粠娴佺▼鍙橀噺涓敤浜庤幏鍙栧疄闄呯殑闆嗗悎銆� + </template> + </el-tooltip> + </span> + </template> + <el-input v-model="formData.collection" @change="collectionChange"></el-input> + </el-form-item> + <el-form-item label="鍏冪礌鍙橀噺"> + <template #label> + <span> + 鍏冪礌鍙橀噺 + <el-tooltip placement="top"> + <el-icon><QuestionFilled /></el-icon> + <template #content> + 姣忓垱寤轰竴涓敤鎴蜂换鍔″墠锛屽厛浠ヨ鍏冪礌鍙橀噺涓簂abel锛岄泦鍚堜腑鐨勪竴椤逛负value锛�<br /> + 鍒涘缓锛堝眬閮級娴佺▼鍙橀噺锛岃灞�閮ㄦ祦绋嬪彉閲忚鐢ㄤ簬鎸囨淳鐢ㄦ埛浠诲姟銆�<br /> + 涓�鑸潵璇达紝璇ュ瓧绗︿覆搴斾笌鎸囧畾浜哄憳鍙橀噺鐩稿悓銆� + </template> + </el-tooltip> + </span> + </template> + <el-input v-model="formData.elementVariable" @change="elementVariableChange"> </el-input> + </el-form-item> + <el-form-item label="瀹屾垚鏉′欢"> + <template #label> + <span> + 瀹屾垚鏉′欢 + <el-tooltip placement="top"> + <el-icon><QuestionFilled /></el-icon> + <template #content> + 澶氬疄渚嬫椿鍔ㄥ湪鎵�鏈夊疄渚嬮兘瀹屾垚鏃剁粨鏉燂紝鐒惰�屼篃鍙互鎸囧畾涓�涓〃杈惧紡锛屽湪姣忎釜瀹炰緥<br /> + 缁撴潫鏃惰繘琛岃绠椼�傚綋琛ㄨ揪寮忚绠椾负true鏃讹紝灏嗛攢姣佹墍鏈夊墿浣欑殑瀹炰緥锛屽苟缁撴潫澶氬疄渚�<br /> + 娲诲姩锛岀户缁墽琛屾祦绋嬨�備緥濡� ${nrOfCompletedInstances/nrOfInstances >= 0.6 }锛�<br /> + 琛ㄧず褰撲换鍔″畬鎴�60%鏃讹紝璇ヨ妭鐐瑰氨绠楀畬鎴� + </template> + </el-tooltip> + </span> + </template> + <el-input v-model="formData.completionCondition" @change="completionConditionChange"> </el-input> + </el-form-item> + </div> + </div> + </el-collapse-item> + <el-collapse-item v-if="showConfig.taskListener" name="4"> + <template #title> + <div class="collapse__title"> + <el-icon> + <BellFilled /> + </el-icon> + 浠诲姟鐩戝惉鍣� + </div> + </template> + <div> + <TaskListener v-if="showConfig.taskListener" :element="element"></TaskListener> + </div> + </el-collapse-item> + <el-collapse-item v-if="showConfig.executionListener" name="5"> + <template #title> + <div class="collapse__title"> + <el-icon> + <BellFilled /> + </el-icon> + 鎵ц鐩戝惉鍣� + </div> + </template> + <div> + <ExecutionListener v-if="showConfig.executionListener" :element="element"></ExecutionListener> + </div> + </el-collapse-item> + + <el-form-item v-if="showConfig.isForCompensation" prop="isForCompensation" label="鏄惁涓鸿ˉ鍋�"> + <el-switch v-model="formData.isForCompensation" inline-prompt active-text="鏄�" inactive-text="鍚�" /> + </el-form-item> + <el-form-item v-if="showConfig.triggerServiceTask" prop="triggerServiceTask" label="鏈嶅姟浠诲姟鍙Е鍙�"> + <el-switch v-model="formData.triggerServiceTask" inline-prompt active-text="鏄�" inactive-text="鍚�" /> + </el-form-item> + <el-form-item v-if="showConfig.autoStoreVariables" prop="autoStoreVariables" label="鑷姩瀛樺偍鍙橀噺"> + <el-switch v-model="formData.autoStoreVariables" inline-prompt active-text="鏄�" inactive-text="鍚�" /> + </el-form-item> + <el-form-item v-if="showConfig.ruleVariablesInput" prop="skipExpression" label="杈撳叆鍙橀噺"> + <el-input v-model="formData.ruleVariablesInput"> </el-input> + </el-form-item> + <el-form-item v-if="showConfig.exclude" prop="exclude" label="鎺掗櫎"> + <el-switch v-model="formData.exclude" inline-prompt active-text="鏄�" inactive-text="鍚�" /> + </el-form-item> + <el-form-item v-if="showConfig.class" prop="class" label="绫�"> + <el-input v-model="formData.class"> </el-input> + </el-form-item> + </el-collapse> + </el-form> + <UserSelect ref="userSelectRef" :data="formData.candidateUsers" @confirm-call-back="userSelectCallBack"></UserSelect> + <UserSelect ref="singleUserSelectRef" :data="formData.assignee" :multiple="false" @confirm-call-back="singleUserSelectCallBack"></UserSelect> + <RoleSelect ref="roleSelectRef" :data="formData.candidateGroups" @confirm-call-back="roleSelectCallBack"></RoleSelect> + <DueDate ref="dueDateRef" v-model="formData.dueDate" :data="formData.dueDate" @confirm-call-back="dueDateCallBack"></DueDate> + </div> +</template> +<script setup lang="ts"> +import useParseElement from '../hooks/useParseElement'; +import usePanel from '../hooks/usePanel'; +import UserSelect from '@/components/UserSelect'; +import RoleSelect from '@/components/RoleSelect'; +import ExecutionListener from './property/ExecutionListener.vue'; +import TaskListener from './property/TaskListener.vue'; +import DueDate from './property/DueDate.vue'; +import type { ModdleElement } from 'bpmn'; +import type { TaskPanel } from 'bpmnDesign'; +import { AllocationTypeEnum, MultiInstanceTypeEnum, SpecifyDescEnum } from '@/enums/bpmn/IndexEnums'; +import { UserVO } from '@/api/system/user/types'; +import { RoleVO } from '@/api/system/role/types'; +import { selectListFormManage } from '@/api/workflow/formManage'; +import { FormManageVO } from '@/api/workflow/formManage/types'; +const formManageList = ref<FormManageVO[]>([]); +const formManageListLoading = ref(false); +interface PropType { + element: ModdleElement; +} +const props = withDefaults(defineProps<PropType>(), {}); +const { showConfig, nameChange, formKeyChange, idChange, updateProperties, getExtensionElements, createModdleElement, constant } = usePanel({ + element: toRaw(props.element) +}); +const { parseData } = useParseElement({ + element: toRaw(props.element) +}); + +const initFormData = { + id: '', + name: '', + dueDate: '', + multiInstanceType: MultiInstanceTypeEnum.NONE, + allocationType: AllocationTypeEnum.USER, + specifyDesc: SpecifyDescEnum.SPECIFY_SINGLE +}; +const formData = ref({ ...initFormData, ...parseData<TaskPanel>() }); +const assignee = ref<Partial<UserVO>>({ + userName: '' +}); +const currentCollapseItem = ref(['1', '2']); +const userSelectRef = ref<InstanceType<typeof UserSelect>>(); +const singleUserSelectRef = ref<InstanceType<typeof UserSelect>>(); +const roleSelectRef = ref<InstanceType<typeof RoleSelect>>(); +const dueDateRef = ref<InstanceType<typeof DueDate>>(); + +const openUserSelect = () => { + userSelectRef.value.open(); +}; +const openSingleUserSelect = () => { + if (formData.value.assignee?.includes('$')) { + formData.value.assignee = ''; + } + singleUserSelectRef.value.open(); +}; +const openRoleSelect = () => { + roleSelectRef.value.open(); +}; +const openDueDate = (e) => { + dueDateRef.value.openDialog(); +}; +const blurAssignee = (assignee) => { + updateProperties({ 'flowable:assignee': assignee ? assignee : undefined }); +}; +const singleUserSelectCallBack = (data: UserVO[]) => { + const user: UserVO = data.length !== 0 ? data[0] : undefined; + updateProperties({ 'flowable:assignee': user?.userId }); + assignee.value = user ? user : { userName: '' }; + formData.value.assignee = String(user?.userId); + let extensionElements = getExtensionElements(); + extensionElements.values = extensionElements.get('values').filter((item) => item.$type !== 'flowable:extAssignee'); + if (user) { + const extAssigneeElement = createModdleElement('flowable:extAssignee', { body: '' }, extensionElements); + extensionElements.get('values').push(extAssigneeElement); + extAssigneeElement.body = JSON.stringify({ userName: user.userName, userId: user.userId }); + } + if (extensionElements.values.length === 0) { + extensionElements = undefined; + } + updateProperties({ extensionElements: extensionElements }); +}; +const userSelectCallBack = (data: UserVO[]) => { + let extensionElements = getExtensionElements(); + extensionElements.values = extensionElements.values.filter((item) => item.$type !== 'flowable:extCandidateUsers'); + if (data.length === 0) { + formData.value.candidateUsers = undefined; + updateProperties({ 'flowable:candidateUsers': undefined }); + } else { + const userIds = data.map((item) => item.userId).join(','); + formData.value.candidateUsers = userIds; + updateProperties({ 'flowable:candidateUsers': userIds }); + const extCandidateUsersElement = createModdleElement('flowable:extCandidateUsers', { body: '' }, extensionElements); + extensionElements.values.push(extCandidateUsersElement); + const users = data.map((item) => { + return { + userId: item.userId, + userName: item.userName + }; + }); + extCandidateUsersElement.body = JSON.stringify(users); + } + if (extensionElements.values.length === 0) { + extensionElements = undefined; + } + updateProperties({ extensionElements: extensionElements }); +}; +const roleSelectCallBack = (data: RoleVO[]) => { + if (data.length === 0) { + formData.value.candidateGroups = ''; + updateProperties({ 'flowable:candidateGroups': undefined }); + } else { + const roleIds = data.map((item) => item.roleId).join(','); + formData.value.candidateGroups = roleIds; + updateProperties({ 'flowable:candidateGroups': roleIds }); + } +}; +const dueDateCallBack = (data: string) => { + updateProperties({ 'flowable:dueDate': data }); +}; + +const taskTabClick = (e) => { + formData.value.candidateGroups = ''; + formData.value.candidateUsers = ''; + formData.value.assignee = ''; + // formData.value.fixedAssignee = ''; + assignee.value = {}; +}; + +const syncChange = (newVal) => { + updateProperties({ 'flowable:async': newVal }); +}; +const skipExpressionChange = (newVal) => { + updateProperties({ 'flowable:skipExpression': newVal && newVal.length > 0 ? newVal : undefined }); +}; +const priorityChange = (newVal) => { + updateProperties({ 'flowable:priority': newVal }); +}; +const fixedAssigneeChange = (newVal) => { + updateProperties({ 'flowable:assignee': newVal && newVal.length > 0 ? newVal : undefined }); +}; +const multiInstanceTypeChange = (newVal) => { + if (newVal !== MultiInstanceTypeEnum.NONE) { + let loopCharacteristics = props.element.businessObject.get('loopCharacteristics'); + if (!loopCharacteristics) { + loopCharacteristics = createModdleElement('bpmn:MultiInstanceLoopCharacteristics', {}, props.element.businessObject); + } + loopCharacteristics.isSequential = newVal === MultiInstanceTypeEnum.SERIAL; + updateProperties({ loopCharacteristics: loopCharacteristics }); + } else { + updateProperties({ loopCharacteristics: undefined }); + } +}; +const collectionChange = (newVal) => { + let loopCharacteristics = props.element.businessObject.get('loopCharacteristics'); + if (!loopCharacteristics) { + loopCharacteristics = createModdleElement('bpmn:MultiInstanceLoopCharacteristics', {}, props.element.businessObject); + } + loopCharacteristics.collection = newVal && newVal.length > 0 ? newVal : undefined; + updateProperties({ loopCharacteristics: loopCharacteristics }); +}; +const elementVariableChange = (newVal) => { + let loopCharacteristics = props.element.businessObject.get('loopCharacteristics'); + if (!loopCharacteristics) { + loopCharacteristics = createModdleElement('bpmn:MultiInstanceLoopCharacteristics', {}, props.element.businessObject); + } + loopCharacteristics.elementVariable = newVal && newVal.length > 0 ? newVal : undefined; + updateProperties({ loopCharacteristics: loopCharacteristics }); +}; +const completionConditionChange = (newVal) => { + let loopCharacteristics = props.element.businessObject.get<ModdleElement>('loopCharacteristics'); + if (!loopCharacteristics) { + loopCharacteristics = createModdleElement('bpmn:MultiInstanceLoopCharacteristics', {}, props.element.businessObject); + } + if (newVal && newVal.length > 0) { + if (!loopCharacteristics.completionCondition) { + loopCharacteristics.completionCondition = createModdleElement('bpmn:Expression', { body: newVal }, loopCharacteristics); + } else { + loopCharacteristics.completionCondition.body = newVal; + } + } else { + loopCharacteristics.completionCondition = undefined; + } + updateProperties({ loopCharacteristics: loopCharacteristics }); +}; +const dueDateChange = (newVal) => { + updateProperties({ 'flowable:dueDate': newVal && newVal.length > 0 ? newVal : undefined }); +}; +const selectUserLength = computed(() => { + if (formData.value.candidateUsers) { + return formData.value.candidateUsers.split(',').length; + } else { + return 0; + } +}); +const selectRoleLength = computed(() => { + if (formData.value.candidateGroups) { + return formData.value.candidateGroups.split(',').length; + } else { + return 0; + } +}); + +onBeforeMount(() => { + const extensionElements = getExtensionElements(false); + if (extensionElements && extensionElements.get('values')) { + let extAssigneeElement = extensionElements.get('values').find((item) => item.$type === 'flowable:extAssignee'); + if (extAssigneeElement) { + assignee.value = JSON.parse(extAssigneeElement.body); + } + } + + if (formData.value.loopCharacteristics) { + const loopCharacteristics = formData.value.loopCharacteristics; + formData.value.collection = loopCharacteristics.collection || ''; + formData.value.elementVariable = loopCharacteristics.elementVariable || ''; + formData.value.completionCondition = loopCharacteristics.completionCondition?.body || ''; + formData.value.multiInstanceType = loopCharacteristics.isSequential ? MultiInstanceTypeEnum.SERIAL : MultiInstanceTypeEnum.PARALLEL; + } + + if (formData.value.assignee) { + formData.value.fixedAssignee = formData.value.assignee; + } +}); + +const formRules = ref<ElFormRules>({ + id: [{ required: true, message: '璇疯緭鍏�', trigger: 'blur' }], + name: [{ required: true, message: '璇疯緭鍏�', trigger: 'blur' }] +}); + +const AllocationTypeSelect = [ + { id: 'b9cdf970-dd91-47c0-819f-42a7010ca2a6', label: '鎸囧畾浜哄憳', value: AllocationTypeEnum.USER }, + { id: '3f7ccbcd-c464-4602-bb9d-e96649d10585', label: '鍊欓�変汉鍛�', value: AllocationTypeEnum.CANDIDATE }, + { id: 'c49065e0-7f2d-4c09-aedb-ab2d47d9a454', label: '鍙戣捣浜鸿嚜宸�', value: AllocationTypeEnum.YOURSELF }, + { id: '6ef40a03-7e9a-4898-89b2-c88fe9064542', label: '鍙戣捣浜烘寚瀹�', value: AllocationTypeEnum.SPECIFY } +]; +const SpecifyDesc = [ + { id: 'fa253b34-4335-458c-b1bc-b039e2a2b7a6', label: '鎸囧畾涓�涓汉', value: 'specifySingle' }, + { id: '7365ff54-2e05-4312-9bfb-0b8edd779c5b', label: '鎸囧畾澶氫釜浜�', value: 'specifyMultiple' } +]; + +const listFormManage = async () => { + formManageListLoading.value = true; + const res = await selectListFormManage(); + formManageList.value = res.data; + formManageListLoading.value = false; +}; +onMounted(() => { + nextTick(() => { + listFormManage(); + }); +}); +</script> + +<style lang="scss" scoped></style> -- Gitblit v1.9.3