mirror of
https://github.com/PanJiaChen/vue-element-admin.git
synced 2025-08-10 12:01:57 +08:00
feat: Update fork repository (#514)
* chore: remove i18n (#1828) * [release] 4.1.0 * perf[Profile]: adapt the profile page to the mobile (#2020) * Revert "perf: optimize page scrolling when setting fixedHeader" This reverts commit e8e6c7e79c2488779090f00efc5f1bbfcb04bd5b. * perf[Style]: refine fixed-header style when open el-dialog * doc: add new article * chore: use mockjs in production environment * fix[sidebar.css]: remove redundant css * perf[style]: refine dashboard style in mobile (#2060) * feat[ErrorLog]: add a clear button in ErrorLog component (#2065) * fix[redirect]: fix redirect bug in vue-devtools (#2066) * perf[Tinymce]: update tinymce cdn version * fix[redirect]: fix redirect bug in vue-devtool again * docs: add support to readme for Spanish (#2070) * docs[es]: add some translation(#2080) * perf[Exapme]: set page title according to article id * perf[RightPanel]: tidy css (#2101) * feat[SvgIcon]: support import svg from url (#2052) * fix: fixed change roles bug (#2072) * perf[Breadcrumb]: do not update breadcrumbs when go to redirect page (#2086) * perf[store]: add support to sub-modules (#2047) * perf[Login]: support other query (#2013) * refactor[chore]: generate postcss.config.js instead of .postcssrc.js consistent with vue-cli * perf[Tinymce]: dynamic import tinymce(#2102) * [release] 4.2.0 * docs: add support to readme for Spanish (#2070) * docs[es]: add some translation(#2080) * perf[Exapme]: set page title according to article id * perf[RightPanel]: tidy css (#2101) * feat[SvgIcon]: support import svg from url (#2052) * fix: fixed change roles bug (#2072) * perf[Breadcrumb]: do not update breadcrumbs when go to redirect page (#2086) * perf[store]: add support to sub-modules (#2047) * perf[Login]: support other query (#2013) * refactor[chore]: generate postcss.config.js instead of .postcssrc.js consistent with vue-cli * perf[Tinymce]: dynamic import tinymce(#2102) * [release] 4.2.0 * perf[Style]: refine example css * fix[Chart]: fixed chart bug in keep-alive (#2119) * perf[Style]: refine example css * fix[Chart]: fixed chart bug in keep-alive (#2119) * Create FUNDING.yml * chore: set localhost => 127.0.0.1 (#2142) * update github ISSUE_TEMPLATE * chore: add autoprefixer to devDependencies * perf[Tinymce]: add language option (#2159) * fix[Tinymce]: fixed bug when init multiple tinymces at the same time (#2152) * feat: add tab url demo (#2114) * perf[request.js]: refine error reject (#2160) * [release] 4.2.1 * Create FUNDING.yml * chore: set localhost => 127.0.0.1 (#2142) * update github ISSUE_TEMPLATE * chore: add autoprefixer to devDependencies * fix[Tinymce]: fixed bug when init multiple tinymces at the same time (#2152) * feat: add tab url demo (#2114) * perf[request.js]: refine error reject (#2160) * [release] 4.2.1 * perf: default not set withCredentials * fix[ImageCropper]: removeEventListener when destroyed(#2169) * docs: fix typo (#2170) * fix: input attribute autocomplete error (#2191) * perf: default not set withCredentials * fix[ImageCropper]: removeEventListener when destroyed(#2169) * docs: fix typo (#2170) * fix: input attribute autocomplete error (#2191) * perf[PanThumb]: Replace the image tag with background-image to prevent the stretching (#2202) * docs: fix typo README.zh-CN.md (#2283) 修改错别字 * perf[clipboard.js]: remove redundant code (#2307) * bump: update axios for security vulnerability * bump: update @vue/cli-plugin-eslint version (#2327) FIx cannot find module '.../node_modules/eslint/lib/api.js/package.json' bug,see https://github.com/vuejs/vue-cli/issues/4231. * chore: allow dynamic set port * fix[complex-table]: form header sort icon is out of sync (#2382) * fix: fixed missing icons * fix: typos (#2532) Role Nmae => Role Name * docs: add awesome-project * fix[Dashboard]: fixed debounce bug (#2586) (#2597) To fixed https://github.com/PanJiaChen/vue-element-admin/issues/2586 * perf: VS Code support webpack alias file jump (#2609) * perf: optimize import file-saver way(#2347) * refactor[ImageCropper]: fix lint error (#2365) * fix: fixed numberFormatter bug https://github.com/PanJiaChen/vue-element-admin/issues/2568 * fix[example]: fixed create.vue cache error https://github.com/PanJiaChen/vue-element-admin/issues/2608 * perf[utils.js]: perf parseTime function (#2625) * perf[tagsView]: pref DEL_CACHED_VIEW and DEL_OTHERS_CACHED_VIEWS function (#2626) * fix[tagsView]: fixed DEL_OTHERS_CACHED_VIEWS bug * fix[logout]: empty tagsview when logout (#2632) * fix[TagsView]: fixed toLastView bug (#2634) * perf[SvgIcon]: change xlink:href to href(#2645) https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/xlink:href * fix[TagsView]: fixed click.middle can close affixed tag bug (#2649) * docs: add job ad * perf[PanThumb]: Replace the image tag with background-image to prevent the stretching (#2202) * docs: fix typo README.zh-CN.md (#2283) 修改错别字 * perf[clipboard.js]: remove redundant code (#2307) * bump: update axios for security vulnerability * bump: update @vue/cli-plugin-eslint version (#2327) FIx cannot find module '.../node_modules/eslint/lib/api.js/package.json' bug,see https://github.com/vuejs/vue-cli/issues/4231. * chore: allow dynamic set port * fix[complex-table]: form header sort icon is out of sync (#2382) * fix: fixed missing icons * fix: typos (#2532) Role Nmae => Role Name * docs: add awesome-project * fix[Dashboard]: fixed debounce bug (#2586) (#2597) To fixed https://github.com/PanJiaChen/vue-element-admin/issues/2586 * perf: VS Code support webpack alias file jump (#2609) * perf: optimize import file-saver way(#2347) * refactor[ImageCropper]: fix lint error (#2365) * fix: fixed numberFormatter bug https://github.com/PanJiaChen/vue-element-admin/issues/2568 * fix[example]: fixed create.vue cache error https://github.com/PanJiaChen/vue-element-admin/issues/2608 * perf[utils.js]: perf parseTime function (#2625) * perf[tagsView]: pref DEL_CACHED_VIEW and DEL_OTHERS_CACHED_VIEWS function (#2626) * fix[tagsView]: fixed DEL_OTHERS_CACHED_VIEWS bug * fix[logout]: empty tagsview when logout (#2632) * fix[TagsView]: fixed toLastView bug (#2634) * perf[SvgIcon]: change xlink:href to href(#2645) https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/xlink:href * fix[TagsView]: fixed click.middle can close affixed tag bug (#2649) * docs: add job ad * feat: add job * docs: improved README.md (#2656) * style: fix el-date-picker css style * perf: format dropdown menu code (#2720) * perf: format inline edit table (#2725) move one format `{row}` * perf: format drag table (#2733) move one format `{row}` * perf: complex table (#2732) * perf: text i18n (#2739) * update 'MarkdownEditor' components name * format: space in user card (#2744) * perf: format pdf download (#2791) * perf[views/icons]: use grid (#2803) * feat: plop new generate store (#2805) * fix[icons]:fixed eslint 1 error and 2 warnings (#2835) * perf[documentation]: refine css * fix[Logout]: click blank area of dropDown able to logout (#2896) * perf: import mockXHR only in production (#2910) * 自动排除mock 生产环境,使用webpack的条件编译自动排除mock数据 * perf: refine Co-authored-by: 花裤衩 <panfree23@gmail.com> * perf[Menu]: remove unused menu-wrapper (#2903) * perf[complex-table]:refine code (#2825) * perf: optimize checkCapslock method (#2635) * optimize checkCapslock method * update Co-authored-by: 花裤衩 <panfree23@gmail.com> * fix[Charts]: fix charts resize in keep-alive bug (#2922) * fix[Charts]: fix charts resize in keep-alive bug * refine * fix: fixed mock server (#2929) * init * refine * update * bump: update element-ui version * fix: fixed require mock bug in production * feat[Search]: route search supports pinyin (#2643) * fix: fixed redirect path regex (#2933) * perf[Mock]: set responseFake to mock-server.js(#2966) * modify 把mock/index.js中与mock-server相关的代码转移到mock-server.js中去,实现两则功能分割 * docs: improve Japanese translation (#2970) * perf: change script-loader to dependencies * fix[profile/UserCard]: fixed wrong key name (#3056) roles => role * fix:fixed parseTime bug in ie and safari(#3066) * /src/utils/index.js parseTime 添加IE浏览器(版本10以下,包括版本10)兼容。 * perf: update Co-authored-by: aisen60 <aisen60@qq.com> Co-authored-by: 花裤衩 <panfree23@gmail.com> * perf: format component names as PascalCase (#3074) format: component names should be PascalCase * docs: add smallsticker * Update README.zh-CN.md * fix: svg support old broswer (#3085) * fixed typo (#3091) * fix: use vue-cli default source-map (#3097) cheap-module-eval-source-map * perf[Tinymce]: editor try to keep these URLs intact (#3141) * fix[element-variables]: missing space in element-variables (#3144) * fix: compatibility with vetur (#1700) * feat: add option to try project on CodeSandbox (#2976) * docs: add tips * perf: when tags-view scroll close the right-menu * fix[parseTime]: fixed when pass null (#3038) * fix[css]: min btn width (#3164) * Add contributor into package.json file. * fixed before merge. Co-authored-by: 花裤衩 <panfree23@gmail.com> Co-authored-by: toruksmakto <42709228+toruksmakto@users.noreply.github.com> Co-authored-by: Yamel Senih <ysenih@erpya.com> Co-authored-by: Yamel Senih <yamelsenih@gmail.com> Co-authored-by: liugq <liugq5713@gmail.com> Co-authored-by: bpzhang <bpzhang@users.noreply.github.com> Co-authored-by: Serge <gaosj1993@foxmail.com> Co-authored-by: MaYuanhai <414199639@qq.com> Co-authored-by: Jessynt <xr5299@gmail.com> Co-authored-by: 肖敏 <392716797@qq.com> Co-authored-by: TinaryTree <mbdkhss@gmail.com> Co-authored-by: itsccn <chen.sun@itsccn.com> Co-authored-by: why <w.why@163.com> Co-authored-by: Baskerville* <wszdlm@gmail.com> Co-authored-by: Francis <31059354+FrancisSano@users.noreply.github.com> Co-authored-by: monkeycf <41945134+monkeycf@users.noreply.github.com> Co-authored-by: BradyBromley <51128276+BradyBromley@users.noreply.github.com> Co-authored-by: Phạm Ngọc Hòa <thaycacac@gmail.com> Co-authored-by: bbigcd <bbigcd@163.com> Co-authored-by: xuanzai <43233731+MikuBlog@users.noreply.github.com> Co-authored-by: flitrue <812863096@qq.com> Co-authored-by: 韬 <605682551@qq.com> Co-authored-by: 任羽飞 <ren12345@126.com> Co-authored-by: Kaitian Xie <xkaitian@gmail.com> Co-authored-by: AndyLZC/AndyLZC.github.io <34624589+AndyLZC@users.noreply.github.com> Co-authored-by: RussXD <shangtouWeb@foxmail.com> Co-authored-by: 李小斐 <623536309@qq.com> Co-authored-by: RoBlues <robluesmail@gmail.com> Co-authored-by: Shota Aratono <195194+artn@users.noreply.github.com> Co-authored-by: echofly <36875450+echofly@users.noreply.github.com> Co-authored-by: Aisen60 <1147319086@qq.com> Co-authored-by: aisen60 <aisen60@qq.com> Co-authored-by: Alex S <50220345+sabatale@users.noreply.github.com> Co-authored-by: Aisen <caixusheng60@gmail.com> Co-authored-by: ntnyq <ntnyq13@gmail.com> Co-authored-by: garethx <gareth.wilson@gmail.com> Co-authored-by: AiMe1991 <sxd.08@163.com> Co-authored-by: cooper <1322849632@qq.com> Co-authored-by: Nickbing Lao <giscafer@outlook.com>
This commit is contained in:
parent
6dd649e020
commit
cc35fd7a1d
4
.github/FUNDING.yml
vendored
Normal file
4
.github/FUNDING.yml
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
# These are supported funding model platforms
|
||||
|
||||
patreon: panjiachen
|
||||
custom: https://panjiachen.github.io/vue-element-admin-site/donate
|
@ -1,8 +0,0 @@
|
||||
// https://github.com/michael-ciniawsky/postcss-load-config
|
||||
|
||||
module.exports = {
|
||||
"plugins": {
|
||||
// to edit target browsers: use "browserslist" field in package.json
|
||||
"autoprefixer": {}
|
||||
}
|
||||
}
|
45
README.es.md
45
README.es.md
@ -10,16 +10,16 @@
|
||||
<img src="https://img.shields.io/badge/element--ui-2.7.0-brightgreen.svg" alt="element-ui">
|
||||
</a>
|
||||
<a href="https://travis-ci.org/adempiere/adempiere-vue" rel="nofollow">
|
||||
<img src="https://travis-ci.org/adempiere/adempiere=vue.svg?branch=develop" alt="Build Status">
|
||||
<img src="https://travis-ci.org/adempiere/adempiere=vue.svg?branch=develop" alt="Estado de Construcción">
|
||||
</a>
|
||||
<a href="https://github.com/adempiere/adempiere-vue/blob/master/LICENSE">
|
||||
<img src="https://img.shields.io/badge/license-GNU/GPL%20(v3)-blue" alt="license">
|
||||
<img src="https://img.shields.io/badge/license-GNU/GPL%20(v3)-blue" alt="Licencia">
|
||||
</a>
|
||||
<a href="https://github.com/adempiere/adempiere-vue/releases">
|
||||
<img src="https://img.shields.io/github/release/adempiere/adempiere-vue.svg" alt="GitHub release">
|
||||
<img src="https://img.shields.io/github/release/adempiere/adempiere-vue.svg" alt="Liberación Github">
|
||||
</a>
|
||||
<a href="https://gitter.im/adempiere/adempiere-vue">
|
||||
<img src="https://badges.gitter.im/Join%20Chat.svg" alt="gitter">
|
||||
<img src="https://badges.gitter.im/Join%20Chat.svg" alt="Gitter">
|
||||
</a>
|
||||
</p>
|
||||
|
||||
@ -27,33 +27,35 @@ Español | [Inglés](./README.md)
|
||||
|
||||
## Introducción
|
||||
|
||||
[adempiere-vue](https://github.com/adempiere/adempiere-vue) es una nueva UI para [ADempiere ERP, CRM & SCM](https://github.com/adempiere/adempiere)]. Se basa en [vue](https://github.com/vuejs/vue) y usa el conjunto de herraminentas de UI [element-ui](https://github.com/ElemeFE/element).
|
||||
[adempiere-vue](https://github.com/adempiere/adempiere-vue) es una nueva UI para [ADempiere ERP, CRM & SCM](https://github.com/adempiere/adempiere)]. Está basada en [vue](https://github.com/vuejs/vue) y usa [element-ui](https://github.com/ElemeFE/element) como conjunto de herramientas de interfáz de usuario.
|
||||
|
||||
Este es una gran UI para [ADempiere ERP, CRM & SCM](https://github.com/adempiere/adempiere)] basada en lo último desarrollado por vue, construido con i18n para manejo multi-idioma, plantillas para aplicaciones de negocio y muchas características asombrosas. Este proyecto es derivado de [Vue-Element-Admin](https://github.com/PanJiaChen/vue-element-admin) originalmente escrito por [PanJiaChen / 花裤衩](https://github.com/PanJiaChen) sobre [licencia MIT](https://github.com/PanJiaChen/vue-element-admin/blob/master/LICENSE) y cambiado a [licencia GNU/GPL v3](https://github.com/adempiere/adempiere-vue/blob/master/LICENSE) por [Yamel Senih](https://github.com/yamelsenih) después de derivar el proyecto y con permisos del autor original [PanJiaChen / 花裤衩](https://github.com/PanJiaChen) en el reporte ["Extend as GNU/Gpl v3 License #1434"](https://github.com/PanJiaChen/vue-element-admin/issues/1434).
|
||||
|
||||
[adempiere-vue](https://github.com/adempiere/adempiere-vue) usa como RPC (Llamado a Procedimientos Remostos)[gRPC](https://grpc.io/) como [server](https://github.com/erpcya/adempiere-gRPC-Server).
|
||||
|
||||
- [Vista Prévia](http://adempiere-ui.erpya.com:9526/)
|
||||
- [Vista Prévia de la Aplicación](http://adempiere-ui.erpya.com:9526/)
|
||||
|
||||
- [Documentación](https://panjiachen.github.io/vue-element-admin-site/)
|
||||
|
||||
- [Gitter](https://gitter.im/adempiere/adempiere-vue)
|
||||
- [Canal de Gitter](https://gitter.im/adempiere/adempiere-vue)
|
||||
|
||||
- [Donar](https://www.paypal.me/?)
|
||||
- [Para Donaciones](https://www.paypal.me/?)
|
||||
|
||||
- [Wikipedia](http://wiki.adempiere.net/ADempiere_ERP)
|
||||
- [Enlace de Wiki](http://wiki.adempiere.net/ADempiere_ERP)
|
||||
|
||||
- [Derivado De](https://github.com/PanJiaChen/vue-element-admin)
|
||||
|
||||
**La versión actual `v1.0+` está construida en `vue-cli`. Si encuentra algún problema, por favor escriba un [reporte de error](https://github.com/adempiere/adempiere-vue/issues/new).**
|
||||
**La versión actual `v1.0+` está construida con `vue-cli`. Si encuentra algún problema, por favor escriba un [reporte de error](https://github.com/adempiere/adempiere-vue/issues/new).**
|
||||
|
||||
**Este proyecto no soporta versiones bajas de los navegadores (e.g. IE).**
|
||||
**Este proyecto no está soportado para versiones muy viejas de navegadores (e.g. IE).**
|
||||
|
||||
## Preparación
|
||||
|
||||
Necesita instalar [node](https://nodejs.org/) y [git](https://git-scm.com/) localmente. El proyecto está basado en [ES2015+](https://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) , [gRPC](https://grpc.io/) y [element-ui](https://github.com/ElemeFE/element).
|
||||
Entendiendo y aprendiendo acerca de lo anterior le ayudará a conocer el proyecto.
|
||||
|
||||
[](https://codesandbox.io/s/github/PanJiaChen/vue-element-admin/tree/CodeSandbox)
|
||||
|
||||
<p align="center">
|
||||
<img width="900" src="https://wpimg.wallstcn.com/a5894c1b-f6af-456e-82df-1151da0839bf.png">
|
||||
</p>
|
||||
@ -65,7 +67,7 @@ Entendiendo y aprendiendo acerca de lo anterior le ayudará a conocer el proyect
|
||||
<a href="http://westfalia-it.com/"><img width="150px" src="https://i1.wp.com/spin-suite.com/westfalia/wp-content/uploads/sites/30/2017/12/logo_copy.jpg?fit=265%2C357" /></a>
|
||||
<a href="http://erpya.com/"><img width="250px" src="https://i0.wp.com/spin-suite.com/openupsolutions/wp-content/uploads/sites/32/2017/05/Openup-Solutions-Logo-2017-80x200px.png" /></a>
|
||||
|
||||
Sea un patrocinante y coloque su logo en nuestro LEEME en GitHub con un link a su sitio web. [Sea un Patrocinante](https://www.paypal.me/?)
|
||||
Sea un patrocinante y coloque su logo en nuestro LEEME en GitHub con un enlace directo a su sitio web. [Sea un Patrocinante](https://www.paypal.me/?)
|
||||
|
||||
## Características
|
||||
|
||||
@ -125,10 +127,11 @@ Sea un patrocinante y coloque su logo en nuestro LEEME en GitHub con un link a s
|
||||
- Adhesión de objetos
|
||||
- Contador hasta
|
||||
- Soporte a ADempiere
|
||||
- Ventan
|
||||
- Proceso
|
||||
- Reporte
|
||||
- Visor Inteligente
|
||||
- Ventana
|
||||
- Proceso
|
||||
- Reporte
|
||||
- Consulta Inteligente
|
||||
- Formulario
|
||||
|
||||
- Ejemplo Avanzado
|
||||
- Registro de Errores
|
||||
@ -145,7 +148,7 @@ Use [gRPC ADempiere Server](https://github.com/erpcya/adempiere-gRPC-Server) com
|
||||
|
||||
```bash
|
||||
# clone el proyecto
|
||||
git clone -b develop git@github.com:adempiere/vue-element-admin.git
|
||||
git clone -b develop git@github.com:adempiere/adempiere-vue.git
|
||||
|
||||
# vaya al directorio clonado
|
||||
cd adempiere-vue
|
||||
@ -185,7 +188,7 @@ npm run lint
|
||||
npm run lint -- --fix
|
||||
```
|
||||
|
||||
Vaya a [Documentation](https://panjiachen.github.io/vue-element-admin-site/guide/essentials/deploy.html) para mayor información.
|
||||
Vaya a [Documentación](https://panjiachen.github.io/vue-element-admin-site/guide/essentials/deploy.html) para mayor información.
|
||||
|
||||
## Registro de Cambios
|
||||
|
||||
@ -193,13 +196,13 @@ Los cambios detallados por cada liberación se encuentran en [notas de liberaci
|
||||
|
||||
## Demostración en línea
|
||||
|
||||
[Preview](http://adempiere-ui.erpya.com:9526/)
|
||||
[Vista Prévia de la Aplicación](http://adempiere-ui.erpya.com:9526/)
|
||||
|
||||
## Donación
|
||||
|
||||
Si este proyecto es de mucha ayuda para ti, puedes ayudar a hacer una mejor UI
|
||||
|
||||
[Dona por Paypal](https://www.paypal.me/?)
|
||||
[dona por Paypal](https://www.paypal.me/?)
|
||||
|
||||
## Navegadores Soportados
|
||||
|
||||
@ -207,7 +210,7 @@ Navegadores modernos e Internet Explorer 10+.
|
||||
|
||||
| [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/edge/edge_48x48.png" alt="IE / Edge" width="24px" height="24px" />](https://godban.github.io/browsers-support-badges/)</br>IE / Edge | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/firefox/firefox_48x48.png" alt="Firefox" width="24px" height="24px" />](https://godban.github.io/browsers-support-badges/)</br>Firefox | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/chrome/chrome_48x48.png" alt="Chrome" width="24px" height="24px" />](https://godban.github.io/browsers-support-badges/)</br>Chrome | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/safari/safari_48x48.png" alt="Safari" width="24px" height="24px" />](https://godban.github.io/browsers-support-badges/)</br>Safari |
|
||||
| --------- | --------- | --------- | --------- |
|
||||
| IE10, IE11, Edge| last 2 versions| last 2 versions| last 2 versions
|
||||
| IE10, IE11, Edge| últimas 2 versiones| últimas 2 versiones| últimas 2 versiones
|
||||
|
||||
## Licencia
|
||||
|
||||
|
@ -54,7 +54,9 @@ It is a great UI for [ADempiere ERP, CRM & SCM](https://github.com/adempiere/ade
|
||||
You need to install [node](https://nodejs.org/) and [git](https://git-scm.com/) locally. The project is based on [ES2015+](https://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) , [gRPC](https://grpc.io/) and [element-ui](https://github.com/ElemeFE/element).
|
||||
Understanding and learning this knowledge in advance will greatly help the use of this project.
|
||||
|
||||
<p align="center">
|
||||
[](https://codesandbox.io/s/github/PanJiaChen/vue-element-admin/tree/CodeSandbox)
|
||||
|
||||
<p align="center">
|
||||
<img width="900" src="https://wpimg.wallstcn.com/a5894c1b-f6af-456e-82df-1151da0839bf.png">
|
||||
</p>
|
||||
|
||||
|
9
jsconfig.json
Normal file
9
jsconfig.json
Normal file
@ -0,0 +1,9 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"baseUrl": "./",
|
||||
"paths": {
|
||||
"@/*": ["src/*"]
|
||||
}
|
||||
},
|
||||
"exclude": ["node_modules", "dist"]
|
||||
}
|
@ -18,7 +18,7 @@ for (let i = 0; i < count; i++) {
|
||||
forecast: '@float(0, 100, 2, 2)',
|
||||
importance: '@integer(1, 3)',
|
||||
'type|1': ['CN', 'US', 'JP', 'EU'],
|
||||
'status|1': ['published', 'draft', 'deleted'],
|
||||
'status|1': ['published', 'draft'],
|
||||
display_time: '@datetime',
|
||||
comment_disabled: true,
|
||||
pageviews: '@integer(300, 5000)',
|
||||
@ -29,7 +29,7 @@ for (let i = 0; i < count; i++) {
|
||||
|
||||
export default [
|
||||
{
|
||||
url: '/article/list',
|
||||
url: '/vue-element-admin/article/list',
|
||||
type: 'get',
|
||||
response: config => {
|
||||
const { importance, type, title, page = 1, limit = 20, sort } = config.query
|
||||
@ -58,7 +58,7 @@ export default [
|
||||
},
|
||||
|
||||
{
|
||||
url: '/article/detail',
|
||||
url: '/vue-element-admin/article/detail',
|
||||
type: 'get',
|
||||
response: config => {
|
||||
const { id } = config.query
|
||||
@ -74,7 +74,7 @@ export default [
|
||||
},
|
||||
|
||||
{
|
||||
url: '/article/pv',
|
||||
url: '/vue-element-admin/article/pv',
|
||||
type: 'get',
|
||||
response: _ => {
|
||||
return {
|
||||
@ -92,7 +92,7 @@ export default [
|
||||
},
|
||||
|
||||
{
|
||||
url: '/article/create',
|
||||
url: '/vue-element-admin/article/create',
|
||||
type: 'post',
|
||||
response: _ => {
|
||||
return {
|
||||
@ -103,7 +103,7 @@ export default [
|
||||
},
|
||||
|
||||
{
|
||||
url: '/article/update',
|
||||
url: '/vue-element-admin/article/update',
|
||||
type: 'post',
|
||||
response: _ => {
|
||||
return {
|
||||
|
@ -54,17 +54,4 @@ export function mockXHR() {
|
||||
}
|
||||
}
|
||||
|
||||
// for mock server
|
||||
const responseFake = (url, type, respond) => {
|
||||
return {
|
||||
url: new RegExp(`/mock${url}`),
|
||||
type: type || 'get',
|
||||
response(req, res) {
|
||||
res.json(Mock.mock(respond instanceof Function ? respond(req, res) : respond))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default mocks.map(route => {
|
||||
return responseFake(route.url, route.type, route.response)
|
||||
})
|
||||
export default mocks
|
||||
|
@ -2,17 +2,21 @@ const chokidar = require('chokidar')
|
||||
const bodyParser = require('body-parser')
|
||||
const chalk = require('chalk')
|
||||
const path = require('path')
|
||||
const Mock = require('mockjs')
|
||||
|
||||
const mockDir = path.join(process.cwd(), 'mock')
|
||||
|
||||
function registerRoutes(app) {
|
||||
let mockLastIndex
|
||||
const { default: mocks } = require('./index.js')
|
||||
for (const mock of mocks) {
|
||||
const mocksForServer = mocks.map(route => {
|
||||
return responseFake(route.url, route.type, route.response)
|
||||
})
|
||||
for (const mock of mocksForServer) {
|
||||
app[mock.type](mock.url, mock.response)
|
||||
mockLastIndex = app._router.stack.length
|
||||
}
|
||||
const mockRoutesLength = Object.keys(mocks).length
|
||||
const mockRoutesLength = Object.keys(mocksForServer).length
|
||||
return {
|
||||
mockRoutesLength: mockRoutesLength,
|
||||
mockStartIndex: mockLastIndex - mockRoutesLength
|
||||
@ -27,6 +31,18 @@ function unregisterRoutes() {
|
||||
})
|
||||
}
|
||||
|
||||
// for mock server
|
||||
const responseFake = (url, type, respond) => {
|
||||
return {
|
||||
url: new RegExp(`${process.env.VUE_APP_BASE_API}${url}`),
|
||||
type: type || 'get',
|
||||
response(req, res) {
|
||||
console.log('request invoke:' + req.path)
|
||||
res.json(Mock.mock(respond instanceof Function ? respond(req, res) : respond))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = app => {
|
||||
// es6 polyfill
|
||||
require('@babel/register')
|
||||
|
@ -13,7 +13,7 @@ NameList.push({ name: 'mock-Pan' })
|
||||
export default [
|
||||
// username search
|
||||
{
|
||||
url: '/search/user',
|
||||
url: '/vue-element-admin/search/user',
|
||||
type: 'get',
|
||||
response: config => {
|
||||
const { name } = config.query
|
||||
@ -30,7 +30,7 @@ export default [
|
||||
|
||||
// transaction list
|
||||
{
|
||||
url: '/transaction/list',
|
||||
url: '/vue-element-admin/transaction/list',
|
||||
type: 'get',
|
||||
response: _ => {
|
||||
return {
|
||||
|
@ -38,7 +38,7 @@ const roles = [
|
||||
export default [
|
||||
// mock get all routes form server
|
||||
{
|
||||
url: '/routes',
|
||||
url: '/vue-element-admin/routes',
|
||||
type: 'get',
|
||||
response: _ => {
|
||||
return {
|
||||
@ -50,7 +50,7 @@ export default [
|
||||
|
||||
// mock get all roles form server
|
||||
{
|
||||
url: '/roles',
|
||||
url: '/vue-element-admin/roles',
|
||||
type: 'get',
|
||||
response: _ => {
|
||||
return {
|
||||
@ -62,7 +62,7 @@ export default [
|
||||
|
||||
// add role
|
||||
{
|
||||
url: '/role',
|
||||
url: '/vue-element-admin/role',
|
||||
type: 'post',
|
||||
response: {
|
||||
code: 20000,
|
||||
@ -74,7 +74,7 @@ export default [
|
||||
|
||||
// update role
|
||||
{
|
||||
url: '/role/[A-Za-z0-9]',
|
||||
url: '/vue-element-admin/role/[A-Za-z0-9]',
|
||||
type: 'put',
|
||||
response: {
|
||||
code: 20000,
|
||||
@ -86,7 +86,7 @@ export default [
|
||||
|
||||
// delete role
|
||||
{
|
||||
url: '/role/[A-Za-z0-9]',
|
||||
url: '/vue-element-admin/role/[A-Za-z0-9]',
|
||||
type: 'delete',
|
||||
response: {
|
||||
code: 20000,
|
||||
|
@ -26,7 +26,7 @@ const users = {
|
||||
export default [
|
||||
// user login
|
||||
{
|
||||
url: '/user/login',
|
||||
url: '/vue-element-admin/user/login',
|
||||
type: 'post',
|
||||
response: config => {
|
||||
const { username } = config.body
|
||||
@ -49,7 +49,7 @@ export default [
|
||||
|
||||
// get user info
|
||||
{
|
||||
url: '/user/info\.*',
|
||||
url: '/vue-element-admin/user/info\.*',
|
||||
type: 'get',
|
||||
response: config => {
|
||||
const { token } = config.query
|
||||
@ -72,7 +72,7 @@ export default [
|
||||
|
||||
// user logout
|
||||
{
|
||||
url: '/user/logout',
|
||||
url: '/vue-element-admin/user/logout',
|
||||
type: 'post',
|
||||
response: _ => {
|
||||
return {
|
||||
|
12
package.json
12
package.json
@ -1,8 +1,14 @@
|
||||
{
|
||||
"name": "adempiere-vue",
|
||||
"version": "4.1.0",
|
||||
"version": "4.2.1",
|
||||
"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>",
|
||||
"contributors": [
|
||||
{
|
||||
"name": "Edwin Betancourt",
|
||||
"url": "https://github.com/EdwinBetanc0urt/"
|
||||
}
|
||||
],
|
||||
"license": "GPL-3.0-or-later",
|
||||
"scripts": {
|
||||
"start": "vue-cli-service serve",
|
||||
@ -68,6 +74,7 @@
|
||||
"normalize.css": "8.0.1",
|
||||
"nprogress": "0.2.0",
|
||||
"path-to-regexp": "2.4.0",
|
||||
"pinyin": "2.9.0",
|
||||
"screenfull": "5.0.2",
|
||||
"script-loader": "0.7.2",
|
||||
"showdown": "1.9.1",
|
||||
@ -124,7 +131,6 @@
|
||||
},
|
||||
"browserslist": [
|
||||
"> 1%",
|
||||
"last 2 versions",
|
||||
"not ie <= 8"
|
||||
"last 2 versions"
|
||||
]
|
||||
}
|
||||
|
16
plop-templates/store/index.hbs
Normal file
16
plop-templates/store/index.hbs
Normal file
@ -0,0 +1,16 @@
|
||||
{{#if state}}
|
||||
const state = {}
|
||||
{{/if}}
|
||||
|
||||
{{#if mutations}}
|
||||
const mutations = {}
|
||||
{{/if}}
|
||||
|
||||
{{#if actions}}
|
||||
const actions = {}
|
||||
{{/if}}
|
||||
|
||||
export default {
|
||||
namespaced: true,
|
||||
{{options}}
|
||||
}
|
62
plop-templates/store/prompt.js
Normal file
62
plop-templates/store/prompt.js
Normal file
@ -0,0 +1,62 @@
|
||||
const { notEmpty } = require('../utils.js')
|
||||
|
||||
module.exports = {
|
||||
description: 'generate store',
|
||||
prompts: [{
|
||||
type: 'input',
|
||||
name: 'name',
|
||||
message: 'store name please',
|
||||
validate: notEmpty('name')
|
||||
},
|
||||
{
|
||||
type: 'checkbox',
|
||||
name: 'blocks',
|
||||
message: 'Blocks:',
|
||||
choices: [{
|
||||
name: 'state',
|
||||
value: 'state',
|
||||
checked: true
|
||||
},
|
||||
{
|
||||
name: 'mutations',
|
||||
value: 'mutations',
|
||||
checked: true
|
||||
},
|
||||
{
|
||||
name: 'actions',
|
||||
value: 'actions',
|
||||
checked: true
|
||||
}
|
||||
],
|
||||
validate(value) {
|
||||
if (!value.includes('state') || !value.includes('mutations')) {
|
||||
return 'store require at least state and mutations'
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
],
|
||||
actions(data) {
|
||||
const name = '{{name}}'
|
||||
const { blocks } = data
|
||||
const options = ['state', 'mutations']
|
||||
const joinFlag = `,
|
||||
`
|
||||
if (blocks.length === 3) {
|
||||
options.push('actions')
|
||||
}
|
||||
|
||||
const actions = [{
|
||||
type: 'add',
|
||||
path: `src/store/modules/${name}.js`,
|
||||
templateFile: 'plop-templates/store/index.hbs',
|
||||
data: {
|
||||
options: options.join(joinFlag),
|
||||
state: blocks.includes('state'),
|
||||
mutations: blocks.includes('mutations'),
|
||||
actions: blocks.includes('actions')
|
||||
}
|
||||
}]
|
||||
return actions
|
||||
}
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
const viewGenerator = require('./plop-templates/view/prompt')
|
||||
const componentGenerator = require('./plop-templates/component/prompt')
|
||||
const storeGenerator = require('./plop-templates/store/prompt.js')
|
||||
const ADempiereView = require('./plop-templates/ADempiere/view/prompt')
|
||||
const ADempiereComponent = require('./plop-templates/ADempiere/component/prompt')
|
||||
const ADempiereStore = require('./plop-templates/ADempiere/store/prompt')
|
||||
@ -7,6 +8,7 @@ const ADempiereStore = require('./plop-templates/ADempiere/store/prompt')
|
||||
module.exports = function(plop) {
|
||||
plop.setGenerator('view', viewGenerator)
|
||||
plop.setGenerator('component', componentGenerator)
|
||||
plop.setGenerator('store', storeGenerator)
|
||||
plop.setGenerator('ADempiere View', ADempiereView)
|
||||
plop.setGenerator('ADempiere Component', ADempiereComponent)
|
||||
plop.setGenerator('ADempiere Store Module', ADempiereStore)
|
||||
|
5
postcss.config.js
Normal file
5
postcss.config.js
Normal file
@ -0,0 +1,5 @@
|
||||
module.exports = {
|
||||
plugins: {
|
||||
autoprefixer: {}
|
||||
}
|
||||
}
|
@ -9,10 +9,6 @@
|
||||
<title><%= webpackConfig.name %></title>
|
||||
</head>
|
||||
<body>
|
||||
<!-- import cdn js -->
|
||||
<% for(var js of htmlWebpackPlugin.options.cdn.js) { %>
|
||||
<script src="<%=js%>"></script>
|
||||
<% } %>
|
||||
<div id="app"></div>
|
||||
<!-- built files will be auto injected -->
|
||||
</body>
|
||||
|
@ -2,7 +2,7 @@ import request from '@/utils/request'
|
||||
|
||||
export function fetchList(query) {
|
||||
return request({
|
||||
url: '/article/list',
|
||||
url: '/vue-element-admin/article/list',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
@ -10,7 +10,7 @@ export function fetchList(query) {
|
||||
|
||||
export function fetchArticle(id) {
|
||||
return request({
|
||||
url: '/article/detail',
|
||||
url: '/vue-element-admin/article/detail',
|
||||
method: 'get',
|
||||
params: { id }
|
||||
})
|
||||
@ -18,7 +18,7 @@ export function fetchArticle(id) {
|
||||
|
||||
export function fetchPv(pv) {
|
||||
return request({
|
||||
url: '/article/pv',
|
||||
url: '/vue-element-admin/article/pv',
|
||||
method: 'get',
|
||||
params: { pv }
|
||||
})
|
||||
@ -26,7 +26,7 @@ export function fetchPv(pv) {
|
||||
|
||||
export function createArticle(data) {
|
||||
return request({
|
||||
url: '/article/create',
|
||||
url: '/vue-element-admin/article/create',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
@ -34,7 +34,7 @@ export function createArticle(data) {
|
||||
|
||||
export function updateArticle(data) {
|
||||
return request({
|
||||
url: '/article/update',
|
||||
url: '/vue-element-admin/article/update',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
|
@ -2,7 +2,7 @@ import request from '@/utils/request'
|
||||
|
||||
export function searchUser(name) {
|
||||
return request({
|
||||
url: '/search/user',
|
||||
url: '/vue-element-admin/search/user',
|
||||
method: 'get',
|
||||
params: { name }
|
||||
})
|
||||
@ -10,7 +10,7 @@ export function searchUser(name) {
|
||||
|
||||
export function transactionList(query) {
|
||||
return request({
|
||||
url: '/transaction/list',
|
||||
url: '/vue-element-admin/transaction/list',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
|
@ -2,21 +2,21 @@ import request from '@/utils/request'
|
||||
|
||||
export function getRoutes() {
|
||||
return request({
|
||||
url: '/routes',
|
||||
url: '/vue-element-admin/routes',
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
export function getRoles() {
|
||||
return request({
|
||||
url: '/roles',
|
||||
url: '/vue-element-admin/roles',
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
export function addRole(data) {
|
||||
return request({
|
||||
url: '/role',
|
||||
url: '/vue-element-admin/role',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
@ -24,7 +24,7 @@ export function addRole(data) {
|
||||
|
||||
export function updateRole(id, data) {
|
||||
return request({
|
||||
url: `/role/${id}`,
|
||||
url: `/vue-element-admin/role/${id}`,
|
||||
method: 'put',
|
||||
data
|
||||
})
|
||||
@ -32,7 +32,7 @@ export function updateRole(id, data) {
|
||||
|
||||
export function deleteRole(id) {
|
||||
return request({
|
||||
url: `/role/${id}`,
|
||||
url: `/vue-element-admin/role/${id}`,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
|
@ -12,7 +12,9 @@
|
||||
</el-breadcrumb-item>
|
||||
<el-breadcrumb-item key="1">
|
||||
<el-popover placement="bottom" trigger="hover" class="breadcrumb-popover">
|
||||
<el-dropdown-item v-for="(item, index) in dropdownList" :key="index" @click.native="handleLink(item)">{{ generateTitle(item.meta.title) }}</el-dropdown-item>
|
||||
<el-dropdown-item v-for="(item, index) in dropdownList" :key="index" @click.native="handleLink(item)">
|
||||
{{ generateTitle(item.meta.title) }}
|
||||
</el-dropdown-item>
|
||||
<i slot="reference" class="el-icon-more" />
|
||||
</el-popover>
|
||||
</el-breadcrumb-item>
|
||||
@ -26,8 +28,9 @@
|
||||
</el-breadcrumb-item>
|
||||
</template>
|
||||
<el-breadcrumb-item v-for="(item,index) in levelList" v-else :key="item.path">
|
||||
<span v-if="item.redirect==='noRedirect'||index==levelList.length-1" class="no-redirect">{{
|
||||
generateTitle(item.meta.title) }}</span>
|
||||
<span v-if="item.redirect==='noRedirect'||index==levelList.length-1" class="no-redirect">
|
||||
{{ generateTitle(item.meta.title) }}
|
||||
</span>
|
||||
<a v-else @click.prevent="handleLink(item)">{{ generateTitle(item.meta.title) }}</a>
|
||||
</el-breadcrumb-item>
|
||||
</transition-group>
|
||||
@ -48,7 +51,11 @@ export default {
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
$route() {
|
||||
$route(route) {
|
||||
// if you go to the redirect page, do not update the breadcrumbs
|
||||
if (route.path.startsWith('/redirect/')) {
|
||||
return
|
||||
}
|
||||
this.getBreadcrumb()
|
||||
}
|
||||
},
|
||||
|
@ -3,32 +3,54 @@ import { debounce } from '@/utils'
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
$_sidebarElm: null
|
||||
$_sidebarElm: null,
|
||||
$_resizeHandler: null
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.__resizeHandler = debounce(() => {
|
||||
if (this.chart) {
|
||||
this.chart.resize()
|
||||
}
|
||||
}, 100)
|
||||
window.addEventListener('resize', this.__resizeHandler)
|
||||
this.initListener()
|
||||
},
|
||||
activated() {
|
||||
if (!this.$_resizeHandler) {
|
||||
// avoid duplication init
|
||||
this.initListener()
|
||||
}
|
||||
|
||||
this.$_sidebarElm = document.getElementsByClassName('sidebar-container')[0]
|
||||
this.$_sidebarElm && this.$_sidebarElm.addEventListener('transitionend', this.$_sidebarResizeHandler)
|
||||
// when keep-alive chart activated, auto resize
|
||||
this.resize()
|
||||
},
|
||||
beforeDestroy() {
|
||||
window.removeEventListener('resize', this.__resizeHandler)
|
||||
|
||||
this.$_sidebarElm && this.$_sidebarElm.removeEventListener('transitionend', this.$_sidebarResizeHandler)
|
||||
this.destroyListener()
|
||||
},
|
||||
deactivated() {
|
||||
this.destroyListener()
|
||||
},
|
||||
methods: {
|
||||
// use $_ for mixins properties
|
||||
// https://vuejs.org/v2/style-guide/index.html#Private-property-names-essential
|
||||
$_sidebarResizeHandler(e) {
|
||||
if (e.propertyName === 'width') {
|
||||
this.__resizeHandler()
|
||||
this.$_resizeHandler()
|
||||
}
|
||||
},
|
||||
initListener() {
|
||||
this.$_resizeHandler = debounce(() => {
|
||||
this.resize()
|
||||
}, 100)
|
||||
window.addEventListener('resize', this.$_resizeHandler)
|
||||
|
||||
this.$_sidebarElm = document.getElementsByClassName('sidebar-container')[0]
|
||||
this.$_sidebarElm && this.$_sidebarElm.addEventListener('transitionend', this.$_sidebarResizeHandler)
|
||||
},
|
||||
destroyListener() {
|
||||
window.removeEventListener('resize', this.$_resizeHandler)
|
||||
this.$_resizeHandler = null
|
||||
|
||||
this.$_sidebarElm && this.$_sidebarElm.removeEventListener('transitionend', this.$_sidebarResizeHandler)
|
||||
},
|
||||
resize() {
|
||||
const { chart } = this
|
||||
chart && chart.resize()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -6,7 +6,11 @@
|
||||
</el-button>
|
||||
</el-badge>
|
||||
|
||||
<el-dialog :visible.sync="dialogTableVisible" title="Error Log" width="80%" append-to-body>
|
||||
<el-dialog :visible.sync="dialogTableVisible" width="80%" append-to-body>
|
||||
<div slot="title">
|
||||
<span style="padding-right: 10px;">Error Log</span>
|
||||
<el-button size="mini" type="primary" icon="el-icon-delete" @click="clearAll">Clear All</el-button>
|
||||
</div>
|
||||
<el-table :data="errorLogs" border>
|
||||
<el-table-column label="Message">
|
||||
<template slot-scope="{row}">
|
||||
@ -54,6 +58,12 @@ export default {
|
||||
errorLogs() {
|
||||
return this.$store.getters.errorLogs
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
clearAll() {
|
||||
this.dialogTableVisible = false
|
||||
this.$store.dispatch('errorLog/clearErrorLog')
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
@ -45,6 +45,9 @@ export default {
|
||||
},
|
||||
lang() {
|
||||
return this.$store.getters.language
|
||||
},
|
||||
supportPinyinSearch() {
|
||||
return this.$store.state.settings.supportPinyinSearch
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
@ -55,6 +58,10 @@ export default {
|
||||
this.searchPool = this.generateRoutes(this.routes)
|
||||
},
|
||||
searchPool(list) {
|
||||
// Support pinyin search
|
||||
if (this.lang === 'zh' && this.supportPinyinSearch) {
|
||||
this.addPinyinField(list)
|
||||
}
|
||||
this.initFuse(list)
|
||||
},
|
||||
show(value) {
|
||||
@ -70,6 +77,23 @@ export default {
|
||||
},
|
||||
methods: {
|
||||
generateTitle,
|
||||
async addPinyinField(list) {
|
||||
const { default: pinyin } = await import('pinyin')
|
||||
if (Array.isArray(list)) {
|
||||
list.forEach(element => {
|
||||
const title = element.title
|
||||
if (Array.isArray(title)) {
|
||||
title.forEach(v => {
|
||||
v = pinyin(v, {
|
||||
style: pinyin.STYLE_NORMAL
|
||||
}).join('')
|
||||
element.pinyinTitle = v
|
||||
})
|
||||
}
|
||||
})
|
||||
return list
|
||||
}
|
||||
},
|
||||
click() {
|
||||
this.show = !this.show
|
||||
if (this.show) {
|
||||
@ -108,6 +132,9 @@ export default {
|
||||
keys: [{
|
||||
name: 'title',
|
||||
weight: 0.7
|
||||
}, {
|
||||
name: 'pinyinTitle',
|
||||
weight: 0.3
|
||||
}, {
|
||||
name: 'path',
|
||||
weight: 0.3
|
||||
@ -118,7 +145,6 @@ export default {
|
||||
// And generate the internationalized title
|
||||
generateRoutes(routes, basePath = '/', prefixTitle = []) {
|
||||
let res = []
|
||||
|
||||
for (const router of routes) {
|
||||
// skip hidden router
|
||||
// if (router.meta && router.meta.isIndex) { continue }
|
||||
@ -128,7 +154,6 @@ export default {
|
||||
meta: router.meta,
|
||||
name: router.name
|
||||
}
|
||||
|
||||
if (router.meta && router.meta.title) {
|
||||
// generate internationalized title
|
||||
const i18ntitle = this.generateTitle(router.meta.title)
|
||||
@ -139,7 +164,6 @@ export default {
|
||||
res.push(data)
|
||||
}
|
||||
}
|
||||
|
||||
// recursive child routes
|
||||
if (router.children) {
|
||||
const tempRoutes = this.generateRoutes(router.children, data.path, data.title)
|
||||
@ -164,13 +188,11 @@ export default {
|
||||
<style lang="scss" scoped>
|
||||
.header-search {
|
||||
font-size: 0 !important;
|
||||
|
||||
.search-icon {
|
||||
cursor: pointer;
|
||||
font-size: 18px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.header-search-select {
|
||||
font-size: 18px;
|
||||
transition: width 0.2s;
|
||||
@ -180,7 +202,6 @@ export default {
|
||||
border-radius: 0;
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
|
||||
/deep/ .el-input__inner {
|
||||
border-radius: 0;
|
||||
border: 0;
|
||||
@ -191,7 +212,6 @@ export default {
|
||||
vertical-align: middle;
|
||||
}
|
||||
}
|
||||
|
||||
&.show {
|
||||
.header-search-select {
|
||||
width: 150px;
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -9,7 +9,7 @@
|
||||
:placeholder="fillPlaceHolder"
|
||||
:readonly="readonly"
|
||||
:disabled="disabled"
|
||||
:autoComplete="autoComplete"
|
||||
:autocomplete="autoComplete"
|
||||
:required="required"
|
||||
type="email"
|
||||
class="material-input"
|
||||
@ -24,7 +24,7 @@
|
||||
:placeholder="fillPlaceHolder"
|
||||
:readonly="readonly"
|
||||
:disabled="disabled"
|
||||
:autoComplete="autoComplete"
|
||||
:autocomplete="autoComplete"
|
||||
:required="required"
|
||||
type="url"
|
||||
class="material-input"
|
||||
@ -40,7 +40,7 @@
|
||||
:step="step"
|
||||
:readonly="readonly"
|
||||
:disabled="disabled"
|
||||
:autoComplete="autoComplete"
|
||||
:autocomplete="autoComplete"
|
||||
:max="max"
|
||||
:min="min"
|
||||
:minlength="minlength"
|
||||
@ -59,7 +59,7 @@
|
||||
:placeholder="fillPlaceHolder"
|
||||
:readonly="readonly"
|
||||
:disabled="disabled"
|
||||
:autoComplete="autoComplete"
|
||||
:autocomplete="autoComplete"
|
||||
:max="max"
|
||||
:min="min"
|
||||
:required="required"
|
||||
@ -76,7 +76,7 @@
|
||||
:placeholder="fillPlaceHolder"
|
||||
:readonly="readonly"
|
||||
:disabled="disabled"
|
||||
:autoComplete="autoComplete"
|
||||
:autocomplete="autoComplete"
|
||||
:required="required"
|
||||
type="tel"
|
||||
class="material-input"
|
||||
@ -91,7 +91,7 @@
|
||||
:placeholder="fillPlaceHolder"
|
||||
:readonly="readonly"
|
||||
:disabled="disabled"
|
||||
:autoComplete="autoComplete"
|
||||
:autocomplete="autoComplete"
|
||||
:minlength="minlength"
|
||||
:maxlength="maxlength"
|
||||
:required="required"
|
||||
|
@ -12,7 +12,7 @@ import Editor from 'tui-editor'
|
||||
import defaultOptions from './default-options'
|
||||
|
||||
export default {
|
||||
name: 'MarddownEditor',
|
||||
name: 'MarkdownEditor',
|
||||
props: {
|
||||
value: {
|
||||
type: String,
|
||||
|
@ -5,7 +5,8 @@
|
||||
<slot />
|
||||
</div>
|
||||
</div>
|
||||
<img :src="image" class="pan-thumb">
|
||||
<!-- eslint-disable-next-line -->
|
||||
<div :style="{backgroundImage: `url(${image})`}" class="pan-thumb"></div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@ -52,7 +53,8 @@ export default {
|
||||
.pan-thumb {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-size: 100%;
|
||||
background-position: center center;
|
||||
background-size: cover;
|
||||
border-radius: 50%;
|
||||
overflow: hidden;
|
||||
position: absolute;
|
||||
@ -60,7 +62,7 @@ export default {
|
||||
transition: all 0.3s ease-in-out;
|
||||
}
|
||||
|
||||
.pan-thumb:after {
|
||||
/* .pan-thumb:after {
|
||||
content: '';
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
@ -71,7 +73,7 @@ export default {
|
||||
margin: -4px 0 0 -4px;
|
||||
background: radial-gradient(ellipse at center, rgba(14, 14, 14, 1) 0%, rgba(125, 126, 125, 1) 100%);
|
||||
box-shadow: 0 0 1px rgba(255, 255, 255, 0.9);
|
||||
}
|
||||
} */
|
||||
|
||||
.pan-info {
|
||||
position: absolute;
|
||||
|
@ -105,32 +105,27 @@ export default {
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.rightPanel-background {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
opacity: 0;
|
||||
transition: opacity .3s cubic-bezier(.7, .3, .1, 1);
|
||||
background: rgba(0, 0, 0, .2);
|
||||
width: 0;
|
||||
height: 0;
|
||||
top: 0;
|
||||
left: 0;
|
||||
position: fixed;
|
||||
z-index: -1;
|
||||
}
|
||||
|
||||
.rightPanel {
|
||||
background: #fff;
|
||||
z-index: 3000;
|
||||
position: fixed;
|
||||
height: 100vh;
|
||||
width: 100%;
|
||||
max-width: 260px;
|
||||
top: 0px;
|
||||
left: 0px;
|
||||
height: 100vh;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
right: 0;
|
||||
box-shadow: 0px 0px 15px 0px rgba(0, 0, 0, .05);
|
||||
transition: all .25s cubic-bezier(.7, .3, .1, 1);
|
||||
transform: translate(100%);
|
||||
background: #fff;
|
||||
z-index: 40000;
|
||||
left: auto;
|
||||
right: 0px;
|
||||
}
|
||||
|
||||
.show {
|
||||
@ -149,20 +144,18 @@ export default {
|
||||
}
|
||||
|
||||
.handle-button {
|
||||
position: absolute;
|
||||
left: -48px;
|
||||
border-radius: 6px 0 0 6px !important;
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
pointer-events: auto;
|
||||
z-index: 0;
|
||||
cursor: pointer;
|
||||
pointer-events: auto;
|
||||
font-size: 24px;
|
||||
position: absolute;
|
||||
left: -48px;
|
||||
text-align: center;
|
||||
font-size: 24px;
|
||||
border-radius: 6px 0 0 6px !important;
|
||||
z-index: 0;
|
||||
pointer-events: auto;
|
||||
cursor: pointer;
|
||||
color: #fff;
|
||||
line-height: 48px;
|
||||
|
||||
i {
|
||||
font-size: 24px;
|
||||
line-height: 48px;
|
||||
|
@ -44,6 +44,7 @@ $t: .1s;
|
||||
width: 250px;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
height: auto!important;
|
||||
&-title {
|
||||
width: 100%;
|
||||
display: block;
|
||||
@ -65,10 +66,12 @@ $t: .1s;
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
background: #e0e0e0;
|
||||
color: #000;
|
||||
line-height: 60px;
|
||||
height: 60px;
|
||||
cursor: pointer;
|
||||
font-size: 20px;
|
||||
font-size: 18px;
|
||||
overflow: hidden;
|
||||
opacity: 1;
|
||||
transition: transform 0.28s ease;
|
||||
&:hover {
|
||||
@ -90,7 +93,7 @@ $t: .1s;
|
||||
.share-dropdown-menu-item {
|
||||
@for $i from 1 through $n {
|
||||
&:nth-of-type(#{$i}) {
|
||||
transition-delay: ($n - $i)*$t;
|
||||
transition-delay: ($n - $i)*$t;
|
||||
transform: translate3d(0, ($i - 1)*60px, 0);
|
||||
}
|
||||
}
|
||||
|
@ -1,10 +1,14 @@
|
||||
<template>
|
||||
<svg :class="svgClass" aria-hidden="true" v-on="$listeners">
|
||||
<div v-if="isExternal" :style="styleExternalIcon" class="svg-external-icon svg-icon" v-on="$listeners" />
|
||||
<svg v-else :class="svgClass" aria-hidden="true" v-on="$listeners">
|
||||
<use :xlink:href="iconName" />
|
||||
</svg>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
// doc: https://panjiachen.github.io/vue-element-admin-site/feature/component/svg-icon.html#usage
|
||||
import { isExternal } from '@/utils/validate'
|
||||
|
||||
export default {
|
||||
name: 'SvgIcon',
|
||||
props: {
|
||||
@ -18,6 +22,9 @@ export default {
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
isExternal() {
|
||||
return isExternal(this.iconClass)
|
||||
},
|
||||
iconName() {
|
||||
return `#icon-${this.iconClass}`
|
||||
},
|
||||
@ -27,6 +34,12 @@ export default {
|
||||
} else {
|
||||
return 'svg-icon'
|
||||
}
|
||||
},
|
||||
styleExternalIcon() {
|
||||
return {
|
||||
mask: `url(${this.iconClass}) no-repeat 50% 50%`,
|
||||
'-webkit-mask': `url(${this.iconClass}) no-repeat 50% 50%`
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -40,4 +53,10 @@ export default {
|
||||
fill: currentColor;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.svg-external-icon {
|
||||
background-color: currentColor;
|
||||
mask-size: cover!important;
|
||||
display: inline-block;
|
||||
}
|
||||
</style>
|
||||
|
59
src/components/Tinymce/dynamicLoadScript.js
Normal file
59
src/components/Tinymce/dynamicLoadScript.js
Normal file
@ -0,0 +1,59 @@
|
||||
let callbacks = []
|
||||
|
||||
function loadedTinymce() {
|
||||
// to fixed https://github.com/PanJiaChen/vue-element-admin/issues/2144
|
||||
// check is successfully downloaded script
|
||||
return window.tinymce
|
||||
}
|
||||
|
||||
const dynamicLoadScript = (src, callback) => {
|
||||
const existingScript = document.getElementById(src)
|
||||
const cb = callback || function() {}
|
||||
|
||||
if (!existingScript) {
|
||||
const script = document.createElement('script')
|
||||
script.src = src // src url for the third-party library being loaded.
|
||||
script.id = src
|
||||
document.body.appendChild(script)
|
||||
callbacks.push(cb)
|
||||
const onEnd = 'onload' in script ? stdOnEnd : ieOnEnd
|
||||
onEnd(script)
|
||||
}
|
||||
|
||||
if (existingScript && cb) {
|
||||
if (loadedTinymce()) {
|
||||
cb(null, existingScript)
|
||||
} else {
|
||||
callbacks.push(cb)
|
||||
}
|
||||
}
|
||||
|
||||
function stdOnEnd(script) {
|
||||
script.onload = function() {
|
||||
// this.onload = null here is necessary
|
||||
// because even IE9 works not like others
|
||||
this.onerror = this.onload = null
|
||||
for (const cb of callbacks) {
|
||||
cb(null, script)
|
||||
}
|
||||
callbacks = null
|
||||
}
|
||||
script.onerror = function() {
|
||||
this.onerror = this.onload = null
|
||||
cb(new Error('Failed to load ' + src), script)
|
||||
}
|
||||
}
|
||||
|
||||
function ieOnEnd(script) {
|
||||
script.onreadystatechange = function() {
|
||||
if (this.readyState !== 'complete' && this.readyState !== 'loaded') return
|
||||
this.onreadystatechange = null
|
||||
for (const cb of callbacks) {
|
||||
cb(null, script) // there is no way to catch loading errors in IE8
|
||||
}
|
||||
callbacks = null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default dynamicLoadScript
|
@ -15,6 +15,10 @@
|
||||
import editorImage from './components/EditorImage'
|
||||
import plugins from './plugins'
|
||||
import toolbar from './toolbar'
|
||||
import load from './dynamicLoadScript'
|
||||
|
||||
// why use this cdn, detail see https://github.com/PanJiaChen/tinymce-all-in-one
|
||||
const tinymceCDN = 'https://cdn.jsdelivr.net/npm/tinymce-all-in-one@4.9.3/tinymce.min.js'
|
||||
|
||||
export default {
|
||||
name: 'Tinymce',
|
||||
@ -91,10 +95,12 @@ export default {
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.initTinymce()
|
||||
this.init()
|
||||
},
|
||||
activated() {
|
||||
this.initTinymce()
|
||||
if (window.tinymce) {
|
||||
this.initTinymce()
|
||||
}
|
||||
},
|
||||
deactivated() {
|
||||
this.destroyTinymce()
|
||||
@ -103,6 +109,16 @@ export default {
|
||||
this.destroyTinymce()
|
||||
},
|
||||
methods: {
|
||||
init() {
|
||||
// dynamic load tinymce from cdn
|
||||
load(tinymceCDN, (err) => {
|
||||
if (err) {
|
||||
this.$message.error(err.message)
|
||||
return
|
||||
}
|
||||
this.initTinymce()
|
||||
})
|
||||
},
|
||||
initTinymce() {
|
||||
const _this = this
|
||||
window.tinymce.init({
|
||||
@ -138,7 +154,11 @@ export default {
|
||||
editor.on('FullscreenStateChanged', (e) => {
|
||||
_this.fullscreen = e.state
|
||||
})
|
||||
}
|
||||
},
|
||||
// it will try to keep these URLs intact
|
||||
// https://www.tiny.cloud/docs-3x/reference/configuration/Configuration3x@convert_urls/
|
||||
// https://stackoverflow.com/questions/5196205/disable-tinymce-absolute-to-relative-url-conversions
|
||||
convert_urls: false
|
||||
// 整合七牛上传
|
||||
// images_dataimg_filter(img) {
|
||||
// setTimeout(() => {
|
||||
|
@ -45,7 +45,7 @@ export function numberFormatter(num, digits) {
|
||||
]
|
||||
for (let i = 0; i < si.length; i++) {
|
||||
if (num >= si[i].value) {
|
||||
return (num / si[i].value + 0.1).toFixed(digits).replace(/\.0+$|(\.[0-9]*[1-9])0+$/, '$1') + si[i].symbol
|
||||
return (num / si[i].value).toFixed(digits).replace(/\.0+$|(\.[0-9]*[1-9])0+$/, '$1') + si[i].symbol
|
||||
}
|
||||
}
|
||||
return num.toString()
|
||||
|
@ -58,8 +58,6 @@ export default {
|
||||
|
||||
.fixed-header+.app-main {
|
||||
padding-top: 50px;
|
||||
height: 100vh;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.hasTagsView {
|
||||
|
@ -30,8 +30,8 @@
|
||||
<a target="_blank" href="https://panjiachen.github.io/vue-element-admin-site/#/">
|
||||
<el-dropdown-item>Docs</el-dropdown-item>
|
||||
</a>
|
||||
<el-dropdown-item divided>
|
||||
<span style="display:block;" @click="logout">{{ $t('navbar.logOut') }}</span>
|
||||
<el-dropdown-item divided @click.native="logout">
|
||||
<span style="display:block;">{{ $t('navbar.logOut') }}</span>
|
||||
</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</el-dropdown> -->
|
||||
|
@ -27,6 +27,18 @@
|
||||
<span>{{ $t('settings.sidebarLogo') }}</span>
|
||||
<el-switch v-model="sidebarLogo" class="drawer-switch" />
|
||||
</div>
|
||||
<a v-if="isShowJob" href="https://panjiachen.github.io/vue-element-admin-site/zh/job/" target="_blank" class="job-link">
|
||||
<el-alert
|
||||
title="部门目前非常缺人!有兴趣的可以点击了解详情。坐标: 字节跳动"
|
||||
type="success"
|
||||
:closable="false"
|
||||
/>
|
||||
</a>
|
||||
|
||||
<div v-if="lang === 'zh'" class="drawer-item">
|
||||
<span>菜单支持拼音搜索</span>
|
||||
<el-switch v-model="supportPinyinSearch" class="drawer-switch" />
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
@ -41,6 +53,9 @@ export default {
|
||||
return {}
|
||||
},
|
||||
computed: {
|
||||
isShowJob() {
|
||||
return this.$store.getters.language === 'zh'
|
||||
},
|
||||
fixedHeader: {
|
||||
get() {
|
||||
return this.$store.state.settings.fixedHeader
|
||||
@ -84,6 +99,20 @@ export default {
|
||||
value: val
|
||||
})
|
||||
}
|
||||
},
|
||||
supportPinyinSearch: {
|
||||
get() {
|
||||
return this.$store.state.settings.supportPinyinSearch
|
||||
},
|
||||
set(val) {
|
||||
this.$store.dispatch('settings/changeSetting', {
|
||||
key: 'supportPinyinSearch',
|
||||
value: val
|
||||
})
|
||||
}
|
||||
},
|
||||
lang() {
|
||||
return this.$store.getters.language
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
@ -120,5 +149,13 @@ export default {
|
||||
.drawer-switch {
|
||||
float: right
|
||||
}
|
||||
|
||||
.job-link{
|
||||
display: block;
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
@ -1,7 +1,5 @@
|
||||
|
||||
<template>
|
||||
<!-- eslint-disable vue/require-component-is -->
|
||||
<component v-bind="linkProps(to)">
|
||||
<component :is="type" v-bind="linkProps(to)">
|
||||
<slot />
|
||||
</component>
|
||||
</template>
|
||||
@ -16,19 +14,28 @@ export default {
|
||||
required: true
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
isExternal() {
|
||||
return isExternal(this.to)
|
||||
},
|
||||
type() {
|
||||
if (this.isExternal) {
|
||||
return 'a'
|
||||
}
|
||||
return 'router-link'
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
linkProps(route) {
|
||||
if (isExternal(route.path)) {
|
||||
linkProps(to) {
|
||||
if (this.isExternal) {
|
||||
return {
|
||||
is: 'a',
|
||||
href: route.path,
|
||||
href: to,
|
||||
target: '_blank',
|
||||
rel: 'noopener'
|
||||
}
|
||||
}
|
||||
return {
|
||||
is: 'router-link',
|
||||
to: { name: route.name }
|
||||
to: to
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div v-if="!item.hidden" class="menu-wrapper">
|
||||
<div v-if="!item.hidden">
|
||||
<template v-if="hasOneShowingChild(item.children,item) && (!onlyOneChild.children||onlyOneChild.noShowingChildren)&&!item.alwaysShow">
|
||||
<app-link v-if="onlyOneChild.meta" :to="onlyOneChild">
|
||||
<el-menu-item :index="resolvePath(onlyOneChild.path)" :class="{'submenu-title-noDropdown':!isNest}">
|
||||
|
@ -31,12 +31,21 @@ export default {
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.scrollWrapper.addEventListener('scroll', this.emitScroll, true)
|
||||
},
|
||||
beforeDestroy() {
|
||||
this.scrollWrapper.removeEventListener('scroll', this.emitScroll)
|
||||
},
|
||||
methods: {
|
||||
handleScroll(e) {
|
||||
const eventDelta = e.wheelDelta || -e.deltaY * 40
|
||||
const $scrollWrapper = this.scrollWrapper
|
||||
$scrollWrapper.scrollLeft = $scrollWrapper.scrollLeft + eventDelta / 4
|
||||
},
|
||||
emitScroll() {
|
||||
this.$emit('scroll')
|
||||
},
|
||||
moveToTarget(currentTag) {
|
||||
const $container = this.$refs.scrollContainer.$el
|
||||
const $containerWidth = $container.offsetWidth
|
||||
|
@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div id="tags-view-container" class="tags-view-container">
|
||||
<scroll-pane ref="scrollPane" class="tags-view-wrapper">
|
||||
<scroll-pane ref="scrollPane" class="tags-view-wrapper" @scroll="handleScroll">
|
||||
<draggable
|
||||
v-if="!isMobile"
|
||||
:list="visitedViews"
|
||||
@ -23,37 +23,27 @@
|
||||
<div v-if="!tag.meta.affix" class="el-icon-close" @click.prevent.stop="closeSelectedTag(tag)" />
|
||||
</router-link>
|
||||
</draggable>
|
||||
<template v-else>
|
||||
<router-link
|
||||
v-for="tag in visitedViews"
|
||||
ref="tag"
|
||||
:key="tag.path"
|
||||
:class="isActive(tag)?'active':''"
|
||||
:to="{ name: tag.name, path: tag.path, query: tag.query, fullPath: tag.fullPath, params: tag.params }"
|
||||
tag="span"
|
||||
class="tags-view-item"
|
||||
@click.middle.native="!isAffix(tag) ? closeSelectedTag(tag) : ''"
|
||||
@contextmenu.prevent.native="openMenu(tag,$event)"
|
||||
>
|
||||
<div class="tag-title">{{ generateTitle(tag.title) }}</div>
|
||||
<div v-if="!isAffix(tag)" class="el-icon-close" @click.prevent.stop="closeSelectedTag(tag)" />
|
||||
</router-link>
|
||||
</template>
|
||||
<router-link
|
||||
v-for="tag in visitedViews"
|
||||
v-else
|
||||
ref="tag"
|
||||
:key="tag.path"
|
||||
:class="isActive(tag)?'active':''"
|
||||
:to="{ name: tag.name, path: tag.path, query: tag.query, fullPath: tag.fullPath, params: tag.params }"
|
||||
tag="span"
|
||||
class="tags-view-item"
|
||||
@click.middle.native="!isAffix(tag)?closeSelectedTag(tag):''"
|
||||
@contextmenu.prevent.native="openMenu(tag,$event)"
|
||||
>
|
||||
{{ generateTitle(tag.title) }}
|
||||
<span v-if="!isAffix(tag)" class="el-icon-close" @click.prevent.stop="closeSelectedTag(tag)" />
|
||||
</router-link>
|
||||
</scroll-pane>
|
||||
<ul v-show="visible" :style="{left:left+'px',top:top+'px'}" class="contextmenu">
|
||||
<li @click="refreshSelectedTag(selectedTag)">
|
||||
{{ $t('tagsView.refresh') }}
|
||||
</li>
|
||||
<li v-if="!isAffix(selectedTag)" @click="closeSelectedTag(selectedTag)">
|
||||
{{
|
||||
$t('tagsView.close') }}
|
||||
</li>
|
||||
<li @click="closeOthersTags">
|
||||
{{ $t('tagsView.closeOthers') }}
|
||||
</li>
|
||||
<li @click="closeAllTags(selectedTag)">
|
||||
{{ $t('tagsView.closeAll') }}
|
||||
</li>
|
||||
<li @click="refreshSelectedTag(selectedTag)">{{ $t('tagsView.refresh') }}</li>
|
||||
<li v-if="!isAffix(selectedTag)" @click="closeSelectedTag(selectedTag)">{{ $t('tagsView.close') }}</li>
|
||||
<li @click="closeOthersTags">{{ $t('tagsView.closeOthers') }}</li>
|
||||
<li @click="closeAllTags(selectedTag)">{{ $t('tagsView.closeAll') }}</li>
|
||||
</ul>
|
||||
</div>
|
||||
</template>
|
||||
@ -235,7 +225,7 @@ export default {
|
||||
toLastView(visitedViews, view) {
|
||||
const latestView = visitedViews.slice(-1)[0]
|
||||
if (latestView) {
|
||||
this.$router.push(latestView)
|
||||
this.$router.push(latestView.fullPath)
|
||||
} else {
|
||||
// now the default is to redirect to the home page if there is no tags-view,
|
||||
// you can adjust it according to your needs.
|
||||
@ -271,6 +261,9 @@ export default {
|
||||
// to avoid Firefox bug
|
||||
// Detail see : https://github.com/RubaXa/Sortable/issues/1012
|
||||
dataTransfer.setData('Text', '')
|
||||
},
|
||||
handleScroll() {
|
||||
this.closeMenu()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -39,10 +39,10 @@ import * as globalMethods from '@/utils/ADempiere/globalMethods' // global metho
|
||||
* you can execute: mockXHR()
|
||||
*
|
||||
* Currently MockJs will be used in the production environment,
|
||||
* please remove it before going online! ! !
|
||||
* please remove it before going online ! ! !
|
||||
*/
|
||||
import { mockXHR } from '../mock'
|
||||
if (process.env.NODE_ENV === 'production') {
|
||||
const { mockXHR } = require('../mock')
|
||||
mockXHR()
|
||||
}
|
||||
Vue.use(VMarkdown)
|
||||
|
@ -24,7 +24,7 @@ router.beforeEach(async(to, from, next) => {
|
||||
if (to.path === '/login') {
|
||||
// if is logged in, redirect to the home page
|
||||
next({ path: '/' })
|
||||
NProgress.done()
|
||||
NProgress.done() // hack: https://github.com/PanJiaChen/vue-element-admin/pull/2939
|
||||
} else {
|
||||
// determine whether the user has obtained his permission roles through getInfo
|
||||
// const hasRoles = store.getters.roles && store.getters.roles.length > 0
|
||||
|
@ -45,7 +45,7 @@ export const constantRoutes = [
|
||||
hidden: true,
|
||||
children: [
|
||||
{
|
||||
path: '/redirect/:path*',
|
||||
path: '/redirect/:path(.*)',
|
||||
component: () => import('@/views/redirect/index')
|
||||
}
|
||||
]
|
||||
@ -93,9 +93,9 @@ export const constantRoutes = [
|
||||
hidden: true
|
||||
},
|
||||
{
|
||||
path: '',
|
||||
path: '/',
|
||||
component: Layout,
|
||||
redirect: 'dashboard',
|
||||
redirect: '/dashboard',
|
||||
meta: { title: 'dashboard', icon: 'dashboard', affix: true, breadcrumb: false },
|
||||
children: [
|
||||
{
|
||||
@ -422,6 +422,7 @@ export const asyncRoutes = [
|
||||
]
|
||||
},
|
||||
|
||||
// 404 page must be placed at the end !!!
|
||||
{ path: '*', redirect: '/404', hidden: true }
|
||||
]
|
||||
|
||||
|
@ -25,6 +25,13 @@ module.exports = {
|
||||
*/
|
||||
sidebarLogo: true,
|
||||
|
||||
/**
|
||||
* @type {boolean} true | false
|
||||
* @description Whether support pinyin search in headerSearch
|
||||
* Bundle size minified 47.3kb,minified + gzipped 63kb
|
||||
*/
|
||||
supportPinyinSearch: true,
|
||||
|
||||
/**
|
||||
* @type {string | array} 'production' | ['production', 'development']
|
||||
* @description Need show err logs component.
|
||||
|
@ -5,12 +5,18 @@ const state = {
|
||||
const mutations = {
|
||||
ADD_ERROR_LOG: (state, log) => {
|
||||
state.logs.push(log)
|
||||
},
|
||||
CLEAR_ERROR_LOG: (state) => {
|
||||
state.logs.splice(0)
|
||||
}
|
||||
}
|
||||
|
||||
const actions = {
|
||||
addErrorLog({ commit }, log) {
|
||||
commit('ADD_ERROR_LOG', log)
|
||||
},
|
||||
clearErrorLog({ commit }) {
|
||||
commit('CLEAR_ERROR_LOG')
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,15 +1,15 @@
|
||||
import variables from '@/styles/element-variables.scss'
|
||||
import defaultSettings from '@/settings'
|
||||
|
||||
const { showSettings, tagsView, fixedHeader, sidebarLogo } = defaultSettings
|
||||
const { showSettings, tagsView, fixedHeader, sidebarLogo, supportPinyinSearch } = defaultSettings
|
||||
|
||||
const state = {
|
||||
theme: variables.theme,
|
||||
showSettings: showSettings,
|
||||
tagsView: tagsView,
|
||||
fixedHeader: fixedHeader,
|
||||
showContextMenu: true,
|
||||
sidebarLogo: sidebarLogo
|
||||
showSettings,
|
||||
tagsView,
|
||||
fixedHeader,
|
||||
sidebarLogo,
|
||||
supportPinyinSearch
|
||||
}
|
||||
|
||||
const mutations = {
|
||||
|
@ -41,13 +41,8 @@ const mutations = {
|
||||
}
|
||||
},
|
||||
DEL_CACHED_VIEW: (state, view) => {
|
||||
for (const i of state.cachedViews) {
|
||||
if (i === view.name) {
|
||||
const index = state.cachedViews.indexOf(i)
|
||||
state.cachedViews.splice(index, 1)
|
||||
break
|
||||
}
|
||||
}
|
||||
const index = state.cachedViews.indexOf(view.name)
|
||||
index > -1 && state.cachedViews.splice(index, 1)
|
||||
},
|
||||
|
||||
DEL_OTHERS_VISITED_VIEWS: (state, view) => {
|
||||
@ -56,12 +51,12 @@ const mutations = {
|
||||
})
|
||||
},
|
||||
DEL_OTHERS_CACHED_VIEWS: (state, view) => {
|
||||
for (const i of state.cachedViews) {
|
||||
if (i === view.name) {
|
||||
const index = state.cachedViews.indexOf(i)
|
||||
state.cachedViews = state.cachedViews.slice(index, index + 1)
|
||||
break
|
||||
}
|
||||
const index = state.cachedViews.indexOf(view.name)
|
||||
if (index > -1) {
|
||||
state.cachedViews = state.cachedViews.slice(index, index + 1)
|
||||
} else {
|
||||
// if index = -1, there is no cached tags
|
||||
state.cachedViews = []
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -294,6 +294,11 @@ const actions = {
|
||||
removeToken()
|
||||
removeCurrentRole()
|
||||
resetRouter()
|
||||
|
||||
// reset visited views and cached views
|
||||
// to fixed https://github.com/PanJiaChen/vue-element-admin/issues/2485
|
||||
dispatch('tagsView/delAllViews', null, { root: true })
|
||||
|
||||
resolve()
|
||||
}).catch(error => {
|
||||
reject(error)
|
||||
|
@ -31,7 +31,7 @@
|
||||
.fixed-width {
|
||||
.el-button--mini {
|
||||
padding: 7px 10px;
|
||||
width: 60px;
|
||||
min-width: 60px;
|
||||
}
|
||||
}
|
||||
|
||||
@ -77,3 +77,8 @@
|
||||
.el-range-editor.el-input__inner {
|
||||
display: inline-flex !important;
|
||||
}
|
||||
|
||||
// to fix el-date-picker css style
|
||||
.el-range-separator {
|
||||
box-sizing: content-box;
|
||||
}
|
||||
|
@ -6,7 +6,7 @@
|
||||
/* theme color */
|
||||
$--color-primary: #1890ff;
|
||||
$--color-success: #13ce66;
|
||||
$--color-warning: #FFBA00;
|
||||
$--color-warning: #ffba00;
|
||||
$--color-danger: #ff4949;
|
||||
// $--color-info: #1E1E1E;
|
||||
|
||||
@ -17,10 +17,10 @@ $--button-font-weight: 400;
|
||||
$--border-color-light: #dfe4ed;
|
||||
$--border-color-lighter: #e6ebf5;
|
||||
|
||||
$--table-border:1px solid#dfe6ec;
|
||||
$--table-border: 1px solid #dfe6ec;
|
||||
|
||||
/* icon font path, required */
|
||||
$--font-path: '~element-ui/lib/theme-chalk/fonts';
|
||||
$--font-path: "~element-ui/lib/theme-chalk/fonts";
|
||||
|
||||
@import "~element-ui/packages/theme-chalk/src/index";
|
||||
|
||||
|
@ -22,14 +22,10 @@ export default function handleClipboard(text, event) {
|
||||
})
|
||||
clipboard.on('success', () => {
|
||||
clipboardSuccess()
|
||||
clipboard.off('error')
|
||||
clipboard.off('success')
|
||||
clipboard.destroy()
|
||||
})
|
||||
clipboard.on('error', () => {
|
||||
clipboardError()
|
||||
clipboard.off('error')
|
||||
clipboard.off('success')
|
||||
clipboard.destroy()
|
||||
})
|
||||
clipboard.onClick(event)
|
||||
|
@ -6,10 +6,10 @@
|
||||
* Parse the time to string
|
||||
* @param {(Object|string|number)} time
|
||||
* @param {string} cFormat
|
||||
* @returns {string}
|
||||
* @returns {string | null}
|
||||
*/
|
||||
export function parseTime(time, cFormat) {
|
||||
if (arguments.length === 0) {
|
||||
if (arguments.length === 0 || !time) {
|
||||
return null
|
||||
}
|
||||
const format = cFormat || '{y}-{m}-{d} {h}:{i}:{s}'
|
||||
@ -17,9 +17,17 @@ export function parseTime(time, cFormat) {
|
||||
if (typeof time === 'object') {
|
||||
date = time
|
||||
} else {
|
||||
if ((typeof time === 'string') && (/^[0-9]+$/.test(time))) {
|
||||
time = parseInt(time)
|
||||
if ((typeof time === 'string')) {
|
||||
if ((/^[0-9]+$/.test(time))) {
|
||||
// support "1548221490638"
|
||||
time = parseInt(time)
|
||||
} else {
|
||||
// support safari
|
||||
// https://stackoverflow.com/questions/4310953/invalid-date-in-safari
|
||||
time = time.replace(new RegExp(/-/gm), '/')
|
||||
}
|
||||
}
|
||||
|
||||
if ((typeof time === 'number') && (time.toString().length === 10)) {
|
||||
time = time * 1000
|
||||
}
|
||||
@ -34,14 +42,11 @@ export function parseTime(time, cFormat) {
|
||||
s: date.getSeconds(),
|
||||
a: date.getDay()
|
||||
}
|
||||
const time_str = format.replace(/{(y|m|d|h|i|s|a)+}/g, (result, key) => {
|
||||
let value = formatObj[key]
|
||||
const time_str = format.replace(/{([ymdhisa])+}/g, (result, key) => {
|
||||
const value = formatObj[key]
|
||||
// Note: getDay() returns 0 on Sunday
|
||||
if (key === 'a') { return ['日', '一', '二', '三', '四', '五', '六'][value ] }
|
||||
if (result.length > 0 && value < 10) {
|
||||
value = '0' + value
|
||||
}
|
||||
return value || 0
|
||||
return value.toString().padStart(2, '0')
|
||||
})
|
||||
return time_str
|
||||
}
|
||||
|
@ -6,7 +6,7 @@ import { getToken } from '@/utils/auth'
|
||||
// create an axios instance
|
||||
const service = axios.create({
|
||||
baseURL: process.env.VUE_APP_BASE_API, // url = base url + request url
|
||||
withCredentials: true, // send cookies when cross-domain requests
|
||||
// withCredentials: true, // send cookies when cross-domain requests
|
||||
timeout: 5000 // request timeout
|
||||
})
|
||||
|
||||
@ -48,7 +48,7 @@ service.interceptors.response.use(
|
||||
// if the custom code is not 20000, it is judged as an error.
|
||||
if (res.code !== 20000) {
|
||||
Message({
|
||||
message: res.message || 'error',
|
||||
message: res.message || 'Error',
|
||||
type: 'error',
|
||||
duration: 5 * 1000
|
||||
})
|
||||
@ -66,7 +66,7 @@ service.interceptors.response.use(
|
||||
})
|
||||
})
|
||||
}
|
||||
return Promise.reject(res.message || 'error')
|
||||
return Promise.reject(new Error(res.message || 'Error'))
|
||||
} else {
|
||||
return res
|
||||
}
|
||||
|
6
src/vendor/Export2Excel.js
vendored
6
src/vendor/Export2Excel.js
vendored
@ -1,5 +1,5 @@
|
||||
/* eslint-disable */
|
||||
require('script-loader!file-saver');
|
||||
import { saveAs } from 'file-saver'
|
||||
import XLSX from 'xlsx'
|
||||
|
||||
function generateArray(table) {
|
||||
@ -151,14 +151,14 @@ export function export_json_to_excel({
|
||||
filename,
|
||||
merges = [],
|
||||
autoWidth = true,
|
||||
bookType= 'xlsx'
|
||||
bookType = 'xlsx'
|
||||
} = {}) {
|
||||
/* original data */
|
||||
filename = filename || 'excel-list'
|
||||
data = [...data]
|
||||
data.unshift(header);
|
||||
|
||||
for (let i = multiHeader.length-1; i > -1; i--) {
|
||||
for (let i = multiHeader.length - 1; i > -1; i--) {
|
||||
data.unshift(multiHeader[i])
|
||||
}
|
||||
|
||||
|
2
src/vendor/Export2Zip.js
vendored
2
src/vendor/Export2Zip.js
vendored
@ -1,5 +1,5 @@
|
||||
/* eslint-disable */
|
||||
require('script-loader!file-saver');
|
||||
import { saveAs } from 'file-saver'
|
||||
import JSZip from 'jszip'
|
||||
|
||||
export function export_txt_to_zip(th, jsonData, txtName, zipName) {
|
||||
|
@ -3,13 +3,13 @@
|
||||
<el-tabs v-model="activeName">
|
||||
<el-tab-pane label="use clipboard directly" name="directly">
|
||||
<el-input v-model="inputData" placeholder="Please input" style="width:400px;max-width:100%;" />
|
||||
<el-button type="primary" icon="document" @click="handleCopy(inputData,$event)">
|
||||
<el-button type="primary" icon="el-icon-document" @click="handleCopy(inputData,$event)">
|
||||
copy
|
||||
</el-button>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="use clipboard by v-directive" name="v-directive">
|
||||
<el-input v-model="inputData" placeholder="Please input" style="width:400px;max-width:100%;" />
|
||||
<el-button v-clipboard:copy="inputData" v-clipboard:success="clipboardSuccess" type="primary" icon="document">
|
||||
<el-button v-clipboard:copy="inputData" v-clipboard:success="clipboardSuccess" type="primary" icon="el-icon-document">
|
||||
copy
|
||||
</el-button>
|
||||
</el-tab-pane>
|
||||
|
@ -7,7 +7,7 @@
|
||||
|
||||
<pan-thumb :image="image" />
|
||||
|
||||
<el-button type="primary" icon="upload" style="position: absolute;bottom: 15px;margin-left: 40px;" @click="imagecropperShow=true">
|
||||
<el-button type="primary" icon="el-icon-upload" style="position: absolute;bottom: 15px;margin-left: 40px;" @click="imagecropperShow=true">
|
||||
Change Avatar
|
||||
</el-button>
|
||||
|
||||
|
@ -49,7 +49,7 @@
|
||||
<div style="height:100px;">
|
||||
<el-form :model="demo" :rules="demoRules">
|
||||
<el-form-item prop="title">
|
||||
<md-input v-model="demo.title" icon="search" name="title" placeholder="输入标题">
|
||||
<md-input v-model="demo.title" icon="el-icon-search" name="title" placeholder="输入标题">
|
||||
标题
|
||||
</md-input>
|
||||
</el-form-item>
|
||||
|
@ -5,11 +5,12 @@
|
||||
<script>
|
||||
import echarts from 'echarts'
|
||||
require('echarts/theme/macarons') // echarts theme
|
||||
import { debounce } from '@/utils'
|
||||
import resize from './mixins/resize'
|
||||
|
||||
const animationDuration = 6000
|
||||
|
||||
export default {
|
||||
mixins: [resize],
|
||||
props: {
|
||||
className: {
|
||||
type: String,
|
||||
@ -30,19 +31,14 @@ export default {
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.initChart()
|
||||
this.__resizeHandler = debounce(() => {
|
||||
if (this.chart) {
|
||||
this.chart.resize()
|
||||
}
|
||||
}, 100)
|
||||
window.addEventListener('resize', this.__resizeHandler)
|
||||
this.$nextTick(() => {
|
||||
this.initChart()
|
||||
})
|
||||
},
|
||||
beforeDestroy() {
|
||||
if (!this.chart) {
|
||||
return
|
||||
}
|
||||
window.removeEventListener('resize', this.__resizeHandler)
|
||||
this.chart.dispose()
|
||||
this.chart = null
|
||||
},
|
||||
|
@ -5,9 +5,10 @@
|
||||
<script>
|
||||
import echarts from 'echarts'
|
||||
require('echarts/theme/macarons') // echarts theme
|
||||
import { debounce } from '@/utils'
|
||||
import resize from './mixins/resize'
|
||||
|
||||
export default {
|
||||
mixins: [resize],
|
||||
props: {
|
||||
className: {
|
||||
type: String,
|
||||
@ -32,8 +33,7 @@ export default {
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
chart: null,
|
||||
sidebarElm: null
|
||||
chart: null
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
@ -45,38 +45,21 @@ export default {
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.initChart()
|
||||
if (this.autoResize) {
|
||||
this.__resizeHandler = debounce(() => {
|
||||
if (this.chart) {
|
||||
this.chart.resize()
|
||||
}
|
||||
}, 100)
|
||||
window.addEventListener('resize', this.__resizeHandler)
|
||||
}
|
||||
|
||||
// 监听侧边栏的变化
|
||||
this.sidebarElm = document.getElementsByClassName('sidebar-container')[0]
|
||||
this.sidebarElm && this.sidebarElm.addEventListener('transitionend', this.sidebarResizeHandler)
|
||||
this.$nextTick(() => {
|
||||
this.initChart()
|
||||
})
|
||||
},
|
||||
beforeDestroy() {
|
||||
if (!this.chart) {
|
||||
return
|
||||
}
|
||||
if (this.autoResize) {
|
||||
window.removeEventListener('resize', this.__resizeHandler)
|
||||
}
|
||||
|
||||
this.sidebarElm && this.sidebarElm.removeEventListener('transitionend', this.sidebarResizeHandler)
|
||||
|
||||
this.chart.dispose()
|
||||
this.chart = null
|
||||
},
|
||||
methods: {
|
||||
sidebarResizeHandler(e) {
|
||||
if (e.propertyName === 'width') {
|
||||
this.__resizeHandler()
|
||||
}
|
||||
initChart() {
|
||||
this.chart = echarts.init(this.$el, 'macarons')
|
||||
this.setOptions(this.chartData)
|
||||
},
|
||||
setOptions({ expectedData, actualData } = {}) {
|
||||
this.chart.setOption({
|
||||
@ -146,10 +129,6 @@ export default {
|
||||
animationEasing: 'quadraticOut'
|
||||
}]
|
||||
})
|
||||
},
|
||||
initChart() {
|
||||
this.chart = echarts.init(this.$el, 'macarons')
|
||||
this.setOptions(this.chartData)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -73,9 +73,11 @@ export default {
|
||||
<style lang="scss" scoped>
|
||||
.panel-group {
|
||||
margin-top: 18px;
|
||||
.card-panel-col{
|
||||
|
||||
.card-panel-col {
|
||||
margin-bottom: 32px;
|
||||
}
|
||||
|
||||
.card-panel {
|
||||
height: 108px;
|
||||
cursor: pointer;
|
||||
@ -86,35 +88,45 @@ export default {
|
||||
background: #fff;
|
||||
box-shadow: 4px 4px 40px rgba(0, 0, 0, .05);
|
||||
border-color: rgba(0, 0, 0, .05);
|
||||
|
||||
&:hover {
|
||||
.card-panel-icon-wrapper {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.icon-people {
|
||||
background: #40c9c6;
|
||||
background: #40c9c6;
|
||||
}
|
||||
|
||||
.icon-message {
|
||||
background: #36a3f7;
|
||||
}
|
||||
|
||||
.icon-money {
|
||||
background: #f4516c;
|
||||
}
|
||||
|
||||
.icon-shopping {
|
||||
background: #34bfa3
|
||||
}
|
||||
}
|
||||
|
||||
.icon-people {
|
||||
color: #40c9c6;
|
||||
}
|
||||
|
||||
.icon-message {
|
||||
color: #36a3f7;
|
||||
}
|
||||
|
||||
.icon-money {
|
||||
color: #f4516c;
|
||||
}
|
||||
|
||||
.icon-shopping {
|
||||
color: #34bfa3
|
||||
}
|
||||
|
||||
.card-panel-icon-wrapper {
|
||||
float: left;
|
||||
margin: 14px 0 0 14px;
|
||||
@ -122,25 +134,48 @@ export default {
|
||||
transition: all 0.38s ease-out;
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.card-panel-icon {
|
||||
float: left;
|
||||
font-size: 48px;
|
||||
}
|
||||
|
||||
.card-panel-description {
|
||||
float: right;
|
||||
font-weight: bold;
|
||||
margin: 26px;
|
||||
margin-left: 0px;
|
||||
|
||||
.card-panel-text {
|
||||
line-height: 18px;
|
||||
color: rgba(0, 0, 0, 0.45);
|
||||
font-size: 16px;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.card-panel-num {
|
||||
font-size: 20px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width:550px) {
|
||||
.card-panel-description {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.card-panel-icon-wrapper {
|
||||
float: none !important;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
margin: 0 !important;
|
||||
|
||||
.svg-icon {
|
||||
display: block;
|
||||
margin: 14px auto !important;
|
||||
float: none !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
@ -5,9 +5,10 @@
|
||||
<script>
|
||||
import echarts from 'echarts'
|
||||
require('echarts/theme/macarons') // echarts theme
|
||||
import { debounce } from '@/utils'
|
||||
import resize from './mixins/resize'
|
||||
|
||||
export default {
|
||||
mixins: [resize],
|
||||
props: {
|
||||
className: {
|
||||
type: String,
|
||||
@ -28,19 +29,14 @@ export default {
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.initChart()
|
||||
this.__resizeHandler = debounce(() => {
|
||||
if (this.chart) {
|
||||
this.chart.resize()
|
||||
}
|
||||
}, 100)
|
||||
window.addEventListener('resize', this.__resizeHandler)
|
||||
this.$nextTick(() => {
|
||||
this.initChart()
|
||||
})
|
||||
},
|
||||
beforeDestroy() {
|
||||
if (!this.chart) {
|
||||
return
|
||||
}
|
||||
window.removeEventListener('resize', this.__resizeHandler)
|
||||
this.chart.dispose()
|
||||
this.chart = null
|
||||
},
|
||||
@ -58,7 +54,6 @@ export default {
|
||||
bottom: '10',
|
||||
data: ['Industries', 'Technology', 'Forex', 'Gold', 'Forecasts']
|
||||
},
|
||||
calculable: true,
|
||||
series: [
|
||||
{
|
||||
name: 'WEEKLY WRITE ARTICLES',
|
||||
|
@ -5,11 +5,12 @@
|
||||
<script>
|
||||
import echarts from 'echarts'
|
||||
require('echarts/theme/macarons') // echarts theme
|
||||
import { debounce } from '@/utils'
|
||||
import resize from './mixins/resize'
|
||||
|
||||
const animationDuration = 3000
|
||||
|
||||
export default {
|
||||
mixins: [resize],
|
||||
props: {
|
||||
className: {
|
||||
type: String,
|
||||
@ -30,19 +31,14 @@ export default {
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.initChart()
|
||||
this.__resizeHandler = debounce(() => {
|
||||
if (this.chart) {
|
||||
this.chart.resize()
|
||||
}
|
||||
}, 100)
|
||||
window.addEventListener('resize', this.__resizeHandler)
|
||||
this.$nextTick(() => {
|
||||
this.initChart()
|
||||
})
|
||||
},
|
||||
beforeDestroy() {
|
||||
if (!this.chart) {
|
||||
return
|
||||
}
|
||||
window.removeEventListener('resize', this.__resizeHandler)
|
||||
this.chart.dispose()
|
||||
this.chart = null
|
||||
},
|
||||
@ -74,7 +70,7 @@ export default {
|
||||
indicator: [
|
||||
{ name: 'Sales', max: 10000 },
|
||||
{ name: 'Administration', max: 20000 },
|
||||
{ name: 'Information Techology', max: 20000 },
|
||||
{ name: 'Information Technology', max: 20000 },
|
||||
{ name: 'Customer Support', max: 20000 },
|
||||
{ name: 'Development', max: 20000 },
|
||||
{ name: 'Marketing', max: 20000 }
|
||||
|
55
src/views/dashboard/admin/components/mixins/resize.js
Normal file
55
src/views/dashboard/admin/components/mixins/resize.js
Normal file
@ -0,0 +1,55 @@
|
||||
import { debounce } from '@/utils'
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
$_sidebarElm: null,
|
||||
$_resizeHandler: null
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.$_resizeHandler = debounce(() => {
|
||||
if (this.chart) {
|
||||
this.chart.resize()
|
||||
}
|
||||
}, 100)
|
||||
this.$_initResizeEvent()
|
||||
this.$_initSidebarResizeEvent()
|
||||
},
|
||||
beforeDestroy() {
|
||||
this.$_destroyResizeEvent()
|
||||
this.$_destroySidebarResizeEvent()
|
||||
},
|
||||
// to fixed bug when cached by keep-alive
|
||||
// https://github.com/PanJiaChen/vue-element-admin/issues/2116
|
||||
activated() {
|
||||
this.$_initResizeEvent()
|
||||
this.$_initSidebarResizeEvent()
|
||||
},
|
||||
deactivated() {
|
||||
this.$_destroyResizeEvent()
|
||||
this.$_destroySidebarResizeEvent()
|
||||
},
|
||||
methods: {
|
||||
// use $_ for mixins properties
|
||||
// https://vuejs.org/v2/style-guide/index.html#Private-property-names-essential
|
||||
$_initResizeEvent() {
|
||||
window.addEventListener('resize', this.$_resizeHandler)
|
||||
},
|
||||
$_destroyResizeEvent() {
|
||||
window.removeEventListener('resize', this.$_resizeHandler)
|
||||
},
|
||||
$_sidebarResizeHandler(e) {
|
||||
if (e.propertyName === 'width') {
|
||||
this.$_resizeHandler()
|
||||
}
|
||||
},
|
||||
$_initSidebarResizeEvent() {
|
||||
this.$_sidebarElm = document.getElementsByClassName('sidebar-container')[0]
|
||||
this.$_sidebarElm && this.$_sidebarElm.addEventListener('transitionend', this.$_sidebarResizeHandler)
|
||||
},
|
||||
$_destroySidebarResizeEvent() {
|
||||
this.$_sidebarElm && this.$_sidebarElm.removeEventListener('transitionend', this.$_sidebarResizeHandler)
|
||||
}
|
||||
}
|
||||
}
|
@ -71,4 +71,10 @@ export default {
|
||||
margin-bottom: 32px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width:1024px) {
|
||||
.chart-wrapper {
|
||||
padding: 8px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
@ -1,11 +1,13 @@
|
||||
<template>
|
||||
<div class="app-container documentation-container">
|
||||
<a class="document-btn" target="_blank" href="https://panjiachen.github.io/vue-element-admin-site/">{{ $t('documentation.documentation') }}</a>
|
||||
<a class="document-btn" target="_blank" href="https://github.com/PanJiaChen/vue-element-admin/">{{ $t('documentation.github') }}</a>
|
||||
<a class="document-btn" target="_blank" href="https://panjiachen.github.io/vue-element-admin-site/">Documentation</a>
|
||||
<a class="document-btn" target="_blank" href="https://github.com/PanJiaChen/vue-element-admin/">Github Repository</a>
|
||||
<a class="document-btn" target="_blank" href="https://panjiachen.gitee.io/vue-element-admin-site/zh/">国内文档</a>
|
||||
<dropdown-menu :items="articleList" style="float:left;margin-left:50px;" title="系列文章" />
|
||||
<dropdown-menu class="document-btn" :items="articleList" title="系列文章" />
|
||||
<a class="document-btn" target="_blank" href="https://panjiachen.github.io/vue-element-admin-site/zh/job/">内推招聘</a>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import DropdownMenu from '@/components/Share/DropdownMenu'
|
||||
|
||||
@ -33,15 +35,19 @@ export default {
|
||||
<style lang="scss" scoped>
|
||||
.documentation-container {
|
||||
margin: 50px;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: space-evenly;
|
||||
|
||||
.document-btn {
|
||||
float: left;
|
||||
margin-left: 50px;
|
||||
flex-shrink: 0;
|
||||
display: block;
|
||||
cursor: pointer;
|
||||
background: black;
|
||||
color: white;
|
||||
height: 60px;
|
||||
width: 200px;
|
||||
margin-bottom: 16px;
|
||||
line-height: 60px;
|
||||
font-size: 20px;
|
||||
text-align: center;
|
||||
|
@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div class="errPage-container">
|
||||
<el-button icon="arrow-left" class="pan-back-btn" @click="back">
|
||||
<el-button icon="el-icon-arrow-left" class="pan-back-btn" @click="back">
|
||||
返回
|
||||
</el-button>
|
||||
<el-row>
|
||||
|
@ -6,7 +6,7 @@
|
||||
<PlatformDropdown v-model="postForm.platforms" />
|
||||
<SourceUrlDropdown v-model="postForm.source_uri" />
|
||||
<el-button v-loading="loading" style="margin-left: 10px;" type="success" @click="submitForm">
|
||||
Publush
|
||||
Publish
|
||||
</el-button>
|
||||
<el-button v-loading="loading" type="warning" @click="draftForm">
|
||||
Draft
|
||||
@ -35,7 +35,7 @@
|
||||
</el-col>
|
||||
|
||||
<el-col :span="10">
|
||||
<el-form-item label-width="120px" label="Publush Time:" class="postInfo-container-item">
|
||||
<el-form-item label-width="120px" label="Publish Time:" class="postInfo-container-item">
|
||||
<el-date-picker v-model="displayTime" type="datetime" format="yyyy-MM-dd HH:mm:ss" placeholder="Select date and time" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
@ -48,7 +48,7 @@
|
||||
:colors="['#99A9BF', '#F7BA2A', '#FF9900']"
|
||||
:low-threshold="1"
|
||||
:high-threshold="3"
|
||||
style="margin-top:8px;"
|
||||
style="display:inline-block"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
@ -172,8 +172,6 @@ export default {
|
||||
if (this.isEdit) {
|
||||
const id = this.$route.params && this.$route.params.id
|
||||
this.fetchData(id)
|
||||
} else {
|
||||
this.postForm = Object.assign({}, defaultForm)
|
||||
}
|
||||
|
||||
// Why need to make a copy of this.$route here?
|
||||
@ -185,12 +183,16 @@ export default {
|
||||
fetchData(id) {
|
||||
fetchArticle(id).then(response => {
|
||||
this.postForm = response.data
|
||||
// Just for test
|
||||
|
||||
// just for test
|
||||
this.postForm.title += ` Article Id:${this.postForm.id}`
|
||||
this.postForm.content_short += ` Article Id:${this.postForm.id}`
|
||||
|
||||
// Set tagsview title
|
||||
// set tagsview title
|
||||
this.setTagsViewTitle()
|
||||
|
||||
// set page title
|
||||
this.setPageTitle()
|
||||
}).catch(err => {
|
||||
console.log(err)
|
||||
})
|
||||
@ -200,6 +202,10 @@ export default {
|
||||
const route = Object.assign({}, this.tempRoute, { title: `${title}-${this.postForm.id}` })
|
||||
this.$store.dispatch('tagsView/updateVisitedView', route)
|
||||
},
|
||||
setPageTitle() {
|
||||
const title = 'Edit Article'
|
||||
document.title = `${title} - ${this.postForm.id}`
|
||||
},
|
||||
submitForm() {
|
||||
console.log(this.postForm)
|
||||
this.$refs.postForm.validate(valid => {
|
||||
|
@ -6,7 +6,7 @@
|
||||
import ArticleDetail from './components/ArticleDetail'
|
||||
|
||||
export default {
|
||||
name: 'CreateForm',
|
||||
name: 'CreateArticle',
|
||||
components: { ArticleDetail }
|
||||
}
|
||||
</script>
|
||||
|
@ -5,7 +5,7 @@
|
||||
<FilenameOption v-model="filename" />
|
||||
<AutoWidthOption v-model="autoWidth" />
|
||||
<BookTypeOption v-model="bookType" />
|
||||
<el-button :loading="downloadLoading" style="margin:0 0 20px 20px;" type="primary" icon="document" @click="handleDownload">
|
||||
<el-button :loading="downloadLoading" style="margin:0 0 20px 20px;" type="primary" icon="el-icon-document" @click="handleDownload">
|
||||
{{ $t('excel.export') }} Excel
|
||||
</el-button>
|
||||
<a href="https://panjiachen.github.io/vue-element-admin-site/feature/component/excel.html" target="_blank" style="margin-left:15px;">
|
||||
@ -13,7 +13,7 @@
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<el-table v-loading="listLoading" :data="list" element-loading-text="拼命加载中" border fit highlight-current-row>
|
||||
<el-table v-loading="listLoading" :data="list" element-loading-text="Loading..." border fit highlight-current-row>
|
||||
<el-table-column align="center" label="Id" width="95">
|
||||
<template slot-scope="scope">
|
||||
{{ scope.$index }}
|
||||
|
@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div class="app-container">
|
||||
|
||||
<el-button :loading="downloadLoading" style="margin-bottom:20px" type="primary" icon="document" @click="handleDownload">Export</el-button>
|
||||
<el-button :loading="downloadLoading" style="margin-bottom:20px" type="primary" icon="el-icon-document" @click="handleDownload">Export</el-button>
|
||||
|
||||
<el-table
|
||||
ref="multipleTable"
|
||||
|
@ -2,7 +2,7 @@
|
||||
<div class="app-container">
|
||||
<!-- $t is vue-i18n global function to translate lang -->
|
||||
<el-input v-model="filename" :placeholder="$t('excel.placeholder')" style="width:350px;" prefix-icon="el-icon-document" />
|
||||
<el-button :loading="downloadLoading" style="margin-bottom:20px" type="primary" icon="document" @click="handleDownload">
|
||||
<el-button :loading="downloadLoading" style="margin-bottom:20px" type="primary" icon="el-icon-document" @click="handleDownload">
|
||||
{{ $t('excel.selectedExport') }}
|
||||
</el-button>
|
||||
<a href="https://panjiachen.github.io/vue-element-admin-site/feature/component/excel.html" target="_blank" style="margin-left:15px;">
|
||||
|
@ -1,74 +1,3 @@
|
||||
const elementIcons = [
|
||||
'info',
|
||||
'error',
|
||||
'success',
|
||||
'warning',
|
||||
'question',
|
||||
'back',
|
||||
'arrow-left',
|
||||
'arrow-down',
|
||||
'arrow-right',
|
||||
'arrow-up',
|
||||
'caret-left',
|
||||
'caret-bottom',
|
||||
'caret-top',
|
||||
'caret-right',
|
||||
'd-arrow-left',
|
||||
'd-arrow-right',
|
||||
'minus',
|
||||
'plus',
|
||||
'remove',
|
||||
'circle-plus',
|
||||
'remove-outline',
|
||||
'circle-plus-outline',
|
||||
'close',
|
||||
'check',
|
||||
'circle-close',
|
||||
'circle-check',
|
||||
'circle-close-outline',
|
||||
'circle-check-outline',
|
||||
'zoom-out',
|
||||
'zoom-in',
|
||||
'd-caret',
|
||||
'sort',
|
||||
'sort-down',
|
||||
'sort-up',
|
||||
'tickets',
|
||||
'document',
|
||||
'goods',
|
||||
'sold-out',
|
||||
'news',
|
||||
'message',
|
||||
'date',
|
||||
'printer',
|
||||
'time',
|
||||
'bell',
|
||||
'mobile-phone',
|
||||
'service',
|
||||
'view',
|
||||
'menu',
|
||||
'more',
|
||||
'more-outline',
|
||||
'star-on',
|
||||
'star-off',
|
||||
'location',
|
||||
'location-outline',
|
||||
'phone',
|
||||
'phone-outline',
|
||||
'picture',
|
||||
'picture-outline',
|
||||
'delete',
|
||||
'search',
|
||||
'edit',
|
||||
'edit-outline',
|
||||
'rank',
|
||||
'refresh',
|
||||
'share',
|
||||
'setting',
|
||||
'upload',
|
||||
'upload2',
|
||||
'download',
|
||||
'loading'
|
||||
]
|
||||
const elementIcons = ['platform-eleme', 'eleme', 'delete-solid', 'delete', 's-tools', 'setting', 'user-solid', 'user', 'phone', 'phone-outline', 'more', 'more-outline', 'star-on', 'star-off', 's-goods', 'goods', 'warning', 'warning-outline', 'question', 'info', 'remove', 'circle-plus', 'success', 'error', 'zoom-in', 'zoom-out', 'remove-outline', 'circle-plus-outline', 'circle-check', 'circle-close', 's-help', 'help', 'minus', 'plus', 'check', 'close', 'picture', 'picture-outline', 'picture-outline-round', 'upload', 'upload2', 'download', 'camera-solid', 'camera', 'video-camera-solid', 'video-camera', 'message-solid', 'bell', 's-cooperation', 's-order', 's-platform', 's-fold', 's-unfold', 's-operation', 's-promotion', 's-home', 's-release', 's-ticket', 's-management', 's-open', 's-shop', 's-marketing', 's-flag', 's-comment', 's-finance', 's-claim', 's-custom', 's-opportunity', 's-data', 's-check', 's-grid', 'menu', 'share', 'd-caret', 'caret-left', 'caret-right', 'caret-bottom', 'caret-top', 'bottom-left', 'bottom-right', 'back', 'right', 'bottom', 'top', 'top-left', 'top-right', 'arrow-left', 'arrow-right', 'arrow-down', 'arrow-up', 'd-arrow-left', 'd-arrow-right', 'video-pause', 'video-play', 'refresh', 'refresh-right', 'refresh-left', 'finished', 'sort', 'sort-up', 'sort-down', 'rank', 'loading', 'view', 'c-scale-to-original', 'date', 'edit', 'edit-outline', 'folder', 'folder-opened', 'folder-add', 'folder-remove', 'folder-delete', 'folder-checked', 'tickets', 'document-remove', 'document-delete', 'document-copy', 'document-checked', 'document', 'document-add', 'printer', 'paperclip', 'takeaway-box', 'search', 'monitor', 'attract', 'mobile', 'scissors', 'umbrella', 'headset', 'brush', 'mouse', 'coordinate', 'magic-stick', 'reading', 'data-line', 'data-board', 'pie-chart', 'data-analysis', 'collection-tag', 'film', 'suitcase', 'suitcase-1', 'receiving', 'collection', 'files', 'notebook-1', 'notebook-2', 'toilet-paper', 'office-building', 'school', 'table-lamp', 'house', 'no-smoking', 'smoking', 'shopping-cart-full', 'shopping-cart-1', 'shopping-cart-2', 'shopping-bag-1', 'shopping-bag-2', 'sold-out', 'sell', 'present', 'box', 'bank-card', 'money', 'coin', 'wallet', 'discount', 'price-tag', 'news', 'guide', 'male', 'female', 'thumb', 'cpu', 'link', 'connection', 'open', 'turn-off', 'set-up', 'chat-round', 'chat-line-round', 'chat-square', 'chat-dot-round', 'chat-dot-square', 'chat-line-square', 'message', 'postcard', 'position', 'turn-off-microphone', 'microphone', 'close-notification', 'bangzhu', 'time', 'odometer', 'crop', 'aim', 'switch-button', 'full-screen', 'copy-document', 'mic', 'stopwatch', 'medal-1', 'medal', 'trophy', 'trophy-1', 'first-aid-kit', 'discover', 'place', 'location', 'location-outline', 'location-information', 'add-location', 'delete-location', 'map-location', 'alarm-clock', 'timer', 'watch-1', 'watch', 'lock', 'unlock', 'key', 'service', 'mobile-phone', 'bicycle', 'truck', 'ship', 'basketball', 'football', 'soccer', 'baseball', 'wind-power', 'light-rain', 'lightning', 'heavy-rain', 'sunrise', 'sunrise-1', 'sunset', 'sunny', 'cloudy', 'partly-cloudy', 'cloudy-and-sunny', 'moon', 'moon-night', 'dish', 'dish-1', 'food', 'chicken', 'fork-spoon', 'knife-fork', 'burger', 'tableware', 'sugar', 'dessert', 'ice-cream', 'hot-water', 'water-cup', 'coffee-cup', 'cold-drink', 'goblet', 'goblet-full', 'goblet-square', 'goblet-square-full', 'refrigerator', 'grape', 'watermelon', 'cherry', 'apple', 'pear', 'orange', 'coffee', 'ice-tea', 'ice-drink', 'milk-tea', 'potato-strips', 'lollipop', 'ice-cream-square', 'ice-cream-round']
|
||||
|
||||
export default elementIcons
|
||||
|
@ -6,29 +6,33 @@
|
||||
</aside>
|
||||
<el-tabs type="border-card">
|
||||
<el-tab-pane label="Icons">
|
||||
<div v-for="item of svgIcons" :key="item" @click="handleClipboard(generateIconCode(item),$event)">
|
||||
<el-tooltip placement="top">
|
||||
<div slot="content">
|
||||
{{ generateIconCode(item) }}
|
||||
</div>
|
||||
<div class="icon-item">
|
||||
<svg-icon :icon-class="item" class-name="disabled" />
|
||||
<span>{{ item }}</span>
|
||||
</div>
|
||||
</el-tooltip>
|
||||
<div class="grid">
|
||||
<div v-for="item of svgIcons" :key="item" @click="handleClipboard(generateIconCode(item),$event)">
|
||||
<el-tooltip placement="top">
|
||||
<div slot="content">
|
||||
{{ generateIconCode(item) }}
|
||||
</div>
|
||||
<div class="icon-item">
|
||||
<svg-icon :icon-class="item" class-name="disabled" />
|
||||
<span>{{ item }}</span>
|
||||
</div>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="Element-UI Icons">
|
||||
<div v-for="item of elementIcons" :key="item" @click="handleClipboard(generateElementIconCode(item),$event)">
|
||||
<el-tooltip placement="top">
|
||||
<div slot="content">
|
||||
{{ generateElementIconCode(item) }}
|
||||
</div>
|
||||
<div class="icon-item">
|
||||
<i :class="'el-icon-' + item" />
|
||||
<span>{{ item }}</span>
|
||||
</div>
|
||||
</el-tooltip>
|
||||
<div class="grid">
|
||||
<div v-for="item of elementIcons" :key="item" @click="handleClipboard(generateElementIconCode(item),$event)">
|
||||
<el-tooltip placement="top">
|
||||
<div slot="content">
|
||||
{{ generateElementIconCode(item) }}
|
||||
</div>
|
||||
<div class="icon-item">
|
||||
<i :class="'el-icon-' + item" />
|
||||
<span>{{ item }}</span>
|
||||
</div>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
@ -67,6 +71,12 @@ export default {
|
||||
margin: 10px 20px 0;
|
||||
overflow: hidden;
|
||||
|
||||
.grid {
|
||||
position: relative;
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
|
||||
}
|
||||
|
||||
.icon-item {
|
||||
margin: 20px;
|
||||
height: 85px;
|
||||
|
@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div class="login-container">
|
||||
<el-form ref="loginForm" :model="loginForm" :rules="loginRules" class="login-form" auto-complete="on" label-position="left">
|
||||
<el-form ref="loginForm" :model="loginForm" :rules="loginRules" class="login-form" autocomplete="on" label-position="left">
|
||||
<el-row>
|
||||
<el-col :span="3">
|
||||
<img src="https://avatars1.githubusercontent.com/u/1263359?s=200&v=4" class="image">
|
||||
@ -26,7 +26,7 @@
|
||||
name="userName"
|
||||
type="text"
|
||||
tabindex="1"
|
||||
auto-complete="on"
|
||||
autocomplete="on"
|
||||
/>
|
||||
</el-form-item>
|
||||
|
||||
@ -43,7 +43,7 @@
|
||||
:placeholder="$t('login.password')"
|
||||
name="password"
|
||||
tabindex="2"
|
||||
auto-complete="on"
|
||||
autocomplete="on"
|
||||
@keyup.native="checkCapslock"
|
||||
@blur="capsTooltip = false"
|
||||
@keyup.enter.native="handleLogin"
|
||||
@ -129,13 +129,18 @@ export default {
|
||||
capsTooltip: false,
|
||||
loading: false,
|
||||
showDialog: false,
|
||||
redirect: undefined
|
||||
redirect: undefined,
|
||||
otherQuery: {}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
$route: {
|
||||
handler: function(route) {
|
||||
this.redirect = route.query.redirect
|
||||
const query = route.query
|
||||
if (query) {
|
||||
this.redirect = query.redirect
|
||||
this.otherQuery = this.getOtherQuery(query)
|
||||
}
|
||||
},
|
||||
immediate: true
|
||||
}
|
||||
@ -154,17 +159,9 @@ export default {
|
||||
// window.removeEventListener('storage', this.afterQRScan)
|
||||
},
|
||||
methods: {
|
||||
checkCapslock({ shiftKey, key } = {}) {
|
||||
if (key && key.length === 1) {
|
||||
if (shiftKey && (key >= 'a' && key <= 'z') || !shiftKey && (key >= 'A' && key <= 'Z')) {
|
||||
this.capsTooltip = true
|
||||
} else {
|
||||
this.capsTooltip = false
|
||||
}
|
||||
}
|
||||
if (key === 'CapsLock' && this.capsTooltip === true) {
|
||||
this.capsTooltip = false
|
||||
}
|
||||
checkCapslock(e) {
|
||||
const { key } = e
|
||||
this.capsTooltip = key && key.length === 1 && (key >= 'A' && key <= 'Z')
|
||||
},
|
||||
handleLogin() {
|
||||
this.$refs.loginForm.validate(valid => {
|
||||
@ -172,9 +169,7 @@ export default {
|
||||
this.loading = true
|
||||
this.$store.dispatch('user/login', this.loginForm)
|
||||
.then(() => {
|
||||
this.$router.push({
|
||||
path: this.redirect || '/'
|
||||
})
|
||||
this.$router.push({ path: this.redirect || '/', query: this.otherQuery })
|
||||
})
|
||||
.catch(error => {
|
||||
let message = this.$t('login.unexpectedError')
|
||||
@ -192,6 +187,14 @@ export default {
|
||||
return false
|
||||
}
|
||||
})
|
||||
},
|
||||
getOtherQuery(query) {
|
||||
return Object.keys(query).reduce((acc, cur) => {
|
||||
if (cur !== 'redirect') {
|
||||
acc[cur] = query[cur]
|
||||
}
|
||||
return acc
|
||||
}, {})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -241,7 +241,7 @@ export default {
|
||||
dangerouslyUseHTMLString: true,
|
||||
message: `
|
||||
<div>Role Key: ${key}</div>
|
||||
<div>Role Nmae: ${name}</div>
|
||||
<div>Role Name: ${name}</div>
|
||||
<div>Description: ${description}</div>
|
||||
`,
|
||||
type: 'success'
|
||||
|
@ -70,7 +70,7 @@ export default {
|
||||
name: '',
|
||||
email: '',
|
||||
avatar: '',
|
||||
roles: ''
|
||||
role: ''
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -87,61 +87,61 @@ export default {
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.box-center {
|
||||
margin: 0 auto;
|
||||
display: table;
|
||||
}
|
||||
.box-center {
|
||||
margin: 0 auto;
|
||||
display: table;
|
||||
}
|
||||
|
||||
.text-muted {
|
||||
color: #777;
|
||||
}
|
||||
.text-muted {
|
||||
color: #777;
|
||||
}
|
||||
|
||||
.user-profile {
|
||||
.user-name {
|
||||
font-weight: bold;
|
||||
}
|
||||
.user-profile {
|
||||
.user-name {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.box-center {
|
||||
padding-top: 10px;
|
||||
}
|
||||
.box-center {
|
||||
padding-top: 10px;
|
||||
}
|
||||
|
||||
.user-role {
|
||||
padding-top: 10px;
|
||||
font-weight: 400;
|
||||
font-size: 14px;
|
||||
}
|
||||
.user-role {
|
||||
padding-top: 10px;
|
||||
font-weight: 400;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.box-social {
|
||||
padding-top: 30px;
|
||||
.box-social {
|
||||
padding-top: 30px;
|
||||
|
||||
.el-table {
|
||||
border-top: 1px solid #dfe6ec;
|
||||
}
|
||||
}
|
||||
.el-table {
|
||||
border-top: 1px solid #dfe6ec;
|
||||
}
|
||||
}
|
||||
|
||||
.user-follow {
|
||||
padding-top: 20px;
|
||||
}
|
||||
}
|
||||
.user-follow {
|
||||
padding-top: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
.user-bio {
|
||||
margin-top: 20px;
|
||||
color: #606266;
|
||||
.user-bio {
|
||||
margin-top: 20px;
|
||||
color: #606266;
|
||||
|
||||
span {
|
||||
padding-left: 4px;
|
||||
}
|
||||
span {
|
||||
padding-left: 4px;
|
||||
}
|
||||
|
||||
.user-bio-section {
|
||||
font-size: 14px;
|
||||
padding: 15px 0;
|
||||
.user-bio-section {
|
||||
font-size: 14px;
|
||||
padding: 15px 0;
|
||||
|
||||
.user-bio-section-header {
|
||||
border-bottom: 1px solid #dfe6ec;
|
||||
padding-bottom: 10px;
|
||||
margin-bottom: 10px;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
}
|
||||
.user-bio-section-header {
|
||||
border-bottom: 1px solid #dfe6ec;
|
||||
padding-bottom: 10px;
|
||||
margin-bottom: 10px;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
@ -13,11 +13,11 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import tabPane from './components/TabPane'
|
||||
import TabPane from './components/TabPane'
|
||||
|
||||
export default {
|
||||
name: 'Tab',
|
||||
components: { tabPane },
|
||||
components: { TabPane },
|
||||
data() {
|
||||
return {
|
||||
tabMapOptions: [
|
||||
@ -30,6 +30,18 @@ export default {
|
||||
createdTimes: 0
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
activeName(val) {
|
||||
this.$router.push(`${this.$route.path}?tab=${val}`)
|
||||
}
|
||||
},
|
||||
created() {
|
||||
// init the default selected tab
|
||||
const tab = this.$route.query.tab
|
||||
if (tab) {
|
||||
this.activeName = tab
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
showCreatedTimes() {
|
||||
this.createdTimes = this.createdTimes + 1
|
||||
|
@ -35,14 +35,14 @@
|
||||
style="width: 100%;"
|
||||
@sort-change="sortChange"
|
||||
>
|
||||
<el-table-column :label="$t('table.id')" prop="id" sortable="custom" align="center" width="80">
|
||||
<template slot-scope="scope">
|
||||
<span>{{ scope.row.id }}</span>
|
||||
<el-table-column :label="$t('table.id')" prop="id" sortable="custom" align="center" width="80" :class-name="getSortClass('id')">
|
||||
<template slot-scope="{row}">
|
||||
<span>{{ row.id }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column :label="$t('table.date')" width="150px" align="center">
|
||||
<template slot-scope="scope">
|
||||
<span>{{ scope.row.timestamp | parseTime('{y}-{m}-{d} {h}:{i}') }}</span>
|
||||
<template slot-scope="{row}">
|
||||
<span>{{ row.timestamp | parseTime('{y}-{m}-{d} {h}:{i}') }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column :label="$t('table.title')" min-width="150px">
|
||||
@ -52,18 +52,18 @@
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column :label="$t('table.author')" width="110px" align="center">
|
||||
<template slot-scope="scope">
|
||||
<span>{{ scope.row.author }}</span>
|
||||
<template slot-scope="{row}">
|
||||
<span>{{ row.author }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column v-if="showReviewer" :label="$t('table.reviewer')" width="110px" align="center">
|
||||
<template slot-scope="scope">
|
||||
<span style="color:red;">{{ scope.row.reviewer }}</span>
|
||||
<template slot-scope="{row}">
|
||||
<span style="color:red;">{{ row.reviewer }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column :label="$t('table.importance')" width="80px">
|
||||
<template slot-scope="scope">
|
||||
<svg-icon v-for="n in +scope.row.importance" :key="n" icon-class="star" class="meta-item__icon" />
|
||||
<template slot-scope="{row}">
|
||||
<svg-icon v-for="n in +row.importance" :key="n" icon-class="star" class="meta-item__icon" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column :label="$t('table.readings')" align="center" width="95">
|
||||
@ -80,7 +80,7 @@
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column :label="$t('table.actions')" align="center" width="230" class-name="small-padding fixed-width">
|
||||
<template slot-scope="{row}">
|
||||
<template slot-scope="{row,$index}">
|
||||
<el-button type="primary" size="mini" @click="handleUpdate(row)">
|
||||
{{ $t('table.edit') }}
|
||||
</el-button>
|
||||
@ -90,7 +90,7 @@
|
||||
<el-button v-if="row.status!='draft'" size="mini" @click="handleModifyStatus(row,'draft')">
|
||||
{{ $t('table.draft') }}
|
||||
</el-button>
|
||||
<el-button v-if="row.status!='deleted'" size="mini" type="danger" @click="handleModifyStatus(row,'deleted')">
|
||||
<el-button v-if="row.status!='deleted'" size="mini" type="danger" @click="handleDelete(row,$index)">
|
||||
{{ $t('table.delete') }}
|
||||
</el-button>
|
||||
</template>
|
||||
@ -319,13 +319,8 @@ export default {
|
||||
const tempData = Object.assign({}, this.temp)
|
||||
tempData.timestamp = +new Date(tempData.timestamp) // change Thu Nov 30 2017 16:41:05 GMT+0800 (CST) to 1512031311464
|
||||
updateArticle(tempData).then(() => {
|
||||
for (const v of this.list) {
|
||||
if (v.id === this.temp.id) {
|
||||
const index = this.list.indexOf(v)
|
||||
this.list.splice(index, 1, this.temp)
|
||||
break
|
||||
}
|
||||
}
|
||||
const index = this.list.findIndex(v => v.id === this.temp.id)
|
||||
this.list.splice(index, 1, this.temp)
|
||||
this.dialogFormVisible = false
|
||||
this.$notify({
|
||||
title: '成功',
|
||||
@ -337,14 +332,13 @@ export default {
|
||||
}
|
||||
})
|
||||
},
|
||||
handleDelete(row) {
|
||||
handleDelete(row, index) {
|
||||
this.$notify({
|
||||
title: '成功',
|
||||
message: '删除成功',
|
||||
type: 'success',
|
||||
duration: 2000
|
||||
})
|
||||
const index = this.list.indexOf(row)
|
||||
this.list.splice(index, 1)
|
||||
},
|
||||
handleFetchPv(pv) {
|
||||
@ -358,7 +352,7 @@ export default {
|
||||
import('@/vendor/Export2Excel').then(excel => {
|
||||
const tHeader = ['timestamp', 'title', 'type', 'importance', 'status']
|
||||
const filterVal = ['timestamp', 'title', 'type', 'importance', 'status']
|
||||
const data = this.formatJson(filterVal, this.list)
|
||||
const data = this.formatJson(filterVal)
|
||||
excel.export_json_to_excel({
|
||||
header: tHeader,
|
||||
data,
|
||||
@ -367,14 +361,18 @@ export default {
|
||||
this.downloadLoading = false
|
||||
})
|
||||
},
|
||||
formatJson(filterVal, jsonData) {
|
||||
return jsonData.map(v => filterVal.map(j => {
|
||||
formatJson(filterVal) {
|
||||
return this.list.map(v => filterVal.map(j => {
|
||||
if (j === 'timestamp') {
|
||||
return parseTime(v[j])
|
||||
} else {
|
||||
return v[j]
|
||||
}
|
||||
}))
|
||||
},
|
||||
getSortClass: function(key) {
|
||||
const sort = this.listQuery.sort
|
||||
return sort === `+${key}` ? 'ascending' : 'descending'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3,38 +3,38 @@
|
||||
<!-- Note that row-key is necessary to get a correct row order. -->
|
||||
<el-table ref="dragTable" v-loading="listLoading" :data="list" row-key="id" border fit highlight-current-row style="width: 100%">
|
||||
<el-table-column align="center" label="ID" width="65">
|
||||
<template slot-scope="scope">
|
||||
<span>{{ scope.row.id }}</span>
|
||||
<template slot-scope="{row}">
|
||||
<span>{{ row.id }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column width="180px" align="center" label="Date">
|
||||
<template slot-scope="scope">
|
||||
<span>{{ scope.row.timestamp | parseTime('{y}-{m}-{d} {h}:{i}') }}</span>
|
||||
<template slot-scope="{row}">
|
||||
<span>{{ row.timestamp | parseTime('{y}-{m}-{d} {h}:{i}') }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column min-width="300px" label="Title">
|
||||
<template slot-scope="scope">
|
||||
<span>{{ scope.row.title }}</span>
|
||||
<template slot-scope="{row}">
|
||||
<span>{{ row.title }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column width="110px" align="center" label="Author">
|
||||
<template slot-scope="scope">
|
||||
<span>{{ scope.row.author }}</span>
|
||||
<template slot-scope="{row}">
|
||||
<span>{{ row.author }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column width="100px" label="Importance">
|
||||
<template slot-scope="scope">
|
||||
<svg-icon v-for="n in +scope.row.importance" :key="n" icon-class="star" class="icon-star" />
|
||||
<template slot-scope="{row}">
|
||||
<svg-icon v-for="n in + row.importance" :key="n" icon-class="star" class="icon-star" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column align="center" label="Readings" width="95">
|
||||
<template slot-scope="scope">
|
||||
<span>{{ scope.row.pageviews }}</span>
|
||||
<template slot-scope="{row}">
|
||||
<span>{{ row.pageviews }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
|
@ -2,26 +2,26 @@
|
||||
<div class="app-container">
|
||||
<el-table v-loading="listLoading" :data="list" border fit highlight-current-row style="width: 100%">
|
||||
<el-table-column align="center" label="ID" width="80">
|
||||
<template slot-scope="scope">
|
||||
<span>{{ scope.row.id }}</span>
|
||||
<template slot-scope="{row}">
|
||||
<span>{{ row.id }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column width="180px" align="center" label="Date">
|
||||
<template slot-scope="scope">
|
||||
<span>{{ scope.row.timestamp | parseTime('{y}-{m}-{d} {h}:{i}') }}</span>
|
||||
<template slot-scope="{row}">
|
||||
<span>{{ row.timestamp | parseTime('{y}-{m}-{d} {h}:{i}') }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column width="120px" align="center" label="Author">
|
||||
<template slot-scope="scope">
|
||||
<span>{{ scope.row.author }}</span>
|
||||
<template slot-scope="{row}">
|
||||
<span>{{ row.author }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column width="100px" label="Importance">
|
||||
<template slot-scope="scope">
|
||||
<svg-icon v-for="n in +scope.row.importance" :key="n" icon-class="star" class="meta-item__icon" />
|
||||
<template slot-scope="{row}">
|
||||
<svg-icon v-for="n in + row.importance" :key="n" icon-class="star" class="meta-item__icon" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
<div class="app-container">
|
||||
<!-- $t is vue-i18n global function to translate lang -->
|
||||
<el-input v-model="filename" :placeholder="$t('zip.placeholder')" style="width:300px;" prefix-icon="el-icon-document" />
|
||||
<el-button :loading="downloadLoading" style="margin-bottom:20px;" type="primary" icon="document" @click="handleDownload">
|
||||
<el-button :loading="downloadLoading" style="margin-bottom:20px;" type="primary" icon="el-icon-document" @click="handleDownload">
|
||||
{{ $t('zip.export') }} Zip
|
||||
</el-button>
|
||||
<el-table v-loading="listLoading" :data="list" element-loading-text="拼命加载中" border fit highlight-current-row>
|
||||
|
@ -1,9 +1,15 @@
|
||||
import { parseTime } from '@/utils/index.js'
|
||||
|
||||
describe('Utils:parseTime', () => {
|
||||
const d = new Date('2018-07-13 17:54:01') // "2018-07-13 17:54:01"
|
||||
it('timestamp', () => {
|
||||
expect(parseTime(d)).toBe('2018-07-13 17:54:01')
|
||||
})
|
||||
|
||||
it('timestamp string', () => {
|
||||
expect(parseTime((d + ''))).toBe('2018-07-13 17:54:01')
|
||||
})
|
||||
|
||||
it('ten digits timestamp', () => {
|
||||
expect(parseTime((d / 1000).toFixed(0))).toBe('2018-07-13 17:54:01')
|
||||
})
|
||||
@ -24,4 +30,8 @@ describe('Utils:parseTime', () => {
|
||||
it('empty argument', () => {
|
||||
expect(parseTime()).toBeNull()
|
||||
})
|
||||
|
||||
it('null', () => {
|
||||
expect(parseTime(null)).toBeNull()
|
||||
})
|
||||
})
|
||||
|
@ -7,10 +7,13 @@ function resolve(dir) {
|
||||
}
|
||||
|
||||
const name = defaultSettings.title || 'Adempiere Vue' // page title
|
||||
|
||||
// If your port is set to 80,
|
||||
// use administrator privileges to execute the command line.
|
||||
// For example, Mac: sudo npm run
|
||||
const port = 9527 // dev port
|
||||
// You can change the port by the following method:
|
||||
// port = 9527 npm run dev OR npm run dev --port = 9527
|
||||
const port = process.env.port || process.env.npm_config_port || 9527 // dev port
|
||||
|
||||
// All configuration item explanations can be find in https://cli.vuejs.org/config/
|
||||
module.exports = {
|
||||
@ -33,18 +36,7 @@ module.exports = {
|
||||
warnings: false,
|
||||
errors: true
|
||||
},
|
||||
proxy: {
|
||||
// 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: {
|
||||
['^' + process.env.VUE_APP_BASE_API]: ''
|
||||
}
|
||||
}
|
||||
},
|
||||
after: require('./mock/mock-server.js')
|
||||
before: require('./mock/mock-server.js')
|
||||
},
|
||||
configureWebpack: {
|
||||
// provide the app's title in webpack's name field, so that
|
||||
@ -57,16 +49,6 @@ module.exports = {
|
||||
}
|
||||
},
|
||||
chainWebpack(config) {
|
||||
const cdn = {
|
||||
// inject tinymce into index.html
|
||||
// why use this cdn, detail see https://github.com/PanJiaChen/tinymce-all-in-one
|
||||
js: ['https://cdn.jsdelivr.net/npm/tinymce-all-in-one@4.9.3/tinymce.min.js']
|
||||
}
|
||||
config.plugin('html')
|
||||
.tap(args => {
|
||||
args[0].cdn = cdn
|
||||
return args
|
||||
})
|
||||
config.plugins.delete('preload') // TODO: need test
|
||||
config.plugins.delete('prefetch') // TODO: need test
|
||||
|
||||
@ -98,12 +80,6 @@ module.exports = {
|
||||
})
|
||||
.end()
|
||||
|
||||
config
|
||||
// https://webpack.js.org/configuration/devtool/#development
|
||||
.when(process.env.NODE_ENV === 'development',
|
||||
config => config.devtool('cheap-source-map')
|
||||
)
|
||||
|
||||
config
|
||||
.when(process.env.NODE_ENV !== 'development',
|
||||
config => {
|
||||
|
Loading…
x
Reference in New Issue
Block a user