【功能优化】触发器添加条件

This commit is contained in:
jason 2025-02-17 13:24:02 +08:00
parent 425e66b0f0
commit 6be64a219e
5 changed files with 593 additions and 150 deletions

View File

@ -735,7 +735,7 @@ export type RouterSetting = {
export type TriggerSetting = {
type: TriggerTypeEnum
httpRequestSetting?: HttpRequestTriggerSetting
normalFormSetting?: NormalFormTriggerSetting
formSettings?: FormTriggerSetting[]
}
/**
@ -769,7 +769,13 @@ export type HttpRequestTriggerSetting = {
/**
*
*/
export type NormalFormTriggerSetting = {
export type FormTriggerSetting = {
// 条件类型
conditionType?: ConditionType
// 条件表达式
conditionExpression?: string
// 条件组
conditionGroups?: ConditionGroup
// 更新表单字段
updateFormFields?: Record<string, any>
}

View File

@ -15,7 +15,10 @@ import {
AssignEmptyHandlerType,
FieldPermissionType,
HttpRequestParam,
ProcessVariableEnum
ProcessVariableEnum,
ConditionType,
ConditionGroup,
COMPARISON_OPERATORS
} from './consts'
import { parseFormFields } from '@/components/FormCreate/src/utils'
@ -543,6 +546,66 @@ export function useTaskStatusClass(taskStatus: TaskStatusEnum | undefined): stri
if (taskStatus === TaskStatusEnum.CANCEL) {
return 'status-cancel'
}
return ''
}
/** 条件组件文字展示 */
export function getConditionShowText(
conditonType: ConditionType | undefined,
conditionExpression: string | undefined,
conditionGroups: ConditionGroup | undefined,
fieldOptions: Array<Record<string, any>>
) {
let showText = ''
if (conditonType === ConditionType.EXPRESSION) {
if (conditionExpression) {
showText = `表达式:${conditionExpression}`
}
}
if (conditonType === ConditionType.RULE) {
// 条件组是否为与关系
const groupAnd = conditionGroups?.and
let warningMesg: undefined | string = undefined
const conditionGroup = conditionGroups?.conditions.map((item) => {
return (
'(' +
item.rules
.map((rule) => {
if (rule.leftSide && rule.rightSide) {
return (
getFormFieldTitle(fieldOptions, rule.leftSide) +
' ' +
getOpName(rule.opCode) +
' ' +
rule.rightSide
)
} else {
// 有一条规则不完善。提示错误
warningMesg = '请完善条件规则'
return ''
}
})
.join(item.and ? ' 且 ' : ' 或 ') +
' ) '
)
})
if (warningMesg) {
showText = ''
} else {
showText = conditionGroup!.join(groupAnd ? ' 且 ' : ' 或 ')
}
}
return showText
}
/** 获取表单字段名称*/
const getFormFieldTitle = (fieldOptions: Array<Record<string, any>>, field: string) => {
const item = fieldOptions.find((item) => item.field === field)
return item?.title
}
/** 获取操作符名称 */
const getOpName = (opCode: string): string => {
const opName = COMPARISON_OPERATORS.find((item: any) => item.value === opCode)
return opName?.label
}

View File

@ -43,13 +43,9 @@
</el-drawer>
</template>
<script setup lang="ts">
import {
SimpleFlowNode,
ConditionType,
COMPARISON_OPERATORS,
} from '../consts'
import { SimpleFlowNode, ConditionType } from '../consts'
import { getDefaultConditionNodeName } from '../utils'
import { useFormFieldsAndStartUser } from '../node'
import { useFormFieldsAndStartUser, getConditionShowText } from '../node'
import Condition from './components/Condition.vue'
const message = useMessage() //
defineOptions({
@ -93,8 +89,6 @@ const blurEvent = () => {
getDefaultConditionNodeName(props.nodeIndex, currentNode.value?.conditionSetting?.defaultFlow)
}
defineExpose({ open }) // open
//
@ -110,6 +104,8 @@ const handleClose = async (done: (cancel?: boolean) => void) => {
done()
}
}
//
const fieldOptions = useFormFieldsAndStartUser()
const conditionRef = ref()
//
@ -118,7 +114,12 @@ const saveConfig = async () => {
//
const valid = await conditionRef.value.validate()
if (!valid) return false
const showText = getShowText()
const showText = getConditionShowText(
condition.value?.conditionType,
condition.value?.conditionExpression,
condition.value.conditionGroups,
fieldOptions
)
if (!showText) {
return false
}
@ -136,59 +137,6 @@ const saveConfig = async () => {
settingVisible.value = false
return true
}
const getShowText = (): string => {
let showText = ''
if (condition.value?.conditionType === ConditionType.EXPRESSION) {
if (condition.value.conditionExpression) {
showText = `表达式:${condition.value.conditionExpression}`
}
}
if (condition.value?.conditionType === ConditionType.RULE) {
//
const groupAnd = condition.value.conditionGroups?.and
let warningMesg: undefined | string = undefined
const conditionGroup = condition.value.conditionGroups?.conditions.map((item) => {
return (
'(' +
item.rules
.map((rule) => {
if (rule.leftSide && rule.rightSide) {
return (
getFieldTitle(rule.leftSide) + ' ' + getOpName(rule.opCode) + ' ' + rule.rightSide
)
} else {
//
warningMesg = '请完善条件规则'
return ''
}
})
.join(item.and ? ' 且 ' : ' 或 ') +
' ) '
)
})
if (warningMesg) {
message.warning(warningMesg)
showText = ''
} else {
showText = conditionGroup!.join(groupAnd ? ' 且 ' : ' 或 ')
}
}
return showText
}
//
const fieldOptions = useFormFieldsAndStartUser()
/** 获取字段名称 */
const getFieldTitle = (field: string) => {
const item = fieldOptions.find((item) => item.field === field)
return item?.title
}
/** 获取操作符名称 */
const getOpName = (opCode: string): string => {
const opName = COMPARISON_OPERATORS.find((item: any) => item.value === opCode)
return opName?.label
}
</script>
<style lang="scss" scoped>

View File

@ -3,7 +3,7 @@
:append-to-body="true"
v-model="settingVisible"
:show-close="false"
:size="550"
:size="630"
:before-close="saveConfig"
>
<template #header>
@ -121,15 +121,54 @@
</el-button>
</el-form-item>
</div>
<div
v-if="
configForm.type === TriggerTypeEnum.UPDATE_NORMAL_FORM && configForm.normalFormSetting
"
<!-- 表单数据修改触发器 -->
<div v-if="configForm.type === TriggerTypeEnum.UPDATE_NORMAL_FORM">
<div v-for="(formSetting, index) in configForm.formSettings" :key="index">
<el-card class="w-580px mt-4">
<template #header>
<div class="flex items-center justify-between">
<div>修改表单设置 {{ index + 1 }}</div>
<el-button
type="primary"
plain
circle
v-if="configForm.formSettings!.length > 1"
@click="deleteFormSetting(index)"
>
<el-divider content-position="left">修改表单设置</el-divider>
<Icon icon="ep:close" />
</el-button>
</div>
</template>
<!-- 条件设置 -->
<ConditionDialog
:ref="`condition-${index}`"
@update-condition="(val) => handleConditionUpdate(index, val)"
/>
<div class="cursor-pointer" v-if="formSetting.conditionType">
<el-tag
type="success"
effect="light"
closable
@close="deleteFormUpdateCondition(formSetting)"
@click="openFormUpdateCondition(index, formSetting)"
>
{{ showConditionText(formSetting) }}
</el-tag>
</div>
<el-button
v-else
type="primary"
text
@click="addFormUpdateCondition(index, formSetting)"
>
<Icon icon="ep:link" class="mr-5px" />添加条件
</el-button>
<el-divider content-position="left">修改表单字段设置</el-divider>
<!-- 表单字段修改设置 -->
<div
class="flex items-center"
v-for="key in Object.keys(configForm.normalFormSetting.updateFormFields!)"
v-for="key in Object.keys(formSetting.updateFormFields || {})"
:key="key"
>
<div class="mr-2 flex items-center">
@ -137,7 +176,7 @@
<el-select
class="w-160px!"
:model-value="key"
@update:model-value="(newKey) => updateFormFieldKey(key, newKey)"
@update:model-value="(newKey) => updateFormFieldKey(formSetting, key, newKey)"
placeholder="请选择表单字段"
:disabled="key !== ''"
>
@ -154,7 +193,7 @@
<div class="mx-2"><el-form-item>的值设置为</el-form-item></div>
<div class="mr-2">
<el-form-item
:prop="`normalFormSetting.updateFormFields.${key}`"
:prop="`formSettings.${index}.updateFormFields.${key}`"
:rules="{
required: true,
message: '值不能为空',
@ -163,7 +202,7 @@
>
<el-input
class="w-160px"
v-model="configForm.normalFormSetting.updateFormFields![key]"
v-model="formSetting.updateFormFields![key]"
placeholder="请输入"
:disabled="!key"
/>
@ -171,12 +210,25 @@
</div>
<div class="mr-1 pt-1 cursor-pointer">
<el-form-item>
<Icon icon="ep:delete" :size="18" @click="deleteFormFieldSetting(key)" />
<Icon
icon="ep:delete"
:size="18"
@click="deleteFormFieldSetting(formSetting, key)"
/>
</el-form-item>
</div>
</div>
<el-button type="primary" text @click="addFormFieldSetting()">
<Icon icon="ep:plus" class="mr-5px" />添加修改字段
<!-- 添加表单字段按钮 -->
<el-button type="primary" text @click="addFormFieldSetting(formSetting)">
<Icon icon="ep:memo" class="mr-5px" />添加修改字段
</el-button>
</el-card>
</div>
<!-- 添加新的设置 -->
<el-button class="mt-6" type="primary" text @click="addFormSetting">
<Icon icon="ep:setting" class="mr-5px" />添加设置
</el-button>
</div>
</el-form>
@ -191,10 +243,26 @@
</el-drawer>
</template>
<script setup lang="ts">
import { SimpleFlowNode, NodeType, TriggerSetting, TRIGGER_TYPES, TriggerTypeEnum } from '../consts'
import { useWatchNode, useDrawer, useNodeName, useFormFields } from '../node'
import {
SimpleFlowNode,
NodeType,
TriggerSetting,
TRIGGER_TYPES,
TriggerTypeEnum,
FormTriggerSetting,
DEFAULT_CONDITION_GROUP_VALUE
} from '../consts'
import {
useWatchNode,
useDrawer,
useNodeName,
useFormFields,
useFormFieldsAndStartUser,
getConditionShowText
} from '../node'
import HttpRequestParamSetting from './components/HttpRequestParamSetting.vue'
import ConditionDialog from './components/ConditionDialog.vue'
const { proxy } = getCurrentInstance() as any
defineOptions({
name: 'TriggerNodeConfig'
})
@ -227,28 +295,25 @@ const configForm = ref<TriggerSetting>({
body: [],
response: []
},
normalFormSetting: { updateFormFields: {} }
formSettings: [
{
conditionGroups: DEFAULT_CONDITION_GROUP_VALUE,
updateFormFields: {}
}
]
})
//
const formFields = useFormFields()
//
const optionalUpdateFormFields = computed(() => {
const usedFields = Object.keys(configForm.value.normalFormSetting?.updateFormFields || {})
return formFields.map((field) => ({
title: field.title,
field: field.field,
disabled: usedFields.includes(field.field)
disabled: false
}))
})
const updateFormFieldKey = (oldKey: string, newKey: string) => {
if (!configForm.value.normalFormSetting?.updateFormFields) return
const value = configForm.value.normalFormSetting.updateFormFields[oldKey]
delete configForm.value.normalFormSetting.updateFormFields[oldKey]
configForm.value.normalFormSetting.updateFormFields[newKey] = value
}
/** 添加 HTTP 请求返回值设置项*/
const addHttpResponseSetting = (responseSetting: Record<string, string>[]) => {
responseSetting.push({
@ -262,17 +327,69 @@ const deleteHttpResponseSetting = (responseSetting: Record<string, string>[], in
responseSetting.splice(index, 1)
}
/** 添加修改表单设置项 */
const addFormFieldSetting = () => {
if (configForm.value.normalFormSetting!.updateFormFields === undefined) {
configForm.value.normalFormSetting!.updateFormFields = {}
/** 添加新的修改表单设置 */
const addFormSetting = () => {
configForm.value.formSettings!.push({
conditionGroups: DEFAULT_CONDITION_GROUP_VALUE,
updateFormFields: {}
})
}
configForm.value.normalFormSetting!.updateFormFields[''] = undefined
/** 删除修改表单设置 */
const deleteFormSetting = (index: number) => {
configForm.value.formSettings!.splice(index, 1)
}
/** 删除修改表单设置项 */
const deleteFormFieldSetting = (key: string) => {
if (!configForm.value.normalFormSetting?.updateFormFields) return
delete configForm.value.normalFormSetting.updateFormFields[key]
/** 添加条件配置 */
const addFormUpdateCondition = (index: number, formSetting: FormTriggerSetting) => {
const conditionDialog = proxy.$refs[`condition-${index}`][0]
conditionDialog.open(formSetting)
}
/** 删除条件配置 */
const deleteFormUpdateCondition = (formSetting: FormTriggerSetting) => {
formSetting.conditionType = undefined
}
/** 打开条件配置弹窗 */
const openFormUpdateCondition = (index: number, formSetting: FormTriggerSetting) => {
const conditionDialog = proxy.$refs[`condition-${index}`][0]
conditionDialog.open(formSetting)
}
/** 处理条件配置保存 */
const handleConditionUpdate = (index: number, condition: any) => {
configForm.value.formSettings![index].conditionType = condition.conditionType
configForm.value.formSettings![index].conditionExpression = condition.conditionExpression
configForm.value.formSettings![index].conditionGroups = condition.conditionGroups
}
/** 条件配置展示 */
const showConditionText = (formSetting: FormTriggerSetting) => {
return getConditionShowText(
formSetting.conditionType,
formSetting.conditionExpression,
formSetting.conditionGroups,
formFields
)
}
/** 添加修改字段设置项 */
const addFormFieldSetting = (formSetting: FormTriggerSetting) => {
if (!formSetting) return
if (!formSetting.updateFormFields) {
formSetting.updateFormFields = {}
}
formSetting.updateFormFields[''] = undefined
}
/** 更新字段 KEY */
const updateFormFieldKey = (formSetting: FormTriggerSetting, oldKey: string, newKey: string) => {
if (!formSetting?.updateFormFields) return
const value = formSetting.updateFormFields[oldKey]
delete formSetting.updateFormFields[oldKey]
formSetting.updateFormFields[newKey] = value
}
/** 删除修改字段设置项 */
const deleteFormFieldSetting = (formSetting: FormTriggerSetting, key: string) => {
if (!formSetting?.updateFormFields) return
delete formSetting.updateFormFields[key]
}
/** 保存配置 */
@ -285,7 +402,7 @@ const saveConfig = async () => {
currentNode.value.name = nodeName.value!
currentNode.value.showText = showText
if (configForm.value.type === TriggerTypeEnum.HTTP_REQUEST) {
configForm.value.normalFormSetting = undefined
configForm.value.formSettings = undefined
}
if (configForm.value.type === TriggerTypeEnum.UPDATE_NORMAL_FORM) {
configForm.value.httpRequestSetting = undefined
@ -301,13 +418,14 @@ const getShowText = (): string => {
if (configForm.value.type === TriggerTypeEnum.HTTP_REQUEST) {
showText = `${configForm.value.httpRequestSetting?.url}`
} else if (configForm.value.type === TriggerTypeEnum.UPDATE_NORMAL_FORM) {
const updatefields = Object.keys(configForm.value.normalFormSetting?.updateFormFields || {})
if (updatefields.length === 0) {
message.warning('请设置修改表单字段')
} else {
showText = '修改表单数据'
for (const [index, setting] of configForm.value.formSettings!.entries()) {
if (!setting.updateFormFields || Object.keys(setting.updateFormFields).length === 0) {
message.warning(`请添加表单设置${index + 1}的修改字段`)
return ''
}
}
showText = '修改表单数据'
}
return showText
}
@ -323,7 +441,12 @@ const showTriggerNodeConfig = (node: SimpleFlowNode) => {
body: [],
response: []
},
normalFormSetting: node.triggerSetting.normalFormSetting || { updateFormFields: {} }
formSettings: node.triggerSetting.formSettings || [
{
conditionGroups: DEFAULT_CONDITION_GROUP_VALUE,
updateFormFields: {}
}
]
}
}
}

View File

@ -0,0 +1,303 @@
<template>
<Dialog v-model="dialogVisible" title="条件配置" width="600px" :fullscreen="false">
<div class="h-410px">
<el-scrollbar wrap-class="h-full">
<el-form ref="formRef" :model="condition" :rules="formRules" label-position="top">
<el-form-item label="配置方式" prop="conditionType">
<el-radio-group v-model="condition.conditionType" @change="changeConditionType">
<el-radio
v-for="(dict, indexConditionType) in conditionConfigTypes"
:key="indexConditionType"
:value="dict.value"
:label="dict.value"
>
{{ dict.label }}
</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item
v-if="condition.conditionType === ConditionType.RULE && condition.conditionGroups"
label="条件规则"
>
<div class="condition-group-tool">
<div class="flex items-center">
<div class="mr-4">条件组关系</div>
<el-switch
v-model="condition.conditionGroups.and"
inline-prompt
active-text="且"
inactive-text="或"
/>
</div>
</div>
<el-space direction="vertical" :spacer="condition.conditionGroups.and ? '且' : '或'">
<el-card
class="condition-group"
style="width: 530px"
v-for="(equation, cIdx) in condition.conditionGroups.conditions"
:key="cIdx"
>
<div
class="condition-group-delete"
v-if="condition.conditionGroups.conditions.length > 1"
>
<Icon
color="#0089ff"
icon="ep:circle-close-filled"
:size="18"
@click="deleteConditionGroup(condition.conditionGroups.conditions, cIdx)"
/>
</div>
<template #header>
<div class="flex items-center justify-between">
<div>条件组</div>
<div class="flex">
<div class="mr-4">规则关系</div>
<el-switch
v-model="equation.and"
inline-prompt
active-text="且"
inactive-text="或"
/>
</div>
</div>
</template>
<div class="flex pt-2" v-for="(rule, rIdx) in equation.rules" :key="rIdx">
<div class="mr-2">
<el-form-item
:prop="`conditionGroups.conditions.${cIdx}.rules.${rIdx}.leftSide`"
:rules="{
required: true,
message: '左值不能为空',
trigger: 'change'
}"
>
<el-select style="width: 160px" v-model="rule.leftSide">
<el-option
v-for="(field, fIdx) in fieldOptions"
:key="fIdx"
:label="field.title"
:value="field.field"
:disabled="!field.required"
/>
</el-select>
</el-form-item>
</div>
<div class="mr-2">
<el-select v-model="rule.opCode" style="width: 100px">
<el-option
v-for="operator in COMPARISON_OPERATORS"
:key="operator.value"
:label="operator.label"
:value="operator.value"
/>
</el-select>
</div>
<div class="mr-2">
<el-form-item
:prop="`conditionGroups.conditions.${cIdx}.rules.${rIdx}.rightSide`"
:rules="{
required: true,
message: '右值不能为空',
trigger: 'blur'
}"
>
<el-input v-model="rule.rightSide" style="width: 160px" />
</el-form-item>
</div>
<div class="cursor-pointer mr-1 flex items-center" v-if="equation.rules.length > 1">
<Icon
icon="ep:delete"
:size="18"
@click="deleteConditionRule(equation, rIdx)"
/>
</div>
<div class="cursor-pointer flex items-center">
<Icon icon="ep:plus" :size="18" @click="addConditionRule(equation, rIdx)" />
</div>
</div>
</el-card>
</el-space>
<div title="添加条件组" class="mt-4 cursor-pointer">
<Icon
color="#0089ff"
icon="ep:plus"
:size="24"
@click="addConditionGroup(condition.conditionGroups?.conditions)"
/>
</div>
</el-form-item>
<el-form-item
v-if="condition.conditionType === ConditionType.EXPRESSION"
label="条件表达式"
prop="conditionExpression"
>
<el-input
type="textarea"
v-model="condition.conditionExpression"
clearable
style="width: 100%"
/>
</el-form-item>
</el-form>
</el-scrollbar>
</div>
<template #footer>
<el-button type="primary" @click="submitForm"> </el-button>
<el-button @click="dialogVisible = false"> </el-button>
</template>
</Dialog>
</template>
<script setup lang="ts">
import {
COMPARISON_OPERATORS,
CONDITION_CONFIG_TYPES,
ConditionType,
ConditionGroup,
DEFAULT_CONDITION_GROUP_VALUE
} from '../../consts'
import { BpmModelFormType } from '@/utils/constants'
import { useFormFieldsAndStartUser } from '../../node'
defineOptions({
name: 'ConditionDialog'
})
const condition = ref<{
conditionType: ConditionType
conditionExpression?: string
conditionGroups?: ConditionGroup
}>({
conditionType: ConditionType.RULE,
conditionGroups: DEFAULT_CONDITION_GROUP_VALUE
})
const emit = defineEmits<{
updateCondition: [condition: object]
}>()
const message = useMessage() //
const dialogVisible = ref(false) //
const formType = inject<Ref<number>>('formType') //
const conditionConfigTypes = computed(() => {
return CONDITION_CONFIG_TYPES.filter((item) => {
//
if (formType?.value === BpmModelFormType.CUSTOM && item.value === ConditionType.RULE) {
return false
} else {
return true
}
})
})
/** 条件规则可选择的表单字段 */
const fieldOptions = useFormFieldsAndStartUser()
//
const formRules = reactive({
conditionType: [{ required: true, message: '配置方式不能为空', trigger: 'blur' }],
conditionExpression: [{ required: true, message: '条件表达式不能为空', trigger: 'blur' }]
})
const formRef = ref() // Ref
/** 切换条件配置方式 */
const changeConditionType = () => {
if (condition.value.conditionType === ConditionType.RULE) {
if (!condition.value.conditionGroups) {
condition.value.conditionGroups = DEFAULT_CONDITION_GROUP_VALUE
}
}
}
const deleteConditionGroup = (conditions, index) => {
conditions.splice(index, 1)
}
const deleteConditionRule = (condition, index) => {
condition.rules.splice(index, 1)
}
const addConditionRule = (condition, index) => {
const rule = {
opCode: '==',
leftSide: '',
rightSide: ''
}
condition.rules.splice(index + 1, 0, rule)
}
const addConditionGroup = (conditions) => {
const condition = {
and: true,
rules: [
{
opCode: '==',
leftSide: '',
rightSide: ''
}
]
}
conditions.push(condition)
}
/** 保存条件设置 */
const submitForm = async () => {
//
if (!formRef) return
const valid = await formRef.value.validate()
if (!valid) {
message.warning('请完善条件规则')
return
}
dialogVisible.value = false
//
emit('updateCondition', condition.value)
}
const open = (conditionObj: any | undefined) => {
if (conditionObj) {
condition.value.conditionType = conditionObj.conditionType
condition.value.conditionExpression = conditionObj.conditionExpression
condition.value.conditionGroups = conditionObj.conditionGroups
}
dialogVisible.value = true
}
defineExpose({ open })
</script>
<style lang="scss" scoped>
.condition-group-tool {
display: flex;
justify-content: space-between;
width: 500px;
margin-bottom: 20px;
}
.condition-group {
position: relative;
&:hover {
border-color: #0089ff;
.condition-group-delete {
opacity: 1;
}
}
.condition-group-delete {
position: absolute;
top: 0;
left: 0;
display: flex;
cursor: pointer;
opacity: 0;
}
}
::v-deep(.el-card__header) {
padding: 8px var(--el-card-padding);
border-bottom: 1px solid var(--el-card-border-color);
box-sizing: border-box;
}
</style>