import { showBatchOperationResult } from '@/utils/showResult'; import { productcontrollerBatchsynctosite, productcontrollerGetproductlist, productcontrollerSynctosite, } from '@/servers/api/product'; import { EditOutlined, SyncOutlined } from '@ant-design/icons'; import { ActionType, ProColumns, ProTable } from '@ant-design/pro-components'; import { request } from '@umijs/max'; import { Button, Card, message, Modal, Progress, Select, Spin, Tag, } from 'antd'; import React, { useEffect, useRef, useState } from 'react'; import EditForm from '../List/EditForm'; import SiteProductCell from './SiteProductCell'; // 定义站点接口 interface Site { id: number; name: string; skuPrefix?: string; isDisabled?: boolean; } // 定义本地产品接口(与后端 Product 实体匹配) interface SiteProduct { id: number; sku: string; name: string; nameCn: string; shortDescription?: string; description?: string; price: number; promotionPrice: number; type: string; categoryId?: number; category?: any; attributes?: any[]; components?: any[]; siteSkus: string[]; source: number; createdAt: Date; updatedAt: Date; } // 定义API响应接口 interface ApiResponse { data: T[]; success: boolean; message?: string; } // 模拟API请求函数 const getSites = async (): Promise> => { const res = await request('/site/list', { method: 'GET', params: { current: 1, pageSize: 1000, }, }); return { data: res.data?.items || [], success: res.success, message: res.message, }; }; const ProductSyncPage: React.FC = () => { const [sites, setSites] = useState([]); const [initialLoading, setInitialLoading] = useState(true); const actionRef = useRef(); const [selectedSiteId, setSelectedSiteId] = useState(''); const [batchSyncModalVisible, setBatchSyncModalVisible] = useState(false); const [syncProgress, setSyncProgress] = useState(0); const [syncing, setSyncing] = useState(false); const [syncResults, setSyncResults] = useState<{ success: number; failed: number; errors: string[]; }>({ success: 0, failed: 0, errors: [] }); const [selectedRowKeys, setSelectedRowKeys] = useState([]); const [selectedRows, setSelectedRows] = useState([]); // 初始化加载站点列表 useEffect(() => { const initializeData = async () => { try { // 获取站点列表 const sitesRes = await getSites(); if (sitesRes.success && sitesRes.data.length > 0) { setSites(sitesRes.data); } } catch (error) { console.error('初始化数据失败:', error); message.error('初始化数据失败'); } finally { setInitialLoading(false); } }; initializeData(); }, []); const syncProductToSite = async ( values: any, record: SiteProduct, site: Site, siteProductId?: string, ) => { try { const hide = message.loading('正在同步...', 0); // 使用 productcontrollerSynctosite API 同步产品到站点 const res = await productcontrollerSynctosite({ productId: Number(record.id), siteId: Number(site.id), } as any); if (!res.success) { hide(); throw new Error(res.message || '同步失败'); } hide(); message.success('同步成功'); return true; } catch (error: any) { message.error('同步失败: ' + (error.message || error.toString())); return false; } }; // 批量同步产品到指定站点 const batchSyncProducts = async (productsToSync?: SiteProduct[]) => { if (!selectedSiteId) { message.error('请选择要同步到的站点'); return; } const targetSite = sites.find((site) => site.id === selectedSiteId); if (!targetSite) { message.error('选择的站点不存在'); return; } // 如果没有传入产品列表,则使用选中的产品 let products = productsToSync || selectedRows; // 如果既没有传入产品也没有选中产品,则同步所有产品 if (!products || products.length === 0) { try { const { data, success } = await productcontrollerGetproductlist({ current: 1, pageSize: 10000, // 获取所有产品 } as any); if (!success || !data?.items) { message.error('获取产品列表失败'); return; } products = data.items as SiteProduct[]; } catch (error) { message.error('获取产品列表失败'); return; } } setSyncing(true); setSyncProgress(0); setSyncResults({ success: 0, failed: 0, errors: [] }); try { // 使用 productcontrollerBatchsynctosite API 批量同步 const productIds = products.map((product) => Number(product.id)); // 更新进度为50%,表示正在处理 setSyncProgress(50); const res = await productcontrollerBatchsynctosite({ productIds: productIds, siteId: Number(targetSite.id), } as any); if (res.success) { const syncedCount = res.data?.synced || 0; const errors = res.data?.errors || []; // 更新进度为100%,表示完成 setSyncProgress(100); setSyncResults({ success: syncedCount, failed: errors.length, errors: errors.map((err: any) => err.error || '未知错误'), }); if (errors.length === 0) { message.success(`批量同步完成,成功同步 ${syncedCount} 个产品`); } else { message.warning( `批量同步完成,成功 ${syncedCount} 个,失败 ${errors.length} 个`, ); } // 刷新表格 actionRef.current?.reload(); } else { throw new Error(res.message || '批量同步失败'); } } catch (error: any) { message.error('批量同步失败: ' + (error.message || error.toString())); } finally { setSyncing(false); } }; // 生成表格列配置 const generateColumns = (): ProColumns[] => { const columns: ProColumns[] = [ { title: 'SKU', dataIndex: 'sku', key: 'sku', width: 150, fixed: 'left', copyable: true, }, { title: '商品信息', key: 'profile', width: 300, fixed: 'left', render: (_, record) => (
{record.name}
} />
价格: {record.price} {record.promotionPrice && ( 促销价: {record.promotionPrice} )}
{/* 属性 */}
{record.attributes?.map((attr: any, idx: number) => ( {attr.dict?.name || attr.name}: {attr.name} ))}
{/* 组成 (如果是 Bundle) */} {record.type === 'bundle' && record.components && record.components.length > 0 && (
Components:
{record.components.map((comp: any, idx: number) => (
{comp.sku} × {comp.quantity}
))}
)}
), }, ]; // 为每个站点生成列 sites.forEach((site: Site) => { const siteColumn: ProColumns = { title: site.name, key: `site_${site.id}`, hideInSearch: true, width: 220, render: (_, record) => { return ( { // 同步成功后刷新表格 actionRef.current?.reload(); }} /> ); }, }; columns.push(siteColumn); }); return columns; }; if (initialLoading) { return ( ); } return ( columns={generateColumns()} actionRef={actionRef} rowKey="id" rowSelection={{ selectedRowKeys, onChange: (keys, rows) => { setSelectedRowKeys(keys); setSelectedRows(rows); }, }} toolBarRender={() => [