diff --git a/src/App.vue b/src/App.vue index d64fb01..04e8130 100644 --- a/src/App.vue +++ b/src/App.vue @@ -5,23 +5,31 @@ * 与后台前端(front/)刻意不同:不渲染平台模块菜单(app_module 是管理端契约), * 只做两个入口——办事大厅、我的办件(详情/办理页从列表进入)。 * - * 皮肤:启动时按运行时配置(env-config 的 theme/themeParams)应用皮肤包; - * 未配置 → default;未注册 → default(整页回退,见 utils/theme.ts)。 + * 皮肤三层优先级(T3 弱联动,2026-10-03): + * CMS 站点推荐(/api/hall/site 的 theme/themeParams,经 utils/cmsTheme 映射; + * stale-while-revalidate——localStorage 缓存先画、后台刷新,失败静默) + * > env-config 部署级皮肤 > default。 + * 推荐值、不保证生效:任一层缺失/非法都回落下一层(utils/theme.ts)。 */ import { onMounted, ref } from "vue"; import { baseApi } from "@/api/module/base"; import config from "@/assets/config/host.config"; import { applyTheme, resolveTheme, type ThemeManifest } from "@/utils/theme"; +import { toHallSkin } from "@/utils/cmsTheme"; import { useSite } from "@/utils/site"; +import { hallApi } from "@/api/module/svc"; const userName = ref(""); const theme = ref(resolveTheme(null)); // CMS 指南页来路(T4 回跳闭环):仅 /#/apply 深链带合法 from 参数时非空 -const { portalFrom } = useSite(); +const { portalFrom, currentSiteCode } = useSite(); onMounted(async () => { - // 皮肤先应用(首屏观感),再拉用户信息——用户信息失败不影响办理页面使用 + // ① 基线:env-config 部署级皮肤(现状语义不变,先应用保证首屏观感) theme.value = applyTheme(config.theme, config.themeParams); + // ② 站点推荐:CMS 站点主题(弱联动)——缓存先画,后台刷新 + applySiteThemeRecommend(); + // 用户信息失败不影响办理页面使用 try { const user: any = await baseApi.getUserInfo().send(); userName.value = user?.name || ""; @@ -32,6 +40,36 @@ onMounted(async () => { } } }); + +/** + * 站点主题推荐应用(stale-while-revalidate): + * 未登录时该请求会 302 跳 CAS(与 items 同行为,页面本来就要登录); + * 任何失败静默保留现皮肤——推荐、不保证生效,绝不阻塞首屏。 + */ +async function applySiteThemeRecommend() { + const code = currentSiteCode.value; // useSite() 模块级 ref,当前视图 onMounted 已 resolve + if (!code) return; + const cacheKey = `svchall.public.siteTheme.${code}`; + // ① stale:同步读缓存立即应用(二次访问无闪色) + try { + const cached = JSON.parse(localStorage.getItem(cacheKey) || "null"); + const stale = toHallSkin(cached); + if (stale) theme.value = applyTheme(stale.name, stale.params); + } catch { + // 坏缓存当没有 + } + // ② revalidate:后台刷新(失败静默保留现皮肤——推荐、不保证生效) + try { + const info: any = await hallApi.site(code).send(); + const pick = toHallSkin({ theme: info?.theme, themeParams: info?.themeParams }); + localStorage.setItem(cacheKey, JSON.stringify({ + theme: info?.theme || null, themeParams: info?.themeParams || null, + })); + if (pick) theme.value = applyTheme(pick.name, pick.params); + } catch (e) { + console.warn("[public-hall] 站点主题获取失败,沿用当前皮肤", e); + } +}