- 新增电工APP独立鉴权中间件与登录注册接口 - 新增定时任务管理模块,支持任务配置、执行日志与手动触发 - 新增运维费定价与电工派单成本价目管理 - 新增电工资质证照管理与到期提醒定时任务 - 完善数据库实体与DTO校验,优化权限控制
5.3 KiB
5.3 KiB
Checklist
数据库与种子
database/migrations/20261002_job_management.sql已创建,建sys_job与sys_job_log两表及索引,可重复执行无报错sys_job含job_key唯一索引与status索引;params为 JSONB 且默认{}sys_job_log含(job_id, created_at DESC)与created_at索引- 迁移写入菜单 id 47(定时任务,parent_id=6,
/system/job,system:job,menu_type=2,sort_order=6)与 48/49/50 三个按钮权限(parent_id=47,menu_type=3) - ADMIN 角色(role_id=1)已绑定菜单 47-50;
sys_menu_id_seq被设为 50 - 迁移写入
demo_heartbeat(*/5 * * * *)与log_clean(0 3 * * *,retry_times=2、retry_interval=60)两条sys_job种子,重复执行不产生重复行 database/db_seed.sql已同步菜单 47-50、ADMIN 绑定、2 条sys_job种子与sys_menu_id_seq=50;新库初始化与迁移后结构一致- 既有菜单 id 7-11 的名称、路径、排序未被改动
后端
server/package.json已显式声明cron依赖,yarn dev可正常编译启动- 内置任务注册表
server/src/task/job_registry.ts提供jobKey/jobName/description/defaultCron/defaultParams/paramFields/handler,页面参数表单由paramFields驱动,无需前端硬编码 demo_heartbeat与log_clean两个内置任务均已注册,job_key与种子数据一致- 调度器启动加载全部启用任务,停用任务不被调度
- 调度初始化失败时不阻塞应用启动(try/catch + 最多 3 次重试),
onStop停止全部定时器 - 页面修改 cron 后无需重启即按新表达式触发,列表
nextRunTime同步更新 - 提交非法 cron 表达式返回 400 且提示明确,配置未落库
- 停用任务后定时触发停止,
nextRunTime为null/-,但仍可手动执行 - 同一任务执行中再次触发时写
status = 3跳过日志且不并发执行 - 失败且
attempt <= retry_times时按retry_interval秒后以trigger_type = 3重试,attempt递增 sys_job.last_run_at / last_run_status / last_run_cost_ms / last_error每次执行后正确回写(成功时清空last_error)log_clean同时清理sys_operation_log与sys_job_log,摘要含两张表删除条数,默认keepDays = 90keepDays越界(如 0 或 5000)返回 400,配置未落库GET /api/jobs支持任务名称模糊与状态筛选,返回分页结构并携带paramFields、nextRunTime、上次执行信息PUT /api/jobs/:id、PUT /api/jobs/:id/status、POST /api/jobs/:id/run、GET /api/jobs/:id/logs、DELETE /api/jobs/logs/clear均可用且返回统一结构- 静态路由
/api/jobs/logs/clear未被:id动态路由吞掉 error_stack落库被截断至 4000 字符,message摘要可读- 未注册的
job_key在页面标记为未注册,编辑/启停/执行返回 400「任务实现不存在」 PERMISSION_MAP已新增'/api/jobs': 'system:job',非 ADMIN 无该权限时访问返回 403- 所有查询/更新走 Sequelize 参数化 API,无字符串拼接 SQL 与模板字符串 LIKE
- 控制器入参使用 DTO +
class-validator,未滥用any(除既有约定处) - 列表接口均使用
limit + offset分页,无全表扫描式查询 - 调度器为进程内单例(
@Scope(ScopeEnum.Singleton)),保证「启动注册」与「接口重载」操作同一个定时器注册表
前端
client/src/api/job.ts提供 6 个接口方法与 TS 类型client/src/views/system/job/index.vue含搜索栏 + 表格 + 编辑弹窗 + 立即执行二次确认 + 执行日志抽屉- 表格列包含任务名/键、cron、参数摘要、状态开关、上次执行时间与状态与耗时、下次执行时间、重试配置
- 编辑弹窗中 cron、参数、重试次数、重试间隔可编辑,且保存前后端校验失败时弹窗保留并提示 message
- 执行日志抽屉支持分页、状态筛选与「清理日志」二次确认(默认清理 90 天前)
- 路由
/system/job已注册,meta.permission = 'system:job' - 侧边栏「系统管理」下可见「定时任务」(ADMIN),非 ADMIN 访问跳转 403
- 页面未使用
v-html,cron 与参数输入含长度/范围校验 - 页面结构与既有页面(操作日志 / 数据字典)保持一致,未引入多余 UI 元素
联调
- 后端
yarn dev启动无编译错误,接口逐条通过 - 前端
yarn dev启动,编辑 → 立即执行 → 查看日志 → 清理日志 全链路可用 - 改 cron 即时生效与启停即时生效已验证
- 重试机制(
trigger_type = 3、attempt递增)已验证 - 迁移脚本与
db_seed.sql在空库与存量库两端结果一致 - 隔离单实例复测:
*/1每分钟恰好触发 1 次、停用后 0 次触发、手动执行正常、恢复后nextRunTime正确(见 tasks.md Task 8)
遗留说明(非阻塞)
sys_job.job_key同时存在列级UNIQUE自动生成的sys_job_job_key_key与显式uk_sys_job_key,两个索引功能重复(冗余但无害,不影响验收)- 非法入参返回的是响应体
code=400,HTTP 状态保持 200,与仓库既有 26 个控制器的约定一致