feat(storage): implement user-group level file management dashboard and APIs

- Expose user-scoped CRUD APIs under `/api/v1/upload` (my files query, stats, rename, delete)
- Update backend handlers and routers with ownership validation checks
- Create a dedicated frontend personal file manager card-list and upload button under `/files`
- Add comprehensive backend test coverage and update API docs
This commit is contained in:
ryan
2026-06-13 16:14:22 +08:00
parent 8b19ffed90
commit 5b13d5b464
13 changed files with 1421 additions and 21 deletions
+1
View File
@@ -27,6 +27,7 @@ export interface Upload {
storage_driver: string
type: string
status: string
access_mode: number
metadata: UploadMetadata
created_at: string
updated_at: string
@@ -136,4 +136,54 @@ export class UploadService extends BaseService {
const result = await this.uploadFile(file, type, undefined, accessMode)
return { id: result.id }
}
/**
* 获取我的文件列表
*/
static async listMyUploads(
page = 1,
pageSize = 20,
keyword?: string,
type?: string,
extension?: string
): Promise<ListUploadsResponse> {
const params: Record<string, string | number> = { page, page_size: pageSize }
if (keyword) params.keyword = keyword
if (type) params.type = type
if (extension) params.extension = extension
const response = await apiClient.get<{ data: ListUploadsResponse }>('/api/v1/upload/my', {
params
} as InternalAxiosRequestConfig)
return response.data.data
}
/**
* 删除我的文件
*/
static async deleteMyFile(id: string): Promise<void> {
const response = await apiClient.delete<{ data: void }>(`/api/v1/upload/${id}`)
return response.data.data
}
/**
* 更新我的文件
*/
static async updateMyFile(id: string, fileName: string, accessMode?: number): Promise<Upload> {
const response = await apiClient.put<{ data: Upload }>(`/api/v1/upload/${id}`, {
file_name: fileName,
access_mode: accessMode
})
return response.data.data
}
/**
* 我的文件批量 ZIP 打包下载
*/
static async batchDownloadMyFiles(ids: string[]): Promise<Blob> {
const response = await apiClient.post<Blob>('/api/v1/upload/download/batch', { ids }, {
responseType: 'blob',
} as InternalAxiosRequestConfig)
return response.data
}
}