Files
WonderQ-Project/docs/superpowers/plans/2026-08-26-ruoyi-admin-shell-visual-design.md
duanshuwen fbf2c772a8 refactor: 清理废弃模块并重构管理端与全端代码
- 移除所有废弃的旧首页配置模块,包括destinationHero、demand相关、HomeExperience、vehicleService等表结构与代码,新增数据库迁移删除遗留表
- 重构管理端后台布局为标准RuoYi风格,新增Sidebar、Navbar、SettingsDrawer等组件,替换旧的过渡菜单实现
- 调整移动端响应断点为768px,更新布局相关测试用例,新增布局组件测试
- 删除OperationsTools发布/重置页面,移除/tools菜单入口,清理对应的API调用与测试代码
- 重构玩法模块编辑器:替换旧的图片手动输入框为图片上传组件,移除冗余的取消按钮
- 新增线索查询offset参数支持,完善查询参数处理逻辑
- 优化rbac菜单构建逻辑,新增可见性控制参数
- 修正管家编辑器提示文案,优化系统资源编辑器表单初始化逻辑
- 清理小程序端废弃的体验推荐组件与相关测试代码
- 更新文档与种子脚本,匹配新的API契约与使用说明
2026-08-26 23:24:28 +08:00

544 lines
22 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# WonderQ Admin UI RuoYi 默认后台壳还原 Implementation Plan
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (- [ ]) syntax for tracking.
**Goal:** 在不改变 WonderQ 业务页面、权限、路由和 API 的前提下,将 WonderQ-Admin-UI-Vue 的后台壳还原为本地 RuoYi-Vue3 的默认布局与交互。
**Architecture:** 保留现有 AdminLayout 作为路由壳,在其下拆分 Sidebar、Navbar、Breadcrumb、TagsView、SettingsDrawer 和 UserMenu。布局状态、页签状态和本地布局设置分别由 Pinia store 与纯函数模块管理;业务页面只接收新的内容区域尺寸和滚动上下文,不改变其数据流。
**Tech Stack:** Vue 3 script setup lang="ts"、Pinia、Vue Router 4、Element Plus、Vite、Vitest、原生 SVG 图标和 CSS 变量。不新增依赖,不修改后端和 API 契约。
---
## 文件结构锁定
### Create
- WonderQ-Admin-UI-Vue/src/components/layout/LayoutIcon.vue:统一渲染布局图标的内联 SVG。
- WonderQ-Admin-UI-Vue/src/components/layout/Sidebar.vue:RuoYi 风格侧栏、移动端抽屉和菜单容器。
- WonderQ-Admin-UI-Vue/src/components/layout/SidebarItem.vue:递归目录/页面菜单项。
- WonderQ-Admin-UI-Vue/src/components/layout/Navbar.vue:50px 顶栏及工具入口。
- WonderQ-Admin-UI-Vue/src/components/layout/Breadcrumb.vue:基于当前路由和权限菜单生成面包屑。
- WonderQ-Admin-UI-Vue/src/components/layout/TagsView.vue:34px 页签、关闭按钮和右键菜单。
- WonderQ-Admin-UI-Vue/src/components/layout/SettingsDrawer.vue:右侧布局配置抽屉。
- WonderQ-Admin-UI-Vue/src/components/layout/UserMenu.vue:用户下拉菜单和退出登录操作。
- WonderQ-Admin-UI-Vue/src/components/layout/TopMenu.vue:顶部/混合导航模式的根菜单。
- WonderQ-Admin-UI-Vue/src/components/layout/Footer.vue:可选的 RuoYi 风格底部版权。
- WonderQ-Admin-UI-Vue/src/stores/layout.ts:侧栏、设备类型和设置抽屉状态。
- WonderQ-Admin-UI-Vue/src/stores/settings.ts:布局设置响应式状态和主题应用。
- WonderQ-Admin-UI-Vue/src/stores/tags.ts:已访问页签状态和操作。
- WonderQ-Admin-UI-Vue/src/lib/layout-settings.ts:默认布局配置、归一化和本地存储。
- WonderQ-Admin-UI-Vue/src/lib/layout-settings.test.ts:布局配置纯函数测试。
- WonderQ-Admin-UI-Vue/src/lib/tags.ts:页签纯函数与上下文菜单操作。
- WonderQ-Admin-UI-Vue/src/lib/tags.test.ts:页签操作测试。
- WonderQ-Admin-UI-Vue/src/lib/menu-display.ts:菜单图标、标题和可导航菜单辅助函数。
- WonderQ-Admin-UI-Vue/src/lib/menu-display.test.ts:菜单展示辅助函数测试。
### Modify
- WonderQ-Admin-UI-Vue/src/layouts/AdminLayout.vue:替换自定义浅色壳为新布局组合,保留 RouterView 和鉴权退出流程。
- WonderQ-Admin-UI-Vue/src/components/MenuTree.vue:迁移为新递归菜单实现的兼容入口,或删除重复实现并更新唯一引用。
- WonderQ-Admin-UI-Vue/src/styles.css:将壳层尺寸、颜色、层级、响应式和 RuoYi Element Plus 覆盖集中到布局样式;保留业务页面专用样式。
- WonderQ-Admin-UI-Vue/src/router/index.ts:仅补充路由 meta 标题/固定页签所需的前端信息,不修改路径、权限和组件注册。
### Test commands
~~~powershell
Set-Location .\WonderQ-Admin-UI-Vue
yarn test
yarn build
~~~
## Task 1: 建立可持久化的布局设置模型
**Files:**
- Create: WonderQ-Admin-UI-Vue/src/lib/layout-settings.ts
- Test: WonderQ-Admin-UI-Vue/src/lib/layout-settings.test.ts
- [ ] Step 1: 先写布局设置失败测试
覆盖默认值、非法值回退、未知字段过滤、保存/读取和重置:
~~~ts
import { describe, expect, it } from "vitest";
import {
DEFAULT_LAYOUT_SETTINGS,
LAYOUT_SETTINGS_KEY,
loadLayoutSettings,
normalizeLayoutSettings,
saveLayoutSettings,
} from "./layout-settings";
describe("layout settings", () => {
it("uses RuoYi defaults", () => {
expect(DEFAULT_LAYOUT_SETTINGS).toMatchObject({
navType: "left",
sideTheme: "theme-dark",
theme: "#409EFF",
tagsView: true,
fixedHeader: false,
sidebarLogo: true,
});
});
it("normalizes invalid persisted values without leaking unknown keys", () => {
expect(normalizeLayoutSettings({ navType: "invalid", theme: 12, unknown: true })).toEqual(DEFAULT_LAYOUT_SETTINGS);
});
it("round-trips settings through the provided storage", () => {
const storage = new Map<string, string>();
const fakeStorage = {
getItem: (key: string) => storage.get(key) ?? null,
setItem: (key: string, value: string) => storage.set(key, value),
removeItem: (key: string) => storage.delete(key),
} as Storage;
const next = { ...DEFAULT_LAYOUT_SETTINGS, tagsIcon: true };
saveLayoutSettings(next, fakeStorage);
expect(fakeStorage.getItem(LAYOUT_SETTINGS_KEY)).toContain('"tagsIcon":true');
expect(loadLayoutSettings(fakeStorage)).toEqual(next);
});
});
~~~
- [ ] Step 2: 运行测试确认当前失败
Run: yarn test src/lib/layout-settings.test.ts
Expected: FAIL because layout-settings.ts does not exist.
- [ ] Step 3: 实现配置类型、默认值和归一化
实现以下公开接口:
~~~ts
export type NavigationType = "left" | "mix" | "top";
export type SideTheme = "theme-dark" | "theme-light";
export type TagsViewStyle = "card" | "chrome";
export type LayoutSettings = {
navType: NavigationType;
sideTheme: SideTheme;
theme: string;
tagsView: boolean;
tagsViewPersist: boolean;
tagsIcon: boolean;
tagsViewStyle: TagsViewStyle;
fixedHeader: boolean;
sidebarLogo: boolean;
dynamicTitle: boolean;
footerVisible: boolean;
};
export const LAYOUT_SETTINGS_KEY = "wonderq-admin-layout-setting";
export const DEFAULT_LAYOUT_SETTINGS: LayoutSettings = {
navType: "left",
sideTheme: "theme-dark",
theme: "#409EFF",
tagsView: true,
tagsViewPersist: false,
tagsIcon: false,
tagsViewStyle: "card",
fixedHeader: false,
sidebarLogo: true,
dynamicTitle: false,
footerVisible: false,
};
export function normalizeLayoutSettings(input: unknown): LayoutSettings;
export function loadLayoutSettings(storage: Storage = window.localStorage): LayoutSettings;
export function saveLayoutSettings(settings: LayoutSettings, storage: Storage = window.localStorage): void;
export function resetLayoutSettings(storage: Storage = window.localStorage): LayoutSettings;
~~~
验证 enum、boolean 和六位十六进制色值;读取异常 JSON 时回退默认值;每次返回新对象,避免 store 修改导出的默认值。
- [ ] Step 4: 运行测试确认通过
Run: yarn test src/lib/layout-settings.test.ts
Expected: all layout settings tests PASS.
- [ ] Step 5: Commit
~~~powershell
git add -- WonderQ-Admin-UI-Vue/src/lib/layout-settings.ts WonderQ-Admin-UI-Vue/src/lib/layout-settings.test.ts
git commit -m "feat(admin-ui): add persisted layout settings model"
~~~
## Task 2: 建立侧栏和设备状态 store
**Files:**
- Create: WonderQ-Admin-UI-Vue/src/stores/layout.ts
- [ ] Step 1: 定义 store 的状态和行为契约
~~~ts
export type DeviceType = "desktop" | "mobile";
export type SidebarToggleOptions = { withoutAnimation?: boolean };
export const useLayoutStore = defineStore("layout", () => {
const device = ref<DeviceType>("desktop");
const sidebarOpened = ref(true);
const settingsDrawerOpen = ref(false);
const withoutAnimation = ref(false);
function syncViewport(width = window.innerWidth): void;
function toggleSidebar(options?: SidebarToggleOptions): void;
function openSidebar(options?: SidebarToggleOptions): void;
function closeSidebar(options?: SidebarToggleOptions): void;
function openSettings(): void;
function closeSettings(): void;
function startViewportWatcher(): () => void;
return { device, sidebarOpened, settingsDrawerOpen, withoutAnimation, syncViewport, toggleSidebar, openSidebar, closeSidebar, openSettings, closeSettings, startViewportWatcher };
});
~~~
syncViewport 在 992px 以下进入 mobile,进入 mobile 时关闭桌面状态;mobile 抽屉仍使用 200px 宽度,不复用桌面 54px 折叠宽度。
- [ ] Step 2: 运行基线测试
Run: yarn test
Expected: existing tests PASS.
- [ ] Step 3: 实现 setup store 和可清理的 resize watcher
使用命名 resize 回调并返回 unsubscribe;store 不读取 localStorage、不读取 Token、不调用后端。
- [ ] Step 4: Commit
~~~powershell
git add -- WonderQ-Admin-UI-Vue/src/stores/layout.ts
git commit -m "feat(admin-ui): add responsive layout state"
~~~
## Task 3: 建立菜单展示辅助函数和布局图标
**Files:**
- Create: WonderQ-Admin-UI-Vue/src/lib/menu-display.ts
- Test: WonderQ-Admin-UI-Vue/src/lib/menu-display.test.ts
- Create: WonderQ-Admin-UI-Vue/src/components/layout/LayoutIcon.vue
- [ ] Step 1: 写菜单展示失败测试
~~~ts
import { describe, expect, it } from "vitest";
import { findMenuTitle, getMenuIconName, visibleNavigableMenus } from "./menu-display";
const menus = [
{ id: "ops", name: "运营管理", type: "directory" as const, children: [
{ id: "play", name: "玩法管理", type: "page" as const, path: "/play", icon: "Route" },
] },
{ id: "hidden", name: "隐藏", type: "page" as const, path: "/hidden", isVisible: false },
];
describe("menu display helpers", () => {
it("removes hidden and button entries from navigable lists", () => {
expect(visibleNavigableMenus(menus).map((item) => item.id)).toEqual(["ops"]);
});
it("finds page and parent titles for breadcrumbs", () => {
expect(findMenuTitle(menus, "/play")).toEqual(["运营管理", "玩法管理"]);
});
it("falls back to a stable icon for unknown menu values", () => {
expect(getMenuIconName({ id: "x", name: "未知", type: "page" })).toBe("Menu");
});
});
~~~
- [ ] Step 2: 运行测试确认失败
Run: yarn test src/lib/menu-display.test.ts
Expected: FAIL because the helper module is not present.
- [ ] Step 3: 实现菜单辅助函数
visibleNavigableMenus 递归过滤 button 和 isVisible === false;findMenuTitle 归一化斜杠并返回父目录/页面标题;getMenuIconName 先按 WonderQ path/component 映射,再使用受支持的 AdminMenu.icon,否则回退 Menu。
- [ ] Step 4: 实现 LayoutIcon.vue
使用固定 24x24 viewBox 的本地 inline SVG,为 Menu、Grid、Route、User、Collection、Setting、Search、FullScreen、Moon、Sunny、Refresh、Close、More、Back、Right 和 Chevron 提供路径。无 title 时设置 aria-hidden="true",禁止 emoji 图标。
- [ ] Step 5: 测试并 Commit
~~~powershell
yarn test src/lib/menu-display.test.ts
git add -- WonderQ-Admin-UI-Vue/src/lib/menu-display.ts WonderQ-Admin-UI-Vue/src/lib/menu-display.test.ts WonderQ-Admin-UI-Vue/src/components/layout/LayoutIcon.vue
git commit -m "feat(admin-ui): add RuoYi layout menu primitives"
~~~
## Task 4: 建立页签纯函数和 Tags store
**Files:**
- Create: WonderQ-Admin-UI-Vue/src/lib/tags.ts
- Test: WonderQ-Admin-UI-Vue/src/lib/tags.test.ts
- Create: WonderQ-Admin-UI-Vue/src/stores/tags.ts
- [ ] Step 1: 写页签失败测试
~~~ts
import { describe, expect, it } from "vitest";
import { addVisitedTag, closeAllTags, closeTag, closeTagsToLeft, closeTagsToRight, type VisitedTag } from "./tags";
const home: VisitedTag = { path: "/dashboard", fullPath: "/dashboard", title: "首页概览", affix: true };
const play: VisitedTag = { path: "/play", fullPath: "/play", title: "玩法管理" };
const leads: VisitedTag = { path: "/leads", fullPath: "/leads", title: "需求线索" };
describe("tags helpers", () => {
it("keeps one entry for a repeated fullPath", () => {
expect(addVisitedTag([home], play)).toEqual([home, play]);
expect(addVisitedTag([home, play], play)).toEqual([home, play]);
});
it("does not close an affix tag", () => {
expect(closeTag([home, play], home)).toEqual([home, play]);
});
it("closes the selected tag and returns the previous fallback", () => {
expect(closeTag([home, play, leads], play)).toEqual([home, leads]);
});
it("closes ranges without removing the selected tag", () => {
expect(closeTagsToLeft([home, play, leads], leads)).toEqual([home, leads]);
expect(closeTagsToRight([home, play, leads], home)).toEqual([home]);
});
it("returns the affix home tag after close all", () => {
expect(closeAllTags([home, play, leads])).toEqual([home]);
});
});
~~~
- [ ] Step 2: 运行失败测试
Run: yarn test src/lib/tags.test.ts
Expected: FAIL because tags.ts is not present.
- [ ] Step 3: 实现页签类型和纯函数
VisitedTag 包含 path、fullPath、title、可选 name/query/icon/affix;所有操作返回新数组;关闭当前优先选择前一个可用页签,否则后一个,最后回退首页。
- [ ] Step 4: 实现 useTagsStore
提供 visitedViews、activePath、addView、updateView、closeSelectedTag、closeOthersTags、closeLeftTags、closeRightTags、closeAllTags、refreshSelectedTag 和 restorePersistedViews。仅在 tagsView 与 tagsViewPersist 都开启时持久化。
- [ ] Step 5: 测试并 Commit
~~~powershell
yarn test src/lib/tags.test.ts
git add -- WonderQ-Admin-UI-Vue/src/lib/tags.ts WonderQ-Admin-UI-Vue/src/lib/tags.test.ts WonderQ-Admin-UI-Vue/src/stores/tags.ts
git commit -m "feat(admin-ui): add tags view state"
~~~
## Task 5: 实现 RuoYi 侧栏和递归菜单
**Files:**
- Create: WonderQ-Admin-UI-Vue/src/components/layout/SidebarItem.vue
- Create: WonderQ-Admin-UI-Vue/src/components/layout/Sidebar.vue
- Create: WonderQ-Admin-UI-Vue/src/components/layout/TopMenu.vue
- Modify: WonderQ-Admin-UI-Vue/src/components/MenuTree.vue only if the old duplicate is still referenced.
- [ ] Step 1: 实现 SidebarItem.vue
接收 menu、basePath、collapsed 和 navigationType;目录使用 el-sub-menu,页面使用 el-menu-item,button 不渲染。标题同时渲染 LayoutIcon 和菜单名,路径使用现有 menu path。
- [ ] Step 2: 实现 Sidebar.vue 和 TopMenu.vue
读取 useAuthStore().menus,调用 visibleNavigableMenus,使用 el-scrollbar 和 el-menu 渲染。桌面端使用 collapse、unique-opened 和当前路由 active;mobile 通过 transform 控制抽屉并渲染遮罩。Logo 保留 WonderQ 品牌,显示/隐藏由布局设置控制。
TopMenu 在 navType 为 top 时渲染根级页面/目录,mix 模式下只渲染根级菜单并让 Sidebar 显示当前根菜单的子树;left 模式不渲染 TopMenu。三种模式只改变展示位置,不改变 auth.menus、权限码和路由。
- [ ] Step 3: 运行类型检查
Run: yarn build
Expected: Vue/TypeScript 编译通过;旧 MenuTree 如无引用则删除其引用,不删除业务菜单数据。
- [ ] Step 4: Commit
~~~powershell
git add -- WonderQ-Admin-UI-Vue/src/components/layout/SidebarItem.vue WonderQ-Admin-UI-Vue/src/components/layout/Sidebar.vue WonderQ-Admin-UI-Vue/src/components/MenuTree.vue
git commit -m "feat(admin-ui): implement RuoYi sidebar shell"
~~~
## Task 6: 实现 Navbar、Breadcrumb、UserMenu 和工具栏
**Files:**
- Create: WonderQ-Admin-UI-Vue/src/components/layout/Breadcrumb.vue
- Create: WonderQ-Admin-UI-Vue/src/components/layout/UserMenu.vue
- Create: WonderQ-Admin-UI-Vue/src/components/layout/Navbar.vue
- [ ] Step 1: 实现面包屑
使用 useRoute、useAuthStore 和 findMenuTitle;首页显示“首页概览”,业务页面显示父目录/页面标题;无菜单匹配时回退到 route.meta.title 或 route name,不新增后端字段。
- [ ] Step 2: 实现用户下拉
用户头像使用当前用户名称首字母或首个中文字符,菜单提供“布局设置”和“退出登录”。退出前调用 ElMessageBox.confirm("确定注销并退出系统吗?", "提示", ...),确认后执行 auth.logout() 并 router.replace({ name: "login" })。
- [ ] Step 3: 实现 Navbar 工具栏
固定 50px 高度,包含汉堡、Breadcrumb、全屏、明暗主题、布局设置和 UserMenu。全屏只调用 document.documentElement.requestFullscreen() / document.exitFullscreen();失败用 ElMessage.warning,不读写敏感浏览器数据。主题只切换 html 的 dark class 和布局变量。
- [ ] Step 4: Commit
~~~powershell
git add -- WonderQ-Admin-UI-Vue/src/components/layout/Navbar.vue WonderQ-Admin-UI-Vue/src/components/layout/Breadcrumb.vue WonderQ-Admin-UI-Vue/src/components/layout/UserMenu.vue
git commit -m "feat(admin-ui): add RuoYi navbar and user tools"
~~~
## Task 7: 实现 TagsView 和布局设置抽屉
**Files:**
- Create: WonderQ-Admin-UI-Vue/src/components/layout/TagsView.vue
- Create: WonderQ-Admin-UI-Vue/src/components/layout/SettingsDrawer.vue
- Create: WonderQ-Admin-UI-Vue/src/stores/settings.ts
- Create: WonderQ-Admin-UI-Vue/src/components/layout/Footer.vue
- [ ] Step 1: 实现 TagsView
监听 router.afterEach 或布局层路由变化,调用 tags.addView(route)。页签使用 router-link,当前页 active;关闭按钮阻止冒泡;右键菜单使用 fixed 定位并在 body click 时关闭。刷新用现有 routeViewKey 或等价的组件 key 重建。
- [ ] Step 2: 实现设置抽屉
使用 el-drawer 右侧 300px 宽度,显示左侧/混合/顶部菜单、深色/浅色侧栏、主色、TagsView、页签持久化/图标/样式、固定 Header、显示 Logo、动态标题和底部版权。依赖 TagsView 的选项在关闭时禁用;保存调用 saveLayoutSettings,重置调用 resetLayoutSettings。
useSettingsStore 以 layout-settings.ts 的默认值初始化响应式 settings,负责把 sideTheme、theme 和 dark class 应用到 document.documentElement,并提供 save、reset、toggleTheme 和 setSetting。Footer 只在 footerVisible 时显示 footerContent,默认关闭且不改变业务页面内容。
- [ ] Step 3: 测试和编译
Run: yarn test && yarn build
Expected: all tests PASS and production build completes.
- [ ] Step 4: Commit
~~~powershell
git add -- WonderQ-Admin-UI-Vue/src/components/layout/TagsView.vue WonderQ-Admin-UI-Vue/src/components/layout/SettingsDrawer.vue WonderQ-Admin-UI-Vue/src/components/layout/Footer.vue WonderQ-Admin-UI-Vue/src/stores/settings.ts
git commit -m "feat(admin-ui): add tags and layout settings interactions"
~~~
## Task 8: 组装 AdminLayout 并接入路由页签
**Files:**
- Modify: WonderQ-Admin-UI-Vue/src/layouts/AdminLayout.vue
- Modify: WonderQ-Admin-UI-Vue/src/router/index.ts
- Modify: WonderQ-Admin-UI-Vue/src/styles.css
- [ ] Step 1: 替换布局模板
~~~vue
<template>
<div class="app-wrapper" :class="{ mobile: layout.device === 'mobile', hideSidebar: !layout.sidebarOpened }">
<Sidebar />
<div class="main-container">
<div class="fixed-header" :class="{ 'without-tags': !settings.tagsView }">
<Navbar />
<TopMenu v-if="settings.navType !== 'left'" />
<TagsView v-if="settings.tagsView" />
</div>
<main class="app-main">
<RouterView v-slot="{ Component }">
<component :is="Component" :key="currentViewKey" />
</RouterView>
</main>
<Footer v-if="settings.footerVisible" />
</div>
<SettingsDrawer />
</div>
</template>
~~~
只保留一个真实 logout 实现,避免用户下拉和布局层重复确认或重复请求。
- [ ] Step 2: 补充静态路由 meta
给 dashboard、home、play、concierge、leads、media、tools 和 system resource 路由补充 title;dashboard 使用 affix: true。不修改 path、permission 或组件注册,动态菜单标题仍由 AdminMenu.name 提供。
- [ ] Step 3: 替换壳层 CSS
设置以下变量并实现固定 Header、主容器左边距过渡、折叠状态、移动抽屉、遮罩、TagsView 层级和 Element Plus 弹层层级:
~~~css
:root {
--sidebar-width: 200px;
--sidebar-collapsed-width: 54px;
--navbar-height: 50px;
--tags-height: 34px;
--sidebar-bg: #304156;
--sidebar-hover: #263445;
--sidebar-submenu-bg: #1f2d3d;
--sidebar-text: #bfcbd9;
--sidebar-active: #409eff;
--app-bg: #f5f7fa;
}
~~~
保留 .page-stack、业务网格、媒体和编辑器样式,移除旧壳的 244px、88px、浅色侧栏规则。
- [ ] Step 4: 运行自动检查
~~~powershell
yarn test
yarn build
~~~
Expected: all existing and new tests PASS; build completes without TypeScript errors.
- [ ] Step 5: Commit
~~~powershell
git add -- WonderQ-Admin-UI-Vue/src/layouts/AdminLayout.vue WonderQ-Admin-UI-Vue/src/router/index.ts WonderQ-Admin-UI-Vue/src/styles.css
git commit -m "feat(admin-ui): integrate RuoYi default admin shell"
~~~
## Task 9: 浏览器视觉与交互验收
**Files:**
- Modify only when verification finds a concrete defect: the relevant layout component or WonderQ-Admin-UI-Vue/src/styles.css.
- [ ] Step 1: 确认服务和工作区状态
Run in separate terminals:
~~~powershell
Set-Location .\WonderQ-Admin
.\.venv\Scripts\python.exe -m uvicorn app.main:app --host 0.0.0.0 --port 4000 --reload
~~~
~~~powershell
Set-Location .\WonderQ-Admin-UI-Vue
yarn dev
~~~
Do not run Alembic, seed, database reset, or migration repair during UI verification.
- [ ] Step 2: Verify desktop visual baseline at 1440px
Open http://localhost:5604/admin/ and verify sidebar 200px dark #304156, RuoYi blue active state, 50px Navbar, 34px TagsView, content below fixed header, and alignment of Logo, breadcrumb, tools, user dropdown and settings entry against the local RuoYi reference.
- [ ] Step 3: Verify shell interactions
Toggle sidebar; visit /home, /play, /leads; close/refresh tags; use tag right-click actions; open user menu; save settings; toggle theme and TagsView; enter fullscreen; cancel and confirm logout. Expected: unchanged route paths/API calls, no duplicate tags, no console errors.
- [ ] Step 4: Verify responsive states
At 1024px verify the 992px boundary. At 390px verify drawer, mask close, auto close after navigation, no horizontal scroll, and Element Plus dialogs/drawers above the mask.
- [ ] Step 5: Run final checks and inspect diff
~~~powershell
yarn test
yarn build
git diff --check HEAD~8..HEAD
git status --short
~~~
Expected: tests/build pass, no whitespace errors, only intended UI files are changed, and existing user changes remain untouched.