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,12 +77,10 @@ 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) => {
return {
fieldName: `formFieldsParams.${item.field}`, fieldName: `formFieldsParams.${item.field}`,
label: item.title, label: item.title,
component: 'Input', component: 'Input',
@@ -85,16 +88,16 @@ export function useGridFormSchema(
placeholder: `请输入${item.title}`, placeholder: `请输入${item.title}`,
allowClear: true, 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 && processDefinition.formFields) { if (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,60 +48,54 @@ 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: () => {
title: '取消流程', return h(Textarea, {
icon: 'question', placeholder: '请输入取消原因',
component: Input, allowClear: true,
modelPropName: 'value', rows: 2,
async beforeClose(scope) { });
if (!scope.isConfirm) return;
if (!scope.value) {
message.warning('请输入取消原因');
return false;
}
await cancelProcessInstanceByAdmin(row.id, scope.value);
return true;
}, },
}).then(() => { content: '请输入取消原因',
title: '取消流程',
modelPropName: 'value',
}).then(async (reason) => {
if (reason) {
await cancelProcessInstanceByAdmin(row.id, reason);
message.success('取消成功'); message.success('取消成功');
handleRefresh(); handleRefresh();
}
}); });
}; }
/** 创建表格 */ const [Grid, gridApi] = useVbenVxeGrid({
const createGrid = () => {
const [GridCompnent, api] = useVbenVxeGrid({
formOptions: { formOptions: {
schema: useGridFormSchema(userList.value, formFields.value), schema: useGridFormSchema(),
}, },
gridOptions: { gridOptions: {
columns: useGridColumns(formFields.value), columns: useGridColumns(),
height: 'auto', height: 'auto',
keepSource: true, keepSource: true,
rowConfig: { rowConfig: {
keyField: 'id', keyField: 'id',
isHover: true,
}, },
toolbarConfig: { toolbarConfig: {
refresh: true, refresh: true,
@@ -121,9 +104,7 @@ const createGrid = () => {
proxyConfig: { proxyConfig: {
ajax: { ajax: {
query: async ({ page }, formValues) => { query: async ({ page }, formValues) => {
// 处理表单值,将 formFieldsParams 对象提取出来
const { formFieldsParams = {}, ...restValues } = formValues || {}; const { formFieldsParams = {}, ...restValues } = formValues || {};
const params = { const params = {
pageNo: page.currentPage, pageNo: page.currentPage,
pageSize: page.pageSize, pageSize: page.pageSize,
@@ -135,37 +116,24 @@ const createGrid = () => {
}, },
}, },
}, },
} 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>