前端导出带有合并单元格的列表

javascript 复制代码
// 导出
  async function exportExcel(fileName = "共识调整.xlsx") {
    // 所有数据
    const exportData = await getAllMainData();
    // 表头内容
    let fitstTitleList = [];
    const secondTitleList = [];
    allColumns.value.forEach(column => {
      if (!column.children) {
        fitstTitleList.push(column.label);
        secondTitleList.push("");
      } else {
        const arr = [column.label, "", ""];
        fitstTitleList = fitstTitleList.concat(arr);
        column.children.forEach(child => {
          secondTitleList.push(child.label);
        });
      }
    });
    let res = exportData.map(item => {
      // 固定列数据
      const fixedData = [item.dimension, item.sku, item.skuDescr1];
      const dynamicData =
        item.qtyData?.flatMap(qtyItem => {
          const arr = [
            qtyItem.machPreQty || "",
            qtyItem.sumQty || "",
            qtyItem.adjRate || ""
          ];
          return arr;
        }) || [];
      return [...fixedData, ...dynamicData];
    });
    res = [fitstTitleList, secondTitleList, ...res];
    const workSheet = utils.aoa_to_sheet(res);
    // 合并单元格
    setMergedCells(workSheet, res);
    // 设置样式
    setStyleCells(utils, workSheet);
    // 设置列宽
    workSheet["!cols"] = [
      { wch: 15 }, // 预测维度
      { wch: 15 }, // 产品代码
      { wch: 20 }, // 产品描述
      ...Array(fitstTitleList.length - 3).fill({ wch: 12 }) // 动态列宽
    ];
    const workBook = utils.book_new();
    utils.book_append_sheet(workBook, workSheet, "数据报表");
    writeFile(workBook, fileName);
    message("导出成功", { type: "success" });
  }
  // 设置样式
  function setStyleCells(utils, workSheet) {
	  // 获取表格范围
	  const range = utils.decode_range(workSheet["!ref"] || "A1:A1");
	  const dataStyle = {
	    alignment: { horizontal: "center", vertical: "center" },
	    border: {
	      top: { style: "thin" },
	      bottom: { style: "thin" },
	      left: { style: "thin" },
	      right: { style: "thin" }
	    }
	  };
	  // 遍历所有单元格,设置水平和垂直居中对齐
	  for (let r = range.s.r; r <= range.e.r; r++) {
	    for (let c = range.s.c; c <= range.e.c; c++) {
	      const cellAddress = utils.encode_cell({ r, c });
	      const cell = workSheet[cellAddress];
	      if (cell) {
	        // 创建或更新样式对象
	        cell.s = { ...(cell.s || {}), ...dataStyle };
	      }
	    }
	  }
	}
  // 设置合并单元格
  function setMergedCells(workSheet, res) {
    const mergeRanges = [];
    const dateRegex = /^\d{4}-\d{2}-\d{2}$/;
    const firstRow = res[0];
    // 处理日期列
    for (let colIndex = 0; colIndex < firstRow.length; colIndex++) {
      const cellValue = firstRow[colIndex];
      if (cellValue && dateRegex.test(String(cellValue))) {
        // 创建合并范围
        const mergeRange = {
          s: { r: 0, c: colIndex },
          e: { r: 0, c: colIndex + 2 }
        };
        mergeRanges.push(mergeRange);
        colIndex += 2; // 跳过已处理的列
      }
    }
    // 处理左侧固定列
    const fixedColumns = [
      { s: { r: 0, c: 0 }, e: { r: 1, c: 0 } }, // 预测维度
      { s: { r: 0, c: 1 }, e: { r: 1, c: 1 } }, // 产品代码
      { s: { r: 0, c: 2 }, e: { r: 1, c: 2 } } // 产品描述
    ];
    fixedColumns.forEach(range => {
      mergeRanges.push(range);
    });
    // 应用合并范围到工作表
    workSheet["!merges"] = mergeRanges;
  }
  // 获取所有数据
  async function getAllMainData() {
    try {
      if (pagination.total === dataList.value.length) {
        return dataList.value;
      } else {
        const params = {
          ...form,
          pageSize: pagination.total,
          currentPage: 1
        };
        const { data } = await getConsensusList(toRaw(params));
        return data?.list ?? [];
      }
    } finally {
      setTimeout(() => {
        loading.value = false;
      }, 500);
    }
  }
相关推荐
万少2 小时前
用腻了 WorkBuddy 的默认界面?这个开源小工具给它换上了毛玻璃
前端·javascript·后端
海上彼尚6 小时前
Nodejs也能写Agent - 16.LangGraph篇 - 条件分支与循环
前端·后端·langchain·node.js
To_OC7 小时前
从 “卡死半天” 到 “打字机效果”:大模型流式输出前端实现全记录
前端·javascript·llm
SoaringHeart7 小时前
Flutter最佳实践:键盘辅助视图输入框天添加图片附件
前端·flutter
kyriewen8 小时前
我看完这篇安全论文——AI推荐的npm包,92%是编出来的
前端·javascript·ai编程
小心我捶你啊9 小时前
数据采集和Web解锁不是一回事,从用途到规则区分
前端·爬虫·网络协议
hunterandroid9 小时前
[鸿蒙从零到一] ArkUI 基础组件实战:Text、Image、Button 与 TextInput
前端
fsssb10 小时前
Chromium 源码学习笔记(五):一次点击,在进入 JS 之前先经历了什么?
前端
hunterandroid10 小时前
WorkManager 可靠性实战:唯一任务、重试与幂等设计
android·前端