You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Google Sheets日志脚本如何自动按月份、日期分层分组新增行并折叠

实现方案

这个需求完全可以实现,直接与你现有RECORD_HISTORY()函数整合是最优方案,无需额外设置触发器,所有逻辑都可以在时间触发器调用记录函数时自动完成。

核心实现思路

  • 每次追加新日志行后,先提取当前行的日期(按GMT+01:00时区处理),与上一行的日志日期对比
  • 若检测到跨月,自动插入月份标题行(如AUGUST 2024),作为顶层一级分组的头部
  • 若检测到跨天,自动插入日期标题行(如2024-08-15),作为二级子分组的头部
  • 新生成的分组创建完成后自动折叠,用户打开表格时默认只看到月份分组,展开后可以看到日期分组,再展开就能看到对应时段的日志行

完整整合代码

// 时区配置,按你的需求设置为GMT+01:00
const TIME_ZONE = 'GMT+01:00';
const HISTORY_SHEET_NAME = 'HISTORY';

function RECORD_HISTORY() {
  let historySheet = getSheetWithName(HISTORY_SHEET_NAME);
  if (historySheet == null) {
    historySheet = SpreadsheetApp.getActiveSpreadsheet().insertSheet(HISTORY_SHEET_NAME, 1);
    // 新创建的表默认写入表头,可根据实际表头调整内容
    historySheet.appendRow(['时间', '列2', '列3', '列4', '列5', '列6', '列7', '列8', '列9']);
  }

  // 读取要写入的原始数据
  const range = historySheet.getRange(2, 1, 1, 9);
  const values = range.getValues();
  const currentDate = new Date();
  values[0][0] = currentDate;

  // 获取最后一行现有数据,判断是否需要插入标题行
  const lastRow = historySheet.getLastRow();
  let needInsertMonth = false;
  let needInsertDate = false;

  if (lastRow > 1) {
    // 读取上一行的时间值
    const prevCellValue = historySheet.getRange(lastRow, 1).getValue();
    if (prevCellValue instanceof Date) {
      // 格式化日期对比年月、日
      const prevMonth = Utilities.formatDate(prevCellValue, TIME_ZONE, 'YYYY-MM');
      const currentMonth = Utilities.formatDate(currentDate, TIME_ZONE, 'YYYY-MM');
      const prevDay = Utilities.formatDate(prevCellValue, TIME_ZONE, 'YYYY-MM-dd');
      const currentDay = Utilities.formatDate(currentDate, TIME_ZONE, 'YYYY-MM-dd');

      needInsertMonth = prevMonth !== currentMonth;
      needInsertDate = prevDay !== currentDay;
    } else {
      // 上一行是标题行,默认需要插入新日期
      needInsertDate = true;
    }
  } else {
    // 表为空首次写入,需要插入月份和日期标题
    needInsertMonth = true;
    needInsertDate = true;
  }

  // 插入月份标题行(跨月时触发)
  if (needInsertMonth) {
    const monthTitle = Utilities.formatDate(currentDate, TIME_ZONE, 'MMMM').toUpperCase();
    historySheet.appendRow([monthTitle, '', '', '', '', '', '', '', '']);
    const newMonthRow = historySheet.getLastRow();
    // 月份标题行样式设置,可自行调整
    historySheet.getRange(newMonthRow, 1).setFontWeight('bold').setFontSize(12);
  }

  // 插入日期标题行(跨天时触发)
  if (needInsertDate) {
    const dateTitle = Utilities.formatDate(currentDate, TIME_ZONE, 'YYYY-MM-dd').toUpperCase();
    historySheet.appendRow([dateTitle, '', '', '', '', '', '', '', '']);
    const newDateRow = historySheet.getLastRow();
    // 日期标题行样式设置,可自行调整
    historySheet.getRange(newDateRow, 1).setFontWeight('bold');
  }

  // 追加日志行
  historySheet.appendRow(values[0]);
  const newLogRow = historySheet.getLastRow();

  // 处理两级分组逻辑
  if (needInsertDate) {
    // 新建日期分组
    historySheet.getRange(newLogRow, 1).shiftRowGroupDepth(1);
    // 自动折叠日期分组
    historySheet.getRowGroup(newLogRow, 1).collapse();
  } else {
    // 加入已有日期分组
    historySheet.getRange(newLogRow, 1).shiftRowGroupDepth(1);
  }

  if (needInsertMonth) {
    // 新建月份分组
    const monthStartRow = needInsertDate ? newLogRow - 1 : newLogRow;
    historySheet.getRange(monthStartRow, 1).shiftRowGroupDepth(2);
    // 自动折叠月份分组
    historySheet.getRowGroup(monthStartRow, 2).collapse();
  } else {
    // 加入已有月份分组
    historySheet.getRange(newLogRow, 1).shiftRowGroupDepth(2);
  }
}

function getSheetWithName(name) {
  const sheets = SpreadsheetApp.getActiveSpreadsheet().getSheets();
  for (let idx in sheets) {
    if (sheets[idx].getName() === name) {
      return sheets[idx];
    }
  }
  return null;
}

注意事项

  • 若现有HISTORY表的表头结构与默认初始化表头不同,可自行调整代码中初始化表头的内容
  • 月份、日期标题的展示格式可修改Utilities.formatDate的格式化参数自定义
  • 所有操作均在时间触发器调用函数时自动完成,无需用户做任何手动操作,打开表格即可看到已折叠好的两级分组结构

内容的提问来源于stack exchange,提问作者Verminous

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.07 18:45:03