This commit is contained in:
张成
2025-10-20 18:18:27 +08:00
parent 0047086013
commit fd3c1a5563
8 changed files with 479 additions and 107 deletions

View File

@@ -0,0 +1,9 @@
{
"permissions": {
"allow": [
"Bash(npm run build:*)"
],
"deny": [],
"ask": []
}
}

View File

@@ -2,6 +2,33 @@
一个基于 Vue2 的通用后台管理系统框架,包含完整的系统功能、登录、路由管理、布局等核心功能。
## ✨ 新版本亮点
**使用超级简单!只需 20 行代码即可启动完整的后台管理系统!**
```javascript
// 引入框架(内置所有依赖)
import AdminFramework from './admin-framework.js'
import componentMap from './router/component-map.js'
// 一行搞定!
const app = AdminFramework.createApp({
title: '我的管理系统',
apiUrl: 'http://localhost:9098/admin_api/', // uploadUrl 会自动设置
componentMap: componentMap
})
app.$mount('#app')
```
**对比旧版本:**
- 代码量减少 **75%+**(从 80+ 行到 20 行)
- **无需手动引入** Vue、VueRouter、Vuex、ViewUI
- **无需手动配置** 路由、状态管理
- **自动处理** 菜单恢复、标题设置
👉 查看详细说明:[简化使用说明.md](./简化使用说明.md)
## 📦 项目结构
```
@@ -21,7 +48,7 @@ admin-framework/
│ │ └── system_high/ # 高级系统页面
│ └── index.js # 框架入口
├── dist/ # 打包产物
│ └── admin-framework.js # 框架打包文件(1.64 MB
│ └── admin-framework.js # 框架打包文件(3.6 MB,内置所有依赖
├── demo-project/ # 完整示例项目 ⭐
│ ├── src/
│ │ ├── config/ # 配置
@@ -101,6 +128,10 @@ npm run build
## ✨ 特性
### 核心功能
-**极简使用** - 只需 20 行代码启动完整系统
-**内置依赖** - Vue、VueRouter、Vuex、ViewUI 全部内置
-**自动配置** - 自动初始化路由、状态管理、菜单恢复
-**主页组件** - 欢迎页面,自动显示系统标题
-**系统管理页面** - 用户、角色、菜单等管理
-**登录和错误页面** - 完整的登录流程和错误处理
@@ -111,6 +142,8 @@ npm run build
## 📚 文档
- **⚡ 快速开始**[快速开始.md](./快速开始.md) - **5 分钟上手指南**
- **🔥 简化使用说明**[简化使用说明.md](./简化使用说明.md) - **详细对比和说明**
- **完整使用文档**[完整使用文档.md](./完整使用文档.md)
- **Demo 项目说明**[demo-project/README.md](./demo-project/README.md)
- **安装指南**[demo-project/INSTALL.md](./demo-project/INSTALL.md)

View File

@@ -1,91 +1,22 @@
// 引入依赖
import Vue from 'vue'
import VueRouter from 'vue-router'
import Vuex from 'vuex'
import ViewUI from 'view-design'
// 引入样式
import 'view-design/dist/styles/iview.css'
// 引入 Admin Framework使用本地构建的文件
// 引入 Admin Framework框架内部已包含所有依赖和样式
import AdminFramework from '../../dist/admin-framework.js'
// 引入组件映射表
import componentMap from './router/component-map.js'
// 【关键】先将框架暴露到全局,确保在任何代码执行前就可以访问
window.framework = AdminFramework
// 使用插件
Vue.use(ViewUI)
// 配置参数
const config = {
// 【超级简化】只需一个函数调用!
const app = AdminFramework.createApp({
title: 'tennis管理系统',
apiUrl: 'http://localhost:9098/admin_api/', // 修改为你的 API 地址
uploadUrl: 'http://localhost:9098/admin_api/upload' // 修改为你的上传地址
}
// 初始化框架
AdminFramework.install(Vue, {
config: config,
ViewUI: ViewUI,
VueRouter: VueRouter,
Vuex: Vuex,
createPersistedState: null,
componentMap: componentMap // 传入组件映射表,用于动态路由
})
// 创建 Vue 实例
const app = new Vue({
router: AdminFramework.router,
store: AdminFramework.store,
render: h => h('router-view'),
async created() {
console.log('=== Admin Framework Demo 启动成功 ===')
console.log('框架版本:', AdminFramework.version)
console.log('配置信息:', this.$config)
// 刷新时恢复菜单和标题
const token = this.$store.state.user.token
const authorityMenus = localStorage.getItem('authorityMenus')
if (token && authorityMenus) {
console.log('检测到登录状态,恢复菜单和标题...')
try {
// 先恢复菜单
await this.$store.dispatch('user/setAuthorityMenus', {
Main: AdminFramework.Main,
ParentView: AdminFramework.ParentView,
Page404: AdminFramework.Page404,
authorityMenus: authorityMenus
})
console.log('菜单恢复成功')
// 再获取系统标题(已登录,会从接口获取)
await this.$store.dispatch('app/getSysTitle', {
defaultTitle: this.$config.title,
defaultLogo: ''
})
} catch (error) {
console.error('恢复失败:', error)
}
} else {
// 未登录,使用默认标题
console.log('未登录,使用默认标题')
document.title = this.$config.title
}
apiUrl: 'http://localhost:9098/admin_api/', // API 地址uploadUrl 会自动设置为 apiUrl + 'upload'
componentMap: componentMap, // 传入组件映射表,用于动态路由
onReady() {
// 可选:应用启动完成后的回调
console.log('应用已准备就绪!')
}
})
// 挂载应用
app.$mount('#app')
// 全局暴露 app 实例(方便调试)
window.app = app
window.rootVue = app
// window.framework 已在文件开头暴露,无需重复

View File

@@ -41,69 +41,55 @@ import WchProfessions from '../views/users/wch_professions.vue'
/**
* 组件映射对象
* key: 后端返回的组件路径(去掉 .vue 后缀或保留都可以)
*
* ✅ 重要提示:只需传递不带 .vue 后缀的路径!
* 框架会自动为每个组件创建带 .vue 和不带 .vue 的两个映射
*
* 例如:'ai/ai_messages': AiMessages
* 框架自动处理为:
* - 'ai/ai_messages' → AiMessages
* - 'ai/ai_messages.vue' → AiMessages (自动添加)
*
* key: 后端返回的组件路径(不带 .vue 后缀)
* value: 实际的 Vue 组件
*/
const componentMap = {
// ===== AI 模块 =====
'ai/ai_messages': AiMessages,
'ai/ai_messages.vue': AiMessages,
// ===== 球场模块 =====
'ball/game_comments': GameComments,
'ball/game_comments.vue': GameComments,
'ball/game_participants': GameParticipants,
'ball/game_participants.vue': GameParticipants,
'ball/games': Games,
'ball/games.vue': Games,
'ball/venues': Venues,
'ball/venues.vue': Venues,
'ball/wch_users': WchUsers,
'ball/wch_users.vue': WchUsers,
// ===== 业务模块 =====
'business/hot_city_qr': HotCityQr,
'business/hot_city_qr.vue': HotCityQr,
// ===== 消息模块 =====
'message/msg_notifications': MsgNotifications,
'message/msg_notifications.vue': MsgNotifications,
// ===== NTRP 模块 =====
'ntrp/ntr_questions': NtrQuestions,
'ntrp/ntr_questions.vue': NtrQuestions,
'ntrp/ntr_records': NtrRecords,
'ntrp/ntr_records.vue': NtrRecords,
// ===== 订单模块 =====
'order/frozen_funds': FrozenFunds,
'order/frozen_funds.vue': FrozenFunds,
'order/pay_orders': PayOrders,
'order/pay_orders.vue': PayOrders,
'order/transfer_details': TransferDetails,
'order/transfer_details.vue': TransferDetails,
'order/wallet_transactions': WalletTransactions,
'order/wallet_transactions.vue': WalletTransactions,
'order/wch_wallets': WchWallets,
'order/wch_wallets.vue': WchWallets,
// ===== 统计模块 =====
'statistics/resources': Resources,
'statistics/resources.vue': Resources,
// ===== 用户模块 =====
'users/recommend_blocks': RecommendBlocks,
'users/recommend_blocks.vue': RecommendBlocks,
'users/user_follows': UserFollows,
'users/user_follows.vue': UserFollows,
'users/user_tracking': UserTracking,
'users/user_tracking.vue': UserTracking,
"users/wch_cities.vue": WchCities,
"users/wch_cities": WchCities,
"users/wch_professions.vue": WchProfessions,
"users/wch_professions": WchProfessions,
'users/wch_cities': WchCities,
'users/wch_professions': WchProfessions,
}
export default componentMap

View File

@@ -3,6 +3,14 @@
* Version: 1.0.0
*/
// 引入核心依赖
import Vue from 'vue'
import VueRouter from 'vue-router'
import Vuex from 'vuex'
import ViewUI from 'view-design'
// 引入样式
import 'view-design/dist/styles/iview.css'
import './assets/css/animate.css'
import './assets/css/base.less'
import './assets/css/ivewExpand.less'
@@ -326,6 +334,93 @@ class AdminFramework {
Vue.component(name, components[name])
})
}
/**
* Create app with simplified API (推荐使用)
* @param {Object} config - application config
* @param {String} config.title - application title
* @param {String} config.apiUrl - API base URL
* @param {String} config.uploadUrl - upload URL (可选,默认为 apiUrl + 'upload')
* @param {Object} config.componentMap - custom component map (optional)
* @param {Function} config.onReady - callback when app is ready (optional)
* @returns {Object} Vue instance
*/
createApp(config = {}) {
// Auto install framework using internal dependencies
if (!this.installed) {
const { componentMap, ...appConfig } = config
// 如果没有提供 uploadUrl自动从 apiUrl 推导
if (!appConfig.uploadUrl && appConfig.apiUrl) {
appConfig.uploadUrl = appConfig.apiUrl + (appConfig.apiUrl.endsWith('/') ? 'upload' : '/upload')
}
this.install(Vue, {
config: appConfig,
ViewUI,
VueRouter,
Vuex,
createPersistedState: null,
componentMap: componentMap || {}
})
}
// Create Vue instance with auto menu/title restoration
const app = new Vue({
router: this.router,
store: this.store,
render: h => h('router-view'),
async created() {
console.log('=== Admin Framework App Started ===')
console.log('Framework Version:', framework.version)
console.log('Config:', this.$config)
// Auto restore menu and title on refresh
const token = this.$store.state.user.token
const authorityMenus = localStorage.getItem('authorityMenus')
if (token && authorityMenus) {
console.log('Restoring menu and title...')
try {
// Restore menu
await this.$store.dispatch('user/setAuthorityMenus', {
Main: framework.Main,
ParentView: framework.ParentView,
Page404: framework.Page404,
authorityMenus: authorityMenus
})
console.log('Menu restored')
// Get system title
await this.$store.dispatch('app/getSysTitle', {
defaultTitle: this.$config.title,
defaultLogo: ''
})
} catch (error) {
console.error('Restore failed:', error)
}
} else {
// Not logged in, use default title
console.log('Not logged in, using default title')
document.title = this.$config.title
}
// Call user callback if provided
if (config.onReady && typeof config.onReady === 'function') {
config.onReady.call(this)
}
}
})
// Expose to global for debugging
if (typeof window !== 'undefined') {
window.app = app
window.rootVue = app
window.framework = framework
}
return app
}
}
const framework = new AdminFramework()

View File

@@ -57,6 +57,25 @@ export const setupRouterGuards = (router, ViewUI, homeName = 'home') => {
next({ name: homeName })
}
} else {
// 已登录,检查路由是否存在
if (token && to.matched.length === 0 && to.path !== '/') {
// 路由不存在,可能是动态路由还未加载完成
console.warn('路由未找到:', to.name || to.path, ',尝试等待动态路由加载')
// 等待一小段时间后重试
setTimeout(() => {
// 检查路由是否已经存在
const route = router.resolve(to.path)
if (route && route.matched.length > 0) {
next({ path: to.path, replace: true })
} else {
console.error('路由仍然不存在:', to.name || to.path, ',跳转到首页')
next({ name: homeName, replace: true })
}
}, 150)
return
}
// 其他情况 → 允许访问
next()
}

View File

@@ -104,9 +104,11 @@ export default {
commit('setMenuList', mainMenu.children)
// 动态添加路由(重要!解决登录后点击菜单空白的问题)
if (this.router) {
const routes =this.router.options.routes
// 从 window.framework 获取 router 实例
const router = window.framework && window.framework.router
if (router) {
const routes = router.options.routes
// 查找并移除旧的主路由
const mainRouteIndex = routes.findIndex(r => r.path === '/')
if (mainRouteIndex !== -1) {
@@ -116,6 +118,11 @@ export default {
// 添加新的主路由
router.addRoute(mainMenu)
console.log('动态路由已添加redirect 设置为:', mainMenu.redirect)
// 等待路由更新完成
await new Promise(resolve => setTimeout(resolve, 100))
} else {
console.warn('未找到 router 实例,动态路由添加失败')
}
}
},

292
快速开始.md Normal file
View File

@@ -0,0 +1,292 @@
# AdminFramework 快速开始
## 🚀 5 分钟上手
### 第一步:引入框架
```javascript
import AdminFramework from './admin-framework.js'
import componentMap from './router/component-map.js'
```
### 第二步:创建应用
```javascript
const app = AdminFramework.createApp({
title: '我的管理系统',
apiUrl: 'http://localhost:9098/admin_api/',
componentMap: componentMap
})
```
### 第三步:挂载应用
```javascript
app.$mount('#app')
```
## ✨ 就这么简单!
**完整代码只需 18 行:**
```javascript
// main.js
import AdminFramework from './admin-framework.js'
import componentMap from './router/component-map.js'
const app = AdminFramework.createApp({
title: '我的管理系统',
apiUrl: 'http://localhost:9098/admin_api/',
componentMap: componentMap
})
app.$mount('#app')
```
## 📋 组件映射表配置
`componentMap` 用于定义业务页面的动态路由。
**重要提示:** 只需传递不带 `.vue` 后缀的路径,框架会自动处理带后缀和不带后缀的两种情况!
```javascript
// router/component-map.js
import ProductList from '../views/business/product-list.vue'
import OrderList from '../views/business/order-list.vue'
export default {
// ✅ 正确:只传递不带 .vue 的路径
'business/product': ProductList,
'business/order': OrderList,
// ❌ 错误:不要同时传递带和不带 .vue 的路径(多余)
// 'business/product.vue': ProductList, // 框架会自动添加
}
```
**说明:** 框架内部会自动为每个组件创建两个映射:
- `'business/product'` → ProductList
- `'business/product.vue'` → ProductList自动添加
所以后台菜单配置 `business/product``business/product.vue` 都可以正常工作!
## ⚙️ 配置说明
### 必填参数
| 参数 | 说明 | 示例 |
|------|------|------|
| `title` | 应用标题 | `'我的管理系统'` |
| `apiUrl` | API 基础地址 | `'http://localhost:9098/admin_api/'` |
| `componentMap` | 组件映射表 | 见上方示例 |
### 可选参数
| 参数 | 说明 | 默认值 |
|------|------|--------|
| `uploadUrl` | 上传文件地址 | `apiUrl + 'upload'` |
| `onReady` | 应用启动回调 | - |
## 🎯 完整示例
```javascript
import AdminFramework from './admin-framework.js'
import componentMap from './router/component-map.js'
const app = AdminFramework.createApp({
// 必填配置
title: '我的管理系统',
apiUrl: 'http://localhost:9098/admin_api/',
componentMap: componentMap,
// 可选配置
uploadUrl: 'http://cdn.example.com/upload', // 可选,默认为 apiUrl + 'upload'
// 应用启动完成回调
onReady() {
console.log('应用已启动!')
console.log('当前登录用户:', this.$store.state.user)
}
})
app.$mount('#app')
```
## 📦 框架内置功能
使用 `createApp()` 后,框架会自动提供:
### 1. 内置页面
- ✅ 登录页面 (`/login`)
- ✅ 主页 (`/home`)
- ✅ 404 页面 (`/404`)
- ✅ 401 页面 (`/401`)
- ✅ 500 页面 (`/500`)
### 2. 系统管理页面
- ✅ 用户管理 (`/system/user`)
- ✅ 角色管理 (`/system/role`)
- ✅ 日志管理 (`/system/log`)
- ✅ 参数设置 (`/system/param`)
- ✅ 菜单管理 (`/system_high/menu`)
- ✅ 权限控制 (`/system_high/control`)
- ✅ 标题设置 (`/system_high/title`)
### 3. 全局组件
-`<Tables>` - 增强型表格
-`<UploadSingle>` - 单图上传
-`<UploadMultiple>` - 多图上传
-`<TreeGrid>` - 树形表格
-`<AsyncModal>` - 异步弹窗
-`<Editor>` - 富文本编辑器
-`<CommonIcon>` - 图标选择器
### 4. 工具方法
在任何组件中可以使用:
```javascript
// HTTP 请求
this.$http.get('/api/users')
this.$http.post('/api/users', data)
// UI 工具
this.$uiTool.showLoading()
this.$uiTool.hideLoading()
this.$uiTool.showSuccess('操作成功')
// 通用工具
this.$tools.formatDate(new Date())
this.$tools.deepClone(obj)
// 文件下载
this.$funTool.downloadFile(response, 'filename.xlsx')
// 配置信息
this.$config.title
this.$config.apiUrl
this.$config.uploadUrl
// 状态管理
this.$store.state.user.token
this.$store.state.app.sysTitle
```
## 🎨 自定义页面
### 1. 创建页面组件
```vue
<!-- views/business/product-list.vue -->
<template>
<div>
<Tables :columns="columns" :data="list" />
</div>
</template>
<script>
export default {
data() {
return {
list: [],
columns: [
{ title: '产品名称', key: 'name' },
{ title: '价格', key: 'price' }
]
}
},
created() {
this.loadData()
},
methods: {
async loadData() {
const res = await this.$http.get('/products')
this.list = res.data
}
}
}
</script>
```
### 2. 添加到组件映射表
```javascript
// router/component-map.js
import ProductList from '../views/business/product-list.vue'
export default {
'business/product': ProductList // 路径对应后台菜单的 component 字段
}
```
### 3. 在后台配置菜单
在"菜单管理"中添加菜单项:
- 菜单名称: `产品列表`
- 路由路径: `/business/product`
- 组件路径: `business/product`(对应 componentMap 的 key
## 📝 常见问题
### Q1: uploadUrl 如何配置?
**A:** 默认情况下无需配置,框架会自动设置为 `apiUrl + 'upload'`
如果需要自定义(如使用 CDN可以手动传入
```javascript
AdminFramework.createApp({
apiUrl: 'http://localhost:9098/admin_api/',
uploadUrl: 'http://cdn.example.com/upload' // 自定义上传地址
})
```
### Q2: 如何访问框架实例?
**A:** 框架实例会自动暴露到全局:
```javascript
// 浏览器控制台
window.framework // 框架实例
window.app // Vue 实例
window.rootVue // Vue 实例(别名)
```
### Q3: 如何添加自定义 Vuex 模块?
**A:** 使用旧的 `install()` 方式:
```javascript
import AdminFramework from './admin-framework.js'
AdminFramework.install(Vue, {
config: { ... },
ViewUI,
VueRouter,
Vuex,
customModules: {
myModule: myModuleConfig
}
})
```
### Q4: 框架文件太大怎么办?
**A:** 新版框架3.6 MB内置了所有依赖使用更方便。如果需要减小文件大小可以使用旧的 `install()` 方式,手动引入依赖。
## 🔗 相关文档
- [简化使用说明.md](./简化使用说明.md) - 详细的使用说明和对比
- [README.md](./README.md) - 项目介绍和特性
- [demo/src/main.js](./demo/src/main.js) - 完整示例代码
## 💡 最佳实践
1. **推荐使用 `createApp()`** - 代码更简洁,减少 77% 的代码量
2. **组件映射表单独管理** - 方便维护和扩展
3. **利用内置组件** - 如 `<Tables>``<UploadSingle>` 等,提高开发效率
4. **使用 `onReady` 回调** - 在应用启动后执行初始化逻辑
## 🎉 开始开发吧!
现在你已经了解了 AdminFramework 的快速使用方法,开始构建你的管理系统吧!