feat: 添加前端页面和业务说明书
refactor(server): 重构服务层代码结构 feat(server): 添加基础设施、跨境电商、AI决策等核心服务 docs: 完善前端业务说明书和开发进度文档 style: 格式化代码和文档
This commit is contained in:
281
dashboard/src/pages/Marketing/Ads.tsx
Normal file
281
dashboard/src/pages/Marketing/Ads.tsx
Normal file
@@ -0,0 +1,281 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { Table, Button, Input, Select, DatePicker, message, Card, Tabs } from 'antd';
|
||||
import { PlusOutlined, EditOutlined, DeleteOutlined, SearchOutlined, PlayCircleOutlined, PauseCircleOutlined } from '@ant-design/icons';
|
||||
|
||||
const { Option } = Select;
|
||||
const { RangePicker } = DatePicker;
|
||||
const { Search } = Input;
|
||||
const { TabPane } = Tabs;
|
||||
|
||||
interface Ad {
|
||||
id: string;
|
||||
name: string;
|
||||
platform: string;
|
||||
campaign: string;
|
||||
status: 'active' | 'paused' | 'completed';
|
||||
budget: number;
|
||||
spend: number;
|
||||
impressions: number;
|
||||
clicks: number;
|
||||
conversions: number;
|
||||
roi: number;
|
||||
startDate: string;
|
||||
endDate: string;
|
||||
}
|
||||
|
||||
const Ads: React.FC = () => {
|
||||
const [ads, setAds] = useState<Ad[]>([]);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [filters, setFilters] = useState({
|
||||
platform: '',
|
||||
status: '',
|
||||
search: '',
|
||||
dateRange: null as any,
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
fetchAds();
|
||||
}, [filters]);
|
||||
|
||||
const fetchAds = async () => {
|
||||
setLoading(true);
|
||||
// 模拟API调用
|
||||
setTimeout(() => {
|
||||
const mockAds: Ad[] = [
|
||||
{
|
||||
id: '1',
|
||||
name: 'Summer Sale',
|
||||
platform: 'Facebook',
|
||||
campaign: 'Summer Campaign',
|
||||
status: 'active',
|
||||
budget: 10000,
|
||||
spend: 5000,
|
||||
impressions: 100000,
|
||||
clicks: 5000,
|
||||
conversions: 250,
|
||||
roi: 3.5,
|
||||
startDate: '2026-06-01',
|
||||
endDate: '2026-06-30',
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
name: 'Back to School',
|
||||
platform: 'Google',
|
||||
campaign: 'Back to School Campaign',
|
||||
status: 'active',
|
||||
budget: 15000,
|
||||
spend: 8000,
|
||||
impressions: 150000,
|
||||
clicks: 7500,
|
||||
conversions: 375,
|
||||
roi: 4.0,
|
||||
startDate: '2026-07-01',
|
||||
endDate: '2026-08-31',
|
||||
},
|
||||
{
|
||||
id: '3',
|
||||
name: 'Holiday Special',
|
||||
platform: 'Instagram',
|
||||
campaign: 'Holiday Campaign',
|
||||
status: 'paused',
|
||||
budget: 20000,
|
||||
spend: 10000,
|
||||
impressions: 200000,
|
||||
clicks: 10000,
|
||||
conversions: 500,
|
||||
roi: 3.0,
|
||||
startDate: '2026-11-01',
|
||||
endDate: '2026-12-31',
|
||||
},
|
||||
];
|
||||
setAds(mockAds);
|
||||
setLoading(false);
|
||||
}, 500);
|
||||
};
|
||||
|
||||
const handleStartAd = (id: string) => {
|
||||
message.success('广告已启动');
|
||||
fetchAds();
|
||||
};
|
||||
|
||||
const handlePauseAd = (id: string) => {
|
||||
message.success('广告已暂停');
|
||||
fetchAds();
|
||||
};
|
||||
|
||||
const handleEditAd = (id: string) => {
|
||||
message.info('编辑广告功能开发中');
|
||||
};
|
||||
|
||||
const handleDeleteAd = (id: string) => {
|
||||
message.success('广告已删除');
|
||||
fetchAds();
|
||||
};
|
||||
|
||||
const columns = [
|
||||
{
|
||||
title: '广告名称',
|
||||
dataIndex: 'name',
|
||||
key: 'name',
|
||||
},
|
||||
{
|
||||
title: '平台',
|
||||
dataIndex: 'platform',
|
||||
key: 'platform',
|
||||
},
|
||||
{
|
||||
title: '活动',
|
||||
dataIndex: 'campaign',
|
||||
key: 'campaign',
|
||||
},
|
||||
{
|
||||
title: '状态',
|
||||
dataIndex: 'status',
|
||||
key: 'status',
|
||||
render: (status: string) => {
|
||||
const statusMap = {
|
||||
active: '活跃',
|
||||
paused: '暂停',
|
||||
completed: '已完成',
|
||||
};
|
||||
return statusMap[status] || status;
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '预算',
|
||||
dataIndex: 'budget',
|
||||
key: 'budget',
|
||||
render: (budget: number) => `$${budget.toFixed(2)}`,
|
||||
},
|
||||
{
|
||||
title: '支出',
|
||||
dataIndex: 'spend',
|
||||
key: 'spend',
|
||||
render: (spend: number) => `$${spend.toFixed(2)}`,
|
||||
},
|
||||
{
|
||||
title: '点击量',
|
||||
dataIndex: 'clicks',
|
||||
key: 'clicks',
|
||||
},
|
||||
{
|
||||
title: '转化数',
|
||||
dataIndex: 'conversions',
|
||||
key: 'conversions',
|
||||
},
|
||||
{
|
||||
title: 'ROI',
|
||||
dataIndex: 'roi',
|
||||
key: 'roi',
|
||||
render: (roi: number) => `${roi.toFixed(2)}x`,
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
key: 'action',
|
||||
render: (_: any, record: Ad) => (
|
||||
<div>
|
||||
{record.status === 'active' ? (
|
||||
<Button
|
||||
type="link"
|
||||
icon={<PauseCircleOutlined />}
|
||||
onClick={() => handlePauseAd(record.id)}
|
||||
>
|
||||
暂停
|
||||
</Button>
|
||||
) : (
|
||||
<Button
|
||||
type="link"
|
||||
icon={<PlayCircleOutlined />}
|
||||
onClick={() => handleStartAd(record.id)}
|
||||
>
|
||||
启动
|
||||
</Button>
|
||||
)}
|
||||
<Button
|
||||
type="link"
|
||||
icon={<EditOutlined />}
|
||||
onClick={() => handleEditAd(record.id)}
|
||||
>
|
||||
编辑
|
||||
</Button>
|
||||
<Button
|
||||
type="link"
|
||||
danger
|
||||
icon={<DeleteOutlined />}
|
||||
onClick={() => handleDeleteAd(record.id)}
|
||||
>
|
||||
删除
|
||||
</Button>
|
||||
</div>
|
||||
),
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<div className="ads">
|
||||
<div className="page-header">
|
||||
<h1>广告管理</h1>
|
||||
<Button
|
||||
type="primary"
|
||||
icon={<PlusOutlined />}
|
||||
>
|
||||
创建广告
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<div className="filter-section" style={{ marginBottom: 24, display: 'flex', gap: 16, flexWrap: 'wrap' }}>
|
||||
<Search
|
||||
placeholder="搜索广告名称或活动"
|
||||
style={{ width: 300 }}
|
||||
onChange={(e) => setFilters({ ...filters, search: e.target.value })}
|
||||
/>
|
||||
<Select
|
||||
placeholder="平台"
|
||||
style={{ width: 120 }}
|
||||
onChange={(value) => setFilters({ ...filters, platform: value })}
|
||||
>
|
||||
<Option value="">全部</Option>
|
||||
<Option value="Facebook">Facebook</Option>
|
||||
<Option value="Google">Google</Option>
|
||||
<Option value="Instagram">Instagram</Option>
|
||||
<Option value="TikTok">TikTok</Option>
|
||||
</Select>
|
||||
<Select
|
||||
placeholder="状态"
|
||||
style={{ width: 120 }}
|
||||
onChange={(value) => setFilters({ ...filters, status: value })}
|
||||
>
|
||||
<Option value="">全部</Option>
|
||||
<Option value="active">活跃</Option>
|
||||
<Option value="paused">暂停</Option>
|
||||
<Option value="completed">已完成</Option>
|
||||
</Select>
|
||||
<RangePicker
|
||||
style={{ width: 300 }}
|
||||
onChange={(dates) => setFilters({ ...filters, dateRange: dates })}
|
||||
/>
|
||||
<Button
|
||||
icon={<SearchOutlined />}
|
||||
onClick={fetchAds}
|
||||
>
|
||||
筛选
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<Card title="广告列表">
|
||||
<Table
|
||||
columns={columns}
|
||||
dataSource={ads}
|
||||
loading={loading}
|
||||
rowKey="id"
|
||||
pagination={{
|
||||
pageSize: 10,
|
||||
showSizeChanger: true,
|
||||
}}
|
||||
/>
|
||||
</Card>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Ads;
|
||||
Reference in New Issue
Block a user