diff --git a/dist.zip b/dist.zip index 28a2741..55849be 100644 Binary files a/dist.zip and b/dist.zip differ diff --git a/package.json b/package.json index fc4d8ed..01474aa 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ant-design-pro", - "version": "4.5.128", + "version": "4.5.131", "private": true, "description": "An out-of-box UI solution for enterprise applications", "scripts": { diff --git a/src/pages/travelMember/BookingMealOrder/components/orderDetailModal.tsx b/src/pages/travelMember/BookingMealOrder/components/orderDetailModal.tsx index a29a0db..158b177 100644 --- a/src/pages/travelMember/BookingMealOrder/components/orderDetailModal.tsx +++ b/src/pages/travelMember/BookingMealOrder/components/orderDetailModal.tsx @@ -787,7 +787,7 @@ const OrderDetailModal = ({ modalVisible, handleCloseModal, currentRow, detailTy }
物流信息 - + { + Number(currentRow?.SALEBILL_STATE) >= 3000 ? '' : + + }
{logisticsList.map((logistics, index) => (
@@ -859,16 +862,19 @@ const OrderDetailModal = ({ modalVisible, handleCloseModal, currentRow, detailTy
- + { + Number(currentRow?.SALEBILL_STATE) >= 3000 ? '' : + + } diff --git a/src/pages/travelMember/MallOrderManage/index.tsx b/src/pages/travelMember/MallOrderManage/index.tsx index 6e6d980..cc90f67 100644 --- a/src/pages/travelMember/MallOrderManage/index.tsx +++ b/src/pages/travelMember/MallOrderManage/index.tsx @@ -137,7 +137,7 @@ const MallOrderManage: React.FC<{ currentUser: CurrentUser, isComponent?: boolea "0": "全部", "3000": "零售商城", "3001": "工会商城", - "3002": "品诺商城", + // "3002": "品诺商城", "3010": "积分商城" }, initialValue: '0', @@ -315,7 +315,7 @@ const MallOrderManage: React.FC<{ currentUser: CurrentUser, isComponent?: boolea valueEnum: { "3000": "零售商城", "3001": "工会商城", - "3002": "品诺商城", + // "3002": "品诺商城", "3010": "积分商城" }, // valueEnum: { @@ -424,40 +424,41 @@ const MallOrderManage: React.FC<{ currentUser: CurrentUser, isComponent?: boolea // } // } // }, - // { - // 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 - // }, - // initialValue: currentUser?.UserPattern === 4000 ? currentUser?.SupplierID : "" - // }, + { + 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 : "" + }, { title: '单位名称', dataIndex: "COMPANY_IDS", @@ -789,15 +790,17 @@ const MallOrderManage: React.FC<{ currentUser: CurrentUser, isComponent?: boolea // 跟交易台账保持一致的 导出Excel const handleGetExportData = async () => { + console.log('searchParams', searchParams); + setGetExportDataLoading(true) const req: any = { ExportType: 1, OwnerUnitId: "911", - CompanyId: searchParams?.CompanyId || "", - MerchantId: currentUser?.SupplierID || "", - SaleBillState: searchParams?.OrderStatus === '0' ? '' : (searchParams?.OrderStatus || ""), - SaleBillType: searchParams?.OrderType === '0' ? '' : (searchParams?.OrderType || ""), - ChannelType: searchParams?.PaymentMethod || "", + CompanyId: searchParams?.COMPANY_IDS || "", + MerchantId: currentUser?.UserPattern === 4000 ? currentUser?.SupplierID : searchParams?.MERCHANTS_IDS || "", + SaleBillState: searchParams?.orderStatus === '0' ? '' : (searchParams?.orderStatus || ""), + SaleBillType: searchParams?.orderType === '0' ? '' : (searchParams?.orderType || ""), + ChannelType: searchParams?.CHANNEL_TYPE === '0' ? '' : searchParams?.CHANNEL_TYPE || "", StartDate: searchParams?.ORDER_DATE_Start || "", EndDate: searchParams?.ORDER_DATE_End || "", // SearchKeyName: "SupplierName,CommodityName,OrderCode", diff --git a/src/pages/travelMember/TradingLedger/index.tsx b/src/pages/travelMember/TradingLedger/index.tsx index a1bf202..ddd99f2 100644 --- a/src/pages/travelMember/TradingLedger/index.tsx +++ b/src/pages/travelMember/TradingLedger/index.tsx @@ -14,7 +14,7 @@ import ProTable from "@ant-design/pro-table"; import ReactHTMLTableToExcel from "react-html-table-to-excel"; import LeftSelectTree from "@/pages/reports/settlementAccount/component/leftSelectTree"; 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 OrderDetailModal from "../BookingMealOrder/components/orderDetailModal"; import { exportXlsxFromProColumnsExcelJS, formatTreeData, handleSetlogSave } from "@/utils/format"; @@ -78,17 +78,6 @@ const TradingLedger: React.FC<{ currentUser: CurrentUser }> = (props) => { 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: '下单时间', 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().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: "序号", dataIndex: "index", @@ -226,6 +307,7 @@ const TradingLedger: React.FC<{ currentUser: CurrentUser }> = (props) => { // "3002": "品诺商城", "3010": "积分商城" }, + hideInSearch: true, initialValue: '0', }, { @@ -305,6 +387,7 @@ const TradingLedger: React.FC<{ currentUser: CurrentUser }> = (props) => { }, align: "center", initialValue: '0', + hideInSearch: true }, // { // dataIndex: 'desc', @@ -575,10 +658,10 @@ const TradingLedger: React.FC<{ currentUser: CurrentUser }> = (props) => { ExportType: type, OwnerUnitId: "911", CompanyId: searchParams?.CompanyId || "", - MerchantId: currentUser?.SupplierID || "", - SaleBillState: searchParams?.OrderStatus === '0' ? '' : (searchParams?.OrderStatus || ""), - SaleBillType: searchParams?.OrderType === '0' ? '' : (searchParams?.OrderType || ""), - ChannelType: searchParams?.PaymentMethod || "", + MerchantId: currentUser?.UserPattern === 4000 ? currentUser?.SupplierID : searchParams?.MERCHANTS_IDS || "", + SaleBillState: searchParams?.orderStatus === '0' ? '' : (searchParams?.orderStatus || ""), + SaleBillType: searchParams?.orderType === '0' ? '' : (searchParams?.orderType || ""), + ChannelType: searchParams?.CHANNEL_TYPE === '0' ? '' : searchParams?.CHANNEL_TYPE || "", StartDate: searchParams?.ORDER_DATE_Start || "", EndDate: searchParams?.ORDER_DATE_End || "", // SearchKeyName: "SupplierName,CommodityName,OrderCode", @@ -695,16 +778,17 @@ const TradingLedger: React.FC<{ currentUser: CurrentUser }> = (props) => { // SearchParameter: { OwnerUnitId: "911", CompanyId: params?.CompanyId || "", - MerchantId: "", + MerchantId: currentUser?.UserPattern === 4000 ? currentUser?.SupplierID : params?.MERCHANTS_IDS || "", SaleBillState: params?.OrderStatus === '0' ? '' : (params?.OrderStatus || ""), SaleBillType: params?.OrderType === '0' ? '' : (params?.OrderType || ""), - ChannelType: params?.PaymentMethod || "", + ChannelType: params?.CHANNEL_TYPE === '0' ? '' : params?.CHANNEL_TYPE || "", StartDate: params?.ORDER_DATE_Start || "", EndDate: params?.ORDER_DATE_End || "", SearchKeyName: "MERCHANTS_NAME,COMMODITY_NAME,SALEBILL_CHILD_CODE,ORDER_PERSON,ORDER_PERSONTEL", SearchKeyValue: params?.searchText || "", SortStr: "" } + console.log('reqreqreq222', req); const data = await handeGetSalebillAccountList(req) setSearchParams(params) setCurrentSearchText(params?.searchText || "") diff --git a/src/utils/exportExcelFun.ts b/src/utils/exportExcelFun.ts index 8521675..224c191 100644 --- a/src/utils/exportExcelFun.ts +++ b/src/utils/exportExcelFun.ts @@ -29,15 +29,33 @@ function flattenTree>( return out; } -/** 抽取 React 节点文本 */ +/** 抽取 React 节点文本(支持换行) */ function extractText(node: any): string { if (node == null || node === false) return ''; - if (typeof node === 'string' || typeof node === 'number') return String(node); - const children = node?.props?.children; - if (Array.isArray(children)) return children.map(extractText).join(''); - if (children != null) return extractText(children); - const html = node?.props?.dangerouslySetInnerHTML?.__html; - if (typeof html === 'string') return html.replace(/<[^>]+>/g, ''); + if (typeof node === 'string' || typeof node === 'number') { + // Excel 内部单元格换行的唯一标准是 \n + return String(node).replace(//gi, '\n').replace(/\r\n/g, '\n'); + } + + // 支持 React 的
节点 + 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(//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 ?? ''); } @@ -143,7 +161,7 @@ function getCellValue(col: AnyCol, record: any, rowIndex: number) { /** 估算列宽(简单) */ const estimateWidth = (v: any) => { 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); }; @@ -196,14 +214,28 @@ export async function exportXlsxFromProColumnsExcelJS( let currentRowIndex = 1; if (topTitle) { const row = ws.getRow(currentRowIndex); - // 写入一个单元格,再合并整行 - row.getCell(1).value = topTitle; - ws.mergeCells(currentRowIndex, 1, currentRowIndex, columnCount); - // 居中 + 加粗 + 较大字号 - const cell = ws.getCell(currentRowIndex, 1); - cell.alignment = { horizontal: 'center', vertical: 'middle' }; - cell.font = { bold: true, size: 14 }; - row.height = 22; + const titleContent = extractText(topTitle); + + // 重要:先执行合并,再分发数据和样式 + ws.mergeCells(currentRowIndex, 1, currentRowIndex, columnCount || 1); + + // 对合并后的 Master Cell 进行赋值和核心样式设置 + const masterCell = ws.getCell(currentRowIndex, 1); + 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; } @@ -231,17 +263,23 @@ export async function exportXlsxFromProColumnsExcelJS( currentRowIndex += 1; } - // 3) 多级表头(全部居中 + 加粗) + // 3) 多级表头(全部居中 + 加粗 + 换行支持) const headerStartRow = currentRowIndex; headerAOA.forEach((r, idx) => { const row = ws.getRow(headerStartRow + idx); + let maxRowLines = 1; r.forEach((v, cIdx) => { + const text = extractText(v); const cell = row.getCell(cIdx + 1); - cell.value = v; - cell.alignment = { horizontal: 'center', vertical: 'middle' }; + cell.value = text; + cell.alignment = { horizontal: 'center', vertical: 'middle', wrapText: 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 => { @@ -257,24 +295,35 @@ export async function exportXlsxFromProColumnsExcelJS( for (let i = 0; i < batch.length; i++) { const rec = batch[i]; const row = ws.getRow(currentRowIndex + i); + let maxRowLines = 1; leafCols.forEach((col, j) => { - // 这里 rowIndex 仍然传全局行号 start + i,序号列会自动正确 - row.getCell(j + 1).value = getCellValue(col, rec, start + i); + const val = 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; - // 5) 列宽:基于表头 + 采样数据估算 + // 5) 列宽与默认样式 const sampleRows = Math.min(batch.length, 200); 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]))); let dataMax = 8; for (let i = 0; i < sampleRows; i++) { const v = leafCols[c - 1] ? getCellValue(leafCols[c - 1], batch[i], start + i) : ''; dataMax = Math.max(dataMax, estimateWidth(v)); } - ws.getColumn(c).width = Math.max(headerMax, dataMax); + wsCol.width = Math.max(headerMax, dataMax); } // 6) 冻结窗格:冻结到(标题 + 信息行 + 表头)这一行的下一行 @@ -290,7 +339,9 @@ export async function exportXlsxFromProColumnsExcelJS( const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; - a.download = `${filename}.xlsx`; + // 清理文件名中的换行符,防止下载异常 + const safeFilename = (filename || '数据导出').replace(/[\r\n]/g, ' '); + a.download = `${safeFilename}.xlsx`; a.click(); URL.revokeObjectURL(url); } \ No newline at end of file diff --git a/src/utils/format.ts b/src/utils/format.ts index 8e4048d..edd167c 100644 --- a/src/utils/format.ts +++ b/src/utils/format.ts @@ -923,15 +923,33 @@ function flattenTree>( return out; } -/** 抽取 React 节点文本 */ +/** 抽取 React 节点文本(支持换行) */ function extractText(node: any): string { if (node == null || node === false) return ''; - if (typeof node === 'string' || typeof node === 'number') return String(node); - const children = node?.props?.children; - if (Array.isArray(children)) return children.map(extractText).join(''); - if (children != null) return extractText(children); - const html = node?.props?.dangerouslySetInnerHTML?.__html; - if (typeof html === 'string') return html.replace(/<[^>]+>/g, ''); + if (typeof node === 'string' || typeof node === 'number') { + // Excel 内部单元格换行的标准是 \n + return String(node).replace(//gi, '\n').replace(/\r\n/g, '\n'); + } + + // 支持 React 的
节点 + 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(//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 ?? ''); } /** 过滤 hideInTable(父级联动) */ @@ -1059,7 +1077,7 @@ function getCellValue(col: AnyCol, record: any, rowIndex: number) { /** 估算列宽(简单) */ const estimateWidth = (v: any) => { 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); }; @@ -1126,12 +1144,27 @@ export async function exportXlsxFromProColumnsExcelJS( // 顶部标题 if (topTitle) { const row = ws.getRow(currentRowIndex); - row.getCell(1).value = topTitle; - ws.mergeCells(currentRowIndex, 1, currentRowIndex, columnCount); - const cell = ws.getCell(currentRowIndex, 1); - cell.alignment = { horizontal: 'center', vertical: 'middle' }; - cell.font = { bold: true, size: 14 }; - row.height = 22; + const titleContent = extractText(topTitle); + + // 重要:先执行合并,再分发数据和样式 + ws.mergeCells(currentRowIndex, 1, currentRowIndex, columnCount || 1); + + // 对合并后的 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; } @@ -1157,17 +1190,23 @@ export async function exportXlsxFromProColumnsExcelJS( currentRowIndex += 1; } - // 表头(保持原有样式与合并) + // 表头(多级支持) const headerStartRow = currentRowIndex; headerAOA.forEach((r, idx) => { const row = ws.getRow(headerStartRow + idx); + let maxRowLines = 1; r.forEach((v, cIdx) => { + const text = extractText(v); const cell = row.getCell(cIdx + 1); - cell.value = v; - cell.alignment = { horizontal: 'center', vertical: 'middle' }; + cell.value = text; + cell.alignment = { horizontal: 'center', vertical: 'middle', wrapText: 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 => { 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++) { const rec = batch[i]; const row = ws.getRow(currentRowIndex + i); + let maxRowLines = 1; leafCols.forEach((col, j) => { const cell = row.getCell(j + 1); - const v = getCellValue(col, rec, start + i); - cell.value = v; - if (col.align) cell.alignment = { horizontal: col.align, vertical: 'middle' }; + const val = getCellValue(col, rec, start + i); + const text = extractText(val); + 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; // 列宽估算 - const sampleRows = Math.min(batch.length, 200); 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]))); 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) : ''; dataMax = Math.max(dataMax, estimateWidth(v)); } - ws.getColumn(c).width = Math.max(headerMax, dataMax); + wsCol.width = Math.max(headerMax, dataMax); } // 注意:不再对 ws.views 进行任何设置(避免冻结表头) diff --git a/src/versionEnv.ts b/src/versionEnv.ts index ac8cc63..8f35c52 100644 --- a/src/versionEnv.ts +++ b/src/versionEnv.ts @@ -1,4 +1,4 @@ // 由 scripts/writeVersion.js 自动生成 -export const VERSION = "4.5.128"; -export const GIT_HASH = "772dc23"; -export const BUILD_TIME = "2026-01-23T11:34:36.109Z"; +export const VERSION = "4.5.131"; +export const GIT_HASH = "83cb30f"; +export const BUILD_TIME = "2026-01-26T10:28:52.569Z";