Spaces:
Running
Running
| // EyeTimeQuery.js - 仅统计用眼分钟数(日/周/月), 支持时区 | |
| const { mongoose } = require('../index'); | |
| const DateRangeHelper = require('../utils/DateRange'); | |
| const TimezoneUtils = require('../utils/timezone'); | |
| const DailyEyeTime = mongoose.model('DailyEyeTime'); | |
| class EyeTimeQuery { | |
| constructor(timezoneOffset = 8) { | |
| // 初始化时区工具与日期范围助手 | |
| this.timezoneOffset = timezoneOffset; | |
| this.timezoneUtils = new TimezoneUtils(timezoneOffset); | |
| this.dateHelper = new DateRangeHelper(timezoneOffset); | |
| } | |
| /** | |
| * 获取某日的用眼分钟数 | |
| * @param {Date} date - 查询目标日期(UTC 或本地时间均可) | |
| * @param {number} timezoneOffset - 时区偏移(小时) | |
| */ | |
| async getDailyMinutes(date, timezoneOffset = this.timezoneOffset) { | |
| const tzUtils = new TimezoneUtils(timezoneOffset); | |
| // 解析输入日期为本地日期 | |
| const localDate = tzUtils.parseDate(date); | |
| // 构建数据库查询的日期(本地零点对应的 UTC 时间) | |
| const localDayStart = new Date(Date.UTC( | |
| localDate.getUTCFullYear(), | |
| localDate.getUTCMonth(), | |
| localDate.getUTCDate(), | |
| 0, 0, 0, 0 | |
| )); | |
| const dbDate = tzUtils.localToUtc(localDayStart); | |
| // 查询记录 | |
| const dayRecords = await DailyEyeTime.find({ | |
| date: dbDate | |
| }).lean(); | |
| // 初始化小时分布 | |
| const hourlyStats = Array(24).fill(0); | |
| for (const rec of dayRecords) { | |
| if (rec.hourlyUsage && Array.isArray(rec.hourlyUsage)) { | |
| for (let i = 0; i < 24; i++) { | |
| hourlyStats[i] += rec.hourlyUsage[i] || 0; | |
| } | |
| } | |
| } | |
| // 总分钟数直接用小时分布求和 | |
| const totalUsage = Math.round(hourlyStats.reduce((a, b) => a + b, 0) * 100) / 100; | |
| return { | |
| date: localDate.toISOString().split('T')[0], | |
| totalUsage, | |
| hourlyStats: hourlyStats.map(v => Math.round(v * 100) / 100), | |
| timezoneOffset | |
| }; | |
| } | |
| /** | |
| * 获取周统计结果 | |
| */ | |
| async getWeeklyMinutes(weekOffset = 0, timezoneOffset = this.timezoneOffset) { | |
| const { startDate, endDate } = this.dateHelper.getWeekRange(weekOffset); | |
| const result = {}; | |
| for (let d = new Date(startDate); d <= endDate; d.setDate(d.getDate() + 1)) { | |
| const stats = await this.getDailyMinutes(new Date(d), timezoneOffset); | |
| result[stats.date] = stats.totalUsage; | |
| } | |
| return { | |
| weekOffset, | |
| weekRange: { | |
| start: startDate.toISOString().split('T')[0], | |
| end: endDate.toISOString().split('T')[0] | |
| }, | |
| dailyTotals: result, | |
| timezoneOffset | |
| }; | |
| } | |
| /** | |
| * 获取月统计结果 | |
| */ | |
| async getMonthlyMinutes(monthOffset = 0, timezoneOffset = this.timezoneOffset) { | |
| const { startDate, endDate } = this.dateHelper.getMonthRange(monthOffset, timezoneOffset); | |
| const result = {}; | |
| for (let d = new Date(startDate); d <= endDate; d.setDate(d.getDate() + 1)) { | |
| const stats = await this.getDailyMinutes(new Date(d), timezoneOffset); | |
| result[stats.date] = stats.totalUsage; | |
| } | |
| return { | |
| monthOffset, | |
| monthRange: { | |
| start: startDate.toISOString().split('T')[0], | |
| end: endDate.toISOString().split('T')[0] | |
| }, | |
| dailyTotals: result, | |
| timezoneOffset | |
| }; | |
| } | |
| } | |
| module.exports = EyeTimeQuery; |