- 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>
122 lines
4.0 KiB
TypeScript
122 lines
4.0 KiB
TypeScript
import type { Dance } from "./types"
|
|
import { apiClient } from "./client"
|
|
import { handleApiError } from "./error-handler"
|
|
|
|
// 将后端 CardTemplate(dance) 数据映射到前端 Dance 类型
|
|
function mapBackendDance(item: any): Dance {
|
|
const attrs = item.attributes || {}
|
|
return {
|
|
id: String(item.id),
|
|
name: item.name,
|
|
choreographer: attrs.choreographer || "",
|
|
duration: attrs.duration || "",
|
|
difficulty: attrs.difficulty || "",
|
|
videoUrl: attrs.tutorial_video || item.model_url || "",
|
|
coverUrl: item.image_url || "/placeholder.svg?height=300&width=400",
|
|
description: item.description || "",
|
|
motionFile: item.model_url || "",
|
|
category: attrs.style || "",
|
|
tags: [],
|
|
createdAt: item.created_at || "",
|
|
updatedAt: item.updated_at || "",
|
|
}
|
|
}
|
|
|
|
// 获取舞蹈列表
|
|
export async function getDances(page = 1, limit = 10, search = "") {
|
|
try {
|
|
const searchParam = search ? `&search=${encodeURIComponent(search)}` : ""
|
|
const response = await apiClient.get(
|
|
`/card/category/dance/?page=${page}&page_size=${limit}${searchParam}`
|
|
)
|
|
|
|
const data = response.data?.data || response.data
|
|
const results: any[] = data.results || data
|
|
const total = data.count || results.length
|
|
|
|
return {
|
|
data: results.map(mapBackendDance),
|
|
pagination: {
|
|
page,
|
|
limit,
|
|
totalItems: total,
|
|
totalPages: Math.ceil(total / limit),
|
|
},
|
|
}
|
|
} catch (error) {
|
|
return handleApiError(error)
|
|
}
|
|
}
|
|
|
|
// 获取单个舞蹈详情
|
|
export async function getDance(id: string) {
|
|
try {
|
|
const response = await apiClient.get(`/card/templates/${id}/`)
|
|
const data = response.data?.data || response.data
|
|
return { data: mapBackendDance(data) }
|
|
} catch (error) {
|
|
return handleApiError(error)
|
|
}
|
|
}
|
|
|
|
// 创建新舞蹈(需要管理员权限)
|
|
export async function createDance(danceData: Omit<Dance, "id" | "createdAt" | "updatedAt">) {
|
|
try {
|
|
const payload: any = {
|
|
name: danceData.name,
|
|
category: "dance",
|
|
description: danceData.description || "",
|
|
dance_attributes: {
|
|
choreographer: danceData.choreographer || "",
|
|
duration: danceData.duration || "",
|
|
difficulty: danceData.difficulty || "",
|
|
tutorial_video: danceData.videoUrl || "",
|
|
style: danceData.category || "",
|
|
},
|
|
}
|
|
if (danceData.coverUrl && !danceData.coverUrl.includes("placeholder")) {
|
|
payload.image_url = danceData.coverUrl
|
|
}
|
|
|
|
const response = await apiClient.post(`/card/templates/`, payload)
|
|
const data = response.data?.data || response.data
|
|
return { data: mapBackendDance(data) }
|
|
} catch (error) {
|
|
return handleApiError(error)
|
|
}
|
|
}
|
|
|
|
// 更新舞蹈(需要管理员权限)
|
|
export async function updateDance(id: string, danceData: Partial<Dance>) {
|
|
try {
|
|
const payload: any = {}
|
|
if (danceData.name !== undefined) payload.name = danceData.name
|
|
if (danceData.description !== undefined) payload.description = danceData.description
|
|
|
|
const attrs: any = {}
|
|
if (danceData.choreographer !== undefined) attrs.choreographer = danceData.choreographer
|
|
if (danceData.duration !== undefined) attrs.duration = danceData.duration
|
|
if (danceData.difficulty !== undefined) attrs.difficulty = danceData.difficulty
|
|
if (danceData.videoUrl !== undefined) attrs.tutorial_video = danceData.videoUrl
|
|
if (danceData.category !== undefined) attrs.style = danceData.category
|
|
if (Object.keys(attrs).length > 0) payload.dance_attributes = attrs
|
|
if (danceData.coverUrl !== undefined) payload.image_url = danceData.coverUrl
|
|
|
|
const response = await apiClient.patch(`/card/templates/${id}/`, payload)
|
|
const data = response.data?.data || response.data
|
|
return { data: mapBackendDance(data) }
|
|
} catch (error) {
|
|
return handleApiError(error)
|
|
}
|
|
}
|
|
|
|
// 删除舞蹈(需要管理员权限)
|
|
export async function deleteDance(id: string) {
|
|
try {
|
|
await apiClient.delete(`/card/templates/${id}/`)
|
|
return { data: { id } }
|
|
} catch (error) {
|
|
return handleApiError(error)
|
|
}
|
|
}
|