Merge branch 'master' into deploy
This commit is contained in:
commit
5935f7a56c
27
README.md
27
README.md
|
@ -38,25 +38,32 @@ It is a magical vue admin based on the newest development stack of vue, built-in
|
|||
|
||||
- [Donate](https://panjiachen.github.io/vue-element-admin-site/donate/)
|
||||
|
||||
- [Gitee](https://panjiachen.gitee.io/vue-element-admin/) 国内用户可访问该地址在线预览
|
||||
|
||||
**This project is positioned as a background integration solution and is not suitable for secondary development as a basic template.**
|
||||
|
||||
- Base template recommends using: [vueAdmin-template](https://github.com/PanJiaChen/vueAdmin-template)
|
||||
- Desktop: [electron-vue-admin](https://github.com/PanJiaChen/electron-vue-admin)
|
||||
- Base template recommends using: [vueAdmin-template](https://github.com/PanJiaChen/vueAdmin-template)
|
||||
- Desktop: [electron-vue-admin](https://github.com/PanJiaChen/electron-vue-admin)
|
||||
|
||||
**This project does not support low version browsers (e.g. IE). Please add polyfill yourself if you need them.**
|
||||
|
||||
**Note: This project uses element-ui@2.3.0+ version, so the minimum compatible vue@2.5.0+**
|
||||
|
||||
**Start using `webpack4` from `v3.8.0`. If you still want to continue using `webpack3`, please use this branch [webpack3](https://github.com/PanJiaChen/vue-element-admin/tree/webpack3)**
|
||||
|
||||
## 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/), [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.
|
||||
|
||||
**This project does not support low version browsers (e.g. IE). Please add polyfill yourself if you need them.**
|
||||
|
||||
**Note: This project uses element-ui@2.3.0+ version, so the minimum compatible vue@2.5.0+**
|
||||
---
|
||||
|
||||
<p align="center">
|
||||
<img width="900" src="https://wpimg.wallstcn.com/a5894c1b-f6af-456e-82df-1151da0839bf.png">
|
||||
</p>
|
||||
|
||||
## Features
|
||||
|
||||
```
|
||||
- Login / Logout
|
||||
|
||||
|
@ -136,6 +143,7 @@ npm run dev
|
|||
This will automatically open http://localhost:9527.
|
||||
|
||||
## Build
|
||||
|
||||
```bash
|
||||
# build for test environment
|
||||
npm run build:sit
|
||||
|
@ -145,10 +153,14 @@ npm run build:prod
|
|||
```
|
||||
|
||||
## Advanced
|
||||
|
||||
```bash
|
||||
# --report to build with bundle size analytics
|
||||
npm run build:prod --report
|
||||
|
||||
# --generate a bundle size analytics. default: bundle-report.html
|
||||
npm run build:prod --generate_report
|
||||
|
||||
# --preview to start a server in local to preview
|
||||
npm run build:prod --preview
|
||||
|
||||
|
@ -162,12 +174,15 @@ npm run lint -- --fix
|
|||
Refer to [Documentation](https://panjiachen.github.io/vue-element-admin-site/guide/essentials/deploy.html) for more information
|
||||
|
||||
## Changelog
|
||||
|
||||
Detailed changes for each release are documented in the [release notes](https://github.com/PanJiaChen/vue-element-admin/releases).
|
||||
|
||||
## Online Demo
|
||||
|
||||
[Preview](http://panjiachen.github.io/vue-element-admin)
|
||||
|
||||
## Donate
|
||||
|
||||
If you find this project useful, you can buy author a glass of juice :tropical_drink:
|
||||
|
||||
![donate](https://wpimg.wallstcn.com/bd273f0d-83a0-4ef2-92e1-9ac8ed3746b9.png)
|
||||
|
|
|
@ -24,50 +24,56 @@
|
|||
|
||||
## 简介
|
||||
|
||||
[vue-element-admin](http://panjiachen.github.io/vue-element-admin) 是一个后台集成解决方案,它基于 [vue](https://github.com/vuejs/vue) 和 [element](https://github.com/ElemeFE/element)。它使用了最新的前端技术栈,内置了i18国际化解决方案,动态路由,权限验证,提炼了典型的业务模型,提供了丰富的功能组件,它可以帮助你快速搭建企业级中后台产品原型。相信不管你的需求是什么,本项目都能帮助到你。
|
||||
[vue-element-admin](http://panjiachen.github.io/vue-element-admin) 是一个后台集成解决方案,它基于 [vue](https://github.com/vuejs/vue) 和 [element](https://github.com/ElemeFE/element)。它使用了最新的前端技术栈,内置了 i18 国际化解决方案,动态路由,权限验证,提炼了典型的业务模型,提供了丰富的功能组件,它可以帮助你快速搭建企业级中后台产品原型。相信不管你的需求是什么,本项目都能帮助到你。
|
||||
|
||||
- [在线访问](http://panjiachen.github.io/vue-element-admin)
|
||||
|
||||
- [使用文档](https://panjiachen.github.io/vue-element-admin-site/zh/)
|
||||
|
||||
- [Gitter讨论组](https://gitter.im/vue-element-admin/discuss)
|
||||
- [Gitter 讨论组](https://gitter.im/vue-element-admin/discuss)
|
||||
|
||||
- [Wiki](https://github.com/PanJiaChen/vue-element-admin/wiki)
|
||||
|
||||
- [Donate](https://panjiachen.github.io/vue-element-admin-site/zh/donate/)
|
||||
|
||||
- [Gitee](https://panjiachen.gitee.io/vue-element-admin/) 国内用户可访问该地址在线预览
|
||||
|
||||
**本项目的定位是后台集成方案,不适合当基础模板来开发。**
|
||||
- 模板建议使用: [vueAdmin-template](https://github.com/PanJiaChen/vueAdmin-template)
|
||||
- 桌面端: [electron-vue-admin](https://github.com/PanJiaChen/electron-vue-admin)
|
||||
|
||||
- 模板建议使用: [vueAdmin-template](https://github.com/PanJiaChen/vueAdmin-template)
|
||||
- 桌面端: [electron-vue-admin](https://github.com/PanJiaChen/electron-vue-admin)
|
||||
|
||||
群主 **[圈子](https://jianshiapp.com/circles/1209)** 楼主会经常分享一些技术相关的东西,或者加入[qq 群](https://github.com/PanJiaChen/vue-element-admin/issues/602)
|
||||
|
||||
**注意:该项目使用 element-ui@2.3.0+ 版本,所以最低兼容 vue@2.5.0+**
|
||||
|
||||
**从`v3.8.0`开始使用`webpack4`。所以若还想使用`webpack3`开发,请使用该分支[webpack3](https://github.com/PanJiaChen/vue-element-admin/tree/webpack3)**
|
||||
|
||||
**该项目不支持低版本浏览器(如 ie),有需求请自行添加 polyfill [详情](https://github.com/PanJiaChen/vue-element-admin/wiki#babel-polyfill)**
|
||||
|
||||
## 前序准备
|
||||
|
||||
你需要在本地安装 [node](http://nodejs.org/) 和 [git](https://git-scm.com/)。本项目技术栈基于 [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/) 、[axios](https://github.com/axios/axios) 和 [element-ui](https://github.com/ElemeFE/element),所有的请求数据都使用[Mock.js](https://github.com/nuysoft/Mock)模拟,提前了解和学习这些知识会对使用本项目有很大的帮助。
|
||||
|
||||
同时配套一个系列的教程文章,如何从零构建后一个完整的后台项目,建议大家先看完这些文章再来实践本项目
|
||||
- [手摸手,带你用 vue 撸后台 系列一(基础篇)](https://juejin.im/post/59097cd7a22b9d0065fb61d2)
|
||||
- [手摸手,带你用 vue 撸后台 系列二(登录权限篇)](https://juejin.im/post/591aa14f570c35006961acac)
|
||||
- [手摸手,带你用 vue 撸后台 系列三 (实战篇)](https://juejin.im/post/593121aa0ce4630057f70d35)
|
||||
- [手摸手,带你用 vue 撸后台 系列四(vueAdmin 一个极简的后台基础模板)](https://juejin.im/post/595b4d776fb9a06bbe7dba56)
|
||||
- [手摸手,带你封装一个 vue component](https://segmentfault.com/a/1190000009090836)
|
||||
- [手摸手,带你优雅的使用 icon](https://juejin.im/post/59bb864b5188257e7a427c09)
|
||||
|
||||
- [手摸手,带你用 vue 撸后台 系列一(基础篇)](https://juejin.im/post/59097cd7a22b9d0065fb61d2)
|
||||
- [手摸手,带你用 vue 撸后台 系列二(登录权限篇)](https://juejin.im/post/591aa14f570c35006961acac)
|
||||
- [手摸手,带你用 vue 撸后台 系列三 (实战篇)](https://juejin.im/post/593121aa0ce4630057f70d35)
|
||||
- [手摸手,带你用 vue 撸后台 系列四(vueAdmin 一个极简的后台基础模板)](https://juejin.im/post/595b4d776fb9a06bbe7dba56)
|
||||
- [手摸手,带你封装一个 vue component](https://segmentfault.com/a/1190000009090836)
|
||||
- [手摸手,带你优雅的使用 icon](https://juejin.im/post/59bb864b5188257e7a427c09)
|
||||
- [手摸手,带你用合理的姿势使用 webpack4(上)](https://juejin.im/post/5b56909a518825195f499806)
|
||||
- [手摸手,带你用合理的姿势使用 webpack4(下)](https://juejin.im/post/5b5d6d6f6fb9a04fea58aabc)
|
||||
|
||||
或者加入该群主 **[圈子](https://jianshiapp.com/circles/1209)** 楼主会经常分享一些技术相关的东西
|
||||
|
||||
**如有问题请先看上述使用文档和文章,若不能满足,欢迎 issue 和 pr**
|
||||
|
||||
**本项目并不是一个脚手架,更倾向于是一个集成解决方案**
|
||||
|
||||
**注意:该项目使用 element-ui@2.3.0+ 版本,所以最低兼容 vue@2.5.0+**
|
||||
|
||||
**该项目不支持低版本浏览器(如ie),有需求请自行添加polyfill [详情](https://github.com/PanJiaChen/vue-element-admin/wiki#babel-polyfill)**
|
||||
**如有问题请先看上述使用文档和文章,若不能满足,欢迎 issue 和 pr**
|
||||
|
||||
<p align="center">
|
||||
<img width="900" src="https://wpimg.wallstcn.com/a5894c1b-f6af-456e-82df-1151da0839bf.png">
|
||||
</p>
|
||||
|
||||
## 功能
|
||||
|
||||
```
|
||||
- 登录 / 注销
|
||||
|
||||
|
@ -132,22 +138,25 @@
|
|||
```
|
||||
|
||||
## 开发
|
||||
|
||||
```bash
|
||||
# 克隆项目
|
||||
git clone https://github.com/PanJiaChen/vue-element-admin.git
|
||||
|
||||
# 安装依赖
|
||||
npm install
|
||||
|
||||
|
||||
# 建议不要用cnpm安装 会有各种诡异的bug 可以通过如下操作解决 npm 下载速度慢的问题
|
||||
npm install --registry=https://registry.npm.taobao.org
|
||||
|
||||
# 启动服务
|
||||
npm run dev
|
||||
```
|
||||
|
||||
浏览器访问 http://localhost:9527
|
||||
|
||||
## 发布
|
||||
|
||||
```bash
|
||||
# 构建测试环境
|
||||
npm run build:sit
|
||||
|
@ -157,9 +166,13 @@ npm run build:prod
|
|||
```
|
||||
|
||||
## 其它
|
||||
|
||||
```bash
|
||||
# --report to build with bundle size analytics
|
||||
npm run build:prod --report
|
||||
npm run build:prod
|
||||
|
||||
# --generate a bundle size analytics. default: bundle-report.html
|
||||
npm run build:prod --generate_report
|
||||
|
||||
# --preview to start a server in local to preview
|
||||
npm run build:prod --preview
|
||||
|
@ -174,12 +187,15 @@ npm run lint -- --fix
|
|||
更多信息请参考 [使用文档](https://panjiachen.github.io/vue-element-admin-site/zh/)
|
||||
|
||||
## Changelog
|
||||
|
||||
Detailed changes for each release are documented in the [release notes](https://github.com/PanJiaChen/vue-element-admin/releases).
|
||||
|
||||
## Online Demo
|
||||
|
||||
[在线 Demo](http://panjiachen.github.io/vue-element-admin)
|
||||
|
||||
## Donate
|
||||
|
||||
如果你觉得这个项目帮助到了你,你可以帮作者买一杯果汁表示鼓励 :tropical_drink:
|
||||
![donate](https://panjiachen.github.io/donate/donation.png)
|
||||
|
||||
|
|
|
@ -8,10 +8,12 @@ const chalk = require('chalk')
|
|||
const webpack = require('webpack')
|
||||
const config = require('../config')
|
||||
const webpackConfig = require('./webpack.prod.conf')
|
||||
var connect = require('connect');
|
||||
var connect = require('connect')
|
||||
var serveStatic = require('serve-static')
|
||||
|
||||
const spinner = ora('building for ' + process.env.env_config + ' environment...')
|
||||
const spinner = ora(
|
||||
'building for ' + process.env.env_config + ' environment...'
|
||||
)
|
||||
spinner.start()
|
||||
|
||||
rm(path.join(config.build.assetsRoot, config.build.assetsSubDirectory), err => {
|
||||
|
@ -19,13 +21,15 @@ rm(path.join(config.build.assetsRoot, config.build.assetsSubDirectory), err => {
|
|||
webpack(webpackConfig, (err, stats) => {
|
||||
spinner.stop()
|
||||
if (err) throw err
|
||||
process.stdout.write(stats.toString({
|
||||
colors: true,
|
||||
modules: false,
|
||||
children: false,
|
||||
chunks: false,
|
||||
chunkModules: false
|
||||
}) + '\n\n')
|
||||
process.stdout.write(
|
||||
stats.toString({
|
||||
colors: true,
|
||||
modules: false,
|
||||
children: false,
|
||||
chunks: false,
|
||||
chunkModules: false
|
||||
}) + '\n\n'
|
||||
)
|
||||
|
||||
if (stats.hasErrors()) {
|
||||
console.log(chalk.red(' Build failed with errors.\n'))
|
||||
|
@ -33,24 +37,31 @@ rm(path.join(config.build.assetsRoot, config.build.assetsSubDirectory), err => {
|
|||
}
|
||||
|
||||
console.log(chalk.cyan(' Build complete.\n'))
|
||||
console.log(chalk.yellow(
|
||||
' Tip: built files are meant to be served over an HTTP server.\n' +
|
||||
' Opening index.html over file:// won\'t work.\n'
|
||||
))
|
||||
console.log(
|
||||
chalk.yellow(
|
||||
' Tip: built files are meant to be served over an HTTP server.\n' +
|
||||
" Opening index.html over file:// won't work.\n"
|
||||
)
|
||||
)
|
||||
|
||||
if (process.env.npm_config_preview) {
|
||||
const port = 9526
|
||||
const host = "http://localhost:" + port
|
||||
const host = 'http://localhost:' + port
|
||||
const basePath = config.build.assetsPublicPath
|
||||
const app = connect()
|
||||
|
||||
app.use(basePath, serveStatic('./dist', {
|
||||
'index': ['index.html', '/']
|
||||
}))
|
||||
app.use(
|
||||
basePath,
|
||||
serveStatic('./dist', {
|
||||
index: ['index.html', '/']
|
||||
})
|
||||
)
|
||||
|
||||
app.listen(port, function () {
|
||||
console.log(chalk.green(`> Listening at http://localhost:${port}${basePath}`))
|
||||
});
|
||||
app.listen(port, function() {
|
||||
console.log(
|
||||
chalk.green(`> Listening at http://localhost:${port}${basePath}`)
|
||||
)
|
||||
})
|
||||
}
|
||||
})
|
||||
})
|
||||
|
|
|
@ -4,8 +4,11 @@ const semver = require('semver')
|
|||
const packageConfig = require('../package.json')
|
||||
const shell = require('shelljs')
|
||||
|
||||
function exec (cmd) {
|
||||
return require('child_process').execSync(cmd).toString().trim()
|
||||
function exec(cmd) {
|
||||
return require('child_process')
|
||||
.execSync(cmd)
|
||||
.toString()
|
||||
.trim()
|
||||
}
|
||||
|
||||
const versionRequirements = [
|
||||
|
@ -24,23 +27,30 @@ if (shell.which('npm')) {
|
|||
})
|
||||
}
|
||||
|
||||
module.exports = function () {
|
||||
module.exports = function() {
|
||||
const warnings = []
|
||||
|
||||
for (let i = 0; i < versionRequirements.length; i++) {
|
||||
const mod = versionRequirements[i]
|
||||
|
||||
if (!semver.satisfies(mod.currentVersion, mod.versionRequirement)) {
|
||||
warnings.push(mod.name + ': ' +
|
||||
chalk.red(mod.currentVersion) + ' should be ' +
|
||||
chalk.green(mod.versionRequirement)
|
||||
warnings.push(
|
||||
mod.name +
|
||||
': ' +
|
||||
chalk.red(mod.currentVersion) +
|
||||
' should be ' +
|
||||
chalk.green(mod.versionRequirement)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
if (warnings.length) {
|
||||
console.log('')
|
||||
console.log(chalk.yellow('To use this template, you must update following to modules:'))
|
||||
console.log(
|
||||
chalk.yellow(
|
||||
'To use this template, you must update following to modules:'
|
||||
)
|
||||
)
|
||||
console.log()
|
||||
|
||||
for (let i = 0; i < warnings.length; i++) {
|
||||
|
|
|
@ -1,18 +1,19 @@
|
|||
'use strict'
|
||||
const path = require('path')
|
||||
const config = require('../config')
|
||||
const ExtractTextPlugin = require('extract-text-webpack-plugin')
|
||||
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
|
||||
const packageConfig = require('../package.json')
|
||||
|
||||
exports.assetsPath = function (_path) {
|
||||
const assetsSubDirectory = process.env.NODE_ENV === 'production'
|
||||
? config.build.assetsSubDirectory
|
||||
: config.dev.assetsSubDirectory
|
||||
exports.assetsPath = function(_path) {
|
||||
const assetsSubDirectory =
|
||||
process.env.NODE_ENV === 'production'
|
||||
? config.build.assetsSubDirectory
|
||||
: config.dev.assetsSubDirectory
|
||||
|
||||
return path.posix.join(assetsSubDirectory, _path)
|
||||
}
|
||||
|
||||
exports.cssLoaders = function (options) {
|
||||
exports.cssLoaders = function(options) {
|
||||
options = options || {}
|
||||
|
||||
const cssLoader = {
|
||||
|
@ -30,8 +31,22 @@ exports.cssLoaders = function (options) {
|
|||
}
|
||||
|
||||
// generate loader string to be used with extract text plugin
|
||||
function generateLoaders (loader, loaderOptions) {
|
||||
const loaders = options.usePostCSS ? [cssLoader, postcssLoader] : [cssLoader]
|
||||
function generateLoaders(loader, loaderOptions) {
|
||||
const loaders = []
|
||||
|
||||
// Extract CSS when that option is specified
|
||||
// (which is the case during production build)
|
||||
if (options.extract) {
|
||||
loaders.push(MiniCssExtractPlugin.loader)
|
||||
} else {
|
||||
loaders.push('vue-style-loader')
|
||||
}
|
||||
|
||||
loaders.push(cssLoader)
|
||||
|
||||
if (options.usePostCSS) {
|
||||
loaders.push(postcssLoader)
|
||||
}
|
||||
|
||||
if (loader) {
|
||||
loaders.push({
|
||||
|
@ -42,24 +57,16 @@ exports.cssLoaders = function (options) {
|
|||
})
|
||||
}
|
||||
|
||||
// Extract CSS when that option is specified
|
||||
// (which is the case during production build)
|
||||
if (options.extract) {
|
||||
return ExtractTextPlugin.extract({
|
||||
use: loaders,
|
||||
fallback: 'vue-style-loader'
|
||||
})
|
||||
} else {
|
||||
return ['vue-style-loader'].concat(loaders)
|
||||
}
|
||||
return loaders
|
||||
}
|
||||
|
||||
// https://vue-loader.vuejs.org/en/configurations/extract-css.html
|
||||
return {
|
||||
css: generateLoaders(),
|
||||
postcss: generateLoaders(),
|
||||
less: generateLoaders('less'),
|
||||
sass: generateLoaders('sass', { indentedSyntax: true }),
|
||||
sass: generateLoaders('sass', {
|
||||
indentedSyntax: true
|
||||
}),
|
||||
scss: generateLoaders('sass'),
|
||||
stylus: generateLoaders('stylus'),
|
||||
styl: generateLoaders('stylus')
|
||||
|
@ -67,7 +74,7 @@ exports.cssLoaders = function (options) {
|
|||
}
|
||||
|
||||
// Generate loaders for standalone style files (outside of .vue)
|
||||
exports.styleLoaders = function (options) {
|
||||
exports.styleLoaders = function(options) {
|
||||
const output = []
|
||||
const loaders = exports.cssLoaders(options)
|
||||
|
||||
|
|
|
@ -1,22 +1,5 @@
|
|||
'use strict'
|
||||
const utils = require('./utils')
|
||||
const config = require('../config')
|
||||
const isProduction = process.env.NODE_ENV === 'production'
|
||||
const sourceMapEnabled = isProduction
|
||||
? config.build.productionSourceMap
|
||||
: config.dev.cssSourceMap
|
||||
|
||||
module.exports = {
|
||||
loaders: utils.cssLoaders({
|
||||
sourceMap: sourceMapEnabled,
|
||||
extract: isProduction
|
||||
}),
|
||||
cssSourceMap: sourceMapEnabled,
|
||||
cacheBusting: config.dev.cacheBusting,
|
||||
transformToRequire: {
|
||||
video: ['src', 'poster'],
|
||||
source: 'src',
|
||||
img: 'src',
|
||||
image: 'xlink:href'
|
||||
}
|
||||
//You can set the vue-loader configuration by yourself.
|
||||
}
|
||||
|
|
|
@ -2,9 +2,10 @@
|
|||
const path = require('path')
|
||||
const utils = require('./utils')
|
||||
const config = require('../config')
|
||||
const { VueLoaderPlugin } = require('vue-loader')
|
||||
const vueLoaderConfig = require('./vue-loader.conf')
|
||||
|
||||
function resolve (dir) {
|
||||
function resolve(dir) {
|
||||
return path.join(__dirname, '..', dir)
|
||||
}
|
||||
|
||||
|
@ -27,14 +28,15 @@ module.exports = {
|
|||
output: {
|
||||
path: config.build.assetsRoot,
|
||||
filename: '[name].js',
|
||||
publicPath: process.env.NODE_ENV === 'production'
|
||||
? config.build.assetsPublicPath
|
||||
: config.dev.assetsPublicPath
|
||||
publicPath:
|
||||
process.env.NODE_ENV === 'production'
|
||||
? config.build.assetsPublicPath
|
||||
: config.dev.assetsPublicPath
|
||||
},
|
||||
resolve: {
|
||||
extensions: ['.js', '.vue', '.json'],
|
||||
alias: {
|
||||
'@': resolve('src'),
|
||||
'@': resolve('src')
|
||||
}
|
||||
},
|
||||
module: {
|
||||
|
@ -48,7 +50,11 @@ module.exports = {
|
|||
{
|
||||
test: /\.js$/,
|
||||
loader: 'babel-loader?cacheDirectory',
|
||||
include: [resolve('src'), resolve('test'), resolve('node_modules/webpack-dev-server/client')]
|
||||
include: [
|
||||
resolve('src'),
|
||||
resolve('test'),
|
||||
resolve('node_modules/webpack-dev-server/client')
|
||||
]
|
||||
},
|
||||
{
|
||||
test: /\.svg$/,
|
||||
|
@ -85,6 +91,7 @@ module.exports = {
|
|||
}
|
||||
]
|
||||
},
|
||||
plugins: [new VueLoaderPlugin()],
|
||||
node: {
|
||||
// prevent webpack from injecting useless setImmediate polyfill because Vue
|
||||
// source contains it (although only uses it if it's native).
|
||||
|
|
|
@ -9,7 +9,7 @@ const HtmlWebpackPlugin = require('html-webpack-plugin')
|
|||
const FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin')
|
||||
const portfinder = require('portfinder')
|
||||
|
||||
function resolve (dir) {
|
||||
function resolve(dir) {
|
||||
return path.join(__dirname, '..', dir)
|
||||
}
|
||||
|
||||
|
@ -17,8 +17,12 @@ const HOST = process.env.HOST
|
|||
const PORT = process.env.PORT && Number(process.env.PORT)
|
||||
|
||||
const devWebpackConfig = merge(baseWebpackConfig, {
|
||||
mode: 'development',
|
||||
module: {
|
||||
rules: utils.styleLoaders({ sourceMap: config.dev.cssSourceMap, usePostCSS: true })
|
||||
rules: utils.styleLoaders({
|
||||
sourceMap: config.dev.cssSourceMap,
|
||||
usePostCSS: true
|
||||
})
|
||||
},
|
||||
// cheap-module-eval-source-map is faster for development
|
||||
devtool: config.dev.devtool,
|
||||
|
@ -39,7 +43,7 @@ const devWebpackConfig = merge(baseWebpackConfig, {
|
|||
proxy: config.dev.proxyTable,
|
||||
quiet: true, // necessary for FriendlyErrorsPlugin
|
||||
watchOptions: {
|
||||
poll: config.dev.poll,
|
||||
poll: config.dev.poll
|
||||
}
|
||||
},
|
||||
plugins: [
|
||||
|
@ -47,8 +51,6 @@ const devWebpackConfig = merge(baseWebpackConfig, {
|
|||
'process.env': require('../config/dev.env')
|
||||
}),
|
||||
new webpack.HotModuleReplacementPlugin(),
|
||||
new webpack.NamedModulesPlugin(), // HMR shows correct file names in console on update.
|
||||
new webpack.NoEmitOnErrorsPlugin(),
|
||||
// https://github.com/ampedandwired/html-webpack-plugin
|
||||
new HtmlWebpackPlugin({
|
||||
filename: 'index.html',
|
||||
|
@ -57,7 +59,7 @@ const devWebpackConfig = merge(baseWebpackConfig, {
|
|||
favicon: resolve('favicon.ico'),
|
||||
title: 'vue-element-admin',
|
||||
path: config.dev.assetsPublicPath + config.dev.assetsSubDirectory
|
||||
}),
|
||||
})
|
||||
]
|
||||
})
|
||||
|
||||
|
@ -73,14 +75,20 @@ module.exports = new Promise((resolve, reject) => {
|
|||
devWebpackConfig.devServer.port = port
|
||||
|
||||
// Add FriendlyErrorsPlugin
|
||||
devWebpackConfig.plugins.push(new FriendlyErrorsPlugin({
|
||||
compilationSuccessInfo: {
|
||||
messages: [`Your application is running here: http://${devWebpackConfig.devServer.host}:${port}`],
|
||||
},
|
||||
onErrors: config.dev.notifyOnErrors
|
||||
? utils.createNotifierCallback()
|
||||
: undefined
|
||||
}))
|
||||
devWebpackConfig.plugins.push(
|
||||
new FriendlyErrorsPlugin({
|
||||
compilationSuccessInfo: {
|
||||
messages: [
|
||||
`Your application is running here: http://${
|
||||
devWebpackConfig.devServer.host
|
||||
}:${port}`
|
||||
]
|
||||
},
|
||||
onErrors: config.dev.notifyOnErrors
|
||||
? utils.createNotifierCallback()
|
||||
: undefined
|
||||
})
|
||||
)
|
||||
|
||||
resolve(devWebpackConfig)
|
||||
}
|
||||
|
|
|
@ -7,17 +7,23 @@ const merge = require('webpack-merge')
|
|||
const baseWebpackConfig = require('./webpack.base.conf')
|
||||
const CopyWebpackPlugin = require('copy-webpack-plugin')
|
||||
const HtmlWebpackPlugin = require('html-webpack-plugin')
|
||||
const ExtractTextPlugin = require('extract-text-webpack-plugin')
|
||||
const OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin')
|
||||
const ScriptExtHtmlWebpackPlugin = require('script-ext-html-webpack-plugin')
|
||||
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
|
||||
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin')
|
||||
const UglifyJsPlugin = require('uglifyjs-webpack-plugin')
|
||||
|
||||
function resolve (dir) {
|
||||
function resolve(dir) {
|
||||
return path.join(__dirname, '..', dir)
|
||||
}
|
||||
|
||||
const env = require('../config/'+process.env.env_config+'.env')
|
||||
const env = require('../config/' + process.env.env_config + '.env')
|
||||
|
||||
// For NamedChunksPlugin
|
||||
const seen = new Set()
|
||||
const nameLength = 4
|
||||
|
||||
const webpackConfig = merge(baseWebpackConfig, {
|
||||
mode: 'production',
|
||||
module: {
|
||||
rules: utils.styleLoaders({
|
||||
sourceMap: config.build.productionSourceMap,
|
||||
|
@ -28,37 +34,18 @@ const webpackConfig = merge(baseWebpackConfig, {
|
|||
devtool: config.build.productionSourceMap ? config.build.devtool : false,
|
||||
output: {
|
||||
path: config.build.assetsRoot,
|
||||
filename: utils.assetsPath('js/[name].[chunkhash].js'),
|
||||
chunkFilename: utils.assetsPath('js/[id].[chunkhash].js')
|
||||
filename: utils.assetsPath('js/[name].[chunkhash:8].js'),
|
||||
chunkFilename: utils.assetsPath('js/[name].[chunkhash:8].js')
|
||||
},
|
||||
plugins: [
|
||||
// http://vuejs.github.io/vue-loader/en/workflow/production.html
|
||||
new webpack.DefinePlugin({
|
||||
'process.env': env
|
||||
}),
|
||||
new UglifyJsPlugin({
|
||||
uglifyOptions: {
|
||||
compress: {
|
||||
warnings: false
|
||||
}
|
||||
},
|
||||
sourceMap: config.build.productionSourceMap,
|
||||
parallel: true
|
||||
}),
|
||||
// extract css into its own file
|
||||
new ExtractTextPlugin({
|
||||
filename: utils.assetsPath('css/[name].[contenthash].css'),
|
||||
// Setting the following option to `false` will not extract CSS from codesplit chunks.
|
||||
// Their CSS will instead be inserted dynamically with style-loader when the codesplit chunk has been loaded by webpack.
|
||||
// increasing file size: https://github.com/vuejs-templates/webpack/issues/1110
|
||||
allChunks: false,
|
||||
}),
|
||||
// Compress extracted CSS. We are using this plugin so that possible
|
||||
// duplicated CSS from different components can be deduped.
|
||||
new OptimizeCSSPlugin({
|
||||
cssProcessorOptions: config.build.productionSourceMap
|
||||
? { safe: true, map: { inline: false } }
|
||||
: { safe: true }
|
||||
new MiniCssExtractPlugin({
|
||||
filename: utils.assetsPath('css/[name].[contenthash:8].css'),
|
||||
chunkFilename: utils.assetsPath('css/[name].[contenthash:8].css')
|
||||
}),
|
||||
// generate dist index.html with correct asset hash for caching.
|
||||
// you can customize output by editing /index.html
|
||||
|
@ -76,68 +63,34 @@ const webpackConfig = merge(baseWebpackConfig, {
|
|||
removeAttributeQuotes: true
|
||||
// more options:
|
||||
// https://github.com/kangax/html-minifier#options-quick-reference
|
||||
},
|
||||
// necessary to consistently work with multiple chunks via CommonsChunkPlugin
|
||||
chunksSortMode: 'dependency'
|
||||
}
|
||||
// default sort mode uses toposort which cannot handle cyclic deps
|
||||
// in certain cases, and in webpack 4, chunk order in HTML doesn't
|
||||
// matter anyway
|
||||
}),
|
||||
new ScriptExtHtmlWebpackPlugin({
|
||||
//`runtime` must same as runtimeChunk name. default is `runtime`
|
||||
inline: /runtime\..*\.js$/
|
||||
}),
|
||||
// keep chunk.id stable when chunk has no name
|
||||
new webpack.NamedChunksPlugin(chunk => {
|
||||
if (chunk.name) {
|
||||
return chunk.name
|
||||
}
|
||||
const modules = Array.from(chunk.modulesIterable)
|
||||
if (modules.length > 1) {
|
||||
const hash = require('hash-sum')
|
||||
const joinedHash = hash(modules.map(m => m.id).join('_'))
|
||||
let len = nameLength
|
||||
while (seen.has(joinedHash.substr(0, len))) len++
|
||||
seen.add(joinedHash.substr(0, len))
|
||||
return `chunk-${joinedHash.substr(0, len)}`
|
||||
} else {
|
||||
return modules[0].id
|
||||
}
|
||||
}),
|
||||
// keep module.id stable when vender modules does not change
|
||||
new webpack.HashedModuleIdsPlugin(),
|
||||
// enable scope hoisting
|
||||
new webpack.optimize.ModuleConcatenationPlugin(),
|
||||
// split vendor js into its own file
|
||||
new webpack.optimize.CommonsChunkPlugin({
|
||||
name: 'vendor',
|
||||
minChunks (module) {
|
||||
// any required modules inside node_modules are extracted to vendor
|
||||
return (
|
||||
module.resource &&
|
||||
/\.js$/.test(module.resource) &&
|
||||
module.resource.indexOf(
|
||||
path.join(__dirname, '../node_modules')
|
||||
) === 0
|
||||
)
|
||||
}
|
||||
}),
|
||||
// extract webpack runtime and module manifest to its own file in order to
|
||||
// prevent vendor hash from being updated whenever app bundle is updated
|
||||
new webpack.optimize.CommonsChunkPlugin({
|
||||
name: 'manifest',
|
||||
minChunks: Infinity
|
||||
}),
|
||||
// This instance extracts shared chunks from code splitted chunks and bundles them
|
||||
// in a separate chunk, similar to the vendor chunk
|
||||
// see: https://webpack.js.org/plugins/commons-chunk-plugin/#extra-async-commons-chunk
|
||||
new webpack.optimize.CommonsChunkPlugin({
|
||||
name: 'app',
|
||||
async: 'vendor-async',
|
||||
children: true,
|
||||
minChunks: 3
|
||||
}),
|
||||
// split echarts into its own file
|
||||
new webpack.optimize.CommonsChunkPlugin({
|
||||
async: 'echarts',
|
||||
minChunks(module) {
|
||||
var context = module.context;
|
||||
return context && (context.indexOf('echarts') >= 0 || context.indexOf('zrender') >= 0);
|
||||
}
|
||||
}),
|
||||
// split xlsx into its own file
|
||||
new webpack.optimize.CommonsChunkPlugin({
|
||||
async: 'xlsx',
|
||||
minChunks(module) {
|
||||
var context = module.context;
|
||||
return context && (context.indexOf('xlsx') >= 0);
|
||||
}
|
||||
}),
|
||||
// split codemirror into its own file
|
||||
new webpack.optimize.CommonsChunkPlugin({
|
||||
async: 'codemirror',
|
||||
minChunks(module) {
|
||||
var context = module.context;
|
||||
return context && (context.indexOf('codemirror') >= 0);
|
||||
}
|
||||
}),
|
||||
|
||||
// copy custom static assets
|
||||
new CopyWebpackPlugin([
|
||||
{
|
||||
|
@ -146,7 +99,48 @@ const webpackConfig = merge(baseWebpackConfig, {
|
|||
ignore: ['.*']
|
||||
}
|
||||
])
|
||||
]
|
||||
],
|
||||
optimization: {
|
||||
splitChunks: {
|
||||
chunks: 'all',
|
||||
cacheGroups: {
|
||||
libs: {
|
||||
name: 'chunk-libs',
|
||||
test: /[\\/]node_modules[\\/]/,
|
||||
priority: 10,
|
||||
chunks: 'initial' // 只打包初始时依赖的第三方
|
||||
},
|
||||
elementUI: {
|
||||
name: 'chunk-elementUI', // 单独将 elementUI 拆包
|
||||
priority: 20, // 权重要大于 libs 和 app 不然会被打包进 libs 或者 app
|
||||
test: /[\\/]node_modules[\\/]element-ui[\\/]/
|
||||
},
|
||||
commons: {
|
||||
name: 'chunk-comomns',
|
||||
test: resolve('src/components'), // 可自定义拓展你的规则
|
||||
minChunks: 3, // 最小公用次数
|
||||
priority: 5,
|
||||
reuseExistingChunk: true
|
||||
}
|
||||
}
|
||||
},
|
||||
runtimeChunk: 'single',
|
||||
minimizer: [
|
||||
new UglifyJsPlugin({
|
||||
uglifyOptions: {
|
||||
mangle: {
|
||||
safari10: true
|
||||
}
|
||||
},
|
||||
sourceMap: config.build.productionSourceMap,
|
||||
cache: true,
|
||||
parallel: true
|
||||
}),
|
||||
// Compress extracted CSS. We are using this plugin so that possible
|
||||
// duplicated CSS from different components can be deduped.
|
||||
new OptimizeCSSAssetsPlugin()
|
||||
]
|
||||
}
|
||||
})
|
||||
|
||||
if (config.build.productionGzip) {
|
||||
|
@ -157,9 +151,7 @@ if (config.build.productionGzip) {
|
|||
asset: '[path].gz[query]',
|
||||
algorithm: 'gzip',
|
||||
test: new RegExp(
|
||||
'\\.(' +
|
||||
config.build.productionGzipExtensions.join('|') +
|
||||
')$'
|
||||
'\\.(' + config.build.productionGzipExtensions.join('|') + ')$'
|
||||
),
|
||||
threshold: 10240,
|
||||
minRatio: 0.8
|
||||
|
@ -167,9 +159,28 @@ if (config.build.productionGzip) {
|
|||
)
|
||||
}
|
||||
|
||||
if (config.build.bundleAnalyzerReport) {
|
||||
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin
|
||||
webpackConfig.plugins.push(new BundleAnalyzerPlugin())
|
||||
if (config.build.generateAnalyzerReport || config.build.bundleAnalyzerReport) {
|
||||
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer')
|
||||
.BundleAnalyzerPlugin
|
||||
|
||||
if (config.build.bundleAnalyzerReport) {
|
||||
webpackConfig.plugins.push(
|
||||
new BundleAnalyzerPlugin({
|
||||
analyzerPort: 8080,
|
||||
generateStatsFile: false
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
if (config.build.generateAnalyzerReport) {
|
||||
webpackConfig.plugins.push(
|
||||
new BundleAnalyzerPlugin({
|
||||
analyzerMode: 'static',
|
||||
reportFilename: 'bundle-report.html',
|
||||
openAnalyzer: false
|
||||
})
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = webpackConfig
|
||||
|
|
|
@ -6,7 +6,6 @@ const path = require('path')
|
|||
|
||||
module.exports = {
|
||||
dev: {
|
||||
|
||||
// Paths
|
||||
assetsSubDirectory: 'static',
|
||||
assetsPublicPath: '/',
|
||||
|
@ -36,19 +35,14 @@ module.exports = {
|
|||
*/
|
||||
|
||||
// https://webpack.js.org/configuration/devtool/#development
|
||||
devtool: '#cheap-source-map',
|
||||
|
||||
// If you have problems debugging vue-files in devtools,
|
||||
// set this to false - it *may* help
|
||||
// https://vue-loader.vuejs.org/en/options.html#cachebusting
|
||||
cacheBusting: true,
|
||||
devtool: 'cheap-source-map',
|
||||
|
||||
// CSS Sourcemaps off by default because relative paths are "buggy"
|
||||
// with this option, according to the CSS-Loader README
|
||||
// (https://github.com/webpack/css-loader#sourcemaps)
|
||||
// In our experience, they generally work as expected,
|
||||
// just be aware of this issue when enabling this option.
|
||||
cssSourceMap: false,
|
||||
cssSourceMap: false
|
||||
},
|
||||
|
||||
build: {
|
||||
|
@ -73,7 +67,7 @@ module.exports = {
|
|||
*/
|
||||
productionSourceMap: false,
|
||||
// https://webpack.js.org/configuration/devtool/#production
|
||||
devtool: '#source-map',
|
||||
devtool: 'source-map',
|
||||
|
||||
// Gzip off by default as many popular static hosts such as
|
||||
// Surge or Netlify already gzip all static assets for you.
|
||||
|
@ -84,8 +78,11 @@ module.exports = {
|
|||
|
||||
// Run the build command with an extra argument to
|
||||
// View the bundle analyzer report after build finishes:
|
||||
// `npm run build --report`
|
||||
// `npm run build:prod --report`
|
||||
// Set to `true` or `false` to always turn it on or off
|
||||
bundleAnalyzerReport: process.env.npm_config_report
|
||||
bundleAnalyzerReport: process.env.npm_config_report || false,
|
||||
|
||||
// `npm run build:prod --generate_report`
|
||||
generateAnalyzerReport: process.env.npm_config_generate_report || false
|
||||
}
|
||||
}
|
||||
|
|
103
package.json
103
package.json
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "vue-element-admin",
|
||||
"version": "3.7.2",
|
||||
"version": "3.8.0",
|
||||
"description": "A magical vue admin. Typical templates for enterprise applications. Newest development stack of vue. Lots of awesome features",
|
||||
"author": "Pan <panfree23@gmail.com>",
|
||||
"license": "MIT",
|
||||
|
@ -34,15 +34,15 @@
|
|||
"url": "https://github.com/PanJiaChen/vue-element-admin/issues"
|
||||
},
|
||||
"dependencies": {
|
||||
"axios": "0.17.1",
|
||||
"axios": "0.18.0",
|
||||
"clipboard": "1.7.1",
|
||||
"codemirror": "5.32.0",
|
||||
"codemirror": "5.39.2",
|
||||
"connect": "3.6.6",
|
||||
"driver.js": "0.5.2",
|
||||
"dropzone": "5.2.0",
|
||||
"echarts": "3.8.5",
|
||||
"element-ui": "2.3.2",
|
||||
"file-saver": "1.3.3",
|
||||
"echarts": "4.1.0",
|
||||
"element-ui": "2.4.6",
|
||||
"file-saver": "1.3.8",
|
||||
"font-awesome": "4.7.0",
|
||||
"js-cookie": "2.2.0",
|
||||
"jsonlint": "1.6.3",
|
||||
|
@ -51,14 +51,13 @@
|
|||
"normalize.css": "7.0.0",
|
||||
"nprogress": "0.2.0",
|
||||
"screenfull": "3.3.2",
|
||||
"serve-static": "1.13.2",
|
||||
"showdown": "1.8.5",
|
||||
"showdown": "1.8.6",
|
||||
"simplemde": "1.11.2",
|
||||
"sortablejs": "1.7.0",
|
||||
"vue": "2.5.10",
|
||||
"vue": "2.5.17",
|
||||
"vue-count-to": "1.0.13",
|
||||
"vue-i18n": "7.3.2",
|
||||
"vue-multiselect": "2.0.8",
|
||||
"vue-multiselect": "2.1.0",
|
||||
"vue-router": "3.0.1",
|
||||
"vue-splitpane": "1.0.2",
|
||||
"vuedraggable": "^2.16.0",
|
||||
|
@ -66,57 +65,61 @@
|
|||
"xlsx": "^0.11.16"
|
||||
},
|
||||
"devDependencies": {
|
||||
"autoprefixer": "7.2.3",
|
||||
"babel-core": "6.26.0",
|
||||
"babel-eslint": "8.0.3",
|
||||
"autoprefixer": "8.5.0",
|
||||
"babel-core": "6.26.3",
|
||||
"babel-eslint": "8.2.6",
|
||||
"babel-helper-vue-jsx-merge-props": "2.0.3",
|
||||
"babel-loader": "7.1.2",
|
||||
"babel-plugin-dynamic-import-node": "^1.2.0",
|
||||
"babel-loader": "7.1.5",
|
||||
"babel-plugin-dynamic-import-node": "2.0.0",
|
||||
"babel-plugin-syntax-jsx": "6.18.0",
|
||||
"babel-plugin-transform-runtime": "6.23.0",
|
||||
"babel-plugin-transform-vue-jsx": "3.5.0",
|
||||
"babel-preset-env": "1.6.1",
|
||||
"babel-plugin-transform-vue-jsx": "3.7.0",
|
||||
"babel-preset-env": "1.7.0",
|
||||
"babel-preset-stage-2": "6.24.1",
|
||||
"chalk": "2.3.0",
|
||||
"copy-webpack-plugin": "4.3.0",
|
||||
"cross-env": "5.1.1",
|
||||
"css-loader": "0.28.7",
|
||||
"eslint": "4.13.1",
|
||||
"eslint-friendly-formatter": "3.0.0",
|
||||
"eslint-loader": "1.9.0",
|
||||
"eslint-plugin-html": "4.0.1",
|
||||
"extract-text-webpack-plugin": "3.0.2",
|
||||
"file-loader": "1.1.5",
|
||||
"friendly-errors-webpack-plugin": "1.6.1",
|
||||
"html-webpack-plugin": "2.30.1",
|
||||
"chalk": "2.4.1",
|
||||
"copy-webpack-plugin": "4.5.2",
|
||||
"cross-env": "5.2.0",
|
||||
"css-loader": "1.0.0",
|
||||
"eslint": "4.19.1",
|
||||
"eslint-friendly-formatter": "4.0.1",
|
||||
"eslint-loader": "2.0.0",
|
||||
"eslint-plugin-html": "4.0.5",
|
||||
"file-loader": "1.1.11",
|
||||
"friendly-errors-webpack-plugin": "1.7.0",
|
||||
"hash-sum": "^1.0.2",
|
||||
"html-webpack-plugin": "^4.0.0-alpha",
|
||||
"husky": "0.14.3",
|
||||
"lint-staged": "7.2.0",
|
||||
"node-notifier": "5.1.2",
|
||||
"lint-staged": "7.2.2",
|
||||
"mini-css-extract-plugin": "0.4.1",
|
||||
"node-notifier": "5.2.1",
|
||||
"node-sass": "^4.7.2",
|
||||
"optimize-css-assets-webpack-plugin": "3.2.0",
|
||||
"ora": "1.3.0",
|
||||
"optimize-css-assets-webpack-plugin": "5.0.0",
|
||||
"ora": "3.0.0",
|
||||
"portfinder": "1.0.13",
|
||||
"postcss-import": "11.0.0",
|
||||
"postcss-loader": "2.0.9",
|
||||
"postcss-url": "7.3.0",
|
||||
"postcss-import": "11.1.0",
|
||||
"postcss-loader": "2.1.6",
|
||||
"postcss-url": "7.3.2",
|
||||
"rimraf": "2.6.2",
|
||||
"sass-loader": "6.0.6",
|
||||
"sass-loader": "7.0.3",
|
||||
"script-ext-html-webpack-plugin": "2.0.1",
|
||||
"script-loader": "0.7.2",
|
||||
"semver": "5.4.1",
|
||||
"shelljs": "0.7.8",
|
||||
"svg-sprite-loader": "3.5.2",
|
||||
"uglifyjs-webpack-plugin": "1.1.3",
|
||||
"url-loader": "0.6.2",
|
||||
"vue-loader": "13.7.2",
|
||||
"vue-style-loader": "3.0.3",
|
||||
"vue-template-compiler": "2.5.10",
|
||||
"webpack": "3.10.0",
|
||||
"webpack-bundle-analyzer": "2.9.1",
|
||||
"webpack-dev-server": "2.9.7",
|
||||
"webpack-merge": "4.1.1"
|
||||
"semver": "5.5.0",
|
||||
"serve-static": "1.13.2",
|
||||
"shelljs": "0.8.2",
|
||||
"svg-sprite-loader": "3.8.0",
|
||||
"uglifyjs-webpack-plugin": "1.2.7",
|
||||
"url-loader": "1.0.1",
|
||||
"vue-loader": "15.3.0",
|
||||
"vue-style-loader": "4.1.2",
|
||||
"vue-template-compiler": "2.5.17",
|
||||
"webpack": "4.16.5",
|
||||
"webpack-bundle-analyzer": "2.13.1",
|
||||
"webpack-cli": "3.1.0",
|
||||
"webpack-dev-server": "3.1.5",
|
||||
"webpack-merge": "4.1.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 4.0.0",
|
||||
"node": ">= 6.0.0",
|
||||
"npm": ">= 3.0.0"
|
||||
},
|
||||
"browserslist": [
|
||||
|
|
|
@ -35,7 +35,7 @@ export default {
|
|||
</script>
|
||||
|
||||
<style rel="stylesheet/scss" lang="scss" >
|
||||
$n: 6; //和items.length 相同
|
||||
$n: 8; //和items.length 相同
|
||||
$t: .1s;
|
||||
.share-dropdown-menu {
|
||||
width: 250px;
|
||||
|
|
|
@ -23,6 +23,7 @@ export default {
|
|||
|
||||
<style>
|
||||
/* Mallki */
|
||||
|
||||
.link--mallki {
|
||||
font-weight: 800;
|
||||
color: #4dd9d5;
|
||||
|
@ -31,10 +32,10 @@ export default {
|
|||
transition: color 0.5s 0.25s;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
line-height: 1;
|
||||
outline: none;
|
||||
text-decoration: none;
|
||||
display: inline-block;
|
||||
line-height: 1;
|
||||
outline: none;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.link--mallki:hover {
|
||||
|
@ -109,5 +110,4 @@ display: inline-block;
|
|||
-webkit-transition-timing-function: cubic-bezier(0.2, 1, 0.3, 1);
|
||||
transition-timing-function: cubic-bezier(0.2, 1, 0.3, 1);
|
||||
}
|
||||
|
||||
</style>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<div class="upload-container">
|
||||
<el-button icon='el-icon-upload' size="mini" :style="{background:color,borderColor:color}" @click=" dialogVisible=true" type="primary">上传图片
|
||||
</el-button>
|
||||
<el-dialog append-to-body :visible.sync="dialogVisible">
|
||||
<el-dialog :visible.sync="dialogVisible">
|
||||
<el-upload class="editor-slide-upload" action="https://httpbin.org/post" :multiple="true" :file-list="fileList" :show-file-list="true"
|
||||
list-type="picture-card" :on-remove="handleRemove" :on-success="handleSuccess" :before-upload="beforeUpload">
|
||||
<el-button size="small" type="primary">点击上传</el-button>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// Here is a list of the toolbar
|
||||
// Detail list see https://www.tinymce.com/docs/advanced/editor-control-identifiers/#toolbarcontrols
|
||||
|
||||
const toolbar = ['bold italic underline strikethrough alignleft aligncenter alignright outdent indent blockquote undo redo removeformat subscript superscript code codesample', 'hr bullist numlist link image charmap preview anchor pagebreak insertdatetime media table emoticons forecolor backcolor fullscreen']
|
||||
const toolbar = ['bold italic underline strikethrough alignleft aligncenter alignright outdent indent blockquote undo redo removeformat subscript superscript code codesample', 'hr bullist numlist link image charmap preview anchor pagebreak insertdatetime media table emoticons forecolor backcolor fullscreen']
|
||||
|
||||
export default toolbar
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<template>
|
||||
<div class="upload-container">
|
||||
<el-upload class="image-uploader" :data="dataObj" drag :multiple="false" :show-file-list="false" action="https://httpbin.org/post"
|
||||
:on-success="handleImageScucess">
|
||||
:on-success="handleImageSuccess">
|
||||
<i class="el-icon-upload"></i>
|
||||
<div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
|
||||
</el-upload>
|
||||
|
@ -43,7 +43,7 @@ export default {
|
|||
emitInput(val) {
|
||||
this.$emit('input', val)
|
||||
},
|
||||
handleImageScucess() {
|
||||
handleImageSuccess() {
|
||||
this.emitInput(this.tempUrl)
|
||||
},
|
||||
beforeUpload() {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<template>
|
||||
<div class="singleImageUpload2 upload-container">
|
||||
<el-upload class="image-uploader" :data="dataObj" drag :multiple="false" :show-file-list="false" action="https://httpbin.org/post"
|
||||
:on-success="handleImageScucess">
|
||||
:on-success="handleImageSuccess">
|
||||
<i class="el-icon-upload"></i>
|
||||
<div class="el-upload__text">Drag或<em>点击上传</em></div>
|
||||
</el-upload>
|
||||
|
@ -42,7 +42,7 @@ export default {
|
|||
emitInput(val) {
|
||||
this.$emit('input', val)
|
||||
},
|
||||
handleImageScucess() {
|
||||
handleImageSuccess() {
|
||||
this.emitInput(this.tempUrl)
|
||||
},
|
||||
beforeUpload() {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<template>
|
||||
<div class="upload-container">
|
||||
<el-upload class="image-uploader" :data="dataObj" drag :multiple="false" :show-file-list="false" action="https://httpbin.org/post"
|
||||
:on-success="handleImageScucess">
|
||||
:on-success="handleImageSuccess">
|
||||
<i class="el-icon-upload"></i>
|
||||
<div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
|
||||
</el-upload>
|
||||
|
@ -50,7 +50,7 @@ export default {
|
|||
emitInput(val) {
|
||||
this.$emit('input', val)
|
||||
},
|
||||
handleImageScucess(file) {
|
||||
handleImageSuccess(file) {
|
||||
this.emitInput(file.files.file)
|
||||
},
|
||||
beforeUpload() {
|
||||
|
|
|
@ -41,6 +41,11 @@ export default {
|
|||
return
|
||||
}
|
||||
const rawFile = files[0] // only use files[0]
|
||||
|
||||
if (!this.isExcel(rawFile)) {
|
||||
this.$message.error('Only supports upload .xlsx, .xls, .csv suffix files')
|
||||
return false
|
||||
}
|
||||
this.upload(rawFile)
|
||||
e.stopPropagation()
|
||||
e.preventDefault()
|
||||
|
@ -110,6 +115,9 @@ export default {
|
|||
headers.push(hdr)
|
||||
}
|
||||
return headers
|
||||
},
|
||||
isExcel(file) {
|
||||
return /\.(xlsx|xls|csv)$/.test(file.name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,8 +29,8 @@ export default{
|
|||
ripple.style.left = (rect.width / 2 - ripple.offsetWidth / 2) + 'px'
|
||||
break
|
||||
default:
|
||||
ripple.style.top = (e.pageY - rect.top - ripple.offsetHeight / 2 - document.body.scrollTop) + 'px'
|
||||
ripple.style.left = (e.pageX - rect.left - ripple.offsetWidth / 2 - document.body.scrollLeft) + 'px'
|
||||
ripple.style.top = (e.pageY - rect.top - ripple.offsetHeight / 2 - document.documentElement.scrollTop || document.body.scrollTop) + 'px'
|
||||
ripple.style.left = (e.pageX - rect.left - ripple.offsetWidth / 2 - document.documentElement.scrollLeft || document.body.scrollLeft) + 'px'
|
||||
}
|
||||
ripple.style.backgroundColor = opts.color
|
||||
ripple.className = 'waves-ripple z-active'
|
||||
|
|
|
@ -20,8 +20,11 @@ const messages = {
|
|||
}
|
||||
|
||||
const i18n = new VueI18n({
|
||||
locale: Cookies.get('language') || 'en', // set locale
|
||||
messages // set locale messages
|
||||
// set locale
|
||||
// options: en or zh
|
||||
locale: Cookies.get('language') || 'en',
|
||||
// set locale messages
|
||||
messages
|
||||
})
|
||||
|
||||
export default i18n
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import Vue from 'vue'
|
||||
|
||||
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-ui/lib/theme-chalk/index.css'
|
||||
|
@ -13,7 +13,7 @@ import store from './store'
|
|||
|
||||
import i18n from './lang' // Internationalization
|
||||
import './icons' // icon
|
||||
import './errorLog'// error log
|
||||
import './errorLog' // error log
|
||||
import './permission' // permission control
|
||||
import './mock' // simulation data
|
||||
|
||||
|
|
|
@ -40,7 +40,7 @@ router.beforeEach((to, from, next) => {
|
|||
} else {
|
||||
// 没有动态改变权限的需求可直接next() 删除下方权限判断 ↓
|
||||
if (hasPermission(store.getters.roles, to.meta.roles)) {
|
||||
next()//
|
||||
next()
|
||||
} else {
|
||||
next({ path: '/401', replace: true, query: { noGoBack: true }})
|
||||
}
|
||||
|
|
|
@ -6,9 +6,15 @@ Vue.use(Router)
|
|||
/* Layout */
|
||||
import Layout from '@/views/layout/Layout'
|
||||
|
||||
/* Router Modules */
|
||||
import componentsRouter from './modules/components'
|
||||
import chartsRouter from './modules/charts'
|
||||
import tableRouter from './modules/table'
|
||||
import nestedRouter from './modules/nested'
|
||||
|
||||
/** note: submenu only apppear when children.length>=1
|
||||
* detail see https://panjiachen.github.io/vue-element-admin-site/guide/essentials/router-and-nav.html
|
||||
**/
|
||||
* 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)
|
||||
|
@ -25,42 +31,64 @@ import Layout from '@/views/layout/Layout'
|
|||
}
|
||||
**/
|
||||
export const constantRouterMap = [
|
||||
{ path: '/login', component: () => import('@/views/login/index'), hidden: true },
|
||||
{ path: '/authredirect', component: () => import('@/views/login/authredirect'), hidden: true },
|
||||
{ path: '/404', component: () => import('@/views/errorPage/404'), hidden: true },
|
||||
{ path: '/401', component: () => import('@/views/errorPage/401'), hidden: true },
|
||||
{
|
||||
path: '/login',
|
||||
component: () => import('@/views/login/index'),
|
||||
hidden: true
|
||||
},
|
||||
{
|
||||
path: '/authredirect',
|
||||
component: () => import('@/views/login/authredirect'),
|
||||
hidden: true
|
||||
},
|
||||
{
|
||||
path: '/404',
|
||||
component: () => import('@/views/errorPage/404'),
|
||||
hidden: true
|
||||
},
|
||||
{
|
||||
path: '/401',
|
||||
component: () => import('@/views/errorPage/401'),
|
||||
hidden: true
|
||||
},
|
||||
{
|
||||
path: '',
|
||||
component: Layout,
|
||||
redirect: 'dashboard',
|
||||
children: [{
|
||||
path: 'dashboard',
|
||||
component: () => import('@/views/dashboard/index'),
|
||||
name: 'dashboard',
|
||||
meta: { title: 'dashboard', icon: 'dashboard', noCache: true }
|
||||
}]
|
||||
children: [
|
||||
{
|
||||
path: 'dashboard',
|
||||
component: () => import('@/views/dashboard/index'),
|
||||
name: 'dashboard',
|
||||
meta: { title: 'dashboard', icon: 'dashboard', noCache: true }
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
path: '/documentation',
|
||||
component: Layout,
|
||||
redirect: '/documentation/index',
|
||||
children: [{
|
||||
path: 'index',
|
||||
component: () => import('@/views/documentation/index'),
|
||||
name: 'documentation',
|
||||
meta: { title: 'documentation', icon: 'documentation', noCache: true }
|
||||
}]
|
||||
children: [
|
||||
{
|
||||
path: 'index',
|
||||
component: () => import('@/views/documentation/index'),
|
||||
name: 'documentation',
|
||||
meta: { title: 'documentation', icon: 'documentation', noCache: true }
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
path: '/guide',
|
||||
component: Layout,
|
||||
redirect: '/guide/index',
|
||||
children: [{
|
||||
path: 'index',
|
||||
component: () => import('@/views/guide/index'),
|
||||
name: 'guide',
|
||||
meta: { title: 'guide', icon: 'guide', noCache: true }
|
||||
}]
|
||||
children: [
|
||||
{
|
||||
path: 'index',
|
||||
component: () => import('@/views/guide/index'),
|
||||
name: 'guide',
|
||||
meta: { title: 'guide', icon: 'guide', noCache: true }
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
|
@ -81,107 +109,46 @@ export const asyncRouterMap = [
|
|||
icon: 'lock',
|
||||
roles: ['admin', 'editor'] // you can set roles in root nav
|
||||
},
|
||||
children: [{
|
||||
path: 'page',
|
||||
component: () => import('@/views/permission/page'),
|
||||
name: 'pagePermission',
|
||||
meta: {
|
||||
title: 'pagePermission',
|
||||
roles: ['admin'] // or you can only set roles in sub nav
|
||||
children: [
|
||||
{
|
||||
path: 'page',
|
||||
component: () => import('@/views/permission/page'),
|
||||
name: 'pagePermission',
|
||||
meta: {
|
||||
title: 'pagePermission',
|
||||
roles: ['admin'] // or you can only set roles in sub nav
|
||||
}
|
||||
},
|
||||
{
|
||||
path: 'directive',
|
||||
component: () => import('@/views/permission/directive'),
|
||||
name: 'directivePermission',
|
||||
meta: {
|
||||
title: 'directivePermission'
|
||||
// if do not set roles, means: this page does not require permission
|
||||
}
|
||||
}
|
||||
}, {
|
||||
path: 'directive',
|
||||
component: () => import('@/views/permission/directive'),
|
||||
name: 'directivePermission',
|
||||
meta: {
|
||||
title: 'directivePermission'
|
||||
// if do not set roles, means: this page does not require permission
|
||||
}
|
||||
}]
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
path: '/icon',
|
||||
component: Layout,
|
||||
children: [{
|
||||
path: 'index',
|
||||
component: () => import('@/views/svg-icons/index'),
|
||||
name: 'icons',
|
||||
meta: { title: 'icons', icon: 'icon', noCache: true }
|
||||
}]
|
||||
},
|
||||
|
||||
{
|
||||
path: '/components',
|
||||
component: Layout,
|
||||
redirect: 'noredirect',
|
||||
name: 'component-demo',
|
||||
meta: {
|
||||
title: 'components',
|
||||
icon: 'component'
|
||||
},
|
||||
children: [
|
||||
{ path: 'tinymce', component: () => import('@/views/components-demo/tinymce'), name: 'tinymce-demo', meta: { title: 'tinymce' }},
|
||||
{ path: 'markdown', component: () => import('@/views/components-demo/markdown'), name: 'markdown-demo', meta: { title: 'markdown' }},
|
||||
{ path: 'json-editor', component: () => import('@/views/components-demo/jsonEditor'), name: 'jsonEditor-demo', meta: { title: 'jsonEditor' }},
|
||||
{ path: 'splitpane', component: () => import('@/views/components-demo/splitpane'), name: 'splitpane-demo', meta: { title: 'splitPane' }},
|
||||
{ path: 'avatar-upload', component: () => import('@/views/components-demo/avatarUpload'), name: 'avatarUpload-demo', meta: { title: 'avatarUpload' }},
|
||||
{ path: 'dropzone', component: () => import('@/views/components-demo/dropzone'), name: 'dropzone-demo', meta: { title: 'dropzone' }},
|
||||
{ path: 'sticky', component: () => import('@/views/components-demo/sticky'), name: 'sticky-demo', meta: { title: 'sticky' }},
|
||||
{ path: 'count-to', component: () => import('@/views/components-demo/countTo'), name: 'countTo-demo', meta: { title: 'countTo' }},
|
||||
{ path: 'mixin', component: () => import('@/views/components-demo/mixin'), name: 'componentMixin-demo', meta: { title: 'componentMixin' }},
|
||||
{ path: 'back-to-top', component: () => import('@/views/components-demo/backToTop'), name: 'backToTop-demo', meta: { title: 'backToTop' }},
|
||||
{ path: 'drag-dialog', component: () => import('@/views/components-demo/dragDialog'), name: 'dragDialog-demo', meta: { title: 'dragDialog' }},
|
||||
{ path: 'dnd-list', component: () => import('@/views/components-demo/dndList'), name: 'dndList-demo', meta: { title: 'dndList' }},
|
||||
{ path: 'drag-kanban', component: () => import('@/views/components-demo/dragKanban'), name: 'dragKanban-demo', meta: { title: 'dragKanban' }}
|
||||
{
|
||||
path: 'index',
|
||||
component: () => import('@/views/svg-icons/index'),
|
||||
name: 'icons',
|
||||
meta: { title: 'icons', icon: 'icon', noCache: true }
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
path: '/charts',
|
||||
component: Layout,
|
||||
redirect: 'noredirect',
|
||||
name: 'charts',
|
||||
meta: {
|
||||
title: 'charts',
|
||||
icon: 'chart'
|
||||
},
|
||||
children: [
|
||||
{ path: 'keyboard', component: () => import('@/views/charts/keyboard'), name: 'keyboardChart', meta: { title: 'keyboardChart', noCache: true }},
|
||||
{ path: 'line', component: () => import('@/views/charts/line'), name: 'lineChart', meta: { title: 'lineChart', noCache: true }},
|
||||
{ path: 'mixchart', component: () => import('@/views/charts/mixChart'), name: 'mixChart', meta: { title: 'mixChart', noCache: true }}
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
path: '/tab',
|
||||
component: Layout,
|
||||
children: [{
|
||||
path: 'index',
|
||||
component: () => import('@/views/tab/index'),
|
||||
name: 'tab',
|
||||
meta: { title: 'tab', icon: 'tab' }
|
||||
}]
|
||||
},
|
||||
|
||||
{
|
||||
path: '/table',
|
||||
component: Layout,
|
||||
redirect: '/table/complex-table',
|
||||
name: 'table',
|
||||
meta: {
|
||||
title: 'Table',
|
||||
icon: 'table'
|
||||
},
|
||||
children: [
|
||||
{ path: 'dynamic-table', component: () => import('@/views/table/dynamicTable/index'), name: 'dynamicTable', meta: { title: 'dynamicTable' }},
|
||||
{ path: 'drag-table', component: () => import('@/views/table/dragTable'), name: 'dragTable', meta: { title: 'dragTable' }},
|
||||
{ path: 'inline-edit-table', component: () => import('@/views/table/inlineEditTable'), name: 'inlineEditTable', meta: { title: 'inlineEditTable' }},
|
||||
{ path: 'tree-table', component: () => import('@/views/table/treeTable/treeTable'), name: 'treeTableDemo', meta: { title: 'treeTable' }},
|
||||
{ path: 'custom-tree-table', component: () => import('@/views/table/treeTable/customTreeTable'), name: 'customTreeTableDemo', meta: { title: 'customTreeTable' }},
|
||||
{ path: 'complex-table', component: () => import('@/views/table/complexTable'), name: 'complexTable', meta: { title: 'complexTable' }}
|
||||
]
|
||||
},
|
||||
/** When your routing table is too long, you can split it into small modules**/
|
||||
componentsRouter,
|
||||
chartsRouter,
|
||||
nestedRouter,
|
||||
tableRouter,
|
||||
|
||||
{
|
||||
path: '/example',
|
||||
|
@ -193,69 +160,37 @@ export const asyncRouterMap = [
|
|||
icon: 'example'
|
||||
},
|
||||
children: [
|
||||
{ path: 'create', component: () => import('@/views/example/create'), name: 'createArticle', meta: { title: 'createArticle', icon: 'edit' }},
|
||||
{ path: 'edit/:id(\\d+)', component: () => import('@/views/example/edit'), name: 'editArticle', meta: { title: 'editArticle', noCache: true }, hidden: true },
|
||||
{ path: 'list', component: () => import('@/views/example/list'), name: 'articleList', meta: { title: 'articleList', icon: 'list' }}
|
||||
{
|
||||
path: 'create',
|
||||
component: () => import('@/views/example/create'),
|
||||
name: 'createArticle',
|
||||
meta: { title: 'createArticle', icon: 'edit' }
|
||||
},
|
||||
{
|
||||
path: 'edit/:id(\\d+)',
|
||||
component: () => import('@/views/example/edit'),
|
||||
name: 'editArticle',
|
||||
meta: { title: 'editArticle', noCache: true },
|
||||
hidden: true
|
||||
},
|
||||
{
|
||||
path: 'list',
|
||||
component: () => import('@/views/example/list'),
|
||||
name: 'articleList',
|
||||
meta: { title: 'articleList', icon: 'list' }
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
path: '/nested',
|
||||
path: '/tab',
|
||||
component: Layout,
|
||||
redirect: '/nested/menu1/menu1-1',
|
||||
name: 'nested',
|
||||
meta: {
|
||||
title: 'nested',
|
||||
icon: 'nested'
|
||||
},
|
||||
children: [
|
||||
{
|
||||
path: 'menu1',
|
||||
component: () => import('@/views/nested/menu1/index'), // Parent router-view
|
||||
name: 'menu1',
|
||||
meta: { title: 'menu1' },
|
||||
redirect: '/nested/menu1/menu1-1',
|
||||
children: [
|
||||
{
|
||||
path: 'menu1-1',
|
||||
component: () => import('@/views/nested/menu1/menu1-1'),
|
||||
name: 'menu1-1',
|
||||
meta: { title: 'menu1-1' }
|
||||
},
|
||||
{
|
||||
path: 'menu1-2',
|
||||
component: () => import('@/views/nested/menu1/menu1-2'),
|
||||
name: 'menu1-2',
|
||||
redirect: '/nested/menu1/menu1-2/menu1-2-1',
|
||||
meta: { title: 'menu1-2' },
|
||||
children: [
|
||||
{
|
||||
path: 'menu1-2-1',
|
||||
component: () => import('@/views/nested/menu1/menu1-2/menu1-2-1'),
|
||||
name: 'menu1-2-1',
|
||||
meta: { title: 'menu1-2-1' }
|
||||
},
|
||||
{
|
||||
path: 'menu1-2-2',
|
||||
component: () => import('@/views/nested/menu1/menu1-2/menu1-2-2'),
|
||||
name: 'menu1-2-2',
|
||||
meta: { title: 'menu1-2-2' }
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
path: 'menu1-3',
|
||||
component: () => import('@/views/nested/menu1/menu1-3'),
|
||||
name: 'menu1-3',
|
||||
meta: { title: 'menu1-3' }
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
path: 'menu2',
|
||||
name: 'menu2',
|
||||
component: () => import('@/views/nested/menu2/index'),
|
||||
meta: { title: 'menu2' }
|
||||
path: 'index',
|
||||
component: () => import('@/views/tab/index'),
|
||||
name: 'tab',
|
||||
meta: { title: 'tab', icon: 'tab' }
|
||||
}
|
||||
]
|
||||
},
|
||||
|
@ -270,8 +205,18 @@ export const asyncRouterMap = [
|
|||
icon: '404'
|
||||
},
|
||||
children: [
|
||||
{ path: '401', component: () => import('@/views/errorPage/401'), name: 'page401', meta: { title: 'page401', noCache: true }},
|
||||
{ path: '404', component: () => import('@/views/errorPage/404'), name: 'page404', meta: { title: 'page404', noCache: true }}
|
||||
{
|
||||
path: '401',
|
||||
component: () => import('@/views/errorPage/401'),
|
||||
name: 'page401',
|
||||
meta: { title: 'page401', noCache: true }
|
||||
},
|
||||
{
|
||||
path: '404',
|
||||
component: () => import('@/views/errorPage/404'),
|
||||
name: 'page404',
|
||||
meta: { title: 'page404', noCache: true }
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
|
@ -279,7 +224,14 @@ export const asyncRouterMap = [
|
|||
path: '/error-log',
|
||||
component: Layout,
|
||||
redirect: 'noredirect',
|
||||
children: [{ path: 'log', component: () => import('@/views/errorLog/index'), name: 'errorLog', meta: { title: 'errorLog', icon: 'bug' }}]
|
||||
children: [
|
||||
{
|
||||
path: 'log',
|
||||
component: () => import('@/views/errorLog/index'),
|
||||
name: 'errorLog',
|
||||
meta: { title: 'errorLog', icon: 'bug' }
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
|
@ -292,9 +244,24 @@ export const asyncRouterMap = [
|
|||
icon: 'excel'
|
||||
},
|
||||
children: [
|
||||
{ path: 'export-excel', component: () => import('@/views/excel/exportExcel'), name: 'exportExcel', meta: { title: 'exportExcel' }},
|
||||
{ path: 'export-selected-excel', component: () => import('@/views/excel/selectExcel'), name: 'selectExcel', meta: { title: 'selectExcel' }},
|
||||
{ path: 'upload-excel', component: () => import('@/views/excel/uploadExcel'), name: 'uploadExcel', meta: { title: 'uploadExcel' }}
|
||||
{
|
||||
path: 'export-excel',
|
||||
component: () => import('@/views/excel/exportExcel'),
|
||||
name: 'exportExcel',
|
||||
meta: { title: 'exportExcel' }
|
||||
},
|
||||
{
|
||||
path: 'export-selected-excel',
|
||||
component: () => import('@/views/excel/selectExcel'),
|
||||
name: 'selectExcel',
|
||||
meta: { title: 'selectExcel' }
|
||||
},
|
||||
{
|
||||
path: 'upload-excel',
|
||||
component: () => import('@/views/excel/uploadExcel'),
|
||||
name: 'uploadExcel',
|
||||
meta: { title: 'uploadExcel' }
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
|
@ -304,27 +271,55 @@ export const asyncRouterMap = [
|
|||
redirect: '/zip/download',
|
||||
alwaysShow: true,
|
||||
meta: { title: 'zip', icon: 'zip' },
|
||||
children: [{ path: 'download', component: () => import('@/views/zip/index'), name: 'exportZip', meta: { title: 'exportZip' }}]
|
||||
children: [
|
||||
{
|
||||
path: 'download',
|
||||
component: () => import('@/views/zip/index'),
|
||||
name: 'exportZip',
|
||||
meta: { title: 'exportZip' }
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
path: '/theme',
|
||||
component: Layout,
|
||||
redirect: 'noredirect',
|
||||
children: [{ path: 'index', component: () => import('@/views/theme/index'), name: 'theme', meta: { title: 'theme', icon: 'theme' }}]
|
||||
children: [
|
||||
{
|
||||
path: 'index',
|
||||
component: () => import('@/views/theme/index'),
|
||||
name: 'theme',
|
||||
meta: { title: 'theme', icon: 'theme' }
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
path: '/clipboard',
|
||||
component: Layout,
|
||||
redirect: 'noredirect',
|
||||
children: [{ path: 'index', component: () => import('@/views/clipboard/index'), name: 'clipboardDemo', meta: { title: 'clipboardDemo', icon: 'clipboard' }}]
|
||||
children: [
|
||||
{
|
||||
path: 'index',
|
||||
component: () => import('@/views/clipboard/index'),
|
||||
name: 'clipboardDemo',
|
||||
meta: { title: 'clipboardDemo', icon: 'clipboard' }
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
path: '/i18n',
|
||||
component: Layout,
|
||||
children: [{ path: 'index', component: () => import('@/views/i18n-demo/index'), name: 'i18n', meta: { title: 'i18n', icon: 'international' }}]
|
||||
children: [
|
||||
{
|
||||
path: 'index',
|
||||
component: () => import('@/views/i18n-demo/index'),
|
||||
name: 'i18n',
|
||||
meta: { title: 'i18n', icon: 'international' }
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
{ path: '*', redirect: '/404', hidden: true }
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
/** When your routing table is too long, you can split it into small modules**/
|
||||
|
||||
import Layout from '@/views/layout/Layout'
|
||||
|
||||
const chartsRouter = {
|
||||
path: '/charts',
|
||||
component: Layout,
|
||||
redirect: 'noredirect',
|
||||
name: 'charts',
|
||||
meta: {
|
||||
title: 'charts',
|
||||
icon: 'chart'
|
||||
},
|
||||
children: [
|
||||
{
|
||||
path: 'keyboard',
|
||||
component: () => import('@/views/charts/keyboard'),
|
||||
name: 'keyboardChart',
|
||||
meta: { title: 'keyboardChart', noCache: true }
|
||||
},
|
||||
{
|
||||
path: 'line',
|
||||
component: () => import('@/views/charts/line'),
|
||||
name: 'lineChart',
|
||||
meta: { title: 'lineChart', noCache: true }
|
||||
},
|
||||
{
|
||||
path: 'mixchart',
|
||||
component: () => import('@/views/charts/mixChart'),
|
||||
name: 'mixChart',
|
||||
meta: { title: 'mixChart', noCache: true }
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
export default chartsRouter
|
|
@ -0,0 +1,96 @@
|
|||
/** When your routing table is too long, you can split it into small modules**/
|
||||
|
||||
import Layout from '@/views/layout/Layout'
|
||||
|
||||
const componentsRouter = {
|
||||
path: '/components',
|
||||
component: Layout,
|
||||
redirect: 'noredirect',
|
||||
name: 'component-demo',
|
||||
meta: {
|
||||
title: 'components',
|
||||
icon: 'component'
|
||||
},
|
||||
children: [
|
||||
{
|
||||
path: 'tinymce',
|
||||
component: () => import('@/views/components-demo/tinymce'),
|
||||
name: 'tinymce-demo',
|
||||
meta: { title: 'tinymce' }
|
||||
},
|
||||
{
|
||||
path: 'markdown',
|
||||
component: () => import('@/views/components-demo/markdown'),
|
||||
name: 'markdown-demo',
|
||||
meta: { title: 'markdown' }
|
||||
},
|
||||
{
|
||||
path: 'json-editor',
|
||||
component: () => import('@/views/components-demo/jsonEditor'),
|
||||
name: 'jsonEditor-demo',
|
||||
meta: { title: 'jsonEditor' }
|
||||
},
|
||||
{
|
||||
path: 'splitpane',
|
||||
component: () => import('@/views/components-demo/splitpane'),
|
||||
name: 'splitpane-demo',
|
||||
meta: { title: 'splitPane' }
|
||||
},
|
||||
{
|
||||
path: 'avatar-upload',
|
||||
component: () => import('@/views/components-demo/avatarUpload'),
|
||||
name: 'avatarUpload-demo',
|
||||
meta: { title: 'avatarUpload' }
|
||||
},
|
||||
{
|
||||
path: 'dropzone',
|
||||
component: () => import('@/views/components-demo/dropzone'),
|
||||
name: 'dropzone-demo',
|
||||
meta: { title: 'dropzone' }
|
||||
},
|
||||
{
|
||||
path: 'sticky',
|
||||
component: () => import('@/views/components-demo/sticky'),
|
||||
name: 'sticky-demo',
|
||||
meta: { title: 'sticky' }
|
||||
},
|
||||
{
|
||||
path: 'count-to',
|
||||
component: () => import('@/views/components-demo/countTo'),
|
||||
name: 'countTo-demo',
|
||||
meta: { title: 'countTo' }
|
||||
},
|
||||
{
|
||||
path: 'mixin',
|
||||
component: () => import('@/views/components-demo/mixin'),
|
||||
name: 'componentMixin-demo',
|
||||
meta: { title: 'componentMixin' }
|
||||
},
|
||||
{
|
||||
path: 'back-to-top',
|
||||
component: () => import('@/views/components-demo/backToTop'),
|
||||
name: 'backToTop-demo',
|
||||
meta: { title: 'backToTop' }
|
||||
},
|
||||
{
|
||||
path: 'drag-dialog',
|
||||
component: () => import('@/views/components-demo/dragDialog'),
|
||||
name: 'dragDialog-demo',
|
||||
meta: { title: 'dragDialog' }
|
||||
},
|
||||
{
|
||||
path: 'dnd-list',
|
||||
component: () => import('@/views/components-demo/dndList'),
|
||||
name: 'dndList-demo',
|
||||
meta: { title: 'dndList' }
|
||||
},
|
||||
{
|
||||
path: 'drag-kanban',
|
||||
component: () => import('@/views/components-demo/dragKanban'),
|
||||
name: 'dragKanban-demo',
|
||||
meta: { title: 'dragKanban' }
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
export default componentsRouter
|
|
@ -0,0 +1,66 @@
|
|||
/** When your routing table is too long, you can split it into small modules**/
|
||||
|
||||
import Layout from '@/views/layout/Layout'
|
||||
|
||||
const nestedRouter = {
|
||||
path: '/nested',
|
||||
component: Layout,
|
||||
redirect: '/nested/menu1/menu1-1',
|
||||
name: 'nested',
|
||||
meta: {
|
||||
title: 'nested',
|
||||
icon: 'nested'
|
||||
},
|
||||
children: [
|
||||
{
|
||||
path: 'menu1',
|
||||
component: () => import('@/views/nested/menu1/index'), // Parent router-view
|
||||
name: 'menu1',
|
||||
meta: { title: 'menu1' },
|
||||
redirect: '/nested/menu1/menu1-1',
|
||||
children: [
|
||||
{
|
||||
path: 'menu1-1',
|
||||
component: () => import('@/views/nested/menu1/menu1-1'),
|
||||
name: 'menu1-1',
|
||||
meta: { title: 'menu1-1' }
|
||||
},
|
||||
{
|
||||
path: 'menu1-2',
|
||||
component: () => import('@/views/nested/menu1/menu1-2'),
|
||||
name: 'menu1-2',
|
||||
redirect: '/nested/menu1/menu1-2/menu1-2-1',
|
||||
meta: { title: 'menu1-2' },
|
||||
children: [
|
||||
{
|
||||
path: 'menu1-2-1',
|
||||
component: () => import('@/views/nested/menu1/menu1-2/menu1-2-1'),
|
||||
name: 'menu1-2-1',
|
||||
meta: { title: 'menu1-2-1' }
|
||||
},
|
||||
{
|
||||
path: 'menu1-2-2',
|
||||
component: () => import('@/views/nested/menu1/menu1-2/menu1-2-2'),
|
||||
name: 'menu1-2-2',
|
||||
meta: { title: 'menu1-2-2' }
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
path: 'menu1-3',
|
||||
component: () => import('@/views/nested/menu1/menu1-3'),
|
||||
name: 'menu1-3',
|
||||
meta: { title: 'menu1-3' }
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
path: 'menu2',
|
||||
name: 'menu2',
|
||||
component: () => import('@/views/nested/menu2/index'),
|
||||
meta: { title: 'menu2' }
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
export default nestedRouter
|
|
@ -0,0 +1,53 @@
|
|||
/** When your routing table is too long, you can split it into small modules**/
|
||||
|
||||
import Layout from '@/views/layout/Layout'
|
||||
|
||||
const tableRouter = {
|
||||
path: '/table',
|
||||
component: Layout,
|
||||
redirect: '/table/complex-table',
|
||||
name: 'table',
|
||||
meta: {
|
||||
title: 'Table',
|
||||
icon: 'table'
|
||||
},
|
||||
children: [
|
||||
{
|
||||
path: 'dynamic-table',
|
||||
component: () => import('@/views/table/dynamicTable/index'),
|
||||
name: 'dynamicTable',
|
||||
meta: { title: 'dynamicTable' }
|
||||
},
|
||||
{
|
||||
path: 'drag-table',
|
||||
component: () => import('@/views/table/dragTable'),
|
||||
name: 'dragTable',
|
||||
meta: { title: 'dragTable' }
|
||||
},
|
||||
{
|
||||
path: 'inline-edit-table',
|
||||
component: () => import('@/views/table/inlineEditTable'),
|
||||
name: 'inlineEditTable',
|
||||
meta: { title: 'inlineEditTable' }
|
||||
},
|
||||
{
|
||||
path: 'tree-table',
|
||||
component: () => import('@/views/table/treeTable/treeTable'),
|
||||
name: 'treeTableDemo',
|
||||
meta: { title: 'treeTable' }
|
||||
},
|
||||
{
|
||||
path: 'custom-tree-table',
|
||||
component: () => import('@/views/table/treeTable/customTreeTable'),
|
||||
name: 'customTreeTableDemo',
|
||||
meta: { title: 'customTreeTable' }
|
||||
},
|
||||
{
|
||||
path: 'complex-table',
|
||||
component: () => import('@/views/table/complexTable'),
|
||||
name: 'complexTable',
|
||||
meta: { title: 'complexTable' }
|
||||
}
|
||||
]
|
||||
}
|
||||
export default tableRouter
|
|
@ -6,9 +6,11 @@ const tagsView = {
|
|||
mutations: {
|
||||
ADD_VISITED_VIEWS: (state, view) => {
|
||||
if (state.visitedViews.some(v => v.path === view.path)) return
|
||||
state.visitedViews.push(Object.assign({}, view, {
|
||||
title: view.meta.title || 'no-name'
|
||||
}))
|
||||
state.visitedViews.push(
|
||||
Object.assign({}, view, {
|
||||
title: view.meta.title || 'no-name'
|
||||
})
|
||||
)
|
||||
if (!view.meta.noCache) {
|
||||
state.cachedViews.push(view.name)
|
||||
}
|
||||
|
@ -38,12 +40,12 @@ const tagsView = {
|
|||
for (const i of state.cachedViews) {
|
||||
if (i === view.name) {
|
||||
const index = state.cachedViews.indexOf(i)
|
||||
state.cachedViews = state.cachedViews.slice(index, i + 1)
|
||||
state.cachedViews = state.cachedViews.slice(index, index + 1)
|
||||
break
|
||||
}
|
||||
}
|
||||
},
|
||||
DEL_ALL_VIEWS: (state) => {
|
||||
DEL_ALL_VIEWS: state => {
|
||||
state.visitedViews = []
|
||||
state.cachedViews = []
|
||||
}
|
||||
|
@ -53,19 +55,19 @@ const tagsView = {
|
|||
commit('ADD_VISITED_VIEWS', view)
|
||||
},
|
||||
delVisitedViews({ commit, state }, view) {
|
||||
return new Promise((resolve) => {
|
||||
return new Promise(resolve => {
|
||||
commit('DEL_VISITED_VIEWS', view)
|
||||
resolve([...state.visitedViews])
|
||||
})
|
||||
},
|
||||
delOthersViews({ commit, state }, view) {
|
||||
return new Promise((resolve) => {
|
||||
return new Promise(resolve => {
|
||||
commit('DEL_OTHERS_VIEWS', view)
|
||||
resolve([...state.visitedViews])
|
||||
})
|
||||
},
|
||||
delAllViews({ commit, state }) {
|
||||
return new Promise((resolve) => {
|
||||
return new Promise(resolve => {
|
||||
commit('DEL_ALL_VIEWS')
|
||||
resolve([...state.visitedViews])
|
||||
})
|
||||
|
|
|
@ -25,7 +25,7 @@ export function parseTime(time, cFormat) {
|
|||
}
|
||||
const time_str = format.replace(/{(y|m|d|h|i|s|a)+}/g, (result, key) => {
|
||||
let value = formatObj[key]
|
||||
if (key === 'a') return ['一', '二', '三', '四', '五', '六', '日'][value - 1]
|
||||
if (key === 'a') { return ['一', '二', '三', '四', '五', '六', '日'][value - 1] }
|
||||
if (result.length > 0 && value < 10) {
|
||||
value = '0' + value
|
||||
}
|
||||
|
@ -43,7 +43,8 @@ export function formatTime(time, option) {
|
|||
|
||||
if (diff < 30) {
|
||||
return '刚刚'
|
||||
} else if (diff < 3600) { // less 1 hour
|
||||
} else if (diff < 3600) {
|
||||
// less 1 hour
|
||||
return Math.ceil(diff / 60) + '分钟前'
|
||||
} else if (diff < 3600 * 24) {
|
||||
return Math.ceil(diff / 3600) + '小时前'
|
||||
|
@ -53,7 +54,17 @@ export function formatTime(time, option) {
|
|||
if (option) {
|
||||
return parseTime(time, option)
|
||||
} else {
|
||||
return d.getMonth() + 1 + '月' + d.getDate() + '日' + d.getHours() + '时' + d.getMinutes() + '分'
|
||||
return (
|
||||
d.getMonth() +
|
||||
1 +
|
||||
'月' +
|
||||
d.getDate() +
|
||||
'日' +
|
||||
d.getHours() +
|
||||
'时' +
|
||||
d.getMinutes() +
|
||||
'分'
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -81,9 +92,11 @@ export function getQueryObject(url) {
|
|||
export function getByteLen(val) {
|
||||
let len = 0
|
||||
for (let i = 0; i < val.length; i++) {
|
||||
if (val[i].match(/[^\x00-\xff]/ig) != null) {
|
||||
if (val[i].match(/[^\x00-\xff]/gi) != null) {
|
||||
len += 1
|
||||
} else { len += 0.5 }
|
||||
} else {
|
||||
len += 0.5
|
||||
}
|
||||
}
|
||||
return Math.floor(len)
|
||||
}
|
||||
|
@ -100,11 +113,12 @@ export function cleanArray(actual) {
|
|||
|
||||
export function param(json) {
|
||||
if (!json) return ''
|
||||
return cleanArray(Object.keys(json).map(key => {
|
||||
if (json[key] === undefined) return ''
|
||||
return encodeURIComponent(key) + '=' +
|
||||
encodeURIComponent(json[key])
|
||||
})).join('&')
|
||||
return cleanArray(
|
||||
Object.keys(json).map(key => {
|
||||
if (json[key] === undefined) return ''
|
||||
return encodeURIComponent(key) + '=' + encodeURIComponent(json[key])
|
||||
})
|
||||
).join('&')
|
||||
}
|
||||
|
||||
export function param2Obj(url) {
|
||||
|
@ -112,7 +126,14 @@ export function param2Obj(url) {
|
|||
if (!search) {
|
||||
return {}
|
||||
}
|
||||
return JSON.parse('{"' + decodeURIComponent(search).replace(/"/g, '\\"').replace(/&/g, '","').replace(/=/g, '":"') + '"}')
|
||||
return JSON.parse(
|
||||
'{"' +
|
||||
decodeURIComponent(search)
|
||||
.replace(/"/g, '\\"')
|
||||
.replace(/&/g, '","')
|
||||
.replace(/=/g, '":"') +
|
||||
'"}'
|
||||
)
|
||||
}
|
||||
|
||||
export function html2Text(val) {
|
||||
|
@ -131,7 +152,7 @@ export function objectMerge(target, source) {
|
|||
if (Array.isArray(source)) {
|
||||
return source.slice()
|
||||
}
|
||||
Object.keys(source).forEach((property) => {
|
||||
Object.keys(source).forEach(property => {
|
||||
const sourceProperty = source[property]
|
||||
if (typeof sourceProperty === 'object') {
|
||||
target[property] = objectMerge(target[property], sourceProperty)
|
||||
|
@ -145,7 +166,7 @@ export function objectMerge(target, source) {
|
|||
export function scrollTo(element, to, duration) {
|
||||
if (duration <= 0) return
|
||||
const difference = to - element.scrollTop
|
||||
const perTick = difference / duration * 10
|
||||
const perTick = (difference / duration) * 10
|
||||
setTimeout(() => {
|
||||
console.log(new Date())
|
||||
element.scrollTop = element.scrollTop + perTick
|
||||
|
@ -163,7 +184,9 @@ export function toggleClass(element, className) {
|
|||
if (nameIndex === -1) {
|
||||
classString += '' + className
|
||||
} else {
|
||||
classString = classString.substr(0, nameIndex) + classString.substr(nameIndex + className.length)
|
||||
classString =
|
||||
classString.substr(0, nameIndex) +
|
||||
classString.substr(nameIndex + className.length)
|
||||
}
|
||||
element.className = classString
|
||||
}
|
||||
|
@ -177,7 +200,8 @@ export const pickerOptions = [
|
|||
end.setTime(start.getTime())
|
||||
picker.$emit('pick', [start, end])
|
||||
}
|
||||
}, {
|
||||
},
|
||||
{
|
||||
text: '最近一周',
|
||||
onClick(picker) {
|
||||
const end = new Date(new Date().toDateString())
|
||||
|
@ -185,7 +209,8 @@ export const pickerOptions = [
|
|||
start.setTime(end.getTime() - 3600 * 1000 * 24 * 7)
|
||||
picker.$emit('pick', [start, end])
|
||||
}
|
||||
}, {
|
||||
},
|
||||
{
|
||||
text: '最近一个月',
|
||||
onClick(picker) {
|
||||
const end = new Date(new Date().toDateString())
|
||||
|
@ -193,7 +218,8 @@ export const pickerOptions = [
|
|||
start.setTime(start.getTime() - 3600 * 1000 * 24 * 30)
|
||||
picker.$emit('pick', [start, end])
|
||||
}
|
||||
}, {
|
||||
},
|
||||
{
|
||||
text: '最近三个月',
|
||||
onClick(picker) {
|
||||
const end = new Date(new Date().toDateString())
|
||||
|
@ -201,7 +227,8 @@ export const pickerOptions = [
|
|||
start.setTime(start.getTime() - 3600 * 1000 * 24 * 90)
|
||||
picker.$emit('pick', [start, end])
|
||||
}
|
||||
}]
|
||||
}
|
||||
]
|
||||
|
||||
export function getTime(type) {
|
||||
if (type === 'start') {
|
||||
|
@ -256,7 +283,7 @@ export function deepClone(source) {
|
|||
throw new Error('error arguments', 'shallowClone')
|
||||
}
|
||||
const targetObj = source.constructor === Array ? [] : {}
|
||||
Object.keys(source).forEach((keys) => {
|
||||
Object.keys(source).forEach(keys => {
|
||||
if (source[keys] && typeof source[keys] === 'object') {
|
||||
targetObj[keys] = deepClone(source[keys])
|
||||
} else {
|
||||
|
|
|
@ -23,4 +23,3 @@ export default function checkPermission(value) {
|
|||
return false
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -10,18 +10,21 @@ const service = axios.create({
|
|||
})
|
||||
|
||||
// request interceptor
|
||||
service.interceptors.request.use(config => {
|
||||
// Do something before request is sent
|
||||
if (store.getters.token) {
|
||||
// 让每个请求携带token-- ['X-Token']为自定义key 请根据实际情况自行修改
|
||||
config.headers['X-Token'] = getToken()
|
||||
service.interceptors.request.use(
|
||||
config => {
|
||||
// Do something before request is sent
|
||||
if (store.getters.token) {
|
||||
// 让每个请求携带token-- ['X-Token']为自定义key 请根据实际情况自行修改
|
||||
config.headers['X-Token'] = getToken()
|
||||
}
|
||||
return config
|
||||
},
|
||||
error => {
|
||||
// Do something with request error
|
||||
console.log(error) // for debug
|
||||
Promise.reject(error)
|
||||
}
|
||||
return config
|
||||
}, error => {
|
||||
// Do something with request error
|
||||
console.log(error) // for debug
|
||||
Promise.reject(error)
|
||||
})
|
||||
)
|
||||
|
||||
// respone interceptor
|
||||
service.interceptors.response.use(
|
||||
|
@ -67,6 +70,7 @@ service.interceptors.response.use(
|
|||
duration: 5 * 1000
|
||||
})
|
||||
return Promise.reject(error)
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
export default service
|
||||
|
|
|
@ -40,4 +40,3 @@ export function validateEmail(email) {
|
|||
const re = /^(([^<>()\[\]\\.,;:\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 re.test(email)
|
||||
}
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<div class="components-container">
|
||||
<code>Markdown is based on
|
||||
<a href="https://github.com/sparksuite/simplemde-markdown-editor" target="_blank">simplemde-markdown-editor</a> ,Simply encapsulated in Vue.
|
||||
<a target="_blank" href="https://segmentfault.com/a/1190000009762198#articleHeader14">
|
||||
<a target="_blank" href="https://juejin.im/post/593121aa0ce4630057f70d35#heading-15">
|
||||
相关文章 </a>
|
||||
</code>
|
||||
<div class="editor-container">
|
||||
|
|
|
@ -7,19 +7,19 @@
|
|||
</div>
|
||||
<div style="margin-bottom:50px;">
|
||||
<el-col :span="4" class="text-center">
|
||||
<router-link class="pan-btn blue-btn" to="/components/index">Components</router-link>
|
||||
<router-link class="pan-btn blue-btn" to="/documentation/index">Documentation</router-link>
|
||||
</el-col>
|
||||
<el-col :span="4" class="text-center">
|
||||
<router-link class="pan-btn light-blue-btn" to="/charts/index">Charts</router-link>
|
||||
<router-link class="pan-btn light-blue-btn" to="/icon/index">Icons</router-link>
|
||||
</el-col>
|
||||
<el-col :span="4" class="text-center">
|
||||
<router-link class="pan-btn pink-btn" to="/excel/download">Excel</router-link>
|
||||
<router-link class="pan-btn pink-btn" to="/excel/export-excel">Excel</router-link>
|
||||
</el-col>
|
||||
<el-col :span="4" class="text-center">
|
||||
<router-link class="pan-btn green-btn" to="/example/table/complex-table">Table</router-link>
|
||||
<router-link class="pan-btn green-btn" to="/table/complex-table">Table</router-link>
|
||||
</el-col>
|
||||
<el-col :span="4" class="text-center">
|
||||
<router-link class="pan-btn tiffany-btn" to="/form/edit-form">Form</router-link>
|
||||
<router-link class="pan-btn tiffany-btn" to="/example/create">Form</router-link>
|
||||
</el-col>
|
||||
<el-col :span="4" class="text-center">
|
||||
<router-link class="pan-btn yellow-btn" to="/theme/index">Theme</router-link>
|
||||
|
@ -130,12 +130,14 @@ export default {
|
|||
title: [{ required: true, trigger: 'change', validator: validate }]
|
||||
},
|
||||
articleList: [
|
||||
{ title: '基础篇', href: 'https://segmentfault.com/a/1190000009275424' },
|
||||
{ title: '登录权限篇', href: 'https://segmentfault.com/a/1190000009506097' },
|
||||
{ title: '实战篇', href: 'https://segmentfault.com/a/1190000009762198' },
|
||||
{ title: 'vueAdmin-template 篇', href: 'https://segmentfault.com/a/1190000010043013' },
|
||||
{ title: '基础篇', href: 'https://juejin.im/post/59097cd7a22b9d0065fb61d2' },
|
||||
{ title: '登录权限篇', href: 'https://juejin.im/post/591aa14f570c35006961acac' },
|
||||
{ title: '实战篇', href: 'https://juejin.im/post/593121aa0ce4630057f70d35' },
|
||||
{ title: 'vueAdmin-template 篇', href: 'https://juejin.im/post/595b4d776fb9a06bbe7dba56' },
|
||||
{ title: '自行封装 component', href: 'https://segmentfault.com/a/1190000009090836' },
|
||||
{ title: '优雅的使用 icon', href: 'https://segmentfault.com/a/https://segmentfault.com/a/1190000012213278' }
|
||||
{ title: '优雅的使用 icon', href: 'https://juejin.im/post/59bb864b5188257e7a427c09' },
|
||||
{ title: 'webpack4(上)', href: 'https://juejin.im/post/59bb864b5188257e7a427c09' },
|
||||
{ title: 'webpack4(下)', href: 'https://juejin.im/post/5b5d6d6f6fb9a04fea58aabc' }
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -72,7 +72,7 @@ export default {
|
|||
}
|
||||
},
|
||||
methods: {
|
||||
setLocalStorgae() {
|
||||
setLocalStorage() {
|
||||
window.localStorage.setItem(STORAGE_KEY, JSON.stringify(this.todos))
|
||||
},
|
||||
addTodo(e) {
|
||||
|
@ -82,30 +82,30 @@ export default {
|
|||
text,
|
||||
done: false
|
||||
})
|
||||
this.setLocalStorgae()
|
||||
this.setLocalStorage()
|
||||
}
|
||||
e.target.value = ''
|
||||
},
|
||||
toggleTodo(val) {
|
||||
val.done = !val.done
|
||||
this.setLocalStorgae()
|
||||
this.setLocalStorage()
|
||||
},
|
||||
deleteTodo(todo) {
|
||||
this.todos.splice(this.todos.indexOf(todo), 1)
|
||||
this.setLocalStorgae()
|
||||
this.setLocalStorage()
|
||||
},
|
||||
editTodo({ todo, value }) {
|
||||
todo.text = value
|
||||
this.setLocalStorgae()
|
||||
this.setLocalStorage()
|
||||
},
|
||||
clearCompleted() {
|
||||
this.todos = this.todos.filter(todo => !todo.done)
|
||||
this.setLocalStorgae()
|
||||
this.setLocalStorage()
|
||||
},
|
||||
toggleAll({ done }) {
|
||||
this.todos.forEach(todo => {
|
||||
todo.done = done
|
||||
this.setLocalStorgae()
|
||||
this.setLocalStorage()
|
||||
})
|
||||
}
|
||||
},
|
||||
|
|
|
@ -14,12 +14,14 @@ export default {
|
|||
data() {
|
||||
return {
|
||||
articleList: [
|
||||
{ title: '基础篇', href: 'https://segmentfault.com/a/1190000009275424' },
|
||||
{ title: '登录权限篇', href: 'https://segmentfault.com/a/1190000009506097' },
|
||||
{ title: '实战篇', href: 'https://segmentfault.com/a/1190000009762198' },
|
||||
{ title: 'vueAdmin-template 篇', href: 'https://segmentfault.com/a/1190000010043013' },
|
||||
{ title: '基础篇', href: 'https://juejin.im/post/59097cd7a22b9d0065fb61d2' },
|
||||
{ title: '登录权限篇', href: 'https://juejin.im/post/591aa14f570c35006961acac' },
|
||||
{ title: '实战篇', href: 'https://juejin.im/post/593121aa0ce4630057f70d35' },
|
||||
{ title: 'vueAdmin-template 篇', href: 'https://juejin.im/post/595b4d776fb9a06bbe7dba56' },
|
||||
{ title: '自行封装 component', href: 'https://segmentfault.com/a/1190000009090836' },
|
||||
{ title: '优雅的使用 icon', href: 'https://segmentfault.com/a/1190000012213278' }
|
||||
{ title: '优雅的使用 icon', href: 'https://juejin.im/post/59bb864b5188257e7a427c09' },
|
||||
{ title: 'webpack4(上)', href: 'https://juejin.im/post/59bb864b5188257e7a427c09' },
|
||||
{ title: 'webpack4(下)', href: 'https://juejin.im/post/5b5d6d6f6fb9a04fea58aabc' }
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,10 +2,10 @@
|
|||
<div class="wscn-http404-container">
|
||||
<div class="wscn-http404">
|
||||
<div class="pic-404">
|
||||
<img class="pic-404__parent" :src="img_404" alt="404">
|
||||
<img class="pic-404__child left" :src="img_404_cloud" alt="404">
|
||||
<img class="pic-404__child mid" :src="img_404_cloud" alt="404">
|
||||
<img class="pic-404__child right" :src="img_404_cloud" alt="404">
|
||||
<img class="pic-404__parent" src="@/assets/404_images/404.png" alt="404">
|
||||
<img class="pic-404__child left" src="@/assets/404_images/404_cloud.png" alt="404">
|
||||
<img class="pic-404__child mid" src="@/assets/404_images/404_cloud.png" alt="404">
|
||||
<img class="pic-404__child right" src="@/assets/404_images/404_cloud.png" alt="404">
|
||||
</div>
|
||||
<div class="bullshit">
|
||||
<div class="bullshit__oops">OOPS!</div>
|
||||
|
@ -21,17 +21,9 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import img_404 from '@/assets/404_images/404.png'
|
||||
import img_404_cloud from '@/assets/404_images/404_cloud.png'
|
||||
|
||||
export default {
|
||||
name: 'page404',
|
||||
data() {
|
||||
return {
|
||||
img_404,
|
||||
img_404_cloud
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
message() {
|
||||
return '网管说这个页面你不能进......'
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
<template>
|
||||
<div v-if="!item.hidden&&item.children" class="menu-wrapper">
|
||||
|
||||
<router-link v-if="hasOneShowingChildren(item.children) && !item.children[0].children&&!item.alwaysShow" :to="resolvePath(item.children[0].path)">
|
||||
<el-menu-item :index="resolvePath(item.children[0].path)" :class="{'submenu-title-noDropdown':!isNest}">
|
||||
<svg-icon v-if="item.children[0].meta&&item.children[0].meta.icon" :icon-class="item.children[0].meta.icon"></svg-icon>
|
||||
<span v-if="item.children[0].meta&&item.children[0].meta.title" slot="title">{{generateTitle(item.children[0].meta.title)}}</span>
|
||||
<router-link v-if="hasOneShowingChild(item.children) && !onlyOneChild.children&&!item.alwaysShow" :to="resolvePath(onlyOneChild.path)">
|
||||
<el-menu-item :index="resolvePath(onlyOneChild.path)" :class="{'submenu-title-noDropdown':!isNest}">
|
||||
<svg-icon v-if="onlyOneChild.meta&&onlyOneChild.meta.icon" :icon-class="onlyOneChild.meta.icon"></svg-icon>
|
||||
<span v-if="onlyOneChild.meta&&onlyOneChild.meta.title" slot="title">{{generateTitle(onlyOneChild.meta.title)}}</span>
|
||||
</el-menu-item>
|
||||
</router-link>
|
||||
|
||||
|
@ -50,10 +50,21 @@ export default {
|
|||
default: ''
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
onlyOneChild: null
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
hasOneShowingChildren(children) {
|
||||
hasOneShowingChild(children) {
|
||||
const showingChildren = children.filter(item => {
|
||||
return !item.hidden
|
||||
if (item.hidden) {
|
||||
return false
|
||||
} else {
|
||||
// temp set(will be used if only has one showing child )
|
||||
this.onlyOneChild = item
|
||||
return true
|
||||
}
|
||||
})
|
||||
if (showingChildren.length === 1) {
|
||||
return true
|
||||
|
|
|
@ -142,36 +142,50 @@ export default {
|
|||
</script>
|
||||
|
||||
<style rel="stylesheet/scss" lang="scss">
|
||||
$bg:#2d3a4b;
|
||||
$light_gray:#eee;
|
||||
/* 修复input 背景不协调 和光标变色 */
|
||||
/* Detail see https://github.com/PanJiaChen/vue-element-admin/pull/927 */
|
||||
|
||||
/* reset element-ui css */
|
||||
.login-container {
|
||||
.el-input {
|
||||
display: inline-block;
|
||||
height: 47px;
|
||||
width: 85%;
|
||||
input {
|
||||
background: transparent;
|
||||
border: 0px;
|
||||
-webkit-appearance: none;
|
||||
border-radius: 0px;
|
||||
padding: 12px 5px 12px 15px;
|
||||
color: $light_gray;
|
||||
height: 47px;
|
||||
&:-webkit-autofill {
|
||||
-webkit-box-shadow: 0 0 0px 1000px $bg inset !important;
|
||||
-webkit-text-fill-color: #fff !important;
|
||||
$bg:#283443;
|
||||
$light_gray:#eee;
|
||||
$cursor: #fff;
|
||||
|
||||
@supports (-webkit-mask: none) and (not (cater-color: $cursor)) {
|
||||
.login-container .el-input input{
|
||||
color: $cursor;
|
||||
&::first-line {
|
||||
color: $light_gray;
|
||||
}
|
||||
}
|
||||
}
|
||||
.el-form-item {
|
||||
border: 1px solid rgba(255, 255, 255, 0.1);
|
||||
background: rgba(0, 0, 0, 0.1);
|
||||
border-radius: 5px;
|
||||
color: #454545;
|
||||
|
||||
/* reset element-ui css */
|
||||
.login-container {
|
||||
.el-input {
|
||||
display: inline-block;
|
||||
height: 47px;
|
||||
width: 85%;
|
||||
input {
|
||||
background: transparent;
|
||||
border: 0px;
|
||||
-webkit-appearance: none;
|
||||
border-radius: 0px;
|
||||
padding: 12px 5px 12px 15px;
|
||||
color: $light_gray;
|
||||
height: 47px;
|
||||
caret-color: $cursor;
|
||||
&:-webkit-autofill {
|
||||
-webkit-box-shadow: 0 0 0px 1000px $bg inset !important;
|
||||
-webkit-text-fill-color: $cursor !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
.el-form-item {
|
||||
border: 1px solid rgba(255, 255, 255, 0.1);
|
||||
background: rgba(0, 0, 0, 0.1);
|
||||
border-radius: 5px;
|
||||
color: #454545;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<style rel="stylesheet/scss" lang="scss" scoped>
|
||||
|
@ -216,7 +230,6 @@ $light_gray:#eee;
|
|||
position: relative;
|
||||
.title {
|
||||
font-size: 26px;
|
||||
font-weight: 400;
|
||||
color: $light_gray;
|
||||
margin: 0px auto 40px auto;
|
||||
text-align: center;
|
||||
|
|
Loading…
Reference in New Issue