This commit is contained in:
张成
2025-10-09 16:09:53 +08:00
parent d941bec7d8
commit d5fb0075b2
51 changed files with 82 additions and 9913 deletions

View File

@@ -1,76 +0,0 @@
@echo off
chcp 65001 >nul
setlocal enabledelayedexpansion
echo ================================
echo Admin Framework 构建工具
echo ================================
echo.
REM 检查 Node.js 是否安装
where node >nul 2>nul
if %errorlevel% neq 0 (
echo ❌ 错误: 未检测到 Node.js请先安装 Node.js
pause
exit /b 1
)
for /f "tokens=*" %%i in ('node -v') do set NODE_VERSION=%%i
for /f "tokens=*" %%i in ('npm -v') do set NPM_VERSION=%%i
echo ✅ Node.js 版本: %NODE_VERSION%
echo ✅ NPM 版本: %NPM_VERSION%
echo.
REM 检查是否已安装依赖
if not exist "node_modules" (
echo 📦 正在安装依赖...
call npm install
if !errorlevel! neq 0 (
echo ❌ 依赖安装失败
pause
exit /b 1
)
echo ✅ 依赖安装成功
echo.
) else (
echo ✅ 依赖已安装
echo.
)
REM 执行打包
echo 🔨 正在打包框架...
call npm run build
if %errorlevel% equ 0 (
echo.
echo ================================
echo ✅ 打包成功!
echo ================================
echo.
echo 📦 输出文件: dist\admin-framework.js
REM 显示文件大小
if exist "dist\admin-framework.js" (
for %%A in (dist\admin-framework.js) do (
set SIZE=%%~zA
set /a SIZE_KB=!SIZE! / 1024
echo 📊 文件大小: !SIZE_KB! KB
)
)
echo.
echo 📚 下一步:
echo 1. 将 dist\admin-framework.js 复制到你的项目
echo 2. 查看 QUICK_START.md 了解如何使用
echo 3. 查看 USAGE_EXAMPLE.md 了解详细示例
echo.
) else (
echo.
echo ❌ 打包失败,请检查错误信息
pause
exit /b 1
)
pause

View File

@@ -1,65 +0,0 @@
#!/bin/bash
# Admin Framework 构建脚本
echo "================================"
echo " Admin Framework 构建工具"
echo "================================"
echo ""
# 检查 Node.js 是否安装
if ! command -v node &> /dev/null
then
echo "❌ 错误: 未检测到 Node.js请先安装 Node.js"
exit 1
fi
echo "✅ Node.js 版本: $(node -v)"
echo "✅ NPM 版本: $(npm -v)"
echo ""
# 检查是否已安装依赖
if [ ! -d "node_modules" ]; then
echo "📦 正在安装依赖..."
npm install
if [ $? -ne 0 ]; then
echo "❌ 依赖安装失败"
exit 1
fi
echo "✅ 依赖安装成功"
echo ""
else
echo "✅ 依赖已安装"
echo ""
fi
# 执行打包
echo "🔨 正在打包框架..."
npm run build
if [ $? -eq 0 ]; then
echo ""
echo "================================"
echo " ✅ 打包成功!"
echo "================================"
echo ""
echo "📦 输出文件: dist/admin-framework.js"
# 显示文件大小
if [ -f "dist/admin-framework.js" ]; then
SIZE=$(du -h dist/admin-framework.js | cut -f1)
echo "📊 文件大小: $SIZE"
fi
echo ""
echo "📚 下一步:"
echo " 1. 将 dist/admin-framework.js 复制到你的项目"
echo " 2. 查看 QUICK_START.md 了解如何使用"
echo " 3. 查看 USAGE_EXAMPLE.md 了解详细示例"
echo ""
else
echo ""
echo "❌ 打包失败,请检查错误信息"
exit 1
fi

View File

@@ -1,28 +0,0 @@
# 依赖
node_modules/
package-lock.json
yarn.lock
# 构建产物
dist/
*.log
# 框架文件(从根目录复制过来的)
src/libs/admin-framework.js
# 编辑器
.vscode/
.idea/
*.swp
*.swo
*~
# 系统文件
.DS_Store
Thumbs.db
# 环境变量
.env
.env.local
.env.*.local

View File

@@ -1,131 +0,0 @@
# Demo Project 更新日志
## [最新更新] - 2025-10-08
### ✅ 添加 Source Map 支持
**新增功能**
- ✅ 完整的 Source Map 支持
- ✅ 开发模式使用 `eval-source-map`
- ✅ 生产模式使用 `source-map`
- ✅ CSS/Less 也启用了 source map
- ✅ 创建了详细的调试指南
**好处**
- 🐛 可以在浏览器中直接调试源码
- 🔍 支持断点调试
- 📍 精确定位到源码行和列
- 🎯 可以调试框架源码和业务代码
**文档**
- 新增 [调试指南.md](./调试指南.md)
- 更新 [README.md](./README.md) 添加调试说明
---
## [2025-10-08] - 修改为使用框架源码
**重要变更**
- ✅ 现在直接使用框架源码而不是打包文件
- ✅ 更方便调试和开发
- ✅ 更新了 webpack 和 babel 配置
### 📦 需要重新安装依赖
由于添加了新的依赖,请重新安装:
```bash
cd demo-project
# 删除旧的依赖(可选)
rm -rf node_modules
rm package-lock.json
# 重新安装
npm install
```
### 🔄 主要更新内容
#### 1. main.js
```javascript
// 之前:使用打包文件
import AdminFramework from './libs/admin-framework.js'
// 现在:使用源码
import AdminFramework from '../../src/index.js'
```
#### 2. webpack.config.js
添加了框架源码的路径别名:
```javascript
alias: {
'@': path.resolve(__dirname, 'src'),
'@component': path.resolve(__dirname, '../src/components'),
'@utils': path.resolve(__dirname, '../src/utils'),
'@api': path.resolve(__dirname, '../src/api'),
'@config': path.resolve(__dirname, '../src/config'),
'@assets': path.resolve(__dirname, '../src/assets')
}
```
#### 3. babel.config.js
添加了 JSX 支持:
```javascript
presets: [
'@babel/preset-env',
'@vue/babel-preset-jsx' // ← 新增
]
```
#### 4. package.json
新增依赖:
- `@vue/babel-preset-jsx` - JSX 支持
- `brace` - 代码编辑器
- `vue2-ace-editor` - Ace 编辑器
### 🚀 启动项目
```bash
# 安装依赖
npm install
# 启动开发服务器
npm run dev
```
### ✅ 优势
使用框架源码的好处:
1. **实时调试**
- 可以直接修改框架源码查看效果
- 无需重新打包框架
2. **开发便利**
- 可以在框架源码中添加 console.log
- 方便追踪问题
3. **热更新**
- 修改框架代码后自动刷新
- 开发体验更好
### ⚠️ 注意事项
1. **API 地址已更新**
-`http://localhost:3000/api/` 改为 `http://localhost:9098/api/`
-`src/config/index.js` 中修改
2. **首次启动**
- 需要运行 `npm install` 安装新依赖
- Windows 用户可以双击 `start.bat` 自动安装
3. **如果遇到错误**
- 删除 `node_modules``package-lock.json`
- 重新运行 `npm install`
---
**更新时间**: 2025-10-08
**作者**: light

View File

@@ -1,164 +0,0 @@
# Demo Project 安装指南
## 📦 安装步骤
### 步骤 1复制框架文件
框架文件已经在创建 demo 时自动复制到 `src/libs/admin-framework.js`
如果需要更新框架,执行:
```bash
# 在 admin-framework 目录重新构建
cd ../
npm run build
# 复制最新的框架文件
cp dist/admin-framework.js demo-project/src/libs/
```
### 步骤 2安装依赖
```bash
cd demo-project
npm install
```
安装过程中会下载以下依赖:
- vue, vue-router, vuex
- view-design (UI 组件库)
- axios (HTTP 客户端)
- webpack 相关工具
### 步骤 3启动项目
#### 开发模式
```bash
npm run dev
```
启动后自动打开浏览器访问 `http://localhost:8080`
#### 生产构建
```bash
npm run build
```
构建完成后,产物在 `dist` 目录。
## 🎯 功能演示
### 1. 登录页面
访问:`http://localhost:8080/login`
默认登录信息(示例):
- 用户名admin
- 密码123456
### 2. 主页
登录后自动跳转到主页:`http://localhost:8080/home`
显示系统欢迎信息和标题。
### 3. 系统管理页面
框架内置的系统页面:
- `/system/user` - 用户管理
- `/system/role` - 角色管理
- `/system_high/menu` - 菜单管理
### 4. 业务示例页面
访问:`http://localhost:8080/business/product`
查看产品列表示例(包含增删改查操作演示)。
## 🔧 开发提示
### 修改配置
编辑 `src/config/index.js`
```javascript
export default {
title: '你的系统名称', // 修改系统标题
apiUrl: 'http://your-api.com/api/', // 修改 API 地址
uploadUrl: 'http://your-api.com/api/upload'
}
```
### 添加新页面
1.`src/views/business/` 创建新的 `.vue` 文件
2.`src/main.js` 中添加路由:
```javascript
import NewPage from './views/business/new_page.vue'
const businessRoutes = [
{
path: '/business/newpage',
name: 'new_page',
component: NewPage
}
]
```
### 调用 API
```javascript
// GET 请求
const res = await this.$http.get('user/list', { page: 1 })
// POST 请求
const res = await this.$http.post('user/add', { name: '张三' })
```
### 使用 Store
```javascript
// 获取用户信息
const userName = this.$store.getters['user/userName']
// 获取系统配置
const sysTitle = this.$store.getters['app/sysFormModel']
```
## ⚠️ 常见问题
### Q1: 启动后页面空白?
检查浏览器控制台错误,确保:
1. 框架文件已正确复制到 `src/libs/`
2. 依赖已完全安装 `npm install`
### Q2: 接口请求失败?
修改 `src/config/index.js` 中的 `apiUrl` 为正确的后端地址。
### Q3: 样式显示异常?
确保已引入 ViewUI 样式:
```javascript
import 'view-design/dist/styles/iview.css'
```
## 📚 更多帮助
- 查看完整框架文档:`../完整使用文档.md`
- 框架 API 文档:`../完整使用文档.md#api-文档`
## 🎉 开始开发
所有准备工作已完成,现在可以开始开发了!
```bash
npm run dev
```
祝开发愉快!🚀

View File

@@ -1,160 +0,0 @@
# Demo Project 项目结构说明
## 📁 完整目录树
```
demo-project/
├── 📄 package.json # 项目依赖配置
├── 📄 webpack.config.js # Webpack 构建配置
├── 📄 babel.config.js # Babel 编译配置
├── 📄 .gitignore # Git 忽略文件
├── 📄 README.md # 项目说明文档
├── 📄 INSTALL.md # 安装指南
├── 📄 PROJECT_STRUCTURE.md # 本文件 - 项目结构说明
├── 🚀 start.bat # Windows 快速启动脚本
├── 🚀 start.sh # Linux/Mac 快速启动脚本
├── 📂 public/ # 静态资源
│ └── index.html # HTML 模板
└── 📂 src/ # 源代码目录
├── 📄 main.js # 入口文件 ⭐
├── 📄 App.vue # 根组件
├── 📂 config/ # 配置文件
│ └── index.js # 项目配置API 地址、系统标题等)
├── 📂 libs/ # 第三方库
│ └── admin-framework.js # Admin Framework 框架文件
└── 📂 views/ # 页面组件
└── business/ # 业务页面
└── product_list.vue # 产品列表示例页面
```
## 📝 核心文件说明
### 1. 入口文件 `src/main.js`
```javascript
// 项目启动入口
// 1. 引入框架
// 2. 配置 Vue 实例
// 3. 挂载应用
```
**主要功能**
- ✅ 引入并初始化 AdminFramework
- ✅ 配置 Router 和 Store
- ✅ 添加自定义业务路由
- ✅ 设置响应式适配
### 2. 配置文件 `src/config/index.js`
```javascript
export default {
title: 'Demo 管理系统',
apiUrl: 'http://localhost:3000/api/',
uploadUrl: 'http://localhost:3000/api/upload',
tokenKey: 'demo_token'
}
```
**说明**
- 系统标题、API 地址等配置
- 可根据环境切换配置
### 3. 框架文件 `src/libs/admin-framework.js`
-`admin-framework/dist/` 复制的打包文件
- 包含所有框架功能(页面、组件、工具等)
- 大小:约 1.64 MB
### 4. 业务页面 `src/views/business/product_list.vue`
- 完整的 CRUD 示例
- 展示如何使用框架的组件和工具
- 包含 Table、Modal、Message 等组件使用
## 🔧 配置文件说明
### webpack.config.js
- 入口:`src/main.js`
- 输出:`dist/bundle.[hash].js`
- 开发服务器:`localhost:8080`
- 支持 Vue、Less、图片等文件处理
### package.json
**主要依赖**
- `vue` - Vue 框架
- `vue-router` - 路由管理
- `vuex` - 状态管理
- `view-design` - UI 组件库
- `axios` - HTTP 客户端
**开发依赖**
- `webpack` - 打包工具
- `babel` - JS 编译
- `vue-loader` - Vue 文件加载器
## 📂 扩展目录说明
随着项目发展,可以添加以下目录:
```
src/
├── api/ # API 接口封装
│ └── business/
│ └── product.js
├── assets/ # 业务资源文件
│ ├── images/ # 图片
│ └── styles/ # 样式
├── components/ # 业务组件
│ └── CustomTable.vue
├── router/ # 路由配置
│ └── index.js
└── store/ # 业务状态管理
└── modules/
└── product.js
```
## 🚀 启动流程
1. **执行** `start.bat``npm run dev`
2. **Webpack** 读取 `webpack.config.js`
3. **入口** 加载 `src/main.js`
4. **初始化** AdminFramework
5. **创建** Vue 实例
6. **挂载**`#app`
7. **启动** 开发服务器
8. **打开** 浏览器 `http://localhost:8080`
## 📊 文件大小参考
| 文件 | 大小 | 说明 |
|------|------|------|
| admin-framework.js | ~1.64 MB | 框架打包文件 |
| main.js | ~2 KB | 入口文件 |
| App.vue | ~0.5 KB | 根组件 |
| product_list.vue | ~4 KB | 业务示例 |
| bundle.js开发 | ~3 MB | 包含所有依赖 |
| bundle.js生产 | ~500 KB | 压缩后 |
## 🎯 下一步
1. **修改配置**:编辑 `src/config/index.js`
2. **添加页面**:在 `src/views/business/` 创建新页面
3. **注册路由**:在 `src/main.js` 添加路由配置
4. **开始开发**:基于框架快速开发业务功能
---
**查看更多**
- [README.md](./README.md) - 项目概述
- [INSTALL.md](./INSTALL.md) - 安装指南
- [../完整使用文档.md](../完整使用文档.md) - 框架完整文档

View File

@@ -1,292 +0,0 @@
# Demo Project - Admin Framework 使用示例
这是一个使用 **Admin Framework** 框架的完整示例项目。
## 📁 项目结构
```
demo-project/
├── public/
│ └── index.html # HTML 模板
├── src/
│ ├── config/
│ │ └── index.js # 配置文件
│ ├── libs/
│ │ └── admin-framework.js # 框架文件(从 dist 复制)
│ ├── views/
│ │ └── business/
│ │ └── product_list.vue # 示例业务页面
│ ├── App.vue # 根组件
│ └── main.js # 入口文件
├── babel.config.js
├── package.json
├── webpack.config.js
└── README.md
```
## ⚠️ 重要说明
**本项目已更新为直接使用框架源码**(不再使用打包文件),更方便调试!
**✅ 已启用完整的 Source Map 支持**,可以在浏览器中直接调试源码!
**首次运行或更新后,请先安装依赖**
```bash
npm install
```
如果遇到问题,删除 `node_modules``package-lock.json` 后重新安装。
---
## 🚀 快速开始
### 方式一:一键启动(推荐)
#### Windows 用户
双击运行 `start.bat`,会自动:
1. 检查并安装依赖
2. 启动开发服务器
3. 自动打开浏览器
#### Linux/Mac 用户
```bash
chmod +x start.sh
./start.sh
```
### 方式二:手动启动
```bash
# 1. 安装依赖(首次运行必须)
npm install
# 2. 启动开发服务器
npm run dev
```
### ~~ 方式三:复制框架文件(已废弃)~~
### 1. 使用源码(当前方式)
将框架打包文件复制到项目中:
```bash
# 在 admin-framework 目录执行构建
cd admin-framework
npm run build
# 创建 libs 目录
mkdir demo-project/src/libs
# 复制打包文件
cp dist/admin-framework.js demo-project/src/libs/
```
### 2. 安装依赖
```bash
cd demo-project
npm install
```
### 3. 启动开发服务器
```bash
npm run dev
```
浏览器会自动打开 `http://localhost:8080`
### 4. 构建生产版本
```bash
npm run build
```
生成的文件在 `dist` 目录中。
## 📝 核心文件说明
### main.js - 入口文件
```javascript
import AdminFramework from './libs/admin-framework.js'
import config from './config'
// 使用框架
Vue.use(AdminFramework, {
config,
ViewUI,
VueRouter,
Vuex,
createPersistedState
})
// 创建 Vue 实例
new Vue({
router: AdminFramework.router,
store: AdminFramework.store,
render: h => h(App)
}).$mount('#app')
```
### config/index.js - 配置文件
```javascript
export default {
title: 'Demo 管理系统',
apiUrl: 'http://localhost:3000/api/',
uploadUrl: 'http://localhost:3000/api/upload',
tokenKey: 'demo_token'
}
```
### 业务页面示例
`src/views/business/product_list.vue` 展示了如何:
- 使用 ViewUI 组件Table、Button、Modal 等)
- 调用 API 接口this.$http
- 使用框架提供的工具方法
## 🎯 框架提供的功能
### 1. 内置页面
-**主页**HomePage- 欢迎页面
-**系统页面**SysUser、SysRole、SysMenu 等)
-**登录页面**LoginPage
-**错误页面**401、404、500
### 2. 布局组件
-**Main** - 主布局
-**ParentView** - 父级视图
### 3. 工具方法
```javascript
// HTTP 请求
this.$http.get(url, params)
this.$http.post(url, data)
// 工具函数
this.$tools.formatDate(date, format)
this.$tools.setToken(token)
this.$tools.getToken()
// UI 工具
this.$uiTool.delConfirm(callback)
this.$uiTool.setRem()
```
### 4. Store 状态管理
```javascript
// 用户模块
this.$store.dispatch('user/handleLogin', data)
this.$store.dispatch('user/handleLogOut')
this.$store.getters['user/userName']
// 应用模块
this.$store.dispatch('app/getSysTitle', { defaultTitle: '系统' })
this.$store.getters['app/sysFormModel']
```
## 🐛 调试功能
### Source Map 已启用
项目已配置完整的 Source Map 支持:
**开发模式**:使用 `eval-source-map`
- 高质量的源码映射
- 可以在浏览器中看到原始源代码
- 支持断点调试
- 包含行和列信息
**生产模式**:使用 `source-map`
- 生成独立的 .map 文件
- 完整的源码信息
### 如何调试
1. **启动开发服务器**
```bash
npm run dev
```
2. **打开浏览器开发者工具**F12
3. **在 Sources 标签页查看源码**
```
webpack://
├── demo-project/src/ ← Demo 项目源码
└── src/ ← 框架源码(可直接调试)
```
4. **设置断点调试**
- 点击行号设置断点
- 或在代码中添加 `debugger` 语句
### 详细调试指南
查看完整调试教程:**[调试指南.md](./调试指南.md)** 📚
包含:
- Source Map 配置说明
- 浏览器调试技巧
- 框架源码调试方法
- Vue DevTools 使用
- Console 调试技巧
## 🔧 自定义开发
### 添加业务路由
在 `main.js` 中添加自定义路由:
```javascript
const businessRoutes = [
{
path: '/business/product',
name: 'product_list',
component: ProductList
}
]
// 添加到主路由
const mainRoute = AdminFramework.router.options.routes.find(r => r.path === '/')
mainRoute.children.push(...businessRoutes)
```
### 使用系统页面
```javascript
import { SysUser, SysRole } from './libs/admin-framework.js'
// 或者直接使用
const SysUser = AdminFramework.SysUser
```
## 📚 更多文档
查看完整文档:`admin-framework/完整使用文档.md`
## 💡 提示
1. **框架文件**:确保将最新的 `admin-framework.js` 复制到 `src/libs/` 目录
2. **ViewUI 样式**:已在 main.js 中引入 `view-design/dist/styles/iview.css`
3. **API 配置**:修改 `config/index.js` 中的 `apiUrl` 为你的后端地址
4. **登录功能**:访问 `/login` 可以看到登录页面
## 🎉 开始开发
现在你可以:
1. 访问 `http://localhost:8080/login` 查看登录页面
2. 访问 `http://localhost:8080/home` 查看主页
3. 访问 `http://localhost:8080/business/product` 查看业务页面示例
4. 开始开发你的业务页面!
祝开发愉快! 🚀

View File

@@ -1,64 +0,0 @@
=====================================================
⭐ 首次运行必读 ⭐
=====================================================
Demo 项目已更新为使用框架源码(更方便调试)!
【第一步:安装依赖】
Windows 用户(推荐):
双击运行 install.bat
或者手动运行:
npm install
【第二步:启动项目】
Windows 用户:
双击运行 start.bat
或者手动运行:
npm run dev
【验证安装成功】
运行以下命令检查依赖:
npm list --depth=0
应该看到(无 UNMET DEPENDENCY 错误):
✅ @vue/babel-preset-jsx
✅ brace
✅ vue2-ace-editor
✅ 其他依赖...
【访问地址】
http://localhost:8080
可用页面:
/login - 登录页面
/home - 主页
/business/product - 产品列表示例
【遇到错误?】
1. 依赖缺失:
npm install @vue/babel-preset-jsx brace vue2-ace-editor
2. 端口占用:
修改 webpack.config.js 中的 port: 8081
3. 删除重装:
rm -rf node_modules package-lock.json
npm install
【详细文档】
- 启动前必读.md - 完整启动指南
- CHANGELOG.md - 更新日志
- README.md - 项目说明
=====================================================
准备好了?运行 install.bat 开始吧!
=====================================================

View File

@@ -1,270 +0,0 @@
# Demo 项目 - 使用打包框架
## 📦 项目说明
这是一个使用 Admin Framework 打包版本的演示项目。
## ✅ 已完成的配置
### 1. 框架引用方式
**文件**`src/main.js`
```javascript
// 使用打包好的框架
import AdminFramework from './libs/admin-framework.js'
```
### 2. 文件结构
```
demo-project/
├── src/
│ ├── libs/
│ │ └── admin-framework.js ← 打包好的框架(从 ../../dist/ 复制)
│ ├── main.js ← 引用框架
│ ├── App.vue
│ ├── config/
│ ├── views/
│ └── ...
├── public/
├── package.json
└── webpack.config.js
```
### 3. .gitignore 配置
```
# 框架文件(从根目录复制过来的)
src/libs/admin-framework.js
```
## 🚀 快速开始
### 1. 确保框架文件存在
检查 `src/libs/admin-framework.js` 是否存在。
如果不存在,在**项目根目录**(不是 demo-project执行
```powershell
# 打包框架
npm run build
# 复制到 demo 项目
Copy-Item "dist\admin-framework.js" "demo-project\src\libs\admin-framework.js" -Force
```
### 2. 安装依赖(首次运行)
```bash
cd demo-project
npm install
```
### 3. 启动开发服务器
```bash
npm run dev
```
### 4. 访问应用
打开浏览器访问http://localhost:8080
**测试账号**
- 用户名admin
- 密码admin123
## 🔄 更新框架
当框架源码(`../../src/`)有更新时:
### 快速更新(推荐)
在**项目根目录**执行:
```powershell
# 一键打包并复制
npm run build; Copy-Item "dist\admin-framework.js" "demo-project\src\libs\admin-framework.js" -Force; Write-Host "✅ 框架已更新!" -ForegroundColor Green
```
### 分步操作
```bash
# 1. 在项目根目录打包框架
npm run build
# 2. 复制到 demo 项目PowerShell
Copy-Item "dist\admin-framework.js" "demo-project\src\libs\admin-framework.js" -Force
# 3. 重启 demo 项目(如果正在运行)
cd demo-project
npm run dev
```
## 📊 优势对比
### 使用打包框架(当前方式)
**优点**
- ✅ 性能更好(打包优化)
- ✅ 更接近生产环境
- ✅ 依赖隔离
- ✅ 边界清晰
**缺点**
- ❌ 修改框架后需要重新打包
- ❌ 调试稍微不便
### 使用源码引用(开发调试)
**优点**
- ✅ 实时更新
- ✅ 调试方便
**缺点**
- ❌ 性能较差
- ❌ 需要安装框架的所有依赖
## 🔧 开发建议
### 调试框架时
临时修改 `src/main.js`
```javascript
// 临时改为源码引用
import AdminFramework from '../../src/index.js'
```
**注意**:调试完成后记得改回来!
### 测试框架时
使用打包文件(当前配置):
```javascript
// 使用打包文件
import AdminFramework from './libs/admin-framework.js'
```
## 📝 组件映射配置
`src/main.js` 中配置业务组件映射:
```javascript
Vue.use(AdminFramework, {
config,
ViewUI,
VueRouter,
Vuex,
createPersistedState,
// 业务组件映射
componentMap: {
'business/product_list': ProductList,
// 添加更多业务组件...
}
})
```
## 🔍 故障排查
### 问题 1找不到 admin-framework.js
**错误**
```
Module not found: Error: Can't resolve './libs/admin-framework.js'
```
**解决**
```powershell
# 在项目根目录
Copy-Item "dist\admin-framework.js" "demo-project\src\libs\admin-framework.js" -Force
```
### 问题 2修改框架源码后没有变化
**原因**:使用的是打包文件,不会自动更新
**解决**
```powershell
# 重新打包并复制
npm run build
Copy-Item "dist\admin-framework.js" "demo-project\src\libs\admin-framework.js" -Force
```
### 问题 3控制台报错
**检查步骤**
1. 确保框架已正确打包
2. 确保文件已复制到正确位置
3. 查看浏览器控制台的详细错误
4. 检查 `src/main.js` 的引用路径
### 问题 4端口被占用
**错误**
```
Error: listen EADDRINUSE: address already in use :::8080
```
**解决**
1. 关闭占用 8080 端口的程序
2. 或修改 `webpack.config.js` 中的端口
## 📚 相关文档
- `使用打包框架说明.md` - 详细使用说明
- `框架更新完成.md` - 更新记录
- `启动说明.md` - 启动步骤
- `../../完整使用文档.md` - 框架完整文档
## 🎯 项目结构
```
demo-project/
├── src/
│ ├── libs/
│ │ └── admin-framework.js # 打包好的框架
│ ├── main.js # 入口文件
│ ├── App.vue # 根组件
│ ├── config/
│ │ ├── index.js # 配置文件
│ │ └── menuConfig.js # 菜单配置
│ ├── views/
│ │ ├── business/ # 业务页面
│ │ └── home/ # 首页
│ └── ...
├── public/
│ └── index.html
├── package.json
├── webpack.config.js
├── babel.config.js
└── README.md
```
## 🌟 特性
- ✅ 基于 Vue 2.x
- ✅ 使用 ViewUI 组件库
- ✅ 动态路由和权限管理
- ✅ Vuex 状态管理
- ✅ 响应式布局
- ✅ 热更新开发
## 📞 支持
如有问题,请查看:
1. 浏览器控制台错误信息
2. 终端编译错误信息
3. 相关文档
---
**框架版本**1.0.0
**Node.js 版本要求**>= 14.0.0
**当前状态**:✅ 就绪

View File

@@ -1,222 +0,0 @@
# Source Map 配置说明
## ✅ 已完成配置
Demo 项目现在已经配置了完整的 Source Map 支持!
### 📝 配置内容
#### 1. Webpack 配置(`webpack.config.js`
```javascript
module.exports = (env, argv) => {
const isDevelopment = argv.mode === 'development'
return {
// Source Map 配置
devtool: isDevelopment ? 'eval-source-map' : 'source-map',
// CSS/Less Source Map
module: {
rules: [
{
test: /\.css$/,
use: [
'vue-style-loader',
{
loader: 'css-loader',
options: { sourceMap: isDevelopment }
}
]
},
{
test: /\.less$/,
use: [
'vue-style-loader',
{
loader: 'css-loader',
options: { sourceMap: isDevelopment }
},
{
loader: 'less-loader',
options: { sourceMap: isDevelopment }
}
]
}
]
}
}
}
```
#### 2. DevServer 配置
```javascript
devServer: {
port: 8080,
hot: true,
open: true,
historyApiFallback: true,
// 错误覆盖层
client: {
overlay: {
errors: true, // 显示错误
warnings: false // 不显示警告
}
}
}
```
### 🎯 Source Map 类型
#### 开发模式:`eval-source-map`
**优点**
- ✅ 高质量的源码映射
- ✅ 包含行和列信息
- ✅ 重新构建速度快
- ✅ 适合开发调试
**缺点**
- ❌ 生成的文件较大
- ❌ 不适合生产环境
#### 生产模式:`source-map`
**优点**
- ✅ 最高质量的源码映射
- ✅ 生成独立的 .map 文件
- ✅ 不影响主文件加载
**缺点**
- ❌ 构建速度慢
- ❌ 文件体积大
### 🔍 调试效果
启动开发服务器后,在浏览器开发者工具中可以看到:
```
webpack://
├── demo-project/
│ └── src/
│ ├── main.js ← 可以看到原始源码
│ ├── App.vue
│ ├── config/
│ │ └── index.js
│ └── views/
│ └── business/
│ └── product_list.vue
└── src/ ← 框架源码
├── index.js
├── components/
│ ├── main/
│ └── ...
├── views/
│ ├── login/
│ ├── home/
│ └── ...
├── store/
│ ├── user.js
│ └── app.js
└── utils/
├── http.js
├── tools.js
└── uiTool.js
```
### 💡 使用方法
#### 1. 设置断点
在浏览器开发者工具的 Sources 面板:
1. 找到要调试的源文件
2. 点击行号设置断点
3. 刷新页面触发断点
#### 2. 使用 debugger
在代码中直接添加:
```javascript
export default {
mounted() {
debugger // ← 程序会在这里暂停
console.log('组件已挂载')
}
}
```
#### 3. Console 调试
```javascript
// 在 Console 中执行
$vm.$store.state // 查看 Vuex 状态
$vm.$route // 查看路由信息
$vm.$root // 查看根实例
```
### 📊 对比
| 功能 | 有 Source Map | 无 Source Map |
|------|--------------|---------------|
| 看到的代码 | 原始源码 | 编译后的代码 |
| 断点位置 | 精确到源码行列 | 只能在编译后代码设置 |
| 变量名 | 原始变量名 | 可能被压缩 |
| 调试体验 | ⭐⭐⭐⭐⭐ | ⭐⭐ |
### ⚠️ 注意事项
#### 1. 文件大小
开发模式的 bundle 会包含 source map 信息,体积较大:
- 开发环境:约 3-5 MB包含 source map
- 生产环境:约 500 KB压缩后.map 文件独立)
#### 2. 性能影响
- **开发环境**:首次构建较慢,热更新很快
- **生产环境**:构建时间增加,但运行时无影响
#### 3. 安全性
生产环境的 .map 文件:
- 不要部署到公开的服务器
- 或配置服务器禁止访问 .map 文件
- 或使用错误追踪服务(如 Sentry管理 source map
### 🚀 快速开始
1. **启动开发服务器**
```bash
npm run dev
```
2. **打开浏览器**
访问 `http://localhost:8080`
3. **打开开发者工具**
按 `F12`
4. **查看源码**
在 Sources 标签页中可以看到完整的源码结构
5. **设置断点调试**
点击行号或在代码中添加 `debugger`
### 📚 相关文档
- **[调试指南.md](./调试指南.md)** - 完整的调试教程
- **[README.md](./README.md)** - 项目说明
- **[CHANGELOG.md](./CHANGELOG.md)** - 更新日志
### 🔗 参考资源
- [Webpack DevTool 文档](https://webpack.js.org/configuration/devtool/)
- [Chrome DevTools](https://developer.chrome.com/docs/devtools/)
- [Vue DevTools](https://devtools.vuejs.org/)
---
**现在你可以愉快地调试代码了!** 🎉

View File

@@ -1,399 +0,0 @@
# Vuex 错误修复说明
## 🔍 问题描述
控制台出现多个 Vuex 相关错误:
1. `[vuex] unknown action type: getSysTitle`
2. `[vuex] unknown getter: isServerRun`
3. `[vuex] unknown getter: infoMsg`
4. `Unknown custom element: <asyncModal>`
## 📝 修复内容
### 1. 修复 `getSysTitle` action 错误
**问题位置**`src/components/main/main.vue`
**错误原因**
-`created` 钩子中调用了 `this.$store.dispatch('getSysTitle')`
- 缺少模块命名空间前缀 `app/`
- 且在 `demo-project/src/main.js` 中已经调用过,不需要重复调用
**修改前**
```javascript
created() {
this.init()
},
methods: {
async init() {
await this.$store.dispatch('getSysTitle') // ❌ 错误
},
}
```
**修改后**
```javascript
created() {
this.init()
},
methods: {
async init() {
// 获取系统标题(已在 main.js 中调用,这里不需要重复调用)
// await this.$store.dispatch('app/getSysTitle')
},
}
```
**说明**
- ✅ 移除了重复的 `getSysTitle` 调用
- ✅ 系统标题在 `demo-project/src/main.js``mounted` 钩子中统一获取
- ✅ 避免了重复请求
### 2. 修复 `isServerRun` getter 错误
**问题位置**`src/components/main/components/terminal/index.vue`
**错误原因**
- 使用了不存在的 `isServerRun` getter
- 这是 Terminal 功能相关的状态,但 store 中没有定义
**修改前**
```javascript
computed: {
...mapGetters({
isServerRun: 'isServerRun' // ❌ 不存在的 getter
}),
iconclass() {
let curClass = 'terminal-icon ml10 '
if (this.isServerRun) {
curClass += ' run'
}
return curClass
}
},
```
**修改后**
```javascript
computed: {
iconclass() {
let curClass = 'terminal-icon ml10'
// Terminal 功能暂时禁用
// if (this.isServerRun) {
// curClass += ' run'
// }
return curClass
}
},
```
**说明**
- ✅ 移除了对不存在的 `isServerRun` getter 的依赖
- ✅ Terminal 功能暂时禁用
- ✅ 如果需要启用,需要在 store 中添加相应的 state 和 getter
### 3. 修复 `infoMsg` getter 错误
**问题位置**`src/components/main/components/terminal/terminal.vue`
**错误原因**
- 使用了不存在的 `infoMsg` getter
- 调用了不存在的 `clearInfoMsg` mutation 和 `setInteverLog` action
**修改前**
```javascript
computed: {
...mapGetters({
infoMsg: 'infoMsg' // ❌ 不存在的 getter
})
},
methods: {
clearLog() {
this.$store.commit('clearInfoMsg') // ❌ 不存在的 mutation
},
reloadLog() {
this.$store.dispatch('setInteverLog') // ❌ 不存在的 action
},
}
```
**修改后**
```javascript
computed: {
infoMsg() {
// Terminal 功能暂时禁用
return '终端功能暂未启用'
}
},
methods: {
clearLog() {
// Terminal 功能暂时禁用
this.$Message.info('终端功能暂未启用')
},
reloadLog() {
// Terminal 功能暂时禁用
this.$Message.info('终端功能暂未启用')
},
}
```
**说明**
- ✅ 移除了对不存在的 Vuex 状态的依赖
- ✅ 提供了友好的提示信息
- ✅ 避免了运行时错误
### 4. 修复 `asyncModal` 组件未注册错误
**问题位置**`src/components/main/components/terminal/index.vue`
**错误原因**
- 模板中使用了 `<asyncModal>` 组件
- 但没有在 `components` 中注册
**修改前**
```javascript
import { mapGetters } from 'vuex'
import Terminal from './terminal.vue'
export default {
components: {
Terminal // ❌ 缺少 asyncModal
},
}
```
**修改后**
```javascript
import Terminal from './terminal.vue'
import asyncModal from '@/components/asyncModal'
export default {
components: {
Terminal,
asyncModal // ✅ 添加 asyncModal 组件
},
}
```
**说明**
- ✅ 导入了 `asyncModal` 组件
- ✅ 在 `components` 中注册
- ✅ 移除了不需要的 `mapGetters` 导入
## 📊 修复总结
### 修改的文件
1. **`src/components/main/main.vue`**
- 移除了重复的 `getSysTitle` 调用
2. **`src/components/main/components/terminal/index.vue`**
- 移除了 `isServerRun` getter 的使用
- 添加了 `asyncModal` 组件注册
3. **`src/components/main/components/terminal/terminal.vue`**
- 移除了 `infoMsg` getter 的使用
- 修改了 `clearLog``reloadLog` 方法
### 错误修复
-`[vuex] unknown action type: getSysTitle` - 已修复
-`[vuex] unknown getter: isServerRun` - 已修复
-`[vuex] unknown getter: infoMsg` - 已修复
-`Unknown custom element: <asyncModal>` - 已修复
## 💡 Terminal 功能说明
### 当前状态
Terminal 功能已**暂时禁用**,因为:
- 缺少相关的 Vuex store 配置
- 缺少后端接口支持
- 不影响系统核心功能
### 如何启用 Terminal 功能
如果需要启用 Terminal 功能,需要:
**1. 在 Vuex store 中添加 Terminal 模块**
创建 `src/store/terminal.js`
```javascript
export default {
namespaced: true,
state: {
isServerRun: false,
infoMsg: ''
},
getters: {
isServerRun: state => state.isServerRun,
infoMsg: state => state.infoMsg
},
mutations: {
setServerRun(state, value) {
state.isServerRun = value
},
setInfoMsg(state, msg) {
state.infoMsg += msg + '\n'
},
clearInfoMsg(state) {
state.infoMsg = ''
}
},
actions: {
async setInteverLog({ commit }) {
// 实现日志加载逻辑
}
}
}
```
**2. 在 `src/store/index.js` 中注册模块**
```javascript
import terminal from './terminal'
export default new Vuex.Store({
modules: {
user,
app,
terminal // 添加 terminal 模块
}
})
```
**3. 更新组件代码**
`src/components/main/components/terminal/index.vue`
```javascript
computed: {
...mapGetters('terminal', {
isServerRun: 'isServerRun'
}),
iconclass() {
let curClass = 'terminal-icon ml10 '
if (this.isServerRun) {
curClass += ' run'
}
return curClass
}
}
```
`src/components/main/components/terminal/terminal.vue`
```javascript
computed: {
...mapGetters('terminal', {
infoMsg: 'infoMsg'
})
},
methods: {
clearLog() {
this.$store.commit('terminal/clearInfoMsg')
},
reloadLog() {
this.$store.dispatch('terminal/setInteverLog')
}
}
```
## ⚠️ 注意事项
### 1. 系统标题获取时机
系统标题在 `demo-project/src/main.js``mounted` 钩子中获取:
```javascript
mounted() {
AdminFramework.uiTool.setRem()
// 只在已登录时获取系统标题
const token = this.$store.state.user.token
if (token) {
this.$store.dispatch('app/getSysTitle', {
defaultTitle: 'Demo 管理系统',
defaultLogo: ''
})
} else {
document.title = 'Demo 管理系统'
}
}
```
**不要在其他地方重复调用**,避免:
- 重复的 HTTP 请求
- 不必要的性能开销
- 可能的竞态条件
### 2. Vuex 模块命名空间
所有 Vuex 模块都使用了 `namespaced: true`
```javascript
// ✅ 正确的调用方式
this.$store.dispatch('app/getSysTitle')
this.$store.commit('user/setToken', token)
this.$store.getters['user/userName']
// ❌ 错误的调用方式
this.$store.dispatch('getSysTitle')
this.$store.commit('setToken', token)
this.$store.getters['userName']
```
**使用 mapGetters/mapActions 时**
```javascript
// ✅ 正确
...mapGetters('app', ['sysFormModel'])
...mapActions('user', ['handleLogin'])
// 或者
...mapGetters({
sysFormModel: 'app/sysFormModel'
})
```
### 3. 组件注册
使用第三方组件或自定义组件时,必须:
1. 导入组件
2.`components` 中注册
3. 才能在模板中使用
```javascript
// ✅ 正确
import asyncModal from '@/components/asyncModal'
export default {
components: {
asyncModal
}
}
// ❌ 错误(直接在模板中使用未注册的组件)
<template>
<asyncModal></asyncModal>
</template>
```
## ✅ 验证清单
### 功能验证
- ✅ 登录功能正常
- ✅ 系统标题正确显示
- ✅ 菜单正确显示
- ✅ 页面跳转正常
- ✅ 控制台没有 Vuex 错误
### 错误检查
- ✅ 没有 `[vuex] unknown action` 错误
- ✅ 没有 `[vuex] unknown getter` 错误
- ✅ 没有 `Unknown custom element` 错误
- ✅ 没有组件注册错误
---
**所有 Vuex 错误已修复!** 🎉
现在系统可以正常运行Terminal 功能暂时禁用但不影响核心功能。

View File

@@ -1,372 +0,0 @@
# API 直接导入重构说明
## 📋 重构内容
### 重构目标
将框架中的 API server 从**注入模式**改为**直接导入模式**,简化代码结构。
### 修改前(注入模式)
**问题**
- 需要在 `src/index.js` 中调用 `setUserServer``setParamSetupServer`
- Store 模块需要导出 setter 函数
- 代码结构复杂,不够直观
**代码示例**
```javascript
// src/store/user.js
let userServerInstance = null
export const setUserServer = (server) => {
userServerInstance = server
}
// 使用时
if (!userServerInstance) {
throw new Error('userServer not initialized')
}
let res = await userServerInstance.login(userFrom)
```
```javascript
// src/index.js
import { setUserServer } from './store/user'
import { setParamSetupServer } from './store/app'
import * as systemApi from './api/system'
import * as systemHighApi from './api/system_high'
// 自动设置 API
setUserServer(systemApi.userServer)
setParamSetupServer(systemHighApi.paramSetupServer)
```
### 修改后(直接导入模式)
**优点**
- ✅ 代码更简洁
- ✅ 不需要额外的 setter 函数
- ✅ 依赖关系更清晰
- ✅ 符合 ES6 模块化规范
**代码示例**
```javascript
// src/store/user.js
import userServer from '../api/system/userServer'
// 直接使用
let res = await userServer.login(userFrom)
```
```javascript
// src/index.js
// 不再需要 setUserServer 和 setParamSetupServer
import * as systemApi from './api/system'
import * as systemHighApi from './api/system_high'
```
## 📁 修改的文件
### 1. `src/store/user.js`
**修改前**
```javascript
import { setToken, getToken } from '../utils/tools'
import uiTool from '../utils/uiTool'
import { defaultMenus, filterMenusByIds } from '../config/menuConfig'
// 注意:这里的 userServer 需要在使用时注入
let userServerInstance = null
export const setUserServer = (server) => {
userServerInstance = server
}
// 使用时
if (!userServerInstance) {
throw new Error('userServer not initialized')
}
let res = await userServerInstance.login(userFrom)
```
**修改后**
```javascript
import { setToken, getToken } from '../utils/tools'
import uiTool from '../utils/uiTool'
import { defaultMenus, filterMenusByIds } from '../config/menuConfig'
import userServer from '../api/system/userServer'
// 直接使用
let res = await userServer.login(userFrom)
```
**变更点**
- ✅ 移除了 `userServerInstance` 变量
- ✅ 移除了 `setUserServer` 导出函数
- ✅ 直接导入 `userServer`
- ✅ 移除了 `if (!userServerInstance)` 检查
- ✅ 将所有 `userServerInstance` 替换为 `userServer`
### 2. `src/store/app.js`
**修改前**
```javascript
import { getBreadCrumbList, getHomeRoute } from '../utils/tools'
// 注意:这里的 paramSetupServer 需要在使用时注入
let paramSetupServerInstance = null
export const setParamSetupServer = (server) => {
paramSetupServerInstance = server
}
// 使用时
if (!paramSetupServerInstance) {
commit('setSysTitle', formModel)
return
}
let res1 = await paramSetupServerInstance.getOne('sys_title')
```
**修改后**
```javascript
import { getBreadCrumbList, getHomeRoute } from '../utils/tools'
import paramSetupServer from '../api/system_high/paramSetupServer'
// 直接使用
let res1 = await paramSetupServer.getOne('sys_title')
```
**变更点**
- ✅ 移除了 `paramSetupServerInstance` 变量
- ✅ 移除了 `setParamSetupServer` 导出函数
- ✅ 直接导入 `paramSetupServer`
- ✅ 移除了 `if (!paramSetupServerInstance)` 检查
- ✅ 将所有 `paramSetupServerInstance` 替换为 `paramSetupServer`
### 3. `src/index.js`
**修改前**
```javascript
// ==================== Store 模块 ====================
import storeModules, { userModule, appModule } from './store'
import { setUserServer } from './store/user'
import { setParamSetupServer } from './store/app'
// ==================== 系统 API ====================
import * as systemApi from './api/system'
import * as systemHighApi from './api/system_high'
// 自动设置 API
setUserServer(systemApi.userServer)
setParamSetupServer(systemHighApi.paramSetupServer)
// AdminFramework 类中的方法
class AdminFramework {
/**
* 设置用户服务实例
*/
setUserServer(userServer) {
setUserServer(userServer)
}
/**
* 设置参数设置服务实例
*/
setParamSetupServer(paramSetupServer) {
setParamSetupServer(paramSetupServer)
}
}
```
**修改后**
```javascript
// ==================== Store 模块 ====================
import storeModules, { userModule, appModule } from './store'
// ==================== 系统 API ====================
import * as systemApi from './api/system'
import * as systemHighApi from './api/system_high'
// AdminFramework 类中移除了 setUserServer 和 setParamSetupServer 方法
```
**变更点**
- ✅ 移除了 `setUserServer``setParamSetupServer` 的导入
- ✅ 移除了自动设置 API 的代码
- ✅ 移除了 `AdminFramework` 类中的 `setUserServer``setParamSetupServer` 方法
## 🎯 影响范围
### 不受影响的功能
- ✅ 登录功能
- ✅ 权限菜单
- ✅ 系统标题
- ✅ 所有业务功能
### 代码简化
**减少的代码行数**
- `src/store/user.js`: -7 行
- `src/store/app.js`: -7 行
- `src/index.js`: -12 行
- **总计**: -26 行
**移除的概念**
-`userServerInstance` 变量
-`paramSetupServerInstance` 变量
-`setUserServer` 函数
-`setParamSetupServer` 函数
- ❌ API 注入机制
## 📊 对比表
| 特性 | 注入模式 | 直接导入模式 |
|------|---------|------------|
| 代码行数 | 多 | 少 |
| 复杂度 | 高 | 低 |
| 依赖关系 | 隐式 | 显式 |
| 初始化检查 | 需要 | 不需要 |
| 灵活性 | 高(可运行时替换) | 中(编译时确定) |
| 可读性 | 中 | 高 |
| 维护性 | 中 | 高 |
## 💡 设计理念
### 为什么选择直接导入?
1. **简单性优先**
- 对于大多数项目API server 是固定的
- 不需要运行时动态替换
- 直接导入更符合直觉
2. **符合 ES6 规范**
- 使用标准的 `import` 语法
- 依赖关系在文件顶部清晰可见
- 便于静态分析和 tree-shaking
3. **减少样板代码**
- 不需要额外的 setter 函数
- 不需要初始化检查
- 代码更简洁
### 何时使用注入模式?
如果你的项目需要以下特性,可以考虑使用注入模式:
1. **运行时替换 API**
- 例如:测试环境使用 mock API
- 例如:多租户系统使用不同的 API
2. **插件化架构**
- 框架作为独立包发布
- 使用者可以自定义 API 实现
3. **依赖注入容器**
- 使用 IoC 容器管理依赖
- 需要复杂的依赖管理
对于本项目,直接导入模式更合适。
## 🧪 测试验证
### 测试步骤
1. **启动项目**
```bash
cd demo-project
npm run dev
```
2. **测试登录**
- 访问 `http://localhost:8080`
- 输入用户名密码
- 点击登录
3. **验证功能**
- ✅ 登录成功
- ✅ 菜单显示正常
- ✅ 系统标题显示正常
- ✅ 页面跳转正常
### 预期结果
所有功能正常工作,与重构前完全一致。
## 📝 迁移指南
如果你的项目使用了旧的注入模式,可以按以下步骤迁移:
### 步骤 1修改 Store 模块
**user.js**:
```javascript
// 删除
let userServerInstance = null
export const setUserServer = (server) => {
userServerInstance = server
}
// 添加
import userServer from '../api/system/userServer'
// 替换所有 userServerInstance 为 userServer
```
**app.js**:
```javascript
// 删除
let paramSetupServerInstance = null
export const setParamSetupServer = (server) => {
paramSetupServerInstance = server
}
// 添加
import paramSetupServer from '../api/system_high/paramSetupServer'
// 替换所有 paramSetupServerInstance 为 paramSetupServer
```
### 步骤 2修改 index.js
```javascript
// 删除这些导入
import { setUserServer } from './store/user'
import { setParamSetupServer } from './store/app'
// 删除这些调用
setUserServer(systemApi.userServer)
setParamSetupServer(systemHighApi.paramSetupServer)
// 删除 AdminFramework 类中的这些方法
setUserServer(userServer) { ... }
setParamSetupServer(paramSetupServer) { ... }
```
### 步骤 3测试验证
运行项目,确保所有功能正常。
## ✅ 总结
### 重构成果
- ✅ 代码更简洁(减少 26 行)
- ✅ 结构更清晰
- ✅ 依赖关系更明确
- ✅ 维护更容易
- ✅ 功能完全正常
### 后续建议
1. **保持简单**:除非有特殊需求,否则使用直接导入
2. **统一风格**:项目中的所有 API 都使用相同的导入方式
3. **文档更新**:更新项目文档,说明 API 的使用方式
---
**重构完成!** 🎉
现在框架代码更简洁、更易维护了。

View File

@@ -1,314 +0,0 @@
# authorityMenus 接口失败解决方案
## 🔧 问题描述
登录成功后,调用 `/sys_user/authorityMenus` 接口失败,导致无法获取完整的菜单数据。
## ✅ 解决方案
### 方案:使用默认菜单配置
`authorityMenus` 接口失败时,系统会自动使用默认的菜单配置,并根据登录接口返回的菜单 ID 数组进行过滤。
## 📁 新增文件
### `src/config/menuConfig.js`
这个文件包含了默认的菜单配置,包括:
1. **系统管理**
- 用户管理 (`/system/user`)
- 角色管理 (`/system/role`)
- 系统日志 (`/system/log`)
- 参数设置 (`/system/param`)
2. **高级管理**
- 菜单管理 (`/system_high/menu`)
- 控制管理 (`/system_high/control`)
- 系统标题 (`/system_high/title`)
3. **首页** (`/home`)
## 🔄 工作流程
### 1. 登录流程
```
用户登录
调用 /sys_user/login 接口
返回: { token, user, authorityMenus: "[1,142,121,...]" }
保存 token 和用户信息
解析 authorityMenus (字符串 → 数组)
调用 /sys_user/authorityMenus 接口
接口失败 ❌
使用默认菜单配置 + 根据 ID 过滤
生成路由
登录成功 ✅
```
### 2. 菜单过滤逻辑
```javascript
// 登录返回的菜单 IDs
authorityMenus: "[1,142,121,143,144,145,124,147,120,123,125,...]"
// 解析为数组
menuIds: [1, 142, 121, 143, 144, 145, 124, 147, 120, 123, 125, ...]
// 从默认菜单配置中过滤出这些 ID 对应的菜单
filteredMenus = filterMenusByIds(menuIds, defaultMenus)
// 生成路由
routes = uiTool.getRoutes(Main, ParentView, Page404)
```
## 📝 代码修改
### 1. `src/store/user.js`
**导入默认菜单配置:**
```javascript
import { defaultMenus, filterMenusByIds } from '../config/menuConfig'
```
**修改 `setAuthorityMenus` 方法:**
```javascript
async setAuthorityMenus({ state, commit }, { Main, ParentView, Page404, authorityMenus, menuIds }) {
let menus = authorityMenus
if (!menus && userServerInstance) {
try {
// 尝试调用接口
let res = await userServerInstance.authorityMenus()
if (res && res.code === 0 && res.data) {
menus = res.data
}
} catch (error) {
console.error('获取权限菜单失败:', error)
console.warn('将使用默认菜单配置')
// 接口失败,使用默认菜单配置
if (menuIds && menuIds.length > 0) {
// 根据 ID 过滤菜单
menus = filterMenusByIds(menuIds, defaultMenus)
} else {
// 使用所有默认菜单
menus = defaultMenus
}
}
}
// ... 后续处理
}
```
**修改 `handleLogin` 方法:**
```javascript
async handleLogin({ state, commit, dispatch }, { userFrom, Main, ParentView, Page404 }) {
let res = await userServerInstance.login(userFrom)
let token = res.data.token
let user = res.data.user
let authorityMenusIds = res.data.authorityMenus
commit('setUserName', user.name.trim())
commit('setToken', token)
// 解析菜单 IDs
let menuIds = []
if (authorityMenusIds) {
if (typeof authorityMenusIds === 'string') {
menuIds = JSON.parse(authorityMenusIds)
} else if (Array.isArray(authorityMenusIds)) {
menuIds = authorityMenusIds
}
}
// 传递 menuIds以便在接口失败时使用
await dispatch('setAuthorityMenus', {
Main,
ParentView,
Page404,
menuIds
})
}
```
## 🎯 测试步骤
### 1. 启动项目
```bash
cd demo-project
npm run dev
```
### 2. 登录测试
- 用户名:`zc`
- 密码:对应的密码
### 3. 查看控制台日志
**成功的日志:**
```
登录接口返回: { code: 0, data: { token, user, authorityMenus } }
登录返回的菜单 IDs: "[1,142,121,...]"
获取权限菜单失败: [错误信息]
将使用默认菜单配置
根据菜单 IDs 过滤后的菜单: [...]
最终处理的权限菜单: [...]
生成的主菜单: { path: '/', children: [...] }
```
### 4. 验证结果
登录成功后,应该能看到:
- ✅ 页面刷新
- ✅ 进入系统首页
- ✅ 左侧显示菜单(根据权限过滤)
- ✅ 顶部显示用户名
## 📊 菜单 ID 映射
根据登录返回的菜单 IDs
```
[1,142,121,143,144,145,124,147,120,123,125,132,133,126,136,137,138,139,151,152,153,154,149,150,156,157,158,122,159,5,11,12,13,67,68,15]
```
默认菜单配置中包含的 IDs
- `1` - 首页
- `5` - 系统管理
- `11` - 用户管理
- `12` - 角色管理
- `13` - 系统日志
- `15` - 参数设置
- `120` - 高级管理
- `122` - 菜单管理
- `123` - 控制管理
- `124` - 系统标题
过滤后会显示这些菜单。
## ⚠️ 注意事项
### 1. 默认菜单配置的限制
默认菜单配置只包含了常用的系统管理菜单。如果你的系统有其他业务菜单,需要:
**选项 A扩展默认菜单配置**
编辑 `src/config/menuConfig.js`,添加更多菜单:
```javascript
export const defaultMenus = [
// ... 现有菜单
{
id: 200,
name: '业务管理',
path: '/business',
component: '',
parent_id: 0,
type: '菜单',
is_show_menu: 1,
icon: 'md-briefcase',
children: [
{
id: 201,
name: '订单管理',
path: '/business/order',
component: 'business/order',
parent_id: 200,
type: '页面',
is_show_menu: 1
}
]
}
]
```
**选项 B修复后端接口**
这是推荐的长期方案。修复 `/sys_user/authorityMenus` 接口,使其返回完整的菜单对象数组。
### 2. 菜单组件路径
默认菜单配置中的 `component` 字段指向 `src/views/` 目录下的组件。
例如:
- `component: 'system/sys_user'``src/views/system/sys_user.vue`
- `component: 'home/index'``src/views/home/index.vue`
确保这些组件文件存在。
### 3. 菜单权限
即使使用默认菜单配置,也会根据登录返回的菜单 IDs 进行过滤。
用户只能看到他有权限的菜单。
## 🔧 后续优化建议
### 短期方案(当前实现)
✅ 使用默认菜单配置 + ID 过滤
- 优点:快速解决问题,用户可以登录
- 缺点:需要手动维护默认菜单配置
### 长期方案(推荐)
🎯 修复后端 `authorityMenus` 接口
- 优点:动态获取菜单,灵活性高
- 缺点:需要修改后端代码
**建议后端接口返回格式:**
```json
{
"code": 0,
"message": "请求成功",
"data": [
{
"id": 1,
"name": "首页",
"path": "/home",
"component": "home/index",
"parent_id": 0,
"type": "页面",
"is_show_menu": 1,
"icon": "md-home",
"sort": 1
},
{
"id": 5,
"name": "系统管理",
"path": "/system",
"component": "",
"parent_id": 0,
"type": "菜单",
"is_show_menu": 1,
"icon": "md-settings",
"sort": 2,
"children": [...]
}
]
}
```
## 🎉 总结
现在即使 `authorityMenus` 接口失败,系统也能:
1. ✅ 正常登录
2. ✅ 显示菜单(根据权限过滤)
3. ✅ 访问有权限的页面
4. ✅ 提供良好的用户体验
如果需要添加更多菜单,请编辑 `src/config/menuConfig.js` 文件。
---
**当前状态**:登录功能已修复,可以正常使用!🎉

View File

@@ -1,225 +0,0 @@
# Demo 项目修复完成报告
## ✅ 修复完成时间
**2025-10-08**
## 🎯 修复的问题
### 1. ✅ 路径别名配置问题
**问题描述**:框架源码中的组件使用 `@/` 别名引用内部文件,但 webpack 配置中的 `@` 别名指向 demo-project/src导致无法找到框架的工具类和组件。
**解决方案**
修改 `demo-project/webpack.config.js`,将 `@` 别名指向框架源码目录:
```javascript
resolve: {
extensions: ['.js', '.vue', '.json'],
alias: {
// 框架源码的别名(必须在前面,优先级高)
'@': path.resolve(__dirname, '../src'),
'@component': path.resolve(__dirname, '../src/components'),
'@utils': path.resolve(__dirname, '../src/utils'),
'@api': path.resolve(__dirname, '../src/api'),
'@config': path.resolve(__dirname, '../src/config'),
'@assets': path.resolve(__dirname, '../src/assets'),
// demo 项目的别名
'~': path.resolve(__dirname, 'src'),
'vue$': 'vue/dist/vue.esm.js'
}
}
```
### 2. ✅ 缺少 core-js 依赖
**问题描述**Babel 编译时需要 core-js 提供 polyfill但项目中未安装。
**解决方案**
```bash
npm install core-js@3
```
### 3. ✅ 登录接口未调用问题
**问题描述**:登录页面调用 `handleLogin` action 时,参数格式不正确,缺少必需的 `Main``ParentView``Page404` 组件参数。
**原代码**`src/views/login/login.vue`
```javascript
async handleSubmit({ userName, password }) {
let user = { name: userName, password: password }
await this.handleLogin(user) // ❌ 参数不完整
window.location.reload()
}
```
**修复后**
```javascript
import Main from '@component/main'
import ParentView from '@component/parent-view'
import Page404 from '@/views/error-page/404.vue'
import { mapActions } from 'vuex'
export default {
methods: {
...mapActions('user', ['handleLogin']),
async handleSubmit({ userName, password }) {
try {
let userFrom = { name: userName, password: password }
await this.handleLogin({
userFrom, // ✅ 用户信息
Main, // ✅ 主布局组件
ParentView, // ✅ 父视图组件
Page404 // ✅ 404页面组件
})
this.$Message.success('登录成功!')
window.location.reload()
} catch (error) {
console.error('登录失败:', error)
this.$Message.error(error.message || '登录失败,请检查用户名和密码')
}
},
},
}
```
## 📊 修复结果
### 编译状态
**webpack 5.102.1 compiled successfully**
### 功能验证
- ✅ 项目可以正常启动
- ✅ 没有编译错误
- ✅ 登录功能可以正确调用登录接口
- ✅ 框架的所有组件和工具类都能正确引用
## 🚀 如何启动项目
### 方式一:使用启动脚本
```bash
双击 demo-project/start.bat
```
### 方式二:命令行启动
```bash
cd demo-project
npm run dev
```
### 访问地址
浏览器会自动打开:`http://localhost:8080`
## 📝 登录测试
项目启动后,你可以在登录页面输入用户名和密码进行测试。
**注意**
- 登录接口会调用 `userServer.login(userFrom)` 方法
- 需要确保后端 API 服务正常运行(默认地址:`http://localhost:9098/api/`
- 如果后端未启动,登录会失败并显示错误信息
## 🔧 配置说明
### API 配置
`demo-project/src/config/index.js` 中配置:
```javascript
export default {
// 系统标题
title: 'Demo 管理系统',
// API 基础路径
apiUrl: 'http://localhost:9098/api/',
// 文件上传路径
uploadUrl: 'http://localhost:9098/api/upload',
// Token 存储的 key
tokenKey: 'demo_token',
// 其他配置
timeout: 30000,
// 是否显示页面加载进度条
showProgressBar: true
}
```
### 修改 API 地址
如果你的后端 API 地址不同,请修改 `apiUrl``uploadUrl`
## 🎉 框架功能
现在你的 Demo 项目已经完全集成了框架的所有功能:
### 1. 用户认证
- ✅ 登录功能
- ✅ 登出功能
- ✅ Token 管理
- ✅ 权限菜单获取
### 2. 路由管理
- ✅ 动态路由
- ✅ 权限路由
- ✅ 路由守卫
### 3. 状态管理
- ✅ Vuex Store
- ✅ 用户状态
- ✅ 应用状态
- ✅ 状态持久化
### 4. UI 组件
- ✅ 主布局Main
- ✅ 侧边菜单
- ✅ 顶部导航
- ✅ 面包屑导航
- ✅ 错误页面401、404、500
### 5. 工具库
- ✅ HTTP 请求封装
- ✅ UI 工具类
- ✅ 通用工具函数
### 6. 系统管理页面
- ✅ 系统日志sys_log
- ✅ 参数设置sys_param_setup
- ✅ 角色管理sys_role
- ✅ 用户管理sys_user
- ✅ 控制管理sys_control
- ✅ 菜单管理sys_menu
- ✅ 系统标题sys_title
## 📚 下一步
1. **启动后端服务**:确保后端 API 服务运行在 `http://localhost:9098/api/`
2. **测试登录**:使用有效的用户名和密码进行登录测试
3. **开发业务功能**:在 `demo-project/src/views/business/` 目录下添加你的业务页面
4. **添加路由**:在 `demo-project/src/main.js` 中添加业务路由
## ⚠️ 注意事项
1. **后端 API**:项目需要配套的后端 API 服务才能完整运行
2. **端口占用**:确保 8080 端口未被占用
3. **浏览器兼容**:推荐使用 Chrome、Edge 或 Firefox 浏览器
4. **Node 版本**:建议使用 Node.js 14+ 版本
## 🐛 常见问题
### Q1: 登录后提示"userServer not initialized"
**A**: 这是因为 userServer 未正确初始化。框架已经在 `src/index.js` 中自动设置了 API应该不会出现这个问题。
### Q2: 登录失败,提示网络错误
**A**: 检查后端 API 服务是否正常运行,以及 `config/index.js` 中的 `apiUrl` 配置是否正确。
### Q3: 页面空白或报错
**A**: 打开浏览器控制台查看具体错误信息,通常是路由或组件引用问题。
## 📞 技术支持
如果遇到问题,请检查:
1. 浏览器控制台的错误信息
2. 终端的编译输出
3. 网络请求是否正常F12 -> Network
---
**修复完成!项目现在可以正常运行了!** 🎉

View File

@@ -1,203 +0,0 @@
# Demo 项目修复说明
## ✅ 已完成的修复
### 1. 配置更新
#### ✅ `src/main.js`
```javascript
// 修改为直接使用框架源码
import AdminFramework from '../../src/index.js'
```
**好处**
- 实时调试框架代码
- 热更新支持
- 无需重新打包
#### ✅ `webpack.config.js`
添加了框架源码的路径别名:
```javascript
alias: {
'@component': path.resolve(__dirname, '../src/components'),
'@utils': path.resolve(__dirname, '../src/utils'),
'@api': path.resolve(__dirname, '../src/api'),
'@config': path.resolve(__dirname, '../src/config'),
'@assets': path.resolve(__dirname, '../src/assets')
}
```
#### ✅ `babel.config.js`
添加了 JSX 支持:
```javascript
presets: [
'@babel/preset-env',
'@vue/babel-preset-jsx'
]
```
#### ✅ `package.json`
新增依赖:
- `@vue/babel-preset-jsx@^1.4.0` - JSX 支持
- `brace@^0.11.1` - 代码编辑器
- `vue2-ace-editor@^0.0.15` - Ace 编辑器
### 2. 脚本文件
#### ✅ `install.bat` - 一键安装脚本
```batch
双击运行即可安装所有依赖
```
#### ✅ `start.bat` - 启动脚本(已更新)
```batch
自动检查并安装缺失的依赖
```
### 3. 文档文件
#### ✅ 创建的文档:
- `README_FIRST.txt` - 首次运行必读 ⭐
- `启动前必读.md` - 详细启动指南
- `修复说明.md` - 本文件
- `CHANGELOG.md` - 更新日志
#### ✅ 更新的文档:
- `README.md` - 项目说明
- `如何启动.txt` - 快速指南
## 🚀 用户需要做什么
### 第一步:安装依赖
**方式一(推荐)**
```bash
双击 install.bat
```
**方式二**
```bash
cd demo-project
npm install
```
如果遇到依赖缺失,运行:
```bash
npm install @vue/babel-preset-jsx brace vue2-ace-editor
```
### 第二步:启动项目
**方式一(推荐)**
```bash
双击 start.bat
```
**方式二**
```bash
npm run dev
```
### 第三步:访问应用
浏览器自动打开 `http://localhost:8080`
## 📋 检查清单
运行前确保:
- [ ] 已进入 `demo-project` 目录
- [ ] 已运行 `npm install``install.bat`
- [ ] 没有 "UNMET DEPENDENCY" 错误
- [ ] 端口 8080 未被占用
验证命令:
```bash
npm list --depth=0
```
应该看到:
```
✅ @vue/babel-preset-jsx@1.4.0
✅ brace@0.11.1
✅ vue2-ace-editor@0.0.15
✅ vue@2.7.16
✅ vuex@3.6.2
✅ vue-router@3.6.5
✅ view-design@4.7.0
```
## ⚠️ 常见错误及解决
### 错误1UNMET DEPENDENCY
**原因**:依赖未安装
**解决**
```bash
npm install @vue/babel-preset-jsx brace vue2-ace-editor
```
### 错误2Cannot find module '../../src/index.js'
**原因**:项目结构不正确
**解决**:确保目录结构为:
```
f:\项目\前端框架项目\
├── src\ ← 框架源码
│ └── index.js
└── demo-project\ ← Demo 项目
```
### 错误3端口被占用
**原因**8080 端口已被使用
**解决**:修改 `webpack.config.js`
```javascript
devServer: {
port: 8081 // 改成其他端口
}
```
### 错误4Babel 编译错误
**原因**JSX preset 未安装
**解决**
```bash
npm install @vue/babel-preset-jsx --save-dev
```
## 📊 项目状态
| 项目 | 状态 |
|------|------|
| 框架源码引用 | ✅ 已配置 |
| Webpack 配置 | ✅ 已更新 |
| Babel 配置 | ✅ 已更新 |
| 依赖列表 | ✅ 已更新 |
| 安装脚本 | ✅ 已创建 |
| 启动脚本 | ✅ 已更新 |
| 文档 | ✅ 已完善 |
## 🎯 下一步
1. **运行** `install.bat` 安装依赖
2. **运行** `start.bat` 启动项目
3. **访问** `http://localhost:8080`
4. **开始** 开发你的应用!
## 📚 相关文档
- [README_FIRST.txt](./README_FIRST.txt) - 首次运行必读
- [启动前必读.md](./启动前必读.md) - 详细指南
- [CHANGELOG.md](./CHANGELOG.md) - 更新日志
- [README.md](./README.md) - 完整说明
---
**修复完成时间**: 2025-10-08
**修复人员**: AI Assistant

View File

@@ -1,115 +0,0 @@
# ⚠️ 启动前必读
## 📦 第一步:安装依赖
**在 `demo-project` 目录下**运行:
```bash
npm install
```
如果遇到依赖缺失错误,运行:
```bash
npm install @vue/babel-preset-jsx brace vue2-ace-editor --save
```
## 🚀 第二步:启动项目
### 方式一:使用脚本(推荐)
**Windows 用户**
```bash
双击 start.bat
```
**Linux/Mac 用户**
```bash
./start.sh
```
### 方式二:手动启动
```bash
npm run dev
```
## ✅ 验证安装
运行以下命令检查依赖是否完整:
```bash
npm list --depth=0
```
应该看到以下关键依赖:
-@vue/babel-preset-jsx
- ✅ brace
- ✅ vue2-ace-editor
- ✅ vue
- ✅ vuex
- ✅ vue-router
- ✅ view-design
## 🔍 常见问题
### 问题1依赖缺失
**症状**:看到 "UNMET DEPENDENCY" 错误
**解决**
```bash
# 删除依赖重装
rm -rf node_modules
rm package-lock.json
npm install
```
### 问题2端口被占用
**症状**8080 端口已被占用
**解决**:修改 `webpack.config.js` 中的端口
```javascript
devServer: {
port: 8081 // 改成其他端口
}
```
### 问题3路径找不到
**症状**:无法找到 ../../src/index.js
**解决**:确保项目结构正确
```
f:\项目\前端框架项目\
├── src\ # ← 框架源码
│ └── index.js # ← 框架入口
└── demo-project\ # ← Demo 项目
└── src\
└── main.js # ← 引用 ../../src/index.js
```
## 📝 项目说明
本项目直接使用框架源码(不是打包文件),好处:
- ✅ 实时调试
- ✅ 热更新
- ✅ 方便开发
## 🎯 访问地址
启动后访问:`http://localhost:8080`
可用页面:
- `/login` - 登录页面
- `/home` - 主页
- `/business/product` - 产品列表示例
---
**如有问题,请查看**
- [CHANGELOG.md](./CHANGELOG.md) - 更新日志
- [README.md](./README.md) - 完整说明
- [如何启动.txt](./如何启动.txt) - 快速指南

View File

@@ -1,50 +0,0 @@
====================================
Demo 项目启动说明
====================================
本项目现在使用框架源码,更方便调试!
⚠️ 重要:首次运行必须先安装依赖!
【方式一:一键安装+启动(推荐)】
Windows 用户:
1. 双击 install.bat安装依赖
2. 双击 start.bat启动项目
【方式二:手动安装+启动】
1. 安装依赖(首次必须)
npm install
2. 如果提示依赖缺失,运行:
npm install @vue/babel-preset-jsx brace vue2-ace-editor
3. 启动开发服务器
npm run dev
4. 浏览器自动打开
http://localhost:8080
【可访问页面】
/login - 登录页面
/home - 主页
/business/product - 产品列表示例
【遇到错误?】
1. 删除依赖重装:
rm -rf node_modules
rm package-lock.json
npm install
2. 查看更新日志:
CHANGELOG.md
3. 查看详细文档:
README.md
快速启动.md
====================================

View File

@@ -1,143 +0,0 @@
# 快速配置组件映射
## 🎯 一句话说明
**在 `Vue.use()` 时传入 `componentMap` 参数,将后端权限菜单中的组件路径映射到实际组件。**
## 📝 三步配置
### 步骤1查看权限菜单接口
查看后端接口返回的所有 `component` 字段:
```json
{
"data": [
{ "component": "ball/games.vue" },
{ "component": "order/pay_orders.vue" },
{ "component": "ball/wch_users.vue" }
]
}
```
### 步骤2创建并导入组件
```javascript
// src/main.js
import GamesComponent from './views/ball/games.vue'
import PayOrdersComponent from './views/order/pay_orders.vue'
import WchUsersComponent from './views/ball/wch_users.vue'
```
### 步骤3配置映射
```javascript
Vue.use(AdminFramework, {
config,
ViewUI,
VueRouter,
Vuex,
createPersistedState,
componentMap: {
'ball/games': GamesComponent,
'order/pay_orders': PayOrdersComponent,
'ball/wch_users': WchUsersComponent
}
})
```
## ✅ 完成!
现在权限菜单中的所有业务页面都能正常显示了。
## 📋 配置模板
```javascript
import Vue from 'vue'
import VueRouter from 'vue-router'
import Vuex from 'vuex'
import ViewUI from 'view-design'
import createPersistedState from 'vuex-persistedstate'
import 'view-design/dist/styles/iview.css'
import AdminFramework from '../../src/index.js'
import config from './config'
import App from './App.vue'
// ==================== 导入业务组件 ====================
// TODO: 根据权限菜单接口,导入所有业务组件
// import XXXComponent from './views/xxx/xxx.vue'
Vue.use(AdminFramework, {
config,
ViewUI,
VueRouter,
Vuex,
createPersistedState,
componentMap: {
// TODO: 配置组件映射
// 'xxx/xxx': XXXComponent
}
})
new Vue({
el: '#app',
router: AdminFramework.router,
store: AdminFramework.store,
render: h => h(App),
mounted() {
AdminFramework.uiTool.setRem()
this.$store.dispatch('user/setAuthorityMenus', {
Main: AdminFramework.Main,
ParentView: AdminFramework.ParentView,
Page404: AdminFramework.Page404
})
}
})
```
## 💡 关键要点
### 1. 路径不需要 .vue 后缀
```javascript
// ✅ 正确
componentMap: {
'ball/games': GamesComponent
}
// ❌ 错误(虽然也能用,但不推荐)
componentMap: {
'ball/games.vue': GamesComponent
}
```
### 2. 系统组件无需配置
这些已自动映射,**不需要**在 componentMap 中配置:
- `home/index.vue`
- `system/sys_user.vue`
- `system/sys_role.vue`
- `system/sys_log.vue`
- `system/sys_param_setup.vue`
- `system_high/sys_menu.vue`
- `system_high/sys_control.vue`
- `system_high/sys_title.vue`
### 3. 未映射的组件会显示提示
如果组件没有配置映射,页面会显示:
```
⚠️ 警告
页面组件未加载: ball/games.vue
请在项目中创建此组件或在组件映射表中注册
```
## 📚 完整文档
查看详细说明:[权限菜单组件配置指南.md](./权限菜单组件配置指南.md)
---
**配置完成后,所有权限菜单中的页面都能正常显示!** 🎉

View File

@@ -1,362 +0,0 @@
# 文档更新说明
## 📝 更新内容
已更新 `完整使用文档.md`,主要修改如下:
### 1. 移除已废弃的方法
**移除的方法**
-`setUserServer(userServer)` - 已废弃
-`setParamSetupServer(paramSetupServer)` - 已废弃
**原因**
- 框架已改为直接导入 API 模块
- 不再使用依赖注入模式
- 简化了代码结构
### 2. 添加 HomePage 参数说明
**新增内容**
#### install 方法参数
```javascript
Vue.use(AdminFramework, {
config: yourConfig,
ViewUI: ViewUI,
VueRouter: VueRouter,
Vuex: Vuex,
createPersistedState: createPersistedState,
HomePage: HomePage // ✅ 新增:可选的自定义首页组件
})
```
**参数说明**
- `HomePage`: 自定义首页组件(可选,不传则使用框架内置组件)
### 3. 完善 Q11: 主页 HomePage 组件说明
**新增两种使用方式**
#### 方式一:使用框架内置的主页组件(默认)
```javascript
// 不传入 HomePage框架会使用内置组件
Vue.use(AdminFramework, {
config,
ViewUI,
VueRouter,
Vuex,
createPersistedState
})
```
**内置组件特性**
- ✅ 自动从 Vuex Store 获取系统标题
- ✅ 优雅的欢迎页面样式
- ✅ 无需额外配置
#### 方式二:传入自定义首页组件(推荐)
**创建自定义首页**
```vue
<!-- src/views/home/index.vue -->
<template>
<div class="custom-home">
<h1>欢迎使用 {{ sysFormModel.title }}</h1>
<p>这是自定义的首页内容</p>
</div>
</template>
<script>
import { mapGetters } from 'vuex'
export default {
computed: {
...mapGetters({
sysFormModel: 'app/sysFormModel'
})
}
}
</script>
```
**传入自定义组件**
```javascript
import HomePage from './views/home/index.vue'
Vue.use(AdminFramework, {
config,
ViewUI,
VueRouter,
Vuex,
createPersistedState,
HomePage // ✅ 传入自定义首页组件
})
```
### 4. 重要说明:首页路由配置
**关键点**
- ⚠️ **首页路由完全由后端权限菜单返回**
- ⚠️ 后端必须返回 `path: '/home'` 的菜单配置
- ⚠️ 后端返回的 `component` 字段会映射到实际组件
**后端菜单配置示例**
```json
{
"id": 1,
"name": "首页",
"path": "/home",
"component": "home/index", // 映射到 src/views/home/index.vue
"parent_id": 0,
"type": "页面",
"is_show_menu": 1,
"icon": "md-home",
"sort": 1
}
```
**组件映射规则**
```javascript
// 后端返回: "component": "home/index"
// 实际加载: src/views/home/index.vue
// 后端返回: "component": "system/user"
// 实际加载: src/views/system/user.vue
```
### 5. 降级方案
如果后端接口失败,框架会使用默认菜单配置(`src/config/menuConfig.js`
```javascript
export const defaultMenus = [
{
id: 1,
name: '首页',
path: '/home',
component: 'home/index',
parent_id: 0,
type: '页面',
is_show_menu: 1,
icon: 'md-home',
sort: 1
},
// ... 其他菜单
]
```
### 6. 更新快速开始示例
**新的 main.js 示例**
```javascript
import Vue from 'vue'
import VueRouter from 'vue-router'
import Vuex from 'vuex'
import ViewUI from 'view-design'
import createPersistedState from 'vuex-persistedstate'
import AdminFramework from './libs/admin-framework.js'
import App from './App.vue'
import config from './config'
import HomePage from './views/home/index.vue' // ✅ 导入自定义首页
Vue.use(AdminFramework, {
config,
ViewUI,
VueRouter,
Vuex,
createPersistedState,
HomePage // ✅ 传入自定义首页组件
})
new Vue({
el: '#app',
router: AdminFramework.router,
store: AdminFramework.store,
render: h => h(App),
mounted() {
AdminFramework.uiTool.setRem()
// 只在已登录时获取系统标题
const token = this.$store.state.user.token
if (token) {
this.$store.dispatch('app/getSysTitle', {
defaultTitle: 'Demo 管理系统',
defaultLogo: ''
})
} else {
document.title = 'Demo 管理系统'
}
}
})
```
## 📊 更新对比
### 旧版本(已废弃)
```javascript
// ❌ 旧版本:使用依赖注入
import { systemApi, systemHighApi } from 'admin-framework'
AdminFramework.setUserServer(systemApi.userServer)
AdminFramework.setParamSetupServer(systemHighApi.paramSetupServer)
// ❌ 旧版本:首页路由硬编码在框架中
// 无法自定义首页组件
```
### 新版本(当前)
```javascript
// ✅ 新版本:直接导入 API
import userServer from '../api/system/userServer'
import paramSetupServer from '../api/system_high/paramSetupServer'
// ✅ 新版本:支持自定义首页组件
import HomePage from './views/home/index.vue'
Vue.use(AdminFramework, {
config,
ViewUI,
VueRouter,
Vuex,
createPersistedState,
HomePage // 可选:传入自定义首页组件
})
```
## 🎯 最佳实践
### 推荐做法
1. **创建自定义首页组件**
```bash
src/views/home/index.vue
```
2. **在 Vue.use() 时传入 HomePage 参数**
```javascript
import HomePage from './views/home/index.vue'
Vue.use(AdminFramework, {
config,
ViewUI,
VueRouter,
Vuex,
createPersistedState,
HomePage // 传入自定义首页组件
})
```
3. **确保后端返回首页菜单配置**
```json
{
"id": 1,
"name": "首页",
"path": "/home",
"component": "home/index",
"parent_id": 0,
"type": "页面",
"is_show_menu": 1
}
```
4. **在 defaultMenus 中包含首页配置作为降级方案**
```javascript
// src/config/menuConfig.js
export const defaultMenus = [
{
id: 1,
name: '首页',
path: '/home',
component: 'home/index',
// ...
}
]
```
### 不推荐的做法
1. ❌ 使用已废弃的 `setUserServer` 和 `setParamSetupServer` 方法
2. ❌ 在代码中硬编码首页路由
3. ❌ 不提供降级方案defaultMenus
## 📝 迁移指南
### 从旧版本迁移到新版本
**步骤 1移除废弃的方法调用**
```javascript
// ❌ 删除这些代码
AdminFramework.setUserServer(systemApi.userServer)
AdminFramework.setParamSetupServer(systemHighApi.paramSetupServer)
```
**步骤 2创建自定义首页组件**
```bash
# 创建首页组件文件
mkdir -p src/views/home
touch src/views/home/index.vue
```
**步骤 3更新 main.js**
```javascript
// 添加 HomePage 导入
import HomePage from './views/home/index.vue'
// 在 Vue.use() 时传入
Vue.use(AdminFramework, {
config,
ViewUI,
VueRouter,
Vuex,
createPersistedState,
HomePage // 新增
})
```
**步骤 4确保后端返回首页配置**
检查后端 `authorityMenus` 接口是否返回首页配置。
**步骤 5测试**
```bash
npm run dev
```
登录后应该能看到自定义的首页。
## ✅ 验证清单
- ✅ 移除了 `setUserServer` 和 `setParamSetupServer` 的调用
- ✅ 创建了自定义首页组件 `src/views/home/index.vue`
- ✅ 在 `Vue.use()` 时传入了 `HomePage` 参数
- ✅ 后端返回了首页菜单配置
- ✅ `defaultMenus` 中包含了首页配置
- ✅ 登录后能正常跳转到首页
- ✅ 首页显示正确的内容
## 📚 相关文档
- `完整使用文档.md` - 完整的框架使用文档
- `demo-project/README.md` - Demo 项目说明
- `demo-project/登录跳转首页修复说明.md` - 登录跳转逻辑说明
- `demo-project/移除硬编码首页说明.md` - 移除硬编码首页的说明
---
**文档已更新完成!** 🎉
现在文档更准确地反映了框架的当前实现,包括:
- ✅ 移除了已废弃的方法
- ✅ 添加了 HomePage 参数说明
- ✅ 完善了首页组件的使用方式
- ✅ 提供了最佳实践和迁移指南

View File

@@ -1,387 +0,0 @@
# 未登录接口调用问题修复
## 🔍 问题描述
### 错误现象
在用户未登录时,`sys_parameter/key` 接口被调用,因为没有 token 导致接口报错。
### 错误原因
`demo-project/src/main.js``mounted` 钩子中,无条件调用了 `getSysTitle` action
```javascript
mounted() {
AdminFramework.uiTool.setRem()
// ❌ 无论是否登录都调用
this.$store.dispatch('app/getSysTitle', {
defaultTitle: 'Demo 管理系统',
defaultLogo: ''
})
}
```
`getSysTitle` action 会调用后端接口:
- `paramSetupServer.getOne('sys_title')` - 获取系统标题
- `paramSetupServer.getOne('sys_logo')` - 获取系统 Logo
这些接口需要 token 认证,但在应用启动时用户可能还没登录,导致接口调用失败。
### 调用时机问题
```
应用启动
Vue 实例 mounted
调用 getSysTitle ← ❌ 此时可能未登录
调用后端接口
没有 token接口报错 ❌
```
## ✅ 解决方案
### 方案:只在已登录时调用接口
**核心思路**
1. 在调用 `getSysTitle` 前检查是否已登录(是否有 token
2. 已登录:调用接口获取系统标题
3. 未登录:直接使用默认标题
### 修改 1`demo-project/src/main.js`
**修改前**
```javascript
mounted() {
AdminFramework.uiTool.setRem()
// ❌ 无条件调用,可能导致未登录时接口报错
this.$store.dispatch('app/getSysTitle', {
defaultTitle: 'Demo 管理系统',
defaultLogo: ''
})
}
```
**修改后**
```javascript
mounted() {
AdminFramework.uiTool.setRem()
// ✅ 检查是否已登录
const token = this.$store.state.user.token
if (token) {
// 已登录,调用接口获取系统标题
this.$store.dispatch('app/getSysTitle', {
defaultTitle: 'Demo 管理系统',
defaultLogo: ''
})
} else {
// 未登录,直接设置默认标题
document.title = 'Demo 管理系统'
}
}
```
### 修改 2`src/store/app.js` 的 `getSysTitle` action
**修改前**
```javascript
async getSysTitle({ state, commit }, { defaultTitle = '智能代码平台', defaultLogo = '' }) {
let formModel = {
title: defaultTitle,
logoUrl: defaultLogo
}
try {
// ❌ 直接调用接口,不检查是否已登录
let res1 = await paramSetupServer.getOne('sys_title')
if (res1 && res1.data) {
formModel.title = res1.data.value
document.title = res1.data.value
}
let res2 = await paramSetupServer.getOne('sys_logo')
if (res2 && res2.data) {
formModel.logoUrl = res2.data.value
}
} catch (error) {
console.warn('获取系统标题失败,使用默认标题:', error || '接口调用失败')
document.title = formModel.title
}
commit('setSysTitle', formModel)
}
```
**修改后**
```javascript
async getSysTitle({ state, commit, rootState }, { defaultTitle = '智能代码平台', defaultLogo = '' }) {
let formModel = {
title: defaultTitle,
logoUrl: defaultLogo
}
// ✅ 检查是否已登录(有 token
const token = rootState.user.token
if (token) {
// 已登录,尝试从后端获取系统标题
try {
let res1 = await paramSetupServer.getOne('sys_title')
if (res1 && res1.data) {
formModel.title = res1.data.value
document.title = res1.data.value
}
let res2 = await paramSetupServer.getOne('sys_logo')
if (res2 && res2.data) {
formModel.logoUrl = res2.data.value
}
} catch (error) {
console.warn('获取系统标题失败,使用默认标题:', error || '接口调用失败')
document.title = formModel.title
}
} else {
// 未登录,直接使用默认标题
document.title = formModel.title
}
commit('setSysTitle', formModel)
}
```
## 📊 修复后的流程
### 未登录时
```
应用启动
Vue 实例 mounted
检查 token
token 不存在 ✅
直接设置默认标题 "Demo 管理系统"
不调用后端接口 ✅
```
### 已登录时
```
应用启动
Vue 实例 mounted
检查 token
token 存在 ✅
调用 getSysTitle action
检查 rootState.user.token
token 存在 ✅
调用后端接口获取系统标题
成功:使用后端返回的标题
失败:使用默认标题
```
### 登录流程
```
用户登录
保存 token 到 store
刷新页面
应用重新启动
Vue 实例 mounted
检查 token此时有 token
调用 getSysTitle 获取系统标题
```
## 🎯 优化点
### 1. 双重检查
**第一层检查**`main.js`
```javascript
const token = this.$store.state.user.token
if (token) {
this.$store.dispatch('app/getSysTitle', ...)
}
```
**第二层检查**`app.js`
```javascript
const token = rootState.user.token
if (token) {
// 调用接口
}
```
**为什么需要双重检查?**
- 第一层:避免不必要的 action 调用
- 第二层:防止 action 被其他地方调用时没有检查 token
### 2. 默认标题处理
**未登录时**
```javascript
document.title = 'Demo 管理系统'
```
**已登录但接口失败时**
```javascript
document.title = formModel.title // 使用传入的 defaultTitle
```
**已登录且接口成功时**
```javascript
document.title = res1.data.value // 使用后端返回的标题
```
### 3. 错误处理
```javascript
try {
// 调用接口
} catch (error) {
console.warn('获取系统标题失败,使用默认标题:', error || '接口调用失败')
document.title = formModel.title
}
```
即使接口调用失败,也会优雅降级到默认标题,不影响用户使用。
## ✅ 验证清单
### 未登录场景
- ✅ 访问首页显示登录页面
- ✅ 页面标题显示 "Demo 管理系统"
- ✅ 控制台没有接口报错
- ✅ Network 标签中没有 `sys_parameter/key` 请求
### 已登录场景
- ✅ 登录成功后刷新页面
- ✅ 页面标题显示系统标题(如果后端有配置)
- ✅ 如果后端接口失败,显示默认标题
- ✅ 系统 Logo 正确显示(如果后端有配置)
### 登录流程
- ✅ 输入用户名密码
- ✅ 点击登录
- ✅ 登录成功
- ✅ 页面刷新
- ✅ 进入系统首页
- ✅ 系统标题正确显示
## 💡 最佳实践
### 1. 接口调用前检查认证状态
```javascript
// ✅ 好的做法
if (token) {
await api.getData()
}
// ❌ 不好的做法
try {
await api.getData() // 可能因为没有 token 而失败
} catch (error) {
// 处理错误
}
```
### 2. 提供默认值
```javascript
// ✅ 好的做法
const title = res.data?.value || defaultTitle
// ❌ 不好的做法
const title = res.data.value // 可能是 undefined
```
### 3. 优雅降级
```javascript
// ✅ 好的做法
if (token) {
try {
const data = await api.getData()
useData(data)
} catch (error) {
useDefaultData()
}
} else {
useDefaultData()
}
```
### 4. 避免不必要的请求
```javascript
// ✅ 好的做法
if (needData && token) {
await api.getData()
}
// ❌ 不好的做法
await api.getData() // 无论是否需要都请求
```
## 🔧 相关修改
### 其他可能需要检查的地方
如果项目中还有其他在应用启动时调用的接口,也需要检查是否需要 token
1. **检查 `main.js` 的 `mounted` 钩子**
- 确保所有接口调用都检查了 token
2. **检查 `App.vue` 的 `mounted` 钩子**
- 确保没有未登录时调用需要认证的接口
3. **检查路由守卫**
- 确保路由守卫正确处理未登录的情况
4. **检查 Vuex actions**
- 确保需要认证的 actions 都检查了 token
## 📝 总结
### 修复的问题
- ✅ 未登录时不再调用需要认证的接口
- ✅ 避免了接口报错
- ✅ 提供了优雅的降级方案
- ✅ 改善了用户体验
### 代码改进
- **更健壮**:双重检查确保不会在未登录时调用接口
- **更友好**:即使接口失败也能正常显示默认标题
- **更清晰**:代码逻辑更容易理解和维护
---
**未登录接口调用问题已修复!** 🎉
现在系统会智能判断是否已登录,只在必要时调用后端接口。

View File

@@ -1,575 +0,0 @@
# 权限菜单组件配置指南
## 🎯 核心问题
**问题**:后端权限菜单接口返回的组件路径需要映射到实际组件,否则会显示 404。
**解决**:在 `Vue.use()` 时传入 `componentMap` 参数,一次性注册所有业务组件。
## 📝 配置步骤
### 第一步:查看权限菜单接口返回的组件路径
后端接口返回的菜单数据示例:
```json
{
"code": 0,
"data": [
{ "component": "home/index.vue" },
{ "component": "system/sys_user.vue" },
{ "component": "ball/games.vue" },
{ "component": "order/pay_orders.vue" },
{ "component": "ball/wch_users.vue" }
]
}
```
### 第二步:创建对应的业务组件
在项目中创建对应的组件文件:
```
src/views/
├── ball/
│ ├── games.vue
│ └── wch_users.vue
└── order/
└── pay_orders.vue
```
### 第三步:在 main.js 中配置组件映射
```javascript
import Vue from 'vue'
import AdminFramework from '../../src/index.js'
import config from './config'
// ✅ 导入所有业务组件(根据权限菜单接口的 component 字段)
import GamesComponent from './views/ball/games.vue'
import PayOrdersComponent from './views/order/pay_orders.vue'
import WchUsersComponent from './views/ball/wch_users.vue'
// 使用框架
Vue.use(AdminFramework, {
config,
ViewUI,
VueRouter,
Vuex,
createPersistedState,
// ✅ 一次性注册所有组件映射
componentMap: {
'ball/games': GamesComponent,
'order/pay_orders': PayOrdersComponent,
'ball/wch_users': WchUsersComponent
// 添加更多业务组件...
}
})
// 创建 Vue 实例
new Vue({
el: '#app',
router: AdminFramework.router,
store: AdminFramework.store,
render: h => h(App),
mounted() {
// 设置权限菜单(会自动加载映射的组件)
this.$store.dispatch('user/setAuthorityMenus', {
Main: AdminFramework.Main,
ParentView: AdminFramework.ParentView,
Page404: AdminFramework.Page404
})
}
})
```
## 🔧 两种配置方式
### 方式一:在 Vue.use 时配置(推荐)
```javascript
Vue.use(AdminFramework, {
config,
ViewUI,
VueRouter,
Vuex,
createPersistedState,
componentMap: {
'ball/games': GamesComponent,
'order/pay_orders': PayOrdersComponent
}
})
```
**优点**
- ✅ 集中配置,清晰明了
- ✅ 在框架初始化时就完成映射
- ✅ 代码简洁
### 方式二:使用 addComponentMap 方法
```javascript
Vue.use(AdminFramework, { config, ViewUI, VueRouter, Vuex, createPersistedState })
// 之后添加映射
AdminFramework.addComponentMap({
'ball/games': GamesComponent,
'order/pay_orders': PayOrdersComponent
})
```
**适用场景**
- 需要动态添加组件映射
- 分模块配置
## 📋 完整示例
### 根据你的权限菜单接口配置
查看你的接口返回数据,列出所有 `component` 字段:
```javascript
// 权限菜单返回的组件列表:
// - home/index.vue
// - system/sys_user.vue
// - system/sys_role.vue
// - system_high/sys_menu.vue
// - system/sys_log.vue
// - system/sys_param_setup.vue
// - ball/games.vue ← 业务组件,需要自己创建
// - ball/wch_users.vue ← 业务组件,需要自己创建
// - ball/venues.vue ← 业务组件,需要自己创建
// - order/pay_orders.vue ← 业务组件,需要自己创建
// - order/wch_wallets.vue ← 业务组件,需要自己创建
// - users/user_follows.vue ← 业务组件,需要自己创建
```
### 完整的 main.js 配置
```javascript
import Vue from 'vue'
import VueRouter from 'vue-router'
import Vuex from 'vuex'
import ViewUI from 'view-design'
import createPersistedState from 'vuex-persistedstate'
import 'view-design/dist/styles/iview.css'
import AdminFramework from '../../src/index.js'
import config from './config'
import App from './App.vue'
// ==================== 导入业务组件 ====================
// 球局模块
import GamesComponent from './views/ball/games.vue'
import WchUsersComponent from './views/ball/wch_users.vue'
import VenuesComponent from './views/ball/venues.vue'
import GameParticipantsComponent from './views/ball/game_participants.vue'
import GameCommentsComponent from './views/ball/game_comments.vue'
// 订单模块
import PayOrdersComponent from './views/order/pay_orders.vue'
import WchWalletsComponent from './views/order/wch_wallets.vue'
import WalletTransactionsComponent from './views/order/wallet_transactions.vue'
import TransferDetailsComponent from './views/order/transfer_details.vue'
import FrozenFundsComponent from './views/order/frozen_funds.vue'
// 用户模块
import UserFollowsComponent from './views/users/user_follows.vue'
import RecommendBlocksComponent from './views/users/recommend_blocks.vue'
import UserTrackingComponent from './views/users/user_tracking.vue'
// 资源模块
import ResourcesComponent from './views/statistics/resources.vue'
import NtrQuestionsComponent from './views/ntrp/ntr_questions.vue'
import NtrRecordsComponent from './views/ntrp/ntr_records.vue'
// 消息模块
import MsgNotificationsComponent from './views/message/msg_notifications.vue'
// 使用框架
Vue.use(AdminFramework, {
config,
ViewUI,
VueRouter,
Vuex,
createPersistedState,
// ✅ 组件映射表
componentMap: {
// 球局模块
'ball/games': GamesComponent,
'ball/wch_users': WchUsersComponent,
'ball/venues': VenuesComponent,
'ball/game_participants': GameParticipantsComponent,
'ball/game_comments': GameCommentsComponent,
// 订单模块
'order/pay_orders': PayOrdersComponent,
'order/wch_wallets': WchWalletsComponent,
'order/wallet_transactions': WalletTransactionsComponent,
'order/transfer_details': TransferDetailsComponent,
'order/frozen_funds': FrozenFundsComponent,
// 用户模块
'users/user_follows': UserFollowsComponent,
'users/recommend_blocks': RecommendBlocksComponent,
'users/user_tracking': UserTrackingComponent,
// 资源模块
'statistics/resources': ResourcesComponent,
'ntrp/ntr_questions': NtrQuestionsComponent,
'ntrp/ntr_records': NtrRecordsComponent,
// 消息模块
'message/msg_notifications': MsgNotificationsComponent
}
})
// 创建 Vue 实例
new Vue({
el: '#app',
router: AdminFramework.router,
store: AdminFramework.store,
render: h => h(App),
mounted() {
AdminFramework.uiTool.setRem()
// 设置权限菜单(会自动根据映射表加载组件)
this.$store.dispatch('user/setAuthorityMenus', {
Main: AdminFramework.Main,
ParentView: AdminFramework.ParentView,
Page404: AdminFramework.Page404
})
// 获取系统标题
this.$store.dispatch('app/getSysTitle', {
defaultTitle: 'Demo 管理系统',
defaultLogo: ''
})
}
})
// 响应式适配
window.addEventListener('load', AdminFramework.uiTool.setRem)
window.addEventListener('resize', AdminFramework.uiTool.setRem)
```
## 🎯 关键要点
### 1. 路径命名规则
**后端返回**
```json
{ "component": "ball/games.vue" }
```
**项目文件**
```
src/views/ball/games.vue
```
**配置映射**(不需要 .vue 后缀):
```javascript
componentMap: {
'ball/games': GamesComponent // ✅ 不需要写 .vue
}
```
**框架会自动处理**
- `ball/games`
- `ball/games.vue`
### 2. 框架内置组件
以下组件**无需配置**,框架已自动映射:
- `home/index.vue` → HomePage
- `system/sys_user.vue` → SysUser
- `system/sys_role.vue` → SysRole
- `system/sys_log.vue` → SysLog
- `system/sys_param_setup.vue` → SysParamSetup
- `system_high/sys_menu.vue` → SysMenu
- `system_high/sys_control.vue` → SysControl
- `system_high/sys_title.vue` → SysTitle
### 3. 业务组件
需要在项目中:
1. **创建组件文件**
2. **在 main.js 中导入**
3. **在 componentMap 中配置**
## ⚠️ 组件未找到的提示
如果后端返回的组件路径没有在映射表中,会显示:
```
┌────────────────────────────────────┐
│ ⚠️ 警告 │
│ 页面组件未加载: ball/games.vue │
│ 请在项目中创建此组件或在组件映射表中注册 │
└────────────────────────────────────┘
```
**控制台也会输出**
```
⚠️ 组件未找到: ball/games.vue使用占位组件
```
## 💡 快速配置技巧
### 技巧1批量导入组件
```javascript
// 按模块组织导入
// 球局模块
import GamesComponent from './views/ball/games.vue'
import WchUsersComponent from './views/ball/wch_users.vue'
// 订单模块
import PayOrdersComponent from './views/order/pay_orders.vue'
import WchWalletsComponent from './views/order/wch_wallets.vue'
```
### 技巧2使用对象展开
```javascript
// 定义模块组件映射
const ballComponents = {
'ball/games': GamesComponent,
'ball/wch_users': WchUsersComponent
}
const orderComponents = {
'order/pay_orders': PayOrdersComponent,
'order/wch_wallets': WchWalletsComponent
}
// 合并配置
Vue.use(AdminFramework, {
config,
ViewUI,
VueRouter,
Vuex,
createPersistedState,
componentMap: {
...ballComponents,
...orderComponents
}
})
```
### 技巧3注释待开发的组件
```javascript
componentMap: {
'ball/games': GamesComponent, // ✅ 已开发
// 'ball/venues': VenuesComponent, // ⏳ 待开发
// 'order/pay_orders': PayOrdersComponent // ⏳ 待开发
}
```
## 📊 配置流程图
```
后端接口返回菜单
查看所有 component 字段
在项目中创建对应的 .vue 文件
在 main.js 中导入组件
在 componentMap 中配置映射
框架自动生成路由
页面正常显示 ✅
```
## 🚀 实战示例
### 示例:添加"球局管理"页面
#### 1. 后端返回的菜单
```json
{
"id": 123,
"name": "球局表",
"path": "games",
"component": "ball/games.vue",
"type": "页面"
}
```
#### 2. 创建组件文件
```vue
<!-- src/views/ball/games.vue -->
<template>
<div class="games-page">
<h2>球局管理</h2>
<Table :columns="columns" :data="list" />
</div>
</template>
<script>
export default {
name: 'games',
data() {
return {
list: [],
columns: []
}
},
mounted() {
this.getData()
},
methods: {
async getData() {
const res = await this.$http.post('ball/games/list', {})
this.list = res.data
}
}
}
</script>
```
#### 3. 在 main.js 中配置
```javascript
// 导入
import GamesComponent from './views/ball/games.vue'
// 配置映射
Vue.use(AdminFramework, {
config,
ViewUI,
VueRouter,
Vuex,
createPersistedState,
componentMap: {
'ball/games': GamesComponent // ✅ 添加映射
}
})
```
#### 4. 完成!
登录后,权限菜单中的"球局表"会自动加载 `GamesComponent` 组件。
## 📚 框架自动处理
### 已自动映射的系统组件
| 后端路径 | 组件 | 说明 |
|---------|------|------|
| `home/index.vue` | HomePage | 主页 |
| `system/sys_user.vue` | SysUser | 用户管理 |
| `system/sys_role.vue` | SysRole | 角色管理 |
| `system/sys_log.vue` | SysLog | 日志管理 |
| `system/sys_param_setup.vue` | SysParamSetup | 参数设置 |
| `system_high/sys_menu.vue` | SysMenu | 菜单管理 |
| `system_high/sys_control.vue` | SysControl | 控制器管理 |
| `system_high/sys_title.vue` | SysTitle | 系统标题设置 |
### 需要手动配置的业务组件
根据你的权限菜单接口,需要配置:
-`ball/games.vue` - 球局表
-`ball/wch_users.vue` - 微信用户
-`ball/venues.vue` - 场地表
-`ball/game_participants.vue` - 球局参与者
-`ball/game_comments.vue` - 球局评论
-`order/pay_orders.vue` - 支付订单
-`order/wch_wallets.vue` - 用户钱包
-`order/wallet_transactions.vue` - 交易记录
-`order/transfer_details.vue` - 转账详情
-`order/frozen_funds.vue` - 冻结资金
-`users/user_follows.vue` - 用户关注
-`users/recommend_blocks.vue` - 推荐屏蔽
-`users/user_tracking.vue` - 行为追踪
-`statistics/resources.vue` - 图库资源表
-`ntrp/ntr_questions.vue` - 题库管理
-`ntrp/ntr_records.vue` - 测试记录
-`message/msg_notifications.vue` - 消息管理
-`system/wch_professions.vue` - 职业管理
-`system/wch_cities.vue` - 城市管理
-`business/hot_city_qr.vue` - 热门城市
## 🎯 推荐配置模板
```javascript
import Vue from 'vue'
import VueRouter from 'vue-router'
import Vuex from 'vuex'
import ViewUI from 'view-design'
import createPersistedState from 'vuex-persistedstate'
import 'view-design/dist/styles/iview.css'
import AdminFramework from '../../src/index.js'
import config from './config'
import App from './App.vue'
// ==================== 导入业务组件 ====================
// TODO: 根据权限菜单接口返回的 component 字段,导入对应组件
// 使用框架
Vue.use(AdminFramework, {
config,
ViewUI,
VueRouter,
Vuex,
createPersistedState,
componentMap: {
// TODO: 在这里添加业务组件映射
// 格式:'后端返回的路径(不含.vue': 导入的组件
}
})
// 创建 Vue 实例
new Vue({
el: '#app',
router: AdminFramework.router,
store: AdminFramework.store,
render: h => h(App),
mounted() {
AdminFramework.uiTool.setRem()
this.$store.dispatch('user/setAuthorityMenus', {
Main: AdminFramework.Main,
ParentView: AdminFramework.ParentView,
Page404: AdminFramework.Page404
})
this.$store.dispatch('app/getSysTitle', {
defaultTitle: config.title,
defaultLogo: ''
})
}
})
window.addEventListener('load', AdminFramework.uiTool.setRem)
window.addEventListener('resize', AdminFramework.uiTool.setRem)
```
## 📝 总结
### ✅ 优化后的优势
1. **代码简洁**
- 不需要重复写 `.vue` 后缀的映射
- 框架自动生成
2. **集中配置**
-`Vue.use()` 时一次性配置所有映射
- 清晰明了
3. **灵活扩展**
- 可以随时使用 `addComponentMap()` 添加新映射
- 支持分模块配置
### 🔗 相关文档
- [../README.md](../README.md) - 项目说明
- [../CHANGELOG.md](../CHANGELOG.md) - 更新日志
- [../../完整使用文档.md](../../完整使用文档.md) - 框架文档
---
**配置完成后,重启项目即可看到所有权限菜单中的页面!** 🎉

View File

@@ -1,326 +0,0 @@
# 权限菜单处理说明
## 📊 当前情况
### 登录接口返回的数据
```json
{
"code": 0,
"message": "请求成功",
"data": {
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"user": {
"id": 1,
"name": "zc",
"roleId": 6
},
"authorityMenus": "[1,142,121,143,144,145,124,147,120,123,125,132,133,126,136,137,138,139,151,152,153,154,149,150,156,157,158,122,159,5,11,12,13,67,68,15]"
}
}
```
### 问题分析
**登录接口返回的 `authorityMenus`**
- 类型:字符串
- 内容:菜单 ID 数组 `"[1,142,121,...]"`
- 作用:表示用户有权限访问的菜单 ID 列表
**框架期望的 `authorityMenus`**
- 类型:对象数组
- 内容:完整的菜单对象,包含以下字段:
```javascript
{
id: 1,
name: "系统管理",
path: "/system",
component: "...",
parent_id: 0,
type: "菜单",
is_show_menu: 1,
children: [...]
}
```
## 🔧 解决方案
### 方案一:调用 authorityMenus 接口(当前实现)
登录成功后,调用 `/sys_user/authorityMenus` 接口获取完整的菜单对象数组。
**流程:**
1. 用户登录 → 获取 token 和菜单 ID 列表
2. 保存 token
3. 调用 `authorityMenus` 接口 → 获取完整菜单对象数组
4. 生成路由
**代码实现:**
```javascript
// src/store/user.js
async handleLogin({ state, commit, dispatch }, { userFrom, Main, ParentView, Page404 }) {
let res = await userServerInstance.login(userFrom)
let token = res.data.token
let user = res.data.user
commit('setUserName', user.name.trim())
commit('setToken', token)
// 调用 authorityMenus 接口获取完整菜单数据
await dispatch('setAuthorityMenus', { Main, ParentView, Page404 })
}
```
**优点:**
- 简单直接
- 不需要修改后端接口
**缺点:**
- 需要额外的 HTTP 请求
- 如果 authorityMenus 接口失败,用户无法进入系统
### 方案二:后端直接返回完整菜单对象(推荐)
修改后端登录接口,直接返回完整的菜单对象数组,而不是菜单 ID 数组。
**修改后的返回数据:**
```json
{
"code": 0,
"message": "请求成功",
"data": {
"token": "...",
"user": {...},
"authorityMenus": [
{
"id": 1,
"name": "系统管理",
"path": "/system",
"component": "Main",
"parent_id": 0,
"type": "菜单",
"is_show_menu": 1,
"children": [...]
},
...
]
}
}
```
**优点:**
- 减少 HTTP 请求
- 登录更快
- 数据一致性更好
**缺点:**
- 需要修改后端代码
## 📝 当前实现
### 登录流程
1. **用户输入用户名密码**
```javascript
// src/views/login/login.vue
handleSubmit({ userName, password }) {
let userFrom = { name: userName, password: password }
this.handleLogin({ userFrom, Main, ParentView, Page404 })
}
```
2. **调用登录接口**
```javascript
// src/store/user.js
let res = await userServerInstance.login(userFrom)
// 返回: { code: 0, data: { token, user, authorityMenus: "[1,2,3...]" } }
```
3. **保存 token 和用户信息**
```javascript
commit('setUserName', user.name.trim())
commit('setToken', token)
```
4. **获取完整菜单数据**
```javascript
// 调用 /sys_user/authorityMenus 接口
await dispatch('setAuthorityMenus', { Main, ParentView, Page404 })
```
5. **处理菜单数据**
```javascript
// src/store/user.js - setAuthorityMenus
let res = await userServerInstance.authorityMenus()
// 期望返回: { code: 0, data: [{id, name, path, ...}, ...] }
let menus = res.data
commit('setAuthorityMenus', JSON.stringify(menus))
// 生成路由
let mainMenu = uiTool.getRoutes(Main, ParentView, Page404)
commit('setMenuList', mainMenu.children)
```
6. **刷新页面进入系统**
```javascript
window.location.reload()
```
## ⚠️ 需要确认的事项
### 1. authorityMenus 接口返回的数据格式
请确认 `/sys_user/authorityMenus` 接口返回的数据格式:
**期望格式:**
```json
{
"code": 0,
"message": "请求成功",
"data": [
{
"id": 1,
"name": "首页",
"path": "/home",
"component": "home/index",
"parent_id": 0,
"type": "页面",
"is_show_menu": 1,
"icon": "md-home",
"sort": 1
},
{
"id": 5,
"name": "系统管理",
"path": "/system",
"component": "",
"parent_id": 0,
"type": "菜单",
"is_show_menu": 1,
"icon": "md-settings",
"sort": 2,
"children": [
{
"id": 11,
"name": "用户管理",
"path": "/system/user",
"component": "system/sys_user",
"parent_id": 5,
"type": "页面",
"is_show_menu": 1
}
]
}
]
}
```
### 2. 菜单对象的必需字段
每个菜单对象需要包含以下字段:
| 字段 | 类型 | 说明 | 必需 |
|------|------|------|------|
| id | Number | 菜单 ID | ✅ |
| name | String | 菜单名称 | ✅ |
| path | String | 路由路径 | ✅ |
| component | String | 组件路径 | ✅ |
| parent_id | Number | 父菜单 ID0 表示顶级菜单) | ✅ |
| type | String | 类型:"菜单"、"页面"、"功能" | ✅ |
| is_show_menu | Number | 是否显示在菜单中1=显示0=隐藏) | ✅ |
| icon | String | 图标名称 | ❌ |
| sort | Number | 排序 | ❌ |
| children | Array | 子菜单 | ❌ |
## 🐛 调试方法
### 1. 查看 authorityMenus 接口返回
在浏览器控制台查看:
```javascript
// 登录成功后,查看控制台日志
获取权限菜单返回: { code: 0, data: [...] }
处理权限菜单: [...]
生成的主菜单: { path: '/', children: [...] }
```
### 2. 查看 localStorage
打开浏览器开发者工具 → Application → Local Storage
```javascript
authorityMenus: "[{\"id\":1,\"name\":\"首页\",...}]"
```
### 3. 查看网络请求
打开浏览器开发者工具 → Network
1. 查看 `/sys_user/login` 请求的响应
2. 查看 `/sys_user/authorityMenus` 请求的响应
## 🎯 测试步骤
### 1. 测试登录
```bash
# 启动项目
cd demo-project
npm run dev
# 打开浏览器
http://localhost:8080
# 输入用户名密码
用户名: zc
密码: ***
# 点击登录
```
### 2. 查看控制台日志
应该看到:
```
登录接口返回: { code: 0, data: { token, user, authorityMenus } }
登录返回的菜单 IDs: "[1,142,121,...]"
获取权限菜单返回: { code: 0, data: [...] }
处理权限菜单: [...]
生成的主菜单: { path: '/', children: [...] }
```
### 3. 验证登录成功
- ✅ 显示"登录成功!"提示
- ✅ 页面刷新
- ✅ 进入系统首页
- ✅ 左侧显示菜单
## 💡 建议
### 短期方案(当前实现)
保持现有实现,登录后调用 `authorityMenus` 接口获取完整菜单数据。
### 长期方案(推荐)
建议后端修改登录接口,直接返回完整的菜单对象数组,减少 HTTP 请求,提升用户体验。
**修改建议:**
```javascript
// 后端登录接口返回
{
"code": 0,
"message": "请求成功",
"data": {
"token": "...",
"user": {...},
"authorityMenus": [
// 完整的菜单对象数组,而不是 ID 数组字符串
{ id: 1, name: "首页", path: "/home", ... },
{ id: 5, name: "系统管理", path: "/system", children: [...] }
]
}
}
```
这样前端就可以直接使用,不需要额外的 HTTP 请求。
---
**当前状态**:登录功能正常,需要确认 `authorityMenus` 接口返回的数据格式是否正确。

View File

@@ -1,277 +0,0 @@
# 登录功能修复说明
## 🔧 修复的问题
### 问题描述
登录时出现错误:`Cannot read properties of undefined (reading 'message')`
### 根本原因
登录接口返回的数据结构与代码中期望的不一致。
## 📊 数据结构分析
### 后端返回的数据结构
```json
{
"code": 0,
"message": "请求成功",
"data": {
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"user": {
"id": 1,
"name": "zc",
"password": "d3df61764ee9a26091f714b88958caef",
"roleId": 6,
"create_time": "2022-10-24 05:45:40",
"last_modify_time": "2025-09-12 06:48:54"
},
"authorityMenus": "[1,142,121,143,144,145,124,147,120,123,125,132,133,126,136,137,138,139,151,152,153,154,149,150,156,157,158,122,159,5,11,12,13,67,68,15]"
}
}
```
### HTTP 工具类的处理流程
1. **axios 响应拦截器**`src/utils/http.js` 第 55-69 行)
```javascript
instance.interceptors.response.use(
response => {
if (response.status === 200) {
if (response.data && response.data.code === 0) {
return response // 返回整个 response 对象
} else {
// code 不为 0拒绝
return Promise.reject(response.data.message)
}
}
}
)
```
2. **http.post 方法**`src/utils/http.js` 第 176-191 行)
```javascript
async post(url, param, config) {
let instance = this.getHttpInstance(config)
let promise = new Promise((resolve, reject) => {
instance.post(url, param).then(response => {
resolve(response.data) // 返回 response.data
})
})
return promise
}
```
3. **最终在 user.js 中得到的数据结构**
```javascript
let res = await userServerInstance.login(userFrom)
// res 的结构是:
// {
// code: 0,
// message: "请求成功",
// data: { token, user, authorityMenus }
// }
```
## ✅ 修复方案
### 1. 修复 `src/store/user.js` 中的 `handleLogin` 方法
**修复前:**
```javascript
let res = await userServerInstance.login(userFrom)
let token = res.data.token // ❌ 错误res.data 是整个数据对象
let user = res.data.user
```
**修复后:**
```javascript
let res = await userServerInstance.login(userFrom)
// 检查返回数据结构
if (res.code !== 0) {
throw new Error(res.message || '登录失败')
}
// 实际数据在 res.data 中
let token = res.data.token // ✅ 正确
let user = res.data.user // ✅ 正确
let authorityMenus = res.data.authorityMenus // ✅ 正确
```
### 2. 修复 `src/store/user.js` 中的 `setAuthorityMenus` 方法
**修复前:**
```javascript
let res = await userServerInstance.authorityMenus()
let authorityMenus = res.data // ❌ 可能不正确
```
**修复后:**
```javascript
let res = await userServerInstance.authorityMenus()
// res 的结构是 { code, message, data }
if (res && res.code === 0 && res.data) {
menus = res.data // ✅ 正确获取数据
}
```
### 3. 增强错误处理
在 `src/views/login/login.vue` 中:
```javascript
async handleSubmit({ userName, password }) {
try {
let userFrom = { name: userName, password: password }
await this.handleLogin({
userFrom,
Main,
ParentView,
Page404
})
this.$Message.success('登录成功!')
window.location.reload()
} catch (error) {
console.error('登录失败:', error)
// 处理不同类型的错误
let errorMsg = '登录失败,请检查用户名和密码'
if (error) {
if (typeof error === 'string') {
errorMsg = error
} else if (error.message) {
errorMsg = error.message
} else if (error.data && error.data.message) {
errorMsg = error.data.message
}
}
this.$Message.error(errorMsg)
}
}
```
## 🎯 登录流程
### 完整的登录流程
1. **用户输入用户名和密码**
- 组件:`src/components/login-form/login-form.vue`
- 触发事件:`on-success-valid`
2. **登录页面处理**
- 组件:`src/views/login/login.vue`
- 调用:`handleLogin` action
3. **Vuex Action 处理**
- 文件:`src/store/user.js`
- 方法:`handleLogin`
- 步骤:
1. 调用登录接口
2. 保存 token 和用户名
3. 处理权限菜单
4. 生成路由
4. **HTTP 请求**
- 文件:`src/api/system/userServer.js`
- 接口:`POST /sys_user/login`
- 参数:`{ name, password }`
5. **登录成功后**
- 显示成功提示
- 刷新页面
- 自动跳转到首页
## 📝 测试步骤
### 1. 启动项目
```bash
cd demo-project
npm run dev
```
### 2. 打开浏览器
访问:`http://localhost:8080`
### 3. 输入登录信息
- 用户名:`zc`(或其他有效用户名)
- 密码:对应的密码
### 4. 查看控制台日志
应该能看到以下日志:
```
登录接口返回: { code: 0, message: "请求成功", data: {...} }
处理权限菜单: [1,142,121,...]
生成的主菜单: { path: '/', children: [...] }
✅ Demo 项目启动成功!
```
### 5. 验证登录成功
- ✅ 显示"登录成功!"提示
- ✅ 页面刷新
- ✅ 跳转到系统首页
- ✅ 显示用户名和菜单
## 🐛 调试技巧
### 查看登录请求
1. 打开浏览器开发者工具F12
2. 切换到 Network 标签
3. 输入用户名密码,点击登录
4. 查看 `/sys_user/login` 请求
5. 检查 Response 数据结构
### 查看 Vuex 状态
1. 安装 Vue DevTools 浏览器插件
2. 打开 Vue DevTools
3. 切换到 Vuex 标签
4. 查看 `user` 模块的状态:
- `token`:应该有值
- `userName`:应该是登录的用户名
- `authorityMenus`:应该是权限菜单数组
### 查看 localStorage
1. 打开浏览器开发者工具F12
2. 切换到 Application 标签
3. 展开 Local Storage
4. 查看存储的数据:
- `demo_token`token 值
- `userName`:用户名
- `authorityMenus`:权限菜单 JSON 字符串
## ⚠️ 注意事项
### 1. authorityMenus 的数据格式
后端返回的 `authorityMenus` 是一个 **字符串**
```json
"authorityMenus": "[1,142,121,143,...]"
```
代码会自动解析这个字符串为数组。
### 2. 权限菜单的处理
- 登录接口返回的 `authorityMenus` 是菜单 ID 数组
- 需要根据这些 ID 从菜单配置中生成实际的路由
- 使用 `uiTool.getRoutes()` 方法生成路由
### 3. Token 的使用
- Token 保存在 Vuex store 和 localStorage 中
- 每次 HTTP 请求都会自动带上 token在请求头 `admin-token` 中)
- Token 失效时会自动跳转到登录页
## 🎉 修复完成
现在登录功能应该可以正常工作了!
### 验证清单
- ✅ 登录接口正确调用
- ✅ Token 正确保存
- ✅ 用户信息正确保存
- ✅ 权限菜单正确处理
- ✅ 登录成功后正确跳转
- ✅ 错误处理完善
如果还有问题,请查看浏览器控制台的错误信息和网络请求详情。

View File

@@ -1,386 +0,0 @@
# 登录功能完整修复报告
## 📋 问题总结
### 1. ✅ 登录接口调用成功
- 接口返回:`{ code: 0, message: "请求成功", data: {...} }`
- Token 获取成功
- 用户信息获取成功
### 2. ⚠️ authorityMenus 接口失败
- 问题:`/sys_user/authorityMenus` 接口调用失败
- 影响:无法从后端获取完整的菜单数据
- 解决:使用默认菜单配置 + 根据 ID 过滤
### 3. ⚠️ 系统标题接口失败
- 问题:`/sys_param_setup/getOne` 接口调用失败
- 影响:无法获取自定义的系统标题和 Logo
- 解决:使用默认标题 "Demo 管理系统"
## 🔧 修复内容
### 修复 1数据结构适配
**文件**`src/store/user.js`
**问题**:登录接口返回的数据结构与代码期望不一致
**修复**
```javascript
// 修复前
let token = res.data.token // ❌ 错误
// 修复后
if (res.code !== 0) {
throw new Error(res.message)
}
let token = res.data.token // ✅ 正确
```
### 修复 2authorityMenus 接口失败降级
**文件**`src/store/user.js``src/config/menuConfig.js`
**问题**`authorityMenus` 接口失败导致无法获取菜单
**修复**
1. 创建默认菜单配置文件
2. 接口失败时使用默认菜单
3. 根据登录返回的菜单 ID 过滤菜单
```javascript
try {
let res = await userServerInstance.authorityMenus()
menus = res.data
} catch (error) {
console.warn('将使用默认菜单配置')
// 使用默认菜单 + ID 过滤
menus = filterMenusByIds(menuIds, defaultMenus)
}
```
### 修复 3系统标题接口失败处理
**文件**`src/store/app.js`
**问题**
1. 代码中有 debugger 语句
2. 接口失败时错误处理不完善
**修复**
```javascript
try {
let res1 = await paramSetupServerInstance.getOne('sys_title')
if (res1 && res1.data) {
formModel.title = res1.data.value
document.title = res1.data.value
}
} catch (error) {
console.warn('获取系统标题失败,使用默认标题')
document.title = formModel.title
}
```
## 📁 新增文件
### `src/config/menuConfig.js`
默认菜单配置文件,包含:
1. **首页** (`/home`)
2. **系统管理**
- 用户管理 (`/system/user`)
- 角色管理 (`/system/role`)
- 系统日志 (`/system/log`)
- 参数设置 (`/system/param`)
3. **高级管理**
- 菜单管理 (`/system_high/menu`)
- 控制管理 (`/system_high/control`)
- 系统标题 (`/system_high/title`)
## 🎯 当前状态
### ✅ 正常工作的功能
1. **用户登录**
- ✅ 调用登录接口
- ✅ 保存 token
- ✅ 保存用户信息
- ✅ 登录成功提示
2. **菜单显示**
- ✅ 使用默认菜单配置
- ✅ 根据权限 ID 过滤菜单
- ✅ 生成路由
- ✅ 左侧菜单栏显示
3. **页面跳转**
- ✅ 登录后跳转到首页
- ✅ 可以访问有权限的页面
- ✅ 路由正常工作
4. **系统标题**
- ✅ 使用默认标题 "Demo 管理系统"
- ✅ 页面标题正常显示
### ⚠️ 降级处理的功能
1. **权限菜单**
- 后端接口失败
- 使用默认菜单配置
- 根据 ID 过滤
2. **系统标题**
- 后端接口失败
- 使用默认标题
## 🔍 控制台日志
### 正常的日志输出
```
✅ Demo 项目启动成功!
框架版本: 1.0.0
App 组件已挂载
登录接口返回: { code: 0, data: { token, user, authorityMenus } }
登录返回的菜单 IDs: "[1,142,121,143,144,145,124,147,120,123,125,...]"
获取权限菜单失败: undefined
将使用默认菜单配置
根据菜单 IDs 过滤后的菜单: [...]
最终处理的权限菜单: [...]
生成的主菜单: { path: '/', children: [...] }
获取系统标题失败,使用默认标题: 接口调用失败
```
### 说明
- `获取权限菜单失败: undefined` - 这是正常的,因为后端接口不可用
- `获取系统标题失败,使用默认标题` - 这是正常的,因为后端接口不可用
- 这些都是**警告信息**,不影响系统正常使用
## 📊 登录流程图
```
用户输入用户名密码
点击登录按钮
调用 /sys_user/login 接口
返回: { code: 0, data: { token, user, authorityMenus: "[1,2,3...]" } }
保存 token 和用户信息
解析 authorityMenus 字符串 → 数组
尝试调用 /sys_user/authorityMenus 接口
接口失败 ❌
使用默认菜单配置
根据菜单 ID 数组过滤菜单
生成路由
保存到 Vuex store
显示"登录成功!"提示
刷新页面
进入系统首页 ✅
显示左侧菜单栏
```
## 🎉 测试结果
### 测试步骤
1. **启动项目**
```bash
cd demo-project
npm run dev
```
2. **访问登录页**
- URL: `http://localhost:8080`
3. **输入登录信息**
- 用户名:`zc`
- 密码:对应的密码
4. **点击登录**
### 预期结果
- ✅ 显示"登录成功!"提示
- ✅ 页面刷新
- ✅ 进入系统首页
- ✅ 左侧显示菜单栏
- ✅ 顶部显示用户名 "zc"
- ✅ 页面标题显示 "Demo 管理系统"
### 实际结果
**全部通过!** ✅
## 💡 后续优化建议
### 短期方案(当前实现)
✅ **已完成**
- 使用默认菜单配置
- 根据权限 ID 过滤菜单
- 使用默认系统标题
- 完善错误处理
### 长期方案(推荐)
🎯 **建议后端修复以下接口**
#### 1. `/sys_user/authorityMenus` 接口
**期望返回格式**
```json
{
"code": 0,
"message": "请求成功",
"data": [
{
"id": 1,
"name": "首页",
"path": "/home",
"component": "home/index",
"parent_id": 0,
"type": "页面",
"is_show_menu": 1,
"icon": "md-home",
"sort": 1
},
{
"id": 5,
"name": "系统管理",
"path": "/system",
"component": "",
"parent_id": 0,
"type": "菜单",
"is_show_menu": 1,
"icon": "md-settings",
"sort": 2,
"children": [
{
"id": 11,
"name": "用户管理",
"path": "/system/user",
"component": "system/sys_user",
"parent_id": 5,
"type": "页面",
"is_show_menu": 1
}
]
}
]
}
```
#### 2. `/sys_param_setup/getOne` 接口
**期望返回格式**
```json
{
"code": 0,
"message": "请求成功",
"data": {
"key": "sys_title",
"value": "我的管理系统"
}
}
```
### 扩展默认菜单
如果需要添加更多业务菜单,编辑 `src/config/menuConfig.js`
```javascript
export const defaultMenus = [
// ... 现有菜单
{
id: 200,
name: '业务管理',
path: '/business',
component: '',
parent_id: 0,
type: '菜单',
is_show_menu: 1,
icon: 'md-briefcase',
sort: 4,
children: [
{
id: 201,
name: '订单管理',
path: '/business/order',
component: 'business/order',
parent_id: 200,
type: '页面',
is_show_menu: 1,
icon: 'md-cart',
sort: 1
},
{
id: 202,
name: '产品管理',
path: '/business/product',
component: 'business/product_list',
parent_id: 200,
type: '页面',
is_show_menu: 1,
icon: 'md-cube',
sort: 2
}
]
}
]
```
## 📝 相关文档
1. **登录功能修复说明.md** - 登录数据结构修复详情
2. **权限菜单说明.md** - 权限菜单处理流程
3. **authorityMenus接口失败解决方案.md** - 接口失败降级方案
## ✅ 总结
### 修复完成的问题
1. ✅ 登录接口数据结构适配
2. ✅ authorityMenus 接口失败降级处理
3. ✅ 系统标题接口失败降级处理
4. ✅ 错误处理完善
5. ✅ 调试代码清理debugger
### 当前系统状态
**完全可用!** 🎉
- ✅ 登录功能正常
- ✅ 菜单显示正常
- ✅ 路由跳转正常
- ✅ 权限控制正常
- ✅ 用户体验良好
### 已知限制
1. **菜单数据来源**:使用默认配置,不是从后端动态获取
2. **系统标题**:使用默认标题,不是从后端获取
3. **菜单扩展**:需要手动编辑配置文件
这些限制不影响系统的核心功能,可以正常使用。
---
**🎉 恭喜!你的 Demo 项目已经可以完美运行了!**
如果需要添加更多功能或修复其他问题,请随时告诉我。

View File

@@ -1,412 +0,0 @@
# 登录跳转首页修复说明
## 🎯 需求
1. 登录成功后自动跳转到首页
2. 访问 `/` 时自动重定向到 `/home`
## 📋 问题分析
### 原来的问题
**登录流程**
```
用户登录
调用 handleLogin
保存 token 和 authorityMenus
显示"登录成功!"
window.location.reload() ← ❌ 刷新当前页面(/login
停留在登录页面 ❌
```
**问题**
- 登录成功后刷新了登录页面
- 虽然路由守卫会检测到 token 并重定向到首页
- 但是刷新操作会导致页面停留在 `/login`
### 路由守卫逻辑
`src/router/index.js` 中的路由守卫:
```javascript
router.beforeEach((to, from, next) => {
const token = getToken()
if (!token && to.name !== 'login') {
// 未登录且访问非登录页 → 跳转到登录页
next({ name: 'login' })
} else if (!token && to.name === 'login') {
// 未登录且访问登录页 → 允许访问
next()
} else if (token && to.name === 'login') {
// 已登录且访问登录页 → 重定向到首页
next({ name: homeName }) // homeName = 'home'
} else {
// 其他情况 → 允许访问
next()
}
})
```
**说明**
- 如果已登录(有 token且访问登录页会重定向到首页
- 但是 `window.location.reload()` 会刷新当前页面,不会触发路由跳转
### 主路由重定向配置
`src/utils/uiTool.js` 中的主路由配置:
```javascript
let mainRoute = {
path: '/',
name: '主视图',
redirect: '/home', // ← 访问 / 时重定向到 /home
component: Main,
children: []
}
```
**说明**
- 访问 `/` 时会自动重定向到 `/home`
- 前提是 `/home` 路由存在(从后端权限菜单生成)
## ✅ 解决方案
### 修改登录成功后的跳转逻辑
**修改文件**`src/views/login/login.vue`
**修改前**
```javascript
async handleSubmit({ userName, password }) {
try {
let userFrom = { name: userName, password: password }
await this.handleLogin({
userFrom,
Main,
ParentView,
Page404
})
this.$Message.success('登录成功!')
window.location.reload() // ❌ 刷新当前页面(/login
} catch (error) {
// 错误处理
}
}
```
**修改后**
```javascript
async handleSubmit({ userName, password }) {
try {
let userFrom = { name: userName, password: password }
await this.handleLogin({
userFrom,
Main,
ParentView,
Page404
})
this.$Message.success('登录成功!')
// ✅ 跳转到首页(使用 location.href 触发完整页面加载)
setTimeout(() => {
window.location.href = window.location.origin + window.location.pathname + '#/'
}, 500)
} catch (error) {
// 错误处理
}
}
```
**改进点**
- ✅ 使用 `window.location.href` 跳转到 `#/`
- ✅ 触发完整的页面加载
- ✅ 路由会重定向到 `/home`
- ✅ 延迟 500ms 确保提示信息显示
## 📊 新的登录流程
### 完整流程
```
用户输入用户名密码
点击登录
调用 handleLogin action
调用登录接口
保存 token 到 localStorage
保存用户信息到 Vuex
调用 setAuthorityMenus
├─ 尝试获取权限菜单
├─ 如果失败,使用默认菜单
└─ 保存到 localStorage.authorityMenus
显示"登录成功!"提示
延迟 500ms
跳转到 #/ (window.location.href)
触发完整页面加载
框架初始化
从 localStorage 读取 authorityMenus
生成路由(包括首页)
访问 / 路由
重定向到 /home ✅
显示首页 ✅
```
### 路由重定向流程
```
访问 #/
匹配主路由 { path: '/', redirect: '/home' }
重定向到 /home
匹配首页路由 { path: '/home', component: HomePage }
显示首页组件 ✅
```
### 已登录用户访问登录页
```
已登录用户访问 #/login
路由守卫检测到 token
检测到访问登录页
重定向到首页 next({ name: 'home' })
显示首页 ✅
```
## 🎯 关键点说明
### 1. 为什么使用 `window.location.href` 而不是 `this.$router.push`
**`this.$router.push({ path: '/' })`**
- 只是客户端路由跳转
- 不会重新加载页面
- 不会重新初始化框架
- 不会重新从 localStorage 读取 authorityMenus
**`window.location.href = '#/'`**
- 触发完整的页面加载
- 重新初始化框架
- 重新从 localStorage 读取 authorityMenus
- 重新生成路由
- 确保路由和菜单正确加载
### 2. 为什么延迟 500ms
```javascript
setTimeout(() => {
window.location.href = window.location.origin + window.location.pathname + '#/'
}, 500)
```
**原因**
- 让"登录成功!"提示信息有时间显示
- 给用户更好的体验
- 确保 localStorage 写入完成
### 3. URL 构造说明
```javascript
window.location.origin + window.location.pathname + '#/'
```
**示例**
- `window.location.origin` = `http://localhost:8080`
- `window.location.pathname` = `/``/demo-project/`
- 最终 URL = `http://localhost:8080/#/``http://localhost:8080/demo-project/#/`
**为什么这样构造**
- 兼容不同的部署路径
- 确保 hash 路由正确
- 避免硬编码 URL
### 4. 主路由的 redirect 配置
```javascript
let mainRoute = {
path: '/',
redirect: '/home',
component: Main,
children: [
{ path: '/home', name: 'home', component: HomePage },
// ... 其他路由
]
}
```
**工作原理**
- 访问 `/` 时,自动重定向到 `/home`
- `/home` 路由由后端权限菜单生成
- 如果后端没有返回首页配置,会使用默认菜单配置
## ✅ 验证清单
### 登录流程验证
- ✅ 访问登录页面
- ✅ 输入用户名密码
- ✅ 点击登录
- ✅ 显示"登录成功!"提示
- ✅ 自动跳转到首页
- ✅ 首页正确显示
- ✅ 菜单正确显示
### 路由重定向验证
- ✅ 登录后访问 `#/` 自动重定向到 `#/home`
- ✅ 已登录状态访问 `#/login` 自动重定向到 `#/home`
- ✅ 未登录状态访问 `#/home` 自动重定向到 `#/login`
### 刷新页面验证
- ✅ 登录后刷新页面,停留在当前页面
- ✅ 菜单和路由保持正确
- ✅ 用户信息保持正确
## 🔧 相关配置
### 路由守卫配置
**文件**`src/router/index.js`
```javascript
export const setupRouterGuards = (router, ViewUI, homeName = 'home') => {
router.beforeEach((to, from, next) => {
const token = getToken()
ViewUI.LoadingBar.start()
if (!token && to.name !== 'login') {
// 未登录 → 跳转到登录页
next({ name: 'login' })
} else if (!token && to.name === 'login') {
// 未登录访问登录页 → 允许
next()
} else if (token && to.name === 'login') {
// 已登录访问登录页 → 重定向到首页
next({ name: homeName })
} else {
// 其他情况 → 允许
next()
}
})
router.afterEach(to => {
ViewUI.LoadingBar.finish()
window.scrollTo(0, 0)
})
return router
}
```
### 主路由配置
**文件**`src/utils/uiTool.js`
```javascript
static getRoutes(Main, ParentView, Page404) {
let mainRoute = {
path: '/',
name: '主视图',
redirect: '/home',
component: Main,
meta: { title: '首页', notCache: true },
children: []
}
// 从 localStorage 读取权限菜单
if (localStorage.authorityMenus && localStorage.authorityMenus !== 'undefined') {
let authorityMenus = JSON.parse(localStorage.authorityMenus) || []
if (authorityMenus && authorityMenus.length > 0) {
let menus = uiTool.transformTree(authorityMenus)
let curRoutes = uiTool.menuToRoute(menus, ParentView, Page404)
// 使用后端返回的路由(包括首页)
mainRoute.children = curRoutes
}
}
return mainRoute
}
```
## 💡 最佳实践
### 1. 登录后的跳转
**推荐**
```javascript
// 使用 location.href 触发完整页面加载
window.location.href = window.location.origin + window.location.pathname + '#/'
```
**不推荐**
```javascript
// 只刷新当前页面,不跳转
window.location.reload()
// 客户端路由跳转,不重新加载
this.$router.push({ path: '/' })
```
### 2. 路由守卫
**推荐**
- 在路由守卫中统一处理登录状态检查
- 已登录访问登录页时自动重定向到首页
- 未登录访问受保护页面时自动重定向到登录页
### 3. 主路由配置
**推荐**
- 设置 `redirect: '/home'` 确保访问 `/` 时重定向到首页
- 从后端权限菜单生成路由
- 提供默认菜单配置作为降级方案
## 📝 总结
### 修改内容
- ✅ 修改了登录成功后的跳转逻辑
- ✅ 使用 `window.location.href` 跳转到首页
- ✅ 触发完整页面加载
- ✅ 确保路由和菜单正确初始化
### 效果
- ✅ 登录成功后自动跳转到首页
- ✅ 访问 `/` 自动重定向到 `/home`
- ✅ 已登录访问登录页自动重定向到首页
- ✅ 用户体验更流畅
---
**登录跳转首页功能已完成!** 🎉
现在登录成功后会自动跳转到首页,访问 `/` 也会正确重定向到 `/home`

View File

@@ -1,452 +0,0 @@
# 移除硬编码首页说明
## 🎯 修改目标
移除代码中硬编码的首页路由,完全依赖后端接口返回的菜单配置(包括首页)。
## 📋 修改原因
### 之前的问题
**硬编码首页**
```javascript
// 在代码中创建默认首页
const defaultHomeRoute = {
path: '/home',
name: 'home',
meta: { title: '首页', notCache: true },
component: HomePage
}
```
**问题**
- ❌ 首页配置写死在代码中
- ❌ 无法通过后端动态配置首页
- ❌ 首页和其他菜单的处理逻辑不一致
- ❌ 增加了代码复杂度
### 新的设计
**完全依赖后端**
- ✅ 首页配置由后端返回
- ✅ 首页和其他菜单统一处理
- ✅ 代码更简洁
- ✅ 配置更灵活
## 📝 修改内容
### 1. 修改 `src/utils/uiTool.js` 的 `getRoutes` 方法
**修改前**
```javascript
static getRoutes(Main, ParentView, Page404, HomePage) {
// 创建默认的首页路由
const defaultHomeRoute = {
path: '/home',
name: 'home',
meta: { title: '首页', notCache: true },
component: HomePage || {
render: h => h('div', { style: { padding: '20px' } }, '欢迎使用管理系统')
}
}
let mainRoute = {
path: '/',
name: '主视图',
redirect: '/home',
component: Main,
meta: { title: '首页', notCache: true },
children: [defaultHomeRoute] // ❌ 硬编码首页
}
// 从 localStorage 读取权限菜单
if (localStorage.authorityMenus && localStorage.authorityMenus !== 'undefined') {
let authorityMenus = JSON.parse(localStorage.authorityMenus) || []
if (authorityMenus && authorityMenus.length > 0) {
let menus = uiTool.transformTree(authorityMenus)
let curRoutes = uiTool.menuToRoute(menus, ParentView, Page404)
// 检查权限路由中是否有 home
const hasHome = curRoutes.some(r => r.name === 'home')
if (hasHome) {
mainRoute.children = curRoutes
} else {
mainRoute.children = [defaultHomeRoute, ...curRoutes] // ❌ 复杂的合并逻辑
}
}
}
return mainRoute
}
```
**修改后**
```javascript
static getRoutes(Main, ParentView, Page404) {
let mainRoute = {
path: '/',
name: '主视图',
redirect: '/home',
component: Main,
meta: { title: '首页', notCache: true },
children: [] // ✅ 初始为空
}
// 从 localStorage 读取权限菜单
if (localStorage.authorityMenus && localStorage.authorityMenus !== 'undefined') {
let authorityMenus = JSON.parse(localStorage.authorityMenus) || []
if (authorityMenus && authorityMenus.length > 0) {
let menus = uiTool.transformTree(authorityMenus)
let curRoutes = uiTool.menuToRoute(menus, ParentView, Page404)
// ✅ 直接使用后端返回的路由(包括首页)
mainRoute.children = curRoutes
}
}
return mainRoute
}
```
**改进点**
- ✅ 移除了 `HomePage` 参数
- ✅ 移除了 `defaultHomeRoute` 的创建
- ✅ 移除了复杂的首页合并逻辑
- ✅ 代码更简洁,逻辑更清晰
### 2. 更新 `src/index.js` 中的调用
**修改前**
```javascript
// 获取主路由配置(包含 home
const mainRoute = this.getRoutes({ Main, ParentView, Page404, HomePage })
// getRoutes 方法
getRoutes(components = {}) {
const { Main, ParentView, Page404, HomePage } = components
if (!Main || !ParentView || !Page404) {
console.error('Missing required layout components')
return null
}
return uiTool.getRoutes(Main, ParentView, Page404, HomePage)
}
```
**修改后**
```javascript
// 获取主路由配置(从后端权限菜单生成)
const mainRoute = this.getRoutes({ Main, ParentView, Page404 })
// getRoutes 方法
getRoutes(components = {}) {
const { Main, ParentView, Page404 } = components
if (!Main || !ParentView || !Page404) {
console.error('Missing required layout components')
return null
}
return uiTool.getRoutes(Main, ParentView, Page404)
}
```
**改进点**
- ✅ 移除了 `HomePage` 参数
- ✅ 注释更准确
### 3. 确保默认菜单配置包含首页
**`src/config/menuConfig.js`**
```javascript
export const defaultMenus = [
{
id: 1,
name: '首页',
path: '/home',
component: 'home/index',
parent_id: 0,
type: '页面',
is_show_menu: 1,
icon: 'md-home',
sort: 1
},
// ... 其他菜单
]
```
**说明**
- ✅ 默认菜单配置中包含首页id: 1
- ✅ 当 `authorityMenus` 接口失败时,会使用这个默认配置
- ✅ 确保即使接口失败,也能显示首页
## 📊 新的路由生成流程
### 应用启动时
```
应用启动
框架初始化
调用 getRoutes
从 localStorage 读取 authorityMenus
authorityMenus 存在?
├─ 是 → 解析菜单数据
│ ↓
│ transformTree (构建树形结构)
│ ↓
│ menuToRoute (转换为路由配置)
│ ↓
│ 生成路由(包括首页)✅
└─ 否 → children = [] (空路由)
显示登录页面
```
### 登录后
```
用户登录
调用登录接口
保存 token 和用户信息
调用 setAuthorityMenus
├─ 尝试调用 authorityMenus 接口
│ ├─ 成功 → 使用后端返回的菜单(包括首页)
│ └─ 失败 → 使用默认菜单配置(包括首页)
保存到 localStorage
刷新页面
重新执行应用启动流程
从 localStorage 读取菜单
生成路由(包括首页)✅
```
## 🎯 后端接口要求
### authorityMenus 接口返回格式
**必须包含首页配置**
```json
{
"code": 0,
"message": "请求成功",
"data": [
{
"id": 1,
"name": "首页",
"path": "/home",
"component": "home/index",
"parent_id": 0,
"type": "页面",
"is_show_menu": 1,
"icon": "md-home",
"sort": 1
},
{
"id": 5,
"name": "系统管理",
"path": "/system",
"component": "",
"parent_id": 0,
"type": "菜单",
"is_show_menu": 1,
"icon": "md-settings",
"sort": 2,
"children": [
{
"id": 11,
"name": "用户管理",
"path": "/system/user",
"component": "system/sys_user",
"parent_id": 5,
"type": "页面",
"is_show_menu": 1
}
]
}
]
}
```
### 首页配置说明
**必需字段**
- `id`: 菜单 ID建议使用 1
- `name`: 菜单名称(如 "首页"
- `path`: 路由路径(必须是 `/home`
- `component`: 组件路径(如 `home/index`
- `parent_id`: 父菜单 ID0 表示顶级菜单)
- `type`: 类型("页面"
- `is_show_menu`: 是否显示在菜单中1=显示0=隐藏)
**可选字段**
- `icon`: 图标名称(如 `md-home`
- `sort`: 排序(建议设为 1让首页排在第一位
## ✅ 优势
### 1. 代码更简洁
**代码行数减少**
- 移除了 `defaultHomeRoute` 的创建
- 移除了首页合并逻辑
- 移除了 `HomePage` 参数传递
**复杂度降低**
- 不需要判断是否有首页
- 不需要合并首页和其他路由
- 逻辑更直观
### 2. 配置更灵活
**后端控制**
- ✅ 首页路径可以动态配置
- ✅ 首页组件可以动态指定
- ✅ 首页标题可以动态设置
- ✅ 首页图标可以动态配置
**统一管理**
- ✅ 所有菜单(包括首页)都由后端管理
- ✅ 权限控制统一
- ✅ 配置方式统一
### 3. 维护更容易
**单一数据源**
- ✅ 菜单配置只来自后端
- ✅ 不需要维护前端的默认首页
- ✅ 修改首页只需要修改后端配置
**降级方案**
- ✅ 如果 `authorityMenus` 接口失败
- ✅ 使用 `defaultMenus` 配置(包含首页)
- ✅ 确保系统可用
## ⚠️ 注意事项
### 1. 后端必须返回首页配置
如果后端返回的菜单数据中没有首页,用户登录后会看不到首页。
**解决方案**
- 确保后端 `authorityMenus` 接口返回包含首页的菜单数据
- 或者在 `defaultMenus` 中包含首页作为兜底
### 2. 首页路径必须是 `/home`
因为主路由的 `redirect` 设置为 `/home`
```javascript
let mainRoute = {
path: '/',
redirect: '/home', // ← 重定向到 /home
// ...
}
```
**要求**
- 后端返回的首页配置中,`path` 必须是 `/home`
- 或者修改主路由的 `redirect` 配置
### 3. 组件路径映射
后端返回的 `component` 字段(如 `home/index`)会被映射到:
```
src/views/home/index.vue
```
**要求**
- 确保组件文件存在
- 组件路径正确
## 🧪 测试验证
### 测试场景 1正常登录
```
1. 启动项目
2. 访问登录页面
3. 输入用户名密码
4. 点击登录
5. 登录成功
6. 页面刷新
7. 进入系统首页 ✅
```
**验证点**
- ✅ 首页正确显示
- ✅ 首页路由是 `/home`
- ✅ 首页组件正确加载
### 测试场景 2authorityMenus 接口失败
```
1. 启动项目
2. 登录authorityMenus 接口失败)
3. 使用默认菜单配置
4. 页面刷新
5. 进入系统首页 ✅
```
**验证点**
- ✅ 使用默认菜单配置
- ✅ 首页正确显示
- ✅ 控制台有警告信息
### 测试场景 3刷新页面
```
1. 已登录状态
2. 刷新页面
3. 从 localStorage 读取菜单
4. 重新生成路由
5. 首页正确显示 ✅
```
**验证点**
- ✅ 首页路由正确
- ✅ 菜单正确显示
- ✅ 用户状态保持
## 📝 总结
### 修改内容
- ✅ 移除了硬编码的首页路由
- ✅ 移除了 `HomePage` 参数
- ✅ 简化了路由生成逻辑
- ✅ 统一了菜单处理方式
### 优势
- ✅ 代码更简洁(减少约 20 行代码)
- ✅ 逻辑更清晰
- ✅ 配置更灵活
- ✅ 维护更容易
### 要求
- ⚠️ 后端必须返回首页配置
- ⚠️ 首页路径必须是 `/home`
- ⚠️ 组件文件必须存在
---
**硬编码首页已移除!** 🎉
现在首页完全由后端配置控制,代码更简洁、更灵活。

View File

@@ -1,233 +0,0 @@
# 组件映射修复总结
## ✅ 问题解决
### 问题:所有页面都显示 404
**原因**
1. 权限菜单接口返回的组件路径(如 `ball/games.vue`)没有映射到实际组件
2. 之前的代码将所有未知组件都设置为 `Page404`
### 解决方案
创建了完整的组件映射机制:
- ✅ 框架自动映射系统组件
- ✅ 支持用户配置业务组件映射
- ✅ 自动处理带和不带 `.vue` 后缀的路径
- ✅ 未映射组件显示友好提示
## 🔧 核心修改
### 1. `src/utils/uiTool.js`
#### 添加组件映射功能
```javascript
// 组件映射表
const componentMap = {}
// 设置组件映射
static setComponentMap(map) {
Object.assign(componentMap, map)
}
// 获取组件
static getComponent(componentPath) {
const normalizedPath = componentPath.replace(/\.vue$/, '')
return componentMap[normalizedPath] || componentMap[componentPath]
}
```
#### 优化 menuToRoute 方法
```javascript
static menuToRoute(menus, ParentView, Page404) {
menus.forEach(item => {
if (item.type === '页面') {
// 从映射表获取组件
let component = uiTool.getComponent(item.component)
if (component) {
item.component = component // ✅ 使用映射的组件
} else {
// 显示友好提示
console.warn(`组件未找到: ${item.component}`)
item.component = PlaceholderComponent
}
}
})
}
```
### 2. `src/index.js`
#### 添加 setupComponentMap 方法
```javascript
setupComponentMap(customMap = {}) {
// 框架内置组件
const components = {
'home/index': HomePage,
'system/sys_log': SysLog,
'system/sys_param_setup': SysParamSetup,
'system/sys_role': SysRole,
'system/sys_user': SysUser,
'system_high/sys_control': SysControl,
'system_high/sys_menu': SysMenu,
'system_high/sys_title': SysTitle,
// 合并用户传入的业务组件
...customMap
}
// 自动生成带 .vue 和不带 .vue 的映射
const map = {}
Object.keys(components).forEach(path => {
const cleanPath = path.replace(/\.vue$/, '')
map[cleanPath] = components[path]
map[cleanPath + '.vue'] = components[path]
})
uiTool.setComponentMap(map)
}
```
#### 支持在 install 时传入 componentMap
```javascript
install(Vue, options = {}) {
const { config, ViewUI, VueRouter, Vuex, createPersistedState, componentMap } = options
// 设置组件映射(包含用户传入的映射)
this.setupComponentMap(componentMap)
// ...
}
```
#### 添加 addComponentMap 方法
```javascript
addComponentMap(customMap) {
uiTool.setComponentMap(customMap)
}
```
## 📊 代码优化
### 优化前(重复代码多)
```javascript
const map = {
'system/sys_user.vue': SysUser,
'system/sys_user': SysUser, // ← 重复
'system/sys_role.vue': SysRole,
'system/sys_role': SysRole, // ← 重复
// ...每个组件都写两遍
}
```
### 优化后(自动生成)
```javascript
const components = {
'system/sys_user': SysUser,
'system/sys_role': SysRole
}
// 自动生成带 .vue 的映射
Object.keys(components).forEach(path => {
map[path] = components[path]
map[path + '.vue'] = components[path]
})
```
**代码量减少 50%**
## 🚀 使用方法
### 方法一:在 Vue.use 时配置(推荐)
```javascript
import GamesComponent from './views/ball/games.vue'
Vue.use(AdminFramework, {
config,
ViewUI,
VueRouter,
Vuex,
createPersistedState,
componentMap: {
'ball/games': GamesComponent
}
})
```
### 方法二:使用 addComponentMap
```javascript
Vue.use(AdminFramework, { config, ViewUI, VueRouter, Vuex, createPersistedState })
AdminFramework.addComponentMap({
'ball/games': GamesComponent
})
```
## 📝 配置清单
根据你的权限菜单接口,需要配置的业务组件:
### 球局模块
- [ ] `ball/games.vue` - 球局表
- [ ] `ball/wch_users.vue` - 微信用户
- [ ] `ball/venues.vue` - 场地表
- [ ] `ball/game_participants.vue` - 球局参与者
- [ ] `ball/game_comments.vue` - 球局评论
### 订单模块
- [ ] `order/pay_orders.vue` - 支付订单
- [ ] `order/wch_wallets.vue` - 用户钱包
- [ ] `order/wallet_transactions.vue` - 交易记录
- [ ] `order/transfer_details.vue` - 转账详情
- [ ] `order/frozen_funds.vue` - 冻结资金
### 用户模块
- [ ] `users/user_follows.vue` - 用户关注
- [ ] `users/recommend_blocks.vue` - 推荐屏蔽
- [ ] `users/user_tracking.vue` - 行为追踪
### 资源模块
- [ ] `statistics/resources.vue` - 图库资源表
- [ ] `ntrp/ntr_questions.vue` - 题库管理
- [ ] `ntrp/ntr_records.vue` - 测试记录
### 其他
- [ ] `message/msg_notifications.vue` - 消息管理
- [ ] `system/wch_professions.vue` - 职业管理
- [ ] `system/wch_cities.vue` - 城市管理
- [ ] `business/hot_city_qr.vue` - 热门城市
## 🎯 已自动映射(无需配置)
-`home/index.vue` - 主页
-`system/sys_user.vue` - 系统用户
-`system/sys_role.vue` - 角色管理
-`system/sys_log.vue` - 日志管理
-`system/sys_param_setup.vue` - 参数设置
-`system_high/sys_menu.vue` - 菜单管理
-`system_high/sys_control.vue` - 控制器管理
-`system_high/sys_title.vue` - 系统标题设置
## 📚 相关文档
- [快速配置组件映射.md](./快速配置组件映射.md) - 快速指南
- [权限菜单组件配置指南.md](./权限菜单组件配置指南.md) - 详细教程
- [../README.md](../README.md) - 项目说明
- [../../完整使用文档.md](../../完整使用文档.md) - 框架文档
---
**修复时间**: 2025-10-08
**修复人员**: light
**现在配置完 componentMap所有菜单页面都能正常显示了** 🎉

View File

@@ -1,339 +0,0 @@
# 组件映射机制说明
## 🎯 问题原因
之前所有页面都显示 404 是因为:
- 后端返回的权限菜单包含组件路径(如 `"component": "system/sys_user.vue"`
- 但框架没有将这些路径映射到实际组件
- 所有页面都被设置为 `Page404` 组件
## ✅ 解决方案
### 1. 框架内置组件映射
框架现在自动映射以下系统页面:
```javascript
// 框架自动映射的组件
{
'home/index': HomePage, // 主页
'system/sys_log': SysLog, // 日志管理
'system/sys_param_setup': SysParamSetup, // 参数设置
'system/sys_role': SysRole, // 角色管理
'system/sys_user': SysUser, // 用户管理
'system_high/sys_control': SysControl, // 控制器管理
'system_high/sys_menu': SysMenu, // 菜单管理
'system_high/sys_title': SysTitle // 系统标题设置
}
```
**自动支持**
-`home/index``home/index.vue` 都能识别
-`system/sys_user``system/sys_user.vue` 都能识别
### 2. 添加自定义业务组件
在项目的 `main.js` 中添加自定义组件映射:
```javascript
import ProductList from './views/business/product_list.vue'
import GamesComponent from './views/ball/games.vue'
import PayOrdersComponent from './views/order/pay_orders.vue'
// 使用框架
Vue.use(AdminFramework, { config, ViewUI, VueRouter, Vuex, createPersistedState })
// 添加自定义组件映射
AdminFramework.addComponentMap({
'business/product_list.vue': ProductList,
'ball/games.vue': GamesComponent,
'order/pay_orders.vue': PayOrdersComponent
})
```
**说明**
- 只需要添加 `.vue` 后缀的映射
- 框架会自动处理不带后缀的路径
### 3. 权限菜单格式
后端返回的菜单格式:
```json
{
"code": 0,
"data": [
{
"id": 1,
"name": "首页",
"path": "home",
"component": "home/index.vue", HomePage
"type": "页面"
},
{
"id": 11,
"name": "系统用户",
"path": "sys_user",
"component": "system/sys_user.vue", SysUser
"type": "页面"
},
{
"id": 123,
"name": "球局表",
"path": "games",
"component": "ball/games.vue",
"type": "页面"
}
]
}
```
## 🔧 完整示例
### demo-project/src/main.js
```javascript
import Vue from 'vue'
import VueRouter from 'vue-router'
import Vuex from 'vuex'
import ViewUI from 'view-design'
import createPersistedState from 'vuex-persistedstate'
import 'view-design/dist/styles/iview.css'
import AdminFramework from '../../src/index.js'
import config from './config'
import App from './App.vue'
// 引入业务组件
import ProductList from './views/business/product_list.vue'
// import GamesComponent from './views/ball/games.vue'
// import PayOrdersComponent from './views/order/pay_orders.vue'
// 使用框架
Vue.use(AdminFramework, {
config,
ViewUI,
VueRouter,
Vuex,
createPersistedState
})
// 添加业务组件映射
AdminFramework.addComponentMap({
'business/product_list.vue': ProductList
// 'ball/games.vue': GamesComponent,
// 'order/pay_orders.vue': PayOrdersComponent
})
// 创建 Vue 实例
new Vue({
el: '#app',
router: AdminFramework.router,
store: AdminFramework.store,
render: h => h(App),
mounted() {
AdminFramework.uiTool.setRem()
// 设置权限菜单(会自动根据映射表加载组件)
this.$store.dispatch('user/setAuthorityMenus', {
Main: AdminFramework.Main,
ParentView: AdminFramework.ParentView,
Page404: AdminFramework.Page404
})
}
})
```
## 📋 映射机制
### 1. 框架自动映射
框架在 `install` 时自动映射系统组件:
```javascript
Vue.use(AdminFramework, { ... })
// ↓ 自动执行
setupComponentMap()
// ↓ 映射系统页面
{
'home/index': HomePage,
'home/index.vue': HomePage,
'system/sys_user': SysUser,
'system/sys_user.vue': SysUser,
// ...
}
```
### 2. 用户添加映射
用户可以添加自定义业务组件映射:
```javascript
AdminFramework.addComponentMap({
'ball/games.vue': GamesComponent
})
// ↓ 添加到映射表
{
...已有映射,
'ball/games.vue': GamesComponent
}
```
### 3. 路由生成
当调用 `setAuthorityMenus` 时:
```javascript
// 后端返回菜单
[
{ component: "system/sys_user.vue", ... }
]
// ↓ menuToRoute 处理
// ↓ 从映射表获取组件
component: SysUser // ✅ 找到对应组件
```
## ⚠️ 未找到组件的处理
如果后端返回的组件路径在映射表中不存在:
```javascript
// 显示占位组件
component: {
render: h => h('div', [
h('Alert', { type: 'warning' }, [
h('p', '页面组件未加载: ball/games.vue'),
h('p', '请在项目中创建此组件或在组件映射表中注册')
])
])
}
```
**控制台警告**
```
⚠️ 组件未找到: ball/games.vue使用占位组件
```
## 💡 最佳实践
### 1. 框架内置页面
直接使用,无需配置:
- `home/index.vue` - 主页
- `system/sys_user.vue` - 用户管理
- `system/sys_role.vue` - 角色管理
- `system/sys_log.vue` - 日志管理
- `system/sys_param_setup.vue` - 参数设置
- `system_high/sys_menu.vue` - 菜单管理
- `system_high/sys_control.vue` - 控制器管理
- `system_high/sys_title.vue` - 系统标题设置
### 2. 自定义业务页面
在 main.js 中添加映射:
```javascript
// 1. 导入组件
import GamesComponent from './views/ball/games.vue'
// 2. 添加映射
AdminFramework.addComponentMap({
'ball/games.vue': GamesComponent
})
```
### 3. 路径命名建议
保持后端返回的路径与实际文件路径一致:
```
后端component: "ball/games.vue"
项目src/views/ball/games.vue
```
## 📊 代码优化对比
### 优化前(重复代码)
```javascript
const map = {
'system/sys_user.vue': SysUser,
'system/sys_user': SysUser, // 重复
'system/sys_role.vue': SysRole,
'system/sys_role': SysRole, // 重复
'system/sys_log.vue': SysLog,
'system/sys_log': SysLog, // 重复
// 每个组件写两遍...
}
```
### 优化后(自动生成)
```javascript
const components = {
'system/sys_user': SysUser,
'system/sys_role': SysRole,
'system/sys_log': SysLog
}
// 自动生成带 .vue 和不带 .vue 的映射
const map = {}
Object.keys(components).forEach(path => {
map[path] = components[path]
map[path + '.vue'] = components[path]
})
```
**优势**
- ✅ 代码量减少 50%
- ✅ 易于维护
- ✅ 不易出错
## 🚀 使用方法
### 步骤 1创建业务组件
在项目中创建组件文件:
```vue
<!-- src/views/ball/games.vue -->
<template>
<div>球局管理页面</div>
</template>
<script>
export default {
name: 'games'
}
</script>
```
### 步骤 2添加组件映射
`src/main.js` 中:
```javascript
import GamesComponent from './views/ball/games.vue'
AdminFramework.addComponentMap({
'ball/games.vue': GamesComponent
})
```
### 步骤 3后端返回菜单
确保后端菜单中的路径正确:
```json
{
"component": "ball/games.vue",
"path": "games"
}
```
### 步骤 4自动生成路由
框架会自动将菜单转换为路由,并加载对应组件!
## 📚 相关文档
- [README.md](./README.md) - 项目说明
- [CHANGELOG.md](./CHANGELOG.md) - 更新日志
- [../完整使用文档.md](../完整使用文档.md) - 框架完整文档
---
**现在启动项目,权限菜单中的系统页面都能正常显示了!** 🎉
对于业务页面ball/games.vue, order/pay_orders.vue 等),只需:
1. 在项目中创建对应组件
2. 在 main.js 中添加组件映射

View File

@@ -1,233 +0,0 @@
# 调试指南
## ✅ Source Map 已启用
现在 Demo 项目已配置了完整的 Source Map 支持,可以在浏览器中直接调试源码!
### 📋 Source Map 配置
#### 开发模式(`npm run dev`
```javascript
devtool: 'eval-source-map'
```
**特点**
- ✅ 高质量的 source map
- ✅ 可以看到原始源代码
- ✅ 可以设置断点调试
- ✅ 包含列信息(精确定位)
- ⚡ 重新构建速度快
#### 生产模式(`npm run build`
```javascript
devtool: 'source-map'
```
**特点**
- ✅ 完整的 source map
- ✅ 生成独立的 .map 文件
- 📦 适合部署到生产环境
### 🔍 如何调试
#### 1. 在浏览器中调试
**启动开发服务器**
```bash
npm run dev
```
**打开浏览器开发者工具**
- Chrome`F12``Ctrl+Shift+I`
- Firefox`F12`
**查看源码**
1. 点击 **Sources** 标签页Chrome**调试器** 标签页Firefox
2. 在左侧文件树中可以看到:
```
webpack://
├── demo-project/
│ └── src/
│ ├── main.js ← Demo 项目源码
│ ├── App.vue
│ └── views/
└── src/ ← 框架源码
├── index.js
├── components/
├── views/
└── utils/
```
#### 2. 设置断点
**在源码中设置断点**
1. 在 Sources 中找到要调试的文件
2. 点击行号设置断点(会出现蓝色标记)
3. 刷新页面或触发相关操作
**使用 debugger 语句**
```javascript
// 在代码中添加
debugger
// 例如在 main.js 中
mounted() {
debugger // ← 程序会在这里暂停
this.$store.dispatch('user/setAuthorityMenus', {
Main: AdminFramework.Main,
ParentView: AdminFramework.ParentView,
Page404: AdminFramework.Page404
})
}
```
#### 3. 查看变量
断点暂停时可以:
- 在 **Scope** 面板查看局部变量
- 在 **Watch** 面板添加监视表达式
- 在 **Console** 中输入变量名查看值
#### 4. 单步调试
使用调试控制按钮:
- **继续** (`F8`) - 继续执行到下一个断点
- **单步跳过** (`F10`) - 执行当前行,不进入函数
- **单步进入** (`F11`) - 进入函数内部
- **单步跳出** (`Shift+F11`) - 跳出当前函数
### 🎯 调试框架源码
由于项目直接使用框架源码(`../../src/index.js`),你可以:
#### 1. 直接在框架代码中设置断点
例如在 `src/index.js` 的 install 方法中:
```javascript
install(Vue, options = {}) {
debugger // ← 可以在这里调试框架初始化过程
if (this.installed) return
// ...
}
```
#### 2. 调试 Store Actions
在 `src/store/user.js` 中:
```javascript
async handleLogin({ state, commit, dispatch }, { userFrom, Main, ParentView, Page404 }) {
debugger // ← 调试登录流程
// ...
}
```
#### 3. 调试 HTTP 请求
在 `src/utils/http.js` 中:
```javascript
post(url, data, config) {
debugger // ← 调试 API 请求
// ...
}
```
### 📊 Source Map 类型对比
| 类型 | 构建速度 | 重构速度 | 质量 | 适用场景 |
|------|---------|---------|------|---------|
| `eval-source-map` | 慢 | 快 | 高 | **开发** ✅ |
| `cheap-module-source-map` | 中 | 中 | 中 | 开发 |
| `source-map` | 很慢 | 很慢 | 最高 | **生产** ✅ |
| `none` | 最快 | 最快 | 无 | 不调试 |
### 💡 调试技巧
#### 1. 使用 Vue DevTools
安装 Vue DevTools 浏览器插件:
- Chrome: [Vue.js devtools](https://chrome.google.com/webstore)
- Firefox: [Vue.js devtools](https://addons.mozilla.org/firefox)
功能:
- 查看组件树
- 检查组件数据和 props
- 查看 Vuex 状态
- 追踪事件
#### 2. Console 调试技巧
```javascript
// 查看 Store 状态
console.log('Store:', this.$store.state)
// 查看路由信息
console.log('Route:', this.$route)
// 查看组件实例
console.log('Component:', this)
// 使用 console.table 显示数组
console.table(this.list)
// 使用 console.dir 显示对象结构
console.dir(AdminFramework)
```
#### 3. 网络请求调试
在 **Network** 标签页中:
- 查看 API 请求和响应
- 检查请求头和响应头
- 查看请求耗时
### ⚠️ 注意事项
#### 1. Source Map 文件大小
开发模式的 source map 会增加包体积,但:
- ✅ 只在开发环境使用
- ✅ 不影响生产环境性能
- ✅ 不会部署到生产服务器
#### 2. 刷新页面
修改代码后:
- 保存文件会自动热更新HMR
- 如果 HMR 失败,手动刷新页面(`F5`
#### 3. 清除缓存
如果看到旧代码:
- 硬刷新:`Ctrl+Shift+R` (Chrome) 或 `Ctrl+F5`
- 或在开发者工具中禁用缓存
### 🚀 开始调试
1. **启动开发服务器**
```bash
npm run dev
```
2. **打开浏览器**
访问 `http://localhost:8080`
3. **打开开发者工具**
按 `F12`
4. **设置断点**
在 Sources 中找到源文件并设置断点
5. **开始调试**
刷新页面或触发相关操作
### 📚 相关资源
- [Chrome DevTools 官方文档](https://developer.chrome.com/docs/devtools/)
- [Firefox Developer Tools](https://developer.mozilla.org/docs/Tools)
- [Vue DevTools](https://devtools.vuejs.org/)
- [Webpack DevTool 文档](https://webpack.js.org/configuration/devtool/)
---
**现在启动项目,打开浏览器开发者工具,就可以看到完整的源码并进行调试了!** 🎉

View File

@@ -1,409 +0,0 @@
# 路由重复导航警告修复
## 🔍 问题描述
控制台出现警告:
```
Avoided redundant navigation to current location: "/home".
NavigationDuplicated: Avoided redundant navigation to current location: "/home".
```
## 📋 问题原因
### 警告产生的场景
**场景 1已在首页时访问登录页**
```
当前路由: /home
用户访问: /login
路由守卫检测到已登录
尝试重定向: next({ name: 'home' })
目标路由: /home
❌ 警告:已经在 /home避免重复导航
```
**场景 2刷新首页**
```
当前路由: /home
刷新页面
路由守卫再次执行
检测到已登录且访问登录页(可能的中间状态)
尝试重定向: next({ name: 'home' })
❌ 警告:已经在 /home避免重复导航
```
### 原来的路由守卫代码
```javascript
router.beforeEach((to, from, next) => {
const token = getToken()
ViewUI.LoadingBar.start()
if (to.name === 'view_log') {
next()
return
}
if (!token && to.name !== 'login') {
next({ name: 'login' })
} else if (!token && to.name === 'login') {
next()
} else if (token && to.name === 'login') {
// ❌ 没有检查来源路由,可能导致重复导航
next({ name: homeName })
} else {
next()
}
})
```
**问题**
- 当已登录用户访问登录页时,总是重定向到首页
- 没有检查来源路由是否已经是首页
- 导致重复导航警告
## ✅ 解决方案
### 修改路由守卫逻辑
**修改文件**`src/router/index.js`
**修改后的代码**
```javascript
router.beforeEach((to, from, next) => {
const token = getToken()
ViewUI.LoadingBar.start()
if (to.name === 'view_log') {
next()
return
}
if (!token && to.name !== 'login') {
// 未登录且访问非登录页 → 跳转到登录页
next({ name: 'login' })
} else if (!token && to.name === 'login') {
// 未登录且访问登录页 → 允许访问
next()
} else if (token && to.name === 'login') {
// 已登录且访问登录页 → 重定向到首页
// ✅ 避免重复导航警告
if (from.name === homeName) {
next(false) // 取消导航,停留在当前页面
} else {
next({ name: homeName }) // 重定向到首页
}
} else {
// 其他情况 → 允许访问
next()
}
})
```
### 关键改进
**添加了来源路由检查**
```javascript
if (from.name === homeName) {
next(false) // 如果来自首页,取消导航
} else {
next({ name: homeName }) // 否则重定向到首页
}
```
**`next(false)` 的作用**
- 取消当前导航
- 停留在当前页面(首页)
- 不会触发重复导航警告
## 📊 修复后的流程
### 场景 1从首页访问登录页
```
当前路由: /home (from.name = 'home')
用户访问: /login (to.name = 'login')
路由守卫检测到已登录
检查来源路由: from.name === 'home' ✅
执行: next(false)
取消导航,停留在首页 ✅
✅ 没有警告
```
### 场景 2从其他页面访问登录页
```
当前路由: /system/user (from.name = 'sys_user')
用户访问: /login (to.name = 'login')
路由守卫检测到已登录
检查来源路由: from.name !== 'home' ✅
执行: next({ name: 'home' })
重定向到首页 ✅
✅ 正常导航,没有警告
```
### 场景 3未登录访问登录页
```
当前路由: 无 (from.name = undefined)
用户访问: /login (to.name = 'login')
路由守卫检测到未登录
执行: next()
允许访问登录页 ✅
```
### 场景 4登录成功后跳转
```
登录成功
执行: window.location.href = '#/'
触发完整页面加载
访问: / (重定向到 /home)
路由守卫检测到已登录
to.name = 'home' (不是 'login')
执行: next()
允许访问首页 ✅
```
## 🎯 `next()` 方法说明
### `next()` 的不同用法
**1. `next()`**
- 允许当前导航
- 继续执行路由跳转
**2. `next(false)`**
- 取消当前导航
- 停留在当前页面
- 不会触发路由变化
**3. `next({ name: 'home' })`**
- 重定向到指定路由
- 取消当前导航
- 跳转到新路由
**4. `next({ path: '/home' })`**
- 重定向到指定路径
- 取消当前导航
- 跳转到新路由
**5. `next(error)`**
- 终止导航
- 触发错误处理
### 为什么使用 `next(false)` 而不是 `next()`
**如果使用 `next()`**
```javascript
if (token && to.name === 'login') {
next() // ❌ 允许访问登录页
}
```
- 会允许已登录用户访问登录页
- 不符合业务逻辑
**如果使用 `next({ name: homeName })`**
```javascript
if (token && to.name === 'login') {
next({ name: homeName }) // ❌ 如果已在首页,会重复导航
}
```
- 如果来源路由已经是首页,会触发重复导航警告
**使用 `next(false)`**
```javascript
if (token && to.name === 'login') {
if (from.name === homeName) {
next(false) // ✅ 取消导航,停留在首页
} else {
next({ name: homeName }) // ✅ 重定向到首页
}
}
```
- 如果来源是首页,取消导航,停留在首页
- 如果来源不是首页,重定向到首页
- 避免重复导航警告
## ✅ 验证清单
### 功能验证
- ✅ 未登录访问登录页 → 正常显示登录页
- ✅ 未登录访问其他页面 → 重定向到登录页
- ✅ 已登录访问登录页(从首页) → 停留在首页
- ✅ 已登录访问登录页(从其他页面) → 重定向到首页
- ✅ 登录成功 → 跳转到首页
### 警告检查
- ✅ 控制台没有 "Avoided redundant navigation" 警告
- ✅ 控制台没有 "NavigationDuplicated" 警告
- ✅ 路由跳转正常工作
### 边界情况
- ✅ 刷新首页 → 停留在首页
- ✅ 刷新其他页面 → 停留在当前页面
- ✅ 直接访问 URL → 正确处理
## 💡 最佳实践
### 1. 路由守卫中检查来源路由
**推荐**
```javascript
if (token && to.name === 'login') {
if (from.name === homeName) {
next(false) // 来自首页,取消导航
} else {
next({ name: homeName }) // 来自其他页面,重定向
}
}
```
**不推荐**
```javascript
if (token && to.name === 'login') {
next({ name: homeName }) // 可能导致重复导航
}
```
### 2. 使用 `next(false)` 取消不必要的导航
**推荐**
```javascript
if (shouldCancelNavigation) {
next(false) // 取消导航
}
```
**不推荐**
```javascript
if (shouldCancelNavigation) {
// 什么都不做,导航会继续
}
```
### 3. 避免在路由守卫中使用 `window.location`
**推荐**
```javascript
router.beforeEach((to, from, next) => {
if (needRedirect) {
next({ name: 'home' }) // 使用 next() 重定向
}
})
```
**不推荐**
```javascript
router.beforeEach((to, from, next) => {
if (needRedirect) {
window.location.href = '#/home' // 不要在守卫中使用
next(false)
}
})
```
## 🔧 相关代码
### 完整的路由守卫代码
**文件**`src/router/index.js`
```javascript
// 路由守卫配置
export const setupRouterGuards = (router, ViewUI, homeName = 'home') => {
router.beforeEach((to, from, next) => {
const token = getToken()
ViewUI.LoadingBar.start()
if (to.name === 'view_log') {
next()
return
}
if (!token && to.name !== 'login') {
// 未登录且访问非登录页 → 跳转到登录页
next({ name: 'login' })
} else if (!token && to.name === 'login') {
// 未登录且访问登录页 → 允许访问
next()
} else if (token && to.name === 'login') {
// 已登录且访问登录页 → 重定向到首页
// 避免重复导航警告
if (from.name === homeName) {
next(false) // 来自首页,取消导航
} else {
next({ name: homeName }) // 来自其他页面,重定向到首页
}
} else {
// 其他情况 → 允许访问
next()
}
})
router.afterEach(to => {
ViewUI.LoadingBar.finish()
window.scrollTo(0, 0)
})
return router
}
```
## 📝 总结
### 修改内容
- ✅ 在路由守卫中添加了来源路由检查
- ✅ 使用 `next(false)` 避免重复导航
- ✅ 保持了原有的业务逻辑
### 效果
- ✅ 消除了 "Avoided redundant navigation" 警告
- ✅ 消除了 "NavigationDuplicated" 警告
- ✅ 路由跳转更加流畅
- ✅ 用户体验更好
---
**路由重复导航警告已修复!** 🎉
现在控制台不会再出现重复导航的警告了。

View File

@@ -1,483 +0,0 @@
# 路由重复导航错误完全修复
## 🔍 问题描述
页面直接报错:
```
ERROR
Avoided redundant navigation to current location: "/home".
NavigationDuplicated: Avoided redundant navigation to current location: "/home".
at HashHistory.push
at VueComponent.turnToPage (main.vue:108:20)
```
## 📋 问题原因
### 错误来源
错误来自 `src/components/main/main.vue` 的两个方法:
**1. `goHome()` 方法**
```javascript
goHome() {
this.$router.push({ path: '/' }) // ❌ 如果已在首页,会报错
}
```
**2. `turnToPage()` 方法**
```javascript
turnToPage(route) {
// ...
this.$router.push({
name,
params,
query
}) // ❌ 如果跳转到当前页面,会报错
}
```
### 触发场景
**场景 1点击 Logo 回到首页**
```
当前页面: /home
点击 Logo
调用 goHome()
执行 this.$router.push({ path: '/' })
❌ 错误:已经在首页,重复导航
```
**场景 2点击当前激活的菜单**
```
当前页面: /home
点击"首页"菜单
调用 turnToPage({ name: 'home' })
执行 this.$router.push({ name: 'home' })
❌ 错误:已经在首页,重复导航
```
**场景 3刷新页面后点击菜单**
```
刷新页面
当前路由: /home
菜单激活状态: home
点击"首页"菜单
❌ 错误:重复导航
```
### Vue Router 的行为
**Vue Router 2.x/3.x**
- `router.push()` 返回一个 Promise
- 如果导航到当前路由,会抛出 `NavigationDuplicated` 错误
- 这个错误会导致页面崩溃(如果没有捕获)
## ✅ 解决方案
### 方案 1在跳转前检查是否是当前路由推荐
**优点**
- 避免不必要的路由跳转
- 性能更好
- 代码更清晰
**缺点**
- 需要在每个跳转方法中添加检查
### 方案 2捕获 Promise 错误
**优点**
- 代码简单
- 统一处理错误
**缺点**
- 仍然会触发路由跳转逻辑
- 性能稍差
### 方案 3结合使用本次采用
**优点**
- 既避免不必要的跳转
- 又捕获可能的错误
- 最稳健的方案
## 📝 修改内容
### 修改 `goHome()` 方法
**修改前**
```javascript
goHome() {
this.$router.push({ path: '/' }) // ❌ 可能重复导航
}
```
**修改后**
```javascript
goHome() {
// 避免重复导航到当前页面
if (this.$route.path !== '/' && this.$route.path !== '/home') {
this.$router.push({ path: '/' }).catch(err => {
// 忽略重复导航错误
if (err.name !== 'NavigationDuplicated') {
console.error(err)
}
})
}
}
```
**改进点**
- ✅ 检查当前路由是否是 `/``/home`
- ✅ 只在不是首页时才跳转
- ✅ 捕获并忽略重复导航错误
- ✅ 其他错误仍然会打印到控制台
### 修改 `turnToPage()` 方法
**修改前**
```javascript
turnToPage(route) {
let { name, params, query } = {}
if (typeof route === 'string') name = route
else {
name = route.name
params = route.params
query = route.query
}
if (name.indexOf('isTurnByHref_') > -1) {
window.open(name.split('_')[1])
return
}
this.$router.push({
name,
params,
query
}) // ❌ 可能重复导航
}
```
**修改后**
```javascript
turnToPage(route) {
let { name, params, query } = {}
if (typeof route === 'string') name = route
else {
name = route.name
params = route.params
query = route.query
}
if (name.indexOf('isTurnByHref_') > -1) {
window.open(name.split('_')[1])
return
}
// 避免重复导航到当前页面
if (this.$route.name === name) {
return
}
this.$router.push({
name,
params,
query
}).catch(err => {
// 忽略重复导航错误
if (err.name !== 'NavigationDuplicated') {
console.error(err)
}
})
}
```
**改进点**
- ✅ 检查目标路由是否是当前路由
- ✅ 如果是当前路由,直接返回,不跳转
- ✅ 捕获并忽略重复导航错误
- ✅ 其他错误仍然会打印到控制台
## 📊 修复后的流程
### 场景 1在首页点击 Logo
```
当前路由: /home
点击 Logo
调用 goHome()
检查: this.$route.path === '/home' ✅
直接返回,不跳转 ✅
✅ 没有错误
```
### 场景 2在其他页面点击 Logo
```
当前路由: /system/user
点击 Logo
调用 goHome()
检查: this.$route.path !== '/' && this.$route.path !== '/home' ✅
执行跳转: this.$router.push({ path: '/' })
跳转到首页 ✅
✅ 正常跳转
```
### 场景 3点击当前激活的菜单
```
当前路由: /home (name: 'home')
点击"首页"菜单
调用 turnToPage({ name: 'home' })
检查: this.$route.name === 'home' ✅
直接返回,不跳转 ✅
✅ 没有错误
```
### 场景 4点击其他菜单
```
当前路由: /home (name: 'home')
点击"用户管理"菜单
调用 turnToPage({ name: 'sys_user' })
检查: this.$route.name !== 'sys_user' ✅
执行跳转: this.$router.push({ name: 'sys_user' })
跳转到用户管理页面 ✅
✅ 正常跳转
```
## 🎯 关键点说明
### 1. 为什么要检查两个路径?
```javascript
if (this.$route.path !== '/' && this.$route.path !== '/home') {
// 跳转
}
```
**原因**
- 主路由配置了 `redirect: '/home'`
- 访问 `/` 会重定向到 `/home`
- 所以需要检查两个路径
### 2. 为什么使用 `catch()` 捕获错误?
```javascript
this.$router.push({ path: '/' }).catch(err => {
if (err.name !== 'NavigationDuplicated') {
console.error(err)
}
})
```
**原因**
- `router.push()` 返回 Promise
- 重复导航会抛出 `NavigationDuplicated` 错误
- 如果不捕获,错误会导致页面崩溃
- 捕获后可以忽略重复导航错误,但保留其他错误的日志
### 3. 为什么检查 `err.name !== 'NavigationDuplicated'`
```javascript
if (err.name !== 'NavigationDuplicated') {
console.error(err)
}
```
**原因**
- 只忽略重复导航错误
- 其他错误(如路由不存在、权限错误等)仍然需要打印
- 方便调试和排查问题
### 4. 为什么在 `turnToPage` 中直接 `return`
```javascript
if (this.$route.name === name) {
return // 直接返回
}
```
**原因**
- 如果是当前路由,不需要跳转
- 直接返回可以避免不必要的路由操作
- 性能更好
## ✅ 验证清单
### 功能验证
- ✅ 在首页点击 Logo → 不跳转,没有错误
- ✅ 在其他页面点击 Logo → 跳转到首页
- ✅ 点击当前激活的菜单 → 不跳转,没有错误
- ✅ 点击其他菜单 → 正常跳转
- ✅ 刷新页面后点击菜单 → 正常工作
### 错误检查
- ✅ 控制台没有 "NavigationDuplicated" 错误
- ✅ 控制台没有 "Avoided redundant navigation" 警告
- ✅ 页面不会崩溃
### 边界情况
- ✅ 快速连续点击菜单 → 正常工作
- ✅ 快速连续点击 Logo → 正常工作
- ✅ 在不同页面之间快速切换 → 正常工作
## 💡 最佳实践
### 1. 路由跳转前检查目标路由
**推荐**
```javascript
if (this.$route.name !== targetName) {
this.$router.push({ name: targetName })
}
```
**不推荐**
```javascript
this.$router.push({ name: targetName }) // 可能重复导航
```
### 2. 捕获 Promise 错误
**推荐**
```javascript
this.$router.push({ name: targetName }).catch(err => {
if (err.name !== 'NavigationDuplicated') {
console.error(err)
}
})
```
**不推荐**
```javascript
this.$router.push({ name: targetName }) // 错误会导致页面崩溃
```
### 3. 结合使用检查和捕获
**推荐**
```javascript
if (this.$route.name !== targetName) {
this.$router.push({ name: targetName }).catch(err => {
if (err.name !== 'NavigationDuplicated') {
console.error(err)
}
})
}
```
**优点**
- 避免不必要的跳转
- 捕获可能的错误
- 最稳健的方案
## 🔧 相关代码
### 完整的 `goHome()` 方法
```javascript
goHome() {
// 避免重复导航到当前页面
if (this.$route.path !== '/' && this.$route.path !== '/home') {
this.$router.push({ path: '/' }).catch(err => {
// 忽略重复导航错误
if (err.name !== 'NavigationDuplicated') {
console.error(err)
}
})
}
}
```
### 完整的 `turnToPage()` 方法
```javascript
turnToPage(route) {
let { name, params, query } = {}
if (typeof route === 'string') name = route
else {
name = route.name
params = route.params
query = route.query
}
if (name.indexOf('isTurnByHref_') > -1) {
window.open(name.split('_')[1])
return
}
// 避免重复导航到当前页面
if (this.$route.name === name) {
return
}
this.$router.push({
name,
params,
query
}).catch(err => {
// 忽略重复导航错误
if (err.name !== 'NavigationDuplicated') {
console.error(err)
}
})
}
```
## 📝 总结
### 修改内容
- ✅ 修改了 `goHome()` 方法,添加路由检查和错误捕获
- ✅ 修改了 `turnToPage()` 方法,添加路由检查和错误捕获
- ✅ 避免了重复导航错误
- ✅ 保持了原有的业务逻辑
### 效果
- ✅ 消除了 "NavigationDuplicated" 错误
- ✅ 页面不会崩溃
- ✅ 路由跳转更加流畅
- ✅ 用户体验更好
---
**路由重复导航错误已完全修复!** 🎉
现在可以放心地点击菜单和 Logo不会再出现错误了。

View File

@@ -1,427 +0,0 @@
# 首页路由梳理说明
## 🔍 问题分析
### 原来的问题
首页在多个地方被设置,导致路由混乱和错误:
1. **`src/utils/uiTool.js``getRoutes` 方法**
- 接收了 `HomePage` 参数但没有使用
- `children` 初始化为空数组
- 尝试查找不存在的 `homeRoute`,返回 `undefined`
- 使用 `undefined` 导致路由错误
2. **`src/index.js``install` 方法**
- 调用 `getRoutes` 创建路由
- 传入了 `HomePage` 但没有被使用
3. **`demo-project/src/main.js``mounted` 钩子**
- 又调用了 `setAuthorityMenus` 重新设置菜单
- 导致路由被重复设置
### 错误信息
```
vue-router.esm.js:1396 Uncaught TypeError: Cannot read properties of undefined (reading 'path')
[vuex] unknown action type: getSysTitle
[vuex] unknown getter: sysFormModel
```
## ✅ 解决方案
### 设计原则
1. **单一职责**:每个方法只负责一件事
2. **避免重复**:路由只在一个地方创建和设置
3. **清晰的流程**:首页设置流程清晰可追踪
### 新的首页设置流程
```
应用启动
框架 install 方法
调用 getRoutes 创建主路由
创建默认首页路由 (/home)
检查 localStorage 中的权限菜单
如果有权限菜单,合并到主路由
创建 VueRouter 实例
应用启动完成
用户登录
保存权限菜单到 localStorage
刷新页面
重新执行上述流程(此时有权限菜单)
```
## 📝 修改内容
### 1. 修复 `src/utils/uiTool.js` 的 `getRoutes` 方法
**修改前**
```javascript
static getRoutes(Main, ParentView, Page404, HomePage) {
let mainRoute = {
path: '/',
name: '主视图',
redirect: '/home',
component: Main,
meta: { title: '首页', notCache: true },
children: [] // ❌ 空数组,没有默认首页
}
// ... 后续逻辑尝试使用不存在的 homeRoute
const homeRoute = mainRoute.children.find(r => r.name === 'home') // ❌ undefined
mainRoute.children = [homeRoute, ...curRoutes] // ❌ 使用 undefined
}
```
**修改后**
```javascript
static getRoutes(Main, ParentView, Page404, HomePage) {
// ✅ 创建默认的首页路由
const defaultHomeRoute = {
path: '/home',
name: 'home',
meta: { title: '首页', notCache: true },
component: HomePage || {
render: h => h('div', { style: { padding: '20px' } }, '欢迎使用管理系统')
}
}
let mainRoute = {
path: '/',
name: '主视图',
redirect: '/home',
component: Main,
meta: { title: '首页', notCache: true },
children: [defaultHomeRoute] // ✅ 包含默认首页
}
// 从 localStorage 读取权限菜单
if (localStorage.authorityMenus && localStorage.authorityMenus !== 'undefined') {
let authorityMenus = JSON.parse(localStorage.authorityMenus) || []
if (authorityMenus && authorityMenus.length > 0) {
let menus = uiTool.transformTree(authorityMenus)
let curRoutes = uiTool.menuToRoute(menus, ParentView, Page404)
// 检查权限路由中是否有 home
const hasHome = curRoutes.some(r => r.name === 'home')
if (hasHome) {
// 如果权限路由中有 home使用权限路由的 home
mainRoute.children = curRoutes
} else {
// 如果权限路由中没有 home保留默认 home 并添加其他路由
mainRoute.children = [defaultHomeRoute, ...curRoutes]
}
}
}
return mainRoute
}
```
**改进点**
- ✅ 使用传入的 `HomePage` 参数
- ✅ 创建默认的首页路由
- ✅ 正确处理权限菜单的合并
- ✅ 避免使用 `undefined`
### 2. 简化 `demo-project/src/main.js`
**修改前**
```javascript
window.rootVue = new Vue({
el: '#app',
router: AdminFramework.router,
store: AdminFramework.store,
render: h => h(App),
mounted() {
AdminFramework.uiTool.setRem()
// ❌ 重复设置权限菜单
this.$store.dispatch('user/setAuthorityMenus', {
Main: AdminFramework.Main,
ParentView: AdminFramework.ParentView,
Page404: AdminFramework.Page404
})
this.$store.dispatch('app/getSysTitle', {
defaultTitle: 'Demo 管理系统',
defaultLogo: ''
})
}
})
```
**修改后**
```javascript
window.rootVue = new Vue({
el: '#app',
router: AdminFramework.router,
store: AdminFramework.store,
render: h => h(App),
mounted() {
AdminFramework.uiTool.setRem()
// ✅ 只获取系统标题,不重复设置菜单
this.$store.dispatch('app/getSysTitle', {
defaultTitle: 'Demo 管理系统',
defaultLogo: ''
})
}
})
```
**改进点**
- ✅ 移除了重复的 `setAuthorityMenus` 调用
- ✅ 路由只在框架初始化时创建一次
- ✅ 登录后通过刷新页面重新加载路由
### 3. 修复 Vuex 模块命名空间问题
**修改的文件**
- `src/components/main/main.vue`
- `src/components/main/components/user/user.vue`
**修改前**
```javascript
// main.vue
...mapGetters({
sysFormModel: 'sysFormModel', // ❌ 缺少模块前缀
menuList: 'menuList',
userName: 'userName',
userAvator: 'avatorImgPath'
})
// user.vue
...mapActions(['handleLogOut']) // ❌ 缺少模块前缀
```
**修改后**
```javascript
// main.vue
...mapGetters({
sysFormModel: 'app/sysFormModel', // ✅ 添加模块前缀
menuList: 'user/menuList',
userName: 'user/userName',
userAvator: 'user/avatorImgPath'
})
// user.vue
...mapActions('user', ['handleLogOut']) // ✅ 指定模块
```
## 🎯 完整的首页路由流程
### 首次访问(未登录)
```
1. 用户访问 http://localhost:8080
2. 框架初始化
3. getRoutes 创建主路由
- localStorage 中没有 authorityMenus
- 使用默认首页路由
4. 路由配置:
{
path: '/',
component: Main,
children: [
{ path: '/home', name: 'home', component: HomePage }
]
}
5. 显示登录页面
```
### 登录流程
```
1. 用户输入用户名密码
2. 调用登录接口
3. 保存 token 和用户信息
4. 调用 setAuthorityMenus
- 尝试获取权限菜单(可能失败)
- 使用默认菜单配置
- 保存到 localStorage
5. 刷新页面 (window.location.reload())
6. 重新执行首次访问流程
- 此时 localStorage 中有 authorityMenus
- 根据权限菜单生成路由
```
### 登录后访问
```
1. 用户访问 http://localhost:8080
2. 框架初始化
3. getRoutes 创建主路由
- localStorage 中有 authorityMenus
- 解析权限菜单
- 生成权限路由
4. 路由配置:
{
path: '/',
component: Main,
children: [
{ path: '/home', name: 'home', component: HomePage },
{ path: '/system/user', name: 'sys_user', component: SysUser },
{ path: '/system/role', name: 'sys_role', component: SysRole },
// ... 其他权限路由
]
}
5. 显示系统首页
```
## 📊 路由结构
### 完整的路由树
```
routes: [
// 登录页面
{
path: '/login',
name: 'login',
component: LoginPage
},
// 主路由
{
path: '/',
name: '主视图',
redirect: '/home',
component: Main,
children: [
// 默认首页
{
path: '/home',
name: 'home',
component: HomePage,
meta: { title: '首页', notCache: true }
},
// 权限路由(从 authorityMenus 生成)
{
path: '/system/user',
name: 'sys_user',
component: SysUser,
meta: { title: '用户管理' }
},
{
path: '/system/role',
name: 'sys_role',
component: SysRole,
meta: { title: '角色管理' }
},
// ... 更多权限路由
]
},
// 错误页面
{
path: '/401',
name: 'error_401',
component: Page401
},
{
path: '/500',
name: 'error_500',
component: Page500
},
{
path: '*',
name: 'error_404',
component: Page404
}
]
```
## ✅ 验证清单
### 功能验证
- ✅ 首次访问显示登录页面
- ✅ 登录成功后跳转到首页
- ✅ 首页正确显示
- ✅ 左侧菜单正确显示
- ✅ 系统标题正确显示
- ✅ 用户名正确显示
- ✅ 页面跳转正常
- ✅ 刷新页面后状态保持
### 错误修复
- ✅ 修复了 `Cannot read properties of undefined (reading 'path')` 错误
- ✅ 修复了 `[vuex] unknown action type: getSysTitle` 错误
- ✅ 修复了 `[vuex] unknown getter: sysFormModel` 错误
- ✅ 修复了首页路由重复设置的问题
## 💡 最佳实践
### 1. 路由创建原则
- **单一入口**:路由只在框架初始化时创建一次
- **数据驱动**:根据 localStorage 中的数据动态生成路由
- **默认兜底**:始终提供默认的首页路由
### 2. 权限菜单处理
- **登录时保存**:登录成功后保存权限菜单到 localStorage
- **启动时读取**:应用启动时从 localStorage 读取权限菜单
- **刷新更新**:登录后刷新页面,重新生成路由
### 3. 避免的陷阱
- ❌ 不要在多个地方创建或修改路由
- ❌ 不要在 mounted 钩子中重复设置菜单
- ❌ 不要忘记处理 undefined 的情况
- ❌ 不要忘记 Vuex 模块的命名空间
## 🎉 总结
### 修复的问题
1. ✅ 首页路由正确创建
2. ✅ 权限菜单正确合并
3. ✅ 避免了重复设置
4. ✅ 修复了 Vuex 命名空间问题
5. ✅ 流程清晰可维护
### 代码改进
- **减少复杂度**:移除了重复的菜单设置逻辑
- **提高可读性**:流程更清晰,易于理解
- **增强健壮性**:正确处理各种边界情况
- **符合规范**:遵循 Vue 和 Vuex 的最佳实践
---
**首页路由梳理完成!** 🎉
现在路由创建流程清晰、简洁、可靠。

View File

@@ -1,14 +0,0 @@
module.exports = {
presets: [
[
'@babel/preset-env',
{
targets: {
browsers: ['> 1%', 'last 2 versions', 'not ie <= 8']
}
}
],
'@vue/babel-preset-jsx'
]
}

View File

@@ -1,39 +0,0 @@
@echo off
echo ====================================
echo 安装 Demo 项目依赖
echo ====================================
echo.
echo [1/3] 清理旧依赖...
if exist "node_modules\" (
echo 删除 node_modules 目录...
rmdir /s /q node_modules
)
if exist "package-lock.json" (
echo 删除 package-lock.json...
del /f /q package-lock.json
)
echo.
echo [2/3] 安装所有依赖...
echo 这可能需要几分钟时间,请耐心等待...
echo.
call npm install
echo.
echo [3/3] 验证关键依赖...
echo.
call npm list @vue/babel-preset-jsx brace vue2-ace-editor --depth=0
echo.
echo ====================================
echo 安装完成!
echo ====================================
echo.
echo 现在可以运行以下命令启动项目:
echo 1. 双击 start.bat
echo 2. 或运行: npm run dev
echo.
pause

View File

@@ -1,49 +0,0 @@
{
"name": "demo-project",
"version": "1.0.0",
"description": "Admin Framework 使用示例项目",
"main": "src/main.js",
"scripts": {
"dev": "webpack-dev-server --mode development --open",
"build": "webpack --mode production"
},
"keywords": [
"admin",
"vue",
"demo"
],
"author": "light",
"license": "MIT",
"dependencies": {
"axios": "^0.21.4",
"brace": "^0.11.1",
"core-js": "^3.45.1",
"dayjs": "^1.10.0",
"js-cookie": "^2.2.1",
"view-design": "^4.7.0",
"vue": "^2.6.14",
"vue-router": "^3.5.3",
"vue2-ace-editor": "^0.0.15",
"vuex": "^3.6.2",
"vuex-persistedstate": "^4.1.0"
},
"devDependencies": {
"@babel/core": "^7.12.0",
"@babel/preset-env": "^7.12.0",
"@vue/babel-preset-jsx": "^1.4.0",
"babel-loader": "^8.2.0",
"css-loader": "^5.0.0",
"file-loader": "^6.2.0",
"html-webpack-plugin": "^5.5.0",
"less": "^4.0.0",
"less-loader": "^7.0.0",
"style-loader": "^2.0.0",
"url-loader": "^4.1.0",
"vue-loader": "^15.9.0",
"vue-style-loader": "^4.1.0",
"vue-template-compiler": "^2.6.14",
"webpack": "^5.0.0",
"webpack-cli": "^4.0.0",
"webpack-dev-server": "^4.0.0"
}
}

View File

@@ -1,31 +0,0 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Demo 管理系统</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
html, body {
width: 100%;
height: 100%;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
}
#app {
width: 100%;
height: 100%;
}
</style>
</head>
<body>
<div id="app"></div>
</body>
</html>

View File

@@ -1,25 +0,0 @@
<template>
<div id="app">
<router-view />
</div>
</template>
<script>
export default {
name: 'App',
mounted() {
console.log('App 组件已挂载')
}
}
</script>
<style>
/* 全局样式 */
#app {
width: 100%;
height: 100%;
}
/* 可以在这里添加你的业务样式 */
</style>

View File

@@ -1,23 +0,0 @@
/**
* 项目配置文件
*/
export default {
// 系统标题
title: 'Demo 管理系统',
// API 基础路径
apiUrl: 'http://localhost:9098/admin_api/',
// 文件上传路径
uploadUrl: 'http://localhost:9098/admin_api/upload',
// Token 存储的 key
tokenKey: 'demo_token',
// 其他配置
timeout: 30000,
// 是否显示页面加载进度条
showProgressBar: true
}

View File

@@ -1,92 +0,0 @@
import Vue from 'vue'
import VueRouter from 'vue-router'
import Vuex from 'vuex'
import ViewUI from 'view-design'
import createPersistedState from 'vuex-persistedstate'
import 'view-design/dist/styles/iview.css'
// 引入框架(使用打包好的框架 JS
import AdminFramework from './libs/admin-framework.js'
// 引入配置
import config from './config'
// 引入根组件
import App from './App.vue'
// 引入业务页面(根据后端权限菜单接口返回的组件路径导入)
import ProductList from './views/business/product_list.vue'
// 根据你的权限菜单接口,导入所有可能用到的业务组件:
// import GamesComponent from './views/ball/games.vue'
// import PayOrdersComponent from './views/order/pay_orders.vue'
// import WchUsersComponent from './views/ball/wch_users.vue'
// ... 导入更多业务组件
// 🎉 使用框架 - 自动完成所有初始化
Vue.use(AdminFramework, {
config,
ViewUI,
VueRouter,
Vuex,
createPersistedState,
// ✅ 在这里一次性注册所有业务组件映射
componentMap: {
// 业务组件映射(根据后端菜单中的 component 字段配置)
'business/product_list': ProductList
// 根据权限菜单接口返回的 component 字段添加映射:
// 'ball/games': GamesComponent,
// 'order/pay_orders': PayOrdersComponent,
// 'ball/wch_users': WchUsersComponent,
// 'order/wch_wallets': WchWalletsComponent,
// 'users/user_follows': UserFollowsComponent,
// ... 添加更多业务组件
}
})
// 添加自定义业务路由(手动添加的路由)
const businessRoutes = [
{
path: '/business/product',
name: 'product_list',
meta: { title: '产品列表' },
component: ProductList
}
]
// 将业务路由添加到主路由中
const mainRoute = AdminFramework.router.options.routes.find(r => r.path === '/')
if (mainRoute && mainRoute.children) {
mainRoute.children.push(...businessRoutes)
}
// 创建 Vue 实例
window.rootVue = new Vue({
el: '#app',
router: AdminFramework.router,
store: AdminFramework.store,
render: h => h(App),
mounted() {
// 设置响应式适配
AdminFramework.uiTool.setRem()
// 只在已登录时获取系统标题
const token = this.$store.state.user.token
if (token) {
this.$store.dispatch('app/getSysTitle', {
defaultTitle: 'Demo 管理系统',
defaultLogo: ''
})
} else {
// 未登录时,直接设置默认标题
document.title = 'Demo 管理系统'
}
}
})
// 响应式适配
window.addEventListener('load', AdminFramework.uiTool.setRem)
window.addEventListener('resize', AdminFramework.uiTool.setRem)
console.log('✅ Demo 项目启动成功!')
console.log('框架版本:', AdminFramework.version)

View File

@@ -1,193 +0,0 @@
<template>
<div class="product-list">
<h2>产品列表</h2>
<div class="toolbar">
<Button type="primary" @click="handleAdd">新增产品</Button>
<Button @click="handleRefresh">刷新</Button>
</div>
<Table
:columns="columns"
:data="list"
:loading="loading"
border
stripe
/>
<div class="page-wrapper">
<Page
:total="total"
:current="page"
:page-size="page_size"
show-total
show-elevator
@on-change="handlePageChange"
/>
</div>
</div>
</template>
<script>
export default {
name: 'product_list',
data() {
return {
loading: false,
list: [],
total: 0,
page: 1,
page_size: 10,
columns: [
{
title: 'ID',
key: 'id',
width: 80
},
{
title: '产品名称',
key: 'name'
},
{
title: '价格',
key: 'price',
render: (h, params) => {
return h('span', '¥' + params.row.price)
}
},
{
title: '状态',
key: 'status',
render: (h, params) => {
const statusMap = {
1: { text: '上架', color: 'success' },
0: { text: '下架', color: 'default' }
}
const status = statusMap[params.row.status] || statusMap[0]
return h('Tag', { props: { color: status.color } }, status.text)
}
},
{
title: '操作',
key: 'action',
width: 200,
render: (h, params) => {
return h('div', [
h('Button', {
props: { type: 'primary', size: 'small' },
style: { marginRight: '5px' },
on: {
click: () => {
this.handleEdit(params.row)
}
}
}, '编辑'),
h('Button', {
props: { type: 'error', size: 'small' },
on: {
click: () => {
this.handleDelete(params.row)
}
}
}, '删除')
])
}
}
]
}
},
mounted() {
this.getData()
},
methods: {
// 获取数据
async getData() {
this.loading = true
// 模拟数据(实际项目中从 API 获取)
setTimeout(() => {
this.list = [
{ id: 1, name: '产品 A', price: 99.00, status: 1 },
{ id: 2, name: '产品 B', price: 199.00, status: 1 },
{ id: 3, name: '产品 C', price: 299.00, status: 0 },
{ id: 4, name: '产品 D', price: 399.00, status: 1 }
]
this.total = 4
this.loading = false
}, 500)
// 实际项目中使用:
// try {
// const res = await this.$http.post('product/list', {
// page: this.page,
// page_size: this.page_size
// })
// this.list = res.data.list
// this.total = res.data.total
// } catch (error) {
// this.$Message.error('获取数据失败')
// } finally {
// this.loading = false
// }
},
// 新增
handleAdd() {
this.$Message.info('打开新增弹窗')
},
// 编辑
handleEdit(row) {
this.$Message.info('编辑产品: ' + row.name)
},
// 删除
handleDelete(row) {
this.$Modal.confirm({
title: '确认删除',
content: `确定要删除产品 "${row.name}" 吗?`,
onOk: () => {
this.$Message.success('删除成功')
this.getData()
}
})
},
// 刷新
handleRefresh() {
this.getData()
},
// 翻页
handlePageChange(page) {
this.page = page
this.getData()
}
}
}
</script>
<style scoped lang="less">
.product-list {
padding: 20px;
h2 {
margin-bottom: 20px;
color: #2d8cf0;
}
.toolbar {
margin-bottom: 15px;
button {
margin-right: 10px;
}
}
.page-wrapper {
margin-top: 20px;
text-align: right;
}
}
</style>

View File

@@ -1,38 +0,0 @@
@echo off
echo ====================================
echo Admin Framework Demo 启动脚本
echo ====================================
echo.
:: 检查关键依赖是否存在
if not exist "node_modules\@vue\babel-preset-jsx\" (
echo [1/2] 首次运行或依赖缺失,正在安装依赖...
echo.
call npm install
echo.
echo [提示] 如果仍有错误,请运行以下命令:
echo npm install @vue/babel-preset-jsx brace vue2-ace-editor --save
echo.
) else (
echo [✓] 依赖已安装
echo.
)
echo [2/2] 启动开发服务器...
echo.
echo 浏览器将自动打开 http://localhost:8080
echo.
echo 可访问:
echo - /login - 登录页面
echo - /home - 主页
echo - /business/product - 业务示例
echo.
echo 按 Ctrl+C 停止服务器
echo.
echo ====================================
echo.
call npm run dev
pause

View File

@@ -1,34 +0,0 @@
#!/bin/bash
echo "===================================="
echo " Admin Framework Demo 启动脚本"
echo "===================================="
echo ""
# 检查 node_modules 是否存在
if [ ! -d "node_modules" ]; then
echo "[1/2] 首次运行,正在安装依赖..."
echo ""
npm install
echo ""
else
echo "[✓] 依赖已安装"
echo ""
fi
echo "[2/2] 启动开发服务器..."
echo ""
echo "浏览器将自动打开 http://localhost:8080"
echo ""
echo "可访问:"
echo " - /login - 登录页面"
echo " - /home - 主页"
echo " - /business/product - 业务示例"
echo ""
echo "按 Ctrl+C 停止服务器"
echo ""
echo "===================================="
echo ""
npm run dev

View File

@@ -1,9 +0,0 @@
// 测试引用框架源码
try {
const AdminFramework = require('../src/index.js')
console.log('✅ 框架引用成功!')
console.log('框架版本:', AdminFramework.version || AdminFramework.default?.version)
} catch (error) {
console.error('❌ 框架引用失败:', error.message)
}

View File

@@ -1,115 +0,0 @@
const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const { VueLoaderPlugin } = require('vue-loader')
module.exports = (env, argv) => {
const isDevelopment = argv.mode === 'development'
return {
entry: './src/main.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: isDevelopment ? 'bundle.js' : 'bundle.[contenthash:8].js',
clean: true
},
// 开发模式使用高质量的 source map方便调试
devtool: isDevelopment ? 'eval-source-map' : 'source-map',
module: {
rules: [
{
test: /\.vue$/,
loader: 'vue-loader'
},
{
test: /\.js$/,
loader: 'babel-loader',
exclude: /node_modules/
},
{
test: /\.css$/,
use: [
'vue-style-loader',
{
loader: 'css-loader',
options: {
sourceMap: isDevelopment
}
}
]
},
{
test: /\.less$/,
use: [
'vue-style-loader',
{
loader: 'css-loader',
options: {
sourceMap: isDevelopment
}
},
{
loader: 'less-loader',
options: {
sourceMap: isDevelopment
}
}
]
},
{
test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
loader: 'url-loader',
options: {
limit: 10000,
name: 'images/[name].[hash:7].[ext]',
esModule: false
}
},
{
test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
loader: 'url-loader',
options: {
limit: 10000,
name: 'fonts/[name].[hash:7].[ext]',
esModule: false
}
}
]
},
plugins: [
new VueLoaderPlugin(),
new HtmlWebpackPlugin({
template: './public/index.html',
filename: 'index.html'
})
],
resolve: {
extensions: ['.js', '.vue', '.json'],
alias: {
// 框架源码的别名(必须在前面,优先级高)
'@': path.resolve(__dirname, '../src'),
'@component': path.resolve(__dirname, '../src/components'),
'@utils': path.resolve(__dirname, '../src/utils'),
'@api': path.resolve(__dirname, '../src/api'),
'@config': path.resolve(__dirname, '../src/config'),
'@assets': path.resolve(__dirname, '../src/assets'),
// demo 项目的别名
'~': path.resolve(__dirname, 'src'),
'vue$': 'vue/dist/vue.esm.js'
}
},
devServer: {
port: 8080,
hot: true,
open: true,
historyApiFallback: true,
// 启用覆盖层显示编译错误
client: {
overlay: {
errors: true,
warnings: false
}
}
}
}
}

View File

@@ -1,206 +0,0 @@
# 使用打包框架说明
## ✅ 已完成的修改
Demo 项目现在使用打包好的框架 JS 文件,而不是直接引用源码。
### 修改内容
**文件**: `demo-project/src/main.js`
```javascript
// 修改前(直接使用源码)
import AdminFramework from '../../src/index.js'
// 修改后(使用打包好的框架)
import AdminFramework from './libs/admin-framework.js'
```
### 文件结构
```
demo-project/
├── src/
│ ├── libs/
│ │ └── admin-framework.js ← 打包好的框架文件
│ ├── main.js ← 引用框架的入口文件
│ └── ...
└── ...
```
## 🔄 更新框架的步骤
当框架源码(`src/` 目录)有更新时,需要重新打包并复制到 demo 项目:
### 方法一:使用 PowerShell 命令(推荐)
```powershell
# 1. 在项目根目录打包框架
npm run build
# 2. 复制到 demo 项目
if (-not (Test-Path "demo-project\src\libs")) {
New-Item -ItemType Directory -Path "demo-project\src\libs" -Force | Out-Null
}
Copy-Item "dist\admin-framework.js" "demo-project\src\libs\admin-framework.js" -Force
Write-Host "✅ 复制成功!" -ForegroundColor Green
```
### 方法二:手动操作
1. **打包框架**
```bash
# 在项目根目录
npm run build
```
2. **复制文件**
- 将 `dist/admin-framework.js` 复制到 `demo-project/src/libs/admin-framework.js`
3. **重启开发服务器**
```bash
cd demo-project
npm run dev
```
## 📊 优势
### 使用打包框架的优势
1. **✅ 性能更好**
- 打包后的文件经过优化和压缩
- 减少了模块解析时间
2. **✅ 更接近生产环境**
- Demo 项目的使用方式和实际项目一致
- 更容易发现潜在问题
3. **✅ 依赖隔离**
- Demo 项目不需要安装框架的所有依赖
- 减少了依赖冲突的可能性
4. **✅ 更清晰的边界**
- 框架和业务代码分离更明确
- 便于理解框架的使用方式
### 使用源码的优势(调试时)
1. **✅ 实时更新**
- 修改源码后立即生效
- 不需要重新打包
2. **✅ 调试方便**
- 可以直接在源码中打断点
- 错误堆栈更清晰
## 🔧 开发建议
### 开发框架时
**使用源码引用**(临时修改):
```javascript
// demo-project/src/main.js
import AdminFramework from '../../src/index.js'
```
**优点**
- 修改框架源码后立即生效
- 方便调试和测试
### 测试框架时
**使用打包文件**(当前配置):
```javascript
// demo-project/src/main.js
import AdminFramework from './libs/admin-framework.js'
```
**优点**
- 测试打包后的实际效果
- 发现打包可能引入的问题
## 📝 注意事项
1. **打包后需要复制**
- 每次修改框架源码并打包后,需要重新复制到 demo 项目
- 否则 demo 项目使用的还是旧版本
2. **Source Map**
- 打包时会生成 source map 文件
- 方便在浏览器中调试打包后的代码
3. **版本管理**
- `demo-project/src/libs/admin-framework.js` 不应该提交到 Git
- 应该在 `.gitignore` 中忽略这个文件
4. **依赖更新**
- 如果框架的依赖有更新,需要重新打包
- Demo 项目不需要安装框架的依赖
## 🎯 快速命令
### 一键更新框架到 Demo 项目
```powershell
# 打包并复制
npm run build; if (-not (Test-Path "demo-project\src\libs")) { New-Item -ItemType Directory -Path "demo-project\src\libs" -Force | Out-Null }; Copy-Item "dist\admin-framework.js" "demo-project\src\libs\admin-framework.js" -Force; Write-Host "✅ 框架已更新到 Demo 项目!" -ForegroundColor Green
```
### 启动 Demo 项目
```bash
cd demo-project
npm run dev
```
## 📚 相关文件
- `build.bat` / `build.sh` - 框架打包脚本
- `webpack.config.js` - Webpack 配置文件
- `dist/admin-framework.js` - 打包后的框架文件
- `demo-project/src/libs/admin-framework.js` - Demo 项目使用的框架文件
- `demo-project/src/main.js` - Demo 项目入口文件
## 🔍 故障排查
### 问题修改框架源码后Demo 项目没有变化
**原因**Demo 项目使用的是打包后的文件,不会自动更新
**解决方案**
1. 重新打包框架:`npm run build`
2. 复制到 Demo 项目(使用上面的 PowerShell 命令)
3. 重启 Demo 项目的开发服务器
### 问题:找不到 admin-framework.js 文件
**原因**:还没有复制打包文件到 Demo 项目
**解决方案**
```powershell
# 确保先打包
npm run build
# 然后复制
if (-not (Test-Path "demo-project\src\libs")) {
New-Item -ItemType Directory -Path "demo-project\src\libs" -Force | Out-Null
}
Copy-Item "dist\admin-framework.js" "demo-project\src\libs\admin-framework.js" -Force
```
### 问题:控制台报错找不到模块
**原因**:可能是打包配置有问题,或者依赖没有正确打包
**解决方案**
1. 检查 `webpack.config.js` 配置
2. 确保所有依赖都已安装
3. 重新打包:`npm run build`
4. 查看打包日志是否有错误
---
**当前状态**:✅ Demo 项目已配置为使用打包后的框架文件
**下一步**:启动 Demo 项目测试:`cd demo-project && npm run dev`

View File

@@ -1,119 +0,0 @@
# Demo 项目启动说明
## ✅ 配置完成
Demo 项目已配置为使用打包好的框架 JS 文件。
## 🚀 启动步骤
### 1. 确保框架文件已复制
检查文件是否存在:
```
demo-project/src/libs/admin-framework.js
```
如果不存在,在项目根目录执行:
```powershell
Copy-Item "dist\admin-framework.js" "demo-project\src\libs\admin-framework.js" -Force
```
### 2. 启动开发服务器
**方法一:使用命令行**
```bash
cd demo-project
npm run dev
```
**方法二:使用 start.batWindows**
```bash
cd demo-project
start.bat
```
**方法三:使用 start.shLinux/Mac**
```bash
cd demo-project
./start.sh
```
### 3. 访问应用
打开浏览器访问:
- **开发环境**http://localhost:8080
- **测试账号**admin / admin123
## 📝 注意事项
1. **端口占用**
- 如果 8080 端口被占用webpack 会自动使用其他端口
- 查看终端输出的实际端口号
2. **首次启动**
- 首次启动可能需要较长时间编译
- 等待 "Compiled successfully" 消息
3. **热更新**
- 修改代码后会自动刷新浏览器
- 如果没有自动刷新,手动刷新页面
## 🔍 故障排查
### 问题:找不到 admin-framework.js
**错误信息**
```
Module not found: Error: Can't resolve './libs/admin-framework.js'
```
**解决方案**
```powershell
# 在项目根目录执行
Copy-Item "dist\admin-framework.js" "demo-project\src\libs\admin-framework.js" -Force
```
### 问题:端口被占用
**错误信息**
```
Error: listen EADDRINUSE: address already in use :::8080
```
**解决方案**
1. 关闭占用 8080 端口的程序
2. 或修改 `webpack.config.js` 中的端口配置
### 问题:编译错误
**解决方案**
1. 检查 `src/main.js` 的引用路径是否正确
2. 确保 `admin-framework.js` 文件完整
3. 删除 `node_modules` 重新安装:
```bash
rm -rf node_modules
npm install
```
## 📚 相关文档
- `使用打包框架说明.md` - 详细使用说明
- `框架更新完成.md` - 更新记录
- `README.md` - 项目说明
## 🎯 下一步
启动成功后:
1. 使用测试账号登录
2. 测试菜单导航功能
3. 测试系统管理功能
4. 查看浏览器控制台,确保没有错误
---
**当前状态**:✅ 就绪
**框架版本**1.0.0
**启动命令**`npm run dev`

View File

@@ -1,157 +0,0 @@
# 框架更新完成 ✅
## 📝 更新内容
Demo 项目已成功切换为使用打包好的框架 JS 文件。
### 修改的文件
1. **`demo-project/src/main.js`**
```javascript
// 修改前
import AdminFramework from '../../src/index.js'
// 修改后
import AdminFramework from './libs/admin-framework.js'
```
2. **`demo-project/.gitignore`**
```
# 新增
src/libs/admin-framework.js
```
3. **新增文件**
- `demo-project/src/libs/admin-framework.js` - 打包好的框架文件
- `demo-project/使用打包框架说明.md` - 使用说明文档
## 🎯 当前状态
- ✅ 框架已打包:`dist/admin-framework.js`
- ✅ 已复制到 Demo 项目:`demo-project/src/libs/admin-framework.js`
- ✅ Demo 项目已配置为使用打包文件
- ✅ `.gitignore` 已更新,忽略框架文件
## 🚀 启动 Demo 项目
```bash
cd demo-project
npm run dev
```
访问http://localhost:8080
## 🔄 更新框架的步骤
当框架源码有更新时:
### 快速更新(一键命令)
```powershell
# 在项目根目录执行
npm run build; Copy-Item "dist\admin-framework.js" "demo-project\src\libs\admin-framework.js" -Force; Write-Host "✅ 框架已更新!" -ForegroundColor Green
```
### 分步操作
```bash
# 1. 打包框架
npm run build
# 2. 复制到 Demo 项目PowerShell
Copy-Item "dist\admin-framework.js" "demo-project\src\libs\admin-framework.js" -Force
# 3. 重启 Demo 项目(如果正在运行)
cd demo-project
npm run dev
```
## 📊 优势
### 使用打包框架的好处
1. **性能更好** - 打包后的文件经过优化
2. **更接近生产环境** - 和实际使用方式一致
3. **依赖隔离** - Demo 项目不需要框架的所有依赖
4. **边界清晰** - 框架和业务代码分离明确
### 开发时的建议
**调试框架时**:临时改回源码引用
```javascript
// demo-project/src/main.js
import AdminFramework from '../../src/index.js'
```
**测试框架时**:使用打包文件(当前配置)
```javascript
// demo-project/src/main.js
import AdminFramework from './libs/admin-framework.js'
```
## 📚 相关文档
- `demo-project/使用打包框架说明.md` - 详细使用说明
- `完整使用文档.md` - 框架完整文档
- `README.md` - 项目说明
## 🔍 故障排查
### 问题修改框架源码后Demo 项目没有变化
**解决**
```powershell
# 重新打包并复制
npm run build
Copy-Item "dist\admin-framework.js" "demo-project\src\libs\admin-framework.js" -Force
```
### 问题:找不到 admin-framework.js
**解决**
```powershell
# 确保文件已复制
if (-not (Test-Path "demo-project\src\libs\admin-framework.js")) {
Write-Host "❌ 文件不存在,正在复制..." -ForegroundColor Yellow
Copy-Item "dist\admin-framework.js" "demo-project\src\libs\admin-framework.js" -Force
Write-Host "✅ 复制完成!" -ForegroundColor Green
}
```
### 问题:控制台报错
**检查**
1. 确保框架已正确打包:`npm run build`
2. 确保文件已复制到正确位置
3. 查看浏览器控制台的详细错误信息
4. 检查 `demo-project/src/main.js` 的引用路径
## 🎉 下一步
1. **启动 Demo 项目**
```bash
cd demo-project
npm run dev
```
2. **访问应用**
- 打开浏览器访问http://localhost:8080
- 使用测试账号登录
3. **测试功能**
- 登录功能
- 菜单导航
- 系统管理功能
4. **查看控制台**
- 确保没有错误
- 查看框架版本信息
---
**更新完成时间**2025-10-08
**框架版本**1.0.0
**状态**:✅ 就绪

View File

@@ -1,175 +0,0 @@
# 注释乱码修复说明
## 🐛 问题描述
控制台出现多个错误,主要原因是 `src/index.js` 文件中的中文注释出现了乱码,导致:
1. **Upload 组件错误**`TypeError: Cannot read properties of undefined (reading 'user')`
- 原因:`src/components/upload/Single.vue``Multiple.vue` 中使用了 `store.state.user.token`,但 store 未正确初始化
2. **TreeGrid 组件错误**`ReferenceError: Cannot access '__WEBPACK_DEFAULT_EXPORT__' before initialization`
- 原因:`src/components/treeGrid/component/subTreeGrid.vue` 中有循环引用问题
3. **LoginPage 未定义错误**`ReferenceError: LoginPage is not defined`
- 原因:`src/index.js` 第43行的 import 语句和注释在同一行,导致 import 被注释掉
4. **Editor 未定义错误**`ReferenceError: Editor is not defined`
- 原因:`registerGlobalComponents` 方法中引用了未导入的组件
5. **map 未定义错误**`ReferenceError: map is not defined`
- 原因:`setupComponentMap` 方法中的注释格式不对,导致代码被注释掉
## ✅ 已修复的问题
### 1. Upload 组件修复
**修改文件**
- `src/components/upload/Single.vue`
- `src/components/upload/Multiple.vue`
**修改内容**
```javascript
// 修改前
import store from '@/store'
let headers = {
'admin-token': store.state.user.token,
}
// 修改后
import { getToken } from '@/utils/tools'
let headers = {
'admin-token': getToken(),
}
```
**原因**
- 使用 `getToken()` 函数从 localStorage 获取 token避免依赖 store 初始化顺序
### 2. TreeGrid 组件修复
**修改文件**
- `src/components/treeGrid/component/subTreeGrid.vue`
**修改内容**
```javascript
// 修改前
import SubTreeGrid from './subTreeGrid.vue'
export default {
components: {
SubTreeGrid,
// ...
}
}
// 修改后
export default {
components: {
SubTreeGrid: () => import('./subTreeGrid.vue'), // 使用异步组件
// ...
}
}
```
**原因**
- 递归组件需要使用异步组件来避免循环引用问题
## ⚠️ 待修复的问题
### 3. src/index.js 文件乱码
**问题**
- 文件中的中文注释出现乱码(如:`閫氱敤鍚庡彴绠$悊绯荤粺妗嗘灦` 应该是 `通用后台管理系统框架`
- 第43行的 import 语句和注释在同一行
- `registerGlobalComponents` 方法中有重复的组件注册
- `setupComponentMap` 方法中的注释格式不对
**需要修复的关键行**
#### 第43行最关键
```javascript
// 当前(错误)
// 鐧诲綍鍜岄敊璇〉闈?import LoginPage from './views/login/login.vue'
// 应该改为
// 登录和错误页面
import LoginPage from './views/login/login.vue'
```
#### registerGlobalComponents 方法
```javascript
// 删除重复的组件注册第218-235行
// 只保留第206-216行的组件注册
```
#### setupComponentMap 方法
```javascript
// 第234行
// 当前(错误)
// 鍚堝苟澶栭儴浼犲叆鐨勭粍浠舵槧灏? ...customMap
// 应该改为
// 合并外部传入的组件映射
...customMap
// 第237行
// 当前(错误)
// 鑷姩鐢熸垚甯?.vue 鍜屼笉甯?.vue 鐨勬槧灏? const map = {}
// 应该改为
// 自动生成带.vue 和不带.vue 的映射
const map = {}
```
## 🔧 修复方法
### 方法一:使用 Git 恢复 + 手动修复
```bash
# 1. 恢复文件到最近的正确版本
git checkout src/index.js
# 2. 手动修复关键问题(使用编辑器)
# - 确保第43行的 import 语句独立一行
# - 删除重复的组件注册
# - 修复注释格式
```
### 方法二:重新创建文件
由于乱码问题严重,建议:
1. 备份当前文件
2. 从 Git 历史中找到最近的正确版本
3. 重新应用必要的修改
## 📝 预防措施
1. **使用 UTF-8 编码保存文件**
- 确保编辑器设置为 UTF-8 编码
- 避免使用 ANSI 或 GBK 编码
2. **避免注释和代码在同一行**
- 注释应该独立一行
- 特别是 import 语句前的注释
3. **定期检查文件编码**
- 使用 `file` 命令检查文件编码
- 使用 `iconv` 或编辑器转换编码
## 🎯 下一步
1. 修复 `src/index.js` 文件的编码问题
2. 确保所有中文注释正确显示
3. 测试页面是否正常加载
4. 检查控制台是否还有错误
## 📚 相关文件
- `src/index.js` - 框架入口文件(需要修复)
- `src/components/upload/Single.vue` - 已修复
- `src/components/upload/Multiple.vue` - 已修复
- `src/components/treeGrid/component/subTreeGrid.vue` - 已修复
---
**修复状态**:部分完成,等待 `src/index.js` 文件修复

64
package-lock.json generated
View File

@@ -24,11 +24,13 @@
"devDependencies": {
"@babel/core": "^7.12.0",
"@babel/preset-env": "^7.12.0",
"autoprefixer": "^10.4.21",
"babel-loader": "^8.2.0",
"css-loader": "^5.0.0",
"file-loader": "^6.2.0",
"less": "^4.0.0",
"less-loader": "^7.0.0",
"postcss": "^8.5.6",
"style-loader": "^2.0.0",
"url-loader": "^4.1.0",
"vue-loader": "^15.9.0",
@@ -2455,6 +2457,44 @@
"license": "MIT",
"peer": true
},
"node_modules/autoprefixer": {
"version": "10.4.21",
"resolved": "https://registry.npmmirror.com/autoprefixer/-/autoprefixer-10.4.21.tgz",
"integrity": "sha512-O+A6LWV5LDHSJD3LjHYoNi4VLsj/Whi7k6zG12xTYaU4cQ8oxQGckXNX8cRHK5yOZ/ppVHe0ZBXGzSV9jXdVbQ==",
"dev": true,
"funding": [
{
"type": "opencollective",
"url": "https://opencollective.com/postcss/"
},
{
"type": "tidelift",
"url": "https://tidelift.com/funding/github/npm/autoprefixer"
},
{
"type": "github",
"url": "https://github.com/sponsors/ai"
}
],
"license": "MIT",
"dependencies": {
"browserslist": "^4.24.4",
"caniuse-lite": "^1.0.30001702",
"fraction.js": "^4.3.7",
"normalize-range": "^0.1.2",
"picocolors": "^1.1.1",
"postcss-value-parser": "^4.2.0"
},
"bin": {
"autoprefixer": "bin/autoprefixer"
},
"engines": {
"node": "^10 || ^12 || >=14"
},
"peerDependencies": {
"postcss": "^8.1.0"
}
},
"node_modules/axios": {
"version": "0.21.4",
"resolved": "https://registry.npmmirror.com/axios/-/axios-0.21.4.tgz",
@@ -3209,6 +3249,20 @@
}
}
},
"node_modules/fraction.js": {
"version": "4.3.7",
"resolved": "https://registry.npmmirror.com/fraction.js/-/fraction.js-4.3.7.tgz",
"integrity": "sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==",
"dev": true,
"license": "MIT",
"engines": {
"node": "*"
},
"funding": {
"type": "patreon",
"url": "https://github.com/sponsors/rawify"
}
},
"node_modules/function-bind": {
"version": "1.1.2",
"resolved": "https://registry.npmmirror.com/function-bind/-/function-bind-1.1.2.tgz",
@@ -3816,6 +3870,16 @@
"integrity": "sha512-cCmFDMSm26S6tQSDpBCg/NR8NENrVPhAJSf+XbxBG4rPFaaonlEoE9wHQmun+cls499TQGSb7ZyPBRlzgKfpeg==",
"license": "MIT"
},
"node_modules/normalize-range": {
"version": "0.1.2",
"resolved": "https://registry.npmmirror.com/normalize-range/-/normalize-range-0.1.2.tgz",
"integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/p-limit": {
"version": "2.3.0",
"resolved": "https://registry.npmmirror.com/p-limit/-/p-limit-2.3.0.tgz",

View File

@@ -38,11 +38,13 @@
"devDependencies": {
"@babel/core": "^7.12.0",
"@babel/preset-env": "^7.12.0",
"autoprefixer": "^10.4.21",
"babel-loader": "^8.2.0",
"css-loader": "^5.0.0",
"file-loader": "^6.2.0",
"less": "^4.0.0",
"less-loader": "^7.0.0",
"postcss": "^8.5.6",
"style-loader": "^2.0.0",
"url-loader": "^4.1.0",
"vue-loader": "^15.9.0",

16
postcss.config.js Normal file
View File

@@ -0,0 +1,16 @@
// PostCSS 配置文件
// 用于处理 CSS 样式转换和优化
module.exports = {
plugins: {
// 自动添加浏览器前缀
autoprefixer: {
overrideBrowserslist: [
'> 1%',
'last 2 versions',
'not dead',
'not ie <= 11'
]
}
}
}