-
+
-
diff --git a/src/components/SvgIcon/index.vue b/src/components/SvgIcon/index.vue
new file mode 100644
index 00000000..e331a27e
--- /dev/null
+++ b/src/components/SvgIcon/index.vue
@@ -0,0 +1,42 @@
+
+
+
+
+
+
+
diff --git a/src/components/TextHoverEffect/Mallki.vue b/src/components/TextHoverEffect/Mallki.vue
new file mode 100644
index 00000000..7e975dc8
--- /dev/null
+++ b/src/components/TextHoverEffect/Mallki.vue
@@ -0,0 +1,113 @@
+
+
+ {{text}}
+
+
+
+
+
+
+
+
+
diff --git a/src/components/ThemePicker/index.vue b/src/components/ThemePicker/index.vue
new file mode 100644
index 00000000..b3791c4c
--- /dev/null
+++ b/src/components/ThemePicker/index.vue
@@ -0,0 +1,145 @@
+
+
+
+
+
+
+
diff --git a/src/components/Tinymce/components/editorImage.vue b/src/components/Tinymce/components/editorImage.vue
new file mode 100644
index 00000000..b0347cf8
--- /dev/null
+++ b/src/components/Tinymce/components/editorImage.vue
@@ -0,0 +1,95 @@
+
+
+ 上传图片
+
+
+
+ 点击上传
+
+ 取 消
+ 确 定
+
+
+
+
+
+
+
diff --git a/src/components/Tinymce/index.vue b/src/components/Tinymce/index.vue
index 403e028b..3367bd03 100644
--- a/src/components/Tinymce/index.vue
+++ b/src/components/Tinymce/index.vue
@@ -1,154 +1,152 @@
-
-
+
@@ -156,18 +154,16 @@
.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;
}
diff --git a/src/components/Upload/singleImage.vue b/src/components/Upload/singleImage.vue
index f4a0a546..18b892fe 100644
--- a/src/components/Upload/singleImage.vue
+++ b/src/components/Upload/singleImage.vue
@@ -1,14 +1,7 @@
-
+
将文件拖到此处,或点击上传
@@ -22,53 +15,55 @@
+
diff --git a/src/components/Upload/singleImage3.vue b/src/components/Upload/singleImage3.vue
index 2a01d0e1..4183b88c 100644
--- a/src/components/Upload/singleImage3.vue
+++ b/src/components/Upload/singleImage3.vue
@@ -1,154 +1,146 @@
-
-
-
- 将文件拖到此处,或点击上传
-
-
-
-
  全球 付费节目单 最热 经济
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+ 将文件拖到此处,或点击上传
+
+
+
+
  全球 付费节目单 最热 经济
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/components/UploadExcel/index.vue b/src/components/UploadExcel/index.vue
new file mode 100644
index 00000000..f02aeae7
--- /dev/null
+++ b/src/components/UploadExcel/index.vue
@@ -0,0 +1,78 @@
+
+
+ select excel file
+
+
+
+
+
+
+
diff --git a/src/components/jsonEditor/index.vue b/src/components/jsonEditor/index.vue
deleted file mode 100644
index c49d482f..00000000
--- a/src/components/jsonEditor/index.vue
+++ /dev/null
@@ -1,64 +0,0 @@
-
-
-
-
-
-
-
-
-
-
diff --git a/src/components/twoDndList/index.vue b/src/components/twoDndList/index.vue
deleted file mode 100644
index c7c3577e..00000000
--- a/src/components/twoDndList/index.vue
+++ /dev/null
@@ -1,156 +0,0 @@
-
-
-
-
{{list1Title}}
-
-
-
[{{element.author}}] {{element.title}}
-
-
-
-
-
-
-
-
-
-
-
{{list2Title}}
-
-
-
[{{element.author}}] {{element.title}}
-
-
-
-
-
-
-
-
-
diff --git a/src/directive/clipboard/clipboard.js b/src/directive/clipboard/clipboard.js
new file mode 100644
index 00000000..49c9b391
--- /dev/null
+++ b/src/directive/clipboard/clipboard.js
@@ -0,0 +1,49 @@
+// Inspired by https://github.com/Inndy/vue-clipboard2
+const Clipboard = require('clipboard')
+if (!Clipboard) {
+ throw new Error('you shold npm install `clipboard` --save at first ')
+}
+
+export default {
+ bind(el, binding) {
+ if (binding.arg === 'success') {
+ el._v_clipboard_success = binding.value
+ } else if (binding.arg === 'error') {
+ el._v_clipboard_error = binding.value
+ } else {
+ const clipboard = new Clipboard(el, {
+ text() { return binding.value },
+ action() { return binding.arg === 'cut' ? 'cut' : 'copy' }
+ })
+ clipboard.on('success', e => {
+ const callback = el._v_clipboard_success
+ callback && callback(e) // eslint-disable-line
+ })
+ clipboard.on('error', e => {
+ const callback = el._v_clipboard_error
+ callback && callback(e) // eslint-disable-line
+ })
+ el._v_clipboard = clipboard
+ }
+ },
+ update(el, binding) {
+ if (binding.arg === 'success') {
+ el._v_clipboard_success = binding.value
+ } else if (binding.arg === 'error') {
+ el._v_clipboard_error = binding.value
+ } else {
+ el._v_clipboard.text = function() { return binding.value }
+ el._v_clipboard.action = function() { return binding.arg === 'cut' ? 'cut' : 'copy' }
+ }
+ },
+ unbind(el, binding) {
+ if (binding.arg === 'success') {
+ delete el._v_clipboard_success
+ } else if (binding.arg === 'error') {
+ delete el._v_clipboard_error
+ } else {
+ el._v_clipboard.destroy()
+ delete el._v_clipboard
+ }
+ }
+}
diff --git a/src/directive/clipboard/index.js b/src/directive/clipboard/index.js
new file mode 100644
index 00000000..02c98163
--- /dev/null
+++ b/src/directive/clipboard/index.js
@@ -0,0 +1,13 @@
+import Clipboard from './clipboard'
+
+const install = function(Vue) {
+ Vue.directive('Clipboard', Clipboard)
+}
+
+if (window.Vue) {
+ window.clipboard = Clipboard
+ Vue.use(install); // eslint-disable-line
+}
+
+Clipboard.install = install
+export default Clipboard
diff --git a/src/directive/sticky.js b/src/directive/sticky.js
index 7eb9e0f4..bc234660 100644
--- a/src/directive/sticky.js
+++ b/src/directive/sticky.js
@@ -1,99 +1,91 @@
-(function() {
- const vueSticky = {};
- let listenAction;
- vueSticky.install = Vue => {
- Vue.directive('sticky', {
- inserted(el, binding) {
- const params = binding.value || {},
- stickyTop = params.stickyTop || 0,
- zIndex = params.zIndex || 1000,
- elStyle = el.style;
+const vueSticky = {}
+let listenAction
+vueSticky.install = Vue => {
+ Vue.directive('sticky', {
+ inserted(el, binding) {
+ const params = binding.value || {}
+ const stickyTop = params.stickyTop || 0
+ const zIndex = params.zIndex || 1000
+ const elStyle = el.style
- elStyle.position = '-webkit-sticky';
- elStyle.position = 'sticky';
- // if the browser support css sticky(Currently Safari, Firefox and Chrome Canary)
- // if (~elStyle.position.indexOf('sticky')) {
- // elStyle.top = `${stickyTop}px`;
- // elStyle.zIndex = zIndex;
- // return
- // }
- const elHeight = el.getBoundingClientRect().height;
- const elWidth = el.getBoundingClientRect().width;
- elStyle.cssText = `top: ${stickyTop}px; z-index: ${zIndex}`;
+ elStyle.position = '-webkit-sticky'
+ elStyle.position = 'sticky'
+ // if the browser support css sticky(Currently Safari, Firefox and Chrome Canary)
+ // if (~elStyle.position.indexOf('sticky')) {
+ // elStyle.top = `${stickyTop}px`;
+ // elStyle.zIndex = zIndex;
+ // return
+ // }
+ const elHeight = el.getBoundingClientRect().height
+ const elWidth = el.getBoundingClientRect().width
+ elStyle.cssText = `top: ${stickyTop}px; z-index: ${zIndex}`
- const parentElm = el.parentNode || document.documentElement;
- const placeholder = document.createElement('div');
- placeholder.style.display = 'none';
- placeholder.style.width = `${elWidth}px`;
- placeholder.style.height = `${elHeight}px`;
- parentElm.insertBefore(placeholder, el)
+ const parentElm = el.parentNode || document.documentElement
+ const placeholder = document.createElement('div')
+ placeholder.style.display = 'none'
+ placeholder.style.width = `${elWidth}px`
+ placeholder.style.height = `${elHeight}px`
+ parentElm.insertBefore(placeholder, el)
- let active = false;
+ let active = false
- const getScroll = (target, top) => {
- const prop = top ? 'pageYOffset' : 'pageXOffset';
- const method = top ? 'scrollTop' : 'scrollLeft';
- let ret = target[prop];
- if (typeof ret !== 'number') {
- ret = window.document.documentElement[method];
- }
- return ret;
- };
-
- const sticky = () => {
- if (active) {
- return
- }
- if (!elStyle.height) {
- elStyle.height = `${el.offsetHeight}px`
- }
-
- elStyle.position = 'fixed';
- elStyle.width = `${elWidth}px`;
- placeholder.style.display = 'inline-block';
- active = true
- };
-
- const reset = () => {
- if (!active) {
- return
- }
-
- elStyle.position = '';
- placeholder.style.display = 'none';
- active = false;
- };
-
- const check = () => {
- const scrollTop = getScroll(window, true);
- const offsetTop = el.getBoundingClientRect().top;
- if (offsetTop < stickyTop) {
- sticky();
- } else {
- if (scrollTop < elHeight + stickyTop) {
- reset()
- }
- }
- };
- listenAction = () => {
- check()
- };
-
- window.addEventListener('scroll', listenAction)
- },
-
- unbind() {
- window.removeEventListener('scroll', listenAction)
+ const getScroll = (target, top) => {
+ const prop = top ? 'pageYOffset' : 'pageXOffset'
+ const method = top ? 'scrollTop' : 'scrollLeft'
+ let ret = target[prop]
+ if (typeof ret !== 'number') {
+ ret = window.document.documentElement[method]
+ }
+ return ret
}
- })
- };
- if (typeof exports == 'object') {
- module.exports = vueSticky
- } else if (typeof define == 'function' && define.amd) {
- define([], () => vueSticky)
- } else if (window.Vue) {
- window.vueSticky = vueSticky;
- Vue.use(vueSticky)
- }
-}());
+
+ const sticky = () => {
+ if (active) {
+ return
+ }
+ if (!elStyle.height) {
+ elStyle.height = `${el.offsetHeight}px`
+ }
+
+ elStyle.position = 'fixed'
+ elStyle.width = `${elWidth}px`
+ placeholder.style.display = 'inline-block'
+ active = true
+ }
+
+ const reset = () => {
+ if (!active) {
+ return
+ }
+
+ elStyle.position = ''
+ placeholder.style.display = 'none'
+ active = false
+ }
+
+ const check = () => {
+ const scrollTop = getScroll(window, true)
+ const offsetTop = el.getBoundingClientRect().top
+ if (offsetTop < stickyTop) {
+ sticky()
+ } else {
+ if (scrollTop < elHeight + stickyTop) {
+ reset()
+ }
+ }
+ }
+ listenAction = () => {
+ check()
+ }
+
+ window.addEventListener('scroll', listenAction)
+ },
+
+ unbind() {
+ window.removeEventListener('scroll', listenAction)
+ }
+ })
+}
+
+export default vueSticky
diff --git a/src/directive/waves.js b/src/directive/waves.js
deleted file mode 100644
index 0f10bd81..00000000
--- a/src/directive/waves.js
+++ /dev/null
@@ -1,54 +0,0 @@
-import './waves.css';
-(function() {
- const vueWaves = {};
- vueWaves.install = (Vue, options = {}) => {
- Vue.directive('waves', {
- bind(el, binding) {
- el.addEventListener('click', e => {
- const customOpts = Object.assign(options, binding.value);
- const opts = Object.assign({
- ele: el, // 波纹作用元素
- type: 'hit', // hit点击位置扩散center中心点扩展
- color: 'rgba(0, 0, 0, 0.15)' // 波纹颜色
- }, customOpts),
- target = opts.ele;
- if (target) {
- target.style.position = 'relative';
- target.style.overflow = 'hidden';
- const rect = target.getBoundingClientRect();
- let ripple = target.querySelector('.waves-ripple');
- if (!ripple) {
- ripple = document.createElement('span');
- ripple.className = 'waves-ripple';
- ripple.style.height = ripple.style.width = Math.max(rect.width, rect.height) + 'px';
- target.appendChild(ripple);
- } else {
- ripple.className = 'waves-ripple';
- }
- switch (opts.type) {
- case 'center':
- ripple.style.top = (rect.height / 2 - ripple.offsetHeight / 2) + 'px';
- ripple.style.left = (rect.width / 2 - ripple.offsetWidth / 2) + 'px';
- break;
- default:
- ripple.style.top = (e.pageY - rect.top - ripple.offsetHeight / 2 - document.body.scrollTop) + 'px';
- ripple.style.left = (e.pageX - rect.left - ripple.offsetWidth / 2 - document.body.scrollLeft) + 'px';
- }
- ripple.style.backgroundColor = opts.color;
- ripple.className = 'waves-ripple z-active';
- return false;
- }
- }, false);
- }
- })
- };
- if (typeof exports == 'object') {
- module.exports = vueWaves
- } else if (typeof define == 'function' && define.amd) {
- define([], () => vueWaves)
- } else if (window.Vue) {
- window.vueWaves = vueWaves;
- Vue.use(vueWaves)
- }
-}());
-
diff --git a/src/directive/waves/index.js b/src/directive/waves/index.js
new file mode 100644
index 00000000..65f9b308
--- /dev/null
+++ b/src/directive/waves/index.js
@@ -0,0 +1,13 @@
+import waves from './waves'
+
+const install = function(Vue) {
+ Vue.directive('waves', waves)
+}
+
+if (window.Vue) {
+ window.waves = waves
+ Vue.use(install); // eslint-disable-line
+}
+
+waves.install = install
+export default waves
diff --git a/src/directive/waves.css b/src/directive/waves/waves.css
similarity index 100%
rename from src/directive/waves.css
rename to src/directive/waves/waves.css
diff --git a/src/directive/waves/waves.js b/src/directive/waves/waves.js
new file mode 100644
index 00000000..ac1d8611
--- /dev/null
+++ b/src/directive/waves/waves.js
@@ -0,0 +1,42 @@
+import './waves.css'
+
+export default{
+ bind(el, binding) {
+ el.addEventListener('click', e => {
+ const customOpts = Object.assign({}, binding.value)
+ const opts = Object.assign({
+ ele: el, // 波纹作用元素
+ type: 'hit', // hit点击位置扩散center中心点扩展
+ color: 'rgba(0, 0, 0, 0.15)' // 波纹颜色
+ }, customOpts)
+ const target = opts.ele
+ if (target) {
+ target.style.position = 'relative'
+ target.style.overflow = 'hidden'
+ const rect = target.getBoundingClientRect()
+ let ripple = target.querySelector('.waves-ripple')
+ if (!ripple) {
+ ripple = document.createElement('span')
+ ripple.className = 'waves-ripple'
+ ripple.style.height = ripple.style.width = Math.max(rect.width, rect.height) + 'px'
+ target.appendChild(ripple)
+ } else {
+ ripple.className = 'waves-ripple'
+ }
+ switch (opts.type) {
+ case 'center':
+ ripple.style.top = (rect.height / 2 - ripple.offsetHeight / 2) + 'px'
+ ripple.style.left = (rect.width / 2 - ripple.offsetWidth / 2) + 'px'
+ break
+ default:
+ ripple.style.top = (e.pageY - rect.top - ripple.offsetHeight / 2 - document.body.scrollTop) + 'px'
+ ripple.style.left = (e.pageX - rect.left - ripple.offsetWidth / 2 - document.body.scrollLeft) + 'px'
+ }
+ ripple.style.backgroundColor = opts.color
+ ripple.className = 'waves-ripple z-active'
+ return false
+ }
+ }, false)
+ }
+}
+
diff --git a/src/errorLog.js b/src/errorLog.js
new file mode 100644
index 00000000..d52c9cab
--- /dev/null
+++ b/src/errorLog.js
@@ -0,0 +1,14 @@
+import Vue from 'vue'
+import errLog from '@/store/errLog'
+
+// 生产环境错误日志
+if (process.env.NODE_ENV === 'production') {
+ Vue.config.errorHandler = function(err, vm) {
+ console.log(err, window.location.href)
+ errLog.pushLog({
+ err,
+ url: window.location.href,
+ vm
+ })
+ }
+}
diff --git a/src/filters/index.js b/src/filters/index.js
index 36cb3e7c..285a314b 100644
--- a/src/filters/index.js
+++ b/src/filters/index.js
@@ -4,8 +4,9 @@ function pluralize(time, label) {
}
return time + label + 's'
}
+
export function timeAgo(time) {
- const between = Date.now() / 1000 - Number(time);
+ const between = Date.now() / 1000 - Number(time)
if (between < 3600) {
return pluralize(~~(between / 60), ' minute')
} else if (between < 86400) {
@@ -17,20 +18,19 @@ export function timeAgo(time) {
export function parseTime(time, cFormat) {
if (arguments.length === 0) {
- return null;
+ return null
}
if ((time + '').length === 10) {
time = +time * 1000
}
-
- const format = cFormat || '{y}-{m}-{d} {h}:{i}:{s}';
- let date;
- if (typeof time == 'object') {
- date = time;
+ const format = cFormat || '{y}-{m}-{d} {h}:{i}:{s}'
+ let date
+ if (typeof time === 'object') {
+ date = time
} else {
- date = new Date(parseInt(time));
+ date = new Date(parseInt(time))
}
const formatObj = {
y: date.getFullYear(),
@@ -40,24 +40,24 @@ export function parseTime(time, cFormat) {
i: date.getMinutes(),
s: date.getSeconds(),
a: date.getDay()
- };
+ }
const time_str = format.replace(/{(y|m|d|h|i|s|a)+}/g, (result, key) => {
- let value = formatObj[key];
- if (key === 'a') return ['一', '二', '三', '四', '五', '六', '日'][value - 1];
+ let value = formatObj[key]
+ if (key === 'a') return ['一', '二', '三', '四', '五', '六', '日'][value - 1]
if (result.length > 0 && value < 10) {
- value = '0' + value;
+ value = '0' + value
}
- return value || 0;
- });
- return time_str;
+ return value || 0
+ })
+ return time_str
}
export function formatTime(time, option) {
- time = +time * 1000;
- const d = new Date(time);
- const now = Date.now();
+ time = +time * 1000
+ const d = new Date(time)
+ const now = Date.now()
- const diff = (now - d) / 1000;
+ const diff = (now - d) / 1000
if (diff < 30) {
return '刚刚'
@@ -75,34 +75,30 @@ export function formatTime(time, option) {
}
}
-
-
/* 数字 格式化*/
export function nFormatter(num, digits) {
const si = [
- { value: 1E18, symbol: 'E' },
- { value: 1E15, symbol: 'P' },
- { value: 1E12, symbol: 'T' },
- { value: 1E9, symbol: 'G' },
- { value: 1E6, symbol: 'M' },
- { value: 1E3, symbol: 'k' }
- ];
+ { value: 1E18, symbol: 'E' },
+ { value: 1E15, symbol: 'P' },
+ { value: 1E12, symbol: 'T' },
+ { value: 1E9, symbol: 'G' },
+ { value: 1E6, symbol: 'M' },
+ { value: 1E3, symbol: 'k' }
+ ]
for (let i = 0; i < si.length; i++) {
if (num >= si[i].value) {
- return (num / si[i].value + 0.1).toFixed(digits).replace(/\.0+$|(\.[0-9]*[1-9])0+$/, '$1') + si[i].symbol;
+ return (num / si[i].value + 0.1).toFixed(digits).replace(/\.0+$|(\.[0-9]*[1-9])0+$/, '$1') + si[i].symbol
}
}
- return num.toString();
+ return num.toString()
}
-
export function html2Text(val) {
- const div = document.createElement('div');
- div.innerHTML = val;
- return div.textContent || div.innerText;
+ const div = document.createElement('div')
+ div.innerHTML = val
+ return div.textContent || div.innerText
}
-
export function toThousandslsFilter(num) {
- return (+num || 0).toString().replace(/(\d)(?=(?:\d{3})+$)/g, '$1,');
+ return (+num || 0).toString().replace(/^-?\d+/g, m => m.replace(/(?=(?!\b)(\d{3})+$)/g, ','))
}
diff --git a/src/icons/index.js b/src/icons/index.js
new file mode 100644
index 00000000..2d689240
--- /dev/null
+++ b/src/icons/index.js
@@ -0,0 +1,12 @@
+import Vue from 'vue'
+import SvgIcon from '@/components/SvgIcon'// svg组件
+import generateIconsView from '@/views/svg-icons/generateIconsView.js'// just for @/views/icons , you can delete it
+
+// register globally
+Vue.component('svg-icon', SvgIcon)
+
+const requireAll = requireContext => requireContext.keys().map(requireContext)
+const req = require.context('./svg', false, /\.svg$/)
+const iconMap = requireAll(req)
+
+generateIconsView.generate(iconMap) // just for @/views/icons , you can delete it
diff --git a/src/icons/svg/404.svg b/src/icons/svg/404.svg
new file mode 100644
index 00000000..bc5bc9fa
--- /dev/null
+++ b/src/icons/svg/404.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/icons/svg/bug.svg b/src/icons/svg/bug.svg
new file mode 100644
index 00000000..a12a9394
--- /dev/null
+++ b/src/icons/svg/bug.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/icons/svg/chart.svg b/src/icons/svg/chart.svg
new file mode 100644
index 00000000..b1b31336
--- /dev/null
+++ b/src/icons/svg/chart.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/icons/svg/clipboard.svg b/src/icons/svg/clipboard.svg
new file mode 100644
index 00000000..cf1c9b0c
--- /dev/null
+++ b/src/icons/svg/clipboard.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/icons/svg/component.svg b/src/icons/svg/component.svg
new file mode 100644
index 00000000..a8008c84
--- /dev/null
+++ b/src/icons/svg/component.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/icons/svg/dashboard.svg b/src/icons/svg/dashboard.svg
new file mode 100644
index 00000000..bee42507
--- /dev/null
+++ b/src/icons/svg/dashboard.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/icons/svg/documentation.svg b/src/icons/svg/documentation.svg
new file mode 100644
index 00000000..caf68ddb
--- /dev/null
+++ b/src/icons/svg/documentation.svg
@@ -0,0 +1 @@
+
diff --git a/src/icons/svg/drag.svg b/src/icons/svg/drag.svg
new file mode 100644
index 00000000..819c8d50
--- /dev/null
+++ b/src/icons/svg/drag.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/icons/svg/email.svg b/src/icons/svg/email.svg
new file mode 100644
index 00000000..8a87e147
--- /dev/null
+++ b/src/icons/svg/email.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/icons/svg/example.svg b/src/icons/svg/example.svg
new file mode 100644
index 00000000..681422ea
--- /dev/null
+++ b/src/icons/svg/example.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/icons/svg/excel.svg b/src/icons/svg/excel.svg
new file mode 100644
index 00000000..e5dd5cec
--- /dev/null
+++ b/src/icons/svg/excel.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/icons/svg/eye.svg b/src/icons/svg/eye.svg
new file mode 100644
index 00000000..194aa45c
--- /dev/null
+++ b/src/icons/svg/eye.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/icons/svg/form.svg b/src/icons/svg/form.svg
new file mode 100644
index 00000000..79716f06
--- /dev/null
+++ b/src/icons/svg/form.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/icons/svg/icon.svg b/src/icons/svg/icon.svg
new file mode 100644
index 00000000..906af96a
--- /dev/null
+++ b/src/icons/svg/icon.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/icons/svg/international.svg b/src/icons/svg/international.svg
new file mode 100644
index 00000000..6912767d
--- /dev/null
+++ b/src/icons/svg/international.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/icons/svg/language.svg b/src/icons/svg/language.svg
new file mode 100644
index 00000000..2baf7431
--- /dev/null
+++ b/src/icons/svg/language.svg
@@ -0,0 +1 @@
+
diff --git a/src/icons/svg/lock.svg b/src/icons/svg/lock.svg
new file mode 100644
index 00000000..37c60701
--- /dev/null
+++ b/src/icons/svg/lock.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/icons/svg/message.svg b/src/icons/svg/message.svg
new file mode 100644
index 00000000..d807b002
--- /dev/null
+++ b/src/icons/svg/message.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/icons/svg/money.svg b/src/icons/svg/money.svg
new file mode 100644
index 00000000..d4fcb9ca
--- /dev/null
+++ b/src/icons/svg/money.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/icons/svg/password.svg b/src/icons/svg/password.svg
new file mode 100644
index 00000000..920b500b
--- /dev/null
+++ b/src/icons/svg/password.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/icons/svg/people.svg b/src/icons/svg/people.svg
new file mode 100644
index 00000000..3985ab51
--- /dev/null
+++ b/src/icons/svg/people.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/icons/svg/peoples.svg b/src/icons/svg/peoples.svg
new file mode 100644
index 00000000..2dccfcc0
--- /dev/null
+++ b/src/icons/svg/peoples.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/icons/svg/qq.svg b/src/icons/svg/qq.svg
new file mode 100644
index 00000000..97aee717
--- /dev/null
+++ b/src/icons/svg/qq.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/icons/svg/shoppingCard.svg b/src/icons/svg/shoppingCard.svg
new file mode 100644
index 00000000..cdebbdb4
--- /dev/null
+++ b/src/icons/svg/shoppingCard.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/icons/svg/star.svg b/src/icons/svg/star.svg
new file mode 100644
index 00000000..685a301d
--- /dev/null
+++ b/src/icons/svg/star.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/icons/svg/tab.svg b/src/icons/svg/tab.svg
new file mode 100644
index 00000000..17aa088b
--- /dev/null
+++ b/src/icons/svg/tab.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/icons/svg/table.svg b/src/icons/svg/table.svg
new file mode 100644
index 00000000..083bc8cc
--- /dev/null
+++ b/src/icons/svg/table.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/icons/svg/theme.svg b/src/icons/svg/theme.svg
new file mode 100644
index 00000000..9c0873c1
--- /dev/null
+++ b/src/icons/svg/theme.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/icons/svg/trendChart1.svg b/src/icons/svg/trendChart1.svg
new file mode 100644
index 00000000..6297fe8a
--- /dev/null
+++ b/src/icons/svg/trendChart1.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/icons/svg/trendChart2.svg b/src/icons/svg/trendChart2.svg
new file mode 100644
index 00000000..0c08ff08
--- /dev/null
+++ b/src/icons/svg/trendChart2.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/icons/svg/trendChart3.svg b/src/icons/svg/trendChart3.svg
new file mode 100644
index 00000000..17124d90
--- /dev/null
+++ b/src/icons/svg/trendChart3.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/icons/svg/user.svg b/src/icons/svg/user.svg
new file mode 100644
index 00000000..5971deeb
--- /dev/null
+++ b/src/icons/svg/user.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/icons/svg/wechat.svg b/src/icons/svg/wechat.svg
new file mode 100644
index 00000000..d88a64bc
--- /dev/null
+++ b/src/icons/svg/wechat.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/icons/svg/zip.svg b/src/icons/svg/zip.svg
new file mode 100644
index 00000000..e9a9d012
--- /dev/null
+++ b/src/icons/svg/zip.svg
@@ -0,0 +1 @@
+
diff --git a/src/lang/en.js b/src/lang/en.js
new file mode 100644
index 00000000..3986a2e5
--- /dev/null
+++ b/src/lang/en.js
@@ -0,0 +1,48 @@
+export default {
+ route: {
+ dashboard: 'Dashboard',
+ introduction: 'Introduction',
+ documentation: 'Documentation',
+ permission: 'Permission',
+ icons: 'Icons',
+ components: 'Components',
+ componentIndex: 'Introduction',
+ tinymce: 'Tinymce',
+ markdown: 'Markdown',
+ jsonEditor: 'JSON Editor',
+ dndList: 'Dnd List',
+ splitPane: 'SplitPane',
+ avatarUpload: 'Avatar Upload',
+ dropzone: 'Dropzone',
+ sticky: 'Sticky',
+ countTo: 'CountTo',
+ componentMixin: 'Mixin',
+ backToTop: 'BackToTop',
+ charts: 'Charts',
+ keyboardChart: 'Keyboard Chart',
+ lineChart: 'Line chart',
+ mixChart: 'Mix Chart',
+ example: 'Example',
+ Table: 'Table',
+ dynamicTable: 'Dynamic Table',
+ dragTable: 'Drag Table',
+ inlineEditTable: 'Inline Edit',
+ complexTable: 'Complex Table',
+ tab: 'Tab',
+ form: 'Form',
+ createForm: 'Create Form',
+ editForm: 'Edit Form',
+ errorPages: 'Error Pages',
+ page401: '401',
+ page404: '404',
+ errorLog: 'Error Log',
+ excel: 'Excel',
+ exportExcel: 'Export Excel',
+ selectExcel: 'Export Selected',
+ uploadExcel: 'Upload Excel',
+ exportZip: 'Zip',
+ theme: 'Theme',
+ clipboardDemo: 'Clipboard',
+ i18n: 'I18n'
+ }
+}
diff --git a/src/lang/index.js b/src/lang/index.js
new file mode 100644
index 00000000..12b9cacb
--- /dev/null
+++ b/src/lang/index.js
@@ -0,0 +1,27 @@
+import Vue from 'vue'
+import VueI18n from 'vue-i18n'
+import Cookies from 'js-cookie'
+import elementEnLocale from 'element-ui/lib/locale/lang/en' // element-ui lang
+import elementZhLocale from 'element-ui/lib/locale/lang/zh-CN'// element-ui lang
+import enLocale from './en'
+import zhLocale from './zh'
+
+Vue.use(VueI18n)
+
+const messages = {
+ en: {
+ ...enLocale,
+ ...elementEnLocale
+ },
+ zh: {
+ ...zhLocale,
+ ...elementZhLocale
+ }
+}
+
+const i18n = new VueI18n({
+ locale: Cookies.get('language') || 'zh', // set locale
+ messages // set locale messages
+})
+
+export default i18n
diff --git a/src/lang/zh.js b/src/lang/zh.js
new file mode 100644
index 00000000..e44d0cf0
--- /dev/null
+++ b/src/lang/zh.js
@@ -0,0 +1,48 @@
+export default {
+ route: {
+ dashboard: '首页',
+ introduction: '简述',
+ documentation: '文档',
+ permission: '权限测试页',
+ icons: '图标',
+ components: '组件',
+ componentIndex: '介绍',
+ tinymce: '富文本编辑器',
+ markdown: 'Markdown',
+ jsonEditor: 'JSON编辑器',
+ dndList: '列表拖拽',
+ splitPane: 'Splitpane',
+ avatarUpload: '头像上传',
+ dropzone: 'Dropzone',
+ sticky: 'Sticky',
+ countTo: 'CountTo',
+ componentMixin: '小组件',
+ backToTop: '返回顶部',
+ charts: '图表',
+ keyboardChart: '键盘图表',
+ lineChart: '折线图',
+ mixChart: '混合图表',
+ example: '综合实例',
+ Table: 'Table',
+ dynamicTable: '动态table',
+ dragTable: '拖拽table',
+ inlineEditTable: 'table内编辑',
+ complexTable: '综合table',
+ tab: 'Tab',
+ form: '表单',
+ createForm: '创建表单',
+ editForm: '编辑表单',
+ errorPages: '错误页面',
+ page401: '401',
+ page404: '404',
+ errorLog: '错误日志',
+ excel: 'excel',
+ exportExcel: 'export excel',
+ selectExcel: 'export selected',
+ uploadExcel: 'upload excel',
+ exportZip: 'zip',
+ theme: '换肤',
+ clipboardDemo: 'clipboard',
+ i18n: '国际化'
+ }
+}
diff --git a/src/main.js b/src/main.js
index aa81cb3b..1a63658e 100644
--- a/src/main.js
+++ b/src/main.js
@@ -1,120 +1,32 @@
-// The Vue build version to load with the `import` command
-// (runtime-only or standalone) has been set in webpack.base.conf with an alias.
-import Vue from 'vue';
-import App from './App';
-import router from './router';
-import store from './store';
-import ElementUI from 'element-ui';
-import 'element-ui/lib/theme-default/index.css';
-import 'assets/custom-theme/index.css'; // 换肤版本element-ui css https://github.com/PanJiaChen/custom-element-theme
-import NProgress from 'nprogress'; // Progress 进度条
-import 'nprogress/nprogress.css';// Progress 进度条 样式
-import 'normalize.css/normalize.css';// normalize.css 样式格式化
-import 'styles/index.scss'; // 全局自定义的css样式
-import 'components/Icon-svg/index'; // 封装的svg组件
-import 'assets/iconfont/iconfont'; // iconfont 具体图标见https://github.com/PanJiaChen/vue-element-admin/wiki
-import * as filters from './filters'; // 全局vue filter
-import Multiselect from 'vue-multiselect';// 使用的一个多选框组件,element-ui的select不能满足所有需求
-import 'vue-multiselect/dist/vue-multiselect.min.css';// 多选框组件css
-import Sticky from 'components/Sticky'; // 粘性header组件
-import vueWaves from './directive/waves';// 水波纹指令
-import errLog from 'store/errLog';// error log组件
-import './mock/index.js'; // 该项目所有请求使用mockjs模拟
+import Vue from 'vue'
+import Element from 'element-ui'
+import 'element-ui/lib/theme-chalk/index.css'
+import i18n from './lang' // 国际化
+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模拟
-// register globally
-Vue.component('multiselect', Multiselect);
-Vue.component('Sticky', Sticky);
-Vue.use(ElementUI);
-Vue.use(vueWaves);
+Vue.use(Element, {
+ i18n: (key, value) => i18n.t(key, value)
+})
// register global utility filters.
Object.keys(filters).forEach(key => {
Vue.filter(key, filters[key])
-});
+})
-// permissiom judge
-function hasPermission(roles, permissionRoles) {
- if (roles.indexOf('admin') >= 0) return true; // admin权限 直接通过
- if (!permissionRoles) return true;
- return roles.some(role => permissionRoles.indexOf(role) >= 0)
-}
-
-// register global progress.
-const whiteList = ['/login', '/authredirect', '/reset', '/sendpwd'];// 不重定向白名单
-router.beforeEach((to, from, next) => {
- NProgress.start(); // 开启Progress
- if (store.getters.token) { // 判断是否有token
- if (to.path === '/login') {
- next({ path: '/' });
- } else {
- if (store.getters.roles.length === 0) { // 判断当前用户是否已拉取完user_info信息
- store.dispatch('GetInfo').then(res => { // 拉取user_info
- const roles = res.data.role;
- store.dispatch('GenerateRoutes', { roles }).then(() => { // 生成可访问的路由表
- router.addRoutes(store.getters.addRouters) // 动态添加可访问路由表
- next(to.path); // hack方法 确保addRoutes已完成
- })
- }).catch(err => {
- console.log(err);
- });
- } else {
- // 没有动态改变权限的需求可直接next() 删除下方权限判断 ↓
- if (hasPermission(store.getters.roles, to.meta.role)) {
- next();//
- } else {
- next({ path: '/401', query: { noGoBack: true } });
- }
- // 可删 ↑
- }
- }
- } else {
- if (whiteList.indexOf(to.path) !== -1) { // 在免登录白名单,直接进入
- next()
- } else {
- next('/login'); // 否则全部重定向到登录页
- NProgress.done(); // 在hash模式下 改变手动改变hash 重定向回来 不会触发afterEach 暂时hack方案 ps:history模式下无问题,可删除该行!
- }
- }
-});
-
-
-router.afterEach(() => {
- NProgress.done(); // 结束Progress
-});
-
-// window.onunhandledrejection = e => {
-// console.log('unhandled', e.reason, e.promise);
-// e.preventDefault()
-// };
-
-// 生产环境错误日志
-if (process.env === 'production') {
- Vue.config.errorHandler = function(err, vm) {
- console.log(err, window.location.href);
- errLog.pushLog({
- err,
- url: window.location.href,
- vm
- })
- };
-}
-
-// window.onerror = function (msg, url, lineNo, columnNo, error) {
-// console.log('window')
-// };
-//
-// console.error = (function (origin) {
-// return function (errorlog) {
-// // handler();//基于业务的日志记录及数据报错
-// console.log('console'+errorlog)
-// origin.call(console, errorlog);
-// }
-// })(console.error);
+Vue.config.productionTip = false
new Vue({
+ el: '#app',
router,
store,
- render: h => h(App)
-}).$mount('#app');
-
-
+ i18n,
+ template: '
',
+ components: { App }
+})
diff --git a/src/mock/article.js b/src/mock/article.js
index 539338f1..20dc4e1c 100644
--- a/src/mock/article.js
+++ b/src/mock/article.js
@@ -1,29 +1,56 @@
-import Mock from 'mockjs';
-
-
-const List = [];
-const count = 20;
+import Mock from 'mockjs'
+import { param2Obj } from '@/utils'
+const List = []
+const count = 100
for (let i = 0; i < count; i++) {
List.push(Mock.mock({
- id: '@id',
- title: '@ctitle(10, 20)',
- 'status|1': ['published', 'draft'],
+ id: '@increment',
+ timestamp: +Mock.Random.date('T'),
author: '@cname',
+ auditor: '@cname',
+ title: '@ctitle(10, 20)',
+ forecast: '@float(0, 100, 2, 2)',
+ importance: '@integer(1, 3)',
+ 'type|1': ['CN', 'US', 'JP', 'EU'],
+ 'status|1': ['published', 'draft', 'deleted'],
display_time: '@datetime',
pageviews: '@integer(300, 5000)'
- }));
+ }))
}
export default {
- getList: () => List,
+ getList: config => {
+ const { importance, type, title, page = 1, limit = 20, sort } = param2Obj(config.url)
+
+ let mockList = List.filter(item => {
+ if (importance && item.importance !== +importance) return false
+ if (type && item.type !== type) return false
+ if (title && item.title.indexOf(title) < 0) return false
+ return true
+ })
+
+ if (sort === '-id') {
+ mockList = mockList.reverse()
+ }
+
+ const pageList = mockList.filter((item, index) => index < limit * page && index >= limit * (page - 1))
+
+ return {
+ total: mockList.length,
+ items: pageList
+ }
+ },
+ getPv: () => ({
+ pvData: [{ key: 'PC网站', pv: 1024 }, { key: 'mobile网站', pv: 1024 }, { key: 'ios', pv: 1024 }, { key: 'android', pv: 1024 }]
+ }),
getArticle: () => ({
id: 120000000001,
author: { key: 'mockPan' },
source_name: '原创作者',
category_item: [{ key: 'global', name: '全球' }],
- comment_disabled: false,
+ comment_disabled: true,
content: '
我是测试数据我是测试数据
"',
content_short: '我是测试数据',
display_time: +new Date(),
@@ -32,6 +59,12 @@ export default {
source_uri: 'https://github.com/PanJiaChen/vue-element-admin',
status: 'published',
tags: [],
- title: ''
+ title: 'vue-element-admin'
+ }),
+ createArticle: () => ({
+ data: 'success'
+ }),
+ updateArticle: () => ({
+ data: 'success'
})
-};
+}
diff --git a/src/mock/article_table.js b/src/mock/article_table.js
deleted file mode 100644
index 7d9ecd1e..00000000
--- a/src/mock/article_table.js
+++ /dev/null
@@ -1,44 +0,0 @@
-import Mock from 'mockjs';
-import { param2Obj } from 'utils';
-
-const List = [];
-const count = 100;
-
-for (let i = 0; i < count; i++) {
- List.push(Mock.mock({
- id: '@increment',
- timestamp: +Mock.Random.date('T'),
- author: '@cname',
- auditor: '@cname',
- title: '@ctitle(10, 20)',
- forecast: '@float(0, 100, 2, 2)',
- importance: '@integer(1, 3)',
- 'type|1': ['FD', 'FE', 'BI', 'VN'],
- 'status|1': ['published', 'draft', 'deleted'],
- pageviews: '@integer(300, 5000)'
- }));
-}
-
-export default {
- getList: config => {
- const { importance, type, title, page, limit, sort } = param2Obj(config.url);
- let mockList = List.filter(item => {
- if (importance && item.importance !== +importance) return false;
- if (type && item.type !== type) return false;
- if (title && item.title.indexOf(title) < 0) return false;
- return true;
- });
- if (sort === '-id') {
- mockList = mockList.reverse()
- }
-
- const pageList = mockList.filter((item, index) => index < limit * page && index >= limit * (page - 1));
- return {
- total: mockList.length,
- items: pageList
- }
- },
- getPv: () => ({
- pvData: [{ key: 'PC网站', pv: 1024 }, { key: 'mobile网站', pv: 1024 }, { key: 'ios', pv: 1024 }, { key: 'android', pv: 1024 }]
- })
-};
diff --git a/src/mock/index.js b/src/mock/index.js
index dea59284..e6644ae1 100644
--- a/src/mock/index.js
+++ b/src/mock/index.js
@@ -1,25 +1,29 @@
-import Mock from 'mockjs';
-import loginAPI from './login';
-import articleAPI from './article';
-import article_tableAPI from './article_table';
-import remoteSearchAPI from './remoteSearch';
+import Mock from 'mockjs'
+import loginAPI from './login'
+import articleAPI from './article'
+import remoteSearchAPI from './remoteSearch'
+import transactionAPI from './transaction'
+// Mock.setup({
+// timeout: '350-600'
+// })
// 登录相关
-Mock.mock(/\/login\/loginbyemail/, 'post', loginAPI.loginByEmail);
-Mock.mock(/\/login\/logout/, 'post', loginAPI.logout);
-Mock.mock(/\/user\/info\.*/, 'get', loginAPI.getInfo)
+Mock.mock(/\/login\/login/, 'post', loginAPI.loginByUsername)
+Mock.mock(/\/login\/logout/, 'post', loginAPI.logout)
+Mock.mock(/\/user\/info\.*/, 'get', loginAPI.getUserInfo)
-// // 文章相关
-Mock.mock(/\/article\/list/, 'get', articleAPI.getList);
-Mock.mock(/\/article\/detail/, 'get', articleAPI.getArticle);
+// 文章相关
+Mock.mock(/\/article\/list/, 'get', articleAPI.getList)
+Mock.mock(/\/article\/detail/, 'get', articleAPI.getArticle)
+Mock.mock(/\/article\/pv/, 'get', articleAPI.getPv)
+Mock.mock(/\/article\/create/, 'post', articleAPI.createArticle)
+Mock.mock(/\/article\/update/, 'post', articleAPI.updateArticle)
-// // table example相关
-Mock.mock(/\/article_table\/list/, 'get', article_tableAPI.getList);
-Mock.mock(/\/article_table\/p/, 'get', article_tableAPI.getPv);
+// 搜索相关
+Mock.mock(/\/search\/user/, 'get', remoteSearchAPI.searchUser)
-// // 搜索相关
-Mock.mock(/\/search\/user/, 'get', remoteSearchAPI.searchUser);
+// 账单相关
+Mock.mock(/\/transaction\/list/, 'get', transactionAPI.getList)
-
-export default Mock;
+export default Mock
diff --git a/src/mock/login.js b/src/mock/login.js
index fa0f330b..8693ef98 100644
--- a/src/mock/login.js
+++ b/src/mock/login.js
@@ -1,4 +1,4 @@
-import { param2Obj } from 'utils';
+import { param2Obj } from '@/utils'
const userMap = {
admin: {
@@ -6,40 +6,29 @@ const userMap = {
token: 'admin',
introduction: '我是超级管理员',
avatar: 'https://wpimg.wallstcn.com/f778738c-e4f8-4870-b634-56703b4acafe.gif',
- name: '超级管理员小潘',
- uid: '001'
+ name: 'Super Admin'
},
editor: {
role: ['editor'],
token: 'editor',
introduction: '我是编辑',
avatar: 'https://wpimg.wallstcn.com/f778738c-e4f8-4870-b634-56703b4acafe.gif',
- name: '普通编辑小张',
- uid: '002'
-
- },
- developer: {
- role: ['develop'],
- token: 'develop',
- introduction: '我是开发',
- avatar: 'https://wpimg.wallstcn.com/f778738c-e4f8-4870-b634-56703b4acafe.gif',
- name: '工程师小王',
- uid: '003'
+ name: 'Normal Editor'
}
}
export default {
- loginByEmail: config => {
- const { email } = JSON.parse(config.body);
- return userMap[email.split('@')[0]];
+ loginByUsername: config => {
+ const { username } = JSON.parse(config.body)
+ return userMap[username]
},
- getInfo: config => {
- const { token } = param2Obj(config.url);
+ getUserInfo: config => {
+ const { token } = param2Obj(config.url)
if (userMap[token]) {
- return userMap[token];
+ return userMap[token]
} else {
- return Promise.reject('a');
+ return false
}
},
logout: () => 'success'
-};
+}
diff --git a/src/mock/remoteSearch.js b/src/mock/remoteSearch.js
index 3d06a4f1..b70f6f7d 100644
--- a/src/mock/remoteSearch.js
+++ b/src/mock/remoteSearch.js
@@ -1,24 +1,24 @@
-import Mock from 'mockjs';
-import { param2Obj } from 'utils';
+import Mock from 'mockjs'
+import { param2Obj } from '@/utils'
-const NameList = [];
-const count = 100;
+const NameList = []
+const count = 100
for (let i = 0; i < count; i++) {
NameList.push(Mock.mock({
name: '@first'
- }));
+ }))
}
NameList.push({ name: 'mockPan' })
export default {
searchUser: config => {
- const { name } = param2Obj(config.url);
+ const { name } = param2Obj(config.url)
const mockNameList = NameList.filter(item => {
const lowerCaseName = item.name.toLowerCase()
- if (name && lowerCaseName.indexOf(name.toLowerCase()) < 0) return false;
- return true;
- });
+ if (name && lowerCaseName.indexOf(name.toLowerCase()) < 0) return false
+ return true
+ })
return { items: mockNameList }
}
-};
+}
diff --git a/src/mock/transaction.js b/src/mock/transaction.js
new file mode 100644
index 00000000..a17517e4
--- /dev/null
+++ b/src/mock/transaction.js
@@ -0,0 +1,23 @@
+import Mock from 'mockjs'
+
+const List = []
+const count = 20
+
+for (let i = 0; i < count; i++) {
+ List.push(Mock.mock({
+ order_no: '@guid()',
+ timestamp: +Mock.Random.date('T'),
+ username: '@name()',
+ price: '@float(1000, 15000, 0, 2)',
+ 'status|1': ['success', 'pending']
+ }))
+}
+
+export default {
+ getList: () => {
+ return {
+ total: List.length,
+ items: List
+ }
+ }
+}
diff --git a/src/permission.js b/src/permission.js
new file mode 100644
index 00000000..77c88e11
--- /dev/null
+++ b/src/permission.js
@@ -0,0 +1,60 @@
+import router from './router'
+import store from './store'
+import NProgress from 'nprogress' // Progress 进度条
+import 'nprogress/nprogress.css'// Progress 进度条样式
+import { getToken } from '@/utils/auth' // 验权
+import { Message } from 'element-ui'
+
+// permissiom judge
+function hasPermission(roles, permissionRoles) {
+ if (roles.indexOf('admin') >= 0) return true // admin权限 直接通过
+ if (!permissionRoles) return true
+ return roles.some(role => permissionRoles.indexOf(role) >= 0)
+}
+
+const whiteList = ['/login', '/authredirect']// 不重定向白名单
+
+router.beforeEach((to, from, next) => {
+ NProgress.start() // 开启Progress
+ if (getToken()) { // 判断是否有token
+ if (to.path === '/login') {
+ next({ path: '/' })
+ NProgress.done() // router在hash模式下 手动改变hash 重定向回来 不会触发afterEach 暂时hack方案 ps:history模式下无问题,可删除该行!
+ } else {
+ if (store.getters.roles.length === 0) { // 判断当前用户是否已拉取完user_info信息
+ store.dispatch('GetUserInfo').then(res => { // 拉取user_info
+ const roles = res.data.role
+ store.dispatch('GenerateRoutes', { roles }).then(() => { // 生成可访问的路由表
+ router.addRoutes(store.getters.addRouters) // 动态添加可访问路由表
+ next({ ...to }) // hack方法 确保addRoutes已完成
+ })
+ }).catch(() => {
+ store.dispatch('FedLogOut').then(() => {
+ Message.error('验证失败,请重新登录')
+ next({ path: '/login' })
+ })
+ })
+ } else {
+ // 没有动态改变权限的需求可直接next() 删除下方权限判断 ↓
+ if (hasPermission(store.getters.roles, to.meta.role)) {
+ next()//
+ } else {
+ next({ path: '/401', query: { noGoBack: true }})
+ NProgress.done() // router在hash模式下 手动改变hash 重定向回来 不会触发afterEach 暂时hack方案 ps:history模式下无问题,可删除该行!
+ }
+ // 可删 ↑
+ }
+ }
+ } else {
+ if (whiteList.indexOf(to.path) !== -1) { // 在免登录白名单,直接进入
+ next()
+ } else {
+ next('/login') // 否则全部重定向到登录页
+ NProgress.done() // router在hash模式下 手动改变hash 重定向回来 不会触发afterEach 暂时hack方案 ps:history模式下无问题,可删除该行!
+ }
+ }
+})
+
+router.afterEach(() => {
+ NProgress.done() // 结束Progress
+})
diff --git a/src/router/_import_development.js b/src/router/_import_development.js
new file mode 100644
index 00000000..7c8b5e6b
--- /dev/null
+++ b/src/router/_import_development.js
@@ -0,0 +1 @@
+module.exports = file => require('@/views/' + file + '.vue').default // vue-loader at least v13.0.0+
diff --git a/src/router/_import_production.js b/src/router/_import_production.js
new file mode 100644
index 00000000..331acba4
--- /dev/null
+++ b/src/router/_import_production.js
@@ -0,0 +1 @@
+module.exports = file => () => import('@/views/' + file + '.vue')
diff --git a/src/router/index.js b/src/router/index.js
index 3d49cf39..26c47f4a 100644
--- a/src/router/index.js
+++ b/src/router/index.js
@@ -1,100 +1,51 @@
-import Vue from 'vue';
-import Router from 'vue-router';
+import Vue from 'vue'
+import Router from 'vue-router'
+const _import = require('./_import_' + process.env.NODE_ENV)
+// in development-env not use lazy-loading, because lazy-loading too many pages will cause webpack hot update too slow. so only in production use lazy-loading;
+// detail: https://panjiachen.github.io/vue-element-admin-site/#/lazy-loading
-/* layout */
-import Layout from '../views/layout/Layout';
+Vue.use(Router)
-/* login */
-import Login from '../views/login/';
-const authRedirect = () => import('../views/login/authredirect');
-const sendPWD = () => import('../views/login/sendpwd');
-const reset = () => import('../views/login/reset');
-
-/* dashboard */
-const dashboard = () => import('../views/dashboard/index');
-
-/* 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 = () => 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 page */
-const Err404 = () => import('../views/error/404');
-const Err401 = () => import('../views/error/401');
-
-/* error log */
-const ErrorLog = () => import('../views/errlog/index');
-
-/* excel */
-const ExcelDownload = () => import('../views/excel/index');
-
-/* theme */
-const Theme = () => import('../views/theme/index');
-
-/* example*/
-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');
-
-/* permission */
-const Permission = () => import('../views/permission/index');
-
-
-Vue.use(Router);
-
- /**
- * icon : the icon show in the sidebar
- * hidden : if hidden:true will not show in the sidebar
- * redirect : if redirect:noredirect will not redirct in the levelbar
- * noDropdown : if noDropdown:true will not has submenu
- * meta : { role: ['admin'] } will control the page role
- **/
+/* Layout */
+import Layout from '../views/layout/Layout'
+/**
+* hidden: true if `hidden:true` will not show in the sidebar(default is false)
+* redirect: noredirect if `redirect:noredirect` will no redirct in the breadcrumb
+* name:'router-name' the name is used by
(must set!!!)
+* meta : {
+ role: ['admin','editor'] will control the page role (you can set multiple roles)
+ title: 'title' the name show in submenu and breadcrumb (recommend set)
+ icon: 'svg-name' the icon show in the sidebar,
+ noCache: true if fasle ,the page will no be cached(default is false)
+ }
+**/
export const constantRouterMap = [
- { path: '/login', component: Login, hidden: true },
- { path: '/authredirect', component: authRedirect, hidden: true },
- { path: '/sendpwd', component: sendPWD, hidden: true },
- { path: '/reset', component: reset, hidden: true },
- { path: '/404', component: Err404, hidden: true },
- { path: '/401', component: Err401, hidden: true },
+ { path: '/login', component: _import('login/index'), hidden: true },
+ { path: '/authredirect', component: _import('login/authredirect'), hidden: true },
+ { path: '/404', component: _import('errorPage/404'), hidden: true },
+ { path: '/401', component: _import('errorPage/401'), hidden: true },
{
- path: '/',
+ path: '',
component: Layout,
- redirect: '/dashboard',
- name: '首页',
- hidden: true,
- children: [{ path: 'dashboard', component: dashboard }]
+ redirect: 'dashboard',
+ children: [{
+ path: 'dashboard',
+ component: _import('dashboard/index'),
+ name: 'dashboard',
+ meta: { title: 'dashboard', icon: 'dashboard', noCache: true }
+ }]
},
{
- path: '/introduction',
+ path: '/documentation',
component: Layout,
- redirect: '/introduction/index',
- icon: 'xinrenzhinan',
- noDropdown: true,
- children: [{ path: 'index', component: Introduction, name: '简述' }]
+ redirect: '/documentation/index',
+ children: [{
+ path: 'index',
+ component: _import('documentation/index'),
+ name: 'documentation',
+ meta: { title: 'documentation', icon: 'documentation', noCache: true }
+ }]
}
]
@@ -102,113 +53,186 @@ export default new Router({
// mode: 'history', //后端支持可开
scrollBehavior: () => ({ y: 0 }),
routes: constantRouterMap
-});
+})
export const asyncRouterMap = [
{
path: '/permission',
component: Layout,
redirect: '/permission/index',
- name: '权限测试',
- icon: 'quanxian',
meta: { role: ['admin'] },
- noDropdown: true,
- children: [{ path: 'index', component: Permission, name: '权限测试页', meta: { role: ['admin'] } }]
+ children: [{
+ path: 'index',
+ component: _import('permission/index'),
+ name: 'permission',
+ meta: {
+ title: 'permission',
+ icon: 'lock',
+ role: ['admin']
+ }
+ }]
},
+
+ {
+ path: '/icon',
+ component: Layout,
+ children: [{
+ path: 'index',
+ component: _import('svg-icons/index'),
+ name: 'icons',
+ meta: { title: 'icons', icon: 'icon', noCache: true }
+ }]
+ },
+
{
path: '/components',
component: Layout,
- redirect: '/components/index',
- name: '组件',
- icon: 'zujian',
+ redirect: 'noredirect',
+ name: 'component-demo',
+ meta: {
+ title: 'components',
+ icon: 'component'
+ },
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: 'tinymce', component: _import('components-demo/tinymce'), name: 'tinymce-demo', meta: { title: 'tinymce' }},
+ { path: 'markdown', component: _import('components-demo/markdown'), name: 'markdown-demo', meta: { title: 'markdown' }},
+ { path: 'json-editor', component: _import('components-demo/jsonEditor'), name: 'jsonEditor-demo', meta: { title: 'jsonEditor' }},
+ { path: 'dnd-list', component: _import('components-demo/dndList'), name: 'dndList-demo', meta: { title: 'dndList' }},
+ { path: 'splitpane', component: _import('components-demo/splitpane'), name: 'splitpane-demo', meta: { title: 'splitPane' }},
+ { path: 'avatar-upload', component: _import('components-demo/avatarUpload'), name: 'avatarUpload-demo', meta: { title: 'avatarUpload' }},
+ { path: 'dropzone', component: _import('components-demo/dropzone'), name: 'dropzone-demo', meta: { title: 'dropzone' }},
+ { path: 'sticky', component: _import('components-demo/sticky'), name: 'sticky-demo', meta: { title: 'sticky' }},
+ { path: 'count-to', component: _import('components-demo/countTo'), name: 'countTo-demo', meta: { title: 'countTo' }},
+ { path: 'mixin', component: _import('components-demo/mixin'), name: 'componentMixin-demo', meta: { title: 'componentMixin' }},
+ { path: 'back-to-top', component: _import('components-demo/backToTop'), name: 'backToTop-demo', meta: { title: 'backToTop' }}
]
},
+
{
path: '/charts',
component: Layout,
- redirect: '/charts/index',
- name: '图表',
- icon: 'tubiaoleixingzhengchang',
+ redirect: 'noredirect',
+ name: 'charts',
+ meta: {
+ title: 'charts',
+ icon: 'chart'
+ },
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: 'keyboard', component: _import('charts/keyboard'), name: 'keyboardChart', meta: { title: 'keyboardChart', noCache: true }},
+ { path: 'line', component: _import('charts/line'), name: 'lineChart', meta: { title: 'lineChart', noCache: true }},
+ { path: 'mixchart', component: _import('charts/mixChart'), name: 'mixChart', meta: { title: 'mixChart', noCache: true }}
]
},
+
{
- path: '/errorpage',
+ path: '/example',
component: Layout,
- redirect: 'noredirect',
- name: '错误页面',
- icon: '404',
+ redirect: '/example/table/complex-table',
+ name: 'example',
+ meta: {
+ title: 'example',
+ icon: 'example'
+ },
children: [
- { path: '401', component: Err401, name: '401' },
- { path: '404', component: Err404, name: '404' }
+ {
+ path: '/example/table',
+ component: _import('example/table/index'),
+ redirect: '/example/table/complex-table',
+ name: 'Table',
+ meta: {
+ title: 'Table',
+ icon: 'table'
+ },
+ children: [
+ { path: 'dynamic-table', component: _import('example/table/dynamicTable/index'), name: 'dynamicTable', meta: { title: 'dynamicTable' }},
+ { path: 'drag-table', component: _import('example/table/dragTable'), name: 'dragTable', meta: { title: 'dragTable' }},
+ { path: 'inline-edit-table', component: _import('example/table/inlineEditTable'), name: 'inlineEditTable', meta: { title: 'inlineEditTable' }},
+ { path: 'complex-table', component: _import('example/table/complexTable'), name: 'complexTable', meta: { title: 'complexTable' }}
+ ]
+ },
+ { path: 'tab/index', icon: 'tab', component: _import('example/tab/index'), name: 'tab', meta: { title: 'tab' }}
]
},
+
{
- path: '/errlog',
+ path: '/form',
component: Layout,
redirect: 'noredirect',
- name: 'errlog',
- icon: 'bug',
- noDropdown: true,
- children: [{ path: 'log', component: ErrorLog, name: '错误日志' }]
+ name: 'form',
+ meta: {
+ title: 'form',
+ icon: 'form'
+ },
+ children: [
+ { path: 'create-form', component: _import('form/create'), name: 'createForm', meta: { title: 'createForm', icon: 'table' }},
+ { path: 'edit-form', component: _import('form/edit'), name: 'editForm', meta: { title: 'editForm', icon: 'table' }}
+ ]
},
+
+ {
+ path: '/error',
+ component: Layout,
+ redirect: 'noredirect',
+ name: 'errorPages',
+ meta: {
+ title: 'errorPages',
+ icon: '404'
+ },
+ children: [
+ { path: '401', component: _import('errorPage/401'), name: 'page401', meta: { title: 'page401', noCache: true }},
+ { path: '404', component: _import('errorPage/404'), name: 'page404', meta: { title: 'page404', noCache: true }}
+ ]
+ },
+
+ {
+ path: '/error-log',
+ component: Layout,
+ redirect: 'noredirect',
+ children: [{ path: 'log', component: _import('errorLog/index'), name: 'errorLog', meta: { title: 'errorLog', icon: 'bug' }}]
+ },
+
{
path: '/excel',
component: Layout,
- redirect: 'noredirect',
+ redirect: '/excel/export-excel',
name: 'excel',
- icon: 'EXCEL',
- noDropdown: true,
- children: [{ path: 'download', component: ExcelDownload, name: '导出excel' }]
+ meta: {
+ title: 'excel',
+ icon: 'excel'
+ },
+ children: [
+ { path: 'export-excel', component: _import('excel/exportExcel'), name: 'exportExcel', meta: { title: 'exportExcel' }},
+ { path: 'export-selected-excel', component: _import('excel/selectExcel'), name: 'selectExcel', meta: { title: 'selectExcel' }},
+ { path: 'upload-excel', component: _import('excel/uploadExcel'), name: 'uploadExcel', meta: { title: 'uploadExcel' }}
+ ]
},
+
+ {
+ path: '/zip',
+ component: Layout,
+ redirect: '/zip/download',
+ children: [{ path: 'download', component: _import('zip/index'), name: 'exportZip', meta: { title: 'exportZip', icon: 'zip' }}]
+ },
+
{
path: '/theme',
component: Layout,
redirect: 'noredirect',
- name: 'theme',
- icon: 'theme',
- noDropdown: true,
- children: [{ path: 'index', component: Theme, name: '换肤' }]
+ children: [{ path: 'index', component: _import('theme/index'), name: 'theme', meta: { title: 'theme', icon: 'theme' }}]
},
+
{
- path: '/example',
+ path: '/clipboard',
component: Layout,
redirect: 'noredirect',
- name: '综合实例',
- icon: 'zonghe',
- children: [
- {
- 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' }
- ]
+ children: [{ path: 'index', component: _import('clipboard/index'), name: 'clipboardDemo', meta: { title: 'clipboardDemo', icon: 'clipboard' }}]
},
+
+ {
+ path: '/i18n',
+ component: Layout,
+ children: [{ path: 'index', component: _import('i18n-demo/index'), name: 'i18n', meta: { title: 'i18n', icon: 'international' }}]
+ },
+
{ path: '*', redirect: '/404', hidden: true }
-];
+]
diff --git a/src/store/errLog.js b/src/store/errLog.js
index 4401babc..6cfbe3cb 100644
--- a/src/store/errLog.js
+++ b/src/store/errLog.js
@@ -6,8 +6,8 @@ const errLog = {
this.state.errLog.unshift(log)
},
clearLog() {
- this.state.errLog = [];
+ this.state.errLog = []
}
-};
+}
-export default errLog;
+export default errLog
diff --git a/src/store/getters.js b/src/store/getters.js
index 4677e6d6..4acc4bbe 100644
--- a/src/store/getters.js
+++ b/src/store/getters.js
@@ -1,16 +1,16 @@
const getters = {
sidebar: state => state.app.sidebar,
+ language: state => state.app.language,
+ visitedViews: state => state.app.visitedViews,
+ cachedViews: state => state.app.cachedViews,
token: state => state.user.token,
avatar: state => state.user.avatar,
name: state => state.user.name,
- uid: state => state.user.uid,
- email: state => state.user.email,
introduction: state => state.user.introduction,
- auth_type: state => state.user.auth_type,
status: state => state.user.status,
roles: state => state.user.roles,
setting: state => state.user.setting,
permission_routers: state => state.permission.routers,
addRouters: state => state.permission.addRouters
-};
+}
export default getters
diff --git a/src/store/index.js b/src/store/index.js
index ee7d313e..9bfa6a77 100644
--- a/src/store/index.js
+++ b/src/store/index.js
@@ -1,11 +1,11 @@
-import Vue from 'vue';
-import Vuex from 'vuex';
-import app from './modules/app';
-import user from './modules/user';
-import permission from './modules/permission';
-import getters from './getters';
+import Vue from 'vue'
+import Vuex from 'vuex'
+import app from './modules/app'
+import user from './modules/user'
+import permission from './modules/permission'
+import getters from './getters'
-Vue.use(Vuex);
+Vue.use(Vuex)
const store = new Vuex.Store({
modules: {
@@ -14,6 +14,6 @@ const store = new Vuex.Store({
permission
},
getters
-});
+})
export default store
diff --git a/src/store/modules/app.js b/src/store/modules/app.js
index 83049ff5..21b4de01 100644
--- a/src/store/modules/app.js
+++ b/src/store/modules/app.js
@@ -1,28 +1,71 @@
-import Cookies from 'js-cookie';
+import Cookies from 'js-cookie'
const app = {
state: {
sidebar: {
opened: !+Cookies.get('sidebarStatus')
},
- theme: 'default',
- livenewsChannels: Cookies.get('livenewsChannels') || '[]'
+ language: Cookies.get('language') || 'zh',
+ visitedViews: [],
+ cachedViews: []
},
mutations: {
TOGGLE_SIDEBAR: state => {
if (state.sidebar.opened) {
- Cookies.set('sidebarStatus', 1);
+ Cookies.set('sidebarStatus', 1)
} else {
- Cookies.set('sidebarStatus', 0);
+ Cookies.set('sidebarStatus', 0)
+ }
+ state.sidebar.opened = !state.sidebar.opened
+ },
+ SET_LANGUAGE: (state, language) => {
+ state.language = language
+ Cookies.set('language', language)
+ },
+ ADD_VISITED_VIEWS: (state, view) => {
+ if (state.visitedViews.some(v => v.path === view.path)) return
+ state.visitedViews.push({
+ name: view.name,
+ path: view.path,
+ title: view.meta.title || 'no-name'
+ })
+ if (!view.meta.noCache) {
+ state.cachedViews.push(view.name)
+ }
+ },
+ DEL_VISITED_VIEWS: (state, view) => {
+ for (const [i, v] of state.visitedViews.entries()) {
+ if (v.path === view.path) {
+ state.visitedViews.splice(i, 1)
+ break
+ }
+ }
+ for (const i of state.cachedViews) {
+ if (i === view.name) {
+ const index = state.cachedViews.indexOf(i)
+ state.cachedViews.splice(index, 1)
+ break
+ }
}
- state.sidebar.opened = !state.sidebar.opened;
}
},
actions: {
- ToggleSideBar: ({ commit }) => {
+ toggleSideBar({ commit }) {
commit('TOGGLE_SIDEBAR')
+ },
+ setLanguage({ commit }, language) {
+ commit('SET_LANGUAGE', language)
+ },
+ addVisitedViews({ commit }, view) {
+ commit('ADD_VISITED_VIEWS', view)
+ },
+ delVisitedViews({ commit, state }, view) {
+ return new Promise((resolve) => {
+ commit('DEL_VISITED_VIEWS', view)
+ resolve([...state.visitedViews])
+ })
}
}
-};
+}
-export default app;
+export default app
diff --git a/src/store/modules/permission.js b/src/store/modules/permission.js
index 926c89b0..50e2bbe8 100644
--- a/src/store/modules/permission.js
+++ b/src/store/modules/permission.js
@@ -1,5 +1,10 @@
-import { asyncRouterMap, constantRouterMap } from 'src/router';
+import { asyncRouterMap, constantRouterMap } from '@/router'
+/**
+ * 通过meta.role判断是否与当前用户权限匹配
+ * @param roles
+ * @param route
+ */
function hasPermission(roles, route) {
if (route.meta && route.meta.role) {
return roles.some(role => route.meta.role.indexOf(role) >= 0)
@@ -8,46 +13,50 @@ function hasPermission(roles, route) {
}
}
+/**
+ * 递归过滤异步路由表,返回符合用户角色权限的路由表
+ * @param asyncRouterMap
+ * @param roles
+ */
+function filterAsyncRouter(asyncRouterMap, roles) {
+ const accessedRouters = asyncRouterMap.filter(route => {
+ if (hasPermission(roles, route)) {
+ if (route.children && route.children.length) {
+ route.children = filterAsyncRouter(route.children, roles)
+ }
+ return true
+ }
+ return false
+ })
+ return accessedRouters
+}
+
const permission = {
state: {
routers: constantRouterMap,
addRouters: []
},
-
mutations: {
SET_ROUTERS: (state, routers) => {
- state.addRouters = routers;
- state.routers = constantRouterMap.concat(routers);
+ state.addRouters = routers
+ state.routers = constantRouterMap.concat(routers)
}
},
-
actions: {
GenerateRoutes({ commit }, data) {
return new Promise(resolve => {
- const { roles } = data;
- const accessedRouters = asyncRouterMap.filter(v => {
- if (roles.indexOf('admin') >= 0) return true;
- if (hasPermission(roles, v)) {
- if (v.children && v.children.length > 0) {
- v.children = v.children.filter(child => {
- if (hasPermission(roles, child)) {
- return child
- }
- return false;
- });
- return v
- } else {
- return v
- }
- }
- return false;
- });
- commit('SET_ROUTERS', accessedRouters);
- resolve();
+ const { roles } = data
+ let accessedRouters
+ if (roles.indexOf('admin') >= 0) {
+ accessedRouters = asyncRouterMap
+ } else {
+ accessedRouters = filterAsyncRouter(asyncRouterMap, roles)
+ }
+ commit('SET_ROUTERS', accessedRouters)
+ resolve()
})
}
}
-};
+}
-
-export default permission;
+export default permission
diff --git a/src/store/modules/user.js b/src/store/modules/user.js
index a134f44f..8cf6d18a 100644
--- a/src/store/modules/user.js
+++ b/src/store/modules/user.js
@@ -1,15 +1,12 @@
-import { loginByEmail, logout, getInfo } from 'api/login';
-import Cookies from 'js-cookie';
+import { loginByUsername, logout, getUserInfo } from '@/api/login'
+import { getToken, setToken, removeToken } from '@/utils/auth'
const user = {
state: {
user: '',
status: '',
- email: '',
code: '',
- uid: undefined,
- auth_type: '',
- token: Cookies.get('Admin-Token'),
+ token: getToken(),
name: '',
avatar: '',
introduction: '',
@@ -20,130 +17,120 @@ const user = {
},
mutations: {
- SET_AUTH_TYPE: (state, type) => {
- state.auth_type = type;
- },
SET_CODE: (state, code) => {
- state.code = code;
+ state.code = code
},
SET_TOKEN: (state, token) => {
- state.token = token;
- },
- SET_UID: (state, uid) => {
- state.uid = uid;
- },
- SET_EMAIL: (state, email) => {
- state.email = email;
+ state.token = token
},
SET_INTRODUCTION: (state, introduction) => {
- state.introduction = introduction;
+ state.introduction = introduction
},
SET_SETTING: (state, setting) => {
- state.setting = setting;
+ state.setting = setting
},
SET_STATUS: (state, status) => {
- state.status = status;
+ state.status = status
},
SET_NAME: (state, name) => {
- state.name = name;
+ state.name = name
},
SET_AVATAR: (state, avatar) => {
- state.avatar = avatar;
+ state.avatar = avatar
},
SET_ROLES: (state, roles) => {
- state.roles = roles;
- },
- LOGIN_SUCCESS: () => {
- console.log('login success')
- },
- LOGOUT_USER: state => {
- state.user = '';
+ state.roles = roles
}
},
actions: {
- // 邮箱登录
- LoginByEmail({ commit }, userInfo) {
- const email = userInfo.email.trim();
+ // 用户名登录
+ LoginByUsername({ commit }, userInfo) {
+ const username = userInfo.username.trim()
return new Promise((resolve, reject) => {
- loginByEmail(email, userInfo.password).then(response => {
- const data = response.data;
- Cookies.set('Admin-Token', response.data.token);
- commit('SET_TOKEN', data.token);
- commit('SET_EMAIL', email);
- resolve();
+ loginByUsername(username, userInfo.password).then(response => {
+ const data = response.data
+ commit('SET_TOKEN', data.token)
+ setToken(response.data.token)
+ resolve()
}).catch(error => {
- reject(error);
- });
- });
+ reject(error)
+ })
+ })
},
-
// 获取用户信息
- GetInfo({ commit, state }) {
+ GetUserInfo({ commit, state }) {
return new Promise((resolve, reject) => {
- getInfo(state.token).then(response => {
- const data = response.data;
- commit('SET_ROLES', data.role);
- commit('SET_NAME', data.name);
- commit('SET_AVATAR', data.avatar);
- commit('SET_UID', data.uid);
- commit('SET_INTRODUCTION', data.introduction);
- resolve(response);
+ getUserInfo(state.token).then(response => {
+ if (!response.data) { // 由于mockjs 不支持自定义状态码只能这样hack
+ reject('error')
+ }
+ const data = response.data
+ commit('SET_ROLES', data.role)
+ commit('SET_NAME', data.name)
+ commit('SET_AVATAR', data.avatar)
+ commit('SET_INTRODUCTION', data.introduction)
+ resolve(response)
}).catch(error => {
- reject(error);
- });
- });
+ reject(error)
+ })
+ })
},
// 第三方验证登录
- LoginByThirdparty({ commit, state }, code) {
- return new Promise((resolve, reject) => {
- commit('SET_CODE', code);
- loginByThirdparty(state.status, state.email, state.code, state.auth_type).then(response => {
- commit('SET_TOKEN', response.data.token);
- Cookies.set('Admin-Token', response.data.token);
- resolve();
- }).catch(error => {
- reject(error);
- });
- });
- },
-
+ // LoginByThirdparty({ commit, state }, code) {
+ // return new Promise((resolve, reject) => {
+ // commit('SET_CODE', code)
+ // loginByThirdparty(state.status, state.email, state.code).then(response => {
+ // commit('SET_TOKEN', response.data.token)
+ // setToken(response.data.token)
+ // resolve()
+ // }).catch(error => {
+ // reject(error)
+ // })
+ // })
+ // },
// 登出
LogOut({ commit, state }) {
return new Promise((resolve, reject) => {
logout(state.token).then(() => {
- commit('SET_TOKEN', '');
- commit('SET_ROLES', []);
- Cookies.remove('Admin-Token');
- resolve();
+ commit('SET_TOKEN', '')
+ commit('SET_ROLES', [])
+ removeToken()
+ resolve()
}).catch(error => {
- reject(error);
- });
- });
+ reject(error)
+ })
+ })
},
// 前端 登出
FedLogOut({ commit }) {
return new Promise(resolve => {
- commit('SET_TOKEN', '');
- Cookies.remove('Admin-Token');
- resolve();
- });
+ commit('SET_TOKEN', '')
+ removeToken()
+ resolve()
+ })
},
// 动态修改权限
ChangeRole({ commit }, role) {
return new Promise(resolve => {
- commit('SET_ROLES', [role]);
- commit('SET_TOKEN', role);
- Cookies.set('Admin-Token', role);
- resolve();
+ commit('SET_TOKEN', role)
+ setToken(role)
+ getUserInfo(role).then(response => {
+ const data = response.data
+ commit('SET_ROLES', data.role)
+ commit('SET_NAME', data.name)
+ commit('SET_AVATAR', data.avatar)
+ commit('SET_INTRODUCTION', data.introduction)
+ resolve()
+ })
})
}
}
-};
+}
-export default user;
+export default user
diff --git a/src/styles/btn.scss b/src/styles/btn.scss
index edd2f318..f3f75c16 100644
--- a/src/styles/btn.scss
+++ b/src/styles/btn.scss
@@ -1,33 +1,24 @@
-$blue:#324157;
-$light-blue:#3A71A8;
-$red:#C03639;
-$pink: #E65D6E;
-$green: #30B08F;
-$tiffany: #4AB7BD;
-$yellow:#FEC171;
-
-$panGreen: #30B08F;
+@import './variables.scss';
@mixin colorBtn($color) {
background: $color;
&:hover {
color: $color;
- &:before, &:after {
+ &:before,
+ &:after {
background: $color;
}
}
}
-
.blue-btn {
@include colorBtn($blue)
}
-.light-blue-btn{
+.light-blue-btn {
@include colorBtn($light-blue)
}
-
.red-btn {
@include colorBtn($red)
}
@@ -40,12 +31,10 @@ $panGreen: #30B08F;
@include colorBtn($green)
}
-
.tiffany-btn {
@include colorBtn($tiffany)
}
-
.yellow-btn {
@include colorBtn($yellow)
}
@@ -63,12 +52,14 @@ $panGreen: #30B08F;
display: inline-block;
&:hover {
background: #fff;
- &:before, &:after {
+ &:before,
+ &:after {
width: 100%;
transition: 600ms ease all;
}
}
- &:before, &:after {
+ &:before,
+ &:after {
content: '';
position: absolute;
top: 0;
@@ -85,19 +76,20 @@ $panGreen: #30B08F;
}
}
-.custom-button{
- display: inline-block;
- line-height: 1;
- white-space: nowrap;
- cursor: pointer;
- background: #fff;
- color: #fff;
- -webkit-appearance: none;
- text-align: center;
- box-sizing: border-box;
- outline: 0;
- margin: 0;
- padding: 10px 15px;
- font-size: 14px;
- border-radius: 4px;
+.custom-button {
+ display: inline-block;
+ line-height: 1;
+ white-space: nowrap;
+ cursor: pointer;
+ background: #fff;
+ color: #fff;
+ -webkit-appearance: none;
+ text-align: center;
+ box-sizing: border-box;
+ outline: 0;
+ margin: 0;
+ padding: 10px 15px;
+ font-size: 14px;
+ border-radius: 4px;
}
+
diff --git a/src/styles/element-ui.scss b/src/styles/element-ui.scss
index 382aff13..28e6180d 100644
--- a/src/styles/element-ui.scss
+++ b/src/styles/element-ui.scss
@@ -1,83 +1,64 @@
//覆盖一些element-ui样式
-.block-checkbox {
- display: block;
-}
-.operation-container {
- .cell {
- padding: 10px !important;
- }
- .el-button {
- &:nth-child(3) {
- margin-top: 10px;
- margin-left: 0px;
- }
- &:nth-child(4) {
- margin-top: 10px;
- }
- }
-}
+ .el-upload {
+ input[type="file"] {
+ display: none !important;
+ }
+ }
-.el-upload {
- input[type="file"] {
- display: none !important;
- }
-}
+ .el-upload__input {
+ display: none;
+ }
-.el-upload__input {
- display: none;
-}
+ .cell {
+ .el-tag {
+ margin-right: 0px;
+ }
+ }
-.cell {
- .el-tag {
- margin-right: 8px;
- }
-}
+ .small-padding {
+ .cell {
+ padding-left: 5px;
+ padding-right: 5px;
+ }
+ }
-.small-padding {
- .cell {
- padding-left: 8px;
- padding-right: 8px;
- }
-}
+ .status-col {
+ .cell {
+ padding: 0 10px;
+ text-align: center;
+ .el-tag {
+ margin-right: 0px;
+ }
+ }
+ }
-.status-col {
- .cell {
- padding: 0 10px;
- text-align: center;
- .el-tag {
- margin-right: 0px;
- }
- }
-}
+ //暂时性解决diolag 问题 https://github.com/ElemeFE/element/issues/2461
+ .el-dialog {
+ transform: none;
+ left: 0;
+ position: relative;
+ margin: 0 auto;
+ }
-//暂时性解决diolag 问题 https://github.com/ElemeFE/element/issues/2461
-.el-dialog {
- transform: none;
- left: 0;
- position: relative;
- margin: 0 auto;
-}
+ //文章页textarea修改样式
+ .article-textarea {
+ textarea {
+ padding-right: 40px;
+ resize: none;
+ border: none;
+ border-radius: 0px;
+ border-bottom: 1px solid #bfcbd9;
+ }
+ }
-
-//文章页textarea修改样式
-.article-textarea {
- textarea {
- padding-right: 40px;
- resize: none;
- border: none;
- border-radius: 0px;
- border-bottom: 1px solid #bfcbd9;
- }
-}
-
-//element ui upload
-.upload-container {
- .el-upload {
- width: 100%;
- .el-upload-dragger {
- width: 100%;
- height: 200px;
- }
- }
-}
+ //element ui upload
+ .upload-container {
+ .el-upload {
+ width: 100%;
+ .el-upload-dragger {
+ width: 100%;
+ height: 200px;
+ }
+ }
+ }
diff --git a/src/styles/index.scss b/src/styles/index.scss
index e566c382..45bbe204 100644
--- a/src/styles/index.scss
+++ b/src/styles/index.scss
@@ -1,7 +1,12 @@
-@import './btn.scss';
+@import './variables.scss';
+@import './mixin.scss';
+@import './transition.scss';
@import './element-ui.scss';
-@import "./mixin.scss";
+@import './sidebar.scss';
+@import './btn.scss';
+
body {
+ height: 100%;
-moz-osx-font-smoothing: grayscale;
-webkit-font-smoothing: antialiased;
text-rendering: optimizeLegibility;
@@ -13,9 +18,14 @@ label {
}
html {
+ height: 100%;
box-sizing: border-box;
}
+#app{
+ height: 100%;
+}
+
*,
*:before,
*:after {
@@ -43,6 +53,10 @@ a:hover {
text-decoration: none;
}
+div:focus{
+ outline: none;
+ }
+
.fr {
float: right;
}
@@ -71,6 +85,17 @@ a:hover {
display: block;
}
+.clearfix {
+ &:after {
+ visibility: hidden;
+ display: block;
+ font-size: 0;
+ content: " ";
+ clear: both;
+ height: 0;
+ }
+}
+
code {
background: #eef1f6;
padding: 15px 10px;
@@ -86,39 +111,39 @@ code {
}
}
-.fade-enter-active,
-.fade-leave-active {
- transition: all .2s ease
-}
-
-.fade-enter,
-.fade-leave-active {
- opacity: 0;
+.warn-content{
+ background: rgba(66,185,131,.1);
+ border-radius: 2px;
+ padding: 16px;
+ padding: 1rem;
+ line-height: 1.6rem;
+ word-spacing: .05rem;
+ a{
+ color: #42b983;
+ font-weight: 600;
+ }
}
//main-container全局样式
.app-container {
padding: 20px;
}
+
.components-container {
margin: 30px 50px;
position: relative;
}
+
.pagination-container {
margin-top: 30px;
}
-
.editor-container .CodeMirror {
height: 100%!important;
}
-.wscn-icon {
- width: 1em;
- height: 1em;
- vertical-align: -0.15em;
- fill: currentColor;
- overflow: hidden;
+.text-center {
+ text-align: center
}
.sub-navbar {
@@ -151,57 +176,6 @@ code {
}
}
-.publishedTag,
-.draftTag,
-.deletedTag {
- color: #fff;
- background-color: $panGreen;
- line-height: 1;
- text-align: center;
- margin: 0;
- padding: 8px 12px;
- font-size: 14px;
- border-radius: 4px;
- position: absolute;
- left: 20px;
- top: 10px;
-}
-
-.draftTag {
- background-color: $yellow;
-}
-
-.deletedTag {
- background-color: $red;
-}
-
-.input-label {
- font-size: 14px;
- color: #48576a;
- line-height: 1;
- padding: 11px 5px 11px 0;
-}
-
-.clearfix {
- &:after {
- visibility: hidden;
- display: block;
- font-size: 0;
- content: " ";
- clear: both;
- height: 0;
- }
-}
-
-.no-marginLeft {
- .el-checkbox {
- margin: 0 20px 15px 0;
- }
- .el-checkbox+.el-checkbox {
- margin-left: 0px;
- }
-}
-
.filter-container {
padding-bottom: 10px;
.filter-item {
@@ -211,7 +185,6 @@ code {
}
}
-
//refine vue-multiselect plugin
.multiselect {
line-height: 16px;
@@ -220,47 +193,3 @@ code {
.multiselect--active {
z-index: 1000 !important;
}
-
-//refine simplemde
-.simplemde-container{
- .editor-toolbar.fullscreen,.CodeMirror-fullscreen{
- z-index: 1003;
- }
-}
-
-//暂时性解决diolag 问题 https://github.com/ElemeFE/element/issues/2461
-.el-dialog {
- transform: none;
- left: 0;
- position: relative;
- margin: 0 auto;
-}
-
-//github-corner
-.github-corner:hover .octo-arm {
- animation: octocat-wave 560ms ease-in-out
-}
-
-@keyframes octocat-wave {
- 0%,
- 100% {
- transform: rotate(0)
- }
- 20%,
- 60% {
- transform: rotate(-25deg)
- }
- 40%,
- 80% {
- transform: rotate(10deg)
- }
-}
-
-@media (max-width:500px) {
- .github-corner:hover .octo-arm {
- animation: none
- }
- .github-corner .octo-arm {
- animation: octocat-wave 560ms ease-in-out
- }
-}
diff --git a/src/styles/sidebar.scss b/src/styles/sidebar.scss
new file mode 100644
index 00000000..2fed2b1d
--- /dev/null
+++ b/src/styles/sidebar.scss
@@ -0,0 +1,100 @@
+#app {
+ // 主体区域
+ .main-container {
+ min-height: 100%;
+ transition: margin-left 0.28s;
+ margin-left: 180px;
+ } // 侧边栏
+ .sidebar-container {
+ transition: width 0.28s;
+ width: 180px!important;
+ height: 100%;
+ position: fixed;
+ top: 0;
+ bottom: 0;
+ left: 0;
+ z-index: 1001;
+ a {
+ display: inline-block;
+ width: 100%;
+ }
+ .svg-icon {
+ margin-right: 16px;
+ }
+ .el-menu {
+ border: none;
+ width: 100%;
+ }
+ }
+ .hideSidebar {
+ .sidebar-container,.sidebar-container .el-menu {
+ width: 36px!important;
+ // overflow: inherit;
+ }
+ .main-container {
+ margin-left: 36px;
+ }
+ }
+ .hideSidebar {
+ .submenu-title-noDropdown {
+ padding-left: 10px!important;
+ position: relative;
+ span {
+ height: 0;
+ width: 0;
+ overflow: hidden;
+ visibility: hidden;
+ transition: opacity .3s cubic-bezier(.55, 0, .1, 1);
+ opacity: 0;
+ display: inline-block;
+ }
+ &:hover {
+ span {
+ display: block;
+ border-radius: 3px;
+ z-index: 1002;
+ width: 140px;
+ height: 56px;
+ visibility: visible;
+ position: absolute;
+ right: -145px;
+ text-align: left;
+ text-indent: 20px;
+ top: 0px;
+ background-color: $subMenuBg!important;
+ opacity: 1;
+ }
+ }
+ }
+ .el-submenu {
+ &>.el-submenu__title {
+ padding-left: 10px!important;
+ &>span {
+ display: none;
+ }
+ .el-submenu__icon-arrow {
+ display: none;
+ }
+ }
+ .nest-menu {
+ .el-submenu__icon-arrow {
+ display: block!important;
+ }
+ span {
+ display: inline-block!important;
+ }
+ }
+ }
+ }
+ .nest-menu .el-submenu>.el-submenu__title,
+ .el-submenu .el-menu-item {
+ min-width: 180px!important;
+ background-color: $subMenuBg!important;
+ &:hover {
+ background-color: $menuHover!important;
+ }
+ }
+ .el-menu--collapse .el-menu .el-submenu{
+ min-width: 180px!important;
+ }
+}
diff --git a/src/styles/transition.scss b/src/styles/transition.scss
new file mode 100644
index 00000000..85c03286
--- /dev/null
+++ b/src/styles/transition.scss
@@ -0,0 +1,33 @@
+//globl transition css
+
+/*fade*/
+.fade-enter-active,
+.fade-leave-active {
+ transition: opacity 0.28s;
+}
+
+.fade-enter,
+.fade-leave-active {
+ opacity: 0;
+}
+
+/*fade*/
+.breadcrumb-enter-active,
+.breadcrumb-leave-active {
+ transition: all .5s;
+}
+
+.breadcrumb-enter,
+.breadcrumb-leave-active {
+ opacity: 0;
+ transform: translateX(20px);
+}
+
+.breadcrumb-move {
+ transition: all .5s;
+}
+
+.breadcrumb-leave-active {
+ position: absolute;
+}
+
diff --git a/src/styles/variables.scss b/src/styles/variables.scss
new file mode 100644
index 00000000..acc77a82
--- /dev/null
+++ b/src/styles/variables.scss
@@ -0,0 +1,13 @@
+$blue:#324157;
+$light-blue:#3A71A8;
+$red:#C03639;
+$pink: #E65D6E;
+$green: #30B08F;
+$tiffany: #4AB7BD;
+$yellow:#FEC171;
+$panGreen: #30B08F;
+
+//sidebar
+$menuBg:#304156;
+$subMenuBg:#1f2d3d;
+$menuHover:#001528;
diff --git a/src/utils/auth.js b/src/utils/auth.js
new file mode 100644
index 00000000..08a43d6e
--- /dev/null
+++ b/src/utils/auth.js
@@ -0,0 +1,15 @@
+import Cookies from 'js-cookie'
+
+const TokenKey = 'Admin-Token'
+
+export function getToken() {
+ return Cookies.get(TokenKey)
+}
+
+export function setToken(token) {
+ return Cookies.set(TokenKey, token)
+}
+
+export function removeToken() {
+ return Cookies.remove(TokenKey)
+}
diff --git a/src/utils/clipboard.js b/src/utils/clipboard.js
new file mode 100644
index 00000000..25295900
--- /dev/null
+++ b/src/utils/clipboard.js
@@ -0,0 +1,36 @@
+import Vue from 'vue'
+import Clipboard from 'clipboard'
+
+function clipboardSuccess() {
+ Vue.prototype.$message({
+ message: '复制成功',
+ type: 'success',
+ duration: 1500
+ })
+}
+
+function clipboardError() {
+ Vue.prototype.$message({
+ message: '复制失败',
+ type: 'error'
+ })
+}
+
+export default function handleClipboard(text, event) {
+ const clipboard = new Clipboard(event.target, {
+ text: () => text
+ })
+ clipboard.on('success', () => {
+ clipboardSuccess()
+ clipboard.off('error')
+ clipboard.off('success')
+ clipboard.destroy()
+ })
+ clipboard.on('error', () => {
+ clipboardError()
+ clipboard.off('error')
+ clipboard.off('success')
+ clipboard.destroy()
+ })
+ clipboard.onClick(event)
+}
diff --git a/src/utils/createUniqueString.js b/src/utils/createUniqueString.js
index 2e6e357e..611725c4 100644
--- a/src/utils/createUniqueString.js
+++ b/src/utils/createUniqueString.js
@@ -2,7 +2,7 @@
* Created by jiachenpan on 17/3/8.
*/
export default function createUniqueString() {
- const timestamp = +new Date() + '';
- const randomNum = parseInt((1 + Math.random()) * 65536) + '';
- return (+(randomNum + timestamp)).toString(32);
+ const timestamp = +new Date() + ''
+ const randomNum = parseInt((1 + Math.random()) * 65536) + ''
+ return (+(randomNum + timestamp)).toString(32)
}
diff --git a/src/utils/fetch.js b/src/utils/fetch.js
deleted file mode 100644
index 8e589a8b..00000000
--- a/src/utils/fetch.js
+++ /dev/null
@@ -1,59 +0,0 @@
-import axios from 'axios';
-import { Message } from 'element-ui';
-import store from '../store';
-// import router from '../router';
-
-// 创建axios实例
-const service = axios.create({
- baseURL: process.env.BASE_API, // api的base_url
- timeout: 5000 // 请求超时时间
-});
-
-// request拦截器
-service.interceptors.request.use(config => {
- // Do something before request is sent
- if (store.getters.token) {
- config.headers['X-Token'] = store.getters.token; // 让每个请求携带token--['X-Token']为自定义key 请根据实际情况自行修改
- }
- return config;
-}, error => {
- // Do something with request error
- console.log(error); // for debug
- Promise.reject(error);
-})
-
-// respone拦截器
-service.interceptors.response.use(
- response => response
- /**
- * 下面的注释为通过response自定义code来标示请求状态,当code返回如下情况为权限有问题,登出并返回到登录页
- * 如通过xmlhttprequest 状态码标识 逻辑可写在下面error中
- */
- // const code = response.data.code;
- // // 50014:Token 过期了 50012:其他客户端登录了 50008:非法的token
- // if (code === 50008 || code === 50014 || code === 50012) {
- // Message({
- // message: res.message,
- // type: 'error',
- // duration: 5 * 1000
- // });
- // // 登出
- // store.dispatch('FedLogOut').then(() => {
- // router.push({ path: '/login' })
- // });
- // } else {
- // return response
- // }
- ,
- error => {
- console.log('err' + error);// for debug
- Message({
- message: error.message,
- type: 'error',
- duration: 5 * 1000
- });
- return Promise.reject(error);
- }
-)
-
-export default service;
diff --git a/src/utils/index.js b/src/utils/index.js
index a011f17e..2d7a86d6 100644
--- a/src/utils/index.js
+++ b/src/utils/index.js
@@ -2,213 +2,272 @@
* Created by jiachenpan on 16/11/18.
*/
- export function parseTime(time, cFormat) {
- if (arguments.length === 0) {
- return null;
- }
- const format = cFormat || '{y}-{m}-{d} {h}:{i}:{s}';
- let date;
- if (typeof time == 'object') {
- date = time;
- } else {
- if (('' + time).length === 10) time = parseInt(time) * 1000;
- date = new Date(time);
- }
- const formatObj = {
- y: date.getFullYear(),
- m: date.getMonth() + 1,
- d: date.getDate(),
- h: date.getHours(),
- i: date.getMinutes(),
- s: date.getSeconds(),
- a: date.getDay()
- };
- const time_str = format.replace(/{(y|m|d|h|i|s|a)+}/g, (result, key) => {
- let value = formatObj[key];
- if (key === 'a') return ['一', '二', '三', '四', '五', '六', '日'][value - 1];
- if (result.length > 0 && value < 10) {
- value = '0' + value;
- }
- return value || 0;
- });
- return time_str;
- }
+export function parseTime(time, cFormat) {
+ if (arguments.length === 0) {
+ return null
+ }
+ const format = cFormat || '{y}-{m}-{d} {h}:{i}:{s}'
+ let date
+ if (typeof time === 'object') {
+ date = time
+ } else {
+ if (('' + time).length === 10) time = parseInt(time) * 1000
+ date = new Date(time)
+ }
+ const formatObj = {
+ y: date.getFullYear(),
+ m: date.getMonth() + 1,
+ d: date.getDate(),
+ h: date.getHours(),
+ i: date.getMinutes(),
+ s: date.getSeconds(),
+ a: date.getDay()
+ }
+ const time_str = format.replace(/{(y|m|d|h|i|s|a)+}/g, (result, key) => {
+ let value = formatObj[key]
+ if (key === 'a') return ['一', '二', '三', '四', '五', '六', '日'][value - 1]
+ if (result.length > 0 && value < 10) {
+ value = '0' + value
+ }
+ return value || 0
+ })
+ return time_str
+}
- export function formatTime(time, option) {
- time = +time * 1000;
- const d = new Date(time);
- const now = Date.now();
+export function formatTime(time, option) {
+ time = +time * 1000
+ const d = new Date(time)
+ const now = Date.now()
- const diff = (now - d) / 1000;
+ const diff = (now - d) / 1000
- if (diff < 30) {
- return '刚刚'
- } else if (diff < 3600) { // less 1 hour
- return Math.ceil(diff / 60) + '分钟前'
- } else if (diff < 3600 * 24) {
- return Math.ceil(diff / 3600) + '小时前'
- } else if (diff < 3600 * 24 * 2) {
- return '1天前'
- }
- if (option) {
- return parseTime(time, option)
- } else {
- return d.getMonth() + 1 + '月' + d.getDate() + '日' + d.getHours() + '时' + d.getMinutes() + '分'
- }
- }
+ if (diff < 30) {
+ return '刚刚'
+ } else if (diff < 3600) { // less 1 hour
+ return Math.ceil(diff / 60) + '分钟前'
+ } else if (diff < 3600 * 24) {
+ return Math.ceil(diff / 3600) + '小时前'
+ } else if (diff < 3600 * 24 * 2) {
+ return '1天前'
+ }
+ if (option) {
+ return parseTime(time, option)
+ } else {
+ return d.getMonth() + 1 + '月' + d.getDate() + '日' + d.getHours() + '时' + d.getMinutes() + '分'
+ }
+}
// 格式化时间
- export function getQueryObject(url) {
- url = url == null ? window.location.href : url;
- const search = url.substring(url.lastIndexOf('?') + 1);
- const obj = {};
- const reg = /([^?&=]+)=([^?&=]*)/g;
- search.replace(reg, (rs, $1, $2) => {
- const name = decodeURIComponent($1);
- let val = decodeURIComponent($2);
- val = String(val);
- obj[name] = val;
- return rs;
- });
- return obj;
- }
-
+export function getQueryObject(url) {
+ url = url == null ? window.location.href : url
+ const search = url.substring(url.lastIndexOf('?') + 1)
+ const obj = {}
+ const reg = /([^?&=]+)=([^?&=]*)/g
+ search.replace(reg, (rs, $1, $2) => {
+ const name = decodeURIComponent($1)
+ let val = decodeURIComponent($2)
+ val = String(val)
+ obj[name] = val
+ return rs
+ })
+ return obj
+}
/**
*get getByteLen
* @param {Sting} val input value
* @returns {number} output value
*/
- export function getByteLen(val) {
- let len = 0;
- for (let i = 0; i < val.length; i++) {
- if (val[i].match(/[^\x00-\xff]/ig) != null) {
- len += 1;
- } else { len += 0.5; }
- }
- return Math.floor(len);
- }
+export function getByteLen(val) {
+ let len = 0
+ for (let i = 0; i < val.length; i++) {
+ if (val[i].match(/[^\x00-\xff]/ig) != null) {
+ len += 1
+ } else { len += 0.5 }
+ }
+ return Math.floor(len)
+}
- export function cleanArray(actual) {
- const newArray = [];
- for (let i = 0; i < actual.length; i++) {
- if (actual[i]) {
- newArray.push(actual[i]);
- }
- }
- return newArray;
- }
+export function cleanArray(actual) {
+ const newArray = []
+ for (let i = 0; i < actual.length; i++) {
+ if (actual[i]) {
+ newArray.push(actual[i])
+ }
+ }
+ return newArray
+}
- export function param(json) {
- if (!json) return '';
- return cleanArray(Object.keys(json).map(key => {
- if (json[key] === undefined) return '';
- return encodeURIComponent(key) + '=' +
- encodeURIComponent(json[key]);
- })).join('&');
- }
+export function param(json) {
+ if (!json) return ''
+ return cleanArray(Object.keys(json).map(key => {
+ if (json[key] === undefined) return ''
+ return encodeURIComponent(key) + '=' +
+ encodeURIComponent(json[key])
+ })).join('&')
+}
- export function param2Obj(url) {
- const search = url.split('?')[1];
- return JSON.parse('{"' + decodeURIComponent(search).replace(/"/g, '\\"').replace(/&/g, '","').replace(/=/g, '":"') + '"}')
- }
+export function param2Obj(url) {
+ const search = url.split('?')[1]
+ if (!search) {
+ return {}
+ }
+ return JSON.parse('{"' + decodeURIComponent(search).replace(/"/g, '\\"').replace(/&/g, '","').replace(/=/g, '":"') + '"}')
+}
- export function html2Text(val) {
- const div = document.createElement('div');
- div.innerHTML = val;
- return div.textContent || div.innerText;
- }
+export function html2Text(val) {
+ const div = document.createElement('div')
+ div.innerHTML = val
+ return div.textContent || div.innerText
+}
- export function objectMerge(target, source) {
- /* Merges two objects,
+export function objectMerge(target, source) {
+ /* Merges two objects,
giving the last one precedence */
- if (typeof target !== 'object') {
- target = {};
- }
- if (Array.isArray(source)) {
- return source.slice();
- }
- for (const property in source) {
- if (source.hasOwnProperty(property)) {
- const sourceProperty = source[property];
- if (typeof sourceProperty === 'object') {
- target[property] = objectMerge(target[property], sourceProperty);
- continue;
- }
- target[property] = sourceProperty;
- }
- }
- return target;
- }
+ if (typeof target !== 'object') {
+ target = {}
+ }
+ if (Array.isArray(source)) {
+ return source.slice()
+ }
+ for (const property in source) {
+ if (source.hasOwnProperty(property)) {
+ const sourceProperty = source[property]
+ if (typeof sourceProperty === 'object') {
+ target[property] = objectMerge(target[property], sourceProperty)
+ continue
+ }
+ target[property] = sourceProperty
+ }
+ }
+ return target
+}
+export function scrollTo(element, to, duration) {
+ if (duration <= 0) return
+ const difference = to - element.scrollTop
+ const perTick = difference / duration * 10
+ setTimeout(() => {
+ console.log(new Date())
+ element.scrollTop = element.scrollTop + perTick
+ if (element.scrollTop === to) return
+ scrollTo(element, to, duration - 10)
+ }, 10)
+}
- export function scrollTo(element, to, duration) {
- if (duration <= 0) return;
- const difference = to - element.scrollTop;
- const perTick = difference / duration * 10;
- setTimeout(() => {
- console.log(new Date())
- element.scrollTop = element.scrollTop + perTick;
- if (element.scrollTop === to) return;
- scrollTo(element, to, duration - 10);
- }, 10);
- }
+export function toggleClass(element, className) {
+ if (!element || !className) {
+ return
+ }
+ let classString = element.className
+ const nameIndex = classString.indexOf(className)
+ if (nameIndex === -1) {
+ classString += '' + className
+ } else {
+ classString = classString.substr(0, nameIndex) + classString.substr(nameIndex + className.length)
+ }
+ element.className = classString
+}
- export function toggleClass(element, className) {
- if (!element || !className) {
- return;
- }
- let classString = element.className;
- const nameIndex = classString.indexOf(className);
- if (nameIndex === -1) {
- classString += '' + className;
- } else {
- classString = classString.substr(0, nameIndex) + classString.substr(nameIndex + className.length);
- }
- element.className = classString;
- }
+export const pickerOptions = [
+ {
+ text: '今天',
+ onClick(picker) {
+ const end = new Date()
+ const start = new Date(new Date().toDateString())
+ end.setTime(start.getTime())
+ picker.$emit('pick', [start, end])
+ }
+ }, {
+ text: '最近一周',
+ onClick(picker) {
+ const end = new Date(new Date().toDateString())
+ const start = new Date()
+ start.setTime(end.getTime() - 3600 * 1000 * 24 * 7)
+ picker.$emit('pick', [start, end])
+ }
+ }, {
+ text: '最近一个月',
+ onClick(picker) {
+ const end = new Date(new Date().toDateString())
+ const start = new Date()
+ start.setTime(start.getTime() - 3600 * 1000 * 24 * 30)
+ picker.$emit('pick', [start, end])
+ }
+ }, {
+ text: '最近三个月',
+ onClick(picker) {
+ const end = new Date(new Date().toDateString())
+ const start = new Date()
+ start.setTime(start.getTime() - 3600 * 1000 * 24 * 90)
+ picker.$emit('pick', [start, end])
+ }
+ }]
- export const pickerOptions = [
- {
- text: '今天',
- onClick(picker) {
- const end = new Date();
- const start = new Date(new Date().toDateString());
- end.setTime(start.getTime());
- picker.$emit('pick', [start, end]);
- }
- }, {
- text: '最近一周',
- onClick(picker) {
- const end = new Date(new Date().toDateString());
- const start = new Date();
- start.setTime(end.getTime() - 3600 * 1000 * 24 * 7);
- picker.$emit('pick', [start, end]);
- }
- }, {
- text: '最近一个月',
- onClick(picker) {
- const end = new Date(new Date().toDateString());
- const start = new Date();
- start.setTime(start.getTime() - 3600 * 1000 * 24 * 30);
- picker.$emit('pick', [start, end]);
- }
- }, {
- text: '最近三个月',
- onClick(picker) {
- const end = new Date(new Date().toDateString());
- const start = new Date();
- start.setTime(start.getTime() - 3600 * 1000 * 24 * 90);
- picker.$emit('pick', [start, end]);
- }
- }]
+export function getTime(type) {
+ if (type === 'start') {
+ return new Date().getTime() - 3600 * 1000 * 24 * 90
+ } else {
+ return new Date(new Date().toDateString())
+ }
+}
- export function getTime(type) {
- if (type === 'start') {
- return new Date().getTime() - 3600 * 1000 * 24 * 90
- } else {
- return new Date(new Date().toDateString())
- }
- }
+export function debounce(func, wait, immediate) {
+ let timeout, args, context, timestamp, result
+ const later = function() {
+ // 据上一次触发时间间隔
+ const last = +new Date() - timestamp
+
+ // 上次被包装函数被调用时间间隔last小于设定时间间隔wait
+ if (last < wait && last > 0) {
+ timeout = setTimeout(later, wait - last)
+ } else {
+ timeout = null
+ // 如果设定为immediate===true,因为开始边界已经调用过了此处无需调用
+ if (!immediate) {
+ result = func.apply(context, args)
+ if (!timeout) context = args = null
+ }
+ }
+ }
+
+ return function(...args) {
+ context = this
+ timestamp = +new Date()
+ const callNow = immediate && !timeout
+ // 如果延时不存在,重新设定延时
+ if (!timeout) timeout = setTimeout(later, wait)
+ if (callNow) {
+ result = func.apply(context, args)
+ context = args = null
+ }
+
+ return result
+ }
+}
+
+export function deepClone(source) {
+ if (!source && typeof source !== 'object') {
+ throw new Error('error arguments', 'shallowClone')
+ }
+ const targetObj = source.constructor === Array ? [] : {}
+ for (const keys in source) {
+ if (source.hasOwnProperty(keys)) {
+ if (source[keys] && typeof source[keys] === 'object') {
+ targetObj[keys] = source[keys].constructor === Array ? [] : {}
+ targetObj[keys] = deepClone(source[keys])
+ } else {
+ targetObj[keys] = source[keys]
+ }
+ }
+ }
+ return targetObj
+}
+
+// get dependencies verison from package.json
+export function getVersion(name) {
+ const p = require('../../package')
+ return p.dependencies[name]
+}
diff --git a/src/utils/openWindow.js b/src/utils/openWindow.js
index a7e2b91c..b63dfbb4 100644
--- a/src/utils/openWindow.js
+++ b/src/utils/openWindow.js
@@ -7,21 +7,20 @@
*/
export default function openWindow(url, title, w, h) {
- // Fixes dual-screen position Most browsers Firefox
- const dualScreenLeft = window.screenLeft !== undefined ? window.screenLeft : screen.left;
- const dualScreenTop = window.screenTop !== undefined ? window.screenTop : screen.top;
+ // Fixes dual-screen position Most browsers Firefox
+ const dualScreenLeft = window.screenLeft !== undefined ? window.screenLeft : screen.left
+ const dualScreenTop = window.screenTop !== undefined ? window.screenTop : screen.top
- const width = window.innerWidth ? window.innerWidth : document.documentElement.clientWidth ? document.documentElement.clientWidth : screen.width;
- const height = window.innerHeight ? window.innerHeight : document.documentElement.clientHeight ? document.documentElement.clientHeight : screen.height;
+ const width = window.innerWidth ? window.innerWidth : document.documentElement.clientWidth ? document.documentElement.clientWidth : screen.width
+ const height = window.innerHeight ? window.innerHeight : document.documentElement.clientHeight ? document.documentElement.clientHeight : screen.height
- const left = ((width / 2) - (w / 2)) + dualScreenLeft;
- const top = ((height / 2) - (h / 2)) + dualScreenTop;
- const newWindow = window.open(url, title, 'toolbar=no, location=no, directories=no, status=no, menubar=no, scrollbars=no, resizable=yes, copyhistory=no, width=' + w + ', height=' + h + ', top=' + top + ', left=' + left);
+ const left = ((width / 2) - (w / 2)) + dualScreenLeft
+ const top = ((height / 2) - (h / 2)) + dualScreenTop
+ const newWindow = window.open(url, title, 'toolbar=no, location=no, directories=no, status=no, menubar=no, scrollbars=no, resizable=yes, copyhistory=no, width=' + w + ', height=' + h + ', top=' + top + ', left=' + left)
// Puts focus on the newWindow
if (window.focus) {
- newWindow.focus();
+ newWindow.focus()
}
}
-
diff --git a/src/utils/request.js b/src/utils/request.js
new file mode 100644
index 00000000..ee007f1f
--- /dev/null
+++ b/src/utils/request.js
@@ -0,0 +1,65 @@
+import axios from 'axios'
+import { Message } from 'element-ui'
+import store from '@/store'
+import { getToken } from '@/utils/auth'
+
+// 创建axios实例
+const service = axios.create({
+ baseURL: process.env.BASE_API, // api的base_url
+ timeout: 5000 // 请求超时时间
+})
+
+// request拦截器
+service.interceptors.request.use(config => {
+ // Do something before request is sent
+ if (store.getters.token) {
+ config.headers['X-Token'] = getToken() // 让每个请求携带token--['X-Token']为自定义key 请根据实际情况自行修改
+ }
+ return config
+}, error => {
+ // Do something with request error
+ console.log(error) // for debug
+ Promise.reject(error)
+})
+
+// respone拦截器
+service.interceptors.response.use(
+ response => response,
+ /**
+ * 下面的注释为通过response自定义code来标示请求状态,当code返回如下情况为权限有问题,登出并返回到登录页
+ * 如通过xmlhttprequest 状态码标识 逻辑可写在下面error中
+ */
+ // const res = response.data;
+ // if (res.code !== 20000) {
+ // Message({
+ // message: res.message,
+ // type: 'error',
+ // duration: 5 * 1000
+ // });
+ // // 50008:非法的token; 50012:其他客户端登录了; 50014:Token 过期了;
+ // if (res.code === 50008 || res.code === 50012 || res.code === 50014) {
+ // MessageBox.confirm('你已被登出,可以取消继续留在该页面,或者重新登录', '确定登出', {
+ // confirmButtonText: '重新登录',
+ // cancelButtonText: '取消',
+ // type: 'warning'
+ // }).then(() => {
+ // store.dispatch('FedLogOut').then(() => {
+ // location.reload();// 为了重新实例化vue-router对象 避免bug
+ // });
+ // })
+ // }
+ // return Promise.reject('error');
+ // } else {
+ // return response.data;
+ // }
+ error => {
+ console.log('err' + error)// for debug
+ Message({
+ message: error.message,
+ type: 'error',
+ duration: 5 * 1000
+ })
+ return Promise.reject(error)
+ })
+
+export default service
diff --git a/src/utils/validate.js b/src/utils/validate.js
index 3dbc5fec..5bdd1b43 100644
--- a/src/utils/validate.js
+++ b/src/utils/validate.js
@@ -2,40 +2,42 @@
* Created by jiachenpan on 16/11/18.
*/
-/* 是否是公司邮箱*/
-export function isWscnEmail(str) {
- const reg = /^[a-z0-9](?:[-_.+]?[a-z0-9]+)*@wallstreetcn\.com$/i;
- return reg.test(str.trim());
+export function isvalidUsername(str) {
+ const valid_map = ['admin', 'editor']
+ return valid_map.indexOf(str.trim()) >= 0
}
/* 合法uri*/
export function validateURL(textval) {
- const urlregex = /^(https?|ftp):\/\/([a-zA-Z0-9.-]+(:[a-zA-Z0-9.&%$-]+)*@)*((25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]?)(\.(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3}|([a-zA-Z0-9-]+\.)*[a-zA-Z0-9-]+\.(com|edu|gov|int|mil|net|org|biz|arpa|info|name|pro|aero|coop|museum|[a-zA-Z]{2}))(:[0-9]+)*(\/($|[a-zA-Z0-9.,?'\\+&%$#=~_-]+))*$/;
- return urlregex.test(textval);
+ const urlregex = /^(https?|ftp):\/\/([a-zA-Z0-9.-]+(:[a-zA-Z0-9.&%$-]+)*@)*((25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]?)(\.(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3}|([a-zA-Z0-9-]+\.)*[a-zA-Z0-9-]+\.(com|edu|gov|int|mil|net|org|biz|arpa|info|name|pro|aero|coop|museum|[a-zA-Z]{2}))(:[0-9]+)*(\/($|[a-zA-Z0-9.,?'\\+&%$#=~_-]+))*$/
+ return urlregex.test(textval)
}
/* 小写字母*/
export function validateLowerCase(str) {
- const reg = /^[a-z]+$/;
- return reg.test(str);
+ const reg = /^[a-z]+$/
+ return reg.test(str)
}
-/* 验证key*/
-// export function validateKey(str) {
-// var reg = /^[a-z_\-:]+$/;
-// return reg.test(str);
-// }
-
/* 大写字母*/
export function validateUpperCase(str) {
- const reg = /^[A-Z]+$/;
- return reg.test(str);
+ const reg = /^[A-Z]+$/
+ return reg.test(str)
}
/* 大小写字母*/
export function validatAlphabets(str) {
- const reg = /^[A-Za-z]+$/;
- return reg.test(str);
+ const reg = /^[A-Za-z]+$/
+ return reg.test(str)
}
+/**
+ * validate email
+ * @param email
+ * @returns {boolean}
+ */
+export function validateEmail(email) {
+ const re = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/
+ return re.test(email)
+}
diff --git a/src/vendor/Export2Excel.js b/src/vendor/Export2Excel.js
index a121a33a..f7765e9a 100644
--- a/src/vendor/Export2Excel.js
+++ b/src/vendor/Export2Excel.js
@@ -1,7 +1,8 @@
/* eslint-disable */
require('script-loader!file-saver');
require('script-loader!vendor/Blob');
-require('script-loader!xlsx/dist/xlsx.core.min');
+import XLSX from 'xlsx'
+
function generateArray(table) {
var out = [];
var rows = table.querySelectorAll('tr');
@@ -93,14 +94,12 @@ function s2ab(s) {
export function export_table_to_excel(id) {
var theTable = document.getElementById(id);
- console.log('a')
var oo = generateArray(theTable);
var ranges = oo[1];
/* original data */
var data = oo[0];
var ws_name = "SheetJS";
- console.log(data);
var wb = new Workbook(), ws = sheet_from_array_of_arrays(data);
@@ -117,9 +116,6 @@ export function export_table_to_excel(id) {
saveAs(new Blob([s2ab(wbout)], {type: "application/octet-stream"}), "test.xlsx")
}
-function formatJson(jsonData) {
- console.log(jsonData)
-}
export function export_json_to_excel(th, jsonData, defaultTitle) {
/* original data */
@@ -130,12 +126,35 @@ export function export_json_to_excel(th, jsonData, defaultTitle) {
var wb = new Workbook(), ws = sheet_from_array_of_arrays(data);
+ /*设置worksheet每列的最大宽度*/
+ const colWidth = data.map(row => row.map(val => {
+ /*先判断是否为null/undefined*/
+ if (val == null) {
+ return {'wch': 10};
+ }
+ /*再判断是否为中文*/
+ else if (val.toString().charCodeAt(0) > 255) {
+ return {'wch': val.toString().length * 2};
+ } else {
+ return {'wch': val.toString().length};
+ }
+ }))
+ /*以第一行为初始值*/
+ let result = colWidth[0];
+ for (let i = 1; i < colWidth.length; i++) {
+ for (let j = 0; j < colWidth[i].length; j++) {
+ if (result[j]['wch'] < colWidth[i][j]['wch']) {
+ result[j]['wch'] = colWidth[i][j]['wch'];
+ }
+ }
+ }
+ ws['!cols'] = result;
/* add worksheet to workbook */
wb.SheetNames.push(ws_name);
wb.Sheets[ws_name] = ws;
var wbout = XLSX.write(wb, {bookType: 'xlsx', bookSST: false, type: 'binary'});
- var title = defaultTitle || '列表'
+ var title = defaultTitle || 'excel-list'
saveAs(new Blob([s2ab(wbout)], {type: "application/octet-stream"}), title + ".xlsx")
}
diff --git a/src/vendor/Export2Zip.js b/src/vendor/Export2Zip.js
new file mode 100644
index 00000000..6e11dc83
--- /dev/null
+++ b/src/vendor/Export2Zip.js
@@ -0,0 +1,22 @@
+/* eslint-disable */
+require('script-loader!file-saver');
+import JSZip from 'jszip'
+
+export function export_txt_to_zip(th, jsonData, txtName, zipName) {
+ const zip = new JSZip()
+ const txt_name = txtName || 'file'
+ const zip_name = zipName || 'file'
+ const data = jsonData
+ let txtData = `${th}\r\n`
+ data.forEach((row) => {
+ let tempStr = ''
+ tempStr = row.toString()
+ txtData += `${tempStr}\r\n`
+ })
+ zip.file(`${txt_name}.txt`, txtData)
+ zip.generateAsync({type:"blob"}).then((blob) => {
+ saveAs(blob, `${zip_name}.zip`)
+ }, (err) => {
+ alert('导出失败')
+ })
+}
diff --git a/src/views/charts/index.vue b/src/views/charts/index.vue
deleted file mode 100644
index 7ca2a285..00000000
--- a/src/views/charts/index.vue
+++ /dev/null
@@ -1,7 +0,0 @@
-
-
-
- 这里的所有的图表都基于ECharts,实例代码来源gallery
其实ECharts封装的很好了,用vue封装是很简单的事情,建议大家自己来封装。相关教程
-
-
-
diff --git a/src/views/charts/keyboard.vue b/src/views/charts/keyboard.vue
index 76840715..4001811e 100644
--- a/src/views/charts/keyboard.vue
+++ b/src/views/charts/keyboard.vue
@@ -1,16 +1,18 @@
-
diff --git a/src/views/charts/line.vue b/src/views/charts/line.vue
index 975cf915..6d62e52f 100644
--- a/src/views/charts/line.vue
+++ b/src/views/charts/line.vue
@@ -1,16 +1,18 @@
+
diff --git a/src/views/components-demo/backToTop.vue b/src/views/components-demo/backToTop.vue
new file mode 100644
index 00000000..51d7879e
--- /dev/null
+++ b/src/views/components-demo/backToTop.vue
@@ -0,0 +1,157 @@
+
+
+
页面滚动到指定位置会在右下角出现返回顶部按钮
+
可自定义按钮的样式、show/hide临界点、返回的位置 如需文字提示,可在外部使用Element的el-tooltip元素
+
我是占位
+
我是占位
+
我是占位
+
我是占位
+
我是占位
+
我是占位
+
我是占位
+
我是占位
+
我是占位
+
我是占位
+
我是占位
+
我是占位
+
我是占位
+
我是占位
+
我是占位
+
我是占位
+
我是占位
+
我是占位
+
我是占位
+
我是占位
+
我是占位
+
我是占位
+
我是占位
+
我是占位
+
我是占位
+
我是占位
+
我是占位
+
我是占位
+
我是占位
+
我是占位
+
我是占位
+
我是占位
+
我是占位
+
我是占位
+
我是占位
+
我是占位
+
我是占位
+
我是占位
+
我是占位
+
我是占位
+
我是占位
+
我是占位
+
我是占位
+
我是占位
+
我是占位
+
我是占位
+
我是占位
+
我是占位
+
我是占位
+
我是占位
+
我是占位
+
我是占位
+
我是占位
+
我是占位
+
我是占位
+
我是占位
+
我是占位
+
我是占位
+
我是占位
+
我是占位
+
我是占位
+
我是占位
+
我是占位
+
我是占位
+
我是占位
+
我是占位
+
我是占位
+
我是占位
+
我是占位
+
我是占位
+
我是占位
+
我是占位
+
我是占位
+
我是占位
+
我是占位
+
我是占位
+
我是占位
+
我是占位
+
我是占位
+
我是占位
+
我是占位
+
我是占位
+
我是占位
+
我是占位
+
我是占位
+
我是占位
+
我是占位
+
我是占位
+
我是占位
+
我是占位
+
我是占位
+
我是占位
+
我是占位
+
我是占位
+
我是占位
+
我是占位
+
我是占位
+
我是占位
+
我是占位
+
我是占位
+
我是占位
+
我是占位
+
我是占位
+
我是占位
+
我是占位
+
我是占位
+
我是占位
+
我是占位
+
我是占位
+
我是占位
+
我是占位
+
我是占位
+
我是占位
+
我是占位
+
我是占位
+
我是占位
+
我是占位
+
我是占位
+
我是占位
+
我是占位
+
我是占位
+
我是占位
+
我是占位
+
我是占位
+
+
+
+
+
+
+
+
+
diff --git a/src/views/components-demo/countTo.vue b/src/views/components-demo/countTo.vue
new file mode 100644
index 00000000..b30204d9
--- /dev/null
+++ b/src/views/components-demo/countTo.vue
@@ -0,0 +1,205 @@
+
+
+
+ countTo-component
+
+
+
+
<count-to :start-val='{{_startVal}}' :end-val='{{_endVal}}' :duration='{{_duration}}'
+ :decimals='{{_decimals}}' :separator='{{_separator}}' :prefix='{{_prefix}}' :suffix='{{_suffix}}'
+ :autoplay=false>
+
+
+
+
+
+
+
+
diff --git a/src/views/components-demo/dndList.vue b/src/views/components-demo/dndList.vue
new file mode 100644
index 00000000..140e4c7f
--- /dev/null
+++ b/src/views/components-demo/dndList.vue
@@ -0,0 +1,40 @@
+
+
+
+
+
+
+
diff --git a/src/views/components-demo/dropzone.vue b/src/views/components-demo/dropzone.vue
new file mode 100644
index 00000000..6af6ae2e
--- /dev/null
+++ b/src/views/components-demo/dropzone.vue
@@ -0,0 +1,32 @@
+
+
+
+ 基于 dropzone 封装 ,
+ 由于我司业务有特殊需求,而且要传七牛 所以没用第三方 选择了自己封装
+
+
+
+
+
+
+
+
+
+
diff --git a/src/views/components-demo/jsonEditor.vue b/src/views/components-demo/jsonEditor.vue
new file mode 100644
index 00000000..c3b12813
--- /dev/null
+++ b/src/views/components-demo/jsonEditor.vue
@@ -0,0 +1,32 @@
+
+
+
JsonEditor is base on CodeMirrorr , lint base on json-lint
+
+
+
+
+
+
+
+
+
+
diff --git a/src/views/components-demo/markdown.vue b/src/views/components-demo/markdown.vue
new file mode 100644
index 00000000..afd07c6c
--- /dev/null
+++ b/src/views/components-demo/markdown.vue
@@ -0,0 +1,49 @@
+
+
+
+
+
+
+
diff --git a/src/views/components-demo/mixin.vue b/src/views/components-demo/mixin.vue
new file mode 100644
index 00000000..e6a29b40
--- /dev/null
+++ b/src/views/components-demo/mixin.vue
@@ -0,0 +1,153 @@
+
+
+
+
+
+ Buttons
+
+
+
+ Components
+
+
+ Charts
+
+
+ Excel
+
+
+ Table
+
+
+ Form
+
+
+ Theme
+
+
+
+
+
+
+
+
+
+ Material Design 的input
+
+
+
+
+ 标题
+
+
+
+
+
+
+
+
+
+ 图片hover效果
+
+
+
+ vue-element-admin
+
+
+
+
+
+
+
+
+ 水波纹 waves v-directive
+
+
+ 水波纹效果
+
+
+
+
+
+
+
+ hover text
+
+
+
+
+
+
+
+
+
+
+
+
+ Share
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/views/components-demo/splitpane.vue b/src/views/components-demo/splitpane.vue
new file mode 100644
index 00000000..fa3f14a4
--- /dev/null
+++ b/src/views/components-demo/splitpane.vue
@@ -0,0 +1,67 @@
+
+
+
+
+
+
+
diff --git a/src/views/components/sticky.vue b/src/views/components-demo/sticky.vue
similarity index 83%
rename from src/views/components/sticky.vue
rename to src/views/components-demo/sticky.vue
index 6e29d19f..014d71fa 100644
--- a/src/views/components/sticky.vue
+++ b/src/views/components-demo/sticky.vue
@@ -1,6 +1,6 @@
-
+
平台
@@ -32,7 +32,7 @@
发布
-
+
Sticky header 当页面滚动到预设的位置会吸附在顶部
@@ -90,33 +90,35 @@
我是占位
-
-
+
+
+
diff --git a/src/views/components/avatarUpload.vue b/src/views/components/avatarUpload.vue
deleted file mode 100644
index 47858560..00000000
--- a/src/views/components/avatarUpload.vue
+++ /dev/null
@@ -1,48 +0,0 @@
-
-
-
这里核心代码用的是vue-image-crop-upload
- 由于我在使用时它只有vue@1版本,而且有些业务的需求耦合到七牛等等原因吧,自己改造了一下,如果大家要使用的话,优先还是使用官方component
-
-
-
-
-
修改头像
-
-
-
-
-
-
-
-
-
diff --git a/src/views/components/countTo.vue b/src/views/components/countTo.vue
deleted file mode 100644
index f0d6cb42..00000000
--- a/src/views/components/countTo.vue
+++ /dev/null
@@ -1,187 +0,0 @@
-
-
-
countTo component
-
-
-
-
<count-to :start-val='{{_startVal}}' :end-val='{{_endVal}}' :duration='{{_duration}}' :decimals='{{_decimals}}'
- :separator='{{_separator}}' :prefix='{{_prefix}}' :suffix='{{_suffix}}' :autoplay=false>
-
-
-
-
-
-
-
-
diff --git a/src/views/components/dndlist.vue b/src/views/components/dndlist.vue
deleted file mode 100644
index d5b82950..00000000
--- a/src/views/components/dndlist.vue
+++ /dev/null
@@ -1,36 +0,0 @@
-
-
-
-
-
-
diff --git a/src/views/components/dropzone.vue b/src/views/components/dropzone.vue
deleted file mode 100644
index 1eb3557b..00000000
--- a/src/views/components/dropzone.vue
+++ /dev/null
@@ -1,30 +0,0 @@
-
-
-
https://github.com/rowanwins/vue-dropzone
- 由于我司业务有特殊需求,而且要传七牛 所以没用第三方 选择了自己封装
-
-
-
-
-
-
-
-
-
diff --git a/src/views/components/index.vue b/src/views/components/index.vue
deleted file mode 100644
index 661c4835..00000000
--- a/src/views/components/index.vue
+++ /dev/null
@@ -1,7 +0,0 @@
-
-
-
这里暂时列出了自己在项目中用到的组件和一些自己封装的组件,如有补充可以提 issue
- 我个人崇尚自己封装组件,因为很多组件会和业务后高度的耦合,而且第三方封装的组件灵活性可控性都不高,如有需要可以看楼主之前写过的一篇文章
-
-
-
diff --git a/src/views/components/jsoneditor.vue b/src/views/components/jsoneditor.vue
deleted file mode 100644
index 1391394b..00000000
--- a/src/views/components/jsoneditor.vue
+++ /dev/null
@@ -1,29 +0,0 @@
-
-
-
jsonEditor is base on CodeMirrorr,lint base on json-lint
-
-
-
-
-
-
-
-
-
-
diff --git a/src/views/components/markdown.vue b/src/views/components/markdown.vue
deleted file mode 100644
index 3ebb371a..00000000
--- a/src/views/components/markdown.vue
+++ /dev/null
@@ -1,33 +0,0 @@
-
-
-
-
-
-
-
diff --git a/src/views/components/mixin.vue b/src/views/components/mixin.vue
deleted file mode 100644
index f8d8d5e0..00000000
--- a/src/views/components/mixin.vue
+++ /dev/null
@@ -1,45 +0,0 @@
-
-
-
-
- 标题
-
- Material Design 的input
-
-
-
-
- 上海花裤衩
-
-
图片hover效果
-
-
-
- 水波纹效果
- 水波纹 v-directive
-
-
-
-
-
-
-
diff --git a/src/views/components/splitpane.vue b/src/views/components/splitpane.vue
deleted file mode 100644
index 47e193c0..00000000
--- a/src/views/components/splitpane.vue
+++ /dev/null
@@ -1,62 +0,0 @@
-
-
-
splitPane 如果你用过codepen,jsfiddle就不会陌生了
- 暂还没有时间开源封装好,日后补上
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/views/components/tinymce.vue b/src/views/components/tinymce.vue
deleted file mode 100644
index 374e0956..00000000
--- a/src/views/components/tinymce.vue
+++ /dev/null
@@ -1,30 +0,0 @@
-
-
-
公司做的后台主要是一个cms系统,公司也是以自媒体为核心的,所以富文本是后台很核心的功能。在选择富文本的过程中也走了不少的弯路,市面上常见的富文本都基本用过了,最终选择了Tinymce 相关文章
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/views/dashboard/admin/components/BarChart.vue b/src/views/dashboard/admin/components/BarChart.vue
new file mode 100644
index 00000000..78e71a93
--- /dev/null
+++ b/src/views/dashboard/admin/components/BarChart.vue
@@ -0,0 +1,106 @@
+
+
+
+
+
diff --git a/src/views/dashboard/admin/components/BoxCard.vue b/src/views/dashboard/admin/components/BoxCard.vue
new file mode 100644
index 00000000..23fdc13e
--- /dev/null
+++ b/src/views/dashboard/admin/components/BoxCard.vue
@@ -0,0 +1,111 @@
+
+
+
+
+
+
+
+ Vue
+
+
+
+ JavaScript
+
+
+
+ Css
+
+
+
+ ESLint
+
+
+
+
+
+
+
+
+
+
diff --git a/src/views/dashboard/admin/components/LineChart.vue b/src/views/dashboard/admin/components/LineChart.vue
new file mode 100644
index 00000000..df96887b
--- /dev/null
+++ b/src/views/dashboard/admin/components/LineChart.vue
@@ -0,0 +1,150 @@
+
+
+
+
+
diff --git a/src/views/dashboard/admin/components/PanelGroup.vue b/src/views/dashboard/admin/components/PanelGroup.vue
new file mode 100644
index 00000000..54e797fc
--- /dev/null
+++ b/src/views/dashboard/admin/components/PanelGroup.vue
@@ -0,0 +1,136 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/views/dashboard/admin/components/PieChart.vue b/src/views/dashboard/admin/components/PieChart.vue
new file mode 100644
index 00000000..36a11227
--- /dev/null
+++ b/src/views/dashboard/admin/components/PieChart.vue
@@ -0,0 +1,84 @@
+
+
+
+
+
diff --git a/src/views/dashboard/admin/components/RaddarChart.vue b/src/views/dashboard/admin/components/RaddarChart.vue
new file mode 100644
index 00000000..017b9748
--- /dev/null
+++ b/src/views/dashboard/admin/components/RaddarChart.vue
@@ -0,0 +1,120 @@
+
+
+
+
+
diff --git a/src/views/dashboard/admin/components/TodoList/Todo.vue b/src/views/dashboard/admin/components/TodoList/Todo.vue
new file mode 100644
index 00000000..028acfc7
--- /dev/null
+++ b/src/views/dashboard/admin/components/TodoList/Todo.vue
@@ -0,0 +1,70 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/views/dashboard/admin/components/TodoList/index.scss b/src/views/dashboard/admin/components/TodoList/index.scss
new file mode 100644
index 00000000..f004e6aa
--- /dev/null
+++ b/src/views/dashboard/admin/components/TodoList/index.scss
@@ -0,0 +1,321 @@
+.todoapp {
+ font: 14px 'Helvetica Neue', Helvetica, Arial, sans-serif;
+ line-height: 1.4em;
+ color: #4d4d4d;
+ min-width: 230px;
+ max-width: 550px;
+ margin: 0 auto ;
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
+ font-weight: 300;
+ background: #fff;
+ z-index: 1;
+ position: relative;
+ button {
+ margin: 0;
+ padding: 0;
+ border: 0;
+ background: none;
+ font-size: 100%;
+ vertical-align: baseline;
+ font-family: inherit;
+ font-weight: inherit;
+ color: inherit;
+ -webkit-appearance: none;
+ appearance: none;
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
+ }
+ :focus {
+ outline: 0;
+ }
+ .hidden {
+ display: none;
+ }
+ .todoapp {
+ background: #fff;
+ margin: 130px 0 40px 0;
+ position: relative;
+ box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.2), 0 25px 50px 0 rgba(0, 0, 0, 0.1);
+ }
+ .todoapp input::-webkit-input-placeholder {
+ font-style: italic;
+ font-weight: 300;
+ color: #e6e6e6;
+ }
+ .todoapp input::-moz-placeholder {
+ font-style: italic;
+ font-weight: 300;
+ color: #e6e6e6;
+ }
+ .todoapp input::input-placeholder {
+ font-style: italic;
+ font-weight: 300;
+ color: #e6e6e6;
+ }
+ .todoapp h1 {
+ position: absolute;
+ top: -155px;
+ width: 100%;
+ font-size: 100px;
+ font-weight: 100;
+ text-align: center;
+ color: rgba(175, 47, 47, 0.15);
+ -webkit-text-rendering: optimizeLegibility;
+ -moz-text-rendering: optimizeLegibility;
+ text-rendering: optimizeLegibility;
+ }
+ .new-todo,
+ .edit {
+ position: relative;
+ margin: 0;
+ width: 100%;
+ font-size: 18px;
+ font-family: inherit;
+ font-weight: inherit;
+ line-height: 1.4em;
+ border: 0;
+ color: inherit;
+ padding: 6px;
+ border: 1px solid #999;
+ box-shadow: inset 0 -1px 5px 0 rgba(0, 0, 0, 0.2);
+ box-sizing: border-box;
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
+ }
+ .new-todo {
+ padding: 10px 16px 16px 60px;
+ border: none;
+ background: rgba(0, 0, 0, 0.003);
+ box-shadow: inset 0 -2px 1px rgba(0, 0, 0, 0.03);
+ }
+ .main {
+ position: relative;
+ z-index: 2;
+ border-top: 1px solid #e6e6e6;
+ }
+ .toggle-all {
+ text-align: center;
+ border: none;
+ /* Mobile Safari */
+ opacity: 0;
+ position: absolute;
+ }
+ .toggle-all+label {
+ width: 60px;
+ height: 34px;
+ font-size: 0;
+ position: absolute;
+ top: -52px;
+ left: -13px;
+ -webkit-transform: rotate(90deg);
+ transform: rotate(90deg);
+ }
+ .toggle-all+label:before {
+ content: '❯';
+ font-size: 22px;
+ color: #e6e6e6;
+ padding: 10px 27px 10px 27px;
+ }
+ .toggle-all:checked+label:before {
+ color: #737373;
+ }
+ .todo-list {
+ margin: 0;
+ padding: 0;
+ list-style: none;
+ }
+ .todo-list li {
+ position: relative;
+ font-size: 24px;
+ border-bottom: 1px solid #ededed;
+ }
+ .todo-list li:last-child {
+ border-bottom: none;
+ }
+ .todo-list li.editing {
+ border-bottom: none;
+ padding: 0;
+ }
+ .todo-list li.editing .edit {
+ display: block;
+ width: 506px;
+ padding: 12px 16px;
+ margin: 0 0 0 43px;
+ }
+ .todo-list li.editing .view {
+ display: none;
+ }
+ .todo-list li .toggle {
+ text-align: center;
+ width: 40px;
+ /* auto, since non-WebKit browsers doesn't support input styling */
+ height: auto;
+ position: absolute;
+ top: 0;
+ bottom: 0;
+ margin: auto 0;
+ border: none;
+ /* Mobile Safari */
+ -webkit-appearance: none;
+ appearance: none;
+ }
+ .todo-list li .toggle {
+ opacity: 0;
+ }
+ .todo-list li .toggle+label {
+ /*
+ Firefox requires `#` to be escaped - https://bugzilla.mozilla.org/show_bug.cgi?id=922433
+ IE and Edge requires *everything* to be escaped to render, so we do that instead of just the `#` - https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/7157459/
+ */
+ background-image: url('data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20width%3D%2240%22%20height%3D%2240%22%20viewBox%3D%22-10%20-18%20100%20135%22%3E%3Ccircle%20cx%3D%2250%22%20cy%3D%2250%22%20r%3D%2250%22%20fill%3D%22none%22%20stroke%3D%22%23ededed%22%20stroke-width%3D%223%22/%3E%3C/svg%3E');
+ background-repeat: no-repeat;
+ background-position: center left;
+ background-size: 36px;
+ }
+ .todo-list li .toggle:checked+label {
+ background-size: 36px;
+ background-image: url('data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20width%3D%2240%22%20height%3D%2240%22%20viewBox%3D%22-10%20-18%20100%20135%22%3E%3Ccircle%20cx%3D%2250%22%20cy%3D%2250%22%20r%3D%2250%22%20fill%3D%22none%22%20stroke%3D%22%23bddad5%22%20stroke-width%3D%223%22/%3E%3Cpath%20fill%3D%22%235dc2af%22%20d%3D%22M72%2025L42%2071%2027%2056l-4%204%2020%2020%2034-52z%22/%3E%3C/svg%3E');
+ }
+ .todo-list li label {
+ word-break: break-all;
+ padding: 15px 15px 15px 50px;
+ display: block;
+ line-height: 1.0;
+ font-size: 14px;
+ transition: color 0.4s;
+ }
+ .todo-list li.completed label {
+ color: #d9d9d9;
+ text-decoration: line-through;
+ }
+ .todo-list li .destroy {
+ display: none;
+ position: absolute;
+ top: 0;
+ right: 10px;
+ bottom: 0;
+ width: 40px;
+ height: 40px;
+ margin: auto 0;
+ font-size: 30px;
+ color: #cc9a9a;
+ transition: color 0.2s ease-out;
+ }
+ .todo-list li .destroy:hover {
+ color: #af5b5e;
+ }
+ .todo-list li .destroy:after {
+ content: '×';
+ }
+ .todo-list li:hover .destroy {
+ display: block;
+ }
+ .todo-list li .edit {
+ display: none;
+ }
+ .todo-list li.editing:last-child {
+ margin-bottom: -1px;
+ }
+ .footer {
+ color: #777;
+ position: relative;
+ padding: 10px 15px;
+ height: 40px;
+ text-align: center;
+ border-top: 1px solid #e6e6e6;
+ }
+ .footer:before {
+ content: '';
+ position: absolute;
+ right: 0;
+ bottom: 0;
+ left: 0;
+ height: 50px;
+ overflow: hidden;
+ box-shadow: 0 1px 1px rgba(0, 0, 0, 0.2), 0 8px 0 -3px #f6f6f6, 0 9px 1px -3px rgba(0, 0, 0, 0.2), 0 16px 0 -6px #f6f6f6, 0 17px 2px -6px rgba(0, 0, 0, 0.2);
+ }
+ .todo-count {
+ float: left;
+ text-align: left;
+ }
+ .todo-count strong {
+ font-weight: 300;
+ }
+ .filters {
+ margin: 0;
+ padding: 0;
+ list-style: none;
+ position: absolute;
+ right: 0;
+ left: -20px;
+ }
+ .filters li {
+ display: inline;
+ }
+ .filters li a {
+ color: inherit;
+ margin: 3px;
+ font-size: 12px;
+ padding: 3px 7px;
+ text-decoration: none;
+ border: 1px solid transparent;
+ border-radius: 3px;
+ }
+ .filters li a:hover {
+ border-color: rgba(175, 47, 47, 0.1);
+ }
+ .filters li a.selected {
+ border-color: rgba(175, 47, 47, 0.2);
+ }
+ .clear-completed,
+ html .clear-completed:active {
+ float: right;
+ position: relative;
+ line-height: 20px;
+ text-decoration: none;
+ cursor: pointer;
+ }
+ .clear-completed:hover {
+ text-decoration: underline;
+ }
+ .info {
+ margin: 65px auto 0;
+ color: #bfbfbf;
+ font-size: 10px;
+ text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5);
+ text-align: center;
+ }
+ .info p {
+ line-height: 1;
+ }
+ .info a {
+ color: inherit;
+ text-decoration: none;
+ font-weight: 400;
+ }
+ .info a:hover {
+ text-decoration: underline;
+ }
+ /*
+ Hack to remove background from Mobile Safari.
+ Can't use it globally since it destroys checkboxes in Firefox
+*/
+ @media screen and (-webkit-min-device-pixel-ratio:0) {
+ .toggle-all,
+ .todo-list li .toggle {
+ background: none;
+ }
+ .todo-list li .toggle {
+ height: 40px;
+ }
+ }
+ @media (max-width: 430px) {
+ .footer {
+ height: 50px;
+ }
+ .filters {
+ bottom: 10px;
+ }
+ }
+}
diff --git a/src/views/dashboard/admin/components/TodoList/index.vue b/src/views/dashboard/admin/components/TodoList/index.vue
new file mode 100644
index 00000000..34f0241d
--- /dev/null
+++ b/src/views/dashboard/admin/components/TodoList/index.vue
@@ -0,0 +1,121 @@
+
+
+
+
+
+
+
diff --git a/src/views/dashboard/admin/components/TransactionTable.vue b/src/views/dashboard/admin/components/TransactionTable.vue
new file mode 100644
index 00000000..35a65153
--- /dev/null
+++ b/src/views/dashboard/admin/components/TransactionTable.vue
@@ -0,0 +1,55 @@
+
+
+
+
+ {{scope.row.order_no}}
+
+
+
+
+ ¥{{scope.row.price | toThousandslsFilter}}
+
+
+
+
+ {{scope.row.status}}
+
+
+
+
+
+
+
diff --git a/src/views/dashboard/admin/index.vue b/src/views/dashboard/admin/index.vue
new file mode 100644
index 00000000..95c9cd6b
--- /dev/null
+++ b/src/views/dashboard/admin/index.vue
@@ -0,0 +1,109 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/views/dashboard/default/index.vue b/src/views/dashboard/default/index.vue
deleted file mode 100644
index 9a16481f..00000000
--- a/src/views/dashboard/default/index.vue
+++ /dev/null
@@ -1,82 +0,0 @@
-
-
-
-
你的权限:
- {{item}}
-
-
-
-
-
- {{name}}
- 普通编辑dashboard
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/views/dashboard/editor/articlesChart.vue b/src/views/dashboard/editor/articlesChart.vue
deleted file mode 100644
index a62e1962..00000000
--- a/src/views/dashboard/editor/articlesChart.vue
+++ /dev/null
@@ -1,34 +0,0 @@
-
-
- 每天撸文
-
-
-
-
-
diff --git a/src/views/dashboard/editor/index.vue b/src/views/dashboard/editor/index.vue
index 74958c66..531c8067 100644
--- a/src/views/dashboard/editor/index.vue
+++ b/src/views/dashboard/editor/index.vue
@@ -1,295 +1,74 @@
-
-
-
你的权限:
- {{item}}
-
-
-
-
-
-
{{name}}
-
-
-
- 文章
-
-
-
-
- 浏览量
-
-
-
-
- 评论
-
-
-
-
-
-
-
- 组件
- 图表
- 错误页面
- 导出excel
- table
- form
-
-
-
-
-
-
最近撸了
-
-
-
- {{item.status | statusFilter}}
-
- {{item.title}}
-
- {{item.author}}
-
-
-
- 你太懒了最近都没有撸
-
-
-
-
+
+
+
你的权限:
+ {{item}}
+
+
+
+ {{name}}
+ 普通编辑dashboard
+
+
+
+
+
diff --git a/src/views/dashboard/editor/monthKpi.vue b/src/views/dashboard/editor/monthKpi.vue
deleted file mode 100644
index 7fdd7501..00000000
--- a/src/views/dashboard/editor/monthKpi.vue
+++ /dev/null
@@ -1,61 +0,0 @@
-
-
- {{month}}月
-
- 文章完成比例
- {{articlesComplete}}篇
-
-
-
-
-
diff --git a/src/views/dashboard/index.vue b/src/views/dashboard/index.vue
index 2e4ce06f..046f6e30 100644
--- a/src/views/dashboard/index.vue
+++ b/src/views/dashboard/index.vue
@@ -1,39 +1,31 @@
-
-
-
+
+
+
diff --git a/src/views/documentation/index.vue b/src/views/documentation/index.vue
new file mode 100644
index 00000000..c4009abc
--- /dev/null
+++ b/src/views/documentation/index.vue
@@ -0,0 +1,47 @@
+
+
+
+
+
+
+
diff --git a/src/views/errlog/index.vue b/src/views/errlog/index.vue
deleted file mode 100644
index 1d478d4e..00000000
--- a/src/views/errlog/index.vue
+++ /dev/null
@@ -1,29 +0,0 @@
-
-
-
-
-
请点击右上角bug小图表
-
- 现在的管理后台基本都是spa的形式了,它增强了用户体验,但同时也会怎增加页面出问题的可能性,可能一个小小的疏忽就导致整个页面的死锁。好在Vue官网提供了一个方法来捕获处理异常
-
-
-
-
-
-
-
-
diff --git a/src/views/error/404.vue b/src/views/error/404.vue
deleted file mode 100644
index 9122a895..00000000
--- a/src/views/error/404.vue
+++ /dev/null
@@ -1,219 +0,0 @@
-
-
-
-
-
-
OOPS!
-
-
{{ message }}
-
请检查您输入的网址是否正确,请点击以下按钮返回主页或者发送错误报告
-
返回首页
-
-
-
-
-
-
-
-
diff --git a/src/views/errlog/errcode.vue b/src/views/errorLog/errcode.vue
similarity index 100%
rename from src/views/errlog/errcode.vue
rename to src/views/errorLog/errcode.vue
diff --git a/src/views/errorLog/index.vue b/src/views/errorLog/index.vue
new file mode 100644
index 00000000..8703bf0a
--- /dev/null
+++ b/src/views/errorLog/index.vue
@@ -0,0 +1,26 @@
+
+
+
+
+
请点击右上角bug小图表
+
+ 现在的管理后台基本都是spa的形式了,它增强了用户体验,但同时也会增加页面出问题的可能性,可能一个小小的疏忽就导致整个页面的死锁。好在Vue官网提供了一个方法来捕获处理异常
+
+
+
+
+
+
+
+
diff --git a/src/views/error/401.vue b/src/views/errorPage/401.vue
similarity index 75%
rename from src/views/error/401.vue
rename to src/views/errorPage/401.vue
index bddfc1de..e36c83a2 100644
--- a/src/views/error/401.vue
+++ b/src/views/errorPage/401.vue
@@ -20,33 +20,34 @@
-
-
+
diff --git a/src/views/example/form.vue b/src/views/example/form.vue
deleted file mode 100644
index c48fcb91..00000000
--- a/src/views/example/form.vue
+++ /dev/null
@@ -1,300 +0,0 @@
-
-
-
-
-
-
-
-
-
-
- 创建form
-
- {{!postForm.comment_disabled?'评论已打开':'评论已关闭'}}
-
-
-
- 关闭评论
- 打开评论
-
-
-
-
-
-
-
-
- 平台
-
-
-
-
- {{item.name}}
-
-
-
-
-
-
-
- 外链
-
-
-
-
- 填写url
-
-
-
-
-
- 发布
-
- 草稿
-
-
-
- 发送异常错误,刷新页面,或者联系程序员
-
-
-
-
-
-
-
-
-
- 标题
-
- app可能会显示不全
-
-
-
-
-
-
-
- 无结果
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- {{contentShortLength}}字
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/views/example/tab/components/tabPane.vue b/src/views/example/tab/components/tabPane.vue
new file mode 100644
index 00000000..1052d609
--- /dev/null
+++ b/src/views/example/tab/components/tabPane.vue
@@ -0,0 +1,98 @@
+
+
+
+
+
+ {{scope.row.id}}
+
+
+
+
+
+ {{scope.row.timestamp | parseTime('{y}-{m}-{d} {h}:{i}')}}
+
+
+
+
+
+ {{scope.row.title}}
+ {{scope.row.type}}
+
+
+
+
+
+ {{scope.row.author}}
+
+
+
+
+
+
+
+
+
+
+
+ {{scope.row.pageviews}}
+
+
+
+
+
+ {{scope.row.status}}
+
+
+
+
+
+
+
+
diff --git a/src/views/example/tab/index.vue b/src/views/example/tab/index.vue
new file mode 100644
index 00000000..3e6a601f
--- /dev/null
+++ b/src/views/example/tab/index.vue
@@ -0,0 +1,44 @@
+
+
+ mounted times :{{createdTimes}}
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/views/example/table/complexTable.vue b/src/views/example/table/complexTable.vue
new file mode 100644
index 00000000..a890c0c6
--- /dev/null
+++ b/src/views/example/table/complexTable.vue
@@ -0,0 +1,352 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 搜索
+ 添加
+ 导出
+ 显示审核人
+
+
+
+
+
+ {{scope.row.id}}
+
+
+
+
+ {{scope.row.timestamp | parseTime('{y}-{m}-{d} {h}:{i}')}}
+
+
+
+
+ {{scope.row.title}}
+ {{scope.row.type | typeFilter}}
+
+
+
+
+ {{scope.row.author}}
+
+
+
+
+ {{scope.row.auditor}}
+
+
+
+
+
+
+
+
+
+ {{scope.row.pageviews}}
+ 无
+
+
+
+
+ {{scope.row.status}}
+
+
+
+
+ 编辑
+ 发布
+
+ 草稿
+
+ 删除
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/views/example/table/dragTable.vue b/src/views/example/table/dragTable.vue
index 512c8a25..9eb16f7c 100644
--- a/src/views/example/table/dragTable.vue
+++ b/src/views/example/table/dragTable.vue
@@ -4,123 +4,122 @@
-
+
{{scope.row.id}}
-
+
{{scope.row.timestamp | parseTime('{y}-{m}-{d} {h}:{i}')}}
-
+
{{scope.row.title}}
-
+
{{scope.row.author}}
-
-
+
+
-
+
{{scope.row.pageviews}}
-
-
+
+
{{scope.row.status}}
-
-
+
+
- 默认顺序 {{ olderList}}
+ 默认顺序 {{ olderList}}
拖拽后顺序{{newList}}