@ray-js/lamp-schedule-core 1.0.0-beta-1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +565 -0
- package/lib/config/dpCodes.d.ts +27 -0
- package/lib/config/dpCodes.js +30 -0
- package/lib/config/index.d.ts +2 -0
- package/lib/config/index.js +2 -0
- package/lib/config/rhythms/defaultValue.d.ts +18 -0
- package/lib/config/rhythms/defaultValue.js +72 -0
- package/lib/config/rhythms/index.d.ts +10 -0
- package/lib/config/rhythms/index.js +35 -0
- package/lib/conflict/ConflictResolver.d.ts +2 -0
- package/lib/conflict/ConflictResolver.js +284 -0
- package/lib/conflict/__test__/ConflictResolver.test.d.ts +1 -0
- package/lib/conflict/__test__/ConflictResolver.test.js +183 -0
- package/lib/conflict/__test__/index.test.d.ts +1 -0
- package/lib/conflict/__test__/index.test.js +385 -0
- package/lib/conflict/__test__/scheduleDataManager.test.d.ts +1 -0
- package/lib/conflict/__test__/scheduleDataManager.test.js +170 -0
- package/lib/conflict/__test__/transform.test.d.ts +1 -0
- package/lib/conflict/__test__/transform.test.js +454 -0
- package/lib/conflict/__test__/updateDeviceDp.d.ts +1 -0
- package/lib/conflict/__test__/updateDeviceDp.js +114 -0
- package/lib/conflict/index.d.ts +42 -0
- package/lib/conflict/index.js +103 -0
- package/lib/conflict/scheduleDataManager.d.ts +12 -0
- package/lib/conflict/scheduleDataManager.js +79 -0
- package/lib/conflict/transform.d.ts +71 -0
- package/lib/conflict/transform.js +251 -0
- package/lib/conflict/type.d.ts +55 -0
- package/lib/conflict/type.js +17 -0
- package/lib/conflict/updateDeviceDp.d.ts +1 -0
- package/lib/conflict/updateDeviceDp.js +41 -0
- package/lib/constant/index.d.ts +5 -0
- package/lib/constant/index.js +5 -0
- package/lib/context/index.d.ts +3 -0
- package/lib/context/index.js +3 -0
- package/lib/context/rhythms/actions.d.ts +20 -0
- package/lib/context/rhythms/actions.js +52 -0
- package/lib/context/rhythms/index.d.ts +5 -0
- package/lib/context/rhythms/index.js +51 -0
- package/lib/context/rhythms/reducer.d.ts +24 -0
- package/lib/context/rhythms/reducer.js +38 -0
- package/lib/context/schedule/actions.d.ts +7 -0
- package/lib/context/schedule/actions.js +51 -0
- package/lib/context/schedule/context.d.ts +6 -0
- package/lib/context/schedule/context.js +52 -0
- package/lib/context/schedule/index.d.ts +1 -0
- package/lib/context/schedule/index.js +1 -0
- package/lib/context/schedule/reducer.d.ts +16 -0
- package/lib/context/schedule/reducer.js +104 -0
- package/lib/context/schedule/type.d.ts +41 -0
- package/lib/context/schedule/type.js +11 -0
- package/lib/context/timer/actions.d.ts +8 -0
- package/lib/context/timer/actions.js +52 -0
- package/lib/context/timer/context.d.ts +10 -0
- package/lib/context/timer/context.js +53 -0
- package/lib/context/timer/index.d.ts +1 -0
- package/lib/context/timer/index.js +1 -0
- package/lib/context/timer/reducer.d.ts +15 -0
- package/lib/context/timer/reducer.js +70 -0
- package/lib/context/timer/type.d.ts +46 -0
- package/lib/context/timer/type.js +24 -0
- package/lib/dpParser/README.md +63 -0
- package/lib/dpParser/__test__/cycle.test.d.ts +1 -0
- package/lib/dpParser/__test__/cycle.test.js +258 -0
- package/lib/dpParser/__test__/random.test.d.ts +1 -0
- package/lib/dpParser/__test__/random.test.js +211 -0
- package/lib/dpParser/__test__/rhythms.test.d.ts +1 -0
- package/lib/dpParser/__test__/rhythms.test.js +71 -0
- package/lib/dpParser/__test__/rtcTimer.test.d.ts +1 -0
- package/lib/dpParser/__test__/rtcTimer.test.js +235 -0
- package/lib/dpParser/__test__/sleep.test.d.ts +1 -0
- package/lib/dpParser/__test__/sleep.test.js +71 -0
- package/lib/dpParser/__test__/sleepCommon.test.d.ts +1 -0
- package/lib/dpParser/__test__/sleepCommon.test.js +197 -0
- package/lib/dpParser/__test__/timerReport.test.d.ts +1 -0
- package/lib/dpParser/__test__/timerReport.test.js +100 -0
- package/lib/dpParser/__test__/wakeup.test.d.ts +1 -0
- package/lib/dpParser/__test__/wakeup.test.js +69 -0
- package/lib/dpParser/__test__/wakeupCommon.test.d.ts +1 -0
- package/lib/dpParser/__test__/wakeupCommon.test.js +131 -0
- package/lib/dpParser/cycle/index.d.ts +15 -0
- package/lib/dpParser/cycle/index.js +134 -0
- package/lib/dpParser/index.d.ts +23 -0
- package/lib/dpParser/index.js +43 -0
- package/lib/dpParser/random/index.d.ts +15 -0
- package/lib/dpParser/random/index.js +127 -0
- package/lib/dpParser/rhythms.d.ts +41 -0
- package/lib/dpParser/rhythms.js +116 -0
- package/lib/dpParser/rtcTimer.d.ts +17 -0
- package/lib/dpParser/rtcTimer.js +300 -0
- package/lib/dpParser/sleep/index.d.ts +9 -0
- package/lib/dpParser/sleep/index.js +29 -0
- package/lib/dpParser/sleep/sleepCommon.d.ts +11 -0
- package/lib/dpParser/sleep/sleepCommon.js +117 -0
- package/lib/dpParser/sleep/sleepSigmesh.d.ts +0 -0
- package/lib/dpParser/sleep/sleepSigmesh.js +101 -0
- package/lib/dpParser/timerReport.d.ts +11 -0
- package/lib/dpParser/timerReport.js +43 -0
- package/lib/dpParser/utils.d.ts +27 -0
- package/lib/dpParser/utils.js +53 -0
- package/lib/dpParser/wakeup/index.d.ts +10 -0
- package/lib/dpParser/wakeup/index.js +34 -0
- package/lib/dpParser/wakeup/wakeupCommon.d.ts +11 -0
- package/lib/dpParser/wakeup/wakeupCommon.js +106 -0
- package/lib/dpParser/wakeup/wakeupSigmesh.d.ts +15 -0
- package/lib/dpParser/wakeup/wakeupSigmesh.js +86 -0
- package/lib/hooks/__test__/useCommon.test.d.ts +1 -0
- package/lib/hooks/__test__/useCommon.test.js +72 -0
- package/lib/hooks/__test__/useCountdownDp.test.d.ts +1 -0
- package/lib/hooks/__test__/useCountdownDp.test.js +82 -0
- package/lib/hooks/__test__/useCycleDp.test.d.ts +1 -0
- package/lib/hooks/__test__/useCycleDp.test.js +92 -0
- package/lib/hooks/__test__/useRandomDp.test.d.ts +1 -0
- package/lib/hooks/__test__/useRandomDp.test.js +88 -0
- package/lib/hooks/__test__/useRhythmsDp.test.d.ts +1 -0
- package/lib/hooks/__test__/useRhythmsDp.test.js +81 -0
- package/lib/hooks/__test__/useSleepDp.test.d.ts +1 -0
- package/lib/hooks/__test__/useSleepDp.test.js +127 -0
- package/lib/hooks/__test__/useTimeFlush.test.d.ts +1 -0
- package/lib/hooks/__test__/useTimeFlush.test.js +109 -0
- package/lib/hooks/__test__/useTimerDp.test.d.ts +1 -0
- package/lib/hooks/__test__/useTimerDp.test.js +79 -0
- package/lib/hooks/__test__/useTimerOperate.test.d.ts +1 -0
- package/lib/hooks/__test__/useTimerOperate.test.js +286 -0
- package/lib/hooks/__test__/useTimerOperateCloud.test.d.ts +1 -0
- package/lib/hooks/__test__/useTimerOperateCloud.test.js +190 -0
- package/lib/hooks/__test__/useTimerOperateLocal.test.d.ts +1 -0
- package/lib/hooks/__test__/useTimerOperateLocal.test.js +216 -0
- package/lib/hooks/__test__/useTimerReportDp.test.d.ts +1 -0
- package/lib/hooks/__test__/useTimerReportDp.test.js +93 -0
- package/lib/hooks/__test__/useTimerSupport.test.d.ts +1 -0
- package/lib/hooks/__test__/useTimerSupport.test.js +110 -0
- package/lib/hooks/__test__/useWakeUpDp.test.d.ts +1 -0
- package/lib/hooks/__test__/useWakeUpDp.test.js +129 -0
- package/lib/hooks/useBaseLightDp.d.ts +21 -0
- package/lib/hooks/useBaseLightDp.js +165 -0
- package/lib/hooks/useCommon.d.ts +29 -0
- package/lib/hooks/useCommon.js +59 -0
- package/lib/hooks/useCommonSupport.d.ts +25 -0
- package/lib/hooks/useCommonSupport.js +241 -0
- package/lib/hooks/useCountdownDp.d.ts +13 -0
- package/lib/hooks/useCountdownDp.js +28 -0
- package/lib/hooks/useCountdownSupport.d.ts +9 -0
- package/lib/hooks/useCountdownSupport.js +13 -0
- package/lib/hooks/useCycleDp.d.ts +7 -0
- package/lib/hooks/useCycleDp.js +21 -0
- package/lib/hooks/useCycleSupport.d.ts +12 -0
- package/lib/hooks/useCycleSupport.js +16 -0
- package/lib/hooks/useRandomDp.d.ts +7 -0
- package/lib/hooks/useRandomDp.js +21 -0
- package/lib/hooks/useRandomSupport.d.ts +12 -0
- package/lib/hooks/useRandomSupport.js +16 -0
- package/lib/hooks/useRhythmsDp.d.ts +7 -0
- package/lib/hooks/useRhythmsDp.js +23 -0
- package/lib/hooks/useSleepDp.d.ts +6 -0
- package/lib/hooks/useSleepDp.js +21 -0
- package/lib/hooks/useSleepSupport.d.ts +8 -0
- package/lib/hooks/useSleepSupport.js +13 -0
- package/lib/hooks/useTimeFlush.d.ts +8 -0
- package/lib/hooks/useTimeFlush.js +31 -0
- package/lib/hooks/useTimerDp.d.ts +5 -0
- package/lib/hooks/useTimerDp.js +25 -0
- package/lib/hooks/useTimerFlushList.d.ts +11 -0
- package/lib/hooks/useTimerFlushList.js +53 -0
- package/lib/hooks/useTimerOperate.d.ts +68 -0
- package/lib/hooks/useTimerOperate.js +403 -0
- package/lib/hooks/useTimerOperateCloud.d.ts +31 -0
- package/lib/hooks/useTimerOperateCloud.js +233 -0
- package/lib/hooks/useTimerOperateLocal.d.ts +40 -0
- package/lib/hooks/useTimerOperateLocal.js +310 -0
- package/lib/hooks/useTimerReportDp.d.ts +15 -0
- package/lib/hooks/useTimerReportDp.js +48 -0
- package/lib/hooks/useTimerSupport.d.ts +13 -0
- package/lib/hooks/useTimerSupport.js +38 -0
- package/lib/hooks/useWakeUpDp.d.ts +6 -0
- package/lib/hooks/useWakeUpDp.js +21 -0
- package/lib/hooks/useWakeUpSupport.d.ts +8 -0
- package/lib/hooks/useWakeUpSupport.js +13 -0
- package/lib/hooks/useWakeupDp.d.ts +6 -0
- package/lib/hooks/useWakeupDp.js +21 -0
- package/lib/hooks/useWakeupSupport.d.ts +8 -0
- package/lib/hooks/useWakeupSupport.js +13 -0
- package/lib/i18n/index.d.ts +142 -0
- package/lib/i18n/index.js +7 -0
- package/lib/i18n/rhythms.d.ts +73 -0
- package/lib/i18n/rhythms.js +72 -0
- package/lib/i18n/strings.d.ts +73 -0
- package/lib/i18n/strings.js +6 -0
- package/lib/index.d.ts +51 -0
- package/lib/index.js +64 -0
- package/lib/types/countdown.d.ts +3 -0
- package/lib/types/countdown.js +1 -0
- package/lib/types/cycle.d.ts +22 -0
- package/lib/types/cycle.js +1 -0
- package/lib/types/global.d.ts +9 -0
- package/lib/types/index.d.ts +331 -0
- package/lib/types/index.js +76 -0
- package/lib/types/random.d.ts +20 -0
- package/lib/types/random.js +1 -0
- package/lib/types/rhythms.d.ts +79 -0
- package/lib/types/rhythms.js +15 -0
- package/lib/types/sleep.d.ts +36 -0
- package/lib/types/sleep.js +1 -0
- package/lib/types/timer.d.ts +107 -0
- package/lib/types/timer.js +1 -0
- package/lib/types/wakeup.d.ts +38 -0
- package/lib/types/wakeup.js +1 -0
- package/lib/utils/ScheduleCache.d.ts +19 -0
- package/lib/utils/ScheduleCache.js +39 -0
- package/lib/utils/ScheduleCloudProperty.d.ts +75 -0
- package/lib/utils/ScheduleCloudProperty.js +220 -0
- package/lib/utils/ScheduleDataSync.d.ts +82 -0
- package/lib/utils/ScheduleDataSync.js +127 -0
- package/lib/utils/ScheduleEmit.d.ts +67 -0
- package/lib/utils/ScheduleEmit.js +61 -0
- package/lib/utils/ScheduleLogger.d.ts +19 -0
- package/lib/utils/ScheduleLogger.js +71 -0
- package/lib/utils/ScheduleSupport.d.ts +131 -0
- package/lib/utils/ScheduleSupport.js +373 -0
- package/lib/utils/ScheduleUtils.d.ts +12 -0
- package/lib/utils/ScheduleUtils.js +51 -0
- package/lib/utils/__test__/ScheduleCloudProperty.test.d.ts +1 -0
- package/lib/utils/__test__/ScheduleCloudProperty.test.js +320 -0
- package/lib/utils/__test__/ScheduleSupport.test.d.ts +1 -0
- package/lib/utils/__test__/ScheduleSupport.test.js +211 -0
- package/lib/utils/__test__/ScheduleUtils.test.d.ts +1 -0
- package/lib/utils/__test__/ScheduleUtils.test.js +119 -0
- package/lib/utils/__test__/common.test.d.ts +1 -0
- package/lib/utils/__test__/common.test.js +147 -0
- package/lib/utils/__test__/storage.test.d.ts +1 -0
- package/lib/utils/__test__/storage.test.js +98 -0
- package/lib/utils/__test__/time.test.d.ts +1 -0
- package/lib/utils/__test__/time.test.js +146 -0
- package/lib/utils/common.d.ts +23 -0
- package/lib/utils/common.js +109 -0
- package/lib/utils/dpState.d.ts +5 -0
- package/lib/utils/dpState.js +27 -0
- package/lib/utils/getCachedSystemInfo.d.ts +39 -0
- package/lib/utils/getCachedSystemInfo.js +20 -0
- package/lib/utils/isInIDE.d.ts +1 -0
- package/lib/utils/isInIDE.js +5 -0
- package/lib/utils/storage.d.ts +5 -0
- package/lib/utils/storage.js +32 -0
- package/lib/utils/time.d.ts +40 -0
- package/lib/utils/time.js +84 -0
- package/package.json +78 -0
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import Strings from '../../i18n';
|
|
2
|
+
export const defaultRhythms = {
|
|
3
|
+
defaultCloud: [{
|
|
4
|
+
name: 'sub_0',
|
|
5
|
+
icon: ''
|
|
6
|
+
}, {
|
|
7
|
+
name: Strings.getLang('rhythms_default_name_0'),
|
|
8
|
+
icon: 'icon1'
|
|
9
|
+
}, {
|
|
10
|
+
name: Strings.getLang('rhythms_default_name_1'),
|
|
11
|
+
icon: 'icon2'
|
|
12
|
+
}, {
|
|
13
|
+
name: Strings.getLang('rhythms_default_name_2'),
|
|
14
|
+
icon: 'icon3'
|
|
15
|
+
}, {
|
|
16
|
+
name: 'sub_3',
|
|
17
|
+
icon: ''
|
|
18
|
+
}, {
|
|
19
|
+
name: Strings.getLang('rhythms_default_name_3'),
|
|
20
|
+
icon: 'icon4'
|
|
21
|
+
}],
|
|
22
|
+
defaultSigMeshCloud: [{
|
|
23
|
+
name: Strings.getLang('rhythms_default_name_0'),
|
|
24
|
+
icon: 'icon1'
|
|
25
|
+
}, {
|
|
26
|
+
name: Strings.getLang('rhythms_default_name_1'),
|
|
27
|
+
icon: 'icon2'
|
|
28
|
+
}, {
|
|
29
|
+
name: Strings.getLang('rhythms_default_name_2'),
|
|
30
|
+
icon: 'icon3'
|
|
31
|
+
}, {
|
|
32
|
+
name: Strings.getLang('rhythms_default_name_3'),
|
|
33
|
+
icon: 'icon4'
|
|
34
|
+
}]
|
|
35
|
+
};
|
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
import "core-js/modules/esnext.iterator.constructor.js";
|
|
2
|
+
import "core-js/modules/esnext.iterator.flat-map.js";
|
|
3
|
+
import "core-js/modules/esnext.iterator.for-each.js";
|
|
4
|
+
/* eslint-disable no-console */
|
|
5
|
+
import dayjs from 'dayjs';
|
|
6
|
+
import { scheduleLogger } from '../utils/ScheduleLogger';
|
|
7
|
+
import { EScheduleFunctionType } from '../types';
|
|
8
|
+
|
|
9
|
+
/** 计划模块间的冲突逻辑 */
|
|
10
|
+
// 综述:生物节律、入睡唤醒、随机定时、循环定时、倒计时面板进行互斥判断确保下发的任务不存在互斥任务
|
|
11
|
+
/**
|
|
12
|
+
* 1. 生物节律
|
|
13
|
+
* - 冲突判断依据:
|
|
14
|
+
* 1.1. 开启:生物节律功能以星期为度进行判断,如果相同星期有其他任务,提示冲突
|
|
15
|
+
* 1.2. 修改:修改星期的时候需要进行判断是否存在时间冲突
|
|
16
|
+
* - 提示文案:
|
|
17
|
+
* 1.3 与以下定时任务存在冲突,请关闭后重试
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* 2. 入睡唤醒 随机定时 循环定时,任务保存默认开启
|
|
22
|
+
* - 冲突判断依据:
|
|
23
|
+
* 2.1 入睡任务时间段为开始入睡到淡出至关灯的时间段
|
|
24
|
+
* 2.2 唤醒任务时间段为开始唤醒到淡入至完全亮灯的时间段,如果设置了持续时间后关灯,任务时间需要加上持续时间
|
|
25
|
+
* 2.3 随机定时任务时间段为开始时间到结束时间
|
|
26
|
+
* - 提示文案:
|
|
27
|
+
* 2.4 冲突提示:与以下定时任务存在冲突,请关闭后重试
|
|
28
|
+
* 2.5 时间提示:如果开始时间早于当前时间,提示 当日任务不生效
|
|
29
|
+
*/
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* 3. 倒计时
|
|
33
|
+
* - 冲突判断依据:
|
|
34
|
+
* 3.1 倒计时属于单次任务,任务时间段为设置时的当前时间段到倒计时结束时间点,在这个时间段内,如果存在其他任务时间重叠,提示冲突
|
|
35
|
+
* - 提示文案:
|
|
36
|
+
* 3.2 冲突提示:与以下定时任务存在冲突,请关闭后重试
|
|
37
|
+
*/
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* 4. 定时
|
|
41
|
+
* - 冲突判断依据:
|
|
42
|
+
* 4.1 不能生成两个相同的定时任务
|
|
43
|
+
* - 提示文案:
|
|
44
|
+
* 4.2 冲突提示:与以下定时任务存在冲突,请关闭后重试
|
|
45
|
+
*/
|
|
46
|
+
|
|
47
|
+
// 跨天处理的核心冲突检测函数
|
|
48
|
+
function doRangesOverlap(aStart, aEnd, bStart, bEnd) {
|
|
49
|
+
// 处理跨天时间范围
|
|
50
|
+
const aIsCrossDay = aEnd < aStart;
|
|
51
|
+
const bIsCrossDay = bEnd < bStart;
|
|
52
|
+
|
|
53
|
+
// 标准化时间范围,将跨天时间段视为两天的总分钟数
|
|
54
|
+
// 例如:22:00 到 02:00 会被转换为 1320 到 1560 (而不是 1320 到 120)
|
|
55
|
+
const aStartMin = aStart;
|
|
56
|
+
const aEndMin = aIsCrossDay ? aEnd + 1440 : aEnd;
|
|
57
|
+
const bStartMin = bStart;
|
|
58
|
+
const bEndMin = bIsCrossDay ? bEnd + 1440 : bEnd;
|
|
59
|
+
|
|
60
|
+
// 情况1: 两个范围完全相同
|
|
61
|
+
if (aStartMin === bStartMin && aEndMin === bEndMin) {
|
|
62
|
+
return true;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// 情况2: 两个范围都跨天
|
|
66
|
+
// 当两个范围都跨天时,它们一定会重叠,因为都覆盖了午夜时间点
|
|
67
|
+
if (aIsCrossDay && bIsCrossDay) {
|
|
68
|
+
return true;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// 情况3: 一个范围跨天,一个不跨天
|
|
72
|
+
// 这种情况下,我们已经将跨天范围标准化为连续分钟数
|
|
73
|
+
// 所以可以直接使用标准区间重叠判断
|
|
74
|
+
|
|
75
|
+
// 情况4: 两个范围都不跨天
|
|
76
|
+
// 使用标准区间重叠判断: [a1,a2] 和 [b1,b2] 重叠当且仅当 a2 > b1 && b2 > a1
|
|
77
|
+
return aEndMin > bStartMin && bEndMin > aStartMin;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// 辅助函数
|
|
81
|
+
function parseTimeToMinutes(timeStr) {
|
|
82
|
+
try {
|
|
83
|
+
if (!timeStr || typeof timeStr !== 'string') {
|
|
84
|
+
throw new Error(`Invalid time format: ${timeStr}`);
|
|
85
|
+
}
|
|
86
|
+
const parts = timeStr.split(':');
|
|
87
|
+
if (parts.length !== 2) {
|
|
88
|
+
throw new Error(`Time string must be in format HH:MM, got: ${timeStr}`);
|
|
89
|
+
}
|
|
90
|
+
const hour = Number(parts[0]);
|
|
91
|
+
const minute = Number(parts[1]);
|
|
92
|
+
if (hour < 0 || hour > 23 || minute < 0 || minute > 59) {
|
|
93
|
+
throw new Error(`Time values out of range, got: ${timeStr}`);
|
|
94
|
+
}
|
|
95
|
+
return hour * 60 + minute;
|
|
96
|
+
} catch (error) {
|
|
97
|
+
scheduleLogger.error('Invalid time format:', error, timeStr);
|
|
98
|
+
return 0;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// 转换原始任务到统一格式
|
|
103
|
+
function convertToTimeRanges(schedules) {
|
|
104
|
+
const daysOfWeek = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];
|
|
105
|
+
|
|
106
|
+
// dayjs 获取当前星期
|
|
107
|
+
const week = dayjs().day();
|
|
108
|
+
return schedules.flatMap(schedule => {
|
|
109
|
+
try {
|
|
110
|
+
// 验证weeks数组
|
|
111
|
+
if (!schedule.data.weeks || !Array.isArray(schedule.data.weeks) || schedule.data.weeks.length !== 7) {
|
|
112
|
+
scheduleLogger.error('Invalid weeks format:', schedule);
|
|
113
|
+
return [];
|
|
114
|
+
}
|
|
115
|
+
const activeDays = daysOfWeek.filter((_, i) => schedule.data.weeks[i] === 1);
|
|
116
|
+
|
|
117
|
+
// 单次任务(weeks全为0)
|
|
118
|
+
if (activeDays.length === 0) {
|
|
119
|
+
try {
|
|
120
|
+
const startTime = schedule.data.startTime ? schedule.data.startTime : schedule.data.time;
|
|
121
|
+
const endTime = schedule.data.endTime ? schedule.data.endTime : schedule.data.time;
|
|
122
|
+
if (!startTime || !endTime) {
|
|
123
|
+
scheduleLogger.error('Missing time data in schedule:', schedule);
|
|
124
|
+
return [];
|
|
125
|
+
}
|
|
126
|
+
const startMinutes = parseTimeToMinutes(startTime);
|
|
127
|
+
const endMinutes = parseTimeToMinutes(endTime);
|
|
128
|
+
const isCrossDay = endMinutes < startMinutes;
|
|
129
|
+
|
|
130
|
+
// 如果定时状态为关闭,则设置星期,忽略冲突判断
|
|
131
|
+
const dayOfWeek = schedule.data.status ? daysOfWeek[isCrossDay ? (week + 1) % 7 : week] : null;
|
|
132
|
+
return [{
|
|
133
|
+
id: schedule.id,
|
|
134
|
+
type: schedule.type,
|
|
135
|
+
dayOfWeek: dayOfWeek,
|
|
136
|
+
startMinutes,
|
|
137
|
+
endMinutes,
|
|
138
|
+
originalSchedule: schedule,
|
|
139
|
+
isCrossDay
|
|
140
|
+
}];
|
|
141
|
+
} catch (error) {
|
|
142
|
+
scheduleLogger.error('Error processing single task:', error, schedule);
|
|
143
|
+
return [];
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// 周期性任务(有星期标记)
|
|
148
|
+
const result = [];
|
|
149
|
+
activeDays.forEach(day => {
|
|
150
|
+
try {
|
|
151
|
+
const startTimeStr = schedule.data.startTime || schedule.data.time;
|
|
152
|
+
const endTimeStr = schedule.data.endTime || schedule.data.time;
|
|
153
|
+
if (!startTimeStr || !endTimeStr) {
|
|
154
|
+
scheduleLogger.error('Missing time data in schedule:', schedule);
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
const start = parseTimeToMinutes(startTimeStr);
|
|
158
|
+
const end = parseTimeToMinutes(endTimeStr);
|
|
159
|
+
const isCrossDay = end < start;
|
|
160
|
+
|
|
161
|
+
// 如果定时状态为关闭,则设置星期,忽略冲突判断
|
|
162
|
+
if (!schedule.data.status) {
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// 添加当前星期的时间范围
|
|
167
|
+
result.push({
|
|
168
|
+
id: schedule.id,
|
|
169
|
+
type: schedule.type,
|
|
170
|
+
dayOfWeek: day,
|
|
171
|
+
startMinutes: start,
|
|
172
|
+
endMinutes: end,
|
|
173
|
+
originalSchedule: schedule,
|
|
174
|
+
isCrossDay
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
// 如果是跨天任务,还需要添加下一天的时间范围
|
|
178
|
+
if (isCrossDay) {
|
|
179
|
+
// 获取下一天的星期
|
|
180
|
+
const nextDayIndex = (daysOfWeek.indexOf(day) + 1) % 7;
|
|
181
|
+
const nextDay = daysOfWeek[nextDayIndex];
|
|
182
|
+
|
|
183
|
+
// 检查下一天是否在激活的星期中
|
|
184
|
+
// 注意:即使下一天不在激活的星期中,我们也需要考虑跨天冲突
|
|
185
|
+
result.push({
|
|
186
|
+
id: schedule.id,
|
|
187
|
+
type: schedule.type,
|
|
188
|
+
dayOfWeek: nextDay,
|
|
189
|
+
startMinutes: 0,
|
|
190
|
+
// 从午夜开始
|
|
191
|
+
endMinutes: end,
|
|
192
|
+
// 到结束时间
|
|
193
|
+
originalSchedule: schedule,
|
|
194
|
+
isCrossDay: false // 这部分不再是跨天
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
} catch (error) {
|
|
198
|
+
scheduleLogger.error('Error processing periodic task:', error, schedule, day);
|
|
199
|
+
}
|
|
200
|
+
});
|
|
201
|
+
return result;
|
|
202
|
+
} catch (error) {
|
|
203
|
+
scheduleLogger.error('Error converting schedule to time ranges:', error, schedule);
|
|
204
|
+
return [];
|
|
205
|
+
}
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
// 默认规则
|
|
210
|
+
const defaultRule = {
|
|
211
|
+
isConflict(a, b) {
|
|
212
|
+
return doRangesOverlap(a.startMinutes, a.endMinutes, b.startMinutes, b.endMinutes);
|
|
213
|
+
},
|
|
214
|
+
shouldIgnore(a, b) {
|
|
215
|
+
// 倒计时和生物节律因为每个都只有一个,不需要与自身判断冲突
|
|
216
|
+
if (a.id === b.id && a.id === EScheduleFunctionType.COUNTDOWN) {
|
|
217
|
+
return true;
|
|
218
|
+
}
|
|
219
|
+
if (a.id === b.id && a.id === EScheduleFunctionType.RHYTHM) {
|
|
220
|
+
return true;
|
|
221
|
+
}
|
|
222
|
+
return false;
|
|
223
|
+
}
|
|
224
|
+
};
|
|
225
|
+
function mergeListByOtherId(list) {
|
|
226
|
+
const mergedData = {};
|
|
227
|
+
list.forEach(item => {
|
|
228
|
+
if (!item || !item.other || !item.other.id) {
|
|
229
|
+
scheduleLogger.warn('Invalid conflict item:', item);
|
|
230
|
+
return;
|
|
231
|
+
}
|
|
232
|
+
const otherId = item.other.id;
|
|
233
|
+
if (!mergedData[otherId]) {
|
|
234
|
+
mergedData[otherId] = {
|
|
235
|
+
other: item.other,
|
|
236
|
+
current: item.current
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
});
|
|
240
|
+
return Object.values(mergedData);
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
// 冲突检测核心函数(修改后的版本)
|
|
244
|
+
export function checkConflicts(scheduleList, currentSchedule) {
|
|
245
|
+
let rule = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : defaultRule;
|
|
246
|
+
const currentRanges = convertToTimeRanges([currentSchedule]);
|
|
247
|
+
const conflicts = [];
|
|
248
|
+
scheduleLogger.debug('checkConflicts rule:', rule);
|
|
249
|
+
scheduleLogger.debug('checkConflicts scheduleList:', scheduleList);
|
|
250
|
+
scheduleLogger.debug('checkConflicts currentSchedule:', currentSchedule);
|
|
251
|
+
const newSplicedScheduleList = [...scheduleList];
|
|
252
|
+
newSplicedScheduleList.forEach(schedule => {
|
|
253
|
+
const otherRanges = convertToTimeRanges([schedule]);
|
|
254
|
+
scheduleLogger.debug('checkConflicts currentRanges:', currentRanges);
|
|
255
|
+
scheduleLogger.debug('checkConflicts otherRanges:', otherRanges);
|
|
256
|
+
currentRanges.forEach(current => {
|
|
257
|
+
otherRanges.forEach(other => {
|
|
258
|
+
var _rule$shouldIgnore, _current$originalSche, _current$originalSche2;
|
|
259
|
+
// 应用规则中的忽略条件
|
|
260
|
+
if ((_rule$shouldIgnore = rule.shouldIgnore) !== null && _rule$shouldIgnore !== void 0 && _rule$shouldIgnore.call(rule, current, other)) {
|
|
261
|
+
return;
|
|
262
|
+
}
|
|
263
|
+
const currentPreId = current === null || current === void 0 || (_current$originalSche = current.originalSchedule) === null || _current$originalSche === void 0 ? void 0 : _current$originalSche.prevId;
|
|
264
|
+
const currentId = current === null || current === void 0 || (_current$originalSche2 = current.originalSchedule) === null || _current$originalSche2 === void 0 ? void 0 : _current$originalSche2.id;
|
|
265
|
+
const otherId = other.id;
|
|
266
|
+
// 如果当前定时自身修改 且 与自身冲突 则忽略
|
|
267
|
+
if (currentPreId && currentId === otherId || otherId === currentPreId) {
|
|
268
|
+
return;
|
|
269
|
+
}
|
|
270
|
+
if (current.dayOfWeek && current.dayOfWeek === other.dayOfWeek && rule.isConflict(current, other)) {
|
|
271
|
+
conflicts.push({
|
|
272
|
+
current: current.originalSchedule,
|
|
273
|
+
other: other.originalSchedule
|
|
274
|
+
});
|
|
275
|
+
}
|
|
276
|
+
});
|
|
277
|
+
});
|
|
278
|
+
});
|
|
279
|
+
scheduleLogger.debug('conflicts', conflicts);
|
|
280
|
+
// 将 conflicts 中相同的 other 字段数据进行合并,防止重复项目产生
|
|
281
|
+
const newConflict = mergeListByOtherId(conflicts);
|
|
282
|
+
scheduleLogger.debug('newConflict', newConflict);
|
|
283
|
+
return newConflict;
|
|
284
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
import { checkConflicts } from '../ConflictResolver';
|
|
2
|
+
import { EScheduleFunctionType } from '../../types';
|
|
3
|
+
describe('ConflictResolver', () => {
|
|
4
|
+
describe('checkConflicts', () => {
|
|
5
|
+
// 测试基本冲突检测功能
|
|
6
|
+
it('should detect conflicts between schedules on the same day', () => {
|
|
7
|
+
// 创建两个在同一天有时间重叠的计划
|
|
8
|
+
const schedule1 = {
|
|
9
|
+
id: 'timer_1',
|
|
10
|
+
type: EScheduleFunctionType.TIMER,
|
|
11
|
+
data: {
|
|
12
|
+
status: true,
|
|
13
|
+
weeks: [1, 0, 0, 0, 0, 0, 0],
|
|
14
|
+
// 周日
|
|
15
|
+
startTime: '10:00',
|
|
16
|
+
endTime: '11:00'
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
const schedule2 = {
|
|
20
|
+
id: 'timer_2',
|
|
21
|
+
type: EScheduleFunctionType.TIMER,
|
|
22
|
+
data: {
|
|
23
|
+
status: true,
|
|
24
|
+
weeks: [1, 0, 0, 0, 0, 0, 0],
|
|
25
|
+
// 周日
|
|
26
|
+
startTime: '10:30',
|
|
27
|
+
endTime: '11:30'
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
const conflicts = checkConflicts([schedule1], schedule2);
|
|
31
|
+
expect(conflicts.length).toBe(1);
|
|
32
|
+
expect(conflicts[0].current).toBe(schedule2);
|
|
33
|
+
expect(conflicts[0].other).toBe(schedule1);
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
// 测试不同天的计划不会冲突
|
|
37
|
+
it('should not detect conflicts between schedules on different days', () => {
|
|
38
|
+
const schedule1 = {
|
|
39
|
+
id: 'timer_1',
|
|
40
|
+
type: EScheduleFunctionType.TIMER,
|
|
41
|
+
data: {
|
|
42
|
+
status: true,
|
|
43
|
+
weeks: [1, 0, 0, 0, 0, 0, 0],
|
|
44
|
+
// 周日
|
|
45
|
+
startTime: '10:00',
|
|
46
|
+
endTime: '11:00'
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
const schedule2 = {
|
|
50
|
+
id: 'timer_2',
|
|
51
|
+
type: EScheduleFunctionType.TIMER,
|
|
52
|
+
data: {
|
|
53
|
+
status: true,
|
|
54
|
+
weeks: [0, 1, 0, 0, 0, 0, 0],
|
|
55
|
+
// 周一
|
|
56
|
+
startTime: '10:00',
|
|
57
|
+
endTime: '11:00'
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
const conflicts = checkConflicts([schedule1], schedule2);
|
|
61
|
+
expect(conflicts.length).toBe(0);
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
// 测试跨天计划的冲突检测
|
|
65
|
+
it('should detect conflicts with cross-day schedules', () => {
|
|
66
|
+
const schedule1 = {
|
|
67
|
+
id: 'timer_1',
|
|
68
|
+
type: EScheduleFunctionType.TIMER,
|
|
69
|
+
data: {
|
|
70
|
+
status: true,
|
|
71
|
+
weeks: [1, 0, 0, 0, 0, 0, 0],
|
|
72
|
+
// 周日
|
|
73
|
+
startTime: '23:00',
|
|
74
|
+
endTime: '01:00' // 跨天到周一
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
const schedule2 = {
|
|
78
|
+
id: 'timer_2',
|
|
79
|
+
type: EScheduleFunctionType.TIMER,
|
|
80
|
+
data: {
|
|
81
|
+
status: true,
|
|
82
|
+
weeks: [0, 1, 0, 0, 0, 0, 0],
|
|
83
|
+
// 周一
|
|
84
|
+
startTime: '00:30',
|
|
85
|
+
endTime: '02:00'
|
|
86
|
+
}
|
|
87
|
+
};
|
|
88
|
+
const conflicts = checkConflicts([schedule1], schedule2);
|
|
89
|
+
expect(conflicts.length).toBe(1);
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
// 测试关闭状态的计划不会产生冲突
|
|
93
|
+
it('should not detect conflicts with schedules that are turned off', () => {
|
|
94
|
+
const schedule1 = {
|
|
95
|
+
id: 'timer_1',
|
|
96
|
+
type: EScheduleFunctionType.TIMER,
|
|
97
|
+
data: {
|
|
98
|
+
status: false,
|
|
99
|
+
// 关闭状态
|
|
100
|
+
weeks: [1, 0, 0, 0, 0, 0, 0],
|
|
101
|
+
// 周日
|
|
102
|
+
startTime: '10:00',
|
|
103
|
+
endTime: '11:00'
|
|
104
|
+
}
|
|
105
|
+
};
|
|
106
|
+
const schedule2 = {
|
|
107
|
+
id: 'timer_2',
|
|
108
|
+
type: EScheduleFunctionType.TIMER,
|
|
109
|
+
data: {
|
|
110
|
+
status: true,
|
|
111
|
+
weeks: [1, 0, 0, 0, 0, 0, 0],
|
|
112
|
+
// 周日
|
|
113
|
+
startTime: '10:30',
|
|
114
|
+
endTime: '11:30'
|
|
115
|
+
}
|
|
116
|
+
};
|
|
117
|
+
const conflicts = checkConflicts([schedule1], schedule2);
|
|
118
|
+
expect(conflicts.length).toBe(0);
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
// 测试自定义冲突规则
|
|
122
|
+
it('should apply custom conflict rules', () => {
|
|
123
|
+
const schedule1 = {
|
|
124
|
+
id: 'timer_1',
|
|
125
|
+
type: EScheduleFunctionType.TIMER,
|
|
126
|
+
data: {
|
|
127
|
+
status: true,
|
|
128
|
+
weeks: [1, 0, 0, 0, 0, 0, 0],
|
|
129
|
+
// 周日
|
|
130
|
+
startTime: '10:00',
|
|
131
|
+
endTime: '11:00'
|
|
132
|
+
}
|
|
133
|
+
};
|
|
134
|
+
const schedule2 = {
|
|
135
|
+
id: 'timer_2',
|
|
136
|
+
type: EScheduleFunctionType.TIMER,
|
|
137
|
+
data: {
|
|
138
|
+
status: true,
|
|
139
|
+
weeks: [1, 0, 0, 0, 0, 0, 0],
|
|
140
|
+
// 周日
|
|
141
|
+
startTime: '10:30',
|
|
142
|
+
endTime: '11:30'
|
|
143
|
+
}
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
// 自定义规则:永不冲突
|
|
147
|
+
|
|
148
|
+
const conflicts = checkConflicts([schedule1], schedule2, {
|
|
149
|
+
isConflict: () => false,
|
|
150
|
+
shouldIgnore: () => false
|
|
151
|
+
});
|
|
152
|
+
expect(conflicts.length).toBe(0);
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
// 测试生物节律类型的特殊处理
|
|
156
|
+
it('should handle RHYTHM type schedules correctly', () => {
|
|
157
|
+
const rhythmSchedule = {
|
|
158
|
+
id: EScheduleFunctionType.RHYTHM,
|
|
159
|
+
type: EScheduleFunctionType.RHYTHM,
|
|
160
|
+
data: {
|
|
161
|
+
status: true,
|
|
162
|
+
weeks: [1, 1, 1, 1, 1, 0, 0],
|
|
163
|
+
// 周一到周五
|
|
164
|
+
startTime: '00:00',
|
|
165
|
+
endTime: '23:59'
|
|
166
|
+
}
|
|
167
|
+
};
|
|
168
|
+
const timerSchedule = {
|
|
169
|
+
id: 'timer_1',
|
|
170
|
+
type: EScheduleFunctionType.TIMER,
|
|
171
|
+
data: {
|
|
172
|
+
status: true,
|
|
173
|
+
weeks: [0, 1, 0, 0, 0, 0, 0],
|
|
174
|
+
// 周一
|
|
175
|
+
startTime: '10:00',
|
|
176
|
+
endTime: '11:00'
|
|
177
|
+
}
|
|
178
|
+
};
|
|
179
|
+
const conflicts = checkConflicts([rhythmSchedule], timerSchedule);
|
|
180
|
+
expect(conflicts.length).toBe(1);
|
|
181
|
+
});
|
|
182
|
+
});
|
|
183
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|