Compare commits
33 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
7287894cb8 | ||
|
29402cc889 | ||
|
a1a96c38d7 | ||
|
2927e08d06 | ||
|
5a8755ec9f | ||
|
3a2bf13a1f | ||
|
4a6ef1af17 | ||
|
42b5875d36 | ||
|
4af4df702c | ||
|
72d9a406b4 | ||
|
bd607b4728 | ||
|
f82ec2d5d7 | ||
|
c412d17b70 | ||
|
09deec1e5e | ||
|
acaa6bb269 | ||
|
7d6917a5ef | ||
|
dd73827112 | ||
|
4fc649e828 | ||
|
5165ec26ae | ||
|
d2827bf047 | ||
|
e9d37a94d3 | ||
|
9607d07cc0 | ||
|
ecf7558e8e | ||
|
703c0c5cc5 | ||
|
46b6a6e19f | ||
|
e8fb41d0ff | ||
|
f2847862e0 | ||
|
e6bae82fe5 | ||
|
96032becf9 | ||
|
9da96e2083 | ||
|
44166278ff | ||
|
327ed42e24 | ||
|
677ef6dbe3 |
@@ -50,8 +50,11 @@ Join the group on QQ 591724180.
|
||||
- Multi-environments distribution
|
||||
- Dashboard
|
||||
- Two-factor authentication
|
||||
- Collapsing sidebar
|
||||
- Collapsing sidebar (support nested routes)
|
||||
- Mock data
|
||||
- cache tabs example
|
||||
- screenfull
|
||||
- markdown2html
|
||||
|
||||
## Development
|
||||
|
||||
@@ -111,6 +114,9 @@ npm run build:prod
|
||||
└── package.json // package.json
|
||||
```
|
||||
|
||||
## Changelog
|
||||
Detailed changes for each release are documented in the [release notes](https://github.com/PanJiaChen/vue-element-admin/releases).
|
||||
|
||||
## State Management
|
||||
|
||||
Only status of user and app configuration is managed by Vuex. Other data are managed by their own business pages.
|
||||
|
26
README.md
@@ -8,19 +8,24 @@
|
||||
**注意:该项目目前使用element-ui@1.3.3版本,所以最低兼容 Vue 2.3.0**
|
||||
|
||||
## 前言
|
||||
> 这半年来一直在用vue写管理后台,目前后台已经有七十多个页面,十几种权限,但维护成本依然很低,所以准备开源分享一下后台开发的经验和成果。目前的技术栈主要的采用vue+element+axios.由于是个人项目,所以数据请求都是用了mockjs模拟。注意:在次项目基础上改造开发时请移除mock文件。
|
||||
> 这半年来一直在用vue写管理后台,目前后台已经有百来个个页面,十几种权限,但维护成本依然很低,所以准备开源分享一下后台开发的经验和成果。目前的技术栈主要的采用vue+element+axios由webpack2打包.由于是个人项目,所以数据请求都是用了mockjs模拟。注意:在次项目基础上改造开发时请移除mock文件。
|
||||
|
||||
后续会出一系列的教程配套文章,如如何从零构建后台项目框架,如何做完整的用户系统(如权限验证,二次登录等),如何二次开发组件(如富文本),如何整合七牛等等文章,各种后台开发经验等等。莫急~~
|
||||
|
||||
相应需求,开了一个qq群 591724180 方便大家交流
|
||||
写了一个系列的教程配套文章,如何从零构建后一个完整的后台项目:
|
||||
|
||||
- [wiki](https://github.com/PanJiaChen/vue-element-admin/wiki)
|
||||
- [手摸手,带你用 vue 撸后台 系列一(基础篇)](https://juejin.im/post/59097cd7a22b9d0065fb61d2)
|
||||
- [手摸手,带你用 vue 撸后台 系列二(登录权限篇)](https://juejin.im/post/591aa14f570c35006961acac)
|
||||
- [ 手摸手,带你封装一个vue component](https://segmentfault.com/a/1190000009090836)
|
||||
- [手摸手,带你用 vue 撸后台 系列三 (实战篇)](https://juejin.im/post/593121aa0ce4630057f70d35)
|
||||
- [手摸手,带你封装一个vue component](https://segmentfault.com/a/1190000009090836)
|
||||
|
||||
相应需求,开了一个qq群 591724180 方便大家交流
|
||||
|
||||
**如有问题请先看上述文章和Wiki,若不能满足,欢迎issue和pr~**
|
||||
|
||||
**该项目并不是一个脚手架,更倾向于是一个集成解决方案方案**
|
||||
|
||||
**该项目不支持低版本游览器,有需求请自行添加polyfill[详情](https://github.com/PanJiaChen/vue-element-admin/wiki#babel-polyfill)**
|
||||
|
||||
**如有问题请先看上述问题和Wiki,不能满足,欢迎issue和pr~**
|
||||
|
||||
## 功能
|
||||
- 登录/注销
|
||||
@@ -42,12 +47,16 @@
|
||||
- table example
|
||||
- 动态table example
|
||||
- 拖拽table example
|
||||
- 内联编辑table example
|
||||
- form example
|
||||
- 多环境发布
|
||||
- dashboard
|
||||
- 二次登录
|
||||
- 动态侧边栏
|
||||
- 动态侧边栏(支持多级路由)
|
||||
- mock数据
|
||||
- cache tabs example
|
||||
- screenfull
|
||||
- markdown2html
|
||||
|
||||
|
||||
## 开发
|
||||
@@ -104,6 +113,9 @@
|
||||
|
||||
```
|
||||
|
||||
## Changelog
|
||||
Detailed changes for each release are documented in the [release notes](https://github.com/PanJiaChen/vue-element-admin/releases).
|
||||
|
||||
## 状态管理
|
||||
后台只有user和app配置相关状态使用vuex存在全局,其它数据都由每个业务页面自己管理。
|
||||
|
||||
|
Before Width: | Height: | Size: 48 KiB After Width: | Height: | Size: 41 KiB |
Before Width: | Height: | Size: 486 KiB After Width: | Height: | Size: 532 KiB |
Before Width: | Height: | Size: 605 KiB After Width: | Height: | Size: 601 KiB |
BIN
gifs/order.gif
Before Width: | Height: | Size: 968 KiB After Width: | Height: | Size: 1.1 MiB |
67
package.json
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "juicy",
|
||||
"version": "1.0.0",
|
||||
"version": "1.0.2",
|
||||
"description": "A Vue.js admin",
|
||||
"author": "Pan <panfree23@gmail.com>",
|
||||
"license": "MIT",
|
||||
@@ -13,57 +13,59 @@
|
||||
"lint": "eslint --ext .js,.vue src"
|
||||
},
|
||||
"dependencies": {
|
||||
"axios": "0.15.3",
|
||||
"codemirror": "5.25.2",
|
||||
"dropzone": "4.3.0",
|
||||
"echarts": "3.4.0",
|
||||
"element-ui": "1.3.3",
|
||||
"axios": "0.16.2",
|
||||
"codemirror": "5.26.0",
|
||||
"dropzone": "5.1.0",
|
||||
"echarts": "3.6.1",
|
||||
"element-ui": "1.3.6",
|
||||
"file-saver": "1.3.3",
|
||||
"jquery": "3.1.1",
|
||||
"js-cookie": "2.1.3",
|
||||
"js-cookie": "2.1.4",
|
||||
"jsonlint": "1.6.2",
|
||||
"mockjs": "1.0.1-beta3",
|
||||
"normalize.css": "3.0.2",
|
||||
"nprogress": "0.2.0",
|
||||
"screenfull": "3.2.2",
|
||||
"showdown": "1.7.1",
|
||||
"simplemde": "1.11.2",
|
||||
"sortablejs": "1.5.1",
|
||||
"vue": "2.3.3",
|
||||
"vue-count-to": "1.0.5",
|
||||
"vue-multiselect": "2.0.0-beta.15",
|
||||
"vue-router": "2.5.3",
|
||||
"vuedraggable": "2.8.4",
|
||||
"vuedraggable": "2.13.1",
|
||||
"vuex": "2.3.1",
|
||||
"xlsx": "0.8.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"autoprefixer": "6.7.2",
|
||||
"babel-core": "6.22.1",
|
||||
"babel-eslint": "7.1.1",
|
||||
"babel-loader": "6.2.10",
|
||||
"babel-plugin-transform-runtime": "6.22.0",
|
||||
"babel-preset-es2015": "6.22.0",
|
||||
"babel-preset-stage-2": "6.22.0",
|
||||
"babel-register": "6.22.0",
|
||||
"autoprefixer": "7.1.1",
|
||||
"babel-core": "6.25.0",
|
||||
"babel-eslint": "7.2.3",
|
||||
"babel-loader": "7.0.0",
|
||||
"babel-plugin-transform-runtime": "6.23.0",
|
||||
"babel-preset-es2015": "6.24.1",
|
||||
"babel-preset-stage-2": "6.24.1",
|
||||
"babel-register": "6.24.1",
|
||||
"chalk": "1.1.3",
|
||||
"connect-history-api-fallback": "1.3.0",
|
||||
"copy-webpack-plugin": "4.0.1",
|
||||
"cross-env": "4.0.0",
|
||||
"css-loader": "0.28.0",
|
||||
"cross-env": "5.0.1",
|
||||
"css-loader": "0.28.4",
|
||||
"eslint": "3.19.0",
|
||||
"eslint-friendly-formatter": "2.0.7",
|
||||
"eslint-friendly-formatter": "3.0.0",
|
||||
"eslint-import-resolver-webpack": "0.8.1",
|
||||
"eslint-loader": "1.7.1",
|
||||
"eslint-plugin-html": "2.0.1",
|
||||
"eslint-plugin-import": "2.2.0",
|
||||
"eslint-plugin-html": "3.0.0",
|
||||
"eslint-plugin-import": "2.3.0",
|
||||
"eventsource-polyfill": "0.9.6",
|
||||
"express": "4.14.1",
|
||||
"extract-text-webpack-plugin": "2.0.0",
|
||||
"file-loader": "0.10.0",
|
||||
"friendly-errors-webpack-plugin": "1.1.3",
|
||||
"express": "4.15.3",
|
||||
"extract-text-webpack-plugin": "2.1.2",
|
||||
"file-loader": "0.11.2",
|
||||
"friendly-errors-webpack-plugin": "1.6.1",
|
||||
"function-bind": "1.1.0",
|
||||
"html-webpack-plugin": "2.28.0",
|
||||
"http-proxy-middleware": "0.17.3",
|
||||
"node-sass": "4.5.2",
|
||||
"http-proxy-middleware": "0.17.4",
|
||||
"node-sass": "^4.5.0",
|
||||
"opn": "4.0.2",
|
||||
"optimize-css-assets-webpack-plugin": "1.3.0",
|
||||
"ora": "1.1.0",
|
||||
@@ -74,13 +76,12 @@
|
||||
"semver": "5.3.0",
|
||||
"style-loader": "0.17.0",
|
||||
"url-loader": "0.5.8",
|
||||
"vue-loader": "12.0.4",
|
||||
"vue-style-loader": "2.0.5",
|
||||
"vue-loader": "12.2.1",
|
||||
"vue-style-loader": "3.0.1",
|
||||
"vue-template-compiler": "2.3.3",
|
||||
"webpack": "2.5.1",
|
||||
"webpack-bundle-analyzer": "2.2.1",
|
||||
"webpack-dashboard": "0.2.1",
|
||||
"webpack-dev-middleware": "1.10.0",
|
||||
"webpack": "2.6.1",
|
||||
"webpack-bundle-analyzer": "2.8.2",
|
||||
"webpack-dev-middleware": "1.10.2",
|
||||
"webpack-hot-middleware": "2.18.0",
|
||||
"webpack-merge": "4.1.0"
|
||||
},
|
||||
|
@@ -1,28 +1,8 @@
|
||||
// import fetch, { tpFetch } from 'utils/fetch';
|
||||
import fetch from 'utils/fetch';
|
||||
|
||||
// export function getToken() {
|
||||
// return fetch({
|
||||
// url: '/qiniu/upload/token',
|
||||
// method: 'get'
|
||||
// });
|
||||
// }
|
||||
// export function upload(data) {
|
||||
// return tpFetch({
|
||||
// url: 'https://upload.qbox.me',
|
||||
// method: 'post',
|
||||
// data
|
||||
// });
|
||||
// }
|
||||
|
||||
|
||||
// /* 外部uri转七牛uri*/
|
||||
// export function netUpload(token, net_url) {
|
||||
// const imgData = {
|
||||
// net_url
|
||||
// };
|
||||
// return fetch({
|
||||
// url: '/qiniu/upload/net/async',
|
||||
// method: 'post',
|
||||
// data: imgData
|
||||
// });
|
||||
// }
|
||||
export function getToken() {
|
||||
return fetch({
|
||||
url: '/qiniu/upload/token', // 假地址 自行替换
|
||||
method: 'get'
|
||||
});
|
||||
}
|
||||
|
@@ -51,7 +51,6 @@
|
||||
backgroundColor: '#344b58',
|
||||
title: {
|
||||
text: '统计',
|
||||
subtext: 'from http://gallery.echartsjs.com',
|
||||
x: '4%',
|
||||
textStyle: {
|
||||
color: '#fff',
|
||||
|
@@ -328,6 +328,7 @@
|
||||
// 关闭控件
|
||||
off() {
|
||||
this.show = false;
|
||||
this.$emit('close');
|
||||
},
|
||||
// 设置步骤
|
||||
setStep(step) {
|
||||
|
57
src/components/Screenfull/index.vue
Normal file
@@ -0,0 +1,57 @@
|
||||
<template>
|
||||
|
||||
<svg @click='click' class="icon screenfull" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" t="1497503607356" viewBox="0 0 1024 1024" version="1.1" p-id="4109" :fill='fill' :width="width" :height="height"><path d="M604.157933 512l204.484208 204.484208 82.942037-82.942037c10.364045-10.952446 26.498514-13.83817 40.309054-8.067746 13.249769 5.742794 22.465664 18.99154 22.465664 33.977859l0 258.042008c0 20.168342-16.695241 36.863582-36.863582 36.863582L659.452283 954.357873c-14.986319 0-28.236088-9.215896-33.977859-23.025413-5.770424-13.249769-2.885723-29.384237 8.067746-39.748283l82.942037-82.942037L512 604.157933 307.515792 808.642141l82.942037 82.942037c10.952446 10.364045 13.83817 26.498514 8.067746 39.748283-5.742794 13.809517-18.99154 23.025413-33.977859 23.025413L106.504686 954.357873c-20.168342 0-36.863582-16.695241-36.863582-36.863582L69.641103 659.452283c0-14.986319 9.215896-28.236088 23.025413-33.977859 13.249769-5.770424 29.384237-2.8847 39.748283 8.067746l82.942037 82.942037 204.484208-204.484208L215.357859 307.515792l-82.942037 82.942037c-6.890944 6.918573-16.10684 10.952446-25.911136 10.952446-4.593622 0-9.804297-1.14815-13.83817-2.8847-13.809517-5.742794-23.025413-18.99154-23.025413-33.977859L69.641103 106.504686c0-20.168342 16.695241-36.863582 36.863582-36.863582L364.546693 69.641103c14.986319 0 28.236088 9.215896 33.977859 23.025413 5.770424 13.249769 2.8847 29.384237-8.067746 39.748283l-82.942037 82.942037 204.484208 204.484208L716.484208 215.357859l-82.942037-82.942037c-10.952446-10.364045-13.83817-26.498514-8.067746-39.748283 5.742794-13.809517 18.99154-23.025413 33.977859-23.025413l258.042008 0c20.168342 0 36.863582 16.695241 36.863582 36.863582l0 258.042008c0 14.986319-9.215896 28.236088-22.465664 33.977859-4.593622 1.736551-9.804297 2.8847-14.397918 2.8847-9.804297 0-19.020192-4.033873-25.911136-10.952446l-82.942037-82.942037L604.157933 512z" p-id="4110"/></svg>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import screenfull from 'screenfull';
|
||||
export default {
|
||||
name: 'hamburger',
|
||||
props: {
|
||||
width: {
|
||||
type: Number,
|
||||
default: 22
|
||||
},
|
||||
height: {
|
||||
type: Number,
|
||||
default: 22
|
||||
},
|
||||
fill: {
|
||||
type: String,
|
||||
default: '#48576a'
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isFullscreen: false
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
click() {
|
||||
if (!screenfull.enabled) {
|
||||
this.$message({
|
||||
message: 'you browser can not work',
|
||||
type: 'warning'
|
||||
});
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this.isFullscreen) {
|
||||
screenfull.exit();
|
||||
this.isFullscreen = false;
|
||||
} else {
|
||||
screenfull.request();
|
||||
this.isFullscreen = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.screenfull {
|
||||
display: inline-block;
|
||||
cursor: pointer;
|
||||
vertical-align: -0.15em;
|
||||
}
|
||||
</style>
|
@@ -1,119 +0,0 @@
|
||||
<template>
|
||||
<div class="upload-container">
|
||||
<el-button :style="{background:color,borderColor:color}" @click=" dialogVisible=true" type="primary">上传音频
|
||||
</el-button>
|
||||
<el-dialog v-model="dialogVisible">
|
||||
<el-form ref="form" :model="form" :rules="rules" label-width="100px" label-position="right">
|
||||
<el-upload
|
||||
class="editor-audio-upload"
|
||||
action="https://upload.qbox.me"
|
||||
:data="dataObj"
|
||||
:show-file-list="true"
|
||||
:file-list="audioList"
|
||||
:on-success="handleAudioScucess"
|
||||
:on-change="handleAudioChange"
|
||||
:before-upload="audioBeforeUpload">
|
||||
<el-button size="small" type="primary">上传音频</el-button>
|
||||
</el-upload>
|
||||
<el-form-item prop="url" label="音频URL">
|
||||
<el-input v-model="form.url"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item prop="title" label="音频标题">
|
||||
<el-input v-model="form.title"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="音频文本">
|
||||
<el-input type="textarea" :autosize="{ minRows: 2}" v-model="form.text"></el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<el-button @click="dialogVisible = false">取 消</el-button>
|
||||
<el-button type="primary" @click="handleSubmit">确 定</el-button>
|
||||
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import { getToken } from 'api/qiniu';
|
||||
|
||||
export default {
|
||||
name: 'editorAudioUpload',
|
||||
props: {
|
||||
color: {
|
||||
type: String,
|
||||
default: '#20a0ff'
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
dialogVisible: false,
|
||||
dataObj: { token: '', key: '' },
|
||||
audioList: [],
|
||||
tempAudioUrl: '',
|
||||
form: {
|
||||
title: '',
|
||||
url: '',
|
||||
text: ''
|
||||
},
|
||||
rules: {
|
||||
title: [
|
||||
{ required: true, trigger: 'blur' }
|
||||
],
|
||||
url: [
|
||||
{ required: true, trigger: 'blur' }
|
||||
]
|
||||
}
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
handleSubmit() {
|
||||
this.$refs.form.validate(valid => {
|
||||
if (valid) {
|
||||
this.$emit('successCBK', this.form);
|
||||
this.dialogVisible = false;
|
||||
this.form = {
|
||||
title: '',
|
||||
url: '',
|
||||
text: ''
|
||||
}
|
||||
} else {
|
||||
this.$message('填写有误');
|
||||
return false;
|
||||
}
|
||||
});
|
||||
},
|
||||
handleAudioChange(file, fileList) {
|
||||
this.audioList = fileList.slice(-1);
|
||||
},
|
||||
handleAudioScucess() {
|
||||
this.form.url = this.tempAudioUrl
|
||||
},
|
||||
audioBeforeUpload() {
|
||||
const _self = this;
|
||||
return new Promise((resolve, reject) => {
|
||||
getToken().then(response => {
|
||||
const key = response.data.qiniu_key;
|
||||
const token = response.data.qiniu_token;
|
||||
_self._data.dataObj.token = token;
|
||||
_self._data.dataObj.key = key;
|
||||
this.tempAudioUrl = response.data.qiniu_url;
|
||||
resolve(true);
|
||||
}).catch(err => {
|
||||
console.log(err);
|
||||
reject(false)
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style rel="stylesheet/scss" lang="scss" scoped>
|
||||
.upload-container {
|
||||
.editor-audio-upload {
|
||||
button {
|
||||
float: left;
|
||||
margin-left: 30px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
@@ -1,88 +0,0 @@
|
||||
<template>
|
||||
<div class="upload-container">
|
||||
<el-button icon='upload' :style="{background:color,borderColor:color}" @click=" dialogVisible=true" type="primary">上传图片
|
||||
</el-button>
|
||||
<el-dialog v-model="dialogVisible">
|
||||
<el-upload
|
||||
class="editor-slide-upload"
|
||||
action="https://httpbin.org/post"
|
||||
:data="dataObj"
|
||||
:multiple="true"
|
||||
:file-list="fileList"
|
||||
:show-file-list="true"
|
||||
list-type="picture-card"
|
||||
:on-remove="handleRemove"
|
||||
:on-success="handleImageScucess">
|
||||
<el-button size="small" type="primary">点击上传</el-button>
|
||||
</el-upload>
|
||||
<el-button @click="dialogVisible = false">取 消</el-button>
|
||||
<el-button type="primary" @click="handleSubmit">确 定</el-button>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import { getToken } from 'api/qiniu';
|
||||
|
||||
export default {
|
||||
name: 'editorSlideUpload',
|
||||
props: {
|
||||
color: {
|
||||
type: String,
|
||||
default: '#20a0ff'
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
dialogVisible: false,
|
||||
dataObj: { token: '', key: '' },
|
||||
list: [],
|
||||
fileList: []
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
handleSubmit() {
|
||||
const arr = this.list.map(v => v.url);
|
||||
this.$emit('successCBK', arr);
|
||||
this.list = [];
|
||||
this.fileList = [];
|
||||
this.dialogVisible = false;
|
||||
},
|
||||
handleRemove(file) {
|
||||
const key = file.response.key;
|
||||
for (let i = 0, len = this.list.length; i < len; i++) {
|
||||
if (this.list[i].key === key) {
|
||||
this.list.splice(i, 1);
|
||||
return
|
||||
}
|
||||
}
|
||||
},
|
||||
handleImageScucess(file) {
|
||||
this.list.push({ url: file.files.file });
|
||||
},
|
||||
beforeUpload() {
|
||||
const _self = this;
|
||||
return new Promise((resolve, reject) => {
|
||||
getToken().then(response => {
|
||||
const key = response.data.qiniu_key;
|
||||
const token = response.data.qiniu_token;
|
||||
_self._data.dataObj.token = token;
|
||||
_self._data.dataObj.key = key;
|
||||
this.list.push({ key, url: response.data.qiniu_url });
|
||||
resolve(true);
|
||||
}).catch(err => {
|
||||
console.log(err);
|
||||
reject(false)
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style rel="stylesheet/scss" lang="scss" scoped>
|
||||
.upload-container {
|
||||
.editor-slide-upload {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
}
|
||||
</style>
|
@@ -1,82 +0,0 @@
|
||||
<template>
|
||||
<div class="upload-container">
|
||||
<el-button :style="{background:color,borderColor:color}" @click=" dialogVisible=true" type="primary">上传轮播图
|
||||
</el-button>
|
||||
<el-dialog v-model="dialogVisible">
|
||||
<el-upload
|
||||
class="editor-slide-upload"
|
||||
action="https://upload.qbox.me"
|
||||
:data="dataObj"
|
||||
:multiple="true"
|
||||
:show-file-list="true"
|
||||
list-type="picture-card"
|
||||
:on-remove="handleRemove"
|
||||
:before-upload="beforeUpload">
|
||||
<el-button size="small" type="primary">点击上传</el-button>
|
||||
</el-upload>
|
||||
<el-button @click="dialogVisible = false">取 消</el-button>
|
||||
<el-button type="primary" @click="handleSubmit">确 定</el-button>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import { getToken } from 'api/qiniu';
|
||||
|
||||
export default {
|
||||
name: 'editorSlideUpload',
|
||||
props: {
|
||||
color: {
|
||||
type: String,
|
||||
default: '#20a0ff'
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
dialogVisible: false,
|
||||
dataObj: { token: '', key: '' },
|
||||
list: []
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
handleSubmit() {
|
||||
const arr = this.list.map(v => v.url);
|
||||
this.$emit('successCBK', arr);
|
||||
this.list = [];
|
||||
this.dialogVisible = false;
|
||||
},
|
||||
handleRemove(file) {
|
||||
const key = file.response.key;
|
||||
for (let i = 0, len = this.list.length; i < len; i++) {
|
||||
if (this.list[i].key === key) {
|
||||
this.list.splice(i, 1);
|
||||
return
|
||||
}
|
||||
}
|
||||
},
|
||||
beforeUpload() {
|
||||
const _self = this;
|
||||
return new Promise((resolve, reject) => {
|
||||
getToken().then(response => {
|
||||
const key = response.data.qiniu_key;
|
||||
const token = response.data.qiniu_token;
|
||||
_self._data.dataObj.token = token;
|
||||
_self._data.dataObj.key = key;
|
||||
this.list.push({ key, url: response.data.qiniu_url });
|
||||
resolve(true);
|
||||
}).catch(err => {
|
||||
console.log(err);
|
||||
reject(false)
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style rel="stylesheet/scss" lang="scss" scoped>
|
||||
.upload-container {
|
||||
.editor-slide-upload {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
}
|
||||
</style>
|
@@ -1,167 +0,0 @@
|
||||
<template>
|
||||
<div class="upload-container">
|
||||
<el-button :style="{background:color,borderColor:color}" @click=" dialogVisible=true" type="primary">上传视频</el-button>
|
||||
<el-dialog v-model="dialogVisible">
|
||||
<el-form ref="form" :model="form" :rules="rules" label-width="140px" label-position="left">
|
||||
<el-upload
|
||||
class="editor-video-upload"
|
||||
action="https://upload.qbox.me"
|
||||
:data="dataObj"
|
||||
:show-file-list="true"
|
||||
:file-list="videoList"
|
||||
:on-success="handleVideoScucess"
|
||||
:on-change="handleVideoChange"
|
||||
:before-upload="videoBeforeUpload">
|
||||
<el-button size="small" type="primary">上传视频</el-button>
|
||||
</el-upload>
|
||||
<el-form-item prop="url" label="视频URL">
|
||||
<el-input v-model="form.url"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item prop="title" label="视频标题">
|
||||
<el-input v-model="form.title"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="上传视频封面图">
|
||||
</el-form-item>
|
||||
<el-upload
|
||||
class="image-uploader"
|
||||
action="https://upload.qbox.me"
|
||||
:show-file-list="false"
|
||||
:data="dataObj"
|
||||
:on-success="handleImageScucess"
|
||||
:before-upload="beforeImageUpload">
|
||||
<img v-if="form.image" :src="form.image" class="image-uploader-image">
|
||||
<i v-else class="el-icon-plus avatar-uploader-icon"></i>
|
||||
</el-upload>
|
||||
</el-form>
|
||||
<el-button @click="dialogVisible = false">取 消</el-button>
|
||||
<el-button type="primary" @click="handleSubmit">确 定</el-button>
|
||||
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import { getToken } from 'api/qiniu';
|
||||
|
||||
export default {
|
||||
name: 'editorVideoUpload',
|
||||
props: {
|
||||
color: {
|
||||
type: String,
|
||||
default: '#20a0ff'
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
dialogVisible: false,
|
||||
dataObj: { token: '', key: '' },
|
||||
videoList: [],
|
||||
tempVideoUrl: '',
|
||||
tempImageUrl: '',
|
||||
form: {
|
||||
title: '',
|
||||
url: '',
|
||||
image: ''
|
||||
},
|
||||
rules: {
|
||||
url: [
|
||||
{ required: true, trigger: 'blur' }
|
||||
],
|
||||
title: [
|
||||
{ required: true, trigger: 'blur' }
|
||||
]
|
||||
}
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
handleSubmit() {
|
||||
this.$refs.form.validate(valid => {
|
||||
if (valid) {
|
||||
if (this.form.image.length > 0) {
|
||||
this.$emit('successCBK', this.form);
|
||||
this.dialogVisible = false;
|
||||
this.form = {
|
||||
title: '',
|
||||
url: '',
|
||||
image: ''
|
||||
}
|
||||
} else {
|
||||
this.$message('请上传图片');
|
||||
}
|
||||
} else {
|
||||
this.$message('填写有误');
|
||||
return false;
|
||||
}
|
||||
});
|
||||
},
|
||||
handleVideoChange(file, fileList) {
|
||||
this.videoList = fileList.slice(-1);
|
||||
},
|
||||
handleVideoScucess() {
|
||||
this.form.url = this.tempVideoUrl
|
||||
},
|
||||
videoBeforeUpload() {
|
||||
const _self = this;
|
||||
return new Promise((resolve, reject) => {
|
||||
getToken().then(response => {
|
||||
const key = response.data.qiniu_key;
|
||||
const token = response.data.qiniu_token;
|
||||
_self._data.dataObj.token = token;
|
||||
_self._data.dataObj.key = key;
|
||||
this.tempVideoUrl = response.data.qiniu_url;
|
||||
resolve(true);
|
||||
}).catch(err => {
|
||||
console.log(err);
|
||||
reject(false)
|
||||
});
|
||||
});
|
||||
},
|
||||
handleImageScucess() {
|
||||
this.form.image = this.tempImageUrl
|
||||
},
|
||||
beforeImageUpload() {
|
||||
const _self = this;
|
||||
return new Promise((resolve, reject) => {
|
||||
getToken().then(response => {
|
||||
const key = response.data.qiniu_key;
|
||||
const token = response.data.qiniu_token;
|
||||
_self._data.dataObj.token = token;
|
||||
_self._data.dataObj.key = key;
|
||||
this.tempImageUrl = response.data.qiniu_url;
|
||||
resolve(true);
|
||||
}).catch(err => {
|
||||
console.log(err);
|
||||
reject(false)
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style rel="stylesheet/scss" lang="scss" scoped>
|
||||
.upload-container {
|
||||
.editor-video-upload {
|
||||
button {
|
||||
float: left;
|
||||
}
|
||||
}
|
||||
.image-uploader {
|
||||
margin: 5px auto;
|
||||
width: 400px;
|
||||
height: 200px;
|
||||
border: 1px dashed #d9d9d9;
|
||||
border-radius: 6px;
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
line-height: 200px;
|
||||
i {
|
||||
font-size: 28px;
|
||||
color: #8c939d;
|
||||
}
|
||||
.image-uploader-image {
|
||||
height: 200px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
@@ -1,29 +1,13 @@
|
||||
<template>
|
||||
<div class='tinymce-container editor-container'>
|
||||
<textarea class='tinymce-textarea' :id="id"></textarea>
|
||||
<!--业务需求可删除-->
|
||||
<div class="editor-custom-btn-container">
|
||||
<editorSlide v-if="customButton.indexOf('editorSlide')>=0" color="#3A71A8" class="editor-upload-btn" @successCBK="slideSuccessCBK"></editorSlide>
|
||||
<editorAudio v-if="customButton.indexOf('editorAudio')>=0" color="#30B08F" class="editor-upload-btn" @successCBK="aduioSuccessCBK"></editorAudio>
|
||||
<editorVideo v-if="customButton.indexOf('editorVideo')>=0" color="#E65D6E" class="editor-upload-btn" @successCBK="videoSuccessCBK"></editorVideo>
|
||||
<editorImage v-if="customButton.indexOf('editorImage')>=0" color="#20a0ff" class="editor-upload-btn" @successCBK="imageSuccessCBK"></editorImage>
|
||||
<!--业务需求可删除-->
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
// tinymce 在最外层目录static下 ,由index.html直接引入,挂载在window下。不通过impot,不打包
|
||||
// 业务需求可删除
|
||||
import editorAudio from './components/editorAudio';
|
||||
import editorVideo from './components/editorVideo';
|
||||
import editorSlide from './components/editorSlide';
|
||||
import editorImage from './components/editorImage';
|
||||
// import { getToken, upload } from 'api/qiniu'; // 七牛
|
||||
// 业务需求可删除
|
||||
export default {
|
||||
name: 'tinymce',
|
||||
components: { editorImage, editorAudio, editorSlide, editorVideo }, // 业务需求可删除
|
||||
props: {
|
||||
id: {
|
||||
type: String,
|
||||
@@ -33,13 +17,6 @@
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
customButton: {
|
||||
type: Array,
|
||||
required: false,
|
||||
default() {
|
||||
return ['editorAudio', 'editorImage']
|
||||
}
|
||||
},
|
||||
toolbar: {
|
||||
type: Array,
|
||||
required: false,
|
||||
@@ -92,15 +69,12 @@
|
||||
imagetools_toolbar: 'watermark',
|
||||
default_link_target: '_blank',
|
||||
link_title: false,
|
||||
textcolor_map: [
|
||||
'1482f0', '1482f0',
|
||||
'4595e6', '4595e6'],
|
||||
init_instance_callback: editor => {
|
||||
if (_this.value) {
|
||||
editor.setContent(_this.value)
|
||||
}
|
||||
_this.hasInit = true;
|
||||
editor.on('Change', () => {
|
||||
editor.on('NodeChange Change KeyUp', () => {
|
||||
this.hasChange = true;
|
||||
this.$emit('input', editor.getContent({ format: 'raw' }));
|
||||
});
|
||||
@@ -172,55 +146,6 @@
|
||||
}
|
||||
});
|
||||
},
|
||||
methods: {
|
||||
/* 业务代码可删除 start*/
|
||||
imageSuccessCBK(arr) {
|
||||
console.log(arr)
|
||||
const _this = this;
|
||||
arr.forEach(v => {
|
||||
const node = document.createElement('img');
|
||||
node.setAttribute('src', v);
|
||||
node.onload = function() {
|
||||
$(this).addClass('wscnph');
|
||||
$(this).attr('data-wscntype', 'image');
|
||||
$(this).attr('data-wscnh', this.height);
|
||||
$(this).attr('data-wscnw', this.width);
|
||||
tinymce.get(_this.id).insertContent(node.outerHTML)
|
||||
}
|
||||
})
|
||||
},
|
||||
slideSuccessCBK(arr) {
|
||||
const node = document.createElement('img');
|
||||
node.setAttribute('data-wscntype', 'slide');
|
||||
node.setAttribute('data-uri', arr.toString());
|
||||
node.setAttribute('data-wscnh', '190');
|
||||
node.setAttribute('data-wscnw', '200');
|
||||
node.setAttribute('src', ' https://wdl.wallstreetcn.com/6410b47d-a54c-4826-9bc1-c3e5df31280c');
|
||||
node.className = 'wscnph editor-placeholder';
|
||||
tinymce.get(this.id).insertContent(node.outerHTML)
|
||||
},
|
||||
videoSuccessCBK(form) {
|
||||
const node = document.createElement('img');
|
||||
node.setAttribute('data-wscntype', 'video');
|
||||
node.setAttribute('data-uri', form.url);
|
||||
node.setAttribute('data-cover-img-uri', form.image);
|
||||
node.setAttribute('data-title', form.title);
|
||||
node.setAttribute('src', 'https://wdl.wallstreetcn.com/07aeb3e7-f4ca-4207-befb-c987b3dc7011');
|
||||
node.className = 'wscnph editor-placeholder';
|
||||
tinymce.get(this.id).insertContent(node.outerHTML)
|
||||
},
|
||||
aduioSuccessCBK(form) {
|
||||
const node = document.createElement('img');
|
||||
node.setAttribute('data-wscntype', 'audio');
|
||||
node.setAttribute('data-uri', form.url);
|
||||
node.setAttribute('data-title', form.title);
|
||||
node.setAttribute('data-text', form.text);
|
||||
node.setAttribute('src', 'https://wdl.wallstreetcn.com/2ed0c8c8-fb82-499d-b81c-3fd1de114eae');
|
||||
node.className = 'wscnph editor-placeholder';
|
||||
tinymce.get(this.id).insertContent(node.outerHTML)
|
||||
}
|
||||
/* 业务代码可删除 end*/
|
||||
},
|
||||
destroyed() {
|
||||
tinymce.get(this.id).destroy();
|
||||
}
|
||||
@@ -240,7 +165,6 @@
|
||||
.editor-custom-btn-container {
|
||||
position: absolute;
|
||||
right: 15px;
|
||||
/*z-index: 2005;*/
|
||||
top: 18px;
|
||||
}
|
||||
|
||||
|
@@ -13,7 +13,7 @@ for (let i = 0; i < count; i++) {
|
||||
title: '@ctitle(10, 20)',
|
||||
forecast: '@float(0, 100, 2, 2)',
|
||||
importance: '@integer(1, 3)',
|
||||
'type|1': ['FD', 'FE', 'BI', 'VN'],
|
||||
'type|1': ['CN', 'US', 'JP', 'EU'],
|
||||
'status|1': ['published', 'draft', 'deleted'],
|
||||
pageviews: '@integer(300, 5000)'
|
||||
}));
|
||||
|
@@ -5,7 +5,7 @@ const userMap = {
|
||||
role: ['admin'],
|
||||
token: 'admin',
|
||||
introduction: '我是超级管理员',
|
||||
avatar: 'https://wdl.wallstreetcn.com/48a3e1e0-ea2c-4a4e-9928-247645e3428b',
|
||||
avatar: 'https://wpimg.wallstcn.com/f778738c-e4f8-4870-b634-56703b4acafe.gif',
|
||||
name: '超级管理员小潘',
|
||||
uid: '001'
|
||||
},
|
||||
@@ -13,7 +13,7 @@ const userMap = {
|
||||
role: ['editor'],
|
||||
token: 'editor',
|
||||
introduction: '我是编辑',
|
||||
avatar: 'https://wdl.wallstreetcn.com/48a3e1e0-ea2c-4a4e-9928-247645e3428b',
|
||||
avatar: 'https://wpimg.wallstcn.com/f778738c-e4f8-4870-b634-56703b4acafe.gif',
|
||||
name: '普通编辑小张',
|
||||
uid: '002'
|
||||
|
||||
@@ -22,7 +22,7 @@ const userMap = {
|
||||
role: ['develop'],
|
||||
token: 'develop',
|
||||
introduction: '我是开发',
|
||||
avatar: 'https://wdl.wallstreetcn.com/48a3e1e0-ea2c-4a4e-9928-247645e3428b',
|
||||
avatar: 'https://wpimg.wallstcn.com/f778738c-e4f8-4870-b634-56703b4acafe.gif',
|
||||
name: '工程师小王',
|
||||
uid: '003'
|
||||
}
|
||||
|
@@ -1,64 +1,67 @@
|
||||
import Vue from 'vue';
|
||||
import Router from 'vue-router';
|
||||
|
||||
/* layout*/
|
||||
/* layout */
|
||||
import Layout from '../views/layout/Layout';
|
||||
|
||||
// dashboard
|
||||
const dashboard = resolve => require(['../views/dashboard/index'], resolve);
|
||||
|
||||
/* error page*/
|
||||
const Err404 = resolve => require(['../views/error/404'], resolve);
|
||||
const Err401 = resolve => require(['../views/error/401'], resolve);
|
||||
|
||||
/* login*/
|
||||
/* login */
|
||||
import Login from '../views/login/';
|
||||
import authRedirect from '../views/login/authredirect';
|
||||
import sendPWD from '../views/login/sendpwd';
|
||||
import reset from '../views/login/reset';
|
||||
const authRedirect = () => import('../views/login/authredirect');
|
||||
const sendPWD = () => import('../views/login/sendpwd');
|
||||
const reset = () => import('../views/login/reset');
|
||||
|
||||
/* Introduction*/
|
||||
const Introduction = resolve => require(['../views/introduction/index'], resolve);
|
||||
/* dashboard */
|
||||
const dashboard = () => import('../views/dashboard/index');
|
||||
|
||||
/* components*/
|
||||
const componentsIndex = resolve => require(['../views/components/index'], resolve);
|
||||
const Tinymce = resolve => require(['../views/components/tinymce'], resolve);
|
||||
const Markdown = resolve => require(['../views/components/markdown'], resolve);
|
||||
const JsonEditor = resolve => require(['../views/components/jsoneditor'], resolve);
|
||||
const DndList = resolve => require(['../views/components/dndlist'], resolve);
|
||||
const AvatarUpload = resolve => require(['../views/components/avatarUpload'], resolve);
|
||||
const Dropzone = resolve => require(['../views/components/dropzone'], resolve);
|
||||
const Sticky = resolve => require(['../views/components/sticky'], resolve);
|
||||
const SplitPane = resolve => require(['../views/components/splitpane'], resolve);
|
||||
const CountTo = resolve => require(['../views/components/countTo'], resolve);
|
||||
const Mixin = resolve => require(['../views/components/mixin'], resolve);
|
||||
/* Introduction */
|
||||
const Introduction = () => import('../views/introduction/index');
|
||||
|
||||
/* components */
|
||||
const componentsIndex = () => import('../views/components/index');
|
||||
const Tinymce = () => import('../views/components/tinymce');
|
||||
const Markdown = () => import('../views/components/markdown');
|
||||
const JsonEditor = () => import('../views/components/jsoneditor');
|
||||
const DndList = () => import('../views/components/dndlist');
|
||||
const AvatarUpload = () => import('../views/components/avatarUpload');
|
||||
const Dropzone = () => import('../views/components/dropzone');
|
||||
const Sticky = () => import('../views/components/sticky');
|
||||
const SplitPane = () => import('../views/components/splitpane');
|
||||
const CountTo = () => import('../views/components/countTo');
|
||||
const Mixin = () => import('../views/components/mixin');
|
||||
|
||||
|
||||
/* charts*/
|
||||
const chartIndex = resolve => require(['../views/charts/index'], resolve);
|
||||
const KeyboardChart = resolve => require(['../views/charts/keyboard'], resolve);
|
||||
const KeyboardChart2 = resolve => require(['../views/charts/keyboard2'], resolve);
|
||||
const LineMarker = resolve => require(['../views/charts/line'], resolve);
|
||||
const MixChart = resolve => require(['../views/charts/mixchart'], resolve);
|
||||
/* charts */
|
||||
const chartIndex = () => import('../views/charts/index');
|
||||
const KeyboardChart = () => import('../views/charts/keyboard');
|
||||
const KeyboardChart2 = () => import('../views/charts/keyboard2');
|
||||
const LineMarker = () => import('../views/charts/line');
|
||||
const MixChart = () => import('../views/charts/mixchart');
|
||||
|
||||
/* error log*/
|
||||
const ErrorLog = resolve => require(['../views/errlog/index'], resolve);
|
||||
/* error page */
|
||||
const Err404 = () => import('../views/error/404');
|
||||
const Err401 = () => import('../views/error/401');
|
||||
|
||||
/* excel*/
|
||||
const ExcelDownload = resolve => require(['../views/excel/index'], resolve);
|
||||
/* error log */
|
||||
const ErrorLog = () => import('../views/errlog/index');
|
||||
|
||||
/* theme*/
|
||||
const Theme = resolve => require(['../views/theme/index'], resolve);
|
||||
/* excel */
|
||||
const ExcelDownload = () => import('../views/excel/index');
|
||||
|
||||
/* theme */
|
||||
const Theme = () => import('../views/theme/index');
|
||||
|
||||
/* example*/
|
||||
const DynamicTable = resolve => require(['../views/example/dynamictable'], resolve);
|
||||
const Table = resolve => require(['../views/example/table'], resolve);
|
||||
const DragTable = resolve => require(['../views/example/dragTable'], resolve);
|
||||
const InlineEditTable = resolve => require(['../views/example/inlineEditTable'], resolve);
|
||||
const Form1 = resolve => require(['../views/example/form1'], resolve);
|
||||
const TableLayout = () => import('../views/example/table/index');
|
||||
const DynamicTable = () => import('../views/example/table/dynamictable');
|
||||
const Table = () => import('../views/example/table/table');
|
||||
const DragTable = () => import('../views/example/table/dragTable');
|
||||
const InlineEditTable = () => import('../views/example/table/inlineEditTable');
|
||||
|
||||
const Form = () => import('../views/example/form');
|
||||
const Tab = () => import('../views/example/tab/index');
|
||||
|
||||
/* permission */
|
||||
const Permission = resolve => require(['../views/permission/index'], resolve);
|
||||
const Permission = () => import('../views/permission/index');
|
||||
|
||||
|
||||
Vue.use(Router);
|
||||
@@ -69,7 +72,7 @@ Vue.use(Router);
|
||||
* 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
|
||||
*/
|
||||
**/
|
||||
|
||||
export const constantRouterMap = [
|
||||
{ path: '/login', component: Login, hidden: true },
|
||||
@@ -120,17 +123,17 @@ export const asyncRouterMap = [
|
||||
name: '组件',
|
||||
icon: 'zujian',
|
||||
children: [
|
||||
{ path: 'index', component: componentsIndex, name: '介绍 ' },
|
||||
{ path: 'tinymce', component: Tinymce, name: '富文本编辑器' },
|
||||
{ path: 'markdown', component: Markdown, name: 'Markdown' },
|
||||
{ path: 'jsoneditor', component: JsonEditor, name: 'JSON编辑器' },
|
||||
{ path: 'dndlist', component: DndList, name: '列表拖拽' },
|
||||
{ path: 'splitpane', component: SplitPane, name: 'SplitPane' },
|
||||
{ path: 'avatarupload', component: AvatarUpload, name: '头像上传' },
|
||||
{ path: 'dropzone', component: Dropzone, name: 'Dropzone' },
|
||||
{ path: 'sticky', component: Sticky, name: 'Sticky' },
|
||||
{ path: 'countto', component: CountTo, name: 'CountTo' },
|
||||
{ path: 'mixin', component: Mixin, name: '小组件' }
|
||||
{ path: 'index', component: componentsIndex, name: '介绍 ' },
|
||||
{ path: 'tinymce', component: Tinymce, name: '富文本编辑器' },
|
||||
{ path: 'markdown', component: Markdown, name: 'Markdown' },
|
||||
{ path: 'jsoneditor', component: JsonEditor, name: 'JSON编辑器' },
|
||||
{ path: 'dndlist', component: DndList, name: '列表拖拽' },
|
||||
{ path: 'splitpane', component: SplitPane, name: 'SplitPane' },
|
||||
{ path: 'avatarupload', component: AvatarUpload, name: '头像上传' },
|
||||
{ path: 'dropzone', component: Dropzone, name: 'Dropzone' },
|
||||
{ path: 'sticky', component: Sticky, name: 'Sticky' },
|
||||
{ path: 'countto', component: CountTo, name: 'CountTo' },
|
||||
{ path: 'mixin', component: Mixin, name: '小组件' }
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -140,11 +143,11 @@ export const asyncRouterMap = [
|
||||
name: '图表',
|
||||
icon: 'tubiaoleixingzhengchang',
|
||||
children: [
|
||||
{ path: 'index', component: chartIndex, name: '介绍' },
|
||||
{ path: 'keyboard', component: KeyboardChart, name: '键盘图表' },
|
||||
{ path: 'keyboard2', component: KeyboardChart2, name: '键盘图表2' },
|
||||
{ path: 'line', component: LineMarker, name: '折线图' },
|
||||
{ path: 'mixchart', component: MixChart, name: '混合图表' }
|
||||
{ path: 'index', component: chartIndex, name: '介绍' },
|
||||
{ path: 'keyboard', component: KeyboardChart, name: '键盘图表' },
|
||||
{ path: 'keyboard2', component: KeyboardChart2, name: '键盘图表2' },
|
||||
{ path: 'line', component: LineMarker, name: '折线图' },
|
||||
{ path: 'mixchart', component: MixChart, name: '混合图表' }
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -154,8 +157,8 @@ export const asyncRouterMap = [
|
||||
name: '错误页面',
|
||||
icon: '404',
|
||||
children: [
|
||||
{ path: '401', component: Err401, name: '401' },
|
||||
{ path: '404', component: Err404, name: '404' }
|
||||
{ path: '401', component: Err401, name: '401' },
|
||||
{ path: '404', component: Err404, name: '404' }
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -192,11 +195,22 @@ export const asyncRouterMap = [
|
||||
name: '综合实例',
|
||||
icon: 'zonghe',
|
||||
children: [
|
||||
{ path: 'dynamictable', component: DynamicTable, name: '动态table' },
|
||||
{ path: 'dragtable', component: DragTable, name: '拖拽table' },
|
||||
{ path: 'inline_edit_table', component: InlineEditTable, name: 'table内编辑' },
|
||||
{ path: 'table', component: Table, name: '综合table' },
|
||||
{ path: 'form1', component: Form1, name: '综合form1' }
|
||||
{
|
||||
path: '/table',
|
||||
component: TableLayout,
|
||||
redirect: '/table/table',
|
||||
name: 'Table',
|
||||
children: [
|
||||
{ path: 'dynamictable', component: DynamicTable, name: '动态table' },
|
||||
{ path: 'dragtable', component: DragTable, name: '拖拽table' },
|
||||
{ path: 'inline_edit_table', component: InlineEditTable, name: 'table内编辑' },
|
||||
{ path: 'table', component: Table, name: '综合table' }
|
||||
]
|
||||
},
|
||||
{ path: 'form/edit', component: Form, name: '编辑Form', meta: { isEdit: true } },
|
||||
{ path: 'form/create', component: Form, name: '创建Form' },
|
||||
|
||||
{ path: 'tab/index', component: Tab, name: 'Tab' }
|
||||
]
|
||||
},
|
||||
{ path: '*', redirect: '/404', hidden: true }
|
||||
|
@@ -132,6 +132,16 @@ const user = {
|
||||
Cookies.remove('Admin-Token');
|
||||
resolve();
|
||||
});
|
||||
},
|
||||
|
||||
// 动态修改权限
|
||||
ChangeRole({ commit }, role) {
|
||||
return new Promise(resolve => {
|
||||
commit('SET_ROLES', [role]);
|
||||
commit('SET_TOKEN', role);
|
||||
Cookies.set('Admin-Token', role);
|
||||
resolve();
|
||||
})
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div class="components-container" >
|
||||
<code>
|
||||
这里的所有的图表都基于echarts,实例代码来源<a href='http://gallery.echartsjs.com/explore.html#sort=rank~timeframe=all~author=all' target='_blank'>gallery</a><br/>其实echarts封装的很好了,用vue封装是很简单的事情,建议大家自己来封装。
|
||||
这里的所有的图表都基于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>
|
||||
</div>
|
||||
</template>
|
||||
|
@@ -1,14 +1,13 @@
|
||||
<template>
|
||||
<div class="components-container" style='height:100vh'>
|
||||
<div class='chart-container'>
|
||||
<keyboardChart height='100%' width='100%' />
|
||||
<keyboardChart height='100%' width='100%' />
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import keyboardChart from 'components/Charts/keyboard';
|
||||
|
||||
export default {
|
||||
components: { keyboardChart }
|
||||
};
|
||||
@@ -16,9 +15,9 @@
|
||||
|
||||
<style scoped>
|
||||
.chart-container{
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 90%;
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 90%;
|
||||
}
|
||||
</style>
|
||||
|
||||
|
@@ -1,14 +1,13 @@
|
||||
<template>
|
||||
<div class="components-container" style='height:100vh'>
|
||||
<div class='chart-container'>
|
||||
<keyboardChart2 id='apple' height='100%' width='100%' />
|
||||
<keyboardChart2 id='apple' height='100%' width='100%' />
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import keyboardChart2 from 'components/Charts/keyboard2';
|
||||
|
||||
export default {
|
||||
components: { keyboardChart2 }
|
||||
};
|
||||
@@ -16,9 +15,9 @@
|
||||
|
||||
<style scoped>
|
||||
.chart-container{
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 90%;
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 90%;
|
||||
}
|
||||
</style>
|
||||
|
||||
|
@@ -1,16 +1,13 @@
|
||||
<template>
|
||||
<div class="components-container" style='height:100vh'>
|
||||
https://github.com/ecomfe/echarts/blob/master/index.js
|
||||
http://echarts.baidu.com/tutorial.html
|
||||
<div class='chart-container'>
|
||||
<lineMarker height='100%' width='100%' />
|
||||
<lineMarker height='100%' width='100%' />
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import lineMarker from 'components/Charts/lineMarker';
|
||||
|
||||
export default {
|
||||
components: { lineMarker }
|
||||
};
|
||||
@@ -18,9 +15,9 @@
|
||||
|
||||
<style scoped>
|
||||
.chart-container{
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 80%;
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 80%;
|
||||
}
|
||||
</style>
|
||||
|
||||
|
@@ -1,14 +1,13 @@
|
||||
<template>
|
||||
<div class="components-container" style='height:100vh'>
|
||||
<div class='chart-container'>
|
||||
<mixchart id='apple' height='100%' width='100%' />
|
||||
<mixchart id='apple' height='100%' width='100%' />
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import mixchart from 'components/Charts/mixchart';
|
||||
|
||||
export default {
|
||||
components: { mixchart }
|
||||
};
|
||||
@@ -16,10 +15,10 @@
|
||||
|
||||
<style scoped>
|
||||
.chart-container{
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 90%;
|
||||
padding-bottom: 40px;
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 90%;
|
||||
padding-bottom: 40px;
|
||||
}
|
||||
</style>
|
||||
|
||||
|
@@ -9,9 +9,11 @@
|
||||
<el-button type="primary" icon="upload" style="position: absolute;bottom: 15px;margin-left: 40px;" @click="imagecropperShow=true">修改头像
|
||||
</el-button>
|
||||
|
||||
<ImageCropper :width="300" :height="300" url="https://httpbin.org/post" @crop-upload-success="cropSuccess" :key="imagecropperKey" v-show="imagecropperShow" />
|
||||
<ImageCropper :width="300" :height="300" url="https://httpbin.org/post" @close='close' @crop-upload-success="cropSuccess"
|
||||
:key="imagecropperKey" v-show="imagecropperShow" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import ImageCropper from 'components/ImageCropper';
|
||||
import PanThumb from 'components/PanThumb';
|
||||
@@ -29,6 +31,9 @@
|
||||
this.imagecropperShow = false;
|
||||
this.imagecropperKey = this.imagecropperKey + 1;
|
||||
this.image = resData.files.avatar;
|
||||
},
|
||||
close() {
|
||||
this.imagecropperShow = false;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@@ -1,8 +1,8 @@
|
||||
<template>
|
||||
<div class="components-container">
|
||||
<code>countTo 组件 <a href='https://github.com/PanJiaChen/vue-countTo' target='_blank'>线上地址</a></code>
|
||||
<code> <a href='https://github.com/PanJiaChen/vue-countTo' target='_blank'>countTo component</a></code>
|
||||
|
||||
<count-to ref='example' class='example' :start-val='_startVal' :end-val='_endVal' :duration='_duration' :decimals='_decimals'
|
||||
<count-to ref='example' class='example' :start-val='_startVal' :end-val='_endVal' :duration='_duration' :decimals='_decimals'
|
||||
:separator='_separator' :prefix='_prefix' :suffix='_suffix' :autoplay='false' />
|
||||
<div style='margin-left: 25%;margin-top: 40px;'>
|
||||
<label class="label" for="startValInput">startVal: <input type="number" v-model.number='setStartVal' name='startValInput' /></label>
|
||||
@@ -20,9 +20,9 @@
|
||||
:separator='{{_separator}}' :prefix='{{_prefix}}' :suffix='{{_suffix}}' :autoplay=false></code>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import countTo from 'vue-count-to';
|
||||
|
||||
export default {
|
||||
components: { countTo },
|
||||
data() {
|
||||
|
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div class="components-container">
|
||||
<code>拖拽https://github.com/SortableJS/Vue.Draggable 项目:Vue.Draggable</code>
|
||||
<code>drag-list base on <a href="https://github.com/SortableJS/Vue.Draggable" target="_blank">Vue.Draggable</a></code>
|
||||
<div class="editor-container">
|
||||
<DndList :list1="list1" :list2="list2" list1Title="头条列表" list2Title="文章池" />
|
||||
</div>
|
||||
|
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div class="components-container">
|
||||
<code>这里暂时列出了自己在项目中自己封装和用到的组件,如有补充可以提<a href='https://github.com/PanJiaChen/vue-element-admin/issues' target='_blank'>issue</a><br/>
|
||||
我个人崇尚自己封装组件,因为很多组件会和业务后高度的耦合,很多时候第三方封装是满足不了需求的,如有需要可以看楼主之前写过的一篇<a href='https://segmentfault.com/a/1190000009090836' target='_blank'>文章</a>
|
||||
<code>这里暂时列出了自己在项目中用到的组件和一些自己封装的组件,如有补充可以提<a target='_blank' href='https://github.com/PanJiaChen/vue-element-admin/issues'> issue </a><br/>
|
||||
我个人崇尚自己封装组件,因为很多组件会和业务后高度的耦合,而且第三方封装的组件灵活性可控性都不高,如有需要可以看楼主之前写过的一篇<a href='https://segmentfault.com/a/1190000009090836' target='_blank'>文章</a>
|
||||
</code>
|
||||
</div>
|
||||
</template>
|
||||
|
@@ -1,11 +1,12 @@
|
||||
<template>
|
||||
<div class="components-container" style='height:100vh'>
|
||||
<code>有校验</code>
|
||||
<code>jsonEditor is base on <a href="https://github.com/codemirror/CodeMirror" target="_blank">CodeMirrorr</a>,lint base on json-lint </code>
|
||||
<div class="editor-container">
|
||||
<json-editor ref="jsonEditor" v-model="value"></json-editor>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import jsonEditor from 'components/jsonEditor';
|
||||
const jsonData = '[{"items":[{"market_type":"forexdata","symbol":"XAUUSD"},{"market_type":"forexdata","symbol":"UKOIL"},{"market_type":"forexdata","symbol":"CORN"}],"name":""},{"items":[{"market_type":"forexdata","symbol":"XAUUSD"},{"market_type":"forexdata","symbol":"XAGUSD"},{"market_type":"forexdata","symbol":"AUTD"},{"market_type":"forexdata","symbol":"AGTD"}],"name":"贵金属"},{"items":[{"market_type":"forexdata","symbol":"CORN"},{"market_type":"forexdata","symbol":"WHEAT"},{"market_type":"forexdata","symbol":"SOYBEAN"},{"market_type":"forexdata","symbol":"SUGAR"}],"name":"农产品"},{"items":[{"market_type":"forexdata","symbol":"UKOIL"},{"market_type":"forexdata","symbol":"USOIL"},{"market_type":"forexdata","symbol":"NGAS"}],"name":"能源化工"}]';
|
||||
@@ -21,8 +22,8 @@
|
||||
|
||||
<style scoped>
|
||||
.editor-container{
|
||||
position: relative;
|
||||
height: 100%;
|
||||
position: relative;
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
||||
|
||||
|
@@ -1,19 +1,30 @@
|
||||
<template>
|
||||
<div class="components-container">
|
||||
<code>公司做的后台主要是一个cms系统,公司也是以自媒体为核心的,所以富文本是后台很核心的功能。在选择富文本的过程中也走了不少的弯路,市面上常见的富文本都基本用过了,最终选择了tinymce</code>
|
||||
<code>Markdown 我们这里选用了 <a href="https://github.com/sparksuite/simplemde-markdown-editor" target="_blank">simplemde-markdown-editor</a> ,简单的用vue封装了一下<a target='_blank' href='https://segmentfault.com/a/1190000009762198#articleHeader14'> 相关文章 </a></code>
|
||||
<div class="editor-container">
|
||||
<MdEditor id='contentEditor' ref="contentEditor" v-model='content' :height="300" :zIndex='20'></MdEditor>
|
||||
<MdEditor id='contentEditor' ref="contentEditor" v-model='content' :height="300" :zIndex='20'></MdEditor>
|
||||
</div>
|
||||
<el-button @click='markdown2Html' style="margin-top:80px;" type="primary">转为HTML<i class="el-icon-document el-icon--right"></i></el-button>
|
||||
<div v-html="html"></div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import MdEditor from 'components/MdEditor';
|
||||
|
||||
export default {
|
||||
components: { MdEditor },
|
||||
data() {
|
||||
return {
|
||||
content: 'Simplemde'
|
||||
content: '## Simplemde',
|
||||
html: ''
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
markdown2Html() {
|
||||
import('showdown').then(showdown => {
|
||||
const converter = new showdown.Converter();
|
||||
this.html = converter.makeHtml(this.content)
|
||||
})
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@@ -1,14 +1,13 @@
|
||||
<template>
|
||||
<div class="components-container">
|
||||
<code>公司做的后台主要是一个cms系统,公司也是以自媒体为核心的,所以富文本是后台很核心的功能。在选择富文本的过程中也走了不少的弯路,市面上常见的富文本都基本用过了,最终选择了tinymce</code>
|
||||
<div class="editor-container">
|
||||
<code>公司做的后台主要是一个cms系统,公司也是以自媒体为核心的,所以富文本是后台很核心的功能。在选择富文本的过程中也走了不少的弯路,市面上常见的富文本都基本用过了,最终选择了Tinymce<a target='_blank' href='https://segmentfault.com/a/1190000009762198#articleHeader13'> 相关文章 </a></code>
|
||||
<div>
|
||||
<Tinymce :height=200 ref="editor" v-model="content"></Tinymce>
|
||||
</div>
|
||||
<!--<div class='editor-content'>
|
||||
{{content}}
|
||||
</div>-->
|
||||
<div class='editor-content' v-html='content'></div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Tinymce from 'components/Tinymce';
|
||||
|
||||
@@ -18,11 +17,14 @@
|
||||
return {
|
||||
content: 'Tinymce'
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.editor-content{
|
||||
margin-top: 20px;
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
|
@@ -1,26 +1,19 @@
|
||||
<template>
|
||||
<div class="errPage-container">
|
||||
<!--error code-->
|
||||
<err-code/>
|
||||
<!--error code-->
|
||||
<err-code/>
|
||||
|
||||
<h3>请点击右上角bug小图表</h3>
|
||||
<code>
|
||||
<code>
|
||||
现在的管理后台基本都是spa的形式了,它增强了用户体验,但同时也会怎增加页面出问题的可能性,可能一个小小的疏忽就导致整个页面的死锁。好在Vue官网提供了一个方法来捕获处理异常
|
||||
</code>
|
||||
<a href="#"><img src='../../../documentImg/code1.png'></a>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import errCode from './errcode';
|
||||
// import code1Img from
|
||||
export default {
|
||||
components: { errCode },
|
||||
data() {
|
||||
return {
|
||||
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
back() {
|
||||
this.$router.go(-1)
|
||||
@@ -28,6 +21,7 @@
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.errPage-container{
|
||||
padding: 30px;
|
||||
|
@@ -4,7 +4,7 @@
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<h1 class="text-jumbo text-ginormous">Oops!</h1>
|
||||
gif来源<a href='https://zh.airbnb.com/' target='_blank'>airbnb</a> 页面
|
||||
gif来源<a href='https://zh.airbnb.com/' target='_blank'>airbnb</a> 页面
|
||||
<h2>你没有权限去该页面</h2>
|
||||
<h6>如有不满请联系你领导</h6>
|
||||
<ul class="list-unstyled">
|
||||
@@ -26,9 +26,9 @@
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import errGif from 'assets/401.gif';
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
@@ -50,38 +50,38 @@
|
||||
</script>
|
||||
|
||||
<style rel="stylesheet/scss" lang="scss" scoped>
|
||||
.errPage-container {
|
||||
width: 800px;
|
||||
margin: 100px auto;
|
||||
.pan-back-btn {
|
||||
background: #008489;
|
||||
color: #fff;
|
||||
}
|
||||
.pan-gif {
|
||||
margin: 0 auto;
|
||||
display: block;
|
||||
}
|
||||
.pan-img{
|
||||
display: block;
|
||||
margin: 0 auto;
|
||||
}
|
||||
.text-jumbo {
|
||||
font-size: 60px;
|
||||
font-weight: 700;
|
||||
color: #484848;
|
||||
}
|
||||
.list-unstyled {
|
||||
font-size: 14px;
|
||||
li {
|
||||
padding-bottom: 5px;
|
||||
}
|
||||
a {
|
||||
color: #008489;
|
||||
text-decoration: none;
|
||||
&:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
}
|
||||
.errPage-container {
|
||||
width: 800px;
|
||||
margin: 100px auto;
|
||||
.pan-back-btn {
|
||||
background: #008489;
|
||||
color: #fff;
|
||||
}
|
||||
.pan-gif {
|
||||
margin: 0 auto;
|
||||
display: block;
|
||||
}
|
||||
.pan-img {
|
||||
display: block;
|
||||
margin: 0 auto;
|
||||
}
|
||||
.text-jumbo {
|
||||
font-size: 60px;
|
||||
font-weight: 700;
|
||||
color: #484848;
|
||||
}
|
||||
.list-unstyled {
|
||||
font-size: 14px;
|
||||
li {
|
||||
padding-bottom: 5px;
|
||||
}
|
||||
a {
|
||||
color: #008489;
|
||||
text-decoration: none;
|
||||
&:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
@@ -9,7 +9,7 @@
|
||||
</div>
|
||||
<div class="bullshit">
|
||||
<div class="bullshit__oops">OOPS!</div>
|
||||
<div class="bullshit__info">版权所有<a class='link-type' href='https://wallstreetcn.com' target='_blank'>华尔街见闻</a></div>
|
||||
<div class="bullshit__info">版权所有<a class='link-type' href='https://wallstreetcn.com' target='_blank'>华尔街见闻</a></div>
|
||||
<div class="bullshit__headline">{{ message }}</div>
|
||||
<div class="bullshit__info">请检查您输入的网址是否正确,请点击以下按钮返回主页或者发送错误报告</div>
|
||||
<a href="/" class="bullshit__return-home">返回首页</a>
|
||||
@@ -17,6 +17,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
computed: {
|
||||
@@ -26,6 +27,7 @@
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style rel="stylesheet/scss" lang="scss" scoped>
|
||||
.wscn-http404 {
|
||||
position: relative;
|
||||
|
@@ -7,6 +7,9 @@
|
||||
<div style="display:inline-block">
|
||||
|
||||
<el-dropdown trigger="click">
|
||||
<router-link style="margin-right:15px;" v-show='isEdit' :to="{ path:'create'}">
|
||||
<el-button type="info">创建form</el-button>
|
||||
</router-link>
|
||||
<el-button>{{!postForm.comment_disabled?'评论已打开':'评论已关闭'}}<i class="el-icon-caret-bottom el-icon--right"></i></el-button>
|
||||
<el-dropdown-menu class="no-padding no-hover" slot="dropdown">
|
||||
<el-dropdown-item>
|
||||
@@ -185,10 +188,16 @@
|
||||
computed: {
|
||||
contentShortLength() {
|
||||
return this.postForm.content_short.length
|
||||
},
|
||||
isEdit() {
|
||||
return this.$route.meta.isEdit // 根据meta判断
|
||||
// return this.$route.path.indexOf('edit') !== -1 // 根据路由判断
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.fetchData();
|
||||
if (this.isEdit) {
|
||||
this.fetchData();
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
fetchData() {
|
98
src/views/example/tab/components/tabPane.vue
Normal file
@@ -0,0 +1,98 @@
|
||||
<template>
|
||||
<el-table :data="list" border fit highlight-current-row style="width: 100%">
|
||||
|
||||
<el-table-column align="center" label="序号" width="65">
|
||||
<template scope="scope">
|
||||
<span>{{scope.row.id}}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column width="180px" align="center" label="时间">
|
||||
<template scope="scope">
|
||||
<span>{{scope.row.timestamp | parseTime('{y}-{m}-{d} {h}:{i}')}}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column min-width="300px" label="标题">
|
||||
<template scope="scope">
|
||||
<span class="link-type" @click="handleUpdate(scope.row)">{{scope.row.title}}</span>
|
||||
<el-tag>{{scope.row.type}}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column width="110px" align="center" label="作者">
|
||||
<template scope="scope">
|
||||
<span>{{scope.row.author}}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column width="80px" label="重要性">
|
||||
<template scope="scope">
|
||||
<wscn-icon-svg v-for="n in +scope.row.importance" icon-class="wujiaoxing" class="meta-item__icon" :key="n" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column align="center" label="阅读数" width="95">
|
||||
<template scope="scope">
|
||||
<span>{{scope.row.pageviews}}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column class-name="status-col" label="状态" width="90">
|
||||
<template scope="scope">
|
||||
<el-tag :type="scope.row.status | statusFilter">{{scope.row.status}}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
</el-table>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { fetchList } from 'api/article_table';
|
||||
|
||||
export default {
|
||||
name: 'articleDetail',
|
||||
props: {
|
||||
type: {
|
||||
type: String,
|
||||
default: 'CN'
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
list: null,
|
||||
total: null,
|
||||
listQuery: {
|
||||
page: 1,
|
||||
limit: 5,
|
||||
type: this.type,
|
||||
sort: '+id'
|
||||
}
|
||||
}
|
||||
},
|
||||
filters: {
|
||||
statusFilter(status) {
|
||||
const statusMap = {
|
||||
published: 'success',
|
||||
draft: 'gray',
|
||||
deleted: 'danger'
|
||||
};
|
||||
return statusMap[status]
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.getList();
|
||||
},
|
||||
methods: {
|
||||
getList() {
|
||||
this.$emit('create'); // for test
|
||||
|
||||
fetchList(this.listQuery).then(response => {
|
||||
this.list = response.data.items;
|
||||
this.total = response.data.total;
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
44
src/views/example/tab/index.vue
Normal file
@@ -0,0 +1,44 @@
|
||||
<template>
|
||||
<div class="tab-container">
|
||||
<el-tag type="primary">mounted times :{{createdTimes}}</el-tag>
|
||||
<el-tabs style='margin-top:15px;' v-model="activeName" type="border-card">
|
||||
<el-tab-pane v-for="item in tabMapOptions" :label="item.label" :key='item.key' :name="item.key">
|
||||
<keep-alive>
|
||||
<tab-pane v-if='activeName==item.key' :type='item.key' @create='showCreatedTimes'></tab-pane>
|
||||
</keep-alive>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import tabPane from './components/tabPane'
|
||||
|
||||
export default {
|
||||
name: 'tabDemo',
|
||||
components: { tabPane },
|
||||
data() {
|
||||
return {
|
||||
tabMapOptions: [
|
||||
{ label: '中国', key: 'CN' },
|
||||
{ label: '美国', key: 'US' },
|
||||
{ label: '日本', key: 'JP' },
|
||||
{ label: '欧元区', key: 'EU' }
|
||||
],
|
||||
activeName: 'CN',
|
||||
createdTimes: 0
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
showCreatedTimes() {
|
||||
this.createdTimes = this.createdTimes + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.tab-container{
|
||||
margin: 30px;
|
||||
}
|
||||
</style>
|
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<div class="filter-container">
|
||||
<el-checkbox-group v-model="formThead">
|
||||
<el-checkbox-group v-model="formThead">
|
||||
<el-checkbox label="apple">apple</el-checkbox>
|
||||
<el-checkbox label="banana">banana</el-checkbox>
|
||||
<el-checkbox label="orange">orange</el-checkbox>
|
||||
@@ -18,22 +18,21 @@
|
||||
</el-table>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
tableData: [{
|
||||
name: '水果',
|
||||
list: [{ name: 'apple', value: 10 }, { name: 'banana', value: 20 }, { name: 'orange', value: 20 }]
|
||||
}, {
|
||||
name: '水果2',
|
||||
list: [{ name: 'apple2', value: 12 }, { name: 'banana2', value: 22 }, { name: 'orange', value: 20 }]
|
||||
}],
|
||||
formThead: ['apple', 'banana']
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
tableData: [{
|
||||
name: '水果',
|
||||
list: [{ name: 'apple', value: 10 }, { name: 'banana', value: 20 }, { name: 'orange', value: 20 }]
|
||||
}, {
|
||||
name: '水果2',
|
||||
list: [{ name: 'apple2', value: 12 }, { name: 'banana2', value: 22 }, { name: 'orange', value: 20 }]
|
||||
}],
|
||||
formThead: ['apple', 'banana']
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
</script>
|
||||
|
3
src/views/example/table/index.vue
Normal file
@@ -0,0 +1,3 @@
|
||||
<template>
|
||||
<router-view></router-view>
|
||||
</template>
|
@@ -22,10 +22,10 @@
|
||||
<el-button class="filter-item" type="primary" v-waves icon="search" @click="handleFilter">搜索</el-button>
|
||||
<el-button class="filter-item" style="margin-left: 10px;" @click="handleCreate" type="primary" icon="edit">添加</el-button>
|
||||
<el-button class="filter-item" type="primary" icon="document" @click="handleDownload">导出</el-button>
|
||||
<el-checkbox class="filter-item" @change='tableKey=tableKey+1' v-model="showAuditor">显示审核人</el-checkbox>
|
||||
<el-checkbox class="filter-item" @change='tableKey=tableKey+1' v-model="showAuditor">显示审核人</el-checkbox>
|
||||
</div>
|
||||
|
||||
<el-table :key='tableKey' :data="list" v-loading.body="listLoading" border fit highlight-current-row style="width: 100%">
|
||||
<el-table :key='tableKey' :data="list" v-loading.body="listLoading" border fit highlight-current-row style="width: 100%">
|
||||
|
||||
<el-table-column align="center" label="序号" width="65">
|
||||
<template scope="scope">
|
||||
@@ -58,10 +58,9 @@
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
|
||||
<el-table-column width="80px" label="重要性">
|
||||
<template scope="scope">
|
||||
<wscn-icon-svg v-for="n in +scope.row.importance" icon-class="wujiaoxing" class="meta-item__icon" :key="n" />
|
||||
<wscn-icon-svg v-for="n in +scope.row.importance" icon-class="wujiaoxing" class="meta-item__icon" :key="n" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
@@ -71,28 +70,28 @@
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column class-name="status-col" label="状态" width="90">
|
||||
<el-table-column class-name="status-col" label="状态" width="90">
|
||||
<template scope="scope">
|
||||
<el-tag :type="scope.row.status | statusFilter">{{scope.row.status}}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column align="center" label="操作" width="150">
|
||||
<el-table-column align="center" label="操作" width="150">
|
||||
<template scope="scope">
|
||||
<el-button v-if="scope.row.status!='published'" size="small" type="success" @click="handleModifyStatus(scope.row,'published')">发布
|
||||
</el-button>
|
||||
<el-button v-if="scope.row.status!='draft'" size="small" @click="handleModifyStatus(scope.row,'draft')">草稿
|
||||
</el-button>
|
||||
<el-button v-if="scope.row.status!='deleted'" size="small" type="danger" @click="handleModifyStatus(scope.row,'deleted')">删除
|
||||
</el-button>
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
</el-table>
|
||||
|
||||
<div v-show="!listLoading" class="pagination-container">
|
||||
<el-pagination @size-change="handleSizeChange" @current-change="handleCurrentChange" :current-page.sync="listQuery.page" :page-sizes="[10,20,30, 50]"
|
||||
:page-size="listQuery.limit" layout="total, sizes, prev, pager, next, jumper" :total="total">
|
||||
<el-pagination @size-change="handleSizeChange" @current-change="handleCurrentChange" :current-page.sync="listQuery.page"
|
||||
:page-sizes="[10,20,30, 50]" :page-size="listQuery.limit" layout="total, sizes, prev, pager, next, jumper" :total="total">
|
||||
</el-pagination>
|
||||
</div>
|
||||
|
||||
@@ -138,14 +137,14 @@
|
||||
</el-dialog>
|
||||
|
||||
<el-dialog title="阅读数统计" :visible.sync="dialogPvVisible" size="small">
|
||||
<el-table :data="pvData" border fit highlight-current-row style="width: 100%">
|
||||
<el-table-column prop="key" label="渠道"> </el-table-column>
|
||||
<el-table-column prop="pv" label="pv"> </el-table-column>
|
||||
<el-table :data="pvData" border fit highlight-current-row style="width: 100%">
|
||||
<el-table-column prop="key" label="渠道"> </el-table-column>
|
||||
<el-table-column prop="pv" label="pv"> </el-table-column>
|
||||
</el-table>
|
||||
<span slot="footer" class="dialog-footer">
|
||||
<el-button type="primary" @click="dialogPvVisible = false">确 定</el-button>
|
||||
</span>
|
||||
</el-dialog >
|
||||
</el-dialog>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
@@ -155,10 +154,10 @@
|
||||
import { parseTime } from 'utils';
|
||||
|
||||
const calendarTypeOptions = [
|
||||
{ key: 'FD', display_name: '经济数据' },
|
||||
{ key: 'FE', display_name: '财经大事' },
|
||||
{ key: 'BI', display_name: '国债发行' },
|
||||
{ key: 'VN', display_name: '假期报告' }
|
||||
{ key: 'CN', display_name: '中国' },
|
||||
{ key: 'US', display_name: '美国' },
|
||||
{ key: 'JP', display_name: '日本' },
|
||||
{ key: 'EU', display_name: '欧元区' }
|
||||
];
|
||||
|
||||
// arr to obj
|
@@ -32,6 +32,7 @@
|
||||
</el-table>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { getList } from 'api/article';
|
||||
export default {
|
||||
|
@@ -1,15 +1,24 @@
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<div class="wrapper">
|
||||
<code>
|
||||
这半年来一直在用vue写管理后台,目前后台已经有七十多个页面,十几种权限,但维护成本依然很低,效率依然很高,所以准备开源分享一下后台开发的经验和成果。目前的技术栈主要的采用vue+element+axios.由于是个人项目,所以数据请求都是用了mockjs代替。会出一系列的教程配套文章,如如何从零构建后台项目框架,如何做完整的用户系统(如权限验证,二次登录等),如何二次开发组件(如富文本),如何整合七牛等等文章,各种后台开发经验等等。莫急~~
|
||||
<code>
|
||||
这半年来一直在用vue写管理后台,目前后台已经有百来个个页面,十几种权限,但维护成本依然很低,所以准备开源分享一下后台开发的经验和成果。目前的技术栈主要的采用vue+element+axios由webpack2打包.由于是个人项目,所以数据请求都是用了mockjs模拟。注意:在次项目基础上改造开发时请移除mock文件。
|
||||
写了一个系列的教程配套文章,如何从零构建后一个完整的后台项目:
|
||||
<ul>
|
||||
<li><a target='_blank' class='lin' href="https://github.com/PanJiaChen/vue-element-admin/wiki">wiki</a></li>
|
||||
<li><a target='_blank' href="https://juejin.im/post/59097cd7a22b9d0065fb61d2">手摸手,带你用 vue 撸后台 系列一(基础篇)</a></li>
|
||||
<li><a target='_blank' href="https://juejin.im/post/591aa14f570c35006961acac">手摸手,带你用 vue 撸后台 系列二(登录权限篇)</a></li>
|
||||
<li><a target='_blank' href="https://juejin.im/post/593121aa0ce4630057f70d35">手摸手,带你用 vue 撸后台 系列三 (实战篇)</a></li>
|
||||
<li><a target='_blank' href="https://segmentfault.com/a/1190000009090836">手摸手,带你封装一个vue component</a></li>
|
||||
</ul>
|
||||
</code>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.wrapper{
|
||||
width: 800px;
|
||||
margin: 30px auto;
|
||||
width: 800px;
|
||||
margin: 30px auto;
|
||||
}
|
||||
</style>
|
||||
|
@@ -11,9 +11,7 @@
|
||||
name: 'AppMain',
|
||||
computed: {
|
||||
key() {
|
||||
return this.$route.name !== undefined
|
||||
? this.$route.name + +new Date()
|
||||
: this.$route + +new Date()
|
||||
return this.$route.name !== undefined ? this.$route.name + +new Date() : this.$route + +new Date()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div class="app-wrapper" :class="{hideSidebar:!sidebar.opened}">
|
||||
<div class="sidebar-wrapper">
|
||||
<Sidebar class="sidebar-container"/>
|
||||
<Sidebar class="sidebar-container" />
|
||||
</div>
|
||||
<div class="main-container">
|
||||
<Navbar/>
|
||||
@@ -27,9 +27,9 @@
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style rel="stylesheet/scss" lang="scss" scoped>
|
||||
@import "src/styles/mixin.scss";
|
||||
|
||||
.app-wrapper {
|
||||
@include clearfix;
|
||||
position: relative;
|
||||
@@ -59,12 +59,17 @@
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
z-index: 1001;
|
||||
overflow-x: hidden;
|
||||
overflow: hidden;
|
||||
transition: all .28s ease-out;
|
||||
@include scrollBar;
|
||||
}
|
||||
.sidebar-container {
|
||||
transition: all .28s ease-out;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: -17px;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
.main-container {
|
||||
min-height: 100%;
|
||||
|
@@ -34,6 +34,7 @@
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style rel="stylesheet/scss" lang="scss" scoped>
|
||||
.app-levelbar.el-breadcrumb {
|
||||
display: inline-block;
|
||||
|
@@ -1,20 +1,21 @@
|
||||
<template>
|
||||
<el-menu class="navbar" mode="horizontal">
|
||||
<Hamburger class="hamburger-container" :toggleClick="toggleSideBar" :isActive="sidebar.opened"></Hamburger>
|
||||
<hamburger class="hamburger-container" :toggleClick="toggleSideBar" :isActive="sidebar.opened"></hamburger>
|
||||
<levelbar></levelbar>
|
||||
<ErrLog v-if="log.length>0" class="errLog-container" :logsList="log"></ErrLog>
|
||||
<error-log v-if="log.length>0" class="errLog-container" :logsList="log"></error-log>
|
||||
<screenfull class='screenfull'></screenfull>
|
||||
<el-dropdown class="avatar-container" trigger="click">
|
||||
<div class="avatar-wrapper">
|
||||
<img class="user-avatar" :src="avatar+'?imageView2/1/w/80/h/80'">
|
||||
<i class="el-icon-caret-bottom"/>
|
||||
<i class="el-icon-caret-bottom" />
|
||||
</div>
|
||||
<el-dropdown-menu class="user-dropdown" slot="dropdown">
|
||||
<router-link class='inlineBlock' to="/">
|
||||
<router-link class='inlineBlock' to="/">
|
||||
<el-dropdown-item>
|
||||
首页
|
||||
</el-dropdown-item>
|
||||
</router-link>
|
||||
<router-link class='inlineBlock' to="/admin/profile">
|
||||
<router-link class='inlineBlock' to="/admin/profile">
|
||||
<el-dropdown-item>
|
||||
设置
|
||||
</el-dropdown-item>
|
||||
@@ -29,14 +30,16 @@
|
||||
import { mapGetters } from 'vuex';
|
||||
import Levelbar from './Levelbar';
|
||||
import Hamburger from 'components/Hamburger';
|
||||
import ErrLog from 'components/ErrLog';
|
||||
import Screenfull from 'components/Screenfull';
|
||||
import ErrorLog from 'components/ErrLog';
|
||||
import errLogStore from 'store/errLog';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
Levelbar,
|
||||
Hamburger,
|
||||
ErrLog
|
||||
ErrorLog,
|
||||
Screenfull
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
@@ -62,6 +65,7 @@
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style rel="stylesheet/scss" lang="scss" scoped>
|
||||
.navbar {
|
||||
height: 50px;
|
||||
@@ -78,6 +82,12 @@
|
||||
position: absolute;
|
||||
right: 150px;
|
||||
}
|
||||
.screenfull{
|
||||
position: absolute;
|
||||
right: 90px;
|
||||
top: 16px;
|
||||
color: red;
|
||||
}
|
||||
.avatar-container {
|
||||
height: 50px;
|
||||
display: inline-block;
|
||||
|
@@ -1,30 +1,14 @@
|
||||
<template>
|
||||
<el-menu :unique-opened='true' mode="vertical" theme="dark" :default-active="$route.path">
|
||||
<template v-for="item in permission_routers" v-if="!item.hidden">
|
||||
<el-submenu :index="item.name" v-if="!item.noDropdown">
|
||||
<template slot="title">
|
||||
<wscn-icon-svg :icon-class="item.icon||'wenzhang1'" /> {{item.name}}
|
||||
</template>
|
||||
<router-link v-for="child in item.children" :key="child.path" v-if="!child.hidden" class="title-link" :to="item.path+'/'+child.path">
|
||||
<el-menu-item :index="item.path+'/'+child.path">
|
||||
{{child.name}}
|
||||
</el-menu-item>
|
||||
</router-link>
|
||||
</el-submenu>
|
||||
<router-link v-if="item.noDropdown&&item.children.length>0" :to="item.path+'/'+item.children[0].path">
|
||||
<el-menu-item :index="item.path+'/'+item.children[0].path">
|
||||
<wscn-icon-svg :icon-class="item.icon||'geren1'" /> {{item.children[0].name}}
|
||||
</el-menu-item>
|
||||
</router-link>
|
||||
</template>
|
||||
<el-menu mode="vertical" theme="dark" :default-active="$route.path">
|
||||
<sidebar-item :routes='permission_routers'></sidebar-item>
|
||||
</el-menu>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapGetters } from 'vuex';
|
||||
|
||||
import SidebarItem from './SidebarItem';
|
||||
export default {
|
||||
name: 'Sidebar',
|
||||
components: { SidebarItem },
|
||||
computed: {
|
||||
...mapGetters([
|
||||
'permission_routers'
|
||||
@@ -37,11 +21,4 @@
|
||||
.el-menu {
|
||||
min-height: 100%;
|
||||
}
|
||||
.wscn-icon {
|
||||
margin-right: 10px;
|
||||
}
|
||||
.hideSidebar .title-link{
|
||||
display: block;
|
||||
text-indent: 10px;
|
||||
}
|
||||
</style>
|
||||
|
47
src/views/layout/SidebarItem.vue
Normal file
@@ -0,0 +1,47 @@
|
||||
<template>
|
||||
<div>
|
||||
<template v-for="item in routes">
|
||||
<router-link v-if="!item.hidden&&item.noDropdown&&item.children.length>0" :to="item.path+'/'+item.children[0].path">
|
||||
<el-menu-item :index="item.path+'/'+item.children[0].path">
|
||||
<wscn-icon-svg v-if='item.icon' :icon-class="item.icon" /> {{item.children[0].name}}
|
||||
</el-menu-item>
|
||||
</router-link>
|
||||
<el-submenu :index="item.name" v-if="!item.noDropdown&&!item.hidden">
|
||||
<template slot="title">
|
||||
<wscn-icon-svg v-if='item.icon' :icon-class="item.icon" /> {{item.name}}
|
||||
</template>
|
||||
<template v-for="child in item.children" v-if='!child.hidden'>
|
||||
<sidebar-item class='menu-indent' v-if='child.children&&child.children.length>0' :routes='[child]'> </sidebar-item>
|
||||
<router-link v-else class="menu-indent" :to="item.path+'/'+child.path">
|
||||
<el-menu-item :index="item.path+'/'+child.path">
|
||||
{{child.name}}
|
||||
</el-menu-item>
|
||||
</router-link>
|
||||
</template>
|
||||
</el-submenu>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
export default {
|
||||
name: 'SidebarItem',
|
||||
props: {
|
||||
routes: {
|
||||
type: Array
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style rel="stylesheet/scss" lang="scss" scoped>
|
||||
.wscn-icon {
|
||||
margin-right: 10px;
|
||||
}
|
||||
.hideSidebar .menu-indent{
|
||||
display: block;
|
||||
text-indent: 10px;
|
||||
}
|
||||
</style>
|
||||
|
@@ -1,10 +1,10 @@
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<div style='margin-bottom:15px;'>你的权限: {{roles}}</div>
|
||||
切换权限:
|
||||
<el-radio-group v-model="role">
|
||||
<el-radio-button label="editor"></el-radio-button>
|
||||
</el-radio-group>
|
||||
<div style='margin-bottom:15px;'>你的权限: {{roles}}</div>
|
||||
切换权限:
|
||||
<el-radio-group v-model="role">
|
||||
<el-radio-button label="editor"></el-radio-button>
|
||||
</el-radio-group>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -23,8 +23,9 @@
|
||||
},
|
||||
watch: {
|
||||
role(val) {
|
||||
this.$store.commit('SET_ROLES', [val]);
|
||||
this.$router.push({ path: '/permission/index?' + +new Date() });
|
||||
this.$store.dispatch('ChangeRole', val).then(() => {
|
||||
this.$router.push({ path: '/permission/index?' + +new Date() });
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
44
src/views/qiniu/upload.vue
Normal file
@@ -0,0 +1,44 @@
|
||||
<template>
|
||||
<el-upload
|
||||
action="https://upload.qbox.me"
|
||||
:data="dataObj"
|
||||
drag
|
||||
:multiple="true"
|
||||
:before-upload="beforeUpload">
|
||||
<i class="el-icon-upload"></i>
|
||||
<div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
|
||||
</el-upload>
|
||||
</template>
|
||||
|
||||
|
||||
<script>
|
||||
import { getToken } from 'api/qiniu'; // 获取七牛token 后端通过Access Key,Secret Key,bucket等生成token
|
||||
// 七牛官方sdk https://developer.qiniu.com/sdk#official-sdk
|
||||
|
||||
export default{
|
||||
data() {
|
||||
return {
|
||||
dataObj: { token: '', key: '' },
|
||||
image_uri: [],
|
||||
fileList: []
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
beforeUpload() {
|
||||
const _self = this;
|
||||
return new Promise((resolve, reject) => {
|
||||
getToken().then(response => {
|
||||
const key = response.data.qiniu_key;
|
||||
const token = response.data.qiniu_token;
|
||||
_self._data.dataObj.token = token;
|
||||
_self._data.dataObj.key = key;
|
||||
resolve(true);
|
||||
}).catch(err => {
|
||||
console.log(err)
|
||||
reject(false)
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
@@ -76,17 +76,17 @@ export default {
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.box-card{
|
||||
width: 400px;
|
||||
margin: 20px auto;
|
||||
}
|
||||
.block{
|
||||
padding: 30px 24px;
|
||||
}
|
||||
.alert-item{
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.tag-item{
|
||||
margin-right: 15px;
|
||||
}
|
||||
.box-card{
|
||||
width: 400px;
|
||||
margin: 20px auto;
|
||||
}
|
||||
.block{
|
||||
padding: 30px 24px;
|
||||
}
|
||||
.alert-item{
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.tag-item{
|
||||
margin-right: 15px;
|
||||
}
|
||||
</style>
|
||||
|