├── .editorconfig
├── .env.development
├── .env.production
├── .env.staging
├── .eslintignore
├── .eslintrc.js
├── .gitignore
├── .travis.yml
├── LICENSE
├── README.md
├── babel.config.js
├── build
└── index.js
├── dist
├── index.html
└── static
│ ├── css
│ ├── app.cda1ed7c.css
│ ├── chunk-4028b836.64c5c8b4.css
│ ├── chunk-768ebd2f.a1c9ad1b.css
│ ├── chunk-cbb61e6a.6e6cbd15.css
│ ├── chunk-d7a7d948.5719ffb1.css
│ ├── chunk-elementUI.18b11d0e.css
│ ├── chunk-f1a6febe.2f3c92ef.css
│ ├── chunk-f8cee08e.305e1e16.css
│ └── chunk-libs.6d232b10.css
│ ├── fonts
│ ├── element-icons.2fad952a.woff
│ ├── element-icons.6f0a7632.ttf
│ ├── fontawesome-webfont.674f50d2.eot
│ ├── fontawesome-webfont.af7ae505.woff2
│ ├── fontawesome-webfont.b06871f2.ttf
│ └── fontawesome-webfont.fee66e71.woff
│ ├── img
│ ├── favicon.ico
│ ├── fontawesome-webfont.912ec66d.svg
│ └── logo.d5e2a9f1.png
│ └── js
│ ├── app.cd0f044f.js
│ ├── chunk-2d230fe7.1db2b25c.js
│ ├── chunk-4028b836.b239e86a.js
│ ├── chunk-73e109b0.c2b18a1b.js
│ ├── chunk-768ebd2f.9c519e42.js
│ ├── chunk-cbb61e6a.921b9935.js
│ ├── chunk-d7a7d948.57e2af3f.js
│ ├── chunk-elementUI.03eb003b.js
│ ├── chunk-f1a6febe.52c245c4.js
│ ├── chunk-f8cee08e.78f2e4d8.js
│ └── chunk-libs.951c1a79.js
├── jest.config.js
├── jsconfig.json
├── mock
├── article.js
├── finance.js
├── index.js
├── mock-server.js
├── table.js
└── user.js
├── package.json
├── postcss.config.js
├── public
├── index.html
└── static
│ └── img
│ └── favicon.ico
├── src
├── App.vue
├── api
│ ├── article.js
│ ├── table.js
│ └── user.js
├── assets
│ ├── 401_images
│ │ └── 401.gif
│ ├── 404_images
│ │ ├── 404.png
│ │ └── 404_cloud.png
│ ├── custom-theme
│ │ ├── fonts
│ │ │ ├── element-icons.ttf
│ │ │ └── element-icons.woff
│ │ └── index.css
│ └── logo.png
├── components
│ ├── Breadcrumb
│ │ └── index.vue
│ ├── Hamburger
│ │ └── index.vue
│ ├── Pagination
│ │ └── index.vue
│ ├── Screenfull
│ │ └── index.vue
│ └── SvgIcon
│ │ └── index.vue
├── directive
│ └── waves
│ │ ├── index.js
│ │ ├── waves.css
│ │ └── waves.js
├── icons
│ ├── index.js
│ ├── svg
│ │ ├── 404.svg
│ │ ├── bug.svg
│ │ ├── chart.svg
│ │ ├── clipboard.svg
│ │ ├── component.svg
│ │ ├── dashboard.svg
│ │ ├── documentation.svg
│ │ ├── drag.svg
│ │ ├── edit.svg
│ │ ├── education.svg
│ │ ├── email.svg
│ │ ├── example.svg
│ │ ├── excel.svg
│ │ ├── exit-fullscreen.svg
│ │ ├── eye-open.svg
│ │ ├── eye.svg
│ │ ├── form.svg
│ │ ├── fullscreen.svg
│ │ ├── guide.svg
│ │ ├── icon.svg
│ │ ├── international.svg
│ │ ├── language.svg
│ │ ├── link.svg
│ │ ├── list.svg
│ │ ├── lock.svg
│ │ ├── message.svg
│ │ ├── money.svg
│ │ ├── nested.svg
│ │ ├── password.svg
│ │ ├── pdf.svg
│ │ ├── people.svg
│ │ ├── peoples.svg
│ │ ├── qq.svg
│ │ ├── search.svg
│ │ ├── shopping.svg
│ │ ├── size.svg
│ │ ├── skill.svg
│ │ ├── star.svg
│ │ ├── tab.svg
│ │ ├── table.svg
│ │ ├── theme.svg
│ │ ├── tree-table.svg
│ │ ├── tree.svg
│ │ ├── user.svg
│ │ ├── wechat.svg
│ │ └── zip.svg
│ └── svgo.yml
├── layout
│ ├── components
│ │ ├── AppMain.vue
│ │ ├── Navbar.vue
│ │ ├── Sidebar
│ │ │ ├── FixiOSBug.js
│ │ │ ├── Item.vue
│ │ │ ├── Link.vue
│ │ │ ├── Logo.vue
│ │ │ ├── SidebarItem.vue
│ │ │ └── index.vue
│ │ ├── TagsView
│ │ │ ├── ScrollPane.vue
│ │ │ └── index.vue
│ │ └── index.js
│ ├── index.vue
│ └── mixin
│ │ └── ResizeHandler.js
├── main.js
├── permission.js
├── router
│ └── index.js
├── settings.js
├── store
│ ├── getters.js
│ ├── index.js
│ └── modules
│ │ ├── app.js
│ │ ├── permission.js
│ │ ├── settings.js
│ │ ├── tagsView.js
│ │ └── user.js
├── styles
│ ├── element-ui.scss
│ ├── index.scss
│ ├── mixin.scss
│ ├── sidebar.scss
│ ├── transition.scss
│ └── variables.scss
├── utils
│ ├── auth.js
│ ├── get-page-title.js
│ ├── index.js
│ ├── request.js
│ ├── scroll-to.js
│ └── validate.js
├── vendor
│ ├── Export2Excel.js
│ └── Export2Zip.js
└── views
│ ├── 404.vue
│ ├── dashboard
│ └── index.vue
│ ├── documentation
│ ├── details.vue
│ └── index.vue
│ ├── editor
│ ├── index.scss
│ ├── index.vue
│ └── mixin.js
│ ├── financialQuery
│ └── balance.vue
│ ├── login
│ └── index.vue
│ ├── nested
│ ├── menu1
│ │ ├── index.vue
│ │ ├── menu1-1
│ │ │ └── index.vue
│ │ ├── menu1-2
│ │ │ ├── index.vue
│ │ │ ├── menu1-2-1
│ │ │ │ └── index.vue
│ │ │ └── menu1-2-2
│ │ │ │ └── index.vue
│ │ └── menu1-3
│ │ │ └── index.vue
│ └── menu2
│ │ └── index.vue
│ └── redirect
│ └── index.vue
├── static
├── css
│ ├── app.7c98ca2f.css
│ ├── chunk-575555d9.96b835c7.css
│ ├── chunk-768ebd2f.a1c9ad1b.css
│ ├── chunk-cbb61e6a.6e6cbd15.css
│ ├── chunk-d7a7d948.5719ffb1.css
│ ├── chunk-elementUI.18b11d0e.css
│ ├── chunk-f1a6febe.2f3c92ef.css
│ └── chunk-libs.6d232b10.css
├── fonts
│ ├── element-icons.2fad952a.woff
│ ├── element-icons.6f0a7632.ttf
│ ├── fontawesome-webfont.674f50d2.eot
│ ├── fontawesome-webfont.af7ae505.woff2
│ ├── fontawesome-webfont.b06871f2.ttf
│ └── fontawesome-webfont.fee66e71.woff
├── img
│ ├── favicon.ico
│ ├── fontawesome-webfont.912ec66d.svg
│ └── logo.7ec6731e.png
└── js
│ ├── app.3c8504dc.js
│ ├── chunk-2d0da8f7.37c90bb0.js
│ ├── chunk-2d21446b.65936c26.js
│ ├── chunk-575555d9.a6bafad6.js
│ ├── chunk-73e109b0.c2b18a1b.js
│ ├── chunk-768ebd2f.3a755ac3.js
│ ├── chunk-cbb61e6a.eb74048e.js
│ ├── chunk-d7a7d948.06e0cdfa.js
│ ├── chunk-elementUI.03eb003b.js
│ ├── chunk-f1a6febe.6af28b13.js
│ └── chunk-libs.983c21dd.js
├── tests
└── unit
│ ├── .eslintrc.js
│ ├── components
│ ├── Breadcrumb.spec.js
│ ├── Hamburger.spec.js
│ └── SvgIcon.spec.js
│ └── utils
│ ├── formatTime.spec.js
│ ├── parseTime.spec.js
│ └── validate.spec.js
└── vue.config.js
/.editorconfig:
--------------------------------------------------------------------------------
1 | # http://editorconfig.org
2 | root = true
3 |
4 | [*]
5 | charset = utf-8
6 | indent_style = space
7 | indent_size = 2
8 | end_of_line = lf
9 | insert_final_newline = true
10 | trim_trailing_whitespace = true
11 |
12 | [*.md]
13 | insert_final_newline = false
14 | trim_trailing_whitespace = false
15 |
--------------------------------------------------------------------------------
/.env.development:
--------------------------------------------------------------------------------
1 | # just a flag
2 | ENV = 'development'
3 |
4 | # base api
5 | # VUE_APP_BASE_API = '/dev-api'
6 | VUE_APP_BASE_API = '/dev-api'
7 |
8 | # vue-cli uses the VUE_CLI_BABEL_TRANSPILE_MODULES environment variable,
9 | # to control whether the babel-plugin-dynamic-import-node plugin is enabled.
10 | # It only does one thing by converting all import() to require().
11 | # This configuration can significantly increase the speed of hot updates,
12 | # when you have a large number of pages.
13 | # Detail: https://github.com/vuejs/vue-cli/blob/dev/packages/@vue/babel-preset-app/index.js
14 |
15 | VUE_CLI_BABEL_TRANSPILE_MODULES = true
16 |
--------------------------------------------------------------------------------
/.env.production:
--------------------------------------------------------------------------------
1 | # just a flag
2 | ENV = 'production'
3 |
4 | # base api
5 | VUE_APP_BASE_API = '/prod-api'
6 |
7 |
--------------------------------------------------------------------------------
/.env.staging:
--------------------------------------------------------------------------------
1 | NODE_ENV = production
2 |
3 | # just a flag
4 | ENV = 'staging'
5 |
6 | # base api
7 | VUE_APP_BASE_API = '/dev-api'
8 |
9 |
--------------------------------------------------------------------------------
/.eslintignore:
--------------------------------------------------------------------------------
1 | build/*.js
2 | src/assets
3 | public
4 | dist
5 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules/
3 | npm-debug.log*
4 | yarn-debug.log*
5 | yarn-error.log*
6 | package-lock.json
7 | tests/**/coverage/
8 |
9 | # Editor directories and files
10 | .idea
11 | .vscode
12 | *.suo
13 | *.ntvs*
14 | *.njsproj
15 | *.sln
16 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | node_js: 10
3 | script: npm run test
4 | notifications:
5 | email: false
6 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017-present PanJiaChen
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 | # vue-element-admin-g6-editor
2 | 基于vue-element-admin框架模板集成了g6-editor,保留了vue-element-admin模板,没有多余的组件代码
3 |
4 | # 克隆项目
5 | git clone https://github.com/zhangwenwu/vue-element-admin-g6-editor.git
6 |
7 | # 进入项目目录
8 | cd vue-element-admin-g6-editor
9 |
10 | # 安装依赖
11 | npm install
12 |
13 | # 建议不要直接使用 cnpm 安装以来,会有各种诡异的 bug。可以通过如下操作解决 npm 下载速度慢的问题
14 | npm install --registry=https://registry.npm.taobao.org
15 |
16 | # 启动服务
17 | npm run dev
18 | ```
19 |
20 | 浏览器访问 [http://localhost:8888](http://localhost:8888)
21 |
22 | ## 发布
23 |
24 | ```bash
25 | # 构建测试环境
26 | npm run build:stage
27 |
28 | # 构建生产环境
29 | npm run build:prod
--------------------------------------------------------------------------------
/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | presets: [
3 | '@vue/app'
4 | ]
5 | }
6 |
--------------------------------------------------------------------------------
/build/index.js:
--------------------------------------------------------------------------------
1 | const { run } = require('runjs')
2 | const chalk = require('chalk')
3 | const config = require('../vue.config.js')
4 | const rawArgv = process.argv.slice(2)
5 | const args = rawArgv.join(' ')
6 |
7 | if (process.env.npm_config_preview || rawArgv.includes('--preview')) {
8 | const report = rawArgv.includes('--report')
9 |
10 | run(`vue-cli-service build ${args}`)
11 |
12 | const port = 9526
13 | const publicPath = config.publicPath
14 |
15 | var connect = require('connect')
16 | var serveStatic = require('serve-static')
17 | const app = connect()
18 |
19 | app.use(
20 | publicPath,
21 | serveStatic('./dist', {
22 | index: ['index.html', '/']
23 | })
24 | )
25 |
26 | app.listen(port, function () {
27 | console.log(chalk.green(`> Preview at http://localhost:${port}${publicPath}`))
28 | if (report) {
29 | console.log(chalk.green(`> Report at http://localhost:${port}${publicPath}report.html`))
30 | }
31 |
32 | })
33 | } else {
34 | run(`vue-cli-service build ${args}`)
35 | }
36 |
--------------------------------------------------------------------------------
/dist/index.html:
--------------------------------------------------------------------------------
1 |
资源统筹系统
--------------------------------------------------------------------------------
/dist/static/css/chunk-4028b836.64c5c8b4.css:
--------------------------------------------------------------------------------
1 | .pagination-container[data-v-6af373ef]{background:#fff;padding:32px 16px}.pagination-container.hidden[data-v-6af373ef]{display:none}.createPost-main-container{padding:40px 45px 20px 50px}.balance .el-table .cell{white-space:nowrap!important}
--------------------------------------------------------------------------------
/dist/static/css/chunk-768ebd2f.a1c9ad1b.css:
--------------------------------------------------------------------------------
1 | #vue-g6-editor .database{overflow:hidden}#vue-g6-editor .el-menu{background-color:#fbfbfb}#vue-g6-editor .el-submenu__title{height:35px;line-height:35px}#vue-g6-editor header:first-of-type{background:#fbfbfb;line-height:40px;padding-left:20px;border-bottom:1px solid #dadce0;-webkit-box-sizing:border-box;box-sizing:border-box}#vue-g6-editor #toolbar{background:#fbfbfb;border-bottom:1px solid #dadce0;padding:4px 14px}#vue-g6-editor #toolbar i{font-size:15px;padding:4px;margin-right:8px;color:#333}#vue-g6-editor #toolbar i:hover{cursor:pointer;background-color:#eee;color:#5cb6ff}#vue-g6-editor #itempannel{-webkit-box-sizing:border-box;box-sizing:border-box;background-color:#f7f9fb;border-right:1px solid #dadce0;height:calc(100vh - 78px);padding-top:10px;overflow:hidden;display:inherit;-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-direction:row;flex-direction:row;-ms-flex-wrap:wrap;flex-wrap:wrap;-ms-flex-pack:distribute;justify-content:space-around;-ms-flex-line-pack:start;align-content:flex-start}#vue-g6-editor #itempannel .getItem{color:rgba(0,0,0,.65);border-radius:4px;height:28px;line-height:26px;padding-left:8px;list-style-type:none;font-size:12px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}#vue-g6-editor #page{height:calc(71vh - 78px)}#vue-g6-editor #page canvas{display:block;width:100%}#vue-g6-editor .right-part{height:calc(100vh - 78px);display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;-webkit-box-pack:start;-ms-flex-pack:start;justify-content:flex-start}#vue-g6-editor #detailpannel{-webkit-box-flex:1;-ms-flex-positive:1;flex-grow:1;background-color:#fbfbfb;border-left:1px solid #dadce0;overflow-y:scroll}#vue-g6-editor #detailpannel #canvasAttributeBar .title,#vue-g6-editor #detailpannel #edgeAttributeBar .title,#vue-g6-editor #detailpannel #groupAttributeBar .title,#vue-g6-editor #detailpannel #multiAttributeBar .title,#vue-g6-editor #detailpannel #nodeAttributeBar .title{height:34px;line-height:34px;text-align:center;-webkit-box-sizing:border-box;box-sizing:border-box;font-weight:700;font-size:13px;border-width:0 0 1px 0;border-style:solid;border-color:#dadce0}#vue-g6-editor #detailpannel #canvasAttributeBar .main,#vue-g6-editor #detailpannel #edgeAttributeBar .main,#vue-g6-editor #detailpannel #groupAttributeBar .main,#vue-g6-editor #detailpannel #multiAttributeBar .main,#vue-g6-editor #detailpannel #nodeAttributeBar .main{padding:10px}#vue-g6-editor #minimap{background-color:#fbfbfb;border-top:1px solid #ccc;border-left:1px solid #ccc}#vue-g6-editor #minimap .title{height:34px;line-height:34px;text-align:center;-webkit-box-sizing:border-box;box-sizing:border-box;font-weight:700;font-size:13px;border-width:0 0 1px 0;border-style:solid;border-color:#dadce0}#vue-g6-editor #contextmenu{display:none}#vue-g6-editor #contextmenu .menu .el-button{width:100%;display:block;margin-left:0;border-radius:0!important;border-bottom:none}#vue-g6-editor #contextmenu .menu .el-button:last-of-type{border-bottom:1px solid #dcdfe6}#vue-g6-editor .save-as-image-dialog .el-select{display:block}#vue-g6-editor .el-pagination{text-align:center}#vue-g6-editor .el-table--medium td,#vue-g6-editor .el-table--medium th{padding:5px 0}#vue-g6-editor .el-table{height:calc(40vh - 78px)!important}.itempannel ul{padding:0;padding-left:16px;border-bottom:1px solid #ccc;padding-bottom:20px}.itempannel li{color:rgba(0,0,0,.65);border-radius:4px;height:28px;line-height:26px;padding-left:8px;border:1px solid transparent;list-style-type:none;font-size:12px}.itempannel li,.itempannel li:hover{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.itempannel li:hover{width:160px}.itempanel li:hover,.itempannel li:hover{background:#fff;border:1px solid #ced4d9;cursor:move}.itempannel .icon{width:16px;height:16px;display:inline-block;vertical-align:middle;margin-right:8px;font-size:14px;background:url(https://gw.alipayobjects.com/zos/rmsportal/czNEJAmyDpclFaSucYWB.svg)}.itempannel h6{font-size:15px;text-align:center;padding:0;margin:0;margin-bottom:14px}.itempannel i{margin-right:10px;margin-left:-10px}
--------------------------------------------------------------------------------
/dist/static/css/chunk-cbb61e6a.6e6cbd15.css:
--------------------------------------------------------------------------------
1 | .knowledge[data-v-74c84609]{padding-top:50px}.knowledge h3[data-v-74c84609]{text-align:center}.knowledge h3 span[data-v-74c84609]{font-size:20px}.knowledge .el-row[data-v-74c84609]{margin-bottom:20px}.knowledge .el-button--primary[data-v-74c84609]{background-color:#0d5391;border-color:#0d5391}
--------------------------------------------------------------------------------
/dist/static/css/chunk-d7a7d948.5719ffb1.css:
--------------------------------------------------------------------------------
1 | .dashboard-container[data-v-682337c0]{margin:30px}.dashboard-text[data-v-682337c0]{font-size:30px;line-height:46px}
--------------------------------------------------------------------------------
/dist/static/css/chunk-f1a6febe.2f3c92ef.css:
--------------------------------------------------------------------------------
1 | .knowledgeDetails[data-v-2636a9b4]{padding-top:10px}.knowledgeDetails .fa-fw[data-v-2636a9b4]{margin-right:5px}.knowledgeDetails .grid-content[data-v-2636a9b4]{height:calc(100vh - 80px)}.knowledgeDetails .grid-content .article[data-v-2636a9b4]{text-indent:30px;line-height:25px;font-size:14px}.knowledgeDetails .grid-content .el-card[data-v-2636a9b4]{height:100%}.knowledgeDetails .grid-content .el-tree[data-v-2636a9b4],.knowledgeDetails .grid-content .text[data-v-2636a9b4]{font-size:14px}.knowledgeDetails .grid-content .item[data-v-2636a9b4]{margin-bottom:18px}.knowledgeDetails .grid-content .clearfix[data-v-2636a9b4]:after,.knowledgeDetails .grid-content .clearfix[data-v-2636a9b4]:before{display:table;content:""}.knowledgeDetails .grid-content .clearfix[data-v-2636a9b4]:after{clear:both}.knowledgeDetails .lists li[data-v-2636a9b4]{list-style:none;margin-bottom:10px}.knowledgeDetails h3[data-v-2636a9b4]{text-align:center}.knowledgeDetails h3 span[data-v-2636a9b4]{font-size:20px}.knowledgeDetails .el-row[data-v-2636a9b4]{margin-bottom:20px}
--------------------------------------------------------------------------------
/dist/static/css/chunk-f8cee08e.305e1e16.css:
--------------------------------------------------------------------------------
1 | @supports (-webkit-mask:none) and (not (cater-color:#fff)){.login-container .el-input input{color:#fff}}.login-container .el-input{display:inline-block;height:47px;width:85%}.login-container .el-input input{background:transparent;border:0;-webkit-appearance:none;border-radius:0;padding:12px 5px 12px 15px;color:#fff;height:47px;caret-color:#fff}.login-container .el-input input:-webkit-autofill{-webkit-box-shadow:0 0 0 1000px #283443 inset!important;box-shadow:inset 0 0 0 1000px #283443!important;-webkit-text-fill-color:#fff!important}.login-container .el-form-item{border:1px solid hsla(0,0%,100%,.1);background:rgba(0,0,0,.1);border-radius:5px;color:#454545}.login-container[data-v-9ea6a6a6]{min-height:100%;width:100%;background-color:#2d3a4b;overflow:hidden}.login-container .login-form[data-v-9ea6a6a6]{position:relative;width:520px;max-width:100%;padding:160px 35px 0;margin:0 auto;overflow:hidden}.login-container .tips[data-v-9ea6a6a6]{font-size:14px;color:#fff;margin-bottom:10px}.login-container .tips span[data-v-9ea6a6a6]:first-of-type{margin-right:16px}.login-container .svg-container[data-v-9ea6a6a6]{padding:6px 5px 6px 15px;color:#889aa4;vertical-align:middle;width:30px;display:inline-block}.login-container .title-container[data-v-9ea6a6a6]{position:relative}.login-container .title-container .title[data-v-9ea6a6a6]{font-size:26px;color:#eee;margin:0 auto 40px auto;text-align:center;font-weight:700}.login-container .show-pwd[data-v-9ea6a6a6]{position:absolute;right:10px;top:7px;font-size:16px;color:#889aa4;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}
--------------------------------------------------------------------------------
/dist/static/fonts/element-icons.2fad952a.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhangwenwu/vue-element-admin-g6-editor/582636f1b259b573a7a0df9ccb3f82013d282fbb/dist/static/fonts/element-icons.2fad952a.woff
--------------------------------------------------------------------------------
/dist/static/fonts/element-icons.6f0a7632.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhangwenwu/vue-element-admin-g6-editor/582636f1b259b573a7a0df9ccb3f82013d282fbb/dist/static/fonts/element-icons.6f0a7632.ttf
--------------------------------------------------------------------------------
/dist/static/fonts/fontawesome-webfont.674f50d2.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhangwenwu/vue-element-admin-g6-editor/582636f1b259b573a7a0df9ccb3f82013d282fbb/dist/static/fonts/fontawesome-webfont.674f50d2.eot
--------------------------------------------------------------------------------
/dist/static/fonts/fontawesome-webfont.af7ae505.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhangwenwu/vue-element-admin-g6-editor/582636f1b259b573a7a0df9ccb3f82013d282fbb/dist/static/fonts/fontawesome-webfont.af7ae505.woff2
--------------------------------------------------------------------------------
/dist/static/fonts/fontawesome-webfont.b06871f2.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhangwenwu/vue-element-admin-g6-editor/582636f1b259b573a7a0df9ccb3f82013d282fbb/dist/static/fonts/fontawesome-webfont.b06871f2.ttf
--------------------------------------------------------------------------------
/dist/static/fonts/fontawesome-webfont.fee66e71.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhangwenwu/vue-element-admin-g6-editor/582636f1b259b573a7a0df9ccb3f82013d282fbb/dist/static/fonts/fontawesome-webfont.fee66e71.woff
--------------------------------------------------------------------------------
/dist/static/img/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhangwenwu/vue-element-admin-g6-editor/582636f1b259b573a7a0df9ccb3f82013d282fbb/dist/static/img/favicon.ico
--------------------------------------------------------------------------------
/dist/static/img/logo.d5e2a9f1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhangwenwu/vue-element-admin-g6-editor/582636f1b259b573a7a0df9ccb3f82013d282fbb/dist/static/img/logo.d5e2a9f1.png
--------------------------------------------------------------------------------
/dist/static/js/chunk-2d230fe7.1db2b25c.js:
--------------------------------------------------------------------------------
1 | (window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-2d230fe7"],{ef3c:function(e,r,n){"use strict";n.r(r);n("a481");var t,u,a={created:function(){var e=this.$route,r=e.params,n=e.query,t=r.path;this.$router.replace({path:"/"+t,query:n})},render:function(e){return e()}},c=a,o=n("2877"),p=Object(o["a"])(c,t,u,!1,null,null,null);r["default"]=p.exports}}]);
--------------------------------------------------------------------------------
/dist/static/js/chunk-cbb61e6a.921b9935.js:
--------------------------------------------------------------------------------
1 | (window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-cbb61e6a"],{"25fa":function(t,e,a){"use strict";var i=a("d005"),s=a.n(i);s.a},"3c34":function(t,e,a){"use strict";a.r(e);var i=function(){var t=this,e=t.$createElement,a=t._self._c||e;return a("div",{staticClass:"knowledge"},[a("el-row",[a("el-col",{attrs:{span:24}},[a("div",{staticClass:"grid-content bg-purple-dark"},[a("h3",{staticClass:"title"},[t._v("数据"),a("span",[t._v("·")]),t._v("知识"),a("span",[t._v("·")]),t._v("智能")])])])],1),t._v(" "),a("el-row",{attrs:{gutter:20}},[a("el-col",{attrs:{span:12,offset:6}},[a("div",{staticClass:"grid-content bg-purple"},[a("div",[a("el-input",{staticClass:"input-with-select",attrs:{placeholder:"请输入内容"},model:{value:t.search,callback:function(e){t.search=e},expression:"search"}},[a("el-button",{attrs:{slot:"append",icon:"el-icon-search"},on:{click:t.enterSearch},slot:"append"})],1)],1)])])],1),t._v(" "),a("el-row",{attrs:{gutter:20}},[a("el-col",{attrs:{span:12,offset:6}},[a("el-button",{attrs:{type:"primary",size:"mini"}},[t._v("法律")]),t._v(" "),a("el-button",{attrs:{type:"primary",size:"mini"}},[t._v("法规")]),t._v(" "),a("el-button",{attrs:{type:"primary",size:"mini"}},[t._v("审计")]),t._v(" "),a("el-button",{attrs:{type:"primary",size:"mini"}},[t._v("工商")]),t._v(" "),a("el-button",{attrs:{type:"primary",size:"mini"}},[t._v("公司")])],1)],1),t._v(" "),a("el-dialog",{attrs:{visible:t.dialogPvVisible,title:"title"},on:{"update:visible":function(e){t.dialogPvVisible=e}}},[a("el-table",{staticStyle:{width:"100%"},attrs:{data:t.pvData,border:"",fit:"","highlight-current-row":""}},[a("el-table-column",{attrs:{prop:"key",label:"Channel"}}),t._v(" "),a("el-table-column",{attrs:{prop:"pv",label:"Pv"}})],1),t._v(" "),a("span",{staticClass:"dialog-footer",attrs:{slot:"footer"},slot:"footer"},[a("el-button",{attrs:{type:"primary"},on:{click:function(e){t.dialogPvVisible=!1}}},[t._v("取消")])],1)],1)],1)},s=[],l={data:function(){return{pvData:"",search:""}},created:function(){this.dialogPvVisible=!1},methods:{enterSearch:function(){this.$router.push({path:"/documentation/details/1"})}}},r=l,n=(a("25fa"),a("2877")),o=Object(n["a"])(r,i,s,!1,null,"74c84609",null);e["default"]=o.exports},d005:function(t,e,a){}}]);
--------------------------------------------------------------------------------
/dist/static/js/chunk-d7a7d948.57e2af3f.js:
--------------------------------------------------------------------------------
1 | (window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-d7a7d948"],{9406:function(t,a,s){"use strict";s.r(a);var n=function(){var t=this,a=t.$createElement,s=t._self._c||a;return s("div",{staticClass:"dashboard-container"},[s("div",{staticClass:"dashboard-text"},[t._v("用户名: "+t._s(t.name))]),t._v(" "),s("div",{staticClass:"dashboard-text"},[t._v("权限: "),t._l(t.roles,(function(a){return s("span",{key:a},[t._v(t._s(a))])}))],2)])},e=[],c=s("5530"),r=s("2f62"),d={name:"Dashboard",computed:Object(c["a"])({},Object(r["b"])(["name","roles"]))},o=d,i=(s("d117"),s("2877")),u=Object(i["a"])(o,n,e,!1,null,"682337c0",null);a["default"]=u.exports},d117:function(t,a,s){"use strict";var n=s("f250"),e=s.n(n);e.a},f250:function(t,a,s){}}]);
--------------------------------------------------------------------------------
/dist/static/js/chunk-f1a6febe.52c245c4.js:
--------------------------------------------------------------------------------
1 | (window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-f1a6febe"],{bd9d:function(t,a,e){"use strict";var l=e("cbfa"),s=e.n(l);s.a},cbfa:function(t,a,e){},dc0f:function(t,a,e){"use strict";e.r(a);var l=function(){var t=this,a=t.$createElement,e=t._self._c||a;return e("div",{staticClass:"knowledgeDetails"},[e("el-row",[e("el-col",{attrs:{span:4}},[e("div",{staticClass:"grid-content bg-purple-dark"},[e("el-card",{staticClass:"box-card"},[e("div",{staticClass:"clearfix",attrs:{slot:"header"},slot:"header"},[e("span",[t._v("------")])]),t._v(" "),e("el-tree",{attrs:{data:t.data,props:t.defaultProps,"default-expand-all":"true"},on:{"node-click":t.handleNodeClick},scopedSlots:t._u([{key:"default",fn:function(a){var l=a.node;return e("span",{staticClass:"custom-tree-node"},[e("span",[e("i",{staticClass:"fa fa-file-o fa-fw"}),t._v(t._s(l.label)+"\n ")])])}}])})],1)],1)]),t._v(" "),e("el-col",{attrs:{span:4}},[e("div",{staticClass:"grid-content bg-purple-dark",staticStyle:{"border-left":"0","border-right":"0"}},[e("el-card",{staticClass:"box-card"},[e("div",{staticClass:"clearfix",attrs:{slot:"header"},slot:"header"},[e("span",[t._v("关键字")])]),t._v(" "),t._l(4,(function(a){return e("div",{key:a,staticClass:"text item"},[t._v("\n "+t._s("列表内容 "+a)+"\n ")])}))],2)],1)]),t._v(" "),e("el-col",{attrs:{span:16}},[e("div",{staticClass:"grid-content bg-purple-dark"},[e("el-card",{staticClass:"box-card"},[e("div",{staticClass:"clearfix",attrs:{slot:"header"},slot:"header"},[e("span",[t._v("文章标题")])]),t._v(" "),e("div",{staticClass:"article"},[t._v("\n 中赢智数(广东)科技有限公司成立于2015年,以为政府及国有企业进行数据治理及大数据分析、数据咨询服务为核心业务及发展目标,为审计机关、检察院、纪委、财政、政府办公厅、工商等政府部门及国资委企业客户提供数据治理及数据分析产品及服务整体解决方案.公司成立产品研发中心、数据分析服务中心、实施交付中心等技术部门。用精湛的技术服务于广大客户并不断累积丰富的经验,为审计机关、教育从审计产品开发、实施及数据服务提供全方位的解决方案。\n "),e("br"),t._v("中赢智数(广东)科技有限公司成立于2015年,以为政府及国有企业进行数据治理及大数据分析、数据咨询服务为核心业务及发展目标,为审计机关、检察院、纪委、财政、政府办公厅、工商等政府部门及国资委企业客户提供数据治理及数据分析产品及服务整体解决方案。\n ")])])],1)])],1),t._v(" "),e("el-dialog",{attrs:{visible:t.dialogPvVisible,title:"title"},on:{"update:visible":function(a){t.dialogPvVisible=a}}},[e("el-table",{staticStyle:{width:"100%"},attrs:{data:t.pvData,border:"",fit:"","highlight-current-row":""}},[e("el-table-column",{attrs:{prop:"key",label:"Channel"}}),t._v(" "),e("el-table-column",{attrs:{prop:"pv",label:"Pv"}})],1),t._v(" "),e("span",{staticClass:"dialog-footer",attrs:{slot:"footer"},slot:"footer"},[e("el-button",{attrs:{type:"primary"},on:{click:function(a){t.dialogPvVisible=!1}}},[t._v("取消")])],1)],1)],1)},s=[],i={data:function(){return{pvData:"",search:"",data:[{label:"法规库",children:[{label:"审计法规"}]},{label:"案例库",children:[{label:"审计案例"},{label:"审计案例3"}]},{label:"刑法库",children:[{label:"审计案例"},{label:"审计案例"}]}],defaultProps:{children:"children",label:"label"}}},created:function(){this.dialogPvVisible=!1},methods:{enterSearch:function(){this.$router.push({path:"/documentation/details/1"})},handleNodeClick:function(t){console.log(t)}}},r=i,n=(e("bd9d"),e("2877")),o=Object(n["a"])(r,l,s,!1,null,"2636a9b4",null);a["default"]=o.exports}}]);
--------------------------------------------------------------------------------
/dist/static/js/chunk-f8cee08e.78f2e4d8.js:
--------------------------------------------------------------------------------
1 | (window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-f8cee08e"],{1469:function(e,t,s){},2017:function(e,t,s){"use strict";var n=s("b12d"),o=s.n(n);o.a},"9ed6":function(e,t,s){"use strict";s.r(t);var n=function(){var e=this,t=e.$createElement,s=e._self._c||t;return s("div",{staticClass:"login-container"},[s("el-form",{ref:"loginForm",staticClass:"login-form",attrs:{model:e.loginForm,rules:e.loginRules,"auto-complete":"on","label-position":"left"}},[s("div",{staticClass:"title-container"},[s("h3",{staticClass:"title"},[e._v("系统登录")])]),e._v(" "),s("el-form-item",{attrs:{prop:"username"}},[s("span",{staticClass:"svg-container"},[s("svg-icon",{attrs:{"icon-class":"user"}})],1),e._v(" "),s("el-input",{ref:"username",attrs:{placeholder:"用户名",name:"username",type:"text",tabindex:"1","auto-complete":"on"},model:{value:e.loginForm.username,callback:function(t){e.$set(e.loginForm,"username",t)},expression:"loginForm.username"}})],1),e._v(" "),s("el-form-item",{attrs:{prop:"password"}},[s("span",{staticClass:"svg-container"},[s("svg-icon",{attrs:{"icon-class":"password"}})],1),e._v(" "),s("el-input",{key:e.passwordType,ref:"password",attrs:{type:e.passwordType,placeholder:"密码",name:"password",tabindex:"2","auto-complete":"on"},nativeOn:{keyup:function(t){return!t.type.indexOf("key")&&e._k(t.keyCode,"enter",13,t.key,"Enter")?null:e.handleLogin(t)}},model:{value:e.loginForm.password,callback:function(t){e.$set(e.loginForm,"password",t)},expression:"loginForm.password"}}),e._v(" "),s("span",{staticClass:"show-pwd",on:{click:e.showPwd}},[s("svg-icon",{attrs:{"icon-class":"password"===e.passwordType?"eye":"eye-open"}})],1)],1),e._v(" "),s("el-button",{staticStyle:{width:"100%","margin-bottom":"30px"},attrs:{loading:e.loading,type:"primary"},nativeOn:{click:function(t){return t.preventDefault(),e.handleLogin(t)}}},[e._v("登录")]),e._v(" "),s("div",{staticStyle:{position:"relative"}},[s("div",{staticClass:"tips"},[s("span",[e._v("用户名 : admin")]),e._v(" "),s("span",[e._v("密码 : admin")])])])],1)],1)},o=[],r={name:"Login",data:function(){var e=function(e,t,s){""===t?s(new Error("请输入用户名")):s()},t=function(e,t,s){t.length<4?s(new Error("密码不能少于4位")):s()};return{loginForm:{username:"admin",password:"admin"},loginRules:{username:[{required:!0,trigger:"blur",validator:e}],password:[{required:!0,trigger:"blur",validator:t}]},loading:!1,passwordType:"password",redirect:void 0}},watch:{$route:{handler:function(e){this.redirect=e.query&&e.query.redirect},immediate:!0}},methods:{showPwd:function(){var e=this;"password"===this.passwordType?this.passwordType="":this.passwordType="password",this.$nextTick((function(){e.$refs.password.focus()}))},handleLogin:function(){var e=this;this.$store.dispatch("user/logout"),this.$refs.loginForm.validate((function(t){if(!t)return console.log("error submit!!"),!1;console.log(e.loginForm),e.loading=!0,e.$store.dispatch("user/login",e.loginForm).then((function(){e.$router.push({path:e.redirect||"/",query:e.otherQuery}),e.loading=!1})).catch((function(){e.loading=!1}))}))}}},a=r,i=(s("2017"),s("b5f7"),s("2877")),l=Object(i["a"])(a,n,o,!1,null,"9ea6a6a6",null);t["default"]=l.exports},b12d:function(e,t,s){},b5f7:function(e,t,s){"use strict";var n=s("1469"),o=s.n(n);o.a}}]);
--------------------------------------------------------------------------------
/jest.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | moduleFileExtensions: ['js', 'jsx', 'json', 'vue'],
3 | transform: {
4 | '^.+\\.vue$': 'vue-jest',
5 | '.+\\.(css|styl|less|sass|scss|svg|png|jpg|ttf|woff|woff2)$':
6 | 'jest-transform-stub',
7 | '^.+\\.jsx?$': 'babel-jest'
8 | },
9 | moduleNameMapper: {
10 | '^@/(.*)$': '/src/$1'
11 | },
12 | snapshotSerializers: ['jest-serializer-vue'],
13 | testMatch: [
14 | '**/tests/unit/**/*.spec.(js|jsx|ts|tsx)|**/__tests__/*.(js|jsx|ts|tsx)'
15 | ],
16 | collectCoverageFrom: ['src/utils/**/*.{js,vue}', '!src/utils/auth.js', '!src/utils/request.js', 'src/components/**/*.{js,vue}'],
17 | coverageDirectory: '/tests/unit/coverage',
18 | // 'collectCoverage': true,
19 | 'coverageReporters': [
20 | 'lcov',
21 | 'text-summary'
22 | ],
23 | testURL: 'http://localhost/'
24 | }
25 |
--------------------------------------------------------------------------------
/jsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "baseUrl": "./",
4 | "paths": {
5 | "@/*": ["src/*"]
6 | }
7 | },
8 | "exclude": ["node_modules", "dist"]
9 | }
10 |
--------------------------------------------------------------------------------
/mock/index.js:
--------------------------------------------------------------------------------
1 | import Mock from 'mockjs'
2 | import { param2Obj } from '../src/utils'
3 |
4 | import user from './user'
5 | import table from './table'
6 | import article from './article'
7 | import finance from './finance'
8 |
9 | const mocks = [
10 | ...user,
11 | ...table,
12 | ...article,
13 | ...finance
14 | ]
15 |
16 | // for front mock
17 | // please use it cautiously, it will redefine XMLHttpRequest,
18 | // which will cause many of your third-party libraries to be invalidated(like progress event).
19 | export function mockXHR() {
20 | // mock patch
21 | // https://github.com/nuysoft/Mock/issues/300
22 | Mock.XHR.prototype.proxy_send = Mock.XHR.prototype.send
23 | Mock.XHR.prototype.send = function() {
24 | if (this.custom.xhr) {
25 | this.custom.xhr.withCredentials = this.withCredentials || false
26 |
27 | if (this.responseType) {
28 | this.custom.xhr.responseType = this.responseType
29 | }
30 | }
31 | this.proxy_send(...arguments)
32 | }
33 |
34 | function XHR2ExpressReqWrap(respond) {
35 | return function(options) {
36 | let result = null
37 | if (respond instanceof Function) {
38 | const { body, type, url } = options
39 | // https://expressjs.com/en/4x/api.html#req
40 | result = respond({
41 | method: type,
42 | body: JSON.parse(body),
43 | query: param2Obj(url)
44 | })
45 | } else {
46 | result = respond
47 | }
48 | return Mock.mock(result)
49 | }
50 | }
51 |
52 | for (const i of mocks) {
53 | Mock.mock(new RegExp(i.url), i.type || 'get', XHR2ExpressReqWrap(i.response))
54 | }
55 | }
56 |
57 | // for mock server
58 | const responseFake = (url, type, respond) => {
59 | return {
60 | url: new RegExp(`/mock${url}`),
61 | type: type || 'get',
62 | response(req, res) {
63 | res.json(Mock.mock(respond instanceof Function ? respond(req, res) : respond))
64 | }
65 | }
66 | }
67 |
68 | export default mocks.map(route => {
69 | return responseFake(route.url, route.type, route.response)
70 | })
71 |
--------------------------------------------------------------------------------
/mock/mock-server.js:
--------------------------------------------------------------------------------
1 | const chokidar = require('chokidar')
2 | const bodyParser = require('body-parser')
3 | const chalk = require('chalk')
4 | const path = require('path')
5 |
6 | const mockDir = path.join(process.cwd(), 'mock')
7 |
8 | function registerRoutes(app) {
9 | let mockLastIndex
10 | const { default: mocks } = require('./index.js')
11 | for (const mock of mocks) {
12 | app[mock.type](mock.url, mock.response)
13 | mockLastIndex = app._router.stack.length
14 | }
15 | const mockRoutesLength = Object.keys(mocks).length
16 | return {
17 | mockRoutesLength: mockRoutesLength,
18 | mockStartIndex: mockLastIndex - mockRoutesLength
19 | }
20 | }
21 |
22 | function unregisterRoutes() {
23 | Object.keys(require.cache).forEach(i => {
24 | if (i.includes(mockDir)) {
25 | delete require.cache[require.resolve(i)]
26 | }
27 | })
28 | }
29 |
30 | module.exports = app => {
31 | // es6 polyfill
32 | require('@babel/register')
33 |
34 | // parse app.body
35 | // https://expressjs.com/en/4x/api.html#req.body
36 | app.use(bodyParser.json())
37 | app.use(bodyParser.urlencoded({
38 | extended: true
39 | }))
40 |
41 | const mockRoutes = registerRoutes(app)
42 | var mockRoutesLength = mockRoutes.mockRoutesLength
43 | var mockStartIndex = mockRoutes.mockStartIndex
44 |
45 | // watch files, hot reload mock server
46 | chokidar.watch(mockDir, {
47 | ignored: /mock-server/,
48 | ignoreInitial: true
49 | }).on('all', (event, path) => {
50 | if (event === 'change' || event === 'add') {
51 | try {
52 | // remove mock routes stack
53 | app._router.stack.splice(mockStartIndex, mockRoutesLength)
54 |
55 | // clear routes cache
56 | unregisterRoutes()
57 |
58 | const mockRoutes = registerRoutes(app)
59 | mockRoutesLength = mockRoutes.mockRoutesLength
60 | mockStartIndex = mockRoutes.mockStartIndex
61 |
62 | console.log(chalk.magentaBright(`\n > Mock Server hot reload success! changed ${path}`))
63 | } catch (error) {
64 | console.log(chalk.redBright(error))
65 | }
66 | }
67 | })
68 | }
69 |
--------------------------------------------------------------------------------
/mock/table.js:
--------------------------------------------------------------------------------
1 | import Mock from 'mockjs'
2 |
3 | const data = Mock.mock({
4 | 'items|30': [{
5 | id: '@id',
6 | title: '@sentence(10, 20)',
7 | 'status|1': ['published', 'draft', 'deleted'],
8 | author: 'name',
9 | display_time: '@datetime',
10 | pageviews: '@integer(300, 5000)'
11 | }]
12 | })
13 |
14 | export default [
15 | {
16 | url: '/table/list',
17 | type: 'get',
18 | response: config => {
19 | const items = data.items
20 | return {
21 | code: 20000,
22 | data: {
23 | total: items.length,
24 | items: items
25 | }
26 | }
27 | }
28 | }
29 | ]
30 |
--------------------------------------------------------------------------------
/mock/user.js:
--------------------------------------------------------------------------------
1 |
2 | const tokens = {
3 | admin: {
4 | token: 'admin-token'
5 | },
6 | editor: {
7 | token: 'editor-token'
8 | }
9 | }
10 |
11 | const users = {
12 | 'admin-token': {
13 | roles: ['admin'],
14 | introduction: 'I am a super administrator',
15 | avatar: 'https://wpimg.wallstcn.com/f778738c-e4f8-4870-b634-56703b4acafe.gif',
16 | name: 'Super Admin'
17 | },
18 | 'editor-token': {
19 | roles: ['editor'],
20 | introduction: 'I am an editor',
21 | avatar: 'https://wpimg.wallstcn.com/f778738c-e4f8-4870-b634-56703b4acafe.gif',
22 | name: 'Normal Editor'
23 | }
24 | }
25 |
26 | export default [
27 | // user login
28 | {
29 | url: '/jwt_auth/',
30 | type: 'post',
31 | response: config => {
32 | const { username } = config.body
33 | const token = tokens[username]
34 |
35 | // mock error
36 | if (!token) {
37 | return {
38 | code: 60204,
39 | message: 'Account and password are incorrect.'
40 | }
41 | }
42 |
43 | return {
44 | code: 20000,
45 | data: token
46 | }
47 | }
48 | },
49 |
50 | // get user info
51 | {
52 | url: '/user/info\.*',
53 | type: 'get',
54 | response: config => {
55 | const { token } = config.query
56 | const info = users[token]
57 |
58 | // mock error
59 | if (!info) {
60 | return {
61 | code: 50008,
62 | message: 'Login failed, unable to get user details.'
63 | }
64 | }
65 |
66 | return {
67 | code: 20000,
68 | data: info
69 | }
70 | }
71 | },
72 |
73 | // user logout
74 | {
75 | url: '/user/logout',
76 | type: 'post',
77 | response: _ => {
78 | return {
79 | code: 20000,
80 | data: 'success'
81 | }
82 | }
83 | }
84 | ]
85 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "vue-permission-basetemplate",
3 | "version": "4.2.1",
4 | "description": "A vue admin template with Element UI & axios & iconfont & permission control & lint",
5 | "author": "Pan ",
6 | "license": "MIT",
7 | "scripts": {
8 | "dev": "vue-cli-service serve",
9 | "build:prod": "vue-cli-service build",
10 | "build:stage": "vue-cli-service build --mode staging",
11 | "preview": "node build/index.js --preview",
12 | "lint": "eslint --ext .js,.vue src",
13 | "test:unit": "jest --clearCache && vue-cli-service test:unit",
14 | "test:ci": "npm run lint && npm run test:unit",
15 | "svgo": "svgo -f src/icons/svg --config=src/icons/svgo.yml"
16 | },
17 | "dependencies": {
18 | "@antv/g6-editor": "^1.2.0",
19 | "axios": "0.18.1",
20 | "element-ui": "2.7.2",
21 | "font-awesome": "^4.7.0",
22 | "js-cookie": "2.2.0",
23 | "netflix-conductor-json-tree": "^0.0.4",
24 | "normalize.css": "7.0.0",
25 | "nprogress": "0.2.0",
26 | "path-to-regexp": "2.4.0",
27 | "screenfull": "^4.2.0",
28 | "vue": "2.6.10",
29 | "vue-router": "3.0.6",
30 | "vuex": "3.1.0"
31 | },
32 | "devDependencies": {
33 | "@babel/core": "7.0.0",
34 | "@babel/register": "7.0.0",
35 | "@vue/cli-plugin-babel": "3.6.0",
36 | "@vue/cli-plugin-eslint": "^3.9.1",
37 | "@vue/cli-plugin-unit-jest": "3.6.3",
38 | "@vue/cli-service": "3.6.0",
39 | "@vue/test-utils": "1.0.0-beta.29",
40 | "autoprefixer": "^9.5.1",
41 | "babel-core": "7.0.0-bridge.0",
42 | "babel-eslint": "10.0.1",
43 | "babel-jest": "23.6.0",
44 | "chalk": "2.4.2",
45 | "connect": "3.6.6",
46 | "eslint": "5.15.3",
47 | "eslint-plugin-vue": "5.2.2",
48 | "html-webpack-plugin": "3.2.0",
49 | "mockjs": "1.0.1-beta3",
50 | "node-sass": "^4.9.0",
51 | "runjs": "^4.3.2",
52 | "sass-loader": "^7.1.0",
53 | "script-ext-html-webpack-plugin": "2.1.3",
54 | "script-loader": "0.7.2",
55 | "serve-static": "^1.13.2",
56 | "svg-sprite-loader": "4.1.3",
57 | "svgo": "1.2.2",
58 | "vue-template-compiler": "2.6.10"
59 | },
60 | "engines": {
61 | "node": ">=8.9",
62 | "npm": ">= 3.0.0"
63 | },
64 | "browserslist": [
65 | "> 1%",
66 | "last 2 versions"
67 | ]
68 | }
69 |
--------------------------------------------------------------------------------
/postcss.config.js:
--------------------------------------------------------------------------------
1 | // https://github.com/michael-ciniawsky/postcss-load-config
2 |
3 | module.exports = {
4 | 'plugins': {
5 | // to edit target browsers: use "browserslist" field in package.json
6 | 'autoprefixer': {}
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | <%= webpackConfig.name %>
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/public/static/img/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhangwenwu/vue-element-admin-g6-editor/582636f1b259b573a7a0df9ccb3f82013d282fbb/public/static/img/favicon.ico
--------------------------------------------------------------------------------
/src/App.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
12 |
--------------------------------------------------------------------------------
/src/api/article.js:
--------------------------------------------------------------------------------
1 | import request from '@/utils/request'
2 |
3 | export function fetchList(query) {
4 | return request({
5 | url: '/vue-element-admin/article/list',
6 | method: 'get',
7 | params: query
8 | })
9 | }
10 |
11 | export function fetchArticle(id) {
12 | return request({
13 | url: '/vue-element-admin/article/detail',
14 | method: 'get',
15 | params: { id }
16 | })
17 | }
18 |
19 | export function fetchPv(pv) {
20 | return request({
21 | url: '/article/pv',
22 | method: 'get',
23 | params: { pv }
24 | })
25 | }
26 |
27 | export function createArticle(data) {
28 | return request({
29 | url: '/article/create',
30 | method: 'post',
31 | data
32 | })
33 | }
34 |
35 | export function updateArticle(data) {
36 | return request({
37 | url: '/article/update',
38 | method: 'post',
39 | data
40 | })
41 | }
42 |
43 | export function getDzzb(data) {
44 | return request({
45 | url: '/finance/dzzb/',
46 | method: 'get',
47 | data
48 | })
49 | }
50 |
51 | export function getKmbm(data) {
52 | return request({
53 | url: '/finance/kjkm/',
54 | method: 'post',
55 | data
56 | })
57 | }
58 |
59 | export function getTables(data) {
60 | return request({
61 | url: '/finance/kmyeb/',
62 | method: 'post',
63 | data
64 | })
65 | }
66 |
--------------------------------------------------------------------------------
/src/api/table.js:
--------------------------------------------------------------------------------
1 | import request from '@/utils/request'
2 |
3 | export function getList(params) {
4 | return request({
5 | url: '/table/list',
6 | method: 'get',
7 | params
8 | })
9 | }
10 |
--------------------------------------------------------------------------------
/src/api/user.js:
--------------------------------------------------------------------------------
1 | import request from '@/utils/request'
2 |
3 | export function login(data) {
4 | return request({
5 | url: '/jwt_auth/',
6 | // url: '/user/login/',
7 | method: 'post',
8 | data
9 | })
10 | }
11 |
12 | export function getInfo(token) {
13 | return request({
14 | url: '/user/info/',
15 | method: 'get',
16 | params: { token }
17 | })
18 | }
19 |
20 | export function logout() {
21 | return request({
22 | url: '/user/logout/',
23 | method: 'post'
24 | })
25 | }
26 |
--------------------------------------------------------------------------------
/src/assets/401_images/401.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhangwenwu/vue-element-admin-g6-editor/582636f1b259b573a7a0df9ccb3f82013d282fbb/src/assets/401_images/401.gif
--------------------------------------------------------------------------------
/src/assets/404_images/404.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhangwenwu/vue-element-admin-g6-editor/582636f1b259b573a7a0df9ccb3f82013d282fbb/src/assets/404_images/404.png
--------------------------------------------------------------------------------
/src/assets/404_images/404_cloud.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhangwenwu/vue-element-admin-g6-editor/582636f1b259b573a7a0df9ccb3f82013d282fbb/src/assets/404_images/404_cloud.png
--------------------------------------------------------------------------------
/src/assets/custom-theme/fonts/element-icons.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhangwenwu/vue-element-admin-g6-editor/582636f1b259b573a7a0df9ccb3f82013d282fbb/src/assets/custom-theme/fonts/element-icons.ttf
--------------------------------------------------------------------------------
/src/assets/custom-theme/fonts/element-icons.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhangwenwu/vue-element-admin-g6-editor/582636f1b259b573a7a0df9ccb3f82013d282fbb/src/assets/custom-theme/fonts/element-icons.woff
--------------------------------------------------------------------------------
/src/assets/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhangwenwu/vue-element-admin-g6-editor/582636f1b259b573a7a0df9ccb3f82013d282fbb/src/assets/logo.png
--------------------------------------------------------------------------------
/src/components/Breadcrumb/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | {{ item.meta.title }}
6 | {{ item.meta.title }}
7 |
8 |
9 |
10 |
11 |
12 |
65 |
66 |
79 |
--------------------------------------------------------------------------------
/src/components/Hamburger/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
14 |
15 |
16 |
32 |
33 |
45 |
--------------------------------------------------------------------------------
/src/components/Pagination/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
15 |
16 |
17 |
92 |
93 |
102 |
--------------------------------------------------------------------------------
/src/components/Screenfull/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
50 |
51 |
61 |
--------------------------------------------------------------------------------
/src/components/SvgIcon/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 |
8 |
47 |
48 |
63 |
--------------------------------------------------------------------------------
/src/directive/waves/index.js:
--------------------------------------------------------------------------------
1 | import waves from './waves'
2 |
3 | const install = function(Vue) {
4 | Vue.directive('waves', waves)
5 | }
6 |
7 | if (window.Vue) {
8 | window.waves = waves
9 | Vue.use(install); // eslint-disable-line
10 | }
11 |
12 | waves.install = install
13 | export default waves
14 |
--------------------------------------------------------------------------------
/src/directive/waves/waves.css:
--------------------------------------------------------------------------------
1 | .waves-ripple {
2 | position: absolute;
3 | border-radius: 100%;
4 | background-color: rgba(0, 0, 0, 0.15);
5 | background-clip: padding-box;
6 | pointer-events: none;
7 | -webkit-user-select: none;
8 | -moz-user-select: none;
9 | -ms-user-select: none;
10 | user-select: none;
11 | -webkit-transform: scale(0);
12 | -ms-transform: scale(0);
13 | transform: scale(0);
14 | opacity: 1;
15 | }
16 |
17 | .waves-ripple.z-active {
18 | opacity: 0;
19 | -webkit-transform: scale(2);
20 | -ms-transform: scale(2);
21 | transform: scale(2);
22 | -webkit-transition: opacity 1.2s ease-out, -webkit-transform 0.6s ease-out;
23 | transition: opacity 1.2s ease-out, -webkit-transform 0.6s ease-out;
24 | transition: opacity 1.2s ease-out, transform 0.6s ease-out;
25 | transition: opacity 1.2s ease-out, transform 0.6s ease-out, -webkit-transform 0.6s ease-out;
26 | }
--------------------------------------------------------------------------------
/src/directive/waves/waves.js:
--------------------------------------------------------------------------------
1 | import './waves.css'
2 |
3 | const context = '@@wavesContext'
4 |
5 | function handleClick(el, binding) {
6 | function handle(e) {
7 | const customOpts = Object.assign({}, binding.value)
8 | const opts = Object.assign({
9 | ele: el, // 波纹作用元素
10 | type: 'hit', // hit 点击位置扩散 center中心点扩展
11 | color: 'rgba(0, 0, 0, 0.15)' // 波纹颜色
12 | },
13 | customOpts
14 | )
15 | const target = opts.ele
16 | if (target) {
17 | target.style.position = 'relative'
18 | target.style.overflow = 'hidden'
19 | const rect = target.getBoundingClientRect()
20 | let ripple = target.querySelector('.waves-ripple')
21 | if (!ripple) {
22 | ripple = document.createElement('span')
23 | ripple.className = 'waves-ripple'
24 | ripple.style.height = ripple.style.width = Math.max(rect.width, rect.height) + 'px'
25 | target.appendChild(ripple)
26 | } else {
27 | ripple.className = 'waves-ripple'
28 | }
29 | switch (opts.type) {
30 | case 'center':
31 | ripple.style.top = rect.height / 2 - ripple.offsetHeight / 2 + 'px'
32 | ripple.style.left = rect.width / 2 - ripple.offsetWidth / 2 + 'px'
33 | break
34 | default:
35 | ripple.style.top =
36 | (e.pageY - rect.top - ripple.offsetHeight / 2 - document.documentElement.scrollTop ||
37 | document.body.scrollTop) + 'px'
38 | ripple.style.left =
39 | (e.pageX - rect.left - ripple.offsetWidth / 2 - document.documentElement.scrollLeft ||
40 | document.body.scrollLeft) + 'px'
41 | }
42 | ripple.style.backgroundColor = opts.color
43 | ripple.className = 'waves-ripple z-active'
44 | return false
45 | }
46 | }
47 |
48 | if (!el[context]) {
49 | el[context] = {
50 | removeHandle: handle
51 | }
52 | } else {
53 | el[context].removeHandle = handle
54 | }
55 |
56 | return handle
57 | }
58 |
59 | export default {
60 | bind(el, binding) {
61 | el.addEventListener('click', handleClick(el, binding), false)
62 | },
63 | update(el, binding) {
64 | el.removeEventListener('click', el[context].removeHandle, false)
65 | el.addEventListener('click', handleClick(el, binding), false)
66 | },
67 | unbind(el) {
68 | el.removeEventListener('click', el[context].removeHandle, false)
69 | el[context] = null
70 | delete el[context]
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/src/icons/index.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import SvgIcon from '@/components/SvgIcon'// svg component
3 |
4 | // register globally
5 | Vue.component('svg-icon', SvgIcon)
6 |
7 | const req = require.context('./svg', false, /\.svg$/)
8 | const requireAll = requireContext => requireContext.keys().map(requireContext)
9 | requireAll(req)
10 |
--------------------------------------------------------------------------------
/src/icons/svg/404.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/bug.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/chart.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/clipboard.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/component.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/dashboard.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/documentation.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/drag.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/edit.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/education.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/email.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/example.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/excel.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/exit-fullscreen.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/eye-open.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/eye.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/form.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/fullscreen.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/guide.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/icon.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/international.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/language.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/link.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/list.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/lock.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/message.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/money.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/nested.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/password.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/pdf.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/people.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/peoples.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/qq.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/search.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/shopping.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/size.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/skill.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/star.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/tab.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/table.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/theme.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/tree-table.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/tree.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/user.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/wechat.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/zip.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svgo.yml:
--------------------------------------------------------------------------------
1 | # replace default config
2 |
3 | # multipass: true
4 | # full: true
5 |
6 | plugins:
7 |
8 | # - name
9 | #
10 | # or:
11 | # - name: false
12 | # - name: true
13 | #
14 | # or:
15 | # - name:
16 | # param1: 1
17 | # param2: 2
18 |
19 | - removeAttrs:
20 | attrs:
21 | - 'fill'
22 | - 'fill-rule'
23 |
--------------------------------------------------------------------------------
/src/layout/components/AppMain.vue:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
11 |
24 |
25 |
48 |
49 |
57 |
--------------------------------------------------------------------------------
/src/layout/components/Navbar.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
9 |
10 |
11 |
33 |
34 |
35 |
36 |
62 |
63 |
141 |
--------------------------------------------------------------------------------
/src/layout/components/Sidebar/FixiOSBug.js:
--------------------------------------------------------------------------------
1 | export default {
2 | computed: {
3 | device() {
4 | return this.$store.state.app.device
5 | }
6 | },
7 | mounted() {
8 | // In order to fix the click on menu on the ios device will trigger the mouseleave bug
9 | // https://github.com/PanJiaChen/vue-element-admin/issues/1135
10 | this.fixBugIniOS()
11 | },
12 | methods: {
13 | fixBugIniOS() {
14 | const $subMenu = this.$refs.subMenu
15 | if ($subMenu) {
16 | const handleMouseleave = $subMenu.handleMouseleave
17 | $subMenu.handleMouseleave = (e) => {
18 | if (this.device === 'mobile') {
19 | return
20 | }
21 | handleMouseleave(e)
22 | }
23 | }
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/layout/components/Sidebar/Item.vue:
--------------------------------------------------------------------------------
1 |
30 |
--------------------------------------------------------------------------------
/src/layout/components/Sidebar/Link.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
37 |
--------------------------------------------------------------------------------
/src/layout/components/Sidebar/Logo.vue:
--------------------------------------------------------------------------------
1 |
2 |
14 |
15 |
16 |
33 |
34 |
83 |
--------------------------------------------------------------------------------
/src/layout/components/Sidebar/SidebarItem.vue:
--------------------------------------------------------------------------------
1 |
2 |
25 |
26 |
27 |
96 |
--------------------------------------------------------------------------------
/src/layout/components/Sidebar/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
55 |
--------------------------------------------------------------------------------
/src/layout/components/TagsView/ScrollPane.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
69 |
70 |
86 |
--------------------------------------------------------------------------------
/src/layout/components/index.js:
--------------------------------------------------------------------------------
1 | export { default as Navbar } from './Navbar'
2 | export { default as Sidebar } from './Sidebar'
3 | export { default as AppMain } from './AppMain'
4 | export { default as TagsView } from './TagsView'
5 |
--------------------------------------------------------------------------------
/src/layout/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
54 |
55 |
99 |
--------------------------------------------------------------------------------
/src/layout/mixin/ResizeHandler.js:
--------------------------------------------------------------------------------
1 | import store from '@/store'
2 |
3 | const { body } = document
4 | const WIDTH = 992 // refer to Bootstrap's responsive design
5 |
6 | export default {
7 | watch: {
8 | $route(route) {
9 | if (this.device === 'mobile' && this.sidebar.opened) {
10 | store.dispatch('app/closeSideBar', { withoutAnimation: false })
11 | }
12 | }
13 | },
14 | beforeMount() {
15 | window.addEventListener('resize', this.$_resizeHandler)
16 | },
17 | beforeDestroy() {
18 | window.removeEventListener('resize', this.$_resizeHandler)
19 | },
20 | mounted() {
21 | const isMobile = this.$_isMobile()
22 | if (isMobile) {
23 | store.dispatch('app/toggleDevice', 'mobile')
24 | store.dispatch('app/closeSideBar', { withoutAnimation: true })
25 | }
26 | },
27 | methods: {
28 | // use $_ for mixins properties
29 | // https://vuejs.org/v2/style-guide/index.html#Private-property-names-essential
30 | $_isMobile() {
31 | const rect = body.getBoundingClientRect()
32 | return rect.width - 1 < WIDTH
33 | },
34 | $_resizeHandler() {
35 | if (!document.hidden) {
36 | const isMobile = this.$_isMobile()
37 | store.dispatch('app/toggleDevice', isMobile ? 'mobile' : 'desktop')
38 |
39 | if (isMobile) {
40 | store.dispatch('app/closeSideBar', { withoutAnimation: true })
41 | }
42 | }
43 | }
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/src/main.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 |
3 | import 'normalize.css/normalize.css' // A modern alternative to CSS resets
4 |
5 | import ElementUI from 'element-ui'
6 | import 'element-ui/lib/theme-chalk/index.css'
7 | import locale from 'element-ui/lib/locale/lang/zh-CN' // lang i18n
8 | import '@/styles/index.scss' // global css
9 | // 字体图标
10 | import 'font-awesome/css/font-awesome.min.css'
11 |
12 |
13 | import App from './App'
14 | import store from './store'
15 | import router from './router'
16 |
17 | import '@/icons' // icon
18 | import '@/permission' // permission control
19 |
20 | /**
21 | * If you don't want to use mock-server
22 | * you want to use MockJs for mock api
23 | * you can execute: mockXHR()
24 | *
25 | * Currently MockJs will be used in the production environment,
26 | * please remove it before going online! ! !
27 | */
28 | console.log('~~9898989899665656')
29 | import { mockXHR } from '../mock'
30 | if (process.env.NODE_ENV === 'production') {
31 | mockXHR()
32 | }
33 |
34 | // set ElementUI lang to EN
35 | Vue.use(ElementUI, { locale })
36 |
37 | Vue.config.productionTip = false
38 |
39 | new Vue({
40 | el: '#app',
41 | router,
42 | store,
43 | render: h => h(App)
44 | })
45 |
--------------------------------------------------------------------------------
/src/permission.js:
--------------------------------------------------------------------------------
1 | import router from './router'
2 | import store from './store'
3 | import { Message } from 'element-ui'
4 | import NProgress from 'nprogress' // progress bar
5 | import 'nprogress/nprogress.css' // progress bar style
6 | import { getToken } from '@/utils/auth' // get token from cookie
7 | import getPageTitle from '@/utils/get-page-title'
8 |
9 | NProgress.configure({ showSpinner: false }) // NProgress Configuration
10 |
11 | const whiteList = ['/login', '/auth-redirect'] // no redirect whitelist
12 |
13 | router.beforeEach(async(to, from, next) => {
14 | // start progress bar
15 | NProgress.start()
16 |
17 | // set page title
18 | document.title = getPageTitle(to.meta.title)
19 |
20 | // determine whether the user has logged in
21 | const hasToken = getToken()
22 |
23 | if (hasToken) {
24 | if (to.path === '/login') {
25 | // if is logged in, redirect to the home page
26 | next({ path: '/' })
27 | NProgress.done()
28 | } else {
29 | // determine whether the user has obtained his permission roles through getInfo
30 | const hasRoles = store.getters.roles && store.getters.roles.length > 0
31 | if (hasRoles) {
32 | next()
33 | } else {
34 | try {
35 | // get user info
36 | // note: roles must be a object array! such as: ['admin'] or ,['developer','editor']
37 | const { roles } = await store.dispatch('user/getInfo')
38 |
39 | // generate accessible routes map based on roles
40 | const accessRoutes = await store.dispatch('permission/generateRoutes', roles)
41 |
42 | // dynamically add accessible routes
43 | router.addRoutes(accessRoutes)
44 |
45 | // hack method to ensure that addRoutes is complete
46 | // set the replace: true, so the navigation will not leave a history record
47 | next({ ...to, replace: true })
48 | } catch (error) {
49 | // remove token and go to login page to re-login
50 | await store.dispatch('user/resetToken')
51 | Message.error(error || 'Has Error')
52 | next(`/login?redirect=${to.path}`)
53 | NProgress.done()
54 | }
55 | }
56 | }
57 | } else {
58 | /* has no token*/
59 |
60 | if (whiteList.indexOf(to.path) !== -1) {
61 | // in the free login whitelist, go directly
62 | next()
63 | } else {
64 | // other pages that do not have permission to access are redirected to the login page.
65 | next(`/login?redirect=${to.path}`)
66 | NProgress.done()
67 | }
68 | }
69 | })
70 |
71 | router.afterEach(() => {
72 | // finish progress bar
73 | NProgress.done()
74 | })
75 |
--------------------------------------------------------------------------------
/src/router/index.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import Router from 'vue-router'
3 |
4 | Vue.use(Router)
5 |
6 | /* Layout */
7 | import Layout from '@/layout'
8 |
9 | /**
10 | * Note: sub-menu only appear when route children.length >= 1
11 | * Detail see: https://panjiachen.github.io/vue-element-admin-site/guide/essentials/router-and-nav.html
12 | *
13 | * hidden: true if set true, item will not show in the sidebar(default is false)
14 | * alwaysShow: true if set true, will always show the root menu
15 | * if not set alwaysShow, when item has more than one children route,
16 | * it will becomes nested mode, otherwise not show the root menu
17 | * redirect: noRedirect if set noRedirect will no redirect in the breadcrumb
18 | * name:'router-name' the name is used by (must set!!!)
19 | * meta : {
20 | roles: ['admin','editor'] control the page roles (you can set multiple roles)
21 | title: 'title' the name show in sidebar and breadcrumb (recommend set)
22 | icon: 'svg-name' the icon show in the sidebar
23 | noCache: true if set true, the page will no be cached(default is false)
24 | affix: true if set true, the tag will affix in the tags-view
25 | breadcrumb: false if set false, the item will hidden in breadcrumb(default is true)
26 | activeMenu: '/example/list' if set path, the sidebar will highlight the path you set
27 | }
28 | */
29 |
30 | /**
31 | * constantRoutes
32 | * a base page that does not have permission requirements
33 | * all roles can be accessed
34 | */
35 | export const constantRoutes = [
36 | {
37 | path: '/redirect',
38 | component: Layout,
39 | hidden: true,
40 | children: [
41 | {
42 | path: '/redirect/:path*',
43 | component: () => import('@/views/redirect/index')
44 | }
45 | ]
46 | },
47 | {
48 | path: '/login',
49 | component: () => import('@/views/login/index'),
50 | hidden: true
51 | },
52 | {
53 | path: '/',
54 | component: Layout,
55 | redirect: '/dashboard',
56 | children: [
57 | {
58 | path: 'dashboard',
59 | component: () => import('@/views/dashboard/index'),
60 | name: 'Dashboard',
61 | meta: { title: '首页', icon: 'user', affix: true }
62 | }
63 | ]
64 | },
65 | {
66 | path: '/editor',
67 | component: Layout,
68 | children: [
69 | {
70 | path: 'index',
71 | component: () => import('@/views/editor/index'),
72 | name: '可视化查询',
73 | meta: { title: '可视化查询', icon: 'dashboard', affix: false }
74 | }
75 | ]
76 | },
77 | {
78 | path: '/financialQuery',
79 | component: Layout,
80 | name: 'financialQuery',
81 | redirect: '/financialQuery',
82 | meta: {
83 | title: '财务查询',
84 | icon: 'money'
85 | },
86 | children: [
87 | {
88 | path: 'balance',
89 | component: () => import('@/views/financialQuery/balance'),
90 | name: 'balance',
91 | meta: { title: '余额表查询', icon: 'documentation' }
92 | }
93 | ]
94 | },
95 | {
96 | path: '/documentation',
97 | component: Layout,
98 | children: [
99 | {
100 | path: 'index',
101 | component: () => import('@/views/documentation/index'),
102 | name: 'Documentation',
103 | meta: { title: '知识库', icon: 'education', affix: false }
104 | },
105 | {
106 | path: 'details/:id',
107 | hidden: true,
108 | component: () => import('@/views/documentation/details'),
109 | name: '详细内容',
110 | meta: { title: '详细内容', icon: 'documentation', affix: false}
111 | }
112 | ]
113 | }
114 | ]
115 |
116 | /**
117 | * asyncRoutes
118 | * the routes that need to be dynamically loaded based on user roles
119 | */
120 | const createRouter = () => new Router({
121 | // mode: 'history', // require service support
122 | scrollBehavior: () => ({ y: 0 }),
123 | routes: constantRoutes
124 | })
125 |
126 | const router = createRouter()
127 |
128 | // Detail see: https://github.com/vuejs/vue-router/issues/1234#issuecomment-357941465
129 | export function resetRouter() {
130 | const newRouter = createRouter()
131 | router.matcher = newRouter.matcher // reset router
132 | }
133 |
134 | export default router
135 |
--------------------------------------------------------------------------------
/src/settings.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 |
3 | title: '资源统筹系统',
4 |
5 | tagsView: true,
6 |
7 | /**
8 | * @type {boolean} true | false
9 | * @description Whether fix the header
10 | */
11 | fixedHeader: false,
12 |
13 | /**
14 | * @type {boolean} true | false
15 | * @description Whether show the logo in sidebar
16 | */
17 | sidebarLogo: true
18 | }
19 |
--------------------------------------------------------------------------------
/src/store/getters.js:
--------------------------------------------------------------------------------
1 | const getters = {
2 | sidebar: state => state.app.sidebar,
3 | device: state => state.app.device,
4 | token: state => state.user.token,
5 | avatar: state => state.user.avatar,
6 | name: state => state.user.name,
7 | roles: state => state.user.roles,
8 | permission_routes: state => state.permission.routes,
9 | visitedViews: state => state.tagsView.visitedViews,
10 | cachedViews: state => state.tagsView.cachedViews
11 | }
12 | export default getters
13 |
--------------------------------------------------------------------------------
/src/store/index.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import Vuex from 'vuex'
3 | import getters from './getters'
4 | import app from './modules/app'
5 | import permission from './modules/permission'
6 | import settings from './modules/settings'
7 | import user from './modules/user'
8 | import tagsView from './modules/tagsView'
9 |
10 | Vue.use(Vuex)
11 |
12 | const store = new Vuex.Store({
13 | modules: {
14 | app,
15 | permission,
16 | settings,
17 | tagsView,
18 | user
19 | },
20 | getters
21 | })
22 |
23 | export default store
24 |
--------------------------------------------------------------------------------
/src/store/modules/app.js:
--------------------------------------------------------------------------------
1 | import Cookies from 'js-cookie'
2 |
3 | const state = {
4 | sidebar: {
5 | opened: Cookies.get('sidebarStatus') ? !!+Cookies.get('sidebarStatus') : true,
6 | withoutAnimation: false
7 | },
8 | device: 'desktop',
9 | size: Cookies.get('size') || 'medium'
10 | }
11 |
12 | const mutations = {
13 | TOGGLE_SIDEBAR: state => {
14 | state.sidebar.opened = !state.sidebar.opened
15 | state.sidebar.withoutAnimation = false
16 | if (state.sidebar.opened) {
17 | Cookies.set('sidebarStatus', 1)
18 | } else {
19 | Cookies.set('sidebarStatus', 0)
20 | }
21 | },
22 | CLOSE_SIDEBAR: (state, withoutAnimation) => {
23 | Cookies.set('sidebarStatus', 0)
24 | state.sidebar.opened = false
25 | state.sidebar.withoutAnimation = withoutAnimation
26 | },
27 | TOGGLE_DEVICE: (state, device) => {
28 | state.device = device
29 | }
30 | }
31 |
32 | const actions = {
33 | toggleSideBar({ commit }) {
34 | commit('TOGGLE_SIDEBAR')
35 | },
36 | closeSideBar({ commit }, { withoutAnimation }) {
37 | commit('CLOSE_SIDEBAR', withoutAnimation)
38 | },
39 | toggleDevice({ commit }, device) {
40 | commit('TOGGLE_DEVICE', device)
41 | }
42 | }
43 |
44 | export default {
45 | namespaced: true,
46 | state,
47 | mutations,
48 | actions
49 | }
50 |
--------------------------------------------------------------------------------
/src/store/modules/permission.js:
--------------------------------------------------------------------------------
1 | import { asyncRoutes, constantRoutes } from '@/router'
2 |
3 | /**
4 | * Use meta.role to determine if the current user has permission
5 | * @param roles
6 | * @param route
7 | */
8 | function hasPermission(roles, route) {
9 | if (route.meta && route.meta.roles) {
10 | return roles.some(role => route.meta.roles.includes(role))
11 | } else {
12 | return true
13 | }
14 | }
15 |
16 | /**
17 | * Filter asynchronous routing tables by recursion
18 | * @param routes asyncRoutes
19 | * @param roles
20 | */
21 | export function filterAsyncRoutes(routes, roles) {
22 | const res = []
23 |
24 | routes.forEach(route => {
25 | const tmp = { ...route }
26 | if (hasPermission(roles, tmp)) {
27 | if (tmp.children) {
28 | tmp.children = filterAsyncRoutes(tmp.children, roles)
29 | }
30 | res.push(tmp)
31 | }
32 | })
33 |
34 | return res
35 | }
36 |
37 | const state = {
38 | routes: [],
39 | addRoutes: []
40 | }
41 |
42 | const mutations = {
43 | SET_ROUTES: (state, routes) => {
44 | state.addRoutes = routes
45 | state.routes = constantRoutes.concat(routes)
46 | }
47 | }
48 |
49 | const actions = {
50 | generateRoutes({ commit }, roles) {
51 | return new Promise(resolve => {
52 | let accessedRoutes
53 | if (roles.includes('admin')) {
54 | accessedRoutes = asyncRoutes || []
55 | } else {
56 | accessedRoutes = filterAsyncRoutes(asyncRoutes, roles)
57 | }
58 | commit('SET_ROUTES', accessedRoutes)
59 | resolve(accessedRoutes)
60 | })
61 | }
62 | }
63 |
64 | export default {
65 | namespaced: true,
66 | state,
67 | mutations,
68 | actions
69 | }
70 |
--------------------------------------------------------------------------------
/src/store/modules/settings.js:
--------------------------------------------------------------------------------
1 | import defaultSettings from '@/settings'
2 |
3 | const { showSettings, tagsView, fixedHeader, sidebarLogo } = defaultSettings
4 |
5 | const state = {
6 | showSettings: showSettings,
7 | fixedHeader: fixedHeader,
8 | sidebarLogo: sidebarLogo,
9 | tagsView: tagsView
10 | }
11 |
12 | const mutations = {
13 | CHANGE_SETTING: (state, { key, value }) => {
14 | if (state.hasOwnProperty(key)) {
15 | state[key] = value
16 | }
17 | }
18 | }
19 |
20 | const actions = {
21 | changeSetting({ commit }, data) {
22 | commit('CHANGE_SETTING', data)
23 | }
24 | }
25 |
26 | export default {
27 | namespaced: true,
28 | state,
29 | mutations,
30 | actions
31 | }
32 |
33 |
--------------------------------------------------------------------------------
/src/store/modules/tagsView.js:
--------------------------------------------------------------------------------
1 | const state = {
2 | visitedViews: [],
3 | cachedViews: []
4 | }
5 |
6 | const mutations = {
7 | ADD_VISITED_VIEW: (state, view) => {
8 | if (state.visitedViews.some(v => v.path === view.path)) return
9 | state.visitedViews.push(
10 | Object.assign({}, view, {
11 | title: view.meta.title || 'no-name'
12 | })
13 | )
14 | },
15 | ADD_CACHED_VIEW: (state, view) => {
16 | if (state.cachedViews.includes(view.name)) return
17 | if (!view.meta.noCache) {
18 | state.cachedViews.push(view.name)
19 | }
20 | },
21 |
22 | DEL_VISITED_VIEW: (state, view) => {
23 | for (const [i, v] of state.visitedViews.entries()) {
24 | if (v.path === view.path) {
25 | state.visitedViews.splice(i, 1)
26 | break
27 | }
28 | }
29 | },
30 | DEL_CACHED_VIEW: (state, view) => {
31 | const index = state.cachedViews.indexOf(view.name)
32 | index > -1 && state.cachedViews.splice(index, 1)
33 | },
34 |
35 | DEL_OTHERS_VISITED_VIEWS: (state, view) => {
36 | state.visitedViews = state.visitedViews.filter(v => {
37 | return v.meta.affix || v.path === view.path
38 | })
39 | },
40 | DEL_OTHERS_CACHED_VIEWS: (state, view) => {
41 | const index = state.cachedViews.indexOf(view.name)
42 | if (index > -1) {
43 | state.cachedViews = state.cachedViews.slice(index, index + 1)
44 | } else {
45 | // if index = -1, there is no cached tags
46 | state.cachedViews = []
47 | }
48 | },
49 |
50 | DEL_ALL_VISITED_VIEWS: state => {
51 | // keep affix tags
52 | const affixTags = state.visitedViews.filter(tag => tag.meta.affix)
53 | state.visitedViews = affixTags
54 | },
55 | DEL_ALL_CACHED_VIEWS: state => {
56 | state.cachedViews = []
57 | },
58 |
59 | UPDATE_VISITED_VIEW: (state, view) => {
60 | for (let v of state.visitedViews) {
61 | if (v.path === view.path) {
62 | v = Object.assign(v, view)
63 | break
64 | }
65 | }
66 | }
67 | }
68 |
69 | const actions = {
70 | addView({ dispatch }, view) {
71 | dispatch('addVisitedView', view)
72 | dispatch('addCachedView', view)
73 | },
74 | addVisitedView({ commit }, view) {
75 | commit('ADD_VISITED_VIEW', view)
76 | },
77 | addCachedView({ commit }, view) {
78 | commit('ADD_CACHED_VIEW', view)
79 | },
80 |
81 | delView({ dispatch, state }, view) {
82 | return new Promise(resolve => {
83 | dispatch('delVisitedView', view)
84 | dispatch('delCachedView', view)
85 | resolve({
86 | visitedViews: [...state.visitedViews],
87 | cachedViews: [...state.cachedViews]
88 | })
89 | })
90 | },
91 | delVisitedView({ commit, state }, view) {
92 | return new Promise(resolve => {
93 | commit('DEL_VISITED_VIEW', view)
94 | resolve([...state.visitedViews])
95 | })
96 | },
97 | delCachedView({ commit, state }, view) {
98 | return new Promise(resolve => {
99 | commit('DEL_CACHED_VIEW', view)
100 | resolve([...state.cachedViews])
101 | })
102 | },
103 |
104 | delOthersViews({ dispatch, state }, view) {
105 | return new Promise(resolve => {
106 | dispatch('delOthersVisitedViews', view)
107 | dispatch('delOthersCachedViews', view)
108 | resolve({
109 | visitedViews: [...state.visitedViews],
110 | cachedViews: [...state.cachedViews]
111 | })
112 | })
113 | },
114 | delOthersVisitedViews({ commit, state }, view) {
115 | return new Promise(resolve => {
116 | commit('DEL_OTHERS_VISITED_VIEWS', view)
117 | resolve([...state.visitedViews])
118 | })
119 | },
120 | delOthersCachedViews({ commit, state }, view) {
121 | return new Promise(resolve => {
122 | commit('DEL_OTHERS_CACHED_VIEWS', view)
123 | resolve([...state.cachedViews])
124 | })
125 | },
126 |
127 | delAllViews({ dispatch, state }, view) {
128 | return new Promise(resolve => {
129 | dispatch('delAllVisitedViews', view)
130 | dispatch('delAllCachedViews', view)
131 | resolve({
132 | visitedViews: [...state.visitedViews],
133 | cachedViews: [...state.cachedViews]
134 | })
135 | })
136 | },
137 | delAllVisitedViews({ commit, state }) {
138 | return new Promise(resolve => {
139 | commit('DEL_ALL_VISITED_VIEWS')
140 | resolve([...state.visitedViews])
141 | })
142 | },
143 | delAllCachedViews({ commit, state }) {
144 | return new Promise(resolve => {
145 | commit('DEL_ALL_CACHED_VIEWS')
146 | resolve([...state.cachedViews])
147 | })
148 | },
149 |
150 | updateVisitedView({ commit }, view) {
151 | commit('UPDATE_VISITED_VIEW', view)
152 | }
153 | }
154 |
155 | export default {
156 | namespaced: true,
157 | state,
158 | mutations,
159 | actions
160 | }
161 |
--------------------------------------------------------------------------------
/src/store/modules/user.js:
--------------------------------------------------------------------------------
1 | import { login, logout, getInfo } from '@/api/user'
2 | import { getToken, setToken, removeToken } from '@/utils/auth'
3 | import router, { resetRouter } from '@/router'
4 |
5 | const state = {
6 | token: getToken(),
7 | name: '',
8 | avatar: require('../../assets/logo.png'),
9 | introduction: '',
10 | roles: []
11 | }
12 |
13 | const mutations = {
14 | SET_TOKEN: (state, token) => {
15 | state.token = token
16 | },
17 | SET_INTRODUCTION: (state, introduction) => {
18 | state.introduction = introduction
19 | },
20 | SET_NAME: (state, name) => {
21 | state.name = name
22 | },
23 | SET_AVATAR: (state, avatar) => {
24 | state.avatar = avatar
25 | },
26 | SET_ROLES: (state, roles) => {
27 | state.roles = roles
28 | }
29 | }
30 |
31 | const actions = {
32 | // user login
33 | login({ commit }, userInfo) {
34 | const { username, password } = userInfo
35 | let a = { username: username.trim(), password: password };
36 | console.log(a)
37 | console.log(typeof(a))
38 | return new Promise((resolve, reject) => {
39 | login({ username: username.trim(), password: password }).then(response => {
40 | const { data } = response
41 | commit('SET_TOKEN', data.token)
42 | setToken(data.token)
43 | resolve()
44 | }).catch(error => {
45 | reject(error)
46 | })
47 | })
48 | },
49 |
50 | // get user info
51 | getInfo({ commit, state }) {
52 | return new Promise((resolve, reject) => {
53 | getInfo(state.token).then(response => {
54 | const { data } = response
55 | if (!data) {
56 | reject('验证失败,请重新登录.')
57 | }
58 | const { roles, name, avatar, introduction } = data
59 | if (avatar !== '') {
60 | commit('SET_AVATAR', avatar)
61 | }
62 | // roles must be a non-empty array
63 | if (!roles || roles.length <= 0) {
64 | reject('角色不能为空!')
65 | }
66 | commit('SET_ROLES', roles)
67 | commit('SET_NAME', name)
68 | resolve(data)
69 | }).catch(error => {
70 | reject(error)
71 | })
72 | })
73 | },
74 |
75 | // user logout
76 | logout({ commit, state, dispatch }) {
77 | return new Promise((resolve, reject) => {
78 | logout(state.token).then(() => {
79 | commit('SET_TOKEN', '')
80 | commit('SET_ROLES', [])
81 | removeToken()
82 | resetRouter()
83 |
84 | // reset visited views and cached views
85 | // to fixed https://github.com/PanJiaChen/vue-element-admin/issues/2485
86 | dispatch('tagsView/delAllViews', null, { root: true })
87 |
88 | resolve()
89 | }).catch(error => {
90 | reject(error)
91 | })
92 | })
93 | },
94 |
95 | // remove token
96 | resetToken({ commit }) {
97 | return new Promise(resolve => {
98 | commit('SET_TOKEN', '')
99 | commit('SET_ROLES', [])
100 | removeToken()
101 | resolve()
102 | })
103 | },
104 |
105 | // dynamically modify permissions
106 | changeRoles({ commit, dispatch }, role) {
107 | return new Promise(async resolve => {
108 | const token = role + '-token'
109 |
110 | commit('SET_TOKEN', token)
111 | setToken(token)
112 |
113 | const { roles } = await dispatch('getInfo')
114 |
115 | resetRouter()
116 |
117 | // generate accessible routes map based on roles
118 | const accessRoutes = await dispatch('permission/generateRoutes', roles, { root: true })
119 |
120 | // dynamically add accessible routes
121 | router.addRoutes(accessRoutes)
122 |
123 | // reset visited views and cached views
124 | dispatch('tagsView/delAllViews', null, { root: true })
125 |
126 | resolve()
127 | })
128 | }
129 | }
130 |
131 | export default {
132 | namespaced: true,
133 | state,
134 | mutations,
135 | actions
136 | }
137 |
--------------------------------------------------------------------------------
/src/styles/element-ui.scss:
--------------------------------------------------------------------------------
1 | // cover some element-ui styles
2 |
3 | .el-breadcrumb__inner,
4 | .el-breadcrumb__inner a {
5 | font-weight: 400 !important;
6 | }
7 |
8 | .el-upload {
9 | input[type="file"] {
10 | display: none !important;
11 | }
12 | }
13 |
14 | .el-upload__input {
15 | display: none;
16 | }
17 |
18 |
19 | // to fixed https://github.com/ElemeFE/element/issues/2461
20 | .el-dialog {
21 | transform: none;
22 | left: 0;
23 | position: relative;
24 | margin: 0 auto;
25 | }
26 |
27 | // refine element ui upload
28 | .upload-container {
29 | .el-upload {
30 | width: 100%;
31 |
32 | .el-upload-dragger {
33 | width: 100%;
34 | height: 200px;
35 | }
36 | }
37 | }
38 |
39 | // dropdown
40 | .el-dropdown-menu {
41 | a {
42 | display: block
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/src/styles/index.scss:
--------------------------------------------------------------------------------
1 |
2 | @import './variables.scss';
3 | @import './mixin.scss';
4 | @import './transition.scss';
5 | @import './element-ui.scss';
6 | @import './sidebar.scss';
7 |
8 | body {
9 | height: 100%;
10 | -moz-osx-font-smoothing: grayscale;
11 | -webkit-font-smoothing: antialiased;
12 | text-rendering: optimizeLegibility;
13 | font-family: Helvetica Neue, Helvetica, PingFang SC, Hiragino Sans GB, Microsoft YaHei, Arial, sans-serif;
14 | }
15 |
16 | label {
17 | font-weight: 700;
18 | }
19 |
20 | html {
21 | height: 100%;
22 | box-sizing: border-box;
23 | }
24 |
25 | #app {
26 | height: 100%;
27 | }
28 |
29 | *,
30 | *:before,
31 | *:after {
32 | box-sizing: inherit;
33 | }
34 |
35 | a:focus,
36 | a:active {
37 | outline: none;
38 | }
39 |
40 | a,
41 | a:focus,
42 | a:hover {
43 | cursor: pointer;
44 | color: inherit;
45 | text-decoration: none;
46 | }
47 |
48 | div:focus {
49 | outline: none;
50 | }
51 |
52 | .clearfix {
53 | &:after {
54 | visibility: hidden;
55 | display: block;
56 | font-size: 0;
57 | content: " ";
58 | clear: both;
59 | height: 0;
60 | }
61 | }
62 |
63 | // main-container global css
64 | .app-container {
65 | padding: 20px;
66 | }
67 |
--------------------------------------------------------------------------------
/src/styles/mixin.scss:
--------------------------------------------------------------------------------
1 | @mixin clearfix {
2 | &:after {
3 | content: "";
4 | display: table;
5 | clear: both;
6 | }
7 | }
8 |
9 | @mixin scrollBar {
10 | &::-webkit-scrollbar-track-piece {
11 | background: #d3dce6;
12 | }
13 |
14 | &::-webkit-scrollbar {
15 | width: 6px;
16 | }
17 |
18 | &::-webkit-scrollbar-thumb {
19 | background: #99a9bf;
20 | border-radius: 20px;
21 | }
22 | }
23 |
24 | @mixin relative {
25 | position: relative;
26 | width: 100%;
27 | height: 100%;
28 | }
29 |
--------------------------------------------------------------------------------
/src/styles/sidebar.scss:
--------------------------------------------------------------------------------
1 | #app {
2 | .el-menu-item.is-active{
3 | background-color: #999 !important;
4 | }
5 | .main-container {
6 | min-height: 100%;
7 | transition: margin-left .28s;
8 | margin-left: $sideBarWidth;
9 | position: relative;
10 | }
11 |
12 | .sidebar-container {
13 | transition: width 0.28s;
14 | width: $sideBarWidth !important;
15 | background-color: $menuBg;
16 | height: 100%;
17 | position: fixed;
18 | font-size: 0px;
19 | top: 0;
20 | bottom: 0;
21 | left: 0;
22 | z-index: 1001;
23 | overflow: hidden;
24 |
25 | // reset element-ui css
26 | .horizontal-collapse-transition {
27 | transition: 0s width ease-in-out, 0s padding-left ease-in-out, 0s padding-right ease-in-out;
28 | }
29 |
30 | .scrollbar-wrapper {
31 | overflow-x: hidden !important;
32 | }
33 |
34 | .el-scrollbar__bar.is-vertical {
35 | right: 0px;
36 | }
37 |
38 | .el-scrollbar {
39 | height: 100%;
40 | }
41 |
42 | &.has-logo {
43 | .el-scrollbar {
44 | height: calc(100% - 60px);
45 | }
46 | }
47 |
48 | .is-horizontal {
49 | display: none;
50 | }
51 |
52 | a {
53 | display: inline-block;
54 | width: 100%;
55 | overflow: hidden;
56 | }
57 |
58 | .svg-icon {
59 | margin-right: 16px;
60 | }
61 |
62 | .el-menu {
63 | border: none;
64 | height: 100%;
65 | width: 100% !important;
66 | }
67 |
68 | // menu hover
69 | .submenu-title-noDropdown,
70 | .el-submenu__title {
71 | &:hover {
72 | background-color: $menuHover !important;
73 | }
74 | }
75 |
76 | .is-active>.el-submenu__title {
77 | color: $subMenuActiveText !important;
78 | }
79 |
80 | & .nest-menu .el-submenu>.el-submenu__title,
81 | & .el-submenu .el-menu-item {
82 | min-width: $sideBarWidth !important;
83 | background-color: $subMenuBg !important;
84 |
85 | &:hover {
86 | background-color: $subMenuHover !important;
87 | }
88 | }
89 | }
90 |
91 | .hideSidebar {
92 | .sidebar-container {
93 | width: 54px !important;
94 | }
95 |
96 | .main-container {
97 | margin-left: 54px;
98 | }
99 |
100 | .submenu-title-noDropdown {
101 | padding: 0 !important;
102 | position: relative;
103 |
104 | .el-tooltip {
105 | padding: 0 !important;
106 |
107 | .svg-icon {
108 | margin-left: 20px;
109 | }
110 | }
111 | }
112 |
113 | .el-submenu {
114 | overflow: hidden;
115 |
116 | &>.el-submenu__title {
117 | padding: 0 !important;
118 |
119 | .svg-icon {
120 | margin-left: 20px;
121 | }
122 |
123 | .el-submenu__icon-arrow {
124 | display: none;
125 | }
126 | }
127 | }
128 |
129 | .el-menu--collapse {
130 | .el-submenu {
131 | &>.el-submenu__title {
132 | &>span {
133 | height: 0;
134 | width: 0;
135 | overflow: hidden;
136 | visibility: hidden;
137 | display: inline-block;
138 | }
139 | }
140 | }
141 | }
142 | }
143 |
144 | .el-menu--collapse .el-menu .el-submenu {
145 | min-width: $sideBarWidth !important;
146 | }
147 |
148 | // mobile responsive
149 | .mobile {
150 | .main-container {
151 | margin-left: 0px;
152 | }
153 |
154 | .sidebar-container {
155 | transition: transform .28s;
156 | width: $sideBarWidth !important;
157 | }
158 |
159 | &.hideSidebar {
160 | .sidebar-container {
161 | pointer-events: none;
162 | transition-duration: 0.3s;
163 | transform: translate3d(-$sideBarWidth, 0, 0);
164 | }
165 | }
166 | }
167 |
168 | .withoutAnimation {
169 |
170 | .main-container,
171 | .sidebar-container {
172 | transition: none;
173 | }
174 | }
175 | }
176 |
177 | // when menu collapsed
178 | .el-menu--vertical {
179 | &>.el-menu {
180 | .svg-icon {
181 | margin-right: 16px;
182 | }
183 | }
184 |
185 | .nest-menu .el-submenu>.el-submenu__title,
186 | .el-menu-item {
187 | &:hover {
188 | // you can use $subMenuHover
189 | background-color: $menuHover !important;
190 | }
191 | }
192 |
193 | // the scroll bar appears when the subMenu is too long
194 | >.el-menu--popup {
195 | max-height: 100vh;
196 | overflow-y: auto;
197 |
198 | &::-webkit-scrollbar-track-piece {
199 | background: #d3dce6;
200 | }
201 |
202 | &::-webkit-scrollbar {
203 | width: 6px;
204 | }
205 |
206 | &::-webkit-scrollbar-thumb {
207 | background: #99a9bf;
208 | border-radius: 20px;
209 | }
210 | }
211 | }
212 |
--------------------------------------------------------------------------------
/src/styles/transition.scss:
--------------------------------------------------------------------------------
1 | // global transition css
2 |
3 | /* fade */
4 | .fade-enter-active,
5 | .fade-leave-active {
6 | transition: opacity 0.28s;
7 | }
8 |
9 | .fade-enter,
10 | .fade-leave-active {
11 | opacity: 0;
12 | }
13 |
14 | /* fade-transform */
15 | .fade-transform-leave-active,
16 | .fade-transform-enter-active {
17 | transition: all .5s;
18 | }
19 |
20 | .fade-transform-enter {
21 | opacity: 0;
22 | transform: translateX(-30px);
23 | }
24 |
25 | .fade-transform-leave-to {
26 | opacity: 0;
27 | transform: translateX(30px);
28 | }
29 |
30 | /* breadcrumb transition */
31 | .breadcrumb-enter-active,
32 | .breadcrumb-leave-active {
33 | transition: all .5s;
34 | }
35 |
36 | .breadcrumb-enter,
37 | .breadcrumb-leave-active {
38 | opacity: 0;
39 | transform: translateX(20px);
40 | }
41 |
42 | .breadcrumb-move {
43 | transition: all .5s;
44 | }
45 |
46 | .breadcrumb-leave-active {
47 | position: absolute;
48 | }
49 |
--------------------------------------------------------------------------------
/src/styles/variables.scss:
--------------------------------------------------------------------------------
1 | // base color
2 | $blue:#324157;
3 | $light-blue:#3A71A8;
4 | $red:#C03639;
5 | $pink: #E65D6E;
6 | $green: #30B08F;
7 | $tiffany: #4AB7BD;
8 | $yellow:#FEC171;
9 | $panGreen: #30B08F;
10 |
11 | // sidebar
12 | $menuText:#fff;
13 | $menuActiveText:#fff;
14 | $subMenuActiveText:#f4f4f5; // https://github.com/ElemeFE/element/issues/12951
15 |
16 | $menuBg:#0d5391;
17 | $menuHover:#999;
18 |
19 | $subMenuBg:#0d5391;
20 | $subMenuHover:#999;
21 | $subMenuText: #333;
22 |
23 | $sideBarWidth: 210px;
24 |
25 | // the :export directive is the magic sauce for webpack
26 | // https://www.bluematador.com/blog/how-to-share-variables-between-js-and-sass
27 | :export {
28 | menuText: $menuText;
29 | menuActiveText: $menuActiveText;
30 | subMenuActiveText: $subMenuActiveText;
31 | menuBg: $menuBg;
32 | menuHover: $menuHover;
33 | subMenuBg: $subMenuBg;
34 | subMenuHover: $subMenuHover;
35 | sideBarWidth: $sideBarWidth;
36 | }
37 |
--------------------------------------------------------------------------------
/src/utils/auth.js:
--------------------------------------------------------------------------------
1 | import Cookies from 'js-cookie'
2 |
3 | const TokenKey = 'vue_admin_template_token'
4 |
5 | export function getToken() {
6 | return Cookies.get(TokenKey)
7 | }
8 |
9 | export function setToken(token) {
10 | console.log(token)
11 | return Cookies.set(TokenKey, token, { expires: 360000 })
12 |
13 | }
14 |
15 | export function removeToken() {
16 | console.log('删除')
17 | return Cookies.remove(TokenKey)
18 | }
19 |
--------------------------------------------------------------------------------
/src/utils/get-page-title.js:
--------------------------------------------------------------------------------
1 | import defaultSettings from '@/settings'
2 |
3 | const title = defaultSettings.title || 'Vue Admin Template'
4 |
5 | export default function getPageTitle(pageTitle) {
6 | if (pageTitle) {
7 | return `${pageTitle} - ${title}`
8 | }
9 | return `${title}`
10 | }
11 |
--------------------------------------------------------------------------------
/src/utils/index.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Created by PanJiaChen on 16/11/18.
3 | */
4 |
5 | /**
6 | * Parse the time to string
7 | * @param {(Object|string|number)} time
8 | * @param {string} cFormat
9 | * @returns {string | null}
10 | */
11 | export function parseTime(time, cFormat) {
12 | if (arguments.length === 0) {
13 | return null
14 | }
15 | const format = cFormat || '{y}-{m}-{d} {h}:{i}:{s}'
16 | let date
17 | if (typeof time === 'object') {
18 | date = time
19 | } else {
20 | if ((typeof time === 'string') && (/^[0-9]+$/.test(time))) {
21 | time = parseInt(time)
22 | }
23 | if ((typeof time === 'number') && (time.toString().length === 10)) {
24 | time = time * 1000
25 | }
26 | date = new Date(time)
27 | }
28 | const formatObj = {
29 | y: date.getFullYear(),
30 | m: date.getMonth() + 1,
31 | d: date.getDate(),
32 | h: date.getHours(),
33 | i: date.getMinutes(),
34 | s: date.getSeconds(),
35 | a: date.getDay()
36 | }
37 | const time_str = format.replace(/{([ymdhisa])+}/g, (result, key) => {
38 | const value = formatObj[key]
39 | // Note: getDay() returns 0 on Sunday
40 | if (key === 'a') { return ['日', '一', '二', '三', '四', '五', '六'][value ] }
41 | return value.toString().padStart(2, '0')
42 | })
43 | return time_str
44 | }
45 |
46 | /**
47 | * @param {number} time
48 | * @param {string} option
49 | * @returns {string}
50 | */
51 | export function formatTime(time, option) {
52 | if (('' + time).length === 10) {
53 | time = parseInt(time) * 1000
54 | } else {
55 | time = +time
56 | }
57 | const d = new Date(time)
58 | const now = Date.now()
59 |
60 | const diff = (now - d) / 1000
61 |
62 | if (diff < 30) {
63 | return '刚刚'
64 | } else if (diff < 3600) {
65 | // less 1 hour
66 | return Math.ceil(diff / 60) + '分钟前'
67 | } else if (diff < 3600 * 24) {
68 | return Math.ceil(diff / 3600) + '小时前'
69 | } else if (diff < 3600 * 24 * 2) {
70 | return '1天前'
71 | }
72 | if (option) {
73 | return parseTime(time, option)
74 | } else {
75 | return (
76 | d.getMonth() +
77 | 1 +
78 | '月' +
79 | d.getDate() +
80 | '日' +
81 | d.getHours() +
82 | '时' +
83 | d.getMinutes() +
84 | '分'
85 | )
86 | }
87 | }
88 |
89 | /**
90 | * @param {string} url
91 | * @returns {Object}
92 | */
93 | export function param2Obj(url) {
94 | const search = url.split('?')[1]
95 | if (!search) {
96 | return {}
97 | }
98 | return JSON.parse(
99 | '{"' +
100 | decodeURIComponent(search)
101 | .replace(/"/g, '\\"')
102 | .replace(/&/g, '","')
103 | .replace(/=/g, '":"')
104 | .replace(/\+/g, ' ') +
105 | '"}'
106 | )
107 | }
108 |
--------------------------------------------------------------------------------
/src/utils/request.js:
--------------------------------------------------------------------------------
1 | import axios from 'axios'
2 | import { MessageBox, Message } from 'element-ui'
3 | import store from '@/store'
4 | import { getToken } from '@/utils/auth'
5 |
6 | // create an axios instance
7 | const service = axios.create({
8 | // baseURL: 'http://192.168.1.193:8000', // url = base url + request url
9 | baseURL: process.env.VUE_APP_BASE_API, // url = base url + request url
10 | // withCredentials: true, // send cookies when cross-domain requests
11 | timeout: 5000, // request timeout
12 | headers: {
13 | 'Content-Type': 'application/json'
14 | }
15 | })
16 |
17 | // request interceptor
18 | service.interceptors.request.use(
19 | config => {
20 | // do something before request is sent
21 |
22 | if (store.getters.token) {
23 | // let each request carry token
24 | // ['X-Token'] is a custom headers key
25 | // please modify it according to the actual situation
26 | config.headers['Authorization'] = 'JWT ' + getToken()
27 | }
28 | return config
29 | },
30 | error => {
31 | // do something with request error
32 | console.log(error) // for debug
33 | return Promise.reject(error)
34 | }
35 | )
36 |
37 | // response interceptor
38 | service.interceptors.response.use(
39 | /**
40 | * If you want to get http information such as headers or status
41 | * Please return response => response
42 | */
43 |
44 | /**
45 | * Determine the request status by custom code
46 | * Here is just an example
47 | * You can also judge the status by HTTP Status Code
48 | */
49 | response => {
50 | const res = response.data
51 |
52 | // if the custom code is not 20000, it is judged as an error.
53 | if (res.code !== 20000) {
54 | Message({
55 | message: res.message || 'Error',
56 | type: 'error',
57 | duration: 5 * 1000
58 | })
59 | if (res.code === 50001) {
60 | Message({
61 | message: res.message,
62 | type: 'error',
63 | duration: 5 * 1000
64 | })
65 | }
66 | // 50008:非法的token; 50012:其他客户端登录了; 50014:Token 过期了;
67 | if (res.code === 50008 || res.code === 50012 || res.code === 50014) {
68 | // to re-login
69 | MessageBox.confirm('你已注销,可以取消以停留在此页,或重新登录', '已注销', {
70 | confirmButtonText: '重新登录',
71 | cancelButtonText: '取消',
72 | type: 'warning'
73 | }).then(() => {
74 | store.dispatch('user/resetToken').then(() => {
75 | location.reload()
76 | })
77 | })
78 | }
79 | return Promise.reject(new Error(res.message || 'Error'))
80 | } else {
81 | return res
82 | }
83 | },
84 | error => {
85 | console.log('err' + error) // for debug
86 | Message({
87 | message: error.message,
88 | type: 'error',
89 | duration: 5 * 1000
90 | })
91 | return Promise.reject(error)
92 | }
93 | )
94 |
95 | export default service
96 |
--------------------------------------------------------------------------------
/src/utils/scroll-to.js:
--------------------------------------------------------------------------------
1 | Math.easeInOutQuad = function(t, b, c, d) {
2 | t /= d / 2
3 | if (t < 1) {
4 | return c / 2 * t * t + b
5 | }
6 | t--
7 | return -c / 2 * (t * (t - 2) - 1) + b
8 | }
9 |
10 | // requestAnimationFrame for Smart Animating http://goo.gl/sx5sts
11 | var requestAnimFrame = (function() {
12 | return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || function(callback) { window.setTimeout(callback, 1000 / 60) }
13 | })()
14 |
15 | /**
16 | * Because it's so fucking difficult to detect the scrolling element, just move them all
17 | * @param {number} amount
18 | */
19 | function move(amount) {
20 | document.documentElement.scrollTop = amount
21 | document.body.parentNode.scrollTop = amount
22 | document.body.scrollTop = amount
23 | }
24 |
25 | function position() {
26 | return document.documentElement.scrollTop || document.body.parentNode.scrollTop || document.body.scrollTop
27 | }
28 |
29 | /**
30 | * @param {number} to
31 | * @param {number} duration
32 | * @param {Function} callback
33 | */
34 | export function scrollTo(to, duration, callback) {
35 | const start = position()
36 | const change = to - start
37 | const increment = 20
38 | let currentTime = 0
39 | duration = (typeof (duration) === 'undefined') ? 500 : duration
40 | var animateScroll = function() {
41 | // increment the time
42 | currentTime += increment
43 | // find the value with the quadratic in-out easing function
44 | var val = Math.easeInOutQuad(currentTime, start, change, duration)
45 | // move the document.body
46 | move(val)
47 | // do the animation unless its over
48 | if (currentTime < duration) {
49 | requestAnimFrame(animateScroll)
50 | } else {
51 | if (callback && typeof (callback) === 'function') {
52 | // the animation is done so lets callback
53 | callback()
54 | }
55 | }
56 | }
57 | animateScroll()
58 | }
59 |
--------------------------------------------------------------------------------
/src/utils/validate.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Created by PanJiaChen on 16/11/18.
3 | */
4 |
5 | /**
6 | * @param {string} path
7 | * @returns {Boolean}
8 | */
9 | export function isExternal(path) {
10 | return /^(https?:|mailto:|tel:)/.test(path)
11 | }
12 |
13 | /**
14 | * @param {string} str
15 | * @returns {Boolean}
16 | */
17 | export function validUsername(str) {
18 | const valid_map = ['admin', 'editor']
19 | return valid_map.indexOf(str.trim()) >= 0
20 | }
21 |
--------------------------------------------------------------------------------
/src/vendor/Export2Zip.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 | import { saveAs } from 'file-saver'
3 | import JSZip from 'jszip'
4 |
5 | export function export_txt_to_zip(th, jsonData, txtName, zipName) {
6 | const zip = new JSZip()
7 | const txt_name = txtName || 'file'
8 | const zip_name = zipName || 'file'
9 | const data = jsonData
10 | let txtData = `${th}\r\n`
11 | data.forEach((row) => {
12 | let tempStr = ''
13 | tempStr = row.toString()
14 | txtData += `${tempStr}\r\n`
15 | })
16 | zip.file(`${txt_name}.txt`, txtData)
17 | zip.generateAsync({
18 | type: "blob"
19 | }).then((blob) => {
20 | saveAs(blob, `${zip_name}.zip`)
21 | }, (err) => {
22 | alert('导出失败')
23 | })
24 | }
25 |
--------------------------------------------------------------------------------
/src/views/dashboard/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
用户名: {{ name }}
4 |
权限: {{ role }}
5 |
6 |
7 |
8 |
21 |
22 |
33 |
--------------------------------------------------------------------------------
/src/views/documentation/details.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | ------
9 |
10 |
11 |
12 |
13 | {{ node.label }}
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 | 关键字
25 |
26 |
27 | {{'列表内容 ' + o }}
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 | 文章标题
37 |
38 |
39 | 中赢智数(广东)科技有限公司成立于2015年,以为政府及国有企业进行数据治理及大数据分析、数据咨询服务为核心业务及发展目标,为审计机关、检察院、纪委、财政、政府办公厅、工商等政府部门及国资委企业客户提供数据治理及数据分析产品及服务整体解决方案.公司成立产品研发中心、数据分析服务中心、实施交付中心等技术部门。用精湛的技术服务于广大客户并不断累积丰富的经验,为审计机关、教育从审计产品开发、实施及数据服务提供全方位的解决方案。
40 | 中赢智数(广东)科技有限公司成立于2015年,以为政府及国有企业进行数据治理及大数据分析、数据咨询服务为核心业务及发展目标,为审计机关、检察院、纪委、财政、政府办公厅、工商等政府部门及国资委企业客户提供数据治理及数据分析产品及服务整体解决方案。
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
54 |
55 |
56 |
57 |
103 |
156 |
--------------------------------------------------------------------------------
/src/views/documentation/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
数据·知识·智能
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 | 法律
24 | 法规
25 | 审计
26 | 工商
27 | 公司
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
38 |
39 |
40 |
41 |
60 |
78 |
--------------------------------------------------------------------------------
/src/views/editor/index.scss:
--------------------------------------------------------------------------------
1 | @backgroundColor: #fbfbfb;
2 | @borderColor: #dadce0;
3 |
4 | @itempannelAndPageBorder: 1px solid #ccc;
5 | @pageHeight: calc(100vh - 41px - 37px);
6 |
7 | body {
8 | margin: 0;
9 | overflow: hidden;
10 | }
11 |
12 | #vue-g6-editor {
13 | header:nth-of-type(1) {
14 | background: @backgroundColor;
15 | line-height: 40px;
16 | padding-left: 20px;
17 | border-bottom: 1px solid @borderColor;
18 | box-sizing: border-box;
19 | }
20 | #toolbar {
21 | background: @backgroundColor;
22 | border-bottom: 1px solid @borderColor;
23 | padding: 4px 14px;
24 | i {
25 | font-size: 18px;
26 | padding: 4px;
27 | margin-right: 8px;
28 | color: #999999;
29 | &:hover {
30 | cursor: pointer;
31 | background-color: #eeeeee;
32 | color: #5cb6ff;
33 | }
34 | }
35 | }
36 | #itempannel {
37 | box-sizing: border-box;
38 | background-color: @backgroundColor;
39 | border-right: 1px solid @borderColor;
40 | height: @pageHeight;
41 | padding-top: 10px;
42 | overflow: hidden;
43 | display: flex;
44 | flex-direction: row;
45 | flex-wrap: wrap;
46 | justify-content: space-around;
47 | align-content: flex-start;
48 | .getItem {
49 | cursor: move;
50 | width: 80px;
51 | height: 80px;
52 | margin-bottom: 20px;
53 | display: flex;
54 | justify-content: center;
55 | align-items: center;
56 | img {
57 | width: 100%;
58 | }
59 | }
60 | }
61 | #page {
62 | height: @pageHeight;
63 | canvas {
64 | display: block;
65 | width: 100%;
66 | }
67 | }
68 | .right-part {
69 | height: @pageHeight;
70 | display: flex;
71 | flex-direction: column;
72 | justify-content: flex-start;
73 | }
74 | #detailpannel {
75 | flex-grow: 1;
76 |
77 | background-color: @backgroundColor;
78 | border-left: 1px solid @borderColor;
79 | overflow-y: scroll;
80 | #nodeAttributeBar,
81 | #edgeAttributeBar,
82 | #groupAttributeBar,
83 | #canvasAttributeBar,
84 | #multiAttributeBar {
85 | .title {
86 | height: 34px;
87 | line-height: 34px;
88 | text-align: center;
89 | box-sizing: border-box;
90 | font-weight: bold;
91 | font-size: 13px;
92 | border-width: 0 0 1px 0;
93 | border-style: solid;
94 | border-color: @borderColor;
95 | }
96 | .main {
97 | padding: 10px;
98 | }
99 | }
100 | }
101 | #minimap {
102 | background-color: @backgroundColor;
103 | border-top: 1px solid #ccc;
104 | border-left: 1px solid #ccc;
105 | .title {
106 | height: 34px;
107 | line-height: 34px;
108 | text-align: center;
109 | box-sizing: border-box;
110 | font-weight: bold;
111 | font-size: 13px;
112 | border-width: 0 0 1px 0;
113 | border-style: solid;
114 | border-color: @borderColor;
115 | }
116 | }
117 | #contextmenu {
118 | display: none;
119 | .menu {
120 | /deep/ .el-button {
121 | width: 100%;
122 | display: block;
123 | margin-left: 0;
124 | border-radius: 0 !important;
125 | border-bottom: none;
126 | &:nth-last-of-type(1) {
127 | border-bottom: 1px solid #dcdfe6;
128 | }
129 | }
130 | }
131 | }
132 | .save-as-image-dialog {
133 | /deep/ .el-select {
134 | display: block;
135 | }
136 | }
137 | }
138 |
--------------------------------------------------------------------------------
/src/views/editor/mixin.js:
--------------------------------------------------------------------------------
1 | export default {
2 | methods: {
3 | // 保存节点属性
4 | saveNodeAttribute() {
5 | this.editor.executeCommand(() => {
6 | // 获取画布
7 | const page = this.editor.getCurrentPage()
8 | // 获取所选对象
9 | const selectedItem = page.getSelected()[0]
10 | page.update(selectedItem.id, {
11 | label: this.nodeAttributeForm.label,
12 | size: this.nodeAttributeForm.width + '*' + this.nodeAttributeForm.height,
13 | color: this.nodeAttributeForm.color
14 | })
15 | })
16 | },
17 | // 保存边属性
18 | saveEdgeAttribute() {
19 | this.editor.executeCommand(() => {
20 | // 获取画布
21 | const page = this.editor.getCurrentPage()
22 | // 获取所选对象
23 | const selectedItem = page.getSelected()[0]
24 | console.log(this.edgeAttributeForm)
25 | page.update(selectedItem.id, {
26 | label: this.edgeAttributeForm.label,
27 | shape: this.edgeAttributeForm.shape
28 | })
29 | })
30 | }
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/views/nested/menu1/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/src/views/nested/menu1/menu1-1/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/src/views/nested/menu1/menu1-2/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/src/views/nested/menu1/menu1-2/menu1-2-1/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/src/views/nested/menu1/menu1-2/menu1-2-2/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/src/views/nested/menu1/menu1-3/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/src/views/nested/menu2/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/src/views/redirect/index.vue:
--------------------------------------------------------------------------------
1 |
13 |
--------------------------------------------------------------------------------
/static/css/chunk-575555d9.96b835c7.css:
--------------------------------------------------------------------------------
1 | @supports (-webkit-mask:none) and (not (cater-color:#fff)){.login-container .el-input input{color:#fff}}.login-container .el-input{display:inline-block;height:47px;width:85%}.login-container .el-input input{background:transparent;border:0;-webkit-appearance:none;border-radius:0;padding:12px 5px 12px 15px;color:#fff;height:47px;caret-color:#fff}.login-container .el-input input:-webkit-autofill{-webkit-box-shadow:0 0 0 1000px #283443 inset!important;box-shadow:inset 0 0 0 1000px #283443!important;-webkit-text-fill-color:#fff!important}.login-container .el-form-item{border:1px solid hsla(0,0%,100%,.1);background:rgba(0,0,0,.1);border-radius:5px;color:#454545}.login-container[data-v-55776db6]{min-height:100%;width:100%;background-color:#2d3a4b;overflow:hidden}.login-container .login-form[data-v-55776db6]{position:relative;width:520px;max-width:100%;padding:160px 35px 0;margin:0 auto;overflow:hidden}.login-container .tips[data-v-55776db6]{font-size:14px;color:#fff;margin-bottom:10px}.login-container .tips span[data-v-55776db6]:first-of-type{margin-right:16px}.login-container .svg-container[data-v-55776db6]{padding:6px 5px 6px 15px;color:#889aa4;vertical-align:middle;width:30px;display:inline-block}.login-container .title-container[data-v-55776db6]{position:relative}.login-container .title-container .title[data-v-55776db6]{font-size:26px;color:#eee;margin:0 auto 40px auto;text-align:center;font-weight:700}.login-container .show-pwd[data-v-55776db6]{position:absolute;right:10px;top:7px;font-size:16px;color:#889aa4;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}
--------------------------------------------------------------------------------
/static/css/chunk-768ebd2f.a1c9ad1b.css:
--------------------------------------------------------------------------------
1 | #vue-g6-editor .database{overflow:hidden}#vue-g6-editor .el-menu{background-color:#fbfbfb}#vue-g6-editor .el-submenu__title{height:35px;line-height:35px}#vue-g6-editor header:first-of-type{background:#fbfbfb;line-height:40px;padding-left:20px;border-bottom:1px solid #dadce0;-webkit-box-sizing:border-box;box-sizing:border-box}#vue-g6-editor #toolbar{background:#fbfbfb;border-bottom:1px solid #dadce0;padding:4px 14px}#vue-g6-editor #toolbar i{font-size:15px;padding:4px;margin-right:8px;color:#333}#vue-g6-editor #toolbar i:hover{cursor:pointer;background-color:#eee;color:#5cb6ff}#vue-g6-editor #itempannel{-webkit-box-sizing:border-box;box-sizing:border-box;background-color:#f7f9fb;border-right:1px solid #dadce0;height:calc(100vh - 78px);padding-top:10px;overflow:hidden;display:inherit;-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-direction:row;flex-direction:row;-ms-flex-wrap:wrap;flex-wrap:wrap;-ms-flex-pack:distribute;justify-content:space-around;-ms-flex-line-pack:start;align-content:flex-start}#vue-g6-editor #itempannel .getItem{color:rgba(0,0,0,.65);border-radius:4px;height:28px;line-height:26px;padding-left:8px;list-style-type:none;font-size:12px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}#vue-g6-editor #page{height:calc(71vh - 78px)}#vue-g6-editor #page canvas{display:block;width:100%}#vue-g6-editor .right-part{height:calc(100vh - 78px);display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;-webkit-box-pack:start;-ms-flex-pack:start;justify-content:flex-start}#vue-g6-editor #detailpannel{-webkit-box-flex:1;-ms-flex-positive:1;flex-grow:1;background-color:#fbfbfb;border-left:1px solid #dadce0;overflow-y:scroll}#vue-g6-editor #detailpannel #canvasAttributeBar .title,#vue-g6-editor #detailpannel #edgeAttributeBar .title,#vue-g6-editor #detailpannel #groupAttributeBar .title,#vue-g6-editor #detailpannel #multiAttributeBar .title,#vue-g6-editor #detailpannel #nodeAttributeBar .title{height:34px;line-height:34px;text-align:center;-webkit-box-sizing:border-box;box-sizing:border-box;font-weight:700;font-size:13px;border-width:0 0 1px 0;border-style:solid;border-color:#dadce0}#vue-g6-editor #detailpannel #canvasAttributeBar .main,#vue-g6-editor #detailpannel #edgeAttributeBar .main,#vue-g6-editor #detailpannel #groupAttributeBar .main,#vue-g6-editor #detailpannel #multiAttributeBar .main,#vue-g6-editor #detailpannel #nodeAttributeBar .main{padding:10px}#vue-g6-editor #minimap{background-color:#fbfbfb;border-top:1px solid #ccc;border-left:1px solid #ccc}#vue-g6-editor #minimap .title{height:34px;line-height:34px;text-align:center;-webkit-box-sizing:border-box;box-sizing:border-box;font-weight:700;font-size:13px;border-width:0 0 1px 0;border-style:solid;border-color:#dadce0}#vue-g6-editor #contextmenu{display:none}#vue-g6-editor #contextmenu .menu .el-button{width:100%;display:block;margin-left:0;border-radius:0!important;border-bottom:none}#vue-g6-editor #contextmenu .menu .el-button:last-of-type{border-bottom:1px solid #dcdfe6}#vue-g6-editor .save-as-image-dialog .el-select{display:block}#vue-g6-editor .el-pagination{text-align:center}#vue-g6-editor .el-table--medium td,#vue-g6-editor .el-table--medium th{padding:5px 0}#vue-g6-editor .el-table{height:calc(40vh - 78px)!important}.itempannel ul{padding:0;padding-left:16px;border-bottom:1px solid #ccc;padding-bottom:20px}.itempannel li{color:rgba(0,0,0,.65);border-radius:4px;height:28px;line-height:26px;padding-left:8px;border:1px solid transparent;list-style-type:none;font-size:12px}.itempannel li,.itempannel li:hover{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.itempannel li:hover{width:160px}.itempanel li:hover,.itempannel li:hover{background:#fff;border:1px solid #ced4d9;cursor:move}.itempannel .icon{width:16px;height:16px;display:inline-block;vertical-align:middle;margin-right:8px;font-size:14px;background:url(https://gw.alipayobjects.com/zos/rmsportal/czNEJAmyDpclFaSucYWB.svg)}.itempannel h6{font-size:15px;text-align:center;padding:0;margin:0;margin-bottom:14px}.itempannel i{margin-right:10px;margin-left:-10px}
--------------------------------------------------------------------------------
/static/css/chunk-cbb61e6a.6e6cbd15.css:
--------------------------------------------------------------------------------
1 | .knowledge[data-v-74c84609]{padding-top:50px}.knowledge h3[data-v-74c84609]{text-align:center}.knowledge h3 span[data-v-74c84609]{font-size:20px}.knowledge .el-row[data-v-74c84609]{margin-bottom:20px}.knowledge .el-button--primary[data-v-74c84609]{background-color:#0d5391;border-color:#0d5391}
--------------------------------------------------------------------------------
/static/css/chunk-d7a7d948.5719ffb1.css:
--------------------------------------------------------------------------------
1 | .dashboard-container[data-v-682337c0]{margin:30px}.dashboard-text[data-v-682337c0]{font-size:30px;line-height:46px}
--------------------------------------------------------------------------------
/static/css/chunk-f1a6febe.2f3c92ef.css:
--------------------------------------------------------------------------------
1 | .knowledgeDetails[data-v-2636a9b4]{padding-top:10px}.knowledgeDetails .fa-fw[data-v-2636a9b4]{margin-right:5px}.knowledgeDetails .grid-content[data-v-2636a9b4]{height:calc(100vh - 80px)}.knowledgeDetails .grid-content .article[data-v-2636a9b4]{text-indent:30px;line-height:25px;font-size:14px}.knowledgeDetails .grid-content .el-card[data-v-2636a9b4]{height:100%}.knowledgeDetails .grid-content .el-tree[data-v-2636a9b4],.knowledgeDetails .grid-content .text[data-v-2636a9b4]{font-size:14px}.knowledgeDetails .grid-content .item[data-v-2636a9b4]{margin-bottom:18px}.knowledgeDetails .grid-content .clearfix[data-v-2636a9b4]:after,.knowledgeDetails .grid-content .clearfix[data-v-2636a9b4]:before{display:table;content:""}.knowledgeDetails .grid-content .clearfix[data-v-2636a9b4]:after{clear:both}.knowledgeDetails .lists li[data-v-2636a9b4]{list-style:none;margin-bottom:10px}.knowledgeDetails h3[data-v-2636a9b4]{text-align:center}.knowledgeDetails h3 span[data-v-2636a9b4]{font-size:20px}.knowledgeDetails .el-row[data-v-2636a9b4]{margin-bottom:20px}
--------------------------------------------------------------------------------
/static/fonts/element-icons.2fad952a.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhangwenwu/vue-element-admin-g6-editor/582636f1b259b573a7a0df9ccb3f82013d282fbb/static/fonts/element-icons.2fad952a.woff
--------------------------------------------------------------------------------
/static/fonts/element-icons.6f0a7632.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhangwenwu/vue-element-admin-g6-editor/582636f1b259b573a7a0df9ccb3f82013d282fbb/static/fonts/element-icons.6f0a7632.ttf
--------------------------------------------------------------------------------
/static/fonts/fontawesome-webfont.674f50d2.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhangwenwu/vue-element-admin-g6-editor/582636f1b259b573a7a0df9ccb3f82013d282fbb/static/fonts/fontawesome-webfont.674f50d2.eot
--------------------------------------------------------------------------------
/static/fonts/fontawesome-webfont.af7ae505.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhangwenwu/vue-element-admin-g6-editor/582636f1b259b573a7a0df9ccb3f82013d282fbb/static/fonts/fontawesome-webfont.af7ae505.woff2
--------------------------------------------------------------------------------
/static/fonts/fontawesome-webfont.b06871f2.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhangwenwu/vue-element-admin-g6-editor/582636f1b259b573a7a0df9ccb3f82013d282fbb/static/fonts/fontawesome-webfont.b06871f2.ttf
--------------------------------------------------------------------------------
/static/fonts/fontawesome-webfont.fee66e71.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhangwenwu/vue-element-admin-g6-editor/582636f1b259b573a7a0df9ccb3f82013d282fbb/static/fonts/fontawesome-webfont.fee66e71.woff
--------------------------------------------------------------------------------
/static/img/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhangwenwu/vue-element-admin-g6-editor/582636f1b259b573a7a0df9ccb3f82013d282fbb/static/img/favicon.ico
--------------------------------------------------------------------------------
/static/img/logo.7ec6731e.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhangwenwu/vue-element-admin-g6-editor/582636f1b259b573a7a0df9ccb3f82013d282fbb/static/img/logo.7ec6731e.png
--------------------------------------------------------------------------------
/static/js/chunk-2d0da8f7.37c90bb0.js:
--------------------------------------------------------------------------------
1 | (window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-2d0da8f7"],{"6bb7":function(n,u,l){"use strict";l.r(u);var a,c,e=l("2877"),o={},p=Object(e["a"])(o,a,c,!1,null,null,null);u["default"]=p.exports}}]);
--------------------------------------------------------------------------------
/static/js/chunk-2d21446b.65936c26.js:
--------------------------------------------------------------------------------
1 | (window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-2d21446b"],{aff6:function(n,u,l){"use strict";l.r(u);var a,c,e=l("2877"),o={},p=Object(e["a"])(o,a,c,!1,null,null,null);u["default"]=p.exports}}]);
--------------------------------------------------------------------------------
/static/js/chunk-575555d9.a6bafad6.js:
--------------------------------------------------------------------------------
1 | (window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-575555d9"],{2017:function(e,t,n){"use strict";var s=n("b12d"),o=n.n(s);o.a},"3e0a":function(e,t,n){"use strict";var s=n("8dc6"),o=n.n(s);o.a},"8dc6":function(e,t,n){},"9ed6":function(e,t,n){"use strict";n.r(t);var s=function(){var e=this,t=e.$createElement,n=e._self._c||t;return n("div",{staticClass:"login-container"},[n("el-form",{ref:"loginForm",staticClass:"login-form",attrs:{model:e.loginForm,rules:e.loginRules,"auto-complete":"on","label-position":"left"}},[n("div",{staticClass:"title-container"},[n("h3",{staticClass:"title"},[e._v("系统登录")])]),e._v(" "),n("el-form-item",{attrs:{prop:"username"}},[n("span",{staticClass:"svg-container"},[n("svg-icon",{attrs:{"icon-class":"user"}})],1),e._v(" "),n("el-input",{ref:"username",attrs:{placeholder:"Username",name:"username",type:"text",tabindex:"1","auto-complete":"on"},model:{value:e.loginForm.username,callback:function(t){e.$set(e.loginForm,"username",t)},expression:"loginForm.username"}})],1),e._v(" "),n("el-form-item",{attrs:{prop:"password"}},[n("span",{staticClass:"svg-container"},[n("svg-icon",{attrs:{"icon-class":"password"}})],1),e._v(" "),n("el-input",{key:e.passwordType,ref:"password",attrs:{type:e.passwordType,placeholder:"Password",name:"password",tabindex:"2","auto-complete":"on"},nativeOn:{keyup:function(t){return!t.type.indexOf("key")&&e._k(t.keyCode,"enter",13,t.key,"Enter")?null:e.handleLogin(t)}},model:{value:e.loginForm.password,callback:function(t){e.$set(e.loginForm,"password",t)},expression:"loginForm.password"}}),e._v(" "),n("span",{staticClass:"show-pwd",on:{click:e.showPwd}},[n("svg-icon",{attrs:{"icon-class":"password"===e.passwordType?"eye":"eye-open"}})],1)],1),e._v(" "),n("el-button",{staticStyle:{width:"100%","margin-bottom":"30px"},attrs:{loading:e.loading,type:"primary"},nativeOn:{click:function(t){return t.preventDefault(),e.handleLogin(t)}}},[e._v("登录")])],1)],1)},o=[],r=n("61f7"),a={name:"Login",data:function(){var e=function(e,t,n){Object(r["b"])(t)?n():n(new Error("Please enter the correct user name"))},t=function(e,t,n){t.length<4?n(new Error("The password can not be less than 6 digits")):n()};return{loginForm:{username:"admin",password:"admin"},loginRules:{username:[{required:!0,trigger:"blur",validator:e}],password:[{required:!0,trigger:"blur",validator:t}]},loading:!1,passwordType:"password",redirect:void 0}},watch:{$route:{handler:function(e){this.redirect=e.query&&e.query.redirect},immediate:!0}},methods:{showPwd:function(){var e=this;"password"===this.passwordType?this.passwordType="":this.passwordType="password",this.$nextTick((function(){e.$refs.password.focus()}))},handleLogin:function(){var e=this;this.$refs.loginForm.validate((function(t){if(!t)return console.log("error submit!!"),!1;e.loading=!0,e.$store.dispatch("user/login",e.loginForm).then((function(){e.$router.push({path:e.redirect||"/"}),e.loading=!1})).catch((function(){e.loading=!1}))}))}}},i=a,l=(n("2017"),n("3e0a"),n("2877")),c=Object(l["a"])(i,s,o,!1,null,"55776db6",null);t["default"]=c.exports},b12d:function(e,t,n){}}]);
--------------------------------------------------------------------------------
/static/js/chunk-cbb61e6a.eb74048e.js:
--------------------------------------------------------------------------------
1 | (window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-cbb61e6a"],{"25fa":function(t,e,a){"use strict";var i=a("d005"),s=a.n(i);s.a},"3c34":function(t,e,a){"use strict";a.r(e);var i=function(){var t=this,e=t.$createElement,a=t._self._c||e;return a("div",{staticClass:"knowledge"},[a("el-row",[a("el-col",{attrs:{span:24}},[a("div",{staticClass:"grid-content bg-purple-dark"},[a("h3",{staticClass:"title"},[t._v("数据"),a("span",[t._v("·")]),t._v("知识"),a("span",[t._v("·")]),t._v("智能")])])])],1),t._v(" "),a("el-row",{attrs:{gutter:20}},[a("el-col",{attrs:{span:12,offset:6}},[a("div",{staticClass:"grid-content bg-purple"},[a("div",[a("el-input",{staticClass:"input-with-select",attrs:{placeholder:"请输入内容"},model:{value:t.search,callback:function(e){t.search=e},expression:"search"}},[a("el-button",{attrs:{slot:"append",icon:"el-icon-search"},on:{click:t.enterSearch},slot:"append"})],1)],1)])])],1),t._v(" "),a("el-row",{attrs:{gutter:20}},[a("el-col",{attrs:{span:12,offset:6}},[a("el-button",{attrs:{type:"primary",size:"mini"}},[t._v("法律")]),t._v(" "),a("el-button",{attrs:{type:"primary",size:"mini"}},[t._v("法规")]),t._v(" "),a("el-button",{attrs:{type:"primary",size:"mini"}},[t._v("审计")]),t._v(" "),a("el-button",{attrs:{type:"primary",size:"mini"}},[t._v("工商")]),t._v(" "),a("el-button",{attrs:{type:"primary",size:"mini"}},[t._v("公司")])],1)],1),t._v(" "),a("el-dialog",{attrs:{visible:t.dialogPvVisible,title:"title"},on:{"update:visible":function(e){t.dialogPvVisible=e}}},[a("el-table",{staticStyle:{width:"100%"},attrs:{data:t.pvData,border:"",fit:"","highlight-current-row":""}},[a("el-table-column",{attrs:{prop:"key",label:"Channel"}}),t._v(" "),a("el-table-column",{attrs:{prop:"pv",label:"Pv"}})],1),t._v(" "),a("span",{staticClass:"dialog-footer",attrs:{slot:"footer"},slot:"footer"},[a("el-button",{attrs:{type:"primary"},on:{click:function(e){t.dialogPvVisible=!1}}},[t._v("取消")])],1)],1)],1)},s=[],l={data:function(){return{pvData:"",search:""}},created:function(){this.dialogPvVisible=!1},methods:{enterSearch:function(){this.$router.push({path:"/documentation/details/1"})}}},r=l,n=(a("25fa"),a("2877")),o=Object(n["a"])(r,i,s,!1,null,"74c84609",null);e["default"]=o.exports},d005:function(t,e,a){}}]);
--------------------------------------------------------------------------------
/static/js/chunk-d7a7d948.06e0cdfa.js:
--------------------------------------------------------------------------------
1 | (window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-d7a7d948"],{9406:function(t,a,s){"use strict";s.r(a);var n=function(){var t=this,a=t.$createElement,s=t._self._c||a;return s("div",{staticClass:"dashboard-container"},[s("div",{staticClass:"dashboard-text"},[t._v("用户名: "+t._s(t.name))]),t._v(" "),s("div",{staticClass:"dashboard-text"},[t._v("权限: "),t._l(t.roles,(function(a){return s("span",{key:a},[t._v(t._s(a))])}))],2)])},e=[],c=s("5530"),r=s("2f62"),d={name:"Dashboard",computed:Object(c["a"])({},Object(r["b"])(["name","roles"]))},o=d,i=(s("d117"),s("2877")),u=Object(i["a"])(o,n,e,!1,null,"682337c0",null);a["default"]=u.exports},d117:function(t,a,s){"use strict";var n=s("f250"),e=s.n(n);e.a},f250:function(t,a,s){}}]);
--------------------------------------------------------------------------------
/static/js/chunk-f1a6febe.6af28b13.js:
--------------------------------------------------------------------------------
1 | (window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-f1a6febe"],{bd9d:function(t,a,e){"use strict";var l=e("cbfa"),s=e.n(l);s.a},cbfa:function(t,a,e){},dc0f:function(t,a,e){"use strict";e.r(a);var l=function(){var t=this,a=t.$createElement,e=t._self._c||a;return e("div",{staticClass:"knowledgeDetails"},[e("el-row",[e("el-col",{attrs:{span:4}},[e("div",{staticClass:"grid-content bg-purple-dark"},[e("el-card",{staticClass:"box-card"},[e("div",{staticClass:"clearfix",attrs:{slot:"header"},slot:"header"},[e("span",[t._v("------")])]),t._v(" "),e("el-tree",{attrs:{data:t.data,props:t.defaultProps,"default-expand-all":"true"},on:{"node-click":t.handleNodeClick},scopedSlots:t._u([{key:"default",fn:function(a){var l=a.node;return e("span",{staticClass:"custom-tree-node"},[e("span",[e("i",{staticClass:"fa fa-file-o fa-fw"}),t._v(t._s(l.label)+"\n ")])])}}])})],1)],1)]),t._v(" "),e("el-col",{attrs:{span:4}},[e("div",{staticClass:"grid-content bg-purple-dark",staticStyle:{"border-left":"0","border-right":"0"}},[e("el-card",{staticClass:"box-card"},[e("div",{staticClass:"clearfix",attrs:{slot:"header"},slot:"header"},[e("span",[t._v("关键字")])]),t._v(" "),t._l(4,(function(a){return e("div",{key:a,staticClass:"text item"},[t._v("\n "+t._s("列表内容 "+a)+"\n ")])}))],2)],1)]),t._v(" "),e("el-col",{attrs:{span:16}},[e("div",{staticClass:"grid-content bg-purple-dark"},[e("el-card",{staticClass:"box-card"},[e("div",{staticClass:"clearfix",attrs:{slot:"header"},slot:"header"},[e("span",[t._v("文章标题")])]),t._v(" "),e("div",{staticClass:"article"},[t._v("\n 中赢智数(广东)科技有限公司成立于2015年,以为政府及国有企业进行数据治理及大数据分析、数据咨询服务为核心业务及发展目标,为审计机关、检察院、纪委、财政、政府办公厅、工商等政府部门及国资委企业客户提供数据治理及数据分析产品及服务整体解决方案.公司成立产品研发中心、数据分析服务中心、实施交付中心等技术部门。用精湛的技术服务于广大客户并不断累积丰富的经验,为审计机关、教育从审计产品开发、实施及数据服务提供全方位的解决方案。\n "),e("br"),t._v("中赢智数(广东)科技有限公司成立于2015年,以为政府及国有企业进行数据治理及大数据分析、数据咨询服务为核心业务及发展目标,为审计机关、检察院、纪委、财政、政府办公厅、工商等政府部门及国资委企业客户提供数据治理及数据分析产品及服务整体解决方案。\n ")])])],1)])],1),t._v(" "),e("el-dialog",{attrs:{visible:t.dialogPvVisible,title:"title"},on:{"update:visible":function(a){t.dialogPvVisible=a}}},[e("el-table",{staticStyle:{width:"100%"},attrs:{data:t.pvData,border:"",fit:"","highlight-current-row":""}},[e("el-table-column",{attrs:{prop:"key",label:"Channel"}}),t._v(" "),e("el-table-column",{attrs:{prop:"pv",label:"Pv"}})],1),t._v(" "),e("span",{staticClass:"dialog-footer",attrs:{slot:"footer"},slot:"footer"},[e("el-button",{attrs:{type:"primary"},on:{click:function(a){t.dialogPvVisible=!1}}},[t._v("取消")])],1)],1)],1)},s=[],i={data:function(){return{pvData:"",search:"",data:[{label:"法规库",children:[{label:"审计法规"}]},{label:"案例库",children:[{label:"审计案例"},{label:"审计案例3"}]},{label:"刑法库",children:[{label:"审计案例"},{label:"审计案例"}]}],defaultProps:{children:"children",label:"label"}}},created:function(){this.dialogPvVisible=!1},methods:{enterSearch:function(){this.$router.push({path:"/documentation/details/1"})},handleNodeClick:function(t){console.log(t)}}},r=i,n=(e("bd9d"),e("2877")),o=Object(n["a"])(r,l,s,!1,null,"2636a9b4",null);a["default"]=o.exports}}]);
--------------------------------------------------------------------------------
/tests/unit/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | env: {
3 | jest: true
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/tests/unit/components/Breadcrumb.spec.js:
--------------------------------------------------------------------------------
1 | import { mount, createLocalVue } from '@vue/test-utils'
2 | import VueRouter from 'vue-router'
3 | import ElementUI from 'element-ui'
4 | import Breadcrumb from '@/components/Breadcrumb/index.vue'
5 |
6 | const localVue = createLocalVue()
7 | localVue.use(VueRouter)
8 | localVue.use(ElementUI)
9 |
10 | const routes = [
11 | {
12 | path: '/',
13 | name: 'home',
14 | children: [{
15 | path: 'dashboard',
16 | name: 'dashboard'
17 | }]
18 | },
19 | {
20 | path: '/menu',
21 | name: 'menu',
22 | children: [{
23 | path: 'menu1',
24 | name: 'menu1',
25 | meta: { title: 'menu1' },
26 | children: [{
27 | path: 'menu1-1',
28 | name: 'menu1-1',
29 | meta: { title: 'menu1-1' }
30 | },
31 | {
32 | path: 'menu1-2',
33 | name: 'menu1-2',
34 | redirect: 'noredirect',
35 | meta: { title: 'menu1-2' },
36 | children: [{
37 | path: 'menu1-2-1',
38 | name: 'menu1-2-1',
39 | meta: { title: 'menu1-2-1' }
40 | },
41 | {
42 | path: 'menu1-2-2',
43 | name: 'menu1-2-2'
44 | }]
45 | }]
46 | }]
47 | }]
48 |
49 | const router = new VueRouter({
50 | routes
51 | })
52 |
53 | describe('Breadcrumb.vue', () => {
54 | const wrapper = mount(Breadcrumb, {
55 | localVue,
56 | router
57 | })
58 | it('dashboard', () => {
59 | router.push('/dashboard')
60 | const len = wrapper.findAll('.el-breadcrumb__inner').length
61 | expect(len).toBe(1)
62 | })
63 | it('normal route', () => {
64 | router.push('/menu/menu1')
65 | const len = wrapper.findAll('.el-breadcrumb__inner').length
66 | expect(len).toBe(2)
67 | })
68 | it('nested route', () => {
69 | router.push('/menu/menu1/menu1-2/menu1-2-1')
70 | const len = wrapper.findAll('.el-breadcrumb__inner').length
71 | expect(len).toBe(4)
72 | })
73 | it('no meta.title', () => {
74 | router.push('/menu/menu1/menu1-2/menu1-2-2')
75 | const len = wrapper.findAll('.el-breadcrumb__inner').length
76 | expect(len).toBe(3)
77 | })
78 | // it('click link', () => {
79 | // router.push('/menu/menu1/menu1-2/menu1-2-2')
80 | // const breadcrumbArray = wrapper.findAll('.el-breadcrumb__inner')
81 | // const second = breadcrumbArray.at(1)
82 | // console.log(breadcrumbArray)
83 | // const href = second.find('a').attributes().href
84 | // expect(href).toBe('#/menu/menu1')
85 | // })
86 | // it('noRedirect', () => {
87 | // router.push('/menu/menu1/menu1-2/menu1-2-1')
88 | // const breadcrumbArray = wrapper.findAll('.el-breadcrumb__inner')
89 | // const redirectBreadcrumb = breadcrumbArray.at(2)
90 | // expect(redirectBreadcrumb.contains('a')).toBe(false)
91 | // })
92 | it('last breadcrumb', () => {
93 | router.push('/menu/menu1/menu1-2/menu1-2-1')
94 | const breadcrumbArray = wrapper.findAll('.el-breadcrumb__inner')
95 | const redirectBreadcrumb = breadcrumbArray.at(3)
96 | expect(redirectBreadcrumb.contains('a')).toBe(false)
97 | })
98 | })
99 |
--------------------------------------------------------------------------------
/tests/unit/components/Hamburger.spec.js:
--------------------------------------------------------------------------------
1 | import { shallowMount } from '@vue/test-utils'
2 | import Hamburger from '@/components/Hamburger/index.vue'
3 | describe('Hamburger.vue', () => {
4 | it('toggle click', () => {
5 | const wrapper = shallowMount(Hamburger)
6 | const mockFn = jest.fn()
7 | wrapper.vm.$on('toggleClick', mockFn)
8 | wrapper.find('.hamburger').trigger('click')
9 | expect(mockFn).toBeCalled()
10 | })
11 | it('prop isActive', () => {
12 | const wrapper = shallowMount(Hamburger)
13 | wrapper.setProps({ isActive: true })
14 | expect(wrapper.contains('.is-active')).toBe(true)
15 | wrapper.setProps({ isActive: false })
16 | expect(wrapper.contains('.is-active')).toBe(false)
17 | })
18 | })
19 |
--------------------------------------------------------------------------------
/tests/unit/components/SvgIcon.spec.js:
--------------------------------------------------------------------------------
1 | import { shallowMount } from '@vue/test-utils'
2 | import SvgIcon from '@/components/SvgIcon/index.vue'
3 | describe('SvgIcon.vue', () => {
4 | it('iconClass', () => {
5 | const wrapper = shallowMount(SvgIcon, {
6 | propsData: {
7 | iconClass: 'test'
8 | }
9 | })
10 | expect(wrapper.find('use').attributes().href).toBe('#icon-test')
11 | })
12 | it('className', () => {
13 | const wrapper = shallowMount(SvgIcon, {
14 | propsData: {
15 | iconClass: 'test'
16 | }
17 | })
18 | expect(wrapper.classes().length).toBe(1)
19 | wrapper.setProps({ className: 'test' })
20 | expect(wrapper.classes().includes('test')).toBe(true)
21 | })
22 | })
23 |
--------------------------------------------------------------------------------
/tests/unit/utils/formatTime.spec.js:
--------------------------------------------------------------------------------
1 | import { formatTime } from '@/utils/index.js'
2 |
3 | describe('Utils:formatTime', () => {
4 | const d = new Date('2018-07-13 17:54:01') // "2018-07-13 17:54:01"
5 | const retrofit = 5 * 1000
6 |
7 | it('ten digits timestamp', () => {
8 | expect(formatTime((d / 1000).toFixed(0))).toBe('7月13日17时54分')
9 | })
10 | it('test now', () => {
11 | expect(formatTime(+new Date() - 1)).toBe('刚刚')
12 | })
13 | it('less two minute', () => {
14 | expect(formatTime(+new Date() - 60 * 2 * 1000 + retrofit)).toBe('2分钟前')
15 | })
16 | it('less two hour', () => {
17 | expect(formatTime(+new Date() - 60 * 60 * 2 * 1000 + retrofit)).toBe('2小时前')
18 | })
19 | it('less one day', () => {
20 | expect(formatTime(+new Date() - 60 * 60 * 24 * 1 * 1000)).toBe('1天前')
21 | })
22 | it('more than one day', () => {
23 | expect(formatTime(d)).toBe('7月13日17时54分')
24 | })
25 | it('format', () => {
26 | expect(formatTime(d, '{y}-{m}-{d} {h}:{i}')).toBe('2018-07-13 17:54')
27 | expect(formatTime(d, '{y}-{m}-{d}')).toBe('2018-07-13')
28 | expect(formatTime(d, '{y}/{m}/{d} {h}-{i}')).toBe('2018/07/13 17-54')
29 | })
30 | })
31 |
--------------------------------------------------------------------------------
/tests/unit/utils/parseTime.spec.js:
--------------------------------------------------------------------------------
1 | import { parseTime } from '@/utils/index.js'
2 |
3 | describe('Utils:parseTime', () => {
4 | const d = new Date('2018-07-13 17:54:01') // "2018-07-13 17:54:01"
5 | it('timestamp', () => {
6 | expect(parseTime(d)).toBe('2018-07-13 17:54:01')
7 | })
8 | it('ten digits timestamp', () => {
9 | expect(parseTime((d / 1000).toFixed(0))).toBe('2018-07-13 17:54:01')
10 | })
11 | it('new Date', () => {
12 | expect(parseTime(new Date(d))).toBe('2018-07-13 17:54:01')
13 | })
14 | it('format', () => {
15 | expect(parseTime(d, '{y}-{m}-{d} {h}:{i}')).toBe('2018-07-13 17:54')
16 | expect(parseTime(d, '{y}-{m}-{d}')).toBe('2018-07-13')
17 | expect(parseTime(d, '{y}/{m}/{d} {h}-{i}')).toBe('2018/07/13 17-54')
18 | })
19 | it('get the day of the week', () => {
20 | expect(parseTime(d, '{a}')).toBe('五') // 星期五
21 | })
22 | it('get the day of the week', () => {
23 | expect(parseTime(+d + 1000 * 60 * 60 * 24 * 2, '{a}')).toBe('日') // 星期日
24 | })
25 | it('empty argument', () => {
26 | expect(parseTime()).toBeNull()
27 | })
28 | })
29 |
--------------------------------------------------------------------------------
/tests/unit/utils/validate.spec.js:
--------------------------------------------------------------------------------
1 | import { validUsername, isExternal } from '@/utils/validate.js'
2 |
3 | describe('Utils:validate', () => {
4 | it('validUsername', () => {
5 | expect(validUsername('admin')).toBe(true)
6 | expect(validUsername('editor')).toBe(true)
7 | expect(validUsername('xxxx')).toBe(false)
8 | })
9 | it('isExternal', () => {
10 | expect(isExternal('https://github.com/PanJiaChen/vue-element-admin')).toBe(true)
11 | expect(isExternal('http://github.com/PanJiaChen/vue-element-admin')).toBe(true)
12 | expect(isExternal('github.com/PanJiaChen/vue-element-admin')).toBe(false)
13 | expect(isExternal('/dashboard')).toBe(false)
14 | expect(isExternal('./dashboard')).toBe(false)
15 | expect(isExternal('dashboard')).toBe(false)
16 | })
17 | })
18 |
--------------------------------------------------------------------------------
/vue.config.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | const path = require('path')
3 | const defaultSettings = require('./src/settings.js')
4 |
5 | function resolve(dir) {
6 | return path.join(__dirname, dir)
7 | }
8 |
9 | const name = defaultSettings.title || 'vue Element Admin' // page title
10 |
11 | // If your port is set to 80,
12 | // use administrator privileges to execute the command line.
13 | // For example, Mac: sudo npm run
14 | // You can change the port by the following method:
15 | // port = 9527 npm run dev OR npm run dev --port = 9527
16 | const port = process.env.port || process.env.npm_config_port || 8888 // dev port
17 |
18 | // All configuration item explanations can be find in https://cli.vuejs.org/config/
19 | module.exports = {
20 | /**
21 | * You will need to set publicPath if you plan to deploy your site under a sub path,
22 | * for example GitHub Pages. If you plan to deploy your site to https://foo.github.io/bar/,
23 | * then publicPath should be set to "/bar/".
24 | * In most cases please use '/' !!!
25 | * Detail: https://cli.vuejs.org/config/#publicpath
26 | */
27 | publicPath: './',
28 | outputDir: 'dist',
29 | assetsDir: 'static',
30 | lintOnSave: process.env.NODE_ENV === 'development',
31 | productionSourceMap: false,
32 | devServer: {
33 | port: port,
34 | open: false,
35 | overlay: {
36 | warnings: false,
37 | errors: true
38 | },
39 | before: require('./mock/mock-server.js')
40 | },
41 | configureWebpack: {
42 | // provide the app's title in webpack's name field, so that
43 | // it can be accessed in index.html to inject the correct title.
44 | name: name,
45 | resolve: {
46 | alias: {
47 | '@': resolve('src')
48 | }
49 | }
50 | },
51 | chainWebpack(config) {
52 | config.plugins.delete('preload') // TODO: need test
53 | config.plugins.delete('prefetch') // TODO: need test
54 |
55 | // set svg-sprite-loader
56 | config.module
57 | .rule('svg')
58 | .exclude.add(resolve('src/icons'))
59 | .end()
60 | config.module
61 | .rule('icons')
62 | .test(/\.svg$/)
63 | .include.add(resolve('src/icons'))
64 | .end()
65 | .use('svg-sprite-loader')
66 | .loader('svg-sprite-loader')
67 | .options({
68 | symbolId: 'icon-[name]'
69 | })
70 | .end()
71 |
72 | // set preserveWhitespace
73 | config.module
74 | .rule('vue')
75 | .use('vue-loader')
76 | .loader('vue-loader')
77 | .tap(options => {
78 | options.compilerOptions.preserveWhitespace = true
79 | return options
80 | })
81 | .end()
82 |
83 | config
84 | // https://webpack.js.org/configuration/devtool/#development
85 | .when(process.env.NODE_ENV === 'development',
86 | config => config.devtool('cheap-source-map')
87 | )
88 |
89 | config
90 | .when(process.env.NODE_ENV !== 'development',
91 | config => {
92 | config
93 | .plugin('ScriptExtHtmlWebpackPlugin')
94 | .after('html')
95 | .use('script-ext-html-webpack-plugin', [{
96 | // `runtime` must same as runtimeChunk name. default is `runtime`
97 | inline: /runtime\..*\.js$/
98 | }])
99 | .end()
100 | config
101 | .optimization.splitChunks({
102 | chunks: 'all',
103 | cacheGroups: {
104 | libs: {
105 | name: 'chunk-libs',
106 | test: /[\\/]node_modules[\\/]/,
107 | priority: 10,
108 | chunks: 'initial' // only package third parties that are initially dependent
109 | },
110 | elementUI: {
111 | name: 'chunk-elementUI', // split elementUI into a single package
112 | priority: 20, // the weight needs to be larger than libs and app or it will be packaged into libs or app
113 | test: /[\\/]node_modules[\\/]_?element-ui(.*)/ // in order to adapt to cnpm
114 | },
115 | commons: {
116 | name: 'chunk-commons',
117 | test: resolve('src/components'), // can customize your rules
118 | minChunks: 3, // minimum common number
119 | priority: 5,
120 | reuseExistingChunk: true
121 | }
122 | }
123 | })
124 | config.optimization.runtimeChunk('single')
125 | }
126 | )
127 | }
128 | }
129 |
--------------------------------------------------------------------------------