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

JavaScript条件合并对象:工时统计逻辑优化与问题修复

实现优化后的每周工时累计逻辑

先明确三类数据的典型结构(你可根据实际业务调整字段名):

// 每日工时记录:[{ userId, date, hours }, ...]
const data_daily = [{ userId: '1', date: '2024-05-20', hours: 8 }, ...];

// 周工时信息:[{ userId, weekStartDate, totalHours }, ...]
const data_week = [{ userId: '1', weekStartDate: '2024-05-20', totalHours: 32 }, ...];

// 请假请求:[{ userId, weekStartDate, reason, minimumHours }, ...]
const time_off_request_query = [{ userId: '1', weekStartDate: '2024-05-20', reason: '病假', minimumHours: 4 }, ...];

第一步:预处理数据(提升查询效率)

先把三类数据按userId+weekStartDate分组,避免后续嵌套循环拖慢性能:

// 按用户+周分组每日工时:key为`userId_weekStartDate`,值为该周的每日工时数组
const dailyByUserWeek = data_daily.reduce((map, record) => {
  const weekStart = getWeekStartDate(record.date); // 需实现:根据日期获取周起始日(比如周一)
  const key = `${record.userId}_${weekStart}`;
  if (!map[key]) map[key] = [];
  map[key].push(record);
  return map;
}, {});

// 按用户+周分组周工时:key为`userId_weekStartDate`,值为周工时对象
const weeklyByUserWeek = data_week.reduce((map, record) => {
  const key = `${record.userId}_${record.weekStartDate}`;
  map[key] = record;
  return map;
}, {});

// 按用户+周分组请假请求:key为`userId_weekStartDate`,值为请假对象
const leaveByUserWeek = time_off_request_query.reduce((map, record) => {
  const key = `${record.userId}_${record.weekStartDate}`;
  map[key] = record;
  return map;
}, {});

// 辅助函数:获取日期所在周的起始日(示例:返回周一的YYYY-MM-DD)
function getWeekStartDate(dateStr) {
  const date = new Date(dateStr);
  const day = date.getDay();
  const diff = date.getDate() - (day === 0 ? 6 : day - 1); // 周日的话往前推6天到周一
  return new Date(date.setDate(diff)).toISOString().split('T')[0];
}

第二步:核心逻辑处理函数

拆分为多个单一职责的小函数,可读性拉满:

1. 计算单周调整后的累计工时(含请假最低工时)

function calculateAdjustedWeeklyHours(weeklyRecord, leaveRecord) {
  if (!weeklyRecord) return 0;
  // 如果本周有请假,把请假最低工时加到周累计里
  return leaveRecord ? weeklyRecord.totalHours + leaveRecord.minimumHours : weeklyRecord.totalHours;
}

2. 处理单周的每日工时记录(覆盖两个场景)

function processWeeklyDailyRecords(userId, weekStartDate) {
  const key = `${userId}_${weekStartDate}`;
  const dailyRecords = dailyByUserWeek[key] || [];
  const weeklyRecord = weeklyByUserWeek[key];
  const leaveRecord = leaveByUserWeek[key];
  const adjustedWeeklyTotal = calculateAdjustedWeeklyHours(weeklyRecord, leaveRecord);

  // 场景1:当日无工时记录但有周累计,补协议最低工时到当日和周记录
  if (dailyRecords.length === 0 && weeklyRecord) {
    // 这里假设协议最低工时为当日标准工时,比如8小时,你可替换为实际值
    const defaultDailyHours = 8;
    return {
      userId,
      weekStartDate,
      adjustedWeeklyTotal,
      dailyRecords: [{ userId, date: weekStartDate, hours: defaultDailyHours, source: '协议补录' }],
      leaveReason: leaveRecord?.reason || null
    };
  }

  // 场景2:当日有工时,且本周有请假,合并当日工时与调整后的周累计
  // 同时确保每日工时的总和与调整后的周累计匹配(若有差异可按需处理)
  return {
    userId,
    weekStartDate,
    adjustedWeeklyTotal,
    dailyRecords: dailyRecords.map(record => ({
      ...record,
      leaveApplied: !!leaveRecord
    })),
    leaveReason: leaveRecord?.reason || null
  };
}

3. 批量处理所有用户的所有周数据

function generateAllUserTrackingData() {
  // 收集所有需要处理的用户+周组合
  const allKeys = new Set([
    ...Object.keys(dailyByUserWeek),
    ...Object.keys(weeklyByUserWeek),
    ...Object.keys(leaveByUserWeek)
  ]);

  return Array.from(allKeys).map(key => {
    const [userId, weekStartDate] = key.split('_');
    return processWeeklyDailyRecords(userId, weekStartDate);
  });
}

第三步:调用示例

const finalTrackingData = generateAllUserTrackingData();
console.log(finalTrackingData);

优化点说明

  • 单一职责:每个函数只做一件事,比如getWeekStartDate只处理日期转周起始,calculateAdjustedWeeklyHours只算调整后的周工时,后续维护时改一处不影响全局
  • 预处理分组:把O(n²)的嵌套循环降到O(n),数据量大时性能提升明显
  • 清晰的场景分支:直接通过条件判断区分两个核心场景,逻辑一目了然,避免原来冗长的函数里绕来绕去
  • 可扩展性:如果后续加新场景(比如加班补工时),只需新增小函数,不用动核心逻辑

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 21:05:36