282 changed files with 42132 additions and 27825 deletions
@ -0,0 +1,4 @@ |
|||
> 1% |
|||
last 2 versions |
|||
Chrome >= 63 |
|||
not dead |
|||
@ -0,0 +1,15 @@ |
|||
# https://editorconfig.org |
|||
root = true |
|||
|
|||
[*] |
|||
indent_style = space |
|||
indent_size = 2 |
|||
tab_width = 2 |
|||
end_of_line = lf |
|||
charset = utf-8 |
|||
trim_trailing_whitespace = true |
|||
insert_final_newline = true |
|||
|
|||
[*.md] |
|||
trim_trailing_whitespace = false |
|||
insert_final_newline = false |
|||
@ -1,3 +1,2 @@ |
|||
VUE_APP_VERSION=3.0 |
|||
VUE_APP_NAME=Bmz Admin |
|||
VUE_APP_API_BASE_URL=http://api.base.ahbmz.com/api |
|||
VUE_APP_NAME=Ele Admin |
|||
VUE_APP_API_BASE_URL=https://v2.eleadmin.com/api |
|||
|
|||
@ -1 +1 @@ |
|||
VUE_APP_API_BASE_URL=http://api.base.ahbmz.com/api |
|||
VUE_APP_API_BASE_URL=https://v2.eleadmin.com/api |
|||
|
|||
@ -1,2 +1,2 @@ |
|||
NODE_ENV=production |
|||
VUE_APP_API_BASE_URL=https://v1.eleadmin.com/api |
|||
VUE_APP_API_BASE_URL=https://v2.eleadmin.com/api |
|||
|
|||
@ -1,16 +1,21 @@ |
|||
module.exports = { |
|||
root: true, |
|||
env: { |
|||
browser: true, |
|||
node: true, |
|||
es6: true |
|||
}, |
|||
parser: 'vue-eslint-parser', |
|||
extends: [ |
|||
"plugin:vue/essential", |
|||
'eslint:recommended' |
|||
'plugin:vue/essential', |
|||
'eslint:recommended', |
|||
'prettier', |
|||
'plugin:prettier/recommended' |
|||
], |
|||
parserOptions: { |
|||
parser: 'babel-eslint' |
|||
parser: '@babel/eslint-parser', |
|||
ecmaVersion: 2020, |
|||
sourceType: 'module' |
|||
}, |
|||
rules: { |
|||
//"no-unused-vars": "off"
|
|||
} |
|||
} |
|||
rules: {} |
|||
}; |
|||
|
|||
@ -0,0 +1,4 @@ |
|||
/public/* |
|||
/src/assets/* |
|||
/dist/* |
|||
/node_modules/* |
|||
@ -1,5 +1,3 @@ |
|||
module.exports = { |
|||
presets: [ |
|||
'@vue/cli-plugin-babel/preset' |
|||
] |
|||
} |
|||
presets: ['@vue/cli-plugin-babel/preset'] |
|||
}; |
|||
|
|||
Binary file not shown.
@ -1,14 +1,13 @@ |
|||
{ |
|||
"compilerOptions": { |
|||
"target": "es6", |
|||
"module": "esnext", |
|||
"moduleResolution": "node", |
|||
"baseUrl": "./", |
|||
"paths": { |
|||
"@/*": [ |
|||
"src/*" |
|||
] |
|||
} |
|||
"@/*": ["src/*"] |
|||
}, |
|||
"lib": ["esnext", "dom", "dom.iterable", "scripthost"] |
|||
}, |
|||
"exclude": [ |
|||
"node_modules", |
|||
"dist" |
|||
] |
|||
"exclude": ["node_modules", "dist"] |
|||
} |
|||
File diff suppressed because it is too large
@ -1,56 +1,63 @@ |
|||
{ |
|||
"name": "ele-admin-template", |
|||
"version": "1.2.0", |
|||
"version": "1.8.0", |
|||
"private": true, |
|||
"scripts": { |
|||
"serve": "vue-cli-service serve", |
|||
"build": "vue-cli-service build", |
|||
"build:preview": "vue-cli-service build --mode preview", |
|||
"build:report": "vue-cli-service build --report", |
|||
"lint": "vue-cli-service lint" |
|||
"lint": "vue-cli-service lint", |
|||
"clean:lib": "rimraf node_modules" |
|||
}, |
|||
"dependencies": { |
|||
"@amap/amap-jsapi-loader": "^0.0.7", |
|||
"@riophae/vue-treeselect": "^0.4.0", |
|||
"@amap/amap-jsapi-loader": "^1.0.1", |
|||
"@ant-design/colors": "^6.0.0", |
|||
"@bytemd/plugin-gfm": "^1.11.0", |
|||
"@bytemd/vue": "^1.11.0", |
|||
"@tinymce/tinymce-vue": "^3.2.8", |
|||
"axios": "^0.21.1", |
|||
"core-js": "^3.8.3", |
|||
"countup.js": "^2.0.7", |
|||
"cropperjs": "^1.5.9", |
|||
"echarts": "^4.9.0", |
|||
"echarts-wordcloud": "^1.1.3", |
|||
"ele-admin": "^1.2.0", |
|||
"element-ui": "^2.15.0", |
|||
"@vue/composition-api": "^1.4.9", |
|||
"axios": "^0.26.0", |
|||
"core-js": "^3.21.1", |
|||
"countup.js": "^2.0.8", |
|||
"cropperjs": "^1.5.12", |
|||
"echarts": "^5.3.0", |
|||
"echarts-wordcloud": "^2.0.0", |
|||
"ele-admin": "1.8.0", |
|||
"element-ui": "^2.15.7", |
|||
"github-markdown-css": "^5.1.0", |
|||
"nprogress": "^0.2.0", |
|||
"tinymce": "^5.7.0", |
|||
"vue": "^2.6.12", |
|||
"vue-axios": "^2.1.5", |
|||
"vue-clipboard2": "^0.3.1", |
|||
"qrcodejs2": "^0.0.2", |
|||
"tinymce": "^5.10.3", |
|||
"vue": "^2.6.14", |
|||
"vue-clipboard2": "^0.3.3", |
|||
"vue-countup-v2": "^4.0.0", |
|||
"vue-qr": "^2.3.0", |
|||
"vue-router": "^3.5.1", |
|||
"vue-echarts": "^6.0.2", |
|||
"vue-i18n": "^8.27.0", |
|||
"vue-router": "^3.5.3", |
|||
"vuedraggable": "^2.24.3", |
|||
"vuex": "^3.6.2", |
|||
"xgplayer-vue": "^1.1.5", |
|||
"xlsx": "^0.16.9" |
|||
"xlsx": "^0.18.2" |
|||
}, |
|||
"devDependencies": { |
|||
"@vue/cli-plugin-babel": "^4.5.11", |
|||
"@vue/cli-plugin-eslint": "^4.5.11", |
|||
"@vue/cli-plugin-router": "^4.5.11", |
|||
"@vue/cli-plugin-vuex": "^4.5.11", |
|||
"@vue/cli-service": "^4.5.11", |
|||
"babel-eslint": "^10.1.0", |
|||
"@babel/core": "^7.17.5", |
|||
"@babel/eslint-parser": "^7.17.0", |
|||
"@vue/cli-plugin-babel": "^5.0.1", |
|||
"@vue/cli-plugin-eslint": "^5.0.1", |
|||
"@vue/cli-plugin-router": "^5.0.1", |
|||
"@vue/cli-plugin-vuex": "^5.0.1", |
|||
"@vue/cli-service": "^5.0.1", |
|||
"compression-webpack-plugin": "^6.1.1", |
|||
"eslint": "^6.8.0", |
|||
"eslint-plugin-vue": "^7.6.0", |
|||
"sass": "^1.3.0", |
|||
"sass-loader": "^10.1.1", |
|||
"vue-template-compiler": "^2.6.12" |
|||
}, |
|||
"browserslist": [ |
|||
"> 1%", |
|||
"last 2 versions", |
|||
"not dead" |
|||
] |
|||
"eslint": "^8.10.0", |
|||
"eslint-config-prettier": "^8.4.0", |
|||
"eslint-plugin-prettier": "^4.0.0", |
|||
"eslint-plugin-vue": "^8.5.0", |
|||
"prettier": "^2.5.1", |
|||
"sass": "^1.49.9", |
|||
"sass-loader": "^12.6.0", |
|||
"vue-eslint-parser": "^8.3.0", |
|||
"vue-template-compiler": "^2.6.14", |
|||
"webpack": "^5.0.0" |
|||
} |
|||
} |
|||
|
|||
@ -0,0 +1,19 @@ |
|||
module.exports = { |
|||
printWidth: 80, |
|||
tabWidth: 2, |
|||
useTabs: false, |
|||
semi: true, |
|||
singleQuote: true, |
|||
quoteProps: 'as-needed', |
|||
jsxSingleQuote: false, |
|||
trailingComma: 'none', |
|||
bracketSpacing: true, |
|||
bracketSameLine: false, |
|||
arrowParens: 'always', |
|||
requirePragma: false, |
|||
insertPragma: false, |
|||
proseWrap: 'never', |
|||
htmlWhitespaceSensitivity: 'strict', |
|||
vueIndentScriptAndStyle: true, |
|||
endOfLine: 'lf' |
|||
}; |
|||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
File diff suppressed because it is too large
@ -0,0 +1,53 @@ |
|||
import axios from '@/utils/request'; |
|||
|
|||
/** |
|||
* 获取支付笔数数据 |
|||
*/ |
|||
export async function getPayNumList() { |
|||
const res = await axios.get( |
|||
'https://cdn.eleadmin.com/20200610/analysis-pay-num.json' |
|||
); |
|||
if (res.data.code === 0) { |
|||
return res.data.data; |
|||
} |
|||
return Promise.reject(new Error(res.data.message)); |
|||
} |
|||
|
|||
/** |
|||
* 获取销售量数据 |
|||
*/ |
|||
export async function getSaleroomList() { |
|||
const res = await axios.get( |
|||
'https://cdn.eleadmin.com/20200610/analysis-saleroom.json' |
|||
); |
|||
if (res.data.code === 0) { |
|||
return res.data.data; |
|||
} |
|||
return Promise.reject(new Error(res.data.message)); |
|||
} |
|||
|
|||
/** |
|||
* 获取最近1小时访问情况数据 |
|||
*/ |
|||
export async function getVisitHourList() { |
|||
const res = await axios.get( |
|||
'https://cdn.eleadmin.com/20200610/analysis-visits.json' |
|||
); |
|||
if (res.data.code === 0) { |
|||
return res.data.data; |
|||
} |
|||
return Promise.reject(new Error(res.data.message)); |
|||
} |
|||
|
|||
/** |
|||
* 获取词云数据 |
|||
*/ |
|||
export async function getWordCloudList() { |
|||
const res = await axios.get( |
|||
'https://cdn.eleadmin.com/20200610/analysis-hot-search.json' |
|||
); |
|||
if (res.data.code === 0) { |
|||
return res.data.data; |
|||
} |
|||
return Promise.reject(new Error(res.data.message)); |
|||
} |
|||
@ -0,0 +1,41 @@ |
|||
import axios from '@/utils/request'; |
|||
const BASE_URL = process.env.BASE_URL; |
|||
|
|||
/** |
|||
* 获取中国地图geo数据 |
|||
*/ |
|||
export async function getChinaMapData() { |
|||
const res = await axios.get(BASE_URL + 'json/china-provinces.geo.json', { |
|||
baseURL: '' |
|||
}); |
|||
if (res.data) { |
|||
return res.data; |
|||
} |
|||
return Promise.reject(new Error('获取地图数据失败')); |
|||
} |
|||
|
|||
/** |
|||
* 获取用户分布数据 |
|||
*/ |
|||
export async function getUserCountList() { |
|||
const res = await axios.get( |
|||
'https://cdn.eleadmin.com/20200610/monitor-user-count.json' |
|||
); |
|||
if (res.data.code === 0) { |
|||
return res.data.data; |
|||
} |
|||
return Promise.reject(new Error(res.data.message)); |
|||
} |
|||
|
|||
/** |
|||
* 获取用户浏览器分布数据 |
|||
*/ |
|||
export async function getBrowserCountList() { |
|||
const res = await axios.get( |
|||
'https://cdn.eleadmin.com/20200610/monitor-browser-count.json' |
|||
); |
|||
if (res.data.code === 0) { |
|||
return res.data.data; |
|||
} |
|||
return Promise.reject(new Error(res.data.message)); |
|||
} |
|||
@ -0,0 +1,15 @@ |
|||
import axios from '@/utils/request'; |
|||
|
|||
/** |
|||
* 获取全部的班级数据 |
|||
*/ |
|||
export async function getAllClasses(params) { |
|||
const res = await axios.get( |
|||
'https://cdn.eleadmin.com/20200610/classes.json', |
|||
{ params } |
|||
); |
|||
if (res.data.code === 0) { |
|||
return res.data.data; |
|||
} |
|||
return Promise.reject(new Error(res.data.message)); |
|||
} |
|||
@ -0,0 +1,31 @@ |
|||
import axios from '@/utils/request'; |
|||
|
|||
/** |
|||
* 获取案卷列表 |
|||
* @param params |
|||
*/ |
|||
export async function getPieceList(params) { |
|||
const res = await axios.get( |
|||
'https://cdn.eleadmin.com/20200610/document.json', |
|||
{ params } |
|||
); |
|||
if (res.data.code === 0) { |
|||
return res.data.data; |
|||
} |
|||
return Promise.reject(new Error(res.data.message)); |
|||
} |
|||
|
|||
/** |
|||
* 获取卷内文件列表 |
|||
* @param params |
|||
*/ |
|||
export async function getArchiveList(params) { |
|||
const res = await axios.get( |
|||
'https://cdn.eleadmin.com/20200610/archive.json', |
|||
{ params } |
|||
); |
|||
if (res.data.code === 0) { |
|||
return res.data.data; |
|||
} |
|||
return Promise.reject(new Error(res.data.message)); |
|||
} |
|||
@ -0,0 +1,11 @@ |
|||
import request from '@/utils/request'; |
|||
|
|||
export async function pageUserScores() { |
|||
const res = await request.get( |
|||
'https://cdn.eleadmin.com/20200610/example-table-merge.json' |
|||
); |
|||
if (res.data.code === 0 && res.data.data) { |
|||
return res.data.data; |
|||
} |
|||
return Promise.reject(new Error(res.data.message)); |
|||
} |
|||
@ -0,0 +1,43 @@ |
|||
import axios from '@/utils/request'; |
|||
|
|||
/** |
|||
* 获取文件列表数据 |
|||
*/ |
|||
export async function getFileList({ directory, sort, order } = {}) { |
|||
const res = await axios.get( |
|||
'https://cdn.eleadmin.com/20200610/extension-files.json', |
|||
{ |
|||
params: { |
|||
directory, |
|||
sort, |
|||
order |
|||
} |
|||
} |
|||
); |
|||
if (res.data.code === 0) { |
|||
// 模拟按文件夹筛选
|
|||
let data = res.data.data; |
|||
if (directory) { |
|||
directory.split('/').forEach((d) => { |
|||
data = data.filter((t) => t.name === d)[0]?.data ?? []; |
|||
}); |
|||
} |
|||
// 模拟排序
|
|||
if (sort) { |
|||
data.sort((a, b) => { |
|||
if (a[sort] == b[sort]) { |
|||
return 0; |
|||
} |
|||
if (order === 'desc') { |
|||
return a[sort] < b[sort] ? 1 : -1; |
|||
} |
|||
return a[sort] < b[sort] ? -1 : 1; |
|||
}); |
|||
} |
|||
data.sort((a, b) => { |
|||
return b.isDirectory ?? false - a.isDirectory ?? false; |
|||
}); |
|||
return data; |
|||
} |
|||
return Promise.reject(new Error(res.data.message)); |
|||
} |
|||
@ -0,0 +1,26 @@ |
|||
/** |
|||
* 获取数据 |
|||
*/ |
|||
export async function queryList() { |
|||
const data = [ |
|||
{ |
|||
key: '1', |
|||
number: '00001', |
|||
name: 'John Brown', |
|||
department: '研发部' |
|||
}, |
|||
{ |
|||
key: '2', |
|||
number: '00002', |
|||
name: 'Jim Green', |
|||
department: '产品部' |
|||
}, |
|||
{ |
|||
key: '3', |
|||
number: '00003', |
|||
name: 'Joe Black', |
|||
department: '产品部' |
|||
} |
|||
]; |
|||
return data; |
|||
} |
|||
@ -0,0 +1,115 @@ |
|||
import request from '@/utils/request'; |
|||
|
|||
/** |
|||
* 获取当前登录的用户信息、菜单、权限、角色 |
|||
*/ |
|||
export async function getUserInfo() { |
|||
const res = await request.get('/auth/user'); |
|||
if (res.data.code === 0 && res.data.data) { |
|||
return res.data.data; |
|||
} |
|||
return Promise.reject(new Error(res.data.message)); |
|||
} |
|||
|
|||
/** |
|||
* 修改当前登录的用户密码 |
|||
*/ |
|||
export async function updatePassword(data) { |
|||
const res = await request.put('/auth/password', data); |
|||
if (res.data.code === 0) { |
|||
return res.data.message ?? '修改成功'; |
|||
} |
|||
return Promise.reject(new Error(res.data.message)); |
|||
} |
|||
|
|||
/** |
|||
* 查询未读通知 |
|||
*/ |
|||
export async function getUnreadNotice() { |
|||
return { |
|||
notice: [ |
|||
{ |
|||
color: '#60B2FC', |
|||
icon: 'el-icon-s-comment', |
|||
title: '你收到了一封14份新周报', |
|||
time: '2020-07-27 18:30:18' |
|||
}, |
|||
{ |
|||
color: '#F5686F', |
|||
icon: 'el-icon-s-check', |
|||
title: '许经理同意了你的请假申请', |
|||
time: '2020-07-27 09:08:36' |
|||
}, |
|||
{ |
|||
color: '#7CD734', |
|||
icon: 'el-icon-video-camera', |
|||
title: '陈总邀请你参加视频会议', |
|||
time: '2020-07-26 18:30:01' |
|||
}, |
|||
{ |
|||
color: '#FAAD14', |
|||
icon: 'el-icon-s-claim', |
|||
title: '你推荐的刘诗雨已通过第三轮面试', |
|||
time: '2020-07-25 16:38:46' |
|||
}, |
|||
{ |
|||
color: '#2BCACD', |
|||
icon: 'el-icon-message-solid', |
|||
title: '你的6月加班奖金已发放', |
|||
time: '2020-07-25 11:03:31' |
|||
} |
|||
], |
|||
letter: [ |
|||
{ |
|||
avatar: |
|||
'https://cdn.eleadmin.com/20200609/c184eef391ae48dba87e3057e70238fb.jpg', |
|||
title: 'SunSmile 评论了你的日志', |
|||
content: '写的不错, 以后多多向你学习~', |
|||
time: '2020-07-27 18:30:18' |
|||
}, |
|||
{ |
|||
avatar: |
|||
'https://cdn.eleadmin.com/20200609/948344a2a77c47a7a7b332fe12ff749a.jpg', |
|||
title: '刘诗雨 点赞了你的日志', |
|||
content: '写的不错, 以后多多向你学习~', |
|||
time: '2020-07-27 09:08:36' |
|||
}, |
|||
{ |
|||
avatar: |
|||
'https://cdn.eleadmin.com/20200609/2d98970a51b34b6b859339c96b240dcd.jpg', |
|||
title: '酷酷的大叔 评论了你的周报', |
|||
content: '写的不错, 以后多多向你学习~', |
|||
time: '2020-07-26 18:30:01' |
|||
}, |
|||
{ |
|||
avatar: |
|||
'https://cdn.eleadmin.com/20200609/f6bc05af944a4f738b54128717952107.jpg', |
|||
title: 'Jasmine 点赞了你的周报', |
|||
content: '写的不错, 以后多多向你学习~', |
|||
time: '2020-07-25 11:03:31' |
|||
} |
|||
], |
|||
todo: [ |
|||
{ |
|||
status: 0, |
|||
title: '刘诗雨的请假审批', |
|||
description: '刘诗雨在 07-27 18:30 提交的请假申请' |
|||
}, |
|||
{ |
|||
status: 1, |
|||
title: '第三方代码紧急变更', |
|||
description: '需要在 2020-07-27 之前完成' |
|||
}, |
|||
{ |
|||
status: 2, |
|||
title: '信息安全考试', |
|||
description: '需要在 2020-07-26 18:30 前完成' |
|||
}, |
|||
{ |
|||
status: 2, |
|||
title: 'EleAdmin发布新版本', |
|||
description: '需要在 2020-07-25 11:03 前完成' |
|||
} |
|||
] |
|||
}; |
|||
} |
|||
@ -0,0 +1,18 @@ |
|||
import axios from '@/utils/request'; |
|||
|
|||
/** |
|||
* 获取列表数据 |
|||
*/ |
|||
export async function queryList(params) { |
|||
const res = await axios.get( |
|||
'https://cdn.eleadmin.com/20200610/list-demo-basic.json', |
|||
{ params } |
|||
); |
|||
if (res.data.code === 0) { |
|||
return { |
|||
list: res.data.data, |
|||
count: res.data.count |
|||
}; |
|||
} |
|||
return Promise.reject(new Error(res.data.message)); |
|||
} |
|||
@ -0,0 +1,26 @@ |
|||
import axios from '@/utils/request'; |
|||
import { setToken } from '@/utils/token-util'; |
|||
|
|||
/** |
|||
* 登录 |
|||
*/ |
|||
export async function login(data) { |
|||
data.tenantId = 1; // 租户id
|
|||
const res = await axios.post('/login', data); |
|||
if (res.data.code === 0) { |
|||
setToken(res.data.data.access_token, data.remember); |
|||
return res.data.message; |
|||
} |
|||
return Promise.reject(new Error(res.data.message)); |
|||
} |
|||
|
|||
/** |
|||
* 获取验证码 |
|||
*/ |
|||
export async function getCaptcha() { |
|||
const res = await axios.get('/captcha'); |
|||
if (res.data.code === 0) { |
|||
return res.data.data; |
|||
} |
|||
return Promise.reject(new Error(res.data.message)); |
|||
} |
|||
@ -0,0 +1,79 @@ |
|||
import axios from '@/utils/request'; |
|||
|
|||
/** |
|||
* 分页查询字典数据 |
|||
* @param params 查询条件 |
|||
*/ |
|||
export async function pageDictionaryData(params) { |
|||
const res = await axios.get('/system/dictionary-data/page', { |
|||
params |
|||
}); |
|||
if (res.data.code === 0) { |
|||
return res.data.data; |
|||
} |
|||
return Promise.reject(new Error(res.data.message)); |
|||
} |
|||
|
|||
/** |
|||
* 查询字典数据列表 |
|||
* @param params 查询条件 |
|||
*/ |
|||
export async function listDictionaryData(params) { |
|||
const res = await axios.get('/system/dictionary-data', { |
|||
params |
|||
}); |
|||
if (res.data.code === 0) { |
|||
return res.data.data; |
|||
} |
|||
return Promise.reject(new Error(res.data.message)); |
|||
} |
|||
|
|||
/** |
|||
* 添加字典数据 |
|||
* @param data 字典数据信息 |
|||
*/ |
|||
export async function addDictionaryData(data) { |
|||
const res = await axios.post('/system/dictionary-data', data); |
|||
if (res.data.code === 0) { |
|||
return res.data.message; |
|||
} |
|||
return Promise.reject(new Error(res.data.message)); |
|||
} |
|||
|
|||
/** |
|||
* 修改字典数据 |
|||
* @param data 字典数据信息 |
|||
*/ |
|||
export async function updateDictionaryData(data) { |
|||
const res = await axios.put('/system/dictionary-data', data); |
|||
if (res.data.code === 0) { |
|||
return res.data.message; |
|||
} |
|||
return Promise.reject(new Error(res.data.message)); |
|||
} |
|||
|
|||
/** |
|||
* 删除字典数据 |
|||
* @param id 字典数据id |
|||
*/ |
|||
export async function removeDictionaryData(id) { |
|||
const res = await axios.delete('/system/dictionary-data/' + id); |
|||
if (res.data.code === 0) { |
|||
return res.data.message; |
|||
} |
|||
return Promise.reject(new Error(res.data.message)); |
|||
} |
|||
|
|||
/** |
|||
* 批量删除字典数据 |
|||
* @param data 字典数据id集合 |
|||
*/ |
|||
export async function removeDictionaryDataBatch(data) { |
|||
const res = await axios.delete('/system/dictionary-data/batch', { |
|||
data |
|||
}); |
|||
if (res.data.code === 0) { |
|||
return res.data.message; |
|||
} |
|||
return Promise.reject(new Error(res.data.message)); |
|||
} |
|||
@ -0,0 +1,51 @@ |
|||
import axios from '@/utils/request'; |
|||
|
|||
/** |
|||
* 查询字典列表 |
|||
* @param params 查询条件 |
|||
*/ |
|||
export async function listDictionaries(params) { |
|||
const res = await axios.get('/system/dictionary', { |
|||
params |
|||
}); |
|||
if (res.data.code === 0) { |
|||
return res.data.data; |
|||
} |
|||
return Promise.reject(new Error(res.data.message)); |
|||
} |
|||
|
|||
/** |
|||
* 添加字典 |
|||
* @param data 字典信息 |
|||
*/ |
|||
export async function addDictionary(data) { |
|||
const res = await axios.post('/system/dictionary', data); |
|||
if (res.data.code === 0) { |
|||
return res.data.message; |
|||
} |
|||
return Promise.reject(new Error(res.data.message)); |
|||
} |
|||
|
|||
/** |
|||
* 修改字典 |
|||
* @param data 字典信息 |
|||
*/ |
|||
export async function updateDictionary(data) { |
|||
const res = await axios.put('/system/dictionary', data); |
|||
if (res.data.code === 0) { |
|||
return res.data.message; |
|||
} |
|||
return Promise.reject(new Error(res.data.message)); |
|||
} |
|||
|
|||
/** |
|||
* 删除字典 |
|||
* @param id 字典id |
|||
*/ |
|||
export async function removeDictionary(id) { |
|||
const res = await axios.delete('/system/dictionary/' + id); |
|||
if (res.data.code === 0) { |
|||
return res.data.message; |
|||
} |
|||
return Promise.reject(new Error(res.data.message)); |
|||
} |
|||
@ -0,0 +1,29 @@ |
|||
import axios from '@/utils/request'; |
|||
|
|||
/** |
|||
* 上传文件 |
|||
* @param file 文件 |
|||
*/ |
|||
export async function uploadFile(file) { |
|||
const formData = new FormData(); |
|||
formData.append('file', file); |
|||
const res = await axios.post('/file/upload', formData); |
|||
if (res.data.code === 0) { |
|||
return res.data.data; |
|||
} |
|||
return Promise.reject(new Error(res.data.message)); |
|||
} |
|||
|
|||
/** |
|||
* 分页查询文件上传记录 |
|||
* @param params 查询条件 |
|||
*/ |
|||
export async function pageFiles(params) { |
|||
const res = await axios.get('/file/page', { |
|||
params |
|||
}); |
|||
if (res.data.code === 0) { |
|||
return res.data.data; |
|||
} |
|||
return Promise.reject(new Error(res.data.message)); |
|||
} |
|||
@ -0,0 +1,29 @@ |
|||
import axios from '@/utils/request'; |
|||
|
|||
/** |
|||
* 分页查询登录日志 |
|||
* @param params 查询条件 |
|||
*/ |
|||
export async function pageLoginRecords(params) { |
|||
const res = await axios.get('/system/login-record/page', { |
|||
params |
|||
}); |
|||
if (res.data.code === 0) { |
|||
return res.data.data; |
|||
} |
|||
return Promise.reject(new Error(res.data.message)); |
|||
} |
|||
|
|||
/** |
|||
* 查询登录日志列表 |
|||
* @param params 查询条件 |
|||
*/ |
|||
export async function listLoginRecords(params) { |
|||
const res = await axios.get('/system/login-record', { |
|||
params |
|||
}); |
|||
if (res.data.code === 0) { |
|||
return res.data.data; |
|||
} |
|||
return Promise.reject(new Error(res.data.message)); |
|||
} |
|||
@ -0,0 +1,51 @@ |
|||
import axios from '@/utils/request'; |
|||
|
|||
/** |
|||
* 查询菜单列表 |
|||
* @param params 查询条件 |
|||
*/ |
|||
export async function listMenus(params) { |
|||
const res = await axios.get('/system/menu', { |
|||
params |
|||
}); |
|||
if (res.data.code === 0) { |
|||
return res.data.data; |
|||
} |
|||
return Promise.reject(new Error(res.data.message)); |
|||
} |
|||
|
|||
/** |
|||
* 添加菜单 |
|||
* @param data 菜单信息 |
|||
*/ |
|||
export async function addMenu(data) { |
|||
const res = await axios.post('/system/menu', data); |
|||
if (res.data.code === 0) { |
|||
return res.data.message; |
|||
} |
|||
return Promise.reject(new Error(res.data.message)); |
|||
} |
|||
|
|||
/** |
|||
* 修改菜单 |
|||
* @param data 菜单信息 |
|||
*/ |
|||
export async function updateMenu(data) { |
|||
const res = await axios.put('/system/menu', data); |
|||
if (res.data.code === 0) { |
|||
return res.data.message; |
|||
} |
|||
return Promise.reject(new Error(res.data.message)); |
|||
} |
|||
|
|||
/** |
|||
* 删除菜单 |
|||
* @param id 菜单id |
|||
*/ |
|||
export async function removeMenu(id) { |
|||
const res = await axios.delete('/system/menu/' + id); |
|||
if (res.data.code === 0) { |
|||
return res.data.message; |
|||
} |
|||
return Promise.reject(new Error(res.data.message)); |
|||
} |
|||
@ -0,0 +1,29 @@ |
|||
import axios from '@/utils/request'; |
|||
|
|||
/** |
|||
* 分页查询操作日志 |
|||
* @param params 查询条件 |
|||
*/ |
|||
export async function pageOperationRecords(params) { |
|||
const res = await axios.get('/system/operation-record/page', { |
|||
params |
|||
}); |
|||
if (res.data.code === 0) { |
|||
return res.data.data; |
|||
} |
|||
return Promise.reject(new Error(res.data.message)); |
|||
} |
|||
|
|||
/** |
|||
* 查询操作日志列表 |
|||
* @param params 查询条件 |
|||
*/ |
|||
export async function listOperationRecords(params) { |
|||
const res = await axios.get('/system/operation-record', { |
|||
params |
|||
}); |
|||
if (res.data.code === 0) { |
|||
return res.data.data; |
|||
} |
|||
return Promise.reject(new Error(res.data.message)); |
|||
} |
|||
@ -0,0 +1,65 @@ |
|||
import axios from '@/utils/request'; |
|||
|
|||
/** |
|||
* 分页查询机构 |
|||
* @param params 查询条件 |
|||
*/ |
|||
export async function pageOrganizations(params) { |
|||
const res = await axios.get('/system/organization/page', { |
|||
params |
|||
}); |
|||
if (res.data.code === 0) { |
|||
return res.data.data; |
|||
} |
|||
return Promise.reject(new Error(res.data.message)); |
|||
} |
|||
|
|||
/** |
|||
* 查询机构列表 |
|||
* @param params 查询条件 |
|||
*/ |
|||
export async function listOrganizations(params) { |
|||
const res = await axios.get('/system/organization', { |
|||
params |
|||
}); |
|||
if (res.data.code === 0) { |
|||
return res.data.data; |
|||
} |
|||
return Promise.reject(new Error(res.data.message)); |
|||
} |
|||
|
|||
/** |
|||
* 添加机构 |
|||
* @param data 机构信息 |
|||
*/ |
|||
export async function addOrganization(data) { |
|||
const res = await axios.post('/system/organization', data); |
|||
if (res.data.code === 0) { |
|||
return res.data.message; |
|||
} |
|||
return Promise.reject(new Error(res.data.message)); |
|||
} |
|||
|
|||
/** |
|||
* 修改机构 |
|||
* @param data 机构信息 |
|||
*/ |
|||
export async function updateOrganization(data) { |
|||
const res = await axios.put('/system/organization', data); |
|||
if (res.data.code === 0) { |
|||
return res.data.message; |
|||
} |
|||
return Promise.reject(new Error(res.data.message)); |
|||
} |
|||
|
|||
/** |
|||
* 删除机构 |
|||
* @param id 机构id |
|||
*/ |
|||
export async function removeOrganization(id) { |
|||
const res = await axios.delete('/system/organization/' + id); |
|||
if (res.data.code === 0) { |
|||
return res.data.message; |
|||
} |
|||
return Promise.reject(new Error(res.data.message)); |
|||
} |
|||
@ -0,0 +1,104 @@ |
|||
import axios from '@/utils/request'; |
|||
|
|||
/** |
|||
* 分页查询角色 |
|||
* @param params 查询条件 |
|||
*/ |
|||
export async function pageRoles(params) { |
|||
const res = await axios.get('/system/role/page', { |
|||
params |
|||
}); |
|||
if (res.data.code === 0) { |
|||
return res.data.data; |
|||
} |
|||
return Promise.reject(new Error(res.data.message)); |
|||
} |
|||
|
|||
/** |
|||
* 查询角色列表 |
|||
* @param params 查询条件 |
|||
*/ |
|||
export async function listRoles(params) { |
|||
const res = await axios.get('/system/role', { |
|||
params |
|||
}); |
|||
if (res.data.code === 0) { |
|||
return res.data.data; |
|||
} |
|||
return Promise.reject(new Error(res.data.message)); |
|||
} |
|||
|
|||
/** |
|||
* 添加角色 |
|||
* @param data 角色信息 |
|||
*/ |
|||
export async function addRole(data) { |
|||
const res = await axios.post('/system/role', data); |
|||
if (res.data.code === 0) { |
|||
return res.data.message; |
|||
} |
|||
return Promise.reject(new Error(res.data.message)); |
|||
} |
|||
|
|||
/** |
|||
* 修改角色 |
|||
* @param data 角色信息 |
|||
*/ |
|||
export async function updateRole(data) { |
|||
const res = await axios.put('/system/role', data); |
|||
if (res.data.code === 0) { |
|||
return res.data.message; |
|||
} |
|||
return Promise.reject(new Error(res.data.message)); |
|||
} |
|||
|
|||
/** |
|||
* 删除角色 |
|||
* @param id 角色id |
|||
*/ |
|||
export async function removeRole(id) { |
|||
const res = await axios.delete('/system/role/' + id); |
|||
if (res.data.code === 0) { |
|||
return res.data.message; |
|||
} |
|||
return Promise.reject(new Error(res.data.message)); |
|||
} |
|||
|
|||
/** |
|||
* 批量删除角色 |
|||
* @param ids 角色id集合 |
|||
*/ |
|||
export async function removeRoles(data) { |
|||
const res = await axios.delete('/system/role/batch', { |
|||
data |
|||
}); |
|||
if (res.data.code === 0) { |
|||
return res.data.message; |
|||
} |
|||
return Promise.reject(new Error(res.data.message)); |
|||
} |
|||
|
|||
/** |
|||
* 获取角色分配的菜单 |
|||
* @param roleId 角色id |
|||
*/ |
|||
export async function listRoleMenus(roleId) { |
|||
const res = await axios.get('/system/role-menu/' + roleId); |
|||
if (res.data.code === 0) { |
|||
return res.data.data; |
|||
} |
|||
return Promise.reject(new Error(res.data.message)); |
|||
} |
|||
|
|||
/** |
|||
* 修改角色菜单 |
|||
* @param roleId 角色id |
|||
* @param data 菜单id集合 |
|||
*/ |
|||
export async function updateRoleMenus(roleId, data) { |
|||
const res = await axios.put('/system/role-menu/' + roleId, data); |
|||
if (res.data.code === 0) { |
|||
return res.data.message; |
|||
} |
|||
return Promise.reject(new Error(res.data.message)); |
|||
} |
|||
@ -0,0 +1,154 @@ |
|||
import axios from '@/utils/request'; |
|||
|
|||
/** |
|||
* 分页查询用户 |
|||
* @param params 查询条件 |
|||
*/ |
|||
export async function pageUsers(params) { |
|||
const res = await axios.get('/system/user/page', { |
|||
params |
|||
}); |
|||
if (res.data.code === 0) { |
|||
return res.data.data; |
|||
} |
|||
return Promise.reject(new Error(res.data.message)); |
|||
} |
|||
|
|||
/** |
|||
* 查询用户列表 |
|||
* @param params 查询条件 |
|||
*/ |
|||
export async function listUsers(params) { |
|||
const res = await axios.get('/system/user', { |
|||
params |
|||
}); |
|||
if (res.data.code === 0) { |
|||
return res.data.data; |
|||
} |
|||
return Promise.reject(new Error(res.data.message)); |
|||
} |
|||
|
|||
/** |
|||
* 根据id查询用户 |
|||
* @param id 用户id |
|||
*/ |
|||
export async function getUser(id) { |
|||
const res = await axios.get('/system/user/' + id); |
|||
if (res.data.code === 0) { |
|||
return res.data.data; |
|||
} |
|||
return Promise.reject(new Error(res.data.message)); |
|||
} |
|||
|
|||
/** |
|||
* 添加用户 |
|||
* @param data 用户信息 |
|||
*/ |
|||
export async function addUser(data) { |
|||
const res = await axios.post('/system/user', data); |
|||
if (res.data.code === 0) { |
|||
return res.data.message; |
|||
} |
|||
return Promise.reject(new Error(res.data.message)); |
|||
} |
|||
|
|||
/** |
|||
* 修改用户 |
|||
* @param data 用户信息 |
|||
*/ |
|||
export async function updateUser(data) { |
|||
const res = await axios.put('/system/user', data); |
|||
if (res.data.code === 0) { |
|||
return res.data.message; |
|||
} |
|||
return Promise.reject(new Error(res.data.message)); |
|||
} |
|||
|
|||
/** |
|||
* 删除用户 |
|||
* @param id 用户id |
|||
*/ |
|||
export async function removeUser(id) { |
|||
const res = await axios.delete('/system/user/' + id); |
|||
if (res.data.code === 0) { |
|||
return res.data.message; |
|||
} |
|||
return Promise.reject(new Error(res.data.message)); |
|||
} |
|||
|
|||
/** |
|||
* 批量删除用户 |
|||
* @param data 用户id集合 |
|||
*/ |
|||
export async function removeUsers(data) { |
|||
const res = await axios.delete('/system/user/batch', { |
|||
data |
|||
}); |
|||
if (res.data.code === 0) { |
|||
return res.data.message; |
|||
} |
|||
return Promise.reject(new Error(res.data.message)); |
|||
} |
|||
|
|||
/** |
|||
* 修改用户状态 |
|||
* @param userId 用户id |
|||
* @param status 状态 |
|||
*/ |
|||
export async function updateUserStatus(userId, status) { |
|||
const res = await axios.put('/system/user/status', { |
|||
userId, |
|||
status |
|||
}); |
|||
if (res.data.code === 0) { |
|||
return res.data.message; |
|||
} |
|||
return Promise.reject(new Error(res.data.message)); |
|||
} |
|||
|
|||
/** |
|||
* 重置用户密码 |
|||
* @param userId 用户id |
|||
* @param password 密码 |
|||
* @returns {Promise<string>} |
|||
*/ |
|||
export async function updateUserPassword(userId, password = '123456') { |
|||
const res = await axios.put('/system/user/password', { |
|||
userId, |
|||
password |
|||
}); |
|||
if (res.data.code === 0) { |
|||
return res.data.message; |
|||
} |
|||
return Promise.reject(new Error(res.data.message)); |
|||
} |
|||
|
|||
/** |
|||
* 导入用户 |
|||
* @param file excel文件 |
|||
*/ |
|||
export async function importUsers(file) { |
|||
const formData = new FormData(); |
|||
formData.append('file', file); |
|||
const res = await axios.post('/system/user/import', formData); |
|||
if (res.data.code === 0) { |
|||
return res.data.message; |
|||
} |
|||
return Promise.reject(new Error(res.data.message)); |
|||
} |
|||
|
|||
/** |
|||
* 检查用户是否存在 |
|||
* @param field 检查的字段 |
|||
* @param value 字段的值 |
|||
* @param id 修改时的id |
|||
*/ |
|||
export async function checkExistence(field, value, id) { |
|||
const res = await axios.get('/system/user/existence', { |
|||
params: { field, value, id } |
|||
}); |
|||
if (res.data.code === 0) { |
|||
return res.data.message; |
|||
} |
|||
return Promise.reject(new Error(res.data.message)); |
|||
} |
|||
@ -0,0 +1,223 @@ |
|||
/** |
|||
* 分页查询通知 |
|||
*/ |
|||
export async function pageNotices() { |
|||
return { |
|||
count: 10, |
|||
list: [ |
|||
{ |
|||
id: 21, |
|||
title: 'EleAdmin新版本发布,欢迎体验', |
|||
time: '2020-07-24 11:35', |
|||
status: 0 |
|||
}, |
|||
{ |
|||
id: 22, |
|||
title: 'EleAdmin新版本发布,欢迎体验', |
|||
time: '2020-07-24 11:35', |
|||
status: 0 |
|||
}, |
|||
{ |
|||
id: 23, |
|||
title: 'EleAdmin新版本发布,欢迎体验', |
|||
time: '2020-07-24 11:35', |
|||
status: 1 |
|||
}, |
|||
{ |
|||
id: 24, |
|||
title: 'EleAdmin新版本发布,欢迎体验', |
|||
time: '2020-07-24 11:35', |
|||
status: 1 |
|||
}, |
|||
{ |
|||
id: 25, |
|||
title: 'EleAdmin新版本发布,欢迎体验', |
|||
time: '2020-07-24 11:35', |
|||
status: 1 |
|||
}, |
|||
{ |
|||
id: 26, |
|||
title: 'EleAdmin新版本发布,欢迎体验', |
|||
time: '2020-07-24 11:35', |
|||
status: 1 |
|||
}, |
|||
{ |
|||
id: 27, |
|||
title: 'EleAdmin新版本发布,欢迎体验', |
|||
time: '2020-07-24 11:35', |
|||
status: 1 |
|||
}, |
|||
{ |
|||
id: 28, |
|||
title: 'EleAdmin新版本发布,欢迎体验', |
|||
time: '2020-07-24 11:35', |
|||
status: 1 |
|||
}, |
|||
{ |
|||
id: 29, |
|||
title: 'EleAdmin新版本发布,欢迎体验', |
|||
time: '2020-07-24 11:35', |
|||
status: 1 |
|||
}, |
|||
{ |
|||
id: 30, |
|||
title: 'EleAdmin新版本发布,欢迎体验', |
|||
time: '2020-07-24 11:35', |
|||
status: 1 |
|||
} |
|||
] |
|||
}; |
|||
} |
|||
|
|||
/** |
|||
* 分页查询私信 |
|||
*/ |
|||
export async function pageLetters() { |
|||
return { |
|||
count: 10, |
|||
list: [ |
|||
{ |
|||
id: 11, |
|||
title: 'Jasmine给你发来了一条私信', |
|||
time: '2020-07-24 11:35', |
|||
status: 0 |
|||
}, |
|||
{ |
|||
id: 12, |
|||
title: 'Jasmine给你发来了一条私信', |
|||
time: '2020-07-24 11:35', |
|||
status: 0 |
|||
}, |
|||
{ |
|||
id: 13, |
|||
title: 'Jasmine给你发来了一条私信', |
|||
time: '2020-07-24 11:35', |
|||
status: 0 |
|||
}, |
|||
{ |
|||
id: 14, |
|||
title: 'Jasmine给你发来了一条私信', |
|||
time: '2020-07-24 11:35', |
|||
status: 1 |
|||
}, |
|||
{ |
|||
id: 15, |
|||
title: 'Jasmine给你发来了一条私信', |
|||
time: '2020-07-24 11:35', |
|||
status: 1 |
|||
}, |
|||
{ |
|||
id: 16, |
|||
title: 'Jasmine给你发来了一条私信', |
|||
time: '2020-07-24 11:35', |
|||
status: 1 |
|||
}, |
|||
{ |
|||
id: 17, |
|||
title: 'Jasmine给你发来了一条私信', |
|||
time: '2020-07-24 11:35', |
|||
status: 1 |
|||
}, |
|||
{ |
|||
id: 18, |
|||
title: 'Jasmine给你发来了一条私信', |
|||
time: '2020-07-24 11:35', |
|||
status: 1 |
|||
}, |
|||
{ |
|||
id: 19, |
|||
title: 'Jasmine给你发来了一条私信', |
|||
time: '2020-07-24 11:35', |
|||
status: 1 |
|||
}, |
|||
{ |
|||
id: 20, |
|||
title: 'Jasmine给你发来了一条私信', |
|||
time: '2020-07-24 11:35', |
|||
status: 1 |
|||
} |
|||
] |
|||
}; |
|||
} |
|||
|
|||
/** |
|||
* 分页查询代办 |
|||
*/ |
|||
export async function pageTodos() { |
|||
return { |
|||
count: 10, |
|||
list: [ |
|||
{ |
|||
id: 1, |
|||
title: '你有两条任务待完成,不要忘了哦~', |
|||
time: '2020-07-24 11:35', |
|||
status: 0 |
|||
}, |
|||
{ |
|||
id: 2, |
|||
title: '你有两条任务待完成,不要忘了哦~', |
|||
time: '2020-07-24 11:35', |
|||
status: 0 |
|||
}, |
|||
{ |
|||
id: 3, |
|||
title: '你有两条任务待完成,不要忘了哦~', |
|||
time: '2020-07-24 11:35', |
|||
status: 0 |
|||
}, |
|||
{ |
|||
id: 4, |
|||
title: '你有两条任务待完成,不要忘了哦~', |
|||
time: '2020-07-24 11:35', |
|||
status: 0 |
|||
}, |
|||
{ |
|||
id: 5, |
|||
title: '你有两条任务待完成,不要忘了哦~', |
|||
time: '2020-07-24 11:35', |
|||
status: 1 |
|||
}, |
|||
{ |
|||
id: 6, |
|||
title: '你有两条任务待完成,不要忘了哦~', |
|||
time: '2020-07-24 11:35', |
|||
status: 1 |
|||
}, |
|||
{ |
|||
id: 7, |
|||
title: '你有两条任务待完成,不要忘了哦~', |
|||
time: '2020-07-24 11:35', |
|||
status: 1 |
|||
}, |
|||
{ |
|||
id: 8, |
|||
title: '你有两条任务待完成,不要忘了哦~', |
|||
time: '2020-07-24 11:35', |
|||
status: 1 |
|||
}, |
|||
{ |
|||
id: 9, |
|||
title: '你有两条任务待完成,不要忘了哦~', |
|||
time: '2020-07-24 11:35', |
|||
status: 1 |
|||
}, |
|||
{ |
|||
id: 10, |
|||
title: '你有两条任务待完成,不要忘了哦~', |
|||
time: '2020-07-24 11:35', |
|||
status: 1 |
|||
} |
|||
] |
|||
}; |
|||
} |
|||
|
|||
/** |
|||
* 查询未读数量 |
|||
*/ |
|||
export async function getUnReadNum() { |
|||
return { |
|||
notice: 2, |
|||
letter: 3, |
|||
todo: 4 |
|||
}; |
|||
} |
|||
@ -0,0 +1,21 @@ |
|||
/** 用于刷新的路由组件 */ |
|||
import { setRouteReload } from '@/utils/page-tab-util'; |
|||
|
|||
export default { |
|||
name: 'RedirectLayout', |
|||
created() { |
|||
const { params, query } = this.$route; |
|||
const from = Array.isArray(params.path) |
|||
? params.path.join('/') |
|||
: params.path; |
|||
const path = '/' + from; |
|||
setTimeout(() => { |
|||
setRouteReload(null).then(() => { |
|||
this.$router.replace({ path, query }); |
|||
}); |
|||
}, 100); |
|||
}, |
|||
render(h) { |
|||
return h('div'); |
|||
} |
|||
}; |
|||
@ -0,0 +1,128 @@ |
|||
<!-- 省市区选择组件 --> |
|||
<template> |
|||
<el-cascader |
|||
clearable |
|||
:value="value" |
|||
:options="regionsData" |
|||
:placeholder="placeholder" |
|||
popper-class="ele-pop-wrap-higher" |
|||
:props="props" |
|||
@input="updateValue" |
|||
/> |
|||
</template> |
|||
|
|||
<script> |
|||
import { getRegionsData } from './load-data'; |
|||
|
|||
export default { |
|||
name: 'RegionsSelect', |
|||
props: { |
|||
value: Array, |
|||
placeholder: String, |
|||
options: Array, |
|||
valueField: { |
|||
type: String, |
|||
validator: (val) => { |
|||
return !val || val === 'label'; |
|||
} |
|||
}, |
|||
type: { |
|||
type: String, |
|||
validator: (type) => { |
|||
return !type || ['provinceCity', 'province'].includes(type); |
|||
} |
|||
}, |
|||
props: Object |
|||
}, |
|||
data() { |
|||
return { |
|||
// 级联选择器数据 |
|||
regionsData: [] |
|||
}; |
|||
}, |
|||
methods: { |
|||
// 更新value |
|||
updateValue(value) { |
|||
this.$emit('input', value); |
|||
}, |
|||
// 级联选择器数据value处理 |
|||
formatData(data) { |
|||
if (this.valueField === 'label') { |
|||
return data.map((d) => { |
|||
const item = { |
|||
label: d.label, |
|||
value: d.label |
|||
}; |
|||
if (d.children) { |
|||
item.children = d.children.map((c) => { |
|||
const cItem = { |
|||
label: c.label, |
|||
value: c.label |
|||
}; |
|||
if (c.children) { |
|||
cItem.children = c.children.map((cc) => { |
|||
return { |
|||
label: cc.label, |
|||
value: cc.label |
|||
}; |
|||
}); |
|||
} |
|||
return cItem; |
|||
}); |
|||
} |
|||
return item; |
|||
}); |
|||
} else { |
|||
return data; |
|||
} |
|||
}, |
|||
// 省市区数据筛选 |
|||
filterData(data) { |
|||
if (this.type === 'provinceCity') { |
|||
return this.formatData( |
|||
data.map((d) => { |
|||
const item = { |
|||
label: d.label, |
|||
value: d.value |
|||
}; |
|||
if (d.children) { |
|||
item.children = d.children.map((c) => { |
|||
return { |
|||
label: c.label, |
|||
value: c.value |
|||
}; |
|||
}); |
|||
} |
|||
return item; |
|||
}) |
|||
); |
|||
} else if (this.type === 'province') { |
|||
return this.formatData( |
|||
data.map((d) => { |
|||
return { |
|||
label: d.label, |
|||
value: d.value |
|||
}; |
|||
}) |
|||
); |
|||
} else { |
|||
return this.formatData(data); |
|||
} |
|||
} |
|||
}, |
|||
watch: { |
|||
options: { |
|||
handler(options) { |
|||
this.regionsData = this.filterData(options ?? []); |
|||
if (!options) { |
|||
getRegionsData().then((data) => { |
|||
this.regionsData = this.filterData(data ?? []); |
|||
this.$emit('load-data-done', data); |
|||
}); |
|||
} |
|||
}, |
|||
immediate: true |
|||
} |
|||
} |
|||
}; |
|||
</script> |
|||
@ -0,0 +1,24 @@ |
|||
import request from '@/utils/request'; |
|||
const BASE_URL = process.env.BASE_URL; |
|||
let reqPromise; |
|||
|
|||
/** |
|||
* 获取省市区数据 |
|||
*/ |
|||
export function getRegionsData() { |
|||
if (!reqPromise) { |
|||
reqPromise = new Promise((resolve, reject) => { |
|||
request |
|||
.get(BASE_URL + 'json/regions-data.json', { |
|||
baseURL: '' |
|||
}) |
|||
.then((res) => { |
|||
resolve(res.data ?? []); |
|||
}) |
|||
.catch((e) => { |
|||
reject(e); |
|||
}); |
|||
}); |
|||
} |
|||
return reqPromise; |
|||
} |
|||
@ -0,0 +1,17 @@ |
|||
<!-- router-view 结合 keep-alive 组件 --> |
|||
<template> |
|||
<keep-alive :include="include"> |
|||
<router-view /> |
|||
</keep-alive> |
|||
</template> |
|||
|
|||
<script> |
|||
export default { |
|||
name: 'RouterLayout', |
|||
computed: { |
|||
include() { |
|||
return this.$store.getters['theme/keepAliveInclude'] ?? []; |
|||
} |
|||
} |
|||
}; |
|||
</script> |
|||
@ -0,0 +1,98 @@ |
|||
<!-- 二维码组件 --> |
|||
<template> |
|||
<div ref="root"></div> |
|||
</template> |
|||
|
|||
<script> |
|||
import QRCode from 'qrcodejs2'; |
|||
|
|||
export default { |
|||
name: 'VueQrCode', |
|||
props: { |
|||
text: String, |
|||
width: { |
|||
type: Number, |
|||
default: 256 |
|||
}, |
|||
height: { |
|||
type: Number, |
|||
default: 256 |
|||
}, |
|||
colorDark: { |
|||
type: String, |
|||
default: '#000000' |
|||
}, |
|||
colorLight: { |
|||
type: String, |
|||
default: '#ffffff' |
|||
}, |
|||
correctLevel: { |
|||
type: Number, |
|||
default: QRCode.CorrectLevel.H |
|||
} |
|||
}, |
|||
data() { |
|||
return { |
|||
instance: undefined |
|||
}; |
|||
}, |
|||
mounted() { |
|||
if (this.text) { |
|||
this.render(); |
|||
} |
|||
}, |
|||
methods: { |
|||
render() { |
|||
this.clear(); |
|||
this.instance = new QRCode(this.getEl(), { |
|||
text: this.text, |
|||
width: this.width, |
|||
height: this.height, |
|||
colorDark: this.colorDark, |
|||
colorLight: this.colorLight, |
|||
correctLevel: this.correctLevel |
|||
}); |
|||
}, |
|||
makeCode(value) { |
|||
if (this.instance) { |
|||
this.instance.makeCode(value); |
|||
} else { |
|||
this.render(); |
|||
} |
|||
}, |
|||
clear() { |
|||
this.instance?.clear(); |
|||
this.instance = undefined; |
|||
this.getEl().innerHTML = ''; |
|||
this.getEl().title = ''; |
|||
}, |
|||
getEl() { |
|||
return this.$refs.root; |
|||
} |
|||
}, |
|||
watch: { |
|||
text(text) { |
|||
if (text) { |
|||
this.makeCode(text); |
|||
} else { |
|||
this.clear(); |
|||
} |
|||
}, |
|||
width() { |
|||
this.render(); |
|||
}, |
|||
height() { |
|||
this.render(); |
|||
}, |
|||
colorDark() { |
|||
this.render(); |
|||
}, |
|||
colorLight() { |
|||
this.render(); |
|||
}, |
|||
correctLevel() { |
|||
this.render(); |
|||
} |
|||
} |
|||
}; |
|||
</script> |
|||
@ -1,79 +0,0 @@ |
|||
/** |
|||
* axios配置 |
|||
*/ |
|||
import Vue from 'vue'; |
|||
import VueAxios from 'vue-axios'; |
|||
import axios from 'axios'; |
|||
import store from '../store'; |
|||
import router from '../router'; |
|||
import setting from './setting'; |
|||
import {MessageBox} from 'element-ui'; |
|||
|
|||
Vue.use(VueAxios, axios); |
|||
|
|||
// 设置统一的url
|
|||
axios.defaults.baseURL = process.env.VUE_APP_API_BASE_URL; |
|||
|
|||
/* 请求拦截器 */ |
|||
axios.interceptors.request.use((config) => { |
|||
// 添加token到header
|
|||
let token = setting.takeToken(); |
|||
if (token) { |
|||
config.headers[setting.tokenHeaderName] = token; |
|||
} |
|||
return config; |
|||
}, function (error) { |
|||
return Promise.reject(error); |
|||
}); |
|||
|
|||
/* 响应拦截器 */ |
|||
axios.interceptors.response.use((res) => { |
|||
// 登录过期处理
|
|||
if (res.data.code === 40512) { |
|||
if (res.config.url === setting.menuUrl) { |
|||
goLogin(); |
|||
} else { |
|||
MessageBox.alert('登录状态已过期, 请退出重新登录!', '系统提示', { |
|||
confirmButtonText: '重新登录', |
|||
callback: (action) => { |
|||
if (action === 'confirm') { |
|||
goLogin(); |
|||
} |
|||
}, |
|||
beforeClose: () => { |
|||
MessageBox.close(); |
|||
} |
|||
}); |
|||
} |
|||
return Promise.reject(new Error(res.data.msg)); |
|||
} |
|||
// token自动续期
|
|||
let access_token = res.headers[setting.tokenHeaderName]; |
|||
if (access_token) { |
|||
setting.cacheToken(access_token); |
|||
} |
|||
return res; |
|||
}, (error) => { |
|||
return Promise.reject(error); |
|||
}); |
|||
|
|||
/** |
|||
* 跳转到登录页面 |
|||
*/ |
|||
function goLogin() { |
|||
store.dispatch('user/removeToken').then(() => { |
|||
const current = router.currentRoute; |
|||
if (current && current.path && current.path !== '/') { |
|||
router.push({ |
|||
path: '/login', |
|||
query: { |
|||
form: current.path |
|||
} |
|||
}).then(() => { |
|||
}); |
|||
} else { |
|||
router.push('/login').then(() => { |
|||
}); |
|||
} |
|||
}); |
|||
} |
|||
@ -1,134 +1,57 @@ |
|||
/** |
|||
* 项目统一配置 |
|||
*/ |
|||
export default { |
|||
// 路由白名单(不需要登录的)
|
|||
whiteList: ['/login', '/forget'], |
|||
// 不显示全局页脚的路由地址
|
|||
hideFooters: ['/system/dictionary', '/system/organization'], |
|||
// 需要缓存的组件名称
|
|||
keepAliveList: [], |
|||
// 菜单数据接口
|
|||
menuUrl: '/manager/permissMenu', |
|||
// 自定义解析接口菜单数据
|
|||
parseMenu: null, |
|||
// 自定义解析接口菜单每一个数据格式
|
|||
parseMenuItem: (item) => { |
|||
if (!item) { |
|||
return; |
|||
} |
|||
item.menuId = item.id; |
|||
item.title = item.name; |
|||
item.parentId = item.parent_id; |
|||
item.menuType = item.menu_type; |
|||
return item; |
|||
}, |
|||
// 接口地址
|
|||
export const API_BASE_URL = process.env.VUE_APP_API_BASE_URL; |
|||
|
|||
// 项目名称
|
|||
export const PROJECT_NAME = process.env.VUE_APP_NAME; |
|||
|
|||
// 不显示侧栏的路由
|
|||
export const HIDE_SIDEBARS = []; |
|||
|
|||
// 不显示页脚的路由
|
|||
export const HIDE_FOOTERS = [ |
|||
'/system/dictionary', |
|||
'/system/organization', |
|||
'/form/advanced', |
|||
'/example/choose' |
|||
]; |
|||
|
|||
// 页签同路由不同参数可重复打开的路由
|
|||
export const REPEATABLE_TABS = ['/system/user-info']; |
|||
|
|||
// 不需要登录的路由
|
|||
export const WHITE_LIST = ['/login', '/forget']; |
|||
|
|||
// 直接指定菜单数据
|
|||
menus: null, |
|||
// 用户信息接口
|
|||
userUrl: '/manager/readPersional', |
|||
uploadImageUrl:'http://api.static.ahbmz.com/api/upload', |
|||
// 自定义解析接口用户信息
|
|||
parseUser(res) { |
|||
// 这里code和msg字段如果不一样可在这里修改
|
|||
let result = {code: res.code, msg: res.msg}; |
|||
if (res.data) { |
|||
// 这里只需要姓名和头像两个字段,如需缓存其它字段可在这里添加
|
|||
result.data = { |
|||
nickname: res.data.truename, |
|||
avatar: res.data.avatar |
|||
}; |
|||
// 下面是获取角色和权限列表,需要string数组类型
|
|||
if (res.data.roles) { |
|||
result.data.roles = res.data.roles.map(d => d.role_code); |
|||
} |
|||
if (res.data.authorities) { |
|||
result.data.authorities = res.data.authorities.map(d => d.authority); |
|||
} |
|||
} |
|||
return result; |
|||
}, |
|||
export const USER_MENUS = null; |
|||
|
|||
// 首页名称, 为空则取第一个菜单的名称
|
|||
export const HOME_TITLE = null; |
|||
|
|||
// 首页路径, 为空则取第一个菜单的地址
|
|||
export const HOME_PATH = null; |
|||
|
|||
// 开启多页签是否缓存组件
|
|||
//export const TAB_KEEP_ALIVE = process.env.NODE_ENV !== 'development';
|
|||
export const TAB_KEEP_ALIVE = true; |
|||
|
|||
// token传递的header名称
|
|||
tokenHeaderName: 'Token', |
|||
export const TOKEN_HEADER_NAME = 'Authorization'; |
|||
|
|||
// token存储的名称
|
|||
tokenStoreName: 'access_token', |
|||
// 获取缓存的token
|
|||
takeToken() { |
|||
let token = localStorage.getItem(this.tokenStoreName); |
|||
if (!token) { |
|||
token = sessionStorage.getItem(this.tokenStoreName); |
|||
} |
|||
return token; |
|||
}, |
|||
// 缓存token
|
|||
cacheToken(token, remember) { |
|||
localStorage.removeItem(this.tokenStoreName); |
|||
sessionStorage.removeItem(this.tokenStoreName); |
|||
if (token) { |
|||
if (remember) { |
|||
localStorage.setItem(this.tokenStoreName, token); |
|||
} else { |
|||
sessionStorage.setItem(this.tokenStoreName, token); |
|||
} |
|||
} |
|||
}, |
|||
// 用户信息存储的名称
|
|||
userStoreName: 'user', |
|||
// 获取缓存的用户信息
|
|||
takeUser() { |
|||
try { |
|||
return JSON.parse(localStorage.getItem(this.userStoreName)) || {}; |
|||
} catch (e) { |
|||
console.error(e); |
|||
} |
|||
return {}; |
|||
}, |
|||
// 缓存用户信息
|
|||
cacheUser(user) { |
|||
if (user) { |
|||
localStorage.setItem(this.userStoreName, JSON.stringify(user)); |
|||
} else { |
|||
localStorage.removeItem(this.userStoreName); |
|||
} |
|||
}, |
|||
export const TOKEN_STORE_NAME = 'access_token'; |
|||
|
|||
// 主题配置存储的名称
|
|||
themeStoreName: 'theme', |
|||
// 首页tab显示标题, null会根据菜单自动获取
|
|||
homeTitle: '主页', |
|||
// 首页路径, null会自动获取
|
|||
homePath: null, |
|||
// 顶栏是否显示主题设置按钮
|
|||
showSetting: true, |
|||
// 侧边栏风格: 0亮色, 1暗色
|
|||
sideStyle: 0, |
|||
// 顶栏风格: 0亮色, 1暗色, 2主色
|
|||
headStyle: 2, |
|||
// 标签页风格: 0默认, 1圆点, 2卡片
|
|||
tabStyle: 0, |
|||
// 布局风格: 0默认, 1顶部菜单风格, 2混合菜单风格
|
|||
layoutStyle: 0, |
|||
// 是否固定侧栏
|
|||
fixedSidebar: true, |
|||
// 是否固定顶栏
|
|||
fixedHeader: false, |
|||
// 是否固定主体
|
|||
fixedBody: true, |
|||
// logo是否自适应宽度
|
|||
logoAutoSize: true, |
|||
// 内容区域宽度是否铺满
|
|||
bodyFull: true, |
|||
// 是否开启多标签
|
|||
showTabs: true, |
|||
// 侧栏是否多彩图标
|
|||
colorfulIcon: true, |
|||
// 侧边栏是否只保持一个子菜单展开
|
|||
sideUniqueOpen: true, |
|||
// 是否开启页脚
|
|||
showFooter: true, |
|||
// 是否是色弱模式
|
|||
weakMode: false, |
|||
// 是否是暗黑模式
|
|||
darkMode: false, |
|||
// 默认主题色
|
|||
color: null |
|||
} |
|||
export const THEME_STORE_NAME = 'theme'; |
|||
|
|||
// i18n缓存的名称
|
|||
export const I18N_CACHE_NAME = 'i18n-lang'; |
|||
|
|||
// 刷新路由的路由地址
|
|||
export const REDIRECT_PATH = '/redirect'; |
|||
|
|||
// 高德地图key
|
|||
export const MAP_KEY = '006d995d433058322319fa797f2876f5'; |
|||
|
|||
// EleAdmin授权码
|
|||
export const LICENSE_CODE = |
|||
'dk9mcwJyetRWQlxWRiojIqJWdzJCLi4Wam2q5iojI0NWZRqL5Tip5JGr5Aqo5Re656mp5sWY5QmZ6Jyp5t9GZiwiI4+Y5tVGZiojIulWYp1GZhVGbl5ybpJCLi02bj5ibtFGRtEjI6ICZ2JCLiw2cnVkViojIu9WazJXZQfiAjL44SM0NW=='; |
|||
|
|||
@ -0,0 +1,29 @@ |
|||
/** |
|||
* 国际化配置 |
|||
*/ |
|||
import Vue from 'vue'; |
|||
import VueI18n from 'vue-i18n'; |
|||
import eleZhCNLocale from 'ele-admin/es/lang/zh-CN'; |
|||
import eleZhTWLocale from 'ele-admin/es/lang/zh-TW'; |
|||
import eleEnLocale from 'ele-admin/es/lang/en'; |
|||
import zhCNLocale from './lang/zh_CN'; |
|||
import zhTWLocale from './lang/zh_TW'; |
|||
import enLocale from './lang/en'; |
|||
import { I18N_CACHE_NAME } from '@/config/setting'; |
|||
|
|||
Vue.use(VueI18n); |
|||
|
|||
const messages = { |
|||
zh_CN: { ...eleZhCNLocale, ...zhCNLocale }, |
|||
zh_TW: { ...eleZhTWLocale, ...zhTWLocale }, |
|||
en: { ...eleEnLocale, ...enLocale } |
|||
}; |
|||
|
|||
const i18n = new VueI18n({ |
|||
messages: messages, |
|||
silentTranslationWarn: true, |
|||
// 默认语言
|
|||
locale: localStorage.getItem(I18N_CACHE_NAME) || 'zh_CN' |
|||
}); |
|||
|
|||
export default i18n; |
|||
@ -0,0 +1,186 @@ |
|||
/** |
|||
* 英语 |
|||
*/ |
|||
export default { |
|||
// 菜单路由
|
|||
route: { |
|||
dashboard: { |
|||
_name: 'Dashboard', |
|||
workplace: { _name: 'Workplace' }, |
|||
analysis: { _name: 'Analysis' }, |
|||
monitor: { _name: 'Monitor' } |
|||
}, |
|||
system: { |
|||
_name: 'System', |
|||
user: { |
|||
_name: 'User' |
|||
}, |
|||
role: { _name: 'Role' }, |
|||
menu: { _name: 'Menu' }, |
|||
dictionary: { _name: 'Dictionary' }, |
|||
organization: { _name: 'Organization' }, |
|||
loginRecord: { _name: 'LoginRecord' }, |
|||
operationRecord: { _name: 'OperationRecord' }, |
|||
userInfo: { _name: '' } |
|||
}, |
|||
form: { |
|||
_name: 'Form', |
|||
basic: { _name: 'Basic Form' }, |
|||
advanced: { _name: 'Advanced Form' }, |
|||
step: { _name: 'Step Form' } |
|||
}, |
|||
list: { |
|||
_name: 'List', |
|||
basic: { _name: 'Basic List' }, |
|||
advanced: { _name: 'Advanced List' }, |
|||
card: { |
|||
_name: 'Card List', |
|||
project: { _name: 'Project' }, |
|||
application: { _name: 'Application' }, |
|||
article: { _name: 'Article' } |
|||
} |
|||
}, |
|||
result: { |
|||
_name: 'Result', |
|||
success: { _name: 'Success' }, |
|||
fail: { _name: 'Fail' } |
|||
}, |
|||
exception: { |
|||
_name: 'Exception', |
|||
403: { _name: '403' }, |
|||
404: { _name: '404' }, |
|||
500: { _name: '500' } |
|||
}, |
|||
user: { |
|||
_name: 'User', |
|||
profile: { _name: 'Profile' }, |
|||
message: { _name: 'Message' } |
|||
}, |
|||
extension: { |
|||
_name: 'Extension', |
|||
icon: { _name: 'Icon' }, |
|||
file: { _name: 'File' }, |
|||
printer: { _name: 'Printer' }, |
|||
excel: { _name: 'Excel' }, |
|||
dragsort: { _name: 'DragSort' }, |
|||
message: { _name: 'Message' }, |
|||
map: { _name: 'Map' }, |
|||
player: { _name: 'Player' }, |
|||
editor: { _name: 'Editor' }, |
|||
tag: { _name: 'Tags' }, |
|||
colorPicker: { _name: 'ColorPicker' }, |
|||
regions: { _name: 'CitySelect' }, |
|||
countUp: { _name: 'CountUp' }, |
|||
empty: { _name: 'Empty' }, |
|||
steps: { _name: 'Steps' }, |
|||
menu: { _name: 'Menu' }, |
|||
treeSelect: { _name: 'TreeSelect' }, |
|||
tableSelect: { _name: 'TableSelect' }, |
|||
qrCode: { _name: 'QRCode' }, |
|||
dialog: { _name: 'DragDialog' } |
|||
}, |
|||
example: { |
|||
_name: 'Example', |
|||
table: { _name: 'ProTable' }, |
|||
menuBadge: { _name: 'MenuBadge' }, |
|||
document: { _name: 'Document' }, |
|||
choose: { _name: 'Choose' }, |
|||
eleadmin: { _name: 'IFrame' } |
|||
}, |
|||
'https://eleadminCom/goods/8': { _name: 'Authorization' } |
|||
}, |
|||
// 主框架
|
|||
layout: { |
|||
home: 'Home', |
|||
header: { |
|||
profile: 'Profile', |
|||
password: 'Password', |
|||
logout: 'SignOut' |
|||
}, |
|||
footer: { |
|||
website: 'Website', |
|||
document: 'Document', |
|||
authorization: 'Authorization', |
|||
copyright: 'Copyright © 2022 Wuhan EClouds Technology Co., Ltd' |
|||
}, |
|||
logout: { |
|||
title: 'Confirm', |
|||
message: 'Are you sure you want to log out?' |
|||
}, |
|||
setting: { |
|||
title: 'Theme Setting', |
|||
sideStyles: { |
|||
dark: 'Dark Sidebar', |
|||
light: 'Light Sidebar' |
|||
}, |
|||
headStyles: { |
|||
light: 'Light Header', |
|||
dark: 'Dark Header', |
|||
primary: 'Primary Header' |
|||
}, |
|||
layoutStyles: { |
|||
side: 'Side Menu Layout', |
|||
top: 'Top Menu Layout', |
|||
mix: 'Mix Menu Layout' |
|||
}, |
|||
colors: { |
|||
default: 'Daybreak Blue', |
|||
dust: 'Dust Blue', |
|||
sunset: 'Sunset Orange', |
|||
volcano: 'Volcano', |
|||
purple: 'Golden Purple', |
|||
cyan: 'Cyan', |
|||
green: 'Polar Green', |
|||
geekblue: 'Geek Blue' |
|||
}, |
|||
darkMode: 'Dark Mode', |
|||
layoutStyle: 'Navigation Mode', |
|||
sideMenuStyle: 'Sidebar Double Menu', |
|||
bodyFull: 'Body Fullscreen', |
|||
other: 'Other Setting', |
|||
fixedHeader: 'Fixed Header', |
|||
fixedSidebar: 'Fixed Sidebar', |
|||
fixedBody: 'Fixed Body', |
|||
logoAutoSize: 'Logo Adaptation', |
|||
colorfulIcon: 'Colorful Icon', |
|||
sideUniqueOpen: 'Menu Unique Open', |
|||
weakMode: 'Weak Mode', |
|||
showFooter: 'Show Footer', |
|||
showTabs: 'Show Tabs', |
|||
tabStyle: 'Tab Style', |
|||
tabStyles: { |
|||
default: 'Default', |
|||
dot: 'Dot', |
|||
card: 'Card' |
|||
}, |
|||
reset: 'Reset', |
|||
tips: 'It will remember your configuration the next time you open it.' |
|||
} |
|||
}, |
|||
// 登录界面
|
|||
login: { |
|||
title: 'User Login', |
|||
username: 'please input username', |
|||
password: 'please input password', |
|||
code: 'please input code', |
|||
remember: 'remember', |
|||
forget: 'forget', |
|||
login: 'login', |
|||
loading: 'loading' |
|||
}, |
|||
// 基础列表
|
|||
list: { |
|||
basic: { |
|||
table: { |
|||
username: 'Username', |
|||
nickname: 'Nickname', |
|||
organizationName: 'OrganizationName', |
|||
phone: 'Phone', |
|||
sexName: 'SexName', |
|||
createTime: 'CreateTime', |
|||
status: 'Status', |
|||
action: 'Action' |
|||
} |
|||
} |
|||
} |
|||
}; |
|||
@ -0,0 +1,187 @@ |
|||
/** |
|||
* 简体中文 |
|||
*/ |
|||
export default { |
|||
// 菜单路由
|
|||
route: { |
|||
dashboard: { |
|||
_name: 'Dashboard', |
|||
workplace: { _name: '工作台' }, |
|||
analysis: { _name: '分析页' }, |
|||
monitor: { _name: '监控页' } |
|||
}, |
|||
system: { |
|||
_name: '系统管理', |
|||
user: { |
|||
_name: '用户管理' |
|||
}, |
|||
role: { _name: '角色管理' }, |
|||
menu: { _name: '菜单管理' }, |
|||
dictionary: { _name: '字典管理' }, |
|||
organization: { _name: '机构管理' }, |
|||
loginRecord: { _name: '登录日志' }, |
|||
operationRecord: { _name: '操作日志' }, |
|||
userInfo: { _name: '' } |
|||
}, |
|||
form: { |
|||
_name: '表单页面', |
|||
basic: { _name: '基础表单' }, |
|||
advanced: { _name: '复杂表单' }, |
|||
step: { _name: '分步表单' } |
|||
}, |
|||
list: { |
|||
_name: '列表页面', |
|||
basic: { _name: '基础列表' }, |
|||
advanced: { _name: '复杂列表' }, |
|||
card: { |
|||
_name: '卡片列表', |
|||
project: { _name: '项目列表' }, |
|||
application: { _name: '应用列表' }, |
|||
article: { _name: '文章列表' } |
|||
} |
|||
}, |
|||
result: { |
|||
_name: '结果页面', |
|||
success: { _name: '成功页' }, |
|||
fail: { _name: '失败页' } |
|||
}, |
|||
exception: { |
|||
_name: '异常页面', |
|||
403: { _name: '403' }, |
|||
404: { _name: '404' }, |
|||
500: { _name: '500' } |
|||
}, |
|||
user: { |
|||
_name: '个人中心', |
|||
profile: { _name: '个人资料' }, |
|||
message: { _name: '我的消息' } |
|||
}, |
|||
extension: { |
|||
_name: '扩展组件', |
|||
icon: { _name: '图标扩展' }, |
|||
file: { _name: '文件列表' }, |
|||
printer: { _name: '打印插件' }, |
|||
excel: { _name: 'excel插件' }, |
|||
dragsort: { _name: '拖拽排序' }, |
|||
message: { _name: '消息提示' }, |
|||
map: { _name: '地图组件' }, |
|||
player: { _name: '视频播放' }, |
|||
editor: { _name: '富文本框' }, |
|||
tag: { _name: '标签组件' }, |
|||
colorPicker: { _name: '颜色选择' }, |
|||
regions: { _name: '城市选择' }, |
|||
countUp: { _name: '滚动数字' }, |
|||
empty: { _name: '空状态' }, |
|||
steps: { _name: '步骤条' }, |
|||
menu: { _name: '菜单导航' }, |
|||
treeSelect: { _name: '树形下拉' }, |
|||
tableSelect: { _name: '表格下拉' }, |
|||
qrCode: { _name: '二维码' }, |
|||
dialog: { _name: '拖拽弹窗' } |
|||
}, |
|||
example: { |
|||
_name: '常用实例', |
|||
table: { _name: '表格实例' }, |
|||
menuBadge: { _name: '菜单徽章' }, |
|||
document: { _name: '案卷调整' }, |
|||
choose: { _name: '批量选择' }, |
|||
eleadmin: { _name: '内嵌页面' } |
|||
}, |
|||
'https://eleadminCom/goods/8': { _name: '获取授权' } |
|||
}, |
|||
// 外层布局
|
|||
layout: { |
|||
home: '主页', |
|||
header: { |
|||
profile: '个人中心', |
|||
password: '修改密码', |
|||
logout: '退出登录' |
|||
}, |
|||
footer: { |
|||
website: '官网', |
|||
document: '文档', |
|||
authorization: '授权', |
|||
copyright: 'Copyright © 2022 武汉易云智科技有限公司' |
|||
}, |
|||
logout: { |
|||
title: '提示', |
|||
message: '确定要退出登录吗?' |
|||
}, |
|||
// 设置抽屉
|
|||
setting: { |
|||
title: '整体风格设置', |
|||
sideStyles: { |
|||
dark: '暗色侧边栏', |
|||
light: '亮色侧边栏' |
|||
}, |
|||
headStyles: { |
|||
light: '亮色顶栏', |
|||
dark: '暗色顶栏', |
|||
primary: '主色顶栏' |
|||
}, |
|||
layoutStyles: { |
|||
side: '左侧菜单布局', |
|||
top: '顶部菜单布局', |
|||
mix: '混合菜单布局' |
|||
}, |
|||
colors: { |
|||
default: '拂晓蓝', |
|||
dust: '薄暮', |
|||
sunset: '日暮', |
|||
volcano: '火山', |
|||
purple: '酱紫', |
|||
cyan: '明青', |
|||
green: '极光绿', |
|||
geekblue: '极客蓝' |
|||
}, |
|||
darkMode: '开启暗黑模式', |
|||
layoutStyle: '导航模式', |
|||
sideMenuStyle: '侧栏双排菜单', |
|||
bodyFull: '内容区域铺满', |
|||
other: '其它配置', |
|||
fixedHeader: '固定顶栏区域', |
|||
fixedSidebar: '固定侧栏区域', |
|||
fixedBody: '固定主体区域', |
|||
logoAutoSize: 'Logo宽度自动', |
|||
colorfulIcon: '侧栏彩色图标', |
|||
sideUniqueOpen: '侧栏排他展开', |
|||
weakMode: '开启色弱模式', |
|||
showFooter: '开启全局页脚', |
|||
showTabs: '开启多页签栏', |
|||
tabStyle: '页签显示风格', |
|||
tabStyles: { |
|||
default: '默认', |
|||
dot: '圆点', |
|||
card: '卡片' |
|||
}, |
|||
reset: '重置', |
|||
tips: '该功能可实时预览各种布局效果, 修改后会缓存在本地, 下次打开会记忆主题配置.' |
|||
} |
|||
}, |
|||
// 登录界面
|
|||
login: { |
|||
title: '用户登录', |
|||
username: '请输入登录账号', |
|||
password: '请输入登录密码', |
|||
code: '请输入验证码', |
|||
remember: '记住密码', |
|||
forget: '忘记密码', |
|||
login: '登录', |
|||
loading: '登录中' |
|||
}, |
|||
// 基础列表
|
|||
list: { |
|||
basic: { |
|||
table: { |
|||
username: '用户账号', |
|||
nickname: '用户名', |
|||
organizationName: '组织机构', |
|||
phone: '手机号', |
|||
sexName: '性别', |
|||
createTime: '创建时间', |
|||
status: '状态', |
|||
action: '操作' |
|||
} |
|||
} |
|||
} |
|||
}; |
|||
@ -0,0 +1,186 @@ |
|||
/** |
|||
* 繁体中文 |
|||
*/ |
|||
export default { |
|||
// 菜单路由
|
|||
route: { |
|||
dashboard: { |
|||
_name: 'Dashboard', |
|||
workplace: { _name: '工作臺' }, |
|||
analysis: { _name: '分析頁' }, |
|||
monitor: { _name: '監控頁' } |
|||
}, |
|||
system: { |
|||
_name: '系統管理', |
|||
user: { |
|||
_name: '用戶管理' |
|||
}, |
|||
role: { _name: '角色管理' }, |
|||
menu: { _name: '選單管理' }, |
|||
dictionary: { _name: '字典管理' }, |
|||
organization: { _name: '機构管理' }, |
|||
loginRecord: { _name: '登入日誌' }, |
|||
operationRecord: { _name: '操作日誌' }, |
|||
userInfo: { _name: '' } |
|||
}, |
|||
form: { |
|||
_name: '表單頁面', |
|||
basic: { _name: '基礎表單' }, |
|||
advanced: { _name: '複雜表單' }, |
|||
step: { _name: '分步表單' } |
|||
}, |
|||
list: { |
|||
_name: '清單頁面', |
|||
basic: { _name: '基礎清單' }, |
|||
advanced: { _name: '複雜清單' }, |
|||
card: { |
|||
_name: '卡片清單', |
|||
project: { _name: '項目清單' }, |
|||
application: { _name: '應用清單' }, |
|||
article: { _name: '文章清單' } |
|||
} |
|||
}, |
|||
result: { |
|||
_name: '結果頁面', |
|||
success: { _name: '成功頁' }, |
|||
fail: { _name: '失敗頁' } |
|||
}, |
|||
exception: { |
|||
_name: '异常頁面', |
|||
403: { _name: '403' }, |
|||
404: { _name: '404' }, |
|||
500: { _name: '500' } |
|||
}, |
|||
user: { |
|||
_name: '個人中心', |
|||
profile: { _name: '個人資料' }, |
|||
message: { _name: '我的消息' } |
|||
}, |
|||
extension: { |
|||
_name: '擴展組件', |
|||
icon: { _name: '圖標擴展' }, |
|||
file: { _name: '檔案清單' }, |
|||
printer: { _name: '列印挿件' }, |
|||
excel: { _name: 'excel挿件' }, |
|||
dragsort: { _name: '拖拽排序' }, |
|||
message: { _name: '消息提示' }, |
|||
map: { _name: '地圖組件' }, |
|||
player: { _name: '視頻播放' }, |
|||
editor: { _name: '富文本框' }, |
|||
tag: { _name: '標籤組件' }, |
|||
colorPicker: { _name: '顏色選擇' }, |
|||
regions: { _name: '城市選擇' }, |
|||
countUp: { _name: '滾動數字' }, |
|||
empty: { _name: '空狀態' }, |
|||
steps: { _name: '步驟條' }, |
|||
menu: { _name: '菜單導航' }, |
|||
treeSelect: { _name: '樹形下拉' }, |
|||
tableSelect: { _name: '表格下拉' }, |
|||
qrCode: { _name: '二維碼' }, |
|||
dialog: { _name: '拖拽彈窗' } |
|||
}, |
|||
example: { |
|||
_name: '常用實例', |
|||
table: { _name: '表格實例' }, |
|||
menuBadge: { _name: '菜單徽章' }, |
|||
document: { _name: '案卷調整' }, |
|||
choose: { _name: '批量選擇' }, |
|||
eleadmin: { _name: '內嵌頁面' } |
|||
}, |
|||
'https://eleadminCom/goods/8': { _name: '獲取授權' } |
|||
}, |
|||
// 主框架
|
|||
layout: { |
|||
home: '主頁', |
|||
header: { |
|||
profile: '個人中心', |
|||
password: '修改密碼', |
|||
logout: '安全登出' |
|||
}, |
|||
footer: { |
|||
website: '官網', |
|||
document: '檔案', |
|||
authorization: '授權', |
|||
copyright: 'Copyright © 2022 武漢易雲智科技有限公司' |
|||
}, |
|||
logout: { |
|||
title: '詢問', |
|||
message: '確定要登出嗎?' |
|||
}, |
|||
setting: { |
|||
title: '整體風格設定', |
|||
sideStyles: { |
|||
dark: '暗色側邊欄', |
|||
light: '亮色側邊欄' |
|||
}, |
|||
headStyles: { |
|||
light: '亮色頂欄', |
|||
dark: '暗色頂欄', |
|||
primary: '主色頂欄' |
|||
}, |
|||
layoutStyles: { |
|||
side: '左側選單佈局', |
|||
top: '頂部選單佈局', |
|||
mix: '混合選單佈局' |
|||
}, |
|||
colors: { |
|||
default: '拂曉藍', |
|||
dust: '薄暮', |
|||
sunset: '日暮', |
|||
volcano: '火山', |
|||
purple: '醬紫', |
|||
cyan: '明青', |
|||
green: '極光綠', |
|||
geekblue: '極客藍' |
|||
}, |
|||
darkMode: '開啟暗黑模式', |
|||
layoutStyle: '導航模式', |
|||
sideMenuStyle: '側欄雙排選單', |
|||
bodyFull: '內容區域鋪滿', |
|||
other: '其它配寘', |
|||
fixedHeader: '固定頂欄區域', |
|||
fixedSidebar: '固定側欄區域', |
|||
fixedBody: '固定主體區域', |
|||
logoAutoSize: 'Logo寬度自動', |
|||
colorfulIcon: '側欄彩色圖標', |
|||
sideUniqueOpen: '側欄排他展開', |
|||
weakMode: '開啟色弱模式', |
|||
showFooter: '開啟全域頁腳', |
|||
showTabs: '開啟多頁簽欄', |
|||
tabStyle: '頁簽顯示風格', |
|||
tabStyles: { |
|||
default: '默認', |
|||
dot: '圓點', |
|||
card: '卡片' |
|||
}, |
|||
reset: '重置', |
|||
tips: '該功能可實时預覽各種佈局效果,修改後會緩存在本地,下次打開會記憶主題配寘.' |
|||
} |
|||
}, |
|||
// 登录界面
|
|||
login: { |
|||
title: '用戶登錄', |
|||
username: '請輸入登入帳號', |
|||
password: '請輸入登入密碼', |
|||
code: '請輸入驗證碼', |
|||
remember: '記住密碼', |
|||
forget: '忘記密碼', |
|||
login: '登入', |
|||
loading: '登入中' |
|||
}, |
|||
// 基础列表
|
|||
list: { |
|||
basic: { |
|||
table: { |
|||
username: '用戶賬號', |
|||
nickname: '用戶名', |
|||
organizationName: '組織機構', |
|||
phone: '手機號', |
|||
sexName: '性別', |
|||
createTime: '創建時間', |
|||
status: '狀態', |
|||
action: '操作' |
|||
} |
|||
} |
|||
} |
|||
}; |
|||
@ -0,0 +1,278 @@ |
|||
<!-- 顶栏消息通知 --> |
|||
<template> |
|||
<el-popover |
|||
:width="330" |
|||
trigger="click" |
|||
v-model="visible" |
|||
class="ele-notice-group" |
|||
transition="el-zoom-in-top" |
|||
popper-class="ele-notice-pop" |
|||
> |
|||
<div slot="reference" class="ele-notice-group"> |
|||
<el-badge :value="unreadNum" :hidden="!unreadNum"> |
|||
<i class="el-icon-bell"></i> |
|||
</el-badge> |
|||
</div> |
|||
<el-tabs v-model="active"> |
|||
<el-tab-pane name="notice" :label="noticeTitle"> |
|||
<div class="ele-notice-list ele-scrollbar-mini"> |
|||
<div |
|||
v-for="(item, index) in notice" |
|||
:key="index" |
|||
class="ele-notice-item" |
|||
> |
|||
<div class="ele-cell ele-notice-item-wrapper"> |
|||
<i :class="[item.icon, 'ele-notice-item-icon']"></i> |
|||
<div class="ele-cell-content"> |
|||
<div class="ele-elip">{{ item.title }}</div> |
|||
<div class="ele-text-secondary ele-elip">{{ item.time }}</div> |
|||
</div> |
|||
</div> |
|||
<el-divider /> |
|||
</div> |
|||
</div> |
|||
<div v-if="notice.length" class="ele-cell ele-notice-actions"> |
|||
<div class="ele-cell-content" @click="clearNotice">清空通知</div> |
|||
<el-divider direction="vertical" class="line-color-light" /> |
|||
<router-link to="/user/message?type=notice" class="ele-cell-content"> |
|||
查看更多 |
|||
</router-link> |
|||
</div> |
|||
<ele-empty v-if="!notice.length" text="已查看所有通知" /> |
|||
</el-tab-pane> |
|||
<el-tab-pane name="letter" :label="letterTitle"> |
|||
<div class="ele-notice-list ele-scrollbar-mini"> |
|||
<div |
|||
v-for="(item, index) in letter" |
|||
:key="index" |
|||
class="ele-notice-item" |
|||
> |
|||
<div class="ele-cell ele-notice-item-wrapper ele-cell-align-top"> |
|||
<el-avatar :src="item.avatar" size="medium" /> |
|||
<div class="ele-cell-content"> |
|||
<div class="ele-elip">{{ item.title }}</div> |
|||
<div class="ele-text-secondary ele-elip"> |
|||
{{ item.content }} |
|||
</div> |
|||
<div class="ele-cell-desc ele-elip">{{ item.time }}</div> |
|||
</div> |
|||
</div> |
|||
<el-divider /> |
|||
</div> |
|||
</div> |
|||
<div v-if="letter.length" class="ele-cell ele-notice-actions"> |
|||
<div class="ele-cell-content" @click="clearLetter">清空私信</div> |
|||
<el-divider direction="vertical" class="line-color-light" /> |
|||
<router-link to="/user/message?type=letter" class="ele-cell-content"> |
|||
查看更多 |
|||
</router-link> |
|||
</div> |
|||
<ele-empty v-if="!letter.length" text="已读完所有私信" /> |
|||
</el-tab-pane> |
|||
<el-tab-pane :label="todoTitle" name="todo"> |
|||
<div class="ele-notice-list ele-scrollbar-mini"> |
|||
<div |
|||
v-for="(item, index) in todo" |
|||
:key="index" |
|||
class="ele-notice-item" |
|||
> |
|||
<div class="ele-notice-item-wrapper"> |
|||
<div class="ele-cell ele-cell-align-top"> |
|||
<div class="ele-cell-content ele-elip">{{ item.title }}</div> |
|||
<el-tag size="mini" :type="['info', 'danger', ''][item.status]"> |
|||
{{ ['未开始', '即将到期', '进行中'][item.status] }} |
|||
</el-tag> |
|||
</div> |
|||
<div class="ele-text-secondary ele-elip"> |
|||
{{ item.description }} |
|||
</div> |
|||
</div> |
|||
<el-divider /> |
|||
</div> |
|||
</div> |
|||
<div v-if="todo.length" class="ele-cell ele-notice-actions"> |
|||
<div class="ele-cell-content" @click="clearTodo">清空待办</div> |
|||
<el-divider direction="vertical" class="line-color-light" /> |
|||
<router-link to="/user/message?type=todo" class="ele-cell-content"> |
|||
查看更多 |
|||
</router-link> |
|||
</div> |
|||
<ele-empty v-if="!todo.length" text="已完成所有任务" /> |
|||
</el-tab-pane> |
|||
</el-tabs> |
|||
</el-popover> |
|||
</template> |
|||
|
|||
<script> |
|||
import { getUnreadNotice } from '@/api/layout'; |
|||
|
|||
export default { |
|||
name: 'HeaderNotice', |
|||
data() { |
|||
return { |
|||
// 是否显示 |
|||
visible: false, |
|||
// 选项卡选中 |
|||
active: 'notice', |
|||
// 通知数据 |
|||
notice: [], |
|||
// 私信数据 |
|||
letter: [], |
|||
// 待办数据 |
|||
todo: [] |
|||
}; |
|||
}, |
|||
computed: { |
|||
// 通知标题 |
|||
noticeTitle() { |
|||
return '通知' + (this.notice.length ? `(${this.notice.length})` : ''); |
|||
}, |
|||
// 私信标题 |
|||
letterTitle() { |
|||
return '私信' + (this.letter.length ? `(${this.letter.length})` : ''); |
|||
}, |
|||
// 待办标题 |
|||
todoTitle() { |
|||
return '待办' + (this.todo.length ? `(${this.todo.length})` : ''); |
|||
}, |
|||
// 未读数量 |
|||
unreadNum() { |
|||
return this.notice.length + this.letter.length + this.todo.length; |
|||
} |
|||
}, |
|||
created() { |
|||
this.query(); |
|||
}, |
|||
methods: { |
|||
/* 查询数据 */ |
|||
query() { |
|||
getUnreadNotice() |
|||
.then((result) => { |
|||
this.notice = result.notice; |
|||
this.letter = result.letter; |
|||
this.todo = result.todo; |
|||
}) |
|||
.catch((e) => { |
|||
this.$message.error(e.message); |
|||
}); |
|||
}, |
|||
/* 清空通知 */ |
|||
clearNotice() { |
|||
this.notice = []; |
|||
}, |
|||
/* 清空通知 */ |
|||
clearLetter() { |
|||
this.letter = []; |
|||
}, |
|||
/* 清空通知 */ |
|||
clearTodo() { |
|||
this.todo = []; |
|||
} |
|||
} |
|||
}; |
|||
</script> |
|||
|
|||
<style lang="scss"> |
|||
.ele-notice-group { |
|||
display: block; |
|||
|
|||
.el-badge { |
|||
line-height: 1; |
|||
display: block; |
|||
} |
|||
} |
|||
|
|||
/* 消息通知pop */ |
|||
.ele-notice-pop { |
|||
padding: 0 !important; |
|||
|
|||
/* tab */ |
|||
.el-tabs__nav-scroll { |
|||
text-align: center; |
|||
} |
|||
|
|||
.el-tabs__nav { |
|||
float: none; |
|||
display: inline-block; |
|||
} |
|||
|
|||
.el-tabs__item { |
|||
height: 44px; |
|||
line-height: 44px; |
|||
padding: 0 20px !important; |
|||
} |
|||
|
|||
/* 空视图 */ |
|||
.ele-empty { |
|||
padding: 100px 0; |
|||
} |
|||
} |
|||
|
|||
/* 列表 */ |
|||
.ele-notice-list { |
|||
padding-top: 8px; |
|||
max-height: 360px; |
|||
overflow: auto; |
|||
} |
|||
|
|||
.ele-notice-item { |
|||
.ele-notice-item-wrapper { |
|||
padding: 12px 15px; |
|||
transition: background-color 0.2s; |
|||
cursor: pointer; |
|||
|
|||
&:hover { |
|||
background-color: hsla(0, 0%, 60%, 0.05); |
|||
} |
|||
} |
|||
|
|||
.ele-text-secondary { |
|||
margin-top: 5px; |
|||
font-size: 13px; |
|||
} |
|||
|
|||
.ele-cell-desc { |
|||
margin-top: 3px !important; |
|||
font-size: 12px !important; |
|||
} |
|||
} |
|||
|
|||
.ele-notice-item-icon { |
|||
width: 32px; |
|||
height: 32px; |
|||
line-height: 32px !important; |
|||
color: #fff; |
|||
font-size: 16px; |
|||
background-color: #60b2fc; |
|||
border-radius: 50%; |
|||
text-align: center; |
|||
|
|||
&.el-icon-s-check { |
|||
background-color: #f5686f; |
|||
} |
|||
|
|||
&.el-icon-video-camera { |
|||
background-color: #7cd734; |
|||
} |
|||
|
|||
&.el-icon-s-claim { |
|||
background-color: #faad14; |
|||
} |
|||
|
|||
&.el-icon-message-solid { |
|||
background-color: #2bcacd; |
|||
} |
|||
} |
|||
|
|||
/* 操作按钮 */ |
|||
.ele-notice-actions > .ele-cell-content { |
|||
line-height: 42px; |
|||
text-align: center; |
|||
cursor: pointer; |
|||
color: inherit; |
|||
|
|||
&:hover { |
|||
background-color: hsla(0, 0%, 60%, 0.05); |
|||
} |
|||
} |
|||
</style> |
|||
@ -0,0 +1,144 @@ |
|||
<!-- 顶栏右侧区域 --> |
|||
<template> |
|||
<div class="ele-admin-header-tool"> |
|||
<!-- 全屏切换 --> |
|||
<div |
|||
class="ele-admin-header-tool-item hidden-xs-only" |
|||
@click="toggleFullscreen" |
|||
> |
|||
<i v-if="fullscreen" class="el-icon-_screen-restore"></i> |
|||
<i v-else class="el-icon-_screen-full"></i> |
|||
</div> |
|||
<!-- 语言切换 --> |
|||
<div class="ele-admin-header-tool-item"> |
|||
<el-dropdown placement="bottom" @command="changeLanguage"> |
|||
<i class="el-icon-_language"></i> |
|||
<el-dropdown-menu slot="dropdown"> |
|||
<el-dropdown-item command="en"> |
|||
<span :class="{ 'ele-text-primary': language === 'en' }"> |
|||
English |
|||
</span> |
|||
</el-dropdown-item> |
|||
<el-dropdown-item command="zh_CN"> |
|||
<span :class="{ 'ele-text-primary': language === 'zh_CN' }"> |
|||
简体中文 |
|||
</span> |
|||
</el-dropdown-item> |
|||
<el-dropdown-item command="zh_TW"> |
|||
<span :class="{ 'ele-text-primary': language === 'zh_TW' }"> |
|||
繁體中文 |
|||
</span> |
|||
</el-dropdown-item> |
|||
</el-dropdown-menu> |
|||
</el-dropdown> |
|||
</div> |
|||
<!-- 消息通知 --> |
|||
<div class="ele-admin-header-tool-item"> |
|||
<header-notice /> |
|||
</div> |
|||
<!-- 用户信息 --> |
|||
<div class="ele-admin-header-tool-item"> |
|||
<el-dropdown @command="onUserDropClick"> |
|||
<div class="ele-admin-header-avatar"> |
|||
<el-avatar :src="loginUser.avatar" /> |
|||
<span class="hidden-xs-only">{{ loginUser.nickname }}</span> |
|||
<i class="el-icon-arrow-down"></i> |
|||
</div> |
|||
<el-dropdown-menu slot="dropdown"> |
|||
<el-dropdown-item command="profile" icon="el-icon-user"> |
|||
{{ $t('layout.header.profile') }} |
|||
</el-dropdown-item> |
|||
<el-dropdown-item command="password" icon="el-icon-key"> |
|||
{{ $t('layout.header.password') }} |
|||
</el-dropdown-item> |
|||
<el-dropdown-item |
|||
command="logout" |
|||
icon="el-icon-switch-button" |
|||
divided |
|||
> |
|||
{{ $t('layout.header.logout') }} |
|||
</el-dropdown-item> |
|||
</el-dropdown-menu> |
|||
</el-dropdown> |
|||
</div> |
|||
<!-- 主题设置 --> |
|||
<div class="ele-admin-header-tool-item" @click="openSetting"> |
|||
<i class="el-icon-_more"></i> |
|||
</div> |
|||
<!-- 修改密码弹窗 --> |
|||
<password-modal :visible.sync="passwordVisible" /> |
|||
<!-- 主题设置抽屉 --> |
|||
<setting-drawer :visible.sync="settingVisible" /> |
|||
</div> |
|||
</template> |
|||
|
|||
<script> |
|||
import HeaderNotice from './header-notice.vue'; |
|||
import PasswordModal from './password-modal.vue'; |
|||
import SettingDrawer from './setting-drawer.vue'; |
|||
import { logout } from '@/utils/page-tab-util'; |
|||
import { I18N_CACHE_NAME } from '@/config/setting'; |
|||
|
|||
export default { |
|||
name: 'HeaderTools', |
|||
components: { HeaderNotice, PasswordModal, SettingDrawer }, |
|||
props: { |
|||
// 是否是全屏 |
|||
fullscreen: Boolean |
|||
}, |
|||
data() { |
|||
return { |
|||
// 是否显示修改密码弹窗 |
|||
passwordVisible: false, |
|||
// 是否显示主题设置抽屉 |
|||
settingVisible: false |
|||
}; |
|||
}, |
|||
computed: { |
|||
// 当前用户信息 |
|||
loginUser() { |
|||
return this.$store.state.user.info; |
|||
}, |
|||
// 当前显示语言 |
|||
language() { |
|||
return this.$i18n.locale; |
|||
} |
|||
}, |
|||
methods: { |
|||
/* 用户信息下拉点击事件 */ |
|||
onUserDropClick(command) { |
|||
if (command === 'password') { |
|||
this.passwordVisible = true; |
|||
} else if (command === 'profile') { |
|||
if (this.$route.fullPath !== '/user/profile') { |
|||
this.$router.push('/user/profile'); |
|||
} |
|||
} else if (command === 'logout') { |
|||
// 退出登录 |
|||
this.$confirm( |
|||
this.$t('layout.logout.message'), |
|||
this.$t('layout.logout.title'), |
|||
{ type: 'warning' } |
|||
) |
|||
.then(() => { |
|||
logout(); |
|||
}) |
|||
.catch(() => {}); |
|||
} |
|||
}, |
|||
/* 全屏切换 */ |
|||
toggleFullscreen() { |
|||
this.$emit('fullscreen'); |
|||
}, |
|||
/* 打开设置抽屉 */ |
|||
openSetting() { |
|||
this.settingVisible = true; |
|||
}, |
|||
/* 切换语言 */ |
|||
changeLanguage(key) { |
|||
this.$i18n.locale = key; |
|||
localStorage.setItem(I18N_CACHE_NAME, key); |
|||
} |
|||
} |
|||
}; |
|||
</script> |
|||
@ -0,0 +1,35 @@ |
|||
<!-- 全局页脚 --> |
|||
<template> |
|||
<div class="ele-text-center" style="padding: 16px 0"> |
|||
<div> |
|||
<a target="_blank" class="ele-text-secondary" href="https://eleadmin.com"> |
|||
{{ $t('layout.footer.website') }} |
|||
</a> |
|||
<em></em> |
|||
<a |
|||
target="_blank" |
|||
class="ele-text-secondary" |
|||
href="https://eleadmin.com/doc/eleadmin/" |
|||
> |
|||
{{ $t('layout.footer.document') }} |
|||
</a> |
|||
<em></em> |
|||
<a |
|||
target="_blank" |
|||
class="ele-text-secondary" |
|||
href="https://eleadmin.com/goods/8" |
|||
> |
|||
{{ $t('layout.footer.authorization') }} |
|||
</a> |
|||
</div> |
|||
<div class="ele-text-secondary" style="margin-top: 8px"> |
|||
{{ $t('layout.footer.copyright') }} |
|||
</div> |
|||
</div> |
|||
</template> |
|||
|
|||
<script> |
|||
export default { |
|||
name: 'PageFooter' |
|||
}; |
|||
</script> |
|||
@ -0,0 +1,137 @@ |
|||
<!-- 修改密码弹窗 --> |
|||
<template> |
|||
<ele-modal |
|||
width="420px" |
|||
title="修改密码" |
|||
:visible="visible" |
|||
:append-to-body="true" |
|||
:close-on-click-modal="true" |
|||
@update:visible="updateVisible" |
|||
@closed="onClose" |
|||
> |
|||
<el-form |
|||
ref="form" |
|||
:model="form" |
|||
:rules="rules" |
|||
label-width="82px" |
|||
@keyup.enter.native="save" |
|||
> |
|||
<el-form-item label="旧密码:" prop="oldPassword"> |
|||
<el-input |
|||
show-password |
|||
v-model="form.oldPassword" |
|||
placeholder="请输入旧密码" |
|||
/> |
|||
</el-form-item> |
|||
<el-form-item label="新密码:" prop="password"> |
|||
<el-input |
|||
show-password |
|||
v-model="form.password" |
|||
placeholder="请输入新密码" |
|||
/> |
|||
</el-form-item> |
|||
<el-form-item label="确认密码:" prop="password2"> |
|||
<el-input |
|||
show-password |
|||
v-model="form.password2" |
|||
placeholder="请再次输入新密码" |
|||
/> |
|||
</el-form-item> |
|||
</el-form> |
|||
<div slot="footer"> |
|||
<el-button @click="updateVisible(false)">取消</el-button> |
|||
<el-button type="primary" @click="save">确定</el-button> |
|||
</div> |
|||
</ele-modal> |
|||
</template> |
|||
|
|||
<script> |
|||
import { updatePassword } from '@/api/layout'; |
|||
|
|||
export default { |
|||
name: 'PasswordModal', |
|||
props: { |
|||
visible: Boolean |
|||
}, |
|||
data() { |
|||
return { |
|||
// 按钮loading |
|||
loading: false, |
|||
// 表单数据 |
|||
form: { |
|||
oldPassword: '', |
|||
password: '', |
|||
password2: '' |
|||
}, |
|||
// 表单验证 |
|||
rules: { |
|||
oldPassword: [ |
|||
{ |
|||
required: true, |
|||
message: '请输入旧密码', |
|||
trigger: 'blur' |
|||
} |
|||
], |
|||
password: [ |
|||
{ |
|||
required: true, |
|||
message: '请输入新密码', |
|||
trigger: 'blur' |
|||
} |
|||
], |
|||
password2: [ |
|||
{ |
|||
required: true, |
|||
trigger: 'blur', |
|||
validator: (_rule, value, callback) => { |
|||
if (!value) { |
|||
return callback(new Error('请再次输入新密码')); |
|||
} |
|||
if (value !== this.form.password) { |
|||
return callback(new Error('两次输入密码不一致')); |
|||
} |
|||
callback(); |
|||
} |
|||
} |
|||
] |
|||
} |
|||
}; |
|||
}, |
|||
methods: { |
|||
/* 修改visible */ |
|||
updateVisible(value) { |
|||
this.$emit('update:visible', value); |
|||
}, |
|||
/* 保存修改 */ |
|||
save() { |
|||
this.$refs['form'].validate((valid) => { |
|||
if (valid) { |
|||
this.loading = true; |
|||
updatePassword(this.form) |
|||
.then((msg) => { |
|||
this.loading = false; |
|||
this.$message.success(msg); |
|||
this.updateVisible(false); |
|||
}) |
|||
.catch((e) => { |
|||
this.loading = false; |
|||
this.$message.error(e.message); |
|||
}); |
|||
} else { |
|||
return false; |
|||
} |
|||
}); |
|||
}, |
|||
/* 关闭回调 */ |
|||
onClose() { |
|||
this.form = { |
|||
oldPassword: '', |
|||
password: '', |
|||
password2: '' |
|||
}; |
|||
this.$refs['form'].resetFields(); |
|||
this.loading = false; |
|||
} |
|||
} |
|||
}; |
|||
</script> |
|||
@ -0,0 +1,627 @@ |
|||
<!-- 主题设置抽屉 --> |
|||
<template> |
|||
<el-drawer |
|||
size="300px" |
|||
:visible="visible" |
|||
:append-to-body="true" |
|||
:title="$t('layout.setting.title')" |
|||
@update:visible="updateVisible" |
|||
> |
|||
<div |
|||
:class="['ele-setting-wrapper', { 'ele-setting-dark': theme.darkMode }]" |
|||
> |
|||
<!-- 侧栏风格 --> |
|||
<div class="ele-setting-theme ele-text-primary"> |
|||
<el-tooltip |
|||
:content="$t('layout.setting.sideStyles.dark')" |
|||
placement="top" |
|||
> |
|||
<div |
|||
class="ele-bg-base ele-side-dark" |
|||
@click="updateSideStyle('dark')" |
|||
> |
|||
<i class="el-icon-check" v-if="theme.sideStyle === 'dark'"></i> |
|||
</div> |
|||
</el-tooltip> |
|||
<el-tooltip |
|||
:content="$t('layout.setting.sideStyles.light')" |
|||
placement="top" |
|||
> |
|||
<div class="ele-bg-base" @click="updateSideStyle('light')"> |
|||
<i class="el-icon-check" v-if="theme.sideStyle === 'light'"></i> |
|||
</div> |
|||
</el-tooltip> |
|||
</div> |
|||
<!-- 顶栏风格 --> |
|||
<div class="ele-setting-theme ele-text-primary"> |
|||
<el-tooltip |
|||
:content="$t('layout.setting.headStyles.light')" |
|||
placement="top" |
|||
> |
|||
<div |
|||
class="ele-bg-base ele-head-light" |
|||
@click="updateHeadStyle('light')" |
|||
> |
|||
<i class="el-icon-check" v-if="theme.headStyle === 'light'"></i> |
|||
</div> |
|||
</el-tooltip> |
|||
<el-tooltip |
|||
:content="$t('layout.setting.headStyles.dark')" |
|||
placement="top" |
|||
> |
|||
<div |
|||
class="ele-bg-base ele-head-dark" |
|||
@click="updateHeadStyle('dark')" |
|||
> |
|||
<i class="el-icon-check" v-if="theme.headStyle === 'dark'"></i> |
|||
</div> |
|||
</el-tooltip> |
|||
<el-tooltip |
|||
:content="$t('layout.setting.headStyles.primary')" |
|||
placement="top" |
|||
> |
|||
<div |
|||
class="ele-bg-base ele-head-primary" |
|||
@click="updateHeadStyle('primary')" |
|||
> |
|||
<div class="ele-bg-primary"></div> |
|||
<i class="el-icon-check" v-if="theme.headStyle === 'primary'"></i> |
|||
</div> |
|||
</el-tooltip> |
|||
</div> |
|||
<!-- 主题色 --> |
|||
<div class="ele-setting-colors"> |
|||
<el-tooltip |
|||
v-for="item in themes" |
|||
:key="item.name" |
|||
:content="$t('layout.setting.colors.' + item.name)" |
|||
placement="top" |
|||
> |
|||
<div |
|||
class="ele-setting-color-item" |
|||
:style="{ 'background-color': item.color || item.value }" |
|||
@click="updateColor(item.value)" |
|||
> |
|||
<i |
|||
class="el-icon-check" |
|||
v-if="item.value ? item.value === theme.color : !theme.color" |
|||
> |
|||
</i> |
|||
</div> |
|||
</el-tooltip> |
|||
<!-- 颜色选择器 --> |
|||
<el-color-picker |
|||
v-model="colorValue" |
|||
:predefine="predefineColors" |
|||
class="ele-setting-color-picker" |
|||
@change="updateColor" |
|||
/> |
|||
</div> |
|||
<!-- 暗黑模式 --> |
|||
<div class="ele-setting-item"> |
|||
<div class="setting-item-title"> |
|||
{{ $t('layout.setting.darkMode') }} |
|||
</div> |
|||
<div class="setting-item-control"> |
|||
<el-switch :value="theme.darkMode" @change="updateDarkMode" /> |
|||
</div> |
|||
</div> |
|||
<el-divider /> |
|||
<!-- 导航布局 --> |
|||
<div class="ele-setting-title ele-text-secondary"> |
|||
{{ $t('layout.setting.layoutStyle') }} |
|||
</div> |
|||
<div class="ele-setting-theme ele-text-primary"> |
|||
<el-tooltip |
|||
:content="$t('layout.setting.layoutStyles.side')" |
|||
placement="top" |
|||
> |
|||
<div |
|||
class="ele-bg-base ele-side-dark" |
|||
@click="updateLayoutStyle('side')" |
|||
> |
|||
<i class="el-icon-check" v-if="theme.layoutStyle === 'side'"></i> |
|||
</div> |
|||
</el-tooltip> |
|||
<el-tooltip |
|||
:content="$t('layout.setting.layoutStyles.top')" |
|||
placement="top" |
|||
> |
|||
<div |
|||
class="ele-bg-base ele-head-dark" |
|||
@click="updateLayoutStyle('top')" |
|||
> |
|||
<i class="el-icon-check" v-if="theme.layoutStyle === 'top'"></i> |
|||
</div> |
|||
</el-tooltip> |
|||
<el-tooltip |
|||
:content="$t('layout.setting.layoutStyles.mix')" |
|||
placement="top" |
|||
> |
|||
<div |
|||
class="ele-bg-base ele-layout-mix" |
|||
@click="updateLayoutStyle('mix')" |
|||
> |
|||
<i class="el-icon-check" v-if="theme.layoutStyle === 'mix'"></i> |
|||
</div> |
|||
</el-tooltip> |
|||
</div> |
|||
<!-- 侧栏菜单布局 --> |
|||
<div class="ele-setting-item"> |
|||
<div class="setting-item-title"> |
|||
{{ $t('layout.setting.sideMenuStyle') }} |
|||
</div> |
|||
<div class="setting-item-control"> |
|||
<el-switch |
|||
:value="theme.sideMenuStyle === 'mix'" |
|||
@change="updateSideMenuStyle" |
|||
/> |
|||
</div> |
|||
</div> |
|||
<!-- 内容区域铺满 --> |
|||
<div class="ele-setting-item"> |
|||
<div class="setting-item-title"> |
|||
{{ $t('layout.setting.bodyFull') }} |
|||
</div> |
|||
<div class="setting-item-control"> |
|||
<el-switch :value="theme.bodyFull" @change="updateBodyFull" /> |
|||
</div> |
|||
</div> |
|||
<el-divider /> |
|||
<div class="ele-setting-title ele-text-secondary"> |
|||
{{ $t('layout.setting.other') }} |
|||
</div> |
|||
<!-- 固定顶栏 --> |
|||
<div class="ele-setting-item"> |
|||
<div class="setting-item-title"> |
|||
{{ $t('layout.setting.fixedHeader') }} |
|||
</div> |
|||
<div class="setting-item-control"> |
|||
<el-switch :value="theme.fixedHeader" @change="updateFixedHeader" /> |
|||
</div> |
|||
</div> |
|||
<!-- 固定侧栏 --> |
|||
<div class="ele-setting-item"> |
|||
<div class="setting-item-title"> |
|||
{{ $t('layout.setting.fixedSidebar') }} |
|||
</div> |
|||
<div class="setting-item-control"> |
|||
<el-switch :value="theme.fixedSidebar" @change="updateFixedSidebar" /> |
|||
</div> |
|||
</div> |
|||
<!-- 固定主体 --> |
|||
<div class="ele-setting-item"> |
|||
<div class="setting-item-title"> |
|||
{{ $t('layout.setting.fixedBody') }} |
|||
</div> |
|||
<div class="setting-item-control"> |
|||
<el-switch :value="theme.fixedBody" @change="updateFixedBody" /> |
|||
</div> |
|||
</div> |
|||
<!-- LOGO自适应宽度 --> |
|||
<div class="ele-setting-item"> |
|||
<div class="setting-item-title"> |
|||
{{ $t('layout.setting.logoAutoSize') }} |
|||
</div> |
|||
<div class="setting-item-control"> |
|||
<el-switch :value="theme.logoAutoSize" @change="updateLogoAutoSize" /> |
|||
</div> |
|||
</div> |
|||
<!-- 侧栏彩色图标 --> |
|||
<div class="ele-setting-item"> |
|||
<div class="setting-item-title"> |
|||
{{ $t('layout.setting.colorfulIcon') }} |
|||
</div> |
|||
<div class="setting-item-control"> |
|||
<el-switch :value="theme.colorfulIcon" @change="updateColorfulIcon" /> |
|||
</div> |
|||
</div> |
|||
<!-- 侧栏排他展开 --> |
|||
<div class="ele-setting-item"> |
|||
<div class="setting-item-title"> |
|||
{{ $t('layout.setting.sideUniqueOpen') }} |
|||
</div> |
|||
<div class="setting-item-control"> |
|||
<el-switch |
|||
:value="theme.sideUniqueOpen" |
|||
@change="updateSideUniqueOpen" |
|||
/> |
|||
</div> |
|||
</div> |
|||
<!-- 全局页脚 --> |
|||
<div class="ele-setting-item"> |
|||
<div class="setting-item-title"> |
|||
{{ $t('layout.setting.showFooter') }} |
|||
</div> |
|||
<div class="setting-item-control"> |
|||
<el-switch :value="theme.showFooter" @change="updateShowFooter" /> |
|||
</div> |
|||
</div> |
|||
<!-- 色弱模式 --> |
|||
<div class="ele-setting-item"> |
|||
<div class="setting-item-title"> |
|||
{{ $t('layout.setting.weakMode') }} |
|||
</div> |
|||
<div class="setting-item-control"> |
|||
<el-switch :value="theme.weakMode" @change="updateWeakMode" /> |
|||
</div> |
|||
</div> |
|||
<!-- 页签 --> |
|||
<div class="ele-setting-item"> |
|||
<div class="setting-item-title"> |
|||
{{ $t('layout.setting.showTabs') }} |
|||
</div> |
|||
<div class="setting-item-control"> |
|||
<el-switch :value="theme.showTabs" @change="updateShowTabs" /> |
|||
</div> |
|||
</div> |
|||
<!-- 页签风格 --> |
|||
<div class="ele-setting-item"> |
|||
<div class="setting-item-title"> |
|||
{{ $t('layout.setting.tabStyle') }} |
|||
</div> |
|||
<div class="setting-item-control"> |
|||
<el-select |
|||
size="mini" |
|||
:value="theme.tabStyle" |
|||
@change="updateTabStyle" |
|||
> |
|||
<el-option |
|||
:label="$t('layout.setting.tabStyles.default')" |
|||
value="default" |
|||
/> |
|||
<el-option |
|||
:label="$t('layout.setting.tabStyles.dot')" |
|||
value="dot" |
|||
/> |
|||
<el-option |
|||
:label="$t('layout.setting.tabStyles.card')" |
|||
value="card" |
|||
/> |
|||
</el-select> |
|||
</div> |
|||
</div> |
|||
<el-divider /> |
|||
<!-- 提示 --> |
|||
<el-alert |
|||
type="warning" |
|||
:closable="false" |
|||
class="ele-alert-border" |
|||
:title="$t('layout.setting.tips')" |
|||
/> |
|||
<!-- 重置 --> |
|||
<div class="ele-setting-button-group"> |
|||
<el-button |
|||
size="small" |
|||
class="ele-fluid" |
|||
icon="el-icon-refresh-left" |
|||
@click="resetSetting" |
|||
> |
|||
{{ $t('layout.setting.reset') }} |
|||
</el-button> |
|||
</div> |
|||
</div> |
|||
</el-drawer> |
|||
</template> |
|||
|
|||
<script> |
|||
import { mapGetters } from 'vuex'; |
|||
import { messageLoading } from 'ele-admin'; |
|||
// 主题列表 |
|||
const themes = [ |
|||
{ |
|||
name: 'default', |
|||
color: '#1890ff' |
|||
}, |
|||
{ |
|||
name: 'dust', |
|||
value: '#5f80c7' |
|||
}, |
|||
{ |
|||
name: 'sunset', |
|||
value: '#faad14' |
|||
}, |
|||
{ |
|||
name: 'volcano', |
|||
value: '#f5686f' |
|||
}, |
|||
{ |
|||
name: 'purple', |
|||
value: '#9266f9' |
|||
}, |
|||
{ |
|||
name: 'green', |
|||
value: '#33cc99' |
|||
}, |
|||
{ |
|||
name: 'geekblue', |
|||
value: '#32a2d4' |
|||
} |
|||
]; |
|||
// 颜色选择器预设颜色 |
|||
const predefineColors = [ |
|||
'#f5222d', |
|||
'#fa541c', |
|||
'#fa8c16', |
|||
'#faad14', |
|||
'#a0d911', |
|||
'#52c41a', |
|||
'#13c2c2', |
|||
'#2f54eb', |
|||
'#722ed1', |
|||
'#eb2f96' |
|||
]; |
|||
|
|||
export default { |
|||
name: 'SettingDrawer', |
|||
props: { |
|||
// 是否显示, 支持.sync修饰 |
|||
visible: Boolean |
|||
}, |
|||
data() { |
|||
const color = this.$store.state.theme.color; |
|||
// 颜色选择器选中颜色 |
|||
const colorValue = |
|||
color && !themes.some((t) => t.value === color) ? color : undefined; |
|||
return { |
|||
themes, |
|||
predefineColors, |
|||
colorValue |
|||
}; |
|||
}, |
|||
computed: { |
|||
...mapGetters(['theme']) |
|||
}, |
|||
methods: { |
|||
updateVisible(value) { |
|||
this.$emit('update:visible', value); |
|||
}, |
|||
updateShowTabs(value) { |
|||
this.$store.dispatch('theme/setShowTabs', value); |
|||
}, |
|||
updateShowFooter(value) { |
|||
this.$store.dispatch('theme/setShowFooter', value); |
|||
}, |
|||
updateHeadStyle(value) { |
|||
this.$store.dispatch('theme/setHeadStyle', value); |
|||
}, |
|||
updateSideStyle(value) { |
|||
this.$store.dispatch('theme/setSideStyle', value); |
|||
}, |
|||
updateLayoutStyle(value) { |
|||
this.$store.dispatch('theme/setLayoutStyle', value); |
|||
}, |
|||
updateSideMenuStyle(value) { |
|||
this.$store.dispatch( |
|||
'theme/setSideMenuStyle', |
|||
value ? 'mix' : 'default' |
|||
); |
|||
}, |
|||
updateTabStyle(value) { |
|||
this.$store.dispatch('theme/setTabStyle', value); |
|||
}, |
|||
updateFixedHeader(value) { |
|||
this.$store.dispatch('theme/setFixedHeader', value); |
|||
}, |
|||
updateFixedSidebar(value) { |
|||
this.$store.dispatch('theme/setFixedSidebar', value); |
|||
}, |
|||
updateFixedBody(value) { |
|||
this.$store.dispatch('theme/setFixedBody', value); |
|||
}, |
|||
updateBodyFull(value) { |
|||
this.$store.dispatch('theme/setBodyFull', value); |
|||
}, |
|||
updateLogoAutoSize(value) { |
|||
this.$store.dispatch('theme/setLogoAutoSize', value); |
|||
}, |
|||
updateColorfulIcon(value) { |
|||
this.$store.dispatch('theme/setColorfulIcon', value); |
|||
}, |
|||
updateSideUniqueOpen(value) { |
|||
this.$store.dispatch('theme/setSideUniqueOpen', value); |
|||
}, |
|||
updateWeakMode(value) { |
|||
this.$store.dispatch('theme/setWeakMode', value); |
|||
}, |
|||
updateDarkMode(value) { |
|||
this.doWithLoading(() => |
|||
this.$store.dispatch('theme/setDarkMode', value) |
|||
); |
|||
}, |
|||
updateColor(value) { |
|||
this.colorValue = undefined; |
|||
this.doWithLoading(() => this.$store.dispatch('theme/setColor', value)); |
|||
}, |
|||
resetSetting() { |
|||
this.doWithLoading(() => this.$store.dispatch('theme/resetSetting')); |
|||
}, |
|||
doWithLoading(fun) { |
|||
const loading = messageLoading('正在加载主题..'); |
|||
fun() |
|||
.then(() => { |
|||
loading.close(); |
|||
}) |
|||
.catch((e) => { |
|||
loading.close(); |
|||
console.error(e); |
|||
this.$message.error('主题加载失败'); |
|||
}); |
|||
} |
|||
} |
|||
}; |
|||
</script> |
|||
|
|||
<style lang="scss"> |
|||
.ele-setting-wrapper { |
|||
padding: 20px 18px; |
|||
|
|||
.ele-setting-title { |
|||
font-size: 13px; |
|||
margin-bottom: 15px; |
|||
} |
|||
|
|||
/* 主题风格 */ |
|||
.ele-setting-theme > div { |
|||
width: 52px; |
|||
height: 36px; |
|||
line-height: 1; |
|||
font-size: 18px; |
|||
border-radius: 3px; |
|||
margin: 0 20px 30px 0; |
|||
padding: 14px 0 0 24px; |
|||
box-sizing: border-box; |
|||
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.15); |
|||
display: inline-block; |
|||
vertical-align: top; |
|||
position: relative; |
|||
overflow: hidden; |
|||
cursor: pointer; |
|||
transition: background-color 0.2s; |
|||
|
|||
&:before, |
|||
&:after, |
|||
& > .ele-bg-primary { |
|||
content: ''; |
|||
width: 100%; |
|||
height: 10px; |
|||
background: #fff; |
|||
position: absolute; |
|||
left: 0; |
|||
top: 0; |
|||
transition: background-color 0.2s; |
|||
} |
|||
|
|||
&:after { |
|||
width: 14px; |
|||
height: 100%; |
|||
} |
|||
|
|||
&.ele-side-dark:after, |
|||
&.ele-head-dark:before, |
|||
&.ele-layout-mix:before, |
|||
&.ele-layout-mix:after { |
|||
background: #001529; |
|||
} |
|||
|
|||
&.ele-head-light:before, |
|||
&.ele-head-dark:before, |
|||
& > .ele-bg-primary { |
|||
z-index: 1; |
|||
} |
|||
} |
|||
|
|||
/* 主题色选择 */ |
|||
.ele-setting-colors { |
|||
color: #fff; |
|||
margin-bottom: 20px; |
|||
|
|||
.ele-setting-color-item { |
|||
width: 20px; |
|||
height: 20px; |
|||
line-height: 22px; |
|||
border-radius: 2px; |
|||
margin: 8px 8px 0 0; |
|||
display: inline-block; |
|||
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.15); |
|||
vertical-align: top; |
|||
position: relative; |
|||
text-align: center; |
|||
cursor: pointer; |
|||
} |
|||
} |
|||
|
|||
/* 主题配置项 */ |
|||
.ele-setting-item { |
|||
display: flex; |
|||
align-items: center; |
|||
margin-bottom: 20px; |
|||
|
|||
.setting-item-title { |
|||
flex: 1; |
|||
line-height: 28px; |
|||
} |
|||
|
|||
.setting-item-control { |
|||
line-height: 1; |
|||
max-width: 95px; |
|||
} |
|||
} |
|||
|
|||
.el-divider { |
|||
margin-bottom: 20px; |
|||
} |
|||
|
|||
.el-alert + .ele-setting-button-group { |
|||
margin-top: 15px; |
|||
} |
|||
} |
|||
|
|||
/* 适配暗黑模式 */ |
|||
.ele-setting-dark .ele-setting-theme > div { |
|||
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.55); |
|||
|
|||
&:before, |
|||
&:after, |
|||
& > .ele-bg-primary { |
|||
background: #1f1f1f; |
|||
} |
|||
|
|||
&.ele-side-dark:after, |
|||
&.ele-head-dark:before, |
|||
&.ele-layout-mix:before, |
|||
&.ele-layout-mix:after { |
|||
background: #262626; |
|||
} |
|||
} |
|||
|
|||
/* 颜色选择器 */ |
|||
.ele-setting-color-picker.el-color-picker { |
|||
height: auto; |
|||
margin-top: 8px; |
|||
|
|||
.el-color-picker__trigger { |
|||
padding: 0; |
|||
width: 20px; |
|||
height: 20px; |
|||
border: none; |
|||
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.15); |
|||
} |
|||
|
|||
.el-color-picker__color { |
|||
border: none; |
|||
} |
|||
|
|||
.el-color-picker__color-inner { |
|||
border-radius: 2px; |
|||
} |
|||
|
|||
.el-color-picker__empty { |
|||
background: conic-gradient( |
|||
from 90deg at 50% 50%, |
|||
rgb(255, 0, 0) -19.41deg, |
|||
rgb(255, 0, 0) 18.76deg, |
|||
rgb(255, 138, 0) 59.32deg, |
|||
rgb(255, 230, 0) 99.87deg, |
|||
rgb(20, 255, 0) 141.65deg, |
|||
rgb(0, 163, 255) 177.72deg, |
|||
rgb(5, 0, 255) 220.23deg, |
|||
rgb(173, 0, 255) 260.13deg, |
|||
rgb(255, 0, 199) 300.69deg, |
|||
rgb(255, 0, 0) 340.59deg, |
|||
rgb(255, 0, 0) 378.76deg |
|||
); |
|||
top: 0; |
|||
left: 0; |
|||
right: 0; |
|||
bottom: 0; |
|||
transform: none; |
|||
border-radius: 2px; |
|||
font-size: 0; |
|||
} |
|||
|
|||
.el-color-picker__icon { |
|||
font-size: 14px; |
|||
} |
|||
} |
|||
</style> |
|||
@ -1,33 +0,0 @@ |
|||
<!-- 页脚 --> |
|||
<template> |
|||
<div class="ele-text-center" style="padding: 16px 0;"> |
|||
<div> |
|||
<a |
|||
class="ele-text-secondary" |
|||
href="https://eleadmin.com" |
|||
target="_blank">官网 |
|||
</a> |
|||
<em/> |
|||
<a |
|||
class="ele-text-secondary" |
|||
href="https://eleadmin.com/doc/eleadmin/" |
|||
target="_blank">文档 |
|||
</a> |
|||
<em/> |
|||
<a |
|||
class="ele-text-secondary" |
|||
href="https://eleadmin.com/goods/8" |
|||
target="_blank">授权 |
|||
</a> |
|||
</div> |
|||
<div class="ele-text-secondary" style="margin-top: 8px;"> |
|||
Copyright © 2021 武汉易云智科技有限公司 |
|||
</div> |
|||
</div> |
|||
</template> |
|||
|
|||
<script> |
|||
export default { |
|||
name: 'EleFooter' |
|||
} |
|||
</script> |
|||
@ -1,111 +0,0 @@ |
|||
<!-- 顶栏右侧区域按钮 --> |
|||
<template> |
|||
<div class="ele-admin-header-tool"> |
|||
<div |
|||
class="ele-admin-header-tool-item" |
|||
@click="toggleFullscreen"> |
|||
<i :class="isFullscreen?'el-icon-_screen-restore':'el-icon-_screen-full'"></i> |
|||
</div> |
|||
<!-- 消息通知 --> |
|||
<div class="ele-admin-header-tool-item"> |
|||
<ele-notice/> |
|||
</div> |
|||
<!-- 用户信息 --> |
|||
<div class="ele-admin-header-tool-item"> |
|||
<el-dropdown @command="onUserDropClick"> |
|||
<div class="ele-admin-header-avatar"> |
|||
<el-avatar :src="loginUser.avatar"/> |
|||
<span>{{ loginUser.nickname }}</span> |
|||
<i class="el-icon-arrow-down"></i> |
|||
</div> |
|||
<el-dropdown-menu slot="dropdown"> |
|||
<el-dropdown-item |
|||
command="user" |
|||
icon="el-icon-user">个人中心 |
|||
</el-dropdown-item> |
|||
<el-dropdown-item |
|||
command="password" |
|||
icon="el-icon-key">修改密码 |
|||
</el-dropdown-item> |
|||
<el-dropdown-item |
|||
command="logout" |
|||
icon="el-icon-switch-button" |
|||
divided>退出登录 |
|||
</el-dropdown-item> |
|||
</el-dropdown-menu> |
|||
</el-dropdown> |
|||
</div> |
|||
<!-- 主题设置 --> |
|||
<div |
|||
class="ele-admin-header-tool-item" |
|||
v-if="showSetting" |
|||
@click="openSetting"> |
|||
<i class="el-icon-_more"></i> |
|||
</div> |
|||
</div> |
|||
</template> |
|||
|
|||
<script> |
|||
import EleNotice from './notice'; |
|||
|
|||
export default { |
|||
name: 'EleHeaderRight', |
|||
components: {EleNotice}, |
|||
props: { |
|||
// 是否显示打开设置抽屉按钮 |
|||
showSetting: { |
|||
type: Boolean, |
|||
default: true |
|||
} |
|||
}, |
|||
computed: { |
|||
// 当前登录用户信息 |
|||
loginUser() { |
|||
return this.$store.state.user.user; |
|||
} |
|||
}, |
|||
data() { |
|||
return { |
|||
// 是否全屏状态 |
|||
isFullscreen: false |
|||
}; |
|||
}, |
|||
methods: { |
|||
/* 个人信息下拉菜单点击 */ |
|||
onUserDropClick(command) { |
|||
if (command === 'user') { |
|||
if (this.$route.fullPath !== '/user/info') { |
|||
this.$router.push('/user/info'); |
|||
} |
|||
} else if (command === 'password') { |
|||
this.$emit('item-click', 'password'); |
|||
} else if (command === 'logout') { |
|||
// 退出登录 |
|||
this.$confirm( |
|||
'确定要退出登录吗?', |
|||
'提示', |
|||
{type: 'warning'} |
|||
).then(() => { |
|||
// 清除缓存的token |
|||
this.$store.dispatch('user/setToken').then(() => { |
|||
location.replace('/'); |
|||
}); |
|||
}).catch(() => { |
|||
}); |
|||
} |
|||
}, |
|||
/* 打开设置抽屉 */ |
|||
openSetting() { |
|||
this.$emit('item-click', 'setting'); |
|||
}, |
|||
/* 全屏切换 */ |
|||
toggleFullscreen() { |
|||
try { |
|||
this.isFullscreen = this.$util.toggleFullscreen(); |
|||
} catch (e) { |
|||
this.$message.error('您的浏览器不支持全屏模式'); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
</script> |
|||
@ -1,189 +1,262 @@ |
|||
<!-- 框架布局 --> |
|||
<template> |
|||
<ele-pro-layout |
|||
:menus="menus" |
|||
:tabs="theme.tabs" |
|||
:collapse="theme.collapse" |
|||
:side-nav-collapse="theme.sideNavCollapse" |
|||
:body-fullscreen="theme.bodyFullscreen" |
|||
:show-tabs="theme.showTabs" |
|||
:show-footer="theme.showFooter" |
|||
:head-style="theme.headStyle" |
|||
:side-style="theme.sideStyle" |
|||
:layout-style="theme.layoutStyle" |
|||
:side-menu-style="theme.sideMenuStyle" |
|||
:tab-style="theme.tabStyle" |
|||
:fixed-header="theme.fixedHeader" |
|||
:fixed-sidebar="theme.fixedSidebar" |
|||
:fixed-body="theme.fixedBody" |
|||
:layout-style="theme.layoutStyle" |
|||
:head-style="theme.headStyle" |
|||
:side-style="theme.sideStyle" |
|||
:body-full="theme.bodyFull" |
|||
:logo-auto-size="theme.logoAutoSize" |
|||
:colorful-icon="theme.colorfulIcon" |
|||
:side-unique-open="theme.sideUniqueOpen" |
|||
:show-tabs="theme.showTabs" |
|||
:tab-style="theme.tabStyle" |
|||
:body-full="theme.bodyFull" |
|||
:keep-alive-list="keepAliveList" |
|||
:project-name="PROJECT_NAME" |
|||
:hide-footers="HIDE_FOOTERS" |
|||
:hide-sidebars="HIDE_SIDEBARS" |
|||
:repeatable-tabs="REPEATABLE_TABS" |
|||
:home-title="homeTitle" |
|||
:project-name="projectName" |
|||
:tabs="user.tabs" |
|||
:menus="user.menus" |
|||
:need-setting="needSetting" |
|||
:show-setting.sync="showSetting" |
|||
:color="theme.color" |
|||
:dark-mode="theme.darkMode" |
|||
:weak-mode="theme.weakMode" |
|||
:show-content="showContent" |
|||
@update-collapse="updateCollapse" |
|||
@update-screen="updateScreen" |
|||
@tab-add="tabAdd" |
|||
@tab-remove="tabRemove" |
|||
@tab-remove-left="tabRemoveLeft" |
|||
@tab-remove-right="tabRemoveRight" |
|||
@tab-remove-other="tabRemoveOther" |
|||
@tab-remove-all="tabRemoveAll" |
|||
@change-color="changeColor" |
|||
@change-style="changeStyle"> |
|||
:locale="locale" |
|||
:i18n="i18n" |
|||
@update:collapse="updateCollapse" |
|||
@update:side-nav-collapse="updateSideNavCollapse" |
|||
@update:body-fullscreen="updateBodyFullscreen" |
|||
@tab-add="addPageTab" |
|||
@tab-remove="removePageTab" |
|||
@tab-remove-all="removeAllPageTab" |
|||
@tab-remove-left="removeLeftPageTab" |
|||
@tab-remove-right="removeRightPageTab" |
|||
@tab-remove-other="removeOtherPageTab" |
|||
@reload-page="reloadPageTab" |
|||
@logo-click="onLogoClick" |
|||
@screen-size-change="screenSizeChange" |
|||
@set-home-components="setHomeComponents" |
|||
> |
|||
<!-- 路由出口 --> |
|||
<router-layout /> |
|||
<!-- logo图标 --> |
|||
<template slot="logo"> |
|||
<img src="@/assets/logo.svg" alt="logo" /> |
|||
</template> |
|||
<!-- 顶栏右侧区域 --> |
|||
<template slot="right"> |
|||
<ele-header-right |
|||
:show-setting="needSetting" |
|||
@item-click="onItemClick"/> |
|||
<header-tools :fullscreen="fullscreen" @fullscreen="onFullscreen" /> |
|||
</template> |
|||
<!-- 全局页脚 --> |
|||
<template slot="footer"> |
|||
<page-footer /> |
|||
</template> |
|||
<!-- 自定义菜单标题增加徽章、小红点 --> |
|||
<template slot="title" slot-scope="{ title, item }"> |
|||
<span>{{ title }} </span> |
|||
<div v-if="item.meta && item.meta.badge" class="ele-menu-badge"> |
|||
<el-badge :value="item.meta.badge" :type="item.meta.badgeColor" /> |
|||
</div> |
|||
</template> |
|||
<template slot="top-title" slot-scope="{ title, item }"> |
|||
<span>{{ title }} </span> |
|||
<div v-if="item.meta && item.meta.badge" class="ele-menu-badge"> |
|||
<el-badge :value="item.meta.badge" :type="item.meta.badgeColor" /> |
|||
</div> |
|||
</template> |
|||
<template slot="nav-title" slot-scope="{ title, item }"> |
|||
<span>{{ title }} </span> |
|||
<div v-if="item.meta && item.meta.badge" class="ele-menu-badge"> |
|||
<el-badge :value="item.meta.badge" :type="item.meta.badgeColor" /> |
|||
</div> |
|||
</template> |
|||
<!-- 修改密码弹窗 --> |
|||
<ele-password :visible.sync="showPassword"/> |
|||
</ele-pro-layout> |
|||
</template> |
|||
|
|||
<script> |
|||
import { mapGetters } from 'vuex'; |
|||
import setting from '@/config/setting'; |
|||
import EleHeaderRight from './header-right'; |
|||
import ElePassword from './password'; |
|||
import { toggleFullscreen, isFullscreen } from 'ele-admin'; |
|||
import RouterLayout from '@/components/RouterLayout/index.vue'; |
|||
import HeaderTools from './components/header-tools.vue'; |
|||
import PageFooter from './components/page-footer.vue'; |
|||
import { |
|||
PROJECT_NAME, |
|||
HIDE_SIDEBARS, |
|||
HIDE_FOOTERS, |
|||
REPEATABLE_TABS, |
|||
HOME_TITLE |
|||
} from '@/config/setting'; |
|||
import { |
|||
addPageTab, |
|||
removePageTab, |
|||
removeAllPageTab, |
|||
removeLeftPageTab, |
|||
removeRightPageTab, |
|||
removeOtherPageTab, |
|||
reloadPageTab, |
|||
setHomeComponents |
|||
} from '@/utils/page-tab-util'; |
|||
|
|||
export default { |
|||
name: 'EleLayout', |
|||
components: { |
|||
EleHeaderRight, |
|||
ElePassword |
|||
}, |
|||
computed: { |
|||
// 主页标题 |
|||
homeTitle() { |
|||
return setting.homeTitle; |
|||
}, |
|||
// 需要缓存的组件 |
|||
keepAliveList() { |
|||
return setting.keepAliveList; |
|||
}, |
|||
// 是否需要主题设置按钮 |
|||
needSetting() { |
|||
return setting.showSetting; |
|||
}, |
|||
...mapGetters(['theme', 'user']) |
|||
RouterLayout, |
|||
HeaderTools, |
|||
PageFooter |
|||
}, |
|||
data() { |
|||
return { |
|||
// 项目名 |
|||
projectName: process.env.VUE_APP_NAME, |
|||
// 是否显示修改密码弹窗 |
|||
showPassword: false, |
|||
// 是否显示主题设置抽屉 |
|||
showSetting: false, |
|||
// 是否显示主体部分, 如果你的首页用到了权限控制指令, 把这个改成false, 避免权限控制指令可能不生效 |
|||
showContent: true |
|||
PROJECT_NAME, |
|||
HIDE_SIDEBARS, |
|||
HIDE_FOOTERS, |
|||
REPEATABLE_TABS, |
|||
// 是否全屏 |
|||
fullscreen: false |
|||
}; |
|||
}, |
|||
mounted() { |
|||
// 获取用户信息 |
|||
this.getUserInfo(); |
|||
computed: { |
|||
// 当前语言 |
|||
locale() { |
|||
return this.$i18n.locale; |
|||
}, |
|||
methods: { |
|||
/* 获取当前用户信息 */ |
|||
getUserInfo() { |
|||
if (setting.userUrl) { |
|||
this.$http.get(setting.userUrl).then(res => { |
|||
let result; |
|||
if (setting.parseUser) { |
|||
result = setting.parseUser(res.data); |
|||
} else { |
|||
result = res.data; |
|||
} |
|||
if (res.data.code === 0) { |
|||
const user = result.data; |
|||
this.$store.dispatch('user/setUser', user); |
|||
this.$store.dispatch('user/setRoles', user ? user.roles : null); |
|||
this.$store.dispatch('user/setAuthorities', user ? user.authorities : null); |
|||
} else { |
|||
this.$message.error(res.data.msg); |
|||
} |
|||
// 在用户权限信息请求完成后再渲染主体部分, 以免权限控制指令不生效 |
|||
this.showContent = true; |
|||
}).catch(e => { |
|||
this.showContent = true; |
|||
this.$message.error(e.message); |
|||
}); |
|||
} |
|||
// 主页标题 |
|||
homeTitle() { |
|||
return HOME_TITLE ?? this.$t('layout.home'); |
|||
}, |
|||
/* 顶栏右侧点击 */ |
|||
onItemClick(key) { |
|||
if (key === 'password') { |
|||
this.showPassword = true; |
|||
} else if (key === 'setting') { |
|||
this.showSetting = true; |
|||
} |
|||
// 菜单数据 |
|||
menus() { |
|||
return this.$store.state.user.menus; |
|||
}, |
|||
// 主题状态 |
|||
...mapGetters(['theme']) |
|||
}, |
|||
/* 更新collapse */ |
|||
methods: { |
|||
updateCollapse(value) { |
|||
this.$store.dispatch('theme/set', { |
|||
key: 'collapse', |
|||
value: value |
|||
}); |
|||
this.$store.dispatch('theme/setCollapse', value); |
|||
}, |
|||
/* 更新屏幕尺寸 */ |
|||
updateScreen() { |
|||
this.$store.dispatch('theme/updateScreen'); |
|||
updateSideNavCollapse(value) { |
|||
this.$store.dispatch('theme/setSideNavCollapse', value); |
|||
}, |
|||
/* 切换主题色 */ |
|||
changeColor(value) { |
|||
const loading = this.$loading({ |
|||
lock: true, |
|||
background: 'transparent' |
|||
}); |
|||
this.$store.dispatch('theme/setColor', value).then(() => { |
|||
loading.close(); |
|||
}).catch(e => { |
|||
loading.close(); |
|||
console.error(e); |
|||
this.$message.error('主题加载失败'); |
|||
}); |
|||
updateBodyFullscreen(value) { |
|||
this.$store.dispatch('theme/setBodyFullscreen', value); |
|||
}, |
|||
/* 切换主题风格 */ |
|||
changeStyle(value) { |
|||
this.$store.dispatch('theme/set', value); |
|||
onLogoClick(isHome) { |
|||
isHome || this.$router.push('/'); |
|||
}, |
|||
/* 添加tab */ |
|||
tabAdd(value) { |
|||
this.$store.dispatch('user/tabAdd', value); |
|||
screenSizeChange() { |
|||
this.$store.dispatch('theme/updateScreenSize'); |
|||
this.fullscreen = isFullscreen(); |
|||
}, |
|||
/* 移除tab */ |
|||
tabRemove(obj) { |
|||
this.$store.dispatch('user/tabRemove', obj.name).then(last => { |
|||
if (obj.active === obj.name) { |
|||
this.$router.push(last === -1 ? '/' : this.user.tabs[last].path); |
|||
onFullscreen() { |
|||
try { |
|||
this.fullscreen = toggleFullscreen(); |
|||
} catch (e) { |
|||
this.$message.error('您的浏览器不支持全屏模式'); |
|||
} |
|||
}); |
|||
}, |
|||
/* 移除左边tab */ |
|||
tabRemoveLeft(value) { |
|||
this.$store.dispatch('user/tabRemoveLeft', value); |
|||
}, |
|||
/* 移除右边tab */ |
|||
tabRemoveRight(value) { |
|||
this.$store.dispatch('user/tabRemoveRight', value); |
|||
/* 菜单标题国际化 */ |
|||
i18n(_path, key) { |
|||
const k = 'route.' + key + '._name'; |
|||
const title = this.$t(k); |
|||
return title === k ? undefined : title; |
|||
}, |
|||
/* 移除其它tab */ |
|||
tabRemoveOther(value) { |
|||
this.$store.dispatch('user/tabRemoveOther', value); |
|||
}, |
|||
/* 移除全部tab */ |
|||
tabRemoveAll() { |
|||
this.$store.dispatch('user/tabRemoveAll'); |
|||
// |
|||
addPageTab, |
|||
removePageTab, |
|||
removeAllPageTab, |
|||
removeLeftPageTab, |
|||
removeRightPageTab, |
|||
removeOtherPageTab, |
|||
reloadPageTab, |
|||
setHomeComponents |
|||
} |
|||
}; |
|||
</script> |
|||
|
|||
<style lang="scss"> |
|||
// 侧栏菜单徽章样式,定位在右侧垂直居中并调小尺寸 |
|||
.ele-menu-badge { |
|||
position: absolute; |
|||
top: 50%; |
|||
right: 14px; |
|||
line-height: 1; |
|||
margin-top: -9px; |
|||
font-size: 0; |
|||
|
|||
.el-badge__content { |
|||
height: 18px; |
|||
line-height: 18px; |
|||
border-radius: 9px; |
|||
border: none; |
|||
min-width: 18px; |
|||
padding: 0 4px; |
|||
box-sizing: border-box; |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
// 父级菜单标题中右侧多定位一点,避免与箭头重合 |
|||
.el-submenu > .el-submenu__title .ele-menu-badge { |
|||
right: 36px; |
|||
} |
|||
|
|||
// 折叠悬浮中样式调整 |
|||
.el-menu--popup { |
|||
.el-submenu > .el-submenu__title .ele-menu-badge { |
|||
right: 20px; |
|||
} |
|||
} |
|||
|
|||
// 侧栏折叠后样式调整 |
|||
.ele-admin-collapse .ele-admin-sidebar-menus > .el-menu { |
|||
& > .el-menu-item, |
|||
& > .el-submenu > .el-submenu__title { |
|||
.ele-menu-badge { |
|||
top: 6px; |
|||
right: 6px; |
|||
margin: 0; |
|||
} |
|||
} |
|||
} |
|||
|
|||
// 顶栏菜单标题中样式调整 |
|||
.ele-admin-header-nav.el-menu { |
|||
& > .el-menu-item, |
|||
& > .el-submenu > .el-submenu__title { |
|||
.ele-menu-badge { |
|||
position: static; |
|||
right: auto; |
|||
top: auto; |
|||
display: inline-block; |
|||
vertical-align: 6px; |
|||
margin: 0 0 0 2px; |
|||
} |
|||
} |
|||
} |
|||
|
|||
// 双侧栏时一级侧栏菜单中样式调整,定位在右上角 |
|||
.ele-admin-sidebar-nav-menu > .el-menu { |
|||
& > .el-menu-item, |
|||
& > .el-submenu > .el-submenu__title { |
|||
.ele-menu-badge { |
|||
top: 2px; |
|||
right: 4px; |
|||
margin: 0; |
|||
} |
|||
} |
|||
} |
|||
|
|||
// 双侧栏时一级侧栏菜单折叠后样式调整 |
|||
.ele-admin-nav-collapse .ele-admin-sidebar-nav-menu > .el-menu { |
|||
& > .el-menu-item, |
|||
& > .el-submenu > .el-submenu__title { |
|||
.ele-menu-badge { |
|||
top: -2px; |
|||
right: -2px; |
|||
} |
|||
} |
|||
} |
|||
</style> |
|||
|
|||
@ -1,300 +0,0 @@ |
|||
<!-- 顶栏消息图标 --> |
|||
<template> |
|||
<el-popover |
|||
width="300" |
|||
v-model="visible" |
|||
trigger="click" |
|||
popper-class="ele-notice-pop" |
|||
transition="el-zoom-in-top" |
|||
class="ele-notice-group"> |
|||
<div |
|||
class="ele-notice-group" |
|||
slot="reference"> |
|||
<el-badge |
|||
:value="allNum" |
|||
:hidden="!allNum"> |
|||
<i class="el-icon-bell"></i> |
|||
</el-badge> |
|||
</div> |
|||
<el-tabs |
|||
v-model="active" |
|||
class="user-info-tabs"> |
|||
<el-tab-pane |
|||
:label="noticeLabel" |
|||
name="notice"> |
|||
<div class="ele-notice-list ele-scrollbar-mini"> |
|||
<div |
|||
v-for="(item,index) in notice" |
|||
:key="index" |
|||
class="ele-notice-item"> |
|||
<div class="ele-cell ele-notice-item-wrapper"> |
|||
<i :class="[item.icon,'ele-notice-item-icon']"></i> |
|||
<div class="ele-cell-content"> |
|||
<div class="ele-elip">{{ item.title }}</div> |
|||
<div class="ele-text-secondary ele-elip">{{ item.pub_time }}</div> |
|||
</div> |
|||
</div> |
|||
<el-divider/> |
|||
</div> |
|||
</div> |
|||
<div |
|||
v-if="notice.length" |
|||
class="ele-cell ele-notice-actions"> |
|||
<!-- <div--> |
|||
<!-- @click="clear(1)"--> |
|||
<!-- class="ele-cell-content">清空通知--> |
|||
<!-- </div>--> |
|||
<el-divider |
|||
direction="vertical" |
|||
class="line-color-light"/> |
|||
<div |
|||
@click="more(1)" |
|||
class="ele-cell-content">查看更多 |
|||
</div> |
|||
</div> |
|||
<ele-empty |
|||
v-if="!notice.length" |
|||
text="你已查看所有通知"/> |
|||
</el-tab-pane> |
|||
<el-tab-pane |
|||
:label="messageLabel" |
|||
name="message"> |
|||
<div class="ele-notice-list ele-scrollbar-mini"> |
|||
<div |
|||
v-for="(item,index) in message" |
|||
:key="index" |
|||
class="ele-notice-item"> |
|||
<div class="ele-cell ele-notice-item-wrapper ele-cell-align-top"> |
|||
<el-avatar |
|||
:src="item.avatar_str" |
|||
size="medium"/> |
|||
<div class="ele-cell-content"> |
|||
<div class="ele-elip">{{ item.title }}</div> |
|||
<div class="ele-text-secondary ele-elip">{{ item.content }}</div> |
|||
<div class="ele-cell-desc ele-elip">{{ item.pub_time }}</div> |
|||
</div> |
|||
</div> |
|||
<el-divider/> |
|||
</div> |
|||
</div> |
|||
<div |
|||
v-if="message.length" |
|||
class="ele-cell ele-notice-actions"> |
|||
<!-- <div--> |
|||
<!-- @click="clear(2)"--> |
|||
<!-- class="ele-cell-content">清空消息--> |
|||
<!-- </div>--> |
|||
<el-divider |
|||
direction="vertical" |
|||
class="line-color-light"/> |
|||
<div |
|||
@click="more(2)" |
|||
class="ele-cell-content">查看更多 |
|||
</div> |
|||
</div> |
|||
<ele-empty |
|||
v-if="!message.length" |
|||
text="你已读完所有私信"/> |
|||
</el-tab-pane> |
|||
</el-tabs> |
|||
</el-popover> |
|||
</template> |
|||
|
|||
<script> |
|||
export default { |
|||
name: 'EleNotice', |
|||
data() { |
|||
return { |
|||
visible: false, |
|||
active: 'notice', |
|||
notice: [ |
|||
|
|||
], |
|||
notice_count:0, |
|||
message: [ |
|||
|
|||
], |
|||
message_count:0, |
|||
}; |
|||
}, |
|||
|
|||
computed: { |
|||
|
|||
|
|||
// 通知标题 |
|||
noticeLabel() { |
|||
if (this.notice_count) { |
|||
return `通知(${this.notice_count})`; |
|||
} |
|||
return '通知'; |
|||
}, |
|||
// 私信标题 |
|||
messageLabel() { |
|||
if (this.message_count) { |
|||
return `私信(${this.message_count})`; |
|||
} |
|||
return '私信'; |
|||
}, |
|||
|
|||
// 所有消息数量 |
|||
allNum() { |
|||
return this.notice_count + this.message_count ; |
|||
} |
|||
}, |
|||
|
|||
mounted() { |
|||
// 获取用户信息 |
|||
this.getMessage(); |
|||
|
|||
setInterval(this.setM,60000) |
|||
}, |
|||
|
|||
methods: { |
|||
setM(){ |
|||
this.setMessage(); |
|||
this.getMessage(); |
|||
}, |
|||
getMessage(){ |
|||
this.$http.get('/manager/getMessage?type=99').then(res => { |
|||
if (res.data.code === 0) { |
|||
this.message = res.data.data.sx.list; |
|||
this.notice = res.data.data.gg.list; |
|||
this.message_count = res.data.data.sx.count; |
|||
this.notice_count = res.data.data.gg.count; |
|||
} |
|||
}) |
|||
}, |
|||
setMessage(){ |
|||
this.$http.get('/manager/setMessage?type=99').then(res => { |
|||
if (res.data.code === 0) { |
|||
this.message = res.data.data.sx.list; |
|||
this.notice = res.data.data.gg.list; |
|||
this.message_count = res.data.data.sx.count; |
|||
this.notice_count = res.data.data.gg.count; |
|||
} |
|||
}) |
|||
}, |
|||
|
|||
/* 清空消息 */ |
|||
clear(type) { |
|||
if (type === 1) { |
|||
this.notice = []; |
|||
} else if (type === 2) { |
|||
this.message = []; |
|||
} |
|||
}, |
|||
/* 查看更多 */ |
|||
more(type) { |
|||
console.log(type); |
|||
if (this.$route.path !== '/user/message') { |
|||
this.$router.push('/user/message'); |
|||
} |
|||
this.show = false; |
|||
} |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style lang="scss"> |
|||
.ele-notice-group { |
|||
vertical-align: top !important; |
|||
display: inline-block; |
|||
|
|||
.el-badge { |
|||
line-height: normal; |
|||
} |
|||
} |
|||
|
|||
/* 消息通知pop */ |
|||
.ele-notice-pop { |
|||
margin: 0 !important; |
|||
padding: 0 !important; |
|||
|
|||
/* tab */ |
|||
.el-tabs__nav-scroll { |
|||
text-align: center; |
|||
} |
|||
|
|||
.el-tabs__nav { |
|||
float: none; |
|||
display: inline-block; |
|||
} |
|||
|
|||
.el-tabs__item { |
|||
padding: 0 20px; |
|||
} |
|||
|
|||
/* 空视图 */ |
|||
.ele-empty { |
|||
padding: 100px 0; |
|||
} |
|||
} |
|||
|
|||
/* 列表 */ |
|||
.ele-notice-list { |
|||
padding-top: 8px; |
|||
max-height: 360px; |
|||
overflow: auto; |
|||
} |
|||
|
|||
.ele-notice-item { |
|||
.ele-notice-item-wrapper { |
|||
padding: 12px 15px; |
|||
transition: background-color .2s; |
|||
cursor: pointer; |
|||
|
|||
&:hover { |
|||
background-color: hsla(0, 0%, 60%, .05); |
|||
} |
|||
} |
|||
|
|||
.ele-text-secondary { |
|||
margin-top: 5px; |
|||
font-size: 13px; |
|||
} |
|||
|
|||
.ele-cell-desc { |
|||
margin-top: 3px !important; |
|||
font-size: 12px !important; |
|||
} |
|||
} |
|||
|
|||
.ele-notice-item-icon { |
|||
width: 32px; |
|||
height: 32px; |
|||
line-height: 32px !important; |
|||
color: #FFF; |
|||
font-size: 16px; |
|||
background-color: #60B2FC; |
|||
border-radius: 50%; |
|||
text-align: center; |
|||
|
|||
|
|||
&.el-icon-s-check { |
|||
background-color: #F5686F; |
|||
} |
|||
|
|||
&.el-icon-video-camera { |
|||
background-color: #7CD734; |
|||
} |
|||
|
|||
&.el-icon-s-claim { |
|||
background-color: #FAAD14; |
|||
} |
|||
|
|||
&.el-icon-message-solid { |
|||
background-color: #2BCACD; |
|||
} |
|||
} |
|||
|
|||
/* 操作按钮 */ |
|||
.ele-notice-actions > .ele-cell-content { |
|||
line-height: 42px; |
|||
text-align: center; |
|||
cursor: pointer; |
|||
|
|||
&:hover { |
|||
background-color: hsla(0, 0%, 60%, .05); |
|||
} |
|||
} |
|||
</style> |
|||
@ -1,136 +0,0 @@ |
|||
<!-- 修改密码弹窗 --> |
|||
<template> |
|||
<el-dialog |
|||
:visible="visible" |
|||
title="修改密码" |
|||
width="400px" |
|||
@closed="onClose" |
|||
@update:visible="updateVisible" |
|||
:append-to-body="true" |
|||
:lock-scroll="false"> |
|||
<el-form |
|||
ref="form" |
|||
:model="form" |
|||
:rules="rules" |
|||
label-width="82px" |
|||
@keyup.enter.native="save"> |
|||
<el-form-item |
|||
label="旧密码:" |
|||
prop="old"> |
|||
<el-input |
|||
v-model="form.old" |
|||
placeholder="请输入旧密码" |
|||
show-password/> |
|||
</el-form-item> |
|||
<el-form-item |
|||
label="新密码:" |
|||
prop="password"> |
|||
<el-input |
|||
v-model="form.password" |
|||
placeholder="请输入新密码" |
|||
show-password/> |
|||
</el-form-item> |
|||
<el-form-item |
|||
label="确认密码:" |
|||
prop="password2"> |
|||
<el-input |
|||
v-model="form.password2" |
|||
placeholder="请再次输入新密码" |
|||
show-password/> |
|||
</el-form-item> |
|||
</el-form> |
|||
<div slot="footer"> |
|||
<el-button |
|||
@click="cancel">取消 |
|||
</el-button> |
|||
<el-button |
|||
type="primary" |
|||
@click="save">确定 |
|||
</el-button> |
|||
</div> |
|||
</el-dialog> |
|||
</template> |
|||
|
|||
<script> |
|||
export default { |
|||
name: 'ElePassword', |
|||
props: { |
|||
visible: Boolean |
|||
}, |
|||
data() { |
|||
let rePswRule = (rule, value, callback) => { |
|||
if (!value) { |
|||
callback(new Error('请再次输入新密码')); |
|||
} else if (value !== this.form.password) { |
|||
callback(new Error('两次输入密码不一致')); |
|||
} else { |
|||
callback(); |
|||
} |
|||
}; |
|||
return { |
|||
// 表单数据 |
|||
form: { |
|||
old: '', |
|||
password: '', |
|||
password2: '' |
|||
}, |
|||
// 表单验证 |
|||
rules: { |
|||
old: [ |
|||
{required: true, message: '请输入旧密码', trigger: 'blur'} |
|||
], |
|||
password: [ |
|||
{required: true, message: '请输入新密码', trigger: 'blur'} |
|||
], |
|||
password2: [ |
|||
{validator: rePswRule, trigger: 'blur'} |
|||
] |
|||
}, |
|||
// 按钮loading |
|||
loading: false |
|||
}; |
|||
}, |
|||
methods: { |
|||
/* 保存修改 */ |
|||
save() { |
|||
this.$refs['form'].validate((valid) => { |
|||
if (valid) { |
|||
this.loading = true; |
|||
let formData = new FormData(); |
|||
formData.append('old_password', this.form.old); |
|||
formData.append('password', this.form.password); |
|||
formData.append('password2', this.form.password2); |
|||
this.$http.post('/manager/passwordEdit', formData).then(res => { |
|||
this.loading = false; |
|||
if (res.data.code === 0) { |
|||
this.$message({type: 'success', message: res.data.msg}); |
|||
this.cancel(); |
|||
} else { |
|||
this.$message.error(res.data.msg); |
|||
} |
|||
}).catch(e => { |
|||
this.loading = false; |
|||
this.$message.error(e.message); |
|||
}); |
|||
} else { |
|||
return false; |
|||
} |
|||
}); |
|||
}, |
|||
/* 取消 */ |
|||
cancel() { |
|||
this.updateVisible(false); |
|||
}, |
|||
/* 关闭回调 */ |
|||
onClose() { |
|||
this.form = {}; |
|||
this.$refs['form'].resetFields(); |
|||
this.loading = false; |
|||
}, |
|||
/* 修改visible */ |
|||
updateVisible(value) { |
|||
this.$emit('update:visible', value); |
|||
} |
|||
} |
|||
} |
|||
</script> |
|||
@ -1,23 +1,33 @@ |
|||
/** 主入口js */ |
|||
import Vue from 'vue'; |
|||
import App from './App.vue'; |
|||
import router from './router'; |
|||
import store from './store'; |
|||
import setting from './config/setting'; |
|||
import permission from '@/utils/permission'; |
|||
import VueClipboard from 'vue-clipboard2'; |
|||
import './config/axios-config'; |
|||
import EleAdmin from 'ele-admin'; |
|||
import router from './router'; |
|||
import permission from './utils/permission'; |
|||
import './styles/index.scss'; |
|||
import EleAdmin from 'ele-admin'; |
|||
import VueClipboard from 'vue-clipboard2'; |
|||
import i18n from './i18n'; |
|||
import { MAP_KEY, LICENSE_CODE } from '@/config/setting'; |
|||
|
|||
Vue.config.productionTip = false; |
|||
Vue.prototype.$setting = setting; |
|||
Vue.use(EleAdmin, {size: 'medium'}); |
|||
|
|||
Vue.use(EleAdmin, { |
|||
response: { |
|||
dataName: 'list' |
|||
}, |
|||
mapKey: MAP_KEY, |
|||
license: LICENSE_CODE, |
|||
i18n: (key, value) => i18n.t(key, value) |
|||
}); |
|||
|
|||
Vue.use(permission); |
|||
|
|||
Vue.use(VueClipboard); |
|||
|
|||
new Vue({ |
|||
router, |
|||
store, |
|||
render: h => h(App) |
|||
i18n, |
|||
render: (h) => h(App) |
|||
}).$mount('#app'); |
|||
|
|||
@ -1,4 +1,7 @@ |
|||
/** |
|||
* vuex getter |
|||
*/ |
|||
export default { |
|||
theme: state => state.theme, |
|||
user: state => state.user |
|||
} |
|||
user: (state) => state.user, |
|||
theme: (state) => state.theme |
|||
}; |
|||
|
|||
@ -1,302 +1,506 @@ |
|||
/** |
|||
* 主题状态管理 license by http://eleadmin.com
|
|||
* 主题状态管理 |
|||
*/ |
|||
import setting from '@/config/setting'; |
|||
|
|||
// 获取本地缓存配置
|
|||
let cache = {}; |
|||
try { |
|||
cache = JSON.parse(localStorage.getItem(setting.themeStoreName)) || {}; |
|||
} catch (e) { |
|||
console.error(e); |
|||
} |
|||
|
|||
// 获取缓存的主题配置和缓存的主题css
|
|||
const cacheTheme = getCache(cache, [ |
|||
'color', 'sideStyle', 'headStyle', |
|||
'tabStyle', 'layoutStyle', 'bodyFull', |
|||
'fixedHeader', 'fixedSidebar', 'fixedBody', |
|||
'showTabs', 'logoAutoSize', 'colorfulIcon', |
|||
'sideUniqueOpen', 'showFooter', 'weakMode', 'darkMode' |
|||
], setting); |
|||
|
|||
// 恢复色弱模式
|
|||
if (cacheTheme.weakMode) { |
|||
document.body.classList.add('ele-admin-weak'); |
|||
} |
|||
|
|||
// 恢复主题色
|
|||
window.onload = function () { |
|||
changeTheme(cacheTheme.color, cacheTheme.darkMode).catch(e => { |
|||
console.error(e); |
|||
}); |
|||
} |
|||
|
|||
// 获取屏幕宽度
|
|||
const screenWidth = document.documentElement.clientWidth || document.body.clientWidth, |
|||
screenHeight = document.documentElement.clientHeight || document.body.clientHeight; |
|||
|
|||
export default { |
|||
namespaced: true, |
|||
state: { |
|||
// 侧边栏风格: 0亮色, 1暗色
|
|||
sideStyle: cacheTheme.sideStyle, |
|||
// 顶栏风格: 0亮色, 1暗色, 2主色
|
|||
headStyle: cacheTheme.headStyle, |
|||
// 标签页风格: 0默认, 1圆点, 2卡片
|
|||
tabStyle: cacheTheme.tabStyle, |
|||
// 布局风格: 0默认, 1顶部菜单风格, 2混合菜单风格
|
|||
layoutStyle: cacheTheme.layoutStyle, |
|||
// 是否固定侧栏
|
|||
fixedSidebar: cacheTheme.fixedSidebar, |
|||
import { |
|||
screenWidth, |
|||
screenHeight, |
|||
contentWidth, |
|||
contentHeight |
|||
} from 'ele-admin'; |
|||
import { changeColor } from 'ele-admin/es/utils/theme-util'; |
|||
import { TAB_KEEP_ALIVE, THEME_STORE_NAME } from '@/config/setting'; |
|||
// state默认值
|
|||
const DEFAULT_STATE = Object.freeze({ |
|||
// 多页签数据
|
|||
tabs: [], |
|||
// 是否折叠侧边栏
|
|||
collapse: false, |
|||
// 是否折叠侧栏一级菜单
|
|||
sideNavCollapse: false, |
|||
// 内容区域是否全屏
|
|||
bodyFullscreen: false, |
|||
// 是否开启多页签
|
|||
showTabs: true, |
|||
// 是否开启页脚
|
|||
showFooter: true, |
|||
// 顶栏风格: light(亮色), dark(暗色), primary(主色)
|
|||
headStyle: 'light', |
|||
// 侧边栏风格: light(亮色), dark(暗色)
|
|||
sideStyle: 'dark', |
|||
// 布局风格: side(默认), top(顶栏菜单), mix(混合菜单)
|
|||
layoutStyle: 'side', |
|||
// 侧边栏菜单风格: default(默认), mix(双排菜单)
|
|||
sideMenuStyle: 'default', |
|||
// 标签页风格: default(默认), dot(圆点), card(卡片)
|
|||
tabStyle: 'default', |
|||
// 是否固定顶栏
|
|||
fixedHeader: cacheTheme.fixedHeader, |
|||
fixedHeader: false, |
|||
// 是否固定侧栏
|
|||
fixedSidebar: true, |
|||
// 是否固定主体
|
|||
fixedBody: cacheTheme.fixedBody, |
|||
fixedBody: true, |
|||
// 内容区域宽度铺满
|
|||
bodyFull: cacheTheme.bodyFull, |
|||
// 是否开启多标签
|
|||
showTabs: cacheTheme.showTabs, |
|||
bodyFull: true, |
|||
// logo是否自适应宽度
|
|||
logoAutoSize: cacheTheme.logoAutoSize, |
|||
// 侧栏是否多彩图标
|
|||
colorfulIcon: cacheTheme.colorfulIcon, |
|||
// 侧边栏是否只保持一个子菜单展开
|
|||
sideUniqueOpen: cacheTheme.sideUniqueOpen, |
|||
// 是否开启页脚
|
|||
showFooter: cacheTheme.showFooter, |
|||
logoAutoSize: false, |
|||
// 侧栏是否彩色图标
|
|||
colorfulIcon: false, |
|||
// 侧栏是否只保持一个子菜单展开
|
|||
sideUniqueOpen: true, |
|||
// 是否是色弱模式
|
|||
weakMode: cacheTheme.weakMode, |
|||
weakMode: false, |
|||
// 是否是暗黑模式
|
|||
darkMode: cacheTheme.darkMode, |
|||
darkMode: false, |
|||
// 主题色
|
|||
color: cacheTheme.color, |
|||
// 是否折叠侧边栏
|
|||
collapse: screenWidth < 992, |
|||
// 当前屏幕宽度
|
|||
screenWidth: screenWidth, |
|||
// 当前屏幕高度
|
|||
screenHeight: screenHeight |
|||
}, |
|||
mutations: { |
|||
SET: (state, obj) => { |
|||
state[obj.key] = obj.value; |
|||
// 开关色弱模式
|
|||
if ('weakMode' === obj.key) { |
|||
if (obj.value) { |
|||
document.body.classList.add('ele-admin-weak'); |
|||
} else { |
|||
document.body.classList.remove('ele-admin-weak'); |
|||
color: null, |
|||
// 主页的组件
|
|||
homeComponents: [], |
|||
// 刷新路由时的参数
|
|||
routeReload: null, |
|||
// 屏幕宽度
|
|||
screenWidth: screenWidth(), |
|||
// 屏幕高度
|
|||
screenHeight: screenHeight(), |
|||
// 内容区域宽度
|
|||
contentWidth: contentWidth(), |
|||
// 内容区域高度
|
|||
contentHeight: contentHeight() |
|||
}); |
|||
// 延时操作定时器
|
|||
let disableTransitionTimer, updateContentSizeTimer; |
|||
const weakClass = 'ele-admin-weak'; |
|||
const disabledClass = 'ele-transition-disabled'; |
|||
|
|||
/** |
|||
* 读取缓存配置 |
|||
*/ |
|||
function getCacheSetting() { |
|||
try { |
|||
const value = localStorage.getItem(THEME_STORE_NAME); |
|||
if (value) { |
|||
const cache = JSON.parse(value); |
|||
if (typeof cache === 'object' && cache !== null) { |
|||
return cache; |
|||
} |
|||
} |
|||
// 缓存修改的配置
|
|||
if (['collapse', 'screenWidth', 'screenHeight'].indexOf(obj.key) === -1) { |
|||
let temp = JSON.parse(localStorage.getItem(setting.themeStoreName) || '{}'); |
|||
temp[obj.key] = obj.value; |
|||
localStorage.setItem(setting.themeStoreName, JSON.stringify(temp)); |
|||
} catch (e) { |
|||
console.error(e); |
|||
} |
|||
return {}; |
|||
} |
|||
}, |
|||
actions: { |
|||
/** |
|||
* 修改配置 |
|||
* @param commit |
|||
* @param obj |
|||
*/ |
|||
set({commit}, obj) { |
|||
commit('SET', obj); |
|||
}, |
|||
|
|||
/** |
|||
* 切换配置(boolean类型的配置) |
|||
* @param commit |
|||
* @param state |
|||
* @param key |
|||
* 缓存配置 |
|||
*/ |
|||
toggle({commit, state}, key) { |
|||
commit('SET', {key: key, value: !state[key]}); |
|||
}, |
|||
function cacheSetting(key, value) { |
|||
const cache = getCacheSetting(); |
|||
if (cache[key] !== value) { |
|||
cache[key] = value; |
|||
localStorage.setItem(THEME_STORE_NAME, JSON.stringify(cache)); |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* 更新屏幕尺寸 |
|||
* @param commit |
|||
* @param state |
|||
* 切换色弱模式 |
|||
*/ |
|||
updateScreen({commit, state}) { |
|||
const w = document.documentElement.clientWidth || document.body.clientWidth, |
|||
h = document.documentElement.clientHeight || document.body.clientHeight; |
|||
if (w !== state.screenWidth) { |
|||
commit('SET', {key: 'screenWidth', value: w}); |
|||
function changeWeakMode(weakMode) { |
|||
if (weakMode) { |
|||
document.body.classList.add(weakClass); |
|||
} else { |
|||
document.body.classList.remove(weakClass); |
|||
} |
|||
if (h !== state.screenHeight) { |
|||
commit('SET', {key: 'screenHeight', value: h}); |
|||
} |
|||
}, |
|||
|
|||
/** |
|||
* 切换主题色 |
|||
* @param commit |
|||
* @param state |
|||
* @param color |
|||
* @returns {Promise<>} |
|||
* 切换主题 |
|||
*/ |
|||
setColor({commit, state}, color) { |
|||
function changeTheme(value, dark) { |
|||
return new Promise((resolve, reject) => { |
|||
changeTheme(color, state.darkMode).then(() => { |
|||
commit('SET', {key: 'color', value: color}); |
|||
return resolve(); |
|||
}).catch(e => { |
|||
try { |
|||
changeColor(value, dark); |
|||
resolve(); |
|||
} catch (e) { |
|||
reject(e); |
|||
}); |
|||
}); |
|||
} |
|||
} |
|||
}); |
|||
} |
|||
|
|||
/** |
|||
* 获取缓存配置项 |
|||
* @param cache 缓存数据 |
|||
* @param k 配置项 |
|||
* @param v 默认值 |
|||
* 切换布局时禁用过渡动画 |
|||
*/ |
|||
function getCache(cache, k, v) { |
|||
if (Array.isArray(k)) { |
|||
let obj = {}; |
|||
k.forEach(t => { |
|||
obj[t] = (cache[t] === null || cache[t] === undefined) ? v[t] : cache[t]; |
|||
}); |
|||
return obj; |
|||
} else { |
|||
if (cache[k] === null || cache[k] === undefined) { |
|||
return v; |
|||
} |
|||
return cache[k]; |
|||
} |
|||
function disableTransition() { |
|||
disableTransitionTimer && clearTimeout(disableTransitionTimer); |
|||
document.body.classList.add(disabledClass); |
|||
disableTransitionTimer = setTimeout(() => { |
|||
document.body.classList.remove(disabledClass); |
|||
}, 100); |
|||
} |
|||
|
|||
/** |
|||
* 切换主题 |
|||
* @param color 主题色 |
|||
* @param darkMode 是否是暗黑模式 |
|||
* @returns {Promise<>} |
|||
* 获取含本地缓存的state值 |
|||
*/ |
|||
function changeTheme(color, darkMode) { |
|||
const version = process.env.VUE_APP_VERSION; |
|||
// 对应的css文件名
|
|||
let colorCss; |
|||
if (darkMode) { |
|||
if (color) { |
|||
colorCss = color + '-dark'; |
|||
} else { |
|||
colorCss = 'dark'; |
|||
} |
|||
} else { |
|||
colorCss = color; |
|||
function getState() { |
|||
const state = Object.assign({}, DEFAULT_STATE); |
|||
const cache = getCacheSetting(); |
|||
Object.keys(state).forEach((key) => { |
|||
if (typeof cache[key] !== 'undefined') { |
|||
state[key] = cache[key]; |
|||
} |
|||
// 获取缓存的主题css
|
|||
let themeCache = {}, |
|||
cacheStoreName = setting.themeStoreName + '-cache'; |
|||
if (window.eleThemeCache) { |
|||
themeCache = window.eleThemeCache; |
|||
} else { |
|||
try { |
|||
const localCache = JSON.parse(localStorage.getItem(cacheStoreName) || '{}'); |
|||
if (localCache && version === localCache.version && localCache.cache) { |
|||
themeCache = localCache.cache; |
|||
window.eleThemeCache = themeCache; |
|||
}); |
|||
return state; |
|||
} |
|||
} catch (e) { |
|||
console.error(e); |
|||
|
|||
export default { |
|||
namespaced: true, |
|||
state: getState(), |
|||
getters: { |
|||
// 需要keep-alive的组件
|
|||
keepAliveInclude(state) { |
|||
if (!TAB_KEEP_ALIVE || !state.showTabs) { |
|||
return []; |
|||
} |
|||
const components = new Set(); |
|||
const { reloadPath, reloadHome } = state.routeReload || {}; |
|||
state.tabs?.forEach((t) => { |
|||
const isReload = reloadPath && reloadPath === t.fullPath; |
|||
if (!isReload && t.components) { |
|||
t.components.forEach((c) => { |
|||
if (typeof c === 'string' && c) { |
|||
components.add(c); |
|||
} |
|||
}); |
|||
} |
|||
// 加载主题css
|
|||
return new Promise((resolve, reject) => { |
|||
// 恢复默认主题
|
|||
if (!colorCss) { |
|||
removeTheme(); |
|||
return resolve(); |
|||
} |
|||
// 主题css已经缓存过
|
|||
if (themeCache[colorCss]) { |
|||
removeTheme(); // 移除上次的主题
|
|||
let elem = document.createElement('style'); |
|||
elem.id = `ele-theme-${colorCss}`; |
|||
elem.setAttribute('type', 'text/css'); |
|||
elem.innerHTML = themeCache[colorCss]; |
|||
document.head.appendChild(elem); |
|||
return resolve(); |
|||
} |
|||
// 主题css的js模块已被加载过
|
|||
const oldElem = document.head.querySelector(`#ele-theme-${colorCss}-js`); |
|||
if (oldElem) { |
|||
removeTheme(); // 移除上次的主题
|
|||
let elem = document.createElement('link'); |
|||
elem.id = `ele-theme-${colorCss}`; |
|||
elem.setAttribute('type', 'text/css'); |
|||
elem.setAttribute('rel', 'stylesheet'); |
|||
elem.setAttribute('href', oldElem.getAttribute('ele-css')); |
|||
document.head.appendChild(elem); |
|||
return resolve(); |
|||
} |
|||
// 把head下面相关元素标记为非主题元素
|
|||
const nid = ':not([id^="ele-theme-"])', sel = `style${nid},link${nid},script${nid}`; |
|||
document.head.querySelectorAll(sel).forEach(elem => { |
|||
if (!elem.getAttribute('ele-theme')) { |
|||
elem.setAttribute('ele-theme', 'no'); |
|||
}); |
|||
if (!reloadHome) { |
|||
state.homeComponents?.forEach((c) => { |
|||
if (typeof c === 'string' && c) { |
|||
components.add(c); |
|||
} |
|||
}); |
|||
// 加载主题css模块
|
|||
import(`@/styles/theme/${colorCss}.scss`).then(() => { |
|||
removeTheme(); // 移除上次的主题
|
|||
// 获取import之后的主题标签
|
|||
let elem = document.head.querySelectorAll('style:not([ele-theme="no"])'); |
|||
elem = elem.length ? elem[elem.length - 1] : null; |
|||
if (!elem) { |
|||
// 可能是style标签也可能是link标签
|
|||
elem = document.head.querySelectorAll('link:not([ele-theme="no"])'); |
|||
elem = elem.length ? elem[elem.length - 1] : null; |
|||
if (!elem) { |
|||
return reject(new Error('theme element not found.')); |
|||
} |
|||
// 再找到对应的主题js模块的标签
|
|||
const href = elem.getAttribute('href'), |
|||
uuid = href.substring(href.indexOf('chunk-'), href.indexOf('.')), |
|||
qs = `script[src^="/js/${uuid}"]:not([ele-theme="no"])`; |
|||
let node = document.head.querySelectorAll(qs); |
|||
if (node.length) { |
|||
node[node.length - 1].id = `ele-theme-${colorCss}-js`; |
|||
// 记录css地址
|
|||
node[node.length - 1].setAttribute('ele-css', href); |
|||
} |
|||
} |
|||
elem.id = `ele-theme-${colorCss}`; |
|||
// 缓存主题css
|
|||
if (elem.innerHTML) { |
|||
let cache = {}; |
|||
cache[colorCss] = elem.innerHTML; |
|||
try { |
|||
localStorage.setItem(cacheStoreName, JSON.stringify({ |
|||
version: version, |
|||
cache: cache |
|||
})); |
|||
} catch (e) { |
|||
console.error(e); |
|||
} |
|||
if (!window.eleThemeCache) { |
|||
window.eleThemeCache = {}; |
|||
return Array.from(components); |
|||
} |
|||
window.eleThemeCache[colorCss] = cache[colorCss]; |
|||
}, |
|||
mutations: { |
|||
SET(state, { key, value }) { |
|||
state[key] = value; |
|||
} |
|||
return resolve(); |
|||
}).catch(e => { |
|||
}, |
|||
actions: { |
|||
setTabs({ commit }, value) { |
|||
commit('SET', { key: 'tabs', value }); |
|||
//cacheSetting('tabs', value);
|
|||
}, |
|||
setCollapse({ commit, dispatch }, value) { |
|||
commit('SET', { key: 'collapse', value }); |
|||
dispatch('delayUpdateContentSize', 800); |
|||
}, |
|||
setSideNavCollapse({ commit, dispatch }, value) { |
|||
commit('SET', { key: 'sideNavCollapse', value }); |
|||
dispatch('delayUpdateContentSize', 800); |
|||
}, |
|||
setBodyFullscreen({ commit, dispatch }, value) { |
|||
disableTransition(); |
|||
commit('SET', { key: 'bodyFullscreen', value }); |
|||
dispatch('delayUpdateContentSize', 800); |
|||
}, |
|||
setShowTabs({ commit, dispatch }, value) { |
|||
commit('SET', { key: 'showTabs', value }); |
|||
cacheSetting('showTabs', value); |
|||
dispatch('delayUpdateContentSize'); |
|||
}, |
|||
setShowFooter({ commit, dispatch }, value) { |
|||
commit('SET', { key: 'showFooter', value }); |
|||
cacheSetting('showFooter', value); |
|||
dispatch('delayUpdateContentSize'); |
|||
}, |
|||
setHeadStyle({ commit }, value) { |
|||
commit('SET', { key: 'headStyle', value }); |
|||
cacheSetting('headStyle', value); |
|||
}, |
|||
setSideStyle({ commit }, value) { |
|||
commit('SET', { key: 'sideStyle', value }); |
|||
cacheSetting('sideStyle', value); |
|||
}, |
|||
setLayoutStyle({ commit, dispatch }, value) { |
|||
disableTransition(); |
|||
commit('SET', { key: 'layoutStyle', value }); |
|||
cacheSetting('layoutStyle', value); |
|||
dispatch('delayUpdateContentSize'); |
|||
}, |
|||
setSideMenuStyle({ commit, dispatch }, value) { |
|||
disableTransition(); |
|||
commit('SET', { key: 'sideMenuStyle', value }); |
|||
cacheSetting('sideMenuStyle', value); |
|||
dispatch('delayUpdateContentSize'); |
|||
}, |
|||
setTabStyle({ commit }, value) { |
|||
commit('SET', { key: 'tabStyle', value }); |
|||
cacheSetting('tabStyle', value); |
|||
}, |
|||
setFixedHeader({ commit }, value) { |
|||
disableTransition(); |
|||
commit('SET', { key: 'fixedHeader', value }); |
|||
cacheSetting('fixedHeader', value); |
|||
}, |
|||
setFixedSidebar({ commit }, value) { |
|||
disableTransition(); |
|||
commit('SET', { key: 'fixedSidebar', value }); |
|||
cacheSetting('fixedSidebar', value); |
|||
}, |
|||
setFixedBody({ commit }, value) { |
|||
disableTransition(); |
|||
commit('SET', { key: 'fixedBody', value }); |
|||
cacheSetting('fixedBody', value); |
|||
}, |
|||
setBodyFull({ commit, dispatch }, value) { |
|||
commit('SET', { key: 'bodyFull', value }); |
|||
cacheSetting('bodyFull', value); |
|||
dispatch('delayUpdateContentSize'); |
|||
}, |
|||
setLogoAutoSize({ commit }, value) { |
|||
disableTransition(); |
|||
commit('SET', { key: 'logoAutoSize', value }); |
|||
cacheSetting('logoAutoSize', value); |
|||
}, |
|||
setColorfulIcon({ commit }, value) { |
|||
commit('SET', { key: 'colorfulIcon', value }); |
|||
cacheSetting('colorfulIcon', value); |
|||
}, |
|||
setSideUniqueOpen({ commit }, value) { |
|||
commit('SET', { key: 'sideUniqueOpen', value }); |
|||
cacheSetting('sideUniqueOpen', value); |
|||
}, |
|||
setWeakMode({ commit }, value) { |
|||
return new Promise((resolve) => { |
|||
changeWeakMode(value); |
|||
commit('SET', { key: 'weakMode', value }); |
|||
cacheSetting('weakMode', value); |
|||
resolve(); |
|||
}); |
|||
}, |
|||
setDarkMode({ commit, state }, value) { |
|||
return new Promise((resolve, reject) => { |
|||
changeTheme(state.color, value) |
|||
.then(() => { |
|||
commit('SET', { key: 'darkMode', value }); |
|||
cacheSetting('darkMode', value); |
|||
resolve(); |
|||
}) |
|||
.catch((e) => { |
|||
reject(e); |
|||
}); |
|||
}); |
|||
}, |
|||
setColor({ commit, state }, value) { |
|||
return new Promise((resolve, reject) => { |
|||
changeTheme(value, state.darkMode) |
|||
.then(() => { |
|||
commit('SET', { key: 'color', value }); |
|||
cacheSetting('color', value); |
|||
resolve(); |
|||
}) |
|||
.catch((e) => { |
|||
reject(e); |
|||
}); |
|||
}); |
|||
}, |
|||
// 设置主页对应的组件
|
|||
setHomeComponents({ commit }, value) { |
|||
commit('SET', { key: 'homeComponents', value }); |
|||
}, |
|||
// 设置刷新路由信息
|
|||
setRouteReload({ commit }, value) { |
|||
commit('SET', { key: 'routeReload', value }); |
|||
}, |
|||
// 更新屏幕尺寸
|
|||
updateScreenSize({ commit, dispatch }) { |
|||
commit('SET', { key: 'screenWidth', value: screenWidth() }); |
|||
commit('SET', { key: 'screenHeight', value: screenHeight() }); |
|||
dispatch('updateContentSize'); |
|||
}, |
|||
// 更新内容区域尺寸
|
|||
updateContentSize({ commit }) { |
|||
commit('SET', { key: 'contentWidth', value: contentWidth() }); |
|||
commit('SET', { key: 'contentHeight', value: contentHeight() }); |
|||
}, |
|||
// 延时更新内容区域尺寸
|
|||
delayUpdateContentSize({ dispatch }, delay) { |
|||
updateContentSizeTimer && clearTimeout(updateContentSizeTimer); |
|||
updateContentSizeTimer = setTimeout(() => { |
|||
dispatch('updateContentSize'); |
|||
}, delay ?? 100); |
|||
}, |
|||
// 重置配置
|
|||
resetSetting({ commit, state }) { |
|||
return new Promise((resolve, reject) => { |
|||
disableTransition(); |
|||
[ |
|||
'showTabs', |
|||
'showFooter', |
|||
'headStyle', |
|||
'sideStyle', |
|||
'layoutStyle', |
|||
'sideMenuStyle', |
|||
'tabStyle', |
|||
'fixedHeader', |
|||
'fixedSidebar', |
|||
'fixedBody', |
|||
'bodyFull', |
|||
'logoAutoSize', |
|||
'colorfulIcon', |
|||
'sideUniqueOpen', |
|||
'weakMode', |
|||
'darkMode', |
|||
'color' |
|||
].forEach((key) => { |
|||
commit('SET', { key, value: DEFAULT_STATE[key] }); |
|||
}); |
|||
localStorage.removeItem(THEME_STORE_NAME); |
|||
changeWeakMode(state.weakMode); |
|||
changeTheme(state.color, state.darkMode) |
|||
.then(() => { |
|||
resolve(); |
|||
}) |
|||
.catch((e) => { |
|||
reject(e); |
|||
}); |
|||
}); |
|||
}, |
|||
// 恢复主题
|
|||
recoverTheme({ state }) { |
|||
// 恢复色弱模式
|
|||
if (state.weakMode) { |
|||
changeWeakMode(true); |
|||
} |
|||
|
|||
/** |
|||
* 移除主题 |
|||
*/ |
|||
function removeTheme() { |
|||
const sel = 'style[id^="ele-theme-"],link[id^="ele-theme-"]'; |
|||
document.head.querySelectorAll(sel).forEach(elem => { |
|||
elem.parentNode.removeChild(elem); |
|||
// 恢复主题色
|
|||
if (state.color || state.darkMode) { |
|||
changeTheme(state.color, state.darkMode).catch((e) => { |
|||
console.error(e); |
|||
}); |
|||
} |
|||
}, |
|||
// 添加页签
|
|||
tabAdd({ dispatch, state }, data) { |
|||
if (Array.isArray(data)) { |
|||
data.forEach((d) => { |
|||
dispatch('tabAdd', d); |
|||
}); |
|||
return; |
|||
} |
|||
const i = state.tabs.findIndex((d) => d.key === data.key); |
|||
if (i === -1) { |
|||
dispatch('setTabs', state.tabs.concat([data])); |
|||
} else if (data.fullPath !== state.tabs[i].fullPath) { |
|||
dispatch( |
|||
'setTabs', |
|||
state.tabs |
|||
.slice(0, i) |
|||
.concat([data]) |
|||
.concat(state.tabs.slice(i + 1)) |
|||
); |
|||
} |
|||
}, |
|||
// 关闭页签
|
|||
tabRemove({ dispatch, state }, key) { |
|||
return new Promise((resolve) => { |
|||
let index = -1; |
|||
let lastIndex = -1; |
|||
let last; |
|||
let lastPath; |
|||
for (let i = 0; i < state.tabs.length; i++) { |
|||
const t = state.tabs[i]; |
|||
if (t.closable && (t.key === key || t.fullPath === key)) { |
|||
index = i; |
|||
break; |
|||
} |
|||
lastIndex = i; |
|||
last = state.tabs[i]; |
|||
lastPath = last.fullPath; |
|||
} |
|||
dispatch( |
|||
'setTabs', |
|||
state.tabs.filter((_d, i) => i !== index) |
|||
); |
|||
resolve({ lastIndex, lastPath, last }); |
|||
}); |
|||
}, |
|||
// 关闭全部页签
|
|||
tabRemoveAll({ dispatch, state }, active) { |
|||
return new Promise((resolve) => { |
|||
const tab = state.tabs.find((d) => d.key === active); |
|||
const stay = active ? !!(tab && tab.closable === false) : false; |
|||
dispatch( |
|||
'setTabs', |
|||
state.tabs.filter((d) => !d.closable) |
|||
); |
|||
resolve(stay); |
|||
}); |
|||
}, |
|||
// 关闭左侧页签
|
|||
tabRemoveLeft({ dispatch, state }, key) { |
|||
for (let i = 0; i < state.tabs.length; i++) { |
|||
if (state.tabs[i].key === key) { |
|||
dispatch( |
|||
'setTabs', |
|||
state.tabs |
|||
.filter((d, j) => !d.closable && j < i) |
|||
.concat(state.tabs.slice(i)) |
|||
); |
|||
break; |
|||
} |
|||
} |
|||
}, |
|||
// 关闭右侧页签
|
|||
tabRemoveRight({ dispatch, state }, key) { |
|||
for (let i = 0; i < state.tabs.length; i++) { |
|||
if (state.tabs[i].key === key) { |
|||
dispatch( |
|||
'setTabs', |
|||
state.tabs |
|||
.slice(0, i + 1) |
|||
.concat(state.tabs.filter((d, j) => !d.closable && j > i)) |
|||
); |
|||
break; |
|||
} |
|||
} |
|||
}, |
|||
// 关闭其它页签
|
|||
tabRemoveOther({ dispatch, state }, key) { |
|||
dispatch( |
|||
'setTabs', |
|||
state.tabs.filter((d) => !d.closable || d.key === key) |
|||
); |
|||
}, |
|||
// 修改页签
|
|||
tabSetItem({ dispatch, state }, data) { |
|||
let i = -1; |
|||
if (data.key) { |
|||
i = state.tabs.findIndex((d) => d.key === data.key); |
|||
} else if (data.fullPath) { |
|||
i = state.tabs.findIndex((d) => d.fullPath === data.fullPath); |
|||
} else if (data.path) { |
|||
i = state.tabs.findIndex((d) => d.path === data.path); |
|||
} |
|||
if (i !== -1) { |
|||
const item = Object.assign({}, state.tabs[i]); |
|||
if (data.title) { |
|||
item.title = data.title; |
|||
} |
|||
if (typeof data.closable === 'boolean') { |
|||
item.closable = data.closable; |
|||
} |
|||
if (data.components) { |
|||
item.components = data.components; |
|||
} |
|||
dispatch( |
|||
'setTabs', |
|||
state.tabs |
|||
.slice(0, i) |
|||
.concat([item]) |
|||
.concat(state.tabs.slice(i + 1)) |
|||
); |
|||
} |
|||
} |
|||
} |
|||
}; |
|||
|
|||
@ -1,259 +1,91 @@ |
|||
/** |
|||
* 登录状态管理 |
|||
*/ |
|||
import axios from 'axios'; |
|||
import {util} from 'ele-admin'; |
|||
import setting from '@/config/setting'; |
|||
import { formatMenus, toTreeData, formatTreeData } from 'ele-admin'; |
|||
import { USER_MENUS } from '@/config/setting'; |
|||
import { getUserInfo } from '@/api/layout'; |
|||
|
|||
export default { |
|||
namespaced: true, |
|||
state: { |
|||
// 当前用户信息
|
|||
user: setting.takeUser(), |
|||
// 当前用户权限
|
|||
authorities: [], |
|||
// 当前用户角色
|
|||
roles: [], |
|||
// 当前用户的菜单
|
|||
// 当前登录用户信息
|
|||
info: null, |
|||
// 当前登录用户的菜单
|
|||
menus: null, |
|||
// 当前打开的选项卡
|
|||
tabs: [] |
|||
// 当前登录用户的权限
|
|||
authorities: [], |
|||
// 当前登录用户的角色
|
|||
roles: [] |
|||
}, |
|||
mutations: { |
|||
SET: (state, obj) => { |
|||
state[obj.key] = obj.value; |
|||
// 设置登录用户的信息
|
|||
setUserInfo(state, info) { |
|||
state.info = info; |
|||
}, |
|||
SET_TOKEN: (state, obj) => { |
|||
setting.cacheToken(obj.token, obj.remember); |
|||
state.token = obj.token; |
|||
if (!obj.token) { |
|||
state.user = {}; |
|||
state.menus = null; |
|||
state.tabs = []; |
|||
setting.cacheUser(); |
|||
} |
|||
// 设置登录用户的菜单
|
|||
setMenus(state, menus) { |
|||
state.menus = menus; |
|||
}, |
|||
TAB_PUSH(state, obj) { |
|||
if (!state.tabs.some(r => r.path === obj.path)) { |
|||
state.tabs.push(obj); |
|||
} |
|||
} |
|||
// 设置登录用户的权限
|
|||
setAuthorities(state, authorities) { |
|||
state.authorities = authorities; |
|||
}, |
|||
actions: { |
|||
/** |
|||
* 缓存token |
|||
* @param commit |
|||
* @param token {String, {token: String, remember: String}} |
|||
*/ |
|||
setToken({commit}, token) { |
|||
let remember = true; |
|||
if (typeof token === 'object') { |
|||
remember = token.remember; |
|||
token = token.token; |
|||
// 设置登录用户的角色
|
|||
setRoles(state, roles) { |
|||
state.roles = roles; |
|||
} |
|||
commit('SET_TOKEN', {token: token, remember: remember}); |
|||
}, |
|||
/** |
|||
* 移除token |
|||
* @param commit |
|||
*/ |
|||
removeToken({commit}) { |
|||
commit('SET_TOKEN', {}); |
|||
}, |
|||
/** |
|||
* 缓存用户信息 |
|||
* @param commit |
|||
* @param user {Object} 用户信息 |
|||
*/ |
|||
setUser({commit}, user) { |
|||
setting.cacheUser(user); |
|||
commit('SET', {key: 'user', value: user}); |
|||
}, |
|||
/** |
|||
* 设置用户权限 |
|||
* @param commit |
|||
* @param authorities {Array<String>} 权限 |
|||
*/ |
|||
setAuthorities({commit}, authorities) { |
|||
commit('SET', {key: 'authorities', value: authorities}); |
|||
}, |
|||
/** |
|||
* 设置用户角色 |
|||
* @param commit |
|||
* @param roles {Array<String>} 角色 |
|||
*/ |
|||
setRoles({commit}, roles) { |
|||
commit('SET', {key: 'roles', value: roles}); |
|||
}, |
|||
/** |
|||
* 设置用户菜单 |
|||
* @param commit |
|||
* @param menus {Array<Object>} 菜单 |
|||
*/ |
|||
setMenus({commit}, menus) { |
|||
commit('SET', {key: 'menus', value: menus}); |
|||
}, |
|||
/** |
|||
* 获取用户菜单路由 |
|||
* @param commit |
|||
* @returns {Promise<Object>} {menus: Array, home: String} |
|||
*/ |
|||
getMenus({commit}) { |
|||
return new Promise((resolve, reject) => { |
|||
if (!setting.menuUrl) { |
|||
let menus = setting.menus || []; |
|||
commit('SET', {key: 'menus', value: menus}); |
|||
return resolve({menus: menus}); |
|||
} |
|||
axios.get(setting.menuUrl).then(res => { |
|||
let result = setting.parseMenu ? setting.parseMenu(res.data) : res.data; |
|||
let menus = result.data, home = null; |
|||
if (!menus) { |
|||
return reject(new Error(result.msg)); |
|||
} |
|||
util.eachTreeData(menus, item => { |
|||
if (setting.parseMenuItem) { |
|||
item = setting.parseMenuItem(item); |
|||
} |
|||
item.meta = Object.assign({ |
|||
title: item.title, |
|||
icon: item.icon, |
|||
hide: item.hide, |
|||
active: item.active || item.uid, |
|||
hideFooter: item.hideFooter |
|||
}, item.meta); |
|||
if (!item.children || !item.children.length) { |
|||
if (!home && item.path && !( |
|||
item.path.startsWith('http://') || |
|||
item.path.startsWith('https://') || |
|||
item.path.startsWith('//') |
|||
)) { |
|||
home = item.path; |
|||
if (!setting.homeTitle) { |
|||
setting.homeTitle = item.title; |
|||
} |
|||
} |
|||
} else if (item.children[0].path) { |
|||
if (!item.redirect) { |
|||
item.redirect = item.children[0].path; |
|||
} |
|||
if (!item.path) { |
|||
const cp = item.children[0].path; |
|||
item.path = cp.substring(0, cp.lastIndexOf('/')); |
|||
} |
|||
} |
|||
}); |
|||
commit('SET', {key: 'menus', value: menus}); |
|||
resolve({menus: menus, home: home}); |
|||
}).catch(e => { |
|||
reject(e); |
|||
}); |
|||
}); |
|||
}, |
|||
/** |
|||
* 添加新tab |
|||
* @param commit |
|||
* @param obj {{path: String, title: String}} tab信息 |
|||
*/ |
|||
tabAdd({commit}, obj) { |
|||
commit('TAB_PUSH', obj); |
|||
}, |
|||
/** |
|||
* 关闭指定tab |
|||
* @param commit |
|||
* @param state |
|||
* @param path {String} tab路由 |
|||
* @returns {Promise<Number>} 前一个tab位置 |
|||
*/ |
|||
tabRemove({commit, state}, path) { |
|||
return new Promise((resolve) => { |
|||
let lastIndex = -1, lastPath, last; |
|||
for (let i = 0; i < state.tabs.length; i++) { |
|||
if (state.tabs[i].path === path) { |
|||
break; |
|||
} |
|||
lastIndex = i; |
|||
last = state.tabs[i]; |
|||
lastPath = last.path; |
|||
} |
|||
commit('SET', { |
|||
key: 'tabs', |
|||
value: state.tabs.filter(d => d.path !== path) |
|||
}); |
|||
resolve({ |
|||
lastIndex: lastIndex, |
|||
lastPath: lastPath, |
|||
last: last |
|||
}); |
|||
}); |
|||
}, |
|||
actions: { |
|||
/** |
|||
* 关闭所有tab |
|||
* @param commit |
|||
* 请求用户信息、权限、角色、菜单 |
|||
*/ |
|||
tabRemoveAll({commit}) { |
|||
commit('SET', {key: 'tabs', value: []}); |
|||
async fetchUserInfo({ commit }) { |
|||
const result = await getUserInfo(); |
|||
// 用户信息
|
|||
commit('setUserInfo', result); |
|||
// 用户权限
|
|||
const authorities = |
|||
result.authorities |
|||
?.filter((d) => !!d.authority) |
|||
?.map((d) => d.authority) ?? []; |
|||
commit('setAuthorities', authorities); |
|||
// 用户角色
|
|||
const roles = result.roles?.map((d) => d.roleCode) ?? []; |
|||
commit('setRoles', roles); |
|||
// 用户菜单, 过滤掉按钮类型并转为children形式
|
|||
const { menus, homePath } = formatMenus( |
|||
USER_MENUS ?? |
|||
toTreeData({ |
|||
data: result.authorities?.filter((d) => d.menuType === 0), |
|||
idField: 'menuId', |
|||
parentIdField: 'parentId' |
|||
}) |
|||
); |
|||
commit('setMenus', menus); |
|||
return { menus, homePath }; |
|||
}, |
|||
/** |
|||
* 关闭左侧tab |
|||
* @param commit |
|||
* @param state |
|||
* @param path {String} tab路由 |
|||
* 更新用户信息 |
|||
*/ |
|||
tabRemoveLeft({commit, state}, path) { |
|||
for (let i = 0; i < state.tabs.length; i++) { |
|||
if (state.tabs[i].path === path) { |
|||
commit('SET', { |
|||
key: 'tabs', |
|||
value: state.tabs.slice(i) |
|||
}); |
|||
break; |
|||
} |
|||
} |
|||
setInfo({ commit }, value) { |
|||
commit('setUserInfo', value); |
|||
}, |
|||
/** |
|||
* 关闭右侧tab |
|||
* @param commit |
|||
* @param state |
|||
* @param path {String} tab路由 |
|||
* 更新菜单的badge |
|||
*/ |
|||
tabRemoveRight({commit, state}, path) { |
|||
for (let i = 0; i < state.tabs.length; i++) { |
|||
if (state.tabs[i].path === path) { |
|||
commit('SET', { |
|||
key: 'tabs', |
|||
value: state.tabs.slice(0, i + 1) |
|||
setMenuBadge({ commit, state }, { path, value, color }) { |
|||
const menus = formatTreeData(state.menus, (m) => { |
|||
if (path === m.path) { |
|||
return Object.assign({}, m, { |
|||
meta: Object.assign({}, m.meta, { |
|||
badge: value, |
|||
badgeColor: color |
|||
}) |
|||
}); |
|||
break; |
|||
} |
|||
} |
|||
}, |
|||
/** |
|||
* 关闭其他tab |
|||
* @param commit |
|||
* @param state |
|||
* @param path {String} tab路由 |
|||
*/ |
|||
tabRemoveOther({commit, state}, path) { |
|||
commit('SET', { |
|||
key: 'tabs', |
|||
value: state.tabs.filter(d => d.path === path) |
|||
return m; |
|||
}); |
|||
}, |
|||
/** |
|||
* 修改指定tab标题 |
|||
* @param commit |
|||
* @param state |
|||
* @param obj {{path: String, title: String}} |
|||
*/ |
|||
tabSetTitle({commit, state}, obj) { |
|||
let i = state.tabs.findIndex(d => d.path === obj.path); |
|||
let tabs = state.tabs.slice(0, i).concat([ |
|||
Object.assign({}, state.tabs[i], { |
|||
title: obj.title |
|||
}) |
|||
]).concat(state.tabs.slice(i + 1)); |
|||
commit('SET', {key: 'tabs', value: tabs}); |
|||
} |
|||
commit('setMenus', menus); |
|||
} |
|||
} |
|||
}; |
|||
|
|||
@ -1,63 +1,9 @@ |
|||
/** 如果需要自己定义一些全局样式写在这里 */ |
|||
|
|||
$--ele-font-path: "~ele-admin/packages/style/fonts"; |
|||
|
|||
@import "./var.scss"; |
|||
@import "~ele-admin/packages/style/index.scss"; |
|||
|
|||
/* 异常页面 */ |
|||
.ele-exception { |
|||
margin: 145px 0; |
|||
|
|||
.ele-exception-img, |
|||
.ele-exception-content { |
|||
margin: 15px 30px; |
|||
display: inline-block; |
|||
vertical-align: middle; |
|||
} |
|||
|
|||
.ele-exception-content > h1 { |
|||
font-size: 72px; |
|||
font-weight: 600; |
|||
margin: 0 0 20px 0; |
|||
} |
|||
|
|||
&:not(.ele-exception-dark) .ele-exception-content > h1 { |
|||
color: #515A6E; |
|||
} |
|||
|
|||
.ele-exception-content > p { |
|||
font-size: 20px; |
|||
margin: 0 0 25px 0; |
|||
} |
|||
|
|||
&:not(.ele-exception-dark) .ele-exception-content > p { |
|||
color: #808695; |
|||
} |
|||
|
|||
&.ele-exception-dark .ele-exception-img { |
|||
opacity: .7; |
|||
} |
|||
} |
|||
|
|||
@media screen and (max-width: 768px) { |
|||
.ele-exception { |
|||
margin: 40px 0; |
|||
|
|||
.ele-exception-img { |
|||
margin: 0; |
|||
|
|||
img { |
|||
max-height: 200px; |
|||
} |
|||
} |
|||
|
|||
.ele-exception-content { |
|||
text-align: center; |
|||
} |
|||
} |
|||
} |
|||
//表格不对齐bug |
|||
.el-table th.gutter { |
|||
display: table-cell !important; |
|||
} |
|||
/** 全局样式 */ |
|||
// 如果需要覆盖更多样式变量请查看文档 |
|||
$--ele-font-path: '~ele-admin/es/style/fonts'; |
|||
// 如果不需要切换主题固定为夜间主题使用这个 |
|||
//@import "~ele-admin/es/style/themes/dark.scss"; |
|||
// 需要在线切换主题使用这个 |
|||
@import '~ele-admin/es/style/themes/dynamic.scss'; |
|||
// 全局引入样式 |
|||
@import '~ele-admin/es/style/index.scss'; |
|||
|
|||
@ -1,5 +0,0 @@ |
|||
/** 明青主题暗黑 */ |
|||
|
|||
$--color-primary: #2BCCCE; |
|||
|
|||
@import "./dark.scss"; |
|||
@ -1,6 +0,0 @@ |
|||
/** 明青主题 */ |
|||
|
|||
$--color-primary: #2BCCCE; |
|||
|
|||
@import "../var.scss"; |
|||
@import "~ele-admin/packages/style/themes/default.scss"; |
|||
@ -1,4 +0,0 @@ |
|||
/** 暗黑主题 */ |
|||
|
|||
@import "../var.scss"; |
|||
@import "~ele-admin/packages/style/themes/dark.scss"; |
|||
@ -1,5 +0,0 @@ |
|||
/** 薄暮主题暗黑 */ |
|||
|
|||
$--color-primary: #5F80C7; |
|||
|
|||
@import "./dark.scss"; |
|||
@ -1,6 +0,0 @@ |
|||
/** 薄暮主题 */ |
|||
|
|||
$--color-primary: #5F80C7; |
|||
|
|||
@import "../var.scss"; |
|||
@import "~ele-admin/packages/style/themes/default.scss"; |
|||
@ -1,5 +0,0 @@ |
|||
/** 极客蓝主题暗黑 */ |
|||
|
|||
$--color-primary: #32A2D4; |
|||
|
|||
@import "./dark.scss"; |
|||
@ -1,6 +0,0 @@ |
|||
/** 极客蓝主题 */ |
|||
|
|||
$--color-primary: #32A2D4; |
|||
|
|||
@import "../var.scss"; |
|||
@import "~ele-admin/packages/style/themes/default.scss"; |
|||
@ -1,5 +0,0 @@ |
|||
/** 极光绿主题暗黑 */ |
|||
|
|||
$--color-primary: #33CC99; |
|||
|
|||
@import "./dark.scss"; |
|||
@ -1,6 +0,0 @@ |
|||
/** 极光绿主题 */ |
|||
|
|||
$--color-primary: #33CC99; |
|||
|
|||
@import "../var.scss"; |
|||
@import "~ele-admin/packages/style/themes/default.scss"; |
|||
@ -1,5 +0,0 @@ |
|||
/** 酱紫主题暗黑 */ |
|||
|
|||
$--color-primary: #9266F9; |
|||
|
|||
@import "./dark.scss"; |
|||
@ -1,6 +0,0 @@ |
|||
/** 酱紫主题 */ |
|||
|
|||
$--color-primary: #9266F9; |
|||
|
|||
@import "../var.scss"; |
|||
@import "~ele-admin/packages/style/themes/default.scss"; |
|||
@ -1,5 +0,0 @@ |
|||
/** 日暮主题暗黑 */ |
|||
|
|||
$--color-primary: #FAAD14; |
|||
|
|||
@import "./dark.scss"; |
|||
@ -1,6 +0,0 @@ |
|||
/** 日暮主题 */ |
|||
|
|||
$--color-primary: #FAAD14; |
|||
|
|||
@import "../var.scss"; |
|||
@import "~ele-admin/packages/style/themes/default.scss"; |
|||
@ -1,5 +0,0 @@ |
|||
/** 火山主题暗黑 */ |
|||
|
|||
$--color-primary: #F5686F; |
|||
|
|||
@import "./dark.scss"; |
|||
@ -1,6 +0,0 @@ |
|||
/** 火山主题 */ |
|||
|
|||
$--color-primary: #F5686F; |
|||
|
|||
@import "../var.scss"; |
|||
@import "~ele-admin/packages/style/themes/default.scss"; |
|||
@ -1,2 +0,0 @@ |
|||
/** 如果需要覆盖框架样式变量写在这里 */ |
|||
$--sidebar-width: 220px; // 侧边栏宽度 |
|||
@ -0,0 +1,39 @@ |
|||
/** |
|||
* echarts混入 |
|||
*/ |
|||
import store from '@/store'; |
|||
import { THEME_KEY } from 'vue-echarts'; |
|||
import { ChartTheme } from 'ele-admin'; |
|||
|
|||
export function echartsMixin(refs) { |
|||
return { |
|||
provide: { |
|||
// 主题设置
|
|||
[THEME_KEY]: ChartTheme |
|||
}, |
|||
computed: { |
|||
// 内容区域宽度
|
|||
layoutContentWidth() { |
|||
return store?.state?.theme?.contentWidth; |
|||
} |
|||
}, |
|||
watch: { |
|||
// 监听内容区域宽度变化
|
|||
layoutContentWidth() { |
|||
this.resizeAllCharts(); |
|||
} |
|||
}, |
|||
// 适配keep-alive
|
|||
activated() { |
|||
this.resizeAllCharts(); |
|||
}, |
|||
methods: { |
|||
// 重置echarts尺寸
|
|||
resizeAllCharts() { |
|||
refs.forEach((ref) => { |
|||
this.$refs[ref]?.resize(); |
|||
}); |
|||
} |
|||
} |
|||
}; |
|||
} |
|||
@ -0,0 +1,128 @@ |
|||
/** |
|||
* 页签操作封装 |
|||
*/ |
|||
import store from '@/store'; |
|||
import router from '@/router'; |
|||
import { HOME_PATH, REDIRECT_PATH } from '@/config/setting'; |
|||
import { removeToken } from '@/utils/token-util'; |
|||
const BASE_URL = process.env.BASE_URL; |
|||
const HOME_ROUTE = HOME_PATH || '/'; |
|||
|
|||
/** |
|||
* 刷新当前路由 |
|||
*/ |
|||
export function reloadPageTab() { |
|||
const { path, fullPath, query, meta, matched } = router.currentRoute; |
|||
if (path.includes(REDIRECT_PATH)) { |
|||
return; |
|||
} |
|||
const { isHome } = meta; |
|||
setRouteReload({ |
|||
reloadHome: isHome, |
|||
reloadPath: isHome ? undefined : fullPath |
|||
}).then(() => { |
|||
router.replace({ |
|||
path: matched[matched.length - 2].path + REDIRECT_PATH + path, |
|||
query |
|||
}); |
|||
}); |
|||
} |
|||
|
|||
/** |
|||
* 关闭当前页签 |
|||
*/ |
|||
export function finishPageTab() { |
|||
const { fullPath } = router.currentRoute; |
|||
removePageTab({ key: fullPath, active: fullPath }); |
|||
} |
|||
|
|||
/** |
|||
* 关闭页签 |
|||
* @param key 页签的key |
|||
* @param active 选中页签的key |
|||
*/ |
|||
export function removePageTab({ key, active }) { |
|||
store.dispatch('theme/tabRemove', key).then(({ lastPath }) => { |
|||
if (active && key === active) { |
|||
router.push(lastPath || HOME_ROUTE); |
|||
} |
|||
}); |
|||
} |
|||
|
|||
/** |
|||
* 关闭全部页签 |
|||
*/ |
|||
export function removeAllPageTab(active) { |
|||
store.dispatch('theme/tabRemoveAll', active).then((stay) => { |
|||
if (!stay && active && active !== HOME_ROUTE) { |
|||
router.push(HOME_ROUTE); |
|||
} |
|||
}); |
|||
} |
|||
|
|||
/** |
|||
* 关闭左侧页签 |
|||
*/ |
|||
export function removeLeftPageTab(key) { |
|||
return store.dispatch('theme/tabRemoveLeft', key); |
|||
} |
|||
|
|||
/** |
|||
* 关闭右侧页签 |
|||
*/ |
|||
export function removeRightPageTab(key) { |
|||
return store.dispatch('theme/tabRemoveRight', key); |
|||
} |
|||
|
|||
/** |
|||
* 关闭其它页签 |
|||
*/ |
|||
export function removeOtherPageTab(key) { |
|||
return store.dispatch('theme/tabRemoveOther', key); |
|||
} |
|||
|
|||
/** |
|||
* 添加页签 |
|||
*/ |
|||
export function addPageTab(data) { |
|||
return store.dispatch('theme/tabAdd', data); |
|||
} |
|||
|
|||
/** |
|||
* 修改页签 |
|||
*/ |
|||
export function setPageTab(data) { |
|||
return store.dispatch('theme/tabSetItem', data); |
|||
} |
|||
|
|||
/** |
|||
* 设置主页的组件名称 |
|||
*/ |
|||
export function setHomeComponents(data) { |
|||
return store.dispatch('theme/setHomeComponents', data); |
|||
} |
|||
|
|||
/** |
|||
* 设置路由刷新信息 |
|||
*/ |
|||
export function setRouteReload(value) { |
|||
return store.dispatch('theme/setRouteReload', value); |
|||
} |
|||
|
|||
/** |
|||
* 退出登录 |
|||
* @param from 是否使用路由跳转 |
|||
* @param from 登录后跳转的地址 |
|||
*/ |
|||
export function logout(route, from) { |
|||
removeToken(); |
|||
if (route) { |
|||
router.push({ |
|||
path: '/login', |
|||
query: from ? { from } : undefined |
|||
}); |
|||
} else { |
|||
// 这样跳转避免再次登录重复注册动态路由
|
|||
location.replace(BASE_URL + 'login' + (from ? '?from=' + from : '')); |
|||
} |
|||
} |
|||
@ -1,128 +1,114 @@ |
|||
/** |
|||
* 权限、角色控制组件 |
|||
* 按钮级权限控制 |
|||
*/ |
|||
import store from '@/store'; |
|||
|
|||
export default { |
|||
install(Vue) { |
|||
// 添加全局方法
|
|||
Vue.prototype.$hasRole = this.hasRole; |
|||
Vue.prototype.$hasAnyRole = this.hasAnyRole; |
|||
Vue.prototype.$hasPermission = this.hasPermission; |
|||
Vue.prototype.$hasAnyPermission = this.hasAnyPermission; |
|||
|
|||
// 添加自定义指令
|
|||
Vue.directive('role', { |
|||
inserted: (el, binding) => { |
|||
if (!this.hasRole(binding.value)) { |
|||
el.parentNode && el.parentNode.removeChild(el); |
|||
/* 数组是否有某些值 */ |
|||
const arrayHas = function (array, value) { |
|||
if (!value) { |
|||
return true; |
|||
} |
|||
if (!array) { |
|||
return false; |
|||
} |
|||
}); |
|||
Vue.directive('any-role', { |
|||
inserted: (el, binding) => { |
|||
if (!this.hasAnyRole(binding.value)) { |
|||
el.parentNode && el.parentNode.removeChild(el); |
|||
if (Array.isArray(value)) { |
|||
for (let i = 0; i < value.length; i++) { |
|||
if (array.indexOf(value[i]) === -1) { |
|||
return false; |
|||
} |
|||
} |
|||
}); |
|||
Vue.directive('permission', { |
|||
inserted: (el, binding) => { |
|||
if (!this.hasPermission(binding.value)) { |
|||
el.parentNode && el.parentNode.removeChild(el); |
|||
return true; |
|||
} |
|||
return array.indexOf(value) !== -1; |
|||
}; |
|||
|
|||
/* 数组是否有任意值 */ |
|||
const arrayHasAny = function (array, value) { |
|||
if (!value) { |
|||
return true; |
|||
} |
|||
}); |
|||
Vue.directive('any-permission', { |
|||
inserted: (el, binding) => { |
|||
if (!this.hasAnyPermission(binding.value)) { |
|||
el.parentNode && el.parentNode.removeChild(el); |
|||
if (!array) { |
|||
return false; |
|||
} |
|||
if (Array.isArray(value)) { |
|||
for (let i = 0; i < value.length; i++) { |
|||
if (array.indexOf(value[i]) !== -1) { |
|||
return true; |
|||
} |
|||
}); |
|||
}, |
|||
} |
|||
return false; |
|||
} |
|||
return array.indexOf(value) !== -1; |
|||
}; |
|||
|
|||
/** |
|||
* 是否有某些角色 |
|||
* @param role {String, Array<String>} 角色字符或字符数组 |
|||
* @returns {boolean} |
|||
* @param value 角色字符或字符数组 |
|||
*/ |
|||
hasRole(role) { |
|||
const data = store.state.user ? store.state.user.roles : null; |
|||
return arrayHas(data, role); |
|||
}, |
|||
export function hasRole(value) { |
|||
return arrayHas(store.state.user?.roles, value); |
|||
} |
|||
|
|||
/** |
|||
* 是否有任意角色 |
|||
* @param role {String, Array<String>} 角色字符或字符数组 |
|||
* @returns {boolean} |
|||
* @param value 角色字符或字符数组 |
|||
*/ |
|||
hasAnyRole(role) { |
|||
const data = store.state.user ? store.state.user.roles : null; |
|||
return arrayHasAny(data, role); |
|||
}, |
|||
export function hasAnyRole(value) { |
|||
return arrayHasAny(store.state.user?.roles, value); |
|||
} |
|||
|
|||
/** |
|||
* 是否有某些权限 |
|||
* @param auth {String, Array<String>} 权限字符或字符数组 |
|||
* @returns {boolean} |
|||
* @param value 权限字符或字符数组 |
|||
*/ |
|||
hasPermission(auth) { |
|||
const data = store.state.user ? store.state.user.authorities : null; |
|||
return arrayHas(data, auth); |
|||
}, |
|||
/** |
|||
* 是否有任意权限 |
|||
* @param auth {String, Array<String>} 权限字符或字符数组 |
|||
* @returns {boolean} |
|||
*/ |
|||
hasAnyPermission(auth) { |
|||
const data = store.state.user ? store.state.user.authorities : null; |
|||
return arrayHasAny(data, auth); |
|||
} |
|||
export function hasPermission(value) { |
|||
return arrayHas(store.state.user?.authorities, value); |
|||
} |
|||
|
|||
/** |
|||
* 数组是否有某些值 |
|||
* @param array {Array<String>} 数组 |
|||
* @param obj {String, Array<String>} 值 |
|||
* @returns {boolean} |
|||
* 是否有任意权限 |
|||
* @param value 权限字符或字符数组 |
|||
*/ |
|||
function arrayHas(array, obj) { |
|||
if (!obj) { |
|||
return true; |
|||
} |
|||
if (!array) { |
|||
return false; |
|||
} |
|||
if (Array.isArray(obj)) { |
|||
for (let i = 0; i < obj.length; i++) { |
|||
if (array.indexOf(obj[i]) === -1) { |
|||
return false; |
|||
export function hasAnyPermission(value) { |
|||
return arrayHasAny(store.state.user?.authorities, value); |
|||
} |
|||
|
|||
export default { |
|||
install(Vue) { |
|||
// 添加全局方法
|
|||
Vue.prototype.$hasRole = hasRole; |
|||
Vue.prototype.$hasAnyRole = hasAnyRole; |
|||
Vue.prototype.$hasPermission = hasPermission; |
|||
Vue.prototype.$hasAnyPermission = hasAnyPermission; |
|||
|
|||
// 添加自定义指令
|
|||
Vue.directive('role', { |
|||
inserted: (el, binding) => { |
|||
if (!hasRole(binding.value)) { |
|||
el.parentNode && el.parentNode.removeChild(el); |
|||
} |
|||
return true; |
|||
} |
|||
return array.indexOf(obj) !== -1; |
|||
}); |
|||
Vue.directive('any-role', { |
|||
inserted: (el, binding) => { |
|||
if (!hasAnyRole(binding.value)) { |
|||
el.parentNode && el.parentNode.removeChild(el); |
|||
} |
|||
|
|||
/** |
|||
* 数组是否有任意值 |
|||
* @param array {Array<String>} 数组 |
|||
* @param obj {String, Array<String>} 值 |
|||
* @returns {boolean} |
|||
*/ |
|||
function arrayHasAny(array, obj) { |
|||
if (!obj) { |
|||
return true; |
|||
} |
|||
if (!array) { |
|||
return false; |
|||
}); |
|||
Vue.directive('permission', { |
|||
inserted: (el, binding) => { |
|||
if (!hasPermission(binding.value)) { |
|||
el.parentNode && el.parentNode.removeChild(el); |
|||
} |
|||
if (Array.isArray(obj)) { |
|||
for (let i = 0; i < obj.length; i++) { |
|||
if (array.indexOf(obj[i]) !== -1) { |
|||
return true; |
|||
} |
|||
}); |
|||
Vue.directive('any-permission', { |
|||
inserted: (el, binding) => { |
|||
if (!hasAnyPermission(binding.value)) { |
|||
el.parentNode && el.parentNode.removeChild(el); |
|||
} |
|||
return false; |
|||
} |
|||
return array.indexOf(obj) !== -1; |
|||
}); |
|||
} |
|||
}; |
|||
|
|||
@ -0,0 +1,65 @@ |
|||
/** |
|||
* axios实例 |
|||
*/ |
|||
import axios from 'axios'; |
|||
import router from '@/router'; |
|||
import { MessageBox } from 'element-ui'; |
|||
import { API_BASE_URL, TOKEN_HEADER_NAME } from '@/config/setting'; |
|||
import { getToken, setToken } from './token-util'; |
|||
import { logout } from './page-tab-util'; |
|||
|
|||
const service = axios.create({ |
|||
baseURL: API_BASE_URL |
|||
}); |
|||
|
|||
// 添加请求拦截器
|
|||
service.interceptors.request.use( |
|||
(config) => { |
|||
// 添加token到header
|
|||
const token = getToken(); |
|||
if (token && config.headers) { |
|||
config.headers.common[TOKEN_HEADER_NAME] = token; |
|||
} |
|||
return config; |
|||
}, |
|||
(error) => { |
|||
return Promise.reject(error); |
|||
} |
|||
); |
|||
|
|||
// 添加响应拦截器
|
|||
service.interceptors.response.use( |
|||
(res) => { |
|||
// 登录过期处理
|
|||
if (res.data?.code === 401) { |
|||
const currentPath = router.currentRoute.path; |
|||
if (currentPath === '/') { |
|||
logout(true); |
|||
} else { |
|||
MessageBox.alert('登录状态已过期, 请退出重新登录!', '系统提示', { |
|||
confirmButtonText: '重新登录', |
|||
callback: (action) => { |
|||
if (action === 'confirm') { |
|||
logout(false, currentPath); |
|||
} |
|||
}, |
|||
beforeClose: () => { |
|||
MessageBox.close(); |
|||
} |
|||
}); |
|||
} |
|||
return Promise.reject(new Error(res.data.message)); |
|||
} |
|||
// token自动续期
|
|||
const token = res.headers[TOKEN_HEADER_NAME.toLowerCase()]; |
|||
if (token) { |
|||
setToken(token); |
|||
} |
|||
return res; |
|||
}, |
|||
(error) => { |
|||
return Promise.reject(error); |
|||
} |
|||
); |
|||
|
|||
export default service; |
|||
Some files were not shown because too many files changed in this diff
Loading…
Reference in new issue