Compare commits

...

31 Commits

Author SHA1 Message Date
花裤衩
378ca2c217 update to webpack4 (#889) 2018-08-15 15:33:34 +08:00
Andrey Dos
1df59cc4b6 fix typo(#965) 2018-08-15 14:51:08 +08:00
shufangyi
312a2ca8ed fixBug[waves.js]: wave's position (#949)
* fixBug[waves.js]-wave's position

* fix[waves.js]-wave's position
2018-08-13 13:45:05 +08:00
Pan
f3733c0b37 fix: demo links 2018-08-13 13:13:41 +08:00
Pan
0ef14ff5c6 tweak 2018-08-09 11:03:13 +08:00
Pan
c57c6045c9 docs: tweak 2018-08-08 13:42:12 +08:00
_xiaotian
fe190b6188 perf[login.vue]: Improve input background and cursor color (#927)
* 完善input背景和光标色;

1.完善在Chrome浏览器时登陆界面的input标签 使用记住密码之后颜色和背景不一致;
2.目前的rgb值是 #2d3a4b  修改的rgb值是 #283443;
3.修复光标使用Chrome记录的账号之后变黑色;
4.移除 .title-container .title 重复的font-weight: 400;
5.不用IE我们大家都是好朋友!~

* Update index.vue
2018-08-01 11:03:29 +08:00
Pan
48a966fe1c docs: add gitee 2018-07-31 11:26:45 +08:00
Pan
63d39727ac [release] 3.7.3 2018-07-31 11:14:18 +08:00
Pan
1e0b9c0055 fix[Tinymce]: fixed tinymce upload dialog bug #654 2018-07-31 11:12:38 +08:00
mimimi
5f20bfc780 fixed[tagsView]: DEL_OTHERS_VIEWS cachedViews bug (#913)
* mutations DEL_OTHERS_VIEWS state.cachedViews -> i type is string slice(begin: number, end: number)
2018-07-25 17:20:32 +08:00
mimimi
8851a68066 tweak setLocalStorgae -> setLocalStorage (#894) 2018-07-20 16:02:38 +08:00
Pan
878628b0ed tweak code comments 2018-07-20 10:25:14 +08:00
Pan
e254fc6c1a fix[Sidebar]: fixed sidebar bug when set hidden:true #880 2018-07-17 18:13:29 +08:00
花裤衩
513eb66d97 fix[UploadExcel]: add file type check (#878) 2018-07-17 13:30:52 +08:00
Pan
62e1c851c8 tweak 2018-07-16 11:18:13 +08:00
Pan
f0a01f0fd1 [release] 3.7.2 2018-07-13 13:38:43 +08:00
博文
aa7eab58f9 refactor(SidebarItem): optimizate SidebarItem (#845)
* refactor(sidebar-item): optimizate SiderbarItem.

* chore: update nested examples.

* fix: fix a wrong path.

* fix: fix a transition bug.

* fix: fix a wrong path.

* perf: using "router" mode of el-menu.

* Revert "perf: using "router" mode of el-menu."

This reverts commit cef02a30b0.

* fix: complement i18n text.
2018-07-13 11:23:06 +08:00
花裤衩
77cb6b1f43 fix[excel]: default filename bug && format code (#857)
* fix filename bug

* format

* format
2018-07-11 14:16:28 +08:00
iGoo丶
5fbf1cf5da 修正README.zh-CN.md (#856) 2018-07-11 00:18:34 +08:00
Pan
6a5197ad51 perf[css]: refine style 2018-07-10 13:22:16 +08:00
Pan
9b7a9a64e5 fix[css]: css bug in mobile #852 2018-07-10 13:02:19 +08:00
Pan
89ce53e185 fix[TagsView]: fix contextmenu position bug #850 2018-07-09 17:25:45 +08:00
Pan
9e04f58163 perf[login]: i18n of input placeholder #844 2018-07-07 01:44:29 +08:00
花裤衩
d98c5032f8 refine style (#843)
* refine style

* refine 404 style

* refine
2018-07-06 11:19:53 +08:00
ZYSzys
a575670cef perf[ArticleDetail]: refine el-col :span (#841) 2018-07-06 10:07:43 +08:00
花裤衩
44fa96f142 chore: add lint-staged (#818) 2018-07-03 16:31:29 +08:00
Pan
e4481a9d34 fix[build.js]: fixed build bug in preview mode #819 2018-07-02 14:02:42 +08:00
Pan
572a2d9c34 perf[Tinymce]: set nonbreaking_force_tab to true 2018-06-30 17:26:31 +08:00
Pan
5070e20dea update docs 2018-06-28 13:20:44 +08:00
Pan
59789d92cf perf[uploadExcel]: fix typo 2018-06-28 09:53:55 +08:00
60 changed files with 928 additions and 679 deletions

1
.gitignore vendored
View File

@@ -4,6 +4,7 @@ dist/
npm-debug.log* npm-debug.log*
yarn-debug.log* yarn-debug.log*
yarn-error.log* yarn-error.log*
**/*.log
test/unit/coverage test/unit/coverage
test/e2e/reports test/e2e/reports

View File

@@ -38,6 +38,8 @@ 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/) - [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.** **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)   - Base template recommends using: [vueAdmin-template](https://github.com/PanJiaChen/vueAdmin-template)  
@@ -149,6 +151,9 @@ npm run build:prod
# --report to build with bundle size analytics # --report to build with bundle size analytics
npm run build:prod --report 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 # --preview to start a server in local to preview
npm run build:prod --preview npm run build:prod --preview

View File

@@ -36,6 +36,8 @@
- [Donate](https://panjiachen.github.io/vue-element-admin-site/zh/donate/) - [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)   - 模板建议使用: [vueAdmin-template](https://github.com/PanJiaChen/vueAdmin-template)  
- 桌面端: [electron-vue-admin](https://github.com/PanJiaChen/electron-vue-admin) - 桌面端: [electron-vue-admin](https://github.com/PanJiaChen/electron-vue-admin)
@@ -51,7 +53,8 @@
- [手摸手,带你用 vue 撸后台 系列四(vueAdmin 一个极简的后台基础模板)](https://juejin.im/post/595b4d776fb9a06bbe7dba56) - [手摸手,带你用 vue 撸后台 系列四(vueAdmin 一个极简的后台基础模板)](https://juejin.im/post/595b4d776fb9a06bbe7dba56)
- [手摸手,带你封装一个 vue component](https://segmentfault.com/a/1190000009090836) - [手摸手,带你封装一个 vue component](https://segmentfault.com/a/1190000009090836)
- [手摸手,带你优雅的使用 icon](https://juejin.im/post/59bb864b5188257e7a427c09) - [手摸手,带你优雅的使用 icon](https://juejin.im/post/59bb864b5188257e7a427c09)
- [手摸手带你用合理的姿势使用webpack4](https://juejin.im/post/5b56909a518825195f499806)
- [手摸手带你用合理的姿势使用webpack4](https://juejin.im/post/5b5d6d6f6fb9a04fea58aabc)
或者加入该群主 **[圈子](https://jianshiapp.com/circles/1209)** 楼主会经常分享一些技术相关的东西 或者加入该群主 **[圈子](https://jianshiapp.com/circles/1209)** 楼主会经常分享一些技术相关的东西
@@ -152,14 +155,17 @@ npm run dev
# 构建测试环境 # 构建测试环境
npm run build:sit npm run build:sit
# 构建生环境 # 构建生环境
npm run build:prod npm run build:prod
``` ```
## 其它 ## 其它
```bash ```bash
# --report to build with bundle size analytics # --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 # --preview to start a server in local to preview
npm run build:prod --preview npm run build:prod --preview

View File

@@ -8,9 +8,12 @@ const chalk = require('chalk')
const webpack = require('webpack') const webpack = require('webpack')
const config = require('../config') const config = require('../config')
const webpackConfig = require('./webpack.prod.conf') const webpackConfig = require('./webpack.prod.conf')
const server = require('pushstate-server') var connect = require('connect')
var serveStatic = require('serve-static')
var spinner = ora('building for '+ process.env.env_config+ ' environment...' ) const spinner = ora(
'building for ' + process.env.env_config + ' environment...'
)
spinner.start() spinner.start()
rm(path.join(config.build.assetsRoot, config.build.assetsSubDirectory), err => { rm(path.join(config.build.assetsRoot, config.build.assetsSubDirectory), err => {
@@ -18,13 +21,15 @@ rm(path.join(config.build.assetsRoot, config.build.assetsSubDirectory), err => {
webpack(webpackConfig, (err, stats) => { webpack(webpackConfig, (err, stats) => {
spinner.stop() spinner.stop()
if (err) throw err if (err) throw err
process.stdout.write(stats.toString({ process.stdout.write(
stats.toString({
colors: true, colors: true,
modules: false, modules: false,
children: false, children: false,
chunks: false, chunks: false,
chunkModules: false chunkModules: false
}) + '\n\n') }) + '\n\n'
)
if (stats.hasErrors()) { if (stats.hasErrors()) {
console.log(chalk.red(' Build failed with errors.\n')) console.log(chalk.red(' Build failed with errors.\n'))
@@ -32,17 +37,31 @@ rm(path.join(config.build.assetsRoot, config.build.assetsSubDirectory), err => {
} }
console.log(chalk.cyan(' Build complete.\n')) console.log(chalk.cyan(' Build complete.\n'))
console.log(chalk.yellow( console.log(
chalk.yellow(
' Tip: built files are meant to be served over an HTTP server.\n' + ' Tip: built files are meant to be served over an HTTP server.\n' +
' Opening index.html over file:// won\'t work.\n' " Opening index.html over file:// won't work.\n"
)) )
if(process.env.npm_config_preview){ )
server.start({
port: 9526, if (process.env.npm_config_preview) {
directory: './dist', const port = 9526
file: '/index.html' const host = 'http://localhost:' + port
}); const basePath = config.build.assetsPublicPath
console.log('> Listening at ' + 'http://localhost:9526' + '\n') const app = connect()
app.use(
basePath,
serveStatic('./dist', {
index: ['index.html', '/']
})
)
app.listen(port, function() {
console.log(
chalk.green(`> Listening at http://localhost:${port}${basePath}`)
)
})
} }
}) })
}) })

View File

@@ -4,8 +4,11 @@ const semver = require('semver')
const packageConfig = require('../package.json') const packageConfig = require('../package.json')
const shell = require('shelljs') const shell = require('shelljs')
function exec (cmd) { function exec(cmd) {
return require('child_process').execSync(cmd).toString().trim() return require('child_process')
.execSync(cmd)
.toString()
.trim()
} }
const versionRequirements = [ const versionRequirements = [
@@ -24,15 +27,18 @@ if (shell.which('npm')) {
}) })
} }
module.exports = function () { module.exports = function() {
const warnings = [] const warnings = []
for (let i = 0; i < versionRequirements.length; i++) { for (let i = 0; i < versionRequirements.length; i++) {
const mod = versionRequirements[i] const mod = versionRequirements[i]
if (!semver.satisfies(mod.currentVersion, mod.versionRequirement)) { if (!semver.satisfies(mod.currentVersion, mod.versionRequirement)) {
warnings.push(mod.name + ': ' + warnings.push(
chalk.red(mod.currentVersion) + ' should be ' + mod.name +
': ' +
chalk.red(mod.currentVersion) +
' should be ' +
chalk.green(mod.versionRequirement) chalk.green(mod.versionRequirement)
) )
} }
@@ -40,7 +46,11 @@ module.exports = function () {
if (warnings.length) { if (warnings.length) {
console.log('') 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() console.log()
for (let i = 0; i < warnings.length; i++) { for (let i = 0; i < warnings.length; i++) {

View File

@@ -1,18 +1,19 @@
'use strict' 'use strict'
const path = require('path') const path = require('path')
const config = require('../config') const config = require('../config')
const ExtractTextPlugin = require('extract-text-webpack-plugin') const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const packageConfig = require('../package.json') const packageConfig = require('../package.json')
exports.assetsPath = function (_path) { exports.assetsPath = function(_path) {
const assetsSubDirectory = process.env.NODE_ENV === 'production' const assetsSubDirectory =
process.env.NODE_ENV === 'production'
? config.build.assetsSubDirectory ? config.build.assetsSubDirectory
: config.dev.assetsSubDirectory : config.dev.assetsSubDirectory
return path.posix.join(assetsSubDirectory, _path) return path.posix.join(assetsSubDirectory, _path)
} }
exports.cssLoaders = function (options) { exports.cssLoaders = function(options) {
options = options || {} options = options || {}
const cssLoader = { const cssLoader = {
@@ -30,8 +31,22 @@ exports.cssLoaders = function (options) {
} }
// generate loader string to be used with extract text plugin // generate loader string to be used with extract text plugin
function generateLoaders (loader, loaderOptions) { function generateLoaders(loader, loaderOptions) {
const loaders = options.usePostCSS ? [cssLoader, postcssLoader] : [cssLoader] 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) { if (loader) {
loaders.push({ loaders.push({
@@ -42,24 +57,16 @@ exports.cssLoaders = function (options) {
}) })
} }
// Extract CSS when that option is specified return loaders
// (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)
} }
}
// https://vue-loader.vuejs.org/en/configurations/extract-css.html // https://vue-loader.vuejs.org/en/configurations/extract-css.html
return { return {
css: generateLoaders(), css: generateLoaders(),
postcss: generateLoaders(), postcss: generateLoaders(),
less: generateLoaders('less'), less: generateLoaders('less'),
sass: generateLoaders('sass', { indentedSyntax: true }), sass: generateLoaders('sass', {
indentedSyntax: true
}),
scss: generateLoaders('sass'), scss: generateLoaders('sass'),
stylus: generateLoaders('stylus'), stylus: generateLoaders('stylus'),
styl: generateLoaders('stylus') styl: generateLoaders('stylus')
@@ -67,7 +74,7 @@ exports.cssLoaders = function (options) {
} }
// Generate loaders for standalone style files (outside of .vue) // Generate loaders for standalone style files (outside of .vue)
exports.styleLoaders = function (options) { exports.styleLoaders = function(options) {
const output = [] const output = []
const loaders = exports.cssLoaders(options) const loaders = exports.cssLoaders(options)

View File

@@ -1,22 +1,5 @@
'use strict' '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 = { module.exports = {
loaders: utils.cssLoaders({ //You can set the vue-loader configuration by yourself.
sourceMap: sourceMapEnabled,
extract: isProduction
}),
cssSourceMap: sourceMapEnabled,
cacheBusting: config.dev.cacheBusting,
transformToRequire: {
video: ['src', 'poster'],
source: 'src',
img: 'src',
image: 'xlink:href'
}
} }

View File

@@ -2,9 +2,10 @@
const path = require('path') const path = require('path')
const utils = require('./utils') const utils = require('./utils')
const config = require('../config') const config = require('../config')
const { VueLoaderPlugin } = require('vue-loader')
const vueLoaderConfig = require('./vue-loader.conf') const vueLoaderConfig = require('./vue-loader.conf')
function resolve (dir) { function resolve(dir) {
return path.join(__dirname, '..', dir) return path.join(__dirname, '..', dir)
} }
@@ -27,14 +28,15 @@ module.exports = {
output: { output: {
path: config.build.assetsRoot, path: config.build.assetsRoot,
filename: '[name].js', filename: '[name].js',
publicPath: process.env.NODE_ENV === 'production' publicPath:
process.env.NODE_ENV === 'production'
? config.build.assetsPublicPath ? config.build.assetsPublicPath
: config.dev.assetsPublicPath : config.dev.assetsPublicPath
}, },
resolve: { resolve: {
extensions: ['.js', '.vue', '.json'], extensions: ['.js', '.vue', '.json'],
alias: { alias: {
'@': resolve('src'), '@': resolve('src')
} }
}, },
module: { module: {
@@ -48,7 +50,11 @@ module.exports = {
{ {
test: /\.js$/, test: /\.js$/,
loader: 'babel-loader?cacheDirectory', 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$/, test: /\.svg$/,
@@ -85,6 +91,7 @@ module.exports = {
} }
] ]
}, },
plugins: [new VueLoaderPlugin()],
node: { node: {
// prevent webpack from injecting useless setImmediate polyfill because Vue // prevent webpack from injecting useless setImmediate polyfill because Vue
// source contains it (although only uses it if it's native). // source contains it (although only uses it if it's native).

View File

@@ -9,7 +9,7 @@ const HtmlWebpackPlugin = require('html-webpack-plugin')
const FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin') const FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin')
const portfinder = require('portfinder') const portfinder = require('portfinder')
function resolve (dir) { function resolve(dir) {
return path.join(__dirname, '..', 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 PORT = process.env.PORT && Number(process.env.PORT)
const devWebpackConfig = merge(baseWebpackConfig, { const devWebpackConfig = merge(baseWebpackConfig, {
mode: 'development',
module: { 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 // cheap-module-eval-source-map is faster for development
devtool: config.dev.devtool, devtool: config.dev.devtool,
@@ -39,7 +43,7 @@ const devWebpackConfig = merge(baseWebpackConfig, {
proxy: config.dev.proxyTable, proxy: config.dev.proxyTable,
quiet: true, // necessary for FriendlyErrorsPlugin quiet: true, // necessary for FriendlyErrorsPlugin
watchOptions: { watchOptions: {
poll: config.dev.poll, poll: config.dev.poll
} }
}, },
plugins: [ plugins: [
@@ -47,8 +51,6 @@ const devWebpackConfig = merge(baseWebpackConfig, {
'process.env': require('../config/dev.env') 'process.env': require('../config/dev.env')
}), }),
new webpack.HotModuleReplacementPlugin(), 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 // https://github.com/ampedandwired/html-webpack-plugin
new HtmlWebpackPlugin({ new HtmlWebpackPlugin({
filename: 'index.html', filename: 'index.html',
@@ -57,7 +59,7 @@ const devWebpackConfig = merge(baseWebpackConfig, {
favicon: resolve('favicon.ico'), favicon: resolve('favicon.ico'),
title: 'vue-element-admin', title: 'vue-element-admin',
path: config.dev.assetsPublicPath + config.dev.assetsSubDirectory path: config.dev.assetsPublicPath + config.dev.assetsSubDirectory
}), })
] ]
}) })
@@ -73,14 +75,20 @@ module.exports = new Promise((resolve, reject) => {
devWebpackConfig.devServer.port = port devWebpackConfig.devServer.port = port
// Add FriendlyErrorsPlugin // Add FriendlyErrorsPlugin
devWebpackConfig.plugins.push(new FriendlyErrorsPlugin({ devWebpackConfig.plugins.push(
new FriendlyErrorsPlugin({
compilationSuccessInfo: { compilationSuccessInfo: {
messages: [`Your application is running here: http://${devWebpackConfig.devServer.host}:${port}`], messages: [
`Your application is running here: http://${
devWebpackConfig.devServer.host
}:${port}`
]
}, },
onErrors: config.dev.notifyOnErrors onErrors: config.dev.notifyOnErrors
? utils.createNotifierCallback() ? utils.createNotifierCallback()
: undefined : undefined
})) })
)
resolve(devWebpackConfig) resolve(devWebpackConfig)
} }

View File

@@ -7,17 +7,23 @@ const merge = require('webpack-merge')
const baseWebpackConfig = require('./webpack.base.conf') const baseWebpackConfig = require('./webpack.base.conf')
const CopyWebpackPlugin = require('copy-webpack-plugin') const CopyWebpackPlugin = require('copy-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin') const HtmlWebpackPlugin = require('html-webpack-plugin')
const ExtractTextPlugin = require('extract-text-webpack-plugin') const ScriptExtHtmlWebpackPlugin = require('script-ext-html-webpack-plugin')
const OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin') const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin')
const UglifyJsPlugin = require('uglifyjs-webpack-plugin') const UglifyJsPlugin = require('uglifyjs-webpack-plugin')
function resolve (dir) { function resolve(dir) {
return path.join(__dirname, '..', 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, { const webpackConfig = merge(baseWebpackConfig, {
mode: 'production',
module: { module: {
rules: utils.styleLoaders({ rules: utils.styleLoaders({
sourceMap: config.build.productionSourceMap, sourceMap: config.build.productionSourceMap,
@@ -28,37 +34,18 @@ const webpackConfig = merge(baseWebpackConfig, {
devtool: config.build.productionSourceMap ? config.build.devtool : false, devtool: config.build.productionSourceMap ? config.build.devtool : false,
output: { output: {
path: config.build.assetsRoot, path: config.build.assetsRoot,
filename: utils.assetsPath('js/[name].[chunkhash].js'), filename: utils.assetsPath('js/[name].[chunkhash:8].js'),
chunkFilename: utils.assetsPath('js/[id].[chunkhash].js') chunkFilename: utils.assetsPath('js/[name].[chunkhash:8].js')
}, },
plugins: [ plugins: [
// http://vuejs.github.io/vue-loader/en/workflow/production.html // http://vuejs.github.io/vue-loader/en/workflow/production.html
new webpack.DefinePlugin({ new webpack.DefinePlugin({
'process.env': env 'process.env': env
}), }),
new UglifyJsPlugin({
uglifyOptions: {
compress: {
warnings: false
}
},
sourceMap: config.build.productionSourceMap,
parallel: true
}),
// extract css into its own file // extract css into its own file
new ExtractTextPlugin({ new MiniCssExtractPlugin({
filename: utils.assetsPath('css/[name].[contenthash].css'), filename: utils.assetsPath('css/[name].[contenthash:8].css'),
// Setting the following option to `false` will not extract CSS from codesplit chunks. chunkFilename: utils.assetsPath('css/[name].[contenthash:8].css')
// 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 }
}), }),
// generate dist index.html with correct asset hash for caching. // generate dist index.html with correct asset hash for caching.
// you can customize output by editing /index.html // you can customize output by editing /index.html
@@ -76,68 +63,34 @@ const webpackConfig = merge(baseWebpackConfig, {
removeAttributeQuotes: true removeAttributeQuotes: true
// more options: // more options:
// https://github.com/kangax/html-minifier#options-quick-reference // https://github.com/kangax/html-minifier#options-quick-reference
}, }
// necessary to consistently work with multiple chunks via CommonsChunkPlugin // default sort mode uses toposort which cannot handle cyclic deps
chunksSortMode: 'dependency' // 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 // keep module.id stable when vender modules does not change
new webpack.HashedModuleIdsPlugin(), 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 // copy custom static assets
new CopyWebpackPlugin([ new CopyWebpackPlugin([
{ {
@@ -146,7 +99,48 @@ const webpackConfig = merge(baseWebpackConfig, {
ignore: ['.*'] 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) { if (config.build.productionGzip) {
@@ -157,9 +151,7 @@ if (config.build.productionGzip) {
asset: '[path].gz[query]', asset: '[path].gz[query]',
algorithm: 'gzip', algorithm: 'gzip',
test: new RegExp( test: new RegExp(
'\\.(' + '\\.(' + config.build.productionGzipExtensions.join('|') + ')$'
config.build.productionGzipExtensions.join('|') +
')$'
), ),
threshold: 10240, threshold: 10240,
minRatio: 0.8 minRatio: 0.8
@@ -167,9 +159,28 @@ if (config.build.productionGzip) {
) )
} }
if (config.build.bundleAnalyzerReport) { if (config.build.generateAnalyzerReport || config.build.bundleAnalyzerReport) {
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin const BundleAnalyzerPlugin = require('webpack-bundle-analyzer')
webpackConfig.plugins.push(new BundleAnalyzerPlugin()) .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 module.exports = webpackConfig

View File

@@ -13,7 +13,10 @@ module.exports = {
proxyTable: {}, proxyTable: {},
// Various Dev Server settings // Various Dev Server settings
host: 'localhost', // can be overwritten by process.env.HOST
// can be overwritten by process.env.HOST
// if you want dev by ip, please set host: '0.0.0.0'
host: 'localhost',
port: 9527, // can be overwritten by process.env.PORT, if port is in use, a free one will be determined port: 9527, // can be overwritten by process.env.PORT, if port is in use, a free one will be determined
autoOpenBrowser: true, autoOpenBrowser: true,
errorOverlay: true, errorOverlay: true,
@@ -33,12 +36,7 @@ module.exports = {
*/ */
// https://webpack.js.org/configuration/devtool/#development // https://webpack.js.org/configuration/devtool/#development
devtool: '#cheap-source-map', 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,
// CSS Sourcemaps off by default because relative paths are "buggy" // CSS Sourcemaps off by default because relative paths are "buggy"
// with this option, according to the CSS-Loader README // with this option, according to the CSS-Loader README
@@ -70,7 +68,7 @@ module.exports = {
*/ */
productionSourceMap: false, productionSourceMap: false,
// https://webpack.js.org/configuration/devtool/#production // https://webpack.js.org/configuration/devtool/#production
devtool: '#source-map', devtool: 'source-map',
// Gzip off by default as many popular static hosts such as // Gzip off by default as many popular static hosts such as
// Surge or Netlify already gzip all static assets for you. // Surge or Netlify already gzip all static assets for you.
@@ -81,8 +79,11 @@ module.exports = {
// Run the build command with an extra argument to // Run the build command with an extra argument to
// View the bundle analyzer report after build finishes: // 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 // 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
} }
} }

View File

@@ -1,6 +1,6 @@
{ {
"name": "vue-element-admin", "name": "vue-element-admin",
"version": "3.7.1", "version": "3.7.3",
"description": "A magical vue admin. Typical templates for enterprise applications. Newest development stack of vue. Lots of awesome features", "description": "A magical vue admin. Typical templates 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",
@@ -9,7 +9,14 @@
"build:prod": "cross-env NODE_ENV=production env_config=prod node build/build.js", "build:prod": "cross-env NODE_ENV=production env_config=prod node build/build.js",
"build:sit": "cross-env NODE_ENV=production env_config=sit node build/build.js", "build:sit": "cross-env NODE_ENV=production env_config=sit node build/build.js",
"lint": "eslint --ext .js,.vue src", "lint": "eslint --ext .js,.vue src",
"test": "npm run lint" "test": "npm run lint",
"precommit": "lint-staged"
},
"lint-staged": {
"src/**/*.{js,vue}": [
"eslint --fix",
"git add"
]
}, },
"keywords": [ "keywords": [
"vue", "vue",
@@ -26,14 +33,15 @@
"url": "https://github.com/PanJiaChen/vue-element-admin/issues" "url": "https://github.com/PanJiaChen/vue-element-admin/issues"
}, },
"dependencies": { "dependencies": {
"axios": "0.17.1", "axios": "0.18.0",
"clipboard": "1.7.1", "clipboard": "1.7.1",
"codemirror": "5.32.0", "codemirror": "5.39.2",
"connect": "3.6.6",
"driver.js": "0.5.2", "driver.js": "0.5.2",
"dropzone": "5.2.0", "dropzone": "5.2.0",
"echarts": "3.8.5", "echarts": "4.1.0",
"element-ui": "2.3.2", "element-ui": "2.4.6",
"file-saver": "1.3.3", "file-saver": "1.3.8",
"font-awesome": "4.7.0", "font-awesome": "4.7.0",
"js-cookie": "2.2.0", "js-cookie": "2.2.0",
"jsonlint": "1.6.3", "jsonlint": "1.6.3",
@@ -42,13 +50,13 @@
"normalize.css": "7.0.0", "normalize.css": "7.0.0",
"nprogress": "0.2.0", "nprogress": "0.2.0",
"screenfull": "3.3.2", "screenfull": "3.3.2",
"showdown": "1.8.5", "showdown": "1.8.6",
"simplemde": "1.11.2", "simplemde": "1.11.2",
"sortablejs": "1.7.0", "sortablejs": "1.7.0",
"vue": "2.5.10", "vue": "2.5.17",
"vue-count-to": "1.0.13", "vue-count-to": "1.0.13",
"vue-i18n": "7.3.2", "vue-i18n": "7.3.2",
"vue-multiselect": "2.0.8", "vue-multiselect": "2.1.0",
"vue-router": "3.0.1", "vue-router": "3.0.1",
"vue-splitpane": "1.0.2", "vue-splitpane": "1.0.2",
"vuedraggable": "^2.16.0", "vuedraggable": "^2.16.0",
@@ -56,56 +64,61 @@
"xlsx": "^0.11.16" "xlsx": "^0.11.16"
}, },
"devDependencies": { "devDependencies": {
"autoprefixer": "7.2.3", "autoprefixer": "8.5.0",
"babel-core": "6.26.0", "babel-core": "6.26.3",
"babel-eslint": "8.0.3", "babel-eslint": "8.2.6",
"babel-helper-vue-jsx-merge-props": "2.0.3", "babel-helper-vue-jsx-merge-props": "2.0.3",
"babel-loader": "7.1.2", "babel-loader": "7.1.5",
"babel-plugin-dynamic-import-node": "^1.2.0", "babel-plugin-dynamic-import-node": "2.0.0",
"babel-plugin-syntax-jsx": "6.18.0", "babel-plugin-syntax-jsx": "6.18.0",
"babel-plugin-transform-runtime": "6.23.0", "babel-plugin-transform-runtime": "6.23.0",
"babel-plugin-transform-vue-jsx": "3.5.0", "babel-plugin-transform-vue-jsx": "3.7.0",
"babel-preset-env": "1.6.1", "babel-preset-env": "1.7.0",
"babel-preset-stage-2": "6.24.1", "babel-preset-stage-2": "6.24.1",
"chalk": "2.3.0", "chalk": "2.4.1",
"copy-webpack-plugin": "4.3.0", "copy-webpack-plugin": "4.5.2",
"cross-env": "5.1.1", "cross-env": "5.2.0",
"css-loader": "0.28.7", "css-loader": "1.0.0",
"eslint": "4.13.1", "eslint": "4.19.1",
"eslint-friendly-formatter": "3.0.0", "eslint-friendly-formatter": "4.0.1",
"eslint-loader": "1.9.0", "eslint-loader": "2.0.0",
"eslint-plugin-html": "4.0.1", "eslint-plugin-html": "4.0.5",
"extract-text-webpack-plugin": "3.0.2", "file-loader": "1.1.11",
"file-loader": "1.1.5", "friendly-errors-webpack-plugin": "1.7.0",
"friendly-errors-webpack-plugin": "1.6.1", "hash-sum": "^1.0.2",
"html-webpack-plugin": "2.30.1", "html-webpack-plugin": "^4.0.0-alpha",
"node-notifier": "5.1.2", "husky": "0.14.3",
"lint-staged": "7.2.2",
"mini-css-extract-plugin": "0.4.1",
"node-notifier": "5.2.1",
"node-sass": "^4.7.2", "node-sass": "^4.7.2",
"optimize-css-assets-webpack-plugin": "3.2.0", "optimize-css-assets-webpack-plugin": "5.0.0",
"ora": "1.3.0", "ora": "3.0.0",
"portfinder": "1.0.13", "portfinder": "1.0.13",
"postcss-import": "11.0.0", "postcss-import": "11.1.0",
"postcss-loader": "2.0.9", "postcss-loader": "2.1.6",
"postcss-url": "7.3.0", "postcss-url": "7.3.2",
"pushstate-server": "3.0.1",
"rimraf": "2.6.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", "script-loader": "0.7.2",
"semver": "5.4.1", "semver": "5.5.0",
"shelljs": "0.7.8", "serve-static": "1.13.2",
"svg-sprite-loader": "3.5.2", "shelljs": "0.8.2",
"uglifyjs-webpack-plugin": "1.1.3", "svg-sprite-loader": "3.8.0",
"url-loader": "0.6.2", "uglifyjs-webpack-plugin": "1.2.7",
"vue-loader": "13.7.2", "url-loader": "1.0.1",
"vue-style-loader": "3.0.3", "vue-loader": "15.3.0",
"vue-template-compiler": "2.5.10", "vue-style-loader": "4.1.2",
"webpack": "3.10.0", "vue-template-compiler": "2.5.17",
"webpack-bundle-analyzer": "2.9.1", "webpack": "4.16.5",
"webpack-dev-server": "2.9.7", "webpack-bundle-analyzer": "2.13.1",
"webpack-merge": "4.1.1" "webpack-cli": "3.1.0",
"webpack-dev-server": "3.1.5",
"webpack-merge": "4.1.4"
}, },
"engines": { "engines": {
"node": ">= 4.0.0", "node": ">= 6.0.0",
"npm": ">= 3.0.0" "npm": ">= 3.0.0"
}, },
"browserslist": [ "browserslist": [

View File

@@ -1,6 +1,6 @@
<template> <template>
<a href="https://github.com/PanJiaChen/vue-element-admin" target="_blank" class="github-corner" aria-label="View source on Github"> <a href="https://github.com/PanJiaChen/vue-element-admin" target="_blank" class="github-corner" aria-label="View source on Github">
<svg width="80" height="80" viewBox="0 0 250 250" style="fill:#40c9c6; color:#fff; position: absolute; top: 84px; border: 0; right: 0;" <svg width="80" height="80" viewBox="0 0 250 250" style="fill:#40c9c6; color:#fff;"
aria-hidden="true"> aria-hidden="true">
<path d="M0,0 L115,115 L130,115 L142,142 L250,250 L250,0 Z"></path> <path d="M0,0 L115,115 L130,115 L142,142 L250,250 L250,0 Z"></path>
<path d="M128.3,109.0 C113.8,99.7 119.0,89.6 119.0,89.6 C122.0,82.7 120.5,78.6 120.5,78.6 C119.2,72.0 123.4,76.3 123.4,76.3 C127.3,80.9 125.5,87.3 125.5,87.3 C122.9,97.6 130.6,101.9 134.4,103.2" <path d="M128.3,109.0 C113.8,99.7 119.0,89.6 119.0,89.6 C122.0,82.7 120.5,78.6 120.5,78.6 C119.2,72.0 123.4,76.3 123.4,76.3 C127.3,80.9 125.5,87.3 125.5,87.3 C122.9,97.6 130.6,101.9 134.4,103.2"

View File

@@ -35,7 +35,7 @@ export default {
</script> </script>
<style rel="stylesheet/scss" lang="scss" > <style rel="stylesheet/scss" lang="scss" >
$n: 6; //和items.length 相同 $n: 8; //和items.length 相同
$t: .1s; $t: .1s;
.share-dropdown-menu { .share-dropdown-menu {
width: 250px; width: 250px;

View File

@@ -23,6 +23,7 @@ export default {
<style> <style>
/* Mallki */ /* Mallki */
.link--mallki { .link--mallki {
font-weight: 800; font-weight: 800;
color: #4dd9d5; color: #4dd9d5;
@@ -31,7 +32,7 @@ export default {
transition: color 0.5s 0.25s; transition: color 0.5s 0.25s;
overflow: hidden; overflow: hidden;
position: relative; position: relative;
display: inline-block; display: inline-block;
line-height: 1; line-height: 1;
outline: none; outline: none;
text-decoration: none; text-decoration: none;
@@ -109,5 +110,4 @@ display: inline-block;
-webkit-transition-timing-function: cubic-bezier(0.2, 1, 0.3, 1); -webkit-transition-timing-function: cubic-bezier(0.2, 1, 0.3, 1);
transition-timing-function: cubic-bezier(0.2, 1, 0.3, 1); transition-timing-function: cubic-bezier(0.2, 1, 0.3, 1);
} }
</style> </style>

View File

@@ -2,7 +2,7 @@
<div class="upload-container"> <div class="upload-container">
<el-button icon='el-icon-upload' size="mini" :style="{background:color,borderColor:color}" @click=" dialogVisible=true" type="primary">上传图片 <el-button icon='el-icon-upload' size="mini" :style="{background:color,borderColor:color}" @click=" dialogVisible=true" type="primary">上传图片
</el-button> </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" <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"> list-type="picture-card" :on-remove="handleRemove" :on-success="handleSuccess" :before-upload="beforeUpload">
<el-button size="small" type="primary">点击上传</el-button> <el-button size="small" type="primary">点击上传</el-button>

View File

@@ -84,6 +84,7 @@ export default {
imagetools_cors_hosts: ['www.tinymce.com', 'codepen.io'], imagetools_cors_hosts: ['www.tinymce.com', 'codepen.io'],
default_link_target: '_blank', default_link_target: '_blank',
link_title: false, link_title: false,
nonbreaking_force_tab: true, // inserting nonbreaking space &nbsp; need Nonbreaking Space Plugin
init_instance_callback: editor => { init_instance_callback: editor => {
if (_this.value) { if (_this.value) {
editor.setContent(_this.value) editor.setContent(_this.value)

View File

@@ -1,7 +1,7 @@
<template> <template>
<div class="upload-container"> <div class="upload-container">
<el-upload class="image-uploader" :data="dataObj" drag :multiple="false" :show-file-list="false" action="https://httpbin.org/post" <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> <i class="el-icon-upload"></i>
<div class="el-upload__text">将文件拖到此处<em>点击上传</em></div> <div class="el-upload__text">将文件拖到此处<em>点击上传</em></div>
</el-upload> </el-upload>
@@ -43,7 +43,7 @@ export default {
emitInput(val) { emitInput(val) {
this.$emit('input', val) this.$emit('input', val)
}, },
handleImageScucess() { handleImageSuccess() {
this.emitInput(this.tempUrl) this.emitInput(this.tempUrl)
}, },
beforeUpload() { beforeUpload() {

View File

@@ -1,7 +1,7 @@
<template> <template>
<div class="singleImageUpload2 upload-container"> <div class="singleImageUpload2 upload-container">
<el-upload class="image-uploader" :data="dataObj" drag :multiple="false" :show-file-list="false" action="https://httpbin.org/post" <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> <i class="el-icon-upload"></i>
<div class="el-upload__text">Drag或<em>点击上传</em></div> <div class="el-upload__text">Drag或<em>点击上传</em></div>
</el-upload> </el-upload>
@@ -42,7 +42,7 @@ export default {
emitInput(val) { emitInput(val) {
this.$emit('input', val) this.$emit('input', val)
}, },
handleImageScucess() { handleImageSuccess() {
this.emitInput(this.tempUrl) this.emitInput(this.tempUrl)
}, },
beforeUpload() { beforeUpload() {

View File

@@ -1,7 +1,7 @@
<template> <template>
<div class="upload-container"> <div class="upload-container">
<el-upload class="image-uploader" :data="dataObj" drag :multiple="false" :show-file-list="false" action="https://httpbin.org/post" <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> <i class="el-icon-upload"></i>
<div class="el-upload__text">将文件拖到此处<em>点击上传</em></div> <div class="el-upload__text">将文件拖到此处<em>点击上传</em></div>
</el-upload> </el-upload>
@@ -50,7 +50,7 @@ export default {
emitInput(val) { emitInput(val) {
this.$emit('input', val) this.$emit('input', val)
}, },
handleImageScucess(file) { handleImageSuccess(file) {
this.emitInput(file.files.file) this.emitInput(file.files.file)
}, },
beforeUpload() { beforeUpload() {

View File

@@ -41,6 +41,11 @@ export default {
return return
} }
const rawFile = files[0] // only use files[0] 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) this.upload(rawFile)
e.stopPropagation() e.stopPropagation()
e.preventDefault() e.preventDefault()
@@ -110,6 +115,9 @@ export default {
headers.push(hdr) headers.push(hdr)
} }
return headers return headers
},
isExcel(file) {
return /\.(xlsx|xls|csv)$/.test(file.name)
} }
} }
} }

View File

@@ -29,8 +29,8 @@ export default{
ripple.style.left = (rect.width / 2 - ripple.offsetWidth / 2) + 'px' ripple.style.left = (rect.width / 2 - ripple.offsetWidth / 2) + 'px'
break break
default: default:
ripple.style.top = (e.pageY - rect.top - ripple.offsetHeight / 2 - document.body.scrollTop) + '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.body.scrollLeft) + 'px' ripple.style.left = (e.pageX - rect.left - ripple.offsetWidth / 2 - document.documentElement.scrollLeft || document.body.scrollLeft) + 'px'
} }
ripple.style.backgroundColor = opts.color ripple.style.backgroundColor = opts.color
ripple.className = 'waves-ripple z-active' ripple.className = 'waves-ripple z-active'

View File

@@ -29,9 +29,13 @@ export default {
mixChart: 'Mix Chart', mixChart: 'Mix Chart',
example: 'Example', example: 'Example',
nested: 'Nested Routes', nested: 'Nested Routes',
bar: 'Bar', menu1: 'Menu 1',
barProfile: 'Profile', 'menu1-1': 'Menu 1-1',
barPosts: 'Posts', 'menu1-2': 'Menu 1-2',
'menu1-2-1': 'Menu 1-2-1',
'menu1-2-2': 'Menu 1-2-2',
'menu1-3': 'Menu 1-3',
menu2: 'Menu 2',
Table: 'Table', Table: 'Table',
dynamicTable: 'Dynamic Table', dynamicTable: 'Dynamic Table',
dragTable: 'Drag Table', dragTable: 'Drag Table',

View File

@@ -20,8 +20,11 @@ const messages = {
} }
const i18n = new VueI18n({ const i18n = new VueI18n({
locale: Cookies.get('language') || 'en', // set locale // set locale
messages // set locale messages // options: en or zh
locale: Cookies.get('language') || 'en',
// set locale messages
messages
}) })
export default i18n export default i18n

View File

@@ -29,9 +29,13 @@ export default {
mixChart: '混合图表', mixChart: '混合图表',
example: '综合实例', example: '综合实例',
nested: '路由嵌套', nested: '路由嵌套',
bar: 'Bar', menu1: '菜单1',
barProfile: 'Profile', 'menu1-1': '菜单1-1',
barPosts: 'Posts', 'menu1-2': '菜单1-2',
'menu1-2-1': '菜单1-2-1',
'menu1-2-2': '菜单1-2-2',
'menu1-3': '菜单1-3',
menu2: '菜单2',
Table: 'Table', Table: 'Table',
dynamicTable: '动态Table', dynamicTable: '动态Table',
dragTable: '拖拽Table', dragTable: '拖拽Table',

View File

@@ -202,7 +202,7 @@ export const asyncRouterMap = [
{ {
path: '/nested', path: '/nested',
component: Layout, component: Layout,
redirect: '/nested/bar/profile', redirect: '/nested/menu1/menu1-1',
name: 'nested', name: 'nested',
meta: { meta: {
title: 'nested', title: 'nested',
@@ -210,24 +210,52 @@ export const asyncRouterMap = [
}, },
children: [ children: [
{ {
path: '/nested/bar', // Must write the full path path: 'menu1',
component: () => import('@/views/nested/bar/index'), // Parent router-view component: () => import('@/views/nested/menu1/index'), // Parent router-view
name: 'bar', name: 'menu1',
meta: { title: 'bar' }, meta: { title: 'menu1' },
redirect: '/nested/menu1/menu1-1',
children: [ children: [
{ {
path: 'profile', path: 'menu1-1',
component: () => import('@/views/nested/bar/profile'), component: () => import('@/views/nested/menu1/menu1-1'),
name: 'bar-profile', name: 'menu1-1',
meta: { title: 'barProfile' } meta: { title: 'menu1-1' }
}, },
{ {
path: 'posts', path: 'menu1-2',
component: () => import('@/views/nested/bar/posts'), component: () => import('@/views/nested/menu1/menu1-2'),
name: 'bar-posts', name: 'menu1-2',
meta: { title: 'barPosts' } 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' }
} }
] ]
}, },

View File

@@ -38,7 +38,7 @@ const tagsView = {
for (const i of state.cachedViews) { for (const i of state.cachedViews) {
if (i === view.name) { if (i === view.name) {
const index = state.cachedViews.indexOf(i) const index = state.cachedViews.indexOf(i)
state.cachedViews = state.cachedViews.slice(index, i + 1) state.cachedViews = state.cachedViews.slice(index, index + 1)
break break
} }
} }

View File

@@ -4,6 +4,7 @@
min-height: 100%; min-height: 100%;
transition: margin-left .28s; transition: margin-left .28s;
margin-left: 180px; margin-left: 180px;
position: relative;
} }
// 侧边栏 // 侧边栏
.sidebar-container { .sidebar-container {

89
src/vendor/Blob.js vendored
View File

@@ -29,41 +29,41 @@
// Internally we use a BlobBuilder implementation to base Blob off of // Internally we use a BlobBuilder implementation to base Blob off of
// in order to support older browsers that only have BlobBuilder // in order to support older browsers that only have BlobBuilder
var BlobBuilder = view.BlobBuilder || view.WebKitBlobBuilder || view.MozBlobBuilder || (function(view) { var BlobBuilder = view.BlobBuilder || view.WebKitBlobBuilder || view.MozBlobBuilder || (function (view) {
var var
get_class = function(object) { get_class = function (object) {
return Object.prototype.toString.call(object).match(/^\[object\s(.*)\]$/)[1]; return Object.prototype.toString.call(object).match(/^\[object\s(.*)\]$/)[1];
} },
, FakeBlobBuilder = function BlobBuilder() { FakeBlobBuilder = function BlobBuilder() {
this.data = []; this.data = [];
} },
, FakeBlob = function Blob(data, type, encoding) { FakeBlob = function Blob(data, type, encoding) {
this.data = data; this.data = data;
this.size = data.length; this.size = data.length;
this.type = type; this.type = type;
this.encoding = encoding; this.encoding = encoding;
} },
, FBB_proto = FakeBlobBuilder.prototype FBB_proto = FakeBlobBuilder.prototype,
, FB_proto = FakeBlob.prototype FB_proto = FakeBlob.prototype,
, FileReaderSync = view.FileReaderSync FileReaderSync = view.FileReaderSync,
, FileException = function(type) { FileException = function (type) {
this.code = this[this.name = type]; this.code = this[this.name = type];
} },
, file_ex_codes = ( file_ex_codes = (
"NOT_FOUND_ERR SECURITY_ERR ABORT_ERR NOT_READABLE_ERR ENCODING_ERR " "NOT_FOUND_ERR SECURITY_ERR ABORT_ERR NOT_READABLE_ERR ENCODING_ERR " +
+ "NO_MODIFICATION_ALLOWED_ERR INVALID_STATE_ERR SYNTAX_ERR" "NO_MODIFICATION_ALLOWED_ERR INVALID_STATE_ERR SYNTAX_ERR"
).split(" ") ).split(" "),
, file_ex_code = file_ex_codes.length file_ex_code = file_ex_codes.length,
, real_URL = view.URL || view.webkitURL || view real_URL = view.URL || view.webkitURL || view,
, real_create_object_URL = real_URL.createObjectURL real_create_object_URL = real_URL.createObjectURL,
, real_revoke_object_URL = real_URL.revokeObjectURL real_revoke_object_URL = real_URL.revokeObjectURL,
, URL = real_URL URL = real_URL,
, btoa = view.btoa btoa = view.btoa,
, atob = view.atob atob = view.atob
, ArrayBuffer = view.ArrayBuffer ,
, Uint8Array = view.Uint8Array ArrayBuffer = view.ArrayBuffer,
; Uint8Array = view.Uint8Array;
FakeBlob.fake = FB_proto.fake = true; FakeBlob.fake = FB_proto.fake = true;
while (file_ex_code--) { while (file_ex_code--) {
FileException.prototype[file_ex_codes[file_ex_code]] = file_ex_code + 1; FileException.prototype[file_ex_codes[file_ex_code]] = file_ex_code + 1;
@@ -71,11 +71,10 @@
if (!real_URL.createObjectURL) { if (!real_URL.createObjectURL) {
URL = view.URL = {}; URL = view.URL = {};
} }
URL.createObjectURL = function(blob) { URL.createObjectURL = function (blob) {
var var
type = blob.type type = blob.type,
, data_URI_header data_URI_header;
;
if (type === null) { if (type === null) {
type = "application/octet-stream"; type = "application/octet-stream";
} }
@@ -85,7 +84,8 @@
return data_URI_header + ";base64," + blob.data; return data_URI_header + ";base64," + blob.data;
} else if (blob.encoding === "URI") { } else if (blob.encoding === "URI") {
return data_URI_header + "," + decodeURIComponent(blob.data); return data_URI_header + "," + decodeURIComponent(blob.data);
} if (btoa) { }
if (btoa) {
return data_URI_header + ";base64," + btoa(blob.data); return data_URI_header + ";base64," + btoa(blob.data);
} else { } else {
return data_URI_header + "," + encodeURIComponent(blob.data); return data_URI_header + "," + encodeURIComponent(blob.data);
@@ -94,21 +94,20 @@
return real_create_object_URL.call(real_URL, blob); return real_create_object_URL.call(real_URL, blob);
} }
}; };
URL.revokeObjectURL = function(object_URL) { URL.revokeObjectURL = function (object_URL) {
if (object_URL.substring(0, 5) !== "data:" && real_revoke_object_URL) { if (object_URL.substring(0, 5) !== "data:" && real_revoke_object_URL) {
real_revoke_object_URL.call(real_URL, object_URL); real_revoke_object_URL.call(real_URL, object_URL);
} }
}; };
FBB_proto.append = function(data/*, endings*/) { FBB_proto.append = function (data /*, endings*/ ) {
var bb = this.data; var bb = this.data;
// decode data to a binary string // decode data to a binary string
if (Uint8Array && (data instanceof ArrayBuffer || data instanceof Uint8Array)) { if (Uint8Array && (data instanceof ArrayBuffer || data instanceof Uint8Array)) {
var var
str = "" str = "",
, buf = new Uint8Array(data) buf = new Uint8Array(data),
, i = 0 i = 0,
, buf_len = buf.length buf_len = buf.length;
;
for (; i < buf_len; i++) { for (; i < buf_len; i++) {
str += String.fromCharCode(buf[i]); str += String.fromCharCode(buf[i]);
} }
@@ -137,30 +136,28 @@
bb.push(unescape(encodeURIComponent(data))); bb.push(unescape(encodeURIComponent(data)));
} }
}; };
FBB_proto.getBlob = function(type) { FBB_proto.getBlob = function (type) {
if (!arguments.length) { if (!arguments.length) {
type = null; type = null;
} }
return new FakeBlob(this.data.join(""), type, "raw"); return new FakeBlob(this.data.join(""), type, "raw");
}; };
FBB_proto.toString = function() { FBB_proto.toString = function () {
return "[object BlobBuilder]"; return "[object BlobBuilder]";
}; };
FB_proto.slice = function(start, end, type) { FB_proto.slice = function (start, end, type) {
var args = arguments.length; var args = arguments.length;
if (args < 3) { if (args < 3) {
type = null; type = null;
} }
return new FakeBlob( return new FakeBlob(
this.data.slice(start, args > 1 ? end : this.data.length) this.data.slice(start, args > 1 ? end : this.data.length), type, this.encoding
, type
, this.encoding
); );
}; };
FB_proto.toString = function() { FB_proto.toString = function () {
return "[object Blob]"; return "[object Blob]";
}; };
FB_proto.close = function() { FB_proto.close = function () {
this.size = this.data.length = 0; this.size = this.data.length = 0;
}; };
return FakeBlobBuilder; return FakeBlobBuilder;

View File

@@ -29,15 +29,24 @@ function generateArray(table) {
if (rowspan || colspan) { if (rowspan || colspan) {
rowspan = rowspan || 1; rowspan = rowspan || 1;
colspan = colspan || 1; colspan = colspan || 1;
ranges.push({s: {r: R, c: outRow.length}, e: {r: R + rowspan - 1, c: outRow.length + colspan - 1}}); ranges.push({
s: {
r: R,
c: outRow.length
},
e: {
r: R + rowspan - 1,
c: outRow.length + colspan - 1
} }
; });
};
//Handle Value //Handle Value
outRow.push(cellValue !== "" ? cellValue : null); outRow.push(cellValue !== "" ? cellValue : null);
//Handle Colspan //Handle Colspan
if (colspan) for (var k = 0; k < colspan - 1; ++k) outRow.push(null); if (colspan)
for (var k = 0; k < colspan - 1; ++k) outRow.push(null);
} }
out.push(outRow); out.push(outRow);
} }
@@ -52,16 +61,30 @@ function datenum(v, date1904) {
function sheet_from_array_of_arrays(data, opts) { function sheet_from_array_of_arrays(data, opts) {
var ws = {}; var ws = {};
var range = {s: {c: 10000000, r: 10000000}, e: {c: 0, r: 0}}; var range = {
s: {
c: 10000000,
r: 10000000
},
e: {
c: 0,
r: 0
}
};
for (var R = 0; R != data.length; ++R) { for (var R = 0; R != data.length; ++R) {
for (var C = 0; C != data[R].length; ++C) { for (var C = 0; C != data[R].length; ++C) {
if (range.s.r > R) range.s.r = R; if (range.s.r > R) range.s.r = R;
if (range.s.c > C) range.s.c = C; if (range.s.c > C) range.s.c = C;
if (range.e.r < R) range.e.r = R; if (range.e.r < R) range.e.r = R;
if (range.e.c < C) range.e.c = C; if (range.e.c < C) range.e.c = C;
var cell = {v: data[R][C]}; var cell = {
v: data[R][C]
};
if (cell.v == null) continue; if (cell.v == null) continue;
var cell_ref = XLSX.utils.encode_cell({c: C, r: R}); var cell_ref = XLSX.utils.encode_cell({
c: C,
r: R
});
if (typeof cell.v === 'number') cell.t = 'n'; if (typeof cell.v === 'number') cell.t = 'n';
else if (typeof cell.v === 'boolean') cell.t = 'b'; else if (typeof cell.v === 'boolean') cell.t = 'b';
@@ -69,8 +92,7 @@ function sheet_from_array_of_arrays(data, opts) {
cell.t = 'n'; cell.t = 'n';
cell.z = XLSX.SSF._table[14]; cell.z = XLSX.SSF._table[14];
cell.v = datenum(cell.v); cell.v = datenum(cell.v);
} } else cell.t = 's';
else cell.t = 's';
ws[cell_ref] = cell; ws[cell_ref] = cell;
} }
@@ -101,7 +123,8 @@ export function export_table_to_excel(id) {
var data = oo[0]; var data = oo[0];
var ws_name = "SheetJS"; var ws_name = "SheetJS";
var wb = new Workbook(), ws = sheet_from_array_of_arrays(data); var wb = new Workbook(),
ws = sheet_from_array_of_arrays(data);
/* add ranges to worksheet */ /* add ranges to worksheet */
// ws['!cols'] = ['apple', 'banan']; // ws['!cols'] = ['apple', 'banan'];
@@ -111,30 +134,49 @@ export function export_table_to_excel(id) {
wb.SheetNames.push(ws_name); wb.SheetNames.push(ws_name);
wb.Sheets[ws_name] = ws; wb.Sheets[ws_name] = ws;
var wbout = XLSX.write(wb, {bookType: 'xlsx', bookSST: false, type: 'binary'}); var wbout = XLSX.write(wb, {
bookType: 'xlsx',
bookSST: false,
type: 'binary'
});
saveAs(new Blob([s2ab(wbout)], {type: "application/octet-stream"}), "test.xlsx") saveAs(new Blob([s2ab(wbout)], {
type: "application/octet-stream"
}), "test.xlsx")
} }
export function export_json_to_excel({header, data, filename='excel-list', autoWidth=true}={}) { export function export_json_to_excel({
header,
data,
filename,
autoWidth = true
} = {}) {
/* original data */ /* original data */
data=[...data] filename = filename || 'excel-list'
data = [...data]
data.unshift(header); data.unshift(header);
var ws_name = "SheetJS"; var ws_name = "SheetJS";
var wb = new Workbook(), ws = sheet_from_array_of_arrays(data); var wb = new Workbook(),
ws = sheet_from_array_of_arrays(data);
if(autoWidth){ if (autoWidth) {
/*设置worksheet每列的最大宽度*/ /*设置worksheet每列的最大宽度*/
const colWidth = data.map(row => row.map(val => { const colWidth = data.map(row => row.map(val => {
/*先判断是否为null/undefined*/ /*先判断是否为null/undefined*/
if (val == null) { if (val == null) {
return {'wch': 10}; return {
'wch': 10
};
} }
/*再判断是否为中文*/ /*再判断是否为中文*/
else if (val.toString().charCodeAt(0) > 255) { else if (val.toString().charCodeAt(0) > 255) {
return {'wch': val.toString().length * 2}; return {
'wch': val.toString().length * 2
};
} else { } else {
return {'wch': val.toString().length}; return {
'wch': val.toString().length
};
} }
})) }))
/*以第一行为初始值*/ /*以第一行为初始值*/
@@ -153,6 +195,12 @@ export function export_json_to_excel({header, data, filename='excel-list', autoW
wb.SheetNames.push(ws_name); wb.SheetNames.push(ws_name);
wb.Sheets[ws_name] = ws; wb.Sheets[ws_name] = ws;
var wbout = XLSX.write(wb, {bookType: 'xlsx', bookSST: false, type: 'binary'}); var wbout = XLSX.write(wb, {
saveAs(new Blob([s2ab(wbout)], {type: "application/octet-stream"}), filename + ".xlsx"); bookType: 'xlsx',
bookSST: false,
type: 'binary'
});
saveAs(new Blob([s2ab(wbout)], {
type: "application/octet-stream"
}), filename + ".xlsx");
} }

View File

@@ -14,7 +14,9 @@ export function export_txt_to_zip(th, jsonData, txtName, zipName) {
txtData += `${tempStr}\r\n` txtData += `${tempStr}\r\n`
}) })
zip.file(`${txt_name}.txt`, txtData) zip.file(`${txt_name}.txt`, txtData)
zip.generateAsync({type:"blob"}).then((blob) => { zip.generateAsync({
type: "blob"
}).then((blob) => {
saveAs(blob, `${zip_name}.zip`) saveAs(blob, `${zip_name}.zip`)
}, (err) => { }, (err) => {
alert('导出失败') alert('导出失败')

View File

@@ -34,7 +34,7 @@ export default {
}, },
clipboardSuccess() { clipboardSuccess() {
this.$message({ this.$message({
message: '复制成功', message: 'Copy successfully',
type: 'success', type: 'success',
duration: 1500 duration: 1500
}) })

View File

@@ -2,7 +2,7 @@
<div class="components-container"> <div class="components-container">
<code>Markdown is based on <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 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> 相关文章 </a>
</code> </code>
<div class="editor-container"> <div class="editor-container">

View File

@@ -7,19 +7,19 @@
</div> </div>
<div style="margin-bottom:50px;"> <div style="margin-bottom:50px;">
<el-col :span="4" class="text-center"> <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>
<el-col :span="4" class="text-center"> <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>
<el-col :span="4" class="text-center"> <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>
<el-col :span="4" class="text-center"> <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>
<el-col :span="4" class="text-center"> <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>
<el-col :span="4" class="text-center"> <el-col :span="4" class="text-center">
<router-link class="pan-btn yellow-btn" to="/theme/index">Theme</router-link> <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 }] title: [{ required: true, trigger: 'change', validator: validate }]
}, },
articleList: [ articleList: [
{ title: '基础篇', href: 'https://segmentfault.com/a/1190000009275424' }, { title: '基础篇', href: 'https://juejin.im/post/59097cd7a22b9d0065fb61d2' },
{ title: '登录权限篇', href: 'https://segmentfault.com/a/1190000009506097' }, { title: '登录权限篇', href: 'https://juejin.im/post/591aa14f570c35006961acac' },
{ title: '实战篇', href: 'https://segmentfault.com/a/1190000009762198' }, { title: '实战篇', href: 'https://juejin.im/post/593121aa0ce4630057f70d35' },
{ title: 'vueAdmin-template 篇', href: 'https://segmentfault.com/a/1190000010043013' }, { title: 'vueAdmin-template 篇', href: 'https://juejin.im/post/595b4d776fb9a06bbe7dba56' },
{ title: '自行封装 component', href: 'https://segmentfault.com/a/1190000009090836' }, { 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' }
] ]
} }
} }

View File

@@ -72,7 +72,7 @@ export default {
} }
}, },
methods: { methods: {
setLocalStorgae() { setLocalStorage() {
window.localStorage.setItem(STORAGE_KEY, JSON.stringify(this.todos)) window.localStorage.setItem(STORAGE_KEY, JSON.stringify(this.todos))
}, },
addTodo(e) { addTodo(e) {
@@ -82,30 +82,30 @@ export default {
text, text,
done: false done: false
}) })
this.setLocalStorgae() this.setLocalStorage()
} }
e.target.value = '' e.target.value = ''
}, },
toggleTodo(val) { toggleTodo(val) {
val.done = !val.done val.done = !val.done
this.setLocalStorgae() this.setLocalStorage()
}, },
deleteTodo(todo) { deleteTodo(todo) {
this.todos.splice(this.todos.indexOf(todo), 1) this.todos.splice(this.todos.indexOf(todo), 1)
this.setLocalStorgae() this.setLocalStorage()
}, },
editTodo({ todo, value }) { editTodo({ todo, value }) {
todo.text = value todo.text = value
this.setLocalStorgae() this.setLocalStorage()
}, },
clearCompleted() { clearCompleted() {
this.todos = this.todos.filter(todo => !todo.done) this.todos = this.todos.filter(todo => !todo.done)
this.setLocalStorgae() this.setLocalStorage()
}, },
toggleAll({ done }) { toggleAll({ done }) {
this.todos.forEach(todo => { this.todos.forEach(todo => {
todo.done = done todo.done = done
this.setLocalStorgae() this.setLocalStorage()
}) })
} }
}, },

View File

@@ -2,7 +2,7 @@
<el-table :data="list" style="width: 100%;padding-top: 15px;"> <el-table :data="list" style="width: 100%;padding-top: 15px;">
<el-table-column label="Order_No" min-width="200"> <el-table-column label="Order_No" min-width="200">
<template slot-scope="scope"> <template slot-scope="scope">
{{scope.row.order_no}} {{scope.row.order_no | orderNoFilter}}
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="Price" width="195" align="center"> <el-table-column label="Price" width="195" align="center">
@@ -34,6 +34,9 @@ export default {
pending: 'danger' pending: 'danger'
} }
return statusMap[status] return statusMap[status]
},
orderNoFilter(str) {
return str.substring(0, 30)
} }
}, },
created() { created() {

View File

@@ -1,6 +1,7 @@
<template> <template>
<div class="dashboard-editor-container"> <div class="dashboard-editor-container">
<github-corner></github-corner>
<github-corner style="position: absolute; top: 0px; border: 0; right: 0;"></github-corner>
<panel-group @handleSetLineChartData="handleSetLineChartData"></panel-group> <panel-group @handleSetLineChartData="handleSetLineChartData"></panel-group>
@@ -30,10 +31,10 @@
<el-col :xs="{span: 24}" :sm="{span: 24}" :md="{span: 24}" :lg="{span: 12}" :xl="{span: 12}" style="padding-right:8px;margin-bottom:30px;"> <el-col :xs="{span: 24}" :sm="{span: 24}" :md="{span: 24}" :lg="{span: 12}" :xl="{span: 12}" style="padding-right:8px;margin-bottom:30px;">
<transaction-table></transaction-table> <transaction-table></transaction-table>
</el-col> </el-col>
<el-col :xs="{span: 24}" :sm="{span: 12}" :md="{span: 12}" :lg="{span: 6}" :xl="{span: 5}" style="margin-bottom:30px;"> <el-col :xs="{span: 24}" :sm="{span: 12}" :md="{span: 12}" :lg="{span: 6}" :xl="{span: 6}" style="margin-bottom:30px;">
<todo-list></todo-list> <todo-list></todo-list>
</el-col> </el-col>
<el-col :xs="{span: 24}" :sm="{span: 12}" :md="{span: 12}" :lg="{span: 6}" :xl="{span: 5}" style="margin-bottom:30px;" > <el-col :xs="{span: 24}" :sm="{span: 12}" :md="{span: 12}" :lg="{span: 6}" :xl="{span: 6}" style="margin-bottom:30px;">
<box-card></box-card> <box-card></box-card>
</el-col> </el-col>
</el-row> </el-row>
@@ -41,6 +42,7 @@
</div> </div>
</template> </template>
<script> <script>
import GithubCorner from '@/components/GithubCorner' import GithubCorner from '@/components/GithubCorner'
import PanelGroup from './components/PanelGroup' import PanelGroup from './components/PanelGroup'

View File

@@ -4,10 +4,10 @@
<pan-thumb style="float: left" :image="avatar"> Your roles: <pan-thumb style="float: left" :image="avatar"> Your roles:
<span class="pan-info-roles" :key='item' v-for="item in roles">{{item}}</span> <span class="pan-info-roles" :key='item' v-for="item in roles">{{item}}</span>
</pan-thumb> </pan-thumb>
<github-corner></github-corner> <github-corner style="position: absolute; top: 0px; border: 0; right: 0;"></github-corner>
<div class="info-container"> <div class="info-container">
<span class="display_name">{{name}}</span> <span class="display_name">{{name}}</span>
<span style="font-size:20px;padding-top:20px;display:inline-block;">editor : dashboard</span> <span style="font-size:20px;padding-top:20px;display:inline-block;">Editor's Dashboard</span>
</div> </div>
</div> </div>
<div> <div>

View File

@@ -14,12 +14,14 @@ export default {
data() { data() {
return { return {
articleList: [ articleList: [
{ title: '基础篇', href: 'https://segmentfault.com/a/1190000009275424' }, { title: '基础篇', href: 'https://juejin.im/post/59097cd7a22b9d0065fb61d2' },
{ title: '登录权限篇', href: 'https://segmentfault.com/a/1190000009506097' }, { title: '登录权限篇', href: 'https://juejin.im/post/591aa14f570c35006961acac' },
{ title: '实战篇', href: 'https://segmentfault.com/a/1190000009762198' }, { title: '实战篇', href: 'https://juejin.im/post/593121aa0ce4630057f70d35' },
{ title: 'vueAdmin-template 篇', href: 'https://segmentfault.com/a/1190000010043013' }, { title: 'vueAdmin-template 篇', href: 'https://juejin.im/post/595b4d776fb9a06bbe7dba56' },
{ title: '自行封装 component', href: 'https://segmentfault.com/a/1190000009090836' }, { 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' }
] ]
} }
} }

View File

@@ -57,6 +57,7 @@ export default {
.pan-back-btn { .pan-back-btn {
background: #008489; background: #008489;
color: #fff; color: #fff;
border: none!important;
} }
.pan-gif { .pan-gif {
margin: 0 auto; margin: 0 auto;

View File

@@ -1,11 +1,11 @@
<template> <template>
<div style="background:#f0f2f5;margin-top: -20px;height:100%;"> <div class="wscn-http404-container">
<div class="wscn-http404"> <div class="wscn-http404">
<div class="pic-404"> <div class="pic-404">
<img class="pic-404__parent" :src="img_404" alt="404"> <img class="pic-404__parent" src="@/assets/404_images/404.png" alt="404">
<img class="pic-404__child left" :src="img_404_cloud" alt="404"> <img class="pic-404__child left" src="@/assets/404_images/404_cloud.png" alt="404">
<img class="pic-404__child mid" :src="img_404_cloud" alt="404"> <img class="pic-404__child mid" src="@/assets/404_images/404_cloud.png" alt="404">
<img class="pic-404__child right" :src="img_404_cloud" alt="404"> <img class="pic-404__child right" src="@/assets/404_images/404_cloud.png" alt="404">
</div> </div>
<div class="bullshit"> <div class="bullshit">
<div class="bullshit__oops">OOPS!</div> <div class="bullshit__oops">OOPS!</div>
@@ -21,37 +21,33 @@
</template> </template>
<script> <script>
import img_404 from '@/assets/404_images/404.png'
import img_404_cloud from '@/assets/404_images/404_cloud.png'
export default { export default {
name: 'page404', name: 'page404',
data() {
return {
img_404,
img_404_cloud
}
},
computed: { computed: {
message() { message() {
return '特朗普说这个页面你不能进......' return '网管说这个页面你不能进......'
} }
} }
} }
</script> </script>
<style rel="stylesheet/scss" lang="scss" scoped> <style rel="stylesheet/scss" lang="scss" scoped>
.wscn-http404-container{
transform: translate(-50%,-50%);
position: absolute;
top: 40%;
left: 50%;
}
.wscn-http404 { .wscn-http404 {
position: relative; position: relative;
width: 1200px; width: 1200px;
margin: 20px auto 60px; padding: 0 50px;
padding: 0 100px;
overflow: hidden; overflow: hidden;
.pic-404 { .pic-404 {
position: relative; position: relative;
float: left; float: left;
width: 600px; width: 600px;
padding: 150px 0;
overflow: hidden; overflow: hidden;
&__parent { &__parent {
width: 100%; width: 100%;
@@ -163,7 +159,7 @@ export default {
position: relative; position: relative;
float: left; float: left;
width: 300px; width: 300px;
padding: 150px 0; padding: 30px 0;
overflow: hidden; overflow: hidden;
&__oops { &__oops {
font-size: 32px; font-size: 32px;
@@ -179,7 +175,8 @@ export default {
&__headline { &__headline {
font-size: 20px; font-size: 20px;
line-height: 24px; line-height: 24px;
color: #1482f0; color: #222;
font-weight: bold;
opacity: 0; opacity: 0;
margin-bottom: 10px; margin-bottom: 10px;
animation-name: slideUp; animation-name: slideUp;

View File

@@ -16,7 +16,7 @@
<Warning /> <Warning />
<el-col :span="21"> <el-col :span="24">
<el-form-item style="margin-bottom: 40px;" prop="title"> <el-form-item style="margin-bottom: 40px;" prop="title">
<MDinput name="name" v-model="postForm.title" required :maxlength="100"> <MDinput name="name" v-model="postForm.title" required :maxlength="100">
标题 标题
@@ -34,14 +34,14 @@
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="8"> <el-col :span="10">
<el-form-item label-width="80px" label="发布时间:" class="postInfo-container-item"> <el-form-item label-width="80px" label="发布时间:" 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="选择日期时间">
</el-date-picker> </el-date-picker>
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="8"> <el-col :span="6">
<el-form-item label-width="60px" label="重要性:" class="postInfo-container-item"> <el-form-item label-width="60px" label="重要性:" class="postInfo-container-item">
<el-rate style="margin-top:8px;" v-model="postForm.importance" :max='3' :colors="['#99A9BF', '#F7BA2A', '#FF9900']" :low-threshold="1" <el-rate style="margin-top:8px;" v-model="postForm.importance" :max='3' :colors="['#99A9BF', '#F7BA2A', '#FF9900']" :low-threshold="1"
:high-threshold="3"> :high-threshold="3">

View File

@@ -22,13 +22,14 @@ export default {
}, },
methods: { methods: {
beforeUpload(file) { beforeUpload(file) {
const isLt2M = file.size / 1024 / 1024 < 1 const isLt1M = file.size / 1024 / 1024 < 1
if (isLt2M) { if (isLt1M) {
return true return true
} }
this.$message({ this.$message({
message: 'Please do not upload files larger than 2m in size.', message: 'Please do not upload files larger than 1m in size.',
type: 'warning' type: 'warning'
}) })
return false return false

View File

@@ -33,6 +33,7 @@ export default {
classObj() { classObj() {
return { return {
hideSidebar: !this.sidebar.opened, hideSidebar: !this.sidebar.opened,
openSidebar: this.sidebar.opened,
withoutAnimation: this.sidebar.withoutAnimation, withoutAnimation: this.sidebar.withoutAnimation,
mobile: this.device === 'mobile' mobile: this.device === 'mobile'
} }
@@ -53,6 +54,10 @@ export default {
position: relative; position: relative;
height: 100%; height: 100%;
width: 100%; width: 100%;
&.mobile.openSidebar{
position: fixed;
top: 0;
}
} }
.drawer-bg { .drawer-bg {
background: #000; background: #000;

View File

@@ -1,5 +1,5 @@
<template> <template>
<section class="app-main" style="min-height: 100%"> <section class="app-main">
<transition name="fade-transform" mode="out-in"> <transition name="fade-transform" mode="out-in">
<keep-alive :include="cachedViews"> <keep-alive :include="cachedViews">
<router-view :key="key"></router-view> <router-view :key="key"></router-view>
@@ -21,3 +21,13 @@ export default {
} }
} }
</script> </script>
<style scoped>
.app-main {
/*84 = navbar + tags-view = 50 +34 */
min-height: calc(100vh - 84px);
position: relative;
overflow: hidden;
}
</style>

View File

@@ -1,26 +1,24 @@
<template> <template>
<div class="menu-wrapper"> <div v-if="!item.hidden&&item.children" class="menu-wrapper">
<template v-for="item in routes" v-if="!item.hidden&&item.children">
<router-link v-if="hasOneShowingChildren(item.children) && !item.children[0].children&&!item.alwaysShow" :to="item.path+'/'+item.children[0].path" <router-link v-if="hasOneShowingChild(item.children) && !onlyOneChild.children&&!item.alwaysShow" :to="resolvePath(onlyOneChild.path)">
:key="item.children[0].name"> <el-menu-item :index="resolvePath(onlyOneChild.path)" :class="{'submenu-title-noDropdown':!isNest}">
<el-menu-item :index="item.path+'/'+item.children[0].path" :class="{'submenu-title-noDropdown':!isNest}"> <svg-icon v-if="onlyOneChild.meta&&onlyOneChild.meta.icon" :icon-class="onlyOneChild.meta.icon"></svg-icon>
<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="onlyOneChild.meta&&onlyOneChild.meta.title" slot="title">{{generateTitle(onlyOneChild.meta.title)}}</span>
<span v-if="item.children[0].meta&&item.children[0].meta.title" slot="title">{{generateTitle(item.children[0].meta.title)}}</span>
</el-menu-item> </el-menu-item>
</router-link> </router-link>
<el-submenu v-else :index="item.name||item.path" :key="item.name"> <el-submenu v-else :index="item.name||item.path">
<template slot="title"> <template slot="title">
<svg-icon v-if="item.meta&&item.meta.icon" :icon-class="item.meta.icon"></svg-icon> <svg-icon v-if="item.meta&&item.meta.icon" :icon-class="item.meta.icon"></svg-icon>
<span v-if="item.meta&&item.meta.title" slot="title">{{generateTitle(item.meta.title)}}</span> <span v-if="item.meta&&item.meta.title" slot="title">{{generateTitle(item.meta.title)}}</span>
</template> </template>
<template v-for="child in item.children" v-if="!child.hidden"> <template v-for="child in item.children" v-if="!child.hidden">
<sidebar-item :is-nest="true" class="nest-menu" v-if="child.children&&child.children.length>0" :routes="[child]" :key="child.path"></sidebar-item> <sidebar-item :is-nest="true" class="nest-menu" v-if="child.children&&child.children.length>0" :item="child" :key="child.path" :base-path="resolvePath(child.path)"></sidebar-item>
<router-link v-else :to="item.path+'/'+child.path" :key="child.name"> <router-link v-else :to="resolvePath(child.path)" :key="child.name">
<el-menu-item :index="item.path+'/'+child.path"> <el-menu-item :index="resolvePath(child.path)">
<svg-icon v-if="child.meta&&child.meta.icon" :icon-class="child.meta.icon"></svg-icon> <svg-icon v-if="child.meta&&child.meta.icon" :icon-class="child.meta.icon"></svg-icon>
<span v-if="child.meta&&child.meta.title" slot="title">{{generateTitle(child.meta.title)}}</span> <span v-if="child.meta&&child.meta.title" slot="title">{{generateTitle(child.meta.title)}}</span>
</el-menu-item> </el-menu-item>
@@ -28,34 +26,54 @@
</template> </template>
</el-submenu> </el-submenu>
</template>
</div> </div>
</template> </template>
<script> <script>
import path from 'path'
import { generateTitle } from '@/utils/i18n' import { generateTitle } from '@/utils/i18n'
export default { export default {
name: 'SidebarItem', name: 'SidebarItem',
props: { props: {
routes: { // route object
type: Array item: {
type: Object,
required: true
}, },
isNest: { isNest: {
type: Boolean, type: Boolean,
default: false default: false
},
basePath: {
type: String,
default: ''
}
},
data() {
return {
onlyOneChild: null
} }
}, },
methods: { methods: {
hasOneShowingChildren(children) { hasOneShowingChild(children) {
const showingChildren = children.filter(item => { 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) { if (showingChildren.length === 1) {
return true return true
} }
return false return false
}, },
resolvePath(...paths) {
return path.resolve(this.basePath, ...paths)
},
generateTitle generateTitle
} }
} }

View File

@@ -9,7 +9,7 @@
text-color="#bfcbd9" text-color="#bfcbd9"
active-text-color="#409EFF" active-text-color="#409EFF"
> >
<sidebar-item :routes="permission_routers"></sidebar-item> <sidebar-item v-for="route in permission_routers" :key="route.name" :item="route" :base-path="route.path"></sidebar-item>
</el-menu> </el-menu>
</el-scrollbar> </el-scrollbar>
</template> </template>

View File

@@ -104,7 +104,8 @@ export default {
openMenu(tag, e) { openMenu(tag, e) {
this.visible = true this.visible = true
this.selectedTag = tag this.selectedTag = tag
this.left = e.clientX const offsetLeft = this.$el.getBoundingClientRect().left // container margin left
this.left = e.clientX - offsetLeft + 15 // 15: margin right
this.top = e.clientY this.top = e.clientY
}, },
closeMenu() { closeMenu() {

View File

@@ -1,22 +1,27 @@
<template> <template>
<div class="login-container"> <div class="login-container">
<el-form class="login-form" autoComplete="on" :model="loginForm" :rules="loginRules" ref="loginForm" label-position="left"> <el-form class="login-form" autoComplete="on" :model="loginForm" :rules="loginRules" ref="loginForm" label-position="left">
<div class="title-container"> <div class="title-container">
<h3 class="title">{{$t('login.title')}}</h3> <h3 class="title">{{$t('login.title')}}</h3>
<lang-select class="set-language"></lang-select> <lang-select class="set-language"></lang-select>
</div> </div>
<el-form-item prop="username"> <el-form-item prop="username">
<span class="svg-container svg-container_login"> <span class="svg-container svg-container_login">
<svg-icon icon-class="user" /> <svg-icon icon-class="user" />
</span> </span>
<el-input name="username" type="text" v-model="loginForm.username" autoComplete="on" placeholder="username" /> <el-input name="username" type="text" v-model="loginForm.username" autoComplete="on" :placeholder="$t('login.username')"
/>
</el-form-item> </el-form-item>
<el-form-item prop="password"> <el-form-item prop="password">
<span class="svg-container"> <span class="svg-container">
<svg-icon icon-class="password" /> <svg-icon icon-class="password" />
</span> </span>
<el-input name="password" :type="passwordType" @keyup.enter.native="handleLogin" v-model="loginForm.password" autoComplete="on" placeholder="password" /> <el-input name="password" :type="passwordType" @keyup.enter.native="handleLogin" v-model="loginForm.password" autoComplete="on"
:placeholder="$t('login.password')" />
<span class="show-pwd" @click="showPwd"> <span class="show-pwd" @click="showPwd">
<svg-icon icon-class="eye" /> <svg-icon icon-class="eye" />
</span> </span>
@@ -137,11 +142,24 @@ export default {
</script> </script>
<style rel="stylesheet/scss" lang="scss"> <style rel="stylesheet/scss" lang="scss">
$bg:#2d3a4b; /* 修复input 背景不协调 和光标变色 */
$light_gray:#eee; /* Detail see https://github.com/PanJiaChen/vue-element-admin/pull/927 */
/* reset element-ui css */ $bg:#283443;
.login-container { $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;
}
}
}
/* reset element-ui css */
.login-container {
.el-input { .el-input {
display: inline-block; display: inline-block;
height: 47px; height: 47px;
@@ -154,9 +172,10 @@ $light_gray:#eee;
padding: 12px 5px 12px 15px; padding: 12px 5px 12px 15px;
color: $light_gray; color: $light_gray;
height: 47px; height: 47px;
caret-color: $cursor;
&:-webkit-autofill { &:-webkit-autofill {
-webkit-box-shadow: 0 0 0px 1000px $bg inset !important; -webkit-box-shadow: 0 0 0px 1000px $bg inset !important;
-webkit-text-fill-color: #fff !important; -webkit-text-fill-color: $cursor !important;
} }
} }
} }
@@ -166,7 +185,7 @@ $light_gray:#eee;
border-radius: 5px; border-radius: 5px;
color: #454545; color: #454545;
} }
} }
</style> </style>
<style rel="stylesheet/scss" lang="scss" scoped> <style rel="stylesheet/scss" lang="scss" scoped>
@@ -211,7 +230,6 @@ $light_gray:#eee;
position: relative; position: relative;
.title { .title {
font-size: 26px; font-size: 26px;
font-weight: 400;
color: $light_gray; color: $light_gray;
margin: 0px auto 40px auto; margin: 0px auto 40px auto;
text-align: center; text-align: center;

View File

@@ -1,7 +0,0 @@
<template>
<div class="app-container">
<code>Parent View: Bar</code>
<img src="https://wpimg.wallstcn.com/be29a7d2-5ccf-4a2b-888d-8a6c2bbb7aac.png">
<router-view></router-view>
</div>
</template>

View File

@@ -1,6 +0,0 @@
<template>
<div style="margin-top:30px;">
<el-alert title="Children: Posts" type="warning" :closable="false">
</el-alert>
</div>
</template>

View File

@@ -1,6 +0,0 @@
<template>
<div style="margin-top:30px;">
<el-alert title="Children: Profile" type="success" :closable="false">
</el-alert>
</div>
</template>

View File

@@ -0,0 +1,7 @@
<template >
<div style="padding:30px;">
<el-alert title="menu 1" :closable="false">
<router-view />
</el-alert>
</div>
</template>

View File

@@ -0,0 +1,7 @@
<template >
<div style="padding:30px;">
<el-alert title="menu 1-1" type="success" :closable="false">
<router-view />
</el-alert>
</div>
</template>

View File

@@ -0,0 +1,7 @@
<template>
<div style="padding:30px;">
<el-alert title="menu 1-2" type="success" :closable="false">
<router-view />
</el-alert>
</div>
</template>

View File

@@ -0,0 +1,5 @@
<template functional>
<div style="padding:30px;">
<el-alert title="menu 1-2-1" type="warning" :closable="false" />
</div>
</template>

View File

@@ -0,0 +1,5 @@
<template functional>
<div style="padding:30px;">
<el-alert title="menu 1-2-2" type="warning" :closable="false" />
</div>
</template>

View File

@@ -0,0 +1,5 @@
<template functional>
<div style="padding:30px;">
<el-alert title="menu 1-3" type="success" :closable="false" />
</div>
</template>

View File

@@ -0,0 +1,5 @@
<template>
<div style="padding:30px;">
<el-alert title="menu 2" :closable="false" />
</div>
</template>