fix: 支持追加队列批量上传PSD字体
Some checks failed
Lint / build (20) (push) Has been cancelled
Playwright Tests / test (push) Has been cancelled

This commit is contained in:
Your Name 2026-04-03 19:50:49 +08:00
parent 3ee9701a50
commit 9362b25593

View File

@ -1,7 +1,7 @@
"use client";
import Link from "next/link";
import { useEffect, useMemo, useState, type ChangeEvent } from "react";
import { useEffect, useMemo, useRef, useState, type ChangeEvent } from "react";
import useSWR from "swr";
import { toast } from "sonner";
import {
@ -104,6 +104,26 @@ function normalizeManagedBrandName(value?: string | null) {
return normalized;
}
function getQueuedFontFileKey(file: File) {
return [file.name, file.size, file.lastModified].join("__");
}
function mergeQueuedFontFiles(current: File[], incoming: File[]) {
const merged = [...current];
const seen = new Set(current.map((file) => getQueuedFontFileKey(file)));
for (const file of incoming) {
const key = getQueuedFontFileKey(file);
if (seen.has(key)) {
continue;
}
seen.add(key);
merged.push(file);
}
return merged;
}
function hasTemplateCategoryTag(tags: string[] | undefined, target: string) {
const normalizedTarget = String(target || "").trim().toLowerCase();
if (!normalizedTarget) {
@ -258,6 +278,7 @@ export function PsdTemplatesSettingsClient({
const [fontFamily, setFontFamily] = useState("");
const [fontUploadBrandName, setFontUploadBrandName] = useState("");
const [fontUploadFiles, setFontUploadFiles] = useState<File[]>([]);
const fontFileInputRef = useRef<HTMLInputElement | null>(null);
const [isCreating, setIsCreating] = useState(false);
const [isCreatingAndParsing, setIsCreatingAndParsing] = useState(false);
const [templateUploadPercent, setTemplateUploadPercent] = useState(0);
@ -487,9 +508,13 @@ export function PsdTemplatesSettingsClient({
function handleFontFileChange(event: ChangeEvent<HTMLInputElement>) {
const nextFiles = Array.from(event.target.files || []);
setFontUploadFiles(nextFiles);
if (nextFiles.length === 0) {
return;
}
if (nextFiles.length === 1) {
setFontUploadFiles((current) => mergeQueuedFontFiles(current, nextFiles));
if (fontUploadFiles.length === 0 && nextFiles.length === 1) {
const normalizedName = nextFiles[0]?.name.replace(/\.[^.]+$/, "") || "";
if (normalizedName && !fontUploadName.trim()) {
setFontUploadName(normalizedName);
@ -498,6 +523,23 @@ export function PsdTemplatesSettingsClient({
setFontFamily(normalizedName);
}
}
event.currentTarget.value = "";
}
function handleRemoveQueuedFontFile(file: File) {
setFontUploadFiles((current) =>
current.filter(
(item) => getQueuedFontFileKey(item) !== getQueuedFontFileKey(file)
)
);
}
function handleClearQueuedFontFiles() {
setFontUploadFiles([]);
if (fontFileInputRef.current) {
fontFileInputRef.current.value = "";
}
}
async function saveCategoryTagConfig(nextTags: string[]) {
@ -734,6 +776,9 @@ export function PsdTemplatesSettingsClient({
setFontFamily("");
setFontUploadBrandName("");
setFontUploadFiles([]);
if (fontFileInputRef.current) {
fontFileInputRef.current.value = "";
}
await mutateFonts();
} catch (error) {
toast.error(error instanceof Error ? error.message : "字体上传失败");
@ -1435,11 +1480,15 @@ export function PsdTemplatesSettingsClient({
<div className="space-y-2">
<Label htmlFor="psdFontFile">字体文件</Label>
<Input
ref={fontFileInputRef}
id="psdFontFile"
type="file"
accept=".ttf,.otf,.woff,.woff2"
multiple
onChange={handleFontFileChange}
onClick={(event) => {
event.currentTarget.value = "";
}}
/>
<p className="text-xs text-muted-foreground">
{fontUploadFiles.length > 0
@ -1448,13 +1497,55 @@ export function PsdTemplatesSettingsClient({
: `已选择 ${fontUploadFiles.length} 个字体文件:${fontUploadFiles
.map((file) => file.name)
.join("、")}`
: "支持一次选择多个字体文件批量上传,建议按实际字重分别整理后再导入"}
: "支持一次多选,也支持多次继续添加字体文件后再批量上传"}
</p>
<p className="text-xs text-muted-foreground">
{fontUploadFiles.length > 1
? "批量上传时会使用每个文件名作为字体名称;如果填写了 CSS 字体族,会批量应用到这一批字体。"
: "单个上传时可自定义字体名称和 CSS 字体族。"}
</p>
{fontUploadFiles.length > 0 ? (
<div className="space-y-2 rounded-xl border border-dashed p-3">
<div className="flex items-center justify-between gap-3">
<div className="text-xs font-medium text-muted-foreground">
待上传文件队列
</div>
<Button
type="button"
variant="ghost"
size="sm"
className="h-7 px-2 text-xs"
onClick={handleClearQueuedFontFiles}
>
清空已选
</Button>
</div>
<div className="space-y-2">
{fontUploadFiles.map((file) => (
<div
key={getQueuedFontFileKey(file)}
className="flex items-center justify-between gap-3 rounded-lg border bg-background/60 px-3 py-2"
>
<div className="min-w-0">
<div className="truncate text-sm">{file.name}</div>
<div className="text-[11px] text-muted-foreground">
{(file.size / 1024 / 1024).toFixed(2)} MB
</div>
</div>
<Button
type="button"
variant="ghost"
size="icon"
className="h-8 w-8 shrink-0"
onClick={() => handleRemoveQueuedFontFile(file)}
>
<Trash2 className="h-4 w-4" />
</Button>
</div>
))}
</div>
</div>
) : null}
</div>
<Button onClick={handleUploadFont} disabled={isUploadingFont} className="w-full" variant="outline">
{isUploadingFont ? (