feat: 添加MSW模拟服务和数据源集成
refactor: 重构页面组件移除冗余Layout组件 feat: 实现WebSocket和事件总线系统 feat: 添加队列和调度系统 docs: 更新架构文档和服务映射 style: 清理重复接口定义使用数据源 chore: 更新依赖项配置 feat: 添加运行时系统和领域引导 ci: 配置ESLint边界检查规则 build: 添加Redis和WebSocket依赖 test: 添加MSW浏览器环境入口 perf: 优化数据获取逻辑使用统一数据源 fix: 修复类型定义和状态管理问题
This commit is contained in:
220
dashboard/src/services/adOptimizationDataSource.ts
Normal file
220
dashboard/src/services/adOptimizationDataSource.ts
Normal file
@@ -0,0 +1,220 @@
|
||||
/**
|
||||
* [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';
|
||||
Reference in New Issue
Block a user