Merge branch 'master' into deploy

This commit is contained in:
Pan 2019-04-08 14:13:53 +08:00
commit caffe6f470
31 changed files with 248 additions and 141 deletions

View File

@ -1,11 +1,23 @@
import Mock from 'mockjs' import Mock from 'mockjs'
import mocks from './mocks'
import { param2Obj } from '../src/utils' import { param2Obj } from '../src/utils'
const MOCK_API_BASE = '/mock' import user from './user'
import role from './role'
import article from './article'
import search from './remoteSearch'
const mocks = [
...user,
...role,
...article,
...search
]
// for front mock
// please use it cautiously, it will redefine XMLHttpRequest,
// which will cause many of your third-party libraries to be invalidated(like progress event).
export function mockXHR() { export function mockXHR() {
// 修复在使用 MockJS 情况下,设置 withCredentials = true且未被拦截的跨域请求丢失 Cookies 的问题 // mock patch
// https://github.com/nuysoft/Mock/issues/300 // https://github.com/nuysoft/Mock/issues/300
Mock.XHR.prototype.proxy_send = Mock.XHR.prototype.send Mock.XHR.prototype.proxy_send = Mock.XHR.prototype.send
Mock.XHR.prototype.send = function() { Mock.XHR.prototype.send = function() {
@ -42,9 +54,10 @@ export function mockXHR() {
} }
} }
// for mock server
const responseFake = (url, type, respond) => { const responseFake = (url, type, respond) => {
return { return {
url: new RegExp(`${MOCK_API_BASE}${url}`), url: new RegExp(`/mock${url}`),
type: type || 'get', type: type || 'get',
response(req, res) { response(req, res) {
res.json(Mock.mock(respond instanceof Function ? respond(req, res) : respond)) res.json(Mock.mock(respond instanceof Function ? respond(req, res) : respond))

79
mock/mock-server.js Normal file
View File

@ -0,0 +1,79 @@
const chokidar = require('chokidar')
const bodyParser = require('body-parser')
const chalk = require('chalk')
function registerRoutes(app) {
const { default: mocks } = require('./index.js')
for (const mock of mocks) {
app[mock.type](mock.url, mock.response)
}
return {
mockRoutesLength: Object.keys(mocks).length
}
}
function unregisterRoutes() {
Object.keys(require.cache).forEach(i => {
if (i.includes('/mock')) {
delete require.cache[require.resolve(i)]
}
})
}
function getPath(path) {
var match = path.toString()
.replace('\\/?', '')
.replace('(?=\\/|$)', '$')
.match(/^\/\^((?:\\[.*+?^${}()|[\]\\\/]|[^.*+?^${}()|[\]\\\/])*)\$\//)
return match
? match[1].replace(/\\(.)/g, '$1').split('/')
: path.toString()
}
function getMockRoutesIndex(app) {
for (let index = 0; index <= app._router.stack.length; index++) {
const r = app._router.stack[index]
if (r.route && r.route.path) {
const path = getPath(r.route.path)
if (path.includes('mock')) {
return index
}
}
}
}
module.exports = app => {
// es6 polyfill
require('@babel/register')
// parse app.body
// http://expressjs.com/en/4x/api.html#req.body
app.use(bodyParser.json())
app.use(bodyParser.urlencoded({
extended: true
}))
const { mockRoutesLength } = registerRoutes(app)
// watch files, hot reload mock server
chokidar.watch(('./mock'), {
ignored: 'mock/mock-server.js',
persistent: true,
ignoreInitial: true
}).on('all', (event, path) => {
if (event === 'change' || event === 'add') {
// find mock routes stack index
const index = getMockRoutesIndex(app)
// remove mock routes stack
app._router.stack.splice(index, mockRoutesLength)
// clear routes cache
unregisterRoutes()
registerRoutes(app)
console.log(chalk.magentaBright(`\n > Mock Server hot reload success! changed ${path}`))
}
})
}

View File

@ -1,12 +0,0 @@
import user from './user'
import role from './role'
import article from './article'
import search from './remoteSearch'
export default [
...user,
...role,
...article,
...search
]

View File

@ -19,7 +19,7 @@ export const constantRoutes = [
}, },
{ {
path: '/auth-redirect', path: '/auth-redirect',
component: 'views/login/authredirect', component: 'views/login/authRedirect',
hidden: true hidden: true
}, },
{ {

View File

@ -84,6 +84,7 @@
"babel-eslint": "10.0.1", "babel-eslint": "10.0.1",
"babel-jest": "23.6.0", "babel-jest": "23.6.0",
"chalk": "2.4.2", "chalk": "2.4.2",
"chokidar": "2.1.5",
"connect": "3.6.6", "connect": "3.6.6",
"eslint": "5.15.3", "eslint": "5.15.3",
"eslint-plugin-vue": "5.2.2", "eslint-plugin-vue": "5.2.2",

View File

@ -2,7 +2,7 @@
<div class="dndList"> <div class="dndList">
<div :style="{width:width1}" class="dndList-list"> <div :style="{width:width1}" class="dndList-list">
<h3>{{ list1Title }}</h3> <h3>{{ list1Title }}</h3>
<draggable :list="list1" group="article" class="dragArea"> <draggable :set-data="setData" :list="list1" group="article" class="dragArea">
<div v-for="element in list1" :key="element.id" class="list-complete-item"> <div v-for="element in list1" :key="element.id" class="list-complete-item">
<div class="list-complete-item-handle"> <div class="list-complete-item-handle">
{{ element.id }}[{{ element.author }}] {{ element.title }} {{ element.id }}[{{ element.author }}] {{ element.title }}
@ -94,6 +94,11 @@ export default {
if (this.isNotInList1(ele)) { if (this.isNotInList1(ele)) {
this.list1.push(ele) this.list1.push(ele)
} }
},
setData(dataTransfer) {
// to avoid Firefox bug
// Detail see : https://github.com/RubaXa/Sortable/issues/1012
dataTransfer.setData('Text', '')
} }
} }
} }

View File

@ -6,7 +6,7 @@
</el-button> </el-button>
</el-badge> </el-badge>
<el-dialog :visible.sync="dialogTableVisible" title="Error Log" width="80%"> <el-dialog :visible.sync="dialogTableVisible" title="Error Log" width="80%" append-to-body>
<el-table :data="errorLogs" border> <el-table :data="errorLogs" border>
<el-table-column label="Message"> <el-table-column label="Message">
<template slot-scope="{row}"> <template slot-scope="{row}">

View File

@ -7,6 +7,7 @@
:list="list" :list="list"
v-bind="$attrs" v-bind="$attrs"
class="board-column-content" class="board-column-content"
:set-data="setData"
> >
<div v-for="element in list" :key="element.id" class="board-item"> <div v-for="element in list" :key="element.id" class="board-item">
{{ element.name }} {{ element.id }} {{ element.name }} {{ element.id }}
@ -39,6 +40,13 @@ export default {
return [] return []
} }
} }
},
methods: {
setData(dataTransfer) {
// to avoid Firefox bug
// Detail see : https://github.com/RubaXa/Sortable/issues/1012
dataTransfer.setData('Text', '')
}
} }
} }
</script> </script>

View File

@ -1,7 +1,6 @@
export default { export default {
route: { route: {
dashboard: 'Dashboard', dashboard: 'Dashboard',
introduction: 'Introduction',
documentation: 'Documentation', documentation: 'Documentation',
guide: 'Guide', guide: 'Guide',
permission: 'Permission', permission: 'Permission',
@ -10,7 +9,6 @@ export default {
directivePermission: 'Directive Permission', directivePermission: 'Directive Permission',
icons: 'Icons', icons: 'Icons',
components: 'Components', components: 'Components',
componentIndex: 'Introduction',
tinymce: 'Tinymce', tinymce: 'Tinymce',
markdown: 'Markdown', markdown: 'Markdown',
jsonEditor: 'JSON Editor', jsonEditor: 'JSON Editor',
@ -88,10 +86,10 @@ export default {
}, },
permission: { permission: {
addRole: 'New Role', addRole: 'New Role',
editPermission: 'Edit Permission', editPermission: 'Edit',
roles: 'Your roles', roles: 'Your roles',
switchRoles: 'Switch roles', switchRoles: 'Switch roles',
tips: 'In some cases it is not suitable to use v-permission, such as element Tab component or el-table-column and other asynchronous rendering dom cases which can only be achieved by manually setting the v-if.', tips: 'In some cases, using v-permission will have no effect. For example: Element-UI el-tab or el-table-column and other scenes that dynamically render dom. You can only do this with v-if.',
delete: 'Delete', delete: 'Delete',
confirm: 'Confirm', confirm: 'Confirm',
cancel: 'Cancel' cancel: 'Cancel'
@ -102,7 +100,7 @@ export default {
}, },
components: { components: {
documentation: 'Documentation', documentation: 'Documentation',
tinymceTips: 'Rich text editor is a core part of management system, but at the same time is a place with lots of problems. In the process of selecting rich texts, I also walked a lot of detours. The common rich text editors in the market are basically used, and the finally chose Tinymce. See documentation for more detailed rich text editor comparisons and introductions.', tinymceTips: 'Rich text is a core feature of the management backend, but at the same time it is a place with lots of pits. In the process of selecting rich texts, I also took a lot of detours. The common rich texts on the market have been basically used, and I finally chose Tinymce. See the more detailed rich text comparison and introduction.',
dropzoneTips: 'Because my business has special needs, and has to upload images to qiniu, so instead of a third party, I chose encapsulate it by myself. It is very simple, you can see the detail code in @/components/Dropzone.', dropzoneTips: 'Because my business has special needs, and has to upload images to qiniu, so instead of a third party, I chose encapsulate it by myself. It is very simple, you can see the detail code in @/components/Dropzone.',
stickyTips: 'when the page is scrolled to the preset position will be sticky on the top.', stickyTips: 'when the page is scrolled to the preset position will be sticky on the top.',
backToTopTips1: 'When the page is scrolled to the specified position, the Back to Top button appears in the lower right corner', backToTopTips1: 'When the page is scrolled to the specified position, the Back to Top button appears in the lower right corner',
@ -150,7 +148,7 @@ export default {
placeholder: 'Please enter the file name (default file)' placeholder: 'Please enter the file name (default file)'
}, },
pdf: { pdf: {
tips: 'Here we use window.print() to implement the feature of downloading pdf.' tips: 'Here we use window.print() to implement the feature of downloading PDF.'
}, },
theme: { theme: {
change: 'Change Theme', change: 'Change Theme',

View File

@ -1,7 +1,6 @@
export default { export default {
route: { route: {
dashboard: 'Panel de control', dashboard: 'Panel de control',
introduction: 'Introducción',
documentation: 'Documentación', documentation: 'Documentación',
guide: 'Guía', guide: 'Guía',
permission: 'Permisos', permission: 'Permisos',
@ -10,7 +9,6 @@ export default {
directivePermission: 'Permisos de la directiva', directivePermission: 'Permisos de la directiva',
icons: 'Iconos', icons: 'Iconos',
components: 'Componentes', components: 'Componentes',
componentIndex: 'Introducción',
tinymce: 'Tinymce', tinymce: 'Tinymce',
markdown: 'Markdown', markdown: 'Markdown',
jsonEditor: 'Editor JSON', jsonEditor: 'Editor JSON',

View File

@ -24,11 +24,24 @@ const messages = {
...elementEsLocale ...elementEsLocale
} }
} }
export function getLanguage() {
const chooseLanguage = Cookies.get('language')
if (chooseLanguage) return chooseLanguage
// if has not choose language
const language = (navigator.language || navigator.browserLanguage).toLowerCase()
const locales = Object.keys(messages)
for (const locale of locales) {
if (language.indexOf(locale) > -1) {
return locale
}
}
return 'en'
}
const i18n = new VueI18n({ const i18n = new VueI18n({
// set locale // set locale
// options: en | zh | es // options: en | zh | es
locale: Cookies.get('language') || 'en', locale: getLanguage(),
// set locale messages // set locale messages
messages messages
}) })

View File

@ -1,7 +1,6 @@
export default { export default {
route: { route: {
dashboard: '首页', dashboard: '首页',
introduction: '简述',
documentation: '文档', documentation: '文档',
guide: '引导页', guide: '引导页',
permission: '权限测试页', permission: '权限测试页',
@ -10,7 +9,6 @@ export default {
directivePermission: '指令权限', directivePermission: '指令权限',
icons: '图标', icons: '图标',
components: '组件', components: '组件',
componentIndex: '介绍',
tinymce: '富文本编辑器', tinymce: '富文本编辑器',
markdown: 'Markdown', markdown: 'Markdown',
jsonEditor: 'JSON 编辑器', jsonEditor: 'JSON 编辑器',
@ -91,7 +89,7 @@ export default {
editPermission: '编辑权限', editPermission: '编辑权限',
roles: '你的权限', roles: '你的权限',
switchRoles: '切换权限', switchRoles: '切换权限',
tips: '在某些情况下,不适合使用 v-permission。例如Element-UI 的 Tab 组件或 el-table-column 以及其它动态渲染 dom 的场景。你只能通过手动设置 v-if 来实现。', tips: '在某些情况下,不适合使用 v-permission。例如Element-UI 的 el-tab 或 el-table-column 以及其它动态渲染 dom 的场景。你只能通过手动设置 v-if 来实现。',
delete: '删除', delete: '删除',
confirm: '确定', confirm: '确定',
cancel: '取消' cancel: '取消'

View File

@ -3,7 +3,7 @@
<logo v-if="showLogo" :collapse="isCollapse" /> <logo v-if="showLogo" :collapse="isCollapse" />
<el-scrollbar wrap-class="scrollbar-wrapper"> <el-scrollbar wrap-class="scrollbar-wrapper">
<el-menu <el-menu
:default-active="$route.path" :default-active="activeMenu"
:collapse="isCollapse" :collapse="isCollapse"
:background-color="variables.menuBg" :background-color="variables.menuBg"
:text-color="variables.menuText" :text-color="variables.menuText"
@ -30,6 +30,15 @@ export default {
'permission_routes', 'permission_routes',
'sidebar' 'sidebar'
]), ]),
activeMenu() {
const route = this.$route
const { meta, path } = route
// if set path, the sidebar will highlight the path you set
if (meta.activeMenu) {
return meta.activeMenu
}
return path
},
showLogo() { showLogo() {
return this.$store.state.settings.sidebarLogo return this.$store.state.settings.sidebarLogo
}, },

View File

@ -243,7 +243,7 @@ export default {
.contextmenu { .contextmenu {
margin: 0; margin: 0;
background: #fff; background: #fff;
z-index: 100; z-index: 3000;
position: absolute; position: absolute;
list-style-type: none; list-style-type: none;
padding: 5px 0; padding: 5px 0;

View File

@ -12,32 +12,32 @@ import chartsRouter from './modules/charts'
import tableRouter from './modules/table' import tableRouter from './modules/table'
import nestedRouter from './modules/nested' import nestedRouter from './modules/nested'
/** note: sub-menu only appear when children.length>=1
* detail see https://panjiachen.github.io/vue-element-admin-site/guide/essentials/router-and-nav.html
**/
/** /**
* hidden: true if `hidden:true` will not show in the sidebar(default is false) * Note: sub-menu only appear when route children.length >= 1
* alwaysShow: true if set true, will always show the root menu, whatever its child routes length * Detail see: https://panjiachen.github.io/vue-element-admin-site/guide/essentials/router-and-nav.html
* if not set alwaysShow, only more than one route under the children *
* hidden: true if set true, item will not show in the sidebar(default is false)
* alwaysShow: true if set true, will always show the root menu
* if not set alwaysShow, when item has more than one children route,
* it will becomes nested mode, otherwise not show the root menu * it will becomes nested mode, otherwise not show the root menu
* redirect: noredirect if `redirect:noredirect` will no redirect in the breadcrumb * redirect: noredirect if `redirect:noredirect` will no redirect in the breadcrumb
* name:'router-name' the name is used by <keep-alive> (must set!!!) * name:'router-name' the name is used by <keep-alive> (must set!!!)
* meta : { * meta : {
roles: ['admin','editor'] will control the page roles (you can set multiple roles) roles: ['admin','editor'] control the page roles (you can set multiple roles)
title: 'title' the name show in sub-menu and breadcrumb (recommend set) title: 'title' the name show in sidebar and breadcrumb (recommend set)
icon: 'svg-name' the icon show in the sidebar icon: 'svg-name' the icon show in the sidebar
noCache: true if true, the page will no be cached(default is false) noCache: true if set true, the page will no be cached(default is false)
breadcrumb: false if false, the item will hidden in breadcrumb(default is true) affix: true if set true, the tag will affix in the tags-view
affix: true if true, the tag will affix in the tags-view breadcrumb: false if set false, the item will hidden in breadcrumb(default is true)
activeMenu: '/example/list' if set path, the sidebar will highlight the path you set
} }
**/ */
/** /**
* constantRoutes * constantRoutes
* a base page that does not have permission requirements * a base page that does not have permission requirements
* all roles can be accessed * all roles can be accessed
* */ */
export const constantRoutes = [ export const constantRoutes = [
{ {
path: '/redirect', path: '/redirect',
@ -57,7 +57,7 @@ export const constantRoutes = [
}, },
{ {
path: '/auth-redirect', path: '/auth-redirect',
component: () => import('@/views/login/authredirect'), component: () => import('@/views/login/authRedirect'),
hidden: true hidden: true
}, },
{ {
@ -195,7 +195,7 @@ export const asyncRoutes = [
path: 'edit/:id(\\d+)', path: 'edit/:id(\\d+)',
component: () => import('@/views/example/edit'), component: () => import('@/views/example/edit'),
name: 'EditArticle', name: 'EditArticle',
meta: { title: 'editArticle', noCache: true }, meta: { title: 'editArticle', noCache: true, activeMenu: '/example/list' },
hidden: true hidden: true
}, },
{ {

View File

@ -1,24 +1,24 @@
import Vue from 'vue' import Vue from 'vue'
import Vuex from 'vuex' import Vuex from 'vuex'
import app from './modules/app'
import errorLog from './modules/errorLog'
import permission from './modules/permission'
import tagsView from './modules/tagsView'
import settings from './modules/settings'
import user from './modules/user'
import getters from './getters' import getters from './getters'
Vue.use(Vuex) Vue.use(Vuex)
// https://webpack.js.org/guides/dependency-management/#requirecontext
const modulesFiles = require.context('./modules', false, /\.js$/)
// you do not need `import app from './modules/app'`
// it will auto require all vuex module from modules file
const modules = modulesFiles.keys().reduce((modules, modulePath) => {
// set './app.js' => 'app'
const moduleName = modulePath.replace(/^\.\/(.*)\.\w+$/, '$1')
const value = modulesFiles(modulePath)
modules[moduleName] = value.default
return modules
}, {})
const store = new Vuex.Store({ const store = new Vuex.Store({
modules: { modules,
app,
errorLog,
permission,
tagsView,
settings,
user
},
getters getters
}) })

View File

@ -1,4 +1,5 @@
import Cookies from 'js-cookie' import Cookies from 'js-cookie'
import { getLanguage } from '@/lang/index'
const state = { const state = {
sidebar: { sidebar: {
@ -6,7 +7,7 @@ const state = {
withoutAnimation: false withoutAnimation: false
}, },
device: 'desktop', device: 'desktop',
language: Cookies.get('language') || 'en', language: getLanguage(),
size: Cookies.get('size') || 'medium' size: Cookies.get('size') || 'medium'
} }

View File

@ -1,4 +1,3 @@
const state = { const state = {
logs: [] logs: []
} }

View File

@ -1,4 +1,3 @@
const state = { const state = {
visitedViews: [], visitedViews: [],
cachedViews: [] cachedViews: []

View File

@ -28,10 +28,6 @@
.scrollbar-wrapper { .scrollbar-wrapper {
overflow-x: hidden !important; overflow-x: hidden !important;
.el-scrollbar__view {
height: 100%;
}
} }
.el-scrollbar__bar.is-vertical { .el-scrollbar__bar.is-vertical {

View File

@ -23,7 +23,7 @@ service.interceptors.request.use(
error => { error => {
// Do something with request error // Do something with request error
console.log(error) // for debug console.log(error) // for debug
Promise.reject(error) return Promise.reject(error)
} }
) )
@ -43,7 +43,7 @@ service.interceptors.response.use(
const res = response.data const res = response.data
if (res.code !== 20000) { if (res.code !== 20000) {
Message({ Message({
message: res.message, message: res.message || 'error',
type: 'error', type: 'error',
duration: 5 * 1000 duration: 5 * 1000
}) })
@ -61,7 +61,7 @@ service.interceptors.response.use(
}) })
}) })
} }
return Promise.reject('error') return Promise.reject(res.message || 'error')
} else { } else {
return res return res
} }

View File

@ -2,7 +2,7 @@
<div style="display:inline-block;"> <div style="display:inline-block;">
<!-- $t is vue-i18n global function to translate lang --> <!-- $t is vue-i18n global function to translate lang -->
<label class="radio-label" style="padding-left:0;">Filename: </label> <label class="radio-label" style="padding-left:0;">Filename: </label>
<el-input v-model="filename" :placeholder="$t('excel.placeholder')" style="width:340px;" prefix-icon="el-icon-document" /> <el-input v-model="filename" :placeholder="$t('excel.placeholder')" style="width:350px;" prefix-icon="el-icon-document" />
</div> </div>
</template> </template>

View File

@ -1,7 +1,7 @@
<template> <template>
<div class="app-container"> <div class="app-container">
<!-- $t is vue-i18n global function to translate lang --> <!-- $t is vue-i18n global function to translate lang -->
<el-input v-model="filename" :placeholder="$t('excel.placeholder')" style="width:340px;" prefix-icon="el-icon-document" /> <el-input v-model="filename" :placeholder="$t('excel.placeholder')" style="width:350px;" prefix-icon="el-icon-document" />
<el-button :loading="downloadLoading" style="margin-bottom:20px" type="primary" icon="document" @click="handleDownload"> <el-button :loading="downloadLoading" style="margin-bottom:20px" type="primary" icon="document" @click="handleDownload">
{{ $t('excel.selectedExport') }} {{ $t('excel.selectedExport') }}
</el-button> </el-button>

View File

@ -1,6 +1,6 @@
<script> <script>
export default { export default {
name: 'Authredirect', name: 'AuthRedirect',
created() { created() {
const hash = window.location.search.slice(1) const hash = window.location.search.slice(1)
if (window.localStorage) { if (window.localStorage) {

View File

@ -23,6 +23,7 @@
/> />
</el-form-item> </el-form-item>
<el-tooltip v-model="capsTooltip" content="Caps lock is On" placement="right" manual>
<el-form-item prop="password"> <el-form-item prop="password">
<span class="svg-container"> <span class="svg-container">
<svg-icon icon-class="password" /> <svg-icon icon-class="password" />
@ -35,12 +36,15 @@
:placeholder="$t('login.password')" :placeholder="$t('login.password')"
name="password" name="password"
auto-complete="on" auto-complete="on"
@keyup.native="checkCapslock"
@blur="capsTooltip = false"
@keyup.enter.native="handleLogin" @keyup.enter.native="handleLogin"
/> />
<span class="show-pwd" @click="showPwd"> <span class="show-pwd" @click="showPwd">
<svg-icon :icon-class="passwordType === 'password' ? 'eye' : 'eye-open'" /> <svg-icon :icon-class="passwordType === 'password' ? 'eye' : 'eye-open'" />
</span> </span>
</el-form-item> </el-form-item>
</el-tooltip>
<el-button :loading="loading" type="primary" style="width:100%;margin-bottom:30px;" @click.native.prevent="handleLogin"> <el-button :loading="loading" type="primary" style="width:100%;margin-bottom:30px;" @click.native.prevent="handleLogin">
{{ $t('login.logIn') }} {{ $t('login.logIn') }}
@ -77,7 +81,7 @@
<script> <script>
import { validUsername } from '@/utils/validate' import { validUsername } from '@/utils/validate'
import LangSelect from '@/components/LangSelect' import LangSelect from '@/components/LangSelect'
import SocialSign from './socialsignin' import SocialSign from './socialSignin'
export default { export default {
name: 'Login', name: 'Login',
@ -107,6 +111,7 @@ export default {
password: [{ required: true, trigger: 'blur', validator: validatePassword }] password: [{ required: true, trigger: 'blur', validator: validatePassword }]
}, },
passwordType: 'password', passwordType: 'password',
capsTooltip: false,
loading: false, loading: false,
showDialog: false, showDialog: false,
redirect: undefined redirect: undefined
@ -134,6 +139,18 @@ export default {
// window.removeEventListener('storage', this.afterQRScan) // window.removeEventListener('storage', this.afterQRScan)
}, },
methods: { methods: {
checkCapslock({ shiftKey, key } = {}) {
if (key && key.length === 1) {
if (shiftKey && (key >= 'a' && key <= 'z') || !shiftKey && (key >= 'A' && key <= 'Z')) {
this.capsTooltip = true
} else {
this.capsTooltip = false
}
}
if (key === 'CapsLock' && this.capsTooltip === true) {
this.capsTooltip = false
}
},
showPwd() { showPwd() {
if (this.passwordType === 'password') { if (this.passwordType === 'password') {
this.passwordType = '' this.passwordType = ''

View File

@ -1,9 +1,9 @@
<template> <template>
<div> <div>
<div style="margin-bottom:15px;"> <div style="margin-bottom:15px;">
{{ $t('permission.roles') }} {{ roles }} {{ $t('permission.roles') }}: {{ roles }}
</div> </div>
{{ $t('permission.switchRoles') }} {{ $t('permission.switchRoles') }}:
<el-radio-group v-model="switchRoles"> <el-radio-group v-model="switchRoles">
<el-radio-button label="editor" /> <el-radio-button label="editor" />
<el-radio-button label="admin" /> <el-radio-button label="admin" />

View File

@ -54,10 +54,10 @@
</el-table> </el-table>
<!-- $t is vue-i18n global function to translate lang (lang in @/lang) --> <!-- $t is vue-i18n global function to translate lang (lang in @/lang) -->
<div class="show-d"> <div class="show-d">
{{ $t('table.dragTips1') }} : &nbsp; {{ oldList }} <el-tag style="margin-right:12px;">{{ $t('table.dragTips1') }} :</el-tag> {{ oldList }}
</div> </div>
<div class="show-d"> <div class="show-d">
{{ $t('table.dragTips2') }} : {{ newList }} <el-tag>{{ $t('table.dragTips2') }} :</el-tag> {{ newList }}
</div> </div>
</div> </div>
</template> </template>
@ -113,9 +113,9 @@ export default {
this.sortable = Sortable.create(el, { this.sortable = Sortable.create(el, {
ghostClass: 'sortable-ghost', // Class name for the drop placeholder, ghostClass: 'sortable-ghost', // Class name for the drop placeholder,
setData: function(dataTransfer) { setData: function(dataTransfer) {
dataTransfer.setData('Text', '')
// to avoid Firefox bug // to avoid Firefox bug
// Detail see : https://github.com/RubaXa/Sortable/issues/1012 // Detail see : https://github.com/RubaXa/Sortable/issues/1012
dataTransfer.setData('Text', '')
}, },
onEnd: evt => { onEnd: evt => {
const targetRow = this.list.splice(evt.oldIndex, 1)[0] const targetRow = this.list.splice(evt.oldIndex, 1)[0]

View File

@ -3,7 +3,7 @@
<!-- $t is vue-i18n global function to translate lang --> <!-- $t is vue-i18n global function to translate lang -->
<el-input v-model="filename" :placeholder="$t('zip.placeholder')" style="width:300px;" prefix-icon="el-icon-document" /> <el-input v-model="filename" :placeholder="$t('zip.placeholder')" style="width:300px;" prefix-icon="el-icon-document" />
<el-button :loading="downloadLoading" style="margin-bottom:20px;" type="primary" icon="document" @click="handleDownload"> <el-button :loading="downloadLoading" style="margin-bottom:20px;" type="primary" icon="document" @click="handleDownload">
{{ $t('zip.export') }} zip {{ $t('zip.export') }} Zip
</el-button> </el-button>
<el-table v-loading="listLoading" :data="list" element-loading-text="拼命加载中" border fit highlight-current-row> <el-table v-loading="listLoading" :data="list" element-loading-text="拼命加载中" border fit highlight-current-row>
<el-table-column align="center" label="ID" width="95"> <el-table-column align="center" label="ID" width="95">

View File

@ -41,22 +41,7 @@ module.exports = {
} }
} }
}, },
after(app) { after: require('./mock/mock-server.js')
require('@babel/register')
const bodyParser = require('body-parser')
// parse app.body
// http://expressjs.com/en/4x/api.html#req.body
app.use(bodyParser.json())
app.use(bodyParser.urlencoded({
extended: true
}))
const { default: mocks } = require('./mock')
for (const mock of mocks) {
app[mock.type](mock.url, mock.response)
}
}
}, },
configureWebpack: { configureWebpack: {
// provide the app's title in webpack's name field, so that // provide the app's title in webpack's name field, so that