Compare commits

...

25 Commits

Author SHA1 Message Date
Pan
db61251d89 [release] 2.1.1 2017-09-25 17:41:03 +08:00
Pan
582c6f4ae4 refine:set icon-class to english 2017-09-25 17:31:23 +08:00
Pan
9c2a7e9485 refine : format code 2017-09-25 14:21:42 +08:00
lei.jiang
fde12e8ef9 修改MdInput的demo,使之能展现验证功能 2017-09-25 11:11:37 +08:00
lei.jiang
8945476c22 修改MDinput组件
1.使之能兼容elementui的表单验证功能
2.增加icon属性,能够使用elementui的图标
3.优化显示效果
2017-09-25 11:11:37 +08:00
lei.jiang
14ff09a414 修改MDinput组件
1.使之能兼容elementui的表单验证功能
2.增加icon属性,能够使用elementui的图标
3.优化显示效果
2017-09-25 11:11:37 +08:00
Pan
a14547aaf9 add tips 2017-09-12 10:39:03 +08:00
Pan
b1311322ad [release] 2.1.0 2017-09-11 14:45:55 +08:00
Pan
ffec6b6df7 add:upload excel 2017-09-11 14:43:12 +08:00
Pan
f0afbf7ea5 refine:set page=1 when table filter 2017-09-11 11:17:29 +08:00
Pan
a4f8e0b805 Update README.md 2017-09-11 10:56:28 +08:00
花裤衩
2d72df3605 Update README.md 2017-09-08 20:10:54 +08:00
花裤衩
e9f92a7d3d Update README.md 2017-09-08 18:32:48 +08:00
花裤衩
ee362f22b2 Update README.md 2017-09-08 18:32:15 +08:00
花裤衩
11426c8494 add donate 2017-09-08 18:24:43 +08:00
Hex
fa5f5e9d26 与 vue-cli webpack 模板不一致 2017-09-08 15:53:09 +08:00
dongsuo
cda292dec1 fix blocked by AdBlock 2017-09-07 10:35:35 +08:00
Svend
877b73cd67 📝 typing fix 2017-09-06 10:20:31 +08:00
maemo
53d7243316 fix a typo 2017-09-05 13:53:24 +08:00
Pan
5379510013 refine tabsview 2017-09-01 10:59:45 +08:00
Pan
f712d4682e add:when active tabs closed will go to last path 2017-09-01 10:46:20 +08:00
Pan
cb0e889829 fix tinymce bug 2017-09-01 10:12:50 +08:00
Pan
6a8a02f839 refine tinymce 2017-09-01 10:04:08 +08:00
Pan
d56cd59474 refine code 2017-08-30 18:22:32 +08:00
Pan
a10cfcc837 add tinymce upload demo 2017-08-30 14:41:10 +08:00
48 changed files with 595 additions and 349 deletions

View File

@@ -1,29 +1,19 @@
[![vue](https://img.shields.io/badge/vue-2.4.2-brightgreen.svg)](https://github.com/vuejs/vue)
[![element-ui](https://img.shields.io/badge/element--ui-1.4.2-brightgreen.svg)](https://github.com/ElemeFE/element)
[![license](https://img.shields.io/github/license/mashape/apistatus.svg)](https://github.com/PanJiaChen/vue-element-admin/blob/master/LICENSE)
[![GitHub release](https://img.shields.io/github/release/PanJiaChen/vue-element-admin.svg)]()
## 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
![donate](https://panjiachen.github.io/donate/donation.png)
## 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

View File

@@ -1,7 +1,7 @@
# vue-element-admin #
[![vue](https://img.shields.io/badge/vue-2.4.2-brightgreen.svg)](https://github.com/vuejs/vue)
[![element-ui](https://img.shields.io/badge/element--ui-1.4.1-brightgreen.svg)](https://github.com/ElemeFE/element)
[![element-ui](https://img.shields.io/badge/element--ui-1.4.2-brightgreen.svg)](https://github.com/ElemeFE/element)
[![license](https://img.shields.io/github/license/mashape/apistatus.svg)](https://github.com/PanJiaChen/vue-element-admin/blob/master/LICENSE)
[![GitHub release](https://img.shields.io/github/release/PanJiaChen/vue-element-admin.svg)]()
@@ -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 @@
- 401404错误页面
- 错误日志
- 导出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
![donate](https://panjiachen.github.io/donate/donation.png)
## 状态管理
后台只有user和app配置相关状态使用vuex存在全局其它数据都由每个业务页面自己管理。

View File

@@ -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]')
}

View File

@@ -1,6 +1,6 @@
{
"name": "juicy",
"version": "2.0.0",
"version": "2.1.1",
"description": "A Vue.js admin",
"author": "Pan <panfree23@gmail.com>",
"license": "MIT",

View File

@@ -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;
}

View File

@@ -1,297 +1,272 @@
<template>
<div class="material-input__component" :class="computedClasses">
<input v-if="type === 'email'" type="email" class="material-input" :name="name" :id="id" :placeholder="placeholder" v-model="valueCopy"
:readonly="readonly" :disabled="disabled" :autocomplete="autocomplete" :required="required" @focus="handleFocus(true)"
@blur="handleFocus(false)" @input="handleModelInput">
<input v-if="type === 'url'" type="url" class="material-input" :name="name" :id="id" :placeholder="placeholder" v-model="valueCopy"
:readonly="readonly" :disabled="disabled" :autocomplete="autocomplete" :required="required" @focus="handleFocus(true)"
@blur="handleFocus(false)" @input="handleModelInput">
<input v-if="type === 'number'" type="number" class="material-input" :name="name" :id="id" :placeholder="placeholder" v-model="valueCopy"
:readonly="readonly" :disabled="disabled" :autocomplete="autocomplete" :max="max" :min="min" :minlength="minlength" :maxlength="maxlength"
:required="required" @focus="handleFocus(true)" @blur="handleFocus(false)" @input="handleModelInput">
<input v-if="type === 'password'" type="password" class="material-input" :name="name" :id="id" :placeholder="placeholder"
v-model="valueCopy" :readonly="readonly" :disabled="disabled" :autocomplete="autocomplete" :max="max" :min="min" :required="required"
@focus="handleFocus(true)" @blur="handleFocus(false)" @input="handleModelInput">
<input v-if="type === 'tel'" type="tel" class="material-input" :name="name" :id="id" :placeholder="placeholder" v-model="valueCopy"
:readonly="readonly" :disabled="disabled" :autocomplete="autocomplete" :required="required" @focus="handleFocus(true)"
@blur="handleFocus(false)" @input="handleModelInput">
<input v-if="type === 'text'" type="text" class="material-input" :name="name" :id="id" :placeholder="placeholder" v-model="valueCopy"
:readonly="readonly" :disabled="disabled" :autocomplete="autocomplete" :minlength="minlength" :maxlength="maxlength"
:required="required" @focus="handleFocus(true)" @blur="handleFocus(false)" @input="handleModelInput">
<span class="material-input-bar"></span>
<label class="material-label">
<slot></slot>
</label>
<div v-if="errorMessages" class="material-errors">
<div v-for="error in computedErrors" class="material-error" :key='error'>
{{ error }}
</div>
<div :class="{iconClass:icon}">
<i class="el-input__icon material-input__icon" :class="['el-icon-' + icon]" v-if="icon"></i>
<input v-if="type === 'email'" type="email" class="material-input" :name="name" :placeholder="fillPlaceHolder" v-model="currentValue"
:readonly="readonly" :disabled="disabled" :autoComplete="autoComplete" :required="required" @focus="handleMdFocus"
@blur="handleMdBlur" @input="handleModelInput">
<input v-if="type === 'url'" type="url" class="material-input" :name="name" :placeholder="fillPlaceHolder" v-model="currentValue"
:readonly="readonly" :disabled="disabled" :autoComplete="autoComplete" :required="required" @focus="handleMdFocus"
@blur="handleMdBlur" @input="handleModelInput">
<input v-if="type === 'number'" type="number" class="material-input" :name="name" :placeholder="fillPlaceHolder" v-model="currentValue"
:step="step" :readonly="readonly" :disabled="disabled" :autoComplete="autoComplete" :max="max" :min="min" :minlength="minlength"
:maxlength="maxlength" :required="required" @focus="handleMdFocus" @blur="handleMdBlur" @input="handleModelInput">
<input v-if="type === 'password'" type="password" class="material-input" :name="name" :placeholder="fillPlaceHolder" v-model="currentValue"
:readonly="readonly" :disabled="disabled" :autoComplete="autoComplete" :max="max" :min="min" :required="required" @focus="handleMdFocus"
@blur="handleMdBlur" @input="handleModelInput">
<input v-if="type === 'tel'" type="tel" class="material-input" :name="name" :placeholder="fillPlaceHolder" v-model="currentValue"
:readonly="readonly" :disabled="disabled" :autoComplete="autoComplete" :required="required" @focus="handleMdFocus"
@blur="handleMdBlur" @input="handleModelInput">
<input v-if="type === 'text'" type="text" class="material-input" :name="name" :placeholder="fillPlaceHolder" v-model="currentValue"
:readonly="readonly" :disabled="disabled" :autoComplete="autoComplete" :minlength="minlength" :maxlength="maxlength"
:required="required" @focus="handleMdFocus" @blur="handleMdBlur" @input="handleModelInput">
<span class="material-input-bar"></span>
<label class="material-label">
<slot></slot>
</label>
</div>
</div>
</template>
<script>
// source:https://github.com/wemake-services/vue-material-input/blob/master/src/components/MaterialInput.vue
// source:https://github.com/wemake-services/vue-material-input/blob/master/src/components/MaterialInput.vue
export default {
name: 'material-input',
computed: {
computedErrors() {
return typeof this.errorMessages === 'string'
? [this.errorMessages] : this.errorMessages
name: 'md-input',
props: {
icon: String,
name: String,
type: {
type: String,
default: 'text'
},
value: [String, Number],
placeholder: String,
readonly: Boolean,
disabled: Boolean,
min: String,
max: String,
step: String,
minlength: Number,
maxlength: Number,
required: {
type: Boolean,
default: true
},
autoComplete: {
type: String,
default: 'off'
},
validateEvent: {
type: Boolean,
default: true
}
},
computed: {
computedClasses() {
return {
'material--active': this.focus,
'material--disabled': this.disabled,
'material--has-errors': Boolean(!this.valid || (this.errorMessages && this.errorMessages.length)),
'material--raised': Boolean(this.focus || this.valueCopy || // has value
(this.placeholder && !this.valueCopy)) // has placeholder
'material--raised': Boolean(this.focus || this.currentValue) // has value
}
}
},
data() {
return {
valueCopy: null,
currentValue: this.value,
focus: false,
valid: true
fillPlaceHolder: null
}
},
beforeMount() {
// Here we are following the Vue2 convention on custom v-model:
// https://github.com/vuejs/vue/issues/2873#issuecomment-223759341
this.copyValue(this.value)
},
methods: {
handleModelInput(event) {
this.$emit('input', event.target.value, event)
this.handleValidation()
const value = event.target.value
this.$emit('input', value)
if (this.$parent.$options.componentName === 'ElFormItem') {
if (this.validateEvent) {
this.$parent.$emit('el.form.change', [value])
}
}
this.$emit('change', value)
},
handleFocus(focused) {
this.focus = focused
handleMdFocus(event) {
this.focus = true
this.$emit('focus', event)
if (this.placeholder && this.placeholder !== '') {
this.fillPlaceHolder = this.placeholder
}
},
handleValidation() {
this.valid = this.$el ? this.$el.querySelector('.material-input').validity.valid : this.valid
},
copyValue(value) {
this.valueCopy = value
this.handleValidation()
}
},
watch: {
value(newValue) {
this.copyValue(newValue)
}
},
props: {
id: {
type: String,
default: null
},
name: {
type: String,
default: null
},
type: {
type: String,
default: 'text'
},
value: {
default: null
},
placeholder: {
type: String,
default: null
},
readonly: {
type: Boolean,
default: false
},
disabled: {
type: Boolean,
default: false
},
min: {
type: String,
default: null
},
max: {
type: String,
default: null
},
minlength: {
type: Number,
default: null
},
maxlength: {
type: Number,
default: null
},
required: {
type: Boolean,
default: true
},
autocomplete: {
type: String,
default: 'off'
},
errorMessages: {
type: [Array, String],
default: null
handleMdBlur(event) {
this.focus = false
this.$emit('blur', event)
this.fillPlaceHolder = null
if (this.$parent.$options.componentName === 'ElFormItem') {
if (this.validateEvent) {
this.$parent.$emit('el.form.blur', [this.currentValue])
}
}
}
}
}
</script>
<style rel="stylesheet/scss" lang="scss" scoped>
// Fonts:
$font-size-base: 16px;
$font-size-small: 18px;
$font-size-smallest: 12px;
$font-weight-normal: normal;
// Utils
$spacer: 12px;
$transition: 0.2s ease all;
// Base clases:
%base-bar-pseudo {
content: '';
height: 1px;
width: 0;
bottom: 0;
// Fonts:
$font-size-base: 16px;
$font-size-small: 18px;
$font-size-smallest: 12px;
$font-weight-normal: normal;
$font-weight-bold: bold;
$apixel: 1px;
// Utils
$spacer: 12px;
$transition: 0.2s ease all;
$index: 0px;
$index-has-icon: 30px;
// Theme:
$color-white: white;
$color-grey: #9E9E9E;
$color-grey-light: #E0E0E0;
$color-blue: #2196F3;
$color-red: #F44336;
$color-black: black;
// Base clases:
%base-bar-pseudo {
content: '';
height: 1px;
width: 0;
bottom: 0;
position: absolute;
transition: $transition;
}
// Mixins:
@mixin slided-top() {
top: - ($font-size-base + $spacer);
left: 0;
font-size: $font-size-base;
font-weight: $font-weight-bold;
}
// Component:
.material-input__component {
margin-top: 36px;
position: relative;
* {
box-sizing: border-box;
}
.iconClass {
.material-input__icon {
position: absolute;
transition: $transition;
left: 0;
color: $color-blue;
top: $spacer;
width: $index-has-icon;
height: $font-size-base;
font-size: $font-size-base;
font-weight: $font-weight-normal;
pointer-events: none;
}
.material-label {
left: $index-has-icon;
}
.material-input {
text-indent: $index-has-icon;
}
}
.material-input {
font-size: $font-size-base;
padding: $spacer $spacer $spacer - $apixel * 10 $spacer / 2;
display: block;
width: 100%;
border: none;
line-height: 1;
border-radius: 0;
&:focus {
outline: none;
border: none;
border-bottom: 1px solid transparent; // fixes the height issue
}
}
.material-label {
font-weight: $font-weight-normal;
position: absolute;
pointer-events: none;
left: $index;
top: 0;
transition: $transition;
font-size: $font-size-small;
}
.material-input-bar {
position: relative;
display: block;
width: 100%;
&:before {
@extend %base-bar-pseudo;
left: 50%;
}
&:after {
@extend %base-bar-pseudo;
right: 50%;
}
}
// Disabled state:
&.material--disabled {
.material-input {
border-bottom-style: dashed;
}
}
// Raised state:
&.material--raised {
.material-label {
@include slided-top();
}
}
// Active state:
&.material--active {
.material-input-bar {
&:before,
&:after {
width: 50%;
}
}
}
}
// Mixins:
@mixin slided-top() {
top: -2 * $spacer;
font-size: $font-size-small;
.material-input__component {
background: $color-white;
.material-input {
background: none;
color: $color-black;
text-indent: $index;
border-bottom: 1px solid $color-grey-light;
}
// Component:
.material-input__component {
/*margin-top: 30px;*/
position: relative;
* {
box-sizing: border-box;
}
.material-input {
font-size: $font-size-base;
padding: $spacer $spacer $spacer $spacer / 2;
display: block;
width: 100%;
border: none;
border-radius: 0;
&:focus {
outline: none;
border: none;
border-bottom: 1px solid transparent; // fixes the height issue
}
}
.material-label {
font-size: $font-size-base;
font-weight: $font-weight-normal;
position: absolute;
pointer-events: none;
left: 0;
top: $spacer;
transition: $transition;
}
.material-input-bar {
position: relative;
display: block;
width: 100%;
&:before {
@extend %base-bar-pseudo;
left: 50%;
}
&:after {
@extend %base-bar-pseudo;
right: 50%;
}
}
// Disabled state:
&.material--disabled {
.material-input {
border-bottom-style: dashed;
}
}
// Raised state:
&.material--raised {
.material-label {
@include slided-top();
}
}
// Active state:
&.material--active {
.material-input-bar {
&:before,
&:after {
width: 50%;
}
}
}
// Errors:
.material-errors {
position: relative;
overflow: hidden;
.material-error {
font-size: $font-size-smallest;
line-height: $font-size-smallest + 2px;
overflow: hidden;
margin-top: 0;
padding-top: $spacer / 2;
padding-right: $spacer / 2;
padding-left: 0;
}
}
.material-label {
color: $color-grey;
}
// Theme:
$color-white: white;
$color-grey: #9E9E9E;
$color-grey-light: #E0E0E0;
$color-blue: #2196F3;
$color-red: #F44336;
$color-black: black;
.material-input__component {
background: $color-white;
.material-input {
background: none;
color: $color-black;
text-indent: 30px;
border-bottom: 1px solid $color-grey-light;
}
.material-label {
color: $color-grey;
}
.material-input-bar {
&:before,
&:after {
background: $color-blue;
}
}
// Active state:
&.material--active {
.material-label {
color: $color-blue;
}
}
// Errors:
&.material--has-errors {
&.material--active .material-label {
color: $color-red;
}
.material-input-bar {
&:before,
&:after {
background: $color-red;
}
}
.material-errors {
color: $color-red;
}
}
.material-input-bar {
&:before,
&:after {
background: $color-blue;
}
}
// Active state:
&.material--active {
.material-label {
color: $color-blue;
}
}
// Errors:
&.material--has-errors {
&.material--active .material-label {
color: $color-red;
}
.material-input-bar {
&:before,
&:after {
background: transparent;
}
}
}
}
</style>

View 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>

View File

@@ -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>

View 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>

View File

Before

Width:  |  Height:  |  Size: 552 B

After

Width:  |  Height:  |  Size: 552 B

View File

@@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1506329916765" class="icon" style="" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1661" xmlns:xlink="http://www.w3.org/1999/xlink" width="64" height="64"><defs><style type="text/css"></style></defs><path d="M64 64 448 64 448 448 64 448 64 64ZM64 576 448 576 448 960 64 960 64 576ZM576 576 960 576 960 960 576 960 576 576ZM768 448C874.038669 448 960 362.038672 960 256 960 149.961328 874.038669 64 768 64 661.961328 64 576 149.961328 576 256 576 362.038672 661.961328 448 768 448Z" p-id="1662"></path></svg>

After

Width:  |  Height:  |  Size: 683 B

View File

Before

Width:  |  Height:  |  Size: 983 B

After

Width:  |  Height:  |  Size: 983 B

View File

Before

Width:  |  Height:  |  Size: 1.0 KiB

After

Width:  |  Height:  |  Size: 1.0 KiB

View File

Before

Width:  |  Height:  |  Size: 866 B

After

Width:  |  Height:  |  Size: 866 B

View File

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

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

@@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1506330387278" class="icon" style="" viewBox="0 0 1069 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1447" xmlns:xlink="http://www.w3.org/1999/xlink" width="66.8125" height="64"><defs><style type="text/css"></style></defs><path d="M746.027944 190.083832q-11.241517 0-18.906188-7.664671t-12.774451-17.884232-7.664671-20.9501-2.55489-17.884232l0-125.700599 2.043912 0q9.197605 0 17.373253 2.043912t19.928144 9.708583 28.61477 21.461078 42.411178 36.279441q27.592814 24.526946 43.944112 41.389222t25.037924 28.61477 10.730539 19.928144 2.043912 14.307385l0 16.351297-150.227545 0zM1063.856287 671.42515q3.065868 8.175649 4.087824 20.439122t-10.219561 23.50499q-5.10978 5.10978-9.197605 9.708583t-7.153693 7.664671q-4.087824 4.087824-7.153693 6.131737l-86.866267-85.844311q6.131737-5.10978 13.796407-12.263473t12.774451-11.241517q12.263473-11.241517 26.570858-9.708583t23.50499 6.642715q10.219561 5.10978 21.972056 17.884232t17.884232 27.081836zM703.105788 766.467066q22.483034 0 37.812375-12.263473l-198.259481 206.43513-282.05988 0q-19.417166 0-42.411178-11.241517t-42.922156-29.636727-33.213573-42.411178-13.285429-49.56487l0-695.952096q0-21.461078 9.708583-44.966068t26.570858-42.411178 38.323353-31.680639 44.966068-12.774451l391.409182 0 0 127.744511q0 19.417166 6.131737 41.9002t18.906188 41.389222 33.213573 31.680639 49.053892 12.774451l149.205589 0 0 338.267465-140.007984 145.117764q11.241517-16.351297 11.241517-35.768463 0-26.570858-18.906188-45.477046t-45.477046-18.906188l-383.233533 0q-26.570858 0-44.966068 18.906188t-18.39521 45.477046 18.39521 44.966068 44.966068 18.39521l383.233533 0zM319.872255 383.233533q-26.570858 0-44.966068 18.906188t-18.39521 45.477046 18.39521 44.966068 44.966068 18.39521l383.233533 0q26.570858 0 45.477046-18.39521t18.906188-44.966068-18.906188-45.477046-45.477046-18.906188l-383.233533 0zM705.149701 895.233533l13.285429-13.285429 25.548902-25.548902q15.329341-15.329341 33.724551-34.235529t36.790419-37.301397q43.944112-43.944112 99.129741-98.107784l85.844311 85.844311-99.129741 99.129741-36.790419 36.790419-33.724551 33.724551q-14.307385 14.307385-24.015968 24.526946t-10.730539 11.241517q-5.10978 4.087824-11.241517 8.686627t-12.263473 7.664671-18.906188 7.664671-26.05988 8.686627-25.548902 7.153693-18.39521 4.087824q-12.263473 2.043912-16.351297-3.065868t-2.043912-17.373253q1.021956-6.131737 4.087824-18.39521t7.153693-25.037924 7.664671-24.015968 5.620758-15.329341q6.131737-13.285429 16.351297-23.50499z" p-id="1448"></path></svg>

After

Width:  |  Height:  |  Size: 2.6 KiB

View File

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

Before

Width:  |  Height:  |  Size: 591 B

View File

Before

Width:  |  Height:  |  Size: 1.0 KiB

After

Width:  |  Height:  |  Size: 1.0 KiB

View File

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

Before

Width:  |  Height:  |  Size: 8.0 KiB

After

Width:  |  Height:  |  Size: 8.0 KiB

View File

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

Before

Width:  |  Height:  |  Size: 602 B

View File

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@@ -1 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1503994012480" class="icon" style="" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="8212" xmlns:xlink="http://www.w3.org/1999/xlink" width="64" height="64"><defs><style type="text/css"></style></defs><path d="M896 320H128V160c0-17.6 14.4-32 32-32h704c17.6 0 32 14.4 32 32v160zM320 896H160c-17.6 0-32-14.4-32-32V384h192v512zM864 896H384V384h512v480c0 17.6-14.4 32-32 32z" p-id="8213"></path></svg>
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1506329761546" class="icon" style="" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1384" xmlns:xlink="http://www.w3.org/1999/xlink" width="64" height="64"><defs><style type="text/css"></style></defs><path d="M622.276923 39.384615H401.723077c-13.784615 0-23.630769 11.815385-23.630769 25.6v49.23077c0 13.784615 11.815385 25.6 23.630769 25.6h220.553846c13.784615 0 23.630769-11.815385 23.630769-25.6V64.984615c1.969231-13.784615-9.846154-25.6-23.630769-25.6z m336.738462 0H738.461538c-13.784615 0-25.6 11.815385-25.6 25.6v49.23077c0 13.784615 11.815385 25.6 25.6 25.6h220.553847c13.784615-1.969231 25.6-11.815385 25.6-25.6V64.984615c0-13.784615-11.815385-25.6-25.6-25.6z m0 165.415385H334.769231c-13.784615 0-25.6-11.815385-25.6-25.6V64.984615c0-13.784615-11.815385-25.6-25.6-25.6H64.984615C51.2 39.384615 39.384615 51.2 39.384615 64.984615v896c0 11.815385 11.815385 23.630769 25.6 23.63077h894.03077c13.784615 0 25.6-11.815385 25.6-25.6v-728.615385c0-13.784615-11.815385-25.6-25.6-25.6z" p-id="1385"></path></svg>

Before

Width:  |  Height:  |  Size: 571 B

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

Before

Width:  |  Height:  |  Size: 678 B

After

Width:  |  Height:  |  Size: 678 B

View File

Before

Width:  |  Height:  |  Size: 678 B

After

Width:  |  Height:  |  Size: 678 B

View File

Before

Width:  |  Height:  |  Size: 673 B

After

Width:  |  Height:  |  Size: 673 B

View File

Before

Width:  |  Height:  |  Size: 777 B

After

Width:  |  Height:  |  Size: 777 B

View File

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

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

Before

Width:  |  Height:  |  Size: 534 B

View File

@@ -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)

View File

@@ -1 +1 @@
module.exports = file => require('@/views/' + file + '.vue').default
module.exports = file => require('@/views/' + file + '.vue').default // vue-loader at least v13.0.0+

View File

@@ -32,7 +32,7 @@ export const constantRouterMap = [
path: '/introduction',
component: Layout,
redirect: '/introduction/index',
icon: 'xinrenzhinan',
icon: 'people',
noDropdown: true,
children: [{ path: 'index', component: _import('introduction/index'), name: '简述' }]
}
@@ -50,7 +50,7 @@ export const asyncRouterMap = [
component: Layout,
redirect: '/permission/index',
name: '权限测试',
icon: 'quanxian',
icon: 'lock',
meta: { role: ['admin'] },
noDropdown: true,
children: [{ path: 'index', component: _import('permission/index'), name: '权限测试页', meta: { role: ['admin'] }}]
@@ -58,7 +58,7 @@ export const asyncRouterMap = [
{
path: '/icon',
component: Layout,
icon: 'icons',
icon: 'icon',
noDropdown: true,
children: [{ path: 'index', component: _import('svg-icons/index'), name: 'icons' }]
},
@@ -67,7 +67,7 @@ export const asyncRouterMap = [
component: Layout,
redirect: '/components/index',
name: '组件',
icon: 'zujian',
icon: 'component',
children: [
{ path: 'index', component: _import('components/index'), name: '介绍 ' },
{ path: 'tinymce', component: _import('components/tinymce'), name: '富文本编辑器' },
@@ -88,7 +88,7 @@ export const asyncRouterMap = [
component: Layout,
redirect: '/charts/index',
name: '图表',
icon: 'tubiao',
icon: 'chart',
children: [
{ path: 'index', component: _import('charts/index'), name: '介绍' },
{ path: 'keyboard', component: _import('charts/keyboard'), name: '键盘图表' },
@@ -102,7 +102,7 @@ export const asyncRouterMap = [
component: Layout,
redirect: 'noredirect',
name: '综合实例',
icon: 'zonghe',
icon: 'example',
children: [
{
path: '/example/table',
@@ -117,8 +117,8 @@ export const asyncRouterMap = [
{ path: 'table', component: _import('example/table/table'), name: '综合table' }
]
},
{ path: 'form/edit', icon: 'shouce', component: _import('example/form'), name: '编辑Form', meta: { isEdit: true }},
{ path: 'form/create', icon: 'from', component: _import('example/form'), name: '创建Form' },
{ path: 'form/edit', icon: 'form', component: _import('example/form'), name: '编辑Form', meta: { isEdit: true }},
{ path: 'form/create', icon: 'form', component: _import('example/form'), name: '创建Form' },
{ path: 'tab/index', icon: 'tab', component: _import('example/tab/index'), name: 'Tab' }
]
},
@@ -147,10 +147,11 @@ export const asyncRouterMap = [
component: Layout,
redirect: '/excel/download',
name: 'excel',
icon: 'EXCEL',
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' }
]
},
{

View File

@@ -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])
})
}
}
}

View File

@@ -1,9 +1,11 @@
<template>
<div class="components-container">
<div class='component-item'>
<md-input name="name" v-model="title" required :maxlength="100">
标题
</md-input>
<el-form :model="demo" :rules="demoRules">
<el-form-item prop="title">
<md-input icon="search" name="title" placeholder="输入标题" v-model="demo.title">标题</md-input>
</el-form-item>
</el-form>
<code class='code-part'>Material Design 的input</code>
</div>
@@ -22,18 +24,33 @@
</template>
<script>
import MdInput from '@/components/MDinput'
import PanThumb from '@/components/PanThumb'
import MdInput from '@/components/MDinput'
import waves from '@/directive/waves.js' // 水波纹指令
export default {
components: { MdInput, PanThumb },
components: {
PanThumb,
MdInput
},
directives: {
waves
},
data() {
const validate = (rule, value, callback) => {
if (value.length !== 6) {
callback(new Error('请输入六个字符'))
} else {
callback()
}
}
return {
title: ''
demo: {
title: ''
},
demoRules: {
title: [{ required: true, trigger: 'change', validator: validate }]
}
}
}
}

View File

@@ -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>

View File

@@ -34,12 +34,12 @@
<div class="info-item">
<count-to class="info-item-num" :startVal='0' :endVal='statisticsData.article_count' :duration='3400'></count-to>
<span class="info-item-text">文章</span>
<icon-svg icon-class="a" class="dashboard-editor-icon"></icon-svg>
<icon-svg icon-class="trendChart1" class="dashboard-editor-icon"></icon-svg>
</div>
<div class="info-item">
<count-to class="info-item-num" :startVal='0' :endVal='statisticsData.pageviews_count' :duration='3600'></count-to>
<span class="info-item-text">浏览量</span>
<icon-svg icon-class="b" class="dashboard-editor-icon"></icon-svg>
<icon-svg icon-class="trendChart2" class="dashboard-editor-icon"></icon-svg>
</div>
</el-card>
</el-col>

View File

@@ -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>

View File

@@ -29,7 +29,7 @@
<el-table-column width="80px" label="重要性">
<template scope="scope">
<icon-svg v-for="n in +scope.row.importance" icon-class="wujiaoxing" :key="n"></icon-svg>
<icon-svg v-for="n in +scope.row.importance" icon-class="star" :key="n"></icon-svg>
</template>
</el-table-column>

View File

@@ -29,7 +29,7 @@
<el-table-column width="80px" label="重要性">
<template scope="scope">
<icon-svg v-for="n in +scope.row.importance" icon-class="wujiaoxing" class="meta-item__icon" :key="n"></icon-svg>
<icon-svg v-for="n in +scope.row.importance" icon-class="star" class="meta-item__icon" :key="n"></icon-svg>
</template>
</el-table-column>
@@ -47,7 +47,7 @@
<el-table-column align="center" label="拖拽" width="95">
<template scope="scope">
<icon-svg class='drag-handler' icon-class="tuozhuai"></icon-svg>
<icon-svg class='drag-handler' icon-class="drag"></icon-svg>
</template>
</el-table-column>

View File

@@ -23,7 +23,7 @@
<el-table-column width="100px" label="重要性">
<template scope="scope">
<icon-svg v-for="n in +scope.row.importance" icon-class="wujiaoxing" class="meta-item__icon" :key="n"></icon-svg>
<icon-svg v-for="n in +scope.row.importance" icon-class="star" class="meta-item__icon" :key="n"></icon-svg>
</template>
</el-table-column>

View File

@@ -60,7 +60,7 @@
<el-table-column width="80px" label="重要性">
<template scope="scope">
<icon-svg v-for="n in +scope.row.importance" icon-class="wujiaoxing" class="meta-item__icon" :key="n"></icon-svg>
<icon-svg v-for="n in +scope.row.importance" icon-class="star" class="meta-item__icon" :key="n"></icon-svg>
</template>
</el-table-column>
@@ -236,6 +236,7 @@ export default {
})
},
handleFilter() {
this.listQuery.page = 1
this.getList()
},
handleSizeChange(val) {

View 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>

View File

@@ -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() {

View File

@@ -5,18 +5,18 @@
<el-form-item prop="username">
<span class="svg-container svg-container_login">
<icon-svg icon-class="yonghuming" />
<icon-svg icon-class="user" />
</span>
<el-input name="username" type="text" v-model="loginForm.username" autoComplete="on" placeholder="邮箱" />
</el-form-item>
<el-form-item prop="password">
<span class="svg-container">
<icon-svg icon-class="mima" />
<icon-svg icon-class="password" />
</span>
<el-input name="password" :type="pwdType" @keyup.enter.native="handleLogin" v-model="loginForm.password" autoComplete="on"
placeholder="密码" />
<span class='show-pwd' @click='showPwd'><icon-svg icon-class="yanjing" /></span>
<span class='show-pwd' @click='showPwd'><icon-svg icon-class="eye" /></span>
</el-form-item>
<el-button type="primary" style="width:100%;margin-bottom:30px;" :loading="loading" @click.native.prevent="handleLogin">登录</el-button>

View File

@@ -1,10 +1,10 @@
<template>
<div class="social-signup-container">
<div class="sign-btn" @click="wechatHandleClick('wechat')">
<span class="wx-svg-container"><icon-svg icon-class="weixin" class="icon"></icon-svg></span> 微信
<span class="wx-svg-container"><icon-svg icon-class="wechat" class="icon"></icon-svg></span> 微信
</div>
<div class="sign-btn" @click="tencentHandleClick('tencent')">
<span class="qq-svg-container"><icon-svg icon-class="QQ" class="icon"></icon-svg></span> QQ
<span class="qq-svg-container"><icon-svg icon-class="qq" class="icon"></icon-svg></span> QQ
</div>
</div>
</template>

View File

@@ -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>