+
+
+
{{tag.id}} {{tag.name}}
+
+ 添加
+
-
+
\ No newline at end of file
+
diff --git a/src/router/import-views.js b/src/router/import-views.js
index 331acba4..0407fbf4 100644
--- a/src/router/import-views.js
+++ b/src/router/import-views.js
@@ -1 +1,3 @@
+// 导出一个函数,该函数接收一个文件名作为参数
+// 返回一个动态导入模块的函数
module.exports = file => () => import('@/views/' + file + '.vue')
diff --git a/src/router/index.js b/src/router/index.js
index 84cd1aed..026caf3b 100644
--- a/src/router/index.js
+++ b/src/router/index.js
@@ -10,75 +10,76 @@ import http from '@/utils/httpRequest'
import { isURL } from '@/utils/validate'
import { clearLoginInfo } from '@/utils'
+// 使用VueRouter插件
Vue.use(VueRouter)
+// 动态导入视图组件的函数
const _import = require('./import-views')
+
// 全局路由(无需嵌套上左右整体布局)
const globalRoutes = [
- { path: '/404', component: () => import('@/views/common/404'), name: '404', meta: { title: '404未找到' } },
- { path: '/login', component: () => import('@/views/common/login'), name: 'login', meta: { title: '登录' } }
+ { path: '/404', component: () => import('@/views/common/404'), name: '404', meta: { title: '404未找到' } }, // 404页面路由
+ { path: '/login', component: () => import('@/views/common/login'), name: 'login', meta: { title: '登录' } } // 登录页面路由
]
// 主入口路由(需嵌套上左右整体布局)
const mainRoutes = {
- path: '/',
- component: () => import('@/views/main'),
- name: 'main',
- redirect: { name: 'home' },
- meta: { title: '主入口整体布局' },
- children: [
- // 通过meta对象设置路由展示方式
- // 1. isTab: 是否通过tab展示内容, true: 是, false: 否
- // 2. iframeUrl: 是否通过iframe嵌套展示内容, '以http[s]://开头': 是, '': 否
- // 提示: 如需要通过iframe嵌套展示内容, 但不通过tab打开, 请自行创建组件使用iframe处理!
- { path: '/home', component: () => import('@/views/common/home'), name: 'home', meta: { title: '首页' } },
- { path: '/theme', component: () => import('@/views/common/theme'), name: 'theme', meta: { title: '主题' } },
- ],
- beforeEnter(to, from, next) {
- let token = Vue.cookie.get('token')
- if (!token || !/\S/.test(token)) {
- clearLoginInfo()
- next({ name: 'login' })
+ path: '/',
+ component: () => import('@/views/main'),
+ name: 'main',
+ redirect: { name: 'home' },
+ meta: { title: '主入口整体布局' },
+ children: [
+ // 通过meta对象设置路由展示方式
+ // 1. isTab: 是否通过tab展示内容, true: 是, false: 否
+ // 2. iframeUrl: 是否通过iframe嵌套展示内容, '以http[s]://开头': 是, '': 否
+ { path: '/home', component: () => import('@/views/common/home'), name: 'home', meta: { title: '首页' } }, // 首页路由
+ { path: '/theme', component: () => import('@/views/common/theme'), name: 'theme', meta: { title: '主题' } } // 主题页面路由
+ ],
+ beforeEnter(to, from, next) {
+ // 检查用户是否已登录,如果未登录则重定向到登录页
+ let token = Vue.cookie.get('token')
+ if (!token || !/\S/.test(token)) {
+ clearLoginInfo()
+ next({ name: 'login' })
+ }
+ next()
}
- next()
- }
}
+// 创建VueRouter实例
const router = new VueRouter({
- mode: 'hash',
- scrollBehavior: () => ({ y: 0 }),
- isAddDynamicMenuRoutes: false, // 是否已经添加动态(菜单)路由
- routes: globalRoutes.concat(mainRoutes)
+ mode: 'hash', // 使用hash模式
+ scrollBehavior: () => ({ y: 0 }), // 滚动行为:切换路由时滚动到顶部
+ isAddDynamicMenuRoutes: false, // 是否已经添加动态(菜单)路由
+ routes: globalRoutes.concat(mainRoutes) // 合并全局路由和主入口路由
})
+// 全局前置守卫,用于处理动态菜单路由的添加
router.beforeEach((to, from, next) => {
- // 添加动态(菜单)路由
- // 1. 已经添加 or 全局路由, 直接访问
- // 2. 获取菜单列表, 添加并保存本地存储
- if (router.options.isAddDynamicMenuRoutes || fnCurrentRouteType(to, globalRoutes) === 'global') {
- next()
- } else {
- http({
- url: http.adornUrl('/sys/menu/nav'),
- method: 'get',
- params: http.adornParams()
- }).then(({ data }) => {
- if (data && data.code === 200) {
- fnAddDynamicMenuRoutes(data.menuList)
- router.options.isAddDynamicMenuRoutes = true
- sessionStorage.setItem('menuList', JSON.stringify(data.menuList || '[]'))
- sessionStorage.setItem('permissions', JSON.stringify(data.permissions || '[]'))
- next({ ...to, replace: true })
- } else {
- sessionStorage.setItem('menuList', '[]')
- sessionStorage.setItem('permissions', '[]')
+ // 如果已经添加了动态(菜单)路由或当前路由是全局路由,直接放行
+ if (router.options.isAddDynamicMenuRoutes || fnCurrentRouteType(to, globalRoutes) === 'global') {
next()
- }
- }).catch((e) => {
- console.log(`%c${e} 请求菜单列表和权限失败,跳转至登录页!!`, 'color:blue')
- router.push({ name: 'login' })
- })
- }
+ } else {
+ // 否则,请求菜单列表并添加动态(菜单)路由
+ http({
+ url: http.adornUrl('/sys/menu/nav'),
+ method: 'get',
+ params: http.adornParams()
+ }).then(({ data }) => {
+ if (data && data.code === 200) {
+ fnAddDynamicMenuRoutes(data.menuList) // 添加动态(菜单)路由
+ router.options.isAddDynamicMenuRoutes = true // 标记为已添加动态(菜单)路由
+ next({ ...to, replace: true }) // 重新导航到当前路由,确保添加完动态路由后能正确显示页面
+ } else {
+ console.log(`%c${e} 请求菜单列表和权限失败,跳转至登录页!!`, 'color:blue') // 打印错误信息
+ router.push({ name: 'login' }) // 跳转到登录页
+ }
+ }).catch((e) => {
+ console.log(`%c${e} 请求菜单列表和权限失败,跳转至登录页!!`, 'color:blue') // 打印错误信息
+ router.push({ name: 'login' }) // 跳转到登录页
+ })
+ }
})
/**
@@ -86,15 +87,15 @@ router.beforeEach((to, from, next) => {
* @param {*} route 当前路由
*/
function fnCurrentRouteType(route, globalRoutes = []) {
- var temp = []
- for (var i = 0; i < globalRoutes.length; i++) {
- if (route.path === globalRoutes[i].path) {
- return 'global'
- } else if (globalRoutes[i].children && globalRoutes[i].children.length >= 1) {
- temp = temp.concat(globalRoutes[i].children)
+ var temp = []
+ for (var i = 0; i < globalRoutes.length; i++) {
+ if (route.path === globalRoutes[i].path) {
+ return 'global' // 如果是全局路由,返回'global'
+ } else if (globalRoutes[i].children && globalRoutes[i].children.length >= 1) {
+ temp = temp.concat(globalRoutes[i].children) // 如果有子路由,添加到临时数组中
+ }
}
- }
- return temp.length >= 1 ? fnCurrentRouteType(route, temp) : 'main'
+ return temp.length >= 1 ? fnCurrentRouteType(route, temp) : 'main' // 递归判断,直到找到匹配的路由类型
}
/**
@@ -103,52 +104,49 @@ function fnCurrentRouteType(route, globalRoutes = []) {
* @param {*} routes 递归创建的动态(菜单)路由
*/
function fnAddDynamicMenuRoutes(menuList = [], routes = []) {
- var temp = []
- for (var i = 0; i < menuList.length; i++) {
- if (menuList[i].list && menuList[i].list.length >= 1) {
- temp = temp.concat(menuList[i].list)
- } else if (menuList[i].url && /\S/.test(menuList[i].url)) {
- menuList[i].url = menuList[i].url.replace(/^\//, '')
- var route = {
- path: menuList[i].url.replace('/', '-'),
- component: null,
- name: menuList[i].url.replace('/', '-'),
- meta: {
- menuId: menuList[i].menuId,
- title: menuList[i].name,
- isDynamic: true,
- isTab: true,
- iframeUrl: ''
+ var temp = []
+ for (var i = 0; i < menuList.length; i++) {
+ if (menuList[i].list && menuList[i].list.length >= 1) {
+ temp = temp.concat(menuList[i].list) // 如果菜单项有子菜单,添加到临时数组中
+ } else if (menuList[i].url && /\S/.test(menuList[i].url)) {
+ menuList[i].url = menuList[i].url.replace(/^\//, '') // 去掉URL前的斜杠
+ var route = {
+ path: menuList[i].url.replace('/', '-'), // 将URL中的斜杠替换为短横线,作为路径的一部分
+ component: null, // 初始化组件为空
+ name: menuList[i].url.replace('/', '-'), // 将URL中的斜杠替换为短横线,作为路由名称的一部分
+ meta: {
+ menuId: menuList[i].menuId, // 菜单ID
+ title: menuList[i].name, // 菜单名称
+ isDynamic: true, // 标记为动态路由
+ isTab: true, // 标记为标签页
+ iframeUrl: '' // 初始化iframeUrl为空
+ }
+ }
+ // 如果URL以http[s]://开头,通过iframe展示
+ if (isURL(menuList[i].url)) {
+ route['path'] = `i-${menuList[i].menuId}` // 修改路径为i-加上菜单ID
+ route['name'] = `i-${menuList[i].menuId}` // 修改名称为i-加上菜单ID
+ route['meta']['iframeUrl'] = menuList[i].url // 设置iframeUrl为菜单URL
+ } else {
+ try {
+ route['component'] = _import(`modules/${menuList[i].url}`) || null // 动态导入组件
+ } catch (e) { } // 如果导入失败,捕获异常但不做处理
+ }
+ routes.push(route) // 将路由添加到routes数组中
}
- }
- // url以http[s]://开头, 通过iframe展示
- if (isURL(menuList[i].url)) {
- route['path'] = `i-${menuList[i].menuId}`
- route['name'] = `i-${menuList[i].menuId}`
- route['meta']['iframeUrl'] = menuList[i].url
- } else {
- try {
- route['component'] = _import(`modules/${menuList[i].url}`) || null
- // route['component'] = ()=>import(`@/views/modules/${menuList[i].url}.vue`) || null
- } catch (e) { }
- }
- routes.push(route)
}
- }
- if (temp.length >= 1) {
- fnAddDynamicMenuRoutes(temp, routes)
- } else {
- mainRoutes.name = 'main-dynamic'
- mainRoutes.children = routes
- router.addRoutes([
- mainRoutes,
- { path: '*', redirect: { name: '404' } }
- ])
- sessionStorage.setItem('dynamicMenuRoutes', JSON.stringify(mainRoutes.children || '[]'))
- console.log('\n')
- console.log('%c!<-------------------- 动态(菜单)路由 s -------------------->', 'color:blue')
- console.log(mainRoutes.children)
- console.log('%c!<-------------------- 动态(菜单)路由 e -------------------->', 'color:blue')
- }
+ if (temp.length >= 1) {
+ fnAddDynamicMenuRoutes(temp, routes) // 如果临时数组中有数据,递归调用自身继续处理
+ } else {
+ mainRoutes.name = 'main-dynamic' // 修改主入口路由的名称为main-dynamic
+ mainRoutes.children = routes // 将动态生成的路由设置为主入口路由的子路由
+ router.addRoutes([mainRoutes, { path: '*', redirect: { name: '404' } }]) // 添加动态路由和404重定向规则到路由器中
+ sessionStorage.setItem('dynamicMenuRoutes', JSON.stringify(mainRoutes.children || '')) // 将动态路由存储到sessionStorage中以便后续使用
+ console.log('\n')
+ console.log('%c!<-------------------- 动态(菜单)路由 s -------------------->', 'color:blue') // 打印动态路由开始标志
+ console.log(mainRoutes.children) // 打印动态生成的路由信息
+ console.log('%c!<-------------------- 动态(菜单)路由 e -------------------->', 'color:blue') // 打印动态路由结束标志
+ console.log('\n')
+ }
}
-export default router
+export default router // 导出路由器实例
diff --git a/src/store/modules/article.js b/src/store/modules/article.js
index 1308ab36..56f94e73 100644
--- a/src/store/modules/article.js
+++ b/src/store/modules/article.js
@@ -1,12 +1,14 @@
export default {
- namespaced: true,
- state: {
- ARTICLE_TYPES: {
- 1: '普通文章',
- 5: '帮助中心',
+ // 启用命名空间,使得该模块的状态和getters、actions、mutations是注册在全局命名空间下的子模块
+ namespaced: true,
+ state: {
+ // 定义文章类型常量对象
+ ARTICLE_TYPES: {
+ 1: '普通文章', // 普通文章类型
+ 5: '帮助中心', // 帮助中心类型
+ }
+ },
+ mutations: {
+ // 目前没有定义任何mutation
}
- },
- mutations: {
-
- }
}
diff --git a/src/store/modules/common.js b/src/store/modules/common.js
index 467e447f..ee514096 100644
--- a/src/store/modules/common.js
+++ b/src/store/modules/common.js
@@ -1,6 +1,7 @@
import router from '@/router'
export default {
+ // 启用命名空间,使得该模块的状态和getters、actions、mutations是注册在全局命名空间下的子模块
namespaced: true,
state: {
// 页面文档可视高度(随窗口改变大小)
@@ -11,47 +12,60 @@ export default {
sidebarLayoutSkin: 'dark',
// 侧边栏, 折叠状态
sidebarFold: false,
- // 侧边栏, 菜单
+ // 侧边栏, 菜单列表
menuList: [],
+ // 当前激活的菜单项名称
menuActiveName: '',
- // 内容, 是否需要刷新
+ // 内容区域是否需要刷新
contentIsNeedRefresh: false,
- // 主入口标签页
+ // 主入口标签页数组
mainTabs: [],
+ // 当前激活的标签页名称
mainTabsActiveName: ''
},
mutations: {
+ // 更新文档可视高度
updateDocumentClientHeight(state, height) {
state.documentClientHeight = height
},
+ // 更新导航条布局类型
updateNavbarLayoutType(state, type) {
state.navbarLayoutType = type
},
+ // 更新侧边栏布局皮肤
updateSidebarLayoutSkin(state, skin) {
state.sidebarLayoutSkin = skin
},
+ // 更新侧边栏折叠状态
updateSidebarFold(state, fold) {
state.sidebarFold = fold
},
+ // 更新菜单列表
updateMenuList(state, list) {
state.menuList = list
},
+ // 更新当前激活的菜单项名称
updateMenuActiveName(state, name) {
state.menuActiveName = name
},
+ // 更新内容区域是否需要刷新
updateContentIsNeedRefresh(state, status) {
state.contentIsNeedRefresh = status
},
+ // 更新主入口标签页数组
updateMainTabs(state, tabs) {
state.mainTabs = tabs
},
+ // 更新当前激活的标签页名称
updateMainTabsActiveName(state, name) {
state.mainTabsActiveName = name
},
+ // 移除指定的标签页
removeTab(state, tabName) {
+ // 过滤掉要删除的标签页
state.mainTabs = state.mainTabs.filter(item => item.name !== tabName)
if (state.mainTabs.length >= 1) {
- // 当前选中tab被删除
+ // 如果当前选中的标签页被删除,则跳转到最后一个标签页
if (tabName === state.mainTabsActiveName) {
var tab = state.mainTabs[state.mainTabs.length - 1]
router.push({ name: tab.name, query: tab.query, params: tab.params }, () => {
@@ -59,12 +73,14 @@ export default {
})
}
} else {
+ // 如果没有剩余的标签页,重置菜单并跳转到首页
state.menuActiveName = ''
router.push({ name: 'home' })
}
},
+ // 关闭当前激活的标签页
closeCurrentTab(state) {
this.commit('common/removeTab', state.mainTabsActiveName)
}
}
-}
\ No newline at end of file
+}
diff --git a/src/store/modules/message.js b/src/store/modules/message.js
index 9b689651..37f0e2ef 100644
--- a/src/store/modules/message.js
+++ b/src/store/modules/message.js
@@ -1,32 +1,39 @@
+// 导出一个默认的模块对象
export default {
+ // 启用命名空间,使得该模块的状态和getters、actions、mutations是注册在全局命名空间下的子模块
namespaced: true,
+
+ // 定义模块的初始状态
state: {
- XmlMsgType:{
- "text":"文字",
- "image":"图片",
- "voice":"语音",
- "shortvideo":"短视频",
- "video":"视频",
- "news":"图文",
- "music":"音乐",
- "location":"位置",
- "link":"链接",
- "event":"事件",
- "transfer_customer_service":"转客服"
+ // 定义微信消息类型的映射关系
+ XmlMsgType: {
+ "text": "文字", // 文本消息类型
+ "image": "图片", // 图片消息类型
+ "voice": "语音", // 语音消息类型
+ "shortvideo": "短视频", // 短视频消息类型
+ "video": "视频", // 视频消息类型
+ "news": "图文", // 图文消息类型
+ "music": "音乐", // 音乐消息类型
+ "location": "位置", // 位置消息类型
+ "link": "链接", // 链接消息类型
+ "event": "事件", // 事件消息类型
+ "transfer_customer_service": "转客服" // 转接客服消息类型
},
+ // 定义客服消息类型的映射关系
KefuMsgType: {
- "text": "文本消息",
- "image": "图片消息",
- "voice": "语音消息",
- "video": "视频消息",
- "music": "音乐消息",
- "news": "文章链接",
- "mpnews": "公众号图文消息",
- "wxcard": "卡券消息",
- "miniprogrampage": "小程序消息",
- "msgmenu": "菜单消息"
+ "text": "文本消息", // 文本消息类型
+ "image": "图片消息", // 图片消息类型
+ "voice": "语音消息", // 语音消息类型
+ "video": "视频消息", // 视频消息类型
+ "music": "音乐消息", // 音乐消息类型
+ "news": "文章链接", // 文章链接消息类型
+ "mpnews": "公众号图文消息", // 公众号图文消息类型
+ "wxcard": "卡券消息", // 卡券消息类型
+ "miniprogrampage": "小程序消息", // 小程序消息类型
+ "msgmenu": "菜单消息" // 菜单消息类型
}
},
+ // 定义用于修改状态的 mutations(目前为空)
mutations: {
}
diff --git a/src/store/modules/user.js b/src/store/modules/user.js
index 6f3798d0..bdb328ff 100644
--- a/src/store/modules/user.js
+++ b/src/store/modules/user.js
@@ -1,15 +1,23 @@
+// 导出一个默认的模块对象
export default {
- namespaced: true,
- state: {
- id: 0,
- name: ''
- },
- mutations: {
- updateId(state, id) {
- state.id = id
+ // 启用命名空间,使得该模块的状态和getters、actions、mutations是注册在全局命名空间下的子模块
+ namespaced: true,
+
+ // 定义模块的初始状态
+ state: {
+ id: 0, // 初始化 id 为 0
+ name: '' // 初始化 name 为空字符串
},
- updateName(state, name) {
- state.name = name
+
+ // 定义用于修改状态的 mutations
+ mutations: {
+ // 更新 id 的 mutation
+ updateId(state, id) {
+ state.id = id; // 将传入的 id 赋值给 state 中的 id
+ },
+ // 更新 name 的 mutation
+ updateName(state, name) {
+ state.name = name; // 将传入的 name 赋值给 state 中的 name
+ }
}
- }
}