From fd3c1a55637c1aa6e52bfdd4a1b942108c0c8a15 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=A0=E6=88=90?= Date: Mon, 20 Oct 2025 18:18:27 +0800 Subject: [PATCH] init --- .claude/settings.local.json | 9 + README.md | 35 +++- demo/src/main.js | 85 +-------- demo/src/router/component-map.js | 38 ++-- src/index.js | 95 ++++++++++ src/router/index.js | 19 ++ src/store/user.js | 13 +- 快速开始.md | 292 +++++++++++++++++++++++++++++++ 8 files changed, 479 insertions(+), 107 deletions(-) create mode 100644 .claude/settings.local.json create mode 100644 快速开始.md diff --git a/.claude/settings.local.json b/.claude/settings.local.json new file mode 100644 index 0000000..2206350 --- /dev/null +++ b/.claude/settings.local.json @@ -0,0 +1,9 @@ +{ + "permissions": { + "allow": [ + "Bash(npm run build:*)" + ], + "deny": [], + "ask": [] + } +} diff --git a/README.md b/README.md index 2ab5b32..87533c4 100644 --- a/README.md +++ b/README.md @@ -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) diff --git a/demo/src/main.js b/demo/src/main.js index 24bf097..e641246 100644 --- a/demo/src/main.js +++ b/demo/src/main.js @@ -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 已在文件开头暴露,无需重复 - diff --git a/demo/src/router/component-map.js b/demo/src/router/component-map.js index 69751a0..f9daa8e 100644 --- a/demo/src/router/component-map.js +++ b/demo/src/router/component-map.js @@ -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 diff --git a/src/index.js b/src/index.js index 2c3a2aa..fa43e3c 100644 --- a/src/index.js +++ b/src/index.js @@ -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() diff --git a/src/router/index.js b/src/router/index.js index 3b602b5..e694132 100644 --- a/src/router/index.js +++ b/src/router/index.js @@ -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() } diff --git a/src/store/user.js b/src/store/user.js index b0a3d3b..d235962 100644 --- a/src/store/user.js +++ b/src/store/user.js @@ -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 实例,动态路由添加失败') } } }, diff --git a/快速开始.md b/快速开始.md new file mode 100644 index 0000000..f9b4a5a --- /dev/null +++ b/快速开始.md @@ -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. 全局组件 +- ✅ `` - 增强型表格 +- ✅ `` - 单图上传 +- ✅ `` - 多图上传 +- ✅ `` - 树形表格 +- ✅ `` - 异步弹窗 +- ✅ `` - 富文本编辑器 +- ✅ `` - 图标选择器 + +### 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 + + + + +``` + +### 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. **利用内置组件** - 如 ``、`` 等,提高开发效率 +4. **使用 `onReady` 回调** - 在应用启动后执行初始化逻辑 + +## 🎉 开始开发吧! + +现在你已经了解了 AdminFramework 的快速使用方法,开始构建你的管理系统吧!