This commit is contained in:
ylj20011123 2026-02-12 09:46:37 +08:00
parent 7427b81262
commit adb62e8ca4
10 changed files with 928 additions and 9 deletions

BIN
dist.zip

Binary file not shown.

View File

@ -1,6 +1,6 @@
{ {
"name": "ant-design-pro", "name": "ant-design-pro",
"version": "4.5.144", "version": "4.5.146",
"private": true, "private": true,
"description": "An out-of-box UI solution for enterprise applications", "description": "An out-of-box UI solution for enterprise applications",
"scripts": { "scripts": {

View File

@ -1023,6 +1023,7 @@ const OrderDetailModal = ({ modalVisible, handleCloseModal, currentRow, detailTy
<td /> <td />
<td style={{ textAlign: 'center', fontWeight: 'bold' }}>{orderDetail?.ORDER_AMOUNT?.toFixed(2) || '0.00'}</td> <td style={{ textAlign: 'center', fontWeight: 'bold' }}>{orderDetail?.ORDER_AMOUNT?.toFixed(2) || '0.00'}</td>
<td /> <td />
<td />
</tr> </tr>
) )
}} }}

View File

@ -0,0 +1,423 @@
import { connect } from "umi";
import type { ConnectState } from "@/models/connect";
import ProTable, { ActionType } from "@ant-design/pro-table";
import { useRef, useState } from "react";
import { Button, FormInstance, message, Modal } from "antd";
import moment from 'moment'
import { handeGetSaleBillWholeList, handeGetSALEDETAILList, handeSynchroMemberOrderBill } from "../../service";
type DetailProps = {
currentUser: any
parentRef: any
setPartialRefundModalVisible: any
}
const PartialRefundModal = ({ currentUser, parentRef, setPartialRefundModalVisible }: DetailProps) => {
const actionRef = useRef<ActionType>();
const formRef = useRef<FormInstance>();
const actionModalRef = useRef<ActionType>();
const formModalRef = useRef<FormInstance>();
// 行数据
const [currentRow, setCurrentRow] = useState<any>()
// 显示现在要实际退款的订单的modal
const [showModal, setShowModal] = useState<boolean>(false)
// 当前勾选的退款商品
const [selectedShopDetail, setSelectShopDetail] = useState<any>([])
// 勾选后的退款loading
const [refundLoading, setRefundLoading] = useState<boolean>(false)
const columns: any = [
{
dataIndex: 'searchText',
title: '查询内容',
hideInTable: true,
fieldProps: {
placeholder: "请输入供货商/购买的商品/订单编号"
}
},
{
title: '查询时间',
dataIndex: 'search_date',
valueType: 'dateRange',
hideInTable: true,
hideInDescriptions: true,
search: {
transform: (value) => {
return {
ORDER_DATE_Start: value[0],
ORDER_DATE_End: value[1],
};
},
},
fieldProps: {
ranges: {
"本月": [moment().startOf('M'), moment()],
"上月": [moment().subtract(1, 'M').startOf('M'), moment().subtract(1, 'M').endOf('M')],
"近三月": [moment().subtract(3, 'M').startOf('M'), moment().endOf('M')],
"近半年": [moment().subtract(6, 'M').startOf('M'), moment().endOf('M')],
}
},
// initialValue: [moment().add(-1, 'M').format('YYYY-MM-DD'), moment().format('YYYY-MM-DD')],
// 2026-01-26 朱老师说的 上个月底前一天
initialValue: [moment().subtract(1, 'M').endOf('M').subtract(1, 'd'), moment().endOf('M')],
},
{
title: "序号",
dataIndex: "index",
valueType: "index",
hideInSearch: true,
align: "center",
width: 60,
},
{
title: "供货商",
dataIndex: "MERCHANTS_NAME",
width: 200,
hideInSearch: true,
ellipsis: true,
align: "center",
},
{
title: "会员姓名",
dataIndex: "ORDERPERSON",
width: 200,
hideInSearch: true,
ellipsis: true,
align: "center",
render: (_, record) => {
return `${record?.ORDER_PERSON || ""}${record?.ORDER_PERSONTEL ? `${record?.ORDER_PERSONTEL}` : ""}`
}
},
{
title: "收货人员",
dataIndex: "AddressInfoPerson",
width: 150,
hideInSearch: true,
ellipsis: true,
align: "center",
render: (_, record) => {
return record?.AddressInfo ? record?.AddressInfo.USER_NAME || "" : ""
}
},
{
title: "联系电话",
dataIndex: "AddressInfoPersonMOBILEPHONE",
width: 150,
hideInSearch: true,
ellipsis: true,
align: "center",
render: (_, record) => {
return record?.AddressInfo ? record?.AddressInfo.MOBILEPHONE || "" : ""
}
},
{
title: "购买的商品",
dataIndex: "COMMODITY_NAME",
width: 300,
hideInSearch: true,
ellipsis: true,
align: "center",
},
{
title: "订单金额",
dataIndex: "ORDER_AMOUNT",
width: 120,
hideInSearch: true,
ellipsis: true,
align: "center",
sorter: (a, b) => a.ORDER_AMOUNT - b.ORDER_AMOUNT
},
{
title: "订单时间",
dataIndex: "ORDER_DATE",
width: 180,
hideInSearch: true,
ellipsis: true,
align: "center",
render: (_, record) => {
return record?.ORDER_DATE ? moment(record?.ORDER_DATE).format('YYYY-MM-DD HH:mm:ss') : "-"
},
sorter: (a, b) => new Date(a.ORDER_DATE).getTime() - new Date(b.ORDER_DATE).getTime(),
defaultSortOrder: 'descend',
},
{
title: "操作",
dataIndex: "action",
width: 120,
hideInSearch: true,
align: "center",
fixed: "right",
render: (_, record) => {
return (
<Button
type="link"
onClick={() => {
setCurrentRow(record)
setShowModal(true)
}}
>
退
</Button>
)
}
}
]
const columnsModal: any = [
{
dataIndex: "index",
title: "序号",
align: 'center',
hideInSearch: true,
valueType: "index",
width: 70,
ellipsis: true,
},
{
dataIndex: 'COMMODITY_NAME',
title: '商品名称',
align: 'center',
hideInSearch: true,
width: 150,
ellipsis: true,
},
{
dataIndex: 'COMMODITY_BARCODE',
title: '商品条码',
align: 'center',
hideInSearch: true,
width: 150,
ellipsis: true,
},
{
dataIndex: 'COMMODITY_UNIT',
title: '商品单位',
align: 'center',
hideInSearch: true,
width: 120,
ellipsis: true,
},
{
dataIndex: 'COMMODITY_RULE',
title: '商品规格',
align: 'center',
hideInSearch: true,
width: 120,
ellipsis: true,
},
{
dataIndex: 'ORDER_COUNT',
title: '数量',
align: 'center',
hideInSearch: true,
width: 120,
ellipsis: true,
},
{
dataIndex: 'AVERAGE_PRICE',
title: '单价',
align: 'center',
hideInSearch: true,
width: 120,
ellipsis: true,
},
{
dataIndex: 'ORDER_AMOUNT',
title: '金额',
align: 'center',
hideInSearch: true,
width: 120,
ellipsis: true,
},
{
dataIndex: 'SALEDETAIL_DESC',
title: '备注',
align: 'center',
hideInSearch: true,
width: 150,
}
]
// 部分退款的方法
const handleRefund = async () => {
// 要退款的商品列表
let list: any = []
console.log('selectedShopDetailselectedShopDetail', selectedShopDetail);
// 商品数量
let ORDER_COUNTSUM: number = 0
// 订单金额合计
let OrderAmountSUM: number = 0
selectedShopDetail.forEach((item: any) => {
list.push({
SupplierId: item.MERCHANTS_ID, // 供应商内码
SupplierName: item.MERCHANTS_NAME, // 供应商名称
OriBillDetailId: item.SALEDETAIL_ID,
GoodsId: item.COMMODITY_ID, // 商品内码
GoodsName: item.COMMODITY_NAME, // 商品名称
GoodsBarcode: item.COMMODITY_BARCODE, // 商品条码
GoodsUnit: item.COMMODITY_UNIT, // 商品单位
GoodsRule: item.COMMODITY_RULE, // 商品规格
OrderCount: item.ORDER_COUNT, // 商品数量
AveragePrice: item.AVERAGE_PRICE, // 商品单价
OrderAmount: item.ORDER_AMOUNT, // 商品金额
CostPrice: item.AVERAGE_COST, // 商品成本
CostAmount: item.COST_AMOUNT, // 成本金额
ConsumePoint: "", // 消耗积分
DeliverState: item.SALEBILL_STATE || "", // 发货状态
Dutyparagraph: item.DUTY_PARAGRAPH
})
ORDER_COUNTSUM += item.ORDER_COUNT
OrderAmountSUM += item.ORDER_AMOUNT
})
let req: any = {
Province_Code: "530000",
Serverpart_Id: currentRow?.SERVERPART_ID,
ServerpartShop_Id: currentRow?.SERVERPARTSHOP_ID,
OrderType: 3999,// 订单类型
OriBillCode: currentRow?.PAYMENT_CODE,
OrderPerson: currentRow?.ORDER_PERSON,
PhoneNumber: currentRow?.ORDER_PERSONTEL,
OrderDate: moment().format('YYYY-MM-DD HH:mm:ss'),
GoodsCount: list && list.length > 0 ? list.length : "",
OrderCount: ORDER_COUNTSUM,
OrderAmount: OrderAmountSUM,
OrderState: 8000,
PayMethod: currentRow?.CHANNEL_TYPE,
PayAmount: OrderAmountSUM,
PayDate: "",
PayState: 0,
MixPay: false,
BalanceAmount: currentRow?.BALANCE_PAYMENT,
WechatAppSignAppId: "wxee018fb96955552a",
DetailList: list
}
console.log('reqreq', req);
setRefundLoading(true)
const data = await handeSynchroMemberOrderBill(req)
setRefundLoading(false)
if (data.Result_Code === 100) {
message.success("退款订单创建成功")
setShowModal(false)
setSelectShopDetail([])
actionRef.current?.reload()
if (setPartialRefundModalVisible) {
setPartialRefundModalVisible(false)
}
if (parentRef) {
parentRef.current?.reload()
}
} else {
message.error(data.Result_Msg)
}
}
return (
<div>
<ProTable
actionRef={actionRef}
formRef={formRef}
columns={columns}
bordered
scroll={{ x: "100%", y: '400px' }}
request={async (params) => {
const req: any = {
SearchParameter: {
OWNERUNIT_ID: currentUser?.OwnerUnitId,
PROVINCE_CODE: currentUser?.ProvinceCode,
SALEBILL_TYPES: '3000,3001,3002,3010',
ORDER_DATE_Start: params?.ORDER_DATE_Start || "",
ORDER_DATE_End: params?.ORDER_DATE_End || "",
SALEBILL_STATES: "1010,2010,3000",
CHANNEL_TYPE: "",
SearchKeyValue: params?.searchText || "",
MERCHANTS_IDS: currentUser?.UserPattern === 4000 ? currentUser?.SupplierID : params?.MERCHANTS_IDS || "",
},
PageIndex: 1,
PageSize: 999999,
SortStr: "ORDER_DATE desc",
}
const data = await handeGetSaleBillWholeList(req);
console.log('可部分退款的订单321312', data);
if (data.List && data.List.length > 0) {
return { data: data.List, success: true }
}
return { data: [], success: true }
}}
/>
{/* currentRow
setCurrentRow(record) */}
<Modal
width={'70%'}
open={showModal}
destroyOnClose
title={`${currentRow?.ORDER_PERSON || ""}${currentRow?.ORDER_PERSONTEL ? `${currentRow?.ORDER_PERSONTEL}` : ""}`}
confirmLoading={refundLoading}
onOk={() => {
if (selectedShopDetail && selectedShopDetail.length > 0) {
handleRefund()
} else {
message.error("请选择要退款的商品")
}
}}
onCancel={() => {
setCurrentRow(undefined)
setShowModal(false)
setSelectShopDetail([])
}}
>
<ProTable
actionRef={actionModalRef}
formRef={formModalRef}
columns={columnsModal}
bordered
rowKey={'COMMODITY_ID'}
scroll={{ x: "100%", y: '400px' }}
search={false}
request={async (params) => {
console.log('currentRow', currentRow);
const req: any = {
searchParameter: {
SALEBILL_ID: currentRow?.SALEBILL_ID,
SALEBILL_CHILD_ID: currentRow?.SALEBILL_CHILD_ID
},
PageIndex: 1,
PageSize: 999999,
}
const data = await handeGetSALEDETAILList(req)
console.log('datadatadata', data);
if (data.List && data.List.length > 0) {
return { data: data.List, success: true }
}
return { data: [], success: true }
}}
rowSelection={{
type: 'checkbox',
onChange: (selectedRowKeys, selectedRows) => {
console.log('selectedRowKeys', selectedRowKeys);
console.log('selectedRows', selectedRows);
setSelectShopDetail(selectedRows)
},
}}
/>
</Modal>
</div>
)
}
export default connect(({ user, }: ConnectState) => ({
currentUser: user.currentUser,
}))(PartialRefundModal);

View File

@ -16,6 +16,7 @@ import closeIcon from '@/assets/detail/closeIcon.png'
import './style.less' import './style.less'
import { handleSetlogSave } from "@/utils/format"; import { handleSetlogSave } from "@/utils/format";
import { highlightText } from "@/utils/highlightText"; import { highlightText } from "@/utils/highlightText";
import PartialRefundModal from "./components/PartialRefundModal";
const OrderAfterSalesManage: React.FC<{ currentUser: CurrentUser }> = (props) => { const OrderAfterSalesManage: React.FC<{ currentUser: CurrentUser }> = (props) => {
@ -32,6 +33,8 @@ const OrderAfterSalesManage: React.FC<{ currentUser: CurrentUser }> = (props) =>
// 弹出框拖动效果 // 弹出框拖动效果
const [bounds, setBounds] = useState<{ left: number, right: number, top: number, bottom: number }>() // 移动的位置 const [bounds, setBounds] = useState<{ left: number, right: number, top: number, bottom: number }>() // 移动的位置
const [disabled, setDraggleDisabled] = useState<boolean>() // 是否拖动 const [disabled, setDraggleDisabled] = useState<boolean>() // 是否拖动
// 部分退款的悬浮框
const [partialRefundModalVisible, setPartialRefundModalVisible] = useState<boolean>(false)
const onDraggaleStart = (event, uiData) => { const onDraggaleStart = (event, uiData) => {
const { clientWidth, clientHeight } = window.document.documentElement; const { clientWidth, clientHeight } = window.document.documentElement;
const targetRect = draggleRef.current?.getBoundingClientRect(); const targetRect = draggleRef.current?.getBoundingClientRect();
@ -405,12 +408,31 @@ const OrderAfterSalesManage: React.FC<{ currentUser: CurrentUser }> = (props) =>
return { data: [], success: true } return { data: [], success: true }
}} }}
toolbar={{ toolbar={{
actions: [
<Button type="primary" onClick={() => {
setPartialRefundModalVisible(true)
}}>退</Button>
]
}} }}
/> />
</div> </div>
</div> </div>
<Modal
width={'75%'}
open={partialRefundModalVisible}
destroyOnClose
onOk={() => {
setPartialRefundModalVisible(false)
}}
onCancel={() => {
setPartialRefundModalVisible(false)
}}
footer={false}
>
{/* 部分退款的组件 */}
<PartialRefundModal currentUser={currentUser} parentRef={actionRef} setPartialRefundModalVisible={setPartialRefundModalVisible} />
</Modal>
<Modal <Modal
className="OrderAfterSalesManageModal" className="OrderAfterSalesManageModal"

View File

@ -0,0 +1,71 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace EShang.Common.Model.WeChatMall
{
/// <summary>
/// 订单明细相关类
/// </summary>
public class OrderDetailModel
{
/// <summary>
/// 供应商名称
/// </summary>
public string SupplierName { get; set; }
/// <summary>
/// 商品内码
/// </summary>
public int? GoodsId { get; set; }
/// <summary>
/// 商品名称
/// </summary>
public string GoodsName { get; set; }
/// <summary>
/// 商品条码
/// </summary>
public string GoodsBarcode { get; set; }
/// <summary>
/// 商品单位
/// </summary>
public string GoodsUnit { get; set; }
/// <summary>
/// 商品规格
/// </summary>
public string GoodsRule { get; set; }
/// <summary>
/// 商品数量
/// </summary>
public decimal OrderCount { get; set; }
/// <summary>
/// 商品单价
/// </summary>
public decimal AveragePrice { get; set; }
/// <summary>
/// 商品金额
/// </summary>
public decimal? OrderAmount { get; set; }
/// <summary>
/// 商品成本
/// </summary>
public decimal CostPrice { get; set; }
/// <summary>
/// 成本金额
/// </summary>
public decimal? CostAmount { get; set; }
/// <summary>
/// 消耗积分
/// </summary>
public decimal? ConsumePoint { get; set; }
/// <summary>
/// 发货状态
/// </summary>
public int DeliverState { get; set; }
/// <summary>
/// 商品图片地址
/// </summary>
public string ImageUrl { get; set; }
}
}

View File

@ -0,0 +1,171 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace EShang.Common.Model.WeChatMall
{
/// <summary>
/// 订单相关类
/// </summary>
public class OrderModel
{
/// <summary>
/// 省份编码
/// </summary>
public int? Province_Code { get; set; }
/// <summary>
/// 服务区内码
/// </summary>
public int? Serverpart_Id { get; set; }
/// <summary>
/// 门店内码
/// </summary>
public int? ServerpartShop_Id { get; set; }
/// <summary>
/// 订单内码
/// </summary>
public int? OrderId { get; set; }
/// <summary>
/// 订单类型
/// </summary>
public int? OrderType { get; set; }
/// <summary>
/// 子订单内码
/// </summary>
public int? OrderChildId { get; set; }
/// <summary>
/// 订单编码
/// </summary>
public string OrderCode { get; set; }
/// <summary>
/// 取餐方式1000:堂食2000预约
/// </summary>
public int? TakeType { get; set; }
/// <summary>
/// 就餐方式1000堂食2000打包
/// </summary>
public int? PackType { get; set; }
/// <summary>
/// 客户单位
/// </summary>
public string CompanyName { get; set; }
/// <summary>
/// 下单人员
/// </summary>
public string OrderPerson { get; set; }
/// <summary>
/// 手机号码
/// </summary>
public string PhoneNumber { get; set; }
/// <summary>
/// 下单时间
/// </summary>
public string OrderDate { get; set; }
/// <summary>
/// 预约时间
/// </summary>
public string ReservationDate { get; set; }
/// <summary>
/// 商品种类
/// </summary>
public int GoodsCount { get; set; }
/// <summary>
/// 下单数量
/// </summary>
public decimal OrderCount { get; set; }
/// <summary>
/// 订单金额
/// </summary>
public decimal? OrderAmount { get; set; }
/// <summary>
/// 消耗积分
/// </summary>
public decimal? ConsumePoint { get; set; }
/// <summary>
/// 优惠金额
/// </summary>
public decimal? DiscountAmount { get; set; }
/// <summary>
/// 打包金额
/// </summary>
public decimal? PackAmount { get; set; }
/// <summary>
/// 订单状态
/// </summary>
public int OrderState { get; set; }
/// <summary>
/// 收货人员
/// </summary>
public string ReceivePerson { get; set; }
/// <summary>
/// 收货人手机
/// </summary>
public string ReceivePersonTel { get; set; }
/// <summary>
/// 收货地址
/// </summary>
public string ReceiveAddress { get; set; }
/// <summary>
/// 门牌号码
/// </summary>
public string ReceiveDoorPlate { get; set; }
/// <summary>
/// 取餐码
/// </summary>
public string TakeNumber { get; set; }
/// <summary>
/// 支付方式
/// </summary>
public string PayMethod { get; set; }
/// <summary>
/// 支付金额
/// </summary>
public decimal? PayAmount { get; set; }
/// <summary>
/// 支付时间
/// </summary>
public string PayDate { get; set; }
/// <summary>
/// 支付状态
/// </summary>
public int PayState { get; set; }
/// <summary>
/// 组合支付
/// </summary>
public bool MixPay { get; set; }
/// <summary>
/// 工会积分支付
/// </summary>
public decimal? BalanceAmount { get; set; }
/// <summary>
/// 微信小程序APPID
/// </summary>
public string WechatAppSignAppId { get; set; }
/// <summary>
/// 订单明细列表
/// </summary>
public List<OrderDetailModel> DetailList { get; set; }
}
/// <summary>
/// 订单数据导入相关类
/// </summary>
public class OrderBillImportModel
{
/// <summary>
/// 业主单位内码
/// </summary>
public int OwnerUnitId { get; set; }
/// <summary>
/// 微信小程序APPID
/// </summary>
public string WechatAppSignAppId { get; set; }
/// <summary>
/// 订单数据
/// </summary>
public List<OrderModel> orderList { get; set; }
}
}

View File

@ -2,11 +2,12 @@
import { connect } from "umi"; import { connect } from "umi";
import type { CurrentUser } from "umi"; import type { CurrentUser } from "umi";
import type { ConnectState } from "@/models/connect"; import type { ConnectState } from "@/models/connect";
import React, { useRef, useState } from "react"; import React, { useRef, useState, useEffect } from "react";
import ProCard from "@ant-design/pro-card"; import ProCard from "@ant-design/pro-card";
import { MenuFoldOutlined } from "@ant-design/icons"; import { MenuFoldOutlined } from "@ant-design/icons";
import type { FormInstance } from "antd"; import type { FormInstance } from "antd";
import { Button, message, Space, Spin, Tree } from "antd"; import { Button, message, Space, Spin, Tree, Modal, Upload, Popconfirm } from "antd";
import { InboxOutlined } from "@ant-design/icons";
import useRequest from "@ahooksjs/use-request"; import useRequest from "@ahooksjs/use-request";
import { getServerpartTree } from "@/services/options"; import { getServerpartTree } from "@/services/options";
import type { ActionType } from "@ant-design/pro-table"; import type { ActionType } from "@ant-design/pro-table";
@ -14,11 +15,12 @@ import ProTable from "@ant-design/pro-table";
import ReactHTMLTableToExcel from "react-html-table-to-excel"; import ReactHTMLTableToExcel from "react-html-table-to-excel";
import LeftSelectTree from "@/pages/reports/settlementAccount/component/leftSelectTree"; import LeftSelectTree from "@/pages/reports/settlementAccount/component/leftSelectTree";
import PageTitleBox from "@/components/PageTitleBox"; import PageTitleBox from "@/components/PageTitleBox";
import { handeGetCOMPANYList, handeGetMERCHANTSList, handeGetOnlineBillAccountList, handeGetSalebillAccountList, handeGetSupplierSaleBillList } from "../service"; import { handeGetCOMPANYList, handeGetMERCHANTSList, handeGetOnlineBillAccountList, handeGetSalebillAccountList, handeGetSupplierSaleBillList, handeImportOrderBill } from "../service";
import moment from 'moment' import moment from 'moment'
import OrderDetailModal from "../BookingMealOrder/components/orderDetailModal"; import OrderDetailModal from "../BookingMealOrder/components/orderDetailModal";
import { exportXlsxFromProColumnsExcelJS, formatTreeData, handleSetlogSave } from "@/utils/format"; import { exportXlsxFromProColumnsExcelJS, formatTreeData, handleSetlogSave } from "@/utils/format";
import { highlightText } from "@/utils/highlightText"; import { highlightText } from "@/utils/highlightText";
import * as XLSX from 'xlsx';
const TradingLedger: React.FC<{ currentUser: CurrentUser }> = (props) => { const TradingLedger: React.FC<{ currentUser: CurrentUser }> = (props) => {
const { currentUser } = props const { currentUser } = props
@ -46,6 +48,20 @@ const TradingLedger: React.FC<{ currentUser: CurrentUser }> = (props) => {
const [currentSearchText, setCurrentSearchText] = useState<string>('') const [currentSearchText, setCurrentSearchText] = useState<string>('')
// 获取导出数据的loading // 获取导出数据的loading
const [getExportDataLoading, setGetExportDataLoading] = useState<boolean>(false); const [getExportDataLoading, setGetExportDataLoading] = useState<boolean>(false);
// 导入订单相关状态
const [importModalVisible, setImportModalVisible] = useState<boolean>(false);
// 当前导入的订单数据
const [parsedOrders, setParsedOrders] = useState<any[]>([]);
// 导入的loading
const [importLoading, setImportLoading] = useState<boolean>(false);
const isMounted = useRef(true);
useEffect(() => {
isMounted.current = true;
return () => {
isMounted.current = false;
};
}, []);
// 获取所属单位 // 获取所属单位
const { loading: companyLoading, data: companyList = [] } = useRequest(async () => { const { loading: companyLoading, data: companyList = [] } = useRequest(async () => {
@ -732,6 +748,130 @@ const TradingLedger: React.FC<{ currentUser: CurrentUser }> = (props) => {
} }
} }
// 处理导入 Excel 并识别内容
const handleImportExcel = async (fileObj: any) => {
// 确保传入的是 Blob/File 对象
const file = fileObj.originFileObj || fileObj;
if (!(file instanceof Blob)) {
console.error('传入的文件对象无效:', fileObj);
message.error('文件上传有误,请重试');
return;
}
try {
const reader = new FileReader();
reader.onload = (e: any) => {
try {
const data = e.target.result;
const workbook = XLSX.read(data, { type: "binary" });
const firstSheetName = workbook.SheetNames[0];
const worksheet = workbook.Sheets[firstSheetName];
const rawData: any = XLSX.utils.sheet_to_json(worksheet);
processExcelData(rawData);
} catch (err) {
console.error('读取 Excel 失败:', err);
message.error('Excel 内容读取失败');
}
};
reader.readAsBinaryString(file);
} catch (error) {
console.error('FileReader 错误:', error);
message.error('文件解析遇到错误');
}
};
const processExcelData = (rawData: any[]) => {
console.log('Excel 原始识别条数:', rawData?.length);
if (rawData && rawData.length > 0) {
const phoneRegex = /^1[3-9]\d{9}$/;
const errorMessages: string[] = [];
const formattedList = rawData.map((item: any, index: number) => {
const orderPerson = item['下单人'] || `${index + 1} 行客户`;
const phoneNumber = String(item['微信授权手机号码'] || '').trim();
const receivePersonTel = String(item['收货手机号码'] || '').trim();
// 手机号有效性检查
if (phoneNumber && !phoneRegex.test(phoneNumber)) {
errorMessages.push(`下单人[${orderPerson}]的“微信授权手机号码”格式不正确`);
}
if (receivePersonTel && !phoneRegex.test(receivePersonTel)) {
errorMessages.push(`下单人[${orderPerson}]的“收货手机号码”格式不正确`);
}
const orderItem: any = {
OrderType: "", // 订单类型 空着
CompanyName: item['单位名称'],
OrderPerson: orderPerson,
PhoneNumber: phoneNumber,
OrderDate: item['下单时间'],
ReceivePerson: item['收货人名称'] || item['收货人'],
ReceivePersonTel: receivePersonTel,
ReceiveAddress: item['收货地址'],
DetailList: []
};
const alphabet = 'ABCDEFGHIJ';
for (let char of alphabet) {
const nameKey = `套餐商品${char}`;
if (item[nameKey]) {
orderItem.DetailList.push({
GoodsName: item[nameKey],
GoodsBarcode: item[`套餐商品${char}条码`],
OrderCount: item[`套餐商品${char}数量`],
OrderAmount: item[`套餐商品${char}金额`],
});
}
}
return orderItem;
});
// 提示所有校验错误
if (errorMessages.length > 0) {
// 如果错误太多只显示前5条
const showErrors = errorMessages.length > 5 ? errorMessages.slice(0, 5).concat(`...等共计 ${errorMessages.length} 处错误`) : errorMessages;
Modal.error({
title: '数据校验失败',
content: (
<div>
{showErrors.map((err, i) => <div key={i} style={{ color: 'red' }}>· {err}</div>)}
</div>
),
});
return; // 校验失败不进行后续预览
}
if (isMounted.current) {
setParsedOrders(formattedList);
message.success(`成功识别 ${formattedList.length} 条订单数据`);
}
}
};
// 提示询问 是否确认导入
const handleConfirmImport = async () => {
if (parsedOrders && parsedOrders.length > 0) {
const req: any = {
OwnerUnitId: "911", // 业主单位内码
WechatAppSignAppId: "wxee018fb96955552a", // 小程序APPID
orderList: parsedOrders // 订单数据
}
setImportLoading(true)
const data = await handeImportOrderBill(req)
setImportLoading(false)
message.success('导入成功!')
console.log('导入结果:', data);
setImportModalVisible(false);
setParsedOrders([]);
actionRef.current?.reload();
} else {
message.error(`请先导入数据!`);
}
}
return ( return (
<div ref={(el) => { <div ref={(el) => {
// 打印报表 // 打印报表
@ -836,7 +976,7 @@ const TradingLedger: React.FC<{ currentUser: CurrentUser }> = (props) => {
Excel Excel
</Button>, </Button>,
<Button onClick={() => { <Button onClick={() => {
setImportModalVisible(true)
}}></Button>, }}></Button>,
<Button onClick={() => { <Button onClick={() => {
window.open('https://samanage.yciccloud.com:6060/cloud/%E2%80%9C%E5%BD%A9%E4%BA%91%E9%A9%BF%E2%80%9D%E5%95%86%E5%9F%8E%E8%AE%A2%E5%8D%95%E5%AF%BC%E5%85%A5%E6%A8%A1%E6%9D%BF.xlsx', '_blank') window.open('https://samanage.yciccloud.com:6060/cloud/%E2%80%9C%E5%BD%A9%E4%BA%91%E9%A9%BF%E2%80%9D%E5%95%86%E5%9F%8E%E8%AE%A2%E5%8D%95%E5%AF%BC%E5%85%A5%E6%A8%A1%E6%9D%BF.xlsx', '_blank')
@ -849,6 +989,69 @@ const TradingLedger: React.FC<{ currentUser: CurrentUser }> = (props) => {
<OrderDetailModal modalVisible={modalVisible} handleCloseModal={handleCloseModal} currentRow={currentRow} showShipment={true} comeType={"TradingLedger"} actionRef={actionRef} /> <OrderDetailModal modalVisible={modalVisible} handleCloseModal={handleCloseModal} currentRow={currentRow} showShipment={true} comeType={"TradingLedger"} actionRef={actionRef} />
<Modal
title="导入订单识别"
visible={importModalVisible}
onCancel={() => {
setImportModalVisible(false);
setParsedOrders([]);
}}
footer={[
<Button key="close" onClick={() => {
setParsedOrders([]);
setImportModalVisible(false)
}}></Button>,
<Popconfirm title={"确认导入?"} onConfirm={() => {
handleConfirmImport()
}}>
<Button type={"primary"} key="import" loading={importLoading}></Button>
</Popconfirm>
]}
width={800}
>
<Upload.Dragger
accept=".xlsx, .xls"
showUploadList={false}
customRequest={(options: any) => {
handleImportExcel(options.file).then(() => {
if (options.onSuccess) options.onSuccess("ok");
}).catch(err => {
if (options.onError) options.onError(err);
});
}}
>
<p className="ant-upload-drag-icon">
<InboxOutlined />
</p>
<p className="ant-upload-text"></p>
<p className="ant-upload-hint"> .xlsx, .xls </p>
</Upload.Dragger>
{parsedOrders.length > 0 && (
<div style={{ marginTop: 20 }}>
<h4> ( {parsedOrders.length} ):</h4>
<div style={{ maxHeight: 300, overflowY: 'auto', border: '1px solid #f0f0f0', padding: 10 }}>
{parsedOrders.map((order, idx) => (
<div key={idx} style={{ marginBottom: 15, borderBottom: '1px dashed #eee', paddingBottom: 10 }}>
<div><b>:</b> {order.OrderPerson} ({order.PhoneNumber})</div>
<div><b>:</b> {order.ReceivePerson} | {order.ReceivePersonTel}</div>
<div><b>:</b> {order.ReceiveAddress}</div>
<div style={{ paddingLeft: 10 }}>
<b>:</b>
{order.DetailList.map((g: any, gIdx: number) => (
<div key={gIdx} style={{ fontSize: '12px', color: '#666' }}>
· {g.GoodsName} x{g.OrderCount} (: {g.OrderAmount})
</div>
))}
</div>
</div>
))}
</div>
</div>
)}
</Modal>
</div> </div>
) )
} }

View File

@ -1457,3 +1457,31 @@ export async function handeSetGoodsDutyParagraph(params: any) {
} }
return data return data
} }
// 导入订单的接口
export async function handeImportOrderBill(params: any) {
const data = await requestEncryption(`/OnlineOrder/ImportOrderBill`, {
method: 'POST',
data: { ...params, requestEncryption: true }
})
if (data.Result_Code !== 100) {
return data
}
return data
}
// 部分退款的同步订单
export async function handeSynchroMemberOrderBill(params: any) {
const data = await requestEncryption(`/OnlineOrder/SynchroMemberOrderBill`, {
method: 'POST',
data: { ...params, requestEncryption: true }
})
if (data.Result_Code !== 100) {
return data
}
return data
}

View File

@ -1,4 +1,4 @@
// 由 scripts/writeVersion.js 自动生成 // 由 scripts/writeVersion.js 自动生成
export const VERSION = "4.5.144"; export const VERSION = "4.5.146";
export const GIT_HASH = "94b60d1"; export const GIT_HASH = "7427b81";
export const BUILD_TIME = "2026-02-06T01:29:10.945Z"; export const BUILD_TIME = "2026-02-12T01:43:51.073Z";