feat(web): 新增媒体库和轮播图 API client
媒体库(media.ts):文件列表/上传/更新/删除/移动/批量删除/裁剪 + 文件夹树形管理 轮播图(banners.ts):列表/创建/更新/删除/排序,字段与后端 DTO 完全对齐
This commit is contained in:
107
apps/web/src/api/health/banners.ts
Normal file
107
apps/web/src/api/health/banners.ts
Normal file
@@ -0,0 +1,107 @@
|
|||||||
|
import client from '../client';
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// 轮播图类型
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
export interface BannerItem {
|
||||||
|
id: string;
|
||||||
|
tenant_id: string;
|
||||||
|
media_item_id: string;
|
||||||
|
title?: string;
|
||||||
|
subtitle?: string;
|
||||||
|
link_type?: string;
|
||||||
|
link_target?: string;
|
||||||
|
sort_order: number;
|
||||||
|
status: string;
|
||||||
|
start_time?: string;
|
||||||
|
end_time?: string;
|
||||||
|
image_url?: string;
|
||||||
|
thumbnail_url?: string;
|
||||||
|
media_deleted: boolean;
|
||||||
|
created_at: string;
|
||||||
|
updated_at: string;
|
||||||
|
created_by?: string;
|
||||||
|
updated_by?: string;
|
||||||
|
version: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CreateBannerReq {
|
||||||
|
media_item_id: string;
|
||||||
|
title?: string;
|
||||||
|
subtitle?: string;
|
||||||
|
link_type?: string;
|
||||||
|
link_target?: string;
|
||||||
|
sort_order?: number;
|
||||||
|
status?: string;
|
||||||
|
start_time?: string;
|
||||||
|
end_time?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface UpdateBannerReq {
|
||||||
|
media_item_id?: string;
|
||||||
|
title?: string;
|
||||||
|
subtitle?: string;
|
||||||
|
link_type?: string;
|
||||||
|
link_target?: string;
|
||||||
|
sort_order?: number;
|
||||||
|
status?: string;
|
||||||
|
start_time?: string;
|
||||||
|
end_time?: string;
|
||||||
|
version: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SortBannerReq {
|
||||||
|
items: Array<{ id: string; sort_order: number }>;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// 轮播图 API
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
export const bannerApi = {
|
||||||
|
/** 获取轮播图列表(可按状态筛选) */
|
||||||
|
list: async (status?: string) => {
|
||||||
|
const { data } = await client.get<{
|
||||||
|
success: boolean;
|
||||||
|
data: BannerItem[];
|
||||||
|
}>('/health/banners', { params: status ? { status } : undefined });
|
||||||
|
return data.data;
|
||||||
|
},
|
||||||
|
|
||||||
|
/** 创建轮播图 */
|
||||||
|
create: async (req: CreateBannerReq) => {
|
||||||
|
const { data } = await client.post<{
|
||||||
|
success: boolean;
|
||||||
|
data: BannerItem;
|
||||||
|
}>('/health/banners', req);
|
||||||
|
return data.data;
|
||||||
|
},
|
||||||
|
|
||||||
|
/** 更新轮播图 */
|
||||||
|
update: async (id: string, req: UpdateBannerReq) => {
|
||||||
|
const { data } = await client.put<{
|
||||||
|
success: boolean;
|
||||||
|
data: BannerItem;
|
||||||
|
}>(`/health/banners/${id}`, req);
|
||||||
|
return data.data;
|
||||||
|
},
|
||||||
|
|
||||||
|
/** 删除轮播图 */
|
||||||
|
delete: async (id: string, version: number) => {
|
||||||
|
const { data } = await client.delete<{
|
||||||
|
success: boolean;
|
||||||
|
data: null;
|
||||||
|
}>(`/health/banners/${id}`, { data: { version } });
|
||||||
|
return data.data;
|
||||||
|
},
|
||||||
|
|
||||||
|
/** 轮播图排序 */
|
||||||
|
sort: async (req: SortBannerReq) => {
|
||||||
|
const { data } = await client.put<{
|
||||||
|
success: boolean;
|
||||||
|
data: null;
|
||||||
|
}>('/health/banners/sort', req);
|
||||||
|
return data.data;
|
||||||
|
},
|
||||||
|
};
|
||||||
208
apps/web/src/api/health/media.ts
Normal file
208
apps/web/src/api/health/media.ts
Normal file
@@ -0,0 +1,208 @@
|
|||||||
|
import client from '../client';
|
||||||
|
import type { PaginatedResponse } from '../types';
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// 媒体文件类型
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
export interface MediaItem {
|
||||||
|
id: string;
|
||||||
|
tenant_id: string;
|
||||||
|
folder_id?: string;
|
||||||
|
filename: string;
|
||||||
|
storage_path: string;
|
||||||
|
thumbnail_path?: string;
|
||||||
|
content_type: string;
|
||||||
|
file_size: number;
|
||||||
|
width?: number;
|
||||||
|
height?: number;
|
||||||
|
alt_text?: string;
|
||||||
|
is_public: boolean;
|
||||||
|
created_at: string;
|
||||||
|
updated_at: string;
|
||||||
|
created_by?: string;
|
||||||
|
updated_by?: string;
|
||||||
|
version: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface MediaListParams {
|
||||||
|
page?: number;
|
||||||
|
page_size?: number;
|
||||||
|
folder_id?: string;
|
||||||
|
content_type?: string;
|
||||||
|
keyword?: string;
|
||||||
|
is_public?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface UpdateMediaReq {
|
||||||
|
filename?: string;
|
||||||
|
alt_text?: string;
|
||||||
|
is_public?: boolean;
|
||||||
|
folder_id?: string;
|
||||||
|
version: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface MoveMediaReq {
|
||||||
|
folder_id?: string;
|
||||||
|
version: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CropReq {
|
||||||
|
x: number;
|
||||||
|
y: number;
|
||||||
|
width: number;
|
||||||
|
height: number;
|
||||||
|
version: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// 文件夹类型
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
export interface FolderItem {
|
||||||
|
id: string;
|
||||||
|
tenant_id: string;
|
||||||
|
name: string;
|
||||||
|
parent_id?: string;
|
||||||
|
sort_order: number;
|
||||||
|
children: FolderItem[];
|
||||||
|
item_count: number;
|
||||||
|
created_at: string;
|
||||||
|
updated_at: string;
|
||||||
|
version: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CreateFolderReq {
|
||||||
|
name: string;
|
||||||
|
parent_id?: string;
|
||||||
|
sort_order?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface UpdateFolderReq {
|
||||||
|
name?: string;
|
||||||
|
parent_id?: string;
|
||||||
|
sort_order?: number;
|
||||||
|
version: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// 媒体文件 API
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
export const mediaApi = {
|
||||||
|
/** 分页查询媒体文件列表 */
|
||||||
|
list: async (params: MediaListParams) => {
|
||||||
|
const { data } = await client.get<{
|
||||||
|
success: boolean;
|
||||||
|
data: PaginatedResponse<MediaItem>;
|
||||||
|
}>('/health/media', { params });
|
||||||
|
return data.data;
|
||||||
|
},
|
||||||
|
|
||||||
|
/** 上传媒体文件(multipart/form-data) */
|
||||||
|
upload: async (formData: FormData) => {
|
||||||
|
const { data } = await client.post<{
|
||||||
|
success: boolean;
|
||||||
|
data: MediaItem;
|
||||||
|
}>('/health/media/upload', formData, {
|
||||||
|
headers: { 'Content-Type': 'multipart/form-data' },
|
||||||
|
});
|
||||||
|
return data.data;
|
||||||
|
},
|
||||||
|
|
||||||
|
/** 获取单个媒体文件详情 */
|
||||||
|
get: async (id: string) => {
|
||||||
|
const { data } = await client.get<{
|
||||||
|
success: boolean;
|
||||||
|
data: MediaItem;
|
||||||
|
}>(`/health/media/${id}`);
|
||||||
|
return data.data;
|
||||||
|
},
|
||||||
|
|
||||||
|
/** 更新媒体文件信息 */
|
||||||
|
update: async (id: string, req: UpdateMediaReq) => {
|
||||||
|
const { data } = await client.put<{
|
||||||
|
success: boolean;
|
||||||
|
data: MediaItem;
|
||||||
|
}>(`/health/media/${id}`, req);
|
||||||
|
return data.data;
|
||||||
|
},
|
||||||
|
|
||||||
|
/** 删除媒体文件 */
|
||||||
|
delete: async (id: string, version: number) => {
|
||||||
|
const { data } = await client.delete<{
|
||||||
|
success: boolean;
|
||||||
|
data: null;
|
||||||
|
}>(`/health/media/${id}`, { data: { version } });
|
||||||
|
return data.data;
|
||||||
|
},
|
||||||
|
|
||||||
|
/** 移动媒体文件到指定文件夹 */
|
||||||
|
move: async (id: string, req: MoveMediaReq) => {
|
||||||
|
const { data } = await client.post<{
|
||||||
|
success: boolean;
|
||||||
|
data: MediaItem;
|
||||||
|
}>(`/health/media/${id}/move`, req);
|
||||||
|
return data.data;
|
||||||
|
},
|
||||||
|
|
||||||
|
/** 批量删除媒体文件 */
|
||||||
|
batchDelete: async (ids: string[]) => {
|
||||||
|
const { data } = await client.post<{
|
||||||
|
success: boolean;
|
||||||
|
data: null;
|
||||||
|
}>('/health/media/batch-delete', { ids });
|
||||||
|
return data.data;
|
||||||
|
},
|
||||||
|
|
||||||
|
/** 裁剪媒体文件 */
|
||||||
|
crop: async (id: string, req: CropReq) => {
|
||||||
|
const { data } = await client.post<{
|
||||||
|
success: boolean;
|
||||||
|
data: MediaItem;
|
||||||
|
}>(`/health/media/${id}/crop`, req);
|
||||||
|
return data.data;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// 文件夹 API
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
export const mediaFolderApi = {
|
||||||
|
/** 获取文件夹树形结构 */
|
||||||
|
tree: async () => {
|
||||||
|
const { data } = await client.get<{
|
||||||
|
success: boolean;
|
||||||
|
data: FolderItem[];
|
||||||
|
}>('/health/media-folders');
|
||||||
|
return data.data;
|
||||||
|
},
|
||||||
|
|
||||||
|
/** 创建文件夹 */
|
||||||
|
create: async (req: CreateFolderReq) => {
|
||||||
|
const { data } = await client.post<{
|
||||||
|
success: boolean;
|
||||||
|
data: FolderItem;
|
||||||
|
}>('/health/media-folders', req);
|
||||||
|
return data.data;
|
||||||
|
},
|
||||||
|
|
||||||
|
/** 更新文件夹 */
|
||||||
|
update: async (id: string, req: UpdateFolderReq) => {
|
||||||
|
const { data } = await client.put<{
|
||||||
|
success: boolean;
|
||||||
|
data: FolderItem;
|
||||||
|
}>(`/health/media-folders/${id}`, req);
|
||||||
|
return data.data;
|
||||||
|
},
|
||||||
|
|
||||||
|
/** 删除文件夹 */
|
||||||
|
delete: async (id: string, version: number) => {
|
||||||
|
const { data } = await client.delete<{
|
||||||
|
success: boolean;
|
||||||
|
data: null;
|
||||||
|
}>(`/health/media-folders/${id}`, { data: { version } });
|
||||||
|
return data.data;
|
||||||
|
},
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user