1
0
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:
Edwin Betancourt 2020-06-19 10:12:27 -04:00 committed by GitHub
parent 6dd649e020
commit cc35fd7a1d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
85 changed files with 2022 additions and 1334 deletions

4
.github/FUNDING.yml vendored Normal file
View File

@ -0,0 +1,4 @@
# These are supported funding model platforms
patreon: panjiachen
custom: https://panjiachen.github.io/vue-element-admin-site/donate

View File

@ -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": {}
}
}

View File

@ -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.
[![Edit on CodeSandbox](https://codesandbox.io/static/img/play-codesandbox.svg)](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

View File

@ -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">
[![Edit on CodeSandbox](https://codesandbox.io/static/img/play-codesandbox.svg)](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
View File

@ -0,0 +1,9 @@
{
"compilerOptions": {
"baseUrl": "./",
"paths": {
"@/*": ["src/*"]
}
},
"exclude": ["node_modules", "dist"]
}

View File

@ -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 {

View File

@ -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

View File

@ -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')

View File

@ -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 {

View File

@ -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,

View File

@ -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 {

View File

@ -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"
]
}

View 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}}
}

View 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
}
}

View File

@ -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
View File

@ -0,0 +1,5 @@
module.exports = {
plugins: {
autoprefixer: {}
}
}

View File

@ -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>

View File

@ -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
})

View File

@ -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
})

View File

@ -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'
})
}

View File

@ -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()
}
},

View File

@ -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()
}
}
}

View File

@ -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>

View File

@ -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

View File

@ -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"

View File

@ -12,7 +12,7 @@ import Editor from 'tui-editor'
import defaultOptions from './default-options'
export default {
name: 'MarddownEditor',
name: 'MarkdownEditor',
props: {
value: {
type: String,

View File

@ -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;

View File

@ -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;

View File

@ -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);
}
}

View File

@ -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>

View 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

View File

@ -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(() => {

View File

@ -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()

View File

@ -58,8 +58,6 @@ export default {
.fixed-header+.app-main {
padding-top: 50px;
height: 100vh;
overflow: auto;
}
.hasTagsView {

View File

@ -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> -->

View File

@ -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>

View File

@ -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
}
}
}

View File

@ -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}">

View File

@ -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

View File

@ -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()
}
}
}

View File

@ -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)

View File

@ -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

View File

@ -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 }
]

View File

@ -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.

View File

@ -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')
}
}

View File

@ -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 = {

View File

@ -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 = []
}
},

View File

@ -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)

View File

@ -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;
}

View File

@ -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";

View File

@ -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)

View File

@ -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
}

View File

@ -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
}

View File

@ -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])
}

View File

@ -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) {

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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
},

View File

@ -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)
}
}
}

View File

@ -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>

View File

@ -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',

View File

@ -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 }

View 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)
}
}
}

View File

@ -71,4 +71,10 @@ export default {
margin-bottom: 32px;
}
}
@media (max-width:1024px) {
.chart-wrapper {
padding: 8px;
}
}
</style>

View File

@ -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;

View File

@ -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>

View File

@ -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 => {

View File

@ -6,7 +6,7 @@
import ArticleDetail from './components/ArticleDetail'
export default {
name: 'CreateForm',
name: 'CreateArticle',
components: { ArticleDetail }
}
</script>

View File

@ -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 }}

View File

@ -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"

View File

@ -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;">

View File

@ -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

View File

@ -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;

View File

@ -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
}, {})
}
}
}

View File

@ -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'

View File

@ -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>

View File

@ -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

View File

@ -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'
}
}
}

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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()
})
})

View File

@ -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 => {