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';
|