Merge branch 'feature/bpm' of https://gitee.com/yudaocode/yudao-ui-admin-vue3 into feature/bpm

This commit is contained in:
jason 2025-02-27 09:05:36 +08:00
commit 91c3b94283
5 changed files with 290 additions and 75 deletions

View File

@ -306,6 +306,9 @@ const addNode = (type: number) => {
}, },
timeoutSetting: { timeoutSetting: {
enable: false enable: false
},
multiInstanceSetting: {
enable: false
} }
} }
} }

View File

@ -814,26 +814,84 @@ export const TRIGGER_TYPES: DictDataVO[] = [
export type ChildProcessSetting = { export type ChildProcessSetting = {
calledProcessDefinitionKey: string calledProcessDefinitionKey: string
calledProcessDefinitionName: string calledProcessDefinitionName: string
async: boolean, async: boolean
inVariables?: IOParameter[], inVariables?: IOParameter[]
outVariables?: IOParameter[], outVariables?: IOParameter[]
skipStartUserNode: boolean, skipStartUserNode: boolean
startUserSetting: StartUserSetting, startUserSetting: StartUserSetting
timeoutSetting: TimeoutSetting, timeoutSetting: TimeoutSetting
multiInstanceSetting: MultiInstanceSetting
} }
export type IOParameter = { export type IOParameter = {
source: string source: string
sourceExpression: string
target: string target: string
targetExpression: string
} }
export type StartUserSetting = { export type StartUserSetting = {
type: number type: ChildProcessStartUserTypeEnum
formField?: string formField?: string
emptyType?: number emptyType?: ChildProcessStartUserEmptyTypeEnum
} }
export type TimeoutSetting = { export type TimeoutSetting = {
enable: boolean, enable: boolean
type?: DelayTypeEnum, type?: DelayTypeEnum
timeExpression?: string, timeExpression?: string
} }
export type MultiInstanceSetting = {
enable: boolean
sequential?: boolean
completeRatio?: number
sourceType?: ChildProcessMultiInstanceSourceTypeEnum
source?: string
}
export enum ChildProcessStartUserTypeEnum {
/**
*
*/
MAIN_PROCESS_START_USER = 1,
/**
*
*/
FROM_FORM = 2
}
export const CHILD_PROCESS_START_USER_TYPE = [
{ label: '同主流程发起人', value: ChildProcessStartUserTypeEnum.MAIN_PROCESS_START_USER },
{ label: '表单', value: ChildProcessStartUserTypeEnum.FROM_FORM }
]
export enum ChildProcessStartUserEmptyTypeEnum {
/**
*
*/
MAIN_PROCESS_START_USER = 1,
/**
*
*/
CHILD_PROCESS_ADMIN = 2,
/**
*
*/
MAIN_PROCESS_ADMIN = 3
}
export const CHILD_PROCESS_START_USER_EMPTY_TYPE = [
{ label: '同主流程发起人', value: ChildProcessStartUserEmptyTypeEnum.MAIN_PROCESS_START_USER },
{ label: '子流程管理员', value: ChildProcessStartUserEmptyTypeEnum.CHILD_PROCESS_ADMIN },
{ label: '主流程管理员', value: ChildProcessStartUserEmptyTypeEnum.MAIN_PROCESS_ADMIN }
]
export enum ChildProcessMultiInstanceSourceTypeEnum {
/**
*
*/
FIXED_QUANTITY = 1,
/**
*
*/
DIGITAL_FORM = 2,
/**
*
*/
MULTI_FORM = 3
}
export const CHILD_PROCESS_MULTI_INSTANCE_SOURCE_TYPE = [
{ label: '固定数量', value: ChildProcessMultiInstanceSourceTypeEnum.FIXED_QUANTITY },
{ label: '数字表单', value: ChildProcessMultiInstanceSourceTypeEnum.DIGITAL_FORM }, // TODO @lesanDIGITAL 改成 NUMBER和 Element plus 更接近?
{ label: '多项表单', value: ChildProcessMultiInstanceSourceTypeEnum.MULTI_FORM } // TODO @lesan多选表单multiple 是这个解释。另外 MULTI => MULTIPLE
]

View File

@ -95,7 +95,7 @@
<Icon <Icon
icon="ep:delete" icon="ep:delete"
:size="18" :size="18"
@click="deleteVariable(configForm.inVariables, index)" @click="deleteVariable(index, configForm.inVariables)"
/> />
</div> </div>
</div> </div>
@ -103,7 +103,6 @@
<Icon icon="ep:plus" class="mr-5px" />添加一行 <Icon icon="ep:plus" class="mr-5px" />添加一行
</el-button> </el-button>
</el-form-item> </el-form-item>
<!-- TODO @lesanasyncsourcetarget 几个字段会告警 -->
<el-form-item <el-form-item
v-if="configForm.async === false" v-if="configForm.async === false"
label="子→主变量传递" label="子→主变量传递"
@ -152,7 +151,7 @@
<Icon <Icon
icon="ep:delete" icon="ep:delete"
:size="18" :size="18"
@click="deleteVariable(configForm.outVariables, index)" @click="deleteVariable(index, configForm.outVariables)"
/> />
</div> </div>
</div> </div>
@ -160,22 +159,30 @@
<Icon icon="ep:plus" class="mr-5px" />添加一行 <Icon icon="ep:plus" class="mr-5px" />添加一行
</el-button> </el-button>
</el-form-item> </el-form-item>
<!-- TODO @lesanstartUserTypestartUserEmptyType 要不走写下枚举类 -->
<el-form-item label="子流程发起人" prop="startUserType"> <el-form-item label="子流程发起人" prop="startUserType">
<el-radio-group v-model="configForm.startUserType"> <el-radio-group v-model="configForm.startUserType">
<el-radio :value="1">同主流程发起人</el-radio> <el-radio
<el-radio :value="2">表单</el-radio> v-for="item in CHILD_PROCESS_START_USER_TYPE"
:key="item.value"
:value="item.value"
>
{{ item.label }}
</el-radio>
</el-radio-group> </el-radio-group>
</el-form-item> </el-form-item>
<el-form-item <el-form-item
v-if="configForm.startUserType === 2" v-if="configForm.startUserType === ChildProcessStartUserTypeEnum.FROM_FORM"
label="当子流程发起人为空时" label="当子流程发起人为空时"
prop="startUserType" prop="startUserType"
> >
<el-radio-group v-model="configForm.startUserEmptyType"> <el-radio-group v-model="configForm.startUserEmptyType">
<el-radio :value="1">同主流程发起人</el-radio> <el-radio
<el-radio :value="2">子流程管理员</el-radio> v-for="item in CHILD_PROCESS_START_USER_EMPTY_TYPE"
<el-radio :value="3">主流程管理员</el-radio> :key="item.value"
:value="item.value"
>
{{ item.label }}
</el-radio>
</el-radio-group> </el-radio-group>
</el-form-item> </el-form-item>
<el-form-item <el-form-item
@ -246,6 +253,73 @@
<el-text>后进入下一节点</el-text> <el-text>后进入下一节点</el-text>
</el-form-item> </el-form-item>
</div> </div>
<el-divider content-position="left">多实例设置</el-divider>
<el-form-item label="启用开关" prop="multiInstanceEnable">
<el-switch
v-model="configForm.multiInstanceEnable"
active-text="开启"
inactive-text="关闭"
/>
</el-form-item>
<div v-if="configForm.multiInstanceEnable">
<el-form-item prop="sequential">
<el-switch
v-model="configForm.sequential"
active-text="串行"
inactive-text="并行"
/>
</el-form-item>
<el-form-item prop="completeRatio">
<el-text>完成比例(%)</el-text>
<el-input-number
class="ml-10px"
v-model="configForm.completeRatio"
:min="10"
:max="100"
:step="10"
/>
</el-form-item>
<el-form-item prop="multiInstanceSourceType">
<el-text>多实例来源</el-text>
<el-select
class="ml-10px w-200px!"
v-model="configForm.multiInstanceSourceType"
@change="handleMultiInstanceSourceTypeChange"
>
<el-option
v-for="item in CHILD_PROCESS_MULTI_INSTANCE_SOURCE_TYPE"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
<!-- TODO @lesan枚举 -->
<el-form-item v-if="configForm.multiInstanceSourceType === 1">
<el-input-number v-model="configForm.multiInstanceSource" :min="1" />
</el-form-item>
<el-form-item v-if="configForm.multiInstanceSourceType === 2">
<el-select class="w-200px!" v-model="configForm.multiInstanceSource">
<el-option
v-for="(field, fIdx) in digitalFormFieldOptions"
:key="fIdx"
:label="field.title"
:value="field.field"
/>
</el-select>
</el-form-item>
<el-form-item v-if="configForm.multiInstanceSourceType === 3">
<el-select class="w-200px!" v-model="configForm.multiInstanceSource">
<el-option
v-for="(field, fIdx) in multiFormFieldOptions"
:key="fIdx"
:label="field.title"
:value="field.field"
/>
</el-select>
</el-form-item>
</div>
</el-form> </el-form>
</div> </div>
</el-tab-pane> </el-tab-pane>
@ -268,7 +342,14 @@ import {
TIME_UNIT_TYPES, TIME_UNIT_TYPES,
TimeUnitType, TimeUnitType,
DelayTypeEnum, DelayTypeEnum,
DELAY_TYPE DELAY_TYPE,
IOParameter,
ChildProcessStartUserTypeEnum,
CHILD_PROCESS_START_USER_TYPE,
ChildProcessStartUserEmptyTypeEnum,
CHILD_PROCESS_START_USER_EMPTY_TYPE,
CHILD_PROCESS_MULTI_INSTANCE_SOURCE_TYPE,
ChildProcessMultiInstanceSourceTypeEnum
} from '../consts' } from '../consts'
import { useWatchNode, useDrawer, useNodeName, useFormFieldsAndStartUser } from '../node' import { useWatchNode, useDrawer, useNodeName, useFormFieldsAndStartUser } from '../node'
import { parseFormFields } from '@/components/FormCreate/src/utils' import { parseFormFields } from '@/components/FormCreate/src/utils'
@ -307,25 +388,57 @@ const formRules = reactive({
timeoutEnable: [{ required: true, message: '超时设置是否开启不能为空', trigger: 'change' }], timeoutEnable: [{ required: true, message: '超时设置是否开启不能为空', trigger: 'change' }],
timeoutType: [{ required: true, message: '超时设置时间不能为空', trigger: 'change' }], timeoutType: [{ required: true, message: '超时设置时间不能为空', trigger: 'change' }],
timeDuration: [{ required: true, message: '超时设置时间不能为空', trigger: 'change' }], timeDuration: [{ required: true, message: '超时设置时间不能为空', trigger: 'change' }],
dateTime: [{ required: true, message: '超时设置时间不能为空', trigger: 'change' }] dateTime: [{ required: true, message: '超时设置时间不能为空', trigger: 'change' }],
multiInstanceEnable: [{ required: true, message: '多实例设置不能为空', trigger: 'change' }]
}) })
const configForm = ref({ type ChildProcessFormType = {
async: boolean
calledProcessDefinitionKey: string
skipStartUserNode: boolean
inVariables?: IOParameter[]
outVariables?: IOParameter[]
startUserType: ChildProcessStartUserTypeEnum
startUserEmptyType: ChildProcessStartUserEmptyTypeEnum
startUserFormField: string
timeoutEnable: boolean
timeoutType: DelayTypeEnum
timeDuration: number
timeUnit: TimeUnitType
dateTime: string
multiInstanceEnable: boolean
sequential: boolean
completeRatio: number
multiInstanceSourceType: ChildProcessMultiInstanceSourceTypeEnum
multiInstanceSource: string
}
const configForm = ref<ChildProcessFormType>({
async: false, async: false,
calledProcessDefinitionKey: '', calledProcessDefinitionKey: '',
skipStartUserNode: false, skipStartUserNode: false,
inVariables: [], inVariables: [],
outVariables: [], outVariables: [],
startUserType: 1, startUserType: ChildProcessStartUserTypeEnum.MAIN_PROCESS_START_USER,
startUserEmptyType: 1, startUserEmptyType: ChildProcessStartUserEmptyTypeEnum.MAIN_PROCESS_START_USER,
startUserFormField: '', startUserFormField: '',
timeoutEnable: false, timeoutEnable: false,
timeoutType: DelayTypeEnum.FIXED_TIME_DURATION, timeoutType: DelayTypeEnum.FIXED_TIME_DURATION,
timeDuration: 1, timeDuration: 1,
timeUnit: TimeUnitType.HOUR, timeUnit: TimeUnitType.HOUR,
dateTime: '' dateTime: '',
multiInstanceEnable: false,
sequential: false,
completeRatio: 100,
multiInstanceSourceType: ChildProcessMultiInstanceSourceTypeEnum.FIXED_QUANTITY,
multiInstanceSource: ''
}) })
const childProcessOptions = ref() const childProcessOptions = ref()
const formFieldOptions = useFormFieldsAndStartUser() const formFieldOptions = useFormFieldsAndStartUser()
const digitalFormFieldOptions = computed(() => {
return formFieldOptions.filter((item) => item.type === 'inputNumber')
})
const multiFormFieldOptions = computed(() => {
return formFieldOptions.filter((item) => item.type === 'select' || item.type === 'checkbox')
})
const childFormFieldOptions = ref() const childFormFieldOptions = ref()
// //
@ -334,9 +447,8 @@ const saveConfig = async () => {
if (!formRef) return false if (!formRef) return false
const valid = await formRef.value.validate() const valid = await formRef.value.validate()
if (!valid) return false if (!valid) return false
// TODO @lesan option
const childInfo = childProcessOptions.value.find( const childInfo = childProcessOptions.value.find(
(option) => option.key === configForm.value.calledProcessDefinitionKey (option: any) => option.key === configForm.value.calledProcessDefinitionKey
) )
currentNode.value.name = nodeName.value! currentNode.value.name = nodeName.value!
if (currentNode.value.childProcessSetting) { if (currentNode.value.childProcessSetting) {
@ -371,6 +483,20 @@ const saveConfig = async () => {
configForm.value.dateTime configForm.value.dateTime
} }
} }
// 8.
currentNode.value.childProcessSetting.multiInstanceSetting = {
enable: configForm.value.multiInstanceEnable
}
if (configForm.value.multiInstanceEnable) {
currentNode.value.childProcessSetting.multiInstanceSetting.sequential =
configForm.value.sequential
currentNode.value.childProcessSetting.multiInstanceSetting.completeRatio =
configForm.value.completeRatio
currentNode.value.childProcessSetting.multiInstanceSetting.sourceType =
configForm.value.multiInstanceSourceType
currentNode.value.childProcessSetting.multiInstanceSetting.source =
configForm.value.multiInstanceSource
}
} }
currentNode.value.showText = `调用子流程:${childInfo.name}` currentNode.value.showText = `调用子流程:${childInfo.name}`
@ -378,7 +504,6 @@ const saveConfig = async () => {
return true return true
} }
// //
// TODO @lesaninVariablesoutVariables
const showChildProcessNodeConfig = (node: SimpleFlowNode) => { const showChildProcessNodeConfig = (node: SimpleFlowNode) => {
nodeName.value = node.name nodeName.value = node.name
if (node.childProcessSetting) { if (node.childProcessSetting) {
@ -415,21 +540,34 @@ const showChildProcessNodeConfig = (node: SimpleFlowNode) => {
configForm.value.dateTime = node.childProcessSetting.timeoutSetting.timeExpression ?? '' configForm.value.dateTime = node.childProcessSetting.timeoutSetting.timeExpression ?? ''
} }
} }
// 8.
configForm.value.multiInstanceEnable =
node.childProcessSetting.multiInstanceSetting.enable ?? false
if (configForm.value.multiInstanceEnable) {
configForm.value.sequential =
node.childProcessSetting.multiInstanceSetting.sequential ?? false
configForm.value.completeRatio =
node.childProcessSetting.multiInstanceSetting.completeRatio ?? 100
configForm.value.multiInstanceSourceType =
node.childProcessSetting.multiInstanceSetting.sourceType ??
ChildProcessMultiInstanceSourceTypeEnum.FIXED_QUANTITY
configForm.value.multiInstanceSource =
node.childProcessSetting.multiInstanceSetting.source ?? ''
}
} }
loadFormInfo() loadFormInfo()
} }
defineExpose({ openDrawer, showChildProcessNodeConfig }) // defineExpose({ openDrawer, showChildProcessNodeConfig }) //
// TODO @lesan arr cursor quick fix const addVariable = (arr?: IOParameter[]) => {
const addVariable = (arr) => { arr?.push({
arr.push({
source: '', source: '',
target: '' target: ''
}) })
} }
const deleteVariable = (arr, index: number) => { const deleteVariable = (index: number, arr?: IOParameter[]) => {
arr.splice(index, 1) arr?.splice(index, 1)
} }
const handleCalledElementChange = () => { const handleCalledElementChange = () => {
configForm.value.inVariables = [] configForm.value.inVariables = []
@ -461,6 +599,9 @@ const getIsoTimeDuration = () => {
} }
return strTimeDuration return strTimeDuration
} }
const handleMultiInstanceSourceTypeChange = () => {
configForm.value.multiInstanceSource = ''
}
onMounted(async () => { onMounted(async () => {
childProcessOptions.value = await getModelList(undefined) childProcessOptions.value = await getModelList(undefined)

View File

@ -48,7 +48,7 @@ import { getDefaultConditionNodeName } from '../utils'
import { useFormFieldsAndStartUser, getConditionShowText } from '../node' import { useFormFieldsAndStartUser, getConditionShowText } from '../node'
import Condition from './components/Condition.vue' import Condition from './components/Condition.vue'
import { cloneDeep } from 'lodash-es' import { cloneDeep } from 'lodash-es'
const message = useMessage() //
defineOptions({ defineOptions({
name: 'ConditionNodeConfig' name: 'ConditionNodeConfig'
}) })
@ -69,14 +69,18 @@ const condition = ref<any>({
conditionExpression: '', conditionExpression: '',
conditionGroups: { conditionGroups: {
and: true, and: true,
conditions: [{ conditions: [
and: true, {
rules: [{ and: true,
opCode: '==', rules: [
leftSide: '', {
rightSide: '' opCode: '==',
}] leftSide: '',
}] rightSide: ''
}
]
}
]
} }
}) })
const open = () => { const open = () => {
@ -90,14 +94,18 @@ const open = () => {
conditionExpression: '', conditionExpression: '',
conditionGroups: { conditionGroups: {
and: true, and: true,
conditions: [{ conditions: [
and: true, {
rules: [{ and: true,
opCode: '==', rules: [
leftSide: '', {
rightSide: '' opCode: '==',
}] leftSide: '',
}] rightSide: ''
}
]
}
]
} }
} }
} }
@ -162,8 +170,14 @@ const saveConfig = async () => {
currentNode.value.conditionSetting = cloneDeep({ currentNode.value.conditionSetting = cloneDeep({
...currentNode.value.conditionSetting, ...currentNode.value.conditionSetting,
conditionType: condition.value?.conditionType, conditionType: condition.value?.conditionType,
conditionExpression: condition.value?.conditionType === ConditionType.EXPRESSION ? condition.value?.conditionExpression : undefined, conditionExpression:
conditionGroups: condition.value?.conditionType === ConditionType.RULE ? condition.value?.conditionGroups : undefined condition.value?.conditionType === ConditionType.EXPRESSION
? condition.value?.conditionExpression
: undefined,
conditionGroups:
condition.value?.conditionType === ConditionType.RULE
? condition.value?.conditionGroups
: undefined
}) })
} }
settingVisible.value = false settingVisible.value = false

View File

@ -157,25 +157,24 @@ const initProcessInfo = async (row: any, formVariables?: any) => {
} }
/** 预测流程节点会因为输入的参数值而产生新的预测结果值,所以需重新预测一次 */ /** 预测流程节点会因为输入的参数值而产生新的预测结果值,所以需重新预测一次 */
// TODO @ @lesan watch(
// watch( detailForm.value,
// detailForm.value, (newValue) => {
// (newValue) => { if (newValue && Object.keys(newValue.value).length > 0) {
// if (newValue && Object.keys(newValue.value).length > 0) { //
// // tempStartUserSelectAssignees.value = startUserSelectAssignees.value
// tempStartUserSelectAssignees.value = startUserSelectAssignees.value startUserSelectAssignees.value = {}
// startUserSelectAssignees.value = {} //
// // getApprovalDetail({
// getApprovalDetail({ id: props.selectProcessDefinition.id,
// id: props.selectProcessDefinition.id, processVariablesStr: JSON.stringify(newValue.value) // GET String JSON
// processVariablesStr: JSON.stringify(newValue.value) // GET String JSON })
// }) }
// } },
// }, {
// { immediate: true
// immediate: true }
// } )
// )
/** 获取审批详情 */ /** 获取审批详情 */
const getApprovalDetail = async (row: any) => { const getApprovalDetail = async (row: any) => {