-- 可配置消息通知中心 -- 背景:现有站内通知为硬编码单点(仅「证照到期」一种、标题模板写死、接收人写死为 ADMIN), -- 且仅 Web 管理端可见;两个移动端(管理端 App / 电工端 App)没有消息中心。 -- 本期建立「可配置 + 两端统一」的站内消息中心: -- - 改造 sys_notice:新增 receiver_type(user|worker),两端共用一套消息数据; -- - 新增 sys_notice_rule(通知规则模板 + 接收对象配置); -- - 新增 sys_notice_batch(手动群发批次/发送记录); -- - 新增内置任务 notice_scan(扫描式规则统一入口)与首批规则种子; -- - 挂载系统管理下的「通知管理」菜单与按钮权限。 -- 幂等:新增列带 DEFAULT + IF NOT EXISTS;建表/索引用 IF NOT EXISTS;菜单/绑定用 ON CONFLICT; -- 任务与规则种子用 ON CONFLICT DO NOTHING。 -- 注意:菜单 id 51-54,避开 20261001(34-46)与 20261002(47-50)已占用区间。 BEGIN; -- ------------------------------------------------------------ -- 1) 改造 sys_notice:增加接收人类型与来源引用 -- ------------------------------------------------------------ ALTER TABLE sys_notice ADD COLUMN IF NOT EXISTS receiver_type VARCHAR(16) NOT NULL DEFAULT 'user'; -- 接收人类型:user-管理端用户 worker-电工 ALTER TABLE sys_notice ADD COLUMN IF NOT EXISTS rule_id BIGINT; -- 来源通知规则(→ sys_notice_rule.id) ALTER TABLE sys_notice ADD COLUMN IF NOT EXISTS batch_id BIGINT; -- 来源群发批次(→ sys_notice_batch.id) COMMENT ON COLUMN sys_notice.receiver_type IS '接收人类型:user-管理端用户 worker-电工'; COMMENT ON COLUMN sys_notice.rule_id IS '来源通知规则(→ sys_notice_rule.id)'; COMMENT ON COLUMN sys_notice.batch_id IS '来源群发批次(→ sys_notice_batch.id)'; -- 幂等键升级:加入 receiver_type(user 与 worker 的 id 空间不同,必须区分) DROP INDEX IF EXISTS uk_sys_notice_biz; CREATE UNIQUE INDEX IF NOT EXISTS uk_sys_notice_deliver ON sys_notice (notice_type, biz_type, biz_id, receiver_type, receiver_id); CREATE INDEX IF NOT EXISTS idx_sys_notice_receiver_type ON sys_notice (receiver_type, receiver_id, is_read); -- ------------------------------------------------------------ -- 2) 通知规则表(规则模板 + 接收对象配置) -- ------------------------------------------------------------ CREATE TABLE IF NOT EXISTS sys_notice_rule ( id BIGSERIAL PRIMARY KEY, rule_key VARCHAR(64) NOT NULL, -- 规则键(唯一) rule_name VARCHAR(64) NOT NULL, -- 规则名称 event_key VARCHAR(64) NOT NULL, -- 事件键(对应代码事件注册表) trigger_mode SMALLINT NOT NULL DEFAULT 1, -- 触发方式:1扫描式 2埋点式 enabled SMALLINT NOT NULL DEFAULT 1, -- 状态:1启用 0停用 advance_days INT, -- 提前天数(扫描式) title_tpl VARCHAR(128) NOT NULL, -- 标题模板(支持 {变量}) content_tpl VARCHAR(512) NOT NULL, -- 正文模板(支持 {变量}) receiver_config JSONB NOT NULL DEFAULT '{"users":{"roles":[],"ids":[]},"workers":{"mode":"none","ids":[]}}'::jsonb, -- 接收对象配置 remark VARCHAR(255), -- 备注 created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW() ); COMMENT ON TABLE sys_notice_rule IS '通知规则表(模板 + 接收对象)'; COMMENT ON COLUMN sys_notice_rule.id IS '自增主键'; COMMENT ON COLUMN sys_notice_rule.rule_key IS '规则键(唯一)'; COMMENT ON COLUMN sys_notice_rule.rule_name IS '规则名称'; COMMENT ON COLUMN sys_notice_rule.event_key IS '事件键(对应代码事件注册表)'; COMMENT ON COLUMN sys_notice_rule.trigger_mode IS '触发方式:1扫描式 2埋点式'; COMMENT ON COLUMN sys_notice_rule.enabled IS '状态:1启用 0停用'; COMMENT ON COLUMN sys_notice_rule.advance_days IS '提前天数(扫描式)'; COMMENT ON COLUMN sys_notice_rule.title_tpl IS '标题模板(支持 {变量})'; COMMENT ON COLUMN sys_notice_rule.content_tpl IS '正文模板(支持 {变量})'; COMMENT ON COLUMN sys_notice_rule.receiver_config IS '接收对象配置:users{roles,ids} + workers{mode:none|event|all|ids|status,ids,auditStatus,status}'; COMMENT ON COLUMN sys_notice_rule.remark IS '备注'; COMMENT ON COLUMN sys_notice_rule.created_at IS '创建时间'; COMMENT ON COLUMN sys_notice_rule.updated_at IS '更新时间'; CREATE UNIQUE INDEX IF NOT EXISTS uk_sys_notice_rule_key ON sys_notice_rule (rule_key); CREATE INDEX IF NOT EXISTS idx_sys_notice_rule_event ON sys_notice_rule (event_key, trigger_mode, enabled); -- ------------------------------------------------------------ -- 3) 手动群发批次表(发送记录) -- ------------------------------------------------------------ CREATE TABLE IF NOT EXISTS sys_notice_batch ( id BIGSERIAL PRIMARY KEY, title VARCHAR(128) NOT NULL, -- 消息标题 content VARCHAR(512) NOT NULL, -- 消息正文 receiver_config JSONB NOT NULL DEFAULT '{"users":{"roles":[],"ids":[]},"workers":{"mode":"none","ids":[]}}'::jsonb, -- 接收对象快照 receiver_count INT NOT NULL DEFAULT 0, -- 实际接收人数 sent_by BIGINT, -- 发送人(→ sys_user.id) sent_at TIMESTAMPTZ NOT NULL DEFAULT NOW() -- 发送时间 ); COMMENT ON TABLE sys_notice_batch IS '手动群发批次表(发送记录)'; COMMENT ON COLUMN sys_notice_batch.id IS '自增主键'; COMMENT ON COLUMN sys_notice_batch.title IS '消息标题'; COMMENT ON COLUMN sys_notice_batch.content IS '消息正文'; COMMENT ON COLUMN sys_notice_batch.receiver_config IS '接收对象快照'; COMMENT ON COLUMN sys_notice_batch.receiver_count IS '实际接收人数'; COMMENT ON COLUMN sys_notice_batch.sent_by IS '发送人(→ sys_user.id)'; COMMENT ON COLUMN sys_notice_batch.sent_at IS '发送时间'; -- ------------------------------------------------------------ -- 4) 菜单与权限(系统管理 parent_id=6 下新增「通知管理」+ 3 个按钮权限) -- ------------------------------------------------------------ INSERT INTO sys_menu (id, parent_id, menu_name, menu_path, component, icon, sort_order, menu_type, permission, visible) VALUES (51, 6, '通知管理', '/system/notice', 'system/notice/index', 'BellOutlined', 7, 2, 'notice:rule', 1), (52, 51, '保存规则', NULL, NULL, NULL, 1, 3, 'notice:rule:update', 1), (53, 51, '删除规则', NULL, NULL, NULL, 2, 3, 'notice:rule:delete', 1), (54, 51, '群发消息', NULL, NULL, NULL, 3, 3, 'notice:batch', 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)拥有 51~54 INSERT INTO sys_role_menu (role_id, menu_id) VALUES (1, 51), (1, 52), (1, 53), (1, 54) ON CONFLICT (role_id, menu_id) DO NOTHING; -- 重置 sys_menu 自增序列,避免后续插入 id 冲突 SELECT setval('sys_menu_id_seq', 54, true); -- ------------------------------------------------------------ -- 5) 内置任务种子:通知规则扫描(扫描式规则的统一入口) -- ------------------------------------------------------------ INSERT INTO sys_job (job_key, job_name, cron_expression, params, retry_times, retry_interval, status, remark) VALUES ('notice_scan', '通知规则扫描', '0 0 8 * * *', '{}'::jsonb, 1, 300, 1, '遍历启用的扫描式通知规则,按模板与接收对象生成站内通知(幂等,默认每日 08:00)') ON CONFLICT (job_key) DO NOTHING; -- ------------------------------------------------------------ -- 6) 首批通知规则种子(按 rule_key 幂等;接收对象均可在「通知管理」页调整) -- ------------------------------------------------------------ INSERT INTO sys_notice_rule (rule_key, rule_name, event_key, trigger_mode, enabled, advance_days, title_tpl, content_tpl, receiver_config, remark) VALUES ('cert_expire', '电工资质证照到期提醒', 'cert_expire', 1, 1, 30, '电工【{workerName}】的{certType}{expireState}', '证书编号:{certNo};发证机关:{issueAuthority};有效期至:{expireDate};{remainDaysText},请及时提醒电工办理续期', '{"users":{"roles":["ADMIN"],"ids":[]},"workers":{"mode":"event","ids":[]}}'::jsonb, '扫描 worker_cert 中 advance_days 天内到期或已过期的证照,通知 ADMIN 与证照所属电工'), ('worker_audit_result', '电工入驻审核结果通知', 'worker_audit_result', 2, 1, NULL, '您的入驻审核{auditState}', '审核{auditState};{auditRemarkText}如资料有误,请修改后重新提交。', '{"users":{"roles":[],"ids":[]},"workers":{"mode":"event","ids":[]}}'::jsonb, '审核通过/驳回时实时通知电工本人(业务埋点触发)'), ('dispatch_assign', '工单派单通知', 'dispatch_assign', 2, 1, NULL, '您有新的{orderTypeName}工单', '工单编号:{orderNo};客户:{customerName};{detailText}请及时在电工端查看并接单。', '{"users":{"roles":[],"ids":[]},"workers":{"mode":"event","ids":[]}}'::jsonb, '勘察/安装/维保/报修派单时实时通知被指派电工(业务埋点触发)'), ('contract_expire', '客户合同到期提醒', 'contract_expire', 1, 1, 30, '客户【{customerName}】的合同{expireState}', '合同编号:{contractNo};合同名称:{contractName};到期日:{endDate};{remainDaysText},请及时跟进续签。', '{"users":{"roles":["ADMIN"],"ids":[]},"workers":{"mode":"none","ids":[]}}'::jsonb, '扫描 contract 中 advance_days 天内到期或已过期的合同,通知 ADMIN'), ('visit_plan', '客户拜访计划提醒', 'visit_plan', 1, 1, 0, '客户拜访计划待执行:{customerName}', '计划拜访日期:{planDate};{remainDaysText}。请及时完成拜访。', '{"users":{"roles":["ADMIN"],"ids":[]},"workers":{"mode":"none","ids":[]}}'::jsonb, '扫描 customer_visit 中未执行且计划日期已到/超期的拜访计划,通知 ADMIN'), ('order_timeout', '工单超时未接单提醒', 'order_timeout', 1, 1, 1, '工单超时未接单:{orderTypeName}', '工单编号:{orderNo};客户:{customerName};已派单 {staleDays} 天仍未接单,请及时跟进。', '{"users":{"roles":["ADMIN"],"ids":[]},"workers":{"mode":"none","ids":[]}}'::jsonb, '扫描派单后超过 advance_days 天仍未接单的工单,通知 ADMIN') ON CONFLICT (rule_key) DO NOTHING; COMMIT;