Compare commits

..

12 Commits

Author SHA1 Message Date
Pan
26d1bf09fd fix[Mock]: fixed mock bug 2019-04-01 17:37:37 +08:00
花裤衩
b94e69be6f [release] 4.0.0 (#1291)
* fix[ExternalLink]: fixed bug when url include chinese #1182

* feature: support  Spanish(#1196)

* fix[MockJS]: fix bug with withCredentials after using mockjs  (#1194)

* 修复 Mock 导致请求丢失 Cookie 的问题

修复 Mock 导致 Cookie 丢失的问题,只有在 XHR.open() 周期时,自定义的 withCredentials 会被挂载,此时检查是否是未被拦截的 xhr,并挂载自定义的 withCredentials ,无则默认为 false

* update readme

* perf[tagsView]: refactor the moveToTarget function (#1195)

* fix[tagsView]:fixed visited view move to currentTag

* edit the scroll regular friendly

* tweak

* fix[tagsView]: fixed moveToCurrentTag bug

* feature: add pagination component (#1213)

* fix[TagsView]: fixed update tags title demo bug (#1223)

* chore: temporary hack cssnano bug #1222

* [release] 3.9.2

* chore: restore the hack of cssnano bug

https://github.com/cssnano/cssnano/issues/643

* add an example of sort data by table  (#1236)

* feature: add drag select component (#1249)

* 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

* update

* add test

* fix bug

* fix[Charts]: fixed charts resize mixins bug  #1285 (#1290)

* perf[Tinymce]: add searchreplace plugin

* perf[avatar]:minimize the selected area of avatar on the mobile phone when user clicked avatar (#1304)

* refine css

* fix[DragSelect]: fixed querySelectorAll bug

* perf[DragSelect]: add $listeners

* fix link

* fix[Breadcurmb]: fixed pathCompile bug

* fix[Breadcurmb]: fixed router-link bug

* perf[style]: use webpack alias instead of hard code src path (#1338)

* perf[style]: use webpack alias instead of hard code src path

* add sponsors

* fix import path bug

* update vue-router to fixed url path for non ascii urls #1362

* fix[Pagination]: apply PageSizes property to el-pagination  (#1355)

Apply PageSizes property to el-pagination

* update dependence

* add tui.editor (#1374)

* tweak

* add preview

* fix return back bug

* update guide page

* fix[Tinymce]: fixed fullScreen bug #1400

* feat[Breadcrumb]: add hide Breadcrumb option #1442

* perf: use WeChat 7.0 new version icon color

* refactor[login]: refactor login page style

* perf[ScrollPane]: refine moveToTarget code (#1460)

* feature[PDF]: add PDF demo (#1469)

* perf[v-permission]: refine v-permission demo

* perf[Sidebar]: refine sidebar store #1473 (#1474)

* refine: GetUserInfo error message

* fix typo (#1505)

* perf: add sidebar width to variables.scss (#1494)

* tweak

* fix[ThemePicker]: fixed bug when oldVal is null (#1517)

* update README.md

* fix[Breadcrumb]: fixed eslint error (#1521)

* fix[DndList]: fixed drag bug (#1527)

https://github.com/PanJiaChen/vue-element-admin/issues/1524

* pref[Hamburger]: refactor Hamburger component (#1528)

* 美化侧栏菜单切换按钮

* tweak

* perf[Login Form]: optimize eye icon style (#1545)

* optimiz: eye icon style for login form

* change eye-open svg

* perf[Sticky]: export reset method (#1550)

* perf[Sticky]: refine width default value

* perf[utils]: refine parseTime function (#1546)

* 优化 parseTime

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

* Update index.js

* perf[UploadExcel]: optimized code (#1552)

* perf: adjust the import order to make it more elegant #1537

* perf[Sidebar]: use sass variables in vue template

* perf[Style]: optimize the sidebar style to make it better to set (#1568)

* perf[SizeSelect]: add default size option (#1566)

* fix[SIdebar]: fixed bug in mobile #1567 (#1569)

* perf: fixed eslint errors

* perf[Lang]: make up for miss keywords

* perf: optimize some code

* perf[Navbar]: refactor navbar style

* perf[Login]: refine css

* feature[Navbar]: add header-search component(#1591)

* fix[Screenfull]: fix screenfull click bug

* perf[Screenfull]: refactor screenfull component

* fix[Screenfull]: fix screenfull bug (#1603)

* fix typo

* fearure[TagsView]: add affix option (#1577)

* perf[utils]: optimize code

* perf[utils]: optimizate variable name

* perf[Navbar]: add scroll bar when the subMenu is too long (#1619)

* perf[ThemePicker]: refine updateStyle function (#554)

* theme replacing should cut tons of irrelevant css

* perf[ResizeHandler]: optimized the judgment of isMobile (#1633)

perf[ResizeHandler]: optimized the judgment of isMobile

*  fix[Sidebar]: fixed infinite loop bug(#1333)

* fixed infinite loop Bug when in hasOneShowingChild Edit the onlyOneChild

* tweak

* fix[Sidebar]: data should return a object

* perf[Sidebar]: optimize code logic (#1349)

* fix[TagsView]: fixed refresh affixed-tag bug (#1653)

* perf[utils.js]: refactor byteLength function (#1650)

* perf[TagsView]: refine code

* perf[TagsView]: set the scrollPane as a business component (#1660)

* fix[DragTable]: support multiple drag-table (#1666)

* perf[Tree-Table]: refactor tree-table

* perf[Tree-Table]: organize the structure and add documentation (#1673)

* fix[Sidebar]: fixed nested router hover bug

* update version

* set preserveWhitespace

* lint code

* fix jest test case

* update config

* bump

* remove empty file

* docs: add link

* fix[Sidebar]: fixed collapse animation problem (#1690)

* fix[Tree-Table]: fixed update item data bug (#1692)

* fix[Waves-Directive]: fixed v-waves does not support update (#1705)

* update husky

* rm cli-plugin-eslint

* add settings (#1707)

* refine settings

* fix[utils]: fixed param2Obj not decoding plus sign (#1712)

* feature[Directive]: add auto-height table directive (#1702)

* fix bug

* feature[Permission]: add role permission management page (#1605)

* feature[Excel]: support export merged header export (#1718)

* feature[Excel]: add export merge header excel demo

* lint

* refine theme color

* add role mock

* tweak mock

* fix[Excel]: fixed export merge-header excel bug

* refine code

* add ThemePicker to setting

* fix[HeaderSearch]: fixed bug in vue2.6+ (#1733)

* fix[Sticky]: fixed bug when set stickyTop

* perf[Sticky]: refine demo

* refine code

* tweak mock

* vuex add namespaced

* fix[Excel]: fixed export bug (#1736)

* rm

* refactor permission

* perf[ThemePicker]: add predefine (#1743)

* fix[Utils]: fixed deepClone error msg (#1748)

* feature: add fixedHeader settings

* fix style in mobile

* fix chore

* perf[Eslint]: update eslint rules

* feature: add create template (#1762)

* add comment

* update vue.config.js

* feature: add sidebar logo (#1767)

* rm

* perf settings

* bump

* refine script and css

* update

* refine settings

* refine config

* update docs

* refine

* rm

* fix jest

* add theme setting

* dump vue-cli

* perf: remove redundant code

* update element-ui

* fix sticky demo bug

* docs

* fixed password input  bug

* refine login form css

* remove tree-table

* update version

* mock error

* refine layout name

* refine
2019-04-01 17:07:16 +08:00
MaYuanhai
96d3cfa215 perf[Login]: optimize input focus interaction (#1798) 2019-03-29 12:55:07 +08:00
Pan
20f6150741 [release] 3.11.0 2019-03-28 14:15:32 +08:00
Pan
7703005013 perf: remove redundant code 2019-03-28 11:44:04 +08:00
zhu yu
9a5c404ef8 docs: fix typo (#1782)
i18 -> i18n
2019-03-27 15:18:30 +08:00
sun ao
9d975b5eff fix[Mock]: add xhr.responseType (#1779) 2019-03-27 13:31:34 +08:00
MaYuanhai
331173ffee perf[Css]: fixed typo (#1776) 2019-03-26 12:59:31 +08:00
Pan
f890685d8d docs 2019-03-25 18:39:54 +08:00
Pan
fb30079477 docs 2019-03-25 18:04:14 +08:00
Pan
3100d0cff4 fix[Sidebar]: fixed v-if meta bug 2019-03-22 15:11:22 +08:00
Yuga Sun
ae6bbf7858 fix[Utils]: fixed deepClone error msg (#1748) 2019-03-21 15:14:15 +08:00
48 changed files with 298 additions and 1125 deletions

View File

@@ -1,9 +1,14 @@
VUE_APP_BASE_API = '/api'
# just a flag
ENV = 'development'
// 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
# 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
VUE_CLI_BABEL_TRANSPILE_MODULES = true

View File

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

View File

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

View File

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

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.5.17-brightgreen.svg" alt="vue">
<img src="https://img.shields.io/badge/vue-2.6.10-brightgreen.svg" alt="vue">
</a>
<a href="https://github.com/ElemeFE/element">
<img src="https://img.shields.io/badge/element--ui-2.4.11-brightgreen.svg" alt="element-ui">
<img src="https://img.shields.io/badge/element--ui-2.7.0-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 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).
[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).
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,36 +40,31 @@ It is a magical vue admin based on the newest development stack of vue, built-in
- [Gitter](https://gitter.im/vue-element-admin/discuss)
- [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/) 国内用户可访问该地址在线预览
- [Wiki](https://github.com/PanJiaChen/vue-element-admin/wiki)
**This project is positioned as a background integration solution and is not suitable for secondary development as a basic template.**
- [Gitee](https://panjiachen.gitee.io/vue-element-admin/) 国内用户可访问该地址在线预览
- 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))
**This project does not support low version browsers (e.g. IE). Please add polyfill yourself if you need them.**
**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)**
**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)**
**This project does not support low version browsers (e.g. IE). Please add polyfill by yourself.**
## 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/), [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/), [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).
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>
@@ -82,6 +77,7 @@ 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
@@ -105,14 +101,13 @@ 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
@@ -146,6 +141,9 @@ 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
@@ -153,13 +151,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:sit
npm run build:stage
# build for production environment
npm run build:prod
@@ -168,19 +166,16 @@ npm run build:prod
## Advanced
```bash
# --report to build with bundle size analytics
npm run build:prod --report
# preview the release environment effect
npm run preview
# --generate a bundle size analytics. default: bundle-report.html
npm run build:prod --generate_report
# preview the release environment effect + static resource analysis
npm run preview -- --report
# --preview to start a server in local to preview
npm run build:prod --preview
# lint code
# code format check
npm run lint
# auto fix
# code format check and 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.5.10-brightgreen.svg" alt="vue">
<img src="https://img.shields.io/badge/vue-2.6.10-brightgreen.svg" alt="vue">
</a>
<a href="https://github.com/ElemeFE/element">
<img src="https://img.shields.io/badge/element--ui-2.4.11-brightgreen.svg" alt="element-ui">
<img src="https://img.shields.io/badge/element--ui-2.7.0-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,41 +30,37 @@
## 简介
[vue-element-admin](http://panjiachen.github.io/vue-element-admin) 是一个后台集成解决方案,它基于 [vue](https://github.com/vuejs/vue) 和 [element](https://github.com/ElemeFE/element)。它使用了最新的前端技术栈,内置了 i18 国际化解决方案,动态路由,权限验证,提炼了典型的业务模型,提供了丰富的功能组件,它可以帮助你快速搭建企业级中后台产品原型。相信不管你的需求是什么,本项目都能帮助到你。
[vue-element-admin](http://panjiachen.github.io/vue-element-admin) 是一个后台前端解决方案,它基于 [vue](https://github.com/vuejs/vue) 和 [element-ui](https://github.com/ElemeFE/element)实现。它使用了最新的前端技术栈,内置了 i18n 国际化解决方案,动态路由,权限验证,提炼了典型的业务模型,提供了丰富的功能组件,它可以帮助你快速搭建企业级中后台产品原型。相信不管你的需求是什么,本项目都能帮助到你。
- [在线访问](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)
- [Wiki](https://github.com/PanJiaChen/vue-element-admin/wiki)
- [Donate](https://panjiachen.gitee.io/vue-element-admin-site/zh/donate)
- [Gitee](https://panjiachen.gitee.io/vue-element-admin/) 国内用户可访问该地址在线预览
- [Wiki](https://github.com/PanJiaChen/vue-element-admin/wiki)
- [国内访问文档](https://panjiachen.gitee.io/vue-element-admin-site/zh/) 方便没翻墙的用户查看文档
- [Gitee](https://panjiachen.gitee.io/vue-element-admin/) 在线预览(国内用户可访问该地址)
**本项目的定位是后台集成方案,不适合当基础模板来开发。**
- [国内访问文档](https://panjiachen.gitee.io/vue-element-admin-site/zh/) 文档(方便没翻墙的用户查看)
- 模板建议使用: [vue-admin-template](https://github.com/PanJiaChen/vue-admin-template)
- 基础模板建议使用: [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))
群主 **[圈子](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)**
**目前版本为 `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)**
**该项目不支持低版本浏览器(如 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/) 、[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/) 、[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)进行模拟,提前了解和学习这些知识会对使用本项目有很大的帮助。
同时配套一个系列教程文章,如何从零构建后一个完整的后台项目,建议大家先看完这些文章再来实践本项目
同时配套系列教程文章,如何从零构建后一个完整的后台项目,建议大家先看完这些文章再来实践本项目
- [手摸手,带你用 vue 撸后台 系列一(基础篇)](https://juejin.im/post/59097cd7a22b9d0065fb61d2)
- [手摸手,带你用 vue 撸后台 系列二(登录权限篇)](https://juejin.im/post/591aa14f570c35006961acac)
@@ -82,6 +78,7 @@
</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>
@@ -94,6 +91,7 @@ Become a sponsor and get your logo on our README on GitHub with a link to your s
- 权限验证
- 页面权限
- 指令权限
- 权限配置
- 二步登录
- 多环境发布
@@ -106,7 +104,7 @@ Become a sponsor and get your logo on our README on GitHub with a link to your s
- 动态面包屑
- 快捷导航(标签页)
- Svg Sprite 图标
- 本地mock数据
- 本地/后端 mock 数据
- Screenfull全屏
- 自适应收缩侧边栏
@@ -117,14 +115,13 @@ Become a sponsor and get your logo on our README on GitHub with a link to your s
- Excel
- 导出excel
- 导出zip
- 导入excel
- 前端可视化excel
- 导出zip
- 表格
- 动态表格
- 拖拽表格
- 树形表格
- 内联编辑
- 错误页面
@@ -158,6 +155,9 @@ 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:sit
npm run build:stage
# 构建生产环境
npm run build:prod
@@ -183,19 +183,16 @@ npm run build:prod
## 其它
```bash
# --report to build with bundle size analytics
npm run build:prod
# 预览发布环境效果
npm run preview
# --generate a bundle size analytics. default: bundle-report.html
npm run build:prod --generate_report
# 预览发布环境效果 + 静态资源分析
npm run preview -- --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
```
@@ -218,6 +215,8 @@ 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,7 +5,9 @@ const rawArgv = process.argv.slice(2)
const args = rawArgv.join(' ')
if (process.env.npm_config_preview || rawArgv.includes('--preview')) {
run(`vue-cli-service build ${args} --report`)
const report = rawArgv.includes('--report')
run(`vue-cli-service build ${args}`)
const port = 9526
const publicPath = config.publicPath
@@ -21,13 +23,12 @@ if (process.env.npm_config_preview || rawArgv.includes('--preview')) {
})
)
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`)
)
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`))
}
})
} 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

@@ -11,6 +11,10 @@ export function mockXHR() {
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)
}

View File

@@ -30,9 +30,19 @@ 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: tokens[username]
data: token
}
}
},
@@ -43,9 +53,19 @@ 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: users[token]
data: info
}
}
},

View File

@@ -1,7 +1,7 @@
{
"name": "vue-element-admin",
"version": "4.0.0",
"description": "A magical vue admin. Typical templates for enterprise applications. Newest development stack of vue. Lots of awesome features",
"description": "A magical vue admin. An out-of-box UI solution 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,10 +28,12 @@
},
"keywords": [
"vue",
"element-ui",
"admin",
"management-system",
"admin-template"
"dashboard",
"element-ui",
"boilerplate",
"admin-template",
"management-system"
],
"repository": {
"type": "git",
@@ -42,12 +44,12 @@
},
"dependencies": {
"axios": "0.18.0",
"clipboard": "1.7.1",
"clipboard": "2.0.4",
"codemirror": "5.45.0",
"driver.js": "0.9.5",
"dropzone": "5.5.1",
"echarts": "4.2.1",
"element-ui": "2.6.3",
"element-ui": "2.7.0",
"file-saver": "2.0.1",
"fuse.js": "3.4.4",
"js-cookie": "2.2.0",
@@ -56,7 +58,7 @@
"normalize.css": "7.0.0",
"nprogress": "0.2.0",
"path-to-regexp": "2.4.0",
"screenfull": "4.1.0",
"screenfull": "4.2.0",
"showdown": "1.9.0",
"sortablejs": "1.8.4",
"tui-editor": "1.3.3",
@@ -72,9 +74,9 @@
"devDependencies": {
"@babel/core": "7.0.0",
"@babel/register": "7.0.0",
"@vue/cli-plugin-babel": "3.5.1",
"@vue/cli-plugin-unit-jest": "3.5.1",
"@vue/cli-service": "3.5.1",
"@vue/cli-plugin-babel": "3.5.3",
"@vue/cli-plugin-unit-jest": "3.5.3",
"@vue/cli-service": "3.5.3",
"@vue/test-utils": "1.0.0-beta.29",
"babel-core": "7.0.0-bridge.0",
"babel-eslint": "10.0.1",

View File

@@ -1,6 +1,6 @@
import request from '@/utils/request'
export function userSearch(name) {
export function searchUser(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,14 +59,15 @@ 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

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

View File

@@ -2,7 +2,9 @@
<div ref="rightPanel" :class="{show:show}" class="rightPanel-container">
<div class="rightPanel-background" />
<div class="rightPanel">
<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="handle-button" :style="{'top':buttonTop+'px','background-color':theme}" @click="show=!show">
<i :class="show?'el-icon-close':'el-icon-setting'" />
</div>
<div class="rightPanel-items">
<slot />
</div>
@@ -30,6 +32,11 @@ export default {
show: false
}
},
computed: {
theme() {
return this.$store.state.settings.theme
}
},
watch: {
show(value) {
if (value && !this.clickNotClose) {
@@ -130,7 +137,16 @@ 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,6 +17,9 @@ export default {
mounted() {
this.init()
},
beforeDestroy() {
this.destroy()
},
methods: {
click() {
if (!screenfull.enabled) {
@@ -28,11 +31,17 @@ export default {
}
screenfull.toggle()
},
change() {
this.isFullscreen = screenfull.isFullscreen
},
init() {
if (screenfull.enabled) {
screenfull.on('change', () => {
this.isFullscreen = screenfull.isFullscreen
})
screenfull.on('change', this.change)
}
},
destroy() {
if (screenfull.enabled) {
screenfull.off('change', this.change)
}
}
}

View File

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

View File

@@ -1,220 +0,0 @@
- [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

@@ -1,48 +0,0 @@
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

@@ -1,193 +0,0 @@
<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

@@ -43,8 +43,6 @@ export default {
dragTable: 'Drag Table',
inlineEditTable: 'Inline Edit',
complexTable: 'Complex Table',
treeTable: 'Tree Table',
customTreeTable: 'Custom TreeTable',
tab: 'Tab',
form: 'Form',
createArticle: 'Create Article',

View File

@@ -43,8 +43,6 @@ 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

@@ -43,8 +43,6 @@ export default {
dragTable: '拖拽Table',
inlineEditTable: 'Table内编辑',
complexTable: '综合Table',
treeTable: '树形表格',
customTreeTable: '自定义树表',
tab: 'Tab',
form: '表单',
createArticle: '创建文章',

View File

@@ -86,12 +86,6 @@ 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;" />
<theme-picker style="float: right;height: 26px;margin: -3px 8px 0 0;" @change="themeChange" />
</div>
<div class="drawer-item">
@@ -69,6 +69,14 @@ 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 :to="resolvePath(onlyOneChild.path)">
<app-link v-if="onlyOneChild.meta" :to="resolvePath(onlyOneChild.path)">
<el-menu-item :index="resolvePath(onlyOneChild.path)" :class="{'submenu-title-noDropdown':!isNest}">
<item v-if="onlyOneChild.meta" :icon="onlyOneChild.meta.icon||(item.meta&&item.meta.icon)" :title="generateTitle(onlyOneChild.meta.title)" />
<item :icon="onlyOneChild.meta.icon||(item.meta&&item.meta.icon)" :title="generateTitle(onlyOneChild.meta.title)" />
</el-menu-item>
</app-link>
</template>

View File

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

View File

@@ -4,13 +4,12 @@ import Router from 'vue-router'
Vue.use(Router)
/* Layout */
import Layout from '@/layout/Layout'
import Layout from '@/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
@@ -175,7 +174,6 @@ export const asyncRoutes = [
chartsRouter,
nestedRouter,
tableRouter,
treeTableRouter,
{
path: '/example',

View File

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

View File

@@ -1,29 +0,0 @@
/** 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,4 +1,8 @@
import variables from '@/styles/element-variables.scss'
export default {
theme: variables.theme,
/**
* @type {boolean} true | false
* @description Whether show the settings right-panel

View File

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

View File

@@ -23,3 +23,9 @@ $--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

@@ -1,5 +1,5 @@
import axios from 'axios'
import { Message } from 'element-ui'
import { MessageBox, Message } from 'element-ui'
import store from '@/store'
import { getToken } from '@/utils/auth'
@@ -33,40 +33,39 @@ 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,
// 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
// }
// },
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 res
}
},
error => {
console.log('err' + error) // for debug
Message({

View File

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

View File

@@ -1,7 +1,7 @@
<template>
<div class="createPost-container">
<el-form ref="postForm" :model="postForm" :rules="rules" class="form-container">
<sticky :class-name="'sub-navbar '+postForm.status">
<sticky :z-index="10" :class-name="'sub-navbar '+postForm.status">
<CommentDropdown v-model="postForm.comment_disabled" />
<PlatformDropdown v-model="postForm.platforms" />
<SourceUrlDropdown v-model="postForm.source_uri" />
@@ -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 { userSearch } from '@/api/remoteSearch'
import { searchUser } 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) {
userSearch(query).then(response => {
searchUser(query).then(response => {
if (!response.data.items) return
this.userListOptions = response.data.items.map(v => v.name)
})

View File

@@ -95,14 +95,6 @@ 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

@@ -14,6 +14,7 @@
<svg-icon icon-class="user" />
</span>
<el-input
ref="username"
v-model="loginForm.username"
:placeholder="$t('login.username')"
name="username"
@@ -27,6 +28,8 @@
<svg-icon icon-class="password" />
</span>
<el-input
:key="passwordType"
ref="password"
v-model="loginForm.password"
:type="passwordType"
:placeholder="$t('login.password')"
@@ -97,7 +100,7 @@ export default {
return {
loginForm: {
username: 'admin',
password: '1111111'
password: '111111'
},
loginRules: {
username: [{ required: true, trigger: 'blur', validator: validateUsername }],
@@ -120,6 +123,13 @@ 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)
},
@@ -130,6 +140,9 @@ export default {
} else {
this.passwordType = 'password'
}
this.$nextTick(() => {
this.$refs.password.focus()
})
},
handleLogin() {
this.$refs.loginForm.validate(valid => {
@@ -176,16 +189,12 @@ export default {
/* Detail see https://github.com/PanJiaChen/vue-element-admin/pull/927 */
$bg:#283443;
$light_gray:#eee;
$light_gray:#fff;
$cursor: #fff;
@supports (-webkit-mask: none) and (not (cater-color: $cursor)) {
.login-container .el-input input {
color: $cursor;
&::first-line {
color: $light_gray;
}
}
}
@@ -207,7 +216,7 @@ $cursor: #fff;
caret-color: $cursor;
&:-webkit-autofill {
-webkit-box-shadow: 0 0 0px 1000px $bg inset !important;
box-shadow: 0 0 0px 1000px $bg inset !important;
-webkit-text-fill-color: $cursor !important;
}
}

View File

@@ -1,51 +0,0 @@
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

@@ -1,159 +0,0 @@
<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

@@ -1,80 +0,0 @@
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

@@ -1,126 +0,0 @@
<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

@@ -1,23 +1,22 @@
'use strict'
const path = require('path')
const pkg = require('./package.json')
function resolve(dir) {
return path.join(__dirname, dir)
}
const name = 'vue-element-admin'
const name = pkg.name || 'vue-element-admin' // page title
const port = 9527 // dev port
// Explanation of each configuration item You can find it in https://cli.vuejs.org/config/
// All configuration item explanations can be find in https://cli.vuejs.org/config/
module.exports = {
/**
* 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/".
* 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/".
* In most cases please use '/' !!!
* Detail https://cli.vuejs.org/config/#publicPath
* Detail: https://cli.vuejs.org/config/#publicpath
*/
publicPath: '/',
outputDir: 'dist',
@@ -32,11 +31,13 @@ module.exports = {
errors: true
},
proxy: {
'/api': {
// change xxx-api/login => mock/login
// detail: https://cli.vuejs.org/config/#devserver-proxy
[process.env.VUE_APP_BASE_API]: {
target: `http://localhost:${port}/mock`,
changeOrigin: true,
pathRewrite: {
'^/api': ''
['^' + process.env.VUE_APP_BASE_API]: ''
}
}
},
@@ -58,7 +59,7 @@ module.exports = {
}
},
configureWebpack: {
// We provide the app's title in Webpack's name field, so that
// 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: {
@@ -70,6 +71,8 @@ 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'))
@@ -85,6 +88,8 @@ module.exports = {
symbolId: 'icon-[name]'
})
.end()
// set preserveWhitespace
config.module
.rule('vue')
.use('vue-loader')
@@ -94,6 +99,7 @@ module.exports = {
return options
})
.end()
config
.when(process.env.NODE_ENV === 'development',
config => config.devtool('cheap-source-map')
@@ -118,17 +124,17 @@ module.exports = {
name: 'chunk-libs',
test: /[\\/]node_modules[\\/]/,
priority: 10,
chunks: 'initial' // 只打包初始时依赖的第三方
chunks: 'initial' // only package third parties that are initially dependent
},
elementUI: {
name: 'chunk-elementUI', // 单独将 elementUI 拆包
priority: 20, // 权重要大于 libs app 不然会被打包进 libs 或者 app
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[\\/]/
},
commons: {
name: 'chunk-commons',
test: resolve('src/components'), // 可自定义拓展你的规则
minChunks: 3, // 最小公用次数
test: resolve('src/components'), // can customize your rules
minChunks: 3, // minimum common number
priority: 5,
reuseExistingChunk: true
}