├── static ├── .gitkeep ├── favicon.ico └── tinymce │ ├── skins │ └── lightgray │ │ ├── img │ │ ├── trans.gif │ │ ├── anchor.gif │ │ ├── loader.gif │ │ └── object.gif │ │ ├── fonts │ │ ├── tinymce.eot │ │ ├── tinymce.ttf │ │ ├── tinymce.woff │ │ ├── tinymce-small.eot │ │ ├── tinymce-small.ttf │ │ ├── tinymce-mobile.woff │ │ └── tinymce-small.woff │ │ ├── content.mobile.min.css │ │ ├── content.inline.min.css │ │ └── content.min.css │ └── zh_CN.js ├── .eslintignore ├── favicon.ico ├── src ├── styles │ ├── variables.scss │ ├── mixin.scss │ ├── element-ui.scss │ ├── transition.scss │ ├── index.scss │ └── sidebar.scss ├── assets │ └── 404_images │ │ ├── 404.png │ │ └── 404_cloud.png ├── views │ ├── layout │ │ ├── components │ │ │ ├── index.js │ │ │ ├── Sidebar │ │ │ │ ├── Item.vue │ │ │ │ ├── Link.vue │ │ │ │ ├── index.vue │ │ │ │ └── SidebarItem.vue │ │ │ ├── AppMain.vue │ │ │ ├── Navbar.vue │ │ │ └── TagsView.vue │ │ ├── mixin │ │ │ └── ResizeHandler.js │ │ └── Layout.vue │ ├── redirect.vue │ ├── dashboard │ │ └── index.vue │ ├── myviews │ │ ├── tinymce_demo.vue │ │ ├── printdemo.vue │ │ └── demoadmin.vue │ ├── 404.vue │ ├── userinfo │ │ └── index.vue │ ├── login │ │ └── index.vue │ └── system │ │ └── user.vue ├── icons │ ├── svg │ │ ├── link.svg │ │ ├── user.svg │ │ ├── example.svg │ │ ├── table.svg │ │ ├── password.svg │ │ ├── nested.svg │ │ ├── eye.svg │ │ ├── eye_show.svg │ │ ├── code.svg │ │ ├── tree.svg │ │ ├── dashboard.svg │ │ └── form.svg │ ├── index.js │ └── svgo.yml ├── utils │ ├── auth.js │ ├── routerStr.js │ ├── validate.js │ ├── index.js │ ├── directives.js │ ├── generateCode.js │ └── request.js ├── store │ ├── index.js │ ├── getters.js │ └── modules │ │ ├── app.js │ │ ├── user.js │ │ └── tagsView.js ├── api │ ├── login.js │ ├── export.js │ └── myapi.js ├── main.js ├── components │ ├── SvgIcon │ │ └── index.vue │ ├── SearchField │ │ ├── index.vue │ │ └── index2.vue │ ├── ScrollPane │ │ └── index.vue │ ├── Breadcrumb │ │ └── index.vue │ ├── Hamburger │ │ └── index.vue │ ├── Pagination │ │ └── index.vue │ ├── Upload │ │ ├── singleImage.vue │ │ ├── singleFile.vue │ │ ├── multiImage.vue │ │ ├── cropperImage.vue │ │ └── mulImage.vue │ ├── MiniPagination │ │ └── index.vue │ ├── Tinymce │ │ └── index.vue │ ├── IdentifyCode │ │ └── index.vue │ └── DataSelect │ │ └── index.vue ├── App.vue ├── permission.js └── router │ └── index.js ├── .travis.yml ├── config ├── prod.env.js ├── dev.env.js ├── export.js └── index.js ├── .gitignore ├── .babelrc ├── .postcssrc.js ├── push.sh ├── .editorconfig ├── index.html ├── README.md ├── LICENSE ├── package.json └── .eslintrc.js /static/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | build/*.js 2 | config/*.js 3 | src/assets 4 | -------------------------------------------------------------------------------- /favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aeasringnar/vue-element-admin/HEAD/favicon.ico -------------------------------------------------------------------------------- /static/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aeasringnar/vue-element-admin/HEAD/static/favicon.ico -------------------------------------------------------------------------------- /src/styles/variables.scss: -------------------------------------------------------------------------------- 1 | //sidebar 2 | $menuBg:#304156; 3 | $subMenuBg:#1f2d3d; 4 | $menuHover:#001528; 5 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: stable 3 | script: npm run test 4 | notifications: 5 | email: false 6 | -------------------------------------------------------------------------------- /src/assets/404_images/404.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aeasringnar/vue-element-admin/HEAD/src/assets/404_images/404.png -------------------------------------------------------------------------------- /config/prod.env.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | module.exports = { 3 | NODE_ENV: '"production"', 4 | BASE_API: '"https://api.line.com"', 5 | } 6 | -------------------------------------------------------------------------------- /src/assets/404_images/404_cloud.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aeasringnar/vue-element-admin/HEAD/src/assets/404_images/404_cloud.png -------------------------------------------------------------------------------- /static/tinymce/skins/lightgray/img/trans.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aeasringnar/vue-element-admin/HEAD/static/tinymce/skins/lightgray/img/trans.gif -------------------------------------------------------------------------------- /static/tinymce/skins/lightgray/img/anchor.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aeasringnar/vue-element-admin/HEAD/static/tinymce/skins/lightgray/img/anchor.gif -------------------------------------------------------------------------------- /static/tinymce/skins/lightgray/img/loader.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aeasringnar/vue-element-admin/HEAD/static/tinymce/skins/lightgray/img/loader.gif -------------------------------------------------------------------------------- /static/tinymce/skins/lightgray/img/object.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aeasringnar/vue-element-admin/HEAD/static/tinymce/skins/lightgray/img/object.gif -------------------------------------------------------------------------------- /static/tinymce/skins/lightgray/fonts/tinymce.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aeasringnar/vue-element-admin/HEAD/static/tinymce/skins/lightgray/fonts/tinymce.eot -------------------------------------------------------------------------------- /static/tinymce/skins/lightgray/fonts/tinymce.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aeasringnar/vue-element-admin/HEAD/static/tinymce/skins/lightgray/fonts/tinymce.ttf -------------------------------------------------------------------------------- /static/tinymce/skins/lightgray/fonts/tinymce.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aeasringnar/vue-element-admin/HEAD/static/tinymce/skins/lightgray/fonts/tinymce.woff -------------------------------------------------------------------------------- /static/tinymce/skins/lightgray/fonts/tinymce-small.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aeasringnar/vue-element-admin/HEAD/static/tinymce/skins/lightgray/fonts/tinymce-small.eot -------------------------------------------------------------------------------- /static/tinymce/skins/lightgray/fonts/tinymce-small.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aeasringnar/vue-element-admin/HEAD/static/tinymce/skins/lightgray/fonts/tinymce-small.ttf -------------------------------------------------------------------------------- /static/tinymce/skins/lightgray/fonts/tinymce-mobile.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aeasringnar/vue-element-admin/HEAD/static/tinymce/skins/lightgray/fonts/tinymce-mobile.woff -------------------------------------------------------------------------------- /static/tinymce/skins/lightgray/fonts/tinymce-small.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aeasringnar/vue-element-admin/HEAD/static/tinymce/skins/lightgray/fonts/tinymce-small.woff -------------------------------------------------------------------------------- /src/views/layout/components/index.js: -------------------------------------------------------------------------------- 1 | export { default as Navbar } from './Navbar' 2 | export { default as Sidebar } from './Sidebar' 3 | export { default as AppMain } from './AppMain' 4 | export { default as TagsView } from './TagsView' 5 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules/ 3 | dist/ 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | package-lock.json 8 | 9 | # Editor directories and files 10 | .idea 11 | .vscode 12 | *.suo 13 | *.ntvs* 14 | *.njsproj 15 | *.sln 16 | -------------------------------------------------------------------------------- /static/tinymce/skins/lightgray/content.mobile.min.css: -------------------------------------------------------------------------------- 1 | .tinymce-mobile-unfocused-selections .tinymce-mobile-unfocused-selection{position:absolute;display:inline-block;background-color:green;opacity:.5}body{-webkit-text-size-adjust:none}body img{max-width:96vw}body table img{max-width:95%} -------------------------------------------------------------------------------- /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | ["env", { 4 | "modules": false, 5 | "targets": { 6 | "browsers": ["> 1%", "last 2 versions", "not ie <= 8"] 7 | } 8 | }], 9 | "stage-2" 10 | ], 11 | "plugins":["transform-vue-jsx", "transform-runtime"] 12 | } 13 | -------------------------------------------------------------------------------- /config/dev.env.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const merge = require('webpack-merge') 3 | const prodEnv = require('./prod.env') 4 | 5 | module.exports = merge(prodEnv, { 6 | NODE_ENV: '"development"', 7 | BASE_API: '"http://127.0.0.1:9000"', 8 | // BASE_API: '"https://btapi.ibeatop.com"', 9 | }) 10 | -------------------------------------------------------------------------------- /.postcssrc.js: -------------------------------------------------------------------------------- 1 | // https://github.com/michael-ciniawsky/postcss-load-config 2 | 3 | module.exports = { 4 | "plugins": { 5 | "postcss-import": {}, 6 | "postcss-url": {}, 7 | // to edit target browsers: use "browserslist" field in package.json 8 | "autoprefixer": {} 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /push.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | proj_dir="demo" 3 | server="127.0.0.1" 4 | npm run build 5 | ssh root@${server} "[[ ! -d /var/www/${proj_dir}/ ]] && mkdir -p /var/www/${proj_dir}/" 6 | ssh root@${server} "[[ -d /var/www/${proj_dir}/ ]] && rm -rf /var/www/${proj_dir}/*" 7 | scp -r dist/* root@${server}:/var/www/${proj_dir}/ -------------------------------------------------------------------------------- /src/icons/svg/link.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | indent_style = space 7 | indent_size = 2 8 | end_of_line = lf 9 | insert_final_newline = true 10 | trim_trailing_whitespace = true 11 | 12 | [*.md] 13 | insert_final_newline = false 14 | trim_trailing_whitespace = false 15 | -------------------------------------------------------------------------------- /src/views/redirect.vue: -------------------------------------------------------------------------------- 1 | 13 | -------------------------------------------------------------------------------- /src/icons/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import SvgIcon from '@/components/SvgIcon' // svg组件 3 | 4 | // register globally 5 | Vue.component('svg-icon', SvgIcon) 6 | 7 | const requireAll = requireContext => requireContext.keys().map(requireContext) 8 | const req = require.context('./svg', false, /\.svg$/) 9 | requireAll(req) 10 | -------------------------------------------------------------------------------- /src/icons/svgo.yml: -------------------------------------------------------------------------------- 1 | # replace default config 2 | 3 | # multipass: true 4 | # full: true 5 | 6 | plugins: 7 | 8 | # - name 9 | # 10 | # or: 11 | # - name: false 12 | # - name: true 13 | # 14 | # or: 15 | # - name: 16 | # param1: 1 17 | # param2: 2 18 | 19 | - removeAttrs: 20 | attrs: 21 | - 'fill' 22 | - 'fill-rule' 23 | -------------------------------------------------------------------------------- /src/utils/auth.js: -------------------------------------------------------------------------------- 1 | import Cookies from 'js-cookie' 2 | 3 | const TokenKey = 'Aeas-Manage-Token' 4 | 5 | export function getToken() { 6 | return localStorage.getItem(TokenKey) 7 | } 8 | 9 | export function setToken(token) { 10 | return localStorage.setItem(TokenKey, token) 11 | } 12 | 13 | export function removeToken() { 14 | return localStorage.removeItem(TokenKey) 15 | } 16 | -------------------------------------------------------------------------------- /src/store/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Vuex from 'vuex' 3 | import app from './modules/app' 4 | import user from './modules/user' 5 | import getters from './getters' 6 | import tagsView from './modules/tagsView' 7 | 8 | Vue.use(Vuex) 9 | 10 | const store = new Vuex.Store({ 11 | modules: { 12 | app, 13 | user, 14 | tagsView 15 | }, 16 | getters 17 | }) 18 | 19 | export default store 20 | -------------------------------------------------------------------------------- /src/icons/svg/user.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/api/login.js: -------------------------------------------------------------------------------- 1 | import request from '@/utils/request' 2 | 3 | export function login(data) { 4 | return request({ 5 | url: '/adminlogin/', 6 | method: 'post', 7 | data: data 8 | }) 9 | } 10 | 11 | export function getInfo() { 12 | return request({ 13 | url: '/userinfo/', 14 | method: 'get' 15 | }) 16 | } 17 | 18 | export function logout() { 19 | return request({ 20 | url: '/logout/', 21 | method: 'post' 22 | }) 23 | } 24 | -------------------------------------------------------------------------------- /src/store/getters.js: -------------------------------------------------------------------------------- 1 | const getters = { 2 | sidebar: state => state.app.sidebar, 3 | device: state => state.app.device, 4 | token: state => state.user.token, 5 | avatar: state => state.user.avatar, 6 | name: state => state.user.name, 7 | roles: state => state.user.roles, 8 | auth_json: state => state.user.auth_json, 9 | user_obj: state => state.user.user_obj, 10 | visitedViews: state => state.tagsView.visitedViews 11 | } 12 | export default getters 13 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | AEAS'S Admin 10 | 11 | 12 |
13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /src/icons/svg/example.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # vue-element-admin 2 | 3 | 这是一个 基于 Vue 2.X + element-UI的后台管理项目模板,用于快速构建企业级高性能的后台管理系统。 4 | 5 | ## 技术栈 6 | 7 | - **框架选择**:基于 Vue2.X + element-UI 8 | - **框架特色**:Vue全家桶 vue + vue-cli + vue-router + vuex + axios 9 | - **授权验证**:基于 JWT 10 | - **内置功能**:通用组件、文件下载、动态权限、代码生成、Demo实例等 11 | 12 | ## 快速入门 13 | 14 | 如需进一步了解,参见 [Vue 文档](https://cn.vuejs.org)。 15 | 16 | ### 本地开发 17 | 18 | ```bash 19 | $ npm install 20 | $ npm run dev 21 | ``` 22 | 23 | ### 部署 24 | 25 | ```bash 26 | $ npm run build 27 | ``` 28 | 29 | -------------------------------------------------------------------------------- /src/styles/mixin.scss: -------------------------------------------------------------------------------- 1 | @mixin clearfix { 2 | &:after { 3 | content: ""; 4 | display: table; 5 | clear: both; 6 | } 7 | } 8 | 9 | @mixin scrollBar { 10 | &::-webkit-scrollbar-track-piece { 11 | background: #d3dce6; 12 | } 13 | &::-webkit-scrollbar { 14 | width: 6px; 15 | } 16 | &::-webkit-scrollbar-thumb { 17 | background: #99a9bf; 18 | border-radius: 20px; 19 | } 20 | } 21 | 22 | @mixin relative { 23 | position: relative; 24 | width: 100%; 25 | height: 100%; 26 | } 27 | 28 | -------------------------------------------------------------------------------- /src/styles/element-ui.scss: -------------------------------------------------------------------------------- 1 | //to reset element-ui default css 2 | .el-upload { 3 | input[type="file"] { 4 | display: none !important; 5 | } 6 | } 7 | 8 | .el-upload__input { 9 | display: none; 10 | } 11 | 12 | //暂时性解决diolag 问题 https://github.com/ElemeFE/element/issues/2461 13 | .el-dialog { 14 | transform: none; 15 | left: 0; 16 | position: relative; 17 | margin: 0 auto; 18 | } 19 | 20 | //element ui upload 21 | .upload-container { 22 | .el-upload { 23 | width: 100%; 24 | .el-upload-dragger { 25 | width: 100%; 26 | height: 200px; 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/icons/svg/table.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/icons/svg/password.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/views/layout/components/Sidebar/Item.vue: -------------------------------------------------------------------------------- 1 | 30 | -------------------------------------------------------------------------------- /config/export.js: -------------------------------------------------------------------------------- 1 | import axios from 'axios' 2 | import store from '@/store' 3 | export function exportXls(params, url, file_name) { 4 | const new_headers = { 'Authorization': 'bearer ' + store.getters.token } 5 | axios({ url: url, 6 | method: 'get', 7 | headers: new_headers, 8 | params: params, 9 | responseType: 'blob' }) 10 | .then(res => { 11 | console.log(res) 12 | const url = window.URL.createObjectURL(new Blob([res.data])) 13 | const link = document.createElement('a') 14 | link.href = url 15 | link.setAttribute('download', file_name) 16 | document.body.appendChild(link) 17 | link.click() 18 | }).catch(res => { 19 | alert(res) 20 | }) 21 | } 22 | -------------------------------------------------------------------------------- /src/api/export.js: -------------------------------------------------------------------------------- 1 | import axios from 'axios' 2 | import store from '@/store' 3 | export function exportXls(params, url, file_name) { 4 | const new_headers = { 'Authorization': 'bearer ' + store.getters.token } 5 | axios({ url: url, 6 | method: 'get', 7 | headers: new_headers, 8 | params: params, 9 | responseType: 'blob' }) 10 | .then(res => { 11 | console.log(res) 12 | const url = window.URL.createObjectURL(new Blob([res.data])) 13 | const link = document.createElement('a') 14 | link.href = url 15 | link.setAttribute('download', file_name) 16 | document.body.appendChild(link) 17 | link.click() 18 | }).catch(res => { 19 | alert(res) 20 | }) 21 | } 22 | -------------------------------------------------------------------------------- /src/views/dashboard/index.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 21 | 22 | 33 | -------------------------------------------------------------------------------- /src/views/layout/components/AppMain.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 21 | 22 | 30 | -------------------------------------------------------------------------------- /src/main.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | 3 | import 'normalize.css/normalize.css' // A modern alternative to CSS resets 4 | 5 | import ElementUI from 'element-ui' 6 | import 'element-ui/lib/theme-chalk/index.css' 7 | import locale from 'element-ui/lib/locale/lang/zh-CN' // lang i18n 8 | 9 | import '@/styles/index.scss' // global css 10 | 11 | import App from './App' 12 | import router from './router' 13 | import store from './store' 14 | 15 | import '@/icons' // icon 16 | import '@/permission' // permission control 17 | import 'babel-polyfill' 18 | import './utils/directives.js' 19 | 20 | Vue.use(ElementUI, { locale }) 21 | 22 | Vue.config.productionTip = false 23 | 24 | new Vue({ 25 | el: '#app', 26 | router, 27 | store, 28 | render: h => h(App) 29 | }) 30 | -------------------------------------------------------------------------------- /src/icons/svg/nested.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/views/layout/components/Sidebar/Link.vue: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 40 | -------------------------------------------------------------------------------- /src/components/SvgIcon/index.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 34 | 35 | 44 | -------------------------------------------------------------------------------- /src/utils/routerStr.js: -------------------------------------------------------------------------------- 1 | function creatRouter(obj_list) { 2 | var str = `[` 3 | for(let i in obj_list){ 4 | var childPath = `` 5 | for (let j in obj_list[i].childs) { 6 | childPath += ` 7 | { 8 | path: '${obj_list[i].childs[j].object_name}', 9 | name: '${obj_list[i].dir_name}_${obj_list[i].childs[j].object_name}', 10 | component: () => import('@/views/${obj_list[i].dir_name}/${obj_list[i].childs[j].object_name}'), 11 | meta: { title: '${obj_list[i].childs[j].object_name_cn}', icon: 'form' } 12 | },` 13 | } 14 | str += ` 15 | { 16 | path: '/${obj_list[i].dir_name}', 17 | meta: { title: '${obj_list[i].dir_name_cn}', icon: 'form' }, 18 | component: Layout, 19 | children: [ 20 | ${childPath} 21 | ] 22 | },` 23 | } 24 | str += `\n]` 25 | return str 26 | } 27 | 28 | module.exports.creatRouter = creatRouter -------------------------------------------------------------------------------- /src/App.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 35 | -------------------------------------------------------------------------------- /src/styles/transition.scss: -------------------------------------------------------------------------------- 1 | //globl transition css 2 | 3 | /*fade*/ 4 | .fade-enter-active, 5 | .fade-leave-active { 6 | transition: opacity 0.28s; 7 | } 8 | 9 | .fade-enter, 10 | .fade-leave-active { 11 | opacity: 0; 12 | } 13 | 14 | /*fade-transform*/ 15 | .fade-transform-leave-active, 16 | .fade-transform-enter-active { 17 | transition: all .5s; 18 | } 19 | .fade-transform-enter { 20 | opacity: 0; 21 | transform: translateX(-30px); 22 | } 23 | .fade-transform-leave-to { 24 | opacity: 0; 25 | transform: translateX(30px); 26 | } 27 | 28 | /*fade*/ 29 | .breadcrumb-enter-active, 30 | .breadcrumb-leave-active { 31 | transition: all .5s; 32 | } 33 | 34 | .breadcrumb-enter, 35 | .breadcrumb-leave-active { 36 | opacity: 0; 37 | transform: translateX(20px); 38 | } 39 | 40 | .breadcrumb-move { 41 | transition: all .5s; 42 | } 43 | 44 | .breadcrumb-leave-active { 45 | position: absolute; 46 | } 47 | -------------------------------------------------------------------------------- /src/icons/svg/eye.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/views/layout/components/Sidebar/index.vue: -------------------------------------------------------------------------------- 1 | 16 | 17 | 36 | -------------------------------------------------------------------------------- /src/utils/validate.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by jiachenpan on 16/11/18. 3 | */ 4 | 5 | export function isvalidUsername(str) { 6 | const valid_map = ['admin', 'editor'] 7 | return valid_map.indexOf(str.trim()) >= 0 8 | } 9 | 10 | /* 合法uri*/ 11 | export function validateURL(textval) { 12 | const urlregex = /^(https?|ftp):\/\/([a-zA-Z0-9.-]+(:[a-zA-Z0-9.&%$-]+)*@)*((25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]?)(\.(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3}|([a-zA-Z0-9-]+\.)*[a-zA-Z0-9-]+\.(com|edu|gov|int|mil|net|org|biz|arpa|info|name|pro|aero|coop|museum|[a-zA-Z]{2}))(:[0-9]+)*(\/($|[a-zA-Z0-9.,?'\\+&%$#=~_-]+))*$/ 13 | return urlregex.test(textval) 14 | } 15 | 16 | /* 小写字母*/ 17 | export function validateLowerCase(str) { 18 | const reg = /^[a-z]+$/ 19 | return reg.test(str) 20 | } 21 | 22 | /* 大写字母*/ 23 | export function validateUpperCase(str) { 24 | const reg = /^[A-Z]+$/ 25 | return reg.test(str) 26 | } 27 | 28 | /* 大小写字母*/ 29 | export function validatAlphabets(str) { 30 | const reg = /^[A-Za-z]+$/ 31 | return reg.test(str) 32 | } 33 | -------------------------------------------------------------------------------- /src/components/SearchField/index.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 45 | 46 | 48 | -------------------------------------------------------------------------------- /src/icons/svg/eye_show.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/api/myapi.js: -------------------------------------------------------------------------------- 1 | import request from '@/utils/request' 2 | 3 | // 上传文件 4 | export function uploadfile(data) { 5 | return request({ 6 | url: '/website/uploadfile', 7 | method: 'post', 8 | data: data 9 | }) 10 | } 11 | 12 | // 第二版本的异步请求 13 | // get 请求数据 14 | export function GetAjax(url, params) { 15 | return request({ 16 | url: url, 17 | method: 'get', 18 | params: params 19 | }) 20 | } 21 | // post 提交数据 22 | export function PostAjax(url, data) { 23 | return request({ 24 | url: url, 25 | method: 'post', 26 | data: data 27 | }) 28 | } 29 | // patch 修改数据 30 | export function PatchAjax(url, data) { 31 | return request({ 32 | url: url, 33 | method: 'patch', 34 | data: data 35 | }) 36 | } 37 | // put 修改数据 38 | export function PutAjax(url, data) { 39 | return request({ 40 | url: url, 41 | method: 'put', 42 | data: data 43 | }) 44 | } 45 | // delete 删除数据 46 | export function DeleteAjax(url, data) { 47 | return request({ 48 | url: url, 49 | method: 'delete', 50 | data: data 51 | }) 52 | } 53 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017-present PanJiaChen 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/views/layout/mixin/ResizeHandler.js: -------------------------------------------------------------------------------- 1 | import store from '@/store' 2 | 3 | const { body } = document 4 | const WIDTH = 1024 5 | const RATIO = 3 6 | 7 | export default { 8 | watch: { 9 | $route(route) { 10 | if (this.device === 'mobile' && this.sidebar.opened) { 11 | store.dispatch('CloseSideBar', { withoutAnimation: false }) 12 | } 13 | } 14 | }, 15 | beforeMount() { 16 | window.addEventListener('resize', this.resizeHandler) 17 | }, 18 | mounted() { 19 | const isMobile = this.isMobile() 20 | if (isMobile) { 21 | store.dispatch('ToggleDevice', 'mobile') 22 | store.dispatch('CloseSideBar', { withoutAnimation: true }) 23 | } 24 | }, 25 | methods: { 26 | isMobile() { 27 | const rect = body.getBoundingClientRect() 28 | return rect.width - RATIO < WIDTH 29 | }, 30 | resizeHandler() { 31 | if (!document.hidden) { 32 | const isMobile = this.isMobile() 33 | store.dispatch('ToggleDevice', isMobile ? 'mobile' : 'desktop') 34 | 35 | if (isMobile) { 36 | store.dispatch('CloseSideBar', { withoutAnimation: true }) 37 | } 38 | } 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/icons/svg/code.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/store/modules/app.js: -------------------------------------------------------------------------------- 1 | import Cookies from 'js-cookie' 2 | 3 | const app = { 4 | state: { 5 | sidebar: { 6 | opened: !+Cookies.get('sidebarStatus'), 7 | withoutAnimation: false 8 | }, 9 | device: 'desktop' 10 | }, 11 | mutations: { 12 | TOGGLE_SIDEBAR: state => { 13 | if (state.sidebar.opened) { 14 | Cookies.set('sidebarStatus', 1) 15 | } else { 16 | Cookies.set('sidebarStatus', 0) 17 | } 18 | state.sidebar.opened = !state.sidebar.opened 19 | state.sidebar.withoutAnimation = false 20 | }, 21 | CLOSE_SIDEBAR: (state, withoutAnimation) => { 22 | Cookies.set('sidebarStatus', 1) 23 | state.sidebar.opened = false 24 | state.sidebar.withoutAnimation = withoutAnimation 25 | }, 26 | TOGGLE_DEVICE: (state, device) => { 27 | state.device = device 28 | } 29 | }, 30 | actions: { 31 | ToggleSideBar: ({ commit }) => { 32 | commit('TOGGLE_SIDEBAR') 33 | }, 34 | CloseSideBar({ commit }, { withoutAnimation }) { 35 | commit('CLOSE_SIDEBAR', withoutAnimation) 36 | }, 37 | ToggleDevice({ commit }, device) { 38 | commit('TOGGLE_DEVICE', device) 39 | } 40 | } 41 | } 42 | 43 | export default app 44 | -------------------------------------------------------------------------------- /src/components/SearchField/index2.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 53 | 54 | 56 | -------------------------------------------------------------------------------- /src/permission.js: -------------------------------------------------------------------------------- 1 | import router from './router' 2 | import store from './store' 3 | import NProgress from 'nprogress' // Progress 进度条 4 | import 'nprogress/nprogress.css'// Progress 进度条样式 5 | import { Message } from 'element-ui' 6 | import { getToken } from '@/utils/auth' // 验权 7 | 8 | const whiteList = ['/login'] // 不重定向白名单 9 | router.beforeEach((to, from, next) => { 10 | NProgress.start() 11 | if (getToken()) { 12 | if (to.path === '/login') { 13 | next({ path: '/' }) 14 | NProgress.done() // if current page is dashboard will not trigger afterEach hook, so manually handle it 15 | } else { 16 | if (store.getters.name == '') { 17 | store.dispatch('GetInfo').then(res => { // 拉取用户信息 18 | next() 19 | }).catch((err) => { 20 | store.dispatch('FedLogOut').then(() => { 21 | Message.error(err || 'Verification failed, please login again') 22 | next({ path: '/' }) 23 | }) 24 | }) 25 | } else { 26 | next() 27 | } 28 | } 29 | } else { 30 | if (whiteList.indexOf(to.path) !== -1) { 31 | next() 32 | } else { 33 | next(`/login?redirect=${to.path}`) // 否则全部重定向到登录页 34 | NProgress.done() 35 | } 36 | } 37 | }) 38 | 39 | router.afterEach(() => { 40 | NProgress.done() // 结束Progress 41 | }) 42 | -------------------------------------------------------------------------------- /src/styles/index.scss: -------------------------------------------------------------------------------- 1 | @import './variables.scss'; 2 | @import './mixin.scss'; 3 | @import './transition.scss'; 4 | @import './element-ui.scss'; 5 | @import './sidebar.scss'; 6 | 7 | body { 8 | height: 100%; 9 | -moz-osx-font-smoothing: grayscale; 10 | -webkit-font-smoothing: antialiased; 11 | text-rendering: optimizeLegibility; 12 | font-family: Helvetica Neue, Helvetica, PingFang SC, Hiragino Sans GB, Microsoft YaHei, Arial, sans-serif; 13 | } 14 | 15 | label { 16 | font-weight: 700; 17 | } 18 | 19 | html { 20 | height: 100%; 21 | box-sizing: border-box; 22 | } 23 | 24 | #app{ 25 | height: 100%; 26 | } 27 | 28 | *, 29 | *:before, 30 | *:after { 31 | box-sizing: inherit; 32 | } 33 | 34 | a, 35 | a:focus, 36 | a:hover { 37 | cursor: pointer; 38 | color: inherit; 39 | outline: none; 40 | text-decoration: none; 41 | } 42 | 43 | div:focus{ 44 | outline: none; 45 | } 46 | 47 | a:focus, 48 | a:active { 49 | outline: none; 50 | } 51 | 52 | a, 53 | a:focus, 54 | a:hover { 55 | cursor: pointer; 56 | color: inherit; 57 | text-decoration: none; 58 | } 59 | 60 | .clearfix { 61 | &:after { 62 | visibility: hidden; 63 | display: block; 64 | font-size: 0; 65 | content: " "; 66 | clear: both; 67 | height: 0; 68 | } 69 | } 70 | 71 | //main-container全局样式 72 | .app-main{ 73 | min-height: 100% 74 | } 75 | 76 | .app-container { 77 | padding: 20px; 78 | } 79 | -------------------------------------------------------------------------------- /src/components/ScrollPane/index.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 40 | 41 | 57 | -------------------------------------------------------------------------------- /src/icons/svg/tree.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/views/layout/Layout.vue: -------------------------------------------------------------------------------- 1 | 12 | 13 | 49 | 50 | 72 | -------------------------------------------------------------------------------- /src/utils/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by jiachenpan on 16/11/18. 3 | */ 4 | 5 | export function parseTime(time, cFormat) { 6 | if (arguments.length === 0) { 7 | return null 8 | } 9 | const format = cFormat || '{y}-{m}-{d} {h}:{i}:{s}' 10 | let date 11 | if (typeof time === 'object') { 12 | date = time 13 | } else { 14 | if (('' + time).length === 10) time = parseInt(time) * 1000 15 | date = new Date(time) 16 | } 17 | const formatObj = { 18 | y: date.getFullYear(), 19 | m: date.getMonth() + 1, 20 | d: date.getDate(), 21 | h: date.getHours(), 22 | i: date.getMinutes(), 23 | s: date.getSeconds(), 24 | a: date.getDay() 25 | } 26 | const time_str = format.replace(/{(y|m|d|h|i|s|a)+}/g, (result, key) => { 27 | let value = formatObj[key] 28 | // Note: getDay() returns 0 on Sunday 29 | if (key === 'a') { return ['日', '一', '二', '三', '四', '五', '六'][value ] } 30 | if (result.length > 0 && value < 10) { 31 | value = '0' + value 32 | } 33 | return value || 0 34 | }) 35 | return time_str 36 | } 37 | 38 | export function formatTime(time, option) { 39 | time = +time * 1000 40 | const d = new Date(time) 41 | const now = Date.now() 42 | 43 | const diff = (now - d) / 1000 44 | 45 | if (diff < 30) { 46 | return '刚刚' 47 | } else if (diff < 3600) { 48 | // less 1 hour 49 | return Math.ceil(diff / 60) + '分钟前' 50 | } else if (diff < 3600 * 24) { 51 | return Math.ceil(diff / 3600) + '小时前' 52 | } else if (diff < 3600 * 24 * 2) { 53 | return '1天前' 54 | } 55 | if (option) { 56 | return parseTime(time, option) 57 | } else { 58 | return ( 59 | d.getMonth() + 60 | 1 + 61 | '月' + 62 | d.getDate() + 63 | '日' + 64 | d.getHours() + 65 | '时' + 66 | d.getMinutes() + 67 | '分' 68 | ) 69 | } 70 | } 71 | 72 | export function isExternal(path) { 73 | return /^(https?:|mailto:|tel:)/.test(path) 74 | } 75 | -------------------------------------------------------------------------------- /src/components/Breadcrumb/index.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 58 | 59 | 71 | -------------------------------------------------------------------------------- /src/components/Hamburger/index.vue: -------------------------------------------------------------------------------- 1 | 28 | 29 | 44 | 45 | 59 | -------------------------------------------------------------------------------- /src/components/Pagination/index.vue: -------------------------------------------------------------------------------- 1 | 16 | 17 | 85 | 86 | 95 | -------------------------------------------------------------------------------- /src/icons/svg/dashboard.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/components/Upload/singleImage.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 62 | 63 | 92 | -------------------------------------------------------------------------------- /src/utils/directives.js: -------------------------------------------------------------------------------- 1 | 2 | import Vue from 'vue' 3 | 4 | // v-dialogDrag: 弹窗拖拽 5 | Vue.directive('dialogDrag', { 6 | bind(el, binding, vnode, oldVnode) { 7 | const dialogHeaderEl = el.querySelector('.el-dialog__header') 8 | const dragDom = el.querySelector('.el-dialog') 9 | dialogHeaderEl.style.cursor = 'move' 10 | 11 | // 获取原有属性 ie dom元素.currentStyle 火狐谷歌 window.getComputedStyle(dom元素, null); 12 | const sty = dragDom.currentStyle || window.getComputedStyle(dragDom, null) 13 | 14 | dialogHeaderEl.onmousedown = (e) => { 15 | // 鼠标按下,计算当前元素距离可视区的距离 16 | const disX = e.clientX - dialogHeaderEl.offsetLeft 17 | const disY = e.clientY - dialogHeaderEl.offsetTop 18 | 19 | // 获取到的值带px 正则匹配替换 20 | let styL, styT 21 | 22 | // 注意在ie中 第一次获取到的值为组件自带50% 移动之后赋值为px 23 | if (sty.left.includes('%')) { 24 | styL = +document.body.clientWidth * (+sty.left.replace(/\%/g, '') / 100) 25 | styT = +document.body.clientHeight * (+sty.top.replace(/\%/g, '') / 100) 26 | } else { 27 | styL = +sty.left.replace(/\px/g, '') 28 | styT = +sty.top.replace(/\px/g, '') 29 | } 30 | 31 | document.onmousemove = function(e) { 32 | // 通过事件委托,计算移动的距离 33 | const l = e.clientX - disX 34 | const t = e.clientY - disY 35 | 36 | // 移动当前元素 37 | dragDom.style.left = `${l + styL}px` 38 | dragDom.style.top = `${t + styT}px` 39 | 40 | // 将此时的位置传出去 41 | // binding.value({x:e.pageX,y:e.pageY}) 42 | } 43 | 44 | document.onmouseup = function(e) { 45 | document.onmousemove = null 46 | document.onmouseup = null 47 | } 48 | } 49 | } 50 | }) 51 | 52 | // v-dialogDragWidth: 弹窗宽度拖大 拖小 53 | Vue.directive('dialogDragWidth', { 54 | bind(el, binding, vnode, oldVnode) { 55 | const dragDom = binding.value.$el.querySelector('.el-dialog') 56 | 57 | el.onmousedown = (e) => { 58 | // 鼠标按下,计算当前元素距离可视区的距离 59 | const disX = e.clientX - el.offsetLeft 60 | 61 | document.onmousemove = function(e) { 62 | e.preventDefault() // 移动时禁用默认事件 63 | 64 | // 通过事件委托,计算移动的距离 65 | const l = e.clientX - disX 66 | dragDom.style.width = `${l}px` 67 | } 68 | 69 | document.onmouseup = function(e) { 70 | document.onmousemove = null 71 | document.onmouseup = null 72 | } 73 | } 74 | } 75 | }) 76 | 77 | -------------------------------------------------------------------------------- /src/icons/svg/form.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/router/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Router from 'vue-router' 3 | Vue.use(Router) 4 | 5 | /* Layout */ 6 | import Layout from '../views/layout/Layout' 7 | export const constantRouterMap = [ 8 | { path: '/login', component: () => import('@/views/login/index'), hidden: true }, 9 | { path: '/404', component: () => import('@/views/404'), hidden: true }, 10 | { 11 | path: '/', 12 | component: Layout, 13 | redirect: '/dashboard', 14 | children: [{ 15 | path: 'dashboard', 16 | name: 'Dashboard', 17 | component: () => import('@/views/userinfo/index'), 18 | meta: { title: '个人信息', icon: 'dashboard', noCache: true } 19 | }] 20 | }, 21 | { 22 | path: '/demoadmin', 23 | component: Layout, 24 | hidden: true, 25 | children: [ 26 | { 27 | path: 'demo', 28 | name: 'demo', 29 | component: () => import('@/views/myviews/demoadmin'), 30 | meta: { title: 'demo admin', icon: 'form' } 31 | } 32 | ] 33 | }, 34 | { 35 | path: '/print', 36 | component: Layout, 37 | hidden: true, 38 | children: [ 39 | { 40 | path: 'pdemo', 41 | name: 'pdemo', 42 | component: () => import('@/views/myviews/printdemo'), 43 | meta: { title: 'demo print', icon: 'form' } 44 | } 45 | ] 46 | }, 47 | { 48 | path: '/tinymceDemo', 49 | component: Layout, 50 | hidden: true, 51 | children: [ 52 | { 53 | path: 'tinymce', 54 | name: 'tinymce', 55 | component: () => import('@/views/myviews/tinymce_demo'), 56 | meta: { title: 'Tinymce Demo', icon: 'form' } 57 | } 58 | ] 59 | }, 60 | { 61 | path: '/system', 62 | meta: { title: '系统管理', icon: 'form' }, 63 | component: Layout, 64 | children: [ 65 | { 66 | path: 'user', 67 | name: 'user', 68 | component: () => import('@/views/system/user'), 69 | meta: { title: '用户管理', icon: 'form' } 70 | }, 71 | { 72 | path: 'auth', 73 | name: 'auth', 74 | component: () => import('@/views/system/auth'), 75 | meta: { title: '权限管理', icon: 'form' } 76 | }, 77 | ] 78 | }, 79 | { 80 | path: '/redirect/:path*', 81 | component: () => import('@/views/redirect') 82 | }, 83 | { path: '*', redirect: '/404', hidden: true } 84 | ] 85 | 86 | export default new Router({ 87 | // mode: 'history', //后端支持可开 88 | scrollBehavior: () => ({ y: 0 }), 89 | routes: constantRouterMap 90 | }) 91 | -------------------------------------------------------------------------------- /src/utils/generateCode.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const fs = require('fs'); 3 | const vueCode = require('./codeStr'); 4 | const router = require('./routerStr'); 5 | // console.log(__dirname); // 当前文件所在的绝对路径。 6 | // console.log(__filename); // 当前文件的文件名,包括全路径。 __dirname和__filename都是全局对象。 7 | 8 | 9 | // 写入主体 10 | var obj_list = [ 11 | { 12 | dir_name:'system', 13 | dir_name_cn:'系统管理', 14 | childs: [ 15 | { 16 | object_name:'group', 17 | object_name_cn:'用户组管理', 18 | fields:[ 19 | {prop:'id',label:'ID'}, 20 | {prop:'group_type',label:'角色类型'}, 21 | ] 22 | }, 23 | { 24 | object_name:'user', 25 | object_name_cn:'用户管理', 26 | fields:[ 27 | {prop:'id',label:'ID'}, 28 | {prop:'username',label:'用户名'} 29 | ] 30 | } 31 | ] 32 | }, 33 | { 34 | dir_name:'info', 35 | dir_name_cn:'信息管理', 36 | childs: [ 37 | { 38 | object_name:'company', 39 | object_name_cn:'公司管理', 40 | fields:[ 41 | {prop:'id',label:'ID'}, 42 | {prop:'name',label:'公司名称'} 43 | ] 44 | }, 45 | { 46 | object_name:'employ', 47 | object_name_cn:'员工管理', 48 | fields:[ 49 | {prop:'id',label:'ID'}, 50 | {prop:'real_name',label:'员工名称'} 51 | ] 52 | } 53 | ] 54 | } 55 | ] 56 | 57 | 58 | // 写入vue文件的函数 59 | function writeCode(dir_path, data, dir_name) { 60 | const file_path = dir_path + '/' + data.object_name + '.vue' 61 | fs.writeFile(file_path, vueCode.creatCode(data, dir_name), (err) => { 62 | if (err) throw err 63 | console.log('文件:' + String(file_path) + '已被保存...') 64 | }) 65 | } 66 | 67 | // 写入路由文件的函数 68 | function writeRouter(file_path, data) { 69 | fs.writeFile(file_path, data, (err) => { 70 | if (err) throw err 71 | console.log('文件:' + String(file_path) + '已被保存...') 72 | }) 73 | } 74 | 75 | // 主体函数 76 | function creatCode(obj_list) { 77 | for (let i in obj_list) { 78 | // 创建目录 79 | const base_path = __dirname + '/my_view' 80 | const dir_path = base_path + '/' + obj_list[i].dir_name 81 | const router_path = base_path + '/router.js' 82 | fs.mkdir(dir_path, { recursive: true }, (err) => { 83 | if (err) throw err 84 | for (let j in obj_list[i].childs) { 85 | writeCode(dir_path, obj_list[i].childs[j], obj_list[i].dir_name) 86 | } 87 | writeRouter(router_path, router.creatRouter(obj_list)) 88 | }) 89 | } 90 | } 91 | 92 | // 运行主体函数 93 | creatCode(obj_list) 94 | -------------------------------------------------------------------------------- /src/views/layout/components/Navbar.vue: -------------------------------------------------------------------------------- 1 | 23 | 24 | 53 | 54 | 96 | 97 | -------------------------------------------------------------------------------- /src/components/MiniPagination/index.vue: -------------------------------------------------------------------------------- 1 | 23 | 24 | 96 | 97 | 106 | -------------------------------------------------------------------------------- /src/utils/request.js: -------------------------------------------------------------------------------- 1 | import axios from 'axios' 2 | import { Message, MessageBox } from 'element-ui' 3 | import store from '../store' 4 | import { getToken } from '@/utils/auth' 5 | 6 | // 创建axios实例 7 | const service = axios.create({ 8 | baseURL: process.env.BASE_API, // api 的 base_url 9 | timeout: 30 * 1000 // 请求超时时间 10 | }) 11 | 12 | // request拦截器 13 | service.interceptors.request.use( 14 | config => { 15 | if (store.getters.token) { 16 | config.headers['Authorization'] = 'bearer ' + getToken() // 让每个请求携带自定义token 请根据实际情况自行修改 17 | } 18 | return config 19 | }, 20 | error => { 21 | // Do something with request error 22 | console.log(error) // for debug 23 | Promise.reject(error) 24 | } 25 | ) 26 | 27 | // response 拦截器 28 | service.interceptors.response.use( 29 | response => { 30 | /** 31 | * code为非20000是抛错 可结合自己业务进行修改 32 | */ 33 | console.log('response拦截器开始拦截') 34 | console.log(response.data) 35 | console.log('response拦截器结束拦截(会拦截所有response)') 36 | const res = response.data 37 | 38 | if (response.status === 201) { 39 | Message({ showClose: true, message: '创建成功', type: 'success' }) 40 | } else if (response.status === 204) { 41 | Message({ showClose: true, message: '删除成功', type: 'success' }) 42 | } else if (response.status === 401) { 43 | return Promise.reject('请登陆') 44 | } else if (response.status === 403) { 45 | MessageBox({ showClose: true, message: '您没有权限', type: 'error' }) 46 | } else if (response.status === 404) { 47 | MessageBox({ showClose: true, message: '资源不存在', type: 'error' }) 48 | } else if (response.status >= 300 && response.status < 400) { 49 | MessageBox({ showClose: true, message: '服务器已迁移', type: 'error' }) 50 | } else if (response.status >= 400 && response.status < 500) { 51 | MessageBox({ showClose: true, message: '请求错误', type: 'error' }) 52 | } else if (response.status >= 500 && response.status < 600) { 53 | MessageBox({ showClose: true, message: '服务器错误', type: 'error' }) 54 | } else if (response.status === 200) { 55 | if (res.errorCode !== 0) { 56 | // MessageBox({ showClose: true, message: res.message, type: 'error' }) 57 | Message({ 58 | showClose: true, 59 | message: res.message, 60 | type: 'error' 61 | }); 62 | } else { 63 | return response.data 64 | } 65 | } else { 66 | // MessageBox({ showClose: true, message: '访问错误', type: 'error' }) 67 | Message({ 68 | showClose: true, 69 | message: '访问错误', 70 | type: 'error' 71 | }); 72 | } 73 | }, 74 | error => { 75 | console.log('error:' + error) // for debug 76 | // localStorage.removeItem('Website-Manage-Token') 77 | // return Promise.reject(error) 78 | alert(error) 79 | } 80 | ) 81 | 82 | export default service 83 | -------------------------------------------------------------------------------- /src/components/Tinymce/index.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "mymanage", 3 | "version": "3.8.0", 4 | "license": "MIT", 5 | "description": "A vue admin template with Element UI & axios & iconfont & permission control & lint", 6 | "author": "Pan ", 7 | "scripts": { 8 | "dev": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js", 9 | "start": "npm run dev", 10 | "code": "node ./src/utils/generateCode.js", 11 | "build": "node build/build.js", 12 | "build:report": "npm_config_report=true npm run build", 13 | "lint": "eslint --ext .js,.vue src", 14 | "test": "npm run lint", 15 | "svgo": "svgo -f src/icons/svg --config=src/icons/svgo.yml" 16 | }, 17 | "dependencies": { 18 | "@tinymce/tinymce-vue": "^1.1.0", 19 | "axios": "0.18.0", 20 | "babel-polyfill": "^6.26.0", 21 | "date-and-time": "^0.6.3", 22 | "element-ui": "2.12.0", 23 | "js-cookie": "2.2.0", 24 | "normalize.css": "7.0.0", 25 | "nprogress": "0.2.0", 26 | "tinymce": "^4.9.5", 27 | "vue": "2.5.17", 28 | "vue-cropper": "^0.4.9", 29 | "vue-router": "3.0.1", 30 | "vuex": "3.0.1" 31 | }, 32 | "devDependencies": { 33 | "autoprefixer": "8.5.0", 34 | "babel-core": "6.26.0", 35 | "babel-eslint": "8.2.6", 36 | "babel-helper-vue-jsx-merge-props": "2.0.3", 37 | "babel-loader": "7.1.5", 38 | "babel-plugin-syntax-jsx": "6.18.0", 39 | "babel-plugin-transform-runtime": "6.23.0", 40 | "babel-plugin-transform-vue-jsx": "3.7.0", 41 | "babel-preset-env": "1.7.0", 42 | "babel-preset-stage-2": "6.24.1", 43 | "chalk": "2.4.1", 44 | "copy-webpack-plugin": "4.5.2", 45 | "css-loader": "^1.0.1", 46 | "eslint": "4.19.1", 47 | "eslint-friendly-formatter": "4.0.1", 48 | "eslint-loader": "2.0.0", 49 | "eslint-plugin-vue": "4.7.1", 50 | "eventsource-polyfill": "0.9.6", 51 | "file-loader": "1.1.11", 52 | "friendly-errors-webpack-plugin": "1.7.0", 53 | "html-webpack-plugin": "4.0.0-alpha", 54 | "mini-css-extract-plugin": "0.4.1", 55 | "node-notifier": "5.2.1", 56 | "node-sass": "^4.7.2", 57 | "optimize-css-assets-webpack-plugin": "5.0.0", 58 | "ora": "3.0.0", 59 | "path-to-regexp": "2.4.0", 60 | "portfinder": "1.0.16", 61 | "postcss-import": "12.0.0", 62 | "postcss-loader": "2.1.6", 63 | "postcss-url": "7.3.2", 64 | "rimraf": "2.6.2", 65 | "sass-loader": "7.0.3", 66 | "script-ext-html-webpack-plugin": "2.0.1", 67 | "semver": "5.5.0", 68 | "shelljs": "0.8.2", 69 | "style-loader": "^0.23.1", 70 | "stylus-loader": "^3.0.2", 71 | "svg-sprite-loader": "3.8.0", 72 | "svgo": "1.0.5", 73 | "uglifyjs-webpack-plugin": "1.2.7", 74 | "url-loader": "1.0.1", 75 | "vue-loader": "15.3.0", 76 | "vue-style-loader": "4.1.2", 77 | "vue-template-compiler": "2.5.17", 78 | "webpack": "4.16.5", 79 | "webpack-bundle-analyzer": "2.13.1", 80 | "webpack-cli": "3.1.0", 81 | "webpack-dev-server": "3.1.5", 82 | "webpack-merge": "4.1.4" 83 | }, 84 | "engines": { 85 | "node": ">= 6.0.0", 86 | "npm": ">= 3.0.0" 87 | }, 88 | "browserslist": [ 89 | "> 1%", 90 | "last 2 versions", 91 | "not ie <= 8" 92 | ] 93 | } 94 | -------------------------------------------------------------------------------- /config/index.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | // Template version: 1.2.6 3 | // see http://vuejs-templates.github.io/webpack for documentation. 4 | 5 | const path = require('path') 6 | 7 | module.exports = { 8 | dev: { 9 | // Paths 10 | assetsSubDirectory: 'static', 11 | assetsPublicPath: '/', 12 | proxyTable: {}, 13 | 14 | // Various Dev Server settings 15 | host: '0.0.0.0', // can be overwritten by process.env.HOST 16 | port: 8099, // can be overwritten by process.env.PORT, if port is in use, a free one will be determined 17 | autoOpenBrowser: false, 18 | errorOverlay: true, 19 | notifyOnErrors: false, 20 | poll: false, // https://webpack.js.org/configuration/dev-server/#devserver-watchoptions- 21 | 22 | // Use Eslint Loader? 23 | // If true, your code will be linted during bundling and 24 | // linting errors and warnings will be shown in the console. 25 | useEslint: true, 26 | // If true, eslint errors and warnings will also be shown in the error overlay 27 | // in the browser. 28 | showEslintErrorsInOverlay: false, 29 | 30 | /** 31 | * Source Maps 32 | */ 33 | 34 | // https://webpack.js.org/configuration/devtool/#development 35 | devtool: 'cheap-source-map', 36 | 37 | // CSS Sourcemaps off by default because relative paths are "buggy" 38 | // with this option, according to the CSS-Loader README 39 | // (https://github.com/webpack/css-loader#sourcemaps) 40 | // In our experience, they generally work as expected, 41 | // just be aware of this issue when enabling this option. 42 | cssSourceMap: false 43 | }, 44 | 45 | build: { 46 | // Template for index.html 47 | index: path.resolve(__dirname, '../dist/index.html'), 48 | 49 | // Paths 50 | assetsRoot: path.resolve(__dirname, '../dist'), 51 | assetsSubDirectory: 'static', 52 | 53 | /** 54 | * You can set by youself according to actual condition 55 | * You will need to set this if you plan to deploy your site under a sub path, 56 | * for example GitHub pages. If you plan to deploy your site to https://foo.github.io/bar/, 57 | * then assetsPublicPath should be set to "/bar/". 58 | * In most cases please use '/' !!! 59 | */ 60 | assetsPublicPath: './', 61 | 62 | /** 63 | * Source Maps 64 | */ 65 | 66 | productionSourceMap: false, 67 | // https://webpack.js.org/configuration/devtool/#production 68 | devtool: 'source-map', 69 | 70 | // Gzip off by default as many popular static hosts such as 71 | // Surge or Netlify already gzip all static assets for you. 72 | // Before setting to `true`, make sure to: 73 | // npm install --save-dev compression-webpack-plugin 74 | productionGzip: false, 75 | productionGzipExtensions: ['js', 'css'], 76 | 77 | // Run the build command with an extra argument to 78 | // View the bundle analyzer report after build finishes: 79 | // `npm run build --report` 80 | // Set to `true` or `false` to always turn it on or off 81 | bundleAnalyzerReport: process.env.npm_config_report || false, 82 | 83 | // `npm run build:prod --generate_report` 84 | generateAnalyzerReport: process.env.npm_config_generate_report || false 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /src/components/Upload/singleFile.vue: -------------------------------------------------------------------------------- 1 | 19 | 20 | 107 | 108 | 111 | -------------------------------------------------------------------------------- /src/views/layout/components/Sidebar/SidebarItem.vue: -------------------------------------------------------------------------------- 1 | 35 | 36 | 102 | -------------------------------------------------------------------------------- /src/styles/sidebar.scss: -------------------------------------------------------------------------------- 1 | #app { 2 | // 主体区域 3 | .main-container { 4 | min-height: 100%; 5 | transition: margin-left .28s; 6 | margin-left: 180px; 7 | position: relative; 8 | } 9 | // 侧边栏 10 | .sidebar-container { 11 | transition: width 0.28s; 12 | width: 180px !important; 13 | height: 100%; 14 | position: fixed; 15 | font-size: 0px; 16 | top: 0; 17 | bottom: 0; 18 | left: 0; 19 | z-index: 1001; 20 | overflow: hidden; 21 | //reset element-ui css 22 | .horizontal-collapse-transition { 23 | transition: 0s width ease-in-out, 0s padding-left ease-in-out, 0s padding-right ease-in-out; 24 | } 25 | .el-scrollbar__bar.is-vertical{ 26 | right: 0px; 27 | } 28 | .scrollbar-wrapper { 29 | overflow-x: hidden!important; 30 | .el-scrollbar__view { 31 | height: 100%; 32 | } 33 | } 34 | .is-horizontal { 35 | display: none; 36 | } 37 | a { 38 | display: inline-block; 39 | width: 100%; 40 | overflow: hidden; 41 | } 42 | .svg-icon { 43 | margin-right: 16px; 44 | } 45 | .el-menu { 46 | border: none; 47 | height: 100%; 48 | width: 100% !important; 49 | } 50 | .is-active > .el-submenu__title{ 51 | color: #f4f4f5!important; 52 | } 53 | } 54 | .hideSidebar { 55 | .sidebar-container { 56 | width: 36px !important; 57 | } 58 | .main-container { 59 | margin-left: 36px; 60 | } 61 | .submenu-title-noDropdown { 62 | padding-left: 10px !important; 63 | position: relative; 64 | .el-tooltip { 65 | padding: 0 10px !important; 66 | } 67 | } 68 | .el-submenu { 69 | overflow: hidden; 70 | &>.el-submenu__title { 71 | padding-left: 10px !important; 72 | .el-submenu__icon-arrow { 73 | display: none; 74 | } 75 | } 76 | } 77 | .el-menu--collapse { 78 | .el-submenu { 79 | &>.el-submenu__title { 80 | &>span { 81 | height: 0; 82 | width: 0; 83 | overflow: hidden; 84 | visibility: hidden; 85 | display: inline-block; 86 | } 87 | } 88 | } 89 | } 90 | } 91 | .sidebar-container .nest-menu .el-submenu>.el-submenu__title, 92 | .sidebar-container .el-submenu .el-menu-item { 93 | min-width: 180px !important; 94 | background-color: $subMenuBg !important; 95 | &:hover { 96 | background-color: $menuHover !important; 97 | } 98 | } 99 | .el-menu--collapse .el-menu .el-submenu { 100 | min-width: 180px !important; 101 | } 102 | 103 | //适配移动端 104 | .mobile { 105 | .main-container { 106 | margin-left: 0px; 107 | } 108 | .sidebar-container { 109 | transition: transform .28s; 110 | width: 180px !important; 111 | } 112 | &.hideSidebar { 113 | .sidebar-container { 114 | transition-duration: 0.3s; 115 | transform: translate3d(-180px, 0, 0); 116 | } 117 | } 118 | } 119 | .withoutAnimation { 120 | .main-container, 121 | .sidebar-container { 122 | transition: none; 123 | } 124 | } 125 | } 126 | 127 | .el-menu--vertical{ 128 | & >.el-menu{ 129 | .svg-icon{ 130 | margin-right: 16px; 131 | } 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /static/tinymce/skins/lightgray/content.inline.min.css: -------------------------------------------------------------------------------- 1 | .word-wrap{word-wrap:break-word;-ms-word-break:break-all;word-break:break-all;word-break:break-word;-ms-hyphens:auto;-moz-hyphens:auto;-webkit-hyphens:auto;hyphens:auto}.mce-content-body .mce-reset{margin:0;padding:0;border:0;outline:0;vertical-align:top;background:transparent;text-decoration:none;color:black;font-family:Arial;font-size:11px;text-shadow:none;float:none;position:static;width:auto;height:auto;white-space:nowrap;cursor:inherit;line-height:normal;font-weight:normal;text-align:left;-webkit-tap-highlight-color:transparent;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box;direction:ltr;max-width:none}.mce-object{border:1px dotted #3A3A3A;background:#D5D5D5 url(img/object.gif) no-repeat center}.mce-preview-object{display:inline-block;position:relative;margin:0 2px 0 2px;line-height:0;border:1px solid gray}.mce-preview-object[data-mce-selected="2"] .mce-shim{display:none}.mce-preview-object .mce-shim{position:absolute;top:0;left:0;width:100%;height:100%;background:url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)}figure.align-left{float:left}figure.align-right{float:right}figure.image.align-center{display:table;margin-left:auto;margin-right:auto}figure.image{display:inline-block;border:1px solid gray;margin:0 2px 0 1px;background:#f5f2f0}figure.image img{margin:8px 8px 0 8px}figure.image figcaption{margin:6px 8px 6px 8px;text-align:center}.mce-toc{border:1px solid gray}.mce-toc h2{margin:4px}.mce-toc li{list-style-type:none}.mce-pagebreak{cursor:default;display:block;border:0;width:100%;height:5px;border:1px dashed #666;margin-top:15px;page-break-before:always}@media print{.mce-pagebreak{border:0}}.mce-item-anchor{cursor:default;display:inline-block;-webkit-user-select:all;-webkit-user-modify:read-only;-moz-user-select:all;-moz-user-modify:read-only;user-select:all;user-modify:read-only;width:9px !important;height:9px !important;border:1px dotted #3A3A3A;background:#D5D5D5 url(img/anchor.gif) no-repeat center}.mce-nbsp,.mce-shy{background:#AAA}.mce-shy::after{content:'-'}.mce-match-marker{background:#AAA;color:#fff}.mce-match-marker-selected{background:#3399ff;color:#fff}.mce-spellchecker-word{border-bottom:2px solid rgba(208,2,27,0.5);cursor:default}.mce-spellchecker-grammar{border-bottom:2px solid #008000;cursor:default}.mce-item-table,.mce-item-table td,.mce-item-table th,.mce-item-table caption{border:1px dashed #BBB}td[data-mce-selected],th[data-mce-selected]{background-color:#2276d2 !important}.mce-edit-focus{outline:1px dotted #333}.mce-content-body *[contentEditable=false] *[contentEditable=true]:focus{outline:2px solid #2276d2}.mce-content-body *[contentEditable=false] *[contentEditable=true]:hover{outline:2px solid #2276d2}.mce-content-body *[contentEditable=false][data-mce-selected]{outline:2px solid #2276d2}.mce-content-body.mce-content-readonly *[contentEditable=true]:focus,.mce-content-body.mce-content-readonly *[contentEditable=true]:hover{outline:none}.mce-content-body *[data-mce-selected="inline-boundary"]{background:#bfe6ff}.mce-content-body .mce-item-anchor[data-mce-selected]{background:#D5D5D5 url(img/anchor.gif) no-repeat center}.mce-content-body hr{cursor:default}.mce-content-body table{-webkit-nbsp-mode:normal}.ephox-snooker-resizer-bar{background-color:#2276d2;opacity:0}.ephox-snooker-resizer-cols{cursor:col-resize}.ephox-snooker-resizer-rows{cursor:row-resize}.ephox-snooker-resizer-bar.ephox-snooker-resizer-bar-dragging{opacity:.2}.mce-content-body{line-height:1.3} -------------------------------------------------------------------------------- /src/components/Upload/multiImage.vue: -------------------------------------------------------------------------------- 1 | 22 | 23 | 117 | 118 | 121 | -------------------------------------------------------------------------------- /static/tinymce/skins/lightgray/content.min.css: -------------------------------------------------------------------------------- 1 | body{background-color:#FFFFFF;color:#000000;font-family:Verdana,Arial,Helvetica,sans-serif;font-size:14px;line-height:1.3;scrollbar-3dlight-color:#F0F0EE;scrollbar-arrow-color:#676662;scrollbar-base-color:#F0F0EE;scrollbar-darkshadow-color:#DDDDDD;scrollbar-face-color:#E0E0DD;scrollbar-highlight-color:#F0F0EE;scrollbar-shadow-color:#F0F0EE;scrollbar-track-color:#F5F5F5}td,th{font-family:Verdana,Arial,Helvetica,sans-serif;font-size:14px}.word-wrap{word-wrap:break-word;-ms-word-break:break-all;word-break:break-all;word-break:break-word;-ms-hyphens:auto;-moz-hyphens:auto;-webkit-hyphens:auto;hyphens:auto}.mce-content-body .mce-reset{margin:0;padding:0;border:0;outline:0;vertical-align:top;background:transparent;text-decoration:none;color:black;font-family:Arial;font-size:11px;text-shadow:none;float:none;position:static;width:auto;height:auto;white-space:nowrap;cursor:inherit;line-height:normal;font-weight:normal;text-align:left;-webkit-tap-highlight-color:transparent;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box;direction:ltr;max-width:none}.mce-object{border:1px dotted #3A3A3A;background:#D5D5D5 url(img/object.gif) no-repeat center}.mce-preview-object{display:inline-block;position:relative;margin:0 2px 0 2px;line-height:0;border:1px solid gray}.mce-preview-object[data-mce-selected="2"] .mce-shim{display:none}.mce-preview-object .mce-shim{position:absolute;top:0;left:0;width:100%;height:100%;background:url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)}figure.align-left{float:left}figure.align-right{float:right}figure.image.align-center{display:table;margin-left:auto;margin-right:auto}figure.image{display:inline-block;border:1px solid gray;margin:0 2px 0 1px;background:#f5f2f0}figure.image img{margin:8px 8px 0 8px}figure.image figcaption{margin:6px 8px 6px 8px;text-align:center}.mce-toc{border:1px solid gray}.mce-toc h2{margin:4px}.mce-toc li{list-style-type:none}.mce-pagebreak{cursor:default;display:block;border:0;width:100%;height:5px;border:1px dashed #666;margin-top:15px;page-break-before:always}@media print{.mce-pagebreak{border:0}}.mce-item-anchor{cursor:default;display:inline-block;-webkit-user-select:all;-webkit-user-modify:read-only;-moz-user-select:all;-moz-user-modify:read-only;user-select:all;user-modify:read-only;width:9px !important;height:9px !important;border:1px dotted #3A3A3A;background:#D5D5D5 url(img/anchor.gif) no-repeat center}.mce-nbsp,.mce-shy{background:#AAA}.mce-shy::after{content:'-'}.mce-match-marker{background:#AAA;color:#fff}.mce-match-marker-selected{background:#3399ff;color:#fff}.mce-spellchecker-word{border-bottom:2px solid rgba(208,2,27,0.5);cursor:default}.mce-spellchecker-grammar{border-bottom:2px solid #008000;cursor:default}.mce-item-table,.mce-item-table td,.mce-item-table th,.mce-item-table caption{border:1px dashed #BBB}td[data-mce-selected],th[data-mce-selected]{background-color:#2276d2 !important}.mce-edit-focus{outline:1px dotted #333}.mce-content-body *[contentEditable=false] *[contentEditable=true]:focus{outline:2px solid #2276d2}.mce-content-body *[contentEditable=false] *[contentEditable=true]:hover{outline:2px solid #2276d2}.mce-content-body *[contentEditable=false][data-mce-selected]{outline:2px solid #2276d2}.mce-content-body.mce-content-readonly *[contentEditable=true]:focus,.mce-content-body.mce-content-readonly *[contentEditable=true]:hover{outline:none}.mce-content-body *[data-mce-selected="inline-boundary"]{background:#bfe6ff}.mce-content-body .mce-item-anchor[data-mce-selected]{background:#D5D5D5 url(img/anchor.gif) no-repeat center}.mce-content-body hr{cursor:default}.mce-content-body table{-webkit-nbsp-mode:normal}.ephox-snooker-resizer-bar{background-color:#2276d2;opacity:0}.ephox-snooker-resizer-cols{cursor:col-resize}.ephox-snooker-resizer-rows{cursor:row-resize}.ephox-snooker-resizer-bar.ephox-snooker-resizer-bar-dragging{opacity:.2} -------------------------------------------------------------------------------- /src/components/IdentifyCode/index.vue: -------------------------------------------------------------------------------- 1 | 6 | -------------------------------------------------------------------------------- /src/views/myviews/tinymce_demo.vue: -------------------------------------------------------------------------------- 1 | 12 | 13 | -------------------------------------------------------------------------------- /src/views/myviews/printdemo.vue: -------------------------------------------------------------------------------- 1 | 51 | 52 | 85 | 86 | -------------------------------------------------------------------------------- /src/components/DataSelect/index.vue: -------------------------------------------------------------------------------- 1 | 16 | 17 | -------------------------------------------------------------------------------- /src/store/modules/user.js: -------------------------------------------------------------------------------- 1 | import { login, logout, getInfo } from '@/api/login' 2 | import { getToken, setToken, removeToken } from '@/utils/auth' 3 | import router from '../../router' 4 | 5 | function handleRouters(routers, auth_json) { 6 | const whiteList = ['/login', '/404', '/', '*', 'dashboard'] 7 | const auth = auth_json 8 | function handleOneRouter(router) { 9 | if (!router.children) { 10 | if (whiteList.indexOf(router.path) === -1) { 11 | if (auth[router.name]) { 12 | if (auth[router.name].auth_list) { 13 | router.hidden = false 14 | } else { 15 | router.hidden = true 16 | } 17 | } else { 18 | router.hidden = true 19 | } 20 | } 21 | return 1 22 | } else { 23 | var count = 1 24 | for (var i in router.children) { 25 | count += handleOneRouter(router.children[i]) 26 | if (router.children[i].children) { 27 | var len = router.children[i].children.length 28 | var false_len = 0 29 | for (let j in router.children[i].children) { 30 | if (router.children[i].children[j].hidden) { 31 | false_len++ 32 | } 33 | } 34 | if (len === false_len) { 35 | router.children[i].hidden = true 36 | } else { 37 | router.children[i].hidden = false 38 | } 39 | } 40 | } 41 | return count 42 | } 43 | } 44 | var need_handle_routers = { children: routers } 45 | handleOneRouter(need_handle_routers) 46 | return need_handle_routers.children 47 | } 48 | 49 | const user = { 50 | state: { 51 | token: getToken(), 52 | name: '', 53 | avatar: '', 54 | roles: '', 55 | auth_json: {}, 56 | routers: router, 57 | user_obj: {} 58 | }, 59 | 60 | mutations: { 61 | SET_TOKEN: (state, token) => { 62 | state.token = token 63 | }, 64 | SET_USER_OBJ: (state, user_obj) => { 65 | state.user_obj = user_obj 66 | }, 67 | SET_NAME: (state, name) => { 68 | state.name = name 69 | }, 70 | SET_AVATAR: (state, avatar) => { 71 | state.avatar = avatar 72 | }, 73 | SET_ROLES: (state, roles) => { 74 | state.roles = roles 75 | }, 76 | SET_AUTHS: (state, auths) => { 77 | var auth_obj = {} 78 | for (let i in auths) { 79 | auth_obj[auths[i].object_name] = { 80 | auth_create: auths[i].auth_create, 81 | auth_list: auths[i].auth_list, 82 | auth_update: auths[i].auth_update, 83 | auth_destroy: auths[i].auth_destroy 84 | } 85 | } 86 | state.auth_json = auth_obj 87 | }, 88 | SET_ROUTE: (state, routers) => { 89 | state.routers = routers 90 | } 91 | }, 92 | 93 | actions: { 94 | // 登录 95 | Login({ commit }, userInfo) { 96 | return new Promise((resolve, reject) => { 97 | login(userInfo).then(response => { 98 | const data = response.data 99 | setToken(data.token) 100 | commit('SET_TOKEN', data.token) 101 | resolve() 102 | }).catch(error => { 103 | reject(error) 104 | // alert(error) 105 | }) 106 | }) 107 | }, 108 | 109 | // 获取用户信息 110 | GetInfo({ commit, state }) { 111 | return new Promise((resolve, reject) => { 112 | getInfo().then(response => { 113 | const data = response.data 114 | console.log(data) 115 | commit('SET_USER_OBJ', data) 116 | commit('SET_NAME', data.username) 117 | commit('SET_ROLES', data.group.group_type) 118 | commit('SET_AVATAR', data.img_url) 119 | if (data.group.group_type !== 'SuperAdmin') { 120 | commit('SET_AUTHS', data.auth.auth_permissions) 121 | console.log('查看auths:', state.auth_json) 122 | console.log(router.options.routes) 123 | var my_router = handleRouters(router.options.routes, state.auth_json) 124 | console.log(my_router) 125 | router.options.routes = my_router 126 | commit('SET_ROUTE', router) 127 | } 128 | resolve(response) 129 | }).catch(error => { 130 | reject(error) 131 | }) 132 | }) 133 | }, 134 | 135 | // 登出 136 | LogOut({ commit, state }) { 137 | return new Promise((resolve, reject) => { 138 | logout(state.token).then(() => { 139 | commit('SET_TOKEN', '') 140 | commit('SET_ROLES', []) 141 | removeToken() 142 | resolve() 143 | }).catch(error => { 144 | reject(error) 145 | }) 146 | }) 147 | }, 148 | 149 | // 前端 登出 150 | FedLogOut({ commit }) { 151 | return new Promise(resolve => { 152 | commit('SET_TOKEN', '') 153 | router.push({path: '/login'}) 154 | removeToken() 155 | resolve() 156 | }) 157 | } 158 | } 159 | } 160 | 161 | export default user 162 | -------------------------------------------------------------------------------- /src/store/modules/tagsView.js: -------------------------------------------------------------------------------- 1 | const tagsView = { 2 | state: { 3 | visitedViews: [], 4 | cachedViews: [] 5 | }, 6 | mutations: { 7 | ADD_VISITED_VIEW: (state, view) => { 8 | if (state.visitedViews.some(v => v.path === view.path)) return 9 | state.visitedViews.push( 10 | Object.assign({}, view, { 11 | title: view.meta.title || 'no-name' 12 | }) 13 | ) 14 | }, 15 | ADD_CACHED_VIEW: (state, view) => { 16 | if (state.cachedViews.includes(view.name)) return 17 | if (!view.meta.noCache) { 18 | state.cachedViews.push(view.name) 19 | } 20 | }, 21 | 22 | DEL_VISITED_VIEW: (state, view) => { 23 | for (const [i, v] of state.visitedViews.entries()) { 24 | if (v.path === view.path) { 25 | state.visitedViews.splice(i, 1) 26 | break 27 | } 28 | } 29 | }, 30 | DEL_CACHED_VIEW: (state, view) => { 31 | for (const i of state.cachedViews) { 32 | if (i === view.name) { 33 | const index = state.cachedViews.indexOf(i) 34 | state.cachedViews.splice(index, 1) 35 | break 36 | } 37 | } 38 | }, 39 | 40 | DEL_OTHERS_VISITED_VIEWS: (state, view) => { 41 | for (const [i, v] of state.visitedViews.entries()) { 42 | if (v.path === view.path) { 43 | state.visitedViews = state.visitedViews.slice(i, i + 1) 44 | break 45 | } 46 | } 47 | }, 48 | DEL_OTHERS_CACHED_VIEWS: (state, view) => { 49 | for (const i of state.cachedViews) { 50 | if (i === view.name) { 51 | const index = state.cachedViews.indexOf(i) 52 | state.cachedViews = state.cachedViews.slice(index, index + 1) 53 | break 54 | } 55 | } 56 | }, 57 | 58 | DEL_ALL_VISITED_VIEWS: state => { 59 | state.visitedViews = [] 60 | }, 61 | DEL_ALL_CACHED_VIEWS: state => { 62 | state.cachedViews = [] 63 | }, 64 | 65 | UPDATE_VISITED_VIEW: (state, view) => { 66 | for (let v of state.visitedViews) { 67 | if (v.path === view.path) { 68 | v = Object.assign(v, view) 69 | break 70 | } 71 | } 72 | } 73 | 74 | }, 75 | actions: { 76 | addView({ dispatch }, view) { 77 | dispatch('addVisitedView', view) 78 | dispatch('addCachedView', view) 79 | }, 80 | addVisitedView({ commit }, view) { 81 | commit('ADD_VISITED_VIEW', view) 82 | }, 83 | addCachedView({ commit }, view) { 84 | commit('ADD_CACHED_VIEW', view) 85 | }, 86 | 87 | delView({ dispatch, state }, view) { 88 | return new Promise(resolve => { 89 | dispatch('delVisitedView', view) 90 | dispatch('delCachedView', view) 91 | resolve({ 92 | visitedViews: [...state.visitedViews], 93 | cachedViews: [...state.cachedViews] 94 | }) 95 | }) 96 | }, 97 | delVisitedView({ commit, state }, view) { 98 | return new Promise(resolve => { 99 | commit('DEL_VISITED_VIEW', view) 100 | resolve([...state.visitedViews]) 101 | }) 102 | }, 103 | delCachedView({ commit, state }, view) { 104 | return new Promise(resolve => { 105 | commit('DEL_CACHED_VIEW', view) 106 | resolve([...state.cachedViews]) 107 | }) 108 | }, 109 | 110 | delOthersViews({ dispatch, state }, view) { 111 | return new Promise(resolve => { 112 | dispatch('delOthersVisitedViews', view) 113 | dispatch('delOthersCachedViews', view) 114 | resolve({ 115 | visitedViews: [...state.visitedViews], 116 | cachedViews: [...state.cachedViews] 117 | }) 118 | }) 119 | }, 120 | delOthersVisitedViews({ commit, state }, view) { 121 | return new Promise(resolve => { 122 | commit('DEL_OTHERS_VISITED_VIEWS', view) 123 | resolve([...state.visitedViews]) 124 | }) 125 | }, 126 | delOthersCachedViews({ commit, state }, view) { 127 | return new Promise(resolve => { 128 | commit('DEL_OTHERS_CACHED_VIEWS', view) 129 | resolve([...state.cachedViews]) 130 | }) 131 | }, 132 | 133 | delAllViews({ dispatch, state }, view) { 134 | return new Promise(resolve => { 135 | dispatch('delAllVisitedViews', view) 136 | dispatch('delAllCachedViews', view) 137 | resolve({ 138 | visitedViews: [...state.visitedViews], 139 | cachedViews: [...state.cachedViews] 140 | }) 141 | }) 142 | }, 143 | delAllVisitedViews({ commit, state }) { 144 | return new Promise(resolve => { 145 | commit('DEL_ALL_VISITED_VIEWS') 146 | resolve([...state.visitedViews]) 147 | }) 148 | }, 149 | delAllCachedViews({ commit, state }) { 150 | return new Promise(resolve => { 151 | commit('DEL_ALL_CACHED_VIEWS') 152 | resolve([...state.cachedViews]) 153 | }) 154 | }, 155 | 156 | updateVisitedView({ commit }, view) { 157 | commit('UPDATE_VISITED_VIEW', view) 158 | } 159 | } 160 | } 161 | 162 | export default tagsView 163 | -------------------------------------------------------------------------------- /src/components/Upload/cropperImage.vue: -------------------------------------------------------------------------------- 1 | 42 | 43 | 141 | 142 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | parserOptions: { 4 | parser: 'babel-eslint', 5 | sourceType: 'module' 6 | }, 7 | env: { 8 | browser: true, 9 | node: true, 10 | es6: true, 11 | }, 12 | extends: ['plugin:vue/recommended', 'eslint:recommended'], 13 | 14 | // add your custom rules here 15 | //it is base on https://github.com/vuejs/eslint-config-vue 16 | rules: { 17 | "vue/max-attributes-per-line": [2, { 18 | "singleline": 10, 19 | "multiline": { 20 | "max": 1, 21 | "allowFirstLine": false 22 | } 23 | }], 24 | "vue/name-property-casing": ["error", "PascalCase"], 25 | 'accessor-pairs': 2, 26 | 'arrow-spacing': [2, { 27 | 'before': true, 28 | 'after': true 29 | }], 30 | 'block-spacing': [2, 'always'], 31 | 'brace-style': [2, '1tbs', { 32 | 'allowSingleLine': true 33 | }], 34 | 'camelcase': [0, { 35 | 'properties': 'always' 36 | }], 37 | 'comma-dangle': [2, 'never'], 38 | 'comma-spacing': [2, { 39 | 'before': false, 40 | 'after': true 41 | }], 42 | 'comma-style': [2, 'last'], 43 | 'constructor-super': 2, 44 | 'curly': [2, 'multi-line'], 45 | 'dot-location': [2, 'property'], 46 | 'eol-last': 2, 47 | 'eqeqeq': [2, 'allow-null'], 48 | 'generator-star-spacing': [2, { 49 | 'before': true, 50 | 'after': true 51 | }], 52 | 'handle-callback-err': [2, '^(err|error)$'], 53 | 'indent': [2, 2, { 54 | 'SwitchCase': 1 55 | }], 56 | 'jsx-quotes': [2, 'prefer-single'], 57 | 'key-spacing': [2, { 58 | 'beforeColon': false, 59 | 'afterColon': true 60 | }], 61 | 'keyword-spacing': [2, { 62 | 'before': true, 63 | 'after': true 64 | }], 65 | 'new-cap': [2, { 66 | 'newIsCap': true, 67 | 'capIsNew': false 68 | }], 69 | 'new-parens': 2, 70 | 'no-array-constructor': 2, 71 | 'no-caller': 2, 72 | 'no-console': 'off', 73 | 'no-class-assign': 2, 74 | 'no-cond-assign': 2, 75 | 'no-const-assign': 2, 76 | 'no-control-regex': 2, 77 | 'no-delete-var': 2, 78 | 'no-dupe-args': 2, 79 | 'no-dupe-class-members': 2, 80 | 'no-dupe-keys': 2, 81 | 'no-duplicate-case': 2, 82 | 'no-empty-character-class': 2, 83 | 'no-empty-pattern': 2, 84 | 'no-eval': 2, 85 | 'no-ex-assign': 2, 86 | 'no-extend-native': 2, 87 | 'no-extra-bind': 2, 88 | 'no-extra-boolean-cast': 2, 89 | 'no-extra-parens': [2, 'functions'], 90 | 'no-fallthrough': 2, 91 | 'no-floating-decimal': 2, 92 | 'no-func-assign': 2, 93 | 'no-implied-eval': 2, 94 | 'no-inner-declarations': [2, 'functions'], 95 | 'no-invalid-regexp': 2, 96 | 'no-irregular-whitespace': 2, 97 | 'no-iterator': 2, 98 | 'no-label-var': 2, 99 | 'no-labels': [2, { 100 | 'allowLoop': false, 101 | 'allowSwitch': false 102 | }], 103 | 'no-lone-blocks': 2, 104 | 'no-mixed-spaces-and-tabs': 2, 105 | 'no-multi-spaces': 2, 106 | 'no-multi-str': 2, 107 | 'no-multiple-empty-lines': [2, { 108 | 'max': 1 109 | }], 110 | 'no-native-reassign': 2, 111 | 'no-negated-in-lhs': 2, 112 | 'no-new-object': 2, 113 | 'no-new-require': 2, 114 | 'no-new-symbol': 2, 115 | 'no-new-wrappers': 2, 116 | 'no-obj-calls': 2, 117 | 'no-octal': 2, 118 | 'no-octal-escape': 2, 119 | 'no-path-concat': 2, 120 | 'no-proto': 2, 121 | 'no-redeclare': 2, 122 | 'no-regex-spaces': 2, 123 | 'no-return-assign': [2, 'except-parens'], 124 | 'no-self-assign': 2, 125 | 'no-self-compare': 2, 126 | 'no-sequences': 2, 127 | 'no-shadow-restricted-names': 2, 128 | 'no-spaced-func': 2, 129 | 'no-sparse-arrays': 2, 130 | 'no-this-before-super': 2, 131 | 'no-throw-literal': 2, 132 | 'no-trailing-spaces': 2, 133 | 'no-undef': 2, 134 | 'no-undef-init': 2, 135 | 'no-unexpected-multiline': 2, 136 | 'no-unmodified-loop-condition': 2, 137 | 'no-unneeded-ternary': [2, { 138 | 'defaultAssignment': false 139 | }], 140 | 'no-unreachable': 2, 141 | 'no-unsafe-finally': 2, 142 | 'no-unused-vars': [2, { 143 | 'vars': 'all', 144 | 'args': 'none' 145 | }], 146 | 'no-useless-call': 2, 147 | 'no-useless-computed-key': 2, 148 | 'no-useless-constructor': 2, 149 | 'no-useless-escape': 0, 150 | 'no-whitespace-before-property': 2, 151 | 'no-with': 2, 152 | 'one-var': [2, { 153 | 'initialized': 'never' 154 | }], 155 | 'operator-linebreak': [2, 'after', { 156 | 'overrides': { 157 | '?': 'before', 158 | ':': 'before' 159 | } 160 | }], 161 | 'padded-blocks': [2, 'never'], 162 | 'quotes': [2, 'single', { 163 | 'avoidEscape': true, 164 | 'allowTemplateLiterals': true 165 | }], 166 | 'semi': [2, 'never'], 167 | 'semi-spacing': [2, { 168 | 'before': false, 169 | 'after': true 170 | }], 171 | 'space-before-blocks': [2, 'always'], 172 | 'space-before-function-paren': [2, 'never'], 173 | 'space-in-parens': [2, 'never'], 174 | 'space-infix-ops': 2, 175 | 'space-unary-ops': [2, { 176 | 'words': true, 177 | 'nonwords': false 178 | }], 179 | 'spaced-comment': [2, 'always', { 180 | 'markers': ['global', 'globals', 'eslint', 'eslint-disable', '*package', '!', ','] 181 | }], 182 | 'template-curly-spacing': [2, 'never'], 183 | 'use-isnan': 2, 184 | 'valid-typeof': 2, 185 | 'wrap-iife': [2, 'any'], 186 | 'yield-star-spacing': [2, 'both'], 187 | 'yoda': [2, 'never'], 188 | 'prefer-const': 2, 189 | 'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0, 190 | 'object-curly-spacing': [2, 'always', { 191 | objectsInObjects: false 192 | }], 193 | 'array-bracket-spacing': [2, 'never'] 194 | } 195 | } 196 | 197 | -------------------------------------------------------------------------------- /src/views/404.vue: -------------------------------------------------------------------------------- 1 | 22 | 23 | 34 | 35 | 229 | -------------------------------------------------------------------------------- /src/views/layout/components/TagsView.vue: -------------------------------------------------------------------------------- 1 | 25 | 26 | 139 | 140 | 206 | 207 | 232 | -------------------------------------------------------------------------------- /src/views/userinfo/index.vue: -------------------------------------------------------------------------------- 1 | 72 | 73 | 173 | 174 | -------------------------------------------------------------------------------- /src/views/login/index.vue: -------------------------------------------------------------------------------- 1 | 48 | 49 | 148 | 149 | 182 | 183 | 236 | -------------------------------------------------------------------------------- /src/components/Upload/mulImage.vue: -------------------------------------------------------------------------------- 1 | 49 | 50 | 208 | 209 | 215 | -------------------------------------------------------------------------------- /static/tinymce/zh_CN.js: -------------------------------------------------------------------------------- 1 | tinymce.addI18n('zh_CN',{ 2 | "Redo": "\u91cd\u590d", 3 | "Undo": "\u64a4\u6d88", 4 | "Cut": "\u526a\u5207", 5 | "Copy": "\u590d\u5236", 6 | "Paste": "\u7c98\u8d34", 7 | "Select all": "\u5168\u9009", 8 | "New document": "\u65b0\u6587\u6863", 9 | "Ok": "\u786e\u5b9a", 10 | "Cancel": "\u53d6\u6d88", 11 | "Visual aids": "\u7f51\u683c\u7ebf", 12 | "Bold": "\u7c97\u4f53", 13 | "Italic": "\u659c\u4f53", 14 | "Underline": "\u4e0b\u5212\u7ebf", 15 | "Strikethrough": "\u5220\u9664\u7ebf", 16 | "Superscript": "\u4e0a\u6807", 17 | "Subscript": "\u4e0b\u6807", 18 | "Clear formatting": "\u6e05\u9664\u683c\u5f0f", 19 | "Align left": "\u5de6\u5bf9\u9f50", 20 | "Align center": "\u5c45\u4e2d", 21 | "Align right": "\u53f3\u5bf9\u9f50", 22 | "Justify": "\u4e24\u7aef\u5bf9\u9f50", 23 | "Bullet list": "\u9879\u76ee\u7b26\u53f7", 24 | "Numbered list": "\u7f16\u53f7\u5217\u8868", 25 | "Decrease indent": "\u51cf\u5c11\u7f29\u8fdb", 26 | "Increase indent": "\u589e\u52a0\u7f29\u8fdb", 27 | "Close": "\u5173\u95ed", 28 | "Formats": "\u683c\u5f0f", 29 | "Your browser doesn't support direct access to the clipboard. Please use the Ctrl+X\/C\/V keyboard shortcuts instead.": "\u4f60\u7684\u6d4f\u89c8\u5668\u4e0d\u652f\u6301\u5bf9\u526a\u8d34\u677f\u7684\u8bbf\u95ee\uff0c\u8bf7\u4f7f\u7528Ctrl+X\/C\/V\u952e\u8fdb\u884c\u590d\u5236\u7c98\u8d34\u3002", 30 | "Headers": "\u6807\u9898", 31 | "Header 1": "\u6807\u98981", 32 | "Header 2": "\u6807\u98982", 33 | "Header 3": "\u6807\u98983", 34 | "Header 4": "\u6807\u98984", 35 | "Header 5": "\u6807\u98985", 36 | "Header 6": "\u6807\u98986", 37 | "Headings": "\u6807\u9898", 38 | "Heading 1": "\u6807\u98981", 39 | "Heading 2": "\u6807\u98982", 40 | "Heading 3": "\u6807\u98983", 41 | "Heading 4": "\u6807\u98984", 42 | "Heading 5": "\u6807\u98985", 43 | "Heading 6": "\u6807\u98986", 44 | "Preformatted": "\u9884\u683c\u5f0f\u5316", 45 | "Div": "Div\u533a\u5757", 46 | "Pre": "\u9884\u683c\u5f0f\u6587\u672c", 47 | "Code": "\u4ee3\u7801", 48 | "Paragraph": "\u6bb5\u843d", 49 | "Blockquote": "\u5f15\u7528", 50 | "Inline": "\u6587\u672c", 51 | "Blocks": "\u533a\u5757", 52 | "Paste is now in plain text mode. Contents will now be pasted as plain text until you toggle this option off.": "\u5f53\u524d\u4e3a\u7eaf\u6587\u672c\u7c98\u8d34\u6a21\u5f0f\uff0c\u518d\u6b21\u70b9\u51fb\u53ef\u4ee5\u56de\u5230\u666e\u901a\u7c98\u8d34\u6a21\u5f0f\u3002", 53 | "Font Family": "\u5b57\u4f53", 54 | "Font Sizes": "\u5b57\u53f7", 55 | "Class": "Class", 56 | "Browse for an image": "\u6d4f\u89c8\u56fe\u50cf", 57 | "OR": "\u6216", 58 | "Drop an image here": "\u62d6\u653e\u4e00\u5f20\u56fe\u50cf\u81f3\u6b64", 59 | "Upload": "\u4e0a\u4f20", 60 | "Block": "\u5757", 61 | "Align": "\u5bf9\u9f50", 62 | "Default": "\u9ed8\u8ba4", 63 | "Circle": "\u7a7a\u5fc3\u5706", 64 | "Disc": "\u5b9e\u5fc3\u5706", 65 | "Square": "\u65b9\u5757", 66 | "Lower Alpha": "\u5c0f\u5199\u82f1\u6587\u5b57\u6bcd", 67 | "Lower Greek": "\u5c0f\u5199\u5e0c\u814a\u5b57\u6bcd", 68 | "Lower Roman": "\u5c0f\u5199\u7f57\u9a6c\u5b57\u6bcd", 69 | "Upper Alpha": "\u5927\u5199\u82f1\u6587\u5b57\u6bcd", 70 | "Upper Roman": "\u5927\u5199\u7f57\u9a6c\u5b57\u6bcd", 71 | "Anchor": "\u951a\u70b9", 72 | "Name": "\u540d\u79f0", 73 | "Id": "\u6807\u8bc6\u7b26", 74 | "Id should start with a letter, followed only by letters, numbers, dashes, dots, colons or underscores.": "\u6807\u8bc6\u7b26\u5e94\u8be5\u4ee5\u5b57\u6bcd\u5f00\u5934\uff0c\u540e\u8ddf\u5b57\u6bcd\u3001\u6570\u5b57\u3001\u7834\u6298\u53f7\u3001\u70b9\u3001\u5192\u53f7\u6216\u4e0b\u5212\u7ebf\u3002", 75 | "You have unsaved changes are you sure you want to navigate away?": "\u4f60\u8fd8\u6709\u6587\u6863\u5c1a\u672a\u4fdd\u5b58\uff0c\u786e\u5b9a\u8981\u79bb\u5f00\uff1f", 76 | "Restore last draft": "\u6062\u590d\u4e0a\u6b21\u7684\u8349\u7a3f", 77 | "Special character": "\u7279\u6b8a\u7b26\u53f7", 78 | "Source code": "\u6e90\u4ee3\u7801", 79 | "Insert\/Edit code sample": "\u63d2\u5165\/\u7f16\u8f91\u4ee3\u7801\u793a\u4f8b", 80 | "Language": "\u8bed\u8a00", 81 | "Code sample": "\u4ee3\u7801\u793a\u4f8b", 82 | "Color": "\u989c\u8272", 83 | "R": "R", 84 | "G": "G", 85 | "B": "B", 86 | "Left to right": "\u4ece\u5de6\u5230\u53f3", 87 | "Right to left": "\u4ece\u53f3\u5230\u5de6", 88 | "Emoticons": "\u8868\u60c5", 89 | "Document properties": "\u6587\u6863\u5c5e\u6027", 90 | "Title": "\u6807\u9898", 91 | "Keywords": "\u5173\u952e\u8bcd", 92 | "Description": "\u63cf\u8ff0", 93 | "Robots": "\u673a\u5668\u4eba", 94 | "Author": "\u4f5c\u8005", 95 | "Encoding": "\u7f16\u7801", 96 | "Fullscreen": "\u5168\u5c4f", 97 | "Action": "\u64cd\u4f5c", 98 | "Shortcut": "\u5feb\u6377\u952e", 99 | "Help": "\u5e2e\u52a9", 100 | "Address": "\u5730\u5740", 101 | "Focus to menubar": "\u79fb\u52a8\u7126\u70b9\u5230\u83dc\u5355\u680f", 102 | "Focus to toolbar": "\u79fb\u52a8\u7126\u70b9\u5230\u5de5\u5177\u680f", 103 | "Focus to element path": "\u79fb\u52a8\u7126\u70b9\u5230\u5143\u7d20\u8def\u5f84", 104 | "Focus to contextual toolbar": "\u79fb\u52a8\u7126\u70b9\u5230\u4e0a\u4e0b\u6587\u83dc\u5355", 105 | "Insert link (if link plugin activated)": "\u63d2\u5165\u94fe\u63a5 (\u5982\u679c\u94fe\u63a5\u63d2\u4ef6\u5df2\u6fc0\u6d3b)", 106 | "Save (if save plugin activated)": "\u4fdd\u5b58(\u5982\u679c\u4fdd\u5b58\u63d2\u4ef6\u5df2\u6fc0\u6d3b)", 107 | "Find (if searchreplace plugin activated)": "\u67e5\u627e(\u5982\u679c\u67e5\u627e\u66ff\u6362\u63d2\u4ef6\u5df2\u6fc0\u6d3b)", 108 | "Plugins installed ({0}):": "\u5df2\u5b89\u88c5\u63d2\u4ef6 ({0}):", 109 | "Premium plugins:": "\u4f18\u79c0\u63d2\u4ef6\uff1a", 110 | "Learn more...": "\u4e86\u89e3\u66f4\u591a...", 111 | "You are using {0}": "\u4f60\u6b63\u5728\u4f7f\u7528 {0}", 112 | "Plugins": "\u63d2\u4ef6", 113 | "Handy Shortcuts": "\u5feb\u6377\u952e", 114 | "Horizontal line": "\u6c34\u5e73\u5206\u5272\u7ebf", 115 | "Insert\/edit image": "\u63d2\u5165\/\u7f16\u8f91\u56fe\u7247", 116 | "Image description": "\u56fe\u7247\u63cf\u8ff0", 117 | "Source": "\u5730\u5740", 118 | "Dimensions": "\u5927\u5c0f", 119 | "Constrain proportions": "\u4fdd\u6301\u7eb5\u6a2a\u6bd4", 120 | "General": "\u666e\u901a", 121 | "Advanced": "\u9ad8\u7ea7", 122 | "Style": "\u6837\u5f0f", 123 | "Vertical space": "\u5782\u76f4\u8fb9\u8ddd", 124 | "Horizontal space": "\u6c34\u5e73\u8fb9\u8ddd", 125 | "Border": "\u8fb9\u6846", 126 | "Insert image": "\u63d2\u5165\u56fe\u7247", 127 | "Image": "\u56fe\u7247", 128 | "Image list": "\u56fe\u7247\u5217\u8868", 129 | "Rotate counterclockwise": "\u9006\u65f6\u9488\u65cb\u8f6c", 130 | "Rotate clockwise": "\u987a\u65f6\u9488\u65cb\u8f6c", 131 | "Flip vertically": "\u5782\u76f4\u7ffb\u8f6c", 132 | "Flip horizontally": "\u6c34\u5e73\u7ffb\u8f6c", 133 | "Edit image": "\u7f16\u8f91\u56fe\u7247", 134 | "Image options": "\u56fe\u7247\u9009\u9879", 135 | "Zoom in": "\u653e\u5927", 136 | "Zoom out": "\u7f29\u5c0f", 137 | "Crop": "\u88c1\u526a", 138 | "Resize": "\u8c03\u6574\u5927\u5c0f", 139 | "Orientation": "\u65b9\u5411", 140 | "Brightness": "\u4eae\u5ea6", 141 | "Sharpen": "\u9510\u5316", 142 | "Contrast": "\u5bf9\u6bd4\u5ea6", 143 | "Color levels": "\u989c\u8272\u5c42\u6b21", 144 | "Gamma": "\u4f3d\u9a6c\u503c", 145 | "Invert": "\u53cd\u8f6c", 146 | "Apply": "\u5e94\u7528", 147 | "Back": "\u540e\u9000", 148 | "Insert date\/time": "\u63d2\u5165\u65e5\u671f\/\u65f6\u95f4", 149 | "Date\/time": "\u65e5\u671f\/\u65f6\u95f4", 150 | "Insert link": "\u63d2\u5165\u94fe\u63a5", 151 | "Insert\/edit link": "\u63d2\u5165\/\u7f16\u8f91\u94fe\u63a5", 152 | "Text to display": "\u663e\u793a\u6587\u5b57", 153 | "Url": "\u5730\u5740", 154 | "Target": "\u6253\u5f00\u65b9\u5f0f", 155 | "None": "\u65e0", 156 | "New window": "\u5728\u65b0\u7a97\u53e3\u6253\u5f00", 157 | "Remove link": "\u5220\u9664\u94fe\u63a5", 158 | "Anchors": "\u951a\u70b9", 159 | "Link": "\u94fe\u63a5", 160 | "Paste or type a link": "\u7c98\u8d34\u6216\u8f93\u5165\u94fe\u63a5", 161 | "The URL you entered seems to be an email address. Do you want to add the required mailto: prefix?": "\u4f60\u6240\u586b\u5199\u7684URL\u5730\u5740\u4e3a\u90ae\u4ef6\u5730\u5740\uff0c\u9700\u8981\u52a0\u4e0amailto:\u524d\u7f00\u5417\uff1f", 162 | "The URL you entered seems to be an external link. Do you want to add the required http:\/\/ prefix?": "\u4f60\u6240\u586b\u5199\u7684URL\u5730\u5740\u5c5e\u4e8e\u5916\u90e8\u94fe\u63a5\uff0c\u9700\u8981\u52a0\u4e0ahttp:\/\/:\u524d\u7f00\u5417\uff1f", 163 | "Link list": "\u94fe\u63a5\u5217\u8868", 164 | "Insert video": "\u63d2\u5165\u89c6\u9891", 165 | "Insert\/edit video": "\u63d2\u5165\/\u7f16\u8f91\u89c6\u9891", 166 | "Insert\/edit media": "\u63d2\u5165\/\u7f16\u8f91\u5a92\u4f53", 167 | "Alternative source": "\u955c\u50cf", 168 | "Poster": "\u5c01\u9762", 169 | "Paste your embed code below:": "\u5c06\u5185\u5d4c\u4ee3\u7801\u7c98\u8d34\u5728\u4e0b\u9762:", 170 | "Embed": "\u5185\u5d4c", 171 | "Media": "\u5a92\u4f53", 172 | "Nonbreaking space": "\u4e0d\u95f4\u65ad\u7a7a\u683c", 173 | "Page break": "\u5206\u9875\u7b26", 174 | "Paste as text": "\u7c98\u8d34\u4e3a\u6587\u672c", 175 | "Preview": "\u9884\u89c8", 176 | "Print": "\u6253\u5370", 177 | "Save": "\u4fdd\u5b58", 178 | "Find": "\u67e5\u627e", 179 | "Replace with": "\u66ff\u6362\u4e3a", 180 | "Replace": "\u66ff\u6362", 181 | "Replace all": "\u5168\u90e8\u66ff\u6362", 182 | "Prev": "\u4e0a\u4e00\u4e2a", 183 | "Next": "\u4e0b\u4e00\u4e2a", 184 | "Find and replace": "\u67e5\u627e\u548c\u66ff\u6362", 185 | "Could not find the specified string.": "\u672a\u627e\u5230\u641c\u7d22\u5185\u5bb9.", 186 | "Match case": "\u533a\u5206\u5927\u5c0f\u5199", 187 | "Whole words": "\u5168\u5b57\u5339\u914d", 188 | "Spellcheck": "\u62fc\u5199\u68c0\u67e5", 189 | "Ignore": "\u5ffd\u7565", 190 | "Ignore all": "\u5168\u90e8\u5ffd\u7565", 191 | "Finish": "\u5b8c\u6210", 192 | "Add to Dictionary": "\u6dfb\u52a0\u5230\u5b57\u5178", 193 | "Insert table": "\u63d2\u5165\u8868\u683c", 194 | "Table properties": "\u8868\u683c\u5c5e\u6027", 195 | "Delete table": "\u5220\u9664\u8868\u683c", 196 | "Cell": "\u5355\u5143\u683c", 197 | "Row": "\u884c", 198 | "Column": "\u5217", 199 | "Cell properties": "\u5355\u5143\u683c\u5c5e\u6027", 200 | "Merge cells": "\u5408\u5e76\u5355\u5143\u683c", 201 | "Split cell": "\u62c6\u5206\u5355\u5143\u683c", 202 | "Insert row before": "\u5728\u4e0a\u65b9\u63d2\u5165", 203 | "Insert row after": "\u5728\u4e0b\u65b9\u63d2\u5165", 204 | "Delete row": "\u5220\u9664\u884c", 205 | "Row properties": "\u884c\u5c5e\u6027", 206 | "Cut row": "\u526a\u5207\u884c", 207 | "Copy row": "\u590d\u5236\u884c", 208 | "Paste row before": "\u7c98\u8d34\u5230\u4e0a\u65b9", 209 | "Paste row after": "\u7c98\u8d34\u5230\u4e0b\u65b9", 210 | "Insert column before": "\u5728\u5de6\u4fa7\u63d2\u5165", 211 | "Insert column after": "\u5728\u53f3\u4fa7\u63d2\u5165", 212 | "Delete column": "\u5220\u9664\u5217", 213 | "Cols": "\u5217", 214 | "Rows": "\u884c", 215 | "Width": "\u5bbd", 216 | "Height": "\u9ad8", 217 | "Cell spacing": "\u5355\u5143\u683c\u5916\u95f4\u8ddd", 218 | "Cell padding": "\u5355\u5143\u683c\u5185\u8fb9\u8ddd", 219 | "Caption": "\u6807\u9898", 220 | "Left": "\u5de6\u5bf9\u9f50", 221 | "Center": "\u5c45\u4e2d", 222 | "Right": "\u53f3\u5bf9\u9f50", 223 | "Cell type": "\u5355\u5143\u683c\u7c7b\u578b", 224 | "Scope": "\u8303\u56f4", 225 | "Alignment": "\u5bf9\u9f50\u65b9\u5f0f", 226 | "H Align": "\u6c34\u5e73\u5bf9\u9f50", 227 | "V Align": "\u5782\u76f4\u5bf9\u9f50", 228 | "Top": "\u9876\u90e8\u5bf9\u9f50", 229 | "Middle": "\u5782\u76f4\u5c45\u4e2d", 230 | "Bottom": "\u5e95\u90e8\u5bf9\u9f50", 231 | "Header cell": "\u8868\u5934\u5355\u5143\u683c", 232 | "Row group": "\u884c\u7ec4", 233 | "Column group": "\u5217\u7ec4", 234 | "Row type": "\u884c\u7c7b\u578b", 235 | "Header": "\u8868\u5934", 236 | "Body": "\u8868\u4f53", 237 | "Footer": "\u8868\u5c3e", 238 | "Border color": "\u8fb9\u6846\u989c\u8272", 239 | "Insert template": "\u63d2\u5165\u6a21\u677f", 240 | "Templates": "\u6a21\u677f", 241 | "Template": "\u6a21\u677f", 242 | "Text color": "\u6587\u5b57\u989c\u8272", 243 | "Background color": "\u80cc\u666f\u8272", 244 | "Custom...": "\u81ea\u5b9a\u4e49...", 245 | "Custom color": "\u81ea\u5b9a\u4e49\u989c\u8272", 246 | "No color": "\u65e0", 247 | "Table of Contents": "\u5185\u5bb9\u5217\u8868", 248 | "Show blocks": "\u663e\u793a\u533a\u5757\u8fb9\u6846", 249 | "Show invisible characters": "\u663e\u793a\u4e0d\u53ef\u89c1\u5b57\u7b26", 250 | "Words: {0}": "\u5b57\u6570\uff1a{0}", 251 | "{0} words": "{0} \u5b57", 252 | "File": "\u6587\u4ef6", 253 | "Edit": "\u7f16\u8f91", 254 | "Insert": "\u63d2\u5165", 255 | "View": "\u89c6\u56fe", 256 | "Format": "\u683c\u5f0f", 257 | "Table": "\u8868\u683c", 258 | "Tools": "\u5de5\u5177", 259 | "Powered by {0}": "\u7531{0}\u9a71\u52a8", 260 | "Rich Text Area. Press ALT-F9 for menu. Press ALT-F10 for toolbar. Press ALT-0 for help": "\u5728\u7f16\u8f91\u533a\u6309ALT-F9\u6253\u5f00\u83dc\u5355\uff0c\u6309ALT-F10\u6253\u5f00\u5de5\u5177\u680f\uff0c\u6309ALT-0\u67e5\u770b\u5e2e\u52a9" 261 | }); -------------------------------------------------------------------------------- /src/views/myviews/demoadmin.vue: -------------------------------------------------------------------------------- 1 | 149 | 154 | 356 | 357 | 386 | -------------------------------------------------------------------------------- /src/views/system/user.vue: -------------------------------------------------------------------------------- 1 | 2 | 175 | 180 | 395 | 396 | 398 | --------------------------------------------------------------------------------