hyper-scheduler 1.0.0
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/.editorconfig +21 -0
- package/.eslintrc.cjs +26 -0
- package/GEMINI.md +1 -0
- package/README.md +38 -0
- package/docs/.vitepress/config.ts +52 -0
- package/docs/README.md +120 -0
- package/docs/api/devtools.md +232 -0
- package/docs/api/index.md +178 -0
- package/docs/api/scheduler.md +322 -0
- package/docs/api/task.md +439 -0
- package/docs/api/types.md +365 -0
- package/docs/examples/index.md +295 -0
- package/docs/guide/best-practices.md +436 -0
- package/docs/guide/core-concepts.md +363 -0
- package/docs/guide/getting-started.md +138 -0
- package/docs/index.md +33 -0
- package/docs/public/logo.svg +54 -0
- package/examples/browser/index.html +354 -0
- package/examples/node/simple.js +36 -0
- package/examples/react-demo/index.html +12 -0
- package/examples/react-demo/package.json +23 -0
- package/examples/react-demo/src/App.css +212 -0
- package/examples/react-demo/src/App.jsx +160 -0
- package/examples/react-demo/src/main.jsx +9 -0
- package/examples/react-demo/vite.config.ts +12 -0
- package/examples/react-demo/yarn.lock +752 -0
- package/examples/vue-demo/index.html +12 -0
- package/examples/vue-demo/package.json +21 -0
- package/examples/vue-demo/src/App.vue +373 -0
- package/examples/vue-demo/src/main.ts +4 -0
- package/examples/vue-demo/vite.config.ts +13 -0
- package/examples/vue-demo/yarn.lock +375 -0
- package/package.json +51 -0
- package/src/constants.ts +18 -0
- package/src/core/retry-strategy.ts +28 -0
- package/src/core/scheduler.ts +601 -0
- package/src/core/task-registry.ts +58 -0
- package/src/index.ts +74 -0
- package/src/platform/browser/browser-timer.ts +66 -0
- package/src/platform/browser/main-thread-timer.ts +16 -0
- package/src/platform/browser/worker.ts +31 -0
- package/src/platform/node/debug-cli.ts +19 -0
- package/src/platform/node/node-timer.ts +15 -0
- package/src/platform/timer-strategy.ts +19 -0
- package/src/plugins/dev-tools.ts +101 -0
- package/src/types.ts +115 -0
- package/src/ui/components/devtools.ts +525 -0
- package/src/ui/components/floating-trigger.ts +102 -0
- package/src/ui/components/icons.ts +16 -0
- package/src/ui/components/resizer.ts +129 -0
- package/src/ui/components/task-detail.ts +228 -0
- package/src/ui/components/task-header.ts +319 -0
- package/src/ui/components/task-list.ts +416 -0
- package/src/ui/components/timeline.ts +364 -0
- package/src/ui/debug-panel.ts +56 -0
- package/src/ui/i18n/en.ts +76 -0
- package/src/ui/i18n/index.ts +42 -0
- package/src/ui/i18n/zh.ts +76 -0
- package/src/ui/store/dev-tools-store.ts +191 -0
- package/src/ui/styles/theme.css.ts +56 -0
- package/src/ui/styles.ts +43 -0
- package/src/utils/cron-lite.ts +221 -0
- package/src/utils/cron.ts +20 -0
- package/src/utils/id.ts +10 -0
- package/src/utils/schedule.ts +93 -0
- package/src/vite-env.d.ts +1 -0
- package/stats.html +4949 -0
- package/tests/integration/Debug.test.ts +58 -0
- package/tests/unit/Plugin.test.ts +16 -0
- package/tests/unit/RetryStrategy.test.ts +21 -0
- package/tests/unit/Scheduler.test.ts +38 -0
- package/tests/unit/schedule.test.ts +70 -0
- package/tests/unit/ui/DevToolsStore.test.ts +67 -0
- package/tsconfig.json +28 -0
- package/vite.config.ts +51 -0
- package/vitest.config.ts +24 -0
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
import { useState, useEffect, useRef } from 'react';
|
|
2
|
+
import { Scheduler, DevTools } from 'hyper-scheduler';
|
|
3
|
+
import './App.css';
|
|
4
|
+
|
|
5
|
+
function App() {
|
|
6
|
+
const [logs, setLogs] = useState([]);
|
|
7
|
+
const [isRunning, setIsRunning] = useState(false);
|
|
8
|
+
const schedulerRef = useRef(null);
|
|
9
|
+
const logBoxRef = useRef(null);
|
|
10
|
+
|
|
11
|
+
const addLog = (msg, type = 'info') => {
|
|
12
|
+
const time = new Date().toLocaleTimeString('zh-CN', {
|
|
13
|
+
hour12: false,
|
|
14
|
+
hour: '2-digit',
|
|
15
|
+
minute: '2-digit',
|
|
16
|
+
second: '2-digit'
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
setLogs(prev => {
|
|
20
|
+
const newLogs = [...prev, { time, msg, type }];
|
|
21
|
+
// 保持最近 50 条
|
|
22
|
+
if (newLogs.length > 50) return newLogs.slice(-50);
|
|
23
|
+
return newLogs;
|
|
24
|
+
});
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
// 自动滚动到底部
|
|
28
|
+
useEffect(() => {
|
|
29
|
+
if (logBoxRef.current) {
|
|
30
|
+
const el = logBoxRef.current;
|
|
31
|
+
// 简单的自动滚动逻辑:如果接近底部,则自动滚动
|
|
32
|
+
const isNearBottom = el.scrollHeight - el.scrollTop - el.clientHeight < 100;
|
|
33
|
+
if (isNearBottom || logs.length < 5) {
|
|
34
|
+
el.scrollTop = el.scrollHeight;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}, [logs]);
|
|
38
|
+
|
|
39
|
+
useEffect(() => {
|
|
40
|
+
// 准备插件
|
|
41
|
+
const plugins = [];
|
|
42
|
+
// 仅在开发模式下加载 DevTools,或者始终加载取决于需求
|
|
43
|
+
plugins.push(new DevTools({
|
|
44
|
+
theme: 'auto',
|
|
45
|
+
language: 'zh',
|
|
46
|
+
trigger: {
|
|
47
|
+
position: 'bottom-right',
|
|
48
|
+
backgroundColor: '#3b82f6'
|
|
49
|
+
}
|
|
50
|
+
}));
|
|
51
|
+
|
|
52
|
+
// 创建调度器
|
|
53
|
+
schedulerRef.current = new Scheduler({
|
|
54
|
+
debug: true,
|
|
55
|
+
plugins: plugins
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
// 主线程心跳 (明确指定 driver: 'main')
|
|
59
|
+
schedulerRef.current.createTask({
|
|
60
|
+
id: 'main-heartbeat',
|
|
61
|
+
schedule: '3s',
|
|
62
|
+
options: { driver: 'main' },
|
|
63
|
+
handler: () => addLog('❤️ [Main] 主线程心跳检测正常', 'error')
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
// Worker 线程心跳 (默认即为 Worker 驱动)
|
|
67
|
+
schedulerRef.current.createTask({
|
|
68
|
+
id: 'worker-heartbeat',
|
|
69
|
+
schedule: '5s',
|
|
70
|
+
handler: () => addLog('💙 [Worker] 后台线程任务执行中', 'info')
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
addLog('✨ 系统就绪,等待启动指令...', 'info');
|
|
74
|
+
|
|
75
|
+
return () => {
|
|
76
|
+
if (schedulerRef.current) {
|
|
77
|
+
schedulerRef.current.stop();
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
}, []);
|
|
81
|
+
|
|
82
|
+
const handleToggle = () => {
|
|
83
|
+
if (!schedulerRef.current) return;
|
|
84
|
+
|
|
85
|
+
if (isRunning) {
|
|
86
|
+
schedulerRef.current.stop();
|
|
87
|
+
addLog('⏹️ 调度器系统已停止', 'info');
|
|
88
|
+
} else {
|
|
89
|
+
schedulerRef.current.start();
|
|
90
|
+
addLog('🚀 调度器系统已启动', 'success');
|
|
91
|
+
}
|
|
92
|
+
setIsRunning(!isRunning);
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
return (
|
|
96
|
+
<div className="dashboard">
|
|
97
|
+
{/* 左侧控制区 */}
|
|
98
|
+
<div className="control-panel">
|
|
99
|
+
<div>
|
|
100
|
+
<div className="header">
|
|
101
|
+
<h1>Hyper Scheduler</h1>
|
|
102
|
+
<p>双线程任务调度演示 (React)</p>
|
|
103
|
+
</div>
|
|
104
|
+
|
|
105
|
+
<div className="task-status">
|
|
106
|
+
<div className="status-item">
|
|
107
|
+
<span className="status-dot dot-main"></span>
|
|
108
|
+
<div>
|
|
109
|
+
<strong>主线程任务</strong>
|
|
110
|
+
<div className="status-desc">每 3 秒 (driver: 'main')</div>
|
|
111
|
+
</div>
|
|
112
|
+
</div>
|
|
113
|
+
<div className="status-item">
|
|
114
|
+
<span className="status-dot dot-worker"></span>
|
|
115
|
+
<div>
|
|
116
|
+
<strong>Worker 任务</strong>
|
|
117
|
+
<div className="status-desc">每 5 秒 (driver: 'worker')</div>
|
|
118
|
+
</div>
|
|
119
|
+
</div>
|
|
120
|
+
</div>
|
|
121
|
+
</div>
|
|
122
|
+
|
|
123
|
+
<div>
|
|
124
|
+
<div className="actions">
|
|
125
|
+
<button
|
|
126
|
+
className={isRunning ? 'btn-stop' : 'btn-start'}
|
|
127
|
+
onClick={handleToggle}
|
|
128
|
+
>
|
|
129
|
+
<span style={{ marginRight: '8px' }}>{isRunning ? '⏹' : '▶'}</span>
|
|
130
|
+
{isRunning ? '停止调度器' : '启动调度器'}
|
|
131
|
+
</button>
|
|
132
|
+
</div>
|
|
133
|
+
<div className="info-tip">
|
|
134
|
+
💡 点击右下角悬浮球打开调试面板
|
|
135
|
+
</div>
|
|
136
|
+
</div>
|
|
137
|
+
</div>
|
|
138
|
+
|
|
139
|
+
{/* 右侧日志区 */}
|
|
140
|
+
<div className="log-panel">
|
|
141
|
+
<div className="log-header">
|
|
142
|
+
<h2>
|
|
143
|
+
<span>📋</span> 执行日志
|
|
144
|
+
</h2>
|
|
145
|
+
<div style={{ fontSize: '12px', color: '#64748b' }}>实时监控中...</div>
|
|
146
|
+
</div>
|
|
147
|
+
<div className="log-box" ref={logBoxRef}>
|
|
148
|
+
{logs.map((log, index) => (
|
|
149
|
+
<div key={index} className={`log-item log-type-${log.type}`}>
|
|
150
|
+
<span className="log-time">{log.time}</span>
|
|
151
|
+
<span className="log-content">{log.msg}</span>
|
|
152
|
+
</div>
|
|
153
|
+
))}
|
|
154
|
+
</div>
|
|
155
|
+
</div>
|
|
156
|
+
</div>
|
|
157
|
+
);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
export default App;
|