import { productcontrollerCreateproduct, productcontrollerGetcategoriesall, productcontrollerGetcategoryattributes, productcontrollerGetproductlist, } from '@/servers/api/product'; import { request } from '@umijs/max'; import { ActionType, PageContainer, ProCard, ProColumns, ProForm, ProFormSelect, ProTable, } from '@ant-design/pro-components'; import { Button, Table, Tag, message } from 'antd'; import React, { useEffect, useState, useRef } from 'react'; import CreateModal from './components/CreateModal'; import EditForm from '../List/EditForm'; const PermutationPage: React.FC = () => { const [categoryId, setCategoryId] = useState(); const [attributes, setAttributes] = useState([]); const [loading, setLoading] = useState(false); const [attributeValues, setAttributeValues] = useState>({}); const [permutations, setPermutations] = useState([]); const [existingProducts, setExistingProducts] = useState>(new Map()); const [productsLoading, setProductsLoading] = useState(false); const [createModalVisible, setCreateModalVisible] = useState(false); const [selectedPermutation, setSelectedPermutation] = useState(null); const [categories, setCategories] = useState([]); const [form] = ProForm.useForm(); // Create a ref to mock ActionType for EditForm const actionRef = useRef(); useEffect(() => { productcontrollerGetcategoriesall().then((res) => { const list = Array.isArray(res) ? res : (res?.data || []); setCategories(list); if (list.length > 0) { setCategoryId(list[0].id); form.setFieldValue('categoryId', list[0].id); } }); }, []); const fetchProducts = async (catId: number) => { setProductsLoading(true); try { const productRes = await productcontrollerGetproductlist({ categoryId: catId, pageSize: 2000, current: 1 }); const products = productRes.data?.items || []; const productMap = new Map(); products.forEach((p: any) => { if (p.attributes && Array.isArray(p.attributes)) { const key = generateAttributeKey(p.attributes); if (key) productMap.set(key, p); } }); setExistingProducts(productMap); } catch (error) { console.error(error); message.error('获取现有产品失败'); } finally { setProductsLoading(false); } }; // Assign reload method to actionRef useEffect(() => { actionRef.current = { reload: async () => { if (categoryId) await fetchProducts(categoryId); }, reloadAndRest: async () => { if (categoryId) await fetchProducts(categoryId); }, reset: () => {}, clearSelected: () => {}, } as any; }, [categoryId]); // Fetch attributes and products when category changes useEffect(() => { if (!categoryId) { setAttributes([]); setAttributeValues({}); setPermutations([]); setExistingProducts(new Map()); return; } const fetchData = async () => { setLoading(true); try { // 1. Fetch Attributes const attrRes = await productcontrollerGetcategoryattributes({ id: categoryId }); const attrs = Array.isArray(attrRes) ? attrRes : (attrRes?.data || []); setAttributes(attrs); // 2. Fetch Attribute Values (Dict Items) const valuesMap: Record = {}; for (const attr of attrs) { const dictId = attr.dict?.id || attr.dictId; if (dictId) { const itemsRes = await request('/dict/items', { params: { dictId } }); valuesMap[attr.name] = itemsRes || []; } } setAttributeValues(valuesMap); // 3. Fetch Existing Products await fetchProducts(categoryId); } catch (error) { console.error(error); message.error('获取数据失败'); } finally { setLoading(false); } }; fetchData(); }, [categoryId]); // Generate Permutations when attributes or values change useEffect(() => { if (attributes.length === 0 || Object.keys(attributeValues).length === 0) { setPermutations([]); return; } const validAttributes = attributes.filter(attr => attributeValues[attr.name]?.length > 0); if (validAttributes.length === 0) { setPermutations([]); return; } const generateCombinations = (index: number, current: any): any[] => { if (index === validAttributes.length) { return [current]; } const attr = validAttributes[index]; const values = attributeValues[attr.name]; let res: any[] = []; for (const val of values) { res = res.concat(generateCombinations(index + 1, { ...current, [attr.name]: val })); } return res; }; const combos = generateCombinations(0, {}); setPermutations(combos); }, [attributes, attributeValues]); const generateAttributeKey = (attrs: any[]) => { const parts = attrs.map(a => { const key = a.dict?.name || a.dictName; const val = a.name || a.value; return `${key}:${val}`; }); return parts.sort().join('|'); }; const generateKeyFromPermutation = (perm: any) => { const parts = Object.keys(perm).map(attrName => { const valItem = perm[attrName]; const val = valItem.name; return `${attrName}:${val}`; }); return parts.sort().join('|'); }; const handleAdd = (record: any) => { setSelectedPermutation(record); setCreateModalVisible(true); }; const columns: any[] = [ ...attributes.map(attr => ({ title: attr.title || attr.name, dataIndex: attr.name, width: 100, // Make columns narrower render: (item: any) => item?.name || '-', sorter: (a: any, b: any) => { const valA = a[attr.name]?.name || ''; const valB = b[attr.name]?.name || ''; return valA.localeCompare(valB); }, filters: attributeValues[attr.name]?.map((v: any) => ({ text: v.name, value: v.name })), onFilter: (value: any, record: any) => record[attr.name]?.name === value, })), { title: '现有 SKU', key: 'sku', width: 150, sorter: (a: any, b: any) => { const keyA = generateKeyFromPermutation(a); const productA = existingProducts.get(keyA); const skuA = productA?.sku || ''; const keyB = generateKeyFromPermutation(b); const productB = existingProducts.get(keyB); const skuB = productB?.sku || ''; return skuA.localeCompare(skuB); }, filters: [ { text: '已存在', value: 'exists' }, { text: '未创建', value: 'missing' }, ], onFilter: (value: any, record: any) => { const key = generateKeyFromPermutation(record); const exists = existingProducts.has(key); if (value === 'exists') return exists; if (value === 'missing') return !exists; return true; }, render: (_: any, record: any) => { const key = generateKeyFromPermutation(record); const product = existingProducts.get(key); return product ? {product.sku} : '-'; }, }, { title: '操作', key: 'action', width: 100, render: (_: any, record: any) => { const key = generateKeyFromPermutation(record); const product = existingProducts.get(key); if (product) { return ( 编辑} /> ); } return ( ); }, }, ]; return ( ({ label: item.name, value: item.id, }))} fieldProps={{ onChange: (val) => setCategoryId(val as number), }} /> {categoryId && ( generateKeyFromPermutation(record)} pagination={{ defaultPageSize: 50, showSizeChanger: true, pageSizeOptions: ['50', '100', '200', '500', '1000', '2000'] }} scroll={{ x: 'max-content' }} search={false} toolBarRender={false} /> )} {selectedPermutation && ( setCreateModalVisible(false)} onSuccess={() => { setCreateModalVisible(false); if (categoryId) fetchProducts(categoryId); }} category={categories.find(c => c.id === categoryId) || null} permutation={selectedPermutation} attributes={attributes} /> )} ); }; export default PermutationPage;