refactor: 重构 bpmnProcessDesigner 组件 ele => antd

This commit is contained in:
puhui999
2025-09-14 18:16:02 +08:00
parent a277f0fa03
commit 71dd9f2d88
24 changed files with 3852 additions and 4451 deletions

View File

@@ -1,34 +1,36 @@
<template>
<div class="panel-tab__content">
<el-form size="small" label-width="90px">
<Form :label-col="{ span: 9 }" :wrapper-col="{ span: 15 }">
<!-- add by 芋艿由于异步延续暂时用不到所以这里 display none -->
<el-form-item label="异步延续" style="display: none">
<el-checkbox
v-model="taskConfigForm.asyncBefore"
label="异步前"
value="异步前"
<Form.Item label="异步延续" style="display: none">
<Checkbox
v-model:checked="taskConfigForm.asyncBefore"
@change="changeTaskAsync"
/>
<el-checkbox
v-model="taskConfigForm.asyncAfter"
label="异步后"
value="异步后"
>
异步前
</Checkbox>
<Checkbox
v-model:checked="taskConfigForm.asyncAfter"
@change="changeTaskAsync"
/>
<el-checkbox
v-model="taskConfigForm.exclusive"
>
异步后
</Checkbox>
<Checkbox
v-model:checked="taskConfigForm.exclusive"
v-if="taskConfigForm.asyncAfter || taskConfigForm.asyncBefore"
label="排除"
value="排除"
@change="changeTaskAsync"
/>
</el-form-item>
>
排除
</Checkbox>
</Form.Item>
<component :is="witchTaskComponent" v-bind="$props" />
</el-form>
</Form>
</div>
</template>
<script lang="ts" setup>
import { Form } from 'ant-design-vue';
import { ref, watch } from 'vue';
import { installedComponent } from './data';
defineOptions({ name: 'ElementTaskConfig' });

View File

@@ -27,10 +27,14 @@ export const installedComponent = {
},
};
export const getTaskCollapseItemName = (elementType) => {
export const getTaskCollapseItemName = (
elementType: keyof typeof installedComponent,
) => {
return installedComponent[elementType].name;
};
export const isTaskCollapseItemShow = (elementType) => {
export const isTaskCollapseItemShow = (
elementType: keyof typeof installedComponent,
) => {
return installedComponent[elementType];
};

View File

@@ -1,189 +1,38 @@
<template>
<div>
<el-form label-width="100px">
<el-form-item label="实例名称" prop="processInstanceName">
<el-input
v-model="formData.processInstanceName"
clearable
placeholder="请输入实例名称"
@change="updateCallActivityAttr('processInstanceName')"
/>
</el-form-item>
<!-- TODO 需要可选择已存在的流程 -->
<el-form-item label="被调用流程" prop="calledElement">
<el-input
v-model="formData.calledElement"
clearable
placeholder="请输入被调用流程"
@change="updateCallActivityAttr('calledElement')"
/>
</el-form-item>
<el-form-item label="继承变量" prop="inheritVariables">
<el-switch
v-model="formData.inheritVariables"
@change="updateCallActivityAttr('inheritVariables')"
/>
</el-form-item>
<el-form-item label="继承业务键" prop="inheritBusinessKey">
<el-switch
v-model="formData.inheritBusinessKey"
@change="updateCallActivityAttr('inheritBusinessKey')"
/>
</el-form-item>
<el-form-item
v-if="!formData.inheritBusinessKey"
label="业务键表达式"
prop="businessKey"
>
<el-input
v-model="formData.businessKey"
clearable
placeholder="请输入业务键表达式"
@change="updateCallActivityAttr('businessKey')"
/>
</el-form-item>
<el-divider />
<div>
<div class="mb-10px flex">
<el-text>输入参数</el-text>
<XButton
class="ml-auto"
type="primary"
preIcon="ep:plus"
title="添加参数"
size="small"
@click="openVariableForm('in', null, -1)"
/>
</div>
<el-table :data="inVariableList" max-height="240" fit border>
<el-table-column
label="源"
prop="source"
min-width="100px"
show-overflow-tooltip
/>
<el-table-column
label="目标"
prop="target"
min-width="100px"
show-overflow-tooltip
/>
<el-table-column label="操作" width="110px">
<template #default="scope">
<el-button
link
@click="openVariableForm('in', scope.row, scope.$index)"
size="small"
>
编辑
</el-button>
<el-divider direction="vertical" />
<el-button
link
size="small"
style="color: #ff4d4f"
@click="removeVariable('in', scope.$index)"
>
移除
</el-button>
</template>
</el-table-column>
</el-table>
</div>
<el-divider />
<div>
<div class="mb-10px flex">
<el-text>输出参数</el-text>
<XButton
class="ml-auto"
type="primary"
preIcon="ep:plus"
title="添加参数"
size="small"
@click="openVariableForm('out', null, -1)"
/>
</div>
<el-table :data="outVariableList" max-height="240" fit border>
<el-table-column
label="源"
prop="source"
min-width="100px"
show-overflow-tooltip
/>
<el-table-column
label="目标"
prop="target"
min-width="100px"
show-overflow-tooltip
/>
<el-table-column label="操作" width="110px">
<template #default="scope">
<el-button
link
@click="openVariableForm('out', scope.row, scope.$index)"
size="small"
>
编辑
</el-button>
<el-divider direction="vertical" />
<el-button
link
size="small"
style="color: #ff4d4f"
@click="removeVariable('out', scope.$index)"
>
移除
</el-button>
</template>
</el-table-column>
</el-table>
</div>
</el-form>
<!-- 添加或修改参数 -->
<el-dialog
v-model="variableDialogVisible"
title="参数配置"
width="600px"
append-to-body
destroy-on-close
>
<el-form
:model="varialbeFormData"
label-width="80px"
ref="varialbeFormRef"
>
<el-form-item label="源:" prop="source">
<el-input v-model="varialbeFormData.source" clearable />
</el-form-item>
<el-form-item label="目标:" prop="target">
<el-input v-model="varialbeFormData.target" clearable />
</el-form-item>
</el-form>
<template #footer>
<el-button @click="variableDialogVisible = false"> </el-button>
<el-button type="primary" @click="saveVariable"> </el-button>
</template>
</el-dialog>
</div>
</template>
<script lang="ts" setup>
import { inject, nextTick, ref, toRaw, watch } from 'vue';
import { alert } from '@vben/common-ui';
import { PlusOutlined } from '@vben/icons';
import {
Button,
Divider,
Form,
FormItem,
Input,
Modal,
Switch,
Table,
TableColumn,
} from 'ant-design-vue';
interface FormData {
processInstanceName: string;
calledElement: string;
inheritVariables: boolean;
businessKey: string;
inheritBusinessKey: boolean;
calledElementType: string;
}
defineOptions({ name: 'CallActivity' });
const props = defineProps({
id: String,
type: String,
id: { type: String, default: '' },
type: { type: String, default: '' },
});
const prefix = inject('prefix');
const message = useMessage();
const formData = ref({
const formData = ref<FormData>({
processInstanceName: '',
calledElement: '',
inheritVariables: false,
@@ -191,44 +40,51 @@ const formData = ref({
inheritBusinessKey: false,
calledElementType: 'key',
});
const inVariableList = ref();
const outVariableList = ref();
const variableType = ref(); // 参数类型
const editingVariableIndex = ref(-1); // 编辑参数下标
const variableDialogVisible = ref(false);
const varialbeFormRef = ref();
const varialbeFormData = ref({
const inVariableList = ref<any[]>([]);
const outVariableList = ref<any[]>([]);
const variableType = ref<string>(); // 参数类型
const editingVariableIndex = ref<number>(-1); // 编辑参数下标
const variableDialogVisible = ref<boolean>(false);
const varialbeFormRef = ref<any>();
const varialbeFormData = ref<{
source: string;
target: string;
}>({
source: '',
target: '',
});
const bpmnInstances = () => (window as any)?.bpmnInstances;
const bpmnElement = ref();
const otherExtensionList = ref();
const bpmnElement = ref<any>();
const otherExtensionList = ref<any[]>([]);
const initCallActivity = () => {
bpmnElement.value = bpmnInstances().bpmnElement;
console.log(bpmnElement.value.businessObject, 'callActivity');
// console.log(bpmnElement.value.businessObject, 'callActivity');
// 初始化所有配置项
Object.keys(formData.value).forEach((key) => {
Object.keys(formData.value).forEach((key: string) => {
// @ts-ignore
formData.value[key] =
bpmnElement.value.businessObject[key] ?? formData.value[key];
bpmnElement.value.businessObject[key] ??
formData.value[key as keyof FormData];
});
otherExtensionList.value = []; // 其他扩展配置
inVariableList.value = [];
outVariableList.value = [];
inVariableList.value.length = 0;
outVariableList.value.length = 0;
// 初始化输入参数
bpmnElement.value.businessObject?.extensionElements?.values?.forEach((ex) => {
if (ex.$type === `${prefix}:In`) {
inVariableList.value.push(ex);
} else if (ex.$type === `${prefix}:Out`) {
outVariableList.value.push(ex);
} else {
otherExtensionList.value.push(ex);
}
});
bpmnElement.value.businessObject?.extensionElements?.values?.forEach(
(ex: any) => {
if (ex.$type === `${prefix}:In`) {
inVariableList.value.push(ex);
} else if (ex.$type === `${prefix}:Out`) {
outVariableList.value.push(ex);
} else {
otherExtensionList.value.push(ex);
}
},
);
// 默认添加
// bpmnInstances().modeling.updateProperties(toRaw(bpmnElement.value), {
@@ -236,22 +92,22 @@ const initCallActivity = () => {
// })
};
const updateCallActivityAttr = (attr) => {
const updateCallActivityAttr = (attr: keyof FormData) => {
bpmnInstances().modeling.updateProperties(toRaw(bpmnElement.value), {
[attr]: formData.value[attr],
});
};
const openVariableForm = (type, data, index) => {
const openVariableForm = (type: string, data: any, index: number) => {
editingVariableIndex.value = index;
variableType.value = type;
varialbeFormData.value = index === -1 ? {} : { ...data };
variableDialogVisible.value = true;
};
const removeVariable = async (type, index) => {
const removeVariable = async (type: string, index: number) => {
try {
await message.delConfirm();
await alert('是否确认删除?');
if (type === 'in') {
inVariableList.value.splice(index, 1);
}
@@ -313,7 +169,7 @@ watch(
() => props.id,
(val) => {
val &&
val.length &&
val.length > 0 &&
nextTick(() => {
initCallActivity();
});
@@ -322,4 +178,184 @@ watch(
);
</script>
<template>
<div>
<Form :label-col="{ span: 6 }" :wrapper-col="{ span: 18 }">
<FormItem label="实例名称">
<Input
v-model:value="formData.processInstanceName"
allow-clear
placeholder="请输入实例名称"
@change="updateCallActivityAttr('processInstanceName')"
/>
</FormItem>
<!-- TODO 需要可选择已存在的流程 -->
<FormItem label="被调用流程">
<Input
v-model:value="formData.calledElement"
allow-clear
placeholder="请输入被调用流程"
@change="updateCallActivityAttr('calledElement')"
/>
</FormItem>
<FormItem label="继承变量">
<Switch
v-model:checked="formData.inheritVariables"
@change="updateCallActivityAttr('inheritVariables')"
/>
</FormItem>
<FormItem label="继承业务键">
<Switch
v-model:checked="formData.inheritBusinessKey"
@change="updateCallActivityAttr('inheritBusinessKey')"
/>
</FormItem>
<FormItem v-if="!formData.inheritBusinessKey" label="业务键表达式">
<Input
v-model:value="formData.businessKey"
allow-clear
placeholder="请输入业务键表达式"
@change="updateCallActivityAttr('businessKey')"
/>
</FormItem>
<Divider />
<div>
<div class="mb-10px flex">
<span>输入参数</span>
<Button
class="ml-auto"
type="primary"
:icon="PlusOutlined"
title="添加参数"
size="small"
@click="openVariableForm('in', null, -1)"
/>
</div>
<Table
:data-source="inVariableList"
:scroll="{ y: 240 }"
bordered
:pagination="false"
>
<TableColumn
title="源"
data-index="source"
:min-width="100"
:ellipsis="true"
/>
<TableColumn
title="目标"
data-index="target"
:min-width="100"
:ellipsis="true"
/>
<TableColumn title="操作" :width="110">
<template #default="{ record, index }">
<Button
type="link"
@click="openVariableForm('in', record, index)"
size="small"
>
编辑
</Button>
<Divider type="vertical" />
<Button
type="link"
size="small"
danger
@click="removeVariable('in', index)"
>
移除
</Button>
</template>
</TableColumn>
</Table>
</div>
<Divider />
<div>
<div class="mb-10px flex">
<span>输出参数</span>
<Button
class="ml-auto"
type="primary"
:icon="PlusOutlined"
title="添加参数"
size="small"
@click="openVariableForm('out', null, -1)"
/>
</div>
<Table
:data-source="outVariableList"
:scroll="{ y: 240 }"
bordered
:pagination="false"
>
<TableColumn
title="源"
data-index="source"
:min-width="100"
:ellipsis="true"
/>
<TableColumn
title="目标"
data-index="target"
:min-width="100"
:ellipsis="true"
/>
<TableColumn title="操作" :width="110">
<template #default="{ record, index }">
<Button
type="link"
@click="openVariableForm('out', record, index)"
size="small"
>
编辑
</Button>
<Divider type="vertical" />
<Button
type="link"
size="small"
danger
@click="removeVariable('out', index)"
>
移除
</Button>
</template>
</TableColumn>
</Table>
</div>
</Form>
<!-- 添加或修改参数 -->
<Modal
v-model:open="variableDialogVisible"
title="参数配置"
:width="600"
:destroy-on-close="true"
@ok="saveVariable"
@cancel="variableDialogVisible = false"
>
<Form
:model="varialbeFormData"
:label-col="{ span: 6 }"
:wrapper-col="{ span: 18 }"
ref="varialbeFormRef"
>
<FormItem label="源:" name="source">
<Input v-model:value="varialbeFormData.source" allow-clear />
</FormItem>
<FormItem label="目标:" name="target">
<Input v-model:value="varialbeFormData.target" allow-clear />
</FormItem>
</Form>
</Modal>
</div>
</template>
<style lang="scss" scoped></style>

View File

@@ -1,46 +1,24 @@
<!-- 表达式选择 -->
<template>
<Dialog title="请选择表达式" v-model="dialogVisible" width="1024px">
<ContentWrap>
<el-table
v-loading="loading"
:data="list"
:stripe="true"
:show-overflow-tooltip="true"
>
<el-table-column label="名字" align="center" prop="name" />
<el-table-column label="表达式" align="center" prop="expression" />
<el-table-column label="操作" align="center">
<template #default="scope">
<el-button link type="primary" @click="select(scope.row)">
选择
</el-button>
</template>
</el-table-column>
</el-table>
<!-- 分页 -->
<Pagination
:total="total"
v-model:page="queryParams.pageNo"
v-model:limit="queryParams.pageSize"
@pagination="getList"
/>
</ContentWrap>
</Dialog>
</template>
<script setup lang="ts">
import { CommonStatusEnum } from '@/utils/constants';
import {
ProcessExpressionApi,
ProcessExpressionVO,
} from '@/api/bpm/processExpression';
import type { BpmProcessExpressionApi } from '#/api/bpm/processExpression';
import { reactive, ref } from 'vue';
import { CommonStatusEnum } from '@vben/constants';
import { Button, Modal, Pagination, Table, TableColumn } from 'ant-design-vue';
import { getProcessExpressionPage } from '#/api/bpm/processExpression';
import { ContentWrap } from '#/components/content-wrap';
/** BPM 流程 表单 */
defineOptions({ name: 'ProcessExpressionDialog' });
/** 提交表单 */
const emit = defineEmits(['select']);
const dialogVisible = ref(false); // 弹窗的是否展示
const loading = ref(true); // 列表的加载中
const list = ref<ProcessExpressionVO[]>([]); // 列表的数据
const list = ref<BpmProcessExpressionApi.ProcessExpression[]>([]); // 列表的数据
const total = ref(0); // 列表的总页数
const queryParams = reactive({
pageNo: 1,
@@ -62,8 +40,7 @@ defineExpose({ open }); // 提供 open 方法,用于打开弹窗
const getList = async () => {
loading.value = true;
try {
const data =
await ProcessExpressionApi.getProcessExpressionPage(queryParams);
const data = await getProcessExpressionPage(queryParams);
list.value = data.list;
total.value = data.total;
} finally {
@@ -71,11 +48,49 @@ const getList = async () => {
}
};
/** 提交表单 */
const emit = defineEmits(['success']); // 定义 success 事件,用于操作成功后的回调
const select = async (row) => {
// 定义 select 事件,用于操作成功后的回调
const select = async (row: BpmProcessExpressionApi.ProcessExpression) => {
dialogVisible.value = false;
// 发送操作成功的事件
emit('select', row);
};
// const handleCancel = () => {
// dialogVisible.value = false;
// };
</script>
<template>
<Modal
title="请选择表达式"
v-model:open="dialogVisible"
width="1024px"
:footer="null"
>
<ContentWrap>
<Table
:loading="loading"
:data-source="list"
:pagination="false"
:scroll="{ x: 'max-content' }"
>
<TableColumn title="名字" align="center" data-index="name" />
<TableColumn title="表达式" align="center" data-index="expression" />
<TableColumn title="操作" align="center">
<template #default="{ record }">
<Button type="primary" @click="select(record)"> 选择 </Button>
</template>
</TableColumn>
</Table>
<!-- 分页 -->
<div class="mt-4 flex justify-end">
<Pagination
:total="total"
v-model:current="queryParams.pageNo"
v-model:page-size="queryParams.pageSize"
show-size-changer
@change="getList"
/>
</div>
</ContentWrap>
</Modal>
</template>

View File

@@ -1,70 +1,38 @@
<template>
<div style="margin-top: 16px">
<el-form-item label="消息实例">
<div
style="
display: flex;
flex-wrap: nowrap;
align-items: center;
justify-content: space-between;
"
>
<el-select v-model="bindMessageId" @change="updateTaskMessage">
<el-option
v-for="key in Object.keys(messageMap)"
:value="key"
:label="messageMap[key]"
:key="key"
/>
</el-select>
<XButton
type="primary"
preIcon="ep:plus"
style="margin-left: 8px"
@click="openMessageModel"
/>
</div>
</el-form-item>
<el-dialog
v-model="messageModelVisible"
:close-on-click-modal="false"
title="创建新消息"
width="400px"
append-to-body
destroy-on-close
>
<el-form :model="newMessageForm" size="small" label-width="90px">
<el-form-item label="消息ID">
<el-input v-model="newMessageForm.id" clearable />
</el-form-item>
<el-form-item label="消息名称">
<el-input v-model="newMessageForm.name" clearable />
</el-form-item>
</el-form>
<template #footer>
<el-button size="small" type="primary" @click="createNewMessage"
> </el-button
>
</template>
</el-dialog>
</div>
</template>
<script lang="ts" setup>
import {
h,
nextTick,
onBeforeUnmount,
onMounted,
ref,
toRaw,
watch,
} from 'vue';
import { PlusOutlined } from '@vben/icons';
import {
Button,
Form,
Input,
message,
Modal,
Select,
SelectOption,
} from 'ant-design-vue';
defineOptions({ name: 'ReceiveTask' });
const props = defineProps({
id: String,
type: String,
id: { type: String, default: '' },
type: { type: String, default: '' },
});
const message = useMessage();
const bindMessageId = ref('');
const newMessageForm = ref<any>({});
const messageMap = ref<any>({});
const newMessageForm = ref<Record<string, any>>({});
const messageMap = ref<Record<string, any>>({});
const messageModelVisible = ref(false);
const bpmnElement = ref<any>();
const bpmnMessageRefsMap = ref<any>();
const bpmnMessageRefsMap = ref<Record<string, any>>();
const bpmnRootElements = ref<any>();
const bpmnInstances = () => (window as any).bpmnInstances;
@@ -88,17 +56,18 @@ const createNewMessage = () => {
);
bpmnRootElements.value.push(newMessage);
messageMap.value[newMessageForm.value.id] = newMessageForm.value.name;
bpmnMessageRefsMap.value[newMessageForm.value.id] = newMessage;
// @ts-ignore
bpmnMessageRefsMap.value?.[newMessageForm.value.id] = newMessage;
messageModelVisible.value = false;
};
const updateTaskMessage = (messageId) => {
const updateTaskMessage = (messageId: string) => {
if (messageId === '-1') {
bpmnInstances().modeling.updateProperties(toRaw(bpmnElement.value), {
messageRef: null,
});
} else {
bpmnInstances().modeling.updateProperties(toRaw(bpmnElement.value), {
messageRef: bpmnMessageRefsMap.value[messageId],
messageRef: bpmnMessageRefsMap.value?.[messageId],
});
}
};
@@ -108,9 +77,10 @@ onMounted(() => {
bpmnRootElements.value =
bpmnInstances().modeler.getDefinitions().rootElements;
bpmnRootElements.value
.filter((el) => el.$type === 'bpmn:Message')
.forEach((m) => {
bpmnMessageRefsMap.value[m.id] = m;
.filter((el: any) => el.$type === 'bpmn:Message')
.forEach((m: any) => {
// @ts-ignore
bpmnMessageRefsMap.value?.[m.id] = m;
messageMap.value[m.id] = m.name;
});
messageMap.value['-1'] = '无';
@@ -130,3 +100,57 @@ watch(
{ immediate: true },
);
</script>
<template>
<div style="margin-top: 16px">
<Form.Item label="消息实例">
<div
style="
display: flex;
flex-wrap: nowrap;
align-items: center;
justify-content: space-between;
"
>
<Select
v-model:value="bindMessageId"
@change="(value: any) => updateTaskMessage(value)"
>
<SelectOption
v-for="key in Object.keys(messageMap)"
:value="key"
:label="messageMap[key]"
:key="key"
/>
</Select>
<Button
type="primary"
:icon="h(PlusOutlined)"
style="margin-left: 8px"
@click="openMessageModel"
/>
</div>
</Form.Item>
<Modal
v-model:open="messageModelVisible"
:mask-closable="false"
title="创建新消息"
width="400px"
:destroy-on-close="true"
>
<Form :model="newMessageForm" size="small" :label-col="{ span: 6 }">
<Form.Item label="消息ID">
<Input v-model:value="newMessageForm.id" allow-clear />
</Form.Item>
<Form.Item label="消息名称">
<Input v-model:value="newMessageForm.name" allow-clear />
</Form.Item>
</Form>
<template #footer>
<Button size="small" type="primary" @click="createNewMessage">
</Button>
</template>
</Modal>
</div>
</template>

View File

@@ -1,57 +1,32 @@
<template>
<div style="margin-top: 16px">
<el-form-item label="脚本格式">
<el-input
v-model="scriptTaskForm.scriptFormat"
clearable
@input="updateElementTask()"
@change="updateElementTask()"
/>
</el-form-item>
<el-form-item label="脚本类型">
<el-select v-model="scriptTaskForm.scriptType">
<el-option label="内联脚本" value="inline" />
<el-option label="外部资源" value="external" />
</el-select>
</el-form-item>
<el-form-item label="脚本" v-show="scriptTaskForm.scriptType === 'inline'">
<el-input
v-model="scriptTaskForm.script"
type="textarea"
resize="vertical"
:autosize="{ minRows: 2, maxRows: 4 }"
clearable
@input="updateElementTask()"
@change="updateElementTask()"
/>
</el-form-item>
<el-form-item
label="资源地址"
v-show="scriptTaskForm.scriptType === 'external'"
>
<el-input
v-model="scriptTaskForm.resource"
clearable
@input="updateElementTask()"
@change="updateElementTask()"
/>
</el-form-item>
<el-form-item label="结果变量">
<el-input
v-model="scriptTaskForm.resultVariable"
clearable
@input="updateElementTask()"
@change="updateElementTask()"
/>
</el-form-item>
</div>
</template>
<script lang="ts" setup>
import {
defineOptions,
defineProps,
nextTick,
onBeforeUnmount,
ref,
toRaw,
watch,
} from 'vue';
import {
FormItem,
Input,
Select,
SelectOption,
Textarea,
} from 'ant-design-vue';
defineOptions({ name: 'ScriptTask' });
const props = defineProps({
id: String,
type: String,
id: {
type: String,
default: '',
},
type: {
type: String,
default: '',
},
});
const defaultTaskForm = ref({
scriptFormat: '',
@@ -65,17 +40,19 @@ const bpmnElement = ref();
const bpmnInstances = () => (window as any)?.bpmnInstances;
const resetTaskForm = () => {
for (let key in defaultTaskForm.value) {
let value =
bpmnElement.value?.businessObject[key] || defaultTaskForm.value[key];
scriptTaskForm.value[key] = value;
for (const key in defaultTaskForm.value) {
// @ts-ignore
scriptTaskForm.value[key] =
bpmnElement.value?.businessObject[
key as keyof typeof defaultTaskForm.value
] || defaultTaskForm.value[key as keyof typeof defaultTaskForm.value];
}
scriptTaskForm.value.scriptType = scriptTaskForm.value.script
? 'inline'
: 'external';
};
const updateElementTask = () => {
let taskAttr = Object.create(null);
const taskAttr = Object.create(null);
taskAttr.scriptFormat = scriptTaskForm.value.scriptFormat || null;
taskAttr.resultVariable = scriptTaskForm.value.resultVariable || null;
if (scriptTaskForm.value.scriptType === 'inline') {
@@ -103,3 +80,50 @@ watch(
{ immediate: true },
);
</script>
<template>
<div class="mt-4">
<FormItem label="脚本格式">
<Input
v-model:value="scriptTaskForm.scriptFormat"
allow-clear
@input="updateElementTask()"
@change="updateElementTask()"
/>
</FormItem>
<FormItem label="脚本类型">
<Select v-model:value="scriptTaskForm.scriptType">
<SelectOption value="inline">内联脚本</SelectOption>
<SelectOption value="external">外部资源</SelectOption>
</Select>
</FormItem>
<FormItem label="脚本" v-show="scriptTaskForm.scriptType === 'inline'">
<Textarea
v-model:value="scriptTaskForm.script"
:auto-size="{ minRows: 2, maxRows: 4 }"
allow-clear
@input="updateElementTask()"
@change="updateElementTask()"
/>
</FormItem>
<FormItem
label="资源地址"
v-show="scriptTaskForm.scriptType === 'external'"
>
<Input
v-model:value="scriptTaskForm.resource"
allow-clear
@input="updateElementTask()"
@change="updateElementTask()"
/>
</FormItem>
<FormItem label="结果变量">
<Input
v-model:value="scriptTaskForm.resultVariable"
allow-clear
@input="updateElementTask()"
@change="updateElementTask()"
/>
</FormItem>
</div>
</template>

View File

@@ -1,56 +1,12 @@
<template>
<div>
<el-form-item label="执行类型" key="executeType">
<el-select v-model="serviceTaskForm.executeType">
<el-option label="Java类" value="class" />
<el-option label="表达式" value="expression" />
<el-option label="代理表达式" value="delegateExpression" />
</el-select>
</el-form-item>
<el-form-item
v-if="serviceTaskForm.executeType === 'class'"
label="Java类"
prop="class"
key="execute-class"
>
<el-input
v-model="serviceTaskForm.class"
clearable
@change="updateElementTask"
/>
</el-form-item>
<el-form-item
v-if="serviceTaskForm.executeType === 'expression'"
label="表达式"
prop="expression"
key="execute-expression"
>
<el-input
v-model="serviceTaskForm.expression"
clearable
@change="updateElementTask"
/>
</el-form-item>
<el-form-item
v-if="serviceTaskForm.executeType === 'delegateExpression'"
label="代理表达式"
prop="delegateExpression"
key="execute-delegate"
>
<el-input
v-model="serviceTaskForm.delegateExpression"
clearable
@change="updateElementTask"
/>
</el-form-item>
</div>
</template>
<script lang="ts" setup>
import { nextTick, onBeforeUnmount, ref, toRaw, watch } from 'vue';
import { FormItem, Input, Select } from 'ant-design-vue';
defineOptions({ name: 'ServiceTask' });
const props = defineProps({
id: String,
type: String,
id: { type: String, default: '' },
type: { type: String, default: '' },
});
const defaultTaskForm = ref({
@@ -66,8 +22,9 @@ const bpmnElement = ref();
const bpmnInstances = () => (window as any)?.bpmnInstances;
const resetTaskForm = () => {
for (let key in defaultTaskForm.value) {
let value =
for (const key in defaultTaskForm.value) {
const value =
// @ts-ignore
bpmnElement.value?.businessObject[key] || defaultTaskForm.value[key];
serviceTaskForm.value[key] = value;
if (value) {
@@ -77,9 +34,9 @@ const resetTaskForm = () => {
};
const updateElementTask = () => {
let taskAttr = Object.create(null);
const taskAttr = Object.create(null);
const type = serviceTaskForm.value.executeType;
for (let key in serviceTaskForm.value) {
for (const key in serviceTaskForm.value) {
if (key !== 'executeType' && key !== type) taskAttr[key] = null;
}
taskAttr[type] = serviceTaskForm.value[type] || '';
@@ -101,3 +58,54 @@ watch(
{ immediate: true },
);
</script>
<template>
<div>
<FormItem label="执行类型" key="executeType">
<Select
v-model:value="serviceTaskForm.executeType"
:options="[
{ label: 'Java类', value: 'class' },
{ label: '表达式', value: 'expression' },
{ label: '代理表达式', value: 'delegateExpression' },
]"
/>
</FormItem>
<FormItem
v-if="serviceTaskForm.executeType === 'class'"
label="Java类"
name="class"
key="execute-class"
>
<Input
v-model:value="serviceTaskForm.class"
allow-clear
@change="updateElementTask"
/>
</FormItem>
<FormItem
v-if="serviceTaskForm.executeType === 'expression'"
label="表达式"
name="expression"
key="execute-expression"
>
<Input
v-model:value="serviceTaskForm.expression"
allow-clear
@change="updateElementTask"
/>
</FormItem>
<FormItem
v-if="serviceTaskForm.executeType === 'delegateExpression'"
label="代理表达式"
name="delegateExpression"
key="execute-delegate"
>
<Input
v-model:value="serviceTaskForm.delegateExpression"
allow-clear
@change="updateElementTask"
/>
</FormItem>
</div>
</template>

View File

@@ -1,250 +1,60 @@
<template>
<el-form label-width="120px">
<el-form-item label="规则类型" prop="candidateStrategy">
<el-select
v-model="userTaskForm.candidateStrategy"
clearable
style="width: 100%"
@change="changeCandidateStrategy"
>
<el-option
v-for="(dict, index) in CANDIDATE_STRATEGY"
:key="index"
:label="dict.label"
:value="dict.value"
/>
</el-select>
</el-form-item>
<el-form-item
v-if="userTaskForm.candidateStrategy == CandidateStrategy.ROLE"
label="指定角色"
prop="candidateParam"
>
<el-select
v-model="userTaskForm.candidateParam"
clearable
multiple
style="width: 100%"
@change="updateElementTask"
>
<el-option
v-for="item in roleOptions"
:key="item.id"
:label="item.name"
:value="item.id"
/>
</el-select>
</el-form-item>
<el-form-item
v-if="
userTaskForm.candidateStrategy == CandidateStrategy.DEPT_MEMBER ||
userTaskForm.candidateStrategy == CandidateStrategy.DEPT_LEADER ||
userTaskForm.candidateStrategy ==
CandidateStrategy.MULTI_LEVEL_DEPT_LEADER
"
label="指定部门"
prop="candidateParam"
span="24"
>
<el-tree-select
ref="treeRef"
v-model="userTaskForm.candidateParam"
:data="deptTreeOptions"
:props="defaultProps"
empty-text="加载中,请稍后"
multiple
node-key="id"
show-checkbox
@change="updateElementTask"
/>
</el-form-item>
<el-form-item
v-if="userTaskForm.candidateStrategy == CandidateStrategy.POST"
label="指定岗位"
prop="candidateParam"
span="24"
>
<el-select
v-model="userTaskForm.candidateParam"
clearable
multiple
style="width: 100%"
@change="updateElementTask"
>
<el-option
v-for="item in postOptions"
:key="item.id"
:label="item.name"
:value="item.id"
/>
</el-select>
</el-form-item>
<el-form-item
v-if="userTaskForm.candidateStrategy == CandidateStrategy.USER"
label="指定用户"
prop="candidateParam"
span="24"
>
<el-select
v-model="userTaskForm.candidateParam"
clearable
multiple
style="width: 100%"
@change="updateElementTask"
>
<el-option
v-for="item in userOptions"
:key="item.id"
:label="item.nickname"
:value="item.id"
/>
</el-select>
</el-form-item>
<el-form-item
v-if="userTaskForm.candidateStrategy === CandidateStrategy.USER_GROUP"
label="指定用户组"
prop="candidateParam"
>
<el-select
v-model="userTaskForm.candidateParam"
clearable
multiple
style="width: 100%"
@change="updateElementTask"
>
<el-option
v-for="item in userGroupOptions"
:key="item.id"
:label="item.name"
:value="item.id"
/>
</el-select>
</el-form-item>
<el-form-item
v-if="userTaskForm.candidateStrategy === CandidateStrategy.FORM_USER"
label="表单内用户字段"
prop="formUser"
>
<el-select
v-model="userTaskForm.candidateParam"
clearable
style="width: 100%"
@change="handleFormUserChange"
>
<el-option
v-for="(item, idx) in userFieldOnFormOptions"
:key="idx"
:label="item.title"
:value="item.field"
:disabled="!item.required"
/>
</el-select>
</el-form-item>
<el-form-item
v-if="
userTaskForm.candidateStrategy === CandidateStrategy.FORM_DEPT_LEADER
"
label="表单内部门字段"
prop="formDept"
>
<el-select
v-model="userTaskForm.candidateParam"
clearable
style="width: 100%"
@change="updateElementTask"
>
<el-option
v-for="(item, idx) in deptFieldOnFormOptions"
:key="idx"
:label="item.title"
:value="item.field"
:disabled="!item.required"
/>
</el-select>
</el-form-item>
<el-form-item
v-if="
userTaskForm.candidateStrategy ==
CandidateStrategy.MULTI_LEVEL_DEPT_LEADER ||
userTaskForm.candidateStrategy ==
CandidateStrategy.START_USER_DEPT_LEADER ||
userTaskForm.candidateStrategy ==
CandidateStrategy.START_USER_MULTI_LEVEL_DEPT_LEADER ||
userTaskForm.candidateStrategy == CandidateStrategy.FORM_DEPT_LEADER
"
:label="deptLevelLabel!"
prop="deptLevel"
span="24"
>
<el-select v-model="deptLevel" clearable @change="updateElementTask">
<el-option
v-for="(item, index) in MULTI_LEVEL_DEPT"
:key="index"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
<el-form-item
v-if="userTaskForm.candidateStrategy === CandidateStrategy.EXPRESSION"
label="流程表达式"
prop="candidateParam"
>
<el-input
type="textarea"
v-model="userTaskForm.candidateParam[0]"
clearable
style="width: 100%"
@change="updateElementTask"
/>
<XButton
class="!w-1/1 mt-5px"
type="success"
preIcon="ep:select"
title="选择表达式"
size="small"
@click="openProcessExpressionDialog"
/>
<!-- 选择弹窗 -->
<ProcessExpressionDialog
ref="processExpressionDialogRef"
@select="selectProcessExpression"
/>
</el-form-item>
<el-form-item label="跳过表达式" prop="skipExpression">
<el-input
type="textarea"
v-model="userTaskForm.skipExpression"
clearable
style="width: 100%"
@change="updateSkipExpression"
/>
</el-form-item>
</el-form>
</template>
<script lang="ts" setup>
import type { BpmProcessExpressionApi } from '#/api/bpm/processExpression';
import type { BpmUserGroupApi } from '#/api/bpm/userGroup';
import type { SystemPostApi } from '#/api/system/post';
import type { SystemRoleApi } from '#/api/system/role';
import type { SystemUserApi } from '#/api/system/user';
import {
computed,
h,
inject,
nextTick,
onBeforeUnmount,
onMounted,
ref,
toRaw,
watch,
} from 'vue';
import { SelectOutlined } from '@vben/icons';
import { handleTree } from '@vben/utils';
import {
Button,
Form,
FormItem,
Select,
SelectOption,
Textarea,
TreeSelect,
} from 'ant-design-vue';
import { getUserGroupSimpleList } from '#/api/bpm/userGroup';
import { getSimpleDeptList } from '#/api/system/dept';
import { getSimplePostList } from '#/api/system/post';
import { getSimpleRoleList } from '#/api/system/role';
import { getSimpleUserList } from '#/api/system/user';
import {
CANDIDATE_STRATEGY,
CandidateStrategy,
FieldPermissionType,
MULTI_LEVEL_DEPT,
} from '@/components/SimpleProcessDesignerV2/src/consts';
import { defaultProps, handleTree } from '@/utils/tree';
import * as RoleApi from '@/api/system/role';
import * as DeptApi from '@/api/system/dept';
import * as PostApi from '@/api/system/post';
import * as UserApi from '@/api/system/user';
import * as UserGroupApi from '@/api/bpm/userGroup';
} from '#/components/simple-process-design/consts';
import { useFormFieldsPermission } from '#/components/simple-process-design/helpers';
import ProcessExpressionDialog from './ProcessExpressionDialog.vue';
import { ProcessExpressionVO } from '@/api/bpm/processExpression';
import { useFormFieldsPermission } from '@/components/SimpleProcessDesignerV2/src/node';
defineOptions({ name: 'UserTask' });
const props = defineProps({
id: String,
type: String,
id: {
type: String,
default: '',
},
type: {
type: String,
default: '',
},
});
const prefix = inject('prefix');
const userTaskForm = ref({
@@ -252,16 +62,24 @@ const userTaskForm = ref({
candidateParam: [], // 分配选项
skipExpression: '', // 跳过表达式
});
const bpmnElement = ref();
const bpmnInstances = () => (window as any)?.bpmnInstances;
const bpmnElement = ref<any>();
const bpmnInstances = () => (window as Record<string, any>)?.bpmnInstances;
const roleOptions = ref<RoleApi.RoleVO[]>([]); // 角色列表
const deptTreeOptions = ref(); // 部门树
const postOptions = ref<PostApi.PostVO[]>([]); // 岗位列表
const userOptions = ref<UserApi.UserVO[]>([]); // 用户列表
const userGroupOptions = ref<UserGroupApi.UserGroupVO[]>([]); // 用户组列表
const roleOptions = ref<SystemRoleApi.Role[]>([]); // 角色列表
const deptTreeOptions = ref<any>(); // 部门树
const postOptions = ref<SystemPostApi.Post[]>([]); // 岗位列表
const userOptions = ref<SystemUserApi.User[]>([]); // 用户列表
const userGroupOptions = ref<BpmUserGroupApi.UserGroup[]>([]); // 用户组列表
const treeRef = ref<any>();
const { formFieldOptions } = useFormFieldsPermission(FieldPermissionType.READ);
// 定义 TreeSelect 的默认属性映射
const defaultProps = {
children: 'children',
label: 'name',
value: 'id',
};
// 表单内用户字段选项, 必须是必填和用户选择器
const userFieldOnFormOptions = computed(() => {
return formFieldOptions.filter((item) => item.type === 'UserSelect');
@@ -275,21 +93,21 @@ const deptLevel = ref(1);
const deptLevelLabel = computed(() => {
let label = '部门负责人来源';
if (
userTaskForm.value.candidateStrategy ==
userTaskForm.value.candidateStrategy ===
CandidateStrategy.MULTI_LEVEL_DEPT_LEADER
) {
label = label + '(指定部门向上)';
label = `${label}(指定部门向上)`;
} else if (
userTaskForm.value.candidateStrategy == CandidateStrategy.FORM_DEPT_LEADER
userTaskForm.value.candidateStrategy === CandidateStrategy.FORM_DEPT_LEADER
) {
label = label + '(表单内部门向上)';
label = `${label}(表单内部门向上)`;
} else {
label = label + '(发起人部门向上)';
label = `${label}(发起人部门向上)`;
}
return label;
});
const otherExtensions = ref();
const otherExtensions = ref<any>();
const resetTaskForm = () => {
const businessObject = bpmnElement.value.businessObject;
@@ -301,50 +119,54 @@ const resetTaskForm = () => {
businessObject?.extensionElements ??
bpmnInstances().moddle.create('bpmn:ExtensionElements', { values: [] });
userTaskForm.value.candidateStrategy = extensionElements.values?.filter(
(ex) => ex.$type === `${prefix}:CandidateStrategy`,
(ex: any) => ex.$type === `${prefix}:CandidateStrategy`,
)?.[0]?.value;
const candidateParamStr = extensionElements.values?.filter(
(ex) => ex.$type === `${prefix}:CandidateParam`,
(ex: any) => ex.$type === `${prefix}:CandidateParam`,
)?.[0]?.value;
if (candidateParamStr && candidateParamStr.length > 0) {
// eslint-disable-next-line unicorn/prefer-switch
if (userTaskForm.value.candidateStrategy === CandidateStrategy.EXPRESSION) {
// 特殊:流程表达式,只有一个 input 输入框
// @ts-ignore
userTaskForm.value.candidateParam = [candidateParamStr];
} else if (
userTaskForm.value.candidateStrategy ==
userTaskForm.value.candidateStrategy ===
CandidateStrategy.MULTI_LEVEL_DEPT_LEADER
) {
// 特殊:多级不部门负责人,需要通过'|'分割
userTaskForm.value.candidateParam = candidateParamStr
.split('|')[0]
.split(',')
.map((item) => {
.map((item: any) => {
// 如果数字超出了最大安全整数范围,则将其作为字符串处理
let num = Number(item);
const num = Number(item);
return num > Number.MAX_SAFE_INTEGER || num < -Number.MAX_SAFE_INTEGER
? item
: num;
});
deptLevel.value = +candidateParamStr.split('|')[1];
} else if (
userTaskForm.value.candidateStrategy ==
userTaskForm.value.candidateStrategy ===
CandidateStrategy.START_USER_DEPT_LEADER ||
userTaskForm.value.candidateStrategy ==
userTaskForm.value.candidateStrategy ===
CandidateStrategy.START_USER_MULTI_LEVEL_DEPT_LEADER
) {
// @ts-ignore
userTaskForm.value.candidateParam = +candidateParamStr;
deptLevel.value = +candidateParamStr;
} else if (
userTaskForm.value.candidateStrategy == CandidateStrategy.FORM_DEPT_LEADER
userTaskForm.value.candidateStrategy ===
CandidateStrategy.FORM_DEPT_LEADER
) {
userTaskForm.value.candidateParam = candidateParamStr.split('|')[0];
deptLevel.value = +candidateParamStr.split('|')[1];
} else {
userTaskForm.value.candidateParam = candidateParamStr
.split(',')
.map((item) => {
.map((item: any) => {
// 如果数字超出了最大安全整数范围,则将其作为字符串处理
let num = Number(item);
const num = Number(item);
return num > Number.MAX_SAFE_INTEGER || num < -Number.MAX_SAFE_INTEGER
? item
: num;
@@ -356,42 +178,41 @@ const resetTaskForm = () => {
otherExtensions.value =
extensionElements.values?.filter(
(ex) =>
(ex: any) =>
ex.$type !== `${prefix}:CandidateStrategy` &&
ex.$type !== `${prefix}:CandidateParam`,
) ?? [];
// 跳过表达式
if (businessObject.skipExpression != undefined) {
userTaskForm.value.skipExpression = businessObject.skipExpression;
} else {
userTaskForm.value.skipExpression = '';
}
userTaskForm.value.skipExpression =
businessObject.skipExpression === undefined
? ''
: businessObject.skipExpression;
// 改用通过extensionElements来存储数据
return;
if (businessObject.candidateStrategy != undefined) {
userTaskForm.value.candidateStrategy = parseInt(
businessObject.candidateStrategy,
) as any;
} else {
userTaskForm.value.candidateStrategy = undefined;
}
if (
businessObject.candidateParam &&
businessObject.candidateParam.length > 0
) {
if (userTaskForm.value.candidateStrategy === 60) {
// 特殊:流程表达式,只有一个 input 输入框
userTaskForm.value.candidateParam = [businessObject.candidateParam];
} else {
userTaskForm.value.candidateParam = businessObject.candidateParam
.split(',')
.map((item) => item);
}
} else {
userTaskForm.value.candidateParam = [];
}
// if (businessObject.candidateStrategy != undefined) {
// userTaskForm.value.candidateStrategy = parseInt(
// businessObject.candidateStrategy,
// ) as any;
// } else {
// userTaskForm.value.candidateStrategy = undefined;
// }
// if (
// businessObject.candidateParam &&
// businessObject.candidateParam.length > 0
// ) {
// if (userTaskForm.value.candidateStrategy === 60) {
// // 特殊:流程表达式,只有一个 input 输入框
// userTaskForm.value.candidateParam = [businessObject.candidateParam];
// } else {
// userTaskForm.value.candidateParam = businessObject.candidateParam
// .split(',')
// .map((item) => item);
// }
// } else {
// userTaskForm.value.candidateParam = [];
// }
};
/** 更新 candidateStrategy 字段时,需要清空 candidateParam并触发 bpmn 图更新 */
@@ -410,27 +231,26 @@ const changeCandidateStrategy = () => {
/** 选中某个 options 时候,更新 bpmn 图 */
const updateElementTask = () => {
let candidateParam =
userTaskForm.value.candidateParam instanceof Array
? userTaskForm.value.candidateParam.join(',')
: userTaskForm.value.candidateParam;
let candidateParam = Array.isArray(userTaskForm.value.candidateParam)
? userTaskForm.value.candidateParam.join(',')
: userTaskForm.value.candidateParam;
// 特殊处理多级部门情况
if (
userTaskForm.value.candidateStrategy ==
userTaskForm.value.candidateStrategy ===
CandidateStrategy.MULTI_LEVEL_DEPT_LEADER ||
userTaskForm.value.candidateStrategy == CandidateStrategy.FORM_DEPT_LEADER
userTaskForm.value.candidateStrategy === CandidateStrategy.FORM_DEPT_LEADER
) {
candidateParam += '|' + deptLevel.value;
candidateParam += `|${deptLevel.value}`;
}
// 特殊处理发起人部门负责人、发起人连续部门负责人
if (
userTaskForm.value.candidateStrategy ==
userTaskForm.value.candidateStrategy ===
CandidateStrategy.START_USER_DEPT_LEADER ||
userTaskForm.value.candidateStrategy ==
userTaskForm.value.candidateStrategy ===
CandidateStrategy.START_USER_MULTI_LEVEL_DEPT_LEADER
) {
candidateParam = deptLevel.value + '';
candidateParam = `${deptLevel.value}`;
}
const extensions = bpmnInstances().moddle.create('bpmn:ExtensionElements', {
@@ -449,11 +269,11 @@ const updateElementTask = () => {
});
// 改用通过extensionElements来存储数据
return;
bpmnInstances().modeling.updateProperties(toRaw(bpmnElement.value), {
candidateStrategy: userTaskForm.value.candidateStrategy,
candidateParam: userTaskForm.value.candidateParam.join(','),
});
// return;
// bpmnInstances().modeling.updateProperties(toRaw(bpmnElement.value), {
// candidateStrategy: userTaskForm.value.candidateStrategy,
// candidateParam: userTaskForm.value.candidateParam.join(','),
// });
};
const updateSkipExpression = () => {
@@ -472,18 +292,22 @@ const updateSkipExpression = () => {
};
// 打开监听器弹窗
const processExpressionDialogRef = ref();
const processExpressionDialogRef = ref<any>();
const openProcessExpressionDialog = async () => {
processExpressionDialogRef.value.open();
};
const selectProcessExpression = (expression: ProcessExpressionVO) => {
const selectProcessExpression = (
expression: BpmProcessExpressionApi.ProcessExpression,
) => {
// @ts-ignore
userTaskForm.value.candidateParam = [expression.expression];
updateElementTask();
};
const handleFormUserChange = (e) => {
const handleFormUserChange = (e: any) => {
if (e === 'PROCESS_START_USER_ID') {
userTaskForm.value.candidateParam = [];
// @ts-ignore
userTaskForm.value.candidateStrategy = CandidateStrategy.START_USER;
}
updateElementTask();
@@ -502,19 +326,238 @@ watch(
onMounted(async () => {
// 获得角色列表
roleOptions.value = await RoleApi.getSimpleRoleList();
roleOptions.value = await getSimpleRoleList();
// 获得部门列表
const deptOptions = await DeptApi.getSimpleDeptList();
const deptOptions = await getSimpleDeptList();
deptTreeOptions.value = handleTree(deptOptions, 'id');
// 获得岗位列表
postOptions.value = await PostApi.getSimplePostList();
postOptions.value = await getSimplePostList();
// 获得用户列表
userOptions.value = await UserApi.getSimpleUserList();
userOptions.value = await getSimpleUserList();
// 获得用户组列表
userGroupOptions.value = await UserGroupApi.getUserGroupSimpleList();
userGroupOptions.value = await getUserGroupSimpleList();
});
onBeforeUnmount(() => {
bpmnElement.value = null;
});
</script>
<template>
<Form :label-col="{ span: 6 }" :wrapper-col="{ span: 18 }">
<FormItem label="规则类型" name="candidateStrategy">
<Select
v-model:value="userTaskForm.candidateStrategy"
allow-clear
style="width: 100%"
@change="changeCandidateStrategy"
>
<SelectOption
v-for="(dict, index) in CANDIDATE_STRATEGY"
:key="index"
:label="dict.label"
:value="dict.value"
/>
</Select>
</FormItem>
<FormItem
v-if="userTaskForm.candidateStrategy === CandidateStrategy.ROLE"
label="指定角色"
name="candidateParam"
>
<Select
v-model:value="userTaskForm.candidateParam"
allow-clear
mode="multiple"
style="width: 100%"
@change="updateElementTask"
>
<SelectOption
v-for="item in roleOptions"
:key="item.id"
:label="item.name"
:value="item.id"
/>
</Select>
</FormItem>
<FormItem
v-if="
userTaskForm.candidateStrategy === CandidateStrategy.DEPT_MEMBER ||
userTaskForm.candidateStrategy === CandidateStrategy.DEPT_LEADER ||
userTaskForm.candidateStrategy ===
CandidateStrategy.MULTI_LEVEL_DEPT_LEADER
"
label="指定部门"
name="candidateParam"
>
<TreeSelect
ref="treeRef"
v-model:value="userTaskForm.candidateParam"
:tree-data="deptTreeOptions"
:field-names="defaultProps"
placeholder="加载中,请稍后"
multiple
tree-checkable
@change="updateElementTask"
/>
</FormItem>
<FormItem
v-if="userTaskForm.candidateStrategy === CandidateStrategy.POST"
label="指定岗位"
name="candidateParam"
>
<Select
v-model:value="userTaskForm.candidateParam"
allow-clear
mode="multiple"
style="width: 100%"
@change="updateElementTask"
>
<SelectOption
v-for="item in postOptions"
:key="item.id"
:label="item.name"
:value="item.id"
/>
</Select>
</FormItem>
<FormItem
v-if="userTaskForm.candidateStrategy === CandidateStrategy.USER"
label="指定用户"
name="candidateParam"
>
<Select
v-model:value="userTaskForm.candidateParam"
allow-clear
mode="multiple"
style="width: 100%"
@change="updateElementTask"
>
<SelectOption
v-for="item in userOptions"
:key="item.id"
:label="item.nickname"
:value="item.id"
/>
</Select>
</FormItem>
<FormItem
v-if="userTaskForm.candidateStrategy === CandidateStrategy.USER_GROUP"
label="指定用户组"
name="candidateParam"
>
<Select
v-model:value="userTaskForm.candidateParam"
allow-clear
mode="multiple"
style="width: 100%"
@change="updateElementTask"
>
<SelectOption
v-for="item in userGroupOptions"
:key="item.id"
:label="item.name"
:value="item.id"
/>
</Select>
</FormItem>
<FormItem
v-if="userTaskForm.candidateStrategy === CandidateStrategy.FORM_USER"
label="表单内用户字段"
name="formUser"
>
<Select
v-model:value="userTaskForm.candidateParam"
allow-clear
style="width: 100%"
@change="handleFormUserChange"
>
<SelectOption
v-for="(item, idx) in userFieldOnFormOptions"
:key="idx"
:label="item.title"
:value="item.field"
:disabled="!item.required"
/>
</Select>
</FormItem>
<FormItem
v-if="
userTaskForm.candidateStrategy === CandidateStrategy.FORM_DEPT_LEADER
"
label="表单内部门字段"
name="formDept"
>
<Select
v-model:value="userTaskForm.candidateParam"
allow-clear
style="width: 100%"
@change="updateElementTask"
>
<SelectOption
v-for="(item, idx) in deptFieldOnFormOptions"
:key="idx"
:label="item.title"
:value="item.field"
:disabled="!item.required"
/>
</Select>
</FormItem>
<FormItem
v-if="
userTaskForm.candidateStrategy ===
CandidateStrategy.MULTI_LEVEL_DEPT_LEADER ||
userTaskForm.candidateStrategy ===
CandidateStrategy.START_USER_DEPT_LEADER ||
userTaskForm.candidateStrategy ===
CandidateStrategy.START_USER_MULTI_LEVEL_DEPT_LEADER ||
userTaskForm.candidateStrategy === CandidateStrategy.FORM_DEPT_LEADER
"
:label="deptLevelLabel!"
name="deptLevel"
>
<Select v-model:value="deptLevel" allow-clear @change="updateElementTask">
<SelectOption
v-for="(item, index) in MULTI_LEVEL_DEPT"
:key="index"
:label="item.label"
:value="item.value"
/>
</Select>
</FormItem>
<FormItem
v-if="userTaskForm.candidateStrategy === CandidateStrategy.EXPRESSION"
label="流程表达式"
name="candidateParam"
>
<Textarea
v-model:value="userTaskForm.candidateParam[0]"
allow-clear
style="width: 100%"
@change="updateElementTask"
/>
<Button
class="!w-1/1 mt-5px"
type="primary"
:icon="h(SelectOutlined)"
@click="openProcessExpressionDialog"
>
选择表达式
</Button>
<!-- 选择弹窗 -->
<ProcessExpressionDialog
ref="processExpressionDialogRef"
@select="selectProcessExpression"
/>
</FormItem>
<FormItem label="跳过表达式" name="skipExpression">
<Textarea
v-model:value="userTaskForm.skipExpression"
allow-clear
style="width: 100%"
@change="updateSkipExpression"
/>
</FormItem>
</Form>
</template>