first version
This commit is contained in:
@@ -0,0 +1,151 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { Button, Space, Tag, Typography } from 'antd';
|
||||
import { NodeExpandOutlined } from '@ant-design/icons';
|
||||
import XinTable from '@/components/XinTable';
|
||||
import type { XinTableColumn, XinTableProps } from '@/components/XinTable/typings.ts';
|
||||
import type IProductCategory from '@/domain/iProductCategory.ts';
|
||||
import { CATEGORY_STATUS_MAP } from '@/domain/iProductCategory.ts';
|
||||
import { getCategoryTable } from '@/api/product/category.ts';
|
||||
|
||||
const { Title, Text } = Typography;
|
||||
|
||||
/**
|
||||
* 递归收集全部节点 id(用于展开整棵树)
|
||||
*/
|
||||
function collectAllIds(nodes: IProductCategory[]): number[] {
|
||||
const ids: number[] = [];
|
||||
const walk = (list: IProductCategory[]) => {
|
||||
list.forEach((node) => {
|
||||
if (node.id !== undefined) {
|
||||
ids.push(node.id);
|
||||
}
|
||||
if (node.children?.length) {
|
||||
walk(node.children);
|
||||
}
|
||||
});
|
||||
};
|
||||
walk(nodes);
|
||||
return ids;
|
||||
}
|
||||
|
||||
/**
|
||||
* 商品分类管理(多级分类树表)
|
||||
*/
|
||||
const ProductCategoryPage: React.FC = () => {
|
||||
const [expandedKeys, setExpandedKeys] = useState<number[]>([]);
|
||||
const [allIds, setAllIds] = useState<number[]>([]);
|
||||
const [categoryTree, setCategoryTree] = useState<IProductCategory[]>([]);
|
||||
|
||||
const loadTree = async () => {
|
||||
const res = await getCategoryTable();
|
||||
const tree = res.data.data ?? [];
|
||||
setCategoryTree(tree);
|
||||
setAllIds(collectAllIds(tree));
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
loadTree();
|
||||
}, []);
|
||||
|
||||
const columns: XinTableColumn<IProductCategory>[] = [
|
||||
{
|
||||
title: '分类名称',
|
||||
dataIndex: 'name',
|
||||
valueType: 'text',
|
||||
required: true,
|
||||
rules: [{ required: true, message: '请输入分类名称' }],
|
||||
},
|
||||
{
|
||||
title: '上级分类',
|
||||
dataIndex: 'parent_id',
|
||||
valueType: 'treeSelect',
|
||||
hideInTable: true,
|
||||
hideInSearch: true,
|
||||
initialValue: 0,
|
||||
fieldProps: {
|
||||
treeData: [{ id: 0, name: '顶级分类', children: categoryTree }],
|
||||
fieldNames: { label: 'name', value: 'id', children: 'children' },
|
||||
placeholder: '默认顶级分类',
|
||||
treeDefaultExpandAll: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '排序',
|
||||
dataIndex: 'sort',
|
||||
valueType: 'digit',
|
||||
hideInSearch: true,
|
||||
fieldProps: { min: 0 },
|
||||
align: 'center',
|
||||
},
|
||||
{
|
||||
title: '状态',
|
||||
dataIndex: 'status',
|
||||
valueType: 'radioButton',
|
||||
initialValue: 1,
|
||||
hideInSearch: true,
|
||||
fieldProps: {
|
||||
options: [
|
||||
{ value: 1, label: '正常' },
|
||||
{ value: 0, label: '停用' },
|
||||
],
|
||||
},
|
||||
render: (_, record) => {
|
||||
const item = CATEGORY_STATUS_MAP[record.status ?? 1];
|
||||
return <Tag color={item?.color}>{item?.text}</Tag>;
|
||||
},
|
||||
align: 'center',
|
||||
},
|
||||
];
|
||||
|
||||
const tableProps: XinTableProps<IProductCategory> = {
|
||||
api: '/product/category',
|
||||
columns,
|
||||
rowKey: 'id',
|
||||
accessName: 'product.category',
|
||||
// 后端直接返回分类树,不走分页接口
|
||||
handleRequest: async () => {
|
||||
const res = await getCategoryTable();
|
||||
const tree = res.data.data ?? [];
|
||||
setCategoryTree(tree);
|
||||
setAllIds(collectAllIds(tree));
|
||||
return { data: tree, total: tree.length };
|
||||
},
|
||||
pagination: { pageSize: 200 },
|
||||
expandable: {
|
||||
expandedRowKeys: expandedKeys,
|
||||
onExpandedRowsChange: (keys) => setExpandedKeys([...keys] as number[]),
|
||||
},
|
||||
formProps: {
|
||||
grid: true,
|
||||
colProps: { span: 12 },
|
||||
layout: 'vertical',
|
||||
},
|
||||
modalProps: { width: 640 },
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="mb-5 flex items-start justify-between">
|
||||
<div>
|
||||
<Title level={3}>商品分类</Title>
|
||||
<Text type="secondary">
|
||||
多级分类(如蔬菜/水果/其他),采购单导出与对账筛选按分类归组;有子分类或挂载商品时不可删除。
|
||||
</Text>
|
||||
</div>
|
||||
<Space>
|
||||
<Button
|
||||
icon={<NodeExpandOutlined />}
|
||||
onClick={() =>
|
||||
setExpandedKeys(expandedKeys.length ? [] : allIds)
|
||||
}
|
||||
>
|
||||
{expandedKeys.length ? '全部收起' : '全部展开'}
|
||||
</Button>
|
||||
</Space>
|
||||
</div>
|
||||
<XinTable<IProductCategory> {...tableProps} />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default ProductCategoryPage;
|
||||
Reference in New Issue
Block a user