feat: 新增产品分类管理和Woo产品工具功能
- 添加产品分类管理页面及相关API - 实现Woo产品标签工具和产品列表功能 - 更新路由配置和API类型定义 - 优化产品列表和同步功能 - 修复部分组件和API调用问题
This commit is contained in:
parent
c66db9b984
commit
3b66a7c49c
32
.umirc.ts
32
.umirc.ts
|
|
@ -97,10 +97,21 @@ export default defineConfig({
|
||||||
path: '/site/list',
|
path: '/site/list',
|
||||||
component: './Site/List',
|
component: './Site/List',
|
||||||
},
|
},
|
||||||
],
|
{
|
||||||
|
name: 'Woo产品列表',
|
||||||
|
path: '/site/woocommerce/product/list',
|
||||||
|
component: './Woo/Product/List',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: '商品管理',
|
name: 'Woo标签工具',
|
||||||
|
path: '/site/woocommerce/product/tool/tag',
|
||||||
|
component: './Woo/Product/TagTool',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
name: '产品管理',
|
||||||
path: '/product',
|
path: '/product',
|
||||||
access: 'canSeeProduct',
|
access: 'canSeeProduct',
|
||||||
routes: [
|
routes: [
|
||||||
|
|
@ -109,6 +120,11 @@ export default defineConfig({
|
||||||
path: '/product/list',
|
path: '/product/list',
|
||||||
component: './Product/List',
|
component: './Product/List',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "产品分类",
|
||||||
|
path: '/product/category',
|
||||||
|
component: './Product/Category',
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: '产品属性',
|
name: '产品属性',
|
||||||
path: '/product/attribute',
|
path: '/product/attribute',
|
||||||
|
|
@ -116,20 +132,10 @@ export default defineConfig({
|
||||||
},
|
},
|
||||||
// sync
|
// sync
|
||||||
{
|
{
|
||||||
name: '同步商品',
|
name: '同步产品',
|
||||||
path: '/product/sync',
|
path: '/product/sync',
|
||||||
component: './Product/Sync',
|
component: './Product/Sync',
|
||||||
},
|
},
|
||||||
{
|
|
||||||
name: 'WP商品列表',
|
|
||||||
path: '/product/wp_list',
|
|
||||||
component: './Product/WpList',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'WP工具箱',
|
|
||||||
path: '/product/wp_tool',
|
|
||||||
component: './Product/WpTool',
|
|
||||||
},
|
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@ import {
|
||||||
productcontrollerGetcategoryattributes,
|
productcontrollerGetcategoryattributes,
|
||||||
productcontrollerUpdatecategory,
|
productcontrollerUpdatecategory,
|
||||||
} from '@/servers/api/product';
|
} from '@/servers/api/product';
|
||||||
import { attributes } from '../Product/Attribute/consts';
|
import { attributes } from '../Attribute/consts';
|
||||||
|
|
||||||
const { Sider, Content } = Layout;
|
const { Sider, Content } = Layout;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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<any[]>([]);
|
||||||
|
const [loadingCategories, setLoadingCategories] = useState(false);
|
||||||
|
const [selectedCategory, setSelectedCategory] = useState<any>(null);
|
||||||
|
const [categoryAttributes, setCategoryAttributes] = useState<any[]>([]);
|
||||||
|
const [loadingAttributes, setLoadingAttributes] = useState(false);
|
||||||
|
|
||||||
|
const [isCategoryModalVisible, setIsCategoryModalVisible] = useState(false);
|
||||||
|
const [categoryForm] = Form.useForm();
|
||||||
|
const [editingCategory, setEditingCategory] = useState<any>(null);
|
||||||
|
|
||||||
|
const [isAttributeModalVisible, setIsAttributeModalVisible] = useState(false);
|
||||||
|
const [availableDicts, setAvailableDicts] = useState<any[]>([]);
|
||||||
|
const [selectedDictIds, setSelectedDictIds] = useState<number[]>([]);
|
||||||
|
|
||||||
|
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 (
|
||||||
|
<PageContainer>
|
||||||
|
<Layout style={{ background: '#fff', height: 'calc(100vh - 200px)' }}>
|
||||||
|
<Sider width={300} style={{ background: '#fff', borderRight: '1px solid #f0f0f0', padding: '16px' }}>
|
||||||
|
<div style={{ marginBottom: 16, display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
|
||||||
|
<span style={{ fontWeight: 'bold' }}>分类列表</span>
|
||||||
|
<Button
|
||||||
|
type="primary"
|
||||||
|
size="small"
|
||||||
|
icon={<PlusOutlined />}
|
||||||
|
onClick={() => {
|
||||||
|
setEditingCategory(null);
|
||||||
|
categoryForm.resetFields();
|
||||||
|
setIsCategoryModalVisible(true);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
新增
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
<List
|
||||||
|
loading={loadingCategories}
|
||||||
|
dataSource={categories}
|
||||||
|
renderItem={(item) => (
|
||||||
|
<List.Item
|
||||||
|
className={selectedCategory?.id === item.id ? 'ant-list-item-active' : ''}
|
||||||
|
style={{
|
||||||
|
cursor: 'pointer',
|
||||||
|
background: selectedCategory?.id === item.id ? '#e6f7ff' : 'transparent',
|
||||||
|
padding: '8px 12px',
|
||||||
|
borderRadius: '4px',
|
||||||
|
}}
|
||||||
|
onClick={() => setSelectedCategory(item)}
|
||||||
|
actions={[
|
||||||
|
<a
|
||||||
|
key="edit"
|
||||||
|
onClick={(e) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
setEditingCategory(item);
|
||||||
|
categoryForm.setFieldsValue(item);
|
||||||
|
setIsCategoryModalVisible(true);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
编辑
|
||||||
|
</a>,
|
||||||
|
<Popconfirm
|
||||||
|
key="delete"
|
||||||
|
title="确定删除该分类吗?"
|
||||||
|
onConfirm={(e) => {
|
||||||
|
e?.stopPropagation();
|
||||||
|
handleDeleteCategory(item.id);
|
||||||
|
}}
|
||||||
|
onCancel={(e) => e?.stopPropagation()}
|
||||||
|
>
|
||||||
|
<a onClick={(e) => e.stopPropagation()} style={{ color: 'red' }}>删除</a>
|
||||||
|
</Popconfirm>,
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
<List.Item.Meta
|
||||||
|
title={item.title}
|
||||||
|
description={item.name}
|
||||||
|
/>
|
||||||
|
</List.Item>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</Sider>
|
||||||
|
<Content style={{ padding: '24px' }}>
|
||||||
|
{selectedCategory ? (
|
||||||
|
<Card title={`分类:${selectedCategory.title} (${selectedCategory.name})`} extra={<Button type="primary" onClick={handleAddAttribute}>添加关联属性</Button>}>
|
||||||
|
<List
|
||||||
|
loading={loadingAttributes}
|
||||||
|
dataSource={categoryAttributes}
|
||||||
|
renderItem={(item) => (
|
||||||
|
<List.Item
|
||||||
|
actions={[
|
||||||
|
<Popconfirm
|
||||||
|
title="确定移除该属性吗?"
|
||||||
|
onConfirm={() => handleDeleteAttribute(item.id)}
|
||||||
|
>
|
||||||
|
<Button type="link" danger>移除</Button>
|
||||||
|
</Popconfirm>
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
<List.Item.Meta
|
||||||
|
title={item.title}
|
||||||
|
description={`Code: ${item.name}`}
|
||||||
|
/>
|
||||||
|
</List.Item>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</Card>
|
||||||
|
) : (
|
||||||
|
<div style={{ display: 'flex', justifyContent: 'center', alignItems: 'center', height: '100%', color: '#999' }}>
|
||||||
|
请选择左侧分类
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</Content>
|
||||||
|
</Layout>
|
||||||
|
|
||||||
|
<Modal
|
||||||
|
title={editingCategory ? '编辑分类' : '新增分类'}
|
||||||
|
open={isCategoryModalVisible}
|
||||||
|
onOk={() => categoryForm.submit()}
|
||||||
|
onCancel={() => setIsCategoryModalVisible(false)}
|
||||||
|
>
|
||||||
|
<Form form={categoryForm} onFinish={handleCategorySubmit} layout="vertical">
|
||||||
|
<Form.Item name="title" label="标题" rules={[{ required: true }]}>
|
||||||
|
<Input />
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item name="name" label="标识 (Code)" rules={[{ required: true }]}>
|
||||||
|
<Input />
|
||||||
|
</Form.Item>
|
||||||
|
</Form>
|
||||||
|
</Modal>
|
||||||
|
|
||||||
|
<Modal
|
||||||
|
title="添加关联属性"
|
||||||
|
open={isAttributeModalVisible}
|
||||||
|
onOk={handleAttributeSubmit}
|
||||||
|
onCancel={() => setIsAttributeModalVisible(false)}
|
||||||
|
>
|
||||||
|
<Form layout="vertical">
|
||||||
|
<Form.Item label="选择属性">
|
||||||
|
<Select
|
||||||
|
mode="multiple"
|
||||||
|
style={{ width: '100%' }}
|
||||||
|
placeholder="请选择要关联的属性"
|
||||||
|
value={selectedDictIds}
|
||||||
|
onChange={setSelectedDictIds}
|
||||||
|
options={availableDicts.map(d => ({ label: d.title, value: d.id }))}
|
||||||
|
/>
|
||||||
|
</Form.Item>
|
||||||
|
</Form>
|
||||||
|
</Modal>
|
||||||
|
</PageContainer>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default CategoryPage;
|
||||||
|
|
@ -327,8 +327,8 @@ const CreateForm: React.FC<{
|
||||||
const [activeAttributes, setActiveAttributes] = useState<any[]>([]);
|
const [activeAttributes, setActiveAttributes] = useState<any[]>([]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
productcontrollerGetcategoriesall().then((res) => {
|
productcontrollerGetcategoriesall().then((res: any) => {
|
||||||
setCategories(res || []);
|
setCategories(res?.data || []);
|
||||||
});
|
});
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
|
@ -338,8 +338,8 @@ const CreateForm: React.FC<{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
const attrs = await productcontrollerGetcategoryattributes({ categoryItemId: categoryId });
|
const res: any = await productcontrollerGetcategoryattributes({ id: categoryId });
|
||||||
setActiveAttributes(attrs || []);
|
setActiveAttributes(res?.data || []);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
message.error('获取分类属性失败');
|
message.error('获取分类属性失败');
|
||||||
}
|
}
|
||||||
|
|
@ -489,7 +489,7 @@ const CreateForm: React.FC<{
|
||||||
onFinish={async (values: any) => {
|
onFinish={async (values: any) => {
|
||||||
// 中文注释:组装 attributes(根据 activeAttributes 动态组装)
|
// 中文注释:组装 attributes(根据 activeAttributes 动态组装)
|
||||||
const attributes = activeAttributes.flatMap((attr: any) => {
|
const attributes = activeAttributes.flatMap((attr: any) => {
|
||||||
const dictName = attr.dict.name;
|
const dictName = attr.name;
|
||||||
const key = `${dictName}Values`;
|
const key = `${dictName}Values`;
|
||||||
const vals = values[key];
|
const vals = values[key];
|
||||||
if (vals && Array.isArray(vals)) {
|
if (vals && Array.isArray(vals)) {
|
||||||
|
|
@ -629,9 +629,9 @@ const CreateForm: React.FC<{
|
||||||
{activeAttributes.map((attr: any) => (
|
{activeAttributes.map((attr: any) => (
|
||||||
<AttributeFormItem
|
<AttributeFormItem
|
||||||
key={attr.id}
|
key={attr.id}
|
||||||
dictName={attr.dict.name}
|
dictName={attr.name}
|
||||||
name={`${attr.dict.name}Values`}
|
name={`${attr.name}Values`}
|
||||||
label={attr.dict.title}
|
label={attr.title}
|
||||||
isTag
|
isTag
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
|
|
@ -680,16 +680,16 @@ const EditForm: React.FC<{
|
||||||
const [activeAttributes, setActiveAttributes] = useState<any[]>([]);
|
const [activeAttributes, setActiveAttributes] = useState<any[]>([]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
productcontrollerGetcategoriesall().then((res) => {
|
productcontrollerGetcategoriesall().then((res: any) => {
|
||||||
setCategories(res || []);
|
setCategories(res?.data || []);
|
||||||
});
|
});
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const categoryId = (record as any).categoryId || (record as any).category?.id;
|
const categoryId = (record as any).categoryId || (record as any).category?.id;
|
||||||
if (categoryId) {
|
if (categoryId) {
|
||||||
productcontrollerGetcategoryattributes({ categoryItemId: categoryId }).then(res => {
|
productcontrollerGetcategoryattributes({ id: categoryId }).then((res: any) => {
|
||||||
setActiveAttributes(res || []);
|
setActiveAttributes(res?.data || []);
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
setActiveAttributes([]);
|
setActiveAttributes([]);
|
||||||
|
|
@ -702,8 +702,8 @@ const EditForm: React.FC<{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
const attrs = await productcontrollerGetcategoryattributes({ categoryItemId: categoryId });
|
const res: any = await productcontrollerGetcategoryattributes({ id: categoryId });
|
||||||
setActiveAttributes(attrs || []);
|
setActiveAttributes(res?.data || []);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
message.error('获取分类属性失败');
|
message.error('获取分类属性失败');
|
||||||
}
|
}
|
||||||
|
|
@ -793,7 +793,7 @@ const EditForm: React.FC<{
|
||||||
onFinish={async (values) => {
|
onFinish={async (values) => {
|
||||||
// 中文注释:组装 attributes
|
// 中文注释:组装 attributes
|
||||||
const attributes = activeAttributes.flatMap((attr: any) => {
|
const attributes = activeAttributes.flatMap((attr: any) => {
|
||||||
const dictName = attr.dict.name;
|
const dictName = attr.name;
|
||||||
const key = `${dictName}Values`;
|
const key = `${dictName}Values`;
|
||||||
const vals = values[key];
|
const vals = values[key];
|
||||||
if (vals && Array.isArray(vals)) {
|
if (vals && Array.isArray(vals)) {
|
||||||
|
|
@ -824,11 +824,11 @@ const EditForm: React.FC<{
|
||||||
await productcontrollerSetproductcomponents(
|
await productcontrollerSetproductcomponents(
|
||||||
{ id: record.id },
|
{ id: record.id },
|
||||||
{
|
{
|
||||||
items: (values.components || []).map((c: any) => ({
|
components: (values.components || []).map((c: any) => ({
|
||||||
sku: c.sku,
|
sku: c.sku,
|
||||||
quantity: Number(c.quantity),
|
quantity: Number(c.quantity),
|
||||||
})),
|
})),
|
||||||
},
|
} as any,
|
||||||
);
|
);
|
||||||
if (!success2) {
|
if (!success2) {
|
||||||
message.error(errMsg2);
|
message.error(errMsg2);
|
||||||
|
|
@ -977,9 +977,9 @@ const EditForm: React.FC<{
|
||||||
{activeAttributes.map((attr: any) => (
|
{activeAttributes.map((attr: any) => (
|
||||||
<AttributeFormItem
|
<AttributeFormItem
|
||||||
key={attr.id}
|
key={attr.id}
|
||||||
dictName={attr.dict.name}
|
dictName={attr.name}
|
||||||
name={`${attr.dict.name}Values`}
|
name={`${attr.name}Values`}
|
||||||
label={attr.dict.title}
|
label={attr.title}
|
||||||
isTag
|
isTag
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
|
|
|
||||||
|
|
@ -164,6 +164,7 @@ const ProductSyncPage: React.FC = () => {
|
||||||
const siteColumn: ProColumns<ProductBase> = {
|
const siteColumn: ProColumns<ProductBase> = {
|
||||||
title: site.name,
|
title: site.name,
|
||||||
key: `site_${site.id}`,
|
key: `site_${site.id}`,
|
||||||
|
hideInSearch: true,
|
||||||
width: 250,
|
width: 250,
|
||||||
render: (_, record: ProductBase) => {
|
render: (_, record: ProductBase) => {
|
||||||
const wpProduct = record.wpProducts[site.id];
|
const wpProduct = record.wpProducts[site.id];
|
||||||
|
|
|
||||||
|
|
@ -272,11 +272,10 @@ const SiteList: React.FC = () => {
|
||||||
新增站点
|
新增站点
|
||||||
</Button>,
|
</Button>,
|
||||||
// 同步包括 orders subscriptions 等等
|
// 同步包括 orders subscriptions 等等
|
||||||
// <Button key='new' type='primary' onClick={()=> {
|
<Button key='new' disabled type='primary' onClick={()=> {
|
||||||
//
|
}}>
|
||||||
// }}}>
|
同步站点数据
|
||||||
// 同步站点数据
|
</Button>
|
||||||
// </Button>
|
|
||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -34,6 +34,10 @@ const List: React.FC = () => {
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
title: '标题',
|
||||||
|
dataIndex: 'title',
|
||||||
|
},
|
||||||
{
|
{
|
||||||
title: '值',
|
title: '值',
|
||||||
dataIndex: 'value',
|
dataIndex: 'value',
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ import { Button, Card, Col, Input, message, Row, Upload } from 'antd';
|
||||||
import React, { useEffect, useState } from 'react';
|
import React, { useEffect, useState } from 'react';
|
||||||
import * as XLSX from 'xlsx';
|
import * as XLSX from 'xlsx';
|
||||||
import { request } from '@umijs/max';
|
import { request } from '@umijs/max';
|
||||||
import { attributes } from '../Attribute/consts';
|
import { attributes } from '../../../Product/Attribute/consts';
|
||||||
|
|
||||||
// 定义配置接口
|
// 定义配置接口
|
||||||
interface TagConfig {
|
interface TagConfig {
|
||||||
|
|
@ -0,0 +1,123 @@
|
||||||
|
// @ts-ignore
|
||||||
|
/* eslint-disable */
|
||||||
|
import { request } from 'umi';
|
||||||
|
|
||||||
|
/** 此处后端没有提供注释 GET /category/ */
|
||||||
|
export async function categorycontrollerGetlist(
|
||||||
|
// 叠加生成的Param类型 (非body参数swagger默认没有生成对象)
|
||||||
|
params: API.categorycontrollerGetlistParams,
|
||||||
|
options?: { [key: string]: any },
|
||||||
|
) {
|
||||||
|
return request<any>('/category/', {
|
||||||
|
method: 'GET',
|
||||||
|
params: {
|
||||||
|
...params,
|
||||||
|
pageSize: undefined,
|
||||||
|
...params['pageSize'],
|
||||||
|
current: undefined,
|
||||||
|
...params['current'],
|
||||||
|
},
|
||||||
|
...(options || {}),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 此处后端没有提供注释 POST /category/ */
|
||||||
|
export async function categorycontrollerCreate(
|
||||||
|
body: Record<string, any>,
|
||||||
|
options?: { [key: string]: any },
|
||||||
|
) {
|
||||||
|
return request<any>('/category/', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'text/plain',
|
||||||
|
},
|
||||||
|
data: body,
|
||||||
|
...(options || {}),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 此处后端没有提供注释 PUT /category/${param0} */
|
||||||
|
export async function categorycontrollerUpdate(
|
||||||
|
// 叠加生成的Param类型 (非body参数swagger默认没有生成对象)
|
||||||
|
params: API.categorycontrollerUpdateParams,
|
||||||
|
body: Record<string, any>,
|
||||||
|
options?: { [key: string]: any },
|
||||||
|
) {
|
||||||
|
const { id: param0, ...queryParams } = params;
|
||||||
|
return request<any>(`/category/${param0}`, {
|
||||||
|
method: 'PUT',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'text/plain',
|
||||||
|
},
|
||||||
|
params: { ...queryParams },
|
||||||
|
data: body,
|
||||||
|
...(options || {}),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 此处后端没有提供注释 DELETE /category/${param0} */
|
||||||
|
export async function categorycontrollerDelete(
|
||||||
|
// 叠加生成的Param类型 (非body参数swagger默认没有生成对象)
|
||||||
|
params: API.categorycontrollerDeleteParams,
|
||||||
|
options?: { [key: string]: any },
|
||||||
|
) {
|
||||||
|
const { id: param0, ...queryParams } = params;
|
||||||
|
return request<any>(`/category/${param0}`, {
|
||||||
|
method: 'DELETE',
|
||||||
|
params: { ...queryParams },
|
||||||
|
...(options || {}),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 此处后端没有提供注释 GET /category/all */
|
||||||
|
export async function categorycontrollerGetall(options?: {
|
||||||
|
[key: string]: any;
|
||||||
|
}) {
|
||||||
|
return request<any>('/category/all', {
|
||||||
|
method: 'GET',
|
||||||
|
...(options || {}),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 此处后端没有提供注释 POST /category/attribute */
|
||||||
|
export async function categorycontrollerCreatecategoryattribute(
|
||||||
|
body: Record<string, any>,
|
||||||
|
options?: { [key: string]: any },
|
||||||
|
) {
|
||||||
|
return request<any>('/category/attribute', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'text/plain',
|
||||||
|
},
|
||||||
|
data: body,
|
||||||
|
...(options || {}),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 此处后端没有提供注释 GET /category/attribute/${param0} */
|
||||||
|
export async function categorycontrollerGetcategoryattributes(
|
||||||
|
// 叠加生成的Param类型 (非body参数swagger默认没有生成对象)
|
||||||
|
params: API.categorycontrollerGetcategoryattributesParams,
|
||||||
|
options?: { [key: string]: any },
|
||||||
|
) {
|
||||||
|
const { categoryId: param0, ...queryParams } = params;
|
||||||
|
return request<any>(`/category/attribute/${param0}`, {
|
||||||
|
method: 'GET',
|
||||||
|
params: { ...queryParams },
|
||||||
|
...(options || {}),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 此处后端没有提供注释 DELETE /category/attribute/${param0} */
|
||||||
|
export async function categorycontrollerDeletecategoryattribute(
|
||||||
|
// 叠加生成的Param类型 (非body参数swagger默认没有生成对象)
|
||||||
|
params: API.categorycontrollerDeletecategoryattributeParams,
|
||||||
|
options?: { [key: string]: any },
|
||||||
|
) {
|
||||||
|
const { id: param0, ...queryParams } = params;
|
||||||
|
return request<any>(`/category/attribute/${param0}`, {
|
||||||
|
method: 'DELETE',
|
||||||
|
params: { ...queryParams },
|
||||||
|
...(options || {}),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
@ -3,6 +3,7 @@
|
||||||
// API 更新时间:
|
// API 更新时间:
|
||||||
// API 唯一标识:
|
// API 唯一标识:
|
||||||
import * as area from './area';
|
import * as area from './area';
|
||||||
|
import * as category from './category';
|
||||||
import * as customer from './customer';
|
import * as customer from './customer';
|
||||||
import * as dict from './dict';
|
import * as dict from './dict';
|
||||||
import * as locales from './locales';
|
import * as locales from './locales';
|
||||||
|
|
@ -19,6 +20,7 @@ import * as webhook from './webhook';
|
||||||
import * as wpProduct from './wpProduct';
|
import * as wpProduct from './wpProduct';
|
||||||
export default {
|
export default {
|
||||||
area,
|
area,
|
||||||
|
category,
|
||||||
customer,
|
customer,
|
||||||
dict,
|
dict,
|
||||||
locales,
|
locales,
|
||||||
|
|
|
||||||
|
|
@ -263,6 +263,107 @@ export async function productcontrollerCompatbrands(
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** 此处后端没有提供注释 GET /product/categories/all */
|
||||||
|
export async function productcontrollerGetcategoriesall(options?: {
|
||||||
|
[key: string]: any;
|
||||||
|
}) {
|
||||||
|
return request<any>('/product/categories/all', {
|
||||||
|
method: 'GET',
|
||||||
|
...(options || {}),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 此处后端没有提供注释 POST /product/category */
|
||||||
|
export async function productcontrollerCreatecategory(
|
||||||
|
body: Record<string, any>,
|
||||||
|
options?: { [key: string]: any },
|
||||||
|
) {
|
||||||
|
return request<any>('/product/category', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'text/plain',
|
||||||
|
},
|
||||||
|
data: body,
|
||||||
|
...(options || {}),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 此处后端没有提供注释 PUT /product/category/${param0} */
|
||||||
|
export async function productcontrollerUpdatecategory(
|
||||||
|
// 叠加生成的Param类型 (非body参数swagger默认没有生成对象)
|
||||||
|
params: API.productcontrollerUpdatecategoryParams,
|
||||||
|
body: Record<string, any>,
|
||||||
|
options?: { [key: string]: any },
|
||||||
|
) {
|
||||||
|
const { id: param0, ...queryParams } = params;
|
||||||
|
return request<any>(`/product/category/${param0}`, {
|
||||||
|
method: 'PUT',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'text/plain',
|
||||||
|
},
|
||||||
|
params: { ...queryParams },
|
||||||
|
data: body,
|
||||||
|
...(options || {}),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 此处后端没有提供注释 DELETE /product/category/${param0} */
|
||||||
|
export async function productcontrollerDeletecategory(
|
||||||
|
// 叠加生成的Param类型 (非body参数swagger默认没有生成对象)
|
||||||
|
params: API.productcontrollerDeletecategoryParams,
|
||||||
|
options?: { [key: string]: any },
|
||||||
|
) {
|
||||||
|
const { id: param0, ...queryParams } = params;
|
||||||
|
return request<any>(`/product/category/${param0}`, {
|
||||||
|
method: 'DELETE',
|
||||||
|
params: { ...queryParams },
|
||||||
|
...(options || {}),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 此处后端没有提供注释 GET /product/category/${param0}/attributes */
|
||||||
|
export async function productcontrollerGetcategoryattributes(
|
||||||
|
// 叠加生成的Param类型 (非body参数swagger默认没有生成对象)
|
||||||
|
params: API.productcontrollerGetcategoryattributesParams,
|
||||||
|
options?: { [key: string]: any },
|
||||||
|
) {
|
||||||
|
const { id: param0, ...queryParams } = params;
|
||||||
|
return request<any>(`/product/category/${param0}/attributes`, {
|
||||||
|
method: 'GET',
|
||||||
|
params: { ...queryParams },
|
||||||
|
...(options || {}),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 此处后端没有提供注释 POST /product/category/attribute */
|
||||||
|
export async function productcontrollerCreatecategoryattribute(
|
||||||
|
body: Record<string, any>,
|
||||||
|
options?: { [key: string]: any },
|
||||||
|
) {
|
||||||
|
return request<any>('/product/category/attribute', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'text/plain',
|
||||||
|
},
|
||||||
|
data: body,
|
||||||
|
...(options || {}),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 此处后端没有提供注释 DELETE /product/category/attribute/${param0} */
|
||||||
|
export async function productcontrollerDeletecategoryattribute(
|
||||||
|
// 叠加生成的Param类型 (非body参数swagger默认没有生成对象)
|
||||||
|
params: API.productcontrollerDeletecategoryattributeParams,
|
||||||
|
options?: { [key: string]: any },
|
||||||
|
) {
|
||||||
|
const { id: param0, ...queryParams } = params;
|
||||||
|
return request<any>(`/product/category/attribute/${param0}`, {
|
||||||
|
method: 'DELETE',
|
||||||
|
params: { ...queryParams },
|
||||||
|
...(options || {}),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/** 此处后端没有提供注释 GET /product/export */
|
/** 此处后端没有提供注释 GET /product/export */
|
||||||
export async function productcontrollerExportproductscsv(options?: {
|
export async function productcontrollerExportproductscsv(options?: {
|
||||||
[key: string]: any;
|
[key: string]: any;
|
||||||
|
|
@ -587,6 +688,16 @@ export async function productcontrollerCompatstrengthall(options?: {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** 此处后端没有提供注释 GET /product/wp-products */
|
||||||
|
export async function productcontrollerGetwpproducts(options?: {
|
||||||
|
[key: string]: any;
|
||||||
|
}) {
|
||||||
|
return request<any>('/product/wp-products', {
|
||||||
|
method: 'GET',
|
||||||
|
...(options || {}),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/** 此处后端没有提供注释 PUT /productupdateNameCn/${param1}/${param0} */
|
/** 此处后端没有提供注释 PUT /productupdateNameCn/${param1}/${param0} */
|
||||||
export async function productcontrollerUpdatenamecn(
|
export async function productcontrollerUpdatenamecn(
|
||||||
// 叠加生成的Param类型 (非body参数swagger默认没有生成对象)
|
// 叠加生成的Param类型 (非body参数swagger默认没有生成对象)
|
||||||
|
|
|
||||||
|
|
@ -46,6 +46,28 @@ declare namespace API {
|
||||||
data?: boolean;
|
data?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
type categorycontrollerDeletecategoryattributeParams = {
|
||||||
|
id: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
type categorycontrollerDeleteParams = {
|
||||||
|
id: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
type categorycontrollerGetcategoryattributesParams = {
|
||||||
|
categoryId: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
type categorycontrollerGetlistParams = {
|
||||||
|
name?: string;
|
||||||
|
pageSize?: Record<string, any>;
|
||||||
|
current?: Record<string, any>;
|
||||||
|
};
|
||||||
|
|
||||||
|
type categorycontrollerUpdateParams = {
|
||||||
|
id: number;
|
||||||
|
};
|
||||||
|
|
||||||
type CreateAreaDTO = {
|
type CreateAreaDTO = {
|
||||||
/** 编码 */
|
/** 编码 */
|
||||||
code?: string;
|
code?: string;
|
||||||
|
|
@ -67,6 +89,8 @@ declare namespace API {
|
||||||
description?: string;
|
description?: string;
|
||||||
/** 产品 SKU */
|
/** 产品 SKU */
|
||||||
sku?: string;
|
sku?: string;
|
||||||
|
/** 分类ID (DictItem ID) */
|
||||||
|
categoryId?: number;
|
||||||
/** 属性列表 */
|
/** 属性列表 */
|
||||||
attributes?: any[];
|
attributes?: any[];
|
||||||
/** 价格 */
|
/** 价格 */
|
||||||
|
|
@ -702,10 +726,6 @@ declare namespace API {
|
||||||
nameCn?: string;
|
nameCn?: string;
|
||||||
/** 产品描述 */
|
/** 产品描述 */
|
||||||
description?: string;
|
description?: string;
|
||||||
/** 产品分类 */
|
|
||||||
category?: string;
|
|
||||||
/** 动态属性值 */
|
|
||||||
properties?: Record<string, any>;
|
|
||||||
/** sku */
|
/** sku */
|
||||||
sku?: string;
|
sku?: string;
|
||||||
/** 价格 */
|
/** 价格 */
|
||||||
|
|
@ -724,13 +744,6 @@ declare namespace API {
|
||||||
updatedAt: string;
|
updatedAt: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
type ProductComponentItemDTO = {
|
|
||||||
/** 组件 SKU */
|
|
||||||
sku?: string;
|
|
||||||
/** 组成数量 */
|
|
||||||
quantity?: number;
|
|
||||||
};
|
|
||||||
|
|
||||||
type productcontrollerAutobindcomponentsParams = {
|
type productcontrollerAutobindcomponentsParams = {
|
||||||
id: number;
|
id: number;
|
||||||
};
|
};
|
||||||
|
|
@ -799,6 +812,14 @@ declare namespace API {
|
||||||
id: number;
|
id: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
type productcontrollerDeletecategoryattributeParams = {
|
||||||
|
id: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
type productcontrollerDeletecategoryParams = {
|
||||||
|
id: number;
|
||||||
|
};
|
||||||
|
|
||||||
type productcontrollerDeleteproductParams = {
|
type productcontrollerDeleteproductParams = {
|
||||||
id: number;
|
id: number;
|
||||||
};
|
};
|
||||||
|
|
@ -814,18 +835,24 @@ declare namespace API {
|
||||||
dictName?: string;
|
dictName?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
type productcontrollerGetcategoryattributesParams = {
|
||||||
|
id: number;
|
||||||
|
};
|
||||||
|
|
||||||
type productcontrollerGetproductcomponentsParams = {
|
type productcontrollerGetproductcomponentsParams = {
|
||||||
id: number;
|
id: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
type productcontrollerGetproductlistParams = {
|
type productcontrollerGetproductlistParams = {
|
||||||
/** 页码 */
|
/** 当前页 */
|
||||||
current?: number;
|
current?: number;
|
||||||
/** 每页大小 */
|
/** 每页数量 */
|
||||||
pageSize?: number;
|
pageSize?: number;
|
||||||
/** 关键字 */
|
/** 搜索关键字 */
|
||||||
name?: string;
|
name?: string;
|
||||||
/** 品牌 ID */
|
/** 分类ID */
|
||||||
|
categoryId?: number;
|
||||||
|
/** 品牌ID */
|
||||||
brandId?: number;
|
brandId?: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -846,6 +873,10 @@ declare namespace API {
|
||||||
id: number;
|
id: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
type productcontrollerUpdatecategoryParams = {
|
||||||
|
id: number;
|
||||||
|
};
|
||||||
|
|
||||||
type productcontrollerUpdatenamecnParams = {
|
type productcontrollerUpdatenamecnParams = {
|
||||||
nameCn: string;
|
nameCn: string;
|
||||||
id: number;
|
id: number;
|
||||||
|
|
@ -1043,13 +1074,15 @@ declare namespace API {
|
||||||
};
|
};
|
||||||
|
|
||||||
type QueryProductDTO = {
|
type QueryProductDTO = {
|
||||||
/** 页码 */
|
/** 当前页 */
|
||||||
current?: number;
|
current?: number;
|
||||||
/** 每页大小 */
|
/** 每页数量 */
|
||||||
pageSize?: number;
|
pageSize?: number;
|
||||||
/** 关键字 */
|
/** 搜索关键字 */
|
||||||
name?: string;
|
name?: string;
|
||||||
/** 品牌 ID */
|
/** 分类ID */
|
||||||
|
categoryId?: number;
|
||||||
|
/** 品牌ID */
|
||||||
brandId?: number;
|
brandId?: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -1194,8 +1227,8 @@ declare namespace API {
|
||||||
};
|
};
|
||||||
|
|
||||||
type SetProductComponentsDTO = {
|
type SetProductComponentsDTO = {
|
||||||
/** 组成项列表 */
|
/** 产品组成 */
|
||||||
items?: ProductComponentItemDTO[];
|
components: any[];
|
||||||
};
|
};
|
||||||
|
|
||||||
type ShipmentBookDTO = {
|
type ShipmentBookDTO = {
|
||||||
|
|
@ -1631,6 +1664,8 @@ declare namespace API {
|
||||||
description?: string;
|
description?: string;
|
||||||
/** 产品 SKU */
|
/** 产品 SKU */
|
||||||
sku?: string;
|
sku?: string;
|
||||||
|
/** 分类ID (DictItem ID) */
|
||||||
|
categoryId?: number;
|
||||||
/** 价格 */
|
/** 价格 */
|
||||||
price?: number;
|
price?: number;
|
||||||
/** 促销价格 */
|
/** 促销价格 */
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue