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
相关产品推荐
相关产品推荐

