# WebQuartz **Repository Path**: ghost_lin/WebQuartz ## Basic Information - **Project Name**: WebQuartz - **Description**: No description available - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-02-01 - **Last Updated**: 2026-10-18 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # WebQuartz 定时任务调度平台 一套前端 + 三后端(JAVA / Go / .NET)的定时任务调度平台,支持 HTTP / SQL 两种任务类型,提供 RBAC 权限管理、定时任务管理、执行日志管理、SQL 控制台、AI 对话助手等功能。**权限管理、任务管理、日志管理均支持通过 AI 对话完成。** 三个后端实现同一套 API 契约(路径、参数、响应、权限码完全一致),前端 `Web/` 无需修改即可对接任意一个后端。 ## 项目结构 ``` Quartz/ ├── JAVA/ # 后端服务(Spring Boot 3 + MyBatis Plus + Quartz,基准实现) ├── GO/ # Go 版本(gin + gorm + robfig/cron) ├── NET/ # .NET 版本(ASP.NET Core 8 + SqlSugar + Quartz.NET) ├── Web/ # 前端界面(Vue 3 + Vite + Element Plus,三后端共用) └── doc/ # 设计文档、迁移脚本、方案说明 ``` ## 技术栈对照 | 端 | 技术栈 | |---|---| | JAVA(基准) | Spring Boot 3.5 + Quartz + MyBatis-Plus + java-jwt + LangChain4j | | GO | gin + gorm + robfig/cron/v3 + golang-jwt/v5 + 标准库 OpenAI 兼容客户端 | | NET | ASP.NET Core 8 (Controller) + SqlSugarCore + Quartz.NET + JwtBearer + HttpClient 原生 AI 客户端 | | Web(共用) | Vue 3 + Vue Router + Pinia + Element Plus + Vite | 各端详细依赖与差异见各自目录的 README。 ## 功能需求清单 完整功能需求(FR-1 ~ FR-6)与三端对齐基准见 `doc/功能需求提取-三后端对齐.md`。 - **FR-1 认证与会话**:SM2 加密传输 + 双 Token(access/refresh)、登出吊销、修改密码、图形验证码、IP 白名单 - **FR-2 用户管理**:分页/详情/新增/更新/删除/批量删除/重置密码、SQL 控制台(执行/查询,白名单校验 + 审计) - **FR-3 权限管理(RBAC)**:角色管理、资源管理(菜单+按钮+接口授权码统一模型)、角色授权、用户角色分配、接口级授权码校验(403)、内存权限缓存 - **FR-4 定时任务管理**:CRUD、启动/停止/暂停/恢复、立即执行、批量操作、下次执行时间预览、Cron 校验、服务重启自动恢复 - **FR-5 日志管理**:执行日志分页/详情/删除/批量删除/清空 - **FR-6 AI 对话助手**:SSE 流式 + 同步对话、16 个 Function Calling 工具(任务/日志全操作)、会话持久化、错误分类、"只说不做"检测 ## 使用说明 ### 1. 启动后端(三选一) **JAVA 版(基准):** ```bash cd JAVA mvn spring-boot:run ``` **Go 版:** ```bash cd GO go mod tidy go run main.go # 首次启动 AutoMigrate 建表;配置见 config.yaml ``` **.NET 版:** ```bash cd NET # 默认 MySQL(appsettings.json "DbType" 可切 "SQLite");首次启动需以 Development 环境运行一次,触发 SqlSugar CodeFirst 建表 $env:ASPNETCORE_ENVIRONMENT='Development'; dotnet run # Windows PowerShell # MySQL 连接串密码在 appsettings.Development.json(gitignore,需自行创建); # QRTZ_* 持久化表由程序启动时按 DbType 自动执行 qrtz_mysql.sql / qrtz_sqlite.sql ``` 三端默认监听 `http://localhost:9010`。 ### 2. 启动前端 ```bash cd Web npm install npm run dev ``` Vite 代理已指向 `localhost:9010`,无需修改。 ### 3. 初始化权限种子数据(必须) 首次启动后,需向数据库导入权限资源种子数据(`SysResource` 表的授权码记录),否则所有带权限码的接口返回 403。 - **GO 版(MySQL)**:执行 `doc/初始化SQL-GO版-MySQL.sql`(含 admin 账号 + 54 项权限资源 + 超级角色授权,一键初始化) - **JAVA 版(MySQL)**:执行 `JAVA/src/main/resources/tables/tables_mysql.sql` 的种子段(与 GO 版同源) - **NET 版(MySQL)**:执行 `doc/初始化SQL-NET版-MySQL.sql`(与 GO 版同源,`IsVisible` 列显式赋值;库不存在时程序自动建库,库名见连接串) - **NET 版(SQLite)**:执行 `doc/初始化SQL-NET版-SQLite.sql`(同源 SQLite 方言转写) ### 4. 启用 AI 对话助手(可选) 三端统一使用 JAVA 版的同一模型配置(`sensenova-6.8-flash-lite` @ `https://token.sensenova.cn/v1`,OpenAI 兼容),API Key 统一从环境变量 `sk-key`(兼容 `SK_KEY`)读取,配置文件不落明文: ```powershell [Environment]::SetEnvironmentVariable("sk-key", "", "User") # 设置后重启后端进程(新进程才能读到) ``` - **GO**:`config.yaml` 的 `chat` 节(已对齐 JAVA,`enabled: true`) - **NET**:`appsettings.json` 的 `Chat` 节(已对齐 JAVA,`Enabled: true`) - **JAVA**:`application.yml` 的 `langchain4j.open-ai` 节(配置源头) 换用其他 OpenAI 兼容模型(OpenAI / DeepSeek / 通义 / 本地 Ollama 等)时,三端同步修改各自的模型地址与名称即可,模型需支持 Function Calling。 ## 权限模型(授权码方式) 从 2026-08-15 版本起,接口鉴权由 URI 前缀匹配升级为**授权码(PermissionCode)**方式: - 后端 Controller 方法使用 `@Permission(code = "USER_SAVE")` 声明所需授权码 - `SysResource` 表新增 `PermissionCode` 字段,type3 接口资源必填 - 切面通过授权码 O(1) 定位资源,再校验用户角色是否授权 - 多实例环境下通过 Redis pub/sub 同步本地权限缓存 详细设计见 `doc/20260815授权优化方案A-统一资源模型.md` 及 `doc/migration_permission_code.sql`。 ## 数据过滤(数据权限) 数据过滤方案与 RBAC 正交,用于控制用户进入接口后能看到的数据范围。设计文档见 `doc/20260815数据过滤方案.md`。 **当前状态**:方案已设计,尚未实施。 ## 更新日志 ### 2026-09-30 NET 版 MySQL 支持与任务执行链路修复 - **NET 数据库配置化**:`DbType` 支持 `MySql`(默认)/`SQLite` 切换,Quartz 持久化与 QRTZ DDL 按方言自动分支;新增 `NET/qrtz_mysql.sql`(Quartz 官方 InnoDB schema,布尔列 TINYINT(1) 适配 MySqlConnector);MySQL 连接串密码与入库配置分离(appsettings.Development.json,gitignore) - **NET 初始化 SQL(MySQL)**:新增 `doc/初始化SQL-NET版-MySQL.sql`(GO 版同源,`IsVisible` 列显式赋值) - **任务执行链路修复(SQLite 同样存在的真缺陷)**:新增任务 `ID:null` 致 `In(null)` 空引用 → 服务层判空自生成;执行日志 `ExecuteBody/ExecuteResult` varchar(255) 超长静默丢失 → 改 text;执行异常仅捕获 HttpRequestException 且 scope 在 try 外 → 全异常捕获 + 失败留痕 - **StartNowJob 契约对齐**:同步执行并返回 `{status, message, elapsed, error}`(原返回 bool 致执行成功也提示"执行失败:未知错误");前端 Cron 表单补默认值 - **AI 对话助手**:API Key 按三端约定写入用户级环境变量 `sk-key`,流式对话已验证可用 - **⚠ 已知问题:AI 对话助手仍有缺陷,待后续排查修复** - 详细清单见 `doc/更新日志-NET版MySQL支持与任务执行链路修复.md` ### 2026-09-29(四)NET 版联调修复与登录过期提示优化 - **定时任务保存 400(两类根因)**:非空 int 收 null(SQL 任务切行时 `HttpMethods/HttpBodyType` 被前端置 null)→ 新增 `NullAsDefaultIntConverter`(null→0,对齐 GO/JAVA 宽容绑定);非空 string 隐式 `[Required]`(`JobRemark: null` 被 400 拦截)→ `JobName/CronExpression/JobRemark` 补 `[ValidateNever]` - **补齐缺失字段**:NET 实体缺 `HttpTimeout`(GO 有),超时值此前无法持久化/回显,CodeFirst 已自动加列 - **同根因连锁修复**:`Role.RoleID`、`SysResource` 的 `ResourceID/ParentID/Icon/ApiPath/PermissionCode/RoutePath` 补 `[ValidateNever]`——否则角色/资源页新增(前端传 null ID、服务层自生成)同样必现 400 - **登录过期提示优化**:token 过期 401 时 `loadPermissions` 静默(拦截器已"单飞刷新→失败登出→跳登录"),不再弹误导性的"加载权限信息失败,请刷新重试";仅网络/服务真实异常才提示 - 详细清单见 `doc/更新日志-NET版联调修复与登录过期提示优化.md` ### 2026-09-29(三)NET 版启动修复与 SM3 算法对齐 - **NET 版首次成功运行**:修复 `no such table: QRTZ_JOB_DETAILS` 启动崩溃(新增 `NET/qrtz_sqlite.sql` 标准 DDL,`Program.cs` 启动时检测并自动初始化 QRTZ_* 11 张表);业务表建表原依赖首次注入触发且仅限 Development,现改为启动时主动执行 CodeFirst(QRTZ 补 `MISFIRE_ORIG_FIRE_TIME` 列对齐 Quartz 3.18 schema) - **NET 初始化 SQL**:新增 `doc/初始化SQL-NET版-SQLite.sql`(SQLite 方言转写 GO 版种子:INSERT OR IGNORE / datetime / `||` 拼接;`IsVisible` NOT NULL 列直接写入,AI 对话资源隐藏) - **三端密码哈希算法对齐(SM3 迭代 1000 次)**:NET `SM3Helper.HashPassword` 原为单次 SM3,现对齐 JAVA/GO 的迭代实现(首轮 password+salt,之后对哈希字节迭代,共 1000 次);admin 密码哈希三端通用,登录/改密/重置全兼容 - **SM2 加解密修复**:后端引擎由默认 C1C2C3 改为 `C1C3C2`(与前端 gm-crypto 一致,修复登录 500 `invalid cipher text`);解密改为"先补 0x04 前缀、失败回退原样"双格式兼容(消除约 1.2% 概率的偶发解密失败) - **NET 联调修复**:`GetByParent` 空 `parentID` 参数改可空(修复资源管理页 400);CORS 白名单补前端 3031 端口 - 验证:admin/123456 登录、退出重登、资源 54 项 / 角色 / 用户列表、定时任务页均正常 - 详细清单见 `doc/更新日志-NET版启动修复与SM3算法对齐.md` ### 2026-09-29(二)GO 版联调修复与 Cron 生成器替换 - **软删除过滤补齐(GO+NET 14 处)**:任务/用户/角色/资源的查询、详情、操作全面过滤已删除数据(原"删除后仍可见/可操作");`Save` 存在性判断防软删数据复活;NET `BaseRepositoyr.Page/GetByID` 的 IsDeleted 过滤生效(物理删除的日志表不受影响) - **前端批量操作**:去除跨页隐藏选中(所见即所得)、批量 ≤10 校验、确认框与结果显示记录数 - **GO 响应契约对齐**:单任务操作接口 `data:null` → `data:true`(JAVA Boolean 契约),修复"删除成功却报失败不刷新" - **Cron 生成器替换**:`no-vue3-cron`(强制 7 段,空值/6 段崩溃)→ `vue3-cron-ep`(支持 6/7 位、Element Plus 同栈、实时校验),直接内嵌任务表单(点输入框展开面板);任务状态表单内只读(状态由操作按钮驱动) - **GO 版初始化 SQL**:新增 `doc/初始化SQL-GO版-MySQL.sql`(admin 账号 + 54 项权限资源 + 超级角色一键初始化) - 其他:utils 空串解析报错消除、路由 chunk 失败防无限重载(sessionStorage 防重入) - 详细清单见 `doc/更新日志-GO版联调修复与Cron生成器替换.md` ### 2026-09-29(一)MemoryCache 缓存替换与三端 AI 模型统一 - **GO 版缓存底层替换**(方案来自 `D:\Projects\MemoryCache` 三平台内存缓存验证项目):新增 `MemoryCache` 统一缓存(内嵌 miniredis + go-redis,TTL 原生自动过期,含时钟同步修复与命中统计);替换 `TokenBlacklist`(删除手写 cleanupLoop)与登录失败计数(INCR+EXPIRE 滑动窗口,修复过期条目不删除的内存泄漏),对外 API 与语义不变。PermissionCache(主动失效型)与验证码存储设计性保留 - **三端 AI 模型统一**:GO / NET 对齐 JAVA 的模型配置(`sensenova-6.8-flash-lite` @ `https://token.sensenova.cn/v1`、温度 0.3、超时 60s),`enabled` 对齐 JAVA"配置即启用";API Key 统一从环境变量 `sk-key` 读取,配置文件不落明文;同步更新 GO 入库模板 `config.example.yaml` - **运行期修复**:GO 登录 403(CORS 白名单补 `127.0.0.1:3031`);`GetPublicKey` 500(补 `security.sm2` 密钥对) - 详细清单见 `doc/更新日志-MemoryCache缓存替换与AI模型统一.md` ### 2026-09-24 三后端功能对齐(GO / NET 补齐) 以前端 `Web/src/api/modules/*` API 契约为唯一基准(提取文档:`doc/功能需求提取-三后端对齐.md`),补齐 GO 与 NET 版本至与 JAVA 基准功能一致: **GO 版(`go build` / `go vet` 通过):** - 契约修正:`ResetPwd→ResetPassword`、`ExecuteSql→ExecuteSQL`、`SelectSql→SelectSQL`、日志 `GetByID` 路径参数、新增 `DelAll` - RBAC 整块:Role/SysResource 控制器与服务、`RequirePermission` 中间件接线、内存权限缓存、防自我提权与超管保护 - 新增 `GetNextFireTime`(cron.Next 预览下次执行时间)、`Logout`、`ChangePassword` - AI 对话助手:OpenAI 兼容客户端(工具循环≤5轮、SSE 逐 token、tool_calls 分片累加)、16 工具集(confirm 防误操作、归属校验)、SSE 三事件协议、`SysChatMessage` 持久化、错误分类(2001/2002/2003/2004/2005/500) - 配置:`config.yaml` 新增 `chat` 节与 `security.superRoleCode` **NET 版(`dotnet build` 0 错误 0 警告):** - RBAC 整块:Role/UserRole/SysResource/RoleResource 模型 + CodeFirst 建表、`PermissionCache` 内存缓存、`[Permission]` ActionFilter、Role/SysResource 控制器(防自我提权、超管保护、授权回显) - 契约对齐:日志路由路径参数 + `DelAll` + `Status` 字段、`ResetPassword`、`ExecuteSQL`/`SelectSQL`(白名单校验 + SysSqlAudit 审计)、`Logout`(refresh token 黑名单)、`ChangePassword` - 任务接口全部挂 FR-4 权限码,新增 `GetNextFireTime`(查调度器实时触发器) - AI 对话助手:ChatClient / ChatMessageService / JobTools / ChatController(SSE over POST,客户端断开自动终止) - 修复仓库原有遗留编译错误(HttpJob 反序列化、QuartzJobLogService 构造器、缺失 using、表达式树空传播等) **运行前提(三端一致):** 导入权限种子数据(`doc/migration_permission_code.sql`);AI 助手需配置 OpenAI 兼容 API Key 后启用。 ### 2026-08-29 部门审计字段 **已完成:** - `BaseEntity` 对称新增 9 个部门审计字段:`Create/Modify/Delete` × `DeptID/DeptName/DeptFullID`,与现有 `CreateUser/ModifyUser/DeleteUser` 同 `FieldFill` - `AutoFillHandler` 新增部门赋值方法:一次验签取 `UserID` + 部门三件套,`insertFill`/`updateFill`(含逻辑删除分支)对称填充;dept 值非空才写入 - `JwtHelper` 新增 `GetClaims(HttpServletRequest)` 批量取 claim(避免逐字段重复验签) - DDL:`Users`/`SysJob`/`SysResource`/`Role` 四表各加 9 列,覆盖 MySQL / PostgreSQL / SQL Server / H2 四方言 - 迁移脚本 `doc/migration_部门审计字段.sql`(MySQL 生效,pg/sqlserver 注释,H2 免执行) 详细清单见 `doc/更新日志-部门审计字段.md`。 **设计要点:** - 部门信息取自 access_token 的 `DeptID/DeptName/DeptFullID` claim(与 `UserID` 同源),需在登录签发 token 时写入 - 灰度安全:MyBatis-Plus 默认 `NOT_NULL` 策略省略 null 字段,加列前后均不破坏存量流程;推荐顺序:部署代码 → 执行迁移加列 → 登录侧写 claim - 未做:部门数据源(无部门表,由后续接入 SSO/自建)、前端部门展示、pg/h2/sqlserver 分离列注释语句 ### 2026-08-16 权限管理完善 补齐 2026-08-15 授权码改造遗留的权限项:前端按钮级显隐、AI 入口显隐、隐藏但可授权、启动期一致性校验。仅改动权限相关代码,未触碰业务逻辑。 **已完成:** - 前端按钮显隐:新增 `GET /api/SysResource/GetCurrentAuthorized` 返回当前用户授权码集合;前端 `stores/permission.js` 提供 `hasPermission(code)` / `hasAny()`,Users/QuartzJob/Role/Resource/JobExecuteLog/ExecuteSQL/Authorize 操作按钮按授权码显隐,与后端 `@Permission(code)` 一一对应 - AI 入口显隐:`Home.vue` AI 按钮按 `CHAT_STREAM/CHAT_SEND/CHAT_CLEAR` 任一码显隐,未授权用户不再可见(后端仍鉴权) - `IsVisible` 字段:`SysResource` 新增列(四方言 + 迁移脚本),`1=菜单树可见 / 0=隐藏但可授权`;`GetCurrentMenus` 过滤 `IsVisible=1`,授权页「显示隐藏资源」开关可勾选隐藏资源(如 AI) - `PermissionScanner`:启动期扫描所有 `@Permission(code)` 注解与资源表登记码比对,漂移告警(注解有/表无 → 切面将 403;表有/注解无 → 疑似废弃资源) 详细清单见 `doc/更新日志-权限管理完善.md`。验证:Java `mvn compile` 通过;`npm run build` 通过。 **明确未做(待确认):** - 数据过滤(`@DataScope` + MyBatis Plus 拦截器):方案文档标注「审阅后再决定是否实施」,且会改写 SysJob/SysJobLog/Users 业务查询 SQL,超出纯权限改动范围,待确认后实施 - 层级授权(授权 type2 页面自动覆盖其下 type3 接口):当前为直接授权模型,可选增强 ### 2026-08-16 功能与性能审查整改 **已完成:** - AI 流式对话:`QuartzJobTools` 改 per-request 实例(携带用户上下文与事件收集器),移除 `InheritableThreadLocal` 与静态 `ToolCallEventBus`,修复流式路径 `tool_calls` 事件丢失与跨用户身份泄露 - Quartz 集群:立即执行改按触发时刻轮询共享日志表(移除 per-JVM `future`),启动恢复收窄 `ObjectAlreadyExistsException` 捕获 - `JsonHelper` 移除全局 `String` 反序列化器(数据腐化 + CPU 税),`TimestampDeserializer` 解析失败返回 null - 数据完整性:分页 pageSize 下限、逻辑删除批量 `UPDATE`、check-then-insert `@Transactional`、Redis `incr+expire` Lua 原子化 - 前端 token 刷新:同步写 Pinia store、SSE 401 自动刷新重试、`isRefreshing` 锁、刷新请求静默 - 前端功能:`Authorize` 半选父节点不再级联放大、`GetQuery` 空末页递归与陈旧响应守卫、`Users` 重复 key、`KeyValueTable` 改 prop、`Resource` 懒树缓存清理 - 性能:日志清理批删、`AsyncConfig` 清理与 `AbortPolicy`、`AiChat` 渲染缓存、`MenuTree` 图标具名导入等 详细清单见 `doc/更新日志-功能性能审查整改.md`。 **明确未改(设计性保留 / 非缺陷):** - `UpdateJob` 调度器失败补偿写回快照(M14 既定设计,改回会逆转"调度器慢操作不持库连接") - SSE 背压(`SseEmitter` 无原生背压,真解需迁 WebFlux;`send` IOException + 超时已兜底) ### 2026-08-15 授权码鉴权改造 **已完成:** - `@Permission` 注解改为必填 `code`,所有 Controller 方法补齐授权码 - `PermissionAspect` 改为按授权码 O(1) 定位资源,不再依赖 URI 前缀匹配 - `PermissionCache` 增加 `codeResources` 缓存与 Redis pub/sub 跨实例刷新 - `SysResource` 实体与四套种子 SQL(MySQL/PostgreSQL/SQL Server/H2)新增 `PermissionCode` 字段并补全授权码 - `RedisService` 新增 `Publish` / `Subscribe` 能力,支持内置 Redis Mock 与真实 Redis - 修复 `SqlSafetyHelper` 中 `Statements.getStatements()` 弃用警告 - 新增迁移脚本 `doc/migration_permission_code.sql` - 新增设计文档: - `doc/20260815授权优化方案A-统一资源模型.md` - `doc/20260815数据过滤方案.md` **明确未做(需在后续迭代完成):** - 数据过滤(`@DataScope` + MyBatis Plus 拦截器)仅完成方案设计,未写代码(方案文档 `doc/20260815数据过滤方案.md` 标注"审阅后再决定是否实施",且会改写业务表 SQL,超出纯权限改动范围,待确认后实施) - 层级授权(授权 type2 页面自动覆盖其下 type3 接口)未实现:当前为直接授权模型,授权某接口需显式勾选该 type3 资源 ## 生产部署注意事项 - **JWT 密钥**:`jwt.access-secret-key` / `refresh-secret-key` 须替换为随机强密钥。 - **SM2 密钥对**:须重新生成并替换,私钥不入版本库。 - **Redis**:生产环境 `infra.redis.mock-enabled` 必须设为 `false`,指向真实 Redis。 - **SQL 执行接口**:`/api/Admin/ExecuteSQL`、`/api/Admin/SelectSQL` 应限制管理员角色并配合 IP 白名单使用。 - **数据库迁移**:从旧版本升级需执行 `doc/migration_permission_code.sql`。 ## 数据表结构 > 最新表结构以 `JAVA/src/main/resources/tables/` 下对应方言 SQL 为准,README 中不再重复维护。 旧版表结构参考见 `JAVA/src/main/resources/tables/tables_mysql.sql`。