This commit is contained in:
dengqichen 2024-12-17 18:25:40 +08:00
parent a2b26591a5
commit b82cf8ab00
4 changed files with 194 additions and 6 deletions

View File

@ -0,0 +1,142 @@
import React, { useState, useEffect } from 'react';
import { Modal, Table, Tag, Button, Space } from 'antd';
import type { ColumnsType } from 'antd/es/table';
import { WorkflowHistoricalInstance } from '../types';
import { getHistoricalInstances } from '../service';
import DetailModal from './DetailModal';
import { DEFAULT_PAGE_SIZE, DEFAULT_CURRENT } from '@/utils/page';
interface HistoryModalProps {
visible: boolean;
onCancel: () => void;
workflowDefinitionId?: number;
}
const HistoryModal: React.FC<HistoryModalProps> = ({ visible, onCancel, workflowDefinitionId }) => {
const [loading, setLoading] = useState(false);
const [data, setData] = useState<WorkflowHistoricalInstance[]>([]);
const [total, setTotal] = useState(0);
const [query, setQuery] = useState({
pageNum: DEFAULT_CURRENT,
pageSize: DEFAULT_PAGE_SIZE,
workflowDefinitionId
});
const [detailVisible, setDetailVisible] = useState(false);
const [selectedInstance, setSelectedInstance] = useState<WorkflowHistoricalInstance>();
const loadData = async () => {
setLoading(true);
try {
const result = await getHistoricalInstances(query);
setData(result.content || []);
setTotal(result.totalElements || 0);
} catch (error) {
console.error('加载历史记录失败:', error);
} finally {
setLoading(false);
}
};
useEffect(() => {
if (visible) {
loadData();
}
}, [visible, query]);
const handleViewDetail = (record: WorkflowHistoricalInstance) => {
setSelectedInstance(record);
setDetailVisible(true);
};
const getStatusTag = (status: string) => {
const statusMap: Record<string, { color: string; text: string }> = {
COMPLETED: { color: 'success', text: '已完成' },
RUNNING: { color: 'processing', text: '运行中' },
FAILED: { color: 'error', text: '失败' },
TERMINATED: { color: 'warning', text: '已终止' }
};
const statusInfo = statusMap[status] || { color: 'default', text: status };
return <Tag color={statusInfo.color}>{statusInfo.text}</Tag>;
};
const columns: ColumnsType<WorkflowHistoricalInstance> = [
{
title: '业务标识',
dataIndex: 'businessKey',
key: 'businessKey',
width: 200,
},
{
title: '状态',
dataIndex: 'status',
key: 'status',
width: 100,
render: status => getStatusTag(status)
},
{
title: '开始时间',
dataIndex: 'startTime',
key: 'startTime',
width: 180,
},
{
title: '结束时间',
dataIndex: 'endTime',
key: 'endTime',
width: 180,
render: time => time || '暂无'
},
{
title: '操作',
key: 'action',
fixed: 'right',
width: 100,
render: (_, record) => (
<Button type="link" onClick={() => handleViewDetail(record)}>
</Button>
),
},
];
return (
<>
<Modal
title="历史执行记录"
open={visible}
onCancel={onCancel}
width={1000}
footer={null}
>
<Table
columns={columns}
dataSource={data}
loading={loading}
rowKey="id"
scroll={{ x: 800 }}
pagination={{
current: query.pageNum + 1,
pageSize: query.pageSize,
total: total,
onChange: (page, pageSize) => setQuery({
...query,
pageNum: page - 1,
pageSize
}),
showSizeChanger: true,
showQuickJumper: true,
}}
/>
</Modal>
{selectedInstance && (
<DetailModal
visible={detailVisible}
onCancel={() => setDetailVisible(false)}
instanceData={selectedInstance}
/>
)}
</>
);
};
export default HistoryModal;

View File

@ -5,22 +5,25 @@ import { getWorkflowInstances } from './service';
import { WorkflowTemplateWithInstances } from './types';
import { Page } from '@/types/base';
import DetailModal from './components/DetailModal';
import HistoryModal from './components/HistoryModal';
const WorkflowInstanceList: React.FC = () => {
const [loading, setLoading] = useState(false);
const [data, setData] = useState<WorkflowTemplateWithInstances[]>([]);
const [data, setData] = useState<Page<WorkflowTemplateWithInstances[]>>([]);
const [query, setQuery] = useState({
current: 1,
pageSize: 10,
});
const [detailVisible, setDetailVisible] = useState(false);
const [selectedInstance, setSelectedInstance] = useState<WorkflowTemplateWithInstances>();
const [historyVisible, setHistoryVisible] = useState(false);
const [selectedWorkflowDefinitionId, setSelectedWorkflowDefinitionId] = useState<number>();
const loadData = async (params: any) => {
setLoading(true);
try {
const result = await getWorkflowInstances(params);
setData(result?.content || []);
setData(result);
} catch (error) {
console.error('加载流程实例失败:', error);
} finally {
@ -37,6 +40,11 @@ const WorkflowInstanceList: React.FC = () => {
setDetailVisible(true);
};
const handleViewHistory = (record: WorkflowTemplateWithInstances) => {
setSelectedWorkflowDefinitionId(record.id);
setHistoryVisible(true);
};
const columns: ColumnsType<WorkflowTemplateWithInstances> = [
{
title: '流程名称',
@ -73,14 +81,14 @@ const WorkflowInstanceList: React.FC = () => {
title: '操作',
key: 'action',
fixed: 'right',
width: 230,
width: 200,
render: (_, record) => (
<Space size="middle">
<a onClick={() => handleViewDetail(record)}></a>
<a onClick={() => handleViewHistory(record)}></a>
{record?.lastExecutionStatus === 'RUNNING' && (
<a onClick={() => console.log('终止流程', record)}></a>
)}
<a onClick={() => handleViewDetail(record)}></a>
</Space>
),
},
@ -98,7 +106,7 @@ const WorkflowInstanceList: React.FC = () => {
<Card title="流程实例">
<Table
columns={columns}
dataSource={data}
dataSource={data.content}
loading={loading}
rowKey="id"
scroll={{ x: 1200 }}
@ -119,6 +127,11 @@ const WorkflowInstanceList: React.FC = () => {
onCancel={() => setDetailVisible(false)}
instanceData={selectedInstance}
/>
<HistoryModal
visible={historyVisible}
onCancel={() => setHistoryVisible(false)}
workflowDefinitionId={selectedWorkflowDefinitionId}
/>
</Card>
);
};

View File

@ -1,6 +1,7 @@
import request from '@/utils/request';
import { WorkflowTemplateWithInstances, WorkflowTemplateWithInstancesQuery } from './types';
import { Page } from '@/types/base';
import { WorkflowHistoricalInstance, WorkflowHistoricalInstanceQuery } from './types';
const INSTANCE_URL = '/api/v1/workflow/instance';
@ -10,3 +11,10 @@ const INSTANCE_URL = '/api/v1/workflow/instance';
*/
export const getWorkflowInstances = (params?: WorkflowTemplateWithInstancesQuery) =>
request.get<Page<WorkflowTemplateWithInstances>>(`${INSTANCE_URL}/templates-with-instances`, { params });
/**
*
* @param params
*/
export const getHistoricalInstances = (params?: WorkflowHistoricalInstanceQuery) =>
request.post<Page<WorkflowHistoricalInstance>>(`${INSTANCE_URL}/historical-instances`, params);

View File

@ -1,4 +1,4 @@
import { Page } from '@/types/base';
import { Page, BaseQuery } from '@/types/base';
export interface WorkflowTemplateWithInstances {
id: number;
@ -11,3 +11,28 @@ export interface WorkflowTemplateWithInstances {
export interface WorkflowTemplateWithInstancesQuery {
}
export interface WorkflowInstanceStage {
id: number | null;
nodeId: string;
nodeName: string;
nodeType: string;
status: string;
startTime: string | null;
endTime: string | null;
}
export interface WorkflowHistoricalInstance {
id: number;
processInstanceId: string;
processDefinitionId: string;
businessKey: string;
status: string;
startTime: string;
endTime: string | null;
stages: WorkflowInstanceStage[];
}
export interface WorkflowHistoricalInstanceQuery extends BaseQuery {
workflowDefinitionId?: number;
}