You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
RuoYi-Vue/docs/superpowers/plans/2026-06-28-frontend-moderni...

1280 lines
48 KiB

# RuoYi-Vue 前端现代化重构实施计划
> **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.
---
```yaml
---
change: refactor-frontend-modernization
design-doc: docs/superpowers/specs/2026-06-28-frontend-modernization-design.md
base-ref: 1c7d266b7f70eae46abd1f011e443ac54b4cc7f4
---
```
**Goal:** 将 RuoYi-Vue 前端从 Vue2 + Vue CLI + Element UI + Vuex 升级到 Vue3 + Vite + TypeScript + Element Plus + Pinia同时参考 demo-dashboard-heatmap.html 的深色主题和数据可视化风格,保持与现有后端 API 完全兼容。
**Architecture:** 采用渐进式迁移策略,先在独立目录 (`ruoyi-ui-next/`) 构建新项目,按模块逐步迁移组件和页面,确保后端零改动。
**Tech Stack:**
| 类别 | 旧技术栈 | 新技术栈 |
|------|---------|---------|
| 框架 | Vue 2.6.12 | Vue 3.5+ |
| 构建 | Vue CLI 4.4.6 | Vite 6+ |
| 语言 | JavaScript | TypeScript 5+ |
| UI | Element UI 2.15.6 | Element Plus 2.9+ |
| 路由 | Vue Router 3.4.9 | Vue Router 4+ |
| 状态 | Vuex 3.6.0 | Pinia 2.3+ |
| HTTP | Axios 0.24.0 | Axios 1.7+ |
| 图表 | ECharts 4.9.0 | ECharts 5.5+ |
| CSS | Sass 1.32 | SCSS + CSS Variables |
## Global Constraints
- **新项目目录**: `ruoyi-ui-next/`(与 `ruoyi-ui/` 并存,不影响现有前端)
- **后端兼容**: 所有 API 路径、请求格式、响应格式保持完全一致
- **权限兼容**: 沿用 `Admin-Token` Cookie 认证和 `*:*:*` 权限标识体系
- **深色主题默认**: 默认深色主题,配色方案源自 `data/demo-dashboard-heatmap.html`
- **TypeScript 严格模式**: 启用 `strict: true`,所有新增代码必须有类型标注
- **代码风格**: ESLint + Prettier + Vue 3 `<script setup>` 语法
- **组件命名**: PascalCase 文件名kebab-case 标签名
---
## Task 1: 项目初始化
**目标**: 使用 Vite 创建 Vue3 + TypeScript 项目骨架,配置开发工具链
**Files:**
- Create: `ruoyi-ui-next/package.json`
- Create: `ruoyi-ui-next/vite.config.ts`
- Create: `ruoyi-ui-next/tsconfig.json`
- Create: `ruoyi-ui-next/tsconfig.node.json`
- Create: `ruoyi-ui-next/index.html`
- Create: `ruoyi-ui-next/.env.development`
- Create: `ruoyi-ui-next/.env.production`
- Create: `ruoyi-ui-next/.eslintrc.cjs`
- Create: `ruoyi-ui-next/.prettierrc`
- Create: `ruoyi-ui-next/.editorconfig`
- Create: `ruoyi-ui-next/.gitignore`
- Create: `ruoyi-ui-next/src/main.ts`
- Create: `ruoyi-ui-next/src/App.vue`
- Reference: `ruoyi-ui/package.json`(依赖参考)
- Reference: `ruoyi-ui/.env.development`(环境变量参考)
**Description:** 创建全新 Vite + Vue3 + TypeScript 项目,配置完整的开发工具链和项目结构
**Dependencies:** 无
### Step 1: 初始化项目结构
```
ruoyi-ui-next/
├── public/
│ └── favicon.ico
├── src/
│ ├── api/ # API 调用层
│ │ ├── index.ts # 通用 API
│ │ ├── login.ts # 登录/认证
│ │ ├── menu.ts # 路由菜单
│ │ ├── system/ # 系统管理 API
│ │ │ ├── user.ts
│ │ │ ├── role.ts
│ │ │ ├── menu.ts
│ │ │ ├── dept.ts
│ │ │ ├── config.ts
│ │ │ ├── notice.ts
│ │ │ ├── post.ts
│ │ │ └── dict/
│ │ │ ├── data.ts
│ │ │ └── type.ts
│ │ ├── monitor/ # 系统监控 API
│ │ │ ├── cache.ts
│ │ │ ├── job.ts
│ │ │ ├── logininfor.ts
│ │ │ ├── online.ts
│ │ │ ├── operlog.ts
│ │ │ └── server.ts
│ │ ├── booksystem/ # 账本系统 API
│ │ │ ├── account.ts
│ │ │ ├── book.ts
│ │ │ ├── operations.ts
│ │ │ ├── statistics.ts
│ │ │ ├── statistictotal.ts
│ │ │ └── statisticremain.ts
│ │ └── stocksystem/ # 股票系统 API
│ │ ├── stocks.ts
│ │ ├── stockbasic.ts
│ │ ├── stockindex.ts
│ │ ├── financial.ts
│ │ ├── trends.ts
│ │ ├── trendStocks.ts
│ │ ├── newrecord.ts
│ │ ├── stockslimit.ts
│ │ └── book.ts
│ ├── assets/
│ │ ├── icons/svg/ # SVG 图标(从 ruoyi-ui 复制全部)
│ │ ├── styles/ # 全局样式
│ │ │ ├── index.scss
│ │ │ ├── variables.scss
│ │ │ ├── dark-theme.scss
│ │ │ └── transition.scss
│ │ └── images/ # 静态图片
│ ├── components/ # 全局通用组件
│ │ ├── SvgIcon/
│ │ ├── DictTag/
│ │ ├── Pagination/
│ │ ├── Breadcrumb/
│ │ ├── Hamburger/
│ │ ├── Screenfull/
│ │ ├── SizeSelect/
│ │ ├── ThemePicker/
│ │ ├── TopNav/
│ │ ├── RightToolbar/
│ │ ├── Editor/
│ │ ├── FileUpload/
│ │ ├── ImageUpload/
│ │ ├── ImagePreview/
│ │ ├── IconSelect/
│ │ ├── HeaderSearch/
│ │ ├── Crontab/
│ │ ├── ParentView/
│ │ └── iFrame/
│ ├── components-business/ # 业务组件(解耦通用组件)
│ │ ├── Kdialog/
│ │ ├── NegativeDialog/
│ │ └── TrendStocksDialog/
│ ├── layout/ # 布局框架
│ │ ├── index.vue
│ │ └── components/
│ │ ├── AppMain.vue
│ │ ├── Navbar.vue
│ │ ├── Sidebar/
│ │ ├── TagsView/
│ │ ├── Settings/
│ │ └── InnerLink/
│ ├── router/
│ │ └── index.ts
│ ├── stores/ # Pinia 状态管理
│ │ ├── index.ts
│ │ ├── modules/
│ │ │ ├── app.ts
│ │ │ ├── user.ts
│ │ │ ├── permission.ts
│ │ │ ├── tagsView.ts
│ │ │ └── settings.ts
│ │ └── types.ts
│ ├── views/ # 页面视图
│ │ ├── dashboard/
│ │ ├── system/
│ │ ├── booksystem/
│ │ ├── stocksystem/
│ │ ├── monitor/
│ │ ├── tool/
│ │ ├── error/
│ │ ├── login.vue
│ │ ├── register.vue
│ │ └── index.vue
│ ├── utils/ # 工具函数
│ │ ├── request.ts
│ │ ├── auth.ts
│ │ ├── permission.ts
│ │ ├── validate.ts
│ │ ├── errorCode.ts
│ │ ├── ruoyi.ts
│ │ ├── dict/
│ │ └── types/
│ ├── directives/ # 自定义指令
│ │ ├── index.ts
│ │ └── permission.ts
│ ├── plugins/ # 插件(从 ruoyi-ui 重构)
│ │ ├── index.ts
│ │ ├── auth.ts
│ │ ├── cache.ts
│ │ ├── modal.ts
│ │ └── tab.ts
│ ├── types/ # TypeScript 类型定义
│ │ ├── api.d.ts
│ │ ├── store.d.ts
│ │ ├── router.d.ts
│ │ └── global.d.ts
│ └── permission.ts # 路由权限守卫
├── index.html
├── vite.config.ts
├── tsconfig.json
├── package.json
└── .env.*
```
- [ ] **Step 1.1: 创建 package.json**
```json
{
"name": "ruoyi-ui-next",
"version": "4.0.0",
"private": true,
"type": "module",
"scripts": {
"dev": "vite",
"build": "vue-tsc --noEmit && vite build",
"build:prod": "vite build --mode production",
"preview": "vite preview",
"lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs,.ts,.tsx --fix",
"format": "prettier --write src/"
},
"dependencies": {
"vue": "^3.5.0",
"vue-router": "^4.4.0",
"pinia": "^2.3.0",
"pinia-plugin-persistedstate": "^4.0.0",
"axios": "^1.7.0",
"element-plus": "^2.9.0",
"@element-plus/icons-vue": "^2.3.0",
"echarts": "^5.5.0",
"nprogress": "^0.2.0",
"js-cookie": "^3.0.5",
"jsencrypt": "^3.3.0",
"lodash-es": "^4.17.21",
"dayjs": "^1.11.0"
},
"devDependencies": {
"@vitejs/plugin-vue": "^5.2.0",
"vite": "^6.0.0",
"vite-plugin-svg-icons": "^2.0.1",
"vue-tsc": "^2.2.0",
"typescript": "^5.7.0",
"sass": "^1.83.0",
"@types/node": "^22.0.0",
"@types/nprogress": "^0.2.3",
"@types/js-cookie": "^3.0.6",
"@types/lodash-es": "^4.17.12",
"eslint": "^9.0.0",
"@eslint/js": "^9.0.0",
"eslint-plugin-vue": "^9.0.0",
"typescript-eslint": "^8.0.0",
"prettier": "^3.4.0",
"unplugin-auto-import": "^0.18.0",
"unplugin-vue-components": "^0.27.0"
}
}
```
- [ ] **Step 1.2: 创建 vite.config.ts**
```typescript
import { defineConfig, loadEnv } from 'vite'
import vue from '@vitejs/plugin-vue'
import { resolve } from 'path'
import { createSvgIconsPlugin } from 'vite-plugin-svg-icons'
import AutoImport from 'unplugin-auto-import/vite'
import Components from 'unplugin-vue-components/vite'
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'
export default defineConfig(({ mode }) => {
const env = loadEnv(mode, process.cwd())
return {
plugins: [
vue(),
createSvgIconsPlugin({
iconDirs: [resolve(__dirname, 'src/assets/icons/svg')],
symbolId: 'icon-[dir]-[name]',
}),
AutoImport({
imports: ['vue', 'vue-router', 'pinia'],
resolvers: [ElementPlusResolver()],
dts: 'src/types/auto-imports.d.ts',
}),
Components({
resolvers: [ElementPlusResolver()],
dts: 'src/types/components.d.ts',
}),
],
resolve: {
alias: {
'@': resolve(__dirname, 'src'),
},
extensions: ['.ts', '.js', '.vue', '.json'],
},
server: {
port: 80,
host: '0.0.0.0',
open: true,
proxy: {
'/dev-api': {
target: env.VITE_APP_BASE_URL || 'http://localhost:8080',
changeOrigin: true,
rewrite: (path) => path.replace(/^\/dev-api/, ''),
},
},
},
build: {
target: 'es2015',
outDir: 'dist',
sourcemap: false,
rollupOptions: {
output: {
manualChunks: {
'element-plus': ['element-plus'],
echarts: ['echarts'],
},
},
},
},
css: {
preprocessorOptions: {
scss: {
additionalData: `@use "@/assets/styles/variables.scss" as *;`,
},
},
},
}
})
```
- [ ] **Step 1.3: 创建 tsconfig.json**
```json
{
"compilerOptions": {
"target": "ES2020",
"module": "ESNext",
"moduleResolution": "bundler",
"strict": true,
"jsx": "preserve",
"importHelpers": true,
"experimentalDecorators": true,
"skipLibCheck": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"forceConsistentCasingInFileNames": true,
"useDefineForClassFields": true,
"sourceMap": true,
"baseUrl": ".",
"paths": {
"@/*": ["src/*"]
},
"lib": ["ES2020", "DOM", "DOM.Iterable"],
"types": ["vite/client"]
},
"include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.vue"],
"exclude": ["node_modules", "dist"]
}
```
- [ ] **Step 1.4: 创建环境变量文件**
`.env.development`:
```
VITE_APP_TITLE=摸金分析系统
VITE_APP_BASE_API=/dev-api
VITE_APP_BASE_URL=http://localhost:8080
```
`.env.production`:
```
VITE_APP_TITLE=摸金分析系统
VITE_APP_BASE_API=/prod-api
VITE_APP_BASE_URL=
```
- [ ] **Step 1.5: 创建 .eslintrc.cjs + .prettierrc**
配置 ESLint 规则:
- `@typescript-eslint/strict`
- `vue/vue3-recommended`
- Prettier 集成
Prettier 配置:
- 2 空格缩进
- 单引号
- 末尾无分号
- 行宽 100
- [ ] **Step 1.6: 创建项目入口文件**
`src/main.ts`:
- 创建 Vue App
- 注册 Element Plus含中文语言包
- 注册 Pinia
- 注册 Vue Router
- 注册全局指令
- 注册全局插件
- 挂载应用
`src/App.vue`:
- 根组件,仅包含 `<router-view />`
- [ ] **Step 1.7: 复制 SVG 图标资源**
`ruoyi-ui/src/assets/icons/svg/` 复制所有 SVG 文件到 `ruoyi-ui-next/src/assets/icons/svg/`
**验收标准:**
- [ ] `npm install` 无报错
- [ ] `npm run dev` 成功启动,访问 `http://localhost` 显示空白页面(仅 App.vue
- [ ] TypeScript 编译通过(`vue-tsc --noEmit`
- [ ] ESLint 检查通过(`npm run lint`
- [ ] 项目结构与规范一致
- [ ] `ruoyi-ui/` 不受任何影响
---
## Task 2: 核心架构搭建
**目标**: 配置 Vue Router 4、Pinia 状态管理、Axios 调用层、权限控制机制
**Files:**
- Create: `ruoyi-ui-next/src/router/index.ts`
- Create: `ruoyi-ui-next/src/stores/index.ts`
- Create: `ruoyi-ui-next/src/stores/modules/app.ts`
- Create: `ruoyi-ui-next/src/stores/modules/user.ts`
- Create: `ruoyi-ui-next/src/stores/modules/permission.ts`
- Create: `ruoyi-ui-next/src/stores/modules/tagsView.ts`
- Create: `ruoyi-ui-next/src/stores/modules/settings.ts`
- Create: `ruoyi-ui-next/src/stores/types.ts`
- Create: `ruoyi-ui-next/src/utils/request.ts`
- Create: `ruoyi-ui-next/src/utils/auth.ts`
- Create: `ruoyi-ui-next/src/utils/permission.ts`
- Create: `ruoyi-ui-next/src/utils/errorCode.ts`
- Create: `ruoyi-ui-next/src/utils/types/api.ts`
- Create: `ruoyi-ui-next/src/types/global.d.ts`
- Create: `ruoyi-ui-next/src/types/store.d.ts`
- Create: `ruoyi-ui-next/src/types/router.d.ts`
- Create: `ruoyi-ui-next/src/directives/index.ts`
- Create: `ruoyi-ui-next/src/directives/permission.ts`
- Create: `ruoyi-ui-next/src/plugins/index.ts`
- Create: `ruoyi-ui-next/src/plugins/auth.ts`
- Create: `ruoyi-ui-next/src/plugins/cache.ts`
- Create: `ruoyi-ui-next/src/plugins/modal.ts`
- Create: `ruoyi-ui-next/src/plugins/tab.ts`
- Create: `ruoyi-ui-next/src/permission.ts`
- Reference: `ruoyi-ui/src/router/index.js`
- Reference: `ruoyi-ui/src/store/modules/*.js`
- Reference: `ruoyi-ui/src/utils/request.js`
- Reference: `ruoyi-ui/src/permission.js`
- Reference: `ruoyi-ui/src/plugins/*.js`
- Reference: `ruoyi-ui/src/directive/`
**Dependencies:** Task 1 完成
### Step 2.1: 配置 TypeScript 类型定义
定义全局类型:
```typescript
// src/types/global.d.ts
interface AjaxResult {
code: number
msg: string
data: any
}
interface TableDataInfo {
code: number
msg: string
total: number
rows: any[]
}
interface MenuOption {
name: string
path: string
hidden?: boolean
redirect?: string
component?: string
alwaysShow?: boolean
meta?: {
title: string
icon?: string
noCache?: boolean
link?: string
}
children?: MenuOption[]
}
```
- [ ] 定义 `AjaxResult` 通用响应类型
- [ ] 定义 `TableDataInfo` 分页响应类型
- [ ] 定义 `MenuOption` 菜单路由类型
- [ ] 定义 `DictDataType` 字典数据类型
- [ ] 定义 `PaginationState` 分页状态类型
### Step 2.2: 配置 Vue Router 4
- [ ] 创建 `router/index.ts`,使用 `createRouter` + `createWebHistory`
- [ ] 配置静态路由(`/login`、`/register`、`/404`、`/401`、首页重定向)
- [ ] 配置动态路由占位(登录后从后端加载)
- [ ] 实现 `loadView` 懒加载函数(统一使用 `() => import()`
- [ ] 路由类型使用 `RouteRecordRaw`Vue Router 4
- [ ] 配置滚动行为 `scrollBehavior`
### Step 2.3: 配置 Pinia 状态管理
替换 Vuex 5 个模块为 Pinia stores
**app store** (`stores/modules/app.ts`):
- [ ] `sidebar` (opened, withoutAnimation) — 侧边栏状态
- [ ] `device` ('desktop' | 'mobile') — 设备类型
- [ ] `size` ('default' | 'large' | 'small') — 组件尺寸Element Plus 命名调整)
- [ ] 使用 `pinia-plugin-persistedstate` 持久化到 Cookie/localStorage
**user store** (`stores/modules/user.ts`):
- [ ] `token`, `name`, `avatar`, `roles`, `permissions`
- [ ] Actions: `login()`, `getInfo()`, `logout()`, `fedLogout()`
- [ ] 登录调用 `POST /login`(保持与现有后端一致)
- [ ] Token 存储到 Cookie键名 `Admin-Token`,与后端一致)
**permission store** (`stores/modules/permission.ts`):
- [ ] `routes`: 完整路由表
- [ ] `addRoutes`: 动态添加的路由
- [ ] `sidebarRouters`: 侧边栏显示的路由
- [ ] Action: `generateRoutes(roles)` — 从后端 `/getRouters` 获取菜单并转换为路由
- [ ] 实现 `filterAsyncRouter` 字符串组件路径转 import 函数
- [ ] 实现权限过滤逻辑
**tagsView store** (`stores/modules/tagsView.ts`):
- [ ] `visitedViews`: 已访问标签页列表
- [ ] `cachedViews`: keep-alive 缓存列表
- [ ] Actions: `addView`, `delView`, `delOthersViews`, `delAllViews`, `delRightTags`, `delLeftTags`
**settings store** (`stores/modules/settings.ts`):
- [ ] `theme`, `sideTheme`, `showSettings`
- [ ] `topNav`, `tagsView`, `fixedHeader`, `sidebarLogo`, `dynamicTitle`
- [ ] 持久化到 localStorage键名 `layout-setting`
### Step 2.4: 配置 Axios 调用层
`src/utils/request.ts`:
- [ ] 创建 Axios 实例,`baseURL = import.meta.env.VITE_APP_BASE_API`
- [ ] 设置 `timeout: 60000`
- [ ] 请求拦截器:注入 `Authorization: Bearer {token}`(支持 `isToken: false` 跳过)
- [ ] 请求拦截器GET 参数序列化(复用 `tansParams` 逻辑)
- [ ] 响应拦截器:解析 `res.data.code`,处理 401/500/其他
- [ ] 401 处理:使用 `ElMessageBox.confirm` → 退出登录 → `router.replace('/')`(修复原 `location.href` 硬跳转问题)
- [ ] 响应拦截器HTTP 错误处理Network Error / Timeout / 4xx / 5xx
- [ ] 导出 `download(url, params, filename)` 方法blob 下载 + 登录态处理)
### Step 2.5: 配置权限控制
- [ ] **路由守卫** (`src/permission.ts`):
- 白名单检查(`/login`, `/register`, 等)
- Token 验证(从 Cookie 读取 `Admin-Token`
- 用户信息加载roles + permissions
- 动态路由注册(`router.addRoute`
- 页面标题设置
- [ ] **指令权限** (`src/directives/permission.ts`):
- `v-hasPermi` 指令:检查权限标识
- `v-hasRole` 指令:检查角色
- 支持超级权限 `*:*:*`
- 支持超级角色 `admin`
- [ ] **全局方法** (`src/plugins/auth.ts`):
- `$auth.hasPermi(permission)` 方法
- `$auth.hasRole(role)` 方法
### Step 2.6: 配置插件系统
重构 `ruoyi-ui/src/plugins/` 下的插件:
- [ ] `modal.ts` — 全局弹窗封装ElMessage, ElMessageBox, ElNotification
- [ ] `cache.ts` — 缓存封装localStorage + sessionStorage带过期支持
- [ ] `tab.ts` — 标签页操作(切换、关闭、刷新)
- [ ] `auth.ts` — 权限校验方法
- [ ] `index.ts` — 统一注册为 Vue 全局属性
**验收标准:**
- [ ] Pinia DevTools 可查看 5 个 store 状态
- [ ] 访问 `/login` 页面可正常渲染
- [ ] Axios 请求拦截器正确注入 Token
- [ ] 401 响应触发确认弹窗而非硬跳转
- [ ] `v-hasPermi` 指令在元素上正确隐藏/显示
- [ ] 路由守卫阻止未登录访问受保护页面
- [ ] TypeScript 编译零错误
---
## Task 3: 深色主题和 UI 框架
**目标**: 安装配置 Element Plus实现深色主题系统配置 CSS 变量
**Files:**
- Create: `ruoyi-ui-next/src/assets/styles/variables.scss`
- Create: `ruoyi-ui-next/src/assets/styles/dark-theme.scss`
- Create: `ruoyi-ui-next/src/assets/styles/index.scss`
- Create: `ruoyi-ui-next/src/assets/styles/element-override.scss`
- Create: `ruoyi-ui-next/src/assets/styles/sidebar.scss`
- Create: `ruoyi-ui-next/src/assets/styles/transition.scss`
- Create: `ruoyi-ui-next/src/assets/styles/btn.scss`
- Reference: `ruoyi-ui/src/assets/styles/` 目录
- Reference: `data/demo-dashboard-heatmap.html`(深色主题配色来源)
**Dependencies:** Task 1, Task 2 完成
### Step 3.1: 安装 Element Plus
- [ ] 确认 `element-plus` 已安装Task 1 package.json
- [ ] 配置按需导入(通过 `unplugin-vue-components` 自动按需导入组件)
- [ ] 安装 `@element-plus/icons-vue` 图标库
- [ ] 配置 Element Plus 中文语言包
### Step 3.2: 实现深色主题 CSS 变量
基于 demo-dashboard-heatmap.html 的配色方案:
```scss
// src/assets/styles/variables.scss
// 源自 demo-dashboard-heatmap.html 的深色主题
:root {
// 背景色
--bg-primary: #0d1117; // 最深背景 (--bg0)
--bg-secondary: #161b22; // 侧边栏/顶栏 (--bg1)
--bg-tertiary: #1c2333; // 卡片背景 (--bg2)
--bg-elevated: #2a3040; // 悬浮背景 (--bg3)
// 边框
--border-color: #30363d; // 边框色 (--bd)
// 文字
--text-primary: #e6edf3; // 主文字 (--t1)
--text-secondary: #8b949e; // 次要文字 (--t2)
--text-muted: #6e7681; // 弱化文字 (--tm)
// 功能色
--color-danger: #f85149; // 红色/下跌 (--red)
--color-success: #3fb950; // 绿色/上涨 (--grn)
--color-warning: #d29922; // 橙色 (--org)
--color-info: #58a6ff; // 蓝色 (--blu)
// 热力图排名色阶
--heat-1: #ff4444;
--heat-2: #ff6b6b;
--heat-3: #ff9a76;
--heat-4: #ffa502;
--heat-5: #e3b341;
--heat-6: #e6d34a;
--heat-7: #8bda5e;
--heat-8: #4dd08b;
--heat-9: #36b37e;
--heat-10: #2d9cdb;
// 布局
--sidebar-width: 200px;
--navbar-height: 50px;
--tags-view-height: 34px;
}
```
- [ ] 创建 `variables.scss` 定义所有 CSS 变量
- [ ] 创建 `dark-theme.scss` 包含热力图排名色阶样式
- [ ] 创建 `element-override.scss` 覆盖 Element Plus 默认样式为深色
- [ ] 创建 `index.scss` 整合所有样式文件
- [ ] 创建 `sidebar.scss` 侧边栏专属样式
- [ ] 创建 `transition.scss` 过渡动画样式
- [ ] 创建 `btn.scss` 按钮工具类
### Step 3.3: 覆盖 Element Plus 深色主题
- [ ] 覆盖 `el-menu` 侧边栏菜单背景色和文字色
- [ ] 覆盖 `el-table` 表格背景色和边框色
- [ ] 覆盖 `el-dialog` 弹窗背景色
- [ ] 覆盖 `el-input` / `el-select` / `el-date-picker` 表单组件
- [ ] 覆盖 `el-pagination` 分页组件
- [ ] 覆盖 `el-message-box` / `el-notification`
- [ ] 覆盖 `el-tag` 标签组件
### Step 3.4: 实现主题切换功能
- [ ] 创建 ThemePicker 组件(支持深色/浅色切换)
- [ ] 使用 CSS `data-theme` 属性切换主题
- [ ] 在 settings store 中保存主题偏好
- [ ] 默认主题为深色
- [ ] 主题切换时无闪烁过渡
### Step 3.5: 配置全局样式
- [ ] 重置默认样式margin/padding/box-sizing
- [ ] 配置滚动条样式(`::-webkit-scrollbar`
- [ ] 配置通用工具类(`.mt-10`, `.mb-10`, `.flex`, `.text-center` 等)
- [ ] 配置 NProgress 进度条深色样式
**验收标准:**
- [ ] 深色主题默认渲染正确
- [ ] Element Plus 组件在深色主题下视觉一致
- [ ] 主题切换功能正常工作
- [ ] CSS 变量在 DevTools 中可查看
- [ ] 热力图排名色阶样式正确1-10 级 + >10 级)
- [ ] 与 demo-dashboard-heatmap.html 配色方案一致
---
## Task 4: 核心组件迁移
**目标**: 迁移布局组件和通用组件,重构为 Composition API + TypeScript
**Files:**
- Create: `ruoyi-ui-next/src/layout/index.vue`
- Create: `ruoyi-ui-next/src/layout/components/AppMain.vue`
- Create: `ruoyi-ui-next/src/layout/components/Navbar.vue`
- Create: `ruoyi-ui-next/src/layout/components/Sidebar/index.vue`
- Create: `ruoyi-ui-next/src/layout/components/Sidebar/SidebarItem.vue`
- Create: `ruoyi-ui-next/src/layout/components/Sidebar/Item.vue`
- Create: `ruoyi-ui-next/src/layout/components/Sidebar/Link.vue`
- Create: `ruoyi-ui-next/src/layout/components/Sidebar/Logo.vue`
- Create: `ruoyi-ui-next/src/layout/components/TagsView/index.vue`
- Create: `ruoyi-ui-next/src/layout/components/TagsView/ScrollPane.vue`
- Create: `ruoyi-ui-next/src/layout/components/Settings/index.vue`
- Create: `ruoyi-ui-next/src/layout/components/InnerLink/index.vue`
- Create: `ruoyi-ui-next/src/components/Breadcrumb/index.vue`
- Create: `ruoyi-ui-next/src/components/Pagination/index.vue`
- Create: `ruoyi-ui-next/src/components/DictTag/index.vue`
- Create: `ruoyi-ui-next/src/components/SvgIcon/index.vue`
- Create: `ruoyi-ui-next/src/components/Hamburger/index.vue`
- Create: `ruoyi-ui-next/src/components/Screenfull/index.vue`
- Create: `ruoyi-ui-next/src/components/SizeSelect/index.vue`
- Create: `ruoyi-ui-next/src/components/ThemePicker/index.vue`
- Create: `ruoyi-ui-next/src/components/TopNav/index.vue`
- Create: `ruoyi-ui-next/src/components/RightToolbar/index.vue`
- Create: `ruoyi-ui-next/src/components/Editor/index.vue`
- Create: `ruoyi-ui-next/src/components/FileUpload/index.vue`
- Create: `ruoyi-ui-next/src/components/ImageUpload/index.vue`
- Create: `ruoyi-ui-next/src/components/ImagePreview/index.vue`
- Create: `ruoyi-ui-next/src/components/IconSelect/index.vue`
- Create: `ruoyi-ui-next/src/components/HeaderSearch/index.vue`
- Create: `ruoyi-ui-next/src/components/Crontab/index.vue`
- Create: `ruoyi-ui-next/src/components/Crontab/day.vue`
- Create: `ruoyi-ui-next/src/components/Crontab/hour.vue`
- Create: `ruoyi-ui-next/src/components/Crontab/min.vue`
- Create: `ruoyi-ui-next/src/components/Crontab/month.vue`
- Create: `ruoyi-ui-next/src/components/Crontab/week.vue`
- Create: `ruoyi-ui-next/src/components/Crontab/year.vue`
- Create: `ruoyi-ui-next/src/components/Crontab/second.vue`
- Create: `ruoyi-ui-next/src/components/Crontab/result.vue`
- Create: `ruoyi-ui-next/src/components/ParentView/index.vue`
- Create: `ruoyi-ui-next/src/components/iFrame/index.vue`
- Reference: `ruoyi-ui/src/layout/` 目录所有文件
- Reference: `ruoyi-ui/src/components/` 目录所有文件
**Dependencies:** Task 1, Task 2, Task 3 完成
### Step 4.1: 迁移布局组件
- [ ] **Layout** (`layout/index.vue`): 主布局容器,使用 `<script setup lang="ts">`,使用 `useAppStore()` 获取侧边栏状态
- [ ] **AppMain**: 主内容区,包含 `<router-view>` + `<keep-alive>` + `<transition>`
- [ ] **Navbar**: 顶部导航栏,包含 Hamburger、Breadcrumb、搜索、全屏、通知、用户下拉菜单
- [ ] **Sidebar**: 侧边栏,包含 Logo + Menu + SidebarItem 递归渲染
- [ ] **SidebarItem**: 递归菜单项,支持嵌套路由
- [ ] **TagsView**: 标签页视图,支持右键菜单(刷新、关闭其他、关闭全部)
- [ ] **Settings**: 系统设置面板(主题、顶栏、标签页等开关)
- [ ] 移除 `ResizeHandler.js` Mixin改用 `useResize()` Composition API 函数
### Step 4.2: 迁移高复用通用组件
每个组件迁移要求:
- 使用 `<script setup lang="ts">` 语法
- Props 使用 `defineProps<T>()` 类型标注
- Emits 使用 `defineEmits<T>()` 类型标注
- 移除 Vue 2 Mixin改用 Composition API
- 保持原有功能不变
**高优先级组件(按复用程度)**:
- [ ] **Pagination**: 分页组件Props 包括 `total`, `page`, `limit`Emits `update:page`, `update:limit`, `pagination`
- [ ] **DictTag**: 字典标签渲染Props 包括 `options`, `value`
- [ ] **RightToolbar**: 右侧工具栏搜索、显隐列Props 包括 `showSearch`, `columns`
- [ ] **Breadcrumb**: 面包屑导航,读取 `useRoute()` 生成面包屑
- [ ] **SvgIcon**: SVG 图标封装,使用 `vite-plugin-svg-icons`
- [ ] **Hamburger**: 汉堡菜单按钮
**中优先级组件**:
- [ ] **Screenfull**: 全屏切换
- [ ] **SizeSelect**: 组件尺寸选择
- [ ] **ThemePicker**: 主题选择器(与 Task 3 整合)
- [ ] **TopNav**: 顶部导航菜单
- [ ] **Editor**: 富文本编辑器Quill确认依赖兼容性
- [ ] **FileUpload**: 文件上传
- [ ] **ImageUpload**: 图片上传
- [ ] **ImagePreview**: 图片预览
**低优先级组件**:
- [ ] **HeaderSearch**: 头部搜索Fuse.js 全文搜索)
- [ ] **IconSelect**: SVG 图标选择器
- [ ] **Crontab**: Cron 表达式生成器9 个子组件)
- [ ] **ParentView**: 父级视图占位
- [ ] **iFrame**: 内嵌 iframe
### Step 4.3: 迁移业务组件
将业务组件从 `src/components/` 移至 `src/components-business/`
- [ ] **Kdialog**: K 线对话框 → `components-business/Kdialog/`
- [ ] **NegativeDialog**: 涨跌停对话框 → `components-business/NegativeDialog/`
- [ ] **TrendStocksDialog**: 板块趋势对话框 → `components-business/TrendStocksDialog/`
### Step 4.4: 全局注册策略
- [ ] 高复用组件Pagination, DictTag, SvgIcon, RightToolbar自动全局注册
- [ ] 布局组件按需导入
- [ ] 业务组件按需导入(仅在其所属模块页面中引用)
- [ ] 移除 `ruoyi-ui/src/main.js` 中的 `Vue.component()` 全局注册方式
### Step 4.5: 字典系统重构
- [ ] 重构 `DictData` 模块为 TypeScript
- [ ] 创建 `utils/dict/index.ts` 统一管理字典加载
- [ ] 字典缓存使用 Pinia store 而非全局变量
- [ ] 保持 `getDicts(dictType)` API 调用兼容
**验收标准:**
- [ ] 所有组件使用 `<script setup lang="ts">` 语法
- [ ] Props 和 Emits 有完整 TypeScript 类型定义
- [ ] 无 Vue 2 特有 API 使用(`this.$xxx`, `Vue.extend`, Mixin
- [ ] Layout 布局渲染正确Sidebar + Navbar + TagsView + AppMain
- [ ] Pagination 组件在列表中正常工作
- [ ] DictTag 正确渲染字典标签
- [ ] SvgIcon 正确渲染 SVG 图标
- [ ] 业务组件不再污染全局组件注册表
- [ ] 组件无 ESLint 报错
---
## Task 5: 数据可视化实现
**目标**: 安装配置 ECharts 5实现行情总览和趋势热力图页面
**Files:**
- Create: `ruoyi-ui-next/src/views/dashboard/index.vue` — 行情总览页面
- Create: `ruoyi-ui-next/src/views/dashboard/components/StatsCards.vue` — 统计卡片
- Create: `ruoyi-ui-next/src/views/dashboard/components/SentimentRow.vue` — 情绪指标行
- Create: `ruoyi-ui-next/src/views/dashboard/components/UpDownChart.vue` — 涨跌分布图
- [ ] Create: `ruoyi-ui-next/src/views/dashboard/components/TopTrends.vue` — 趋势板块 TOP 10
- Create: `ruoyi-ui-next/src/views/dashboard/components/TrendChanges.vue` — 趋势变化榜
- Create: `ruoyi-ui-next/src/views/dashboard/components/ConsecutiveStats.vue` — 连续统计
- Create: `ruoyi-ui-next/src/views/heatmap/index.vue` — 趋势热力图页面
- Create: `ruoyi-ui-next/src/views/heatmap/components/HeatmapMatrix.vue` — 热力矩阵
- Create: `ruoyi-ui-next/src/views/heatmap/components/EnhancedTable.vue` — 增强表格
- Create: `ruoyi-ui-next/src/views/heatmap/components/DetailModal.vue` — 详情弹窗
- Create: `ruoyi-ui-next/src/utils/echarts.ts` — ECharts 封装工具
- Reference: `data/demo-dashboard-heatmap.html`UI 参考)
- Reference: `ruoyi-ui/src/views/dashboard/` 目录(旧图表组件)
**Dependencies:** Task 1, Task 2, Task 3, Task 4 完成
### Step 5.1: 配置 ECharts 5
- [ ] 确认 `echarts@^5.5.0` 已安装
- [ ] 创建 `utils/echarts.ts` 封装工具:
- `initChart(dom, theme)` — 初始化图表
- `resizeChart(chart)` — 响应式调整
- 自定义深色主题配置(与全局 CSS 变量一致)
- [ ] 创建 `useECharts` Composition API Hook
- 自动处理 resize
- 自动处理组件卸载时的 dispose
- 支持响应式 option 更新
### Step 5.2: 实现行情总览页面
参考 demo-dashboard-heatmap.html 中 `#pg-dashboard` 的布局:
```
行情总览布局:
├── 市场范围筛选器全A / 上证 / 深证 / 创业板 / 科创板 / 中证1000
├── 迷你统计卡片4 格)
│ ├── 上涨家数
│ ├── 下跌家数
│ ├── 涨停家数
│ └── 跌停家数
├── 情绪指标行4 格)
│ ├── 全A情绪含进度条 + 元信息)
│ ├── 中证1000情绪
│ ├── 创业板情绪
│ └── 科创板情绪
├── 双列布局
│ ├── 左涨跌分布柱状图ECharts
│ └── 右:趋势板块 TOP 10表格
└── 双列布局
├── 左:趋势变化榜(上升/下降列表)
└── 右:强势板块连续统计(表格)
```
- [ ] **StatsCards**: 4 格迷你统计卡片组件
- [ ] **SentimentRow**: 情绪指标行,含热力色阶进度条
- [ ] **UpDownChart**: ECharts 涨跌分布柱状图
- [ ] **TopTrends**: 趋势板块 TOP 10 表格(含排名徽章、动量信号、详情按钮)
- [ ] **TrendChanges**: 趋势变化榜(上升红色/下降绿色箭头)
- [ ] **ConsecutiveStats**: 连续统计表格
### Step 5.3: 实现趋势热力图页面
参考 demo-dashboard-heatmap.html 中 `#pg-heatmap` 的布局:
```
趋势热力图布局:
├── 筛选栏动量周期1日/3日/5日/10日/15日/20日/30日 + 日期选择 + 刷新)
├── 视图切换(热力矩阵 / 增强表格)
├── 热力矩阵视图
│ └── 2级行业 × 交易日排名矩阵
│ └── 点击单元格 → 详情弹窗
└── 增强表格视图
└── 行业 × 日期排名 + 趋势变化
```
- [ ] **HeatmapMatrix**: 热力矩阵组件
- 2 级行业为行,交易日为列
- 排名 1-10 使用色阶渐变(源自 CSS 变量 `--heat-1``--heat-10`
- 排名 >10 使用默认灰色
- 点击单元格触发详情弹窗
- [ ] **EnhancedTable**: 增强表格视图
- 行业 × 日期排名
- 趋势变化列(上升/下降)
- [ ] **DetailModal**: 详情弹窗
- 统计卡片当前动量、近5日趋势、涨停家数、创新高、连续天数、平均排名
- ECharts K 线图
- ECharts 排名趋势折线图
- Tab 切换(概览 / 排名趋势 / 成分股 / 历史数据)
### Step 5.4: 数据卡片和统计组件
- [ ] 创建通用 `StatCard` 组件label + value + sub
- [ ] 创建通用 `MiniBarChart` 组件(小型柱状图)
- [ ] 创建通用 `RankBadge` 组件排名徽章1-3 金色/2 银色/3 铜色/其他普通)
- [ ] 创建通用 `SignalTag` 组件(动量信号标签)
### Step 5.5: 数据适配层
- [ ] 创建 Mock 数据(开发阶段使用)
- [ ] 创建 API 调用函数(连接后端实际接口)
- [ ] 确保数据格式与现有后端 API 兼容
**验收标准:**
- [ ] 行情总览页面渲染正确,布局与 demo 一致
- [ ] 趋势热力图页面渲染正确,热力矩阵色阶正确
- [ ] ECharts 图表在窗口缩放时自适应
- [ ] 点击热力图单元格可打开详情弹窗
- [ ] 详情弹窗中 K 线图和排名趋势图正确渲染
- [ ] 视图切换(热力矩阵/增强表格)正常工作
- [ ] 所有图表使用深色主题
- [ ] 组件使用 Composition API + TypeScript
---
## Task 6: 业务模块迁移
**目标**: 迁移所有业务模块页面,保持与后端 API 兼容
**Files:**
- Create: `ruoyi-ui-next/src/views/system/user/index.vue` — 用户管理
- Create: `ruoyi-ui-next/src/views/system/role/index.vue` — 角色管理
- Create: `ruoyi-ui-next/src/views/system/menu/index.vue` — 菜单管理
- Create: `ruoyi-ui-next/src/views/system/dept/index.vue` — 部门管理
- Create: `ruoyi-ui-next/src/views/system/config/index.vue` — 参数配置
- Create: `ruoyi-ui-next/src/views/system/notice/index.vue` — 通知公告
- Create: `ruoyi-ui-next/src/views/system/post/index.vue` — 岗位管理
- Create: `ruoyi-ui-next/src/views/system/dict/index.vue` — 字典管理
- Create: `ruoyi-ui-next/src/views/system/dict/data.vue` — 字典数据
- Create: `ruoyi-ui-next/src/views/system/user/profile/index.vue` — 个人中心
- Create: `ruoyi-ui-next/src/views/system/role/authUser.vue` — 角色分配用户
- Create: `ruoyi-ui-next/src/views/books/account/index.vue` — 交易账户
- Create: `ruoyi-ui-next/src/views/books/book/index.vue` — 账本管理
- Create: `ruoyi-ui-next/src/views/books/operations/index.vue` — 操作记录
- Create: `ruoyi-ui-next/src/views/books/statistics/index.vue` — 统计分析
- Create: `ruoyi-ui-next/src/views/books/statistictotal/index.vue` — 统计汇总
- Create: `ruoyi-ui-next/src/views/books/statisticremain/index.vue` — 统计结余
- Create: `ruoyi-ui-next/src/views/stocks/stocks/index.vue` — 股票列表
- Create: `ruoyi-ui-next/src/views/stocks/stockbasic/index.vue` — 股票基础信息
- Create: `ruoyi-ui-next/src/views/stocks/stockindex/index.vue` — 指数信息
- Create: `ruoyi-ui-next/src/views/stocks/financial/index.vue` — 财务数据
- Create: `ruoyi-ui-next/src/views/stocks/trends/index.vue` — 趋势数据
- Create: `ruoyi-ui-next/src/views/stocks/trendStocks/index.vue` — 板块趋势
- Create: `ruoyi-ui-next/src/views/stocks/newrecord/index.vue` — 新增记录
- Create: `ruoyi-ui-next/src/views/stocks/stockslimit/index.vue` — 涨跌停
- Create: `ruoyi-ui-next/src/views/stocks/book/index.vue` — 股票账本
- Create: `ruoyi-ui-next/src/views/monitor/cache/index.vue` — 缓存监控
- Create: `ruoyi-ui-next/src/views/monitor/job/index.vue` — 定时任务
- Create: `ruoyi-ui-next/src/views/monitor/job/log.vue` — 调度日志
- Create: `ruoyi-ui-next/src/views/monitor/logininfor/index.vue` — 登录日志
- Create: `ruoyi-ui-next/src/views/monitor/online/index.vue` — 在线用户
- Create: `ruoyi-ui-next/src/views/monitor/operlog/index.vue` — 操作日志
- Create: `ruoyi-ui-next/src/views/monitor/server/index.vue` — 服务器监控
- Create: `ruoyi-ui-next/src/views/tool/gen/index.vue` — 代码生成
- Create: `ruoyi-ui-next/src/views/login.vue` — 登录页
- Create: `ruoyi-ui-next/src/views/register.vue` — 注册页
- Create: `ruoyi-ui-next/src/views/error/401.vue` — 401 错误页
- Create: `ruoyi-ui-next/src/views/error/404.vue` — 404 错误页
- Create: `ruoyi-ui-next/src/api/*.ts` — 所有 API 模块TypeScript
- Reference: `ruoyi-ui/src/views/` 目录所有页面文件
- Reference: `ruoyi-ui/src/api/` 目录所有 API 文件
**Dependencies:** Task 1, Task 2, Task 3, Task 4 完成
### Step 6.1: 迁移 API 调用层
`ruoyi-ui/src/api/` 下所有 `.js` 文件重构为 `.ts` 文件:
- [ ] **API 类型定义** — 为每个 API 模块定义请求参数和响应类型
- [ ] **system API** (8 文件) — user, role, menu, dept, config, notice, post, dict(data+type)
- [ ] **monitor API** (6 文件) — cache, job, jobLog, logininfor, online, operlog, server
- [ ] **booksystem API** (6 文件) — account, book, operations, statistics, statistictotal, statisticremain
- [ ] **stocksystem API** (9 文件) — stocks, stockbasic, stockindex, financial, trends, trendStocks, newrecord, stockslimit, book
- [ ] 保持 API 路径完全一致(如 `/system/user/list` 不变)
- [ ] 使用 `request.get<T>()` / `request.post<T>()` 泛型方法
### Step 6.2: 迁移系统管理模块10+ 页面)
每个页面迁移要求:
- 使用 `<script setup lang="ts">` 语法
- 使用 Composition API 替代 Vue 2 Options API
- API 调用使用 TypeScript 类型
- 使用 Element Plus 组件替代 Element UI
- 保持搜索表单 + 表格 + 分页 + 弹窗的 CRUD 布局
- 使用 `v-hasPermi` 指令控制按钮权限
- 使用 `DictTag` 组件展示字典
- 使用 `Pagination` 组件分页
页面清单:
- [ ] **用户管理** — 用户列表、新增/编辑弹窗、分配角色、导入/导出
- [ ] **角色管理** — 角色列表、权限分配、数据权限、分配用户
- [ ] **菜单管理** — 菜单树、新增/编辑弹窗、图标选择
- [ ] **部门管理** — 部门树、新增/编辑弹窗
- [ ] **参数配置** — 配置列表、新增/编辑弹窗
- [ ] **通知公告** — 公告列表、富文本编辑
- [ ] **岗位管理** — 岗位列表、新增/编辑弹窗
- [ ] **字典管理** — 字典类型列表、字典数据子页面
- [ ] **个人中心** — 用户信息修改、头像上传、密码修改
### Step 6.3: 迁移账本系统模块6 页面)
- [ ] **交易账户** — 账户列表、CRUD
- [ ] **账本管理** — 账本列表、CRUD
- [ ] **操作记录** — 操作日志列表
- [ ] **统计分析** — 统计图表 + 列表
- [ ] **统计汇总** — 汇总数据展示
- [ ] **统计结余** — 结余数据展示
### Step 6.4: 迁移股票系统模块8+ 页面)
- [ ] **股票列表** — 股票信息列表、CRUD
- [ ] **股票基础信息** — 基础数据列表
- [ ] **指数信息** — 指数列表
- [ ] **财务数据** — 财务信息列表
- [ ] **趋势数据** — 趋势数据列表
- [ ] **板块趋势** — 板块趋势列表(含业务组件 TrendStocksDialog
- [ ] **新增记录** — 新增记录列表
- [ ] **涨跌停** — 涨跌停列表(含业务组件 NegativeDialog
- [ ] **股票账本** — 股票相关账本
### Step 6.5: 迁移监控模块7 页面)
- [ ] **缓存监控** — Redis 缓存信息
- [ ] **定时任务** — 任务列表、执行、日志
- [ ] **调度日志** — 任务执行日志
- [ ] **登录日志** — 登录记录列表
- [ ] **在线用户** — 在线用户列表、强退
- [ ] **操作日志** — 操作记录列表
- [ ] **服务器监控** — CPU/内存/磁盘信息
### Step 6.6: 迁移认证和错误页面
- [ ] **登录页** — 用户名/密码/验证码登录RSA 加密
- [ ] **注册页** — 用户注册
- [ ] **401 错误页** — 无权限页面
- [ ] **404 错误页** — 页面不存在
### Step 6.7: 优化 API 调用层
- [ ] 添加请求重试机制(可配置重试次数和间隔)
- [ ] 添加请求取消机制(页面切换时取消未完成的请求)
- [ ] 统一错误码处理逻辑
- [ ] 添加 API 请求 loading 状态管理
**验收标准:**
- [ ] 所有页面可正常访问(路由配置正确)
- [ ] CRUD 操作功能正常(增删改查)
- [ ] 分页功能正常
- [ ] 搜索/过滤功能正常
- [ ] 权限按钮正确显示/隐藏
- [ ] 字典标签正确渲染
- [ ] 文件上传功能正常
- [ ] 富文本编辑器正常工作
- [ ] 与后端 API 完全兼容(无需后端改动)
- [ ] TypeScript 编译零错误
- [ ] 无 ESLint 报错
---
## Task 7: 测试和优化
**目标**: 功能测试、性能优化、响应式适配、浏览器兼容性测试
**Files:**
- Modify: `ruoyi-ui-next/vite.config.ts`(构建优化配置)
- Modify: `ruoyi-ui-next/src/utils/request.ts`(性能优化)
- Create: `ruoyi-ui-next/.browserslistrc`
- Reference: 所有已创建的页面和组件文件
**Dependencies:** Task 1-6 全部完成
### Step 7.1: 功能测试
- [ ] 登录/注册流程测试
- [ ] 动态路由加载测试(不同角色看到不同菜单)
- [ ] 权限控制测试(无权限按钮隐藏)
- [ ] 所有系统管理页面 CRUD 测试
- [ ] 所有业务模块页面功能测试
- [ ] 监控模块页面功能测试
- [ ] 数据可视化页面测试(行情总览 + 趋势热力图)
- [ ] 标签页操作测试(切换、关闭、刷新、关闭其他)
- [ ] 主题切换测试(深色/浅色)
- [ ] 文件上传/下载测试
- [ ] 富文本编辑器测试
- [ ] 401 处理测试Token 过期 → 确认弹窗 → 退出登录)
### Step 7.2: 性能优化
**构建优化**:
- [ ] 配置 Vite 代码分割(`manualChunks`
- `element-plus` 独立 chunk
- `echarts` 独立 chunk
- `vendor` 第三方库 chunk
- [ ] 启用 gzip/brotli 压缩
- [ ] 图片资源优化(自动 webp 转换)
- [ ] 移除开发环境的 source map
- [ ] 配置预加载/预取策略
**运行时优化**:
- [ ] 路由懒加载验证(所有路由页面按需加载)
- [ ] ECharts 按需引入(仅使用需要的图表类型)
- [ ] 大表格虚拟滚动(如数据量超过 100 行)
- [ ] 图片懒加载
- [ ] keep-alive 缓存策略优化
- [ ] 移除未使用的依赖和代码
**加载速度目标**:
- [ ] 首屏加载 < 2 秒(3G 网络模拟)
- [ ] 构建产物 < 2 MBgzip 后)
- [ ] 构建时间 < 30
### Step 7.3: 响应式适配
- [ ] 桌面端1920px / 1440px / 1280px
- [ ] 平板端1024px / 768px
- [ ] 移动端375px— 侧边栏自动折叠
- [ ] 热力图矩阵在小屏幕下可横向滚动
- [ ] 表格在小屏幕下可横向滚动
- [ ] 弹窗在小屏幕下自适应宽度
### Step 7.4: 浏览器兼容性
- [ ] Chrome 90+
- [ ] Firefox 90+
- [ ] Safari 14+
- [ ] Edge 90+
- [ ] 配置 `.browserslistrc`
- [ ] 验证无浏览器特有 API 使用(或添加 polyfill
### Step 7.5: 代码质量检查
- [ ] ESLint 全量检查通过(零警告)
- [ ] TypeScript 严格模式编译通过(零错误)
- [ ] Prettier 格式化全部代码
- [ ]`any` 类型滥用(最多 5 处 `any`
- [ ] 无 Vue 2 残留代码(`this.` 引用、Mixin、Options API
- [ ] 组件命名规范检查
- [ ] 导入路径规范检查(使用 `@/` 别名)
**验收标准:**
- [ ] 所有页面功能测试通过
- [ ] 首屏加载 < 2
- [ ] 构建产物 < 2 MBgzip 后)
- [ ] 响应式适配桌面/平板/移动端
- [ ] 主流浏览器兼容
- [ ] ESLint + TypeScript 零错误
- [ ] 无 Vue 2 残留代码
- [ ] 项目可独立运行(`npm run dev` + `npm run build`
---
## 任务依赖关系图
```
Task 1 (项目初始化)
Task 2 (核心架构搭建)
Task 3 (深色主题和 UI 框架) ──┐
│ │
▼ ▼
Task 4 (核心组件迁移) Task 5 (数据可视化实现)
│ │
└──────────┬───────────────┘
Task 6 (业务模块迁移)
Task 7 (测试和优化)
```
## 里程碑
| 里程碑 | 包含任务 | 预期产出 |
|--------|---------|---------|
| **M1: 项目骨架** | Task 1 | 可运行的 Vite + Vue3 + TS 空项目 |
| **M2: 架构就绪** | Task 2 | 路由、状态、权限、API 层完成 |
| **M3: 主题完成** | Task 3 | 深色主题 + Element Plus 配置完成 |
| **M4: 组件迁移** | Task 4 | 所有布局组件和通用组件迁移完成 |
| **M5: 可视化完成** | Task 5 | 行情总览和趋势热力图页面完成 |
| **M6: 全量迁移** | Task 6 | 所有业务页面迁移完成 |
| **M7: 发布就绪** | Task 7 | 测试通过、性能达标、可部署 |
## 风险提示
| 风险 | 影响 | 应对策略 |
|------|------|---------|
| ECharts 5 API 变化 | 图表组件需适配 | 对比 4.x/5.x 文档,逐项验证 |
| Element Plus 组件 API 差异 | 部分组件属性变更 | 查阅 Element Plus 文档,逐个适配 |
| Quill 富文本编辑器兼容性 | 可能需替换方案 | 准备 wangEditor 作为备选 |
| 后端 API 未适配 Vue3 | 前端需额外处理 | 保持 API 调用层兼容,无需后端改动 |
| 大项目 TypeScript 类型定义工作量 | 开发周期延长 | 优先核心类型,逐步补充 |
| 旧组件逻辑复杂难以重构 | 重构风险高 | 先复制功能,再逐步优化 |
## 自检查
### 1. 规范覆盖
- [x] Task 1: 项目初始化 ✓
- [x] Task 2: 核心架构搭建 ✓
- [x] Task 3: 深色主题和 UI 框架 ✓
- [x] Task 4: 核心组件迁移 ✓
- [x] Task 5: 数据可视化实现 ✓
- [x] Task 6: 业务模块迁移 ✓
- [x] Task 7: 测试和优化 ✓
### 2. Placeholder 扫描
- [x] 无 "TBD"、"TODO"
- [x] 无 "implement later"
- [x] 所有步骤包含具体文件路径和实施内容
- [x] 无 "Similar to Task N"
### 3. 类型一致性
- [x] 所有路径使用 `ruoyi-ui-next/` 前缀
- [x] 文件名命名一致kebab-case / PascalCase
- [x] API 路径与现有后端一致
- [x] CSS 变量命名与 demo 一致
### 4. 最小单元验证
- [x] 每个任务可独立执行(按依赖顺序)
- [x] 每个任务有明确输出和验收标准
- [x] 每个任务可独立验证
- [x] 依赖关系清晰
---
## 执行选择
计划完成!共 7 个任务,约 150+ 步骤,产出完整的 Vue3 前端项目。
**执行选项**
1. **Subagent-Driven推荐** — 每个任务分发到独立子 agent 执行,任务间审查,快速迭代
2. **Inline Execution** — 在当前会话中顺序执行所有任务
3. **按里程碑分批执行** — 按 M1-M7 分批,每个里程碑完成后审查再继续
您希望采用哪种执行方式?