refactor(server): 移除已放弃的 Ozon API 直传模块,新增素材删除接口
- 删除 shops/publish/categories/ozon 相关路由、模型、schema 与客户端服务(V2.1 决策放弃 API 直传,改人工上传)
- materials 新增 DELETE /assets/{id}:删除素材记录与本地文件,并同步修正 asset_counts
- 试算页支持单张素材删除,生图弹窗交互微调
- 新增 docs/v2.1/HANDOFF.md 工作交接说明,README 补充索引
This commit is contained in:
@@ -9,7 +9,7 @@ interface Props {
|
||||
open: boolean;
|
||||
productId: string;
|
||||
/** 待生成的源图(采集图或生成图) */
|
||||
source: { url: string; name: string } | null;
|
||||
source: { url: string; name: string; afterAssetId?: string } | null;
|
||||
onClose: () => void;
|
||||
/** 生成成功回调(服务端 append 后刷新素材列表) */
|
||||
onGenerated?: (url: string) => void;
|
||||
@@ -49,9 +49,10 @@ export default function AiImageGenModal({ open, productId, source, onClose, onGe
|
||||
prompt: prompt.trim(),
|
||||
model,
|
||||
append: true,
|
||||
after_asset_id: source.afterAssetId,
|
||||
});
|
||||
setResultUrl(r.url);
|
||||
message.success('生成完成,已追加到「生成图」分组');
|
||||
message.success('生成完成,已追加到「生成结果」');
|
||||
onGenerated?.(r.url);
|
||||
} catch (e) {
|
||||
message.error(apiErrorMessage(e));
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
*/
|
||||
import { useEffect, useMemo, useRef, useState, type CSSProperties } from 'react';
|
||||
import {
|
||||
Alert, Button, Card, Checkbox, Col, Empty, Image, Input, InputNumber, message, Modal, Popover, Progress,
|
||||
Alert, Button, Card, Checkbox, Col, Empty, Image, Input, InputNumber, message, Modal, Popconfirm, Popover, Progress,
|
||||
Radio, Row, Segmented, Select, Space, Tag, Typography, Upload,
|
||||
} from 'antd';
|
||||
import { DownloadOutlined, SettingOutlined, ThunderboltOutlined, UploadOutlined } from '@ant-design/icons';
|
||||
@@ -14,7 +14,7 @@ import { apiErrorMessage } from '@/services/api';
|
||||
import {
|
||||
DEFAULT_IMAGE_MODEL, DEFAULT_PLAN, DEFAULT_WATERMARK, IMAGE_MODEL_OPTIONS,
|
||||
STYLE_SET_OPTIONS, SuiteInfo, SuiteTextPayload, WatermarkPayload,
|
||||
downloadSuiteZip, exportImages, generateSuite, getSuite, planSuite, uploadProductAsset,
|
||||
deleteAsset, downloadSuiteZip, exportImages, generateSuite, getSuite, planSuite, uploadProductAsset,
|
||||
type PlanItem,
|
||||
} from '@/services/suite';
|
||||
import { cleanFilename, downloadBlob } from '@/utils/file';
|
||||
@@ -174,8 +174,8 @@ export default function TrialSuitePanel({ product, assets, onRefreshAssets }: Pr
|
||||
/** 规划请求序号:重置后丢弃迟到的过期响应 */
|
||||
const planSeqRef = useRef(0);
|
||||
|
||||
// 单张 AI 生图弹窗
|
||||
const [genModal, setGenModal] = useState<{ url: string; name: string } | null>(null);
|
||||
// 单张 AI 生图弹窗(afterAssetId:结果插到该素材之后,方便对比)
|
||||
const [genModal, setGenModal] = useState<{ url: string; name: string; afterAssetId?: string } | null>(null);
|
||||
|
||||
// 采集图片卡只放采集/上传素材;单张 AI 生图结果(generated)放「生成结果」卡展示
|
||||
const imgs = useMemo(() => assets.filter((a) => a.type !== 'video' && a.group_key !== 'generated'), [assets]);
|
||||
@@ -510,6 +510,17 @@ export default function TrialSuitePanel({ product, assets, onRefreshAssets }: Pr
|
||||
);
|
||||
|
||||
const selectableCount = imgs.length;
|
||||
/** 删除一张已生成的图片(二次确认后调用),成功后刷新素材列表 */
|
||||
const handleDeleteGenerated = async (assetId: string) => {
|
||||
try {
|
||||
await deleteAsset(assetId);
|
||||
message.success('已删除');
|
||||
onRefreshAssets();
|
||||
} catch (e) {
|
||||
message.error(apiErrorMessage(e));
|
||||
}
|
||||
};
|
||||
|
||||
const displayGroups = DISPLAY_GROUPS.filter((g) => groupImages(g).length > 0);
|
||||
|
||||
return (
|
||||
@@ -947,7 +958,7 @@ export default function TrialSuitePanel({ product, assets, onRefreshAssets }: Pr
|
||||
<Image.PreviewGroup>
|
||||
<div style={{ display: 'flex', flexWrap: 'wrap', gap: 10, marginTop: 10 }}>
|
||||
{generatedAssets.map((a) => (
|
||||
<div key={a.id} style={{ width: 112 }}>
|
||||
<div key={a.id} style={{ width: 100, position: 'relative' }}>
|
||||
<Image
|
||||
src={assetUrl(a)}
|
||||
width={100}
|
||||
@@ -955,18 +966,58 @@ export default function TrialSuitePanel({ product, assets, onRefreshAssets }: Pr
|
||||
style={{ objectFit: 'cover', borderRadius: 6 }}
|
||||
fallback="data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='100' height='133'><rect width='100' height='133' fill='%23eee'/><text x='18' y='70' font-size='11' fill='%23999'>无预览</text></svg>"
|
||||
/>
|
||||
{/* 删除(二次确认) */}
|
||||
<Popconfirm
|
||||
title="删除图片"
|
||||
description="确认删除这张已生成的图片?"
|
||||
okText="删除"
|
||||
cancelText="取消"
|
||||
okButtonProps={{ danger: true }}
|
||||
onConfirm={() => handleDeleteGenerated(a.id)}
|
||||
>
|
||||
<span
|
||||
title="删除这张图片"
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
style={{
|
||||
position: 'absolute',
|
||||
top: 6,
|
||||
right: 6,
|
||||
width: 20,
|
||||
height: 20,
|
||||
borderRadius: '50%',
|
||||
background: 'rgba(255,255,255,0.95)',
|
||||
color: '#ff4d4f',
|
||||
border: '1px solid #ffccc7',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
cursor: 'pointer',
|
||||
fontSize: 12,
|
||||
zIndex: 1,
|
||||
userSelect: 'none',
|
||||
lineHeight: 1,
|
||||
}}
|
||||
>
|
||||
✕
|
||||
</span>
|
||||
</Popconfirm>
|
||||
<div
|
||||
style={{
|
||||
fontSize: 11,
|
||||
color: 'rgba(0,0,0,0.45)',
|
||||
marginTop: 2,
|
||||
overflow: 'hidden',
|
||||
textOverflow: 'ellipsis',
|
||||
whiteSpace: 'nowrap',
|
||||
}}
|
||||
title={a.stored_url ?? undefined}
|
||||
title="基于这张图再次 AI 编辑"
|
||||
onClick={() => setGenModal({ url: assetUrl(a), name: a.variant_name || 'AI 编辑', afterAssetId: a.id })}
|
||||
>
|
||||
AI 生图 {a.created_at ? new Date(a.created_at).toLocaleTimeString() : ''}
|
||||
<a style={{ color: '#1677ff' }}>AI 编辑</a>
|
||||
{a.created_at && (
|
||||
<span style={{ color: 'rgba(0,0,0,0.45)', marginLeft: 4 }}>
|
||||
{new Date(a.created_at).toLocaleTimeString()}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
|
||||
@@ -161,6 +161,8 @@ export interface ImageEditSinglePayload {
|
||||
prompt: string;
|
||||
model: string;
|
||||
append?: boolean;
|
||||
/** 插入锚点:新素材排在该素材之后(方便与原图对比) */
|
||||
after_asset_id?: string;
|
||||
}
|
||||
|
||||
/** ★ 单张 AI 生图(采集图/生成图上的「AI生图」入口) */
|
||||
@@ -168,6 +170,11 @@ export function imageEditSingle(payload: ImageEditSinglePayload) {
|
||||
return api.post<{ url: string; asset_id: string | null }>('/suite/image-edit', payload);
|
||||
}
|
||||
|
||||
/** 删除一条素材(DB 记录 + 本地文件),用于删除已生成的图片 */
|
||||
export function deleteAsset(assetId: string) {
|
||||
return api.delete<{ deleted: boolean }>(`/assets/${assetId}`);
|
||||
}
|
||||
|
||||
export interface ExportImagesPayload {
|
||||
title: string;
|
||||
images: Array<{ url: string; groupName: string; variantName?: string | null; key: string }>;
|
||||
|
||||
Reference in New Issue
Block a user