diff --git a/.umirc.ts b/.umirc.ts index f06eec5..4d9e0ad 100644 --- a/.umirc.ts +++ b/.umirc.ts @@ -97,10 +97,21 @@ export default defineConfig({ path: '/site/list', component: './Site/List', }, + { + name: 'Woo产品列表', + path: '/site/woocommerce/product/list', + component: './Woo/Product/List', + }, + { + name: 'Woo标签工具', + path: '/site/woocommerce/product/tool/tag', + component: './Woo/Product/TagTool', + }, ], }, + { - name: '商品管理', + name: '产品管理', path: '/product', access: 'canSeeProduct', routes: [ @@ -109,6 +120,11 @@ export default defineConfig({ path: '/product/list', component: './Product/List', }, + { + name: "产品分类", + path: '/product/category', + component: './Product/Category', + }, { name: '产品属性', path: '/product/attribute', @@ -116,20 +132,10 @@ export default defineConfig({ }, // sync { - name: '同步商品', + name: '同步产品', path: '/product/sync', component: './Product/Sync', }, - { - name: 'WP商品列表', - path: '/product/wp_list', - component: './Product/WpList', - }, - { - name: 'WP工具箱', - path: '/product/wp_tool', - component: './Product/WpTool', - }, ], }, { diff --git a/src/pages/Category/index.tsx b/src/pages/Category/index.tsx index 53cda7a..0a076b0 100644 --- a/src/pages/Category/index.tsx +++ b/src/pages/Category/index.tsx @@ -25,7 +25,7 @@ import { productcontrollerGetcategoryattributes, productcontrollerUpdatecategory, } from '@/servers/api/product'; -import { attributes } from '../Product/Attribute/consts'; +import { attributes } from '../Attribute/consts'; const { Sider, Content } = Layout; diff --git a/src/pages/Product/Category/index.tsx b/src/pages/Product/Category/index.tsx new file mode 100644 index 0000000..b96283f --- /dev/null +++ b/src/pages/Product/Category/index.tsx @@ -0,0 +1,296 @@ +import { PlusOutlined } from '@ant-design/icons'; +import { + PageContainer, +} from '@ant-design/pro-components'; +import { request } from '@umijs/max'; +import { + Button, + Card, + Form, + Input, + Layout, + List, + Modal, + Popconfirm, + Select, + message, +} from 'antd'; +import React, { useEffect, useState } from 'react'; +import { + productcontrollerCreatecategory, + productcontrollerCreatecategoryattribute, + productcontrollerDeletecategory, + productcontrollerDeletecategoryattribute, + productcontrollerGetcategoriesall, + productcontrollerGetcategoryattributes, + productcontrollerUpdatecategory, +} from '@/servers/api/product'; +import { attributes } from '../Attribute/consts'; + +const { Sider, Content } = Layout; + +const CategoryPage: React.FC = () => { + const [categories, setCategories] = useState([]); + const [loadingCategories, setLoadingCategories] = useState(false); + const [selectedCategory, setSelectedCategory] = useState(null); + const [categoryAttributes, setCategoryAttributes] = useState([]); + const [loadingAttributes, setLoadingAttributes] = useState(false); + + const [isCategoryModalVisible, setIsCategoryModalVisible] = useState(false); + const [categoryForm] = Form.useForm(); + const [editingCategory, setEditingCategory] = useState(null); + + const [isAttributeModalVisible, setIsAttributeModalVisible] = useState(false); + const [availableDicts, setAvailableDicts] = useState([]); + const [selectedDictIds, setSelectedDictIds] = useState([]); + + const fetchCategories = async () => { + setLoadingCategories(true); + try { + const res = await productcontrollerGetcategoriesall(); + setCategories(res?.data || []); + } catch (error) { + message.error('获取分类列表失败'); + } + setLoadingCategories(false); + }; + + useEffect(() => { + fetchCategories(); + }, []); + + const fetchCategoryAttributes = async (categoryId: number) => { + setLoadingAttributes(true); + try { + const res = await productcontrollerGetcategoryattributes({ id: categoryId }); + setCategoryAttributes(res?.data || []); + } catch (error) { + message.error('获取分类属性失败'); + } + setLoadingAttributes(false); + }; + + useEffect(() => { + if (selectedCategory) { + fetchCategoryAttributes(selectedCategory.id); + } else { + setCategoryAttributes([]); + } + }, [selectedCategory]); + + const handleCategorySubmit = async (values: any) => { + try { + if (editingCategory) { + await productcontrollerUpdatecategory({ id: editingCategory.id }, values); + message.success('更新成功'); + } else { + await productcontrollerCreatecategory(values); + message.success('创建成功'); + } + setIsCategoryModalVisible(false); + fetchCategories(); + } catch (error: any) { + message.error(error.message || '操作失败'); + } + }; + + const handleDeleteCategory = async (id: number) => { + try { + await productcontrollerDeletecategory({ id }); + message.success('删除成功'); + if (selectedCategory?.id === id) { + setSelectedCategory(null); + } + fetchCategories(); + } catch (error: any) { + message.error(error.message || '删除失败'); + } + }; + + const handleAddAttribute = async () => { + // Fetch all dicts and filter those that are allowed attributes + try { + const res = await request('/dict/list'); + // Defensive check for response structure: handle both raw array and wrapped response + const list = Array.isArray(res) ? res : (res?.data || []); + const filtered = list.filter((d: any) => attributes.has(d.name)); + // Filter out already added attributes + const existingDictIds = new Set(categoryAttributes.map((ca: any) => ca.dictId)); + const available = filtered.filter((d: any) => !existingDictIds.has(d.id)); + setAvailableDicts(available); + setSelectedDictIds([]); + setIsAttributeModalVisible(true); + } catch (error) { + message.error('获取属性字典失败'); + } + }; + + const handleAttributeSubmit = async () => { + if (selectedDictIds.length === 0) { + message.warning('请选择属性'); + return; + } + try { + // Loop through selected IDs and create attribute for each + await Promise.all(selectedDictIds.map(dictId => + productcontrollerCreatecategoryattribute({ + categoryId: selectedCategory.id, + dictId: dictId, + }) + )); + message.success('添加属性成功'); + setIsAttributeModalVisible(false); + fetchCategoryAttributes(selectedCategory.id); + } catch (error: any) { + message.error(error.message || '添加失败'); + } + }; + + const handleDeleteAttribute = async (id: number) => { + try { + await productcontrollerDeletecategoryattribute({ id }); + message.success('移除属性成功'); + fetchCategoryAttributes(selectedCategory.id); + } catch (error: any) { + message.error(error.message || '移除失败'); + } + }; + + return ( + + + +
+ 分类列表 + +
+ ( + setSelectedCategory(item)} + actions={[ + { + e.stopPropagation(); + setEditingCategory(item); + categoryForm.setFieldsValue(item); + setIsCategoryModalVisible(true); + }} + > + 编辑 + , + { + e?.stopPropagation(); + handleDeleteCategory(item.id); + }} + onCancel={(e) => e?.stopPropagation()} + > + e.stopPropagation()} style={{ color: 'red' }}>删除 + , + ]} + > + + + )} + /> +
+ + {selectedCategory ? ( + 添加关联属性}> + ( + handleDeleteAttribute(item.id)} + > + + + ]} + > + + + )} + /> + + ) : ( +
+ 请选择左侧分类 +
+ )} +
+
+ + categoryForm.submit()} + onCancel={() => setIsCategoryModalVisible(false)} + > +
+ + + + + + +
+
+ + setIsAttributeModalVisible(false)} + > +
+ +