feat: 主要优化产品相关工作 #39
|
|
@ -170,6 +170,11 @@ export default defineConfig({
|
||||||
path: '/product/sync',
|
path: '/product/sync',
|
||||||
component: './Product/Sync',
|
component: './Product/Sync',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: '产品CSV 工具',
|
||||||
|
path: '/product/csvtool',
|
||||||
|
component: './Product/CsvTool',
|
||||||
|
}
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ WORKDIR /app
|
||||||
# 复制 package.json 和 package-lock.json
|
# 复制 package.json 和 package-lock.json
|
||||||
COPY package*.json ./
|
COPY package*.json ./
|
||||||
|
|
||||||
# 安装依赖(使用 --legacy-peer-deps 解决依赖冲突)
|
# 安装依赖(使用 --legacy-peer-deps 解决依赖冲突)
|
||||||
RUN npm install --legacy-peer-deps
|
RUN npm install --legacy-peer-deps
|
||||||
|
|
||||||
# 复制源代码
|
# 复制源代码
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,7 @@ export const showSyncResult = (
|
||||||
} = result;
|
} = result;
|
||||||
|
|
||||||
// 构建结果消息
|
// 构建结果消息
|
||||||
let resultMessage = `同步完成!共处理 ${processed} 个${entityType}(总数 ${total} 个):`;
|
let resultMessage = `同步完成!共处理 ${processed} 个${entityType}(总数 ${total} 个):`;
|
||||||
if (created > 0) resultMessage += ` 新建 ${created} 个`;
|
if (created > 0) resultMessage += ` 新建 ${created} 个`;
|
||||||
if (updated > 0) resultMessage += ` 更新 ${updated} 个`;
|
if (updated > 0) resultMessage += ` 更新 ${updated} 个`;
|
||||||
if (synced > 0) resultMessage += ` 同步成功 ${synced} 个`;
|
if (synced > 0) resultMessage += ` 同步成功 ${synced} 个`;
|
||||||
|
|
@ -50,7 +50,7 @@ export const showSyncResult = (
|
||||||
<div>
|
<div>
|
||||||
<div>{resultMessage}</div>
|
<div>{resultMessage}</div>
|
||||||
<div style={{ marginTop: 8, fontSize: 12, color: '#faad14' }}>
|
<div style={{ marginTop: 8, fontSize: 12, color: '#faad14' }}>
|
||||||
失败详情:
|
失败详情:
|
||||||
{errors
|
{errors
|
||||||
.slice(0, 3)
|
.slice(0, 3)
|
||||||
.map((err: any) => `${err.identifier}: ${err.error}`)
|
.map((err: any) => `${err.identifier}: ${err.error}`)
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ interface Site {
|
||||||
[key: string]: any;
|
[key: string]: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 自定义 Hook:管理站点数据
|
// 自定义 Hook:管理站点数据
|
||||||
const useSites = () => {
|
const useSites = () => {
|
||||||
// 添加站点数据状态
|
// 添加站点数据状态
|
||||||
const [sites, setSites] = useState<Site[]>([]);
|
const [sites, setSites] = useState<Site[]>([]);
|
||||||
|
|
|
||||||
|
|
@ -60,7 +60,7 @@ const HistoryOrders: React.FC<HistoryOrdersProps> = ({ customer, siteId }) => {
|
||||||
const items = order.line_items || order.items || [];
|
const items = order.line_items || order.items || [];
|
||||||
if (Array.isArray(items)) {
|
if (Array.isArray(items)) {
|
||||||
items.forEach((item: any) => {
|
items.forEach((item: any) => {
|
||||||
// 检查商品名称或SKU是否包含yoone(不区分大小写)
|
// 检查商品名称或SKU是否包含yoone(不区分大小写)
|
||||||
const itemName = (item.name || '').toLowerCase();
|
const itemName = (item.name || '').toLowerCase();
|
||||||
const sku = (item.sku || '').toLowerCase();
|
const sku = (item.sku || '').toLowerCase();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -502,7 +502,7 @@ const SyncCustomersModal: React.FC<{
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// 添加日期范围过滤(使用 after 和 before 参数)
|
// 添加日期范围过滤(使用 after 和 before 参数)
|
||||||
if (values.dateRange && values.dateRange[0] && values.dateRange[1]) {
|
if (values.dateRange && values.dateRange[0] && values.dateRange[1]) {
|
||||||
params.where = {
|
params.where = {
|
||||||
...params.where,
|
...params.where,
|
||||||
|
|
@ -536,7 +536,7 @@ const SyncCustomersModal: React.FC<{
|
||||||
errors = [],
|
errors = [],
|
||||||
} = result;
|
} = result;
|
||||||
|
|
||||||
let resultMessage = `同步完成!共处理 ${total} 个客户:`;
|
let resultMessage = `同步完成!共处理 ${total} 个客户:`;
|
||||||
if (created > 0) resultMessage += ` 新建 ${created} 个`;
|
if (created > 0) resultMessage += ` 新建 ${created} 个`;
|
||||||
if (updated > 0) resultMessage += ` 更新 ${updated} 个`;
|
if (updated > 0) resultMessage += ` 更新 ${updated} 个`;
|
||||||
if (synced > 0) resultMessage += ` 同步成功 ${synced} 个`;
|
if (synced > 0) resultMessage += ` 同步成功 ${synced} 个`;
|
||||||
|
|
@ -549,7 +549,7 @@ const SyncCustomersModal: React.FC<{
|
||||||
<div>
|
<div>
|
||||||
<div>{resultMessage}</div>
|
<div>{resultMessage}</div>
|
||||||
<div style={{ marginTop: 8, fontSize: 12, color: '#faad14' }}>
|
<div style={{ marginTop: 8, fontSize: 12, color: '#faad14' }}>
|
||||||
失败详情:
|
失败详情:
|
||||||
{errors
|
{errors
|
||||||
.slice(0, 3)
|
.slice(0, 3)
|
||||||
.map((err: any) => err.email || err.error)
|
.map((err: any) => err.email || err.error)
|
||||||
|
|
@ -653,12 +653,12 @@ const SyncCustomersModal: React.FC<{
|
||||||
placeholder="选择排序方式"
|
placeholder="选择排序方式"
|
||||||
options={[
|
options={[
|
||||||
{ label: '默认排序', value: '' },
|
{ label: '默认排序', value: '' },
|
||||||
{ label: '注册时间(升序)', value: 'date_created:asc' },
|
{ label: '注册时间(升序)', value: 'date_created:asc' },
|
||||||
{ label: '注册时间(降序)', value: 'date_created:desc' },
|
{ label: '注册时间(降序)', value: 'date_created:desc' },
|
||||||
{ label: '邮箱(升序)', value: 'email:asc' },
|
{ label: '邮箱(升序)', value: 'email:asc' },
|
||||||
{ label: '邮箱(降序)', value: 'email:desc' },
|
{ label: '邮箱(降序)', value: 'email:desc' },
|
||||||
{ label: '姓名(升序)', value: 'first_name:asc' },
|
{ label: '姓名(升序)', value: 'first_name:asc' },
|
||||||
{ label: '姓名(降序)', value: 'first_name:desc' },
|
{ label: '姓名(降序)', value: 'first_name:desc' },
|
||||||
]}
|
]}
|
||||||
fieldProps={{
|
fieldProps={{
|
||||||
allowClear: true,
|
allowClear: true,
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,7 @@ const DictPage: React.FC = () => {
|
||||||
const [isEditDictModalVisible, setIsEditDictModalVisible] = useState(false);
|
const [isEditDictModalVisible, setIsEditDictModalVisible] = useState(false);
|
||||||
const [editDictData, setEditDictData] = useState<any>(null);
|
const [editDictData, setEditDictData] = useState<any>(null);
|
||||||
|
|
||||||
// 字典项模态框状态(由 DictItemModal 组件管理)
|
// 字典项模态框状态(由 DictItemModal 组件管理)
|
||||||
const [isDictItemModalVisible, setIsDictItemModalVisible] = useState(false);
|
const [isDictItemModalVisible, setIsDictItemModalVisible] = useState(false);
|
||||||
const [isEditDictItem, setIsEditDictItem] = useState(false);
|
const [isEditDictItem, setIsEditDictItem] = useState(false);
|
||||||
const [editingDictItemData, setEditingDictItemData] = useState<any>(null);
|
const [editingDictItemData, setEditingDictItemData] = useState<any>(null);
|
||||||
|
|
@ -137,7 +137,7 @@ const DictPage: React.FC = () => {
|
||||||
link.remove();
|
link.remove();
|
||||||
window.URL.revokeObjectURL(url);
|
window.URL.revokeObjectURL(url);
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
message.error('下载字典模板失败:' + (error.message || '未知错误'));
|
message.error('下载字典模板失败:' + (error.message || '未知错误'));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -173,7 +173,7 @@ const DictPage: React.FC = () => {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// 处理字典项模态框提交(添加或编辑)
|
// 处理字典项模态框提交(添加或编辑)
|
||||||
const handleDictItemModalOk = async (values: any) => {
|
const handleDictItemModalOk = async (values: any) => {
|
||||||
try {
|
try {
|
||||||
if (isEditDictItem && editingDictItemData) {
|
if (isEditDictItem && editingDictItemData) {
|
||||||
|
|
@ -205,7 +205,7 @@ const DictPage: React.FC = () => {
|
||||||
}, 100);
|
}, 100);
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
message.error(
|
message.error(
|
||||||
`${isEditDictItem ? '更新' : '添加'}失败:${
|
`${isEditDictItem ? '更新' : '添加'}失败:${
|
||||||
error.message || '未知错误'
|
error.message || '未知错误'
|
||||||
}`,
|
}`,
|
||||||
);
|
);
|
||||||
|
|
@ -275,7 +275,7 @@ const DictPage: React.FC = () => {
|
||||||
|
|
||||||
message.success(`成功导出 ${response.length} 条数据`);
|
message.success(`成功导出 ${response.length} 条数据`);
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
message.error('导出字典项失败:' + (error.message || '未知错误'));
|
message.error('导出字典项失败:' + (error.message || '未知错误'));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -477,7 +477,7 @@ const DictPage: React.FC = () => {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// 兼容旧的响应格式(直接返回数组)
|
// 兼容旧的响应格式(直接返回数组)
|
||||||
return {
|
return {
|
||||||
data: res || [],
|
data: res || [],
|
||||||
success: true,
|
success: true,
|
||||||
|
|
@ -524,7 +524,7 @@ const DictPage: React.FC = () => {
|
||||||
</Content>
|
</Content>
|
||||||
</Layout>
|
</Layout>
|
||||||
|
|
||||||
{/* 字典项 Modal(添加或编辑) */}
|
{/* 字典项 Modal(添加或编辑) */}
|
||||||
<DictItemModal
|
<DictItemModal
|
||||||
visible={isDictItemModalVisible}
|
visible={isDictItemModalVisible}
|
||||||
isEdit={isEditDictItem}
|
isEdit={isEditDictItem}
|
||||||
|
|
|
||||||
|
|
@ -11,19 +11,19 @@ interface DictItemActionsProps {
|
||||||
selectedDict?: any;
|
selectedDict?: any;
|
||||||
// ProTable 的 actionRef,用于刷新列表
|
// ProTable 的 actionRef,用于刷新列表
|
||||||
actionRef?: React.MutableRefObject<ActionType | undefined>;
|
actionRef?: React.MutableRefObject<ActionType | undefined>;
|
||||||
// 是否显示导出按钮(某些页面可能不需要导出功能)
|
// 是否显示导出按钮(某些页面可能不需要导出功能)
|
||||||
showExport?: boolean;
|
showExport?: boolean;
|
||||||
// 导入字典项的回调函数(如果不提供,则使用默认的导入逻辑)
|
// 导入字典项的回调函数(如果不提供,则使用默认的导入逻辑)
|
||||||
onImport?: (file: File, dictId: number) => Promise<any>;
|
onImport?: (file: File, dictId: number) => Promise<any>;
|
||||||
// 导出字典项的回调函数
|
// 导出字典项的回调函数
|
||||||
onExport?: () => Promise<void>;
|
onExport?: () => Promise<void>;
|
||||||
// 添加字典项的回调函数
|
// 添加字典项的回调函数
|
||||||
onAdd?: () => void;
|
onAdd?: () => void;
|
||||||
// 刷新字典列表的回调函数(导入成功后可能需要刷新左侧字典列表)
|
// 刷新字典列表的回调函数(导入成功后可能需要刷新左侧字典列表)
|
||||||
onRefreshDicts?: () => void;
|
onRefreshDicts?: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 字典项操作组合组件(包含添加、导入、导出按钮)
|
// 字典项操作组合组件(包含添加、导入、导出按钮)
|
||||||
const DictItemActions: React.FC<DictItemActionsProps> = ({
|
const DictItemActions: React.FC<DictItemActionsProps> = ({
|
||||||
selectedDict,
|
selectedDict,
|
||||||
actionRef,
|
actionRef,
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,7 @@ const DictItemExportButton: React.FC<DictItemExportButtonProps> = ({
|
||||||
message.warning('未提供导出函数');
|
message.warning('未提供导出函数');
|
||||||
}
|
}
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
message.error('导出字典项失败:' + (error.message || '未知错误'));
|
message.error('导出字典项失败:' + (error.message || '未知错误'));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ interface DictItemImportButtonProps {
|
||||||
actionRef?: React.MutableRefObject<ActionType | undefined>;
|
actionRef?: React.MutableRefObject<ActionType | undefined>;
|
||||||
// 是否禁用按钮
|
// 是否禁用按钮
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
// 自定义导入函数,返回 Promise(如果不提供,则使用默认的导入逻辑)
|
// 自定义导入函数,返回 Promise(如果不提供,则使用默认的导入逻辑)
|
||||||
onImport?: (file: File, dictId: number) => Promise<any>;
|
onImport?: (file: File, dictId: number) => Promise<any>;
|
||||||
// 导入成功后刷新字典列表的回调函数
|
// 导入成功后刷新字典列表的回调函数
|
||||||
onRefreshDicts?: () => void;
|
onRefreshDicts?: () => void;
|
||||||
|
|
@ -73,7 +73,7 @@ const DictItemImportButton: React.FC<DictItemImportButtonProps> = ({
|
||||||
|
|
||||||
// 显示导入结果详情
|
// 显示导入结果详情
|
||||||
const showImportResult = (result: any) => {
|
const showImportResult = (result: any) => {
|
||||||
// 从 result.data 中获取实际数据(因为后端返回格式为 { success: true, data: {...} })
|
// 从 result.data 中获取实际数据(因为后端返回格式为 { success: true, data: {...} })
|
||||||
const data = result.data || result;
|
const data = result.data || result;
|
||||||
const { total, processed, updated, created, errors } = data;
|
const { total, processed, updated, created, errors } = data;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ const AttributePage: React.FC = () => {
|
||||||
// 右侧字典项 ProTable 的引用
|
// 右侧字典项 ProTable 的引用
|
||||||
const actionRef = useRef<ActionType>();
|
const actionRef = useRef<ActionType>();
|
||||||
|
|
||||||
// 字典项模态框状态(由 DictItemModal 组件管理)
|
// 字典项模态框状态(由 DictItemModal 组件管理)
|
||||||
const [isDictItemModalVisible, setIsDictItemModalVisible] = useState(false);
|
const [isDictItemModalVisible, setIsDictItemModalVisible] = useState(false);
|
||||||
const [isEditDictItem, setIsEditDictItem] = useState(false);
|
const [isEditDictItem, setIsEditDictItem] = useState(false);
|
||||||
const [editingDictItemData, setEditingDictItemData] = useState<any>(null);
|
const [editingDictItemData, setEditingDictItemData] = useState<any>(null);
|
||||||
|
|
@ -99,7 +99,7 @@ const AttributePage: React.FC = () => {
|
||||||
|
|
||||||
message.success(`成功导出 ${data.length} 条数据`);
|
message.success(`成功导出 ${data.length} 条数据`);
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
message.error('导出字典项失败:' + (error.message || '未知错误'));
|
message.error('导出字典项失败:' + (error.message || '未知错误'));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -389,7 +389,7 @@ const AttributePage: React.FC = () => {
|
||||||
</Content>
|
</Content>
|
||||||
</Layout>
|
</Layout>
|
||||||
|
|
||||||
{/* 字典项 Modal(添加或编辑) */}
|
{/* 字典项 Modal(添加或编辑) */}
|
||||||
<DictItemModal
|
<DictItemModal
|
||||||
visible={isDictItemModalVisible}
|
visible={isDictItemModalVisible}
|
||||||
isEdit={isEditDictItem}
|
isEdit={isEditDictItem}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,7 @@
|
||||||
|
export default function CsvTool() {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<h1>产品CSV 工具</h1>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
@ -77,7 +77,7 @@ const CreateForm: React.FC<{
|
||||||
const strengthName: string = String(strengthValues?.[0] || '');
|
const strengthName: string = String(strengthValues?.[0] || '');
|
||||||
const flavorName: string = String(flavorValues?.[0] || '');
|
const flavorName: string = String(flavorValues?.[0] || '');
|
||||||
const humidityName: string = String(humidityValues?.[0] || '');
|
const humidityName: string = String(humidityValues?.[0] || '');
|
||||||
|
console.log(formValues)
|
||||||
// 调用模板渲染API来生成SKU
|
// 调用模板渲染API来生成SKU
|
||||||
const {
|
const {
|
||||||
data: rendered,
|
data: rendered,
|
||||||
|
|
@ -86,10 +86,25 @@ const CreateForm: React.FC<{
|
||||||
} = await templatecontrollerRendertemplate(
|
} = await templatecontrollerRendertemplate(
|
||||||
{ name: 'product.sku' },
|
{ name: 'product.sku' },
|
||||||
{
|
{
|
||||||
brand: brandName || '',
|
category: formValues.category,
|
||||||
strength: strengthName || '',
|
attributes: [
|
||||||
flavor: flavorName || '',
|
{
|
||||||
humidity: humidityName ? capitalize(humidityName) : '',
|
dict: {name: "brand"},
|
||||||
|
shortName: brandName || '',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
dict: {name: "flavor"},
|
||||||
|
shortName: flavorName || '',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
dict: {name: "strength"},
|
||||||
|
shortName: strengthName || '',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
dict: {name: "humidity"},
|
||||||
|
shortName: humidityName ? capitalize(humidityName) : '',
|
||||||
|
},
|
||||||
|
]
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
if (!success) {
|
if (!success) {
|
||||||
|
|
|
||||||
|
|
@ -217,7 +217,7 @@ const List: React.FC = () => {
|
||||||
sorter: true,
|
sorter: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '商品SKU',
|
title: '关联商品',
|
||||||
dataIndex: 'siteSkus',
|
dataIndex: 'siteSkus',
|
||||||
render: (_, record) => (
|
render: (_, record) => (
|
||||||
<>
|
<>
|
||||||
|
|
@ -244,13 +244,7 @@ const List: React.FC = () => {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
|
||||||
title: '商品类型',
|
|
||||||
dataIndex: 'category',
|
|
||||||
render: (_, record: any) => {
|
|
||||||
return record.category?.title || record.category?.name || '-';
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
title: '价格',
|
title: '价格',
|
||||||
dataIndex: 'price',
|
dataIndex: 'price',
|
||||||
|
|
@ -262,6 +256,13 @@ const List: React.FC = () => {
|
||||||
dataIndex: 'promotionPrice',
|
dataIndex: 'promotionPrice',
|
||||||
hideInSearch: true,
|
hideInSearch: true,
|
||||||
sorter: true,
|
sorter: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '商品类型',
|
||||||
|
dataIndex: 'category',
|
||||||
|
render: (_, record: any) => {
|
||||||
|
return record.category?.title || record.category?.name || '-';
|
||||||
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '属性',
|
title: '属性',
|
||||||
|
|
@ -442,6 +443,7 @@ const List: React.FC = () => {
|
||||||
onError?.(error);
|
onError?.(error);
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
|
|
||||||
>
|
>
|
||||||
<Button>批量导入</Button>
|
<Button>批量导入</Button>
|
||||||
</Upload>,
|
</Upload>,
|
||||||
|
|
@ -541,6 +543,11 @@ const List: React.FC = () => {
|
||||||
rowSelection={{
|
rowSelection={{
|
||||||
onChange: (_, selectedRows) => setSelectedRows(selectedRows),
|
onChange: (_, selectedRows) => setSelectedRows(selectedRows),
|
||||||
}}
|
}}
|
||||||
|
pagination={{
|
||||||
|
showSizeChanger: true,
|
||||||
|
showQuickJumper: true,
|
||||||
|
pageSizeOptions: ['10', '20', '50', '100', '1000', '2000'],
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
<BatchEditModal
|
<BatchEditModal
|
||||||
visible={batchEditModalVisible}
|
visible={batchEditModalVisible}
|
||||||
|
|
|
||||||
|
|
@ -211,7 +211,7 @@ const PermutationPage: React.FC = () => {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 生成CSV表头(包含所有属性列和SKU列)
|
// 生成CSV表头(包含所有属性列和SKU列)
|
||||||
const headers = [
|
const headers = [
|
||||||
...attributes.map((attr) => attr.title || attr.name),
|
...attributes.map((attr) => attr.title || attr.name),
|
||||||
'SKU',
|
'SKU',
|
||||||
|
|
@ -239,7 +239,7 @@ const PermutationPage: React.FC = () => {
|
||||||
// 将表头和数据行合并
|
// 将表头和数据行合并
|
||||||
const csvContent = [headers, ...rows]
|
const csvContent = [headers, ...rows]
|
||||||
.map((row) =>
|
.map((row) =>
|
||||||
// 处理CSV中的特殊字符(逗号、双引号、换行符)
|
// 处理CSV中的特殊字符(逗号、双引号、换行符)
|
||||||
row
|
row
|
||||||
.map((cell) => {
|
.map((cell) => {
|
||||||
const cellStr = String(cell || '');
|
const cellStr = String(cell || '');
|
||||||
|
|
@ -268,7 +268,7 @@ const PermutationPage: React.FC = () => {
|
||||||
const url = URL.createObjectURL(blob);
|
const url = URL.createObjectURL(blob);
|
||||||
link.setAttribute('href', url);
|
link.setAttribute('href', url);
|
||||||
|
|
||||||
// 生成文件名(包含当前分类名称和日期)
|
// 生成文件名(包含当前分类名称和日期)
|
||||||
const category = categories.find((c) => c.id === categoryId);
|
const category = categories.find((c) => c.id === categoryId);
|
||||||
const categoryName = category?.name || '产品';
|
const categoryName = category?.name || '产品';
|
||||||
const date = new Date().toISOString().slice(0, 10);
|
const date = new Date().toISOString().slice(0, 10);
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@ interface Site {
|
||||||
isDisabled?: boolean;
|
isDisabled?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 定义本地产品接口(与后端 Product 实体匹配)
|
// 定义本地产品接口(与后端 Product 实体匹配)
|
||||||
interface SiteProduct {
|
interface SiteProduct {
|
||||||
id: number;
|
id: number;
|
||||||
sku: string;
|
sku: string;
|
||||||
|
|
@ -115,7 +115,7 @@ const SiteProductCell: React.FC<SiteProductCellProps> = ({
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
try {
|
try {
|
||||||
// 首先查找该产品在该站点的实际SKU
|
// 首先查找该产品在该站点的实际SKU
|
||||||
// 注意:siteSkus 现在是字符串数组,无法直接匹配站点
|
// 注意:siteSkus 现在是字符串数组,无法直接匹配站点
|
||||||
// 这里使用模板生成的 SKU 作为默认值
|
// 这里使用模板生成的 SKU 作为默认值
|
||||||
let siteProductSku = '';
|
let siteProductSku = '';
|
||||||
// 如果需要更精确的站点 SKU 匹配,需要后端提供额外的接口
|
// 如果需要更精确的站点 SKU 匹配,需要后端提供额外的接口
|
||||||
|
|
@ -363,7 +363,7 @@ const SiteProductCell: React.FC<SiteProductCellProps> = ({
|
||||||
// 如果没有找到站点产品,显示同步按钮
|
// 如果没有找到站点产品,显示同步按钮
|
||||||
if (!siteProduct) {
|
if (!siteProduct) {
|
||||||
// 首先查找该产品在该站点的实际SKU
|
// 首先查找该产品在该站点的实际SKU
|
||||||
// 注意:siteSkus 现在是字符串数组,无法直接匹配站点
|
// 注意:siteSkus 现在是字符串数组,无法直接匹配站点
|
||||||
// 这里使用模板生成的 SKU 作为默认值
|
// 这里使用模板生成的 SKU 作为默认值
|
||||||
let siteProductSku = '';
|
let siteProductSku = '';
|
||||||
// 如果需要更精确的站点 SKU 匹配,需要后端提供额外的接口
|
// 如果需要更精确的站点 SKU 匹配,需要后端提供额外的接口
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@ interface Site {
|
||||||
isDisabled?: boolean;
|
isDisabled?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 定义本地产品接口(与后端 Product 实体匹配)
|
// 定义本地产品接口(与后端 Product 实体匹配)
|
||||||
interface SiteProduct {
|
interface SiteProduct {
|
||||||
id: number;
|
id: number;
|
||||||
sku: string;
|
sku: string;
|
||||||
|
|
@ -438,7 +438,7 @@ const ProductSyncPage: React.FC = () => {
|
||||||
>
|
>
|
||||||
<div style={{ marginBottom: 16 }}>
|
<div style={{ marginBottom: 16 }}>
|
||||||
<p>
|
<p>
|
||||||
目标站点:
|
目标站点:
|
||||||
<strong>{sites.find((s) => s.id === selectedSiteId)?.name}</strong>
|
<strong>{sites.find((s) => s.id === selectedSiteId)?.name}</strong>
|
||||||
</p>
|
</p>
|
||||||
{selectedRows.length > 0 ? (
|
{selectedRows.length > 0 ? (
|
||||||
|
|
@ -452,17 +452,17 @@ const ProductSyncPage: React.FC = () => {
|
||||||
|
|
||||||
{syncing && (
|
{syncing && (
|
||||||
<div style={{ marginBottom: 16 }}>
|
<div style={{ marginBottom: 16 }}>
|
||||||
<div style={{ marginBottom: 8 }}>同步进度:</div>
|
<div style={{ marginBottom: 8 }}>同步进度:</div>
|
||||||
<Progress percent={syncProgress} status="active" />
|
<Progress percent={syncProgress} status="active" />
|
||||||
<div style={{ marginTop: 8, fontSize: 12, color: '#666' }}>
|
<div style={{ marginTop: 8, fontSize: 12, color: '#666' }}>
|
||||||
成功:{syncResults.success} | 失败:{syncResults.failed}
|
成功:{syncResults.success} | 失败:{syncResults.failed}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{syncResults.errors.length > 0 && (
|
{syncResults.errors.length > 0 && (
|
||||||
<div style={{ marginBottom: 16, maxHeight: 200, overflow: 'auto' }}>
|
<div style={{ marginBottom: 16, maxHeight: 200, overflow: 'auto' }}>
|
||||||
<div style={{ marginBottom: 8, color: '#ff4d4f' }}>错误详情:</div>
|
<div style={{ marginBottom: 8, color: '#ff4d4f' }}>错误详情:</div>
|
||||||
{syncResults.errors.slice(0, 10).map((error, index) => (
|
{syncResults.errors.slice(0, 10).map((error, index) => (
|
||||||
<div
|
<div
|
||||||
key={index}
|
key={index}
|
||||||
|
|
|
||||||
|
|
@ -411,7 +411,7 @@ const SiteList: React.FC = () => {
|
||||||
name="areas"
|
name="areas"
|
||||||
label="区域"
|
label="区域"
|
||||||
mode="multiple"
|
mode="multiple"
|
||||||
placeholder="请选择区域(留空表示不修改)"
|
placeholder="请选择区域(留空表示不修改)"
|
||||||
showSearch
|
showSearch
|
||||||
filterOption={(input, option) =>
|
filterOption={(input, option) =>
|
||||||
(option?.label ?? '').toLowerCase().includes(input.toLowerCase())
|
(option?.label ?? '').toLowerCase().includes(input.toLowerCase())
|
||||||
|
|
@ -422,7 +422,7 @@ const SiteList: React.FC = () => {
|
||||||
name="stockPointIds"
|
name="stockPointIds"
|
||||||
label="关联仓库"
|
label="关联仓库"
|
||||||
mode="multiple"
|
mode="multiple"
|
||||||
placeholder="请选择关联仓库(留空表示不修改)"
|
placeholder="请选择关联仓库(留空表示不修改)"
|
||||||
request={async () => {
|
request={async () => {
|
||||||
// 从后端接口获取仓库数据
|
// 从后端接口获取仓库数据
|
||||||
const res = await stockcontrollerGetallstockpoints();
|
const res = await stockcontrollerGetallstockpoints();
|
||||||
|
|
|
||||||
|
|
@ -116,7 +116,6 @@ const ProductsPage: React.FC = () => {
|
||||||
// ID
|
// ID
|
||||||
title: 'ID',
|
title: 'ID',
|
||||||
dataIndex: 'id',
|
dataIndex: 'id',
|
||||||
hideInSearch: true,
|
|
||||||
width: 120,
|
width: 120,
|
||||||
copyable: true,
|
copyable: true,
|
||||||
render: (_, record) => {
|
render: (_, record) => {
|
||||||
|
|
@ -156,7 +155,7 @@ const ProductsPage: React.FC = () => {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
// 库存
|
// 库存
|
||||||
title: '库存',
|
title: '库存数量',
|
||||||
dataIndex: 'stock_quantity',
|
dataIndex: 'stock_quantity',
|
||||||
hideInSearch: true,
|
hideInSearch: true,
|
||||||
},
|
},
|
||||||
|
|
@ -423,7 +422,7 @@ const ProductsPage: React.FC = () => {
|
||||||
params: {
|
params: {
|
||||||
page,
|
page,
|
||||||
per_page: pageSize,
|
per_page: pageSize,
|
||||||
...where,
|
where,
|
||||||
...(orderObj
|
...(orderObj
|
||||||
? {
|
? {
|
||||||
sortField: Object.keys(orderObj)[0],
|
sortField: Object.keys(orderObj)[0],
|
||||||
|
|
|
||||||
|
|
@ -121,7 +121,7 @@ const WebhooksPage: React.FC = () => {
|
||||||
message.error(isEditMode ? '更新失败' : '创建失败');
|
message.error(isEditMode ? '更新失败' : '创建失败');
|
||||||
}
|
}
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
message.error('表单验证失败:' + error.message);
|
message.error('表单验证失败:' + error.message);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -305,12 +305,12 @@ const WebhooksPage: React.FC = () => {
|
||||||
{ type: 'url', message: '请输入有效的URL' },
|
{ type: 'url', message: '请输入有效的URL' },
|
||||||
]}
|
]}
|
||||||
>
|
>
|
||||||
<Input placeholder="请输入回调URL,如:https://example.com/webhook" />
|
<Input placeholder="请输入回调URL,如:https://example.com/webhook" />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
|
||||||
<Form.Item
|
<Form.Item
|
||||||
name="secret"
|
name="secret"
|
||||||
label="密钥(可选)"
|
label="密钥(可选)"
|
||||||
rules={[{ max: 255, message: '密钥不能超过255个字符' }]}
|
rules={[{ max: 255, message: '密钥不能超过255个字符' }]}
|
||||||
>
|
>
|
||||||
<Input placeholder="请输入密钥,用于验证webhook请求" />
|
<Input placeholder="请输入密钥,用于验证webhook请求" />
|
||||||
|
|
|
||||||
|
|
@ -69,12 +69,12 @@ export const ErpProductBindModal: React.FC<ErpProductBindModalProps> = ({
|
||||||
onFinish={handleBind}
|
onFinish={handleBind}
|
||||||
>
|
>
|
||||||
<div style={{ marginBottom: 16 }}>
|
<div style={{ marginBottom: 16 }}>
|
||||||
<strong>站点产品信息:</strong>
|
<strong>站点产品信息:</strong>
|
||||||
<div>SKU: {siteProduct.sku}</div>
|
<div>SKU: {siteProduct.sku}</div>
|
||||||
<div>名称: {siteProduct.name}</div>
|
<div>名称: {siteProduct.name}</div>
|
||||||
{siteProduct.erpProduct && (
|
{siteProduct.erpProduct && (
|
||||||
<div style={{ color: '#ff4d4f' }}>
|
<div style={{ color: '#ff4d4f' }}>
|
||||||
⚠️ 当前已绑定ERP产品:{siteProduct.erpProduct.sku} -{' '}
|
⚠️ 当前已绑定ERP产品:{siteProduct.erpProduct.sku} -{' '}
|
||||||
{siteProduct.erpProduct.name}
|
{siteProduct.erpProduct.name}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
@ -164,7 +164,7 @@ export const ErpProductBindModal: React.FC<ErpProductBindModalProps> = ({
|
||||||
border: '1px solid #b7eb8f',
|
border: '1px solid #b7eb8f',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<strong>已选择:</strong>
|
<strong>已选择:</strong>
|
||||||
<div>SKU: {selectedProduct.sku}</div>
|
<div>SKU: {selectedProduct.sku}</div>
|
||||||
<div>名称: {selectedProduct.name}</div>
|
<div>名称: {selectedProduct.name}</div>
|
||||||
{selectedProduct.nameCn && (
|
{selectedProduct.nameCn && (
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,13 @@
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
/* eslint-disable */
|
/* eslint-disable */
|
||||||
// API 更新时间:
|
// API 更新时间:
|
||||||
// API 唯一标识:
|
// API 唯一标识:
|
||||||
import * as area from './area';
|
import * as area from './area';
|
||||||
import * as category from './category';
|
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';
|
||||||
import * as logistics from './logistics';
|
import * as logistics from './logistics';
|
||||||
import * as media from './media';
|
|
||||||
import * as order from './order';
|
import * as order from './order';
|
||||||
import * as product from './product';
|
import * as product from './product';
|
||||||
import * as site from './site';
|
import * as site from './site';
|
||||||
|
|
@ -26,7 +25,6 @@ export default {
|
||||||
dict,
|
dict,
|
||||||
locales,
|
locales,
|
||||||
logistics,
|
logistics,
|
||||||
media,
|
|
||||||
order,
|
order,
|
||||||
product,
|
product,
|
||||||
siteApi,
|
siteApi,
|
||||||
|
|
|
||||||
|
|
@ -1,92 +0,0 @@
|
||||||
// @ts-ignore
|
|
||||||
/* eslint-disable */
|
|
||||||
import { request } from 'umi';
|
|
||||||
|
|
||||||
/** 此处后端没有提供注释 DELETE /media/${param0} */
|
|
||||||
export async function mediacontrollerDelete(
|
|
||||||
// 叠加生成的Param类型 (非body参数swagger默认没有生成对象)
|
|
||||||
params: API.mediacontrollerDeleteParams,
|
|
||||||
options?: { [key: string]: any },
|
|
||||||
) {
|
|
||||||
const { id: param0, ...queryParams } = params;
|
|
||||||
return request<any>(`/media/${param0}`, {
|
|
||||||
method: 'DELETE',
|
|
||||||
params: {
|
|
||||||
...queryParams,
|
|
||||||
},
|
|
||||||
...(options || {}),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 此处后端没有提供注释 GET /media/list */
|
|
||||||
export async function mediacontrollerList(
|
|
||||||
// 叠加生成的Param类型 (非body参数swagger默认没有生成对象)
|
|
||||||
params: API.mediacontrollerListParams,
|
|
||||||
options?: { [key: string]: any },
|
|
||||||
) {
|
|
||||||
return request<any>('/media/list', {
|
|
||||||
method: 'GET',
|
|
||||||
params: {
|
|
||||||
...params,
|
|
||||||
},
|
|
||||||
...(options || {}),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 此处后端没有提供注释 POST /media/update/${param0} */
|
|
||||||
export async function mediacontrollerUpdate(
|
|
||||||
// 叠加生成的Param类型 (非body参数swagger默认没有生成对象)
|
|
||||||
params: API.mediacontrollerUpdateParams,
|
|
||||||
body: Record<string, any>,
|
|
||||||
options?: { [key: string]: any },
|
|
||||||
) {
|
|
||||||
const { id: param0, ...queryParams } = params;
|
|
||||||
return request<any>(`/media/update/${param0}`, {
|
|
||||||
method: 'POST',
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'text/plain',
|
|
||||||
},
|
|
||||||
params: { ...queryParams },
|
|
||||||
data: body,
|
|
||||||
...(options || {}),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 此处后端没有提供注释 POST /media/upload */
|
|
||||||
export async function mediacontrollerUpload(
|
|
||||||
body: {},
|
|
||||||
files?: File[],
|
|
||||||
options?: { [key: string]: any },
|
|
||||||
) {
|
|
||||||
const formData = new FormData();
|
|
||||||
|
|
||||||
if (files) {
|
|
||||||
files.forEach((f) => formData.append('files', f || ''));
|
|
||||||
}
|
|
||||||
|
|
||||||
Object.keys(body).forEach((ele) => {
|
|
||||||
const item = (body as any)[ele];
|
|
||||||
|
|
||||||
if (item !== undefined && item !== null) {
|
|
||||||
if (typeof item === 'object' && !(item instanceof File)) {
|
|
||||||
if (item instanceof Array) {
|
|
||||||
item.forEach((f) => formData.append(ele, f || ''));
|
|
||||||
} else {
|
|
||||||
formData.append(
|
|
||||||
ele,
|
|
||||||
new Blob([JSON.stringify(item)], { type: 'application/json' }),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
formData.append(ele, item);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return request<any>('/media/upload', {
|
|
||||||
method: 'POST',
|
|
||||||
data: formData,
|
|
||||||
requestType: 'form',
|
|
||||||
...(options || {}),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
@ -282,6 +282,20 @@ export async function siteapicontrollerBatchfulfillorders(
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** 此处后端没有提供注释 GET /site-api/${param0}/orders/count */
|
||||||
|
export async function siteapicontrollerCountorders(
|
||||||
|
// 叠加生成的Param类型 (非body参数swagger默认没有生成对象)
|
||||||
|
params: API.siteapicontrollerCountordersParams,
|
||||||
|
options?: { [key: string]: any },
|
||||||
|
) {
|
||||||
|
const { siteId: param0, ...queryParams } = params;
|
||||||
|
return request<Record<string, any>>(`/site-api/${param0}/orders/count`, {
|
||||||
|
method: 'GET',
|
||||||
|
params: { ...queryParams },
|
||||||
|
...(options || {}),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/** 此处后端没有提供注释 GET /site-api/${param0}/orders/export */
|
/** 此处后端没有提供注释 GET /site-api/${param0}/orders/export */
|
||||||
export async function siteapicontrollerExportorders(
|
export async function siteapicontrollerExportorders(
|
||||||
// 叠加生成的Param类型 (非body参数swagger默认没有生成对象)
|
// 叠加生成的Param类型 (非body参数swagger默认没有生成对象)
|
||||||
|
|
@ -776,23 +790,18 @@ export async function siteapicontrollerCancelfulfillment(
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 此处后端没有提供注释 POST /site-api/${param1}/orders/${param0}/fulfill */
|
/** 此处后端没有提供注释 GET /site-api/${param1}/orders/${param0}/fulfillments */
|
||||||
export async function siteapicontrollerFulfillorder(
|
export async function siteapicontrollerGetorderfulfillments(
|
||||||
// 叠加生成的Param类型 (非body参数swagger默认没有生成对象)
|
// 叠加生成的Param类型 (非body参数swagger默认没有生成对象)
|
||||||
params: API.siteapicontrollerFulfillorderParams,
|
params: API.siteapicontrollerGetorderfulfillmentsParams,
|
||||||
body: API.FulfillmentDTO,
|
|
||||||
options?: { [key: string]: any },
|
options?: { [key: string]: any },
|
||||||
) {
|
) {
|
||||||
const { id: param0, siteId: param1, ...queryParams } = params;
|
const { orderId: param0, siteId: param1, ...queryParams } = params;
|
||||||
return request<Record<string, any>>(
|
return request<Record<string, any>>(
|
||||||
`/site-api/${param1}/orders/${param0}/fulfill`,
|
`/site-api/${param1}/orders/${param0}/fulfillments`,
|
||||||
{
|
{
|
||||||
method: 'POST',
|
method: 'GET',
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
},
|
|
||||||
params: { ...queryParams },
|
params: { ...queryParams },
|
||||||
data: body,
|
|
||||||
...(options || {}),
|
...(options || {}),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
@ -859,23 +868,6 @@ export async function siteapicontrollerCreateordernote(
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 此处后端没有提供注释 GET /site-api/${param1}/orders/${param0}/trackings */
|
|
||||||
export async function siteapicontrollerGetordertrackings(
|
|
||||||
// 叠加生成的Param类型 (非body参数swagger默认没有生成对象)
|
|
||||||
params: API.siteapicontrollerGetordertrackingsParams,
|
|
||||||
options?: { [key: string]: any },
|
|
||||||
) {
|
|
||||||
const { orderId: param0, siteId: param1, ...queryParams } = params;
|
|
||||||
return request<Record<string, any>>(
|
|
||||||
`/site-api/${param1}/orders/${param0}/trackings`,
|
|
||||||
{
|
|
||||||
method: 'GET',
|
|
||||||
params: { ...queryParams },
|
|
||||||
...(options || {}),
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 此处后端没有提供注释 GET /site-api/${param1}/products/${param0} */
|
/** 此处后端没有提供注释 GET /site-api/${param1}/products/${param0} */
|
||||||
export async function siteapicontrollerGetproduct(
|
export async function siteapicontrollerGetproduct(
|
||||||
// 叠加生成的Param类型 (非body参数swagger默认没有生成对象)
|
// 叠加生成的Param类型 (非body参数swagger默认没有生成对象)
|
||||||
|
|
|
||||||
|
|
@ -62,7 +62,7 @@ declare namespace API {
|
||||||
};
|
};
|
||||||
|
|
||||||
type BatchErrorItemDTO = {
|
type BatchErrorItemDTO = {
|
||||||
/** 错误项标识(如ID、邮箱等) */
|
/** 错误项标识(如ID、邮箱等) */
|
||||||
identifier?: string;
|
identifier?: string;
|
||||||
/** 错误信息 */
|
/** 错误信息 */
|
||||||
error?: string;
|
error?: string;
|
||||||
|
|
@ -591,22 +591,6 @@ declare namespace API {
|
||||||
weight?: Cubid;
|
weight?: Cubid;
|
||||||
};
|
};
|
||||||
|
|
||||||
type mediacontrollerDeleteParams = {
|
|
||||||
force?: boolean;
|
|
||||||
siteId?: number;
|
|
||||||
id: number;
|
|
||||||
};
|
|
||||||
|
|
||||||
type mediacontrollerListParams = {
|
|
||||||
pageSize?: number;
|
|
||||||
page?: number;
|
|
||||||
siteId?: number;
|
|
||||||
};
|
|
||||||
|
|
||||||
type mediacontrollerUpdateParams = {
|
|
||||||
id: number;
|
|
||||||
};
|
|
||||||
|
|
||||||
type Money = {
|
type Money = {
|
||||||
currency?: string;
|
currency?: string;
|
||||||
value?: string;
|
value?: string;
|
||||||
|
|
@ -1433,7 +1417,7 @@ declare namespace API {
|
||||||
keyword?: string;
|
keyword?: string;
|
||||||
/** 是否禁用 */
|
/** 是否禁用 */
|
||||||
isDisabled?: boolean;
|
isDisabled?: boolean;
|
||||||
/** 站点ID列表(逗号分隔) */
|
/** 站点ID列表(逗号分隔) */
|
||||||
ids?: string;
|
ids?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -1635,6 +1619,10 @@ declare namespace API {
|
||||||
siteId: number;
|
siteId: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
type siteapicontrollerCountordersParams = {
|
||||||
|
siteId: number;
|
||||||
|
};
|
||||||
|
|
||||||
type siteapicontrollerCreatecustomerParams = {
|
type siteapicontrollerCreatecustomerParams = {
|
||||||
siteId: number;
|
siteId: number;
|
||||||
};
|
};
|
||||||
|
|
@ -1813,11 +1801,6 @@ declare namespace API {
|
||||||
siteId: number;
|
siteId: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
type siteapicontrollerFulfillorderParams = {
|
|
||||||
id: string;
|
|
||||||
siteId: number;
|
|
||||||
};
|
|
||||||
|
|
||||||
type siteapicontrollerGetcustomerordersParams = {
|
type siteapicontrollerGetcustomerordersParams = {
|
||||||
/** 页码 */
|
/** 页码 */
|
||||||
page?: number;
|
page?: number;
|
||||||
|
|
@ -1882,6 +1865,11 @@ declare namespace API {
|
||||||
siteId: number;
|
siteId: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
type siteapicontrollerGetorderfulfillmentsParams = {
|
||||||
|
orderId: string;
|
||||||
|
siteId: number;
|
||||||
|
};
|
||||||
|
|
||||||
type siteapicontrollerGetordernotesParams = {
|
type siteapicontrollerGetordernotesParams = {
|
||||||
id: string;
|
id: string;
|
||||||
siteId: number;
|
siteId: number;
|
||||||
|
|
@ -1910,11 +1898,6 @@ declare namespace API {
|
||||||
siteId: number;
|
siteId: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
type siteapicontrollerGetordertrackingsParams = {
|
|
||||||
orderId: string;
|
|
||||||
siteId: number;
|
|
||||||
};
|
|
||||||
|
|
||||||
type siteapicontrollerGetproductParams = {
|
type siteapicontrollerGetproductParams = {
|
||||||
id: string;
|
id: string;
|
||||||
siteId: number;
|
siteId: number;
|
||||||
|
|
@ -2095,7 +2078,7 @@ declare namespace API {
|
||||||
keyword?: string;
|
keyword?: string;
|
||||||
/** 是否禁用 */
|
/** 是否禁用 */
|
||||||
isDisabled?: boolean;
|
isDisabled?: boolean;
|
||||||
/** 站点ID列表(逗号分隔) */
|
/** 站点ID列表(逗号分隔) */
|
||||||
ids?: string;
|
ids?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -2406,7 +2389,7 @@ declare namespace API {
|
||||||
type SyncCustomersDTO = {
|
type SyncCustomersDTO = {
|
||||||
/** 站点ID */
|
/** 站点ID */
|
||||||
siteId?: number;
|
siteId?: number;
|
||||||
/** 查询参数(支持where和orderBy) */
|
/** 查询参数(支持where和orderBy) */
|
||||||
params?: UnifiedSearchParamsDTO;
|
params?: UnifiedSearchParamsDTO;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -2787,7 +2770,7 @@ declare namespace API {
|
||||||
variation?: boolean;
|
variation?: boolean;
|
||||||
/** 属性选项 */
|
/** 属性选项 */
|
||||||
options?: string[];
|
options?: string[];
|
||||||
/** 变体属性值(单个值) */
|
/** 变体属性值(单个值) */
|
||||||
option?: string;
|
option?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -3222,6 +3205,11 @@ declare namespace API {
|
||||||
id?: number;
|
id?: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
type webhookcontrollerHandleshoppywebhookParams = {
|
||||||
|
signature?: string;
|
||||||
|
siteId?: string;
|
||||||
|
};
|
||||||
|
|
||||||
type webhookcontrollerHandlewoowebhookParams = {
|
type webhookcontrollerHandlewoowebhookParams = {
|
||||||
siteId?: string;
|
siteId?: string;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,26 @@ export async function webhookcontrollerTest(options?: { [key: string]: any }) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** 此处后端没有提供注释 POST /webhook/shoppy */
|
||||||
|
export async function webhookcontrollerHandleshoppywebhook(
|
||||||
|
// 叠加生成的Param类型 (非body参数swagger默认没有生成对象)
|
||||||
|
params: API.webhookcontrollerHandleshoppywebhookParams,
|
||||||
|
body: Record<string, any>,
|
||||||
|
options?: { [key: string]: any },
|
||||||
|
) {
|
||||||
|
return request<any>('/webhook/shoppy', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'text/plain',
|
||||||
|
},
|
||||||
|
params: {
|
||||||
|
...params,
|
||||||
|
},
|
||||||
|
data: body,
|
||||||
|
...(options || {}),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/** 此处后端没有提供注释 POST /webhook/woocommerce */
|
/** 此处后端没有提供注释 POST /webhook/woocommerce */
|
||||||
export async function webhookcontrollerHandlewoowebhook(
|
export async function webhookcontrollerHandlewoowebhook(
|
||||||
// 叠加生成的Param类型 (非body参数swagger默认没有生成对象)
|
// 叠加生成的Param类型 (非body参数swagger默认没有生成对象)
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@ export interface BatchOperationResult {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 显示批量操作结果(导入、删除等)
|
* 显示批量操作结果(导入、删除等)
|
||||||
* @param result 批量操作结果对象
|
* @param result 批量操作结果对象
|
||||||
* @param operationType 操作类型,用于显示在消息中
|
* @param operationType 操作类型,用于显示在消息中
|
||||||
*/
|
*/
|
||||||
|
|
@ -30,12 +30,12 @@ export function showBatchOperationResult(
|
||||||
result: BatchOperationResult,
|
result: BatchOperationResult,
|
||||||
operationType: string = '操作',
|
operationType: string = '操作',
|
||||||
): string {
|
): string {
|
||||||
// 从 result.data 中获取实际数据(因为后端返回格式为 { success: true, data: {...} })
|
// 从 result.data 中获取实际数据(因为后端返回格式为 { success: true, data: {...} })
|
||||||
const data = (result as any).data || result;
|
const data = (result as any).data || result;
|
||||||
const { total, processed, created, updated, deleted, errors } = data;
|
const { total, processed, created, updated, deleted, errors } = data;
|
||||||
|
|
||||||
// 构建结果消息
|
// 构建结果消息
|
||||||
let messageContent = `${operationType}结果:共 ${total} 条,成功 ${processed} 条`;
|
let messageContent = `${operationType}结果:共 ${total} 条,成功 ${processed} 条`;
|
||||||
|
|
||||||
if (created) {
|
if (created) {
|
||||||
messageContent += `,创建 ${created} 条`;
|
messageContent += `,创建 ${created} 条`;
|
||||||
|
|
@ -54,7 +54,7 @@ export function showBatchOperationResult(
|
||||||
const errorDetails = errors
|
const errorDetails = errors
|
||||||
.map((err: BatchErrorItem) => `${err.identifier}: ${err.error}`)
|
.map((err: BatchErrorItem) => `${err.identifier}: ${err.error}`)
|
||||||
.join('\n');
|
.join('\n');
|
||||||
message.warning(messageContent + '\n\n错误详情:\n' + errorDetails);
|
message.warning(messageContent + '\n\n错误详情:\n' + errorDetails);
|
||||||
} else {
|
} else {
|
||||||
message.success(messageContent);
|
message.success(messageContent);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue