refactor: 清理废弃模块并重构管理端与全端代码
- 移除所有废弃的旧首页配置模块,包括destinationHero、demand相关、HomeExperience、vehicleService等表结构与代码,新增数据库迁移删除遗留表 - 重构管理端后台布局为标准RuoYi风格,新增Sidebar、Navbar、SettingsDrawer等组件,替换旧的过渡菜单实现 - 调整移动端响应断点为768px,更新布局相关测试用例,新增布局组件测试 - 删除OperationsTools发布/重置页面,移除/tools菜单入口,清理对应的API调用与测试代码 - 重构玩法模块编辑器:替换旧的图片手动输入框为图片上传组件,移除冗余的取消按钮 - 新增线索查询offset参数支持,完善查询参数处理逻辑 - 优化rbac菜单构建逻辑,新增可见性控制参数 - 修正管家编辑器提示文案,优化系统资源编辑器表单初始化逻辑 - 清理小程序端废弃的体验推荐组件与相关测试代码 - 更新文档与种子脚本,匹配新的API契约与使用说明
This commit is contained in:
@@ -0,0 +1,543 @@
|
||||
# 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.
|
||||
Reference in New Issue
Block a user