refactor: 重构页面组件移除冗余Layout组件 feat: 实现WebSocket和事件总线系统 feat: 添加队列和调度系统 docs: 更新架构文档和服务映射 style: 清理重复接口定义使用数据源 chore: 更新依赖项配置 feat: 添加运行时系统和领域引导 ci: 配置ESLint边界检查规则 build: 添加Redis和WebSocket依赖 test: 添加MSW浏览器环境入口 perf: 优化数据获取逻辑使用统一数据源 fix: 修复类型定义和状态管理问题
221 lines
6.7 KiB
TypeScript
221 lines
6.7 KiB
TypeScript
/**
|
||
* [MOCK-AD-001] Ad Optimization数据源抽象层
|
||
* AI注意: 这是数据源抽象层,业务组件通过此层获取数据
|
||
* 仅在REACT_APP_USE_MOCK=true时启用Mock
|
||
*
|
||
* @module services/adOptimizationDataSource
|
||
* @created 2026-03-19
|
||
*/
|
||
|
||
import { IMockDataSource } from '@/types/datasource';
|
||
|
||
// ============================================
|
||
// 类型定义
|
||
// ============================================
|
||
|
||
export interface OptimizationSuggestion {
|
||
id: string;
|
||
adId: string;
|
||
adName: string;
|
||
currentCPC: number;
|
||
suggestedCPC: number;
|
||
currentROI: number;
|
||
expectedROI: number;
|
||
currentSpend: number;
|
||
suggestedSpend: number;
|
||
confidence: number;
|
||
status: 'pending' | 'applied' | 'rejected';
|
||
}
|
||
|
||
export interface AdPerformance {
|
||
id: string;
|
||
date: string;
|
||
clicks: number;
|
||
conversions: number;
|
||
spend: number;
|
||
roi: number;
|
||
}
|
||
|
||
export interface AdOptimizationQueryParams {
|
||
adId?: string;
|
||
startDate?: string;
|
||
endDate?: string;
|
||
}
|
||
|
||
export interface AdOptimizationData {
|
||
suggestions: OptimizationSuggestion[];
|
||
performance: AdPerformance[];
|
||
}
|
||
|
||
// ============================================
|
||
// Ad Optimization专用接口
|
||
// ============================================
|
||
|
||
export interface IAdOptimizationDataSource {
|
||
optimize(params?: AdOptimizationQueryParams): Promise<AdOptimizationData>;
|
||
fetchSuggestions(): Promise<OptimizationSuggestion[]>;
|
||
fetchPerformance(): Promise<AdPerformance[]>;
|
||
applySuggestion(id: string): Promise<OptimizationSuggestion>;
|
||
rejectSuggestion(id: string): Promise<OptimizationSuggestion>;
|
||
}
|
||
|
||
// ============================================
|
||
// API实现
|
||
// ============================================
|
||
|
||
class ApiAdOptimizationDataSource implements IAdOptimizationDataSource {
|
||
async optimize(params?: AdOptimizationQueryParams): Promise<AdOptimizationData> {
|
||
const [suggestions, performance] = await Promise.all([
|
||
this.fetchSuggestions(),
|
||
this.fetchPerformance(),
|
||
]);
|
||
return { suggestions, performance };
|
||
}
|
||
|
||
async fetchSuggestions(): Promise<OptimizationSuggestion[]> {
|
||
const response = await fetch('/api/v1/ad/optimization/suggestions');
|
||
const result = await response.json();
|
||
return result.data;
|
||
}
|
||
|
||
async fetchPerformance(): Promise<AdPerformance[]> {
|
||
const response = await fetch('/api/v1/ad/optimization/performance');
|
||
const result = await response.json();
|
||
return result.data;
|
||
}
|
||
|
||
async applySuggestion(id: string): Promise<OptimizationSuggestion> {
|
||
const response = await fetch(`/api/v1/ad/optimization/suggestions/${id}/apply`, {
|
||
method: 'POST',
|
||
});
|
||
const result = await response.json();
|
||
return result.data;
|
||
}
|
||
|
||
async rejectSuggestion(id: string): Promise<OptimizationSuggestion> {
|
||
const response = await fetch(`/api/v1/ad/optimization/suggestions/${id}/reject`, {
|
||
method: 'POST',
|
||
});
|
||
const result = await response.json();
|
||
return result.data;
|
||
}
|
||
}
|
||
|
||
// ============================================
|
||
// Mock实现
|
||
// ============================================
|
||
|
||
/**
|
||
* [MOCK] Ad Optimization Mock数据源
|
||
* AI注意: 这是Mock实现,不是真实业务逻辑
|
||
* 仅在REACT_APP_USE_MOCK=true时启用
|
||
*/
|
||
class MockAdOptimizationDataSource implements IAdOptimizationDataSource, IMockDataSource {
|
||
readonly __MOCK__ = true as const;
|
||
readonly __MOCK_NAME__ = 'MockAdOptimizationDataSource';
|
||
|
||
private mockSuggestions: OptimizationSuggestion[] = [
|
||
{
|
||
id: '1',
|
||
adId: 'AD001',
|
||
adName: '智能手表推广',
|
||
currentCPC: 1.5,
|
||
suggestedCPC: 1.2,
|
||
currentROI: 3.2,
|
||
expectedROI: 4.5,
|
||
currentSpend: 1000,
|
||
suggestedSpend: 1200,
|
||
confidence: 0.85,
|
||
status: 'pending',
|
||
},
|
||
{
|
||
id: '2',
|
||
adId: 'AD002',
|
||
adName: '无线耳机促销',
|
||
currentCPC: 0.8,
|
||
suggestedCPC: 1.0,
|
||
currentROI: 2.8,
|
||
expectedROI: 3.5,
|
||
currentSpend: 800,
|
||
suggestedSpend: 900,
|
||
confidence: 0.90,
|
||
status: 'pending',
|
||
},
|
||
{
|
||
id: '3',
|
||
adId: 'AD003',
|
||
adName: '智能音箱新品',
|
||
currentCPC: 2.0,
|
||
suggestedCPC: 1.8,
|
||
currentROI: 2.5,
|
||
expectedROI: 3.2,
|
||
currentSpend: 1200,
|
||
suggestedSpend: 1000,
|
||
confidence: 0.80,
|
||
status: 'pending',
|
||
},
|
||
];
|
||
|
||
private mockPerformance: AdPerformance[] = [
|
||
{ id: '1', date: '2026-03-12', clicks: 1200, conversions: 120, spend: 1800, roi: 3.2 },
|
||
{ id: '2', date: '2026-03-13', clicks: 1300, conversions: 135, spend: 1950, roi: 3.4 },
|
||
{ id: '3', date: '2026-03-14', clicks: 1100, conversions: 105, spend: 1650, roi: 3.1 },
|
||
{ id: '4', date: '2026-03-15', clicks: 1400, conversions: 150, spend: 2100, roi: 3.3 },
|
||
{ id: '5', date: '2026-03-16', clicks: 1500, conversions: 165, spend: 2250, roi: 3.5 },
|
||
{ id: '6', date: '2026-03-17', clicks: 1600, conversions: 180, spend: 2400, roi: 3.6 },
|
||
{ id: '7', date: '2026-03-18', clicks: 1700, conversions: 195, spend: 2550, roi: 3.8 },
|
||
];
|
||
|
||
async optimize(params?: AdOptimizationQueryParams): Promise<AdOptimizationData> {
|
||
await this.simulateDelay(1500);
|
||
const [suggestions, performance] = await Promise.all([
|
||
this.fetchSuggestions(),
|
||
this.fetchPerformance(),
|
||
]);
|
||
return { suggestions, performance };
|
||
}
|
||
|
||
async fetchSuggestions(): Promise<OptimizationSuggestion[]> {
|
||
await this.simulateDelay(300);
|
||
return [...this.mockSuggestions];
|
||
}
|
||
|
||
async fetchPerformance(): Promise<AdPerformance[]> {
|
||
await this.simulateDelay(200);
|
||
return [...this.mockPerformance];
|
||
}
|
||
|
||
async applySuggestion(id: string): Promise<OptimizationSuggestion> {
|
||
await this.simulateDelay(200);
|
||
const index = this.mockSuggestions.findIndex(s => s.id === id);
|
||
if (index === -1) throw new Error('Suggestion not found');
|
||
this.mockSuggestions[index] = { ...this.mockSuggestions[index], status: 'applied' };
|
||
return this.mockSuggestions[index];
|
||
}
|
||
|
||
async rejectSuggestion(id: string): Promise<OptimizationSuggestion> {
|
||
await this.simulateDelay(200);
|
||
const index = this.mockSuggestions.findIndex(s => s.id === id);
|
||
if (index === -1) throw new Error('Suggestion not found');
|
||
this.mockSuggestions[index] = { ...this.mockSuggestions[index], status: 'rejected' };
|
||
return this.mockSuggestions[index];
|
||
}
|
||
|
||
private simulateDelay(ms: number): Promise<void> {
|
||
return new Promise(resolve => setTimeout(resolve, ms));
|
||
}
|
||
}
|
||
|
||
// ============================================
|
||
// 导出数据源实例
|
||
// ============================================
|
||
|
||
const useMock = process.env.REACT_APP_USE_MOCK === 'true';
|
||
|
||
export const adOptimizationDataSource: IAdOptimizationDataSource = useMock
|
||
? new MockAdOptimizationDataSource()
|
||
: new ApiAdOptimizationDataSource();
|
||
|
||
export const __MOCK__ = useMock;
|
||
export const __DATA_SOURCE_TYPE__ = useMock ? 'mock' : 'api';
|