feat(wms): 添加钢卷报表导出功能的多行合并选项
- 在异常报表页面添加导出产出钢卷(多行合并)和导出消耗钢卷(多行合并)菜单项 - 新增 mergeCoilCells 工具函数实现 Excel 单元格合并功能 - 实现 exportWithMerge 通用方法处理带合并的 Excel 导出 - 添加导出时的加载提示和错误处理机制 - 优化 MES 质检样本详情加载逻辑,移除不必要的异步请求
This commit is contained in:
@@ -344,9 +344,8 @@ export default {
|
|||||||
|
|
||||||
loadMainDetails() {
|
loadMainDetails() {
|
||||||
if (this.mainList.length === 0) return
|
if (this.mainList.length === 0) return
|
||||||
const promises = this.mainList.map(main => {
|
this.mainList.forEach(main => {
|
||||||
return listInspectionDetail({ mainId: main.mainId, pageNum: 1, pageSize: 9999 }).then(response => {
|
const details = main.detailList || []
|
||||||
const details = response.rows || []
|
|
||||||
details.forEach(detail => {
|
details.forEach(detail => {
|
||||||
if (main._items[detail.itemName]) {
|
if (main._items[detail.itemName]) {
|
||||||
main._items[detail.itemName] = {
|
main._items[detail.itemName] = {
|
||||||
@@ -362,9 +361,7 @@ export default {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
main._originalItems = JSON.parse(JSON.stringify(main._items))
|
main._originalItems = JSON.parse(JSON.stringify(main._items))
|
||||||
}).catch(() => {})
|
|
||||||
})
|
})
|
||||||
return Promise.all(promises)
|
|
||||||
},
|
},
|
||||||
|
|
||||||
handleAddMain() {
|
handleAddMain() {
|
||||||
|
|||||||
@@ -58,6 +58,8 @@
|
|||||||
|
|
||||||
<el-dropdown-item command="exportDataMore">导出产出钢卷(多行)</el-dropdown-item>
|
<el-dropdown-item command="exportDataMore">导出产出钢卷(多行)</el-dropdown-item>
|
||||||
<el-dropdown-item command="exportLossDataMore">导出消耗钢卷(多行)</el-dropdown-item>
|
<el-dropdown-item command="exportLossDataMore">导出消耗钢卷(多行)</el-dropdown-item>
|
||||||
|
<el-dropdown-item command="exportDataMerged" divided>导出产出钢卷(多行合并)</el-dropdown-item>
|
||||||
|
<el-dropdown-item command="exportLossDataMerged">导出消耗钢卷(多行合并)</el-dropdown-item>
|
||||||
</el-dropdown-menu>
|
</el-dropdown-menu>
|
||||||
</el-dropdown>
|
</el-dropdown>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
@@ -144,6 +146,11 @@ import CoilTable from "@/views/wms/report/components/coilTable";
|
|||||||
import ColumnsSetting from "@/views/wms/report/components/setting/columns";
|
import ColumnsSetting from "@/views/wms/report/components/setting/columns";
|
||||||
import TimeRangePicker from "@/views/wms/report/components/timeRangePicker.vue";
|
import TimeRangePicker from "@/views/wms/report/components/timeRangePicker.vue";
|
||||||
import { saveReportFile } from "@/views/wms/report/js/reportFile";
|
import { saveReportFile } from "@/views/wms/report/js/reportFile";
|
||||||
|
import { mergeCoilCells } from "@/views/wms/report/js/mergeExcelCells";
|
||||||
|
import { saveAs } from 'file-saver'
|
||||||
|
import request from '@/utils/request'
|
||||||
|
import { tansParams } from "@/utils/klp";
|
||||||
|
import { Loading } from 'element-ui'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'MergeTemplate',
|
name: 'MergeTemplate',
|
||||||
@@ -362,6 +369,54 @@ export default {
|
|||||||
abnormalExportCount: 0
|
abnormalExportCount: 0
|
||||||
}, `materialCoil_${new Date().getTime()}.xlsx`)
|
}, `materialCoil_${new Date().getTime()}.xlsx`)
|
||||||
},
|
},
|
||||||
|
// 导出产出钢卷(多行合并) — 二次合并钢卷列单元格
|
||||||
|
async exportDataMerged() {
|
||||||
|
if (this.outList.length === 0) {
|
||||||
|
this.$message.warning('暂无数据可导出')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
await this.exportWithMerge('wms/materialCoil/exportAbnormal', {
|
||||||
|
coilIds: this.outList.map(item => item.coilId).join(','),
|
||||||
|
abnormalExportCount: 0
|
||||||
|
}, `abnormalCoil_${new Date().getTime()}.xlsx`)
|
||||||
|
},
|
||||||
|
|
||||||
|
// 导出消耗钢卷(多行合并) — 二次合并钢卷列单元格
|
||||||
|
async exportLossDataMerged() {
|
||||||
|
if (this.lossList.length === 0) {
|
||||||
|
this.$message.warning('暂无数据可导出')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
await this.exportWithMerge('wms/materialCoil/export', {
|
||||||
|
coilIds: this.lossList.map(item => item.coilId).join(','),
|
||||||
|
abnormalExportCount: 0
|
||||||
|
}, `materialCoil_${new Date().getTime()}.xlsx`)
|
||||||
|
},
|
||||||
|
|
||||||
|
// 通用:导出多行 → ExcelJS 二次合并钢卷列 → 保存
|
||||||
|
async exportWithMerge(url, params, filename) {
|
||||||
|
const loading = Loading.service({
|
||||||
|
text: '正在导出并合并单元格,请稍候',
|
||||||
|
spinner: 'el-icon-loading',
|
||||||
|
background: 'rgba(0, 0, 0, 0.7)'
|
||||||
|
})
|
||||||
|
try {
|
||||||
|
const data = await request.post(url, params, {
|
||||||
|
transformRequest: [(params) => { return tansParams(params) }],
|
||||||
|
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
||||||
|
responseType: 'blob'
|
||||||
|
})
|
||||||
|
// data 是拦截器返回的 res.data(Blob),与 download 函数一致
|
||||||
|
const blob = new Blob([data])
|
||||||
|
const mergedBlob = await mergeCoilCells(blob, 26)
|
||||||
|
saveAs(mergedBlob, filename)
|
||||||
|
} catch (e) {
|
||||||
|
console.error('导出合并失败', e)
|
||||||
|
this.$message.error('导出失败,请联系管理员')
|
||||||
|
} finally {
|
||||||
|
loading.close()
|
||||||
|
}
|
||||||
|
},
|
||||||
// 处理命令
|
// 处理命令
|
||||||
handleCommand(command) {
|
handleCommand(command) {
|
||||||
if (command === 'exportData') {
|
if (command === 'exportData') {
|
||||||
@@ -376,6 +431,10 @@ export default {
|
|||||||
this.exportDataMore()
|
this.exportDataMore()
|
||||||
} else if (command === 'exportLossDataMore') {
|
} else if (command === 'exportLossDataMore') {
|
||||||
this.exportLossDataMore()
|
this.exportLossDataMore()
|
||||||
|
} else if (command === 'exportDataMerged') {
|
||||||
|
this.exportDataMerged()
|
||||||
|
} else if (command === 'exportLossDataMerged') {
|
||||||
|
this.exportLossDataMerged()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
// 加载列设置
|
// 加载列设置
|
||||||
|
|||||||
74
klp-ui/src/views/wms/report/js/mergeExcelCells.js
Normal file
74
klp-ui/src/views/wms/report/js/mergeExcelCells.js
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
import ExcelJS from 'exceljs'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 对异常钢卷报表导出的 Excel 进行二次合并处理
|
||||||
|
* 将钢卷信息列(前26列,A-Z)中连续相同值的单元格合并
|
||||||
|
*
|
||||||
|
* 原理:
|
||||||
|
* 1. 用 row.values 数组代替逐格 getCell,避免 9万+ 次对象创建
|
||||||
|
* 2. 合并单元格后用列级别样式统一居中,代替逐格设置
|
||||||
|
*
|
||||||
|
* @param {Blob} blob - 原始 Excel 文件 Blob
|
||||||
|
* @param {number} mergeColumnCount - 需要合并的钢卷列数,默认 26(A-Z列)
|
||||||
|
* @returns {Promise<Blob>} - 合并后的新 Blob
|
||||||
|
*/
|
||||||
|
export async function mergeCoilCells(blob, mergeColumnCount = 26) {
|
||||||
|
const workbook = new ExcelJS.Workbook()
|
||||||
|
const arrayBuffer = await blob.arrayBuffer()
|
||||||
|
await workbook.xlsx.load(arrayBuffer)
|
||||||
|
|
||||||
|
const worksheet = workbook.worksheets[0]
|
||||||
|
const rowCount = worksheet.rowCount
|
||||||
|
|
||||||
|
if (rowCount <= 1) return blob
|
||||||
|
|
||||||
|
// === 第一步:按钢卷身份标识分组 ===
|
||||||
|
// 使用 row.values 数组(1-based),字符拼接一次性比较,避免逐格 getCell
|
||||||
|
const groups = []
|
||||||
|
let groupStart = 2
|
||||||
|
let prevFingerprint = rowFingerprint(worksheet.getRow(2), mergeColumnCount)
|
||||||
|
|
||||||
|
for (let row = 3; row <= rowCount; row++) {
|
||||||
|
const curFingerprint = rowFingerprint(worksheet.getRow(row), mergeColumnCount)
|
||||||
|
if (curFingerprint !== prevFingerprint) {
|
||||||
|
groups.push({ start: groupStart, end: row - 1 })
|
||||||
|
groupStart = row
|
||||||
|
prevFingerprint = curFingerprint
|
||||||
|
}
|
||||||
|
}
|
||||||
|
groups.push({ start: groupStart, end: rowCount })
|
||||||
|
|
||||||
|
// === 第二步:合并单元格 ===
|
||||||
|
for (const group of groups) {
|
||||||
|
if (group.end > group.start) {
|
||||||
|
for (let col = 1; col <= mergeColumnCount; col++) {
|
||||||
|
worksheet.mergeCells(group.start, col, group.end, col)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// === 第三步:列级别统一居中(替换逐格设置,26 次 vs 9万次) ===
|
||||||
|
for (let col = 1; col <= mergeColumnCount; col++) {
|
||||||
|
const column = worksheet.getColumn(col)
|
||||||
|
column.alignment = { vertical: 'middle', horizontal: 'center', wrapText: true }
|
||||||
|
}
|
||||||
|
|
||||||
|
// === 第四步:写回 Blob ===
|
||||||
|
const buffer = await workbook.xlsx.writeBuffer()
|
||||||
|
return new Blob([buffer], {
|
||||||
|
type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生成行的"指纹"字符串,用于快速比较两行钢卷列是否相同
|
||||||
|
* row.values 是 ExcelJS 的 1-based 数组:values[1]=A列, values[2]=B列 ...
|
||||||
|
*/
|
||||||
|
function rowFingerprint(row, colCount) {
|
||||||
|
const vals = row.values || []
|
||||||
|
let fp = ''
|
||||||
|
for (let i = 1; i <= colCount; i++) {
|
||||||
|
fp += String(vals[i] ?? '') + '\x00'
|
||||||
|
}
|
||||||
|
return fp
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user