248 lines
8.1 KiB
TypeScript
248 lines
8.1 KiB
TypeScript
import React, { useState, useEffect } from 'react';
|
|
import { Table, Card, Button, Space, Tag, message, Modal } from 'antd';
|
|
import { PlusOutlined, ExclamationCircleOutlined } from '@ant-design/icons';
|
|
import { useNavigate } from 'react-router-dom';
|
|
import * as service from './service';
|
|
import type { WorkflowDefinition, WorkflowDefinitionQuery, WorkflowCategory } from './types';
|
|
import { DEFAULT_PAGE_SIZE, DEFAULT_CURRENT } from '@/utils/page';
|
|
import EditModal from './components/EditModal';
|
|
|
|
const { confirm } = Modal;
|
|
|
|
const WorkflowDefinitionList: React.FC = () => {
|
|
const navigate = useNavigate();
|
|
const [loading, setLoading] = useState(false);
|
|
const [pageData, setPageData] = useState<{
|
|
content: WorkflowDefinition[];
|
|
totalElements: number;
|
|
size: number;
|
|
number: number;
|
|
} | null>(null);
|
|
const [modalVisible, setModalVisible] = useState(false);
|
|
const [currentRecord, setCurrentRecord] = useState<WorkflowDefinition>();
|
|
const [categories, setCategories] = useState<WorkflowCategory[]>([]);
|
|
const [query, setQuery] = useState<WorkflowDefinitionQuery>({
|
|
pageNum: DEFAULT_CURRENT - 1,
|
|
pageSize: DEFAULT_PAGE_SIZE
|
|
});
|
|
|
|
const loadData = async (params: WorkflowDefinitionQuery) => {
|
|
setLoading(true);
|
|
try {
|
|
const data = await service.getDefinitions(params);
|
|
setPageData(data);
|
|
} catch (error) {
|
|
if (error instanceof Error) {
|
|
message.error(error.message);
|
|
}
|
|
} finally {
|
|
setLoading(false);
|
|
}
|
|
};
|
|
|
|
const loadCategories = async () => {
|
|
try {
|
|
const data = await service.getWorkflowCategories();
|
|
setCategories(data);
|
|
} catch (error) {
|
|
console.error('加载工作流分类失败:', error);
|
|
message.error('加载工作流分类失败');
|
|
}
|
|
};
|
|
|
|
useEffect(() => {
|
|
loadData(query);
|
|
loadCategories();
|
|
}, [query]);
|
|
|
|
const handleCreateFlow = () => {
|
|
setCurrentRecord(undefined);
|
|
setModalVisible(true);
|
|
};
|
|
|
|
const handleEditFlow = (record: WorkflowDefinition) => {
|
|
setCurrentRecord(record);
|
|
setModalVisible(true);
|
|
};
|
|
|
|
const handleDesignFlow = (record: WorkflowDefinition) => {
|
|
// 新的React Flow设计器路径
|
|
navigate(`/workflow2/design/${record.id}`);
|
|
};
|
|
|
|
const handleModalClose = () => {
|
|
setModalVisible(false);
|
|
setCurrentRecord(undefined);
|
|
};
|
|
|
|
const handleDeploy = async (id: number) => {
|
|
confirm({
|
|
title: '确认发布',
|
|
icon: <ExclamationCircleOutlined />,
|
|
content: '确定要发布该流程定义吗?发布后将不能修改。',
|
|
onOk: async () => {
|
|
try {
|
|
await service.publishDefinition(id);
|
|
message.success('发布成功');
|
|
loadData(query);
|
|
} catch (error) {
|
|
if (error instanceof Error) {
|
|
message.error(error.message);
|
|
}
|
|
}
|
|
},
|
|
});
|
|
};
|
|
|
|
const handleDelete = async (id: number) => {
|
|
confirm({
|
|
title: '确认删除',
|
|
icon: <ExclamationCircleOutlined />,
|
|
content: '确定要删除该流程定义吗?删除后不可恢复。',
|
|
onOk: async () => {
|
|
try {
|
|
await service.deleteDefinition(id);
|
|
message.success('删除成功');
|
|
loadData(query);
|
|
} catch (error) {
|
|
if (error instanceof Error) {
|
|
message.error(error.message);
|
|
}
|
|
}
|
|
},
|
|
});
|
|
};
|
|
|
|
const handleStartFlow = async (record: WorkflowDefinition) => {
|
|
try {
|
|
await service.startWorkflowInstance(record.key, record.category);
|
|
message.success('流程启动成功');
|
|
} catch (error) {
|
|
if (error instanceof Error) {
|
|
message.error(error.message);
|
|
}
|
|
}
|
|
};
|
|
|
|
const columns = [
|
|
{
|
|
title: '流程名称',
|
|
dataIndex: 'name',
|
|
key: 'name',
|
|
},
|
|
{
|
|
title: '流程标识',
|
|
dataIndex: 'key',
|
|
key: 'key',
|
|
},
|
|
{
|
|
title: '流程分类',
|
|
dataIndex: 'category',
|
|
key: 'category',
|
|
render: (category: string) => {
|
|
const categoryInfo = categories.find(c => c.code === category);
|
|
return categoryInfo?.label || category;
|
|
}
|
|
},
|
|
{
|
|
title: '触发方式',
|
|
dataIndex: 'triggers',
|
|
key: 'triggers',
|
|
render: (triggers: string[], record: WorkflowDefinition) => {
|
|
const categoryInfo = categories.find(c => c.code === record.category);
|
|
return (triggers || [])?.map(triggerCode => {
|
|
const triggerInfo = categoryInfo?.supportedTriggers?.find(t => t.code === triggerCode);
|
|
return (
|
|
<Tag key={triggerCode}>
|
|
{triggerInfo?.label || triggerCode}
|
|
</Tag>
|
|
);
|
|
});
|
|
}
|
|
},
|
|
{
|
|
title: '版本',
|
|
dataIndex: 'flowVersion',
|
|
key: 'flowVersion',
|
|
},
|
|
{
|
|
title: '状态',
|
|
dataIndex: 'status',
|
|
key: 'status',
|
|
render: (status: string) => (
|
|
<Tag color={status === 'DRAFT' ? 'orange' : 'green'}>
|
|
{status === 'DRAFT' ? '草稿' : '已发布'}
|
|
</Tag>
|
|
),
|
|
},
|
|
{
|
|
title: '描述',
|
|
dataIndex: 'description',
|
|
key: 'description',
|
|
ellipsis: true,
|
|
},
|
|
{
|
|
title: '操作',
|
|
key: 'action',
|
|
fixed: 'right' as const,
|
|
width: 220,
|
|
render: (_: any, record: WorkflowDefinition) => (
|
|
<Space size="middle">
|
|
{record.status === 'DRAFT' && (
|
|
<>
|
|
<a onClick={() => handleEditFlow(record)}>编辑</a>
|
|
<a onClick={() => handleDesignFlow(record)}>设计(React Flow)</a>
|
|
</>
|
|
)}
|
|
{record.status === 'DRAFT' && (
|
|
<a onClick={() => handleDeploy(record.id)}>发布</a>
|
|
)}
|
|
<a onClick={() => handleDelete(record.id)}>删除</a>
|
|
{record.status !== 'DRAFT' && (
|
|
<a onClick={() => handleStartFlow(record)}>启动</a>
|
|
)}
|
|
</Space>
|
|
),
|
|
},
|
|
];
|
|
|
|
return (
|
|
<Card
|
|
title={
|
|
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
|
|
<span>工作流定义管理 (React Flow版本)</span>
|
|
<Button type="primary" icon={<PlusOutlined />} onClick={handleCreateFlow}>
|
|
新建流程
|
|
</Button>
|
|
</div>
|
|
}
|
|
>
|
|
<Table
|
|
columns={columns}
|
|
dataSource={pageData?.content}
|
|
loading={loading}
|
|
rowKey="id"
|
|
scroll={{ x: 1400 }}
|
|
pagination={{
|
|
current: (query.pageNum || 0) + 1,
|
|
pageSize: query.pageSize,
|
|
total: pageData?.totalElements || 0,
|
|
onChange: (page, pageSize) => setQuery({
|
|
...query,
|
|
pageNum: page - 1,
|
|
pageSize
|
|
}),
|
|
}}
|
|
/>
|
|
<EditModal
|
|
visible={modalVisible}
|
|
onClose={handleModalClose}
|
|
onSuccess={() => loadData(query)}
|
|
record={currentRecord}
|
|
/>
|
|
</Card>
|
|
);
|
|
};
|
|
|
|
export default WorkflowDefinitionList;
|