[CMS-VISUAL] E 激进清场: 下架 10 套伪主题(tag themes-before-cleanup-2026-09 + docs/主题备份/ 双备份)→ 保留 default/scholar-blue/campus-glow 三套;色皮档并入 default.colorScheme、克隆档并入 scholar-blue.colorScheme(ThemeParam.presets + ThemeVarsCss 变量组注入);别名表 R-46 映射(渲染端不断渲染 + 保存归一化 + 站点级 theme_params.colorScheme)

This commit is contained in:
chenxing
2026-09-28 14:58:31 +08:00
parent efd3cb30f9
commit a9e4240bb3
166 changed files with 435 additions and 20200 deletions
@@ -75,12 +75,24 @@ public class PortalQueryService {
return null;
}
PortalSiteSnapshot snapshot = PortalSiteSnapshot.of(site);
snapshot.setTheme(resolveTheme(snapshot.getTheme(), snapshot.getCode()));
String originalTheme = snapshot.getTheme();
snapshot.setTheme(resolveTheme(originalTheme, snapshot.getCode()));
derivePublicBaseUrl(site, snapshot);
// 微调参数注入(方案 §5.3):按已解析主题 schema 过滤,回退主题与参数过滤天然一致
com.yunhai.cms.theme.ThemeInfo themeInfo = themeRegistry.get(snapshot.getTheme());
java.util.Map<String, String> themeParams =
themeInfo.filterValidValues(rawParamsMap(snapshot));
// docs/20 E(R-46):站点用下架主题 → 强制对应 colorScheme 预设(保持原视觉近似);
// 站点保存归一化后 theme 已是保留主题,改由 config.theme_params.colorScheme 站点级驱动
com.yunhai.cms.theme.ThemeRegistry.AliasInfo alias =
com.yunhai.cms.theme.ThemeRegistry.aliasOf(originalTheme);
String siteScheme = siteColorScheme(snapshot.getConfig());
if (alias != null && alias.colorScheme != null) {
themeParams.put("colorScheme", alias.colorScheme);
} else if (siteScheme != null && themeInfo.param("colorScheme") != null
&& themeInfo.param("colorScheme").isValidValue(siteScheme)) {
themeParams.put("colorScheme", siteScheme);
}
snapshot.setThemeParams(themeParams);
snapshot.setThemeVarsCss(com.yunhai.cms.theme.ThemeVarsCss.build(themeInfo, themeParams));
@@ -280,15 +292,41 @@ public class PortalQueryService {
}
}
/** 皮肤包存在性检查:委托 ThemeRegistry(theme.json + 4 模板齐全校验,方案 §5.1 重构,缺省回退 default) */
/**
* 皮肤包存在性检查:委托 ThemeRegistry;docs/20 E 后下架主题按别名表映射到保留主题
* (R-46:门户不断渲染),未知主题回退 default。
*/
private String resolveTheme(String theme, String siteCode) {
if (themeRegistry.contains(theme)) {
return theme;
}
com.yunhai.cms.theme.ThemeRegistry.AliasInfo alias =
com.yunhai.cms.theme.ThemeRegistry.aliasOf(theme);
if (alias != null) {
log.warn("皮肤包 {} 已下架(docs/20 E 清场),映射到 {}(colorScheme={})site={}",
theme, alias.target, alias.colorScheme, siteCode);
return alias.target;
}
log.warn("皮肤包 {} 未注册(site={}),回退 default", theme, siteCode);
return com.yunhai.cms.theme.ThemeRegistry.DEFAULT_THEME;
}
/** 站点级 colorScheme(config_json.theme_params.colorScheme,仅归一化保存后的别名站点使用) */
private static String siteColorScheme(java.util.Map<String, Object> config) {
if (config == null) {
return null;
}
Object tp = config.get("theme_params");
if (tp instanceof Map) {
Object v = ((Map<?, ?>) tp).get("colorScheme");
if (v != null) {
String s = String.valueOf(v);
return s.isEmpty() ? null : s;
}
}
return null;
}
/**
* 参数原始值(工作项 T:参数微调上移为皮肤包级):取当前主题的包级 {@code paramValues}
* ({@code themes/.meta/{name}.json} 覆盖层)。站点 {@code config_json.theme_params} 已退役、不再读取
@@ -191,13 +191,27 @@ public class SiteService {
site.setSchId(req.getSchId());
site.setSchName(req.getSchName());
site.setName(req.getName());
String resolvedTheme = StringUtils.hasText(req.getTheme())
String requestedTheme = StringUtils.hasText(req.getTheme())
? req.getTheme() : com.yunhai.cms.theme.ThemeRegistry.DEFAULT_THEME;
// docs/20 E:下架主题名按别名表归一化为保留主题(保存后 theme 字段收敛到 3 套注册包)
com.yunhai.cms.theme.ThemeRegistry.AliasInfo alias =
com.yunhai.cms.theme.ThemeRegistry.aliasOf(requestedTheme);
String resolvedTheme = requestedTheme;
if (!themeRegistry.contains(resolvedTheme)) {
throw new BizException(ErrorCode.PARAM_ERROR, "皮肤包未注册:" + resolvedTheme);
if (alias != null) {
resolvedTheme = alias.target;
} else {
throw new BizException(ErrorCode.PARAM_ERROR, "皮肤包未注册:" + resolvedTheme);
}
}
site.setTheme(resolvedTheme);
validateConfigJson(req.getConfigJson(), site.getId());
String configJson = req.getConfigJson();
if (alias != null && alias.colorScheme != null) {
// 原配色写入站点级 theme_params.colorScheme(渲染端据此套用预设,保留原视觉近似)
configJson = withSiteColorScheme(configJson, alias.colorScheme);
req.setConfigJson(configJson);
}
validateConfigJson(configJson, site.getId());
// 工作项 T:参数微调上移为皮肤包级,站点不再持有参数值——themeParams 入参直接忽略
// (config_json 原样入库;theme_params 仍是 RESERVED 键以容忍存量/老前端提交,不报错)
site.setConfigJson(req.getConfigJson());
@@ -209,6 +223,26 @@ public class SiteService {
return SiteVo.of(site);
}
/**
* docs/20 E:站点级 colorScheme 写入 config_json.theme_params(仅 colorScheme 键,
* 其余 theme_params 内容原样保留;theme_params 为 RESERVED 键不参与常规校验)。
*/
private String withSiteColorScheme(String configJson, String colorScheme) {
java.util.Map<String, Object> config = ExtJsonUtils.parse(configJson);
Object tp = config.get("theme_params");
java.util.Map<String, Object> themeParams = new java.util.LinkedHashMap<>();
if (tp instanceof java.util.Map) {
((java.util.Map<?, ?>) tp).forEach((k, v) -> themeParams.put(String.valueOf(k), v));
}
themeParams.put("colorScheme", colorScheme);
config.put("theme_params", themeParams);
try {
return CONFIG_MAPPER.writeValueAsString(config);
} catch (Exception e) {
throw new BizException(ErrorCode.PARAM_ERROR, "站点配置序列化失败");
}
}
/**
* W4 门户 path 计算(唯一入口,前后端各一份纯函数语义:front/src/utils/sitePath.ts 同构):
* 顶层(parentSiteId≤0)=code;子站=父站 path + '/' + code。