refactor(storage): move file management routes from user to admin namespace

- Remove file list, stats, download, and deletion routes from '/api/v1/upload'
- Move these endpoints under '/api/v1/admin/uploads'
- Remove user-specific filtering from files query and statistics to aggregate system-wide uploads by default
- Allow admins to bypass ownership check when downloading private files
- Update backend unit tests, Swagger documentation, and frontend service client and components
This commit is contained in:
ryan
2026-06-13 16:04:21 +08:00
parent dbabe8b8d7
commit 8b19ffed90
13 changed files with 908 additions and 818 deletions
@@ -80,8 +80,8 @@ export function FileList() {
// 文件列表查询
const listQuery = useQuery({
queryKey: ["files", "my", page, pageSize, debouncedKeyword],
queryFn: () => UploadService.listMyFiles(page, pageSize, debouncedKeyword || undefined),
queryKey: ["files", "all", page, pageSize, debouncedKeyword],
queryFn: () => UploadService.listUploads(page, pageSize, debouncedKeyword || undefined),
})
const files = listQuery.data?.items ?? []
+2 -2
View File
@@ -22,10 +22,10 @@ export function FilesMain() {
<div className="flex flex-col md:flex-row md:items-center justify-between gap-4 border-b pb-5">
<div>
<h1 className="text-xl font-bold tracking-tight bg-gradient-to-r from-foreground via-foreground/90 to-muted-foreground bg-clip-text text-transparent">
文件管理
存储管理
</h1>
<p className="text-sm text-muted-foreground">
管理您上传的所有文件,支持下载、数据统计与批量操作
管理系统存储的所有文件,支持下载、数据统计与批量操作
</p>
</div>
</div>
+1 -1
View File
@@ -71,8 +71,8 @@ const data = {
],
admin: [
{ title: "用户管理", url: "/admin/users", icon: UserRound },
{ title: "文件管理", url: "/admin/files", icon: FolderOpen },
{ title: "任务管理", url: "/admin/tasks", icon: Layers },
{ title: "存储管理", url: "/admin/files", icon: FolderOpen },
{ title: "数据管理", url: "/admin/database", icon: Database },
{ title: "系统日志", url: "/admin/logs", icon: Terminal },
{ title: "系统配置", url: "/admin/system", icon: ShieldCheck },
@@ -1,6 +1,7 @@
import {BaseService} from '../core/base.service'
import type {ListUploadsResponse, Upload, UploadImageResponse, FileStatsResponse} from './types'
import type {InternalAxiosRequestConfig} from 'axios'
import apiClient from '../core/api-client'
export type ImageQuality = 'low' | 'medium' | 'high' | 'origin'
@@ -35,7 +36,7 @@ export function formatFileSize(bytes: number): string {
* 处理文件上传相关的 API 请求
*/
export class UploadService extends BaseService {
protected static readonly basePath = '/api/v1/upload'
protected static readonly basePath = '/api/v1/admin/uploads'
/**
* 通用文件上传
@@ -59,20 +60,21 @@ export class UploadService extends BaseService {
formData.append('access_mode', String(accessMode))
}
return this.post<Upload>('', formData, {
const response = await apiClient.post<{ data: Upload }>('/api/v1/upload', formData, {
headers: { 'Content-Type': 'multipart/form-data' },
} as InternalAxiosRequestConfig)
return response.data.data
}
/**
* 获取我的文件列表
* 获取文件列表
* @param page - 页码(1-based)
* @param pageSize - 每页数量
* @param keyword - 搜索关键词(文件名模糊)
* @param type - 业务分类过滤
* @param extension - 扩展名过滤
*/
static async listMyFiles(
static async listUploads(
page = 1,
pageSize = 20,
keyword?: string,
@@ -83,7 +85,7 @@ export class UploadService extends BaseService {
if (keyword) params.keyword = keyword
if (type) params.type = type
if (extension) params.extension = extension
return this.get<ListUploadsResponse>('/my', params)
return this.get<ListUploadsResponse>('', params)
}
/**
@@ -104,7 +106,7 @@ export class UploadService extends BaseService {
* 获取单文件下载 URL(触发 attachment 下载)
*/
static getDownloadUrl(id: string): string {
return `/api/v1/upload/download/${id}`
return `/api/v1/admin/uploads/download/${id}`
}
/**