Pre Merge pull request !702 from Lemon/feature/bpm-流程审批-办理-抄送

pull/702/MERGE
Lemon 2025-02-18 06:44:57 +00:00 committed by Gitee
commit 20fdfd8081
No known key found for this signature in database
GPG Key ID: 173E9B9CA92EEF8F
24 changed files with 977 additions and 324 deletions

View File

@ -114,7 +114,8 @@ const include = [
'element-plus/es/components/segmented/style/css', 'element-plus/es/components/segmented/style/css',
'@element-plus/icons-vue', '@element-plus/icons-vue',
'element-plus/es/components/footer/style/css', 'element-plus/es/components/footer/style/css',
'element-plus/es/components/empty/style/css' 'element-plus/es/components/empty/style/css',
'element-plus/es/components/mention/style/css'
] ]
const exclude = ['@iconify/json'] const exclude = ['@iconify/json']

View File

@ -0,0 +1 @@
<svg t="1739406626368" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1300" width="200" height="200"><path d="M803.221 925.573H224.356c-68.568 0-124.352-55.784-124.352-124.353V222.356c0-68.568 55.784-124.352 124.352-124.352h355.311v64H224.356c-33.278 0-60.352 27.074-60.352 60.352V801.22c0 33.278 27.074 60.353 60.352 60.353H803.22c33.278 0 60.353-27.074 60.353-60.353V448.208h64V801.22c0 68.569-55.784 124.353-124.352 124.353z" fill="#ffffff" p-id="1301"></path><path d="M300.357 756.916l35.024-195.867L770.117 84.404c10.05-11.02 25.015-18.052 41.058-19.293 16.017-1.247 31.987 3.379 43.841 12.667l83.662 65.549c21.643 16.956 24.254 45.964 5.942 66.038l-437.613 479.8-206.65 67.751z m104.994-170.751l-13.14 73.487 69.671-22.842 415.465-455.517-59.909-46.939-412.087 451.811z" fill="#ffffff" p-id="1302"></path><path d="M732.25 220.897l41.144-49.023 81.151 68.11-41.145 49.023z" fill="#ffffff" p-id="1303"></path></svg>

After

Width:  |  Height:  |  Size: 964 B

View File

@ -15,6 +15,12 @@
</div> </div>
<div class="handler-item-text">审批人</div> <div class="handler-item-text">审批人</div>
</div> </div>
<div class="handler-item" @click="addNode(NodeType.TRANSACTOR_NODE)">
<div class="transactor handler-item-icon">
<span class="iconfont icon-transactor icon-size"></span>
</div>
<div class="handler-item-text">办理人</div>
</div>
<div class="handler-item" @click="addNode(NodeType.COPY_TASK_NODE)"> <div class="handler-item" @click="addNode(NodeType.COPY_TASK_NODE)">
<div class="handler-item-icon copy"> <div class="handler-item-icon copy">
<span class="iconfont icon-size icon-copy"></span> <span class="iconfont icon-size icon-copy"></span>
@ -57,7 +63,7 @@
</div> </div>
<div class="handler-item-text">触发器</div> <div class="handler-item-text">触发器</div>
</div> </div>
</div> </div>
<template #reference> <template #reference>
<div class="add-icon"><Icon icon="ep:plus" /></div> <div class="add-icon"><Icon icon="ep:plus" /></div>
</template> </template>
@ -78,7 +84,7 @@ import {
SimpleFlowNode, SimpleFlowNode,
DEFAULT_CONDITION_GROUP_VALUE DEFAULT_CONDITION_GROUP_VALUE
} from './consts' } from './consts'
import {generateUUID} from '@/utils' import { generateUUID } from '@/utils'
defineOptions({ defineOptions({
name: 'NodeHandler' name: 'NodeHandler'
@ -114,13 +120,13 @@ const addNode = (type: number) => {
} }
popoverShow.value = false popoverShow.value = false
if (type === NodeType.USER_TASK_NODE) { if (type === NodeType.USER_TASK_NODE || type === NodeType.TRANSACTOR_NODE) {
const id = 'Activity_' + generateUUID() const id = 'Activity_' + generateUUID()
const data: SimpleFlowNode = { const data: SimpleFlowNode = {
id: id, id: id,
name: NODE_DEFAULT_NAME.get(NodeType.USER_TASK_NODE) as string, name: NODE_DEFAULT_NAME.get(type) as string,
showText: '', showText: '',
type: NodeType.USER_TASK_NODE, type: type,
approveMethod: ApproveMethodType.SEQUENTIAL_APPROVE, approveMethod: ApproveMethodType.SEQUENTIAL_APPROVE,
// //
rejectHandler: { rejectHandler: {

View File

@ -6,7 +6,11 @@
/> />
<!-- 审批节点 --> <!-- 审批节点 -->
<UserTaskNode <UserTaskNode
v-if="currentNode && currentNode.type === NodeType.USER_TASK_NODE" v-if="
currentNode &&
(currentNode.type === NodeType.USER_TASK_NODE ||
currentNode.type === NodeType.TRANSACTOR_NODE)
"
:flow-node="currentNode" :flow-node="currentNode"
@update:flow-node="handleModelValueUpdate" @update:flow-node="handleModelValueUpdate"
@find:parent-node="findFromParentNode" @find:parent-node="findFromParentNode"

View File

@ -45,4 +45,3 @@ watch(
provide('tasks', approveTasks) provide('tasks', approveTasks)
provide('processInstance', currentProcessInstance) provide('processInstance', currentProcessInstance)
</script> </script>
p

View File

@ -23,6 +23,11 @@ export enum NodeType {
*/ */
COPY_TASK_NODE = 12, COPY_TASK_NODE = 12,
/**
*
*/
TRANSACTOR_NODE = 13,
/** /**
* *
*/ */
@ -506,6 +511,7 @@ NODE_DEFAULT_TEXT.set(NodeType.START_USER_NODE, '请设置发起人')
NODE_DEFAULT_TEXT.set(NodeType.DELAY_TIMER_NODE, '请设置延迟器') NODE_DEFAULT_TEXT.set(NodeType.DELAY_TIMER_NODE, '请设置延迟器')
NODE_DEFAULT_TEXT.set(NodeType.ROUTER_BRANCH_NODE, '请设置路由节点') NODE_DEFAULT_TEXT.set(NodeType.ROUTER_BRANCH_NODE, '请设置路由节点')
NODE_DEFAULT_TEXT.set(NodeType.TRIGGER_NODE, '请设置触发器') NODE_DEFAULT_TEXT.set(NodeType.TRIGGER_NODE, '请设置触发器')
NODE_DEFAULT_TEXT.set(NodeType.TRANSACTOR_NODE, '请设置办理人')
export const NODE_DEFAULT_NAME = new Map<number, string>() export const NODE_DEFAULT_NAME = new Map<number, string>()
NODE_DEFAULT_NAME.set(NodeType.USER_TASK_NODE, '审批人') NODE_DEFAULT_NAME.set(NodeType.USER_TASK_NODE, '审批人')
@ -515,15 +521,17 @@ NODE_DEFAULT_NAME.set(NodeType.START_USER_NODE, '发起人')
NODE_DEFAULT_NAME.set(NodeType.DELAY_TIMER_NODE, '延迟器') NODE_DEFAULT_NAME.set(NodeType.DELAY_TIMER_NODE, '延迟器')
NODE_DEFAULT_NAME.set(NodeType.ROUTER_BRANCH_NODE, '路由分支') NODE_DEFAULT_NAME.set(NodeType.ROUTER_BRANCH_NODE, '路由分支')
NODE_DEFAULT_NAME.set(NodeType.TRIGGER_NODE, '触发器') NODE_DEFAULT_NAME.set(NodeType.TRIGGER_NODE, '触发器')
NODE_DEFAULT_NAME.set(NodeType.TRANSACTOR_NODE, '办理人')
// 候选人策略。暂时不从字典中取。 后续可能调整。控制显示顺序 // 候选人策略。暂时不从字典中取。 后续可能调整。控制显示顺序
export const CANDIDATE_STRATEGY: DictDataVO[] = [ export const CANDIDATE_STRATEGY: DictDataVO[] = [
{ label: '指定成员', value: CandidateStrategy.USER }, { label: '指定成员', value: CandidateStrategy.USER },
{ label: '指定角色', value: CandidateStrategy.ROLE }, { label: '指定角色', value: CandidateStrategy.ROLE },
{ label: '指定岗位', value: CandidateStrategy.POST },
{ label: '部门成员', value: CandidateStrategy.DEPT_MEMBER }, { label: '部门成员', value: CandidateStrategy.DEPT_MEMBER },
{ label: '部门负责人', value: CandidateStrategy.DEPT_LEADER }, { label: '部门负责人', value: CandidateStrategy.DEPT_LEADER },
{ label: '连续多级部门负责人', value: CandidateStrategy.MULTI_LEVEL_DEPT_LEADER }, { label: '连续多级部门负责人', value: CandidateStrategy.MULTI_LEVEL_DEPT_LEADER },
{ label: '发起人自选', value: CandidateStrategy.START_USER_SELECT }, { label: '指定岗位', value: CandidateStrategy.MULTI_LEVEL_DEPT_LEADER },
{ label: '发起人本人', value: CandidateStrategy.START_USER }, { label: '发起人本人', value: CandidateStrategy.START_USER },
{ label: '发起人部门负责人', value: CandidateStrategy.START_USER_DEPT_LEADER }, { label: '发起人部门负责人', value: CandidateStrategy.START_USER_DEPT_LEADER },
{ label: '发起人连续部门负责人', value: CandidateStrategy.START_USER_MULTI_LEVEL_DEPT_LEADER }, { label: '发起人连续部门负责人', value: CandidateStrategy.START_USER_MULTI_LEVEL_DEPT_LEADER },
@ -627,6 +635,16 @@ export const DEFAULT_BUTTON_SETTING: ButtonSetting[] = [
{ id: OperationButtonType.RETURN, displayName: '退回', enable: true } { id: OperationButtonType.RETURN, displayName: '退回', enable: true }
] ]
// 办理人默认的按钮权限设置
export const TRANSACTOR_DEFAULT_BUTTON_SETTING: ButtonSetting[] = [
{ id: OperationButtonType.APPROVE, displayName: '办理', enable: true },
{ id: OperationButtonType.REJECT, displayName: '拒绝', enable: false },
{ id: OperationButtonType.TRANSFER, displayName: '转办', enable: false },
{ id: OperationButtonType.DELEGATE, displayName: '委派', enable: false },
{ id: OperationButtonType.ADD_SIGN, displayName: '加签', enable: false },
{ id: OperationButtonType.RETURN, displayName: '退回', enable: false }
]
// 发起人的按钮权限。暂时定死,不可以编辑 // 发起人的按钮权限。暂时定死,不可以编辑
export const START_USER_BUTTON_SETTING: ButtonSetting[] = [ export const START_USER_BUTTON_SETTING: ButtonSetting[] = [
{ id: OperationButtonType.APPROVE, displayName: '提交', enable: true }, { id: OperationButtonType.APPROVE, displayName: '提交', enable: true },
@ -717,7 +735,7 @@ export type RouterSetting = {
export type TriggerSetting = { export type TriggerSetting = {
type: TriggerTypeEnum type: TriggerTypeEnum
httpRequestSetting?: HttpRequestTriggerSetting httpRequestSetting?: HttpRequestTriggerSetting
normalFormSetting?: NormalFormTriggerSetting formSettings?: FormTriggerSetting[]
} }
/** /**
@ -751,7 +769,13 @@ export type HttpRequestTriggerSetting = {
/** /**
* *
*/ */
export type NormalFormTriggerSetting = { export type FormTriggerSetting = {
// 条件类型
conditionType?: ConditionType
// 条件表达式
conditionExpression?: string
// 条件组
conditionGroups?: ConditionGroup
// 更新表单字段 // 更新表单字段
updateFormFields?: Record<string, any> updateFormFields?: Record<string, any>
} }

View File

@ -15,7 +15,10 @@ import {
AssignEmptyHandlerType, AssignEmptyHandlerType,
FieldPermissionType, FieldPermissionType,
HttpRequestParam, HttpRequestParam,
ProcessVariableEnum ProcessVariableEnum,
ConditionType,
ConditionGroup,
COMPARISON_OPERATORS
} from './consts' } from './consts'
import { parseFormFields } from '@/components/FormCreate/src/utils' import { parseFormFields } from '@/components/FormCreate/src/utils'
@ -201,7 +204,7 @@ export function useNodeForm(nodeType: NodeType) {
const deptTreeOptions = inject('deptTree', ref()) // 部门树 const deptTreeOptions = inject('deptTree', ref()) // 部门树
const formFields = inject<Ref<string[]>>('formFields', ref([])) // 流程表单字段 const formFields = inject<Ref<string[]>>('formFields', ref([])) // 流程表单字段
const configForm = ref<UserTaskFormType | CopyTaskFormType>() const configForm = ref<UserTaskFormType | CopyTaskFormType>()
if (nodeType === NodeType.USER_TASK_NODE) { if (nodeType === NodeType.USER_TASK_NODE || nodeType === NodeType.TRANSACTOR_NODE) {
configForm.value = { configForm.value = {
candidateStrategy: CandidateStrategy.USER, candidateStrategy: CandidateStrategy.USER,
approveMethod: ApproveMethodType.SEQUENTIAL_APPROVE, approveMethod: ApproveMethodType.SEQUENTIAL_APPROVE,
@ -543,6 +546,66 @@ export function useTaskStatusClass(taskStatus: TaskStatusEnum | undefined): stri
if (taskStatus === TaskStatusEnum.CANCEL) { if (taskStatus === TaskStatusEnum.CANCEL) {
return 'status-cancel' return 'status-cancel'
} }
return '' 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> </el-drawer>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { import { SimpleFlowNode, ConditionType } from '../consts'
SimpleFlowNode,
ConditionType,
COMPARISON_OPERATORS,
} from '../consts'
import { getDefaultConditionNodeName } from '../utils' import { getDefaultConditionNodeName } from '../utils'
import { useFormFieldsAndStartUser } from '../node' import { useFormFieldsAndStartUser, getConditionShowText } from '../node'
import Condition from './components/Condition.vue' import Condition from './components/Condition.vue'
const message = useMessage() // const message = useMessage() //
defineOptions({ defineOptions({
@ -93,8 +89,6 @@ const blurEvent = () => {
getDefaultConditionNodeName(props.nodeIndex, currentNode.value?.conditionSetting?.defaultFlow) getDefaultConditionNodeName(props.nodeIndex, currentNode.value?.conditionSetting?.defaultFlow)
} }
defineExpose({ open }) // open defineExpose({ open }) // open
// //
@ -110,6 +104,8 @@ const handleClose = async (done: (cancel?: boolean) => void) => {
done() done()
} }
} }
//
const fieldOptions = useFormFieldsAndStartUser()
const conditionRef = ref() const conditionRef = ref()
// //
@ -118,7 +114,12 @@ const saveConfig = async () => {
// //
const valid = await conditionRef.value.validate() const valid = await conditionRef.value.validate()
if (!valid) return false if (!valid) return false
const showText = getShowText() const showText = getConditionShowText(
condition.value?.conditionType,
condition.value?.conditionExpression,
condition.value.conditionGroups,
fieldOptions
)
if (!showText) { if (!showText) {
return false return false
} }
@ -136,59 +137,6 @@ const saveConfig = async () => {
settingVisible.value = false settingVisible.value = false
return true 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> </script>
<style lang="scss" scoped> <style lang="scss" scoped>

View File

@ -195,9 +195,13 @@
<div class="field-permit-title"> <div class="field-permit-title">
<div class="setting-title-label first-title"> 字段名称 </div> <div class="setting-title-label first-title"> 字段名称 </div>
<div class="other-titles"> <div class="other-titles">
<span class="setting-title-label">只读</span> <span class="setting-title-label">只读
<el-switch v-model="readSwitch" @change="updatePermission('READ')" />
</span>
<span class="setting-title-label">可编辑</span> <span class="setting-title-label">可编辑</span>
<span class="setting-title-label">隐藏</span> <span class="setting-title-label">隐藏
<el-switch v-model="noneSwitch" @change="updatePermission('NONE')" />
</span>
</div> </div>
</div> </div>
<div <div
@ -367,7 +371,23 @@ const showCopyTaskNodeConfig = (node: SimpleFlowNode) => {
// //
getNodeConfigFormFields(node.fieldsPermission) getNodeConfigFormFields(node.fieldsPermission)
} }
const readSwitch = ref(false);
const noneSwitch = ref(false);
const updatePermission = (type: string) => {
if (type === 'READ') {
readSwitch.value = true;
noneSwitch.value = false;
} else if (type === 'NONE') {
readSwitch.value = false;
noneSwitch.value = true;
}
fieldsPermissionConfig.value.forEach(field => {
field.permission = type === 'READ' ? FieldPermissionType.READ : FieldPermissionType.NONE;
});
};
defineExpose({ openDrawer, showCopyTaskNodeConfig }) // defineExpose({ openDrawer, showCopyTaskNodeConfig }) //
</script> </script>

View File

@ -46,9 +46,15 @@
<div class="field-permit-title"> <div class="field-permit-title">
<div class="setting-title-label first-title"> 字段名称 </div> <div class="setting-title-label first-title"> 字段名称 </div>
<div class="other-titles"> <div class="other-titles">
<span class="setting-title-label">只读</span> <span class="setting-title-label">只读
<span class="setting-title-label">可编辑</span> <el-switch v-model="readSwitch" @change="updatePermission('READ')" />
<span class="setting-title-label">隐藏</span> </span>
<span class="setting-title-label">可编辑
<el-switch v-model="writeSwitch" @change="updatePermission('WRITE')" />
</span>
<span class="setting-title-label">隐藏
<el-switch v-model="noneSwitch" @change="updatePermission('NONE')" />
</span>
</div> </div>
</div> </div>
<div <div
@ -156,8 +162,32 @@ const showStartUserNodeConfig = (node: SimpleFlowNode) => {
// //
getNodeConfigFormFields(node.fieldsPermission) getNodeConfigFormFields(node.fieldsPermission)
} }
const readSwitch = ref(false)
const writeSwitch = ref(false)
const noneSwitch = ref(false)
const updatePermission = (type) => {
if (type === 'READ') {
readSwitch.value = true;
writeSwitch.value = false;
noneSwitch.value = false;
} else if (type === 'WRITE') {
readSwitch.value = false;
writeSwitch.value = true;
noneSwitch.value = false;
} else if (type === 'NONE') {
readSwitch.value = false;
writeSwitch.value = false;
noneSwitch.value = true;
}
fieldsPermissionConfig.value.forEach(item => {
item.permission = type === 'READ' ? FieldPermissionType.READ :
type === 'WRITE' ? FieldPermissionType.WRITE :
FieldPermissionType.NONE;
});
}
defineExpose({ openDrawer, showStartUserNodeConfig }) // defineExpose({ openDrawer, showStartUserNodeConfig }) //
</script> </script>
<style lang="scss" scoped></style> <style lang="scss" scoped></style>

View File

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

View File

@ -25,7 +25,7 @@
<div class="divide-line"></div> <div class="divide-line"></div>
</div> </div>
</template> </template>
<div class="flex flex-items-center mb-3"> <div v-if="currentNode.type === NodeType.USER_TASK_NODE" class="flex flex-items-center mb-3">
<span class="font-size-16px mr-3">审批类型 :</span> <span class="font-size-16px mr-3">审批类型 :</span>
<el-radio-group v-model="approveType"> <el-radio-group v-model="approveType">
<el-radio <el-radio
@ -39,10 +39,10 @@
</el-radio-group> </el-radio-group>
</div> </div>
<el-tabs type="border-card" v-model="activeTabName" v-if="approveType === ApproveType.USER"> <el-tabs type="border-card" v-model="activeTabName" v-if="approveType === ApproveType.USER">
<el-tab-pane label="审批人" name="user"> <el-tab-pane :label="`${nodeTypeName}人`" name="user">
<div> <div>
<el-form ref="formRef" :model="configForm" label-position="top" :rules="formRules"> <el-form ref="formRef" :model="configForm" label-position="top" :rules="formRules">
<el-form-item label="审批人设置" prop="candidateStrategy"> <el-form-item :label="`${nodeTypeName}人设置`" prop="candidateStrategy">
<el-radio-group <el-radio-group
v-model="configForm.candidateStrategy" v-model="configForm.candidateStrategy"
@change="changeCandidateStrategy" @change="changeCandidateStrategy"
@ -61,7 +61,13 @@
label="指定角色" label="指定角色"
prop="roleIds" prop="roleIds"
> >
<el-select filterable v-model="configForm.roleIds" clearable multiple style="width: 100%"> <el-select
filterable
v-model="configForm.roleIds"
clearable
multiple
style="width: 100%"
>
<el-option <el-option
v-for="item in roleOptions" v-for="item in roleOptions"
:key="item.id" :key="item.id"
@ -99,7 +105,13 @@
prop="postIds" prop="postIds"
span="24" span="24"
> >
<el-select filterable v-model="configForm.postIds" clearable multiple style="width: 100%"> <el-select
filterable
v-model="configForm.postIds"
clearable
multiple
style="width: 100%"
>
<el-option <el-option
v-for="item in postOptions" v-for="item in postOptions"
:key="item.id" :key="item.id"
@ -114,7 +126,13 @@
prop="userIds" prop="userIds"
span="24" span="24"
> >
<el-select filterable v-model="configForm.userIds" clearable multiple style="width: 100%"> <el-select
filterable
v-model="configForm.userIds"
clearable
multiple
style="width: 100%"
>
<el-option <el-option
v-for="item in userOptions" v-for="item in userOptions"
:key="item.id" :key="item.id"
@ -128,7 +146,13 @@
label="指定用户组" label="指定用户组"
prop="userGroups" prop="userGroups"
> >
<el-select filterable v-model="configForm.userGroups" clearable multiple style="width: 100%"> <el-select
filterable
v-model="configForm.userGroups"
clearable
multiple
style="width: 100%"
>
<el-option <el-option
v-for="item in userGroupOptions" v-for="item in userGroupOptions"
:key="item.id" :key="item.id"
@ -201,7 +225,7 @@
style="width: 100%" style="width: 100%"
/> />
</el-form-item> </el-form-item>
<el-form-item label="多人审批方式" prop="approveMethod"> <el-form-item :label="`多人${nodeTypeName}方式`" prop="approveMethod">
<el-radio-group v-model="configForm.approveMethod" @change="approveMethodChanged"> <el-radio-group v-model="configForm.approveMethod" @change="approveMethodChanged">
<div class="flex-col"> <div class="flex-col">
<div <div
@ -230,93 +254,102 @@
</el-radio-group> </el-radio-group>
</el-form-item> </el-form-item>
<el-divider content-position="left">审批人拒绝时</el-divider> <div v-if="currentNode.type === NodeType.USER_TASK_NODE">
<el-form-item prop="rejectHandlerType"> <el-divider content-position="left">审批人拒绝时</el-divider>
<el-radio-group v-model="configForm.rejectHandlerType"> <el-form-item prop="rejectHandlerType">
<div class="flex-col"> <el-radio-group v-model="configForm.rejectHandlerType">
<div v-for="(item, index) in REJECT_HANDLER_TYPES" :key="index"> <div class="flex-col">
<el-radio :key="item.value" :value="item.value" :label="item.label" /> <div v-for="(item, index) in REJECT_HANDLER_TYPES" :key="index">
<el-radio :key="item.value" :value="item.value" :label="item.label" />
</div>
</div> </div>
</div> </el-radio-group>
</el-radio-group> </el-form-item>
</el-form-item> <el-form-item
<el-form-item v-if="configForm.rejectHandlerType == RejectHandlerType.RETURN_USER_TASK"
v-if="configForm.rejectHandlerType == RejectHandlerType.RETURN_USER_TASK" label="驳回节点"
label="驳回节点" prop="returnNodeId"
prop="returnNodeId"
>
<el-select filterable v-model="configForm.returnNodeId" clearable style="width: 100%">
<el-option
v-for="item in returnTaskList"
:key="item.id"
:label="item.name"
:value="item.id"
/>
</el-select>
</el-form-item>
<el-divider content-position="left">审批人超时未处理时</el-divider>
<el-form-item label="启用开关" prop="timeoutHandlerEnable">
<el-switch
v-model="configForm.timeoutHandlerEnable"
active-text="开启"
inactive-text="关闭"
@change="timeoutHandlerChange"
/>
</el-form-item>
<el-form-item
label="执行动作"
prop="timeoutHandlerType"
v-if="configForm.timeoutHandlerEnable"
>
<el-radio-group
v-model="configForm.timeoutHandlerType"
@change="timeoutHandlerTypeChanged"
> >
<el-radio-button <el-select
v-for="item in TIMEOUT_HANDLER_TYPES" filterable
:key="item.value" v-model="configForm.returnNodeId"
:value="item.value" clearable
:label="item.label" style="width: 100%"
/> >
</el-radio-group> <el-option
</el-form-item> v-for="item in returnTaskList"
<el-form-item label="超时时间设置" v-if="configForm.timeoutHandlerEnable"> :key="item.id"
<span class="mr-2">当超过</span> :label="item.name"
<el-form-item prop="timeDuration"> :value="item.id"
<el-input-number />
class="mr-2" </el-select>
:style="{ width: '100px' }" </el-form-item>
v-model="configForm.timeDuration" </div>
:min="1"
controls-position="right" <div v-if="currentNode.type === NodeType.USER_TASK_NODE">
<el-divider content-position="left">审批人超时未处理时</el-divider>
<el-form-item label="启用开关" prop="timeoutHandlerEnable">
<el-switch
v-model="configForm.timeoutHandlerEnable"
active-text="开启"
inactive-text="关闭"
@change="timeoutHandlerChange"
/> />
</el-form-item> </el-form-item>
<el-select <el-form-item
filterable label="执行动作"
v-model="timeUnit" prop="timeoutHandlerType"
class="mr-2" v-if="configForm.timeoutHandlerEnable"
:style="{ width: '100px' }"
@change="timeUnitChange"
> >
<el-option <el-radio-group
v-for="item in TIME_UNIT_TYPES" v-model="configForm.timeoutHandlerType"
:key="item.value" @change="timeoutHandlerTypeChanged"
:label="item.label" >
:value="item.value" <el-radio-button
/> v-for="item in TIMEOUT_HANDLER_TYPES"
</el-select> :key="item.value"
未处理 :value="item.value"
</el-form-item> :label="item.label"
<el-form-item />
label="最大提醒次数" </el-radio-group>
prop="maxRemindCount" </el-form-item>
v-if="configForm.timeoutHandlerEnable && configForm.timeoutHandlerType === 1" <el-form-item label="超时时间设置" v-if="configForm.timeoutHandlerEnable">
> <span class="mr-2">当超过</span>
<el-input-number v-model="configForm.maxRemindCount" :min="1" :max="10" /> <el-form-item prop="timeDuration">
</el-form-item> <el-input-number
class="mr-2"
:style="{ width: '100px' }"
v-model="configForm.timeDuration"
:min="1"
controls-position="right"
/>
</el-form-item>
<el-select
filterable
v-model="timeUnit"
class="mr-2"
:style="{ width: '100px' }"
@change="timeUnitChange"
>
<el-option
v-for="item in TIME_UNIT_TYPES"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
未处理
</el-form-item>
<el-form-item
label="最大提醒次数"
prop="maxRemindCount"
v-if="configForm.timeoutHandlerEnable && configForm.timeoutHandlerType === 1"
>
<el-input-number v-model="configForm.maxRemindCount" :min="1" :max="10" />
</el-form-item>
</div>
<el-divider content-position="left">审批人为空时</el-divider> <el-divider content-position="left">{{ nodeTypeName }}人为空时</el-divider>
<el-form-item prop="assignEmptyHandlerType"> <el-form-item prop="assignEmptyHandlerType">
<el-radio-group v-model="configForm.assignEmptyHandlerType"> <el-radio-group v-model="configForm.assignEmptyHandlerType">
<div class="flex-col"> <div class="flex-col">
@ -348,30 +381,44 @@
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-divider content-position="left">审批人与提交人为同一人时</el-divider> <div v-if="currentNode.type === NodeType.USER_TASK_NODE">
<el-form-item prop="assignStartUserHandlerType"> <el-divider content-position="left">审批人与提交人为同一人时</el-divider>
<el-radio-group v-model="configForm.assignStartUserHandlerType"> <el-form-item prop="assignStartUserHandlerType">
<div class="flex-col"> <el-radio-group v-model="configForm.assignStartUserHandlerType">
<div v-for="(item, index) in ASSIGN_START_USER_HANDLER_TYPES" :key="index"> <div class="flex-col">
<el-radio :key="item.value" :value="item.value" :label="item.label" /> <div v-for="(item, index) in ASSIGN_START_USER_HANDLER_TYPES" :key="index">
<el-radio :key="item.value" :value="item.value" :label="item.label" />
</div>
</div> </div>
</div> </el-radio-group>
</el-radio-group> </el-form-item>
</el-form-item> </div>
<el-divider content-position="left">是否需要签名</el-divider> <div v-if="currentNode.type === NodeType.USER_TASK_NODE">
<el-form-item prop="signEnable"> <el-divider content-position="left">是否需要签名</el-divider>
<el-switch v-model="configForm.signEnable" active-text="" inactive-text="" /> <el-form-item prop="signEnable">
</el-form-item> <el-switch v-model="configForm.signEnable" active-text="" inactive-text="" />
</el-form-item>
</div>
<el-divider content-position="left">审批意见</el-divider> <div v-if="currentNode.type === NodeType.USER_TASK_NODE">
<el-form-item prop="reasonRequire"> <el-divider content-position="left">审批意见</el-divider>
<el-switch v-model="configForm.reasonRequire" active-text="" inactive-text="" /> <el-form-item prop="reasonRequire">
</el-form-item> <el-switch
v-model="configForm.reasonRequire"
active-text="必填"
inactive-text="非必填"
/>
</el-form-item>
</div>
</el-form> </el-form>
</div> </div>
</el-tab-pane> </el-tab-pane>
<el-tab-pane label="操作按钮设置" name="buttons"> <el-tab-pane
label="操作按钮设置"
v-if="currentNode.type === NodeType.USER_TASK_NODE"
name="buttons"
>
<div class="button-setting-pane"> <div class="button-setting-pane">
<div class="button-setting-desc">操作按钮</div> <div class="button-setting-desc">操作按钮</div>
<div class="button-setting-title"> <div class="button-setting-title">
@ -407,9 +454,15 @@
<div class="field-permit-title"> <div class="field-permit-title">
<div class="setting-title-label first-title"> 字段名称 </div> <div class="setting-title-label first-title"> 字段名称 </div>
<div class="other-titles"> <div class="other-titles">
<span class="setting-title-label">只读</span> <span class="setting-title-label">只读
<span class="setting-title-label">可编辑</span> <el-switch v-model="readSwitch" @change="updatePermission('READ')" />
<span class="setting-title-label">隐藏</span> </span>
<span class="setting-title-label">可编辑
<el-switch v-model="writeSwitch" @change="updatePermission('WRITE')" />
</span>
<span class="setting-title-label">隐藏
<el-switch v-model="noneSwitch" @change="updatePermission('NONE')" />
</span>
</div> </div>
</div> </div>
<div <div
@ -448,7 +501,11 @@
</div> </div>
</el-tab-pane> </el-tab-pane>
<el-tab-pane label="监听器" name="listener"> <el-tab-pane label="监听器" name="listener">
<UserTaskListener ref="userTaskListenerRef" v-model="configForm" :form-field-options="formFieldOptions" /> <UserTaskListener
ref="userTaskListenerRef"
v-model="configForm"
:form-field-options="formFieldOptions"
/>
</el-tab-pane> </el-tab-pane>
</el-tabs> </el-tabs>
<template #footer> <template #footer>
@ -485,7 +542,8 @@ import {
ASSIGN_EMPTY_HANDLER_TYPES, ASSIGN_EMPTY_HANDLER_TYPES,
AssignEmptyHandlerType, AssignEmptyHandlerType,
FieldPermissionType, FieldPermissionType,
ProcessVariableEnum ProcessVariableEnum,
TRANSACTOR_DEFAULT_BUTTON_SETTING
} from '../consts' } from '../consts'
import { import {
@ -588,7 +646,7 @@ const {
handleCandidateParam, handleCandidateParam,
parseCandidateParam, parseCandidateParam,
getShowText getShowText
} = useNodeForm(NodeType.USER_TASK_NODE) } = useNodeForm(currentNode.value.type)
const configForm = tempConfigForm as Ref<UserTaskFormType> const configForm = tempConfigForm as Ref<UserTaskFormType>
// //
@ -627,7 +685,12 @@ const {
const userTaskListenerRef = ref() const userTaskListenerRef = ref()
// /** 节点类型名称 */
const nodeTypeName = computed(() => {
return currentNode.value.type === NodeType.TRANSACTOR_NODE ? '办理' : '审批'
})
/** 保存配置 */
const saveConfig = async () => { const saveConfig = async () => {
// activeTabName.value = 'user' // activeTabName.value = 'user'
// //
@ -713,7 +776,7 @@ const saveConfig = async () => {
return true return true
} }
// /** 显示审批节点配置, 由父组件传过来 */
const showUserTaskNodeConfig = (node: SimpleFlowNode) => { const showUserTaskNodeConfig = (node: SimpleFlowNode) => {
nodeName.value = node.name nodeName.value = node.name
// 1 // 1
@ -733,13 +796,13 @@ const showUserTaskNodeConfig = (node: SimpleFlowNode) => {
configForm.value.approveRatio = node.approveRatio! configForm.value.approveRatio = node.approveRatio!
} }
// 2.3 // 2.3
configForm.value.rejectHandlerType = node.rejectHandler!.type configForm.value.rejectHandlerType = node.rejectHandler?.type
configForm.value.returnNodeId = node.rejectHandler?.returnNodeId configForm.value.returnNodeId = node.rejectHandler?.returnNodeId
const matchNodeList = [] const matchNodeList = []
emits('find:returnTaskNodes', matchNodeList) emits('find:returnTaskNodes', matchNodeList)
returnTaskList.value = matchNodeList returnTaskList.value = matchNodeList
// 2.4 // 2.4
configForm.value.timeoutHandlerEnable = node.timeoutHandler!.enable configForm.value.timeoutHandlerEnable = node.timeoutHandler?.enable
if (node.timeoutHandler?.enable && node.timeoutHandler?.timeDuration) { if (node.timeoutHandler?.enable && node.timeoutHandler?.timeDuration) {
const strTimeDuration = node.timeoutHandler.timeDuration const strTimeDuration = node.timeoutHandler.timeDuration
let parseTime = strTimeDuration.slice(2, strTimeDuration.length - 1) let parseTime = strTimeDuration.slice(2, strTimeDuration.length - 1)
@ -755,7 +818,11 @@ const showUserTaskNodeConfig = (node: SimpleFlowNode) => {
// 2.6 // 2.6
configForm.value.assignStartUserHandlerType = node.assignStartUserHandlerType configForm.value.assignStartUserHandlerType = node.assignStartUserHandlerType
// 3. // 3.
buttonsSetting.value = cloneDeep(node.buttonsSetting) || DEFAULT_BUTTON_SETTING buttonsSetting.value =
cloneDeep(node.buttonsSetting) ||
(node.type === NodeType.TRANSACTOR_NODE
? TRANSACTOR_DEFAULT_BUTTON_SETTING
: DEFAULT_BUTTON_SETTING)
// 4. // 4.
getNodeConfigFormFields(node.fieldsPermission) getNodeConfigFormFields(node.fieldsPermission)
// 5. // 5.
@ -773,7 +840,7 @@ const showUserTaskNodeConfig = (node: SimpleFlowNode) => {
header: node.taskAssignListener?.header ?? [], header: node.taskAssignListener?.header ?? [],
body: node.taskAssignListener?.body ?? [] body: node.taskAssignListener?.body ?? []
} }
// 5.3 // 5.3
configForm.value.taskCompleteListenerEnable = node.taskCompleteListener?.enable configForm.value.taskCompleteListenerEnable = node.taskCompleteListener?.enable
configForm.value.taskCompleteListenerPath = node.taskCompleteListener?.path configForm.value.taskCompleteListenerPath = node.taskCompleteListener?.path
configForm.value.taskCompleteListener = { configForm.value.taskCompleteListener = {
@ -788,9 +855,7 @@ const showUserTaskNodeConfig = (node: SimpleFlowNode) => {
defineExpose({ openDrawer, showUserTaskNodeConfig }) // defineExpose({ openDrawer, showUserTaskNodeConfig }) //
/** /** 操作按钮设置 */
* @description 操作按钮设置
*/
function useButtonsSetting() { function useButtonsSetting() {
const buttonsSetting = ref<ButtonSetting[]>() const buttonsSetting = ref<ButtonSetting[]>()
// //
@ -811,9 +876,7 @@ function useButtonsSetting() {
} }
} }
/** /** 审批人超时未处理配置 */
* @description 审批人超时未处理配置
*/
function useTimeoutHandler() { function useTimeoutHandler() {
// //
const timeUnit = ref(TimeUnitType.HOUR) const timeUnit = ref(TimeUnitType.HOUR)
@ -896,6 +959,31 @@ function useTimeoutHandler() {
cTimeoutMaxRemindCount cTimeoutMaxRemindCount
} }
} }
const readSwitch = ref(false);
const writeSwitch = ref(false);
const noneSwitch = ref(false);
const updatePermission = (type: string) => {
if (type === 'READ') {
readSwitch.value = true;
writeSwitch.value = false;
noneSwitch.value = false;
} else if (type === 'WRITE') {
readSwitch.value = false;
writeSwitch.value = true;
noneSwitch.value = false;
} else if (type === 'NONE') {
readSwitch.value = false;
writeSwitch.value = false;
noneSwitch.value = true;
}
fieldsPermissionConfig.value.forEach(field => {
field.permission = type === 'READ' ? FieldPermissionType.READ :
type === 'WRITE' ? FieldPermissionType.WRITE :
FieldPermissionType.NONE;
});
};
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>

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>

View File

@ -9,7 +9,14 @@
]" ]"
> >
<div class="node-title-container"> <div class="node-title-container">
<div class="node-title-icon user-task"><span class="iconfont icon-approve"></span></div> <div
:class="`node-title-icon ${currentNode.type === NodeType.TRANSACTOR_NODE ? 'transactor-task' : 'user-task'}`"
>
<span
:class="`iconfont ${currentNode.type === NodeType.TRANSACTOR_NODE ? 'icon-transactor' : 'icon-approve'}`"
>
</span>
</div>
<input <input
v-if="!readonly && showInput" v-if="!readonly && showInput"
type="text" type="text"
@ -28,7 +35,7 @@
{{ currentNode.showText }} {{ currentNode.showText }}
</div> </div>
<div class="node-text" v-else> <div class="node-text" v-else>
{{ NODE_DEFAULT_TEXT.get(NodeType.USER_TASK_NODE) }} {{ NODE_DEFAULT_TEXT.get(currentNode.type) }}
</div> </div>
<Icon icon="ep:arrow-right-bold" v-if="!readonly" /> <Icon icon="ep:arrow-right-bold" v-if="!readonly" />
</div> </div>

View File

@ -177,6 +177,10 @@
color: #ca3a31 color: #ca3a31
} }
.transactor {
color: #330099;
}
.handler-item-text { .handler-item-text {
margin-top: 4px; margin-top: 4px;
width: 80px; width: 80px;
@ -290,10 +294,14 @@
&.trigger-node { &.trigger-node {
color: #3373d2; color: #3373d2;
} }
&.router-node { &.router-node {
color: #ca3a31 color: #ca3a31
} }
&.transactor-task {
color: #330099;
}
} }
.node-title { .node-title {
@ -777,7 +785,7 @@
content: "\e7eb"; content: "\e7eb";
} }
.icon-handle:before { .icon-transactor:before {
content: "\e61c"; content: "\e61c";
} }

View File

@ -191,6 +191,7 @@ import {
} from '@/components/SimpleProcessDesignerV2/src/consts' } from '@/components/SimpleProcessDesignerV2/src/consts'
import * as UserApi from '@/api/system/user' import * as UserApi from '@/api/system/user'
import { useFormFieldsPermission } from '@/components/SimpleProcessDesignerV2/src/node' import { useFormFieldsPermission } from '@/components/SimpleProcessDesignerV2/src/node'
import { BpmModelFormType } from '@/utils/constants'
defineOptions({ name: 'ElementCustomConfig4UserTask' }) defineOptions({ name: 'ElementCustomConfig4UserTask' })
const props = defineProps({ const props = defineProps({
@ -248,7 +249,6 @@ const resetCustomConfigList = () => {
bpmnElement.value.id, bpmnElement.value.id,
bpmnInstances().modeler bpmnInstances().modeler
) )
// //
elExtensionElements.value = elExtensionElements.value =
bpmnElement.value.businessObject?.extensionElements ?? bpmnElement.value.businessObject?.extensionElements ??
@ -311,14 +311,13 @@ const resetCustomConfigList = () => {
} }
// //
if (formType.value === 10) { if (formType.value === BpmModelFormType.NORMAL) {
const fieldsPermissionList = elExtensionElements.value.values?.filter( const fieldsPermissionList = elExtensionElements.value.values?.filter(
(ex) => ex.$type === `${prefix}:FieldsPermission` (ex) => ex.$type === `${prefix}:FieldsPermission`
) )
fieldsPermissionEl.value = [] fieldsPermissionEl.value = []
getNodeConfigFormFields() getNodeConfigFormFields()
// fieldsPermissionConfig.value = fieldsPermissionConfig.value
fieldsPermissionConfig.value = fieldsPermissionConfig.value.slice(1)
fieldsPermissionConfig.value.forEach((element) => { fieldsPermissionConfig.value.forEach((element) => {
element.permission = element.permission =
fieldsPermissionList?.find((obj) => obj.field === element.field)?.permission ?? '1' fieldsPermissionList?.find((obj) => obj.field === element.field)?.permission ?? '1'
@ -497,9 +496,9 @@ onMounted(async () => {
<style lang="scss" scoped> <style lang="scss" scoped>
.button-setting-pane { .button-setting-pane {
display: flex; display: flex;
flex-direction: column;
font-size: 14px;
margin-top: 8px; margin-top: 8px;
font-size: 14px;
flex-direction: column;
.button-setting-desc { .button-setting-desc {
padding-right: 8px; padding-right: 8px;

View File

@ -453,14 +453,14 @@ export function jsonParse(str: string) {
/** /**
* *
* *
* @param name * @param str
* @param start * @param start
* @param end * @param end
*/ */
export const sliceName = (name: string,start: number, end : number) => { export const subString = (str: string, start: number, end: number) => {
if (name.length > end) { if (str.length > end) {
return name.slice(start, end) return str.slice(start, end)
} }
return name return str
} }

View File

@ -89,7 +89,7 @@
</el-tooltip> </el-tooltip>
<el-image v-if="row.icon" :src="row.icon" class="h-38px w-38px mr-10px rounded" /> <el-image v-if="row.icon" :src="row.icon" class="h-38px w-38px mr-10px rounded" />
<div v-else class="flow-icon"> <div v-else class="flow-icon">
<span style="font-size: 12px; color: #fff">{{ sliceName(row.name,0,2) }}</span> <span style="font-size: 12px; color: #fff">{{ subString(row.name, 0, 2) }}</span>
</div> </div>
{{ row.name }} {{ row.name }}
</div> </div>
@ -273,7 +273,7 @@ import { useAppStore } from '@/store/modules/app'
import { cloneDeep, isEqual } from 'lodash-es' import { cloneDeep, isEqual } from 'lodash-es'
import { useTagsView } from '@/hooks/web/useTagsView' import { useTagsView } from '@/hooks/web/useTagsView'
import { useDebounceFn } from '@vueuse/core' import { useDebounceFn } from '@vueuse/core'
import { sliceName } from '@/utils/index' import { subString } from '@/utils/index'
defineOptions({ name: 'BpmModel' }) defineOptions({ name: 'BpmModel' })

View File

@ -34,6 +34,8 @@ import CustomContentPadProvider from '@/components/bpmnProcessDesigner/package/d
// //
import CustomPaletteProvider from '@/components/bpmnProcessDesigner/package/designer/plugins/palette' import CustomPaletteProvider from '@/components/bpmnProcessDesigner/package/designer/plugins/palette'
import * as ModelApi from '@/api/bpm/model' import * as ModelApi from '@/api/bpm/model'
import { BpmModelFormType } from '@/utils/constants'
import * as FormApi from '@/api/bpm/form'
defineOptions({ name: 'BpmModelEditor' }) defineOptions({ name: 'BpmModelEditor' })
@ -49,7 +51,8 @@ const message = useMessage() // 国际化
// //
const formFields = ref<string[]>([]) const formFields = ref<string[]>([])
const formType = ref(20) //
const formType = ref(BpmModelFormType.NORMAL)
provide('formFields', formFields) provide('formFields', formFields)
provide('formType', formType) provide('formType', formType)
@ -88,6 +91,20 @@ const save = async (bpmnXml: string) => {
} }
} }
/** 监听表单 ID 变化,加载表单数据 */
watch(
() => modelData.value.formId,
async (newFormId) => {
if (newFormId && modelData.value.formType === BpmModelFormType.NORMAL) {
const data = await FormApi.getForm(newFormId)
formFields.value = data.fields
} else {
formFields.value = []
}
},
{ immediate: true }
)
// //
onBeforeUnmount(() => { onBeforeUnmount(() => {
modeler.value = null modeler.value = null

View File

@ -11,12 +11,12 @@
</el-radio> </el-radio>
</el-radio-group> </el-radio-group>
</el-form-item> </el-form-item>
<el-form-item v-if="modelData.formType === 10" label="流程表单" prop="formId"> <el-form-item v-if="modelData.formType === BpmModelFormType.NORMAL" label="流程表单" prop="formId">
<el-select v-model="modelData.formId" clearable style="width: 100%"> <el-select v-model="modelData.formId" clearable style="width: 100%">
<el-option v-for="form in formList" :key="form.id" :label="form.name" :value="form.id" /> <el-option v-for="form in formList" :key="form.id" :label="form.name" :value="form.id" />
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item v-if="modelData.formType === 20" label="表单提交路由" prop="formCustomCreatePath"> <el-form-item v-if="modelData.formType === BpmModelFormType.CUSTOM" label="表单提交路由" prop="formCustomCreatePath">
<el-input <el-input
v-model="modelData.formCustomCreatePath" v-model="modelData.formCustomCreatePath"
placeholder="请输入表单提交路由" placeholder="请输入表单提交路由"
@ -31,7 +31,7 @@
<Icon icon="ep:question" class="ml-5px" /> <Icon icon="ep:question" class="ml-5px" />
</el-tooltip> </el-tooltip>
</el-form-item> </el-form-item>
<el-form-item v-if="modelData.formType === 20" label="表单查看地址" prop="formCustomViewPath"> <el-form-item v-if="modelData.formType === BpmModelFormType.CUSTOM" label="表单查看地址" prop="formCustomViewPath">
<el-input <el-input
v-model="modelData.formCustomViewPath" v-model="modelData.formCustomViewPath"
placeholder="请输入表单查看的组件地址" placeholder="请输入表单查看的组件地址"
@ -48,7 +48,7 @@
</el-form-item> </el-form-item>
<!-- 表单预览 --> <!-- 表单预览 -->
<div <div
v-if="modelData.formType === 10 && modelData.formId && formPreview.rule.length > 0" v-if="modelData.formType === BpmModelFormType.NORMAL && modelData.formId && formPreview.rule.length > 0"
class="mt-20px" class="mt-20px"
> >
<div class="flex items-center mb-15px"> <div class="flex items-center mb-15px">
@ -68,6 +68,7 @@
import { DICT_TYPE, getIntDictOptions } from '@/utils/dict' import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
import * as FormApi from '@/api/bpm/form' import * as FormApi from '@/api/bpm/form'
import { setConfAndFields2 } from '@/utils/formCreate' import { setConfAndFields2 } from '@/utils/formCreate'
import { BpmModelFormType } from '@/utils/constants'
const props = defineProps({ const props = defineProps({
formList: { formList: {
@ -96,7 +97,7 @@ const formPreview = ref({
watch( watch(
() => modelData.value.formId, () => modelData.value.formId,
async (newFormId) => { async (newFormId) => {
if (newFormId && modelData.value.formType === 10) { if (newFormId && modelData.value.formType === BpmModelFormType.NORMAL) {
const data = await FormApi.getForm(newFormId) const data = await FormApi.getForm(newFormId)
setConfAndFields2(formPreview.value, data.conf, data.fields) setConfAndFields2(formPreview.value, data.conf, data.fields)
// //

View File

@ -64,9 +64,9 @@
class="w-32px h-32px" class="w-32px h-32px"
/> />
<div v-else class="flow-icon"> <div v-else class="flow-icon">
<span style="font-size: 12px; color: #fff">{{ <span style="font-size: 12px; color: #fff">
sliceName(definition.name,0,2) {{ subString(definition.name, 0, 2) }}
}}</span> </span>
</div> </div>
<el-text class="!ml-10px" size="large">{{ definition.name }}</el-text> <el-text class="!ml-10px" size="large">{{ definition.name }}</el-text>
</div> </div>
@ -97,7 +97,7 @@ import * as ProcessInstanceApi from '@/api/bpm/processInstance'
import { CategoryApi, CategoryVO } from '@/api/bpm/category' import { CategoryApi, CategoryVO } from '@/api/bpm/category'
import ProcessDefinitionDetail from './ProcessDefinitionDetail.vue' import ProcessDefinitionDetail from './ProcessDefinitionDetail.vue'
import { groupBy } from 'lodash-es' import { groupBy } from 'lodash-es'
import { sliceName } from '@/utils/index' import { subString } from '@/utils/index'
defineOptions({ name: 'BpmProcessInstanceCreate' }) defineOptions({ name: 'BpmProcessInstanceCreate' })

View File

@ -36,10 +36,10 @@
:rule="approveForm.rule" :rule="approveForm.rule"
/> />
</el-card> </el-card>
<el-form-item label="审批意见" prop="reason"> <el-form-item :label="`${nodeTypeName}意见`" prop="reason">
<el-input <el-input
v-model="approveReasonForm.reason" v-model="approveReasonForm.reason"
placeholder="请输入审批意见" :placeholder="`请输入${nodeTypeName}意见`"
type="textarea" type="textarea"
:rows="4" :rows="4"
/> />
@ -504,6 +504,7 @@ import * as TaskApi from '@/api/bpm/task'
import * as ProcessInstanceApi from '@/api/bpm/processInstance' import * as ProcessInstanceApi from '@/api/bpm/processInstance'
import * as UserApi from '@/api/system/user' import * as UserApi from '@/api/system/user'
import { import {
NodeType,
OPERATION_BUTTON_NAME, OPERATION_BUTTON_NAME,
OperationButtonType OperationButtonType
} from '@/components/SimpleProcessDesignerV2/src/consts' } from '@/components/SimpleProcessDesignerV2/src/consts'
@ -546,6 +547,7 @@ const returnList = ref([] as any) // 退回节点
const runningTask = ref<any>() // const runningTask = ref<any>() //
const approveForm = ref<any>({}) // const approveForm = ref<any>({}) //
const approveFormFApi = ref<any>({}) // approveForms fAPi const approveFormFApi = ref<any>({}) // approveForms fAPi
const nodeTypeName = ref('审批') //
// //
const reasonRequire = ref() const reasonRequire = ref()
@ -558,7 +560,9 @@ const approveReasonForm = reactive({
}) })
const approveReasonRule = computed(() => { const approveReasonRule = computed(() => {
return { return {
reason: [{ required: reasonRequire.value, message: '审批意见不能为空', trigger: 'blur' }], reason: [
{ required: reasonRequire.value, message: nodeTypeName + '意见不能为空', trigger: 'blur' }
],
signPicUrl: [{ required: true, message: '签名不能为空', trigger: 'change' }] signPicUrl: [{ required: true, message: '签名不能为空', trigger: 'change' }]
} }
}) })
@ -969,9 +973,10 @@ const getButtonDisplayName = (btnType: OperationButtonType) => {
const loadTodoTask = (task: any) => { const loadTodoTask = (task: any) => {
approveForm.value = {} approveForm.value = {}
approveFormFApi.value = {}
runningTask.value = task runningTask.value = task
approveFormFApi.value = {}
reasonRequire.value = task?.reasonRequire ?? false reasonRequire.value = task?.reasonRequire ?? false
nodeTypeName.value = task?.nodeType === NodeType.TRANSACTOR_NODE ? '办理' : '审批'
// approve . // approve .
if (task && task.formId && task.formConf) { if (task && task.formId && task.formConf) {
const tempApproveForm = {} const tempApproveForm = {}

View File

@ -84,7 +84,8 @@ const setSimpleModelNodeTaskStatus = (
// //
if ( if (
simpleModel.type === NodeType.START_USER_NODE || simpleModel.type === NodeType.START_USER_NODE ||
simpleModel.type === NodeType.USER_TASK_NODE simpleModel.type === NodeType.USER_TASK_NODE ||
simpleModel.type === NodeType.TRANSACTOR_NODE
) { ) {
simpleModel.activityStatus = TaskStatusEnum.NOT_START simpleModel.activityStatus = TaskStatusEnum.NOT_START
if (rejectedTaskActivityIds.includes(simpleModel.id)) { if (rejectedTaskActivityIds.includes(simpleModel.id)) {

View File

@ -121,6 +121,7 @@
" "
class="text-#a5a5a5 text-13px mt-1 w-full bg-#f8f8fa p2 rounded-md" class="text-#a5a5a5 text-13px mt-1 w-full bg-#f8f8fa p2 rounded-md"
> >
<!-- TODO lesan这里如果是办理需要是办理意见 -->
审批意见{{ task.reason }} 审批意见{{ task.reason }}
</div> </div>
<div <div
@ -179,6 +180,7 @@ import copySvg from '@/assets/svgs/bpm/copy.svg'
import conditionSvg from '@/assets/svgs/bpm/condition.svg' import conditionSvg from '@/assets/svgs/bpm/condition.svg'
import parallelSvg from '@/assets/svgs/bpm/parallel.svg' import parallelSvg from '@/assets/svgs/bpm/parallel.svg'
import finishSvg from '@/assets/svgs/bpm/finish.svg' import finishSvg from '@/assets/svgs/bpm/finish.svg'
import transactorSvg from '@/assets/svgs/bpm/transactor.svg'
defineOptions({ name: 'BpmProcessInstanceTimeline' }) defineOptions({ name: 'BpmProcessInstanceTimeline' })
withDefaults( withDefaults(
@ -240,6 +242,8 @@ const nodeTypeSvgMap = {
[NodeType.START_USER_NODE]: { color: '#909398', svg: starterSvg }, [NodeType.START_USER_NODE]: { color: '#909398', svg: starterSvg },
// //
[NodeType.USER_TASK_NODE]: { color: '#ff943e', svg: auditorSvg }, [NodeType.USER_TASK_NODE]: { color: '#ff943e', svg: auditorSvg },
//
[NodeType.TRANSACTOR_NODE]: { color: '#ff943e', svg: transactorSvg },
// //
[NodeType.COPY_TASK_NODE]: { color: '#3296fb', svg: copySvg }, [NodeType.COPY_TASK_NODE]: { color: '#3296fb', svg: copySvg },
// //
@ -264,6 +268,7 @@ const getApprovalNodeIcon = (taskStatus: number, nodeType: NodeType) => {
if ( if (
nodeType === NodeType.START_USER_NODE || nodeType === NodeType.START_USER_NODE ||
nodeType === NodeType.USER_TASK_NODE || nodeType === NodeType.USER_TASK_NODE ||
nodeType === NodeType.TRANSACTOR_NODE ||
nodeType === NodeType.END_EVENT_NODE nodeType === NodeType.END_EVENT_NODE
) { ) {
return statusIconMap[taskStatus]?.icon return statusIconMap[taskStatus]?.icon