refactor: extract canvas upload validation helpers
This commit is contained in:
parent
9821832364
commit
593b7e3df0
@ -168,6 +168,12 @@ import {
|
||||
fillDetailSlotAttachments,
|
||||
getDetailSlotTargetIndexes,
|
||||
} from "@/components/canvas/chat-panel/canvas-detail-slots";
|
||||
import {
|
||||
buildCanvasUploadedImageAttachment,
|
||||
getCanvasUploadImageTitle,
|
||||
normalizeUploadedAssetId,
|
||||
validateCanvasImageUploadFile,
|
||||
} from "@/components/canvas/chat-panel/canvas-upload-helpers";
|
||||
import {
|
||||
clampChatRequestText,
|
||||
deriveSessionTitleFromMessages,
|
||||
@ -4816,14 +4822,9 @@ export function CanvasChatPanel({
|
||||
const file = event.target.files?.[0];
|
||||
if (!file) return;
|
||||
|
||||
if (!file.type.startsWith("image/")) {
|
||||
toast.error("请上传图片文件");
|
||||
event.currentTarget.value = "";
|
||||
return;
|
||||
}
|
||||
|
||||
if (file.size > 50 * 1024 * 1024) {
|
||||
toast.error("图片大小不能超过 50MB");
|
||||
const validation = validateCanvasImageUploadFile(file);
|
||||
if (!validation.ok) {
|
||||
toast.error(validation.message);
|
||||
event.currentTarget.value = "";
|
||||
return;
|
||||
}
|
||||
@ -4841,15 +4842,12 @@ export function CanvasChatPanel({
|
||||
|
||||
const data = await response.json();
|
||||
const imageUrl = data.url as string;
|
||||
const assetId =
|
||||
typeof data.assetId === "string" && data.assetId.trim() ? data.assetId.trim() : undefined;
|
||||
const assetId = normalizeUploadedAssetId(data.assetId);
|
||||
|
||||
updateAttachmentAtVideoSlot(slotIndex, {
|
||||
url: imageUrl,
|
||||
name: file.name,
|
||||
contentType: file.type || "image/jpeg",
|
||||
assetId,
|
||||
});
|
||||
updateAttachmentAtVideoSlot(
|
||||
slotIndex,
|
||||
buildCanvasUploadedImageAttachment({ file, imageUrl, assetId })
|
||||
);
|
||||
|
||||
const dimensions = await getImageDimensions(imageUrl);
|
||||
const nodeIndex = nodes.length + slotIndex;
|
||||
@ -4863,8 +4861,8 @@ export function CanvasChatPanel({
|
||||
data: {
|
||||
src: imageUrl,
|
||||
status: "completed",
|
||||
title: file.name.replace(/\.[^.]+$/, ""),
|
||||
prompt: file.name.replace(/\.[^.]+$/, ""),
|
||||
title: getCanvasUploadImageTitle(file.name),
|
||||
prompt: getCanvasUploadImageTitle(file.name),
|
||||
metadata: {
|
||||
originalWidth: dimensions.originalWidth,
|
||||
originalHeight: dimensions.originalHeight,
|
||||
@ -4888,14 +4886,9 @@ export function CanvasChatPanel({
|
||||
const file = event.target.files?.[0];
|
||||
if (!file) return;
|
||||
|
||||
if (!file.type.startsWith("image/")) {
|
||||
toast.error("请上传图片文件");
|
||||
event.currentTarget.value = "";
|
||||
return;
|
||||
}
|
||||
|
||||
if (file.size > 50 * 1024 * 1024) {
|
||||
toast.error("图片大小不能超过 50MB");
|
||||
const validation = validateCanvasImageUploadFile(file);
|
||||
if (!validation.ok) {
|
||||
toast.error(validation.message);
|
||||
event.currentTarget.value = "";
|
||||
return;
|
||||
}
|
||||
@ -4913,15 +4906,12 @@ export function CanvasChatPanel({
|
||||
|
||||
const data = await response.json();
|
||||
const imageUrl = data.url as string;
|
||||
const assetId =
|
||||
typeof data.assetId === "string" && data.assetId.trim() ? data.assetId.trim() : undefined;
|
||||
const assetId = normalizeUploadedAssetId(data.assetId);
|
||||
|
||||
updateAttachmentAtAgentSlot(slotIndex, {
|
||||
url: imageUrl,
|
||||
name: file.name,
|
||||
contentType: file.type || "image/jpeg",
|
||||
assetId,
|
||||
});
|
||||
updateAttachmentAtAgentSlot(
|
||||
slotIndex,
|
||||
buildCanvasUploadedImageAttachment({ file, imageUrl, assetId })
|
||||
);
|
||||
|
||||
const dimensions = await getImageDimensions(imageUrl);
|
||||
const nodeIndex = nodes.length + slotIndex;
|
||||
@ -4935,8 +4925,8 @@ export function CanvasChatPanel({
|
||||
data: {
|
||||
src: imageUrl,
|
||||
status: "completed",
|
||||
title: file.name.replace(/\.[^.]+$/, ""),
|
||||
prompt: file.name.replace(/\.[^.]+$/, ""),
|
||||
title: getCanvasUploadImageTitle(file.name),
|
||||
prompt: getCanvasUploadImageTitle(file.name),
|
||||
metadata: {
|
||||
originalWidth: dimensions.originalWidth,
|
||||
originalHeight: dimensions.originalHeight,
|
||||
@ -5046,14 +5036,9 @@ export function CanvasChatPanel({
|
||||
const file = event.target.files?.[0];
|
||||
if (!file) return;
|
||||
|
||||
if (!file.type.startsWith("image/")) {
|
||||
toast.error("请上传图片文件");
|
||||
event.currentTarget.value = "";
|
||||
return;
|
||||
}
|
||||
|
||||
if (file.size > 50 * 1024 * 1024) {
|
||||
toast.error("图片大小不能超过 50MB");
|
||||
const validation = validateCanvasImageUploadFile(file);
|
||||
if (!validation.ok) {
|
||||
toast.error(validation.message);
|
||||
event.currentTarget.value = "";
|
||||
return;
|
||||
}
|
||||
@ -5071,18 +5056,15 @@ export function CanvasChatPanel({
|
||||
|
||||
const data = await response.json();
|
||||
const imageUrl = String(data.url || "").trim();
|
||||
const assetId =
|
||||
typeof data.assetId === "string" && data.assetId.trim() ? data.assetId.trim() : undefined;
|
||||
const assetId = normalizeUploadedAssetId(data.assetId);
|
||||
if (!imageUrl) {
|
||||
throw new Error("未获取到图片地址");
|
||||
}
|
||||
|
||||
updateDetailSlotAttachment(slotIndex, {
|
||||
url: imageUrl,
|
||||
name: file.name,
|
||||
contentType: file.type || "image/jpeg",
|
||||
assetId,
|
||||
});
|
||||
updateDetailSlotAttachment(
|
||||
slotIndex,
|
||||
buildCanvasUploadedImageAttachment({ file, imageUrl, assetId })
|
||||
);
|
||||
toast.success(`${DETAIL_SLOT_CONFIGS[slotIndex]?.label || "图片"}上传成功`);
|
||||
} catch (_error) {
|
||||
toast.error("图片上传失败");
|
||||
|
||||
46
components/canvas/chat-panel/canvas-upload-helpers.ts
Normal file
46
components/canvas/chat-panel/canvas-upload-helpers.ts
Normal file
@ -0,0 +1,46 @@
|
||||
import type { PickedObjectAttachment } from "@/components/canvas/chat-panel/canvas-chat-session";
|
||||
|
||||
export const CANVAS_IMAGE_UPLOAD_MAX_BYTES = 50 * 1024 * 1024;
|
||||
|
||||
export type CanvasUploadFileLike = {
|
||||
name: string;
|
||||
type: string;
|
||||
size: number;
|
||||
};
|
||||
|
||||
export function validateCanvasImageUploadFile(file?: CanvasUploadFileLike | null):
|
||||
| { ok: true }
|
||||
| { ok: false; message: string } {
|
||||
if (!file) {
|
||||
return { ok: false, message: "请选择图片文件" };
|
||||
}
|
||||
if (!file.type.startsWith("image/")) {
|
||||
return { ok: false, message: "请上传图片文件" };
|
||||
}
|
||||
if (file.size > CANVAS_IMAGE_UPLOAD_MAX_BYTES) {
|
||||
return { ok: false, message: "图片大小不能超过 50MB" };
|
||||
}
|
||||
return { ok: true };
|
||||
}
|
||||
|
||||
export function getCanvasUploadImageTitle(fileName: string): string {
|
||||
const title = String(fileName || "").replace(/\.[^.]+$/, "").trim();
|
||||
return title || "图片";
|
||||
}
|
||||
|
||||
export function buildCanvasUploadedImageAttachment(params: {
|
||||
file: CanvasUploadFileLike;
|
||||
imageUrl: string;
|
||||
assetId?: string;
|
||||
}): PickedObjectAttachment {
|
||||
return {
|
||||
url: params.imageUrl,
|
||||
name: params.file.name,
|
||||
contentType: params.file.type || "image/jpeg",
|
||||
assetId: params.assetId,
|
||||
};
|
||||
}
|
||||
|
||||
export function normalizeUploadedAssetId(value: unknown): string | undefined {
|
||||
return typeof value === "string" && value.trim() ? value.trim() : undefined;
|
||||
}
|
||||
@ -38,6 +38,13 @@ import {
|
||||
fillDetailSlotAttachments,
|
||||
getDetailSlotTargetIndexes,
|
||||
} from "@/components/canvas/chat-panel/canvas-detail-slots";
|
||||
import {
|
||||
buildCanvasUploadedImageAttachment,
|
||||
CANVAS_IMAGE_UPLOAD_MAX_BYTES,
|
||||
getCanvasUploadImageTitle,
|
||||
normalizeUploadedAssetId,
|
||||
validateCanvasImageUploadFile,
|
||||
} from "@/components/canvas/chat-panel/canvas-upload-helpers";
|
||||
import type { PickedObjectAttachment } from "@/components/canvas/chat-panel/canvas-chat-session";
|
||||
import type { ChatMessage } from "@/lib/types";
|
||||
|
||||
@ -444,4 +451,60 @@ test.describe("canvas chat pure helpers", () => {
|
||||
expect(filled.slots[4]).toBe(productB);
|
||||
expect(filled.slots[5]).toBeNull();
|
||||
});
|
||||
|
||||
test("validates and normalizes canvas image upload helper payloads", () => {
|
||||
expect(validateCanvasImageUploadFile(null)).toEqual({
|
||||
ok: false,
|
||||
message: "请选择图片文件",
|
||||
});
|
||||
expect(
|
||||
validateCanvasImageUploadFile({
|
||||
name: "demo.txt",
|
||||
type: "text/plain",
|
||||
size: 10,
|
||||
})
|
||||
).toEqual({
|
||||
ok: false,
|
||||
message: "请上传图片文件",
|
||||
});
|
||||
expect(
|
||||
validateCanvasImageUploadFile({
|
||||
name: "huge.png",
|
||||
type: "image/png",
|
||||
size: CANVAS_IMAGE_UPLOAD_MAX_BYTES + 1,
|
||||
})
|
||||
).toEqual({
|
||||
ok: false,
|
||||
message: "图片大小不能超过 50MB",
|
||||
});
|
||||
expect(
|
||||
validateCanvasImageUploadFile({
|
||||
name: "valid.webp",
|
||||
type: "image/webp",
|
||||
size: CANVAS_IMAGE_UPLOAD_MAX_BYTES,
|
||||
})
|
||||
).toEqual({ ok: true });
|
||||
|
||||
expect(getCanvasUploadImageTitle(" product.hero.final.png ")).toBe("product.hero.final");
|
||||
expect(getCanvasUploadImageTitle(".png")).toBe("图片");
|
||||
expect(normalizeUploadedAssetId(" asset-123 ")).toBe("asset-123");
|
||||
expect(normalizeUploadedAssetId(" ")).toBeUndefined();
|
||||
|
||||
expect(
|
||||
buildCanvasUploadedImageAttachment({
|
||||
file: {
|
||||
name: "photo.png",
|
||||
type: "",
|
||||
size: 100,
|
||||
},
|
||||
imageUrl: "https://cdn.example.com/photo.png",
|
||||
assetId: "asset-1",
|
||||
})
|
||||
).toEqual({
|
||||
name: "photo.png",
|
||||
url: "https://cdn.example.com/photo.png",
|
||||
contentType: "image/jpeg",
|
||||
assetId: "asset-1",
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user