Merge pull request #8 from PanJiaChen/master

pull
This commit is contained in:
toruksmakto 2019-04-18 03:51:51 +08:00 committed by GitHub
commit 7f40044fc9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
127 changed files with 1000 additions and 694 deletions

View File

@ -1,4 +1,4 @@
# http://editorconfig.org # https://editorconfig.org
root = true root = true
[*] [*]

View File

@ -30,11 +30,11 @@ English | [简体中文](./README.zh-CN.md)
## Introduction ## Introduction
[vue-element-admin](http://panjiachen.github.io/vue-element-admin) is a production-ready front-end solution for admin interfaces. It based on [vue](https://github.com/vuejs/vue) and use the UI Toolkit [element-ui](https://github.com/ElemeFE/element). [vue-element-admin](https://panjiachen.github.io/vue-element-admin) is a production-ready front-end solution for admin interfaces. It based on [vue](https://github.com/vuejs/vue) and use the UI Toolkit [element-ui](https://github.com/ElemeFE/element).
It is a magical vue admin based on the newest development stack of vue, built-in i18n solution, typical templates for enterprise applications, lots of awesome features. It helps you build a large complex Single-Page Applications. I believe whatever your needs are, this project will help you. It is a magical vue admin based on the newest development stack of vue, built-in i18n solution, typical templates for enterprise applications, lots of awesome features. It helps you build a large complex Single-Page Applications. I believe whatever your needs are, this project will help you.
- [Preview](http://panjiachen.github.io/vue-element-admin) - [Preview](https://panjiachen.github.io/vue-element-admin)
- [Documentation](https://panjiachen.github.io/vue-element-admin-site/) - [Documentation](https://panjiachen.github.io/vue-element-admin-site/)
@ -50,13 +50,13 @@ It is a magical vue admin based on the newest development stack of vue, built-in
- Desktop: [electron-vue-admin](https://github.com/PanJiaChen/electron-vue-admin) - Desktop: [electron-vue-admin](https://github.com/PanJiaChen/electron-vue-admin)
- Typescript: [vue-typescript-admin-template](https://github.com/Armour/vue-typescript-admin-template) (Credits: [@Armour](https://github.com/Armour)) - Typescript: [vue-typescript-admin-template](https://github.com/Armour/vue-typescript-admin-template) (Credits: [@Armour](https://github.com/Armour))
**The current version is `4.0-beta`. If you find a problem, please put [issue](https://github.com/PanJiaChen/vue-element-admin/issues/new). If you want to use the old version - stable version, you can switch branch to [tag/3.11.0](https://github.com/PanJiaChen/vue-element-admin/tree/tag/3.11.0)** **The current version is `v4.0+` build on `vue-cli`. If you find a problem, please put [issue](https://github.com/PanJiaChen/vue-element-admin/issues/new). If you want to use the old version , you can switch branch to [tag/3.11.0](https://github.com/PanJiaChen/vue-element-admin/tree/tag/3.11.0), it does not rely on `vue-cli'**
**This project does not support low version browsers (e.g. IE). Please add polyfill by yourself.** **This project does not support low version browsers (e.g. IE). Please add polyfill by yourself.**
## Preparation ## Preparation
You need to install [node](http://nodejs.org/) and [git](https://git-scm.com/) locally. The project is based on [ES2015+](http://es6.ruanyifeng.com/), [vue](https://cn.vuejs.org/index.html), [vuex](https://vuex.vuejs.org/zh-cn/), [vue-router](https://router.vuejs.org/zh-cn/), [vue-cli](https://github.com/vuejs/vue-cli) , [axios](https://github.com/axios/axios) and [element-ui](https://github.com/ElemeFE/element), all request data is simulated using [Mock.js](https://github.com/nuysoft/Mock). You need to install [node](https://nodejs.org/) and [git](https://git-scm.com/) locally. The project is based on [ES2015+](https://es6.ruanyifeng.com/), [vue](https://cn.vuejs.org/index.html), [vuex](https://vuex.vuejs.org/zh-cn/), [vue-router](https://router.vuejs.org/zh-cn/), [vue-cli](https://github.com/vuejs/vue-cli) , [axios](https://github.com/axios/axios) and [element-ui](https://github.com/ElemeFE/element), all request data is simulated using [Mock.js](https://github.com/nuysoft/Mock).
Understanding and learning this knowledge in advance will greatly help the use of this project. Understanding and learning this knowledge in advance will greatly help the use of this project.
<p align="center"> <p align="center">
@ -187,7 +187,7 @@ Detailed changes for each release are documented in the [release notes](https://
## Online Demo ## Online Demo
[Preview](http://panjiachen.github.io/vue-element-admin) [Preview](https://panjiachen.github.io/vue-element-admin)
## Donate ## Donate
@ -203,7 +203,7 @@ If you find this project useful, you can buy author a glass of juice :tropical_d
Modern browsers and Internet Explorer 10+. Modern browsers and Internet Explorer 10+.
| [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/edge/edge_48x48.png" alt="IE / Edge" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>IE / Edge | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/firefox/firefox_48x48.png" alt="Firefox" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Firefox | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/chrome/chrome_48x48.png" alt="Chrome" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Chrome | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/safari/safari_48x48.png" alt="Safari" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Safari | | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/edge/edge_48x48.png" alt="IE / Edge" width="24px" height="24px" />](https://godban.github.io/browsers-support-badges/)</br>IE / Edge | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/firefox/firefox_48x48.png" alt="Firefox" width="24px" height="24px" />](https://godban.github.io/browsers-support-badges/)</br>Firefox | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/chrome/chrome_48x48.png" alt="Chrome" width="24px" height="24px" />](https://godban.github.io/browsers-support-badges/)</br>Chrome | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/safari/safari_48x48.png" alt="Safari" width="24px" height="24px" />](https://godban.github.io/browsers-support-badges/)</br>Safari |
| --------- | --------- | --------- | --------- | | --------- | --------- | --------- | --------- |
| IE10, IE11, Edge| last 2 versions| last 2 versions| last 2 versions | IE10, IE11, Edge| last 2 versions| last 2 versions| last 2 versions

View File

@ -30,9 +30,9 @@
## 简介 ## 简介
[vue-element-admin](http://panjiachen.github.io/vue-element-admin) 是一个后台前端解决方案,它基于 [vue](https://github.com/vuejs/vue) 和 [element-ui](https://github.com/ElemeFE/element)实现。它使用了最新的前端技术栈,内置了 i18n 国际化解决方案,动态路由,权限验证,提炼了典型的业务模型,提供了丰富的功能组件,它可以帮助你快速搭建企业级中后台产品原型。相信不管你的需求是什么,本项目都能帮助到你。 [vue-element-admin](https://panjiachen.github.io/vue-element-admin) 是一个后台前端解决方案,它基于 [vue](https://github.com/vuejs/vue) 和 [element-ui](https://github.com/ElemeFE/element)实现。它使用了最新的前端技术栈,内置了 i18n 国际化解决方案,动态路由,权限验证,提炼了典型的业务模型,提供了丰富的功能组件,它可以帮助你快速搭建企业级中后台产品原型。相信不管你的需求是什么,本项目都能帮助到你。
- [在线预览](http://panjiachen.github.io/vue-element-admin) - [在线预览](https://panjiachen.github.io/vue-element-admin)
- [使用文档](https://panjiachen.github.io/vue-element-admin-site/zh/) - [使用文档](https://panjiachen.github.io/vue-element-admin-site/zh/)
@ -50,7 +50,7 @@
- 桌面端: [electron-vue-admin](https://github.com/PanJiaChen/electron-vue-admin) - 桌面端: [electron-vue-admin](https://github.com/PanJiaChen/electron-vue-admin)
- Typescript 版: [vue-typescript-admin-template](https://github.com/Armour/vue-typescript-admin-template) (鸣谢: [@Armour](https://github.com/Armour)) - Typescript 版: [vue-typescript-admin-template](https://github.com/Armour/vue-typescript-admin-template) (鸣谢: [@Armour](https://github.com/Armour))
**目前版本为 `4.0-beta`,若发现问题,欢迎提[issue](https://github.com/PanJiaChen/vue-element-admin/issues/new)。若你想使用旧版本-稳定版,可以切换分支到[tag/3.11.0](https://github.com/PanJiaChen/vue-element-admin/tree/tag/3.11.0)** **目前版本为 `v4.0+` 基于 `vue-cli` 进行构建,若发现问题,欢迎提[issue](https://github.com/PanJiaChen/vue-element-admin/issues/new)。若你想使用旧版本,可以切换分支到[tag/3.11.0](https://github.com/PanJiaChen/vue-element-admin/tree/tag/3.11.0),它不依赖 `vue-cli`**
**该项目不支持低版本浏览器(如 ie),有需求请自行添加 polyfill [详情](https://github.com/PanJiaChen/vue-element-admin/wiki#babel-polyfill)** **该项目不支持低版本浏览器(如 ie),有需求请自行添加 polyfill [详情](https://github.com/PanJiaChen/vue-element-admin/wiki#babel-polyfill)**
@ -204,7 +204,7 @@ Detailed changes for each release are documented in the [release notes](https://
## Online Demo ## Online Demo
[在线 Demo](http://panjiachen.github.io/vue-element-admin) [在线 Demo](https://panjiachen.github.io/vue-element-admin)
## Donate ## Donate
@ -221,7 +221,7 @@ Detailed changes for each release are documented in the [release notes](https://
Modern browsers and Internet Explorer 10+. Modern browsers and Internet Explorer 10+.
| [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/edge/edge_48x48.png" alt="IE / Edge" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>IE / Edge | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/firefox/firefox_48x48.png" alt="Firefox" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Firefox | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/chrome/chrome_48x48.png" alt="Chrome" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Chrome | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/safari/safari_48x48.png" alt="Safari" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Safari | | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/edge/edge_48x48.png" alt="IE / Edge" width="24px" height="24px" />](https://godban.github.io/browsers-support-badges/)</br>IE / Edge | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/firefox/firefox_48x48.png" alt="Firefox" width="24px" height="24px" />](https://godban.github.io/browsers-support-badges/)</br>Firefox | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/chrome/chrome_48x48.png" alt="Chrome" width="24px" height="24px" />](https://godban.github.io/browsers-support-badges/)</br>Chrome | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/safari/safari_48x48.png" alt="Safari" width="24px" height="24px" />](https://godban.github.io/browsers-support-badges/)</br>Safari |
| --------- | --------- | --------- | --------- | | --------- | --------- | --------- | --------- |
| IE10, IE11, Edge| last 2 versions| last 2 versions| last 2 versions | IE10, IE11, Edge| last 2 versions| last 2 versions| last 2 versions

View File

@ -26,7 +26,7 @@ if (process.env.npm_config_preview || rawArgv.includes('--preview')) {
app.listen(port, function () { app.listen(port, function () {
console.log(chalk.green(`> Preview at http://localhost:${port}${publicPath}`)) console.log(chalk.green(`> Preview at http://localhost:${port}${publicPath}`))
if (report) { if (report) {
console.log(chalk.green(`> Report at http://localhost:${port}${publicPath}/report.html`)) console.log(chalk.green(`> Report at http://localhost:${port}${publicPath}report.html`))
} }
}) })

View File

@ -3,7 +3,7 @@ import Mock from 'mockjs'
const List = [] const List = []
const count = 100 const count = 100
const baseContent = '<p>我是测试数据我是测试数据</p><p><img src="https://wpimg.wallstcn.com/4c69009c-0fd4-4153-b112-6cb53d1cf943"></p>' const baseContent = '<p>I am testing data, I am testing data.</p><p><img src="https://wpimg.wallstcn.com/4c69009c-0fd4-4153-b112-6cb53d1cf943"></p>'
const image_uri = 'https://wpimg.wallstcn.com/e4558086-631c-425c-9430-56ffb46e70b3' const image_uri = 'https://wpimg.wallstcn.com/e4558086-631c-425c-9430-56ffb46e70b3'
for (let i = 0; i < count; i++) { for (let i = 0; i < count; i++) {

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 './remote-search'
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))

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

@ -0,0 +1,62 @@
const chokidar = require('chokidar')
const bodyParser = require('body-parser')
const chalk = require('chalk')
function registerRoutes(app) {
let mockLastIndex
const { default: mocks } = require('./index.js')
for (const mock of mocks) {
app[mock.type](mock.url, mock.response)
mockLastIndex = app._router.stack.length
}
const mockRoutesLength = Object.keys(mocks).length
return {
mockRoutesLength: mockRoutesLength,
mockStartIndex: mockLastIndex - mockRoutesLength
}
}
function unregisterRoutes() {
Object.keys(require.cache).forEach(i => {
if (i.includes('/mock')) {
delete require.cache[require.resolve(i)]
}
})
}
module.exports = app => {
// es6 polyfill
require('@babel/register')
// parse app.body
// https://expressjs.com/en/4x/api.html#req.body
app.use(bodyParser.json())
app.use(bodyParser.urlencoded({
extended: true
}))
const mockRoutes = registerRoutes(app)
var mockRoutesLength = mockRoutes.mockRoutesLength
var mockStartIndex = mockRoutes.mockStartIndex
// 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') {
// remove mock routes stack
app._router.stack.splice(mockStartIndex, mockRoutesLength)
// clear routes cache
unregisterRoutes()
const mockRoutes = registerRoutes(app)
mockRoutesLength = mockRoutes.mockRoutesLength
mockStartIndex = mockRoutes.mockStartIndex
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,17 +19,17 @@ export const constantRoutes = [
}, },
{ {
path: '/auth-redirect', path: '/auth-redirect',
component: 'views/login/authRedirect', component: 'views/login/auth-redirect',
hidden: true hidden: true
}, },
{ {
path: '/404', path: '/404',
component: 'views/errorPage/404', component: 'views/error-page/404',
hidden: true hidden: true
}, },
{ {
path: '/401', path: '/401',
component: 'views/errorPage/401', component: 'views/error-page/401',
hidden: true hidden: true
}, },
{ {
@ -119,7 +119,7 @@ export const asyncRoutes = [
children: [ children: [
{ {
path: 'index', path: 'index',
component: 'views/svg-icons/index', component: 'views/icons/index',
name: 'Icons', name: 'Icons',
meta: { title: 'icons', icon: 'icon', noCache: true } meta: { title: 'icons', icon: 'icon', noCache: true }
} }
@ -129,7 +129,7 @@ export const asyncRoutes = [
{ {
path: '/components', path: '/components',
component: 'layout/Layout', component: 'layout/Layout',
redirect: 'noredirect', redirect: 'noRedirect',
name: 'ComponentDemo', name: 'ComponentDemo',
meta: { meta: {
title: 'components', title: 'components',
@ -150,19 +150,19 @@ export const asyncRoutes = [
}, },
{ {
path: 'json-editor', path: 'json-editor',
component: 'views/components-demo/jsonEditor', component: 'views/components-demo/json-editor',
name: 'JsonEditorDemo', name: 'JsonEditorDemo',
meta: { title: 'jsonEditor' } meta: { title: 'jsonEditor' }
}, },
{ {
path: 'splitpane', path: 'split-pane',
component: 'views/components-demo/splitpane', component: 'views/components-demo/split-pane',
name: 'SplitpaneDemo', name: 'SplitpaneDemo',
meta: { title: 'splitPane' } meta: { title: 'splitPane' }
}, },
{ {
path: 'avatar-upload', path: 'avatar-upload',
component: 'views/components-demo/avatarUpload', component: 'views/components-demo/avatar-upload',
name: 'AvatarUploadDemo', name: 'AvatarUploadDemo',
meta: { title: 'avatarUpload' } meta: { title: 'avatarUpload' }
}, },
@ -180,7 +180,7 @@ export const asyncRoutes = [
}, },
{ {
path: 'count-to', path: 'count-to',
component: 'views/components-demo/countTo', component: 'views/components-demo/count-to',
name: 'CountToDemo', name: 'CountToDemo',
meta: { title: 'countTo' } meta: { title: 'countTo' }
}, },
@ -192,31 +192,31 @@ export const asyncRoutes = [
}, },
{ {
path: 'back-to-top', path: 'back-to-top',
component: 'views/components-demo/backToTop', component: 'views/components-demo/back-to-top',
name: 'BackToTopDemo', name: 'BackToTopDemo',
meta: { title: 'backToTop' } meta: { title: 'backToTop' }
}, },
{ {
path: 'drag-dialog', path: 'drag-dialog',
component: 'views/components-demo/dragDialog', component: 'views/components-demo/drag-dialog',
name: 'DragDialogDemo', name: 'DragDialogDemo',
meta: { title: 'dragDialog' } meta: { title: 'dragDialog' }
}, },
{ {
path: 'drag-select', path: 'drag-select',
component: 'views/components-demo/dragSelect', component: 'views/components-demo/drag-select',
name: 'DragSelectDemo', name: 'DragSelectDemo',
meta: { title: 'dragSelect' } meta: { title: 'dragSelect' }
}, },
{ {
path: 'dnd-list', path: 'dnd-list',
component: 'views/components-demo/dndList', component: 'views/components-demo/dnd-list',
name: 'DndListDemo', name: 'DndListDemo',
meta: { title: 'dndList' } meta: { title: 'dndList' }
}, },
{ {
path: 'drag-kanban', path: 'drag-kanban',
component: 'views/components-demo/dragKanban', component: 'views/components-demo/drag-kanban',
name: 'DragKanbanDemo', name: 'DragKanbanDemo',
meta: { title: 'dragKanban' } meta: { title: 'dragKanban' }
} }
@ -225,7 +225,7 @@ export const asyncRoutes = [
{ {
path: '/charts', path: '/charts',
component: 'layout/Layout', component: 'layout/Layout',
redirect: 'noredirect', redirect: 'noRedirect',
name: 'Charts', name: 'Charts',
meta: { meta: {
title: 'charts', title: 'charts',
@ -361,7 +361,7 @@ export const asyncRoutes = [
{ {
path: '/error', path: '/error',
component: 'layout/Layout', component: 'layout/Layout',
redirect: 'noredirect', redirect: 'noRedirect',
name: 'ErrorPages', name: 'ErrorPages',
meta: { meta: {
title: 'errorPages', title: 'errorPages',
@ -370,13 +370,13 @@ export const asyncRoutes = [
children: [ children: [
{ {
path: '401', path: '401',
component: 'views/errorPage/401', component: 'views/error-page/401',
name: 'Page401', name: 'Page401',
meta: { title: 'page401', noCache: true } meta: { title: 'page401', noCache: true }
}, },
{ {
path: '404', path: '404',
component: 'views/errorPage/404', component: 'views/error-page/404',
name: 'Page404', name: 'Page404',
meta: { title: 'page404', noCache: true } meta: { title: 'page404', noCache: true }
} }
@ -386,11 +386,11 @@ export const asyncRoutes = [
{ {
path: '/error-log', path: '/error-log',
component: 'layout/Layout', component: 'layout/Layout',
redirect: 'noredirect', redirect: 'noRedirect',
children: [ children: [
{ {
path: 'log', path: 'log',
component: 'views/errorLog/index', component: 'views/error-log/index',
name: 'ErrorLog', name: 'ErrorLog',
meta: { title: 'errorLog', icon: 'bug' } meta: { title: 'errorLog', icon: 'bug' }
} }
@ -409,25 +409,25 @@ export const asyncRoutes = [
children: [ children: [
{ {
path: 'export-excel', path: 'export-excel',
component: 'views/excel/exportExcel', component: 'views/excel/export-excel',
name: 'ExportExcel', name: 'ExportExcel',
meta: { title: 'exportExcel' } meta: { title: 'exportExcel' }
}, },
{ {
path: 'export-selected-excel', path: 'export-selected-excel',
component: 'views/excel/selectExcel', component: 'views/excel/select-excel',
name: 'SelectExcel', name: 'SelectExcel',
meta: { title: 'selectExcel' } meta: { title: 'selectExcel' }
}, },
{ {
path: 'export-merge-header', path: 'export-merge-header',
component: 'views/excel/mergeHeader', component: 'views/excel/merge-header',
name: 'MergeHeader', name: 'MergeHeader',
meta: { title: 'mergeHeader' } meta: { title: 'mergeHeader' }
}, },
{ {
path: 'upload-excel', path: 'upload-excel',
component: 'views/excel/uploadExcel', component: 'views/excel/upload-excel',
name: 'UploadExcel', name: 'UploadExcel',
meta: { title: 'uploadExcel' } meta: { title: 'uploadExcel' }
} }
@ -472,7 +472,7 @@ export const asyncRoutes = [
{ {
path: '/theme', path: '/theme',
component: 'layout/Layout', component: 'layout/Layout',
redirect: 'noredirect', redirect: 'noRedirect',
children: [ children: [
{ {
path: 'index', path: 'index',
@ -486,7 +486,7 @@ export const asyncRoutes = [
{ {
path: '/clipboard', path: '/clipboard',
component: 'layout/Layout', component: 'layout/Layout',
redirect: 'noredirect', redirect: 'noRedirect',
children: [ children: [
{ {
path: 'index', path: 'index',

View File

@ -1,6 +1,6 @@
{ {
"name": "vue-element-admin", "name": "vue-element-admin",
"version": "4.0.0", "version": "4.0.1",
"description": "A magical vue admin. An out-of-box UI solution for enterprise applications. Newest development stack of vue. Lots of awesome features", "description": "A magical vue admin. An out-of-box UI solution for enterprise applications. Newest development stack of vue. Lots of awesome features",
"author": "Pan <panfree23@gmail.com>", "author": "Pan <panfree23@gmail.com>",
"license": "MIT", "license": "MIT",
@ -75,6 +75,7 @@
"@babel/core": "7.0.0", "@babel/core": "7.0.0",
"@babel/register": "7.0.0", "@babel/register": "7.0.0",
"@vue/cli-plugin-babel": "3.5.3", "@vue/cli-plugin-babel": "3.5.3",
"@vue/cli-plugin-eslint": "3.5.1",
"@vue/cli-plugin-unit-jest": "3.5.3", "@vue/cli-plugin-unit-jest": "3.5.3",
"@vue/cli-service": "3.5.3", "@vue/cli-service": "3.5.3",
"@vue/test-utils": "1.0.0-beta.29", "@vue/test-utils": "1.0.0-beta.29",
@ -82,6 +83,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

@ -1,12 +1,7 @@
<template> <template>
<transition :name="transitionName"> <transition :name="transitionName">
<div v-show="visible" :style="customStyle" class="back-to-ceiling" @click="backToTop"> <div v-show="visible" :style="customStyle" class="back-to-ceiling" @click="backToTop">
<svg width="16" height="16" viewBox="0 0 17 17" xmlns="http://www.w3.org/2000/svg" class="Icon Icon--backToTopArrow" aria-hidden="true" style="height: 16px; width: 16px;"> <svg width="16" height="16" viewBox="0 0 17 17" xmlns="http://www.w3.org/2000/svg" class="Icon Icon--backToTopArrow" aria-hidden="true" style="height:16px;width:16px"><path d="M12.036 15.59a1 1 0 0 1-.997.995H5.032a.996.996 0 0 1-.997-.996V8.584H1.03c-1.1 0-1.36-.633-.578-1.416L7.33.29a1.003 1.003 0 0 1 1.412 0l6.878 6.88c.782.78.523 1.415-.58 1.415h-3.004v7.004z" /></svg>
<title>回到顶部</title>
<g>
<path d="M12.036 15.59c0 .55-.453.995-.997.995H5.032c-.55 0-.997-.445-.997-.996V8.584H1.03c-1.1 0-1.36-.633-.578-1.416L7.33.29c.39-.39 1.026-.385 1.412 0l6.878 6.88c.782.78.523 1.415-.58 1.415h-3.004v7.004z" fill-rule="evenodd" />
</g>
</svg>
</div> </div>
</transition> </transition>
</template> </template>

View File

@ -2,7 +2,7 @@
<el-breadcrumb class="app-breadcrumb" separator="/"> <el-breadcrumb class="app-breadcrumb" separator="/">
<transition-group name="breadcrumb"> <transition-group name="breadcrumb">
<el-breadcrumb-item v-for="(item,index) in levelList" :key="item.path"> <el-breadcrumb-item v-for="(item,index) in levelList" :key="item.path">
<span v-if="item.redirect==='noredirect'||index==levelList.length-1" class="no-redirect">{{ <span v-if="item.redirect==='noRedirect'||index==levelList.length-1" class="no-redirect">{{
generateTitle(item.meta.title) }}</span> generateTitle(item.meta.title) }}</span>
<a v-else @click.prevent="handleLink(item)">{{ generateTitle(item.meta.title) }}</a> <a v-else @click.prevent="handleLink(item)">{{ generateTitle(item.meta.title) }}</a>
</el-breadcrumb-item> </el-breadcrumb-item>
@ -31,15 +31,23 @@ export default {
methods: { methods: {
generateTitle, generateTitle,
getBreadcrumb() { getBreadcrumb() {
let matched = this.$route.matched.filter(item => item.name) // only show routes with meta.title
let matched = this.$route.matched.filter(item => item.meta && item.meta.title)
const first = matched[0] const first = matched[0]
if (first && first.name.trim().toLocaleLowerCase() !== 'Dashboard'.toLocaleLowerCase()) {
if (!this.isDashboard(first)) {
matched = [{ path: '/dashboard', meta: { title: 'dashboard' }}].concat(matched) matched = [{ path: '/dashboard', meta: { title: 'dashboard' }}].concat(matched)
} }
this.levelList = matched.filter(item => item.meta && item.meta.title && item.meta.breadcrumb !== false) this.levelList = matched.filter(item => item.meta && item.meta.title && item.meta.breadcrumb !== false)
}, },
isDashboard(route) {
const name = route && route.name
if (!name) {
return false
}
return name.trim().toLocaleLowerCase() === 'Dashboard'.toLocaleLowerCase()
},
pathCompile(path) { pathCompile(path) {
// To solve this problem https://github.com/PanJiaChen/vue-element-admin/issues/561 // To solve this problem https://github.com/PanJiaChen/vue-element-admin/issues/561
const { params } = this.$route const { params } = this.$route

View File

@ -0,0 +1,155 @@
<template>
<div :id="id" :class="className" :style="{height:height,width:width}" />
</template>
<script>
import echarts from 'echarts'
import resize from './mixins/resize'
export default {
mixins: [resize],
props: {
className: {
type: String,
default: 'chart'
},
id: {
type: String,
default: 'chart'
},
width: {
type: String,
default: '200px'
},
height: {
type: String,
default: '200px'
}
},
data() {
return {
chart: null
}
},
mounted() {
this.initChart()
},
beforeDestroy() {
if (!this.chart) {
return
}
this.chart.dispose()
this.chart = null
},
methods: {
initChart() {
this.chart = echarts.init(document.getElementById(this.id))
const xAxisData = []
const data = []
const data2 = []
for (let i = 0; i < 50; i++) {
xAxisData.push(i)
data.push((Math.sin(i / 5) * (i / 5 - 10) + i / 6) * 5)
data2.push((Math.sin(i / 5) * (i / 5 + 10) + i / 6) * 3)
}
this.chart.setOption({
backgroundColor: '#08263a',
grid: {
left: '5%',
right: '5%'
},
xAxis: [{
show: false,
data: xAxisData
}, {
show: false,
data: xAxisData
}],
visualMap: {
show: false,
min: 0,
max: 50,
dimension: 0,
inRange: {
color: ['#4a657a', '#308e92', '#b1cfa5', '#f5d69f', '#f5898b', '#ef5055']
}
},
yAxis: {
axisLine: {
show: false
},
axisLabel: {
textStyle: {
color: '#4a657a'
}
},
splitLine: {
show: true,
lineStyle: {
color: '#08263f'
}
},
axisTick: {
show: false
}
},
series: [{
name: 'back',
type: 'bar',
data: data2,
z: 1,
itemStyle: {
normal: {
opacity: 0.4,
barBorderRadius: 5,
shadowBlur: 3,
shadowColor: '#111'
}
}
}, {
name: 'Simulate Shadow',
type: 'line',
data,
z: 2,
showSymbol: false,
animationDelay: 0,
animationEasing: 'linear',
animationDuration: 1200,
lineStyle: {
normal: {
color: 'transparent'
}
},
areaStyle: {
normal: {
color: '#08263a',
shadowBlur: 50,
shadowColor: '#000'
}
}
}, {
name: 'front',
type: 'bar',
data,
xAxisIndex: 1,
z: 3,
itemStyle: {
normal: {
barBorderRadius: 5
}
}
}],
animationEasing: 'elasticOut',
animationEasingUpdate: 'elasticOut',
animationDelay(idx) {
return idx * 20
},
animationDelayUpdate(idx) {
return idx * 20
}
})
}
}
}
</script>

View File

@ -1,156 +0,0 @@
<template>
<div :id="id" :class="className" :style="{height:height,width:width}" />
</template>
<script>
import echarts from 'echarts'
import resize from './mixins/resize'
export default {
mixins: [resize],
props: {
className: {
type: String,
default: 'chart'
},
id: {
type: String,
default: 'chart'
},
width: {
type: String,
default: '200px'
},
height: {
type: String,
default: '200px'
}
},
data() {
return {
chart: null
}
},
mounted() {
this.initChart()
},
beforeDestroy() {
if (!this.chart) {
return
}
this.chart.dispose()
this.chart = null
},
methods: {
initChart() {
this.chart = echarts.init(document.getElementById(this.id))
const xAxisData = []
const data = []
const data2 = []
for (let i = 0; i < 50; i++) {
xAxisData.push(i)
data.push((Math.sin(i / 5) * (i / 5 - 10) + i / 6) * 5)
data2.push((Math.sin(i / 5) * (i / 5 + 10) + i / 6) * 3)
}
this.chart.setOption(
{
backgroundColor: '#08263a',
grid: {
left: '5%',
right: '5%'
},
xAxis: [{
show: false,
data: xAxisData
}, {
show: false,
data: xAxisData
}],
visualMap: {
show: false,
min: 0,
max: 50,
dimension: 0,
inRange: {
color: ['#4a657a', '#308e92', '#b1cfa5', '#f5d69f', '#f5898b', '#ef5055']
}
},
yAxis: {
axisLine: {
show: false
},
axisLabel: {
textStyle: {
color: '#4a657a'
}
},
splitLine: {
show: true,
lineStyle: {
color: '#08263f'
}
},
axisTick: {
show: false
}
},
series: [{
name: 'back',
type: 'bar',
data: data2,
z: 1,
itemStyle: {
normal: {
opacity: 0.4,
barBorderRadius: 5,
shadowBlur: 3,
shadowColor: '#111'
}
}
}, {
name: 'Simulate Shadow',
type: 'line',
data,
z: 2,
showSymbol: false,
animationDelay: 0,
animationEasing: 'linear',
animationDuration: 1200,
lineStyle: {
normal: {
color: 'transparent'
}
},
areaStyle: {
normal: {
color: '#08263a',
shadowBlur: 50,
shadowColor: '#000'
}
}
}, {
name: 'front',
type: 'bar',
data,
xAxisIndex: 1,
z: 3,
itemStyle: {
normal: {
barBorderRadius: 5
}
}
}],
animationEasing: 'elasticOut',
animationEasingUpdate: 'elasticOut',
animationDelay(idx) {
return idx * 20
},
animationDelayUpdate(idx) {
return idx * 20
}
})
}
}
}
</script>

View File

@ -3,7 +3,7 @@ import { debounce } from '@/utils'
export default { export default {
data() { data() {
return { return {
sidebarElm: null $_sidebarElm: null
} }
}, },
mounted() { mounted() {
@ -14,16 +14,18 @@ export default {
}, 100) }, 100)
window.addEventListener('resize', this.__resizeHandler) window.addEventListener('resize', this.__resizeHandler)
this.sidebarElm = document.getElementsByClassName('sidebar-container')[0] this.$_sidebarElm = document.getElementsByClassName('sidebar-container')[0]
this.sidebarElm && this.sidebarElm.addEventListener('transitionend', this.sidebarResizeHandler) this.$_sidebarElm && this.$_sidebarElm.addEventListener('transitionend', this.$_sidebarResizeHandler)
}, },
beforeDestroy() { beforeDestroy() {
window.removeEventListener('resize', this.__resizeHandler) window.removeEventListener('resize', this.__resizeHandler)
this.sidebarElm && this.sidebarElm.removeEventListener('transitionend', this.sidebarResizeHandler) this.$_sidebarElm && this.$_sidebarElm.removeEventListener('transitionend', this.$_sidebarResizeHandler)
}, },
methods: { methods: {
sidebarResizeHandler(e) { // use $_ for mixins properties
// https://vuejs.org/v2/style-guide/index.html#Private-property-names-essential
$_sidebarResizeHandler(e) {
if (e.propertyName === 'width') { if (e.propertyName === 'width') {
this.__resizeHandler() this.__resizeHandler()
} }

View File

@ -49,13 +49,13 @@ export default {
</script> </script>
<style scoped> <style scoped>
.drag-select >>> .sortable-ghost{ .drag-select >>> .sortable-ghost {
opacity: .8; opacity: .8;
color: #fff!important; color: #fff!important;
background: #42b983!important; background: #42b983!important;
} }
.drag-select >>> .el-tag{ .drag-select >>> .el-tag {
cursor: pointer; cursor: pointer;
} }
</style> </style>

View File

@ -121,7 +121,7 @@ export default {
data.title = [...data.title, i18ntitle] data.title = [...data.title, i18ntitle]
if (router.redirect !== 'noredirect') { if (router.redirect !== 'noRedirect') {
// only push the routes with title // only push the routes with title
// special case: need to exclude parent router without redirect // special case: need to exclude parent router without redirect
res.push(data) res.push(data)

View File

@ -25,8 +25,8 @@ export default {
}, },
watch: { watch: {
value(value) { value(value) {
const editor_value = this.jsonEditor.getValue() const editorValue = this.jsonEditor.getValue()
if (value !== editor_value) { if (value !== editorValue) {
this.jsonEditor.setValue(JSON.stringify(this.value, null, 2)) this.jsonEditor.setValue(JSON.stringify(this.value, null, 2))
} }
} }

View File

@ -15,6 +15,7 @@
</draggable> </draggable>
</div> </div>
</template> </template>
<script> <script>
import draggable from 'vuedraggable' import draggable from 'vuedraggable'

View File

@ -9,7 +9,7 @@ import 'tui-editor/dist/tui-editor.css' // editor ui
import 'tui-editor/dist/tui-editor-contents.css' // editor content import 'tui-editor/dist/tui-editor-contents.css' // editor content
import Editor from 'tui-editor' import Editor from 'tui-editor'
import defaultOptions from './defaultOptions' import defaultOptions from './default-options'
export default { export default {
name: 'MarddownEditor', name: 'MarddownEditor',

View File

@ -15,7 +15,7 @@
</template> </template>
<script> <script>
import { scrollTo } from '@/utils/scrollTo' import { scrollTo } from '@/utils/scroll-to'
export default { export default {
name: 'Pagination', name: 'Pagination',

View File

@ -8,19 +8,28 @@
</template> </template>
<script> <script>
const version = require('element-ui/package.json').version // element-ui version from node_modules const version = require('element-ui/package.json').version // element-ui version from node_modules
const ORIGINAL_THEME = '#409EFF' // default color const ORIGINAL_THEME = '#409EFF' // default color
import defaultSettings from '@/settings'
export default { export default {
data() { data() {
return { return {
chalk: '', // content of theme-chalk css chalk: '', // content of theme-chalk css
theme: defaultSettings.theme theme: ''
}
},
computed: {
defaultTheme() {
return this.$store.state.settings.theme
} }
}, },
watch: { watch: {
defaultTheme: {
handler: function(val, oldVal) {
this.theme = val
},
immediate: true
},
async theme(val) { async theme(val) {
const oldVal = this.chalk ? this.theme : ORIGINAL_THEME const oldVal = this.chalk ? this.theme : ORIGINAL_THEME
if (typeof val !== 'string') return if (typeof val !== 'string') return

View File

@ -1,7 +1,7 @@
<template> <template>
<div class="upload-container"> <div class="upload-container">
<el-button :style="{background:color,borderColor:color}" icon="el-icon-upload" size="mini" type="primary" @click=" dialogVisible=true"> <el-button :style="{background:color,borderColor:color}" icon="el-icon-upload" size="mini" type="primary" @click=" dialogVisible=true">
上传图片 upload
</el-button> </el-button>
<el-dialog :visible.sync="dialogVisible"> <el-dialog :visible.sync="dialogVisible">
<el-upload <el-upload
@ -16,14 +16,14 @@
list-type="picture-card" list-type="picture-card"
> >
<el-button size="small" type="primary"> <el-button size="small" type="primary">
点击上传 Click upload
</el-button> </el-button>
</el-upload> </el-upload>
<el-button @click="dialogVisible = false"> <el-button @click="dialogVisible = false">
Cancel
</el-button> </el-button>
<el-button type="primary" @click="handleSubmit"> <el-button type="primary" @click="handleSubmit">
Confirm
</el-button> </el-button>
</el-dialog> </el-dialog>
</div> </div>
@ -54,7 +54,7 @@ export default {
handleSubmit() { handleSubmit() {
const arr = Object.keys(this.listObj).map(v => this.listObj[v]) const arr = Object.keys(this.listObj).map(v => this.listObj[v])
if (!this.checkAllSuccess()) { if (!this.checkAllSuccess()) {
this.$message('请等待所有图片上传成功 或 出现了网络问题,请刷新页面重新上传!') this.$message('Please wait for all images to be uploaded successfully. If there is a network problem, please refresh the page and upload again!')
return return
} }
this.$emit('successCBK', arr) this.$emit('successCBK', arr)

View File

@ -8,7 +8,7 @@
</template> </template>
<script> <script>
import editorImage from './components/editorImage' import editorImage from './components/EditorImage'
import plugins from './plugins' import plugins from './plugins'
import toolbar from './toolbar' import toolbar from './toolbar'

View File

@ -26,7 +26,6 @@
</template> </template>
<script> <script>
//
import { getToken } from '@/api/qiniu' import { getToken } from '@/api/qiniu'
export default { export default {

View File

@ -1,11 +1,10 @@
import { addResizeListener, removeResizeListener } from 'element-ui/src/utils/resize-event' import { addResizeListener, removeResizeListener } from 'element-ui/src/utils/resize-event'
/** /**
* How to use * How to use
* <el-table height="100px" v-el-height-adaptive-table="{bottomOffset: 30}">...</el-table> * <el-table height="100px" v-el-height-adaptive-table="{bottomOffset: 30}">...</el-table>
* el-table height is must be set * el-table height is must be set
* bottomOffset: 30(default) // The height of the table from the bottom of the page. * bottomOffset: 30(default) // The height of the table from the bottom of the page.
*/ */
const doResize = (el, binding, vnode) => { const doResize = (el, binding, vnode) => {
@ -30,13 +29,13 @@ export default {
el.resizeListener = () => { el.resizeListener = () => {
doResize(el, binding, vnode) doResize(el, binding, vnode)
} }
// parameter 1 is must be "Element" type
addResizeListener(el, el.resizeListener) addResizeListener(window.document.body, el.resizeListener)
}, },
inserted(el, binding, vnode) { inserted(el, binding, vnode) {
doResize(el, binding, vnode) doResize(el, binding, vnode)
}, },
unbind(el) { unbind(el) {
removeResizeListener(el, el.resizeListener) removeResizeListener(window.document.body, el.resizeListener)
} }
} }

View File

@ -1,4 +1,3 @@
import adaptive from './adaptive' import adaptive from './adaptive'
const install = function(Vue) { const install = function(Vue) {

View File

@ -1,4 +1,3 @@
import store from '@/store' import store from '@/store'
export default { export default {

View File

@ -1,6 +1,12 @@
// set function parseTime,formatTime to filter // import parseTime, formatTime and set to filter
export { parseTime, formatTime } from '@/utils' export { parseTime, formatTime } from '@/utils'
/**
* Show plural label if time is plural number
* @param {number} time
* @param {string} label
* @return {string}
*/
function pluralize(time, label) { function pluralize(time, label) {
if (time === 1) { if (time === 1) {
return time + label return time + label
@ -8,6 +14,9 @@ function pluralize(time, label) {
return time + label + 's' return time + label + 's'
} }
/**
* @param {number} time
*/
export function timeAgo(time) { export function timeAgo(time) {
const between = Date.now() / 1000 - Number(time) const between = Date.now() / 1000 - Number(time)
if (between < 3600) { if (between < 3600) {
@ -19,7 +28,12 @@ export function timeAgo(time) {
} }
} }
/* 数字 格式化*/ /**
* Number formatting
* like 10000 => 10k
* @param {number} num
* @param {number} digits
*/
export function numberFormatter(num, digits) { export function numberFormatter(num, digits) {
const si = [ const si = [
{ value: 1E18, symbol: 'E' }, { value: 1E18, symbol: 'E' },
@ -37,6 +51,10 @@ export function numberFormatter(num, digits) {
return num.toString() return num.toString()
} }
/**
* 10000 => "10,000"
* @param {number} num
*/
export function toThousandFilter(num) { export function toThousandFilter(num) {
return (+num || 0).toString().replace(/^-?\d+/g, m => m.replace(/(?=(?!\b)(\d{3})+$)/g, ',')) return (+num || 0).toString().replace(/^-?\d+/g, m => m.replace(/(?=(?!\b)(\d{3})+$)/g, ','))
} }

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',
@ -19,9 +17,9 @@ export default {
avatarUpload: 'Avatar Upload', avatarUpload: 'Avatar Upload',
dropzone: 'Dropzone', dropzone: 'Dropzone',
sticky: 'Sticky', sticky: 'Sticky',
countTo: 'CountTo', countTo: 'Count To',
componentMixin: 'Mixin', componentMixin: 'Mixin',
backToTop: 'BackToTop', backToTop: 'Back To Top',
dragDialog: 'Drag Dialog', dragDialog: 'Drag Dialog',
dragSelect: 'Drag Select', dragSelect: 'Drag Select',
dragKanban: 'Drag Kanban', dragKanban: 'Drag Kanban',
@ -74,7 +72,7 @@ export default {
}, },
login: { login: {
title: 'Login Form', title: 'Login Form',
logIn: 'Log in', logIn: 'Login',
username: 'Username', username: 'Username',
password: 'Password', password: 'Password',
any: 'any', any: 'any',
@ -87,10 +85,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'
@ -101,7 +99,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',
@ -134,6 +132,9 @@ export default {
cancel: 'Cancel', cancel: 'Cancel',
confirm: 'Confirm' confirm: 'Confirm'
}, },
example: {
warning: 'Creating and editing pages cannot be cached by keep-alive because keep-alive include does not currently support caching based on routes, so it is currently cached based on component name. If you want to achieve a similar caching effect, you can use a browser caching scheme such as localStorage. Or do not use keep-alive include to cache all pages directly. See details'
},
errorLog: { errorLog: {
tips: 'Please click the bug icon in the upper right corner', tips: 'Please click the bug icon in the upper right corner',
description: 'Now the management system are basically the form of the spa, it enhances the user experience, but it also increases the possibility of page problems, a small negligence may lead to the entire page deadlock. Fortunately Vue provides a way to catch handling exceptions, where you can handle errors or report exceptions.', description: 'Now the management system are basically the form of the spa, it enhances the user experience, but it also increases the possibility of page problems, a small negligence may lead to the entire page deadlock. Fortunately Vue provides a way to catch handling exceptions, where you can handle errors or report exceptions.',
@ -142,14 +143,14 @@ export default {
excel: { excel: {
export: 'Export', export: 'Export',
selectedExport: 'Export Selected Items', selectedExport: 'Export Selected Items',
placeholder: 'Please enter the file name(default excel-list)' placeholder: 'Please enter the file name (default excel-list)'
}, },
zip: { zip: {
export: 'Export', export: 'Export',
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',
@ -134,6 +132,9 @@ export default {
cancel: 'Cancelar', cancel: 'Cancelar',
confirm: 'Confirmar' confirm: 'Confirmar'
}, },
example: {
warning: 'Creating and editing pages cannot be cached by keep-alive because keep-alive include does not currently support caching based on routes, so it is currently cached based on component name. If you want to achieve a similar caching effect, you can use a browser caching scheme such as localStorage. Or do not use keep-alive include to cache all pages directly. See details'
},
errorLog: { errorLog: {
tips: 'Please click the bug icon in the upper right corner', tips: 'Please click the bug icon in the upper right corner',
description: 'Now the management system are basically the form of the spa, it enhances the user experience, but it also increases the possibility of page problems, a small negligence may lead to the entire page deadlock. Fortunately Vue provides a way to catch handling exceptions, where you can handle errors or report exceptions.', description: 'Now the management system are basically the form of the spa, it enhances the user experience, but it also increases the possibility of page problems, a small negligence may lead to the entire page deadlock. Fortunately Vue provides a way to catch handling exceptions, where you can handle errors or report exceptions.',

View File

@ -1,7 +1,6 @@
export default { export default {
route: { route: {
dashboard: '首页', dashboard: '首页',
introduction: '简述',
documentation: '文档', documentation: '文档',
guide: '引导页', guide: '引导页',
permission: '权限测试页', permission: '权限测试页',
@ -10,16 +9,15 @@ export default {
directivePermission: '指令权限', directivePermission: '指令权限',
icons: '图标', icons: '图标',
components: '组件', components: '组件',
componentIndex: '介绍',
tinymce: '富文本编辑器', tinymce: '富文本编辑器',
markdown: 'Markdown', markdown: 'Markdown',
jsonEditor: 'JSON编辑器', jsonEditor: 'JSON 编辑器',
dndList: '列表拖拽', dndList: '列表拖拽',
splitPane: 'Splitpane', splitPane: 'Splitpane',
avatarUpload: '头像上传', avatarUpload: '头像上传',
dropzone: 'Dropzone', dropzone: 'Dropzone',
sticky: 'Sticky', sticky: 'Sticky',
countTo: 'CountTo', countTo: 'Count To',
componentMixin: '小组件', componentMixin: '小组件',
backToTop: '返回顶部', backToTop: '返回顶部',
dragDialog: '拖拽 Dialog', dragDialog: '拖拽 Dialog',
@ -32,17 +30,17 @@ export default {
example: '综合实例', example: '综合实例',
nested: '路由嵌套', nested: '路由嵌套',
menu1: '菜单1', menu1: '菜单1',
'menu1-1': '菜单1-1', 'menu1-1': '菜单 1-1',
'menu1-2': '菜单1-2', 'menu1-2': '菜单 1-2',
'menu1-2-1': '菜单1-2-1', 'menu1-2-1': '菜单 1-2-1',
'menu1-2-2': '菜单1-2-2', 'menu1-2-2': '菜单 1-2-2',
'menu1-3': '菜单1-3', 'menu1-3': '菜单 1-3',
menu2: '菜单2', menu2: '菜单 2',
Table: 'Table', Table: 'Table',
dynamicTable: '动态Table', dynamicTable: '动态 Table',
dragTable: '拖拽Table', dragTable: '拖拽 Table',
inlineEditTable: 'Table内编辑', inlineEditTable: 'Table 内编辑',
complexTable: '综合Table', complexTable: '综合 Table',
tab: 'Tab', tab: 'Tab',
form: '表单', form: '表单',
createArticle: '创建文章', createArticle: '创建文章',
@ -90,7 +88,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: '取消'
@ -134,6 +132,9 @@ export default {
cancel: '取 消', cancel: '取 消',
confirm: '确 定' confirm: '确 定'
}, },
example: {
warning: '创建和编辑页面是不能被 keep-alive 缓存的因为keep-alive 的 include 目前不支持根据路由来缓存,所以目前都是基于 component name 来进行缓存的。如果你想类似的实现缓存效果,可以使用 localStorage 等浏览器缓存方案。或者不要使用 keep-alive 的 include直接缓存所有页面。详情见'
},
errorLog: { errorLog: {
tips: '请点击右上角bug小图标', tips: '请点击右上角bug小图标',
description: '现在的管理后台基本都是spa的形式了它增强了用户体验但同时也会增加页面出问题的可能性可能一个小小的疏忽就导致整个页面的死锁。好在 Vue 官网提供了一个方法来捕获处理异常,你可以在其中进行错误处理或者异常上报。', description: '现在的管理后台基本都是spa的形式了它增强了用户体验但同时也会增加页面出问题的可能性可能一个小小的疏忽就导致整个页面的死锁。好在 Vue 官网提供了一个方法来捕获处理异常,你可以在其中进行错误处理或者异常上报。',

View File

@ -86,6 +86,9 @@ export default {
if (isExternal(routePath)) { if (isExternal(routePath)) {
return routePath return routePath
} }
if (isExternal(this.basePath)) {
return this.basePath
}
return path.resolve(this.basePath, routePath) return path.resolve(this.basePath, routePath)
}, },

View File

@ -3,10 +3,11 @@
<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"
:unique-opened="false"
:active-text-color="variables.menuActiveText" :active-text-color="variables.menuActiveText"
:collapse-transition="false" :collapse-transition="false"
mode="vertical" mode="vertical"
@ -30,6 +31,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

@ -145,7 +145,7 @@ export default {
closeSelectedTag(view) { closeSelectedTag(view) {
this.$store.dispatch('tagsView/delView', view).then(({ visitedViews }) => { this.$store.dispatch('tagsView/delView', view).then(({ visitedViews }) => {
if (this.isActive(view)) { if (this.isActive(view)) {
this.toLastView(visitedViews) this.toLastView(visitedViews, view)
} }
}) })
}, },
@ -160,16 +160,22 @@ export default {
if (this.affixTags.some(tag => tag.path === view.path)) { if (this.affixTags.some(tag => tag.path === view.path)) {
return return
} }
this.toLastView(visitedViews) this.toLastView(visitedViews, view)
}) })
}, },
toLastView(visitedViews) { toLastView(visitedViews, view) {
const latestView = visitedViews.slice(-1)[0] const latestView = visitedViews.slice(-1)[0]
if (latestView) { if (latestView) {
this.$router.push(latestView) this.$router.push(latestView)
} else { } else {
// You can set another route // now the default is to redirect to the home page if there is no tags-view,
this.$router.push('/') // you can adjust it according to your needs.
if (view.name === 'Dashboard') {
// to reload home page
this.$router.replace({ path: '/redirect' + view.fullPath })
} else {
this.$router.push('/')
}
} }
}, },
openMenu(tag, e) { openMenu(tag, e) {

View File

@ -1,5 +1,5 @@
export { default as AppMain } from './AppMain'
export { default as Navbar } from './Navbar' export { default as Navbar } from './Navbar'
export { default as Settings } from './Settings'
export { default as Sidebar } from './Sidebar/index.vue' export { default as Sidebar } from './Sidebar/index.vue'
export { default as TagsView } from './TagsView/index.vue' export { default as TagsView } from './TagsView/index.vue'
export { default as AppMain } from './AppMain'
export { default as Settings } from './Settings'

View File

@ -17,19 +17,19 @@
<script> <script>
import RightPanel from '@/components/RightPanel' import RightPanel from '@/components/RightPanel'
import { Navbar, Sidebar, AppMain, TagsView, Settings } from './components' import { AppMain, Navbar, Settings, Sidebar, TagsView } from './components'
import ResizeMixin from './mixin/ResizeHandler' import ResizeMixin from './mixin/ResizeHandler'
import { mapState } from 'vuex' import { mapState } from 'vuex'
export default { export default {
name: 'Layout', name: 'Layout',
components: { components: {
RightPanel,
Navbar,
Sidebar,
AppMain, AppMain,
TagsView, Navbar,
Settings RightPanel,
Settings,
Sidebar,
TagsView
}, },
mixins: [ResizeMixin], mixins: [ResizeMixin],
computed: { computed: {

View File

@ -12,26 +12,28 @@ export default {
} }
}, },
beforeMount() { beforeMount() {
window.addEventListener('resize', this.resizeHandler) window.addEventListener('resize', this.$_resizeHandler)
}, },
beforeDestroy() { beforeDestroy() {
window.removeEventListener('resize', this.resizeHandler) window.removeEventListener('resize', this.$_resizeHandler)
}, },
mounted() { mounted() {
const isMobile = this.isMobile() const isMobile = this.$_isMobile()
if (isMobile) { if (isMobile) {
store.dispatch('app/toggleDevice', 'mobile') store.dispatch('app/toggleDevice', 'mobile')
store.dispatch('app/closeSideBar', { withoutAnimation: true }) store.dispatch('app/closeSideBar', { withoutAnimation: true })
} }
}, },
methods: { methods: {
isMobile() { // use $_ for mixins properties
// https://vuejs.org/v2/style-guide/index.html#Private-property-names-essential
$_isMobile() {
const rect = body.getBoundingClientRect() const rect = body.getBoundingClientRect()
return rect.width - 1 < WIDTH return rect.width - 1 < WIDTH
}, },
resizeHandler() { $_resizeHandler() {
if (!document.hidden) { if (!document.hidden) {
const isMobile = this.isMobile() const isMobile = this.$_isMobile()
store.dispatch('app/toggleDevice', isMobile ? 'mobile' : 'desktop') store.dispatch('app/toggleDevice', isMobile ? 'mobile' : 'desktop')
if (isMobile) { if (isMobile) {

View File

@ -2,7 +2,7 @@ import Vue from 'vue'
import Cookies from 'js-cookie' import Cookies from 'js-cookie'
import 'normalize.css/normalize.css' // A modern alternative to CSS resets import 'normalize.css/normalize.css' // a modern alternative to CSS resets
import Element from 'element-ui' import Element from 'element-ui'
import './styles/element-variables.scss' import './styles/element-variables.scss'
@ -13,24 +13,28 @@ import App from './App'
import store from './store' import store from './store'
import router from './router' import router from './router'
import i18n from './lang' // Internationalization import i18n from './lang' // internationalization
import './icons' // icon import './icons' // icon
import './permission' // permission control import './permission' // permission control
import './utils/errorLog' // error log import './utils/error-log' // error log
import * as filters from './filters' // global filters import * as filters from './filters' // global filters
import { mockXHR } from '../mock' // simulation data /**
* If you don't want to use mock-server
// mock api in github pages site build * you want to use mockjs for request interception
if (process.env.NODE_ENV === 'production') { mockXHR() } * you can execute:
*
* import { mockXHR } from '../mock'
* mockXHR()
*/
Vue.use(Element, { Vue.use(Element, {
size: Cookies.get('size') || 'medium', // set element-ui default size size: Cookies.get('size') || 'medium', // set element-ui default size
i18n: (key, value) => i18n.t(key, value) i18n: (key, value) => i18n.t(key, value)
}) })
// register global utility filters. // register global utility filters
Object.keys(filters).forEach(key => { Object.keys(filters).forEach(key => {
Vue.filter(key, filters[key]) Vue.filter(key, filters[key])
}) })

View File

@ -4,6 +4,7 @@ import { Message } from 'element-ui'
import NProgress from 'nprogress' // progress bar import NProgress from 'nprogress' // progress bar
import 'nprogress/nprogress.css' // progress bar style import 'nprogress/nprogress.css' // progress bar style
import { getToken } from '@/utils/auth' // get token from cookie import { getToken } from '@/utils/auth' // get token from cookie
import getPageTitle from '@/utils/get-page-title'
NProgress.configure({ showSpinner: false }) // NProgress Configuration NProgress.configure({ showSpinner: false }) // NProgress Configuration
@ -13,6 +14,9 @@ router.beforeEach(async(to, from, next) => {
// start progress bar // start progress bar
NProgress.start() NProgress.start()
// set page title
document.title = getPageTitle(to.meta.title)
// determine whether the user has logged in // determine whether the user has logged in
const hasToken = getToken() const hasToken = getToken()

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 *
* it will becomes nested mode, otherwise not show the root menu * hidden: true if set true, item will not show in the sidebar(default is false)
* redirect: noredirect if `redirect:noredirect` will no redirect in the breadcrumb * alwaysShow: true if set true, will always show the root menu
* name:'router-name' the name is used by <keep-alive> (must set!!!) * if not set alwaysShow, when item has more than one children route,
* meta : { * it will becomes nested mode, otherwise not show the root menu
roles: ['admin','editor'] will control the page roles (you can set multiple roles) * redirect: noRedirect if set noRedirect will no redirect in the breadcrumb
title: 'title' the name show in sub-menu and breadcrumb (recommend set) * name:'router-name' the name is used by <keep-alive> (must set!!!)
* meta : {
roles: ['admin','editor'] control the page roles (you can set multiple roles)
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,17 +57,17 @@ export const constantRoutes = [
}, },
{ {
path: '/auth-redirect', path: '/auth-redirect',
component: () => import('@/views/login/authRedirect'), component: () => import('@/views/login/auth-redirect'),
hidden: true hidden: true
}, },
{ {
path: '/404', path: '/404',
component: () => import('@/views/errorPage/404'), component: () => import('@/views/error-page/404'),
hidden: true hidden: true
}, },
{ {
path: '/401', path: '/401',
component: () => import('@/views/errorPage/401'), component: () => import('@/views/error-page/401'),
hidden: true hidden: true
}, },
{ {
@ -113,13 +113,14 @@ export const constantRoutes = [
/** /**
* asyncRoutes * asyncRoutes
* the routes that need to be dynamically loaded based on user roles * the routes that need to be dynamically loaded based on user roles
*/ */
export const asyncRoutes = [ export const asyncRoutes = [
{ {
path: '/permission', path: '/permission',
component: Layout, component: Layout,
redirect: '/permission/index', redirect: '/permission/page',
alwaysShow: true, // will always show the root menu alwaysShow: true, // will always show the root menu
name: 'Permission',
meta: { meta: {
title: 'permission', title: 'permission',
icon: 'lock', icon: 'lock',
@ -162,7 +163,7 @@ export const asyncRoutes = [
children: [ children: [
{ {
path: 'index', path: 'index',
component: () => import('@/views/svg-icons/index'), component: () => import('@/views/icons/index'),
name: 'Icons', name: 'Icons',
meta: { title: 'icons', icon: 'icon', noCache: true } meta: { title: 'icons', icon: 'icon', noCache: true }
} }
@ -195,7 +196,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
}, },
{ {
@ -223,7 +224,7 @@ export const asyncRoutes = [
{ {
path: '/error', path: '/error',
component: Layout, component: Layout,
redirect: 'noredirect', redirect: 'noRedirect',
name: 'ErrorPages', name: 'ErrorPages',
meta: { meta: {
title: 'errorPages', title: 'errorPages',
@ -232,13 +233,13 @@ export const asyncRoutes = [
children: [ children: [
{ {
path: '401', path: '401',
component: () => import('@/views/errorPage/401'), component: () => import('@/views/error-page/401'),
name: 'Page401', name: 'Page401',
meta: { title: 'page401', noCache: true } meta: { title: 'page401', noCache: true }
}, },
{ {
path: '404', path: '404',
component: () => import('@/views/errorPage/404'), component: () => import('@/views/error-page/404'),
name: 'Page404', name: 'Page404',
meta: { title: 'page404', noCache: true } meta: { title: 'page404', noCache: true }
} }
@ -248,11 +249,10 @@ export const asyncRoutes = [
{ {
path: '/error-log', path: '/error-log',
component: Layout, component: Layout,
redirect: 'noredirect',
children: [ children: [
{ {
path: 'log', path: 'log',
component: () => import('@/views/errorLog/index'), component: () => import('@/views/error-log/index'),
name: 'ErrorLog', name: 'ErrorLog',
meta: { title: 'errorLog', icon: 'bug' } meta: { title: 'errorLog', icon: 'bug' }
} }
@ -271,25 +271,25 @@ export const asyncRoutes = [
children: [ children: [
{ {
path: 'export-excel', path: 'export-excel',
component: () => import('@/views/excel/exportExcel'), component: () => import('@/views/excel/export-excel'),
name: 'ExportExcel', name: 'ExportExcel',
meta: { title: 'exportExcel' } meta: { title: 'exportExcel' }
}, },
{ {
path: 'export-selected-excel', path: 'export-selected-excel',
component: () => import('@/views/excel/selectExcel'), component: () => import('@/views/excel/select-excel'),
name: 'SelectExcel', name: 'SelectExcel',
meta: { title: 'selectExcel' } meta: { title: 'selectExcel' }
}, },
{ {
path: 'export-merge-header', path: 'export-merge-header',
component: () => import('@/views/excel/mergeHeader'), component: () => import('@/views/excel/merge-header'),
name: 'MergeHeader', name: 'MergeHeader',
meta: { title: 'mergeHeader' } meta: { title: 'mergeHeader' }
}, },
{ {
path: 'upload-excel', path: 'upload-excel',
component: () => import('@/views/excel/uploadExcel'), component: () => import('@/views/excel/upload-excel'),
name: 'UploadExcel', name: 'UploadExcel',
meta: { title: 'uploadExcel' } meta: { title: 'uploadExcel' }
} }
@ -301,6 +301,7 @@ export const asyncRoutes = [
component: Layout, component: Layout,
redirect: '/zip/download', redirect: '/zip/download',
alwaysShow: true, alwaysShow: true,
name: 'Zip',
meta: { title: 'zip', icon: 'zip' }, meta: { title: 'zip', icon: 'zip' },
children: [ children: [
{ {
@ -334,7 +335,6 @@ export const asyncRoutes = [
{ {
path: '/theme', path: '/theme',
component: Layout, component: Layout,
redirect: 'noredirect',
children: [ children: [
{ {
path: 'index', path: 'index',
@ -348,7 +348,6 @@ export const asyncRoutes = [
{ {
path: '/clipboard', path: '/clipboard',
component: Layout, component: Layout,
redirect: 'noredirect',
children: [ children: [
{ {
path: 'index', path: 'index',

View File

@ -5,7 +5,7 @@ import Layout from '@/layout'
const chartsRouter = { const chartsRouter = {
path: '/charts', path: '/charts',
component: Layout, component: Layout,
redirect: 'noredirect', redirect: 'noRedirect',
name: 'Charts', name: 'Charts',
meta: { meta: {
title: 'charts', title: 'charts',
@ -25,8 +25,8 @@ const chartsRouter = {
meta: { title: 'lineChart', noCache: true } meta: { title: 'lineChart', noCache: true }
}, },
{ {
path: 'mixchart', path: 'mix-chart',
component: () => import('@/views/charts/mixChart'), component: () => import('@/views/charts/mix-chart'),
name: 'MixChart', name: 'MixChart',
meta: { title: 'mixChart', noCache: true } meta: { title: 'mixChart', noCache: true }
} }

View File

@ -1,11 +1,11 @@
/** When your routing table is too long, you can split it into small modules**/ /** When your routing table is too long, you can split it into small modules **/
import Layout from '@/layout' import Layout from '@/layout'
const componentsRouter = { const componentsRouter = {
path: '/components', path: '/components',
component: Layout, component: Layout,
redirect: 'noredirect', redirect: 'noRedirect',
name: 'ComponentDemo', name: 'ComponentDemo',
meta: { meta: {
title: 'components', title: 'components',
@ -26,19 +26,19 @@ const componentsRouter = {
}, },
{ {
path: 'json-editor', path: 'json-editor',
component: () => import('@/views/components-demo/jsonEditor'), component: () => import('@/views/components-demo/json-editor'),
name: 'JsonEditorDemo', name: 'JsonEditorDemo',
meta: { title: 'jsonEditor' } meta: { title: 'jsonEditor' }
}, },
{ {
path: 'splitpane', path: 'split-pane',
component: () => import('@/views/components-demo/splitpane'), component: () => import('@/views/components-demo/split-pane'),
name: 'SplitpaneDemo', name: 'SplitpaneDemo',
meta: { title: 'splitPane' } meta: { title: 'splitPane' }
}, },
{ {
path: 'avatar-upload', path: 'avatar-upload',
component: () => import('@/views/components-demo/avatarUpload'), component: () => import('@/views/components-demo/avatar-upload'),
name: 'AvatarUploadDemo', name: 'AvatarUploadDemo',
meta: { title: 'avatarUpload' } meta: { title: 'avatarUpload' }
}, },
@ -56,7 +56,7 @@ const componentsRouter = {
}, },
{ {
path: 'count-to', path: 'count-to',
component: () => import('@/views/components-demo/countTo'), component: () => import('@/views/components-demo/count-to'),
name: 'CountToDemo', name: 'CountToDemo',
meta: { title: 'countTo' } meta: { title: 'countTo' }
}, },
@ -68,31 +68,31 @@ const componentsRouter = {
}, },
{ {
path: 'back-to-top', path: 'back-to-top',
component: () => import('@/views/components-demo/backToTop'), component: () => import('@/views/components-demo/back-to-top'),
name: 'BackToTopDemo', name: 'BackToTopDemo',
meta: { title: 'backToTop' } meta: { title: 'backToTop' }
}, },
{ {
path: 'drag-dialog', path: 'drag-dialog',
component: () => import('@/views/components-demo/dragDialog'), component: () => import('@/views/components-demo/drag-dialog'),
name: 'DragDialogDemo', name: 'DragDialogDemo',
meta: { title: 'dragDialog' } meta: { title: 'dragDialog' }
}, },
{ {
path: 'drag-select', path: 'drag-select',
component: () => import('@/views/components-demo/dragSelect'), component: () => import('@/views/components-demo/drag-select'),
name: 'DragSelectDemo', name: 'DragSelectDemo',
meta: { title: 'dragSelect' } meta: { title: 'dragSelect' }
}, },
{ {
path: 'dnd-list', path: 'dnd-list',
component: () => import('@/views/components-demo/dndList'), component: () => import('@/views/components-demo/dnd-list'),
name: 'DndListDemo', name: 'DndListDemo',
meta: { title: 'dndList' } meta: { title: 'dndList' }
}, },
{ {
path: 'drag-kanban', path: 'drag-kanban',
component: () => import('@/views/components-demo/dragKanban'), component: () => import('@/views/components-demo/drag-kanban'),
name: 'DragKanbanDemo', name: 'DragKanbanDemo',
meta: { title: 'dragKanban' } meta: { title: 'dragKanban' }
} }

View File

@ -1,4 +1,4 @@
/** When your routing table is too long, you can split it into small modules**/ /** When your routing table is too long, you can split it into small modules **/
import Layout from '@/layout' import Layout from '@/layout'

View File

@ -1,4 +1,4 @@
/** When your routing table is too long, you can split it into small modules**/ /** When your routing table is too long, you can split it into small modules **/
import Layout from '@/layout' import Layout from '@/layout'
@ -14,25 +14,25 @@ const tableRouter = {
children: [ children: [
{ {
path: 'dynamic-table', path: 'dynamic-table',
component: () => import('@/views/table/dynamicTable/index'), component: () => import('@/views/table/dynamic-table/index'),
name: 'DynamicTable', name: 'DynamicTable',
meta: { title: 'dynamicTable' } meta: { title: 'dynamicTable' }
}, },
{ {
path: 'drag-table', path: 'drag-table',
component: () => import('@/views/table/dragTable'), component: () => import('@/views/table/drag-table'),
name: 'DragTable', name: 'DragTable',
meta: { title: 'dragTable' } meta: { title: 'dragTable' }
}, },
{ {
path: 'inline-edit-table', path: 'inline-edit-table',
component: () => import('@/views/table/inlineEditTable'), component: () => import('@/views/table/inline-edit-table'),
name: 'InlineEditTable', name: 'InlineEditTable',
meta: { title: 'inlineEditTable' } meta: { title: 'inlineEditTable' }
}, },
{ {
path: 'complex-table', path: 'complex-table',
component: () => import('@/views/table/complexTable'), component: () => import('@/views/table/complex-table'),
name: 'ComplexTable', name: 'ComplexTable',
meta: { title: 'complexTable' } meta: { title: 'complexTable' }
} }

View File

@ -1,7 +1,5 @@
import variables from '@/styles/element-variables.scss' module.exports = {
title: 'Vue Element Admin',
export default {
theme: variables.theme,
/** /**
* @type {boolean} true | false * @type {boolean} true | false

View File

@ -1,7 +1,7 @@
import { asyncRoutes, constantRoutes } from '@/router' import { asyncRoutes, constantRoutes } from '@/router'
/** /**
* 通过meta.role判断是否与当前用户权限匹配 * Use meta.role to determine if the current user has permission
* @param roles * @param roles
* @param route * @param route
*/ */
@ -14,7 +14,7 @@ function hasPermission(roles, route) {
} }
/** /**
* 递归过滤异步路由表返回符合用户角色权限的路由表 * Filter asynchronous routing tables by recursion
* @param routes asyncRoutes * @param routes asyncRoutes
* @param roles * @param roles
*/ */

View File

@ -1,8 +1,10 @@
import variables from '@/styles/element-variables.scss'
import defaultSettings from '@/settings' import defaultSettings from '@/settings'
const { showSettings, tagsView, fixedHeader, sidebarLogo, theme } = defaultSettings
const { showSettings, tagsView, fixedHeader, sidebarLogo } = defaultSettings
const state = { const state = {
theme: theme, theme: variables.theme,
showSettings: showSettings, showSettings: showSettings,
tagsView: tagsView, tagsView: tagsView,
fixedHeader: fixedHeader, fixedHeader: fixedHeader,

View File

@ -1,4 +1,4 @@
//覆盖一些element-ui样式 // cover some element-ui styles
.el-breadcrumb__inner, .el-breadcrumb__inner,
.el-breadcrumb__inner a { .el-breadcrumb__inner a {
@ -46,7 +46,7 @@
} }
} }
//暂时性解决dialog 问题 https://github.com/ElemeFE/element/issues/2461 // to fixed https://github.com/ElemeFE/element/issues/2461
.el-dialog { .el-dialog {
transform: none; transform: none;
left: 0; left: 0;
@ -54,18 +54,7 @@
margin: 0 auto; margin: 0 auto;
} }
//文章页textarea修改样式 // refine element ui upload
.article-textarea {
textarea {
padding-right: 40px;
resize: none;
border: none;
border-radius: 0px;
border-bottom: 1px solid #bfcbd9;
}
}
//element ui upload
.upload-container { .upload-container {
.el-upload { .el-upload {
width: 100%; width: 100%;
@ -77,9 +66,14 @@
} }
} }
//dropdown // dropdown
.el-dropdown-menu { .el-dropdown-menu {
a { a {
display: block display: block
} }
} }
// fix date-picker ui bug in filter-item
.el-range-editor.el-input__inner {
display: inline-flex !important;
}

View File

@ -96,14 +96,18 @@ div:focus {
} }
} }
code { aside {
background: #eef1f6; background: #eef1f6;
padding: 15px 16px; padding: 8px 24px;
margin-bottom: 20px; margin-bottom: 20px;
border-radius: 2px;
display: block; display: block;
line-height: 36px; line-height: 32px;
font-size: 15px; font-size: 16px;
font-family: "Source Sans Pro", "Helvetica Neue", Arial, sans-serif; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif;
color: #2c3e50;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
a { a {
color: #337ab7; color: #337ab7;
@ -115,20 +119,6 @@ code {
} }
} }
.warn-content {
background: rgba(66, 185, 131, .1);
border-radius: 2px;
padding: 16px;
padding: 1rem;
line-height: 1.6rem;
word-spacing: .05rem;
a {
color: #42b983;
font-weight: 600;
}
}
//main-container全局样式 //main-container全局样式
.app-container { .app-container {
padding: 20px; padding: 20px;

View File

@ -1,6 +1,5 @@
#app { #app {
// 主体区域 Main container
.main-container { .main-container {
min-height: 100%; min-height: 100%;
transition: margin-left .28s; transition: margin-left .28s;
@ -8,10 +7,10 @@
position: relative; position: relative;
} }
// 侧边栏 Sidebar container
.sidebar-container { .sidebar-container {
transition: width 0.28s; transition: width 0.28s;
width: $sideBarWidth !important; width: $sideBarWidth !important;
background-color: $menuBg;
height: 100%; height: 100%;
position: fixed; position: fixed;
font-size: 0px; font-size: 0px;
@ -21,17 +20,13 @@
z-index: 1001; z-index: 1001;
overflow: hidden; overflow: hidden;
//reset element-ui css // reset element-ui css
.horizontal-collapse-transition { .horizontal-collapse-transition {
transition: 0s width ease-in-out, 0s padding-left ease-in-out, 0s padding-right ease-in-out; transition: 0s width ease-in-out, 0s padding-left ease-in-out, 0s padding-right ease-in-out;
} }
.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 {
@ -152,7 +147,7 @@
min-width: $sideBarWidth !important; min-width: $sideBarWidth !important;
} }
// 适配移动端, Mobile responsive // mobile responsive
.mobile { .mobile {
.main-container { .main-container {
margin-left: 0px; margin-left: 0px;

View File

@ -1,6 +1,6 @@
//global transition css // global transition css
/*fade*/ /* fade */
.fade-enter-active, .fade-enter-active,
.fade-leave-active { .fade-leave-active {
transition: opacity 0.28s; transition: opacity 0.28s;
@ -11,7 +11,7 @@
opacity: 0; opacity: 0;
} }
/*fade-transform*/ /* fade-transform */
.fade-transform-leave-active, .fade-transform-leave-active,
.fade-transform-enter-active { .fade-transform-enter-active {
transition: all .5s; transition: all .5s;
@ -27,7 +27,7 @@
transform: translateX(30px); transform: translateX(30px);
} }
/*breadcrumb transition*/ /* breadcrumb transition */
.breadcrumb-enter-active, .breadcrumb-enter-active,
.breadcrumb-leave-active { .breadcrumb-leave-active {
transition: all .5s; transition: all .5s;

View File

@ -8,10 +8,10 @@ $tiffany: #4AB7BD;
$yellow:#FEC171; $yellow:#FEC171;
$panGreen: #30B08F; $panGreen: #30B08F;
//sidebar // sidebar
$menuText:#bfcbd9; $menuText:#bfcbd9;
$menuActiveText:#409EFF; $menuActiveText:#409EFF;
$subMenuActiveText:#f4f4f5; //https://github.com/ElemeFE/element/issues/12951 $subMenuActiveText:#f4f4f5; // https://github.com/ElemeFE/element/issues/12951
$menuBg:#304156; $menuBg:#304156;
$menuHover:#263445; $menuHover:#263445;

View File

@ -4,10 +4,10 @@ import { isString, isArray } from '@/utils/validate'
import settings from '@/settings' import settings from '@/settings'
// you can set in settings.js // you can set in settings.js
// errorLog:'production' | ['production','development'] // errorLog:'production' | ['production', 'development']
const { errorLog: needErrorLog } = settings const { errorLog: needErrorLog } = settings
function checkNeed(arg) { function checkNeed() {
const env = process.env.NODE_ENV const env = process.env.NODE_ENV
if (isString(needErrorLog)) { if (isString(needErrorLog)) {
return env === needErrorLog return env === needErrorLog

View File

@ -0,0 +1,13 @@
import defaultSettings from '@/settings'
import i18n from '@/lang'
const title = defaultSettings.title || 'Vue Element Admin'
export default function getPageTitle(key) {
const hasKey = i18n.te(`route.${key}`)
if (hasKey) {
const pageName = i18n.t(`route.${key}`)
return `${pageName} - ${title}`
}
return `${title}`
}

View File

@ -2,6 +2,12 @@
* Created by jiachenpan on 16/11/18. * Created by jiachenpan on 16/11/18.
*/ */
/**
* Parse the time to string
* @param {(Object|string|number)} time
* @param {string} cFormat
* @returns {string}
*/
export function parseTime(time, cFormat) { export function parseTime(time, cFormat) {
if (arguments.length === 0) { if (arguments.length === 0) {
return null return null
@ -40,6 +46,11 @@ export function parseTime(time, cFormat) {
return time_str return time_str
} }
/**
* @param {number} time
* @param {string} option
* @returns {string}
*/
export function formatTime(time, option) { export function formatTime(time, option) {
if (('' + time).length === 10) { if (('' + time).length === 10) {
time = parseInt(time) * 1000 time = parseInt(time) * 1000
@ -78,7 +89,10 @@ export function formatTime(time, option) {
} }
} }
// 格式化时间 /**
* @param {string} url
* @returns {Object}
*/
export function getQueryObject(url) { export function getQueryObject(url) {
url = url == null ? window.location.href : url url = url == null ? window.location.href : url
const search = url.substring(url.lastIndexOf('?') + 1) const search = url.substring(url.lastIndexOf('?') + 1)
@ -95,7 +109,7 @@ export function getQueryObject(url) {
} }
/** /**
* @param {Sting} input value * @param {string} input value
* @returns {number} output value * @returns {number} output value
*/ */
export function byteLength(str) { export function byteLength(str) {
@ -110,6 +124,10 @@ export function byteLength(str) {
return s return s
} }
/**
* @param {Array} actual
* @returns {Array}
*/
export function cleanArray(actual) { export function cleanArray(actual) {
const newArray = [] const newArray = []
for (let i = 0; i < actual.length; i++) { for (let i = 0; i < actual.length; i++) {
@ -120,6 +138,10 @@ export function cleanArray(actual) {
return newArray return newArray
} }
/**
* @param {Object} json
* @returns {Array}
*/
export function param(json) { export function param(json) {
if (!json) return '' if (!json) return ''
return cleanArray( return cleanArray(
@ -130,6 +152,10 @@ export function param(json) {
).join('&') ).join('&')
} }
/**
* @param {string} url
* @returns {Object}
*/
export function param2Obj(url) { export function param2Obj(url) {
const search = url.split('?')[1] const search = url.split('?')[1]
if (!search) { if (!search) {
@ -146,16 +172,23 @@ export function param2Obj(url) {
) )
} }
/**
* @param {string} val
* @returns {string}
*/
export function html2Text(val) { export function html2Text(val) {
const div = document.createElement('div') const div = document.createElement('div')
div.innerHTML = val div.innerHTML = val
return div.textContent || div.innerText return div.textContent || div.innerText
} }
/**
* Merges two objects, giving the last one precedence
* @param {Object} target
* @param {(Object|Array)} source
* @returns {Object}
*/
export function objectMerge(target, source) { export function objectMerge(target, source) {
/* Merges two objects,
giving the last one precedence */
if (typeof target !== 'object') { if (typeof target !== 'object') {
target = {} target = {}
} }
@ -173,6 +206,10 @@ export function objectMerge(target, source) {
return target return target
} }
/**
* @param {HTMLElement} element
* @param {string} className
*/
export function toggleClass(element, className) { export function toggleClass(element, className) {
if (!element || !className) { if (!element || !className) {
return return
@ -189,45 +226,10 @@ export function toggleClass(element, className) {
element.className = classString element.className = classString
} }
export const pickerOptions = [ /**
{ * @param {string} type
text: '今天', * @returns {Date}
onClick(picker) { */
const end = new Date()
const start = new Date(new Date().toDateString())
end.setTime(start.getTime())
picker.$emit('pick', [start, end])
}
},
{
text: '最近一周',
onClick(picker) {
const end = new Date(new Date().toDateString())
const start = new Date()
start.setTime(end.getTime() - 3600 * 1000 * 24 * 7)
picker.$emit('pick', [start, end])
}
},
{
text: '最近一个月',
onClick(picker) {
const end = new Date(new Date().toDateString())
const start = new Date()
start.setTime(start.getTime() - 3600 * 1000 * 24 * 30)
picker.$emit('pick', [start, end])
}
},
{
text: '最近三个月',
onClick(picker) {
const end = new Date(new Date().toDateString())
const start = new Date()
start.setTime(start.getTime() - 3600 * 1000 * 24 * 90)
picker.$emit('pick', [start, end])
}
}
]
export function getTime(type) { export function getTime(type) {
if (type === 'start') { if (type === 'start') {
return new Date().getTime() - 3600 * 1000 * 24 * 90 return new Date().getTime() - 3600 * 1000 * 24 * 90
@ -236,6 +238,12 @@ export function getTime(type) {
} }
} }
/**
* @param {Function} func
* @param {number} wait
* @param {boolean} immediate
* @return {*}
*/
export function debounce(func, wait, immediate) { export function debounce(func, wait, immediate) {
let timeout, args, context, timestamp, result let timeout, args, context, timestamp, result
@ -275,6 +283,8 @@ export function debounce(func, wait, immediate) {
* This is just a simple version of deep copy * This is just a simple version of deep copy
* Has a lot of edge cases bug * Has a lot of edge cases bug
* If you want to use a perfect deep copy, use lodash's _.cloneDeep * If you want to use a perfect deep copy, use lodash's _.cloneDeep
* @param {Object} source
* @returns {Object}
*/ */
export function deepClone(source) { export function deepClone(source) {
if (!source && typeof source !== 'object') { if (!source && typeof source !== 'object') {
@ -291,22 +301,47 @@ export function deepClone(source) {
return targetObj return targetObj
} }
/**
* @param {Array} arr
* @returns {Array}
*/
export function uniqueArr(arr) { export function uniqueArr(arr) {
return Array.from(new Set(arr)) return Array.from(new Set(arr))
} }
/**
* @returns {string}
*/
export function createUniqueString() { export function createUniqueString() {
const timestamp = +new Date() + '' const timestamp = +new Date() + ''
const randomNum = parseInt((1 + Math.random()) * 65536) + '' const randomNum = parseInt((1 + Math.random()) * 65536) + ''
return (+(randomNum + timestamp)).toString(32) return (+(randomNum + timestamp)).toString(32)
} }
/**
* Check if an element has a class
* @param {HTMLElement} elm
* @param {string} cls
* @returns {boolean}
*/
export function hasClass(ele, cls) { export function hasClass(ele, cls) {
return !!ele.className.match(new RegExp('(\\s|^)' + cls + '(\\s|$)')) return !!ele.className.match(new RegExp('(\\s|^)' + cls + '(\\s|$)'))
} }
/**
* Add class to element
* @param {HTMLElement} elm
* @param {string} cls
*/
export function addClass(ele, cls) { export function addClass(ele, cls) {
if (!hasClass(ele, cls)) ele.className += ' ' + cls if (!hasClass(ele, cls)) ele.className += ' ' + cls
} }
/**
* Remove class from element
* @param {HTMLElement} elm
* @param {string} cls
*/
export function removeClass(ele, cls) { export function removeClass(ele, cls) {
if (hasClass(ele, cls)) { if (hasClass(ele, cls)) {
const reg = new RegExp('(\\s|^)' + cls + '(\\s|$)') const reg = new RegExp('(\\s|^)' + cls + '(\\s|$)')

View File

@ -5,7 +5,6 @@
* @param {Number} w * @param {Number} w
* @param {Number} h * @param {Number} h
*/ */
export default function openWindow(url, title, w, h) { export default function openWindow(url, title, w, h) {
// Fixes dual-screen position Most browsers Firefox // Fixes dual-screen position Most browsers Firefox
const dualScreenLeft = window.screenLeft !== undefined ? window.screenLeft : screen.left const dualScreenLeft = window.screenLeft !== undefined ? window.screenLeft : screen.left

View File

@ -5,23 +5,25 @@ import { getToken } from '@/utils/auth'
// create an axios instance // create an axios instance
const service = axios.create({ const service = axios.create({
baseURL: process.env.VUE_APP_BASE_API, // api 的 base_url baseURL: process.env.VUE_APP_BASE_API, // url = base url + request url
withCredentials: true, // 跨域请求时发送 cookies withCredentials: true, // send cookies when cross-domain requests
timeout: 5000 // request timeout timeout: 5000 // request timeout
}) })
// request interceptor // request interceptor
service.interceptors.request.use( service.interceptors.request.use(
config => { config => {
// Do something before request is sent // do something before request is sent
if (store.getters.token) { if (store.getters.token) {
// 让每个请求携带token-- ['X-Token']为自定义key 请根据实际情况自行修改 // let each request carry token --['X-Token'] as a custom key.
// please modify it according to the actual situation.
config.headers['X-Token'] = getToken() config.headers['X-Token'] = getToken()
} }
return config return config
}, },
error => { error => {
// Do something with request error // do something with request error
console.log(error) // for debug console.log(error) // for debug
return Promise.reject(error) return Promise.reject(error)
} }
@ -33,35 +35,37 @@ service.interceptors.response.use(
* If you want to get information such as headers or status * If you want to get information such as headers or status
* Please return response => response * Please return response => response
*/ */
/** /**
* 下面的注释为通过在response里自定义code来标示请求状态 * Determine the request status by custom code
* 当code返回如下情况则说明权限有问题登出并返回到登录页 * Here is just an example
* 如想通过 XMLHttpRequest 来状态码标识 逻辑可写在下面error中 * You can also judge the status by HTTP Status Code.
* 以下代码均为样例请结合自生需求加以修改若不需要则可删除
*/ */
response => { response => {
const res = response.data const res = response.data
// if the custom code is not 20000, it is judged as an error.
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
}) })
// 50008:非法的token; 50012:其他客户端登录了; 50014:Token 过期了;
// 50008: Illegal token; 50012: Other clients logged in; 50014: Token expired;
if (res.code === 50008 || res.code === 50012 || res.code === 50014) { if (res.code === 50008 || res.code === 50012 || res.code === 50014) {
// 请自行在引入 MessageBox // to re-login
// import { Message, MessageBox } from 'element-ui' MessageBox.confirm('You have been logged out, you can cancel to stay on this page, or log in again', 'Confirm logout', {
MessageBox.confirm('你已被登出,可以取消继续留在该页面,或者重新登录', '确定登出', { confirmButtonText: 'Re-Login',
confirmButtonText: '重新登录', cancelButtonText: 'Cancel',
cancelButtonText: '取消',
type: 'warning' type: 'warning'
}).then(() => { }).then(() => {
store.dispatch('user/resetToken').then(() => { store.dispatch('user/resetToken').then(() => {
location.reload() // 为了重新实例化vue-router对象 避免bug location.reload()
}) })
}) })
} }
return Promise.reject('error') return Promise.reject(res.message || 'error')
} else { } else {
return res return res
} }

View File

@ -12,7 +12,10 @@ var requestAnimFrame = (function() {
return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || function(callback) { window.setTimeout(callback, 1000 / 60) } return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || function(callback) { window.setTimeout(callback, 1000 / 60) }
})() })()
// because it's so fucking difficult to detect the scrolling element, just move them all /**
* Because it's so fucking difficult to detect the scrolling element, just move them all
* @param {number} amount
*/
function move(amount) { function move(amount) {
document.documentElement.scrollTop = amount document.documentElement.scrollTop = amount
document.body.parentNode.scrollTop = amount document.body.parentNode.scrollTop = amount
@ -23,6 +26,11 @@ function position() {
return document.documentElement.scrollTop || document.body.parentNode.scrollTop || document.body.scrollTop return document.documentElement.scrollTop || document.body.parentNode.scrollTop || document.body.scrollTop
} }
/**
* @param {number} to
* @param {number} duration
* @param {Function} callback
*/
export function scrollTo(to, duration, callback) { export function scrollTo(to, duration, callback) {
const start = position() const start = position()
const change = to - start const change = to - start

View File

@ -1,41 +1,72 @@
/** /**
* Created by jiachenpan on 16/11/18. * Created by jiachenpan on 16/11/18.
*/ */
/**
* @param {string} path
* @returns {Boolean}
*/
export function isExternal(path) { export function isExternal(path) {
return /^(https?:|mailto:|tel:)/.test(path) return /^(https?:|mailto:|tel:)/.test(path)
} }
/**
* @param {string} str
* @returns {Boolean}
*/
export function validUsername(str) { export function validUsername(str) {
const valid_map = ['admin', 'editor'] const valid_map = ['admin', 'editor']
return valid_map.indexOf(str.trim()) >= 0 return valid_map.indexOf(str.trim()) >= 0
} }
/**
* @param {string} url
* @returns {Boolean}
*/
export function validURL(url) { export function validURL(url) {
const reg = /^(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.,?'\\+&%$#=~_-]+))*$/ const reg = /^(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.,?'\\+&%$#=~_-]+))*$/
return reg.test(url) return reg.test(url)
} }
/**
* @param {string} str
* @returns {Boolean}
*/
export function validLowerCase(str) { export function validLowerCase(str) {
const reg = /^[a-z]+$/ const reg = /^[a-z]+$/
return reg.test(str) return reg.test(str)
} }
/**
* @param {string} str
* @returns {Boolean}
*/
export function validUpperCase(str) { export function validUpperCase(str) {
const reg = /^[A-Z]+$/ const reg = /^[A-Z]+$/
return reg.test(str) return reg.test(str)
} }
/**
* @param {string} str
* @returns {Boolean}
*/
export function validAlphabets(str) { export function validAlphabets(str) {
const reg = /^[A-Za-z]+$/ const reg = /^[A-Za-z]+$/
return reg.test(str) return reg.test(str)
} }
/**
* @param {string} email
* @returns {Boolean}
*/
export function validEmail(email) { export function validEmail(email) {
const reg = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/ const reg = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/
return reg.test(email) return reg.test(email)
} }
/**
* @param {string} str
* @returns {Boolean}
*/
export function isString(str) { export function isString(str) {
if (typeof str === 'string' || str instanceof String) { if (typeof str === 'string' || str instanceof String) {
return true return true
@ -43,6 +74,10 @@ export function isString(str) {
return false return false
} }
/**
* @param {Array} arg
* @returns {Boolean}
*/
export function isArray(arg) { export function isArray(arg) {
if (typeof Array.isArray === 'undefined') { if (typeof Array.isArray === 'undefined') {
return Object.prototype.toString.call(arg) === '[object Array]' return Object.prototype.toString.call(arg) === '[object Array]'

View File

@ -5,7 +5,7 @@
</template> </template>
<script> <script>
import Chart from '@/components/Charts/keyboard' import Chart from '@/components/Charts/Keyboard'
export default { export default {
name: 'KeyboardChart', name: 'KeyboardChart',

View File

@ -5,7 +5,7 @@
</template> </template>
<script> <script>
import Chart from '@/components/Charts/lineMarker' import Chart from '@/components/Charts/LineMarker'
export default { export default {
name: 'LineChart', name: 'LineChart',

View File

@ -5,7 +5,7 @@
</template> </template>
<script> <script>
import Chart from '@/components/Charts/mixChart' import Chart from '@/components/Charts/MixChart'
export default { export default {
name: 'MixChart', name: 'MixChart',

View File

@ -1,9 +1,9 @@
<template> <template>
<div class="components-container"> <div class="components-container">
<code>This is based on <aside>This is based on
<a class="link-type" href="//github.com/dai-siki/vue-image-crop-upload"> vue-image-crop-upload</a>. <a class="link-type" href="//github.com/dai-siki/vue-image-crop-upload"> vue-image-crop-upload</a>.
{{ $t('components.imageUploadTips') }} {{ $t('components.imageUploadTips') }}
</code> </aside>
<pan-thumb :image="image" /> <pan-thumb :image="image" />

View File

@ -1,7 +1,7 @@
<template> <template>
<div class="components-container"> <div class="components-container">
<code>{{ $t('components.backToTopTips1') }}</code> <aside>{{ $t('components.backToTopTips1') }}</aside>
<code>{{ $t('components.backToTopTips2') }}</code> <aside>{{ $t('components.backToTopTips2') }}</aside>
<div class="placeholder-container"> <div class="placeholder-container">
<div>placeholder</div> <div>placeholder</div>
<div>placeholder</div> <div>placeholder</div>
@ -113,8 +113,7 @@
<div>placeholder</div> <div>placeholder</div>
<div>placeholder</div> <div>placeholder</div>
</div> </div>
<!--可自定义按钮的样式show/hide临界点返回的位置 --> <!-- you can add element-ui's tooltip -->
<!--如需文字提示可在外部添加element的<el-tooltip></el-tooltip> -->
<el-tooltip placement="top" content="tooltip"> <el-tooltip placement="top" content="tooltip">
<back-to-top :custom-style="myBackToTopStyle" :visibility-height="300" :back-position="50" transition-name="fade" /> <back-to-top :custom-style="myBackToTopStyle" :visibility-height="300" :back-position="50" transition-name="fade" />
</el-tooltip> </el-tooltip>
@ -129,6 +128,7 @@ export default {
components: { BackToTop }, components: { BackToTop },
data() { data() {
return { return {
// customizable button style, show/hide critical point, return position
myBackToTopStyle: { myBackToTopStyle: {
right: '50px', right: '50px',
bottom: '50px', bottom: '50px',

View File

@ -1,8 +1,8 @@
<template> <template>
<div class="components-container"> <div class="components-container">
<p class="warn-content"> <aside>
<a href="https://github.com/PanJiaChen/vue-countTo" target="_blank">countTo-component</a> <a href="https://github.com/PanJiaChen/vue-countTo" target="_blank">countTo-component</a>
</p> </aside>
<count-to <count-to
ref="example" ref="example"
:start-val="_startVal" :start-val="_startVal"
@ -45,9 +45,9 @@
<input v-model="setSuffix" name="suffixInput"> <input v-model="setSuffix" name="suffixInput">
</label> </label>
</div> </div>
<code>&lt;count-to :start-val=&#x27;{{ _startVal }}&#x27; :end-val=&#x27;{{ _endVal }}&#x27; :duration=&#x27;{{ _duration }}&#x27; <aside>&lt;count-to :start-val=&#x27;{{ _startVal }}&#x27; :end-val=&#x27;{{ _endVal }}&#x27; :duration=&#x27;{{ _duration }}&#x27;
:decimals=&#x27;{{ _decimals }}&#x27; :separator=&#x27;{{ _separator }}&#x27; :prefix=&#x27;{{ _prefix }}&#x27; :suffix=&#x27;{{ _suffix }}&#x27; :decimals=&#x27;{{ _decimals }}&#x27; :separator=&#x27;{{ _separator }}&#x27; :prefix=&#x27;{{ _prefix }}&#x27; :suffix=&#x27;{{ _suffix }}&#x27;
:autoplay=false&gt;</code> :autoplay=false&gt;</aside>
</div> </div>
</template> </template>

View File

@ -1,8 +1,8 @@
<template> <template>
<div class="components-container"> <div class="components-container">
<code>drag-list base on <aside>drag-list base on
<a href="https://github.com/SortableJS/Vue.Draggable" target="_blank">Vue.Draggable</a> <a href="https://github.com/SortableJS/Vue.Draggable" target="_blank">Vue.Draggable</a>
</code> </aside>
<div class="editor-container"> <div class="editor-container">
<dnd-list :list1="list1" :list2="list2" list1-title="List" list2-title="Article pool" /> <dnd-list :list1="list1" :list2="list2" list1-title="List" list2-title="Article pool" />
</div> </div>

View File

@ -17,7 +17,7 @@
</template> </template>
<script> <script>
import elDragDialog from '@/directive/el-dragDialog' // base on element-ui import elDragDialog from '@/directive/el-drag-dialog' // base on element-ui
export default { export default {
name: 'DragDialogDemo', name: 'DragDialogDemo',

View File

@ -1,9 +1,9 @@
<template> <template>
<div class="components-container"> <div class="components-container">
<code> <aside>
Based on <a class="link-type" href="https://github.com/rowanwins/vue-dropzone"> dropzone </a>. Based on <a class="link-type" href="https://github.com/rowanwins/vue-dropzone"> dropzone </a>.
{{ $t('components.dropzoneTips') }} {{ $t('components.dropzoneTips') }}
</code> </aside>
<div class="editor-container"> <div class="editor-container">
<dropzone id="myVueDropzone" url="https://httpbin.org/post" @dropzone-removedFile="dropzoneR" @dropzone-success="dropzoneS" /> <dropzone id="myVueDropzone" url="https://httpbin.org/post" @dropzone-removedFile="dropzoneR" @dropzone-success="dropzoneS" />
</div> </div>

View File

@ -1,10 +1,10 @@
<template> <template>
<div class="components-container"> <div class="components-container">
<code>Json-Editor is base on <a href="https://github.com/codemirror/CodeMirror" target="_blank">CodeMirrorr</a>. Lint <aside>Json-Editor is base on <a href="https://github.com/codemirror/CodeMirror" target="_blank">CodeMirrorr</a>. Lint
base on <a base on <a
href="https://github.com/codemirror/CodeMirror/blob/master/addon/lint/json-lint.js" href="https://github.com/codemirror/CodeMirror/blob/master/addon/lint/json-lint.js"
target="_blank" target="_blank"
>json-lint</a>.</code> >json-lint</a>.</aside>
<div class="editor-container"> <div class="editor-container">
<json-editor ref="jsonEditor" v-model="value" /> <json-editor ref="jsonEditor" v-model="value" />
</div> </div>

View File

@ -1,13 +1,13 @@
<template> <template>
<div class="components-container"> <div class="components-container">
<code>Markdown is based on <aside>Markdown is based on
<a href="https://github.com/nhnent/tui.editor" target="_blank">tui.editor</a> simply wrapped with Vue. <a href="https://github.com/nhnent/tui.editor" target="_blank">tui.editor</a> simply wrapped with Vue.
<a <a
target="_blank" target="_blank"
href="https://panjiachen.github.io/vue-element-admin-site/feature/component/markdown-editor.html" href="https://panjiachen.github.io/vue-element-admin-site/feature/component/markdown-editor.html"
> >
Documentation </a> Documentation </a>
</code> </aside>
<div class="editor-container"> <div class="editor-container">
<el-tag class="tag-title"> <el-tag class="tag-title">

View File

@ -115,7 +115,7 @@
import PanThumb from '@/components/PanThumb' import PanThumb from '@/components/PanThumb'
import MdInput from '@/components/MDinput' import MdInput from '@/components/MDinput'
import Mallki from '@/components/TextHoverEffect/Mallki' import Mallki from '@/components/TextHoverEffect/Mallki'
import DropdownMenu from '@/components/Share/dropdownMenu' import DropdownMenu from '@/components/Share/DropdownMenu'
import waves from '@/directive/waves/index.js' // import waves from '@/directive/waves/index.js' //
export default { export default {

View File

@ -1,10 +1,10 @@
<template> <template>
<div class="components-container"> <div class="components-container">
<code><strong>SplitPane</strong> If you've used <aside><strong>SplitPane</strong> If you've used
<a href="http://codepen.io/" target="_blank"> codepen</a>, <a href="https://codepen.io/" target="_blank"> codepen</a>,
<a href="https://jsfiddle.net/" target="_blank"> jsfiddle </a>will not be unfamiliar. <a href="https://jsfiddle.net/" target="_blank"> jsfiddle </a>will not be unfamiliar.
<a href="https://github.com/PanJiaChen/vue-split-pane" target="_blank"> Github repository</a> <a href="https://github.com/PanJiaChen/vue-split-pane" target="_blank"> Github repository</a>
</code> </aside>
<split-pane split="vertical" @resize="resize"> <split-pane split="vertical" @resize="resize">
<template slot="paneL"> <template slot="paneL">
<div class="left-container" /> <div class="left-container" />

View File

@ -28,7 +28,7 @@
</el-dropdown> </el-dropdown>
<div class="time-container"> <div class="time-container">
<el-date-picker v-model="time" :picker-options="pickerOptions" type="datetime" format="yyyy-MM-dd HH:mm:ss" placeholder="Release time" /> <el-date-picker v-model="time" type="datetime" format="yyyy-MM-dd HH:mm:ss" placeholder="Release time" />
</div> </div>
<el-button style="margin-left: 10px;" type="success"> <el-button style="margin-left: 10px;" type="success">
@ -37,7 +37,7 @@
</sticky> </sticky>
<div class="components-container"> <div class="components-container">
<code>Sticky header, {{ $t('components.stickyTips') }}</code> <aside>Sticky header, {{ $t('components.stickyTips') }}</aside>
<div>placeholder</div> <div>placeholder</div>
<div>placeholder</div> <div>placeholder</div>
<div>placeholder</div> <div>placeholder</div>

View File

@ -1,9 +1,9 @@
<template> <template>
<div class="components-container"> <div class="components-container">
<code> <aside>
{{ $t('components.tinymceTips') }} {{ $t('components.tinymceTips') }}
<a target="_blank" class="link-type" href="https://panjiachen.github.io/vue-element-admin-site/component/rich-editor.html"> {{ $t('components.documentation') }}</a> <a target="_blank" class="link-type" href="https://panjiachen.github.io/vue-element-admin-site/component/rich-editor.html"> {{ $t('components.documentation') }}</a>
</code> </aside>
<div> <div>
<tinymce v-model="content" :height="300" /> <tinymce v-model="content" :height="300" />
</div> </div>

View File

@ -21,7 +21,7 @@
</template> </template>
<script> <script>
import { transactionList } from '@/api/remoteSearch' import { transactionList } from '@/api/remote-search'
export default { export default {
filters: { filters: {

View File

@ -7,7 +7,7 @@
</div> </div>
</template> </template>
<script> <script>
import DropdownMenu from '@/components/Share/dropdownMenu' import DropdownMenu from '@/components/Share/DropdownMenu'
export default { export default {
name: 'Documentation', name: 'Documentation',

View File

@ -1,15 +1,15 @@
<template> <template>
<div class="errPage-container"> <div class="errPage-container">
<errorA /> <ErrorA />
<errorB /> <ErrorB />
<!-- $t is vue-i18n global function to translate lang --> <!-- $t is vue-i18n global function to translate lang -->
<h3>{{ $t('errorLog.tips') }}</h3> <h3>{{ $t('errorLog.tips') }}</h3>
<code> <aside>
{{ $t('errorLog.description') }} {{ $t('errorLog.description') }}
<a target="_blank" class="link-type" href="https://panjiachen.github.io/vue-element-admin-site/guide/advanced/error.html"> <a target="_blank" class="link-type" href="https://panjiachen.github.io/vue-element-admin-site/guide/advanced/error.html">
{{ $t('errorLog.documentation') }} {{ $t('errorLog.documentation') }}
</a> </a>
</code> </aside>
<a href="#"> <a href="#">
<img src="https://wpimg.wallstcn.com/360e4842-4db5-42d0-b078-f9a84a825546.gif"> <img src="https://wpimg.wallstcn.com/360e4842-4db5-42d0-b078-f9a84a825546.gif">
</a> </a>
@ -17,12 +17,12 @@
</template> </template>
<script> <script>
import errorA from './errorTestA' import ErrorA from './components/ErrorTestA'
import errorB from './errorTestB' import ErrorB from './components/ErrorTestB'
export default { export default {
name: 'ErrorLog', name: 'ErrorLog',
components: { errorA, errorB } components: { ErrorA, ErrorB }
} }
</script> </script>

View File

@ -6,10 +6,10 @@
<PlatformDropdown v-model="postForm.platforms" /> <PlatformDropdown v-model="postForm.platforms" />
<SourceUrlDropdown v-model="postForm.source_uri" /> <SourceUrlDropdown v-model="postForm.source_uri" />
<el-button v-loading="loading" style="margin-left: 10px;" type="success" @click="submitForm"> <el-button v-loading="loading" style="margin-left: 10px;" type="success" @click="submitForm">
发布 Publush
</el-button> </el-button>
<el-button v-loading="loading" type="warning" @click="draftForm"> <el-button v-loading="loading" type="warning" @click="draftForm">
草稿 Draft
</el-button> </el-button>
</sticky> </sticky>
@ -20,28 +20,28 @@
<el-col :span="24"> <el-col :span="24">
<el-form-item style="margin-bottom: 40px;" prop="title"> <el-form-item style="margin-bottom: 40px;" prop="title">
<MDinput v-model="postForm.title" :maxlength="100" name="name" required> <MDinput v-model="postForm.title" :maxlength="100" name="name" required>
标题 Title
</MDinput> </MDinput>
</el-form-item> </el-form-item>
<div class="postInfo-container"> <div class="postInfo-container">
<el-row> <el-row>
<el-col :span="8"> <el-col :span="8">
<el-form-item label-width="45px" label="作者:" class="postInfo-container-item"> <el-form-item label-width="60px" label="Author:" class="postInfo-container-item">
<el-select v-model="postForm.author" :remote-method="getRemoteUserList" filterable default-first-option remote placeholder="搜索用户"> <el-select v-model="postForm.author" :remote-method="getRemoteUserList" filterable default-first-option remote placeholder="Search user">
<el-option v-for="(item,index) in userListOptions" :key="item+index" :label="item" :value="item" /> <el-option v-for="(item,index) in userListOptions" :key="item+index" :label="item" :value="item" />
</el-select> </el-select>
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="10"> <el-col :span="10">
<el-form-item label-width="80px" label="发布时间:" class="postInfo-container-item"> <el-form-item label-width="120px" label="Publush Time:" class="postInfo-container-item">
<el-date-picker v-model="postForm.display_time" type="datetime" format="yyyy-MM-dd HH:mm:ss" placeholder="选择日期时间" /> <el-date-picker v-model="postForm.display_time" type="datetime" format="yyyy-MM-dd HH:mm:ss" placeholder="Select date and time" />
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="6"> <el-col :span="6">
<el-form-item label-width="60px" label="重要性:" class="postInfo-container-item"> <el-form-item label-width="90px" label="Importance:" class="postInfo-container-item">
<el-rate <el-rate
v-model="postForm.importance" v-model="postForm.importance"
:max="3" :max="3"
@ -57,9 +57,9 @@
</el-col> </el-col>
</el-row> </el-row>
<el-form-item style="margin-bottom: 40px;" label-width="45px" label="摘要:"> <el-form-item style="margin-bottom: 40px;" label-width="70px" label="Summary:">
<el-input v-model="postForm.content_short" :rows="1" type="textarea" class="article-textarea" autosize placeholder="请输入内容" /> <el-input v-model="postForm.content_short" :rows="1" type="textarea" class="article-textarea" autosize placeholder="Please enter the content" />
<span v-show="contentShortLength" class="word-counter">{{ contentShortLength }}</span> <span v-show="contentShortLength" class="word-counter">{{ contentShortLength }}words</span>
</el-form-item> </el-form-item>
<el-form-item prop="content" style="margin-bottom: 30px;"> <el-form-item prop="content" style="margin-bottom: 30px;">
@ -76,12 +76,12 @@
<script> <script>
import Tinymce from '@/components/Tinymce' import Tinymce from '@/components/Tinymce'
import Upload from '@/components/Upload/singleImage3' import Upload from '@/components/Upload/SingleImage3'
import MDinput from '@/components/MDinput' import MDinput from '@/components/MDinput'
import Sticky from '@/components/Sticky' // header import Sticky from '@/components/Sticky' // header
import { validURL } from '@/utils/validate' import { validURL } from '@/utils/validate'
import { fetchArticle } from '@/api/article' import { fetchArticle } from '@/api/article'
import { searchUser } from '@/api/remoteSearch' import { searchUser } from '@/api/remote-search'
import Warning from './Warning' import Warning from './Warning'
import { CommentDropdown, PlatformDropdown, SourceUrlDropdown } from './Dropdown' import { CommentDropdown, PlatformDropdown, SourceUrlDropdown } from './Dropdown'
@ -236,24 +236,39 @@ export default {
<style lang="scss" scoped> <style lang="scss" scoped>
@import "~@/styles/mixin.scss"; @import "~@/styles/mixin.scss";
.createPost-container { .createPost-container {
position: relative; position: relative;
.createPost-main-container { .createPost-main-container {
padding: 40px 45px 20px 50px; padding: 40px 45px 20px 50px;
.postInfo-container { .postInfo-container {
position: relative; position: relative;
@include clearfix; @include clearfix;
margin-bottom: 10px; margin-bottom: 10px;
.postInfo-container-item { .postInfo-container-item {
float: left; float: left;
} }
} }
} }
.word-counter { .word-counter {
width: 40px; width: 40px;
position: absolute; position: absolute;
right: -10px; right: 10px;
top: 0px; top: 0px;
} }
} }
.article-textarea /deep/ {
textarea {
padding-right: 40px;
resize: none;
border: none;
border-radius: 0px;
border-bottom: 1px solid #bfcbd9;
}
}
</style> </style>

View File

@ -1,17 +1,17 @@
<template> <template>
<el-dropdown :show-timeout="100" trigger="click"> <el-dropdown :show-timeout="100" trigger="click">
<el-button plain> <el-button plain>
{{ !comment_disabled?'评论已打开':'评论已关闭' }} {{ !comment_disabled?'Comment: opened':'Comment: closed' }}
<i class="el-icon-caret-bottom el-icon--right" /> <i class="el-icon-caret-bottom el-icon--right" />
</el-button> </el-button>
<el-dropdown-menu slot="dropdown" class="no-padding"> <el-dropdown-menu slot="dropdown" class="no-padding">
<el-dropdown-item> <el-dropdown-item>
<el-radio-group v-model="comment_disabled" style="padding: 10px;"> <el-radio-group v-model="comment_disabled" style="padding: 10px;">
<el-radio :label="true"> <el-radio :label="true">
关闭评论 Close comment
</el-radio> </el-radio>
<el-radio :label="false"> <el-radio :label="false">
打开评论 Open comment
</el-radio> </el-radio>
</el-radio-group> </el-radio-group>
</el-dropdown-item> </el-dropdown-item>

View File

@ -1,7 +1,7 @@
<template> <template>
<el-dropdown :hide-on-click="false" :show-timeout="100" trigger="click"> <el-dropdown :hide-on-click="false" :show-timeout="100" trigger="click">
<el-button plain> <el-button plain>
平台({{ platforms.length }}) Platfroms({{ platforms.length }})
<i class="el-icon-caret-bottom el-icon--right" /> <i class="el-icon-caret-bottom el-icon--right" />
</el-button> </el-button>
<el-dropdown-menu slot="dropdown" class="no-border"> <el-dropdown-menu slot="dropdown" class="no-border">

View File

@ -1,14 +1,14 @@
<template> <template>
<el-dropdown :show-timeout="100" trigger="click"> <el-dropdown :show-timeout="100" trigger="click">
<el-button plain> <el-button plain>
外链 Link
<i class="el-icon-caret-bottom el-icon--right" /> <i class="el-icon-caret-bottom el-icon--right" />
</el-button> </el-button>
<el-dropdown-menu slot="dropdown" class="no-padding no-border" style="width:400px"> <el-dropdown-menu slot="dropdown" class="no-padding no-border" style="width:400px">
<el-form-item label-width="0px" style="margin-bottom: 0px" prop="source_uri"> <el-form-item label-width="0px" style="margin-bottom: 0px" prop="source_uri">
<el-input v-model="source_uri" placeholder="请输入内容"> <el-input v-model="source_uri" placeholder="Please enter the content">
<template slot="prepend"> <template slot="prepend">
填写url URL
</template> </template>
</el-input> </el-input>
</el-form-item> </el-form-item>

View File

@ -1,11 +1,10 @@
<template> <template>
<p class="warn-content"> <aside>
创建和编辑页面是不能被keep-alive 缓存的因为keep-alive 的include 目前不支持根据路由来缓存所以目前都是基于component name 来缓存的如果你想要实现缓存的效果可以使用localstorage 等浏览器缓存方案或者不要使用keep-alive {{ $t('example.warning') }}
的include直接缓存所有页面详情见
<a <a
href="https://panjiachen.github.io/vue-element-admin-site/guide/essentials/tags-view.html" href="https://panjiachen.github.io/vue-element-admin-site/guide/essentials/tags-view.html"
target="_blank" target="_blank"
>文档</a> >Document</a>
</p> </aside>
</template> </template>

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>

Some files were not shown because too many files have changed in this diff Show More