deploy-ease-platform/frontend/src/pages/Workflow2/Definition/index.tsx
dengqichen a542ee9d2f 1
2025-10-20 19:34:44 +08:00

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;