refactor(core): 抽出共享 ProductCreateDrawer · 商品/项目新建复用同一流程
- 新增 components/product-create-drawer.tsx,products/projects 改用同一右侧 Drawer 组件(products -188 / projects -116) - ai-tools 配套调整;附 perf-report 产物 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -523,6 +523,19 @@ export function ImageWorkbenchPage({
|
||||
const [searchOpen, setSearchOpen] = useState(false);
|
||||
// 模特网格默认只露 6 个;「全部模特 →」展开后露全部,再点收起(超过 6 个时第 7 个之后本来选不到)
|
||||
const [showAllModels, setShowAllModels] = useState(false);
|
||||
// 左侧商品空间搜索(原 input 无 state/无过滤=死框,输入无效);按名称/分类过滤
|
||||
const [prodQuery, setProdQuery] = useState("");
|
||||
const visibleProducts = products.filter((item) => {
|
||||
const q = prodQuery.trim().toLowerCase();
|
||||
if (!q) return true;
|
||||
return `${item.title} ${item.category || ""}`.toLowerCase().includes(q);
|
||||
});
|
||||
// 商品主图:用后端内嵌的 preview_url(cover_preview_url / images[].preview_url),不再反查全局 assets
|
||||
const productCoverUrl = (p: Product): string => {
|
||||
const sorted = [...(p.images || [])].sort((a, b) => a.sort_order - b.sort_order);
|
||||
const primary = p.images?.find((img) => img.is_primary) || sorted[0];
|
||||
return p.cover_preview_url || primary?.preview_url || "";
|
||||
};
|
||||
function pickReference(event: ChangeEvent<HTMLInputElement>) {
|
||||
const file = event.target.files?.[0];
|
||||
if (!file) return;
|
||||
@@ -1052,7 +1065,7 @@ export function ImageWorkbenchPage({
|
||||
</div>
|
||||
<div className="iw-ps-search">
|
||||
<Search size={13} />
|
||||
<input placeholder="搜索商品 / 分类" />
|
||||
<input placeholder="搜索商品 / 分类" value={prodQuery} onChange={(event) => setProdQuery(event.target.value)} />
|
||||
</div>
|
||||
<div className="iw-list-h">
|
||||
<span className="mono">// 商品空间</span>
|
||||
@@ -1070,23 +1083,36 @@ export function ImageWorkbenchPage({
|
||||
<br />
|
||||
// NO PRODUCTS
|
||||
</div>
|
||||
) : visibleProducts.length === 0 ? (
|
||||
<div className="iw-ps-empty">
|
||||
没有匹配的商品
|
||||
<br />
|
||||
// NO MATCH
|
||||
</div>
|
||||
) : (
|
||||
products.slice(0, 12).map((item) => (
|
||||
<button
|
||||
className={`iw-prod-item ${productId === item.id ? "active" : ""}`}
|
||||
type="button"
|
||||
key={item.id}
|
||||
onClick={() => setProductId(item.id)}
|
||||
>
|
||||
<div className="placeholder thumb">
|
||||
<span className="ph-frame">{item.title.slice(0, 2)}</span>
|
||||
</div>
|
||||
<div className="body">
|
||||
<div className="nm">{item.title}</div>
|
||||
<div className="sub">// {item.category || "未分类"}</div>
|
||||
</div>
|
||||
</button>
|
||||
))
|
||||
visibleProducts.slice(0, 12).map((item) => {
|
||||
const cover = productCoverUrl(item);
|
||||
return (
|
||||
<button
|
||||
className={`iw-prod-item ${productId === item.id ? "active" : ""}`}
|
||||
type="button"
|
||||
key={item.id}
|
||||
onClick={() => setProductId(item.id)}
|
||||
>
|
||||
{cover ? (
|
||||
<div className="thumb has-real-media"><img src={cover} alt={item.title} loading="lazy" /></div>
|
||||
) : (
|
||||
<div className="placeholder thumb">
|
||||
<span className="ph-frame">{item.title.slice(0, 2)}</span>
|
||||
</div>
|
||||
)}
|
||||
<div className="body">
|
||||
<div className="nm">{item.title}</div>
|
||||
<div className="sub">// {item.category || "未分类"}</div>
|
||||
</div>
|
||||
</button>
|
||||
);
|
||||
})
|
||||
)}
|
||||
</div>
|
||||
</aside>
|
||||
|
||||
Reference in New Issue
Block a user