update
This commit is contained in:
parent
83cb30fc12
commit
63f1b3dc8a
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "ant-design-pro",
|
"name": "ant-design-pro",
|
||||||
"version": "4.5.128",
|
"version": "4.5.131",
|
||||||
"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": {
|
||||||
|
|||||||
@ -787,7 +787,7 @@ const OrderDetailModal = ({ modalVisible, handleCloseModal, currentRow, detailTy
|
|||||||
}
|
}
|
||||||
<Col span={8} className="memberInfoDetailItem">
|
<Col span={8} className="memberInfoDetailItem">
|
||||||
<ProFormText
|
<ProFormText
|
||||||
name={"OrderDesc"}
|
name={"SALEBILL_DESC"}
|
||||||
label={"订单备注"}
|
label={"订单备注"}
|
||||||
readonly
|
readonly
|
||||||
style={{ marginBottom: '16px' }}
|
style={{ marginBottom: '16px' }}
|
||||||
@ -802,15 +802,18 @@ const OrderDetailModal = ({ modalVisible, handleCloseModal, currentRow, detailTy
|
|||||||
<div style={{ marginBottom: '16px' }}>
|
<div style={{ marginBottom: '16px' }}>
|
||||||
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: '12px' }}>
|
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: '12px' }}>
|
||||||
<span style={{ fontWeight: 'bold', fontSize: '14px' }}>物流信息</span>
|
<span style={{ fontWeight: 'bold', fontSize: '14px' }}>物流信息</span>
|
||||||
<Button
|
{
|
||||||
type="dashed"
|
Number(currentRow?.SALEBILL_STATE) >= 3000 ? '' :
|
||||||
icon={<PlusOutlined />}
|
<Button
|
||||||
size="small"
|
type="dashed"
|
||||||
onClick={addLogistics}
|
icon={<PlusOutlined />}
|
||||||
style={{ borderStyle: 'dashed' }}
|
size="small"
|
||||||
>
|
onClick={addLogistics}
|
||||||
添加物流信息
|
style={{ borderStyle: 'dashed' }}
|
||||||
</Button>
|
>
|
||||||
|
添加物流信息
|
||||||
|
</Button>
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
{logisticsList.map((logistics, index) => (
|
{logisticsList.map((logistics, index) => (
|
||||||
<div key={logistics.id} style={{ marginBottom: '12px', padding: '12px', border: '1px solid #d9d9d9', borderRadius: '6px', backgroundColor: '#fafafa' }}>
|
<div key={logistics.id} style={{ marginBottom: '12px', padding: '12px', border: '1px solid #d9d9d9', borderRadius: '6px', backgroundColor: '#fafafa' }}>
|
||||||
@ -859,16 +862,19 @@ const OrderDetailModal = ({ modalVisible, handleCloseModal, currentRow, detailTy
|
|||||||
</div>
|
</div>
|
||||||
</Col>
|
</Col>
|
||||||
<Col span={6}>
|
<Col span={6}>
|
||||||
<Button
|
{
|
||||||
type="text"
|
Number(currentRow?.SALEBILL_STATE) >= 3000 ? '' :
|
||||||
danger
|
<Button
|
||||||
icon={<DeleteOutlined />}
|
type="text"
|
||||||
onClick={() => removeLogistics(logistics.id)}
|
danger
|
||||||
style={{ marginTop: '24px' }}
|
icon={<DeleteOutlined />}
|
||||||
disabled={logisticsList.length === 1}
|
onClick={() => removeLogistics(logistics.id)}
|
||||||
>
|
style={{ marginTop: '24px' }}
|
||||||
删除
|
disabled={logisticsList.length === 1}
|
||||||
</Button>
|
>
|
||||||
|
删除
|
||||||
|
</Button>
|
||||||
|
}
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -137,7 +137,7 @@ const MallOrderManage: React.FC<{ currentUser: CurrentUser, isComponent?: boolea
|
|||||||
"0": "全部",
|
"0": "全部",
|
||||||
"3000": "零售商城",
|
"3000": "零售商城",
|
||||||
"3001": "工会商城",
|
"3001": "工会商城",
|
||||||
"3002": "品诺商城",
|
// "3002": "品诺商城",
|
||||||
"3010": "积分商城"
|
"3010": "积分商城"
|
||||||
},
|
},
|
||||||
initialValue: '0',
|
initialValue: '0',
|
||||||
@ -315,7 +315,7 @@ const MallOrderManage: React.FC<{ currentUser: CurrentUser, isComponent?: boolea
|
|||||||
valueEnum: {
|
valueEnum: {
|
||||||
"3000": "零售商城",
|
"3000": "零售商城",
|
||||||
"3001": "工会商城",
|
"3001": "工会商城",
|
||||||
"3002": "品诺商城",
|
// "3002": "品诺商城",
|
||||||
"3010": "积分商城"
|
"3010": "积分商城"
|
||||||
},
|
},
|
||||||
// valueEnum: {
|
// valueEnum: {
|
||||||
@ -424,40 +424,41 @@ const MallOrderManage: React.FC<{ currentUser: CurrentUser, isComponent?: boolea
|
|||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
// },
|
// },
|
||||||
// {
|
{
|
||||||
// title: '供应商',
|
title: '供应商',
|
||||||
// dataIndex: "MERCHANTS_IDS",
|
dataIndex: "MERCHANTS_IDS",
|
||||||
// valueType: 'select',
|
valueType: 'select',
|
||||||
// request: async () => {
|
request: async () => {
|
||||||
// const req = {
|
const req = {
|
||||||
// searchParameter: {
|
searchParameter: {
|
||||||
// OWNERUNIT_ID: currentUser?.OwnerUnitId,
|
OWNERUNIT_ID: currentUser?.OwnerUnitId,
|
||||||
// PROVINCE_CODE: currentUser?.ProvinceCode,
|
PROVINCE_CODE: currentUser?.ProvinceCode,
|
||||||
// MERCHANTS_TYPE: ""
|
MERCHANTS_TYPE: ""
|
||||||
// },
|
},
|
||||||
// PageIndex: 1,
|
PageIndex: 1,
|
||||||
// PageSize: 999999,
|
PageSize: 999999,
|
||||||
// }
|
}
|
||||||
// const data = await handeGetMERCHANTSList(req);
|
const data = await handeGetMERCHANTSList(req);
|
||||||
// return data.List
|
return data.List
|
||||||
// },
|
},
|
||||||
// hideInTable: true,
|
hideInTable: true,
|
||||||
// fieldProps: {
|
fieldProps: {
|
||||||
// allowClear: true,
|
allowClear: true,
|
||||||
// showSearch: true,
|
showSearch: true,
|
||||||
// filterTreeNode: (input, node) => {
|
filterTreeNode: (input, node) => {
|
||||||
// // ✅ 输入时根据 AUTOTYPE_NAME 模糊匹配
|
// ✅ 输入时根据 AUTOTYPE_NAME 模糊匹配
|
||||||
// return node?.MERCHANTS_NAME?.toLowerCase()?.includes(input.toLowerCase());
|
return node?.MERCHANTS_NAME?.toLowerCase()?.includes(input.toLowerCase());
|
||||||
// },
|
},
|
||||||
// treeDefaultExpandAll: true,
|
treeDefaultExpandAll: true,
|
||||||
// fieldNames: {
|
fieldNames: {
|
||||||
// label: 'MERCHANTS_NAME',
|
label: 'MERCHANTS_NAME',
|
||||||
// value: 'MERCHANTS_ID',
|
value: 'MERCHANTS_ID',
|
||||||
// },
|
},
|
||||||
// disabled: currentUser?.UserPattern === 4000
|
disabled: currentUser?.UserPattern === 4000
|
||||||
// },
|
},
|
||||||
// initialValue: currentUser?.UserPattern === 4000 ? currentUser?.SupplierID : ""
|
hideInSearch: currentUser?.UserPattern === 4000,
|
||||||
// },
|
// initialValue: currentUser?.UserPattern === 4000 ? currentUser?.SupplierID : ""
|
||||||
|
},
|
||||||
{
|
{
|
||||||
title: '单位名称',
|
title: '单位名称',
|
||||||
dataIndex: "COMPANY_IDS",
|
dataIndex: "COMPANY_IDS",
|
||||||
@ -789,15 +790,17 @@ const MallOrderManage: React.FC<{ currentUser: CurrentUser, isComponent?: boolea
|
|||||||
|
|
||||||
// 跟交易台账保持一致的 导出Excel
|
// 跟交易台账保持一致的 导出Excel
|
||||||
const handleGetExportData = async () => {
|
const handleGetExportData = async () => {
|
||||||
|
console.log('searchParams', searchParams);
|
||||||
|
|
||||||
setGetExportDataLoading(true)
|
setGetExportDataLoading(true)
|
||||||
const req: any = {
|
const req: any = {
|
||||||
ExportType: 1,
|
ExportType: 1,
|
||||||
OwnerUnitId: "911",
|
OwnerUnitId: "911",
|
||||||
CompanyId: searchParams?.CompanyId || "",
|
CompanyId: searchParams?.COMPANY_IDS || "",
|
||||||
MerchantId: currentUser?.SupplierID || "",
|
MerchantId: currentUser?.UserPattern === 4000 ? currentUser?.SupplierID : searchParams?.MERCHANTS_IDS || "",
|
||||||
SaleBillState: searchParams?.OrderStatus === '0' ? '' : (searchParams?.OrderStatus || ""),
|
SaleBillState: searchParams?.orderStatus === '0' ? '' : (searchParams?.orderStatus || ""),
|
||||||
SaleBillType: searchParams?.OrderType === '0' ? '' : (searchParams?.OrderType || ""),
|
SaleBillType: searchParams?.orderType === '0' ? '' : (searchParams?.orderType || ""),
|
||||||
ChannelType: searchParams?.PaymentMethod || "",
|
ChannelType: searchParams?.CHANNEL_TYPE === '0' ? '' : searchParams?.CHANNEL_TYPE || "",
|
||||||
StartDate: searchParams?.ORDER_DATE_Start || "",
|
StartDate: searchParams?.ORDER_DATE_Start || "",
|
||||||
EndDate: searchParams?.ORDER_DATE_End || "",
|
EndDate: searchParams?.ORDER_DATE_End || "",
|
||||||
// SearchKeyName: "SupplierName,CommodityName,OrderCode",
|
// SearchKeyName: "SupplierName,CommodityName,OrderCode",
|
||||||
|
|||||||
@ -14,7 +14,7 @@ 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, handeGetOnlineBillAccountList, handeGetSalebillAccountList, handeGetSupplierSaleBillList } from "../service";
|
import { handeGetCOMPANYList, handeGetMERCHANTSList, handeGetOnlineBillAccountList, handeGetSalebillAccountList, handeGetSupplierSaleBillList } 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";
|
||||||
@ -78,17 +78,6 @@ const TradingLedger: React.FC<{ currentUser: CurrentUser }> = (props) => {
|
|||||||
placeholder: "请输入供货商/购买的商品/订单编号/会员名称/电话号码"
|
placeholder: "请输入供货商/购买的商品/订单编号/会员名称/电话号码"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
|
||||||
dataIndex: "CompanyId",
|
|
||||||
title: "所属单位",
|
|
||||||
hideInTable: true,
|
|
||||||
valueType: 'select',
|
|
||||||
fieldProps: {
|
|
||||||
showSearch: true,
|
|
||||||
options: companyList,
|
|
||||||
filterOption: (input: any, option: any) => (option?.label ?? '').toLowerCase().includes(input.toLowerCase()),
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
title: '下单时间',
|
title: '下单时间',
|
||||||
dataIndex: 'search_date',
|
dataIndex: 'search_date',
|
||||||
@ -114,6 +103,98 @@ const TradingLedger: React.FC<{ currentUser: CurrentUser }> = (props) => {
|
|||||||
// initialValue: [moment().subtract(1, 'M').format('YYYY-MM-DD'), moment().format('YYYY-MM-DD')],
|
// initialValue: [moment().subtract(1, 'M').format('YYYY-MM-DD'), moment().format('YYYY-MM-DD')],
|
||||||
initialValue: [moment().startOf('M'), moment()],
|
initialValue: [moment().startOf('M'), moment()],
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
title: "订单状态",
|
||||||
|
dataIndex: "OrderStatus",
|
||||||
|
valueType: "select",
|
||||||
|
valueEnum: {
|
||||||
|
"0": "全部",
|
||||||
|
"1005": "订单待支付",
|
||||||
|
"1010": "订单待发货",
|
||||||
|
"2010": "订单已发货",
|
||||||
|
"3000": "订单已完成",
|
||||||
|
"8000": "退款申请中",
|
||||||
|
"8900": "订单已退款",
|
||||||
|
"9000": "订单已关闭",
|
||||||
|
"9999": "订单已撤销"
|
||||||
|
},
|
||||||
|
initialValue: '0',
|
||||||
|
hideInTable: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "订单类型",
|
||||||
|
dataIndex: "OrderType",
|
||||||
|
valueType: "select",
|
||||||
|
valueEnum: {
|
||||||
|
"0": "全部",
|
||||||
|
"3000": "零售商城",
|
||||||
|
"3001": "工会商城",
|
||||||
|
// "3002": "品诺商城",
|
||||||
|
"3010": "积分商城"
|
||||||
|
},
|
||||||
|
initialValue: '0',
|
||||||
|
hideInTable: true,
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
title: "支付方式",
|
||||||
|
dataIndex: "CHANNEL_TYPE",
|
||||||
|
valueType: "select",
|
||||||
|
valueEnum: {
|
||||||
|
"0": "全部",
|
||||||
|
"工会余额": "工会余额",
|
||||||
|
"组合支付": "组合支付",
|
||||||
|
"微信": "微信"
|
||||||
|
},
|
||||||
|
initialValue: '0',
|
||||||
|
hideInTable: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '供应商',
|
||||||
|
dataIndex: "MERCHANTS_IDS",
|
||||||
|
valueType: 'select',
|
||||||
|
request: async () => {
|
||||||
|
const req = {
|
||||||
|
searchParameter: {
|
||||||
|
OWNERUNIT_ID: currentUser?.OwnerUnitId,
|
||||||
|
PROVINCE_CODE: currentUser?.ProvinceCode,
|
||||||
|
MERCHANTS_TYPE: ""
|
||||||
|
},
|
||||||
|
PageIndex: 1,
|
||||||
|
PageSize: 999999,
|
||||||
|
}
|
||||||
|
const data = await handeGetMERCHANTSList(req);
|
||||||
|
return data.List
|
||||||
|
},
|
||||||
|
hideInTable: true,
|
||||||
|
fieldProps: {
|
||||||
|
allowClear: true,
|
||||||
|
showSearch: true,
|
||||||
|
filterTreeNode: (input, node) => {
|
||||||
|
// ✅ 输入时根据 AUTOTYPE_NAME 模糊匹配
|
||||||
|
return node?.MERCHANTS_NAME?.toLowerCase()?.includes(input.toLowerCase());
|
||||||
|
},
|
||||||
|
treeDefaultExpandAll: true,
|
||||||
|
fieldNames: {
|
||||||
|
label: 'MERCHANTS_NAME',
|
||||||
|
value: 'MERCHANTS_ID',
|
||||||
|
},
|
||||||
|
disabled: currentUser?.UserPattern === 4000
|
||||||
|
},
|
||||||
|
hideInSearch: currentUser?.UserPattern === 4000,
|
||||||
|
// initialValue: currentUser?.UserPattern === 4000 ? currentUser?.SupplierID : ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
dataIndex: "CompanyId",
|
||||||
|
title: "所属单位",
|
||||||
|
hideInTable: true,
|
||||||
|
valueType: 'select',
|
||||||
|
fieldProps: {
|
||||||
|
showSearch: true,
|
||||||
|
options: companyList,
|
||||||
|
filterOption: (input: any, option: any) => (option?.label ?? '').toLowerCase().includes(input.toLowerCase()),
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
title: "序号",
|
title: "序号",
|
||||||
dataIndex: "index",
|
dataIndex: "index",
|
||||||
@ -226,6 +307,7 @@ const TradingLedger: React.FC<{ currentUser: CurrentUser }> = (props) => {
|
|||||||
// "3002": "品诺商城",
|
// "3002": "品诺商城",
|
||||||
"3010": "积分商城"
|
"3010": "积分商城"
|
||||||
},
|
},
|
||||||
|
hideInSearch: true,
|
||||||
initialValue: '0',
|
initialValue: '0',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -305,6 +387,7 @@ const TradingLedger: React.FC<{ currentUser: CurrentUser }> = (props) => {
|
|||||||
},
|
},
|
||||||
align: "center",
|
align: "center",
|
||||||
initialValue: '0',
|
initialValue: '0',
|
||||||
|
hideInSearch: true
|
||||||
},
|
},
|
||||||
// {
|
// {
|
||||||
// dataIndex: 'desc',
|
// dataIndex: 'desc',
|
||||||
@ -575,10 +658,10 @@ const TradingLedger: React.FC<{ currentUser: CurrentUser }> = (props) => {
|
|||||||
ExportType: type,
|
ExportType: type,
|
||||||
OwnerUnitId: "911",
|
OwnerUnitId: "911",
|
||||||
CompanyId: searchParams?.CompanyId || "",
|
CompanyId: searchParams?.CompanyId || "",
|
||||||
MerchantId: currentUser?.SupplierID || "",
|
MerchantId: currentUser?.UserPattern === 4000 ? currentUser?.SupplierID : searchParams?.MERCHANTS_IDS || "",
|
||||||
SaleBillState: searchParams?.OrderStatus === '0' ? '' : (searchParams?.OrderStatus || ""),
|
SaleBillState: searchParams?.orderStatus === '0' ? '' : (searchParams?.orderStatus || ""),
|
||||||
SaleBillType: searchParams?.OrderType === '0' ? '' : (searchParams?.OrderType || ""),
|
SaleBillType: searchParams?.orderType === '0' ? '' : (searchParams?.orderType || ""),
|
||||||
ChannelType: searchParams?.PaymentMethod || "",
|
ChannelType: searchParams?.CHANNEL_TYPE === '0' ? '' : searchParams?.CHANNEL_TYPE || "",
|
||||||
StartDate: searchParams?.ORDER_DATE_Start || "",
|
StartDate: searchParams?.ORDER_DATE_Start || "",
|
||||||
EndDate: searchParams?.ORDER_DATE_End || "",
|
EndDate: searchParams?.ORDER_DATE_End || "",
|
||||||
// SearchKeyName: "SupplierName,CommodityName,OrderCode",
|
// SearchKeyName: "SupplierName,CommodityName,OrderCode",
|
||||||
@ -695,16 +778,17 @@ const TradingLedger: React.FC<{ currentUser: CurrentUser }> = (props) => {
|
|||||||
// SearchParameter: {
|
// SearchParameter: {
|
||||||
OwnerUnitId: "911",
|
OwnerUnitId: "911",
|
||||||
CompanyId: params?.CompanyId || "",
|
CompanyId: params?.CompanyId || "",
|
||||||
MerchantId: "",
|
MerchantId: currentUser?.UserPattern === 4000 ? currentUser?.SupplierID : params?.MERCHANTS_IDS || "",
|
||||||
SaleBillState: params?.OrderStatus === '0' ? '' : (params?.OrderStatus || ""),
|
SaleBillState: params?.OrderStatus === '0' ? '' : (params?.OrderStatus || ""),
|
||||||
SaleBillType: params?.OrderType === '0' ? '' : (params?.OrderType || ""),
|
SaleBillType: params?.OrderType === '0' ? '' : (params?.OrderType || ""),
|
||||||
ChannelType: params?.PaymentMethod || "",
|
ChannelType: params?.CHANNEL_TYPE === '0' ? '' : params?.CHANNEL_TYPE || "",
|
||||||
StartDate: params?.ORDER_DATE_Start || "",
|
StartDate: params?.ORDER_DATE_Start || "",
|
||||||
EndDate: params?.ORDER_DATE_End || "",
|
EndDate: params?.ORDER_DATE_End || "",
|
||||||
SearchKeyName: "MERCHANTS_NAME,COMMODITY_NAME,SALEBILL_CHILD_CODE,ORDER_PERSON,ORDER_PERSONTEL",
|
SearchKeyName: "MERCHANTS_NAME,COMMODITY_NAME,SALEBILL_CHILD_CODE,ORDER_PERSON,ORDER_PERSONTEL",
|
||||||
SearchKeyValue: params?.searchText || "",
|
SearchKeyValue: params?.searchText || "",
|
||||||
SortStr: ""
|
SortStr: ""
|
||||||
}
|
}
|
||||||
|
console.log('reqreqreq222', req);
|
||||||
const data = await handeGetSalebillAccountList(req)
|
const data = await handeGetSalebillAccountList(req)
|
||||||
setSearchParams(params)
|
setSearchParams(params)
|
||||||
setCurrentSearchText(params?.searchText || "")
|
setCurrentSearchText(params?.searchText || "")
|
||||||
|
|||||||
@ -29,15 +29,33 @@ function flattenTree<T extends Record<string, any>>(
|
|||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 抽取 React 节点文本 */
|
/** 抽取 React 节点文本(支持换行) */
|
||||||
function extractText(node: any): string {
|
function extractText(node: any): string {
|
||||||
if (node == null || node === false) return '';
|
if (node == null || node === false) return '';
|
||||||
if (typeof node === 'string' || typeof node === 'number') return String(node);
|
if (typeof node === 'string' || typeof node === 'number') {
|
||||||
const children = node?.props?.children;
|
// Excel 内部单元格换行的唯一标准是 \n
|
||||||
if (Array.isArray(children)) return children.map(extractText).join('');
|
return String(node).replace(/<br\s*\/?>/gi, '\n').replace(/\r\n/g, '\n');
|
||||||
if (children != null) return extractText(children);
|
}
|
||||||
const html = node?.props?.dangerouslySetInnerHTML?.__html;
|
|
||||||
if (typeof html === 'string') return html.replace(/<[^>]+>/g, '');
|
// 支持 React 的 <br/> 节点
|
||||||
|
if (node?.type === 'br') return '\n';
|
||||||
|
|
||||||
|
const props = node?.props;
|
||||||
|
if (props) {
|
||||||
|
// 渲染 dangerouslySetInnerHTML
|
||||||
|
const html = props?.dangerouslySetInnerHTML?.__html;
|
||||||
|
if (typeof html === 'string') {
|
||||||
|
return html
|
||||||
|
.replace(/<br\s*\/?>/gi, '\n')
|
||||||
|
.replace(/<[^>]+>/g, '')
|
||||||
|
.replace(/ /g, ' ');
|
||||||
|
}
|
||||||
|
// 递归渲染 children
|
||||||
|
const children = props?.children;
|
||||||
|
if (Array.isArray(children)) return children.map(extractText).join('');
|
||||||
|
if (children != null) return extractText(children);
|
||||||
|
}
|
||||||
|
|
||||||
return String(node ?? '');
|
return String(node ?? '');
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -143,7 +161,7 @@ function getCellValue(col: AnyCol, record: any, rowIndex: number) {
|
|||||||
/** 估算列宽(简单) */
|
/** 估算列宽(简单) */
|
||||||
const estimateWidth = (v: any) => {
|
const estimateWidth = (v: any) => {
|
||||||
const s = (v ?? '').toString();
|
const s = (v ?? '').toString();
|
||||||
const len = Array.from(s).reduce((n, ch) => n + (/[^\x00-\xff]/.test(ch) ? 2 : 1), 0);
|
const len = Array.from(s).reduce((n: number, ch: any) => n + (/[^\x00-\xff]/.test(ch) ? 2 : 1), 0);
|
||||||
return Math.min(Math.max(len + 2, 8), 60);
|
return Math.min(Math.max(len + 2, 8), 60);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -196,14 +214,28 @@ export async function exportXlsxFromProColumnsExcelJS(
|
|||||||
let currentRowIndex = 1;
|
let currentRowIndex = 1;
|
||||||
if (topTitle) {
|
if (topTitle) {
|
||||||
const row = ws.getRow(currentRowIndex);
|
const row = ws.getRow(currentRowIndex);
|
||||||
// 写入一个单元格,再合并整行
|
const titleContent = extractText(topTitle);
|
||||||
row.getCell(1).value = topTitle;
|
|
||||||
ws.mergeCells(currentRowIndex, 1, currentRowIndex, columnCount);
|
// 重要:先执行合并,再分发数据和样式
|
||||||
// 居中 + 加粗 + 较大字号
|
ws.mergeCells(currentRowIndex, 1, currentRowIndex, columnCount || 1);
|
||||||
const cell = ws.getCell(currentRowIndex, 1);
|
|
||||||
cell.alignment = { horizontal: 'center', vertical: 'middle' };
|
// 对合并后的 Master Cell 进行赋值和核心样式设置
|
||||||
cell.font = { bold: true, size: 14 };
|
const masterCell = ws.getCell(currentRowIndex, 1);
|
||||||
row.height = 22;
|
masterCell.value = titleContent;
|
||||||
|
masterCell.font = { bold: true, size: 14, name: 'Microsoft YaHei' };
|
||||||
|
|
||||||
|
// 重要:由于合并单元格会共享样式,直接对 Row 应用对齐是最稳妥的
|
||||||
|
row.alignment = { horizontal: 'center', vertical: 'middle', wrapText: true };
|
||||||
|
|
||||||
|
// 双重加固:对合并范围内的所有单元格显式设置 wrapText (解决某些版本只看 Master Cell 却失效的问题)
|
||||||
|
for (let i = 1; i <= (columnCount || 1); i++) {
|
||||||
|
row.getCell(i).alignment = { horizontal: 'center', vertical: 'middle', wrapText: true };
|
||||||
|
}
|
||||||
|
|
||||||
|
// 动态行高计算(关键:确保换行后的内容不被遮盖)
|
||||||
|
const lines = titleContent.split('\n').length;
|
||||||
|
row.height = Math.max(lines * 32, 40);
|
||||||
|
|
||||||
currentRowIndex += 1;
|
currentRowIndex += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -231,17 +263,23 @@ export async function exportXlsxFromProColumnsExcelJS(
|
|||||||
currentRowIndex += 1;
|
currentRowIndex += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3) 多级表头(全部居中 + 加粗)
|
// 3) 多级表头(全部居中 + 加粗 + 换行支持)
|
||||||
const headerStartRow = currentRowIndex;
|
const headerStartRow = currentRowIndex;
|
||||||
headerAOA.forEach((r, idx) => {
|
headerAOA.forEach((r, idx) => {
|
||||||
const row = ws.getRow(headerStartRow + idx);
|
const row = ws.getRow(headerStartRow + idx);
|
||||||
|
let maxRowLines = 1;
|
||||||
r.forEach((v, cIdx) => {
|
r.forEach((v, cIdx) => {
|
||||||
|
const text = extractText(v);
|
||||||
const cell = row.getCell(cIdx + 1);
|
const cell = row.getCell(cIdx + 1);
|
||||||
cell.value = v;
|
cell.value = text;
|
||||||
cell.alignment = { horizontal: 'center', vertical: 'middle' };
|
cell.alignment = { horizontal: 'center', vertical: 'middle', wrapText: true };
|
||||||
cell.font = { bold: true };
|
cell.font = { bold: true };
|
||||||
|
|
||||||
|
const lines = text.split('\n').length;
|
||||||
|
if (lines > maxRowLines) maxRowLines = lines;
|
||||||
});
|
});
|
||||||
row.height = 18;
|
row.alignment = { horizontal: 'center', vertical: 'middle', wrapText: true };
|
||||||
|
row.height = Math.max(22, maxRowLines * 20);
|
||||||
});
|
});
|
||||||
// 应用表头合并
|
// 应用表头合并
|
||||||
merges.forEach(m => {
|
merges.forEach(m => {
|
||||||
@ -257,24 +295,35 @@ export async function exportXlsxFromProColumnsExcelJS(
|
|||||||
for (let i = 0; i < batch.length; i++) {
|
for (let i = 0; i < batch.length; i++) {
|
||||||
const rec = batch[i];
|
const rec = batch[i];
|
||||||
const row = ws.getRow(currentRowIndex + i);
|
const row = ws.getRow(currentRowIndex + i);
|
||||||
|
let maxRowLines = 1;
|
||||||
leafCols.forEach((col, j) => {
|
leafCols.forEach((col, j) => {
|
||||||
// 这里 rowIndex 仍然传全局行号 start + i,序号列会自动正确
|
const val = getCellValue(col, rec, start + i);
|
||||||
row.getCell(j + 1).value = getCellValue(col, rec, start + i);
|
const text = extractText(val);
|
||||||
|
const cell = row.getCell(j + 1);
|
||||||
|
cell.value = text;
|
||||||
|
cell.alignment = { vertical: 'middle', wrapText: true };
|
||||||
|
|
||||||
|
const lines = text.split('\n').length;
|
||||||
|
if (lines > maxRowLines) maxRowLines = lines;
|
||||||
});
|
});
|
||||||
// 适度让出主线程:ExcelJS 是纯 JS,通常也很稳;如需进一步优化可用 setTimeout 分批
|
row.height = Math.max(18, maxRowLines * 16);
|
||||||
}
|
}
|
||||||
currentRowIndex += batch.length;
|
currentRowIndex += batch.length;
|
||||||
|
|
||||||
// 5) 列宽:基于表头 + 采样数据估算
|
// 5) 列宽与默认样式
|
||||||
const sampleRows = Math.min(batch.length, 200);
|
const sampleRows = Math.min(batch.length, 200);
|
||||||
for (let c = 1; c <= columnCount; c++) {
|
for (let c = 1; c <= columnCount; c++) {
|
||||||
|
const wsCol = ws.getColumn(c);
|
||||||
|
// 默认开启换行
|
||||||
|
wsCol.alignment = { vertical: 'middle', wrapText: true };
|
||||||
|
|
||||||
const headerMax = Math.max(...headerAOA.map(r => estimateWidth(r[c - 1])));
|
const headerMax = Math.max(...headerAOA.map(r => estimateWidth(r[c - 1])));
|
||||||
let dataMax = 8;
|
let dataMax = 8;
|
||||||
for (let i = 0; i < sampleRows; i++) {
|
for (let i = 0; i < sampleRows; i++) {
|
||||||
const v = leafCols[c - 1] ? getCellValue(leafCols[c - 1], batch[i], start + i) : '';
|
const v = leafCols[c - 1] ? getCellValue(leafCols[c - 1], batch[i], start + i) : '';
|
||||||
dataMax = Math.max(dataMax, estimateWidth(v));
|
dataMax = Math.max(dataMax, estimateWidth(v));
|
||||||
}
|
}
|
||||||
ws.getColumn(c).width = Math.max(headerMax, dataMax);
|
wsCol.width = Math.max(headerMax, dataMax);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 6) 冻结窗格:冻结到(标题 + 信息行 + 表头)这一行的下一行
|
// 6) 冻结窗格:冻结到(标题 + 信息行 + 表头)这一行的下一行
|
||||||
@ -290,7 +339,9 @@ export async function exportXlsxFromProColumnsExcelJS(
|
|||||||
const url = URL.createObjectURL(blob);
|
const url = URL.createObjectURL(blob);
|
||||||
const a = document.createElement('a');
|
const a = document.createElement('a');
|
||||||
a.href = url;
|
a.href = url;
|
||||||
a.download = `${filename}.xlsx`;
|
// 清理文件名中的换行符,防止下载异常
|
||||||
|
const safeFilename = (filename || '数据导出').replace(/[\r\n]/g, ' ');
|
||||||
|
a.download = `${safeFilename}.xlsx`;
|
||||||
a.click();
|
a.click();
|
||||||
URL.revokeObjectURL(url);
|
URL.revokeObjectURL(url);
|
||||||
}
|
}
|
||||||
@ -923,15 +923,33 @@ function flattenTree<T extends Record<string, any>>(
|
|||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 抽取 React 节点文本 */
|
/** 抽取 React 节点文本(支持换行) */
|
||||||
function extractText(node: any): string {
|
function extractText(node: any): string {
|
||||||
if (node == null || node === false) return '';
|
if (node == null || node === false) return '';
|
||||||
if (typeof node === 'string' || typeof node === 'number') return String(node);
|
if (typeof node === 'string' || typeof node === 'number') {
|
||||||
const children = node?.props?.children;
|
// Excel 内部单元格换行的标准是 \n
|
||||||
if (Array.isArray(children)) return children.map(extractText).join('');
|
return String(node).replace(/<br\s*\/?>/gi, '\n').replace(/\r\n/g, '\n');
|
||||||
if (children != null) return extractText(children);
|
}
|
||||||
const html = node?.props?.dangerouslySetInnerHTML?.__html;
|
|
||||||
if (typeof html === 'string') return html.replace(/<[^>]+>/g, '');
|
// 支持 React 的 <br/> 节点
|
||||||
|
if (node?.type === 'br') return '\n';
|
||||||
|
|
||||||
|
const props = node?.props;
|
||||||
|
if (props) {
|
||||||
|
// 渲染 dangerouslySetInnerHTML
|
||||||
|
const html = props?.dangerouslySetInnerHTML?.__html;
|
||||||
|
if (typeof html === 'string') {
|
||||||
|
return html
|
||||||
|
.replace(/<br\s*\/?>/gi, '\n')
|
||||||
|
.replace(/<[^>]+>/g, '')
|
||||||
|
.replace(/ /g, ' ');
|
||||||
|
}
|
||||||
|
// 递归渲染 children
|
||||||
|
const children = props?.children;
|
||||||
|
if (Array.isArray(children)) return children.map(extractText).join('');
|
||||||
|
if (children != null) return extractText(children);
|
||||||
|
}
|
||||||
|
|
||||||
return String(node ?? '');
|
return String(node ?? '');
|
||||||
}
|
}
|
||||||
/** 过滤 hideInTable(父级联动) */
|
/** 过滤 hideInTable(父级联动) */
|
||||||
@ -1059,7 +1077,7 @@ function getCellValue(col: AnyCol, record: any, rowIndex: number) {
|
|||||||
/** 估算列宽(简单) */
|
/** 估算列宽(简单) */
|
||||||
const estimateWidth = (v: any) => {
|
const estimateWidth = (v: any) => {
|
||||||
const s = (v ?? '').toString();
|
const s = (v ?? '').toString();
|
||||||
const len = Array.from(s).reduce((n, ch) => n + (/[^\x00-\xff]/.test(ch) ? 2 : 1), 0);
|
const len = Array.from(s).reduce((n: number, ch: any) => n + (/[^\x00-\xff]/.test(ch) ? 2 : 1), 0);
|
||||||
return Math.min(Math.max(len + 2, 8), 60);
|
return Math.min(Math.max(len + 2, 8), 60);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1126,12 +1144,27 @@ export async function exportXlsxFromProColumnsExcelJS(
|
|||||||
// 顶部标题
|
// 顶部标题
|
||||||
if (topTitle) {
|
if (topTitle) {
|
||||||
const row = ws.getRow(currentRowIndex);
|
const row = ws.getRow(currentRowIndex);
|
||||||
row.getCell(1).value = topTitle;
|
const titleContent = extractText(topTitle);
|
||||||
ws.mergeCells(currentRowIndex, 1, currentRowIndex, columnCount);
|
|
||||||
const cell = ws.getCell(currentRowIndex, 1);
|
// 重要:先执行合并,再分发数据和样式
|
||||||
cell.alignment = { horizontal: 'center', vertical: 'middle' };
|
ws.mergeCells(currentRowIndex, 1, currentRowIndex, columnCount || 1);
|
||||||
cell.font = { bold: true, size: 14 };
|
|
||||||
row.height = 22;
|
// 对合并后的 Master Cell 进行赋值和核心样式设置
|
||||||
|
const masterCell = ws.getCell(currentRowIndex, 1);
|
||||||
|
masterCell.value = titleContent;
|
||||||
|
// 字体正常,不加粗
|
||||||
|
masterCell.font = { size: 14, name: 'Microsoft YaHei' };
|
||||||
|
|
||||||
|
// 强制对主单元格设置居中和换行
|
||||||
|
masterCell.alignment = { horizontal: 'center', vertical: 'middle', wrapText: true };
|
||||||
|
|
||||||
|
// 强制整行设置换行对齐属性作为辅助
|
||||||
|
row.alignment = { horizontal: 'center', vertical: 'middle', wrapText: true };
|
||||||
|
|
||||||
|
// 计算行高 (基准 32 保证显示完整)
|
||||||
|
const lines = titleContent.split('\n').length;
|
||||||
|
row.height = Math.max(lines * 32, 40);
|
||||||
|
|
||||||
currentRowIndex += 1;
|
currentRowIndex += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1157,17 +1190,23 @@ export async function exportXlsxFromProColumnsExcelJS(
|
|||||||
currentRowIndex += 1;
|
currentRowIndex += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 表头(保持原有样式与合并)
|
// 表头(多级支持)
|
||||||
const headerStartRow = currentRowIndex;
|
const headerStartRow = currentRowIndex;
|
||||||
headerAOA.forEach((r, idx) => {
|
headerAOA.forEach((r, idx) => {
|
||||||
const row = ws.getRow(headerStartRow + idx);
|
const row = ws.getRow(headerStartRow + idx);
|
||||||
|
let maxRowLines = 1;
|
||||||
r.forEach((v, cIdx) => {
|
r.forEach((v, cIdx) => {
|
||||||
|
const text = extractText(v);
|
||||||
const cell = row.getCell(cIdx + 1);
|
const cell = row.getCell(cIdx + 1);
|
||||||
cell.value = v;
|
cell.value = text;
|
||||||
cell.alignment = { horizontal: 'center', vertical: 'middle' };
|
cell.alignment = { horizontal: 'center', vertical: 'middle', wrapText: true };
|
||||||
cell.font = { bold: true };
|
cell.font = { bold: true };
|
||||||
|
|
||||||
|
const lines = text.split('\n').length;
|
||||||
|
if (lines > maxRowLines) maxRowLines = lines;
|
||||||
});
|
});
|
||||||
row.height = 18;
|
row.alignment = { horizontal: 'center', vertical: 'middle', wrapText: true };
|
||||||
|
row.height = Math.max(22, maxRowLines * 18);
|
||||||
});
|
});
|
||||||
merges.forEach(m => {
|
merges.forEach(m => {
|
||||||
ws.mergeCells(headerStartRow + (m.r1 - 1), m.c1, headerStartRow + (m.r2 - 1), m.c2);
|
ws.mergeCells(headerStartRow + (m.r1 - 1), m.c1, headerStartRow + (m.r2 - 1), m.c2);
|
||||||
@ -1182,25 +1221,38 @@ export async function exportXlsxFromProColumnsExcelJS(
|
|||||||
for (let i = 0; i < batch.length; i++) {
|
for (let i = 0; i < batch.length; i++) {
|
||||||
const rec = batch[i];
|
const rec = batch[i];
|
||||||
const row = ws.getRow(currentRowIndex + i);
|
const row = ws.getRow(currentRowIndex + i);
|
||||||
|
let maxRowLines = 1;
|
||||||
leafCols.forEach((col, j) => {
|
leafCols.forEach((col, j) => {
|
||||||
const cell = row.getCell(j + 1);
|
const cell = row.getCell(j + 1);
|
||||||
const v = getCellValue(col, rec, start + i);
|
const val = getCellValue(col, rec, start + i);
|
||||||
cell.value = v;
|
const text = extractText(val);
|
||||||
if (col.align) cell.alignment = { horizontal: col.align, vertical: 'middle' };
|
cell.value = text;
|
||||||
|
|
||||||
|
const alignment: any = { vertical: 'middle', wrapText: true };
|
||||||
|
if (col.align) alignment.horizontal = col.align;
|
||||||
|
cell.alignment = alignment;
|
||||||
|
|
||||||
|
const lines = text.split('\n').length;
|
||||||
|
if (lines > maxRowLines) maxRowLines = lines;
|
||||||
});
|
});
|
||||||
|
row.height = Math.max(18, maxRowLines * 16);
|
||||||
}
|
}
|
||||||
currentRowIndex += batch.length;
|
currentRowIndex += batch.length;
|
||||||
|
|
||||||
// 列宽估算
|
// 列宽估算
|
||||||
const sampleRows = Math.min(batch.length, 200);
|
|
||||||
for (let c = 1; c <= columnCount; c++) {
|
for (let c = 1; c <= columnCount; c++) {
|
||||||
|
const wsCol = ws.getColumn(c);
|
||||||
|
// 注意:不再此处设置 wsCol.alignment,防止覆盖标题和表头的水平居中样式
|
||||||
|
// 对齐已在数据行渲染阶段(Step 4)按列配置精准应用
|
||||||
|
|
||||||
const headerMax = Math.max(...headerAOA.map(r => estimateWidth(r[c - 1])));
|
const headerMax = Math.max(...headerAOA.map(r => estimateWidth(r[c - 1])));
|
||||||
let dataMax = 8;
|
let dataMax = 8;
|
||||||
for (let i = 0; i < sampleRows; i++) {
|
const sampleRowsLimit = Math.min(batch.length, 100);
|
||||||
|
for (let i = 0; i < sampleRowsLimit; i++) {
|
||||||
const v = leafCols[c - 1] ? getCellValue(leafCols[c - 1], batch[i], start + i) : '';
|
const v = leafCols[c - 1] ? getCellValue(leafCols[c - 1], batch[i], start + i) : '';
|
||||||
dataMax = Math.max(dataMax, estimateWidth(v));
|
dataMax = Math.max(dataMax, estimateWidth(v));
|
||||||
}
|
}
|
||||||
ws.getColumn(c).width = Math.max(headerMax, dataMax);
|
wsCol.width = Math.max(headerMax, dataMax);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 注意:不再对 ws.views 进行任何设置(避免冻结表头)
|
// 注意:不再对 ws.views 进行任何设置(避免冻结表头)
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
// 由 scripts/writeVersion.js 自动生成
|
// 由 scripts/writeVersion.js 自动生成
|
||||||
export const VERSION = "4.5.128";
|
export const VERSION = "4.5.131";
|
||||||
export const GIT_HASH = "772dc23";
|
export const GIT_HASH = "83cb30f";
|
||||||
export const BUILD_TIME = "2026-01-23T11:34:36.109Z";
|
export const BUILD_TIME = "2026-01-26T10:28:52.569Z";
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user