From 357c0edb522e33dea808b00512476a3272d3b479 Mon Sep 17 00:00:00 2001 From: chenxing Date: Wed, 30 Sep 2026 12:59:35 +0800 Subject: [PATCH] =?UTF-8?q?feat(theme):=20=E8=AE=BE=E7=BD=AE=E9=A1=B5?= =?UTF-8?q?=E3=80=8C=E4=B8=BB=E9=A2=98=E3=80=8D=E5=AF=BC=E8=88=AA=E7=BB=84?= =?UTF-8?q?=20+=20iframe=20=E9=A2=84=E8=A7=88=E9=A1=B5=20+=20=E5=AD=A6?= =?UTF-8?q?=E6=A0=A1=E9=BB=98=E8=AE=A4=E6=A1=A3=E5=AF=B9=E6=8E=A5=EF=BC=88?= =?UTF-8?q?=E4=B8=BB=E9=A2=98=E8=AE=BE=E7=BD=AE=20S2=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Settings.vue:新增「主题」导航组(组级不设 adminOnly),mytheme「我的主题」所有人可见、schooltheme「本校默认」item 级 adminOnly + 入 ADMIN_PANES 双保险(NavItem 扩展 adminOnly 字段,navGroups 组级+item 级双层过滤);两个 pane 左色块右预览 iframe——候选档经 ?yh-theme=/yh-side=/yh-grad= URL 覆盖参数拼进 #/theme-preview src,切候选即换 src 重载;档位清单本轮硬编码 5 档(主色取通道 tokens);「跟随学校默认」=删用户键、「跟随系统默认」=clearSchTheme 清空学校配置;当前生效档与来源(我的选择/学校默认/系统默认)经 resolveEffectiveThemeState 标注 - views/ThemePreview.vue(新增):纯展示预览页——顶栏 .header-container + 左菜单 .left-menu + 面包屑 + iview Table 写死 4 行,DOM 结构对齐 Notice layout,观感由通道 CSS 按档位类驱动;根容器 pointer-events:none,无搜索/分页/ThemeSwitcher;挂载时动态 append 通道 init(baseHost + /static/js/yh-theme-init.js,判重防双挂)——仅该 document 吃通道 CSS,UserHome 本体 index.html 不加 loader(定案) - App.vue:/theme-preview 顶层独立分支(不进桌面框架、不依赖登录态与 isRouterAlive——未登录直开不白屏);菜单白名单加 /theme-preview;登录成功后异步拉 schTheme 写 localStorage[yh-theme-sch-default](失败/空不写不报错,推荐值语义) - router/routes.ts:登记 /theme-preview(实际渲染走 App.vue 分支;若后续引入守卫须列入免登录白名单——注释已写明) - BaseApi:getSchTheme / saveSchThemeState / clearSchTheme 三封装 - src/utils/theme.ts:YschTheme npm run sync 下发(版本 20260930-1248-4e12e6d,含 SCHOOL_DEFAULT_STORAGE_KEY 与 resolveEffectiveThemeState 新导出) --- src/App.vue | 26 +++- src/api/BaseApi.ts | 23 +++ src/router/routes.ts | 9 ++ src/utils/theme.ts | 151 ++++++++++++++++++ src/views/Settings.vue | 312 ++++++++++++++++++++++++++++++++++++- src/views/ThemePreview.vue | 142 +++++++++++++++++ 6 files changed, 657 insertions(+), 6 deletions(-) create mode 100644 src/utils/theme.ts create mode 100644 src/views/ThemePreview.vue diff --git a/src/App.vue b/src/App.vue index 5621c7f..c1e4a9d 100644 --- a/src/App.vue +++ b/src/App.vue @@ -12,6 +12,7 @@ import BschIframe from "@/components/BschIframe.vue"; import SearchPanel from "@/components/SearchPanel.vue"; import UserInfoModal from "@/components/UserInfoModal.vue"; import LightPageModal from "@/components/LightPageModal.vue"; +import ThemePreview from "@/views/ThemePreview.vue"; import BaseApi from "@/api/BaseApi"; import { BschIframeType, IframePageParmas, RoleInfo, StateEnum } from "./types"; @@ -60,6 +61,7 @@ mittBus.on("openBschIframePage", async (params: IframePageParmas) => { try { const [r1, r2] = await Promise.all([p1, p2]); store.$state.userInfo = userinfo; + loadSchThemeDefault(); if (r1.length == 0) { store.$state.userRoleList = [ { @@ -86,6 +88,21 @@ mittBus.on("openBschIframePage", async (params: IframePageParmas) => { console.timeEnd("init"); })(); +/** 拉学校默认主题档写键(异步尽力而为:失败/404/空 → 不写、不报错、不阻塞登录流程) */ +function loadSchThemeDefault() { + BaseApi.getSchTheme() + .then((res: any) => { + if (res && res.themeState) { + try { + localStorage.setItem("yh-theme-sch-default", res.themeState); + } catch (e) { + /* 隐私模式写失败静默 */ + } + } + }) + .catch(() => undefined); +} + /**切换角色 */ async function switchRole() { await loadUserMenuBarList(); @@ -113,8 +130,9 @@ async function loadUserMenuBarList() { } else { findIndex = menuList.findIndex(x => x.url === route.path); } - // /msg、/settings 由后台「边栏设置」配置后即进入菜单表;未配置时也允许直达/刷新,不被弹回桌面 - if (findIndex === -1 && !["/msg", "/settings"].includes(route.path)) router.push({ name: "index" }); + // /msg、/settings 由后台「边栏设置」配置后即进入菜单表;未配置时也允许直达/刷新,不被弹回桌面。 + // /theme-preview 同理(预览页按 URL 参数挂档,不依赖菜单表与登录态) + if (findIndex === -1 && !["/msg", "/settings", "/theme-preview"].includes(route.path)) router.push({ name: "index" }); } const getRouterKey: (route: any) => string = route => { @@ -128,7 +146,11 @@ const mainStyle = computed(() => `background-image: url(${store.getCurWallPaperU