@@ -0,0 +1,14 @@ | |||
# https://editorconfig.org | |||
root = true | |||
[*] | |||
charset = utf-8 | |||
indent_style = space | |||
indent_size = 2 | |||
end_of_line = lf | |||
insert_final_newline = true | |||
trim_trailing_whitespace = true | |||
[*.md] | |||
insert_final_newline = false | |||
trim_trailing_whitespace = false |
@@ -0,0 +1,7 @@ | |||
# just a flag | |||
ENV = 'development' | |||
# base api | |||
VUE_APP_BASE_URL = '/api' | |||
VUE_APP_BASE_API = '/api' | |||
IMAGE_BASE_PATH = 'http://192.168.0.116:3200/static' |
@@ -0,0 +1,7 @@ | |||
# just a flag | |||
ENV = 'production' | |||
# base api | |||
BASE_API = '' | |||
VUE_APP_BASE_API = '' | |||
@@ -0,0 +1,9 @@ | |||
NODE_ENV = production | |||
# just a flag | |||
ENV = 'staging' | |||
# base api | |||
BASE_API = '/api' | |||
VUE_APP_BASE_API = '/stage-api' | |||
@@ -0,0 +1,4 @@ | |||
build/*.js | |||
src/assets | |||
public | |||
dist |
@@ -0,0 +1,276 @@ | |||
module.exports = { | |||
root: true, | |||
parserOptions: { | |||
parser: 'babel-eslint', | |||
sourceType: 'module' | |||
}, | |||
env: { | |||
browser: true, | |||
node: true, | |||
es6: true | |||
}, | |||
extends: ['plugin:vue/recommended', 'eslint:recommended'], | |||
// add your custom rules here | |||
//it is base on https://github.com/vuejs/eslint-config-vue | |||
rules: { | |||
'vue/max-attributes-per-line': 'off', | |||
'vue/html-closing-bracket-newline': [ | |||
0, | |||
{ | |||
singleline: 'never', | |||
multiline: 'always' | |||
} | |||
], | |||
'vue/html-indent': 'off', | |||
indent: [2, 4], | |||
'vue/html-self-closing': 'off', | |||
'vue/singleline-html-element-content-newline': 'off', | |||
'vue/multiline-html-element-content-newline': 'off', | |||
'vue/name-property-casing': ['error', 'PascalCase'], | |||
'vue/no-v-html': 'off', | |||
'accessor-pairs': 2, | |||
'arrow-spacing': [ | |||
2, | |||
{ | |||
before: true, | |||
after: true | |||
} | |||
], | |||
'block-spacing': [2, 'always'], | |||
'brace-style': [ | |||
2, | |||
'1tbs', | |||
{ | |||
allowSingleLine: true | |||
} | |||
], | |||
camelcase: [ | |||
0, | |||
{ | |||
properties: 'always' | |||
} | |||
], | |||
'comma-dangle': [2, 'never'], | |||
'comma-spacing': [ | |||
2, | |||
{ | |||
before: false, | |||
after: true | |||
} | |||
], | |||
'comma-style': [2, 'last'], | |||
'constructor-super': 2, | |||
curly: [2, 'multi-line'], | |||
'dot-location': [2, 'property'], | |||
'eol-last': 2, | |||
eqeqeq: ['error', 'always', { null: 'ignore' }], | |||
'generator-star-spacing': [ | |||
2, | |||
{ | |||
before: true, | |||
after: true | |||
} | |||
], | |||
'handle-callback-err': [2, '^(err|error)$'], | |||
indent: [ | |||
2, | |||
2, | |||
{ | |||
SwitchCase: 1 | |||
} | |||
], | |||
'jsx-quotes': [2, 'prefer-single'], | |||
'key-spacing': [ | |||
2, | |||
{ | |||
beforeColon: false, | |||
afterColon: true | |||
} | |||
], | |||
'keyword-spacing': [ | |||
2, | |||
{ | |||
before: true, | |||
after: true | |||
} | |||
], | |||
'new-cap': [ | |||
2, | |||
{ | |||
newIsCap: true, | |||
capIsNew: false | |||
} | |||
], | |||
'new-parens': 2, | |||
'no-array-constructor': 2, | |||
'no-caller': 2, | |||
'no-console': 'off', | |||
'no-class-assign': 2, | |||
'no-cond-assign': 2, | |||
'no-const-assign': 2, | |||
'no-control-regex': 0, | |||
'no-delete-var': 2, | |||
'no-dupe-args': 2, | |||
'no-dupe-class-members': 2, | |||
'no-dupe-keys': 2, | |||
'no-duplicate-case': 2, | |||
'no-empty-character-class': 2, | |||
'no-empty-pattern': 2, | |||
'no-eval': 2, | |||
'no-ex-assign': 2, | |||
'no-extend-native': 2, | |||
'no-extra-bind': 2, | |||
'no-extra-boolean-cast': 2, | |||
'no-extra-parens': [2, 'functions'], | |||
'no-fallthrough': 2, | |||
'no-floating-decimal': 2, | |||
'no-func-assign': 2, | |||
'no-implied-eval': 2, | |||
'no-inner-declarations': [2, 'functions'], | |||
'no-invalid-regexp': 2, | |||
'no-irregular-whitespace': 2, | |||
'no-iterator': 2, | |||
'no-label-var': 2, | |||
'no-labels': [ | |||
2, | |||
{ | |||
allowLoop: false, | |||
allowSwitch: false | |||
} | |||
], | |||
'no-lone-blocks': 2, | |||
'no-mixed-spaces-and-tabs': 2, | |||
'no-multi-spaces': 2, | |||
'no-multi-str': 2, | |||
'no-multiple-empty-lines': [ | |||
2, | |||
{ | |||
max: 1 | |||
} | |||
], | |||
'no-native-reassign': 2, | |||
'no-negated-in-lhs': 2, | |||
'no-new-object': 2, | |||
'no-new-require': 2, | |||
'no-new-symbol': 2, | |||
'no-new-wrappers': 2, | |||
'no-obj-calls': 2, | |||
'no-octal': 2, | |||
'no-octal-escape': 2, | |||
'no-path-concat': 2, | |||
'no-proto': 2, | |||
'no-redeclare': 2, | |||
'no-regex-spaces': 2, | |||
'no-return-assign': [2, 'except-parens'], | |||
'no-self-assign': 2, | |||
'no-self-compare': 2, | |||
'no-sequences': 2, | |||
'no-shadow-restricted-names': 2, | |||
'no-spaced-func': 2, | |||
'no-sparse-arrays': 2, | |||
'no-this-before-super': 2, | |||
'no-throw-literal': 2, | |||
'no-trailing-spaces': 2, | |||
'no-undef': 2, | |||
'no-undef-init': 2, | |||
'no-unexpected-multiline': 2, | |||
'no-unmodified-loop-condition': 2, | |||
'no-unneeded-ternary': [ | |||
2, | |||
{ | |||
defaultAssignment: false | |||
} | |||
], | |||
'no-unreachable': 2, | |||
'no-unsafe-finally': 2, | |||
'no-unused-vars': [ | |||
2, | |||
{ | |||
vars: 'all', | |||
args: 'none' | |||
} | |||
], | |||
'no-useless-call': 2, | |||
'no-useless-computed-key': 2, | |||
'no-useless-constructor': 2, | |||
'no-useless-escape': 0, | |||
'no-whitespace-before-property': 2, | |||
'no-with': 2, | |||
'one-var': [ | |||
2, | |||
{ | |||
initialized: 'never' | |||
} | |||
], | |||
'operator-linebreak': [ | |||
2, | |||
'after', | |||
{ | |||
overrides: { | |||
'?': 'before', | |||
':': 'before' | |||
} | |||
} | |||
], | |||
'padded-blocks': [2, 'never'], | |||
quotes: [ | |||
2, | |||
'single', | |||
{ | |||
avoidEscape: true, | |||
allowTemplateLiterals: true | |||
} | |||
], | |||
semi: [2, 'never'], | |||
'semi-spacing': [ | |||
2, | |||
{ | |||
before: false, | |||
after: true | |||
} | |||
], | |||
'space-before-blocks': [2, 'always'], | |||
'space-before-function-paren': 'off', | |||
'space-in-parens': [2, 'never'], | |||
'space-infix-ops': 2, | |||
'space-unary-ops': [ | |||
2, | |||
{ | |||
words: true, | |||
nonwords: false | |||
} | |||
], | |||
'spaced-comment': [ | |||
2, | |||
'always', | |||
{ | |||
markers: [ | |||
'global', | |||
'globals', | |||
'eslint', | |||
'eslint-disable', | |||
'*package', | |||
'!', | |||
',' | |||
] | |||
} | |||
], | |||
'template-curly-spacing': [2, 'never'], | |||
'use-isnan': 2, | |||
'valid-typeof': 2, | |||
'wrap-iife': [2, 'any'], | |||
'yield-star-spacing': [2, 'both'], | |||
yoda: [2, 'never'], | |||
'prefer-const': 2, | |||
'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0, | |||
'object-curly-spacing': [ | |||
2, | |||
'always', | |||
{ | |||
objectsInObjects: true | |||
} | |||
], | |||
'array-bracket-spacing': [2, 'never'] | |||
} | |||
} |
@@ -0,0 +1,23 @@ | |||
.DS_Store | |||
node_modules/ | |||
dist/ | |||
npm-debug.log* | |||
yarn-debug.log* | |||
yarn-error.log* | |||
**/*.log | |||
tests/**/coverage/ | |||
tests/e2e/reports | |||
selenium-debug.log | |||
# Editor directories and files | |||
.idea | |||
*.suo | |||
*.ntvs* | |||
*.njsproj | |||
*.sln | |||
*.local | |||
package-lock.json | |||
vue.config.js | |||
.devcontainer |
@@ -0,0 +1,5 @@ | |||
{ | |||
"singleQuote": true, | |||
"semi": false, | |||
"space-before-function-paren": 0 | |||
} |
@@ -0,0 +1,5 @@ | |||
language: node_js | |||
node_js: 10 | |||
script: npm run test | |||
notifications: | |||
email: false |
@@ -0,0 +1,21 @@ | |||
MIT License | |||
Copyright (c) 2017-present PanJiaChen | |||
Permission is hereby granted, free of charge, to any person obtaining a copy | |||
of this software and associated documentation files (the "Software"), to deal | |||
in the Software without restriction, including without limitation the rights | |||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |||
copies of the Software, and to permit persons to whom the Software is | |||
furnished to do so, subject to the following conditions: | |||
The above copyright notice and this permission notice shall be included in all | |||
copies or substantial portions of the Software. | |||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |||
SOFTWARE. |
@@ -0,0 +1,222 @@ | |||
<p align="center"> | |||
<img width="320" src="https://wpimg.wallstcn.com/ecc53a42-d79b-42e2-8852-5126b810a4c8.svg"> | |||
</p> | |||
<p align="center"> | |||
<a href="https://github.com/vuejs/vue"> | |||
<img src="https://img.shields.io/badge/vue-2.6.10-brightgreen.svg" alt="vue"> | |||
</a> | |||
<a href="https://github.com/ElemeFE/element"> | |||
<img src="https://img.shields.io/badge/element--ui-2.7.0-brightgreen.svg" alt="element-ui"> | |||
</a> | |||
<a href="https://travis-ci.org/PanJiaChen/vue-element-admin" rel="nofollow"> | |||
<img src="https://travis-ci.org/PanJiaChen/vue-element-admin.svg?branch=master" alt="Estado de Construcción"> | |||
</a> | |||
<a href="https://github.com/PanJiaChen/vue-element-admin/blob/master/LICENSE"> | |||
<img src="https://img.shields.io/github/license/mashape/apistatus.svg" alt="Licencia"> | |||
</a> | |||
<a href="https://github.com/PanJiaChen/vue-element-admin/releases"> | |||
<img src="https://img.shields.io/github/release/PanJiaChen/vue-element-admin.svg" alt="Liberación Github"> | |||
</a> | |||
<a href="https://gitter.im/vue-element-admin/discuss"> | |||
<img src="https://badges.gitter.im/Join%20Chat.svg" alt="Gitter"> | |||
</a> | |||
<a href="https://panjiachen.github.io/vue-element-admin-site/donate"> | |||
<img src="https://img.shields.io/badge/%24-donate-ff69b4.svg" alt="Donación"> | |||
</a> | |||
</p> | |||
Español | [English](./README.md) | [简体中文](./README.zh-CN.md) | [日本語](./README.ja.md) | |||
## Introducción | |||
[vue-element-admin](https://panjiachen.github.io/vue-element-admin) es una interfáz de administración preparada para producción. 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. | |||
Vue Element Admin es una solución práctica basada en la nueva plataforma de desarrollo de vue, construida con soporte a i18 para el manejo de múltiples lenguajes, plantillas estándares para aplicaciones de negocio y un conjunto de asombrosas características. Esta herramienta ayuda a construir largas y complejas Aplicacones de una sola página (SPA). Creo que lo que necesites hacer, este proyecto te ayudará. | |||
- [Vista Prévia de la Aplicación](https://panjiachen.github.io/vue-element-admin) | |||
- [Documentación](https://panjiachen.github.io/vue-element-admin-site/) | |||
- [Canal de Gitter](https://gitter.im/vue-element-admin/discuss) | |||
- [Para Donaciones](https://panjiachen.github.io/vue-element-admin-site/donate/) | |||
- [Enlace de Wiki](https://github.com/PanJiaChen/vue-element-admin/wiki) | |||
- [Canal de Gitee](https://panjiachen.gitee.io/vue-element-admin/) | |||
- Plantilla base recomendada para usar: [vue-admin-template](https://github.com/PanJiaChen/vue-admin-template) | |||
- Aplicación de Escritorio: [electron-vue-admin](https://github.com/PanJiaChen/electron-vue-admin) | |||
- Plantilla de Typescript: [vue-typescript-admin-template](https://github.com/Armour/vue-typescript-admin-template) (Créditos: [@Armour](https://github.com/Armour)) | |||
- [awesome-project](https://github.com/PanJiaChen/vue-element-admin/issues/2312) | |||
**Después de la versión `v4.1.0+`, la rama por defecto master no tendrá soporte para i18n. Por favor utilice la rama [i18n](https://github.com/PanJiaChen/vue-element-admin/tree/i18n), los cambios serán incluidos en la rama master** | |||
**la versión actual es `v4.0+` construida con `vue-cli`. Si encuentra algún problema, por favor coloque un [issue](https://github.com/PanJiaChen/vue-element-admin/issues/new). Si desea usar la versión anterior, puede cambiar de rama a [tag/3.11.0](https://github.com/PanJiaChen/vue-element-admin/tree/tag/3.11.0), no relacionado con `vue-cli`** | |||
**Este proyecto no está soportado para versiones antigüas de navegadores (ej. IE).** | |||
## Preparación | |||
Necesita instalar [node](https://nodejs.org/) y [git](https://git-scm.com/) localmente. El proyecto es 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) , [axios](https://github.com/axios/axios) and [element-ui](https://github.com/ElemeFE/element), toda la solicitud de datos simulada se realiza a través de [Mock.js](https://github.com/nuysoft/Mock). | |||
Entendiendo y aprendiendo esto pudiera ayudarle con su 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> | |||
## Patrocinantes | |||
Sea un patrocinante y coloque su logo en nuestro LEEME en GitHub con un enlace directo a su sitio web. [[Se un Patrocinante]](https://www.patreon.com/panjiachen) | |||
<a href="https://flatlogic.com/admin-dashboards?from=vue-element-admin"><img width="150px" src="https://wpimg.wallstcn.com/9c0b719b-5551-4c1e-b776-63994632d94a.png" /></a><p>Plantilla de Dashboard de administración hecha con Vue, React y Angular.</p> | |||
## Características | |||
``` | |||
- Iniciar / Cerrar Sesión | |||
- Permisos de Autenticación | |||
- Página de Permisos | |||
- Directivas de permisos | |||
- Página de configuración de permisos | |||
- Autenticación por dos pasos | |||
- Construcción Multi-entorno | |||
- Desarrollo (dev) | |||
- sit | |||
- Escenario de pruebas (stage), | |||
- Producción (prod) | |||
- Características Globales | |||
- I18n | |||
- Temas dinámicos | |||
- Menu lateral dinámico (soporte a rutas multi-nivel) | |||
- Barra de rutas dinámica | |||
- Tags-view (Pestañas de página, Soporta operación de clic derecho) | |||
- Svg Sprite | |||
- Datos de simulación con Mock | |||
- Pantalla completa | |||
- Menu lateral responsivo | |||
- Editor | |||
- Editor de Texto Enriquecido | |||
- Editor Markdown | |||
- Editor JSON | |||
- Excel | |||
- Exportación a Excel | |||
- Carga de Excel | |||
- Visualización de Excel | |||
- Exportación como ZIP | |||
- Tabla | |||
- Tabla Dinámica | |||
- Tabla con Arrastrar y Soltar | |||
- Tabla de edición en línea | |||
- Páginas de Error | |||
- 401 | |||
- 404 | |||
- Componentes | |||
- Carga de Avatar | |||
- Botón para subir al inicio | |||
- Arrastrar y Soltar (Diaglogo) | |||
- Arrastrar y Soltar (Seleccionar) | |||
- Arrastrar y Soltar (Kanban) | |||
- Arrastrar y Soltar (Lista) | |||
- Panel de división | |||
- Componente para soltar archivos | |||
- Adhesión de objetos | |||
- Contador hasta | |||
- Ejemplo Avanzado | |||
- Registro de Errores | |||
- Tablero de indicadores | |||
- Página de Guías | |||
- ECharts (Gráficos) | |||
- Portapapeles | |||
- Convertidor de Markdown a HTML | |||
``` | |||
## Iniciando | |||
```bash | |||
# clone el proyecto | |||
git clone https://github.com/PanJiaChen/vue-element-admin.git | |||
# vaya al directorio clonado | |||
cd vue-element-admin | |||
# instale las dependencias | |||
npm install | |||
# corra el proyecto como desarrollador | |||
npm run dev | |||
``` | |||
Automáticamente se abrirá el siguiente enlace en su navegador http://localhost:9527 | |||
## Construcción | |||
```bash | |||
# Construcción para entornos de prueba | |||
npm run build:stage | |||
# Construcción para entornos de producción | |||
npm run build:prod | |||
``` | |||
## Avanzado | |||
```bash | |||
# Vista previa con efectos de entorno | |||
npm run preview | |||
# Vista previa con efectos + análisis de recursos estáticos | |||
npm run preview -- --report | |||
# Chequeo de formato de código | |||
npm run lint | |||
# Chequeo de formato de código y auto-corrección | |||
npm run lint -- --fix | |||
``` | |||
Vaya a [Documentación](https://panjiachen.github.io/vue-element-admin-site/guide/essentials/deploy.html) para mayor información | |||
## Registro de Cambios | |||
Los cambios detallados por cada liberación se encuentran en [notas de liberación](https://github.com/PanJiaChen/vue-element-admin/releases). | |||
## Demostración en línea | |||
[Vista Prévia de la Aplicación](https://panjiachen.github.io/vue-element-admin) | |||
## Donación | |||
Si este proyecto es de mucha ayuda para ti, puedes comprarle al autor un vaso de jugo :tropical_drink: | |||
![Donar](https://wpimg.wallstcn.com/bd273f0d-83a0-4ef2-92e1-9ac8ed3746b9.png) | |||
[dona por Paypal](https://www.paypal.me/panfree23) | |||
[Comprame un Café](https://www.buymeacoffee.com/Pan) | |||
## Navegadores Soportados | |||
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 | últimas 2 versiones | últimas 2 versiones | últimas 2 versiones | | |||
## Licencia | |||
[MIT](https://github.com/PanJiaChen/vue-element-admin/blob/master/LICENSE) | |||
Copyright (c) 2017-presente PanJiaChen |
@@ -0,0 +1,10 @@ | |||
# 开发规范文档 | |||
- 组件命名与配置 | |||
1. 使用大驼峰命名组件 vue 文件,导出组件命名与文件名相同. | |||
2. 组件样式一定是要 scoped 的,以免样式冲突. | |||
3. 前端开发工具统一使用 vscode,统一使用格式化插件配置(前端群文件中). | |||
4. 组件初始模板的生成,使用统一的代码片段进行生成,不要去更改内部属性的排列顺序,删掉属性是可以的. | |||
- 组件编写与引用 | |||
1. 通用组件标签部分,最外层标签为组件盒子,它用于隔离内在样式与外在样式的干扰. | |||
2. |
@@ -0,0 +1,245 @@ | |||
<p align="center"> | |||
<img width="320" src="https://wpimg.wallstcn.com/ecc53a42-d79b-42e2-8852-5126b810a4c8.svg"> | |||
</p> | |||
出现nodejieba安装错误的信息,请执行 npm install --global --production windows-build-tools ,不动的情况下就回车一下试试看. | |||
<p align="center"> | |||
<a href="https://github.com/vuejs/vue"> | |||
<img src="https://img.shields.io/badge/vue-2.6.10-brightgreen.svg" alt="vue"> | |||
</a> | |||
<a href="https://github.com/ElemeFE/element"> | |||
<img src="https://img.shields.io/badge/element--ui-2.7.0-brightgreen.svg" alt="element-ui"> | |||
</a> | |||
<a href="https://travis-ci.org/PanJiaChen/vue-element-admin" rel="nofollow"> | |||
<img src="https://travis-ci.org/PanJiaChen/vue-element-admin.svg?branch=master" alt="Build Status"> | |||
</a> | |||
<a href="https://github.com/PanJiaChen/vue-element-admin/blob/master/LICENSE"> | |||
<img src="https://img.shields.io/github/license/mashape/apistatus.svg" alt="license"> | |||
</a> | |||
<a href="https://github.com/PanJiaChen/vue-element-admin/releases"> | |||
<img src="https://img.shields.io/github/release/PanJiaChen/vue-element-admin.svg" alt="GitHub release"> | |||
</a> | |||
<a href="https://gitter.im/vue-element-admin/discuss"> | |||
<img src="https://badges.gitter.im/Join%20Chat.svg" alt="gitter"> | |||
</a> | |||
<a href="https://panjiachen.gitee.io/vue-element-admin-site/zh/donate"> | |||
<img src="https://img.shields.io/badge/%24-donate-ff69b4.svg" alt="donate"> | |||
</a> | |||
</p> | |||
简体中文 | [English](./README.md) | [日本語](./README.ja.md) | [Spanish](./README.es.md) | |||
## 简介 | |||
[vue-element-admin](https://panjiachen.github.io/vue-element-admin) 是一个后台前端解决方案,它基于 [vue](https://github.com/vuejs/vue) 和 [element-ui](https://github.com/ElemeFE/element)实现。它使用了最新的前端技术栈,内置了 i18n 国际化解决方案,动态路由,权限验证,提炼了典型的业务模型,提供了丰富的功能组件,它可以帮助你快速搭建企业级中后台产品原型。相信不管你的需求是什么,本项目都能帮助到你。 | |||
- [在线预览](https://panjiachen.github.io/vue-element-admin) | |||
- [使用文档](https://panjiachen.github.io/vue-element-admin-site/zh/) | |||
- [Gitter 讨论组](https://gitter.im/vue-element-admin/discuss) | |||
- [Donate](https://panjiachen.gitee.io/vue-element-admin-site/zh/donate) | |||
- [Wiki](https://github.com/PanJiaChen/vue-element-admin/wiki) | |||
- [Gitee](https://panjiachen.gitee.io/vue-element-admin/) 在线预览(国内用户可访问该地址) | |||
- [国内访问文档](https://panjiachen.gitee.io/vue-element-admin-site/zh/) 文档(方便没翻墙的用户查看) | |||
- 基础模板建议使用: [vue-admin-template](https://github.com/PanJiaChen/vue-admin-template) | |||
- 桌面端: [electron-vue-admin](https://github.com/PanJiaChen/electron-vue-admin) | |||
- Typescript 版: [vue-typescript-admin-template](https://github.com/Armour/vue-typescript-admin-template) (鸣谢: [@Armour](https://github.com/Armour)) | |||
- [awesome-project](https://github.com/PanJiaChen/vue-element-admin/issues/2312) | |||
**`v4.1.0+`版本之后默认 master 分支将不支持国际化,有需要的请使用[i18n](https://github.com/PanJiaChen/vue-element-admin/tree/i18n)分支,它会和 master 保持同步更新** | |||
**该项目不支持低版本浏览器(如 ie),有需求请自行添加 polyfill [详情](https://github.com/PanJiaChen/vue-element-admin/wiki#babel-polyfill)** | |||
**目前版本为 `v4.0+` 基于 `vue-cli` 进行构建,若发现问题,欢迎提[issue](https://github.com/PanJiaChen/vue-element-admin/issues/new)。若你想使用旧版本,可以切换分支到[tag/3.11.0](https://github.com/PanJiaChen/vue-element-admin/tree/tag/3.11.0),它不依赖 `vue-cli`** | |||
群主 **[圈子](https://jianshiapp.com/circles/1209)** 群主会经常分享一些技术相关的东西,或者加入 [qq 群](https://github.com/PanJiaChen/vue-element-admin/issues/602) 或者关注 [微博](https://weibo.com/u/3423485724?is_all=1) | |||
## 前序准备 | |||
你需要在本地安装 [node](http://nodejs.org/) 和 [git](https://git-scm.com/)。本项目技术栈基于 [ES2015+](http://es6.ruanyifeng.com/)、[vue](https://cn.vuejs.org/index.html)、[vuex](https://vuex.vuejs.org/zh-cn/)、[vue-router](https://router.vuejs.org/zh-cn/) 、[vue-cli](https://github.com/vuejs/vue-cli) 、[axios](https://github.com/axios/axios) 和 [element-ui](https://github.com/ElemeFE/element),所有的请求数据都使用[Mock.js](https://github.com/nuysoft/Mock)进行模拟,提前了解和学习这些知识会对使用本项目有很大的帮助。 | |||
同时配套了系列教程文章,如何从零构建后一个完整的后台项目,建议大家先看完这些文章再来实践本项目 | |||
- [手摸手,带你用 vue 撸后台 系列一(基础篇)](https://juejin.im/post/59097cd7a22b9d0065fb61d2) | |||
- [手摸手,带你用 vue 撸后台 系列二(登录权限篇)](https://juejin.im/post/591aa14f570c35006961acac) | |||
- [手摸手,带你用 vue 撸后台 系列三 (实战篇)](https://juejin.im/post/593121aa0ce4630057f70d35) | |||
- [手摸手,带你用 vue 撸后台 系列四(vueAdmin 一个极简的后台基础模板)](https://juejin.im/post/595b4d776fb9a06bbe7dba56) | |||
- [手摸手,带你用vue撸后台 系列五(v4.0新版本)](https://juejin.im/post/5c92ff94f265da6128275a85) | |||
- [手摸手,带你封装一个 vue component](https://segmentfault.com/a/1190000009090836) | |||
- [手摸手,带你优雅的使用 icon](https://juejin.im/post/59bb864b5188257e7a427c09) | |||
- [手摸手,带你用合理的姿势使用 webpack4(上)](https://juejin.im/post/5b56909a518825195f499806) | |||
- [手摸手,带你用合理的姿势使用 webpack4(下)](https://juejin.im/post/5b5d6d6f6fb9a04fea58aabc) | |||
**如有问题请先看上述使用文档和文章,若不能满足,欢迎 issue 和 pr** | |||
[![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> | |||
## Sponsors | |||
Become a sponsor and get your logo on our README on GitHub with a link to your site. [[Become a sponsor]](https://www.patreon.com/panjiachen) | |||
<a href="https://flatlogic.com/admin-dashboards?from=vue-element-admin"><img width="150px" src="https://wpimg.wallstcn.com/9c0b719b-5551-4c1e-b776-63994632d94a.png" /></a><p>Admin Dashboard Templates made with Vue, React and Angular.</p> | |||
## 功能 | |||
``` | |||
- 登录 / 注销 | |||
- 权限验证 | |||
- 页面权限 | |||
- 指令权限 | |||
- 权限配置 | |||
- 二步登录 | |||
- 多环境发布 | |||
- dev | |||
- sit | |||
- stage | |||
- prod | |||
- 全局功能 | |||
- 国际化多语言 | |||
- 多种动态换肤 | |||
- 动态侧边栏(支持多级路由嵌套) | |||
- 动态面包屑 | |||
- 快捷导航(标签页) | |||
- Svg Sprite 图标 | |||
- 本地/后端 mock 数据 | |||
- Screenfull全屏 | |||
- 自适应收缩侧边栏 | |||
- 编辑器 | |||
- 富文本 | |||
- Markdown | |||
- JSON 等多格式 | |||
- Excel | |||
- 导出excel | |||
- 导入excel | |||
- 前端可视化excel | |||
- 导出zip | |||
- 表格 | |||
- 动态表格 | |||
- 拖拽表格 | |||
- 内联编辑 | |||
- 错误页面 | |||
- 401 | |||
- 404 | |||
- 組件 | |||
- 头像上传 | |||
- 返回顶部 | |||
- 拖拽Dialog | |||
- 拖拽Select | |||
- 拖拽看板 | |||
- 列表拖拽 | |||
- SplitPane | |||
- Dropzone | |||
- Sticky | |||
- CountTo | |||
- 综合实例 | |||
- 错误日志 | |||
- Dashboard | |||
- 引导页 | |||
- ECharts 图表 | |||
- Clipboard(剪贴复制) | |||
- Markdown2html | |||
``` | |||
## 开发 | |||
```bash | |||
# 克隆项目 | |||
git clone -b i18n git@github.com:PanJiaChen/vue-element-admin.git | |||
# 进入项目目录 | |||
cd vue-element-admin | |||
# 安装依赖 | |||
npm install | |||
# 建议不要直接使用 cnpm 安装依赖,会有各种诡异的 bug。可以通过如下操作解决 npm 下载速度慢的问题 | |||
npm install --registry=https://registry.npm.taobao.org | |||
# 启动服务 | |||
npm run dev | |||
``` | |||
浏览器访问 http://localhost:9527 | |||
## 发布 | |||
```bash | |||
# 构建测试环境 | |||
npm run build:stage | |||
# 构建生产环境 | |||
npm run build:prod | |||
``` | |||
## 其它 | |||
```bash | |||
# 预览发布环境效果 | |||
npm run preview | |||
# 预览发布环境效果 + 静态资源分析 | |||
npm run preview -- --report | |||
# 代码格式检查 | |||
npm run lint | |||
# 代码格式检查并自动修复 | |||
npm run lint -- --fix | |||
``` | |||
更多信息请参考 [使用文档](https://panjiachen.github.io/vue-element-admin-site/zh/) | |||
## Changelog | |||
Detailed changes for each release are documented in the [release notes](https://github.com/PanJiaChen/vue-element-admin/releases). | |||
## Online Demo | |||
[在线 Demo](https://panjiachen.github.io/vue-element-admin) | |||
## Donate | |||
如果你觉得这个项目帮助到了你,你可以帮作者买一杯果汁表示鼓励 :tropical_drink: | |||
![donate](https://panjiachen.github.io/donate/donation.png) | |||
[更多捐赠方式](https://panjiachen.gitee.io/vue-element-admin-site/zh/donate) | |||
[Paypal Me](https://www.paypal.me/panfree23) | |||
[Buy me a coffee](https://www.buymeacoffee.com/Pan) | |||
## 购买贴纸 | |||
你也可以通过 购买[官方授权的贴纸](https://smallsticker.com/product/vue-element-admin) 的方式来支持 vue-element-admin - 每售出一张贴纸,本项目将获得 2 元的捐赠。 | |||
## Browsers support | |||
Modern browsers and 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 | | |||
## License | |||
[MIT](https://github.com/PanJiaChen/vue-element-admin/blob/master/LICENSE) | |||
Copyright (c) 2017-present PanJiaChen |
@@ -0,0 +1,14 @@ | |||
module.exports = { | |||
presets: [ | |||
// https://github.com/vuejs/vue-cli/tree/master/packages/@vue/babel-preset-app | |||
'@vue/cli-plugin-babel/preset' | |||
], | |||
'env': { | |||
'development': { | |||
// babel-plugin-dynamic-import-node plugin only does one thing by converting all import() to require(). | |||
// This plugin can significantly increase the speed of hot updates, when you have a large number of pages. | |||
// https://panjiachen.github.io/vue-element-admin-site/guide/advanced/lazy-loading.html | |||
'plugins': ['dynamic-import-node'] | |||
} | |||
} | |||
} |
@@ -0,0 +1,24 @@ | |||
module.exports = { | |||
moduleFileExtensions: ['js', 'jsx', 'json', 'vue'], | |||
transform: { | |||
'^.+\\.vue$': 'vue-jest', | |||
'.+\\.(css|styl|less|sass|scss|svg|png|jpg|ttf|woff|woff2)$': | |||
'jest-transform-stub', | |||
'^.+\\.jsx?$': 'babel-jest' | |||
}, | |||
moduleNameMapper: { | |||
'^@/(.*)$': '<rootDir>/src/$1' | |||
}, | |||
snapshotSerializers: ['jest-serializer-vue'], | |||
testMatch: [ | |||
'**/tests/unit/**/*.spec.(js|jsx|ts|tsx)|**/__tests__/*.(js|jsx|ts|tsx)' | |||
], | |||
collectCoverageFrom: ['src/utils/**/*.{js,vue}', '!src/utils/auth.js', '!src/utils/request.js', 'src/components/**/*.{js,vue}'], | |||
coverageDirectory: '<rootDir>/tests/unit/coverage', | |||
// 'collectCoverage': true, | |||
'coverageReporters': [ | |||
'lcov', | |||
'text-summary' | |||
], | |||
testURL: 'http://localhost/' | |||
} |
@@ -0,0 +1,9 @@ | |||
{ | |||
"compilerOptions": { | |||
"baseUrl": "./", | |||
"paths": { | |||
"@/*": ["src/*"] | |||
} | |||
}, | |||
"exclude": ["node_modules", "dist"] | |||
} |
@@ -0,0 +1,116 @@ | |||
const Mock = require('mockjs') | |||
const List = [] | |||
const count = 100 | |||
const baseContent = '<p>I am testing data, I am testing data.</p><p><img src="https://wpimg.wallstcn.com/4c69009c-0fd4-4153-b112-6cb53d1cf943"></p>' | |||
const image_uri = 'https://wpimg.wallstcn.com/e4558086-631c-425c-9430-56ffb46e70b3' | |||
for (let i = 0; i < count; i++) { | |||
List.push(Mock.mock({ | |||
id: '@increment', | |||
timestamp: +Mock.Random.date('T'), | |||
author: '@first', | |||
reviewer: '@first', | |||
title: '@title(5, 10)', | |||
content_short: 'mock data', | |||
content: baseContent, | |||
forecast: '@float(0, 100, 2, 2)', | |||
importance: '@integer(1, 3)', | |||
'type|1': ['CN', 'US', 'JP', 'EU'], | |||
'status|1': ['published', 'draft'], | |||
display_time: '@datetime', | |||
comment_disabled: true, | |||
pageviews: '@integer(300, 5000)', | |||
image_uri, | |||
platforms: ['a-platform'] | |||
})) | |||
} | |||
module.exports = [ | |||
{ | |||
url: '/vue-element-admin/article/list', | |||
type: 'get', | |||
response: config => { | |||
const { importance, type, title, page = 1, limit = 20, sort } = config.query | |||
let mockList = List.filter(item => { | |||
if (importance && item.importance !== +importance) return false | |||
if (type && item.type !== type) return false | |||
if (title && item.title.indexOf(title) < 0) return false | |||
return true | |||
}) | |||
if (sort === '-id') { | |||
mockList = mockList.reverse() | |||
} | |||
const pageList = mockList.filter((item, index) => index < limit * page && index >= limit * (page - 1)) | |||
return { | |||
code: 20000, | |||
data: { | |||
total: mockList.length, | |||
items: pageList | |||
} | |||
} | |||
} | |||
}, | |||
{ | |||
url: '/vue-element-admin/article/detail', | |||
type: 'get', | |||
response: config => { | |||
const { id } = config.query | |||
for (const article of List) { | |||
if (article.id === +id) { | |||
return { | |||
code: 20000, | |||
data: article | |||
} | |||
} | |||
} | |||
} | |||
}, | |||
{ | |||
url: '/vue-element-admin/article/pv', | |||
type: 'get', | |||
response: _ => { | |||
return { | |||
code: 20000, | |||
data: { | |||
pvData: [ | |||
{ key: 'PC', pv: 1024 }, | |||
{ key: 'mobile', pv: 1024 }, | |||
{ key: 'ios', pv: 1024 }, | |||
{ key: 'android', pv: 1024 } | |||
] | |||
} | |||
} | |||
} | |||
}, | |||
{ | |||
url: '/vue-element-admin/article/create', | |||
type: 'post', | |||
response: _ => { | |||
return { | |||
code: 20000, | |||
data: 'success' | |||
} | |||
} | |||
}, | |||
{ | |||
url: '/vue-element-admin/article/update', | |||
type: 'post', | |||
response: _ => { | |||
return { | |||
code: 20000, | |||
data: 'success' | |||
} | |||
} | |||
} | |||
] | |||
@@ -0,0 +1,60 @@ | |||
const Mock = require('mockjs') | |||
const { param2Obj } = require('./utils') | |||
const user = require('./user') | |||
const role = require('./role') | |||
const article = require('./article') | |||
const search = require('./remote-search') | |||
const mocks = [ | |||
...user, | |||
...role, | |||
...article, | |||
...search | |||
] | |||
// for front mock | |||
// please use it cautiously, it will redefine XMLHttpRequest, | |||
// which will cause many of your third-party libraries to be invalidated(like progress event). | |||
function mockXHR() { | |||
// mock patch | |||
// https://github.com/nuysoft/Mock/issues/300 | |||
Mock.XHR.prototype.proxy_send = Mock.XHR.prototype.send | |||
Mock.XHR.prototype.send = function() { | |||
if (this.custom.xhr) { | |||
this.custom.xhr.withCredentials = this.withCredentials || false | |||
if (this.responseType) { | |||
this.custom.xhr.responseType = this.responseType | |||
} | |||
} | |||
this.proxy_send(...arguments) | |||
} | |||
function XHR2ExpressReqWrap(respond) { | |||
return function(options) { | |||
let result = null | |||
if (respond instanceof Function) { | |||
const { body, type, url } = options | |||
// https://expressjs.com/en/4x/api.html#req | |||
result = respond({ | |||
method: type, | |||
body: JSON.parse(body), | |||
query: param2Obj(url) | |||
}) | |||
} else { | |||
result = respond | |||
} | |||
return Mock.mock(result) | |||
} | |||
} | |||
for (const i of mocks) { | |||
Mock.mock(new RegExp(i.url), i.type || 'get', XHR2ExpressReqWrap(i.response)) | |||
} | |||
} | |||
module.exports = { | |||
mocks, | |||
mockXHR | |||
} |
@@ -0,0 +1,81 @@ | |||
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 { mocks } = require('./index.js') | |||
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(mocksForServer).length | |||
return { | |||
mockRoutesLength: mockRoutesLength, | |||
mockStartIndex: mockLastIndex - mockRoutesLength | |||
} | |||
} | |||
function unregisterRoutes() { | |||
Object.keys(require.cache).forEach(i => { | |||
if (i.includes(mockDir)) { | |||
delete require.cache[require.resolve(i)] | |||
} | |||
}) | |||
} | |||
// 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 => { | |||
// parse app.body | |||
// https://expressjs.com/en/4x/api.html#req.body | |||
app.use(bodyParser.json()) | |||
app.use(bodyParser.urlencoded({ | |||
extended: true | |||
})) | |||
const mockRoutes = registerRoutes(app) | |||
var mockRoutesLength = mockRoutes.mockRoutesLength | |||
var mockStartIndex = mockRoutes.mockStartIndex | |||
// watch files, hot reload mock server | |||
chokidar.watch(mockDir, { | |||
ignored: /mock-server/, | |||
ignoreInitial: true | |||
}).on('all', (event, path) => { | |||
if (event === 'change' || event === 'add') { | |||
try { | |||
// remove mock routes stack | |||
app._router.stack.splice(mockStartIndex, mockRoutesLength) | |||
// clear routes cache | |||
unregisterRoutes() | |||
const mockRoutes = registerRoutes(app) | |||
mockRoutesLength = mockRoutes.mockRoutesLength | |||
mockStartIndex = mockRoutes.mockStartIndex | |||
console.log(chalk.magentaBright(`\n > Mock Server hot reload success! changed ${path}`)) | |||
} catch (error) { | |||
console.log(chalk.redBright(error)) | |||
} | |||
} | |||
}) | |||
} |
@@ -0,0 +1,51 @@ | |||
const Mock = require('mockjs') | |||
const NameList = [] | |||
const count = 100 | |||
for (let i = 0; i < count; i++) { | |||
NameList.push(Mock.mock({ | |||
name: '@first' | |||
})) | |||
} | |||
NameList.push({ name: 'mock-Pan' }) | |||
module.exports = [ | |||
// username search | |||
{ | |||
url: '/vue-element-admin/search/user', | |||
type: 'get', | |||
response: config => { | |||
const { name } = config.query | |||
const mockNameList = NameList.filter(item => { | |||
const lowerCaseName = item.name.toLowerCase() | |||
return !(name && lowerCaseName.indexOf(name.toLowerCase()) < 0) | |||
}) | |||
return { | |||
code: 20000, | |||
data: { items: mockNameList } | |||
} | |||
} | |||
}, | |||
// transaction list | |||
{ | |||
url: '/vue-element-admin/transaction/list', | |||
type: 'get', | |||
response: _ => { | |||
return { | |||
code: 20000, | |||
data: { | |||
total: 20, | |||
'items|20': [{ | |||
order_no: '@guid()', | |||
timestamp: +Mock.Random.date('T'), | |||
username: '@name()', | |||
price: '@float(1000, 15000, 0, 2)', | |||
'status|1': ['success', 'pending'] | |||
}] | |||
} | |||
} | |||
} | |||
} | |||
] |
@@ -0,0 +1,98 @@ | |||
const Mock = require('mockjs') | |||
const { deepClone } = require('../utils') | |||
const { asyncRoutes, constantRoutes } = require('./routes.js') | |||
const routes = deepClone([...constantRoutes, ...asyncRoutes]) | |||
const roles = [ | |||
{ | |||
key: 'admin', | |||
name: 'admin', | |||
description: 'Super Administrator. Have access to view all pages.', | |||
routes: routes | |||
}, | |||
{ | |||
key: 'editor', | |||
name: 'editor', | |||
description: 'Normal Editor. Can see all pages except permission page', | |||
routes: routes.filter(i => i.path !== '/permission')// just a mock | |||
}, | |||
{ | |||
key: 'visitor', | |||
name: 'visitor', | |||
description: 'Just a visitor. Can only see the home page and the document page', | |||
routes: [{ | |||
path: '', | |||
redirect: 'dashboard', | |||
children: [ | |||
{ | |||
path: 'dashboard', | |||
name: 'Dashboard', | |||
meta: { title: 'dashboard', icon: 'dashboard' } | |||
} | |||
] | |||
}] | |||
} | |||
] | |||
module.exports = [ | |||
// mock get all routes form server | |||
{ | |||
url: '/vue-element-admin/routes', | |||
type: 'get', | |||
response: _ => { | |||
return { | |||
code: 20000, | |||
data: routes | |||
} | |||
} | |||
}, | |||
// mock get all roles form server | |||
{ | |||
url: '/vue-element-admin/roles', | |||
type: 'get', | |||
response: _ => { | |||
return { | |||
code: 20000, | |||
data: roles | |||
} | |||
} | |||
}, | |||
// add role | |||
{ | |||
url: '/vue-element-admin/role', | |||
type: 'post', | |||
response: { | |||
code: 20000, | |||
data: { | |||
key: Mock.mock('@integer(300, 5000)') | |||
} | |||
} | |||
}, | |||
// update role | |||
{ | |||
url: '/vue-element-admin/role/[A-Za-z0-9]', | |||
type: 'put', | |||
response: { | |||
code: 20000, | |||
data: { | |||
status: 'success' | |||
} | |||
} | |||
}, | |||
// delete role | |||
{ | |||
url: '/vue-element-admin/role/[A-Za-z0-9]', | |||
type: 'delete', | |||
response: { | |||
code: 20000, | |||
data: { | |||
status: 'success' | |||
} | |||
} | |||
} | |||
] |
@@ -0,0 +1,530 @@ | |||
// Just a mock data | |||
const constantRoutes = [ | |||
{ | |||
path: '/redirect', | |||
component: 'layout/Layout', | |||
hidden: true, | |||
children: [ | |||
{ | |||
path: '/redirect/:path*', | |||
component: 'views/redirect/index' | |||
} | |||
] | |||
}, | |||
{ | |||
path: '/login', | |||
component: 'views/login/index', | |||
hidden: true | |||
}, | |||
{ | |||
path: '/auth-redirect', | |||
component: 'views/login/auth-redirect', | |||
hidden: true | |||
}, | |||
{ | |||
path: '/404', | |||
component: 'views/error-page/404', | |||
hidden: true | |||
}, | |||
{ | |||
path: '/401', | |||
component: 'views/error-page/401', | |||
hidden: true | |||
}, | |||
{ | |||
path: '', | |||
component: 'layout/Layout', | |||
redirect: 'dashboard', | |||
children: [ | |||
{ | |||
path: 'dashboard', | |||
component: 'views/dashboard/index', | |||
name: 'Dashboard', | |||
meta: { title: 'dashboard', icon: 'dashboard', affix: true } | |||
} | |||
] | |||
}, | |||
{ | |||
path: '/documentation', | |||
component: 'layout/Layout', | |||
children: [ | |||
{ | |||
path: 'index', | |||
component: 'views/documentation/index', | |||
name: 'Documentation', | |||
meta: { title: 'documentation', icon: 'documentation', affix: true } | |||
} | |||
] | |||
}, | |||
{ | |||
path: '/guide', | |||
component: 'layout/Layout', | |||
redirect: '/guide/index', | |||
children: [ | |||
{ | |||
path: 'index', | |||
component: 'views/guide/index', | |||
name: 'Guide', | |||
meta: { title: 'guide', icon: 'guide', noCache: true } | |||
} | |||
] | |||
} | |||
] | |||
const asyncRoutes = [ | |||
{ | |||
path: '/permission', | |||
component: 'layout/Layout', | |||
redirect: '/permission/index', | |||
alwaysShow: true, | |||
meta: { | |||
title: 'permission', | |||
icon: 'lock', | |||
roles: ['admin', 'editor'] | |||
}, | |||
children: [ | |||
{ | |||
path: 'page', | |||
component: 'views/permission/page', | |||
name: 'PagePermission', | |||
meta: { | |||
title: 'pagePermission', | |||
roles: ['admin'] | |||
} | |||
}, | |||
{ | |||
path: 'directive', | |||
component: 'views/permission/directive', | |||
name: 'DirectivePermission', | |||
meta: { | |||
title: 'directivePermission' | |||
} | |||
}, | |||
{ | |||
path: 'role', | |||
component: 'views/permission/role', | |||
name: 'RolePermission', | |||
meta: { | |||
title: 'rolePermission', | |||
roles: ['admin'] | |||
} | |||
} | |||
] | |||
}, | |||
{ | |||
path: '/icon', | |||
component: 'layout/Layout', | |||
children: [ | |||
{ | |||
path: 'index', | |||
component: 'views/icons/index', | |||
name: 'Icons', | |||
meta: { title: 'icons', icon: 'icon', noCache: true } | |||
} | |||
] | |||
}, | |||
{ | |||
path: '/components', | |||
component: 'layout/Layout', | |||
redirect: 'noRedirect', | |||
name: 'ComponentDemo', | |||
meta: { | |||
title: 'components', | |||
icon: 'component' | |||
}, | |||
children: [ | |||
{ | |||
path: 'tinymce', | |||
component: 'views/components-demo/tinymce', | |||
name: 'TinymceDemo', | |||
meta: { title: 'tinymce' } | |||
}, | |||
{ | |||
path: 'markdown', | |||
component: 'views/components-demo/markdown', | |||
name: 'MarkdownDemo', | |||
meta: { title: 'markdown' } | |||
}, | |||
{ | |||
path: 'json-editor', | |||
component: 'views/components-demo/json-editor', | |||
name: 'JsonEditorDemo', | |||
meta: { title: 'jsonEditor' } | |||
}, | |||
{ | |||
path: 'split-pane', | |||
component: 'views/components-demo/split-pane', | |||
name: 'SplitpaneDemo', | |||
meta: { title: 'splitPane' } | |||
}, | |||
{ | |||
path: 'avatar-upload', | |||
component: 'views/components-demo/avatar-upload', | |||
name: 'AvatarUploadDemo', | |||
meta: { title: 'avatarUpload' } | |||
}, | |||
{ | |||
path: 'dropzone', | |||
component: 'views/components-demo/dropzone', | |||
name: 'DropzoneDemo', | |||
meta: { title: 'dropzone' } | |||
}, | |||
{ | |||
path: 'sticky', | |||
component: 'views/components-demo/sticky', | |||
name: 'StickyDemo', | |||
meta: { title: 'sticky' } | |||
}, | |||
{ | |||
path: 'count-to', | |||
component: 'views/components-demo/count-to', | |||
name: 'CountToDemo', | |||
meta: { title: 'countTo' } | |||
}, | |||
{ | |||
path: 'mixin', | |||
component: 'views/components-demo/mixin', | |||
name: 'ComponentMixinDemo', | |||
meta: { title: 'componentMixin' } | |||
}, | |||
{ | |||
path: 'back-to-top', | |||
component: 'views/components-demo/back-to-top', | |||
name: 'BackToTopDemo', | |||
meta: { title: 'backToTop' } | |||
}, | |||
{ | |||
path: 'drag-dialog', | |||
component: 'views/components-demo/drag-dialog', | |||
name: 'DragDialogDemo', | |||
meta: { title: 'dragDialog' } | |||
}, | |||
{ | |||
path: 'drag-select', | |||
component: 'views/components-demo/drag-select', | |||
name: 'DragSelectDemo', | |||
meta: { title: 'dragSelect' } | |||
}, | |||
{ | |||
path: 'dnd-list', | |||
component: 'views/components-demo/dnd-list', | |||
name: 'DndListDemo', | |||
meta: { title: 'dndList' } | |||
}, | |||
{ | |||
path: 'drag-kanban', | |||
component: 'views/components-demo/drag-kanban', | |||
name: 'DragKanbanDemo', | |||
meta: { title: 'dragKanban' } | |||
} | |||
] | |||
}, | |||
{ | |||
path: '/charts', | |||
component: 'layout/Layout', | |||
redirect: 'noRedirect', | |||
name: 'Charts', | |||
meta: { | |||
title: 'charts', | |||
icon: 'chart' | |||
}, | |||
children: [ | |||
{ | |||
path: 'keyboard', | |||
component: 'views/charts/keyboard', | |||
name: 'KeyboardChart', | |||
meta: { title: 'keyboardChart', noCache: true } | |||
}, | |||
{ | |||
path: 'line', | |||
component: 'views/charts/line', | |||
name: 'LineChart', | |||
meta: { title: 'lineChart', noCache: true } | |||
}, | |||
{ | |||
path: 'mixchart', | |||
component: 'views/charts/mixChart', | |||
name: 'MixChart', | |||
meta: { title: 'mixChart', noCache: true } | |||
} | |||
] | |||
}, | |||
{ | |||
path: '/nested', | |||
component: 'layout/Layout', | |||
redirect: '/nested/menu1/menu1-1', | |||
name: 'Nested', | |||
meta: { | |||
title: 'nested', | |||
icon: 'nested' | |||
}, | |||
children: [ | |||
{ | |||
path: 'menu1', | |||
component: 'views/nested/menu1/index', | |||
name: 'Menu1', | |||
meta: { title: 'menu1' }, | |||
redirect: '/nested/menu1/menu1-1', | |||
children: [ | |||
{ | |||
path: 'menu1-1', | |||
component: 'views/nested/menu1/menu1-1', | |||
name: 'Menu1-1', | |||
meta: { title: 'menu1-1' } | |||
}, | |||
{ | |||
path: 'menu1-2', | |||
component: 'views/nested/menu1/menu1-2', | |||
name: 'Menu1-2', | |||
redirect: '/nested/menu1/menu1-2/menu1-2-1', | |||
meta: { title: 'menu1-2' }, | |||
children: [ | |||
{ | |||
path: 'menu1-2-1', | |||
component: 'views/nested/menu1/menu1-2/menu1-2-1', | |||
name: 'Menu1-2-1', | |||
meta: { title: 'menu1-2-1' } | |||
}, | |||
{ | |||
path: 'menu1-2-2', | |||
component: 'views/nested/menu1/menu1-2/menu1-2-2', | |||
name: 'Menu1-2-2', | |||
meta: { title: 'menu1-2-2' } | |||
} | |||
] | |||
}, | |||
{ | |||
path: 'menu1-3', | |||
component: 'views/nested/menu1/menu1-3', | |||
name: 'Menu1-3', | |||
meta: { title: 'menu1-3' } | |||
} | |||
] | |||
}, | |||
{ | |||
path: 'menu2', | |||
name: 'Menu2', | |||
component: 'views/nested/menu2/index', | |||
meta: { title: 'menu2' } | |||
} | |||
] | |||
}, | |||
{ | |||
path: '/example', | |||
component: 'layout/Layout', | |||
redirect: '/example/list', | |||
name: 'Example', | |||
meta: { | |||
title: 'example', | |||
icon: 'example' | |||
}, | |||
children: [ | |||
{ | |||
path: 'create', | |||
component: 'views/example/create', | |||
name: 'CreateArticle', | |||
meta: { title: 'createArticle', icon: 'edit' } | |||
}, | |||
{ | |||
path: 'edit/:id(\\d+)', | |||
component: 'views/example/edit', | |||
name: 'EditArticle', | |||
meta: { title: 'editArticle', noCache: true }, | |||
hidden: true | |||
}, | |||
{ | |||
path: 'list', | |||
component: 'views/example/list', | |||
name: 'ArticleList', | |||
meta: { title: 'articleList', icon: 'list' } | |||
} | |||
] | |||
}, | |||
{ | |||
path: '/tab', | |||
component: 'layout/Layout', | |||
children: [ | |||
{ | |||
path: 'index', | |||
component: 'views/tab/index', | |||
name: 'Tab', | |||
meta: { title: 'tab', icon: 'tab' } | |||
} | |||
] | |||
}, | |||
{ | |||
path: '/error', | |||
component: 'layout/Layout', | |||
redirect: 'noRedirect', | |||
name: 'ErrorPages', | |||
meta: { | |||
title: 'errorPages', | |||
icon: '404' | |||
}, | |||
children: [ | |||
{ | |||
path: '401', | |||
component: 'views/error-page/401', | |||
name: 'Page401', | |||
meta: { title: 'page401', noCache: true } | |||
}, | |||
{ | |||
path: '404', | |||
component: 'views/error-page/404', | |||
name: 'Page404', | |||
meta: { title: 'page404', noCache: true } | |||
} | |||
] | |||
}, | |||
{ | |||
path: '/error-log', | |||
component: 'layout/Layout', | |||
redirect: 'noRedirect', | |||
children: [ | |||
{ | |||
path: 'log', | |||
component: 'views/error-log/index', | |||
name: 'ErrorLog', | |||
meta: { title: 'errorLog', icon: 'bug' } | |||
} | |||
] | |||
}, | |||
{ | |||
path: '/excel', | |||
component: 'layout/Layout', | |||
redirect: '/excel/export-excel', | |||
name: 'Excel', | |||
meta: { | |||
title: 'excel', | |||
icon: 'excel' | |||
}, | |||
children: [ | |||
{ | |||
path: 'export-excel', | |||
component: 'views/excel/export-excel', | |||
name: 'ExportExcel', | |||
meta: { title: 'exportExcel' } | |||
}, | |||
{ | |||
path: 'export-selected-excel', | |||
component: 'views/excel/select-excel', | |||
name: 'SelectExcel', | |||
meta: { title: 'selectExcel' } | |||
}, | |||
{ | |||
path: 'export-merge-header', | |||
component: 'views/excel/merge-header', | |||
name: 'MergeHeader', | |||
meta: { title: 'mergeHeader' } | |||
}, | |||
{ | |||
path: 'upload-excel', | |||
component: 'views/excel/upload-excel', | |||
name: 'UploadExcel', | |||
meta: { title: 'uploadExcel' } | |||
} | |||
] | |||
}, | |||
{ | |||
path: '/zip', | |||
component: 'layout/Layout', | |||
redirect: '/zip/download', | |||
alwaysShow: true, | |||
meta: { title: 'zip', icon: 'zip' }, | |||
children: [ | |||
{ | |||
path: 'download', | |||
component: 'views/zip/index', | |||
name: 'ExportZip', | |||
meta: { title: 'exportZip' } | |||
} | |||
] | |||
}, | |||
{ | |||
path: '/pdf', | |||
component: 'layout/Layout', | |||
redirect: '/pdf/index', | |||
children: [ | |||
{ | |||
path: 'index', | |||
component: 'views/pdf/index', | |||
name: 'PDF', | |||
meta: { title: 'pdf', icon: 'pdf' } | |||
} | |||
] | |||
}, | |||
{ | |||
path: '/pdf/download', | |||
component: 'views/pdf/download', | |||
hidden: true | |||
}, | |||
{ | |||
path: '/theme', | |||
component: 'layout/Layout', | |||
redirect: 'noRedirect', | |||
children: [ | |||
{ | |||
path: 'index', | |||
component: 'views/theme/index', | |||
name: 'Theme', | |||
meta: { title: 'theme', icon: 'theme' } | |||
} | |||
] | |||
}, | |||
{ | |||
path: '/clipboard', | |||
component: 'layout/Layout', | |||
redirect: 'noRedirect', | |||
children: [ | |||
{ | |||
path: 'index', | |||
component: 'views/clipboard/index', | |||
name: 'ClipboardDemo', | |||
meta: { title: 'clipboardDemo', icon: 'clipboard' } | |||
} | |||
] | |||
}, | |||
{ | |||
path: '/i18n', | |||
component: 'layout/Layout', | |||
children: [ | |||
{ | |||
path: 'index', | |||
component: 'views/i18n-demo/index', | |||
name: 'I18n', | |||
meta: { title: 'i18n', icon: 'international' } | |||
} | |||
] | |||
}, | |||
{ | |||
path: 'external-link', | |||
component: 'layout/Layout', | |||
children: [ | |||
{ | |||
path: 'https://github.com/PanJiaChen/vue-element-admin', | |||
meta: { title: 'externalLink', icon: 'link' } | |||
} | |||
] | |||
}, | |||
{ path: '*', redirect: '/404', hidden: true } | |||
] | |||
module.exports = { | |||
constantRoutes, | |||
asyncRoutes | |||
} |
@@ -0,0 +1,85 @@ | |||
const tokens = { | |||
'19923693200': { | |||
token: 'admin-token' | |||
}, | |||
editor: { | |||
token: 'editor-token' | |||
} | |||
} | |||
const users = { | |||
'admin-token': { | |||
roles: ['admin'], | |||
introduction: 'I am a super administrator', | |||
avatar: | |||
'https://wpimg.wallstcn.com/f778738c-e4f8-4870-b634-56703b4acafe.gif', | |||
name: 'Super Admin' | |||
}, | |||
'editor-token': { | |||
roles: ['editor'], | |||
introduction: 'I am an editor', | |||
avatar: | |||
'https://wpimg.wallstcn.com/f778738c-e4f8-4870-b634-56703b4acafe.gif', | |||
name: 'Normal Editor' | |||
} | |||
} | |||
module.exports = [ | |||
// user login | |||
{ | |||
url: '/vue-element-admin/user/login', | |||
type: 'post', | |||
response: config => { | |||
const { phone } = config.body | |||
const token = tokens[phone] | |||
// mock error | |||
if (!token) { | |||
return { | |||
code: 60204, | |||
message: 'Account and password are incorrect.' | |||
} | |||
} | |||
return { | |||
code: 20000, | |||
data: token | |||
} | |||
} | |||
}, | |||
// get user info | |||
{ | |||
url: '/vue-element-admin/user/info.*', | |||
type: 'get', | |||
response: config => { | |||
const { token } = config.query | |||
const info = users[token] | |||
// mock error | |||
if (!info) { | |||
return { | |||
code: 50008, | |||
message: 'Login failed, unable to get user details.' | |||
} | |||
} | |||
return { | |||
code: 20000, | |||
data: info | |||
} | |||
} | |||
}, | |||
// user logout | |||
{ | |||
url: '/vue-element-admin/user/logout', | |||
type: 'post', | |||
response: _ => { | |||
return { | |||
code: 20000, | |||
data: 'success' | |||
} | |||
} | |||
} | |||
] |
@@ -0,0 +1,48 @@ | |||
/** | |||
* @param {string} url | |||
* @returns {Object} | |||
*/ | |||
function param2Obj(url) { | |||
const search = decodeURIComponent(url.split('?')[1]).replace(/\+/g, ' ') | |||
if (!search) { | |||
return {} | |||
} | |||
const obj = {} | |||
const searchArr = search.split('&') | |||
searchArr.forEach(v => { | |||
const index = v.indexOf('=') | |||
if (index !== -1) { | |||
const name = v.substring(0, index) | |||
const val = v.substring(index + 1, v.length) | |||
obj[name] = val | |||
} | |||
}) | |||
return obj | |||
} | |||
/** | |||
* This is just a simple version of deep copy | |||
* Has a lot of edge cases bug | |||
* If you want to use a perfect deep copy, use lodash's _.cloneDeep | |||
* @param {Object} source | |||
* @returns {Object} | |||
*/ | |||
function deepClone(source) { | |||
if (!source && typeof source !== 'object') { | |||
throw new Error('error arguments', 'deepClone') | |||
} | |||
const targetObj = source.constructor === Array ? [] : {} | |||
Object.keys(source).forEach(keys => { | |||
if (source[keys] && typeof source[keys] === 'object') { | |||
targetObj[keys] = deepClone(source[keys]) | |||
} else { | |||
targetObj[keys] = source[keys] | |||
} | |||
}) | |||
return targetObj | |||
} | |||
module.exports = { | |||
param2Obj, | |||
deepClone | |||
} |
@@ -0,0 +1,121 @@ | |||
{ | |||
"name": "funoos", | |||
"version": "4.3.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>", | |||
"scripts": { | |||
"dev": "vue-cli-service serve", | |||
"lint": "eslint --ext .js,.vue src", | |||
"build:prod": "vue-cli-service build", | |||
"build:stage": "vue-cli-service build --mode staging", | |||
"preview": "node build/index.js --preview", | |||
"new": "plop", | |||
"svgo": "svgo -f src/icons/svg --config=src/icons/svgo.yml", | |||
"test:unit": "jest --clearCache && vue-cli-service test:unit", | |||
"test:ci": "npm run lint && npm run test:unit" | |||
}, | |||
"dependencies": { | |||
"axios": "^0.21.1", | |||
"bignumber.js": "^9.0.1", | |||
"clipboard": "^2.0.4", | |||
"codemirror": "5.45.0", | |||
"core-js": "3.6.5", | |||
"crypto-js": "^4.0.0", | |||
"driver.js": "0.9.5", | |||
"dropzone": "5.5.1", | |||
"echarts": "4.2.1", | |||
"element-ui": "2.13.2", | |||
"file-saver": "2.0.1", | |||
"fuse.js": "3.4.4", | |||
"hevue-img-preview": "^3.0.0", | |||
"js-cookie": "2.2.0", | |||
"jsonlint": "1.6.3", | |||
"jszip": "3.2.1", | |||
"lodash": "^4.17.20", | |||
"normalize.css": "7.0.0", | |||
"nprogress": "0.2.0", | |||
"path-to-regexp": "2.4.0", | |||
"pinyin": "2.9.0", | |||
"screenfull": "4.2.0", | |||
"script-loader": "0.7.2", | |||
"sortablejs": "1.8.4", | |||
"tui-editor": "1.3.3", | |||
"vue": "2.6.10", | |||
"vue-count-to": "1.0.13", | |||
"vue-i18n": "^7.3.2", | |||
"vue-mini-player": "^0.2.1", | |||
"vue-router": "3.0.2", | |||
"vue-splitpane": "1.0.4", | |||
"vuedraggable": "2.20.0", | |||
"vuex": "3.1.0", | |||
"xlsx": "0.14.1" | |||
}, | |||
"devDependencies": { | |||
"@vue/cli-plugin-babel": "4.4.4", | |||
"@vue/cli-plugin-eslint": "4.4.4", | |||
"@vue/cli-plugin-unit-jest": "^4.5.9", | |||
"@vue/cli-service": "4.4.4", | |||
"@vue/test-utils": "1.0.0-beta.29", | |||
"autoprefixer": "9.5.1", | |||
"babel-eslint": "10.1.0", | |||
"babel-jest": "^26.6.3", | |||
"babel-plugin-dynamic-import-node": "2.3.3", | |||
"chalk": "2.4.2", | |||
"chokidar": "2.1.5", | |||
"connect": "3.6.6", | |||
"eslint": "6.7.2", | |||
"eslint-plugin-vue": "6.2.2", | |||
"html-webpack-plugin": "3.2.0", | |||
"husky": "1.3.1", | |||
"less": "^4.1.1", | |||
"less-loader": "^7.3.0", | |||
"lint-staged": "8.1.5", | |||
"mockjs": "1.0.1-beta3", | |||
"plop": "2.3.0", | |||
"runjs": "^4.4.2", | |||
"sass": "1.26.2", | |||
"sass-loader": "8.0.2", | |||
"sass-resources-loader": "^2.1.0", | |||
"script-ext-html-webpack-plugin": "2.1.3", | |||
"serve-static": "1.13.2", | |||
"svg-sprite-loader": "4.1.3", | |||
"svgo": "1.2.0", | |||
"vue-template-compiler": "2.6.10" | |||
}, | |||
"browserslist": [ | |||
"> 1%", | |||
"last 2 versions" | |||
], | |||
"bugs": { | |||
"url": "https://github.com/PanJiaChen/vue-element-admin/issues" | |||
}, | |||
"engines": { | |||
"node": ">=8.9", | |||
"npm": ">= 3.0.0" | |||
}, | |||
"keywords": [ | |||
"vue", | |||
"admin", | |||
"dashboard", | |||
"element-ui", | |||
"boilerplate", | |||
"admin-template", | |||
"management-system" | |||
], | |||
"license": "MIT", | |||
"lint-staged": { | |||
"src/**/*.{js,vue}": [ | |||
"eslint --fix", | |||
"git add" | |||
] | |||
}, | |||
"husky": { | |||
"hooks": { | |||
"pre-commit": "lint-staged" | |||
} | |||
}, | |||
"repository": { | |||
"type": "git", | |||
"url": "git+https://github.com/PanJiaChen/vue-element-admin.git" | |||
} | |||
} |
@@ -0,0 +1,26 @@ | |||
{{#if template}} | |||
<template> | |||
<div /> | |||
</template> | |||
{{/if}} | |||
{{#if script}} | |||
<script> | |||
export default { | |||
name: '{{ properCase name }}', | |||
props: {}, | |||
data() { | |||
return {} | |||
}, | |||
created() {}, | |||
mounted() {}, | |||
methods: {} | |||
} | |||
</script> | |||
{{/if}} | |||
{{#if style}} | |||
<style lang="scss" scoped> | |||
</style> | |||
{{/if}} |
@@ -0,0 +1,55 @@ | |||
const { notEmpty } = require('../utils.js') | |||
module.exports = { | |||
description: 'generate vue component', | |||
prompts: [{ | |||
type: 'input', | |||
name: 'name', | |||
message: 'component name please', | |||
validate: notEmpty('name') | |||
}, | |||
{ | |||
type: 'checkbox', | |||
name: 'blocks', | |||
message: 'Blocks:', | |||
choices: [{ | |||
name: '<template>', | |||
value: 'template', | |||
checked: true | |||
}, | |||
{ | |||
name: '<script>', | |||
value: 'script', | |||
checked: true | |||
}, | |||
{ | |||
name: 'style', | |||
value: 'style', | |||
checked: true | |||
} | |||
], | |||
validate(value) { | |||
if (value.indexOf('script') === -1 && value.indexOf('template') === -1) { | |||
return 'Components require at least a <script> or <template> tag.' | |||
} | |||
return true | |||
} | |||
} | |||
], | |||
actions: data => { | |||
const name = '{{properCase name}}' | |||
const actions = [{ | |||
type: 'add', | |||
path: `src/components/${name}/index.vue`, | |||
templateFile: 'plop-templates/component/index.hbs', | |||
data: { | |||
name: name, | |||
template: data.blocks.includes('template'), | |||
script: data.blocks.includes('script'), | |||
style: data.blocks.includes('style') | |||
} | |||
}] | |||
return actions | |||
} | |||
} |
@@ -0,0 +1,16 @@ | |||
{{#if state}} | |||
const state = {} | |||
{{/if}} | |||
{{#if mutations}} | |||
const mutations = {} | |||
{{/if}} | |||
{{#if actions}} | |||
const actions = {} | |||
{{/if}} | |||
export default { | |||
namespaced: true, | |||
{{options}} | |||
} |
@@ -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 | |||
} | |||
} |
@@ -0,0 +1,2 @@ | |||
exports.notEmpty = name => v => | |||
!v || v.trim() === '' ? `${name} is required` : true |
@@ -0,0 +1,26 @@ | |||
{{#if template}} | |||
<template> | |||
<div /> | |||
</template> | |||
{{/if}} | |||
{{#if script}} | |||
<script> | |||
export default { | |||
name: '{{ properCase name }}', | |||
props: {}, | |||
data() { | |||
return {} | |||
}, | |||
created() {}, | |||
mounted() {}, | |||
methods: {} | |||
} | |||
</script> | |||
{{/if}} | |||
{{#if style}} | |||
<style lang="scss" scoped> | |||
</style> | |||
{{/if}} |
@@ -0,0 +1,55 @@ | |||
const { notEmpty } = require('../utils.js') | |||
module.exports = { | |||
description: 'generate a view', | |||
prompts: [{ | |||
type: 'input', | |||
name: 'name', | |||
message: 'view name please', | |||
validate: notEmpty('name') | |||
}, | |||
{ | |||
type: 'checkbox', | |||
name: 'blocks', | |||
message: 'Blocks:', | |||
choices: [{ | |||
name: '<template>', | |||
value: 'template', | |||
checked: true | |||
}, | |||
{ | |||
name: '<script>', | |||
value: 'script', | |||
checked: true | |||
}, | |||
{ | |||
name: 'style', | |||
value: 'style', | |||
checked: true | |||
} | |||
], | |||
validate(value) { | |||
if (value.indexOf('script') === -1 && value.indexOf('template') === -1) { | |||
return 'View require at least a <script> or <template> tag.' | |||
} | |||
return true | |||
} | |||
} | |||
], | |||
actions: data => { | |||
const name = '{{name}}' | |||
const actions = [{ | |||
type: 'add', | |||
path: `src/views/${name}/index.vue`, | |||
templateFile: 'plop-templates/view/index.hbs', | |||
data: { | |||
name: name, | |||
template: data.blocks.includes('template'), | |||
script: data.blocks.includes('script'), | |||
style: data.blocks.includes('style') | |||
} | |||
}] | |||
return actions | |||
} | |||
} |
@@ -0,0 +1,9 @@ | |||
const viewGenerator = require('./plop-templates/view/prompt') | |||
const componentGenerator = require('./plop-templates/component/prompt') | |||
const storeGenerator = require('./plop-templates/store/prompt.js') | |||
module.exports = function(plop) { | |||
plop.setGenerator('view', viewGenerator) | |||
plop.setGenerator('component', componentGenerator) | |||
plop.setGenerator('store', storeGenerator) | |||
} |
@@ -0,0 +1,5 @@ | |||
module.exports = { | |||
plugins: { | |||
autoprefixer: {} | |||
} | |||
} |
@@ -0,0 +1,15 @@ | |||
<!DOCTYPE html> | |||
<html> | |||
<head> | |||
<meta charset="utf-8"> | |||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> | |||
<meta name="renderer" content="webkit"> | |||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no"> | |||
<link rel="icon" href="<%= BASE_URL %>favicon.ico"> | |||
<title><%= webpackConfig.name %></title> | |||
</head> | |||
<body> | |||
<div id="app"></div> | |||
<!-- built files will be auto injected --> | |||
</body> | |||
</html> |