- Update food, outfits, props, home-decor pages and components - Add permissions page and sidebar updates - Update API client and all API modules (auth, food, dances, etc.) - Add card model migrations for optional fields - Update Django views, serializers, and authentication - Add affinity level migrations and user app updates - Add project documentation Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
118 lines
4.2 KiB
TypeScript
118 lines
4.2 KiB
TypeScript
import type { Achievement } from "./types"
|
|
import { apiClient } from "./client"
|
|
import type { PaginatedResponse, PaginationParams } from "./client"
|
|
|
|
// 将后端成就数据映射到前端 Achievement 类型
|
|
function mapBackendAchievement(a: any): Achievement {
|
|
// 后端 achievement_type → 前端 category 映射
|
|
const categoryMap: Record<string, Achievement["category"]> = {
|
|
login: "互动",
|
|
activity: "互动",
|
|
social: "互动",
|
|
usage: "收集",
|
|
special: "特殊",
|
|
hidden: "隐藏",
|
|
}
|
|
|
|
return {
|
|
id: String(a.id),
|
|
name: a.name,
|
|
description: a.description,
|
|
icon: undefined,
|
|
category: categoryMap[a.achievement_type] || "特殊",
|
|
requirement: a.conditions ? JSON.stringify(a.conditions) : "",
|
|
rewardType: "经验值",
|
|
rewardAmount: a.points || 0,
|
|
isHidden: a.is_hidden || false,
|
|
unlockRate: undefined,
|
|
createdAt: a.created_at ? a.created_at.split("T")[0] : "",
|
|
updatedAt: a.updated_at ? a.updated_at.split("T")[0] : "",
|
|
}
|
|
}
|
|
|
|
// 获取成就列表
|
|
export const getAchievements = async (params?: PaginationParams): Promise<PaginatedResponse<Achievement>> => {
|
|
const page = params?.page || 1
|
|
const pageSize = params?.pageSize || 10
|
|
const searchParam = params?.search ? `&search=${encodeURIComponent(params.search)}` : ""
|
|
|
|
const response = await apiClient.get(
|
|
`/achievement/achievements/?page=${page}&page_size=${pageSize}&show_hidden=true${searchParam}`
|
|
)
|
|
|
|
const data = response.data?.data || response.data
|
|
const results: any[] = data.results || data
|
|
const total = data.count || results.length
|
|
|
|
return {
|
|
items: results.map(mapBackendAchievement),
|
|
total,
|
|
page,
|
|
pageSize,
|
|
totalPages: Math.ceil(total / pageSize),
|
|
}
|
|
}
|
|
|
|
// 获取单个成就
|
|
export const getAchievement = async (id: string): Promise<Achievement> => {
|
|
const response = await apiClient.get(`/achievement/achievements/${id}/`)
|
|
const data = response.data?.data || response.data
|
|
return mapBackendAchievement(data)
|
|
}
|
|
|
|
// 创建成就(需要管理员权限)
|
|
export const createAchievement = async (achievementData: Partial<Achievement>): Promise<Achievement> => {
|
|
const typeReverseMap: Record<string, string> = {
|
|
互动: "activity",
|
|
好感度: "activity",
|
|
收集: "usage",
|
|
探索: "activity",
|
|
特殊: "special",
|
|
隐藏: "hidden",
|
|
}
|
|
|
|
const payload = {
|
|
name: achievementData.name,
|
|
description: achievementData.description,
|
|
achievement_type: typeReverseMap[achievementData.category || "特殊"] || "special",
|
|
is_hidden: achievementData.isHidden || false,
|
|
points: achievementData.rewardAmount || 0,
|
|
rarity: "common",
|
|
conditions: achievementData.requirement ? { description: achievementData.requirement } : {},
|
|
}
|
|
|
|
const response = await apiClient.post(`/achievement/achievements/`, payload)
|
|
const data = response.data?.data || response.data
|
|
return mapBackendAchievement(data)
|
|
}
|
|
|
|
// 更新成就(需要管理员权限)
|
|
export const updateAchievement = async (id: string, achievementData: Partial<Achievement>): Promise<Achievement> => {
|
|
const typeReverseMap: Record<string, string> = {
|
|
互动: "activity",
|
|
好感度: "activity",
|
|
收集: "usage",
|
|
探索: "activity",
|
|
特殊: "special",
|
|
隐藏: "hidden",
|
|
}
|
|
|
|
const payload: any = {}
|
|
if (achievementData.name !== undefined) payload.name = achievementData.name
|
|
if (achievementData.description !== undefined) payload.description = achievementData.description
|
|
if (achievementData.category !== undefined) payload.achievement_type = typeReverseMap[achievementData.category] || "special"
|
|
if (achievementData.isHidden !== undefined) payload.is_hidden = achievementData.isHidden
|
|
if (achievementData.rewardAmount !== undefined) payload.points = achievementData.rewardAmount
|
|
if (achievementData.requirement !== undefined) payload.conditions = { description: achievementData.requirement }
|
|
|
|
const response = await apiClient.patch(`/achievement/achievements/${id}/`, payload)
|
|
const data = response.data?.data || response.data
|
|
return mapBackendAchievement(data)
|
|
}
|
|
|
|
// 删除成就(需要管理员权限)
|
|
export const deleteAchievement = async (id: string): Promise<boolean> => {
|
|
await apiClient.delete(`/achievement/achievements/${id}/`)
|
|
return true
|
|
}
|