feat: systematic functional audit — fix 18 issues across Phase A/B
Phase A (P1 production blockers): - A1: Apply IP rate limiting to public routes (login/refresh) - A2: Publish domain events for workflow instance state transitions (completed/suspended/resumed/terminated) via outbox pattern - A3: Replace hardcoded nil UUID default tenant with dynamic DB lookup - A4: Add GET /api/v1/audit-logs query endpoint with pagination - A5: Enhance CORS wildcard warning for production environments Phase B (P2 functional gaps): - B1: Remove dead erp-common crate (zero references in codebase) - B2: Refactor 5 settings pages to use typed API modules instead of direct client calls; create api/themes.ts; delete dead errors.ts - B3: Add resume/suspend buttons to InstanceMonitor page - B4: Remove unused EventHandler trait from erp-core - B5: Handle task.completed events in message module (send notifications) - B6: Wire TimeoutChecker as 60s background task - B7: Auto-skip ServiceTask nodes instead of crashing the process - B8: Remove empty register_routes() from ErpModule trait and modules
This commit is contained in:
@@ -3,6 +3,8 @@ import { Button, message, Modal, Table, Tag } from 'antd';
|
||||
import type { ColumnsType } from 'antd/es/table';
|
||||
import {
|
||||
listInstances,
|
||||
resumeInstance,
|
||||
suspendInstance,
|
||||
terminateInstance,
|
||||
type ProcessInstanceInfo,
|
||||
} from '../../api/workflowInstances';
|
||||
@@ -77,6 +79,35 @@ export default function InstanceMonitor() {
|
||||
});
|
||||
};
|
||||
|
||||
const handleSuspend = async (id: string) => {
|
||||
Modal.confirm({
|
||||
title: '确认挂起',
|
||||
content: '确定要挂起该流程实例吗?挂起后可通过"恢复"按钮继续执行。',
|
||||
okText: '确定挂起',
|
||||
okType: 'warning',
|
||||
cancelText: '取消',
|
||||
onOk: async () => {
|
||||
try {
|
||||
await suspendInstance(id);
|
||||
message.success('已挂起');
|
||||
fetchData();
|
||||
} catch {
|
||||
message.error('操作失败');
|
||||
}
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const handleResume = async (id: string) => {
|
||||
try {
|
||||
await resumeInstance(id);
|
||||
message.success('已恢复');
|
||||
fetchData();
|
||||
} catch {
|
||||
message.error('操作失败');
|
||||
}
|
||||
};
|
||||
|
||||
const columns: ColumnsType<ProcessInstanceInfo> = [
|
||||
{ title: '流程', dataIndex: 'definition_name', key: 'definition_name' },
|
||||
{ title: '业务键', dataIndex: 'business_key', key: 'business_key' },
|
||||
@@ -91,14 +122,26 @@ export default function InstanceMonitor() {
|
||||
render: (v: string) => new Date(v).toLocaleString(),
|
||||
},
|
||||
{
|
||||
title: '操作', key: 'action', width: 150,
|
||||
title: '操作', key: 'action', width: 220,
|
||||
render: (_, record) => (
|
||||
<>
|
||||
<Button size="small" onClick={() => handleViewFlow(record)} style={{ marginRight: 8 }}>
|
||||
流程图
|
||||
</Button>
|
||||
{record.status === 'running' && (
|
||||
<Button size="small" danger onClick={() => handleTerminate(record.id)}>终止</Button>
|
||||
<>
|
||||
<Button size="small" onClick={() => handleSuspend(record.id)} style={{ marginRight: 8 }}>
|
||||
挂起
|
||||
</Button>
|
||||
<Button size="small" danger onClick={() => handleTerminate(record.id)}>
|
||||
终止
|
||||
</Button>
|
||||
</>
|
||||
)}
|
||||
{record.status === 'suspended' && (
|
||||
<Button size="small" type="primary" onClick={() => handleResume(record.id)}>
|
||||
恢复
|
||||
</Button>
|
||||
)}
|
||||
</>
|
||||
),
|
||||
|
||||
Reference in New Issue
Block a user