feat(collection): 采集箱开发
This commit is contained in:
@@ -1,8 +1,26 @@
|
||||
import PagePlaceholder from '@/components/PagePlaceholder';
|
||||
import { useCallback, useEffect, useState } from 'react';
|
||||
import { App as AntdApp, Button, Card, Form, Input, Modal, Progress, Select, Space, Table, Tag, Typography } from 'antd';
|
||||
import type { TableProps } from 'antd';
|
||||
import { DeleteOutlined, PlusOutlined, ReloadOutlined } from '@ant-design/icons';
|
||||
import type { CollectionItem } from '@atlas/contracts';
|
||||
import { collectionApi } from '@/services/collection';
|
||||
import { apiErrorMessage } from '@/services/api';
|
||||
import { usePlatform } from '@/services/platform';
|
||||
|
||||
/** 采集箱:查看已采集的商品,进入编辑上架(业务模块尚未实现) */
|
||||
const CollectionPage = () => (
|
||||
<PagePlaceholder title="采集箱" description="查看已采集的商品,进入编辑上架,模块开发中。" />
|
||||
);
|
||||
|
||||
export default CollectionPage;
|
||||
const statusLabel: Record<string, string> = { received: '已接收', materializing: '素材处理中', ready_for_edit: '可编辑', needs_review: '待确认', failed: '采集失败' };
|
||||
export default function CollectionPage() {
|
||||
const { message, modal } = AntdApp.useApp(); const { currentPlatform } = usePlatform(); const [items, setItems] = useState<CollectionItem[]>([]); const [meta, setMeta] = useState({ active_count: 0, collection_limit: 1000 }); const [loading, setLoading] = useState(false); const [selected, setSelected] = useState<string[]>([]); const [q, setQ] = useState(''); const [source, setSource] = useState<string>(); const [createOpen, setCreateOpen] = useState(false); const [form] = Form.useForm<{ title?: string; note?: string }>();
|
||||
const load = useCallback(async () => { if (!currentPlatform) return; setLoading(true); try { const result = await collectionApi.list(currentPlatform.id, { ...(q.trim() ? { q: q.trim() } : {}), ...(source ? { source_platform_code: source as 'OZON' } : {}) }); setItems(result.data); setMeta(result.meta); } catch (error) { message.error(apiErrorMessage(error)); } finally { setLoading(false); } }, [currentPlatform, message, q, source]);
|
||||
useEffect(() => { void load(); }, [load]);
|
||||
const create = async (values: { title?: string; note?: string }) => { try { await collectionApi.create({ title: values.title?.trim() || undefined, note: values.note?.trim() || null }); message.success('商品草稿已加入采集箱'); setCreateOpen(false); form.resetFields(); await load(); } catch (error) { message.error(apiErrorMessage(error)); } };
|
||||
const remove = (ids: string[], all = false) => modal.confirm({ title: all ? '清空采集箱' : '删除采集商品', content: all ? `将清空当前 ${meta.active_count} 条采集草稿,不会删除或下架任何平台商品。确定继续吗?` : '仅删除 Atlas 内的采集草稿,不会删除或下架任何平台商品。确定继续吗?', okText: all ? '清空' : '删除', okButtonProps: { danger: true }, onOk: async () => { try { const result = all ? await collectionApi.clear(meta.active_count) : await collectionApi.bulkDelete(ids); message.success(`已删除 ${result.deleted_count} 条采集草稿`); setSelected([]); await load(); } catch (error) { message.error(apiErrorMessage(error)); } } });
|
||||
const columns: TableProps<CollectionItem>['columns'] = [
|
||||
{ title: '产品名称', dataIndex: 'title', render: (value) => value || '未命名商品' }, { title: '来源', dataIndex: 'source', width: 110, render: (value) => <Tag>{value.kind === 'manual' ? '手动创建' : value.platform_code}</Tag> }, { title: 'SKU', dataIndex: 'variant_summary', width: 80, render: (value) => value.count }, { title: '采集状态', dataIndex: 'collection_status', width: 120, render: (value) => statusLabel[value] ?? value }, { title: '当前平台上架', dataIndex: 'listing_summary', width: 150, render: (value) => <Typography.Text type="secondary">{value.detail}</Typography.Text> }, { title: '备注', dataIndex: 'note', ellipsis: true, render: (value) => value || '—' }, { title: '更新时间', dataIndex: 'updated_at', width: 170, render: (value) => new Date(value).toLocaleString('zh-CN', { hour12: false }) }, { title: '操作', width: 150, render: (_, item) => <Space><Button type="link" size="small" onClick={() => message.info('商品编辑将在下一任务提供')}>编辑上架</Button><Button type="link" danger size="small" onClick={() => remove([item.id])}>删除</Button></Space> },
|
||||
];
|
||||
return <Card title="采集箱" extra={<Space><Button icon={<ReloadOutlined />} onClick={() => void load()} /><Button danger disabled={!items.length} onClick={() => remove([], true)}>清空采集箱</Button><Button danger icon={<DeleteOutlined />} disabled={!selected.length} onClick={() => remove(selected)}>批量删除</Button><Button type="primary" icon={<PlusOutlined />} onClick={() => setCreateOpen(true)}>手动创建商品</Button></Space>}>
|
||||
<Progress percent={meta.collection_limit ? Math.round(meta.active_count / meta.collection_limit * 100) : 0} format={() => `${meta.active_count} / ${meta.collection_limit}`} style={{ maxWidth: 420, marginBottom: 18 }} />
|
||||
<Space wrap style={{ marginBottom: 16 }}><Input value={q} onChange={(e) => setQ(e.target.value)} placeholder="搜索产品名称" allowClear style={{ width: 220 }} /><Select allowClear placeholder="采集来源" value={source} onChange={setSource} style={{ width: 140 }} options={[{ value: 'OZON', label: 'Ozon' }, { value: '1688', label: '1688' }, { value: 'TAOBAO', label: '淘宝' }, { value: 'TMALL', label: '天猫' }]} /><Button type="primary" onClick={() => void load()}>查询</Button></Space>
|
||||
<Table rowKey="id" loading={loading} columns={columns} dataSource={items} pagination={false} rowSelection={{ selectedRowKeys: selected, onChange: (keys) => setSelected(keys.map(String)) }} locale={{ emptyText: '暂无采集商品,点击右上角手动创建商品' }} />
|
||||
<Modal title="手动创建商品" open={createOpen} footer={null} onCancel={() => setCreateOpen(false)} destroyOnHidden><Form form={form} layout="vertical" onFinish={create}><Form.Item name="title" label="商品名称"><Input maxLength={300} placeholder="可稍后在商品编辑中完善" /></Form.Item><Form.Item name="note" label="备注"><Input.TextArea maxLength={2000} /></Form.Item><Space><Button type="primary" htmlType="submit">创建草稿</Button><Button onClick={() => setCreateOpen(false)}>取消</Button></Space></Form></Modal>
|
||||
</Card>;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user