# OmniScheduler 开发指导 本文档面向参与 OmniScheduler 开发、构建和发布的维护者。 ## 技术栈 - 语言:C# - 运行时:.NET 8 - 框架:WPF - 目标平台:Windows - 项目类型:WinExe - 项目文件:`OmniScheduler/OmniScheduler.csproj` 项目启用了: - `UseWPF` - `UseWindowsForms` 其中 Windows Forms 主要用于系统托盘 `NotifyIcon`。 ## 目录结构 ```text . ├── OmniScheduler/ │ ├── App.xaml │ ├── MainWindow.xaml │ ├── MainWindow.xaml.cs │ ├── Models.cs │ ├── Services.cs │ ├── SettingsWindow.xaml │ ├── SettingsWindow.xaml.cs │ ├── TaskEditorWindow.xaml │ ├── TaskEditorWindow.xaml.cs │ └── OmniScheduler.csproj ├── app.ico ├── README.md ├── DEVELOPMENT.md └── PRD.md ``` ## 主要模块 ### `Models.cs` 定义核心数据模型: - `SchedulerState`:应用整体状态,包含任务、日志和设置。 - `AppSettings`:全局设置,例如 OmniNotify API 地址和日志保留策略。 - `ScheduledTask`:单个调度任务。 - `TaskTrigger`:任务触发器。 - `ExecutionLog`:执行日志。 触发器类型由 `TriggerKind` 定义: - `OneTime` - `Interval` - `Daily` - `Weekly` - `Monthly` - `Cron` ### `Services.cs` 包含应用服务层: - `StateStore`:负责读取和保存 `%LOCALAPPDATA%\OmniScheduler\state.json`。 - `NotifyClient`:负责向 OmniNotify API 发送 JSON 请求。 - `SchedulerService`:调度循环、任务触发、手动触发和补偿策略处理。 - `NextRunCalculator`:计算下次执行时间和未来执行预览。 ### `MainWindow` 主界面,负责: - 任务列表展示 - 日志列表展示 - 新建、编辑、删除、克隆、手动触发任务 - 全局暂停/恢复 - 托盘菜单与隐藏窗口行为 ### `TaskEditorWindow` 任务编辑窗口,包含三个页签: - 常规 - 触发器 - 消息动作 触发器页会根据 `TriggerKind` 动态切换配置区域。时间输入应优先使用日期选择器、下拉框、按钮等结构化控件,避免要求用户手写时间格式。 ### `SettingsWindow` 全局设置窗口。当前支持: - OmniNotify API 地址 - 日志保留天数 - 最大日志条数 为了降低对用户系统的影响,项目不提供开机自启功能,也不写入 Windows 启动项。 ## 本地开发 ### 环境要求 - Windows - .NET 8 SDK - 支持 WPF 的开发环境,例如 Visual Studio、Rider 或 VS Code + .NET SDK ### 还原与构建 ```powershell dotnet restore .\OmniScheduler\OmniScheduler.csproj dotnet build .\OmniScheduler\OmniScheduler.csproj ``` 如果本地正在运行 `OmniScheduler.exe`,构建可能因为 `bin` 目录文件被锁定而失败。可以先退出应用,或临时输出到其他目录: ```powershell dotnet build .\OmniScheduler\OmniScheduler.csproj -p:OutDir=.\obj\codex-verify\ ``` ### 运行 ```powershell dotnet run --project .\OmniScheduler\OmniScheduler.csproj ``` 也可以直接运行构建后的 exe。 ## 数据存储 运行时数据保存在: ```text %LOCALAPPDATA%\OmniScheduler\state.json ``` `StateStore` 会在文件不存在或读取失败时创建默认状态。默认任务用于 OmniNotify 连通性测试,并保持禁用,避免首次启动自动发送消息。 ## 调度规则开发注意事项 - 所有下次执行时间计算应集中在 `NextRunCalculator`。 - UI 里的触发器摘要来自 `TaskTrigger.Summary`。 - 修改触发器模型时,需要同步检查: - 克隆逻辑:`TaskTrigger.Clone` - 摘要逻辑:`TaskTrigger.Summary` - 下次执行计算:`NextRunCalculator.NextRun` - 任务编辑窗口加载与保存:`TaskEditorWindow` - 对用户可见的时间输入,优先使用结构化控件,不新增要求用户记忆格式的文本输入。 ## OmniNotify API 约定 `NotifyClient` 发送 `POST` 请求,Content-Type 为 `application/json`: ```json { "channel": "default", "title": "标题", "body": "内容" } ``` 发送前会替换以下变量: - `{CurrentTime}` - `{TaskName}` - `{TriggerType}` 响应状态码非 2xx 时,日志级别记为 `ERROR`。如果响应中包含 `IllegalChannel`,错误消息会提示检查频道名。 ## 托盘图标 项目图标由根目录 `app.ico` 提供: - `ApplicationIcon` 用于嵌入 exe 图标。 - `Resource Include="..\app.ico"` 用于 WPF 窗口图标资源。 - 托盘图标从当前进程 exe 的关联图标读取,不依赖发布目录中的独立 `app.ico` 文件。 发布包中不应包含外置 `app.ico`。 ## 发布构建 首次发布使用 framework-dependent、多文件包,不内置运行时,不启用 single-file: ```powershell dotnet publish .\OmniScheduler\OmniScheduler.csproj ` -c Release ` -r win-x64 ` --self-contained false ` -p:PublishSingleFile=false ` -p:PublishReadyToRun=false ` -p:DebugType=none ` -p:DebugSymbols=false ` -p:PublishDir=..\artifacts\OmniScheduler-v0.1.0-win-x64\ ``` 压缩包命名建议遵循 GitHub Release 常见格式: ```text OmniScheduler-v0.1.0-win-x64.zip ``` 压缩: ```powershell Compress-Archive ` -Path .\artifacts\OmniScheduler-v0.1.0-win-x64 ` -DestinationPath .\artifacts\OmniScheduler-v0.1.0-win-x64.zip ``` 计算校验值: ```powershell Get-FileHash .\artifacts\OmniScheduler-v0.1.0-win-x64.zip -Algorithm SHA256 ``` 发布包预期包含: ```text OmniScheduler.exe OmniScheduler.dll OmniScheduler.deps.json OmniScheduler.runtimeconfig.json ``` ## Git 与提交规范 提交信息使用 Conventional Commits: ```text [optional scope]: [optional body] ``` 示例: ```text feat: 优化触发器配置体验 - 根据触发器类型动态展示对应配置区域。 - 增加单次执行的延后快捷设置。 ``` 常用 type: - `feat`:新增功能 - `fix`:修复问题 - `docs`:文档变更 - `refactor`:重构 - `chore`:构建、发布、工具或维护性变更 ## 版本标签 创建版本标签: ```powershell git tag -a v0.1.0 -m "v0.1.0" git push origin v0.1.0 ``` 如果发布内容修正后需要移动尚未正式发布的标签,应明确确认后再执行: ```powershell git tag -fa v0.1.0 -m "v0.1.0" git push --force origin v0.1.0 ``` ## 质量检查清单 提交前建议确认: - `dotnet build` 通过。 - 触发器编辑窗口能正常切换各触发类型。 - 单次执行快捷设置能正确回填日期时间。 - Cron 预览可显示未来执行时间或明确错误提示。 - 发送测试消息不会要求保存任务。 - 发布包不包含 `app.ico`、PDB、运行时目录或其他多余文件。 - 程序关闭后能隐藏到托盘,托盘菜单可打开、暂停和退出。