Compare commits

...

44 Commits

Author SHA1 Message Date
Pan
c8e632f0c3 [release] 2.0.0 2017-08-29 18:06:35 +08:00
Pan
c182a119e1 add icon tips 2017-08-29 18:05:35 +08:00
Pan
90fd4328b7 add icons page 2017-08-29 18:05:35 +08:00
Pan
97570fa612 refactor icons 2017-08-29 18:05:35 +08:00
Pan
bae698c9ad update vue-loader 2017-08-28 22:59:09 +08:00
Pan
f7aee3b5a3 refactor 2017-08-28 13:18:35 +08:00
Pan
b98860ace1 refine inline edit table example 2017-08-28 13:18:35 +08:00
Pan
3c05519a09 refine 2017-08-28 13:18:35 +08:00
Pan
385ec5a762 refine 2017-08-28 13:18:35 +08:00
Pan
33a4369cd7 refine code 2017-08-28 13:18:35 +08:00
Pan
8fa2364a3b add mock delay 2017-08-28 13:18:35 +08:00
Pan
551e911eb4 全局lint优化 2017-08-28 13:18:35 +08:00
Pan
b8ecda19d8 refine code 2017-08-28 13:18:35 +08:00
Pan
62d2f62bff 增加第三方登录 demo 2017-08-28 13:18:35 +08:00
Pan
0094f44910 change login by username 2017-08-28 13:18:35 +08:00
Pan
d06d476b50 refine import normalize.css && update 2017-08-21 20:55:56 +08:00
Pan
aa5f9059b3 rm jquery 2017-08-21 20:24:02 +08:00
Pan
9768305166 refine main.js 2017-08-21 15:55:46 +08:00
Pan
e912cea26a refine sidebaritem code 2017-08-18 11:03:11 +08:00
Pan
eac12e3ac0 bump deps 2017-08-18 11:03:11 +08:00
花裤衩
c32fc58a3a Update fetch.js 2017-08-16 09:57:05 +08:00
spiritree
bf0f2e7ee3 fix dashboard button router-link bug 2017-08-10 17:25:19 +08:00
Pan
2e9a3a849b refine build 2017-08-07 16:11:10 +08:00
Pan
cdebb5c012 fix levelbar bug 2017-08-07 11:02:51 +08:00
Pan
00a83d1e5a update echarts remove warning 2017-08-07 10:27:39 +08:00
Pan
17ada3c65e add HashedModuleIdsPlugin 2017-08-04 16:04:14 +08:00
Pan
391e7703ed fix router deepClone bug 2017-08-03 11:24:26 +08:00
Pan
97e94c067d refine sidebar css 2017-08-02 14:43:57 +08:00
Pan
a3b1dd81fd refine sidebar css 2017-08-02 14:42:20 +08:00
花裤衩
c96bdeb99d Update README.md 2017-07-31 14:45:32 +08:00
Pan
630d06bf76 [release] 1.2.0 2017-07-28 17:38:42 +08:00
Pan
8c9ebd7345 set productionSourceMap: false 2017-07-28 17:29:07 +08:00
Pan
89c72d277e refine css 2017-07-28 17:19:40 +08:00
Pan
108b380d20 menu 支持 icon 嵌套 2017-07-28 17:19:40 +08:00
Pan
69fc52d4e9 refine router.js 2017-07-28 17:19:40 +08:00
Pan
d78b49803d refine css 2017-07-28 17:19:40 +08:00
Pan
dd9ef5145d refine sidebar 2017-07-28 17:19:40 +08:00
Pan
ae44d0b8ca update element & vue 2017-07-28 17:19:40 +08:00
Pan
6ad03ac5f0 rm documentImg 2017-07-28 16:10:00 +08:00
Pan
553ef477ef fix typo 2017-07-28 09:50:52 +08:00
Pan
1083a17386 fix chart bug 2017-07-27 14:12:31 +08:00
Pan
535fe083e5 fix bug 2017-07-27 13:55:06 +08:00
spiritree
83e8dfc494 fix selectExcel bug 2017-07-27 12:20:04 +08:00
Pan
77ff823037 fix levelbar bug 2017-07-26 13:32:02 +08:00
160 changed files with 4769 additions and 4952 deletions

View File

@@ -6,7 +6,8 @@ module.exports = {
}, },
env: { env: {
browser: true, browser: true,
node: true node: true,
es6: true,
}, },
extends: 'eslint:recommended', extends: 'eslint:recommended',
// required to lint *.vue files // required to lint *.vue files
@@ -22,297 +23,122 @@ module.exports = {
} }
}, },
// add your custom rules here // add your custom rules here
//it is base on https://github.com/vuejs/eslint-config-vue
'rules': { 'rules': {
// don't require .vue extension when importing 'accessor-pairs': 2,
// 'import/extensions': ['error', 'always', { 'arrow-spacing': [2, { 'before': true, 'after': true }],
// 'js': 'never', 'block-spacing': [2, 'always'],
// 'vue': 'never' 'brace-style': [2, '1tbs', { 'allowSingleLine': true }],
// }], 'camelcase': [0, { 'properties': 'always' }],
// allow debugger during development 'comma-dangle': [2, 'never'],
'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0, 'comma-spacing': [2, { 'before': false, 'after': true }],
/* 'comma-style': [2, 'last'],
* Possible Errors 'constructor-super': 2,
*/ 'curly': [2, 'multi-line'],
'dot-location': [2, 'property'],
// disallow unnecessary parentheses 'eol-last': 2,
'no-extra-parens': ['error', 'all', {'nestedBinaryExpressions': false}], 'eqeqeq': [2, 'allow-null'],
'generator-star-spacing': [2, { 'before': true, 'after': true }],
// disallow negating the left operand of relational operators 'handle-callback-err': [2, '^(err|error)$' ],
'no-unsafe-negation': 'error', 'indent': [2, 2, { 'SwitchCase': 1 }],
'jsx-quotes': [2, 'prefer-single'],
// enforce valid JSDoc comments 'key-spacing': [2, { 'beforeColon': false, 'afterColon': true }],
'valid-jsdoc': 'off', 'keyword-spacing': [2, { 'before': true, 'after': true }],
'new-cap': [2, { 'newIsCap': true, 'capIsNew': false }],
/* 'new-parens': 2,
* Best Practices 'no-array-constructor': 2,
*/ 'no-caller': 2,
// enforce return statements in callbacks of array methods
'array-callback-return': 'error',
// enforce consistent brace style for all control statements
curly: ['error', 'multi-line'],
// enforce consistent newlines before and after dots
'dot-location': ['error', 'property'],
// enforce dot notation whenever possible
'dot-notation': 'error',
// require the use of === and !==
'eqeqeq': ['error', 'smart'],
// disallow the use of arguments.caller or arguments.callee
'no-caller': 'error',
// disallow empty functions
'no-empty-function': 'error',
// disallow unnecessary calls to .bind()
'no-extra-bind': 'error',
// disallow unnecessary labels
'no-extra-label': 'error',
// disallow leading or trailing decimal points in numeric literals
'no-floating-decimal': 'error',
// disallow assignments to native objects or read-only global variables
'no-global-assign': 'error',
// disallow the use of eval()-like methods
'no-implied-eval': 'error',
// disallow the use of the __iterator__ property
'no-iterator': 'error',
// disallow unnecessary nested blocks
'no-lone-blocks': 'error',
// disallow multiple spaces
'no-multi-spaces': 'error',
// disallow new operators with the String, Number, and Boolean objects
'no-new-wrappers': 'error',
// disallow octal escape sequences in string literals
'no-octal-escape': 'error',
// disallow the use of the __proto__ property
'no-proto': 'error',
// disallow comparisons where both sides are exactly the same
'no-self-compare': 'error',
// disallow throwing literals as exceptions
'no-throw-literal': 'error',
// disallow unused expressions
'no-unused-expressions': 'error',
// disallow unnecessary calls to .call() and .apply()
'no-useless-call': 'error',
// disallow unnecessary concatenation of literals or template literals
'no-useless-concat': 'error',
// disallow unnecessary escape characters
'no-useless-escape': 'error',
// disallow void operators
'no-void': 'error',
// require parentheses around immediate function invocations
'wrap-iife': 'error',
// require or disallow “Yoda” conditions
yoda: 'error',
/*
* Variables
*/
// disallow labels that share a name with a variable
'no-label-var': 'error',
// disallow initializing variables to undefined
'no-undef-init': 'error',
'no-undef': 'off',
// disallow the use of variables before they are defined
'no-use-before-define': 'error',
/*
* Node.js and CommonJS
*/
// disallow new operators with calls to require
'no-new-require': 'error',
/*
* Stylistic Issues
*/
// enforce consistent spacing inside array brackets
'array-bracket-spacing': 'error',
// enforce consistent spacing inside single-line blocks
'block-spacing': 'error',
// enforce consistent brace style for blocks
'brace-style': ['error', '1tbs', {'allowSingleLine': true}],
// require or disallow trailing commas
'comma-dangle': 'error',
// enforce consistent spacing before and after commas
'comma-spacing': 'error',
// enforce consistent comma style
'comma-style': 'error',
// enforce consistent spacing inside computed property brackets
'computed-property-spacing': 'error',
// require or disallow spacing between function identifiers and their invocations
'func-call-spacing': 'error',
// enforce consistent indentation
indent: ['error', 2, {SwitchCase: 1}],
// enforce the consistent use of either double or single quotes in JSX attributes
'jsx-quotes': 'error',
// enforce consistent spacing between keys and values in object literal properties
'key-spacing': 'error',
// enforce consistent spacing before and after keywords
'keyword-spacing': 'error',
// enforce consistent linebreak style
'linebreak-style': 'error',
// require or disallow newlines around directives
'lines-around-directive': 'error',
// require constructor names to begin with a capital letter
'new-cap': 'off',
// require parentheses when invoking a constructor with no arguments
'new-parens': 'error',
// disallow Array constructors
'no-array-constructor': 'error',
// disallow Object constructors
'no-new-object': 'error',
// disallow trailing whitespace at the end of lines
'no-trailing-spaces': 'error',
// disallow ternary operators when simpler alternatives exist
'no-unneeded-ternary': 'error',
// disallow whitespace before properties
'no-whitespace-before-property': 'error',
// enforce consistent spacing inside braces
'object-curly-spacing': ['error', 'always'],
// require or disallow padding within blocks
'padded-blocks': ['error', 'never'],
// require quotes around object literal property names
'quote-props': ['error', 'as-needed'],
// enforce the consistent use of either backticks, double, or single quotes
quotes: ['error', 'single'],
// enforce consistent spacing before and after semicolons
'semi-spacing': 'error',
// require or disallow semicolons instead of ASI
// semi: ['error', 'never'],
// enforce consistent spacing before blocks
'space-before-blocks': 'error',
'no-console': 'off', 'no-console': 'off',
'no-class-assign': 2,
// enforce consistent spacing before function definition opening parenthesis 'no-cond-assign': 2,
'space-before-function-paren': ['error', 'never'], 'no-const-assign': 2,
'no-control-regex': 2,
// enforce consistent spacing inside parentheses 'no-delete-var': 2,
'space-in-parens': 'error', 'no-dupe-args': 2,
'no-dupe-class-members': 2,
// require spacing around infix operators 'no-dupe-keys': 2,
'space-infix-ops': 'error', 'no-duplicate-case': 2,
'no-empty-character-class': 2,
// enforce consistent spacing before or after unary operators 'no-empty-pattern': 2,
'space-unary-ops': 'error', 'no-eval': 2,
'no-ex-assign': 2,
// enforce consistent spacing after the // or /* in a comment 'no-extend-native': 2,
'spaced-comment': 'error', 'no-extra-bind': 2,
'no-extra-boolean-cast': 2,
// require or disallow Unicode byte order mark (BOM) 'no-extra-parens': [2, 'functions'],
'unicode-bom': 'error', 'no-fallthrough': 2,
'no-floating-decimal': 2,
'no-func-assign': 2,
/* 'no-implied-eval': 2,
* ECMAScript 6 'no-inner-declarations': [2, 'functions'],
*/ 'no-invalid-regexp': 2,
'no-irregular-whitespace': 2,
// require braces around arrow function bodies 'no-iterator': 2,
'arrow-body-style': 'error', 'no-label-var': 2,
'no-labels': [2, { 'allowLoop': false, 'allowSwitch': false }],
// require parentheses around arrow function arguments 'no-lone-blocks': 2,
'arrow-parens': ['error', 'as-needed'], 'no-mixed-spaces-and-tabs': 2,
'no-multi-spaces': 2,
// enforce consistent spacing before and after the arrow in arrow functions 'no-multi-str': 2,
'arrow-spacing': 'error', 'no-multiple-empty-lines': [2, { 'max': 1 }],
'no-native-reassign': 2,
// enforce consistent spacing around * operators in generator functions 'no-negated-in-lhs': 2,
'generator-star-spacing': ['error', 'after'], 'no-new-object': 2,
'no-new-require': 2,
// disallow duplicate module imports 'no-new-symbol': 2,
'no-duplicate-imports': 'error', 'no-new-wrappers': 2,
'no-obj-calls': 2,
// disallow unnecessary computed property keys in object literals 'no-octal': 2,
'no-useless-computed-key': 'error', 'no-octal-escape': 2,
'no-path-concat': 2,
// disallow unnecessary constructors 'no-proto': 2,
'no-useless-constructor': 'error', 'no-redeclare': 2,
'no-regex-spaces': 2,
// disallow renaming import, export, and destructured assignments to the same name 'no-return-assign': [2, 'except-parens'],
'no-useless-rename': 'error', 'no-self-assign': 2,
'no-self-compare': 2,
// require let or const instead of var 'no-sequences': 2,
'no-var': 'error', 'no-shadow-restricted-names': 2,
'no-spaced-func': 2,
// require or disallow method and property shorthand syntax for object literals 'no-sparse-arrays': 2,
'object-shorthand': 'error', 'no-this-before-super': 2,
'no-throw-literal': 2,
// require arrow functions as callbacks 'no-trailing-spaces': 2,
'prefer-arrow-callback': 'error', 'no-undef': 2,
'no-undef-init': 2,
// require const declarations for variables that are never reassigned after declared 'no-unexpected-multiline': 2,
'prefer-const': 'error', 'no-unmodified-loop-condition': 2,
'no-unneeded-ternary': [2, { 'defaultAssignment': false }],
// disallow parseInt() in favor of binary, octal, and hexadecimal literals 'no-unreachable': 2,
'prefer-numeric-literals': 'error', 'no-unsafe-finally': 2,
'no-unused-vars': [2, { 'vars': 'all', 'args': 'none' }],
// require rest parameters instead of arguments 'no-useless-call': 2,
'prefer-rest-params': 'error', 'no-useless-computed-key': 2,
'no-useless-constructor': 2,
// require spread operators instead of .apply() 'no-useless-escape': 0,
'prefer-spread': 'error', 'no-whitespace-before-property': 2,
'no-with': 2,
// enforce spacing between rest and spread operators and their expressions 'one-var': [2, { 'initialized': 'never' }],
'rest-spread-spacing': 'error', 'operator-linebreak': [2, 'after', { 'overrides': { '?': 'before', ':': 'before' } }],
'padded-blocks': [2, 'never'],
// require or disallow spacing around embedded expressions of template strings 'quotes': [2, 'single', { 'avoidEscape': true, 'allowTemplateLiterals': true }],
'template-curly-spacing': 'error', 'semi': [2, 'never'],
'semi-spacing': [2, { 'before': false, 'after': true }],
// require or disallow spacing around the * in yield* expressions 'space-before-blocks': [2, 'always'],
'yield-star-spacing': 'error' 'space-before-function-paren': [2, 'never'],
'space-in-parens': [2, 'never'],
'space-infix-ops': 2,
'space-unary-ops': [2, { 'words': true, 'nonwords': false }],
'spaced-comment': [2, 'always', { 'markers': ['global', 'globals', 'eslint', 'eslint-disable', '*package', '!', ','] }],
'template-curly-spacing': [2, 'never'],
'use-isnan': 2,
'valid-typeof': 2,
'wrap-iife': [2, 'any'],
'yield-star-spacing': [2, 'both'],
'yoda': [2, 'never'],
'prefer-const': 2,
'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0,
'object-curly-spacing': [2, 'always', { objectsInObjects: false }],
'array-bracket-spacing': [2, 'never']
} }
} }

View File

@@ -105,7 +105,6 @@ npm run build:prod
│   ├── App.vue // entry view │   ├── App.vue // entry view
│   └── main.js // entry for loading components, initialization │   └── main.js // entry for loading components, initialization
├── static // third-party libraries not packed with Webpack ├── static // third-party libraries not packed with Webpack
│   ├── jquery
│   └── Tinymce // rich text │   └── Tinymce // rich text
├── .babelrc // babel-loader config ├── .babelrc // babel-loader config
├── eslintrc.js // eslint config ├── eslintrc.js // eslint config

View File

@@ -1,4 +1,11 @@
# vue-element-admin # # vue-element-admin #
[![vue](https://img.shields.io/badge/vue-2.4.2-brightgreen.svg)](https://github.com/vuejs/vue)
[![element-ui](https://img.shields.io/badge/element--ui-1.4.1-brightgreen.svg)](https://github.com/ElemeFE/element)
[![license](https://img.shields.io/github/license/mashape/apistatus.svg)](https://github.com/PanJiaChen/vue-element-admin/blob/master/LICENSE)
[![GitHub release](https://img.shields.io/github/release/PanJiaChen/vue-element-admin.svg)]()
[线上地址](http://panjiachen.github.io/vue-element-admin) [线上地址](http://panjiachen.github.io/vue-element-admin)
[English Document](https://github.com/PanJiaChen/vue-element-admin/blob/master/README-en.md) [English Document](https://github.com/PanJiaChen/vue-element-admin/blob/master/README-en.md)
@@ -9,7 +16,7 @@
**注意该项目目前使用element-ui@1.3.3版本,所以最低兼容 Vue 2.3.0** **注意该项目目前使用element-ui@1.4.1版本,所以最低兼容 Vue 2.3.0**
## 前言 ## 前言
> 这半年来一直在用vue写管理后台目前后台已经有百来个页面十几种权限但维护成本依然很低所以准备开源分享一下后台开发的经验和成果。目前的技术栈主要的采用vue+element+axios由webpack2打包。由于是个人项目所以数据请求都是用了mockjs模拟。注意在此项目基础上改造开发时请移除mock文件。 > 这半年来一直在用vue写管理后台目前后台已经有百来个页面十几种权限但维护成本依然很低所以准备开源分享一下后台开发的经验和成果。目前的技术栈主要的采用vue+element+axios由webpack2打包。由于是个人项目所以数据请求都是用了mockjs模拟。注意在此项目基础上改造开发时请移除mock文件。
@@ -47,7 +54,7 @@
- Sticky - Sticky
- CountTo - CountTo
- echarts图表 - echarts图表
- 401401错误页面 - 401404错误页面
- 错误日志 - 错误日志
- 导出excel - 导出excel
- table example - table example
@@ -109,7 +116,6 @@
│   ├── App.vue // 入口页面 │   ├── App.vue // 入口页面
│   └── main.js // 入口 加载组件 初始化等 │   └── main.js // 入口 加载组件 初始化等
├── static // 第三方不打包资源 ├── static // 第三方不打包资源
│   ├── jquery
│   └── Tinymce // 富文本 │   └── Tinymce // 富文本
├── .babelrc // babel-loader 配置 ├── .babelrc // babel-loader 配置
├── eslintrc.js // eslint 配置项 ├── eslintrc.js // eslint 配置项

View File

@@ -1,85 +1,92 @@
var path = require('path'); var path = require('path')
var utils = require('./utils'); var utils = require('./utils')
var config = require('../config'); var config = require('../config')
var vueLoaderConfig = require('./vue-loader.conf'); var vueLoaderConfig = require('./vue-loader.conf')
function resolve(dir) { function resolve(dir) {
return path.join(__dirname, '..', dir) return path.join(__dirname, '..', dir)
} }
var src = path.resolve(__dirname, '../src');
module.exports = { module.exports = {
entry: { entry: {
app: './src/main.js' app: './src/main.js'
}, },
output: { output: {
path: config.build.assetsRoot, path: config.build.assetsRoot,
filename: '[name].js', filename: '[name].js',
publicPath: process.env.NODE_ENV !== 'development' ? config.build.assetsPublicPath: config.dev.assetsPublicPath publicPath: process.env.NODE_ENV !== 'development' ? config.build.assetsPublicPath : config.dev.assetsPublicPath
}, },
resolve: { resolve: {
extensions: ['.js', '.vue', '.json'], extensions: ['.js', '.vue', '.json'],
alias: { alias: {
'vue$': 'vue/dist/vue.esm.js', 'vue$': 'vue/dist/vue.esm.js',
'@': resolve('src'), '@': resolve('src'),
'src': path.resolve(__dirname, '../src'), 'src': path.resolve(__dirname, '../src'),
'assets': path.resolve(__dirname, '../src/assets'), 'assets': path.resolve(__dirname, '../src/assets'),
'components': path.resolve(__dirname, '../src/components'), 'components': path.resolve(__dirname, '../src/components'),
'views': path.resolve(__dirname, '../src/views'), 'views': path.resolve(__dirname, '../src/views'),
'styles': path.resolve(__dirname, '../src/styles'), 'styles': path.resolve(__dirname, '../src/styles'),
'api': path.resolve(__dirname, '../src/api'), 'api': path.resolve(__dirname, '../src/api'),
'utils': path.resolve(__dirname, '../src/utils'), 'utils': path.resolve(__dirname, '../src/utils'),
'store': path.resolve(__dirname, '../src/store'), 'store': path.resolve(__dirname, '../src/store'),
'router': path.resolve(__dirname, '../src/router'), 'router': path.resolve(__dirname, '../src/router'),
'mock': path.resolve(__dirname, '../src/mock'), 'mock': path.resolve(__dirname, '../src/mock'),
'vendor': path.resolve(__dirname, '../src/vendor'), 'vendor': path.resolve(__dirname, '../src/vendor'),
'static': path.resolve(__dirname, '../static') 'static': path.resolve(__dirname, '../static')
}
},
module: {
rules: [
{
test: /\.(js|vue)$/,
loader: 'eslint-loader',
enforce: "pre",
include: [resolve('src'), resolve('test')],
options: {
formatter: require('eslint-friendly-formatter')
}
},
{
test: /\.vue$/,
loader: 'vue-loader',
options: vueLoaderConfig
},
{
test: /\.js$/,
loader: 'babel-loader?cacheDirectory',
include: [resolve('src'), resolve('test')]
},
{
test: /\.svg$/,
loader: 'svg-sprite-loader',
include: [resolve('src/icons')],
options: {
symbolId: 'icon-[name]'
} }
}, },
externals: { {
jquery: 'jQuery' test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
}, loader: 'url-loader',
module: { exclude: [resolve('src/icons')],
rules: [ query: {
// { limit: 10000,
// test: /\.(js|vue)$/, name: utils.assetsPath('img/[name].[hash:7].[ext]')
// loader: 'eslint-loader', }
// enforce: "pre", },
// include: [resolve('src'), resolve('test')], {
// options: { test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
// formatter: require('eslint-friendly-formatter') loader: 'url-loader',
// } query: {
// }, limit: 10000,
{ test: /\.vue$/, name: utils.assetsPath('fonts/[name].[hash:7].[ext]')
loader: 'vue-loader', }
options: vueLoaderConfig }
}, ]
{ },
test: /\.js$/, //注入全局mixin
loader: 'babel-loader?cacheDirectory', // sassResources: path.join(__dirname, '../src/styles/mixin.scss'),
include: [resolve('src'), resolve('test')] // sassLoader: {
}, // data: path.join(__dirname, '../src/styles/index.scss')
{ // },
test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
loader: 'url-loader',
query: {
limit: 10000,
name: utils.assetsPath('img/[name].[hash:7].[ext]')
}
},
{
test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
loader: 'url-loader',
query: {
limit: 10000,
name: utils.assetsPath('fonts/[name].[hash:7].[ext]')
}
}
]
},
//注入全局mixin
// sassResources: path.join(__dirname, '../src/styles/mixin.scss'),
// sassLoader: {
// data: path.join(__dirname, '../src/styles/index.scss')
// },
} }

View File

@@ -9,39 +9,38 @@ var FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin')
// add hot-reload related code to entry chunks // add hot-reload related code to entry chunks
Object.keys(baseWebpackConfig.entry).forEach(function (name) { Object.keys(baseWebpackConfig.entry).forEach(function (name) {
baseWebpackConfig.entry[name] = ['./build/dev-client'].concat(baseWebpackConfig.entry[name]) baseWebpackConfig.entry[name] = ['./build/dev-client'].concat(baseWebpackConfig.entry[name])
}) })
function resolveApp(relativePath) { function resolveApp(relativePath) {
return path.resolve(relativePath); return path.resolve(relativePath);
} }
module.exports = merge(baseWebpackConfig, { module.exports = merge(baseWebpackConfig, {
module: { module: {
rules: utils.styleLoaders({sourceMap: config.dev.cssSourceMap}) rules: utils.styleLoaders({
}, sourceMap: config.dev.cssSourceMap
// cheap-source-map is faster for development })
devtool: '#cheap-source-map', },
cache: true, // cheap-source-map is faster for development
plugins: [ devtool: '#cheap-source-map',
new webpack.DefinePlugin({ cache: true,
'process.env': config.dev.env plugins: [
}), new webpack.DefinePlugin({
new webpack.ProvidePlugin({ 'process.env': config.dev.env
$: 'jquery', }),
'jQuery': 'jquery' // https://github.com/glenjamin/webpack-hot-middleware#installation--usage
}), new webpack.HotModuleReplacementPlugin(),
// https://github.com/glenjamin/webpack-hot-middleware#installation--usage new webpack.NoEmitOnErrorsPlugin(),
new webpack.HotModuleReplacementPlugin(), // https://github.com/ampedandwired/html-webpack-plugin
new webpack.NoEmitOnErrorsPlugin(), new HtmlWebpackPlugin({
// https://github.com/ampedandwired/html-webpack-plugin filename: 'index.html',
new HtmlWebpackPlugin({ template: 'index.html',
filename: 'index.html', favicon: resolveApp('favicon.ico'),
template: 'index.html', inject: true,
favicon: resolveApp('favicon.ico'), path: config.dev.assetsPublicPath + config.dev.assetsSubDirectory
inject: true, }),
path:config.dev.staticPath new FriendlyErrorsPlugin()
}), ]
new FriendlyErrorsPlugin()
]
}) })

View File

@@ -12,110 +12,106 @@ var OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin')
var env = process.env.NODE_ENV === 'production' ? config.build.prodEnv : config.build.sitEnv var env = process.env.NODE_ENV === 'production' ? config.build.prodEnv : config.build.sitEnv
function resolveApp(relativePath) { function resolveApp(relativePath) {
return path.resolve(relativePath); return path.resolve(relativePath);
} }
var webpackConfig = merge(baseWebpackConfig, { var webpackConfig = merge(baseWebpackConfig, {
module: { module: {
rules: utils.styleLoaders({ rules: utils.styleLoaders({
sourceMap: config.build.productionSourceMap, sourceMap: config.build.productionSourceMap,
extract: true extract: true
}) })
}, },
devtool: config.build.productionSourceMap ? '#source-map' : false, devtool: config.build.productionSourceMap ? '#source-map' : false,
output: { output: {
path: config.build.assetsRoot, path: config.build.assetsRoot,
filename: utils.assetsPath('js/[name].[chunkhash].js'), filename: utils.assetsPath('js/[name].[chunkhash].js'),
chunkFilename: utils.assetsPath('js/[id].[chunkhash].js') chunkFilename: utils.assetsPath('js/[id].[chunkhash].js'),
}, publicPath: config.build.assetsPublicPath
plugins: [ },
// http://vuejs.github.io/vue-loader/en/workflow/production.html plugins: [
new webpack.DefinePlugin({ // http://vuejs.github.io/vue-loader/en/workflow/production.html
'process.env': env new webpack.DefinePlugin({
}), 'process.env': env
new webpack.optimize.UglifyJsPlugin({ }),
compress: { new webpack.optimize.UglifyJsPlugin({
warnings: false compress: {
}, warnings: false
sourceMap: true },
}), sourceMap: true
// extract css into its own file }),
new ExtractTextPlugin({ // extract css into its own file
filename: utils.assetsPath('css/[name].[contenthash].css') new ExtractTextPlugin({
}), filename: utils.assetsPath('css/[name].[contenthash].css')
// Compress extracted CSS. We are using this plugin so that possible }),
// duplicated CSS from different components can be deduped. // Compress extracted CSS. We are using this plugin so that possible
new OptimizeCSSPlugin(), // duplicated CSS from different components can be deduped.
// generate dist index.html with correct asset hash for caching. new OptimizeCSSPlugin(),
// you can customize output by editing /index.html // generate dist index.html with correct asset hash for caching.
// see https://github.com/ampedandwired/html-webpack-plugin // you can customize output by editing /index.html
new HtmlWebpackPlugin({ // see https://github.com/ampedandwired/html-webpack-plugin
filename: process.env.NODE_ENV === 'testing' new HtmlWebpackPlugin({
? 'index.html' filename: 'index.html',
: config.build.index, template: 'index.html',
template: 'index.html', inject: true,
inject: true, favicon: resolveApp('favicon.ico'),
favicon: resolveApp('favicon.ico'), minify: {
minify: { removeComments: true,
removeComments: true, collapseWhitespace: true,
collapseWhitespace: true, removeRedundantAttributes: true,
removeRedundantAttributes: true, useShortDoctype: true,
useShortDoctype: true, removeEmptyAttributes: true,
removeEmptyAttributes: true, removeStyleLinkTypeAttributes: true,
removeStyleLinkTypeAttributes: true, keepClosingSlash: true,
keepClosingSlash: true, minifyJS: true,
minifyJS: true, minifyCSS: true,
minifyCSS: true, minifyURLs: true
minifyURLs: true },
}, path: config.build.assetsPublicPath + config.build.assetsSubDirectory,
path:config.build.staticPath, // necessary to consistently work with multiple chunks via CommonsChunkPlugin
// necessary to consistently work with multiple chunks via CommonsChunkPlugin chunksSortMode: 'dependency'
chunksSortMode: 'dependency' }),
}), // cache Module Identifiers
// split vendor js into its own file new webpack.HashedModuleIdsPlugin(),
new webpack.optimize.CommonsChunkPlugin({ // split vendor js into its own file
name: 'vendor', new webpack.optimize.CommonsChunkPlugin({
minChunks: function (module, count) { name: 'vendor',
// any required modules inside node_modules are extracted to vendor minChunks: function (module, count) {
return ( // any required modules inside node_modules are extracted to vendor
module.resource && return (
/\.js$/.test(module.resource) && module.resource &&
module.resource.indexOf( /\.js$/.test(module.resource) &&
path.join(__dirname, '../node_modules') module.resource.indexOf(
) === 0 path.join(__dirname, '../node_modules')
) ) === 0
} )
}), }
// split echarts into its own file }),
new webpack.optimize.CommonsChunkPlugin({ // split echarts into its own file
async:'echarts', new webpack.optimize.CommonsChunkPlugin({
minChunks(module) { async: 'echarts',
var context = module.context; minChunks(module) {
return context && (context.indexOf('echarts') >= 0 || context.indexOf('zrender') >= 0); var context = module.context;
} return context && (context.indexOf('echarts') >= 0 || context.indexOf('zrender') >= 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 // extract webpack runtime and module manifest to its own file in order to
new webpack.optimize.CommonsChunkPlugin({ // prevent vendor hash from being updated whenever app bundle is updated
name: 'manifest', new webpack.optimize.CommonsChunkPlugin({
chunks: ['vendor'] name: 'manifest',
}), chunks: ['vendor']
// copy custom static assets }),
new CopyWebpackPlugin([ // copy custom static assets
{ new CopyWebpackPlugin([{
from: path.resolve(__dirname, '../static'), from: path.resolve(__dirname, '../static'),
to: config.build.assetsSubDirectory, to: config.build.assetsSubDirectory,
ignore: ['.*'] ignore: ['.*']
} }])
]), ]
new webpack.ProvidePlugin({
$: 'jquery',
'jQuery': 'jquery'
})
]
}) })
if (config.build.bundleAnalyzerReport) { if (config.build.bundleAnalyzerReport) {
var BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin var BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin
webpackConfig.plugins.push(new BundleAnalyzerPlugin()) webpackConfig.plugins.push(new BundleAnalyzerPlugin())
} }
module.exports = webpackConfig module.exports = webpackConfig

View File

@@ -9,8 +9,7 @@ module.exports = {
assetsRoot: path.resolve(__dirname, '../dist'), assetsRoot: path.resolve(__dirname, '../dist'),
assetsSubDirectory: 'static', assetsSubDirectory: 'static',
assetsPublicPath: './', //请根据自己路径配置更改 assetsPublicPath: './', //请根据自己路径配置更改
staticPath:'./static/', //请根据自己路径配置更改 productionSourceMap: false,
productionSourceMap: true,
// 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.
// Before setting to `true`, make sure to: // Before setting to `true`, make sure to:
@@ -29,7 +28,6 @@ module.exports = {
autoOpenBrowser: true, autoOpenBrowser: true,
assetsSubDirectory: 'static', assetsSubDirectory: 'static',
assetsPublicPath: '/', assetsPublicPath: '/',
staticPath:'/static/',
proxyTable: {}, proxyTable: {},
// 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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 117 KiB

View File

@@ -8,10 +8,8 @@
<title>Juicy</title> <title>Juicy</title>
</head> </head>
<body> <body>
<script src=<%= htmlWebpackPlugin.options.path %>jquery.min.js></script> <script src=<%= htmlWebpackPlugin.options.path %>/tinymce/tinymce.min.js></script>
<script src=<%= htmlWebpackPlugin.options.path %>tinymce/tinymce.min.js></script>
<div id="app"></div> <div id="app"></div>
<!-- built files will be auto injected --> <!-- built files will be auto injected -->
</body> </body>
</html> </html>

View File

@@ -1,6 +1,6 @@
{ {
"name": "juicy", "name": "juicy",
"version": "1.1.1", "version": "2.0.0",
"description": "A Vue.js admin", "description": "A Vue.js admin",
"author": "Pan <panfree23@gmail.com>", "author": "Pan <panfree23@gmail.com>",
"license": "MIT", "license": "MIT",
@@ -16,24 +16,24 @@
"axios": "0.16.2", "axios": "0.16.2",
"codemirror": "5.26.0", "codemirror": "5.26.0",
"dropzone": "5.1.0", "dropzone": "5.1.0",
"echarts": "3.6.1", "echarts": "3.6.2",
"element-ui": "1.3.6", "element-ui": "1.4.2",
"file-saver": "1.3.3", "file-saver": "1.3.3",
"jquery": "3.1.1",
"js-cookie": "2.1.4", "js-cookie": "2.1.4",
"jsonlint": "1.6.2", "jsonlint": "1.6.2",
"mockjs": "1.0.1-beta3", "mockjs": "1.0.1-beta3",
"normalize.css": "3.0.2", "normalize.css": "7.0.0",
"nprogress": "0.2.0", "nprogress": "0.2.0",
"screenfull": "3.2.2", "screenfull": "3.2.2",
"showdown": "1.7.1", "showdown": "1.7.1",
"simplemde": "1.11.2", "simplemde": "1.11.2",
"sortablejs": "1.5.1", "sortablejs": "1.5.1",
"vue": "2.3.3", "vue": "2.4.2",
"vue-count-to": "1.0.5", "vue-count-to": "1.0.5",
"vue-multiselect": "2.0.0-beta.15", "vue-multiselect": "2.0.2",
"vue-router": "2.5.3", "vue-router": "2.7.0",
"vuedraggable": "2.13.1", "vue-splitpane": "^1.0.0",
"vuedraggable": "2.14.1",
"vuex": "2.3.1", "vuex": "2.3.1",
"xlsx": "^0.10.8" "xlsx": "^0.10.8"
}, },
@@ -75,10 +75,11 @@
"script-loader": "0.7.0", "script-loader": "0.7.0",
"semver": "5.3.0", "semver": "5.3.0",
"style-loader": "0.17.0", "style-loader": "0.17.0",
"svg-sprite-loader": "3.2.4",
"url-loader": "0.5.8", "url-loader": "0.5.8",
"vue-loader": "12.2.1", "vue-loader": "13.0.4",
"vue-style-loader": "3.0.1", "vue-style-loader": "3.0.1",
"vue-template-compiler": "2.3.3", "vue-template-compiler": "2.4.2",
"webpack": "2.6.1", "webpack": "2.6.1",
"webpack-bundle-analyzer": "2.8.2", "webpack-bundle-analyzer": "2.8.2",
"webpack-dev-middleware": "1.10.2", "webpack-dev-middleware": "1.10.2",

View File

@@ -11,5 +11,6 @@
</script> </script>
<style lang="scss"> <style lang="scss">
@import './styles/index.scss'; // 全局自定义的css样式 @import '~normalize.css/normalize.css';// normalize.css 样式格式化
@import './styles/index.scss'; // 全局自定义的css样式
</style> </style>

View File

@@ -1,16 +1,25 @@
import fetch from 'utils/fetch'; import fetch from '@/utils/fetch'
export function getList() { export function fetchList(query) {
return fetch({ return fetch({
url: '/article/list', url: '/article/list',
method: 'get' method: 'get',
}); params: query
})
} }
export function getArticle() { export function fetchArticle() {
return fetch({ return fetch({
url: '/article/detail', url: '/article/detail',
method: 'get' method: 'get'
}); })
}
export function fetchPv(pv) {
return fetch({
url: '/article/pv',
method: 'get',
params: { pv }
})
} }

View File

@@ -1,17 +0,0 @@
import fetch from 'utils/fetch';
export function fetchList(query) {
return fetch({
url: '/article_table/list',
method: 'get',
params: query
});
}
export function fetchPv(pv) {
return fetch({
url: '/article_table/pv',
method: 'get',
params: { pv }
});
}

View File

@@ -1,29 +1,29 @@
import fetch from 'utils/fetch'; import fetch from '@/utils/fetch'
export function loginByEmail(email, password) { export function loginByUsername(username, password) {
const data = { const data = {
email, username,
password password
}; }
return fetch({ return fetch({
url: '/login/loginbyemail', url: '/login/login',
method: 'post', method: 'post',
data data
}); })
} }
export function logout() { export function logout() {
return fetch({ return fetch({
url: '/login/logout', url: '/login/logout',
method: 'post' method: 'post'
}); })
} }
export function getInfo(token) { export function getUserInfo(token) {
return fetch({ return fetch({
url: '/user/info', url: '/user/info',
method: 'get', method: 'get',
params: { token } params: { token }
}); })
} }

View File

@@ -1,8 +1,8 @@
import fetch from 'utils/fetch'; import fetch from '@/utils/fetch'
export function getToken() { export function getToken() {
return fetch({ return fetch({
url: '/qiniu/upload/token', // 假地址 自行替换 url: '/qiniu/upload/token', // 假地址 自行替换
method: 'get' method: 'get'
}); })
} }

View File

@@ -1,9 +1,9 @@
import fetch from 'utils/fetch'; import fetch from '@/utils/fetch'
export function userSearch(name) { export function userSearch(name) {
return fetch({ return fetch({
url: '/search/user', url: '/search/user',
method: 'get', method: 'get',
params: { name } params: { name }
}); })
} }

File diff suppressed because one or more lines are too long

View File

@@ -12,73 +12,73 @@
</template> </template>
<script> <script>
export default { export default {
name: 'BackToTop', name: 'BackToTop',
props: { props: {
visibilityHeight: { visibilityHeight: {
type: Number, type: Number,
default: 400 default: 400
}, },
backPosition: { backPosition: {
type: Number, type: Number,
default: 0 default: 0
}, },
customStyle: { customStyle: {
type: Object, type: Object,
default: { default: {
right: '50px', right: '50px',
bottom: '50px', bottom: '50px',
width: '40px', width: '40px',
height: '40px', height: '40px',
'border-radius': '4px', 'border-radius': '4px',
'line-height': '45px', 'line-height': '45px',
background: '#e7eaf1' background: '#e7eaf1'
}
},
transitionName: {
type: String,
default: 'fade'
}
},
data() {
return {
visible: false,
interval: null
}
},
mounted() {
window.addEventListener('scroll', this.handleScroll)
},
beforeDestroy() {
window.removeEventListener('scroll', this.handleScroll)
if (this.interval) {
clearInterval(this.interval)
}
},
methods: {
handleScroll() {
this.visible = window.pageYOffset > this.visibilityHeight
},
backToTop() {
const start = window.pageYOffset
let i = 0
this.interval = setInterval(() => {
const next = Math.floor(this.easeInOutQuad(10 * i, start, -start, 500))
if (next <= this.backPosition) {
window.scrollTo(0, this.backPosition)
clearInterval(this.interval)
} else {
window.scrollTo(0, next)
} }
}, i++
transitionName: { }, 16.7)
type: String,
default: 'fade'
}
}, },
data() { easeInOutQuad(t, b, c, d) {
return { if ((t /= d / 2) < 1) return c / 2 * t * t + b
visible: false, return -c / 2 * (--t * (t - 2) - 1) + b
interval: null
}
},
mounted() {
window.addEventListener('scroll', this.handleScroll);
},
beforeDestroy() {
window.removeEventListener('scroll', this.handleScroll);
if (this.interval) {
clearInterval(this.interval);
}
},
methods: {
handleScroll() {
this.visible = window.pageYOffset > this.visibilityHeight;
},
backToTop() {
const start = window.pageYOffset;
let i = 0;
this.interval = setInterval(() => {
const next = Math.floor(this.easeInOutQuad(10 * i, start, -start, 500));
if (next <= this.backPosition) {
window.scrollTo(0, this.backPosition);
clearInterval(this.interval)
} else {
window.scrollTo(0, next);
}
i++;
}, 16.7)
},
easeInOutQuad(t, b, c, d) {
if ((t /= d / 2) < 1) return c / 2 * t * t + b;
return -c / 2 * (--t * (t - 2) - 1) + b;
}
} }
} }
}
</script> </script>
<style scoped> <style scoped>

View File

@@ -3,111 +3,111 @@
</template> </template>
<script> <script>
import echarts from 'echarts'; import echarts from 'echarts'
export default { export default {
props: { props: {
className: { className: {
type: String, type: String,
default: 'chart' default: 'chart'
}, },
id: { id: {
type: String, type: String,
default: 'chart' default: 'chart'
}, },
width: { width: {
type: String, type: String,
default: '200px' default: '200px'
}, },
height: { height: {
type: String, type: String,
default: '200px' default: '200px'
} }
}, },
data() { data() {
return { return {
chart: null chart: null
}; }
}, },
mounted() { mounted() {
this.initChart(); this.initChart()
}, },
beforeDestroy() { beforeDestroy() {
if (!this.chart) { if (!this.chart) {
return return
} }
this.chart.dispose(); this.chart.dispose()
this.chart = null; this.chart = null
}, },
methods: { methods: {
initChart() { initChart() {
this.chart = echarts.init(document.getElementById(this.id)); this.chart = echarts.init(document.getElementById(this.id))
const xAxisData = []; const xAxisData = []
const data = []; const data = []
for (let i = 0; i < 30; i++) { for (let i = 0; i < 30; i++) {
xAxisData.push(i + '号'); xAxisData.push(i + '号')
data.push(Math.round(Math.random() * 2 + 3)) data.push(Math.round(Math.random() * 2 + 3))
} }
this.chart.setOption( this.chart.setOption(
{ {
backgroundColor: '#08263a', backgroundColor: '#08263a',
tooltip: { tooltip: {
trigger: 'axis' trigger: 'axis'
}, },
xAxis: { xAxis: {
show: false, show: false,
data: xAxisData data: xAxisData
}, },
visualMap: { visualMap: {
show: false, show: false,
min: 0, min: 0,
max: 50, max: 50,
dimension: 0, dimension: 0,
inRange: { inRange: {
color: ['#4a657a', '#308e92', '#b1cfa5', '#f5d69f', '#f5898b', '#ef5055'] color: ['#4a657a', '#308e92', '#b1cfa5', '#f5d69f', '#f5898b', '#ef5055']
} }
}, },
yAxis: { yAxis: {
axisLine: { axisLine: {
show: false show: false
}, },
axisLabel: { axisLabel: {
textStyle: { textStyle: {
color: '#4a657a' color: '#4a657a'
} }
}, },
splitLine: { splitLine: {
show: true, show: true,
lineStyle: { lineStyle: {
color: '#08263f' color: '#08263f'
} }
}, },
axisTick: {} axisTick: {}
}, },
series: [{ series: [{
type: 'bar', type: 'bar',
data, data,
name: '撸文数', name: '撸文数',
itemStyle: { itemStyle: {
normal: { normal: {
barBorderRadius: 5, barBorderRadius: 5,
shadowBlur: 10, shadowBlur: 10,
shadowColor: '#111' shadowColor: '#111'
} }
}, },
animationEasing: 'elasticOut', animationEasing: 'elasticOut',
animationEasingUpdate: 'elasticOut', animationEasingUpdate: 'elasticOut',
animationDelay(idx) { animationDelay(idx) {
return idx * 20; return idx * 20
}, },
animationDelayUpdate(idx) { animationDelayUpdate(idx) {
return idx * 20; return idx * 20
} }
}] }]
}) })
} }
} }
} }
</script> </script>

View File

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

View File

@@ -3,220 +3,220 @@
</template> </template>
<script> <script>
import echarts from 'echarts'; import echarts from 'echarts'
export default { export default {
props: { props: {
className: { className: {
type: String, type: String,
default: 'chart' default: 'chart'
},
id: {
type: String,
default: 'chart'
},
width: {
type: String,
default: '200px'
},
height: {
type: String,
default: '200px'
}
}, },
data() { id: {
return { type: String,
chart: null default: 'chart'
};
}, },
mounted() { width: {
this.initChart(); type: String,
default: '200px'
}, },
beforeDestroy() { height: {
if (!this.chart) { type: String,
return default: '200px'
}
this.chart.dispose();
this.chart = null;
},
methods: {
initChart() {
this.chart = echarts.init(document.getElementById(this.id));
this.chart.setOption({
backgroundColor: '#394056',
title: {
text: '请求数',
textStyle: {
fontWeight: 'normal',
fontSize: 16,
color: '#F1F1F3'
},
left: '6%'
},
tooltip: {
trigger: 'axis',
axisPointer: {
lineStyle: {
color: '#57617B'
}
}
},
legend: {
icon: 'rect',
itemWidth: 14,
itemHeight: 5,
itemGap: 13,
data: ['移动', '电信', '联通'],
right: '4%',
textStyle: {
fontSize: 12,
color: '#F1F1F3'
}
},
grid: {
left: '3%',
right: '4%',
bottom: '3%',
containLabel: true
},
xAxis: [{
type: 'category',
boundaryGap: false,
axisLine: {
lineStyle: {
color: '#57617B'
}
},
data: ['13:00', '13:05', '13:10', '13:15', '13:20', '13:25', '13:30', '13:35', '13:40', '13:45', '13:50', '13:55']
}],
yAxis: [{
type: 'value',
name: '单位(%',
axisTick: {
show: false
},
axisLine: {
lineStyle: {
color: '#57617B'
}
},
axisLabel: {
margin: 10,
textStyle: {
fontSize: 14
}
},
splitLine: {
lineStyle: {
color: '#57617B'
}
}
}],
series: [{
name: '移动',
type: 'line',
smooth: true,
symbol: 'circle',
symbolSize: 5,
showSymbol: false,
lineStyle: {
normal: {
width: 1
}
},
areaStyle: {
normal: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{
offset: 0,
color: 'rgba(137, 189, 27, 0.3)'
}, {
offset: 0.8,
color: 'rgba(137, 189, 27, 0)'
}], false),
shadowColor: 'rgba(0, 0, 0, 0.1)',
shadowBlur: 10
}
},
itemStyle: {
normal: {
color: 'rgb(137,189,27)',
borderColor: 'rgba(137,189,2,0.27)',
borderWidth: 12
}
},
data: [220, 182, 191, 134, 150, 120, 110, 125, 145, 122, 165, 122]
}, {
name: '电信',
type: 'line',
smooth: true,
symbol: 'circle',
symbolSize: 5,
showSymbol: false,
lineStyle: {
normal: {
width: 1
}
},
areaStyle: {
normal: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{
offset: 0,
color: 'rgba(0, 136, 212, 0.3)'
}, {
offset: 0.8,
color: 'rgba(0, 136, 212, 0)'
}], false),
shadowColor: 'rgba(0, 0, 0, 0.1)',
shadowBlur: 10
}
},
itemStyle: {
normal: {
color: 'rgb(0,136,212)',
borderColor: 'rgba(0,136,212,0.2)',
borderWidth: 12
}
},
data: [120, 110, 125, 145, 122, 165, 122, 220, 182, 191, 134, 150]
}, {
name: '联通',
type: 'line',
smooth: true,
symbol: 'circle',
symbolSize: 5,
showSymbol: false,
lineStyle: {
normal: {
width: 1
}
},
areaStyle: {
normal: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{
offset: 0,
color: 'rgba(219, 50, 51, 0.3)'
}, {
offset: 0.8,
color: 'rgba(219, 50, 51, 0)'
}], false),
shadowColor: 'rgba(0, 0, 0, 0.1)',
shadowBlur: 10
}
},
itemStyle: {
normal: {
color: 'rgb(219,50,51)',
borderColor: 'rgba(219,50,51,0.2)',
borderWidth: 12
}
},
data: [220, 182, 125, 145, 122, 191, 134, 150, 120, 110, 165, 122]
}]
})
}
} }
},
data() {
return {
chart: null
}
},
mounted() {
this.initChart()
},
beforeDestroy() {
if (!this.chart) {
return
}
this.chart.dispose()
this.chart = null
},
methods: {
initChart() {
this.chart = echarts.init(document.getElementById(this.id))
this.chart.setOption({
backgroundColor: '#394056',
title: {
text: '请求数',
textStyle: {
fontWeight: 'normal',
fontSize: 16,
color: '#F1F1F3'
},
left: '6%'
},
tooltip: {
trigger: 'axis',
axisPointer: {
lineStyle: {
color: '#57617B'
}
}
},
legend: {
icon: 'rect',
itemWidth: 14,
itemHeight: 5,
itemGap: 13,
data: ['移动', '电信', '联通'],
right: '4%',
textStyle: {
fontSize: 12,
color: '#F1F1F3'
}
},
grid: {
left: '3%',
right: '4%',
bottom: '3%',
containLabel: true
},
xAxis: [{
type: 'category',
boundaryGap: false,
axisLine: {
lineStyle: {
color: '#57617B'
}
},
data: ['13:00', '13:05', '13:10', '13:15', '13:20', '13:25', '13:30', '13:35', '13:40', '13:45', '13:50', '13:55']
}],
yAxis: [{
type: 'value',
name: '单位(%',
axisTick: {
show: false
},
axisLine: {
lineStyle: {
color: '#57617B'
}
},
axisLabel: {
margin: 10,
textStyle: {
fontSize: 14
}
},
splitLine: {
lineStyle: {
color: '#57617B'
}
}
}],
series: [{
name: '移动',
type: 'line',
smooth: true,
symbol: 'circle',
symbolSize: 5,
showSymbol: false,
lineStyle: {
normal: {
width: 1
}
},
areaStyle: {
normal: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{
offset: 0,
color: 'rgba(137, 189, 27, 0.3)'
}, {
offset: 0.8,
color: 'rgba(137, 189, 27, 0)'
}], false),
shadowColor: 'rgba(0, 0, 0, 0.1)',
shadowBlur: 10
}
},
itemStyle: {
normal: {
color: 'rgb(137,189,27)',
borderColor: 'rgba(137,189,2,0.27)',
borderWidth: 12
}
},
data: [220, 182, 191, 134, 150, 120, 110, 125, 145, 122, 165, 122]
}, {
name: '电信',
type: 'line',
smooth: true,
symbol: 'circle',
symbolSize: 5,
showSymbol: false,
lineStyle: {
normal: {
width: 1
}
},
areaStyle: {
normal: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{
offset: 0,
color: 'rgba(0, 136, 212, 0.3)'
}, {
offset: 0.8,
color: 'rgba(0, 136, 212, 0)'
}], false),
shadowColor: 'rgba(0, 0, 0, 0.1)',
shadowBlur: 10
}
},
itemStyle: {
normal: {
color: 'rgb(0,136,212)',
borderColor: 'rgba(0,136,212,0.2)',
borderWidth: 12
}
},
data: [120, 110, 125, 145, 122, 165, 122, 220, 182, 191, 134, 150]
}, {
name: '联通',
type: 'line',
smooth: true,
symbol: 'circle',
symbolSize: 5,
showSymbol: false,
lineStyle: {
normal: {
width: 1
}
},
areaStyle: {
normal: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{
offset: 0,
color: 'rgba(219, 50, 51, 0.3)'
}, {
offset: 0.8,
color: 'rgba(219, 50, 51, 0)'
}], false),
shadowColor: 'rgba(0, 0, 0, 0.1)',
shadowBlur: 10
}
},
itemStyle: {
normal: {
color: 'rgb(219,50,51)',
borderColor: 'rgba(219,50,51,0.2)',
borderWidth: 12
}
},
data: [220, 182, 125, 145, 122, 191, 134, 150, 120, 110, 165, 122]
}]
})
}
}
} }
</script> </script>

View File

@@ -3,266 +3,265 @@
</template> </template>
<script> <script>
import echarts from 'echarts'; import echarts from 'echarts'
export default { export default {
props: { props: {
className: { className: {
type: String, type: String,
default: 'chart' default: 'chart'
},
id: {
type: String,
default: 'chart'
},
width: {
type: String,
default: '200px'
},
height: {
type: String,
default: '200px'
}
}, },
data() { id: {
return { type: String,
chart: null default: 'chart'
};
}, },
mounted() { width: {
this.initChart(); type: String,
this.chart = null; default: '200px'
}, },
beforeDestroy() { height: {
if (!this.chart) { type: String,
return default: '200px'
} }
this.chart.dispose(); },
this.chart = null; data() {
}, return {
methods: { chart: null
initChart() { }
this.chart = echarts.init(document.getElementById(this.id)); },
const xData = (function() { mounted() {
const data = []; this.initChart()
for (let i = 1; i < 13; i++) { this.chart = null
data.push(i + '月份'); },
beforeDestroy() {
if (!this.chart) {
return
}
this.chart.dispose()
this.chart = null
},
methods: {
initChart() {
this.chart = echarts.init(document.getElementById(this.id))
const xData = (function() {
const data = []
for (let i = 1; i < 13; i++) {
data.push(i + '月份')
}
return data
}())
this.chart.setOption({
backgroundColor: '#344b58',
title: {
text: '统计',
x: '4%',
textStyle: {
color: '#fff',
fontSize: '22'
},
subtextStyle: {
color: '#90979c',
fontSize: '16'
} }
return data; },
}()); tooltip: {
this.chart.setOption({ trigger: 'axis',
backgroundColor: '#344b58', axisPointer: {
title: {
text: '统计',
x: '4%',
textStyle: {
color: '#fff',
fontSize: '22'
},
subtextStyle: {
color: '#90979c',
fontSize: '16'
}
},
tooltip: {
trigger: 'axis',
axisPointer: {
textStyle: {
color: '#fff'
}
}
},
grid: {
borderWidth: 0,
top: 110,
bottom: 95,
textStyle: { textStyle: {
color: '#fff' color: '#fff'
} }
},
legend: {
x: '15%',
top: '10%',
textStyle: {
color: '#90979c'
},
data: ['女', '男', '平均']
},
calculable: true,
xAxis: [{
type: 'category',
axisLine: {
lineStyle: {
color: '#90979c'
}
},
splitLine: {
show: false
},
axisTick: {
show: false
},
splitArea: {
show: false
},
axisLabel: {
interval: 0
},
data: xData
}],
yAxis: [{
type: 'value',
splitLine: {
show: false
},
axisLine: {
lineStyle: {
color: '#90979c'
}
},
axisTick: {
show: false
},
axisLabel: {
interval: 0
},
splitArea: {
show: false
}
}],
dataZoom: [{
show: true,
height: 30,
xAxisIndex: [
0
],
bottom: 30,
start: 10,
end: 80,
handleIcon: 'path://M306.1,413c0,2.2-1.8,4-4,4h-59.8c-2.2,0-4-1.8-4-4V200.8c0-2.2,1.8-4,4-4h59.8c2.2,0,4,1.8,4,4V413z',
handleSize: '110%',
handleStyle: {
color: '#d3dee5'
},
textStyle: {
color: '#fff' },
borderColor: '#90979c'
}, {
type: 'inside',
show: true,
height: 15,
start: 1,
end: 35
}],
series: [{
name: '女',
type: 'bar',
stack: '总量',
barMaxWidth: 35,
barGap: '10%',
itemStyle: {
normal: {
color: 'rgba(255,144,128,1)',
label: {
show: true,
textStyle: {
color: '#fff'
},
position: 'insideTop',
formatter(p) {
return p.value > 0 ? p.value : '';
}
}
}
},
data: [
709,
1917,
2455,
2610,
1719,
1433,
1544,
3285,
5208,
3372,
2484,
4078
]
},
{
name: '男',
type: 'bar',
stack: '总量',
itemStyle: {
normal: {
color: 'rgba(0,191,183,1)',
barBorderRadius: 0,
label: {
show: true,
position: 'top',
formatter(p) {
return p.value > 0 ? p.value : '';
}
}
}
},
data: [
327,
1776,
507,
1200,
800,
482,
204,
1390,
1001,
951,
381,
220
]
}, {
name: '平均',
type: 'line',
stack: '总量',
symbolSize: 10,
symbol: 'circle',
itemStyle: {
normal: {
color: 'rgba(252,230,48,1)',
barBorderRadius: 0,
label: {
show: true,
position: 'top',
formatter(p) {
return p.value > 0 ? p.value : '';
}
}
}
},
data: [
1036,
3693,
2962,
3810,
2519,
1915,
1748,
4675,
6209,
4323,
2865,
4298
]
} }
},
grid: {
borderWidth: 0,
top: 110,
bottom: 95,
textStyle: {
color: '#fff'
}
},
legend: {
x: '15%',
top: '10%',
textStyle: {
color: '#90979c'
},
data: ['女', '男', '平均']
},
calculable: true,
xAxis: [{
type: 'category',
axisLine: {
lineStyle: {
color: '#90979c'
}
},
splitLine: {
show: false
},
axisTick: {
show: false
},
splitArea: {
show: false
},
axisLabel: {
interval: 0
},
data: xData
}],
yAxis: [{
type: 'value',
splitLine: {
show: false
},
axisLine: {
lineStyle: {
color: '#90979c'
}
},
axisTick: {
show: false
},
axisLabel: {
interval: 0
},
splitArea: {
show: false
}
}],
dataZoom: [{
show: true,
height: 30,
xAxisIndex: [
0
],
bottom: 30,
start: 10,
end: 80,
handleIcon: 'path://M306.1,413c0,2.2-1.8,4-4,4h-59.8c-2.2,0-4-1.8-4-4V200.8c0-2.2,1.8-4,4-4h59.8c2.2,0,4,1.8,4,4V413z',
handleSize: '110%',
handleStyle: {
color: '#d3dee5'
},
textStyle: {
color: '#fff' },
borderColor: '#90979c'
}, {
type: 'inside',
show: true,
height: 15,
start: 1,
end: 35
}],
series: [{
name: '女',
type: 'bar',
stack: '总量',
barMaxWidth: 35,
barGap: '10%',
itemStyle: {
normal: {
color: 'rgba(255,144,128,1)',
label: {
show: true,
textStyle: {
color: '#fff'
},
position: 'insideTop',
formatter(p) {
return p.value > 0 ? p.value : ''
}
}
}
},
data: [
709,
1917,
2455,
2610,
1719,
1433,
1544,
3285,
5208,
3372,
2484,
4078
] ]
}) },
}
{
name: '男',
type: 'bar',
stack: '总量',
itemStyle: {
normal: {
color: 'rgba(0,191,183,1)',
barBorderRadius: 0,
label: {
show: true,
position: 'top',
formatter(p) {
return p.value > 0 ? p.value : ''
}
}
}
},
data: [
327,
1776,
507,
1200,
800,
482,
204,
1390,
1001,
951,
381,
220
]
}, {
name: '平均',
type: 'line',
stack: '总量',
symbolSize: 10,
symbol: 'circle',
itemStyle: {
normal: {
color: 'rgba(252,230,48,1)',
barBorderRadius: 0,
label: {
show: true,
position: 'top',
formatter(p) {
return p.value > 0 ? p.value : ''
}
}
}
},
data: [
1036,
3693,
2962,
3810,
2519,
1915,
1748,
4675,
6209,
4323,
2865,
4298
]
}
]
})
} }
} }
}
</script> </script>

View File

@@ -5,59 +5,59 @@
</template> </template>
<script> <script>
import Dropzone from 'dropzone'; import Dropzone from 'dropzone'
import 'dropzone/dist/dropzone.css'; import 'dropzone/dist/dropzone.css'
// import { getToken } from 'api/qiniu'; // import { getToken } from 'api/qiniu';
Dropzone.autoDiscover = false; Dropzone.autoDiscover = false
export default { export default {
data() { data() {
return { return {
dropzone: '', dropzone: '',
initOnce: true initOnce: true
} }
}, },
mounted() { mounted() {
const element = document.getElementById(this.id); const element = document.getElementById(this.id)
const vm = this; const vm = this
this.dropzone = new Dropzone(element, { this.dropzone = new Dropzone(element, {
clickable: this.clickable, clickable: this.clickable,
thumbnailWidth: this.thumbnailWidth, thumbnailWidth: this.thumbnailWidth,
thumbnailHeight: this.thumbnailHeight, thumbnailHeight: this.thumbnailHeight,
maxFiles: this.maxFiles, maxFiles: this.maxFiles,
maxFilesize: this.maxFilesize, maxFilesize: this.maxFilesize,
dictRemoveFile: 'Remove', dictRemoveFile: 'Remove',
addRemoveLinks: this.showRemoveLink, addRemoveLinks: this.showRemoveLink,
acceptedFiles: this.acceptedFiles, acceptedFiles: this.acceptedFiles,
autoProcessQueue: this.autoProcessQueue, autoProcessQueue: this.autoProcessQueue,
dictDefaultMessage: '<i style="margin-top: 3em;display: inline-block" class="material-icons">' + this.defaultMsg + '</i><br>Drop files here to upload', dictDefaultMessage: '<i style="margin-top: 3em;display: inline-block" class="material-icons">' + this.defaultMsg + '</i><br>Drop files here to upload',
dictMaxFilesExceeded: '只能一个图', dictMaxFilesExceeded: '只能一个图',
previewTemplate: '<div class="dz-preview dz-file-preview"> <div class="dz-image" style="width:' + this.thumbnailWidth + 'px;height:' + this.thumbnailHeight + 'px" ><img style="width:' + this.thumbnailWidth + 'px;height:' + this.thumbnailHeight + 'px" data-dz-thumbnail /></div> <div class="dz-details"><div class="dz-size"><span data-dz-size></span></div> <div class="dz-progress"><span class="dz-upload" data-dz-uploadprogress></span></div> <div class="dz-error-message"><span data-dz-errormessage></span></div> <div class="dz-success-mark"> <i class="material-icons">done</i> </div> <div class="dz-error-mark"><i class="material-icons">error</i></div></div>', previewTemplate: '<div class="dz-preview dz-file-preview"> <div class="dz-image" style="width:' + this.thumbnailWidth + 'px;height:' + this.thumbnailHeight + 'px" ><img style="width:' + this.thumbnailWidth + 'px;height:' + this.thumbnailHeight + 'px" data-dz-thumbnail /></div> <div class="dz-details"><div class="dz-size"><span data-dz-size></span></div> <div class="dz-progress"><span class="dz-upload" data-dz-uploadprogress></span></div> <div class="dz-error-message"><span data-dz-errormessage></span></div> <div class="dz-success-mark"> <i class="material-icons">done</i> </div> <div class="dz-error-mark"><i class="material-icons">error</i></div></div>',
init() { init() {
const val = vm.defaultImg; const val = vm.defaultImg
if (!val) return; if (!val) return
if (Array.isArray(val)) { if (Array.isArray(val)) {
if (val.length === 0) return; if (val.length === 0) return
val.map((v, i) => { val.map((v, i) => {
const mockFile = { name: 'name' + i, size: 12345, url: v }; const mockFile = { name: 'name' + i, size: 12345, url: v }
this.options.addedfile.call(this, mockFile); this.options.addedfile.call(this, mockFile)
this.options.thumbnail.call(this, mockFile, v); this.options.thumbnail.call(this, mockFile, v)
mockFile.previewElement.classList.add('dz-success'); mockFile.previewElement.classList.add('dz-success')
mockFile.previewElement.classList.add('dz-complete'); mockFile.previewElement.classList.add('dz-complete')
vm.initOnce = false; vm.initOnce = false
return true; return true
}) })
} else { } else {
const mockFile = { name: 'name', size: 12345, url: val }; const mockFile = { name: 'name', size: 12345, url: val }
this.options.addedfile.call(this, mockFile); this.options.addedfile.call(this, mockFile)
this.options.thumbnail.call(this, mockFile, val); this.options.thumbnail.call(this, mockFile, val)
mockFile.previewElement.classList.add('dz-success'); mockFile.previewElement.classList.add('dz-success')
mockFile.previewElement.classList.add('dz-complete'); mockFile.previewElement.classList.add('dz-complete')
vm.initOnce = false; vm.initOnce = false
} }
}, },
accept: (file, done) => { accept: (file, done) => {
/* 七牛*/ /* 七牛*/
// const token = this.$store.getters.token; // const token = this.$store.getters.token;
// getToken(token).then(response => { // getToken(token).then(response => {
@@ -66,142 +66,140 @@
// file.url = response.data.qiniu_url; // file.url = response.data.qiniu_url;
// done(); // done();
// }) // })
done(); done()
}, },
sending: (file, xhr, formData) => { sending: (file, xhr, formData) => {
/* 七牛*/
console.log(file, xhr, formData)
// formData.append('token', file.token); // formData.append('token', file.token);
// formData.append('key', file.key); // formData.append('key', file.key);
vm.initOnce = false; vm.initOnce = false
}
});
if (this.couldPaste) {
document.addEventListener('paste', this.pasteImg)
} }
})
this.dropzone.on('success', file => { if (this.couldPaste) {
vm.$emit('dropzone-success', file, vm.dropzone.element) document.addEventListener('paste', this.pasteImg)
}); }
this.dropzone.on('addedfile', file => {
vm.$emit('dropzone-fileAdded', file)
});
this.dropzone.on('removedfile', file => {
vm.$emit('dropzone-removedFile', file)
});
this.dropzone.on('error', (file, error, xhr) => {
vm.$emit('dropzone-error', file, error, xhr)
});
this.dropzone.on('successmultiple', (file, error, xhr) => {
vm.$emit('dropzone-successmultiple', file, error, xhr)
});
},
methods: {
removeAllFiles() {
this.dropzone.removeAllFiles(true)
},
processQueue() {
this.dropzone.processQueue()
},
pasteImg(event) {
const items = (event.clipboardData || event.originalEvent.clipboardData).items;
if (items[0].kind === 'file') {
this.dropzone.addFile(items[0].getAsFile())
}
},
initImages(val) {
if (!val) return;
if (Array.isArray(val)) {
val.map((v, i) => {
const mockFile = { name: 'name' + i, size: 12345, url: v };
this.dropzone.options.addedfile.call(this.dropzone, mockFile);
this.dropzone.options.thumbnail.call(this.dropzone, mockFile, v);
mockFile.previewElement.classList.add('dz-success');
mockFile.previewElement.classList.add('dz-complete');
return true
})
} else {
const mockFile = { name: 'name', size: 12345, url: val };
this.dropzone.options.addedfile.call(this.dropzone, mockFile);
this.dropzone.options.thumbnail.call(this.dropzone, mockFile, val);
mockFile.previewElement.classList.add('dz-success');
mockFile.previewElement.classList.add('dz-complete');
}
}
this.dropzone.on('success', file => {
vm.$emit('dropzone-success', file, vm.dropzone.element)
})
this.dropzone.on('addedfile', file => {
vm.$emit('dropzone-fileAdded', file)
})
this.dropzone.on('removedfile', file => {
vm.$emit('dropzone-removedFile', file)
})
this.dropzone.on('error', (file, error, xhr) => {
vm.$emit('dropzone-error', file, error, xhr)
})
this.dropzone.on('successmultiple', (file, error, xhr) => {
vm.$emit('dropzone-successmultiple', file, error, xhr)
})
},
methods: {
removeAllFiles() {
this.dropzone.removeAllFiles(true)
}, },
destroyed() { processQueue() {
document.removeEventListener('paste', this.pasteImg); this.dropzone.processQueue()
this.dropzone.destroy();
}, },
watch: { pasteImg(event) {
defaultImg(val) { const items = (event.clipboardData || event.originalEvent.clipboardData).items
if (val.length === 0) { if (items[0].kind === 'file') {
this.initOnce = false; this.dropzone.addFile(items[0].getAsFile())
return;
}
if (!this.initOnce) return;
this.initImages(val);
this.initOnce = false;
} }
}, },
props: { initImages(val) {
id: { if (!val) return
type: String, if (Array.isArray(val)) {
required: true val.map((v, i) => {
}, const mockFile = { name: 'name' + i, size: 12345, url: v }
url: { this.dropzone.options.addedfile.call(this.dropzone, mockFile)
type: String, this.dropzone.options.thumbnail.call(this.dropzone, mockFile, v)
required: true mockFile.previewElement.classList.add('dz-success')
}, mockFile.previewElement.classList.add('dz-complete')
clickable: { return true
type: Boolean, })
default: true } else {
}, const mockFile = { name: 'name', size: 12345, url: val }
defaultMsg: { this.dropzone.options.addedfile.call(this.dropzone, mockFile)
type: String, this.dropzone.options.thumbnail.call(this.dropzone, mockFile, val)
default: '上传图片' mockFile.previewElement.classList.add('dz-success')
}, mockFile.previewElement.classList.add('dz-complete')
acceptedFiles: {
type: String
},
thumbnailHeight: {
type: Number,
default: 200
},
thumbnailWidth: {
type: Number,
default: 200
},
showRemoveLink: {
type: Boolean,
default: true
},
maxFilesize: {
type: Number,
default: 2
},
maxFiles: {
type: Number,
default: 3
},
autoProcessQueue: {
type: Boolean,
default: true
},
useCustomDropzoneOptions: {
type: Boolean,
default: false
},
defaultImg: {
default: false
},
couldPaste: {
default: false
} }
} }
},
destroyed() {
document.removeEventListener('paste', this.pasteImg)
this.dropzone.destroy()
},
watch: {
defaultImg(val) {
if (val.length === 0) {
this.initOnce = false
return
}
if (!this.initOnce) return
this.initImages(val)
this.initOnce = false
}
},
props: {
id: {
type: String,
required: true
},
url: {
type: String,
required: true
},
clickable: {
type: Boolean,
default: true
},
defaultMsg: {
type: String,
default: '上传图片'
},
acceptedFiles: {
type: String
},
thumbnailHeight: {
type: Number,
default: 200
},
thumbnailWidth: {
type: Number,
default: 200
},
showRemoveLink: {
type: Boolean,
default: true
},
maxFilesize: {
type: Number,
default: 2
},
maxFiles: {
type: Number,
default: 3
},
autoProcessQueue: {
type: Boolean,
default: true
},
useCustomDropzoneOptions: {
type: Boolean,
default: false
},
defaultImg: {
default: false
},
couldPaste: {
default: false
}
} }
}
</script> </script>
<style scoped> <style scoped>

View File

@@ -30,19 +30,19 @@
</template> </template>
<script> <script>
export default { export default {
name: 'errLog', name: 'errLog',
props: { props: {
logsList: { logsList: {
type: Array type: Array
} }
}, },
data() { data() {
return { return {
dialogTableVisible: false dialogTableVisible: false
}
} }
} }
}
</script> </script>
<style scoped> <style scoped>

View File

@@ -0,0 +1,13 @@
<template>
<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:#4AB7BD; color:#fff; position: absolute; top: 50px; border: 0; right: 0;"
aria-hidden="true">
<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"
fill="currentColor" style="transform-origin: 130px 106px;" class="octo-arm"></path>
<path d="M115.0,115.0 C114.9,115.1 118.7,116.5 119.8,115.4 L133.7,101.6 C136.9,99.2 139.9,98.4 142.2,98.6 C133.8,88.0 127.5,74.4 143.8,58.0 C148.5,53.4 154.0,51.2 159.7,51.0 C160.3,49.4 163.2,43.6 171.4,40.1 C171.4,40.1 176.1,42.5 178.8,56.2 C183.1,58.6 187.2,61.8 190.9,65.4 C194.5,69.0 197.7,73.2 200.1,77.6 C213.8,80.2 216.3,84.9 216.3,84.9 C212.7,93.1 206.9,96.0 205.4,96.6 C205.1,102.4 203.0,107.8 198.3,112.5 C181.9,128.9 168.3,122.5 157.7,114.1 C157.9,116.9 156.7,120.9 152.7,124.9 L141.0,136.5 C139.8,137.7 141.6,141.9 141.8,141.8 Z"
fill="currentColor" class="octo-body"></path>
</svg>
</a>
</template>

View File

@@ -13,19 +13,19 @@
</template> </template>
<script> <script>
export default { export default {
name: 'hamburger', name: 'hamburger',
props: { props: {
isActive: { isActive: {
type: Boolean, type: Boolean,
default: false default: false
}, },
toggleClick: { toggleClick: {
type: Function, type: Function,
default: null default: null
}
} }
} }
}
</script> </script>
<style scoped> <style scoped>

View File

@@ -5,18 +5,18 @@
</template> </template>
<script> <script>
export default { export default {
name: 'icon-svg', name: 'icon-svg',
props: { props: {
iconClass: { iconClass: {
type: String, type: String,
required: true required: true
} }
}, },
computed: { computed: {
iconName() { iconName() {
return `#icon-${this.iconClass}` return `#icon-${this.iconClass}`
}
} }
} }
}
</script> </script>

View File

@@ -37,5 +37,5 @@ const langBag = {
lowestPx: 'The lowest pixel in the image: ' lowestPx: 'The lowest pixel in the image: '
} }
} }
}; }
export default langBag; export default langBag

View File

@@ -1,40 +1,40 @@
<template> <template>
<div class="material-input__component" :class="computedClasses"> <div class="material-input__component" :class="computedClasses">
<input v-if="type === 'email'" type="email" class="material-input" :name="name" :id="id" :placeholder="placeholder" v-model="valueCopy" <input v-if="type === 'email'" type="email" class="material-input" :name="name" :id="id" :placeholder="placeholder" v-model="valueCopy"
:readonly="readonly" :disabled="disabled" :autocomplete="autocomplete" :required="required" @focus="handleFocus(true)" :readonly="readonly" :disabled="disabled" :autocomplete="autocomplete" :required="required" @focus="handleFocus(true)"
@blur="handleFocus(false)" @input="handleModelInput"> @blur="handleFocus(false)" @input="handleModelInput">
<input v-if="type === 'url'" type="url" class="material-input" :name="name" :id="id" :placeholder="placeholder" v-model="valueCopy" <input v-if="type === 'url'" type="url" class="material-input" :name="name" :id="id" :placeholder="placeholder" v-model="valueCopy"
:readonly="readonly" :disabled="disabled" :autocomplete="autocomplete" :required="required" @focus="handleFocus(true)" :readonly="readonly" :disabled="disabled" :autocomplete="autocomplete" :required="required" @focus="handleFocus(true)"
@blur="handleFocus(false)" @input="handleModelInput"> @blur="handleFocus(false)" @input="handleModelInput">
<input v-if="type === 'number'" type="number" class="material-input" :name="name" :id="id" :placeholder="placeholder" v-model="valueCopy" <input v-if="type === 'number'" type="number" class="material-input" :name="name" :id="id" :placeholder="placeholder" v-model="valueCopy"
:readonly="readonly" :disabled="disabled" :autocomplete="autocomplete" :max="max" :min="min" :minlength="minlength" :maxlength="maxlength" :readonly="readonly" :disabled="disabled" :autocomplete="autocomplete" :max="max" :min="min" :minlength="minlength" :maxlength="maxlength"
:required="required" @focus="handleFocus(true)" @blur="handleFocus(false)" @input="handleModelInput"> :required="required" @focus="handleFocus(true)" @blur="handleFocus(false)" @input="handleModelInput">
<input v-if="type === 'password'" type="password" class="material-input" :name="name" :id="id" :placeholder="placeholder" <input v-if="type === 'password'" type="password" class="material-input" :name="name" :id="id" :placeholder="placeholder"
v-model="valueCopy" :readonly="readonly" :disabled="disabled" :autocomplete="autocomplete" :max="max" :min="min" :required="required" v-model="valueCopy" :readonly="readonly" :disabled="disabled" :autocomplete="autocomplete" :max="max" :min="min" :required="required"
@focus="handleFocus(true)" @blur="handleFocus(false)" @input="handleModelInput"> @focus="handleFocus(true)" @blur="handleFocus(false)" @input="handleModelInput">
<input v-if="type === 'tel'" type="tel" class="material-input" :name="name" :id="id" :placeholder="placeholder" v-model="valueCopy" <input v-if="type === 'tel'" type="tel" class="material-input" :name="name" :id="id" :placeholder="placeholder" v-model="valueCopy"
:readonly="readonly" :disabled="disabled" :autocomplete="autocomplete" :required="required" @focus="handleFocus(true)" :readonly="readonly" :disabled="disabled" :autocomplete="autocomplete" :required="required" @focus="handleFocus(true)"
@blur="handleFocus(false)" @input="handleModelInput"> @blur="handleFocus(false)" @input="handleModelInput">
<input v-if="type === 'text'" type="text" class="material-input" :name="name" :id="id" :placeholder="placeholder" v-model="valueCopy" <input v-if="type === 'text'" type="text" class="material-input" :name="name" :id="id" :placeholder="placeholder" v-model="valueCopy"
:readonly="readonly" :disabled="disabled" :autocomplete="autocomplete" :minlength="minlength" :maxlength="maxlength" :required="required" :readonly="readonly" :disabled="disabled" :autocomplete="autocomplete" :minlength="minlength" :maxlength="maxlength"
@focus="handleFocus(true)" @blur="handleFocus(false)" @input="handleModelInput"> :required="required" @focus="handleFocus(true)" @blur="handleFocus(false)" @input="handleModelInput">
<span class="material-input-bar"></span> <span class="material-input-bar"></span>
<label class="material-label"> <label class="material-label">
<slot></slot> <slot></slot>
</label> </label>
<div v-if="errorMessages" class="material-errors"> <div v-if="errorMessages" class="material-errors">
<div v-for="error in computedErrors" class="material-error" :key='error'> <div v-for="error in computedErrors" class="material-error" :key='error'>
{{ error }} {{ error }}
</div> </div>
</div> </div>
</div> </div>
</template> </template>
<script> <script>
// source:https://github.com/wemake-services/vue-material-input/blob/master/src/components/MaterialInput.vue // source:https://github.com/wemake-services/vue-material-input/blob/master/src/components/MaterialInput.vue
export default { export default {
name: 'material-input', name: 'material-input',
computed: { computed: {
computedErrors() { computedErrors() {

View File

@@ -0,0 +1,114 @@
<template>
<div class='simplemde-container' :style="{height:height+'px',zIndex:zIndex}">
<textarea :id='id'>
</textarea>
</div>
</template>
<script>
import 'simplemde/dist/simplemde.min.css'
import SimpleMDE from 'simplemde'
export default {
name: 'simplemde-md',
props: {
value: String,
id: {
type: String,
default: 'markdown-editor'
},
autofocus: {
type: Boolean,
default: false
},
placeholder: {
type: String,
default: ''
},
height: {
type: Number,
default: 150
},
zIndex: {
type: Number,
default: 10
},
toolbar: {
type: Array
}
},
data() {
return {
simplemde: null,
hasChange: false
}
},
watch: {
value(val) {
if (val === this.simplemde.value() && !this.hasChange) return
this.simplemde.value(val)
}
},
mounted() {
this.simplemde = new SimpleMDE({
element: document.getElementById(this.id),
autofocus: this.autofocus,
toolbar: this.toolbar,
spellChecker: false,
insertTexts: {
link: ['[', ']( )']
},
// hideIcons: ['guide', 'heading', 'quote', 'image', 'preview', 'side-by-side', 'fullscreen'],
placeholder: this.placeholder
})
if (this.value) {
this.simplemde.value(this.value)
}
this.simplemde.codemirror.on('change', () => {
if (this.hasChange) {
this.hasChange = true
}
this.$emit('input', this.simplemde.value())
})
},
destroyed() {
this.simplemde = null
}
}
</script>
<style>
.simplemde-container .CodeMirror {
/*height: 150px;*/
min-height: 150px;
}
.simplemde-container .CodeMirror-scroll {
min-height: 150px;
}
.simplemde-container .CodeMirror-code {
padding-bottom: 40px;
}
.simplemde-container .editor-statusbar {
display: none;
}
.simplemde-container .CodeMirror .CodeMirror-code .cm-link {
color: #1482F0;
}
.simplemde-container .CodeMirror .CodeMirror-code .cm-string.cm-url {
color: #2d3b4d;
font-weight: bold;
}
.simplemde-container .CodeMirror .CodeMirror-code .cm-formatting-link-string.cm-url {
padding: 0 2px;
font-weight: bold;
color: #E61E1E;
}
</style>

View File

@@ -1,114 +0,0 @@
<template>
<div class='simplemde-container' :style="{height:height+'px',zIndex:zIndex}">
<textarea :id='id'>
</textarea>
</div>
</template>
<script>
import 'simplemde/dist/simplemde.min.css';
import SimpleMDE from 'simplemde';
export default {
name: 'Sticky',
props: {
value: String,
id: {
type: String,
default: 'markdown-editor'
},
autofocus: {
type: Boolean,
default: false
},
placeholder: {
type: String,
default: ''
},
height: {
type: Number,
default: 150
},
zIndex: {
type: Number,
default: 10
},
toolbar: {
type: Array
}
},
data() {
return {
simplemde: null,
hasChange: false
};
},
watch: {
value(val) {
if (val === this.simplemde.value() && !this.hasChange) return;
this.simplemde.value(val);
}
},
mounted() {
this.simplemde = new SimpleMDE({
element: document.getElementById(this.id),
autofocus: this.autofocus,
toolbar: this.toolbar,
spellChecker: false,
insertTexts: {
link: ['[', ']( )']
},
// hideIcons: ['guide', 'heading', 'quote', 'image', 'preview', 'side-by-side', 'fullscreen'],
placeholder: this.placeholder
});
if (this.value) {
this.simplemde.value(this.value);
}
this.simplemde.codemirror.on('change', () => {
if (this.hasChange) {
this.hasChange = true
}
this.$emit('input', this.simplemde.value());
});
},
destroyed() {
this.simplemde = null;
}
};
</script>
<style>
.simplemde-container .CodeMirror {
/*height: 150px;*/
min-height: 150px;
}
.simplemde-container .CodeMirror-scroll {
min-height: 150px;
}
.simplemde-container .CodeMirror-code {
padding-bottom: 40px;
}
.simplemde-container .editor-statusbar {
display: none;
}
.simplemde-container .CodeMirror .CodeMirror-code .cm-link {
color: #1482F0;
}
.simplemde-container .CodeMirror .CodeMirror-code .cm-string.cm-url {
color: #2d3b4d;
font-weight: bold;
}
.simplemde-container .CodeMirror .CodeMirror-code .cm-formatting-link-string.cm-url {
padding: 0 2px;
font-weight: bold;
color: #E61E1E;
}
</style>

View File

@@ -10,27 +10,27 @@
</template> </template>
<script> <script>
export default { export default {
name: 'PanThumb', name: 'PanThumb',
props: { props: {
image: { image: {
type: String, type: String,
required: true required: true
}, },
zIndex: { zIndex: {
type: Number, type: Number,
default: 100 default: 100
}, },
width: { width: {
type: String, type: String,
default: '150px' default: '150px'
}, },
height: { height: {
type: String, type: String,
default: '150px' default: '150px'
}
} }
}; }
}
</script> </script>
<style scoped> <style scoped>

View File

@@ -7,41 +7,42 @@
</template> </template>
<script> <script>
import screenfull from 'screenfull'; import screenfull from 'screenfull'
export default {
name: 'hamburger', export default {
props: { name: 'hamburger',
width: { props: {
type: Number, width: {
default: 22 type: Number,
}, default: 22
height: {
type: Number,
default: 22
},
fill: {
type: String,
default: '#48576a'
}
}, },
data() { height: {
return { type: Number,
isFullscreen: false default: 22
}
}, },
methods: { fill: {
click() { type: String,
if (!screenfull.enabled) { default: '#48576a'
this.$message({ }
message: 'you browser can not work', },
type: 'warning' data() {
}); return {
return false; isFullscreen: false
} }
screenfull.toggle(); },
methods: {
click() {
if (!screenfull.enabled) {
this.$message({
message: 'you browser can not work',
type: 'warning'
})
return false
} }
screenfull.toggle()
} }
} }
}
</script> </script>
<style scoped> <style scoped>

View File

@@ -5,16 +5,16 @@
</template> </template>
<script> <script>
export default { export default {
name: 'Pane', name: 'Pane',
data() { data() {
const classes = ['Pane', this.$parent.split, 'className']; const classes = ['Pane', this.$parent.split, 'className']
return { return {
classes: classes.join(' '), classes: classes.join(' '),
percent: 50 percent: 50
} }
} }
} }
</script> </script>
<style scoped> <style scoped>

View File

@@ -3,26 +3,26 @@
</template> </template>
<script> <script>
export default { export default {
props: { props: {
split: { split: {
validator(value) { validator(value) {
return ['vertical', 'horizontal'].indexOf(value) >= 0 return ['vertical', 'horizontal'].indexOf(value) >= 0
},
required: true
}, },
onMouseDown: { required: true
type: Function,
required: true
}
}, },
data() { onMouseDown: {
const classes = ['Resizer', this.split, 'className']; type: Function,
return { required: true
classes: classes.join(' ') }
} },
data() {
const classes = ['Resizer', this.split, 'className']
return {
classes: classes.join(' ')
} }
} }
}
</script> </script>
<style scoped> <style scoped>

View File

@@ -11,86 +11,86 @@
</template> </template>
<script> <script>
import Resizer from './Resizer'; import Resizer from './Resizer'
import Pane from './Pane'; import Pane from './Pane'
export default { export default {
name: 'splitPane', name: 'splitPane',
components: { Resizer, Pane }, components: { Resizer, Pane },
props: { props: {
margin: { margin: {
type: Number, type: Number,
default: 10 default: 10
},
split: {
validator(value) {
return ['vertical', 'horizontal'].indexOf(value) >= 0
}, },
split: { required: true
validator(value) { }
return ['vertical', 'horizontal'].indexOf(value) >= 0 },
}, data() {
required: true return {
active: false,
hasMoved: false,
height: null,
percent: 50,
type: this.split === 'vertical' ? 'width' : 'height',
resizeType: this.split === 'vertical' ? 'left' : 'top'
}
},
computed: {
userSelect() {
return this.active ? 'none' : ''
},
cursor() {
return this.active ? 'col-resize' : ''
}
},
methods: {
onClick() {
if (!this.hasMoved) {
this.percent = 50
this.$emit('resize')
} }
}, },
data() { onMouseDown() {
return { this.active = true
active: false, this.hasMoved = false
hasMoved: false,
height: null,
percent: 50,
type: this.split === 'vertical' ? 'width' : 'height',
resizeType: this.split === 'vertical' ? 'left' : 'top'
}
}, },
computed: { onMouseUp() {
userSelect() { this.active = false
return this.active ? 'none' : ''
},
cursor() {
return this.active ? 'col-resize' : ''
}
}, },
methods: { onMouseMove(e) {
onClick() { if (e.buttons === 0 || e.which === 0) {
if (!this.hasMoved) { this.active = false
this.percent = 50; }
this.$emit('resize'); if (this.active) {
} let offset = 0
}, let target = e.currentTarget
onMouseDown() { if (this.split === 'vertical') {
this.active = true; while (target) {
this.hasMoved = false; offset += target.offsetLeft
}, target = target.offsetParent
onMouseUp() {
this.active = false;
},
onMouseMove(e) {
if (e.buttons === 0 || e.which === 0) {
this.active = false;
}
if (this.active) {
let offset = 0;
let target = e.currentTarget;
if (this.split === 'vertical') {
while (target) {
offset += target.offsetLeft;
target = target.offsetParent;
}
} else {
while (target) {
offset += target.offsetTop;
target = target.offsetParent;
}
} }
} else {
while (target) {
offset += target.offsetTop
target = target.offsetParent
}
}
const currentPage = this.split === 'vertical' ? e.pageX : e.pageY; const currentPage = this.split === 'vertical' ? e.pageX : e.pageY
const targetOffset = this.split === 'vertical' ? e.currentTarget.offsetWidth : e.currentTarget.offsetHeight; const targetOffset = this.split === 'vertical' ? e.currentTarget.offsetWidth : e.currentTarget.offsetHeight
const percent = Math.floor(((currentPage - offset) / targetOffset) * 10000) / 100; const percent = Math.floor(((currentPage - offset) / targetOffset) * 10000) / 100
if (percent > this.margin && percent < 100 - this.margin) { if (percent > this.margin && percent < 100 - this.margin) {
this.percent = percent; this.percent = percent
}
this.$emit('resize');
this.hasMoved = true;
} }
this.$emit('resize')
this.hasMoved = true
} }
} }
} }
}
</script> </script>
<style scoped> <style scoped>

View File

@@ -9,66 +9,66 @@
</template> </template>
<script> <script>
export default { export default {
name: 'Sticky', name: 'Sticky',
props: { props: {
stickyTop: { stickyTop: {
type: Number, type: Number,
default: 0 default: 0
},
zIndex: {
type: Number,
default: 1
},
className: {
type: String
}
}, },
data() { zIndex: {
return { type: Number,
active: false, default: 1
position: '',
currentTop: '',
width: undefined,
height: undefined,
child: null,
stickyHeight: 0
};
}, },
methods: { className: {
sticky() { type: String
if (this.active) {
return
}
this.position = 'fixed';
this.active = true;
this.width = this.width + 'px';
},
reset() {
if (!this.active) {
return
}
this.position = '';
this.width = 'auto'
this.active = false
},
handleScroll() {
this.width = this.$el.getBoundingClientRect().width;
const offsetTop = this.$el.getBoundingClientRect().top;
if (offsetTop <= this.stickyTop) {
this.sticky();
return
}
this.reset()
}
},
mounted() {
this.height = this.$el.getBoundingClientRect().height;
window.addEventListener('scroll', this.handleScroll);
},
destroyed() {
window.removeEventListener('scroll', this.handleScroll);
} }
}; },
data() {
return {
active: false,
position: '',
currentTop: '',
width: undefined,
height: undefined,
child: null,
stickyHeight: 0
}
},
methods: {
sticky() {
if (this.active) {
return
}
this.position = 'fixed'
this.active = true
this.width = this.width + 'px'
},
reset() {
if (!this.active) {
return
}
this.position = ''
this.width = 'auto'
this.active = false
},
handleScroll() {
this.width = this.$el.getBoundingClientRect().width
const offsetTop = this.$el.getBoundingClientRect().top
if (offsetTop <= this.stickyTop) {
this.sticky()
return
}
this.reset()
}
},
mounted() {
this.height = this.$el.getBoundingClientRect().height
window.addEventListener('scroll', this.handleScroll)
},
destroyed() {
window.removeEventListener('scroll', this.handleScroll)
}
}
</script> </script>

View File

@@ -5,80 +5,77 @@
</template> </template>
<script> <script>
// import { getToken, upload } from 'api/qiniu'; // 七牛 export default {
export default { name: 'tinymce',
name: 'tinymce', props: {
props: { id: {
id: { type: String,
type: String, default: 'tinymceEditor'
default: 'tinymceEditor' },
}, value: {
value: { type: String,
type: String, default: ''
default: '' },
}, toolbar: {
toolbar: { type: Array,
type: Array, required: false,
required: false, default() {
default() { return ['removeformat undo redo | bullist numlist | outdent indent | forecolor | fullscreen code', 'bold italic blockquote | h2 p media link | alignleft aligncenter alignright']
return ['removeformat undo redo | bullist numlist | outdent indent | forecolor | fullscreen code', 'bold italic blockquote | h2 p media link | alignleft aligncenter alignright'] }
} },
}, data() {
data() { return {
return { hasChange: false,
hasChange: false, hasInit: false
hasInit: false }
} },
}, menubar: {
menubar: { default: ''
default: '' },
}, height: {
height: { type: Number,
type: Number, required: false,
required: false, default: 360
default: 360 }
} },
}, watch: {
watch: { value(val) {
value(val) { if (!this.hasChange && this.hasInit) {
if (!this.hasChange && this.hasInit) { this.$nextTick(() => window.tinymce.get(this.id).setContent(val))
this.$nextTick(() => tinymce.get(this.id).setContent(val)) }
} }
} },
}, mounted() {
mounted() { const _this = this
const _this = this; window.tinymce.init({
tinymce.init({ selector: `#${this.id}`,
selector: `#${this.id}`, height: this.height,
height: this.height, body_class: 'panel-body ',
body_class: 'panel-body ', object_resizing: false,
object_resizing: false, toolbar: this.toolbar,
// language: 'zh_CN', menubar: this.menubar,
// language_url: '/static/tinymce/langs/zh_CN.js', plugins: 'advlist,autolink,code,paste,textcolor, colorpicker,fullscreen,link,lists,media,wordcount, imagetools',
toolbar: this.toolbar, end_container_on_empty_block: true,
menubar: this.menubar, powerpaste_word_import: 'clean',
plugins: 'advlist,autolink,code,paste,textcolor, colorpicker,fullscreen,link,lists,media,wordcount, imagetools,watermark', code_dialog_height: 450,
end_container_on_empty_block: true, code_dialog_width: 1000,
powerpaste_word_import: 'clean', advlist_bullet_styles: 'square',
code_dialog_height: 450, advlist_number_styles: 'default',
code_dialog_width: 1000, block_formats: '普通标签=p;小标题=h2;',
advlist_bullet_styles: 'square', imagetools_cors_hosts: ['wpimg.wallstcn.com', 'wallstreetcn.com'],
advlist_number_styles: 'default', imagetools_toolbar: 'watermark',
block_formats: '普通标签=p;小标题=h2;', default_link_target: '_blank',
imagetools_cors_hosts: ['wpimg.wallstcn.com', 'wallstreetcn.com'], link_title: false,
imagetools_toolbar: 'watermark', init_instance_callback: editor => {
default_link_target: '_blank', if (_this.value) {
link_title: false, editor.setContent(_this.value)
init_instance_callback: editor => { }
if (_this.value) { _this.hasInit = true
editor.setContent(_this.value) editor.on('NodeChange Change KeyUp', () => {
} this.hasChange = true
_this.hasInit = true; this.$emit('input', editor.getContent({ format: 'raw' }))
editor.on('NodeChange Change KeyUp', () => { })
this.hasChange = true; },
this.$emit('input', editor.getContent({ format: 'raw' }));
});
},
// 整合七牛上传 // 整合七牛上传
// images_dataimg_filter(img) { // images_dataimg_filter(img) {
// setTimeout(() => { // setTimeout(() => {
@@ -112,44 +109,44 @@
// console.log(err); // console.log(err);
// }); // });
// }, // },
setup(editor) { setup(editor) {
editor.addButton('h2', { editor.addButton('h2', {
title: '小标题', // tooltip text seen on mouseover title: '小标题', // tooltip text seen on mouseover
text: '小标题', text: '小标题',
onclick() { onclick() {
editor.execCommand('mceToggleFormat', false, 'h2'); editor.execCommand('mceToggleFormat', false, 'h2')
}, },
onPostRender() { onPostRender() {
const btn = this; const btn = this
editor.on('init', () => { editor.on('init', () => {
editor.formatter.formatChanged('h2', state => { editor.formatter.formatChanged('h2', state => {
btn.active(state); btn.active(state)
}); })
}); })
} }
}); })
editor.addButton('p', { editor.addButton('p', {
title: '正文', title: '正文',
text: '正文', text: '正文',
onclick() { onclick() {
editor.execCommand('mceToggleFormat', false, 'p'); editor.execCommand('mceToggleFormat', false, 'p')
}, },
onPostRender() { onPostRender() {
const btn = this; const btn = this
editor.on('init', () => { editor.on('init', () => {
editor.formatter.formatChanged('p', state => { editor.formatter.formatChanged('p', state => {
btn.active(state); btn.active(state)
}); })
}); })
} }
}); })
} }
}); })
}, },
destroyed() { destroyed() {
tinymce.get(this.id).destroy(); window.tinymce.get(this.id).destroy()
}
} }
}
</script> </script>
<style scoped> <style scoped>
@@ -161,14 +158,4 @@
visibility: hidden; visibility: hidden;
z-index: -1; z-index: -1;
} }
.editor-custom-btn-container {
position: absolute;
right: 15px;
top: 18px;
}
.editor-upload-btn {
display: inline-block;
}
</style> </style>

View File

@@ -33,6 +33,7 @@
<script> <script>
import Todo from './Todo.vue' import Todo from './Todo.vue'
const STORAGE_KEY = 'todos' const STORAGE_KEY = 'todos'
const filters = { const filters = {
all: todos => todos, all: todos => todos,
@@ -84,12 +85,10 @@ export default {
this.setLocalStorgae() this.setLocalStorgae()
}, },
deleteTodo(todo) { deleteTodo(todo) {
console.log(todo)
this.todos.splice(this.todos.indexOf(todo), 1) this.todos.splice(this.todos.indexOf(todo), 1)
this.setLocalStorgae() this.setLocalStorgae()
}, },
editTodo({ todo, value }) { editTodo({ todo, value }) {
console.log(todo, value)
todo.text = value todo.text = value
this.setLocalStorgae() this.setLocalStorgae()
}, },

View File

@@ -17,52 +17,53 @@
</template> </template>
<script> <script>
// 预览效果见付费文章 // 预览效果见付费文章
import { getToken } from 'api/qiniu'; import { getToken } from '@/api/qiniu'
export default {
name: 'singleImageUpload', export default {
props: { name: 'singleImageUpload',
value: String props: {
value: String
}, },
computed: { computed: {
imageUrl() { imageUrl() {
return this.value return this.value
} }
}, },
data() { data() {
return { return {
tempUrl: '', tempUrl: '',
dataObj: { token: '', key: '' } dataObj: { token: '', key: '' }
}; }
}, },
methods: { methods: {
rmImage() { rmImage() {
this.emitInput(''); this.emitInput('')
}, },
emitInput(val) { emitInput(val) {
this.$emit('input', val); this.$emit('input', val)
}, },
handleImageScucess() { handleImageScucess() {
this.emitInput(this.tempUrl) this.emitInput(this.tempUrl)
}, },
beforeUpload() { beforeUpload() {
const _self = this; const _self = this
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
getToken().then(response => { getToken().then(response => {
const key = response.data.qiniu_key; const key = response.data.qiniu_key
const token = response.data.qiniu_token; const token = response.data.qiniu_token
_self._data.dataObj.token = token; _self._data.dataObj.token = token
_self._data.dataObj.key = key; _self._data.dataObj.key = key
this.tempUrl = response.data.qiniu_url; this.tempUrl = response.data.qiniu_url
resolve(true); resolve(true)
}).catch(err => { }).catch(err => {
console.log(err); console.log(err)
reject(false) reject(false)
}); })
}); })
} }
} }
}; }
</script> </script>
<style rel="stylesheet/scss" lang="scss" scoped> <style rel="stylesheet/scss" lang="scss" scoped>

View File

@@ -17,52 +17,51 @@
</template> </template>
<script> <script>
// 预览效果见专题 import { getToken } from '@/api/qiniu'
import { getToken } from 'api/qiniu';
export default { export default {
name: 'singleImageUpload2', name: 'singleImageUpload2',
props: { props: {
value: String value: String
}, },
computed: { computed: {
imageUrl() { imageUrl() {
return this.value return this.value
} }
}, },
data() { data() {
return { return {
tempUrl: '', tempUrl: '',
dataObj: { token: '', key: '' } dataObj: { token: '', key: '' }
}; }
}, },
methods: { methods: {
rmImage() { rmImage() {
this.emitInput(''); this.emitInput('')
}, },
emitInput(val) { emitInput(val) {
this.$emit('input', val); this.$emit('input', val)
}, },
handleImageScucess() { handleImageScucess() {
this.emitInput(this.tempUrl) this.emitInput(this.tempUrl)
}, },
beforeUpload() { beforeUpload() {
const _self = this; const _self = this
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
getToken().then(response => { getToken().then(response => {
const key = response.data.qiniu_key; const key = response.data.qiniu_key
const token = response.data.qiniu_token; const token = response.data.qiniu_token
_self._data.dataObj.token = token; _self._data.dataObj.token = token
_self._data.dataObj.key = key; _self._data.dataObj.key = key
this.tempUrl = response.data.qiniu_url; this.tempUrl = response.data.qiniu_url
resolve(true); resolve(true)
}).catch(err => { }).catch(() => {
console.log(err); reject(false)
reject(false) })
}); })
});
} }
} }
}; }
</script> </script>
<style rel="stylesheet/scss" lang="scss" scoped> <style rel="stylesheet/scss" lang="scss" scoped>

View File

@@ -26,52 +26,52 @@
</template> </template>
<script> <script>
// 预览效果见文章 import { getToken } from '@/api/qiniu'
import { getToken } from 'api/qiniu';
export default { export default {
name: 'singleImageUpload', name: 'singleImageUpload',
props: { props: {
value: String value: String
}, },
computed: { computed: {
imageUrl() { imageUrl() {
return this.value return this.value
} }
}, },
data() { data() {
return { return {
tempUrl: '', tempUrl: '',
dataObj: { token: '', key: '' } dataObj: { token: '', key: '' }
}; }
}, },
methods: { methods: {
rmImage() { rmImage() {
this.emitInput(''); this.emitInput('')
}, },
emitInput(val) { emitInput(val) {
this.$emit('input', val); this.$emit('input', val)
}, },
handleImageScucess(file) { handleImageScucess(file) {
this.emitInput(file.files.file) this.emitInput(file.files.file)
}, },
beforeUpload() { beforeUpload() {
const _self = this; const _self = this
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
getToken().then(response => { getToken().then(response => {
const key = response.data.qiniu_key; const key = response.data.qiniu_key
const token = response.data.qiniu_token; const token = response.data.qiniu_token
_self._data.dataObj.token = token; _self._data.dataObj.token = token
_self._data.dataObj.key = key; _self._data.dataObj.key = key
this.tempUrl = response.data.qiniu_url; this.tempUrl = response.data.qiniu_url
resolve(true); resolve(true)
}).catch(err => { }).catch(err => {
console.log(err); console.log(err)
reject(false) reject(false)
}); })
}); })
} }
} }
}; }
</script> </script>
<style rel="stylesheet/scss" lang="scss" scoped> <style rel="stylesheet/scss" lang="scss" scoped>

View File

@@ -5,52 +5,52 @@
</template> </template>
<script> <script>
import CodeMirror from 'codemirror'; import CodeMirror from 'codemirror'
import 'codemirror/addon/lint/lint.css'; import 'codemirror/addon/lint/lint.css'
import 'codemirror/lib/codemirror.css'; import 'codemirror/lib/codemirror.css'
import 'codemirror/theme/rubyblue.css'; import 'codemirror/theme/rubyblue.css'
require('script-loader!jsonlint'); require('script-loader!jsonlint')
import 'codemirror/mode/javascript/javascript' import 'codemirror/mode/javascript/javascript'
import 'codemirror/addon/lint/lint' import 'codemirror/addon/lint/lint'
import 'codemirror/addon/lint/json-lint'; import 'codemirror/addon/lint/json-lint'
export default { export default {
name: 'jsonEditor', name: 'jsonEditor',
data() { data() {
return { return {
jsonEditor: false jsonEditor: false
} }
}, },
props: ['value'], props: ['value'],
watch: { watch: {
value(value) { value(value) {
const editor_value = this.jsonEditor.getValue(); const editor_value = this.jsonEditor.getValue()
if (value !== editor_value) { if (value !== editor_value) {
this.jsonEditor.setValue(JSON.stringify(this.value, null, 2)); this.jsonEditor.setValue(JSON.stringify(this.value, null, 2))
}
}
},
mounted() {
this.jsonEditor = CodeMirror.fromTextArea(this.$refs.textarea, {
lineNumbers: true,
mode: 'application/json',
gutters: ['CodeMirror-lint-markers'],
theme: 'rubyblue',
lint: true
});
this.jsonEditor.setValue(JSON.stringify(this.value, null, 2));
this.jsonEditor.on('change', cm => {
this.$emit('changed', cm.getValue())
this.$emit('input', cm.getValue())
})
},
methods: {
getValue() {
return this.jsonEditor.getValue()
} }
} }
},
mounted() {
this.jsonEditor = CodeMirror.fromTextArea(this.$refs.textarea, {
lineNumbers: true,
mode: 'application/json',
gutters: ['CodeMirror-lint-markers'],
theme: 'rubyblue',
lint: true
})
this.jsonEditor.setValue(JSON.stringify(this.value, null, 2))
this.jsonEditor.on('change', cm => {
this.$emit('changed', cm.getValue())
this.$emit('input', cm.getValue())
})
},
methods: {
getValue() {
return this.jsonEditor.getValue()
}
} }
}
</script> </script>
<style> <style>

View File

@@ -3,21 +3,20 @@
<div class="twoDndList-list" :style="{width:width1}"> <div class="twoDndList-list" :style="{width:width1}">
<h3>{{list1Title}}</h3> <h3>{{list1Title}}</h3>
<draggable :list="list1" class="dragArea" :options="{group:'article'}"> <draggable :list="list1" class="dragArea" :options="{group:'article'}">
<div class="list-complete-item" v-for="element in list1" :key='element'> <div class="list-complete-item" v-for="element in list1" :key='element.id'>
<div class="list-complete-item-handle">[{{element.author}}] {{element.title}}</div> <div class="list-complete-item-handle">[{{element.author}}] {{element.title}}</div>
<div style="position:absolute;right:0px;"> <div style="position:absolute;right:0px;">
<span style="float: right ;margin-top: -20px;margin-right:5px;" @click="deleteEle(element)"> <span style="float: right ;margin-top: -20px;margin-right:5px;" @click="deleteEle(element)">
<i style="color:#ff4949" class="el-icon-delete"></i> <i style="color:#ff4949" class="el-icon-delete"></i>
</span> </span>
</div> </div>
</div> </div>
</draggable> </draggable>
</div> </div>
<div class="twoDndList-list" :style="{width:width2}"> <div class="twoDndList-list" :style="{width:width2}">
<h3>{{list2Title}}</h3> <h3>{{list2Title}}</h3>
<draggable :list="filterList2" class="dragArea" :options="{group:'article'}"> <draggable :list="filterList2" class="dragArea" :options="{group:'article'}">
<div class="list-complete-item" v-for="element in filterList2" :key='element'> <div class="list-complete-item" v-for="element in filterList2" :key='element.id'>
<div class='list-complete-item-handle2' @click="pushEle(element)"> [{{element.author}}] {{element.title}}</div> <div class='list-complete-item-handle2' @click="pushEle(element)"> [{{element.author}}] {{element.title}}</div>
</div> </div>
</draggable> </draggable>
@@ -26,74 +25,75 @@
</template> </template>
<script> <script>
import draggable from 'vuedraggable' import draggable from 'vuedraggable'
export default {
name: 'twoDndList', export default {
components: { draggable }, name: 'twoDndList',
computed: { components: { draggable },
filterList2() { computed: {
return this.list2.filter(v => { filterList2() {
if (this.isNotInList1(v)) { return this.list2.filter(v => {
return v if (this.isNotInList1(v)) {
} return v
return false; }
}) return false
})
}
},
props: {
list1: {
type: Array,
default() {
return []
} }
}, },
props: { list2: {
list1: { type: Array,
type: Array, default() {
default() { return []
return []
}
},
list2: {
type: Array,
default() {
return []
}
},
list1Title: {
type: String,
default: 'list1'
},
list2Title: {
type: String,
default: 'list2'
},
width1: {
type: String,
default: '48%'
},
width2: {
type: String,
default: '48%'
} }
}, },
methods: { list1Title: {
isNotInList1(v) { type: String,
return this.list1.every(k => v.id !== k.id) default: 'list1'
}, },
isNotInList2(v) { list2Title: {
return this.list2.every(k => v.id !== k.id) type: String,
}, default: 'list2'
deleteEle(ele) { },
for (const item of this.list1) { width1: {
if (item.id === ele.id) { type: String,
const index = this.list1.indexOf(item); default: '48%'
this.list1.splice(index, 1) },
break width2: {
} type: String,
default: '48%'
}
},
methods: {
isNotInList1(v) {
return this.list1.every(k => v.id !== k.id)
},
isNotInList2(v) {
return this.list2.every(k => v.id !== k.id)
},
deleteEle(ele) {
for (const item of this.list1) {
if (item.id === ele.id) {
const index = this.list1.indexOf(item)
this.list1.splice(index, 1)
break
} }
if (this.isNotInList2(ele)) {
this.list2.unshift(ele)
}
},
pushEle(ele) {
this.list1.push(ele)
} }
if (this.isNotInList2(ele)) {
this.list2.unshift(ele)
}
},
pushEle(ele) {
this.list1.push(ele)
} }
} }
}
</script> </script>
<style rel="stylesheet/scss" lang="scss" scoped> <style rel="stylesheet/scss" lang="scss" scoped>

View File

@@ -1,43 +1,43 @@
const vueSticky = {}; const vueSticky = {}
let listenAction; let listenAction
vueSticky.install = Vue => { vueSticky.install = Vue => {
Vue.directive('sticky', { Vue.directive('sticky', {
inserted(el, binding) { inserted(el, binding) {
const params = binding.value || {}, const params = binding.value || {}
stickyTop = params.stickyTop || 0, const stickyTop = params.stickyTop || 0
zIndex = params.zIndex || 1000, const zIndex = params.zIndex || 1000
elStyle = el.style; const elStyle = el.style
elStyle.position = '-webkit-sticky'; elStyle.position = '-webkit-sticky'
elStyle.position = 'sticky'; elStyle.position = 'sticky'
// if the browser support css stickyCurrently Safari, Firefox and Chrome Canary // if the browser support css stickyCurrently Safari, Firefox and Chrome Canary
// if (~elStyle.position.indexOf('sticky')) { // if (~elStyle.position.indexOf('sticky')) {
// elStyle.top = `${stickyTop}px`; // elStyle.top = `${stickyTop}px`;
// elStyle.zIndex = zIndex; // elStyle.zIndex = zIndex;
// return // return
// } // }
const elHeight = el.getBoundingClientRect().height; const elHeight = el.getBoundingClientRect().height
const elWidth = el.getBoundingClientRect().width; const elWidth = el.getBoundingClientRect().width
elStyle.cssText = `top: ${stickyTop}px; z-index: ${zIndex}`; elStyle.cssText = `top: ${stickyTop}px; z-index: ${zIndex}`
const parentElm = el.parentNode || document.documentElement; const parentElm = el.parentNode || document.documentElement
const placeholder = document.createElement('div'); const placeholder = document.createElement('div')
placeholder.style.display = 'none'; placeholder.style.display = 'none'
placeholder.style.width = `${elWidth}px`; placeholder.style.width = `${elWidth}px`
placeholder.style.height = `${elHeight}px`; placeholder.style.height = `${elHeight}px`
parentElm.insertBefore(placeholder, el) parentElm.insertBefore(placeholder, el)
let active = false; let active = false
const getScroll = (target, top) => { const getScroll = (target, top) => {
const prop = top ? 'pageYOffset' : 'pageXOffset'; const prop = top ? 'pageYOffset' : 'pageXOffset'
const method = top ? 'scrollTop' : 'scrollLeft'; const method = top ? 'scrollTop' : 'scrollLeft'
let ret = target[prop]; let ret = target[prop]
if (typeof ret !== 'number') { if (typeof ret !== 'number') {
ret = window.document.documentElement[method]; ret = window.document.documentElement[method]
} }
return ret; return ret
}; }
const sticky = () => { const sticky = () => {
if (active) { if (active) {
@@ -47,36 +47,36 @@ vueSticky.install = Vue => {
elStyle.height = `${el.offsetHeight}px` elStyle.height = `${el.offsetHeight}px`
} }
elStyle.position = 'fixed'; elStyle.position = 'fixed'
elStyle.width = `${elWidth}px`; elStyle.width = `${elWidth}px`
placeholder.style.display = 'inline-block'; placeholder.style.display = 'inline-block'
active = true active = true
}; }
const reset = () => { const reset = () => {
if (!active) { if (!active) {
return return
} }
elStyle.position = ''; elStyle.position = ''
placeholder.style.display = 'none'; placeholder.style.display = 'none'
active = false; active = false
}; }
const check = () => { const check = () => {
const scrollTop = getScroll(window, true); const scrollTop = getScroll(window, true)
const offsetTop = el.getBoundingClientRect().top; const offsetTop = el.getBoundingClientRect().top
if (offsetTop < stickyTop) { if (offsetTop < stickyTop) {
sticky(); sticky()
} else { } else {
if (scrollTop < elHeight + stickyTop) { if (scrollTop < elHeight + stickyTop) {
reset() reset()
} }
} }
}; }
listenAction = () => { listenAction = () => {
check() check()
}; }
window.addEventListener('scroll', listenAction) window.addEventListener('scroll', listenAction)
}, },
@@ -85,7 +85,7 @@ vueSticky.install = Vue => {
window.removeEventListener('scroll', listenAction) window.removeEventListener('scroll', listenAction)
} }
}) })
}; }
export default vueSticky export default vueSticky

View File

@@ -1,47 +1,42 @@
import './waves.css'; import './waves.css'
const vueWaves = {}; export default{
vueWaves.install = (Vue, options = {}) => { bind(el, binding) {
Vue.directive('waves', { el.addEventListener('click', e => {
bind(el, binding) { const customOpts = Object.assign({}, binding.value)
el.addEventListener('click', e => { const opts = Object.assign({
const customOpts = Object.assign(options, binding.value); ele: el, // 波纹作用元素
const opts = Object.assign({ type: 'hit', // hit点击位置扩散center中心点扩展
ele: el, // 波纹作用元素 color: 'rgba(0, 0, 0, 0.15)' // 波纹颜色
type: 'hit', // hit点击位置扩散center中心点扩展 }, customOpts)
color: 'rgba(0, 0, 0, 0.15)' // 波纹颜色 const target = opts.ele
}, customOpts), if (target) {
target = opts.ele; target.style.position = 'relative'
if (target) { target.style.overflow = 'hidden'
target.style.position = 'relative'; const rect = target.getBoundingClientRect()
target.style.overflow = 'hidden'; let ripple = target.querySelector('.waves-ripple')
const rect = target.getBoundingClientRect(); if (!ripple) {
let ripple = target.querySelector('.waves-ripple'); ripple = document.createElement('span')
if (!ripple) { ripple.className = 'waves-ripple'
ripple = document.createElement('span'); ripple.style.height = ripple.style.width = Math.max(rect.width, rect.height) + 'px'
ripple.className = 'waves-ripple'; target.appendChild(ripple)
ripple.style.height = ripple.style.width = Math.max(rect.width, rect.height) + 'px'; } else {
target.appendChild(ripple); ripple.className = 'waves-ripple'
} else {
ripple.className = 'waves-ripple';
}
switch (opts.type) {
case 'center':
ripple.style.top = (rect.height / 2 - ripple.offsetHeight / 2) + 'px';
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.backgroundColor = opts.color;
ripple.className = 'waves-ripple z-active';
return false;
} }
}, false); switch (opts.type) {
} case 'center':
}) ripple.style.top = (rect.height / 2 - ripple.offsetHeight / 2) + 'px'
}; ripple.style.left = (rect.width / 2 - ripple.offsetWidth / 2) + 'px'
break
export default vueWaves; 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.backgroundColor = opts.color
ripple.className = 'waves-ripple z-active'
return false
}
}, false)
}
}

14
src/errorLog.js Normal file
View File

@@ -0,0 +1,14 @@
import Vue from 'vue'
import errLog from '@/store/errLog'
// 生产环境错误日志
if (process.env.NODE_ENV === 'production') {
Vue.config.errorHandler = function(err, vm) {
console.log(err, window.location.href)
errLog.pushLog({
err,
url: window.location.href,
vm
})
}
}

View File

@@ -5,7 +5,7 @@ function pluralize(time, label) {
return time + label + 's' return time + label + 's'
} }
export function timeAgo(time) { export function timeAgo(time) {
const between = Date.now() / 1000 - Number(time); const between = Date.now() / 1000 - Number(time)
if (between < 3600) { if (between < 3600) {
return pluralize(~~(between / 60), ' minute') return pluralize(~~(between / 60), ' minute')
} else if (between < 86400) { } else if (between < 86400) {
@@ -17,19 +17,19 @@ export function timeAgo(time) {
export function parseTime(time, cFormat) { export function parseTime(time, cFormat) {
if (arguments.length === 0) { if (arguments.length === 0) {
return null; return null
} }
if ((time + '').length === 10) { if ((time + '').length === 10) {
time = +time * 1000 time = +time * 1000
} }
const format = cFormat || '{y}-{m}-{d} {h}:{i}:{s}'; const format = cFormat || '{y}-{m}-{d} {h}:{i}:{s}'
let date; let date
if (typeof time == 'object') { if (typeof time === 'object') {
date = time; date = time
} else { } else {
date = new Date(parseInt(time)); date = new Date(parseInt(time))
} }
const formatObj = { const formatObj = {
y: date.getFullYear(), y: date.getFullYear(),
@@ -39,24 +39,24 @@ export function parseTime(time, cFormat) {
i: date.getMinutes(), i: date.getMinutes(),
s: date.getSeconds(), s: date.getSeconds(),
a: date.getDay() a: date.getDay()
}; }
const time_str = format.replace(/{(y|m|d|h|i|s|a)+}/g, (result, key) => { const time_str = format.replace(/{(y|m|d|h|i|s|a)+}/g, (result, key) => {
let value = formatObj[key]; let value = formatObj[key]
if (key === 'a') return ['一', '二', '三', '四', '五', '六', '日'][value - 1]; if (key === 'a') return ['一', '二', '三', '四', '五', '六', '日'][value - 1]
if (result.length > 0 && value < 10) { if (result.length > 0 && value < 10) {
value = '0' + value; value = '0' + value
} }
return value || 0; return value || 0
}); })
return time_str; return time_str
} }
export function formatTime(time, option) { export function formatTime(time, option) {
time = +time * 1000; time = +time * 1000
const d = new Date(time); const d = new Date(time)
const now = Date.now(); const now = Date.now()
const diff = (now - d) / 1000; const diff = (now - d) / 1000
if (diff < 30) { if (diff < 30) {
return '刚刚' return '刚刚'
@@ -83,21 +83,21 @@ export function nFormatter(num, digits) {
{ value: 1E9, symbol: 'G' }, { value: 1E9, symbol: 'G' },
{ value: 1E6, symbol: 'M' }, { value: 1E6, symbol: 'M' },
{ value: 1E3, symbol: 'k' } { value: 1E3, symbol: 'k' }
]; ]
for (let i = 0; i < si.length; i++) { for (let i = 0; i < si.length; i++) {
if (num >= si[i].value) { if (num >= si[i].value) {
return (num / si[i].value + 0.1).toFixed(digits).replace(/\.0+$|(\.[0-9]*[1-9])0+$/, '$1') + si[i].symbol; return (num / si[i].value + 0.1).toFixed(digits).replace(/\.0+$|(\.[0-9]*[1-9])0+$/, '$1') + si[i].symbol
} }
} }
return num.toString(); return num.toString()
} }
export function html2Text(val) { export function html2Text(val) {
const div = document.createElement('div'); const div = document.createElement('div')
div.innerHTML = val; div.innerHTML = val
return div.textContent || div.innerText; return div.textContent || div.innerText
} }
export function toThousandslsFilter(num) { export function toThousandslsFilter(num) {
return (+num || 0).toString().replace(/^-?\d+/g, m => m.replace(/(?=(?!\b)(\d{3})+$)/g, ',')); return (+num || 0).toString().replace(/^-?\d+/g, m => m.replace(/(?=(?!\b)(\d{3})+$)/g, ','))
} }

12
src/icons/index.js Normal file
View File

@@ -0,0 +1,12 @@
import Vue from 'vue'
import IconSvg from '@/components/Icon-svg'// svg组件
import generateIconsView from '@/views/svg-icons/generateIconsView.js'// just for views/icons , you can delete it
// register globally
Vue.component('icon-svg', IconSvg)
const requireAll = requireContext => requireContext.keys().map(requireContext)
const req = require.context('./svg', false, /\.svg$/)
const iconMap = requireAll(req)
generateIconsView.generate(iconMap) // just for views/icons , you can delete it

1
src/icons/svg/404.svg Normal file
View File

@@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1503994850540" class="icon" style="" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="10206" xmlns:xlink="http://www.w3.org/1999/xlink" width="64" height="64"><defs><style type="text/css"></style></defs><path d="M931.6 585.6l0 79c28.6-60.2 44.8-127.4 44.8-198.4C976.4 211 769.4 4 514.2 4S52 211 52 466.2c0 3.2 0.2 6.4 0.2 9.6l166-206 96.4 0L171.8 485.6l46.4 0 0-54.8 99.2-154.6 0 209.4 0 100 0 82.4-99.2 0 0-82.4L67.6 585.6c43 161 170.6 287.4 332.4 328.6-10.4 26.2-40.6 89.4-90.8 100.6-62.2 14 168.8 3.4 333.6-104.6 126.6-36.6 230.8-125.8 287.4-242.2l-97.6 0 0-82.4-166.2 0 0-87.2 0-12.8L666.4 476l166.2-206.2 94 0-140.4 215.8 46.4 0 0-59 99.2-154 0 213.2L931.8 585.6zM366.2 608c-4.8-11.2-7.2-23.2-7.2-36L359 357.6c0-12.8 2.4-24.8 7.2-36 4.8-11.2 11.4-21 19.6-29.2 8.2-8.2 18-14.8 29.2-19.6 11.2-4.8 23.2-7.2 36-7.2l81.6 0c12.8 0 24.8 2.4 36 7.2 11 4.8 20.6 11.2 28.8 19.2l-88.6 129.4 0-23c0-4.8-1.6-8.8-4.8-12-3.2-3.2-7.2-4.8-12-4.8-4.8 0-8.8 1.6-12 4.8-3.2 3.2-4.8 7.2-4.8 12l0 72L372.6 620C370.2 616.2 368 612.2 366.2 608zM624.4 572c0 12.8-2.4 24.8-7.2 36-4.8 11.2-11.4 21-19.6 29.2-8.2 8.2-18 14.8-29.2 19.6-11.2 4.8-23.2 7.2-36 7.2l-81.6 0c-12.8 0-24.8-2.4-36-7.2-11.2-4.8-21-11.4-29.2-19.6-3.6-3.6-7-7.8-10-12l99.2-144.6 0 50.6c0 4.8 1.6 8.8 4.8 12 3.2 3.2 7.2 4.8 12 4.8 4.8 0 8.8-1.6 12-4.8 3.2-3.2 4.8-7.2 4.8-12l0-99.6 92.6-135.2c6.6 7.4 12 15.8 16 25.2 4.8 11.2 7.2 23.2 7.2 36L624.2 572z" p-id="10207"></path></svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

1
src/icons/svg/EXCEL.svg Normal file
View File

@@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1503994842272" class="icon" style="" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="10097" xmlns:xlink="http://www.w3.org/1999/xlink" width="64" height="64"><defs><style type="text/css"></style></defs><path d="M625.664 132.608V199.68h309.76v43.008h-309.76V312.32h309.76v43.008h-309.76v68.608h309.76v43.008h-309.76v68.608h309.76v43.008h-309.76v68.608h309.76v43.008h-309.76v68.096h309.76v43.008h-309.76v89.088H1024v-757.76h-398.336zM0 914.944L577.024 1024V0L0 109.056" p-id="10098"></path><path d="M229.376 660.48H139.776l118.272-187.904-112.64-180.736h92.16l65.536 119.808L370.688 291.84h89.088l-112.64 177.664L466.944 660.48H373.248l-70.144-125.44L229.376 660.48z" p-id="10099"></path></svg>

After

Width:  |  Height:  |  Size: 866 B

1
src/icons/svg/QQ.svg Normal file

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 8.0 KiB

1
src/icons/svg/a.svg Normal file
View File

@@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1503994155726" class="icon" style="" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="8554" xmlns:xlink="http://www.w3.org/1999/xlink" width="64" height="64"><defs><style type="text/css"></style></defs><path d="M44.521739 0h44.521739v979.478261H44.521739zM267.130435 534.26087h44.521739v445.217391H267.130435zM489.73913 311.652174h44.52174v667.826087h-44.52174zM712.347826 712.347826h44.521739v267.130435h-44.521739zM934.956522 445.217391h44.521739v534.26087h-44.521739z" fill="" p-id="8555"></path></svg>

After

Width:  |  Height:  |  Size: 678 B

1
src/icons/svg/b.svg Normal file
View File

@@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1503994177895" class="icon" style="" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="8894" xmlns:xlink="http://www.w3.org/1999/xlink" width="64" height="64"><defs><style type="text/css"></style></defs><path d="M712.347826 0h44.521739v979.478261h-44.521739zM267.130435 534.26087h44.521739v445.217391H267.130435zM489.73913 311.652174h44.52174v667.826087h-44.52174zM44.521739 712.347826h44.521739v267.130435H44.521739zM934.956522 445.217391h44.521739v534.26087h-44.521739z" fill="" p-id="8895"></path></svg>

After

Width:  |  Height:  |  Size: 678 B

1
src/icons/svg/bug.svg Normal file
View File

@@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1503994864347" class="icon" style="" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="10314" xmlns:xlink="http://www.w3.org/1999/xlink" width="64" height="64"><defs><style type="text/css"></style></defs><path d="M969.142857 548.571429q0 14.848-10.861714 25.709714t-25.709714 10.861714l-128 0q0 97.718857-38.290286 165.705143l118.857143 119.442286q10.861714 10.861714 10.861714 25.709714t-10.861714 25.709714q-10.276571 10.861714-25.709714 10.861714t-25.709714-10.861714l-113.152-112.566857q-2.852571 2.852571-8.557714 7.424t-23.990857 16.274286-37.156571 20.845714-46.848 16.566857-55.442286 7.424l0-512-73.142857 0 0 512q-29.147429 0-58.002286-7.716571t-49.700571-18.870857-37.705143-22.272-24.868571-18.578286l-8.557714-8.009143-104.557714 118.272q-11.446857 11.995429-27.428571 11.995429-13.714286 0-24.576-9.142857-10.861714-10.276571-11.702857-25.417143t8.850286-26.587429l115.419429-129.718857q-33.133714-65.133714-33.133714-156.562286l-128 0q-14.848 0-25.709714-10.861714t-10.861714-25.709714 10.861714-25.709714 25.709714-10.861714l128 0 0-168.009143-98.852571-98.852571q-10.861714-10.861714-10.861714-25.709714t10.861714-25.709714 25.709714-10.861714 25.709714 10.861714l98.852571 98.852571 482.304 0 98.852571-98.852571q10.861714-10.861714 25.709714-10.861714t25.709714 10.861714 10.861714 25.709714-10.861714 25.709714l-98.852571 98.852571 0 168.009143 128 0q14.848 0 25.709714 10.861714t10.861714 25.709714zM694.857143 219.428571l-365.714286 0q0-75.995429 53.430857-129.426286t129.426286-53.430857 129.426286 53.430857 53.430857 129.426286z" p-id="10315"></path></svg>

After

Width:  |  Height:  |  Size: 1.7 KiB

1
src/icons/svg/c.svg Normal file
View File

@@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1503994166937" class="icon" style="" viewBox="0 0 1131 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="8786" xmlns:xlink="http://www.w3.org/1999/xlink" width="70.6875" height="64"><defs><style type="text/css"></style></defs><path d="M0 0h53.894737v970.105263H0zM269.473684 431.157895h53.894737v538.947368H269.473684zM538.947368 161.684211h53.894737v808.421052h-53.894737zM808.421053 646.736842h53.894736v323.368421h-53.894736zM1077.894737 323.368421h53.894737v646.736842h-53.894737z" fill="" p-id="8787"></path></svg>

After

Width:  |  Height:  |  Size: 673 B

1
src/icons/svg/email.svg Normal file
View File

@@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1503994210967" class="icon" style="" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="9120" xmlns:xlink="http://www.w3.org/1999/xlink" width="64" height="64"><defs><style type="text/css"></style></defs><path d="M513 583.8l448.5-448.5c-11.6-4.7-24.3-7.3-37.5-7.3L100 128c-12.7 0-24.9 2.4-36.1 6.7L513 583.8z" p-id="9121"></path><path d="M513 674.3 14.6 175.9C5.3 191.1 0 208.9 0 228l0 568c0 55.2 44.8 100 100 100l824 0c55.2 0 100-44.8 100-100l0-568c0-18.5-5.1-35.9-13.9-50.8L513 674.3z" p-id="9122"></path></svg>

After

Width:  |  Height:  |  Size: 684 B

1
src/icons/svg/from.svg Normal file
View File

@@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1503993937334" class="icon" style="" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="8099" xmlns:xlink="http://www.w3.org/1999/xlink" width="64" height="64"><defs><style type="text/css"></style></defs><path d="M960 256v64H64v-64c0-35.2 28.8-64 64-64h768c35.2 0 64 28.8 64 64z m0 128v384c0 35.2-28.8 64-64 64H128c-35.2 0-64-28.8-64-64V384h896zM256 640H128v32h128v-32z m128-64H128v32h256v-32z" p-id="8100"></path></svg>

After

Width:  |  Height:  |  Size: 591 B

1
src/icons/svg/icons.svg Normal file
View File

@@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1504000178424" class="icon" style="" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="14764" xmlns:xlink="http://www.w3.org/1999/xlink" width="64" height="64"><defs><style type="text/css"></style></defs><path d="M871.424 61.44q18.432 0 34.816 6.656t28.672 18.944 19.456 28.672 7.168 35.84l0 720.896q0 38.912-25.088 64.512t-62.976 25.6l-721.92 0q-40.96 0-66.048-26.624t-25.088-66.56l0-718.848q0-35.84 24.576-62.464t65.536-26.624l720.896 0zM633.856 829.44q18.432 0 26.624-8.704t8.192-23.04q0-13.312-8.192-22.528t-26.624-9.216l-62.464 0q1.024-2.048 1.024-6.144l0-507.904 63.488 0q18.432 0 25.6-9.216t7.168-22.528-7.168-22.528-25.6-9.216l-249.856 0q-18.432 0-25.6 9.216t-7.168 22.528 7.168 22.528 25.6 9.216l57.344 0 0 507.904q0 2.048 0.512 3.072t0.512 3.072l-56.32 0q-18.432 0-26.624 9.216t-8.192 22.528q0 14.336 8.192 23.04t26.624 8.704l245.76 0z" p-id="14765"></path></svg>

After

Width:  |  Height:  |  Size: 1.0 KiB

1
src/icons/svg/mima.svg Normal file
View File

@@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1503994678729" class="icon" style="" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="9229" xmlns:xlink="http://www.w3.org/1999/xlink" width="64" height="64"><defs><style type="text/css"></style></defs><path d="M780.8 354.579692 665.6 354.579692 665.6 311.689846c0-72.310154-19.849846-193.299692-153.6-193.299692-138.870154 0-153.6 135.049846-153.6 193.299692l0 42.889846L243.2 354.579692 243.2 311.689846C243.2 122.249846 348.790154 0 512 0s268.8 122.249846 268.8 311.689846L780.8 354.579692zM588.8 669.420308C588.8 625.900308 554.220308 590.769231 512 590.769231s-76.8 35.131077-76.8 78.651077c0 29.459692 15.399385 54.468923 38.439385 67.820308l0 89.639385c0 21.740308 17.250462 39.699692 38.4 39.699692s38.4-17.959385 38.4-39.699692l0-89.639385C573.44 723.889231 588.8 698.88 588.8 669.420308zM896 512l0 393.609846c0 65.260308-51.869538 118.390154-115.2 118.390154L243.2 1024c-63.291077 0-115.2-53.129846-115.2-118.390154L128 512c0-65.220923 51.869538-118.390154 115.2-118.390154l537.6 0C844.130462 393.609846 896 446.779077 896 512z" p-id="9230"></path></svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1503994776084" class="icon" style="" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="9662" xmlns:xlink="http://www.w3.org/1999/xlink" width="64" height="64"><defs><style type="text/css"></style></defs><path d="M818.246893 412.326906l-45.988404 0 0-70.991868c0-152.307871-123.463939-275.778974-275.778974-275.778974s-275.78102 123.471103-275.78102 275.778974l0 70.991868-45.987381 0c-25.379017 0-45.988404 20.566408-45.988404 45.987381l0 455.407074c0 25.428136 20.560268 45.988404 45.988404 45.988404l643.535779 0c25.37697 0 45.988404-20.560268 45.988404-45.988404L864.235296 458.314287C864.190271 432.893314 843.623863 412.326906 818.246893 412.326906L818.246893 412.326906zM680.331823 412.326906 312.62516 412.326906l0-70.991868c0-101.55393 82.344426-183.853331 183.854355-183.853331 101.509928 0 183.853331 82.343403 183.853331 183.853331L680.332846 412.326906 680.331823 412.326906zM680.331823 412.326906" p-id="9663"></path></svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

1
src/icons/svg/shouce.svg Normal file
View File

@@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1503994075075" class="icon" style="" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="8325" xmlns:xlink="http://www.w3.org/1999/xlink" width="64" height="64"><defs><style type="text/css"></style></defs><path d="M896 192v704H256.8c-71.2 0-128.8-57.6-128.8-128.8V256.8C128 185.6 185.6 128 256.8 128H768v512H257.6c-36 0-65.6 29.6-65.6 65.6v60.8c0 36 29.6 65.6 65.6 65.6H832V192h64zM768 704H256v64h512v-64z" p-id="8326"></path></svg>

After

Width:  |  Height:  |  Size: 602 B

1
src/icons/svg/tab.svg Normal file
View File

@@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1503994012480" class="icon" style="" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="8212" xmlns:xlink="http://www.w3.org/1999/xlink" width="64" height="64"><defs><style type="text/css"></style></defs><path d="M896 320H128V160c0-17.6 14.4-32 32-32h704c17.6 0 32 14.4 32 32v160zM320 896H160c-17.6 0-32-14.4-32-32V384h192v512zM864 896H384V384h512v480c0 17.6-14.4 32-32 32z" p-id="8213"></path></svg>

After

Width:  |  Height:  |  Size: 571 B

1
src/icons/svg/table.svg Normal file
View File

@@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1503994138443" class="icon" style="" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="8433" xmlns:xlink="http://www.w3.org/1999/xlink" width="64" height="64"><defs><style type="text/css"></style></defs><path d="M67.039347 100.410897l889.919259 0 0 200.231347-889.919259 0 0-200.231347Z" p-id="8434"></path><path d="M67.039347 345.138668l266.976494 0 0 266.975471-266.976494 0 0-266.975471Z" p-id="8435"></path><path d="M67.039347 656.610562l266.976494 0 0 266.976494-266.976494 0 0-266.976494Z" p-id="8436"></path><path d="M378.511241 345.138668l266.976494 0 0 266.975471-266.976494 0 0-266.975471Z" p-id="8437"></path><path d="M378.511241 656.610562l266.976494 0 0 266.976494-266.976494 0 0-266.976494Z" p-id="8438"></path><path d="M689.983135 345.138668l266.976494 0 0 266.975471-266.976494 0 0-266.975471Z" p-id="8439"></path><path d="M689.983135 656.610562l266.976494 0 0 266.976494-266.976494 0 0-266.976494Z" p-id="8440"></path><path d="M67.039347 100.410897l889.919259 0 0 200.231347-889.919259 0 0-200.231347Z" p-id="8441"></path><path d="M67.039347 345.138668l266.976494 0 0 266.975471-266.976494 0 0-266.975471Z" p-id="8442"></path><path d="M67.039347 656.610562l266.976494 0 0 266.976494-266.976494 0 0-266.976494Z" p-id="8443"></path><path d="M378.511241 345.138668l266.976494 0 0 266.975471-266.976494 0 0-266.975471Z" p-id="8444"></path><path d="M378.511241 656.610562l266.976494 0 0 266.976494-266.976494 0 0-266.976494Z" p-id="8445"></path><path d="M689.983135 345.138668l266.976494 0 0 266.975471-266.976494 0 0-266.975471Z" p-id="8446"></path><path d="M689.983135 656.610562l266.976494 0 0 266.976494-266.976494 0 0-266.976494Z" p-id="8447"></path></svg>

After

Width:  |  Height:  |  Size: 1.8 KiB

1
src/icons/svg/theme.svg Normal file
View File

@@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1503994829667" class="icon" style="" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="9989" xmlns:xlink="http://www.w3.org/1999/xlink" width="64" height="64"><defs><style type="text/css"></style></defs><path d="M788.00002 159.831491C756.00002 128 746 128 724.3801 128L642 128C642 128 576 188.923077 512 188.923077 448 188.923077 384 128 384 128L299.204802 128C276.629934 128 266 140.923077 245.847214 159.831491L81.582979 323.871735C70.243732 335.19552 52 371.692308 81.582979 408.655004 81.582979 408.655004 224.023667 540.29784 238.000003 541.53846L238.000003 835.076924C238.000003 868.452352 286.579 896 320 896L706 896C739.419808 896 788.00002 868.452352 788.00002 835.076924L788.00002 541.53846C802.145492 540.385864 942.448564 408.654992 942.448564 408.654992 974.00002 372 965.851264 334.883878 942.448584 311.513109L788.00002 159.831491Z" p-id="9990"></path></svg>

After

Width:  |  Height:  |  Size: 1.0 KiB

1
src/icons/svg/tubiao.svg Normal file
View File

@@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1503994873331" class="icon" style="" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="10422" xmlns:xlink="http://www.w3.org/1999/xlink" width="64" height="64"><defs><style type="text/css"></style></defs><path d="M64 448 320 448 320 960 64 960 64 448 64 448ZM704 256 960 256 960 960 704 960 704 256 704 256ZM384 64 640 64 640 960 384 960 384 64 384 64Z" p-id="10423"></path></svg>

After

Width:  |  Height:  |  Size: 552 B

View File

@@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1503994190757" class="icon" style="" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="9007" xmlns:xlink="http://www.w3.org/1999/xlink" width="64" height="64"><defs><style type="text/css"></style></defs><path d="M574.957891 267.016403 511.503696 267.016403l204.64896 0L511.212054 63.654762l-203.361641 203.361641L449.041086 267.016403l0 189.662641L258.687714 456.679044l0 125.916804L449.041086 582.595848l0 190.354396 125.916804 0L574.957891 582.595848l188.874695 0L763.832586 456.679044 574.957891 456.679044 574.957891 267.016403zM511.25401 960.345238l189.620685-187.394994L323.125305 772.950244 511.25401 960.345238zM71.291696 518.891967l187.394994 189.620685L258.68669 330.762239 71.291696 518.891967zM763.832586 330.762239l0 377.74939 188.874695-189.620685L763.832586 330.762239z" p-id="9008"></path></svg>

After

Width:  |  Height:  |  Size: 983 B

1
src/icons/svg/weixin.svg Normal file
View File

@@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1503994712492" class="icon" style="" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="9337" xmlns:xlink="http://www.w3.org/1999/xlink" width="64" height="64"><defs><style type="text/css"></style></defs><path d="M669.029188 317.395814c10.181291 0 20.235686 0.748037 30.23789 1.865487C672.100256 192.728466 536.831031 98.730629 382.414962 98.730629c-172.618362 0-314.03484 117.659747-314.03484 267.066545 0 86.2422 47.044337 157.061129 125.674313 211.988112l-31.406554 94.467535 109.75511-55.05285c39.302708 7.78122 70.80955 15.765055 110.010947 15.765055 9.849726 0 19.624747-0.481977 29.323017-1.243317-6.144182-20.996197-9.69827-42.982954-9.69827-65.792449C402.040732 428.732551 519.845498 317.395814 669.029188 317.395814zM500.167537 232.256738c23.639342 0 39.302708 15.550161 39.302708 39.185464 0 23.536043-15.66439 39.300075-39.302708 39.300075-23.535984 0-47.146672-15.765055-47.146672-39.300075C453.021889 247.806899 476.632577 232.256738 500.167537 232.256738zM280.402504 310.7433c-23.537007 0-47.300174-15.765055-47.300174-39.300075 0-23.635303 23.76419-39.185464 47.300174-39.185464 23.53496 0 39.200373 15.550161 39.200373 39.185464C319.602877 294.978245 303.937464 310.7433 280.402504 310.7433z" p-id="9338"></path><path d="M955.617831 562.14712c0-125.543298-125.622123-227.882104-266.733643-227.882104-149.41292 0-267.090791 102.338806-267.090791 227.882104 0 125.770472 117.677871 227.879034 267.090791 227.879034 31.278636 0 62.837668-7.896854 94.243199-15.765055l86.119862 47.170323-23.612735-78.473259C908.675829 695.672206 955.617831 632.965026 955.617831 562.14712zM602.306891 522.858302c-15.638806 0-31.431114-15.549138-31.431114-31.416524 0-15.651468 15.792308-31.405267 31.431114-31.405267 23.73963 0 39.302708 15.754822 39.302708 31.405267C641.609599 507.309164 626.04652 522.858302 602.306891 522.858302zM775.027587 522.858302c-15.538518 0-31.201884-15.549138-31.201884-31.416524 0-15.651468 15.66439-31.405267 31.201884-31.405267 23.535984 0 39.300661 15.754822 39.300661 31.405267C814.329272 507.309164 798.563571 522.858302 775.027587 522.858302z" p-id="9339"></path></svg>

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

@@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1503994797471" class="icon" style="" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="9770" xmlns:xlink="http://www.w3.org/1999/xlink" width="64" height="64"><defs><style type="text/css"></style></defs><path d="M565.272827 34.627285l112.095872 237.542288c8.706637 18.321022 25.411424 31.051641 44.82285 33.996289l250.776598 38.081157c48.697387 7.411435 68.22505 70.046082 32.933559 105.979639l-181.494353 184.937155c-13.998147 14.230618-20.352386 34.815477-17.05903 54.93539l42.819161 261.127145c8.346858 50.695541-42.64204 89.451974-86.225039 65.51841l-224.307979-123.271141c-17.285968-9.525824-37.992596-9.525824-55.278564 0l-224.313514 123.271141c-43.582999 23.933565-94.571897-14.822869-86.219504-65.51841l42.813626-261.127145c3.321031-20.119914-3.088559-40.704772-17.086706-54.93539l-181.439002-184.937155c-35.285956-35.933557-15.819179-98.57374 32.933559-105.979639l250.748923-38.081157c19.350541-2.939112 36.083003-15.675267 44.75643-33.996289l112.123547-237.542288C480.497972-11.540583 543.509003-11.540583 565.272827 34.627285z" p-id="9771"></path></svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1503994743287" class="icon" style="" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="9554" xmlns:xlink="http://www.w3.org/1999/xlink" width="64" height="64"><defs><style type="text/css"></style></defs><path d="M780.108 761.059c54.451 60.351 87.706 138.983 87.706 225.358 0 12.015-0.659 23.882-1.902 35.581l-71.955 0c1.589-11.675 2.695-23.493 2.695-35.581 0-71.578-29.094-136.386-76.189-185.002C658.778 836.02 587.76 855.95 512 855.95c-75.689 0-146.65-19.888-208.294-54.432-47.129 48.604-76.358 113.305-76.358 184.9 0 12.088 1.105 23.906 2.695 35.581l-71.955 0c-1.243-11.699-1.902-23.567-1.902-35.581 0-86.366 33.19-165.055 87.587-225.446-96.765-78.277-158.75-197.84-158.75-331.998C85.023 193.163 276.188 2.001 512 2.001s426.977 191.162 426.977 426.972C938.977 563.184 876.94 682.785 780.108 761.059zM512 295.787c-196.511 0-355.814-80.302-355.814 122.251 0 202.551 159.303 366.749 355.814 366.749s355.814-164.199 355.814-366.749C867.814 215.485 708.511 295.787 512 295.787zM678.047 500.136c-26.2 0-47.442-21.24-47.442-47.442 0-26.197 21.242-47.442 47.442-47.442 26.202 0 47.442 21.244 47.442 47.442C725.488 478.896 704.249 500.136 678.047 500.136zM654.326 630.601c0 32.754-63.722 59.302-142.326 59.302s-142.326-26.549-142.326-59.302c0-8.445 4.376-16.446 12.017-23.719 21.98 20.927 71.979 35.579 130.309 35.579s108.329-14.652 130.309-35.579C649.949 614.155 654.326 622.156 654.326 630.601zM345.953 500.136c-26.202 0-47.442-21.24-47.442-47.442 0-26.197 21.24-47.442 47.442-47.442 26.2 0 47.442 21.244 47.442 47.442C393.395 478.896 372.153 500.136 345.953 500.136z" p-id="9555"></path></svg>

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

@@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1503993826520" class="icon" style="" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="7878" xmlns:xlink="http://www.w3.org/1999/xlink" width="64" height="64"><defs><style type="text/css"></style></defs><path d="M941.677063 391.710356c9.337669-14.005992 6.224772-32.68133-6.224772-43.575447-14.005992-10.894118-32.68133-7.78122-43.575447 6.224771-1.556449 1.556449-174.300768 205.426673-379.727441 205.426673-199.200878 0-379.727441-205.426673-381.28389-206.982098-10.894118-12.450567-31.124881-14.005992-43.575448-3.112898-12.450567 10.894118-14.005992 31.124881-3.112897 43.575448 3.112897 4.668323 40.46255 46.687322 99.600439 93.375667l-79.369676 82.48155c-12.450567 12.450567-10.894118 32.68133 1.556449 43.575448 3.112897 6.224772 10.894118 9.337669 18.675338 9.337669 7.78122 0 15.562441-3.112897 21.787213-9.337669l85.594447-88.706321c40.46255 28.013007 88.706321 54.469566 141.619438 73.14388L340.959485 707.631586c-4.668323 17.118889 4.669346 34.237779 21.787213 38.906101h9.337669c14.005992 0 26.456558-9.337669 29.568432-23.343661l32.68133-110.494556c24.90011 4.668323 51.356668 7.78122 77.813227 7.78122s52.913117-3.112897 77.813227-7.78122l32.68133 108.938108c3.112897 14.005992 17.118889 23.343661 29.569456 23.343661 3.112897 0 6.224772 0 7.78122-1.556449 17.118889-4.669346 26.456558-21.787212 21.788236-38.906102l-32.68133-108.938108c52.913117-18.675338 101.156888-45.131897 141.619438-73.14388l84.037998 87.150896c6.224772 6.224772 14.005992 9.337669 21.787212 9.337669 7.78122 0 15.562441-3.112897 21.787212-9.337669 12.450567-12.450567 12.450567-31.124881 1.556449-43.575448l-79.369675-82.48155c63.808258-46.688345 101.158934-91.820242 101.158934-91.820242z" p-id="7879"></path></svg>

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

@@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1503993891882" class="icon" style="" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="7986" xmlns:xlink="http://www.w3.org/1999/xlink" width="64" height="64"><defs><style type="text/css"></style></defs><path d="M504.951 511.98c93.49 0 169.28-74.002 169.28-165.26 0-91.276-75.79-165.248-169.28-165.248-93.486 0-169.287 73.972-169.279 165.248-0.001 91.258 75.793 165.26 169.28 165.26z m77.6 55.098H441.466c-120.767 0-218.678 95.564-218.678 213.45V794.3c0 48.183 97.911 48.229 218.678 48.229H582.55c120.754 0 218.66-1.78 218.66-48.229v-13.77c0-117.887-97.898-213.45-218.66-213.45z" p-id="7987"></path></svg>

After

Width:  |  Height:  |  Size: 777 B

1
src/icons/svg/zonghe.svg Normal file
View File

@@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1503994811583" class="icon" style="" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="9878" xmlns:xlink="http://www.w3.org/1999/xlink" width="64" height="64"><defs><style type="text/css"></style></defs><path d="M770.56 460.8l250.88 0C998.4 220.16 803.84 25.6 563.2 2.56l0 250.88C668.16 273.92 750.08 355.84 770.56 460.8L770.56 460.8zM770.56 460.8" p-id="9879"></path><path d="M460.8 253.44 460.8 2.56C220.16 25.6 25.6 220.16 2.56 460.8l250.88 0C273.92 355.84 355.84 273.92 460.8 253.44L460.8 253.44zM460.8 253.44" p-id="9880"></path><path d="M563.2 770.56l0 250.88c243.2-23.04 435.2-217.6 460.8-460.8l-250.88 0C750.08 668.16 668.16 750.08 563.2 770.56L563.2 770.56zM563.2 770.56" p-id="9881"></path><path d="M253.44 563.2 2.56 563.2c23.04 243.2 217.6 435.2 460.8 460.8l0-250.88C355.84 750.08 273.92 668.16 253.44 563.2L253.44 563.2zM253.44 563.2" p-id="9882"></path></svg>

After

Width:  |  Height:  |  Size: 1.0 KiB

1
src/icons/svg/zujian.svg Normal file
View File

@@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1503994912370" class="icon" style="" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="10530" xmlns:xlink="http://www.w3.org/1999/xlink" width="64" height="64"><defs><style type="text/css"></style></defs><path d="M568.6 0h454.9v454.9H568.6V0z m0 568.6h454.9v454.9H568.6V568.6zM0 568.6h454.9v454.9H0V568.6zM0 0h454.9v454.9H0V0z" fill="" p-id="10531"></path></svg>

After

Width:  |  Height:  |  Size: 534 B

View File

@@ -1,102 +1,23 @@
// The Vue build version to load with the `import` command import Vue from 'vue'
// (runtime-only or standalone) has been set in webpack.base.conf with an alias. import ElementUI from 'element-ui'
import Vue from 'vue'; import 'element-ui/lib/theme-default/index.css'
import App from './App'; import App from './App'
import router from './router'; import router from './router'
import store from './store'; import store from './store'
import ElementUI from 'element-ui'; import * as filters from '@/filters' // 全局filter
import 'element-ui/lib/theme-default/index.css'; import '@/icons' // icon
import 'assets/custom-theme/index.css'; // 换肤版本element-ui css import '@/errorLog'// error log
import NProgress from 'nprogress'; // Progress 进度条 import '@/permission' // 权限
import 'nprogress/nprogress.css';// Progress 进度条 样式 import '@/mock' // 该项目所有请求使用mockjs模拟
import 'normalize.css/normalize.css';// normalize.css 样式格式化
import 'assets/iconfont/iconfont'; // iconfont 具体图标见https://github.com/PanJiaChen/vue-element-admin/wiki
import * as filters from './filters'; // 全局vue filter
import Multiselect from 'vue-multiselect';// 使用的一个多选框组件element-ui的select不能满足所有需求
import 'vue-multiselect/dist/vue-multiselect.min.css';// 多选框组件css
import Sticky from 'components/Sticky'; // 粘性header组件
import IconSvg from 'components/Icon-svg';// svg 组件
import vueWaves from './directive/waves';// 水波纹指令
import errLog from 'store/errLog';// error log组件
import './mock/index.js'; // 该项目所有请求使用mockjs模拟
import { getToken } from 'utils/auth';
// register globally Vue.use(ElementUI)
Vue.component('multiselect', Multiselect);
Vue.component('Sticky', Sticky);
Vue.component('icon-svg', IconSvg)
Vue.use(ElementUI);
Vue.use(vueWaves);
// register global utility filters. // register global utility filters.
Object.keys(filters).forEach(key => { Object.keys(filters).forEach(key => {
Vue.filter(key, filters[key]) Vue.filter(key, filters[key])
}); })
// permissiom judge Vue.config.productionTip = false
function hasPermission(roles, permissionRoles) {
if (roles.indexOf('admin') >= 0) return true; // admin权限 直接通过
if (!permissionRoles) return true;
return roles.some(role => permissionRoles.indexOf(role) >= 0)
}
// register global progress.
const whiteList = ['/login', '/authredirect', '/reset', '/sendpwd'];// 不重定向白名单
router.beforeEach((to, from, next) => {
NProgress.start(); // 开启Progress
if (getToken()) { // 判断是否有token
if (to.path === '/login') {
next({ path: '/' });
} else {
if (store.getters.roles.length === 0) { // 判断当前用户是否已拉取完user_info信息
store.dispatch('GetInfo').then(res => { // 拉取user_info
const roles = res.data.role;
store.dispatch('GenerateRoutes', { roles }).then(() => { // 生成可访问的路由表
router.addRoutes(store.getters.addRouters) // 动态添加可访问路由表
next({ ...to }); // hack方法 确保addRoutes已完成
})
}).catch(() => {
store.dispatch('FedLogOut').then(() => {
next({ path: '/login' });
})
})
} else {
// 没有动态改变权限的需求可直接next() 删除下方权限判断 ↓
if (hasPermission(store.getters.roles, to.meta.role)) {
next();//
} else {
next({ path: '/401', query: { noGoBack: true } });
}
// 可删 ↑
}
}
} else {
if (whiteList.indexOf(to.path) !== -1) { // 在免登录白名单,直接进入
next()
} else {
next('/login'); // 否则全部重定向到登录页
NProgress.done(); // 在hash模式下 改变手动改变hash 重定向回来 不会触发afterEach 暂时hack方案 pshistory模式下无问题可删除该行
}
}
});
router.afterEach(() => {
NProgress.done(); // 结束Progress
});
Vue.config.productionTip = false;
// 生产环境错误日志
if (process.env === 'production') {
Vue.config.errorHandler = function(err, vm) {
console.log(err, window.location.href);
errLog.pushLog({
err,
url: window.location.href,
vm
})
};
}
new Vue({ new Vue({
el: '#app', el: '#app',
@@ -105,5 +26,3 @@ new Vue({
template: '<App/>', template: '<App/>',
components: { App } components: { App }
}) })

View File

@@ -1,23 +1,50 @@
import Mock from 'mockjs'; import Mock from 'mockjs'
import { param2Obj } from '@/utils'
const List = [];
const count = 20;
const List = []
const count = 100
for (let i = 0; i < count; i++) { for (let i = 0; i < count; i++) {
List.push(Mock.mock({ List.push(Mock.mock({
id: '@id', id: '@increment',
title: '@ctitle(10, 20)', timestamp: +Mock.Random.date('T'),
'status|1': ['published', 'draft'],
author: '@cname', author: '@cname',
auditor: '@cname',
title: '@ctitle(10, 20)',
forecast: '@float(0, 100, 2, 2)',
importance: '@integer(1, 3)',
'type|1': ['CN', 'US', 'JP', 'EU'],
'status|1': ['published', 'draft', 'deleted'],
display_time: '@datetime', display_time: '@datetime',
pageviews: '@integer(300, 5000)' pageviews: '@integer(300, 5000)'
})); }))
} }
export default { export default {
getList: () => List, getList: config => {
const { importance, type, title, page = 1, limit = 20, sort } = param2Obj(config.url)
let mockList = List.filter(item => {
if (importance && item.importance !== +importance) return false
if (type && item.type !== type) return false
if (title && item.title.indexOf(title) < 0) return false
return true
})
if (sort === '-id') {
mockList = mockList.reverse()
}
const pageList = mockList.filter((item, index) => index < limit * page && index >= limit * (page - 1))
return {
total: mockList.length,
items: pageList
}
},
getPv: () => ({
pvData: [{ key: 'PC网站', pv: 1024 }, { key: 'mobile网站', pv: 1024 }, { key: 'ios', pv: 1024 }, { key: 'android', pv: 1024 }]
}),
getArticle: () => ({ getArticle: () => ({
id: 120000000001, id: 120000000001,
author: { key: 'mockPan' }, author: { key: 'mockPan' },
@@ -34,4 +61,4 @@ export default {
tags: [], tags: [],
title: '' title: ''
}) })
}; }

View File

@@ -1,44 +0,0 @@
import Mock from 'mockjs';
import { param2Obj } from 'utils';
const List = [];
const count = 100;
for (let i = 0; i < count; i++) {
List.push(Mock.mock({
id: '@increment',
timestamp: +Mock.Random.date('T'),
author: '@cname',
auditor: '@cname',
title: '@ctitle(10, 20)',
forecast: '@float(0, 100, 2, 2)',
importance: '@integer(1, 3)',
'type|1': ['CN', 'US', 'JP', 'EU'],
'status|1': ['published', 'draft', 'deleted'],
pageviews: '@integer(300, 5000)'
}));
}
export default {
getList: config => {
const { importance, type, title, page, limit, sort } = param2Obj(config.url);
let mockList = List.filter(item => {
if (importance && item.importance !== +importance) return false;
if (type && item.type !== type) return false;
if (title && item.title.indexOf(title) < 0) return false;
return true;
});
if (sort === '-id') {
mockList = mockList.reverse()
}
const pageList = mockList.filter((item, index) => index < limit * page && index >= limit * (page - 1));
return {
total: mockList.length,
items: pageList
}
},
getPv: () => ({
pvData: [{ key: 'PC网站', pv: 1024 }, { key: 'mobile网站', pv: 1024 }, { key: 'ios', pv: 1024 }, { key: 'android', pv: 1024 }]
})
};

View File

@@ -1,25 +1,23 @@
import Mock from 'mockjs'; import Mock from 'mockjs'
import loginAPI from './login'; import loginAPI from './login'
import articleAPI from './article'; import articleAPI from './article'
import article_tableAPI from './article_table'; import remoteSearchAPI from './remoteSearch'
import remoteSearchAPI from './remoteSearch';
Mock.setup({
timeout: '350-600'
})
// 登录相关 // 登录相关
Mock.mock(/\/login\/loginbyemail/, 'post', loginAPI.loginByEmail); Mock.mock(/\/login\/login/, 'post', loginAPI.loginByUsername)
Mock.mock(/\/login\/logout/, 'post', loginAPI.logout); Mock.mock(/\/login\/logout/, 'post', loginAPI.logout)
Mock.mock(/\/user\/info\.*/, 'get', loginAPI.getInfo) Mock.mock(/\/user\/info\.*/, 'get', loginAPI.getUserInfo)
// // 文章相关 // 文章相关
Mock.mock(/\/article\/list/, 'get', articleAPI.getList); Mock.mock(/\/article\/list/, 'get', articleAPI.getList)
Mock.mock(/\/article\/detail/, 'get', articleAPI.getArticle); Mock.mock(/\/article\/detail/, 'get', articleAPI.getArticle)
Mock.mock(/\/article\/pv/, 'get', articleAPI.getPv)
// // table example相关 // 搜索相关
Mock.mock(/\/article_table\/list/, 'get', article_tableAPI.getList); Mock.mock(/\/search\/user/, 'get', remoteSearchAPI.searchUser)
Mock.mock(/\/article_table\/p/, 'get', article_tableAPI.getPv);
// // 搜索相关 export default Mock
Mock.mock(/\/search\/user/, 'get', remoteSearchAPI.searchUser);
export default Mock;

View File

@@ -1,4 +1,4 @@
import { param2Obj } from 'utils'; import { param2Obj } from '@/utils'
const userMap = { const userMap = {
admin: { admin: {
@@ -25,17 +25,17 @@ const userMap = {
} }
export default { export default {
loginByEmail: config => { loginByUsername: config => {
const { email } = JSON.parse(config.body); const { username } = JSON.parse(config.body)
return userMap[email.split('@')[0]]; return userMap[username]
}, },
getInfo: config => { getUserInfo: config => {
const { token } = param2Obj(config.url); const { token } = param2Obj(config.url)
if (userMap[token]) { if (userMap[token]) {
return userMap[token]; return userMap[token]
} else { } else {
return Promise.reject('a'); return Promise.reject('error')
} }
}, },
logout: () => 'success' logout: () => 'success'
}; }

View File

@@ -1,24 +1,24 @@
import Mock from 'mockjs'; import Mock from 'mockjs'
import { param2Obj } from 'utils'; import { param2Obj } from '@/utils'
const NameList = []; const NameList = []
const count = 100; const count = 100
for (let i = 0; i < count; i++) { for (let i = 0; i < count; i++) {
NameList.push(Mock.mock({ NameList.push(Mock.mock({
name: '@first' name: '@first'
})); }))
} }
NameList.push({ name: 'mockPan' }) NameList.push({ name: 'mockPan' })
export default { export default {
searchUser: config => { searchUser: config => {
const { name } = param2Obj(config.url); const { name } = param2Obj(config.url)
const mockNameList = NameList.filter(item => { const mockNameList = NameList.filter(item => {
const lowerCaseName = item.name.toLowerCase() const lowerCaseName = item.name.toLowerCase()
if (name && lowerCaseName.indexOf(name.toLowerCase()) < 0) return false; if (name && lowerCaseName.indexOf(name.toLowerCase()) < 0) return false
return true; return true
}); })
return { items: mockNameList } return { items: mockNameList }
} }
}; }

56
src/permission.js Normal file
View File

@@ -0,0 +1,56 @@
import router from './router'
import store from './store'
import NProgress from 'nprogress' // Progress 进度条
import 'nprogress/nprogress.css'// Progress 进度条样式
import { getToken } from '@/utils/auth' // 验权
// permissiom judge
function hasPermission(roles, permissionRoles) {
if (roles.indexOf('admin') >= 0) return true // admin权限 直接通过
if (!permissionRoles) return true
return roles.some(role => permissionRoles.indexOf(role) >= 0)
}
// register global progress.
const whiteList = ['/login', '/authredirect']// 不重定向白名单
router.beforeEach((to, from, next) => {
NProgress.start() // 开启Progress
if (getToken()) { // 判断是否有token
if (to.path === '/login') {
next({ path: '/' })
} else {
if (store.getters.roles.length === 0) { // 判断当前用户是否已拉取完user_info信息
store.dispatch('GetUserInfo').then(res => { // 拉取user_info
const roles = res.data.role
store.dispatch('GenerateRoutes', { roles }).then(() => { // 生成可访问的路由表
router.addRoutes(store.getters.addRouters) // 动态添加可访问路由表
next({ ...to }) // hack方法 确保addRoutes已完成
})
}).catch(() => {
store.dispatch('FedLogOut').then(() => {
next({ path: '/login' })
})
})
} else {
// 没有动态改变权限的需求可直接next() 删除下方权限判断 ↓
if (hasPermission(store.getters.roles, to.meta.role)) {
next()//
} else {
next({ path: '/401', query: { noGoBack: true }})
}
// 可删 ↑
}
}
} else {
if (whiteList.indexOf(to.path) !== -1) { // 在免登录白名单,直接进入
next()
} else {
next('/login') // 否则全部重定向到登录页
NProgress.done() // 在hash模式下 改变手动改变hash 重定向回来 不会触发afterEach 暂时hack方案 pshistory模式下无问题可删除该行
}
}
})
router.afterEach(() => {
NProgress.done() // 结束Progress
})

View File

@@ -1 +1 @@
module.exports = file => require('@/views/' + file + '.vue') module.exports = file => require('@/views/' + file + '.vue').default

View File

@@ -1,91 +1,32 @@
import Vue from 'vue'; import Vue from 'vue'
import Router from 'vue-router'; import Router from 'vue-router'
const _import = require('./_import_' + process.env.NODE_ENV); const _import = require('./_import_' + process.env.NODE_ENV)
// in development env not use Lazy Loading,because Lazy Loading large page will cause webpack hot update too slow.so only in production use Lazy Loading // in development env not use Lazy Loading,because Lazy Loading too many pages will cause webpack hot update too slow.so only in production use Lazy Loading
Vue.use(Router)
/* layout */ /* layout */
import Layout from '../views/layout/Layout'; import Layout from '../views/layout/Layout'
/* login */
const Login = _import('login/index');
const authRedirect = _import('login/authredirect');
/* dashboard */
const dashboard = _import('dashboard/index');
/* Introduction */
const Introduction = _import('introduction/index');
/* components */
const componentsIndex = _import('components/index');
const Tinymce = _import('components/tinymce');
const Markdown = _import('components/markdown');
const JsonEditor = _import('components/jsoneditor');
const DndList = _import('components/dndlist');
const AvatarUpload = _import('components/avatarUpload');
const Dropzone = _import('components/dropzone');
const Sticky = _import('components/sticky');
const SplitPane = _import('components/splitpane');
const CountTo = _import('components/countTo');
const Mixin = _import('components/mixin');
const BackToTop = _import('components/backToTop')
/* charts */
const chartIndex = _import('charts/index');
const KeyboardChart = _import('charts/keyboard');
const KeyboardChart2 = _import('charts/keyboard2');
const LineMarker = _import('charts/line');
const MixChart = _import('charts/mixChart');
/* error page */
const Err404 = _import('error/404');
const Err401 = _import('error/401');
/* error log */
const ErrorLog = _import('errlog/index');
/* excel */
const ExcelDownload = _import('excel/index');
const SelectExcelDownload = _import('excel/selectExcel');
/* theme */
const Theme = _import('theme/index');
/* example */
const TableLayout = _import('example/table/index');
const DynamicTable = _import('example/table/dynamictable');
const Table = _import('example/table/table');
const DragTable = _import('example/table/dragTable');
const InlineEditTable = _import('example/table/inlineEditTable');
const Form = _import('example/form');
const Tab = _import('example/tab/index');
/* permission */
const Permission = _import('permission/index');
Vue.use(Router);
/**
* icon : the icon show in the sidebar
* hidden : if hidden:true will not show in the sidebar
* redirect : if redirect:noredirect will not redirct in the levelbar
* noDropdown : if noDropdown:true will not has submenu
* meta : { role: ['admin'] } will control the page role
**/
/**
* icon : the icon show in the sidebar
* hidden : if `hidden:true` will not show in the sidebar
* redirect : if `redirect:noredirect` will no redirct in the levelbar
* noDropdown : if `noDropdown:true` will has no submenu
* meta : { role: ['admin'] } will control the page role
**/
export const constantRouterMap = [ export const constantRouterMap = [
{ path: '/login', component: Login, hidden: true }, { path: '/login', component: _import('login/index'), hidden: true },
{ path: '/authredirect', component: authRedirect, hidden: true }, { path: '/authredirect', component: _import('login/authredirect'), hidden: true },
{ path: '/404', component: Err404, hidden: true }, { path: '/404', component: _import('errorPage/404'), hidden: true },
{ path: '/401', component: Err401, hidden: true }, { path: '/401', component: _import('errorPage/401'), hidden: true },
{ {
path: '/', path: '/',
component: Layout, component: Layout,
redirect: '/dashboard', redirect: '/dashboard',
name: '首页', name: '首页',
hidden: true, hidden: true,
children: [{ path: 'dashboard', component: dashboard }] children: [{ path: 'dashboard', component: _import('dashboard/index') }]
}, },
{ {
path: '/introduction', path: '/introduction',
@@ -93,7 +34,7 @@ export const constantRouterMap = [
redirect: '/introduction/index', redirect: '/introduction/index',
icon: 'xinrenzhinan', icon: 'xinrenzhinan',
noDropdown: true, noDropdown: true,
children: [{ path: 'index', component: Introduction, name: '简述' }] children: [{ path: 'index', component: _import('introduction/index'), name: '简述' }]
} }
] ]
@@ -101,7 +42,7 @@ export default new Router({
// mode: 'history', //后端支持可开 // mode: 'history', //后端支持可开
scrollBehavior: () => ({ y: 0 }), scrollBehavior: () => ({ y: 0 }),
routes: constantRouterMap routes: constantRouterMap
}); })
export const asyncRouterMap = [ export const asyncRouterMap = [
{ {
@@ -112,7 +53,14 @@ export const asyncRouterMap = [
icon: 'quanxian', icon: 'quanxian',
meta: { role: ['admin'] }, meta: { role: ['admin'] },
noDropdown: true, noDropdown: true,
children: [{ path: 'index', component: Permission, name: '权限测试页', meta: { role: ['admin'] } }] children: [{ path: 'index', component: _import('permission/index'), name: '权限测试页', meta: { role: ['admin'] }}]
},
{
path: '/icon',
component: Layout,
icon: 'icons',
noDropdown: true,
children: [{ path: 'index', component: _import('svg-icons/index'), name: 'icons' }]
}, },
{ {
path: '/components', path: '/components',
@@ -121,18 +69,18 @@ export const asyncRouterMap = [
name: '组件', name: '组件',
icon: 'zujian', icon: 'zujian',
children: [ children: [
{ path: 'index', component: componentsIndex, name: '介绍 ' }, { path: 'index', component: _import('components/index'), name: '介绍 ' },
{ path: 'tinymce', component: Tinymce, name: '富文本编辑器' }, { path: 'tinymce', component: _import('components/tinymce'), name: '富文本编辑器' },
{ path: 'markdown', component: Markdown, name: 'Markdown' }, { path: 'markdown', component: _import('components/markdown'), name: 'Markdown' },
{ path: 'jsoneditor', component: JsonEditor, name: 'JSON编辑器' }, { path: 'jsoneditor', component: _import('components/jsonEditor'), name: 'JSON编辑器' },
{ path: 'dndlist', component: DndList, name: '列表拖拽' }, { path: 'dndlist', component: _import('components/dndList'), name: '列表拖拽' },
{ path: 'splitpane', component: SplitPane, name: 'SplitPane' }, { path: 'splitpane', component: _import('components/splitpane'), name: 'SplitPane' },
{ path: 'avatarupload', component: AvatarUpload, name: '头像上传' }, { path: 'avatarupload', component: _import('components/avatarUpload'), name: '头像上传' },
{ path: 'dropzone', component: Dropzone, name: 'Dropzone' }, { path: 'dropzone', component: _import('components/dropzone'), name: 'Dropzone' },
{ path: 'sticky', component: Sticky, name: 'Sticky' }, { path: 'sticky', component: _import('components/sticky'), name: 'Sticky' },
{ path: 'countto', component: CountTo, name: 'CountTo' }, { path: 'countto', component: _import('components/countTo'), name: 'CountTo' },
{ path: 'mixin', component: Mixin, name: '小组件' }, { path: 'mixin', component: _import('components/mixin'), name: '小组件' },
{ path: 'backtotop', component: BackToTop, name: '返回顶部' } { path: 'backtotop', component: _import('components/backToTop'), name: '返回顶部' }
] ]
}, },
{ {
@@ -140,55 +88,15 @@ export const asyncRouterMap = [
component: Layout, component: Layout,
redirect: '/charts/index', redirect: '/charts/index',
name: '图表', name: '图表',
icon: 'tubiaoleixingzhengchang', icon: 'tubiao',
children: [ children: [
{ path: 'index', component: chartIndex, name: '介绍' }, { path: 'index', component: _import('charts/index'), name: '介绍' },
{ path: 'keyboard', component: KeyboardChart, name: '键盘图表' }, { path: 'keyboard', component: _import('charts/keyboard'), name: '键盘图表' },
{ path: 'keyboard2', component: KeyboardChart2, name: '键盘图表2' }, { path: 'keyboard2', component: _import('charts/keyboard2'), name: '键盘图表2' },
{ path: 'line', component: LineMarker, name: '折线图' }, { path: 'line', component: _import('charts/line'), name: '折线图' },
{ path: 'mixchart', component: MixChart, name: '混合图表' } { path: 'mixchart', component: _import('charts/mixChart'), name: '混合图表' }
] ]
}, },
{
path: '/errorpage',
component: Layout,
redirect: 'noredirect',
name: '错误页面',
icon: '404',
children: [
{ path: '401', component: Err401, name: '401' },
{ path: '404', component: Err404, name: '404' }
]
},
{
path: '/errlog',
component: Layout,
redirect: 'noredirect',
name: 'errlog',
icon: 'bug',
noDropdown: true,
children: [{ path: 'log', component: ErrorLog, name: '错误日志' }]
},
{
path: '/excel',
component: Layout,
redirect: 'noredirect',
name: 'excel',
icon: 'EXCEL',
children: [
{ path: 'download', component: ExcelDownload, name: '导出excel' },
{ path: 'download2', component: SelectExcelDownload, name: '选择导出excel' }
]
},
{
path: '/theme',
component: Layout,
redirect: 'noredirect',
name: 'theme',
icon: 'theme',
noDropdown: true,
children: [{ path: 'index', component: Theme, name: '换肤' }]
},
{ {
path: '/example', path: '/example',
component: Layout, component: Layout,
@@ -198,21 +106,62 @@ export const asyncRouterMap = [
children: [ children: [
{ {
path: '/example/table', path: '/example/table',
component: TableLayout, component: _import('example/table/index'),
redirect: '/example/table/table', redirect: '/example/table/table',
name: 'Table', name: 'Table',
icon: 'table',
children: [ children: [
{ path: 'dynamictable', component: DynamicTable, name: '动态table' }, { path: 'dynamictable', component: _import('example/table/dynamictable/index'), name: '动态table' },
{ path: 'dragtable', component: DragTable, name: '拖拽table' }, { path: 'dragtable', component: _import('example/table/dragTable'), name: '拖拽table' },
{ path: 'inline_edit_table', component: InlineEditTable, name: 'table内编辑' }, { path: 'inline_edit_table', component: _import('example/table/inlineEditTable'), name: 'table内编辑' },
{ path: 'table', component: Table, name: '综合table' } { path: 'table', component: _import('example/table/table'), name: '综合table' }
] ]
}, },
{ path: 'form/edit', component: Form, name: '编辑Form', meta: { isEdit: true } }, { path: 'form/edit', icon: 'shouce', component: _import('example/form'), name: '编辑Form', meta: { isEdit: true }},
{ path: 'form/create', component: Form, name: '创建Form' }, { path: 'form/create', icon: 'from', component: _import('example/form'), name: '创建Form' },
{ path: 'tab/index', icon: 'tab', component: _import('example/tab/index'), name: 'Tab' }
{ path: 'tab/index', component: Tab, name: 'Tab' }
] ]
}, },
{
path: '/error',
component: Layout,
redirect: 'noredirect',
name: '错误页面',
icon: '404',
children: [
{ path: '401', component: _import('errorPage/401'), name: '401' },
{ path: '404', component: _import('errorPage/404'), name: '404' }
]
},
{
path: '/errlog',
component: Layout,
redirect: 'noredirect',
name: 'errlog',
icon: 'bug',
noDropdown: true,
children: [{ path: 'log', component: _import('errlog/index'), name: '错误日志' }]
},
{
path: '/excel',
component: Layout,
redirect: '/excel/download',
name: 'excel',
icon: 'EXCEL',
children: [
{ path: 'download', component: _import('excel/index'), name: '导出excel' },
{ path: 'download2', component: _import('excel/selectExcel'), name: '导出已选择项' }
]
},
{
path: '/theme',
component: Layout,
redirect: 'noredirect',
name: 'theme',
icon: 'theme',
noDropdown: true,
children: [{ path: 'index', component: _import('theme/index'), name: '换肤' }]
},
{ path: '*', redirect: '/404', hidden: true } { path: '*', redirect: '/404', hidden: true }
]; ]

View File

@@ -6,8 +6,8 @@ const errLog = {
this.state.errLog.unshift(log) this.state.errLog.unshift(log)
}, },
clearLog() { clearLog() {
this.state.errLog = []; this.state.errLog = []
} }
}; }
export default errLog; export default errLog

View File

@@ -10,5 +10,5 @@ const getters = {
setting: state => state.user.setting, setting: state => state.user.setting,
permission_routers: state => state.permission.routers, permission_routers: state => state.permission.routers,
addRouters: state => state.permission.addRouters addRouters: state => state.permission.addRouters
}; }
export default getters export default getters

View File

@@ -1,11 +1,11 @@
import Vue from 'vue'; import Vue from 'vue'
import Vuex from 'vuex'; import Vuex from 'vuex'
import app from './modules/app'; import app from './modules/app'
import user from './modules/user'; import user from './modules/user'
import permission from './modules/permission'; import permission from './modules/permission'
import getters from './getters'; import getters from './getters'
Vue.use(Vuex); Vue.use(Vuex)
const store = new Vuex.Store({ const store = new Vuex.Store({
modules: { modules: {
@@ -14,6 +14,6 @@ const store = new Vuex.Store({
permission permission
}, },
getters getters
}); })
export default store export default store

View File

@@ -1,22 +1,20 @@
import Cookies from 'js-cookie'; import Cookies from 'js-cookie'
const app = { const app = {
state: { state: {
sidebar: { sidebar: {
opened: !+Cookies.get('sidebarStatus') opened: !+Cookies.get('sidebarStatus')
}, },
theme: 'default',
livenewsChannels: Cookies.get('livenewsChannels') || '[]',
visitedViews: [] visitedViews: []
}, },
mutations: { mutations: {
TOGGLE_SIDEBAR: state => { TOGGLE_SIDEBAR: state => {
if (state.sidebar.opened) { if (state.sidebar.opened) {
Cookies.set('sidebarStatus', 1); Cookies.set('sidebarStatus', 1)
} else { } else {
Cookies.set('sidebarStatus', 0); Cookies.set('sidebarStatus', 0)
} }
state.sidebar.opened = !state.sidebar.opened; state.sidebar.opened = !state.sidebar.opened
}, },
ADD_VISITED_VIEWS: (state, view) => { ADD_VISITED_VIEWS: (state, view) => {
if (state.visitedViews.some(v => v.path === view.path)) return if (state.visitedViews.some(v => v.path === view.path)) return
@@ -44,6 +42,6 @@ const app = {
commit('DEL_VISITED_VIEWS', view) commit('DEL_VISITED_VIEWS', view)
} }
} }
}; }
export default app; export default app

View File

@@ -1,5 +1,4 @@
import { asyncRouterMap, constantRouterMap } from 'src/router'; import { asyncRouterMap, constantRouterMap } from '@/router'
import { deepClone } from 'utils'
/** /**
* 通过meta.role判断是否与当前用户权限匹配 * 通过meta.role判断是否与当前用户权限匹配
@@ -39,8 +38,8 @@ const permission = {
}, },
mutations: { mutations: {
SET_ROUTERS: (state, routers) => { SET_ROUTERS: (state, routers) => {
state.addRouters = deepClone(routers) state.addRouters = routers
state.routers = deepClone(constantRouterMap.concat(routers)) state.routers = constantRouterMap.concat(routers)
} }
}, },
actions: { actions: {
@@ -53,11 +52,11 @@ const permission = {
} else { } else {
accessedRouters = filterAsyncRouter(asyncRouterMap, roles) accessedRouters = filterAsyncRouter(asyncRouterMap, roles)
} }
commit('SET_ROUTERS', accessedRouters); commit('SET_ROUTERS', accessedRouters)
resolve(); resolve()
}) })
} }
} }
}; }
export default permission; export default permission

View File

@@ -1,5 +1,5 @@
import { loginByEmail, logout, getInfo } from 'api/login'; import { loginByUsername, logout, getUserInfo } from '@/api/login'
import { getToken, setToken, removeToken } from 'utils/auth'; import { getToken, setToken, removeToken } from '@/utils/auth'
const user = { const user = {
state: { state: {
@@ -18,116 +18,116 @@ const user = {
mutations: { mutations: {
SET_CODE: (state, code) => { SET_CODE: (state, code) => {
state.code = code; state.code = code
}, },
SET_TOKEN: (state, token) => { SET_TOKEN: (state, token) => {
state.token = token; state.token = token
}, },
SET_INTRODUCTION: (state, introduction) => { SET_INTRODUCTION: (state, introduction) => {
state.introduction = introduction; state.introduction = introduction
}, },
SET_SETTING: (state, setting) => { SET_SETTING: (state, setting) => {
state.setting = setting; state.setting = setting
}, },
SET_STATUS: (state, status) => { SET_STATUS: (state, status) => {
state.status = status; state.status = status
}, },
SET_NAME: (state, name) => { SET_NAME: (state, name) => {
state.name = name; state.name = name
}, },
SET_AVATAR: (state, avatar) => { SET_AVATAR: (state, avatar) => {
state.avatar = avatar; state.avatar = avatar
}, },
SET_ROLES: (state, roles) => { SET_ROLES: (state, roles) => {
state.roles = roles; state.roles = roles
},
LOGIN_SUCCESS: () => {
console.log('login success')
},
LOGOUT_USER: state => {
state.user = '';
} }
}, },
actions: { actions: {
// 邮箱登录 // 用户名登录
LoginByEmail({ commit }, userInfo) { LoginByUsername({ commit }, userInfo) {
const email = userInfo.email.trim(); const username = userInfo.username.trim()
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
loginByEmail(email, userInfo.password).then(response => { loginByUsername(username, userInfo.password).then(response => {
const data = response.data; const data = response.data
setToken(response.data.token); setToken(response.data.token)
commit('SET_TOKEN', data.token); commit('SET_TOKEN', data.token)
resolve(); resolve()
}).catch(error => { }).catch(error => {
reject(error); reject(error)
}); })
}); })
}, },
// 获取用户信息 // 获取用户信息
GetInfo({ commit, state }) { GetUserInfo({ commit, state }) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
getInfo(state.token).then(response => { getUserInfo(state.token).then(response => {
const data = response.data; const data = response.data
commit('SET_ROLES', data.role); commit('SET_ROLES', data.role)
commit('SET_NAME', data.name); commit('SET_NAME', data.name)
commit('SET_AVATAR', data.avatar); commit('SET_AVATAR', data.avatar)
commit('SET_INTRODUCTION', data.introduction); commit('SET_INTRODUCTION', data.introduction)
resolve(response); resolve(response)
}).catch(error => { }).catch(error => {
reject(error); reject(error)
}); })
}); })
}, },
// 第三方验证登录 // 第三方验证登录
LoginByThirdparty({ commit, state }, code) { // LoginByThirdparty({ commit, state }, code) {
return new Promise((resolve, reject) => { // return new Promise((resolve, reject) => {
commit('SET_CODE', code); // commit('SET_CODE', code)
loginByThirdparty(state.status, state.email, state.code).then(response => { // loginByThirdparty(state.status, state.email, state.code).then(response => {
commit('SET_TOKEN', response.data.token); // commit('SET_TOKEN', response.data.token)
setToken(response.data.token); // setToken(response.data.token)
resolve(); // resolve()
}).catch(error => { // }).catch(error => {
reject(error); // reject(error)
}); // })
}); // })
}, // },
// 登出 // 登出
LogOut({ commit, state }) { LogOut({ commit, state }) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
logout(state.token).then(() => { logout(state.token).then(() => {
commit('SET_TOKEN', ''); commit('SET_TOKEN', '')
commit('SET_ROLES', []); commit('SET_ROLES', [])
removeToken(); removeToken()
resolve(); resolve()
}).catch(error => { }).catch(error => {
reject(error); reject(error)
}); })
}); })
}, },
// 前端 登出 // 前端 登出
FedLogOut({ commit }) { FedLogOut({ commit }) {
return new Promise(resolve => { return new Promise(resolve => {
commit('SET_TOKEN', ''); commit('SET_TOKEN', '')
removeToken(); removeToken()
resolve(); resolve()
}); })
}, },
// 动态修改权限 // 动态修改权限
ChangeRole({ commit }, role) { ChangeRole({ commit }, role) {
return new Promise(resolve => { return new Promise(resolve => {
commit('SET_ROLES', [role]); commit('SET_TOKEN', role)
commit('SET_TOKEN', role); setToken(role)
setToken(role); getUserInfo(role).then(response => {
resolve(); const data = response.data
commit('SET_ROLES', data.role)
commit('SET_NAME', data.name)
commit('SET_AVATAR', data.avatar)
commit('SET_INTRODUCTION', data.introduction)
resolve()
})
}) })
} }
} }
}; }
export default user; export default user

View File

@@ -5,29 +5,27 @@ $pink: #E65D6E;
$green: #30B08F; $green: #30B08F;
$tiffany: #4AB7BD; $tiffany: #4AB7BD;
$yellow:#FEC171; $yellow:#FEC171;
$panGreen: #30B08F; $panGreen: #30B08F;
@mixin colorBtn($color) { @mixin colorBtn($color) {
background: $color; background: $color;
&:hover { &:hover {
color: $color; color: $color;
&:before, &:after { &:before,
&:after {
background: $color; background: $color;
} }
} }
} }
.blue-btn { .blue-btn {
@include colorBtn($blue) @include colorBtn($blue)
} }
.light-blue-btn{ .light-blue-btn {
@include colorBtn($light-blue) @include colorBtn($light-blue)
} }
.red-btn { .red-btn {
@include colorBtn($red) @include colorBtn($red)
} }
@@ -40,12 +38,10 @@ $panGreen: #30B08F;
@include colorBtn($green) @include colorBtn($green)
} }
.tiffany-btn { .tiffany-btn {
@include colorBtn($tiffany) @include colorBtn($tiffany)
} }
.yellow-btn { .yellow-btn {
@include colorBtn($yellow) @include colorBtn($yellow)
} }
@@ -63,12 +59,14 @@ $panGreen: #30B08F;
display: inline-block; display: inline-block;
&:hover { &:hover {
background: #fff; background: #fff;
&:before, &:after { &:before,
&:after {
width: 100%; width: 100%;
transition: 600ms ease all; transition: 600ms ease all;
} }
} }
&:before, &:after { &:before,
&:after {
content: ''; content: '';
position: absolute; position: absolute;
top: 0; top: 0;
@@ -85,19 +83,20 @@ $panGreen: #30B08F;
} }
} }
.custom-button{ .custom-button {
display: inline-block; display: inline-block;
line-height: 1; line-height: 1;
white-space: nowrap; white-space: nowrap;
cursor: pointer; cursor: pointer;
background: #fff; background: #fff;
color: #fff; color: #fff;
-webkit-appearance: none; -webkit-appearance: none;
text-align: center; text-align: center;
box-sizing: border-box; box-sizing: border-box;
outline: 0; outline: 0;
margin: 0; margin: 0;
padding: 10px 15px; padding: 10px 15px;
font-size: 14px; font-size: 14px;
border-radius: 4px; border-radius: 4px;
} }

View File

@@ -1,83 +1,82 @@
//覆盖一些element-ui样式 //覆盖一些element-ui样式
.block-checkbox { .block-checkbox {
display: block; display: block;
} }
.operation-container { .operation-container {
.cell { .cell {
padding: 10px !important; padding: 10px !important;
} }
.el-button { .el-button {
&:nth-child(3) { &:nth-child(3) {
margin-top: 10px; margin-top: 10px;
margin-left: 0px; margin-left: 0px;
} }
&:nth-child(4) { &:nth-child(4) {
margin-top: 10px; margin-top: 10px;
} }
} }
} }
.el-upload { .el-upload {
input[type="file"] { input[type="file"] {
display: none !important; display: none !important;
} }
} }
.el-upload__input { .el-upload__input {
display: none; display: none;
} }
.cell { .cell {
.el-tag { .el-tag {
margin-right: 8px; margin-right: 8px;
} }
} }
.small-padding { .small-padding {
.cell { .cell {
padding-left: 8px; padding-left: 8px;
padding-right: 8px; padding-right: 8px;
} }
} }
.status-col { .status-col {
.cell { .cell {
padding: 0 10px; padding: 0 10px;
text-align: center; text-align: center;
.el-tag { .el-tag {
margin-right: 0px; margin-right: 0px;
} }
} }
} }
//暂时性解决diolag 问题 https://github.com/ElemeFE/element/issues/2461 //暂时性解决diolag 问题 https://github.com/ElemeFE/element/issues/2461
.el-dialog { .el-dialog {
transform: none; transform: none;
left: 0; left: 0;
position: relative; position: relative;
margin: 0 auto; margin: 0 auto;
} }
//文章页textarea修改样式
.article-textarea {
textarea {
padding-right: 40px;
resize: none;
border: none;
border-radius: 0px;
border-bottom: 1px solid #bfcbd9;
}
}
//文章页textarea修改样式 //element ui upload
.article-textarea { .upload-container {
textarea { .el-upload {
padding-right: 40px; width: 100%;
resize: none; .el-upload-dragger {
border: none; width: 100%;
border-radius: 0px; height: 200px;
border-bottom: 1px solid #bfcbd9; }
} }
} }
//element ui upload
.upload-container {
.el-upload {
width: 100%;
.el-upload-dragger {
width: 100%;
height: 200px;
}
}
}

View File

@@ -1,6 +1,7 @@
@import './mixin.scss';
@import './btn.scss'; @import './btn.scss';
@import './element-ui.scss'; @import './element-ui.scss';
@import './mixin.scss'; @import './sidebar.scss';
body { body {
-moz-osx-font-smoothing: grayscale; -moz-osx-font-smoothing: grayscale;
-webkit-font-smoothing: antialiased; -webkit-font-smoothing: antialiased;
@@ -96,15 +97,16 @@ code {
opacity: 0; opacity: 0;
} }
//main-container全局样式 //main-container全局样式
.app-container { .app-container {
padding: 20px; padding: 20px;
} }
.components-container { .components-container {
margin: 30px 50px; margin: 30px 50px;
position: relative; position: relative;
} }
.pagination-container { .pagination-container {
margin-top: 30px; margin-top: 30px;
} }
@@ -113,9 +115,10 @@ code {
height: 100%!important; height: 100%!important;
} }
.text-center{ .text-center {
text-align: center text-align: center
} }
.svg-icon { .svg-icon {
width: 1em; width: 1em;
height: 1em; height: 1em;
@@ -214,7 +217,6 @@ code {
} }
} }
//refine vue-multiselect plugin //refine vue-multiselect plugin
.multiselect { .multiselect {
line-height: 16px; line-height: 16px;
@@ -225,8 +227,9 @@ code {
} }
//refine simplemde //refine simplemde
.simplemde-container{ .simplemde-container {
.editor-toolbar.fullscreen,.CodeMirror-fullscreen{ .editor-toolbar.fullscreen,
.CodeMirror-fullscreen {
z-index: 1003; z-index: 1003;
} }
} }

77
src/styles/sidebar.scss Normal file
View File

@@ -0,0 +1,77 @@
// 侧边栏
.sidebar-container>.el-menu {
width: 100%!important;
min-height: 100%;
}
.sidebar-container .svg-icon {
margin-right: 16px;
}
.hideSidebar .el-submenu>.el-submenu__title,
.hideSidebar .submenu-title-noDropdown {
padding-left: 10px!important;
}
.hideSidebar .submenu-title-noDropdown span,
.hideSidebar .el-submenu>.el-submenu__title>span {
height: 0;
width: 0;
overflow: hidden;
visibility: hidden;
display: inline-block;
}
.hideSidebar .nest-menu .el-submenu__title {
text-align: initial!important;
padding-left: 20px!important;
span {
height: auto;
width: auto;
visibility: visible;
display: inline;
}
.el-submenu__icon-arrow {
display: block!important;
}
}
.hideSidebar .menu-wrapper>.el-menu-item,
.hideSidebar .submenu-title-noDropdown,
.hideSidebar .menu-wrapper>.el-submenu .el-submenu__title {
text-align: center;
}
.hideSidebar .el-menu-item .el-submenu__icon-arrow,
.hideSidebar .el-submenu .el-submenu__title .el-submenu__icon-arrow {
display: none;
}
.hideSidebar .submenu-title-noDropdown {
position: relative;
span {
transition: opacity .3s cubic-bezier(.55, 0, .1, 1);
opacity: 0;
}
&:hover {
span {
display: block;
border-radius: 3px;
z-index: 1002;
width: 140px;
height: 56px;
visibility: visible;
position: absolute;
right: -145px;
text-align: left;
text-indent: 20px;
top: 0px;
background-color: #1f2d3d;
opacity: 1;
}
}
}
.el-submenu .el-menu-item {
min-width: 180px!important;
}

View File

@@ -2,7 +2,7 @@
* Created by jiachenpan on 17/3/8. * Created by jiachenpan on 17/3/8.
*/ */
export default function createUniqueString() { export default function createUniqueString() {
const timestamp = +new Date() + ''; const timestamp = +new Date() + ''
const randomNum = parseInt((1 + Math.random()) * 65536) + ''; const randomNum = parseInt((1 + Math.random()) * 65536) + ''
return (+(randomNum + timestamp)).toString(32); return (+(randomNum + timestamp)).toString(32)
} }

View File

@@ -1,25 +1,25 @@
import axios from 'axios'; import axios from 'axios'
import { Message } from 'element-ui'; import { Message } from 'element-ui'
import store from '../store'; import store from '@/store'
import { getToken } from 'utils/auth'; import { getToken } from '@/utils/auth'
// 创建axios实例 // 创建axios实例
const service = axios.create({ const service = axios.create({
baseURL: process.env.BASE_API, // api的base_url baseURL: process.env.BASE_API, // api的base_url
timeout: 5000 // 请求超时时间 timeout: 5000 // 请求超时时间
}); })
// request拦截器 // request拦截器
service.interceptors.request.use(config => { service.interceptors.request.use(config => {
// Do something before request is sent // Do something before request is sent
if (store.getters.token) { if (store.getters.token) {
config.headers['X-Token'] = getToken(); // 让每个请求携带token--['X-Token']为自定义key 请根据实际情况自行修改 config.headers['X-Token'] = getToken() // 让每个请求携带token--['X-Token']为自定义key 请根据实际情况自行修改
} }
return config; return config
}, error => { }, error => {
// Do something with request error // Do something with request error
console.log(error); // for debug console.log(error) // for debug
Promise.reject(error); Promise.reject(error)
}) })
// respone拦截器 // respone拦截器
@@ -48,19 +48,19 @@ service.interceptors.response.use(
// }); // });
// }) // })
// } // }
// return Promise.reject(error); // return Promise.reject('error');
// } else { // } else {
// return response.data; // return response.data;
// } // }
error => { error => {
console.log('err' + error);// for debug console.log('err' + error)// for debug
Message({ Message({
message: error.message, message: error.message,
type: 'error', type: 'error',
duration: 5 * 1000 duration: 5 * 1000
}); })
return Promise.reject(error); return Promise.reject(error)
} }
) )
export default service; export default service

View File

@@ -4,15 +4,15 @@
export function parseTime(time, cFormat) { export function parseTime(time, cFormat) {
if (arguments.length === 0) { if (arguments.length === 0) {
return null; return null
} }
const format = cFormat || '{y}-{m}-{d} {h}:{i}:{s}'; const format = cFormat || '{y}-{m}-{d} {h}:{i}:{s}'
let date; let date
if (typeof time == 'object') { if (typeof time === 'object') {
date = time; date = time
} else { } else {
if (('' + time).length === 10) time = parseInt(time) * 1000; if (('' + time).length === 10) time = parseInt(time) * 1000
date = new Date(time); date = new Date(time)
} }
const formatObj = { const formatObj = {
y: date.getFullYear(), y: date.getFullYear(),
@@ -22,24 +22,24 @@
i: date.getMinutes(), i: date.getMinutes(),
s: date.getSeconds(), s: date.getSeconds(),
a: date.getDay() a: date.getDay()
}; }
const time_str = format.replace(/{(y|m|d|h|i|s|a)+}/g, (result, key) => { const time_str = format.replace(/{(y|m|d|h|i|s|a)+}/g, (result, key) => {
let value = formatObj[key]; let value = formatObj[key]
if (key === 'a') return ['一', '二', '三', '四', '五', '六', '日'][value - 1]; if (key === 'a') return ['一', '二', '三', '四', '五', '六', '日'][value - 1]
if (result.length > 0 && value < 10) { if (result.length > 0 && value < 10) {
value = '0' + value; value = '0' + value
} }
return value || 0; return value || 0
}); })
return time_str; return time_str
} }
export function formatTime(time, option) { export function formatTime(time, option) {
time = +time * 1000; time = +time * 1000
const d = new Date(time); const d = new Date(time)
const now = Date.now(); const now = Date.now()
const diff = (now - d) / 1000; const diff = (now - d) / 1000
if (diff < 30) { if (diff < 30) {
return '刚刚' return '刚刚'
@@ -59,67 +59,66 @@
// 格式化时间 // 格式化时间
export function getQueryObject(url) { export function getQueryObject(url) {
url = url == null ? window.location.href : url; url = url == null ? window.location.href : url
const search = url.substring(url.lastIndexOf('?') + 1); const search = url.substring(url.lastIndexOf('?') + 1)
const obj = {}; const obj = {}
const reg = /([^?&=]+)=([^?&=]*)/g; const reg = /([^?&=]+)=([^?&=]*)/g
search.replace(reg, (rs, $1, $2) => { search.replace(reg, (rs, $1, $2) => {
const name = decodeURIComponent($1); const name = decodeURIComponent($1)
let val = decodeURIComponent($2); let val = decodeURIComponent($2)
val = String(val); val = String(val)
obj[name] = val; obj[name] = val
return rs; return rs
}); })
return obj; return obj
} }
/** /**
*get getByteLen *get getByteLen
* @param {Sting} val input value * @param {Sting} val input value
* @returns {number} output value * @returns {number} output value
*/ */
export function getByteLen(val) { export function getByteLen(val) {
let len = 0; let len = 0
for (let i = 0; i < val.length; i++) { for (let i = 0; i < val.length; i++) {
if (val[i].match(/[^\x00-\xff]/ig) != null) { if (val[i].match(/[^\x00-\xff]/ig) != null) {
len += 1; len += 1
} else { len += 0.5; } } else { len += 0.5 }
} }
return Math.floor(len); return Math.floor(len)
} }
export function cleanArray(actual) { export function cleanArray(actual) {
const newArray = []; const newArray = []
for (let i = 0; i < actual.length; i++) { for (let i = 0; i < actual.length; i++) {
if (actual[i]) { if (actual[i]) {
newArray.push(actual[i]); newArray.push(actual[i])
} }
} }
return newArray; return newArray
} }
export function param(json) { export function param(json) {
if (!json) return ''; if (!json) return ''
return cleanArray(Object.keys(json).map(key => { return cleanArray(Object.keys(json).map(key => {
if (json[key] === undefined) return ''; if (json[key] === undefined) return ''
return encodeURIComponent(key) + '=' + return encodeURIComponent(key) + '=' +
encodeURIComponent(json[key]); encodeURIComponent(json[key])
})).join('&'); })).join('&')
} }
export function param2Obj(url) { export function param2Obj(url) {
const search = url.split('?')[1]; const search = url.split('?')[1]
if (!search) { if (!search) {
return {} 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) { export function html2Text(val) {
const div = document.createElement('div'); const div = document.createElement('div')
div.innerHTML = val; div.innerHTML = val
return div.textContent || div.innerText; return div.textContent || div.innerText
} }
export function objectMerge(target, source) { export function objectMerge(target, source) {
@@ -127,83 +126,82 @@
giving the last one precedence */ giving the last one precedence */
if (typeof target !== 'object') { if (typeof target !== 'object') {
target = {}; target = {}
} }
if (Array.isArray(source)) { if (Array.isArray(source)) {
return source.slice(); return source.slice()
} }
for (const property in source) { for (const property in source) {
if (source.hasOwnProperty(property)) { if (source.hasOwnProperty(property)) {
const sourceProperty = source[property]; const sourceProperty = source[property]
if (typeof sourceProperty === 'object') { if (typeof sourceProperty === 'object') {
target[property] = objectMerge(target[property], sourceProperty); target[property] = objectMerge(target[property], sourceProperty)
continue; continue
} }
target[property] = sourceProperty; target[property] = sourceProperty
} }
} }
return target; return target
} }
export function scrollTo(element, to, duration) { export function scrollTo(element, to, duration) {
if (duration <= 0) return; if (duration <= 0) return
const difference = to - element.scrollTop; const difference = to - element.scrollTop
const perTick = difference / duration * 10; const perTick = difference / duration * 10
setTimeout(() => { setTimeout(() => {
console.log(new Date()) console.log(new Date())
element.scrollTop = element.scrollTop + perTick; element.scrollTop = element.scrollTop + perTick
if (element.scrollTop === to) return; if (element.scrollTop === to) return
scrollTo(element, to, duration - 10); scrollTo(element, to, duration - 10)
}, 10); }, 10)
} }
export function toggleClass(element, className) { export function toggleClass(element, className) {
if (!element || !className) { if (!element || !className) {
return; return
} }
let classString = element.className; let classString = element.className
const nameIndex = classString.indexOf(className); const nameIndex = classString.indexOf(className)
if (nameIndex === -1) { if (nameIndex === -1) {
classString += '' + className; classString += '' + className
} else { } else {
classString = classString.substr(0, nameIndex) + classString.substr(nameIndex + className.length); classString = classString.substr(0, nameIndex) + classString.substr(nameIndex + className.length)
} }
element.className = classString; element.className = classString
} }
export const pickerOptions = [ export const pickerOptions = [
{ {
text: '今天', text: '今天',
onClick(picker) { onClick(picker) {
const end = new Date(); const end = new Date()
const start = new Date(new Date().toDateString()); const start = new Date(new Date().toDateString())
end.setTime(start.getTime()); end.setTime(start.getTime())
picker.$emit('pick', [start, end]); picker.$emit('pick', [start, end])
} }
}, { }, {
text: '最近一周', text: '最近一周',
onClick(picker) { onClick(picker) {
const end = new Date(new Date().toDateString()); const end = new Date(new Date().toDateString())
const start = new Date(); const start = new Date()
start.setTime(end.getTime() - 3600 * 1000 * 24 * 7); start.setTime(end.getTime() - 3600 * 1000 * 24 * 7)
picker.$emit('pick', [start, end]); picker.$emit('pick', [start, end])
} }
}, { }, {
text: '最近一个月', text: '最近一个月',
onClick(picker) { onClick(picker) {
const end = new Date(new Date().toDateString()); const end = new Date(new Date().toDateString())
const start = new Date(); const start = new Date()
start.setTime(start.getTime() - 3600 * 1000 * 24 * 30); start.setTime(start.getTime() - 3600 * 1000 * 24 * 30)
picker.$emit('pick', [start, end]); picker.$emit('pick', [start, end])
} }
}, { }, {
text: '最近三个月', text: '最近三个月',
onClick(picker) { onClick(picker) {
const end = new Date(new Date().toDateString()); const end = new Date(new Date().toDateString())
const start = new Date(); const start = new Date()
start.setTime(start.getTime() - 3600 * 1000 * 24 * 90); start.setTime(start.getTime() - 3600 * 1000 * 24 * 90)
picker.$emit('pick', [start, end]); picker.$emit('pick', [start, end])
} }
}] }]
@@ -216,55 +214,54 @@
} }
export function debounce(func, wait, immediate) { export function debounce(func, wait, immediate) {
let timeout, args, context, timestamp, result; let timeout, args, context, timestamp, result
const later = function() { const later = function() {
// 据上一次触发时间间隔 // 据上一次触发时间间隔
const last = +new Date() - timestamp; const last = +new Date() - timestamp
// 上次被包装函数被调用时间间隔last小于设定时间间隔wait // 上次被包装函数被调用时间间隔last小于设定时间间隔wait
if (last < wait && last > 0) { if (last < wait && last > 0) {
timeout = setTimeout(later, wait - last); timeout = setTimeout(later, wait - last)
} else { } else {
timeout = null; timeout = null
// 如果设定为immediate===true因为开始边界已经调用过了此处无需调用 // 如果设定为immediate===true因为开始边界已经调用过了此处无需调用
if (!immediate) { if (!immediate) {
result = func.apply(context, args); result = func.apply(context, args)
if (!timeout) context = args = null; if (!timeout) context = args = null
} }
} }
}; }
return function(...args) { return function(...args) {
context = this; context = this
timestamp = +new Date(); timestamp = +new Date()
const callNow = immediate && !timeout; const callNow = immediate && !timeout
// 如果延时不存在,重新设定延时 // 如果延时不存在,重新设定延时
if (!timeout) timeout = setTimeout(later, wait); if (!timeout) timeout = setTimeout(later, wait)
if (callNow) { if (callNow) {
result = func.apply(context, args); result = func.apply(context, args)
context = args = null; context = args = null
} }
return result; return result
}; }
} }
export function deepClone(source) { export function deepClone(source) {
if (!source && typeof source !== 'object') { if (!source && typeof source !== 'object') {
throw new Error('error arguments', 'shallowClone'); throw new Error('error arguments', 'shallowClone')
} }
const targetObj = source.constructor === Array ? [] : {}; const targetObj = source.constructor === Array ? [] : {}
for (const keys in source) { for (const keys in source) {
if (source.hasOwnProperty(keys)) { if (source.hasOwnProperty(keys)) {
if (source[keys] && typeof source[keys] === 'object') { if (source[keys] && typeof source[keys] === 'object') {
targetObj[keys] = source[keys].constructor === Array ? [] : {}; targetObj[keys] = source[keys].constructor === Array ? [] : {}
targetObj[keys] = deepClone(source[keys]); targetObj[keys] = deepClone(source[keys])
} else { } else {
targetObj[keys] = source[keys]; targetObj[keys] = source[keys]
} }
} }
} }
return targetObj; return targetObj
} }

View File

@@ -8,20 +8,19 @@
export default function openWindow(url, title, w, h) { export default function openWindow(url, title, w, h) {
// Fixes dual-screen position Most browsers Firefox // Fixes dual-screen position Most browsers Firefox
const dualScreenLeft = window.screenLeft !== undefined ? window.screenLeft : screen.left; const dualScreenLeft = window.screenLeft !== undefined ? window.screenLeft : screen.left
const dualScreenTop = window.screenTop !== undefined ? window.screenTop : screen.top; const dualScreenTop = window.screenTop !== undefined ? window.screenTop : screen.top
const width = window.innerWidth ? window.innerWidth : document.documentElement.clientWidth ? document.documentElement.clientWidth : screen.width; const width = window.innerWidth ? window.innerWidth : document.documentElement.clientWidth ? document.documentElement.clientWidth : screen.width
const height = window.innerHeight ? window.innerHeight : document.documentElement.clientHeight ? document.documentElement.clientHeight : screen.height; const height = window.innerHeight ? window.innerHeight : document.documentElement.clientHeight ? document.documentElement.clientHeight : screen.height
const left = ((width / 2) - (w / 2)) + dualScreenLeft; const left = ((width / 2) - (w / 2)) + dualScreenLeft
const top = ((height / 2) - (h / 2)) + dualScreenTop; const top = ((height / 2) - (h / 2)) + dualScreenTop
const newWindow = window.open(url, title, 'toolbar=no, location=no, directories=no, status=no, menubar=no, scrollbars=no, resizable=yes, copyhistory=no, width=' + w + ', height=' + h + ', top=' + top + ', left=' + left); const newWindow = window.open(url, title, 'toolbar=no, location=no, directories=no, status=no, menubar=no, scrollbars=no, resizable=yes, copyhistory=no, width=' + w + ', height=' + h + ', top=' + top + ', left=' + left)
// Puts focus on the newWindow // Puts focus on the newWindow
if (window.focus) { if (window.focus) {
newWindow.focus(); newWindow.focus()
} }
} }

View File

@@ -2,40 +2,32 @@
* Created by jiachenpan on 16/11/18. * Created by jiachenpan on 16/11/18.
*/ */
/* 是否是公司邮箱*/ export function isvalidUsername(str) {
export function isWscnEmail(str) { const valid_map = ['admin', 'editor']
const reg = /^[a-z0-9](?:[-_.+]?[a-z0-9]+)*@wallstreetcn\.com$/i; return valid_map.indexOf(str.trim()) >= 0
return reg.test(str.trim());
} }
/* 合法uri*/ /* 合法uri*/
export function validateURL(textval) { export function validateURL(textval) {
const urlregex = /^(https?|ftp):\/\/([a-zA-Z0-9.-]+(:[a-zA-Z0-9.&%$-]+)*@)*((25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]?)(\.(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3}|([a-zA-Z0-9-]+\.)*[a-zA-Z0-9-]+\.(com|edu|gov|int|mil|net|org|biz|arpa|info|name|pro|aero|coop|museum|[a-zA-Z]{2}))(:[0-9]+)*(\/($|[a-zA-Z0-9.,?'\\+&%$#=~_-]+))*$/; const urlregex = /^(https?|ftp):\/\/([a-zA-Z0-9.-]+(:[a-zA-Z0-9.&%$-]+)*@)*((25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]?)(\.(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3}|([a-zA-Z0-9-]+\.)*[a-zA-Z0-9-]+\.(com|edu|gov|int|mil|net|org|biz|arpa|info|name|pro|aero|coop|museum|[a-zA-Z]{2}))(:[0-9]+)*(\/($|[a-zA-Z0-9.,?'\\+&%$#=~_-]+))*$/
return urlregex.test(textval); return urlregex.test(textval)
} }
/* 小写字母*/ /* 小写字母*/
export function validateLowerCase(str) { export function validateLowerCase(str) {
const reg = /^[a-z]+$/; const reg = /^[a-z]+$/
return reg.test(str); return reg.test(str)
} }
/* 验证key*/
// export function validateKey(str) {
// var reg = /^[a-z_\-:]+$/;
// return reg.test(str);
// }
/* 大写字母*/ /* 大写字母*/
export function validateUpperCase(str) { export function validateUpperCase(str) {
const reg = /^[A-Z]+$/; const reg = /^[A-Z]+$/
return reg.test(str); return reg.test(str)
} }
/* 大小写字母*/ /* 大小写字母*/
export function validatAlphabets(str) { export function validatAlphabets(str) {
const reg = /^[A-Za-z]+$/; const reg = /^[A-Za-z]+$/
return reg.test(str); return reg.test(str)
} }

View File

@@ -1,7 +1,7 @@
<template> <template>
<div class="components-container" > <div class="components-container" >
<code> <code>
这里的所有的图表都基于ECharts,实例代码来源<a href='http://gallery.echartsjs.com/explore.html#sort=rank~timeframe=all~author=all' target='_blank'>gallery</a><br/>其实ECharts封装的很好了用vue封装是很简单的事情建议大家自己来封装<a target='_blank' class='lin' href="https://segmentfault.com/a/1190000009762198#articleHeader16">相关教程</a> 这里的所有的图表都基于ECharts,实例代码来源<a href='http://gallery.echartsjs.com/explore.html#sort=rank~timeframe=all~author=all' target='_blank'> gallery</a><br/>其实ECharts封装的很好了用vue封装是很简单的事情建议大家自己来封装<a target='_blank' class='lin' href="https://segmentfault.com/a/1190000009762198#articleHeader16">相关教程</a>
</code> </code>
</div> </div>
</template> </template>

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