├── .babelrc ├── .editorconfig ├── .eslintignore ├── .eslintrc.js ├── .gitignore ├── .postcssrc.js ├── .travis.yml ├── LICENSE ├── README.md ├── cypress.json ├── package.json ├── public ├── index.html ├── yesapi_api.bmp └── yesapi_api.ico ├── src ├── App.vue ├── api │ ├── data.js │ ├── okayapi_config.js │ ├── routers.js │ ├── stats.js │ └── user.js ├── assets │ ├── icons │ │ ├── file-icon │ │ │ ├── doc_logo.jpg │ │ │ ├── html_logo.jpg │ │ │ ├── others_logo.jpg │ │ │ ├── ppt_logo.jpg │ │ │ ├── xls_logo.jpg │ │ │ ├── 文件.png │ │ │ └── 文件.psd │ │ ├── iconfont.css │ │ ├── iconfont.eot │ │ ├── iconfont.svg │ │ ├── iconfont.ttf │ │ └── iconfont.woff │ └── images │ │ ├── error-page │ │ ├── error-401.svg │ │ ├── error-404.svg │ │ └── error-500.svg │ │ ├── icon-qr-qq-wechat.png │ │ ├── icon-social-bilibili.svg │ │ ├── icon-social-juejin.svg │ │ ├── icon-social-twitter.svg │ │ ├── icon-social-zhihu.svg │ │ ├── left.png │ │ ├── login-bg.jpg │ │ ├── logo-min.jpg │ │ ├── logo.jpg │ │ ├── logo.png │ │ ├── right.png │ │ ├── talkingdata.png │ │ ├── yesadmin.jpg │ │ ├── yesapi_admin.png │ │ └── yesapi_admin_min.jpg ├── components │ ├── charts │ │ ├── bar.vue │ │ ├── index.js │ │ ├── pie.vue │ │ └── theme.json │ ├── common-icon │ │ ├── common-icon.vue │ │ └── index.js │ ├── common │ │ ├── common.less │ │ └── util.js │ ├── count-to │ │ ├── count-to.vue │ │ ├── index.js │ │ └── index.less │ ├── cropper │ │ ├── index.js │ │ ├── index.less │ │ ├── index.vue │ │ └── xls_logo.jpg │ ├── drag-drawer │ │ ├── drag-drawer-trigger.vue │ │ ├── drag-drawer.vue │ │ ├── index.js │ │ ├── index.less │ │ └── mixin.js │ ├── drag-list │ │ ├── drag-list.vue │ │ └── index.js │ ├── editor │ │ ├── editor.vue │ │ └── index.js │ ├── icons │ │ ├── icons.vue │ │ └── index.js │ ├── info-card │ │ ├── index.js │ │ └── infor-card.vue │ ├── login-form │ │ ├── index.js │ │ └── login-form.vue │ ├── main │ │ ├── components │ │ │ ├── a-back-top │ │ │ │ ├── index.js │ │ │ │ └── index.vue │ │ │ ├── error-store │ │ │ │ ├── error-store.vue │ │ │ │ └── index.js │ │ │ ├── fullscreen │ │ │ │ ├── fullscreen.vue │ │ │ │ └── index.js │ │ │ ├── header-bar │ │ │ │ ├── custom-bread-crumb │ │ │ │ │ ├── custom-bread-crumb.less │ │ │ │ │ ├── custom-bread-crumb.vue │ │ │ │ │ └── index.js │ │ │ │ ├── header-bar.less │ │ │ │ ├── header-bar.vue │ │ │ │ ├── index.js │ │ │ │ └── sider-trigger │ │ │ │ │ ├── index.js │ │ │ │ │ ├── sider-trigger.less │ │ │ │ │ └── sider-trigger.vue │ │ │ ├── language │ │ │ │ ├── index.js │ │ │ │ └── language.vue │ │ │ ├── side-menu │ │ │ │ ├── collapsed-menu.vue │ │ │ │ ├── index.js │ │ │ │ ├── item-mixin.js │ │ │ │ ├── mixin.js │ │ │ │ ├── side-menu-item.vue │ │ │ │ ├── side-menu.less │ │ │ │ └── side-menu.vue │ │ │ ├── tags-nav │ │ │ │ ├── index.js │ │ │ │ ├── tags-nav.less │ │ │ │ └── tags-nav.vue │ │ │ └── user │ │ │ │ ├── index.js │ │ │ │ ├── user.less │ │ │ │ └── user.vue │ │ ├── index.js │ │ ├── main.less │ │ └── main.vue │ ├── markdown │ │ ├── index.js │ │ └── markdown.vue │ ├── parent-view │ │ ├── index.js │ │ └── parent-view.vue │ ├── paste-editor │ │ ├── index.js │ │ ├── paste-editor.less │ │ ├── paste-editor.vue │ │ └── plugins │ │ │ └── placeholder.js │ ├── register-form │ │ ├── index.js │ │ └── register-form.vue │ ├── split-pane │ │ ├── index.js │ │ ├── index.less │ │ ├── split.vue │ │ └── trigger.vue │ ├── tables │ │ ├── edit.vue │ │ ├── handle-btns.js │ │ ├── index.js │ │ ├── index.less │ │ └── tables.vue │ └── tree-select │ │ ├── index.js │ │ ├── tree-select-tree.vue │ │ └── tree-select.vue ├── config │ └── index.js ├── directive │ ├── directives.js │ ├── index.js │ └── module │ │ ├── clipboard.js │ │ └── draggable.js ├── index.less ├── libs │ ├── api.request.js │ ├── axios.js │ ├── excel.js │ ├── render-dom.js │ ├── tools.js │ └── util.js ├── locale │ ├── index.js │ └── lang │ │ ├── en-US.js │ │ ├── zh-CN.js │ │ └── zh-TW.js ├── main.js ├── mock │ ├── data.js │ ├── data │ │ ├── org-data.js │ │ └── tree-select.js │ ├── index.js │ ├── login.js │ └── user.js ├── plugin │ ├── error-store │ │ └── index.js │ └── index.js ├── router │ ├── before-close.js │ ├── index.js │ └── routers.js ├── store │ ├── index.js │ └── module │ │ ├── app.js │ │ └── user.js └── view │ ├── argu-page │ ├── params.vue │ └── query.vue │ ├── article-lib │ ├── article-add │ │ └── index.vue │ ├── article-manage │ │ └── index.vue │ ├── article-review │ │ └── index.vue │ └── upload-csv │ │ └── index.vue │ ├── assets-lib │ ├── assets-manage │ │ ├── index.vue │ │ └── item-card.vue │ └── assets-upload │ │ └── index.vue │ ├── components │ ├── count-to │ │ └── count-to.vue │ ├── cropper │ │ └── cropper.vue │ ├── drag-drawer │ │ └── index.vue │ ├── drag-list │ │ └── drag-list.vue │ ├── editor │ │ └── editor.vue │ ├── icons │ │ └── icons.vue │ ├── markdown │ │ └── markdown.vue │ ├── org-tree │ │ ├── components │ │ │ ├── org-view.vue │ │ │ └── zoom-controller.vue │ │ ├── index.less │ │ └── index.vue │ ├── split-pane │ │ └── split-pane.vue │ ├── tables │ │ └── tables.vue │ ├── tree-select │ │ └── index.vue │ └── tree-table │ │ └── index.vue │ ├── directive │ └── directive.vue │ ├── error-page │ ├── 401.vue │ ├── 404.vue │ ├── 500.vue │ ├── back-btn-group.vue │ ├── error-content.vue │ └── error.less │ ├── error-store │ └── error-store.vue │ ├── excel │ ├── common.less │ ├── export-excel.vue │ └── upload-excel.vue │ ├── i18n │ └── i18n-page.vue │ ├── join-page.vue │ ├── login │ ├── login.less │ └── login.vue │ ├── multilevel │ ├── level-2-1.vue │ ├── level-2-2 │ │ ├── level-2-2-1.vue │ │ └── level-2-2-2.vue │ └── level-2-3.vue │ ├── register │ ├── register.less │ └── register.vue │ ├── single-page │ ├── error-logger.vue │ ├── home │ │ ├── example.vue │ │ ├── home.vue │ │ └── index.js │ └── message │ │ └── index.vue │ ├── stats │ ├── login-stats │ │ └── index.vue │ └── register-stats │ │ └── index.vue │ ├── tools-methods │ └── tools-methods.vue │ └── update │ ├── update-paste.vue │ └── update-table.vue ├── tests ├── e2e │ ├── .eslintrc │ ├── plugins │ │ └── index.js │ ├── specs │ │ └── test.js │ └── support │ │ ├── commands.js │ │ └── index.js └── unit │ ├── .eslintrc.js │ └── HelloWorld.spec.js └── vue.config.js /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | "@vue/app" 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yesapicn/YesAdmin/f8ecd8e83c9367c3205272eb1f39c06f8708453a/.eslintignore -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | 'extends': [ 4 | 'plugin:vue/essential', 5 | '@vue/standard' 6 | ], 7 | rules: { 8 | // allow async-await 9 | 'generator-star-spacing': 'off', 10 | // allow debugger during development 11 | 'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off', 12 | 'vue/no-parsing-error': [2, { 13 | 'x-invalid-end-tag': false 14 | }], 15 | 'no-undef': 'off', 16 | 'camelcase': 'off' 17 | }, 18 | parserOptions: { 19 | parser: 'babel-eslint' 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /dist 4 | 5 | package-lock.json 6 | 7 | /tests/e2e/videos/ 8 | /tests/e2e/screenshots/ 9 | 10 | # local env files 11 | .env.local 12 | .env.*.local 13 | 14 | # Log files 15 | npm-debug.log* 16 | yarn-debug.log* 17 | yarn-error.log* 18 | 19 | # Editor directories and files 20 | .idea 21 | .vscode 22 | *.suo 23 | *.ntvs* 24 | *.njsproj 25 | *.sln 26 | *.sw* 27 | 28 | build/env.js 29 | 30 | dist.zip 31 | 32 | README.html 33 | 34 | -------------------------------------------------------------------------------- /.postcssrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | autoprefixer: {} 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: stable 3 | script: npm run lint 4 | notifications: 5 | email: false 6 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 TalkingData 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 | -------------------------------------------------------------------------------- /cypress.json: -------------------------------------------------------------------------------- 1 | { 2 | "pluginsFile": "tests/e2e/plugins/index.js" 3 | } 4 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "iview-admin", 3 | "version": "2.0.0", 4 | "author": "Lison", 5 | "private": false, 6 | "scripts": { 7 | "dev": "vue-cli-service serve --open", 8 | "build": "vue-cli-service build", 9 | "lint": "vue-cli-service lint", 10 | "test:unit": "vue-cli-service test:unit", 11 | "test:e2e": "vue-cli-service test:e2e" 12 | }, 13 | "dependencies": { 14 | "axios": "^0.18.0", 15 | "clipboard": "^2.0.0", 16 | "codemirror": "^5.38.0", 17 | "cookiejar": "^2.1.2", 18 | "countup": "^1.8.2", 19 | "cropperjs": "^1.2.2", 20 | "dayjs": "^1.7.7", 21 | "echarts": "^4.0.4", 22 | "html2canvas": "^1.0.0-alpha.12", 23 | "iview": "^3.2.2", 24 | "iview-area": "^1.5.17", 25 | "js-cookie": "^2.2.0", 26 | "js-md5": "^0.7.3", 27 | "less-loader": "^5.0.0", 28 | "node-sass": "^4.14.1", 29 | "sass-loader": "^8.0.2", 30 | "simplemde": "^1.11.2", 31 | "sortablejs": "^1.7.0", 32 | "tree-table-vue": "^1.1.0", 33 | "v-org-tree": "^1.0.6", 34 | "vue": "^2.5.10", 35 | "vue-i18n": "^7.8.0", 36 | "vue-router": "^3.0.1", 37 | "vuedraggable": "^2.16.0", 38 | "vuex": "^3.0.1", 39 | "wangeditor": "^3.1.1", 40 | "xlsx": "^0.13.3" 41 | }, 42 | "devDependencies": { 43 | "@vue/cli-plugin-babel": "^3.0.1", 44 | "@vue/cli-plugin-eslint": "^3.0.1", 45 | "@vue/cli-plugin-unit-mocha": "^3.0.1", 46 | "@vue/cli-service": "^3.0.1", 47 | "@vue/eslint-config-standard": "^3.0.0-beta.10", 48 | "@vue/test-utils": "^1.0.0-beta.10", 49 | "chai": "^4.1.2", 50 | "eslint-plugin-cypress": "^2.0.1", 51 | "less": "^2.7.3", 52 | "lint-staged": "^6.0.0", 53 | "mockjs": "^1.0.1-beta3", 54 | "vue-template-compiler": "^2.5.13" 55 | }, 56 | "browserslist": [ 57 | "> 1%", 58 | "last 2 versions", 59 | "not ie <= 8" 60 | ], 61 | "gitHooks": { 62 | "pre-commit": "lint-staged" 63 | }, 64 | "lint-staged": { 65 | "*.js": [ 66 | "vue-cli-service lint", 67 | "git add" 68 | ], 69 | "*.vue": [ 70 | "vue-cli-service lint", 71 | "git add" 72 | ] 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | YesAdmin 9 | 10 | 11 | 14 |
15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /public/yesapi_api.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yesapicn/YesAdmin/f8ecd8e83c9367c3205272eb1f39c06f8708453a/public/yesapi_api.bmp -------------------------------------------------------------------------------- /public/yesapi_api.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yesapicn/YesAdmin/f8ecd8e83c9367c3205272eb1f39c06f8708453a/public/yesapi_api.ico -------------------------------------------------------------------------------- /src/App.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 12 | 13 | 28 | -------------------------------------------------------------------------------- /src/api/data.js: -------------------------------------------------------------------------------- 1 | import axios from '@/libs/api.request' 2 | 3 | import validateUrl from './okayapi_config.js'// 添加请求合法性校验的查询参数 4 | 5 | 6 | //向CDN上传图片 7 | export const uploadImg = (data = { flie, file_name, file_type }) => { 8 | let url = validateUrl('App.CDN.UploadImgByBase64', data) 9 | return axios.request({ 10 | method: 'post', 11 | url, 12 | data 13 | }) 14 | } 15 | 16 | //向CDN上传文件 17 | export const uploadFile = (data = { flie, file_name, file_type }) => { 18 | let url = validateUrl('App.CDN.UploadOfficeByBase64', data) 19 | return axios.request({ 20 | method: 'post', 21 | url, 22 | data 23 | }) 24 | } 25 | 26 | //获取CDN素材库 27 | export const getAssetsList = (data = { file_name, file_type, order_type, page, perpage }) => { 28 | let url = validateUrl('App.CDN.RecordList', data) 29 | return axios.request({ 30 | method: 'post', 31 | url, 32 | data 33 | }) 34 | } 35 | 36 | //根据ID删除CDN中的文件或图片 37 | export const delet_file = (id) => { 38 | let url = validateUrl('App.CDN.DeleteById', {id}) 39 | return axios.request({ 40 | method: 'post', 41 | url, 42 | data: {id} 43 | }) 44 | } 45 | 46 | //获取文章模型中的数据 model_name= 'okayapi_article' 47 | export const getArticleList = (data = { model_name: 'okayapi_article', where, page, perpage }) => { 48 | let url = validateUrl('App.Table.FreeQuery', data) 49 | return axios.request({ 50 | method: 'post', 51 | url, 52 | data 53 | }) 54 | } 55 | 56 | //删除文章模型中的数据 57 | export const removeArticleData = (data = { model_name: 'okayapi_article', id }) => { 58 | let url = validateUrl('App.Table.Delete', data) 59 | return axios.request({ 60 | method: 'post', 61 | url, 62 | data 63 | }) 64 | } 65 | 66 | //添加文章模型中的数据 67 | export const createArticleData = (data = { model_name: 'okayapi_article', id }) => { 68 | let url = validateUrl('App.Table.Create', data) 69 | return axios.request({ 70 | method: 'post', 71 | url, 72 | data 73 | }) 74 | } 75 | 76 | 77 | export const getTableData = () => { 78 | return axios.request({ 79 | url: 'get_table_data', 80 | method: 'get' 81 | }) 82 | } 83 | 84 | export const getDragList = () => { 85 | return axios.request({ 86 | url: 'get_drag_list', 87 | method: 'get' 88 | }) 89 | } 90 | 91 | export const errorReq = () => { 92 | return axios.request({ 93 | url: 'error_url', 94 | method: 'post' 95 | }) 96 | } 97 | 98 | export const saveErrorLogger = info => { 99 | return axios.request({ 100 | url: 'save_error_logger', 101 | data: info, 102 | method: 'post' 103 | }) 104 | } 105 | 106 | 107 | 108 | export const getOrgData = () => { 109 | return axios.request({ 110 | url: 'get_org_data', 111 | method: 'get' 112 | }) 113 | } 114 | 115 | export const getTreeSelectData = () => { 116 | return axios.request({ 117 | url: 'get_tree_select_data', 118 | method: 'get' 119 | }) 120 | } 121 | -------------------------------------------------------------------------------- /src/api/okayapi_config.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @Description: 3 | * @Author: He Jiecong 4 | * @Date: 2019-12-13 18:40:24 5 | * @LastEditTime : 2019-12-30 19:36:06 6 | * @LastEditors : He Jiecong 7 | */ 8 | import md5 from 'js-md5' 9 | import config from '@/config' 10 | 11 | // APP_KEY 12 | const OKAYAPI_APP_KEY = config.OKAYAPI_APP_KEY 13 | // 密钥 14 | const OKAYAPI_APP_SECRECT = config.OKAYAPI_APP_SECRECT 15 | 16 | // 小白官方生成动态签名的方法 17 | function enryptData (apiName, params) { 18 | params['app_key'] = OKAYAPI_APP_KEY 19 | params['s'] = apiName 20 | params['sign'] = '' // 屏蔽sign参数 21 | 22 | // 按字典顺序对参数排序 23 | let sdic = Object.keys(params).sort() 24 | let paramsStrExceptSign = '' 25 | for (let ki in sdic) { 26 | paramsStrExceptSign += params[sdic[ki]] 27 | } 28 | 29 | let SIGN = md5(paramsStrExceptSign + OKAYAPI_APP_SECRECT).toUpperCase() 30 | 31 | return SIGN 32 | } 33 | 34 | // 公共参数与接口的拼接 35 | export default function validateUrl (apiName, params) { 36 | let SIGN = enryptData(apiName, params) 37 | let url = '?s=' + apiName + '&app_key=' + OKAYAPI_APP_KEY + '&sign=' + SIGN 38 | 39 | return url 40 | } 41 | -------------------------------------------------------------------------------- /src/api/routers.js: -------------------------------------------------------------------------------- 1 | import axios from '@/libs/api.request' 2 | 3 | export const getRouterReq = (access) => { 4 | return axios.request({ 5 | url: 'get_router', 6 | params: { 7 | access 8 | }, 9 | method: 'get' 10 | }) 11 | } 12 | -------------------------------------------------------------------------------- /src/api/stats.js: -------------------------------------------------------------------------------- 1 | import axios from '@/libs/api.request' 2 | 3 | import validateUrl from './okayapi_config.js'// 添加请求合法性校验的查询参数 4 | 5 | export const GetDailyRegister = (data = { start_date, end_date }) => { 6 | let url = validateUrl('App.Statistics.GetDailyRegister', data) 7 | return axios.request({ 8 | method: 'post', 9 | url, 10 | data 11 | }) 12 | } 13 | 14 | export const GetDailyLoginReport = (data = { start_date, end_date }) => { 15 | let url = validateUrl('App.Statistics.GetDailyLoginReport', data) 16 | return axios.request({ 17 | method: 'post', 18 | url, 19 | data 20 | }) 21 | } 22 | -------------------------------------------------------------------------------- /src/api/user.js: -------------------------------------------------------------------------------- 1 | import axios from '@/libs/api.request' 2 | 3 | import validateUrl from './okayapi_config.js'// 添加请求合法性校验的查询参数 4 | 5 | export const login = (data = { username, password }) => { 6 | let url = validateUrl('App.User.Login', data) 7 | return axios.request({ 8 | method: 'post', 9 | url, 10 | data 11 | }) 12 | } 13 | 14 | export const register = (params = { username, password }) => { 15 | let url = validateUrl('App.User.Register', params) 16 | return axios.request({ 17 | method: 'post', 18 | url, 19 | params 20 | }) 21 | } 22 | 23 | // export const getUserInfo = (token) => { 24 | // return axios.request({ 25 | // url: 'get_info', 26 | // params: { 27 | // token 28 | // }, 29 | // method: 'get' 30 | // }) 31 | // } 32 | 33 | export const logout = (token) => { 34 | return axios.request({ 35 | url: 'logout', 36 | method: 'post' 37 | }) 38 | } 39 | 40 | export const getUnreadCount = () => { 41 | return axios.request({ 42 | url: 'message/count', 43 | method: 'get' 44 | }) 45 | } 46 | 47 | export const getMessage = () => { 48 | return axios.request({ 49 | url: 'message/init', 50 | method: 'get' 51 | }) 52 | } 53 | 54 | export const getContentByMsgId = msg_id => { 55 | return axios.request({ 56 | url: 'message/content', 57 | method: 'get', 58 | params: { 59 | msg_id 60 | } 61 | }) 62 | } 63 | 64 | export const hasRead = msg_id => { 65 | return axios.request({ 66 | url: 'message/has_read', 67 | method: 'post', 68 | data: { 69 | msg_id 70 | } 71 | }) 72 | } 73 | 74 | export const removeReaded = msg_id => { 75 | return axios.request({ 76 | url: 'message/remove_readed', 77 | method: 'post', 78 | data: { 79 | msg_id 80 | } 81 | }) 82 | } 83 | 84 | export const restoreTrash = msg_id => { 85 | return axios.request({ 86 | url: 'message/restore', 87 | method: 'post', 88 | data: { 89 | msg_id 90 | } 91 | }) 92 | } 93 | -------------------------------------------------------------------------------- /src/assets/icons/file-icon/doc_logo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yesapicn/YesAdmin/f8ecd8e83c9367c3205272eb1f39c06f8708453a/src/assets/icons/file-icon/doc_logo.jpg -------------------------------------------------------------------------------- /src/assets/icons/file-icon/html_logo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yesapicn/YesAdmin/f8ecd8e83c9367c3205272eb1f39c06f8708453a/src/assets/icons/file-icon/html_logo.jpg -------------------------------------------------------------------------------- /src/assets/icons/file-icon/others_logo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yesapicn/YesAdmin/f8ecd8e83c9367c3205272eb1f39c06f8708453a/src/assets/icons/file-icon/others_logo.jpg -------------------------------------------------------------------------------- /src/assets/icons/file-icon/ppt_logo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yesapicn/YesAdmin/f8ecd8e83c9367c3205272eb1f39c06f8708453a/src/assets/icons/file-icon/ppt_logo.jpg -------------------------------------------------------------------------------- /src/assets/icons/file-icon/xls_logo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yesapicn/YesAdmin/f8ecd8e83c9367c3205272eb1f39c06f8708453a/src/assets/icons/file-icon/xls_logo.jpg -------------------------------------------------------------------------------- /src/assets/icons/file-icon/文件.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yesapicn/YesAdmin/f8ecd8e83c9367c3205272eb1f39c06f8708453a/src/assets/icons/file-icon/文件.png -------------------------------------------------------------------------------- /src/assets/icons/file-icon/文件.psd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yesapicn/YesAdmin/f8ecd8e83c9367c3205272eb1f39c06f8708453a/src/assets/icons/file-icon/文件.psd -------------------------------------------------------------------------------- /src/assets/icons/iconfont.css: -------------------------------------------------------------------------------- 1 | 2 | @font-face {font-family: "iconfont"; 3 | src: url('iconfont.eot?t=1541579316141'); /* IE9*/ 4 | src: url('iconfont.eot?t=1541579316141#iefix') format('embedded-opentype'), /* IE6-IE8 */ 5 | url('data:application/x-font-woff;charset=utf-8;base64,d09GRgABAAAAAAiEAAsAAAAADmgAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAABHU1VCAAABCAAAADMAAABCsP6z7U9TLzIAAAE8AAAARAAAAFY8eUnXY21hcAAAAYAAAACjAAACLi+YJuBnbHlmAAACJAAABAgAAAcg4dRWHmhlYWQAAAYsAAAAMQAAADYTL8piaGhlYQAABmAAAAAgAAAAJAfdA4xobXR4AAAGgAAAABQAAAAsLAD//2xvY2EAAAaUAAAAGAAAABgImgpGbWF4cAAABqwAAAAfAAAAIAEcAG5uYW1lAAAGzAAAAUUAAAJtPlT+fXBvc3QAAAgUAAAAbgAAAI54roygeJxjYGRgYOBikGPQYWB0cfMJYeBgYGGAAJAMY05meiJQDMoDyrGAaQ4gZoOIAgCKIwNPAHicY2BkYWCcwMDKwMHUyXSGgYGhH0IzvmYwYuRgYGBiYGVmwAoC0lxTGByeMTx/ytzwv4EhhrmBoRkozAiSAwDuUwzMeJzlkUEKwkAMRd/YabXFhQvxFF6qPYPrUujGY7jyIr1JoZNjtMnEhag3MOEN5MMk8D9QAoVyVSKEJwGrh6oh6wVN1iM3nc+cVImJVKdOehlklElmWdYVstp+ql8VdIv15a1NLW0zFXsO7Kjz3erH/3+rY37vr6kxnx1LKNWOJZlaxxJNnWOpSu+ot8jgqMvI6KjfyOSo88jsaAbI4tBsig89rQB4nLVUTWwbRRSeNzO767i2g7N/FP9s7MRrE5ON4/V6rSZyU0PiINSSNImES4IUoapWz6hEiqiMBDQqEojkAkiFStyKRC+9VSoFCeUEyqESVUAqEkcu3OAQb3hrJxAXwSGI3X0/szPz5vvm2x0i7O/vf8IJe5VkSJnUyUtklRBQJE1VIjRtUafkmk6pSu2ipleh4+xikkKxSksWTUeo8m8NoagpYtoslTmxrLl37z64e33esuJjU8P5Wd262LxoPVnPZ06Pxfe+C0YjkhSJygPhQCA8ABPOykwuN7NyuRvgUnAgLEnhATkaCQQiUe/7XKUyV6nQz+t2o7l66+rs7NVbq82GXTdrdjxjRGU5amTids2bUDMFtzCsqsMYMqr3IDY6OT05GjsI8Exv/6CSkOWEQigh+y3clxY5QVTcEZFIGtHLxDUJs6WsHR1y9SFKdr1HggCp3V1ICYL36OOpVmvKN9bC1u6R3vZ0qwWtVovgJfqOfUvfIYxIWL+fyETHNVJqSkIT1JTjW8ZWh3yDJDz0ctvsyt51etvrg9/QHhqGlzMM+vbmizPnDWPLMNbW19e7tffvsBzL99aWEfBRY46t+tbe3PypXv/IMDYN43WsQBe9HL2NC33RuxABrPsG+xH3o4bVRE2KgCRqulbWNf8W/UYVHM129aKra24VshZkq+CWD/Oy6Xt8cGYEthgHVlVliCfynAlqjo6oysTKlYUAD4docMI5/1ZioN+GwZNBcTwWUmTdBUqhTwX29QebXzF4An4JJMzwfMl+WQ01+IlQZVR4yhie53ycA16pOI/ODiYNGK4MChdCgXNnX5gIJXPCSYnf2OF850aQ+zJIyOs+u8+mMO8jQdwtg1TIWVRjKAnFcslMi8KfGUPoSUCergUyUk77dMyS69Ms6tijKZKYwUGKbpfdzu+iYeZYAHMFiOVi+MD7h9mb99qC0L7X8c+XatMfTj97KZ5IxJt/pd43tYYQKEjAnXMOB6kQEBrwg+LPjindAPOHNdC3q3ait0I3/ZIunZEARLNYNEUA6czSP3N/7j9wz6ZESdX0VNl1zGNS/szbQaQSIGk4DtVPcZf8AgXpf9A2OyTit5s2syZmand46bhEe2WtodLHkvaoqtTXuXN2/c42WADP9HGfbUcUW7JgqHss4xHtlMys679FqUomdP9VJBQBdnlPABBubpuNwqnmQj6/0HwNQzKxDUJFgKiXurBG6dqFjmeBzsvtRPJgGIZThYa5fdOvsReOticPh6JHHXxsv7ItJpOniYPYsmZ/x0QD/o5P105DeQwF6MH33ogoLi+KQp7zpY3HQV5bFMURzheXeds7gpP+jKNXljjHuYvXHke7cdCxLLZf6YX7B63UcCV4nGNgZGBgAOKAN2ZR8fw2Xxm4WRhA4AbHYRMY/f///1oWBuYGIJeDgQkkCgAvWgs2AAAAeJxjYGRgYG7438AQw8Lw/z8DAwsDA1AEBXADAHXiBHJ4nGNhYGBgYfj/nwVM48cATwECKwAAAAAAjAC6AOgBFAGAAf4CbgLqAzgDkHicY2BkYGDgZkhiYGcAASYg5gJCBob/YD4DABOmAYsAeJxlj01OwzAQhV/6B6QSqqhgh+QFYgEo/RGrblhUavdddN+mTpsqiSPHrdQDcB6OwAk4AtyAO/BIJ5s2lsffvHljTwDc4Acejt8t95E9XDI7cg0XuBeuU38QbpBfhJto41W4Rf1N2MczpsJtdGF5g9e4YvaEd2EPHXwI13CNT+E69S/hBvlbuIk7/Aq30PHqwj7mXle4jUcv9sdWL5xeqeVBxaHJIpM5v4KZXu+Sha3S6pxrW8QmU4OgX0lTnWlb3VPs10PnIhVZk6oJqzpJjMqt2erQBRvn8lGvF4kehCblWGP+tsYCjnEFhSUOjDFCGGSIyujoO1Vm9K+xQ8Jee1Y9zed0WxTU/3OFAQL0z1xTurLSeTpPgT1fG1J1dCtuy56UNJFezUkSskJe1rZUQuoBNmVXjhF6XNGJPyhnSP8ACVpuyAAAAHicbYhdDoIwEAb3a6k/YIIX8VArWewmdJFWJOnpJTG+OQ+TzJCjLy39p4ODR4OAA4444YwWHS7U3IVzn6Voldtb8ksHnvohrlqjjmw1rmzXsvdT7fEbblnCmOfNfJIYStJJfGIL27yb6AOCGR89AAA=') format('woff'), 6 | url('iconfont.ttf?t=1541579316141') format('truetype'), /* chrome, firefox, opera, Safari, Android, iOS 4.2+*/ 7 | url('iconfont.svg?t=1541579316141#iconfont') format('svg'); /* iOS 4.1- */ 8 | } 9 | 10 | .iconfont { 11 | font-family:"iconfont" !important; 12 | font-size:16px; 13 | font-style:normal; 14 | -webkit-font-smoothing: antialiased; 15 | -moz-osx-font-smoothing: grayscale; 16 | } 17 | 18 | .icon-bear:before { content: "\e600"; } 19 | 20 | .icon-resize-vertical:before { content: "\e7c3"; } 21 | 22 | .icon-chuizhifanzhuan:before { content: "\e661"; } 23 | 24 | .icon-shuipingfanzhuan:before { content: "\e662"; } 25 | 26 | .icon-qq:before { content: "\e609"; } 27 | 28 | .icon-frown:before { content: "\e77e"; } 29 | 30 | .icon-meh:before { content: "\e780"; } 31 | 32 | .icon-smile:before { content: "\e783"; } 33 | 34 | .icon-man:before { content: "\e7e2"; } 35 | 36 | .icon-woman:before { content: "\e7e5"; } 37 | 38 | -------------------------------------------------------------------------------- /src/assets/icons/iconfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yesapicn/YesAdmin/f8ecd8e83c9367c3205272eb1f39c06f8708453a/src/assets/icons/iconfont.eot -------------------------------------------------------------------------------- /src/assets/icons/iconfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yesapicn/YesAdmin/f8ecd8e83c9367c3205272eb1f39c06f8708453a/src/assets/icons/iconfont.ttf -------------------------------------------------------------------------------- /src/assets/icons/iconfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yesapicn/YesAdmin/f8ecd8e83c9367c3205272eb1f39c06f8708453a/src/assets/icons/iconfont.woff -------------------------------------------------------------------------------- /src/assets/images/icon-qr-qq-wechat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yesapicn/YesAdmin/f8ecd8e83c9367c3205272eb1f39c06f8708453a/src/assets/images/icon-qr-qq-wechat.png -------------------------------------------------------------------------------- /src/assets/images/icon-social-juejin.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/images/icon-social-twitter.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/images/icon-social-zhihu.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/images/left.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yesapicn/YesAdmin/f8ecd8e83c9367c3205272eb1f39c06f8708453a/src/assets/images/left.png -------------------------------------------------------------------------------- /src/assets/images/login-bg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yesapicn/YesAdmin/f8ecd8e83c9367c3205272eb1f39c06f8708453a/src/assets/images/login-bg.jpg -------------------------------------------------------------------------------- /src/assets/images/logo-min.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yesapicn/YesAdmin/f8ecd8e83c9367c3205272eb1f39c06f8708453a/src/assets/images/logo-min.jpg -------------------------------------------------------------------------------- /src/assets/images/logo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yesapicn/YesAdmin/f8ecd8e83c9367c3205272eb1f39c06f8708453a/src/assets/images/logo.jpg -------------------------------------------------------------------------------- /src/assets/images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yesapicn/YesAdmin/f8ecd8e83c9367c3205272eb1f39c06f8708453a/src/assets/images/logo.png -------------------------------------------------------------------------------- /src/assets/images/right.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yesapicn/YesAdmin/f8ecd8e83c9367c3205272eb1f39c06f8708453a/src/assets/images/right.png -------------------------------------------------------------------------------- /src/assets/images/talkingdata.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yesapicn/YesAdmin/f8ecd8e83c9367c3205272eb1f39c06f8708453a/src/assets/images/talkingdata.png -------------------------------------------------------------------------------- /src/assets/images/yesadmin.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yesapicn/YesAdmin/f8ecd8e83c9367c3205272eb1f39c06f8708453a/src/assets/images/yesadmin.jpg -------------------------------------------------------------------------------- /src/assets/images/yesapi_admin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yesapicn/YesAdmin/f8ecd8e83c9367c3205272eb1f39c06f8708453a/src/assets/images/yesapi_admin.png -------------------------------------------------------------------------------- /src/assets/images/yesapi_admin_min.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yesapicn/YesAdmin/f8ecd8e83c9367c3205272eb1f39c06f8708453a/src/assets/images/yesapi_admin_min.jpg -------------------------------------------------------------------------------- /src/components/charts/bar.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 59 | -------------------------------------------------------------------------------- /src/components/charts/index.js: -------------------------------------------------------------------------------- 1 | import ChartPie from './pie.vue' 2 | import ChartBar from './bar.vue' 3 | export { ChartPie, ChartBar } 4 | -------------------------------------------------------------------------------- /src/components/charts/pie.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 71 | -------------------------------------------------------------------------------- /src/components/common-icon/common-icon.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 39 | 40 | 43 | -------------------------------------------------------------------------------- /src/components/common-icon/index.js: -------------------------------------------------------------------------------- 1 | import CommonIcon from './common-icon.vue' 2 | export default CommonIcon 3 | -------------------------------------------------------------------------------- /src/components/common/common.less: -------------------------------------------------------------------------------- 1 | .no-select{ 2 | -webkit-touch-callout: none; 3 | -webkit-user-select: none; 4 | -khtml-user-select: none; 5 | -moz-user-select: none; 6 | -ms-user-select: none; 7 | user-select: none; 8 | } 9 | -------------------------------------------------------------------------------- /src/components/common/util.js: -------------------------------------------------------------------------------- 1 | export const showTitle = (item, vm) => { 2 | return vm.$config.useI18n ? vm.$t(item.name) : ((item.meta && item.meta.title) || item.name) 3 | } 4 | -------------------------------------------------------------------------------- /src/components/count-to/index.js: -------------------------------------------------------------------------------- 1 | import countTo from './count-to.vue' 2 | export default countTo 3 | -------------------------------------------------------------------------------- /src/components/count-to/index.less: -------------------------------------------------------------------------------- 1 | @prefix: ~"count-to"; 2 | 3 | .@{prefix}-wrapper{ 4 | .content-outer{ 5 | display: inline-block; 6 | .@{prefix}-unit-text{ 7 | font-style: normal; 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/components/cropper/index.js: -------------------------------------------------------------------------------- 1 | import Cropper from './index.vue' 2 | export default Cropper 3 | -------------------------------------------------------------------------------- /src/components/cropper/index.less: -------------------------------------------------------------------------------- 1 | .bg{ 2 | background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAAA3NCSVQICAjb4U/gAAAABlBMVEXMzMz////TjRV2AAAACXBIWXMAAArrAAAK6wGCiw1aAAAAHHRFWHRTb2Z0d2FyZQBBZG9iZSBGaXJld29ya3MgQ1M26LyyjAAAABFJREFUCJlj+M/AgBVhF/0PAH6/D/HkDxOGAAAAAElFTkSuQmCC") 3 | } 4 | .cropper-wrapper{ 5 | min-height: 500px; 6 | display: flex; 7 | justify-content: center; 8 | flex-flow: column; 9 | align-items: center; 10 | .cropper-box { 11 | display: flex; 12 | justify-content: center; 13 | margin-top: 20px; 14 | } 15 | .img-box{ 16 | margin: 0 auto; 17 | height: 540px; 18 | width: 960px; 19 | border: 1px solid #ebebeb; 20 | display: inline-block; 21 | .bg; 22 | img{ 23 | max-width: 100%; 24 | display: block; 25 | } 26 | } 27 | 28 | .button-box{ 29 | padding: 10px 0 0; 30 | margin-bottom: 25px; 31 | button { 32 | margin: 0 5px; 33 | } 34 | } 35 | 36 | .file_logo{ 37 | .file_name{ 38 | text-align: center; 39 | padding-bottom: 15px; 40 | } 41 | } 42 | .underline { 43 | display: flex; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/components/cropper/xls_logo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yesapicn/YesAdmin/f8ecd8e83c9367c3205272eb1f39c06f8708453a/src/components/cropper/xls_logo.jpg -------------------------------------------------------------------------------- /src/components/drag-drawer/drag-drawer-trigger.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 16 | 17 | 19 | -------------------------------------------------------------------------------- /src/components/drag-drawer/index.js: -------------------------------------------------------------------------------- 1 | import DragDrawer from './drag-drawer.vue' 2 | export default DragDrawer 3 | -------------------------------------------------------------------------------- /src/components/drag-drawer/index.less: -------------------------------------------------------------------------------- 1 | @prefix: ~"drag-drawer"; 2 | @drag-drawer-trigger-height: 100px; 3 | @drag-drawer-trigger-width: 8px; 4 | 5 | .@{prefix}-wrapper{ 6 | &.no-select{ 7 | user-select: none; 8 | } 9 | &.pointer-events-none{ 10 | pointer-events: none; 11 | & .@{prefix}-trigger-wrapper{ 12 | pointer-events: all; 13 | } 14 | } 15 | .ivu-drawer{ 16 | &-header{ 17 | overflow: hidden !important; 18 | box-sizing: border-box; 19 | } 20 | &-body{ 21 | padding: 0; 22 | overflow: visible; 23 | position: static; 24 | display: flex; 25 | flex-direction: column; 26 | } 27 | } 28 | .@{prefix}-body-wrapper{ 29 | width: 100%; 30 | height: 100%; 31 | padding: 16px; 32 | overflow: auto; 33 | } 34 | .@{prefix}-trigger-wrapper{ 35 | top: 0; 36 | height: 100%; 37 | width: 0; 38 | .@{prefix}-move-trigger{ 39 | position: absolute; 40 | top: 50%; 41 | height: @drag-drawer-trigger-height; 42 | width: @drag-drawer-trigger-width; 43 | background: rgb(243, 243, 243); 44 | transform: translate(-50%, -50%); 45 | border-radius: ~"4px / 6px"; 46 | box-shadow: 0 0 1px 1px rgba(0, 0, 0, .2); 47 | line-height: @drag-drawer-trigger-height; 48 | cursor: col-resize; 49 | &-point{ 50 | display: inline-block; 51 | width: 50%; 52 | transform: translateX(50%); 53 | i{ 54 | display: block; 55 | border-bottom: 1px solid rgb(192, 192, 192); 56 | padding-bottom: 2px; 57 | } 58 | } 59 | } 60 | } 61 | .@{prefix}-footer{ 62 | flex-grow: 1; 63 | width: 100%; 64 | bottom: 0; 65 | left: 0; 66 | border-top: 1px solid #e8e8e8; 67 | padding: 10px 16px; 68 | background: #fff; 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/components/drag-drawer/mixin.js: -------------------------------------------------------------------------------- 1 | export default { 2 | data () { 3 | return { 4 | prefix: 'drag-drawer' 5 | } 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/components/drag-list/drag-list.vue: -------------------------------------------------------------------------------- 1 | 21 | 84 | 93 | -------------------------------------------------------------------------------- /src/components/drag-list/index.js: -------------------------------------------------------------------------------- 1 | import DragList from './drag-list.vue' 2 | export default DragList 3 | -------------------------------------------------------------------------------- /src/components/editor/editor.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 70 | 71 | 76 | -------------------------------------------------------------------------------- /src/components/editor/index.js: -------------------------------------------------------------------------------- 1 | import Editor from './editor.vue' 2 | export default Editor 3 | -------------------------------------------------------------------------------- /src/components/icons/icons.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 32 | 33 | 36 | -------------------------------------------------------------------------------- /src/components/icons/index.js: -------------------------------------------------------------------------------- 1 | import Icons from './icons.vue' 2 | export default Icons 3 | -------------------------------------------------------------------------------- /src/components/info-card/index.js: -------------------------------------------------------------------------------- 1 | import InforCard from './infor-card.vue' 2 | export default InforCard 3 | -------------------------------------------------------------------------------- /src/components/info-card/infor-card.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 55 | 56 | 95 | -------------------------------------------------------------------------------- /src/components/login-form/index.js: -------------------------------------------------------------------------------- 1 | import LoginForm from './login-form.vue' 2 | export default LoginForm 3 | -------------------------------------------------------------------------------- /src/components/login-form/login-form.vue: -------------------------------------------------------------------------------- 1 | 26 | 85 | 86 | 101 | -------------------------------------------------------------------------------- /src/components/main/components/a-back-top/index.js: -------------------------------------------------------------------------------- 1 | import ABackTop from './index.vue' 2 | export default ABackTop 3 | -------------------------------------------------------------------------------- /src/components/main/components/a-back-top/index.vue: -------------------------------------------------------------------------------- 1 | 8 | 17 | 98 | -------------------------------------------------------------------------------- /src/components/main/components/error-store/error-store.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 38 | 39 | 50 | -------------------------------------------------------------------------------- /src/components/main/components/error-store/index.js: -------------------------------------------------------------------------------- 1 | import ErrorStore from './error-store.vue' 2 | export default ErrorStore 3 | -------------------------------------------------------------------------------- /src/components/main/components/fullscreen/fullscreen.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 75 | 76 | 85 | -------------------------------------------------------------------------------- /src/components/main/components/fullscreen/index.js: -------------------------------------------------------------------------------- 1 | import Fullscreen from './fullscreen.vue' 2 | export default Fullscreen 3 | -------------------------------------------------------------------------------- /src/components/main/components/header-bar/custom-bread-crumb/custom-bread-crumb.less: -------------------------------------------------------------------------------- 1 | .custom-bread-crumb{ 2 | display: inline-block; 3 | vertical-align: top; 4 | } 5 | -------------------------------------------------------------------------------- /src/components/main/components/header-bar/custom-bread-crumb/custom-bread-crumb.vue: -------------------------------------------------------------------------------- 1 | 11 | 47 | -------------------------------------------------------------------------------- /src/components/main/components/header-bar/custom-bread-crumb/index.js: -------------------------------------------------------------------------------- 1 | import customBreadCrumb from './custom-bread-crumb.vue' 2 | export default customBreadCrumb 3 | -------------------------------------------------------------------------------- /src/components/main/components/header-bar/header-bar.less: -------------------------------------------------------------------------------- 1 | .header-bar{ 2 | width: 100%; 3 | height: 100%; 4 | position: relative; 5 | .custom-content-con{ 6 | float: right; 7 | height: auto; 8 | padding-right: 20px; 9 | line-height: 64px; 10 | & > *{ 11 | float: right; 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/components/main/components/header-bar/header-bar.vue: -------------------------------------------------------------------------------- 1 | 10 | 35 | -------------------------------------------------------------------------------- /src/components/main/components/header-bar/index.js: -------------------------------------------------------------------------------- 1 | import HeaderBar from './header-bar' 2 | export default HeaderBar 3 | -------------------------------------------------------------------------------- /src/components/main/components/header-bar/sider-trigger/index.js: -------------------------------------------------------------------------------- 1 | import siderTrigger from './sider-trigger.vue' 2 | export default siderTrigger 3 | -------------------------------------------------------------------------------- /src/components/main/components/header-bar/sider-trigger/sider-trigger.less: -------------------------------------------------------------------------------- 1 | .trans{ 2 | transition: transform .2s ease; 3 | } 4 | @size: 40px; 5 | .sider-trigger-a{ 6 | padding: 6px; 7 | width: @size; 8 | height: @size; 9 | display: inline-block; 10 | text-align: center; 11 | color: #5c6b77; 12 | margin-top: 12px; 13 | i{ 14 | .trans; 15 | vertical-align: top; 16 | } 17 | &.collapsed i{ 18 | transform: rotateZ(90deg); 19 | .trans; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/components/main/components/header-bar/sider-trigger/sider-trigger.vue: -------------------------------------------------------------------------------- 1 | 4 | 25 | 28 | -------------------------------------------------------------------------------- /src/components/main/components/language/index.js: -------------------------------------------------------------------------------- 1 | import Language from './language.vue' 2 | export default Language 3 | -------------------------------------------------------------------------------- /src/components/main/components/language/language.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 52 | -------------------------------------------------------------------------------- /src/components/main/components/side-menu/collapsed-menu.vue: -------------------------------------------------------------------------------- 1 | 12 | 52 | -------------------------------------------------------------------------------- /src/components/main/components/side-menu/index.js: -------------------------------------------------------------------------------- 1 | import SideMenu from './side-menu.vue' 2 | export default SideMenu 3 | -------------------------------------------------------------------------------- /src/components/main/components/side-menu/item-mixin.js: -------------------------------------------------------------------------------- 1 | export default { 2 | props: { 3 | parentItem: { 4 | type: Object, 5 | default: () => {} 6 | }, 7 | theme: String, 8 | iconSize: Number 9 | }, 10 | computed: { 11 | parentName () { 12 | return this.parentItem.name 13 | }, 14 | children () { 15 | return this.parentItem.children 16 | }, 17 | textColor () { 18 | return this.theme === 'dark' ? '#fff' : '#495060' 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/components/main/components/side-menu/mixin.js: -------------------------------------------------------------------------------- 1 | import CommonIcon from '_c/common-icon' 2 | import { showTitle } from '@/libs/util' 3 | export default { 4 | components: { 5 | CommonIcon 6 | }, 7 | methods: { 8 | showTitle (item) { 9 | return showTitle(item, this) 10 | }, 11 | showChildren (item) { 12 | return item.children && (item.children.length > 1 || (item.meta && item.meta.showAlways)) 13 | }, 14 | getNameOrHref (item, children0) { 15 | return item.href ? `isTurnByHref_${item.href}` : (children0 ? item.children[0].name : item.name) 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/components/main/components/side-menu/side-menu-item.vue: -------------------------------------------------------------------------------- 1 | 19 | 27 | -------------------------------------------------------------------------------- /src/components/main/components/side-menu/side-menu.less: -------------------------------------------------------------------------------- 1 | .side-menu-wrapper{ 2 | user-select: none; 3 | .menu-collapsed{ 4 | padding-top: 10px; 5 | 6 | .ivu-dropdown{ 7 | width: 100%; 8 | .ivu-dropdown-rel a{ 9 | width: 100%; 10 | } 11 | } 12 | .ivu-tooltip{ 13 | width: 100%; 14 | .ivu-tooltip-rel{ 15 | width: 100%; 16 | } 17 | .ivu-tooltip-popper .ivu-tooltip-content{ 18 | .ivu-tooltip-arrow{ 19 | border-right-color: #fff; 20 | } 21 | .ivu-tooltip-inner{ 22 | background: #fff; 23 | color: #495060; 24 | } 25 | } 26 | } 27 | 28 | 29 | } 30 | a.drop-menu-a{ 31 | display: inline-block; 32 | padding: 6px 15px; 33 | width: 100%; 34 | text-align: center; 35 | color: #495060; 36 | } 37 | } 38 | .menu-title{ 39 | padding-left: 6px; 40 | } 41 | -------------------------------------------------------------------------------- /src/components/main/components/tags-nav/index.js: -------------------------------------------------------------------------------- 1 | import TagsNav from './tags-nav.vue' 2 | export default TagsNav 3 | -------------------------------------------------------------------------------- /src/components/main/components/tags-nav/tags-nav.less: -------------------------------------------------------------------------------- 1 | .no-select{ 2 | -webkit-touch-callout: none; 3 | -webkit-user-select: none; 4 | -khtml-user-select: none; 5 | -moz-user-select: none; 6 | -ms-user-select: none; 7 | user-select: none; 8 | } 9 | .size{ 10 | width: 100%; 11 | height: 100%; 12 | } 13 | .tags-nav{ 14 | position: relative; 15 | border-top: 1px solid #F0F0F0; 16 | border-bottom: 1px solid #F0F0F0; 17 | .no-select; 18 | .size; 19 | .close-con{ 20 | position: absolute; 21 | right: 0; 22 | top: 0; 23 | height: 100%; 24 | width: 32px; 25 | background: #fff; 26 | text-align: center; 27 | z-index: 10; 28 | } 29 | .btn-con{ 30 | position: absolute; 31 | top: 0px; 32 | height: 100%; 33 | background: #fff; 34 | padding-top: 3px; 35 | z-index: 10; 36 | button{ 37 | padding: 6px 4px; 38 | line-height: 14px; 39 | text-align: center; 40 | } 41 | &.left-btn{ 42 | left: 0px; 43 | } 44 | &.right-btn{ 45 | right: 32px; 46 | border-right: 1px solid #F0F0F0; 47 | } 48 | } 49 | .scroll-outer{ 50 | position: absolute; 51 | left: 28px; 52 | right: 61px; 53 | top: 0; 54 | bottom: 0; 55 | box-shadow: 0px 0 3px 2px rgba(100,100,100,.1) inset; 56 | .scroll-body{ 57 | height: ~"calc(100% - 1px)"; 58 | display: inline-block; 59 | padding: 1px 4px 0; 60 | position: absolute; 61 | overflow: visible; 62 | white-space: nowrap; 63 | transition: left .3s ease; 64 | .ivu-tag-dot-inner{ 65 | transition: background .2s ease; 66 | } 67 | } 68 | } 69 | .contextmenu { 70 | position: absolute; 71 | margin: 0; 72 | padding: 5px 0; 73 | background: #fff; 74 | z-index: 1000; 75 | list-style-type: none; 76 | border-radius: 4px; 77 | box-shadow: 2px 2px 3px 0 rgba(0, 0, 0, .1); 78 | li { 79 | margin: 0; 80 | padding: 5px 15px; 81 | cursor: pointer; 82 | &:hover { 83 | background: #eee; 84 | } 85 | } 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /src/components/main/components/user/index.js: -------------------------------------------------------------------------------- 1 | import User from './user.vue' 2 | export default User 3 | -------------------------------------------------------------------------------- /src/components/main/components/user/user.less: -------------------------------------------------------------------------------- 1 | .user{ 2 | &-avatar-dropdown{ 3 | cursor: pointer; 4 | display: inline-block; 5 | // height: 64px; 6 | vertical-align: middle; 7 | // line-height: 64px; 8 | .ivu-badge-dot{ 9 | top: 16px; 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/components/main/components/user/user.vue: -------------------------------------------------------------------------------- 1 | 17 | 18 | 60 | -------------------------------------------------------------------------------- /src/components/main/index.js: -------------------------------------------------------------------------------- 1 | import Main from './main.vue' 2 | export default Main 3 | -------------------------------------------------------------------------------- /src/components/main/main.less: -------------------------------------------------------------------------------- 1 | .main{ 2 | .logo-con{ 3 | height: 64px; 4 | padding: 10px; 5 | img{ 6 | height: 44px; 7 | width: auto; 8 | display: block; 9 | } 10 | } 11 | .header-con{ 12 | background: #fff; 13 | padding: 0 20px; 14 | width: 100%; 15 | } 16 | .main-layout-con{ 17 | height: 100%; 18 | overflow: hidden; 19 | } 20 | .main-content-con{ 21 | height: ~"calc(100% - 60px)"; 22 | overflow: hidden; 23 | } 24 | .tag-nav-wrapper{ 25 | padding: 0; 26 | height:40px; 27 | background:#F0F0F0; 28 | } 29 | .content-wrapper{ 30 | padding: 18px; 31 | height: ~"calc(100% - 80px)"; 32 | overflow: auto; 33 | } 34 | .left-sider{ 35 | .ivu-layout-sider-children{ 36 | overflow-y: scroll; 37 | margin-right: -18px; 38 | } 39 | } 40 | } 41 | .ivu-menu-item > i{ 42 | margin-right: 12px !important; 43 | } 44 | .ivu-menu-submenu > .ivu-menu > .ivu-menu-item > i { 45 | margin-right: 8px !important; 46 | } 47 | .collased-menu-dropdown{ 48 | width: 100%; 49 | margin: 0; 50 | line-height: normal; 51 | padding: 7px 0 6px 16px; 52 | clear: both; 53 | font-size: 12px !important; 54 | white-space: nowrap; 55 | list-style: none; 56 | cursor: pointer; 57 | transition: background 0.2s ease-in-out; 58 | &:hover{ 59 | background: rgba(100, 100, 100, 0.1); 60 | } 61 | & * { 62 | color: #515a6e; 63 | } 64 | .ivu-menu-item > i{ 65 | margin-right: 12px !important; 66 | } 67 | .ivu-menu-submenu > .ivu-menu > .ivu-menu-item > i { 68 | margin-right: 8px !important; 69 | } 70 | } 71 | 72 | .ivu-select-dropdown.ivu-dropdown-transfer{ 73 | max-height: 400px; 74 | } 75 | -------------------------------------------------------------------------------- /src/components/markdown/index.js: -------------------------------------------------------------------------------- 1 | import MarkdownEditor from './markdown.vue' 2 | export default MarkdownEditor 3 | -------------------------------------------------------------------------------- /src/components/markdown/markdown.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 63 | 64 | 77 | -------------------------------------------------------------------------------- /src/components/parent-view/index.js: -------------------------------------------------------------------------------- 1 | import ParentView from './parent-view.vue' 2 | export default ParentView 3 | -------------------------------------------------------------------------------- /src/components/parent-view/parent-view.vue: -------------------------------------------------------------------------------- 1 | 6 | 22 | -------------------------------------------------------------------------------- /src/components/paste-editor/index.js: -------------------------------------------------------------------------------- 1 | import PasteEditor from './paste-editor.vue' 2 | export default PasteEditor 3 | -------------------------------------------------------------------------------- /src/components/paste-editor/paste-editor.less: -------------------------------------------------------------------------------- 1 | .paste-editor-wrapper{ 2 | width: 100%; 3 | height: 100%; 4 | border: 1px dashed gainsboro; 5 | textarea.textarea-el{ 6 | width: 100%; 7 | height: 100%; 8 | } 9 | .CodeMirror{ 10 | height: 100%; 11 | padding: 0; 12 | .CodeMirror-code div .CodeMirror-line > span > span.cm-tab{ 13 | &::after{ 14 | content: '→'; 15 | color: #BFBFBF; 16 | } 17 | } 18 | } 19 | .first-row{ 20 | font-weight: 700; 21 | font-size: 14px; 22 | } 23 | .incorrect-row{ 24 | background: #F5CBD1; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/components/paste-editor/paste-editor.vue: -------------------------------------------------------------------------------- 1 | 6 | 113 | 116 | -------------------------------------------------------------------------------- /src/components/paste-editor/plugins/placeholder.js: -------------------------------------------------------------------------------- 1 | export default (codemirror) => { 2 | (function (mod) { 3 | mod(codemirror) 4 | })(function (CodeMirror) { 5 | CodeMirror.defineOption('placeholder', '', function (cm, val, old) { 6 | var prev = old && old !== CodeMirror.Init 7 | if (val && !prev) { 8 | cm.on('blur', onBlur) 9 | cm.on('change', onChange) 10 | cm.on('swapDoc', onChange) 11 | onChange(cm) 12 | } else if (!val && prev) { 13 | cm.off('blur', onBlur) 14 | cm.off('change', onChange) 15 | cm.off('swapDoc', onChange) 16 | clearPlaceholder(cm) 17 | var wrapper = cm.getWrapperElement() 18 | wrapper.className = wrapper.className.replace(' CodeMirror-empty', '') 19 | } 20 | 21 | if (val && !cm.hasFocus()) onBlur(cm) 22 | }) 23 | 24 | function clearPlaceholder (cm) { 25 | if (cm.state.placeholder) { 26 | cm.state.placeholder.parentNode.removeChild(cm.state.placeholder) 27 | cm.state.placeholder = null 28 | } 29 | } 30 | function setPlaceholder (cm) { 31 | clearPlaceholder(cm) 32 | var elt = cm.state.placeholder = document.createElement('pre') 33 | elt.style.cssText = 'height: 0; overflow: visible; color: #80848f;' 34 | elt.style.direction = cm.getOption('direction') 35 | elt.className = 'CodeMirror-placeholder' 36 | var placeHolder = cm.getOption('placeholder') 37 | if (typeof placeHolder === 'string') placeHolder = document.createTextNode(placeHolder) 38 | elt.appendChild(placeHolder) 39 | cm.display.lineSpace.insertBefore(elt, cm.display.lineSpace.firstChild) 40 | } 41 | 42 | function onBlur (cm) { 43 | if (isEmpty(cm)) setPlaceholder(cm) 44 | } 45 | function onChange (cm) { 46 | let wrapper = cm.getWrapperElement() 47 | let empty = isEmpty(cm) 48 | wrapper.className = wrapper.className.replace(' CodeMirror-empty', '') + (empty ? ' CodeMirror-empty' : '') 49 | 50 | if (empty) setPlaceholder(cm) 51 | else clearPlaceholder(cm) 52 | } 53 | 54 | function isEmpty (cm) { 55 | return (cm.lineCount() === 1) && (cm.getLine(0) === '') 56 | } 57 | }) 58 | } 59 | -------------------------------------------------------------------------------- /src/components/register-form/index.js: -------------------------------------------------------------------------------- 1 | import registerForm from './register-form.vue' 2 | export default registerForm 3 | -------------------------------------------------------------------------------- /src/components/register-form/register-form.vue: -------------------------------------------------------------------------------- 1 | 48 | 115 | 116 | 137 | -------------------------------------------------------------------------------- /src/components/split-pane/index.js: -------------------------------------------------------------------------------- 1 | import Split from './split.vue' 2 | export default Split 3 | -------------------------------------------------------------------------------- /src/components/split-pane/index.less: -------------------------------------------------------------------------------- 1 | @split-prefix-cls: ~"ivu-split"; 2 | @box-shadow: 0 0 4px 0 rgba(28, 36, 56, 0.4); 3 | @trigger-bar-background: rgba(23, 35, 61, 0.25); 4 | @trigger-background: #F8F8F9; 5 | @trigger-width: 6px; 6 | @trigger-bar-width: 4px; 7 | @trigger-bar-offset: (@trigger-width - @trigger-bar-width) / 2; 8 | @trigger-bar-interval: 3px; 9 | @trigger-bar-weight: 1px; 10 | @trigger-bar-con-height: (@trigger-bar-weight + @trigger-bar-interval) * 8; 11 | 12 | .@{split-prefix-cls}{ 13 | &-wrapper{ 14 | position: relative; 15 | width: 100%; 16 | height: 100%; 17 | } 18 | &-pane{ 19 | position: absolute; 20 | &.left-pane, &.right-pane{ 21 | top: 0px; 22 | bottom: 0px; 23 | } 24 | &.left-pane{ 25 | left: 0px; 26 | } 27 | &.right-pane{ 28 | right: 0px; 29 | } 30 | &.top-pane, &.bottom-pane{ 31 | left: 0px; 32 | right: 0px; 33 | } 34 | &.top-pane{ 35 | top: 0px; 36 | } 37 | &.bottom-pane{ 38 | bottom: 0px; 39 | } 40 | } 41 | &-trigger{ 42 | &-con{ 43 | position: absolute; 44 | transform: translate(-50%, -50%); 45 | z-index: 10; 46 | } 47 | &-bar-con{ 48 | position: absolute; 49 | overflow: hidden; 50 | &.vertical{ 51 | left: @trigger-bar-offset; 52 | top: 50%; 53 | height: @trigger-bar-con-height; 54 | transform: translate(0, -50%); 55 | } 56 | &.horizontal{ 57 | left: 50%; 58 | top: @trigger-bar-offset; 59 | width: @trigger-bar-con-height; 60 | transform: translate(-50%, 0); 61 | } 62 | } 63 | &-vertical{ 64 | width: @trigger-width; 65 | height: 100%; 66 | background: @trigger-background; 67 | box-shadow: @box-shadow; 68 | cursor: col-resize; 69 | .@{split-prefix-cls}-trigger-bar{ 70 | width: @trigger-bar-width; 71 | height: 1px; 72 | background: @trigger-bar-background; 73 | float: left; 74 | margin-top: @trigger-bar-interval; 75 | } 76 | } 77 | &-horizontal{ 78 | height: @trigger-width; 79 | width: 100%; 80 | background: @trigger-background; 81 | box-shadow: @box-shadow; 82 | cursor: row-resize; 83 | .@{split-prefix-cls}-trigger-bar{ 84 | height: @trigger-bar-width; 85 | width: 1px; 86 | background: @trigger-bar-background; 87 | float: left; 88 | margin-right: @trigger-bar-interval; 89 | } 90 | } 91 | } 92 | &-horizontal{ 93 | .@{split-prefix-cls}-trigger-con{ 94 | top: 50%; 95 | height: 100%; 96 | width: 0; 97 | } 98 | } 99 | &-vertical{ 100 | .@{split-prefix-cls}-trigger-con{ 101 | left: 50%; 102 | height: 0; 103 | width: 100%; 104 | } 105 | } 106 | .no-select{ 107 | -webkit-touch-callout: none; 108 | -webkit-user-select: none; 109 | -khtml-user-select: none; 110 | -moz-user-select: none; 111 | -ms-user-select: none; 112 | user-select: none; 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /src/components/split-pane/trigger.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 40 | 41 | 44 | -------------------------------------------------------------------------------- /src/components/tables/edit.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 45 | 46 | 74 | -------------------------------------------------------------------------------- /src/components/tables/handle-btns.js: -------------------------------------------------------------------------------- 1 | const btns = { 2 | delete: (h, params, vm) => { 3 | return h('Poptip', { 4 | props: { 5 | confirm: true, 6 | title: '你确定要删除吗?' 7 | }, 8 | on: { 9 | 'on-ok': () => { 10 | vm.$emit('on-delete', params) 11 | vm.$emit('input', params.tableData.filter((item, index) => index !== params.row.initRowIndex)) 12 | } 13 | } 14 | }, [ 15 | h('Button', { 16 | props: { 17 | type: 'text', 18 | ghost: true 19 | } 20 | }, [ 21 | h('Icon', { 22 | props: { 23 | type: 'md-trash', 24 | size: 18, 25 | color: '#000000' 26 | } 27 | }) 28 | ]) 29 | ]) 30 | } 31 | } 32 | 33 | export default btns 34 | -------------------------------------------------------------------------------- /src/components/tables/index.js: -------------------------------------------------------------------------------- 1 | import Tables from './tables.vue' 2 | export default Tables 3 | -------------------------------------------------------------------------------- /src/components/tables/index.less: -------------------------------------------------------------------------------- 1 | .search-con{ 2 | padding: 10px 0; 3 | .search{ 4 | &-col{ 5 | display: inline-block; 6 | width: 200px; 7 | } 8 | &-input{ 9 | display: inline-block; 10 | width: 200px; 11 | margin-left: 2px; 12 | } 13 | &-btn{ 14 | margin-left: 2px; 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/components/tree-select/index.js: -------------------------------------------------------------------------------- 1 | export { default } from './tree-select.vue' 2 | -------------------------------------------------------------------------------- /src/components/tree-select/tree-select-tree.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 134 | 135 | 136 | -------------------------------------------------------------------------------- /src/components/tree-select/tree-select.vue: -------------------------------------------------------------------------------- 1 | 18 | 19 | 65 | 66 | 73 | -------------------------------------------------------------------------------- /src/config/index.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @Description: 3 | * @Author: He Jiecong 4 | * @Date: 2019-12-13 18:40:24 5 | * @LastEditTime : 2019-12-30 19:33:51 6 | * @LastEditors : He Jiecong 7 | */ 8 | export default { 9 | /** 10 | * @description 配置显示在浏览器标签的title 11 | */ 12 | title: 'YesAdmin', 13 | /** 14 | * @description token在Cookie中存储的天数,默认保存1天,记住登录状态时保存30天 15 | */ 16 | cookieExpires_short: 1, 17 | cookieExpires_long: 30, 18 | /** 19 | * @description 是否使用国际化,默认为false 20 | * 如果不使用,则需要在路由中给需要在菜单中展示的路由设置meta: {title: 'xxx'} 21 | * 用来在菜单中显示文字 22 | */ 23 | useI18n: true, 24 | /** 25 | * @description 小白后台接用户的APP_KEY和密钥 26 | * 用于在请求中生成动态签名 27 | */ 28 | OKAYAPI_APP_KEY: '16BD4337FB1D355902E0502AFCBFD4DF', // TODO: 你的app_key 29 | OKAYAPI_APP_SECRECT: 'vL1UcBrUalTYr7N39joqGzYHNMcSk28qfir7OJIuSxVAzPcLpd8WVCPtDzLcS', // TODO: 仅本地开发调试需要,构建时可置空 30 | 31 | /** 32 | * @description api请求基础路径 33 | */ 34 | baseUrl: { 35 | dev: 'http://api.yesapi.cn/yesapi/', // TODO:你的小白接口域名 36 | pro: '/yesapi/'// 正式域名,不需要修改 37 | }, 38 | proxyTable: { 39 | '/api': { 40 | target: 'http://hn216.api.yesapi.cn/yesapi/', // TODO:你的小白接口域名 41 | changeOrigin: true, // 开启代理 42 | pathRewrite: { 43 | '^/api': '/' 44 | } 45 | } 46 | }, 47 | 48 | /** 49 | * @description 默认打开的首页的路由name值,默认为home 50 | */ 51 | homeName: 'home', 52 | /** 53 | * @description 需要加载的插件 54 | */ 55 | plugin: { 56 | 'error-store': { 57 | showInHeader: true, // 设为false后不会在顶部显示错误日志徽标 58 | developmentOff: true // 设为true后在开发环境不会收集错误信息,方便开发中排查错误 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/directive/directives.js: -------------------------------------------------------------------------------- 1 | import draggable from './module/draggable' 2 | import clipboard from './module/clipboard' 3 | 4 | const directives = { 5 | draggable, 6 | clipboard 7 | } 8 | 9 | export default directives 10 | 11 | //todo clipboard 12 | -------------------------------------------------------------------------------- /src/directive/index.js: -------------------------------------------------------------------------------- 1 | import directive from './directives' 2 | 3 | const importDirective = Vue => { 4 | /** 5 | * 拖拽指令 v-draggable="options" 6 | * options = { 7 | * trigger: /这里传入作为拖拽触发器的CSS选择器/, 8 | * body: /这里传入需要移动容器的CSS选择器/, 9 | * recover: /拖动结束之后是否恢复到原来的位置/ 10 | * } 11 | */ 12 | Vue.directive('draggable', directive.draggable) 13 | /** 14 | * clipboard指令 v-draggable="options" 15 | * options = { 16 | * value: /在输入框中使用v-model绑定的值/, 17 | * success: /复制成功后的回调/, 18 | * error: /复制失败后的回调/ 19 | * } 20 | */ 21 | Vue.directive('clipboard', directive.clipboard) 22 | } 23 | 24 | export default importDirective 25 | -------------------------------------------------------------------------------- /src/directive/module/clipboard.js: -------------------------------------------------------------------------------- 1 | import Clipboard from 'clipboard' 2 | export default { 3 | bind: (el, binding) => { 4 | const clipboard = new Clipboard(el, { 5 | text: () => binding.value.value 6 | }) 7 | el.__success_callback__ = binding.value.success 8 | el.__error_callback__ = binding.value.error 9 | clipboard.on('success', e => { 10 | const callback = el.__success_callback__ 11 | callback && callback(e) 12 | }) 13 | clipboard.on('error', e => { 14 | const callback = el.__error_callback__ 15 | callback && callback(e) 16 | }) 17 | el.__clipboard__ = clipboard 18 | }, 19 | update: (el, binding) => { 20 | el.__clipboard__.text = () => binding.value.value 21 | el.__success_callback__ = binding.value.success 22 | el.__error_callback__ = binding.value.error 23 | }, 24 | unbind: (el, binding) => { 25 | delete el.__success_callback__ 26 | delete el.__error_callback__ 27 | el.__clipboard__.destroy() 28 | delete el.__clipboard__ 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/directive/module/draggable.js: -------------------------------------------------------------------------------- 1 | import { on } from '@/libs/tools' 2 | export default { 3 | inserted: (el, binding, vnode) => { 4 | let triggerDom = document.querySelector(binding.value.trigger) 5 | triggerDom.style.cursor = 'move' 6 | let bodyDom = document.querySelector(binding.value.body) 7 | let pageX = 0 8 | let pageY = 0 9 | let transformX = 0 10 | let transformY = 0 11 | let canMove = false 12 | const handleMousedown = e => { 13 | let transform = /\(.*\)/.exec(bodyDom.style.transform) 14 | if (transform) { 15 | transform = transform[0].slice(1, transform[0].length - 1) 16 | let splitxy = transform.split('px, ') 17 | transformX = parseFloat(splitxy[0]) 18 | transformY = parseFloat(splitxy[1].split('px')[0]) 19 | } 20 | pageX = e.pageX 21 | pageY = e.pageY 22 | canMove = true 23 | } 24 | const handleMousemove = e => { 25 | let xOffset = e.pageX - pageX + transformX 26 | let yOffset = e.pageY - pageY + transformY 27 | if (canMove) bodyDom.style.transform = `translate(${xOffset}px, ${yOffset}px)` 28 | } 29 | const handleMouseup = e => { 30 | canMove = false 31 | } 32 | on(triggerDom, 'mousedown', handleMousedown) 33 | on(document, 'mousemove', handleMousemove) 34 | on(document, 'mouseup', handleMouseup) 35 | }, 36 | update: (el, binding, vnode) => { 37 | if (!binding.value.recover) return 38 | let bodyDom = document.querySelector(binding.value.body) 39 | bodyDom.style.transform = '' 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/index.less: -------------------------------------------------------------------------------- 1 | @import '~iview/src/styles/index.less'; 2 | 3 | /* 4 | 修改侧栏颜色 5 | */ 6 | @menu-dark-title: rgb(17, 40, 88); 7 | @menu-dark-active-bg: rgb(14, 31, 70); 8 | @layout-sider-background: rgb(17, 40, 88); 9 | @layout-header-background: rgb(17, 40, 88); 10 | 11 | /* 12 | 修改iview样式主题色 13 | */ 14 | @primary-color : #466FCD; 15 | @info-color : #2db7f5; 16 | @warning-color : #EDA008; -------------------------------------------------------------------------------- /src/libs/api.request.js: -------------------------------------------------------------------------------- 1 | import HttpRequest from '@/libs/axios' 2 | import config from '@/config' 3 | const baseUrl = process.env.NODE_ENV === 'development' ? config.baseUrl.dev : config.baseUrl.pro 4 | 5 | const axios = new HttpRequest(baseUrl) 6 | export default axios 7 | -------------------------------------------------------------------------------- /src/libs/axios.js: -------------------------------------------------------------------------------- 1 | import axios from 'axios' 2 | import store from '@/store' 3 | // import { Spin } from 'iview' 4 | const addErrorLog = errorInfo => { 5 | const { statusText, status, request: { responseURL } } = errorInfo 6 | let info = { 7 | type: 'ajax', 8 | code: status, 9 | mes: statusText, 10 | url: responseURL 11 | } 12 | if (!responseURL.includes('save_error_logger')) store.dispatch('addErrorLog', info) 13 | } 14 | 15 | class HttpRequest { 16 | constructor (baseUrl = baseURL) { 17 | this.baseUrl = baseUrl 18 | this.queue = {} 19 | } 20 | // 获取http请求中的请求配置 21 | getInsideConfig () { 22 | const config = { 23 | baseURL: this.baseUrl, 24 | headers: { 25 | 'Content-Type': 'application/x-www-form-urlencoded' 26 | } 27 | } 28 | return config 29 | } 30 | destroy (url) { 31 | delete this.queue[url] // deleted 的用法?ES6class的规范? 32 | 33 | if (!Object.keys(this.queue).length) { 34 | // Spin.hide() 35 | } 36 | } 37 | interceptors (instance, url) { 38 | // 请求拦截 39 | instance.interceptors.request.use(config => { 40 | // 添加全局的loading... 41 | if (!Object.keys(this.queue).length) { 42 | // Spin.show() // 不建议开启,因为界面不友好 43 | } 44 | this.queue[url] = true 45 | return config 46 | }, error => { 47 | return Promise.reject(error) 48 | }) 49 | // 响应拦截 50 | instance.interceptors.response.use(res => { 51 | this.destroy(url) 52 | const { data, status } = res 53 | return { data, status } 54 | }, error => { 55 | this.destroy(url) 56 | let errorInfo = error.response 57 | if (!errorInfo) { 58 | const { request: { statusText, status }, config } = JSON.parse(JSON.stringify(error)) 59 | errorInfo = { 60 | statusText, 61 | status, 62 | request: { responseURL: config.url } 63 | } 64 | } 65 | addErrorLog(errorInfo) 66 | return Promise.reject(error) 67 | }) 68 | } 69 | request (options) { 70 | const instance = axios.create() 71 | options = Object.assign(this.getInsideConfig(), options) 72 | this.interceptors(instance, options.url) 73 | return instance(options) 74 | } 75 | } 76 | export default HttpRequest 77 | -------------------------------------------------------------------------------- /src/libs/excel.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | import XLSX from 'xlsx'; 3 | 4 | function auto_width(ws, data){ 5 | /*set worksheet max width per col*/ 6 | const colWidth = data.map(row => row.map(val => { 7 | /*if null/undefined*/ 8 | if (val == null) { 9 | return {'wch': 10}; 10 | } 11 | /*if chinese*/ 12 | else if (val.toString().charCodeAt(0) > 255) { 13 | return {'wch': val.toString().length * 2}; 14 | } else { 15 | return {'wch': val.toString().length}; 16 | } 17 | })) 18 | /*start in the first row*/ 19 | let result = colWidth[0]; 20 | for (let i = 1; i < colWidth.length; i++) { 21 | for (let j = 0; j < colWidth[i].length; j++) { 22 | if (result[j]['wch'] < colWidth[i][j]['wch']) { 23 | result[j]['wch'] = colWidth[i][j]['wch']; 24 | } 25 | } 26 | } 27 | ws['!cols'] = result; 28 | } 29 | 30 | function json_to_array(key, jsonData){ 31 | return jsonData.map(v => key.map(j => { return v[j] })); 32 | } 33 | 34 | // fix data,return string 35 | function fixdata(data) { 36 | let o = '' 37 | let l = 0 38 | const w = 10240 39 | for (; l < data.byteLength / w; ++l) o += String.fromCharCode.apply(null, new Uint8Array(data.slice(l * w, l * w + w))) 40 | o += String.fromCharCode.apply(null, new Uint8Array(data.slice(l * w))) 41 | return o 42 | } 43 | 44 | // get head from excel file,return array 45 | function get_header_row(sheet) { 46 | const headers = [] 47 | const range = XLSX.utils.decode_range(sheet['!ref']) 48 | let C 49 | const R = range.s.r /* start in the first row */ 50 | for (C = range.s.c; C <= range.e.c; ++C) { /* walk every column in the range */ 51 | var cell = sheet[XLSX.utils.encode_cell({ c: C, r: R })] /* find the cell in the first row */ 52 | var hdr = 'UNKNOWN ' + C // <-- replace with your desired default 53 | if (cell && cell.t) hdr = XLSX.utils.format_cell(cell) 54 | headers.push(hdr) 55 | } 56 | return headers 57 | } 58 | 59 | export const export_table_to_excel= (id, filename) => { 60 | const table = document.getElementById(id); 61 | const wb = XLSX.utils.table_to_book(table); 62 | XLSX.writeFile(wb, filename); 63 | 64 | /* the second way */ 65 | // const table = document.getElementById(id); 66 | // const wb = XLSX.utils.book_new(); 67 | // const ws = XLSX.utils.table_to_sheet(table); 68 | // XLSX.utils.book_append_sheet(wb, ws, filename); 69 | // XLSX.writeFile(wb, filename); 70 | } 71 | 72 | export const export_json_to_excel = ({data, key, title, filename, autoWidth}) => { 73 | const wb = XLSX.utils.book_new(); 74 | data.unshift(title); 75 | const ws = XLSX.utils.json_to_sheet(data, {header: key, skipHeader: true}); 76 | if(autoWidth){ 77 | const arr = json_to_array(key, data); 78 | auto_width(ws, arr); 79 | } 80 | XLSX.utils.book_append_sheet(wb, ws, filename); 81 | XLSX.writeFile(wb, filename + '.xlsx'); 82 | } 83 | 84 | export const export_array_to_excel = ({key, data, title, filename, autoWidth}) => { 85 | const wb = XLSX.utils.book_new(); 86 | const arr = json_to_array(key, data); 87 | arr.unshift(title); 88 | const ws = XLSX.utils.aoa_to_sheet(arr); 89 | if(autoWidth){ 90 | auto_width(ws, arr); 91 | } 92 | XLSX.utils.book_append_sheet(wb, ws, filename); 93 | XLSX.writeFile(wb, filename + '.xlsx'); 94 | } 95 | 96 | export const read = (data, type) => { 97 | /* if type == 'base64' must fix data first */ 98 | // const fixedData = fixdata(data) 99 | // const workbook = XLSX.read(btoa(fixedData), { type: 'base64' }) 100 | const workbook = XLSX.read(data, { type: type }); 101 | const firstSheetName = workbook.SheetNames[0]; 102 | const worksheet = workbook.Sheets[firstSheetName]; 103 | const header = get_header_row(worksheet); 104 | const results = XLSX.utils.sheet_to_json(worksheet); 105 | return {header, results}; 106 | } 107 | 108 | export default { 109 | export_table_to_excel, 110 | export_array_to_excel, 111 | export_json_to_excel, 112 | read 113 | } 114 | -------------------------------------------------------------------------------- /src/libs/render-dom.js: -------------------------------------------------------------------------------- 1 | export default { 2 | name: 'RenderDom', 3 | functional: true, 4 | props: { 5 | render: Function 6 | }, 7 | render: (h, ctx) => { 8 | return ctx.props.render(h) 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/locale/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import VueI18n from 'vue-i18n' 3 | import { localRead } from '@/libs/util' 4 | import customZhCn from './lang/zh-CN' 5 | import customZhTw from './lang/zh-TW' 6 | import customEnUs from './lang/en-US' 7 | import zhCnLocale from 'iview/src/locale/lang/zh-CN' 8 | import enUsLocale from 'iview/src/locale/lang/en-US' 9 | import zhTwLocale from 'iview/src/locale/lang/zh-TW' 10 | 11 | Vue.use(VueI18n) 12 | 13 | // 自动根据浏览器系统语言设置语言 14 | const navLang = navigator.language 15 | const localLang = (navLang === 'zh-CN' || navLang === 'en-US') ? navLang : false 16 | let lang = localLang || localRead('local') || 'zh-CN' 17 | 18 | Vue.config.lang = lang 19 | 20 | // vue-i18n 6.x+写法 21 | Vue.locale = () => {} 22 | const messages = { 23 | 'zh-CN': Object.assign(zhCnLocale, customZhCn), 24 | 'zh-TW': Object.assign(zhTwLocale, customZhTw), 25 | 'en-US': Object.assign(enUsLocale, customEnUs) 26 | } 27 | const i18n = new VueI18n({ 28 | locale: lang, 29 | messages 30 | }) 31 | 32 | export default i18n 33 | 34 | // vue-i18n 5.x写法 35 | // Vue.locale('zh-CN', Object.assign(zhCnLocale, customZhCn)) 36 | // Vue.locale('en-US', Object.assign(zhTwLocale, customZhTw)) 37 | // Vue.locale('zh-TW', Object.assign(enUsLocale, customEnUs)) 38 | -------------------------------------------------------------------------------- /src/locale/lang/en-US.js: -------------------------------------------------------------------------------- 1 | export default { 2 | home: 'Home', 3 | login: 'Login', 4 | components: 'Components', 5 | count_to_page: 'Count-to', 6 | tables_page: 'Table', 7 | split_pane_page: 'Split-pane', 8 | markdown_page: 'Markdown-editor', 9 | editor_page: 'Rich-Text-Editor', 10 | icons_page: 'Custom-icon', 11 | img_cropper_page: 'Image-editor', 12 | update: 'Update', 13 | doc: 'Document', 14 | join_page: 'QQ Group', 15 | update_table_page: 'Update .CSV', 16 | update_paste_page: 'Paste Table Data', 17 | multilevel: 'multilevel', 18 | directive_page: 'Directive', 19 | level_1: 'Level-1', 20 | level_2: 'Level-2', 21 | level_2_1: 'Level-2-1', 22 | level_2_3: 'Level-2-3', 23 | level_2_2: 'Level-2-2', 24 | level_2_2_1: 'Level-2-2-1', 25 | level_2_2_2: 'Level-2-2-2', 26 | excel: 'Excel', 27 | 'upload-excel': 'Upload Excel', 28 | 'export-excel': 'Export Excel', 29 | tools_methods_page: 'Tools Methods', 30 | drag_list_page: 'Drag-list', 31 | i18n_page: 'Internationalization', 32 | modalTitle: 'Modal Title', 33 | content: 'This is the modal box content.', 34 | buttonText: 'Show Modal', 35 | 'i18n-tip': 'Note: Only this page is multi-language, other pages do not add language content to the multi-language package.', 36 | error_store_page: 'Error Collection', 37 | error_logger_page: 'Error Logger', 38 | query: 'Query', 39 | params: 'Params', 40 | cropper_page: 'Cropper', 41 | message_page: 'Message Center', 42 | tree_table_page: 'Tree Table', 43 | org_tree_page: 'Org Tree', 44 | drag_drawer_page: 'Draggable Drawer', 45 | tree_select_page: 'Tree Selector', 46 | pictures: 'picture', 47 | assets_upload: 'Picture Upload', 48 | assets_manage: 'Picture Manage', 49 | articles: 'Articles', 50 | articles_manage: 'Article Manage', 51 | acticle_add: 'Article Add', 52 | article_review: 'Article Review', 53 | upload_csv: 'Upload CSV', 54 | stats: 'Stats', 55 | login_stats: 'Login Stats', 56 | register_stats: 'Register Stats' 57 | } 58 | -------------------------------------------------------------------------------- /src/locale/lang/zh-CN.js: -------------------------------------------------------------------------------- 1 | export default { 2 | home: '首页', 3 | login: '登录', 4 | components: '组件', 5 | count_to_page: '数字渐变', 6 | tables_page: '多功能表格', 7 | split_pane_page: '分割窗口', 8 | markdown_page: 'Markdown编辑器', 9 | editor_page: '富文本编辑器', 10 | icons_page: '自定义图标', 11 | img_cropper_page: '图片编辑器', 12 | update: '上传数据', 13 | join_page: 'QQ群', 14 | doc: '文档', 15 | update_table_page: '上传CSV文件', 16 | update_paste_page: '粘贴表格数据', 17 | multilevel: '多级菜单', 18 | directive_page: '指令', 19 | level_1: 'Level-1', 20 | level_2: 'Level-2', 21 | level_2_1: 'Level-2-1', 22 | level_2_3: 'Level-2-3', 23 | level_2_2: 'Level-2-2', 24 | level_2_2_1: 'Level-2-2-1', 25 | level_2_2_2: 'Level-2-2-2', 26 | excel: 'Excel', 27 | 'upload-excel': '上传excel', 28 | 'export-excel': '导出excel', 29 | tools_methods_page: '工具函数', 30 | drag_list_page: '拖拽列表', 31 | i18n_page: '多语言', 32 | modalTitle: '模态框题目', 33 | content: '这是模态框内容', 34 | buttonText: '显示模态框', 35 | 'i18n-tip': '注:仅此页做了多语言,其他页面没有在多语言包中添加语言内容', 36 | error_store_page: '错误收集', 37 | error_logger_page: '错误日志', 38 | query: '带参路由', 39 | params: '动态路由', 40 | cropper_page: '图片裁剪', 41 | message_page: '消息中心', 42 | tree_table_page: '树状表格', 43 | org_tree_page: '组织结构树', 44 | drag_drawer_page: '可拖动抽屉', 45 | tree_select_page: '树状下拉选择器', 46 | pictures:'素材库', 47 | assets_upload:'上传图片', 48 | assets_manage:'素材管理', 49 | articles: '文章管理', 50 | articles_manage: '文章管理', 51 | acticle_add: '添加文章', 52 | article_review: '查看文章', 53 | upload_csv: '上传csv文件', 54 | stats: '数据统计', 55 | login_stats: '登录统计', 56 | register_stats: '注册统计' 57 | } 58 | -------------------------------------------------------------------------------- /src/locale/lang/zh-TW.js: -------------------------------------------------------------------------------- 1 | export default { 2 | home: '首頁', 3 | login: '登錄', 4 | components: '组件', 5 | count_to_page: '数字渐变', 6 | tables_page: '多功能表格', 7 | split_pane_page: '分割窗口', 8 | markdown_page: 'Markdown編輯器', 9 | editor_page: '富文本編輯器', 10 | icons_page: '自定義圖標', 11 | img_cropper_page: '圖片編輯器', 12 | update: '上傳數據', 13 | join_page: 'QQ群', 14 | doc: '文檔', 15 | update_table_page: '上傳CSV文件', 16 | update_paste_page: '粘貼表格數據', 17 | multilevel: '多级菜单', 18 | directive_page: '指令', 19 | level_1: 'Level-1', 20 | level_2: 'Level-2', 21 | level_2_1: 'Level-2-1', 22 | level_2_3: 'Level-2-3', 23 | level_2_2: 'Level-2-2', 24 | level_2_2_1: 'Level-2-2-1', 25 | level_2_2_2: 'Level-2-2-2', 26 | excel: 'Excel', 27 | 'upload-excel': '上傳excel', 28 | 'export-excel': '導出excel', 29 | tools_methods_page: '工具函數', 30 | drag_list_page: '拖拽列表', 31 | i18n_page: '多語言', 32 | modalTitle: '模態框題目', 33 | content: '這是模態框內容', 34 | buttonText: '顯示模態框', 35 | 'i18n-tip': '注:僅此頁做了多語言,其他頁面沒有在多語言包中添加語言內容', 36 | error_store_page: '錯誤收集', 37 | error_logger_page: '錯誤日誌', 38 | query: '帶參路由', 39 | params: '動態路由', 40 | cropper_page: '圖片裁剪', 41 | message_page: '消息中心', 42 | tree_table_page: '樹狀表格', 43 | org_tree_page: '組織結構樹', 44 | drag_drawer_page: '可拖動抽屜', 45 | tree_select_page: '樹狀下拉選擇器', 46 | pictures:'素材庫', 47 | assets_upload:'上傳圖片', 48 | assets_manage:'素材管理', 49 | articles: '文章管理', 50 | articles_manage: '文章管理', 51 | acticle_add: '添加文章', 52 | article_review: '查看文章', 53 | upload_csv: '上傳csv文件', 54 | stats: '數據統計', 55 | login_stats: '登錄統計', 56 | register_stats: '註冊統計' 57 | } 58 | -------------------------------------------------------------------------------- /src/main.js: -------------------------------------------------------------------------------- 1 | // The Vue build version to load with the `import` command 2 | // (runtime-only or standalone) has been set in webpack.base.conf with an alias. 3 | import Vue from 'vue' 4 | import App from './App' 5 | import router from './router' 6 | import store from './store' 7 | import iView from 'iview' 8 | import i18n from '@/locale' 9 | import config from '@/config' 10 | import importDirective from '@/directive' 11 | import { directive as clickOutside } from 'v-click-outside-x' 12 | import installPlugin from '@/plugin' 13 | import './index.less' 14 | import '@/assets/icons/iconfont.css' 15 | import TreeTable from 'tree-table-vue' 16 | import VOrgTree from 'v-org-tree' 17 | import 'v-org-tree/dist/v-org-tree.css' 18 | // 实际打包时应该不引入mock 19 | /* eslint-disable */ 20 | if (process.env.NODE_ENV !== 'production') require('@/mock') 21 | 22 | Vue.use(iView, { 23 | i18n: (key, value) => i18n.t(key, value) 24 | }) 25 | Vue.use(TreeTable) 26 | Vue.use(VOrgTree) 27 | /** 28 | * @description 注册admin内置插件 29 | */ 30 | installPlugin(Vue) 31 | /** 32 | * @description 生产环境关掉提示 33 | */ 34 | Vue.config.productionTip = false 35 | /** 36 | * @description 全局注册应用配置 37 | */ 38 | Vue.prototype.$config = config 39 | /** 40 | * 注册指令 41 | */ 42 | importDirective(Vue) 43 | Vue.directive('clickOutside', clickOutside) 44 | 45 | /* eslint-disable no-new */ 46 | new Vue({ 47 | el: '#app', 48 | router, 49 | i18n, 50 | store, 51 | render: h => h(App) 52 | }) 53 | -------------------------------------------------------------------------------- /src/mock/data.js: -------------------------------------------------------------------------------- 1 | import Mock from 'mockjs' 2 | import { doCustomTimes } from '@/libs/util' 3 | import orgData from './data/org-data' 4 | import { treeData } from './data/tree-select' 5 | const Random = Mock.Random 6 | 7 | export const getTableData = req => { 8 | let tableData = [] 9 | doCustomTimes(5, () => { 10 | tableData.push(Mock.mock({ 11 | name: '@name', 12 | email: '@email', 13 | createTime: '@date' 14 | })) 15 | }) 16 | return tableData 17 | } 18 | 19 | export const getDragList = req => { 20 | let dragList = [] 21 | doCustomTimes(5, () => { 22 | dragList.push(Mock.mock({ 23 | name: Random.csentence(10, 13), 24 | id: Random.increment(10) 25 | })) 26 | }) 27 | return dragList 28 | } 29 | 30 | export const uploadImage = req => { 31 | return Promise.resolve() 32 | } 33 | 34 | export const getOrgData = req => { 35 | return orgData 36 | } 37 | 38 | export const getTreeSelectData = req => { 39 | return treeData 40 | } 41 | -------------------------------------------------------------------------------- /src/mock/data/org-data.js: -------------------------------------------------------------------------------- 1 | export default { 2 | id: 0, 3 | label: 'XXX科技有限公司', 4 | children: [ 5 | { 6 | id: 2, 7 | label: '产品研发部', 8 | children: [ 9 | { 10 | id: 5, 11 | label: '研发-前端' 12 | }, { 13 | id: 6, 14 | label: '研发-后端' 15 | }, { 16 | id: 9, 17 | label: 'UI设计' 18 | }, { 19 | id: 10, 20 | label: '产品经理' 21 | } 22 | ] 23 | }, 24 | { 25 | id: 3, 26 | label: '销售部', 27 | children: [ 28 | { 29 | id: 7, 30 | label: '销售一部' 31 | }, { 32 | id: 8, 33 | label: '销售二部' 34 | } 35 | ] 36 | }, 37 | { 38 | id: 4, 39 | label: '财务部' 40 | }, { 41 | id: 11, 42 | label: 'HR人事' 43 | } 44 | ] 45 | } 46 | -------------------------------------------------------------------------------- /src/mock/data/tree-select.js: -------------------------------------------------------------------------------- 1 | export const treeData = [ 2 | { 3 | id: 1, 4 | title: '1', 5 | children: [ 6 | { 7 | id: 11, 8 | title: '1-1', 9 | loading: false, 10 | children: [ 11 | // { 12 | // id: 111, 13 | // title: '1-1-1' 14 | // }, 15 | // { 16 | // id: 112, 17 | // title: '1-1-2' 18 | // }, 19 | // { 20 | // id: 113, 21 | // title: '1-1-3' 22 | // }, 23 | // { 24 | // id: 114, 25 | // title: '1-1-4' 26 | // } 27 | ] 28 | }, 29 | { 30 | id: 12, 31 | title: '1-2', 32 | children: [ 33 | { 34 | id: 121, 35 | title: '1-2-1' 36 | } 37 | ] 38 | } 39 | ] 40 | } 41 | ] 42 | 43 | export const newTreeData = [ 44 | { 45 | id: 'a', 46 | title: 'a', 47 | children: [ 48 | { 49 | id: 'a1', 50 | title: 'a-1', 51 | children: [ 52 | { 53 | id: 112, 54 | title: '1-1-2' 55 | }, 56 | { 57 | id: 'a12', 58 | title: 'a-1-2' 59 | }, 60 | { 61 | id: 'a13', 62 | title: 'a-1-3' 63 | }, 64 | { 65 | id: 'a14', 66 | title: 'a-1-4' 67 | } 68 | ] 69 | }, 70 | { 71 | id: 'a2', 72 | title: 'a-2', 73 | children: [ 74 | { 75 | id: 'a21', 76 | title: 'b-2-1' 77 | } 78 | ] 79 | } 80 | ] 81 | } 82 | ] 83 | -------------------------------------------------------------------------------- /src/mock/index.js: -------------------------------------------------------------------------------- 1 | import Mock from 'mockjs' 2 | import { login, logout, getUserInfo } from './login' 3 | import { getTableData, getDragList, uploadImage, getOrgData, getTreeSelectData } from './data' 4 | import { getMessageInit, getContentByMsgId, hasRead, removeReaded, restoreTrash, messageCount } from './user' 5 | 6 | // 配置Ajax请求延时,可用来测试网络延迟大时项目中一些效果 7 | Mock.setup({ 8 | timeout: 1000 9 | }) 10 | 11 | // 登录相关和获取用户信息 12 | Mock.mock(/\/login/, login) 13 | // Mock.mock(/\/get_info/, getUserInfo) 14 | Mock.mock(/\/logout/, logout) 15 | Mock.mock(/\/get_table_data/, getTableData) 16 | Mock.mock(/\/get_drag_list/, getDragList) 17 | Mock.mock(/\/save_error_logger/, 'success') 18 | Mock.mock(/\/image\/upload/, uploadImage) 19 | Mock.mock(/\/message\/init/, getMessageInit) 20 | Mock.mock(/\/message\/content/, getContentByMsgId) 21 | Mock.mock(/\/message\/has_read/, hasRead) 22 | Mock.mock(/\/message\/remove_readed/, removeReaded) 23 | Mock.mock(/\/message\/restore/, restoreTrash) 24 | Mock.mock(/\/message\/count/, messageCount) 25 | Mock.mock(/\/get_org_data/, getOrgData) 26 | Mock.mock(/\/get_tree_select_data/, getTreeSelectData) 27 | 28 | export default Mock 29 | -------------------------------------------------------------------------------- /src/mock/login.js: -------------------------------------------------------------------------------- 1 | import { getParams } from '@/libs/util' 2 | const USER_MAP = { 3 | super_admin: { 4 | name: 'super_admin', 5 | user_id: '1', 6 | access: ['super_admin', 'admin'], 7 | token: 'super_admin', 8 | avatar: 'https://file.iviewui.com/dist/a0e88e83800f138b94d2414621bd9704.png' 9 | }, 10 | admin: { 11 | name: 'admin', 12 | user_id: '2', 13 | access: ['admin'], 14 | token: 'admin', 15 | avatar: 'https://avatars0.githubusercontent.com/u/20942571?s=460&v=4' 16 | } 17 | } 18 | 19 | export const login = req => { 20 | req = JSON.parse(req.body) 21 | return { token: USER_MAP[req.userName].token } 22 | } 23 | 24 | export const getUserInfo = req => { 25 | const params = getParams(req.url) 26 | return USER_MAP[params.token] 27 | } 28 | 29 | export const logout = req => { 30 | return null 31 | } 32 | -------------------------------------------------------------------------------- /src/mock/user.js: -------------------------------------------------------------------------------- 1 | import Mock from 'mockjs' 2 | import { doCustomTimes } from '@/libs/util' 3 | const Random = Mock.Random 4 | 5 | export const getMessageInit = () => { 6 | let unreadList = [] 7 | doCustomTimes(3, () => { 8 | unreadList.push(Mock.mock({ 9 | title: Random.cword(10, 15), 10 | create_time: '@date', 11 | msg_id: Random.increment(100) 12 | })) 13 | }) 14 | let readedList = [] 15 | doCustomTimes(4, () => { 16 | readedList.push(Mock.mock({ 17 | title: Random.cword(10, 15), 18 | create_time: '@date', 19 | msg_id: Random.increment(100) 20 | })) 21 | }) 22 | let trashList = [] 23 | doCustomTimes(2, () => { 24 | trashList.push(Mock.mock({ 25 | title: Random.cword(10, 15), 26 | create_time: '@date', 27 | msg_id: Random.increment(100) 28 | })) 29 | }) 30 | return { 31 | unread: unreadList, 32 | readed: readedList, 33 | trash: trashList 34 | } 35 | } 36 | 37 | export const getContentByMsgId = () => { 38 | return `
        这是消息内容,这个内容是使用富文本编辑器编辑的,所以你可以看到一些格式
  1. 你可以查看Mock返回的数据格式,和api请求的接口,来确定你的后端接口的开发
  2. 使用你的真实接口后,前端页面基本不需要修改即可满足基本需求
  3. 快来试试吧

${Random.csentence(100, 200)}

` 39 | } 40 | 41 | export const hasRead = () => { 42 | return true 43 | } 44 | 45 | export const removeReaded = () => { 46 | return true 47 | } 48 | 49 | export const restoreTrash = () => { 50 | return true 51 | } 52 | 53 | export const messageCount = () => { 54 | return 3 55 | } 56 | -------------------------------------------------------------------------------- /src/plugin/error-store/index.js: -------------------------------------------------------------------------------- 1 | import store from '@/store' 2 | export default { 3 | install (Vue, options) { 4 | if (options.developmentOff && process.env.NODE_ENV === 'development') return 5 | Vue.config.errorHandler = (error, vm, mes) => { 6 | let info = { 7 | type: 'script', 8 | code: 0, 9 | mes: error.message, 10 | url: window.location.href 11 | } 12 | Vue.nextTick(() => { 13 | store.dispatch('addErrorLog', info) 14 | }) 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/plugin/index.js: -------------------------------------------------------------------------------- 1 | import config from '@/config' 2 | const { plugin } = config 3 | 4 | export default (Vue) => { 5 | for (let name in plugin) { 6 | const value = plugin[name] 7 | Vue.use(require(`./${name}`).default, typeof value === 'object' ? value : undefined) 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/router/before-close.js: -------------------------------------------------------------------------------- 1 | import { Modal } from 'iview' 2 | 3 | const beforeClose = { 4 | before_close_normal: (resolve) => { 5 | Modal.confirm({ 6 | title: '确定要关闭这一页吗', 7 | onOk: () => { 8 | resolve(true) 9 | }, 10 | onCancel: () => { 11 | resolve(false) 12 | } 13 | }) 14 | } 15 | } 16 | 17 | export default beforeClose 18 | -------------------------------------------------------------------------------- /src/router/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Router from 'vue-router' 3 | import routes from './routers' 4 | import store from '@/store' 5 | import iView from 'iview' 6 | import { setToken, getToken, canTurnTo, setTitle } from '@/libs/util' 7 | import config from '@/config' 8 | const { homeName } = config 9 | 10 | const baseUrl = process.env.NODE_ENV === 'production' ? '/admin-api_demo/' : '/' // 注意区分本地和线上的环境 11 | 12 | Vue.use(Router) 13 | const router = new Router({ 14 | routes, 15 | base: baseUrl, 16 | mode: 'history' 17 | }) 18 | const LOGIN_PAGE_NAME = 'login' 19 | const REGISTER_PAGE_NAME = 'register' 20 | 21 | const turnTo = (to, access, next) => { 22 | if (canTurnTo(to.name, access, routes)) next() // 有权限,可访问 23 | else next({ replace: true, name: 'error_401' }) // 无权限,重定向到401页面 24 | } 25 | 26 | router.beforeEach((to, from, next) => { 27 | iView.LoadingBar.start() 28 | const token = getToken() 29 | console.log(token, to.name) 30 | if ((!token || token == 'undefined') && to.name == REGISTER_PAGE_NAME) { // 遗留问题:token undefined怎么变成了'undefined' 31 | next() // 跳转 32 | } else if ((!token || token == 'undefined') && to.name !== LOGIN_PAGE_NAME) { 33 | // 未登录且要跳转的页面不是登录页 34 | next({ 35 | name: LOGIN_PAGE_NAME // 跳转到登录页 36 | }) 37 | } else if ((!token || token == 'undefined') && to.name === LOGIN_PAGE_NAME) { 38 | // 未登陆且要跳转的页面是登录页 39 | next() // 跳转 40 | } else if ((token && token !== 'undefined') && to.name === LOGIN_PAGE_NAME) { 41 | // 已登录且要跳转的页面是登录页 42 | next({ 43 | name: homeName // 跳转到homeName页 44 | }) 45 | } else { 46 | if (store.state.user.hasGetInfo) { 47 | turnTo(to, store.state.user.access, next) 48 | } else { 49 | console.log('222') 50 | next() // 允许跳转 todo 增加三种身份的浏览权限限制 51 | // store.dispatch('getUserInfo').then(user => { 52 | // 拉取用户信息,通过用户权限和跳转的页面的name来判断是否有权限访问;access必须是一个数组,如:['super_admin'] ['super_admin', 'admin'] 53 | // turnTo(to, user.access, next) 54 | // }).catch(() => { 55 | // setToken('') 56 | // next({ 57 | // name: 'login' 58 | // }) 59 | // }) 60 | } 61 | } 62 | }) 63 | 64 | router.afterEach(to => { 65 | setTitle(to, router.app) 66 | iView.LoadingBar.finish() 67 | window.scrollTo(0, 0) 68 | }) 69 | 70 | export default router 71 | -------------------------------------------------------------------------------- /src/store/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Vuex from 'vuex' 3 | 4 | import user from './module/user' 5 | import app from './module/app' 6 | 7 | Vue.use(Vuex) 8 | 9 | export default new Vuex.Store({ 10 | state: { 11 | // 12 | }, 13 | mutations: { 14 | // 15 | }, 16 | actions: { 17 | // 18 | }, 19 | modules: { 20 | user, 21 | app 22 | } 23 | }) 24 | -------------------------------------------------------------------------------- /src/store/module/app.js: -------------------------------------------------------------------------------- 1 | import { 2 | getBreadCrumbList, 3 | setTagNavListInLocalstorage, 4 | getMenuByRouter, 5 | getTagNavListFromLocalstorage, 6 | getHomeRoute, 7 | getNextRoute, 8 | routeHasExist, 9 | routeEqual, 10 | getRouteTitleHandled, 11 | localSave, 12 | localRead 13 | } from '@/libs/util' 14 | import { saveErrorLogger } from '@/api/data' 15 | import router from '@/router' 16 | import routers from '@/router/routers' 17 | import config from '@/config' 18 | const { homeName } = config 19 | 20 | const closePage = (state, route) => { 21 | const nextRoute = getNextRoute(state.tagNavList, route) 22 | state.tagNavList = state.tagNavList.filter(item => { 23 | return !routeEqual(item, route) 24 | }) 25 | router.push(nextRoute) 26 | } 27 | 28 | export default { 29 | state: { 30 | breadCrumbList: [], 31 | tagNavList: [], 32 | homeRoute: {}, 33 | local: localRead('local'), 34 | errorList: [], 35 | hasReadErrorPage: false 36 | }, 37 | getters: { 38 | menuList: (state, getters, rootState) => getMenuByRouter(routers, rootState.user.access), 39 | errorCount: state => state.errorList.length 40 | }, 41 | mutations: { 42 | setBreadCrumb (state, route) { 43 | state.breadCrumbList = getBreadCrumbList(route, state.homeRoute) 44 | }, 45 | setHomeRoute (state, routes) { 46 | state.homeRoute = getHomeRoute(routes, homeName) 47 | }, 48 | setTagNavList (state, list) { 49 | let tagList = [] 50 | if (list) { 51 | tagList = [...list] 52 | } else tagList = getTagNavListFromLocalstorage() || [] 53 | if (tagList[0] && tagList[0].name !== homeName) tagList.shift() 54 | let homeTagIndex = tagList.findIndex(item => item.name === homeName) 55 | if (homeTagIndex > 0) { 56 | let homeTag = tagList.splice(homeTagIndex, 1)[0] 57 | tagList.unshift(homeTag) 58 | } 59 | state.tagNavList = tagList 60 | setTagNavListInLocalstorage([...tagList]) 61 | }, 62 | closeTag (state, route) { 63 | let tag = state.tagNavList.filter(item => routeEqual(item, route)) 64 | route = tag[0] ? tag[0] : null 65 | if (!route) return 66 | closePage(state, route) 67 | }, 68 | addTag (state, { route, type = 'unshift' }) { 69 | let router = getRouteTitleHandled(route) 70 | if (!routeHasExist(state.tagNavList, router)) { 71 | if (type === 'push') state.tagNavList.push(router) 72 | else { 73 | if (router.name === homeName) state.tagNavList.unshift(router) 74 | else state.tagNavList.splice(1, 0, router) 75 | } 76 | setTagNavListInLocalstorage([...state.tagNavList]) 77 | } 78 | }, 79 | setLocal (state, lang) { 80 | localSave('local', lang) 81 | state.local = lang 82 | }, 83 | addError (state, error) { 84 | state.errorList.push(error) 85 | }, 86 | setHasReadErrorLoggerStatus (state, status = true) { 87 | state.hasReadErrorPage = status 88 | } 89 | }, 90 | actions: { 91 | addErrorLog ({ commit, rootState }, info) { 92 | if (!window.location.href.includes('error_logger_page')) commit('setHasReadErrorLoggerStatus', false) 93 | const { user: { token, userId, userName } } = rootState 94 | let data = { 95 | ...info, 96 | time: Date.parse(new Date()), 97 | token, 98 | userId, 99 | userName 100 | } 101 | saveErrorLogger(info).then(() => { 102 | commit('addError', data) 103 | }) 104 | } 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /src/view/argu-page/params.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 33 | 34 | 37 | -------------------------------------------------------------------------------- /src/view/argu-page/query.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 33 | 34 | 37 | -------------------------------------------------------------------------------- /src/view/article-lib/article-add/index.vue: -------------------------------------------------------------------------------- 1 | 21 | 22 | 66 | 67 | 107 | -------------------------------------------------------------------------------- /src/view/article-lib/article-review/index.vue: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/view/article-lib/upload-csv/index.vue: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/view/assets-lib/assets-upload/index.vue: -------------------------------------------------------------------------------- 1 | 8 | 21 | 22 | 66 | 67 | 72 | -------------------------------------------------------------------------------- /src/view/components/cropper/cropper.vue: -------------------------------------------------------------------------------- 1 | 18 | 19 | 43 | 44 | 49 | -------------------------------------------------------------------------------- /src/view/components/drag-drawer/index.vue: -------------------------------------------------------------------------------- 1 | 55 | 56 | 88 | 89 | 98 | -------------------------------------------------------------------------------- /src/view/components/drag-list/drag-list.vue: -------------------------------------------------------------------------------- 1 | 30 | 62 | 114 | -------------------------------------------------------------------------------- /src/view/components/editor/editor.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 30 | 31 | 34 | -------------------------------------------------------------------------------- /src/view/components/icons/icons.vue: -------------------------------------------------------------------------------- 1 | 31 | 32 | 55 | 56 | 64 | -------------------------------------------------------------------------------- /src/view/components/markdown/markdown.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 21 | 22 | 25 | -------------------------------------------------------------------------------- /src/view/components/org-tree/components/zoom-controller.vue: -------------------------------------------------------------------------------- 1 | 12 | 13 | 48 | 49 | 82 | -------------------------------------------------------------------------------- /src/view/components/org-tree/index.less: -------------------------------------------------------------------------------- 1 | @wrapper: ~'department'; 2 | .percent-100 { 3 | width: 100%; 4 | height: 100%; 5 | } 6 | .@{wrapper}-outer { 7 | .percent-100; 8 | overflow: hidden; 9 | .tip-box{ 10 | position: absolute; 11 | left: 20px; 12 | top: 20px; 13 | z-index: 12; 14 | } 15 | .zoom-box { 16 | position: absolute; 17 | right: 30px; 18 | bottom: 30px; 19 | z-index: 2; 20 | } 21 | .view-box { 22 | position: absolute; 23 | top: 0; 24 | bottom: 0; 25 | left: 0; 26 | right: 0; 27 | z-index: 1; 28 | cursor: move; 29 | .org-tree-drag-wrapper { 30 | width: 100%; 31 | height: 100%; 32 | } 33 | .org-tree-wrapper { 34 | display: inline-block; 35 | position: absolute; 36 | left: 50%; 37 | top: 50%; 38 | transition: transform 0.2s ease-out; 39 | .org-tree-node-label { 40 | box-shadow: 0px 2px 12px 0px rgba(143, 154, 165, 0.4); 41 | border-radius: 4px; 42 | .org-tree-node-label-inner { 43 | padding: 0; 44 | .custom-org-node { 45 | padding: 14px 41px; 46 | background: #738699; 47 | user-select: none; 48 | word-wrap: none; 49 | white-space: nowrap; 50 | border-radius: 4px; 51 | color: #ffffff; 52 | font-size: 14px; 53 | font-weight: 500; 54 | line-height: 20px; 55 | transition: background 0.1s ease-in; 56 | cursor: default; 57 | &:hover { 58 | background: #5d6c7b; 59 | transition: background 0.1s ease-in; 60 | } 61 | &.has-children-label { 62 | cursor: pointer; 63 | } 64 | .context-menu{ 65 | position: absolute; 66 | right: -10px; 67 | bottom: 20px; 68 | z-index: 10; 69 | } 70 | } 71 | } 72 | } 73 | } 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/view/components/org-tree/index.vue: -------------------------------------------------------------------------------- 1 | 22 | 23 | 74 | 75 | 77 | -------------------------------------------------------------------------------- /src/view/components/split-pane/split-pane.vue: -------------------------------------------------------------------------------- 1 | 17 | 18 | 40 | 41 | 80 | -------------------------------------------------------------------------------- /src/view/components/tables/tables.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 68 | 69 | 72 | -------------------------------------------------------------------------------- /src/view/components/tree-select/index.vue: -------------------------------------------------------------------------------- 1 | 19 | 20 | 87 | 88 | 91 | -------------------------------------------------------------------------------- /src/view/directive/directive.vue: -------------------------------------------------------------------------------- 1 | 68 | 69 | 108 | 109 | 122 | -------------------------------------------------------------------------------- /src/view/error-page/401.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 20 | -------------------------------------------------------------------------------- /src/view/error-page/404.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 20 | -------------------------------------------------------------------------------- /src/view/error-page/500.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 20 | -------------------------------------------------------------------------------- /src/view/error-page/back-btn-group.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 39 | -------------------------------------------------------------------------------- /src/view/error-page/error-content.vue: -------------------------------------------------------------------------------- 1 | 13 | 14 | 29 | -------------------------------------------------------------------------------- /src/view/error-page/error.less: -------------------------------------------------------------------------------- 1 | .error-page{ 2 | width: 100%; 3 | height: 100%; 4 | position: relative; 5 | background: #f8f8f9; 6 | .content-con{ 7 | width: 700px; 8 | height: 600px; 9 | position: absolute; 10 | left: 50%; 11 | top: 50%; 12 | transform: translate(-50%, -60%); 13 | img{ 14 | display: block; 15 | width: 100%; 16 | height: 100%; 17 | } 18 | .text-con{ 19 | position: absolute; 20 | left: 0px; 21 | top: 0px; 22 | h4{ 23 | position: absolute; 24 | left: 0px; 25 | top: 0px; 26 | font-size: 80px; 27 | font-weight: 700; 28 | color: #348EED; 29 | } 30 | h5{ 31 | position: absolute; 32 | width: 700px; 33 | left: 0px; 34 | top: 100px; 35 | font-size: 20px; 36 | font-weight: 700; 37 | color: #67647D; 38 | } 39 | } 40 | .back-btn-group{ 41 | position: absolute; 42 | right: 0px; 43 | bottom: 20px; 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/view/error-store/error-store.vue: -------------------------------------------------------------------------------- 1 | 21 | 22 | 36 | 37 | 40 | -------------------------------------------------------------------------------- /src/view/excel/common.less: -------------------------------------------------------------------------------- 1 | .margin-top-8{ 2 | margin-top: 8px; 3 | } 4 | .margin-top-10{ 5 | margin-top: 10px; 6 | } 7 | .margin-top-20{ 8 | margin-top: 20px; 9 | } 10 | .margin-left-10{ 11 | margin-left: 10px; 12 | } 13 | .margin-bottom-10{ 14 | margin-bottom: 10px; 15 | } 16 | .margin-bottom-100{ 17 | margin-bottom: 100px; 18 | } 19 | .margin-right-10{ 20 | margin-right: 10px; 21 | } 22 | .padding-left-6{ 23 | padding-left: 6px; 24 | } 25 | .padding-left-8{ 26 | padding-left: 5px; 27 | } 28 | .padding-left-10{ 29 | padding-left: 10px; 30 | } 31 | .padding-left-20{ 32 | padding-left: 20px; 33 | } 34 | .height-100{ 35 | height: 100%; 36 | } 37 | .height-120px{ 38 | height: 100px; 39 | } 40 | .height-200px{ 41 | height: 200px; 42 | } 43 | .height-492px{ 44 | height: 492px; 45 | } 46 | .height-460px{ 47 | height: 460px; 48 | } 49 | .line-gray{ 50 | height: 0; 51 | border-bottom: 2px solid #dcdcdc; 52 | } 53 | .notwrap{ 54 | word-break:keep-all; 55 | white-space:nowrap; 56 | overflow: hidden; 57 | text-overflow: ellipsis; 58 | } 59 | .padding-left-5{ 60 | padding-left: 10px; 61 | } 62 | [v-cloak]{ 63 | display: none; 64 | } -------------------------------------------------------------------------------- /src/view/excel/export-excel.vue: -------------------------------------------------------------------------------- 1 | 4 | 16 | 82 | -------------------------------------------------------------------------------- /src/view/excel/upload-excel.vue: -------------------------------------------------------------------------------- 1 | 4 | 35 | 115 | -------------------------------------------------------------------------------- /src/view/i18n/i18n-page.vue: -------------------------------------------------------------------------------- 1 | 24 | 25 | 40 | 41 | 51 | -------------------------------------------------------------------------------- /src/view/join-page.vue: -------------------------------------------------------------------------------- 1 | 18 | 19 | 28 | 47 | -------------------------------------------------------------------------------- /src/view/login/login.less: -------------------------------------------------------------------------------- 1 | .login{ 2 | width: 100%; 3 | height: 100%; 4 | background-image: url('../../assets/images/login-bg.jpg'); 5 | background-size: cover; 6 | background-position: center; 7 | position: relative; 8 | &-title { 9 | font-size: 36px; 10 | color: #fff; 11 | text-align: center; 12 | margin: 15px; 13 | border-bottom: rgb(212, 212, 212) solid 1px; 14 | height: 60px; 15 | } 16 | &-con{ 17 | position: absolute; 18 | right: 50%; 19 | top: 45%; 20 | transform: translate(50%,-55%); 21 | width: 450px; 22 | &-header{ 23 | font-size: 16px; 24 | font-weight: 300; 25 | text-align: center; 26 | padding: 30px 20px; 27 | } 28 | .form-con{ 29 | padding: 10px 0 0; 30 | } 31 | .login-tip{ 32 | font-size: 10px; 33 | text-align: center; 34 | color: #c3c3c3; 35 | } 36 | .ivu-card-body { 37 | padding: 16px 25px; 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/view/login/login.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 18 | 19 | 46 | 47 | 50 | -------------------------------------------------------------------------------- /src/view/multilevel/level-2-1.vue: -------------------------------------------------------------------------------- 1 | 4 | 9 | -------------------------------------------------------------------------------- /src/view/multilevel/level-2-2/level-2-2-1.vue: -------------------------------------------------------------------------------- 1 | 7 | 17 | -------------------------------------------------------------------------------- /src/view/multilevel/level-2-2/level-2-2-2.vue: -------------------------------------------------------------------------------- 1 | 7 | 17 | -------------------------------------------------------------------------------- /src/view/multilevel/level-2-3.vue: -------------------------------------------------------------------------------- 1 | 4 | 9 | -------------------------------------------------------------------------------- /src/view/register/register.less: -------------------------------------------------------------------------------- 1 | .login{ 2 | width: 100%; 3 | height: 100%; 4 | background-image: url('../../assets/images/login-bg.jpg'); 5 | background-size: cover; 6 | background-position: center; 7 | position: relative; 8 | &-title { 9 | font-size: 36px; 10 | color: #fff; 11 | text-align: center; 12 | margin: 20px; 13 | border-bottom: rgb(212, 212, 212) solid 1px; 14 | } 15 | &-con{ 16 | position: absolute; 17 | right: 50%; 18 | top: 45%; 19 | transform: translate(50%,-55%); 20 | width: 450px; 21 | &-header{ 22 | font-size: 16px; 23 | font-weight: 300; 24 | text-align: center; 25 | padding: 30px 20px; 26 | } 27 | .form-con{ 28 | padding: 10px 0 0; 29 | } 30 | .login-tip{ 31 | font-size: 10px; 32 | text-align: center; 33 | color: #c3c3c3; 34 | } 35 | .ivu-card-body { 36 | padding: 16px 40px; 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/view/register/register.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 18 | 19 | 48 | 49 | 52 | -------------------------------------------------------------------------------- /src/view/single-page/error-logger.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 88 | 89 | 92 | -------------------------------------------------------------------------------- /src/view/single-page/home/example.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 115 | -------------------------------------------------------------------------------- /src/view/single-page/home/home.vue: -------------------------------------------------------------------------------- 1 | 30 | 31 | 78 | 79 | 84 | -------------------------------------------------------------------------------- /src/view/single-page/home/index.js: -------------------------------------------------------------------------------- 1 | import home from './home.vue' 2 | export default home 3 | -------------------------------------------------------------------------------- /src/view/tools-methods/tools-methods.vue: -------------------------------------------------------------------------------- 1 | 35 | 36 | 78 | 79 | 82 | -------------------------------------------------------------------------------- /src/view/update/update-paste.vue: -------------------------------------------------------------------------------- 1 | 21 | 22 | 62 | 63 | 78 | -------------------------------------------------------------------------------- /src/view/update/update-table.vue: -------------------------------------------------------------------------------- 1 | 25 | 26 | 53 | 54 | 62 | -------------------------------------------------------------------------------- /tests/e2e/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": [ 3 | "cypress" 4 | ], 5 | "env": { 6 | "mocha": true, 7 | "cypress/globals": true 8 | }, 9 | "rules": { 10 | "strict": "off" 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /tests/e2e/plugins/index.js: -------------------------------------------------------------------------------- 1 | // https://docs.cypress.io/guides/guides/plugins-guide.html 2 | 3 | module.exports = (on, config) => Object.assign({}, config, { 4 | fixturesFolder: 'tests/e2e/fixtures', 5 | integrationFolder: 'tests/e2e/specs', 6 | screenshotsFolder: 'tests/e2e/screenshots', 7 | videosFolder: 'tests/e2e/videos', 8 | supportFile: 'tests/e2e/support/index.js' 9 | }) 10 | -------------------------------------------------------------------------------- /tests/e2e/specs/test.js: -------------------------------------------------------------------------------- 1 | // https://docs.cypress.io/api/introduction/api.html 2 | 3 | describe('My First Test', () => { 4 | it('Visits the app root url', () => { 5 | cy.visit('/') 6 | cy.contains('h1', 'Welcome to Your Vue.js App') 7 | }) 8 | }) 9 | -------------------------------------------------------------------------------- /tests/e2e/support/commands.js: -------------------------------------------------------------------------------- 1 | // *********************************************** 2 | // This example commands.js shows you how to 3 | // create various custom commands and overwrite 4 | // existing commands. 5 | // 6 | // For more comprehensive examples of custom 7 | // commands please read more here: 8 | // https://on.cypress.io/custom-commands 9 | // *********************************************** 10 | // 11 | // 12 | // -- This is a parent command -- 13 | // Cypress.Commands.add("login", (email, password) => { ... }) 14 | // 15 | // 16 | // -- This is a child command -- 17 | // Cypress.Commands.add("drag", { prevSubject: 'element'}, (subject, options) => { ... }) 18 | // 19 | // 20 | // -- This is a dual command -- 21 | // Cypress.Commands.add("dismiss", { prevSubject: 'optional'}, (subject, options) => { ... }) 22 | // 23 | // 24 | // -- This is will overwrite an existing command -- 25 | // Cypress.Commands.overwrite("visit", (originalFn, url, options) => { ... }) 26 | -------------------------------------------------------------------------------- /tests/e2e/support/index.js: -------------------------------------------------------------------------------- 1 | // *********************************************************** 2 | // This example support/index.js is processed and 3 | // loaded automatically before your test files. 4 | // 5 | // This is a great place to put global configuration and 6 | // behavior that modifies Cypress. 7 | // 8 | // You can change the location of this file or turn off 9 | // automatically serving support files with the 10 | // 'supportFile' configuration option. 11 | // 12 | // You can read more here: 13 | // https://on.cypress.io/configuration 14 | // *********************************************************** 15 | 16 | // Import commands.js using ES2015 syntax: 17 | import './commands' 18 | 19 | // Alternatively you can use CommonJS syntax: 20 | // require('./commands') 21 | -------------------------------------------------------------------------------- /tests/unit/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | env: { 3 | mocha: true 4 | }, 5 | rules: { 6 | 'import/no-extraneous-dependencies': 'off' 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /tests/unit/HelloWorld.spec.js: -------------------------------------------------------------------------------- 1 | import { expect } from 'chai' 2 | import { shallow } from '@vue/test-utils' 3 | import HelloWorld from '@/components/HelloWorld.vue' 4 | 5 | describe('HelloWorld.vue', () => { 6 | it('renders props.msg when passed', () => { 7 | const msg = 'new message' 8 | const wrapper = shallow(HelloWorld, { 9 | propsData: { msg } 10 | }) 11 | expect(wrapper.text()).to.include(msg) 12 | }) 13 | }) 14 | -------------------------------------------------------------------------------- /vue.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | 3 | const resolve = dir => { 4 | return path.join(__dirname, dir) 5 | } 6 | 7 | // 项目部署基础 8 | // 默认情况下,我们假设你的应用将被部署在域的根目录下, 9 | // 例如:https://www.my-app.com/ 10 | // 默认:'/' 11 | // 如果您的应用程序部署在子路径中,则需要在这指定子路径 12 | // 例如:https://www.foobar.com/my-app/ 13 | // 需要将它改为'/my-app/' 14 | // iview-admin线上演示打包路径: https://file.iviewui.com/admin-dist/ 15 | const BASE_URL = process.env.NODE_ENV === 'production' 16 | ? '/admin-api_demo/' // 线上的托管环境的根目录,最终正式的访问链接是 http://open.yesapi.cn/admin-你的果创云登录账号/ 17 | : '/' // 本地根目录 18 | 19 | module.exports = { 20 | // Project deployment base 21 | // By default we assume your app will be deployed at the root of a domain, 22 | // e.g. https://www.my-app.com/ 23 | // If your app is deployed at a sub-path, you will need to specify that 24 | // sub-path here. For example, if your app is deployed at 25 | // https://www.foobar.com/my-app/ 26 | // then change this to '/my-app/' 27 | publicPath: BASE_URL, 28 | // tweak internal webpack configuration. 29 | // see https://github.com/vuejs/vue-cli/blob/dev/docs/webpack.md 30 | // 如果你不需要使用eslint,把lintOnSave设为false即可 31 | lintOnSave: true, 32 | chainWebpack: config => { 33 | config.resolve.alias 34 | .set('@', resolve('src')) // key,value自行定义,比如.set('@@', resolve('src/components')) 35 | .set('_c', resolve('src/components')) 36 | }, 37 | // 设为false打包时不生成.map文件 38 | productionSourceMap: false 39 | // 这里写你调用接口的基础路径,来解决跨域,如果设置了代理,那你本地开发环境的axios的baseUrl要写为 '' ,即空字符串 40 | // devServer: { 41 | // proxy: 'localhost:3000' 42 | // } 43 | } 44 | --------------------------------------------------------------------------------