395 lines
11 KiB
TypeScript
395 lines
11 KiB
TypeScript
import {
|
|
productcontrollerCreateproduct,
|
|
productcontrollerDeleteproduct,
|
|
productcontrollerGetbrandall,
|
|
productcontrollerGetflavorsall,
|
|
productcontrollerGetproductlist,
|
|
productcontrollerGetstrengthall,
|
|
productcontrollerUpdateproductnamecn,
|
|
} from '@/servers/api/product';
|
|
import { templatecontrollerRendertemplate } from '@/servers/api/template';
|
|
import { PlusOutlined } from '@ant-design/icons';
|
|
import {
|
|
ActionType,
|
|
DrawerForm,
|
|
PageContainer,
|
|
ProColumns,
|
|
ProForm,
|
|
ProFormInstance,
|
|
ProFormSelect,
|
|
ProFormText,
|
|
ProFormTextArea,
|
|
ProTable,
|
|
} from '@ant-design/pro-components';
|
|
import { App, Button, Popconfirm } from 'antd';
|
|
import React, { useRef, useState } from 'react';
|
|
// TODO
|
|
interface DictItem {
|
|
id: number;
|
|
name: string;
|
|
title: string;
|
|
}
|
|
const NameCn: React.FC<{
|
|
id: number;
|
|
value: string | undefined;
|
|
tableRef: React.MutableRefObject<ActionType | undefined>;
|
|
}> = ({ value, tableRef, id }) => {
|
|
const { message } = App.useApp();
|
|
const [editable, setEditable] = React.useState<boolean>(false);
|
|
if (!editable)
|
|
return <div onClick={() => setEditable(true)}>{value || '-'}</div>;
|
|
return (
|
|
<ProFormText
|
|
initialValue={value}
|
|
fieldProps={{
|
|
autoFocus: true,
|
|
onBlur: async (e: React.FocusEvent<HTMLInputElement>) => {
|
|
if (!e.target.value) return setEditable(false);
|
|
const { success, message: errMsg } =
|
|
await productcontrollerUpdateproductnamecn({
|
|
id,
|
|
nameCn: e.target.value,
|
|
});
|
|
setEditable(false);
|
|
if (!success) {
|
|
return message.error(errMsg);
|
|
}
|
|
tableRef?.current?.reload();
|
|
},
|
|
}}
|
|
/>
|
|
);
|
|
};
|
|
const List: React.FC = () => {
|
|
const actionRef = useRef<ActionType>();
|
|
// 状态:存储当前选中的行
|
|
const [selectedRows, setSelectedRows] = React.useState<API.Product[]>([]);
|
|
|
|
const { message } = App.useApp();
|
|
const columns: ProColumns<API.Product>[] = [
|
|
{
|
|
title: '名称',
|
|
dataIndex: 'name',
|
|
},
|
|
{
|
|
title: '中文名',
|
|
dataIndex: 'nameCn',
|
|
render: (_, record) => {
|
|
return (
|
|
<NameCn value={record.nameCn} id={record.id} tableRef={actionRef} />
|
|
);
|
|
},
|
|
},
|
|
{
|
|
title: '产品描述',
|
|
dataIndex: 'description',
|
|
hideInSearch: true,
|
|
},
|
|
{
|
|
title: '产品品牌',
|
|
dataIndex: 'brandName',
|
|
},
|
|
{
|
|
title: '强度',
|
|
dataIndex: 'strengthName',
|
|
},
|
|
{
|
|
title: '口味',
|
|
dataIndex: 'flavorsName',
|
|
},
|
|
{
|
|
title: '湿度',
|
|
dataIndex: 'humidity',
|
|
},
|
|
{
|
|
title: 'sku',
|
|
dataIndex: 'sku',
|
|
},
|
|
{
|
|
title: '更新时间',
|
|
dataIndex: 'updatedAt',
|
|
valueType: 'dateTime',
|
|
hideInSearch: true,
|
|
},
|
|
{
|
|
title: '创建时间',
|
|
dataIndex: 'createdAt',
|
|
valueType: 'dateTime',
|
|
hideInSearch: true,
|
|
},
|
|
{
|
|
title: '操作',
|
|
dataIndex: 'option',
|
|
valueType: 'option',
|
|
render: (_, record) => (
|
|
<>
|
|
<Popconfirm
|
|
title="删除"
|
|
description="确认删除?"
|
|
onConfirm={async () => {
|
|
try {
|
|
const { success, message: errMsg } =
|
|
await productcontrollerDeleteproduct({ id: record.id });
|
|
if (!success) {
|
|
throw new Error(errMsg);
|
|
}
|
|
actionRef.current?.reload();
|
|
} catch (error: any) {
|
|
message.error(error.message);
|
|
}
|
|
}}
|
|
>
|
|
<Button type="primary" danger>
|
|
删除
|
|
</Button>
|
|
</Popconfirm>
|
|
</>
|
|
),
|
|
},
|
|
];
|
|
|
|
return (
|
|
<PageContainer header={{ title: '产品列表' }}>
|
|
<ProTable<API.Product>
|
|
headerTitle="查询表格"
|
|
actionRef={actionRef}
|
|
rowKey="id"
|
|
toolBarRender={() => [<CreateForm tableRef={actionRef} />]}
|
|
request={async (params) => {
|
|
const { data, success } = await productcontrollerGetproductlist(
|
|
params,
|
|
);
|
|
return {
|
|
total: data?.total || 0,
|
|
data: data?.items || [],
|
|
success,
|
|
};
|
|
}}
|
|
columns={columns}
|
|
editable={{
|
|
type: 'single',
|
|
onSave: async (key, record, originRow) => {
|
|
console.log('保存数据:', record);
|
|
},
|
|
}}
|
|
rowSelection={{
|
|
onChange: (_, selectedRows) => setSelectedRows(selectedRows),
|
|
}}
|
|
/>
|
|
</PageContainer>
|
|
);
|
|
};
|
|
|
|
const CreateForm: React.FC<{
|
|
tableRef: React.MutableRefObject<ActionType | undefined>;
|
|
}> = ({ tableRef }) => {
|
|
// antd 的消息提醒
|
|
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 (
|
|
<DrawerForm<API.CreateProductDTO>
|
|
title="新建"
|
|
formRef={formRef} // Pass formRef
|
|
trigger={
|
|
<Button type="primary">
|
|
<PlusOutlined />
|
|
新建
|
|
</Button>
|
|
}
|
|
autoFocusFirstInput
|
|
drawerProps={{
|
|
destroyOnHidden: true,
|
|
}}
|
|
onFinish={async (values) => {
|
|
try {
|
|
const { success, message: errMsg } =
|
|
await productcontrollerCreateproduct(values);
|
|
if (!success) {
|
|
throw new Error(errMsg);
|
|
}
|
|
tableRef.current?.reload();
|
|
message.success('提交成功');
|
|
return true;
|
|
} catch (error: any) {
|
|
message.error(error.message);
|
|
}
|
|
}}
|
|
>
|
|
<ProFormSelect
|
|
name="brandId"
|
|
width="lg"
|
|
label="产品品牌"
|
|
placeholder="请选择产品品牌"
|
|
request={async () => {
|
|
const { data = [] } = await productcontrollerGetbrandall();
|
|
setBrandOptions(data);
|
|
return data.map((item: DictItem) => ({
|
|
label: item.name,
|
|
value: item.id,
|
|
}));
|
|
}}
|
|
rules={[{ required: true, message: '请选择产品品牌' }]}
|
|
/>
|
|
<ProFormSelect
|
|
name="strengthId"
|
|
width="lg"
|
|
label="强度"
|
|
placeholder="请选择强度"
|
|
request={async () => {
|
|
const { data = [] } = await productcontrollerGetstrengthall();
|
|
setStrengthOptions(data);
|
|
return data.map((item: DictItem) => ({
|
|
label: item.name,
|
|
value: item.id,
|
|
}));
|
|
}}
|
|
rules={[{ required: true, message: '请选择强度' }]}
|
|
/>
|
|
<ProFormSelect
|
|
name="flavorsId"
|
|
width="lg"
|
|
label="口味"
|
|
placeholder="请选择口味"
|
|
request={async () => {
|
|
const { data = [] } = await productcontrollerGetflavorsall();
|
|
setFlavorOptions(data);
|
|
return data.map((item: DictItem) => ({
|
|
label: item.name,
|
|
value: item.id,
|
|
}));
|
|
}}
|
|
rules={[{ required: true, message: '请选择口味' }]}
|
|
/>
|
|
<ProFormSelect
|
|
name="humidity"
|
|
width="lg"
|
|
label="干湿"
|
|
placeholder="请选择干湿"
|
|
valueEnum={{
|
|
dry: 'dry',
|
|
wet: 'wet',
|
|
}}
|
|
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>
|
|
<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>
|
|
);
|
|
};
|
|
|
|
export default List;
|