From 0c65edfa6fbe36b5d23882e1587f6cde9baf36d7 Mon Sep 17 00:00:00 2001 From: zhx Date: Tue, 2 Jun 2026 18:22:36 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E7=A4=BC=E7=89=A9=E4=B8=8D?= =?UTF-8?q?=E6=94=AF=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../resources/pages/ResourceListPage.jsx | 4 +-- src/shared/api/upload.test.ts | 27 +++++++++++++++++-- src/shared/api/upload.ts | 12 +++++++++ 3 files changed, 39 insertions(+), 4 deletions(-) diff --git a/src/features/resources/pages/ResourceListPage.jsx b/src/features/resources/pages/ResourceListPage.jsx index 3fe6f59..d691415 100644 --- a/src/features/resources/pages/ResourceListPage.jsx +++ b/src/features/resources/pages/ResourceListPage.jsx @@ -45,7 +45,7 @@ import { translateResourceCodes, } from "@/features/resources/batchUpload.js"; import { useResourceListPage } from "@/features/resources/hooks/useResourcePages.js"; -import { uploadImagesBatch } from "@/shared/api/upload"; +import { uploadFilesBatch } from "@/shared/api/upload"; import { useToast } from "@/shared/ui/ToastProvider.jsx"; import styles from "@/features/resources/resources.module.css"; @@ -182,7 +182,7 @@ export function ResourceListPage() { label: `上传素材 ${index + 1}-${index + chunk.length}/${uploadEntries.length}`, running: true, }); - const results = await uploadImagesBatch(chunk.map((entry) => entry.file)); + const results = await uploadFilesBatch(chunk.map((entry) => entry.file)); results.forEach((result, resultIndex) => { const entry = chunk[resultIndex]; resources[entry.resourceIndex][entry.role === "cover" ? "coverUrl" : "animationUrl"] = result.url; diff --git a/src/shared/api/upload.test.ts b/src/shared/api/upload.test.ts index 6691127..f561b7e 100644 --- a/src/shared/api/upload.test.ts +++ b/src/shared/api/upload.test.ts @@ -1,6 +1,6 @@ import { afterEach, expect, test, vi } from "vitest"; import { setAccessToken } from "@/shared/api/request"; -import { uploadFile, uploadImage, uploadImagesBatch } from "@/shared/api/upload"; +import { uploadFile, uploadFilesBatch, uploadImage, uploadImagesBatch } from "@/shared/api/upload"; afterEach(() => { setAccessToken(""); @@ -46,7 +46,30 @@ test("uploadFile sends multipart data to generated file endpoint", async () => { expect(init?.headers).not.toHaveProperty("Content-Type"); }); -test("uploadImagesBatch sends multipart data to admin batch endpoint", async () => { +test("uploadFilesBatch sends multipart data to admin generic batch endpoint", async () => { + vi.stubGlobal( + "fetch", + vi.fn( + async () => + new Response( + JSON.stringify({ + code: 0, + data: [{ url: "https://media.haiyihy.com/admin/files/gift.mp4" }], + }), + ), + ), + ); + + await uploadFilesBatch([new File(["video"], "gift.mp4", { type: "video/mp4" })]); + const [url, init] = vi.mocked(fetch).mock.calls[0]; + + expect(String(url)).toContain("/api/v1/admin/files/batch-upload"); + expect(init?.method).toBe("POST"); + expect(init?.body).toBeInstanceOf(FormData); + expect(init?.headers).not.toHaveProperty("Content-Type"); +}); + +test("uploadImagesBatch sends multipart data to admin image batch endpoint", async () => { vi.stubGlobal( "fetch", vi.fn( diff --git a/src/shared/api/upload.ts b/src/shared/api/upload.ts index 8c3b59f..77ccec6 100644 --- a/src/shared/api/upload.ts +++ b/src/shared/api/upload.ts @@ -24,6 +24,18 @@ export function uploadImage(file: File): Promise { }); } +export function uploadFilesBatch(files: File[]): Promise { + const formData = new FormData(); + files.forEach((file) => { + formData.append("files", file); + }); + + return apiRequest("/v1/admin/files/batch-upload", { + body: formData, + method: "POST", + }); +} + export function uploadImagesBatch(files: File[]): Promise { const formData = new FormData(); files.forEach((file) => {