Files
omniai-ds-code-package/src/features/ecommerce/panels/WatermarkToolPage.tsx
T

238 lines
8.5 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import {
CloudUploadOutlined,
FileImageOutlined,
FolderOpenOutlined,
FrownOutlined,
LoadingOutlined,
QuestionCircleOutlined,
} from "@ant-design/icons";
import type { ChangeEvent, DragEvent, KeyboardEvent, RefObject } from "react";
import { toast } from "../../../components/toast/toastStore";
export interface WatermarkImageItem {
src: string;
name: string;
format: string;
}
export type WatermarkStatus = "idle" | "processing" | "done" | "failed";
interface WatermarkToolPageProps {
inputRef: RefObject<HTMLInputElement>;
urlInputRef: RefObject<HTMLInputElement>;
image: WatermarkImageItem | null;
isDragging: boolean;
status: WatermarkStatus;
progress: number;
resultUrl: string | null;
onUpload: (event: ChangeEvent<HTMLInputElement>) => void;
onDrop: (event: DragEvent<HTMLDivElement>) => void;
onDraggingChange: (dragging: boolean) => void;
onRemoveImage: () => void;
onUrlImport: () => void;
onGenerate: () => void;
onDownload: () => void;
onClose: () => void;
}
// 去水印工具页面:上传含水印图片 → AI 清理 → 预览/下载结果。
// 从 EcommercePage 的 watermarkPreview 抽出,状态与处理逻辑仍在父组件,本组件纯展示 + 回调。
export default function WatermarkToolPage({
inputRef,
urlInputRef,
image,
isDragging,
status,
progress,
resultUrl,
onUpload,
onDrop,
onDraggingChange,
onRemoveImage,
onUrlImport,
onGenerate,
onDownload,
onClose,
}: WatermarkToolPageProps) {
return (
<main key="watermark" className="ecom-watermark-page ecom-tool-page-enter" aria-label="去水印">
<input
ref={inputRef}
type="file"
accept="image/*"
className="ecom-command-hidden-file"
onChange={onUpload}
aria-label="上传去水印图片"
/>
<aside className="ecom-watermark-side">
<header className="ecom-quick-set-panel-head ecom-watermark-panel-head">
<strong className="ecom-quick-set-page-title"></strong>
<button type="button" className="ecom-quick-set-back" onClick={onClose}></button>
<button type="button" className="ecom-quick-set-back" onClick={onClose}></button>
</header>
<p className="ecom-watermark-intro"></p>
<section className="ecom-watermark-panel">
<header>
<strong></strong>
<span>{image ? "已上传" : "待上传"}</span>
</header>
<div
className={`ecom-watermark-upload-card${isDragging ? " is-dragging" : ""}${image ? " has-image" : ""}`}
role="button"
tabIndex={0}
onClick={() => inputRef.current?.click()}
onKeyDown={(event: KeyboardEvent) => {
if (event.key === "Enter" || event.key === " ") {
event.preventDefault();
inputRef.current?.click();
}
}}
onDragEnter={(event) => {
event.preventDefault();
onDraggingChange(true);
}}
onDragOver={(event) => event.preventDefault()}
onDragLeave={() => onDraggingChange(false)}
onDrop={onDrop}
>
{image ? (
<>
<button
type="button"
className="ecom-watermark-remove"
onClick={(event) => {
event.preventDefault();
event.stopPropagation();
onRemoveImage();
}}
aria-label="删除素材"
>
×
</button>
<figure>
<img src={image.src} alt={image.name} />
</figure>
<div>
<strong>{image.name}</strong>
<span>{image.format || "PNG / JPG / WebP"}</span>
</div>
</>
) : (
<>
<CloudUploadOutlined />
<strong></strong>
<span> PNG / JPG / WebP</span>
</>
)}
</div>
<div className="ecom-watermark-url-row">
<input
ref={urlInputRef}
placeholder="粘贴图片 URL"
aria-label="粘贴图片 URL"
onKeyDown={(event) => {
if (event.key === "Enter") void onUrlImport();
}}
/>
<button type="button" onClick={() => void onUrlImport()}></button>
</div>
</section>
<section className="ecom-watermark-panel">
<strong></strong>
<p></p>
</section>
<button
type="button"
className="ecom-watermark-primary"
onClick={onGenerate}
disabled={!image || status === "processing"}
>
{status === "processing" ? <LoadingOutlined /> : <FileImageOutlined />}
{status === "processing" ? "处理中" : "开始去水印"}
</button>
</aside>
<section className="ecom-watermark-workspace">
{!image ? (
<div
className={`ecom-watermark-dropzone${isDragging ? " is-dragging" : ""}`}
role="button"
tabIndex={0}
onClick={() => inputRef.current?.click()}
onKeyDown={(event: KeyboardEvent) => {
if (event.key === "Enter" || event.key === " ") {
event.preventDefault();
inputRef.current?.click();
}
}}
onDragEnter={(event) => {
event.preventDefault();
onDraggingChange(true);
}}
onDragOver={(event) => event.preventDefault()}
onDragLeave={() => onDraggingChange(false)}
onDrop={onDrop}
>
<CloudUploadOutlined />
<strong></strong>
<span> PNG / JPG / WebP</span>
</div>
) : (
<div className="ecom-watermark-grid">
<article className="ecom-watermark-preview-card">
<span></span>
<img src={image.src} alt="原图" />
</article>
<article className="ecom-watermark-preview-card">
<span></span>
{status === "processing" ? (
<div className="ecom-watermark-processing" role="status" aria-live="polite">
<LoadingOutlined />
<strong></strong>
<em>AI </em>
<div className="ecom-quick-set-progress">
<div className="ecom-quick-set-progress-bar" style={{ width: `${Math.round(progress)}%` }} />
</div>
<em className="ecom-quick-set-progress-text">{Math.round(progress)}%</em>
</div>
) : status === "done" && resultUrl ? (
<>
<img src={resultUrl} alt="去水印结果" />
<button type="button" className="ecom-watermark-zoom" aria-label="查看大图">
<QuestionCircleOutlined />
</button>
</>
) : status === "failed" ? (
<div className="ecom-watermark-empty">
<FrownOutlined />
<strong></strong>
<em></em>
</div>
) : (
<div className="ecom-watermark-empty">
<FileImageOutlined />
<strong></strong>
<em></em>
</div>
)}
<div className="ecom-watermark-actions">
<button type="button" onClick={() => toast.success("已加入资产库")} disabled={status !== "done"}>
<FolderOpenOutlined />
</button>
<button type="button" onClick={onDownload} disabled={status !== "done"}>
<CloudUploadOutlined />
</button>
</div>
</article>
</div>
)}
</section>
</main>
);
}