1
This commit is contained in:
parent
a2b26591a5
commit
b82cf8ab00
142
frontend/src/pages/Workflow/Instance/components/HistoryModal.tsx
Normal file
142
frontend/src/pages/Workflow/Instance/components/HistoryModal.tsx
Normal 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;
|
||||||
@ -5,22 +5,25 @@ import { getWorkflowInstances } from './service';
|
|||||||
import { WorkflowTemplateWithInstances } from './types';
|
import { WorkflowTemplateWithInstances } from './types';
|
||||||
import { Page } from '@/types/base';
|
import { Page } from '@/types/base';
|
||||||
import DetailModal from './components/DetailModal';
|
import DetailModal from './components/DetailModal';
|
||||||
|
import HistoryModal from './components/HistoryModal';
|
||||||
|
|
||||||
const WorkflowInstanceList: React.FC = () => {
|
const WorkflowInstanceList: React.FC = () => {
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const [data, setData] = useState<WorkflowTemplateWithInstances[]>([]);
|
const [data, setData] = useState<Page<WorkflowTemplateWithInstances[]>>([]);
|
||||||
const [query, setQuery] = useState({
|
const [query, setQuery] = useState({
|
||||||
current: 1,
|
current: 1,
|
||||||
pageSize: 10,
|
pageSize: 10,
|
||||||
});
|
});
|
||||||
const [detailVisible, setDetailVisible] = useState(false);
|
const [detailVisible, setDetailVisible] = useState(false);
|
||||||
const [selectedInstance, setSelectedInstance] = useState<WorkflowTemplateWithInstances>();
|
const [selectedInstance, setSelectedInstance] = useState<WorkflowTemplateWithInstances>();
|
||||||
|
const [historyVisible, setHistoryVisible] = useState(false);
|
||||||
|
const [selectedWorkflowDefinitionId, setSelectedWorkflowDefinitionId] = useState<number>();
|
||||||
|
|
||||||
const loadData = async (params: any) => {
|
const loadData = async (params: any) => {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
try {
|
try {
|
||||||
const result = await getWorkflowInstances(params);
|
const result = await getWorkflowInstances(params);
|
||||||
setData(result?.content || []);
|
setData(result);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('加载流程实例失败:', error);
|
console.error('加载流程实例失败:', error);
|
||||||
} finally {
|
} finally {
|
||||||
@ -37,6 +40,11 @@ const WorkflowInstanceList: React.FC = () => {
|
|||||||
setDetailVisible(true);
|
setDetailVisible(true);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleViewHistory = (record: WorkflowTemplateWithInstances) => {
|
||||||
|
setSelectedWorkflowDefinitionId(record.id);
|
||||||
|
setHistoryVisible(true);
|
||||||
|
};
|
||||||
|
|
||||||
const columns: ColumnsType<WorkflowTemplateWithInstances> = [
|
const columns: ColumnsType<WorkflowTemplateWithInstances> = [
|
||||||
{
|
{
|
||||||
title: '流程名称',
|
title: '流程名称',
|
||||||
@ -73,14 +81,14 @@ const WorkflowInstanceList: React.FC = () => {
|
|||||||
title: '操作',
|
title: '操作',
|
||||||
key: 'action',
|
key: 'action',
|
||||||
fixed: 'right',
|
fixed: 'right',
|
||||||
width: 230,
|
width: 200,
|
||||||
render: (_, record) => (
|
render: (_, record) => (
|
||||||
<Space size="middle">
|
<Space size="middle">
|
||||||
<a onClick={() => handleViewDetail(record)}>查看详情</a>
|
<a onClick={() => handleViewDetail(record)}>查看详情</a>
|
||||||
|
<a onClick={() => handleViewHistory(record)}>历史执行</a>
|
||||||
{record?.lastExecutionStatus === 'RUNNING' && (
|
{record?.lastExecutionStatus === 'RUNNING' && (
|
||||||
<a onClick={() => console.log('终止流程', record)}>终止流程</a>
|
<a onClick={() => console.log('终止流程', record)}>终止流程</a>
|
||||||
)}
|
)}
|
||||||
<a onClick={() => handleViewDetail(record)}>历史执行</a>
|
|
||||||
</Space>
|
</Space>
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
@ -98,7 +106,7 @@ const WorkflowInstanceList: React.FC = () => {
|
|||||||
<Card title="流程实例">
|
<Card title="流程实例">
|
||||||
<Table
|
<Table
|
||||||
columns={columns}
|
columns={columns}
|
||||||
dataSource={data}
|
dataSource={data.content}
|
||||||
loading={loading}
|
loading={loading}
|
||||||
rowKey="id"
|
rowKey="id"
|
||||||
scroll={{ x: 1200 }}
|
scroll={{ x: 1200 }}
|
||||||
@ -119,6 +127,11 @@ const WorkflowInstanceList: React.FC = () => {
|
|||||||
onCancel={() => setDetailVisible(false)}
|
onCancel={() => setDetailVisible(false)}
|
||||||
instanceData={selectedInstance}
|
instanceData={selectedInstance}
|
||||||
/>
|
/>
|
||||||
|
<HistoryModal
|
||||||
|
visible={historyVisible}
|
||||||
|
onCancel={() => setHistoryVisible(false)}
|
||||||
|
workflowDefinitionId={selectedWorkflowDefinitionId}
|
||||||
|
/>
|
||||||
</Card>
|
</Card>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
import request from '@/utils/request';
|
import request from '@/utils/request';
|
||||||
import { WorkflowTemplateWithInstances, WorkflowTemplateWithInstancesQuery } from './types';
|
import { WorkflowTemplateWithInstances, WorkflowTemplateWithInstancesQuery } from './types';
|
||||||
import { Page } from '@/types/base';
|
import { Page } from '@/types/base';
|
||||||
|
import { WorkflowHistoricalInstance, WorkflowHistoricalInstanceQuery } from './types';
|
||||||
|
|
||||||
const INSTANCE_URL = '/api/v1/workflow/instance';
|
const INSTANCE_URL = '/api/v1/workflow/instance';
|
||||||
|
|
||||||
@ -10,3 +11,10 @@ const INSTANCE_URL = '/api/v1/workflow/instance';
|
|||||||
*/
|
*/
|
||||||
export const getWorkflowInstances = (params?: WorkflowTemplateWithInstancesQuery) =>
|
export const getWorkflowInstances = (params?: WorkflowTemplateWithInstancesQuery) =>
|
||||||
request.get<Page<WorkflowTemplateWithInstances>>(`${INSTANCE_URL}/templates-with-instances`, { params });
|
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);
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { Page } from '@/types/base';
|
import { Page, BaseQuery } from '@/types/base';
|
||||||
|
|
||||||
export interface WorkflowTemplateWithInstances {
|
export interface WorkflowTemplateWithInstances {
|
||||||
id: number;
|
id: number;
|
||||||
@ -11,3 +11,28 @@ export interface WorkflowTemplateWithInstances {
|
|||||||
export interface WorkflowTemplateWithInstancesQuery {
|
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;
|
||||||
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user