forked from yoone/WEB
feat(站点管理): 添加批量编辑功能并优化区域选择
增加站点批量编辑功能,支持同时修改多个站点的区域、关联仓库和禁用状态 使用i18n-iso-countries库替换原有区域选择逻辑,支持中文显示国家名称 优化站点列表查询参数处理,添加分页和排序支持 修复产品创建表单中属性组装逻辑,根据产品类型决定是否组装attributes
This commit is contained in:
parent
6d97ecbcc7
commit
e23b0b3e39
|
|
@ -91,7 +91,9 @@ const HistoryOrders: React.FC<HistoryOrdersProps> = ({ customer, siteId }) => {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
try {
|
try {
|
||||||
const response = await ordercontrollerGetorders({
|
const response = await ordercontrollerGetorders({
|
||||||
|
where: {
|
||||||
customer_email: customer.email,
|
customer_email: customer.email,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
if (response) {
|
if (response) {
|
||||||
|
|
|
||||||
|
|
@ -152,6 +152,7 @@ const CustomerList: React.FC = () => {
|
||||||
{
|
{
|
||||||
title: '原始 ID',
|
title: '原始 ID',
|
||||||
dataIndex: 'origin_id',
|
dataIndex: 'origin_id',
|
||||||
|
sorter: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '站点',
|
title: '站点',
|
||||||
|
|
@ -172,10 +173,6 @@ const CustomerList: React.FC = () => {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
render(_, record) {
|
|
||||||
// console.log(`siteId`, record.site_id);
|
|
||||||
return <span>{getSiteName(record.site_id) || '-'}</span>;
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '头像',
|
title: '头像',
|
||||||
|
|
@ -209,16 +206,17 @@ const CustomerList: React.FC = () => {
|
||||||
title: '用户名',
|
title: '用户名',
|
||||||
dataIndex: 'username',
|
dataIndex: 'username',
|
||||||
hideInSearch: true,
|
hideInSearch: true,
|
||||||
|
sorter: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '邮箱',
|
title: '邮箱',
|
||||||
dataIndex: 'email',
|
dataIndex: 'email',
|
||||||
copyable: true,
|
copyable: true,
|
||||||
|
sorter: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '电话',
|
title: '电话',
|
||||||
dataIndex: 'phone',
|
dataIndex: 'phone',
|
||||||
hideInSearch: true,
|
|
||||||
copyable: true,
|
copyable: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -240,6 +238,7 @@ const CustomerList: React.FC = () => {
|
||||||
dataIndex: 'rate',
|
dataIndex: 'rate',
|
||||||
width: 120,
|
width: 120,
|
||||||
hideInSearch: true,
|
hideInSearch: true,
|
||||||
|
sorter: true,
|
||||||
render: (_, record) => {
|
render: (_, record) => {
|
||||||
return (
|
return (
|
||||||
<Rate
|
<Rate
|
||||||
|
|
@ -345,55 +344,25 @@ const CustomerList: React.FC = () => {
|
||||||
headerTitle="查询表格"
|
headerTitle="查询表格"
|
||||||
actionRef={actionRef}
|
actionRef={actionRef}
|
||||||
rowKey="id"
|
rowKey="id"
|
||||||
request={async (params, sorter) => {
|
request={async (params, sorter,filter) => {
|
||||||
// 获取排序字段和排序方向
|
console.log('custoemr request',params, sorter,filter)
|
||||||
const key = Object.keys(sorter)[0];
|
const { current, pageSize, ...restParams } = params;
|
||||||
|
const orderBy:any = {}
|
||||||
// 构建过滤条件对象
|
Object.entries(sorter).forEach(([key, value]) => {
|
||||||
const where: any = {};
|
orderBy[key] = value === 'ascend' ? 'asc' : 'desc';
|
||||||
|
})
|
||||||
// 添加邮箱过滤
|
|
||||||
if (params.email) {
|
|
||||||
where.email = params.email;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 添加站点ID过滤
|
|
||||||
if (params.site_id) {
|
|
||||||
where.site_id = params.site_id;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 添加用户名过滤
|
|
||||||
if (params.username) {
|
|
||||||
where.username = params.username;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 添加电话过滤
|
|
||||||
if (params.phone) {
|
|
||||||
where.phone = params.phone;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 构建查询参数
|
// 构建查询参数
|
||||||
const queryParams: any = {
|
const queryParams: any = {
|
||||||
page: params.current || 1,
|
page: current || 1,
|
||||||
per_page: params.pageSize || 20,
|
per_page: pageSize || 20,
|
||||||
|
where: {
|
||||||
|
...filter,
|
||||||
|
...restParams
|
||||||
|
},
|
||||||
|
orderBy
|
||||||
};
|
};
|
||||||
|
|
||||||
// 添加搜索关键词
|
const result = await customercontrollerGetcustomerlist({params: queryParams});
|
||||||
if (params.fullname) {
|
|
||||||
queryParams.search = params.fullname;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 添加过滤条件(只有在有过滤条件时才添加)
|
|
||||||
if (Object.keys(where).length > 0) {
|
|
||||||
queryParams.where = where;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 添加排序
|
|
||||||
if (key) {
|
|
||||||
queryParams.orderBy = { [key]: sorter[key] as 'asc' | 'desc' };
|
|
||||||
}
|
|
||||||
|
|
||||||
const result = await customercontrollerGetcustomerlist(queryParams);
|
|
||||||
console.log(queryParams, result);
|
console.log(queryParams, result);
|
||||||
return {
|
return {
|
||||||
total: result?.data?.total || 0,
|
total: result?.data?.total || 0,
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ import {
|
||||||
productcontrollerCreateproduct,
|
productcontrollerCreateproduct,
|
||||||
productcontrollerGetcategoriesall,
|
productcontrollerGetcategoriesall,
|
||||||
productcontrollerGetcategoryattributes,
|
productcontrollerGetcategoryattributes,
|
||||||
|
productcontrollerGetproductlist,
|
||||||
} from '@/servers/api/product';
|
} from '@/servers/api/product';
|
||||||
import { stockcontrollerGetstocks as getStocks } from '@/servers/api/stock';
|
import { stockcontrollerGetstocks as getStocks } from '@/servers/api/stock';
|
||||||
import { templatecontrollerRendertemplate } from '@/servers/api/template';
|
import { templatecontrollerRendertemplate } from '@/servers/api/template';
|
||||||
|
|
@ -200,8 +201,12 @@ const CreateForm: React.FC<{
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
onFinish={async (values: any) => {
|
onFinish={async (values: any) => {
|
||||||
// 组装 attributes(根据 activeAttributes 动态组装)
|
// 根据产品类型决定是否组装 attributes
|
||||||
const attributes = activeAttributes.flatMap((attr: any) => {
|
// 如果产品类型为 bundle,则 attributes 为空数组
|
||||||
|
// 如果产品类型为 single,则根据 activeAttributes 动态组装 attributes
|
||||||
|
const attributes = values.type === 'bundle'
|
||||||
|
? []
|
||||||
|
: activeAttributes.flatMap((attr: any) => {
|
||||||
const dictName = attr.name;
|
const dictName = attr.name;
|
||||||
const key = `${dictName}Values`;
|
const key = `${dictName}Values`;
|
||||||
const vals = values[key];
|
const vals = values[key];
|
||||||
|
|
@ -315,15 +320,18 @@ const CreateForm: React.FC<{
|
||||||
rules={[{ required: true, message: '请输入子产品SKU' }]}
|
rules={[{ required: true, message: '请输入子产品SKU' }]}
|
||||||
request={async ({ keyWords }) => {
|
request={async ({ keyWords }) => {
|
||||||
const params = keyWords
|
const params = keyWords
|
||||||
? { sku: keyWords, name: keyWords }
|
? { sku: keyWords, name: keyWords, type: 'single' }
|
||||||
: { pageSize: 9999 };
|
: { pageSize: 9999, type: 'single' };
|
||||||
const { data } = await getStocks(params as any);
|
const { data } = await productcontrollerGetproductlist(
|
||||||
|
params as any,
|
||||||
|
);
|
||||||
if (!data || !data.items) {
|
if (!data || !data.items) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
// 只返回类型为单品的产品
|
||||||
return data.items
|
return data.items
|
||||||
.filter((item) => item.sku)
|
.filter((item: any) => item.type === 'single' && item.sku)
|
||||||
.map((item) => ({
|
.map((item: any) => ({
|
||||||
label: `${item.sku} - ${item.name}`,
|
label: `${item.sku} - ${item.name}`,
|
||||||
value: item.sku,
|
value: item.sku,
|
||||||
}));
|
}));
|
||||||
|
|
|
||||||
|
|
@ -6,10 +6,13 @@ import {
|
||||||
sitecontrollerUpdate,
|
sitecontrollerUpdate,
|
||||||
} from '@/servers/api/site';
|
} from '@/servers/api/site';
|
||||||
import { subscriptioncontrollerSync } from '@/servers/api/subscription';
|
import { subscriptioncontrollerSync } from '@/servers/api/subscription';
|
||||||
import { ActionType, ProColumns, ProTable } from '@ant-design/pro-components';
|
import { stockcontrollerGetallstockpoints } from '@/servers/api/stock';
|
||||||
import { Button, message, notification, Popconfirm, Space, Tag } from 'antd';
|
import { ActionType, ProColumns, ProTable, DrawerForm, ProFormSelect, ProFormSwitch } from '@ant-design/pro-components';
|
||||||
import React, { useRef, useState } from 'react';
|
import { Button, message, notification, Popconfirm, Space, Tag, Form } from 'antd';
|
||||||
|
import React, { useRef, useState, useEffect } from 'react';
|
||||||
import EditSiteForm from '../Shop/EditSiteForm'; // 引入重构后的表单组件
|
import EditSiteForm from '../Shop/EditSiteForm'; // 引入重构后的表单组件
|
||||||
|
import * as countries from 'i18n-iso-countries';
|
||||||
|
import zhCN from 'i18n-iso-countries/langs/zh';
|
||||||
|
|
||||||
// 区域数据项类型
|
// 区域数据项类型
|
||||||
interface AreaItem {
|
interface AreaItem {
|
||||||
|
|
@ -42,6 +45,10 @@ const SiteList: React.FC = () => {
|
||||||
const [open, setOpen] = useState(false);
|
const [open, setOpen] = useState(false);
|
||||||
const [editing, setEditing] = useState<SiteItem | null>(null);
|
const [editing, setEditing] = useState<SiteItem | null>(null);
|
||||||
const [selectedRowKeys, setSelectedRowKeys] = useState<React.Key[]>([]);
|
const [selectedRowKeys, setSelectedRowKeys] = useState<React.Key[]>([]);
|
||||||
|
const [batchEditOpen, setBatchEditOpen] = useState(false);
|
||||||
|
const [batchEditForm] = Form.useForm();
|
||||||
|
countries.registerLocale(zhCN);
|
||||||
|
|
||||||
|
|
||||||
const handleSync = async (ids: number[]) => {
|
const handleSync = async (ids: number[]) => {
|
||||||
if (!ids.length) return;
|
if (!ids.length) return;
|
||||||
|
|
@ -96,6 +103,68 @@ const SiteList: React.FC = () => {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 获取所有国家/地区的选项
|
||||||
|
const getCountryOptions = () => {
|
||||||
|
// 获取所有国家的 ISO 代码
|
||||||
|
const countryCodes = countries.getAlpha2Codes();
|
||||||
|
// 将国家代码转换为选项数组
|
||||||
|
return Object.keys(countryCodes).map((code) => ({
|
||||||
|
label: countries.getName(code, 'zh') || code, // 使用中文名称, 如果没有则使用代码
|
||||||
|
value: code,
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
|
||||||
|
// 处理批量编辑提交
|
||||||
|
const handleBatchEditFinish = async (values: any) => {
|
||||||
|
if (!selectedRowKeys.length) return;
|
||||||
|
const hide = message.loading('正在批量更新...', 0);
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 遍历所有选中的站点 ID
|
||||||
|
for (const id of selectedRowKeys) {
|
||||||
|
// 构建更新数据对象,只包含用户填写了值的字段
|
||||||
|
const updateData: any = {};
|
||||||
|
|
||||||
|
// 如果用户选择了区域,则更新区域
|
||||||
|
if (values.areas && values.areas.length > 0) {
|
||||||
|
updateData.areas = values.areas;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果用户选择了仓库,则更新仓库
|
||||||
|
if (values.stockPointIds && values.stockPointIds.length > 0) {
|
||||||
|
updateData.stockPointIds = values.stockPointIds;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果用户设置了禁用状态,则更新状态
|
||||||
|
if (values.isDisabled !== undefined) {
|
||||||
|
updateData.isDisabled = values.isDisabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果有需要更新的字段,则调用更新接口
|
||||||
|
if (Object.keys(updateData).length > 0) {
|
||||||
|
await sitecontrollerUpdate({ id: String(id) }, updateData);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
hide();
|
||||||
|
message.success('批量更新成功');
|
||||||
|
setBatchEditOpen(false);
|
||||||
|
setSelectedRowKeys([]);
|
||||||
|
batchEditForm.resetFields();
|
||||||
|
actionRef.current?.reload();
|
||||||
|
} catch (error: any) {
|
||||||
|
hide();
|
||||||
|
message.error(error.message || '批量更新失败');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 当批量编辑弹窗打开时,重置表单
|
||||||
|
useEffect(() => {
|
||||||
|
if (batchEditOpen) {
|
||||||
|
batchEditForm.resetFields();
|
||||||
|
}
|
||||||
|
}, [batchEditOpen, batchEditForm]);
|
||||||
|
|
||||||
// 表格列定义
|
// 表格列定义
|
||||||
const columns: ProColumns<SiteItem>[] = [
|
const columns: ProColumns<SiteItem>[] = [
|
||||||
{
|
{
|
||||||
|
|
@ -122,23 +191,42 @@ const SiteList: React.FC = () => {
|
||||||
{
|
{
|
||||||
title: 'SKU 前缀',
|
title: 'SKU 前缀',
|
||||||
dataIndex: 'skuPrefix',
|
dataIndex: 'skuPrefix',
|
||||||
width: 160,
|
|
||||||
hideInSearch: true,
|
hideInSearch: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '平台',
|
title: '平台',
|
||||||
dataIndex: 'type',
|
dataIndex: 'type',
|
||||||
width: 140,
|
|
||||||
valueType: 'select',
|
valueType: 'select',
|
||||||
request: async () => [
|
request: async () => [
|
||||||
{ label: 'WooCommerce', value: 'woocommerce' },
|
{ label: 'WooCommerce', value: 'woocommerce' },
|
||||||
{ label: 'Shopyy', value: 'shopyy' },
|
{ label: 'Shopyy', value: 'shopyy' },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
// 地区列配置
|
||||||
|
title: "地区",
|
||||||
|
dataIndex: "areas",
|
||||||
|
hideInSearch: true,
|
||||||
|
render: (_, row) => {
|
||||||
|
// 如果没有关联地区,显示"全局"标签
|
||||||
|
if (!row.areas || row.areas.length === 0) {
|
||||||
|
return <Tag color="default">全局</Tag>;
|
||||||
|
}
|
||||||
|
// 遍历显示所有关联的地区名称
|
||||||
|
return (
|
||||||
|
<Space wrap>
|
||||||
|
{row.areas.map((area) => (
|
||||||
|
<Tag color="geekblue" key={area.code}>
|
||||||
|
{area.name}
|
||||||
|
</Tag>
|
||||||
|
))}
|
||||||
|
</Space>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
title: '关联仓库',
|
title: '关联仓库',
|
||||||
dataIndex: 'stockPoints',
|
dataIndex: 'stockPoints',
|
||||||
width: 200,
|
|
||||||
hideInSearch: true,
|
hideInSearch: true,
|
||||||
render: (_, row) => {
|
render: (_, row) => {
|
||||||
if (!row.stockPoints || row.stockPoints.length === 0) {
|
if (!row.stockPoints || row.stockPoints.length === 0) {
|
||||||
|
|
@ -267,6 +355,12 @@ const SiteList: React.FC = () => {
|
||||||
selectedRowKeys,
|
selectedRowKeys,
|
||||||
onChange: setSelectedRowKeys,
|
onChange: setSelectedRowKeys,
|
||||||
}}
|
}}
|
||||||
|
pagination={{
|
||||||
|
defaultPageSize: 20,
|
||||||
|
showSizeChanger: true,
|
||||||
|
showQuickJumper: true,
|
||||||
|
showTotal: (total) => `共 ${total} 条`,
|
||||||
|
}}
|
||||||
toolBarRender={() => [
|
toolBarRender={() => [
|
||||||
<Button
|
<Button
|
||||||
type="primary"
|
type="primary"
|
||||||
|
|
@ -277,6 +371,12 @@ const SiteList: React.FC = () => {
|
||||||
>
|
>
|
||||||
新建站点
|
新建站点
|
||||||
</Button>,
|
</Button>,
|
||||||
|
<Button
|
||||||
|
disabled={!selectedRowKeys.length}
|
||||||
|
onClick={() => setBatchEditOpen(true)}
|
||||||
|
>
|
||||||
|
批量编辑
|
||||||
|
</Button>,
|
||||||
<Button
|
<Button
|
||||||
disabled={!selectedRowKeys.length}
|
disabled={!selectedRowKeys.length}
|
||||||
onClick={() => handleSync(selectedRowKeys as number[])}
|
onClick={() => handleSync(selectedRowKeys as number[])}
|
||||||
|
|
@ -298,6 +398,51 @@ const SiteList: React.FC = () => {
|
||||||
isEdit={!!editing}
|
isEdit={!!editing}
|
||||||
onFinish={handleFinish}
|
onFinish={handleFinish}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
{/* 批量编辑弹窗 */}
|
||||||
|
<DrawerForm
|
||||||
|
title={`批量编辑站点 (${selectedRowKeys.length} 个)`}
|
||||||
|
form={batchEditForm}
|
||||||
|
open={batchEditOpen}
|
||||||
|
onOpenChange={setBatchEditOpen}
|
||||||
|
onFinish={handleBatchEditFinish}
|
||||||
|
layout="vertical"
|
||||||
|
>
|
||||||
|
<ProFormSelect
|
||||||
|
name="areas"
|
||||||
|
label="区域"
|
||||||
|
mode="multiple"
|
||||||
|
placeholder="请选择区域(留空表示不修改)"
|
||||||
|
showSearch
|
||||||
|
filterOption={(input, option) =>
|
||||||
|
(option?.label ?? '').toLowerCase().includes(input.toLowerCase())
|
||||||
|
}
|
||||||
|
options={getCountryOptions()}
|
||||||
|
/>
|
||||||
|
<ProFormSelect
|
||||||
|
name="stockPointIds"
|
||||||
|
label="关联仓库"
|
||||||
|
mode="multiple"
|
||||||
|
placeholder="请选择关联仓库(留空表示不修改)"
|
||||||
|
request={async () => {
|
||||||
|
// 从后端接口获取仓库数据
|
||||||
|
const res = await stockcontrollerGetallstockpoints();
|
||||||
|
// 使用可选链和空值合并运算符来安全地处理可能未定义的数据
|
||||||
|
return (
|
||||||
|
res?.data?.map((sp: any) => ({ label: sp.name, value: sp.id })) ??
|
||||||
|
[]
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<ProFormSwitch
|
||||||
|
name="isDisabled"
|
||||||
|
label="是否禁用"
|
||||||
|
fieldProps={{
|
||||||
|
checkedChildren: '是',
|
||||||
|
unCheckedChildren: '否',
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</DrawerForm>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,8 @@ import {
|
||||||
} from '@ant-design/pro-components';
|
} from '@ant-design/pro-components';
|
||||||
import { Form } from 'antd';
|
import { Form } from 'antd';
|
||||||
import React, { useEffect } from 'react';
|
import React, { useEffect } from 'react';
|
||||||
|
import * as countries from 'i18n-iso-countries';
|
||||||
|
import zhCN from 'i18n-iso-countries/langs/zh';
|
||||||
|
|
||||||
// 定义组件的 props 类型
|
// 定义组件的 props 类型
|
||||||
interface EditSiteFormProps {
|
interface EditSiteFormProps {
|
||||||
|
|
@ -29,6 +31,9 @@ const EditSiteForm: React.FC<EditSiteFormProps> = ({
|
||||||
}) => {
|
}) => {
|
||||||
const [form] = Form.useForm();
|
const [form] = Form.useForm();
|
||||||
|
|
||||||
|
// 初始化中文语言包
|
||||||
|
countries.registerLocale(zhCN);
|
||||||
|
|
||||||
// 当 initialValues 或 open 状态变化时, 更新表单的值
|
// 当 initialValues 或 open 状态变化时, 更新表单的值
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// 如果抽屉是打开的
|
// 如果抽屉是打开的
|
||||||
|
|
@ -36,8 +41,10 @@ const EditSiteForm: React.FC<EditSiteFormProps> = ({
|
||||||
// 如果是编辑模式并且有初始值
|
// 如果是编辑模式并且有初始值
|
||||||
if (isEdit && initialValues) {
|
if (isEdit && initialValues) {
|
||||||
// 编辑模式下, 设置表单值为初始值
|
// 编辑模式下, 设置表单值为初始值
|
||||||
|
const { token, consumerKey, consumerSecret, ...safeInitialValues } = initialValues;
|
||||||
|
// 清空敏感字段, 让用户输入最新的数据
|
||||||
form.setFieldsValue({
|
form.setFieldsValue({
|
||||||
...initialValues,
|
...safeInitialValues,
|
||||||
isDisabled: initialValues.isDisabled === 1, // 将后端的 1/0 转换成 true/false
|
isDisabled: initialValues.isDisabled === 1, // 将后端的 1/0 转换成 true/false
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -47,6 +54,17 @@ const EditSiteForm: React.FC<EditSiteFormProps> = ({
|
||||||
}
|
}
|
||||||
}, [initialValues, isEdit, open, form]);
|
}, [initialValues, isEdit, open, form]);
|
||||||
|
|
||||||
|
// 获取所有国家/地区的选项
|
||||||
|
const getCountryOptions = () => {
|
||||||
|
// 获取所有国家的 ISO 代码
|
||||||
|
const countryCodes = countries.getAlpha2Codes();
|
||||||
|
// 将国家代码转换为选项数组
|
||||||
|
return Object.keys(countryCodes).map((code) => ({
|
||||||
|
label: countries.getName(code, 'zh') || code, // 使用中文名称, 如果没有则使用代码
|
||||||
|
value: code,
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DrawerForm
|
<DrawerForm
|
||||||
title={isEdit ? '编辑站点' : '新建站点'}
|
title={isEdit ? '编辑站点' : '新建站点'}
|
||||||
|
|
@ -146,15 +164,11 @@ const EditSiteForm: React.FC<EditSiteFormProps> = ({
|
||||||
label="区域"
|
label="区域"
|
||||||
mode="multiple"
|
mode="multiple"
|
||||||
placeholder="请选择区域"
|
placeholder="请选择区域"
|
||||||
request={async () => {
|
showSearch
|
||||||
// 从后端接口获取区域数据
|
filterOption={(input, option) =>
|
||||||
const res = await areacontrollerGetarealist({ pageSize: 1000 });
|
(option?.label ?? '').toLowerCase().includes(input.toLowerCase())
|
||||||
// areacontrollerGetarealist 直接返回数组, 所以不需要 .data.list
|
}
|
||||||
return res.map((area: any) => ({
|
options={getCountryOptions()}
|
||||||
label: area.name,
|
|
||||||
value: area.code,
|
|
||||||
}));
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
<ProFormSelect
|
<ProFormSelect
|
||||||
name="stockPointIds"
|
name="stockPointIds"
|
||||||
|
|
|
||||||
|
|
@ -15,9 +15,13 @@ import {
|
||||||
ProFormText,
|
ProFormText,
|
||||||
ProTable,
|
ProTable,
|
||||||
} from '@ant-design/pro-components';
|
} from '@ant-design/pro-components';
|
||||||
import { request } from '@umijs/max';
|
|
||||||
import { App, Button, Divider, Popconfirm, Space, Tag } from 'antd';
|
import { App, Button, Divider, Popconfirm, Space, Tag } from 'antd';
|
||||||
import { useRef } from 'react';
|
import { useRef } from 'react';
|
||||||
|
import * as countries from 'i18n-iso-countries';
|
||||||
|
import zhCN from 'i18n-iso-countries/langs/zh';
|
||||||
|
|
||||||
|
// 初始化中文语言包
|
||||||
|
countries.registerLocale(zhCN);
|
||||||
|
|
||||||
// 区域数据项类型
|
// 区域数据项类型
|
||||||
interface AreaItem {
|
interface AreaItem {
|
||||||
|
|
@ -25,6 +29,17 @@ interface AreaItem {
|
||||||
name: string;
|
name: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 获取所有国家/地区的选项
|
||||||
|
const getCountryOptions = () => {
|
||||||
|
// 获取所有国家的 ISO 代码
|
||||||
|
const countryCodes = countries.getAlpha2Codes();
|
||||||
|
// 将国家代码转换为选项数组
|
||||||
|
return Object.keys(countryCodes).map((code) => ({
|
||||||
|
label: countries.getName(code, 'zh') || code, // 使用中文名称, 如果没有则使用代码
|
||||||
|
value: code,
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
|
||||||
const ListPage: React.FC = () => {
|
const ListPage: React.FC = () => {
|
||||||
const { message } = App.useApp();
|
const { message } = App.useApp();
|
||||||
const actionRef = useRef<ActionType>();
|
const actionRef = useRef<ActionType>();
|
||||||
|
|
@ -190,23 +205,11 @@ const CreateForm: React.FC<{
|
||||||
width="lg"
|
width="lg"
|
||||||
mode="multiple"
|
mode="multiple"
|
||||||
placeholder="留空表示全球"
|
placeholder="留空表示全球"
|
||||||
request={async () => {
|
showSearch
|
||||||
try {
|
filterOption={(input, option) =>
|
||||||
const resp = await request('/area', {
|
(option?.label ?? '').toLowerCase().includes(input.toLowerCase())
|
||||||
method: 'GET',
|
|
||||||
params: { pageSize: 1000 },
|
|
||||||
});
|
|
||||||
if (resp.success) {
|
|
||||||
return resp.data.list.map((area: AreaItem) => ({
|
|
||||||
label: area.name,
|
|
||||||
value: area.code,
|
|
||||||
}));
|
|
||||||
}
|
}
|
||||||
return [];
|
options={getCountryOptions()}
|
||||||
} catch (e) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
</ProForm.Group>
|
</ProForm.Group>
|
||||||
</DrawerForm>
|
</DrawerForm>
|
||||||
|
|
@ -289,23 +292,11 @@ const UpdateForm: React.FC<{
|
||||||
width="lg"
|
width="lg"
|
||||||
mode="multiple"
|
mode="multiple"
|
||||||
placeholder="留空表示全球"
|
placeholder="留空表示全球"
|
||||||
request={async () => {
|
showSearch
|
||||||
try {
|
filterOption={(input, option) =>
|
||||||
const resp = await request('/area', {
|
(option?.label ?? '').toLowerCase().includes(input.toLowerCase())
|
||||||
method: 'GET',
|
|
||||||
params: { pageSize: 1000 },
|
|
||||||
});
|
|
||||||
if (resp.success) {
|
|
||||||
return resp.data.list.map((area: AreaItem) => ({
|
|
||||||
label: area.name,
|
|
||||||
value: area.code,
|
|
||||||
}));
|
|
||||||
}
|
}
|
||||||
return [];
|
options={getCountryOptions()}
|
||||||
} catch (e) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
</ProForm.Group>
|
</ProForm.Group>
|
||||||
</DrawerForm>
|
</DrawerForm>
|
||||||
|
|
|
||||||
|
|
@ -59,9 +59,16 @@ export async function sitecontrollerGet(
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 此处后端没有提供注释 GET /site/list */
|
/** 此处后端没有提供注释 GET /site/list */
|
||||||
export async function sitecontrollerList(options?: { [key: string]: any }) {
|
export async function sitecontrollerList(
|
||||||
|
// 叠加生成的Param类型 (非body参数swagger默认没有生成对象)
|
||||||
|
params: API.sitecontrollerListParams,
|
||||||
|
options?: { [key: string]: any },
|
||||||
|
) {
|
||||||
return request<any>('/site/list', {
|
return request<any>('/site/list', {
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
|
params: {
|
||||||
|
...params,
|
||||||
|
},
|
||||||
...(options || {}),
|
...(options || {}),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -302,6 +302,24 @@ declare namespace API {
|
||||||
};
|
};
|
||||||
|
|
||||||
type CreateSiteDTO = {
|
type CreateSiteDTO = {
|
||||||
|
/** 站点 API URL */
|
||||||
|
apiUrl?: string;
|
||||||
|
/** 站点网站 URL */
|
||||||
|
websiteUrl?: string;
|
||||||
|
/** 站点 REST Key */
|
||||||
|
consumerKey?: string;
|
||||||
|
/** 站点 REST 秘钥 */
|
||||||
|
consumerSecret?: string;
|
||||||
|
/** 访问令牌 */
|
||||||
|
token?: string;
|
||||||
|
/** 站点名称 */
|
||||||
|
name?: string;
|
||||||
|
/** 站点描述 */
|
||||||
|
description?: string;
|
||||||
|
/** 平台类型 */
|
||||||
|
type?: 'woocommerce' | 'shopyy';
|
||||||
|
/** SKU 前缀 */
|
||||||
|
skuPrefix?: string;
|
||||||
/** 区域 */
|
/** 区域 */
|
||||||
areas?: any;
|
areas?: any;
|
||||||
/** 绑定仓库ID列表 */
|
/** 绑定仓库ID列表 */
|
||||||
|
|
@ -426,7 +444,10 @@ declare namespace API {
|
||||||
id: number;
|
id: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
type DisableSiteDTO = {};
|
type DisableSiteDTO = {
|
||||||
|
/** 是否禁用 */
|
||||||
|
disabled?: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
type FulfillmentDTO = {
|
type FulfillmentDTO = {
|
||||||
/** 物流单号 */
|
/** 物流单号 */
|
||||||
|
|
@ -1399,7 +1420,18 @@ declare namespace API {
|
||||||
isActive?: boolean;
|
isActive?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
type QuerySiteDTO = {};
|
type QuerySiteDTO = {
|
||||||
|
/** 当前页码 */
|
||||||
|
current?: number;
|
||||||
|
/** 每页数量 */
|
||||||
|
pageSize?: number;
|
||||||
|
/** 搜索关键词 */
|
||||||
|
keyword?: string;
|
||||||
|
/** 是否禁用 */
|
||||||
|
isDisabled?: boolean;
|
||||||
|
/** 站点ID列表(逗号分隔) */
|
||||||
|
ids?: string;
|
||||||
|
};
|
||||||
|
|
||||||
type QueryStockDTO = {
|
type QueryStockDTO = {
|
||||||
/** 页码 */
|
/** 页码 */
|
||||||
|
|
@ -2050,6 +2082,19 @@ declare namespace API {
|
||||||
id: string;
|
id: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
type sitecontrollerListParams = {
|
||||||
|
/** 当前页码 */
|
||||||
|
current?: number;
|
||||||
|
/** 每页数量 */
|
||||||
|
pageSize?: number;
|
||||||
|
/** 搜索关键词 */
|
||||||
|
keyword?: string;
|
||||||
|
/** 是否禁用 */
|
||||||
|
isDisabled?: boolean;
|
||||||
|
/** 站点ID列表(逗号分隔) */
|
||||||
|
ids?: string;
|
||||||
|
};
|
||||||
|
|
||||||
type sitecontrollerUpdateParams = {
|
type sitecontrollerUpdateParams = {
|
||||||
id: string;
|
id: string;
|
||||||
};
|
};
|
||||||
|
|
@ -3080,6 +3125,24 @@ declare namespace API {
|
||||||
};
|
};
|
||||||
|
|
||||||
type UpdateSiteDTO = {
|
type UpdateSiteDTO = {
|
||||||
|
/** 站点 API URL */
|
||||||
|
apiUrl?: string;
|
||||||
|
/** 站点 REST Key */
|
||||||
|
consumerKey?: string;
|
||||||
|
/** 站点 REST 秘钥 */
|
||||||
|
consumerSecret?: string;
|
||||||
|
/** 访问令牌 */
|
||||||
|
token?: string;
|
||||||
|
/** 站点名称 */
|
||||||
|
name?: string;
|
||||||
|
/** 站点描述 */
|
||||||
|
description?: string;
|
||||||
|
/** 是否禁用 */
|
||||||
|
isDisabled?: boolean;
|
||||||
|
/** 平台类型 */
|
||||||
|
type?: 'woocommerce' | 'shopyy';
|
||||||
|
/** SKU 前缀 */
|
||||||
|
skuPrefix?: string;
|
||||||
/** 区域 */
|
/** 区域 */
|
||||||
areas?: any;
|
areas?: any;
|
||||||
/** 绑定仓库ID列表 */
|
/** 绑定仓库ID列表 */
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue