lty/qy-lty-admin/lib/api/client.ts
pmc bd95ba470c feat: update admin panel, API modules, and add migrations
- 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>
2026-03-20 13:06:50 +08:00

272 lines
6.9 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// 基础API客户端配置
import axios from 'axios';
/**
* 基础API路径 - 从环境变量获取
* 环境变量配置文件优先级:
* .env.local > .env.development (开发环境) / .env.production (生产环境) > .env
*/
export const API_BASE_URL = process.env.NEXT_PUBLIC_API_BASE_URL || "http://localhost:8000/api"
// 创建API客户端实例
export const apiClient = axios.create({
baseURL: API_BASE_URL,
headers: {
'Content-Type': 'application/json',
},
});
// 添加请求拦截器,自动为请求添加认证令牌
apiClient.interceptors.request.use((config) => {
if (typeof window !== 'undefined') {
const token = localStorage.getItem('auth_token');
console.log('🔍 Token检查:', token ? `存在 (${token.substring(0, 20)}...)` : '不存在');
if (token) {
config.headers.Authorization = `Bearer ${token}`;
console.log('✅ Token已添加到请求头');
} else {
console.warn('⚠️ 未找到auth_token请求将不包含认证');
}
} else {
console.log('🔍 服务端渲染环境跳过token检查');
}
console.log('📡 发送请求:', config.method?.toUpperCase(), config.url);
console.log('📋 请求头:', config.headers);
return config;
}, (error) => {
console.error('❌ 请求拦截器错误:', error);
return Promise.reject(error);
});
// 添加响应拦截器,用于处理认证错误
apiClient.interceptors.response.use(
(response) => {
console.log('✅ 响应成功:', response.status, response.config.url);
return response;
},
(error) => {
console.error('❌ 响应错误:', error.response?.status, error.config?.url);
// 处理401未授权错误token过期或无效
if (error.response?.status === 401) {
console.warn('🚫 认证失败token可能过期或无效');
console.log('响应详情:', error.response?.data);
localStorage.removeItem('auth_token');
if (typeof window !== 'undefined' && window.location.pathname !== '/login') {
window.location.href = '/login';
}
}
return Promise.reject(error);
}
);
// 模拟网络延迟
export const simulateDelay = async (minMs = 300, maxMs = 800) => {
const delay = Math.floor(Math.random() * (maxMs - minMs + 1)) + minMs
await new Promise((resolve) => setTimeout(resolve, delay))
}
// 模拟API响应
export const mockResponse = async <T>(data: T, error?: string) => {
await simulateDelay()
// 随机模拟错误概率约5%
if (!error && Math.random() < 0.05) {
throw new Error("模拟随机网络错误,请重试")
}
// 如果提供了错误信息,则抛出错误
if (error) {
throw new Error(error)
}
return data
}
// API响应类型
export interface ApiResponse<T> {
success: boolean;
code: number;
message: string;
data: T;
}
// 分页响应类型
export interface PaginatedResponse<T> {
items: T[];
total: number;
page: number;
pageSize: number;
totalPages: number;
}
// 分页请求参数
export interface PaginationParams {
page?: number;
pageSize?: number;
search?: string;
}
// 获取当前环境
export const getCurrentEnvironment = (): 'development' | 'production' | 'test' => {
return (process.env.NODE_ENV as 'development' | 'production' | 'test') || 'development'
}
// 判断是否为开发环境
export const isDevelopment = (): boolean => getCurrentEnvironment() === 'development'
// 判断是否为生产环境
export const isProduction = (): boolean => getCurrentEnvironment() === 'production'
// 模拟用户数据
export const mockUsers = [
{
id: "1",
name: "管理员",
email: "admin@example.com",
role: "超级管理员",
status: "活跃",
registeredAt: "2023-01-01",
lastLogin: "今天 08:45",
phone: "13800138000",
address: "北京市海淀区中关村",
permissions: [
"仪表盘查看",
"用户管理",
"角色权限管理",
"AI模型管理",
"服装管理",
"道具管理",
"歌曲管理",
"系统设置",
],
loginHistory: [
{ date: "2023-05-15 08:45", ip: "192.168.1.1", device: "Chrome / Windows" },
{ date: "2023-05-14 15:30", ip: "192.168.1.1", device: "Chrome / Windows" },
{ date: "2023-05-13 09:20", ip: "192.168.1.1", device: "Chrome / Windows" },
],
},
{
id: "2",
name: "张三",
email: "zhangsan@example.com",
role: "内容管理员",
status: "活跃",
registeredAt: "2023-03-15",
lastLogin: "昨天 16:30",
phone: "13900139000",
permissions: ["仪表盘查看", "服装管理", "道具管理", "歌曲管理"],
loginHistory: [
{ date: "2023-05-14 16:30", ip: "192.168.1.2", device: "Safari / macOS" },
{ date: "2023-05-13 14:20", ip: "192.168.1.2", device: "Safari / macOS" },
],
},
{
id: "3",
name: "李四",
email: "lisi@example.com",
role: "AI模型管理员",
status: "活跃",
registeredAt: "2023-05-20",
lastLogin: "3天前",
permissions: ["仪表盘查看", "AI模型管理"],
loginHistory: [{ date: "2023-05-12 10:15", ip: "192.168.1.3", device: "Firefox / Ubuntu" }],
},
{
id: "4",
name: "王五",
email: "wangwu@example.com",
role: "卡牌管理员",
status: "活跃",
registeredAt: "2023-07-10",
lastLogin: "1周前",
permissions: ["仪表盘查看", "服装管理", "道具管理", "家居装饰管理"],
},
{
id: "5",
name: "赵六",
email: "zhaoliu@example.com",
role: "查看者",
status: "未激活",
registeredAt: "2023-09-05",
permissions: ["仪表盘查看"],
},
]
// 模拟角色数据
export const mockRoles = [
{
id: "1",
name: "超级管理员",
description: "拥有系统所有权限",
userCount: 1,
createdAt: "2023-01-01",
status: "系统角色",
permissions: {
dashboard: true,
users: true,
roles: true,
ai_models: true,
outfits: true,
props: true,
songs: true,
settings: true,
},
},
{
id: "2",
name: "内容管理员",
description: "管理系统内容",
userCount: 2,
createdAt: "2023-01-15",
status: "系统角色",
permissions: {
dashboard: true,
outfits: true,
props: true,
songs: true,
},
},
{
id: "3",
name: "AI模型管理员",
description: "管理AI模型",
userCount: 1,
createdAt: "2023-02-10",
status: "系统角色",
permissions: {
dashboard: true,
ai_models: true,
},
},
{
id: "4",
name: "卡牌管理员",
description: "管理卡牌内容",
userCount: 1,
createdAt: "2023-03-05",
status: "自定义角色",
permissions: {
dashboard: true,
outfits: true,
props: true,
home_decor: true,
},
},
{
id: "5",
name: "查看者",
description: "只能查看仪表盘",
userCount: 1,
createdAt: "2023-04-20",
status: "自定义角色",
permissions: {
dashboard: true,
},
},
]