import React, { useState, useEffect, useCallback } from 'react'; import { useNavigate } from 'react-router-dom'; import { Card, Table, Button, Space, Tag, Input, InputNumber, Select, Row, Col, Modal, message, Tooltip, Badge, Dropdown, Menu, Image, Typography, DatePicker, Form, Drawer, Alert, Spin, } from 'antd'; import { PlusOutlined, EditOutlined, DeleteOutlined, SyncOutlined, UploadOutlined, FilterOutlined, SortAscendingOutlined, SortDescendingOutlined, MoreOutlined, EyeOutlined, CopyOutlined, ArrowUpOutlined, ArrowDownOutlined, DollarOutlined, ShoppingOutlined, CheckCircleOutlined, CloseCircleOutlined, ExclamationCircleOutlined, } from '@ant-design/icons'; import type { ColumnsType, TablePaginationConfig } from 'antd/es/table'; import type { FilterValue, SorterResult, TableCurrentDataSource } from 'antd/es/table/interface'; import moment from 'moment'; const { Title, Text } = Typography; const { Option } = Select; const { RangePicker } = DatePicker; const { Search } = Input; interface Product { id: string; sku: string; name: string; image: string; category: string; price: number; costPrice: number; profit: number; roi: number; stock: number; status: 'DRAFT' | 'PRICED' | 'LISTED' | 'SYNCING' | 'LIVE' | 'SYNC_FAILED' | 'OFFLINE'; platformStatus: Record; createdAt: string; updatedAt: string; } interface FilterState { keyword: string; status: string[]; platform: string[]; category: string[]; roiRange: [number, number] | null; dateRange: any; } interface SortState { field: string; order: 'ascend' | 'descend' | null; } const STATUS_CONFIG: Record = { DRAFT: { color: 'default', text: '草稿', icon: }, PRICED: { color: 'processing', text: '已定价', icon: }, LISTED: { color: 'warning', text: '已上架', icon: }, SYNCING: { color: 'processing', text: '同步中', icon: }, LIVE: { color: 'success', text: '已在线', icon: }, SYNC_FAILED: { color: 'error', text: '同步失败', icon: }, OFFLINE: { color: 'default', text: '已下架', icon: }, }; const PLATFORMS = ['Amazon', 'eBay', 'Shopee', 'TikTok', 'Shopify']; const CATEGORIES = ['工业自动化', '电子元器件', '工具设备', '仪器仪表', '安防设备']; const MOCK_PRODUCTS: Product[] = [ { id: '1', sku: 'TP-TEMP-001', name: '工业温度传感器 Pro', image: 'https://via.placeholder.com/80x80?text=Product', category: '工业自动化', price: 89.99, costPrice: 45.00, profit: 44.99, roi: 99.98, stock: 256, status: 'LIVE', platformStatus: { Amazon: 'LIVE', eBay: 'LIVE', Shopee: 'PENDING' }, createdAt: '2025-12-15', updatedAt: '2026-03-18', }, { id: '2', sku: 'TP-PRES-002', name: '压力传感器 Digital', image: 'https://via.placeholder.com/80x80?text=Product', category: '工业自动化', price: 129.99, costPrice: 65.00, profit: 64.99, roi: 99.98, stock: 128, status: 'DRAFT', platformStatus: {}, createdAt: '2026-03-10', updatedAt: '2026-03-10', }, { id: '3', sku: 'TP-FLOW-003', name: '流量计 Ultra', image: 'https://via.placeholder.com/80x80?text=Product', category: '仪器仪表', price: 299.99, costPrice: 150.00, profit: 149.99, roi: 99.99, stock: 64, status: 'PRICED', platformStatus: {}, createdAt: '2026-03-15', updatedAt: '2026-03-16', }, { id: '4', sku: 'TP-MOTR-004', name: '步进电机 57型', image: 'https://via.placeholder.com/80x80?text=Product', category: '工业自动化', price: 59.99, costPrice: 30.00, profit: 29.99, roi: 99.97, stock: 512, status: 'LISTED', platformStatus: { Amazon: 'LISTED' }, createdAt: '2026-03-01', updatedAt: '2026-03-17', }, { id: '5', sku: 'TP-CTRL-005', name: 'PLC控制器 Mini', image: 'https://via.placeholder.com/80x80?text=Product', category: '工业自动化', price: 199.99, costPrice: 100.00, profit: 99.99, roi: 99.99, stock: 32, status: 'SYNCING', platformStatus: { Amazon: 'SYNCING', eBay: 'SYNCING' }, createdAt: '2026-03-18', updatedAt: '2026-03-18', }, { id: '6', sku: 'TP-SENS-006', name: '光电传感器', image: 'https://via.placeholder.com/80x80?text=Product', category: '工业自动化', price: 39.99, costPrice: 20.00, profit: 19.99, roi: 99.95, stock: 0, status: 'SYNC_FAILED', platformStatus: { Amazon: 'FAILED' }, createdAt: '2026-03-05', updatedAt: '2026-03-18', }, { id: '7', sku: 'TP-VALV-007', name: '电磁阀 24V', image: 'https://via.placeholder.com/80x80?text=Product', category: '工具设备', price: 79.99, costPrice: 40.00, profit: 39.99, roi: 99.98, stock: 200, status: 'OFFLINE', platformStatus: { Amazon: 'OFFLINE', eBay: 'OFFLINE' }, createdAt: '2025-11-20', updatedAt: '2026-02-28', }, ]; export const ProductList: React.FC = () => { const navigate = useNavigate(); const [products, setProducts] = useState([]); const [loading, setLoading] = useState(false); const [selectedRows, setSelectedRows] = useState([]); const [filterVisible, setFilterVisible] = useState(false); const [sortDrawerVisible, setSortDrawerVisible] = useState(false); const [pricingModalVisible, setPricingModalVisible] = useState(false); const [currentProduct, setCurrentProduct] = useState(null); const [syncLoading, setSyncLoading] = useState>({}); const [filters, setFilters] = useState({ keyword: '', status: [], platform: [], category: [], roiRange: null, dateRange: null, }); const [sort, setSort] = useState({ field: 'updatedAt', order: 'descend', }); useEffect(() => { fetchProducts(); }, []); const fetchProducts = useCallback(async () => { setLoading(true); await new Promise(resolve => setTimeout(resolve, 500)); setProducts(MOCK_PRODUCTS); setLoading(false); }, []); const handleFilterChange = (key: keyof FilterState, value: any) => { setFilters(prev => ({ ...prev, [key]: value })); }; const handleSortChange = (field: string, order: 'ascend' | 'descend') => { setSort({ field, order }); setSortDrawerVisible(false); message.success(`已按 ${field} ${order === 'ascend' ? '升序' : '降序'} 排序`); }; const handleTableChange = ( pagination: TablePaginationConfig, filters: Record, sorter: SorterResult | SorterResult[], extra: TableCurrentDataSource ) => { if (!Array.isArray(sorter) && sorter.field) { setSort({ field: sorter.field as string, order: sorter.order || null, }); } }; const handleSearch = (value: string) => { handleFilterChange('keyword', value); }; const handleResetFilters = () => { setFilters({ keyword: '', status: [], platform: [], category: [], roiRange: null, dateRange: null, }); message.success('筛选条件已重置'); }; const handleAddProduct = () => { navigate('/dashboard/product/publish'); }; const handleEditProduct = (record: Product) => { navigate(`/dashboard/product/detail/${record.id}`); }; const handleViewProduct = (record: Product) => { navigate(`/dashboard/product/detail/${record.id}`); }; const handleDeleteProduct = (record: Product) => { Modal.confirm({ title: '确认删除', content: `确定要删除商品 "${record.name}" 吗?此操作不可恢复。`, okText: '删除', okType: 'danger', onOk: () => { setProducts(products.filter(p => p.id !== record.id)); message.success('商品删除成功'); }, }); }; const handleDuplicateProduct = (record: Product) => { const newProduct: Product = { ...record, id: `${Date.now()}`, sku: `${record.sku}-COPY`, name: `${record.name} (复制)`, status: 'DRAFT', platformStatus: {}, createdAt: moment().format('YYYY-MM-DD'), updatedAt: moment().format('YYYY-MM-DD'), }; setProducts([newProduct, ...products]); message.success('商品复制成功'); }; const handlePricing = (record: Product) => { setCurrentProduct(record); setPricingModalVisible(true); }; const handlePublish = (record: Product) => { Modal.confirm({ title: '确认上架', content: `确定要上架商品 "${record.name}" 吗?`, onOk: () => { updateProductStatus(record.id, 'LISTED'); message.success('商品上架成功'); }, }); }; const handleSync = async (record: Product) => { setSyncLoading(prev => ({ ...prev, [record.id]: true })); updateProductStatus(record.id, 'SYNCING'); message.loading({ content: '正在同步到平台...', key: record.id }); await new Promise(resolve => setTimeout(resolve, 2000)); const success = Math.random() > 0.3; if (success) { updateProductStatus(record.id, 'LIVE'); message.success({ content: '同步成功', key: record.id }); } else { updateProductStatus(record.id, 'SYNC_FAILED'); message.error({ content: '同步失败,请重试', key: record.id }); } setSyncLoading(prev => ({ ...prev, [record.id]: false })); }; const handleOffline = (record: Product) => { Modal.confirm({ title: '确认下架', content: `确定要下架商品 "${record.name}" 吗?`, onOk: () => { updateProductStatus(record.id, 'OFFLINE'); message.success('商品已下架'); }, }); }; const handleRetrySync = (record: Product) => { handleSync(record); }; const updateProductStatus = (productId: string, status: Product['status']) => { setProducts(products.map(p => p.id === productId ? { ...p, status, updatedAt: moment().format('YYYY-MM-DD') } : p )); }; const handleBatchDelete = () => { if (selectedRows.length === 0) { message.warning('请先选择要删除的商品'); return; } Modal.confirm({ title: '确认批量删除', content: `确定要删除选中的 ${selectedRows.length} 个商品吗?`, okText: '删除', okType: 'danger', onOk: () => { const ids = selectedRows.map(r => r.id); setProducts(products.filter(p => !ids.includes(p.id))); setSelectedRows([]); message.success(`成功删除 ${ids.length} 个商品`); }, }); }; const handleBatchPricing = () => { if (selectedRows.length === 0) { message.warning('请先选择要定价的商品'); return; } message.info(`批量定价功能:已选择 ${selectedRows.length} 个商品`); }; const handleBatchPublish = () => { if (selectedRows.length === 0) { message.warning('请先选择要上架的商品'); return; } const pricedProducts = selectedRows.filter(p => p.status === 'PRICED'); if (pricedProducts.length === 0) { message.warning('选中的商品中没有已定价的商品'); return; } Modal.confirm({ title: '确认批量上架', content: `确定要上架选中的 ${pricedProducts.length} 个商品吗?`, onOk: () => { pricedProducts.forEach(p => updateProductStatus(p.id, 'LISTED')); setSelectedRows([]); message.success(`成功上架 ${pricedProducts.length} 个商品`); }, }); }; const handleBatchSync = () => { if (selectedRows.length === 0) { message.warning('请先选择要同步的商品'); return; } const listableProducts = selectedRows.filter(p => p.status === 'LISTED' || p.status === 'LIVE'); if (listableProducts.length === 0) { message.warning('选中的商品中没有可同步的商品'); return; } message.loading('正在批量同步...'); setTimeout(() => { listableProducts.forEach(p => handleSync(p)); setSelectedRows([]); }, 500); }; const filteredProducts = products.filter(product => { if (filters.keyword && !product.name.toLowerCase().includes(filters.keyword.toLowerCase()) && !product.sku.toLowerCase().includes(filters.keyword.toLowerCase())) { return false; } if (filters.status.length > 0 && !filters.status.includes(product.status)) { return false; } if (filters.category.length > 0 && !filters.category.includes(product.category)) { return false; } return true; }); const sortedProducts = [...filteredProducts].sort((a, b) => { const field = sort.field as keyof Product; const aValue = a[field]; const bValue = b[field]; if (sort.order === 'ascend') { return aValue > bValue ? 1 : -1; } else { return aValue < bValue ? 1 : -1; } }); const columns: ColumnsType = [ { title: '商品信息', dataIndex: 'name', key: 'name', render: (text, record) => (
{text}
SKU: {record.sku}
{record.category}
), sorter: true, }, { title: '售价', dataIndex: 'price', key: 'price', render: (value) => ${value.toFixed(2)}, sorter: true, }, { title: '成本', dataIndex: 'costPrice', key: 'costPrice', render: (value) => ${value.toFixed(2)}, sorter: true, }, { title: '利润', dataIndex: 'profit', key: 'profit', render: (value) => ${value.toFixed(2)}, sorter: true, }, { title: 'ROI', dataIndex: 'roi', key: 'roi', render: (value) => {value.toFixed(2)}%, sorter: true, }, { title: '库存', dataIndex: 'stock', key: 'stock', render: (value) => ( 50 ? '#52c41a' : value > 0 ? '#faad14' : '#ff4d4f' }} /> ), sorter: true, }, { title: '状态', dataIndex: 'status', key: 'status', render: (status) => { const config = STATUS_CONFIG[status]; return ( {config.text} ); }, filters: Object.entries(STATUS_CONFIG).map(([key, config]) => ({ text: config.text, value: key, })), }, { title: '平台状态', key: 'platformStatus', render: (_, record) => ( {Object.entries(record.platformStatus).map(([platform, status]) => ( {platform.charAt(0)} ))} ), }, { title: '更新时间', dataIndex: 'updatedAt', key: 'updatedAt', sorter: true, }, { title: '操作', key: 'action', fixed: 'right', width: 200, render: (_, record) => { const menu = ( } onClick={() => handleViewProduct(record)}> 查看详情 } onClick={() => handleEditProduct(record)}> 编辑 } onClick={() => handleDuplicateProduct(record)}> 复制 } onClick={() => handlePricing(record)}> 定价 {record.status === 'PRICED' && ( } onClick={() => handlePublish(record)}> 上架 )} {(record.status === 'LISTED' || record.status === 'LIVE') && ( } onClick={() => handleSync(record)} disabled={syncLoading[record.id]} > 同步到平台 )} {record.status === 'SYNC_FAILED' && ( } onClick={() => handleRetrySync(record)}> 重试同步 )} {(record.status === 'LISTED' || record.status === 'LIVE') && ( } onClick={() => handleOffline(record)}> 下架 )} } danger onClick={() => handleDeleteProduct(record)}> 删除 ); return ( ); }, }, ]; const rowSelection = { selectedRowKeys: selectedRows.map(r => r.id), onChange: (selectedRowKeys: React.Key[], selectedRows: Product[]) => { setSelectedRows(selectedRows); }, }; return (

1. 新建商品:先保存到本地系统(草稿状态)

2. 定价上架:完成定价后上架到本地(已上架状态)

3. 平台同步:手动或自动同步到各销售平台(同步中 → 已在线)

所有商品数据以本地系统为准,平台数据通过同步机制保持一致

} type="info" showIcon style={{ marginBottom: 16 }} /> 商品列表 {selectedRows.length > 0 && ( } style={{ marginBottom: 16 }} /> )} `共 ${total} 条`, }} /> setFilterVisible(false)} visible={filterVisible} width={400} >
handleFilterChange('dateRange', dates)} style={{ width: '100%' }} />
setSortDrawerVisible(false)} visible={sortDrawerVisible} width={300} > {[ { key: 'name', label: '商品名称' }, { key: 'price', label: '售价' }, { key: 'profit', label: '利润' }, { key: 'roi', label: 'ROI' }, { key: 'stock', label: '库存' }, { key: 'updatedAt', label: '更新时间' }, ].map(item => (
{item.label}
))}
setPricingModalVisible(false)} footer={null} width={600} > {currentProduct && (
{currentProduct.name} ${currentProduct.price.toFixed(2)} )}
); }; export default ProductList;