Files
andyesfly f4454ad014 feat: 新增电工APP端与定时任务管理功能
- 新增电工APP独立鉴权中间件与登录注册接口
- 新增定时任务管理模块,支持任务配置、执行日志与手动触发
- 新增运维费定价与电工派单成本价目管理
- 新增电工资质证照管理与到期提醒定时任务
- 完善数据库实体与DTO校验,优化权限控制
2026-10-02 16:08:00 +08:00

124 lines
8.5 KiB
PL/PgSQL
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
-- 定时任务管理功能扩展
-- 背景:系统周期性后台作业(物化视图刷新、日志清理等)分散在 pg_cron 与应用 @midwayjs/cron 注解中,
-- 运维无法在管理端查看/启停/调频/追溯执行记录。本期新增「自研轻量调度器 + 内置任务注册表」,
-- 新增 sys_job(任务定义与调度配置)、sys_job_log(执行日志)两张表,
-- 并挂载系统管理下的「定时任务」菜单与按钮权限。
-- 幂等:建表/索引用 IF NOT EXISTS;菜单/角色绑定用 ON CONFLICT;任务种子用 ON CONFLICT (job_key) DO NOTHING。
-- 注意:菜单 id 47-50,避开并行规格 add-om-pricing-and-worker-registry 已占用的 34-46。
BEGIN;
-- ------------------------------------------------------------
-- 1) 任务定义与调度配置表
-- ------------------------------------------------------------
CREATE TABLE IF NOT EXISTS sys_job (
id BIGSERIAL PRIMARY KEY,
job_key VARCHAR(64) NOT NULL UNIQUE, -- 任务键,与代码注册表一一对应
job_name VARCHAR(64) NOT NULL, -- 任务名称
cron_expression VARCHAR(64) NOT NULL, -- cron 表达式
params JSONB NOT NULL DEFAULT '{}'::jsonb, -- 任务参数(受白名单约束)
retry_times SMALLINT NOT NULL DEFAULT 0, -- 失败后最大重试次数 0-5
retry_interval INT NOT NULL DEFAULT 60, -- 失败后重试间隔(秒 10-3600)
status SMALLINT NOT NULL DEFAULT 1, -- 1启用 0停用
remark VARCHAR(255), -- 备注
last_run_at TIMESTAMPTZ, -- 上次执行时间
last_run_status SMALLINT, -- 上次执行状态:1成功 2失败 3跳过
last_run_cost_ms INT, -- 上次执行耗时(毫秒)
last_error TEXT, -- 上次失败原因(成功时清空)
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
COMMENT ON TABLE sys_job IS '定时任务定义与调度配置表';
COMMENT ON COLUMN sys_job.id IS '自增主键';
COMMENT ON COLUMN sys_job.job_key IS '任务键,与代码注册表一一对应';
COMMENT ON COLUMN sys_job.job_name IS '任务名称';
COMMENT ON COLUMN sys_job.cron_expression IS 'cron 表达式(分 时 日 月 周,支持 6 段带秒)';
COMMENT ON COLUMN sys_job.params IS '任务参数(受白名单字段约束)';
COMMENT ON COLUMN sys_job.retry_times IS '失败后最大重试次数 0-5';
COMMENT ON COLUMN sys_job.retry_interval IS '失败后重试间隔(秒 10-3600)';
COMMENT ON COLUMN sys_job.status IS '状态:1启用 0停用';
COMMENT ON COLUMN sys_job.remark IS '备注';
COMMENT ON COLUMN sys_job.last_run_at IS '上次执行时间';
COMMENT ON COLUMN sys_job.last_run_status IS '上次执行状态:1成功 2失败 3跳过';
COMMENT ON COLUMN sys_job.last_run_cost_ms IS '上次执行耗时(毫秒)';
COMMENT ON COLUMN sys_job.last_error IS '上次失败原因(成功时清空)';
COMMENT ON COLUMN sys_job.created_at IS '创建时间';
COMMENT ON COLUMN sys_job.updated_at IS '更新时间';
CREATE UNIQUE INDEX IF NOT EXISTS uk_sys_job_key ON sys_job (job_key);
CREATE INDEX IF NOT EXISTS idx_sys_job_status ON sys_job (status);
-- ------------------------------------------------------------
-- 2) 任务执行日志表
-- ------------------------------------------------------------
CREATE TABLE IF NOT EXISTS sys_job_log (
id BIGSERIAL PRIMARY KEY,
job_id BIGINT NOT NULL REFERENCES sys_job(id) ON DELETE CASCADE, -- 任务ID(→ sys_job.id)
job_key VARCHAR(64) NOT NULL, -- 任务键(冗余,便于查询)
job_name VARCHAR(64) NOT NULL, -- 任务名称(冗余)
trigger_type SMALLINT NOT NULL DEFAULT 1, -- 触发方式:1定时自动 2手动触发 3失败重试
status SMALLINT NOT NULL, -- 1成功 2失败 3跳过
attempt SMALLINT NOT NULL DEFAULT 1, -- 第几次尝试
started_at TIMESTAMPTZ, -- 开始时间
finished_at TIMESTAMPTZ, -- 结束时间
cost_ms INT, -- 执行耗时(毫秒)
message TEXT, -- 结果摘要
error_stack TEXT, -- 异常堆栈(截断 4000 字符)
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
COMMENT ON TABLE sys_job_log IS '定时任务执行日志表';
COMMENT ON COLUMN sys_job_log.id IS '自增主键';
COMMENT ON COLUMN sys_job_log.job_id IS '任务ID(→ sys_job.id)';
COMMENT ON COLUMN sys_job_log.job_key IS '任务键(冗余,便于查询)';
COMMENT ON COLUMN sys_job_log.job_name IS '任务名称(冗余)';
COMMENT ON COLUMN sys_job_log.trigger_type IS '触发方式:1定时自动 2手动触发 3失败重试';
COMMENT ON COLUMN sys_job_log.status IS '执行状态:1成功 2失败 3跳过';
COMMENT ON COLUMN sys_job_log.attempt IS '第几次尝试';
COMMENT ON COLUMN sys_job_log.started_at IS '开始时间';
COMMENT ON COLUMN sys_job_log.finished_at IS '结束时间';
COMMENT ON COLUMN sys_job_log.cost_ms IS '执行耗时(毫秒)';
COMMENT ON COLUMN sys_job_log.message IS '结果摘要';
COMMENT ON COLUMN sys_job_log.error_stack IS '异常堆栈(截断 4000 字符)';
COMMENT ON COLUMN sys_job_log.created_at IS '创建时间';
CREATE INDEX IF NOT EXISTS idx_sys_job_log_job_created ON sys_job_log (job_id, created_at DESC);
CREATE INDEX IF NOT EXISTS idx_sys_job_log_created ON sys_job_log (created_at);
-- ------------------------------------------------------------
-- 3) 菜单与权限(系统管理 parent_id=6 下新增「定时任务」菜单 + 3 个按钮权限)
-- ------------------------------------------------------------
INSERT INTO sys_menu (id, parent_id, menu_name, menu_path, component, icon, sort_order, menu_type, permission, visible) VALUES
(47, 6, '定时任务', '/system/job', 'system/job/index', 'ClockCircleOutlined', 6, 2, 'system:job', 1),
(48, 47, '编辑定时任务', NULL, NULL, NULL, 1, 3, 'system:job:update', 1),
(49, 47, '立即执行', NULL, NULL, NULL, 2, 3, 'system:job:run', 1),
(50, 47, '清理日志', NULL, NULL, NULL, 3, 3, 'system:job:log:clear', 1)
ON CONFLICT (id) DO UPDATE SET
parent_id = EXCLUDED.parent_id,
menu_name = EXCLUDED.menu_name,
menu_path = EXCLUDED.menu_path,
component = EXCLUDED.component,
icon = EXCLUDED.icon,
sort_order = EXCLUDED.sort_order,
menu_type = EXCLUDED.menu_type,
permission = EXCLUDED.permission,
visible = EXCLUDED.visible;
-- 角色绑定:ADMIN(role_id=1)拥有 47~50
INSERT INTO sys_role_menu (role_id, menu_id) VALUES
(1, 47), (1, 48), (1, 49), (1, 50)
ON CONFLICT (role_id, menu_id) DO NOTHING;
-- 重置 sys_menu 自增序列,避免后续插入 id 冲突
SELECT setval('sys_menu_id_seq', 50, true);
-- ------------------------------------------------------------
-- 4) sys_job 内置任务种子(按 job_key 幂等)
-- ------------------------------------------------------------
INSERT INTO sys_job (job_key, job_name, cron_expression, params, retry_times, retry_interval, status, remark) VALUES
('demo_heartbeat', '示例心跳', '*/5 * * * *', '{"message":"heartbeat"}'::jsonb, 0, 60, 1,
'示例心跳任务:用于验证调度链路,默认每 5 分钟写入一条 info 日志'),
('log_clean', '日志清理', '0 3 * * *', '{"keepDays":90}'::jsonb, 2, 60, 1,
'日志清理任务:每日 03:00 清理早于 keepDays 天的操作日志与任务日志,默认保留 90 天')
ON CONFLICT (job_key) DO NOTHING;
COMMIT;