登录
注册
开源
企业版
高校版
搜索
帮助中心
使用条款
关于我们
开源
企业版
高校版
私有云
模力方舟
登录
注册
代码拉取完成,页面将自动刷新
开源项目
>
程序开发
>
权限管理
&&
捐赠
捐赠前请先登录
取消
前往登录
扫描微信二维码支付
取消
支付完成
支付提示
将跳转至支付宝完成支付
确定
取消
Watch
不关注
关注所有动态
仅关注版本发行动态
关注但不提醒动态
416
Star
2.9K
Fork
4.2K
lengleng
/
pig-ui
代码
Pull Requests
6
Wiki
统计
流水线
服务
质量分析
Jenkins for Gitee
腾讯云托管
腾讯云 Serverless
悬镜安全
阿里云 SAE
Codeblitz
SBOM
我知道了,不再自动展开
26
解决配置菜单带参数的问题,菜单配置为: /admin/user/index/:username=zhangsan
已关闭
lengleng:electron
lengleng:dev
Frank
创建于 2021-12-22 18:25
克隆/下载
HTTPS
SSH
复制
下载 Email Patch
下载 Diff 文件
### avue-router.js ``` const RouterPlugin = function() { this.$router = null this.$store = null } let num = 0; RouterPlugin.install = function(router, store) { this.$router = router this.$store = store function isURL(s) { return /^http[s]?:\/\/.*/.test(s) } function objToform(obj) { const result = [] Object.keys(obj).forEach(ele => { result.push(`${ele}=${obj[ele]}`) }) return result.join('&') } this.$router.$avueRouter = { // 全局配置 $website: this.$store.getters.website, $defaultTitle: 'DSV Warehouse Web Visibility', routerList: [], group: '', safe: this, // 设置标题 setTitle: function(title) { title = title ? `${title}——${this.$defaultTitle}` : this.$defaultTitle document.title = title }, closeTag: (value) => { const tag = value || this.$store.getters.tag this.$store.commit('DEL_TAG', tag) }, // 处理路由 getPath: function(params) { const { src } = params let result = src || '/' if (src.includes('http') || src.includes('https')) { result = `/myiframe/urlPath?${objToform(params)}` } return result }, //更新路由名称 getRealName(toRoute=null){ const menuList = this.safe.$store.getters.newMenu; const result = this.getMenuName(menuList,toRoute.fullPath); return result&&result.name||''; }, getMenuName(menuList,path){ let result =null; for(let item of menuList){ if(item.path == path){ result = item; break; } if(item.children.length){ const childResult = this.getMenuName(item.children,path); if(childResult){ result = childResult; break; } } } return result; }, // 正则处理路由 vaildPath: function(list, path) { let result = false list.forEach(ele => { if (new RegExp('^' + ele + '.*', 'g').test(path)) { result = true } }) return result }, // 设置路由值 getValue: function(route) { let value = '' if (route.query.src) { value = route.query.src } else { value = route.path } return value }, // 动态路由 formatRoutes: function(aMenu = [], first) { const aRouter = [] const propsConfig = this.$website.menu.props const propsDefault = { label: propsConfig.label || 'label', path: propsConfig.path || 'path', icon: propsConfig.icon || 'icon', children: propsConfig.children || 'children', meta: propsConfig.meta || 'meta' } if (aMenu.length === 0) return for (let i = 0; i < aMenu.length; i++) { const oMenu = aMenu[i] if (this.routerList.includes(oMenu[propsDefault.path])) return let path = (() => { if (!oMenu[propsDefault.path]) { return } else if (first) { return oMenu[propsDefault.path].replace('/index', '') } else { return oMenu[propsDefault.path] } })() path = path.replace(/\?.*$/, '') //特殊处理组件 let component = 'views' + oMenu.path component = component.replace(/\?.*$/, '') //新增动态路由处理 if(path.includes('=')){ path = path.replace(/\=.*$/, ''); component = component.replace(/\/:.*$/, ''); } const name = oMenu[propsDefault.label] const icon = oMenu[propsDefault.icon] const children = oMenu[propsDefault.children] const meta = { keepAlive: Number(oMenu['keepAlive']) === 1, realName:aMenu[i].name||aMenu[i].label, } const isChild = children.length !== 0 const oRouter = { path: path, component(resolve) { // 判断是否为首路由 if (first) { require(['../page/index'], resolve) // 判断是否为多层路由 } else if (isChild && !first) { require(['../page/index/layout'], resolve) // 判断是否为最终的页面视图 } else { require([`../${component}.vue`], resolve) } }, name: name, icon: icon, meta: meta, redirect: (() => { if (!isChild && first && !isURL(path)) return `${path}/index` else return '' })(), // 处理是否为一级路由 children: !isChild ? (() => { if (first) { if (!isURL(path)) oMenu[propsDefault.path] = `${path}/index` return [{ component(resolve) { require([`../${component}.vue`], resolve) }, icon: icon, name: name, meta: meta, path: 'index' }] } return [] })() : (() => { return this.formatRoutes(children, false) })() } aRouter.push(oRouter) } if (first) { if (!this.routerList.includes(aRouter[0][propsDefault.path])) { this.safe.$router.addRoutes(aRouter) this.routerList.push(aRouter[0][propsDefault.path]) } } else { return aRouter } } } } export default RouterPlugin ``` ### router.js ``` import Vue from 'vue' import VueRouter from 'vue-router' import PageRouter from './page/' import ViewsRouter from './views/' import AvueRouter from './avue-router' import Store from '../store/' Vue.use(VueRouter) //===装饰Router.prototype.push== const oldPush = VueRouter.prototype.push; VueRouter.prototype.push= function(...location){ return oldPush.call(this,...location).catch(err=>err); } //===end== let Router = new VueRouter({ scrollBehavior (to, from, savedPosition) { if (savedPosition) { return savedPosition } else { if (from.meta.keepAlive) { from.meta.savedPosition = document.body.scrollTop } return { x: 0, y: to.meta.savedPosition || 0 } } }, routes: [].concat([]) }) AvueRouter.install(Router, Store) Router.$avueRouter.formatRoutes(Store.state.user.menu, true) Router.addRoutes([...PageRouter, ...ViewsRouter]) export default Router ``` ### sidebar/index.vue ``` <template> <div class="avue-sidebar"> <logo></logo> <el-scrollbar style="height:100%;background-color: rgba(2, 44, 99, 0.94);"> <div v-if="validatenull(newMenu)" class="avue-sidebar--tip" style="background-color: #11386c">No menus found </div> <el-menu unique-opened :default-active="nowTagValue" mode="vertical" :show-timeout="200" active-text-color="#ffd04b" :collapse="keyCollapse"> <sidebar-item :menu="newMenu" :screen="screen" first :props="website.menu.props" :collapse="keyCollapse"></sidebar-item> </el-menu> </el-scrollbar> </div> </template> <script> import {mapGetters} from "vuex"; import logo from "../logo"; import sidebarItem from "./sidebarItem"; export default { name: "sidebar", components: {sidebarItem, logo}, data() { return {}; }, created() { this.$store.dispatch("GetMenu", {type: true, id: -1}).then(data => { if (data.length === 0) return; this.$router.$avueRouter.formatRoutes(data, true); }); }, computed: { ...mapGetters(["website", "menu", "tag", "keyCollapse", "screen","newMenu"]), nowTagValue: function () { return this.$router.$avueRouter.getValue(this.$route); }, }, mounted() { }, methods: { } }; </script> <style lang="scss" scoped> .avue-sidebar{ background-color: white; } </style> ``` ### sidebar/sidebarItem.vue ``` <template> <div class="menu-wrapper"> <template v-for="item in menu"> <el-menu-item v-if="validatenull(item[childrenKey]) && vaildRoles(item)" :index="item[pathKey]" @click="open(item)" :key="item[labelKey]" :class="{'is-active':vaildAvtive(item)}"> <i :class="item[iconKey]"></i> <span slot="title" :alt="item[pathKey]">{{item[labelKey]}}</span> </el-menu-item> <el-submenu v-else-if="!validatenull(item[childrenKey])&&vaildRoles(item)" :index="item[pathKey]" :key="item[labelKey]"> <template slot="title"> <i :class="item[iconKey]"></i> <span slot="title" :class="{'el-menu--display':collapse && first}">{{item[labelKey]}}</span> </template> <template v-for="(child,cindex) in item[childrenKey]"> <el-menu-item :index="child[pathKey],cindex" @click="open(child)" :class="{'is-active':vaildAvtive(child)}" v-if="validatenull(child[childrenKey])" :key="child[labelKey]"> <i :class="child[iconKey]"></i> <span slot="title">{{child[labelKey]}}</span> </el-menu-item> <sidebar-item v-else :menu="[child]" :key="cindex" :props="props" :screen="screen" :collapse="collapse"></sidebar-item> </template> </el-submenu> </template> </div> </template> <script> import { mapGetters } from "vuex"; import { validatenull } from "@/util/validate"; import config from "./config.js"; export default { name: "sidebarItem", data() { return { config: config }; }, props: { menu: { type: Array }, screen: { type: Number }, first: { type: Boolean, default: false }, props: { type: Object, default: () => { return {}; } }, collapse: { type: Boolean } }, created() {}, mounted() {}, computed: { ...mapGetters(["roles"]), labelKey() { return this.props.label || this.config.propsDefault.label; }, pathKey() { return this.props.path || this.config.propsDefault.path; }, iconKey() { return this.props.icon || this.config.propsDefault.icon; }, childrenKey() { return this.props.children || this.config.propsDefault.children; }, nowTagValue() { return this.$router.$avueRouter.getValue(this.$route); } }, methods: { vaildAvtive(item) { const groupFlag = (item["group"] || []).some(ele => this.$route.path.includes(this.newFilterFn(ele)) ); return this.nowTagValue === item[this.pathKey] || groupFlag; }, vaildRoles(item) { item.meta = item.meta || {}; return item.meta.roles ? item.meta.roles.includes(this.roles) : true; }, validatenull(val) { return validatenull(val); }, open(item) { if (this.screen <= 1) this.$store.commit("SET_COLLAPSE"); this.$router.$avueRouter.group = item.group; this.$router.push({ path: this.$router.$avueRouter.getPath({ name: item[this.labelKey], src: item[this.pathKey] }), query: item.query }).catch(() => {}); }, } }; </script> ``` ### util/util.js ``` import {validatenull} from './validate' import * as CryptoJS from 'crypto-js' // 表单序列化 export const serialize = data => { let list = [] Object.keys(data).forEach(ele => { list.push(`${ele}=${data[ele]}`) }) return list.join('&') } export const getObjType = obj => { var toString = Object.prototype.toString var map = { '[object Boolean]': 'boolean', '[object Number]': 'number', '[object String]': 'string', '[object Function]': 'function', '[object Array]': 'array', '[object Date]': 'date', '[object RegExp]': 'regExp', '[object Undefined]': 'undefined', '[object Null]': 'null', '[object Object]': 'object' } if (obj instanceof Element) { return 'element' } return map[toString.call(obj)] } /** * 对象深拷贝 */ export const deepClone = data => { var type = getObjType(data) var obj if (type === 'array') { obj = [] } else if (type === 'object') { obj = {} } else { // 不再具有下一层次 return data } if (type === 'array') { for (var i = 0, len = data.length; i < len; i++) { obj.push(deepClone(data[i])) } } else if (type === 'object') { for (var key in data) { obj[key] = deepClone(data[key]) } } return obj } /** * 判断路由是否相等 */ export const diff = (obj1, obj2) => { delete obj1.close var o1 = obj1 instanceof Object var o2 = obj2 instanceof Object if (!o1 || !o2) { /* 判断不是对象 */ return obj1 === obj2 } if (Object.keys(obj1).length !== Object.keys(obj2).length) { return false // Object.keys() 返回一个由对象的自身可枚举属性(key值)组成的数组,例如:数组返回下表:let arr = ["a", "b", "c"];console.log(Object.keys(arr))->0,1,2; } for (var attr in obj1) { var t1 = obj1[attr] instanceof Object var t2 = obj2[attr] instanceof Object if (t1 && t2) { return diff(obj1[attr], obj2[attr]) } else if (obj1[attr] !== obj2[attr]) { return false } } return true } /** * 设置灰度模式 */ export const toggleGrayMode = (status) => { if (status) { document.body.className = document.body.className + ' grayMode' } else { document.body.className = document.body.className.replace(' grayMode', '') } } /** * 设置主题 */ export const setTheme = (name) => { document.body.className = name } /** *加密处理 */ export const encryption = (params) => { let { data, type, param, key } = params const result = JSON.parse(JSON.stringify(data)) if (type === 'Base64') { param.forEach(ele => { result[ele] = btoa(result[ele]) }) } else { param.forEach(ele => { var data = result[ele] key = CryptoJS.enc.Latin1.parse(key) var iv = key // 加密 var encrypted = CryptoJS.AES.encrypt( data, key, { iv: iv, mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.ZeroPadding }) result[ele] = encrypted.toString() }) } return result } /** * 浏览器判断是否全屏 */ export const fullscreenToggel = () => { if (fullscreenEnable()) { exitFullScreen(); } else { reqFullScreen(); } }; /** * esc监听全屏 */ export const listenfullscreen = (callback) => { function listen() { callback() } document.addEventListener("fullscreenchange", function () { listen(); }); document.addEventListener("mozfullscreenchange", function () { listen(); }); document.addEventListener("webkitfullscreenchange", function () { listen(); }); document.addEventListener("msfullscreenchange", function () { listen(); }); }; /** * 浏览器判断是否全屏 */ export const fullscreenEnable = () => { return document.isFullScreen || document.mozIsFullScreen || document.webkitIsFullScreen } /** * 浏览器全屏 */ export const reqFullScreen = () => { if (document.documentElement.requestFullScreen) { document.documentElement.requestFullScreen(); } else if (document.documentElement.webkitRequestFullScreen) { document.documentElement.webkitRequestFullScreen(); } else if (document.documentElement.mozRequestFullScreen) { document.documentElement.mozRequestFullScreen(); } }; /** * 浏览器退出全屏 */ export const exitFullScreen = () => { if (document.documentElement.requestFullScreen) { document.exitFullScreen(); } else if (document.documentElement.webkitRequestFullScreen) { document.webkitCancelFullScreen(); } else if (document.documentElement.mozRequestFullScreen) { document.mozCancelFullScreen(); } }; /** * 递归寻找子类的父类 */ export const findParent = (menu, id) => { for (let i = 0; i < menu.length; i++) { if (menu[i].children.length != 0) { for (let j = 0; j < menu[i].children.length; j++) { if (menu[i].children[j].id == id) { return menu[i] } else { if (menu[i].children[j].children.length != 0) { return findParent(menu[i].children[j].children, id) } } } } } } /** * 动态插入css */ export const loadStyle = url => { const link = document.createElement('link') link.type = 'text/css' link.rel = 'stylesheet' link.href = url const head = document.getElementsByTagName('head')[0] head.appendChild(link) } /** * 判断路由是否相等 */ export const isObjectValueEqual = (a, b) => { let result = true Object.keys(a).forEach(ele => { const type = typeof (a[ele]) if (type === 'string' && a[ele] !== b[ele]) result = false else if (type === 'object' && JSON.stringify(a[ele]) !== JSON.stringify(b[ele])) result = false }) return result } /** * 根据字典的value显示label */ export const findByvalue = (dic, value) => { let result = '' if (validatenull(dic)) return value if (typeof (value) === 'string' || typeof (value) === 'number' || typeof (value) === 'boolean') { let index = 0 index = findArray(dic, value) if (index != -1) { result = dic[index].label } else { result = value } } else if (value instanceof Array) { result = [] let index = 0 value.forEach(ele => { index = findArray(dic, ele) if (index != -1) { result.push(dic[index].label) } else { result.push(value) } }) result = result.toString() } return result } /** * 根据字典的value查找对应的index */ export const findArray = (dic, value) => { for (let i = 0; i < dic.length; i++) { if (dic[i].value == value) { return i } } return -1 } /** * 生成随机len位数字 */ export const randomLenNum = (len, date) => { let random = '' random = Math.ceil(Math.random() * 100000000000000).toString().substr(0, len || 4) if (date) random = random + Date.now() return random } /** * 将xx/:params=abc转化为xx/abc * @param {*} routePath * @returns */ export const newFilterFn=(routePath='')=>{ if(routePath&&routePath.includes('/:')){ let tempSrc = routePath.replace(/\/:.*$/, ''), paramVal = routePath.split('=')[1]; routePath = tempSrc +'/' + paramVal; } return routePath; } //map export const newRouteArr=(arr=[])=>{ return arr.map(item=>{ item.path = newFilterFn(item.path); if(item['children']){ item.children = newRouteArr(item.children); } return item; }); } ``` ### permission.js ``` /** * 全站权限配置 * */ import router from './router/router' import store from '@/store' import {validatenull} from '@/util/validate' import NProgress from 'nprogress' // progress bar import 'nprogress/nprogress.css' // progress bar style NProgress.configure({showSpinner: false}) /** * 导航守卫,相关内容可以参考: * https://router.vuejs.org/zh/guide/advanced/navigation-guards.html */ router.beforeEach((to, from, next) => { // 缓冲设置 if (to.meta.keepAlive === true && store.state.tags.tagList.some(ele => { return ele.value === to.fullPath })) { to.meta.$keepAlive = true } else { NProgress.start() if (to.meta.keepAlive === true && validatenull(to.meta.$keepAlive)) { to.meta.$keepAlive = true } else { to.meta.$keepAlive = false } } const meta = to.meta || {} if (store.getters.access_token) { if (to.path === '/login') { next({path: '/'}) } else { // NOTE: 当用户角色不存在时,会存在无限请求用户信息接口的问题 if (store.getters.roles.length === 0) { store.dispatch('GetUserInfo').then(() => { next() }).catch(() => { store.dispatch('FedLogOut').then(() => { next({path: '/login'}) }) }) } else { const value = to.query.src || to.fullPath const label = router.$avueRouter.getRealName(to) || to.query.name || to.name // 针对外链跳转 if (value.includes('http') || value.includes('https')) { NProgress.done(); window.open(value, '_blank') return } if (meta.isTab !== false && !validatenull(value) && !validatenull(label)) { store.commit('ADD_TAG', { label: label, value: value, params: to.params, query: to.query, group: router.$avueRouter.group || [] }) } next() } } } else { if (meta.isAuth === false) { next() } else { next('/login') } } }) router.afterEach(() => { NProgress.done() const title = store.getters.tag.label router.$avueRouter.setTitle(title) }) ```
此 Pull Request 无法自动合并
尝试通过 WebIDE 解决冲突
怎样手动合并此 Pull Request
git checkout dev
git pull https://gitee.com/log4j/pig-ui.git electron
git push origin dev
评论
3
提交
84
文件
100+
检查
代码问题
0
批量操作
展开设置
折叠设置
审查
Code Owner
审查人员
FelixSuXP
FelixSuXP
lisb
lisb
j3east
j3east
lht
LauCollapsar
lengleng
log4j
李寻欢
best_lxh
smallwei
smallweigit
lbw
gi2
aeizzz
aeizzz
未设置
最少人数
0
测试
FelixSuXP
FelixSuXP
lisb
lisb
j3east
j3east
lht
LauCollapsar
lengleng
log4j
李寻欢
best_lxh
smallwei
smallweigit
lbw
gi2
aeizzz
aeizzz
未设置
最少人数
0
优先级
不指定
严重
主要
次要
不重要
标签
标签管理
未设置
关联 Issue
未关联
Pull Request 合并后将关闭上述关联 Issue
里程碑
未关联里程碑
参与者
(3)
JavaScript
1
https://gitee.com/log4j/pig-ui.git
git@gitee.com:log4j/pig-ui.git
log4j
pig-ui
pig-ui
点此查找更多帮助
搜索帮助
Git 命令在线学习
如何在 Gitee 导入 GitHub 仓库
Git 仓库基础操作
企业版和社区版功能对比
SSH 公钥设置
如何处理代码冲突
仓库体积过大,如何减小?
如何找回被删除的仓库数据
Gitee 产品配额说明
GitHub仓库快速导入Gitee及同步更新
什么是 Release(发行版)
将 PHP 项目自动发布到 packagist.org
仓库举报
回到顶部
登录提示
该操作需登录 Gitee 帐号,请先登录后再操作。
立即登录
没有帐号,去注册