Compare commits

...

79 Commits

Author SHA1 Message Date
Pan
8b41d0fdc9 update readme 2017-07-06 18:15:12 +08:00
Pan
de992c50a6 全局代码格式 优化 2017-07-06 17:56:23 +08:00
Pan
622a8c3a69 refine icon-svg 2017-07-06 17:56:23 +08:00
花裤衩
9342ae6fc3 Update README.md 2017-07-04 16:17:39 +08:00
Pan
540168985d refine code 2017-07-04 16:14:04 +08:00
花裤衩
04261f7347 Update README.md 2017-07-04 15:52:12 +08:00
孙晨光
f0db0697e6 fix: todolist delete icon style 2017-07-03 20:23:23 +08:00
Pan
b3ddf60d04 rm duplicate code 2017-07-03 13:33:26 +08:00
卜木
4fa07aea09 Update index.js 2017-07-03 13:26:57 +08:00
卜木
56a048865d prevent JSON.parse fault when search is undefined 2017-07-03 13:26:57 +08:00
Pan
ffd668fb7d refine dashboard css 2017-07-03 12:45:31 +08:00
Pan
ed803c68b2 fix next bug 2017-07-03 12:45:31 +08:00
Pan
a1a4808c23 fix tabsview bug 2017-07-03 12:45:31 +08:00
Pan
cfa82b0714 fix next bug 2017-07-03 12:45:31 +08:00
Pan
506ecdc0ff split echarts into own file 2017-07-03 12:45:31 +08:00
Pan
8886ab2262 ADD TODOLIST 2017-07-03 12:45:31 +08:00
Pan
e3bc9c7e78 delete redundant code 2017-07-03 12:45:31 +08:00
Pan
54884f50c1 refine css 2017-07-03 12:45:31 +08:00
Pan
f27b16718e add new charts 2017-07-03 12:45:31 +08:00
Pan
4b4bf494b0 refine echarts demo 2017-06-30 15:36:21 +08:00
Pan
b15caf637f fix tabel demo bug 2017-06-30 13:40:18 +08:00
Pan
3466b9feb2 fix postcss bug 2017-06-30 11:31:21 +08:00
Pan
00e06fe44e ignore gifs 2017-06-28 16:04:19 +08:00
Pan
025c6cf038 add tabs gif 2017-06-28 16:00:56 +08:00
Pan
95ef202d20 fix screenfull bug 2017-06-27 14:20:50 +08:00
Pan
cb53ba891c refine code 2017-06-26 17:16:05 +08:00
Pan
805ab1d0ac add github link 2017-06-26 16:50:34 +08:00
Pan
33cf5ef16e refine code 2017-06-26 13:35:43 +08:00
Pan
63ad0fc2f5 refine code 2017-06-26 11:21:53 +08:00
Pan
80a281733a refine assets path config 2017-06-26 09:57:24 +08:00
Pan
f1aa01a233 fix theme example bug 2017-06-23 21:19:30 +08:00
Pan
5cd245ac15 split tabs-view to separate files 2017-06-23 17:56:45 +08:00
Pan
0c3063f46c Release 1.0.3 2017-06-23 17:38:30 +08:00
Pan
91cb0ac5ca add view tabs 2017-06-23 17:36:13 +08:00
Pan
7549eb8044 fix eslint && refine code 2017-06-23 15:39:13 +08:00
孙晨光
1072572ac6 update: 递归过滤异步路由表 2017-06-23 15:25:58 +08:00
Pan
046d1369d2 not use Lazy Loading In dev 2017-06-21 16:59:02 +08:00
Pan
657937c7a5 Revert "refine css"
This reverts commit 6de521d671.
2017-06-21 09:46:47 +08:00
Pan
6de521d671 refine css 2017-06-20 23:14:50 +08:00
Pan
dbf9638922 refine dynamictable example 2017-06-20 23:02:36 +08:00
轩辕Rowboat
aaa64a8ccf update format code
没用编辑器,所以代码没格式化/(ㄒoㄒ)/~~
2017-06-20 15:44:14 +08:00
轩辕Rowboat
ff8d7ada73 千分符考虑小数点 2017-06-20 15:44:14 +08:00
Pan
bf480ca6b4 fix router path bug 2017-06-19 18:14:31 +08:00
Pan
803201af3a fix error link 2017-06-19 18:02:19 +08:00
Pan
e97dbf6115 use babel-preset-env 2017-06-19 17:59:56 +08:00
Pan
cf1fb6cd4d refine demo code 2017-06-15 15:35:14 +08:00
Pan
7287894cb8 Release 1.0.2 2017-06-15 14:44:26 +08:00
Pan
29402cc889 fix typo 2017-06-15 14:35:48 +08:00
Pan
a1a96c38d7 add tabs example 2017-06-15 14:33:02 +08:00
Pan
2927e08d06 change mock data 2017-06-15 13:44:48 +08:00
Pan
5a8755ec9f add screenfull 2017-06-15 13:23:49 +08:00
Pan
3a2bf13a1f refine code 2017-06-15 11:05:41 +08:00
Pan
4a6ef1af17 degrade eslint
eslint4.0 has some problem
2017-06-15 10:49:27 +08:00
Pan
42b5875d36 upgrade babel-core 2017-06-15 10:39:03 +08:00
Pan
4af4df702c upgrade package.json 2017-06-15 10:38:12 +08:00
Pan
72d9a406b4 refine introduction document 2017-06-14 18:02:35 +08:00
Pan
bd607b4728 refine code && document 2017-06-14 18:02:12 +08:00
Pan
f82ec2d5d7 rm redundant code 2017-06-14 17:37:21 +08:00
Pan
c412d17b70 refine tinymce && tinymce demo 2017-06-14 17:34:32 +08:00
Pan
09deec1e5e update iconfont 2017-06-14 16:50:11 +08:00
Pan
acaa6bb269 refine sidebar css 2017-06-13 16:48:47 +08:00
Pan
7d6917a5ef Create README.md 2017-06-13 13:44:01 +08:00
Pan
dd73827112 fix avatar component bug 2017-06-13 11:04:54 +08:00
Pan
4fc649e828 refine node-sass version 2017-06-12 18:01:29 +08:00
Pan
5165ec26ae Create README.md 2017-06-12 17:50:19 +08:00
Pan
d2827bf047 add edit and create demo 2017-06-12 16:05:40 +08:00
Pan
e9d37a94d3 add markdown to html 2017-06-12 15:25:56 +08:00
Pan
9607d07cc0 Create README.md 2017-06-12 09:48:38 +08:00
Pan
ecf7558e8e refine permission example 2017-06-06 10:46:20 +08:00
Pan
703c0c5cc5 fix lint 2017-06-02 18:14:39 +08:00
Pan
46b6a6e19f add qiniu upload example 2017-06-02 18:14:19 +08:00
Pan
e8fb41d0ff update read 2017-05-31 18:28:06 +08:00
Pan
f2847862e0 replace readme gifs 2017-05-31 17:04:26 +08:00
Pan
e6bae82fe5 replace img 2017-05-31 16:49:24 +08:00
Pan
96032becf9 update version && release 2017-05-31 16:12:53 +08:00
Pan
9da96e2083 refine code 2017-05-31 16:06:41 +08:00
Pan
44166278ff update readme 2017-05-31 15:55:56 +08:00
Pan
327ed42e24 sidebar accept Nested Routes 2017-05-31 15:52:27 +08:00
Pan
677ef6dbe3 router Code Splitting use import replace require.ensure 2017-05-29 13:19:05 +08:00
125 changed files with 5990 additions and 5867 deletions

View File

@@ -1,5 +1,8 @@
{ {
"presets": ["es2015", "stage-2"], "presets": [
["env", { "modules": false }],
"stage-2"
],
"plugins": ["transform-runtime"], "plugins": ["transform-runtime"],
"comments": false "comments": false
} }

2
.gitignore vendored
View File

@@ -2,7 +2,7 @@
node_modules/ node_modules/
dist/ dist/
static/ckeditor static/ckeditor
gifs/
npm-debug.log npm-debug.log
test/unit/coverage test/unit/coverage
test/e2e/reports test/e2e/reports

8
.postcssrc.js Normal file
View File

@@ -0,0 +1,8 @@
// https://github.com/michael-ciniawsky/postcss-load-config
module.exports = {
"plugins": {
// to edit target browsers: use "browserlist" field in package.json
"autoprefixer": {}
}
}

View File

@@ -50,8 +50,12 @@ Join the group on QQ 591724180.
- Multi-environments distribution - Multi-environments distribution
- Dashboard - Dashboard
- Two-factor authentication - Two-factor authentication
- Collapsing sidebar - Collapsing sidebar (support nested routes)
- Mock data - Mock data
- cache tabs example
- screenfull
- markdown2html
- views-tab
## Development ## Development
@@ -111,6 +115,9 @@ npm run build:prod
└── package.json // package.json └── package.json // package.json
``` ```
## Changelog
Detailed changes for each release are documented in the [release notes](https://github.com/PanJiaChen/vue-element-admin/releases).
## State Management ## State Management
Only status of user and app configuration is managed by Vuex. Other data are managed by their own business pages. Only status of user and app configuration is managed by Vuex. Other data are managed by their own business pages.
@@ -125,6 +132,10 @@ Only status of user and app configuration is managed by Vuex. Other data are man
![](https://github.com/PanJiaChen/vue-element-admin/blob/master/gifs/theme.gif) ![](https://github.com/PanJiaChen/vue-element-admin/blob/master/gifs/theme.gif)
#### tabs
![tabs](https://github.com/PanJiaChen/vue-element-admin/blob/master/gifs/tabs.gif)<br />
#### Collapsing sidebar #### Collapsing sidebar
![](https://github.com/PanJiaChen/vue-element-admin/blob/master/gifs/leftmenu.gif) ![](https://github.com/PanJiaChen/vue-element-admin/blob/master/gifs/leftmenu.gif)

View File

@@ -5,22 +5,30 @@
[wiki](https://github.com/PanJiaChen/vue-element-admin/wiki) [wiki](https://github.com/PanJiaChen/vue-element-admin/wiki)
**本项目的定位是后台集成方案,不适合当基础模板来开发,模板建议使用 [vueAdmin-template](https://github.com/PanJiaChen/vueAdmin-template)**
**注意该项目目前使用element-ui@1.3.3版本,所以最低兼容 Vue 2.3.0** **注意该项目目前使用element-ui@1.3.3版本,所以最低兼容 Vue 2.3.0**
## 前言 ## 前言
> 这半年来一直在用vue写管理后台目前后台已经有七十多个页面十几种权限但维护成本依然很低所以准备开源分享一下后台开发的经验和成果。目前的技术栈主要的采用vue+element+axios.由于是个人项目所以数据请求都是用了mockjs模拟。注意在次项目基础上改造开发时请移除mock文件。 > 这半年来一直在用vue写管理后台目前后台已经有百来个个页面十几种权限但维护成本依然很低所以准备开源分享一下后台开发的经验和成果。目前的技术栈主要的采用vue+element+axios由webpack2打包.由于是个人项目所以数据请求都是用了mockjs模拟。注意在次项目基础上改造开发时请移除mock文件。
后续会出一系列的教程配套文章,如何从零构建后台项目框架,如何做完整的用户系统(如权限验证,二次登录等),如何二次开发组件(如富文本),如何整合七牛等等文章,各种后台开发经验等等。莫急~~ 写了一个系列的教程配套文章,如何从零构建后一个完整的后台项目:
相应需求开了一个qq群 591724180 方便大家交流
- [wiki](https://github.com/PanJiaChen/vue-element-admin/wiki) - [wiki](https://github.com/PanJiaChen/vue-element-admin/wiki)
- [手摸手,带你用 vue 撸后台 系列一(基础篇)](https://juejin.im/post/59097cd7a22b9d0065fb61d2) - [手摸手,带你用 vue 撸后台 系列一(基础篇)](https://juejin.im/post/59097cd7a22b9d0065fb61d2)
- [手摸手,带你用 vue 撸后台 系列二(登录权限篇)](https://juejin.im/post/591aa14f570c35006961acac) - [手摸手,带你用 vue 撸后台 系列二(登录权限篇)](https://juejin.im/post/591aa14f570c35006961acac)
- [ 手摸手,带你封装一个vue component](https://segmentfault.com/a/1190000009090836) - [手摸手,带你用 vue 撸后台 系列三 (实战篇)](https://juejin.im/post/593121aa0ce4630057f70d35)
- [手摸手带你用vue撸后台 系列四(vueAdmin 一个极简的后台基础模板)](https://juejin.im/post/595b4d776fb9a06bbe7dba56)
- [手摸手带你封装一个vue component](https://segmentfault.com/a/1190000009090836)
相应需求开了一个qq群 591724180 方便大家交流
**如有问题请先看上述文章和Wiki,若不能满足欢迎issue和pr~**
**该项目并不是一个脚手架,更倾向于是一个集成解决方案方案**
**该项目不支持低版本游览器有需求请自行添加polyfill[详情](https://github.com/PanJiaChen/vue-element-admin/wiki#babel-polyfill)**
**如有问题请先看上述问题和Wiki,不能满足欢迎issue和pr~**
## 功能 ## 功能
- 登录/注销 - 登录/注销
@@ -42,12 +50,17 @@
- table example - table example
- 动态table example - 动态table example
- 拖拽table example - 拖拽table example
- 内联编辑table example
- form example - form example
- 多环境发布 - 多环境发布
- dashboard - dashboard
- 二次登录 - 二次登录
- 动态侧边栏 - 动态侧边栏(支持多级路由)
- mock数据 - mock数据
- cache tabs example
- screenfull
- markdown2html
- views-tab
## 开发 ## 开发
@@ -104,6 +117,9 @@
``` ```
## Changelog
Detailed changes for each release are documented in the [release notes](https://github.com/PanJiaChen/vue-element-admin/releases).
## 状态管理 ## 状态管理
后台只有user和app配置相关状态使用vuex存在全局其它数据都由每个业务页面自己管理。 后台只有user和app配置相关状态使用vuex存在全局其它数据都由每个业务页面自己管理。
@@ -118,6 +134,10 @@
![真正的动态换肤](https://github.com/PanJiaChen/vue-element-admin/blob/master/gifs/theme.gif)<br /> ![真正的动态换肤](https://github.com/PanJiaChen/vue-element-admin/blob/master/gifs/theme.gif)<br />
#### tabs
![tabs](https://github.com/PanJiaChen/vue-element-admin/blob/master/gifs/tabs.gif)<br />
#### 可收起侧边栏 #### 可收起侧边栏

View File

@@ -21,7 +21,7 @@ exports.cssLoaders = function (options) {
} }
// generate loader string to be used with extract text plugin // generate loader string to be used with extract text plugin
function generateLoaders(loader, loaderOptions) { function generateLoaders (loader, loaderOptions) {
var loaders = [cssLoader] var loaders = [cssLoader]
if (loader) { if (loader) {
loaders.push({ loaders.push({
@@ -44,12 +44,12 @@ exports.cssLoaders = function (options) {
} }
} }
// http://vuejs.github.io/vue-loader/en/configurations/extract-css.html // https://vue-loader.vuejs.org/en/configurations/extract-css.html
return { return {
css: generateLoaders(), css: generateLoaders(),
postcss: generateLoaders(), postcss: generateLoaders(),
less: generateLoaders('less'), less: generateLoaders('less'),
sass: generateLoaders('sass', {indentedSyntax: true}), sass: generateLoaders('sass', { indentedSyntax: true }),
scss: generateLoaders('sass'), scss: generateLoaders('sass'),
stylus: generateLoaders('stylus'), stylus: generateLoaders('stylus'),
styl: generateLoaders('stylus') styl: generateLoaders('stylus')

View File

@@ -86,6 +86,14 @@ var webpackConfig = merge(baseWebpackConfig, {
) )
} }
}), }),
// split echarts into its own file
new webpack.optimize.CommonsChunkPlugin({
async:'echarts',
minChunks(module) {
var context = module.context;
return context && (context.indexOf('echarts') >= 0 || context.indexOf('zrender') >= 0);
}
}),
// extract webpack runtime and module manifest to its own file in order to // extract webpack runtime and module manifest to its own file in order to
// prevent vendor hash from being updated whenever app bundle is updated // prevent vendor hash from being updated whenever app bundle is updated
new webpack.optimize.CommonsChunkPlugin({ new webpack.optimize.CommonsChunkPlugin({

View File

@@ -7,9 +7,9 @@ module.exports = {
prodEnv: require('./prod.env'), prodEnv: require('./prod.env'),
index: path.resolve(__dirname, '../dist/index.html'), index: path.resolve(__dirname, '../dist/index.html'),
assetsRoot: path.resolve(__dirname, '../dist'), assetsRoot: path.resolve(__dirname, '../dist'),
assetsSubDirectory: '', assetsSubDirectory: 'static',
assetsPublicPath: './', //生产环境assetsPublicPath: '/' assetsPublicPath: './', //请根据自己路径配置更改
staticPath:'./', //生产环境 staticPath:'' staticPath:'./static/', //请根据自己路径配置更改
productionSourceMap: true, productionSourceMap: true,
// Gzip off by default as many popular static hosts such as // Gzip off by default as many popular static hosts such as
// Surge or Netlify already gzip all static assets for you. // Surge or Netlify already gzip all static assets for you.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 KiB

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 486 KiB

After

Width:  |  Height:  |  Size: 532 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 605 KiB

After

Width:  |  Height:  |  Size: 601 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 968 KiB

After

Width:  |  Height:  |  Size: 1.1 MiB

BIN
gifs/tabs.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

View File

@@ -1,6 +1,6 @@
{ {
"name": "juicy", "name": "juicy",
"version": "1.0.0", "version": "1.0.3",
"description": "A Vue.js admin", "description": "A Vue.js admin",
"author": "Pan <panfree23@gmail.com>", "author": "Pan <panfree23@gmail.com>",
"license": "MIT", "license": "MIT",
@@ -13,57 +13,59 @@
"lint": "eslint --ext .js,.vue src" "lint": "eslint --ext .js,.vue src"
}, },
"dependencies": { "dependencies": {
"axios": "0.15.3", "axios": "0.16.2",
"codemirror": "5.25.2", "codemirror": "5.26.0",
"dropzone": "4.3.0", "dropzone": "5.1.0",
"echarts": "3.4.0", "echarts": "3.6.1",
"element-ui": "1.3.3", "element-ui": "1.3.6",
"file-saver": "1.3.3", "file-saver": "1.3.3",
"jquery": "3.1.1", "jquery": "3.1.1",
"js-cookie": "2.1.3", "js-cookie": "2.1.4",
"jsonlint": "1.6.2", "jsonlint": "1.6.2",
"mockjs": "1.0.1-beta3", "mockjs": "1.0.1-beta3",
"normalize.css": "3.0.2", "normalize.css": "3.0.2",
"nprogress": "0.2.0", "nprogress": "0.2.0",
"screenfull": "3.2.2",
"showdown": "1.7.1",
"simplemde": "1.11.2", "simplemde": "1.11.2",
"sortablejs": "1.5.1", "sortablejs": "1.5.1",
"vue": "2.3.3", "vue": "2.3.3",
"vue-count-to": "1.0.5", "vue-count-to": "1.0.5",
"vue-multiselect": "2.0.0-beta.15", "vue-multiselect": "2.0.0-beta.15",
"vue-router": "2.5.3", "vue-router": "2.5.3",
"vuedraggable": "2.8.4", "vuedraggable": "2.13.1",
"vuex": "2.3.1", "vuex": "2.3.1",
"xlsx": "0.8.1" "xlsx": "0.8.1"
}, },
"devDependencies": { "devDependencies": {
"autoprefixer": "6.7.2", "autoprefixer": "7.1.1",
"babel-core": "6.22.1", "babel-core": "6.25.0",
"babel-eslint": "7.1.1", "babel-eslint": "7.2.3",
"babel-loader": "6.2.10", "babel-loader": "7.0.0",
"babel-plugin-transform-runtime": "6.22.0", "babel-plugin-transform-runtime": "6.23.0",
"babel-preset-es2015": "6.22.0", "babel-preset-env": "1.5.2",
"babel-preset-stage-2": "6.22.0", "babel-preset-stage-2": "6.24.1",
"babel-register": "6.22.0", "babel-register": "6.24.1",
"chalk": "1.1.3", "chalk": "1.1.3",
"connect-history-api-fallback": "1.3.0", "connect-history-api-fallback": "1.3.0",
"copy-webpack-plugin": "4.0.1", "copy-webpack-plugin": "4.0.1",
"cross-env": "4.0.0", "cross-env": "5.0.1",
"css-loader": "0.28.0", "css-loader": "0.28.4",
"eslint": "3.19.0", "eslint": "3.19.0",
"eslint-friendly-formatter": "2.0.7", "eslint-friendly-formatter": "3.0.0",
"eslint-import-resolver-webpack": "0.8.1", "eslint-import-resolver-webpack": "0.8.1",
"eslint-loader": "1.7.1", "eslint-loader": "1.7.1",
"eslint-plugin-html": "2.0.1", "eslint-plugin-html": "3.0.0",
"eslint-plugin-import": "2.2.0", "eslint-plugin-import": "2.3.0",
"eventsource-polyfill": "0.9.6", "eventsource-polyfill": "0.9.6",
"express": "4.14.1", "express": "4.15.3",
"extract-text-webpack-plugin": "2.0.0", "extract-text-webpack-plugin": "2.1.2",
"file-loader": "0.10.0", "file-loader": "0.11.2",
"friendly-errors-webpack-plugin": "1.1.3", "friendly-errors-webpack-plugin": "1.6.1",
"function-bind": "1.1.0", "function-bind": "1.1.0",
"html-webpack-plugin": "2.28.0", "html-webpack-plugin": "2.28.0",
"http-proxy-middleware": "0.17.3", "http-proxy-middleware": "0.17.4",
"node-sass": "4.5.2", "node-sass": "^4.5.0",
"opn": "4.0.2", "opn": "4.0.2",
"optimize-css-assets-webpack-plugin": "1.3.0", "optimize-css-assets-webpack-plugin": "1.3.0",
"ora": "1.1.0", "ora": "1.1.0",
@@ -74,13 +76,12 @@
"semver": "5.3.0", "semver": "5.3.0",
"style-loader": "0.17.0", "style-loader": "0.17.0",
"url-loader": "0.5.8", "url-loader": "0.5.8",
"vue-loader": "12.0.4", "vue-loader": "12.2.1",
"vue-style-loader": "2.0.5", "vue-style-loader": "3.0.1",
"vue-template-compiler": "2.3.3", "vue-template-compiler": "2.3.3",
"webpack": "2.5.1", "webpack": "2.6.1",
"webpack-bundle-analyzer": "2.2.1", "webpack-bundle-analyzer": "2.8.2",
"webpack-dashboard": "0.2.1", "webpack-dev-middleware": "1.10.2",
"webpack-dev-middleware": "1.10.0",
"webpack-hot-middleware": "2.18.0", "webpack-hot-middleware": "2.18.0",
"webpack-merge": "4.1.0" "webpack-merge": "4.1.0"
}, },

View File

@@ -9,3 +9,7 @@
name: 'APP' name: 'APP'
} }
</script> </script>
<style lang="scss">
@import './styles/index.scss'; // 全局自定义的css样式
</style>

View File

@@ -1,28 +1,8 @@
// import fetch, { tpFetch } from 'utils/fetch'; import fetch from 'utils/fetch';
// export function getToken() { export function getToken() {
// return fetch({ return fetch({
// url: '/qiniu/upload/token', url: '/qiniu/upload/token', // 假地址 自行替换
// method: 'get' method: 'get'
// }); });
// } }
// export function upload(data) {
// return tpFetch({
// url: 'https://upload.qbox.me',
// method: 'post',
// data
// });
// }
// /* 外部uri转七牛uri*/
// export function netUpload(token, net_url) {
// const imgData = {
// net_url
// };
// return fetch({
// url: '/qiniu/upload/net/async',
// method: 'post',
// data: imgData
// });
// }

View File

Before

Width:  |  Height:  |  Size: 160 KiB

After

Width:  |  Height:  |  Size: 160 KiB

View File

Before

Width:  |  Height:  |  Size: 96 KiB

After

Width:  |  Height:  |  Size: 96 KiB

View File

Before

Width:  |  Height:  |  Size: 4.7 KiB

After

Width:  |  Height:  |  Size: 4.7 KiB

View File

@@ -0,0 +1,199 @@
/* eslint-disable */
(function (root, factory) {
if (typeof define === 'function' && define.amd) {
// AMD. Register as an anonymous module.
define(['exports', 'echarts'], factory);
} else if (typeof exports === 'object' && typeof exports.nodeName !== 'string') {
// CommonJS
factory(exports, require('echarts'));
} else {
// Browser globals
factory({}, root.echarts);
}
}(this, function (exports, echarts) {
var log = function (msg) {
if (typeof console !== 'undefined') {
console && console.error && console.error(msg);
}
};
if (!echarts) {
log('ECharts is not Loaded');
return;
}
var colorPalette = [
'#2ec7c9','#b6a2de','#5ab1ef','#ffb980','#d87a80',
'#8d98b3','#e5cf0d','#97b552','#95706d','#dc69aa',
'#07a2a4','#9a7fd1','#588dd5','#f5994e','#c05050',
'#59678c','#c9ab00','#7eb00a','#6f5553','#c14089'
];
var theme = {
color: colorPalette,
title: {
textStyle: {
fontWeight: 'normal',
color: '#008acd'
}
},
visualMap: {
itemWidth: 15,
color: ['#5ab1ef','#e0ffff']
},
toolbox: {
iconStyle: {
normal: {
borderColor: colorPalette[0]
}
}
},
tooltip: {
backgroundColor: 'rgba(50,50,50,0.5)',
axisPointer : {
type : 'line',
lineStyle : {
color: '#008acd'
},
crossStyle: {
color: '#008acd'
},
shadowStyle : {
color: 'rgba(200,200,200,0.2)'
}
}
},
dataZoom: {
dataBackgroundColor: '#efefff',
fillerColor: 'rgba(182,162,222,0.2)',
handleColor: '#008acd'
},
grid: {
borderColor: '#eee'
},
categoryAxis: {
axisLine: {
lineStyle: {
color: '#008acd'
}
},
splitLine: {
lineStyle: {
color: ['#eee']
}
}
},
valueAxis: {
axisLine: {
lineStyle: {
color: '#008acd'
}
},
splitArea : {
show : true,
areaStyle : {
color: ['rgba(250,250,250,0.1)','rgba(200,200,200,0.1)']
}
},
splitLine: {
lineStyle: {
color: ['#eee']
}
}
},
timeline : {
lineStyle : {
color : '#008acd'
},
controlStyle : {
normal : { color : '#008acd'},
emphasis : { color : '#008acd'}
},
symbol : 'emptyCircle',
symbolSize : 3
},
line: {
smooth : true,
symbol: 'emptyCircle',
symbolSize: 3
},
candlestick: {
itemStyle: {
normal: {
color: '#d87a80',
color0: '#2ec7c9',
lineStyle: {
color: '#d87a80',
color0: '#2ec7c9'
}
}
}
},
scatter: {
symbol: 'circle',
symbolSize: 4
},
map: {
label: {
normal: {
textStyle: {
color: '#d87a80'
}
}
},
itemStyle: {
normal: {
borderColor: '#eee',
areaColor: '#ddd'
},
emphasis: {
areaColor: '#fe994e'
}
}
},
graph: {
color: colorPalette
},
gauge : {
axisLine: {
lineStyle: {
color: [[0.2, '#2ec7c9'],[0.8, '#5ab1ef'],[1, '#d87a80']],
width: 10
}
},
axisTick: {
splitNumber: 10,
length :15,
lineStyle: {
color: 'auto'
}
},
splitLine: {
length :22,
lineStyle: {
color: 'auto'
}
},
pointer : {
width : 5
}
}
};
echarts.registerTheme('macarons', theme);
}));

File diff suppressed because one or more lines are too long

View File

@@ -1,104 +0,0 @@
<template>
<div :class="className" :id="id" :style="{height:height,width:width}"></div>
</template>
<script>
// 引入 ECharts 主模块
const echarts = require('echarts/lib/echarts');
// 引入柱状图
require('echarts/lib/chart/bar');
// 引入提示框和标题组件
require('echarts/lib/component/tooltip');
export default {
name: 'barPercent',
props: {
className: {
type: String,
default: 'bar-percent-chart'
},
id: {
type: String,
default: 'bar-percent-chart'
},
width: {
type: String,
default: '100px'
},
height: {
type: String,
default: '80px'
},
dataNum: {
type: Number,
default: 0
}
},
data() {
return {
chart: null
};
},
watch: {
dataNum() {
this.setOptions()
}
},
mounted() {
this.initBar();
},
methods: {
initBar() {
this.chart = echarts.init(document.getElementById(this.id));
this.setOptions();
},
setOptions() {
this.chart.setOption({
tooltip: {
show: true,
formatter(params) {
return '已完成' + params.value + '篇<br/>目标90篇<br/>完成进度' + Math.round((params.value / 90) * 100) + '%'
}
},
grid: {
left: 0,
right: 0,
bottom: 0,
top: 0,
containLabel: false
},
xAxis: [{
type: 'category',
data: ['文章完成比例']
}],
yAxis: [{
type: 'value',
data: [],
show: false
}],
animationDelay: 1000,
series: [{
type: 'bar',
name: '初诊',
itemStyle: {
normal: {
color: '#e5e5e5'
}
},
silent: true,
barGap: '-100%', // Make series be overlap
data: [150]
}, {
type: 'bar',
name: 'app',
itemStyle: {
normal: {
color: '#30b08f'
}
},
z: 10,
data: [this.dataNum]
}]
})
}
}
}
</script>

View File

@@ -1,19 +1,11 @@
<template> <template>
<div :class="className" :id="id" :style="{height:height,width:width}"></div> <div :class="className" :id="id" :style="{height:height,width:width}"></div>
</template> </template>
<script>
// 引入 ECharts 主模块
const echarts = require('echarts/lib/echarts');
// 引入柱状图
require('echarts/lib/chart/bar');
require('echarts/lib/chart/line');
// 引入提示框和标题组件
require('echarts/lib/component/tooltip');
require('echarts/lib/component/title');
require('echarts/lib/component/visualMap'); <script>
import echarts from 'echarts';
export default { export default {
name: 'barPercent',
props: { props: {
className: { className: {
type: String, type: String,
@@ -33,13 +25,22 @@
} }
}, },
data() { data() {
return {}; return {
chart: null
};
}, },
mounted() { mounted() {
this.initBar(); this.initChart();
},
beforeDestroy() {
if (!this.chart) {
return
}
this.chart.dispose();
this.chart = null;
}, },
methods: { methods: {
initBar() { initChart() {
this.chart = echarts.init(document.getElementById(this.id)); this.chart = echarts.init(document.getElementById(this.id));
const xAxisData = []; const xAxisData = [];

View File

@@ -1,19 +1,11 @@
<template> <template>
<div :class="className" :id="id" :style="{height:height,width:width}"></div> <div :class="className" :id="id" :style="{height:height,width:width}"></div>
</template> </template>
<script>
// 引入 ECharts 主模块
const echarts = require('echarts/lib/echarts');
// 引入柱状图
require('echarts/lib/chart/bar');
require('echarts/lib/chart/line');
// 引入提示框和标题组件
require('echarts/lib/component/tooltip');
require('echarts/lib/component/title');
require('echarts/lib/component/visualMap'); <script>
import echarts from 'echarts';
export default { export default {
name: 'barPercent',
props: { props: {
className: { className: {
type: String, type: String,
@@ -33,13 +25,22 @@
} }
}, },
data() { data() {
return {}; return {
chart: null
};
}, },
mounted() { mounted() {
this.initBar(); this.initChart();
},
beforeDestroy() {
if (!this.chart) {
return
}
this.chart.dispose();
this.chart = null;
}, },
methods: { methods: {
initBar() { initChart() {
this.chart = echarts.init(document.getElementById(this.id)); this.chart = echarts.init(document.getElementById(this.id));
const xAxisData = []; const xAxisData = [];

View File

@@ -1,146 +0,0 @@
<template>
<div :class="className" :id="id" :style="{height:height,width:width}"></div>
</template>
<script>
// 引入 ECharts 主模块
const echarts = require('echarts/lib/echarts');
// 引入图
require('echarts/lib/chart/line');
// 引入提示框和标题组件
require('echarts/lib/component/markLine');
require('echarts/lib/component/markPoint');
require('echarts/lib/component/tooltip');
export default {
name: 'lineChart',
props: {
className: {
type: String,
default: 'line-chart'
},
id: {
type: String,
default: 'line-chart'
},
width: {
type: String,
default: '100%'
},
height: {
type: String,
default: '280px'
},
listData: {
type: Array,
require: true
}
},
data() {
return {
chart: null
};
},
watch: {
listData(dataList) {
this.setLine(dataList)
}
},
mounted() {
this.chart = echarts.init(document.getElementById(this.id));
this.setLine(this.listData);
},
methods: {
setLine(dataList) {
const xAxisData = [];
const data = [];
for (let i = 0; i < dataList.length; i++) {
const item = dataList[i]
xAxisData.push(item.week.substring(item.week.length - 2) + '周');
data.push(item.count)
}
const markLineData = [];
for (let i = 1; i < data.length; i++) {
markLineData.push([{
xAxis: i - 1,
yAxis: data[i - 1],
value: data[i] - data[i - 1]
}, {
xAxis: i,
yAxis: data[i]
}]);
}
this.chart.setOption({
title: {
text: 'Awesome Chart'
},
grid: {
left: 0,
right: 0,
bottom: 20,
containLabel: true
},
tooltip: {
trigger: 'axis'
},
animationDelay: 1000,
xAxis: {
data: xAxisData,
axisLine: {
show: false
},
axisTick: {
show: false
}
// axisLabel:{
// show:false
// },
},
yAxis: {
splitLine: {
show: false
},
show: false
// min: 90
},
series: [{
name: '撸文数',
type: 'line',
data,
markPoint: {
data: [
{ type: 'max', name: '最大值' },
{ type: 'min', name: '最小值' }
]
},
itemStyle: {
normal: {
color: '#30b08f'
}
},
markLine: {
silent: true,
smooth: true,
effect: {
show: true
},
animationDuration(idx) {
return idx * 100;
},
animationDelay: 1000,
animationEasing: 'quadraticInOut',
distance: 1,
label: {
normal: {
position: 'middle'
}
},
symbol: ['none', 'none'],
data: markLineData
}
}]
})
}
}
}
</script>

View File

@@ -1,17 +1,11 @@
<template> <template>
<div :class="className" :id="id" :style="{height:height,width:width}"></div> <div :class="className" :id="id" :style="{height:height,width:width}"></div>
</template> </template>
<script>
// 引入 ECharts 主模块
const echarts = require('echarts/lib/echarts');
require('echarts/lib/chart/line'); <script>
// 引入提示框和标题组件 import echarts from 'echarts';
require('echarts/lib/component/tooltip');
require('echarts/lib/component/title');
require('echarts/lib/component/legend');
export default { export default {
name: 'barPercent',
props: { props: {
className: { className: {
type: String, type: String,
@@ -31,11 +25,20 @@
} }
}, },
data() { data() {
return {}; return {
chart: null
};
}, },
mounted() { mounted() {
this.initChart(); this.initChart();
}, },
beforeDestroy() {
if (!this.chart) {
return
}
this.chart.dispose();
this.chart = null;
},
methods: { methods: {
initChart() { initChart() {
this.chart = echarts.init(document.getElementById(this.id)); this.chart = echarts.init(document.getElementById(this.id));
@@ -215,5 +218,5 @@
}) })
} }
} }
} }
</script> </script>

View File

@@ -1,18 +1,11 @@
<template> <template>
<div :class="className" :id="id" :style="{height:height,width:width}"></div> <div :class="className" :id="id" :style="{height:height,width:width}"></div>
</template> </template>
<script> <script>
// 引入 ECharts 主模块 import echarts from 'echarts';
const echarts = require('echarts/lib/echarts');
require('echarts/lib/chart/bar');
require('echarts/lib/chart/line');
// 引入提示框和标题组件
require('echarts/lib/component/tooltip');
require('echarts/lib/component/title');
require('echarts/lib/component/legend');
require('echarts/lib/component/dataZoom');
export default { export default {
name: 'barPercent',
props: { props: {
className: { className: {
type: String, type: String,
@@ -32,10 +25,20 @@
} }
}, },
data() { data() {
return {}; return {
chart: null
};
}, },
mounted() { mounted() {
this.initChart(); this.initChart();
this.chart = null;
},
beforeDestroy() {
if (!this.chart) {
return
}
this.chart.dispose();
this.chart = null;
}, },
methods: { methods: {
initChart() { initChart() {
@@ -51,7 +54,6 @@
backgroundColor: '#344b58', backgroundColor: '#344b58',
title: { title: {
text: '统计', text: '统计',
subtext: 'from http://gallery.echartsjs.com',
x: '4%', x: '4%',
textStyle: { textStyle: {
color: '#fff', color: '#fff',

View File

@@ -3,6 +3,7 @@
<input type="file" name="file"> <input type="file" name="file">
</div> </div>
</template> </template>
<script> <script>
import Dropzone from 'dropzone'; import Dropzone from 'dropzone';
import 'dropzone/dist/dropzone.css'; import 'dropzone/dist/dropzone.css';

View File

@@ -2,7 +2,11 @@
<div> <div>
<el-badge :is-dot="true" style="line-height: 30px;" @click.native="dialogTableVisible=true"> <el-badge :is-dot="true" style="line-height: 30px;" @click.native="dialogTableVisible=true">
<el-button size="small" type="primary"> <el-button size="small" type="primary">
<svg t="1492682037685" class="bug-svg" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1863" xmlns:xlink="http://www.w3.org/1999/xlink" width="64" height="64"><path d="M969.142857 548.571429q0 14.848-10.861714 25.709714t-25.709714 10.861714l-128 0q0 97.718857-38.290286 165.705143l118.857143 119.442286q10.861714 10.861714 10.861714 25.709714t-10.861714 25.709714q-10.276571 10.861714-25.709714 10.861714t-25.709714-10.861714l-113.152-112.566857q-2.852571 2.852571-8.557714 7.424t-23.990857 16.274286-37.156571 20.845714-46.848 16.566857-55.442286 7.424l0-512-73.142857 0 0 512q-29.147429 0-58.002286-7.716571t-49.700571-18.870857-37.705143-22.272-24.868571-18.578286l-8.557714-8.009143-104.557714 118.272q-11.446857 11.995429-27.428571 11.995429-13.714286 0-24.576-9.142857-10.861714-10.276571-11.702857-25.417143t8.850286-26.587429l115.419429-129.718857q-33.133714-65.133714-33.133714-156.562286l-128 0q-14.848 0-25.709714-10.861714t-10.861714-25.709714 10.861714-25.709714 25.709714-10.861714l128 0 0-168.009143-98.852571-98.852571q-10.861714-10.861714-10.861714-25.709714t10.861714-25.709714 25.709714-10.861714 25.709714 10.861714l98.852571 98.852571 482.304 0 98.852571-98.852571q10.861714-10.861714 25.709714-10.861714t25.709714 10.861714 10.861714 25.709714-10.861714 25.709714l-98.852571 98.852571 0 168.009143 128 0q14.848 0 25.709714 10.861714t10.861714 25.709714zM694.857143 219.428571l-365.714286 0q0-75.995429 53.430857-129.426286t129.426286-53.430857 129.426286 53.430857 53.430857 129.426286z" p-id="1864"></path></svg> <svg t="1492682037685" class="bug-svg" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1863"
xmlns:xlink="http://www.w3.org/1999/xlink" width="64" height="64">
<path d="M969.142857 548.571429q0 14.848-10.861714 25.709714t-25.709714 10.861714l-128 0q0 97.718857-38.290286 165.705143l118.857143 119.442286q10.861714 10.861714 10.861714 25.709714t-10.861714 25.709714q-10.276571 10.861714-25.709714 10.861714t-25.709714-10.861714l-113.152-112.566857q-2.852571 2.852571-8.557714 7.424t-23.990857 16.274286-37.156571 20.845714-46.848 16.566857-55.442286 7.424l0-512-73.142857 0 0 512q-29.147429 0-58.002286-7.716571t-49.700571-18.870857-37.705143-22.272-24.868571-18.578286l-8.557714-8.009143-104.557714 118.272q-11.446857 11.995429-27.428571 11.995429-13.714286 0-24.576-9.142857-10.861714-10.276571-11.702857-25.417143t8.850286-26.587429l115.419429-129.718857q-33.133714-65.133714-33.133714-156.562286l-128 0q-14.848 0-25.709714-10.861714t-10.861714-25.709714 10.861714-25.709714 25.709714-10.861714l128 0 0-168.009143-98.852571-98.852571q-10.861714-10.861714-10.861714-25.709714t10.861714-25.709714 25.709714-10.861714 25.709714 10.861714l98.852571 98.852571 482.304 0 98.852571-98.852571q10.861714-10.861714 25.709714-10.861714t25.709714 10.861714 10.861714 25.709714-10.861714 25.709714l-98.852571 98.852571 0 168.009143 128 0q14.848 0 25.709714 10.861714t10.861714 25.709714zM694.857143 219.428571l-365.714286 0q0-75.995429 53.430857-129.426286t129.426286-53.430857 129.426286 53.430857 53.430857 129.426286z"
p-id="1864"></path>
</svg>
</el-button> </el-button>
</el-badge> </el-badge>
<el-dialog title="bug日志" :visible.sync="dialogTableVisible"> <el-dialog title="bug日志" :visible.sync="dialogTableVisible">
@@ -40,6 +44,7 @@
} }
} }
</script> </script>
<style scoped> <style scoped>
.bug-svg { .bug-svg {
width: 1em; width: 1em;

View File

@@ -1,6 +1,14 @@
<template> <template>
<div> <div>
<svg t="1492500959545" @click="toggleClick" class="wscn-icon hamburger" :class="{'is-active':isActive}" style="" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1691" xmlns:xlink="http://www.w3.org/1999/xlink" width="64" height="64"><path d="M966.8023 568.849776 57.196677 568.849776c-31.397081 0-56.850799-25.452695-56.850799-56.850799l0 0c0-31.397081 25.452695-56.849776 56.850799-56.849776l909.605623 0c31.397081 0 56.849776 25.452695 56.849776 56.849776l0 0C1023.653099 543.397081 998.200404 568.849776 966.8023 568.849776z" p-id="1692"></path><path d="M966.8023 881.527125 57.196677 881.527125c-31.397081 0-56.850799-25.452695-56.850799-56.849776l0 0c0-31.397081 25.452695-56.849776 56.850799-56.849776l909.605623 0c31.397081 0 56.849776 25.452695 56.849776 56.849776l0 0C1023.653099 856.07443 998.200404 881.527125 966.8023 881.527125z" p-id="1693"></path><path d="M966.8023 256.17345 57.196677 256.17345c-31.397081 0-56.850799-25.452695-56.850799-56.849776l0 0c0-31.397081 25.452695-56.850799 56.850799-56.850799l909.605623 0c31.397081 0 56.849776 25.452695 56.849776 56.850799l0 0C1023.653099 230.720755 998.200404 256.17345 966.8023 256.17345z" p-id="1694"></path></svg> <svg t="1492500959545" @click="toggleClick" class="wscn-icon hamburger" :class="{'is-active':isActive}" style="" viewBox="0 0 1024 1024"
version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1691" xmlns:xlink="http://www.w3.org/1999/xlink" width="64" height="64">
<path d="M966.8023 568.849776 57.196677 568.849776c-31.397081 0-56.850799-25.452695-56.850799-56.850799l0 0c0-31.397081 25.452695-56.849776 56.850799-56.849776l909.605623 0c31.397081 0 56.849776 25.452695 56.849776 56.849776l0 0C1023.653099 543.397081 998.200404 568.849776 966.8023 568.849776z"
p-id="1692"></path>
<path d="M966.8023 881.527125 57.196677 881.527125c-31.397081 0-56.850799-25.452695-56.850799-56.849776l0 0c0-31.397081 25.452695-56.849776 56.850799-56.849776l909.605623 0c31.397081 0 56.849776 25.452695 56.849776 56.849776l0 0C1023.653099 856.07443 998.200404 881.527125 966.8023 881.527125z"
p-id="1693"></path>
<path d="M966.8023 256.17345 57.196677 256.17345c-31.397081 0-56.850799-25.452695-56.850799-56.849776l0 0c0-31.397081 25.452695-56.850799 56.850799-56.850799l909.605623 0c31.397081 0 56.849776 25.452695 56.849776 56.850799l0 0C1023.653099 230.720755 998.200404 256.17345 966.8023 256.17345z"
p-id="1694"></path>
</svg>
</div> </div>
</template> </template>
@@ -21,7 +29,7 @@
</script> </script>
<style scoped> <style scoped>
.hamburger { .hamburger {
display: inline-block; display: inline-block;
cursor: pointer; cursor: pointer;
width: 20px; width: 20px;
@@ -29,8 +37,10 @@
transform: rotate(0deg); transform: rotate(0deg);
transition: .38s; transition: .38s;
transform-origin: 50% 50%; transform-origin: 50% 50%;
} }
.hamburger.is-active {
.hamburger.is-active {
transform: rotate(90deg); transform: rotate(90deg);
} }
</style> </style>

View File

@@ -1,11 +0,0 @@
import Vue from 'vue'
function registerAllComponents(requireContext) {
return requireContext.keys().forEach(comp => {
const vueComp = requireContext(comp)
const compName = vueComp.name ? vueComp.name.toLowerCase() : /\/([\w-]+)\.vue$/.exec(comp)[1]
Vue.component(compName, vueComp)
})
}
registerAllComponents(require.context('./', false, /\.vue$/))

View File

@@ -1,12 +1,12 @@
<template> <template>
<svg class="wscn-icon" aria-hidden="true"> <svg class="svg-icon" aria-hidden="true">
<use :xlink:href="iconName"></use> <use :xlink:href="iconName"></use>
</svg> </svg>
</template> </template>
<script> <script>
export default { export default {
name: 'wscn-icon-svg', name: 'icon-svg',
props: { props: {
iconClass: { iconClass: {
type: String, type: String,
@@ -20,7 +20,3 @@
} }
} }
</script> </script>
<style lang="scss" scoped>
</style>

View File

@@ -1,52 +0,0 @@
<template>
<div class="icon-container" :style="containerStyle">
<slot class="icon"></slot>
</div>
</template>
<script>
export default {
name: 'wscn-icon-stack',
props: {
width: {
type: Number,
default: 20
},
shape: {
type: String,
default: 'circle',
validator: val => {
const validShapes = ['circle', 'square']
return validShapes.indexOf(val) > -1
}
}
},
computed: {
containerStyle() {
return {
width: `${this.width}px`,
height: `${this.width}px`,
fontSize: `${this.width * 0.6}px`,
borderRadius: `${this.shape === 'circle' && '50%'}`
}
}
}
}
</script>
<style lang="scss" scoped>
.icon-container {
display: inline-block;
position: relative;
overflow: hidden;
background: #1482F0;
.icon {
position: absolute;
color: #ffffff;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
}
</style>

View File

@@ -328,6 +328,7 @@
// 关闭控件 // 关闭控件
off() { off() {
this.show = false; this.show = false;
this.$emit('close');
}, },
// 设置步骤 // 设置步骤
setStep(step) { setStep(step) {

View File

@@ -7,17 +7,17 @@
:readonly="readonly" :disabled="disabled" :autocomplete="autocomplete" :required="required" @focus="handleFocus(true)" :readonly="readonly" :disabled="disabled" :autocomplete="autocomplete" :required="required" @focus="handleFocus(true)"
@blur="handleFocus(false)" @input="handleModelInput"> @blur="handleFocus(false)" @input="handleModelInput">
<input v-if="type === 'number'" type="number" class="material-input" :name="name" :id="id" :placeholder="placeholder" v-model="valueCopy" <input v-if="type === 'number'" type="number" class="material-input" :name="name" :id="id" :placeholder="placeholder" v-model="valueCopy"
:readonly="readonly" :disabled="disabled" :autocomplete="autocomplete" :max="max" :min="min" :minlength="minlength" :readonly="readonly" :disabled="disabled" :autocomplete="autocomplete" :max="max" :min="min" :minlength="minlength" :maxlength="maxlength"
:maxlength="maxlength" :required="required" @focus="handleFocus(true)" @blur="handleFocus(false)" @input="handleModelInput">
<input v-if="type === 'password'" type="password" class="material-input" :name="name" :id="id" :placeholder="placeholder"
v-model="valueCopy" :readonly="readonly" :disabled="disabled" :autocomplete="autocomplete" :max="max" :min="min"
:required="required" @focus="handleFocus(true)" @blur="handleFocus(false)" @input="handleModelInput"> :required="required" @focus="handleFocus(true)" @blur="handleFocus(false)" @input="handleModelInput">
<input v-if="type === 'password'" type="password" class="material-input" :name="name" :id="id" :placeholder="placeholder"
v-model="valueCopy" :readonly="readonly" :disabled="disabled" :autocomplete="autocomplete" :max="max" :min="min" :required="required"
@focus="handleFocus(true)" @blur="handleFocus(false)" @input="handleModelInput">
<input v-if="type === 'tel'" type="tel" class="material-input" :name="name" :id="id" :placeholder="placeholder" v-model="valueCopy" <input v-if="type === 'tel'" type="tel" class="material-input" :name="name" :id="id" :placeholder="placeholder" v-model="valueCopy"
:readonly="readonly" :disabled="disabled" :autocomplete="autocomplete" :required="required" @focus="handleFocus(true)" :readonly="readonly" :disabled="disabled" :autocomplete="autocomplete" :required="required" @focus="handleFocus(true)"
@blur="handleFocus(false)" @input="handleModelInput"> @blur="handleFocus(false)" @input="handleModelInput">
<input v-if="type === 'text'" type="text" class="material-input" :name="name" :id="id" :placeholder="placeholder" v-model="valueCopy" <input v-if="type === 'text'" type="text" class="material-input" :name="name" :id="id" :placeholder="placeholder" v-model="valueCopy"
:readonly="readonly" :disabled="disabled" :autocomplete="autocomplete" :minlength="minlength" :maxlength="maxlength" :readonly="readonly" :disabled="disabled" :autocomplete="autocomplete" :minlength="minlength" :maxlength="maxlength" :required="required"
:required="required" @focus="handleFocus(true)" @blur="handleFocus(false)" @input="handleModelInput"> @focus="handleFocus(true)" @blur="handleFocus(false)" @input="handleModelInput">
<span class="material-input-bar"></span> <span class="material-input-bar"></span>
@@ -25,7 +25,7 @@
<slot></slot> <slot></slot>
</label> </label>
<div v-if="errorMessages" class="material-errors"> <div v-if="errorMessages" class="material-errors">
<div v-for="error in computedErrors" class="material-error"> <div v-for="error in computedErrors" class="material-error" :key='error'>
{{ error }} {{ error }}
</div> </div>
</div> </div>
@@ -141,7 +141,7 @@
default: null default: null
} }
} }
} }
</script> </script>
<style rel="stylesheet/scss" lang="scss" scoped> <style rel="stylesheet/scss" lang="scss" scoped>

View File

@@ -6,9 +6,10 @@
</template> </template>
<script> <script>
import 'simplemde/dist/simplemde.min.css' import 'simplemde/dist/simplemde.min.css';
import SimpleMDE from 'simplemde' import SimpleMDE from 'simplemde';
export default {
export default {
name: 'Sticky', name: 'Sticky',
props: { props: {
value: String, value: String,
@@ -77,35 +78,37 @@ export default {
</script> </script>
<style> <style>
.simplemde-container .CodeMirror { .simplemde-container .CodeMirror {
/*height: 150px;*/ /*height: 150px;*/
min-height: 150px; min-height: 150px;
} }
.simplemde-container .CodeMirror-scroll{
.simplemde-container .CodeMirror-scroll {
min-height: 150px; min-height: 150px;
} }
.simplemde-container .CodeMirror-code{ .simplemde-container .CodeMirror-code {
padding-bottom: 40px; padding-bottom: 40px;
} }
.simplemde-container .editor-statusbar {
.simplemde-container .editor-statusbar {
display: none; display: none;
} }
.simplemde-container .CodeMirror .CodeMirror-code .cm-link { .simplemde-container .CodeMirror .CodeMirror-code .cm-link {
color: #1482F0; color: #1482F0;
} }
.simplemde-container .CodeMirror .CodeMirror-code .cm-string.cm-url { .simplemde-container .CodeMirror .CodeMirror-code .cm-string.cm-url {
color: #2d3b4d; color: #2d3b4d;
font-weight: bold; font-weight: bold;
} }
.simplemde-container .CodeMirror .CodeMirror-code .cm-formatting-link-string.cm-url { .simplemde-container .CodeMirror .CodeMirror-code .cm-formatting-link-string.cm-url {
padding: 0 2px; padding: 0 2px;
font-weight: bold; font-weight: bold;
color: #E61E1E; color: #E61E1E;
} }
</style> </style>

View File

@@ -8,6 +8,7 @@
<img class="pan-thumb" :src="image"> <img class="pan-thumb" :src="image">
</div> </div>
</template> </template>
<script> <script>
export default { export default {
name: 'PanThumb', name: 'PanThumb',
@@ -28,15 +29,12 @@
type: String, type: String,
default: '150px' default: '150px'
} }
},
data() {
return {};
} }
}; };
</script> </script>
<style scoped> <style scoped>
.pan-item { .pan-item {
width: 200px; width: 200px;
height: 200px; height: 200px;
border-radius: 50%; border-radius: 50%;
@@ -44,14 +42,14 @@
position: relative; position: relative;
cursor: default; cursor: default;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2); box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);
} }
.pan-info-roles-container { .pan-info-roles-container {
padding: 20px; padding: 20px;
text-align: center; text-align: center;
} }
.pan-thumb { .pan-thumb {
width: 100%; width: 100%;
height: 100%; height: 100%;
background-size: 100%; background-size: 100%;
@@ -60,9 +58,9 @@
position: absolute; position: absolute;
transform-origin: 95% 40%; transform-origin: 95% 40%;
transition: all 0.3s ease-in-out; transition: all 0.3s ease-in-out;
} }
.pan-thumb:after { .pan-thumb:after {
content: ''; content: '';
width: 8px; width: 8px;
height: 8px; height: 8px;
@@ -73,18 +71,18 @@
margin: -4px 0 0 -4px; margin: -4px 0 0 -4px;
background: radial-gradient(ellipse at center, rgba(14, 14, 14, 1) 0%, rgba(125, 126, 125, 1) 100%); background: radial-gradient(ellipse at center, rgba(14, 14, 14, 1) 0%, rgba(125, 126, 125, 1) 100%);
box-shadow: 0 0 1px rgba(255, 255, 255, 0.9); box-shadow: 0 0 1px rgba(255, 255, 255, 0.9);
} }
.pan-info { .pan-info {
position: absolute; position: absolute;
width: inherit; width: inherit;
height: inherit; height: inherit;
border-radius: 50%; border-radius: 50%;
overflow: hidden; overflow: hidden;
box-shadow: inset 0 0 0 5px rgba(0, 0, 0, 0.05); box-shadow: inset 0 0 0 5px rgba(0, 0, 0, 0.05);
} }
.pan-info h3 { .pan-info h3 {
color: #fff; color: #fff;
text-transform: uppercase; text-transform: uppercase;
position: relative; position: relative;
@@ -94,20 +92,19 @@
padding: 22px 0 0 0; padding: 22px 0 0 0;
height: 85px; height: 85px;
font-family: 'Open Sans', Arial, sans-serif; font-family: 'Open Sans', Arial, sans-serif;
text-shadow: 0 0 1px #fff, text-shadow: 0 0 1px #fff, 0 1px 2px rgba(0, 0, 0, 0.3);
0 1px 2px rgba(0, 0, 0, 0.3); }
}
.pan-info p { .pan-info p {
color: #fff; color: #fff;
padding: 10px 5px; padding: 10px 5px;
font-style: italic; font-style: italic;
margin: 0 30px; margin: 0 30px;
font-size: 12px; font-size: 12px;
border-top: 1px solid rgba(255, 255, 255, 0.5); border-top: 1px solid rgba(255, 255, 255, 0.5);
} }
.pan-info p a { .pan-info p a {
display: block; display: block;
color: #333; color: #333;
width: 80px; width: 80px;
@@ -124,22 +121,20 @@
margin: 7px auto 0; margin: 7px auto 0;
font-family: 'Open Sans', Arial, sans-serif; font-family: 'Open Sans', Arial, sans-serif;
opacity: 0; opacity: 0;
transition: transform 0.3s ease-in-out 0.2s, transition: transform 0.3s ease-in-out 0.2s, opacity 0.3s ease-in-out 0.2s, background 0.2s linear 0s;
opacity 0.3s ease-in-out 0.2s,
background 0.2s linear 0s;
transform: translateX(60px) rotate(90deg); transform: translateX(60px) rotate(90deg);
} }
.pan-info p a:hover { .pan-info p a:hover {
background: rgba(255, 255, 255, 0.5); background: rgba(255, 255, 255, 0.5);
} }
.pan-item:hover .pan-thumb { .pan-item:hover .pan-thumb {
transform: rotate(-110deg); transform: rotate(-110deg);
} }
.pan-item:hover .pan-info p a { .pan-item:hover .pan-info p a {
opacity: 1; opacity: 1;
transform: translateX(0px) rotate(0deg); transform: translateX(0px) rotate(0deg);
} }
</style> </style>

View File

@@ -0,0 +1,53 @@
<template>
<svg @click='click' class="icon screenfull" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
t="1497503607356" viewBox="0 0 1024 1024" version="1.1" p-id="4109" :fill='fill' :width="width" :height="height">
<path d="M604.157933 512l204.484208 204.484208 82.942037-82.942037c10.364045-10.952446 26.498514-13.83817 40.309054-8.067746 13.249769 5.742794 22.465664 18.99154 22.465664 33.977859l0 258.042008c0 20.168342-16.695241 36.863582-36.863582 36.863582L659.452283 954.357873c-14.986319 0-28.236088-9.215896-33.977859-23.025413-5.770424-13.249769-2.885723-29.384237 8.067746-39.748283l82.942037-82.942037L512 604.157933 307.515792 808.642141l82.942037 82.942037c10.952446 10.364045 13.83817 26.498514 8.067746 39.748283-5.742794 13.809517-18.99154 23.025413-33.977859 23.025413L106.504686 954.357873c-20.168342 0-36.863582-16.695241-36.863582-36.863582L69.641103 659.452283c0-14.986319 9.215896-28.236088 23.025413-33.977859 13.249769-5.770424 29.384237-2.8847 39.748283 8.067746l82.942037 82.942037 204.484208-204.484208L215.357859 307.515792l-82.942037 82.942037c-6.890944 6.918573-16.10684 10.952446-25.911136 10.952446-4.593622 0-9.804297-1.14815-13.83817-2.8847-13.809517-5.742794-23.025413-18.99154-23.025413-33.977859L69.641103 106.504686c0-20.168342 16.695241-36.863582 36.863582-36.863582L364.546693 69.641103c14.986319 0 28.236088 9.215896 33.977859 23.025413 5.770424 13.249769 2.8847 29.384237-8.067746 39.748283l-82.942037 82.942037 204.484208 204.484208L716.484208 215.357859l-82.942037-82.942037c-10.952446-10.364045-13.83817-26.498514-8.067746-39.748283 5.742794-13.809517 18.99154-23.025413 33.977859-23.025413l258.042008 0c20.168342 0 36.863582 16.695241 36.863582 36.863582l0 258.042008c0 14.986319-9.215896 28.236088-22.465664 33.977859-4.593622 1.736551-9.804297 2.8847-14.397918 2.8847-9.804297 0-19.020192-4.033873-25.911136-10.952446l-82.942037-82.942037L604.157933 512z"
p-id="4110" />
</svg>
</template>
<script>
import screenfull from 'screenfull';
export default {
name: 'hamburger',
props: {
width: {
type: Number,
default: 22
},
height: {
type: Number,
default: 22
},
fill: {
type: String,
default: '#48576a'
}
},
data() {
return {
isFullscreen: false
}
},
methods: {
click() {
if (!screenfull.enabled) {
this.$message({
message: 'you browser can not work',
type: 'warning'
});
return false;
}
screenfull.toggle();
}
}
}
</script>
<style scoped>
.screenfull {
display: inline-block;
cursor: pointer;
vertical-align: -0.15em;
}
</style>

View File

@@ -17,25 +17,28 @@
} }
</script> </script>
<style> <style scoped>
.splitter-pane.vertical.splitter-paneL{ .splitter-pane.vertical.splitter-paneL {
position: absolute; position: absolute;
left: 0px; left: 0px;
height: 100%; height: 100%;
} }
.splitter-pane.vertical.splitter-paneR{
.splitter-pane.vertical.splitter-paneR {
position: absolute; position: absolute;
right: 0px; right: 0px;
height: 100%; height: 100%;
} }
.splitter-pane.horizontal.splitter-paneL{
.splitter-pane.horizontal.splitter-paneL {
position: absolute; position: absolute;
top: 0px; top: 0px;
width: 100%; width: 100%;
} }
.splitter-pane.horizontal.splitter-paneR{
.splitter-pane.horizontal.splitter-paneR {
position: absolute; position: absolute;
bottom: 0px; bottom: 0px;
width: 100%; width: 100%;
} }
</style> </style>

View File

@@ -1,6 +1,7 @@
<template> <template>
<div :class="classes" @mousedown="onMouseDown"></div> <div :class="classes" @mousedown="onMouseDown"></div>
</template> </template>
<script> <script>
export default { export default {
props: { props: {
@@ -23,8 +24,9 @@
} }
} }
</script> </script>
<style scoped> <style scoped>
.Resizer { .Resizer {
-moz-box-sizing: border-box; -moz-box-sizing: border-box;
-webkit-box-sizing: border-box; -webkit-box-sizing: border-box;
box-sizing: border-box; box-sizing: border-box;
@@ -35,37 +37,36 @@
/*-moz-background-clip: padding;*/ /*-moz-background-clip: padding;*/
/*-webkit-background-clip: padding;*/ /*-webkit-background-clip: padding;*/
/*background-clip: padding-box;*/ /*background-clip: padding-box;*/
} }
/*.Resizer:hover {*/
/*-webkit-transition: all 2s ease;*/
/*transition: all 2s ease;*/
/*}*/
/*.Resizer:hover {*/ .Resizer.horizontal {
/*-webkit-transition: all 2s ease;*/
/*transition: all 2s ease;*/
/*}*/
.Resizer.horizontal {
height: 11px; height: 11px;
margin: -5px 0; margin: -5px 0;
border-top: 5px solid rgba(255, 255, 255, 0); border-top: 5px solid rgba(255, 255, 255, 0);
border-bottom: 5px solid rgba(255, 255, 255, 0); border-bottom: 5px solid rgba(255, 255, 255, 0);
cursor: row-resize; cursor: row-resize;
width: 100%; width: 100%;
} }
.Resizer.horizontal:hover { .Resizer.horizontal:hover {
border-top: 5px solid rgba(0, 0, 0, 0.5); border-top: 5px solid rgba(0, 0, 0, 0.5);
border-bottom: 5px solid rgba(0, 0, 0, 0.5); border-bottom: 5px solid rgba(0, 0, 0, 0.5);
} }
.Resizer.vertical { .Resizer.vertical {
width: 11px; width: 11px;
height: 100%; height: 100%;
border-left: 5px solid rgba(255, 255, 255, 0); border-left: 5px solid rgba(255, 255, 255, 0);
border-right: 5px solid rgba(255, 255, 255, 0); border-right: 5px solid rgba(255, 255, 255, 0);
cursor: col-resize; cursor: col-resize;
} }
.Resizer.vertical:hover { .Resizer.vertical:hover {
border-left: 5px solid rgba(0, 0, 0, 0.5); border-left: 5px solid rgba(0, 0, 0, 0.5);
border-right: 5px solid rgba(0, 0, 0, 0.5); border-right: 5px solid rgba(0, 0, 0, 0.5);
} }
</style> </style>

View File

@@ -1,31 +1,14 @@
<template> <template>
<div ref :style="{ cursor, userSelect}" class="vue-splitter-container clearfix" @mouseup="onMouseUp" <div ref :style="{ cursor, userSelect}" class="vue-splitter-container clearfix" @mouseup="onMouseUp" @mousemove="onMouseMove">
@mousemove="onMouseMove"> <pane class="splitter-pane splitter-paneL" :split="split" :style="{ [type]: percent+'%'}">
<Pane class="splitter-pane splitter-paneL" :split="split" :style="{ [type]: percent+'%'}">
<slot name="paneL"></slot> <slot name="paneL"></slot>
</Pane> </pane>
<Resizer :style="{ [resizeType]: percent+'%'}" :split="split" :onMouseDown="onMouseDown" <resizer :style="{ [resizeType]: percent+'%'}" :split="split" :onMouseDown="onMouseDown" @click="onClick"></resizer>
@click="onClick"></Resizer> <pane class="splitter-pane splitter-paneR" :split="split" :style="{ [type]: 100-percent+'%'}">
<Pane class="splitter-pane splitter-paneR" :split="split" :style="{ [type]: 100-percent+'%'}">
<slot name="paneR"></slot> <slot name="paneR"></slot>
</Pane> </pane>
</div> </div>
</template> </template>
<style scoped>
.clearfix:after {
visibility: hidden;
display: block;
font-size: 0;
content: " ";
clear: both;
height: 0;
}
.vue-splitter-container {
height: 100%;
/*display: flex;*/
position: relative;
}
</style>
<script> <script>
import Resizer from './Resizer'; import Resizer from './Resizer';
@@ -109,3 +92,20 @@
} }
} }
</script> </script>
<style scoped>
.clearfix:after {
visibility: hidden;
display: block;
font-size: 0;
content: " ";
clear: both;
height: 0;
}
.vue-splitter-container {
height: 100%;
/*display: flex;*/
position: relative;
}
</style>

View File

@@ -7,6 +7,7 @@
</div> </div>
</div> </div>
</template> </template>
<script> <script>
export default { export default {
name: 'Sticky', name: 'Sticky',

View File

@@ -1,119 +0,0 @@
<template>
<div class="upload-container">
<el-button :style="{background:color,borderColor:color}" @click=" dialogVisible=true" type="primary">上传音频
</el-button>
<el-dialog v-model="dialogVisible">
<el-form ref="form" :model="form" :rules="rules" label-width="100px" label-position="right">
<el-upload
class="editor-audio-upload"
action="https://upload.qbox.me"
:data="dataObj"
:show-file-list="true"
:file-list="audioList"
:on-success="handleAudioScucess"
:on-change="handleAudioChange"
:before-upload="audioBeforeUpload">
<el-button size="small" type="primary">上传音频</el-button>
</el-upload>
<el-form-item prop="url" label="音频URL">
<el-input v-model="form.url"></el-input>
</el-form-item>
<el-form-item prop="title" label="音频标题">
<el-input v-model="form.title"></el-input>
</el-form-item>
<el-form-item label="音频文本">
<el-input type="textarea" :autosize="{ minRows: 2}" v-model="form.text"></el-input>
</el-form-item>
</el-form>
<el-button @click="dialogVisible = false"> </el-button>
<el-button type="primary" @click="handleSubmit"> </el-button>
</el-dialog>
</div>
</template>
<script>
import { getToken } from 'api/qiniu';
export default {
name: 'editorAudioUpload',
props: {
color: {
type: String,
default: '#20a0ff'
}
},
data() {
return {
dialogVisible: false,
dataObj: { token: '', key: '' },
audioList: [],
tempAudioUrl: '',
form: {
title: '',
url: '',
text: ''
},
rules: {
title: [
{ required: true, trigger: 'blur' }
],
url: [
{ required: true, trigger: 'blur' }
]
}
};
},
methods: {
handleSubmit() {
this.$refs.form.validate(valid => {
if (valid) {
this.$emit('successCBK', this.form);
this.dialogVisible = false;
this.form = {
title: '',
url: '',
text: ''
}
} else {
this.$message('填写有误');
return false;
}
});
},
handleAudioChange(file, fileList) {
this.audioList = fileList.slice(-1);
},
handleAudioScucess() {
this.form.url = this.tempAudioUrl
},
audioBeforeUpload() {
const _self = this;
return new Promise((resolve, reject) => {
getToken().then(response => {
const key = response.data.qiniu_key;
const token = response.data.qiniu_token;
_self._data.dataObj.token = token;
_self._data.dataObj.key = key;
this.tempAudioUrl = response.data.qiniu_url;
resolve(true);
}).catch(err => {
console.log(err);
reject(false)
});
});
}
}
};
</script>
<style rel="stylesheet/scss" lang="scss" scoped>
.upload-container {
.editor-audio-upload {
button {
float: left;
margin-left: 30px;
margin-bottom: 20px;
}
}
}
</style>

View File

@@ -1,88 +0,0 @@
<template>
<div class="upload-container">
<el-button icon='upload' :style="{background:color,borderColor:color}" @click=" dialogVisible=true" type="primary">上传图片
</el-button>
<el-dialog v-model="dialogVisible">
<el-upload
class="editor-slide-upload"
action="https://httpbin.org/post"
:data="dataObj"
:multiple="true"
:file-list="fileList"
:show-file-list="true"
list-type="picture-card"
:on-remove="handleRemove"
:on-success="handleImageScucess">
<el-button size="small" type="primary">点击上传</el-button>
</el-upload>
<el-button @click="dialogVisible = false"> </el-button>
<el-button type="primary" @click="handleSubmit"> </el-button>
</el-dialog>
</div>
</template>
<script>
import { getToken } from 'api/qiniu';
export default {
name: 'editorSlideUpload',
props: {
color: {
type: String,
default: '#20a0ff'
}
},
data() {
return {
dialogVisible: false,
dataObj: { token: '', key: '' },
list: [],
fileList: []
};
},
methods: {
handleSubmit() {
const arr = this.list.map(v => v.url);
this.$emit('successCBK', arr);
this.list = [];
this.fileList = [];
this.dialogVisible = false;
},
handleRemove(file) {
const key = file.response.key;
for (let i = 0, len = this.list.length; i < len; i++) {
if (this.list[i].key === key) {
this.list.splice(i, 1);
return
}
}
},
handleImageScucess(file) {
this.list.push({ url: file.files.file });
},
beforeUpload() {
const _self = this;
return new Promise((resolve, reject) => {
getToken().then(response => {
const key = response.data.qiniu_key;
const token = response.data.qiniu_token;
_self._data.dataObj.token = token;
_self._data.dataObj.key = key;
this.list.push({ key, url: response.data.qiniu_url });
resolve(true);
}).catch(err => {
console.log(err);
reject(false)
});
});
}
}
};
</script>
<style rel="stylesheet/scss" lang="scss" scoped>
.upload-container {
.editor-slide-upload {
margin-bottom: 20px;
}
}
</style>

View File

@@ -1,82 +0,0 @@
<template>
<div class="upload-container">
<el-button :style="{background:color,borderColor:color}" @click=" dialogVisible=true" type="primary">上传轮播图
</el-button>
<el-dialog v-model="dialogVisible">
<el-upload
class="editor-slide-upload"
action="https://upload.qbox.me"
:data="dataObj"
:multiple="true"
:show-file-list="true"
list-type="picture-card"
:on-remove="handleRemove"
:before-upload="beforeUpload">
<el-button size="small" type="primary">点击上传</el-button>
</el-upload>
<el-button @click="dialogVisible = false"> </el-button>
<el-button type="primary" @click="handleSubmit"> </el-button>
</el-dialog>
</div>
</template>
<script>
import { getToken } from 'api/qiniu';
export default {
name: 'editorSlideUpload',
props: {
color: {
type: String,
default: '#20a0ff'
}
},
data() {
return {
dialogVisible: false,
dataObj: { token: '', key: '' },
list: []
};
},
methods: {
handleSubmit() {
const arr = this.list.map(v => v.url);
this.$emit('successCBK', arr);
this.list = [];
this.dialogVisible = false;
},
handleRemove(file) {
const key = file.response.key;
for (let i = 0, len = this.list.length; i < len; i++) {
if (this.list[i].key === key) {
this.list.splice(i, 1);
return
}
}
},
beforeUpload() {
const _self = this;
return new Promise((resolve, reject) => {
getToken().then(response => {
const key = response.data.qiniu_key;
const token = response.data.qiniu_token;
_self._data.dataObj.token = token;
_self._data.dataObj.key = key;
this.list.push({ key, url: response.data.qiniu_url });
resolve(true);
}).catch(err => {
console.log(err);
reject(false)
});
});
}
}
};
</script>
<style rel="stylesheet/scss" lang="scss" scoped>
.upload-container {
.editor-slide-upload {
margin-bottom: 20px;
}
}
</style>

View File

@@ -1,167 +0,0 @@
<template>
<div class="upload-container">
<el-button :style="{background:color,borderColor:color}" @click=" dialogVisible=true" type="primary">上传视频</el-button>
<el-dialog v-model="dialogVisible">
<el-form ref="form" :model="form" :rules="rules" label-width="140px" label-position="left">
<el-upload
class="editor-video-upload"
action="https://upload.qbox.me"
:data="dataObj"
:show-file-list="true"
:file-list="videoList"
:on-success="handleVideoScucess"
:on-change="handleVideoChange"
:before-upload="videoBeforeUpload">
<el-button size="small" type="primary">上传视频</el-button>
</el-upload>
<el-form-item prop="url" label="视频URL">
<el-input v-model="form.url"></el-input>
</el-form-item>
<el-form-item prop="title" label="视频标题">
<el-input v-model="form.title"></el-input>
</el-form-item>
<el-form-item label="上传视频封面图">
</el-form-item>
<el-upload
class="image-uploader"
action="https://upload.qbox.me"
:show-file-list="false"
:data="dataObj"
:on-success="handleImageScucess"
:before-upload="beforeImageUpload">
<img v-if="form.image" :src="form.image" class="image-uploader-image">
<i v-else class="el-icon-plus avatar-uploader-icon"></i>
</el-upload>
</el-form>
<el-button @click="dialogVisible = false"> </el-button>
<el-button type="primary" @click="handleSubmit"> </el-button>
</el-dialog>
</div>
</template>
<script>
import { getToken } from 'api/qiniu';
export default {
name: 'editorVideoUpload',
props: {
color: {
type: String,
default: '#20a0ff'
}
},
data() {
return {
dialogVisible: false,
dataObj: { token: '', key: '' },
videoList: [],
tempVideoUrl: '',
tempImageUrl: '',
form: {
title: '',
url: '',
image: ''
},
rules: {
url: [
{ required: true, trigger: 'blur' }
],
title: [
{ required: true, trigger: 'blur' }
]
}
};
},
methods: {
handleSubmit() {
this.$refs.form.validate(valid => {
if (valid) {
if (this.form.image.length > 0) {
this.$emit('successCBK', this.form);
this.dialogVisible = false;
this.form = {
title: '',
url: '',
image: ''
}
} else {
this.$message('请上传图片');
}
} else {
this.$message('填写有误');
return false;
}
});
},
handleVideoChange(file, fileList) {
this.videoList = fileList.slice(-1);
},
handleVideoScucess() {
this.form.url = this.tempVideoUrl
},
videoBeforeUpload() {
const _self = this;
return new Promise((resolve, reject) => {
getToken().then(response => {
const key = response.data.qiniu_key;
const token = response.data.qiniu_token;
_self._data.dataObj.token = token;
_self._data.dataObj.key = key;
this.tempVideoUrl = response.data.qiniu_url;
resolve(true);
}).catch(err => {
console.log(err);
reject(false)
});
});
},
handleImageScucess() {
this.form.image = this.tempImageUrl
},
beforeImageUpload() {
const _self = this;
return new Promise((resolve, reject) => {
getToken().then(response => {
const key = response.data.qiniu_key;
const token = response.data.qiniu_token;
_self._data.dataObj.token = token;
_self._data.dataObj.key = key;
this.tempImageUrl = response.data.qiniu_url;
resolve(true);
}).catch(err => {
console.log(err);
reject(false)
});
});
}
}
};
</script>
<style rel="stylesheet/scss" lang="scss" scoped>
.upload-container {
.editor-video-upload {
button {
float: left;
}
}
.image-uploader {
margin: 5px auto;
width: 400px;
height: 200px;
border: 1px dashed #d9d9d9;
border-radius: 6px;
cursor: pointer;
position: relative;
overflow: hidden;
line-height: 200px;
i {
font-size: 28px;
color: #8c939d;
}
.image-uploader-image {
height: 200px;
}
}
}
</style>

View File

@@ -1,29 +1,13 @@
<template> <template>
<div class='tinymce-container editor-container'> <div class='tinymce-container editor-container'>
<textarea class='tinymce-textarea' :id="id"></textarea> <textarea class='tinymce-textarea' :id="id"></textarea>
<!--业务需求可删除-->
<div class="editor-custom-btn-container">
<editorSlide v-if="customButton.indexOf('editorSlide')>=0" color="#3A71A8" class="editor-upload-btn" @successCBK="slideSuccessCBK"></editorSlide>
<editorAudio v-if="customButton.indexOf('editorAudio')>=0" color="#30B08F" class="editor-upload-btn" @successCBK="aduioSuccessCBK"></editorAudio>
<editorVideo v-if="customButton.indexOf('editorVideo')>=0" color="#E65D6E" class="editor-upload-btn" @successCBK="videoSuccessCBK"></editorVideo>
<editorImage v-if="customButton.indexOf('editorImage')>=0" color="#20a0ff" class="editor-upload-btn" @successCBK="imageSuccessCBK"></editorImage>
<!--业务需求可删除-->
</div>
</div> </div>
</template> </template>
<script> <script>
// tinymce 在最外层目录static下 由index.html直接引入挂载在window下。不通过impot不打包
// 业务需求可删除
import editorAudio from './components/editorAudio';
import editorVideo from './components/editorVideo';
import editorSlide from './components/editorSlide';
import editorImage from './components/editorImage';
// import { getToken, upload } from 'api/qiniu'; // 七牛 // import { getToken, upload } from 'api/qiniu'; // 七牛
// 业务需求可删除
export default { export default {
name: 'tinymce', name: 'tinymce',
components: { editorImage, editorAudio, editorSlide, editorVideo }, // 业务需求可删除
props: { props: {
id: { id: {
type: String, type: String,
@@ -33,13 +17,6 @@
type: String, type: String,
default: '' default: ''
}, },
customButton: {
type: Array,
required: false,
default() {
return ['editorAudio', 'editorImage']
}
},
toolbar: { toolbar: {
type: Array, type: Array,
required: false, required: false,
@@ -92,15 +69,12 @@
imagetools_toolbar: 'watermark', imagetools_toolbar: 'watermark',
default_link_target: '_blank', default_link_target: '_blank',
link_title: false, link_title: false,
textcolor_map: [
'1482f0', '1482f0',
'4595e6', '4595e6'],
init_instance_callback: editor => { init_instance_callback: editor => {
if (_this.value) { if (_this.value) {
editor.setContent(_this.value) editor.setContent(_this.value)
} }
_this.hasInit = true; _this.hasInit = true;
editor.on('Change', () => { editor.on('NodeChange Change KeyUp', () => {
this.hasChange = true; this.hasChange = true;
this.$emit('input', editor.getContent({ format: 'raw' })); this.$emit('input', editor.getContent({ format: 'raw' }));
}); });
@@ -172,59 +146,10 @@
} }
}); });
}, },
methods: {
/* 业务代码可删除 start*/
imageSuccessCBK(arr) {
console.log(arr)
const _this = this;
arr.forEach(v => {
const node = document.createElement('img');
node.setAttribute('src', v);
node.onload = function() {
$(this).addClass('wscnph');
$(this).attr('data-wscntype', 'image');
$(this).attr('data-wscnh', this.height);
$(this).attr('data-wscnw', this.width);
tinymce.get(_this.id).insertContent(node.outerHTML)
}
})
},
slideSuccessCBK(arr) {
const node = document.createElement('img');
node.setAttribute('data-wscntype', 'slide');
node.setAttribute('data-uri', arr.toString());
node.setAttribute('data-wscnh', '190');
node.setAttribute('data-wscnw', '200');
node.setAttribute('src', ' https://wdl.wallstreetcn.com/6410b47d-a54c-4826-9bc1-c3e5df31280c');
node.className = 'wscnph editor-placeholder';
tinymce.get(this.id).insertContent(node.outerHTML)
},
videoSuccessCBK(form) {
const node = document.createElement('img');
node.setAttribute('data-wscntype', 'video');
node.setAttribute('data-uri', form.url);
node.setAttribute('data-cover-img-uri', form.image);
node.setAttribute('data-title', form.title);
node.setAttribute('src', 'https://wdl.wallstreetcn.com/07aeb3e7-f4ca-4207-befb-c987b3dc7011');
node.className = 'wscnph editor-placeholder';
tinymce.get(this.id).insertContent(node.outerHTML)
},
aduioSuccessCBK(form) {
const node = document.createElement('img');
node.setAttribute('data-wscntype', 'audio');
node.setAttribute('data-uri', form.url);
node.setAttribute('data-title', form.title);
node.setAttribute('data-text', form.text);
node.setAttribute('src', 'https://wdl.wallstreetcn.com/2ed0c8c8-fb82-499d-b81c-3fd1de114eae');
node.className = 'wscnph editor-placeholder';
tinymce.get(this.id).insertContent(node.outerHTML)
}
/* 业务代码可删除 end*/
},
destroyed() { destroyed() {
tinymce.get(this.id).destroy(); tinymce.get(this.id).destroy();
} }
} }
</script> </script>
<style scoped> <style scoped>
@@ -240,7 +165,6 @@
.editor-custom-btn-container { .editor-custom-btn-container {
position: absolute; position: absolute;
right: 15px; right: 15px;
/*z-index: 2005;*/
top: 18px; top: 18px;
} }

View File

@@ -0,0 +1,70 @@
<template>
<li class="todo" :class="{ completed: todo.done, editing: editing }">
<div class="view">
<input class="toggle"
type="checkbox"
:checked="todo.done"
@change="toggleTodo( todo)">
<label v-text="todo.text" @dblclick="editing = true"></label>
<button class="destroy" @click="deleteTodo( todo )"></button>
</div>
<input class="edit"
v-show="editing"
v-focus="editing"
:value="todo.text"
@keyup.enter="doneEdit"
@keyup.esc="cancelEdit"
@blur="doneEdit">
</li>
</template>
<script>
export default {
name: 'Todo',
props: ['todo'],
data() {
return {
editing: false
}
},
directives: {
focus(el, { value }, { context }) {
if (value) {
context.$nextTick(() => {
el.focus()
})
}
}
},
methods: {
deleteTodo(todo) {
this.$emit('deleteTodo', todo)
},
editTodo({ todo, value }) {
this.$emit('editTodo', { todo, value })
},
toggleTodo(todo) {
this.$emit('toggleTodo', todo)
},
doneEdit(e) {
const value = e.target.value.trim()
const { todo } = this
if (!value) {
this.deleteTodo({
todo
})
} else if (this.editing) {
this.editTodo({
todo,
value
})
this.editing = false
}
},
cancelEdit(e) {
e.target.value = this.todo.text
this.editing = false
}
}
}
</script>

View File

@@ -0,0 +1,318 @@
.todoapp {
font: 14px 'Helvetica Neue', Helvetica, Arial, sans-serif;
line-height: 1.4em;
color: #4d4d4d;
min-width: 230px;
max-width: 550px;
margin: 40PX auto 0;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
font-weight: 300;
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: 16px 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;
}
}
}

View File

@@ -0,0 +1,116 @@
<template>
<section class="todoapp">
<!-- header -->
<header class="header">
<input class="new-todo" autofocus autocomplete="off" placeholder="TODO LIST?" @keyup.enter="addTodo">
</header>
<!-- main section -->
<section class="main" v-show="todos.length">
<input class="toggle-all" id="toggle-all" type="checkbox" :checked="allChecked" @change="toggleAll({ done: !allChecked })">
<label for="toggle-all"></label>
<ul class="todo-list">
<todo @toggleTodo='toggleTodo' @editTodo='editTodo' @deleteTodo='deleteTodo' v-for="(todo, index) in filteredTodos" :key="index"
:todo="todo"></todo>
</ul>
</section>
<!-- footer -->
<footer class="footer" v-show="todos.length">
<span class="todo-count">
<strong>{{ remaining }}</strong>
{{ remaining | pluralize('item') }} left
</span>
<ul class="filters">
<li v-for="(val, key) in filters" :key="key">
<a :class="{ selected: visibility === key }" @click.prevent="visibility = key">{{ key | capitalize }}</a>
</li>
</ul>
<button class="clear-completed" v-show="todos.length > remaining" @click="clearCompleted">
Clear completed
</button>
</footer>
</section>
</template>
<script>
import Todo from './Todo.vue'
const STORAGE_KEY = 'todos'
const filters = {
all: todos => todos,
active: todos => todos.filter(todo => !todo.done),
completed: todos => todos.filter(todo => todo.done)
}
const defalutList = [
{ text: 'star this repository', done: false },
{ text: 'fork this repository', done: false },
{ text: 'follow author', done: false }
]
export default {
components: { Todo },
data() {
return {
visibility: 'all',
filters,
todos: JSON.parse(window.localStorage.getItem(STORAGE_KEY)) || defalutList
}
},
computed: {
allChecked() {
return this.todos.every(todo => todo.done)
},
filteredTodos() {
return filters[this.visibility](this.todos)
},
remaining() {
return this.todos.filter(todo => !todo.done).length
}
},
methods: {
setLocalStorgae() {
window.localStorage.setItem(STORAGE_KEY, JSON.stringify(this.todos))
},
addTodo(e) {
const text = e.target.value
if (text.trim()) {
this.todos.push({
text,
done: false
})
this.setLocalStorgae()
}
e.target.value = ''
},
toggleTodo(val) {
val.done = !val.done
this.setLocalStorgae()
},
deleteTodo(todo) {
console.log(todo)
this.todos.splice(this.todos.indexOf(todo), 1)
this.setLocalStorgae()
},
editTodo({ todo, value }) {
console.log(todo, value)
todo.text = value
this.setLocalStorgae()
},
clearCompleted() {
this.todos = this.todos.filter(todo => !todo.done)
this.setLocalStorgae()
},
toggleAll({ done }) {
this.todos.forEach(todo => {
todo.done = done
this.setLocalStorgae()
})
}
},
filters: {
pluralize: (n, w) => n === 1 ? w : w + 's',
capitalize: s => s.charAt(0).toUpperCase() + s.slice(1)
}
}
</script>
<style lang="scss">
@import './index.scss';
</style>

View File

@@ -1,13 +1,6 @@
<template> <template>
<div class="upload-container"> <div class="upload-container">
<el-upload <el-upload class="image-uploader" :data="dataObj" drag :multiple="false" :show-file-list="false" action="https://httpbin.org/post"
class="image-uploader"
:data="dataObj"
drag
:multiple="false"
:show-file-list="false"
action="https://httpbin.org/post"
:on-success="handleImageScucess"> :on-success="handleImageScucess">
<i class="el-icon-upload"></i> <i class="el-icon-upload"></i>
<div class="el-upload__text">将文件拖到此处<em>点击上传</em></div> <div class="el-upload__text">将文件拖到此处<em>点击上传</em></div>
@@ -22,6 +15,7 @@
</div> </div>
</div> </div>
</template> </template>
<script> <script>
// 预览效果见付费文章 // 预览效果见付费文章
import { getToken } from 'api/qiniu'; import { getToken } from 'api/qiniu';

View File

@@ -1,13 +1,6 @@
<template> <template>
<div class="singleImageUpload2 upload-container"> <div class="singleImageUpload2 upload-container">
<el-upload <el-upload class="image-uploader" :data="dataObj" drag :multiple="false" :show-file-list="false" action="https://httpbin.org/post"
class="image-uploader"
:data="dataObj"
drag
:multiple="false"
:show-file-list="false"
action="https://httpbin.org/post"
:on-success="handleImageScucess"> :on-success="handleImageScucess">
<i class="el-icon-upload"></i> <i class="el-icon-upload"></i>
<div class="el-upload__text">Drag或<em>点击上传</em></div> <div class="el-upload__text">Drag或<em>点击上传</em></div>
@@ -22,6 +15,7 @@
</div> </div>
</div> </div>
</template> </template>
<script> <script>
// 预览效果见专题 // 预览效果见专题
import { getToken } from 'api/qiniu'; import { getToken } from 'api/qiniu';
@@ -72,11 +66,11 @@
</script> </script>
<style rel="stylesheet/scss" lang="scss" scoped> <style rel="stylesheet/scss" lang="scss" scoped>
.upload-container { .upload-container {
width: 100%; width: 100%;
height: 100%; height: 100%;
position: relative; position: relative;
.image-uploader{ .image-uploader {
height: 100%; height: 100%;
} }
.image-preview { .image-preview {
@@ -121,6 +115,5 @@
} }
} }
} }
} }
</style> </style>

View File

@@ -1,13 +1,6 @@
<template> <template>
<div class="upload-container"> <div class="upload-container">
<el-upload <el-upload class="image-uploader" :data="dataObj" drag :multiple="false" :show-file-list="false" action="https://httpbin.org/post"
class="image-uploader"
:data="dataObj"
drag
:multiple="false"
:show-file-list="false"
action="https://httpbin.org/post"
:on-success="handleImageScucess"> :on-success="handleImageScucess">
<i class="el-icon-upload"></i> <i class="el-icon-upload"></i>
<div class="el-upload__text">将文件拖到此处<em>点击上传</em></div> <div class="el-upload__text">将文件拖到此处<em>点击上传</em></div>
@@ -31,6 +24,7 @@
</div> </div>
</div> </div>
</template> </template>
<script> <script>
// 预览效果见文章 // 预览效果见文章
import { getToken } from 'api/qiniu'; import { getToken } from 'api/qiniu';
@@ -81,8 +75,8 @@
</script> </script>
<style rel="stylesheet/scss" lang="scss" scoped> <style rel="stylesheet/scss" lang="scss" scoped>
@import "src/styles/mixin.scss"; @import "src/styles/mixin.scss";
.upload-container { .upload-container {
width: 100%; width: 100%;
position: relative; position: relative;
@include clearfix; @include clearfix;
@@ -132,23 +126,21 @@
} }
} }
} }
.image-app-preview{ .image-app-preview {
width: 320px; width: 320px;
height: 180px; height: 180px;
position: relative; position: relative;
border: 1px dashed #d9d9d9; border: 1px dashed #d9d9d9;
float: left; float: left;
margin-left: 50px; margin-left: 50px;
.app-fake-conver{ .app-fake-conver {
height: 44px; height: 44px;
position: absolute; position: absolute;
width: 100%; width: 100%; // background: rgba(0, 0, 0, .1);
// background: rgba(0, 0, 0, .1);
text-align: center; text-align: center;
line-height: 64px; line-height: 64px;
color: #fff; color: #fff;
}
} }
} }
}
</style> </style>

View File

@@ -4,7 +4,6 @@
</div> </div>
</template> </template>
<script> <script>
import CodeMirror from 'codemirror'; import CodeMirror from 'codemirror';
import 'codemirror/addon/lint/lint.css'; import 'codemirror/addon/lint/lint.css';
@@ -55,10 +54,11 @@
</script> </script>
<style> <style>
.CodeMirror { .CodeMirror {
height: 100%; height: 100%;
} }
.json-editor .cm-s-rubyblue span.cm-string{
.json-editor .cm-s-rubyblue span.cm-string {
color: #F08047; color: #F08047;
} }
</style> </style>

View File

@@ -3,7 +3,7 @@
<div class="twoDndList-list" :style="{width:width1}"> <div class="twoDndList-list" :style="{width:width1}">
<h3>{{list1Title}}</h3> <h3>{{list1Title}}</h3>
<draggable :list="list1" class="dragArea" :options="{group:'article'}"> <draggable :list="list1" class="dragArea" :options="{group:'article'}">
<div class="list-complete-item" v-for="element in list1"> <div class="list-complete-item" v-for="element in list1" :key='element'>
<div class="list-complete-item-handle">[{{element.author}}] {{element.title}}</div> <div class="list-complete-item-handle">[{{element.author}}] {{element.title}}</div>
<div style="position:absolute;right:0px;"> <div style="position:absolute;right:0px;">
<span style="float: right ;margin-top: -20px;margin-right:5px;" @click="deleteEle(element)"> <span style="float: right ;margin-top: -20px;margin-right:5px;" @click="deleteEle(element)">
@@ -17,7 +17,7 @@
<div class="twoDndList-list" :style="{width:width2}"> <div class="twoDndList-list" :style="{width:width2}">
<h3>{{list2Title}}</h3> <h3>{{list2Title}}</h3>
<draggable :list="filterList2" class="dragArea" :options="{group:'article'}"> <draggable :list="filterList2" class="dragArea" :options="{group:'article'}">
<div class="list-complete-item" v-for="element in filterList2"> <div class="list-complete-item" v-for="element in filterList2" :key='element'>
<div class='list-complete-item-handle2' @click="pushEle(element)"> [{{element.author}}] {{element.title}}</div> <div class='list-complete-item-handle2' @click="pushEle(element)"> [{{element.author}}] {{element.title}}</div>
</div> </div>
</draggable> </draggable>
@@ -97,7 +97,7 @@
</script> </script>
<style rel="stylesheet/scss" lang="scss" scoped> <style rel="stylesheet/scss" lang="scss" scoped>
.twoDndList { .twoDndList {
background: #fff; background: #fff;
padding-bottom: 40px; padding-bottom: 40px;
&:after { &:after {
@@ -117,9 +117,9 @@
padding-bottom: 30px; padding-bottom: 30px;
} }
} }
} }
.list-complete-item { .list-complete-item {
cursor: pointer; cursor: pointer;
position: relative; position: relative;
font-size: 14px; font-size: 14px;
@@ -127,30 +127,32 @@
margin-top: 4px; margin-top: 4px;
border: 1px solid #bfcbd9; border: 1px solid #bfcbd9;
transition: all 1s; transition: all 1s;
} }
.list-complete-item-handle { .list-complete-item-handle {
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
white-space: nowrap; white-space: nowrap;
margin-right: 50px; margin-right: 50px;
} }
.list-complete-item-handle2{
.list-complete-item-handle2 {
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
white-space: nowrap; white-space: nowrap;
margin-right: 20px; margin-right: 20px;
} }
.list-complete-item.sortable-chosen { .list-complete-item.sortable-chosen {
background: #4AB7BD; background: #4AB7BD;
} }
.list-complete-item.sortable-ghost { .list-complete-item.sortable-ghost {
background: #30B08F; background: #30B08F;
} }
.list-complete-enter, .list-complete-leave-active { .list-complete-enter,
.list-complete-leave-active {
opacity: 0; opacity: 0;
} }
</style> </style>

View File

@@ -1,7 +1,6 @@
(function() { const vueSticky = {};
const vueSticky = {}; let listenAction;
let listenAction; vueSticky.install = Vue => {
vueSticky.install = Vue => {
Vue.directive('sticky', { Vue.directive('sticky', {
inserted(el, binding) { inserted(el, binding) {
const params = binding.value || {}, const params = binding.value || {},
@@ -86,14 +85,7 @@
window.removeEventListener('scroll', listenAction) window.removeEventListener('scroll', listenAction)
} }
}) })
}; };
if (typeof exports == 'object') {
module.exports = vueSticky export default vueSticky
} else if (typeof define == 'function' && define.amd) {
define([], () => vueSticky)
} else if (window.Vue) {
window.vueSticky = vueSticky;
Vue.use(vueSticky)
}
}());

View File

@@ -1,7 +1,7 @@
import './waves.css'; import './waves.css';
(function() {
const vueWaves = {}; const vueWaves = {};
vueWaves.install = (Vue, options = {}) => { vueWaves.install = (Vue, options = {}) => {
Vue.directive('waves', { Vue.directive('waves', {
bind(el, binding) { bind(el, binding) {
el.addEventListener('click', e => { el.addEventListener('click', e => {
@@ -41,14 +41,7 @@ import './waves.css';
}, false); }, false);
} }
}) })
}; };
if (typeof exports == 'object') {
module.exports = vueWaves export default vueWaves;
} else if (typeof define == 'function' && define.amd) {
define([], () => vueWaves)
} else if (window.Vue) {
window.vueWaves = vueWaves;
Vue.use(vueWaves)
}
}());

View File

@@ -24,7 +24,6 @@ export function parseTime(time, cFormat) {
time = +time * 1000 time = +time * 1000
} }
const format = cFormat || '{y}-{m}-{d} {h}:{i}:{s}'; const format = cFormat || '{y}-{m}-{d} {h}:{i}:{s}';
let date; let date;
if (typeof time == 'object') { if (typeof time == 'object') {
@@ -75,8 +74,6 @@ export function formatTime(time, option) {
} }
} }
/* 数字 格式化*/ /* 数字 格式化*/
export function nFormatter(num, digits) { export function nFormatter(num, digits) {
const si = [ const si = [
@@ -95,14 +92,12 @@ export function nFormatter(num, digits) {
return num.toString(); return num.toString();
} }
export function html2Text(val) { export function html2Text(val) {
const div = document.createElement('div'); const div = document.createElement('div');
div.innerHTML = val; div.innerHTML = val;
return div.textContent || div.innerText; return div.textContent || div.innerText;
} }
export function toThousandslsFilter(num) { 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, ','));
} }

View File

@@ -6,17 +6,16 @@ import router from './router';
import store from './store'; import store from './store';
import ElementUI from 'element-ui'; import ElementUI from 'element-ui';
import 'element-ui/lib/theme-default/index.css'; 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 'assets/custom-theme/index.css'; // 换肤版本element-ui css
import NProgress from 'nprogress'; // Progress 进度条 import NProgress from 'nprogress'; // Progress 进度条
import 'nprogress/nprogress.css';// Progress 进度条 样式 import 'nprogress/nprogress.css';// Progress 进度条 样式
import 'normalize.css/normalize.css';// normalize.css 样式格式化 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 'assets/iconfont/iconfont'; // iconfont 具体图标见https://github.com/PanJiaChen/vue-element-admin/wiki
import * as filters from './filters'; // 全局vue filter import * as filters from './filters'; // 全局vue filter
import Multiselect from 'vue-multiselect';// 使用的一个多选框组件element-ui的select不能满足所有需求 import Multiselect from 'vue-multiselect';// 使用的一个多选框组件element-ui的select不能满足所有需求
import 'vue-multiselect/dist/vue-multiselect.min.css';// 多选框组件css import 'vue-multiselect/dist/vue-multiselect.min.css';// 多选框组件css
import Sticky from 'components/Sticky'; // 粘性header组件 import Sticky from 'components/Sticky'; // 粘性header组件
import IconSvg from 'components/Icon-svg';// svg 组件
import vueWaves from './directive/waves';// 水波纹指令 import vueWaves from './directive/waves';// 水波纹指令
import errLog from 'store/errLog';// error log组件 import errLog from 'store/errLog';// error log组件
import './mock/index.js'; // 该项目所有请求使用mockjs模拟 import './mock/index.js'; // 该项目所有请求使用mockjs模拟
@@ -24,6 +23,7 @@ import './mock/index.js'; // 该项目所有请求使用mockjs模拟
// register globally // register globally
Vue.component('multiselect', Multiselect); Vue.component('multiselect', Multiselect);
Vue.component('Sticky', Sticky); Vue.component('Sticky', Sticky);
Vue.component('icon-svg', IconSvg)
Vue.use(ElementUI); Vue.use(ElementUI);
Vue.use(vueWaves); Vue.use(vueWaves);
@@ -52,11 +52,9 @@ router.beforeEach((to, from, next) => {
const roles = res.data.role; const roles = res.data.role;
store.dispatch('GenerateRoutes', { roles }).then(() => { // 生成可访问的路由表 store.dispatch('GenerateRoutes', { roles }).then(() => { // 生成可访问的路由表
router.addRoutes(store.getters.addRouters) // 动态添加可访问路由表 router.addRoutes(store.getters.addRouters) // 动态添加可访问路由表
next(to.path); // hack方法 确保addRoutes已完成 next({ ...to }); // hack方法 确保addRoutes已完成
})
}) })
}).catch(err => {
console.log(err);
});
} else { } else {
// 没有动态改变权限的需求可直接next() 删除下方权限判断 ↓ // 没有动态改变权限的需求可直接next() 删除下方权限判断 ↓
if (hasPermission(store.getters.roles, to.meta.role)) { if (hasPermission(store.getters.roles, to.meta.role)) {
@@ -77,15 +75,11 @@ router.beforeEach((to, from, next) => {
} }
}); });
router.afterEach(() => { router.afterEach(() => {
NProgress.done(); // 结束Progress NProgress.done(); // 结束Progress
}); });
// window.onunhandledrejection = e => { Vue.config.productionTip = false;
// console.log('unhandled', e.reason, e.promise);
// e.preventDefault()
// };
// 生产环境错误日志 // 生产环境错误日志
if (process.env === 'production') { if (process.env === 'production') {
@@ -99,22 +93,12 @@ if (process.env === 'production') {
}; };
} }
// 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);
new Vue({ new Vue({
el: '#app',
router, router,
store, store,
render: h => h(App) template: '<App/>',
}).$mount('#app'); components: { App }
})

View File

@@ -13,7 +13,7 @@ for (let i = 0; i < count; i++) {
title: '@ctitle(10, 20)', title: '@ctitle(10, 20)',
forecast: '@float(0, 100, 2, 2)', forecast: '@float(0, 100, 2, 2)',
importance: '@integer(1, 3)', importance: '@integer(1, 3)',
'type|1': ['FD', 'FE', 'BI', 'VN'], 'type|1': ['CN', 'US', 'JP', 'EU'],
'status|1': ['published', 'draft', 'deleted'], 'status|1': ['published', 'draft', 'deleted'],
pageviews: '@integer(300, 5000)' pageviews: '@integer(300, 5000)'
})); }));

View File

@@ -5,26 +5,22 @@ const userMap = {
role: ['admin'], role: ['admin'],
token: 'admin', token: 'admin',
introduction: '我是超级管理员', introduction: '我是超级管理员',
avatar: 'https://wdl.wallstreetcn.com/48a3e1e0-ea2c-4a4e-9928-247645e3428b', avatar: 'https://wpimg.wallstcn.com/f778738c-e4f8-4870-b634-56703b4acafe.gif',
name: '超级管理员小潘', name: 'Super Admin'
uid: '001'
}, },
editor: { editor: {
role: ['editor'], role: ['editor'],
token: 'editor', token: 'editor',
introduction: '我是编辑', introduction: '我是编辑',
avatar: 'https://wdl.wallstreetcn.com/48a3e1e0-ea2c-4a4e-9928-247645e3428b', avatar: 'https://wpimg.wallstcn.com/f778738c-e4f8-4870-b634-56703b4acafe.gif',
name: '普通编辑小张', name: 'Normal Editor'
uid: '002'
}, },
developer: { developer: {
role: ['develop'], role: ['develop'],
token: 'develop', token: 'develop',
introduction: '我是开发', introduction: '我是开发',
avatar: 'https://wdl.wallstreetcn.com/48a3e1e0-ea2c-4a4e-9928-247645e3428b', avatar: 'https://wpimg.wallstcn.com/f778738c-e4f8-4870-b634-56703b4acafe.gif',
name: '工程师小王', name: '工程师小王'
uid: '003'
} }
} }

View File

@@ -0,0 +1 @@
module.exports = file => require('@/views/' + file + '.vue')

View File

@@ -0,0 +1 @@
module.exports = file => () => import('@/views/' + file + '.vue')

View File

@@ -1,65 +1,66 @@
import Vue from 'vue'; import Vue from 'vue';
import Router from 'vue-router'; import Router from 'vue-router';
const _import = require('./_import_' + process.env.NODE_ENV);
// in development env not use Lazy Loading,because Lazy Loading large page will cause webpack hot update too slow.so only in production use Lazy Loading
/* layout*/ /* layout */
import Layout from '../views/layout/Layout'; import Layout from '../views/layout/Layout';
// dashboard /* login */
const dashboard = resolve => require(['../views/dashboard/index'], resolve); const Login = _import('login/index');
const authRedirect = _import('login/authredirect');
/* error page*/ /* dashboard */
const Err404 = resolve => require(['../views/error/404'], resolve); const dashboard = _import('dashboard/index');
const Err401 = resolve => require(['../views/error/401'], resolve);
/* login*/ /* Introduction */
import Login from '../views/login/'; const Introduction = _import('introduction/index');
import authRedirect from '../views/login/authredirect';
import sendPWD from '../views/login/sendpwd';
import reset from '../views/login/reset';
/* Introduction*/ /* components */
const Introduction = resolve => require(['../views/introduction/index'], resolve); const componentsIndex = _import('components/index');
const Tinymce = _import('components/tinymce');
const Markdown = _import('components/markdown');
const JsonEditor = _import('components/jsoneditor');
const DndList = _import('components/dndlist');
const AvatarUpload = _import('components/avatarUpload');
const Dropzone = _import('components/dropzone');
const Sticky = _import('components/sticky');
const SplitPane = _import('components/splitpane');
const CountTo = _import('components/countTo');
const Mixin = _import('components/mixin');
/* components*/ /* charts */
const componentsIndex = resolve => require(['../views/components/index'], resolve); const chartIndex = _import('charts/index');
const Tinymce = resolve => require(['../views/components/tinymce'], resolve); const KeyboardChart = _import('charts/keyboard');
const Markdown = resolve => require(['../views/components/markdown'], resolve); const KeyboardChart2 = _import('charts/keyboard2');
const JsonEditor = resolve => require(['../views/components/jsoneditor'], resolve); const LineMarker = _import('charts/line');
const DndList = resolve => require(['../views/components/dndlist'], resolve); const MixChart = _import('charts/mixchart');
const AvatarUpload = resolve => require(['../views/components/avatarUpload'], resolve);
const Dropzone = resolve => require(['../views/components/dropzone'], resolve);
const Sticky = resolve => require(['../views/components/sticky'], resolve);
const SplitPane = resolve => require(['../views/components/splitpane'], resolve);
const CountTo = resolve => require(['../views/components/countTo'], resolve);
const Mixin = resolve => require(['../views/components/mixin'], resolve);
/* error page */
const Err404 = _import('error/404');
const Err401 = _import('error/401');
/* charts*/ /* error log */
const chartIndex = resolve => require(['../views/charts/index'], resolve); const ErrorLog = _import('errlog/index');
const KeyboardChart = resolve => require(['../views/charts/keyboard'], resolve);
const KeyboardChart2 = resolve => require(['../views/charts/keyboard2'], resolve);
const LineMarker = resolve => require(['../views/charts/line'], resolve);
const MixChart = resolve => require(['../views/charts/mixchart'], resolve);
/* error log*/ /* excel */
const ErrorLog = resolve => require(['../views/errlog/index'], resolve); const ExcelDownload = _import('excel/index');
/* excel*/ /* theme */
const ExcelDownload = resolve => require(['../views/excel/index'], resolve); const Theme = _import('theme/index');
/* theme*/
const Theme = resolve => require(['../views/theme/index'], resolve);
/* example*/ /* example*/
const DynamicTable = resolve => require(['../views/example/dynamictable'], resolve); const TableLayout = _import('example/table/index');
const Table = resolve => require(['../views/example/table'], resolve); const DynamicTable = _import('example/table/dynamictable');
const DragTable = resolve => require(['../views/example/dragTable'], resolve); const Table = _import('example/table/table');
const InlineEditTable = resolve => require(['../views/example/inlineEditTable'], resolve); const DragTable = _import('example/table/dragTable');
const Form1 = resolve => require(['../views/example/form1'], resolve); const InlineEditTable = _import('example/table/inlineEditTable');
const Form = _import('example/form');
const Tab = _import('example/tab/index');
/* permission */ /* permission */
const Permission = resolve => require(['../views/permission/index'], resolve); const Permission = _import('permission/index');
Vue.use(Router); Vue.use(Router);
@@ -69,13 +70,11 @@ Vue.use(Router);
* redirect : if redirect:noredirect will not redirct in the levelbar * redirect : if redirect:noredirect will not redirct in the levelbar
* noDropdown : if noDropdown:true will not has submenu * noDropdown : if noDropdown:true will not has submenu
* meta : { role: ['admin'] } will control the page role * meta : { role: ['admin'] } will control the page role
*/ **/
export const constantRouterMap = [ export const constantRouterMap = [
{ path: '/login', component: Login, hidden: true }, { path: '/login', component: Login, hidden: true },
{ path: '/authredirect', component: authRedirect, 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: '/404', component: Err404, hidden: true },
{ path: '/401', component: Err401, hidden: true }, { path: '/401', component: Err401, hidden: true },
{ {
@@ -191,12 +190,23 @@ export const asyncRouterMap = [
redirect: 'noredirect', redirect: 'noredirect',
name: '综合实例', name: '综合实例',
icon: 'zonghe', icon: 'zonghe',
children: [
{
path: '/example/table',
component: TableLayout,
redirect: '/example/table/table',
name: 'Table',
children: [ children: [
{ path: 'dynamictable', component: DynamicTable, name: '动态table' }, { path: 'dynamictable', component: DynamicTable, name: '动态table' },
{ path: 'dragtable', component: DragTable, name: '拖拽table' }, { path: 'dragtable', component: DragTable, name: '拖拽table' },
{ path: 'inline_edit_table', component: InlineEditTable, name: 'table内编辑' }, { path: 'inline_edit_table', component: InlineEditTable, name: 'table内编辑' },
{ path: 'table', component: Table, name: '综合table' }, { path: 'table', component: Table, name: '综合table' }
{ path: 'form1', component: Form1, name: '综合form1' } ]
},
{ path: 'form/edit', component: Form, name: '编辑Form', meta: { isEdit: true } },
{ path: 'form/create', component: Form, name: '创建Form' },
{ path: 'tab/index', component: Tab, name: 'Tab' }
] ]
}, },
{ path: '*', redirect: '/404', hidden: true } { path: '*', redirect: '/404', hidden: true }

View File

@@ -1,12 +1,10 @@
const getters = { const getters = {
sidebar: state => state.app.sidebar, sidebar: state => state.app.sidebar,
visitedViews: state => state.app.visitedViews,
token: state => state.user.token, token: state => state.user.token,
avatar: state => state.user.avatar, avatar: state => state.user.avatar,
name: state => state.user.name, name: state => state.user.name,
uid: state => state.user.uid,
email: state => state.user.email,
introduction: state => state.user.introduction, introduction: state => state.user.introduction,
auth_type: state => state.user.auth_type,
status: state => state.user.status, status: state => state.user.status,
roles: state => state.user.roles, roles: state => state.user.roles,
setting: state => state.user.setting, setting: state => state.user.setting,

View File

@@ -6,7 +6,8 @@ const app = {
opened: !+Cookies.get('sidebarStatus') opened: !+Cookies.get('sidebarStatus')
}, },
theme: 'default', theme: 'default',
livenewsChannels: Cookies.get('livenewsChannels') || '[]' livenewsChannels: Cookies.get('livenewsChannels') || '[]',
visitedViews: []
}, },
mutations: { mutations: {
TOGGLE_SIDEBAR: state => { TOGGLE_SIDEBAR: state => {
@@ -16,11 +17,25 @@ const app = {
Cookies.set('sidebarStatus', 0); Cookies.set('sidebarStatus', 0);
} }
state.sidebar.opened = !state.sidebar.opened; state.sidebar.opened = !state.sidebar.opened;
},
ADD_VISITED_VIEWS: (state, view) => {
if (state.visitedViews.includes(view)) return
state.visitedViews.push(view)
},
DEL_VISITED_VIEWS: (state, view) => {
const index = state.visitedViews.indexOf(view)
state.visitedViews.splice(index, 1)
} }
}, },
actions: { actions: {
ToggleSideBar: ({ commit }) => { ToggleSideBar: ({ commit }) => {
commit('TOGGLE_SIDEBAR') commit('TOGGLE_SIDEBAR')
},
addVisitedViews: ({ commit }, view) => {
commit('ADD_VISITED_VIEWS', view)
},
delVisitedViews: ({ commit }, view) => {
commit('DEL_VISITED_VIEWS', view)
} }
} }
}; };

View File

@@ -1,5 +1,10 @@
import { asyncRouterMap, constantRouterMap } from 'src/router'; import { asyncRouterMap, constantRouterMap } from 'src/router';
/**
* 通过meta.role判断是否与当前用户权限匹配
* @param roles
* @param route
*/
function hasPermission(roles, route) { function hasPermission(roles, route) {
if (route.meta && route.meta.role) { if (route.meta && route.meta.role) {
return roles.some(role => route.meta.role.indexOf(role) >= 0) return roles.some(role => route.meta.role.indexOf(role) >= 0)
@@ -8,40 +13,45 @@ 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 = { const permission = {
state: { state: {
routers: constantRouterMap, routers: constantRouterMap,
addRouters: [] addRouters: []
}, },
mutations: { mutations: {
SET_ROUTERS: (state, routers) => { SET_ROUTERS: (state, routers) => {
state.addRouters = routers; state.addRouters = routers;
state.routers = constantRouterMap.concat(routers); state.routers = constantRouterMap.concat(routers);
} }
}, },
actions: { actions: {
GenerateRoutes({ commit }, data) { GenerateRoutes({ commit }, data) {
return new Promise(resolve => { return new Promise(resolve => {
const { roles } = data; const { roles } = data
const accessedRouters = asyncRouterMap.filter(v => { let accessedRouters
if (roles.indexOf('admin') >= 0) return true; if (roles.indexOf('admin') >= 0) {
if (hasPermission(roles, v)) { accessedRouters = asyncRouterMap
if (v.children && v.children.length > 0) {
v.children = v.children.filter(child => {
if (hasPermission(roles, child)) {
return child
}
return false;
});
return v
} else { } else {
return v accessedRouters = filterAsyncRouter(asyncRouterMap, roles)
} }
}
return false;
});
commit('SET_ROUTERS', accessedRouters); commit('SET_ROUTERS', accessedRouters);
resolve(); resolve();
}) })
@@ -49,5 +59,4 @@ const permission = {
} }
}; };
export default permission; export default permission;

View File

@@ -5,10 +5,7 @@ const user = {
state: { state: {
user: '', user: '',
status: '', status: '',
email: '',
code: '', code: '',
uid: undefined,
auth_type: '',
token: Cookies.get('Admin-Token'), token: Cookies.get('Admin-Token'),
name: '', name: '',
avatar: '', avatar: '',
@@ -20,21 +17,12 @@ const user = {
}, },
mutations: { mutations: {
SET_AUTH_TYPE: (state, type) => {
state.auth_type = type;
},
SET_CODE: (state, code) => { SET_CODE: (state, code) => {
state.code = code; state.code = code;
}, },
SET_TOKEN: (state, token) => { SET_TOKEN: (state, token) => {
state.token = token; state.token = token;
}, },
SET_UID: (state, uid) => {
state.uid = uid;
},
SET_EMAIL: (state, email) => {
state.email = email;
},
SET_INTRODUCTION: (state, introduction) => { SET_INTRODUCTION: (state, introduction) => {
state.introduction = introduction; state.introduction = introduction;
}, },
@@ -70,7 +58,6 @@ const user = {
const data = response.data; const data = response.data;
Cookies.set('Admin-Token', response.data.token); Cookies.set('Admin-Token', response.data.token);
commit('SET_TOKEN', data.token); commit('SET_TOKEN', data.token);
commit('SET_EMAIL', email);
resolve(); resolve();
}).catch(error => { }).catch(error => {
reject(error); reject(error);
@@ -78,7 +65,6 @@ const user = {
}); });
}, },
// 获取用户信息 // 获取用户信息
GetInfo({ commit, state }) { GetInfo({ commit, state }) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
@@ -87,7 +73,6 @@ const user = {
commit('SET_ROLES', data.role); commit('SET_ROLES', data.role);
commit('SET_NAME', data.name); commit('SET_NAME', data.name);
commit('SET_AVATAR', data.avatar); commit('SET_AVATAR', data.avatar);
commit('SET_UID', data.uid);
commit('SET_INTRODUCTION', data.introduction); commit('SET_INTRODUCTION', data.introduction);
resolve(response); resolve(response);
}).catch(error => { }).catch(error => {
@@ -100,7 +85,7 @@ const user = {
LoginByThirdparty({ commit, state }, code) { LoginByThirdparty({ commit, state }, code) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
commit('SET_CODE', code); commit('SET_CODE', code);
loginByThirdparty(state.status, state.email, state.code, state.auth_type).then(response => { loginByThirdparty(state.status, state.email, state.code).then(response => {
commit('SET_TOKEN', response.data.token); commit('SET_TOKEN', response.data.token);
Cookies.set('Admin-Token', response.data.token); Cookies.set('Admin-Token', response.data.token);
resolve(); resolve();
@@ -110,7 +95,6 @@ const user = {
}); });
}, },
// 登出 // 登出
LogOut({ commit, state }) { LogOut({ commit, state }) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
@@ -132,6 +116,16 @@ const user = {
Cookies.remove('Admin-Token'); Cookies.remove('Admin-Token');
resolve(); resolve();
}); });
},
// 动态修改权限
ChangeRole({ commit }, role) {
return new Promise(resolve => {
commit('SET_ROLES', [role]);
commit('SET_TOKEN', role);
Cookies.set('Admin-Token', role);
resolve();
})
} }
} }
}; };

View File

@@ -1,6 +1,6 @@
@import './btn.scss'; @import './btn.scss';
@import './element-ui.scss'; @import './element-ui.scss';
@import "./mixin.scss"; @import './mixin.scss';
body { body {
-moz-osx-font-smoothing: grayscale; -moz-osx-font-smoothing: grayscale;
-webkit-font-smoothing: antialiased; -webkit-font-smoothing: antialiased;
@@ -96,6 +96,7 @@ code {
opacity: 0; opacity: 0;
} }
//main-container全局样式 //main-container全局样式
.app-container { .app-container {
padding: 20px; padding: 20px;
@@ -108,12 +109,14 @@ code {
margin-top: 30px; margin-top: 30px;
} }
.editor-container .CodeMirror { .editor-container .CodeMirror {
height: 100%!important; height: 100%!important;
} }
.wscn-icon { .text-center{
text-align: center
}
.svg-icon {
width: 1em; width: 1em;
height: 1em; height: 1em;
vertical-align: -0.15em; vertical-align: -0.15em;

View File

@@ -24,27 +24,34 @@ service.interceptors.request.use(config => {
// respone拦截器 // respone拦截器
service.interceptors.response.use( service.interceptors.response.use(
response => response response => response,
/** /**
* 下面的注释为通过response自定义code来标示请求状态当code返回如下情况为权限有问题登出并返回到登录页 * 下面的注释为通过response自定义code来标示请求状态当code返回如下情况为权限有问题登出并返回到登录页
* 如通过xmlhttprequest 状态码标识 逻辑可写在下面error中 * 如通过xmlhttprequest 状态码标识 逻辑可写在下面error中
*/ */
// const code = response.data.code; // const res = response.data;
// // 50014:Token 过期了 50012:其他客户端登录了 50008:非法的token // if (res.code !== 20000) {
// if (code === 50008 || code === 50014 || code === 50012) { // Message({
// Message({ // message: res.message,
// message: res.message, // type: 'error',
// type: 'error', // duration: 5 * 1000
// duration: 5 * 1000 // });
// }); // // 50008:非法的token; 50012:其他客户端登录了; 50014:Token 过期了;
// // 登出 // if (res.code === 50008 || res.code === 50012 || res.code === 50014) {
// store.dispatch('FedLogOut').then(() => { // MessageBox.confirm('你已被登出,可以取消继续留在该页面,或者重新登录', '确定登出', {
// router.push({ path: '/login' }) // confirmButtonText: '重新登录',
// }); // cancelButtonText: '取消',
// } else { // type: 'warning'
// return response // }).then(() => {
// } // store.dispatch('FedLogOut').then(() => {
, // location.reload();// 为了重新实例化vue-router对象 避免bug
// });
// })
// }
// return Promise.reject(error);
// } else {
// return response.data;
// }
error => { error => {
console.log('err' + error);// for debug console.log('err' + error);// for debug
Message({ Message({

View File

@@ -110,7 +110,10 @@
export function param2Obj(url) { export function param2Obj(url) {
const search = url.split('?')[1]; const search = url.split('?')[1];
return JSON.parse('{"' + decodeURIComponent(search).replace(/"/g, '\\"').replace(/&/g, '","').replace(/=/g, '":"') + '"}') if (!search) {
return {}
}
return JSON.parse('{"' + decodeURIComponent(search).replace(/"/g, '\\"').replace(/&/g, '","').replace(/=/g, '":"') + '"}');
} }
export function html2Text(val) { export function html2Text(val) {
@@ -212,3 +215,38 @@
} }
} }
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;
};
}

View File

@@ -1,7 +1,7 @@
<template> <template>
<div class="components-container" > <div class="components-container" >
<code> <code>
这里的所有的图表都基于echarts,实例代码来源<a href='http://gallery.echartsjs.com/explore.html#sort=rank~timeframe=all~author=all' target='_blank'>gallery</a><br/>其实echarts封装的很好了用vue封装是很简单的事情建议大家自己来封装 这里的所有的图表都基于ECharts,实例代码来源<a href='http://gallery.echartsjs.com/explore.html#sort=rank~timeframe=all~author=all' target='_blank'>gallery</a><br/>其实ECharts封装的很好了用vue封装是很简单的事情建议大家自己来封装<a target='_blank' class='lin' href="https://segmentfault.com/a/1190000009762198#articleHeader16">相关教程</a>
</code> </code>
</div> </div>
</template> </template>

View File

@@ -1,11 +1,11 @@
<template> <template>
<div class="components-container" style='height:100vh'> <div class="components-container" style='height:100vh'>
<div class='chart-container'> <div class='chart-container'>
<keyboardChart height='100%' width='100%' /> <keyboard-chart height='100%' width='100%'></keyboard-chart>
</div> </div>
</div> </div>
</template> </template>
<script> <script>
import keyboardChart from 'components/Charts/keyboard'; import keyboardChart from 'components/Charts/keyboard';

View File

@@ -1,11 +1,11 @@
<template> <template>
<div class="components-container" style='height:100vh'> <div class="components-container" style='height:100vh'>
<div class='chart-container'> <div class='chart-container'>
<keyboardChart2 id='apple' height='100%' width='100%' /> <keyboard-chart2 id='apple' height='100%' width='100%'></keyboard-chart2>
</div> </div>
</div> </div>
</template> </template>
<script> <script>
import keyboardChart2 from 'components/Charts/keyboard2'; import keyboardChart2 from 'components/Charts/keyboard2';

View File

@@ -1,13 +1,11 @@
<template> <template>
<div class="components-container" style='height:100vh'> <div class="components-container" style='height:100vh'>
https://github.com/ecomfe/echarts/blob/master/index.js
http://echarts.baidu.com/tutorial.html
<div class='chart-container'> <div class='chart-container'>
<lineMarker height='100%' width='100%' /> <line-marker height='100%' width='100%'></line-marker>
</div> </div>
</div> </div>
</template> </template>
<script> <script>
import lineMarker from 'components/Charts/lineMarker'; import lineMarker from 'components/Charts/lineMarker';

View File

@@ -1,16 +1,16 @@
<template> <template>
<div class="components-container" style='height:100vh'> <div class="components-container" style='height:100vh'>
<div class='chart-container'> <div class='chart-container'>
<mixchart id='apple' height='100%' width='100%' /> <mix-chart id='apple' height='100%' width='100%'></mix-chart>
</div> </div>
</div> </div>
</template> </template>
<script> <script>
import mixchart from 'components/Charts/mixchart'; import mixChart from 'components/Charts/mixChart';
export default { export default {
components: { mixchart } components: { mixChart }
}; };
</script> </script>

View File

@@ -4,17 +4,19 @@
由于我在使用时它只有vue@1版本而且有些业务的需求耦合到七牛等等原因吧自己改造了一下如果大家要使用的话优先还是使用官方component 由于我在使用时它只有vue@1版本而且有些业务的需求耦合到七牛等等原因吧自己改造了一下如果大家要使用的话优先还是使用官方component
</code> </code>
<PanThumb :image='image'> <pan-thumb :image='image'></pan-thumb>
</PanThumb>
<el-button type="primary" icon="upload" style="position: absolute;bottom: 15px;margin-left: 40px;" @click="imagecropperShow=true">修改头像 <el-button type="primary" icon="upload" style="position: absolute;bottom: 15px;margin-left: 40px;" @click="imagecropperShow=true">修改头像
</el-button> </el-button>
<ImageCropper :width="300" :height="300" url="https://httpbin.org/post" @crop-upload-success="cropSuccess" :key="imagecropperKey" v-show="imagecropperShow" /> <image-cropper :width="300" :height="300" url="https://httpbin.org/post" @close='close' @crop-upload-success="cropSuccess" :key="imagecropperKey" v-show="imagecropperShow"></image-cropper>
</div> </div>
</template> </template>
<script> <script>
import ImageCropper from 'components/ImageCropper'; import ImageCropper from 'components/ImageCropper';
import PanThumb from 'components/PanThumb'; import PanThumb from 'components/PanThumb';
export default { export default {
components: { ImageCropper, PanThumb }, components: { ImageCropper, PanThumb },
data() { data() {
@@ -29,15 +31,19 @@
this.imagecropperShow = false; this.imagecropperShow = false;
this.imagecropperKey = this.imagecropperKey + 1; this.imagecropperKey = this.imagecropperKey + 1;
this.image = resData.files.avatar; this.image = resData.files.avatar;
},
close() {
this.imagecropperShow = false;
} }
} }
}; };
</script> </script>
<style scoped> <style scoped>
.avatar{ .avatar{
width: 200px; width: 200px;
height: 200px; height: 200px;
border-radius: 50%; border-radius: 50%;
} }
</style> </style>

View File

@@ -1,9 +1,9 @@
<template> <template>
<div class="components-container"> <div class="components-container">
<code>countTo 组件 <a href='https://github.com/PanJiaChen/vue-countTo' target='_blank'>线上地址</a></code> <code> <a href='https://github.com/PanJiaChen/vue-countTo' target='_blank'>countTo component</a></code>
<count-to ref='example' class='example' :start-val='_startVal' :end-val='_endVal' :duration='_duration' :decimals='_decimals' <count-to ref='example' class='example' :start-val='_startVal' :end-val='_endVal' :duration='_duration' :decimals='_decimals'
:separator='_separator' :prefix='_prefix' :suffix='_suffix' :autoplay='false' /> :separator='_separator' :prefix='_prefix' :suffix='_suffix' :autoplay='false'></count-to>
<div style='margin-left: 25%;margin-top: 40px;'> <div style='margin-left: 25%;margin-top: 40px;'>
<label class="label" for="startValInput">startVal: <input type="number" v-model.number='setStartVal' name='startValInput' /></label> <label class="label" for="startValInput">startVal: <input type="number" v-model.number='setStartVal' name='startValInput' /></label>
<label class="label" for="endValInput">endVal: <input type="number" v-model.number='setEndVal' name='endVaInput' /></label> <label class="label" for="endValInput">endVal: <input type="number" v-model.number='setEndVal' name='endVaInput' /></label>
@@ -20,9 +20,9 @@
:separator=&#x27;{{_separator}}&#x27; :prefix=&#x27;{{_prefix}}&#x27; :suffix=&#x27;{{_suffix}}&#x27; :autoplay=false&gt;</code> :separator=&#x27;{{_separator}}&#x27; :prefix=&#x27;{{_prefix}}&#x27; :suffix=&#x27;{{_suffix}}&#x27; :autoplay=false&gt;</code>
</div> </div>
</template> </template>
<script> <script>
import countTo from 'vue-count-to'; import countTo from 'vue-count-to';
export default { export default {
components: { countTo }, components: { countTo },
data() { data() {

View File

@@ -1,14 +1,16 @@
<template> <template>
<div class="components-container"> <div class="components-container">
<code>拖拽https://github.com/SortableJS/Vue.Draggable 项目Vue.Draggable</code> <code>drag-list base on <a href="https://github.com/SortableJS/Vue.Draggable" target="_blank">Vue.Draggable</a></code>
<div class="editor-container"> <div class="editor-container">
<DndList :list1="list1" :list2="list2" list1Title="头条列表" list2Title="文章池" /> <dnd-list :list1="list1" :list2="list2" list1Title="头条列表" list2Title="文章池"></dnd-list>
</div> </div>
</div> </div>
</template> </template>
<script> <script>
import DndList from 'components/twoDndList' import DndList from 'components/twoDndList'
import { getList } from 'api/article'; import { getList } from 'api/article';
export default { export default {
components: { DndList }, components: { DndList },
data() { data() {

View File

@@ -4,11 +4,11 @@
由于我司业务有特殊需求而且要传七牛 所以没用第三方 选择了自己封装 由于我司业务有特殊需求而且要传七牛 所以没用第三方 选择了自己封装
</code> </code>
<div class="editor-container"> <div class="editor-container">
<Dropzone v-on:dropzone-removedFile="dropzoneR" v-on:dropzone-success="dropzoneS" id="myVueDropzone" <dropzone v-on:dropzone-removedFile="dropzoneR" v-on:dropzone-success="dropzoneS" id="myVueDropzone" url="https://httpbin.org/post"></dropzone>
url="https://httpbin.org/post"></Dropzone>
</div> </div>
</div> </div>
</template> </template>
<script> <script>
import Dropzone from 'components/Dropzone'; import Dropzone from 'components/Dropzone';

View File

@@ -1,7 +1,7 @@
<template> <template>
<div class="components-container"> <div class="components-container">
<code>这里暂时列出了自己在项目中自己封装和用到的组件如有补充可以提<a href='https://github.com/PanJiaChen/vue-element-admin/issues' target='_blank'>issue</a><br/> <code>这里暂时列出了自己在项目中用到的组件和一些自己封装的组件如有补充可以提<a target='_blank' href='https://github.com/PanJiaChen/vue-element-admin/issues'> issue </a><br/>
我个人崇尚自己封装组件因为很多组件会和业务后高度的耦合很多时候第三方封装是满足不了需求的如有需要可以看楼主之前写过的一篇<a href='https://segmentfault.com/a/1190000009090836' target='_blank'>文章</a> 我个人崇尚自己封装组件因为很多组件会和业务后高度的耦合而且第三方封装的组件灵活性可控性都不高如有需要可以看楼主之前写过的一篇<a href='https://segmentfault.com/a/1190000009090836' target='_blank'>文章</a>
</code> </code>
</div> </div>
</template> </template>

View File

@@ -1,14 +1,16 @@
<template> <template>
<div class="components-container" style='height:100vh'> <div class="components-container" style='height:100vh'>
<code>有校验</code> <code>jsonEditor is base on <a href="https://github.com/codemirror/CodeMirror" target="_blank">CodeMirrorr</a>,lint base on json-lint </code>
<div class="editor-container"> <div class="editor-container">
<json-editor ref="jsonEditor" v-model="value"></json-editor> <json-editor ref="jsonEditor" v-model="value"></json-editor>
</div> </div>
</div> </div>
</template> </template>
<script> <script>
import jsonEditor from 'components/jsonEditor'; import jsonEditor from 'components/jsonEditor';
const jsonData = '[{"items":[{"market_type":"forexdata","symbol":"XAUUSD"},{"market_type":"forexdata","symbol":"UKOIL"},{"market_type":"forexdata","symbol":"CORN"}],"name":""},{"items":[{"market_type":"forexdata","symbol":"XAUUSD"},{"market_type":"forexdata","symbol":"XAGUSD"},{"market_type":"forexdata","symbol":"AUTD"},{"market_type":"forexdata","symbol":"AGTD"}],"name":"贵金属"},{"items":[{"market_type":"forexdata","symbol":"CORN"},{"market_type":"forexdata","symbol":"WHEAT"},{"market_type":"forexdata","symbol":"SOYBEAN"},{"market_type":"forexdata","symbol":"SUGAR"}],"name":"农产品"},{"items":[{"market_type":"forexdata","symbol":"UKOIL"},{"market_type":"forexdata","symbol":"USOIL"},{"market_type":"forexdata","symbol":"NGAS"}],"name":"能源化工"}]'; const jsonData = '[{"items":[{"market_type":"forexdata","symbol":"XAUUSD"},{"market_type":"forexdata","symbol":"UKOIL"},{"market_type":"forexdata","symbol":"CORN"}],"name":""},{"items":[{"market_type":"forexdata","symbol":"XAUUSD"},{"market_type":"forexdata","symbol":"XAGUSD"},{"market_type":"forexdata","symbol":"AUTD"},{"market_type":"forexdata","symbol":"AGTD"}],"name":"贵金属"},{"items":[{"market_type":"forexdata","symbol":"CORN"},{"market_type":"forexdata","symbol":"WHEAT"},{"market_type":"forexdata","symbol":"SOYBEAN"},{"market_type":"forexdata","symbol":"SUGAR"}],"name":"农产品"},{"items":[{"market_type":"forexdata","symbol":"UKOIL"},{"market_type":"forexdata","symbol":"USOIL"},{"market_type":"forexdata","symbol":"NGAS"}],"name":"能源化工"}]';
export default { export default {
components: { jsonEditor }, components: { jsonEditor },
data() { data() {

View File

@@ -1,19 +1,30 @@
<template> <template>
<div class="components-container"> <div class="components-container">
<code>公司做的后台主要是一个cms系统公司也是以自媒体为核心的所以富文本是后台很核心的功能在选择富文本的过程中也走了不少的弯路市面上常见的富文本都基本用过了最终选择了tinymce</code> <code>Markdown 我们这里选用了 <a href="https://github.com/sparksuite/simplemde-markdown-editor" target="_blank">simplemde-markdown-editor</a> 简单的用vue封装了一下<a target='_blank' href='https://segmentfault.com/a/1190000009762198#articleHeader14'> 相关文章 </a></code>
<div class="editor-container"> <div class="editor-container">
<MdEditor id='contentEditor' ref="contentEditor" v-model='content' :height="300" :zIndex='20'></MdEditor> <md-editor id='contentEditor' ref="contentEditor" v-model='content' :height="300" :zIndex='20'></md-editor>
</div> </div>
<el-button @click='markdown2Html' style="margin-top:80px;" type="primary">转为HTML<i class="el-icon-document el-icon--right"></i></el-button>
<div v-html="html"></div>
</div> </div>
</template> </template>
<script> <script>
import MdEditor from 'components/MdEditor'; import MdEditor from 'components/MdEditor';
export default { export default {
components: { MdEditor }, components: { MdEditor },
data() { data() {
return { return {
content: 'Simplemde' content: '## Simplemde',
html: ''
}
},
methods: {
markdown2Html() {
import('showdown').then(showdown => {
const converter = new showdown.Converter();
this.html = converter.makeHtml(this.content)
})
} }
} }
}; };

View File

@@ -1,16 +1,16 @@
<template> <template>
<div class="components-container"> <div class="components-container">
<div class='component-item'> <div class='component-item'>
<MDinput name="name" v-model="title" required :maxlength="100"> <md-input name="name" v-model="title" required :maxlength="100">
标题 标题
</MDinput> </md-input>
<code class='code-part'>Material Design 的input</code> <code class='code-part'>Material Design 的input</code>
</div> </div>
<div class='component-item'> <div class='component-item'>
<PanThumb image='https://wpimg.wallstcn.com/577965b9-bb9e-4e02-9f0c-095b41417191'> <pan-thumb image='https://wpimg.wallstcn.com/577965b9-bb9e-4e02-9f0c-095b41417191'>
上海花裤衩 上海花裤衩
</PanThumb> </pan-thumb>
<code class='code-part'>图片hover效果</code> <code class='code-part'>图片hover效果</code>
</div> </div>
@@ -18,15 +18,15 @@
<el-button v-waves type="primary">水波纹效果</el-button> <el-button v-waves type="primary">水波纹效果</el-button>
<code class='code-part'>水波纹 v-directive</code> <code class='code-part'>水波纹 v-directive</code>
</div> </div>
</div> </div>
</template> </template>
<script> <script>
import MDinput from 'components/MDinput'; import MdInput from 'components/MDinput';
import PanThumb from 'components/PanThumb'; import PanThumb from 'components/PanThumb';
export default { export default {
components: { MDinput, PanThumb }, components: { MdInput, PanThumb },
data() { data() {
return { return {
title: '' title: ''

View File

@@ -1,9 +1,9 @@
<template> <template>
<div class="components-container" > <div class="components-container">
<code>splitPane 如果你用过<a href='http://codepen.io/' target='_blank'>codepen</a>,<a href='https://jsfiddle.net/' target='_blank'>jsfiddle</a>就不会陌生了 <code>splitPane 如果你用过<a href='http://codepen.io/' target='_blank'>codepen</a>,<a href='https://jsfiddle.net/' target='_blank'>jsfiddle</a>就不会陌生了
暂还没有时间开源封装好日后补上 暂还没有时间开源封装好日后补上
</code> </code>
<splitPane v-on:resize="resize" split="vertical"> <split-pane v-on:resize="resize" split="vertical">
<template slot="paneL"> <template slot="paneL">
<div class="left-container"></div> <div class="left-container"></div>
</template> </template>
@@ -18,12 +18,13 @@
</template> </template>
</split-pane> </split-pane>
</template> </template>
</splitPane> </split-pane>
</div> </div>
</template> </template>
<script> <script>
import splitPane from 'components/SplitPane' import splitPane from 'components/SplitPane'
export default { export default {
components: { splitPane }, components: { splitPane },
methods: { methods: {
@@ -33,14 +34,16 @@
} }
}; };
</script> </script>
<style scoped> <style scoped>
.components-container{ .components-container {
position: relative; position: relative;
height: 100vh; height: 100vh;
} }
.left-container { .left-container {
background-color: #F38181; background-color: #F38181;
height:100%; height: 100%;
} }
.right-container { .right-container {

View File

@@ -1,6 +1,6 @@
<template> <template>
<div> <div>
<Sticky className="sub-navbar"> <sticky className="sub-navbar">
<el-dropdown trigger="click"> <el-dropdown trigger="click">
<el-button> <el-button>
平台<i class="el-icon-caret-bottom el-icon--right"></i> 平台<i class="el-icon-caret-bottom el-icon--right"></i>
@@ -32,7 +32,7 @@
<el-button style="margin-left: 10px;" type="success">发布 <el-button style="margin-left: 10px;" type="success">发布
</el-button> </el-button>
</Sticky> </sticky>
<div class="components-container"> <div class="components-container">
<code>Sticky header 当页面滚动到预设的位置会吸附在顶部</code> <code>Sticky header 当页面滚动到预设的位置会吸附在顶部</code>
@@ -90,8 +90,9 @@
<div>我是占位</div> <div>我是占位</div>
</div> </div>
</div> </div>
</template> </template>
<script> <script>
import Sticky from 'components/Sticky'; import Sticky from 'components/Sticky';
@@ -114,9 +115,9 @@
} }
} }
} }
}; };
</script> </script>
<style scoped> <style scoped>
.time-container { .time-container {
display: inline-block; display: inline-block;

View File

@@ -1,14 +1,13 @@
<template> <template>
<div class="components-container"> <div class="components-container">
<code>公司做的后台主要是一个cms系统公司也是以自媒体为核心的所以富文本是后台很核心的功能在选择富文本的过程中也走了不少的弯路市面上常见的富文本都基本用过了最终选择了tinymce</code> <code>公司做的后台主要是一个cms系统公司也是以自媒体为核心的所以富文本是后台很核心的功能在选择富文本的过程中也走了不少的弯路市面上常见的富文本都基本用过了最终选择了Tinymce<a target='_blank' href='https://segmentfault.com/a/1190000009762198#articleHeader13'> 相关文章 </a></code>
<div class="editor-container"> <div>
<Tinymce :height=200 ref="editor" v-model="content"></Tinymce> <Tinymce :height=200 ref="editor" v-model="content"></Tinymce>
</div> </div>
<!--<div class='editor-content'> <div class='editor-content' v-html='content'></div>
{{content}}
</div>-->
</div> </div>
</template> </template>
<script> <script>
import Tinymce from 'components/Tinymce'; import Tinymce from 'components/Tinymce';
@@ -18,11 +17,14 @@
return { return {
content: 'Tinymce' content: 'Tinymce'
} }
},
methods: {
} }
}; };
</script> </script>
<style scoped>
.editor-content{
margin-top: 20px;
}
</style>

View File

@@ -1,16 +1,17 @@
<template> <template>
<div class="dashboard-editor-container"> <div class="dashboard-editor-container">
<div class=" clearfix"> <div class=" clearfix">
<PanThumb style="float: left" :image="avatar"> 你的权限: <pan-thumb style="float: left" :image="avatar"> 你的权限:
<span class="pan-info-roles" v-for="item in roles">{{item}}</span> <span class="pan-info-roles" v-for="item in roles">{{item}}</span>
</PanThumb> </pan-thumb>
<a href="https://github.com/PanJiaChen/vue-element-admin" target="_blank" class="github-corner" aria-label="View source on Github"> <a href="https://github.com/PanJiaChen/vue-element-admin" target="_blank" class="github-corner" aria-label="View source on Github">
<svg width="80" height="80" viewBox="0 0 250 250" style="fill:#4AB7BD; color:#fff; position: absolute; top: 50px; border: 0; right: 0;" <svg width="80" height="80" viewBox="0 0 250 250" style="fill:#4AB7BD; color:#fff; position: absolute; top: 50px; border: 0; right: 0;"
aria-hidden="true"> aria-hidden="true">
<path d="M0,0 L115,115 L130,115 L142,142 L250,250 L250,0 Z"></path> <path d="M0,0 L115,115 L130,115 L142,142 L250,250 L250,0 Z"></path>
<path d="M128.3,109.0 C113.8,99.7 119.0,89.6 119.0,89.6 C122.0,82.7 120.5,78.6 120.5,78.6 C119.2,72.0 123.4,76.3 123.4,76.3 C127.3,80.9 125.5,87.3 125.5,87.3 C122.9,97.6 130.6,101.9 134.4,103.2" <path d="M128.3,109.0 C113.8,99.7 119.0,89.6 119.0,89.6 C122.0,82.7 120.5,78.6 120.5,78.6 C119.2,72.0 123.4,76.3 123.4,76.3 C127.3,80.9 125.5,87.3 125.5,87.3 C122.9,97.6 130.6,101.9 134.4,103.2"
fill="currentColor" style="transform-origin: 130px 106px;" class="octo-arm"></path> fill="currentColor" style="transform-origin: 130px 106px;" class="octo-arm"></path>
<path d="M115.0,115.0 C114.9,115.1 118.7,116.5 119.8,115.4 L133.7,101.6 C136.9,99.2 139.9,98.4 142.2,98.6 C133.8,88.0 127.5,74.4 143.8,58.0 C148.5,53.4 154.0,51.2 159.7,51.0 C160.3,49.4 163.2,43.6 171.4,40.1 C171.4,40.1 176.1,42.5 178.8,56.2 C183.1,58.6 187.2,61.8 190.9,65.4 C194.5,69.0 197.7,73.2 200.1,77.6 C213.8,80.2 216.3,84.9 216.3,84.9 C212.7,93.1 206.9,96.0 205.4,96.6 C205.1,102.4 203.0,107.8 198.3,112.5 C181.9,128.9 168.3,122.5 157.7,114.1 C157.9,116.9 156.7,120.9 152.7,124.9 L141.0,136.5 C139.8,137.7 141.6,141.9 141.8,141.8 Z"fill="currentColor" class="octo-body"></path> <path d="M115.0,115.0 C114.9,115.1 118.7,116.5 119.8,115.4 L133.7,101.6 C136.9,99.2 139.9,98.4 142.2,98.6 C133.8,88.0 127.5,74.4 143.8,58.0 C148.5,53.4 154.0,51.2 159.7,51.0 C160.3,49.4 163.2,43.6 171.4,40.1 C171.4,40.1 176.1,42.5 178.8,56.2 C183.1,58.6 187.2,61.8 190.9,65.4 C194.5,69.0 197.7,73.2 200.1,77.6 C213.8,80.2 216.3,84.9 216.3,84.9 C212.7,93.1 206.9,96.0 205.4,96.6 C205.1,102.4 203.0,107.8 198.3,112.5 C181.9,128.9 168.3,122.5 157.7,114.1 C157.9,116.9 156.7,120.9 152.7,124.9 L141.0,136.5 C139.8,137.7 141.6,141.9 141.8,141.8 Z"
fill="currentColor" class="octo-body"></path>
</svg> </svg>
</a> </a>
<div class="info-container"> <div class="info-container">
@@ -19,7 +20,7 @@
</div> </div>
</div> </div>
<div> <div>
<img class='emptyGif' :src="emptyGif" > <img class='emptyGif' :src="emptyGif">
</div> </div>
</div> </div>
</template> </template>
@@ -27,6 +28,7 @@
<script> <script>
import { mapGetters } from 'vuex'; import { mapGetters } from 'vuex';
import PanThumb from 'components/PanThumb'; import PanThumb from 'components/PanThumb';
export default { export default {
name: 'dashboard-default', name: 'dashboard-default',
components: { PanThumb }, components: { PanThumb },
@@ -39,9 +41,6 @@
...mapGetters([ ...mapGetters([
'name', 'name',
'avatar', 'avatar',
'email',
'uid',
'introduction',
'roles' 'roles'
]) ])
} }
@@ -54,6 +53,7 @@
width: 45%; width: 45%;
margin: 0 auto; margin: 0 auto;
} }
.dashboard-editor-container { .dashboard-editor-container {
background-color: #e3e3e3; background-color: #e3e3e3;
min-height: 100vh; min-height: 100vh;

View File

@@ -1,34 +0,0 @@
<template>
<div class="articlesChart-container">
<span class="articlesChart-container-title">每天撸文</span>
<line-chart :listData='listData' ></line-chart>
</div>
</template>
<script>
import LineChart from 'components/Charts/line';
export default {
name: 'articlesChart',
components: { LineChart },
props: {
listData: {
type: Array,
default: [],
require: true
}
},
data() {
return {}
}
}
</script>
<style>
.articlesChart-container {
width: 100%;
}
.articlesChart-container-title {
color: #7F8C8D;
font-size: 16px;
display: inline-block;
margin-top: 10px;
}
</style>

View File

@@ -0,0 +1,89 @@
<template>
<div :class="className" :style="{height:height,width:width}"></div>
</template>
<script>
import echarts from 'echarts';
require('echarts/theme/macarons'); // echarts 主题
export default {
props: {
className: {
type: String,
default: 'chart'
},
width: {
type: String,
default: '100%'
},
height: {
type: String,
default: '300px'
}
},
data() {
return {
chart: null
};
},
mounted() {
this.initChart();
},
beforeDestroy() {
if (!this.chart) {
return
}
this.chart.dispose();
this.chart = null;
},
methods: {
initChart() {
this.chart = echarts.init(this.$el, 'macarons');
this.chart.setOption({
tooltip: {
trigger: 'axis',
axisPointer: { // 坐标轴指示器,坐标轴触发有效
type: 'shadow' // 默认为直线,可选为:'line' | 'shadow'
}
},
grid: {
left: '3%',
right: '4%',
bottom: '3%',
containLabel: true
},
xAxis: [{
type: 'category',
data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],
axisTick: {
alignWithLabel: true
}
}],
yAxis: [{
type: 'value'
}],
series: [{
name: 'pageA',
type: 'bar',
stack: 'vistors',
barWidth: '60%',
data: [79, 52, 200, 334, 390, 330, 220]
}, {
name: 'pageB',
type: 'bar',
stack: 'vistors',
barWidth: '60%',
data: [80, 52, 200, 334, 390, 330, 220]
}, {
name: 'pageC',
type: 'bar',
stack: 'vistors',
barWidth: '60%',
data: [30, 52, 200, 334, 390, 330, 220]
}]
})
}
}
}
</script>

View File

@@ -1,295 +1,141 @@
<template> <template>
<div class="dashboard-editor-container"> <div class="dashboard-editor-container">
<div class=" clearfix">
<PanThumb style="float: left" :image="avatar"> 你的权限:
<span class="pan-info-roles" v-for="item in roles">{{item}}</span>
</PanThumb>
<a href="https://github.com/PanJiaChen/vue-element-admin" target="_blank" class="github-corner" aria-label="View source on Github"> <a href="https://github.com/PanJiaChen/vue-element-admin" target="_blank" class="github-corner" aria-label="View source on Github">
<svg width="80" height="80" viewBox="0 0 250 250" style="fill:#4AB7BD; color:#fff; position: absolute; top: 50px; border: 0; right: 0;" <svg width="80" height="80" viewBox="0 0 250 250" style="fill:#4AB7BD; color:#fff; position: absolute; top: 50px; border: 0; right: 0;"
aria-hidden="true"> aria-hidden="true">
<path d="M0,0 L115,115 L130,115 L142,142 L250,250 L250,0 Z"></path> <path d="M0,0 L115,115 L130,115 L142,142 L250,250 L250,0 Z"></path>
<path d="M128.3,109.0 C113.8,99.7 119.0,89.6 119.0,89.6 C122.0,82.7 120.5,78.6 120.5,78.6 C119.2,72.0 123.4,76.3 123.4,76.3 C127.3,80.9 125.5,87.3 125.5,87.3 C122.9,97.6 130.6,101.9 134.4,103.2" <path d="M128.3,109.0 C113.8,99.7 119.0,89.6 119.0,89.6 C122.0,82.7 120.5,78.6 120.5,78.6 C119.2,72.0 123.4,76.3 123.4,76.3 C127.3,80.9 125.5,87.3 125.5,87.3 C122.9,97.6 130.6,101.9 134.4,103.2"
fill="currentColor" style="transform-origin: 130px 106px;" class="octo-arm"></path> fill="currentColor" style="transform-origin: 130px 106px;" class="octo-arm"></path>
<path d="M115.0,115.0 C114.9,115.1 118.7,116.5 119.8,115.4 L133.7,101.6 C136.9,99.2 139.9,98.4 142.2,98.6 C133.8,88.0 127.5,74.4 143.8,58.0 C148.5,53.4 154.0,51.2 159.7,51.0 C160.3,49.4 163.2,43.6 171.4,40.1 C171.4,40.1 176.1,42.5 178.8,56.2 C183.1,58.6 187.2,61.8 190.9,65.4 C194.5,69.0 197.7,73.2 200.1,77.6 C213.8,80.2 216.3,84.9 216.3,84.9 C212.7,93.1 206.9,96.0 205.4,96.6 C205.1,102.4 203.0,107.8 198.3,112.5 C181.9,128.9 168.3,122.5 157.7,114.1 C157.9,116.9 156.7,120.9 152.7,124.9 L141.0,136.5 C139.8,137.7 141.6,141.9 141.8,141.8 Z"fill="currentColor" class="octo-body"></path> <path d="M115.0,115.0 C114.9,115.1 118.7,116.5 119.8,115.4 L133.7,101.6 C136.9,99.2 139.9,98.4 142.2,98.6 C133.8,88.0 127.5,74.4 143.8,58.0 C148.5,53.4 154.0,51.2 159.7,51.0 C160.3,49.4 163.2,43.6 171.4,40.1 C171.4,40.1 176.1,42.5 178.8,56.2 C183.1,58.6 187.2,61.8 190.9,65.4 C194.5,69.0 197.7,73.2 200.1,77.6 C213.8,80.2 216.3,84.9 216.3,84.9 C212.7,93.1 206.9,96.0 205.4,96.6 C205.1,102.4 203.0,107.8 198.3,112.5 C181.9,128.9 168.3,122.5 157.7,114.1 C157.9,116.9 156.7,120.9 152.7,124.9 L141.0,136.5 C139.8,137.7 141.6,141.9 141.8,141.8 Z"
fill="currentColor" class="octo-body"></path>
</svg> </svg>
</a> </a>
<div class="info-container"> <el-row class="btn-group">
<el-col :span="4" class='text-center'>
<router-link class="pan-btn blue-btn" to="/components/index">Components</router-link>
</el-col>
<el-col :span="4" class='text-center'>
<router-link class="pan-btn light-blue-btn" to="/charts/index">Charts</router-link>
</el-col>
<el-col :span="4" class='text-center'>
<router-link class="pan-btn pink-btn" to="/excel/download">Excel</router-link>
</el-col>
<el-col :span="4" class='text-center'>
<router-link class="pan-btn green-btn" to="/example/table/table">Table</router-link>
</el-col>
<el-col :span="4" class='text-center'>
<router-link class="pan-btn tiffany-btn" to="/example/form/edit">Form</router-link>
</el-col>
<el-col :span="4" class='text-center'>
<router-link class="pan-btn yellow-btn" to="/example/form/edit">Theme</router-link>
</el-col>
</el-row>
<el-row>
<el-col :span="6">
<el-card class="box-card">
<div slot="header" class="box-card-header">
<pan-thumb class="panThumb" :image="avatar"> 你的权限:
<span class="pan-info-roles" :key='item' v-for="item in roles">{{item}}</span>
</pan-thumb>
</div>
<span class="display_name">{{name}}</span> <span class="display_name">{{name}}</span>
<div class="info-wrapper"> <div class="info-item">
<div class="info-item" :to="'/article/wscnlist?uid='+uid">
<countTo class="info-item-num" :startVal='0' :endVal='statisticsData.article_count' :duration='3400'></countTo> <countTo class="info-item-num" :startVal='0' :endVal='statisticsData.article_count' :duration='3400'></countTo>
<span class="info-item-text">文章</span> <span class="info-item-text">文章</span>
<wscn-icon-svg icon-class="a" class="dashboard-editor-icon"/> <icon-svg icon-class="a" class="dashboard-editor-icon"></icon-svg>
</div> </div>
<div class="info-item" style="cursor: auto"> <div class="info-item">
<countTo class="info-item-num" :startVal='0' :endVal='statisticsData.pageviews_count' :duration='3600'></countTo> <countTo class="info-item-num" :startVal='0' :endVal='statisticsData.pageviews_count' :duration='3600'></countTo>
<span class="info-item-text">浏览量</span> <span class="info-item-text">浏览量</span>
<wscn-icon-svg icon-class="b" class="dashboard-editor-icon"/> <icon-svg icon-class="b" class="dashboard-editor-icon"></icon-svg>
</div>
<div class="info-item" :to="'/comment/commentslist?res_author_id='+uid">
<countTo class="info-item-num" ref='countTo3' :startVal='0' :endVal='statisticsData.comment_count' :duration='3800'></countTo>
<span class="info-item-text">评论</span>
<wscn-icon-svg icon-class="c" class="dashboard-editor-icon"/>
</div>
</div>
</div>
</div> </div>
</el-card>
</el-col>
<div class="btn-group"> <el-col :span="8">
<router-link class="pan-btn blue-btn" to="/components/index">组件</router-link> <pie-chart></pie-chart>
<router-link class="pan-btn light-blue-btn" to="/charts/index">图表</router-link> </el-col>
<router-link class="pan-btn red-btn" to="/errorpage/404">错误页面</router-link>
<router-link class="pan-btn pink-btn" to="/excel/download">导出excel</router-link> <el-col :span="10">
<router-link class="pan-btn green-btn" to="/example/table">table</router-link> <bar-chart></bar-chart>
<router-link class="pan-btn tiffany-btn" to="/example/form1">form</router-link> </el-col>
</div> </el-row>
<el-row :gutter="20">
<el-col :span="15">
<line-chart></line-chart>
</el-col>
<el-col :span="9">
<todo-list></todo-list>
</el-col>
</el-row>
<div class="clearfix main-dashboard-container">
<div class="chart-container">
<MonthKpi style="border-bottom: 1px solid #DEE1E2;"
:articlesComplete='statisticsData.month_article_count'></MonthKpi>
<ArticlesChart :listData='statisticsData.week_article'></ArticlesChart>
</div>
<div class="recent-articles-container">
<div class="recent-articles-title">最近撸了</div>
<div class="recent-articles-wrapper">
<template v-if="recentArticles.length!=0">
<div class="recent-articles-item" v-for="item in recentArticles">
<span class="recent-articles-status">{{item.status | statusFilter}}</span>
<span class="recent-articles-content" :to="'/article/edit/'+item.id">
{{item.title}}
</span>
<span class="recent-articles-time">{{item.author}}</span>
</div>
</template>
<template v-else>
<div class="recent-articles-emptyTitle">你太懒了最近都没有撸</div>
</template>
</div>
</div>
</div>
</div> </div>
</template> </template>
<script> <script>
import { mapGetters } from 'vuex'; import { mapGetters } from 'vuex';
import PanThumb from 'components/PanThumb'; import panThumb from 'components/PanThumb';
import MonthKpi from './monthKpi'; import pieChart from './pieChart';
import ArticlesChart from './articlesChart'; import barChart from './barChart';
import { getList } from 'api/article'; import lineChart from './lineChart';
import countTo from 'vue-count-to'; import countTo from 'vue-count-to';
import todoList from 'components/TodoList';
export default { export default {
name: 'dashboard-editor', name: 'dashboard-editor',
components: { PanThumb, MonthKpi, ArticlesChart, countTo }, components: { panThumb, countTo, pieChart, lineChart, barChart, todoList },
data() { data() {
return { return {
chart: null,
statisticsData: { statisticsData: {
article_count: 1024, article_count: 1024,
comment_count: 102400, comment_count: 102400,
latest_article: [], latest_article: [],
month_article_count: 28, month_article_count: 28,
pageviews_count: 1024, pageviews_count: 1024
week_article: [ }
{ count: 30, week: '201716' },
{ count: 26, week: '201715' },
{ count: 31, week: '201714' },
{ count: 28, week: '201713' },
{ count: 40, week: '201712' },
{ count: 41, week: '201711' },
{ count: 50, week: '201710' },
{ count: 42, week: '201709' },
{ count: 36, week: '201708' },
{ count: 32, week: '201707' },
{ count: 40, week: '201706' },
{ count: 41, week: '201705' }
]
},
list: []
} }
},
created() {
this.fetchData();
}, },
computed: { computed: {
...mapGetters([ ...mapGetters([
'name', 'name',
'avatar', 'avatar',
'email',
'uid',
'introduction',
'roles' 'roles'
]), ])
recentArticles() {
return this.list.slice(0, 7)
}
},
methods: {
fetchData() {
getList(this.listQuery).then(response => {
this.list = response.data;
})
}
},
filters: {
statusFilter(status) {
const statusMap = {
published: '已发布',
draft: '草稿中',
deleted: '已删除'
};
return statusMap[status];
}
} }
} }
</script> </script>
<style rel="stylesheet/scss" lang="scss" scoped> <style rel="stylesheet/scss" lang="scss" scoped>
.recent-articles-emptyTitle { .dashboard-editor-container {
font-size: 16px; margin: 30px;
color: #95A5A6; .btn-group {
padding-top: 20px; margin-bottom: 60px;
text-align: center;
} }
.box-card-header {
.dashboard-editor-container { position: relative;
padding: 30px 50px; height: 160px;
.pan-info-roles { }
font-size: 12px; .panThumb {
font-weight: 700; z-index: 100;
color: #333; height: 150px;
width: 150px;
position: absolute;
left: 0px;
right: 0px;
margin: auto;
}
.display_name{
font-size: 30px;
display: block; display: block;
} }
.info-container { .info-item{
position: relative;
margin-left: 190px;
height: 150px;
line-height: 200px;
.display_name {
font-size: 48px;
line-height: 48px;
color: #212121;
position: absolute;
top: 25px;
}
.info-wrapper {
line-height: 40px;
position: absolute;
bottom: 0px;
.info-item {
cursor: pointer;
display: inline-block; display: inline-block;
margin-right: 95px; margin-top: 10px;
.info-item-num {
color: #212121;
font-size: 24px;
display: inline-block;
padding-right: 5px;
}
.info-item-text {
color: #727272;
font-size: 14px; font-size: 14px;
padding-right: 5px; &:last-of-type{
display: inline-block; margin-left: 15px;
}
}
}
.dashboard-editor-icon {
width: 22px;
height: 22px;
}
}
.btn-group {
margin: 30px 36px 30px 0;
}
.main-dashboard-container {
width: 100%;
position: relative;
border: 1px solid #DEE1E2;
padding: 0 10px;
}
.chart-container {
float: left;
position: relative;
padding-right: 10px;
width: 40%;
border-right: 1px solid #DEE1E2;
}
.recent-articles-container {
padding: 12px 12px 0px;
float: left;
width: 60%;
position: relative;
.recent-articles- {
&title {
font-size: 16px;
color: #95A5A6;
letter-spacing: 1px;
padding-left: 15px;
padding-bottom: 10px;
border-bottom: 1px solid #DEE1E2;
}
&more {
color: #2C3E50;
font-size: 12px;
float: right;
margin-right: 25px;
line-height: 40px;
&:hover {
color: #3A71A8;
}
}
&wrapper {
padding: 0 20px 0 22px;
.recent-articles- {
&item {
cursor: pointer;
padding: 16px 100px 16px 16px;
border-bottom: 1px solid #DEE1E2;
position: relative;
&:before {
content: "";
height: 104%;
width: 0px;
background: #30B08F;
display: inline-block;
position: absolute;
opacity: 0;
left: 0px;
top: -2px;
transition: 0.3s ease all;
}
&:hover {
&:before {
opacity: 1;
width: 3px;
}
}
}
&status {
font-size: 12px;
display: inline-block;
color: #9B9B9B;
padding-right: 6px;
}
&content {
font-size: 13px;
color: #2C3E50;
&:hover {
color: #3A71A8;
}
}
&time {
position: absolute;
right: 16px;
top: 16px;
color: #9B9B9B;
}
}
}
}
} }
} }
}
</style> </style>

View File

@@ -0,0 +1,108 @@
<template>
<div :class="className" :style="{height:height,width:width}"></div>
</template>
<script>
import echarts from 'echarts';
require('echarts/theme/macarons'); // echarts 主题
import { debounce } from 'utils';
export default {
props: {
className: {
type: String,
default: 'chart'
},
width: {
type: String,
default: '100%'
},
height: {
type: String,
default: '300px'
},
autoResize: {
type: Boolean,
default: true
}
},
data() {
return {
chart: null
};
},
mounted() {
this.initChart();
if (this.autoResize) {
this.__resizeHanlder = debounce(() => {
this.chart.resize()
}, 100)
window.addEventListener('resize', this.__resizeHanlder)
}
},
beforeDestroy() {
if (!this.chart) {
return
}
if (this.autoResize) {
window.removeEventListener('resize', this.__resizeHanlder)
}
this.chart.dispose();
this.chart = null;
},
methods: {
initChart() {
this.chart = echarts.init(this.$el, 'macarons');
this.chart.setOption({
xAxis: {
data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],
boundaryGap: false
},
grid: {
left: 10,
right: 10,
bottom: 20,
containLabel: true
},
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'cross'
}
},
yAxis: {},
series: [{
name: 'visitors',
itemStyle: {
normal: {
areaStyle: {}
}
},
smooth: true,
type: 'line',
data: [100, 120, 161, 134, 105, 160, 165]
},
{
name: 'buyers',
smooth: true,
type: 'line',
itemStyle: {
normal: {
color: 'rgba(2, 197, 233, 0.2)',
lineStyle: {
color: 'rgba(2, 197, 233, 0.2)'
},
areaStyle: {
color: 'rgba(99,194,255, 0.6)'
}
}
},
data: [120, 82, 91, 154, 162, 140, 130]
}]
})
}
}
}
</script>

View File

@@ -1,61 +0,0 @@
<template>
<div class="monthKpi-container">
<span class="monthKpi-container-title">{{month}}</span>
<BarPercent class="monthKpi-container-chart" :dataNum='articlesComplete'></BarPercent>
<span class="monthKpi-container-text">文章完成比例</span>
<span class="monthKpi-container-count">{{articlesComplete}}<b></b></span>
</div>
</template>
<script>
import BarPercent from 'components/Charts/barPercent';
export default {
name: 'monthKpi',
components: { BarPercent },
props: {
articlesComplete: {
type: Number
}
},
data() {
return {
month: new Date().getMonth() + 1
}
}
}
</script>
<style rel="stylesheet/scss" lang="scss" scoped>
.monthKpi-container{
width: 100%;
}
.monthKpi-container-title {
color: #7F8C8D;
font-size: 16px;
display: inline-block;
margin-top: 10px;
}
.monthKpi-container-chart {
margin-left: 100px;
margin-bottom: 4px;
}
.monthKpi-container-text {
margin-left: 112px;
color: #9EA7B3;
font-size: 12px;
}
.monthKpi-container-count {
color: #30B08F;
font-size: 34px;
position: absolute;
left: 260px;
top: 60px;
b {
padding-left: 10px;
color: #9EA7B3;
font-size: 12px;
}
}
</style>

View File

@@ -0,0 +1,77 @@
<template>
<div :class="className" :style="{height:height,width:width}"></div>
</template>
<script>
import echarts from 'echarts';
require('echarts/theme/macarons'); // echarts 主题
export default {
props: {
className: {
type: String,
default: 'chart'
},
width: {
type: String,
default: '100%'
},
height: {
type: String,
default: '300px'
}
},
data() {
return {
chart: null
};
},
mounted() {
this.initChart();
},
beforeDestroy() {
if (!this.chart) {
return
}
this.chart.dispose();
this.chart = null;
},
methods: {
initChart() {
this.chart = echarts.init(this.$el, 'macarons');
this.chart.setOption({
title: {
text: 'WEEKLY WRITE ARTICLES',
x: 'center'
},
tooltip: {
trigger: 'item',
formatter: '{a} <br/>{b} : {c} ({d}%)'
},
legend: {
x: 'center',
y: 'bottom',
data: ['industries', 'technology', 'gold', 'forex', 'forecasts', 'markets']
},
calculable: true,
series: [
{
name: 'WEEKLY WRITE ARTICLES',
type: 'pie',
roseType: 'radius',
data: [
{ value: 320, name: 'industries' },
{ value: 240, name: 'technology' },
{ value: 149, name: 'forex' },
{ value: 100, name: 'gold' },
{ value: 59, name: 'forecastsx' },
{ value: 49, name: 'markets' }
]
}
]
})
}
}
}
</script>

View File

@@ -8,6 +8,7 @@
import { mapGetters } from 'vuex'; import { mapGetters } from 'vuex';
import EditorDashboard from './editor/index'; import EditorDashboard from './editor/index';
import DefaultDashboard from './default/index'; import DefaultDashboard from './default/index';
export default { export default {
name: 'dashboard', name: 'dashboard',
components: { EditorDashboard, DefaultDashboard }, components: { EditorDashboard, DefaultDashboard },
@@ -29,10 +30,6 @@
if (this.roles.indexOf('admin') >= 0) { if (this.roles.indexOf('admin') >= 0) {
return; return;
} }
// const isEditor = this.roles.some(v => v.indexOf('editor') >= 0)
// if (!isEditor) {
// this.currentRole = 'DefaultDashboard';
// }
this.currentRole = 'DefaultDashboard'; this.currentRole = 'DefaultDashboard';
} }
} }

View File

@@ -1,35 +1,25 @@
<template> <template>
<div class="errPage-container"> <div class="errPage-container">
<!--error code--> <err-code></err-code>
<err-code/>
<!--error code-->
<h3>请点击右上角bug小图表</h3> <h3>请点击右上角bug小图表</h3>
<code> <code>
现在的管理后台基本都是spa的形式了它增强了用户体验但同时也会怎增加页面出问题的可能性可能一个小小的疏忽就导致整个页面的死锁好在Vue官网提供了一个方法来捕获处理异常 现在的管理后台基本都是spa的形式了它增强了用户体验但同时也会怎增加页面出问题的可能性可能一个小小的疏忽就导致整个页面的死锁好在Vue官网提供了一个方法来捕获处理异常
</code> </code>
<a href="#"><img src='../../../documentImg/code1.png'></a> <a href="#"><img src='../../../documentImg/code1.png'></a>
</div> </div>
</template> </template>
<script> <script>
import errCode from './errcode'; import errCode from './errcode';
// import code1Img from
export default {
components: { errCode },
data() {
return {
} export default {
}, components: { errCode }
methods: {
back() {
this.$router.go(-1)
}
}
}; };
</script> </script>
<style scoped> <style scoped>
.errPage-container{ .errPage-container {
padding: 30px; padding: 30px;
} }
</style> </style>

View File

@@ -26,9 +26,9 @@
</el-dialog> </el-dialog>
</div> </div>
</template> </template>
<script>
import errGif from 'assets/401.gif';
<script>
import errGif from 'assets/401_images/401.gif';
export default { export default {
data() { data() {
return { return {
@@ -61,7 +61,7 @@
margin: 0 auto; margin: 0 auto;
display: block; display: block;
} }
.pan-img{ .pan-img {
display: block; display: block;
margin: 0 auto; margin: 0 auto;
} }

View File

@@ -2,10 +2,10 @@
<div style="background:#f0f2f5;margin-top: -20px;"> <div style="background:#f0f2f5;margin-top: -20px;">
<div class="wscn-http404"> <div class="wscn-http404">
<div class="pic-404"> <div class="pic-404">
<img class="pic-404__parent" src="../../assets/404.png" alt="404"> <img class="pic-404__parent" :src="img_404" alt="404">
<img class="pic-404__child left" src="../../assets/404_cloud.png" alt="404"> <img class="pic-404__child left" :src="img_404_cloud" alt="404">
<img class="pic-404__child mid" src="../../assets/404_cloud.png" alt="404"> <img class="pic-404__child mid" :src="img_404_cloud" alt="404">
<img class="pic-404__child right" src="../../assets/404_cloud.png" alt="404"> <img class="pic-404__child right" :src="img_404_cloud" alt="404">
</div> </div>
<div class="bullshit"> <div class="bullshit">
<div class="bullshit__oops">OOPS!</div> <div class="bullshit__oops">OOPS!</div>
@@ -17,8 +17,18 @@
</div> </div>
</div> </div>
</template> </template>
<script> <script>
import img_404 from '@/assets/404_images/404.png'
import img_404_cloud from '@/assets/404_images/404_cloud.png'
export default { export default {
data() {
return {
img_404,
img_404_cloud
}
},
computed: { computed: {
message() { message() {
return '特朗普说这个页面你不能进......' return '特朗普说这个页面你不能进......'
@@ -26,8 +36,9 @@
} }
} }
</script> </script>
<style rel="stylesheet/scss" lang="scss" scoped> <style rel="stylesheet/scss" lang="scss" scoped>
.wscn-http404 { .wscn-http404 {
position: relative; position: relative;
width: 1200px; width: 1200px;
margin: 20px auto 60px; margin: 20px auto 60px;
@@ -213,5 +224,6 @@
} }
} }
} }
} }
</style> </style>

View File

@@ -7,6 +7,9 @@
<div style="display:inline-block"> <div style="display:inline-block">
<el-dropdown trigger="click"> <el-dropdown trigger="click">
<router-link style="margin-right:15px;" v-show='isEdit' :to="{ path:'create'}">
<el-button type="info">创建form</el-button>
</router-link>
<el-button>{{!postForm.comment_disabled?'评论已打开':'评论已关闭'}}<i class="el-icon-caret-bottom el-icon--right"></i></el-button> <el-button>{{!postForm.comment_disabled?'评论已打开':'评论已关闭'}}<i class="el-icon-caret-bottom el-icon--right"></i></el-button>
<el-dropdown-menu class="no-padding no-hover" slot="dropdown"> <el-dropdown-menu class="no-padding no-hover" slot="dropdown">
<el-dropdown-item> <el-dropdown-item>
@@ -185,10 +188,16 @@
computed: { computed: {
contentShortLength() { contentShortLength() {
return this.postForm.content_short.length return this.postForm.content_short.length
},
isEdit() {
return this.$route.meta.isEdit // meta
// return this.$route.path.indexOf('edit') !== -1 //
} }
}, },
created() { created() {
if (this.isEdit) {
this.fetchData(); this.fetchData();
}
}, },
methods: { methods: {
fetchData() { fetchData() {

View File

@@ -0,0 +1,98 @@
<template>
<el-table :data="list" border fit highlight-current-row style="width: 100%">
<el-table-column align="center" label="序号" width="65">
<template scope="scope">
<span>{{scope.row.id}}</span>
</template>
</el-table-column>
<el-table-column width="180px" align="center" label="时间">
<template scope="scope">
<span>{{scope.row.timestamp | parseTime('{y}-{m}-{d} {h}:{i}')}}</span>
</template>
</el-table-column>
<el-table-column min-width="300px" label="标题">
<template scope="scope">
<span class="link-type" @click="handleUpdate(scope.row)">{{scope.row.title}}</span>
<el-tag>{{scope.row.type}}</el-tag>
</template>
</el-table-column>
<el-table-column width="110px" align="center" label="作者">
<template scope="scope">
<span>{{scope.row.author}}</span>
</template>
</el-table-column>
<el-table-column width="80px" label="重要性">
<template scope="scope">
<icon-svg v-for="n in +scope.row.importance" icon-class="wujiaoxing" class="meta-item__icon" :key="n"></icon-svg>
</template>
</el-table-column>
<el-table-column align="center" label="阅读数" width="95">
<template scope="scope">
<span>{{scope.row.pageviews}}</span>
</template>
</el-table-column>
<el-table-column class-name="status-col" label="状态" width="90">
<template scope="scope">
<el-tag :type="scope.row.status | statusFilter">{{scope.row.status}}</el-tag>
</template>
</el-table-column>
</el-table>
</template>
<script>
import { fetchList } from 'api/article_table';
export default {
name: 'articleDetail',
props: {
type: {
type: String,
default: 'CN'
}
},
data() {
return {
list: null,
total: null,
listQuery: {
page: 1,
limit: 5,
type: this.type,
sort: '+id'
}
}
},
filters: {
statusFilter(status) {
const statusMap = {
published: 'success',
draft: 'gray',
deleted: 'danger'
};
return statusMap[status]
}
},
created() {
this.getList();
},
methods: {
getList() {
this.$emit('create'); // for test
fetchList(this.listQuery).then(response => {
this.list = response.data.items;
this.total = response.data.total;
})
}
}
}
</script>

Some files were not shown because too many files have changed in this diff Show More