商品列表、分类管理、客户等级

This commit is contained in:
liu
2026-08-05 19:28:53 +08:00
parent dfa471bf22
commit 258df92e6c
36 changed files with 472 additions and 516 deletions
+78 -20
View File
@@ -2,7 +2,7 @@ import React, { useEffect, useState } from 'react';
import {
Button,
Drawer,
Form,
Form, Image,
Input,
InputNumber,
message,
@@ -21,7 +21,7 @@ import type IProduct from '@/domain/iProduct.ts';
import type { IBatchPriceUpdate, IPriceMatrixRow } from '@/domain/iProduct.ts';
import { PRODUCT_STATUS_MAP } from '@/domain/iProduct.ts';
import type ICustomerLevel from '@/domain/iCustomerLevel.ts';
import type IProductCategory from '@/domain/iProductCategory.ts';
import type {IProductCategoryTree} from '@/domain/iProductCategory.ts';
import { getLevelOptions } from '@/api/customer/level.ts';
import { getSupplierOptions } from '@/api/customer/supplier.ts';
import type ISupplier from '@/domain/iSupplier.ts';
@@ -36,7 +36,7 @@ const { Title, Text } = Typography;
const ProductGoodsPage: React.FC = () => {
const [levels, setLevels] = useState<ICustomerLevel[]>([]);
const [suppliers, setSuppliers] = useState<ISupplier[]>([]);
const [categoryTree, setCategoryTree] = useState<IProductCategory[]>([]);
const [categoryTree, setCategoryTree] = useState<IProductCategoryTree[]>([]);
// ===== 价格矩阵抽屉 =====
const [matrixOpen, setMatrixOpen] = useState(false);
@@ -161,22 +161,61 @@ const ProductGoodsPage: React.FC = () => {
width: 70,
align: 'center',
},
{
title: '商品图片',
dataIndex: 'image_ids',
valueType: 'image',
fieldProps: {
action: '/product/goods/upload',
maxWidth: 3000,
maxHeight: 3000,
maxSize: 10,
mode: 'multiple',
maxCount: 5,
changeType: "id"
},
render: (_, record) => {
if (!record.images_arr || record.images_arr?.length <= 0) return '-';
return (
<Space wrap={false}>
{record.images_arr.map(i => (
<Image
key={i.id}
src={i.preview_url}
width={60}
height={60}
style={{ objectFit: 'cover', borderRadius: 4 }}
/>
))}
</Space>
);
},
align: 'center',
hideInSearch: true,
colProps: { span: 24 },
},
{
title: '商品名称',
dataIndex: 'name',
valueType: 'text',
colProps: { span: 24 },
fieldProps: {
styles: { input: { height: 52, fontSize: 22 } }
},
required: true,
rules: [{ required: true, message: '请输入商品名称' }],
},
{
title: '商品描述',
dataIndex: 'remark',
valueType: 'text',
hideInSearch: true,
hideInTable: true,
colProps: { span: 24 },
},
{
title: '规格/包规',
dataIndex: 'spec',
valueType: 'text',
hideInSearch: true,
align: "center",
},
{
title: '单位',
@@ -184,12 +223,14 @@ const ProductGoodsPage: React.FC = () => {
valueType: 'text',
hideInSearch: true,
initialValue: '斤',
align: "center",
},
{
title: '分类',
dataIndex: 'category_id',
valueType: 'treeSelect',
required: true,
align: "center",
rules: [{ required: true, message: '请选择分类' }],
fieldProps: {
treeData: categoryTree,
@@ -207,6 +248,7 @@ const ProductGoodsPage: React.FC = () => {
dataIndex: 'supplier_id',
valueType: 'select',
hideInSearch: true,
align: "center",
fieldProps: {
options: suppliers.map((s) => ({ label: s.name, value: s.id })),
showSearch: true,
@@ -216,17 +258,33 @@ const ProductGoodsPage: React.FC = () => {
},
render: (_, record) => record.supplier?.name ?? '-',
},
{
title: '图文详情',
dataIndex: 'content',
valueType: 'richText',
hideInSearch: true,
hideInTable: true,
colProps: { span: 24 },
fieldProps: {
height: 400,
groupId: 11,
placeholder: '输入商品图文详情,支持插入图片',
},
},
{
title: '等级价格',
dataIndex: 'prices',
hideInForm: true,
hideInSearch: true,
width: 370,
align: 'center',
render: (_, record) => (
<Space size={[0, 4]} wrap>
<Space wrap>
{record.prices?.length
? record.prices.map((p) => (
<Tag key={p.level_id} color="geekblue">
{p.level?.name ?? `等级${p.level_id}`} ¥{p.price}
<Tag key={p.id} color="geekblue">
{p.level?.name ?? `等级${p.level_id}`}
<span style={{color: 'red', marginLeft: 5 }}>¥{p.price ?? '未设定'}</span>
</Tag>
))
: '-'}
@@ -258,19 +316,12 @@ const ProductGoodsPage: React.FC = () => {
},
align: 'center',
},
{
title: '备注',
dataIndex: 'remark',
valueType: 'textarea',
hideInSearch: true,
hideInTable: true,
fieldProps: { rows: 2 },
},
{
title: '等级价格设置',
dataIndex: 'prices',
hideInTable: true,
hideInSearch: true,
colProps: { span: 24 },
fieldRender: () => (
<Form.List name="prices">
{(fields, { add, remove }) => (
@@ -281,7 +332,7 @@ const ProductGoodsPage: React.FC = () => {
{...restField}
name={[name, 'level_id']}
rules={[{ required: true, message: '请选择等级' }]}
className="!mb-0"
className="mb-0!"
>
<Select
style={{ width: 180 }}
@@ -293,7 +344,7 @@ const ProductGoodsPage: React.FC = () => {
{...restField}
name={[name, 'price']}
rules={[{ required: true, message: '请输入单价' }]}
className="!mb-0"
className="mb-0!"
>
<InputNumber
min={0}
@@ -324,6 +375,13 @@ const ProductGoodsPage: React.FC = () => {
</Form.List>
),
},
{
title: '创建时间',
dataIndex: 'created_at',
hideInForm: true,
hideInSearch: true,
align: 'center',
},
];
const tableProps: XinTableProps<IProduct> = {
@@ -347,7 +405,7 @@ const ProductGoodsPage: React.FC = () => {
},
modalProps: {
width: 800,
styles: {container: {height: '80vh', overflowY: "auto" }}
classNames: { body: "overflow-y-auto [scrollbar-width:none] [&::-webkit-scrollbar]:hidden h-[80vh]" },
},
};