feat(theme): 设置页「主题」导航组 + iframe 预览页 + 学校默认档对接(主题设置 S2)

- 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 新导出)
This commit is contained in:
chenxing
2026-09-30 12:59:35 +08:00
parent 0ded3cce9f
commit 357c0edb52
6 changed files with 657 additions and 6 deletions
+24 -2
View File
@@ -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
</script>
<template>
<!-- 主题预览页(主题设置 2026-09-30):顶层独立分支——不进桌面框架(无左栏/Header/壁纸)、
不依赖登录态与 isRouterAlive 门控(未登录直开也不白屏);仅在该 document 内动态引通道 init -->
<ThemePreview v-if="route.path === '/theme-preview'" />
<div
v-else
:class="['app-desktop app-desktop__animation', !menuVisible ? 'app-desktop__full' : '']"
:style="mainStyle"
v-show="StateType > StateEnum.Loading"