Files
omniai-web/src/features/ecommerce/panels/EcommerceDetailPanel.tsx
T
OmniAI Developer 10b8379965 feat: 交互式对话框生成器 + 电商取消生成与上传优化
新增:
- 交互式对话框生成器模块(路由、页面、样式、MorePage入口)
- 电商模块取消生成功能(任务追踪/取消按钮/中止逻辑)
- 视频服务图片上传支持 Blob/dataURL/远程URL 多种来源

优化:
- 电商图片上传修复本地 blob 预览图缺少原始文件的问题
- 视频规划管线错误信息改进
- 生成流程中多处增加中止检查点
2026-06-05 00:37:38 +08:00

176 lines
6.3 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, LoadingOutlined, QuestionCircleOutlined } from "@ant-design/icons";
import type { ChangeEvent, RefObject } from "react";
import { EcommerceProgressBar } from "../EcommerceProgressBar";
interface EcommerceDetailPanelProps {
detailInputRef: RefObject<HTMLInputElement>;
detailProductImages: Array<{ id: string; src: string; name: string }>;
detailPlatform: string;
detailMarket: string;
detailLanguage: string;
detailType: string;
detailRequirement: string;
selectedDetailModules: string[];
detailStatus: string;
canGenerateDetail: boolean;
detailPrimaryLabel: string;
platformOptions: string[];
marketOptions: string[];
detailLanguageOptions: string[];
detailTypeOptions: string[];
detailModules: Array<{ id: string; title: string; desc: string }>;
handleDetailUpload: (event: ChangeEvent<HTMLInputElement>) => void;
handleDetailPlatformChange: (value: string) => void;
handleDetailMarketChange: (value: string) => void;
setDetailLanguage: (value: string) => void;
setDetailType: (value: string) => void;
setDetailRequirement: (value: string) => void;
handleDetailAiWrite: () => void;
toggleDetailModule: (id: string) => void;
handleDetailGenerate: () => void;
onCancelGenerate: () => void;
}
export default function EcommerceDetailPanel({
detailInputRef,
detailProductImages,
detailPlatform,
detailMarket,
detailLanguage,
detailType,
detailRequirement,
selectedDetailModules,
detailStatus,
canGenerateDetail,
detailPrimaryLabel,
platformOptions,
marketOptions,
detailLanguageOptions,
detailTypeOptions,
detailModules,
handleDetailUpload,
handleDetailPlatformChange,
handleDetailMarketChange,
setDetailLanguage,
setDetailType,
setDetailRequirement,
handleDetailAiWrite,
toggleDetailModule,
handleDetailGenerate,
onCancelGenerate,
}: EcommerceDetailPanelProps) {
return (
<>
<div className="product-clone-panel__scroll">
<section className="product-clone-field">
<h2>
<QuestionCircleOutlined />
</h2>
<button type="button" className="product-clone-upload-zone product-detail-upload" onClick={() => detailInputRef.current?.click()}>
<strong>
<CloudUploadOutlined />
</strong>
<span>3</span>
</button>
<input ref={detailInputRef} type="file" accept="image/*" multiple onChange={handleDetailUpload} />
{detailProductImages.length ? (
<div className="product-clone-thumb-row" aria-label="已上传商品原图">
{detailProductImages.map((item) => (
<figure key={item.id} className="product-clone-uploaded-thumb">
<img src={item.src} alt={item.name} />
<span className="uploaded-image-zoom" aria-hidden="true">
<img src={item.src} alt="" />
</span>
</figure>
))}
</div>
) : null}
</section>
<section className="product-clone-field">
<h2></h2>
<div className="product-detail-settings-grid">
<select value={detailPlatform} onChange={(event) => handleDetailPlatformChange(event.target.value)}>
{platformOptions.map((item) => (
<option key={item}>{item}</option>
))}
</select>
<select value={detailMarket} onChange={(event) => handleDetailMarketChange(event.target.value)}>
{marketOptions.map((item) => (
<option key={item}>{item}</option>
))}
</select>
<select value={detailLanguage} onChange={(event) => setDetailLanguage(event.target.value)}>
{detailLanguageOptions.map((item) => (
<option key={item}>{item}</option>
))}
</select>
<select value={detailType} onChange={(event) => setDetailType(event.target.value)}>
{detailTypeOptions.map((item) => (
<option key={item}>{item}</option>
))}
</select>
</div>
</section>
<section className="product-clone-field product-detail-requirement">
<h2>
&
<QuestionCircleOutlined />
<button
type="button"
onClick={(event) => {
event.preventDefault();
event.stopPropagation();
handleDetailAiWrite();
}}
>
AI
</button>
</h2>
<textarea
value={detailRequirement}
onChange={(event) => setDetailRequirement(event.target.value)}
placeholder={"建议包含以下信息生成更精准:\n1.产品名称\n2.核心卖点\n3.适用人群\n4.期望场景\n5.具体参数"}
/>
</section>
<section className="product-clone-field">
<h2>
<QuestionCircleOutlined />
</h2>
<div className="product-detail-module-grid">
{detailModules.map((module) => (
<button
key={module.id}
type="button"
className={selectedDetailModules.includes(module.id) ? "is-active" : ""}
onClick={() => toggleDetailModule(module.id)}
>
<strong>{module.title}</strong>
<span>{module.desc}</span>
</button>
))}
</div>
</section>
</div>
<footer className="product-clone-panel__footer">
{detailStatus === "generating" ? <EcommerceProgressBar status="generating" label="A+详情页" /> : null}
<button type="button" className="product-clone-primary" disabled={!canGenerateDetail} onClick={handleDetailGenerate}>
{detailStatus === "generating" ? <LoadingOutlined /> : null}
{detailPrimaryLabel}
</button>
{detailStatus === "generating" ? (
<button type="button" className="product-clone-primary product-clone-primary--cancel" onClick={onCancelGenerate}>
{"\u53d6\u6d88\u751f\u6210"}
</button>
) : null}
</footer>
</>
);
}