File size: 3,704 Bytes
00b9b23
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
// 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;