feat:【antd】bpm processInstance/report/ 的迁移

This commit is contained in:
YunaiV
2025-10-21 19:26:06 +08:00
parent f61e58db96
commit 17558993d4
2 changed files with 102 additions and 130 deletions

View File

@@ -8,26 +8,31 @@ import type { BpmProcessInstanceApi } from '#/api/bpm/processInstance';
import { DICT_TYPE } from '@vben/constants'; import { DICT_TYPE } from '@vben/constants';
import { getDictOptions } from '@vben/hooks'; import { getDictOptions } from '@vben/hooks';
import { getSimpleUserList } from '#/api/system/user';
import { getRangePickerDefaultProps } from '#/utils'; import { getRangePickerDefaultProps } from '#/utils';
/** 搜索的表单 */ interface FormField {
field: string;
title: string;
type: string;
}
/** 列表的搜索表单 */
export function useGridFormSchema( export function useGridFormSchema(
userList: any[] = [], formFields: FormField[] = [],
formFields: any[] = [],
): VbenFormSchema[] { ): VbenFormSchema[] {
// 基础搜索字段 // 基础搜索字段配置
const baseFormSchema = [ const baseFormSchema: VbenFormSchema[] = [
{ {
fieldName: 'startUserId', fieldName: 'startUserId',
label: '发起人', label: '发起人',
component: 'Select', component: 'ApiSelect',
componentProps: { componentProps: {
placeholder: '请选择发起人', placeholder: '请选择发起人',
allowClear: true, allowClear: true,
options: userList.map((user) => ({ api: getSimpleUserList,
label: user.nickname, labelField: 'nickname',
value: user.id, valueField: 'id',
})),
}, },
}, },
{ {
@@ -72,29 +77,27 @@ export function useGridFormSchema(
}, },
]; ];
// 动态表单字段 暂时只支持 input 和 textarea, TODO 其他类型的支持 // 动态表单字段配置:目前支持 input 和 textarea 类型
const dynamicFormSchema = formFields const dynamicFormSchema: VbenFormSchema[] = formFields
.filter((item) => item.type === 'input' || item.type === 'textarea') .filter((item) => ['input', 'textarea'].includes(item.type))
// 根据类型选择合适的表单组件 .map((item) => ({
.map((item) => { fieldName: `formFieldsParams.${item.field}`,
return { label: item.title,
fieldName: `formFieldsParams.${item.field}`, component: 'Input',
label: item.title, componentProps: {
component: 'Input', placeholder: `请输入${item.title}`,
componentProps: { allowClear: true,
placeholder: `请输入${item.title}`, },
allowClear: true, }));
},
};
});
return [...baseFormSchema, ...dynamicFormSchema]; return [...baseFormSchema, ...dynamicFormSchema];
} }
/** 列表的字段 */ /** 列表的字段 */
export function useGridColumns( export function useGridColumns(
formFields: any[] = [], formFields: FormField[] = [],
): VxeTableGridOptions<BpmProcessInstanceApi.ProcessInstance>['columns'] { ): VxeTableGridOptions['columns'] {
// 基础列配置
const baseColumns: VxeGridPropTypes.Columns<BpmProcessInstanceApi.ProcessInstance> = const baseColumns: VxeGridPropTypes.Columns<BpmProcessInstanceApi.ProcessInstance> =
[ [
{ {
@@ -131,8 +134,8 @@ export function useGridColumns(
}, },
]; ];
// 添加动态表单字段列暂时全部以字符串TODO 展示优化, 按 type 展示控制 // 动态表单字段列配置:根据表单字段生成对应的列,从 formVariables 中获取值
const formFieldColumns = (formFields || []).map((item) => ({ const formFieldColumns = formFields.map((item) => ({
field: `formVariables.${item.field}`, field: `formVariables.${item.field}`,
title: item.title, title: item.title,
minWidth: 120, minWidth: 120,

View File

@@ -2,12 +2,12 @@
import type { VxeTableGridOptions } from '#/adapter/vxe-table'; import type { VxeTableGridOptions } from '#/adapter/vxe-table';
import type { BpmProcessInstanceApi } from '#/api/bpm/processInstance'; import type { BpmProcessInstanceApi } from '#/api/bpm/processInstance';
import { nextTick, onMounted, ref } from 'vue'; import { h, onMounted, ref } from 'vue';
import { useRoute, useRouter } from 'vue-router'; import { useRoute, useRouter } from 'vue-router';
import { Page, prompt } from '@vben/common-ui'; import { Page, prompt } from '@vben/common-ui';
import { Input, message } from 'ant-design-vue'; import { message, Textarea } from 'ant-design-vue';
import { ACTION_ICON, TableAction, useVbenVxeGrid } from '#/adapter/vxe-table'; import { ACTION_ICON, TableAction, useVbenVxeGrid } from '#/adapter/vxe-table';
import { getProcessDefinition } from '#/api/bpm/definition'; import { getProcessDefinition } from '#/api/bpm/definition';
@@ -15,39 +15,28 @@ import {
cancelProcessInstanceByAdmin, cancelProcessInstanceByAdmin,
getProcessInstanceManagerPage, getProcessInstanceManagerPage,
} from '#/api/bpm/processInstance'; } from '#/api/bpm/processInstance';
import { getSimpleUserList } from '#/api/system/user';
import { parseFormFields } from '#/components/simple-process-design'; import { parseFormFields } from '#/components/simple-process-design';
import { useGridColumns, useGridFormSchema } from './data'; import { useGridColumns, useGridFormSchema } from './data';
defineOptions({ name: 'BpmProcessInstanceReport' }); defineOptions({ name: 'BpmProcessInstanceReport' });
const router = useRouter(); // 路由 const router = useRouter();
const { query } = useRoute(); const { query } = useRoute();
const processDefinitionId = query.processDefinitionId as string; const processDefinitionId = query.processDefinitionId as string;
const formFields = ref<any[]>([]); const formFields = ref<any[]>([]);
const userList = ref<any[]>([]); // 用户列表
const gridReady = ref(false); // 表格是否准备好
// 表格的列需要解析表单字段,这里定义成变量,解析表单字段后再渲染
let Grid: any = null;
let gridApi: any = null;
/** 获取流程定义 */ /** 获取流程定义 */
const getProcessDefinitionData = async () => { async function getProcessDefinitionData() {
try { const processDefinition = await getProcessDefinition(processDefinitionId);
const processDefinition = await getProcessDefinition(processDefinitionId); if (processDefinition?.formFields) {
if (processDefinition && processDefinition.formFields) { formFields.value = parseFormCreateFields(processDefinition.formFields);
formFields.value = parseFormCreateFields(processDefinition.formFields);
}
} catch (error) {
console.error('获取流程定义失败', error);
} }
}; }
/** 解析表单字段 */ /** 解析表单字段 */
const parseFormCreateFields = (formFields?: string[]) => { function parseFormCreateFields(formFields?: string[]) {
const result: Array<Record<string, any>> = []; const result: Array<Record<string, any>> = [];
if (formFields) { if (formFields) {
formFields.forEach((fieldStr: string) => { formFields.forEach((fieldStr: string) => {
@@ -59,113 +48,92 @@ const parseFormCreateFields = (formFields?: string[]) => {
}); });
} }
return result; return result;
}; }
/** 刷新表格 */ /** 刷新表格 */
function handleRefresh() { function handleRefresh() {
if (gridApi) { gridApi.query();
gridApi.query();
}
} }
/** 查看详情 */ /** 查看详情 */
const handleDetail = (row: BpmProcessInstanceApi.ProcessInstance) => { function handleDetail(row: BpmProcessInstanceApi.ProcessInstance) {
router.push({ router.push({
name: 'BpmProcessInstanceDetail', name: 'BpmProcessInstanceDetail',
query: { query: { id: row.id },
id: row.id,
},
}); });
}; }
/** 取消按钮操作 */ /** 取消流程实例 */
const handleCancel = async (row: BpmProcessInstanceApi.ProcessInstance) => { function handleCancel(row: BpmProcessInstanceApi.ProcessInstance) {
prompt({ prompt({
content: '请输入取消原因:', component: () => {
return h(Textarea, {
placeholder: '请输入取消原因',
allowClear: true,
rows: 2,
});
},
content: '请输入取消原因',
title: '取消流程', title: '取消流程',
icon: 'question',
component: Input,
modelPropName: 'value', modelPropName: 'value',
async beforeClose(scope) { }).then(async (reason) => {
if (!scope.isConfirm) return; if (reason) {
if (!scope.value) { await cancelProcessInstanceByAdmin(row.id, reason);
message.warning('请输入取消原因'); message.success('取消成功');
return false; handleRefresh();
} }
await cancelProcessInstanceByAdmin(row.id, scope.value);
return true;
},
}).then(() => {
message.success('取消成功');
handleRefresh();
}); });
}; }
/** 创建表格 */ const [Grid, gridApi] = useVbenVxeGrid({
const createGrid = () => { formOptions: {
const [GridCompnent, api] = useVbenVxeGrid({ schema: useGridFormSchema(),
formOptions: { },
schema: useGridFormSchema(userList.value, formFields.value), gridOptions: {
columns: useGridColumns(),
height: 'auto',
keepSource: true,
rowConfig: {
keyField: 'id',
isHover: true,
}, },
gridOptions: { toolbarConfig: {
columns: useGridColumns(formFields.value), refresh: true,
height: 'auto', search: true,
keepSource: true, },
rowConfig: { proxyConfig: {
keyField: 'id', ajax: {
}, query: async ({ page }, formValues) => {
toolbarConfig: { const { formFieldsParams = {}, ...restValues } = formValues || {};
refresh: true, const params = {
search: true, pageNo: page.currentPage,
}, pageSize: page.pageSize,
proxyConfig: { ...restValues,
ajax: { processDefinitionKey: query.processDefinitionKey,
query: async ({ page }, formValues) => { formFieldsParams: JSON.stringify(formFieldsParams),
// 处理表单值,将 formFieldsParams 对象提取出来 };
const { formFieldsParams = {}, ...restValues } = formValues || {}; return await getProcessInstanceManagerPage(params);
const params = {
pageNo: page.currentPage,
pageSize: page.pageSize,
...restValues,
processDefinitionKey: query.processDefinitionKey,
formFieldsParams: JSON.stringify(formFieldsParams),
};
return await getProcessInstanceManagerPage(params);
},
}, },
}, },
} as VxeTableGridOptions, },
}); } as VxeTableGridOptions<BpmProcessInstanceApi.ProcessInstance>,
});
Grid = GridCompnent;
gridApi = api;
gridReady.value = true;
};
/** 初始化 */ /** 初始化 */
onMounted(async () => { onMounted(async () => {
// 获取用户列表 // 获取流程定义
userList.value = await getSimpleUserList();
// 获取流程定义,并获取表单字段。
await getProcessDefinitionData(); await getProcessDefinitionData();
// 更新表单配置、表格列配置
// 解析表单字段后,再创建表格,表格的列依赖于表单字段 gridApi.formApi.setState({
createGrid(); schema: useGridFormSchema(formFields.value),
});
// 确保 DOM 更新完成 await gridApi.grid.reloadColumn(useGridColumns(formFields.value) as any[]);
await nextTick();
// 加载表格数据
gridApi.query();
}); });
</script> </script>
<template> <template>
<Page auto-content-height> <Page auto-content-height>
<!-- 动态渲染表格 --> <Grid table-title="流程实例列表">
<component :is="Grid" v-if="gridReady" table-title="流程实例列表">
<template #actions="{ row }"> <template #actions="{ row }">
<TableAction <TableAction
:actions="[ :actions="[
@@ -179,6 +147,7 @@ onMounted(async () => {
{ {
label: '取消', label: '取消',
type: 'link', type: 'link',
danger: true,
icon: ACTION_ICON.DELETE, icon: ACTION_ICON.DELETE,
auth: ['bpm:process-instance:cancel'], auth: ['bpm:process-instance:cancel'],
ifShow: row.status === 1, ifShow: row.status === 1,
@@ -187,6 +156,6 @@ onMounted(async () => {
]" ]"
/> />
</template> </template>
</component> </Grid>
</Page> </Page>
</template> </template>