feat: 添加汇率服务和缓存服务,优化数据源和日志服务
refactor: 重构数据源工厂和类型定义,提升代码可维护性 fix: 修复类型转换和状态机文档中的错误 docs: 更新服务架构文档,添加新的服务闭环流程 test: 添加汇率服务单元测试 chore: 清理无用代码和注释,优化代码结构
This commit is contained in:
260
dashboard/src/pages/AutoExecution/components/EvolutionStage.tsx
Normal file
260
dashboard/src/pages/AutoExecution/components/EvolutionStage.tsx
Normal file
@@ -0,0 +1,260 @@
|
||||
/**
|
||||
* [FE-AIAUTO-003] 演进阶段展示组件
|
||||
* 展示自动化等级的演进阶段和能力说明
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import {
|
||||
Card,
|
||||
Row,
|
||||
Col,
|
||||
Steps,
|
||||
Tag,
|
||||
Typography,
|
||||
Space,
|
||||
Badge,
|
||||
Tooltip,
|
||||
Descriptions,
|
||||
Progress,
|
||||
} from 'antd';
|
||||
import {
|
||||
RobotOutlined,
|
||||
UserOutlined,
|
||||
ThunderboltOutlined,
|
||||
SafetyOutlined,
|
||||
CheckCircleOutlined,
|
||||
LockOutlined,
|
||||
} from '@ant-design/icons';
|
||||
import { AutomationLevel, LEVEL_CAPABILITIES, RiskLevel } from '@/services/autoExecutionDataSource';
|
||||
|
||||
const { Title, Text, Paragraph } = Typography;
|
||||
|
||||
const RISK_LEVEL_COLORS: Record<RiskLevel, string> = {
|
||||
LOW: 'green',
|
||||
MEDIUM: 'orange',
|
||||
HIGH: 'red',
|
||||
CRITICAL: 'purple',
|
||||
};
|
||||
|
||||
const LEVEL_ICONS: Record<AutomationLevel, React.ReactNode> = {
|
||||
L1: <UserOutlined />,
|
||||
L2: <RobotOutlined />,
|
||||
L3: <ThunderboltOutlined />,
|
||||
L4: <SafetyOutlined />,
|
||||
};
|
||||
|
||||
const LEVEL_DESCRIPTIONS: Record<AutomationLevel, {
|
||||
title: string;
|
||||
subtitle: string;
|
||||
features: string[];
|
||||
requirements: string[];
|
||||
}> = {
|
||||
L1: {
|
||||
title: '建议模式',
|
||||
subtitle: '所有操作需人工确认',
|
||||
features: [
|
||||
'AI仅提供建议',
|
||||
'所有决策需人工审核',
|
||||
'适合新模块或高风险场景',
|
||||
'完整的操作日志记录',
|
||||
],
|
||||
requirements: [
|
||||
'无需前置条件',
|
||||
'默认初始等级',
|
||||
],
|
||||
},
|
||||
L2: {
|
||||
title: '辅助模式',
|
||||
subtitle: '低风险操作可自动执行',
|
||||
features: [
|
||||
'低风险操作自动执行',
|
||||
'中高风险需人工审核',
|
||||
'支持金额限制',
|
||||
'自动回滚机制',
|
||||
],
|
||||
requirements: [
|
||||
'执行次数 ≥ 100次',
|
||||
'成功率 ≥ 95%',
|
||||
'平均置信度 ≥ 80%',
|
||||
],
|
||||
},
|
||||
L3: {
|
||||
title: '自动模式',
|
||||
subtitle: '大部分操作可自动执行',
|
||||
features: [
|
||||
'大部分操作自动执行',
|
||||
'仅高风险需审核',
|
||||
'支持更高金额限制',
|
||||
'智能异常检测',
|
||||
],
|
||||
requirements: [
|
||||
'L2等级运行 ≥ 7天',
|
||||
'执行次数 ≥ 500次',
|
||||
'成功率 ≥ 97%',
|
||||
],
|
||||
},
|
||||
L4: {
|
||||
title: '全自主模式',
|
||||
subtitle: '完全自动化运行',
|
||||
features: [
|
||||
'全自动化执行',
|
||||
'包含关键操作',
|
||||
'实时监控告警',
|
||||
'智能风险控制',
|
||||
],
|
||||
requirements: [
|
||||
'L3等级运行 ≥ 30天',
|
||||
'执行次数 ≥ 2000次',
|
||||
'成功率 ≥ 99%',
|
||||
'管理员审批',
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
interface EvolutionStageProps {
|
||||
currentLevel?: AutomationLevel;
|
||||
onLevelClick?: (level: AutomationLevel) => void;
|
||||
}
|
||||
|
||||
const EvolutionStage: React.FC<EvolutionStageProps> = ({
|
||||
currentLevel = 'L1',
|
||||
onLevelClick,
|
||||
}) => {
|
||||
const levels: AutomationLevel[] = ['L1', 'L2', 'L3', 'L4'];
|
||||
const currentIndex = levels.indexOf(currentLevel);
|
||||
|
||||
return (
|
||||
<Card title="自动化等级演进路线" className="evolution-stage-card">
|
||||
<Steps
|
||||
current={currentIndex}
|
||||
size="small"
|
||||
items={levels.map((level, index) => {
|
||||
const capability = LEVEL_CAPABILITIES[level];
|
||||
const desc = LEVEL_DESCRIPTIONS[level];
|
||||
const isActive = index <= currentIndex;
|
||||
const isLocked = index > currentIndex + 1;
|
||||
|
||||
return {
|
||||
title: (
|
||||
<Space>
|
||||
<Tag color={isActive ? 'processing' : 'default'}>{level}</Tag>
|
||||
{isLocked && <LockOutlined style={{ color: '#999' }} />}
|
||||
</Space>
|
||||
),
|
||||
description: desc.title,
|
||||
icon: LEVEL_ICONS[level],
|
||||
status: isActive ? 'finish' : 'wait',
|
||||
};
|
||||
})}
|
||||
/>
|
||||
|
||||
<Row gutter={[16, 16]} style={{ marginTop: 24 }}>
|
||||
{levels.map((level, index) => {
|
||||
const capability = LEVEL_CAPABILITIES[level];
|
||||
const desc = LEVEL_DESCRIPTIONS[level];
|
||||
const isActive = index <= currentIndex;
|
||||
const isCurrent = index === currentIndex;
|
||||
|
||||
return (
|
||||
<Col span={6} key={level}>
|
||||
<Card
|
||||
size="small"
|
||||
hoverable={isActive}
|
||||
onClick={() => isActive && onLevelClick?.(level)}
|
||||
style={{
|
||||
opacity: isActive ? 1 : 0.6,
|
||||
border: isCurrent ? '2px solid #1890ff' : undefined,
|
||||
}}
|
||||
>
|
||||
<Space direction="vertical" style={{ width: '100%' }}>
|
||||
<Space>
|
||||
{LEVEL_ICONS[level]}
|
||||
<Text strong>{level}</Text>
|
||||
<Tag color={isCurrent ? 'blue' : 'default'}>{desc.title}</Tag>
|
||||
</Space>
|
||||
|
||||
<Text type="secondary" style={{ fontSize: 12 }}>
|
||||
{desc.subtitle}
|
||||
</Text>
|
||||
|
||||
<Descriptions column={1} size="small">
|
||||
<Descriptions.Item label="最大风险等级">
|
||||
<Tag color={RISK_LEVEL_COLORS[capability.max_risk_level]}>
|
||||
{capability.max_risk_level}
|
||||
</Tag>
|
||||
</Descriptions.Item>
|
||||
<Descriptions.Item label="金额倍数">
|
||||
{capability.max_amount_multiplier}x
|
||||
</Descriptions.Item>
|
||||
<Descriptions.Item label="需审批">
|
||||
{capability.requires_approval ? (
|
||||
<CheckCircleOutlined style={{ color: '#52c41a' }} />
|
||||
) : (
|
||||
<Text type="secondary">否</Text>
|
||||
)}
|
||||
</Descriptions.Item>
|
||||
</Descriptions>
|
||||
|
||||
{index > 0 && (
|
||||
<>
|
||||
<Text type="secondary" style={{ fontSize: 11 }}>升级条件:</Text>
|
||||
<ul style={{ margin: 0, paddingLeft: 16, fontSize: 11 }}>
|
||||
{desc.requirements.map((req, i) => (
|
||||
<li key={i}>{req}</li>
|
||||
))}
|
||||
</ul>
|
||||
</>
|
||||
)}
|
||||
</Space>
|
||||
</Card>
|
||||
</Col>
|
||||
);
|
||||
})}
|
||||
</Row>
|
||||
|
||||
<Card size="small" style={{ marginTop: 16, background: '#fafafa' }}>
|
||||
<Title level={5}>等级能力对比</Title>
|
||||
<Row gutter={16}>
|
||||
<Col span={6}>
|
||||
<Text strong>风险承受能力</Text>
|
||||
<Progress
|
||||
percent={(currentIndex + 1) * 25}
|
||||
format={() => `${['LOW', 'MEDIUM', 'HIGH', 'CRITICAL'][currentIndex]}`}
|
||||
strokeColor={{
|
||||
'0%': '#52c41a',
|
||||
'50%': '#faad14',
|
||||
'100%': '#f5222d',
|
||||
}}
|
||||
/>
|
||||
</Col>
|
||||
<Col span={6}>
|
||||
<Text strong>自动化程度</Text>
|
||||
<Progress
|
||||
percent={(currentIndex + 1) * 25}
|
||||
format={() => `${(currentIndex + 1) * 25}%`}
|
||||
strokeColor="#1890ff"
|
||||
/>
|
||||
</Col>
|
||||
<Col span={6}>
|
||||
<Text strong>金额限制倍数</Text>
|
||||
<Progress
|
||||
percent={Math.min(LEVEL_CAPABILITIES[currentLevel].max_amount_multiplier * 20, 100)}
|
||||
format={() => `${LEVEL_CAPABILITIES[currentLevel].max_amount_multiplier}x`}
|
||||
strokeColor="#722ed1"
|
||||
/>
|
||||
</Col>
|
||||
<Col span={6}>
|
||||
<Text strong>人工干预需求</Text>
|
||||
<Progress
|
||||
percent={100 - (currentIndex * 30)}
|
||||
format={() => currentIndex === 0 ? '100%' : currentIndex === 1 ? '70%' : currentIndex === 2 ? '40%' : '10%'}
|
||||
strokeColor="#13c2c2"
|
||||
/>
|
||||
</Col>
|
||||
</Row>
|
||||
</Card>
|
||||
</Card>
|
||||
);
|
||||
};
|
||||
|
||||
export default EvolutionStage;
|
||||
@@ -0,0 +1,337 @@
|
||||
/**
|
||||
* [FE-AIAUTO-002] 阈值配置表单组件
|
||||
* 用于配置自动执行的置信度阈值和风险限制
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import {
|
||||
Form,
|
||||
InputNumber,
|
||||
Select,
|
||||
Switch,
|
||||
Divider,
|
||||
Row,
|
||||
Col,
|
||||
Card,
|
||||
Slider,
|
||||
Space,
|
||||
Tag,
|
||||
Alert,
|
||||
} from 'antd';
|
||||
import {
|
||||
ThunderboltOutlined,
|
||||
SafetyOutlined,
|
||||
ClockCircleOutlined,
|
||||
BellOutlined,
|
||||
} from '@ant-design/icons';
|
||||
import { AutoExecutionConfig, RiskLevel, LEVEL_CAPABILITIES } from '@/services/autoExecutionDataSource';
|
||||
|
||||
const { Option } = Select;
|
||||
|
||||
interface ThresholdConfigFormProps {
|
||||
config: AutoExecutionConfig;
|
||||
onSubmit: (values: Partial<AutoExecutionConfig>) => void;
|
||||
onCancel: () => void;
|
||||
}
|
||||
|
||||
const ThresholdConfigForm: React.FC<ThresholdConfigFormProps> = ({
|
||||
config,
|
||||
onSubmit,
|
||||
onCancel,
|
||||
}) => {
|
||||
const [form] = Form.useForm();
|
||||
|
||||
const handleSubmit = (values: any) => {
|
||||
const thresholds = {
|
||||
auto_execute: values.auto_execute / 100,
|
||||
pending_review: values.pending_review / 100,
|
||||
auto_reject: values.auto_reject / 100,
|
||||
};
|
||||
|
||||
const riskLimits = {
|
||||
max_amount: values.max_amount,
|
||||
max_quantity: values.max_quantity,
|
||||
allowed_risk_levels: values.allowed_risk_levels,
|
||||
};
|
||||
|
||||
const timeRestrictions = {
|
||||
allowed_hours: values.allowed_hours || Array.from({ length: 24 }, (_, i) => i),
|
||||
excluded_dates: config.time_restrictions.excluded_dates,
|
||||
};
|
||||
|
||||
const rollbackConfig = {
|
||||
enabled: values.rollback_enabled,
|
||||
max_attempts: values.max_attempts,
|
||||
cooldown_minutes: values.cooldown_minutes,
|
||||
};
|
||||
|
||||
const notificationConfig = {
|
||||
on_execute: values.notify_execute,
|
||||
on_fail: values.notify_fail,
|
||||
on_rollback: values.notify_rollback,
|
||||
channels: values.notification_channels,
|
||||
};
|
||||
|
||||
onSubmit({
|
||||
confidence_thresholds: thresholds,
|
||||
risk_limits: riskLimits,
|
||||
time_restrictions: timeRestrictions,
|
||||
rollback_config: rollbackConfig,
|
||||
notification_config: notificationConfig,
|
||||
});
|
||||
};
|
||||
|
||||
const levelCapability = LEVEL_CAPABILITIES[config.automation_level];
|
||||
const maxAmountLimit = config.risk_limits.max_amount * levelCapability.max_amount_multiplier;
|
||||
|
||||
return (
|
||||
<Form
|
||||
form={form}
|
||||
layout="vertical"
|
||||
initialValues={{
|
||||
auto_execute: config.confidence_thresholds.auto_execute * 100,
|
||||
pending_review: config.confidence_thresholds.pending_review * 100,
|
||||
auto_reject: config.confidence_thresholds.auto_reject * 100,
|
||||
max_amount: config.risk_limits.max_amount,
|
||||
max_quantity: config.risk_limits.max_quantity,
|
||||
allowed_risk_levels: config.risk_limits.allowed_risk_levels,
|
||||
allowed_hours: config.time_restrictions.allowed_hours,
|
||||
rollback_enabled: config.rollback_config.enabled,
|
||||
max_attempts: config.rollback_config.max_attempts,
|
||||
cooldown_minutes: config.rollback_config.cooldown_minutes,
|
||||
notify_execute: config.notification_config.on_execute,
|
||||
notify_fail: config.notification_config.on_fail,
|
||||
notify_rollback: config.notification_config.on_rollback,
|
||||
notification_channels: config.notification_config.channels,
|
||||
}}
|
||||
onFinish={handleSubmit}
|
||||
>
|
||||
<Alert
|
||||
message={`当前等级: ${config.automation_level} - ${levelCapability.description}`}
|
||||
type="info"
|
||||
showIcon
|
||||
style={{ marginBottom: 16 }}
|
||||
/>
|
||||
|
||||
<Card
|
||||
title={<><ThunderboltOutlined /> 置信度阈值配置</>}
|
||||
size="small"
|
||||
style={{ marginBottom: 16 }}
|
||||
>
|
||||
<Row gutter={16}>
|
||||
<Col span={8}>
|
||||
<Form.Item
|
||||
name="auto_execute"
|
||||
label="自动执行阈值 (%)"
|
||||
tooltip="置信度达到此阈值时自动执行"
|
||||
>
|
||||
<Slider
|
||||
min={50}
|
||||
max={100}
|
||||
marks={{ 50: '50%', 75: '75%', 100: '100%' }}
|
||||
/>
|
||||
</Form.Item>
|
||||
</Col>
|
||||
<Col span={8}>
|
||||
<Form.Item
|
||||
name="pending_review"
|
||||
label="待审核阈值 (%)"
|
||||
tooltip="置信度在此区间需要人工审核"
|
||||
>
|
||||
<Slider
|
||||
min={30}
|
||||
max={90}
|
||||
marks={{ 30: '30%', 60: '60%', 90: '90%' }}
|
||||
/>
|
||||
</Form.Item>
|
||||
</Col>
|
||||
<Col span={8}>
|
||||
<Form.Item
|
||||
name="auto_reject"
|
||||
label="自动拒绝阈值 (%)"
|
||||
tooltip="置信度低于此阈值自动拒绝"
|
||||
>
|
||||
<Slider
|
||||
min={10}
|
||||
max={70}
|
||||
marks={{ 10: '10%', 40: '40%', 70: '70%' }}
|
||||
/>
|
||||
</Form.Item>
|
||||
</Col>
|
||||
</Row>
|
||||
</Card>
|
||||
|
||||
<Card
|
||||
title={<><SafetyOutlined /> 风险限制配置</>}
|
||||
size="small"
|
||||
style={{ marginBottom: 16 }}
|
||||
>
|
||||
<Row gutter={16}>
|
||||
<Col span={8}>
|
||||
<Form.Item
|
||||
name="max_amount"
|
||||
label="最大金额限制"
|
||||
tooltip={`当前等级最大允许: ${maxAmountLimit}`}
|
||||
>
|
||||
<InputNumber
|
||||
style={{ width: '100%' }}
|
||||
min={0}
|
||||
max={maxAmountLimit}
|
||||
prefix="¥"
|
||||
formatter={(value) => `${value}`.replace(/\B(?=(\d{3})+(?!\d))/g, ',')}
|
||||
/>
|
||||
</Form.Item>
|
||||
</Col>
|
||||
<Col span={8}>
|
||||
<Form.Item
|
||||
name="max_quantity"
|
||||
label="最大数量限制"
|
||||
>
|
||||
<InputNumber
|
||||
style={{ width: '100%' }}
|
||||
min={1}
|
||||
max={10000}
|
||||
/>
|
||||
</Form.Item>
|
||||
</Col>
|
||||
<Col span={8}>
|
||||
<Form.Item
|
||||
name="allowed_risk_levels"
|
||||
label="允许的风险等级"
|
||||
>
|
||||
<Select mode="multiple" style={{ width: '100%' }}>
|
||||
<Option value="LOW">
|
||||
<Tag color="green">LOW</Tag>
|
||||
</Option>
|
||||
<Option value="MEDIUM">
|
||||
<Tag color="orange">MEDIUM</Tag>
|
||||
</Option>
|
||||
<Option value="HIGH" disabled={levelCapability.max_risk_level === 'LOW'}>
|
||||
<Tag color="red">HIGH</Tag>
|
||||
</Option>
|
||||
<Option value="CRITICAL" disabled={levelCapability.max_risk_level !== 'CRITICAL'}>
|
||||
<Tag color="purple">CRITICAL</Tag>
|
||||
</Option>
|
||||
</Select>
|
||||
</Form.Item>
|
||||
</Col>
|
||||
</Row>
|
||||
</Card>
|
||||
|
||||
<Card
|
||||
title={<><ClockCircleOutlined /> 时间限制配置</>}
|
||||
size="small"
|
||||
style={{ marginBottom: 16 }}
|
||||
>
|
||||
<Form.Item
|
||||
name="allowed_hours"
|
||||
label="允许执行的时间段"
|
||||
tooltip="选择允许自动执行的小时(0-23)"
|
||||
>
|
||||
<Select mode="multiple" style={{ width: '100%' }}>
|
||||
{Array.from({ length: 24 }, (_, i) => (
|
||||
<Option key={i} value={i}>
|
||||
{i.toString().padStart(2, '0')}:00
|
||||
</Option>
|
||||
))}
|
||||
</Select>
|
||||
</Form.Item>
|
||||
</Card>
|
||||
|
||||
<Card
|
||||
title={<><ThunderboltOutlined /> 回滚配置</>}
|
||||
size="small"
|
||||
style={{ marginBottom: 16 }}
|
||||
>
|
||||
<Row gutter={16}>
|
||||
<Col span={6}>
|
||||
<Form.Item
|
||||
name="rollback_enabled"
|
||||
label="启用自动回滚"
|
||||
valuePropName="checked"
|
||||
>
|
||||
<Switch />
|
||||
</Form.Item>
|
||||
</Col>
|
||||
<Col span={9}>
|
||||
<Form.Item
|
||||
name="max_attempts"
|
||||
label="最大重试次数"
|
||||
>
|
||||
<InputNumber min={1} max={10} style={{ width: '100%' }} />
|
||||
</Form.Item>
|
||||
</Col>
|
||||
<Col span={9}>
|
||||
<Form.Item
|
||||
name="cooldown_minutes"
|
||||
label="冷却时间(分钟)"
|
||||
>
|
||||
<InputNumber min={1} max={1440} style={{ width: '100%' }} />
|
||||
</Form.Item>
|
||||
</Col>
|
||||
</Row>
|
||||
</Card>
|
||||
|
||||
<Card
|
||||
title={<><BellOutlined /> 通知配置</>}
|
||||
size="small"
|
||||
style={{ marginBottom: 16 }}
|
||||
>
|
||||
<Row gutter={16}>
|
||||
<Col span={6}>
|
||||
<Form.Item
|
||||
name="notify_execute"
|
||||
label="执行时通知"
|
||||
valuePropName="checked"
|
||||
>
|
||||
<Switch />
|
||||
</Form.Item>
|
||||
</Col>
|
||||
<Col span={6}>
|
||||
<Form.Item
|
||||
name="notify_fail"
|
||||
label="失败时通知"
|
||||
valuePropName="checked"
|
||||
>
|
||||
<Switch />
|
||||
</Form.Item>
|
||||
</Col>
|
||||
<Col span={6}>
|
||||
<Form.Item
|
||||
name="notify_rollback"
|
||||
label="回滚时通知"
|
||||
valuePropName="checked"
|
||||
>
|
||||
<Switch />
|
||||
</Form.Item>
|
||||
</Col>
|
||||
<Col span={6}>
|
||||
<Form.Item
|
||||
name="notification_channels"
|
||||
label="通知渠道"
|
||||
>
|
||||
<Select mode="multiple" style={{ width: '100%' }}>
|
||||
<Option value="EMAIL">邮件</Option>
|
||||
<Option value="SMS">短信</Option>
|
||||
<Option value="WEBHOOK">Webhook</Option>
|
||||
</Select>
|
||||
</Form.Item>
|
||||
</Col>
|
||||
</Row>
|
||||
</Card>
|
||||
|
||||
<Divider />
|
||||
|
||||
<Space style={{ width: '100%', justifyContent: 'flex-end' }}>
|
||||
<button type="button" onClick={onCancel} className="ant-btn">
|
||||
取消
|
||||
</button>
|
||||
<button type="submit" className="ant-btn ant-btn-primary">
|
||||
保存配置
|
||||
</button>
|
||||
</Space>
|
||||
</Form>
|
||||
);
|
||||
};
|
||||
|
||||
export default ThresholdConfigForm;
|
||||
Reference in New Issue
Block a user