|
@ -8,3 +8,4 @@ test/unit/coverage
|
||||||
test/e2e/reports
|
test/e2e/reports
|
||||||
selenium-debug.log
|
selenium-debug.log
|
||||||
.idea
|
.idea
|
||||||
|
package-lock.json
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
"plugins": {
|
"plugins": {
|
||||||
// to edit target browsers: use "browserlist" field in package.json
|
// to edit target browsers: use "browserslist" field in package.json
|
||||||
"autoprefixer": {}
|
"autoprefixer": {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,8 +32,9 @@
|
||||||
- ECharts
|
- ECharts
|
||||||
- 401, 404 error page
|
- 401, 404 error page
|
||||||
- Error log
|
- Error log
|
||||||
- Exporting to Excel
|
- Export Excel
|
||||||
- Upload Excel
|
- Upload Excel
|
||||||
|
- Export Zip
|
||||||
- Table example
|
- Table example
|
||||||
- Interactive table example
|
- Interactive table example
|
||||||
- Drag & drop table example
|
- Drag & drop table example
|
||||||
|
@ -47,6 +48,7 @@
|
||||||
- screenfull
|
- screenfull
|
||||||
- markdown2html
|
- markdown2html
|
||||||
- views-tab
|
- views-tab
|
||||||
|
- clipboard
|
||||||
|
|
||||||
## Development
|
## Development
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,8 @@
|
||||||
|
|
||||||
**注意:该项目目前使用element-ui@1.4.2版本,所以最低兼容 Vue 2.3.0**
|
**注意:该项目目前使用element-ui@1.4.2版本,所以最低兼容 Vue 2.3.0**
|
||||||
|
|
||||||
|
楼主这里有一份调查[问卷](https://www.wjx.cn/m/16866569.aspx) 有空请填写一下,以表对本项目的支持~ps:不是给这个调查问卷网站做广告,所以填完问卷不用点上面抽奖有的没的那些东西
|
||||||
|
|
||||||
## 前言
|
## 前言
|
||||||
> 这半年来一直在用vue写管理后台,目前后台已经有百来个页面,十几种权限,但维护成本依然很低,所以准备开源分享一下后台开发的经验和成果。目前的技术栈主要的采用vue+element+axios由webpack2打包。由于是个人项目,所以数据请求都是用了mockjs模拟。注意:在此项目基础上改造开发时请移除mock文件。
|
> 这半年来一直在用vue写管理后台,目前后台已经有百来个页面,十几种权限,但维护成本依然很低,所以准备开源分享一下后台开发的经验和成果。目前的技术栈主要的采用vue+element+axios由webpack2打包。由于是个人项目,所以数据请求都是用了mockjs模拟。注意:在此项目基础上改造开发时请移除mock文件。
|
||||||
|
|
||||||
|
@ -63,6 +65,7 @@
|
||||||
- 401,404错误页面
|
- 401,404错误页面
|
||||||
- 错误日志
|
- 错误日志
|
||||||
- 导出excel
|
- 导出excel
|
||||||
|
- zip
|
||||||
- 前端可视化excel
|
- 前端可视化excel
|
||||||
- table example
|
- table example
|
||||||
- 动态table example
|
- 动态table example
|
||||||
|
@ -78,6 +81,7 @@
|
||||||
- screenfull
|
- screenfull
|
||||||
- markdown2html
|
- markdown2html
|
||||||
- views-tab
|
- views-tab
|
||||||
|
- clipboard
|
||||||
|
|
||||||
|
|
||||||
## 开发
|
## 开发
|
||||||
|
|
|
@ -9,9 +9,7 @@ var webpack = require('webpack');
|
||||||
var config = require('../config');
|
var config = require('../config');
|
||||||
var webpackConfig = require('./webpack.prod.conf');
|
var webpackConfig = require('./webpack.prod.conf');
|
||||||
|
|
||||||
console.log(process.env.NODE_ENV)
|
var spinner = ora('building for ' + process.env.NODE_ENV + ' of ' + process.env.env_config+ ' mode...' )
|
||||||
|
|
||||||
var spinner = ora('building for ' + process.env.NODE_ENV + '...')
|
|
||||||
spinner.start()
|
spinner.start()
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
require('./check-versions')(); // 检查 Node 和 npm 版本
|
require('./check-versions')(); // 检查 Node 和 npm 版本
|
||||||
|
|
||||||
var config = require('../config');
|
var config = require('../config');
|
||||||
if (!process.env.NODE_ENV) {
|
if (!process.env.NODE_ENV) {
|
||||||
process.env.NODE_ENV = JSON.parse(config.dev.env.NODE_ENV)
|
process.env.NODE_ENV = JSON.parse(config.dev.env.NODE_ENV)
|
||||||
|
@ -28,8 +29,8 @@ var devMiddleware = require('webpack-dev-middleware')(compiler, {
|
||||||
});
|
});
|
||||||
|
|
||||||
var hotMiddleware = require('webpack-hot-middleware')(compiler, {
|
var hotMiddleware = require('webpack-hot-middleware')(compiler, {
|
||||||
log: () => {
|
log: false,
|
||||||
}
|
heartbeat: 2000
|
||||||
});
|
});
|
||||||
|
|
||||||
// force page reload when html-webpack-plugin template changes
|
// force page reload when html-webpack-plugin template changes
|
||||||
|
@ -40,8 +41,6 @@ compiler.plugin('compilation', function (compilation) {
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
// compiler.apply(new DashboardPlugin());
|
|
||||||
|
|
||||||
// proxy api requests
|
// proxy api requests
|
||||||
Object.keys(proxyTable).forEach(function (context) {
|
Object.keys(proxyTable).forEach(function (context) {
|
||||||
var options = proxyTable[context]
|
var options = proxyTable[context]
|
||||||
|
@ -67,18 +66,26 @@ app.use(staticPath, express.static('./static'));
|
||||||
|
|
||||||
var uri = 'http://localhost:' + port
|
var uri = 'http://localhost:' + port
|
||||||
|
|
||||||
devMiddleware.waitUntilValid(function () {
|
var _resolve
|
||||||
|
var readyPromise = new Promise(resolve => {
|
||||||
|
_resolve = resolve
|
||||||
|
})
|
||||||
|
|
||||||
|
console.log('> Starting dev server...')
|
||||||
|
devMiddleware.waitUntilValid(() => {
|
||||||
console.log('> Listening at ' + uri + '\n')
|
console.log('> Listening at ' + uri + '\n')
|
||||||
});
|
|
||||||
|
|
||||||
module.exports = app.listen(port, function (err) {
|
|
||||||
if (err) {
|
|
||||||
console.log(err);
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// when env is testing, don't need open it
|
// when env is testing, don't need open it
|
||||||
if (autoOpenBrowser && process.env.NODE_ENV !== 'testing') {
|
if (autoOpenBrowser && process.env.NODE_ENV !== 'testing') {
|
||||||
opn(uri)
|
opn(uri)
|
||||||
}
|
}
|
||||||
});
|
_resolve()
|
||||||
|
})
|
||||||
|
|
||||||
|
var server = app.listen(port)
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
ready: readyPromise,
|
||||||
|
close: () => {
|
||||||
|
server.close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -14,7 +14,7 @@ module.exports = {
|
||||||
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 === 'production' ? config.build.assetsPublicPath : config.dev.assetsPublicPath
|
||||||
},
|
},
|
||||||
resolve: {
|
resolve: {
|
||||||
extensions: ['.js', '.vue', '.json'],
|
extensions: ['.js', '.vue', '.json'],
|
||||||
|
|
|
@ -9,7 +9,7 @@ var HtmlWebpackPlugin = require('html-webpack-plugin')
|
||||||
var ExtractTextPlugin = require('extract-text-webpack-plugin')
|
var ExtractTextPlugin = require('extract-text-webpack-plugin')
|
||||||
var OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin')
|
var OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin')
|
||||||
|
|
||||||
var env = process.env.NODE_ENV === 'production' ? config.build.prodEnv : config.build.sitEnv
|
var env = config.build[process.env.env_config+'Env']
|
||||||
|
|
||||||
function resolveApp(relativePath) {
|
function resolveApp(relativePath) {
|
||||||
return path.resolve(relativePath);
|
return path.resolve(relativePath);
|
||||||
|
@ -95,6 +95,14 @@ var webpackConfig = merge(baseWebpackConfig, {
|
||||||
return context && (context.indexOf('echarts') >= 0 || context.indexOf('zrender') >= 0);
|
return context && (context.indexOf('echarts') >= 0 || context.indexOf('zrender') >= 0);
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
|
// split xlsx into its own file
|
||||||
|
new webpack.optimize.CommonsChunkPlugin({
|
||||||
|
async: 'xlsx',
|
||||||
|
minChunks(module) {
|
||||||
|
var context = module.context;
|
||||||
|
return context && (context.indexOf('xlsx') >= 0);
|
||||||
|
}
|
||||||
|
}),
|
||||||
// extract webpack runtime and module manifest to its own file in order to
|
// extract webpack runtime and module manifest to its own file in order to
|
||||||
// prevent vendor hash from being updated whenever app bundle is updated
|
// prevent vendor hash from being updated whenever app bundle is updated
|
||||||
new webpack.optimize.CommonsChunkPlugin({
|
new webpack.optimize.CommonsChunkPlugin({
|
||||||
|
@ -109,9 +117,11 @@ var webpackConfig = merge(baseWebpackConfig, {
|
||||||
}])
|
}])
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
|
|
||||||
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
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
module.exports = {
|
module.exports = {
|
||||||
NODE_ENV: '"development"',
|
NODE_ENV: '"development"',
|
||||||
|
ENV_CONFIG: '"dev"',
|
||||||
BASE_API: '"https://api-dev"',
|
BASE_API: '"https://api-dev"',
|
||||||
APP_ORIGIN: '"https://wallstreetcn.com"'
|
APP_ORIGIN: '"https://wallstreetcn.com"'
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
module.exports = {
|
module.exports = {
|
||||||
NODE_ENV: '"production"',
|
NODE_ENV: '"production"',
|
||||||
|
ENV_CONFIG: '"prod"',
|
||||||
BASE_API: '"https://api-prod"',
|
BASE_API: '"https://api-prod"',
|
||||||
APP_ORIGIN: '"https://wallstreetcn.com"'
|
APP_ORIGIN: '"https://wallstreetcn.com"'
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
module.exports = {
|
module.exports = {
|
||||||
NODE_ENV: '"production"',
|
NODE_ENV: '"production"',
|
||||||
|
ENV_CONFIG: '"sit"',
|
||||||
BASE_API: '"https://api-sit"',
|
BASE_API: '"https://api-sit"',
|
||||||
APP_ORIGIN: '"https://wallstreetcn.com"'
|
APP_ORIGIN: '"https://wallstreetcn.com"'
|
||||||
};
|
};
|
||||||
|
|
16
package.json
|
@ -1,22 +1,23 @@
|
||||||
{
|
{
|
||||||
"name": "juicy",
|
"name": "juicy",
|
||||||
"version": "2.1.0",
|
"version": "2.2.1",
|
||||||
"description": "A Vue.js admin",
|
"description": "A Vue.js admin",
|
||||||
"author": "Pan <panfree23@gmail.com>",
|
"author": "Pan <panfree23@gmail.com>",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "node build/dev-server.js",
|
"dev": "node build/dev-server.js",
|
||||||
"build:prod": "cross-env NODE_ENV=production node build/build.js",
|
"build:prod": "cross-env NODE_ENV=production env_config=prod node build/build.js",
|
||||||
"build:sit": "cross-env NODE_ENV=sit node build/build.js",
|
"build:sit": "cross-env NODE_ENV=production env_config=sit node build/build.js",
|
||||||
"build:sit-preview": "cross-env NODE_ENV=sit npm_config_preview=true npm_config_report=true node build/build.js",
|
"build:sit-preview": "cross-env NODE_ENV=production env_config=sit npm_config_preview=true npm_config_report=true node build/build.js",
|
||||||
"lint": "eslint --ext .js,.vue src"
|
"lint": "eslint --ext .js,.vue src"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"axios": "0.16.2",
|
"axios": "0.16.2",
|
||||||
|
"clipboard": "1.7.1",
|
||||||
"codemirror": "5.26.0",
|
"codemirror": "5.26.0",
|
||||||
"dropzone": "5.1.0",
|
"dropzone": "5.1.0",
|
||||||
"echarts": "3.6.2",
|
"echarts": "3.8.2",
|
||||||
"element-ui": "1.4.2",
|
"element-ui": "1.4.2",
|
||||||
"file-saver": "1.3.3",
|
"file-saver": "1.3.3",
|
||||||
"js-cookie": "2.1.4",
|
"js-cookie": "2.1.4",
|
||||||
|
@ -35,7 +36,8 @@
|
||||||
"vue-splitpane": "^1.0.0",
|
"vue-splitpane": "^1.0.0",
|
||||||
"vuedraggable": "2.14.1",
|
"vuedraggable": "2.14.1",
|
||||||
"vuex": "2.3.1",
|
"vuex": "2.3.1",
|
||||||
"xlsx": "^0.10.8"
|
"xlsx": "^0.10.8",
|
||||||
|
"jszip": "^3.1.4"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"autoprefixer": "7.1.1",
|
"autoprefixer": "7.1.1",
|
||||||
|
@ -90,7 +92,7 @@
|
||||||
"node": ">= 4.0.0",
|
"node": ">= 4.0.0",
|
||||||
"npm": ">= 3.0.0"
|
"npm": ">= 3.0.0"
|
||||||
},
|
},
|
||||||
"browserlist": [
|
"browserslist": [
|
||||||
"> 1%",
|
"> 1%",
|
||||||
"last 2 versions",
|
"last 2 versions",
|
||||||
"not ie <= 8"
|
"not ie <= 8"
|
||||||
|
|
|
@ -1,144 +1,110 @@
|
||||||
<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"
|
<div :class="{iconClass:icon}">
|
||||||
:readonly="readonly" :disabled="disabled" :autocomplete="autocomplete" :required="required" @focus="handleFocus(true)"
|
<i class="el-input__icon material-input__icon" :class="['el-icon-' + icon]" v-if="icon"></i>
|
||||||
@blur="handleFocus(false)" @input="handleModelInput">
|
<input v-if="type === 'email'" type="email" class="material-input" :name="name" :placeholder="fillPlaceHolder" v-model="currentValue"
|
||||||
<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="handleMdFocus"
|
||||||
:readonly="readonly" :disabled="disabled" :autocomplete="autocomplete" :required="required" @focus="handleFocus(true)"
|
@blur="handleMdBlur" @input="handleModelInput">
|
||||||
@blur="handleFocus(false)" @input="handleModelInput">
|
<input v-if="type === 'url'" type="url" class="material-input" :name="name" :placeholder="fillPlaceHolder" v-model="currentValue"
|
||||||
<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" :required="required" @focus="handleMdFocus"
|
||||||
:readonly="readonly" :disabled="disabled" :autocomplete="autocomplete" :max="max" :min="min" :minlength="minlength" :maxlength="maxlength"
|
@blur="handleMdBlur" @input="handleModelInput">
|
||||||
:required="required" @focus="handleFocus(true)" @blur="handleFocus(false)" @input="handleModelInput">
|
<input v-if="type === 'number'" type="number" class="material-input" :name="name" :placeholder="fillPlaceHolder" v-model="currentValue"
|
||||||
<input v-if="type === 'password'" type="password" class="material-input" :name="name" :id="id" :placeholder="placeholder"
|
:step="step" :readonly="readonly" :disabled="disabled" :autoComplete="autoComplete" :max="max" :min="min" :minlength="minlength"
|
||||||
v-model="valueCopy" :readonly="readonly" :disabled="disabled" :autocomplete="autocomplete" :max="max" :min="min" :required="required"
|
:maxlength="maxlength" :required="required" @focus="handleMdFocus" @blur="handleMdBlur" @input="handleModelInput">
|
||||||
@focus="handleFocus(true)" @blur="handleFocus(false)" @input="handleModelInput">
|
<input v-if="type === 'password'" type="password" class="material-input" :name="name" :placeholder="fillPlaceHolder" v-model="currentValue"
|
||||||
<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" :max="max" :min="min" :required="required" @focus="handleMdFocus"
|
||||||
:readonly="readonly" :disabled="disabled" :autocomplete="autocomplete" :required="required" @focus="handleFocus(true)"
|
@blur="handleMdBlur" @input="handleModelInput">
|
||||||
@blur="handleFocus(false)" @input="handleModelInput">
|
<input v-if="type === 'tel'" type="tel" class="material-input" :name="name" :placeholder="fillPlaceHolder" v-model="currentValue"
|
||||||
<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" :required="required" @focus="handleMdFocus"
|
||||||
:readonly="readonly" :disabled="disabled" :autocomplete="autocomplete" :minlength="minlength" :maxlength="maxlength"
|
@blur="handleMdBlur" @input="handleModelInput">
|
||||||
:required="required" @focus="handleFocus(true)" @blur="handleFocus(false)" @input="handleModelInput">
|
<input v-if="type === 'text'" type="text" class="material-input" :name="name" :placeholder="fillPlaceHolder" v-model="currentValue"
|
||||||
|
:readonly="readonly" :disabled="disabled" :autoComplete="autoComplete" :minlength="minlength" :maxlength="maxlength"
|
||||||
|
:required="required" @focus="handleMdFocus" @blur="handleMdBlur" @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-for="error in computedErrors" class="material-error" :key='error'>
|
|
||||||
{{ error }}
|
|
||||||
</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: 'md-input',
|
||||||
computed: {
|
props: {
|
||||||
computedErrors() {
|
icon: String,
|
||||||
return typeof this.errorMessages === 'string'
|
name: String,
|
||||||
? [this.errorMessages] : this.errorMessages
|
type: {
|
||||||
|
type: String,
|
||||||
|
default: 'text'
|
||||||
},
|
},
|
||||||
|
value: [String, Number],
|
||||||
|
placeholder: String,
|
||||||
|
readonly: Boolean,
|
||||||
|
disabled: Boolean,
|
||||||
|
min: String,
|
||||||
|
max: String,
|
||||||
|
step: String,
|
||||||
|
minlength: Number,
|
||||||
|
maxlength: Number,
|
||||||
|
required: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
autoComplete: {
|
||||||
|
type: String,
|
||||||
|
default: 'off'
|
||||||
|
},
|
||||||
|
validateEvent: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
computedClasses() {
|
computedClasses() {
|
||||||
return {
|
return {
|
||||||
'material--active': this.focus,
|
'material--active': this.focus,
|
||||||
'material--disabled': this.disabled,
|
'material--disabled': this.disabled,
|
||||||
'material--has-errors': Boolean(!this.valid || (this.errorMessages && this.errorMessages.length)),
|
'material--raised': Boolean(this.focus || this.currentValue) // has value
|
||||||
'material--raised': Boolean(this.focus || this.valueCopy || // has value
|
|
||||||
(this.placeholder && !this.valueCopy)) // has placeholder
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
valueCopy: null,
|
currentValue: this.value,
|
||||||
focus: false,
|
focus: false,
|
||||||
valid: true
|
fillPlaceHolder: null
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
beforeMount() {
|
|
||||||
// Here we are following the Vue2 convention on custom v-model:
|
|
||||||
// https://github.com/vuejs/vue/issues/2873#issuecomment-223759341
|
|
||||||
this.copyValue(this.value)
|
|
||||||
},
|
|
||||||
methods: {
|
methods: {
|
||||||
handleModelInput(event) {
|
handleModelInput(event) {
|
||||||
this.$emit('input', event.target.value, event)
|
const value = event.target.value
|
||||||
this.handleValidation()
|
this.$emit('input', value)
|
||||||
|
if (this.$parent.$options.componentName === 'ElFormItem') {
|
||||||
|
if (this.validateEvent) {
|
||||||
|
this.$parent.$emit('el.form.change', [value])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.$emit('change', value)
|
||||||
},
|
},
|
||||||
handleFocus(focused) {
|
handleMdFocus(event) {
|
||||||
this.focus = focused
|
this.focus = true
|
||||||
},
|
this.$emit('focus', event)
|
||||||
handleValidation() {
|
if (this.placeholder && this.placeholder !== '') {
|
||||||
this.valid = this.$el ? this.$el.querySelector('.material-input').validity.valid : this.valid
|
this.fillPlaceHolder = this.placeholder
|
||||||
},
|
|
||||||
copyValue(value) {
|
|
||||||
this.valueCopy = value
|
|
||||||
this.handleValidation()
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
watch: {
|
handleMdBlur(event) {
|
||||||
value(newValue) {
|
this.focus = false
|
||||||
this.copyValue(newValue)
|
this.$emit('blur', event)
|
||||||
|
this.fillPlaceHolder = null
|
||||||
|
if (this.$parent.$options.componentName === 'ElFormItem') {
|
||||||
|
if (this.validateEvent) {
|
||||||
|
this.$parent.$emit('el.form.blur', [this.currentValue])
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
|
||||||
props: {
|
|
||||||
id: {
|
|
||||||
type: String,
|
|
||||||
default: null
|
|
||||||
},
|
|
||||||
name: {
|
|
||||||
type: String,
|
|
||||||
default: null
|
|
||||||
},
|
|
||||||
type: {
|
|
||||||
type: String,
|
|
||||||
default: 'text'
|
|
||||||
},
|
|
||||||
value: {
|
|
||||||
default: null
|
|
||||||
},
|
|
||||||
placeholder: {
|
|
||||||
type: String,
|
|
||||||
default: null
|
|
||||||
},
|
|
||||||
readonly: {
|
|
||||||
type: Boolean,
|
|
||||||
default: false
|
|
||||||
},
|
|
||||||
disabled: {
|
|
||||||
type: Boolean,
|
|
||||||
default: false
|
|
||||||
},
|
|
||||||
min: {
|
|
||||||
type: String,
|
|
||||||
default: null
|
|
||||||
},
|
|
||||||
max: {
|
|
||||||
type: String,
|
|
||||||
default: null
|
|
||||||
},
|
|
||||||
minlength: {
|
|
||||||
type: Number,
|
|
||||||
default: null
|
|
||||||
},
|
|
||||||
maxlength: {
|
|
||||||
type: Number,
|
|
||||||
default: null
|
|
||||||
},
|
|
||||||
required: {
|
|
||||||
type: Boolean,
|
|
||||||
default: true
|
|
||||||
},
|
|
||||||
autocomplete: {
|
|
||||||
type: String,
|
|
||||||
default: 'off'
|
|
||||||
},
|
|
||||||
errorMessages: {
|
|
||||||
type: [Array, String],
|
|
||||||
default: null
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -150,9 +116,20 @@ export default {
|
||||||
$font-size-small: 18px;
|
$font-size-small: 18px;
|
||||||
$font-size-smallest: 12px;
|
$font-size-smallest: 12px;
|
||||||
$font-weight-normal: normal;
|
$font-weight-normal: normal;
|
||||||
|
$font-weight-bold: bold;
|
||||||
|
$apixel: 1px;
|
||||||
// Utils
|
// Utils
|
||||||
$spacer: 12px;
|
$spacer: 12px;
|
||||||
$transition: 0.2s ease all;
|
$transition: 0.2s ease all;
|
||||||
|
$index: 0px;
|
||||||
|
$index-has-icon: 30px;
|
||||||
|
// Theme:
|
||||||
|
$color-white: white;
|
||||||
|
$color-grey: #9E9E9E;
|
||||||
|
$color-grey-light: #E0E0E0;
|
||||||
|
$color-blue: #2196F3;
|
||||||
|
$color-red: #F44336;
|
||||||
|
$color-black: black;
|
||||||
// Base clases:
|
// Base clases:
|
||||||
%base-bar-pseudo {
|
%base-bar-pseudo {
|
||||||
content: '';
|
content: '';
|
||||||
|
@ -165,23 +142,45 @@ export default {
|
||||||
|
|
||||||
// Mixins:
|
// Mixins:
|
||||||
@mixin slided-top() {
|
@mixin slided-top() {
|
||||||
top: -2 * $spacer;
|
top: - ($font-size-base + $spacer);
|
||||||
font-size: $font-size-small;
|
left: 0;
|
||||||
|
font-size: $font-size-base;
|
||||||
|
font-weight: $font-weight-bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Component:
|
// Component:
|
||||||
.material-input__component {
|
.material-input__component {
|
||||||
/*margin-top: 30px;*/
|
margin-top: 36px;
|
||||||
position: relative;
|
position: relative;
|
||||||
* {
|
* {
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
|
.iconClass {
|
||||||
|
.material-input__icon {
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
color: $color-blue;
|
||||||
|
top: $spacer;
|
||||||
|
width: $index-has-icon;
|
||||||
|
height: $font-size-base;
|
||||||
|
font-size: $font-size-base;
|
||||||
|
font-weight: $font-weight-normal;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
.material-label {
|
||||||
|
left: $index-has-icon;
|
||||||
|
}
|
||||||
|
.material-input {
|
||||||
|
text-indent: $index-has-icon;
|
||||||
|
}
|
||||||
|
}
|
||||||
.material-input {
|
.material-input {
|
||||||
font-size: $font-size-base;
|
font-size: $font-size-base;
|
||||||
padding: $spacer $spacer $spacer $spacer / 2;
|
padding: $spacer $spacer $spacer - $apixel * 10 $spacer / 2;
|
||||||
display: block;
|
display: block;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
border: none;
|
border: none;
|
||||||
|
line-height: 1;
|
||||||
border-radius: 0;
|
border-radius: 0;
|
||||||
&:focus {
|
&:focus {
|
||||||
outline: none;
|
outline: none;
|
||||||
|
@ -190,13 +189,13 @@ export default {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.material-label {
|
.material-label {
|
||||||
font-size: $font-size-base;
|
|
||||||
font-weight: $font-weight-normal;
|
font-weight: $font-weight-normal;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
left: 0;
|
left: $index;
|
||||||
top: $spacer;
|
top: 0;
|
||||||
transition: $transition;
|
transition: $transition;
|
||||||
|
font-size: $font-size-small;
|
||||||
}
|
}
|
||||||
.material-input-bar {
|
.material-input-bar {
|
||||||
position: relative;
|
position: relative;
|
||||||
|
@ -232,35 +231,14 @@ export default {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Errors:
|
|
||||||
.material-errors {
|
|
||||||
position: relative;
|
|
||||||
overflow: hidden;
|
|
||||||
.material-error {
|
|
||||||
font-size: $font-size-smallest;
|
|
||||||
line-height: $font-size-smallest + 2px;
|
|
||||||
overflow: hidden;
|
|
||||||
margin-top: 0;
|
|
||||||
padding-top: $spacer / 2;
|
|
||||||
padding-right: $spacer / 2;
|
|
||||||
padding-left: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Theme:
|
|
||||||
$color-white: white;
|
|
||||||
$color-grey: #9E9E9E;
|
|
||||||
$color-grey-light: #E0E0E0;
|
|
||||||
$color-blue: #2196F3;
|
|
||||||
$color-red: #F44336;
|
|
||||||
$color-black: black;
|
|
||||||
.material-input__component {
|
.material-input__component {
|
||||||
background: $color-white;
|
background: $color-white;
|
||||||
.material-input {
|
.material-input {
|
||||||
background: none;
|
background: none;
|
||||||
color: $color-black;
|
color: $color-black;
|
||||||
text-indent: 30px;
|
text-indent: $index;
|
||||||
border-bottom: 1px solid $color-grey-light;
|
border-bottom: 1px solid $color-grey-light;
|
||||||
}
|
}
|
||||||
.material-label {
|
.material-label {
|
||||||
|
@ -286,12 +264,9 @@ export default {
|
||||||
.material-input-bar {
|
.material-input-bar {
|
||||||
&:before,
|
&:before,
|
||||||
&:after {
|
&:after {
|
||||||
background: $color-red;
|
background: transparent;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.material-errors {
|
|
||||||
color: $color-red;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -150,6 +150,12 @@ export default {
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
setContent(value) {
|
||||||
|
window.tinymce.get(this.tinymceId).setContent(value)
|
||||||
|
},
|
||||||
|
getContent() {
|
||||||
|
window.tinymce.get(this.tinymceId).getContent()
|
||||||
|
},
|
||||||
imageSuccessCBK(arr) {
|
imageSuccessCBK(arr) {
|
||||||
const _this = this
|
const _this = this
|
||||||
arr.forEach(v => {
|
arr.forEach(v => {
|
||||||
|
|
|
@ -0,0 +1,49 @@
|
||||||
|
// Inspired by https://github.com/Inndy/vue-clipboard2
|
||||||
|
const Clipboard = require('clipboard')
|
||||||
|
if (!Clipboard) {
|
||||||
|
throw new Error('you shold npm install `clipboard` --save at first ')
|
||||||
|
}
|
||||||
|
|
||||||
|
export default {
|
||||||
|
bind(el, binding) {
|
||||||
|
if (binding.arg === 'success') {
|
||||||
|
el._v_clipboard_success = binding.value
|
||||||
|
} else if (binding.arg === 'error') {
|
||||||
|
el._v_clipboard_error = binding.value
|
||||||
|
} else {
|
||||||
|
const clipboard = new Clipboard(el, {
|
||||||
|
text() { return binding.value },
|
||||||
|
action() { return binding.arg === 'cut' ? 'cut' : 'copy' }
|
||||||
|
})
|
||||||
|
clipboard.on('success', e => {
|
||||||
|
const callback = el._v_clipboard_success
|
||||||
|
callback && callback(e) // eslint-disable-line
|
||||||
|
})
|
||||||
|
clipboard.on('error', e => {
|
||||||
|
const callback = el._v_clipboard_error
|
||||||
|
callback && callback(e) // eslint-disable-line
|
||||||
|
})
|
||||||
|
el._v_clipboard = clipboard
|
||||||
|
}
|
||||||
|
},
|
||||||
|
update(el, binding) {
|
||||||
|
if (binding.arg === 'success') {
|
||||||
|
el._v_clipboard_success = binding.value
|
||||||
|
} else if (binding.arg === 'error') {
|
||||||
|
el._v_clipboard_error = binding.value
|
||||||
|
} else {
|
||||||
|
el._v_clipboard.text = function() { return binding.value }
|
||||||
|
el._v_clipboard.action = function() { return binding.arg === 'cut' ? 'cut' : 'copy' }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
unbind(el, binding) {
|
||||||
|
if (binding.arg === 'success') {
|
||||||
|
delete el._v_clipboard_success
|
||||||
|
} else if (binding.arg === 'error') {
|
||||||
|
delete el._v_clipboard_error
|
||||||
|
} else {
|
||||||
|
el._v_clipboard.destroy()
|
||||||
|
delete el._v_clipboard
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,13 @@
|
||||||
|
import Clipboard from './clipboard'
|
||||||
|
|
||||||
|
const install = function(Vue) {
|
||||||
|
Vue.directive('Clipboard', Clipboard)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (window.Vue) {
|
||||||
|
window.clipboard = Clipboard
|
||||||
|
Vue.use(install); // eslint-disable-line
|
||||||
|
}
|
||||||
|
|
||||||
|
Clipboard.install = install
|
||||||
|
export default Clipboard
|
|
@ -0,0 +1,13 @@
|
||||||
|
import waves from './waves'
|
||||||
|
|
||||||
|
const install = function(Vue) {
|
||||||
|
Vue.directive('waves', waves)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (window.Vue) {
|
||||||
|
window.waves = waves
|
||||||
|
Vue.use(install); // eslint-disable-line
|
||||||
|
}
|
||||||
|
|
||||||
|
waves.install = install
|
||||||
|
export default waves
|
Before Width: | Height: | Size: 552 B After Width: | Height: | Size: 552 B |
|
@ -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="1506419860538" class="icon" style="" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4662" xmlns:xlink="http://www.w3.org/1999/xlink" width="64" height="64"><defs><style type="text/css"></style></defs><path d="M438.857143 950.857143l512 0 0-365.714286-237.714286 0q-22.820571 0-38.838857-16.018286t-16.018286-38.838857l0-237.714286-219.428571 0 0 658.285714zM585.142857 128l0-36.571429q0-7.460571-5.412571-12.873143t-12.873143-5.412571l-402.285714 0q-7.460571 0-12.873143 5.412571t-5.412571 12.873143l0 36.571429q0 7.460571 5.412571 12.873143t12.873143 5.412571l402.285714 0q7.460571 0 12.873143-5.412571t5.412571-12.873143zM731.428571 512l170.861714 0-170.861714-170.861714 0 170.861714zM1024 585.142857l0 384q0 22.820571-16.018286 38.838857t-38.838857 16.018286l-548.571429 0q-22.820571 0-38.838857-16.018286t-16.018286-38.838857l0-91.428571-310.857143 0q-22.820571 0-38.838857-16.018286t-16.018286-38.838857l0-768q0-22.820571 16.018286-38.838857t38.838857-16.018286l621.714286 0q22.820571 0 38.838857 16.018286t16.018286 38.838857l0 187.465143q11.995429 7.460571 20.553143 16.018286l233.179429 233.179429q16.018286 16.018286 27.428571 43.446857t11.410286 50.322286z" p-id="4663"></path></svg>
|
After Width: | Height: | Size: 1.3 KiB |
|
@ -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="1506329916765" class="icon" style="" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1661" xmlns:xlink="http://www.w3.org/1999/xlink" width="64" height="64"><defs><style type="text/css"></style></defs><path d="M64 64 448 64 448 448 64 448 64 64ZM64 576 448 576 448 960 64 960 64 576ZM576 576 960 576 960 960 576 960 576 576ZM768 448C874.038669 448 960 362.038672 960 256 960 149.961328 874.038669 64 768 64 661.961328 64 576 149.961328 576 256 576 362.038672 661.961328 448 768 448Z" p-id="1662"></path></svg>
|
After Width: | Height: | Size: 683 B |
Before Width: | Height: | Size: 983 B After Width: | Height: | Size: 983 B |
Before Width: | Height: | Size: 1.0 KiB After Width: | Height: | Size: 1.0 KiB |
Before Width: | Height: | Size: 866 B After Width: | Height: | Size: 866 B |
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 1.8 KiB |
|
@ -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="1506330387278" class="icon" style="" viewBox="0 0 1069 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1447" xmlns:xlink="http://www.w3.org/1999/xlink" width="66.8125" height="64"><defs><style type="text/css"></style></defs><path d="M746.027944 190.083832q-11.241517 0-18.906188-7.664671t-12.774451-17.884232-7.664671-20.9501-2.55489-17.884232l0-125.700599 2.043912 0q9.197605 0 17.373253 2.043912t19.928144 9.708583 28.61477 21.461078 42.411178 36.279441q27.592814 24.526946 43.944112 41.389222t25.037924 28.61477 10.730539 19.928144 2.043912 14.307385l0 16.351297-150.227545 0zM1063.856287 671.42515q3.065868 8.175649 4.087824 20.439122t-10.219561 23.50499q-5.10978 5.10978-9.197605 9.708583t-7.153693 7.664671q-4.087824 4.087824-7.153693 6.131737l-86.866267-85.844311q6.131737-5.10978 13.796407-12.263473t12.774451-11.241517q12.263473-11.241517 26.570858-9.708583t23.50499 6.642715q10.219561 5.10978 21.972056 17.884232t17.884232 27.081836zM703.105788 766.467066q22.483034 0 37.812375-12.263473l-198.259481 206.43513-282.05988 0q-19.417166 0-42.411178-11.241517t-42.922156-29.636727-33.213573-42.411178-13.285429-49.56487l0-695.952096q0-21.461078 9.708583-44.966068t26.570858-42.411178 38.323353-31.680639 44.966068-12.774451l391.409182 0 0 127.744511q0 19.417166 6.131737 41.9002t18.906188 41.389222 33.213573 31.680639 49.053892 12.774451l149.205589 0 0 338.267465-140.007984 145.117764q11.241517-16.351297 11.241517-35.768463 0-26.570858-18.906188-45.477046t-45.477046-18.906188l-383.233533 0q-26.570858 0-44.966068 18.906188t-18.39521 45.477046 18.39521 44.966068 44.966068 18.39521l383.233533 0zM319.872255 383.233533q-26.570858 0-44.966068 18.906188t-18.39521 45.477046 18.39521 44.966068 44.966068 18.39521l383.233533 0q26.570858 0 45.477046-18.39521t18.906188-44.966068-18.906188-45.477046-45.477046-18.906188l-383.233533 0zM705.149701 895.233533l13.285429-13.285429 25.548902-25.548902q15.329341-15.329341 33.724551-34.235529t36.790419-37.301397q43.944112-43.944112 99.129741-98.107784l85.844311 85.844311-99.129741 99.129741-36.790419 36.790419-33.724551 33.724551q-14.307385 14.307385-24.015968 24.526946t-10.730539 11.241517q-5.10978 4.087824-11.241517 8.686627t-12.263473 7.664671-18.906188 7.664671-26.05988 8.686627-25.548902 7.153693-18.39521 4.087824q-12.263473 2.043912-16.351297-3.065868t-2.043912-17.373253q1.021956-6.131737 4.087824-18.39521t7.153693-25.037924 7.664671-24.015968 5.620758-15.329341q6.131737-13.285429 16.351297-23.50499z" p-id="1448"></path></svg>
|
After Width: | Height: | Size: 2.6 KiB |
|
@ -1 +0,0 @@
|
||||||
<?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>
|
|
Before Width: | Height: | Size: 591 B |
Before Width: | Height: | Size: 1.0 KiB After Width: | Height: | Size: 1.0 KiB |
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.2 KiB |
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.7 KiB |
Before Width: | Height: | Size: 8.0 KiB After Width: | Height: | Size: 8.0 KiB |
|
@ -1 +0,0 @@
|
||||||
<?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>
|
|
Before Width: | Height: | Size: 602 B |
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.2 KiB |
|
@ -1 +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>
|
<?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="1506329761546" class="icon" style="" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1384" xmlns:xlink="http://www.w3.org/1999/xlink" width="64" height="64"><defs><style type="text/css"></style></defs><path d="M622.276923 39.384615H401.723077c-13.784615 0-23.630769 11.815385-23.630769 25.6v49.23077c0 13.784615 11.815385 25.6 23.630769 25.6h220.553846c13.784615 0 23.630769-11.815385 23.630769-25.6V64.984615c1.969231-13.784615-9.846154-25.6-23.630769-25.6z m336.738462 0H738.461538c-13.784615 0-25.6 11.815385-25.6 25.6v49.23077c0 13.784615 11.815385 25.6 25.6 25.6h220.553847c13.784615-1.969231 25.6-11.815385 25.6-25.6V64.984615c0-13.784615-11.815385-25.6-25.6-25.6z m0 165.415385H334.769231c-13.784615 0-25.6-11.815385-25.6-25.6V64.984615c0-13.784615-11.815385-25.6-25.6-25.6H64.984615C51.2 39.384615 39.384615 51.2 39.384615 64.984615v896c0 11.815385 11.815385 23.630769 25.6 23.63077h894.03077c13.784615 0 25.6-11.815385 25.6-25.6v-728.615385c0-13.784615-11.815385-25.6-25.6-25.6z" p-id="1385"></path></svg>
|
Before Width: | Height: | Size: 571 B After Width: | Height: | Size: 1.2 KiB |
Before Width: | Height: | Size: 678 B After Width: | Height: | Size: 678 B |
Before Width: | Height: | Size: 678 B After Width: | Height: | Size: 678 B |
Before Width: | Height: | Size: 673 B After Width: | Height: | Size: 673 B |
Before Width: | Height: | Size: 777 B After Width: | Height: | Size: 777 B |
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 2.2 KiB |
|
@ -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="1506326020470" class="icon" style="" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2561" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M619.364365 933.396352c1.372783 0.06385 2.681715 0.191551 4.054497 0.191551h309.291099a65.670086 65.670086 0 0 0 65.606235-65.606235V150.974154a65.670086 65.670086 0 0 0-65.606235-65.606235H623.418862c-1.372783 0-2.71364 0.127701-4.054497 0.191551V-0.031925L15.691224 80.547217v858.404116l603.673141 82.654279v-88.20926z m0-810.101325c1.340857-0.191551 2.681715-0.415027 4.054497-0.415027h309.291099c15.515635 0 28.12608 12.610444 28.12608 28.12608v717.007513a28.158005 28.158005 0 0 1-28.12608 28.12608H623.418862c-1.372783 0-2.71364-0.223476-4.054497-0.415028V123.326952zM248.329977 605.429026l-143.918691-3.671395v-23.401154l86.868402-133.255682v-1.181231l-78.919033 1.308932v-36.043523l134.564614-3.51177v26.082869l-87.506906 133.734559v1.149307l88.911614 1.404707v37.352456z m72.406297 1.85166l-44.759096-1.149306v-201.192456l44.759096-1.149306v203.491068z m171.087015-92.966111c-16.664942 15.356009-41.151551 22.060296-69.341481 21.868745a113.81325 113.81325 0 0 1-16.122213-1.05353v74.353733l-46.099954-1.181231v-202.788714c14.238628-2.809415 34.383414-5.171878 63.179923-5.938083 29.498862-0.766204 50.792954 4.309899 65.191208 15.292159 13.887451 10.439532 23.305378 27.966454 23.305378 48.845518s-7.119314 38.629462-20.080936 50.601403z m-65.925487-79.174435a80.13219 80.13219 0 0 0-19.538207 2.202837v61.392113c4.022572 0.92583 8.970974 1.213157 15.834887 1.213156 25.380514-0.031925 41.215401-12.897771 41.215401-34.479189 0-19.378581-13.63205-30.712019-37.480156-30.296992z m306.322058-296.233702h73.523679v30.328917h-73.523679v-30.328917z m-73.555604 45.397599h73.523679v30.360842h-73.523679v-30.360842z m73.555604 49.675573h73.523679v30.360842h-73.523679v-30.360842z m0 95.903227h73.523679v30.328917h-73.523679v-30.328917z m-73.555604-48.717818h73.523679v30.328917h-73.523679v-30.328917z m72.821325 376.142417a72.7894 72.7894 0 0 0 72.7894-72.821325l-13.440499-121.986095c0-40.225721-19.155105-72.821325-59.380827-72.821325s-59.348901 32.595604-59.348901 72.821325l-13.472424 121.986095a72.7894 72.7894 0 0 0 72.821325 72.821325z m-24.103508-133.862261h48.207015v101.84131h-48.207015v-101.84131z" p-id="2562"></path></svg>
|
After Width: | Height: | Size: 2.5 KiB |
|
@ -1 +0,0 @@
|
||||||
<?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>
|
|
Before Width: | Height: | Size: 534 B |
|
@ -34,7 +34,7 @@ export default {
|
||||||
if (userMap[token]) {
|
if (userMap[token]) {
|
||||||
return userMap[token]
|
return userMap[token]
|
||||||
} else {
|
} else {
|
||||||
return Promise.reject('error')
|
return false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
logout: () => 'success'
|
logout: () => 'success'
|
||||||
|
|
|
@ -3,6 +3,7 @@ import store from './store'
|
||||||
import NProgress from 'nprogress' // Progress 进度条
|
import NProgress from 'nprogress' // Progress 进度条
|
||||||
import 'nprogress/nprogress.css'// Progress 进度条样式
|
import 'nprogress/nprogress.css'// Progress 进度条样式
|
||||||
import { getToken } from '@/utils/auth' // 验权
|
import { getToken } from '@/utils/auth' // 验权
|
||||||
|
import { Message } from 'element-ui'
|
||||||
|
|
||||||
// permissiom judge
|
// permissiom judge
|
||||||
function hasPermission(roles, permissionRoles) {
|
function hasPermission(roles, permissionRoles) {
|
||||||
|
@ -18,6 +19,7 @@ router.beforeEach((to, from, next) => {
|
||||||
if (getToken()) { // 判断是否有token
|
if (getToken()) { // 判断是否有token
|
||||||
if (to.path === '/login') {
|
if (to.path === '/login') {
|
||||||
next({ path: '/' })
|
next({ path: '/' })
|
||||||
|
NProgress.done() // router在hash模式下 手动改变hash 重定向回来 不会触发afterEach 暂时hack方案 ps:history模式下无问题,可删除该行!
|
||||||
} else {
|
} else {
|
||||||
if (store.getters.roles.length === 0) { // 判断当前用户是否已拉取完user_info信息
|
if (store.getters.roles.length === 0) { // 判断当前用户是否已拉取完user_info信息
|
||||||
store.dispatch('GetUserInfo').then(res => { // 拉取user_info
|
store.dispatch('GetUserInfo').then(res => { // 拉取user_info
|
||||||
|
@ -28,6 +30,7 @@ router.beforeEach((to, from, next) => {
|
||||||
})
|
})
|
||||||
}).catch(() => {
|
}).catch(() => {
|
||||||
store.dispatch('FedLogOut').then(() => {
|
store.dispatch('FedLogOut').then(() => {
|
||||||
|
Message.error('验证失败,请重新登录')
|
||||||
next({ path: '/login' })
|
next({ path: '/login' })
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
@ -37,6 +40,7 @@ router.beforeEach((to, from, next) => {
|
||||||
next()//
|
next()//
|
||||||
} else {
|
} else {
|
||||||
next({ path: '/401', query: { noGoBack: true }})
|
next({ path: '/401', query: { noGoBack: true }})
|
||||||
|
NProgress.done() // router在hash模式下 手动改变hash 重定向回来 不会触发afterEach 暂时hack方案 ps:history模式下无问题,可删除该行!
|
||||||
}
|
}
|
||||||
// 可删 ↑
|
// 可删 ↑
|
||||||
}
|
}
|
||||||
|
@ -46,7 +50,7 @@ router.beforeEach((to, from, next) => {
|
||||||
next()
|
next()
|
||||||
} else {
|
} else {
|
||||||
next('/login') // 否则全部重定向到登录页
|
next('/login') // 否则全部重定向到登录页
|
||||||
NProgress.done() // 在hash模式下 改变手动改变hash 重定向回来 不会触发afterEach 暂时hack方案 ps:history模式下无问题,可删除该行!
|
NProgress.done() // router在hash模式下 手动改变hash 重定向回来 不会触发afterEach 暂时hack方案 ps:history模式下无问题,可删除该行!
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
|
@ -32,7 +32,7 @@ export const constantRouterMap = [
|
||||||
path: '/introduction',
|
path: '/introduction',
|
||||||
component: Layout,
|
component: Layout,
|
||||||
redirect: '/introduction/index',
|
redirect: '/introduction/index',
|
||||||
icon: 'xinrenzhinan',
|
icon: 'people',
|
||||||
noDropdown: true,
|
noDropdown: true,
|
||||||
children: [{ path: 'index', component: _import('introduction/index'), name: '简述' }]
|
children: [{ path: 'index', component: _import('introduction/index'), name: '简述' }]
|
||||||
}
|
}
|
||||||
|
@ -50,7 +50,7 @@ export const asyncRouterMap = [
|
||||||
component: Layout,
|
component: Layout,
|
||||||
redirect: '/permission/index',
|
redirect: '/permission/index',
|
||||||
name: '权限测试',
|
name: '权限测试',
|
||||||
icon: 'quanxian',
|
icon: 'lock',
|
||||||
meta: { role: ['admin'] },
|
meta: { role: ['admin'] },
|
||||||
noDropdown: true,
|
noDropdown: true,
|
||||||
children: [{ path: 'index', component: _import('permission/index'), name: '权限测试页', meta: { role: ['admin'] }}]
|
children: [{ path: 'index', component: _import('permission/index'), name: '权限测试页', meta: { role: ['admin'] }}]
|
||||||
|
@ -58,7 +58,7 @@ export const asyncRouterMap = [
|
||||||
{
|
{
|
||||||
path: '/icon',
|
path: '/icon',
|
||||||
component: Layout,
|
component: Layout,
|
||||||
icon: 'icons',
|
icon: 'icon',
|
||||||
noDropdown: true,
|
noDropdown: true,
|
||||||
children: [{ path: 'index', component: _import('svg-icons/index'), name: 'icons' }]
|
children: [{ path: 'index', component: _import('svg-icons/index'), name: 'icons' }]
|
||||||
},
|
},
|
||||||
|
@ -67,7 +67,7 @@ export const asyncRouterMap = [
|
||||||
component: Layout,
|
component: Layout,
|
||||||
redirect: '/components/index',
|
redirect: '/components/index',
|
||||||
name: '组件',
|
name: '组件',
|
||||||
icon: 'zujian',
|
icon: 'component',
|
||||||
children: [
|
children: [
|
||||||
{ path: 'index', component: _import('components/index'), name: '介绍 ' },
|
{ path: 'index', component: _import('components/index'), name: '介绍 ' },
|
||||||
{ path: 'tinymce', component: _import('components/tinymce'), name: '富文本编辑器' },
|
{ path: 'tinymce', component: _import('components/tinymce'), name: '富文本编辑器' },
|
||||||
|
@ -88,7 +88,7 @@ export const asyncRouterMap = [
|
||||||
component: Layout,
|
component: Layout,
|
||||||
redirect: '/charts/index',
|
redirect: '/charts/index',
|
||||||
name: '图表',
|
name: '图表',
|
||||||
icon: 'tubiao',
|
icon: 'chart',
|
||||||
children: [
|
children: [
|
||||||
{ path: 'index', component: _import('charts/index'), name: '介绍' },
|
{ path: 'index', component: _import('charts/index'), name: '介绍' },
|
||||||
{ path: 'keyboard', component: _import('charts/keyboard'), name: '键盘图表' },
|
{ path: 'keyboard', component: _import('charts/keyboard'), name: '键盘图表' },
|
||||||
|
@ -102,7 +102,7 @@ export const asyncRouterMap = [
|
||||||
component: Layout,
|
component: Layout,
|
||||||
redirect: 'noredirect',
|
redirect: 'noredirect',
|
||||||
name: '综合实例',
|
name: '综合实例',
|
||||||
icon: 'zonghe',
|
icon: 'example',
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
path: '/example/table',
|
path: '/example/table',
|
||||||
|
@ -117,8 +117,8 @@ export const asyncRouterMap = [
|
||||||
{ path: 'table', component: _import('example/table/table'), name: '综合table' }
|
{ path: 'table', component: _import('example/table/table'), name: '综合table' }
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{ path: 'form/edit', icon: 'shouce', component: _import('example/form'), name: '编辑Form', meta: { isEdit: true }},
|
{ path: 'form/edit', icon: 'form', component: _import('example/form'), name: '编辑Form', meta: { isEdit: true }},
|
||||||
{ path: 'form/create', icon: 'from', component: _import('example/form'), name: '创建Form' },
|
{ path: 'form/create', icon: 'form', component: _import('example/form'), name: '创建Form' },
|
||||||
{ path: 'tab/index', icon: 'tab', component: _import('example/tab/index'), name: 'Tab' }
|
{ path: 'tab/index', icon: 'tab', component: _import('example/tab/index'), name: 'Tab' }
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
@ -147,13 +147,23 @@ export const asyncRouterMap = [
|
||||||
component: Layout,
|
component: Layout,
|
||||||
redirect: '/excel/download',
|
redirect: '/excel/download',
|
||||||
name: 'excel',
|
name: 'excel',
|
||||||
icon: 'EXCEL',
|
icon: 'excel',
|
||||||
children: [
|
children: [
|
||||||
{ path: 'download', component: _import('excel/index'), name: '导出excel' },
|
{ path: 'download', component: _import('excel/index'), name: 'export excel' },
|
||||||
{ path: 'download2', component: _import('excel/selectExcel'), name: '导出已选择项' },
|
{ path: 'download2', component: _import('excel/selectExcel'), name: 'export selected' },
|
||||||
{ path: 'upload', component: _import('excel/uploadExcel'), name: 'upload excel' }
|
{ path: 'upload', component: _import('excel/uploadExcel'), name: 'upload excel' }
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: '/zip',
|
||||||
|
component: Layout,
|
||||||
|
redirect: '/zip/download',
|
||||||
|
name: 'zip',
|
||||||
|
icon: 'zip',
|
||||||
|
children: [
|
||||||
|
{ path: 'download', component: _import('zip/index'), name: 'export zip' }
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: '/theme',
|
path: '/theme',
|
||||||
component: Layout,
|
component: Layout,
|
||||||
|
@ -163,6 +173,14 @@ export const asyncRouterMap = [
|
||||||
noDropdown: true,
|
noDropdown: true,
|
||||||
children: [{ path: 'index', component: _import('theme/index'), name: '换肤' }]
|
children: [{ path: 'index', component: _import('theme/index'), name: '换肤' }]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: '/clipboard',
|
||||||
|
component: Layout,
|
||||||
|
redirect: 'noredirect',
|
||||||
|
icon: 'clipboard',
|
||||||
|
noDropdown: true,
|
||||||
|
children: [{ path: 'index', component: _import('clipboard/index'), name: 'clipboard' }]
|
||||||
|
},
|
||||||
|
|
||||||
{ path: '*', redirect: '/404', hidden: true }
|
{ path: '*', redirect: '/404', hidden: true }
|
||||||
]
|
]
|
||||||
|
|
|
@ -63,6 +63,9 @@ const user = {
|
||||||
GetUserInfo({ commit, state }) {
|
GetUserInfo({ commit, state }) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
getUserInfo(state.token).then(response => {
|
getUserInfo(state.token).then(response => {
|
||||||
|
if (!response.data) { // 由于mockjs 不支持自定义状态码只能这样hack
|
||||||
|
reject('error')
|
||||||
|
}
|
||||||
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)
|
||||||
|
|
|
@ -0,0 +1,36 @@
|
||||||
|
import Clipboard from 'clipboard'
|
||||||
|
import Vue from 'vue'
|
||||||
|
|
||||||
|
function clipboardSuccess() {
|
||||||
|
Vue.prototype.$message({
|
||||||
|
message: '复制成功',
|
||||||
|
type: 'success',
|
||||||
|
duration: 1500
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function clipboardError() {
|
||||||
|
Vue.prototype.$message({
|
||||||
|
message: '复制失败',
|
||||||
|
type: 'error'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function handleClipboard(text, event) {
|
||||||
|
const clipboard = new Clipboard(event.target, {
|
||||||
|
text: () => text
|
||||||
|
})
|
||||||
|
clipboard.on('success', () => {
|
||||||
|
clipboardSuccess()
|
||||||
|
clipboard.off('error')
|
||||||
|
clipboard.off('success')
|
||||||
|
clipboard.destroy()
|
||||||
|
})
|
||||||
|
clipboard.on('error', () => {
|
||||||
|
clipboardError()
|
||||||
|
clipboard.off('error')
|
||||||
|
clipboard.off('success')
|
||||||
|
clipboard.destroy()
|
||||||
|
})
|
||||||
|
clipboard.onClick(event)
|
||||||
|
}
|
|
@ -1,7 +1,8 @@
|
||||||
/* eslint-disable */
|
/* eslint-disable */
|
||||||
require('script-loader!file-saver');
|
require('script-loader!file-saver');
|
||||||
require('script-loader!vendor/Blob');
|
require('script-loader!vendor/Blob');
|
||||||
require('script-loader!xlsx/dist/xlsx.core.min');
|
import XLSX from 'xlsx'
|
||||||
|
|
||||||
function generateArray(table) {
|
function generateArray(table) {
|
||||||
var out = [];
|
var out = [];
|
||||||
var rows = table.querySelectorAll('tr');
|
var rows = table.querySelectorAll('tr');
|
||||||
|
@ -93,14 +94,12 @@ function s2ab(s) {
|
||||||
|
|
||||||
export function export_table_to_excel(id) {
|
export function export_table_to_excel(id) {
|
||||||
var theTable = document.getElementById(id);
|
var theTable = document.getElementById(id);
|
||||||
console.log('a')
|
|
||||||
var oo = generateArray(theTable);
|
var oo = generateArray(theTable);
|
||||||
var ranges = oo[1];
|
var ranges = oo[1];
|
||||||
|
|
||||||
/* original data */
|
/* original data */
|
||||||
var data = oo[0];
|
var data = oo[0];
|
||||||
var ws_name = "SheetJS";
|
var ws_name = "SheetJS";
|
||||||
console.log(data);
|
|
||||||
|
|
||||||
var wb = new Workbook(), ws = sheet_from_array_of_arrays(data);
|
var wb = new Workbook(), ws = sheet_from_array_of_arrays(data);
|
||||||
|
|
||||||
|
@ -117,9 +116,6 @@ export function export_table_to_excel(id) {
|
||||||
saveAs(new Blob([s2ab(wbout)], {type: "application/octet-stream"}), "test.xlsx")
|
saveAs(new Blob([s2ab(wbout)], {type: "application/octet-stream"}), "test.xlsx")
|
||||||
}
|
}
|
||||||
|
|
||||||
function formatJson(jsonData) {
|
|
||||||
console.log(jsonData)
|
|
||||||
}
|
|
||||||
export function export_json_to_excel(th, jsonData, defaultTitle) {
|
export function export_json_to_excel(th, jsonData, defaultTitle) {
|
||||||
|
|
||||||
/* original data */
|
/* original data */
|
||||||
|
@ -130,6 +126,29 @@ export function export_json_to_excel(th, jsonData, defaultTitle) {
|
||||||
|
|
||||||
var wb = new Workbook(), ws = sheet_from_array_of_arrays(data);
|
var wb = new Workbook(), ws = sheet_from_array_of_arrays(data);
|
||||||
|
|
||||||
|
/*设置worksheet每列的最大宽度*/
|
||||||
|
const colWidth = data.map(row => row.map(val => {
|
||||||
|
/*先判断是否为null/undefined*/
|
||||||
|
if (val == null) {
|
||||||
|
return {'wch': 10};
|
||||||
|
}
|
||||||
|
/*再判断是否为中文*/
|
||||||
|
else if (val.toString().charCodeAt(0) > 255) {
|
||||||
|
return {'wch': val.toString().length * 2};
|
||||||
|
} else {
|
||||||
|
return {'wch': val.toString().length};
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
/*以第一行为初始值*/
|
||||||
|
let result = colWidth[0];
|
||||||
|
for (let i = 1; i < colWidth.length; i++) {
|
||||||
|
for (let j = 0; j < colWidth[i].length; j++) {
|
||||||
|
if (result[j]['wch'] < colWidth[i][j]['wch']) {
|
||||||
|
result[j]['wch'] = colWidth[i][j]['wch'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ws['!cols'] = result;
|
||||||
|
|
||||||
/* add worksheet to workbook */
|
/* add worksheet to workbook */
|
||||||
wb.SheetNames.push(ws_name);
|
wb.SheetNames.push(ws_name);
|
||||||
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
/* eslint-disable */
|
||||||
|
require('script-loader!file-saver');
|
||||||
|
import JSZip from 'jszip'
|
||||||
|
|
||||||
|
export function export_txt_to_zip(th, jsonData, txtName, zipName) {
|
||||||
|
const zip = new JSZip()
|
||||||
|
const txt_name = txtName || '文本'
|
||||||
|
const zip_name = zipName || '压缩包'
|
||||||
|
const data = jsonData
|
||||||
|
let txtData = `${th}\r\n`
|
||||||
|
data.forEach((row) => {
|
||||||
|
let tempStr = ''
|
||||||
|
tempStr = row.toString()
|
||||||
|
txtData += `${tempStr}\r\n`
|
||||||
|
})
|
||||||
|
zip.file(`${txt_name}.txt`, txtData)
|
||||||
|
zip.generateAsync({type:"blob"}).then((blob) => {
|
||||||
|
saveAs(blob, `${zip_name}.zip`)
|
||||||
|
}, (err) => {
|
||||||
|
alert('导出失败')
|
||||||
|
})
|
||||||
|
}
|
|
@ -0,0 +1,44 @@
|
||||||
|
<template>
|
||||||
|
<div class="app-container">
|
||||||
|
<el-tabs v-model="activeName">
|
||||||
|
<el-tab-pane label="use clipboard directly" name="directly">
|
||||||
|
<el-input v-model="inputData" placeholder="请输入内容" style='width:400px;'></el-input>
|
||||||
|
<el-button type="primary" icon="document" @click='handleCopy(inputData,$event)'>copy</el-button>
|
||||||
|
</el-tab-pane>
|
||||||
|
<el-tab-pane label="use clipboard by v-directive" name="v-directive">
|
||||||
|
<el-input v-model="inputData" placeholder="请输入内容" style='width:400px;'></el-input>
|
||||||
|
<el-button type="primary" icon="document" v-clipboard:copy='inputData' v-clipboard:success='clipboardSuccess'>copy</el-button>
|
||||||
|
</el-tab-pane>
|
||||||
|
</el-tabs>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import clip from '@/utils/clipboard' // use clipboard directly
|
||||||
|
import clipboard from '@/directive/clipboard/index.js' // use clipboard by v-directive
|
||||||
|
|
||||||
|
export default {
|
||||||
|
directives: {
|
||||||
|
clipboard
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
activeName: 'directly',
|
||||||
|
inputData: 'https://github.com/PanJiaChen/vue-element-admin'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
handleCopy(text, event) {
|
||||||
|
clip(text, event)
|
||||||
|
},
|
||||||
|
clipboardSuccess() {
|
||||||
|
this.$message({
|
||||||
|
message: '复制成功',
|
||||||
|
type: 'success',
|
||||||
|
duration: 1500
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="components-container">
|
<div class="components-container">
|
||||||
<div class='component-item'>
|
<div class='component-item'>
|
||||||
<md-input name="name" v-model="title" required :maxlength="100">
|
<el-form :model="demo" :rules="demoRules">
|
||||||
标题
|
<el-form-item prop="title">
|
||||||
</md-input>
|
<md-input icon="search" name="title" placeholder="输入标题" v-model="demo.title">标题</md-input>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
<code class='code-part'>Material Design 的input</code>
|
<code class='code-part'>Material Design 的input</code>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -22,18 +24,33 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import MdInput from '@/components/MDinput'
|
|
||||||
import PanThumb from '@/components/PanThumb'
|
import PanThumb from '@/components/PanThumb'
|
||||||
import waves from '@/directive/waves.js' // 水波纹指令
|
import MdInput from '@/components/MDinput'
|
||||||
|
import waves from '@/directive/waves/index.js' // 水波纹指令
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: { MdInput, PanThumb },
|
components: {
|
||||||
|
PanThumb,
|
||||||
|
MdInput
|
||||||
|
},
|
||||||
directives: {
|
directives: {
|
||||||
waves
|
waves
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
|
const validate = (rule, value, callback) => {
|
||||||
|
if (value.length !== 6) {
|
||||||
|
callback(new Error('请输入六个字符'))
|
||||||
|
} else {
|
||||||
|
callback()
|
||||||
|
}
|
||||||
|
}
|
||||||
return {
|
return {
|
||||||
|
demo: {
|
||||||
title: ''
|
title: ''
|
||||||
|
},
|
||||||
|
demoRules: {
|
||||||
|
title: [{ required: true, trigger: 'change', validator: validate }]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,12 +34,12 @@
|
||||||
<div class="info-item">
|
<div class="info-item">
|
||||||
<count-to class="info-item-num" :startVal='0' :endVal='statisticsData.article_count' :duration='3400'></count-to>
|
<count-to class="info-item-num" :startVal='0' :endVal='statisticsData.article_count' :duration='3400'></count-to>
|
||||||
<span class="info-item-text">文章</span>
|
<span class="info-item-text">文章</span>
|
||||||
<icon-svg icon-class="a" class="dashboard-editor-icon"></icon-svg>
|
<icon-svg icon-class="trendChart1" class="dashboard-editor-icon"></icon-svg>
|
||||||
</div>
|
</div>
|
||||||
<div class="info-item">
|
<div class="info-item">
|
||||||
<count-to class="info-item-num" :startVal='0' :endVal='statisticsData.pageviews_count' :duration='3600'></count-to>
|
<count-to class="info-item-num" :startVal='0' :endVal='statisticsData.pageviews_count' :duration='3600'></count-to>
|
||||||
<span class="info-item-text">浏览量</span>
|
<span class="info-item-text">浏览量</span>
|
||||||
<icon-svg icon-class="b" class="dashboard-editor-icon"></icon-svg>
|
<icon-svg icon-class="trendChart2" class="dashboard-editor-icon"></icon-svg>
|
||||||
</div>
|
</div>
|
||||||
</el-card>
|
</el-card>
|
||||||
</el-col>
|
</el-col>
|
||||||
|
|
|
@ -29,7 +29,7 @@
|
||||||
|
|
||||||
<el-table-column width="80px" label="重要性">
|
<el-table-column width="80px" label="重要性">
|
||||||
<template scope="scope">
|
<template scope="scope">
|
||||||
<icon-svg v-for="n in +scope.row.importance" icon-class="wujiaoxing" :key="n"></icon-svg>
|
<icon-svg v-for="n in +scope.row.importance" icon-class="star" :key="n"></icon-svg>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
|
|
||||||
|
|
|
@ -29,7 +29,7 @@
|
||||||
|
|
||||||
<el-table-column width="80px" label="重要性">
|
<el-table-column width="80px" label="重要性">
|
||||||
<template scope="scope">
|
<template scope="scope">
|
||||||
<icon-svg v-for="n in +scope.row.importance" icon-class="wujiaoxing" class="meta-item__icon" :key="n"></icon-svg>
|
<icon-svg v-for="n in +scope.row.importance" icon-class="star" class="meta-item__icon" :key="n"></icon-svg>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
|
|
||||||
|
@ -47,7 +47,7 @@
|
||||||
|
|
||||||
<el-table-column align="center" label="拖拽" width="95">
|
<el-table-column align="center" label="拖拽" width="95">
|
||||||
<template scope="scope">
|
<template scope="scope">
|
||||||
<icon-svg class='drag-handler' icon-class="tuozhuai"></icon-svg>
|
<icon-svg class='drag-handler' icon-class="drag"></icon-svg>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,7 @@
|
||||||
|
|
||||||
<el-table-column width="100px" label="重要性">
|
<el-table-column width="100px" label="重要性">
|
||||||
<template scope="scope">
|
<template scope="scope">
|
||||||
<icon-svg v-for="n in +scope.row.importance" icon-class="wujiaoxing" class="meta-item__icon" :key="n"></icon-svg>
|
<icon-svg v-for="n in +scope.row.importance" icon-class="star" class="meta-item__icon" :key="n"></icon-svg>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
|
|
||||||
|
|
|
@ -60,7 +60,7 @@
|
||||||
|
|
||||||
<el-table-column width="80px" label="重要性">
|
<el-table-column width="80px" label="重要性">
|
||||||
<template scope="scope">
|
<template scope="scope">
|
||||||
<icon-svg v-for="n in +scope.row.importance" icon-class="wujiaoxing" class="meta-item__icon" :key="n"></icon-svg>
|
<icon-svg v-for="n in +scope.row.importance" icon-class="star" class="meta-item__icon" :key="n"></icon-svg>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
|
|
||||||
|
@ -151,7 +151,7 @@
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { fetchList, fetchPv } from '@/api/article'
|
import { fetchList, fetchPv } from '@/api/article'
|
||||||
import waves from '@/directive/waves.js'// 水波纹指令
|
import waves from '@/directive/waves/index.js' // 水波纹指令
|
||||||
import { parseTime } from '@/utils'
|
import { parseTime } from '@/utils'
|
||||||
|
|
||||||
const calendarTypeOptions = [
|
const calendarTypeOptions = [
|
||||||
|
|
|
@ -25,7 +25,7 @@
|
||||||
<el-table-column align="center" prop="created_at" label="发布时间" width="220">
|
<el-table-column align="center" prop="created_at" label="发布时间" width="220">
|
||||||
<template scope="scope">
|
<template scope="scope">
|
||||||
<i class="el-icon-time"></i>
|
<i class="el-icon-time"></i>
|
||||||
<span>{{scope.row.display_time}}</span>
|
<span>{{scope.row.timestamp | parseTime('{y}-{m}-{d} {h}:{i}')}}</span>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
|
@ -34,6 +34,7 @@
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { fetchList } from '@/api/article'
|
import { fetchList } from '@/api/article'
|
||||||
|
import { parseTime } from 'utils'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
data() {
|
data() {
|
||||||
|
@ -67,7 +68,13 @@ export default {
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
formatJson(filterVal, jsonData) {
|
formatJson(filterVal, jsonData) {
|
||||||
return jsonData.map(v => filterVal.map(j => v[j]))
|
return jsonData.map(v => filterVal.map(j => {
|
||||||
|
if (j === 'timestamp') {
|
||||||
|
return parseTime(v[j])
|
||||||
|
} else {
|
||||||
|
return v[j]
|
||||||
|
}
|
||||||
|
}))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,13 +30,16 @@ export default {
|
||||||
$event.preventDefault()
|
$event.preventDefault()
|
||||||
},
|
},
|
||||||
generateRoute() {
|
generateRoute() {
|
||||||
if (this.$route.matched[this.$route.matched.length - 1].name) {
|
if (this.$route.name) {
|
||||||
return this.$route.matched[this.$route.matched.length - 1]
|
return this.$route
|
||||||
}
|
}
|
||||||
this.$route.matched[0].path = '/'
|
return false
|
||||||
return this.$route.matched[0]
|
|
||||||
},
|
},
|
||||||
addViewTabs() {
|
addViewTabs() {
|
||||||
|
const route = this.generateRoute()
|
||||||
|
if (!route) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
this.$store.dispatch('addVisitedViews', this.generateRoute())
|
this.$store.dispatch('addVisitedViews', this.generateRoute())
|
||||||
},
|
},
|
||||||
isActive(path) {
|
isActive(path) {
|
||||||
|
|
|
@ -5,18 +5,18 @@
|
||||||
|
|
||||||
<el-form-item prop="username">
|
<el-form-item prop="username">
|
||||||
<span class="svg-container svg-container_login">
|
<span class="svg-container svg-container_login">
|
||||||
<icon-svg icon-class="yonghuming" />
|
<icon-svg icon-class="user" />
|
||||||
</span>
|
</span>
|
||||||
<el-input name="username" type="text" v-model="loginForm.username" autoComplete="on" placeholder="邮箱" />
|
<el-input name="username" type="text" v-model="loginForm.username" autoComplete="on" placeholder="邮箱" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<el-form-item prop="password">
|
<el-form-item prop="password">
|
||||||
<span class="svg-container">
|
<span class="svg-container">
|
||||||
<icon-svg icon-class="mima" />
|
<icon-svg icon-class="password" />
|
||||||
</span>
|
</span>
|
||||||
<el-input name="password" :type="pwdType" @keyup.enter.native="handleLogin" v-model="loginForm.password" autoComplete="on"
|
<el-input name="password" :type="pwdType" @keyup.enter.native="handleLogin" v-model="loginForm.password" autoComplete="on"
|
||||||
placeholder="密码" />
|
placeholder="密码" />
|
||||||
<span class='show-pwd' @click='showPwd'><icon-svg icon-class="yanjing" /></span>
|
<span class='show-pwd' @click='showPwd'><icon-svg icon-class="eye" /></span>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<el-button type="primary" style="width:100%;margin-bottom:30px;" :loading="loading" @click.native.prevent="handleLogin">登录</el-button>
|
<el-button type="primary" style="width:100%;margin-bottom:30px;" :loading="loading" @click.native.prevent="handleLogin">登录</el-button>
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="social-signup-container">
|
<div class="social-signup-container">
|
||||||
<div class="sign-btn" @click="wechatHandleClick('wechat')">
|
<div class="sign-btn" @click="wechatHandleClick('wechat')">
|
||||||
<span class="wx-svg-container"><icon-svg icon-class="weixin" class="icon"></icon-svg></span> 微信
|
<span class="wx-svg-container"><icon-svg icon-class="wechat" class="icon"></icon-svg></span> 微信
|
||||||
</div>
|
</div>
|
||||||
<div class="sign-btn" @click="tencentHandleClick('tencent')">
|
<div class="sign-btn" @click="tencentHandleClick('tencent')">
|
||||||
<span class="qq-svg-container"><icon-svg icon-class="QQ" class="icon"></icon-svg></span> QQ
|
<span class="qq-svg-container"><icon-svg icon-class="qq" class="icon"></icon-svg></span> QQ
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="icons-container">
|
<div class="icons-container">
|
||||||
<div class="icons-wrapper">
|
<div class="icons-wrapper">
|
||||||
<div v-for='item of iconsMap' :key='item' class='icon-item'>
|
<div v-for='item of iconsMap' :key='item' class='icon-item' @click='handleClipboard(generateIconCode(item),$event)'>
|
||||||
<el-tooltip placement="top" effect="light">
|
<el-tooltip placement="top" effect="light">
|
||||||
<div slot="content">
|
<div slot="content">
|
||||||
{{`<icon-svg :icon-class="${item}" />`}}
|
{{generateIconCode(item)}}
|
||||||
</div>
|
</div>
|
||||||
<icon-svg :icon-class="item" />
|
<icon-svg :icon-class="item" />
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
|
@ -16,6 +16,7 @@
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import icons from './generateIconsView'
|
import icons from './generateIconsView'
|
||||||
|
import clipboard from '@/utils/clipboard' // use clipboard directly
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
data() {
|
data() {
|
||||||
|
@ -28,6 +29,14 @@ export default {
|
||||||
return i.default.id.split('-')[1]
|
return i.default.id.split('-')[1]
|
||||||
})
|
})
|
||||||
this.iconsMap = iconsMap
|
this.iconsMap = iconsMap
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
generateIconCode(symbol) {
|
||||||
|
return `<icon-svg :icon-class="${symbol}" />`
|
||||||
|
},
|
||||||
|
handleClipboard(text, event) {
|
||||||
|
clipboard(text, event)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -0,0 +1,74 @@
|
||||||
|
<template>
|
||||||
|
<div class="app-container">
|
||||||
|
<el-button style='margin-bottom:20px;' type="primary" icon="document" @click="handleDownload" :loading="downloadLoading">导出zip</el-button>
|
||||||
|
<el-table :data="list" v-loading.body="listLoading" element-loading-text="拼命加载中" border fit highlight-current-row>
|
||||||
|
<el-table-column align="center" label='ID' width="95">
|
||||||
|
<template scope="scope">
|
||||||
|
{{scope.$index}}
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="文章标题">
|
||||||
|
<template scope="scope">
|
||||||
|
{{scope.row.title}}
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="作者" width="95" align="center">
|
||||||
|
<template scope="scope">
|
||||||
|
<el-tag>{{scope.row.author}}</el-tag>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="阅读数" width="115" align="center">
|
||||||
|
<template scope="scope">
|
||||||
|
{{scope.row.pageviews}}
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column align="center" prop="created_at" label="发布时间" width="220">
|
||||||
|
<template scope="scope">
|
||||||
|
<i class="el-icon-time"></i>
|
||||||
|
<span>{{scope.row.display_time}}</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { fetchList } from '@/api/article'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
list: null,
|
||||||
|
listLoading: true,
|
||||||
|
downloadLoading: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
this.fetchData()
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
fetchData() {
|
||||||
|
this.listLoading = true
|
||||||
|
fetchList().then(response => {
|
||||||
|
this.list = response.data.items
|
||||||
|
this.listLoading = false
|
||||||
|
})
|
||||||
|
},
|
||||||
|
handleDownload() {
|
||||||
|
this.downloadLoading = true
|
||||||
|
require.ensure([], () => {
|
||||||
|
const { export_txt_to_zip } = require('vendor/Export2Zip')
|
||||||
|
const tHeader = ['序号', '文章标题', '作者', '阅读数', '发布时间']
|
||||||
|
const filterVal = ['id', 'title', 'author', 'pageviews', 'display_time']
|
||||||
|
const list = this.list
|
||||||
|
const data = this.formatJson(filterVal, list)
|
||||||
|
export_txt_to_zip(tHeader, data, '列表文本', '压缩文本')
|
||||||
|
this.downloadLoading = false
|
||||||
|
})
|
||||||
|
},
|
||||||
|
formatJson(filterVal, jsonData) {
|
||||||
|
return jsonData.map(v => filterVal.map(j => v[j]))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|