forked from CarrotSkin/carrotskin
feat: 完成navbar隐藏优化和侧边栏冻结功能
- 优化navbar滚动隐藏逻辑,更敏感响应 - 添加返回顶部按钮,固定在右下角 - 实现profile页面侧边栏真正冻结效果 - 修复首页滑动指示器位置 - 优化整体布局确保首屏内容完整显示
This commit is contained in:
303
src/lib/api.ts
Normal file
303
src/lib/api.ts
Normal file
@@ -0,0 +1,303 @@
|
||||
const API_BASE_URL = process.env.NEXT_PUBLIC_API_BASE_URL || 'http://localhost:8080/api/v1';
|
||||
|
||||
export interface Texture {
|
||||
id: number;
|
||||
uploader_id: number;
|
||||
name: string;
|
||||
description?: string;
|
||||
type: 'SKIN' | 'CAPE';
|
||||
url: string;
|
||||
hash: string;
|
||||
size: number;
|
||||
is_public: boolean;
|
||||
download_count: number;
|
||||
favorite_count: number;
|
||||
is_slim: boolean;
|
||||
status: number;
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
}
|
||||
|
||||
export interface Profile {
|
||||
uuid: string;
|
||||
user_id: number;
|
||||
name: string;
|
||||
skin_id?: number;
|
||||
cape_id?: number;
|
||||
is_active: boolean;
|
||||
last_used_at?: string;
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
}
|
||||
|
||||
export interface PaginatedResponse<T> {
|
||||
list: T[];
|
||||
total: number;
|
||||
page: number;
|
||||
page_size: number;
|
||||
total_pages: number;
|
||||
}
|
||||
|
||||
export interface ApiResponse<T> {
|
||||
code: number;
|
||||
message: string;
|
||||
data: T;
|
||||
}
|
||||
|
||||
// 获取认证头
|
||||
function getAuthHeaders(): HeadersInit {
|
||||
const token = typeof window !== 'undefined' ? localStorage.getItem('authToken') : null;
|
||||
return {
|
||||
'Content-Type': 'application/json',
|
||||
...(token && { Authorization: `Bearer ${token}` }),
|
||||
};
|
||||
}
|
||||
|
||||
// 搜索材质
|
||||
export async function searchTextures(params: {
|
||||
keyword?: string;
|
||||
type?: 'SKIN' | 'CAPE';
|
||||
public_only?: boolean;
|
||||
page?: number;
|
||||
page_size?: number;
|
||||
}): Promise<ApiResponse<PaginatedResponse<Texture>>> {
|
||||
const queryParams = new URLSearchParams();
|
||||
if (params.keyword) queryParams.append('keyword', params.keyword);
|
||||
if (params.type) queryParams.append('type', params.type);
|
||||
if (params.public_only !== undefined) queryParams.append('public_only', String(params.public_only));
|
||||
if (params.page) queryParams.append('page', String(params.page));
|
||||
if (params.page_size) queryParams.append('page_size', String(params.page_size));
|
||||
|
||||
const response = await fetch(`${API_BASE_URL}/texture?${queryParams.toString()}`, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
});
|
||||
|
||||
return response.json();
|
||||
}
|
||||
|
||||
// 获取材质详情
|
||||
export async function getTexture(id: number): Promise<ApiResponse<Texture>> {
|
||||
const response = await fetch(`${API_BASE_URL}/texture/${id}`, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
});
|
||||
|
||||
return response.json();
|
||||
}
|
||||
|
||||
// 切换收藏状态
|
||||
export async function toggleFavorite(id: number): Promise<ApiResponse<{ is_favorited: boolean }>> {
|
||||
const response = await fetch(`${API_BASE_URL}/texture/${id}/favorite`, {
|
||||
method: 'POST',
|
||||
headers: getAuthHeaders(),
|
||||
});
|
||||
|
||||
return response.json();
|
||||
}
|
||||
|
||||
// 获取用户上传的材质列表
|
||||
export async function getMyTextures(params: {
|
||||
page?: number;
|
||||
page_size?: number;
|
||||
}): Promise<ApiResponse<PaginatedResponse<Texture>>> {
|
||||
const queryParams = new URLSearchParams();
|
||||
if (params.page) queryParams.append('page', String(params.page));
|
||||
if (params.page_size) queryParams.append('page_size', String(params.page_size));
|
||||
|
||||
const response = await fetch(`${API_BASE_URL}/texture/my?${queryParams.toString()}`, {
|
||||
method: 'GET',
|
||||
headers: getAuthHeaders(),
|
||||
});
|
||||
|
||||
return response.json();
|
||||
}
|
||||
|
||||
// 获取用户收藏的材质列表
|
||||
export async function getFavoriteTextures(params: {
|
||||
page?: number;
|
||||
page_size?: number;
|
||||
}): Promise<ApiResponse<PaginatedResponse<Texture>>> {
|
||||
const queryParams = new URLSearchParams();
|
||||
if (params.page) queryParams.append('page', String(params.page));
|
||||
if (params.page_size) queryParams.append('page_size', String(params.page_size));
|
||||
|
||||
const response = await fetch(`${API_BASE_URL}/texture/favorites?${queryParams.toString()}`, {
|
||||
method: 'GET',
|
||||
headers: getAuthHeaders(),
|
||||
});
|
||||
|
||||
return response.json();
|
||||
}
|
||||
|
||||
// 获取用户档案列表
|
||||
export async function getProfiles(): Promise<ApiResponse<Profile[]>> {
|
||||
const response = await fetch(`${API_BASE_URL}/profile`, {
|
||||
method: 'GET',
|
||||
headers: getAuthHeaders(),
|
||||
});
|
||||
|
||||
return response.json();
|
||||
}
|
||||
|
||||
// 创建档案
|
||||
export async function createProfile(name: string): Promise<ApiResponse<Profile>> {
|
||||
const response = await fetch(`${API_BASE_URL}/profile`, {
|
||||
method: 'POST',
|
||||
headers: getAuthHeaders(),
|
||||
body: JSON.stringify({ name }),
|
||||
});
|
||||
|
||||
return response.json();
|
||||
}
|
||||
|
||||
// 更新档案
|
||||
export async function updateProfile(uuid: string, data: {
|
||||
name?: string;
|
||||
skin_id?: number;
|
||||
cape_id?: number;
|
||||
}): Promise<ApiResponse<Profile>> {
|
||||
const response = await fetch(`${API_BASE_URL}/profile/${uuid}`, {
|
||||
method: 'PUT',
|
||||
headers: getAuthHeaders(),
|
||||
body: JSON.stringify(data),
|
||||
});
|
||||
|
||||
return response.json();
|
||||
}
|
||||
|
||||
// 删除档案
|
||||
export async function deleteProfile(uuid: string): Promise<ApiResponse<null>> {
|
||||
const response = await fetch(`${API_BASE_URL}/profile/${uuid}`, {
|
||||
method: 'DELETE',
|
||||
headers: getAuthHeaders(),
|
||||
});
|
||||
|
||||
return response.json();
|
||||
}
|
||||
|
||||
// 设置活跃档案
|
||||
export async function setActiveProfile(uuid: string): Promise<ApiResponse<{ message: string }>> {
|
||||
const response = await fetch(`${API_BASE_URL}/profile/${uuid}/activate`, {
|
||||
method: 'POST',
|
||||
headers: getAuthHeaders(),
|
||||
});
|
||||
|
||||
return response.json();
|
||||
}
|
||||
|
||||
// 获取用户信息
|
||||
export async function getUserProfile(): Promise<ApiResponse<{
|
||||
id: number;
|
||||
username: string;
|
||||
email: string;
|
||||
avatar?: string;
|
||||
points: number;
|
||||
role: string;
|
||||
status: number;
|
||||
last_login_at?: string;
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
}>> {
|
||||
const response = await fetch(`${API_BASE_URL}/user/profile`, {
|
||||
method: 'GET',
|
||||
headers: getAuthHeaders(),
|
||||
});
|
||||
|
||||
return response.json();
|
||||
}
|
||||
|
||||
// 更新用户信息
|
||||
export async function updateUserProfile(data: {
|
||||
avatar?: string;
|
||||
old_password?: string;
|
||||
new_password?: string;
|
||||
}): Promise<ApiResponse<{
|
||||
id: number;
|
||||
username: string;
|
||||
email: string;
|
||||
avatar?: string;
|
||||
points: number;
|
||||
role: string;
|
||||
status: number;
|
||||
last_login_at?: string;
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
}>> {
|
||||
const response = await fetch(`${API_BASE_URL}/user/profile`, {
|
||||
method: 'PUT',
|
||||
headers: getAuthHeaders(),
|
||||
body: JSON.stringify(data),
|
||||
});
|
||||
|
||||
return response.json();
|
||||
}
|
||||
|
||||
// 直接上传皮肤文件
|
||||
export async function uploadTexture(file: File, data: {
|
||||
name: string;
|
||||
description?: string;
|
||||
type?: 'SKIN' | 'CAPE';
|
||||
is_public?: boolean;
|
||||
is_slim?: boolean;
|
||||
}): Promise<ApiResponse<Texture>> {
|
||||
const formData = new FormData();
|
||||
formData.append('file', file);
|
||||
formData.append('name', data.name);
|
||||
if (data.description) formData.append('description', data.description);
|
||||
if (data.type) formData.append('type', data.type);
|
||||
if (data.is_public !== undefined) formData.append('is_public', String(data.is_public));
|
||||
if (data.is_slim !== undefined) formData.append('is_slim', String(data.is_slim));
|
||||
|
||||
const response = await fetch(`${API_BASE_URL}/texture/upload`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
...(typeof window !== 'undefined' ? { Authorization: `Bearer ${localStorage.getItem('authToken')}` } : {}),
|
||||
},
|
||||
body: formData,
|
||||
});
|
||||
|
||||
return response.json();
|
||||
}
|
||||
|
||||
// 生成头像上传URL
|
||||
export async function generateAvatarUploadUrl(fileName: string): Promise<ApiResponse<{
|
||||
post_url: string;
|
||||
form_data: Record<string, string>;
|
||||
avatar_url: string;
|
||||
expires_in: number;
|
||||
}>> {
|
||||
const response = await fetch(`${API_BASE_URL}/user/avatar/upload-url`, {
|
||||
method: 'POST',
|
||||
headers: getAuthHeaders(),
|
||||
body: JSON.stringify({ file_name: fileName }),
|
||||
});
|
||||
|
||||
return response.json();
|
||||
}
|
||||
|
||||
// 更新头像URL
|
||||
export async function updateAvatarUrl(avatarUrl: string): Promise<ApiResponse<{
|
||||
id: number;
|
||||
username: string;
|
||||
email: string;
|
||||
avatar: string;
|
||||
points: number;
|
||||
role: string;
|
||||
status: number;
|
||||
last_login_at?: string;
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
}>> {
|
||||
const response = await fetch(`${API_BASE_URL}/user/avatar?avatar_url=${encodeURIComponent(avatarUrl)}`, {
|
||||
method: 'PUT',
|
||||
headers: getAuthHeaders(),
|
||||
});
|
||||
|
||||
return response.json();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user