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

View File

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