style: 统一中文标点符号为英文格式并优化注释格式

修复中文标点符号使用不一致的问题,将全角标点替换为半角标点
优化代码注释格式,移除冗余的中文注释标记
调整部分注释内容使其更简洁清晰
This commit is contained in:
tikkhun 2025-12-02 22:24:55 +08:00
parent 3b66a7c49c
commit 04c0d0a756
32 changed files with 321 additions and 243 deletions

View File

@ -15,7 +15,7 @@ import { usercontrollerGetuser } from './servers/api/user';
// 设置 dayjs 全局语言为中文
dayjs.locale('zh-cn');
// 全局初始化数据配置用于 Layout 用户信息和权限初始化
// 全局初始化数据配置,用于 Layout 用户信息和权限初始化
// 更多信息见文档:https://umijs.org/docs/api/runtime-config#getinitialstate
export async function getInitialState(): Promise<{
user?: Record<string, any>;
@ -102,11 +102,11 @@ export const request: RequestConfig = {
export const onRouteChange = ({ location }: { location: Location }) => {
const token = localStorage.getItem('token');
// 白名单不需要登录的页面
// 白名单,不需要登录的页面
const whiteList = ['/login', '/track'];
if (!token && !whiteList.includes(location.pathname)) {
// 没有 token 且不在白名单内跳转到登录页
// 没有 token 且不在白名单内,跳转到登录页
history.push('/login');
}
};

View File

@ -27,7 +27,7 @@ const SyncForm: React.FC<SyncFormProps> = ({ tableRef, onFinish }) => {
return (
<DrawerForm<API.ordercontrollerSyncorderParams>
title="同步订单"
// 表单的触发器一个带图标的按钮
// 表单的触发器,一个带图标的按钮
trigger={
<Button key="syncSite" type="primary">
<SyncOutlined />

View File

@ -29,5 +29,5 @@ export function useDeviceFingerprint() {
};
}, []);
return fingerprint; // 初始为 null加载后返回指纹 ID
return fingerprint; // 初始为 null,加载后返回指纹 ID
}

View File

@ -80,7 +80,7 @@ const AreaList: React.FC = () => {
</Button>
<Popconfirm
title="删除区域"
description="确认删除该区域"
description="确认删除该区域?"
onConfirm={async () => {
try {
await request(`/area/${row.id}`, {

View File

@ -197,7 +197,7 @@ const CategoryPage: React.FC = () => {
</a>,
<Popconfirm
key="delete"
title="确定删除该分类吗"
title="确定删除该分类吗?"
onConfirm={(e) => {
e?.stopPropagation();
handleDeleteCategory(item.id);
@ -218,7 +218,7 @@ const CategoryPage: React.FC = () => {
</Sider>
<Content style={{ padding: '24px' }}>
{selectedCategory ? (
<Card title={`分类${selectedCategory.title} (${selectedCategory.name})`} extra={<Button type="primary" onClick={handleAddAttribute}></Button>}>
<Card title={`分类:${selectedCategory.title} (${selectedCategory.name})`} extra={<Button type="primary" onClick={handleAddAttribute}></Button>}>
<List
loading={loadingAttributes}
dataSource={categoryAttributes}
@ -226,7 +226,7 @@ const CategoryPage: React.FC = () => {
<List.Item
actions={[
<Popconfirm
title="确定移除该属性吗"
title="确定移除该属性吗?"
onConfirm={() => handleDeleteAttribute(item.id)}
>
<Button type="link" danger></Button>

View File

@ -289,7 +289,7 @@ const DictPage: React.FC = () => {
size="small"
onRow={(record) => ({
onClick: () => {
// 如果点击的是当前已选中的行则取消选择
// 如果点击的是当前已选中的行,则取消选择
if (selectedDict?.id === record.id) {
setSelectedDict(null);
} else {
@ -356,7 +356,7 @@ const DictPage: React.FC = () => {
<ProTable
columns={dictItemColumns}
request={async (params) => {
// 当没有选择字典时不发起请求
// 当没有选择字典时,不发起请求
if (!selectedDict?.id) {
return {
data: [],

View File

@ -96,11 +96,11 @@ const Page = () => {
/>
),
}}
placeholder={'请输入密码'}
placeholder={'请输入密码!'}
rules={[
{
required: true,
message: '请输入密码',
message: '请输入密码!',
},
]}
/>

View File

@ -75,7 +75,7 @@ const ListPage: React.FC = () => {
<Divider type="vertical" />
<Popconfirm
title="删除"
description="确认删除"
description="确认删除?"
onConfirm={async () => {
try {
const { success, message: errMsg } =

View File

@ -74,9 +74,9 @@ const ListPage: React.FC = () => {
await navigator.clipboard.writeText(
record.return_tracking_number,
);
message.success('复制成功');
message.success('复制成功!');
} catch (err) {
message.error('复制失败');
message.error('复制失败!');
}
}}
/>
@ -140,7 +140,7 @@ const ListPage: React.FC = () => {
<Popconfirm
disabled={isLoading}
title="删除"
description="确认删除"
description="确认删除?"
onConfirm={async () => {
try {
setIsLoading(true);

View File

@ -28,7 +28,7 @@ const OrderItemsPage: React.FC = () => {
const actionRef = useRef<ActionType>();
const { message } = App.useApp();
// 列配置(中文标题,符合当前项目风格;显示英文默认语言可后续走国际化)
// 列配置(中文标题,符合当前项目风格;显示英文默认语言可后续走国际化)
const columns: ProColumns<OrderItemAggRow>[] = [
{
title: '商品名称',

View File

@ -381,7 +381,7 @@ const ListPage: React.FC = () => {
label: (
<Popconfirm
title="转至售后"
description="确认转至售后"
description="确认转至售后?"
onConfirm={async () => {
try {
if (!record.id) {
@ -513,7 +513,7 @@ const Detail: React.FC<{
orderId,
});
if (!success || !data) return { data: {} };
// 合并订单中相同的sku只显示一次记录总数
// 合并订单中相同的sku,只显示一次记录总数
data.sales = data.sales?.reduce(
(acc: API.OrderSale[], cur: API.OrderSale) => {
let idx = acc.findIndex((v: any) => v.productId === cur.productId);
@ -605,7 +605,7 @@ const Detail: React.FC<{
<Divider type="vertical" />,
<Popconfirm
title="转至售后"
description="确认转至售后"
description="确认转至售后?"
onConfirm={async () => {
try {
if (!record.id) {
@ -641,7 +641,7 @@ const Detail: React.FC<{
<Divider type="vertical" />,
<Popconfirm
title="转至取消"
description="确认转至取消"
description="确认转至取消?"
onConfirm={async () => {
try {
if (!record.id) {
@ -668,7 +668,7 @@ const Detail: React.FC<{
<Divider type="vertical" />,
<Popconfirm
title="转至退款"
description="确认转至退款"
description="确认转至退款?"
onConfirm={async () => {
try {
if (!record.id) {
@ -695,7 +695,7 @@ const Detail: React.FC<{
<Divider type="vertical" />,
<Popconfirm
title="转至完成"
description="确认转至完成"
description="确认转至完成?"
onConfirm={async () => {
try {
if (!record.id) {
@ -722,7 +722,7 @@ const Detail: React.FC<{
<Divider type="vertical" />,
<Popconfirm
title="转至待补发"
description="确认转至待补发"
description="确认转至待补发?"
onConfirm={async () => {
try {
const { success, message: errMsg } =
@ -999,9 +999,9 @@ const Detail: React.FC<{
await navigator.clipboard.writeText(
v.tracking_url,
);
message.success('复制成功');
message.success('复制成功!');
} catch (err) {
message.error('复制失败');
message.error('复制失败!');
}
}}
/>
@ -1013,7 +1013,7 @@ const Detail: React.FC<{
? [
<Popconfirm
title="取消运单"
description="确认取消运单"
description="确认取消运单?"
onConfirm={async () => {
try {
const { success, message: errMsg } =
@ -1461,7 +1461,7 @@ const Shipping: React.FC<{
showSearch: true,
filterOption: false,
}}
debounceTime={300} // 防抖减少请求频率
debounceTime={300} // 防抖,减少请求频率
rules={[{ required: true, message: '请选择产品' }]}
/>
<ProFormDigit
@ -2083,7 +2083,7 @@ const SalesChange: React.FC<{
showSearch: true,
filterOption: false,
}}
debounceTime={300} // 防抖减少请求频率
debounceTime={300} // 防抖,减少请求频率
rules={[{ required: true, message: '请选择订单' }]}
/>
<ProFormDigit
@ -2126,7 +2126,7 @@ const SalesChange: React.FC<{
showSearch: true,
filterOption: false,
}}
debounceTime={300} // 防抖减少请求频率
debounceTime={300} // 防抖,减少请求频率
rules={[{ required: true, message: '请选择产品' }]}
/>
<ProFormDigit
@ -2226,7 +2226,7 @@ const CreateOrder: React.FC<{
showSearch: true,
filterOption: false,
}}
debounceTime={300} // 防抖减少请求频率
debounceTime={300} // 防抖,减少请求频率
rules={[{ required: true, message: '请选择产品' }]}
/>
<ProFormDigit

View File

@ -37,7 +37,7 @@ const ListPage: React.FC = () => {
hideInSearch: true,
width: 800,
render: (_, record) => {
return record?.numbers?.join?.('');
return record?.numbers?.join?.(',');
},
},
];
@ -72,7 +72,7 @@ const ListPage: React.FC = () => {
// 数据行
const rows = (data?.items || []).map((item) => {
return [item.name, item.quantity, item.numbers?.join('')];
return [item.name, item.quantity, item.numbers?.join(',')];
});
// 导出

View File

@ -70,7 +70,7 @@ const ListPage: React.FC = () => {
danger={record.isActive}
type="link"
onClick={async () => {
// 中文注释软删除为禁用isActive=false再次点击可启用
// 软删除为禁用(isActive=false),再次点击可启用
const next = !record.isActive;
const { success, message: errMsg } =
await usercontrollerToggleactive({
@ -204,7 +204,7 @@ const EditForm: React.FC<{
}}
onFinish={async (values: any) => {
try {
// 中文注释:更新用户,密码可选填
// 更新用户,密码可选填
const { success, message: err } = await usercontrollerUpdateuser(
{ id: record.id },
values,

View File

@ -1,4 +1,4 @@
// 中文注释:限定允许管理的字典名称集合
// 限定允许管理的字典名称集合
export const attributes = new Set([
'brand',
'strength',

View File

@ -23,16 +23,16 @@ const { Sider, Content } = Layout;
import { attributes } from './consts';
const AttributePage: React.FC = () => {
// 中文注释:左侧字典列表状态
// 左侧字典列表状态
const [dicts, setDicts] = useState<any[]>([]);
const [loadingDicts, setLoadingDicts] = useState(false);
const [searchText, setSearchText] = useState('');
const [selectedDict, setSelectedDict] = useState<any>(null);
// 中文注释:右侧字典项 ProTable 的引用
// 右侧字典项 ProTable 的引用
const actionRef = useRef<ActionType>();
// 中文注释:字典项新增/编辑模态框控制
// 字典项新增/编辑模态框控制
const [isDictItemModalVisible, setIsDictItemModalVisible] = useState(false);
const [editingDictItem, setEditingDictItem] = useState<any>(null);
const [dictItemForm] = Form.useForm();
@ -41,7 +41,7 @@ const AttributePage: React.FC = () => {
setLoadingDicts(true);
try {
const res = await request('/dict/list', { params: { title } });
// 中文注释:条件判断,过滤只保留 allowedDictNames 中的字典
// 条件判断,过滤只保留 allowedDictNames 中的字典
const filtered = (res || []).filter((d: any) => attributes.has(d?.name));
setDicts(filtered);
} catch (error) {
@ -50,42 +50,42 @@ const AttributePage: React.FC = () => {
setLoadingDicts(false);
};
// 中文注释:组件挂载时初始化数据
// 组件挂载时初始化数据
useEffect(() => {
fetchDicts();
}, []);
// 中文注释:搜索触发过滤
// 搜索触发过滤
const handleSearch = (value: string) => {
fetchDicts(value);
};
// 中文注释:打开添加字典项模态框
// 打开添加字典项模态框
const handleAddDictItem = () => {
setEditingDictItem(null);
dictItemForm.resetFields();
setIsDictItemModalVisible(true);
};
// 中文注释:打开编辑字典项模态框
// 打开编辑字典项模态框
const handleEditDictItem = (item: any) => {
setEditingDictItem(item);
dictItemForm.setFieldsValue(item);
setIsDictItemModalVisible(true);
};
// 中文注释:字典项表单提交(新增或编辑)
// 字典项表单提交(新增或编辑)
const handleDictItemFormSubmit = async (values: any) => {
try {
if (editingDictItem) {
// 中文注释:条件判断,存在编辑项则执行更新
// 条件判断,存在编辑项则执行更新
await request(`/dict/item/${editingDictItem.id}`, {
method: 'PUT',
data: values,
});
message.success('更新成功');
} else {
// 中文注释:否则执行新增,绑定到当前选择的字典
// 否则执行新增,绑定到当前选择的字典
await request('/dict/item', {
method: 'POST',
data: { ...values, dictId: selectedDict.id },
@ -93,30 +93,30 @@ const AttributePage: React.FC = () => {
message.success('添加成功');
}
setIsDictItemModalVisible(false);
actionRef.current?.reload(); // 中文注释:刷新 ProTable
actionRef.current?.reload(); // 刷新 ProTable
} catch (error) {
message.error(editingDictItem ? '更新失败' : '添加失败');
}
};
// 中文注释:删除字典项
// 删除字典项
const handleDeleteDictItem = async (itemId: number) => {
try {
await request(`/dict/item/${itemId}`, { method: 'DELETE' });
message.success('删除成功');
actionRef.current?.reload(); // 中文注释:刷新 ProTable
actionRef.current?.reload(); // 刷新 ProTable
} catch (error) {
message.error('删除失败');
}
};
// 中文注释:左侧字典列表列定义(紧凑样式)
// 左侧字典列表列定义(紧凑样式)
const dictColumns = [
{ title: '名称', dataIndex: 'name', key: 'name' },
{ title: '标题', dataIndex: 'title', key: 'title' },
];
// 中文注释:右侧字典项列表列定义(紧凑样式)
// 右侧字典项列表列定义(紧凑样式)
const dictItemColumns: any[] = [
{ title: '名称', dataIndex: 'name', key: 'name', copyable: true },
{ title: '标题', dataIndex: 'title', key: 'title', copyable: true },
@ -177,7 +177,7 @@ const AttributePage: React.FC = () => {
size="small"
onRow={(record) => ({
onClick: () => {
// 中文注释:条件判断,重复点击同一行则取消选择
// 条件判断,重复点击同一行则取消选择
if (selectedDict?.id === record.id) {
setSelectedDict(null);
} else {
@ -197,7 +197,7 @@ const AttributePage: React.FC = () => {
columns={dictItemColumns}
actionRef={actionRef}
request={async (params) => {
// 中文注释:当没有选择字典时,不发起请求
// 当没有选择字典时,不发起请求
if (!selectedDict?.id) {
return {
data: [],
@ -242,7 +242,7 @@ const AttributePage: React.FC = () => {
showUploadList={false}
disabled={!selectedDict}
onChange={(info) => {
// 中文注释:条件判断,上传状态处理
// 条件判断,上传状态处理
if (info.file.status === 'done') {
message.success(`${info.file.name} 文件上传成功`);
actionRef.current?.reload();

View File

@ -202,7 +202,7 @@ const CategoryPage: React.FC = () => {
</a>,
<Popconfirm
key="delete"
title="确定删除该分类吗"
title="确定删除该分类吗?"
onConfirm={(e) => {
e?.stopPropagation();
handleDeleteCategory(item.id);
@ -223,7 +223,7 @@ const CategoryPage: React.FC = () => {
</Sider>
<Content style={{ padding: '24px' }}>
{selectedCategory ? (
<Card title={`分类${selectedCategory.title} (${selectedCategory.name})`} extra={<Button type="primary" onClick={handleAddAttribute}></Button>}>
<Card title={`分类:${selectedCategory.title} (${selectedCategory.name})`} extra={<Button type="primary" onClick={handleAddAttribute}></Button>}>
<List
loading={loadingAttributes}
dataSource={categoryAttributes}
@ -231,7 +231,7 @@ const CategoryPage: React.FC = () => {
<List.Item
actions={[
<Popconfirm
title="确定移除该属性吗"
title="确定移除该属性吗?"
onConfirm={() => handleDeleteAttribute(item.id)}
>
<Button type="link" danger></Button>

View File

@ -94,11 +94,11 @@ const ComponentsCell: React.FC<{ productId: number }> = ({ productId }) => {
components.map((component: any) => (
<Tag key={component.id} color="blue" style={{ marginBottom: 4 }}>
{component.sku || `#${component.id}`} × {component.quantity}
(:
{component.stock
?.map((s: any) => `${s.name}:${s.quantity}`)
.join(', ') || '-'}
)
</Tag>
))
) : (
@ -110,22 +110,22 @@ const ComponentsCell: React.FC<{ productId: number }> = ({ productId }) => {
const List: React.FC = () => {
const actionRef = useRef<ActionType>();
// 状态存储当前选中的行
// 状态:存储当前选中的行
const [selectedRows, setSelectedRows] = React.useState<API.Product[]>([]);
const { message } = App.useApp();
// 中文注释:导出产品 CSV带认证请求
// 导出产品 CSV(带认证请求)
const handleDownloadProductsCSV = async () => {
try {
// 中文注释:发起认证请求获取 CSV Blob
// 发起认证请求获取 CSV Blob
const blob = await request('/product/export', { responseType: 'blob' });
// 中文注释:构建下载文件名
// 构建下载文件名
const d = new Date();
const pad = (n: number) => String(n).padStart(2, '0');
const filename = `products-${d.getFullYear()}${pad(
d.getMonth() + 1,
)}${pad(d.getDate())}.csv`;
// 中文注释:创建临时链接并触发下载
// 创建临时链接并触发下载
const url = window.URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
@ -142,10 +142,12 @@ const List: React.FC = () => {
{
title: 'sku',
dataIndex: 'sku',
sorter: true,
},
{
title: '名称',
dataIndex: 'name',
sorter: true,
},
{
title: '中文名',
@ -156,27 +158,7 @@ const List: React.FC = () => {
);
},
},
{
title: '产品类型',
dataIndex: 'type',
valueType: 'select',
valueEnum: {
single: { text: '单品' },
bundle: { text: '套装' },
},
render: (_, record) => {
// 如果类型不存在,则返回-
if (!record.type) return '-';
// 判断是否为单品
const isSingle = record.type === 'single';
// 根据类型显示不同颜色的标签
return (
<Tag color={isSingle ? 'green' : 'orange'}>
{isSingle ? '单品' : '套装'}
</Tag>
);
},
},
{
title: '商品类型',
dataIndex: 'category',
@ -188,17 +170,40 @@ const List: React.FC = () => {
title: '价格',
dataIndex: 'price',
hideInSearch: true,
sorter: true,
},
{
title: '促销价',
dataIndex: 'promotionPrice',
hideInSearch: true,
sorter: true,
},
{
title: '属性',
dataIndex: 'attributes',
hideInSearch: true,
render: (_, record) => <AttributesCell record={record} />,
},
{
title: '产品类型',
dataIndex: 'type',
valueType: 'select',
valueEnum: {
single: { text: '单品' },
bundle: { text: '套装' },
},
render: (_, record) => {
// 如果类型不存在,则返回-
if (!record.type) return '-';
// 判断是否为单品
const isSingle = record.type === 'single';
// 根据类型显示不同颜色的标签
return (
<Tag color={isSingle ? 'green' : 'orange'}>
{isSingle ? '单品' : '套装'}
</Tag>
);
},
},
{
title: '构成',
@ -217,12 +222,14 @@ const List: React.FC = () => {
dataIndex: 'updatedAt',
valueType: 'dateTime',
hideInSearch: true,
sorter: true,
},
{
title: '创建时间',
dataIndex: 'createdAt',
valueType: 'dateTime',
hideInSearch: true,
sorter: true,
},
{
title: '操作',
@ -234,7 +241,7 @@ const List: React.FC = () => {
<EditForm record={record} tableRef={actionRef} />
<Popconfirm
title="删除"
description="确认删除"
description="确认删除?"
onConfirm={async () => {
try {
const { success, message: errMsg } =
@ -264,33 +271,53 @@ const List: React.FC = () => {
actionRef={actionRef}
rowKey="id"
toolBarRender={() => [
// 中文注释:新建按钮
// 新建按钮
<CreateForm tableRef={actionRef} />,
// 中文注释:导出 CSV后端返回 text/csv直接新窗口下载
// 导出 CSV(后端返回 text/csv,直接新窗口下载)
<Button onClick={handleDownloadProductsCSV}>CSV</Button>,
// 中文注释:导入 CSV上传文件成功后刷新表格
// 导入 CSV(使用 customRequest 以支持 request 拦截器和鉴权)
<Upload
name="file"
action="/product/import"
accept=".csv"
showUploadList={false}
maxCount={1}
onChange={({ file }) => {
if (file.status === 'done') {
customRequest={async (options) => {
const { file, onSuccess, onError } = options;
const formData = new FormData();
formData.append('file', file);
try {
await request('/product/import', {
method: 'POST',
data: formData,
requestType: 'form',
});
message.success('导入完成');
onSuccess?.('ok');
actionRef.current?.reload();
} else if (file.status === 'error') {
} catch (error: any) {
message.error('导入失败');
onError?.(error);
}
}}
>
<Button>CSV</Button>
</Upload>,
]}
request={async (params) => {
const { data, success } = await productcontrollerGetproductlist(
params,
);
request={async (params, sort) => {
let sortField = undefined;
let sortOrder = undefined;
if (sort && Object.keys(sort).length > 0) {
const field = Object.keys(sort)[0];
sortField = field;
sortOrder = sort[field];
}
const { data, success } = await productcontrollerGetproductlist({
...params,
sortField,
sortOrder,
} as any);
return {
total: data?.total || 0,
data: data?.items || [],
@ -355,10 +382,10 @@ const CreateForm: React.FC<{
const { humidityValues, brandValues, strengthValues, flavorValues } =
formValues;
// 检查是否所有必需的字段都已选择
// 注意:这里仅检查标准属性,如果当前分类没有这些属性,可能需要调整逻辑
// 暂时保持原样假设常用属性会被配置
// 注意:这里仅检查标准属性,如果当前分类没有这些属性,可能需要调整逻辑
// 暂时保持原样,假设常用属性会被配置
// 所选值(用于 SKU 模板传入 name
// 所选值(用于 SKU 模板传入 name)
const brandName: string = String(brandValues?.[0] || '');
const strengthName: string = String(strengthValues?.[0] || '');
const flavorName: string = String(flavorValues?.[0] || '');
@ -480,14 +507,14 @@ const CreateForm: React.FC<{
formRef.current?.setFieldsValue({ type: 'bundle' });
}
} else {
// 如果 sku 不存在则重置状态
// 如果 sku 不存在,则重置状态
setStockStatus(null);
formRef.current?.setFieldsValue({ type: null });
}
}
}}
onFinish={async (values: any) => {
// 中文注释:组装 attributes根据 activeAttributes 动态组装)
// 组装 attributes(根据 activeAttributes 动态组装)
const attributes = activeAttributes.flatMap((attr: any) => {
const dictName = attr.name;
const key = `${dictName}Values`;
@ -715,12 +742,12 @@ const EditForm: React.FC<{
sku: record.sku,
} as any);
if (stockData && stockData.items && stockData.items.length > 0) {
// 如果有库存则为单品
// 如果有库存,则为单品
setType('single');
setStockStatus('in-stock');
formRef.current?.setFieldsValue({ type: 'single' });
} else {
// 如果没有库存则为套装
// 如果没有库存,则为套装
setType('bundle');
setStockStatus('out-of-stock');
formRef.current?.setFieldsValue({ type: 'bundle' });
@ -785,13 +812,13 @@ const EditForm: React.FC<{
formRef.current?.setFieldsValue({ type: 'bundle' });
}
} else {
// 如果 sku 不存在则重置状态
// 如果 sku 不存在,则重置状态
formRef.current?.setFieldsValue({ type: null });
}
}
}}
onFinish={async (values) => {
// 中文注释:组装 attributes
// 组装 attributes
const attributes = activeAttributes.flatMap((attr: any) => {
const dictName = attr.name;
const key = `${dictName}Values`;

View File

@ -8,6 +8,7 @@ interface Site {
id: string;
name: string;
prefix?: string;
isDisabled?: boolean;
}
// 定义WordPress商品接口
@ -80,7 +81,9 @@ const ProductSyncPage: React.FC = () => {
setLoading(true);
// 获取所有站点
const sitesResponse = await getSites();
const siteList: Site[] = sitesResponse.data || [];
const rawSiteList = sitesResponse.data || [];
// 过滤掉已禁用的站点
const siteList: Site[] = rawSiteList.filter(site => !site.isDisabled);
setSites(siteList);
// 获取所有 WordPress 商品
@ -120,7 +123,7 @@ const ProductSyncPage: React.FC = () => {
// 转换为数组
setProducts(Array.from(productMap.values()));
} catch (error) {
message.error('获取数据失败请重试');
message.error('获取数据失败,请重试');
console.error('Error fetching data:', error);
} finally {
setLoading(false);

View File

@ -2,6 +2,7 @@ import {
ActionType,
DrawerForm,
ProColumns,
ProFormDependency,
ProFormInstance,
ProFormSelect,
ProFormSwitch,
@ -18,7 +19,7 @@ interface AreaItem {
name: string;
}
// 站点数据项类型(前端不包含密钥字段,后端列表不返回密钥)
// 站点数据项类型(前端不包含密钥字段,后端列表不返回密钥)
interface SiteItem {
id: number;
name: string;
@ -29,7 +30,7 @@ interface SiteItem {
areas?: AreaItem[];
}
// 创建/更新表单的值类型包含可选的密钥字段
// 创建/更新表单的值类型,包含可选的密钥字段
interface SiteFormValues {
name: string;
apiUrl?: string;
@ -37,6 +38,7 @@ interface SiteFormValues {
isDisabled?: boolean;
consumerKey?: string; // WooCommerce REST API 的 consumer key
consumerSecret?: string; // WooCommerce REST API 的 consumer secret
token?: string; // Shopyy token
skuPrefix?: string;
areas?: string[];
}
@ -58,6 +60,7 @@ const SiteList: React.FC = () => {
isDisabled: !!editing.isDisabled,
consumerKey: undefined,
consumerSecret: undefined,
token: undefined,
areas: editing.areas?.map((area) => area.code) ?? [],
});
} else {
@ -69,6 +72,7 @@ const SiteList: React.FC = () => {
isDisabled: false,
consumerKey: undefined,
consumerSecret: undefined,
token: undefined,
});
}
}, [open, editing]);
@ -148,7 +152,7 @@ const SiteList: React.FC = () => {
<Popconfirm
title={row.isDisabled ? '启用站点' : '禁用站点'}
description={
row.isDisabled ? '确认启用该站点' : '确认禁用该站点?'
row.isDisabled ? '确认启用该站点?' : '确认禁用该站点?'
}
onConfirm={async () => {
try {
@ -198,14 +202,17 @@ const SiteList: React.FC = () => {
}
};
// 提交创建/更新逻辑;编辑时未填写密钥则不提交(保持原值)
// 提交创建/更新逻辑;编辑时未填写密钥则不提交(保持原值)
const handleSubmit = async (values: SiteFormValues) => {
try {
const isShopyy = values.type === 'shopyy';
const apiUrl = isShopyy ? 'https://openapi.oemapps.com' : values.apiUrl;
if (editing) {
const payload: Record<string, any> = {
// 仅提交存在的字段,避免覆盖为 null/空
// 仅提交存在的字段,避免覆盖为 null/空
...(values.name ? { name: values.name } : {}),
...(values.apiUrl ? { apiUrl: values.apiUrl } : {}),
...(apiUrl ? { apiUrl: apiUrl } : {}),
...(values.type ? { type: values.type } : {}),
...(typeof values.isDisabled === 'boolean'
? { isDisabled: values.isDisabled }
@ -213,30 +220,46 @@ const SiteList: React.FC = () => {
...(values.skuPrefix ? { skuPrefix: values.skuPrefix } : {}),
areas: values.areas ?? [],
};
// 仅当输入了新密钥时才提交,未输入则保持原本值
if (values.consumerKey && values.consumerKey.trim()) {
payload.consumerKey = values.consumerKey.trim();
}
if (values.consumerSecret && values.consumerSecret.trim()) {
payload.consumerSecret = values.consumerSecret.trim();
if (isShopyy) {
if (values.token && values.token.trim()) {
payload.token = values.token.trim();
}
} else {
// 仅当输入了新密钥时才提交,未输入则保持原本值
if (values.consumerKey && values.consumerKey.trim()) {
payload.consumerKey = values.consumerKey.trim();
}
if (values.consumerSecret && values.consumerSecret.trim()) {
payload.consumerSecret = values.consumerSecret.trim();
}
}
await request(`/site/update/${editing.id}`, {
method: 'PUT',
data: payload,
});
} else {
// 新增站点时要求填写 consumerKey 和 consumerSecret
if (!values.consumerKey || !values.consumerSecret) {
throw new Error('Consumer Key and Secret are required');
if (isShopyy) {
if (!values.token) {
throw new Error('Token is required for Shopyy');
}
} else {
// 新增站点时要求填写 consumerKey 和 consumerSecret
if (!values.consumerKey || !values.consumerSecret) {
throw new Error('Consumer Key and Secret are required for WooCommerce');
}
}
await request('/site/create', {
method: 'POST',
data: {
name: values.name,
apiUrl: values.apiUrl,
apiUrl: apiUrl,
type: values.type || 'woocommerce',
consumerKey: values.consumerKey,
consumerSecret: values.consumerSecret,
consumerKey: isShopyy ? undefined : values.consumerKey,
consumerSecret: isShopyy ? undefined : values.consumerSecret,
token: isShopyy ? values.token : undefined,
skuPrefix: values.skuPrefix,
areas: values.areas ?? [],
},
@ -286,31 +309,14 @@ const SiteList: React.FC = () => {
formRef={formRef}
onFinish={handleSubmit}
>
{/* 站点名称必填 */}
{/* 站点名称,必填 */}
<ProFormText
name="name"
label="站点名称"
placeholder="例如本地商店"
placeholder="例如:本地商店"
rules={[{ required: true, message: '站点名称为必填项' }]}
/>
{/* API 地址,可选 */}
<ProFormText
name="apiUrl"
label="API 地址"
placeholder="例如https://shop.example.com"
/>
{/* 平台类型选择 */}
<ProFormSelect
name="type"
label="平台"
options={[
{ label: 'WooCommerce', value: 'woocommerce' },
{ label: 'Shopyy', value: 'shopyy' },
]}
/>
{/* 是否禁用 */}
<ProFormSwitch name="isDisabled" label="禁用" />
{/* 区域选择 */}
{/* 区域选择 */}
<ProFormSelect
name="areas"
label="区域"
@ -334,27 +340,69 @@ const SiteList: React.FC = () => {
}
}}
/>
{/* 平台类型选择 */}
<ProFormSelect
name="type"
label="平台"
options={[
{ label: 'WooCommerce', value: 'woocommerce' },
{ label: 'Shopyy', value: 'shopyy' },
]}
/>
<ProFormDependency name={['type']}>
{({ type }) => {
const isShopyy = type === 'shopyy';
return isShopyy ? (
<>
<ProFormText
name="apiUrl"
label="API 地址"
disabled
initialValue="https://openapi.oemapps.com"
placeholder="https://openapi.oemapps.com"
/>
<ProFormText
name="token"
label="Token"
placeholder={editing ? '留空表示不修改' : '必填'}
rules={editing ? [] : [{ required: true, message: 'Token 为必填项' }]}
/>
</>
) : (
<>
<ProFormText
name="apiUrl"
label="API 地址"
placeholder="例如:https://shop.example.com"
rules={[{ required: true, message: 'API 地址为必填项' }]}
/>
{/* WooCommerce REST consumer key */}
<ProFormText
name="consumerKey"
label="Key"
placeholder={editing ? '留空表示不修改' : '必填'}
rules={editing ? [] : [{ required: true, message: 'Key 为必填项' }]}
/>
{/* WooCommerce REST consumer secret */}
<ProFormText
name="consumerSecret"
label="Secret"
placeholder={editing ? '留空表示不修改' : '必填'}
rules={editing ? [] : [{ required: true, message: 'Secret 为必填项' }]}
/>
</>
);
}}
</ProFormDependency>
{editing && <ProFormSwitch name="isDisabled" label="禁用" />}
<ProFormText
name="skuPrefix"
label="SKU 前缀"
placeholder={editing ? '留空表示不修改' : '可选'}
/>
{/* WooCommerce REST consumer key新增必填编辑不填则保持原值 */}
<ProFormText
name="consumerKey"
label="Key"
placeholder={editing ? '留空表示不修改' : '必填'}
rules={editing ? [] : [{ required: true, message: 'Key 为必填项' }]}
/>
{/* WooCommerce REST consumer secret新增必填编辑不填则保持原值 */}
<ProFormText
name="consumerSecret"
label="Secret"
placeholder={editing ? '留空表示不修改' : '必填'}
rules={
editing ? [] : [{ required: true, message: 'Secret 为必填项' }]
}
/>
</DrawerForm>
</>
);

View File

@ -118,7 +118,7 @@ const ListPage: React.FC = () => {
// 数据行
const rows = (data?.items || []).map((item: API.StockDTO) => {
// 处理stockPoint可能为undefined的情况并正确定义类型
// 处理stockPoint可能为undefined的情况,并正确定义类型
const stockMap = new Map<number, number>(
(item.stockPoint || []).map((sp: any) => [
sp.id || 0,

View File

@ -94,7 +94,7 @@ const PurchaseOrderPage: React.FC = () => {
<Divider type="vertical" />
<Popconfirm
title="删除"
description="确认删除"
description="确认删除?"
onConfirm={async () => {
try {
const { success, message: errMsg } =
@ -120,7 +120,7 @@ const PurchaseOrderPage: React.FC = () => {
<Divider type="vertical" />
<Popconfirm
title="入库"
description="确认已到达"
description="确认已到达?"
onConfirm={async () => {
try {
const { success, message: errMsg } =
@ -297,7 +297,7 @@ const CreateForm: React.FC<{
transform={(value) => {
return value?.value || value;
}}
debounceTime={300} // 防抖减少请求频率
debounceTime={300} // 防抖,减少请求频率
rules={[{ required: true, message: '请选择产品' }]}
onChange={(_, option) => {
form.setFieldValue(
@ -478,7 +478,7 @@ const UpdateForm: React.FC<{
transform={(value) => {
return value?.value || value;
}}
debounceTime={300} // 防抖减少请求频率
debounceTime={300} // 防抖,减少请求频率
rules={[{ required: true, message: '请选择产品' }]}
onChange={(_, option) => {
form.setFieldValue(
@ -643,7 +643,7 @@ const DetailForm: React.FC<{
transform={(value) => {
return value?.value || value;
}}
debounceTime={300} // 防抖减少请求频率
debounceTime={300} // 防抖,减少请求频率
rules={[{ required: true, message: '请选择产品' }]}
onChange={(_, option) => {
form.setFieldValue(

View File

@ -95,7 +95,7 @@ const TransferPage: React.FC = () => {
<Divider type="vertical" />
<Popconfirm
title="入库"
description="确认已到达"
description="确认已到达?"
onConfirm={async () => {
try {
const { success, message: errMsg } =
@ -116,7 +116,7 @@ const TransferPage: React.FC = () => {
<Divider type="vertical" />
<Popconfirm
title="丢失"
description="确认该批货已丢失"
description="确认该批货已丢失?"
onConfirm={async () => {
try {
const { success, message: errMsg } =
@ -137,7 +137,7 @@ const TransferPage: React.FC = () => {
<Divider type="vertical" />
<Popconfirm
title="取消"
description="确认取消"
description="确认取消?"
onConfirm={async () => {
try {
const { success, message: errMsg } =
@ -354,7 +354,7 @@ const CreateForm: React.FC<{
transform={(value) => {
return value?.value || value;
}}
debounceTime={300} // 防抖减少请求频率
debounceTime={300} // 防抖,减少请求频率
rules={[{ required: true, message: '请选择产品' }]}
onChange={(_, option) => {
form.setFieldValue(
@ -530,7 +530,7 @@ const UpdateForm: React.FC<{
transform={(value) => {
return value?.value || value;
}}
debounceTime={300} // 防抖减少请求频率
debounceTime={300} // 防抖,减少请求频率
rules={[{ required: true, message: '请选择产品' }]}
onChange={(_, option) => {
form.setFieldValue(
@ -687,7 +687,7 @@ const DetailForm: React.FC<{
transform={(value) => {
return value?.value || value;
}}
debounceTime={300} // 防抖减少请求频率
debounceTime={300} // 防抖,减少请求频率
rules={[{ required: true, message: '请选择产品' }]}
onChange={(_, option) => {
form.setFieldValue(

View File

@ -76,7 +76,7 @@ const ListPage: React.FC = () => {
<Divider type="vertical" />
<Popconfirm
title="删除"
description="确认删除"
description="确认删除?"
onConfirm={async () => {
try {
const { success, message: errMsg } =

View File

@ -29,7 +29,7 @@ const SUBSCRIPTION_STATUS_ENUM: Record<string, { text: string }> = {
};
/**
* 订阅列表页:展示
* 订阅列表页:展示,,
*/
const ListPage: React.FC = () => {
// 表格操作引用:用于在同步后触发表格刷新
@ -75,7 +75,7 @@ const ListPage: React.FC = () => {
dataIndex: 'status',
valueType: 'select',
valueEnum: SUBSCRIPTION_STATUS_ENUM,
// 以 Tag 形式展示更易辨识
// 以 Tag 形式展示,更易辨识
render: (_, row) =>
row?.status ? (
<Tag>{SUBSCRIPTION_STATUS_ENUM[row.status]?.text || row.status}</Tag>
@ -159,7 +159,7 @@ const ListPage: React.FC = () => {
const candidates: any[] = (
Array.isArray(data) ? data : []
).filter((c: any) => String(c?.externalOrderId) === parentNumber);
// 拉取详情,补充状态、金额、时间
// 拉取详情,补充状态,金额,时间
const details = [] as any[];
for (const c of candidates) {
const d = await request(`/order/${c.id}`, { method: 'GET' });
@ -205,7 +205,7 @@ const ListPage: React.FC = () => {
rowKey="id"
actionRef={actionRef}
/**
*
* ;
* data.items data.list
*/
request={async (params) => {
@ -220,7 +220,7 @@ const ListPage: React.FC = () => {
// 工具栏:订阅同步入口
toolBarRender={() => [<SyncForm key="sync" tableRef={actionRef} />]}
/>
{/* 关联订单抽屉:展示订单号、关系、时间、状态与金额 */}
{/* 关联订单抽屉:展示订单号,关系,时间,状态与金额 */}
<Drawer
open={drawerOpen}
title={drawerTitle}
@ -234,7 +234,7 @@ const ListPage: React.FC = () => {
<List.Item>
<List.Item.Meta
title={`#${item?.externalOrderId || '-'}`}
description={`关系:${item?.relationship || '-'}站点:${
description={`关系:${item?.relationship || '-'},站点:${
item?.siteName || '-'
}`}
/>
@ -281,7 +281,7 @@ const SyncForm: React.FC<{
/**
* :
* 1. ProForm + rules
* 2.
* 2. ,
* 3.
*/
onFinish={async (values) => {

View File

@ -17,8 +17,8 @@ import { ORDER_STATUS_ENUM } from '@/constants';
import { formatShipmentState, formatSource } from '@/utils/format';
import RelatedOrders from './RelatedOrders';
// 为保持原文件结构简单此处从 index.tsx 引入的子组件仍由原文件导出或保持原状
// 若后续需要彻底解耦可将 OrderNote / Shipping / SalesChange 也独立到文件
// 为保持原文件结构简单,此处从 index.tsx 引入的子组件仍由原文件导出或保持原状
// 若后续需要彻底解耦,可将 OrderNote / Shipping / SalesChange 也独立到文件
// 当前按你的要求仅抽离详情 Drawer
type OrderRecord = API.Order;
@ -118,7 +118,7 @@ const OrderDetailDrawer: React.FC<OrderDetailDrawerProps> = ({
<Popconfirm
key="btn-after-sale"
title="转至售后"
description="确认转至售后"
description="确认转至售后?"
onConfirm={async () => {
try {
const { success, message: errMsg } =
@ -145,7 +145,7 @@ const OrderDetailDrawer: React.FC<OrderDetailDrawerProps> = ({
<Popconfirm
key="btn-cancel"
title="转至取消"
description="确认转至取消"
description="确认转至取消?"
onConfirm={async () => {
try {
const { success, message: errMsg } =
@ -168,7 +168,7 @@ const OrderDetailDrawer: React.FC<OrderDetailDrawerProps> = ({
<Popconfirm
key="btn-refund"
title="转至退款"
description="确认转至退款"
description="确认转至退款?"
onConfirm={async () => {
try {
const { success, message: errMsg } =
@ -191,7 +191,7 @@ const OrderDetailDrawer: React.FC<OrderDetailDrawerProps> = ({
<Popconfirm
key="btn-completed"
title="转至完成"
description="确认转至完成"
description="确认转至完成?"
onConfirm={async () => {
try {
const { success, message: errMsg } =
@ -425,9 +425,9 @@ const OrderDetailDrawer: React.FC<OrderDetailDrawerProps> = ({
await navigator.clipboard.writeText(
v.tracking_url,
);
message.success('复制成功');
message.success('复制成功!');
} catch {
message.error('复制失败');
message.error('复制失败!');
}
}}
/>
@ -440,7 +440,7 @@ const OrderDetailDrawer: React.FC<OrderDetailDrawerProps> = ({
<Popconfirm
key="action-cancel"
title="取消运单"
description="确认取消运单"
description="确认取消运单?"
onConfirm={async () => {
try {
const { success, message: errMsg } =

View File

@ -7,8 +7,8 @@ dayjs.extend(relativeTime);
/**
* RelatedOrders
* (/)
* 便
* (/),
* ,便
*/
const RelatedOrders: React.FC<{ data?: any[] }> = ({ data = [] }) => {
const rows = (Array.isArray(data) ? data : []).map((it: any) => {
@ -48,7 +48,7 @@ const RelatedOrders: React.FC<{ data?: any[] }> = ({ data = [] }) => {
return (
<div style={{ width: '100%' }}>
{/* 表头(英文文案符合国际化默认英文的要求) */}
{/* 表头(英文文案,符合国际化默认英文的要求) */}
<div
style={{
display: 'grid',

View File

@ -63,7 +63,7 @@ const List: React.FC = () => {
<UpdateForm tableRef={actionRef} values={record} />
<Popconfirm
title="删除"
description="确认删除"
description="确认删除?"
onConfirm={async () => {
if (!record.id) return;
try {

View File

@ -630,7 +630,7 @@ const SetComponent: React.FC<{
transform={(value) => {
return value?.value || value;
}}
debounceTime={300} // 防抖减少请求频率
debounceTime={300} // 防抖,减少请求频率
rules={[{ required: true, message: '请选择产品' }]}
/>
<ProFormDigit

View File

@ -25,7 +25,7 @@ interface TagConfig {
// 移植 Python 脚本中的核心函数
/**
* @description
* @description ,,
*/
const parseName = (
name: string,
@ -38,8 +38,8 @@ const parseName = (
const mgMatch = nm.match(/(\d+)\s*MG/i);
const mg = mgMatch ? mgMatch[1] : '';
// 确保品牌按长度降序排序,避免部分匹配(如匹配到 VELO 而不是 VELO MAX
// 这一步其实应该在传入 brands 之前就做好了但这里再保险一下
// 确保品牌按长度降序排序,避免部分匹配(如匹配到 VELO 而不是 VELO MAX)
// 这一步其实应该在传入 brands 之前就做好了,但这里再保险一下
// 实际调用时 sortedBrands 已经排好序了
for (const b of brands) {
if (nm.toUpperCase().startsWith(b.toUpperCase())) {
@ -84,7 +84,7 @@ const splitFlavorTokens = (flavorPart: string): string[] => {
};
/**
* @description Fruit, Mint
* @description ( Fruit, Mint)
*/
const classifyExtraTags = (
flavorPart: string,
@ -111,7 +111,7 @@ const classifyExtraTags = (
const matchAttributes = (text: string, keys: string[]): string[] => {
const matched = new Set<string>();
for (const key of keys) {
// 使用单词边界匹配避免部分匹配
// 使用单词边界匹配,避免部分匹配
// 转义正则特殊字符
const escapedKey = key.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
const regex = new RegExp(`\\b${escapedKey}\\b`, 'i');
@ -129,7 +129,7 @@ const computeTags = (name: string, sku: string, config: TagConfig): string => {
const [brand, flavorPart, mg, dryness] = parseName(name, config.brands);
const tokens = splitFlavorTokens(flavorPart);
// 白名单模式只保留在 flavorKeys 中的 token
// 白名单模式:只保留在 flavorKeys 中的 token
// 且对比时忽略大小写
const flavorKeysLower = config.flavorKeys.map(k => k.toLowerCase());
@ -181,7 +181,7 @@ const computeTags = (name: string, sku: string, config: TagConfig): string => {
}
// 保留原有的 dryness 提取逻辑 (从括号中提取)
// 如果 dict 匹配已经覆盖了去重时会处理
// 如果 dict 匹配已经覆盖了,去重时会处理
if (dryness) {
if (/moist/i.test(dryness)) {
tags.push('Moisture');
@ -197,8 +197,8 @@ const computeTags = (name: string, sku: string, config: TagConfig): string => {
// 去重并保留顺序
const seen = new Set<string>();
const finalTags = tags.filter((t) => {
// 简单的去重忽略大小写差异? 或者完全匹配
// 这里使用完全匹配因为前面已经做了一些格式化
// 简单的去重,忽略大小写差异? 或者完全匹配
// 这里使用完全匹配,因为前面已经做了一些格式化
if (t && !seen.has(t)) {
seen.add(t);
return true;
@ -210,7 +210,7 @@ const computeTags = (name: string, sku: string, config: TagConfig): string => {
};
/**
* @description WordPress CSV Tags
* @description WordPress , CSV Tags
*/
const WpToolPage: React.FC = () => {
// 状态管理
@ -285,9 +285,9 @@ const WpToolPage: React.FC = () => {
* @param {File} uploadedFile -
*/
const handleFileUpload = (uploadedFile: File) => {
// 检查文件类型,虽然 xlsx 库更宽容,但最好还是保留基本验证
// 检查文件类型,虽然 xlsx 库更宽容,但最好还是保留基本验证
if (!uploadedFile.name.match(/\.(csv|xlsx|xls)$/)) {
message.error('请上传 CSV 或 Excel 格式的文件');
message.error('请上传 CSV 或 Excel 格式的文件!');
return false;
}
setFile(uploadedFile);
@ -302,7 +302,7 @@ const WpToolPage: React.FC = () => {
const jsonData = XLSX.utils.sheet_to_json(worksheet, { header: 1 });
if (jsonData.length < 2) {
message.error('文件为空或缺少表头');
message.error('文件为空或缺少表头!');
setCsvData([]);
return;
}
@ -317,17 +317,17 @@ const WpToolPage: React.FC = () => {
return rowData;
});
message.success(`成功解析 ${rows.length} 条数据`);
message.success(`成功解析 ${rows.length} 条数据.`);
setCsvData(rows);
setProcessedData([]); // 清空旧的处理结果
} catch (error) {
message.error('文件解析失败,请检查文件格式!');
message.error('文件解析失败,请检查文件格式!');
console.error('File Parse Error:', error);
setCsvData([]);
}
};
reader.onerror = (error) => {
message.error('文件读取失败');
message.error('文件读取失败!');
console.error('File Read Error:', error);
};
reader.readAsBinaryString(uploadedFile);
@ -352,16 +352,16 @@ const WpToolPage: React.FC = () => {
const fileName = `products_with_tags_${Date.now()}.xlsx`;
XLSX.writeFile(workbook, fileName);
message.success('下载任务已开始');
message.success('下载任务已开始!');
};
/**
* @description CSV Tags
* @description 核心逻辑:根据配置处CSV Tags
*/
const handleProcessData = async () => {
// 验证是否已上传并解析了数据
if (csvData.length === 0) {
message.warning('请先上传并成功解析一个 CSV 文件');
message.warning('请先上传并成功解析一个 CSV 文件.');
return;
}
@ -400,7 +400,7 @@ const WpToolPage: React.FC = () => {
setProcessedData(dataWithTags);
message.success({
content: 'Tags 生成成功正在自动下载...',
content: 'Tags 生成成功!正在自动下载...',
key: 'processing',
});
@ -409,7 +409,7 @@ const WpToolPage: React.FC = () => {
} catch (error) {
message.error({
content: '处理失败,请检查配置或文件。',
content: '处理失败,请检查配置或文件.',
key: 'processing',
});
console.error('Processing Error:', error);
@ -421,7 +421,7 @@ const WpToolPage: React.FC = () => {
return (
<PageContainer title="WordPress 产品工具">
<Row gutter={[16, 16]}>
{/* 左侧配置表单 */}
{/* 左侧:配置表单 */}
<Col xs={24} md={10}>
<Card title="1. 配置映射规则">
<ProForm
@ -434,58 +434,58 @@ const WpToolPage: React.FC = () => {
name="brands"
label="品牌列表"
mode="tags"
placeholder="请输入品牌按回车确认"
placeholder="请输入品牌,按回车确认"
rules={[{ required: true, message: '至少需要一个品牌' }]}
tooltip="按品牌名称长度倒序匹配,请将较长的品牌(如 WHITE FOX放在前面。"
tooltip="按品牌名称长度倒序匹配,请将较长的品牌(如 WHITE FOX)放在前面."
/>
<ProFormSelect
name="fruitKeys"
label="水果关键词"
mode="tags"
placeholder="请输入关键词按回车确认"
placeholder="请输入关键词,按回车确认"
/>
<ProFormSelect
name="mintKeys"
label="薄荷关键词"
mode="tags"
placeholder="请输入关键词按回车确认"
placeholder="请输入关键词,按回车确认"
/>
<ProFormSelect
name="flavorKeys"
label="口味白名单"
mode="tags"
placeholder="请输入关键词按回车确认"
tooltip="只有在白名单中的词才会被识别为口味"
placeholder="请输入关键词,按回车确认"
tooltip="只有在白名单中的词才会被识别为口味."
/>
<ProFormSelect
name="strengthKeys"
label="强度关键词"
mode="tags"
placeholder="请输入关键词按回车确认"
placeholder="请输入关键词,按回车确认"
/>
<ProFormSelect
name="sizeKeys"
label="尺寸关键词"
mode="tags"
placeholder="请输入关键词按回车确认"
placeholder="请输入关键词,按回车确认"
/>
<ProFormSelect
name="humidityKeys"
label="湿度关键词"
mode="tags"
placeholder="请输入关键词按回车确认"
placeholder="请输入关键词,按回车确认"
/>
<ProFormSelect
name="categoryKeys"
label="分类关键词"
mode="tags"
placeholder="请输入关键词按回车确认"
placeholder="请输入关键词,按回车确认"
/>
</ProForm>
</Card>
</Col>
{/* 右侧文件上传与操作 */}
{/* 右侧:文件上传与操作 */}
<Col xs={24} md={14}>
<Card title="2. 上传文件并操作">
<Upload

View File

@ -2,7 +2,7 @@
/* eslint-disable */
import { request } from 'umi';
/** 获取区域列表(分页) GET /area/ */
/** 获取区域列表(分页) GET /area/ */
export async function areacontrollerGetarealist(
// 叠加生成的Param类型 (非body参数swagger默认没有生成对象)
params: API.areacontrollerGetarealistParams,

View File

@ -1,7 +1,7 @@
// @ts-ignore
/* eslint-disable */
// API 更新时间
// API 唯一标识
// API 更新时间:
// API 唯一标识:
import * as area from './area';
import * as category from './category';
import * as customer from './customer';

View File

@ -27,7 +27,7 @@ declare namespace API {
currentPage?: number;
/** 每页数量 */
pageSize?: number;
/** 关键词(名称或编码) */
/** 关键词(名称或编码) */
keyword?: string;
};
@ -443,7 +443,7 @@ declare namespace API {
| 'return-approved'
| 'return-cancelled';
payment_method?: string;
/** 仅订阅订单(父订阅订单或包含订阅商品) */
/** 仅订阅订单(父订阅订单或包含订阅商品) */
isSubscriptionOnly?: boolean;
};
@ -994,7 +994,7 @@ declare namespace API {
currentPage?: number;
/** 每页数量 */
pageSize?: number;
/** 关键词(名称或编码) */
/** 关键词(名称或编码) */
keyword?: string;
};
@ -1036,7 +1036,7 @@ declare namespace API {
| 'return-approved'
| 'return-cancelled';
payment_method?: string;
/** 仅订阅订单(父订阅订单或包含订阅商品) */
/** 仅订阅订单(父订阅订单或包含订阅商品) */
isSubscriptionOnly?: boolean;
};
@ -1115,7 +1115,7 @@ declare namespace API {
sku?: string;
/** 按库存点ID排序 */
sortPointId?: number;
/** 排序对象格式如 { productName: "asc", sku: "desc" } */
/** 排序对象,格式如 { productName: "asc", sku: "desc" } */
order?: Record<string, any>;
};
@ -1149,7 +1149,7 @@ declare namespace API {
| 'pending-cancel';
/** 客户邮箱 */
customer_email?: string;
/** 关键字订阅ID、邮箱等 */
/** 关键字(订阅ID,邮箱等) */
keyword?: string;
};
@ -1383,7 +1383,7 @@ declare namespace API {
sku?: string;
/** 按库存点ID排序 */
sortPointId?: number;
/** 排序对象格式如 { productName: "asc", sku: "desc" } */
/** 排序对象,格式如 { productName: "asc", sku: "desc" } */
order?: Record<string, any>;
};
@ -1548,7 +1548,7 @@ declare namespace API {
billing_interval?: number;
customer_id?: number;
customer_email?: string;
/** 父订单/父订阅ID(如有) */
/** 父订单/父订阅ID(如有) */
parent_id?: number;
start_date?: string;
trial_end?: string;
@ -1579,7 +1579,7 @@ declare namespace API {
| 'pending-cancel';
/** 客户邮箱 */
customer_email?: string;
/** 关键字订阅ID、邮箱等 */
/** 关键字(订阅ID,邮箱等) */
keyword?: string;
};