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
82 changed files with 574 additions and 1575 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

@@ -1,52 +0,0 @@
#!/usr/bin/env node
'use strict'
const checker = require('../lib/checkSystem.js')
const colors = require('colors')
// set color theme
colors.setTheme({
success: 'green',
info: 'grey',
warn: 'yellow',
error: 'red',
boldWarn: ['bold', 'yellow'],
boldUnderlineSuccess: ['bold', 'underline', 'green'],
boldUnderlineError: ['bold', 'underline', 'red']
})
console.log('Checking versions...'.info, '\n')
checker(process.argv[2]).then((result) => {
// check if the process should exit prematurely
if (result.status != 0) {
console.log(colors[result.message.type](result.message.text))
process.exit(result.status)
}
// print out results for each package
result.packages.forEach((p) => {
if (p.type === 'success') {
console.log(('✔ ' + colors.bold(p.name) + ' was validated with ' + p.expectedVersion + '.').success)
} else if (p.type === 'warn') {
console.log((colors.bold(p.name) + ' was expected, but no validator found!').warn)
} else if (p.type === 'error' && p.commandError) {
console.log(('✘ Error validating ' + colors.bold(p.name) + ': ' + p.commandError).error)
} else if (p.type === 'error' && !p.commandError) {
console.log((
'✘ ' + colors.bold(p.name) +
' version is incorrect! Expected ' +
p.expectedVersion + ' but was ' + p.foundVersion + '.'
).error)
}
})
// print out a summary message
if (result.message.type === 'success') {
console.log('\n', result.message.text.boldUnderlineSuccess)
} else {
console.log('\n', result.message.text.boldUnderlineError)
process.exit(1)
}
})

View File

@@ -5,6 +5,8 @@ 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}`)
const port = 9526
@@ -21,10 +23,12 @@ if (process.env.npm_config_preview || rawArgv.includes('--preview')) {
})
)
app.listen(port, function() {
console.log(
chalk.green(`> Listening at http://localhost:${port}${publicPath}`)
)
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

@@ -1,122 +0,0 @@
'use strict'
const check = function(pathToPackage) {
const path = require('path')
const Promise = require('bluebird')
const exec = Promise.promisify(require('child_process').exec)
const _ = require('lodash')
const fs = require('fs')
const jsonfile = require('jsonfile')
const validaterRules = require('./validatorRules')
const promiseHelpers = require('./promiseHelpers')
let engines
const checkerResult = {
status: 0,
message: '',
packages: []
}
const packageJsonPath = pathToPackage || path.join(process.cwd(), 'package.json')
try {
fs.accessSync(packageJsonPath)
engines = jsonfile.readFileSync(packageJsonPath).engines
} catch (ex) {
checkerResult.message = {
text: '✘ No package.json found in the current directory so I can\'t validate what you need!',
type: 'error'
}
checkerResult.status = -1
return Promise.resolve(checkerResult)
}
if (!engines) {
checkerResult.message = {
text: '✘ No engines found in package.json so I can\'t validate what you need!',
type: 'error'
}
checkerResult.status = -1
return Promise.resolve(checkerResult)
}
const thingsToCheck = Object.getOwnPropertyNames(engines)
const validatorPromises = thingsToCheck.map(validate) // run the function over all items.
return promiseHelpers.allSettled(validatorPromises)
.then((inspections) => {
const environmentIsValid = _.every(inspections,
(inspection) => inspection.isFulfilled() && inspection.value())
if (environmentIsValid) {
checkerResult.message = {
text: 'Environment looks good!',
type: 'success'
}
} else {
checkerResult.message = {
text: 'Environment is invalid!',
type: 'error'
}
}
return checkerResult
})
function validate(name) {
// find it in the validators
const validator = validaterRules[name]
if (validator === undefined) {
checkerResult.packages.push({
name: name,
validatorFound: false,
type: 'warn'
})
return Promise.resolve(false)
}
// call the validator and pass in the version we expect
return execAndCheck(validator, engines[name]).then((results) => {
if (results.result) {
checkerResult.packages.push({
name: name,
validatorFound: true,
expectedVersion: engines[name],
foundVersion: engines[name],
type: 'success'
})
} else {
checkerResult.packages.push({
name: name,
validatorFound: true,
expectedVersion: engines[name],
foundVersion: results.reason.trim() || 'missing',
type: 'error'
})
}
return Promise.resolve(results.result)
}).catch((error) => {
checkerResult.packages.push({
name: name,
validatorFound: true,
expectedVersion: engines[name],
commandError: error,
type: 'error'
})
return Promise.reject()
})
}
function execAndCheck(validator, expectedVersion) {
return exec(validator.versionCheck).then((result) => {
return {
result: validator.versionValidate(result, expectedVersion),
reason: result
}
}).catch((e) => { throw e })
}
}
module.exports = check

View File

@@ -1,24 +0,0 @@
const Promise = require('bluebird')
/**
* Creates a promise that is resolved when all input promises have been
* settled. The returned Promise is resolved with an array of
* Promise.Inspection objects.
*
* This is the commonly accepted way of implementing allSettled() in Bluebird.
* See: http://bluebirdjs.com/docs/api/reflect.html
*
* @param promises - The array of input promises.
* @returns {Promise<Promise.Inspection[]>} A promise that will be resolved once
* all input Promises have settled. The returned Promise will be resolved with a
* corresponding array of Promise.Inspection objects.
*/
function allSettled(promises) {
'use strict'
const wrappedPromises = promises.map((curPromise) => curPromise.reflect())
return Promise.all(wrappedPromises)
}
module.exports = {
allSettled: allSettled
}

View File

@@ -1,141 +0,0 @@
'use strict'
const semver = require('semver')
module.exports = {
osx: {
versionCheck: 'sw_vers -productVersion',
versionValidate:
(detectedVersion, expectedVersion) => expectedVersion === detectedVersion.trim()
},
node: {
versionCheck: 'node -v',
versionValidate:
(detectedVersion, expectedVersion) => semver.satisfies(detectedVersion, expectedVersion)
},
npm: {
versionCheck: 'npm -v',
versionValidate:
(detectedVersion, expectedVersion) => semver.satisfies(detectedVersion, expectedVersion)
},
jx: {
versionCheck: 'jx -jxv',
versionValidate:
(result, version) => 'v' + version === result.trim()
},
cordova: {
versionCheck: 'cordova -v',
versionValidate:
(result, version) => version === result.trim()
},
appium: {
versionCheck: 'appium -v',
versionValidate:
(result, version) => version === result.trim()
},
'ios-deploy': {
versionCheck: 'ios-deploy -V',
versionValidate:
(result, version) => version === result.trim()
},
'ios-sim': {
versionCheck: 'ios-sim --version',
versionValidate:
(result, version) => version === result.trim()
},
bower: {
versionCheck: 'bower -v',
versionValidate:
(result, version) => semver.satisfies(result, version)
},
'ios-webkit-debug-proxy': {
versionCheck: 'brew list ios-webkit-debug-proxy --versions',
versionValidate:
(result, version) => result.includes(version)
},
'ideviceinstaller': {
versionCheck: 'brew list ideviceinstaller --versions',
versionValidate:
(result, version) => result.includes(version)
},
java: {
versionCheck: 'javac -version 2>&1',
versionValidate:
(result, version) => result.includes(version)
},
ant: {
versionCheck: 'ant -version',
versionValidate:
(result, version) => result.includes(version)
},
adb: {
versionCheck: 'adb version',
versionValidate:
(result, version) => result.includes(version)
},
git: {
versionCheck: 'git --version',
versionValidate:
(result, version) => {
// http://stackoverflow.com/questions/82064/a-regex-for-version-number-parsing
const found = result.match(/(\d+\.)?(\d+\.)?(\d+)/i)
return found[0] === version
}
},
windows: {
versionCheck: 'ver',
versionValidate:
(result, version) => result.includes(version)
},
'gulp-cli': {
versionCheck: 'npm list --depth=0 -g |grep gulp-cli',
versionValidate:
(result, version) => result.includes(version)
},
cocoapods: {
versionCheck: 'pod --version',
versionValidate:
(result, version) => version === result.trim()
},
xcodebuild: {
versionCheck: 'xcodebuild -version',
versionValidate:
(result, version) => result.includes(version)
},
carthage: {
versionCheck: 'carthage version',
versionValidate:
(result, version) => version === result.trim()
},
xcpretty: {
versionCheck: 'xcpretty -v',
versionValidate:
(result, version) => version === result.trim()
},
libimobiledevice: {
versionCheck: 'brew list --versions |grep libimobiledevice',
versionValidate:
(result, version) => result.includes(version)
},
'deviceconsole': {
versionCheck: 'npm list --depth=0 -g |grep deviceconsole',
versionValidate:
(result, version) => result.includes(version)
},
'check-engine': {
versionCheck: 'npm list --depth=0 -g |grep check-engine',
versionValidate:
(result, version) => result.includes(version)
},
yarn: {
versionCheck: 'yarn -v',
versionValidate:
(result, version) => semver.satisfies(result, version)
},
nsp: {
versionCheck: 'nsp --version',
versionValidate:
(result, version) => version === result.trim()
}
}

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,18 +1,17 @@
{
"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": {
"dev": "vue-cli-service serve",
"build:prod": "vue-cli-service build",
"build:stage": "vue-cli-service build --mode staging",
"build:preview": "node build/index.js --preview",
"build:report": "node build/index.js --report",
"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"
},
@@ -29,10 +28,12 @@
},
"keywords": [
"vue",
"element-ui",
"admin",
"management-system",
"admin-template"
"dashboard",
"element-ui",
"boilerplate",
"admin-template",
"management-system"
],
"repository": {
"type": "git",
@@ -43,49 +44,50 @@
},
"dependencies": {
"axios": "0.18.0",
"clipboard": "1.7.1",
"codemirror": "5.44.0",
"clipboard": "2.0.4",
"codemirror": "5.45.0",
"driver.js": "0.9.5",
"dropzone": "5.5.1",
"echarts": "4.1.0",
"element-ui": "2.6.1",
"echarts": "4.2.1",
"element-ui": "2.7.0",
"file-saver": "2.0.1",
"fuse.js": "3.4.4",
"js-cookie": "2.2.0",
"jsonlint": "1.6.3",
"jszip": "3.2.0",
"jszip": "3.2.1",
"normalize.css": "7.0.0",
"nprogress": "0.2.0",
"path-to-regexp": "2.4.0",
"screenfull": "4.0.1",
"screenfull": "4.2.0",
"showdown": "1.9.0",
"sortablejs": "1.8.3",
"tui-editor": "1.3.2",
"vue": "2.6.8",
"sortablejs": "1.8.4",
"tui-editor": "1.3.3",
"vue": "2.6.10",
"vue-count-to": "1.0.13",
"vue-i18n": "7.3.2",
"vue-router": "3.0.2",
"vue-splitpane": "1.0.2",
"vuedraggable": "2.17.0",
"vue-splitpane": "1.0.4",
"vuedraggable": "2.20.0",
"vuex": "3.1.0",
"xlsx": "0.14.1"
},
"devDependencies": {
"@babel/core": "7.0.0",
"@babel/register": "7.0.0",
"@vue/cli-plugin-babel": "3.5.0",
"@vue/cli-plugin-unit-jest": "3.5.0",
"@vue/cli-service": "3.5.0",
"@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",
"babel-jest": "23.6.0",
"chalk": "2.4.2",
"connect": "3.6.6",
"eslint": "5.15.1",
"eslint": "5.15.3",
"eslint-plugin-vue": "5.2.2",
"html-webpack-plugin": "3.2.0",
"husky": "1.3.1",
"lint-staged": "7.2.2",
"lint-staged": "8.1.5",
"mockjs": "1.0.1-beta3",
"node-sass": "^4.9.0",
"plop": "2.3.0",
@@ -96,7 +98,7 @@
"serve-static": "^1.13.2",
"svg-sprite-loader": "4.1.3",
"svgo": "1.2.0",
"vue-template-compiler": "2.6.8"
"vue-template-compiler": "2.6.10"
},
"engines": {
"node": ">=8.9",

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

@@ -58,15 +58,16 @@ export default {
}
</script>
<style rel="stylesheet/scss" 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;
}
<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;
}
}
</style>

View File

@@ -2,7 +2,7 @@
<div class="dndList">
<div :style="{width:width1}" class="dndList-list">
<h3>{{ list1Title }}</h3>
<draggable :list="list1" :options="{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 }}
@@ -17,7 +17,7 @@
</div>
<div :style="{width:width2}" class="dndList-list">
<h3>{{ list2Title }}</h3>
<draggable :list="list2" :options="{group:'article'}" class="dragArea">
<draggable :list="list2" group="article" class="dragArea">
<div v-for="element in list2" :key="element.id" class="list-complete-item">
<div class="list-complete-item-handle2" @click="pushEle(element)">
{{ element.id }} [{{ element.author }}] {{ element.title }}
@@ -99,7 +99,7 @@ export default {
}
</script>
<style rel="stylesheet/scss" lang="scss" scoped>
<style lang="scss" scoped>
.dndList {
background: #fff;
padding-bottom: 40px;

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

@@ -5,7 +5,7 @@
</div>
<draggable
:list="list"
:options="options"
v-bind="$attrs"
class="board-column-content"
>
<div v-for="element in list" :key="element.id" class="board-item">

View File

@@ -197,7 +197,7 @@ export default {
}
</script>
<style rel="stylesheet/scss" lang="scss" scoped>
<style lang="scss" scoped>
// Fonts:
$font-size-base: 16px;
$font-size-small: 18px;

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>
@@ -21,7 +23,7 @@ export default {
type: Boolean
},
buttonTop: {
default: 240,
default: 250,
type: Number
}
},
@@ -30,6 +32,11 @@ export default {
show: false
}
},
computed: {
theme() {
return this.$store.state.settings.theme
}
},
watch: {
show(value) {
if (value && !this.clickNotClose) {
@@ -77,7 +84,7 @@ export default {
}
</style>
<style rel="stylesheet/scss" lang="scss" scoped>
<style lang="scss" scoped>
.rightPanel-background {
opacity: 0;
transition: opacity .3s cubic-bezier(.7, .3, .1, 1);
@@ -108,7 +115,6 @@ export default {
}
.show {
transition: all .3s cubic-bezier(.7, .3, .1, 1);
.rightPanel-background {
@@ -131,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

@@ -37,7 +37,7 @@ export default {
}
</script>
<style rel="stylesheet/scss" lang="scss" >
<style lang="scss" >
$n: 8; //和items.length 相同
$t: .1s;
.share-dropdown-menu {

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

@@ -101,7 +101,7 @@ export default {
}
</script>
<style rel="stylesheet/scss" lang="scss" scoped>
<style lang="scss" scoped>
.editor-slide-upload {
margin-bottom: 20px;
/deep/ .el-upload--picture-card {

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

@@ -78,7 +78,7 @@ export default {
}
</script>
<style rel="stylesheet/scss" lang="scss" scoped>
<style lang="scss" scoped>
@import "~@/styles/mixin.scss";
.upload-container {
width: 100%;

View File

@@ -76,7 +76,7 @@ export default {
}
</script>
<style rel="stylesheet/scss" lang="scss" scoped>
<style lang="scss" scoped>
.upload-container {
width: 100%;
height: 100%;

View File

@@ -85,7 +85,7 @@ export default {
}
</script>
<style rel="stylesheet/scss" lang="scss" scoped>
<style lang="scss" scoped>
@import "~@/styles/mixin.scss";
.upload-container {
width: 100%;

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',
@@ -163,5 +161,12 @@ export default {
close: 'Close',
closeOthers: 'Close Others',
closeAll: 'Close All'
},
settings: {
title: 'Page style setting',
theme: 'Theme Color',
tagsView: 'Open Tags-View',
fixedHeader: 'Fixed Header',
sidebarLogo: 'Sidebar Logo'
}
}

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',
@@ -163,5 +161,12 @@ export default {
close: 'Cerrar',
closeOthers: 'Cerrar otros',
closeAll: 'Cerrar todos'
},
settings: {
title: 'Page style setting',
theme: 'Theme Color',
tagsView: 'Open Tags-View',
fixedHeader: 'Fixed Header',
sidebarLogo: 'Sidebar Logo'
}
}

View File

@@ -43,8 +43,6 @@ export default {
dragTable: '拖拽Table',
inlineEditTable: 'Table内编辑',
complexTable: '综合Table',
treeTable: '树形表格',
customTreeTable: '自定义树表',
tab: 'Tab',
form: '表单',
createArticle: '创建文章',
@@ -163,5 +161,12 @@ export default {
close: '关闭',
closeOthers: '关闭其它',
closeAll: '关闭所有'
},
settings: {
title: '系统布局配置',
theme: '主题色',
tagsView: '开启 Tags-View',
fixedHeader: '固定 Header',
sidebarLogo: '侧边栏 Logo'
}
}

View File

@@ -22,9 +22,9 @@ export default {
}
</script>
<style rel="stylesheet/scss" lang="scss" scoped>
<style lang="scss" scoped>
.app-main {
/*50= navbar 50 */
/* 50= navbar 50 */
min-height: calc(100vh - 50px);
width: 100%;
position: relative;
@@ -32,17 +32,17 @@ export default {
}
.fixed-header+.app-main {
margin-top: 50px;
padding-top: 50px;
}
.hasTagsView {
.app-main {
/*84 = navbar + tags-view = 50 + 34 */
/* 84 = navbar + tags-view = 50 + 34 */
min-height: calc(100vh - 84px);
}
.fixed-header+.app-main {
margin-top: 80px;
padding-top: 84px;
}
}
</style>

View File

@@ -85,13 +85,7 @@ export default {
}
</script>
<style rel="stylesheet/scss" lang="scss" scoped>
.hasTagsView {
.navbar {
border-bottom: none;
}
}
<style lang="scss" scoped>
.navbar {
height: 50px;
overflow: hidden;
@@ -105,6 +99,7 @@ export default {
float: left;
cursor: pointer;
transition: background .3s;
-webkit-tap-highlight-color:transparent;
&:hover {
background: rgba(0, 0, 0, .025)

View File

@@ -1,25 +1,28 @@
<template>
<div class="drawer-container">
<div>
<h3 class="drawer-title">
系统布局配置
</h3>
<h3 class="drawer-title">{{ $t('settings.title') }}</h3>
<div class="drawer-item">
<span>主题色</span>
<theme-picker style="float: right;height: 26px;margin: -3px 5px 0 0;" />
<span>{{ $t('settings.theme') }}</span>
<theme-picker style="float: right;height: 26px;margin: -3px 8px 0 0;" @change="themeChange" />
</div>
<div class="drawer-item">
<span>开启 Tags-View</span>
<span>{{ $t('settings.tagsView') }}</span>
<el-switch v-model="tagsView" class="drawer-switch" />
</div>
<div class="drawer-item">
<span>固定 Header</span>
<span>{{ $t('settings.fixedHeader') }}</span>
<el-switch v-model="fixedHeader" class="drawer-switch" />
</div>
<div class="drawer-item">
<span>{{ $t('settings.sidebarLogo') }}</span>
<el-switch v-model="sidebarLogo" class="drawer-switch" />
</div>
</div>
</div>
</template>
@@ -30,9 +33,7 @@ import ThemePicker from '@/components/ThemePicker'
export default {
components: { ThemePicker },
data() {
return {
sidebarLogo: true
}
return {}
},
computed: {
fixedHeader: {
@@ -56,12 +57,31 @@ export default {
value: val
})
}
},
sidebarLogo: {
get() {
return this.$store.state.settings.sidebarLogo
},
set(val) {
this.$store.dispatch('settings/changeSetting', {
key: 'sidebarLogo',
value: val
})
}
}
},
methods: {
themeChange(val) {
this.$store.dispatch('settings/changeSetting', {
key: 'theme',
value: val
})
}
}
}
</script>
<style rel="stylesheet/scss" lang="scss" scoped>
<style lang="scss" scoped>
.drawer-container {
padding: 24px;
font-size: 14px;

View File

@@ -0,0 +1,82 @@
<template>
<div class="sidebar-logo-container" :class="{'collapse':collapse}">
<transition name="sidebarLogoFade">
<router-link v-if="collapse" key="collapse" class="sidebar-logo-link" to="/">
<img v-if="logo" :src="logo" class="sidebar-logo">
<h1 v-else class="sidebar-title">{{ title }} </h1>
</router-link>
<router-link v-else key="expand" class="sidebar-logo-link" to="/">
<img v-if="logo" :src="logo" class="sidebar-logo">
<h1 class="sidebar-title">{{ title }} </h1>
</router-link>
</transition>
</div>
</template>
<script>
export default {
name: 'SidebarLogo',
props: {
collapse: {
type: Boolean,
required: true
}
},
data() {
return {
title: 'Vue Element Admin',
logo: 'https://wpimg.wallstcn.com/69a1c46c-eb1c-4b46-8bd4-e9e686ef5251.png'
}
}
}
</script>
<style lang="scss" scoped>
.sidebarLogoFade-enter-active {
transition: opacity 1.5s;
}
.sidebarLogoFade-enter,
.sidebarLogoFade-leave-to {
opacity: 0;
}
.sidebar-logo-container {
position: relative;
width: 100%;
height: 50px;
line-height: 50px;
background: #2b2f3a;
text-align: center;
overflow: hidden;
& .sidebar-logo-link {
height: 100%;
width: 100%;
& .sidebar-logo {
width: 32px;
height: 32px;
vertical-align: middle;
margin-right: 12px;
}
& .sidebar-title {
display: inline-block;
margin: 0;
color: #fff;
font-weight: 600;
line-height: 50px;
font-size: 14px;
font-family: Avenir, Helvetica Neue, Arial, Helvetica, sans-serif;
vertical-align: middle;
}
}
&.collapse {
.sidebar-logo {
margin-right: 0px;
}
}
}
</style>

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

@@ -1,31 +1,38 @@
<template>
<el-scrollbar wrap-class="scrollbar-wrapper">
<el-menu
:default-active="$route.path"
:collapse="isCollapse"
:background-color="variables.menuBg"
:text-color="variables.menuText"
:active-text-color="variables.menuActiveText"
:collapse-transition="false"
mode="vertical"
>
<sidebar-item v-for="route in permission_routes" :key="route.path" :item="route" :base-path="route.path" />
</el-menu>
</el-scrollbar>
<div :class="{'has-logo':showLogo}">
<logo v-if="showLogo" :collapse="isCollapse" />
<el-scrollbar wrap-class="scrollbar-wrapper">
<el-menu
:default-active="$route.path"
:collapse="isCollapse"
:background-color="variables.menuBg"
:text-color="variables.menuText"
:active-text-color="variables.menuActiveText"
:collapse-transition="false"
mode="vertical"
>
<sidebar-item v-for="route in permission_routes" :key="route.path" :item="route" :base-path="route.path" />
</el-menu>
</el-scrollbar>
</div>
</template>
<script>
import { mapGetters } from 'vuex'
import Logo from './Logo'
import SidebarItem from './SidebarItem'
import variables from '@/styles/variables.scss'
export default {
components: { SidebarItem },
components: { SidebarItem, Logo },
computed: {
...mapGetters([
'permission_routes',
'sidebar'
]),
showLogo() {
return this.$store.state.settings.sidebarLogo
},
variables() {
return variables
},

View File

@@ -67,7 +67,7 @@ export default {
}
</script>
<style rel="stylesheet/scss" lang="scss" scoped>
<style lang="scss" scoped>
.scroll-container {
white-space: nowrap;
position: relative;

View File

@@ -196,7 +196,7 @@ export default {
}
</script>
<style rel="stylesheet/scss" lang="scss" scoped>
<style lang="scss" scoped>
.tags-view-container {
height: 34px;
width: 100%;
@@ -264,7 +264,7 @@ export default {
}
</style>
<style rel="stylesheet/scss" lang="scss">
<style lang="scss">
//reset element css of el-icon-close
.tags-view-wrapper {
.tags-view-item {

View File

@@ -57,7 +57,7 @@ export default {
}
</script>
<style rel="stylesheet/scss" lang="scss" scoped>
<style lang="scss" scoped>
@import "~@/styles/mixin.scss";
@import "~@/styles/variables.scss";
@@ -66,11 +66,13 @@ export default {
position: relative;
height: 100%;
width: 100%;
&.mobile.openSidebar{
&.mobile.openSidebar {
position: fixed;
top: 0;
}
}
.drawer-bg {
background: #000;
opacity: 0.3;
@@ -80,18 +82,21 @@ export default {
position: absolute;
z-index: 999;
}
.fixed-header{
.fixed-header {
position: fixed;
top: 0;
right: 0;
z-index: 9;
width: calc(100% - #{$sideBarWidth});
transition: width 0.28s;
transition: width 0.28s;
}
.hideSidebar .fixed-header{
width: calc(100% - 54px)
.hideSidebar .fixed-header {
width: calc(100% - 54px)
}
.mobile .fixed-header{
.mobile .fixed-header {
width: 100%;
}
</style>

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
@@ -33,6 +32,12 @@ import nestedRouter from './modules/nested'
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',
@@ -105,6 +110,10 @@ export const constantRoutes = [
}
]
/**
* asyncRoutes
* the routes that need to be dynamically loaded based on user roles
*/
export const asyncRoutes = [
{
path: '/permission',
@@ -160,12 +169,11 @@ export const asyncRoutes = [
]
},
/** When your routing table is too long, you can split it into small modules**/
/** when your routing map is too long, you can split it into small modules **/
componentsRouter,
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,5 +1,7 @@
import variables from '@/styles/element-variables.scss'
export default {
title: 'vue-element-admin',
theme: variables.theme,
/**
* @type {boolean} true | false
@@ -17,7 +19,13 @@ export default {
* @type {boolean} true | false
* @description Whether fix the header
*/
fixedHeader: true,
fixedHeader: false,
/**
* @type {boolean} true | false
* @description Whether show the logo in sidebar
*/
sidebarLogo: false,
/**
* @type {string | array} 'production' | ['production','development']

View File

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

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

@@ -38,6 +38,16 @@
right: 0px;
}
.el-scrollbar {
height: 100%;
}
&.has-logo {
.el-scrollbar {
height: calc(100% - 50px);
}
}
.is-horizontal {
display: none;
}
@@ -100,6 +110,7 @@
.el-tooltip {
padding: 0 !important;
.svg-icon {
margin-left: 20px;
}
@@ -111,6 +122,7 @@
&>.el-submenu__title {
padding: 0 !important;
.svg-icon {
margin-left: 20px;
}

View File

@@ -1,4 +1,4 @@
//globl transition css
//global transition css
/*fade*/
.fade-enter-active,

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

@@ -26,10 +26,10 @@
<input v-model.number="setDuration" type="number" name="durationInput">
</label>
<div class="startBtn example-btn" @click="start">
开始
Start
</div>
<div class="pause-resume-btn example-btn" @click="pauseResume">
暂停/恢复
pause/resume
</div>
<br>
<label class="label" for="decimalsInput">decimals:

View File

@@ -1,8 +1,8 @@
<template>
<div class="components-container board">
<Kanban :key="1" :list="list1" :options="options" class="kanban todo" header-text="Todo" />
<Kanban :key="2" :list="list2" :options="options" class="kanban working" header-text="Working" />
<Kanban :key="3" :list="list3" :options="options" class="kanban done" header-text="Done" />
<Kanban :key="1" :list="list1" :group="group" class="kanban todo" header-text="Todo" />
<Kanban :key="2" :list="list2" :group="group" class="kanban working" header-text="Working" />
<Kanban :key="3" :list="list3" :group="group" class="kanban done" header-text="Done" />
</div>
</template>
<script>
@@ -15,9 +15,7 @@ export default {
},
data() {
return {
options: {
group: 'mission'
},
group: 'mission',
list1: [
{ name: 'Mission', id: 1 },
{ name: 'Mission', id: 2 },

View File

@@ -1,6 +1,10 @@
<template>
<div class="components-container">
<code>JsonEditor is base on <a href="https://github.com/codemirror/CodeMirror" target="_blank">CodeMirrorr</a> , lint base on json-lint </code>
<code>Json-Editor is base on <a href="https://github.com/codemirror/CodeMirror" target="_blank">CodeMirrorr</a>. Lint
base on <a
href="https://github.com/codemirror/CodeMirror/blob/master/addon/lint/json-lint.js"
target="_blank"
>json-lint</a>.</code>
<div class="editor-container">
<json-editor ref="jsonEditor" v-model="value" />
</div>

View File

@@ -1,8 +1,11 @@
<template>
<div class="components-container">
<code>Markdown is based on
<a href="https://github.com/nhnent/tui.editor" target="_blank">tui.editor</a> Simply encapsulated in Vue.
<a target="_blank" href="https://panjiachen.github.io/vue-element-admin-site/feature/component/markdown-editor.html">
<a href="https://github.com/nhnent/tui.editor" target="_blank">tui.editor</a> simply wrapped with Vue.
<a
target="_blank"
href="https://panjiachen.github.io/vue-element-admin-site/feature/component/markdown-editor.html"
>
Documentation </a>
</code>
@@ -10,33 +13,33 @@
<el-tag class="tag-title">
Basic:
</el-tag>
<markdown-editor v-model="content" height="300px" />
<markdown-editor v-model="content1" height="300px" />
</div>
<div class="editor-container">
<el-tag class="tag-title">
Markdown Mode:
</el-tag>
<markdown-editor ref="markdownEditor" v-model="content" :options="{hideModeSwitch:true,previewStyle:'tab'}" height="200px" />
<markdown-editor ref="markdownEditor" v-model="content2" :options="{hideModeSwitch:true,previewStyle:'tab'}" height="200px" />
</div>
<div class="editor-container">
<el-tag class="tag-title">
Customize Toolbar:
</el-tag>
<markdown-editor
ref="markdownEditor"
v-model="content"
:options="{ toolbarItems: ['heading','bold','italic']}"
/>
<markdown-editor v-model="content3" :options="{ toolbarItems: ['heading','bold','italic']}" />
</div>
<div class="editor-container">
<el-tag class="tag-title">
I18n:
</el-tag>
<el-alert :closable="false" title="You can change the language of the admin system to see the effect" type="success" />
<markdown-editor v-model="content" :language="language" height="300px" />
<el-alert
:closable="false"
title="You can change the language of the admin system to see the effect"
type="success"
/>
<markdown-editor ref="markdownEditor" v-model="content4" :language="language" height="300px" />
</div>
<el-button style="margin-top:80px;" type="primary" icon="el-icon-document" @click="getHtml">
@@ -62,7 +65,10 @@ export default {
components: { MarkdownEditor },
data() {
return {
content: content,
content1: content,
content2: content,
content3: content,
content4: content,
html: '',
languageTypeList: {
'en': 'en_US',

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

@@ -61,14 +61,14 @@ export default {
}
</script>
<style rel="stylesheet/scss" lang="scss" >
<style lang="scss" >
.box-card-component{
.el-card__header {
padding: 0px!important;
}
}
</style>
<style rel="stylesheet/scss" lang="scss" scoped>
<style lang="scss" scoped>
.box-card-component {
.box-card-header {
position: relative;

View File

@@ -70,7 +70,7 @@ export default {
}
</script>
<style rel="stylesheet/scss" lang="scss" scoped>
<style lang="scss" scoped>
.panel-group {
margin-top: 18px;
.card-panel-col{

View File

@@ -96,7 +96,7 @@ export default {
}
</script>
<style rel="stylesheet/scss" lang="scss" scoped>
<style lang="scss" scoped>
.dashboard-editor-container {
padding: 32px;
background-color: rgb(240, 242, 245);

View File

@@ -40,7 +40,7 @@ export default {
}
</script>
<style rel="stylesheet/scss" lang="scss" scoped>
<style lang="scss" scoped>
.emptyGif {
display: block;
width: 45%;

View File

@@ -29,7 +29,7 @@ export default {
}
</script>
<style rel="stylesheet/scss" lang="scss" scoped>
<style lang="scss" scoped>
.documentation-container {
margin: 50px;
.document-btn {

View File

@@ -58,7 +58,7 @@ export default {
}
</script>
<style rel="stylesheet/scss" lang="scss" scoped>
<style lang="scss" scoped>
.errPage-container {
width: 800px;
max-width: 100%;

View File

@@ -41,7 +41,7 @@ export default {
}
</script>
<style rel="stylesheet/scss" lang="scss" scoped>
<style lang="scss" scoped>
.wscn-http404-container{
transform: translate(-50%,-50%);
position: absolute;

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)
})
@@ -234,7 +234,7 @@ export default {
}
</script>
<style rel="stylesheet/scss" lang="scss" scoped>
<style lang="scss" scoped>
@import "~@/styles/mixin.scss";
.createPost-container {
position: relative;

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 => {
@@ -171,21 +184,17 @@ export default {
}
</script>
<style rel="stylesheet/scss" lang="scss">
<style lang="scss">
/* 修复input 背景不协调 和光标变色 */
/* 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;
}
}
@@ -222,7 +231,7 @@ $cursor: #fff;
}
</style>
<style rel="stylesheet/scss" lang="scss" scoped>
<style lang="scss" scoped>
$bg:#2d3a4b;
$dark_gray:#889aa4;
$light_gray:#eee;

View File

@@ -35,7 +35,7 @@ export default {
}
</script>
<style rel="stylesheet/scss" lang="scss" scoped>
<style lang="scss" scoped>
.social-signup-container {
margin: 20px 0;
.sign-btn {

View File

@@ -42,7 +42,7 @@ export default {
}
</script>
<style rel="stylesheet/scss" lang="scss">
<style lang="scss">
@mixin clearfix {
&:before {
display: table;

View File

@@ -89,7 +89,7 @@ export default {
}
</script>
<style rel="stylesheet/scss" lang="scss" scoped>
<style lang="scss" scoped>
.app-container {
/deep/ .permission-alert {
width: 320px;

View File

@@ -42,7 +42,7 @@ export default {
}
</script>
<style rel="stylesheet/scss" lang="scss" scoped>
<style lang="scss" scoped>
.icons-container {
margin: 10px 20px 0;
overflow: hidden;

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')
@@ -103,13 +109,13 @@ module.exports = {
.when(process.env.NODE_ENV !== 'development',
config => {
config
// .plugin('ScriptExtHtmlWebpackPlugin')
// .after('html')
// .use('script-ext-html-webpack-plugin', [{
// // `runtime` must same as runtimeChunk name. default is `runtime`
// inline: /runtime\..*\.js$/
// }])
// .end()
.plugin('ScriptExtHtmlWebpackPlugin')
.after('html')
.use('script-ext-html-webpack-plugin', [{
// `runtime` must same as runtimeChunk name. default is `runtime`
inline: /runtime\..*\.js$/
}])
.end()
config
.optimization.splitChunks({
chunks: 'all',
@@ -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
}