feat:【antd】【bpm】processInstance/detail 代码评审

This commit is contained in:
YunaiV
2025-10-24 00:01:38 +08:00
parent cbb65ffff3
commit bbd32a274e
26 changed files with 227 additions and 299 deletions

View File

@@ -11,6 +11,12 @@ import {
BpmTaskStatusEnum, BpmTaskStatusEnum,
DICT_TYPE, DICT_TYPE,
} from '@vben/constants'; } from '@vben/constants';
import {
SvgBpmApproveIcon,
SvgBpmCancelIcon,
SvgBpmRejectIcon,
SvgBpmRunningIcon,
} from '@vben/icons';
import { formatDateTime } from '@vben/utils'; import { formatDateTime } from '@vben/utils';
import { Avatar, Card, Col, message, Row, TabPane, Tabs } from 'ant-design-vue'; import { Avatar, Card, Col, message, Row, TabPane, Tabs } from 'ant-design-vue';
@@ -23,12 +29,6 @@ import { getSimpleUserList } from '#/api/system/user';
import DictTag from '#/components/dict-tag/dict-tag.vue'; import DictTag from '#/components/dict-tag/dict-tag.vue';
import { setConfAndFields2 } from '#/components/form-create'; import { setConfAndFields2 } from '#/components/form-create';
import { registerComponent } from '#/utils'; import { registerComponent } from '#/utils';
import {
SvgBpmApproveIcon,
SvgBpmCancelIcon,
SvgBpmRejectIcon,
SvgBpmRunningIcon,
} from '#/views/bpm/processInstance/detail/modules/icons';
import ProcessInstanceBpmnViewer from './modules/bpm-viewer.vue'; import ProcessInstanceBpmnViewer from './modules/bpm-viewer.vue';
import ProcessInstanceOperationButton from './modules/operation-button.vue'; import ProcessInstanceOperationButton from './modules/operation-button.vue';
@@ -44,22 +44,11 @@ const props = defineProps<{
taskId?: string; // 任务编号 taskId?: string; // 任务编号
}>(); }>();
// TODO @jason是不是使用全局的 FieldPermissionTypeexport enum FieldPermissionType {
enum FieldPermissionType { enum FieldPermissionType {
/** NONE = '3', // 隐藏
* 隐藏 READ = '1', // 只读
*/ WRITE = '2', // 编辑
// eslint-disable-next-line no-unused-vars
NONE = '3',
/**
* 只读
*/
// eslint-disable-next-line no-unused-vars
READ = '1',
/**
* 编辑
*/
// eslint-disable-next-line no-unused-vars
WRITE = '2',
} }
const processInstanceLoading = ref(false); // 流程实例的加载中 const processInstanceLoading = ref(false); // 流程实例的加载中
@@ -67,6 +56,8 @@ const processInstance = ref<BpmProcessInstanceApi.ProcessInstance>(); // 流程
const processDefinition = ref<any>({}); // 流程定义 const processDefinition = ref<any>({}); // 流程定义
const processModelView = ref<any>({}); // 流程模型视图 const processModelView = ref<any>({}); // 流程模型视图
const operationButtonRef = ref(); // 操作按钮组件 ref const operationButtonRef = ref(); // 操作按钮组件 ref
const activeTab = ref('form');
const taskListRef = ref();
const auditIconsMap: { const auditIconsMap: {
[key: string]: [key: string]:
| typeof SvgBpmApproveIcon | typeof SvgBpmApproveIcon
@@ -82,29 +73,28 @@ const auditIconsMap: {
[BpmTaskStatusEnum.RETURN]: SvgBpmRejectIcon, [BpmTaskStatusEnum.RETURN]: SvgBpmRejectIcon,
[BpmTaskStatusEnum.WAIT]: SvgBpmRunningIcon, [BpmTaskStatusEnum.WAIT]: SvgBpmRunningIcon,
}; };
const activityNodes = ref<BpmProcessInstanceApi.ApprovalNodeInfo[]>([]); // 审批节点信息
const userOptions = ref<SystemUserApi.User[]>([]); // 用户列表
// ========== 申请信息 ========== const fApi = ref<any>();
const fApi = ref<any>(); //
const detailForm = ref({ const detailForm = ref({
rule: [], rule: [],
option: {}, option: {},
value: {}, value: {},
}); // 流程实例的表单详情 }); // 流程实例的表单详情
const writableFields: Array<string> = []; // 表单可以编辑的字段 const writableFields: Array<string> = []; // 表单可以编辑的字段
/** 加载流程实例 */ const BusinessFormComponent = shallowRef<any>(null); // 异步组件(业务表单)
const BusinessFormComponent = shallowRef<any>(null); // 异步组件
/** 获取详情 */ /** 获取详情 */
async function getDetail() { async function getDetail() {
// 获得审批详情 // 获得审批详情
getApprovalDetail(); await getApprovalDetail();
// 获得流程模型视图 // 获得流程模型视图
getProcessModelView(); await getProcessModelView();
} }
/** 获得审批详情 */
async function getApprovalDetail() { async function getApprovalDetail() {
processInstanceLoading.value = true; processInstanceLoading.value = true;
try { try {
@@ -114,11 +104,9 @@ async function getApprovalDetail() {
taskId: props.taskId, taskId: props.taskId,
}; };
const data = await getApprovalDetailApi(param); const data = await getApprovalDetailApi(param);
if (!data) { if (!data) {
message.error('查询不到审批详情信息!'); message.error('查询不到审批详情信息!');
} }
if (!data.processDefinition || !data.processInstance) { if (!data.processDefinition || !data.processInstance) {
message.error('查询不到流程信息!'); message.error('查询不到流程信息!');
} }
@@ -143,6 +131,7 @@ async function getApprovalDetail() {
processInstance.value.formVariables, processInstance.value.formVariables,
); );
} }
// TODO @jason这里 await 来搞?
nextTick().then(() => { nextTick().then(() => {
fApi.value?.btn.show(false); fApi.value?.btn.show(false);
fApi.value?.resetBtn.show(false); fApi.value?.resetBtn.show(false);
@@ -187,11 +176,7 @@ async function getProcessModelView() {
} }
} }
// 审批节点信息 /** 设置表单权限 */
const activityNodes = ref<BpmProcessInstanceApi.ApprovalNodeInfo[]>([]);
/**
* 设置表单权限
*/
function setFieldPermission(field: string, permission: string) { function setFieldPermission(field: string, permission: string) {
if (permission === FieldPermissionType.READ) { if (permission === FieldPermissionType.READ) {
fApi.value?.disabled(true, field); fApi.value?.disabled(true, field);
@@ -206,6 +191,7 @@ function setFieldPermission(field: string, permission: string) {
} }
} }
// TODO @jason这个还要么
/** /**
* 操作成功后刷新 * 操作成功后刷新
*/ */
@@ -214,16 +200,13 @@ function setFieldPermission(field: string, permission: string) {
// getDetail(); // getDetail();
// }; // };
/** 当前的Tab */
const activeTab = ref('form');
const taskListRef = ref();
/** 监听 Tab 切换,当切换到 "record" 标签时刷新任务列表 */ /** 监听 Tab 切换,当切换到 "record" 标签时刷新任务列表 */
watch( watch(
() => activeTab.value, () => activeTab.value,
(newVal) => { (newVal) => {
if (newVal === 'record') { if (newVal === 'record') {
// 如果切换到流转记录标签,刷新任务列表 // 如果切换到流转记录标签,刷新任务列表
// TODO @jasonawait nextTick 要不?
nextTick(() => { nextTick(() => {
taskListRef.value?.refresh(); taskListRef.value?.refresh();
}); });
@@ -232,7 +215,6 @@ watch(
); );
/** 初始化 */ /** 初始化 */
const userOptions = ref<SystemUserApi.User[]>([]); // 用户列表
onMounted(async () => { onMounted(async () => {
await getDetail(); await getDetail();
// 获得用户列表 // 获得用户列表
@@ -281,9 +263,9 @@ onMounted(async () => {
> >
{{ processInstance?.startUser?.nickname.substring(0, 1) }} {{ processInstance?.startUser?.nickname.substring(0, 1) }}
</Avatar> </Avatar>
<span class="text-sm">{{ <span class="text-sm">
processInstance?.startUser?.nickname {{ processInstance?.startUser?.nickname }}
}}</span> </span>
</div> </div>
<div class="text-gray-500"> <div class="text-gray-500">
{{ formatDateTime(processInstance?.startTime) }} 提交 {{ formatDateTime(processInstance?.startTime) }} 提交
@@ -324,9 +306,8 @@ onMounted(async () => {
:rule="detailForm.rule" :rule="detailForm.rule"
/> />
</div> </div>
<div <div
v-if=" v-else-if="
processDefinition?.formType === BpmModelFormType.CUSTOM processDefinition?.formType === BpmModelFormType.CUSTOM
" "
class="h-full" class="h-full"
@@ -341,7 +322,6 @@ onMounted(async () => {
</Col> </Col>
</Row> </Row>
</TabPane> </TabPane>
<TabPane <TabPane
tab="流程图" tab="流程图"
key="diagram" key="diagram"
@@ -367,7 +347,6 @@ onMounted(async () => {
/> />
</div> </div>
</TabPane> </TabPane>
<TabPane tab="流转记录" key="record" class="tab-pane-content"> <TabPane tab="流转记录" key="record" class="tab-pane-content">
<div class="h-full"> <div class="h-full">
<BpmProcessInstanceTaskList <BpmProcessInstanceTaskList
@@ -377,7 +356,6 @@ onMounted(async () => {
/> />
</div> </div>
</TabPane> </TabPane>
<!-- TODO 待开发 --> <!-- TODO 待开发 -->
<TabPane <TabPane
tab="流转评论" tab="流转评论"
@@ -410,6 +388,7 @@ onMounted(async () => {
</template> </template>
<style lang="scss" scoped> <style lang="scss" scoped>
// @jason看看能不能通过 tailwindcss 简化下
.ant-tabs-content { .ant-tabs-content {
height: 100%; height: 100%;
} }

View File

@@ -3,7 +3,7 @@ defineOptions({ name: 'ProcessInstanceBpmnViewer' });
</script> </script>
<template> <template>
<!-- TODO @ziye可以后续找下 antd 有没可以直接用的组件哈 --> <!-- TODO @jason这里 BPMN 图的接入 -->
<div> <div>
<h1>BPMN Viewer</h1> <h1>BPMN Viewer</h1>
</div> </div>

View File

@@ -1,15 +0,0 @@
import { createIconifyIcon } from '@vben/icons';
// bpm 图标
// TODO @siye可以新建出一个 bpm 目录哇icons/bpm
const SvgBpmRunningIcon = createIconifyIcon('svg:bpm-running');
const SvgBpmApproveIcon = createIconifyIcon('svg:bpm-approve');
const SvgBpmRejectIcon = createIconifyIcon('svg:bpm-reject');
const SvgBpmCancelIcon = createIconifyIcon('svg:bpm-cancel');
export {
SvgBpmApproveIcon,
SvgBpmCancelIcon,
SvgBpmRejectIcon,
SvgBpmRunningIcon,
};

View File

@@ -1,4 +1,5 @@
<script lang="ts" setup> <script lang="ts" setup>
// TODO @jason你感觉要拆分下按照表单么
import type { FormInstance } from 'ant-design-vue'; import type { FormInstance } from 'ant-design-vue';
import type { Rule } from 'ant-design-vue/es/form'; import type { Rule } from 'ant-design-vue/es/form';
@@ -51,8 +52,6 @@ import ProcessInstanceTimeline from './time-line.vue';
defineOptions({ name: 'ProcessInstanceBtnContainer' }); defineOptions({ name: 'ProcessInstanceBtnContainer' });
// 定义 success 事件,用于操作成功后的回调
const props = defineProps<{ const props = defineProps<{
normalForm: any; // 流程表单 formCreate normalForm: any; // 流程表单 formCreate
normalFormApi: any; // 流程表单 formCreate Api normalFormApi: any; // 流程表单 formCreate Api
@@ -68,11 +67,6 @@ const [SignatureModal, signatureModalApi] = useVbenModal({
destroyOnClose: true, destroyOnClose: true,
}); });
/** 创建流程表达式 */
function openSignatureModal() {
signatureModalApi.setData(null).open();
}
const router = useRouter(); const router = useRouter();
const userStore = useUserStore(); const userStore = useUserStore();
const userId = userStore.userInfo?.id; const userId = userStore.userInfo?.id;
@@ -90,15 +84,19 @@ const popOverVisible: any = ref({
}); // 气泡卡是否展示 }); // 气泡卡是否展示
const returnList = ref([] as any); // 退回节点 const returnList = ref([] as any); // 退回节点
/** 创建流程表达式 */
function openSignatureModal() {
signatureModalApi.setData(null).open();
}
// ========== 审批信息 ========== // ========== 审批信息 ==========
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 nodeTypeName = ref('审批'); // 节点类型名称
// 审批通过意见表单
const reasonRequire = ref(); const reasonRequire = ref();
const approveFormRef = ref<FormInstance>(); const approveFormRef = ref<FormInstance>(); // 审批通过意见表单
const approveSignFormRef = ref(); const approveSignFormRef = ref();
const nextAssigneesActivityNode = ref<BpmProcessInstanceApi.ApprovalNodeInfo[]>( const nextAssigneesActivityNode = ref<BpmProcessInstanceApi.ApprovalNodeInfo[]>(
[], [],
@@ -127,11 +125,10 @@ const approveReasonRule: Record<string, any> = computed(() => {
}; };
}); });
// 拒绝表单
const rejectFormRef = ref<FormInstance>(); const rejectFormRef = ref<FormInstance>();
const rejectReasonForm = reactive({ const rejectReasonForm = reactive({
reason: '', reason: '',
}); }); // 拒绝表单
const rejectReasonRule: any = computed(() => { const rejectReasonRule: any = computed(() => {
return { return {
reason: [ reason: [
@@ -144,8 +141,7 @@ const rejectReasonRule: any = computed(() => {
} as Record<string, Rule[]>; } as Record<string, Rule[]>;
}); });
// 抄送表单 const copyFormRef = ref<FormInstance>(); // 抄送表单
const copyFormRef = ref<FormInstance>();
const copyForm = reactive({ const copyForm = reactive({
copyUserIds: [], copyUserIds: [],
copyReason: '', copyReason: '',
@@ -156,8 +152,7 @@ const copyFormRule: Record<string, Rule[]> = reactive({
], ],
}); });
// 转办表单 const transferFormRef = ref<FormInstance>(); // 转办表单
const transferFormRef = ref<FormInstance>();
const transferForm = reactive({ const transferForm = reactive({
assigneeUserId: undefined, assigneeUserId: undefined,
reason: '', reason: '',
@@ -169,8 +164,7 @@ const transferFormRule: Record<string, Rule[]> = reactive({
reason: [{ required: true, message: '审批意见不能为空', trigger: 'blur' }], reason: [{ required: true, message: '审批意见不能为空', trigger: 'blur' }],
}); });
// 委派表单 const delegateFormRef = ref<FormInstance>(); // 委派表单
const delegateFormRef = ref<FormInstance>();
const delegateForm = reactive({ const delegateForm = reactive({
delegateUserId: undefined, delegateUserId: undefined,
reason: '', reason: '',
@@ -182,8 +176,7 @@ const delegateFormRule: Record<string, Rule[]> = reactive({
reason: [{ required: true, message: '审批意见不能为空', trigger: 'blur' }], reason: [{ required: true, message: '审批意见不能为空', trigger: 'blur' }],
}); });
// 加签表单 const addSignFormRef = ref<FormInstance>(); // 加签表单
const addSignFormRef = ref<FormInstance>();
const addSignForm = reactive({ const addSignForm = reactive({
addSignUserIds: undefined, addSignUserIds: undefined,
reason: '', reason: '',
@@ -195,8 +188,7 @@ const addSignFormRule: Record<string, Rule[]> = reactive({
reason: [{ required: true, message: '审批意见不能为空', trigger: 'blur' }], reason: [{ required: true, message: '审批意见不能为空', trigger: 'blur' }],
}); });
// 减签表单 const deleteSignFormRef = ref<FormInstance>(); // 减签表单
const deleteSignFormRef = ref<FormInstance>();
const deleteSignForm = reactive({ const deleteSignForm = reactive({
deleteSignTaskId: undefined, deleteSignTaskId: undefined,
reason: '', reason: '',
@@ -208,8 +200,7 @@ const deleteSignFormRule: Record<string, Rule[]> = reactive({
reason: [{ required: true, message: '审批意见不能为空', trigger: 'blur' }], reason: [{ required: true, message: '审批意见不能为空', trigger: 'blur' }],
}); });
// 退回表单 const returnFormRef = ref<FormInstance>(); // 退回表单
const returnFormRef = ref<FormInstance>();
const returnForm = reactive({ const returnForm = reactive({
targetTaskDefinitionKey: undefined, targetTaskDefinitionKey: undefined,
returnReason: '', returnReason: '',
@@ -223,9 +214,7 @@ const returnFormRule: Record<string, Rule[]> = reactive({
], ],
}); });
// 取消表单 const cancelFormRef = ref<FormInstance>(); // 取消表单
const cancelFormRef = ref<FormInstance>();
const cancelForm = reactive({ const cancelForm = reactive({
cancelReason: '', cancelReason: '',
}); });
@@ -256,7 +245,7 @@ async function openPopover(type: string) {
message.warning('表单校验不通过,请先完善表单!!'); message.warning('表单校验不通过,请先完善表单!!');
return; return;
} }
initNextAssigneesFormField(); await initNextAssigneesFormField();
} }
if (type === 'return') { if (type === 'return') {
// 获取退回节点 // 获取退回节点
@@ -269,6 +258,7 @@ async function openPopover(type: string) {
Object.keys(popOverVisible.value).forEach((item) => { Object.keys(popOverVisible.value).forEach((item) => {
if (popOverVisible.value[item]) popOverVisible.value[item] = item === type; if (popOverVisible.value[item]) popOverVisible.value[item] = item === type;
}); });
// TODO @jason下面这 2 行,要删除么?
// await nextTick() // await nextTick()
// formRef.value.resetFields() // formRef.value.resetFields()
} }
@@ -333,6 +323,7 @@ async function initNextAssigneesFormField() {
function selectNextAssigneesConfirm(id: string, userList: any[]) { function selectNextAssigneesConfirm(id: string, userList: any[]) {
approveReasonForm.nextAssignees[id] = userList?.map((item: any) => item.id); approveReasonForm.nextAssignees[id] = userList?.map((item: any) => item.id);
} }
/** 审批通过时,校验每个自选审批人的节点是否都已配置了审批人 */ /** 审批通过时,校验每个自选审批人的节点是否都已配置了审批人 */
function validateNextAssignees() { function validateNextAssignees() {
if (Object.keys(nextAssigneesActivityNode.value).length === 0) { if (Object.keys(nextAssigneesActivityNode.value).length === 0) {
@@ -438,7 +429,9 @@ async function handleTransfer() {
formLoading.value = true; formLoading.value = true;
try { try {
// 1.1 校验表单 // 1.1 校验表单
if (!transferFormRef.value) return; if (!transferFormRef.value) {
return;
}
await transferFormRef.value.validate(); await transferFormRef.value.validate();
// 1.2 提交转交 // 1.2 提交转交
const data = { const data = {
@@ -470,7 +463,6 @@ async function handleDelegate() {
reason: delegateForm.reason, reason: delegateForm.reason,
delegateUserId: delegateForm.delegateUserId, delegateUserId: delegateForm.delegateUserId,
}; };
await TaskApi.delegateTask(data); await TaskApi.delegateTask(data);
popOverVisible.value.delegate = false; popOverVisible.value.delegate = false;
delegateFormRef.value.resetFields(); delegateFormRef.value.resetFields();
@@ -520,7 +512,6 @@ async function handleReturn() {
reason: returnForm.returnReason, reason: returnForm.returnReason,
targetTaskDefinitionKey: returnForm.targetTaskDefinitionKey, targetTaskDefinitionKey: returnForm.targetTaskDefinitionKey,
}; };
await TaskApi.returnTask(data); await TaskApi.returnTask(data);
popOverVisible.value.return = false; popOverVisible.value.return = false;
returnFormRef.value.resetFields(); returnFormRef.value.resetFields();
@@ -557,11 +548,11 @@ async function handleCancel() {
/** 处理再次提交 */ /** 处理再次提交 */
async function handleReCreate() { async function handleReCreate() {
// 跳转发起流程界面 // 跳转发起流程界面
// TODO @jason这个要优化成 push 到 name 么?这样后续 path 可以按需调整;
await router.push({ await router.push({
path: '/bpm/task/create', path: '/bpm/task/create',
query: { processInstanceId: props.processInstance?.id }, query: { processInstanceId: props.processInstance?.id },
}); });
// router.push('/bpm/task/my');
} }
/** 获取减签人员标签 */ /** 获取减签人员标签 */
@@ -570,6 +561,7 @@ function getDeleteSignUserLabel(task: any): string {
const nickname = task?.assigneeUser?.nickname || task?.ownerUser?.nickname; const nickname = task?.assigneeUser?.nickname || task?.ownerUser?.nickname;
return `${nickname} ( 所属部门:${deptName} )`; return `${nickname} ( 所属部门:${deptName} )`;
} }
/** 处理减签 */ /** 处理减签 */
async function handlerDeleteSign() { async function handlerDeleteSign() {
formLoading.value = true; formLoading.value = true;
@@ -592,6 +584,7 @@ async function handlerDeleteSign() {
formLoading.value = false; formLoading.value = false;
} }
} }
/** 重新加载数据 */ /** 重新加载数据 */
function reload() { function reload() {
emit('success'); emit('success');
@@ -643,6 +636,7 @@ function getButtonDisplayName(btnType: BpmTaskOperationButtonTypeEnum) {
return displayName; return displayName;
} }
/** 加载待办任务 */
function loadTodoTask(task: any) { function loadTodoTask(task: any) {
approveForm.value = {}; approveForm.value = {};
runningTask.value = task; runningTask.value = task;
@@ -650,7 +644,7 @@ function loadTodoTask(task: any) {
reasonRequire.value = task?.reasonRequire ?? false; reasonRequire.value = task?.reasonRequire ?? false;
nodeTypeName.value = nodeTypeName.value =
task?.nodeType === BpmNodeTypeEnum.TRANSACTOR_NODE ? '办理' : '审批'; task?.nodeType === BpmNodeTypeEnum.TRANSACTOR_NODE ? '办理' : '审批';
// 处理 approve 表单. // 处理 approve 表单
if (task && task.formId && task.formConf) { if (task && task.formId && task.formConf) {
const tempApproveForm = {}; const tempApproveForm = {};
setConfAndFields2( setConfAndFields2(
@@ -707,6 +701,7 @@ defineExpose({ loadTodoTask });
</script> </script>
<template> <template>
<div class="flex items-center"> <div class="flex items-center">
<!-- TODO @jason这里要删除么 -->
<!-- <div>是否处理中 {{ !!isHandleTaskStatus() }}</div> --> <!-- <div>是否处理中 {{ !!isHandleTaskStatus() }}</div> -->
<!-- 通过按钮 --> <!-- 通过按钮 -->
@@ -777,7 +772,6 @@ defineExpose({ loadTodoTask });
<Button @click="openSignatureModal" type="primary"> <Button @click="openSignatureModal" type="primary">
{{ approveReasonForm.signPicUrl ? '重新签名' : '点击签名' }} {{ approveReasonForm.signPicUrl ? '重新签名' : '点击签名' }}
</Button> </Button>
<div class="mt-2"> <div class="mt-2">
<Image <Image
class="float-left h-40 w-80" class="float-left h-40 w-80"
@@ -786,7 +780,6 @@ defineExpose({ loadTodoTask });
/> />
</div> </div>
</FormItem> </FormItem>
<FormItem :label="`${nodeTypeName}意见`" name="reason"> <FormItem :label="`${nodeTypeName}意见`" name="reason">
<Textarea <Textarea
v-model:value="approveReasonForm.reason" v-model:value="approveReasonForm.reason"
@@ -794,7 +787,6 @@ defineExpose({ loadTodoTask });
:rows="4" :rows="4"
/> />
</FormItem> </FormItem>
<FormItem> <FormItem>
<Space> <Space>
<Button <Button
@@ -902,6 +894,7 @@ defineExpose({ loadTodoTask });
label-width="100px" label-width="100px"
> >
<FormItem label="抄送人" name="copyUserIds"> <FormItem label="抄送人" name="copyUserIds">
<!-- TODO @jason看看是不是用 看看能不能通过 tailwindcss 简化下 style -->
<Select <Select
v-model:value="copyForm.copyUserIds" v-model:value="copyForm.copyUserIds"
:allow-clear="true" :allow-clear="true"

View File

@@ -6,7 +6,6 @@ import { IconifyIcon } from '@vben/icons';
import { base64ToFile } from '@vben/utils'; import { base64ToFile } from '@vben/utils';
import { Button, message, Space, Tooltip } from 'ant-design-vue'; import { Button, message, Space, Tooltip } from 'ant-design-vue';
// TODO @ziye这个可能适合放到全局因为 element-plus 也用这个;
import Vue3Signature from 'vue3-signature'; import Vue3Signature from 'vue3-signature';
import { uploadFile } from '#/api/infra/file'; import { uploadFile } from '#/api/infra/file';
@@ -20,28 +19,29 @@ const emits = defineEmits(['success']);
const signature = ref<InstanceType<typeof Vue3Signature>>(); const signature = ref<InstanceType<typeof Vue3Signature>>();
const [Modal, modalApi] = useVbenModal({ const [Modal, modalApi] = useVbenModal({
title: '流程签名',
onOpenChange(visible) {
if (!visible) {
modalApi.close();
}
},
async onConfirm() { async onConfirm() {
// TODO @jason这里需要使用类似 modalApi.lock() 么?类似别的模块
message.success({ message.success({
content: '签名上传中请稍等。。。', content: '签名上传中请稍等...',
}); });
const signFileUrl = await uploadFile({ const signFileUrl = await uploadFile({
file: base64ToFile(signature?.value?.save('image/jpeg') || '', '签名'), file: base64ToFile(signature?.value?.save('image/jpeg') || '', '签名'),
}); });
emits('success', signFileUrl); emits('success', signFileUrl);
// TODO @ziye下面有个告警哈ps所有告警皆是错误可以关注 ide 给的提示哈; // TODO @jason是不是不用主动 close
modalApi.close(); await modalApi.close();
},
// TODO @jason这个是不是下面方法可以删除
onOpenChange(visible) {
if (!visible) {
modalApi.close();
}
}, },
}); });
</script> </script>
<template> <template>
<Modal class="h-2/5 w-3/5"> <Modal title="流程签名" class="h-2/5 w-3/5">
<div class="mb-2 flex justify-end"> <div class="mb-2 flex justify-end">
<Space> <Space>
<Tooltip title="撤销上一步操作"> <Tooltip title="撤销上一步操作">
@@ -52,7 +52,6 @@ const [Modal, modalApi] = useVbenModal({
撤销 撤销
</Button> </Button>
</Tooltip> </Tooltip>
<Tooltip title="清空画布"> <Tooltip title="清空画布">
<Button @click="signature?.clear()"> <Button @click="signature?.clear()">
<template #icon> <template #icon>

View File

@@ -23,10 +23,8 @@ const props = withDefaults(
); );
const simpleModel = ref<any>({}); const simpleModel = ref<any>({});
// 用户任务 const tasks = ref([]); // 用户任务
const tasks = ref([]); const processInstance = ref(); // 流程实例
// 流程实例
const processInstance = ref();
/** 监控模型视图 包括任务列表、进行中的活动节点编号等 */ /** 监控模型视图 包括任务列表、进行中的活动节点编号等 */
watch( watch(
@@ -69,6 +67,7 @@ watch(
} }
}, },
); );
const setSimpleModelNodeTaskStatus = ( const setSimpleModelNodeTaskStatus = (
simpleModel: SimpleFlowNode | undefined, simpleModel: SimpleFlowNode | undefined,
processStatus: number, processStatus: number,
@@ -102,7 +101,7 @@ const setSimpleModelNodeTaskStatus = (
} else if (finishedActivityIds.includes(simpleModel.id)) { } else if (finishedActivityIds.includes(simpleModel.id)) {
simpleModel.activityStatus = BpmTaskStatusEnum.APPROVE; simpleModel.activityStatus = BpmTaskStatusEnum.APPROVE;
} }
// TODO 是不是还缺一个 cancel 的状态 // TODO 是不是还缺一个 cancel 的状态 @jason
} }
// 抄送节点 // 抄送节点
if (simpleModel.type === BpmNodeTypeEnum.COPY_TASK_NODE) { if (simpleModel.type === BpmNodeTypeEnum.COPY_TASK_NODE) {
@@ -177,5 +176,3 @@ const setSimpleModelNodeTaskStatus = (
/> />
</div> </div>
</template> </template>
<style lang="scss" scoped></style>

View File

@@ -1,10 +1,10 @@
<script setup lang="ts"> <script lang="ts" setup>
import type { formCreate } from '@form-create/antd-designer'; import type { formCreate } from '@form-create/antd-designer';
import type { VxeTableGridOptions } from '#/adapter/vxe-table'; import type { VxeTableGridOptions } from '#/adapter/vxe-table';
import type { BpmTaskApi } from '#/api/bpm/task'; import type { BpmTaskApi } from '#/api/bpm/task';
import { nextTick, onMounted, ref, shallowRef } from 'vue'; import { nextTick, ref } from 'vue';
import { useVbenModal } from '@vben/common-ui'; import { useVbenModal } from '@vben/common-ui';
import { DICT_TYPE } from '@vben/constants'; import { DICT_TYPE } from '@vben/constants';
@@ -25,64 +25,119 @@ const props = defineProps<{
loading: boolean; loading: boolean;
}>(); }>();
// 使用 shallowRef 减少不必要的深度响应 /** 表单类型定义 */
const columns = shallowRef([ interface TaskForm {
{ rule: any[];
field: 'name', option: Record<string, any>;
title: '审批节点', value: Record<string, any>;
minWidth: 150, }
},
{ /** 获取表格列配置 */
field: 'approver', function useGridColumns(): VxeTableGridOptions['columns'] {
title: '审批人', return [
slots: { {
default: ({ row }: { row: BpmTaskApi.TaskManager }) => { field: 'name',
return row.assigneeUser?.nickname || row.ownerUser?.nickname; title: '审批节点',
minWidth: 150,
},
{
field: 'approver',
title: '审批人',
slots: {
default: ({ row }: { row: BpmTaskApi.TaskManager }) => {
return row.assigneeUser?.nickname || row.ownerUser?.nickname;
},
},
minWidth: 180,
},
{
field: 'createTime',
title: '开始时间',
formatter: 'formatDateTime',
minWidth: 180,
},
{
field: 'endTime',
title: '结束时间',
formatter: 'formatDateTime',
minWidth: 180,
},
{
field: 'status',
title: '审批状态',
minWidth: 150,
cellRender: {
name: 'CellDict',
props: { type: DICT_TYPE.BPM_TASK_STATUS },
}, },
}, },
minWidth: 180, {
}, field: 'reason',
{ title: '审批建议',
field: 'createTime', slots: {
title: '开始时间', default: 'slot-reason',
formatter: 'formatDateTime', },
minWidth: 180, minWidth: 200,
},
{
field: 'endTime',
title: '结束时间',
formatter: 'formatDateTime',
minWidth: 180,
},
{
field: 'status',
title: '审批状态',
minWidth: 150,
cellRender: {
name: 'CellDict',
props: { type: DICT_TYPE.BPM_TASK_STATUS },
}, },
}, {
{ field: 'durationInMillis',
field: 'reason', title: '耗时',
title: '审批建议', minWidth: 180,
slots: { formatter: 'formatPast2',
default: 'slot-reason',
}, },
minWidth: 200, ];
}, }
{
field: 'durationInMillis', const formRef = ref<formCreate>();
title: '耗时', const taskForm = ref<TaskForm>({
minWidth: 180, rule: [],
formatter: 'formatPast2', option: {},
}, value: {},
]); });
const [Modal, modalApi] = useVbenModal({
title: '查看表单',
footer: false,
});
/** 刷新表格 */
function handleRefresh() {
gridApi.query();
}
/** 显示表单详情 */
async function handleShowFormDetail(row: BpmTaskApi.TaskManager) {
// 设置表单配置和表单字段
taskForm.value = {
rule: [],
option: {},
value: row,
};
setConfAndFields2(
taskForm,
row.formConf,
row.formFields || [],
row.formVariables || {},
);
// 打开弹窗
modalApi.open();
// 等待表单渲染
await nextTick();
// 获取表单 API 实例
const formApi = formRef.value?.fapi;
if (!formApi) {
return;
}
// 设置表单不可编辑
formApi.btn.show(false);
formApi.resetBtn.show(false);
formApi.disabled(true);
}
// Grid配置和API
const [Grid, gridApi] = useVbenVxeGrid({ const [Grid, gridApi] = useVbenVxeGrid({
gridOptions: { gridOptions: {
columns: columns.value, columns: useGridColumns(),
keepSource: true, keepSource: true,
showFooter: true, showFooter: true,
border: true, border: true,
@@ -96,6 +151,7 @@ const [Grid, gridApi] = useVbenVxeGrid({
}, },
rowConfig: { rowConfig: {
keyField: 'id', keyField: 'id',
isHover: true,
}, },
pagerConfig: { pagerConfig: {
enabled: false, enabled: false,
@@ -103,84 +159,11 @@ const [Grid, gridApi] = useVbenVxeGrid({
toolbarConfig: { toolbarConfig: {
enabled: false, enabled: false,
}, },
cellConfig: { } as VxeTableGridOptions<BpmTaskApi.TaskManager>,
height: 60,
},
} as VxeTableGridOptions<BpmTaskApi.Task>,
}); });
/**
* 刷新表格数据
*/
function refresh() {
gridApi.query();
}
// 表单相关
interface TaskForm {
rule: any[];
option: Record<string, any>;
value: Record<string, any>;
}
// 定义表单组件引用类型
// 使用明确的类型定义
const formRef = ref<formCreate>();
const taskForm = ref<TaskForm>({
rule: [],
option: {},
value: {},
});
/**
* 显示表单详情
* @param row 任务数据
*/
async function showFormDetail(row: BpmTaskApi.TaskManager): Promise<void> {
// 设置表单配置和表单字段
taskForm.value = {
rule: [],
option: {},
value: row,
};
setConfAndFields2(
taskForm,
row.formConf,
row.formFields || [],
row.formVariables || {},
);
// 打开弹窗
modalApi.open();
// 等待表单渲染
await nextTick();
// 获取表单API实例
const formApi = formRef.value?.fapi;
if (!formApi) return;
// 设置表单不可编辑
formApi.btn.show(false);
formApi.resetBtn.show(false);
formApi.disabled(true);
}
// 表单查看模态框
const [Modal, modalApi] = useVbenModal({
title: '查看表单',
footer: false,
});
onMounted(() => {
refresh();
});
// 暴露刷新方法给父组件
defineExpose({ defineExpose({
refresh, refresh: handleRefresh,
}); });
</script> </script>
@@ -191,14 +174,13 @@ defineExpose({
<div class="flex flex-wrap items-center justify-center"> <div class="flex flex-wrap items-center justify-center">
<span v-if="row.reason">{{ row.reason }}</span> <span v-if="row.reason">{{ row.reason }}</span>
<span v-else>-</span> <span v-else>-</span>
<Button <Button
v-if="row.formId > 0" v-if="row.formId > 0"
type="primary" type="primary"
@click="showFormDetail(row)"
size="small" size="small"
ghost ghost
class="ml-1" class="ml-1"
@click="handleShowFormDetail(row)"
> >
<IconifyIcon icon="lucide:file-text" /> <IconifyIcon icon="lucide:file-text" />
<span class="!ml-0.5 text-xs">查看表单</span> <span class="!ml-0.5 text-xs">查看表单</span>

View File

@@ -38,34 +38,21 @@ const emit = defineEmits<{
const { push } = useRouter(); const { push } = useRouter();
// 状态图标映射
const statusIconMap: Record< const statusIconMap: Record<
string, string,
{ animation?: string; color: string; icon: string } { animation?: string; color: string; icon: string }
> = { > = {
// 跳过 '-2': { color: '#909398', icon: 'mdi:skip-forward-outline' }, // 跳过
'-2': { color: '#909398', icon: 'mdi:skip-forward-outline' }, '-1': { color: '#909398', icon: 'mdi:clock-outline' }, // 审批未开始
// 审批未开始 '0': { color: '#ff943e', icon: 'mdi:loading', animation: 'animate-spin' }, // 审批
'-1': { color: '#909398', icon: 'mdi:clock-outline' }, '1': { color: '#448ef7', icon: 'mdi:loading', animation: 'animate-spin' }, // 审批中
// 审批 '2': { color: '#00b32a', icon: 'mdi:check' }, // 审批通过
'0': { color: '#ff943e', icon: 'mdi:loading', animation: 'animate-spin' }, '3': { color: '#f46b6c', icon: 'mdi:close' }, // 审批不通过
// 审批中 '4': { color: '#cccccc', icon: 'mdi:trash-can-outline' }, // 已取消
'1': { color: '#448ef7', icon: 'mdi:loading', animation: 'animate-spin' }, '5': { color: '#f46b6c', icon: 'mdi:arrow-left' }, // 退回
// 审批通过 '6': { color: '#448ef7', icon: 'mdi:clock-outline' }, // 委派中
'2': { color: '#00b32a', icon: 'mdi:check' }, '7': { color: '#00b32a', icon: 'mdi:check' }, // 审批通过中
// 审批不通过 }; // 状态图标映射
'3': { color: '#f46b6c', icon: 'mdi:close' },
// 已取消
'4': { color: '#cccccc', icon: 'mdi:trash-can-outline' },
// 退回
'5': { color: '#f46b6c', icon: 'mdi:arrow-left' },
// 委派中
'6': { color: '#448ef7', icon: 'mdi:clock-outline' },
// 审批通过中
'7': { color: '#00b32a', icon: 'mdi:check' },
};
// 节点类型图标映射
const nodeTypeSvgMap = { const nodeTypeSvgMap = {
// 结束节点 // 结束节点
[BpmNodeTypeEnum.END_EVENT_NODE]: { [BpmNodeTypeEnum.END_EVENT_NODE]: {
@@ -107,40 +94,39 @@ const nodeTypeSvgMap = {
color: '#14bb83', color: '#14bb83',
icon: 'icon-park-outline:tree-diagram', icon: 'icon-park-outline:tree-diagram',
}, },
} as Record<BpmNodeTypeEnum, { color: string; icon: string }>; } as Record<BpmNodeTypeEnum, { color: string; icon: string }>; // 节点类型图标映射
const onlyStatusIconShow = [-1, 0, 1]; // 只有状态是 -1、0、1 才展示头像右小角状态小 icon
// 只有状态是 -1、0、1 才展示头像右小角状态小icon /** 获取审批节点类型图标 */
const onlyStatusIconShow = [-1, 0, 1];
// 获取审批节点类型图标
function getApprovalNodeTypeIcon(nodeType: BpmNodeTypeEnum) { function getApprovalNodeTypeIcon(nodeType: BpmNodeTypeEnum) {
return nodeTypeSvgMap[nodeType]?.icon; return nodeTypeSvgMap[nodeType]?.icon;
} }
// 获取审批节点图标 /** 获取审批节点图标 */
function getApprovalNodeIcon(taskStatus: number, nodeType: BpmNodeTypeEnum) { function getApprovalNodeIcon(taskStatus: number, nodeType: BpmNodeTypeEnum) {
if (taskStatus === BpmTaskStatusEnum.NOT_START) { if (taskStatus === BpmTaskStatusEnum.NOT_START) {
return statusIconMap[taskStatus]?.icon || 'mdi:clock-outline'; return statusIconMap[taskStatus]?.icon || 'mdi:clock-outline';
} }
if ( if (
nodeType === BpmNodeTypeEnum.START_USER_NODE || [
nodeType === BpmNodeTypeEnum.USER_TASK_NODE || BpmNodeTypeEnum.START_USER_NODE,
nodeType === BpmNodeTypeEnum.TRANSACTOR_NODE || BpmNodeTypeEnum.USER_TASK_NODE,
nodeType === BpmNodeTypeEnum.CHILD_PROCESS_NODE || BpmNodeTypeEnum.TRANSACTOR_NODE,
nodeType === BpmNodeTypeEnum.END_EVENT_NODE BpmNodeTypeEnum.CHILD_PROCESS_NODE,
BpmNodeTypeEnum.END_EVENT_NODE,
].includes(nodeType)
) { ) {
return statusIconMap[taskStatus]?.icon || 'mdi:clock-outline'; return statusIconMap[taskStatus]?.icon || 'mdi:clock-outline';
} }
return 'mdi:clock-outline'; return 'mdi:clock-outline';
} }
// 获取审批节点颜色 /** 获取审批节点颜色 */
function getApprovalNodeColor(taskStatus: number) { function getApprovalNodeColor(taskStatus: number) {
return statusIconMap[taskStatus]?.color; return statusIconMap[taskStatus]?.color;
} }
// 获取审批节点时间 /** 获取审批节点时间 */
function getApprovalNodeTime(node: BpmProcessInstanceApi.ApprovalNodeInfo) { function getApprovalNodeTime(node: BpmProcessInstanceApi.ApprovalNodeInfo) {
if (node.nodeType === BpmNodeTypeEnum.START_USER_NODE && node.startTime) { if (node.nodeType === BpmNodeTypeEnum.START_USER_NODE && node.startTime) {
return formatDateTime(node.startTime); return formatDateTime(node.startTime);
@@ -154,7 +140,6 @@ function getApprovalNodeTime(node: BpmProcessInstanceApi.ApprovalNodeInfo) {
return ''; return '';
} }
// 选择自定义审批人
const [UserSelectModalComp, userSelectModalApi] = useVbenModal({ const [UserSelectModalComp, userSelectModalApi] = useVbenModal({
connectedComponent: UserSelectModal, connectedComponent: UserSelectModal,
destroyOnClose: true, destroyOnClose: true,
@@ -162,7 +147,7 @@ const [UserSelectModalComp, userSelectModalApi] = useVbenModal({
const selectedActivityNodeId = ref<string>(); const selectedActivityNodeId = ref<string>();
const customApproveUsers = ref<Record<string, any[]>>({}); // keyactivityIdvalue用户列表 const customApproveUsers = ref<Record<string, any[]>>({}); // keyactivityIdvalue用户列表
// 打开选择用户弹窗 /** 打开选择用户弹窗 */
const handleSelectUser = (activityId: string, selectedList: any[]) => { const handleSelectUser = (activityId: string, selectedList: any[]) => {
selectedActivityNodeId.value = activityId; selectedActivityNodeId.value = activityId;
userSelectModalApi userSelectModalApi
@@ -170,7 +155,7 @@ const handleSelectUser = (activityId: string, selectedList: any[]) => {
.open(); .open();
}; };
// 选择用户完成 /** 选择用户完成 */
const selectedUsers = ref<number[]>([]); const selectedUsers = ref<number[]>([]);
function handleUserSelectConfirm(userList: any[]) { function handleUserSelectConfirm(userList: any[]) {
if (!selectedActivityNodeId.value) { if (!selectedActivityNodeId.value) {
@@ -194,7 +179,7 @@ function handleChildProcess(activity: any) {
}); });
} }
// 判断是否需要显示自定义选择审批人 /** 判断是否需要显示自定义选择审批人 */
function shouldShowCustomUserSelect( function shouldShowCustomUserSelect(
activity: BpmProcessInstanceApi.ApprovalNodeInfo, activity: BpmProcessInstanceApi.ApprovalNodeInfo,
) { ) {
@@ -209,7 +194,7 @@ function shouldShowCustomUserSelect(
); );
} }
// 判断是否需要显示审批意见 /** 判断是否需要显示审批意见 */
function shouldShowApprovalReason(task: any, nodeType: BpmNodeTypeEnum) { function shouldShowApprovalReason(task: any, nodeType: BpmNodeTypeEnum) {
return ( return (
task.reason && task.reason &&
@@ -219,12 +204,12 @@ function shouldShowApprovalReason(task: any, nodeType: BpmNodeTypeEnum) {
); );
} }
// 用户选择弹窗关闭 /** 用户选择弹窗关闭 */
function handleUserSelectClosed() { function handleUserSelectClosed() {
selectedUsers.value = []; selectedUsers.value = [];
} }
// 用户选择弹窗取消 /** 用户选择弹窗取消 */
function handleUserSelectCancel() { function handleUserSelectCancel() {
selectedUsers.value = []; selectedUsers.value = [];
} }
@@ -241,7 +226,6 @@ const batchSetCustomApproveUsers = (data: Record<string, any[]>) => {
}); });
}; };
// 暴露方法给父组件
defineExpose({ setCustomApproveUsers, batchSetCustomApproveUsers }); defineExpose({ setCustomApproveUsers, batchSetCustomApproveUsers });
</script> </script>
@@ -264,10 +248,9 @@ defineExpose({ setCustomApproveUsers, batchSetCustomApproveUsers });
class="size-6 text-white" class="size-6 text-white"
/> />
</div> </div>
<div <div
v-if="showStatusIcon" v-if="showStatusIcon"
class="absolute right--2.5 top-4 flex size-5 items-center rounded-full border-2 border-solid border-white p-0.5" class="absolute left-4 top-4 flex size-4 items-center rounded-full border-2 border-solid border-white p-0.5"
:style="{ :style="{
backgroundColor: getApprovalNodeColor(activity.status), backgroundColor: getApprovalNodeColor(activity.status),
}" }"
@@ -409,14 +392,14 @@ defineExpose({ setCustomApproveUsers, batchSetCustomApproveUsers });
v-if=" v-if="
showStatusIcon && onlyStatusIconShow.includes(task.status) showStatusIcon && onlyStatusIconShow.includes(task.status)
" "
class="absolute left-6 top-5 flex items-center rounded-full border-2 border-solid border-white p-1" class="absolute left-5 top-5 flex items-center rounded-full border-2 border-solid border-white p-1"
:style="{ :style="{
backgroundColor: statusIconMap[task.status]?.color, backgroundColor: statusIconMap[task.status]?.color,
}" }"
> >
<IconifyIcon <IconifyIcon
:icon="statusIconMap[task.status]?.icon || 'lucide:clock'" :icon="statusIconMap[task.status]?.icon || 'lucide:clock'"
class="size-2 text-white" class="size-1.5 text-white"
:class="[statusIconMap[task.status]?.animation]" :class="[statusIconMap[task.status]?.animation]"
/> />
</div> </div>

View File

Before

Width:  |  Height:  |  Size: 3.0 KiB

After

Width:  |  Height:  |  Size: 3.0 KiB

View File

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 10 KiB

View File

Before

Width:  |  Height:  |  Size: 7.4 KiB

After

Width:  |  Height:  |  Size: 7.4 KiB

View File

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 KiB

View File

Before

Width:  |  Height:  |  Size: 7.4 KiB

After

Width:  |  Height:  |  Size: 7.4 KiB

View File

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

Before

Width:  |  Height:  |  Size: 3.9 KiB

After

Width:  |  Height:  |  Size: 3.9 KiB

View File

Before

Width:  |  Height:  |  Size: 939 B

After

Width:  |  Height:  |  Size: 939 B

View File

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

Before

Width:  |  Height:  |  Size: 1.0 KiB

After

Width:  |  Height:  |  Size: 1.0 KiB

View File

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

Before

Width:  |  Height:  |  Size: 4.0 KiB

After

Width:  |  Height:  |  Size: 4.0 KiB

View File

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

Before

Width:  |  Height:  |  Size: 2.4 KiB

After

Width:  |  Height:  |  Size: 2.4 KiB

View File

@@ -34,6 +34,12 @@ const SvgWxBarIcon = createIconifyIcon('svg:wx-bar');
const SvgWalletIcon = createIconifyIcon('svg:wallet'); const SvgWalletIcon = createIconifyIcon('svg:wallet');
const SvgMockIcon = createIconifyIcon('svg:mock'); const SvgMockIcon = createIconifyIcon('svg:mock');
/** BPM */
const SvgBpmRunningIcon = createIconifyIcon('svg:bpm-running');
const SvgBpmApproveIcon = createIconifyIcon('svg:bpm-approve');
const SvgBpmRejectIcon = createIconifyIcon('svg:bpm-reject');
const SvgBpmCancelIcon = createIconifyIcon('svg:bpm-cancel');
export { export {
SvgAlipayAppIcon, SvgAlipayAppIcon,
SvgAlipayBarIcon, SvgAlipayBarIcon,
@@ -46,6 +52,10 @@ export {
SvgAvatar3Icon, SvgAvatar3Icon,
SvgAvatar4Icon, SvgAvatar4Icon,
SvgBellIcon, SvgBellIcon,
SvgBpmApproveIcon,
SvgBpmCancelIcon,
SvgBpmRejectIcon,
SvgBpmRunningIcon,
SvgCakeIcon, SvgCakeIcon,
SvgCardIcon, SvgCardIcon,
SvgDingDingIcon, SvgDingDingIcon,