Files
xiaozhi-admin-ui/src/pages/workflow/spel/index.tsx
T

228 lines
8.0 KiB
TypeScript

import { DeleteOutlined, EditOutlined, PlusOutlined } from '@ant-design/icons';
import {
ModalForm,
PageContainer,
ProFormRadio,
ProFormText,
ProFormTextArea,
ProTable,
type ActionType,
type ProColumns
} from '@ant-design/pro-components';
import { useBoolean } from 'ahooks';
import { Button, Form, message, Popconfirm } from 'antd';
import { useEffect, useMemo, useRef, useState } from 'react';
import type { SpelForm, SpelQuery, SpelVO } from '@/api/workflow/spel/types';
import { addSpel, delSpel, getSpel, listSpel, updateSpel } from '@/api/workflow/spel';
import DictTag from '@/components/common/DictTag';
import EllipsisText from '@/components/common/EllipsisText';
import RowActions from '@/components/common/RowActions';
import { useDict } from '@/hooks/useDict';
import { useTableSelection } from '@/hooks/useTableSelection';
import { useUserStore } from '@/stores/userStore';
import { dictOptions } from '@/utils/dict';
import { hasPermi } from '@/utils/permission';
import { toPageQuery, toTableData } from '@/utils/ruoyi';
const defaultSpelForm: SpelForm = { status: '0' };
const spelPlaceholder = '例如:#{@组件名.方法名(#方法参数)} 或 ${方法参数}';
function buildViewSpel(values: Pick<SpelForm, 'componentName' | 'methodName' | 'methodParams'>) {
const comp = (values.componentName || '').trim();
const method = (values.methodName || '').trim();
const paramStr = (values.methodParams || '').trim();
if (!comp && !method && !paramStr) return '';
if (!comp && !method && paramStr) {
const params = paramStr
.split(',')
.map(item => item.trim())
.filter(Boolean);
if (params.length === 1) return `\${${params[0]}}`;
}
if (!comp || !method) return '请填写组件名称和方法名';
const params = paramStr
.split(',')
.map(item => item.trim())
.filter(Boolean);
const paramPart = params.length ? `(${params.map(item => `#${item}`).join(',')})` : '()';
return `#{@${comp}.${method}${paramPart}}`;
}
export default function WorkflowSpelPage() {
const actionRef = useRef<ActionType | undefined>(undefined);
const [form] = Form.useForm<SpelForm>();
const userInfo = useUserStore(state => state.userInfo);
const dicts = useDict('sys_normal_disable');
const { ids, selectedOne, handleSelectionChange, clearSelection } = useTableSelection<SpelVO>(row => row.id);
const [modalOpen, { setTrue: openModal, setFalse: closeModal }] = useBoolean(false);
const [modalTitle, setModalTitle] = useState('');
const [preview, setPreview] = useState('');
const canAdd = hasPermi(userInfo, ['workflow:spel:add']);
const canEdit = hasPermi(userInfo, ['workflow:spel:edit']);
const canRemove = hasPermi(userInfo, ['workflow:spel:remove']);
const statusOptions = useMemo(() => dictOptions(dicts.sys_normal_disable), [dicts.sys_normal_disable]);
const watchedValues = Form.useWatch([], form);
useEffect(() => {
const nextPreview = buildViewSpel(watchedValues || {});
setPreview(nextPreview);
form.setFieldValue('viewSpel', nextPreview);
}, [form, watchedValues]);
const openAdd = () => {
form.resetFields();
form.setFieldsValue(defaultSpelForm);
setModalTitle('添加流程spel表达式定义');
setPreview('');
openModal();
};
const openEdit = async (row?: SpelVO) => {
const target = row || selectedOne;
if (!target?.id) return;
const res = await getSpel(target.id);
form.resetFields();
form.setFieldsValue(res.data);
setModalTitle('修改流程spel表达式定义');
setPreview(res.data.viewSpel || '');
openModal();
};
const submitForm = async (values: SpelForm) => {
values.id ? await updateSpel(values) : await addSpel(values);
message.success('操作成功');
form.resetFields();
actionRef.current?.reload();
return true;
};
const remove = async (row?: SpelVO) => {
await delSpel(row?.id || ids);
message.success('删除成功');
clearSelection();
actionRef.current?.reloadAndRest?.();
};
const columns: ProColumns<SpelVO>[] = [
{ title: '组件名称', dataIndex: 'componentName', renderText: value => value || '-' },
{ title: '方法名称', dataIndex: 'methodName', renderText: value => value || '-' },
{ title: '参数名称', dataIndex: 'methodParams', search: false, renderText: value => value || '-' },
{
title: 'SPEL表达式',
dataIndex: 'viewSpel',
search: false,
width: 260,
render: (_, row) => <EllipsisText value={row.viewSpel} maxWidth={240} />
},
{
title: '状态',
dataIndex: 'status',
valueType: 'select',
width: 100,
fieldProps: { options: statusOptions },
render: (_, row) => <DictTag options={dicts.sys_normal_disable} value={row.status} />
},
{
title: '备注',
dataIndex: 'remark',
search: false,
width: 180,
render: (_, row) => <EllipsisText value={row.remark} maxWidth={160} />
},
{
title: '操作',
valueType: 'option',
width: 120,
fixed: 'right',
render: (_, row) => (
<RowActions
actions={[
canEdit && { key: 'edit', label: '修改', icon: <EditOutlined />, onClick: () => openEdit(row) },
canRemove && {
key: 'delete',
label: '删除',
icon: <DeleteOutlined />,
danger: true,
confirm: `是否确认删除流程spel表达式定义编号为"${row.id}"的数据项?`,
onClick: () => remove(row)
}
]}
/>
)
}
];
return (
<PageContainer title="流程表达式">
<ProTable<SpelVO, SpelQuery>
actionRef={actionRef}
rowKey="id"
columns={columns}
scroll={{ x: 1110 }}
search={{ labelWidth: 90 }}
rowSelection={{ selectedRowKeys: ids, onChange: handleSelectionChange }}
request={async params => {
const res = await listSpel(toPageQuery(params));
return toTableData(res);
}}
toolbar={{ title: '流程表达式列表' }}
toolBarRender={() => [
canAdd && (
<Button key="add" type="primary" icon={<PlusOutlined />} onClick={openAdd}>
新增
</Button>
),
canEdit && (
<Button key="edit" disabled={!selectedOne} icon={<EditOutlined />} onClick={() => openEdit()}>
修改
</Button>
),
canRemove && (
<Popconfirm
key="delete"
title={`是否确认删除流程spel表达式定义编号为"${ids}"的数据项?`}
onConfirm={() => remove()}
>
<Button danger disabled={!ids.length} icon={<DeleteOutlined />}>
删除
</Button>
</Popconfirm>
)
]}
/>
<ModalForm<SpelForm>
title={modalTitle}
open={modalOpen}
width={560}
form={form}
layout="vertical"
initialValues={defaultSpelForm}
modalProps={{ destroyOnHidden: true, onCancel: closeModal }}
onOpenChange={open => !open && closeModal()}
onFinish={submitForm}
>
<ProFormText name="id" hidden />
<ProFormText name="componentName" label="组件名称" placeholder="如:spelRuleComponent" />
<ProFormText name="methodName" label="方法名称" placeholder="如:selectDeptLeaderById" />
<ProFormText name="methodParams" label="方法参数" placeholder="如:deptId,多个使用逗号分隔" />
<ProFormText name="viewSpel" hidden />
<Form.Item label="SPEL表达式">
<div className="preview-box-react">{preview || spelPlaceholder}</div>
</Form.Item>
<ProFormRadio.Group
name="status"
label="状态"
rules={[{ required: true, message: '状态不能为空' }]}
options={statusOptions}
/>
<ProFormTextArea name="remark" label="备注" fieldProps={{ rows: 3 }} />
</ModalForm>
</PageContainer>
);
}