├── .babelrc ├── .editorconfig ├── .eslintignore ├── .eslintrc.js ├── .gitignore ├── .postcssrc.js ├── .travis.yml ├── LICENSE ├── README.md ├── cypress.json ├── package.json ├── public ├── favicon.ico └── index.html ├── src ├── App.vue ├── api │ ├── assets.js │ ├── data.js │ ├── linux.js │ ├── mysql.js │ ├── oracle.js │ ├── redis.js │ ├── routers.js │ ├── system.js │ └── user.js ├── assets │ ├── demo │ │ ├── demo1.jpg │ │ ├── demo2.jpg │ │ └── demo3.jpg │ ├── icons │ │ ├── iconfont.css │ │ ├── iconfont.eot │ │ ├── iconfont.svg │ │ ├── iconfont.ttf │ │ └── iconfont.woff │ └── images │ │ ├── bak │ │ ├── logo-min.jpg │ │ └── logo.jpg │ │ ├── error-page │ │ ├── error-401.svg │ │ ├── error-404.svg │ │ └── error-500.svg │ │ ├── icon-qr-qq-wechat.png │ │ ├── icon-social-bilibili.svg │ │ ├── icon-social-juejin.svg │ │ ├── icon-social-twitter.svg │ │ ├── icon-social-zhihu.svg │ │ ├── login-bg.jpg │ │ ├── logo-min.jpg │ │ └── logo.jpg ├── components │ ├── charts │ │ ├── bar.vue │ │ ├── index.js │ │ ├── line-1.vue │ │ ├── line-2.vue │ │ ├── line-3.vue │ │ ├── line-4.vue │ │ ├── line-5.vue │ │ ├── line-6.vue │ │ ├── pie-3.vue │ │ ├── pie.vue │ │ ├── simpe-pie.vue │ │ └── theme.json │ ├── common-icon │ │ ├── common-icon.vue │ │ └── index.js │ ├── common │ │ ├── common.less │ │ └── util.js │ ├── count-to │ │ ├── count-to-int.vue │ │ ├── count-to.vue │ │ ├── index.js │ │ └── index.less │ ├── icons │ │ ├── icons.vue │ │ └── index.js │ ├── info-card │ │ ├── index.js │ │ └── infor-card.vue │ ├── login-form │ │ ├── index.js │ │ └── login-form.vue │ ├── main │ │ ├── components │ │ │ ├── a-back-top │ │ │ │ ├── index.js │ │ │ │ └── index.vue │ │ │ ├── error-store │ │ │ │ ├── error-store.vue │ │ │ │ └── index.js │ │ │ ├── fullscreen │ │ │ │ ├── fullscreen.vue │ │ │ │ └── index.js │ │ │ ├── header-bar │ │ │ │ ├── custom-bread-crumb │ │ │ │ │ ├── custom-bread-crumb.less │ │ │ │ │ ├── custom-bread-crumb.vue │ │ │ │ │ └── index.js │ │ │ │ ├── header-bar.less │ │ │ │ ├── header-bar.vue │ │ │ │ ├── index.js │ │ │ │ └── sider-trigger │ │ │ │ │ ├── index.js │ │ │ │ │ ├── sider-trigger.less │ │ │ │ │ └── sider-trigger.vue │ │ │ ├── language │ │ │ │ ├── index.js │ │ │ │ └── language.vue │ │ │ ├── side-menu │ │ │ │ ├── collapsed-menu.vue │ │ │ │ ├── index.js │ │ │ │ ├── item-mixin.js │ │ │ │ ├── mixin.js │ │ │ │ ├── side-menu-item.vue │ │ │ │ ├── side-menu.less │ │ │ │ └── side-menu.vue │ │ │ ├── tags-nav │ │ │ │ ├── index.js │ │ │ │ ├── tags-nav.less │ │ │ │ └── tags-nav.vue │ │ │ └── user │ │ │ │ ├── index.js │ │ │ │ ├── user.less │ │ │ │ └── user.vue │ │ ├── index.js │ │ ├── main.less │ │ └── main.vue │ ├── parent-view │ │ ├── index.js │ │ └── parent-view.vue │ └── top-menu │ │ ├── index.js │ │ ├── linux-menu.vue │ │ ├── mysql-menu.vue │ │ ├── oracle-menu.vue │ │ └── redis-menu.vue ├── config │ └── index.js ├── demo │ ├── demo1.jpg │ └── demo2.jpg ├── directive │ ├── directives.js │ ├── index.js │ └── module │ │ ├── clipboard.js │ │ └── draggable.js ├── index.less ├── libs │ ├── api.request.js │ ├── axios.js │ ├── excel.js │ ├── render-dom.js │ ├── router-util.js │ ├── tools.js │ └── util.js ├── locale │ ├── index.js │ └── lang │ │ ├── en-US.js │ │ ├── zh-CN.js │ │ └── zh-TW.js ├── main.js ├── mock │ └── index.js ├── plugin │ ├── error-store │ │ └── index.js │ └── index.js ├── router │ ├── _import_development.js │ ├── _import_production.js │ ├── before-close.js │ ├── index.js │ └── routers.js ├── store │ ├── index.js │ └── module │ │ ├── app.js │ │ └── user.js └── view │ ├── argu-page │ ├── params.vue │ └── query.vue │ ├── assets │ ├── linux-list.vue │ ├── mysql-list.vue │ ├── oracle-list.vue │ └── redis-list.vue │ ├── error-page │ ├── 401.vue │ ├── 404.vue │ ├── 500.vue │ ├── back-btn-group.vue │ ├── error-content.vue │ └── error.less │ ├── linux │ ├── io.vue │ ├── memory.vue │ ├── stat-list.vue │ └── view.vue │ ├── login │ ├── login.less │ └── login.vue │ ├── multilevel │ └── level-2-1.vue │ ├── mysql │ ├── alert-log.vue │ ├── innodb.vue │ ├── myisam.vue │ ├── slowquery-log.vue │ ├── stat-list.vue │ └── view.vue │ ├── oracle │ ├── active-session.vue │ ├── alert-log.vue │ ├── performance.vue │ ├── resource.vue │ ├── stat-list.vue │ ├── table-stats.vue │ ├── tablespace.vue │ ├── temp-tablespace.vue │ ├── top-sql.vue │ ├── undo-tablespace.vue │ └── view.vue │ ├── redis │ ├── alert-log.vue │ ├── clientlist.vue │ ├── command-stats.vue │ ├── config.vue │ ├── immediate-stats.vue │ ├── slowlog.vue │ ├── stat-list.vue │ └── view.vue │ └── system │ ├── alarm-conf.vue │ ├── alarm-info.vue │ ├── home │ ├── home.vue │ └── index.js │ ├── mysql-setup.vue │ ├── oracle-onenode-setup.vue │ ├── oracle-rac-onenode-setup.vue │ └── oracle-rac-setup.vue ├── tests ├── e2e │ ├── .eslintrc │ ├── plugins │ │ └── index.js │ ├── specs │ │ └── test.js │ └── support │ │ ├── commands.js │ │ └── index.js └── unit │ ├── .eslintrc.js │ └── HelloWorld.spec.js ├── vue.config.js └── yarn.lock /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | "@vue/app" 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gumengkai/db_monitor_vue/1c0c8928b2051dc0b8e490bd78ab61574365e033/.eslintignore -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | 'extends': [ 4 | 'plugin:vue/essential', 5 | '@vue/standard' 6 | ], 7 | rules: { 8 | // allow async-await 9 | 'generator-star-spacing': 'off', 10 | // allow debugger during development 11 | 'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off', 12 | 'vue/no-parsing-error': [2, { 13 | 'x-invalid-end-tag': false 14 | }], 15 | 'no-undef': 'off', 16 | 'camelcase': 'off' 17 | }, 18 | parserOptions: { 19 | parser: 'babel-eslint' 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /dist 4 | 5 | package-lock.json 6 | 7 | /tests/e2e/videos/ 8 | /tests/e2e/screenshots/ 9 | 10 | # local env files 11 | .env.local 12 | .env.*.local 13 | 14 | # Log files 15 | npm-debug.log* 16 | yarn-debug.log* 17 | yarn-error.log* 18 | 19 | # Editor directories and files 20 | .idea 21 | .vscode 22 | *.suo 23 | *.ntvs* 24 | *.njsproj 25 | *.sln 26 | *.sw* 27 | 28 | *.history 29 | 30 | index_*.js 31 | .gitignore_* 32 | 33 | build/env.js 34 | -------------------------------------------------------------------------------- /.postcssrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | autoprefixer: {} 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: stable 3 | script: npm run lint 4 | notifications: 5 | email: false 6 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 db_monitor 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## 项目介绍 2 | 3 | > 基于 iview-admin 2.5.0 4 | 5 | 6 | ## 运行 7 | 8 | ```bush 9 | 1. 下载项目源码 10 | git clone https://github.com/gumengkai/db_monitor_vue 11 | 12 | 2. 修改后端API连接地址 13 | src/config/index.js 14 | baseUrl: 15 | dev: 测试 16 | pro: 线上 17 | 示例API地址:47.100.119.84:43278 18 | 19 | 3. 安装依赖包 20 | yarn install 21 | 22 | 4. 开发环境运行 23 | yarn run dev 24 | ``` 25 | 26 | ## DEMO 27 | 28 | > http://122.51.204.250:8080/ 29 | 30 | > 账户 admin 密码 111111 31 | 32 | ![demo1](src/demo/demo1.jpg) 33 | ![demo2](src/demo/demo2.jpg) 34 | 35 | ## 编译 36 | 37 | > dist 38 | 39 | ```bush 40 | yarn build 41 | ``` 42 | 43 | 将dist文件夹部署到nginx即可 44 | -------------------------------------------------------------------------------- /cypress.json: -------------------------------------------------------------------------------- 1 | { 2 | "pluginsFile": "tests/e2e/plugins/index.js" 3 | } 4 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "db_monitor", 3 | "version": "1.0.0", 4 | "author": "gumengkai", 5 | "private": false, 6 | "scripts": { 7 | "dev": "vue-cli-service serve --open", 8 | "build": "vue-cli-service build", 9 | "lint": "eslint --fix --ext .js,.vue src", 10 | "test:unit": "vue-cli-service test:unit", 11 | "test:e2e": "vue-cli-service test:e2e" 12 | }, 13 | "dependencies": { 14 | "axios": "^0.18.0", 15 | "clipboard": "^2.0.0", 16 | "codemirror": "^5.38.0", 17 | "countup": "^1.8.2", 18 | "cropperjs": "^1.2.2", 19 | "dayjs": "^1.7.7", 20 | "echarts": "^4.3.0", 21 | "html2canvas": "^1.0.0-alpha.12", 22 | "iview": "^3.4.0", 23 | "iview-area": "^1.5.17", 24 | "js-cookie": "^2.2.0", 25 | "simplemde": "^1.11.2", 26 | "sortablejs": "^1.7.0", 27 | "tree-table-vue": "^1.1.0", 28 | "v-org-tree": "^1.0.6", 29 | "vue": "^2.5.10", 30 | "vue-i18n": "^7.8.0", 31 | "vue-router": "^3.0.1", 32 | "vuedraggable": "^2.16.0", 33 | "vuex": "^3.0.1", 34 | "wangeditor": "^3.1.1", 35 | "xlsx": "^0.13.3", 36 | "xterm": "^3.14.2" 37 | }, 38 | "devDependencies": { 39 | "@vue/cli-plugin-babel": "^3.0.1", 40 | "@vue/cli-plugin-eslint": "^3.0.1", 41 | "@vue/cli-plugin-unit-mocha": "^3.0.1", 42 | "@vue/cli-service": "^3.0.1", 43 | "@vue/eslint-config-standard": "^3.0.0-beta.10", 44 | "@vue/test-utils": "^1.0.0-beta.10", 45 | "chai": "^4.1.2", 46 | "eslint-plugin-cypress": "^2.0.1", 47 | "less": "^2.7.3", 48 | "less-loader": "^4.0.5", 49 | "lint-staged": "^6.0.0", 50 | "mockjs": "^1.0.1-beta3", 51 | "vue-template-compiler": "^2.5.13" 52 | }, 53 | "browserslist": [ 54 | "> 1%", 55 | "last 2 versions", 56 | "not ie <= 8" 57 | ], 58 | "gitHooks": { 59 | "pre-commit": "lint-staged" 60 | }, 61 | "lint-staged": { 62 | "*.js": [ 63 | "vue-cli-service lint", 64 | "git add" 65 | ], 66 | "*.vue": [ 67 | "vue-cli-service lint", 68 | "git add" 69 | ] 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gumengkai/db_monitor_vue/1c0c8928b2051dc0b8e490bd78ab61574365e033/public/favicon.ico -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 14 |
15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /src/App.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 12 | 13 | 28 | -------------------------------------------------------------------------------- /src/api/assets.js: -------------------------------------------------------------------------------- 1 | import axios from '@/libs/api.request' 2 | 3 | export const getOracleList = parameter => { 4 | return axios.request({ 5 | url: `/assets/api/oracle?${parameter}`, 6 | method: 'get' 7 | }) 8 | } 9 | 10 | export const createOracle = data => { 11 | return axios.request({ 12 | url: '/assets/api/oracle', 13 | data: data, 14 | method: 'post' 15 | }) 16 | } 17 | 18 | export const updateOracle = (id, data) => { 19 | return axios.request({ 20 | url: `/assets/api/oracle/${id}`, 21 | data: data, 22 | method: 'PUT' 23 | }) 24 | } 25 | 26 | export const deleteOracle = id => { 27 | return axios.request({ 28 | url: `/assets/api/oracle/${id}`, 29 | method: 'delete' 30 | }) 31 | } 32 | 33 | export const getMysqlList = parameter => { 34 | return axios.request({ 35 | url: `/assets/api/mysql?${parameter}`, 36 | method: 'get' 37 | }) 38 | } 39 | 40 | export const createMysql = data => { 41 | return axios.request({ 42 | url: '/assets/api/mysql', 43 | data: data, 44 | method: 'post' 45 | }) 46 | } 47 | 48 | export const updateMysql = (id, data) => { 49 | return axios.request({ 50 | url: `/assets/api/mysql/${id}`, 51 | data: data, 52 | method: 'PUT' 53 | }) 54 | } 55 | 56 | export const deleteMysql = id => { 57 | return axios.request({ 58 | url: `/assets/api/mysql/${id}`, 59 | method: 'delete' 60 | }) 61 | } 62 | 63 | export const getLinuxList = parameter => { 64 | return axios.request({ 65 | url: `/assets/api/linux?${parameter}`, 66 | method: 'get' 67 | }) 68 | } 69 | 70 | export const createLinux = data => { 71 | return axios.request({ 72 | url: '/assets/api/linux', 73 | data: data, 74 | method: 'post' 75 | }) 76 | } 77 | 78 | export const updateLinux = (id, data) => { 79 | return axios.request({ 80 | url: `/assets/api/linux/${id}`, 81 | data: data, 82 | method: 'PUT' 83 | }) 84 | } 85 | 86 | export const deleteLinux = id => { 87 | return axios.request({ 88 | url: `/assets/api/linux/${id}`, 89 | method: 'delete' 90 | }) 91 | } 92 | 93 | export const getRedisList = parameter => { 94 | return axios.request({ 95 | url: `/assets/api/redis?${parameter}`, 96 | method: 'get' 97 | }) 98 | } 99 | 100 | export const createRedis = data => { 101 | return axios.request({ 102 | url: '/assets/api/redis', 103 | data: data, 104 | method: 'post' 105 | }) 106 | } 107 | 108 | export const updateRedis = (id, data) => { 109 | return axios.request({ 110 | url: `/assets/api/redis/${id}`, 111 | data: data, 112 | method: 'PUT' 113 | }) 114 | } 115 | 116 | export const deleteRedis = id => { 117 | return axios.request({ 118 | url: `/assets/api/redis/${id}`, 119 | method: 'delete' 120 | }) 121 | } 122 | -------------------------------------------------------------------------------- /src/api/data.js: -------------------------------------------------------------------------------- 1 | import axios from '@/libs/api.request' 2 | 3 | export const errorReq = () => { 4 | return axios.request({ 5 | url: 'error_url', 6 | method: 'post' 7 | }) 8 | } 9 | 10 | export const saveErrorLogger = info => { 11 | return axios.request({ 12 | url: 'save_error_logger', 13 | data: info, 14 | method: 'post' 15 | }) 16 | } 17 | 18 | export const getMockMenuData = () => { 19 | return axios.request({ 20 | url: 'system/menu', 21 | method: 'post' 22 | }) 23 | } 24 | -------------------------------------------------------------------------------- /src/api/linux.js: -------------------------------------------------------------------------------- 1 | import axios from '@/libs/api.request' 2 | 3 | export const getLinuxStatList = parameter => { 4 | return axios.request({ 5 | url: `/linux/api/linux-stat-list?${parameter}`, 6 | method: 'get' 7 | }) 8 | } 9 | 10 | export const getLinuxStat = parameter => { 11 | return axios.request({ 12 | url: `/linux/api/linux-stat?${parameter}`, 13 | method: 'get' 14 | }) 15 | } 16 | 17 | export const getLinuxStatHis = parameter => { 18 | return axios.request({ 19 | url: `/linux/api/linux-stat-his?${parameter}`, 20 | method: 'get' 21 | }) 22 | } 23 | 24 | export const getLinuxDisk = parameter => { 25 | return axios.request({ 26 | url: `/linux/api/linux-disk?${parameter}`, 27 | method: 'get' 28 | }) 29 | } 30 | 31 | export const getLinuxDiskHis = parameter => { 32 | return axios.request({ 33 | url: `/linux/api/linux-disk-his?${parameter}`, 34 | method: 'get' 35 | }) 36 | } 37 | 38 | export const getLinuxIoStat = parameter => { 39 | return axios.request({ 40 | url: `/linux/api/linux-io-stat?${parameter}`, 41 | method: 'get' 42 | }) 43 | } 44 | 45 | export const getLinuxIoStatHis = parameter => { 46 | return axios.request({ 47 | url: `/linux/api/linux-io-stat-his?${parameter}`, 48 | method: 'get' 49 | }) 50 | } 51 | -------------------------------------------------------------------------------- /src/api/mysql.js: -------------------------------------------------------------------------------- 1 | import axios from '@/libs/api.request' 2 | 3 | export const getMysqlStatList = parameter => { 4 | return axios.request({ 5 | url: `/mysql/api/mysql-stat-list?${parameter}`, 6 | method: 'get' 7 | }) 8 | } 9 | 10 | export const getMysqlStat = parameter => { 11 | return axios.request({ 12 | url: `/mysql/api/mysql-stat?${parameter}`, 13 | method: 'get' 14 | }) 15 | } 16 | 17 | export const getMysqlStatHis = parameter => { 18 | return axios.request({ 19 | url: `/mysql/api/mysql-stat-his?${parameter}`, 20 | method: 'get' 21 | }) 22 | } 23 | 24 | export const getMysqlSlowquery = parameter => { 25 | return axios.request({ 26 | url: `/mysql/api/mysql-slowquery?${parameter}`, 27 | method: 'get' 28 | }) 29 | } 30 | 31 | -------------------------------------------------------------------------------- /src/api/redis.js: -------------------------------------------------------------------------------- 1 | import axios from '@/libs/api.request' 2 | 3 | export const getRedisStatList = parameter => { 4 | return axios.request({ 5 | url: `/rds/api/redis-stat-list?${parameter}`, 6 | method: 'get' 7 | }) 8 | } 9 | 10 | export const getRedisStat = parameter => { 11 | return axios.request({ 12 | url: `/rds/api/redis-stat?${parameter}`, 13 | method: 'get' 14 | }) 15 | } 16 | 17 | export const getRedisStatHis = parameter => { 18 | return axios.request({ 19 | url: `/rds/api/redis-stat-his?${parameter}`, 20 | method: 'get' 21 | }) 22 | } 23 | 24 | export const getRedisConfig = parameter => { 25 | return axios.request({ 26 | url: `/rds/api/get-redis-config?${parameter}`, 27 | method: 'get' 28 | }) 29 | } 30 | 31 | export const getRedisSlowLog = parameter => { 32 | return axios.request({ 33 | url: `/rds/api/get-redis-slowlog?${parameter}`, 34 | method: 'get' 35 | }) 36 | } 37 | 38 | export const getRedisClientList = parameter => { 39 | return axios.request({ 40 | url: `/rds/api/get-redis-clientlist?${parameter}`, 41 | method: 'get' 42 | }) 43 | } 44 | 45 | export const getRedisImmediateStats = parameter => { 46 | return axios.request({ 47 | url: `/rds/api/get-redis-immediate-stats?${parameter}`, 48 | method: 'get' 49 | }) 50 | } 51 | -------------------------------------------------------------------------------- /src/api/routers.js: -------------------------------------------------------------------------------- 1 | // import axios from '@/libs/api.request' 2 | 3 | // export const getRouterReq = (access) => { 4 | // return axios.request({ 5 | // url: 'get_router', 6 | // params: { 7 | // access 8 | // }, 9 | // method: 'get' 10 | // }) 11 | // } 12 | -------------------------------------------------------------------------------- /src/api/system.js: -------------------------------------------------------------------------------- 1 | import axios from '@/libs/api.request' 2 | 3 | export const getAlertLog = parameter => { 4 | return axios.request({ 5 | url: `/system/api/alert-log?${parameter}`, 6 | method: 'get' 7 | }) 8 | } 9 | 10 | export const getAlarmConf = parameter => { 11 | return axios.request({ 12 | url: `/system/api/alarm-conf?${parameter}`, 13 | method: 'get' 14 | }) 15 | } 16 | 17 | export const updateAlarmConf = (id, data) => { 18 | return axios.request({ 19 | url: `/system/api/alarm-conf/${id}`, 20 | data: data, 21 | method: 'PUT' 22 | }) 23 | } 24 | 25 | export const deleteAlarmCconf = id => { 26 | return axios.request({ 27 | url: `/system/api/alarm-conf/${id}`, 28 | method: 'delete' 29 | }) 30 | } 31 | 32 | export const getAlarmInfo = parameter => { 33 | return axios.request({ 34 | url: `/system/api/alarm-info?${parameter}`, 35 | method: 'get' 36 | }) 37 | } 38 | 39 | export const setupOracleRac = data => { 40 | return axios.request({ 41 | url: '/system/api/oracle-rac-setup', 42 | data: data, 43 | method: 'post' 44 | }) 45 | } 46 | 47 | export const setupOracleRacOneNode = data => { 48 | return axios.request({ 49 | url: '/system/api/oracle-rac-onenode-setup', 50 | data: data, 51 | method: 'post' 52 | }) 53 | } 54 | 55 | export const setupOracleOneNode = data => { 56 | return axios.request({ 57 | url: '/system/api/oracle-onenode-setup', 58 | data: data, 59 | method: 'post' 60 | }) 61 | } 62 | 63 | export const setupMysql = data => { 64 | return axios.request({ 65 | url: '/system/api/mysql-setup', 66 | data: data, 67 | method: 'post' 68 | }) 69 | } 70 | 71 | export const getSetupLog = parameter => { 72 | return axios.request({ 73 | url: `/system/api/setup-log?${parameter}`, 74 | method: 'get' 75 | }) 76 | } 77 | -------------------------------------------------------------------------------- /src/api/user.js: -------------------------------------------------------------------------------- 1 | import axios from '@/libs/api.request' 2 | 3 | export const login = ({ userName, password }) => { 4 | const data = { 5 | username: userName, 6 | password 7 | } 8 | return axios.request({ 9 | url: '/api/auth', 10 | data, 11 | method: 'post' 12 | }) 13 | } 14 | 15 | export const getUserInfo = token => { 16 | return axios.request({ 17 | url: '/system/api/user_info', 18 | data: { 19 | token 20 | }, 21 | method: 'post' 22 | }) 23 | } 24 | 25 | export const logout = token => { 26 | return axios.request({ 27 | url: '/system/api/logout', 28 | data: { 29 | token 30 | }, 31 | method: 'post' 32 | }) 33 | } 34 | -------------------------------------------------------------------------------- /src/assets/demo/demo1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gumengkai/db_monitor_vue/1c0c8928b2051dc0b8e490bd78ab61574365e033/src/assets/demo/demo1.jpg -------------------------------------------------------------------------------- /src/assets/demo/demo2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gumengkai/db_monitor_vue/1c0c8928b2051dc0b8e490bd78ab61574365e033/src/assets/demo/demo2.jpg -------------------------------------------------------------------------------- /src/assets/demo/demo3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gumengkai/db_monitor_vue/1c0c8928b2051dc0b8e490bd78ab61574365e033/src/assets/demo/demo3.jpg -------------------------------------------------------------------------------- /src/assets/icons/iconfont.css: -------------------------------------------------------------------------------- 1 | 2 | @font-face {font-family: "iconfont"; 3 | src: url('iconfont.eot?t=1541579316141'); /* IE9*/ 4 | src: url('iconfont.eot?t=1541579316141#iefix') format('embedded-opentype'), /* IE6-IE8 */ 5 | url('data:application/x-font-woff;charset=utf-8;base64,d09GRgABAAAAAAiEAAsAAAAADmgAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAABHU1VCAAABCAAAADMAAABCsP6z7U9TLzIAAAE8AAAARAAAAFY8eUnXY21hcAAAAYAAAACjAAACLi+YJuBnbHlmAAACJAAABAgAAAcg4dRWHmhlYWQAAAYsAAAAMQAAADYTL8piaGhlYQAABmAAAAAgAAAAJAfdA4xobXR4AAAGgAAAABQAAAAsLAD//2xvY2EAAAaUAAAAGAAAABgImgpGbWF4cAAABqwAAAAfAAAAIAEcAG5uYW1lAAAGzAAAAUUAAAJtPlT+fXBvc3QAAAgUAAAAbgAAAI54roygeJxjYGRgYOBikGPQYWB0cfMJYeBgYGGAAJAMY05meiJQDMoDyrGAaQ4gZoOIAgCKIwNPAHicY2BkYWCcwMDKwMHUyXSGgYGhH0IzvmYwYuRgYGBiYGVmwAoC0lxTGByeMTx/ytzwv4EhhrmBoRkozAiSAwDuUwzMeJzlkUEKwkAMRd/YabXFhQvxFF6qPYPrUujGY7jyIr1JoZNjtMnEhag3MOEN5MMk8D9QAoVyVSKEJwGrh6oh6wVN1iM3nc+cVImJVKdOehlklElmWdYVstp+ql8VdIv15a1NLW0zFXsO7Kjz3erH/3+rY37vr6kxnx1LKNWOJZlaxxJNnWOpSu+ot8jgqMvI6KjfyOSo88jsaAbI4tBsig89rQB4nLVUTWwbRRSeNzO767i2g7N/FP9s7MRrE5ON4/V6rSZyU0PiINSSNImES4IUoapWz6hEiqiMBDQqEojkAkiFStyKRC+9VSoFCeUEyqESVUAqEkcu3OAQb3hrJxAXwSGI3X0/szPz5vvm2x0i7O/vf8IJe5VkSJnUyUtklRBQJE1VIjRtUafkmk6pSu2ipleh4+xikkKxSksWTUeo8m8NoagpYtoslTmxrLl37z64e33esuJjU8P5Wd262LxoPVnPZ06Pxfe+C0YjkhSJygPhQCA8ABPOykwuN7NyuRvgUnAgLEnhATkaCQQiUe/7XKUyV6nQz+t2o7l66+rs7NVbq82GXTdrdjxjRGU5amTids2bUDMFtzCsqsMYMqr3IDY6OT05GjsI8Exv/6CSkOWEQigh+y3clxY5QVTcEZFIGtHLxDUJs6WsHR1y9SFKdr1HggCp3V1ICYL36OOpVmvKN9bC1u6R3vZ0qwWtVovgJfqOfUvfIYxIWL+fyETHNVJqSkIT1JTjW8ZWh3yDJDz0ctvsyt51etvrg9/QHhqGlzMM+vbmizPnDWPLMNbW19e7tffvsBzL99aWEfBRY46t+tbe3PypXv/IMDYN43WsQBe9HL2NC33RuxABrPsG+xH3o4bVRE2KgCRqulbWNf8W/UYVHM129aKra24VshZkq+CWD/Oy6Xt8cGYEthgHVlVliCfynAlqjo6oysTKlYUAD4docMI5/1ZioN+GwZNBcTwWUmTdBUqhTwX29QebXzF4An4JJMzwfMl+WQ01+IlQZVR4yhie53ycA16pOI/ODiYNGK4MChdCgXNnX5gIJXPCSYnf2OF850aQ+zJIyOs+u8+mMO8jQdwtg1TIWVRjKAnFcslMi8KfGUPoSUCergUyUk77dMyS69Ms6tijKZKYwUGKbpfdzu+iYeZYAHMFiOVi+MD7h9mb99qC0L7X8c+XatMfTj97KZ5IxJt/pd43tYYQKEjAnXMOB6kQEBrwg+LPjindAPOHNdC3q3ait0I3/ZIunZEARLNYNEUA6czSP3N/7j9wz6ZESdX0VNl1zGNS/szbQaQSIGk4DtVPcZf8AgXpf9A2OyTit5s2syZmand46bhEe2WtodLHkvaoqtTXuXN2/c42WADP9HGfbUcUW7JgqHss4xHtlMys679FqUomdP9VJBQBdnlPABBubpuNwqnmQj6/0HwNQzKxDUJFgKiXurBG6dqFjmeBzsvtRPJgGIZThYa5fdOvsReOticPh6JHHXxsv7ItJpOniYPYsmZ/x0QD/o5P105DeQwF6MH33ogoLi+KQp7zpY3HQV5bFMURzheXeds7gpP+jKNXljjHuYvXHke7cdCxLLZf6YX7B63UcCV4nGNgZGBgAOKAN2ZR8fw2Xxm4WRhA4AbHYRMY/f///1oWBuYGIJeDgQkkCgAvWgs2AAAAeJxjYGRgYG7438AQw8Lw/z8DAwsDA1AEBXADAHXiBHJ4nGNhYGBgYfj/nwVM48cATwECKwAAAAAAjAC6AOgBFAGAAf4CbgLqAzgDkHicY2BkYGDgZkhiYGcAASYg5gJCBob/YD4DABOmAYsAeJxlj01OwzAQhV/6B6QSqqhgh+QFYgEo/RGrblhUavdddN+mTpsqiSPHrdQDcB6OwAk4AtyAO/BIJ5s2lsffvHljTwDc4Acejt8t95E9XDI7cg0XuBeuU38QbpBfhJto41W4Rf1N2MczpsJtdGF5g9e4YvaEd2EPHXwI13CNT+E69S/hBvlbuIk7/Aq30PHqwj7mXle4jUcv9sdWL5xeqeVBxaHJIpM5v4KZXu+Sha3S6pxrW8QmU4OgX0lTnWlb3VPs10PnIhVZk6oJqzpJjMqt2erQBRvn8lGvF4kehCblWGP+tsYCjnEFhSUOjDFCGGSIyujoO1Vm9K+xQ8Jee1Y9zed0WxTU/3OFAQL0z1xTurLSeTpPgT1fG1J1dCtuy56UNJFezUkSskJe1rZUQuoBNmVXjhF6XNGJPyhnSP8ACVpuyAAAAHicbYhdDoIwEAb3a6k/YIIX8VArWewmdJFWJOnpJTG+OQ+TzJCjLy39p4ODR4OAA4444YwWHS7U3IVzn6Voldtb8ksHnvohrlqjjmw1rmzXsvdT7fEbblnCmOfNfJIYStJJfGIL27yb6AOCGR89AAA=') format('woff'), 6 | url('iconfont.ttf?t=1541579316141') format('truetype'), /* chrome, firefox, opera, Safari, Android, iOS 4.2+*/ 7 | url('iconfont.svg?t=1541579316141#iconfont') format('svg'); /* iOS 4.1- */ 8 | } 9 | 10 | .iconfont { 11 | font-family:"iconfont" !important; 12 | font-size:16px; 13 | font-style:normal; 14 | -webkit-font-smoothing: antialiased; 15 | -moz-osx-font-smoothing: grayscale; 16 | } 17 | 18 | .icon-bear:before { content: "\e600"; } 19 | 20 | .icon-resize-vertical:before { content: "\e7c3"; } 21 | 22 | .icon-chuizhifanzhuan:before { content: "\e661"; } 23 | 24 | .icon-shuipingfanzhuan:before { content: "\e662"; } 25 | 26 | .icon-qq:before { content: "\e609"; } 27 | 28 | .icon-frown:before { content: "\e77e"; } 29 | 30 | .icon-meh:before { content: "\e780"; } 31 | 32 | .icon-smile:before { content: "\e783"; } 33 | 34 | .icon-man:before { content: "\e7e2"; } 35 | 36 | .icon-woman:before { content: "\e7e5"; } 37 | 38 | -------------------------------------------------------------------------------- /src/assets/icons/iconfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gumengkai/db_monitor_vue/1c0c8928b2051dc0b8e490bd78ab61574365e033/src/assets/icons/iconfont.eot -------------------------------------------------------------------------------- /src/assets/icons/iconfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gumengkai/db_monitor_vue/1c0c8928b2051dc0b8e490bd78ab61574365e033/src/assets/icons/iconfont.ttf -------------------------------------------------------------------------------- /src/assets/icons/iconfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gumengkai/db_monitor_vue/1c0c8928b2051dc0b8e490bd78ab61574365e033/src/assets/icons/iconfont.woff -------------------------------------------------------------------------------- /src/assets/images/bak/logo-min.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gumengkai/db_monitor_vue/1c0c8928b2051dc0b8e490bd78ab61574365e033/src/assets/images/bak/logo-min.jpg -------------------------------------------------------------------------------- /src/assets/images/bak/logo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gumengkai/db_monitor_vue/1c0c8928b2051dc0b8e490bd78ab61574365e033/src/assets/images/bak/logo.jpg -------------------------------------------------------------------------------- /src/assets/images/icon-qr-qq-wechat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gumengkai/db_monitor_vue/1c0c8928b2051dc0b8e490bd78ab61574365e033/src/assets/images/icon-qr-qq-wechat.png -------------------------------------------------------------------------------- /src/assets/images/icon-social-juejin.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/images/icon-social-twitter.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/images/icon-social-zhihu.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/images/login-bg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gumengkai/db_monitor_vue/1c0c8928b2051dc0b8e490bd78ab61574365e033/src/assets/images/login-bg.jpg -------------------------------------------------------------------------------- /src/assets/images/logo-min.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gumengkai/db_monitor_vue/1c0c8928b2051dc0b8e490bd78ab61574365e033/src/assets/images/logo-min.jpg -------------------------------------------------------------------------------- /src/assets/images/logo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gumengkai/db_monitor_vue/1c0c8928b2051dc0b8e490bd78ab61574365e033/src/assets/images/logo.jpg -------------------------------------------------------------------------------- /src/components/charts/bar.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 93 | -------------------------------------------------------------------------------- /src/components/charts/index.js: -------------------------------------------------------------------------------- 1 | import ChartPie from './pie.vue' 2 | import ChartBar from './bar.vue' 3 | import SimpleChartPie from './simpe-pie.vue' 4 | import ChartPie3 from './pie-3.vue' 5 | import ChartLine1 from './line-1.vue' 6 | import ChartLine2 from './line-2.vue' 7 | import ChartLine3 from './line-3.vue' 8 | import ChartLine4 from './line-4.vue' 9 | import ChartLine5 from './line-5.vue' 10 | import ChartLine6 from './line-6.vue' 11 | export { ChartPie, ChartBar, SimpleChartPie, ChartPie3, ChartLine1, ChartLine2, ChartLine3, ChartLine4, ChartLine5, ChartLine6 } 12 | -------------------------------------------------------------------------------- /src/components/charts/line-1.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 111 | -------------------------------------------------------------------------------- /src/components/charts/line-2.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 135 | -------------------------------------------------------------------------------- /src/components/charts/line-3.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 159 | -------------------------------------------------------------------------------- /src/components/charts/line-4.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 183 | -------------------------------------------------------------------------------- /src/components/charts/pie-3.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 106 | -------------------------------------------------------------------------------- /src/components/charts/pie.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 71 | -------------------------------------------------------------------------------- /src/components/charts/simpe-pie.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 144 | -------------------------------------------------------------------------------- /src/components/common-icon/common-icon.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 39 | 40 | 43 | -------------------------------------------------------------------------------- /src/components/common-icon/index.js: -------------------------------------------------------------------------------- 1 | import CommonIcon from './common-icon.vue' 2 | export default CommonIcon 3 | -------------------------------------------------------------------------------- /src/components/common/common.less: -------------------------------------------------------------------------------- 1 | .no-select{ 2 | -webkit-touch-callout: none; 3 | -webkit-user-select: none; 4 | -khtml-user-select: none; 5 | -moz-user-select: none; 6 | -ms-user-select: none; 7 | user-select: none; 8 | } 9 | -------------------------------------------------------------------------------- /src/components/common/util.js: -------------------------------------------------------------------------------- 1 | export const showTitle = (item, vm) => { 2 | return vm.$config.useI18n ? vm.$t(item.name) : ((item.meta && item.meta.title) || item.name) 3 | } 4 | -------------------------------------------------------------------------------- /src/components/count-to/count-to-int.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 175 | -------------------------------------------------------------------------------- /src/components/count-to/count-to.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 175 | -------------------------------------------------------------------------------- /src/components/count-to/index.js: -------------------------------------------------------------------------------- 1 | import CountTo from './count-to.vue' 2 | import CountToInt from './count-to-int.vue' 3 | export { CountTo, CountToInt } 4 | -------------------------------------------------------------------------------- /src/components/count-to/index.less: -------------------------------------------------------------------------------- 1 | @prefix: ~"count-to"; 2 | 3 | .@{prefix}-wrapper{ 4 | .content-outer{ 5 | display: inline-block; 6 | .@{prefix}-unit-text{ 7 | font-style: normal; 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/components/icons/icons.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 32 | 33 | 36 | -------------------------------------------------------------------------------- /src/components/icons/index.js: -------------------------------------------------------------------------------- 1 | import Icons from './icons.vue' 2 | export default Icons 3 | -------------------------------------------------------------------------------- /src/components/info-card/index.js: -------------------------------------------------------------------------------- 1 | import InforCard from './infor-card.vue' 2 | export default InforCard 3 | -------------------------------------------------------------------------------- /src/components/info-card/infor-card.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 55 | 56 | 95 | -------------------------------------------------------------------------------- /src/components/login-form/index.js: -------------------------------------------------------------------------------- 1 | import LoginForm from './login-form.vue' 2 | export default LoginForm 3 | -------------------------------------------------------------------------------- /src/components/login-form/login-form.vue: -------------------------------------------------------------------------------- 1 | 22 | 73 | -------------------------------------------------------------------------------- /src/components/main/components/a-back-top/index.js: -------------------------------------------------------------------------------- 1 | import ABackTop from './index.vue' 2 | export default ABackTop 3 | -------------------------------------------------------------------------------- /src/components/main/components/a-back-top/index.vue: -------------------------------------------------------------------------------- 1 | 10 | 91 | -------------------------------------------------------------------------------- /src/components/main/components/error-store/error-store.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 38 | 39 | 50 | -------------------------------------------------------------------------------- /src/components/main/components/error-store/index.js: -------------------------------------------------------------------------------- 1 | import ErrorStore from './error-store.vue' 2 | export default ErrorStore 3 | -------------------------------------------------------------------------------- /src/components/main/components/fullscreen/fullscreen.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 75 | 76 | 85 | -------------------------------------------------------------------------------- /src/components/main/components/fullscreen/index.js: -------------------------------------------------------------------------------- 1 | import Fullscreen from './fullscreen.vue' 2 | export default Fullscreen 3 | -------------------------------------------------------------------------------- /src/components/main/components/header-bar/custom-bread-crumb/custom-bread-crumb.less: -------------------------------------------------------------------------------- 1 | .custom-bread-crumb{ 2 | display: inline-block; 3 | vertical-align: top; 4 | } 5 | -------------------------------------------------------------------------------- /src/components/main/components/header-bar/custom-bread-crumb/custom-bread-crumb.vue: -------------------------------------------------------------------------------- 1 | 11 | 47 | -------------------------------------------------------------------------------- /src/components/main/components/header-bar/custom-bread-crumb/index.js: -------------------------------------------------------------------------------- 1 | import customBreadCrumb from './custom-bread-crumb.vue' 2 | export default customBreadCrumb 3 | -------------------------------------------------------------------------------- /src/components/main/components/header-bar/header-bar.less: -------------------------------------------------------------------------------- 1 | .header-bar{ 2 | width: 100%; 3 | height: 100%; 4 | position: relative; 5 | .custom-content-con{ 6 | float: right; 7 | height: auto; 8 | padding-right: 20px; 9 | line-height: 64px; 10 | & > *{ 11 | float: right; 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/components/main/components/header-bar/header-bar.vue: -------------------------------------------------------------------------------- 1 | 10 | 35 | -------------------------------------------------------------------------------- /src/components/main/components/header-bar/index.js: -------------------------------------------------------------------------------- 1 | import HeaderBar from './header-bar' 2 | export default HeaderBar 3 | -------------------------------------------------------------------------------- /src/components/main/components/header-bar/sider-trigger/index.js: -------------------------------------------------------------------------------- 1 | import siderTrigger from './sider-trigger.vue' 2 | export default siderTrigger 3 | -------------------------------------------------------------------------------- /src/components/main/components/header-bar/sider-trigger/sider-trigger.less: -------------------------------------------------------------------------------- 1 | .trans{ 2 | transition: transform .2s ease; 3 | } 4 | @size: 40px; 5 | .sider-trigger-a{ 6 | padding: 6px; 7 | width: @size; 8 | height: @size; 9 | display: inline-block; 10 | text-align: center; 11 | color: #5c6b77; 12 | margin-top: 12px; 13 | i{ 14 | .trans; 15 | vertical-align: top; 16 | } 17 | &.collapsed i{ 18 | transform: rotateZ(90deg); 19 | .trans; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/components/main/components/header-bar/sider-trigger/sider-trigger.vue: -------------------------------------------------------------------------------- 1 | 4 | 25 | 28 | -------------------------------------------------------------------------------- /src/components/main/components/language/index.js: -------------------------------------------------------------------------------- 1 | import Language from './language.vue' 2 | export default Language 3 | -------------------------------------------------------------------------------- /src/components/main/components/language/language.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 52 | -------------------------------------------------------------------------------- /src/components/main/components/side-menu/collapsed-menu.vue: -------------------------------------------------------------------------------- 1 | 12 | 52 | -------------------------------------------------------------------------------- /src/components/main/components/side-menu/index.js: -------------------------------------------------------------------------------- 1 | import SideMenu from './side-menu.vue' 2 | export default SideMenu 3 | -------------------------------------------------------------------------------- /src/components/main/components/side-menu/item-mixin.js: -------------------------------------------------------------------------------- 1 | export default { 2 | props: { 3 | parentItem: { 4 | type: Object, 5 | default: () => {} 6 | }, 7 | theme: String, 8 | iconSize: Number 9 | }, 10 | computed: { 11 | parentName () { 12 | return this.parentItem.name 13 | }, 14 | children () { 15 | return this.parentItem.children 16 | }, 17 | textColor () { 18 | return this.theme === 'dark' ? '#fff' : '#495060' 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/components/main/components/side-menu/mixin.js: -------------------------------------------------------------------------------- 1 | import CommonIcon from '_c/common-icon' 2 | import { showTitle } from '@/libs/util' 3 | export default { 4 | components: { 5 | CommonIcon 6 | }, 7 | methods: { 8 | showTitle (item) { 9 | return showTitle(item, this) 10 | }, 11 | showChildren (item) { 12 | return item.children && (item.children.length > 1 || (item.meta && item.meta.showAlways)) 13 | }, 14 | getNameOrHref (item, children0) { 15 | return item.href ? `isTurnByHref_${item.href}` : (children0 ? item.children[0].name : item.name) 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/components/main/components/side-menu/side-menu-item.vue: -------------------------------------------------------------------------------- 1 | 19 | 27 | -------------------------------------------------------------------------------- /src/components/main/components/side-menu/side-menu.less: -------------------------------------------------------------------------------- 1 | .side-menu-wrapper{ 2 | user-select: none; 3 | .menu-collapsed{ 4 | padding-top: 10px; 5 | 6 | .ivu-dropdown{ 7 | width: 100%; 8 | .ivu-dropdown-rel a{ 9 | width: 100%; 10 | } 11 | } 12 | .ivu-tooltip{ 13 | width: 100%; 14 | .ivu-tooltip-rel{ 15 | width: 100%; 16 | } 17 | .ivu-tooltip-popper .ivu-tooltip-content{ 18 | .ivu-tooltip-arrow{ 19 | border-right-color: #fff; 20 | } 21 | .ivu-tooltip-inner{ 22 | background: #fff; 23 | color: #495060; 24 | } 25 | } 26 | } 27 | 28 | 29 | } 30 | a.drop-menu-a{ 31 | display: inline-block; 32 | padding: 6px 15px; 33 | width: 100%; 34 | text-align: center; 35 | color: #495060; 36 | } 37 | } 38 | .menu-title{ 39 | padding-left: 6px; 40 | } 41 | -------------------------------------------------------------------------------- /src/components/main/components/side-menu/side-menu.vue: -------------------------------------------------------------------------------- 1 | 26 | 112 | 115 | -------------------------------------------------------------------------------- /src/components/main/components/tags-nav/index.js: -------------------------------------------------------------------------------- 1 | import TagsNav from './tags-nav.vue' 2 | export default TagsNav 3 | -------------------------------------------------------------------------------- /src/components/main/components/tags-nav/tags-nav.less: -------------------------------------------------------------------------------- 1 | .no-select{ 2 | -webkit-touch-callout: none; 3 | -webkit-user-select: none; 4 | -khtml-user-select: none; 5 | -moz-user-select: none; 6 | -ms-user-select: none; 7 | user-select: none; 8 | } 9 | .size{ 10 | width: 100%; 11 | height: 100%; 12 | } 13 | .tags-nav{ 14 | position: relative; 15 | border-top: 1px solid #F0F0F0; 16 | border-bottom: 1px solid #F0F0F0; 17 | .no-select; 18 | .size; 19 | .close-con{ 20 | position: absolute; 21 | right: 0; 22 | top: 0; 23 | height: 100%; 24 | width: 32px; 25 | background: #fff; 26 | text-align: center; 27 | z-index: 10; 28 | } 29 | .btn-con{ 30 | position: absolute; 31 | top: 0px; 32 | height: 100%; 33 | background: #fff; 34 | padding-top: 3px; 35 | z-index: 10; 36 | button{ 37 | padding: 6px 4px; 38 | line-height: 14px; 39 | text-align: center; 40 | } 41 | &.left-btn{ 42 | left: 0px; 43 | } 44 | &.right-btn{ 45 | right: 32px; 46 | border-right: 1px solid #F0F0F0; 47 | } 48 | } 49 | .scroll-outer{ 50 | position: absolute; 51 | left: 28px; 52 | right: 61px; 53 | top: 0; 54 | bottom: 0; 55 | box-shadow: 0px 0 3px 2px rgba(100,100,100,.1) inset; 56 | .scroll-body{ 57 | height: ~"calc(100% - 1px)"; 58 | display: inline-block; 59 | padding: 1px 4px 0; 60 | position: absolute; 61 | overflow: visible; 62 | white-space: nowrap; 63 | transition: left .3s ease; 64 | .ivu-tag-dot-inner{ 65 | transition: background .2s ease; 66 | } 67 | } 68 | } 69 | .contextmenu { 70 | position: absolute; 71 | margin: 0; 72 | padding: 5px 0; 73 | background: #fff; 74 | z-index: 1000; 75 | list-style-type: none; 76 | border-radius: 4px; 77 | box-shadow: 2px 2px 3px 0 rgba(0, 0, 0, .1); 78 | li { 79 | margin: 0; 80 | padding: 5px 15px; 81 | cursor: pointer; 82 | &:hover { 83 | background: #eee; 84 | } 85 | } 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /src/components/main/components/user/index.js: -------------------------------------------------------------------------------- 1 | import User from './user.vue' 2 | export default User 3 | -------------------------------------------------------------------------------- /src/components/main/components/user/user.less: -------------------------------------------------------------------------------- 1 | .user{ 2 | &-avatar-dropdown{ 3 | cursor: pointer; 4 | display: inline-block; 5 | // height: 64px; 6 | vertical-align: middle; 7 | // line-height: 64px; 8 | .ivu-badge-dot{ 9 | top: 16px; 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/components/main/components/user/user.vue: -------------------------------------------------------------------------------- 1 | 19 | 20 | 56 | -------------------------------------------------------------------------------- /src/components/main/index.js: -------------------------------------------------------------------------------- 1 | import Main from './main.vue' 2 | export default Main 3 | -------------------------------------------------------------------------------- /src/components/main/main.less: -------------------------------------------------------------------------------- 1 | .main{ 2 | .logo-con{ 3 | height: 64px; 4 | padding: 10px; 5 | img{ 6 | height: 44px; 7 | width: auto; 8 | display: block; 9 | margin: 0 auto; 10 | } 11 | } 12 | .header-con{ 13 | background: #fff; 14 | padding: 0 20px; 15 | width: 100%; 16 | } 17 | .main-layout-con{ 18 | height: 100%; 19 | overflow: hidden; 20 | } 21 | .main-content-con{ 22 | height: ~"calc(100% - 60px)"; 23 | overflow: hidden; 24 | } 25 | .tag-nav-wrapper{ 26 | padding: 0; 27 | height:40px; 28 | background:#F0F0F0; 29 | } 30 | .content-wrapper{ 31 | padding: 18px; 32 | height: ~"calc(100% - 80px)"; 33 | overflow: auto; 34 | } 35 | .left-sider{ 36 | .ivu-layout-sider-children{ 37 | overflow-y: scroll; 38 | margin-right: -18px; 39 | } 40 | } 41 | } 42 | .ivu-menu-item > i{ 43 | margin-right: 12px !important; 44 | } 45 | .ivu-menu-submenu > .ivu-menu > .ivu-menu-item > i { 46 | margin-right: 8px !important; 47 | } 48 | .collased-menu-dropdown{ 49 | width: 100%; 50 | margin: 0; 51 | line-height: normal; 52 | padding: 7px 0 6px 16px; 53 | clear: both; 54 | font-size: 12px !important; 55 | white-space: nowrap; 56 | list-style: none; 57 | cursor: pointer; 58 | transition: background 0.2s ease-in-out; 59 | &:hover{ 60 | background: rgba(100, 100, 100, 0.1); 61 | } 62 | & * { 63 | color: #515a6e; 64 | } 65 | .ivu-menu-item > i{ 66 | margin-right: 12px !important; 67 | } 68 | .ivu-menu-submenu > .ivu-menu > .ivu-menu-item > i { 69 | margin-right: 8px !important; 70 | } 71 | } 72 | 73 | .ivu-select-dropdown.ivu-dropdown-transfer{ 74 | max-height: 400px; 75 | } 76 | -------------------------------------------------------------------------------- /src/components/parent-view/index.js: -------------------------------------------------------------------------------- 1 | import ParentView from './parent-view.vue' 2 | export default ParentView 3 | -------------------------------------------------------------------------------- /src/components/parent-view/parent-view.vue: -------------------------------------------------------------------------------- 1 | 6 | 22 | -------------------------------------------------------------------------------- /src/components/top-menu/index.js: -------------------------------------------------------------------------------- 1 | import OracleMenu from './oracle-menu.vue' 2 | import LinuxMenu from './linux-menu.vue' 3 | import MysqlMenu from './mysql-menu.vue' 4 | import RedisMenu from './redis-menu.vue' 5 | export { OracleMenu, LinuxMenu, MysqlMenu, RedisMenu } 6 | -------------------------------------------------------------------------------- /src/components/top-menu/linux-menu.vue: -------------------------------------------------------------------------------- 1 | 19 | 20 | 48 | 49 | 52 | -------------------------------------------------------------------------------- /src/components/top-menu/mysql-menu.vue: -------------------------------------------------------------------------------- 1 | 31 | 32 | 64 | 65 | 68 | -------------------------------------------------------------------------------- /src/components/top-menu/oracle-menu.vue: -------------------------------------------------------------------------------- 1 | 35 | 36 | 73 | 74 | 77 | -------------------------------------------------------------------------------- /src/components/top-menu/redis-menu.vue: -------------------------------------------------------------------------------- 1 | 35 | 36 | 74 | 75 | \ 78 | -------------------------------------------------------------------------------- /src/config/index.js: -------------------------------------------------------------------------------- 1 | export default { 2 | /** 3 | * @description 配置显示在浏览器标签的title 4 | */ 5 | title: 'DBmoitor 数据库监控平台', 6 | /** 7 | * @description token在Cookie中存储的天数,默认1天 8 | */ 9 | cookieExpires: 1, 10 | /** 11 | * @description 是否使用国际化,默认为false 12 | * 如果不使用,则需要在路由中给需要在菜单中展示的路由设置meta: {title: 'xxx'} 13 | * 用来在菜单中显示文字 14 | */ 15 | useI18n: false, 16 | /** 17 | * @description api请求基础路径 18 | */ 19 | baseUrl: { 20 | // dev: 'https://www.easy-mock.com/mock/5add9213ce4d0e69998a6f51/iview-admin/', 21 | dev: 'http://192.168.48.51:8000/', 22 | pro: 'http://192.168.48.51:8000/' 23 | }, 24 | /** 25 | * @description 默认打开的首页的路由name值,默认为home 26 | */ 27 | homeName: 'home', 28 | /** 29 | * @description 需要加载的插件 30 | */ 31 | plugin: { 32 | // 'error-store': { 33 | // showInHeader: false, // 设为false后不会在顶部显示错误日志徽标 34 | // developmentOff: false // 设为true后在开发环境不会收集错误信息,方便开发中排查错误 35 | // } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/demo/demo1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gumengkai/db_monitor_vue/1c0c8928b2051dc0b8e490bd78ab61574365e033/src/demo/demo1.jpg -------------------------------------------------------------------------------- /src/demo/demo2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gumengkai/db_monitor_vue/1c0c8928b2051dc0b8e490bd78ab61574365e033/src/demo/demo2.jpg -------------------------------------------------------------------------------- /src/directive/directives.js: -------------------------------------------------------------------------------- 1 | import draggable from './module/draggable' 2 | import clipboard from './module/clipboard' 3 | 4 | const directives = { 5 | draggable, 6 | clipboard 7 | } 8 | 9 | export default directives 10 | -------------------------------------------------------------------------------- /src/directive/index.js: -------------------------------------------------------------------------------- 1 | import directive from './directives' 2 | 3 | const importDirective = Vue => { 4 | /** 5 | * 拖拽指令 v-draggable="options" 6 | * options = { 7 | * trigger: /这里传入作为拖拽触发器的CSS选择器/, 8 | * body: /这里传入需要移动容器的CSS选择器/, 9 | * recover: /拖动结束之后是否恢复到原来的位置/ 10 | * } 11 | */ 12 | Vue.directive('draggable', directive.draggable) 13 | /** 14 | * clipboard指令 v-draggable="options" 15 | * options = { 16 | * value: /在输入框中使用v-model绑定的值/, 17 | * success: /复制成功后的回调/, 18 | * error: /复制失败后的回调/ 19 | * } 20 | */ 21 | Vue.directive('clipboard', directive.clipboard) 22 | } 23 | 24 | export default importDirective 25 | -------------------------------------------------------------------------------- /src/directive/module/clipboard.js: -------------------------------------------------------------------------------- 1 | import Clipboard from 'clipboard' 2 | export default { 3 | bind: (el, binding) => { 4 | const clipboard = new Clipboard(el, { 5 | text: () => binding.value.value 6 | }) 7 | el.__success_callback__ = binding.value.success 8 | el.__error_callback__ = binding.value.error 9 | clipboard.on('success', e => { 10 | const callback = el.__success_callback__ 11 | callback && callback(e) 12 | }) 13 | clipboard.on('error', e => { 14 | const callback = el.__error_callback__ 15 | callback && callback(e) 16 | }) 17 | el.__clipboard__ = clipboard 18 | }, 19 | update: (el, binding) => { 20 | el.__clipboard__.text = () => binding.value.value 21 | el.__success_callback__ = binding.value.success 22 | el.__error_callback__ = binding.value.error 23 | }, 24 | unbind: (el, binding) => { 25 | delete el.__success_callback__ 26 | delete el.__error_callback__ 27 | el.__clipboard__.destroy() 28 | delete el.__clipboard__ 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/directive/module/draggable.js: -------------------------------------------------------------------------------- 1 | import { on } from '@/libs/tools' 2 | export default { 3 | inserted: (el, binding, vnode) => { 4 | let triggerDom = document.querySelector(binding.value.trigger) 5 | triggerDom.style.cursor = 'move' 6 | let bodyDom = document.querySelector(binding.value.body) 7 | let pageX = 0 8 | let pageY = 0 9 | let transformX = 0 10 | let transformY = 0 11 | let canMove = false 12 | const handleMousedown = e => { 13 | let transform = /\(.*\)/.exec(bodyDom.style.transform) 14 | if (transform) { 15 | transform = transform[0].slice(1, transform[0].length - 1) 16 | let splitxy = transform.split('px, ') 17 | transformX = parseFloat(splitxy[0]) 18 | transformY = parseFloat(splitxy[1].split('px')[0]) 19 | } 20 | pageX = e.pageX 21 | pageY = e.pageY 22 | canMove = true 23 | } 24 | const handleMousemove = e => { 25 | let xOffset = e.pageX - pageX + transformX 26 | let yOffset = e.pageY - pageY + transformY 27 | if (canMove) bodyDom.style.transform = `translate(${xOffset}px, ${yOffset}px)` 28 | } 29 | const handleMouseup = e => { 30 | canMove = false 31 | } 32 | on(triggerDom, 'mousedown', handleMousedown) 33 | on(document, 'mousemove', handleMousemove) 34 | on(document, 'mouseup', handleMouseup) 35 | }, 36 | update: (el, binding, vnode) => { 37 | if (!binding.value.recover) return 38 | let bodyDom = document.querySelector(binding.value.body) 39 | bodyDom.style.transform = '' 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/index.less: -------------------------------------------------------------------------------- 1 | @import '~iview/src/styles/index.less'; 2 | 3 | @menu-dark-title: #001529; 4 | @menu-dark-active-bg: #000c17; 5 | @layout-sider-background: #001529; 6 | -------------------------------------------------------------------------------- /src/libs/api.request.js: -------------------------------------------------------------------------------- 1 | import HttpRequest from '@/libs/axios' 2 | import config from '@/config' 3 | const baseUrl = process.env.NODE_ENV === 'development' ? config.baseUrl.dev : config.baseUrl.pro 4 | 5 | const axios = new HttpRequest(baseUrl) 6 | export default axios 7 | -------------------------------------------------------------------------------- /src/libs/axios.js: -------------------------------------------------------------------------------- 1 | import axios from 'axios' 2 | import store from '@/store' 3 | // import { Spin } from 'iview' 4 | import { getToken } from '@/libs/util' 5 | const addErrorLog = errorInfo => { 6 | const { statusText, status, request: { responseURL } } = errorInfo 7 | let info = { 8 | type: 'ajax', 9 | code: status, 10 | mes: statusText, 11 | url: responseURL 12 | } 13 | if (!responseURL.includes('save_error_logger')) store.dispatch('addErrorLog', info) 14 | } 15 | 16 | class HttpRequest { 17 | constructor (baseUrl = baseURL) { 18 | this.baseUrl = baseUrl 19 | this.queue = {} 20 | } 21 | getInsideConfig () { 22 | const config = { 23 | baseURL: this.baseUrl, 24 | headers: { 25 | // 26 | } 27 | } 28 | if (getToken()) { 29 | config.headers['Authorization'] = `token ${getToken()}` 30 | } 31 | return config 32 | } 33 | destroy (url) { 34 | delete this.queue[url] 35 | if (!Object.keys(this.queue).length) { 36 | // Spin.hide() 37 | } 38 | } 39 | interceptors (instance, url) { 40 | // 请求拦截 41 | instance.interceptors.request.use(config => { 42 | // 添加全局的loading... 43 | if (!Object.keys(this.queue).length) { 44 | // Spin.show() // 不建议开启,因为界面不友好 45 | } 46 | this.queue[url] = true 47 | return config 48 | }, error => { 49 | return Promise.reject(error) 50 | }) 51 | // 响应拦截 52 | instance.interceptors.response.use(res => { 53 | this.destroy(url) 54 | const { data, status } = res 55 | return { data, status } 56 | }, error => { 57 | this.destroy(url) 58 | let errorInfo = error.response 59 | if (!errorInfo) { 60 | const { request: { statusText, status }, config } = JSON.parse(JSON.stringify(error)) 61 | errorInfo = { 62 | statusText, 63 | status, 64 | request: { responseURL: config.url } 65 | } 66 | } 67 | addErrorLog(errorInfo) 68 | return Promise.reject(error) 69 | }) 70 | } 71 | request (options) { 72 | const instance = axios.create() 73 | options = Object.assign(this.getInsideConfig(), options) 74 | this.interceptors(instance, options.url) 75 | return instance(options) 76 | } 77 | } 78 | export default HttpRequest 79 | -------------------------------------------------------------------------------- /src/libs/excel.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | import XLSX from 'xlsx'; 3 | 4 | function auto_width(ws, data){ 5 | /*set worksheet max width per col*/ 6 | const colWidth = data.map(row => row.map(val => { 7 | /*if null/undefined*/ 8 | if (val == null) { 9 | return {'wch': 10}; 10 | } 11 | /*if chinese*/ 12 | else if (val.toString().charCodeAt(0) > 255) { 13 | return {'wch': val.toString().length * 2}; 14 | } else { 15 | return {'wch': val.toString().length}; 16 | } 17 | })) 18 | /*start in the first row*/ 19 | let result = colWidth[0]; 20 | for (let i = 1; i < colWidth.length; i++) { 21 | for (let j = 0; j < colWidth[i].length; j++) { 22 | if (result[j]['wch'] < colWidth[i][j]['wch']) { 23 | result[j]['wch'] = colWidth[i][j]['wch']; 24 | } 25 | } 26 | } 27 | ws['!cols'] = result; 28 | } 29 | 30 | function json_to_array(key, jsonData){ 31 | return jsonData.map(v => key.map(j => { return v[j] })); 32 | } 33 | 34 | // fix data,return string 35 | function fixdata(data) { 36 | let o = '' 37 | let l = 0 38 | const w = 10240 39 | for (; l < data.byteLength / w; ++l) o += String.fromCharCode.apply(null, new Uint8Array(data.slice(l * w, l * w + w))) 40 | o += String.fromCharCode.apply(null, new Uint8Array(data.slice(l * w))) 41 | return o 42 | } 43 | 44 | // get head from excel file,return array 45 | function get_header_row(sheet) { 46 | const headers = [] 47 | const range = XLSX.utils.decode_range(sheet['!ref']) 48 | let C 49 | const R = range.s.r /* start in the first row */ 50 | for (C = range.s.c; C <= range.e.c; ++C) { /* walk every column in the range */ 51 | var cell = sheet[XLSX.utils.encode_cell({ c: C, r: R })] /* find the cell in the first row */ 52 | var hdr = 'UNKNOWN ' + C // <-- replace with your desired default 53 | if (cell && cell.t) hdr = XLSX.utils.format_cell(cell) 54 | headers.push(hdr) 55 | } 56 | return headers 57 | } 58 | 59 | export const export_table_to_excel= (id, filename) => { 60 | const table = document.getElementById(id); 61 | const wb = XLSX.utils.table_to_book(table); 62 | XLSX.writeFile(wb, filename); 63 | 64 | /* the second way */ 65 | // const table = document.getElementById(id); 66 | // const wb = XLSX.utils.book_new(); 67 | // const ws = XLSX.utils.table_to_sheet(table); 68 | // XLSX.utils.book_append_sheet(wb, ws, filename); 69 | // XLSX.writeFile(wb, filename); 70 | } 71 | 72 | export const export_json_to_excel = ({data, key, title, filename, autoWidth}) => { 73 | const wb = XLSX.utils.book_new(); 74 | data.unshift(title); 75 | const ws = XLSX.utils.json_to_sheet(data, {header: key, skipHeader: true}); 76 | if(autoWidth){ 77 | const arr = json_to_array(key, data); 78 | auto_width(ws, arr); 79 | } 80 | XLSX.utils.book_append_sheet(wb, ws, filename); 81 | XLSX.writeFile(wb, filename + '.xlsx'); 82 | } 83 | 84 | export const export_array_to_excel = ({key, data, title, filename, autoWidth}) => { 85 | const wb = XLSX.utils.book_new(); 86 | const arr = json_to_array(key, data); 87 | arr.unshift(title); 88 | const ws = XLSX.utils.aoa_to_sheet(arr); 89 | if(autoWidth){ 90 | auto_width(ws, arr); 91 | } 92 | XLSX.utils.book_append_sheet(wb, ws, filename); 93 | XLSX.writeFile(wb, filename + '.xlsx'); 94 | } 95 | 96 | export const read = (data, type) => { 97 | /* if type == 'base64' must fix data first */ 98 | // const fixedData = fixdata(data) 99 | // const workbook = XLSX.read(btoa(fixedData), { type: 'base64' }) 100 | const workbook = XLSX.read(data, { type: type }); 101 | const firstSheetName = workbook.SheetNames[0]; 102 | const worksheet = workbook.Sheets[firstSheetName]; 103 | const header = get_header_row(worksheet); 104 | const results = XLSX.utils.sheet_to_json(worksheet); 105 | return {header, results}; 106 | } 107 | 108 | export default { 109 | export_table_to_excel, 110 | export_array_to_excel, 111 | export_json_to_excel, 112 | read 113 | } 114 | -------------------------------------------------------------------------------- /src/libs/render-dom.js: -------------------------------------------------------------------------------- 1 | export default { 2 | name: 'RenderDom', 3 | functional: true, 4 | props: { 5 | render: Function 6 | }, 7 | render: (h, ctx) => { 8 | return ctx.props.render(h) 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/libs/router-util.js: -------------------------------------------------------------------------------- 1 | /** 2 | * ①添 3 | * @@新增 定义初始化菜单 4 | */ 5 | // import axios from 'axios' 6 | import { getToken, localSave, localRead } from '@/libs/util' 7 | // import config from '@/config' 8 | import { lazyLoadingCop } from '@/libs/tools' 9 | import { getMockMenuData } from '@/api/data' 10 | import Main from '@/components/main' // Main 是架构组件,不在后台返回,在文件里单独引入 11 | import parentView from '@/components/parent-view' // 获取组件的方法 12 | import store from '@/store' // parentView 是二级架构组件,不在后台返回,在文件里单独引入 13 | // eslint-disable-next-line no-unused-vars 14 | const _import = require('@/router/_import_' + process.env.NODE_ENV) 15 | 16 | var gotRouter 17 | // 初始化路由 18 | export const initRouter = () => { 19 | console.log('----------------开始初始化路由--------------------') 20 | if (!getToken()) { 21 | return 22 | } 23 | // 异步请求 24 | /* axios.get(baseUrl+'/menuList',{ 25 | header:{'Authorization':getToken()} 26 | }).then(res=>{ 27 | var menuData=res.data.data; 28 | localSave('route',JSON.stringify(menuData)); 29 | gotRouter=formatMenu(menuData); 30 | vm.$store.commit('updateMenuList',gotRouter); 31 | }); */ 32 | var routerData 33 | if (!gotRouter) { 34 | getMockMenuData().then(res => { 35 | routerData = res.data // 后台拿到路由 36 | localSave('dynamicRouter', JSON.stringify(routerData)) // 存储路由到localStorage 37 | gotRouter = filterAsyncRouter(routerData) // 过滤路由,路由组件转换 38 | store.commit('updateMenuList', gotRouter) 39 | dynamicRouterAdd() 40 | }) 41 | } else { 42 | gotRouter = dynamicRouterAdd() 43 | } 44 | return gotRouter 45 | } 46 | 47 | // 加载路由菜单,从localStorage拿到路由,在创建路由时使用 48 | export const dynamicRouterAdd = () => { 49 | let dynamicRouter = [] 50 | let data = localRead('dynamicRouter') 51 | console.log('从本地加载出来', data) 52 | if (!data) { 53 | return dynamicRouter 54 | } 55 | dynamicRouter = filterAsyncRouter(JSON.parse(data)) 56 | 57 | return dynamicRouter 58 | } 59 | 60 | // @函数: 遍历后台传来的路由字符串,转换为组件对象 61 | export const filterAsyncRouter = asyncRouterMap => { 62 | const accessedRouters = asyncRouterMap.filter(route => { 63 | if (route.component) { 64 | if (route.component === 'Main') { 65 | // Main组件特殊处理 66 | route.component = Main 67 | } else if (route.component === 'parentView') { 68 | // parentView组件特殊处理 69 | route.component = parentView 70 | } else { 71 | // route.component = _import(route.component) 72 | route.component = lazyLoadingCop(route.component) 73 | } 74 | } 75 | if (route.children && route.children.length) { 76 | route.children = filterAsyncRouter(route.children) 77 | } 78 | return true 79 | }) 80 | return accessedRouters 81 | } 82 | -------------------------------------------------------------------------------- /src/locale/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import VueI18n from 'vue-i18n' 3 | import { localRead } from '@/libs/util' 4 | import customZhCn from './lang/zh-CN' 5 | import customZhTw from './lang/zh-TW' 6 | import customEnUs from './lang/en-US' 7 | import zhCnLocale from 'iview/src/locale/lang/zh-CN' 8 | import enUsLocale from 'iview/src/locale/lang/en-US' 9 | import zhTwLocale from 'iview/src/locale/lang/zh-TW' 10 | 11 | Vue.use(VueI18n) 12 | 13 | // 自动根据浏览器系统语言设置语言 14 | const navLang = navigator.language 15 | const localLang = (navLang === 'zh-CN' || navLang === 'en-US') ? navLang : false 16 | let lang = localLang || localRead('local') || 'zh-CN' 17 | 18 | Vue.config.lang = lang 19 | 20 | // vue-i18n 6.x+写法 21 | Vue.locale = () => {} 22 | const messages = { 23 | 'zh-CN': Object.assign(zhCnLocale, customZhCn), 24 | 'zh-TW': Object.assign(zhTwLocale, customZhTw), 25 | 'en-US': Object.assign(enUsLocale, customEnUs) 26 | } 27 | const i18n = new VueI18n({ 28 | locale: lang, 29 | messages 30 | }) 31 | 32 | export default i18n 33 | 34 | // vue-i18n 5.x写法 35 | // Vue.locale('zh-CN', Object.assign(zhCnLocale, customZhCn)) 36 | // Vue.locale('en-US', Object.assign(zhTwLocale, customZhTw)) 37 | // Vue.locale('zh-TW', Object.assign(enUsLocale, customEnUs)) 38 | -------------------------------------------------------------------------------- /src/locale/lang/en-US.js: -------------------------------------------------------------------------------- 1 | export default { 2 | home: 'Home', 3 | login: 'Login', 4 | components: 'Components', 5 | count_to_page: 'Count-to', 6 | tables_page: 'Table', 7 | split_pane_page: 'Split-pane', 8 | markdown_page: 'Markdown-editor', 9 | editor_page: 'Rich-Text-Editor', 10 | icons_page: 'Custom-icon', 11 | img_cropper_page: 'Image-editor', 12 | update: 'Update', 13 | doc: 'Document', 14 | join_page: 'QQ Group', 15 | update_table_page: 'Update .CSV', 16 | update_paste_page: 'Paste Table Data', 17 | multilevel: 'multilevel', 18 | directive_page: 'Directive', 19 | level_1: 'Level-1', 20 | level_2: 'Level-2', 21 | level_2_1: 'Level-2-1', 22 | level_2_3: 'Level-2-3', 23 | level_2_2: 'Level-2-2', 24 | level_2_2_1: 'Level-2-2-1', 25 | level_2_2_2: 'Level-2-2-2', 26 | excel: 'Excel', 27 | 'upload-excel': 'Upload Excel', 28 | 'export-excel': 'Export Excel', 29 | tools_methods_page: 'Tools Methods', 30 | drag_list_page: 'Drag-list', 31 | i18n_page: 'Internationalization', 32 | modalTitle: 'Modal Title', 33 | content: 'This is the modal box content.', 34 | buttonText: 'Show Modal', 35 | 'i18n-tip': 'Note: Only this page is multi-language, other pages do not add language content to the multi-language package.', 36 | error_store_page: 'Error Collection', 37 | error_logger_page: 'Error Logger', 38 | query: 'Query', 39 | params: 'Params', 40 | cropper_page: 'Cropper', 41 | message_page: 'Message Center', 42 | tree_table_page: 'Tree Table', 43 | org_tree_page: 'Org Tree', 44 | drag_drawer_page: 'Draggable Drawer', 45 | tree_select_page: 'Tree Selector' 46 | } 47 | -------------------------------------------------------------------------------- /src/locale/lang/zh-CN.js: -------------------------------------------------------------------------------- 1 | export default { 2 | home: '首页', 3 | login: '登录', 4 | components: '组件', 5 | count_to_page: '数字渐变', 6 | tables_page: '多功能表格', 7 | split_pane_page: '分割窗口', 8 | markdown_page: 'Markdown编辑器', 9 | editor_page: '富文本编辑器', 10 | icons_page: '自定义图标', 11 | img_cropper_page: '图片编辑器', 12 | update: '上传数据', 13 | join_page: 'QQ群', 14 | doc: '文档', 15 | update_table_page: '上传CSV文件', 16 | update_paste_page: '粘贴表格数据', 17 | multilevel: '多级菜单', 18 | directive_page: '指令', 19 | level_1: 'Level-1', 20 | level_2: 'Level-2', 21 | level_2_1: 'Level-2-1', 22 | level_2_3: 'Level-2-3', 23 | level_2_2: 'Level-2-2', 24 | level_2_2_1: 'Level-2-2-1', 25 | level_2_2_2: 'Level-2-2-2', 26 | excel: 'Excel', 27 | 'upload-excel': '上传excel', 28 | 'export-excel': '导出excel', 29 | tools_methods_page: '工具函数', 30 | drag_list_page: '拖拽列表', 31 | i18n_page: '多语言', 32 | modalTitle: '模态框题目', 33 | content: '这是模态框内容', 34 | buttonText: '显示模态框', 35 | 'i18n-tip': '注:仅此页做了多语言,其他页面没有在多语言包中添加语言内容', 36 | error_store_page: '错误收集', 37 | error_logger_page: '错误日志', 38 | query: '带参路由', 39 | params: '动态路由', 40 | cropper_page: '图片裁剪', 41 | message_page: '消息中心', 42 | tree_table_page: '树状表格', 43 | org_tree_page: '组织结构树', 44 | drag_drawer_page: '可拖动抽屉', 45 | tree_select_page: '树状下拉选择器' 46 | } 47 | -------------------------------------------------------------------------------- /src/locale/lang/zh-TW.js: -------------------------------------------------------------------------------- 1 | export default { 2 | home: '首頁', 3 | login: '登錄', 4 | components: '组件', 5 | count_to_page: '数字渐变', 6 | tables_page: '多功能表格', 7 | split_pane_page: '分割窗口', 8 | markdown_page: 'Markdown編輯器', 9 | editor_page: '富文本編輯器', 10 | icons_page: '自定義圖標', 11 | img_cropper_page: '圖片編輯器', 12 | update: '上傳數據', 13 | join_page: 'QQ群', 14 | doc: '文檔', 15 | update_table_page: '上傳CSV文件', 16 | update_paste_page: '粘貼表格數據', 17 | multilevel: '多级菜单', 18 | directive_page: '指令', 19 | level_1: 'Level-1', 20 | level_2: 'Level-2', 21 | level_2_1: 'Level-2-1', 22 | level_2_3: 'Level-2-3', 23 | level_2_2: 'Level-2-2', 24 | level_2_2_1: 'Level-2-2-1', 25 | level_2_2_2: 'Level-2-2-2', 26 | excel: 'Excel', 27 | 'upload-excel': '上傳excel', 28 | 'export-excel': '導出excel', 29 | tools_methods_page: '工具函數', 30 | drag_list_page: '拖拽列表', 31 | i18n_page: '多語言', 32 | modalTitle: '模態框題目', 33 | content: '這是模態框內容', 34 | buttonText: '顯示模態框', 35 | 'i18n-tip': '注:僅此頁做了多語言,其他頁面沒有在多語言包中添加語言內容', 36 | error_store_page: '錯誤收集', 37 | error_logger_page: '錯誤日誌', 38 | query: '帶參路由', 39 | params: '動態路由', 40 | cropper_page: '圖片裁剪', 41 | message_page: '消息中心', 42 | tree_table_page: '樹狀表格', 43 | org_tree_page: '組織結構樹', 44 | drag_drawer_page: '可拖動抽屜', 45 | tree_select_page: '樹狀下拉選擇器' 46 | } 47 | -------------------------------------------------------------------------------- /src/main.js: -------------------------------------------------------------------------------- 1 | // The Vue build version to load with the `import` command 2 | // (runtime-only or standalone) has been set in webpack.base.conf with an alias. 3 | import Vue from 'vue' 4 | import App from './App' 5 | import router from './router' 6 | import store from './store' 7 | import iView from 'iview' 8 | import i18n from '@/locale' 9 | import config from '@/config' 10 | import importDirective from '@/directive' 11 | import { directive as clickOutside } from 'v-click-outside-x' 12 | import installPlugin from '@/plugin' 13 | import './index.less' 14 | import '@/assets/icons/iconfont.css' 15 | import TreeTable from 'tree-table-vue' 16 | import VOrgTree from 'v-org-tree' 17 | import 'v-org-tree/dist/v-org-tree.css' 18 | import { initRouter } from '@/libs/router-util' // ①新增 引入动态菜单渲染 19 | import 'xterm/dist/xterm.css' 20 | // 实际打包时应该不引入mock 21 | /* eslint-disable */ 22 | if (process.env.NODE_ENV !== 'production') require('@/mock') 23 | 24 | Vue.use(iView, { 25 | i18n: (key, value) => i18n.t(key, value) 26 | }) 27 | Vue.use(TreeTable) 28 | Vue.use(VOrgTree) 29 | /** 30 | * @description 注册admin内置插件 31 | */ 32 | installPlugin(Vue) 33 | /** 34 | * @description 生产环境关掉提示 35 | */ 36 | Vue.config.productionTip = false 37 | /** 38 | * @description 全局注册应用配置 39 | */ 40 | Vue.prototype.$config = config 41 | /** 42 | * 注册指令 43 | */ 44 | importDirective(Vue) 45 | Vue.directive('clickOutside', clickOutside) 46 | 47 | /* eslint-disable no-new */ 48 | new Vue({ 49 | el: '#app', 50 | router, 51 | i18n, 52 | store, 53 | render: h => h(App), 54 | mounted() { 55 | initRouter() // ①新增 调用方法,动态生成路由, 56 | } 57 | }) 58 | -------------------------------------------------------------------------------- /src/mock/index.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gumengkai/db_monitor_vue/1c0c8928b2051dc0b8e490bd78ab61574365e033/src/mock/index.js -------------------------------------------------------------------------------- /src/plugin/error-store/index.js: -------------------------------------------------------------------------------- 1 | import store from '@/store' 2 | export default { 3 | install (Vue, options) { 4 | if (options.developmentOff && process.env.NODE_ENV === 'development') return 5 | Vue.config.errorHandler = (error, vm, mes) => { 6 | let info = { 7 | type: 'script', 8 | code: 0, 9 | mes: error.message, 10 | url: window.location.href 11 | } 12 | Vue.nextTick(() => { 13 | store.dispatch('addErrorLog', info) 14 | }) 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/plugin/index.js: -------------------------------------------------------------------------------- 1 | import config from '@/config' 2 | const { plugin } = config 3 | 4 | export default (Vue) => { 5 | for (let name in plugin) { 6 | const value = plugin[name] 7 | Vue.use(require(`./${name}`).default, typeof value === 'object' ? value : undefined) 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/router/_import_development.js: -------------------------------------------------------------------------------- 1 | module.default = file => require('@/view/' + file + '.vue').default // vue-loader at least v13.0.0+ 2 | -------------------------------------------------------------------------------- /src/router/_import_production.js: -------------------------------------------------------------------------------- 1 | module.exports = file => () => import('@/view/' + file + '.vue') 2 | -------------------------------------------------------------------------------- /src/router/before-close.js: -------------------------------------------------------------------------------- 1 | import { Modal } from 'iview' 2 | 3 | const beforeClose = { 4 | before_close_normal: (resolve) => { 5 | Modal.confirm({ 6 | title: '确定要关闭这一页吗', 7 | onOk: () => { 8 | resolve(true) 9 | }, 10 | onCancel: () => { 11 | resolve(false) 12 | } 13 | }) 14 | } 15 | } 16 | 17 | export default beforeClose 18 | -------------------------------------------------------------------------------- /src/router/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Router from 'vue-router' 3 | import routes from './routers' 4 | import store from '@/store' 5 | import iView from 'iview' 6 | import { dynamicRouterAdd } from '@/libs/router-util' 7 | import { setToken, getToken, canTurnTo, setTitle } from '@/libs/util' 8 | import config from '@/config' 9 | 10 | const { homeName } = config 11 | 12 | Vue.use(Router) 13 | const router = new Router({ 14 | routes, 15 | mode: 'history' 16 | }) 17 | const LOGIN_PAGE_NAME = 'login' 18 | 19 | const turnTo = (to, access, next) => { 20 | if (canTurnTo(to.name, access, [...routes, ...dynamicRouterAdd()])) next() 21 | // 有权限,可访问 22 | else next({ replace: true, name: 'error_401' }) // 无权限,重定向到401页面 23 | } 24 | 25 | router.beforeEach((to, from, next) => { 26 | iView.LoadingBar.start() 27 | const token = getToken() 28 | if (!token && to.name !== LOGIN_PAGE_NAME) { 29 | // 未登录且要跳转的页面不是登录页 30 | next({ 31 | name: LOGIN_PAGE_NAME // 跳转到登录页 32 | }) 33 | } else if (!token && to.name === LOGIN_PAGE_NAME) { 34 | // 未登陆且要跳转的页面是登录页 35 | next() // 跳转 36 | } else if (token && to.name === LOGIN_PAGE_NAME) { 37 | // 已登录且要跳转的页面是登录页 38 | next({ 39 | name: homeName // 跳转到homeName页 40 | }) 41 | } else { 42 | if (store.state.user.hasGetInfo) { 43 | console.log('1', to.name, store.state.user.access) 44 | turnTo(to, store.state.user.access, next) 45 | } else { 46 | store 47 | .dispatch('getUserInfo') 48 | .then(user => { 49 | // 拉取用户信息,通过用户权限和跳转的页面的name来判断是否有权限访问;access必须是一个数组,如:['super_admin'] ['super_admin', 'admin'] 50 | turnTo(to, user.access, next) 51 | }) 52 | .catch(() => { 53 | setToken('') 54 | next({ 55 | name: 'login' 56 | }) 57 | }) 58 | } 59 | } 60 | }) 61 | 62 | router.afterEach(to => { 63 | setTitle(to, router.app) 64 | iView.LoadingBar.finish() 65 | window.scrollTo(0, 0) 66 | }) 67 | 68 | export default router 69 | -------------------------------------------------------------------------------- /src/router/routers.js: -------------------------------------------------------------------------------- 1 | import Main from '@/components/main' 2 | import { dynamicRouterAdd } from '@/libs/router-util' // ①添 引入加载菜单 3 | 4 | /** 5 | * iview-admin中meta除了原生参数外可配置的参数: 6 | * meta: { 7 | * title: { String|Number|Function } 8 | * 显示在侧边栏、面包屑和标签栏的文字 9 | * 使用'{{ 多语言字段 }}'形式结合多语言使用,例子看多语言的路由配置; 10 | * 可以传入一个回调函数,参数是当前路由对象,例子看动态路由和带参路由 11 | * hideInBread: (false) 设为true后此级路由将不会出现在面包屑中,示例看QQ群路由配置 12 | * hideInMenu: (false) 设为true后在左侧菜单不会显示该页面选项 13 | * notCache: (false) 设为true后页面在切换标签后不会缓存,如果需要缓存,无需设置这个字段,而且需要设置页面组件name属性和路由配置的name一致 14 | * access: (null) 可访问该页面的权限数组,当前路由设置的权限会影响子路由 15 | * icon: (-) 该页面在左侧菜单、面包屑和标签导航处显示的图标,如果是自定义图标,需要在图标名称前加下划线'_' 16 | * beforeCloseName: (-) 设置该字段,则在关闭当前tab页时会去'@/router/before-close.js'里寻找该字段名对应的方法,作为关闭前的钩子函数 17 | * } 18 | */ 19 | // 不作为Main组件的子页面展示的页面单独写 20 | export const otherRouter = [ 21 | { 22 | path: '/login', 23 | name: 'login', 24 | meta: { 25 | title: 'Login - 登录', 26 | hideInMenu: true 27 | }, 28 | component: () => import('@/view/login/login.vue') 29 | }, 30 | { 31 | path: '/401', 32 | name: 'error_401', 33 | meta: { 34 | hideInMenu: true 35 | }, 36 | component: () => import('@/view/error-page/401.vue') 37 | } 38 | ] 39 | 40 | // 作为Main组件的子页面展示但是不在左侧菜单显示的路由写在mainRouter里 41 | export const mainRouter = [ 42 | { 43 | path: '/', 44 | name: '_home', 45 | redirect: '/home', 46 | component: Main, 47 | meta: { 48 | hideInMenu: true, 49 | notCache: true 50 | }, 51 | children: [ 52 | { 53 | path: '/home', 54 | name: 'home', 55 | meta: { 56 | hideInMenu: true, 57 | title: '首页', 58 | notCache: true, 59 | icon: 'md-home' 60 | }, 61 | component: () => import('@/view/system/home') 62 | } 63 | ] 64 | } 65 | ] 66 | 67 | // 作为Main组件的子页面展示并且在左侧菜单显示的路由写在appRouter里 68 | export const appRouter = [...dynamicRouterAdd()] 69 | 70 | export const routes = [...otherRouter, ...mainRouter, ...appRouter] 71 | 72 | // 所有上面定义的路由都要写在下面输出 73 | export default routes 74 | -------------------------------------------------------------------------------- /src/store/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Vuex from 'vuex' 3 | 4 | import user from './module/user' 5 | import app from './module/app' 6 | 7 | Vue.use(Vuex) 8 | 9 | export default new Vuex.Store({ 10 | state: { 11 | // 12 | }, 13 | mutations: { 14 | // 15 | }, 16 | actions: { 17 | // 18 | }, 19 | modules: { 20 | user, 21 | app 22 | } 23 | }) 24 | -------------------------------------------------------------------------------- /src/store/module/app.js: -------------------------------------------------------------------------------- 1 | import { 2 | getBreadCrumbList, 3 | setTagNavListInLocalstorage, 4 | getMenuByRouter, 5 | getTagNavListFromLocalstorage, 6 | getHomeRoute, 7 | getNextRoute, 8 | routeHasExist, 9 | routeEqual, 10 | getRouteTitleHandled, 11 | localSave, 12 | localRead 13 | } from '@/libs/util' 14 | import { saveErrorLogger } from '@/api/data' 15 | import router from '@/router' 16 | // import routers from '@/router/routers' 17 | import config from '@/config' 18 | const { homeName } = config 19 | 20 | const closePage = (state, route) => { 21 | const nextRoute = getNextRoute(state.tagNavList, route) 22 | state.tagNavList = state.tagNavList.filter(item => { 23 | return !routeEqual(item, route) 24 | }) 25 | router.push(nextRoute) 26 | } 27 | 28 | export default { 29 | state: { 30 | breadCrumbList: [], 31 | tagNavList: [], 32 | homeRoute: {}, 33 | local: localRead('local'), 34 | errorList: [], 35 | hasReadErrorPage: false, 36 | menuList: [] 37 | }, 38 | getters: { 39 | menuList: (state, getters, rootState) => 40 | getMenuByRouter(state.menuList, rootState.user.access), 41 | errorCount: state => state.errorList.length 42 | }, 43 | mutations: { 44 | updateMenuList (state, routes) { 45 | // ①添 接受前台数组,刷新菜单 46 | router.addRoutes(routes) // 动态添加路由 47 | state.menuList = routes 48 | console.log('updateMenuList 添 menuList', state.menuList) 49 | }, 50 | setBreadCrumb (state, route) { 51 | state.breadCrumbList = getBreadCrumbList(route, state.homeRoute) 52 | }, 53 | setHomeRoute (state, routes) { 54 | state.homeRoute = getHomeRoute(routes, homeName) 55 | }, 56 | setTagNavList (state, list) { 57 | let tagList = [] 58 | if (list) { 59 | tagList = [...list] 60 | } else tagList = getTagNavListFromLocalstorage() || [] 61 | if (tagList[0] && tagList[0].name !== homeName) tagList.shift() 62 | let homeTagIndex = tagList.findIndex(item => item.name === homeName) 63 | if (homeTagIndex > 0) { 64 | let homeTag = tagList.splice(homeTagIndex, 1)[0] 65 | tagList.unshift(homeTag) 66 | } 67 | state.tagNavList = tagList 68 | setTagNavListInLocalstorage([...tagList]) 69 | }, 70 | closeTag (state, route) { 71 | let tag = state.tagNavList.filter(item => routeEqual(item, route)) 72 | route = tag[0] ? tag[0] : null 73 | if (!route) return 74 | closePage(state, route) 75 | }, 76 | addTag (state, { route, type = 'unshift' }) { 77 | let router = getRouteTitleHandled(route) 78 | if (!routeHasExist(state.tagNavList, router)) { 79 | if (type === 'push') state.tagNavList.push(router) 80 | else { 81 | if (router.name === homeName) state.tagNavList.unshift(router) 82 | else state.tagNavList.splice(1, 0, router) 83 | } 84 | setTagNavListInLocalstorage([...state.tagNavList]) 85 | } 86 | }, 87 | setLocal (state, lang) { 88 | localSave('local', lang) 89 | state.local = lang 90 | }, 91 | addError (state, error) { 92 | state.errorList.push(error) 93 | }, 94 | setHasReadErrorLoggerStatus (state, status = true) { 95 | state.hasReadErrorPage = status 96 | } 97 | }, 98 | actions: { 99 | addErrorLog ({ commit, rootState }, info) { 100 | if (!window.location.href.includes('error_logger_page')) { 101 | commit('setHasReadErrorLoggerStatus', false) 102 | } 103 | const { 104 | user: { token, userId, userName } 105 | } = rootState 106 | let data = { 107 | ...info, 108 | time: Date.parse(new Date()), 109 | token, 110 | userId, 111 | userName 112 | } 113 | saveErrorLogger(info).then(() => { 114 | commit('addError', data) 115 | }) 116 | } 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /src/store/module/user.js: -------------------------------------------------------------------------------- 1 | import { login, logout, getUserInfo } from '@/api/user' 2 | import { setToken, getToken, localSave } from '@/libs/util' 3 | import { initRouter } from '@/libs/router-util' // ①新增 引入动态菜单渲染 4 | export default { 5 | state: { 6 | userName: '', 7 | userId: '', 8 | avatarImgPath: '', 9 | token: getToken(), 10 | access: '', 11 | hasGetInfo: false, 12 | unreadCount: 0 13 | }, 14 | mutations: { 15 | setAvatar (state, avatarPath) { 16 | state.avatarImgPath = avatarPath 17 | }, 18 | setUserId (state, id) { 19 | state.userId = id 20 | }, 21 | setUserName (state, name) { 22 | state.userName = name 23 | }, 24 | setAccess (state, access) { 25 | state.access = access 26 | }, 27 | setToken (state, token) { 28 | state.token = token 29 | setToken(token) 30 | }, 31 | setHasGetInfo (state, status) { 32 | state.hasGetInfo = status 33 | } 34 | }, 35 | getters: {}, 36 | actions: { 37 | // 登录 38 | handleLogin ({ commit }, { userName, password }) { 39 | userName = userName.trim() 40 | return new Promise((resolve, reject) => { 41 | login({ 42 | userName, 43 | password 44 | }) 45 | .then(res => { 46 | const data = res.data 47 | commit('setToken', data.token) 48 | initRouter() 49 | resolve() 50 | }) 51 | .catch(err => { 52 | reject(err) 53 | }) 54 | }) 55 | }, 56 | // 退出登录 57 | handleLogOut ({ state, commit }) { 58 | return new Promise((resolve, reject) => { 59 | logout(state.token) 60 | .then(res => { 61 | console.log('退出', res) 62 | commit('setToken', '') 63 | commit('setAccess', []) 64 | localSave('dynamicRouter', []) // 清空本地路由 65 | resolve() 66 | }) 67 | .catch(err => { 68 | reject(err) 69 | }) 70 | // 如果你的退出登录无需请求接口,则可以直接使用下面三行代码而无需使用logout调用接口 71 | // commit('setToken', '') 72 | // commit('setAccess', []) 73 | // resolve() 74 | }) 75 | }, 76 | // 获取用户相关信息 77 | getUserInfo ({ state, commit }) { 78 | return new Promise((resolve, reject) => { 79 | try { 80 | getUserInfo(state.token) 81 | .then(res => { 82 | const data = res.data 83 | commit('setAvatar', data.avatar) 84 | commit('setUserName', data.name) 85 | commit('setUserId', data.user_id) 86 | commit('setAccess', data.access) 87 | commit('setHasGetInfo', true) 88 | resolve(data) 89 | }) 90 | .catch(err => { 91 | reject(err) 92 | }) 93 | } catch (error) { 94 | reject(error) 95 | } 96 | }) 97 | } 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /src/view/argu-page/params.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 33 | 34 | 37 | -------------------------------------------------------------------------------- /src/view/argu-page/query.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 33 | 34 | 37 | -------------------------------------------------------------------------------- /src/view/error-page/401.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 20 | -------------------------------------------------------------------------------- /src/view/error-page/404.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 20 | -------------------------------------------------------------------------------- /src/view/error-page/500.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 20 | -------------------------------------------------------------------------------- /src/view/error-page/back-btn-group.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 39 | -------------------------------------------------------------------------------- /src/view/error-page/error-content.vue: -------------------------------------------------------------------------------- 1 | 13 | 14 | 29 | -------------------------------------------------------------------------------- /src/view/error-page/error.less: -------------------------------------------------------------------------------- 1 | .error-page{ 2 | width: 100%; 3 | height: 100%; 4 | position: relative; 5 | background: #f8f8f9; 6 | .content-con{ 7 | width: 700px; 8 | height: 600px; 9 | position: absolute; 10 | left: 50%; 11 | top: 50%; 12 | transform: translate(-50%, -60%); 13 | img{ 14 | display: block; 15 | width: 100%; 16 | height: 100%; 17 | } 18 | .text-con{ 19 | position: absolute; 20 | left: 0px; 21 | top: 0px; 22 | h4{ 23 | position: absolute; 24 | left: 0px; 25 | top: 0px; 26 | font-size: 80px; 27 | font-weight: 700; 28 | color: #348EED; 29 | } 30 | h5{ 31 | position: absolute; 32 | width: 700px; 33 | left: 0px; 34 | top: 100px; 35 | font-size: 20px; 36 | font-weight: 700; 37 | color: #67647D; 38 | } 39 | } 40 | .back-btn-group{ 41 | position: absolute; 42 | right: 0px; 43 | bottom: 20px; 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/view/linux/memory.vue: -------------------------------------------------------------------------------- 1 | 23 | 24 | 118 | 119 | 147 | -------------------------------------------------------------------------------- /src/view/login/login.less: -------------------------------------------------------------------------------- 1 | .login{ 2 | width: 100%; 3 | height: 100%; 4 | background-image: url('../../assets/images/login-bg.jpg'); 5 | background-size: cover; 6 | background-position: center; 7 | position: relative; 8 | &-con{ 9 | position: absolute; 10 | right: 160px; 11 | top: 50%; 12 | transform: translateY(-60%); 13 | width: 300px; 14 | &-header{ 15 | font-size: 16px; 16 | font-weight: 300; 17 | text-align: center; 18 | padding: 30px 0; 19 | } 20 | .form-con{ 21 | padding: 10px 0 0; 22 | } 23 | .login-tip{ 24 | font-size: 10px; 25 | text-align: center; 26 | color: #c3c3c3; 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/view/login/login.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 19 | 20 | 52 | 53 | 55 | -------------------------------------------------------------------------------- /src/view/multilevel/level-2-1.vue: -------------------------------------------------------------------------------- 1 | 6 | 15 | -------------------------------------------------------------------------------- /src/view/mysql/alert-log.vue: -------------------------------------------------------------------------------- 1 | 40 | 41 | 143 | 163 | -------------------------------------------------------------------------------- /src/view/mysql/slowquery-log.vue: -------------------------------------------------------------------------------- 1 | 22 | 23 | 155 | 175 | -------------------------------------------------------------------------------- /src/view/oracle/alert-log.vue: -------------------------------------------------------------------------------- 1 | 42 | 43 | 151 | 171 | -------------------------------------------------------------------------------- /src/view/oracle/table-stats.vue: -------------------------------------------------------------------------------- 1 | 25 | 26 | 132 | 152 | -------------------------------------------------------------------------------- /src/view/oracle/top-sql.vue: -------------------------------------------------------------------------------- 1 | 40 | 41 | 169 | 189 | -------------------------------------------------------------------------------- /src/view/redis/alert-log.vue: -------------------------------------------------------------------------------- 1 | 40 | 41 | 143 | 163 | -------------------------------------------------------------------------------- /src/view/redis/clientlist.vue: -------------------------------------------------------------------------------- 1 | 19 | 20 | 165 | 185 | -------------------------------------------------------------------------------- /src/view/redis/command-stats.vue: -------------------------------------------------------------------------------- 1 | 25 | 26 | 103 | 104 | 132 | -------------------------------------------------------------------------------- /src/view/redis/config.vue: -------------------------------------------------------------------------------- 1 | 29 | 30 | 114 | 134 | -------------------------------------------------------------------------------- /src/view/redis/immediate-stats.vue: -------------------------------------------------------------------------------- 1 | 19 | 20 | 111 | 131 | -------------------------------------------------------------------------------- /src/view/redis/slowlog.vue: -------------------------------------------------------------------------------- 1 | 19 | 20 | 113 | 133 | -------------------------------------------------------------------------------- /src/view/system/alarm-info.vue: -------------------------------------------------------------------------------- 1 | 21 | 22 | 106 | 126 | -------------------------------------------------------------------------------- /src/view/system/home/index.js: -------------------------------------------------------------------------------- 1 | import home from './home.vue' 2 | export default home 3 | -------------------------------------------------------------------------------- /tests/e2e/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": [ 3 | "cypress" 4 | ], 5 | "env": { 6 | "mocha": true, 7 | "cypress/globals": true 8 | }, 9 | "rules": { 10 | "strict": "off" 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /tests/e2e/plugins/index.js: -------------------------------------------------------------------------------- 1 | // https://docs.cypress.io/guides/guides/plugins-guide.html 2 | 3 | module.exports = (on, config) => Object.assign({}, config, { 4 | fixturesFolder: 'tests/e2e/fixtures', 5 | integrationFolder: 'tests/e2e/specs', 6 | screenshotsFolder: 'tests/e2e/screenshots', 7 | videosFolder: 'tests/e2e/videos', 8 | supportFile: 'tests/e2e/support/index.js' 9 | }) 10 | -------------------------------------------------------------------------------- /tests/e2e/specs/test.js: -------------------------------------------------------------------------------- 1 | // https://docs.cypress.io/api/introduction/api.html 2 | 3 | describe('My First Test', () => { 4 | it('Visits the app root url', () => { 5 | cy.visit('/') 6 | cy.contains('h1', 'Welcome to Your Vue.js App') 7 | }) 8 | }) 9 | -------------------------------------------------------------------------------- /tests/e2e/support/commands.js: -------------------------------------------------------------------------------- 1 | // *********************************************** 2 | // This example commands.js shows you how to 3 | // create various custom commands and overwrite 4 | // existing commands. 5 | // 6 | // For more comprehensive examples of custom 7 | // commands please read more here: 8 | // https://on.cypress.io/custom-commands 9 | // *********************************************** 10 | // 11 | // 12 | // -- This is a parent command -- 13 | // Cypress.Commands.add("login", (email, password) => { ... }) 14 | // 15 | // 16 | // -- This is a child command -- 17 | // Cypress.Commands.add("drag", { prevSubject: 'element'}, (subject, options) => { ... }) 18 | // 19 | // 20 | // -- This is a dual command -- 21 | // Cypress.Commands.add("dismiss", { prevSubject: 'optional'}, (subject, options) => { ... }) 22 | // 23 | // 24 | // -- This is will overwrite an existing command -- 25 | // Cypress.Commands.overwrite("visit", (originalFn, url, options) => { ... }) 26 | -------------------------------------------------------------------------------- /tests/e2e/support/index.js: -------------------------------------------------------------------------------- 1 | // *********************************************************** 2 | // This example support/index.js is processed and 3 | // loaded automatically before your test files. 4 | // 5 | // This is a great place to put global configuration and 6 | // behavior that modifies Cypress. 7 | // 8 | // You can change the location of this file or turn off 9 | // automatically serving support files with the 10 | // 'supportFile' configuration option. 11 | // 12 | // You can read more here: 13 | // https://on.cypress.io/configuration 14 | // *********************************************************** 15 | 16 | // Import commands.js using ES2015 syntax: 17 | import './commands' 18 | 19 | // Alternatively you can use CommonJS syntax: 20 | // require('./commands') 21 | -------------------------------------------------------------------------------- /tests/unit/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | env: { 3 | mocha: true 4 | }, 5 | rules: { 6 | 'import/no-extraneous-dependencies': 'off' 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /tests/unit/HelloWorld.spec.js: -------------------------------------------------------------------------------- 1 | import { expect } from 'chai' 2 | import { shallow } from '@vue/test-utils' 3 | import HelloWorld from '@/components/HelloWorld.vue' 4 | 5 | describe('HelloWorld.vue', () => { 6 | it('renders props.msg when passed', () => { 7 | const msg = 'new message' 8 | const wrapper = shallow(HelloWorld, { 9 | propsData: { msg } 10 | }) 11 | expect(wrapper.text()).to.include(msg) 12 | }) 13 | }) 14 | -------------------------------------------------------------------------------- /vue.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | 3 | const resolve = dir => { 4 | return path.join(__dirname, dir) 5 | } 6 | 7 | // 项目部署基础 8 | // 默认情况下,我们假设你的应用将被部署在域的根目录下, 9 | // 例如:https://www.my-app.com/ 10 | // 默认:'/' 11 | // 如果您的应用程序部署在子路径中,则需要在这指定子路径 12 | // 例如:https://www.foobar.com/my-app/ 13 | // 需要将它改为'/my-app/' 14 | // iview-admin线上演示打包路径: https://file.iviewui.com/admin-dist/ 15 | const BASE_URL = process.env.NODE_ENV === 'production' 16 | ? '/' 17 | : '/' 18 | 19 | module.exports = { 20 | // Project deployment base 21 | // By default we assume your app will be deployed at the root of a domain, 22 | // e.g. https://www.my-app.com/ 23 | // If your app is deployed at a sub-path, you will need to specify that 24 | // sub-path here. For example, if your app is deployed at 25 | // https://www.foobar.com/my-app/ 26 | // then change this to '/my-app/' 27 | baseUrl: BASE_URL, 28 | // tweak internal webpack configuration. 29 | // see https://github.com/vuejs/vue-cli/blob/dev/docs/webpack.md 30 | // 如果你不需要使用eslint,把lintOnSave设为false即可 31 | lintOnSave: true, 32 | chainWebpack: config => { 33 | config.resolve.alias 34 | .set('@', resolve('src')) // key,value自行定义,比如.set('@@', resolve('src/components')) 35 | .set('_c', resolve('src/components')) 36 | }, 37 | // 设为false打包时不生成.map文件 38 | productionSourceMap: false, 39 | // 这里写你调用接口的基础路径,来解决跨域,如果设置了代理,那你本地开发环境的axios的baseUrl要写为 '' ,即空字符串 40 | // devServer: { 41 | // proxy: 'localhost:3000' 42 | // } 43 | devServer: { 44 | host: '0.0.0.0', 45 | hot: true, 46 | disableHostCheck: true 47 | } 48 | 49 | } 50 | --------------------------------------------------------------------------------