feat(challenges): 接入真实接口并完善挑战列表与详情状态管理
- 新增 challengesApi 服务层,支持列表/详情/加入/退出/打卡接口 - 重构 challengesSlice,使用 createAsyncThunk 管理异步状态 - 列表页支持加载、空态、错误重试及状态标签 - 详情页支持进度展示、打卡、退出及错误提示 - 统一卡片与详情数据模型,支持动态状态更新
This commit is contained in:
65
services/challengesApi.ts
Normal file
65
services/challengesApi.ts
Normal file
@@ -0,0 +1,65 @@
|
||||
import { api } from './api';
|
||||
|
||||
export type ChallengeStatus = 'upcoming' | 'ongoing' | 'expired';
|
||||
|
||||
export type ChallengeProgressDto = {
|
||||
completed: number;
|
||||
target: number;
|
||||
remaining: number;
|
||||
badge: string;
|
||||
subtitle?: string;
|
||||
};
|
||||
|
||||
export type RankingItemDto = {
|
||||
id: string;
|
||||
name: string;
|
||||
avatar: string | null;
|
||||
metric: string;
|
||||
badge?: string;
|
||||
};
|
||||
|
||||
export type ChallengeListItemDto = {
|
||||
id: string;
|
||||
title: string;
|
||||
image: string;
|
||||
periodLabel?: string;
|
||||
durationLabel: string;
|
||||
requirementLabel: string;
|
||||
status: ChallengeStatus;
|
||||
participantsCount: number;
|
||||
rankingDescription?: string;
|
||||
highlightTitle: string;
|
||||
highlightSubtitle: string;
|
||||
ctaLabel: string;
|
||||
progress?: ChallengeProgressDto;
|
||||
isJoined: boolean;
|
||||
startAt?: string;
|
||||
endAt?: string;
|
||||
};
|
||||
|
||||
export type ChallengeDetailDto = ChallengeListItemDto & {
|
||||
summary?: string;
|
||||
rankings: RankingItemDto[];
|
||||
userRank?: number;
|
||||
};
|
||||
|
||||
export async function listChallenges(): Promise<ChallengeListItemDto[]> {
|
||||
return api.get<ChallengeListItemDto[]>('/challenges');
|
||||
}
|
||||
|
||||
export async function getChallengeDetail(id: string): Promise<ChallengeDetailDto> {
|
||||
return api.get<ChallengeDetailDto>(`/challenges/${encodeURIComponent(id)}`);
|
||||
}
|
||||
|
||||
export async function joinChallenge(id: string): Promise<ChallengeProgressDto> {
|
||||
return api.post<ChallengeProgressDto>(`/challenges/${encodeURIComponent(id)}/join`);
|
||||
}
|
||||
|
||||
export async function leaveChallenge(id: string): Promise<boolean> {
|
||||
return api.post<boolean>(`/challenges/${encodeURIComponent(id)}/leave`);
|
||||
}
|
||||
|
||||
export async function reportChallengeProgress(id: string, increment?: number): Promise<ChallengeProgressDto> {
|
||||
const body = increment != null ? { increment } : undefined;
|
||||
return api.post<ChallengeProgressDto>(`/challenges/${encodeURIComponent(id)}/progress`, body);
|
||||
}
|
||||
Reference in New Issue
Block a user