Compare commits

..

151 Commits

Author SHA1 Message Date
Pan
3a796471c3 refine settings 2019-03-26 11:43:37 +08:00
Pan
387b206199 update 2019-03-25 18:37:22 +08:00
Pan
b9fd5ae6d3 refine script and css 2019-03-25 17:57:14 +08:00
Pan
297959083c bump 2019-03-25 16:36:40 +08:00
Pan
5e3ae144b3 perf settings 2019-03-25 15:49:13 +08:00
Pan
c48777ff2d rm 2019-03-25 15:18:52 +08:00
Pan
3c0415c86d Merge branch 'v4.0' of https://github.com/PanJiaChen/vue-element-admin into v4.0 2019-03-25 15:16:13 +08:00
花裤衩
58a66d4902 feature: add sidebar logo (#1767) 2019-03-25 15:15:40 +08:00
Pan
960b562e84 update vue.config.js 2019-03-25 14:12:23 +08:00
Pan
ea0602a50f add comment 2019-03-25 10:42:30 +08:00
花裤衩
896b7369bf feature: add create template (#1762) 2019-03-22 18:22:14 +08:00
Pan
a9b4467472 perf[Eslint]: update eslint rules 2019-03-22 18:15:37 +08:00
Pan
74b6bb8069 fix chore 2019-03-22 18:06:42 +08:00
Pan
ec7c585813 fix style in mobile 2019-03-22 13:12:03 +08:00
Pan
d919acf64b feature: add fixedHeader settings 2019-03-21 16:38:41 +08:00
Yuga Sun
3594052c90 fix[Utils]: fixed deepClone error msg (#1748) 2019-03-21 15:50:19 +08:00
Pan
d1b786946c Merge branch 'master' into v4.0 2019-03-21 13:54:21 +08:00
MaYuanhai
59b1493579 perf[ThemePicker]: add predefine (#1743) 2019-03-21 11:27:25 +08:00
Pan
0c6e45e9a1 refactor permission 2019-03-21 10:58:44 +08:00
Pan
e1d61898ed rm 2019-03-20 16:20:11 +08:00
toruksmakto
fef9fda685 fix[Excel]: fixed export bug (#1736) 2019-03-20 16:19:38 +08:00
Pan
0c50029cf7 vuex add namespaced 2019-03-20 13:44:42 +08:00
Pan
7c33568883 tweak mock 2019-03-20 11:00:54 +08:00
Pan
d927d4172f refine code 2019-03-19 18:46:30 +08:00
Pan
fd4b5c4052 perf[Sticky]: refine demo 2019-03-19 18:07:54 +08:00
Mrli2016
a2b9b37c9c fix[Sticky]: fixed bug when set stickyTop 2019-03-19 18:07:43 +08:00
花裤衩
9665307220 fix[HeaderSearch]: fixed bug in vue2.6+ (#1733) 2019-03-19 18:07:28 +08:00
Pan
27322ac4d3 add ThemePicker to setting 2019-03-19 17:46:56 +08:00
Pan
6c6f03f664 merge 2019-03-18 18:33:17 +08:00
Pan
8b382e1e15 refine code 2019-03-18 18:07:55 +08:00
Pan
c93d88a348 fix[Excel]: fixed export merge-header excel bug 2019-03-18 15:56:43 +08:00
Pan
686d0acd6d tweak mock 2019-03-18 15:51:48 +08:00
Pan
05ca5cae6d add role mock 2019-03-18 12:32:23 +08:00
Pan
f3aefe54e8 refine theme color 2019-03-18 09:42:52 +08:00
Jere
a80999e0a2 lint 2019-03-17 21:07:56 +08:00
Pan
4b5b0a6e6b feature[Excel]: add export merge header excel demo 2019-03-17 21:06:12 +08:00
小新
3d973f7ddd feature[Excel]: support export merged header export (#1718) 2019-03-17 21:06:02 +08:00
Pan
b44335f012 feature[Permission]: add role permission management page (#1605) 2019-03-17 21:05:46 +08:00
Serge
f175427a61 fix bug 2019-03-17 19:36:48 +08:00
yuntao1997
183249a5d4 feature[Directive]: add auto-height table directive (#1702) 2019-03-15 18:31:32 +08:00
Yunfei
87272fd62d fix[utils]: fixed param2Obj not decoding plus sign (#1712) 2019-03-15 18:31:25 +08:00
Pan
b0e3dc8617 refine settings 2019-03-14 17:23:32 +08:00
花裤衩
e855f6a121 add settings (#1707) 2019-03-14 17:11:25 +08:00
Pan
537ecf9990 rm cli-plugin-eslint 2019-03-13 17:43:34 +08:00
Pan
dedf8e7ced update husky 2019-03-13 16:08:19 +08:00
裤裆三重奏
6c1c03c828 fix[Waves-Directive]: fixed v-waves does not support update (#1705) 2019-03-13 15:33:39 +08:00
Jesonhu
20fdb5cd8b fix[Tree-Table]: fixed update item data bug (#1692) 2019-03-13 15:29:58 +08:00
花裤衩
60b4549bf5 fix[Sidebar]: fixed collapse animation problem (#1690) 2019-03-13 15:29:50 +08:00
Pan
6b74a4ec72 docs: add link 2019-03-13 15:29:43 +08:00
花裤衩
1d3683a8c8 remove empty file 2019-03-13 15:29:36 +08:00
Pan
66e8ca9cec bump 2019-03-11 16:56:27 +08:00
Pan
653de1f31e update config 2019-03-11 16:29:59 +08:00
Pan
1dfea3b287 fix jest test case 2019-03-11 14:41:20 +08:00
Pan
2ac4cee805 adjust the layout to the src directory 2019-03-09 16:30:51 +08:00
Pan
94a3d7be7e lint code 2019-03-08 18:43:26 +08:00
Pan
3560fcacf9 set preserveWhitespace 2019-03-08 18:33:36 +08:00
Pan
8e0b5624a9 update version 2019-03-08 17:57:14 +08:00
Pan
44e4d3d005 fix[Sidebar]: fixed nested router hover bug 2019-03-08 17:35:01 +08:00
花裤衩
fef2853951 perf[Tree-Table]: organize the structure and add documentation (#1673) 2019-03-08 17:34:47 +08:00
liugq
f8f7667ab1 perf[Tree-Table]: refactor tree-table 2019-03-08 17:34:35 +08:00
Pan
5508f05132 merge master 2019-03-06 18:39:16 +08:00
花裤衩
cbc77c9a93 fix[DragTable]: support multiple drag-table (#1666) 2019-03-06 18:36:25 +08:00
花裤衩
583e96cca5 perf[TagsView]: set the scrollPane as a business component (#1660) 2019-03-06 18:36:00 +08:00
Pan
6d9ac37662 perf[TagsView]: refine code 2019-03-06 18:35:53 +08:00
MaYuanhai
9a5827ca8a perf[utils.js]: refactor byteLength function (#1650) 2019-03-06 18:35:46 +08:00
kaisawind
c44d001df6 fix[TagsView]: fixed refresh affixed-tag bug (#1653) 2019-03-06 18:35:39 +08:00
王洪莹
8029c076b9 perf[Sidebar]: optimize code logic (#1349) 2019-03-06 18:35:31 +08:00
Pan
d45e80549f fix[Sidebar]: data should return a object 2019-03-06 18:35:24 +08:00
frank10000
0bc681efe6 fix[Sidebar]: fixed infinite loop bug(#1333)
* fixed infinite loop Bug when in hasOneShowingChild Edit the onlyOneChild

* tweak
2019-03-06 18:35:18 +08:00
花裤衩
0f3d2bcd05 perf[ResizeHandler]: optimized the judgment of isMobile (#1633)
perf[ResizeHandler]: optimized the judgment of isMobile
2019-03-06 18:35:11 +08:00
WangXinhai
2d8a238880 perf[ThemePicker]: refine updateStyle function (#554)
* theme replacing should cut tons of irrelevant css
2019-03-06 18:35:02 +08:00
花裤衩
30d4d85b34 perf[Navbar]: add scroll bar when the subMenu is too long (#1619) 2019-03-06 18:34:54 +08:00
Pan
5224a00ddc perf[utils]: optimizate variable name 2019-03-06 18:34:42 +08:00
Pan
054e9c4a73 perf[utils]: optimize code 2019-03-06 18:32:34 +08:00
花裤衩
041075633f fearure[TagsView]: add affix option (#1577) 2019-03-06 18:32:27 +08:00
Pan
d955fe8b0f fix typo 2019-03-06 18:32:10 +08:00
花裤衩
e0991da9cf fix[Screenfull]: fix screenfull bug (#1603) 2019-03-06 18:32:01 +08:00
Pan
a9fd6e2919 perf[Screenfull]: refactor screenfull component 2019-02-14 16:30:26 +08:00
Pan
3cba7b52da fix[Screenfull]: fix screenfull click bug 2019-02-14 16:29:05 +08:00
花裤衩
32b747014d feature[Navbar]: add header-search component(#1591) 2019-02-14 16:28:54 +08:00
Pan
8e047596b1 perf[Login]: refine css 2019-02-14 16:27:39 +08:00
Pan
172d6a1d08 perf[Navbar]: refactor navbar style 2019-02-14 16:27:30 +08:00
Pan
abc8ce21f4 perf: optimize some code 2019-02-14 16:27:17 +08:00
Pan
e574ca0331 perf[Lang]: make up for miss keywords 2019-02-14 16:27:05 +08:00
Pan
1e5d2c0ed2 perf: fixed eslint errors 2019-02-14 16:26:47 +08:00
花裤衩
56bd080b54 fix[SIdebar]: fixed bug in mobile #1567 (#1569) 2019-01-30 14:08:55 +08:00
花裤衩
87f1bbdb7b perf[SizeSelect]: add default size option (#1566) 2019-01-30 14:08:48 +08:00
花裤衩
bea356ac70 perf[Style]: optimize the sidebar style to make it better to set (#1568) 2019-01-30 14:08:42 +08:00
Pan
ce35a6f744 perf[Sidebar]: use sass variables in vue template 2019-01-30 14:08:22 +08:00
Pan
6363eb627d perf: adjust the import order to make it more elegant #1537 2019-01-30 14:08:10 +08:00
花裤衩
0f6946a88e perf[UploadExcel]: optimized code (#1552) 2019-01-30 14:07:34 +08:00
xbigcat
22cdfc246c perf[utils]: refine parseTime function (#1546)
* 优化 parseTime

修复传入的时间戳是字符串类型,不能转换时间的问题
例:parseTime("1548221490638")

* Update index.js
2019-01-30 14:07:26 +08:00
Pan
2d275a9891 perf[Sticky]: refine width default value 2019-01-30 14:07:18 +08:00
花裤衩
93c13d2cea perf[Sticky]: export reset method (#1550) 2019-01-30 14:07:08 +08:00
Yuga Sun
78e8888389 perf[Login Form]: optimize eye icon style (#1545)
* optimiz: eye icon style for login form

* change eye-open svg
2019-01-30 14:06:57 +08:00
Jiankian
bb50a7422d pref[Hamburger]: refactor Hamburger component (#1528)
* 美化侧栏菜单切换按钮

* tweak
2019-01-17 11:36:43 +08:00
花裤衩
4afb57a1e5 fix[DndList]: fixed drag bug (#1527)
https://github.com/PanJiaChen/vue-element-admin/issues/1524
2019-01-17 11:36:23 +08:00
花裤衩
3af14bc297 fix[Breadcrumb]: fixed eslint error (#1521) 2019-01-17 11:36:14 +08:00
Pan
0bf8b5960d update README.md 2019-01-17 11:36:02 +08:00
花裤衩
bae3601606 fix[ThemePicker]: fixed bug when oldVal is null (#1517) 2019-01-17 11:35:51 +08:00
Pan
77113a0cb2 tweak 2019-01-11 15:44:03 +08:00
Duy Nguyen Hoang
1cd1ef690c perf: add sidebar width to variables.scss (#1494) 2019-01-11 15:43:44 +08:00
Nikita Sobolev
4e9f08e639 fix typo (#1505) 2019-01-11 15:36:06 +08:00
Pan
94ed283c51 refine: GetUserInfo error message 2019-01-11 15:35:54 +08:00
花裤衩
67c06022e1 perf[Sidebar]: refine sidebar store #1473 (#1474) 2019-01-11 15:35:07 +08:00
Pan
d3904e6c28 perf[v-permission]: refine v-permission demo 2018-12-27 18:20:42 +08:00
花裤衩
5a1fa14753 feature[PDF]: add PDF demo (#1469) 2018-12-27 18:20:26 +08:00
董雨
cff015f5d6 perf[ScrollPane]: refine moveToTarget code (#1460) 2018-12-27 18:20:11 +08:00
Pan
3a2da6afd3 refactor[login]: refactor login page style 2018-12-24 17:51:24 +08:00
Pan
a92151d048 perf: use WeChat 7.0 new version icon color 2018-12-24 16:24:25 +08:00
Pan
9ce0f81d5f feat[Breadcrumb]: add hide Breadcrumb option #1442 2018-12-24 11:21:28 +08:00
Pan
49f1e5e6dc fix[Tinymce]: fixed fullScreen bug #1400 2018-12-04 18:23:16 +08:00
Pan
b8b787733c update guide page 2018-12-04 18:23:05 +08:00
Pan
075d29acea fix return back bug 2018-11-29 18:17:30 +08:00
Pan
84b19d7283 add preview 2018-11-28 18:11:18 +08:00
Pan
2f731000c1 tweak 2018-11-28 14:57:26 +08:00
花裤衩
a6c8e1a11a add tui.editor (#1374) 2018-11-28 11:05:41 +08:00
Pan
929a4fc0c8 update dependence 2018-11-27 16:30:21 +08:00
Heedong Im
8836133f66 fix[Pagination]: apply PageSizes property to el-pagination (#1355)
Apply PageSizes property to el-pagination
2018-11-26 18:18:32 +08:00
Pan
5849b13d3f update vue-router to fixed url path for non ascii urls #1362 2018-11-26 17:53:06 +08:00
Pan
5f343ec9e4 fix import path bug 2018-11-21 13:14:43 +08:00
Pan
05b28e20bd add sponsors 2018-11-21 12:38:23 +08:00
Pan
8cb6983550 perf[style]: use webpack alias instead of hard code src path 2018-11-19 12:47:47 +08:00
samuelchlui
f0f8363cf7 perf[style]: use webpack alias instead of hard code src path (#1338) 2018-11-19 12:45:56 +08:00
Pan
6f5591c290 fix[Breadcurmb]: fixed router-link bug 2018-11-09 17:59:34 +08:00
Pan
5c23accd9e fix[Breadcurmb]: fixed pathCompile bug 2018-11-09 13:37:23 +08:00
Pan
14ece5ba9b fix link 2018-11-09 09:51:29 +08:00
Pan
cfdff383db perf[DragSelect]: add $listeners 2018-11-08 17:30:33 +08:00
Pan
8921752441 fix[DragSelect]: fixed querySelectorAll bug 2018-11-08 17:19:12 +08:00
Pan
8e5b142c36 refine css 2018-11-06 16:22:20 +08:00
jaysunxiao
4b916c8e4d perf[avatar]:minimize the selected area of avatar on the mobile phone when user clicked avatar (#1304) 2018-11-06 16:13:37 +08:00
Pan
889771fa7a perf[Tinymce]: add searchreplace plugin 2018-11-02 15:10:15 +08:00
LarchLiu
21516170a9 fix[Charts]: fixed charts resize mixins bug #1285 (#1290) 2018-11-02 15:07:39 +08:00
Pan
da286d4439 fix bug 2018-11-01 10:41:19 +08:00
Pan
51f99770fe add test 2018-10-29 15:29:54 +08:00
Pan
aefd8bb36a update 2018-10-29 15:02:06 +08:00
zthxxx
40a7626acb feat: perfect migrate to @vue/cli-service, upgrade vue babel version (#1267)
* feat: perfect migrate to @vue/cli-service, upgrade vue babel version

1. update to @vue/cli-service@3.0.5, @babel/core@7.0.0
2. use vue-cli service replace config file in build/ and config/
3. upgrade vue and babel configuration
4. solve the svg-sprite config problem #980

refs: #932 #1087  #980 #1056

* fix: fix breadcrumb dependency

* fix: fix index template and static assets load with vue-cli 3

* fix: fix import driver.js in guide page

* refactor(mock): mak mock api compatible with both web-view and webpack server

1. 把 Mockjs 功能移到 server 端中间件,同时也兼容前端直接劫持 XHR
2. dev 环境下默认作为 express 中间件通过 webpack server 提供 mock api
3. prod 构建时,默认在前端用 Mockjs 劫持 XHR

benefits:
  - dev 开发调试时能直接看到 XHR 请求,方便调试网络,能和后端对接联调
  - 避开在开发时因为 Mockjs 引起的网络 bug
  - prod 构建时劫持 XHR,保证本项目的 Github Pages preview 能正常显示 (逻辑和 error-log 一样)
  - 前后台使用的 mock 是同一份代码,不会增加维护负担

ref: [#562](https://github.com/PanJiaChen/vue-element-admin/issues/562#issuecomment-378116233)

* update requires the lowest version of node

* add favicon

* fix(TreeTable): fix `Array.prototype.concat` on custom-tree-table page
2018-10-29 13:55:36 +08:00
Pan
6c967f177a Merge branch 'master' into v4.0 2018-10-26 10:46:43 +08:00
花裤衩
c042dc8de3 feature: add drag select component (#1249) 2018-10-24 18:34:45 +08:00
花裤衩
f79d0febb1 add an example of sort data by table (#1236) 2018-10-24 18:34:45 +08:00
Pan
10031547ec chore: restore the hack of cssnano bug
https://github.com/cssnano/cssnano/issues/643
2018-10-24 18:34:45 +08:00
Pan
ccc90502ce [release] 3.9.2 2018-10-24 18:34:45 +08:00
Pan
6f0c40e841 chore: temporary hack cssnano bug #1222 2018-10-24 18:34:45 +08:00
花裤衩
2ba5f25205 fix[TagsView]: fixed update tags title demo bug (#1223) 2018-10-24 18:34:45 +08:00
花裤衩
b9eedb8689 feature: add pagination component (#1213) 2018-10-24 18:34:45 +08:00
Pan
a67b455306 fix[tagsView]: fixed moveToCurrentTag bug 2018-10-24 18:34:45 +08:00
frank10000
27772946c2 perf[tagsView]: refactor the moveToTarget function (#1195)
* fix[tagsView]:fixed visited view move to currentTag

* edit the scroll regular friendly

* tweak
2018-10-24 18:34:45 +08:00
Pan
4cdcbee0d6 update readme 2018-10-24 18:34:45 +08:00
CNine
97261a2feb fix[MockJS]: fix bug with withCredentials after using mockjs (#1194)
* 修复 Mock 导致请求丢失 Cookie 的问题

修复 Mock 导致 Cookie 丢失的问题,只有在 XHR.open() 周期时,自定义的 withCredentials 会被挂载,此时检查是否是未被拦截的 xhr,并挂载自定义的 withCredentials ,无则默认为 false
2018-10-24 18:34:45 +08:00
Ramón Menor
0f7cf7e820 feature: support Spanish(#1196) 2018-10-24 18:34:45 +08:00
Pan
3802f6f8d2 fix[ExternalLink]: fixed bug when url include chinese #1182 2018-10-24 18:34:45 +08:00
81 changed files with 1364 additions and 721 deletions

View File

@@ -1,14 +1,9 @@
# just a flag
VUE_APP_BASE_API = '/api'
ENV = 'development'
# base api
VUE_APP_BASE_API = '/dev-api'
# vue-cli uses the VUE_CLI_BABEL_TRANSPILE_MODULES environment variable,
# to control whether the babel-plugin-dynamic-import-node plugin is enabled.
# It only does one thing by converting all import() to require().
# This configuration can significantly increase the speed of hot updates,
# when you have a large number of pages.
# Detail: https://github.com/vuejs/vue-cli/blob/dev/packages/@vue/babel-preset-app/index.js
// With this configuration, vue-cli uses babel-plugin-dynamic-import-node
// It only does one thing by converting all import() to require()
// So that all asynchronous components can be import synchronously using this plugin
// This configuration can significantly increase the speed of hot updates when you have a large number of pages
// https://github.com/vuejs/vue-cli/blob/dev/packages/@vue/babel-preset-app/index.js
VUE_CLI_BABEL_TRANSPILE_MODULES = true

View File

@@ -1,6 +1,2 @@
# just a flag
VUE_APP_BASE_API = '/api'
ENV = 'production'
# base api
VUE_APP_BASE_API = '/prod-api'

View File

@@ -1,8 +1,3 @@
NODE_ENV = production
# just a flag
NODE_ENV=production
VUE_APP_BASE_API = '/api'
ENV = 'staging'
# base api
VUE_APP_BASE_API = '/stage-api'

View File

@@ -1,4 +1,3 @@
build/*.js
config/*.js
src/assets
public
dist

View File

@@ -1,33 +0,0 @@
---
name: Bug report报告问题
about: Create a report to help us improve
---
<!--
注意:为更好的解决你的问题,请参考模板提供完整信息,准确描述问题,信息不全的 issue 将被关闭。
Note: In order to better solve your problem, please refer to the template to provide complete information, accurately describe the problem, and the incomplete information issue will be closed.
-->
## Bug report问题描述
#### Steps to reproduce问题复现步骤
<!--
1. [xxx]
2. [xxx]
3. [xxxx]
-->
#### Screenshot or Gif截图或动态图
#### Link to minimal reproduction最小可在线还原demo
<!--
Please only use Codepen, JSFiddle, CodeSandbox or a github repo
-->
#### Other relevant information格外信息
- Your OS:
- Node.js version:
- vue-element-admin version:

View File

@@ -1,7 +0,0 @@
---
name: Feature Request新功能建议
about: Suggest an idea for this project
---
## Feature request新功能建议

View File

@@ -1,14 +0,0 @@
---
name: Question提问
about: Asking questions about use
---
## Question提问
<!--
提问之前,请确定你已经过自己的努力,尝试解决过这个问题。
若是代码相关问题,请不要只截图,请提供在线 demo以便节约彼此的时间。
Before asking a question, please make sure that you have tried your best to solve this problem.
If it's a code-related issue, please don't just take screenshots. Please provide an online demo to save each other's time.
-->

View File

@@ -4,10 +4,10 @@
<p align="center">
<a href="https://github.com/vuejs/vue">
<img src="https://img.shields.io/badge/vue-2.6.10-brightgreen.svg" alt="vue">
<img src="https://img.shields.io/badge/vue-2.5.17-brightgreen.svg" alt="vue">
</a>
<a href="https://github.com/ElemeFE/element">
<img src="https://img.shields.io/badge/element--ui-2.7.0-brightgreen.svg" alt="element-ui">
<img src="https://img.shields.io/badge/element--ui-2.4.11-brightgreen.svg" alt="element-ui">
</a>
<a href="https://travis-ci.org/PanJiaChen/vue-element-admin" rel="nofollow">
<img src="https://travis-ci.org/PanJiaChen/vue-element-admin.svg?branch=master" alt="Build Status">
@@ -30,7 +30,7 @@ English | [简体中文](./README.zh-CN.md)
## Introduction
[vue-element-admin](http://panjiachen.github.io/vue-element-admin) is a production-ready front-end solution for admin interfaces. It based on [vue](https://github.com/vuejs/vue) and use the UI Toolkit [element-ui](https://github.com/ElemeFE/element).
[vue-element-admin](http://panjiachen.github.io/vue-element-admin) is a front-end management background integration solution. It based on [vue](https://github.com/vuejs/vue) and use the UI Toolkit [element](https://github.com/ElemeFE/element).
It is a magical vue admin based on the newest development stack of vue, built-in i18n solution, typical templates for enterprise applications, lots of awesome features. It helps you build a large complex Single-Page Applications. I believe whatever your needs are, this project will help you.
@@ -40,31 +40,36 @@ It is a magical vue admin based on the newest development stack of vue, built-in
- [Gitter](https://gitter.im/vue-element-admin/discuss)
- [Donate](https://panjiachen.github.io/vue-element-admin-site/donate/)
- [Wiki](https://github.com/PanJiaChen/vue-element-admin/wiki)
- [Donate](https://panjiachen.github.io/vue-element-admin-site/donate/)
- [Gitee](https://panjiachen.gitee.io/vue-element-admin/) 国内用户可访问该地址在线预览
**This project is positioned as a background integration solution and is not suitable for secondary development as a basic template.**
- Base template recommends using: [vue-admin-template](https://github.com/PanJiaChen/vue-admin-template)
- Desktop: [electron-vue-admin](https://github.com/PanJiaChen/electron-vue-admin)
- Typescript: [vue-typescript-admin-template](https://github.com/Armour/vue-typescript-admin-template) (Credits: [@Armour](https://github.com/Armour))
**The current version is `4.0-beta`. If you find a problem, please put [issue](https://github.com/PanJiaChen/vue-element-admin/issues/new). If you want to use the old version - stable version, you can switch branch to [tag/3.11.0](https://github.com/PanJiaChen/vue-element-admin/tree/tag/3.11.0)**
**This project does not support low version browsers (e.g. IE). Please add polyfill yourself if you need them.**
**This project does not support low version browsers (e.g. IE). Please add polyfill by yourself.**
**Note: This project uses element-ui@2.3.0+ version, so the minimum compatible vue@2.5.0+**
**Start using `webpack4` from `v3.8.0`. If you still want to continue using `webpack3`, please use this branch [webpack3](https://github.com/PanJiaChen/vue-element-admin/tree/webpack3)**
## Preparation
You need to install [node](http://nodejs.org/) and [git](https://git-scm.com/) locally. The project is based on [ES2015+](http://es6.ruanyifeng.com/), [vue](https://cn.vuejs.org/index.html), [vuex](https://vuex.vuejs.org/zh-cn/), [vue-router](https://router.vuejs.org/zh-cn/), [vue-cli](https://github.com/vuejs/vue-cli) , [axios](https://github.com/axios/axios) and [element-ui](https://github.com/ElemeFE/element), all request data is simulated using [Mock.js](https://github.com/nuysoft/Mock).
You need to install [node](http://nodejs.org/) and [git](https://git-scm.com/) locally. The project is based on [ES2015+](http://es6.ruanyifeng.com/), [vue](https://cn.vuejs.org/index.html), [vuex](https://vuex.vuejs.org/zh-cn/), [vue-router](https://router.vuejs.org/zh-cn/), [axios](https://github.com/axios/axios) and [element-ui](https://github.com/ElemeFE/element), all request data is simulated using [Mock.js](https://github.com/nuysoft/Mock).
Understanding and learning this knowledge in advance will greatly help the use of this project.
---
<p align="center">
<img width="900" src="https://wpimg.wallstcn.com/a5894c1b-f6af-456e-82df-1151da0839bf.png">
</p>
## Sponsors
Become a sponsor and get your logo on our README on GitHub with a link to your site. [[Become a sponsor]](https://www.patreon.com/panjiachen)
<a href="https://flatlogic.com/admin-dashboards?from=vue-element-admin"><img width="150px" src="https://wpimg.wallstcn.com/9c0b719b-5551-4c1e-b776-63994632d94a.png" /></a><p>Admin Dashboard Templates made with Vue, React and Angular.</p>
@@ -77,7 +82,6 @@ Become a sponsor and get your logo on our README on GitHub with a link to your s
- Permission Authentication
- Page permission
- Directive permission
- Permission configuration page
- Two-step login
- Multi-environment build
@@ -101,13 +105,14 @@ Become a sponsor and get your logo on our README on GitHub with a link to your s
- Excel
- Export Excel
- Export zip
- Upload Excel
- Visualization Excel
- Export zip
- Table
- Dynamic Table
- Drag And Drop Table
- Tree Table
- Inline Edit Table
- Error Page
@@ -141,9 +146,6 @@ Become a sponsor and get your logo on our README on GitHub with a link to your s
# clone the project
git clone https://github.com/PanJiaChen/vue-element-admin.git
# enter the project directory
cd vue-element-admin
# install dependency
npm install
@@ -151,13 +153,13 @@ npm install
npm run dev
```
This will automatically open http://localhost:9527
This will automatically open http://localhost:9527.
## Build
```bash
# build for test environment
npm run build:stage
npm run build:sit
# build for production environment
npm run build:prod
@@ -166,16 +168,19 @@ npm run build:prod
## Advanced
```bash
# preview the release environment effect
npm run preview
# --report to build with bundle size analytics
npm run build:prod --report
# preview the release environment effect + static resource analysis
npm run preview -- --report
# --generate a bundle size analytics. default: bundle-report.html
npm run build:prod --generate_report
# code format check
# --preview to start a server in local to preview
npm run build:prod --preview
# lint code
npm run lint
# code format check and auto fix
# auto fix
npm run lint -- --fix
```

View File

@@ -4,10 +4,10 @@
<p align="center">
<a href="https://github.com/vuejs/vue">
<img src="https://img.shields.io/badge/vue-2.6.10-brightgreen.svg" alt="vue">
<img src="https://img.shields.io/badge/vue-2.5.10-brightgreen.svg" alt="vue">
</a>
<a href="https://github.com/ElemeFE/element">
<img src="https://img.shields.io/badge/element--ui-2.7.0-brightgreen.svg" alt="element-ui">
<img src="https://img.shields.io/badge/element--ui-2.4.11-brightgreen.svg" alt="element-ui">
</a>
<a href="https://travis-ci.org/PanJiaChen/vue-element-admin" rel="nofollow">
<img src="https://travis-ci.org/PanJiaChen/vue-element-admin.svg?branch=master" alt="Build Status">
@@ -30,37 +30,41 @@
## 简介
[vue-element-admin](http://panjiachen.github.io/vue-element-admin) 是一个后台前端解决方案,它基于 [vue](https://github.com/vuejs/vue) 和 [element-ui](https://github.com/ElemeFE/element)实现。它使用了最新的前端技术栈,内置了 i18n 国际化解决方案,动态路由,权限验证,提炼了典型的业务模型,提供了丰富的功能组件,它可以帮助你快速搭建企业级中后台产品原型。相信不管你的需求是什么,本项目都能帮助到你。
[vue-element-admin](http://panjiachen.github.io/vue-element-admin) 是一个后台集成解决方案,它基于 [vue](https://github.com/vuejs/vue) 和 [element](https://github.com/ElemeFE/element)。它使用了最新的前端技术栈,内置了 i18 国际化解决方案,动态路由,权限验证,提炼了典型的业务模型,提供了丰富的功能组件,它可以帮助你快速搭建企业级中后台产品原型。相信不管你的需求是什么,本项目都能帮助到你。
- [在线预览](http://panjiachen.github.io/vue-element-admin)
- [在线访问](http://panjiachen.github.io/vue-element-admin)
- [使用文档](https://panjiachen.github.io/vue-element-admin-site/zh/)
- [Gitter 讨论组](https://gitter.im/vue-element-admin/discuss)
- [Donate](https://panjiachen.gitee.io/vue-element-admin-site/zh/donate)
- [Wiki](https://github.com/PanJiaChen/vue-element-admin/wiki)
- [Gitee](https://panjiachen.gitee.io/vue-element-admin/) 在线预览(国内用户可访问该地址)
- [Donate](https://panjiachen.gitee.io/vue-element-admin-site/zh/donate)
- [国内访问文档](https://panjiachen.gitee.io/vue-element-admin-site/zh/) 文档(方便没翻墙的用户查看)
- [Gitee](https://panjiachen.gitee.io/vue-element-admin/) 国内用户可访问该地址在线预览
- 基础模板建议使用: [vue-admin-template](https://github.com/PanJiaChen/vue-admin-template)
- [国内访问文档](https://panjiachen.gitee.io/vue-element-admin-site/zh/) 方便没翻墙的用户查看文档
**本项目的定位是后台集成方案,不适合当基础模板来开发。**
- 模板建议使用: [vue-admin-template](https://github.com/PanJiaChen/vue-admin-template)
- 桌面端: [electron-vue-admin](https://github.com/PanJiaChen/electron-vue-admin)
- Typescript 版: [vue-typescript-admin-template](https://github.com/Armour/vue-typescript-admin-template) (鸣谢: [@Armour](https://github.com/Armour))
- Typescript版: [vue-typescript-admin-template](https://github.com/Armour/vue-typescript-admin-template) (鸣谢: [@Armour](https://github.com/Armour))
**目前版本为 `4.0-beta`,若发现问题,欢迎提[issue](https://github.com/PanJiaChen/vue-element-admin/issues/new)。若你想使用旧版本-稳定版,可以切换分支到[tag/3.11.0](https://github.com/PanJiaChen/vue-element-admin/tree/tag/3.11.0)**
群主 **[圈子](https://jianshiapp.com/circles/1209)** 楼主会经常分享一些技术相关的东西,或者加入[qq 群](https://github.com/PanJiaChen/vue-element-admin/issues/602)
**注意:该项目使用 element-ui@2.3.0+ 版本,所以最低兼容 vue@2.5.0+**
**从`v3.8.0`开始使用`webpack4`。所以若还想使用`webpack3`开发,请使用该分支[webpack3](https://github.com/PanJiaChen/vue-element-admin/tree/webpack3)**
**该项目不支持低版本浏览器(如 ie),有需求请自行添加 polyfill [详情](https://github.com/PanJiaChen/vue-element-admin/wiki#babel-polyfill)**
群主 **[圈子](https://jianshiapp.com/circles/1209)** 群主会经常分享一些技术相关的东西,或者加入 [qq 群](https://github.com/PanJiaChen/vue-element-admin/issues/602) 或者关注 [微博](https://weibo.com/u/3423485724?is_all=1)
## 前序准备
你需要在本地安装 [node](http://nodejs.org/) 和 [git](https://git-scm.com/)。本项目技术栈基于 [ES2015+](http://es6.ruanyifeng.com/)、[vue](https://cn.vuejs.org/index.html)、[vuex](https://vuex.vuejs.org/zh-cn/)、[vue-router](https://router.vuejs.org/zh-cn/) 、[vue-cli](https://github.com/vuejs/vue-cli) 、[axios](https://github.com/axios/axios) 和 [element-ui](https://github.com/ElemeFE/element),所有的请求数据都使用[Mock.js](https://github.com/nuysoft/Mock)进行模拟,提前了解和学习这些知识会对使用本项目有很大的帮助。
你需要在本地安装 [node](http://nodejs.org/) 和 [git](https://git-scm.com/)。本项目技术栈基于 [ES2015+](http://es6.ruanyifeng.com/)、[vue](https://cn.vuejs.org/index.html)、[vuex](https://vuex.vuejs.org/zh-cn/)、[vue-router](https://router.vuejs.org/zh-cn/) 、[axios](https://github.com/axios/axios) 和 [element-ui](https://github.com/ElemeFE/element),所有的请求数据都使用[Mock.js](https://github.com/nuysoft/Mock)模拟,提前了解和学习这些知识会对使用本项目有很大的帮助。
同时配套系列教程文章,如何从零构建后一个完整的后台项目,建议大家先看完这些文章再来实践本项目
同时配套一个系列教程文章,如何从零构建后一个完整的后台项目,建议大家先看完这些文章再来实践本项目
- [手摸手,带你用 vue 撸后台 系列一(基础篇)](https://juejin.im/post/59097cd7a22b9d0065fb61d2)
- [手摸手,带你用 vue 撸后台 系列二(登录权限篇)](https://juejin.im/post/591aa14f570c35006961acac)
@@ -78,7 +82,6 @@
</p>
## Sponsors
Become a sponsor and get your logo on our README on GitHub with a link to your site. [[Become a sponsor]](https://www.patreon.com/panjiachen)
<a href="https://flatlogic.com/admin-dashboards?from=vue-element-admin"><img width="150px" src="https://wpimg.wallstcn.com/9c0b719b-5551-4c1e-b776-63994632d94a.png" /></a><p>Admin Dashboard Templates made with Vue, React and Angular.</p>
@@ -91,7 +94,6 @@ Become a sponsor and get your logo on our README on GitHub with a link to your s
- 权限验证
- 页面权限
- 指令权限
- 权限配置
- 二步登录
- 多环境发布
@@ -104,7 +106,7 @@ Become a sponsor and get your logo on our README on GitHub with a link to your s
- 动态面包屑
- 快捷导航(标签页)
- Svg Sprite 图标
- 本地/后端 mock 数据
- 本地mock数据
- Screenfull全屏
- 自适应收缩侧边栏
@@ -115,13 +117,14 @@ Become a sponsor and get your logo on our README on GitHub with a link to your s
- Excel
- 导出excel
- 导出zip
- 导入excel
- 前端可视化excel
- 导出zip
- 表格
- 动态表格
- 拖拽表格
- 树形表格
- 内联编辑
- 错误页面
@@ -155,9 +158,6 @@ Become a sponsor and get your logo on our README on GitHub with a link to your s
# 克隆项目
git clone https://github.com/PanJiaChen/vue-element-admin.git
# 进入项目目录
cd vue-element-admin
# 安装依赖
npm install
@@ -174,7 +174,7 @@ npm run dev
```bash
# 构建测试环境
npm run build:stage
npm run build:sit
# 构建生产环境
npm run build:prod
@@ -183,16 +183,19 @@ npm run build:prod
## 其它
```bash
# 预览发布环境效果
npm run preview
# --report to build with bundle size analytics
npm run build:prod
# 预览发布环境效果 + 静态资源分析
npm run preview -- --report
# --generate a bundle size analytics. default: bundle-report.html
npm run build:prod --generate_report
# 代码格式检查
# --preview to start a server in local to preview
npm run build:prod --preview
# lint code
npm run lint
# 代码格式检查并自动修复
# auto fix
npm run lint -- --fix
```
@@ -215,8 +218,6 @@ Detailed changes for each release are documented in the [release notes](https://
[Paypal Me](https://www.paypal.me/panfree23)
[Buy me a coffee](https://www.buymeacoffee.com/Pan)
## Browsers support
Modern browsers and Internet Explorer 10+.

View File

@@ -5,9 +5,7 @@ const rawArgv = process.argv.slice(2)
const args = rawArgv.join(' ')
if (process.env.npm_config_preview || rawArgv.includes('--preview')) {
const report = rawArgv.includes('--report')
run(`vue-cli-service build ${args}`)
run(`vue-cli-service build ${args} --report`)
const port = 9526
const publicPath = config.publicPath
@@ -23,12 +21,13 @@ if (process.env.npm_config_preview || rawArgv.includes('--preview')) {
})
)
app.listen(port, function () {
console.log(chalk.green(`> Preview at http://localhost:${port}${publicPath}`))
if (report) {
console.log(chalk.green(`> Report at http://localhost:${port}${publicPath}report.html`))
}
app.listen(port, function() {
console.log(
chalk.green(`> Preview at http://localhost:${port}${publicPath}`)
)
console.log(
chalk.green(`> Report at http://localhost:${port}${publicPath}/report.html`)
)
})
} else {
run(`vue-cli-service build ${args}`)

View File

@@ -1,9 +1,9 @@
module.exports = {
verbose: true,
moduleFileExtensions: ['js', 'jsx', 'json', 'vue'],
transformIgnorePatterns: [
'node_modules/(?!(babel-jest|jest-vue-preprocessor)/)'
],
// transformIgnorePatterns: [
// 'node_modules/(?!(babel-jest|jest-vue-preprocessor)/)'
// ],
transform: {
'^.+\\.vue$': 'vue-jest',
'.+\\.(css|styl|less|sass|scss|svg|png|jpg|ttf|woff|woff2)$': 'jest-transform-stub',

View File

@@ -1,32 +1,16 @@
import Mock from 'mockjs'
import mocks from './mocks'
import { param2Obj } from '../src/utils'
import user from './user'
import role from './role'
import article from './article'
import search from './remoteSearch'
const MOCK_API_BASE = '/mock'
const mocks = [
...user,
...role,
...article,
...search
]
// for front mock
// please use it cautiously, it will redefine XMLHttpRequest,
// which will cause many of your third-party libraries to be invalidated(like progress event).
export function mockXHR() {
// mock patch
// 修复在使用 MockJS 情况下,设置 withCredentials = true且未被拦截的跨域请求丢失 Cookies 的问题
// https://github.com/nuysoft/Mock/issues/300
Mock.XHR.prototype.proxy_send = Mock.XHR.prototype.send
Mock.XHR.prototype.send = function() {
if (this.custom.xhr) {
this.custom.xhr.withCredentials = this.withCredentials || false
if (this.responseType) {
this.custom.xhr.responseType = this.responseType
}
}
this.proxy_send(...arguments)
}
@@ -54,10 +38,9 @@ export function mockXHR() {
}
}
// for mock server
const responseFake = (url, type, respond) => {
return {
url: new RegExp(`/mock${url}`),
url: new RegExp(`${MOCK_API_BASE}${url}`),
type: type || 'get',
response(req, res) {
res.json(Mock.mock(respond instanceof Function ? respond(req, res) : respond))

View File

@@ -1,62 +0,0 @@
const chokidar = require('chokidar')
const bodyParser = require('body-parser')
const chalk = require('chalk')
function registerRoutes(app) {
let mockStartIndex
const { default: mocks } = require('./index.js')
for (const mock of mocks) {
app[mock.type](mock.url, mock.response)
mockStartIndex = app._router.stack.length
}
const mockRoutesLength = Object.keys(mocks).length
return {
mockRoutesLength: mockRoutesLength,
mockStartIndex: mockStartIndex - mockRoutesLength
}
}
function unregisterRoutes() {
Object.keys(require.cache).forEach(i => {
if (i.includes('/mock')) {
delete require.cache[require.resolve(i)]
}
})
}
module.exports = app => {
// es6 polyfill
require('@babel/register')
// parse app.body
// http://expressjs.com/en/4x/api.html#req.body
app.use(bodyParser.json())
app.use(bodyParser.urlencoded({
extended: true
}))
const mockRoutes = registerRoutes(app)
var mockRoutesLength = mockRoutes.mockRoutesLength
var mockStartIndex = mockRoutes.mockStartIndex
// watch files, hot reload mock server
chokidar.watch(('./mock'), {
ignored: 'mock/mock-server.js',
persistent: true,
ignoreInitial: true
}).on('all', (event, path) => {
if (event === 'change' || event === 'add') {
// remove mock routes stack
app._router.stack.splice(mockStartIndex, mockRoutesLength)
// clear routes cache
unregisterRoutes()
const mockRoutes = registerRoutes(app)
mockRoutesLength = mockRoutes.mockRoutesLength
mockStartIndex = mockRoutes.mockStartIndex
console.log(chalk.magentaBright(`\n > Mock Server hot reload success! changed ${path}`))
}
})
}

12
mock/mocks.js Normal file
View File

@@ -0,0 +1,12 @@
import user from './user'
import role from './role'
import article from './article'
import search from './remoteSearch'
export default [
...user,
...role,
...article,
...search
]

View File

@@ -19,7 +19,7 @@ export const constantRoutes = [
},
{
path: '/auth-redirect',
component: 'views/login/authRedirect',
component: 'views/login/authredirect',
hidden: true
},
{

View File

@@ -30,19 +30,9 @@ export default [
type: 'post',
response: config => {
const { username } = config.body
const token = tokens[username]
// mock error
if (!token) {
return {
code: 60204,
message: 'Account and password are incorrect.'
}
}
return {
code: 20000,
data: token
data: tokens[username]
}
}
},
@@ -53,19 +43,9 @@ export default [
type: 'get',
response: config => {
const { token } = config.query
const info = users[token]
// mock error
if (!info) {
return {
code: 50008,
message: 'Login failed, unable to get user details.'
}
}
return {
code: 20000,
data: info
data: users[token]
}
}
},

View File

@@ -1,7 +1,7 @@
{
"name": "vue-element-admin",
"version": "4.0.1",
"description": "A magical vue admin. An out-of-box UI solution for enterprise applications. Newest development stack of vue. Lots of awesome features",
"version": "4.0.0",
"description": "A magical vue admin. Typical templates for enterprise applications. Newest development stack of vue. Lots of awesome features",
"author": "Pan <panfree23@gmail.com>",
"license": "MIT",
"scripts": {
@@ -10,8 +10,8 @@
"build:stage": "vue-cli-service build --mode staging",
"preview": "node build/index.js --preview",
"lint": "eslint --ext .js,.vue src",
"test": "npm run lint",
"test:unit": "vue-cli-service test:unit",
"test:ci": "npm run lint && npm run test:unit",
"svgo": "svgo -f src/icons/svg --config=src/icons/svgo.yml",
"new": "plop"
},
@@ -28,12 +28,10 @@
},
"keywords": [
"vue",
"admin",
"dashboard",
"element-ui",
"boilerplate",
"admin-template",
"management-system"
"admin",
"management-system",
"admin-template"
],
"repository": {
"type": "git",
@@ -44,12 +42,12 @@
},
"dependencies": {
"axios": "0.18.0",
"clipboard": "2.0.4",
"clipboard": "1.7.1",
"codemirror": "5.45.0",
"driver.js": "0.9.5",
"dropzone": "5.5.1",
"echarts": "4.2.1",
"element-ui": "2.7.0",
"element-ui": "2.6.3",
"file-saver": "2.0.1",
"fuse.js": "3.4.4",
"js-cookie": "2.2.0",
@@ -58,7 +56,7 @@
"normalize.css": "7.0.0",
"nprogress": "0.2.0",
"path-to-regexp": "2.4.0",
"screenfull": "4.2.0",
"screenfull": "4.1.0",
"showdown": "1.9.0",
"sortablejs": "1.8.4",
"tui-editor": "1.3.3",
@@ -74,16 +72,14 @@
"devDependencies": {
"@babel/core": "7.0.0",
"@babel/register": "7.0.0",
"@vue/cli-plugin-babel": "3.5.3",
"@vue/cli-plugin-eslint": "3.5.1",
"@vue/cli-plugin-unit-jest": "3.5.3",
"@vue/cli-service": "3.5.3",
"@vue/cli-plugin-babel": "3.5.1",
"@vue/cli-plugin-unit-jest": "3.5.1",
"@vue/cli-service": "3.5.1",
"@vue/test-utils": "1.0.0-beta.29",
"babel-core": "7.0.0-bridge.0",
"babel-eslint": "10.0.1",
"babel-jest": "23.6.0",
"chalk": "2.4.2",
"chokidar": "2.1.5",
"connect": "3.6.6",
"eslint": "5.15.3",
"eslint-plugin-vue": "5.2.2",

View File

@@ -1,6 +1,6 @@
import request from '@/utils/request'
export function searchUser(name) {
export function userSearch(name) {
return request({
url: '/search/user',
method: 'get',

View File

@@ -88,29 +88,29 @@ export default {
</script>
<style scoped>
.back-to-ceiling {
position: fixed;
display: inline-block;
text-align: center;
cursor: pointer;
}
.back-to-ceiling {
position: fixed;
display: inline-block;
text-align: center;
cursor: pointer;
}
.back-to-ceiling:hover {
background: #d5dbe7;
}
.back-to-ceiling:hover {
background: #d5dbe7;
}
.fade-enter-active,
.fade-leave-active {
transition: opacity .5s;
}
.fade-enter-active,
.fade-leave-active {
transition: opacity .5s;
}
.fade-enter,
.fade-leave-to {
opacity: 0
}
.fade-enter,
.fade-leave-to {
opacity: 0
}
.back-to-ceiling .Icon {
fill: #9aaabf;
background: none;
}
.back-to-ceiling .Icon {
fill: #9aaabf;
background: none;
}
</style>

View File

@@ -59,15 +59,14 @@ export default {
</script>
<style lang="scss" scoped>
.app-breadcrumb.el-breadcrumb {
display: inline-block;
font-size: 14px;
line-height: 50px;
margin-left: 8px;
.no-redirect {
color: #97a8be;
cursor: text;
.app-breadcrumb.el-breadcrumb {
display: inline-block;
font-size: 14px;
line-height: 50px;
margin-left: 8px;
.no-redirect {
color: #97a8be;
cursor: text;
}
}
}
</style>

View File

@@ -2,7 +2,7 @@
<div class="dndList">
<div :style="{width:width1}" class="dndList-list">
<h3>{{ list1Title }}</h3>
<draggable :set-data="setData" :list="list1" group="article" class="dragArea">
<draggable :list="list1" group="article" class="dragArea">
<div v-for="element in list1" :key="element.id" class="list-complete-item">
<div class="list-complete-item-handle">
{{ element.id }}[{{ element.author }}] {{ element.title }}
@@ -94,11 +94,6 @@ export default {
if (this.isNotInList1(ele)) {
this.list1.push(ele)
}
},
setData(dataTransfer) {
// to avoid Firefox bug
// Detail see : https://github.com/RubaXa/Sortable/issues/1012
dataTransfer.setData('Text', '')
}
}
}

View File

@@ -237,7 +237,7 @@ export default {
.dropzone .dz-preview:hover .dz-image img {
transform: none;
filter: none;
-webkit-filter: none;
width: 100%;
height: 100%;
}

View File

@@ -6,28 +6,28 @@
</el-button>
</el-badge>
<el-dialog :visible.sync="dialogTableVisible" title="Error Log" width="80%" append-to-body>
<el-dialog :visible.sync="dialogTableVisible" title="Error Log" width="80%">
<el-table :data="errorLogs" border>
<el-table-column label="Message">
<template slot-scope="{row}">
<template slot-scope="scope">
<div>
<span class="message-title">Msg:</span>
<el-tag type="danger">
{{ row.err.message }}
{{ scope.row.err.message }}
</el-tag>
</div>
<br>
<div>
<span class="message-title" style="padding-right: 10px;">Info: </span>
<el-tag type="warning">
{{ row.vm.$vnode.tag }} error in {{ row.info }}
{{ scope.row.vm.$vnode.tag }} error in {{ scope.row.info }}
</el-tag>
</div>
<br>
<div>
<span class="message-title" style="padding-right: 16px;">Url: </span>
<el-tag type="success">
{{ row.url }}
{{ scope.row.url }}
</el-tag>
</div>
</template>

View File

@@ -7,7 +7,6 @@
:list="list"
v-bind="$attrs"
class="board-column-content"
:set-data="setData"
>
<div v-for="element in list" :key="element.id" class="board-item">
{{ element.name }} {{ element.id }}
@@ -40,13 +39,6 @@ export default {
return []
}
}
},
methods: {
setData(dataTransfer) {
// to avoid Firefox bug
// Detail see : https://github.com/RubaXa/Sortable/issues/1012
dataTransfer.setData('Text', '')
}
}
}
</script>

View File

@@ -2,9 +2,7 @@
<div ref="rightPanel" :class="{show:show}" class="rightPanel-container">
<div class="rightPanel-background" />
<div class="rightPanel">
<div class="handle-button" :style="{'top':buttonTop+'px','background-color':theme}" @click="show=!show">
<i :class="show?'el-icon-close':'el-icon-setting'" />
</div>
<el-button class="handle-button" :style="{'top':buttonTop+'px'}" type="primary" circle :icon="show?'el-icon-close':'el-icon-setting'" @click="show=!show" />
<div class="rightPanel-items">
<slot />
</div>
@@ -32,11 +30,6 @@ export default {
show: false
}
},
computed: {
theme() {
return this.$store.state.settings.theme
}
},
watch: {
show(value) {
if (value && !this.clickNotClose) {
@@ -137,16 +130,7 @@ export default {
height: 48px;
pointer-events: auto;
z-index: 0;
cursor: pointer;
pointer-events: auto;
font-size: 24px;
text-align: center;
color: #fff;
line-height: 48px;
i {
font-size: 24px;
line-height: 48px;
}
}
</style>

View File

@@ -17,9 +17,6 @@ export default {
mounted() {
this.init()
},
beforeDestroy() {
this.destroy()
},
methods: {
click() {
if (!screenfull.enabled) {
@@ -31,17 +28,11 @@ export default {
}
screenfull.toggle()
},
change() {
this.isFullscreen = screenfull.isFullscreen
},
init() {
if (screenfull.enabled) {
screenfull.on('change', this.change)
}
},
destroy() {
if (screenfull.enabled) {
screenfull.off('change', this.change)
screenfull.on('change', () => {
this.isFullscreen = screenfull.isFullscreen
})
}
}
}

View File

@@ -1,7 +1,7 @@
<template>
<el-color-picker
v-model="theme"
:predefine="['#409EFF', '#1890ff', '#304156','#212121','#11a983', '#13c2c2', '#6959CD', '#f5222d', ]"
:predefine="['#409EFF', '#11a983', '#13c2c2', '#6959CD', '#f5222d', '#eb2f96', '#DB7093', '#e6a23c', '#8B8989', '#212121']"
class="theme-picker"
popper-class="theme-picker-dropdown"
/>
@@ -11,18 +11,17 @@
const version = require('element-ui/package.json').version // element-ui version from node_modules
const ORIGINAL_THEME = '#409EFF' // default color
import defaultSettings from '@/settings'
export default {
data() {
return {
chalk: '', // content of theme-chalk css
theme: defaultSettings.theme
theme: ORIGINAL_THEME
}
},
watch: {
async theme(val) {
const oldVal = this.chalk ? this.theme : ORIGINAL_THEME
const oldVal = this.theme
if (typeof val !== 'string') return
const themeCluster = this.getThemeCluster(val.replace('#', ''))
const originalCluster = this.getThemeCluster(oldVal.replace('#', ''))
@@ -71,8 +70,6 @@ export default {
style.innerText = this.updateStyle(innerText, originalCluster, themeCluster)
})
this.$emit('change', val)
$message.close()
}
},

View File

@@ -0,0 +1,220 @@
- [Enlgish](#Brief)
# 中文
## 写在前面
此组件仅提供一个创建 `TreeTable` 的解决思路。它基于`element-ui`的 table 组件实现,通过`el-table``row-style`方法,在里面判断元素是否需要隐藏或者显示,从而实现`TreeTable`的展开与收起。
并且本组件充分利用 `vue` 插槽的特性来方便用户自定义。
`evel.js` 里面,`addAttrs` 方法会给数据添加几个属性,`treeTotable` 会对数组扁平化。这些操作都不会破坏源数据,只是会新增属性。
## Props 说明
| Attribute | Description | Type | Default |
| :--------------: | :--------------------------------- | :-----: | :------: |
| data | 原始展示数据 | Array | [] |
| columns | 列属性 | Array | [] |
| defaultExpandAll | 默认是否全部展开 | Boolean | false |
| defaultChildren | 指定子树为节点对象的某个属性值 | String | children | |
| indent | 相邻级节点间的水平缩进,单位为像素 | Number | 50 |
> 任何 `el-table` 的属性都支持,例如`border`、`fit`、`size`或者`@select`、`@cell-click`等方法。详情属性见`el-table`文档。
---
### 代码示例
```html
<tree-table :data="data" :columns="columns" border>
```
#### data(**必填**)
```js
const data = [
{
name:'1'
children: [
{
name: '1-1'
},
{
name: '1-2'
}
]
},
{
name: `2`
}
]
```
#### columns(**必填**)
- label: 显示在表头的文字
- key: 对应 data 的 key。treeTable 将显示相应的 value
- expand: `true` or `false`。若为 true则在该列显示展开收起图标
- checkbox: `true` or `false`。若为 true则在该列显示`checkbox`
- width: 每列的宽度,为一个数字(可选)。例如`200`
- align: 对齐方式 `left/center/right`
- header-align: 表头对齐方式 `left/center/right`
```javascript
const columns = [
{
label: 'Checkbox',
checkbox: true
},
{
label: '',
key: 'id',
expand: true
},
{
label: 'Event',
key: 'event',
width: 200,
align: 'left'
},
{
label: 'Scope',
key: 'scope'
}
]
```
> 树表组件将会根据 columns 的 key 属性生成具名插槽,如果你需要对列数据进行自定义,通过插槽即可实现
```html
<template slot="your key" slot-scope="{scope}">
<el-tag>level: {{ scope.row._level }}</el-tag>
<el-tag>expand: {{ scope.row._expand }}</el-tag>
<el-tag>select: {{ scope.row._select }}</el-tag>
</template>
```
## Events
目前提供了几个方法,不过只是`beta`版本,之后很可能会修改。
```js
this.$refs.TreeTable.addChild(row, data) //添加子元素
this.$refs.TreeTable.addBrother(row, data) //添加兄弟元素
this.$refs.TreeTable.delete(row) //删除该元素
```
## 其他
如果有其他的需求,请参考[el-table](http://element-cn.eleme.io/#/en-US/component/table)的 api 自行修改 index.vue
# English
## Brief
This component only provides a solution for creating `TreeTable`. It is based on the `element-ui` table component. It uses the `row-style` method of `el-table` to determine whether the element needs to be hidden or displayed.
And this component makes full use of the features of the `vue` slot to make it user-friendly.
In `evel.js`, the `addAttrs` method adds several properties to the data, and `treeTotable` flattens the array. None of these operations will destroy the source data, just add properties.
## Props
| Attribute | Description | Type | Default |
| :--------------: | :----------------------------------------------------------- | :-----: | :------: |
| data | original display data | Array | [] |
| columns | column attribute | Array | [] |
| defaultExpandAll | whether to expand all nodes by default | Boolean | false |
| defaultChildren | specify which node object is used as the node's subtree | String | children | |
| indent | horizontal indentation of nodes in adjacent levels in pixels | Number | 50 |
> Any of the `el-table` properties are supported, such as `border`, `fit`, `size` or `@select`, `@cell-click`. See the ʻel-table` documentation for details.
---
### Example
```html
<tree-table :data="data" :columns="columns" border>
```
#### data(**Required**)
```js
const data = [
{
name:'1'
children: [
{
name: '1-1'
},
{
name: '1-2'
}
]
},
{
name: `2`
}
]
```
#### columns(**Required**)
- label: text displayed in the header
- key: data.key will show in column
- expand: `true` or `false`
- checkbox: `true` or `false`
- width: column width 。such as `200`
- align: alignment `left/center/right`
- header-align: alignment of the table header `left/center/right`
```javascript
const columns = [
{
label: 'Checkbox',
checkbox: true
},
{
label: '',
key: 'id',
expand: true
},
{
label: 'Event',
key: 'event',
width: 200,
align: 'left'
},
{
label: 'Scope',
key: 'scope'
}
]
```
> The tree table component will generate a named slot based on the key property of columns. If you need to customize the column data, you can do it through the slot.
```html
<template slot="your key" slot-scope="{scope}">
<el-tag>level: {{ scope.row._level }}</el-tag>
<el-tag>expand: {{ scope.row._expand }}</el-tag>
<el-tag>select: {{ scope.row._select }}</el-tag>
</template>
```
## Events
Several methods are currently available, but only the `beta` version, which is likely to be modified later.
```js
this.$refs.TreeTable.addChild(row, data) //Add child elements
this.$refs.TreeTable.addBrother(row, data) //Add a sibling element
this.$refs.TreeTable.delete(row) //Delete the element
```
## Other
If you have other requirements, please refer to the [el-table](http://element-cn.eleme.io/#/en-US/component/table) api to modify the index.vue

View File

@@ -0,0 +1,48 @@
import Vue from 'vue'
// Flattened array
export default function treeToArray(data, children = 'children') {
let tmp = []
data.forEach((item, index) => {
Vue.set(item, '_index', index)
tmp.push(item)
if (item[children] && item[children].length > 0) {
const res = treeToArray(item[children], children)
tmp = tmp.concat(res)
}
})
return tmp
}
export function addAttrs(data, { parent = null, preIndex = false, level = 0, expand = false, children = 'children', show = true, select = false } = {}) {
data.forEach((item, index) => {
const _id = (preIndex ? `${preIndex}-${index}` : index) + ''
Vue.set(item, '_id', _id)
Vue.set(item, '_level', level)
Vue.set(item, '_expand', expand)
Vue.set(item, '_parent', parent)
Vue.set(item, '_show', show)
Vue.set(item, '_select', select)
if (item[children] && item[children].length > 0) {
addAttrs(item[children], {
parent: item,
level: level + 1,
expand,
preIndex: _id,
children,
status,
select
})
}
})
}
export function cleanParentAttr(data, children = 'children') {
data.forEach(item => {
item._parent = null
if (item[children] && item[children].length > 0) {
addAttrs(item[children], children)
}
})
return data
}

View File

@@ -0,0 +1,193 @@
<template>
<el-table :data="tableData" :row-style="showRow" v-bind="$attrs" v-on="$listeners">
<slot name="selection" />
<slot name="pre-column" />
<el-table-column
v-for="item in columns"
:key="item.key"
:label="item.label"
:width="item.width"
:align="item.align||'center'"
:header-align="item.headerAlign"
>
<template slot-scope="scope">
<slot :scope="scope" :name="item.key">
<template v-if="item.expand">
<span :style="{'padding-left':+scope.row._level*indent + 'px'} " />
<span v-show="showSperadIcon(scope.row)" class="tree-ctrl" @click="toggleExpanded(scope.$index)">
<i v-if="!scope.row._expand" class="el-icon-plus" />
<i v-else class="el-icon-minus" />
</span>
</template>
<template v-if="item.checkbox">
<el-checkbox
v-if="scope.row[defaultChildren]&&scope.row[defaultChildren].length>0"
v-model="scope.row._select"
:style="{'padding-left':+scope.row._level*indent + 'px'} "
:indeterminate="scope.row._select"
@change="handleCheckAllChange(scope.row)"
/>
<el-checkbox
v-else
v-model="scope.row._select"
:style="{'padding-left':+scope.row._level*indent + 'px'} "
@change="handleCheckAllChange(scope.row)"
/>
</template>
{{ scope.row[item.key] }}
</slot>
</template>
</el-table-column>
</el-table>
</template>
<script>
import treeToArray, { addAttrs } from './eval.js'
export default {
name: 'TreeTable',
props: {
data: {
type: Array,
required: true,
default: () => []
},
columns: {
type: Array,
default: () => []
},
defaultExpandAll: {
type: Boolean,
default: false
},
defaultChildren: {
type: String,
default: 'children'
},
indent: {
type: Number,
default: 50
}
},
data() {
return {
guard: 1
}
},
computed: {
children() {
return this.defaultChildren
},
tableData() {
const data = this.data
if (this.data.length === 0) {
return []
}
addAttrs(data, {
expand: this.defaultExpandAll,
children: this.defaultChildren
})
const retval = treeToArray(data, this.defaultChildren)
return retval
}
},
methods: {
addBrother(row, data) {
if (row._parent) {
row._parent.children.push(data)
} else {
this.data.push(data)
}
},
addChild(row, data) {
if (!row.children) {
this.$set(row, 'children', [])
}
row.children.push(data)
},
delete(row) {
const { _index, _parent } = row
if (_parent) {
_parent.children.splice(_index, 1)
} else {
this.data.splice(_index, 1)
}
},
getData() {
return this.tableData
},
showRow: function({ row }) {
const parent = row._parent
const show = parent ? parent._expand && parent._show : true
row._show = show
return show
? 'animation:treeTableShow 1s;-webkit-animation:treeTableShow 1s;'
: 'display:none;'
},
showSperadIcon(record) {
return record[this.children] && record[this.children].length > 0
},
toggleExpanded(trIndex) {
const record = this.tableData[trIndex]
const expand = !record._expand
record._expand = expand
},
handleCheckAllChange(row) {
this.selcetRecursion(row, row._select, this.defaultChildren)
this.isIndeterminate = row._select
},
selcetRecursion(row, select, children = 'children') {
if (select) {
this.$set(row, '_expand', true)
this.$set(row, '_show', true)
}
const sub_item = row[children]
if (sub_item && sub_item.length > 0) {
sub_item.map(child => {
child._select = select
this.selcetRecursion(child, select, children)
})
}
},
updateTreeNode(item) {
return new Promise(resolve => {
const { _id, _parent } = item
const index = _id.split('-').slice(-1)[0] // get last index
if (_parent) {
_parent.children.splice(index, 1, item)
resolve(this.data)
} else {
this.data.splice(index, 1, item)
resolve(this.data)
}
})
}
}
}
</script>
<style>
@keyframes treeTableShow {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
@-webkit-keyframes treeTableShow {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
.tree-ctrl {
position: relative;
cursor: pointer;
color: #2196f3;
}
</style>

View File

@@ -1,6 +1,7 @@
export default {
route: {
dashboard: 'Dashboard',
introduction: 'Introduction',
documentation: 'Documentation',
guide: 'Guide',
permission: 'Permission',
@@ -9,6 +10,7 @@ export default {
directivePermission: 'Directive Permission',
icons: 'Icons',
components: 'Components',
componentIndex: 'Introduction',
tinymce: 'Tinymce',
markdown: 'Markdown',
jsonEditor: 'JSON Editor',
@@ -17,9 +19,9 @@ export default {
avatarUpload: 'Avatar Upload',
dropzone: 'Dropzone',
sticky: 'Sticky',
countTo: 'Count To',
countTo: 'CountTo',
componentMixin: 'Mixin',
backToTop: 'Back To Top',
backToTop: 'BackToTop',
dragDialog: 'Drag Dialog',
dragSelect: 'Drag Select',
dragKanban: 'Drag Kanban',
@@ -41,6 +43,8 @@ export default {
dragTable: 'Drag Table',
inlineEditTable: 'Inline Edit',
complexTable: 'Complex Table',
treeTable: 'Tree Table',
customTreeTable: 'Custom TreeTable',
tab: 'Tab',
form: 'Form',
createArticle: 'Create Article',
@@ -72,7 +76,7 @@ export default {
},
login: {
title: 'Login Form',
logIn: 'Login',
logIn: 'Log in',
username: 'Username',
password: 'Password',
any: 'any',
@@ -85,10 +89,10 @@ export default {
},
permission: {
addRole: 'New Role',
editPermission: 'Edit',
editPermission: 'Edit Permission',
roles: 'Your roles',
switchRoles: 'Switch roles',
tips: 'In some cases, using v-permission will have no effect. For example: Element-UI el-tab or el-table-column and other scenes that dynamically render dom. You can only do this with v-if.',
tips: 'In some cases it is not suitable to use v-permission, such as element Tab component or el-table-column and other asynchronous rendering dom cases which can only be achieved by manually setting the v-if.',
delete: 'Delete',
confirm: 'Confirm',
cancel: 'Cancel'
@@ -99,7 +103,7 @@ export default {
},
components: {
documentation: 'Documentation',
tinymceTips: 'Rich text is a core feature of the management backend, but at the same time it is a place with lots of pits. In the process of selecting rich texts, I also took a lot of detours. The common rich texts on the market have been basically used, and I finally chose Tinymce. See the more detailed rich text comparison and introduction.',
tinymceTips: 'Rich text editor is a core part of management system, but at the same time is a place with lots of problems. In the process of selecting rich texts, I also walked a lot of detours. The common rich text editors in the market are basically used, and the finally chose Tinymce. See documentation for more detailed rich text editor comparisons and introductions.',
dropzoneTips: 'Because my business has special needs, and has to upload images to qiniu, so instead of a third party, I chose encapsulate it by myself. It is very simple, you can see the detail code in @/components/Dropzone.',
stickyTips: 'when the page is scrolled to the preset position will be sticky on the top.',
backToTopTips1: 'When the page is scrolled to the specified position, the Back to Top button appears in the lower right corner',
@@ -140,14 +144,14 @@ export default {
excel: {
export: 'Export',
selectedExport: 'Export Selected Items',
placeholder: 'Please enter the file name (default excel-list)'
placeholder: 'Please enter the file name(default excel-list)'
},
zip: {
export: 'Export',
placeholder: 'Please enter the file name (default file)'
placeholder: 'Please enter the file name(default file)'
},
pdf: {
tips: 'Here we use window.print() to implement the feature of downloading PDF.'
tips: 'Here we use window.print() to implement the feature of downloading pdf.'
},
theme: {
change: 'Change Theme',

View File

@@ -1,6 +1,7 @@
export default {
route: {
dashboard: 'Panel de control',
introduction: 'Introducción',
documentation: 'Documentación',
guide: 'Guía',
permission: 'Permisos',
@@ -9,6 +10,7 @@ export default {
directivePermission: 'Permisos de la directiva',
icons: 'Iconos',
components: 'Componentes',
componentIndex: 'Introducción',
tinymce: 'Tinymce',
markdown: 'Markdown',
jsonEditor: 'Editor JSON',
@@ -41,6 +43,8 @@ export default {
dragTable: 'Arrastrar tabla',
inlineEditTable: 'Editor',
complexTable: 'Complex Table',
treeTable: 'Tree Table',
customTreeTable: 'Custom TreeTable',
tab: 'Pestaña',
form: 'Formulario',
createArticle: 'Crear artículo',

View File

@@ -24,24 +24,11 @@ const messages = {
...elementEsLocale
}
}
export function getLanguage() {
const chooseLanguage = Cookies.get('language')
if (chooseLanguage) return chooseLanguage
// if has not choose language
const language = (navigator.language || navigator.browserLanguage).toLowerCase()
const locales = Object.keys(messages)
for (const locale of locales) {
if (language.indexOf(locale) > -1) {
return locale
}
}
return 'en'
}
const i18n = new VueI18n({
// set locale
// options: en | zh | es
locale: getLanguage(),
locale: Cookies.get('language') || 'en',
// set locale messages
messages
})

View File

@@ -1,6 +1,7 @@
export default {
route: {
dashboard: '首页',
introduction: '简述',
documentation: '文档',
guide: '引导页',
permission: '权限测试页',
@@ -9,15 +10,16 @@ export default {
directivePermission: '指令权限',
icons: '图标',
components: '组件',
componentIndex: '介绍',
tinymce: '富文本编辑器',
markdown: 'Markdown',
jsonEditor: 'JSON 编辑器',
jsonEditor: 'JSON编辑器',
dndList: '列表拖拽',
splitPane: 'Splitpane',
avatarUpload: '头像上传',
dropzone: 'Dropzone',
sticky: 'Sticky',
countTo: 'Count To',
countTo: 'CountTo',
componentMixin: '小组件',
backToTop: '返回顶部',
dragDialog: '拖拽 Dialog',
@@ -30,17 +32,19 @@ export default {
example: '综合实例',
nested: '路由嵌套',
menu1: '菜单1',
'menu1-1': '菜单 1-1',
'menu1-2': '菜单 1-2',
'menu1-2-1': '菜单 1-2-1',
'menu1-2-2': '菜单 1-2-2',
'menu1-3': '菜单 1-3',
menu2: '菜单 2',
'menu1-1': '菜单1-1',
'menu1-2': '菜单1-2',
'menu1-2-1': '菜单1-2-1',
'menu1-2-2': '菜单1-2-2',
'menu1-3': '菜单1-3',
menu2: '菜单2',
Table: 'Table',
dynamicTable: '动态 Table',
dragTable: '拖拽 Table',
inlineEditTable: 'Table 内编辑',
complexTable: '综合 Table',
dynamicTable: '动态Table',
dragTable: '拖拽Table',
inlineEditTable: 'Table内编辑',
complexTable: '综合Table',
treeTable: '树形表格',
customTreeTable: '自定义树表',
tab: 'Tab',
form: '表单',
createArticle: '创建文章',
@@ -88,7 +92,7 @@ export default {
editPermission: '编辑权限',
roles: '你的权限',
switchRoles: '切换权限',
tips: '在某些情况下,不适合使用 v-permission。例如Element-UI 的 el-tab 或 el-table-column 以及其它动态渲染 dom 的场景。你只能通过手动设置 v-if 来实现。',
tips: '在某些情况下,不适合使用 v-permission。例如Element-UI 的 Tab 组件或 el-table-column 以及其它动态渲染 dom 的场景。你只能通过手动设置 v-if 来实现。',
delete: '删除',
confirm: '确定',
cancel: '取消'

View File

@@ -1,19 +1,19 @@
<template>
<div class="navbar">
<hamburger id="hamburger-container" :is-active="sidebar.opened" class="hamburger-container" @toggleClick="toggleSideBar" />
<hamburger :is-active="sidebar.opened" class="hamburger-container" @toggleClick="toggleSideBar" />
<breadcrumb id="breadcrumb-container" class="breadcrumb-container" />
<breadcrumb class="breadcrumb-container" />
<div class="right-menu">
<template v-if="device!=='mobile'">
<search id="header-search" class="right-menu-item" />
<search class="right-menu-item" />
<error-log class="errLog-container right-menu-item hover-effect" />
<screenfull id="screenfull" class="right-menu-item hover-effect" />
<screenfull class="right-menu-item hover-effect" />
<el-tooltip :content="$t('navbar.size')" effect="dark" placement="bottom">
<size-select id="size-select" class="right-menu-item hover-effect" />
<size-select class="right-menu-item hover-effect" />
</el-tooltip>
<lang-select class="right-menu-item hover-effect" />
@@ -86,6 +86,12 @@ export default {
</script>
<style lang="scss" scoped>
.hasTagsView {
.navbar {
border-bottom: none;
}
}
.navbar {
height: 50px;
overflow: hidden;

View File

@@ -5,7 +5,7 @@
<div class="drawer-item">
<span>{{ $t('settings.theme') }}</span>
<theme-picker style="float: right;height: 26px;margin: -3px 8px 0 0;" @change="themeChange" />
<theme-picker style="float: right;height: 26px;margin: -3px 8px 0 0;" />
</div>
<div class="drawer-item">
@@ -69,14 +69,6 @@ export default {
})
}
}
},
methods: {
themeChange(val) {
this.$store.dispatch('settings/changeSetting', {
key: 'theme',
value: val
})
}
}
}
</script>

View File

@@ -1,9 +1,9 @@
<template>
<div v-if="!item.hidden" class="menu-wrapper">
<template v-if="hasOneShowingChild(item.children,item) && (!onlyOneChild.children||onlyOneChild.noShowingChildren)&&!item.alwaysShow">
<app-link v-if="onlyOneChild.meta" :to="resolvePath(onlyOneChild.path)">
<app-link :to="resolvePath(onlyOneChild.path)">
<el-menu-item :index="resolvePath(onlyOneChild.path)" :class="{'submenu-title-noDropdown':!isNest}">
<item :icon="onlyOneChild.meta.icon||(item.meta&&item.meta.icon)" :title="generateTitle(onlyOneChild.meta.title)" />
<item v-if="onlyOneChild.meta" :icon="onlyOneChild.meta.icon||(item.meta&&item.meta.icon)" :title="generateTitle(onlyOneChild.meta.title)" />
</el-menu-item>
</app-link>
</template>
@@ -86,9 +86,6 @@ export default {
if (isExternal(routePath)) {
return routePath
}
if (isExternal(this.basePath)) {
return this.basePath
}
return path.resolve(this.basePath, routePath)
},

View File

@@ -3,7 +3,7 @@
<logo v-if="showLogo" :collapse="isCollapse" />
<el-scrollbar wrap-class="scrollbar-wrapper">
<el-menu
:default-active="activeMenu"
:default-active="$route.path"
:collapse="isCollapse"
:background-color="variables.menuBg"
:text-color="variables.menuText"
@@ -30,15 +30,6 @@ export default {
'permission_routes',
'sidebar'
]),
activeMenu() {
const route = this.$route
const { meta, path } = route
// if set path, the sidebar will highlight the path you set
if (meta.activeMenu) {
return meta.activeMenu
}
return path
},
showLogo() {
return this.$store.state.settings.sidebarLogo
},

View File

@@ -1,5 +1,5 @@
<template>
<div id="tags-view-container" class="tags-view-container">
<div class="tags-view-container">
<scroll-pane ref="scrollPane" class="tags-view-wrapper">
<router-link
v-for="tag in visitedViews"
@@ -145,7 +145,7 @@ export default {
closeSelectedTag(view) {
this.$store.dispatch('tagsView/delView', view).then(({ visitedViews }) => {
if (this.isActive(view)) {
this.toLastView(visitedViews, view)
this.toLastView(visitedViews)
}
})
},
@@ -160,22 +160,16 @@ export default {
if (this.affixTags.some(tag => tag.path === view.path)) {
return
}
this.toLastView(visitedViews, view)
this.toLastView(visitedViews)
})
},
toLastView(visitedViews, view) {
toLastView(visitedViews) {
const latestView = visitedViews.slice(-1)[0]
if (latestView) {
this.$router.push(latestView)
} else {
// now the default is to redirect to the home page if there is no tags-view,
// you can adjust it according to your needs.
if (view.name === 'Dashboard') {
// to reload home page
this.$router.replace({ path: '/redirect' + view.fullPath })
} else {
this.$router.push('/')
}
// You can set another route
this.$router.push('/')
}
},
openMenu(tag, e) {
@@ -249,7 +243,7 @@ export default {
.contextmenu {
margin: 0;
background: #fff;
z-index: 3000;
z-index: 100;
position: absolute;
list-style-type: none;
padding: 5px 0;

View File

@@ -14,9 +14,6 @@ export default {
beforeMount() {
window.addEventListener('resize', this.resizeHandler)
},
beforeDestroy() {
window.removeEventListener('resize', this.resizeHandler)
},
mounted() {
const isMobile = this.isMobile()
if (isMobile) {

View File

@@ -4,40 +4,41 @@ import Router from 'vue-router'
Vue.use(Router)
/* Layout */
import Layout from '@/layout'
import Layout from '@/layout/Layout'
/* Router Modules */
import componentsRouter from './modules/components'
import chartsRouter from './modules/charts'
import tableRouter from './modules/table'
import treeTableRouter from './modules/tree-table'
import nestedRouter from './modules/nested'
/** note: sub-menu only appear when children.length>=1
* detail see https://panjiachen.github.io/vue-element-admin-site/guide/essentials/router-and-nav.html
**/
/**
* Note: sub-menu only appear when route children.length >= 1
* Detail see: https://panjiachen.github.io/vue-element-admin-site/guide/essentials/router-and-nav.html
*
* hidden: true if set true, item will not show in the sidebar(default is false)
* alwaysShow: true if set true, will always show the root menu
* if not set alwaysShow, when item has more than one children route,
* it will becomes nested mode, otherwise not show the root menu
* redirect: noredirect if `redirect:noredirect` will no redirect in the breadcrumb
* name:'router-name' the name is used by <keep-alive> (must set!!!)
* meta : {
roles: ['admin','editor'] control the page roles (you can set multiple roles)
title: 'title' the name show in sidebar and breadcrumb (recommend set)
* hidden: true if `hidden:true` will not show in the sidebar(default is false)
* alwaysShow: true if set true, will always show the root menu, whatever its child routes length
* if not set alwaysShow, only more than one route under the children
* it will becomes nested mode, otherwise not show the root menu
* redirect: noredirect if `redirect:noredirect` will no redirect in the breadcrumb
* name:'router-name' the name is used by <keep-alive> (must set!!!)
* meta : {
roles: ['admin','editor'] will control the page roles (you can set multiple roles)
title: 'title' the name show in sub-menu and breadcrumb (recommend set)
icon: 'svg-name' the icon show in the sidebar
noCache: true if set true, the page will no be cached(default is false)
affix: true if set true, the tag will affix in the tags-view
breadcrumb: false if set false, the item will hidden in breadcrumb(default is true)
activeMenu: '/example/list' if set path, the sidebar will highlight the path you set
noCache: true if true, the page will no be cached(default is false)
breadcrumb: false if false, the item will hidden in breadcrumb(default is true)
affix: true if true, the tag will affix in the tags-view
}
*/
**/
/**
* constantRoutes
* a base page that does not have permission requirements
* all roles can be accessed
*/
* */
export const constantRoutes = [
{
path: '/redirect',
@@ -57,7 +58,7 @@ export const constantRoutes = [
},
{
path: '/auth-redirect',
component: () => import('@/views/login/authRedirect'),
component: () => import('@/views/login/authredirect'),
hidden: true
},
{
@@ -113,7 +114,7 @@ export const constantRoutes = [
/**
* asyncRoutes
* the routes that need to be dynamically loaded based on user roles
*/
*/
export const asyncRoutes = [
{
path: '/permission',
@@ -174,6 +175,7 @@ export const asyncRoutes = [
chartsRouter,
nestedRouter,
tableRouter,
treeTableRouter,
{
path: '/example',
@@ -195,7 +197,7 @@ export const asyncRoutes = [
path: 'edit/:id(\\d+)',
component: () => import('@/views/example/edit'),
name: 'EditArticle',
meta: { title: 'editArticle', noCache: true, activeMenu: '/example/list' },
meta: { title: 'editArticle', noCache: true },
hidden: true
},
{

View File

@@ -1,6 +1,6 @@
/** When your routing table is too long, you can split it into small modules**/
import Layout from '@/layout'
import Layout from '@/layout/Layout'
const chartsRouter = {
path: '/charts',

View File

@@ -1,6 +1,6 @@
/** When your routing table is too long, you can split it into small modules**/
import Layout from '@/layout'
import Layout from '@/layout/Layout'
const componentsRouter = {
path: '/components',

View File

@@ -1,6 +1,6 @@
/** When your routing table is too long, you can split it into small modules**/
import Layout from '@/layout'
import Layout from '@/layout/Layout'
const nestedRouter = {
path: '/nested',

View File

@@ -1,6 +1,6 @@
/** When your routing table is too long, you can split it into small modules**/
import Layout from '@/layout'
import Layout from '@/layout/Layout'
const tableRouter = {
path: '/table',

View File

@@ -0,0 +1,29 @@
/** When your routing table is too long, you can split it into small modules**/
import Layout from '@/layout/Layout'
const treeTableRouter = {
path: '/tree-table',
component: Layout,
redirect: '/table/complex-table',
name: 'TreeTable',
meta: {
title: 'treeTable',
icon: 'tree-table'
},
children: [
{
path: 'index',
component: () => import('@/views/tree-table/index'),
name: 'TreeTableDemo',
meta: { title: 'treeTable' }
},
{
path: 'custom',
component: () => import('@/views/tree-table/custom'),
name: 'CustomTreeTableDemo',
meta: { title: 'customTreeTable' }
}
]
}
export default treeTableRouter

View File

@@ -1,8 +1,4 @@
import variables from '@/styles/element-variables.scss'
export default {
theme: variables.theme,
/**
* @type {boolean} true | false
* @description Whether show the settings right-panel
@@ -28,10 +24,10 @@ export default {
sidebarLogo: false,
/**
* @type {string | array} 'production' | ['production', 'development']
* @type {string | array} 'production' | ['production','development']
* @description Need show err logs component.
* The default is only used in the production env
* If you want to also use it in dev, you can pass ['production', 'development']
* If you want to also use it in dev, you can pass ['production','development']
*/
errorLog: 'production'
}

View File

@@ -1,24 +1,24 @@
import Vue from 'vue'
import Vuex from 'vuex'
import app from './modules/app'
import errorLog from './modules/errorLog'
import permission from './modules/permission'
import tagsView from './modules/tagsView'
import settings from './modules/settings'
import user from './modules/user'
import getters from './getters'
Vue.use(Vuex)
// https://webpack.js.org/guides/dependency-management/#requirecontext
const modulesFiles = require.context('./modules', false, /\.js$/)
// you do not need `import app from './modules/app'`
// it will auto require all vuex module from modules file
const modules = modulesFiles.keys().reduce((modules, modulePath) => {
// set './app.js' => 'app'
const moduleName = modulePath.replace(/^\.\/(.*)\.\w+$/, '$1')
const value = modulesFiles(modulePath)
modules[moduleName] = value.default
return modules
}, {})
const store = new Vuex.Store({
modules,
modules: {
app,
errorLog,
permission,
tagsView,
settings,
user
},
getters
})

View File

@@ -1,5 +1,4 @@
import Cookies from 'js-cookie'
import { getLanguage } from '@/lang/index'
const state = {
sidebar: {
@@ -7,7 +6,7 @@ const state = {
withoutAnimation: false
},
device: 'desktop',
language: getLanguage(),
language: Cookies.get('language') || 'en',
size: Cookies.get('size') || 'medium'
}

View File

@@ -1,3 +1,4 @@
const state = {
logs: []
}

View File

@@ -1,8 +1,7 @@
import defaultSettings from '@/settings'
const { showSettings, tagsView, fixedHeader, sidebarLogo, theme } = defaultSettings
const { showSettings, tagsView, fixedHeader, sidebarLogo } = defaultSettings
const state = {
theme: theme,
showSettings: showSettings,
tagsView: tagsView,
fixedHeader: fixedHeader,

View File

@@ -1,3 +1,4 @@
const state = {
visitedViews: [],
cachedViews: []

View File

@@ -23,9 +23,3 @@ $--table-border:1px solid#dfe6ec;
$--font-path: '~element-ui/lib/theme-chalk/fonts';
@import "~element-ui/packages/theme-chalk/src/index";
// the :export directive is the magic sauce for webpack
// https://www.bluematador.com/blog/how-to-share-variables-between-js-and-sass
:export {
theme: $--color-primary;
}

View File

@@ -12,7 +12,6 @@
.sidebar-container {
transition: width 0.28s;
width: $sideBarWidth !important;
background-color: $menuBg;
height: 100%;
position: fixed;
font-size: 0px;
@@ -29,6 +28,10 @@
.scrollbar-wrapper {
overflow-x: hidden !important;
.el-scrollbar__view {
height: 100%;
}
}
.el-scrollbar__bar.is-vertical {

View File

@@ -1,5 +1,5 @@
import axios from 'axios'
import { MessageBox, Message } from 'element-ui'
import { Message } from 'element-ui'
import store from '@/store'
import { getToken } from '@/utils/auth'
@@ -23,7 +23,7 @@ service.interceptors.request.use(
error => {
// Do something with request error
console.log(error) // for debug
return Promise.reject(error)
Promise.reject(error)
}
)
@@ -33,39 +33,40 @@ service.interceptors.response.use(
* If you want to get information such as headers or status
* Please return response => response
*/
response => response.data,
/**
* 下面的注释为通过在response里自定义code来标示请求状态
* 当code返回如下情况则说明权限有问题登出并返回到登录页
* 如想通过 XMLHttpRequest 来状态码标识 逻辑可写在下面error中
* 如想通过 xmlhttprequest 来状态码标识 逻辑可写在下面error中
* 以下代码均为样例,请结合自生需求加以修改,若不需要,则可删除
*/
response => {
const res = response.data
if (res.code !== 20000) {
Message({
message: res.message || 'error',
type: 'error',
duration: 5 * 1000
})
// 50008:非法的token; 50012:其他客户端登录了; 50014:Token 过期了;
if (res.code === 50008 || res.code === 50012 || res.code === 50014) {
// 请自行在引入 MessageBox
// import { Message, MessageBox } from 'element-ui'
MessageBox.confirm('你已被登出,可以取消继续留在该页面,或者重新登录', '确定登出', {
confirmButtonText: '重新登录',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
store.dispatch('user/resetToken').then(() => {
location.reload() // 为了重新实例化vue-router对象 避免bug
})
})
}
return Promise.reject(res.message || 'error')
} else {
return res
}
},
// response => {
// const res = response.data
// if (res.code !== 20000) {
// Message({
// message: res.message,
// type: 'error',
// duration: 5 * 1000
// })
// // 50008:非法的token; 50012:其他客户端登录了; 50014:Token 过期了;
// if (res.code === 50008 || res.code === 50012 || res.code === 50014) {
// // 请自行在引入 MessageBox
// // import { Message, MessageBox } from 'element-ui'
// MessageBox.confirm('你已被登出,可以取消继续留在该页面,或者重新登录', '确定登出', {
// confirmButtonText: '重新登录',
// cancelButtonText: '取消',
// type: 'warning'
// }).then(() => {
// store.dispatch('user/resetToken').then(() => {
// location.reload() // 为了重新实例化vue-router对象 避免bug
// })
// })
// }
// return Promise.reject('error')
// } else {
// return response.data
// }
// },
error => {
console.log('err' + error) // for debug
Message({

View File

@@ -1,6 +1,6 @@
<template>
<div>
<sticky :z-index="10" class-name="sub-navbar">
<sticky class-name="sub-navbar">
<el-dropdown trigger="click">
<el-button plain>
Platform<i class="el-icon-caret-bottom el-icon--right" />

View File

@@ -11,9 +11,9 @@
</template>
</el-table-column>
<el-table-column label="Status" width="100" align="center">
<template slot-scope="{row}">
<el-tag :type="row.status | statusFilter">
{{ row.status }}
<template slot-scope="scope">
<el-tag :type="scope.row.status | statusFilter">
{{ scope.row.status }}
</el-tag>
</template>
</el-table-column>

View File

@@ -1,6 +1,6 @@
<template>
<div class="dashboard-editor-container">
<github-corner class="github-corner" />
<github-corner style="position: absolute; top: 0px; border: 0; right: 0;" />
<panel-group @handleSetLineChartData="handleSetLineChartData" />
@@ -100,15 +100,6 @@ export default {
.dashboard-editor-container {
padding: 32px;
background-color: rgb(240, 242, 245);
position: relative;
.github-corner {
position: absolute;
top: 0px;
border: 0;
right: 0;
}
.chart-wrapper {
background: #fff;
padding: 16px 16px 0;

View File

@@ -1,7 +1,7 @@
<template>
<div class="createPost-container">
<el-form ref="postForm" :model="postForm" :rules="rules" class="form-container">
<sticky :z-index="10" :class-name="'sub-navbar '+postForm.status">
<sticky :class-name="'sub-navbar '+postForm.status">
<CommentDropdown v-model="postForm.comment_disabled" />
<PlatformDropdown v-model="postForm.platforms" />
<SourceUrlDropdown v-model="postForm.source_uri" />
@@ -28,7 +28,7 @@
<el-row>
<el-col :span="8">
<el-form-item label-width="45px" label="作者:" class="postInfo-container-item">
<el-select v-model="postForm.author" :remote-method="getRemoteUserList" filterable default-first-option remote placeholder="搜索用户">
<el-select v-model="postForm.author" :remote-method="getRemoteUserList" filterable remote placeholder="搜索用户">
<el-option v-for="(item,index) in userListOptions" :key="item+index" :label="item" :value="item" />
</el-select>
</el-form-item>
@@ -81,7 +81,7 @@ import MDinput from '@/components/MDinput'
import Sticky from '@/components/Sticky' // 粘性header组件
import { validURL } from '@/utils/validate'
import { fetchArticle } from '@/api/article'
import { searchUser } from '@/api/remoteSearch'
import { userSearch } from '@/api/remoteSearch'
import Warning from './Warning'
import { CommentDropdown, PlatformDropdown, SourceUrlDropdown } from './Dropdown'
@@ -225,7 +225,7 @@ export default {
this.postForm.status = 'draft'
},
getRemoteUserList(query) {
searchUser(query).then(response => {
userSearch(query).then(response => {
if (!response.data.items) return
this.userListOptions = response.data.items.map(v => v.name)
})

View File

@@ -26,17 +26,17 @@
</el-table-column>
<el-table-column class-name="status-col" label="Status" width="110">
<template slot-scope="{row}">
<el-tag :type="row.status | statusFilter">
{{ row.status }}
<template slot-scope="scope">
<el-tag :type="scope.row.status | statusFilter">
{{ scope.row.status }}
</el-tag>
</template>
</el-table-column>
<el-table-column min-width="300px" label="Title">
<template slot-scope="{row}">
<router-link :to="'/example/edit/'+row.id" class="link-type">
<span>{{ row.title }}</span>
<template slot-scope="scope">
<router-link :to="'/example/edit/'+scope.row.id" class="link-type">
<span>{{ scope.row.title }}</span>
</router-link>
</template>
</el-table-column>
@@ -95,6 +95,14 @@ export default {
this.total = response.data.total
this.listLoading = false
})
},
handleSizeChange(val) {
this.listQuery.limit = val
this.getList()
},
handleCurrentChange(val) {
this.listQuery.page = val
this.getList()
}
}
}

View File

@@ -2,7 +2,7 @@
<div style="display:inline-block;">
<!-- $t is vue-i18n global function to translate lang -->
<label class="radio-label" style="padding-left:0;">Filename: </label>
<el-input v-model="filename" :placeholder="$t('excel.placeholder')" style="width:350px;" prefix-icon="el-icon-document" />
<el-input v-model="filename" :placeholder="$t('excel.placeholder')" style="width:340px;" prefix-icon="el-icon-document" />
</div>
</template>

View File

@@ -1,7 +1,7 @@
<template>
<div class="app-container">
<!-- $t is vue-i18n global function to translate lang -->
<el-input v-model="filename" :placeholder="$t('excel.placeholder')" style="width:350px;" prefix-icon="el-icon-document" />
<el-input v-model="filename" :placeholder="$t('excel.placeholder')" style="width:340px;" prefix-icon="el-icon-document" />
<el-button :loading="downloadLoading" style="margin-bottom:20px" type="primary" icon="document" @click="handleDownload">
{{ $t('excel.selectedExport') }}
</el-button>

View File

@@ -1,6 +1,6 @@
const steps = [
{
element: '#hamburger-container',
element: '.hamburger-container',
popover: {
title: 'Hamburger',
description: 'Open && Close sidebar',
@@ -8,7 +8,7 @@ const steps = [
}
},
{
element: '#breadcrumb-container',
element: '.breadcrumb-container',
popover: {
title: 'Breadcrumb',
description: 'Indicate the current page location',
@@ -16,31 +16,31 @@ const steps = [
}
},
{
element: '#header-search',
popover: {
title: 'Page Search',
description: 'Page search, quick navigation',
position: 'left'
}
},
{
element: '#screenfull',
element: '.screenfull',
popover: {
title: 'Screenfull',
description: 'Set the page into fullscreen',
description: 'Bring the page into fullscreen',
position: 'left'
}
},
{
element: '#size-select',
element: '.international-icon',
popover: {
title: 'Switch Size',
description: 'Switch the system size',
title: 'Switch language',
description: 'Switch the system language',
position: 'left'
}
},
{
element: '#tags-view-container',
element: '.theme-switch',
popover: {
title: 'Theme Switch',
description: 'Custom switch system theme',
position: 'left'
}
},
{
element: '.tags-view-container',
popover: {
title: 'Tags view',
description: 'The history of the page you visited',

View File

@@ -1,6 +1,6 @@
<script>
export default {
name: 'AuthRedirect',
name: 'Authredirect',
created() {
const hash = window.location.search.slice(1)
if (window.localStorage) {

View File

@@ -14,7 +14,6 @@
<svg-icon icon-class="user" />
</span>
<el-input
ref="username"
v-model="loginForm.username"
:placeholder="$t('login.username')"
name="username"
@@ -23,28 +22,22 @@
/>
</el-form-item>
<el-tooltip v-model="capsTooltip" content="Caps lock is On" placement="right" manual>
<el-form-item prop="password">
<span class="svg-container">
<svg-icon icon-class="password" />
</span>
<el-input
:key="passwordType"
ref="password"
v-model="loginForm.password"
:type="passwordType"
:placeholder="$t('login.password')"
name="password"
auto-complete="on"
@keyup.native="checkCapslock"
@blur="capsTooltip = false"
@keyup.enter.native="handleLogin"
/>
<span class="show-pwd" @click="showPwd">
<svg-icon :icon-class="passwordType === 'password' ? 'eye' : 'eye-open'" />
</span>
</el-form-item>
</el-tooltip>
<el-form-item prop="password">
<span class="svg-container">
<svg-icon icon-class="password" />
</span>
<el-input
v-model="loginForm.password"
:type="passwordType"
:placeholder="$t('login.password')"
name="password"
auto-complete="on"
@keyup.enter.native="handleLogin"
/>
<span class="show-pwd" @click="showPwd">
<svg-icon :icon-class="passwordType === 'password' ? 'eye' : 'eye-open'" />
</span>
</el-form-item>
<el-button :loading="loading" type="primary" style="width:100%;margin-bottom:30px;" @click.native.prevent="handleLogin">
{{ $t('login.logIn') }}
@@ -81,7 +74,7 @@
<script>
import { validUsername } from '@/utils/validate'
import LangSelect from '@/components/LangSelect'
import SocialSign from './socialSignin'
import SocialSign from './socialsignin'
export default {
name: 'Login',
@@ -104,14 +97,13 @@ export default {
return {
loginForm: {
username: 'admin',
password: '111111'
password: '1111111'
},
loginRules: {
username: [{ required: true, trigger: 'blur', validator: validateUsername }],
password: [{ required: true, trigger: 'blur', validator: validatePassword }]
},
passwordType: 'password',
capsTooltip: false,
loading: false,
showDialog: false,
redirect: undefined
@@ -128,38 +120,16 @@ export default {
created() {
// window.addEventListener('storage', this.afterQRScan)
},
mounted() {
if (this.loginForm.username === '') {
this.$refs.username.focus()
} else if (this.loginForm.password === '') {
this.$refs.password.focus()
}
},
destroyed() {
// window.removeEventListener('storage', this.afterQRScan)
},
methods: {
checkCapslock({ shiftKey, key } = {}) {
if (key && key.length === 1) {
if (shiftKey && (key >= 'a' && key <= 'z') || !shiftKey && (key >= 'A' && key <= 'Z')) {
this.capsTooltip = true
} else {
this.capsTooltip = false
}
}
if (key === 'CapsLock' && this.capsTooltip === true) {
this.capsTooltip = false
}
},
showPwd() {
if (this.passwordType === 'password') {
this.passwordType = ''
} else {
this.passwordType = 'password'
}
this.$nextTick(() => {
this.$refs.password.focus()
})
},
handleLogin() {
this.$refs.loginForm.validate(valid => {
@@ -206,12 +176,16 @@ export default {
/* Detail see https://github.com/PanJiaChen/vue-element-admin/pull/927 */
$bg:#283443;
$light_gray:#fff;
$light_gray:#eee;
$cursor: #fff;
@supports (-webkit-mask: none) and (not (cater-color: $cursor)) {
.login-container .el-input input {
color: $cursor;
&::first-line {
color: $light_gray;
}
}
}
@@ -233,7 +207,7 @@ $cursor: #fff;
caret-color: $cursor;
&:-webkit-autofill {
box-shadow: 0 0 0px 1000px $bg inset !important;
-webkit-box-shadow: 0 0 0px 1000px $bg inset !important;
-webkit-text-fill-color: $cursor !important;
}
}

View File

@@ -1,9 +1,9 @@
<template>
<div>
<div style="margin-bottom:15px;">
{{ $t('permission.roles') }}: {{ roles }}
{{ $t('permission.roles') }} {{ roles }}
</div>
{{ $t('permission.switchRoles') }}:
{{ $t('permission.switchRoles') }}
<el-radio-group v-model="switchRoles">
<el-radio-button label="editor" />
<el-radio-button label="admin" />

View File

@@ -1 +0,0 @@
["info","error","success","warning","question","back","arrow-left","arrow-down","arrow-right","arrow-up","caret-left","caret-bottom","caret-top","caret-right","d-arrow-left","d-arrow-right","minus","plus","remove","circle-plus","remove-outline","circle-plus-outline","close","check","circle-close","circle-check","circle-close-outline","circle-check-outline","zoom-out","zoom-in","d-caret","sort","sort-down","sort-up","tickets","document","goods","sold-out","news","message","date","printer","time","bell","mobile-phone","service","view","menu","more","more-outline","star-on","star-off","location","location-outline","phone","phone-outline","picture","picture-outline","delete","search","edit","edit-outline","rank","refresh","share","setting","upload","upload2","download","loading"]

View File

@@ -4,57 +4,37 @@
<a href="https://panjiachen.github.io/vue-element-admin-site/guide/advanced/icon.html" target="_blank">Add and use
</a>
</p>
<el-tabs type="border-card">
<el-tab-pane label="Icons">
<div v-for="item of iconsMap" :key="item" @click="handleClipboard(generateIconCode(item),$event)">
<el-tooltip placement="top">
<div slot="content">
{{ generateIconCode(item) }}
</div>
<div class="icon-item">
<svg-icon :icon-class="item" class-name="disabled" />
<span>{{ item }}</span>
</div>
</el-tooltip>
</div>
</el-tab-pane>
<el-tab-pane label="Element-UI Icons">
<div v-for="item of elementIcons" :key="item" @click="handleClipboard(generateElementIconCode(item),$event)">
<el-tooltip placement="top">
<div slot="content">
{{ generateElementIconCode(item) }}
</div>
<div class="icon-item">
<i :class="'el-icon-' + item" />
<span>{{ item }}</span>
</div>
</el-tooltip>
</div>
</el-tab-pane>
</el-tabs>
<div class="icons-wrapper">
<div v-for="item of iconsMap" :key="item" @click="handleClipboard(generateIconCode(item),$event)">
<el-tooltip placement="top">
<div slot="content">
{{ generateIconCode(item) }}
</div>
<div class="icon-item">
<svg-icon :icon-class="item" class-name="disabled" />
<span>{{ item }}</span>
</div>
</el-tooltip>
</div>
</div>
</div>
</template>
<script>
import clipboard from '@/utils/clipboard'
import icons from './requireIcons'
import elementIcons from './element-icon.json'
import clipboard from '@/utils/clipboard'
export default {
name: 'Icons',
data() {
return {
iconsMap: icons,
elementIcons: elementIcons
iconsMap: icons
}
},
methods: {
generateIconCode(symbol) {
return `<svg-icon icon-class="${symbol}" />`
},
generateElementIconCode(symbol) {
return `<i class="el-icon-${symbol}" />`
},
handleClipboard(text, event) {
clipboard(text, event)
}
@@ -66,25 +46,25 @@ export default {
.icons-container {
margin: 10px 20px 0;
overflow: hidden;
.icons-wrapper {
margin: 0 auto;
}
.icon-item {
margin: 20px;
height: 85px;
height: 110px;
text-align: center;
width: 100px;
width: 110px;
float: left;
font-size: 30px;
color: #24292e;
cursor: pointer;
}
span {
display: block;
font-size: 16px;
font-size: 24px;
margin-top: 10px;
}
.disabled {
.disabled{
pointer-events: none;
}
}

View File

@@ -1,3 +1,4 @@
const req = require.context('../../icons/svg', false, /\.svg$/)
const requireAll = requireContext => requireContext.keys()

View File

@@ -19,9 +19,9 @@
</el-table-column>
<el-table-column min-width="300px" label="Title">
<template slot-scope="{row}">
<span>{{ row.title }}</span>
<el-tag>{{ row.type }}</el-tag>
<template slot-scope="scope">
<span>{{ scope.row.title }}</span>
<el-tag>{{ scope.row.type }}</el-tag>
</template>
</el-table-column>
@@ -44,9 +44,9 @@
</el-table-column>
<el-table-column class-name="status-col" label="Status" width="110">
<template slot-scope="{row}">
<el-tag :type="row.status | statusFilter">
{{ row.status }}
<template slot-scope="scope">
<el-tag :type="scope.row.status | statusFilter">
{{ scope.row.status }}
</el-tag>
</template>
</el-table-column>

View File

@@ -46,9 +46,9 @@
</template>
</el-table-column>
<el-table-column :label="$t('table.title')" min-width="150px">
<template slot-scope="{row}">
<span class="link-type" @click="handleUpdate(row)">{{ row.title }}</span>
<el-tag>{{ row.type | typeFilter }}</el-tag>
<template slot-scope="scope">
<span class="link-type" @click="handleUpdate(scope.row)">{{ scope.row.title }}</span>
<el-tag>{{ scope.row.type | typeFilter }}</el-tag>
</template>
</el-table-column>
<el-table-column :label="$t('table.author')" width="110px" align="center">
@@ -67,30 +67,30 @@
</template>
</el-table-column>
<el-table-column :label="$t('table.readings')" align="center" width="95">
<template slot-scope="{row}">
<span v-if="row.pageviews" class="link-type" @click="handleFetchPv(row.pageviews)">{{ row.pageviews }}</span>
<template slot-scope="scope">
<span v-if="scope.row.pageviews" class="link-type" @click="handleFetchPv(scope.row.pageviews)">{{ scope.row.pageviews }}</span>
<span v-else>0</span>
</template>
</el-table-column>
<el-table-column :label="$t('table.status')" class-name="status-col" width="100">
<template slot-scope="{row}">
<el-tag :type="row.status | statusFilter">
{{ row.status }}
<template slot-scope="scope">
<el-tag :type="scope.row.status | statusFilter">
{{ scope.row.status }}
</el-tag>
</template>
</el-table-column>
<el-table-column :label="$t('table.actions')" align="center" width="230" class-name="small-padding fixed-width">
<template slot-scope="{row}">
<el-button type="primary" size="mini" @click="handleUpdate(row)">
<template slot-scope="scope">
<el-button type="primary" size="mini" @click="handleUpdate(scope.row)">
{{ $t('table.edit') }}
</el-button>
<el-button v-if="row.status!='published'" size="mini" type="success" @click="handleModifyStatus(row,'published')">
<el-button v-if="scope.row.status!='published'" size="mini" type="success" @click="handleModifyStatus(scope.row,'published')">
{{ $t('table.publish') }}
</el-button>
<el-button v-if="row.status!='draft'" size="mini" @click="handleModifyStatus(row,'draft')">
<el-button v-if="scope.row.status!='draft'" size="mini" @click="handleModifyStatus(scope.row,'draft')">
{{ $t('table.draft') }}
</el-button>
<el-button v-if="row.status!='deleted'" size="mini" type="danger" @click="handleModifyStatus(row,'deleted')">
<el-button v-if="scope.row.status!='deleted'" size="mini" type="danger" @click="handleModifyStatus(scope.row,'deleted')">
{{ $t('table.delete') }}
</el-button>
</template>

View File

@@ -39,9 +39,9 @@
</el-table-column>
<el-table-column class-name="status-col" label="Status" width="110">
<template slot-scope="{row}">
<el-tag :type="row.status | statusFilter">
{{ row.status }}
<template slot-scope="scope">
<el-tag :type="scope.row.status | statusFilter">
{{ scope.row.status }}
</el-tag>
</template>
</el-table-column>
@@ -54,10 +54,10 @@
</el-table>
<!-- $t is vue-i18n global function to translate lang (lang in @/lang) -->
<div class="show-d">
<el-tag style="margin-right:12px;">{{ $t('table.dragTips1') }} :</el-tag> {{ oldList }}
{{ $t('table.dragTips1') }} : &nbsp; {{ oldList }}
</div>
<div class="show-d">
<el-tag>{{ $t('table.dragTips2') }} :</el-tag> {{ newList }}
{{ $t('table.dragTips2') }} : {{ newList }}
</div>
</div>
</template>
@@ -113,9 +113,9 @@ export default {
this.sortable = Sortable.create(el, {
ghostClass: 'sortable-ghost', // Class name for the drop placeholder,
setData: function(dataTransfer) {
dataTransfer.setData('Text', '')
// to avoid Firefox bug
// Detail see : https://github.com/RubaXa/Sortable/issues/1012
dataTransfer.setData('Text', '')
},
onEnd: evt => {
const targetRow = this.list.splice(evt.oldIndex, 1)[0]

View File

@@ -26,31 +26,31 @@
</el-table-column>
<el-table-column class-name="status-col" label="Status" width="110">
<template slot-scope="{row}">
<el-tag :type="row.status | statusFilter">
{{ row.status }}
<template slot-scope="scope">
<el-tag :type="scope.row.status | statusFilter">
{{ scope.row.status }}
</el-tag>
</template>
</el-table-column>
<el-table-column min-width="300px" label="Title">
<template slot-scope="{row}">
<template v-if="row.edit">
<el-input v-model="row.title" class="edit-input" size="small" />
<el-button class="cancel-btn" size="small" icon="el-icon-refresh" type="warning" @click="cancelEdit(row)">
<template slot-scope="scope">
<template v-if="scope.row.edit">
<el-input v-model="scope.row.title" class="edit-input" size="small" />
<el-button class="cancel-btn" size="small" icon="el-icon-refresh" type="warning" @click="cancelEdit(scope.row)">
cancel
</el-button>
</template>
<span v-else>{{ row.title }}</span>
<span v-else>{{ scope.row.title }}</span>
</template>
</el-table-column>
<el-table-column align="center" label="Actions" width="120">
<template slot-scope="{row}">
<el-button v-if="row.edit" type="success" size="small" icon="el-icon-circle-check-outline" @click="confirmEdit(row)">
<template slot-scope="scope">
<el-button v-if="scope.row.edit" type="success" size="small" icon="el-icon-circle-check-outline" @click="confirmEdit(scope.row)">
Ok
</el-button>
<el-button v-else type="primary" size="small" icon="el-icon-edit" @click="row.edit=!row.edit">
<el-button v-else type="primary" size="small" icon="el-icon-edit" @click="scope.row.edit=!scope.row.edit">
Edit
</el-button>
</template>

View File

@@ -0,0 +1,51 @@
const data = [
{
name: '1',
timeLine: 100,
children: [
{
name: '1-1',
timeLine: 20
},
{
name: '1-2',
timeLine: 60,
children: [
{
name: '1-2-1',
timeLine: 35
},
{
name: '1-2-2',
timeLine: 25
}
]
}
]
},
{
name: '2',
timeLine: 80,
children: [
{
name: '2-1',
timeLine: 30
},
{
name: '2-2',
timeLine: 50
},
{
name: '2-3',
timeLine: 60
}
]
},
{
name: '3',
timeLine: 40
}
]
export default data

View File

@@ -0,0 +1,159 @@
<template>
<div>
<div class="app-container">
<el-button type="primary" size="small" style="margin:0 0 20px 0;">
<a href="https://github.com/PanJiaChen/vue-element-admin/tree/master/src/components/TreeTable" target="_blank">Documentation</a>
</el-button>
<tree-table
ref="TreeTable"
:data="tableData"
:default-expand-all="true"
:columns="columns"
border
default-children="children"
@selection-change="selectChange"
>
<template slot="selection">
<el-table-column type="selection" align="center" width="55" />
</template>
<template slot="pre-column">
<el-table-column type="expand" width="55">
<template>
<el-tag type="info">
Here is just a placeholder slot, you can display anything.
</el-tag>
</template>
</el-table-column>
</template>
<template slot="timeline" slot-scope="{scope}">
<el-tooltip :content="scope.row.timeLine+'ms'" effect="dark" placement="left">
<div class="processContainer">
<div
:style="{ width:(scope.row.timeLine||0) * 3+'px',
background:scope.row.timeLine>50?'rgba(233,0,0,.5)':'rgba(0,0,233,0.5)',
marginLeft:scope.row._level * 50+'px' }"
class="process"
>
<span style="display:inline-block" />
</div>
</div>
</el-tooltip>
</template>
<template slot="append" slot-scope="{scope}">
<el-button
size="mini"
type="primary"
@click="addMenuItem(scope.row,'brother')"
>
Append Brother
</el-button>
<el-button
size="mini"
type="primary"
@click="addMenuItem(scope.row,'children')"
>
Append Child
</el-button>
</template>
<template slot="operation" slot-scope="{scope}">
<el-button size="mini" type="success" @click="editItem(scope.row)">
Edit
</el-button>
<el-button size="mini" type="danger" @click="deleteItem(scope.row)">
Delete
</el-button>
</template>
</tree-table>
</div>
<el-dialog :visible.sync="dialogFormVisible" title="Edit">
<el-form :model="tempItem" label-width="100px" style="width:600px">
<el-form-item label="Name">
<el-input v-model.trim="tempItem.name" placeholder="Name" />
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button @click="dialogFormVisible = false">Cancel</el-button>
<el-button type="primary" @click="updateItem">Confirm</el-button>
</span>
</el-dialog>
</div>
</template>
<script>
import TreeTable from '@/components/TreeTable'
import data from './data.js'
export default {
components: { TreeTable },
data() {
return {
tableData: [],
tempItem: {},
dialogFormVisible: false,
columns: [
{
label: 'Name',
key: 'name',
expand: true
},
{
label: 'Timeline',
key: 'timeline'
},
{
label: 'Append',
key: 'append',
width: 300
},
{
label: 'Operation',
key: 'operation',
width: 160
}
]
}
},
created() {
this.getData()
},
methods: {
getData() {
this.tableData = data
},
editItem(row) {
this.tempItem = Object.assign({}, row)
this.dialogFormVisible = true
},
async updateItem() {
await this.$refs.TreeTable.updateTreeNode(this.tempItem)
this.dialogFormVisible = false
},
addMenuItem(row, type) {
if (type === 'children') {
this.$refs.TreeTable.addChild(row, { name: 'child', timeLine: this.randomNum() })
}
if (type === 'brother') {
this.$refs.TreeTable.addBrother(row, { name: 'brother', timeLine: this.randomNum() })
}
},
deleteItem(row) {
this.$refs.TreeTable.delete(row)
},
selectChange(val) {
console.log(val)
},
randomNum() {
// return 1~100
const max = 100
const min = 1
return Math.floor(Math.random() * (max - min + 1) + min)
}
}
}
</script>

View File

@@ -0,0 +1,80 @@
const data = [
{
id: 0,
event: 'Event-0',
timeLine: 50
},
{
id: 1,
event: 'Event-1',
timeLine: 100,
children: [
{
id: 2,
event: 'Event-2',
timeLine: 10
},
{
id: 3,
event: 'Event-3',
timeLine: 90,
children: [
{
id: 4,
event: 'Event-4',
timeLine: 5
},
{
id: 5,
event: 'Event-5',
timeLine: 10
},
{
id: 6,
event: 'Event-6',
timeLine: 75,
children: [
{
id: 7,
event: 'Event-7',
timeLine: 50,
children: [
{
id: 71,
event: 'Event-7-1',
timeLine: 25
},
{
id: 72,
event: 'Event-7-2',
timeLine: 5
},
{
id: 73,
event: 'Event-7-3',
timeLine: 20
}
]
},
{
id: 8,
event: 'Event-8',
timeLine: 25
}
]
}
]
}
]
}
]
export default data

View File

@@ -0,0 +1,126 @@
<template>
<div class="app-container">
<div style="margin-bottom:20px;">
<el-button type="primary" size="small" class="option-item">
<a href="https://github.com/PanJiaChen/vue-element-admin/tree/master/src/components/TreeTable" target="_blank">Documentation</a>
</el-button>
<div class="option-item">
<el-tag>Expand All</el-tag>
<el-switch
v-model="defaultExpandAll"
active-color="#13ce66"
inactive-color="#ff4949"
@change="reset"
/>
</div>
<div class="option-item">
<el-tag>Show Checkbox</el-tag>
<el-switch
v-model="showCheckbox"
active-color="#13ce66"
inactive-color="#ff4949"
/>
</div>
</div>
<tree-table :key="key" :default-expand-all="defaultExpandAll" :data="data" :columns="columns" border>
<template slot="scope" slot-scope="{scope}">
<el-tag>level: {{ scope.row._level }}</el-tag>
<el-tag>expand: {{ scope.row._expand }}</el-tag>
<el-tag>select: {{ scope.row._select }}</el-tag>
</template>
<template slot="operation" slot-scope="{scope}">
<el-button type="primary" size="" @click="click(scope)">
Click
</el-button>
</template>
</tree-table>
</div>
</template>
<script>
import treeTable from '@/components/TreeTable'
import data from './data'
export default {
name: 'TreeTableDemo',
components: { treeTable },
data() {
return {
defaultExpandAll: false,
showCheckbox: true,
key: 1,
columns: [
{
label: 'Checkbox',
checkbox: true
},
{
label: '',
key: 'id',
expand: true
},
{
label: 'Event',
key: 'event',
width: 200,
align: 'left'
},
{
label: 'Scope',
key: 'scope'
},
{
label: 'Operation',
key: 'operation'
}
],
data: data
}
},
watch: {
showCheckbox(val) {
if (val) {
this.columns.unshift({
label: 'Checkbox',
checkbox: true
})
} else {
this.columns.shift()
}
this.reset()
}
},
methods: {
reset() {
++this.key
},
click(scope) {
console.log(scope)
const row = scope.row
const message = Object.keys(row)
.map(i => {
return `<p>${i}: ${row[i]}</p>`
})
.join('')
this.$notify({
title: 'Success',
dangerouslyUseHTMLString: true,
message: message,
type: 'success'
})
}
}
}
</script>
<style scoped>
.option-item{
display: inline-block;
margin-right: 15px;
}
</style>

View File

@@ -3,7 +3,7 @@
<!-- $t is vue-i18n global function to translate lang -->
<el-input v-model="filename" :placeholder="$t('zip.placeholder')" style="width:300px;" prefix-icon="el-icon-document" />
<el-button :loading="downloadLoading" style="margin-bottom:20px;" type="primary" icon="document" @click="handleDownload">
{{ $t('zip.export') }} Zip
{{ $t('zip.export') }} zip
</el-button>
<el-table v-loading="listLoading" :data="list" element-loading-text="拼命加载中" border fit highlight-current-row>
<el-table-column align="center" label="ID" width="95">

View File

@@ -1,27 +1,28 @@
'use strict'
const path = require('path')
const pkg = require('./package.json')
function resolve(dir) {
return path.join(__dirname, dir)
}
const name = pkg.name || 'vue-element-admin' // page title
const name = 'vue-element-admin'
const port = 9527 // dev port
// All configuration item explanations can be find in https://cli.vuejs.org/config/
// Explanation of each configuration item You can find it in https://cli.vuejs.org/config/
module.exports = {
/**
* You will need to set publicPath if you plan to deploy your site under a sub path,
* for example GitHub Pages. If you plan to deploy your site to https://foo.github.io/bar/,
* then publicPath should be set to "/bar/".
* You can set by yourself according to actual condition
* You will need to set this if you plan to deploy your site under a sub path,
* for example GitHub pages. If you plan to deploy your site to https://foo.github.io/bar/,
* then assetsPublicPath should be set to "/bar/".
* In most cases please use '/' !!!
* Detail: https://cli.vuejs.org/config/#publicpath
* Detail https://cli.vuejs.org/config/#publicPath
*/
publicPath: '/',
outputDir: 'dist',
assetsDir: 'static',
lintOnSave: process.env.NODE_ENV === 'development',
lintOnSave: process.env.NODE_ENV === 'development' ? 'error' : false,
productionSourceMap: false,
devServer: {
port: port,
@@ -31,20 +32,33 @@ module.exports = {
errors: true
},
proxy: {
// change xxx-api/login => mock/login
// detail: https://cli.vuejs.org/config/#devserver-proxy
[process.env.VUE_APP_BASE_API]: {
'/api': {
target: `http://localhost:${port}/mock`,
changeOrigin: true,
pathRewrite: {
['^' + process.env.VUE_APP_BASE_API]: ''
'^/api': ''
}
}
},
after: require('./mock/mock-server.js')
after(app) {
require('@babel/register')
const bodyParser = require('body-parser')
// parse app.body
// http://expressjs.com/en/4x/api.html#req.body
app.use(bodyParser.json())
app.use(bodyParser.urlencoded({
extended: true
}))
const { default: mocks } = require('./mock')
for (const mock of mocks) {
app[mock.type](mock.url, mock.response)
}
}
},
configureWebpack: {
// provide the app's title in webpack's name field, so that
// We provide the app's title in Webpack's name field, so that
// it can be accessed in index.html to inject the correct title.
name: name,
resolve: {
@@ -56,8 +70,6 @@ module.exports = {
chainWebpack(config) {
config.plugins.delete('preload') // TODO: need test
config.plugins.delete('prefetch') // TODO: need test
// set svg-sprite-loader
config.module
.rule('svg')
.exclude.add(resolve('src/icons'))
@@ -73,8 +85,6 @@ module.exports = {
symbolId: 'icon-[name]'
})
.end()
// set preserveWhitespace
config.module
.rule('vue')
.use('vue-loader')
@@ -84,7 +94,6 @@ module.exports = {
return options
})
.end()
config
.when(process.env.NODE_ENV === 'development',
config => config.devtool('cheap-source-map')
@@ -109,17 +118,17 @@ module.exports = {
name: 'chunk-libs',
test: /[\\/]node_modules[\\/]/,
priority: 10,
chunks: 'initial' // only package third parties that are initially dependent
chunks: 'initial' // 只打包初始时依赖的第三方
},
elementUI: {
name: 'chunk-elementUI', // split elementUI into a single package
priority: 20, // the weight needs to be larger than libs and app or it will be packaged into libs or app
test: /[\\/]node_modules[\\/]_?element-ui(.*)/ // in order to adapt to cnpm
name: 'chunk-elementUI', // 单独将 elementUI 拆包
priority: 20, // 权重要大于 libs app 不然会被打包进 libs 或者 app
test: /[\\/]node_modules[\\/]element-ui[\\/]/
},
commons: {
name: 'chunk-commons',
test: resolve('src/components'), // can customize your rules
minChunks: 3, // minimum common number
test: resolve('src/components'), // 可自定义拓展你的规则
minChunks: 3, // 最小公用次数
priority: 5,
reuseExistingChunk: true
}