feat(health): 线下活动管理端 CRUD + 积分统计 API + 前端页面 (Chunk 4)
后端: - 线下活动管理: create/update/delete/list/checkin 5 个管理端接口 - 活动签到自动发放积分 (事务内原子操作) - 积分统计 API: 总发放/总消耗/总过期/活跃账户/Top10排行 前端: - OfflineEventList: 活动管理页面 (创建/编辑/删除/状态筛选) - points.ts 扩展: 线下活动 + 统计 API 方法 - 侧边栏新增线下活动入口
This commit is contained in:
@@ -75,6 +75,49 @@ export interface VerifyOrderReq {
|
||||
qr_code: string;
|
||||
}
|
||||
|
||||
export interface OfflineEvent {
|
||||
id: string;
|
||||
title: string;
|
||||
description: string | null;
|
||||
event_date: string;
|
||||
start_time: string | null;
|
||||
end_time: string | null;
|
||||
location: string | null;
|
||||
points_reward: number;
|
||||
max_participants: number;
|
||||
current_participants: number;
|
||||
status: string; // draft / published / ongoing / completed / cancelled
|
||||
image_url: string | null;
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
version: number;
|
||||
}
|
||||
|
||||
export interface CreateOfflineEventReq {
|
||||
title: string;
|
||||
description?: string;
|
||||
event_date: string;
|
||||
start_time?: string;
|
||||
end_time?: string;
|
||||
location?: string;
|
||||
points_reward?: number;
|
||||
max_participants?: number;
|
||||
status?: string;
|
||||
image_url?: string;
|
||||
}
|
||||
|
||||
export interface PointsStatistics {
|
||||
total_issued: number;
|
||||
total_spent: number;
|
||||
total_expired: number;
|
||||
active_accounts: number;
|
||||
top_earners: Array<{
|
||||
account_id: string;
|
||||
patient_id: string;
|
||||
total_earned: number;
|
||||
}>;
|
||||
}
|
||||
|
||||
// --- API ---
|
||||
|
||||
export const pointsApi = {
|
||||
@@ -128,4 +171,44 @@ export const pointsApi = {
|
||||
}>('/health/points/verify', req);
|
||||
return data.data;
|
||||
},
|
||||
|
||||
// Offline Events
|
||||
listOfflineEvents: async (params?: Record<string, unknown>) => {
|
||||
const { data } = await client.get<{
|
||||
success: boolean;
|
||||
data: PaginatedResponse<OfflineEvent>;
|
||||
}>('/health/admin/offline-events', { params });
|
||||
return data.data;
|
||||
},
|
||||
|
||||
createOfflineEvent: async (req: CreateOfflineEventReq) => {
|
||||
const { data } = await client.post<{
|
||||
success: boolean;
|
||||
data: OfflineEvent;
|
||||
}>('/health/admin/offline-events', req);
|
||||
return data.data;
|
||||
},
|
||||
|
||||
updateOfflineEvent: async (id: string, req: Partial<CreateOfflineEventReq> & { version: number }) => {
|
||||
const { data } = await client.put<{
|
||||
success: boolean;
|
||||
data: OfflineEvent;
|
||||
}>(`/health/admin/offline-events/${id}`, req);
|
||||
return data.data;
|
||||
},
|
||||
|
||||
deleteOfflineEvent: async (id: string, version: number) => {
|
||||
await client.delete(`/health/admin/offline-events/${id}`, {
|
||||
data: { version },
|
||||
});
|
||||
},
|
||||
|
||||
// Points Statistics
|
||||
getStatistics: async () => {
|
||||
const { data } = await client.get<{
|
||||
success: boolean;
|
||||
data: PointsStatistics;
|
||||
}>('/health/admin/points/statistics');
|
||||
return data.data;
|
||||
},
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user