feat: 添加前端页面和业务说明书
refactor(server): 重构服务层代码结构 feat(server): 添加基础设施、跨境电商、AI决策等核心服务 docs: 完善前端业务说明书和开发进度文档 style: 格式化代码和文档
This commit is contained in:
369
dashboard/src/pages/Ad/AutoAdjustment/index.tsx
Normal file
369
dashboard/src/pages/Ad/AutoAdjustment/index.tsx
Normal file
@@ -0,0 +1,369 @@
|
||||
import React, { useState } from 'react';
|
||||
import { Card, Layout, Typography, Row, Col, Form, Input, Select, Button, Table, Switch, DatePicker, TimePicker, message, Alert, Modal } from 'antd';
|
||||
import { PlusOutlined, EditOutlined, DeleteOutlined, SaveOutlined, PlayCircleOutlined, PauseCircleOutlined, HistoryOutlined } from '@ant-design/icons';
|
||||
import { Link } from 'umi';
|
||||
|
||||
const { Content } = Layout;
|
||||
const { Title, Text, Paragraph } = Typography;
|
||||
const { Option } = Select;
|
||||
const { Item } = Form;
|
||||
const { RangePicker } = DatePicker;
|
||||
|
||||
interface Strategy {
|
||||
id: string;
|
||||
name: string;
|
||||
adId: string;
|
||||
adName: string;
|
||||
type: string;
|
||||
condition: string;
|
||||
action: string;
|
||||
status: 'active' | 'inactive' | 'paused';
|
||||
createdAt: string;
|
||||
lastExecuted: string;
|
||||
executionCount: number;
|
||||
}
|
||||
|
||||
interface ExecutionHistory {
|
||||
id: string;
|
||||
strategyId: string;
|
||||
strategyName: string;
|
||||
executionTime: string;
|
||||
status: 'success' | 'failed' | 'pending';
|
||||
result: string;
|
||||
details: string;
|
||||
}
|
||||
|
||||
const AutoAdjustment: React.FC = () => {
|
||||
const [strategies, setStrategies] = useState<Strategy[]>([]);
|
||||
const [executionHistory, setExecutionHistory] = useState<ExecutionHistory[]>([]);
|
||||
const [isModalVisible, setIsModalVisible] = useState<boolean>(false);
|
||||
const [editingStrategy, setEditingStrategy] = useState<Strategy | null>(null);
|
||||
const [form] = Form.useForm();
|
||||
|
||||
const mockStrategies: Strategy[] = [
|
||||
{
|
||||
id: '1',
|
||||
name: 'ROI自动调整',
|
||||
adId: 'AD001',
|
||||
adName: '智能手表推广',
|
||||
type: 'ROI',
|
||||
condition: 'ROI < 3.0',
|
||||
action: '降低CPC 10%',
|
||||
status: 'active',
|
||||
createdAt: '2026-03-10',
|
||||
lastExecuted: '2026-03-18 10:30',
|
||||
executionCount: 15,
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
name: '点击率优化',
|
||||
adId: 'AD002',
|
||||
adName: '无线耳机促销',
|
||||
type: 'CTR',
|
||||
condition: 'CTR < 2.0%',
|
||||
action: '调整创意',
|
||||
status: 'paused',
|
||||
createdAt: '2026-03-08',
|
||||
lastExecuted: '2026-03-15 14:20',
|
||||
executionCount: 8,
|
||||
},
|
||||
{
|
||||
id: '3',
|
||||
name: '预算自动分配',
|
||||
adId: 'AD003',
|
||||
adName: '智能音箱新品',
|
||||
type: 'Budget',
|
||||
condition: '日花费 < 预算的80%',
|
||||
action: '增加预算10%',
|
||||
status: 'active',
|
||||
createdAt: '2026-03-05',
|
||||
lastExecuted: '2026-03-18 09:15',
|
||||
executionCount: 20,
|
||||
},
|
||||
];
|
||||
|
||||
const mockExecutionHistory: ExecutionHistory[] = [
|
||||
{
|
||||
id: '1',
|
||||
strategyId: '1',
|
||||
strategyName: 'ROI自动调整',
|
||||
executionTime: '2026-03-18 10:30',
|
||||
status: 'success',
|
||||
result: 'CPC降低10%',
|
||||
details: 'ROI为2.8,低于阈值3.0,执行降低CPC操作',
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
strategyId: '3',
|
||||
strategyName: '预算自动分配',
|
||||
executionTime: '2026-03-18 09:15',
|
||||
status: 'success',
|
||||
result: '预算增加10%',
|
||||
details: '日花费为预算的75%,低于阈值80%,执行增加预算操作',
|
||||
},
|
||||
{
|
||||
id: '3',
|
||||
strategyId: '1',
|
||||
strategyName: 'ROI自动调整',
|
||||
executionTime: '2026-03-17 16:45',
|
||||
status: 'failed',
|
||||
result: '操作失败',
|
||||
details: 'API调用失败,无法执行调整操作',
|
||||
},
|
||||
];
|
||||
|
||||
const handleAddStrategy = () => {
|
||||
setEditingStrategy(null);
|
||||
form.resetFields();
|
||||
setIsModalVisible(true);
|
||||
};
|
||||
|
||||
const handleEditStrategy = (strategy: Strategy) => {
|
||||
setEditingStrategy(strategy);
|
||||
form.setFieldsValue(strategy);
|
||||
setIsModalVisible(true);
|
||||
};
|
||||
|
||||
const handleDeleteStrategy = (id: string) => {
|
||||
const updatedStrategies = strategies.filter(item => item.id !== id);
|
||||
setStrategies(updatedStrategies);
|
||||
message.success('策略已删除');
|
||||
};
|
||||
|
||||
const handleToggleStrategy = (id: string) => {
|
||||
const updatedStrategies = strategies.map(item =>
|
||||
item.id === id
|
||||
? { ...item, status: item.status === 'active' ? 'paused' : 'active' }
|
||||
: item
|
||||
);
|
||||
setStrategies(updatedStrategies);
|
||||
message.success('策略状态已更新');
|
||||
};
|
||||
|
||||
const handleSaveStrategy = () => {
|
||||
form.validateFields().then(values => {
|
||||
if (editingStrategy) {
|
||||
const updatedStrategies = strategies.map(item =>
|
||||
item.id === editingStrategy.id ? { ...item, ...values } : item
|
||||
);
|
||||
setStrategies(updatedStrategies);
|
||||
message.success('策略已更新');
|
||||
} else {
|
||||
const newStrategy: Strategy = {
|
||||
id: (strategies.length + 1).toString(),
|
||||
...values,
|
||||
status: 'inactive' as const,
|
||||
createdAt: new Date().toISOString().split('T')[0],
|
||||
lastExecuted: '-',
|
||||
executionCount: 0,
|
||||
};
|
||||
setStrategies([...strategies, newStrategy]);
|
||||
message.success('策略已创建');
|
||||
}
|
||||
setIsModalVisible(false);
|
||||
});
|
||||
};
|
||||
|
||||
const columns = [
|
||||
{
|
||||
title: '策略名称',
|
||||
dataIndex: 'name',
|
||||
key: 'name',
|
||||
},
|
||||
{
|
||||
title: '广告',
|
||||
dataIndex: 'adName',
|
||||
key: 'adName',
|
||||
},
|
||||
{
|
||||
title: '类型',
|
||||
dataIndex: 'type',
|
||||
key: 'type',
|
||||
},
|
||||
{
|
||||
title: '条件',
|
||||
dataIndex: 'condition',
|
||||
key: 'condition',
|
||||
},
|
||||
{
|
||||
title: '动作',
|
||||
dataIndex: 'action',
|
||||
key: 'action',
|
||||
},
|
||||
{
|
||||
title: '状态',
|
||||
dataIndex: 'status',
|
||||
key: 'status',
|
||||
render: (status: string) => (
|
||||
<span style={{
|
||||
color: status === 'active' ? '#52c41a' :
|
||||
status === 'paused' ? '#faad14' : '#d9d9d9'
|
||||
}}>
|
||||
{status === 'active' ? '活跃' :
|
||||
status === 'paused' ? '暂停' : '未激活'}
|
||||
</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: '执行次数',
|
||||
dataIndex: 'executionCount',
|
||||
key: 'executionCount',
|
||||
},
|
||||
{
|
||||
title: '上次执行',
|
||||
dataIndex: 'lastExecuted',
|
||||
key: 'lastExecuted',
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
key: 'action',
|
||||
render: (_: any, record: Strategy) => (
|
||||
<div style={{ display: 'flex', gap: 8 }}>
|
||||
<Button
|
||||
icon={record.status === 'active' ? <PauseCircleOutlined /> : <PlayCircleOutlined />}
|
||||
size="small"
|
||||
onClick={() => handleToggleStrategy(record.id)}
|
||||
>
|
||||
{record.status === 'active' ? '暂停' : '激活'}
|
||||
</Button>
|
||||
<Button
|
||||
icon={<EditOutlined />}
|
||||
size="small"
|
||||
onClick={() => handleEditStrategy(record)}
|
||||
>
|
||||
编辑
|
||||
</Button>
|
||||
<Button
|
||||
icon={<DeleteOutlined />}
|
||||
size="small"
|
||||
danger
|
||||
onClick={() => handleDeleteStrategy(record.id)}
|
||||
>
|
||||
删除
|
||||
</Button>
|
||||
</div>
|
||||
),
|
||||
},
|
||||
];
|
||||
|
||||
const historyColumns = [
|
||||
{
|
||||
title: '策略名称',
|
||||
dataIndex: 'strategyName',
|
||||
key: 'strategyName',
|
||||
},
|
||||
{
|
||||
title: '执行时间',
|
||||
dataIndex: 'executionTime',
|
||||
key: 'executionTime',
|
||||
},
|
||||
{
|
||||
title: '状态',
|
||||
dataIndex: 'status',
|
||||
key: 'status',
|
||||
render: (status: string) => (
|
||||
<span style={{
|
||||
color: status === 'success' ? '#52c41a' :
|
||||
status === 'failed' ? '#ff4d4f' : '#faad14'
|
||||
}}>
|
||||
{status === 'success' ? '成功' :
|
||||
status === 'failed' ? '失败' : '待执行'}
|
||||
</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: '结果',
|
||||
dataIndex: 'result',
|
||||
key: 'result',
|
||||
},
|
||||
{
|
||||
title: '详情',
|
||||
dataIndex: 'details',
|
||||
key: 'details',
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<Content style={{ padding: 24, margin: 0, minHeight: 280, background: '#fff' }}>
|
||||
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 24 }}>
|
||||
<Title level={4}>自动调整策略配置</Title>
|
||||
<Button type="primary" icon={<PlusOutlined />} onClick={handleAddStrategy}>
|
||||
添加策略
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
{/* 策略列表 */}
|
||||
<Card title="策略列表" style={{ marginBottom: 24 }}>
|
||||
<Table
|
||||
columns={columns}
|
||||
dataSource={mockStrategies}
|
||||
rowKey="id"
|
||||
pagination={{ pageSize: 10 }}
|
||||
/>
|
||||
</Card>
|
||||
|
||||
{/* 执行历史 */}
|
||||
<Card title="执行历史">
|
||||
<Table
|
||||
columns={historyColumns}
|
||||
dataSource={mockExecutionHistory}
|
||||
rowKey="id"
|
||||
pagination={{ pageSize: 10 }}
|
||||
/>
|
||||
</Card>
|
||||
|
||||
{/* 策略编辑模态框 */}
|
||||
<Modal
|
||||
title={editingStrategy ? "编辑策略" : "添加策略"}
|
||||
open={isModalVisible}
|
||||
onCancel={() => setIsModalVisible(false)}
|
||||
footer={null}
|
||||
>
|
||||
<Form
|
||||
form={form}
|
||||
layout="vertical"
|
||||
initialValues={{
|
||||
name: '',
|
||||
adId: 'AD001',
|
||||
type: 'ROI',
|
||||
condition: '',
|
||||
action: '',
|
||||
}}
|
||||
>
|
||||
<Item label="策略名称" name="name" rules={[{ required: true, message: '请输入策略名称' }]}>
|
||||
<Input placeholder="输入策略名称" />
|
||||
</Item>
|
||||
<Item label="广告" name="adId">
|
||||
<Select>
|
||||
<Option value="AD001">智能手表推广</Option>
|
||||
<Option value="AD002">无线耳机促销</Option>
|
||||
<Option value="AD003">智能音箱新品</Option>
|
||||
</Select>
|
||||
</Item>
|
||||
<Item label="策略类型" name="type">
|
||||
<Select>
|
||||
<Option value="ROI">ROI优化</Option>
|
||||
<Option value="CTR">点击率优化</Option>
|
||||
<Option value="Budget">预算管理</Option>
|
||||
<Option value="Conversion">转化优化</Option>
|
||||
</Select>
|
||||
</Item>
|
||||
<Item label="触发条件" name="condition" rules={[{ required: true, message: '请输入触发条件' }]}>
|
||||
<Input placeholder="例如:ROI < 3.0" />
|
||||
</Item>
|
||||
<Item label="执行动作" name="action" rules={[{ required: true, message: '请输入执行动作' }]}>
|
||||
<Input placeholder="例如:降低CPC 10%" />
|
||||
</Item>
|
||||
<div style={{ display: 'flex', justifyContent: 'flex-end', gap: 12, marginTop: 24 }}>
|
||||
<Button onClick={() => setIsModalVisible(false)}>取消</Button>
|
||||
<Button type="primary" icon={<SaveOutlined />} onClick={handleSaveStrategy}>
|
||||
保存
|
||||
</Button>
|
||||
</div>
|
||||
</Form>
|
||||
</Modal>
|
||||
</Content>
|
||||
);
|
||||
};
|
||||
|
||||
export default AutoAdjustment;
|
||||
Reference in New Issue
Block a user