diff --git a/internal/http/request/file.go b/internal/http/request/file.go index 6656e19b..ded15afc 100644 --- a/internal/http/request/file.go +++ b/internal/http/request/file.go @@ -73,6 +73,7 @@ type ChunkUploadStart struct { FileName string `json:"file_name" validate:"required"` // 文件名 FileHash string `json:"file_hash" validate:"required|len:64"` // 文件SHA256 ChunkCount int `json:"chunk_count" validate:"required|min:1"` // 分块总数 + Force bool `json:"force"` // 是否覆盖已存在文件 } // ChunkUploadFinish 分块上传完成请求 @@ -81,4 +82,5 @@ type ChunkUploadFinish struct { FileName string `json:"file_name" validate:"required"` // 文件名 FileHash string `json:"file_hash" validate:"required|len:64"` // 文件SHA256 ChunkCount int `json:"chunk_count" validate:"required|min:1"` // 分块总数 + Force bool `json:"force"` // 是否覆盖已存在文件 } diff --git a/internal/service/file.go b/internal/service/file.go index fb0c0b64..3dffd946 100644 --- a/internal/service/file.go +++ b/internal/service/file.go @@ -155,12 +155,13 @@ func (s *FileService) Upload(w http.ResponseWriter, r *http.Request) { } path := r.FormValue("path") + force := r.FormValue("force") == "true" _, handler, err := r.FormFile("file") if err != nil { Error(w, http.StatusInternalServerError, s.t.Get("upload file error: %v", err)) return } - if io.Exists(path) { + if io.Exists(path) && !force { Error(w, http.StatusForbidden, s.t.Get("target path %s already exists", path)) return } @@ -565,7 +566,7 @@ func (s *FileService) ChunkUploadStart(w http.ResponseWriter, r *http.Request) { } targetPath := filepath.Join(req.Path, req.FileName) - if io.Exists(targetPath) { + if io.Exists(targetPath) && !req.Force { Error(w, http.StatusForbidden, s.t.Get("target path %s already exists", targetPath)) return } @@ -680,7 +681,7 @@ func (s *FileService) ChunkUploadFinish(w http.ResponseWriter, r *http.Request) targetPath := filepath.Join(req.Path, req.FileName) // 检查目标文件是否已存在 - if io.Exists(targetPath) { + if io.Exists(targetPath) && !req.Force { Error(w, http.StatusForbidden, s.t.Get("target path %s already exists", targetPath)) return } diff --git a/web/src/api/panel/file/index.ts b/web/src/api/panel/file/index.ts index 0950dc32..f2d0e1c2 100644 --- a/web/src/api/panel/file/index.ts +++ b/web/src/api/panel/file/index.ts @@ -10,8 +10,7 @@ export default { // 删除文件 delete: (path: string): any => http.Post('/file/delete', { path }), // 上传文件 - upload: (formData: FormData): any => - http.Post('/file/upload', formData, { meta: { noAlert: true } }), + upload: (formData: FormData): any => http.Post('/file/upload', formData), // 检查文件是否存在 exist: (paths: string[]): any => http.Post('/file/exist', paths), // 移动文件 @@ -48,15 +47,16 @@ export default { file_name: string file_hash: string chunk_count: number + force?: boolean }): any => http.Post('/file/chunk/start', data), // 上传分块 - chunkUpload: (formData: FormData): any => - http.Post('/file/chunk/upload', formData, { meta: { noAlert: true } }), + chunkUpload: (formData: FormData): any => http.Post('/file/chunk/upload', formData), // 完成分块上传 chunkFinish: (data: { path: string file_name: string file_hash: string chunk_count: number + force?: boolean }): any => http.Post('/file/chunk/finish', data) } diff --git a/web/src/locales/en.po b/web/src/locales/en.po index 8b64511d..e66d38a2 100644 --- a/web/src/locales/en.po +++ b/web/src/locales/en.po @@ -4618,6 +4618,10 @@ msgstr "There are items with the same name. Do you want to overwrite?" msgid "Overwrite" msgstr "Overwrite" +#: src/views/file/UploadModal.vue +msgid "Overwrite existing files" +msgstr "Overwrite existing files" + #: src/views/file/ListView.vue:744 src/views/file/ListView.vue:763 msgid "Renamed %{ source } to %{ target } successfully" msgstr "Renamed %{ source } to %{ target } successfully" diff --git a/web/src/locales/frontend.pot b/web/src/locales/frontend.pot index 667fc728..df7de642 100644 --- a/web/src/locales/frontend.pot +++ b/web/src/locales/frontend.pot @@ -4705,6 +4705,10 @@ msgstr "" msgid "Overwrite" msgstr "" +#: src/views/file/UploadModal.vue +msgid "Overwrite existing files" +msgstr "" + #: src/views/file/ListView.vue:744 #: src/views/file/ListView.vue:763 msgid "Renamed %{ source } to %{ target } successfully" diff --git a/web/src/locales/zh_CN.po b/web/src/locales/zh_CN.po index 2865fc29..7b7e0b0c 100644 --- a/web/src/locales/zh_CN.po +++ b/web/src/locales/zh_CN.po @@ -4395,6 +4395,10 @@ msgstr "存在同名项目。您要覆盖吗?" msgid "Overwrite" msgstr "覆盖" +#: src/views/file/UploadModal.vue +msgid "Overwrite existing files" +msgstr "覆盖已存在的文件" + #: src/views/file/ListView.vue:744 src/views/file/ListView.vue:763 msgid "Renamed %{ source } to %{ target } successfully" msgstr "成功将 %{ source } 重命名为 %{ target }" diff --git a/web/src/locales/zh_TW.po b/web/src/locales/zh_TW.po index 4936a989..1312d287 100644 --- a/web/src/locales/zh_TW.po +++ b/web/src/locales/zh_TW.po @@ -4396,6 +4396,10 @@ msgstr "存在同名項目。您要覆蓋嗎?" msgid "Overwrite" msgstr "覆蓋" +#: src/views/file/UploadModal.vue +msgid "Overwrite existing files" +msgstr "覆蓋已存在的檔案" + #: src/views/file/ListView.vue:744 src/views/file/ListView.vue:763 msgid "Renamed %{ source } to %{ target } successfully" msgstr "成功將 %{ source } 重命名為 %{ target }" diff --git a/web/src/views/file/UploadModal.vue b/web/src/views/file/UploadModal.vue index 99284f2a..feb98cff 100644 --- a/web/src/views/file/UploadModal.vue +++ b/web/src/views/file/UploadModal.vue @@ -17,6 +17,9 @@ const props = defineProps<{ const upload = ref(null) const fileList = ref([]) +// 覆盖上传选项 +const forceOverwrite = ref(false) + // 文件数量阈值,超过此数量需要二次确认 const FILE_COUNT_THRESHOLD = 100 // 大文件阈值,超过此大小使用分块上传 (100MB) @@ -203,7 +206,8 @@ const chunkedUpload = async ( path: path.value, file_name: file.name, file_hash: fileHash, - chunk_count: chunkCount + chunk_count: chunkCount, + force: forceOverwrite.value }) task.activeRequests.push(startMethod) const startRes = await startMethod @@ -287,7 +291,8 @@ const chunkedUpload = async ( path: path.value, file_name: file.name, file_hash: fileHash, - chunk_count: chunkCount + chunk_count: chunkCount, + force: forceOverwrite.value }) task.activeRequests.push(finishMethod) await finishMethod @@ -390,6 +395,7 @@ const uploadRequest = ({ file, onFinish, onError, onProgress }: UploadCustomRequ const formData = new FormData() formData.append('path', `${path.value}/${file.name}`) formData.append('file', fileObj) + formData.append('force', forceOverwrite.value.toString()) const method = api.upload(formData) task.activeRequests.push(method) @@ -463,6 +469,10 @@ const handleChange = (data: { fileList: UploadFileInfo[] }) => { :segmented="false" > + + + {{ $gettext('Overwrite existing files') }} +