feat: 新增电工APP端与定时任务管理功能
- 新增电工APP独立鉴权中间件与登录注册接口 - 新增定时任务管理模块,支持任务配置、执行日志与手动触发 - 新增运维费定价与电工派单成本价目管理 - 新增电工资质证照管理与到期提醒定时任务 - 完善数据库实体与DTO校验,优化权限控制
This commit is contained in:
1 parent
1803ad679c
commit
f4454ad014
57 files changed
+9388
-200
No files matched your search
@@ -0,0 +1,19 @@
|
||||
import { Inject } from "@midwayjs/core";
|
||||
import { Job, IJob } from "@midwayjs/cron";
|
||||
import { NoticeService } from "../service/notice.service";
|
||||
|
||||
/**
|
||||
* 电工资质证照到期提醒定时任务
|
||||
* 每天 08:00 扫描 worker_cert 中 30 天内到期或已过期的证照,
|
||||
* 为每个 ADMIN 生成一条站内通知(幂等,已存在的提醒不会重复生成)。
|
||||
*/
|
||||
@Job({ cronTime: "0 0 8 * * *", start: true, timeZone: "Asia/Shanghai" })
|
||||
export class CertExpireTask implements IJob {
|
||||
@Inject()
|
||||
noticeService!: NoticeService;
|
||||
|
||||
async onTick() {
|
||||
const result = await this.noticeService.scanCertExpireAndNotify();
|
||||
console.log(`[cert-expire] 证照到期扫描完成:扫描 ${result.scanned} 条,新增通知 ${result.created} 条`);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
import dayjs from "dayjs";
|
||||
import type { BuiltinJob } from "./job_registry";
|
||||
|
||||
/**
|
||||
* 示例心跳任务:用于验证调度链路是否打通。
|
||||
* 默认每 5 分钟执行一次,写一条 info 日志并返回本次心跳时间。
|
||||
*/
|
||||
export const demoHeartbeatJob: BuiltinJob = {
|
||||
jobKey: "demo_heartbeat",
|
||||
jobName: "示例心跳",
|
||||
description: "用于验证调度链路的示例任务,按周期写入一条心跳日志",
|
||||
defaultCron: "*/5 * * * *",
|
||||
defaultParams: { message: "heartbeat" },
|
||||
paramFields: [
|
||||
{ key: "message", label: "心跳内容", type: "string", placeholder: "默认 heartbeat" }
|
||||
],
|
||||
handler: (params, ctx) => {
|
||||
throw new Error("E2E 重试验证");
|
||||
const now = dayjs().format("YYYY-MM-DD HH:mm:ss");
|
||||
const message = params?.message ?? "heartbeat";
|
||||
ctx.runtime.logger.info(`[${ctx.jobKey}] 心跳 ${now}(message=${message})`);
|
||||
return `心跳正常:${now}(message=${message})`;
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,59 @@
|
||||
import { demoHeartbeatJob } from "./demo_heartbeat.task";
|
||||
import { logCleanJob } from "./log_clean.task";
|
||||
|
||||
export type JobParamType = "number" | "string";
|
||||
|
||||
/** 可编辑参数白名单字段(前端表单由它驱动渲染) */
|
||||
export interface JobParamField {
|
||||
key: string;
|
||||
label: string;
|
||||
type: JobParamType;
|
||||
min?: number; // type=number 时的最小值
|
||||
max?: number; // type=number 时的最大值
|
||||
placeholder?: string;
|
||||
}
|
||||
|
||||
export interface JobLogger {
|
||||
info(message: string, ...args: any[]): void;
|
||||
warn(message: string, ...args: any[]): void;
|
||||
error(message: string, ...args: any[]): void;
|
||||
}
|
||||
|
||||
/** 调度器注入给任务的运行时能力(避免任务模块直接依赖 DI 与 Sequelize) */
|
||||
export interface JobRuntime {
|
||||
logger: JobLogger;
|
||||
/** 清理 sys_operation_log 中早于 keepDays 天的记录,返回删除条数 */
|
||||
cleanOperationLogs(keepDays: number): Promise<number>;
|
||||
/** 清理 sys_job_log 中早于 keepDays 天的记录,返回删除条数 */
|
||||
cleanJobLogs(keepDays: number): Promise<number>;
|
||||
}
|
||||
|
||||
export interface JobHandlerContext {
|
||||
jobKey: string;
|
||||
jobName: string;
|
||||
triggerType: number; // 1定时自动 2手动触发 3失败重试
|
||||
attempt: number; // 第几次尝试,从 1 开始
|
||||
runtime: JobRuntime;
|
||||
}
|
||||
|
||||
/** 返回值作为本次执行的结果摘要(message);抛异常视为执行失败 */
|
||||
export type JobHandler = (
|
||||
params: Record<string, any>,
|
||||
ctx: JobHandlerContext
|
||||
) => Promise<string | void> | string | void;
|
||||
|
||||
export interface BuiltinJob {
|
||||
jobKey: string;
|
||||
jobName: string;
|
||||
description: string;
|
||||
defaultCron: string;
|
||||
defaultParams: Record<string, any>;
|
||||
paramFields: JobParamField[];
|
||||
handler: JobHandler;
|
||||
}
|
||||
|
||||
export const BUILTIN_JOBS: BuiltinJob[] = [demoHeartbeatJob, logCleanJob];
|
||||
|
||||
export function getBuiltinJob(jobKey: string): BuiltinJob | undefined {
|
||||
return BUILTIN_JOBS.find(job => job.jobKey === jobKey);
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
import type { BuiltinJob } from "./job_registry";
|
||||
|
||||
/**
|
||||
* 日志清理任务:清理早于 keepDays 天的操作日志与任务日志。
|
||||
* 默认保留 90 天,每日 03:00 执行。
|
||||
*/
|
||||
export const logCleanJob: BuiltinJob = {
|
||||
jobKey: "log_clean",
|
||||
jobName: "日志清理",
|
||||
description: "清理早于 keepDays 天的操作日志与任务日志",
|
||||
defaultCron: "0 3 * * *",
|
||||
defaultParams: { keepDays: 90 },
|
||||
paramFields: [
|
||||
{ key: "keepDays", label: "保留天数", type: "number", min: 1, max: 3650 }
|
||||
],
|
||||
handler: async (params, ctx) => {
|
||||
const keepDays = Number(params?.keepDays ?? 90);
|
||||
const opCount = await ctx.runtime.cleanOperationLogs(keepDays);
|
||||
const jobCount = await ctx.runtime.cleanJobLogs(keepDays);
|
||||
return `清理操作日志 ${opCount} 条、任务日志 ${jobCount} 条`;
|
||||
}
|
||||
};
|
||||
Reference in new issue
Block a user