增加工具栏提示。

This commit is contained in:
dengqichen 2024-12-11 13:03:12 +08:00
parent a5793f5367
commit e37175099a
8 changed files with 130 additions and 292 deletions

View File

@ -1,7 +1,7 @@
import React, { useEffect, useState } from 'react';
import { Tabs, Spin } from 'antd';
import { NodeType, getNodeTypes } from '../../service';
import { NODE_CONFIG } from '../../configs/nodeConfig';
import { NodeType, NodeCategory } from '../../../../types';
import { getNodeTypes } from '../../../../service';
import './index.less';
interface NodePanelProps {
@ -17,10 +17,8 @@ const NodePanel: React.FC<NodePanelProps> = ({ onNodeDragStart }) => {
setLoading(true);
try {
const response = await getNodeTypes({ enabled: true });
if (response) {
// 只保留有配置的节点类型
const filteredTypes = response.filter(type => NODE_CONFIG[type.code]);
setNodeTypes(filteredTypes);
if (response?.content) {
setNodeTypes(response.content);
}
} catch (error) {
console.error('获取节点类型失败:', error);
@ -49,39 +47,35 @@ const NodePanel: React.FC<NodePanelProps> = ({ onNodeDragStart }) => {
children: (
<div className="node-panel-content">
{types.map((nodeType) => {
const config = NODE_CONFIG[nodeType.code];
if (!config) return null;
const graphConfig = JSON.parse(nodeType.graphConfig || '{}');
return (
<div
key={nodeType.code}
key={nodeType.type}
className="node-card"
draggable
onDragStart={(e) => {
e.dataTransfer.setData('node-type', JSON.stringify({
...nodeType,
config: config // 添加节点配置
graphConfig
}));
onNodeDragStart(nodeType);
}}
style={{
borderColor: config.theme.stroke,
backgroundColor: config.theme.fill
borderColor: graphConfig.attrs?.body?.stroke || '#5F95FF',
backgroundColor: graphConfig.attrs?.body?.fill || '#fff'
}}
>
<div
className="node-icon"
style={{ color: config.theme.stroke }}
style={{ color: graphConfig.attrs?.body?.stroke || '#5F95FF' }}
>
{config.extras?.icon ? (
{graphConfig.attrs?.icon?.xlinkHref && (
<img
src={config.extras.icon['xlink:href']}
src={graphConfig.attrs.icon.xlinkHref}
width={32}
height={32}
alt={nodeType.name}
/>
) : (
<i className={nodeType.icon} />
)}
</div>
<div className="node-name">{nodeType.name}</div>
@ -104,7 +98,7 @@ const NodePanel: React.FC<NodePanelProps> = ({ onNodeDragStart }) => {
<div className="node-panel">
<Tabs
className="node-tabs"
defaultActiveKey="BASIC"
defaultActiveKey="EVENT"
items={tabItems}
/>
</div>
@ -114,7 +108,6 @@ const NodePanel: React.FC<NodePanelProps> = ({ onNodeDragStart }) => {
// 获取类别标签
const getCategoryLabel = (category: string) => {
const labels: Record<string, string> = {
BASIC: '基础节点',
TASK: '任务节点',
EVENT: '事件节点',
GATEWAY: '网关节点',

View File

@ -1,14 +1,14 @@
import { NodeConfig } from '../types';
export const NODE_CONFIG: Record<string, NodeConfig> = {
START: {
startEvent: {
size: { width: 80, height: 80 },
shape: 'circle',
theme: {
fill: '#f6ffed',
stroke: '#52c41a'
},
label: '开始',
label: '开始节点',
extras: {
icon: {
'xlink:href': 'data:image/svg+xml;base64,PHN2ZyB0PSIxNzAzODQ4NTM1NDY5IiBjbGFzcz0iaWNvbiIgdmlld0JveD0iMCAwIDEwMjQgMTAyNCIgdmVyc2lvbj0iMS4xIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHAtaWQ9IjQxNjEiIHdpZHRoPSIyMDAiIGhlaWdodD0iMjAwIj48cGF0aCBkPSJNNTEyIDY0QzI2NC42IDY0IDY0IDI2NC42IDY0IDUxMnMyMDAuNiA0NDggNDQ4IDQ0OCA0NDgtMjAwLjYgNDQ4LTQ0OFM3NTkuNCA2NCA1MTIgNjR6bTE5MiAzMzZjMCA0LjQtMy42IDgtOCA4SDU0NHYxNTJjMCA0LjQtMy42IDgtOCA4aC00OGMtNC40IDAtOC0zLjYtOC04VjQwOEgzMjhjLTQuNCAwLTgtMy42LTgtOHYtNDhjMC00LjQgMy42LTggOC04aDE1MlYxOTJjMC00LjQgMy42LTggOC04aDQ4YzQuNCAwIDggMy42IDggOHYxNTJoMTUyYzQuNCAwIDggMy42IDggOHY0OHoiIGZpbGw9IiM1MmM0MWEiIHAtaWQ9IjQxNjIiPjwvcGF0aD48L3N2Zz4=',
@ -19,14 +19,14 @@ export const NODE_CONFIG: Record<string, NodeConfig> = {
}
}
},
END: {
endEvent: {
size: { width: 80, height: 80 },
shape: 'circle',
theme: {
fill: '#fff1f0',
stroke: '#ff4d4f'
},
label: '结束',
label: '结束节点',
extras: {
icon: {
'xlink:href': 'data:image/svg+xml;base64,PHN2ZyB0PSIxNzAzODQ4NTM1NDY5IiBjbGFzcz0iaWNvbiIgdmlld0JveD0iMCAwIDEwMjQgMTAyNCIgdmVyc2lvbj0iMS4xIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHAtaWQ9IjQxNjEiIHdpZHRoPSIyMDAiIGhlaWdodD0iMjAwIj48cGF0aCBkPSJNNTEyIDY0QzI2NC42IDY0IDY0IDI2NC42IDY0IDUxMnMyMDAuNiA0NDggNDQ4IDQ0OCA0NDgtMjAwLjYgNDQ4LTQ0OFM3NTkuNCA2NCA1MTIgNjR6bTE5MiAyODhjMCA0LjQtMy42IDgtOCA4SDMyOGMtNC40IDAtOC0zLjYtOC04di00OGMwLTQuNCAzLjYtOCA4LThoMzY4YzQuNCAwIDggMy42IDggOHY0OHoiIGZpbGw9IiNmZjRkNGYiIHAtaWQ9IjQxNjIiPjwvcGF0aD48L3N2Zz4=',
@ -37,7 +37,7 @@ export const NODE_CONFIG: Record<string, NodeConfig> = {
}
}
},
SCRIPT: {
shellTask: {
size: { width: 200, height: 80 },
shape: 'rect',
theme: {
@ -57,42 +57,22 @@ export const NODE_CONFIG: Record<string, NodeConfig> = {
}
}
},
TIMER: {
size: { width: 200, height: 80 },
shape: 'rect',
theme: {
fill: '#fff7e6',
stroke: '#fa8c16'
},
label: '定时器',
extras: {
rx: 4,
ry: 4,
icon: {
'xlink:href': 'data:image/svg+xml;base64,PHN2ZyB0PSIxNzAzODQ4NjE2NTM2IiBjbGFzcz0iaWNvbiIgdmlld0JveD0iMCAwIDEwMjQgMTAyNCIgdmVyc2lvbj0iMS4xIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHAtaWQ9IjUzNTgiIHdpZHRoPSIyMDAiIGhlaWdodD0iMjAwIj48cGF0aCBkPSJNNTEyIDY0QzI2NC42IDY0IDY0IDI2NC42IDY0IDUxMnMyMDAuNiA0NDggNDQ4IDQ0OCA0NDgtMjAwLjYgNDQ4LTQ0OFM3NTkuNCA2NCA1MTIgNjR6IG0wIDgyMGMtMjA1LjQgMC0zNzItMTY2LjYtMzcyLTM3MnMxNjYuNi0zNzIgMzcyLTM3MiAzNzIgMTY2LjYgMzcyIDM3Mi0xNjYuNiAzNzItMzcyIDM3MnogbS00NC44LTM3Mi4zaDIzNS45djUzLjhIMzk4LjdWMjk3LjZoNjguNXYyMTQuMXoiIGZpbGw9IiNmYThjMTYiIHAtaWQ9IjUzNTkiPjwvcGF0aD48L3N2Zz4=',
width: 32,
height: 32,
x: 8,
y: 24
}
}
},
GATEWAY: {
exclusiveGateway: {
size: { width: 60, height: 60 },
shape: 'polygon',
theme: {
fill: '#f9f0ff',
stroke: '#722ed1'
},
label: '网关',
label: '排他网关',
extras: {
refPoints: '0,30 30,0 60,30 30,60',
icon: {
'xlink:href': 'data:image/svg+xml;base64,PHN2ZyB0PSIxNzAzODQ4NzAzODY0IiBjbGFzcz0iaWNvbiIgdmlld0JveD0iMCAwIDEwMjQgMTAyNCIgdmVyc2lvbj0iMS4xIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHAtaWQ9IjY1NTUiIHdpZHRoPSIyMDAiIGhlaWdodD0iMjAwIj48cGF0aCBkPSJNNzgyLjcgNDQxLjRMNTQ1IDMwNC44YzAuMy0wLjMgMC40LTAuNyAwLjctMUw3ODIuNyA0NDEuNHogbTExOC45IDQzMi45TDIxNy43IDE1OC4xQzIwMi4xIDE0Mi41IDE3NiAxNDIuNSAxNjAuNCAxNTguMWMtMTUuNiAxNS42LTE1LjYgNDEuNyAwIDU3LjNsNjgzLjkgNzE2LjJjMTUuNiAxNS42IDQxLjcgMTUuNiA1Ny4zIDBzMTUuNi00MS43IDAtNTcuM3ogbS00MjYtMjQuNmMtMC4zIDAuMy0wLjQgMC43LTAuNyAxTDIzNy42IDU4Mi42YzAuMy0wLjMgMC40LTAuNyAwLjctMWwyMzcuMyAyNjguMXogbTIzNy4zLTI2Ny4xTDQ3NS42IDg1MC43YzAuMy0wLjMgMC40LTAuNyAwLjctMUw3MTIuOSA1ODIuNnogbS00NzUtMjY3LjFsMjM3LjMgMjY4LjFjLTAuMyAwLjMtMC40IDAuNy0wLjcgMUwyMzcuOSAzMTUuNXoiIGZpbGw9IiM3MjJlZDEiIHAtaWQ9IjY1NTYiPjwvcGF0aD48L3N2Zz4=',
width: 24,
height: 24,
x: 18,
y: 6
'xlink:href': 'data:image/svg+xml;base64,PHN2ZyB0PSIxNzAzODQ4NzAzODY0IiBjbGFzcz0iaWNvbiIgdmlld0JveD0iMCAwIDEwMjQgMTAyNCIgdmVyc2lvbj0iMS4xIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHAtaWQ9IjY1NTUiIHdpZHRoPSIyMDAiIGhlaWdodD0iMjAwIj48cGF0aCBkPSJNNzgyLjcgNDQxLjRMNTQ1IDMwNC44YzAuMy0wLjMgMC40LTAuNyAwLjctMUw3ODIuNyA0NDEuNHogbTExOC45IDQzMi45TDIxNy43IDE1OC4xQzIwMi4xIDE0Mi41IDE3NiAxNDIuNSAxNjAuNCAxNTguMWMtMTUuNiAxNS42LTE1LjYgNDEuNyAwIDU3LjNsNjgzLjkgNzE2LjJjMTUuNiAxNS42IDQxLjcgMTUuNiA1Ny4zIDBzMTUuNi00MS43IDAtNTcuM3ogbS00MjYtMjQuNmMtMC4zIDAuMy0wLjQgMC43LTAuNyAxTDIzNy42IDU4Mi42YzAuMy0wLjMgMC40LTAuNyAwLjctMWwyMzcuMyAyNjguMXogbTIzNy4zLTI2Ny4xTDQ3NS42IDg1MC43YzAuMy0wLjMgMC40LTAuNyAwLjctMUw3MTMuNiA1ODIuNnoiIGZpbGw9IiM3MjJlZDEiIHAtaWQ9IjY1NTYiPjwvcGF0aD48L3N2Zz4=',
width: 32,
height: 32,
x: 14,
y: 14
}
}
}

View File

@ -105,7 +105,7 @@ const FlowDesigner: React.FC = () => {
if (contextMenu.cell && contextMenu.cell.isNode()) {
setCurrentNode(contextMenu.cell);
const data = contextMenu.cell.getData() as NodeData;
const nodeType = nodeTypes.find(type => type.code === data.type);
const nodeType = nodeTypes.find(type => type.type === data.type);
if (nodeType) {
setCurrentNodeType(nodeType);
const formValues = {
@ -198,7 +198,7 @@ const FlowDesigner: React.FC = () => {
console.log('Node clicked, data:', data);
if (data) {
const nodeType = nodeTypes.find(type => type.code === data.type);
const nodeType = nodeTypes.find(type => type.type === data.type);
if (nodeType) {
setCurrentNodeType(nodeType);
const formValues = {
@ -273,13 +273,13 @@ const FlowDesigner: React.FC = () => {
);
// 获取节点配置
const position = calculateNodePosition(nodeType.code, dropPosition);
const nodeStyle = generateNodeStyle(nodeType.code);
const ports = generatePorts(nodeType.code);
const config = NODE_CONFIG[nodeType.code];
const position = calculateNodePosition(nodeType.type, dropPosition);
const nodeStyle = generateNodeStyle(nodeType.type);
const ports = generatePorts(nodeType.type);
const config = NODE_CONFIG[nodeType.type];
if (!config) {
throw new Error(`未找到节点类型 ${nodeType.code} 的配置`);
throw new Error(`未找到节点类型 ${nodeType.type} 的配置`);
}
// 创建节点
@ -288,8 +288,8 @@ const FlowDesigner: React.FC = () => {
...nodeStyle,
ports,
data: {
type: nodeType.code,
name: config.label, // 使用配置中的中文名称
type: nodeType.type,
name: nodeType.name,
config: {} as any,
},
});
@ -299,7 +299,7 @@ const FlowDesigner: React.FC = () => {
graphRef.current.select(node);
setCurrentNode(node);
setCurrentNodeType(nodeType);
form.setFieldsValue({ name: config.label }); // 使用配置中的中文名称
form.setFieldsValue({ name: nodeType.name });
setConfigVisible(true);
message.success('节点创建成功');

View File

@ -1,159 +0,0 @@
import React, {useEffect, useState} from 'react';
import {useNavigate, useParams} from 'react-router-dom';
import {Button, Card, Form, Input, message, Space, Spin} from 'antd';
import {getDefinition, updateDefinition} from '../../service';
import {UpdateWorkflowDefinitionRequest, WorkflowDefinition, WorkflowStatus} from '../../types';
import {ArrowLeftOutlined} from '@ant-design/icons';
import {WorkflowConfigUtils} from '../../../Workflow/utils';
const WorkflowDefinitionEdit: React.FC = () => {
const navigate = useNavigate();
const {id} = useParams<{ id: string }>();
const [form] = Form.useForm();
const [loading, setLoading] = useState(false);
const [detail, setDetail] = useState<WorkflowDefinition>();
// 获取详情
const fetchDetail = async () => {
if (!id) return;
setLoading(true);
try {
const response = await getDefinition(parseInt(id));
if (response) {
setDetail(response);
// 设置表单初始值
form.setFieldsValue({
code: response.code,
name: response.name,
description: response.description,
});
}
} finally {
setLoading(false);
}
};
// 首次加载
useEffect(() => {
fetchDetail();
}, [id]);
// 处理保存
const handleSave = async (values: any) => {
if (!id || !detail) return;
try {
// 保留原有配置和状态
const data: UpdateWorkflowDefinitionRequest = {
...values,
status: detail.status,
version: detail.version,
enabled: detail.enabled,
nodeConfig: JSON.stringify(WorkflowConfigUtils.parseNodeConfig(detail.nodeConfig)),
transitionConfig: JSON.stringify(WorkflowConfigUtils.parseTransitionConfig(detail.transitionConfig)),
formDefinition: JSON.stringify(WorkflowConfigUtils.parseFormDefinition(detail.formDefinition)),
graphDefinition: JSON.stringify(WorkflowConfigUtils.parseGraphDefinition(detail.graphDefinition))
};
await updateDefinition(parseInt(id), data);
message.success('保存成功');
navigate('/workflow/definition');
} catch (error) {
// 错误已在请求拦截器中处理
}
};
// 处理取消
const handleCancel = () => {
navigate('/workflow/definition');
};
if (loading) {
return (
<div style={{textAlign: 'center', padding: 100}}>
<Spin size="large"/>
</div>
);
}
return (
<Card
title="编辑流程定义"
extra={
<Button icon={<ArrowLeftOutlined/>} onClick={handleCancel}>
</Button>
}
>
<div style={{maxWidth: 800, margin: '0 auto'}}>
{detail?.status !== WorkflowStatus.DRAFT && (
<div style={{marginBottom: 24, padding: '12px 24px', backgroundColor: '#fff2f0', border: '1px solid #ffccc7', borderRadius: 4, color: '#ff4d4f'}}>
稿
</div>
)}
<Form
form={form}
labelCol={{span: 6}}
wrapperCol={{span: 18}}
onFinish={handleSave}
layout="horizontal"
size="large"
>
<Form.Item
name="code"
label="流程编码"
rules={[
{required: true, message: '请输入流程编码'},
{pattern: /^[A-Z_]+$/, message: '编码只能包含大写字母和下划线'},
]}
extra="编码只能包含大写字母和下划线例如DEPLOY_WORKFLOW"
>
<Input
placeholder="请输入流程编码"
disabled={detail?.status !== WorkflowStatus.DRAFT}
allowClear
/>
</Form.Item>
<Form.Item
name="name"
label="流程名称"
rules={[{required: true, message: '请输入流程名称'}]}
extra="给流程起一个简单易懂的名称"
>
<Input
placeholder="请输入流程名称"
disabled={detail?.status !== WorkflowStatus.DRAFT}
allowClear
/>
</Form.Item>
<Form.Item
name="description"
label="流程描述"
extra="详细描述流程的用途、步骤和注意事项"
>
<Input.TextArea
placeholder="请输入流程描述"
disabled={detail?.status !== WorkflowStatus.DRAFT}
allowClear
rows={4}
/>
</Form.Item>
<Form.Item wrapperCol={{offset: 6, span: 18}}>
<Space size="large">
<Button
type="primary"
htmlType="submit"
disabled={detail?.status !== WorkflowStatus.DRAFT}
>
</Button>
<Button onClick={handleCancel}></Button>
</Space>
</Form.Item>
</Form>
</div>
</Card>
);
};
export default WorkflowDefinitionEdit;

View File

@ -3,6 +3,7 @@ import {Button, Card, Form, Input, message, Modal, Select, Space, Table, Tag} fr
import {useNavigate} from 'react-router-dom';
import {
createDefinition,
updateDefinition,
deleteDefinition,
disableDefinition,
enableDefinition,
@ -27,6 +28,7 @@ const WorkflowDefinitionList: React.FC = () => {
const [current, setCurrent] = useState(1);
const [size, setSize] = useState(10);
const [createModalVisible, setCreateModalVisible] = useState(false);
const [editingRecord, setEditingRecord] = useState<WorkflowDefinition | null>(null);
// 获取列表数据
const fetchList = async (page = current, pageSize = size) => {
@ -72,33 +74,44 @@ const WorkflowDefinitionList: React.FC = () => {
fetchList(1);
};
// 处理创建
const handleCreate = async (values: WorkflowDefinitionBase) => {
// 处理创建或更新
const handleSubmit = async (values: WorkflowDefinitionBase) => {
try {
// 设置系统字段的默认值
if (editingRecord) {
// 更新流程
const updateData = {
...values,
status: editingRecord.status,
flowVersion: editingRecord.flowVersion
};
await updateDefinition(editingRecord.id, updateData);
message.success('更新成功');
} else {
// 创建流程
const data = {
...values,
status: WorkflowStatus.DRAFT,
version: 1,
enabled: true,
nodeConfig: JSON.stringify({
nodes: []
}),
transitionConfig: JSON.stringify({
transitions: []
}),
formDefinition: JSON.stringify({}),
graphDefinition: JSON.stringify({})
flowVersion: 1
};
await createDefinition(data);
message.success('创建成功');
}
setCreateModalVisible(false);
setEditingRecord(null);
form.resetFields();
fetchList();
} catch (error) {
// 错误已在请求拦截器中处理
}
};
// 处理弹窗关闭
const handleModalClose = () => {
setCreateModalVisible(false);
setEditingRecord(null);
form.resetFields();
};
// 处理删除
const handleDelete = (record: WorkflowDefinition) => {
confirm({
@ -143,6 +156,17 @@ const WorkflowDefinitionList: React.FC = () => {
}
};
// 处理编辑
const handleEdit = (record: WorkflowDefinition) => {
setEditingRecord(record);
form.setFieldsValue({
key: record.key,
name: record.name,
description: record.description
});
setCreateModalVisible(true);
};
// 表格列定义
const columns = [
{
@ -224,13 +248,14 @@ const WorkflowDefinitionList: React.FC = () => {
width: 380,
render: (_: any, record: WorkflowDefinition) => (
<Space>
{record.status === WorkflowStatus.DRAFT && (
<Button
type="link"
icon={<EditOutlined/>}
onClick={() => navigate(`/workflow/definition/edit/${record.id}`)}
onClick={() => handleEdit(record)}
>
</Button>
)}
<Button
type="link"
onClick={() => navigate(`/workflow/definition/designer/${record.id}`)}
@ -329,44 +354,51 @@ const WorkflowDefinitionList: React.FC = () => {
onChange={handleTableChange}
/>
{/* 创建表单弹窗 */}
{/* 创建/编辑表单弹窗 */}
<Modal
title="新建流程"
title={editingRecord ? "编辑流程" : "新建流程"}
open={createModalVisible}
onCancel={() => setCreateModalVisible(false)}
onCancel={handleModalClose}
footer={null}
>
<Form
labelCol={{span: 4}}
wrapperCol={{span: 20}}
onFinish={handleCreate}
form={form}
labelCol={{span: 6}}
wrapperCol={{span: 18}}
onFinish={handleSubmit}
>
<Form.Item
name="code"
label="编码"
name="key"
label="业务标识"
rules={[
{required: true, message: '请输入流程编码'},
{pattern: /^[A-Z_]+$/, message: '编码只能包含大写字母和下划线'},
{required: true, message: '请输入业务标识'},
{pattern: /^[A-Z_]+$/, message: '标识只能包含大写字母和下划线'},
]}
>
<Input placeholder="请输入流程编码"/>
<Input
placeholder="请输入业务标识"
disabled={!!editingRecord}
/>
</Form.Item>
<Form.Item
name="name"
label="名称"
label="流程名称"
rules={[{required: true, message: '请输入流程名称'}]}
>
<Input placeholder="请输入流<EFBFBD><EFBFBD><EFBFBD>名称"/>
<Input placeholder="请输入流名称"/>
</Form.Item>
<Form.Item name="description" label="描述">
<Form.Item
name="description"
label="流程描述"
>
<Input.TextArea placeholder="请输入流程描述"/>
</Form.Item>
<Form.Item wrapperCol={{offset: 4, span: 20}}>
<Form.Item wrapperCol={{offset: 6, span: 18}}>
<Space>
<Button type="primary" htmlType="submit">
</Button>
<Button onClick={() => setCreateModalVisible(false)}>
<Button onClick={handleModalClose}>
</Button>
</Space>

View File

@ -10,7 +10,7 @@ import {
} from './types';
const WORKFLOW_DEFINITION_URL = '/api/v1/workflow/definition';
const NODE_TYPE_URL = '/api/v1/node-types';
const NODE_DEFINITION_URL = '/api/v1/workflow/node-definition';
// 创建工作流定义
export const createDefinition = (data: CreateWorkflowDefinitionRequest) =>
@ -44,13 +44,13 @@ export const disableDefinition = (id: number) =>
export const enableDefinition = (id: number) =>
request.post<WorkflowDefinition>(`${WORKFLOW_DEFINITION_URL}/${id}/enable`);
// 建新版本
// <EFBFBD><EFBFBD><EFBFBD>建新版本
export const createVersion = (id: number) =>
request.post<WorkflowDefinition>(`${WORKFLOW_DEFINITION_URL}/${id}/versions`);
// 节点类型相关接口
// 获取节点类型列表
export const getNodeTypes = (params?: NodeTypeQuery) =>
request.get<NodeType[]>(NODE_TYPE_URL, { params });
request.get<Page<NodeType>>(`${NODE_DEFINITION_URL}/page`, { params });
export const getNodeTypeExecutors = (code: string) =>
request.get<NodeType>(`${NODE_TYPE_URL}/${code}/executors`);
request.get<NodeType>(`${NODE_DEFINITION_URL}/${code}/executors`);

View File

@ -32,18 +32,22 @@ export interface NodeExecutor {
// 节点类型
export interface NodeType {
id: number;
code: string;
type: string;
name: string;
category: NodeCategory;
description: string;
category: NodeCategory;
flowableConfig: string; // JSON string
graphConfig: string; // JSON string
formConfig: string; // JSON string
orderNum: number;
enabled: boolean;
icon: string;
color: string;
executors: NodeExecutor[];
configSchema: string; // JSON Schema
defaultConfig: string;
createTime: string;
updateTime: string;
createBy: string;
updateBy: string;
version: number;
deleted: boolean;
extraData: any;
}
// 工作流定义查询参数
@ -77,15 +81,16 @@ export interface TransitionConfig {
// 工作流定义基本信息
export interface WorkflowDefinitionBase {
code: string;
name: string;
key: string;
flowVersion?: number;
status?: WorkflowStatus;
description?: string;
}
// 工作流定义
export interface WorkflowDefinition extends WorkflowDefinitionBase {
id: number;
version: number;
status: WorkflowStatus;
enabled: boolean;
nodeConfig: string; // JSON string of NodeConfig
@ -94,17 +99,13 @@ export interface WorkflowDefinition extends WorkflowDefinitionBase {
graphDefinition: string; // JSON string
createTime: string;
updateTime: string;
createBy: string;
updateBy: string;
}
// 创建工作流定义请求
export interface CreateWorkflowDefinitionRequest extends WorkflowDefinitionBase {
status: WorkflowStatus;
version: number;
enabled: boolean;
nodeConfig: string; // JSON string of NodeConfig
transitionConfig: string; // JSON string of TransitionConfig
formDefinition: string; // JSON string
graphDefinition: string; // JSON string
}
// 更新工作流定义请求

View File

@ -33,7 +33,6 @@ const Department = lazy(() => import('../pages/System/Department'));
const External = lazy(() => import('../pages/System/External'));
const X6Test = lazy(() => import('../pages/X6Test'));
const WorkflowDefinition = lazy(() => import('../pages/Workflow/Definition'));
const WorkflowDefinitionEdit = lazy(() => import('../pages/Workflow/Definition/Edit'));
const WorkflowInstance = lazy(() => import('../pages/Workflow/Instance'));
const WorkflowMonitor = lazy(() => import('../pages/Workflow/Monitor'));
const FlowDesigner = lazy(() => import('../pages/Workflow/Definition/Designer'));
@ -132,14 +131,6 @@ const router = createBrowserRouter([
</Suspense>
)
},
{
path: 'edit/:id?',
element: (
<Suspense fallback={<LoadingComponent/>}>
<WorkflowDefinitionEdit/>
</Suspense>
)
},
{
path: 'designer/:id?',
element: (