Compare commits
18 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
b1311322ad | ||
|
ffec6b6df7 | ||
|
f0afbf7ea5 | ||
|
a4f8e0b805 | ||
|
2d72df3605 | ||
|
e9f92a7d3d | ||
|
ee362f22b2 | ||
|
11426c8494 | ||
|
fa5f5e9d26 | ||
|
cda292dec1 | ||
|
877b73cd67 | ||
|
53d7243316 | ||
|
5379510013 | ||
|
f712d4682e | ||
|
cb0e889829 | ||
|
6a8a02f839 | ||
|
d56cd59474 | ||
|
a10cfcc837 |
37
README-en.md
37
README-en.md
@@ -1,29 +1,19 @@
|
||||
[](https://github.com/vuejs/vue)
|
||||
[](https://github.com/ElemeFE/element)
|
||||
[](https://github.com/PanJiaChen/vue-element-admin/blob/master/LICENSE)
|
||||
[]()
|
||||
|
||||
## Intro
|
||||
|
||||
> In the past half year, I have been building a backend for management dashboard using Vue. Though the backend has contained greater than 70 pages and over 10 permissions, it still takes insignificant effort to maintain the project. So I decide to make it open source so as to share my development experience and progress on backend. The tech stack is mainly [Vue.js](https://github.com/vuejs/vue)+[Element](https://github.com/ElemeFE/element)+[axios](https://github.com/mzabriskie/axios). Since it's a personal project, all data requests are simulated with [Mock.js](https://github.com/nuysoft/Mock). **Note:** if anyone wants to modify or develop based on this project, please remove the mock files.
|
||||
|
||||
**Live demo:** http://panjiachen.github.io/vue-element-admin
|
||||
|
||||
**Note: element-ui@1.3.3 is used in the project, so vue 2.3.0+ is required.**
|
||||
**Note: element-ui@1.4.2 is used in the project, so vue 2.3.0+ is required.**
|
||||
|
||||
More tutorials incoming. Including articles on:
|
||||
|
||||
- How to build structure of a backend dashboard project from scratch
|
||||
- How to make a complete user system (e.g. permission authentication, two-factor authentication)
|
||||
- How to package components (e.g. rich text)
|
||||
- How to integrate with [Qiniu](https://www.qiniu.com/)
|
||||
- Other development experience on backend
|
||||
|
||||
Join the group on QQ 591724180.
|
||||
|
||||
**Tutorials:**
|
||||
|
||||
- [Wiki](https://github.com/PanJiaChen/vue-element-admin/wiki)
|
||||
- [Step by step instructions on playing with backend using Vue Part 1 - Fundamentals](https://juejin.im/post/59097cd7a22b9d0065fb61d2)
|
||||
- [Step by step instructions on playing with backend using Vue Part 2 - Login permission](https://juejin.im/post/591aa14f570c35006961acac)
|
||||
- [Step by step instructions on packaging a Vue component](https://segmentfault.com/a/1190000009090836)
|
||||
|
||||
**Please read the Wiki and articles above before creating any issue. Feel free to contribute by making a pull request.**
|
||||
- vueAdmin-template: [vueAdmin-template](https://github.com/PanJiaChen/vueAdmin-template)
|
||||
- electron-vue-admin: [electron-vue-admin](https://github.com/PanJiaChen/electron-vue-admin)
|
||||
- Donate:[donate](https://github.com/PanJiaChen/vue-element-admin/blob/master/README-en.md#donate)
|
||||
|
||||
## Features
|
||||
|
||||
@@ -43,6 +33,7 @@ Join the group on QQ 591724180.
|
||||
- 401, 404 error page
|
||||
- Error log
|
||||
- Exporting to Excel
|
||||
- Upload Excel
|
||||
- Table example
|
||||
- Interactive table example
|
||||
- Drag & drop table example
|
||||
@@ -117,6 +108,10 @@ npm run build:prod
|
||||
## Changelog
|
||||
Detailed changes for each release are documented in the [release notes](https://github.com/PanJiaChen/vue-element-admin/releases).
|
||||
|
||||
## Donate
|
||||
If you find this project useful, you can buy me a cup of coffee
|
||||

|
||||
|
||||
## State Management
|
||||
|
||||
Only status of user and app configuration is managed by Vuex. Other data are managed by their own business pages.
|
||||
@@ -174,3 +169,7 @@ Only status of user and app configuration is managed by Vuex. Other data are man
|
||||
#### More
|
||||
|
||||
http://panjiachen.github.io/vue-element-admin
|
||||
|
||||
## License
|
||||
|
||||
MIT
|
||||
|
21
README.md
21
README.md
@@ -1,7 +1,7 @@
|
||||
# vue-element-admin #
|
||||
|
||||
[](https://github.com/vuejs/vue)
|
||||
[](https://github.com/ElemeFE/element)
|
||||
[](https://github.com/ElemeFE/element)
|
||||
[](https://github.com/PanJiaChen/vue-element-admin/blob/master/LICENSE)
|
||||
[]()
|
||||
|
||||
@@ -12,11 +12,15 @@
|
||||
|
||||
[wiki](https://github.com/PanJiaChen/vue-element-admin/wiki)
|
||||
|
||||
**本项目的定位是后台集成方案,不适合当基础模板来开发,模板建议使用 [vueAdmin-template](https://github.com/PanJiaChen/vueAdmin-template) , 桌面端 [electron-vue-admin](https://github.com/PanJiaChen/electron-vue-admin)**
|
||||
[donate](https://github.com/PanJiaChen/vue-element-admin#donate)
|
||||
|
||||
**本项目的定位是后台集成方案,不适合当基础模板来开发。**
|
||||
- 模板建议使用: [vueAdmin-template](https://github.com/PanJiaChen/vueAdmin-template)
|
||||
- 桌面端: [electron-vue-admin](https://github.com/PanJiaChen/electron-vue-admin)
|
||||
|
||||
|
||||
|
||||
**注意:该项目目前使用element-ui@1.4.1版本,所以最低兼容 Vue 2.3.0**
|
||||
**注意:该项目目前使用element-ui@1.4.2版本,所以最低兼容 Vue 2.3.0**
|
||||
|
||||
## 前言
|
||||
> 这半年来一直在用vue写管理后台,目前后台已经有百来个页面,十几种权限,但维护成本依然很低,所以准备开源分享一下后台开发的经验和成果。目前的技术栈主要的采用vue+element+axios由webpack2打包。由于是个人项目,所以数据请求都是用了mockjs模拟。注意:在此项目基础上改造开发时请移除mock文件。
|
||||
@@ -33,11 +37,13 @@
|
||||
|
||||
相应需求,开了一个qq群 `591724180` 方便大家交流
|
||||
|
||||
**如有问题请先看上述文章和Wiki,若不能满足,欢迎 issue 和 pr ~**
|
||||
或者可以加入该 **[圈子](https://jianshiapp.com/circles/1209)** 讨论问题
|
||||
|
||||
**如有问题请先看上述文章和Wiki,若不能满足,欢迎 issue 和 pr**
|
||||
|
||||
**该项目并不是一个脚手架,更倾向于是一个集成解决方案**
|
||||
|
||||
**该项目不支持低版本游览器,有需求请自行添加polyfill [详情](https://github.com/PanJiaChen/vue-element-admin/wiki#babel-polyfill)**
|
||||
**该项目不支持低版本游览器(如ie),有需求请自行添加polyfill [详情](https://github.com/PanJiaChen/vue-element-admin/wiki#babel-polyfill)**
|
||||
|
||||
|
||||
## 功能
|
||||
@@ -57,6 +63,7 @@
|
||||
- 401,404错误页面
|
||||
- 错误日志
|
||||
- 导出excel
|
||||
- 前端可视化excel
|
||||
- table example
|
||||
- 动态table example
|
||||
- 拖拽table example
|
||||
@@ -129,6 +136,10 @@
|
||||
## Changelog
|
||||
Detailed changes for each release are documented in the [release notes](https://github.com/PanJiaChen/vue-element-admin/releases).
|
||||
|
||||
## Donate
|
||||
If you find this project useful, you can buy me a cup of coffee
|
||||

|
||||
|
||||
## 状态管理
|
||||
后台只有user和app配置相关状态使用vuex存在全局,其它数据都由每个业务页面自己管理。
|
||||
|
||||
|
@@ -68,7 +68,7 @@ module.exports = {
|
||||
test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
|
||||
loader: 'url-loader',
|
||||
exclude: [resolve('src/icons')],
|
||||
query: {
|
||||
options: {
|
||||
limit: 10000,
|
||||
name: utils.assetsPath('img/[name].[hash:7].[ext]')
|
||||
}
|
||||
@@ -76,7 +76,7 @@ module.exports = {
|
||||
{
|
||||
test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
|
||||
loader: 'url-loader',
|
||||
query: {
|
||||
options: {
|
||||
limit: 10000,
|
||||
name: utils.assetsPath('fonts/[name].[hash:7].[ext]')
|
||||
}
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "juicy",
|
||||
"version": "2.0.0",
|
||||
"version": "2.1.0",
|
||||
"description": "A Vue.js admin",
|
||||
"author": "Pan <panfree23@gmail.com>",
|
||||
"license": "MIT",
|
||||
|
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<transition :name="transitionName">
|
||||
<div class="back-to-top" @click="backToTop" v-show="visible" :style="customStyle">
|
||||
<div class="back-to-ceiling" @click="backToTop" v-show="visible" :style="customStyle">
|
||||
<svg width="16" height="16" viewBox="0 0 17 17" xmlns="http://www.w3.org/2000/svg" class="Icon Icon--backToTopArrow" aria-hidden="true" style="height: 16px; width: 16px;">
|
||||
<title>回到顶部</title>
|
||||
<g>
|
||||
@@ -82,14 +82,14 @@ export default {
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.back-to-top {
|
||||
.back-to-ceiling {
|
||||
position: fixed;
|
||||
display: inline-block;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.back-to-top:hover {
|
||||
.back-to-ceiling:hover {
|
||||
background: #d5dbe7;
|
||||
}
|
||||
|
||||
@@ -103,7 +103,7 @@ export default {
|
||||
opacity: 0
|
||||
}
|
||||
|
||||
.back-to-top .Icon {
|
||||
.back-to-ceiling .Icon {
|
||||
fill: #9aaabf;
|
||||
background: none;
|
||||
}
|
||||
|
102
src/components/Tinymce/components/editorImage.vue
Normal file
102
src/components/Tinymce/components/editorImage.vue
Normal file
@@ -0,0 +1,102 @@
|
||||
<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"
|
||||
:multiple="true"
|
||||
:file-list="fileList"
|
||||
:show-file-list="true"
|
||||
list-type="picture-card"
|
||||
:on-remove="handleRemove"
|
||||
:on-success="handleSuccess"
|
||||
:before-upload="beforeUpload">
|
||||
<el-button size="small" type="primary">点击上传</el-button>
|
||||
</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,
|
||||
listObj: {},
|
||||
fileList: []
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
checkAllSuccess() {
|
||||
return Object.keys(this.listObj).every(item => this.listObj[item].hasSuccess)
|
||||
},
|
||||
handleSubmit() {
|
||||
const arr = Object.keys(this.listObj).map(v => this.listObj[v])
|
||||
if (!this.checkAllSuccess()) {
|
||||
this.$message('请等待所有图片上传成功 或 出现了网络问题,请刷新页面重新上传!')
|
||||
return
|
||||
}
|
||||
console.log(arr)
|
||||
this.$emit('successCBK', arr)
|
||||
this.listObj = {}
|
||||
this.fileList = []
|
||||
this.dialogVisible = false
|
||||
},
|
||||
handleSuccess(response, file) {
|
||||
const uid = file.uid
|
||||
const objKeyArr = Object.keys(this.listObj)
|
||||
for (let i = 0, len = objKeyArr.length; i < len; i++) {
|
||||
if (this.listObj[objKeyArr[i]].uid === uid) {
|
||||
this.listObj[objKeyArr[i]].url = response.files.file
|
||||
this.listObj[objKeyArr[i]].hasSuccess = true
|
||||
return
|
||||
}
|
||||
}
|
||||
},
|
||||
handleRemove(file) {
|
||||
const uid = file.uid
|
||||
const objKeyArr = Object.keys(this.listObj)
|
||||
for (let i = 0, len = objKeyArr.length; i < len; i++) {
|
||||
if (this.listObj[objKeyArr[i]].uid === uid) {
|
||||
delete this.listObj[objKeyArr[i]]
|
||||
return
|
||||
}
|
||||
}
|
||||
},
|
||||
beforeUpload(file) {
|
||||
const _self = this
|
||||
const _URL = window.URL || window.webkitURL
|
||||
const fileName = file.uid
|
||||
this.listObj[fileName] = {}
|
||||
return new Promise((resolve, reject) => {
|
||||
const img = new Image()
|
||||
img.src = _URL.createObjectURL(file)
|
||||
img.onload = function() {
|
||||
_self.listObj[fileName] = { hasSuccess: false, uid: file.uid, width: this.width, height: this.height }
|
||||
}
|
||||
resolve(true)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style rel="stylesheet/scss" lang="scss" scoped>
|
||||
.upload-container {
|
||||
.editor-slide-upload {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
}
|
||||
</style>
|
@@ -1,16 +1,21 @@
|
||||
<template>
|
||||
<div class='tinymce-container editor-container'>
|
||||
<textarea class='tinymce-textarea' :id="id"></textarea>
|
||||
<textarea class='tinymce-textarea' :id="tinymceId"></textarea>
|
||||
<div class="editor-custom-btn-container">
|
||||
<editorImage color="#20a0ff" class="editor-upload-btn" @successCBK="imageSuccessCBK"></editorImage>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import editorImage from './components/editorImage'
|
||||
|
||||
export default {
|
||||
name: 'tinymce',
|
||||
components: { editorImage },
|
||||
props: {
|
||||
id: {
|
||||
type: String,
|
||||
default: 'tinymceEditor'
|
||||
type: String
|
||||
},
|
||||
value: {
|
||||
type: String,
|
||||
@@ -23,12 +28,6 @@ export default {
|
||||
return ['removeformat undo redo | bullist numlist | outdent indent | forecolor | fullscreen code', 'bold italic blockquote | h2 p media link | alignleft aligncenter alignright']
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
hasChange: false,
|
||||
hasInit: false
|
||||
}
|
||||
},
|
||||
menubar: {
|
||||
default: ''
|
||||
},
|
||||
@@ -38,17 +37,24 @@ export default {
|
||||
default: 360
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
hasChange: false,
|
||||
hasInit: false,
|
||||
tinymceId: this.id || 'vue-tinymce-' + +new Date()
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
value(val) {
|
||||
if (!this.hasChange && this.hasInit) {
|
||||
this.$nextTick(() => window.tinymce.get(this.id).setContent(val))
|
||||
this.$nextTick(() => window.tinymce.get(this.tinymceId).setContent(val))
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
const _this = this
|
||||
window.tinymce.init({
|
||||
selector: `#${this.id}`,
|
||||
selector: `#${this.tinymceId}`,
|
||||
height: this.height,
|
||||
body_class: 'panel-body ',
|
||||
object_resizing: false,
|
||||
@@ -143,8 +149,16 @@ export default {
|
||||
}
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
imageSuccessCBK(arr) {
|
||||
const _this = this
|
||||
arr.forEach(v => {
|
||||
window.tinymce.get(_this.tinymceId).insertContent(`<img class="wscnph" src="${v.url}" >`)
|
||||
})
|
||||
}
|
||||
},
|
||||
destroyed() {
|
||||
window.tinymce.get(this.id).destroy()
|
||||
window.tinymce.get(this.tinymceId).destroy()
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -153,9 +167,17 @@ export default {
|
||||
.tinymce-container {
|
||||
position: relative
|
||||
}
|
||||
|
||||
.tinymce-textarea {
|
||||
visibility: hidden;
|
||||
z-index: -1;
|
||||
}
|
||||
.editor-custom-btn-container {
|
||||
position: absolute;
|
||||
right: 15px;
|
||||
/*z-index: 2005;*/
|
||||
top: 18px;
|
||||
}
|
||||
.editor-upload-btn {
|
||||
display: inline-block;
|
||||
}
|
||||
</style>
|
||||
|
78
src/components/UploadExcel/index.vue
Normal file
78
src/components/UploadExcel/index.vue
Normal file
@@ -0,0 +1,78 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-button :loading="loading" type="primary" @click="handleUpload">select excel file</el-button>
|
||||
<input id="excel-upload-input" type="file" accept=".xlsx, .xls" class="c-hide" @change="handkeFileChange">
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import XLSX from 'xlsx'
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
loading: false,
|
||||
excelData: {
|
||||
header: null,
|
||||
results: null
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
generateDate({ header, results }) {
|
||||
this.excelData.header = header
|
||||
this.excelData.results = results
|
||||
this.loading = false
|
||||
this.$emit('on-selected-file', this.excelData)
|
||||
},
|
||||
handleUpload() {
|
||||
document.getElementById('excel-upload-input').click()
|
||||
},
|
||||
handkeFileChange(e) {
|
||||
this.loading = true
|
||||
const files = e.target.files
|
||||
const itemFile = files[0] // only use files[0]
|
||||
const reader = new FileReader()
|
||||
reader.onload = e => {
|
||||
const data = e.target.result
|
||||
const fixedData = this.fixdata(data)
|
||||
const workbook = XLSX.read(btoa(fixedData), { type: 'base64' })
|
||||
const firstSheetName = workbook.SheetNames[0]
|
||||
const worksheet = workbook.Sheets[firstSheetName]
|
||||
const header = this.get_header_row(worksheet)
|
||||
const results = XLSX.utils.sheet_to_json(worksheet)
|
||||
this.generateDate({ header, results })
|
||||
}
|
||||
reader.readAsArrayBuffer(itemFile)
|
||||
},
|
||||
fixdata(data) {
|
||||
let o = ''
|
||||
let l = 0
|
||||
const w = 10240
|
||||
for (; l < data.byteLength / w; ++l) o += String.fromCharCode.apply(null, new Uint8Array(data.slice(l * w, l * w + w)))
|
||||
o += String.fromCharCode.apply(null, new Uint8Array(data.slice(l * w)))
|
||||
return o
|
||||
},
|
||||
get_header_row(sheet) {
|
||||
const headers = []
|
||||
const range = XLSX.utils.decode_range(sheet['!ref'])
|
||||
let C
|
||||
const R = range.s.r /* start in the first row */
|
||||
for (C = range.s.c; C <= range.e.c; ++C) { /* walk every column in the range */
|
||||
var cell = sheet[XLSX.utils.encode_cell({ c: C, r: R })] /* find the cell in the first row */
|
||||
var hdr = 'UNKNOWN ' + C // <-- replace with your desired default
|
||||
if (cell && cell.t) hdr = XLSX.utils.format_cell(cell)
|
||||
headers.push(hdr)
|
||||
}
|
||||
return headers
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
#excel-upload-input{
|
||||
display: none;
|
||||
z-index: -9999;
|
||||
}
|
||||
</style>
|
10
src/main.js
10
src/main.js
@@ -4,11 +4,11 @@ import 'element-ui/lib/theme-default/index.css'
|
||||
import App from './App'
|
||||
import router from './router'
|
||||
import store from './store'
|
||||
import * as filters from '@/filters' // 全局filter
|
||||
import '@/icons' // icon
|
||||
import '@/errorLog'// error log
|
||||
import '@/permission' // 权限
|
||||
import '@/mock' // 该项目所有请求使用mockjs模拟
|
||||
import * as filters from './filters' // 全局filter
|
||||
import './icons' // icon
|
||||
import './errorLog'// error log
|
||||
import './permission' // 权限
|
||||
import './mock' // 该项目所有请求使用mockjs模拟
|
||||
|
||||
Vue.use(ElementUI)
|
||||
|
||||
|
@@ -150,7 +150,8 @@ export const asyncRouterMap = [
|
||||
icon: 'EXCEL',
|
||||
children: [
|
||||
{ path: 'download', component: _import('excel/index'), name: '导出excel' },
|
||||
{ path: 'download2', component: _import('excel/selectExcel'), name: '导出已选择项' }
|
||||
{ path: 'download2', component: _import('excel/selectExcel'), name: '导出已选择项' },
|
||||
{ path: 'upload', component: _import('excel/uploadExcel'), name: 'upload excel' }
|
||||
]
|
||||
},
|
||||
{
|
||||
|
@@ -32,14 +32,17 @@ const app = {
|
||||
}
|
||||
},
|
||||
actions: {
|
||||
ToggleSideBar: ({ commit }) => {
|
||||
ToggleSideBar({ commit }) {
|
||||
commit('TOGGLE_SIDEBAR')
|
||||
},
|
||||
addVisitedViews: ({ commit }, view) => {
|
||||
addVisitedViews({ commit }, view) {
|
||||
commit('ADD_VISITED_VIEWS', view)
|
||||
},
|
||||
delVisitedViews: ({ commit }, view) => {
|
||||
commit('DEL_VISITED_VIEWS', view)
|
||||
delVisitedViews({ commit, state }, view) {
|
||||
return new Promise((resolve) => {
|
||||
commit('DEL_VISITED_VIEWS', view)
|
||||
resolve([...state.visitedViews])
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -2,7 +2,7 @@
|
||||
<div class="components-container">
|
||||
<code>公司做的后台主要是一个cms系统,公司也是以自媒体为核心的,所以富文本是后台很核心的功能。在选择富文本的过程中也走了不少的弯路,市面上常见的富文本都基本用过了,最终选择了Tinymce<a target='_blank' href='https://segmentfault.com/a/1190000009762198#articleHeader13'> 相关文章 </a> <a target='_blank' href='https://www.tinymce.com/'> 官网 </a></code>
|
||||
<div>
|
||||
<tinymce :height=200 ref="editor" v-model="content"></tinymce>
|
||||
<tinymce :height='200' v-model="content"></tinymce>
|
||||
</div>
|
||||
<div class='editor-content' v-html='content'></div>
|
||||
</div>
|
||||
|
@@ -4,7 +4,7 @@
|
||||
|
||||
<h3>请点击右上角bug小图表</h3>
|
||||
<code>
|
||||
现在的管理后台基本都是spa的形式了,它增强了用户体验,但同时也会怎增加页面出问题的可能性,可能一个小小的疏忽就导致整个页面的死锁。好在Vue官网提供了一个方法来捕获处理异常
|
||||
现在的管理后台基本都是spa的形式了,它增强了用户体验,但同时也会增加页面出问题的可能性,可能一个小小的疏忽就导致整个页面的死锁。好在Vue官网提供了一个方法来捕获处理异常
|
||||
</code>
|
||||
<a href="#"><img src='http://panjiachen.github.io/images/errHandler.png'></a>
|
||||
</div>
|
||||
|
@@ -236,6 +236,7 @@ export default {
|
||||
})
|
||||
},
|
||||
handleFilter() {
|
||||
this.listQuery.page = 1
|
||||
this.getList()
|
||||
},
|
||||
handleSizeChange(val) {
|
||||
|
29
src/views/excel/uploadExcel.vue
Normal file
29
src/views/excel/uploadExcel.vue
Normal file
@@ -0,0 +1,29 @@
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<upload-excel @on-selected-file='selected'></upload-excel>
|
||||
<el-table :data="tableData" border highlight-current-row style="width: 100%;margin-top:20px;">
|
||||
<el-table-column v-for='item of tableHeader' :prop="item" :label="item" :key='item'>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import uploadExcel from 'components/UploadExcel/index.vue'
|
||||
|
||||
export default {
|
||||
components: { uploadExcel },
|
||||
data() {
|
||||
return {
|
||||
tableData: [],
|
||||
tableHeader: []
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
selected(data) {
|
||||
this.tableData = data.results
|
||||
this.tableHeader = data.header
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
@@ -17,7 +17,16 @@ export default {
|
||||
},
|
||||
methods: {
|
||||
closeViewTabs(view, $event) {
|
||||
this.$store.dispatch('delVisitedViews', view)
|
||||
this.$store.dispatch('delVisitedViews', view).then((views) => {
|
||||
if (this.isActive(view.path)) {
|
||||
const latestView = views.slice(-1)[0]
|
||||
if (latestView) {
|
||||
this.$router.push(latestView.path)
|
||||
} else {
|
||||
this.$router.push('/')
|
||||
}
|
||||
}
|
||||
})
|
||||
$event.preventDefault()
|
||||
},
|
||||
generateRoute() {
|
||||
|
@@ -3,7 +3,7 @@
|
||||
<el-card class="box-card">
|
||||
<div slot="header">
|
||||
<span style="line-height: 36px;">偏好设置</span>
|
||||
<a class='link-type link-title' target="_blank" href='https://segmentfault.com/a/1190000009762198#articleHeader2'>态换肤的教程</a>
|
||||
<a class='link-type link-title' target="_blank" href='https://segmentfault.com/a/1190000009762198#articleHeader2'>动态换肤的教程</a>
|
||||
</div>
|
||||
<div class="box-item">
|
||||
<span class="field-label">换肤:</span>
|
||||
|
Reference in New Issue
Block a user