

项目创建好之后新建一个vue.config.js文件
这是项目的配置文件包含打包路径、css、跨域、插件配置、别名配置等等,可以进入webpack这块看一看,会带我们入门

配置vue.config.js是需要点前置知识
webpack的官网:https://webpack.docschina.org/concepts/
node知识:https://www.runoob.com/nodejs/nodejs-global-object.html (比如有_dirname、requrire(paht)等等)
看一看已经配置好的vue.config.js
//引入path模块,提供了处理和转换文件路径的工具
const path = require('path');
//设置绝对路径,后面配置路径别名有用
function resolve(dir) {
//__dirname是__dirname 表示当前执行脚本所在的目录
return path.join(__dirname, dir)
}
// 向外暴露该模块
module.exports = {
// 基本路径
publicPath: process.env.NODE_ENV === 'prod' ? '' : './',
// 输出文件目录
outputDir: process.env.NODE_ENV === 'prod' ? 'dist' : 'devdist',
//打包好的静态文件位置
assetsDir: 'static',
// eslint-loader 是否在保存的时候检查,代码格式检查,一般不开,不然一直报错
lintOnSave: false,
// 生产环境是否生成 sourceMap 文件
productionSourceMap: false,
// css相关配置
css: {
// 是否使用css分离插件 ExtractTextPlugin
extract: true,
// 开启 CSS source maps?
sourceMap: false,
// css预设器配置项
loaderOptions: {
// 全局样式配置,也可以不要
// sass: {
// prependData: `@import "./src/common/css/global.scss";`
// }
//scss: {
// prependData: `@import "./src/styles/main.scss";`
//}
},
// 启用 CSS modules for all css / pre-processor files.
requireModuleExtension: true,
},
//跨域配置
devServer: {
open: true, // 编译完成是否打开网页
host: '0.0.0.0', // 指定使用地址,默认localhost,0.0.0.0代表可以被外界访问
//port: 8080, // 访问端口
https: false, // 编译失败时刷新页面
hot: true, // 开启热加载
hotOnly: false,
proxy: {
//设置代理
'/api': {
// target: `${VUE_APP_BASE_API}`,自己的后端服务接口
// target: 'http://old.web-jshtml.cn/vue_admin_api',
target: 'http://localhost:8088/konglz',
changeOrigin: true,
ws: true,
secure: false, //如果是http接口,需要配置该参数
//将上面的dev-api变成''
pathRewrite: {
'^/api': ''
}
}
},
overlay: { // 全屏模式下是否显示脚本错误
warnings: true,
errors: true
},
before: app => {
}
},
//链式配置配置规则,这里是svg一些配置
chainWebpack: config => {
config.module
.rule('svg')
.exclude.add(resolve('src/icons')) //对应下面配置svg的路径
.end();
config.module
.rule('icons')
.test(/\.svg$/)
.include.add(resolve('src/icons')) //对应下面配置svg的路径
.end()
.use('svg-sprite-loader')
.loader('svg-sprite-loader')
.options({
symbolId: 'icon-[name]'
})
.end();
},
//别名配置用到了我们上面的resove()函数
configureWebpack: (config) => {
config.resolve = { // 配置解析别名
extensions: ['.js', '.json', '.vue'],
alias: {
// 改变vue的运行模式由默认的runtime改为compiler,为了使用全局组件
'vue': 'vue/dist/vue.js',
'@': path.resolve(__dirname, './src'),
'public': path.resolve(__dirname, './public'),
'components': path.resolve(__dirname, './src/components'),
'api': path.resolve(__dirname, './src/api'),
'views': path.resolve(__dirname, './src/views'),
'data': path.resolve(__dirname, './src/data')
}
}
},
// 构建时开启多进程处理 babel 编译
//是否为 Babel 或 TypeScript 使用 thread-loader。
//该选项在系统的 CPU 有多于一个内核时自动启用,仅作用于生产构建,在适当的时候开启几个子进程去并发的执行压缩
parallel: require("os").cpus().length > 1,
}
//-g是全局安装
npm install --save element-ui
//引入element-ui
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
Vue.use(ElementUI);
npm install --save axios vue-axios
npm install font-awesome --save
/* 使用font-awesone图标库 */
import 'font-awesome/css/font-awesome.min.css'
//svg依赖
npm install --save js-cookie
参考:https://router.vuejs.org/zh/introduction.html
目录结构

/**
* 全局常量、方法封装模块
* 通过原型挂载到Vue属性
* 通过 this.Global 调用
*/
// 后台管理系统服务器地址
//这个配置的是跨域地址,它会转到帮我们转到${process.env.VUE_APP_BASE_URL}
export const baseUrl = 'http://localhost:8080/api'
//也可以直接使用后端的地址,这时不用配跨域把vue.config.js的proxy注释掉
//export const baseUrl = 'http://localhost:8088/konglz'
// 系统数据备份还原服务器地址
export const backupBaseUrl = 'http://localhost:8080'
export default {
baseUrl,
backupBaseUrl
}
// const BASEURL = process.env.NODE_ENV === 'production' ? process.env.VUE_APP_BASE_API : process.env.VUE_APP_BASE_API;
import { baseUrl } from '@/utils/global'
export default {
method: 'get',
// 基础url前缀
// baseUrl: BASEURL,
baseUrl: baseUrl,
// 请求头信息
headers: {
'Content-Type': 'application/json;charset=UTF-8'
},
// 参数
data: {},
// 设置超时时间
timeout: 10000,
// 携带凭证
withCredentials: true,
// 返回数据类型
responseType: 'json'
}
import axios from 'axios';
import config from './config';
import Cookies from "js-cookie";
import router from '@/router'
const service = axios.create({
baseURL: config.baseUrl,
headers: config.headers,
timeout: config.timeout,
withCredentials: config.withCredentials
})
service.interceptors.request.use(
config => {
let token = Cookies.get('token')
// 发送请求时携带token
if (token) {
config.headers.token = token
} else {
// 重定向到登录页面
router.push('/login')
}
return config
},
error => {
// 请求发生错误时
console.log('request:', error)
// 判断请求超时
if (error.code === 'ECONNABORTED' && error.message.indexOf('timeout') !== -1) {
console.log('timeout请求超时')
}
// 需要重定向到错误页面
const errorInfo = error.response
console.log(errorInfo)
if (errorInfo) {
error = errorInfo.data // 页面那边catch的时候就能拿到详细的错误信息,看最下边的Promise.reject
const errorStatus = errorInfo.status; // 404 403 500 ...
router.push({
path: `/error/${errorStatus}`
})
}
return Promise.reject(error) // 在调用的那边可以拿到(catch)你想返回的错误信息
}
)
service.interceptors.response.use(
response => {
return response.data
},
err => {
if (err && err.response) {
switch (err.response.status) {
case 400:
err.message = '请求错误'
break
case 401:
err.message = '未授权,请登录'
break
case 403:
err.message = '拒绝访问'
break
case 404:
err.message = `请求地址出错: ${err.response.config.url}`
break
case 408:
err.message = '请求超时'
break
case 500:
err.message = '服务器内部错误'
break
case 501:
err.message = '服务未实现'
break
case 502:
err.message = '网关错误'
break
case 503:
err.message = '服务不可用'
break
case 504:
err.message = '网关超时'
break
case 505:
err.message = 'HTTP版本不受支持'
break
default:
}
}
console.error(err)
return Promise.reject(err) // 返回接口返回的错误信息
}
)
export default service
/*
* 接口统一集成模块
*/
import * as login from './modules/login'
import * as user from './modules/user'
import * as menu from './modules/menu'
// 默认全部导出
export default {
login,
user,
menu,
}
login.js
import service from '@/api/request.js'; //导入request中创建的实例
//参考文档:http://axios-js.com/zh-cn/docs/
/*
* 系统登录模块
*/
// 获取验证码
export const getverifyCode = () =>{
return service.request({
method: "get",
url: "/getVerifyCode"
// data: data, 左边的data是变量名(key)后台接收的。右边的Data是接收的参数。如果两者都是同名的情况下,可以写成单一个即可(ES6的写法)
})
}
// 登录接口
export const login = (data) =>{
return service.request({
url: '/login',
method: 'post',
data: data
})
}
// 导入所有接口
import api from './api'
const install = Vue => {
if (install.installed)
return;
install.installed = true;
Object.defineProperties(Vue.prototype, {
// 注意,此处挂载在 Vue 原型的 $api 对象上
$api: {
get() {
return api
}
}
})
}
export default install
getVeCode(){
this.$api.login.getverifyCode().then(res=>{
console.log(res)
this.imageUrl = res.data.base64
this.code = res.data.code
})
},
参考:https://vuex.vuejs.org/zh/
注意: 使用namespaced: true 需要在调用添加具体的模块名比如 this.$store.commit(‘app/onCollapse’)
目录结构

import Vue from 'vue'
import vuex from 'vuex'
Vue.use(vuex);
// 引入子模块
import app from './modules/app'
import tab from './modules/tab'
import user from './modules/user'
import menu from './modules/menu'
const store = new vuex.Store({
modules: {
app: app,
tab: tab,
user: user,
menu: menu
}
})
export default store
import {login,getverifyCode} from '@/api/modules/login.js'
const state = {
appName: "Mango Platform", // 应用名称
themeColor: "#14889A", // 主题颜色
oldThemeColor: "#14889A", // 上一次主题颜色
collapse: false, // 导航栏收缩状态
menuRouteLoaded: false // 菜单和路由是否已经加载
}
const getters = {
collapse(state){// 对应着上面state
return state.collapse
}
}
const mutations = {
onCollapse(state){ // 改变收缩状态
state.collapse = !state.collapse
},
setThemeColor(state, themeColor){ // 改变主题颜色
state.oldThemeColor = state.themeColor
state.themeColor = themeColor
},
menuRouteLoaded(state, menuRouteLoaded){ // 改变菜单和路由的加载状态
state.menuRouteLoaded = menuRouteLoaded;
}
}
const actions= {
getverifyCode(content) {
return new Promise((resolve, reject) => {
getverifyCode().then(response=>{
resolve(response)
}).catch(error => {
reject(error)
})
})
},
// getClassifyList(content,data) {
// return new Promise((resolve, reject) => {
// getClassifyList(data).then(response => {
// resolve(response)
// }).catch(error => {
// reject(error)
// })
// })
// },
}
export default {
//namespaced: true,
state,
getters,
mutations,
actions
}

npm install --save svg-sprite-loader
//链式配置配置规则,这里是svg一些配置
chainWebpack: config => {
config.module
.rule('svg')
.exclude.add(resolve('src/assets/icons')) //对应下面配置svg的路径
.end();
config.module
.rule('icons')
.test(/\.svg$/)
.include.add(resolve('src/assets/icons')) //对应下面配置svg的路径
.end()
.use('svg-sprite-loader')
.loader('svg-sprite-loader')
.options({
symbolId: 'icon-[name]'
})
.end();
},
import Vue from 'vue';
import SvgIcon from '@/components/SvgIcon/index.vue';
// import SvgIcon from '@/components/SvgIcon.vue';
Vue.component('svg-icon',SvgIcon)
//读取指定目录的所有文件,用来读取svg文件夹下存的图标
/**
第一个:目录
第二个:是否遍历子级目录
第三个:定义遍历文件规则
*/
const req = require.context('./svg', false, /\.svg$/)
const requireAll = requireContext => {
console.log(requireContext.keys().map(requireContext));
return requireContext.keys().map(requireContext);
}
requireAll(req)
<svg-icon :iconClass="collapse === false ? 'fold-left' : 'fold-right' " :className="collapse === false ? 'fold-left' : 'fold-right'" />
npm install --save vue-i18n
//vue2 用下面这个
npm i --save vue-i18n@8
{
"common": {
"home": "Home",
"login": "Login",
"logout": "Logout",
"doc": "Document",
"blog": "Blog",
"projectRepo": "Project",
"myMsg": "My Message",
"config": "Config",
"backup": "Backup",
"restore": "Restore",
"backupRestore": "Backup Restore",
"versionName": "Version",
"exit": "Exit"
},
"action": {
"operation": "Operation",
"add": "Add",
"edit": "Edit",
"delete": "Delete",
"batchDelete": "Batch Delete",
"search": "Search",
"loading": "loading",
"submit": "Submit",
"comfirm": "Comfirm",
"cancel": "Cancel",
"reset": "Reset"
},
"nav": {
"home": "Home",
"monitor": "Monitor",
"analyze": "Analyze",
"alarm": "Alarm",
"maintenance": "Maintenance",
"config": "Config",
"device": "Device",
"scada": "Scada"
},
"confirm": {
"ok": "Logout",
"cancel": "Cancel",
"content": "Are you sure you want to quit the system?",
"logout": "Logout"
},
"breadCrumb": {
"home": "Home",
"sysIntro": "SysIntro",
"sysAdmin": "SysAdmin",
"userAdmin": "UserAdmin",
"roleAdmin": "RoleAdmin",
"menuAdmin": "MenuAdmin",
"loginLog": "LoginLog",
"operateLog": "OperateLog"
}
}
{
"common": {
"home": "首页",
"login": "登录",
"logout": "退出登录",
"doc": "文档",
"blog": "博客",
"projectRepo": "项目",
"myMsg": "我的消息",
"config": "系统配置",
"backup": "备份",
"restore": "还原",
"backupRestore": "备份还原",
"versionName": "版本名称",
"exit": "退出"
},
"action": {
"operation": "操作",
"add": "新增",
"edit": "编辑",
"delete": "删除",
"batchDelete": "批量删除",
"search": "查询",
"loading": "拼命加载中",
"submit": "提交",
"comfirm": "确定",
"cancel": "取消",
"reset": "重置"
},
"nav": {
"home": "首页",
"monitor": "监控",
"analyze": "分析",
"alarm": "报警",
"maintenance": "运维",
"config": "配置",
"device": "设备",
"scada": "画面"
},
"confirm": {
"ok": "确认",
"cancel": "取消",
"content": "你确认要退出系统吗?",
"logout": "退 出"
},
"breadCrumb": {
"home": "首页",
"sysIntro": "系统介绍",
"sysAdmin": "系统管理",
"userAdmin": "用户管理",
"roleAdmin": "角色管理",
"menuAdmin": "菜单管理",
"loginLog": "登录日志",
"operateLog": "操作日志"
}
}
import Vue from 'vue'
import VueI18n from 'vue-i18n'
Vue.use(VueI18n)
// 注册i18n实例并引入语言文件,文件格式等下解析
const i18n = new VueI18n({
locale: 'zh_cn',
messages: {
'zh_cn': require('@/assets/languages/zh_cn.json'),
'en_us': require('@/assets/languages/en_us.json')
}
})
export default i18n
//i18n插件
import i18n from './i18n'
new Vue({
i18n,
router,
store,
render: h => h(App)
}).$mount('#app')
//使用$t(xxx),xxx是i18n模块下的变量,这样方式不太适用从后端获取的动态菜单数据
{{$t("common.doc")}}
// 语言切换
changeLanguage(lang) {
lang === '' ? 'zh_cn' : lang
this.$i18n.locale = lang
this.langVisible = false
}
import { login, getverifyCode } from '@/api/modules/login.js'
const state = {
appName: "konglz-admin", // 应用名称
themeColor: "#14889A", // 主题颜色
oldThemeColor: "#14889A", // 上一次主题颜色
collapse: false, // 导航栏收缩状态
menuRouteLoaded: false, // 菜单和路由是否已经加载
}
const getters = {
collapse(state) {// 对应着上面state
return state.collapse
}
}
const mutations = {
onCollapse(state) { // 改变收缩状态
state.collapse = !state.collapse
},
setThemeColor(state, themeColor) { // 改变主题颜色
state.oldThemeColor = state.themeColor
state.themeColor = themeColor
},
menuRouteLoaded(state, menuRouteLoaded) { // 改变菜单和路由的加载状态
state.menuRouteLoaded = menuRouteLoaded;
},
}
const actions = {
getverifyCode(content) {
return new Promise((resolve, reject) => {
getverifyCode().then(response => {
resolve(response)
}).catch(error => {
reject(error)
})
})
},
// getClassifyList(content,data) {
// return new Promise((resolve, reject) => {
// getClassifyList(data).then(response => {
// resolve(response)
// }).catch(error => {
// reject(error)
// })
// })
// },
}
export default {
//namespaced: true,
state,
getters,
mutations,
actions
}
{{menu.name}}
{{menu.name}}
{{ item.name }}
// Breadcrumb.vue
<template>
<div class="headbar" :style="{'background':themeColor}"
:class="collapse?'position-collapse-left':'position-left'">
<!-- 导航收缩 -->
<span class="hamburg">
<el-menu class="el-menu-demo" :background-color="themeColor" text-color="#fff"
:active-text-color="themeColor" mode="horizontal">
<el-menu-item index="1" @click="onCollapse">
<!-- <hamburger :isActive="collapse"></hamburger> -->
<svg-icon :iconClass="collapse === false ? 'fold-left' : 'fold-right' " :className="collapse === false ? 'fold-left' : 'fold-right'" />
</el-menu-item>
</el-menu>
</span>
<span class="bread"> <bread-crumb></bread-crumb></span>
<!-- 工具栏 -->
<span class="toolbar">
<el-menu class="el-menu-demo" :background-color="themeColor" text-color="#14889A"
:active-text-color="themeColor" mode="horizontal">
<el-menu-item index="1">
<!-- 主题切换 -->
<theme-picker class="theme-picker" :default="themeColor"
@onThemeChange="onThemeChange">
</theme-picker>
</el-menu-item>
<el-menu-item index="2" v-popover:popover-lang>
<!-- 语言切换 -->
<li style="color:#fff;" class="fa fa-language fa-lg"></li>
<el-popover ref="popover-lang" placement="bottom-start" trigger="click" v-model="langVisible">
<div class="lang-item" @click="changeLanguage('zh_cn')">简体中文</div>
<div class="lang-item" @click="changeLanguage('en_us')">English</div>
</el-popover>
</el-menu-item>
<el-menu-item index="3" v-popover:popover-message>
<!-- 我的私信 -->
<el-badge :value="5" :max="99" class="badge">
<li style="color:#fff;" class="fa fa-envelope-o fa-lg"></li>
</el-badge>
<el-popover ref="popover-message" placement="bottom-end" trigger="click">
<message-panel></message-panel>
</el-popover>
</el-menu-item>
<el-menu-item index="4" v-popover:popover-notice>
<!-- 系统通知 -->
<el-badge :value="4" :max="99" class="badge">
<li style="color:#fff;" class="fa fa-bell-o fa-lg"></li>
</el-badge>
<el-popover ref="popover-notice" placement="bottom-end" trigger="click">
<notice-panel></notice-panel>
</el-popover>
</el-menu-item>
<el-menu-item index="5" v-popover:popover-personal>
<!-- 用户信息 -->
<!-- <span class="user-info"><img :src="user.avatar" />{{user.name}}</span> -->
<span class="el-dropdown-link">
<el-avatar :size="40">klz</el-avatar>
</span>
<el-popover ref="popover-personal" placement="bottom-end" trigger="click" :visible-arrow="false">
<personal-panel :user="user"></personal-panel>
</el-popover>
</el-menu-item>
</el-menu>
</span>
</div>
</template>
<script>
import BreadCrumb from '@/components/BreadCrumb'
import SvgIcon from '@/components/SvgIcon'
import { mapState } from 'vuex'
// import Hamburger from "@/components/Hamburger"
import ThemePicker from "@/components/ThemePicker"
// import NoticePanel from "@/views/Core/NoticePanel"
// import MessagePanel from "@/views/Core/MessagePanel"
// import PersonalPanel from "@/views/Core/PersonalPanel"
export default {
components:{
// Hamburger,
ThemePicker,
BreadCrumb
// NoticePanel,
// MessagePanel,
// PersonalPanel
},
data() {
return {
user: {
name: "konglz",
avatar: "",
role: "超级管理员",
registeInfo: "注册时间:2018-12-20 "
},
activeIndex: '1',
langVisible: false,
foldMenu: 'fold-left',
// collapse: this.$store.app.state.collapse
}
},
methods: {
openWindow(url) {
window.open(url)
},
selectNavBar(key, keyPath) {
console.log(key, keyPath)
},
// 折叠导航栏
onCollapse: function() {
this.$store.commit('onCollapse')
// console.log(this.collapse)
// if(this.collapse){
// this.foldMenu = 'fold-right'
// }else{
// this.foldMenu = 'fold-left'
// }
},
// 切换主题
onThemeChange: function(themeColor) {
this.$store.commit('setThemeColor', themeColor)
},
// 语言切换
changeLanguage(lang) {
lang === '' ? 'zh_cn' : lang
this.$i18n.locale = lang
this.langVisible = false
}
},
mounted() {
var user = sessionStorage.getItem("user")
// if (user) {
// this.user.name = user
// this.user.avatar = require("@/assets/user.png")
// }
},
computed:{
...mapState({
themeColor: state=>state.app.themeColor,
collapse: state=>state.app.collapse
})
}
}
</script>
<style scoped lang="scss">
.headbar {
position: fixed;
top: 0;
right: 0;
z-index: 1030;
height: 60px;
line-height: 60px;
border-color: rgba(180, 190, 190, 0.8);
border-left-width: 1px;
border-left-style: solid;
}
.hamburg {
float: left;
}
.bread{
float: left;
padding: 0px;
margin: 0px;
// border: 1px solid red;
margin-top: 20px;
}
.navbar {
float: left;
}
.toolbar {
float: right;
}
.lang-item {
font-size: 16px;
padding-left: 8px;
padding-top: 8px;
padding-bottom: 8px;
cursor: pointer;
}
.lang-item:hover {
font-size: 18px;
background: #b0d6ce4d;
}
.user-info {
font-size: 20px;
color: #fff;
cursor: pointer;
img {
width: 40px;
height: 40px;
border-radius: 10px;
margin: 10px 0px 10px 10px;
float: right;
}
}
.badge {
line-height: 18px;
}
.position-left {
left: 200px;
}
.position-collapse-left {
left: 65px;
}
// svg格式图标的大小,不知道为什么设置
// .svg-icon {
// font-size: 25px;
// width: 60px;
// cursor: pointer;
// align-items: center;
// }
</style>
import Vue from 'vue'
import VueRouter from 'vue-router'
import api from '@/api/api'
import store from '@/store'
import { getIFramePath, getIFrameUrl } from '@/utils/iframe'
Vue.use(VueRouter)
const routes = [
{
path: '/',
name: '首页',
component: () => import('@/views/layout/Home.vue'),
children: [
{
path: '',
name: '系统介绍',
component: () => import('@/views/Intro.vue'),
meta: {
icon: 'fa fa-home fa-lg',
index: 0
}
}
]
},
{
path: '/login',
name: 'Login',
component: () => import('@/views/Login.vue')
},
// {
// path: '/register',
// name: 'Register',
// component: ()=> import('@/views/Register.vue')
// },
]
const router = new VueRouter({
//路由模式默认是hash会在拒绝后面加上#
// mode: 'history',
routes
})
//路由守卫
router.beforeEach((to, from, next) => {
// 登录界面登录成功之后,会把用户信息保存在会话
// 存在时间为会话生命周期,页面关闭即失效。
let userName = sessionStorage.getItem('user')
if (to.path === '/login') {
// 如果是访问登录界面,如果用户会话信息存在,代表已登录过,跳转到主页
if(userName) {
next({ path: '/' })
} else {
next()
}
} else {
if (!userName) {
// 如果访问非登录界面,且户会话信息不存在,代表未登录,则跳转到登录界面
next({ path: '/login' })
} else {
// 加载动态菜单和路由
addDynamicMenuAndRoutes(userName, to, from)
next()
}
}
})
/**
* 加载动态菜单和路由
*/
function addDynamicMenuAndRoutes(userName, to, from) {
// 处理IFrame嵌套页面
handleIFrameUrl(to.path)
if(store.state.app.menuRouteLoaded) {
console.log('动态菜单和路由已经存在.')
return
}
api.menu.findNavTree({'userName':userName})
.then(res => {
// 添加动态路由
let dynamicRoutes = addDynamicRoutes(res.data)
// 处理静态组件绑定路由
router.options.routes[0].children = router.options.routes[0].children.concat(dynamicRoutes)
router.addRoutes(router.options.routes)
// 保存加载状态
store.commit('menuRouteLoaded', true)
// 保存菜单树
store.commit('setNavTree', res.data)
}).then(res => {
api.user.findPermissions({'name':userName}).then(res => {
// 保存用户权限标识集合
store.commit('setPerms', res.data)
})
})
.catch(function(res) {
})
}
/**
* 处理IFrame嵌套页面
*/
function handleIFrameUrl(path) {
// 嵌套页面,保存iframeUrl到store,供IFrame组件读取展示
let url = path
let length = store.state.iframe.iframeUrls.length
for(let i=0; i<length; i++) {
let iframe = store.state.iframe.iframeUrls[i]
if(path != null && path.endsWith(iframe.path)) {
url = iframe.url
store.commit('setIFrameUrl', url)
break
}
}
}
/**
* 添加动态(菜单)路由
* @param {*} menuList 菜单列表
* @param {*} routes 递归创建的动态(菜单)路由
*/
function addDynamicRoutes (menuList = [], routes = []) {
var temp = []
for (var i = 0; i < menuList.length; i++) {
if (menuList[i].children && menuList[i].children.length >= 1) {
temp = temp.concat(menuList[i].children)
} else if (menuList[i].url && /\S/.test(menuList[i].url)) {
menuList[i].url = menuList[i].url.replace(/^\//, '')
// 创建路由配置
var route = {
path: menuList[i].url,
component: null,
name: menuList[i].name,
meta: {
icon: menuList[i].icon,
index: menuList[i].id
}
}
let path = getIFramePath(menuList[i].url)
if (path) {
// 如果是嵌套页面, 通过iframe展示
route['path'] = path
route['component'] = resolve => require([`@/views/IFrame/IFrame`], resolve)
// 存储嵌套页面路由路径和访问URL
let url = getIFrameUrl(menuList[i].url)
let iFrameUrl = {'path':path, 'url':url}
store.commit('addIFrameUrl', iFrameUrl)
} else {
try {
// 根据菜单URL动态加载vue组件,这里要求vue组件须按照url路径存储
// 如url="sys/user",则组件路径应是"@/views/sys/user.vue",否则组件加载不到
let array = menuList[i].url.split('/')
let url = ''
for(let i=0; i<array.length; i++) {
url += array[i].substring(0,1).toUpperCase() + array[i].substring(1) + '/'
}
url = url.substring(0, url.length - 1)
route['component'] = resolve => require([`@/views/${url}`], resolve)
} catch (e) {}
}
routes.push(route)
}
}
if (temp.length >= 1) {
addDynamicRoutes(temp, routes)
} else {
console.log('动态路由加载...')
console.log(routes)
console.log('动态路由加载完成.')
}
return routes
}
export default router
import { login, getverifyCode } from '@/api/modules/login.js'
const state = {
appName: "Mango Platform", // 应用名称
themeColor: "#14889A", // 主题颜色
oldThemeColor: "#14889A", // 上一次主题颜色
collapse: false, // 导航栏收缩状态
menuRouteLoaded: false // 菜单和路由是否已经加载
}
const getters = {
collapse(state) {// 对应着上面state
return state.collapse
}
}
const mutations = {
onCollapse(state) { // 改变收缩状态
state.collapse = !state.collapse
},
setThemeColor(state, themeColor) { // 改变主题颜色
state.oldThemeColor = state.themeColor
state.themeColor = themeColor
},
menuRouteLoaded(state, menuRouteLoaded) { // 改变菜单和路由的加载状态
state.menuRouteLoaded = menuRouteLoaded;
}
}
const actions = {
getverifyCode(content) {
return new Promise((resolve, reject) => {
getverifyCode().then(response => {
resolve(response)
}).catch(error => {
reject(error)
})
})
},
// getClassifyList(content,data) {
// return new Promise((resolve, reject) => {
// getClassifyList(data).then(response => {
// resolve(response)
// }).catch(error => {
// reject(error)
// })
// })
// },
}
export default {
namespaced: true,
state,
getters,
mutations,
actions
}
export default {
state: {
navTree: [], // 导航菜单树
},
getters: {
},
mutations: {
setNavTree(state, navTree){ // 设置导航菜单树
state.navTree = navTree;
}
},
actions: {
}
}
export default {
state: {
// 主入口标签页
mainTabs: [],
// 当前标签页名
mainTabsActiveName: ''
},
mutations: {
updateMainTabs (state, tabs) {
state.mainTabs = tabs
},
updateMainTabsActiveName (state, name) {
state.mainTabsActiveName = name
}
}
}
export default {
state: {
// 主入口标签页
mainTabs: [],
// 当前标签页名
mainTabsActiveName: ''
},
mutations: {
updateMainTabs (state, tabs) {
state.mainTabs = tabs
},
updateMainTabsActiveName (state, name) {
state.mainTabsActiveName = name
}
}
}
关闭当前标签
关闭其它标签
关闭全部标签
刷新当前标签
{{item.title}}
{{label}}
import store from '@/store'
/**
* 判断用户是否拥有操作权限
* 根据传入的权限标识,查看是否存在用户权限标识集合
* @param perms
*/
export function hasPermission (perms) {
let hasPermission = false
let permissions = store.state.user.perms
for(let i=0, len=permissions.length; i<len; i++) {
if(permissions[i] === perms) {
hasPermission = true;
break
}
}
return hasPermission
}
