- 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>
139 lines
5.2 KiB
TypeScript
139 lines
5.2 KiB
TypeScript
import type { AffinityRule, AffinityLevel } from "./types"
|
|
import { apiClient } from "./client"
|
|
import type { PaginatedResponse, PaginationParams } from "./client"
|
|
|
|
// 将后端 AffinityRule 数据映射到前端类型
|
|
function mapBackendRule(r: any): AffinityRule {
|
|
return {
|
|
id: String(r.id),
|
|
action: r.name,
|
|
points: r.points || 0,
|
|
description: r.description || "",
|
|
dailyLimit: r.daily_limit ?? undefined,
|
|
}
|
|
}
|
|
|
|
// 将后端 AffinityLevel 数据映射到前端类型
|
|
function mapBackendLevel(l: any): AffinityLevel {
|
|
return {
|
|
id: String(l.id),
|
|
level: l.level,
|
|
name: l.name,
|
|
description: l.description || "",
|
|
requiredPoints: l.required_points,
|
|
rewards: Array.isArray(l.rewards) ? l.rewards : [],
|
|
}
|
|
}
|
|
|
|
// ── 好感度规则 ────────────────────────────────────────────
|
|
|
|
export const getAffinityRules = async (params?: PaginationParams): Promise<PaginatedResponse<AffinityRule>> => {
|
|
const page = params?.page || 1
|
|
const pageSize = params?.pageSize || 10
|
|
|
|
const response = await apiClient.get(`/user/affinity-rules/?page=${page}&page_size=${pageSize}`)
|
|
const data = response.data?.data || response.data
|
|
const results: any[] = data.results || (Array.isArray(data) ? data : [])
|
|
const total = data.count || results.length
|
|
|
|
return {
|
|
items: results.map(mapBackendRule),
|
|
total,
|
|
page,
|
|
pageSize,
|
|
totalPages: Math.ceil(total / pageSize),
|
|
}
|
|
}
|
|
|
|
export const getAffinityRule = async (id: string): Promise<AffinityRule> => {
|
|
const response = await apiClient.get(`/user/affinity-rules/${id}/`)
|
|
const data = response.data?.data || response.data
|
|
return mapBackendRule(data)
|
|
}
|
|
|
|
export const createAffinityRule = async (ruleData: Partial<AffinityRule>): Promise<AffinityRule> => {
|
|
const payload = {
|
|
name: ruleData.action,
|
|
description: ruleData.description || "",
|
|
points: ruleData.points || 0,
|
|
daily_limit: ruleData.dailyLimit ?? null,
|
|
is_active: true,
|
|
}
|
|
const response = await apiClient.post(`/user/affinity-rules/`, payload)
|
|
const data = response.data?.data || response.data
|
|
return mapBackendRule(data)
|
|
}
|
|
|
|
export const updateAffinityRule = async (id: string, ruleData: Partial<AffinityRule>): Promise<AffinityRule> => {
|
|
const payload: any = {}
|
|
if (ruleData.action !== undefined) payload.name = ruleData.action
|
|
if (ruleData.description !== undefined) payload.description = ruleData.description
|
|
if (ruleData.points !== undefined) payload.points = ruleData.points
|
|
if (ruleData.dailyLimit !== undefined) payload.daily_limit = ruleData.dailyLimit
|
|
|
|
const response = await apiClient.patch(`/user/affinity-rules/${id}/`, payload)
|
|
const data = response.data?.data || response.data
|
|
return mapBackendRule(data)
|
|
}
|
|
|
|
export const deleteAffinityRule = async (id: string): Promise<boolean> => {
|
|
await apiClient.delete(`/user/affinity-rules/${id}/`)
|
|
return true
|
|
}
|
|
|
|
// ── 好感度等级 ────────────────────────────────────────────
|
|
|
|
export const getAffinityLevels = async (params?: PaginationParams): Promise<PaginatedResponse<AffinityLevel>> => {
|
|
const page = params?.page || 1
|
|
const pageSize = params?.pageSize || 50 // 等级数量通常较少,一次全取
|
|
|
|
const response = await apiClient.get(`/user/affinity-levels/?page=${page}&page_size=${pageSize}`)
|
|
const data = response.data?.data || response.data
|
|
const results: any[] = data.results || (Array.isArray(data) ? data : [])
|
|
const total = data.count || results.length
|
|
|
|
return {
|
|
items: results.map(mapBackendLevel),
|
|
total,
|
|
page,
|
|
pageSize,
|
|
totalPages: Math.ceil(total / pageSize),
|
|
}
|
|
}
|
|
|
|
export const getAffinityLevel = async (id: string): Promise<AffinityLevel> => {
|
|
const response = await apiClient.get(`/user/affinity-levels/${id}/`)
|
|
const data = response.data?.data || response.data
|
|
return mapBackendLevel(data)
|
|
}
|
|
|
|
export const createAffinityLevel = async (levelData: Partial<AffinityLevel>): Promise<AffinityLevel> => {
|
|
const payload = {
|
|
level: levelData.level,
|
|
name: levelData.name,
|
|
description: levelData.description || "",
|
|
required_points: levelData.requiredPoints || 0,
|
|
rewards: levelData.rewards || [],
|
|
}
|
|
const response = await apiClient.post(`/user/affinity-levels/`, payload)
|
|
const data = response.data?.data || response.data
|
|
return mapBackendLevel(data)
|
|
}
|
|
|
|
export const updateAffinityLevel = async (id: string, levelData: Partial<AffinityLevel>): Promise<AffinityLevel> => {
|
|
const payload: any = {}
|
|
if (levelData.name !== undefined) payload.name = levelData.name
|
|
if (levelData.description !== undefined) payload.description = levelData.description
|
|
if (levelData.requiredPoints !== undefined) payload.required_points = levelData.requiredPoints
|
|
if (levelData.rewards !== undefined) payload.rewards = levelData.rewards
|
|
|
|
const response = await apiClient.patch(`/user/affinity-levels/${id}/`, payload)
|
|
const data = response.data?.data || response.data
|
|
return mapBackendLevel(data)
|
|
}
|
|
|
|
export const deleteAffinityLevel = async (id: string): Promise<boolean> => {
|
|
await apiClient.delete(`/user/affinity-levels/${id}/`)
|
|
return true
|
|
}
|