-- ===================================================================== -- 模板主键与模板目录错位订正脚本 -- 事故:https://gxhrtc.shoplnk.cn/ 渲染成 template-09 墨绿出版风, -- 实际应为 template-08 金棕企业风(广西恒瑞天诚,tenantId=10140) -- 日期:2026-08-03 -- -- 【根因】 -- 前端模板目录名曾按 app_template 自增主键补零推导(9 → template-09)。 -- 但后台 app_template 主键跳号(id=8 缺失),从第 8 套模板起主键与前端目录整体错位一位, -- 且 code 字段当初也是跟着主键生成的,同样错位: -- -- app_template 现状 前端 app/templates/ 实际内容 -- id=9 code=template-09 恒瑞天诚 ← 内容是金棕企业风,对应 template-08 -- id=10 code=template-10 墨绿出版模板 ← 对应 template-09 -- id=11 code=template-11 哈哈333 ← 测试脏数据,前端无此目录 -- -- 【配套代码改动(已完成,见 website-template 仓库)】 -- 前端解析改为「code 优先、主键兜底」: -- - app/utils/index.ts 新增 resolveTemplateKey(code, id) -- - server/utils/template-map.ts SSR 侧按 templateId 反查 app_template 拿权威 code -- - server/middleware/tenant.ts 回填 siteInfo.templateCode -- 因此只要本脚本把 code 修正到位,前端无需重新部署数据即可正确解析。 -- -- 【库分布】同一 MySQL 实例 -- db_websopy.app_template 模板库 -- modules.cms_website 站点表(template_id 指向 app_template.id) -- -- 【执行建议】 -- Step 1 必做、低风险,执行完 gxhrtc 即恢复正常(无需清 Redis)。 -- Step 2 可选、需停机窗口,执行后【必须清除 Redis 缓存】,否则会二次错位。 -- ===================================================================== -- --------------------------------------------------------------------- -- Step 0. 备份(必做) -- --------------------------------------------------------------------- CREATE TABLE IF NOT EXISTS db_websopy.app_template_bak_20260803 AS SELECT * FROM db_websopy.app_template; CREATE TABLE IF NOT EXISTS modules.cms_website_tplid_bak_20260803 AS SELECT website_id, tenant_id, website_name, template_id FROM modules.cms_website WHERE template_id IS NOT NULL; -- 执行前先看一眼现状 SELECT id, code, name, comments FROM db_websopy.app_template ORDER BY id; SELECT template_id, COUNT(*) AS site_count FROM modules.cms_website WHERE template_id IS NOT NULL GROUP BY template_id ORDER BY template_id; -- --------------------------------------------------------------------- -- Step 1. 【必做】修正 code,使其与前端模板目录一一对应 -- -- ⚠️ 执行顺序不可颠倒:若 code 上有唯一索引,先腾空 template-09 再占用, -- 否则 id=10 改为 template-09 时会与 id=9 的旧值冲突。 -- --------------------------------------------------------------------- START TRANSACTION; -- 1.1 id=9「恒瑞天诚」实为金棕企业模板 → 让出 template-09,改挂 template-08 -- 顺带把客户名改回模板语义名(模板库不应以单个客户命名;如需保留客户名可删掉 name/comments 两行) UPDATE db_websopy.app_template SET code = 'template-08', name = '金棕企业模板', comments = '金棕企业风,适合招标公告、工程建设、咨询服务类企业官网' WHERE id = 9; -- 1.2 id=10「墨绿出版模板」→ 接手已腾空的 template-09 UPDATE db_websopy.app_template SET code = 'template-09', comments = '墨绿文化出版风,适合出版社、文化传媒、图书发行、教育机构类官网' WHERE id = 10; -- 1.3 清理测试脏数据(逻辑删除,保留可恢复性;确认无用后再物理删除) UPDATE db_websopy.app_template SET deleted = 1 WHERE id = 11 AND name = '哈哈333'; COMMIT; -- 校验:code 应与前端 app/templates/ 目录一一对应(template-01 ~ template-09,无重复、无缺号) SELECT id, code, name FROM db_websopy.app_template WHERE deleted = 0 ORDER BY code; -- 到此为止,gxhrtc(cms_website.template_id = 9)经前端反查得到 code = 'template-08', -- 渲染恢复为金棕企业风。SiteInfo Redis 缓存存的是 template_id 主键(未变),故无需清缓存; -- 前端 SSR 侧模板映射有 10 分钟内存缓存,等待 10 分钟或重启 Node 进程即可生效。 -- --------------------------------------------------------------------- -- Step 2.【可选】重排主键,使 id 数字 == code 数字(彻底消除歧义) -- -- ⚠️⚠️ 高风险操作,务必在停机窗口执行,且严格按顺序: -- 先改 cms_website 引用,再改 app_template 主键,否则中间态会指向错误模板。 -- ⚠️⚠️ 执行完必须清除 Redis 缓存 SiteInfo:*,否则站点仍返回旧 template_id, -- 反查新表会得到错误的 code(旧 9 → 新 9 = 墨绿),造成二次错位。 -- --------------------------------------------------------------------- -- START TRANSACTION; -- -- -- 2.1 先迁移站点引用(顺序:9→8 腾空 9,再 10→9) -- UPDATE modules.cms_website SET template_id = 8 WHERE template_id = 9; -- UPDATE modules.cms_website SET template_id = 9 WHERE template_id = 10; -- UPDATE modules.cms_website SET template_id = NULL WHERE template_id = 11; -- 脏模板引用清空,回退默认模板 -- -- -- 2.2 再重排模板主键(同样先 9→8 腾空,再 10→9) -- UPDATE db_websopy.app_template SET id = 8 WHERE id = 9; -- UPDATE db_websopy.app_template SET id = 9 WHERE id = 10; -- DELETE FROM db_websopy.app_template WHERE id = 11 AND name = '哈哈333'; -- -- -- 2.3 复位自增起点,避免后续新增再次跳号 -- ALTER TABLE db_websopy.app_template AUTO_INCREMENT = 10; -- -- COMMIT; -- -- -- 2.4 清除站点信息缓存(在服务器上执行,Redis 键前缀见 CmsWebsiteServiceImpl.SITE_INFO_KEY_PREFIX) -- -- redis-cli --scan --pattern 'SiteInfo:*' | xargs -r redis-cli del -- -- -- 2.5 校验:id 数字必须等于 code 数字 -- SELECT id, code, name, -- CASE WHEN id = CAST(SUBSTRING(code, 10) AS UNSIGNED) THEN 'OK' ELSE 'MISMATCH' END AS aligned -- FROM db_websopy.app_template WHERE deleted = 0 ORDER BY id; -- --------------------------------------------------------------------- -- 回滚 -- --------------------------------------------------------------------- -- Step 1 回滚: -- UPDATE db_websopy.app_template t -- JOIN db_websopy.app_template_bak_20260803 b ON b.id = t.id -- SET t.code = b.code, t.name = b.name, t.comments = b.comments, t.deleted = b.deleted; -- -- Step 2 回滚:先从 app_template_bak_20260803 整表还原 app_template, -- 再按 cms_website_tplid_bak_20260803 还原各站点的 template_id,最后清 Redis SiteInfo:*。 -- --------------------------------------------------------------------- -- 【后续防复发】 -- 1. 新增模板时手工指定主键,强制 id 数字 == code 数字,禁止依赖自增跳号。 -- 2. 上游 getSiteInfo 建议增返 templateCode 字段(关联 app_template.code), -- 前端 server/utils/template-map.ts 的反查会自动跳过,少一次上游请求。 -- 3. website-admin 的模板管理页「预览」按 code 解析、「选用」却提交 id, -- 两者口径不一致是本次事故的放大器;建议选用也改为提交 code。 -- =====================================================================