feat(产品列表): 添加自动生成SKU和产品名称功能

实现通过模板渲染API自动生成产品SKU和名称的功能
添加品牌、强度、口味和干湿选项的状态管理
优化表单布局,将生成按钮与对应字段分组
This commit is contained in:
tikkhun 2025-11-28 10:51:11 +08:00
parent bd4096258e
commit 15c8588357
3 changed files with 208 additions and 63 deletions

View File

@ -7,6 +7,7 @@ import {
productcontrollerGetstrengthall, productcontrollerGetstrengthall,
productcontrollerUpdateproductnamecn, productcontrollerUpdateproductnamecn,
} from '@/servers/api/product'; } from '@/servers/api/product';
import { templatecontrollerRendertemplate } from '@/servers/api/template';
import { PlusOutlined } from '@ant-design/icons'; import { PlusOutlined } from '@ant-design/icons';
import { import {
ActionType, ActionType,
@ -14,14 +15,20 @@ import {
PageContainer, PageContainer,
ProColumns, ProColumns,
ProForm, ProForm,
ProFormInstance,
ProFormSelect, ProFormSelect,
ProFormText, ProFormText,
ProFormTextArea, ProFormTextArea,
ProTable, ProTable,
} from '@ant-design/pro-components'; } from '@ant-design/pro-components';
import { App, Button, Popconfirm } from 'antd'; import { App, Button, Popconfirm } from 'antd';
import React, { useRef } from 'react'; import React, { useRef, useState } from 'react';
// TODO
interface DictItem {
id: number;
name: string;
title: string;
}
const NameCn: React.FC<{ const NameCn: React.FC<{
id: number; id: number;
value: string | undefined; value: string | undefined;
@ -176,10 +183,99 @@ const List: React.FC = () => {
const CreateForm: React.FC<{ const CreateForm: React.FC<{
tableRef: React.MutableRefObject<ActionType | undefined>; tableRef: React.MutableRefObject<ActionType | undefined>;
}> = ({ tableRef }) => { }> = ({ tableRef }) => {
// antd 的消息提醒
const { message } = App.useApp(); const { message } = App.useApp();
// 表单引用
const formRef = useRef<ProFormInstance>();
// 状态:存储品牌、强度和口味的选项
const [brandOptions, setBrandOptions] = useState<DictItem[]>([]);
const [strengthOptions, setStrengthOptions] = useState<DictItem[]>([]);
const [flavorOptions, setFlavorOptions] = useState<DictItem[]>([]);
/**
* @description SKU
*/
const handleGenerateSku = async () => {
try {
// 从表单引用中获取当前表单的值
const formValues = formRef.current?.getFieldsValue();
const { humidity, brandId, strengthId, flavorsId } = formValues;
// 检查是否所有必需的字段都已选择
if (!brandId || !strengthId || !flavorsId || !humidity) {
message.warning('请先选择品牌、强度、口味和干湿');
return;
}
// 从选项中查找所选品牌、强度和口味的完整对象
const brand = brandOptions.find((item) => item.id === brandId);
const strength = strengthOptions.find((item) => item.id === strengthId);
const flavor = flavorOptions.find((item) => item.id === flavorsId);
// 调用模板渲染API来生成SKU
const { data: rendered, message: msg, success } = await templatecontrollerRendertemplate(
{ name: 'product.sku' },
{
brand: brand ? brand.name : "",
strength: strength ? strength.name : '',
flavor: flavor ? flavor.name : '',
humidity: humidity === 'dry' ? 'Dry' : 'Moisture',
},
);
if (!success) {
throw new Error(msg);
}
// 将生成的SKU设置到表单字段中
formRef.current?.setFieldsValue({ sku: rendered });
} catch (error: any) {
message.error(`生成失败: ${error.message}`);
}
};
/**
* @description
*/
const handleGenerateName = async () => {
try {
// 从表单引用中获取当前表单的值
const formValues = formRef.current?.getFieldsValue();
const { humidity, brandId, strengthId, flavorsId } = formValues;
// 检查是否所有必需的字段都已选择
if (!brandId || !strengthId || !flavorsId || !humidity) {
message.warning('请先选择品牌、强度、口味和干湿');
return;
}
// 从选项中查找所选品牌、强度和口味的完整对象
const brand = brandOptions.find((item) => item.id === brandId);
const strength = strengthOptions.find((item) => item.id === strengthId);
const flavor = flavorOptions.find((item) => item.id === flavorsId);
// 调用模板渲染API来生成产品名称
const { message: msg, data: rendered, success } = await templatecontrollerRendertemplate(
{ name: 'product.title' },
{
brand: brand ? brand.title : "",
strength: strength ? strength.title : '',
flavor: flavor ? flavor.title : '',
model: '',
humidity: humidity === 'dry' ? 'Dry' : 'Moisture',
},
);
if (!success) {
throw new Error(msg);
}
// 将生成的名称设置到表单字段中
formRef.current?.setFieldsValue({ name: rendered });
} catch (error: any) {
message.error(`生成失败: ${error.message}`);
}
};
// TODO 可以输入brand等
return ( return (
<DrawerForm<API.CreateProductDTO> <DrawerForm<API.CreateProductDTO>
title="新建" title="新建"
formRef={formRef} // Pass formRef
trigger={ trigger={
<Button type="primary"> <Button type="primary">
<PlusOutlined /> <PlusOutlined />
@ -205,20 +301,6 @@ const CreateForm: React.FC<{
} }
}} }}
> >
<ProForm.Group>
<ProFormText
name="name"
label="名称"
width="lg"
placeholder="请输入名称"
rules={[{ required: true, message: '请输入名称' }]}
/>
<ProFormTextArea
name="description"
width="lg"
label="产品描述"
placeholder="请输入产品描述"
/>
<ProFormSelect <ProFormSelect
name="brandId" name="brandId"
width="lg" width="lg"
@ -226,7 +308,8 @@ const CreateForm: React.FC<{
placeholder="请选择产品品牌" placeholder="请选择产品品牌"
request={async () => { request={async () => {
const { data = [] } = await productcontrollerGetbrandall(); const { data = [] } = await productcontrollerGetbrandall();
return data.map((item: API.Brand) => ({ setBrandOptions(data);
return data.map((item: DictItem) => ({
label: item.name, label: item.name,
value: item.id, value: item.id,
})); }));
@ -240,7 +323,8 @@ const CreateForm: React.FC<{
placeholder="请选择强度" placeholder="请选择强度"
request={async () => { request={async () => {
const { data = [] } = await productcontrollerGetstrengthall(); const { data = [] } = await productcontrollerGetstrengthall();
return data.map((item) => ({ setStrengthOptions(data);
return data.map((item: DictItem) => ({
label: item.name, label: item.name,
value: item.id, value: item.id,
})); }));
@ -254,7 +338,8 @@ const CreateForm: React.FC<{
placeholder="请选择口味" placeholder="请选择口味"
request={async () => { request={async () => {
const { data = [] } = await productcontrollerGetflavorsall(); const { data = [] } = await productcontrollerGetflavorsall();
return data.map((item) => ({ setFlavorOptions(data);
return data.map((item: DictItem) => ({
label: item.name, label: item.name,
value: item.id, value: item.id,
})); }));
@ -267,12 +352,41 @@ const CreateForm: React.FC<{
label="干湿" label="干湿"
placeholder="请选择干湿" placeholder="请选择干湿"
valueEnum={{ valueEnum={{
dry: '干', dry: 'dry',
wet: '湿', wet: 'wet',
}} }}
rules={[{ required: true, message: '请选择干湿' }]} rules={[{ required: true, message: '请选择干湿' }]}
/> />
<ProForm.Group>
<ProFormText
name="sku"
label="SKU"
width="md"
placeholder="请输入SKU"
rules={[{ required: true, message: '请输入SKU' }]}
/>
<Button style={{ marginTop: '32px' }} onClick={handleGenerateSku}>
</Button>
</ProForm.Group> </ProForm.Group>
<ProForm.Group>
<ProFormText
name="name"
label="名称"
width="md"
placeholder="请输入名称"
rules={[{ required: true, message: '请输入名称' }]}
/>
<Button style={{ marginTop: '32px' }} onClick={handleGenerateName}>
</Button>
</ProForm.Group>
<ProFormTextArea
name="description"
width="lg"
label="产品描述"
placeholder="请输入产品描述"
/>
</DrawerForm> </DrawerForm>
); );
}; };

View File

@ -73,3 +73,22 @@ export async function templatecontrollerGettemplatelist(options?: {
...(options || {}), ...(options || {}),
}); });
} }
/** 此处后端没有提供注释 POST /template/render/${param0} */
export async function templatecontrollerRendertemplate(
// 叠加生成的Param类型 (非body参数swagger默认没有生成对象)
params: API.templatecontrollerRendertemplateParams,
body: Record<string, any>,
options?: { [key: string]: any },
) {
const { name: param0, ...queryParams } = params;
return request<Record<string, any>>(`/template/render/${param0}`, {
method: 'POST',
headers: {
'Content-Type': 'text/plain',
},
params: { ...queryParams },
data: body,
...(options || {}),
});
}

View File

@ -71,6 +71,8 @@ declare namespace API {
/** 口味 */ /** 口味 */
flavor?: DictItemDTO; flavor?: DictItemDTO;
humidity?: string; humidity?: string;
/** 价格 */
price?: number;
}; };
type CreatePurchaseOrderDTO = { type CreatePurchaseOrderDTO = {
@ -701,6 +703,8 @@ declare namespace API {
description?: string; description?: string;
/** sku */ /** sku */
sku?: string; sku?: string;
/** 价格 */
price?: number;
/** 创建时间 */ /** 创建时间 */
createdAt: string; createdAt: string;
/** 更新时间 */ /** 更新时间 */
@ -1536,6 +1540,8 @@ declare namespace API {
name?: string; name?: string;
value?: string; value?: string;
description?: string; description?: string;
/** 是否可删除 */
deletable: boolean;
/** 创建时间 */ /** 创建时间 */
createdAt: string; createdAt: string;
/** 更新时间 */ /** 更新时间 */
@ -1550,6 +1556,10 @@ declare namespace API {
name: string; name: string;
}; };
type templatecontrollerRendertemplateParams = {
name: string;
};
type templatecontrollerUpdatetemplateParams = { type templatecontrollerUpdatetemplateParams = {
id: number; id: number;
}; };
@ -1591,6 +1601,8 @@ declare namespace API {
/** 口味 */ /** 口味 */
flavor?: DictItemDTO; flavor?: DictItemDTO;
humidity?: string; humidity?: string;
/** 价格 */
price?: number;
}; };
type UpdatePurchaseOrderDTO = { type UpdatePurchaseOrderDTO = {
@ -1749,7 +1761,7 @@ declare namespace API {
siteId: string; siteId: string;
/** wp产品ID */ /** wp产品ID */
externalProductId: string; externalProductId: string;
/** sku */ /** 商店sku */
sku?: string; sku?: string;
/** 产品名称 */ /** 产品名称 */
name: string; name: string;