Files
makemd/dashboard/src/services/leaderboardDataSource.ts
wurenzhi aa2cf560c6 feat: 添加汇率服务和缓存服务,优化数据源和日志服务
refactor: 重构数据源工厂和类型定义,提升代码可维护性

fix: 修复类型转换和状态机文档中的错误

docs: 更新服务架构文档,添加新的服务闭环流程

test: 添加汇率服务单元测试

chore: 清理无用代码和注释,优化代码结构
2026-03-19 14:19:01 +08:00

118 lines
3.8 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* [MOCK] 排行榜数据源
* AI注意: 这是Mock实现不是真实业务逻辑
* 仅在USE_MOCK=true时启用
*/
import { BaseDataSource, BaseMockDataSource, DataSourceFactory } from './dataSourceFactory';
export interface LeaderboardEntry {
rank: number;
tenant_id: string;
tenant_name: string;
shop_id: string;
shop_name: string;
value: number;
tier: string;
is_verified: boolean;
growth_rate: number;
}
export interface LeaderboardData {
revenue: { rankings: LeaderboardEntry[]; total: number };
roi: { rankings: LeaderboardEntry[]; total: number };
growth: { rankings: LeaderboardEntry[]; total: number };
period: string;
updatedAt: string;
}
export interface MyRank {
revenue: { rank: number; percentile: number } | null;
roi: { rank: number; percentile: number } | null;
growth: { rank: number; percentile: number } | null;
period: string;
}
export interface ILeaderboardDataSource {
fetchLeaderboard(period: 'DAILY' | 'WEEKLY' | 'MONTHLY' | 'ALL_TIME'): Promise<LeaderboardData>;
fetchMyRank(period: 'DAILY' | 'WEEKLY' | 'MONTHLY' | 'ALL_TIME'): Promise<MyRank>;
}
class ApiLeaderboardDataSource extends BaseDataSource<any, any> implements ILeaderboardDataSource {
constructor() {
super('/api/leaderboard');
}
async fetchLeaderboard(period: 'DAILY' | 'WEEKLY' | 'MONTHLY' | 'ALL_TIME'): Promise<LeaderboardData> {
const response = await fetch(`${this.baseUrl}?period=${period}`);
if (!response.ok) throw new Error('Failed to fetch leaderboard');
return response.json();
}
async fetchMyRank(period: 'DAILY' | 'WEEKLY' | 'MONTHLY' | 'ALL_TIME'): Promise<MyRank> {
const response = await fetch(`${this.baseUrl}/my-rank?period=${period}`);
if (!response.ok) throw new Error('Failed to fetch my rank');
return response.json();
}
}
class MockLeaderboardDataSource extends BaseMockDataSource<any, any> implements ILeaderboardDataSource {
/** Mock数据源名称 */
readonly __MOCK_NAME__ = 'MockLeaderboardDataSource';
/** Mock数据 */
protected mockData: any[] = [];
private generateRankings(count: number, type: 'revenue' | 'roi' | 'growth'): LeaderboardEntry[] {
return Array.from({ length: count }, (_, i) => ({
rank: i + 1,
tenant_id: `tenant_${i + 1}`,
tenant_name: `Tenant ${i + 1}`,
shop_id: `shop_${i + 1}`,
shop_name: `Shop ${i + 1}`,
value: type === 'revenue' ? Math.floor(Math.random() * 100000) + 10000 :
type === 'roi' ? Math.floor(Math.random() * 100) + 20 :
Math.floor(Math.random() * 50) + 5,
tier: ['BASIC', 'PRO', 'ENTERPRISE'][Math.floor(Math.random() * 3)],
is_verified: Math.random() > 0.3,
growth_rate: Math.floor(Math.random() * 100) - 20,
}));
}
async fetchLeaderboard(period: 'DAILY' | 'WEEKLY' | 'MONTHLY' | 'ALL_TIME'): Promise<LeaderboardData> {
await this.delay(500);
return {
revenue: { rankings: this.generateRankings(10, 'revenue'), total: 100 },
roi: { rankings: this.generateRankings(10, 'roi'), total: 100 },
growth: { rankings: this.generateRankings(10, 'growth'), total: 100 },
period,
updatedAt: new Date().toISOString(),
};
}
async fetchMyRank(period: 'DAILY' | 'WEEKLY' | 'MONTHLY' | 'ALL_TIME'): Promise<MyRank> {
await this.delay(300);
return {
revenue: { rank: 15, percentile: 85 },
roi: { rank: 8, percentile: 92 },
growth: { rank: 22, percentile: 78 },
period,
};
}
}
export const leaderboardDataSource = DataSourceFactory.createWithMethods<
any,
any,
ILeaderboardDataSource
>({
apiDataSource: ApiLeaderboardDataSource,
mockDataSource: MockLeaderboardDataSource,
});
/**
* Mock状态标记
* 用于调试和开发环境识别
*/
export { __MOCK__, __DATA_SOURCE_TYPE__ } from './dataSourceFactory';