zksu
/
WEB
forked from yoone/WEB
1
0
Fork 0

Compare commits

..

6 Commits

Author SHA1 Message Date
tikkhun c8064f20e3 feat(CSV工具): 添加产品SKU和名称生成选项
新增两个复选框选项控制是否自动生成产品SKU和名称
移除旧的生成bundle SKU选项并重构相关逻辑
添加SKU重复检查功能
2026-01-27 18:20:21 +08:00
tikkhun 82a0213631 fix(DictItemModal): 为表单字段添加 trim 规范化处理
防止用户输入前后空格导致数据不一致问题
2026-01-27 15:10:04 +08:00
tikkhun 85ad42278b feat(产品列表): 添加批量创建套装产品功能
新增批量创建套装产品功能,包含以下主要修改:
1. 添加 BatchCreateBundleModal 组件用于批量创建套装
2. 在产品列表页面添加批量创建套装按钮
3. 实现批量创建逻辑,支持选择单品和数量组合创建套装
2026-01-27 10:30:05 +08:00
tikkhun 686432f893 refactor(product): site skus 的后端进行了分表重构,前端跟随修改。 2026-01-24 18:19:54 +08:00
tikkhun f2db99c630 fix(Statistics/Sales): 将列标题从'产品名称'改为'产品sku' 2026-01-23 18:29:07 +08:00
tikkhun a2104c0f3d feat(地图): 添加加拿大和澳大利亚地图组件及路由配置
添加两个新的地图组件用于展示加拿大和澳大利亚的省级地图数据
修复 ProFromSelect 拼写错误为 ProFormSelect
2026-01-23 17:17:25 +08:00
4 changed files with 15 additions and 218 deletions

View File

@ -393,14 +393,6 @@ const UpdateForm: React.FC<{
})); }));
}} }}
/> />
<ProFormText
name={['email']}
label="邮箱"
width="lg"
placeholder="请输入邮箱"
required
rules={[{ required: true, message: '请输入邮箱' }]}
/>
<ProForm.Group title="地址"> <ProForm.Group title="地址">
<ProFormText <ProFormText
name={['address', 'country']} name={['address', 'country']}
@ -439,8 +431,6 @@ const UpdateForm: React.FC<{
required required
rules={[{ required: true, message: '请输入详细地址' }]} rules={[{ required: true, message: '请输入详细地址' }]}
/> />
</ProForm.Group> </ProForm.Group>
<ProFormItem <ProFormItem
name="contact" name="contact"

View File

@ -3,7 +3,6 @@ import styles from '../../../style/order-list.css';
import InternationalPhoneInput from '@/components/InternationalPhoneInput'; import InternationalPhoneInput from '@/components/InternationalPhoneInput';
import SyncForm from '@/components/SyncForm'; import SyncForm from '@/components/SyncForm';
import { showSyncResult, SyncResultData } from '@/components/SyncResultMessage'; import { showSyncResult, SyncResultData } from '@/components/SyncResultMessage';
import { UploadOutlined } from '@ant-design/icons';
import { ORDER_STATUS_ENUM } from '@/constants'; import { ORDER_STATUS_ENUM } from '@/constants';
import { HistoryOrder } from '@/pages/Statistics/Order'; import { HistoryOrder } from '@/pages/Statistics/Order';
import { import {
@ -25,7 +24,6 @@ import {
ordercontrollerSyncorderbyid, ordercontrollerSyncorderbyid,
ordercontrollerSyncorders, ordercontrollerSyncorders,
ordercontrollerUpdateorderitems, ordercontrollerUpdateorderitems,
ordercontrollerImportwintopay,
} from '@/servers/api/order'; } from '@/servers/api/order';
import { productcontrollerSearchproducts } from '@/servers/api/product'; import { productcontrollerSearchproducts } from '@/servers/api/product';
import { sitecontrollerAll } from '@/servers/api/site'; import { sitecontrollerAll } from '@/servers/api/site';
@ -76,16 +74,11 @@ import {
Tabs, Tabs,
TabsProps, TabsProps,
Tag, Tag,
Upload,
} from 'antd'; } from 'antd';
import React, { useMemo, useRef, useState } from 'react'; import React, { useMemo, useRef, useState } from 'react';
import RelatedOrders from '../../Subscription/Orders/RelatedOrders'; import RelatedOrders from '../../Subscription/Orders/RelatedOrders';
import dayjs from 'dayjs';
import * as XLSX from 'xlsx';
const ListPage: React.FC = () => { const ListPage: React.FC = () => {
const [file, setFile] = useState<File | null>(null);
const [csvData, setCsvData] = useState<any[]>([]);
const [processedData, setProcessedData] = useState<any[]>([]);
const actionRef = useRef<ActionType>(); const actionRef = useRef<ActionType>();
const [activeKey, setActiveKey] = useState<string>('all'); const [activeKey, setActiveKey] = useState<string>('all');
const [count, setCount] = useState<any[]>([]); const [count, setCount] = useState<any[]>([]);
@ -475,64 +468,6 @@ const ListPage: React.FC = () => {
]; ];
const [selectedRowKeys, setSelectedRowKeys] = useState([]); const [selectedRowKeys, setSelectedRowKeys] = useState([]);
/**
* @description
*/
const handleFileUpload = (uploadedFile: File) => {
// 检查文件类型
if (!uploadedFile.name.match(/\.(xlsx)$/)) {
message.error('请上传 xlsx 格式的文件!');
return false;
}
setFile(uploadedFile);
const reader = new FileReader();
// 对于Excel文件继续使用readAsArrayBuffer
reader.onload = (e) => {
try {
const data = e.target?.result;
// 如果是ArrayBuffer使用type: 'array'来处理
const workbook = XLSX.read(data, { type: 'array' });
const sheetName = workbook.SheetNames[0];
const worksheet = workbook.Sheets[sheetName];
const jsonData = XLSX.utils.sheet_to_json(worksheet, { header: 1 });
if (jsonData.length < 2) {
message.error('文件为空或缺少表头!');
setCsvData([]);
return;
}
// 将数组转换为对象数组
const headers = jsonData[0] as string[];
const rows = jsonData.slice(1).map((rowArray: any) => {
const rowData: { [key: string]: any } = {};
headers.forEach((header, index) => {
rowData[header] = rowArray[index];
});
return rowData;
});
message.success(`成功解析 ${rows.length} 条数据.`);
setCsvData(rows);
setProcessedData([]); // 清空旧的处理结果
} catch (error) {
message.error('Excel文件解析失败,请检查文件格式!');
console.error('Excel Parse Error:', error);
setCsvData([]);
}
};
reader.readAsArrayBuffer(uploadedFile);
reader.onerror = (error) => {
message.error('文件读取失败!');
console.error('File Read Error:', error);
};
return false; // 阻止antd Upload组件的默认上传行为
};
return ( return (
<PageContainer ghost> <PageContainer ghost>
<Tabs items={tabs} activeKey={activeKey} onChange={setActiveKey} /> <Tabs items={tabs} activeKey={activeKey} onChange={setActiveKey} />
@ -560,55 +495,6 @@ const ListPage: React.FC = () => {
}} }}
toolBarRender={() => [ toolBarRender={() => [
// <CreateOrder tableRef={actionRef} />, // <CreateOrder tableRef={actionRef} />,
<Upload
// beforeUpload={handleFileUpload}
name="file"
accept=".xlsx"
showUploadList={false}
maxCount={1}
customRequest={async (options) => {
const { file, onSuccess, onError } = options;
console.log(file);
const formData = new FormData();
formData.append('file', file);
try {
const res = await request('/order/import', {
method: 'POST',
data: formData,
requestType: 'form',
});
if (res?.success && res.data) {
// 使用xlsx将JSON数据转换为Excel
const XLSX = require('xlsx');
const worksheet = XLSX.utils.json_to_sheet(res.data);
const workbook = XLSX.utils.book_new();
XLSX.utils.book_append_sheet(workbook, worksheet, 'Orders');
const excelBuffer = XLSX.write(workbook, { bookType: 'xlsx', type: 'array' });
// 否则按原逻辑处理二进制数据
const blob = new Blob([excelBuffer], {
type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
});
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'orders.xlsx';
a.click();
URL.revokeObjectURL(url);
} else {
message.error(res.message || '导出失败');
}
actionRef.current?.reload();
setSelectedRowKeys([]);
} catch (error: any) {
message.error('导入失败: ' + (error.message || '未知错误'));
onError?.(error);
}
}}
>
<Button icon={<UploadOutlined />}></Button>
</Upload>,
<SyncForm <SyncForm
onFinish={async (values: any) => { onFinish={async (values: any) => {
try { try {
@ -1381,10 +1267,7 @@ const Shipping: React.FC<{
const [rates, setRates] = useState<API.RateDTO[]>([]); const [rates, setRates] = useState<API.RateDTO[]>([]);
const [ratesLoading, setRatesLoading] = useState(false); const [ratesLoading, setRatesLoading] = useState(false);
const { message } = App.useApp(); const { message } = App.useApp();
const [shipmentPlatforms, setShipmentPlatforms] = useState([
{ label: 'uniuni', value: 'uniuni' },
{ label: 'tms.freightwaves', value: 'freightwaves' },
]);
return ( return (
<ModalForm <ModalForm
formRef={formRef} formRef={formRef}
@ -1413,7 +1296,6 @@ const [shipmentPlatforms, setShipmentPlatforms] = useState([
await ordercontrollerGetorderdetail({ await ordercontrollerGetorderdetail({
orderId: id, orderId: id,
}); });
console.log('success data',success,data)
if (!success || !data) return {}; if (!success || !data) return {};
data.sales = data.sales?.reduce( data.sales = data.sales?.reduce(
(acc: API.OrderSale[], cur: API.OrderSale) => { (acc: API.OrderSale[], cur: API.OrderSale) => {
@ -1436,8 +1318,7 @@ const [shipmentPlatforms, setShipmentPlatforms] = useState([
if (reShipping) data.sales = [{}]; if (reShipping) data.sales = [{}];
let shipmentInfo = localStorage.getItem('shipmentInfo'); let shipmentInfo = localStorage.getItem('shipmentInfo');
if (shipmentInfo) shipmentInfo = JSON.parse(shipmentInfo); if (shipmentInfo) shipmentInfo = JSON.parse(shipmentInfo);
const a = { return {
shipmentPlatform: 'uniuni',
...data, ...data,
// payment_method_id: shipmentInfo?.payment_method_id, // payment_method_id: shipmentInfo?.payment_method_id,
stockPointId: shipmentInfo?.stockPointId, stockPointId: shipmentInfo?.stockPointId,
@ -1497,7 +1378,6 @@ const [shipmentPlatforms, setShipmentPlatforms] = useState([
}, },
}, },
}; };
return a
}} }}
onFinish={async ({ onFinish={async ({
customer_note, customer_note,
@ -1561,18 +1441,7 @@ const [shipmentPlatforms, setShipmentPlatforms] = useState([
} }
}} }}
> >
<Row gutter={16}> <ProFormText label="订单号" readonly name={'externalOrderId'} />
<Col span={8}>
<ProFormSelect
name="shipmentPlatform"
label="发货平台"
options={shipmentPlatforms}
placeholder="请选择发货平台"
rules={[{ required: true, message: '请选择一个选项' }]}
/>
</Col>
</Row>
<ProFormText label="订单号" readonly name='externalOrderId' />
<ProFormText label="客户备注" readonly name="customer_note" /> <ProFormText label="客户备注" readonly name="customer_note" />
<ProFormList <ProFormList
label="后台备注" label="后台备注"
@ -1704,21 +1573,16 @@ const [shipmentPlatforms, setShipmentPlatforms] = useState([
title="发货信息" title="发货信息"
extra={ extra={
<AddressPicker <AddressPicker
onChange={(row) => { onChange={({
console.log(row); address,
const { phone_number,
address, phone_number_extension,
phone_number, stockPointId,
phone_number_extension, }) => {
stockPointId,
email,
} = row;
formRef?.current?.setFieldsValue({ formRef?.current?.setFieldsValue({
stockPointId, stockPointId,
// address_id: row.id,
details: { details: {
origin: { origin: {
email_addresses:email,
address, address,
phone_number: { phone_number: {
phone: phone_number, phone: phone_number,
@ -1731,11 +1595,6 @@ const [shipmentPlatforms, setShipmentPlatforms] = useState([
/> />
} }
> >
{/* <ProFormText
label="address_id"
name={'address_id'}
rules={[{ required: true, message: '请输入ID' }]}
/> */}
<ProFormSelect <ProFormSelect
name="stockPointId" name="stockPointId"
width="md" width="md"
@ -1828,6 +1687,7 @@ const [shipmentPlatforms, setShipmentPlatforms] = useState([
<ProFormText <ProFormText
label="公司名称" label="公司名称"
name={['details', 'destination', 'name']} name={['details', 'destination', 'name']}
rules={[{ required: true, message: '请输入公司名称' }]}
/> />
<ProFormItem <ProFormItem
name={['details', 'destination', 'address', 'country']} name={['details', 'destination', 'address', 'country']}
@ -2157,7 +2017,6 @@ const [shipmentPlatforms, setShipmentPlatforms] = useState([
details.origin.phone_number.number = details.origin.phone_number.number =
details.origin.phone_number.phone; details.origin.phone_number.phone;
const res = await logisticscontrollerGetshipmentfee({ const res = await logisticscontrollerGetshipmentfee({
shipmentPlatform: data.shipmentPlatform,
stockPointId: data.stockPointId, stockPointId: data.stockPointId,
sender: details.origin.contact_name, sender: details.origin.contact_name,
@ -2484,7 +2343,7 @@ const CreateOrder: React.FC<{
<ProFormText <ProFormText
label="公司名称" label="公司名称"
name={['billing', 'company']} name={['billing', 'company']}
rules={[{ message: '请输入公司名称' }]} rules={[{ required: true, message: '请输入公司名称' }]}
/> />
<ProFormItem <ProFormItem
name={['billing', 'country']} name={['billing', 'country']}
@ -2570,11 +2429,6 @@ const AddressPicker: React.FC<{
value: item.id, value: item.id,
})); }));
}, },
},
{
title: 'id',
dataIndex: ['id'],
hideInSearch: true,
}, },
{ {
title: '地区', title: '地区',
@ -2602,11 +2456,6 @@ const AddressPicker: React.FC<{
`+${record.phone_number_extension} ${record.phone_number}`, `+${record.phone_number_extension} ${record.phone_number}`,
hideInSearch: true, hideInSearch: true,
}, },
{
title: '邮箱',
dataIndex: [ 'email'],
hideInSearch: true,
},
]; ];
return ( return (
<ModalForm <ModalForm

View File

@ -149,45 +149,6 @@ export async function ordercontrollerGetordersales(
}); });
} }
/** 此处后端没有提供注释 POST /order/import */
export async function ordercontrollerImportwintopay(
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>('/order/import', {
method: 'POST',
data: formData,
requestType: 'form',
...(options || {}),
});
}
/** 此处后端没有提供注释 POST /order/order/cancel/${param0} */ /** 此处后端没有提供注释 POST /order/order/cancel/${param0} */
export async function ordercontrollerCancelorder( export async function ordercontrollerCancelorder(
// 叠加生成的Param类型 (非body参数swagger默认没有生成对象) // 叠加生成的Param类型 (非body参数swagger默认没有生成对象)

View File

@ -460,8 +460,6 @@ declare namespace API {
tracking_id?: string; tracking_id?: string;
/** 物流单号 */ /** 物流单号 */
tracking_number?: string; tracking_number?: string;
/** 物流产品代码 */
tracking_product_code?: string;
/** 物流公司 */ /** 物流公司 */
shipping_provider?: string; shipping_provider?: string;
/** 发货方式 */ /** 发货方式 */
@ -623,7 +621,7 @@ declare namespace API {
shipping_total?: number; shipping_total?: number;
shipping_tax?: number; shipping_tax?: number;
cart_tax?: number; cart_tax?: number;
total?: any; total?: number;
total_tax?: number; total_tax?: number;
customer_id?: number; customer_id?: number;
customer_email?: string; customer_email?: string;
@ -822,7 +820,7 @@ declare namespace API {
shipping_total?: number; shipping_total?: number;
shipping_tax?: number; shipping_tax?: number;
cart_tax?: number; cart_tax?: number;
total?: any; total?: number;
total_tax?: number; total_tax?: number;
customer_id?: number; customer_id?: number;
customer_email?: string; customer_email?: string;
@ -1636,7 +1634,7 @@ declare namespace API {
shipmentPlatform?: string; shipmentPlatform?: string;
stockPointId?: number; stockPointId?: number;
sender?: string; sender?: string;
startPhone?: Record<string, any>; startPhone?: string;
startPostalCode?: string; startPostalCode?: string;
pickupAddress?: string; pickupAddress?: string;
shipperCountryCode?: string; shipperCountryCode?: string;
@ -1665,7 +1663,6 @@ declare namespace API {
phone_number?: string; phone_number?: string;
phone_number_extension?: string; phone_number_extension?: string;
phone_number_country?: string; phone_number_country?: string;
email?: string;
/** 创建时间 */ /** 创建时间 */
createdAt: string; createdAt: string;
/** 更新时间 */ /** 更新时间 */