Compare commits
1 Commits
master
...
perf/keep-
Author | SHA1 | Date |
---|---|---|
Pan | d431de0589 |
|
@ -0,0 +1,12 @@
|
||||||
|
{
|
||||||
|
"presets": [
|
||||||
|
["env", {
|
||||||
|
"modules": false,
|
||||||
|
"targets": {
|
||||||
|
"browsers": ["> 1%", "last 2 versions", "not ie <= 8"]
|
||||||
|
}
|
||||||
|
}],
|
||||||
|
"stage-2"
|
||||||
|
],
|
||||||
|
"plugins": ["transform-vue-jsx", "transform-runtime"]
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
# https://editorconfig.org
|
# http://editorconfig.org
|
||||||
root = true
|
root = true
|
||||||
|
|
||||||
[*]
|
[*]
|
||||||
|
|
|
@ -1,5 +0,0 @@
|
||||||
# just a flag
|
|
||||||
ENV = 'development'
|
|
||||||
|
|
||||||
# base api
|
|
||||||
VUE_APP_BASE_API = '/dev-api'
|
|
|
@ -1,6 +0,0 @@
|
||||||
# just a flag
|
|
||||||
ENV = 'production'
|
|
||||||
|
|
||||||
# base api
|
|
||||||
VUE_APP_BASE_API = '/prod-api'
|
|
||||||
|
|
|
@ -1,8 +0,0 @@
|
||||||
NODE_ENV = production
|
|
||||||
|
|
||||||
# just a flag
|
|
||||||
ENV = 'staging'
|
|
||||||
|
|
||||||
# base api
|
|
||||||
VUE_APP_BASE_API = '/stage-api'
|
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
build/*.js
|
build/*.js
|
||||||
|
config/*.js
|
||||||
src/assets
|
src/assets
|
||||||
public
|
|
||||||
dist
|
|
||||||
|
|
33
.eslintrc.js
|
@ -1,7 +1,7 @@
|
||||||
module.exports = {
|
module.exports = {
|
||||||
root: true,
|
root: true,
|
||||||
parserOptions: {
|
|
||||||
parser: 'babel-eslint',
|
parser: 'babel-eslint',
|
||||||
|
parserOptions: {
|
||||||
sourceType: 'module'
|
sourceType: 'module'
|
||||||
},
|
},
|
||||||
env: {
|
env: {
|
||||||
|
@ -9,22 +9,22 @@ module.exports = {
|
||||||
node: true,
|
node: true,
|
||||||
es6: true,
|
es6: true,
|
||||||
},
|
},
|
||||||
extends: ['plugin:vue/recommended', 'eslint:recommended'],
|
extends: 'eslint:recommended',
|
||||||
|
// required to lint *.vue files
|
||||||
|
plugins: [
|
||||||
|
'html'
|
||||||
|
],
|
||||||
|
// check if imports actually resolve
|
||||||
|
'settings': {
|
||||||
|
'import/resolver': {
|
||||||
|
'webpack': {
|
||||||
|
'config': 'build/webpack.base.conf.js'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
// add your custom rules here
|
// add your custom rules here
|
||||||
//it is base on https://github.com/vuejs/eslint-config-vue
|
//it is base on https://github.com/vuejs/eslint-config-vue
|
||||||
rules: {
|
'rules': {
|
||||||
"vue/max-attributes-per-line": [2, {
|
|
||||||
"singleline": 10,
|
|
||||||
"multiline": {
|
|
||||||
"max": 1,
|
|
||||||
"allowFirstLine": false
|
|
||||||
}
|
|
||||||
}],
|
|
||||||
"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,
|
'accessor-pairs': 2,
|
||||||
'arrow-spacing': [2, {
|
'arrow-spacing': [2, {
|
||||||
'before': true,
|
'before': true,
|
||||||
|
@ -47,7 +47,7 @@ module.exports = {
|
||||||
'curly': [2, 'multi-line'],
|
'curly': [2, 'multi-line'],
|
||||||
'dot-location': [2, 'property'],
|
'dot-location': [2, 'property'],
|
||||||
'eol-last': 2,
|
'eol-last': 2,
|
||||||
'eqeqeq': ["error", "always", {"null": "ignore"}],
|
'eqeqeq': [2, 'allow-null'],
|
||||||
'generator-star-spacing': [2, {
|
'generator-star-spacing': [2, {
|
||||||
'before': true,
|
'before': true,
|
||||||
'after': true
|
'after': true
|
||||||
|
@ -196,3 +196,4 @@ module.exports = {
|
||||||
'array-bracket-spacing': [2, 'never']
|
'array-bracket-spacing': [2, 'never']
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,4 +0,0 @@
|
||||||
# These are supported funding model platforms
|
|
||||||
|
|
||||||
patreon: panjiachen
|
|
||||||
custom: https://panjiachen.github.io/vue-element-admin-site/donate
|
|
|
@ -1,33 +0,0 @@
|
||||||
---
|
|
||||||
name: Bug report(报告问题)
|
|
||||||
about: Create a report to help us improve
|
|
||||||
---
|
|
||||||
<!--
|
|
||||||
注意:为更好的解决你的问题,请参考模板提供完整信息,准确描述问题,信息不全的 issue 将被关闭。
|
|
||||||
|
|
||||||
Note: In order to better solve your problem, please refer to the template to provide complete information, accurately describe the problem, and the incomplete information issue will be closed.
|
|
||||||
-->
|
|
||||||
|
|
||||||
|
|
||||||
## Bug report(问题描述)
|
|
||||||
|
|
||||||
#### Steps to reproduce(问题复现步骤)
|
|
||||||
<!--
|
|
||||||
1. [xxx]
|
|
||||||
2. [xxx]
|
|
||||||
3. [xxxx]
|
|
||||||
-->
|
|
||||||
|
|
||||||
#### Screenshot or Gif(截图或动态图)
|
|
||||||
|
|
||||||
|
|
||||||
#### Link to minimal reproduction(最小可在线还原demo)
|
|
||||||
|
|
||||||
<!--
|
|
||||||
Please only use Codepen, JSFiddle, CodeSandbox or a github repo
|
|
||||||
-->
|
|
||||||
|
|
||||||
#### Other relevant information(格外信息)
|
|
||||||
- Your OS:
|
|
||||||
- Node.js version:
|
|
||||||
- vue-element-admin version:
|
|
|
@ -1,7 +0,0 @@
|
||||||
---
|
|
||||||
name: Feature Request(新功能建议)
|
|
||||||
about: Suggest an idea for this project
|
|
||||||
---
|
|
||||||
|
|
||||||
## Feature request(新功能建议)
|
|
||||||
|
|
|
@ -1,35 +0,0 @@
|
||||||
---
|
|
||||||
name: Question(提问)
|
|
||||||
about: Asking questions about use
|
|
||||||
---
|
|
||||||
|
|
||||||
## Question(提问)
|
|
||||||
|
|
||||||
<!--
|
|
||||||
提问之前,请确定你已经过自己的努力,尝试解决过这个问题。
|
|
||||||
若是代码相关问题,请不要只截图,请提供在线 demo,以便节约彼此的时间。
|
|
||||||
|
|
||||||
Before asking a question, please make sure that you have tried your best to solve this problem.
|
|
||||||
If it's a code-related issue, please don't just take screenshots. Please provide an online demo to save each other's time.
|
|
||||||
-->
|
|
||||||
|
|
||||||
#### Steps to reproduce(问题复现步骤)
|
|
||||||
<!--
|
|
||||||
1. [xxx]
|
|
||||||
2. [xxx]
|
|
||||||
3. [xxxx]
|
|
||||||
-->
|
|
||||||
|
|
||||||
#### Screenshot or Gif(截图或动态图)
|
|
||||||
|
|
||||||
|
|
||||||
#### Link to minimal reproduction(最小可在线还原demo)
|
|
||||||
|
|
||||||
<!--
|
|
||||||
Please only use Codepen, JSFiddle, CodeSandbox or a github repo
|
|
||||||
-->
|
|
||||||
|
|
||||||
#### Other relevant information(格外信息)
|
|
||||||
- Your OS:
|
|
||||||
- Node.js version:
|
|
||||||
- vue-element-admin version:
|
|
|
@ -1,13 +1,13 @@
|
||||||
.DS_Store
|
.DS_Store
|
||||||
node_modules/
|
node_modules/
|
||||||
dist/
|
dist/
|
||||||
|
gifs/
|
||||||
npm-debug.log*
|
npm-debug.log*
|
||||||
yarn-debug.log*
|
yarn-debug.log*
|
||||||
yarn-error.log*
|
yarn-error.log*
|
||||||
**/*.log
|
|
||||||
|
|
||||||
tests/**/coverage/
|
test/unit/coverage
|
||||||
tests/e2e/reports
|
test/e2e/reports
|
||||||
selenium-debug.log
|
selenium-debug.log
|
||||||
|
|
||||||
# Editor directories and files
|
# Editor directories and files
|
||||||
|
@ -17,7 +17,5 @@ selenium-debug.log
|
||||||
*.ntvs*
|
*.ntvs*
|
||||||
*.njsproj
|
*.njsproj
|
||||||
*.sln
|
*.sln
|
||||||
*.local
|
|
||||||
|
|
||||||
package-lock.json
|
package-lock.json
|
||||||
yarn.lock
|
|
||||||
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
// https://github.com/michael-ciniawsky/postcss-load-config
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
"plugins": {
|
||||||
|
"postcss-import": {},
|
||||||
|
"postcss-url": {},
|
||||||
|
// to edit target browsers: use "browserslist" field in package.json
|
||||||
|
"autoprefixer": {}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
language: node_js
|
language: node_js
|
||||||
node_js: 10
|
node_js: stable
|
||||||
script: npm run test
|
script: npm run test
|
||||||
notifications:
|
notifications:
|
||||||
email: false
|
email: false
|
||||||
|
|
228
README.es.md
|
@ -1,228 +0,0 @@
|
||||||
<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)
|
|
||||||
|
|
||||||
### Akveo
|
|
||||||
<a href="https://store.akveo.com/products/vue-java-admin-dashboard-spring?utm_campaign=akveo_store-Vue-Vue_demo%2Fgithub&utm_source=vue_admin&utm_medium=referral&utm_content=github_banner"><img width="500px" src="https://raw.githubusercontent.com/PanJiaChen/vue-element-admin-site/master/docs/.vuepress/public/images/vue-java-banner.png" /></a><p>Get Java backend for Vue admin with 20% discount for 39$ use coupon code SWB0RAZPZR1M
|
|
||||||
</p>
|
|
||||||
|
|
||||||
### Flatlogic
|
|
||||||
|
|
||||||
<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>
|
|
||||||
|
|
||||||
## 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
|
|
224
README.ja.md
|
@ -1,224 +0,0 @@
|
||||||
<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="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.zh-CN.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/)
|
|
||||||
|
|
||||||
- [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)
|
|
||||||
|
|
||||||
- おすすめシンプルテンプレート: [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をサポートしていません。masterブランチと共にアップデートされる[i18n Branch](https://github.com/PanJiaChen/vue-element-admin/tree/i18n)を使用してください。 **
|
|
||||||
|
|
||||||
**現在のバージョン `v4.0+` は `vue-cli` で構築していて、バグ報告は[issue](https://github.com/PanJiaChen/vue-element-admin/issues/new)のissueでお願いします。旧バージョン[tag/3.11.0](https://github.com/PanJiaChen/vue-element-admin/tree/tag/3.11.0)もあります。こちらは`vue-cli`に依存しないです。**
|
|
||||||
|
|
||||||
**低いバージョンのブラウザはサーポートしないです(例えば ie),必要があれば polyfill を追加してください。 [詳細はこちら](https://github.com/PanJiaChen/vue-element-admin/wiki#babel-polyfill)**
|
|
||||||
|
|
||||||
## 前準備
|
|
||||||
|
|
||||||
ローカル環境に [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)で開発しています。Requestは[Mock.js](https://github.com/nuysoft/Mock)のモックデータを使っています。
|
|
||||||
|
|
||||||
**バグ修正や新規機能追加のissue と pull requestは大歓迎です。**
|
|
||||||
|
|
||||||
[![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)
|
|
||||||
|
|
||||||
### Akveo
|
|
||||||
<a href="https://store.akveo.com/products/vue-java-admin-dashboard-spring?utm_campaign=akveo_store-Vue-Vue_demo%2Fgithub&utm_source=vue_admin&utm_medium=referral&utm_content=github_banner"><img width="500px" src="https://raw.githubusercontent.com/PanJiaChen/vue-element-admin-site/master/docs/.vuepress/public/images/vue-java-banner.png" /></a><p>Get Java backend for Vue admin with 20% discount for 39$ use coupon code SWB0RAZPZR1M
|
|
||||||
</p>
|
|
||||||
|
|
||||||
### Flatlogic
|
|
||||||
|
|
||||||
<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>
|
|
||||||
|
|
||||||
## 機能一覧
|
|
||||||
|
|
||||||
```
|
|
||||||
- ログイン / ログアウト
|
|
||||||
|
|
||||||
- Auth認証
|
|
||||||
- ページ権限
|
|
||||||
- 権限パーミッション
|
|
||||||
- 権限設定
|
|
||||||
- 外部IDでログイン
|
|
||||||
|
|
||||||
- 複数環境デプロイ
|
|
||||||
- dev
|
|
||||||
- sit
|
|
||||||
- stage
|
|
||||||
- prod
|
|
||||||
|
|
||||||
- 共通機能
|
|
||||||
- 多言語切替
|
|
||||||
- テーマ切替
|
|
||||||
- サイトメニュー(ルートから生成)
|
|
||||||
- パンくずリストナビゲーション
|
|
||||||
- タブナビゲーション
|
|
||||||
- Svg Sprite アイコン
|
|
||||||
- ローカル/バックエンド モック データ
|
|
||||||
- Screenfull
|
|
||||||
|
|
||||||
- WYSIWYG
|
|
||||||
- TinyMCE
|
|
||||||
- Markdown
|
|
||||||
- JSON
|
|
||||||
|
|
||||||
- Excel
|
|
||||||
- エクスポート
|
|
||||||
- インポート
|
|
||||||
- リード
|
|
||||||
- Zip
|
|
||||||
|
|
||||||
- テーブル
|
|
||||||
- ダイナミックテーブル
|
|
||||||
- ドラッグアンドドロップテーブル
|
|
||||||
- インラインエディットテーブル
|
|
||||||
|
|
||||||
- エラーページ
|
|
||||||
- 401
|
|
||||||
- 404
|
|
||||||
|
|
||||||
- コンポーネント
|
|
||||||
- アバターアップロード
|
|
||||||
- トップに戻る
|
|
||||||
- ドラッグダイアログ
|
|
||||||
- ドラッグ選択
|
|
||||||
- ドラッグKanban
|
|
||||||
- ドラッグリスト
|
|
||||||
- ペインの分割
|
|
||||||
- Dropzone
|
|
||||||
- スティッキー
|
|
||||||
- CountTo
|
|
||||||
|
|
||||||
- 高度なサンプル
|
|
||||||
- エラーログ
|
|
||||||
- ダッシュボード
|
|
||||||
- ガイドページ
|
|
||||||
- ECharts
|
|
||||||
- クリップボード
|
|
||||||
- Markdown to html
|
|
||||||
```
|
|
||||||
|
|
||||||
## Getting started
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# clone the project
|
|
||||||
git clone https://github.com/PanJiaChen/vue-element-admin.git
|
|
||||||
|
|
||||||
# enter the project directory
|
|
||||||
cd vue-element-admin
|
|
||||||
|
|
||||||
# install dependency
|
|
||||||
npm install
|
|
||||||
|
|
||||||
# develop
|
|
||||||
npm run dev
|
|
||||||
```
|
|
||||||
|
|
||||||
http://localhost:9527 が自動的に開きます。
|
|
||||||
|
|
||||||
## Build
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# build for test environment
|
|
||||||
npm run build:stage
|
|
||||||
|
|
||||||
# build for production environment
|
|
||||||
npm run build:prod
|
|
||||||
```
|
|
||||||
|
|
||||||
## Advanced
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# preview the release environment effect
|
|
||||||
npm run preview
|
|
||||||
|
|
||||||
# preview the release environment effect + static resource analysis
|
|
||||||
npm run preview -- --report
|
|
||||||
|
|
||||||
# code format check
|
|
||||||
npm run lint
|
|
||||||
|
|
||||||
# code format check and auto fix
|
|
||||||
npm run lint -- --fix
|
|
||||||
```
|
|
||||||
|
|
||||||
詳細は [Documentation](https://panjiachen.github.io/vue-element-admin-site/guide/essentials/deploy.html) を参照してください。
|
|
||||||
|
|
||||||
## Changelog
|
|
||||||
|
|
||||||
各リリースの詳細は [release notes](https://github.com/PanJiaChen/vue-element-admin/releases) にあります。
|
|
||||||
|
|
||||||
## Online Demo
|
|
||||||
|
|
||||||
[Preview](https://panjiachen.github.io/vue-element-admin)
|
|
||||||
|
|
||||||
## Donate
|
|
||||||
|
|
||||||
If you find this project useful, you can buy author a glass of juice :tropical_drink:
|
|
||||||
|
|
||||||
![donate](https://wpimg.wallstcn.com/bd273f0d-83a0-4ef2-92e1-9ac8ed3746b9.png)
|
|
||||||
|
|
||||||
[Paypal Me](https://www.paypal.me/panfree23)
|
|
||||||
|
|
||||||
[Buy me a coffee](https://www.buymeacoffee.com/Pan)
|
|
||||||
|
|
||||||
## 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
|
|
213
README.md
|
@ -4,10 +4,10 @@
|
||||||
|
|
||||||
<p align="center">
|
<p align="center">
|
||||||
<a href="https://github.com/vuejs/vue">
|
<a href="https://github.com/vuejs/vue">
|
||||||
<img src="https://img.shields.io/badge/vue-2.6.10-brightgreen.svg" alt="vue">
|
<img src="https://img.shields.io/badge/vue-2.5.10-brightgreen.svg" alt="vue">
|
||||||
</a>
|
</a>
|
||||||
<a href="https://github.com/ElemeFE/element">
|
<a href="https://github.com/ElemeFE/element">
|
||||||
<img src="https://img.shields.io/badge/element--ui-2.7.0-brightgreen.svg" alt="element-ui">
|
<img src="https://img.shields.io/badge/element--ui-2.0.8-brightgreen.svg" alt="element-ui">
|
||||||
</a>
|
</a>
|
||||||
<a href="https://travis-ci.org/PanJiaChen/vue-element-admin" rel="nofollow">
|
<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">
|
<img src="https://travis-ci.org/PanJiaChen/vue-element-admin.svg?branch=master" alt="Build Status">
|
||||||
|
@ -18,168 +18,86 @@
|
||||||
<a href="https://github.com/PanJiaChen/vue-element-admin/releases">
|
<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">
|
<img src="https://img.shields.io/github/release/PanJiaChen/vue-element-admin.svg" alt="GitHub release">
|
||||||
</a>
|
</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="donate">
|
|
||||||
</a>
|
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
English | [简体中文](./README.zh-CN.md) | [日本語](./README.ja.md) | [Spanish](./README.es.md)
|
English | [简体中文](./README.zh-CN.md)
|
||||||
|
|
||||||
<p align="center">
|
|
||||||
<b>SPONSORED BY</b>
|
|
||||||
</p>
|
|
||||||
<table align="center" cellspacing="0" cellpadding="0">
|
|
||||||
<tbody>
|
|
||||||
<tr>
|
|
||||||
<td align="center" valign="middle" width="250">
|
|
||||||
<a href="https://www.duohui.cn/?utm_source=vue-element-admin&utm_medium=web&utm_campaign=vue-element-admin_github" title="多会" target="_blank">
|
|
||||||
<img height="60px" src="https://qiniu.cdn.duohui.co/brand/duohui.png" title="多会 - 活动服务销售平台">
|
|
||||||
<p>活动服务销售平台</p>
|
|
||||||
</a>
|
|
||||||
</td>
|
|
||||||
<td align="center" valign="middle" width="250">
|
|
||||||
<a href="https://youke.co/?utm_source=vue-element-admin&utm_medium=web&utm_campaign=vue-element-admin_github" title="有客" target="_blank">
|
|
||||||
<img height="60px" src="https://qiniu.cdn.duohui.co/brand/youke.png" title="有客 - 客户消息直达工作群">
|
|
||||||
<p>客户消息直达工作群</p>
|
|
||||||
</a>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
## Introduction
|
## Introduction
|
||||||
|
|
||||||
[vue-element-admin](https://panjiachen.github.io/vue-element-admin) is a production-ready front-end solution for admin interfaces. It is based on [vue](https://github.com/vuejs/vue) and uses the UI Toolkit [element-ui](https://github.com/ElemeFE/element).
|
`vue-element-admin` is a production-ready solution for admin interfaces. Based on [Vue.js](https://github.com/vuejs/vue) and use the UI Toolkit -- [element](https://github.com/ElemeFE/element). `vue-element-admin` is a magical vue admin, it based on the newest development stack of vue, built-in i18n solution, typical templates for enterprise applications, lots of awesome features. It helps you build a large complex Single-Page Applications. I believe whatever your needs are, this project will help you.
|
||||||
|
|
||||||
[vue-element-admin](https://panjiachen.github.io/vue-element-admin) is based on the newest development stack of vue and it has a built-in i18n solution, typical templates for enterprise applications, and lots of awesome features. It helps you build large and complex Single-Page Applications. I believe whatever your needs are, this project will help you.
|
- [Preview](http://panjiachen.github.io/vue-element-admin)
|
||||||
|
|
||||||
- [Preview](https://panjiachen.github.io/vue-element-admin)
|
- [Documentation](https://panjiachen.github.io/vue-element-admin-site/#/)
|
||||||
|
|
||||||
- [Documentation](https://panjiachen.github.io/vue-element-admin-site/)
|
- [wiki](https://github.com/PanJiaChen/vue-element-admin/wiki)
|
||||||
|
|
||||||
- [Gitter](https://gitter.im/vue-element-admin/discuss)
|
- [donate](https://panjiachen.github.io/vue-element-admin-site/#/donate)
|
||||||
|
|
||||||
- [Donate](https://panjiachen.github.io/vue-element-admin-site/donate/)
|
**vue-element-admin is a admin interfaces integration solution, which is not suitable for secondary development as a base template.**
|
||||||
|
|
||||||
- [Wiki](https://github.com/PanJiaChen/vue-element-admin/wiki)
|
- Base template recommends using: [vueAdmin-template](https://github.com/PanJiaChen/vueAdmin-template)
|
||||||
|
- Desktop: [electron-vue-admin](https://github.com/PanJiaChen/electron-vue-admin)
|
||||||
|
|
||||||
- [Gitee](https://panjiachen.gitee.io/vue-element-admin/) 国内用户可访问该地址在线预览
|
**Note: This project uses element-ui@2.0.0+ version, so the minimum compatible vue@2.5.0**
|
||||||
|
|
||||||
- Base template recommends using: [vue-admin-template](https://github.com/PanJiaChen/vue-admin-template)
|
|
||||||
- Desktop: [electron-vue-admin](https://github.com/PanJiaChen/electron-vue-admin)
|
|
||||||
- Typescript: [vue-typescript-admin-template](https://github.com/Armour/vue-typescript-admin-template) (Credits: [@Armour](https://github.com/Armour))
|
|
||||||
- [awesome-project](https://github.com/PanJiaChen/vue-element-admin/issues/2312)
|
|
||||||
|
|
||||||
**After the `v4.1.0+` version, the default master branch will not support i18n. Please use [i18n Branch](https://github.com/PanJiaChen/vue-element-admin/tree/i18n), it will keep up with the master update**
|
|
||||||
|
|
||||||
**The current version is `v4.0+` build on `vue-cli`. If you find a problem, please put [issue](https://github.com/PanJiaChen/vue-element-admin/issues/new). If you want to use the old version , you can switch branch to [tag/3.11.0](https://github.com/PanJiaChen/vue-element-admin/tree/tag/3.11.0), it does not rely on `vue-cli`**
|
|
||||||
|
|
||||||
**This project does not support low version browsers (e.g. IE). Please add polyfill by yourself.**
|
|
||||||
|
|
||||||
## Preparation
|
## Preparation
|
||||||
|
|
||||||
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) , [axios](https://github.com/axios/axios) and [element-ui](https://github.com/ElemeFE/element), all request data is simulated using [Mock.js](https://github.com/nuysoft/Mock).
|
You need to install [node](http://nodejs.org/) and [git](https://git-scm.com/) locally. The project is based on [ES2015+](http://es6.ruanyifeng.com/)、[vue](https://cn.vuejs.org/index.html)、[vuex](https://vuex.vuejs.org/zh-cn/)、[vue-router](https://router.vuejs.org/zh-cn/) 和 [element-ui](https://github.com/ElemeFE/element). All data requests for this project are simulated using [Mock.js](https://github.com/nuysoft/Mock). It would be helpful if you have pre-existing knowledge on those.
|
||||||
Understanding and learning this knowledge in advance will greatly help the use of this project.
|
|
||||||
|
|
||||||
[![Edit on CodeSandbox](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/s/github/PanJiaChen/vue-element-admin/tree/CodeSandbox)
|
**This project is not a scaffolding and is more of an integrated solution.**
|
||||||
|
|
||||||
<p align="center">
|
**This project does not support low version browsers (e.g. IE). Please add polyfill yourself if you need them.**
|
||||||
|
|
||||||
|
<p align="center">
|
||||||
<img width="900" src="https://wpimg.wallstcn.com/a5894c1b-f6af-456e-82df-1151da0839bf.png">
|
<img width="900" src="https://wpimg.wallstcn.com/a5894c1b-f6af-456e-82df-1151da0839bf.png">
|
||||||
</p>
|
</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)
|
|
||||||
|
|
||||||
### Akveo
|
|
||||||
<a href="https://store.akveo.com/products/vue-java-admin-dashboard-spring?utm_campaign=akveo_store-Vue-Vue_demo%2Fgithub&utm_source=vue_admin&utm_medium=referral&utm_content=github_banner"><img width="500px" src="https://raw.githubusercontent.com/PanJiaChen/vue-element-admin-site/master/docs/.vuepress/public/images/vue-java-banner.png" /></a><p>Get Java backend for Vue admin with 20% discount for 39$ use coupon code SWB0RAZPZR1M
|
|
||||||
</p>
|
|
||||||
|
|
||||||
### Flatlogic
|
|
||||||
|
|
||||||
<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>
|
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
```
|
```
|
||||||
- Login / Logout
|
- Login / Logout
|
||||||
|
- Permission authentication
|
||||||
- Permission Authentication
|
|
||||||
- Page permission
|
|
||||||
- Directive permission
|
|
||||||
- Permission configuration page
|
|
||||||
- Two-step login
|
|
||||||
|
|
||||||
- Multi-environment build
|
- Multi-environment build
|
||||||
- Develop (dev)
|
- Dynamic sidebar (supports multi-level routing)
|
||||||
- sit
|
- Dynamic breadcrumb
|
||||||
- Stage Test (stage)
|
- I18n
|
||||||
- Production (prod)
|
- Customizable theme
|
||||||
|
- Tags-view(Tab page Support right-click operation)
|
||||||
- Global Features
|
- Rich text editor
|
||||||
- I18n
|
- Markdown editor
|
||||||
- Multiple dynamic themes
|
- JSON editor
|
||||||
- Dynamic sidebar (supports multi-level routing)
|
- Screenfull
|
||||||
- Dynamic breadcrumb
|
- Drag and drop list
|
||||||
- Tags-view (Tab page Support right-click operation)
|
- Svg Sprite
|
||||||
- Svg Sprite
|
|
||||||
- Mock data
|
|
||||||
- Screenfull
|
|
||||||
- Responsive Sidebar
|
|
||||||
|
|
||||||
- Editor
|
|
||||||
- Rich Text Editor
|
|
||||||
- Markdown Editor
|
|
||||||
- JSON Editor
|
|
||||||
|
|
||||||
- Excel
|
|
||||||
- Export Excel
|
|
||||||
- Upload Excel
|
|
||||||
- Visualization Excel
|
|
||||||
- Export zip
|
|
||||||
|
|
||||||
- Table
|
|
||||||
- Dynamic Table
|
|
||||||
- Drag And Drop Table
|
|
||||||
- Inline Edit Table
|
|
||||||
|
|
||||||
- Error Page
|
|
||||||
- 401
|
|
||||||
- 404
|
|
||||||
|
|
||||||
- Components
|
|
||||||
- Avatar Upload
|
|
||||||
- Back To Top
|
|
||||||
- Drag Dialog
|
|
||||||
- Drag Select
|
|
||||||
- Drag Kanban
|
|
||||||
- Drag List
|
|
||||||
- SplitPane
|
|
||||||
- Dropzone
|
|
||||||
- Sticky
|
|
||||||
- CountTo
|
|
||||||
|
|
||||||
- Advanced Example
|
|
||||||
- Error Log
|
|
||||||
- Dashboard
|
- Dashboard
|
||||||
- Guide Page
|
- Mock data
|
||||||
- ECharts
|
- Echarts
|
||||||
- Clipboard
|
- Clipboard
|
||||||
|
- 401/404 error page
|
||||||
|
- Error log
|
||||||
|
- Export excel
|
||||||
|
- Export zip
|
||||||
|
- Front-end visualization excel
|
||||||
|
- Tree Table
|
||||||
|
- Table example
|
||||||
|
- Dynamictable example
|
||||||
|
- Drag and drop table example
|
||||||
|
- Inline edit table example
|
||||||
|
- Form example
|
||||||
|
- Two-step login
|
||||||
|
- SplitPane
|
||||||
|
- Dropzone
|
||||||
|
- Sticky
|
||||||
|
- CountTo
|
||||||
- Markdown to html
|
- Markdown to html
|
||||||
```
|
```
|
||||||
|
|
||||||
## Getting started
|
## Getting started
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# clone the project
|
# clone the projice
|
||||||
git clone https://github.com/PanJiaChen/vue-element-admin.git
|
git clone https://github.com/PanJiaChen/vue-element-admin.git
|
||||||
|
|
||||||
# enter the project directory
|
|
||||||
cd vue-element-admin
|
|
||||||
|
|
||||||
# install dependency
|
# install dependency
|
||||||
npm install
|
npm install
|
||||||
|
|
||||||
|
@ -187,62 +105,47 @@ npm install
|
||||||
npm run dev
|
npm run dev
|
||||||
```
|
```
|
||||||
|
|
||||||
This will automatically open http://localhost:9527
|
This will automatically open http://localhost:9527.
|
||||||
|
|
||||||
## Build
|
## Build
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# build for test environment
|
# build for test environment
|
||||||
npm run build:stage
|
npm run build:sit
|
||||||
|
|
||||||
# build for production environment
|
# build for production environment
|
||||||
npm run build:prod
|
npm run build:prod
|
||||||
```
|
```
|
||||||
|
|
||||||
## Advanced
|
## Advanced
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# preview the release environment effect
|
# --report to build with bundle size analytics
|
||||||
npm run preview
|
npm run build:prod --report
|
||||||
|
|
||||||
# preview the release environment effect + static resource analysis
|
# --preview to start a server in local to preview
|
||||||
npm run preview -- --report
|
npm run build:prod --preview
|
||||||
|
|
||||||
# code format check
|
# lint code
|
||||||
npm run lint
|
npm run lint
|
||||||
|
|
||||||
# code format check and auto fix
|
# auto fix
|
||||||
npm run lint -- --fix
|
npm run lint -- --fix
|
||||||
```
|
```
|
||||||
|
|
||||||
Refer to [Documentation](https://panjiachen.github.io/vue-element-admin-site/guide/essentials/deploy.html) for more information
|
Refer to [Documentation](https://panjiachen.github.io/vue-element-admin-site/#/deploy) for more information
|
||||||
|
|
||||||
## Changelog
|
## Changelog
|
||||||
|
|
||||||
Detailed changes for each release are documented in the [release notes](https://github.com/PanJiaChen/vue-element-admin/releases).
|
Detailed changes for each release are documented in the [release notes](https://github.com/PanJiaChen/vue-element-admin/releases).
|
||||||
|
|
||||||
## Online Demo
|
## Online Demo
|
||||||
|
[Preview](http://panjiachen.github.io/vue-element-admin)
|
||||||
[Preview](https://panjiachen.github.io/vue-element-admin)
|
|
||||||
|
|
||||||
## Donate
|
## Donate
|
||||||
|
|
||||||
If you find this project useful, you can buy author a glass of juice :tropical_drink:
|
If you find this project useful, you can buy author a glass of juice :tropical_drink:
|
||||||
|
|
||||||
![donate](https://wpimg.wallstcn.com/bd273f0d-83a0-4ef2-92e1-9ac8ed3746b9.png)
|
![donate](https://wpimg.wallstcn.com/bd273f0d-83a0-4ef2-92e1-9ac8ed3746b9.png)
|
||||||
|
|
||||||
[Paypal Me](https://www.paypal.me/panfree23)
|
[Paypal Me](https://www.paypal.me/panfree23)
|
||||||
|
|
||||||
[Buy me a coffee](https://www.buymeacoffee.com/Pan)
|
|
||||||
|
|
||||||
## 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
|
## License
|
||||||
|
|
||||||
[MIT](https://github.com/PanJiaChen/vue-element-admin/blob/master/LICENSE)
|
[MIT](https://github.com/PanJiaChen/vue-element-admin/blob/master/LICENSE)
|
||||||
|
|
247
README.zh-CN.md
|
@ -4,10 +4,10 @@
|
||||||
|
|
||||||
<p align="center">
|
<p align="center">
|
||||||
<a href="https://github.com/vuejs/vue">
|
<a href="https://github.com/vuejs/vue">
|
||||||
<img src="https://img.shields.io/badge/vue-2.6.10-brightgreen.svg" alt="vue">
|
<img src="https://img.shields.io/badge/vue-2.5.10-brightgreen.svg" alt="vue">
|
||||||
</a>
|
</a>
|
||||||
<a href="https://github.com/ElemeFE/element">
|
<a href="https://github.com/ElemeFE/element">
|
||||||
<img src="https://img.shields.io/badge/element--ui-2.7.0-brightgreen.svg" alt="element-ui">
|
<img src="https://img.shields.io/badge/element--ui-2.0.8-brightgreen.svg" alt="element-ui">
|
||||||
</a>
|
</a>
|
||||||
<a href="https://travis-ci.org/PanJiaChen/vue-element-admin" rel="nofollow">
|
<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">
|
<img src="https://travis-ci.org/PanJiaChen/vue-element-admin.svg?branch=master" alt="Build Status">
|
||||||
|
@ -18,254 +18,147 @@
|
||||||
<a href="https://github.com/PanJiaChen/vue-element-admin/releases">
|
<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">
|
<img src="https://img.shields.io/github/release/PanJiaChen/vue-element-admin.svg" alt="GitHub release">
|
||||||
</a>
|
</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>
|
</p>
|
||||||
|
|
||||||
简体中文 | [English](./README.md) | [日本語](./README.ja.md) | [Spanish](./README.es.md)
|
简体中文 | [English](./README.md)
|
||||||
|
|
||||||
<p align="center">
|
|
||||||
<b>SPONSORED BY</b>
|
|
||||||
</p>
|
|
||||||
<table align="center" cellspacing="0" cellpadding="0">
|
|
||||||
<tbody>
|
|
||||||
<tr>
|
|
||||||
<td align="center" valign="middle" width="250">
|
|
||||||
<a href="https://www.duohui.cn/?utm_source=vue-element-admin&utm_medium=web&utm_campaign=vue-element-admin_github" title="多会" target="_blank">
|
|
||||||
<img height="60px" src="https://qiniu.cdn.duohui.co/brand/duohui.png" title="多会 - 活动服务销售平台">
|
|
||||||
<p>活动服务销售平台</p>
|
|
||||||
</a>
|
|
||||||
</td>
|
|
||||||
<td align="center" valign="middle" width="250">
|
|
||||||
<a href="https://youke.co/?utm_source=vue-element-admin&utm_medium=web&utm_campaign=vue-element-admin_github" title="有客" target="_blank">
|
|
||||||
<img height="60px" src="https://qiniu.cdn.duohui.co/brand/youke.png" title="有客 - 客户消息直达工作群">
|
|
||||||
<p>客户消息直达工作群</p>
|
|
||||||
</a>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
## 简介
|
## 简介
|
||||||
|
|
||||||
[vue-element-admin](https://panjiachen.github.io/vue-element-admin) 是一个后台前端解决方案,它基于 [vue](https://github.com/vuejs/vue) 和 [element-ui](https://github.com/ElemeFE/element)实现。它使用了最新的前端技术栈,内置了 i18n 国际化解决方案,动态路由,权限验证,提炼了典型的业务模型,提供了丰富的功能组件,它可以帮助你快速搭建企业级中后台产品原型。相信不管你的需求是什么,本项目都能帮助到你。
|
`vue-element-admin` 是一个后台集成解决方案,它基于 [Vue.js](https://github.com/vuejs/vue) 和 [element](https://github.com/ElemeFE/element)。它使用了最新的前端技术栈,内置了i18国际化解决方案,动态路由,权限验证等很多功能特性,相信不管你的需求是什么,本项目都能帮助到你。
|
||||||
|
|
||||||
- [在线预览](https://panjiachen.github.io/vue-element-admin)
|
- [在线访问](http://panjiachen.github.io/vue-element-admin)
|
||||||
|
|
||||||
- [使用文档](https://panjiachen.github.io/vue-element-admin-site/zh/)
|
- [使用文档](https://panjiachen.github.io/vue-element-admin-site/#/)
|
||||||
|
|
||||||
- [Gitter 讨论组](https://gitter.im/vue-element-admin/discuss)
|
- [wiki](https://github.com/PanJiaChen/vue-element-admin/wiki)
|
||||||
|
|
||||||
- [Donate](https://panjiachen.gitee.io/vue-element-admin-site/zh/donate)
|
- [donate](https://panjiachen.github.io/vue-element-admin-site/#/donate)
|
||||||
|
|
||||||
- [Wiki](https://github.com/PanJiaChen/vue-element-admin/wiki)
|
**本项目的定位是后台集成方案,不适合当基础模板来开发。**
|
||||||
|
- 模板建议使用: [vueAdmin-template](https://github.com/PanJiaChen/vueAdmin-template)
|
||||||
|
- 桌面端: [electron-vue-admin](https://github.com/PanJiaChen/electron-vue-admin)
|
||||||
|
|
||||||
- [Gitee](https://panjiachen.gitee.io/vue-element-admin/) 在线预览(国内用户可访问该地址)
|
**注意:该项目使用 element-ui@2.0.0+ 版本,所以最低兼容 vue@2.5.0**
|
||||||
|
|
||||||
- [国内访问文档](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)进行模拟,提前了解和学习这些知识会对使用本项目有很大的帮助。
|
你的本地环境需要安装 [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/) and [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 component](https://segmentfault.com/a/1190000009090836)
|
||||||
|
- [手摸手,带你优雅的使用 icon](https://juejin.im/post/59bb864b5188257e7a427c09)
|
||||||
|
|
||||||
- [手摸手,带你用 vue 撸后台 系列一(基础篇)](https://juejin.im/post/59097cd7a22b9d0065fb61d2)
|
响应需求,开了一个qq群 `591724180` 方便大家交流
|
||||||
- [手摸手,带你用 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**
|
或者加入该群主 **[圈子](https://jianshiapp.com/circles/1209)** 楼主会经常分享一些技术相关的东西
|
||||||
|
|
||||||
[![Edit on CodeSandbox](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/s/github/PanJiaChen/vue-element-admin/tree/CodeSandbox)
|
**如有问题请先看上述使用文档和文章,若不能满足,欢迎 issue 和 pr**
|
||||||
|
|
||||||
<p align="center">
|
**本项目并不是一个脚手架,更倾向于是一个集成解决方案**
|
||||||
|
|
||||||
|
**该项目不支持低版本浏览器(如ie),有需求请自行添加polyfill [详情](https://github.com/PanJiaChen/vue-element-admin/wiki#babel-polyfill)**
|
||||||
|
|
||||||
|
<p align="center">
|
||||||
<img width="900" src="https://wpimg.wallstcn.com/a5894c1b-f6af-456e-82df-1151da0839bf.png">
|
<img width="900" src="https://wpimg.wallstcn.com/a5894c1b-f6af-456e-82df-1151da0839bf.png">
|
||||||
</p>
|
</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)
|
|
||||||
|
|
||||||
### Akveo
|
|
||||||
<a href="https://store.akveo.com/products/vue-java-admin-dashboard-spring?utm_campaign=akveo_store-Vue-Vue_demo%2Fgithub&utm_source=vue_admin&utm_medium=referral&utm_content=github_banner"><img width="500px" src="https://raw.githubusercontent.com/PanJiaChen/vue-element-admin-site/master/docs/.vuepress/public/images/vue-java-banner.png" /></a><p>Java 后端整合,可以使用优惠码:SWB0RAZPZR1M,获得20%的价格优化</p>
|
|
||||||
|
|
||||||
### Flatlogic
|
|
||||||
|
|
||||||
<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
|
- 多种动态换肤
|
||||||
|
- 快捷导航(标签页)
|
||||||
- 全局功能
|
- 富文本编辑器
|
||||||
- 国际化多语言
|
- Markdown编辑器
|
||||||
- 多种动态换肤
|
- JSON编辑器
|
||||||
- 动态侧边栏(支持多级路由嵌套)
|
- Screenfull全屏
|
||||||
- 动态面包屑
|
- 列表拖拽
|
||||||
- 快捷导航(标签页)
|
- Svg Sprite 图标
|
||||||
- Svg Sprite 图标
|
|
||||||
- 本地/后端 mock 数据
|
|
||||||
- Screenfull全屏
|
|
||||||
- 自适应收缩侧边栏
|
|
||||||
|
|
||||||
- 编辑器
|
|
||||||
- 富文本
|
|
||||||
- Markdown
|
|
||||||
- JSON 等多格式
|
|
||||||
|
|
||||||
- Excel
|
|
||||||
- 导出excel
|
|
||||||
- 导入excel
|
|
||||||
- 前端可视化excel
|
|
||||||
- 导出zip
|
|
||||||
|
|
||||||
- 表格
|
|
||||||
- 动态表格
|
|
||||||
- 拖拽表格
|
|
||||||
- 内联编辑
|
|
||||||
|
|
||||||
- 错误页面
|
|
||||||
- 401
|
|
||||||
- 404
|
|
||||||
|
|
||||||
- 組件
|
|
||||||
- 头像上传
|
|
||||||
- 返回顶部
|
|
||||||
- 拖拽Dialog
|
|
||||||
- 拖拽Select
|
|
||||||
- 拖拽看板
|
|
||||||
- 列表拖拽
|
|
||||||
- SplitPane
|
|
||||||
- Dropzone
|
|
||||||
- Sticky
|
|
||||||
- CountTo
|
|
||||||
|
|
||||||
- 综合实例
|
|
||||||
- 错误日志
|
|
||||||
- Dashboard
|
- Dashboard
|
||||||
- 引导页
|
- 本地mock数据
|
||||||
- ECharts 图表
|
- Echarts 图表
|
||||||
- Clipboard(剪贴复制)
|
- Clipboard(剪贴复制)
|
||||||
|
- 401/404错误页面
|
||||||
|
- 错误日志
|
||||||
|
- 导出excel
|
||||||
|
- 导出zip
|
||||||
|
- 前端可视化excel
|
||||||
|
- 树形table
|
||||||
|
- Table example
|
||||||
|
- 动态table example
|
||||||
|
- 拖拽table example
|
||||||
|
- 内联编辑table example
|
||||||
|
- Form example
|
||||||
|
- 二步登录
|
||||||
|
- SplitPane
|
||||||
|
- Dropzone
|
||||||
|
- Sticky
|
||||||
|
- CountTo
|
||||||
- Markdown2html
|
- Markdown2html
|
||||||
```
|
```
|
||||||
|
|
||||||
## 开发
|
## 开发
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# 克隆项目
|
# 克隆项目
|
||||||
git clone https://github.com/PanJiaChen/vue-element-admin.git
|
git clone https://github.com/PanJiaChen/vue-element-admin.git
|
||||||
|
|
||||||
# 进入项目目录
|
|
||||||
cd vue-element-admin
|
|
||||||
|
|
||||||
# 安装依赖
|
# 安装依赖
|
||||||
npm install
|
npm install
|
||||||
|
|
||||||
# 建议不要直接使用 cnpm 安装依赖,会有各种诡异的 bug。可以通过如下操作解决 npm 下载速度慢的问题
|
# 建议不要用cnpm安装 会有各种诡异的bug 可以通过如下操作解决 npm 下载速度慢的问题
|
||||||
npm install --registry=https://registry.npm.taobao.org
|
npm install --registry=https://registry.npm.taobao.org
|
||||||
|
|
||||||
# 启动服务
|
# 启动服务
|
||||||
npm run dev
|
npm run dev
|
||||||
```
|
```
|
||||||
|
|
||||||
浏览器访问 http://localhost:9527
|
浏览器访问 http://localhost:9527
|
||||||
|
|
||||||
## 发布
|
## 发布
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# 构建测试环境
|
# 构建测试环境
|
||||||
npm run build:stage
|
npm run build:sit
|
||||||
|
|
||||||
# 构建生产环境
|
# 构建生成环境
|
||||||
npm run build:prod
|
npm run build:prod
|
||||||
```
|
```
|
||||||
|
|
||||||
## 其它
|
## 其它
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# 预览发布环境效果
|
# --report to build with bundle size analytics
|
||||||
npm run preview
|
npm run build:prod --report
|
||||||
|
|
||||||
# 预览发布环境效果 + 静态资源分析
|
# --preview to start a server in local to preview
|
||||||
npm run preview -- --report
|
npm run build:prod --preview
|
||||||
|
|
||||||
# 代码格式检查
|
# lint code
|
||||||
npm run lint
|
npm run lint
|
||||||
|
|
||||||
# 代码格式检查并自动修复
|
# auto fix
|
||||||
npm run lint -- --fix
|
npm run lint -- --fix
|
||||||
```
|
```
|
||||||
|
|
||||||
更多信息请参考 [使用文档](https://panjiachen.github.io/vue-element-admin-site/zh/)
|
更多信息请参考 [使用文档](https://panjiachen.github.io/vue-element-admin-site/#/deploy)
|
||||||
|
|
||||||
## Changelog
|
## Changelog
|
||||||
|
|
||||||
Detailed changes for each release are documented in the [release notes](https://github.com/PanJiaChen/vue-element-admin/releases).
|
Detailed changes for each release are documented in the [release notes](https://github.com/PanJiaChen/vue-element-admin/releases).
|
||||||
|
|
||||||
## Online Demo
|
## Online Demo
|
||||||
|
[在线 Demo](http://panjiachen.github.io/vue-element-admin)
|
||||||
[在线 Demo](https://panjiachen.github.io/vue-element-admin)
|
|
||||||
|
|
||||||
## Donate
|
## Donate
|
||||||
|
|
||||||
如果你觉得这个项目帮助到了你,你可以帮作者买一杯果汁表示鼓励 :tropical_drink:
|
如果你觉得这个项目帮助到了你,你可以帮作者买一杯果汁表示鼓励 :tropical_drink:
|
||||||
![donate](https://panjiachen.github.io/donate/donation.png)
|
![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)
|
[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
|
## License
|
||||||
|
|
||||||
[MIT](https://github.com/PanJiaChen/vue-element-admin/blob/master/LICENSE)
|
[MIT](https://github.com/PanJiaChen/vue-element-admin/blob/master/LICENSE)
|
||||||
|
|
|
@ -1,14 +0,0 @@
|
||||||
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,48 @@
|
||||||
|
'use strict'
|
||||||
|
require('./check-versions')()
|
||||||
|
|
||||||
|
const ora = require('ora')
|
||||||
|
const rm = require('rimraf')
|
||||||
|
const path = require('path')
|
||||||
|
const chalk = require('chalk')
|
||||||
|
const webpack = require('webpack')
|
||||||
|
const config = require('../config')
|
||||||
|
const webpackConfig = require('./webpack.prod.conf')
|
||||||
|
const server = require('pushstate-server')
|
||||||
|
|
||||||
|
var spinner = ora('building for '+ process.env.env_config+ ' environment...' )
|
||||||
|
spinner.start()
|
||||||
|
|
||||||
|
rm(path.join(config.build.assetsRoot, config.build.assetsSubDirectory), err => {
|
||||||
|
if (err) throw err
|
||||||
|
webpack(webpackConfig, (err, stats) => {
|
||||||
|
spinner.stop()
|
||||||
|
if (err) throw err
|
||||||
|
process.stdout.write(stats.toString({
|
||||||
|
colors: true,
|
||||||
|
modules: false,
|
||||||
|
children: false,
|
||||||
|
chunks: false,
|
||||||
|
chunkModules: false
|
||||||
|
}) + '\n\n')
|
||||||
|
|
||||||
|
if (stats.hasErrors()) {
|
||||||
|
console.log(chalk.red(' Build failed with errors.\n'))
|
||||||
|
process.exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(chalk.cyan(' Build complete.\n'))
|
||||||
|
console.log(chalk.yellow(
|
||||||
|
' Tip: built files are meant to be served over an HTTP server.\n' +
|
||||||
|
' Opening index.html over file:// won\'t work.\n'
|
||||||
|
))
|
||||||
|
if(process.env.npm_config_preview){
|
||||||
|
server.start({
|
||||||
|
port: 9526,
|
||||||
|
directory: './dist',
|
||||||
|
file: '/index.html'
|
||||||
|
});
|
||||||
|
console.log('> Listening at ' + 'http://localhost:9526' + '\n')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
|
@ -0,0 +1,54 @@
|
||||||
|
'use strict'
|
||||||
|
const chalk = require('chalk')
|
||||||
|
const semver = require('semver')
|
||||||
|
const packageConfig = require('../package.json')
|
||||||
|
const shell = require('shelljs')
|
||||||
|
|
||||||
|
function exec (cmd) {
|
||||||
|
return require('child_process').execSync(cmd).toString().trim()
|
||||||
|
}
|
||||||
|
|
||||||
|
const versionRequirements = [
|
||||||
|
{
|
||||||
|
name: 'node',
|
||||||
|
currentVersion: semver.clean(process.version),
|
||||||
|
versionRequirement: packageConfig.engines.node
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
if (shell.which('npm')) {
|
||||||
|
versionRequirements.push({
|
||||||
|
name: 'npm',
|
||||||
|
currentVersion: exec('npm --version'),
|
||||||
|
versionRequirement: packageConfig.engines.npm
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = function () {
|
||||||
|
const warnings = []
|
||||||
|
|
||||||
|
for (let i = 0; i < versionRequirements.length; i++) {
|
||||||
|
const mod = versionRequirements[i]
|
||||||
|
|
||||||
|
if (!semver.satisfies(mod.currentVersion, mod.versionRequirement)) {
|
||||||
|
warnings.push(mod.name + ': ' +
|
||||||
|
chalk.red(mod.currentVersion) + ' should be ' +
|
||||||
|
chalk.green(mod.versionRequirement)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (warnings.length) {
|
||||||
|
console.log('')
|
||||||
|
console.log(chalk.yellow('To use this template, you must update following to modules:'))
|
||||||
|
console.log()
|
||||||
|
|
||||||
|
for (let i = 0; i < warnings.length; i++) {
|
||||||
|
const warning = warnings[i]
|
||||||
|
console.log(' ' + warning)
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log()
|
||||||
|
process.exit(1)
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,35 +0,0 @@
|
||||||
const { run } = require('runjs')
|
|
||||||
const chalk = require('chalk')
|
|
||||||
const config = require('../vue.config.js')
|
|
||||||
const rawArgv = process.argv.slice(2)
|
|
||||||
const args = rawArgv.join(' ')
|
|
||||||
|
|
||||||
if (process.env.npm_config_preview || rawArgv.includes('--preview')) {
|
|
||||||
const report = rawArgv.includes('--report')
|
|
||||||
|
|
||||||
run(`vue-cli-service build ${args}`)
|
|
||||||
|
|
||||||
const port = 9526
|
|
||||||
const publicPath = config.publicPath
|
|
||||||
|
|
||||||
var connect = require('connect')
|
|
||||||
var serveStatic = require('serve-static')
|
|
||||||
const app = connect()
|
|
||||||
|
|
||||||
app.use(
|
|
||||||
publicPath,
|
|
||||||
serveStatic('./dist', {
|
|
||||||
index: ['index.html', '/']
|
|
||||||
})
|
|
||||||
)
|
|
||||||
|
|
||||||
app.listen(port, function () {
|
|
||||||
console.log(chalk.green(`> Preview at http://localhost:${port}${publicPath}`))
|
|
||||||
if (report) {
|
|
||||||
console.log(chalk.green(`> Report at http://localhost:${port}${publicPath}report.html`))
|
|
||||||
}
|
|
||||||
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
run(`vue-cli-service build ${args}`)
|
|
||||||
}
|
|
After Width: | Height: | Size: 6.7 KiB |
|
@ -0,0 +1,101 @@
|
||||||
|
'use strict'
|
||||||
|
const path = require('path')
|
||||||
|
const config = require('../config')
|
||||||
|
const ExtractTextPlugin = require('extract-text-webpack-plugin')
|
||||||
|
const packageConfig = require('../package.json')
|
||||||
|
|
||||||
|
exports.assetsPath = function (_path) {
|
||||||
|
const assetsSubDirectory = process.env.NODE_ENV === 'production'
|
||||||
|
? config.build.assetsSubDirectory
|
||||||
|
: config.dev.assetsSubDirectory
|
||||||
|
|
||||||
|
return path.posix.join(assetsSubDirectory, _path)
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.cssLoaders = function (options) {
|
||||||
|
options = options || {}
|
||||||
|
|
||||||
|
const cssLoader = {
|
||||||
|
loader: 'css-loader',
|
||||||
|
options: {
|
||||||
|
sourceMap: options.sourceMap
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const postcssLoader = {
|
||||||
|
loader: 'postcss-loader',
|
||||||
|
options: {
|
||||||
|
sourceMap: options.sourceMap
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// generate loader string to be used with extract text plugin
|
||||||
|
function generateLoaders (loader, loaderOptions) {
|
||||||
|
const loaders = options.usePostCSS ? [cssLoader, postcssLoader] : [cssLoader]
|
||||||
|
|
||||||
|
if (loader) {
|
||||||
|
loaders.push({
|
||||||
|
loader: loader + '-loader',
|
||||||
|
options: Object.assign({}, loaderOptions, {
|
||||||
|
sourceMap: options.sourceMap
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract CSS when that option is specified
|
||||||
|
// (which is the case during production build)
|
||||||
|
if (options.extract) {
|
||||||
|
return ExtractTextPlugin.extract({
|
||||||
|
use: loaders,
|
||||||
|
fallback: 'vue-style-loader'
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
return ['vue-style-loader'].concat(loaders)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://vue-loader.vuejs.org/en/configurations/extract-css.html
|
||||||
|
return {
|
||||||
|
css: generateLoaders(),
|
||||||
|
postcss: generateLoaders(),
|
||||||
|
less: generateLoaders('less'),
|
||||||
|
sass: generateLoaders('sass', { indentedSyntax: true }),
|
||||||
|
scss: generateLoaders('sass'),
|
||||||
|
stylus: generateLoaders('stylus'),
|
||||||
|
styl: generateLoaders('stylus')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate loaders for standalone style files (outside of .vue)
|
||||||
|
exports.styleLoaders = function (options) {
|
||||||
|
const output = []
|
||||||
|
const loaders = exports.cssLoaders(options)
|
||||||
|
|
||||||
|
for (const extension in loaders) {
|
||||||
|
const loader = loaders[extension]
|
||||||
|
output.push({
|
||||||
|
test: new RegExp('\\.' + extension + '$'),
|
||||||
|
use: loader
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return output
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.createNotifierCallback = () => {
|
||||||
|
const notifier = require('node-notifier')
|
||||||
|
|
||||||
|
return (severity, errors) => {
|
||||||
|
if (severity !== 'error') return
|
||||||
|
|
||||||
|
const error = errors[0]
|
||||||
|
const filename = error.file && error.file.split('!').pop()
|
||||||
|
|
||||||
|
notifier.notify({
|
||||||
|
title: packageConfig.name,
|
||||||
|
message: severity + ': ' + error.name,
|
||||||
|
subtitle: filename || '',
|
||||||
|
icon: path.join(__dirname, 'logo.png')
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,22 @@
|
||||||
|
'use strict'
|
||||||
|
const utils = require('./utils')
|
||||||
|
const config = require('../config')
|
||||||
|
const isProduction = process.env.NODE_ENV === 'production'
|
||||||
|
const sourceMapEnabled = isProduction
|
||||||
|
? config.build.productionSourceMap
|
||||||
|
: config.dev.cssSourceMap
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
loaders: utils.cssLoaders({
|
||||||
|
sourceMap: sourceMapEnabled,
|
||||||
|
extract: isProduction
|
||||||
|
}),
|
||||||
|
cssSourceMap: sourceMapEnabled,
|
||||||
|
cacheBusting: config.dev.cacheBusting,
|
||||||
|
transformToRequire: {
|
||||||
|
video: ['src', 'poster'],
|
||||||
|
source: 'src',
|
||||||
|
img: 'src',
|
||||||
|
image: 'xlink:href'
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,101 @@
|
||||||
|
'use strict'
|
||||||
|
const path = require('path')
|
||||||
|
const utils = require('./utils')
|
||||||
|
const config = require('../config')
|
||||||
|
const vueLoaderConfig = require('./vue-loader.conf')
|
||||||
|
|
||||||
|
function resolve (dir) {
|
||||||
|
return path.join(__dirname, '..', dir)
|
||||||
|
}
|
||||||
|
|
||||||
|
const createLintingRule = () => ({
|
||||||
|
test: /\.(js|vue)$/,
|
||||||
|
loader: 'eslint-loader',
|
||||||
|
enforce: 'pre',
|
||||||
|
include: [resolve('src'), resolve('test')],
|
||||||
|
options: {
|
||||||
|
formatter: require('eslint-friendly-formatter'),
|
||||||
|
emitWarning: !config.dev.showEslintErrorsInOverlay
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
context: path.resolve(__dirname, '../'),
|
||||||
|
entry: {
|
||||||
|
app: './src/main.js'
|
||||||
|
},
|
||||||
|
output: {
|
||||||
|
path: config.build.assetsRoot,
|
||||||
|
filename: '[name].js',
|
||||||
|
publicPath: process.env.NODE_ENV === 'production'
|
||||||
|
? config.build.assetsPublicPath
|
||||||
|
: config.dev.assetsPublicPath
|
||||||
|
},
|
||||||
|
resolve: {
|
||||||
|
extensions: ['.js', '.vue', '.json'],
|
||||||
|
alias: {
|
||||||
|
'vue$': 'vue/dist/vue.esm.js',
|
||||||
|
'@': resolve('src'),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
module: {
|
||||||
|
rules: [
|
||||||
|
...(config.dev.useEslint ? [createLintingRule()] : []),
|
||||||
|
{
|
||||||
|
test: /\.vue$/,
|
||||||
|
loader: 'vue-loader',
|
||||||
|
options: vueLoaderConfig
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: /\.js$/,
|
||||||
|
loader: 'babel-loader?cacheDirectory',
|
||||||
|
include: [resolve('src'), resolve('test'), resolve('node_modules/webpack-dev-server/client')]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: /\.svg$/,
|
||||||
|
loader: 'svg-sprite-loader',
|
||||||
|
include: [resolve('src/icons')],
|
||||||
|
options: {
|
||||||
|
symbolId: 'icon-[name]'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
|
||||||
|
loader: 'url-loader',
|
||||||
|
exclude: [resolve('src/icons')],
|
||||||
|
options: {
|
||||||
|
limit: 10000,
|
||||||
|
name: utils.assetsPath('img/[name].[hash:7].[ext]')
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/,
|
||||||
|
loader: 'url-loader',
|
||||||
|
options: {
|
||||||
|
limit: 10000,
|
||||||
|
name: utils.assetsPath('media/[name].[hash:7].[ext]')
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
|
||||||
|
loader: 'url-loader',
|
||||||
|
options: {
|
||||||
|
limit: 10000,
|
||||||
|
name: utils.assetsPath('fonts/[name].[hash:7].[ext]')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
node: {
|
||||||
|
// prevent webpack from injecting useless setImmediate polyfill because Vue
|
||||||
|
// source contains it (although only uses it if it's native).
|
||||||
|
setImmediate: false,
|
||||||
|
// prevent webpack from injecting mocks to Node native modules
|
||||||
|
// that does not make sense for the client
|
||||||
|
dgram: 'empty',
|
||||||
|
fs: 'empty',
|
||||||
|
net: 'empty',
|
||||||
|
tls: 'empty',
|
||||||
|
child_process: 'empty'
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,88 @@
|
||||||
|
'use strict'
|
||||||
|
const path = require('path')
|
||||||
|
const utils = require('./utils')
|
||||||
|
const webpack = require('webpack')
|
||||||
|
const config = require('../config')
|
||||||
|
const merge = require('webpack-merge')
|
||||||
|
const baseWebpackConfig = require('./webpack.base.conf')
|
||||||
|
const HtmlWebpackPlugin = require('html-webpack-plugin')
|
||||||
|
const FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin')
|
||||||
|
const portfinder = require('portfinder')
|
||||||
|
|
||||||
|
function resolve (dir) {
|
||||||
|
return path.join(__dirname, '..', dir)
|
||||||
|
}
|
||||||
|
|
||||||
|
const HOST = process.env.HOST
|
||||||
|
const PORT = process.env.PORT && Number(process.env.PORT)
|
||||||
|
|
||||||
|
const devWebpackConfig = merge(baseWebpackConfig, {
|
||||||
|
module: {
|
||||||
|
rules: utils.styleLoaders({ sourceMap: config.dev.cssSourceMap, usePostCSS: true })
|
||||||
|
},
|
||||||
|
// cheap-module-eval-source-map is faster for development
|
||||||
|
devtool: config.dev.devtool,
|
||||||
|
|
||||||
|
// these devServer options should be customized in /config/index.js
|
||||||
|
devServer: {
|
||||||
|
clientLogLevel: 'warning',
|
||||||
|
historyApiFallback: true,
|
||||||
|
hot: true,
|
||||||
|
compress: true,
|
||||||
|
host: HOST || config.dev.host,
|
||||||
|
port: PORT || config.dev.port,
|
||||||
|
open: config.dev.autoOpenBrowser,
|
||||||
|
overlay: config.dev.errorOverlay
|
||||||
|
? { warnings: false, errors: true }
|
||||||
|
: false,
|
||||||
|
publicPath: config.dev.assetsPublicPath,
|
||||||
|
proxy: config.dev.proxyTable,
|
||||||
|
quiet: true, // necessary for FriendlyErrorsPlugin
|
||||||
|
watchOptions: {
|
||||||
|
poll: config.dev.poll,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
plugins: [
|
||||||
|
new webpack.DefinePlugin({
|
||||||
|
'process.env': require('../config/dev.env')
|
||||||
|
}),
|
||||||
|
new webpack.HotModuleReplacementPlugin(),
|
||||||
|
new webpack.NamedModulesPlugin(), // HMR shows correct file names in console on update.
|
||||||
|
new webpack.NoEmitOnErrorsPlugin(),
|
||||||
|
// https://github.com/ampedandwired/html-webpack-plugin
|
||||||
|
new HtmlWebpackPlugin({
|
||||||
|
filename: 'index.html',
|
||||||
|
template: 'index.html',
|
||||||
|
inject: true,
|
||||||
|
favicon: resolve('favicon.ico'),
|
||||||
|
title: 'vue-element-admin',
|
||||||
|
path: config.dev.assetsPublicPath + config.dev.assetsSubDirectory
|
||||||
|
}),
|
||||||
|
]
|
||||||
|
})
|
||||||
|
|
||||||
|
module.exports = new Promise((resolve, reject) => {
|
||||||
|
portfinder.basePort = process.env.PORT || config.dev.port
|
||||||
|
portfinder.getPort((err, port) => {
|
||||||
|
if (err) {
|
||||||
|
reject(err)
|
||||||
|
} else {
|
||||||
|
// publish the new Port, necessary for e2e tests
|
||||||
|
process.env.PORT = port
|
||||||
|
// add port to devServer config
|
||||||
|
devWebpackConfig.devServer.port = port
|
||||||
|
|
||||||
|
// Add FriendlyErrorsPlugin
|
||||||
|
devWebpackConfig.plugins.push(new FriendlyErrorsPlugin({
|
||||||
|
compilationSuccessInfo: {
|
||||||
|
messages: [`Your application is running here: http://${devWebpackConfig.devServer.host}:${port}`],
|
||||||
|
},
|
||||||
|
onErrors: config.dev.notifyOnErrors
|
||||||
|
? utils.createNotifierCallback()
|
||||||
|
: undefined
|
||||||
|
}))
|
||||||
|
|
||||||
|
resolve(devWebpackConfig)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
|
@ -0,0 +1,175 @@
|
||||||
|
'use strict'
|
||||||
|
const path = require('path')
|
||||||
|
const utils = require('./utils')
|
||||||
|
const webpack = require('webpack')
|
||||||
|
const config = require('../config')
|
||||||
|
const merge = require('webpack-merge')
|
||||||
|
const baseWebpackConfig = require('./webpack.base.conf')
|
||||||
|
const CopyWebpackPlugin = require('copy-webpack-plugin')
|
||||||
|
const HtmlWebpackPlugin = require('html-webpack-plugin')
|
||||||
|
const ExtractTextPlugin = require('extract-text-webpack-plugin')
|
||||||
|
const OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin')
|
||||||
|
const UglifyJsPlugin = require('uglifyjs-webpack-plugin')
|
||||||
|
|
||||||
|
function resolve (dir) {
|
||||||
|
return path.join(__dirname, '..', dir)
|
||||||
|
}
|
||||||
|
|
||||||
|
const env = require('../config/'+process.env.env_config+'.env')
|
||||||
|
|
||||||
|
const webpackConfig = merge(baseWebpackConfig, {
|
||||||
|
module: {
|
||||||
|
rules: utils.styleLoaders({
|
||||||
|
sourceMap: config.build.productionSourceMap,
|
||||||
|
extract: true,
|
||||||
|
usePostCSS: true
|
||||||
|
})
|
||||||
|
},
|
||||||
|
devtool: config.build.productionSourceMap ? config.build.devtool : false,
|
||||||
|
output: {
|
||||||
|
path: config.build.assetsRoot,
|
||||||
|
filename: utils.assetsPath('js/[name].[chunkhash].js'),
|
||||||
|
chunkFilename: utils.assetsPath('js/[id].[chunkhash].js')
|
||||||
|
},
|
||||||
|
plugins: [
|
||||||
|
// http://vuejs.github.io/vue-loader/en/workflow/production.html
|
||||||
|
new webpack.DefinePlugin({
|
||||||
|
'process.env': env
|
||||||
|
}),
|
||||||
|
new UglifyJsPlugin({
|
||||||
|
uglifyOptions: {
|
||||||
|
compress: {
|
||||||
|
warnings: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
sourceMap: config.build.productionSourceMap,
|
||||||
|
parallel: true
|
||||||
|
}),
|
||||||
|
// extract css into its own file
|
||||||
|
new ExtractTextPlugin({
|
||||||
|
filename: utils.assetsPath('css/[name].[contenthash].css'),
|
||||||
|
// Setting the following option to `false` will not extract CSS from codesplit chunks.
|
||||||
|
// Their CSS will instead be inserted dynamically with style-loader when the codesplit chunk has been loaded by webpack.
|
||||||
|
// increasing file size: https://github.com/vuejs-templates/webpack/issues/1110
|
||||||
|
allChunks: false,
|
||||||
|
}),
|
||||||
|
// Compress extracted CSS. We are using this plugin so that possible
|
||||||
|
// duplicated CSS from different components can be deduped.
|
||||||
|
new OptimizeCSSPlugin({
|
||||||
|
cssProcessorOptions: config.build.productionSourceMap
|
||||||
|
? { safe: true, map: { inline: false } }
|
||||||
|
: { safe: true }
|
||||||
|
}),
|
||||||
|
// generate dist index.html with correct asset hash for caching.
|
||||||
|
// you can customize output by editing /index.html
|
||||||
|
// see https://github.com/ampedandwired/html-webpack-plugin
|
||||||
|
new HtmlWebpackPlugin({
|
||||||
|
filename: config.build.index,
|
||||||
|
template: 'index.html',
|
||||||
|
inject: true,
|
||||||
|
favicon: resolve('favicon.ico'),
|
||||||
|
title: 'vue-element-admin',
|
||||||
|
path: config.build.assetsPublicPath + config.build.assetsSubDirectory,
|
||||||
|
minify: {
|
||||||
|
removeComments: true,
|
||||||
|
collapseWhitespace: true,
|
||||||
|
removeAttributeQuotes: true
|
||||||
|
// more options:
|
||||||
|
// https://github.com/kangax/html-minifier#options-quick-reference
|
||||||
|
},
|
||||||
|
// necessary to consistently work with multiple chunks via CommonsChunkPlugin
|
||||||
|
chunksSortMode: 'dependency'
|
||||||
|
}),
|
||||||
|
// keep module.id stable when vender modules does not change
|
||||||
|
new webpack.HashedModuleIdsPlugin(),
|
||||||
|
// enable scope hoisting
|
||||||
|
new webpack.optimize.ModuleConcatenationPlugin(),
|
||||||
|
// split vendor js into its own file
|
||||||
|
new webpack.optimize.CommonsChunkPlugin({
|
||||||
|
name: 'vendor',
|
||||||
|
minChunks (module) {
|
||||||
|
// any required modules inside node_modules are extracted to vendor
|
||||||
|
return (
|
||||||
|
module.resource &&
|
||||||
|
/\.js$/.test(module.resource) &&
|
||||||
|
module.resource.indexOf(
|
||||||
|
path.join(__dirname, '../node_modules')
|
||||||
|
) === 0
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
// extract webpack runtime and module manifest to its own file in order to
|
||||||
|
// prevent vendor hash from being updated whenever app bundle is updated
|
||||||
|
new webpack.optimize.CommonsChunkPlugin({
|
||||||
|
name: 'manifest',
|
||||||
|
minChunks: Infinity
|
||||||
|
}),
|
||||||
|
// This instance extracts shared chunks from code splitted chunks and bundles them
|
||||||
|
// in a separate chunk, similar to the vendor chunk
|
||||||
|
// see: https://webpack.js.org/plugins/commons-chunk-plugin/#extra-async-commons-chunk
|
||||||
|
new webpack.optimize.CommonsChunkPlugin({
|
||||||
|
name: 'app',
|
||||||
|
async: 'vendor-async',
|
||||||
|
children: true,
|
||||||
|
minChunks: 3
|
||||||
|
}),
|
||||||
|
// split echarts into its own file
|
||||||
|
new webpack.optimize.CommonsChunkPlugin({
|
||||||
|
async: 'echarts',
|
||||||
|
minChunks(module) {
|
||||||
|
var context = module.context;
|
||||||
|
return context && (context.indexOf('echarts') >= 0 || context.indexOf('zrender') >= 0);
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
// split xlsx into its own file
|
||||||
|
new webpack.optimize.CommonsChunkPlugin({
|
||||||
|
async: 'xlsx',
|
||||||
|
minChunks(module) {
|
||||||
|
var context = module.context;
|
||||||
|
return context && (context.indexOf('xlsx') >= 0);
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
// split codemirror into its own file
|
||||||
|
new webpack.optimize.CommonsChunkPlugin({
|
||||||
|
async: 'codemirror',
|
||||||
|
minChunks(module) {
|
||||||
|
var context = module.context;
|
||||||
|
return context && (context.indexOf('codemirror') >= 0);
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
|
||||||
|
// copy custom static assets
|
||||||
|
new CopyWebpackPlugin([
|
||||||
|
{
|
||||||
|
from: path.resolve(__dirname, '../static'),
|
||||||
|
to: config.build.assetsSubDirectory,
|
||||||
|
ignore: ['.*']
|
||||||
|
}
|
||||||
|
])
|
||||||
|
]
|
||||||
|
})
|
||||||
|
|
||||||
|
if (config.build.productionGzip) {
|
||||||
|
const CompressionWebpackPlugin = require('compression-webpack-plugin')
|
||||||
|
|
||||||
|
webpackConfig.plugins.push(
|
||||||
|
new CompressionWebpackPlugin({
|
||||||
|
asset: '[path].gz[query]',
|
||||||
|
algorithm: 'gzip',
|
||||||
|
test: new RegExp(
|
||||||
|
'\\.(' +
|
||||||
|
config.build.productionGzipExtensions.join('|') +
|
||||||
|
')$'
|
||||||
|
),
|
||||||
|
threshold: 10240,
|
||||||
|
minRatio: 0.8
|
||||||
|
})
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (config.build.bundleAnalyzerReport) {
|
||||||
|
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin
|
||||||
|
webpackConfig.plugins.push(new BundleAnalyzerPlugin())
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = webpackConfig
|
|
@ -0,0 +1,5 @@
|
||||||
|
module.exports = {
|
||||||
|
NODE_ENV: '"development"',
|
||||||
|
ENV_CONFIG: '"dev"',
|
||||||
|
BASE_API: '"https://api-dev"'
|
||||||
|
}
|
|
@ -0,0 +1,83 @@
|
||||||
|
'use strict'
|
||||||
|
// Template version: 1.2.6
|
||||||
|
// see http://vuejs-templates.github.io/webpack for documentation.
|
||||||
|
|
||||||
|
const path = require('path')
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
dev: {
|
||||||
|
|
||||||
|
// Paths
|
||||||
|
assetsSubDirectory: 'static',
|
||||||
|
assetsPublicPath: '/',
|
||||||
|
proxyTable: {},
|
||||||
|
|
||||||
|
// Various Dev Server settings
|
||||||
|
host: 'localhost', // can be overwritten by process.env.HOST
|
||||||
|
port: 9527, // can be overwritten by process.env.PORT, if port is in use, a free one will be determined
|
||||||
|
autoOpenBrowser: true,
|
||||||
|
errorOverlay: true,
|
||||||
|
notifyOnErrors: false,
|
||||||
|
poll: false, // https://webpack.js.org/configuration/dev-server/#devserver-watchoptions-
|
||||||
|
|
||||||
|
// Use Eslint Loader?
|
||||||
|
// If true, your code will be linted during bundling and
|
||||||
|
// linting errors and warnings will be shown in the console.
|
||||||
|
useEslint: true,
|
||||||
|
// If true, eslint errors and warnings will also be shown in the error overlay
|
||||||
|
// in the browser.
|
||||||
|
showEslintErrorsInOverlay: false,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Source Maps
|
||||||
|
*/
|
||||||
|
|
||||||
|
// https://webpack.js.org/configuration/devtool/#development
|
||||||
|
devtool: '#cheap-source-map',
|
||||||
|
|
||||||
|
// If you have problems debugging vue-files in devtools,
|
||||||
|
// set this to false - it *may* help
|
||||||
|
// https://vue-loader.vuejs.org/en/options.html#cachebusting
|
||||||
|
cacheBusting: true,
|
||||||
|
|
||||||
|
// CSS Sourcemaps off by default because relative paths are "buggy"
|
||||||
|
// with this option, according to the CSS-Loader README
|
||||||
|
// (https://github.com/webpack/css-loader#sourcemaps)
|
||||||
|
// In our experience, they generally work as expected,
|
||||||
|
// just be aware of this issue when enabling this option.
|
||||||
|
cssSourceMap: false,
|
||||||
|
},
|
||||||
|
|
||||||
|
build: {
|
||||||
|
// Template for index.html
|
||||||
|
index: path.resolve(__dirname, '../dist/index.html'),
|
||||||
|
|
||||||
|
// Paths
|
||||||
|
assetsRoot: path.resolve(__dirname, '../dist'),
|
||||||
|
assetsSubDirectory: 'static',
|
||||||
|
|
||||||
|
// you can set by youself according to actual condition
|
||||||
|
assetsPublicPath: './',
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Source Maps
|
||||||
|
*/
|
||||||
|
|
||||||
|
productionSourceMap: false,
|
||||||
|
// https://webpack.js.org/configuration/devtool/#production
|
||||||
|
devtool: '#source-map',
|
||||||
|
|
||||||
|
// Gzip off by default as many popular static hosts such as
|
||||||
|
// Surge or Netlify already gzip all static assets for you.
|
||||||
|
// Before setting to `true`, make sure to:
|
||||||
|
// npm install --save-dev compression-webpack-plugin
|
||||||
|
productionGzip: false,
|
||||||
|
productionGzipExtensions: ['js', 'css'],
|
||||||
|
|
||||||
|
// Run the build command with an extra argument to
|
||||||
|
// View the bundle analyzer report after build finishes:
|
||||||
|
// `npm run build --report`
|
||||||
|
// Set to `true` or `false` to always turn it on or off
|
||||||
|
bundleAnalyzerReport: process.env.npm_config_report
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
module.exports = {
|
||||||
|
NODE_ENV: '"production"',
|
||||||
|
ENV_CONFIG: '"prod"',
|
||||||
|
BASE_API: '"https://api-prod"'
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
module.exports = {
|
||||||
|
NODE_ENV: '"production"',
|
||||||
|
ENV_CONFIG: '"sit"',
|
||||||
|
BASE_API: '"https://api-sit"'
|
||||||
|
}
|
Before Width: | Height: | Size: 66 KiB After Width: | Height: | Size: 66 KiB |
After Width: | Height: | Size: 275 KiB |
After Width: | Height: | Size: 41 KiB |
After Width: | Height: | Size: 229 KiB |
After Width: | Height: | Size: 435 KiB |
After Width: | Height: | Size: 532 KiB |
After Width: | Height: | Size: 36 KiB |
After Width: | Height: | Size: 601 KiB |
After Width: | Height: | Size: 51 KiB |
After Width: | Height: | Size: 1.1 MiB |
After Width: | Height: | Size: 390 KiB |
After Width: | Height: | Size: 1.2 MiB |
After Width: | Height: | Size: 265 KiB |
After Width: | Height: | Size: 148 KiB |
After Width: | Height: | Size: 330 KiB |
|
@ -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">
|
||||||
|
<title>vue-element-admin</title>
|
||||||
|
</head>
|
||||||
|
<script src=<%= htmlWebpackPlugin.options.path %>/tinymce/tinymce.min.js></script>
|
||||||
|
<body>
|
||||||
|
<div id="app"></div>
|
||||||
|
<!-- built files will be auto injected -->
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -1,24 +0,0 @@
|
||||||
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/'
|
|
||||||
}
|
|
|
@ -1,9 +0,0 @@
|
||||||
{
|
|
||||||
"compilerOptions": {
|
|
||||||
"baseUrl": "./",
|
|
||||||
"paths": {
|
|
||||||
"@/*": ["src/*"]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"exclude": ["node_modules", "dist"]
|
|
||||||
}
|
|
116
mock/article.js
|
@ -1,116 +0,0 @@
|
||||||
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'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
|
|
|
@ -1,60 +0,0 @@
|
||||||
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
|
|
||||||
}
|
|
|
@ -1,81 +0,0 @@
|
||||||
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))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
|
@ -1,51 +0,0 @@
|
||||||
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']
|
|
||||||
}]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
|
@ -1,98 +0,0 @@
|
||||||
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'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
|
@ -1,530 +0,0 @@
|
||||||
// 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: 'Page Permission',
|
|
||||||
roles: ['admin']
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: 'directive',
|
|
||||||
component: 'views/permission/directive',
|
|
||||||
name: 'DirectivePermission',
|
|
||||||
meta: {
|
|
||||||
title: 'Directive Permission'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: 'role',
|
|
||||||
component: 'views/permission/role',
|
|
||||||
name: 'RolePermission',
|
|
||||||
meta: {
|
|
||||||
title: 'Role Permission',
|
|
||||||
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: 'Json Editor' }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
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: 'Avatar Upload' }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
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: 'Count To' }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
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: 'Back To Top' }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: 'drag-dialog',
|
|
||||||
component: 'views/components-demo/drag-dialog',
|
|
||||||
name: 'DragDialogDemo',
|
|
||||||
meta: { title: 'Drag Dialog' }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: 'drag-select',
|
|
||||||
component: 'views/components-demo/drag-select',
|
|
||||||
name: 'DragSelectDemo',
|
|
||||||
meta: { title: 'Drag Select' }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: 'dnd-list',
|
|
||||||
component: 'views/components-demo/dnd-list',
|
|
||||||
name: 'DndListDemo',
|
|
||||||
meta: { title: 'Dnd List' }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: 'drag-kanban',
|
|
||||||
component: 'views/components-demo/drag-kanban',
|
|
||||||
name: 'DragKanbanDemo',
|
|
||||||
meta: { title: 'Drag Kanban' }
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
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: 'Keyboard Chart', noCache: true }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: 'line',
|
|
||||||
component: 'views/charts/line',
|
|
||||||
name: 'LineChart',
|
|
||||||
meta: { title: 'Line Chart', noCache: true }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: 'mixchart',
|
|
||||||
component: 'views/charts/mixChart',
|
|
||||||
name: 'MixChart',
|
|
||||||
meta: { title: 'Mix Chart', 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: 'Create Article', icon: 'edit' }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: 'edit/:id(\\d+)',
|
|
||||||
component: 'views/example/edit',
|
|
||||||
name: 'EditArticle',
|
|
||||||
meta: { title: 'Edit Article', noCache: true },
|
|
||||||
hidden: true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: 'list',
|
|
||||||
component: 'views/example/list',
|
|
||||||
name: 'ArticleList',
|
|
||||||
meta: { title: 'Article List', 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: 'Error Pages',
|
|
||||||
icon: '404'
|
|
||||||
},
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
path: '401',
|
|
||||||
component: 'views/error-page/401',
|
|
||||||
name: 'Page401',
|
|
||||||
meta: { title: 'Page 401', noCache: true }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: '404',
|
|
||||||
component: 'views/error-page/404',
|
|
||||||
name: 'Page404',
|
|
||||||
meta: { title: 'Page 404', noCache: true }
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
path: '/error-log',
|
|
||||||
component: 'layout/Layout',
|
|
||||||
redirect: 'noRedirect',
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
path: 'log',
|
|
||||||
component: 'views/error-log/index',
|
|
||||||
name: 'ErrorLog',
|
|
||||||
meta: { title: 'Error Log', 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: 'Export Excel' }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: 'export-selected-excel',
|
|
||||||
component: 'views/excel/select-excel',
|
|
||||||
name: 'SelectExcel',
|
|
||||||
meta: { title: 'Select Excel' }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: 'export-merge-header',
|
|
||||||
component: 'views/excel/merge-header',
|
|
||||||
name: 'MergeHeader',
|
|
||||||
meta: { title: 'Merge Header' }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: 'upload-excel',
|
|
||||||
component: 'views/excel/upload-excel',
|
|
||||||
name: 'UploadExcel',
|
|
||||||
meta: { title: 'Upload Excel' }
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
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: 'Export Zip' }
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
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: 'Clipboard Demo', 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: 'External Link', icon: 'link' }
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
|
|
||||||
{ path: '*', redirect: '/404', hidden: true }
|
|
||||||
]
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
constantRoutes,
|
|
||||||
asyncRoutes
|
|
||||||
}
|
|
84
mock/user.js
|
@ -1,84 +0,0 @@
|
||||||
|
|
||||||
const tokens = {
|
|
||||||
admin: {
|
|
||||||
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 { username } = config.body
|
|
||||||
const token = tokens[username]
|
|
||||||
|
|
||||||
// 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'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
|
@ -1,48 +0,0 @@
|
||||||
/**
|
|
||||||
* @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
|
|
||||||
}
|
|
176
package.json
|
@ -1,111 +1,101 @@
|
||||||
{
|
{
|
||||||
"name": "vue-element-admin",
|
"name": "vue-element-admin",
|
||||||
"version": "4.4.0",
|
"version": "3.6.1",
|
||||||
"description": "A magical vue admin. An out-of-box UI solution for enterprise applications. Newest development stack of vue. Lots of awesome features",
|
"description": "A magical vue admin. Typical templates for enterprise applications. Newest development stack of vue. Lots of awesome features",
|
||||||
"author": "Pan <panfree23@gmail.com>",
|
"author": "Pan <panfree23@gmail.com>",
|
||||||
|
"license": "MIT",
|
||||||
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vue-cli-service serve",
|
"dev": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js",
|
||||||
|
"build:prod": "cross-env NODE_ENV=production env_config=prod node build/build.js",
|
||||||
|
"build:sit": "cross-env NODE_ENV=production env_config=sit node build/build.js",
|
||||||
"lint": "eslint --ext .js,.vue src",
|
"lint": "eslint --ext .js,.vue src",
|
||||||
"build:prod": "vue-cli-service build",
|
"test": "npm run lint"
|
||||||
"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": {
|
"dependencies": {
|
||||||
"axios": "0.18.1",
|
"axios": "0.17.1",
|
||||||
"clipboard": "2.0.4",
|
"clipboard": "1.7.1",
|
||||||
"codemirror": "5.45.0",
|
"codemirror": "5.32.0",
|
||||||
"core-js": "3.6.5",
|
"dropzone": "5.2.0",
|
||||||
"driver.js": "0.9.5",
|
"echarts": "3.8.5",
|
||||||
"dropzone": "5.5.1",
|
"element-ui": "2.0.8",
|
||||||
"echarts": "4.2.1",
|
"file-saver": "1.3.3",
|
||||||
"element-ui": "2.13.2",
|
"font-awesome": "4.7.0",
|
||||||
"file-saver": "2.0.1",
|
|
||||||
"fuse.js": "3.4.4",
|
|
||||||
"js-cookie": "2.2.0",
|
"js-cookie": "2.2.0",
|
||||||
"jsonlint": "1.6.3",
|
"jsonlint": "1.6.2",
|
||||||
"jszip": "3.2.1",
|
"jszip": "3.1.5",
|
||||||
|
"mockjs": "1.0.1-beta3",
|
||||||
"normalize.css": "7.0.0",
|
"normalize.css": "7.0.0",
|
||||||
"nprogress": "0.2.0",
|
"nprogress": "0.2.0",
|
||||||
"path-to-regexp": "2.4.0",
|
"screenfull": "3.3.2",
|
||||||
"screenfull": "4.2.0",
|
"showdown": "1.8.5",
|
||||||
"script-loader": "0.7.2",
|
"simplemde": "1.11.2",
|
||||||
"sortablejs": "1.8.4",
|
"sortablejs": "1.7.0",
|
||||||
"tui-editor": "1.3.3",
|
"vue": "2.5.10",
|
||||||
"vue": "2.6.10",
|
|
||||||
"vue-count-to": "1.0.13",
|
"vue-count-to": "1.0.13",
|
||||||
"vue-router": "3.0.2",
|
"vue-i18n": "7.3.2",
|
||||||
"vue-splitpane": "1.0.4",
|
"vue-multiselect": "2.0.8",
|
||||||
"vuedraggable": "2.20.0",
|
"vue-router": "3.0.1",
|
||||||
"vuex": "3.1.0",
|
"vue-splitpane": "1.0.2",
|
||||||
"xlsx": "0.14.1"
|
"vuedraggable": "2.15.0",
|
||||||
|
"vuex": "3.0.1",
|
||||||
|
"xlsx": "^0.11.16"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@vue/cli-plugin-babel": "4.4.4",
|
"autoprefixer": "7.2.3",
|
||||||
"@vue/cli-plugin-eslint": "4.4.4",
|
"babel-core": "6.26.0",
|
||||||
"@vue/cli-plugin-unit-jest": "4.4.4",
|
"babel-eslint": "8.0.3",
|
||||||
"@vue/cli-service": "4.4.4",
|
"babel-helper-vue-jsx-merge-props": "2.0.3",
|
||||||
"@vue/test-utils": "1.0.0-beta.29",
|
"babel-loader": "7.1.2",
|
||||||
"autoprefixer": "9.5.1",
|
"babel-plugin-syntax-jsx": "6.18.0",
|
||||||
"babel-eslint": "10.1.0",
|
"babel-plugin-transform-runtime": "6.23.0",
|
||||||
"babel-jest": "23.6.0",
|
"babel-plugin-transform-vue-jsx": "3.5.0",
|
||||||
"babel-plugin-dynamic-import-node": "2.3.3",
|
"babel-preset-env": "1.6.1",
|
||||||
"chalk": "2.4.2",
|
"babel-preset-stage-2": "6.24.1",
|
||||||
"chokidar": "2.1.5",
|
"chalk": "2.3.0",
|
||||||
"connect": "3.6.6",
|
"copy-webpack-plugin": "4.3.0",
|
||||||
"eslint": "6.7.2",
|
"cross-env": "5.1.1",
|
||||||
"eslint-plugin-vue": "6.2.2",
|
"css-loader": "0.28.7",
|
||||||
"html-webpack-plugin": "3.2.0",
|
"eslint": "4.13.1",
|
||||||
"husky": "1.3.1",
|
"eslint-friendly-formatter": "3.0.0",
|
||||||
"lint-staged": "8.1.5",
|
"eslint-loader": "1.9.0",
|
||||||
"mockjs": "1.0.1-beta3",
|
"eslint-plugin-html": "4.0.1",
|
||||||
"plop": "2.3.0",
|
"extract-text-webpack-plugin": "3.0.2",
|
||||||
"runjs": "4.3.2",
|
"file-loader": "1.1.5",
|
||||||
"sass": "1.26.2",
|
"friendly-errors-webpack-plugin": "1.6.1",
|
||||||
"sass-loader": "8.0.2",
|
"html-webpack-plugin": "2.30.1",
|
||||||
"script-ext-html-webpack-plugin": "2.1.3",
|
"node-notifier": "5.1.2",
|
||||||
"serve-static": "1.13.2",
|
"node-sass": "^4.7.2",
|
||||||
"svg-sprite-loader": "4.1.3",
|
"optimize-css-assets-webpack-plugin": "3.2.0",
|
||||||
"svgo": "1.2.0",
|
"ora": "1.3.0",
|
||||||
"vue-template-compiler": "2.6.10"
|
"portfinder": "1.0.13",
|
||||||
|
"postcss-import": "11.0.0",
|
||||||
|
"postcss-loader": "2.0.9",
|
||||||
|
"postcss-url": "7.3.0",
|
||||||
|
"pushstate-server": "3.0.1",
|
||||||
|
"rimraf": "2.6.2",
|
||||||
|
"sass-loader": "6.0.6",
|
||||||
|
"script-loader": "0.7.2",
|
||||||
|
"semver": "5.4.1",
|
||||||
|
"shelljs": "0.7.8",
|
||||||
|
"svg-sprite-loader": "3.5.2",
|
||||||
|
"uglifyjs-webpack-plugin": "1.1.3",
|
||||||
|
"url-loader": "0.6.2",
|
||||||
|
"vue-loader": "13.5.0",
|
||||||
|
"vue-style-loader": "3.0.3",
|
||||||
|
"vue-template-compiler": "2.5.10",
|
||||||
|
"webpack": "3.10.0",
|
||||||
|
"webpack-bundle-analyzer": "2.9.1",
|
||||||
|
"webpack-dev-server": "2.9.7",
|
||||||
|
"webpack-merge": "4.1.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 4.0.0",
|
||||||
|
"npm": ">= 3.0.0"
|
||||||
},
|
},
|
||||||
"browserslist": [
|
"browserslist": [
|
||||||
"> 1%",
|
"> 1%",
|
||||||
"last 2 versions"
|
"last 2 versions",
|
||||||
],
|
"not ie <= 8"
|
||||||
"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"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,26 +0,0 @@
|
||||||
{{#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}}
|
|
|
@ -1,55 +0,0 @@
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,16 +0,0 @@
|
||||||
{{#if state}}
|
|
||||||
const state = {}
|
|
||||||
{{/if}}
|
|
||||||
|
|
||||||
{{#if mutations}}
|
|
||||||
const mutations = {}
|
|
||||||
{{/if}}
|
|
||||||
|
|
||||||
{{#if actions}}
|
|
||||||
const actions = {}
|
|
||||||
{{/if}}
|
|
||||||
|
|
||||||
export default {
|
|
||||||
namespaced: true,
|
|
||||||
{{options}}
|
|
||||||
}
|
|
|
@ -1,62 +0,0 @@
|
||||||
const { notEmpty } = require('../utils.js')
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
description: 'generate store',
|
|
||||||
prompts: [{
|
|
||||||
type: 'input',
|
|
||||||
name: 'name',
|
|
||||||
message: 'store name please',
|
|
||||||
validate: notEmpty('name')
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: 'checkbox',
|
|
||||||
name: 'blocks',
|
|
||||||
message: 'Blocks:',
|
|
||||||
choices: [{
|
|
||||||
name: 'state',
|
|
||||||
value: 'state',
|
|
||||||
checked: true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'mutations',
|
|
||||||
value: 'mutations',
|
|
||||||
checked: true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'actions',
|
|
||||||
value: 'actions',
|
|
||||||
checked: true
|
|
||||||
}
|
|
||||||
],
|
|
||||||
validate(value) {
|
|
||||||
if (!value.includes('state') || !value.includes('mutations')) {
|
|
||||||
return 'store require at least state and mutations'
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
actions(data) {
|
|
||||||
const name = '{{name}}'
|
|
||||||
const { blocks } = data
|
|
||||||
const options = ['state', 'mutations']
|
|
||||||
const joinFlag = `,
|
|
||||||
`
|
|
||||||
if (blocks.length === 3) {
|
|
||||||
options.push('actions')
|
|
||||||
}
|
|
||||||
|
|
||||||
const actions = [{
|
|
||||||
type: 'add',
|
|
||||||
path: `src/store/modules/${name}.js`,
|
|
||||||
templateFile: 'plop-templates/store/index.hbs',
|
|
||||||
data: {
|
|
||||||
options: options.join(joinFlag),
|
|
||||||
state: blocks.includes('state'),
|
|
||||||
mutations: blocks.includes('mutations'),
|
|
||||||
actions: blocks.includes('actions')
|
|
||||||
}
|
|
||||||
}]
|
|
||||||
return actions
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,2 +0,0 @@
|
||||||
exports.notEmpty = name => v =>
|
|
||||||
!v || v.trim() === '' ? `${name} is required` : true
|
|
|
@ -1,26 +0,0 @@
|
||||||
{{#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}}
|
|
|
@ -1,55 +0,0 @@
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,9 +0,0 @@
|
||||||
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)
|
|
||||||
}
|
|
|
@ -1,5 +0,0 @@
|
||||||
module.exports = {
|
|
||||||
plugins: {
|
|
||||||
autoprefixer: {}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,15 +0,0 @@
|
||||||
<!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>
|
|
|
@ -1,11 +1,11 @@
|
||||||
<template>
|
<template>
|
||||||
<div id="app">
|
<div id="app">
|
||||||
<router-view />
|
<router-view></router-view>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
export default {
|
export default{
|
||||||
name: 'App'
|
name: 'APP'
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -2,23 +2,22 @@ import request from '@/utils/request'
|
||||||
|
|
||||||
export function fetchList(query) {
|
export function fetchList(query) {
|
||||||
return request({
|
return request({
|
||||||
url: '/vue-element-admin/article/list',
|
url: '/article/list',
|
||||||
method: 'get',
|
method: 'get',
|
||||||
params: query
|
params: query
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export function fetchArticle(id) {
|
export function fetchArticle() {
|
||||||
return request({
|
return request({
|
||||||
url: '/vue-element-admin/article/detail',
|
url: '/article/detail',
|
||||||
method: 'get',
|
method: 'get'
|
||||||
params: { id }
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export function fetchPv(pv) {
|
export function fetchPv(pv) {
|
||||||
return request({
|
return request({
|
||||||
url: '/vue-element-admin/article/pv',
|
url: '/article/pv',
|
||||||
method: 'get',
|
method: 'get',
|
||||||
params: { pv }
|
params: { pv }
|
||||||
})
|
})
|
||||||
|
@ -26,7 +25,7 @@ export function fetchPv(pv) {
|
||||||
|
|
||||||
export function createArticle(data) {
|
export function createArticle(data) {
|
||||||
return request({
|
return request({
|
||||||
url: '/vue-element-admin/article/create',
|
url: '/article/create',
|
||||||
method: 'post',
|
method: 'post',
|
||||||
data
|
data
|
||||||
})
|
})
|
||||||
|
@ -34,7 +33,7 @@ export function createArticle(data) {
|
||||||
|
|
||||||
export function updateArticle(data) {
|
export function updateArticle(data) {
|
||||||
return request({
|
return request({
|
||||||
url: '/vue-element-admin/article/update',
|
url: '/article/update',
|
||||||
method: 'post',
|
method: 'post',
|
||||||
data
|
data
|
||||||
})
|
})
|
||||||
|
|
|
@ -1,24 +1,29 @@
|
||||||
import request from '@/utils/request'
|
import request from '@/utils/request'
|
||||||
|
|
||||||
export function login(data) {
|
export function loginByUsername(username, password) {
|
||||||
|
const data = {
|
||||||
|
username,
|
||||||
|
password
|
||||||
|
}
|
||||||
return request({
|
return request({
|
||||||
url: '/vue-element-admin/user/login',
|
url: '/login/login',
|
||||||
method: 'post',
|
method: 'post',
|
||||||
data
|
data
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getInfo(token) {
|
export function logout() {
|
||||||
return request({
|
return request({
|
||||||
url: '/vue-element-admin/user/info',
|
url: '/login/logout',
|
||||||
|
method: 'post'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getUserInfo(token) {
|
||||||
|
return request({
|
||||||
|
url: '/user/info',
|
||||||
method: 'get',
|
method: 'get',
|
||||||
params: { token }
|
params: { token }
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export function logout() {
|
|
||||||
return request({
|
|
||||||
url: '/vue-element-admin/user/logout',
|
|
||||||
method: 'post'
|
|
||||||
})
|
|
||||||
}
|
|
|
@ -1,17 +0,0 @@
|
||||||
import request from '@/utils/request'
|
|
||||||
|
|
||||||
export function searchUser(name) {
|
|
||||||
return request({
|
|
||||||
url: '/vue-element-admin/search/user',
|
|
||||||
method: 'get',
|
|
||||||
params: { name }
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
export function transactionList(query) {
|
|
||||||
return request({
|
|
||||||
url: '/vue-element-admin/transaction/list',
|
|
||||||
method: 'get',
|
|
||||||
params: query
|
|
||||||
})
|
|
||||||
}
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
import request from '@/utils/request'
|
||||||
|
|
||||||
|
export function userSearch(name) {
|
||||||
|
return request({
|
||||||
|
url: '/search/user',
|
||||||
|
method: 'get',
|
||||||
|
params: { name }
|
||||||
|
})
|
||||||
|
}
|
|
@ -1,38 +0,0 @@
|
||||||
import request from '@/utils/request'
|
|
||||||
|
|
||||||
export function getRoutes() {
|
|
||||||
return request({
|
|
||||||
url: '/vue-element-admin/routes',
|
|
||||||
method: 'get'
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getRoles() {
|
|
||||||
return request({
|
|
||||||
url: '/vue-element-admin/roles',
|
|
||||||
method: 'get'
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
export function addRole(data) {
|
|
||||||
return request({
|
|
||||||
url: '/vue-element-admin/role',
|
|
||||||
method: 'post',
|
|
||||||
data
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
export function updateRole(id, data) {
|
|
||||||
return request({
|
|
||||||
url: `/vue-element-admin/role/${id}`,
|
|
||||||
method: 'put',
|
|
||||||
data
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
export function deleteRole(id) {
|
|
||||||
return request({
|
|
||||||
url: `/vue-element-admin/role/${id}`,
|
|
||||||
method: 'delete'
|
|
||||||
})
|
|
||||||
}
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
import request from '@/utils/request'
|
||||||
|
|
||||||
|
export function fetchList(query) {
|
||||||
|
return request({
|
||||||
|
url: '/transaction/list',
|
||||||
|
method: 'get',
|
||||||
|
params: query
|
||||||
|
})
|
||||||
|
}
|
|
@ -0,0 +1,199 @@
|
||||||
|
/* eslint-disable */
|
||||||
|
(function (root, factory) {
|
||||||
|
if (typeof define === 'function' && define.amd) {
|
||||||
|
// AMD. Register as an anonymous module.
|
||||||
|
define(['exports', 'echarts'], factory);
|
||||||
|
} else if (typeof exports === 'object' && typeof exports.nodeName !== 'string') {
|
||||||
|
// CommonJS
|
||||||
|
factory(exports, require('echarts'));
|
||||||
|
} else {
|
||||||
|
// Browser globals
|
||||||
|
factory({}, root.echarts);
|
||||||
|
}
|
||||||
|
}(this, function (exports, echarts) {
|
||||||
|
var log = function (msg) {
|
||||||
|
if (typeof console !== 'undefined') {
|
||||||
|
console && console.error && console.error(msg);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if (!echarts) {
|
||||||
|
log('ECharts is not Loaded');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var colorPalette = [
|
||||||
|
'#2ec7c9','#b6a2de','#5ab1ef','#ffb980','#d87a80',
|
||||||
|
'#8d98b3','#e5cf0d','#97b552','#95706d','#dc69aa',
|
||||||
|
'#07a2a4','#9a7fd1','#588dd5','#f5994e','#c05050',
|
||||||
|
'#59678c','#c9ab00','#7eb00a','#6f5553','#c14089'
|
||||||
|
];
|
||||||
|
|
||||||
|
|
||||||
|
var theme = {
|
||||||
|
color: colorPalette,
|
||||||
|
|
||||||
|
title: {
|
||||||
|
textStyle: {
|
||||||
|
fontWeight: 'normal',
|
||||||
|
color: '#008acd'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
visualMap: {
|
||||||
|
itemWidth: 15,
|
||||||
|
color: ['#5ab1ef','#e0ffff']
|
||||||
|
},
|
||||||
|
|
||||||
|
toolbox: {
|
||||||
|
iconStyle: {
|
||||||
|
normal: {
|
||||||
|
borderColor: colorPalette[0]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
tooltip: {
|
||||||
|
backgroundColor: 'rgba(50,50,50,0.5)',
|
||||||
|
axisPointer : {
|
||||||
|
type : 'line',
|
||||||
|
lineStyle : {
|
||||||
|
color: '#008acd'
|
||||||
|
},
|
||||||
|
crossStyle: {
|
||||||
|
color: '#008acd'
|
||||||
|
},
|
||||||
|
shadowStyle : {
|
||||||
|
color: 'rgba(200,200,200,0.2)'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
dataZoom: {
|
||||||
|
dataBackgroundColor: '#efefff',
|
||||||
|
fillerColor: 'rgba(182,162,222,0.2)',
|
||||||
|
handleColor: '#008acd'
|
||||||
|
},
|
||||||
|
|
||||||
|
grid: {
|
||||||
|
borderColor: '#eee'
|
||||||
|
},
|
||||||
|
|
||||||
|
categoryAxis: {
|
||||||
|
axisLine: {
|
||||||
|
lineStyle: {
|
||||||
|
color: '#008acd'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
splitLine: {
|
||||||
|
lineStyle: {
|
||||||
|
color: ['#eee']
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
valueAxis: {
|
||||||
|
axisLine: {
|
||||||
|
lineStyle: {
|
||||||
|
color: '#008acd'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
splitArea : {
|
||||||
|
show : true,
|
||||||
|
areaStyle : {
|
||||||
|
color: ['rgba(250,250,250,0.1)','rgba(200,200,200,0.1)']
|
||||||
|
}
|
||||||
|
},
|
||||||
|
splitLine: {
|
||||||
|
lineStyle: {
|
||||||
|
color: ['#eee']
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
timeline : {
|
||||||
|
lineStyle : {
|
||||||
|
color : '#008acd'
|
||||||
|
},
|
||||||
|
controlStyle : {
|
||||||
|
normal : { color : '#008acd'},
|
||||||
|
emphasis : { color : '#008acd'}
|
||||||
|
},
|
||||||
|
symbol : 'emptyCircle',
|
||||||
|
symbolSize : 3
|
||||||
|
},
|
||||||
|
|
||||||
|
line: {
|
||||||
|
smooth : true,
|
||||||
|
symbol: 'emptyCircle',
|
||||||
|
symbolSize: 3
|
||||||
|
},
|
||||||
|
|
||||||
|
candlestick: {
|
||||||
|
itemStyle: {
|
||||||
|
normal: {
|
||||||
|
color: '#d87a80',
|
||||||
|
color0: '#2ec7c9',
|
||||||
|
lineStyle: {
|
||||||
|
color: '#d87a80',
|
||||||
|
color0: '#2ec7c9'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
scatter: {
|
||||||
|
symbol: 'circle',
|
||||||
|
symbolSize: 4
|
||||||
|
},
|
||||||
|
|
||||||
|
map: {
|
||||||
|
label: {
|
||||||
|
normal: {
|
||||||
|
textStyle: {
|
||||||
|
color: '#d87a80'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
itemStyle: {
|
||||||
|
normal: {
|
||||||
|
borderColor: '#eee',
|
||||||
|
areaColor: '#ddd'
|
||||||
|
},
|
||||||
|
emphasis: {
|
||||||
|
areaColor: '#fe994e'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
graph: {
|
||||||
|
color: colorPalette
|
||||||
|
},
|
||||||
|
|
||||||
|
gauge : {
|
||||||
|
axisLine: {
|
||||||
|
lineStyle: {
|
||||||
|
color: [[0.2, '#2ec7c9'],[0.8, '#5ab1ef'],[1, '#d87a80']],
|
||||||
|
width: 10
|
||||||
|
}
|
||||||
|
},
|
||||||
|
axisTick: {
|
||||||
|
splitNumber: 10,
|
||||||
|
length :15,
|
||||||
|
lineStyle: {
|
||||||
|
color: 'auto'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
splitLine: {
|
||||||
|
length :22,
|
||||||
|
lineStyle: {
|
||||||
|
color: 'auto'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
pointer : {
|
||||||
|
width : 5
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
echarts.registerTheme('macarons', theme);
|
||||||
|
}));
|
|
@ -1,7 +1,12 @@
|
||||||
<template>
|
<template>
|
||||||
<transition :name="transitionName">
|
<transition :name="transitionName">
|
||||||
<div v-show="visible" :style="customStyle" class="back-to-ceiling" @click="backToTop">
|
<div class="back-to-ceiling" @click="backToTop" v-show="visible" :style="customStyle">
|
||||||
<svg width="16" height="16" viewBox="0 0 17 17" xmlns="http://www.w3.org/2000/svg" class="Icon Icon--backToTopArrow" aria-hidden="true" style="height:16px;width:16px"><path d="M12.036 15.59a1 1 0 0 1-.997.995H5.032a.996.996 0 0 1-.997-.996V8.584H1.03c-1.1 0-1.36-.633-.578-1.416L7.33.29a1.003 1.003 0 0 1 1.412 0l6.878 6.88c.782.78.523 1.415-.58 1.415h-3.004v7.004z" /></svg>
|
<svg width="16" height="16" viewBox="0 0 17 17" xmlns="http://www.w3.org/2000/svg" class="Icon Icon--backToTopArrow" aria-hidden="true" style="height: 16px; width: 16px;">
|
||||||
|
<title>回到顶部</title>
|
||||||
|
<g>
|
||||||
|
<path d="M12.036 15.59c0 .55-.453.995-.997.995H5.032c-.55 0-.997-.445-.997-.996V8.584H1.03c-1.1 0-1.36-.633-.578-1.416L7.33.29c.39-.39 1.026-.385 1.412 0l6.878 6.88c.782.78.523 1.415-.58 1.415h-3.004v7.004z" fill-rule="evenodd"></path>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
</transition>
|
</transition>
|
||||||
</template>
|
</template>
|
||||||
|
@ -20,8 +25,7 @@ export default {
|
||||||
},
|
},
|
||||||
customStyle: {
|
customStyle: {
|
||||||
type: Object,
|
type: Object,
|
||||||
default: function() {
|
default: {
|
||||||
return {
|
|
||||||
right: '50px',
|
right: '50px',
|
||||||
bottom: '50px',
|
bottom: '50px',
|
||||||
width: '40px',
|
width: '40px',
|
||||||
|
@ -30,7 +34,6 @@ export default {
|
||||||
'line-height': '45px',
|
'line-height': '45px',
|
||||||
background: '#e7eaf1'
|
background: '#e7eaf1'
|
||||||
}
|
}
|
||||||
}
|
|
||||||
},
|
},
|
||||||
transitionName: {
|
transitionName: {
|
||||||
type: String,
|
type: String,
|
||||||
|
@ -40,8 +43,7 @@ export default {
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
visible: false,
|
visible: false,
|
||||||
interval: null,
|
interval: null
|
||||||
isMoving: false
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
|
@ -58,16 +60,13 @@ export default {
|
||||||
this.visible = window.pageYOffset > this.visibilityHeight
|
this.visible = window.pageYOffset > this.visibilityHeight
|
||||||
},
|
},
|
||||||
backToTop() {
|
backToTop() {
|
||||||
if (this.isMoving) return
|
|
||||||
const start = window.pageYOffset
|
const start = window.pageYOffset
|
||||||
let i = 0
|
let i = 0
|
||||||
this.isMoving = true
|
|
||||||
this.interval = setInterval(() => {
|
this.interval = setInterval(() => {
|
||||||
const next = Math.floor(this.easeInOutQuad(10 * i, start, -start, 500))
|
const next = Math.floor(this.easeInOutQuad(10 * i, start, -start, 500))
|
||||||
if (next <= this.backPosition) {
|
if (next <= this.backPosition) {
|
||||||
window.scrollTo(0, this.backPosition)
|
window.scrollTo(0, this.backPosition)
|
||||||
clearInterval(this.interval)
|
clearInterval(this.interval)
|
||||||
this.isMoving = false
|
|
||||||
} else {
|
} else {
|
||||||
window.scrollTo(0, next)
|
window.scrollTo(0, next)
|
||||||
}
|
}
|
||||||
|
@ -83,29 +82,29 @@ export default {
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
.back-to-ceiling {
|
.back-to-ceiling {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
.back-to-ceiling:hover {
|
.back-to-ceiling:hover {
|
||||||
background: #d5dbe7;
|
background: #d5dbe7;
|
||||||
}
|
}
|
||||||
|
|
||||||
.fade-enter-active,
|
.fade-enter-active,
|
||||||
.fade-leave-active {
|
.fade-leave-active {
|
||||||
transition: opacity .5s;
|
transition: opacity .5s;
|
||||||
}
|
}
|
||||||
|
|
||||||
.fade-enter,
|
.fade-enter,
|
||||||
.fade-leave-to {
|
.fade-leave-to {
|
||||||
opacity: 0
|
opacity: 0
|
||||||
}
|
}
|
||||||
|
|
||||||
.back-to-ceiling .Icon {
|
.back-to-ceiling .Icon {
|
||||||
fill: #9aaabf;
|
fill: #9aaabf;
|
||||||
background: none;
|
background: none;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -1,82 +1,54 @@
|
||||||
<template>
|
<template>
|
||||||
<el-breadcrumb class="app-breadcrumb" separator="/">
|
<el-breadcrumb class="app-breadcrumb" separator="/">
|
||||||
<transition-group name="breadcrumb">
|
<transition-group name="breadcrumb">
|
||||||
<el-breadcrumb-item v-for="(item,index) in levelList" :key="item.path">
|
<el-breadcrumb-item v-for="(item,index) in levelList" :key="item.path" v-if='item.meta.title'>
|
||||||
<span v-if="item.redirect==='noRedirect'||index==levelList.length-1" class="no-redirect">{{ 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)">{{ item.meta.title }}</a>
|
<router-link v-else :to="item.redirect||item.path">{{generateTitle(item.meta.title)}}</router-link>
|
||||||
</el-breadcrumb-item>
|
</el-breadcrumb-item>
|
||||||
</transition-group>
|
</transition-group>
|
||||||
</el-breadcrumb>
|
</el-breadcrumb>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import pathToRegexp from 'path-to-regexp'
|
import { generateTitle } from '@/utils/i18n'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
created() {
|
||||||
|
this.getBreadcrumb()
|
||||||
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
levelList: null
|
levelList: null
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
$route(route) {
|
$route() {
|
||||||
// if you go to the redirect page, do not update the breadcrumbs
|
|
||||||
if (route.path.startsWith('/redirect/')) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
this.getBreadcrumb()
|
this.getBreadcrumb()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
created() {
|
|
||||||
this.getBreadcrumb()
|
|
||||||
},
|
|
||||||
methods: {
|
methods: {
|
||||||
|
generateTitle,
|
||||||
getBreadcrumb() {
|
getBreadcrumb() {
|
||||||
// only show routes with meta.title
|
let matched = this.$route.matched.filter(item => item.name)
|
||||||
let matched = this.$route.matched.filter(item => item.meta && item.meta.title)
|
|
||||||
const first = matched[0]
|
const first = matched[0]
|
||||||
|
if (first && first.name !== 'dashboard') {
|
||||||
if (!this.isDashboard(first)) {
|
matched = [{ path: '/dashboard', meta: { title: 'dashboard' }}].concat(matched)
|
||||||
matched = [{ path: '/dashboard', meta: { title: 'Dashboard' }}].concat(matched)
|
|
||||||
}
|
}
|
||||||
|
this.levelList = matched
|
||||||
this.levelList = matched.filter(item => item.meta && item.meta.title && item.meta.breadcrumb !== false)
|
|
||||||
},
|
|
||||||
isDashboard(route) {
|
|
||||||
const name = route && route.name
|
|
||||||
if (!name) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return name.trim().toLocaleLowerCase() === 'Dashboard'.toLocaleLowerCase()
|
|
||||||
},
|
|
||||||
pathCompile(path) {
|
|
||||||
// To solve this problem https://github.com/PanJiaChen/vue-element-admin/issues/561
|
|
||||||
const { params } = this.$route
|
|
||||||
var toPath = pathToRegexp.compile(path)
|
|
||||||
return toPath(params)
|
|
||||||
},
|
|
||||||
handleLink(item) {
|
|
||||||
const { redirect, path } = item
|
|
||||||
if (redirect) {
|
|
||||||
this.$router.push(redirect)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
this.$router.push(this.pathCompile(path))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style rel="stylesheet/scss" lang="scss" scoped>
|
||||||
.app-breadcrumb.el-breadcrumb {
|
.app-breadcrumb.el-breadcrumb {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
line-height: 50px;
|
line-height: 50px;
|
||||||
margin-left: 8px;
|
margin-left: 10px;
|
||||||
|
|
||||||
.no-redirect {
|
.no-redirect {
|
||||||
color: #97a8be;
|
color: #97a8be;
|
||||||
cursor: text;
|
cursor: text;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -1,155 +0,0 @@
|
||||||
<template>
|
|
||||||
<div :id="id" :class="className" :style="{height:height,width:width}" />
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import echarts from 'echarts'
|
|
||||||
import resize from './mixins/resize'
|
|
||||||
|
|
||||||
export default {
|
|
||||||
mixins: [resize],
|
|
||||||
props: {
|
|
||||||
className: {
|
|
||||||
type: String,
|
|
||||||
default: 'chart'
|
|
||||||
},
|
|
||||||
id: {
|
|
||||||
type: String,
|
|
||||||
default: 'chart'
|
|
||||||
},
|
|
||||||
width: {
|
|
||||||
type: String,
|
|
||||||
default: '200px'
|
|
||||||
},
|
|
||||||
height: {
|
|
||||||
type: String,
|
|
||||||
default: '200px'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
chart: null
|
|
||||||
}
|
|
||||||
},
|
|
||||||
mounted() {
|
|
||||||
this.initChart()
|
|
||||||
},
|
|
||||||
beforeDestroy() {
|
|
||||||
if (!this.chart) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
this.chart.dispose()
|
|
||||||
this.chart = null
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
initChart() {
|
|
||||||
this.chart = echarts.init(document.getElementById(this.id))
|
|
||||||
|
|
||||||
const xAxisData = []
|
|
||||||
const data = []
|
|
||||||
const data2 = []
|
|
||||||
for (let i = 0; i < 50; i++) {
|
|
||||||
xAxisData.push(i)
|
|
||||||
data.push((Math.sin(i / 5) * (i / 5 - 10) + i / 6) * 5)
|
|
||||||
data2.push((Math.sin(i / 5) * (i / 5 + 10) + i / 6) * 3)
|
|
||||||
}
|
|
||||||
this.chart.setOption({
|
|
||||||
backgroundColor: '#08263a',
|
|
||||||
grid: {
|
|
||||||
left: '5%',
|
|
||||||
right: '5%'
|
|
||||||
},
|
|
||||||
xAxis: [{
|
|
||||||
show: false,
|
|
||||||
data: xAxisData
|
|
||||||
}, {
|
|
||||||
show: false,
|
|
||||||
data: xAxisData
|
|
||||||
}],
|
|
||||||
visualMap: {
|
|
||||||
show: false,
|
|
||||||
min: 0,
|
|
||||||
max: 50,
|
|
||||||
dimension: 0,
|
|
||||||
inRange: {
|
|
||||||
color: ['#4a657a', '#308e92', '#b1cfa5', '#f5d69f', '#f5898b', '#ef5055']
|
|
||||||
}
|
|
||||||
},
|
|
||||||
yAxis: {
|
|
||||||
axisLine: {
|
|
||||||
show: false
|
|
||||||
},
|
|
||||||
axisLabel: {
|
|
||||||
textStyle: {
|
|
||||||
color: '#4a657a'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
splitLine: {
|
|
||||||
show: true,
|
|
||||||
lineStyle: {
|
|
||||||
color: '#08263f'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
axisTick: {
|
|
||||||
show: false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
series: [{
|
|
||||||
name: 'back',
|
|
||||||
type: 'bar',
|
|
||||||
data: data2,
|
|
||||||
z: 1,
|
|
||||||
itemStyle: {
|
|
||||||
normal: {
|
|
||||||
opacity: 0.4,
|
|
||||||
barBorderRadius: 5,
|
|
||||||
shadowBlur: 3,
|
|
||||||
shadowColor: '#111'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, {
|
|
||||||
name: 'Simulate Shadow',
|
|
||||||
type: 'line',
|
|
||||||
data,
|
|
||||||
z: 2,
|
|
||||||
showSymbol: false,
|
|
||||||
animationDelay: 0,
|
|
||||||
animationEasing: 'linear',
|
|
||||||
animationDuration: 1200,
|
|
||||||
lineStyle: {
|
|
||||||
normal: {
|
|
||||||
color: 'transparent'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
areaStyle: {
|
|
||||||
normal: {
|
|
||||||
color: '#08263a',
|
|
||||||
shadowBlur: 50,
|
|
||||||
shadowColor: '#000'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, {
|
|
||||||
name: 'front',
|
|
||||||
type: 'bar',
|
|
||||||
data,
|
|
||||||
xAxisIndex: 1,
|
|
||||||
z: 3,
|
|
||||||
itemStyle: {
|
|
||||||
normal: {
|
|
||||||
barBorderRadius: 5
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}],
|
|
||||||
animationEasing: 'elasticOut',
|
|
||||||
animationEasingUpdate: 'elasticOut',
|
|
||||||
animationDelay(idx) {
|
|
||||||
return idx * 20
|
|
||||||
},
|
|
||||||
animationDelayUpdate(idx) {
|
|
||||||
return idx * 20
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
|
@ -0,0 +1,150 @@
|
||||||
|
<template>
|
||||||
|
<div :class="className" :id="id" :style="{height:height,width:width}"></div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import echarts from 'echarts'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
className: {
|
||||||
|
type: String,
|
||||||
|
default: 'chart'
|
||||||
|
},
|
||||||
|
id: {
|
||||||
|
type: String,
|
||||||
|
default: 'chart'
|
||||||
|
},
|
||||||
|
width: {
|
||||||
|
type: String,
|
||||||
|
default: '200px'
|
||||||
|
},
|
||||||
|
height: {
|
||||||
|
type: String,
|
||||||
|
default: '200px'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
chart: null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.initChart()
|
||||||
|
},
|
||||||
|
beforeDestroy() {
|
||||||
|
if (!this.chart) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.chart.dispose()
|
||||||
|
this.chart = null
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
initChart() {
|
||||||
|
this.chart = echarts.init(document.getElementById(this.id))
|
||||||
|
|
||||||
|
const xAxisData = []
|
||||||
|
const data = []
|
||||||
|
const data2 = []
|
||||||
|
for (let i = 0; i < 50; i++) {
|
||||||
|
xAxisData.push(i)
|
||||||
|
data.push((Math.sin(i / 5) * (i / 5 - 10) + i / 6) * 5)
|
||||||
|
data2.push((Math.sin(i / 5) * (i / 5 + 10) + i / 6) * 3)
|
||||||
|
}
|
||||||
|
this.chart.setOption(
|
||||||
|
{
|
||||||
|
backgroundColor: '#08263a',
|
||||||
|
xAxis: [{
|
||||||
|
show: false,
|
||||||
|
data: xAxisData
|
||||||
|
}, {
|
||||||
|
show: false,
|
||||||
|
data: xAxisData
|
||||||
|
}],
|
||||||
|
visualMap: {
|
||||||
|
show: false,
|
||||||
|
min: 0,
|
||||||
|
max: 50,
|
||||||
|
dimension: 0,
|
||||||
|
inRange: {
|
||||||
|
color: ['#4a657a', '#308e92', '#b1cfa5', '#f5d69f', '#f5898b', '#ef5055']
|
||||||
|
}
|
||||||
|
},
|
||||||
|
yAxis: {
|
||||||
|
axisLine: {
|
||||||
|
show: false
|
||||||
|
},
|
||||||
|
axisLabel: {
|
||||||
|
textStyle: {
|
||||||
|
color: '#4a657a'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
splitLine: {
|
||||||
|
show: true,
|
||||||
|
lineStyle: {
|
||||||
|
color: '#08263f'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
axisTick: {
|
||||||
|
show: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
series: [{
|
||||||
|
name: 'back',
|
||||||
|
type: 'bar',
|
||||||
|
data: data2,
|
||||||
|
z: 1,
|
||||||
|
itemStyle: {
|
||||||
|
normal: {
|
||||||
|
opacity: 0.4,
|
||||||
|
barBorderRadius: 5,
|
||||||
|
shadowBlur: 3,
|
||||||
|
shadowColor: '#111'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
name: 'Simulate Shadow',
|
||||||
|
type: 'line',
|
||||||
|
data,
|
||||||
|
z: 2,
|
||||||
|
showSymbol: false,
|
||||||
|
animationDelay: 0,
|
||||||
|
animationEasing: 'linear',
|
||||||
|
animationDuration: 1200,
|
||||||
|
lineStyle: {
|
||||||
|
normal: {
|
||||||
|
color: 'transparent'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
areaStyle: {
|
||||||
|
normal: {
|
||||||
|
color: '#08263a',
|
||||||
|
shadowBlur: 50,
|
||||||
|
shadowColor: '#000'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
name: 'front',
|
||||||
|
type: 'bar',
|
||||||
|
data,
|
||||||
|
xAxisIndex: 1,
|
||||||
|
z: 3,
|
||||||
|
itemStyle: {
|
||||||
|
normal: {
|
||||||
|
barBorderRadius: 5
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}],
|
||||||
|
animationEasing: 'elasticOut',
|
||||||
|
animationEasingUpdate: 'elasticOut',
|
||||||
|
animationDelay(idx) {
|
||||||
|
return idx * 20
|
||||||
|
},
|
||||||
|
animationDelayUpdate(idx) {
|
||||||
|
return idx * 20
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
|
@ -1,13 +1,11 @@
|
||||||
<template>
|
<template>
|
||||||
<div :id="id" :class="className" :style="{height:height,width:width}" />
|
<div :class="className" :id="id" :style="{height:height,width:width}"></div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import echarts from 'echarts'
|
import echarts from 'echarts'
|
||||||
import resize from './mixins/resize'
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
mixins: [resize],
|
|
||||||
props: {
|
props: {
|
||||||
className: {
|
className: {
|
||||||
type: String,
|
type: String,
|
||||||
|
@ -80,8 +78,8 @@ export default {
|
||||||
},
|
},
|
||||||
grid: {
|
grid: {
|
||||||
top: 100,
|
top: 100,
|
||||||
left: '2%',
|
left: '3%',
|
||||||
right: '2%',
|
right: '4%',
|
||||||
bottom: '2%',
|
bottom: '2%',
|
||||||
containLabel: true
|
containLabel: true
|
||||||
},
|
},
|
|
@ -1,13 +1,11 @@
|
||||||
<template>
|
<template>
|
||||||
<div :id="id" :class="className" :style="{height:height,width:width}" />
|
<div :class="className" :id="id" :style="{height:height,width:width}"></div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import echarts from 'echarts'
|
import echarts from 'echarts'
|
||||||
import resize from './mixins/resize'
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
mixins: [resize],
|
|
||||||
props: {
|
props: {
|
||||||
className: {
|
className: {
|
||||||
type: String,
|
type: String,
|
||||||
|
@ -33,6 +31,7 @@ export default {
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
this.initChart()
|
this.initChart()
|
||||||
|
this.chart = null
|
||||||
},
|
},
|
||||||
beforeDestroy() {
|
beforeDestroy() {
|
||||||
if (!this.chart) {
|
if (!this.chart) {
|
||||||
|
@ -75,10 +74,8 @@ export default {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
grid: {
|
grid: {
|
||||||
left: '5%',
|
|
||||||
right: '5%',
|
|
||||||
borderWidth: 0,
|
borderWidth: 0,
|
||||||
top: 150,
|
top: 110,
|
||||||
bottom: 95,
|
bottom: 95,
|
||||||
textStyle: {
|
textStyle: {
|
||||||
color: '#fff'
|
color: '#fff'
|
|
@ -1,56 +0,0 @@
|
||||||
import { debounce } from '@/utils'
|
|
||||||
|
|
||||||
export default {
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
$_sidebarElm: null,
|
|
||||||
$_resizeHandler: null
|
|
||||||
}
|
|
||||||
},
|
|
||||||
mounted() {
|
|
||||||
this.initListener()
|
|
||||||
},
|
|
||||||
activated() {
|
|
||||||
if (!this.$_resizeHandler) {
|
|
||||||
// avoid duplication init
|
|
||||||
this.initListener()
|
|
||||||
}
|
|
||||||
|
|
||||||
// when keep-alive chart activated, auto resize
|
|
||||||
this.resize()
|
|
||||||
},
|
|
||||||
beforeDestroy() {
|
|
||||||
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()
|
|
||||||
}
|
|
||||||
},
|
|
||||||
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()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,27 +1,23 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="dndList">
|
<div class="dndList">
|
||||||
<div :style="{width:width1}" class="dndList-list">
|
<div class="dndList-list" :style="{width:width1}">
|
||||||
<h3>{{ list1Title }}</h3>
|
<h3>{{list1Title}}</h3>
|
||||||
<draggable :set-data="setData" :list="list1" group="article" class="dragArea">
|
<draggable :list="list1" class="dragArea" :options="{group:'article'}">
|
||||||
<div v-for="element in list1" :key="element.id" class="list-complete-item">
|
<div class="list-complete-item" v-for="element in list1" :key='element.id'>
|
||||||
<div class="list-complete-item-handle">
|
<div class="list-complete-item-handle">[{{element.author}}] {{element.title}}</div>
|
||||||
{{ element.id }}[{{ element.author }}] {{ element.title }}
|
|
||||||
</div>
|
|
||||||
<div style="position:absolute;right:0px;">
|
<div style="position:absolute;right:0px;">
|
||||||
<span style="float: right ;margin-top: -20px;margin-right:5px;" @click="deleteEle(element)">
|
<span style="float: right ;margin-top: -20px;margin-right:5px;" @click="deleteEle(element)">
|
||||||
<i style="color:#ff4949" class="el-icon-delete" />
|
<i style="color:#ff4949" class="el-icon-delete"></i>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</draggable>
|
</draggable>
|
||||||
</div>
|
</div>
|
||||||
<div :style="{width:width2}" class="dndList-list">
|
<div class="dndList-list" :style="{width:width2}">
|
||||||
<h3>{{ list2Title }}</h3>
|
<h3>{{list2Title}}</h3>
|
||||||
<draggable :list="list2" group="article" class="dragArea">
|
<draggable :list="filterList2" class="dragArea" :options="{group:'article'}">
|
||||||
<div v-for="element in list2" :key="element.id" class="list-complete-item">
|
<div class="list-complete-item" v-for="element in filterList2" :key='element.id'>
|
||||||
<div class="list-complete-item-handle2" @click="pushEle(element)">
|
<div class='list-complete-item-handle2' @click="pushEle(element)"> [{{element.author}}] {{element.title}}</div>
|
||||||
{{ element.id }} [{{ element.author }}] {{ element.title }}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</draggable>
|
</draggable>
|
||||||
</div>
|
</div>
|
||||||
|
@ -34,6 +30,16 @@ import draggable from 'vuedraggable'
|
||||||
export default {
|
export default {
|
||||||
name: 'DndList',
|
name: 'DndList',
|
||||||
components: { draggable },
|
components: { draggable },
|
||||||
|
computed: {
|
||||||
|
filterList2() {
|
||||||
|
return this.list2.filter(v => {
|
||||||
|
if (this.isNotInList1(v)) {
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
props: {
|
props: {
|
||||||
list1: {
|
list1: {
|
||||||
type: Array,
|
type: Array,
|
||||||
|
@ -84,27 +90,13 @@ export default {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
pushEle(ele) {
|
pushEle(ele) {
|
||||||
for (const item of this.list2) {
|
|
||||||
if (item.id === ele.id) {
|
|
||||||
const index = this.list2.indexOf(item)
|
|
||||||
this.list2.splice(index, 1)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (this.isNotInList1(ele)) {
|
|
||||||
this.list1.push(ele)
|
this.list1.push(ele)
|
||||||
}
|
}
|
||||||
},
|
|
||||||
setData(dataTransfer) {
|
|
||||||
// to avoid Firefox bug
|
|
||||||
// Detail see : https://github.com/RubaXa/Sortable/issues/1012
|
|
||||||
dataTransfer.setData('Text', '')
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style rel="stylesheet/scss" lang="scss" scoped>
|
||||||
.dndList {
|
.dndList {
|
||||||
background: #fff;
|
background: #fff;
|
||||||
padding-bottom: 40px;
|
padding-bottom: 40px;
|
||||||
|
|
|
@ -1,65 +0,0 @@
|
||||||
<template>
|
|
||||||
<el-select ref="dragSelect" v-model="selectVal" v-bind="$attrs" class="drag-select" multiple v-on="$listeners">
|
|
||||||
<slot />
|
|
||||||
</el-select>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import Sortable from 'sortablejs'
|
|
||||||
|
|
||||||
export default {
|
|
||||||
name: 'DragSelect',
|
|
||||||
props: {
|
|
||||||
value: {
|
|
||||||
type: Array,
|
|
||||||
required: true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
computed: {
|
|
||||||
selectVal: {
|
|
||||||
get() {
|
|
||||||
return [...this.value]
|
|
||||||
},
|
|
||||||
set(val) {
|
|
||||||
this.$emit('input', [...val])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
mounted() {
|
|
||||||
this.setSort()
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
setSort() {
|
|
||||||
const el = this.$refs.dragSelect.$el.querySelectorAll('.el-select__tags > span')[0]
|
|
||||||
this.sortable = Sortable.create(el, {
|
|
||||||
ghostClass: 'sortable-ghost', // Class name for the drop placeholder,
|
|
||||||
setData: function(dataTransfer) {
|
|
||||||
dataTransfer.setData('Text', '')
|
|
||||||
// to avoid Firefox bug
|
|
||||||
// Detail see : https://github.com/RubaXa/Sortable/issues/1012
|
|
||||||
},
|
|
||||||
onEnd: evt => {
|
|
||||||
const targetRow = this.value.splice(evt.oldIndex, 1)[0]
|
|
||||||
this.value.splice(evt.newIndex, 0, targetRow)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
|
||||||
.drag-select {
|
|
||||||
::v-deep {
|
|
||||||
.sortable-ghost {
|
|
||||||
opacity: .8;
|
|
||||||
color: #fff !important;
|
|
||||||
background: #42b983 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.el-tag {
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
|
@ -1,5 +1,5 @@
|
||||||
<template>
|
<template>
|
||||||
<div :id="id" :ref="id" :action="url" class="dropzone">
|
<div :ref="id" :action="url" class="dropzone" :id="id">
|
||||||
<input type="file" name="file">
|
<input type="file" name="file">
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
@ -12,81 +12,12 @@ import 'dropzone/dist/dropzone.css'
|
||||||
Dropzone.autoDiscover = false
|
Dropzone.autoDiscover = false
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
props: {
|
|
||||||
id: {
|
|
||||||
type: String,
|
|
||||||
required: true
|
|
||||||
},
|
|
||||||
url: {
|
|
||||||
type: String,
|
|
||||||
required: true
|
|
||||||
},
|
|
||||||
clickable: {
|
|
||||||
type: Boolean,
|
|
||||||
default: true
|
|
||||||
},
|
|
||||||
defaultMsg: {
|
|
||||||
type: String,
|
|
||||||
default: '上传图片'
|
|
||||||
},
|
|
||||||
acceptedFiles: {
|
|
||||||
type: String,
|
|
||||||
default: ''
|
|
||||||
},
|
|
||||||
thumbnailHeight: {
|
|
||||||
type: Number,
|
|
||||||
default: 200
|
|
||||||
},
|
|
||||||
thumbnailWidth: {
|
|
||||||
type: Number,
|
|
||||||
default: 200
|
|
||||||
},
|
|
||||||
showRemoveLink: {
|
|
||||||
type: Boolean,
|
|
||||||
default: true
|
|
||||||
},
|
|
||||||
maxFilesize: {
|
|
||||||
type: Number,
|
|
||||||
default: 2
|
|
||||||
},
|
|
||||||
maxFiles: {
|
|
||||||
type: Number,
|
|
||||||
default: 3
|
|
||||||
},
|
|
||||||
autoProcessQueue: {
|
|
||||||
type: Boolean,
|
|
||||||
default: true
|
|
||||||
},
|
|
||||||
useCustomDropzoneOptions: {
|
|
||||||
type: Boolean,
|
|
||||||
default: false
|
|
||||||
},
|
|
||||||
defaultImg: {
|
|
||||||
default: '',
|
|
||||||
type: [String, Array]
|
|
||||||
},
|
|
||||||
couldPaste: {
|
|
||||||
type: Boolean,
|
|
||||||
default: false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
dropzone: '',
|
dropzone: '',
|
||||||
initOnce: true
|
initOnce: true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
watch: {
|
|
||||||
defaultImg(val) {
|
|
||||||
if (val.length === 0) {
|
|
||||||
this.initOnce = false
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if (!this.initOnce) return
|
|
||||||
this.initImages(val)
|
|
||||||
this.initOnce = false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
mounted() {
|
mounted() {
|
||||||
const element = document.getElementById(this.id)
|
const element = document.getElementById(this.id)
|
||||||
const vm = this
|
const vm = this
|
||||||
|
@ -164,10 +95,6 @@ export default {
|
||||||
vm.$emit('dropzone-successmultiple', file, error, xhr)
|
vm.$emit('dropzone-successmultiple', file, error, xhr)
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
destroyed() {
|
|
||||||
document.removeEventListener('paste', this.pasteImg)
|
|
||||||
this.dropzone.destroy()
|
|
||||||
},
|
|
||||||
methods: {
|
methods: {
|
||||||
removeAllFiles() {
|
removeAllFiles() {
|
||||||
this.dropzone.removeAllFiles(true)
|
this.dropzone.removeAllFiles(true)
|
||||||
|
@ -201,6 +128,76 @@ export default {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
},
|
||||||
|
destroyed() {
|
||||||
|
document.removeEventListener('paste', this.pasteImg)
|
||||||
|
this.dropzone.destroy()
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
defaultImg(val) {
|
||||||
|
if (val.length === 0) {
|
||||||
|
this.initOnce = false
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (!this.initOnce) return
|
||||||
|
this.initImages(val)
|
||||||
|
this.initOnce = false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
id: {
|
||||||
|
type: String,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
url: {
|
||||||
|
type: String,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
clickable: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
defaultMsg: {
|
||||||
|
type: String,
|
||||||
|
default: '上传图片'
|
||||||
|
},
|
||||||
|
acceptedFiles: {
|
||||||
|
type: String
|
||||||
|
},
|
||||||
|
thumbnailHeight: {
|
||||||
|
type: Number,
|
||||||
|
default: 200
|
||||||
|
},
|
||||||
|
thumbnailWidth: {
|
||||||
|
type: Number,
|
||||||
|
default: 200
|
||||||
|
},
|
||||||
|
showRemoveLink: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
maxFilesize: {
|
||||||
|
type: Number,
|
||||||
|
default: 2
|
||||||
|
},
|
||||||
|
maxFiles: {
|
||||||
|
type: Number,
|
||||||
|
default: 3
|
||||||
|
},
|
||||||
|
autoProcessQueue: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
useCustomDropzoneOptions: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
defaultImg: {
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
couldPaste: {
|
||||||
|
default: false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
@ -237,7 +234,7 @@ export default {
|
||||||
|
|
||||||
.dropzone .dz-preview:hover .dz-image img {
|
.dropzone .dz-preview:hover .dz-image img {
|
||||||
transform: none;
|
transform: none;
|
||||||
filter: none;
|
-webkit-filter: none;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,54 +1,49 @@
|
||||||
<template>
|
<template>
|
||||||
<div v-if="errorLogs.length>0">
|
<div v-if="errorLogs.length>0">
|
||||||
<el-badge :is-dot="true" style="line-height: 25px;margin-top: -5px;" @click.native="dialogTableVisible=true">
|
<el-badge :is-dot="true" style="line-height: 30px;" @click.native="dialogTableVisible=true">
|
||||||
<el-button style="padding: 8px 10px;" size="small" type="danger">
|
<el-button size="small" type="danger" class="bug-btn">
|
||||||
<svg-icon icon-class="bug" />
|
<svg t="1492682037685" class="bug-svg" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1863"
|
||||||
|
xmlns:xlink="http://www.w3.org/1999/xlink" width="128" height="128">
|
||||||
|
<path d="M969.142857 548.571429q0 14.848-10.861714 25.709714t-25.709714 10.861714l-128 0q0 97.718857-38.290286 165.705143l118.857143 119.442286q10.861714 10.861714 10.861714 25.709714t-10.861714 25.709714q-10.276571 10.861714-25.709714 10.861714t-25.709714-10.861714l-113.152-112.566857q-2.852571 2.852571-8.557714 7.424t-23.990857 16.274286-37.156571 20.845714-46.848 16.566857-55.442286 7.424l0-512-73.142857 0 0 512q-29.147429 0-58.002286-7.716571t-49.700571-18.870857-37.705143-22.272-24.868571-18.578286l-8.557714-8.009143-104.557714 118.272q-11.446857 11.995429-27.428571 11.995429-13.714286 0-24.576-9.142857-10.861714-10.276571-11.702857-25.417143t8.850286-26.587429l115.419429-129.718857q-33.133714-65.133714-33.133714-156.562286l-128 0q-14.848 0-25.709714-10.861714t-10.861714-25.709714 10.861714-25.709714 25.709714-10.861714l128 0 0-168.009143-98.852571-98.852571q-10.861714-10.861714-10.861714-25.709714t10.861714-25.709714 25.709714-10.861714 25.709714 10.861714l98.852571 98.852571 482.304 0 98.852571-98.852571q10.861714-10.861714 25.709714-10.861714t25.709714 10.861714 10.861714 25.709714-10.861714 25.709714l-98.852571 98.852571 0 168.009143 128 0q14.848 0 25.709714 10.861714t10.861714 25.709714zM694.857143 219.428571l-365.714286 0q0-75.995429 53.430857-129.426286t129.426286-53.430857 129.426286 53.430857 53.430857 129.426286z"
|
||||||
|
p-id="1864"></path>
|
||||||
|
</svg>
|
||||||
</el-button>
|
</el-button>
|
||||||
</el-badge>
|
</el-badge>
|
||||||
|
|
||||||
<el-dialog :visible.sync="dialogTableVisible" width="80%" append-to-body>
|
<el-dialog title="Error Log" :visible.sync="dialogTableVisible" width="80%">
|
||||||
<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 :data="errorLogs" border>
|
||||||
<el-table-column label="Message">
|
<el-table-column label="Message">
|
||||||
<template slot-scope="{row}">
|
<template slot-scope="scope">
|
||||||
<div>
|
<div>
|
||||||
<span class="message-title">Msg:</span>
|
<span class="message-title">Msg:</span>
|
||||||
<el-tag type="danger">
|
<el-tag type="danger">{{ scope.row.err.message }}</el-tag>
|
||||||
{{ row.err.message }}
|
|
||||||
</el-tag>
|
|
||||||
</div>
|
</div>
|
||||||
<br>
|
<br/>
|
||||||
<div>
|
<div>
|
||||||
<span class="message-title" style="padding-right: 10px;">Info: </span>
|
<span class="message-title" style="padding-right: 10px;">Info: </span>
|
||||||
<el-tag type="warning">
|
<el-tag type="warning">{{scope.row.vm.$vnode.tag}} error in {{scope.row.info}}</el-tag>
|
||||||
{{ row.vm.$vnode.tag }} error in {{ row.info }}
|
|
||||||
</el-tag>
|
|
||||||
</div>
|
</div>
|
||||||
<br>
|
<br/>
|
||||||
<div>
|
<div>
|
||||||
<span class="message-title" style="padding-right: 16px;">Url: </span>
|
<span class="message-title" style="padding-right: 16px;">Url: </span>
|
||||||
<el-tag type="success">
|
<el-tag type="success">{{scope.row.url}}</el-tag>
|
||||||
{{ row.url }}
|
|
||||||
</el-tag>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="Stack">
|
<el-table-column label="Stack">
|
||||||
<template slot-scope="scope">
|
<template slot-scope="scope">
|
||||||
{{ scope.row.err.stack }}
|
{{ scope.row.err.stack}}
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
export default {
|
export default {
|
||||||
name: 'ErrorLog',
|
name: 'errorLog',
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
dialogTableVisible: false
|
dialogTableVisible: false
|
||||||
|
@ -58,17 +53,21 @@ export default {
|
||||||
errorLogs() {
|
errorLogs() {
|
||||||
return this.$store.getters.errorLogs
|
return this.$store.getters.errorLogs
|
||||||
}
|
}
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
clearAll() {
|
|
||||||
this.dialogTableVisible = false
|
|
||||||
this.$store.dispatch('errorLog/clearErrorLog')
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
.bug-btn.el-button--small {
|
||||||
|
padding: 9px 10px;
|
||||||
|
}
|
||||||
|
.bug-svg {
|
||||||
|
width: 1em;
|
||||||
|
height: 1em;
|
||||||
|
vertical-align: -0.15em;
|
||||||
|
fill: currentColor;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
.message-title {
|
.message-title {
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
color: #333;
|
color: #333;
|
||||||
|
|
|
@ -1,24 +1,12 @@
|
||||||
<template>
|
<template>
|
||||||
<a href="https://github.com/PanJiaChen/vue-element-admin" target="_blank" class="github-corner" aria-label="View source on Github">
|
<a href="https://github.com/PanJiaChen/vue-element-admin" target="_blank" class="github-corner" aria-label="View source on Github">
|
||||||
<svg
|
<svg width="80" height="80" viewBox="0 0 250 250" style="fill:#40c9c6; color:#fff; position: absolute; top: 84px; border: 0; right: 0;"
|
||||||
width="80"
|
aria-hidden="true">
|
||||||
height="80"
|
<path d="M0,0 L115,115 L130,115 L142,142 L250,250 L250,0 Z"></path>
|
||||||
viewBox="0 0 250 250"
|
<path d="M128.3,109.0 C113.8,99.7 119.0,89.6 119.0,89.6 C122.0,82.7 120.5,78.6 120.5,78.6 C119.2,72.0 123.4,76.3 123.4,76.3 C127.3,80.9 125.5,87.3 125.5,87.3 C122.9,97.6 130.6,101.9 134.4,103.2"
|
||||||
style="fill:#40c9c6; color:#fff;"
|
fill="currentColor" style="transform-origin: 130px 106px;" class="octo-arm"></path>
|
||||||
aria-hidden="true"
|
<path d="M115.0,115.0 C114.9,115.1 118.7,116.5 119.8,115.4 L133.7,101.6 C136.9,99.2 139.9,98.4 142.2,98.6 C133.8,88.0 127.5,74.4 143.8,58.0 C148.5,53.4 154.0,51.2 159.7,51.0 C160.3,49.4 163.2,43.6 171.4,40.1 C171.4,40.1 176.1,42.5 178.8,56.2 C183.1,58.6 187.2,61.8 190.9,65.4 C194.5,69.0 197.7,73.2 200.1,77.6 C213.8,80.2 216.3,84.9 216.3,84.9 C212.7,93.1 206.9,96.0 205.4,96.6 C205.1,102.4 203.0,107.8 198.3,112.5 C181.9,128.9 168.3,122.5 157.7,114.1 C157.9,116.9 156.7,120.9 152.7,124.9 L141.0,136.5 C139.8,137.7 141.6,141.9 141.8,141.8 Z"
|
||||||
>
|
fill="currentColor" class="octo-body"></path>
|
||||||
<path d="M0,0 L115,115 L130,115 L142,142 L250,250 L250,0 Z" />
|
|
||||||
<path
|
|
||||||
d="M128.3,109.0 C113.8,99.7 119.0,89.6 119.0,89.6 C122.0,82.7 120.5,78.6 120.5,78.6 C119.2,72.0 123.4,76.3 123.4,76.3 C127.3,80.9 125.5,87.3 125.5,87.3 C122.9,97.6 130.6,101.9 134.4,103.2"
|
|
||||||
fill="currentColor"
|
|
||||||
style="transform-origin: 130px 106px;"
|
|
||||||
class="octo-arm"
|
|
||||||
/>
|
|
||||||
<path
|
|
||||||
d="M115.0,115.0 C114.9,115.1 118.7,116.5 119.8,115.4 L133.7,101.6 C136.9,99.2 139.9,98.4 142.2,98.6 C133.8,88.0 127.5,74.4 143.8,58.0 C148.5,53.4 154.0,51.2 159.7,51.0 C160.3,49.4 163.2,43.6 171.4,40.1 C171.4,40.1 176.1,42.5 178.8,56.2 C183.1,58.6 187.2,61.8 190.9,65.4 C194.5,69.0 197.7,73.2 200.1,77.6 C213.8,80.2 216.3,84.9 216.3,84.9 C212.7,93.1 206.9,96.0 205.4,96.6 C205.1,102.4 203.0,107.8 198.3,112.5 C181.9,128.9 168.3,122.5 157.7,114.1 C157.9,116.9 156.7,120.9 152.7,124.9 L141.0,136.5 C139.8,137.7 141.6,141.9 141.8,141.8 Z"
|
|
||||||
fill="currentColor"
|
|
||||||
class="octo-body"
|
|
||||||
/>
|
|
||||||
</svg>
|
</svg>
|
||||||
</a>
|
</a>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -1,30 +1,28 @@
|
||||||
<template>
|
<template>
|
||||||
<div style="padding: 0 15px;" @click="toggleClick">
|
<div>
|
||||||
<svg
|
<svg t="1492500959545" @click="toggleClick" class="wscn-icon hamburger" :class="{'is-active':isActive}" style="" viewBox="0 0 1024 1024"
|
||||||
:class="{'is-active':isActive}"
|
version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1691" xmlns:xlink="http://www.w3.org/1999/xlink" width="64" height="64">
|
||||||
class="hamburger"
|
<path d="M966.8023 568.849776 57.196677 568.849776c-31.397081 0-56.850799-25.452695-56.850799-56.850799l0 0c0-31.397081 25.452695-56.849776 56.850799-56.849776l909.605623 0c31.397081 0 56.849776 25.452695 56.849776 56.849776l0 0C1023.653099 543.397081 998.200404 568.849776 966.8023 568.849776z"
|
||||||
viewBox="0 0 1024 1024"
|
p-id="1692"></path>
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
<path d="M966.8023 881.527125 57.196677 881.527125c-31.397081 0-56.850799-25.452695-56.850799-56.849776l0 0c0-31.397081 25.452695-56.849776 56.850799-56.849776l909.605623 0c31.397081 0 56.849776 25.452695 56.849776 56.849776l0 0C1023.653099 856.07443 998.200404 881.527125 966.8023 881.527125z"
|
||||||
width="64"
|
p-id="1693"></path>
|
||||||
height="64"
|
<path d="M966.8023 256.17345 57.196677 256.17345c-31.397081 0-56.850799-25.452695-56.850799-56.849776l0 0c0-31.397081 25.452695-56.850799 56.850799-56.850799l909.605623 0c31.397081 0 56.849776 25.452695 56.849776 56.850799l0 0C1023.653099 230.720755 998.200404 256.17345 966.8023 256.17345z"
|
||||||
>
|
p-id="1694"></path>
|
||||||
<path d="M408 442h480c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8H408c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8zm-8 204c0 4.4 3.6 8 8 8h480c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8H408c-4.4 0-8 3.6-8 8v56zm504-486H120c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h784c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zm0 632H120c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h784c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zM142.4 642.1L298.7 519a8.84 8.84 0 0 0 0-13.9L142.4 381.9c-5.8-4.6-14.4-.5-14.4 6.9v246.3a8.9 8.9 0 0 0 14.4 7z" />
|
|
||||||
</svg>
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
export default {
|
export default {
|
||||||
name: 'Hamburger',
|
name: 'hamburger',
|
||||||
props: {
|
props: {
|
||||||
isActive: {
|
isActive: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: false
|
default: false
|
||||||
}
|
|
||||||
},
|
},
|
||||||
methods: {
|
toggleClick: {
|
||||||
toggleClick() {
|
type: Function,
|
||||||
this.$emit('toggleClick')
|
default: null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -33,12 +31,15 @@ export default {
|
||||||
<style scoped>
|
<style scoped>
|
||||||
.hamburger {
|
.hamburger {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
vertical-align: middle;
|
cursor: pointer;
|
||||||
width: 20px;
|
width: 20px;
|
||||||
height: 20px;
|
height: 20px;
|
||||||
|
transform: rotate(90deg);
|
||||||
|
transition: .38s;
|
||||||
|
transform-origin: 50% 50%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.hamburger.is-active {
|
.hamburger.is-active {
|
||||||
transform: rotate(180deg);
|
transform: rotate(0deg);
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -1,180 +0,0 @@
|
||||||
<template>
|
|
||||||
<div :class="{'show':show}" class="header-search">
|
|
||||||
<svg-icon class-name="search-icon" icon-class="search" @click.stop="click" />
|
|
||||||
<el-select
|
|
||||||
ref="headerSearchSelect"
|
|
||||||
v-model="search"
|
|
||||||
:remote-method="querySearch"
|
|
||||||
filterable
|
|
||||||
default-first-option
|
|
||||||
remote
|
|
||||||
placeholder="Search"
|
|
||||||
class="header-search-select"
|
|
||||||
@change="change"
|
|
||||||
>
|
|
||||||
<el-option v-for="item in options" :key="item.path" :value="item" :label="item.title.join(' > ')" />
|
|
||||||
</el-select>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
// fuse is a lightweight fuzzy-search module
|
|
||||||
// make search results more in line with expectations
|
|
||||||
import Fuse from 'fuse.js'
|
|
||||||
import path from 'path'
|
|
||||||
|
|
||||||
export default {
|
|
||||||
name: 'HeaderSearch',
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
search: '',
|
|
||||||
options: [],
|
|
||||||
searchPool: [],
|
|
||||||
show: false,
|
|
||||||
fuse: undefined
|
|
||||||
}
|
|
||||||
},
|
|
||||||
computed: {
|
|
||||||
routes() {
|
|
||||||
return this.$store.getters.permission_routes
|
|
||||||
}
|
|
||||||
},
|
|
||||||
watch: {
|
|
||||||
routes() {
|
|
||||||
this.searchPool = this.generateRoutes(this.routes)
|
|
||||||
},
|
|
||||||
searchPool(list) {
|
|
||||||
this.initFuse(list)
|
|
||||||
},
|
|
||||||
show(value) {
|
|
||||||
if (value) {
|
|
||||||
document.body.addEventListener('click', this.close)
|
|
||||||
} else {
|
|
||||||
document.body.removeEventListener('click', this.close)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
mounted() {
|
|
||||||
this.searchPool = this.generateRoutes(this.routes)
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
click() {
|
|
||||||
this.show = !this.show
|
|
||||||
if (this.show) {
|
|
||||||
this.$refs.headerSearchSelect && this.$refs.headerSearchSelect.focus()
|
|
||||||
}
|
|
||||||
},
|
|
||||||
close() {
|
|
||||||
this.$refs.headerSearchSelect && this.$refs.headerSearchSelect.blur()
|
|
||||||
this.options = []
|
|
||||||
this.show = false
|
|
||||||
},
|
|
||||||
change(val) {
|
|
||||||
this.$router.push(val.path)
|
|
||||||
this.search = ''
|
|
||||||
this.options = []
|
|
||||||
this.$nextTick(() => {
|
|
||||||
this.show = false
|
|
||||||
})
|
|
||||||
},
|
|
||||||
initFuse(list) {
|
|
||||||
this.fuse = new Fuse(list, {
|
|
||||||
shouldSort: true,
|
|
||||||
threshold: 0.4,
|
|
||||||
location: 0,
|
|
||||||
distance: 100,
|
|
||||||
maxPatternLength: 32,
|
|
||||||
minMatchCharLength: 1,
|
|
||||||
keys: [{
|
|
||||||
name: 'title',
|
|
||||||
weight: 0.7
|
|
||||||
}, {
|
|
||||||
name: 'path',
|
|
||||||
weight: 0.3
|
|
||||||
}]
|
|
||||||
})
|
|
||||||
},
|
|
||||||
// Filter out the routes that can be displayed in the sidebar
|
|
||||||
// And generate the internationalized title
|
|
||||||
generateRoutes(routes, basePath = '/', prefixTitle = []) {
|
|
||||||
let res = []
|
|
||||||
|
|
||||||
for (const router of routes) {
|
|
||||||
// skip hidden router
|
|
||||||
if (router.hidden) { continue }
|
|
||||||
|
|
||||||
const data = {
|
|
||||||
path: path.resolve(basePath, router.path),
|
|
||||||
title: [...prefixTitle]
|
|
||||||
}
|
|
||||||
|
|
||||||
if (router.meta && router.meta.title) {
|
|
||||||
data.title = [...data.title, router.meta.title]
|
|
||||||
|
|
||||||
if (router.redirect !== 'noRedirect') {
|
|
||||||
// only push the routes with title
|
|
||||||
// special case: need to exclude parent router without redirect
|
|
||||||
res.push(data)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// recursive child routes
|
|
||||||
if (router.children) {
|
|
||||||
const tempRoutes = this.generateRoutes(router.children, data.path, data.title)
|
|
||||||
if (tempRoutes.length >= 1) {
|
|
||||||
res = [...res, ...tempRoutes]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return res
|
|
||||||
},
|
|
||||||
querySearch(query) {
|
|
||||||
if (query !== '') {
|
|
||||||
this.options = this.fuse.search(query)
|
|
||||||
} else {
|
|
||||||
this.options = []
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<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;
|
|
||||||
width: 0;
|
|
||||||
overflow: hidden;
|
|
||||||
background: transparent;
|
|
||||||
border-radius: 0;
|
|
||||||
display: inline-block;
|
|
||||||
vertical-align: middle;
|
|
||||||
|
|
||||||
::v-deep .el-input__inner {
|
|
||||||
border-radius: 0;
|
|
||||||
border: 0;
|
|
||||||
padding-left: 0;
|
|
||||||
padding-right: 0;
|
|
||||||
box-shadow: none !important;
|
|
||||||
border-bottom: 1px solid #d9d9d9;
|
|
||||||
vertical-align: middle;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&.show {
|
|
||||||
.header-search-select {
|
|
||||||
width: 210px;
|
|
||||||
margin-left: 10px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
|
@ -0,0 +1,41 @@
|
||||||
|
const langBag = {
|
||||||
|
zh: {
|
||||||
|
hint: '点击,或拖动图片至此处',
|
||||||
|
loading: '正在上传……',
|
||||||
|
noSupported: '浏览器不支持该功能,请使用IE10以上或其他现在浏览器!',
|
||||||
|
success: '上传成功',
|
||||||
|
fail: '图片上传失败',
|
||||||
|
preview: '头像预览',
|
||||||
|
btn: {
|
||||||
|
off: '取消',
|
||||||
|
close: '关闭',
|
||||||
|
back: '上一步',
|
||||||
|
save: '保存'
|
||||||
|
},
|
||||||
|
error: {
|
||||||
|
onlyImg: '仅限图片格式',
|
||||||
|
outOfSize: '单文件大小不能超过 ',
|
||||||
|
lowestPx: '图片最低像素为(宽*高):'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
en: {
|
||||||
|
hint: 'Click, or drag the file here',
|
||||||
|
loading: 'Uploading……',
|
||||||
|
noSupported: 'Browser does not support, please use IE10+ or other browsers',
|
||||||
|
success: 'Upload success',
|
||||||
|
fail: 'Upload failed',
|
||||||
|
preview: 'Preview',
|
||||||
|
btn: {
|
||||||
|
off: 'Cancel',
|
||||||
|
close: 'Close',
|
||||||
|
back: 'Back',
|
||||||
|
save: 'Save'
|
||||||
|
},
|
||||||
|
error: {
|
||||||
|
onlyImg: 'Image only',
|
||||||
|
outOfSize: 'Image exceeds size limit: ',
|
||||||
|
lowestPx: 'The lowest pixel in the image: '
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
export default langBag
|
|
@ -0,0 +1,691 @@
|
||||||
|
@charset "UTF-8";
|
||||||
|
@-webkit-keyframes vicp_progress {
|
||||||
|
0% {
|
||||||
|
background-position-y: 0;
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
background-position-y: 40px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes vicp_progress {
|
||||||
|
0% {
|
||||||
|
background-position-y: 0;
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
background-position-y: 40px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@-webkit-keyframes vicp {
|
||||||
|
0% {
|
||||||
|
opacity: 0;
|
||||||
|
-webkit-transform: scale(0) translatey(-60px);
|
||||||
|
transform: scale(0) translatey(-60px);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
opacity: 1;
|
||||||
|
-webkit-transform: scale(1) translatey(0);
|
||||||
|
transform: scale(1) translatey(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes vicp {
|
||||||
|
0% {
|
||||||
|
opacity: 0;
|
||||||
|
-webkit-transform: scale(0) translatey(-60px);
|
||||||
|
transform: scale(0) translatey(-60px);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
opacity: 1;
|
||||||
|
-webkit-transform: scale(1) translatey(0);
|
||||||
|
transform: scale(1) translatey(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.vue-image-crop-upload {
|
||||||
|
position: fixed;
|
||||||
|
display: block;
|
||||||
|
-webkit-box-sizing: border-box;
|
||||||
|
box-sizing: border-box;
|
||||||
|
z-index: 10000;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
background-color: rgba(0, 0, 0, 0.65);
|
||||||
|
-webkit-tap-highlight-color: transparent;
|
||||||
|
-moz-tap-highlight-color: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vue-image-crop-upload .vicp-wrap {
|
||||||
|
-webkit-box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.23);
|
||||||
|
box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.23);
|
||||||
|
position: fixed;
|
||||||
|
display: block;
|
||||||
|
-webkit-box-sizing: border-box;
|
||||||
|
box-sizing: border-box;
|
||||||
|
z-index: 10000;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
margin: auto;
|
||||||
|
width: 600px;
|
||||||
|
height: 330px;
|
||||||
|
padding: 25px;
|
||||||
|
background-color: #fff;
|
||||||
|
border-radius: 2px;
|
||||||
|
-webkit-animation: vicp 0.12s ease-in;
|
||||||
|
animation: vicp 0.12s ease-in;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vue-image-crop-upload .vicp-wrap .vicp-close {
|
||||||
|
position: absolute;
|
||||||
|
right: -30px;
|
||||||
|
top: -30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vue-image-crop-upload .vicp-wrap .vicp-close .vicp-icon4 {
|
||||||
|
position: relative;
|
||||||
|
display: block;
|
||||||
|
width: 30px;
|
||||||
|
height: 30px;
|
||||||
|
cursor: pointer;
|
||||||
|
-webkit-transition: -webkit-transform 0.18s;
|
||||||
|
transition: -webkit-transform 0.18s;
|
||||||
|
transition: transform 0.18s;
|
||||||
|
transition: transform 0.18s, -webkit-transform 0.18s;
|
||||||
|
-webkit-transform: rotate(0);
|
||||||
|
-ms-transform: rotate(0);
|
||||||
|
transform: rotate(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
.vue-image-crop-upload .vicp-wrap .vicp-close .vicp-icon4::after, .vue-image-crop-upload .vicp-wrap .vicp-close .vicp-icon4::before {
|
||||||
|
-webkit-box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.23);
|
||||||
|
box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.23);
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
top: 12px;
|
||||||
|
left: 4px;
|
||||||
|
width: 20px;
|
||||||
|
height: 3px;
|
||||||
|
-webkit-transform: rotate(45deg);
|
||||||
|
-ms-transform: rotate(45deg);
|
||||||
|
transform: rotate(45deg);
|
||||||
|
background-color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vue-image-crop-upload .vicp-wrap .vicp-close .vicp-icon4::after {
|
||||||
|
-webkit-transform: rotate(-45deg);
|
||||||
|
-ms-transform: rotate(-45deg);
|
||||||
|
transform: rotate(-45deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.vue-image-crop-upload .vicp-wrap .vicp-close .vicp-icon4:hover {
|
||||||
|
-webkit-transform: rotate(90deg);
|
||||||
|
-ms-transform: rotate(90deg);
|
||||||
|
transform: rotate(90deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.vue-image-crop-upload .vicp-wrap .vicp-step1 .vicp-drop-area {
|
||||||
|
position: relative;
|
||||||
|
padding: 35px;
|
||||||
|
height: 200px;
|
||||||
|
background-color: rgba(0, 0, 0, 0.03);
|
||||||
|
text-align: center;
|
||||||
|
border: 1px dashed rgba(0, 0, 0, 0.08);
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vue-image-crop-upload .vicp-wrap .vicp-step1 .vicp-drop-area .vicp-icon1 {
|
||||||
|
display: block;
|
||||||
|
margin: 0 auto 6px;
|
||||||
|
width: 42px;
|
||||||
|
height: 42px;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vue-image-crop-upload .vicp-wrap .vicp-step1 .vicp-drop-area .vicp-icon1 .vicp-icon1-arrow {
|
||||||
|
display: block;
|
||||||
|
margin: 0 auto;
|
||||||
|
width: 0;
|
||||||
|
height: 0;
|
||||||
|
border-bottom: 14.7px solid rgba(0, 0, 0, 0.3);
|
||||||
|
border-left: 14.7px solid transparent;
|
||||||
|
border-right: 14.7px solid transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vue-image-crop-upload .vicp-wrap .vicp-step1 .vicp-drop-area .vicp-icon1 .vicp-icon1-body {
|
||||||
|
display: block;
|
||||||
|
width: 12.6px;
|
||||||
|
height: 14.7px;
|
||||||
|
margin: 0 auto;
|
||||||
|
background-color: rgba(0, 0, 0, 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.vue-image-crop-upload .vicp-wrap .vicp-step1 .vicp-drop-area .vicp-icon1 .vicp-icon1-bottom {
|
||||||
|
-webkit-box-sizing: border-box;
|
||||||
|
box-sizing: border-box;
|
||||||
|
display: block;
|
||||||
|
height: 12.6px;
|
||||||
|
border: 6px solid rgba(0, 0, 0, 0.3);
|
||||||
|
border-top: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vue-image-crop-upload .vicp-wrap .vicp-step1 .vicp-drop-area .vicp-hint {
|
||||||
|
display: block;
|
||||||
|
padding: 15px;
|
||||||
|
font-size: 14px;
|
||||||
|
color: #666;
|
||||||
|
line-height: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vue-image-crop-upload .vicp-wrap .vicp-step1 .vicp-drop-area .vicp-no-supported-hint {
|
||||||
|
display: block;
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
padding: 30px;
|
||||||
|
width: 100%;
|
||||||
|
height: 60px;
|
||||||
|
line-height: 30px;
|
||||||
|
background-color: #eee;
|
||||||
|
text-align: center;
|
||||||
|
color: #666;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vue-image-crop-upload .vicp-wrap .vicp-step1 .vicp-drop-area:hover {
|
||||||
|
cursor: pointer;
|
||||||
|
border-color: rgba(0, 0, 0, 0.1);
|
||||||
|
background-color: rgba(0, 0, 0, 0.05);
|
||||||
|
}
|
||||||
|
|
||||||
|
.vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop {
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-left {
|
||||||
|
float: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-left .vicp-img-container {
|
||||||
|
position: relative;
|
||||||
|
display: block;
|
||||||
|
width: 240px;
|
||||||
|
height: 180px;
|
||||||
|
background-color: #e5e5e0;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-left .vicp-img-container .vicp-img {
|
||||||
|
position: absolute;
|
||||||
|
display: block;
|
||||||
|
cursor: move;
|
||||||
|
-webkit-user-select: none;
|
||||||
|
-moz-user-select: none;
|
||||||
|
-ms-user-select: none;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-left .vicp-img-container .vicp-img-shade {
|
||||||
|
-webkit-box-shadow: 0 2px 6px 0 rgba(0, 0, 0, 0.18);
|
||||||
|
box-shadow: 0 2px 6px 0 rgba(0, 0, 0, 0.18);
|
||||||
|
position: absolute;
|
||||||
|
background-color: rgba(241, 242, 243, 0.8);
|
||||||
|
}
|
||||||
|
|
||||||
|
.vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-left .vicp-img-container .vicp-img-shade.vicp-img-shade-1 {
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-left .vicp-img-container .vicp-img-shade.vicp-img-shade-2 {
|
||||||
|
bottom: 0;
|
||||||
|
right: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-left .vicp-range {
|
||||||
|
position: relative;
|
||||||
|
margin: 30px 0;
|
||||||
|
width: 240px;
|
||||||
|
height: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-left .vicp-range .vicp-icon5,
|
||||||
|
.vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-left .vicp-range .vicp-icon6 {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
width: 18px;
|
||||||
|
height: 18px;
|
||||||
|
border-radius: 100%;
|
||||||
|
background-color: rgba(0, 0, 0, 0.08);
|
||||||
|
}
|
||||||
|
|
||||||
|
.vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-left .vicp-range .vicp-icon5:hover,
|
||||||
|
.vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-left .vicp-range .vicp-icon6:hover {
|
||||||
|
-webkit-box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.12);
|
||||||
|
box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.12);
|
||||||
|
cursor: pointer;
|
||||||
|
background-color: rgba(0, 0, 0, 0.14);
|
||||||
|
}
|
||||||
|
|
||||||
|
.vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-left .vicp-range .vicp-icon5 {
|
||||||
|
left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-left .vicp-range .vicp-icon5::before {
|
||||||
|
position: absolute;
|
||||||
|
content: '';
|
||||||
|
display: block;
|
||||||
|
left: 3px;
|
||||||
|
top: 8px;
|
||||||
|
width: 12px;
|
||||||
|
height: 2px;
|
||||||
|
background-color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-left .vicp-range .vicp-icon6 {
|
||||||
|
right: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-left .vicp-range .vicp-icon6::before {
|
||||||
|
position: absolute;
|
||||||
|
content: '';
|
||||||
|
display: block;
|
||||||
|
left: 3px;
|
||||||
|
top: 8px;
|
||||||
|
width: 12px;
|
||||||
|
height: 2px;
|
||||||
|
background-color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-left .vicp-range .vicp-icon6::after {
|
||||||
|
position: absolute;
|
||||||
|
content: '';
|
||||||
|
display: block;
|
||||||
|
top: 3px;
|
||||||
|
left: 8px;
|
||||||
|
width: 2px;
|
||||||
|
height: 12px;
|
||||||
|
background-color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-left .vicp-range input[type=range] {
|
||||||
|
display: block;
|
||||||
|
padding-top: 5px;
|
||||||
|
margin: 0 auto;
|
||||||
|
width: 180px;
|
||||||
|
height: 8px;
|
||||||
|
vertical-align: top;
|
||||||
|
background: transparent;
|
||||||
|
-webkit-appearance: none;
|
||||||
|
-moz-appearance: none;
|
||||||
|
appearance: none;
|
||||||
|
cursor: pointer;
|
||||||
|
/* 滑块
|
||||||
|
---------------------------------------------------------------*/
|
||||||
|
/* 轨道
|
||||||
|
---------------------------------------------------------------*/
|
||||||
|
}
|
||||||
|
|
||||||
|
.vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-left .vicp-range input[type=range]:focus {
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-left .vicp-range input[type=range]::-webkit-slider-thumb {
|
||||||
|
-webkit-box-shadow: 0 2px 6px 0 rgba(0, 0, 0, 0.18);
|
||||||
|
box-shadow: 0 2px 6px 0 rgba(0, 0, 0, 0.18);
|
||||||
|
-webkit-appearance: none;
|
||||||
|
appearance: none;
|
||||||
|
margin-top: -3px;
|
||||||
|
width: 12px;
|
||||||
|
height: 12px;
|
||||||
|
background-color: #61c091;
|
||||||
|
border-radius: 100%;
|
||||||
|
border: none;
|
||||||
|
-webkit-transition: 0.2s;
|
||||||
|
transition: 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-left .vicp-range input[type=range]::-moz-range-thumb {
|
||||||
|
box-shadow: 0 2px 6px 0 rgba(0, 0, 0, 0.18);
|
||||||
|
-moz-appearance: none;
|
||||||
|
appearance: none;
|
||||||
|
width: 12px;
|
||||||
|
height: 12px;
|
||||||
|
background-color: #61c091;
|
||||||
|
border-radius: 100%;
|
||||||
|
border: none;
|
||||||
|
-webkit-transition: 0.2s;
|
||||||
|
transition: 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-left .vicp-range input[type=range]::-ms-thumb {
|
||||||
|
box-shadow: 0 2px 6px 0 rgba(0, 0, 0, 0.18);
|
||||||
|
appearance: none;
|
||||||
|
width: 12px;
|
||||||
|
height: 12px;
|
||||||
|
background-color: #61c091;
|
||||||
|
border: none;
|
||||||
|
border-radius: 100%;
|
||||||
|
-webkit-transition: 0.2s;
|
||||||
|
transition: 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-left .vicp-range input[type=range]:active::-moz-range-thumb {
|
||||||
|
box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.23);
|
||||||
|
width: 14px;
|
||||||
|
height: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-left .vicp-range input[type=range]:active::-ms-thumb {
|
||||||
|
box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.23);
|
||||||
|
width: 14px;
|
||||||
|
height: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-left .vicp-range input[type=range]:active::-webkit-slider-thumb {
|
||||||
|
-webkit-box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.23);
|
||||||
|
box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.23);
|
||||||
|
margin-top: -4px;
|
||||||
|
width: 14px;
|
||||||
|
height: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-left .vicp-range input[type=range]::-webkit-slider-runnable-track {
|
||||||
|
-webkit-box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.12);
|
||||||
|
box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.12);
|
||||||
|
width: 100%;
|
||||||
|
height: 6px;
|
||||||
|
cursor: pointer;
|
||||||
|
border-radius: 2px;
|
||||||
|
border: none;
|
||||||
|
background-color: rgba(68, 170, 119, 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-left .vicp-range input[type=range]::-moz-range-track {
|
||||||
|
box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.12);
|
||||||
|
width: 100%;
|
||||||
|
height: 6px;
|
||||||
|
cursor: pointer;
|
||||||
|
border-radius: 2px;
|
||||||
|
border: none;
|
||||||
|
background-color: rgba(68, 170, 119, 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-left .vicp-range input[type=range]::-ms-track {
|
||||||
|
box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.12);
|
||||||
|
width: 100%;
|
||||||
|
cursor: pointer;
|
||||||
|
background: transparent;
|
||||||
|
border-color: transparent;
|
||||||
|
color: transparent;
|
||||||
|
height: 6px;
|
||||||
|
border-radius: 2px;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-left .vicp-range input[type=range]::-ms-fill-lower {
|
||||||
|
background-color: rgba(68, 170, 119, 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-left .vicp-range input[type=range]::-ms-fill-upper {
|
||||||
|
background-color: rgba(68, 170, 119, 0.15);
|
||||||
|
}
|
||||||
|
|
||||||
|
.vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-left .vicp-range input[type=range]:focus::-webkit-slider-runnable-track {
|
||||||
|
background-color: rgba(68, 170, 119, 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
.vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-left .vicp-range input[type=range]:focus::-moz-range-track {
|
||||||
|
background-color: rgba(68, 170, 119, 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
.vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-left .vicp-range input[type=range]:focus::-ms-fill-lower {
|
||||||
|
background-color: rgba(68, 170, 119, 0.45);
|
||||||
|
}
|
||||||
|
|
||||||
|
.vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-left .vicp-range input[type=range]:focus::-ms-fill-upper {
|
||||||
|
background-color: rgba(68, 170, 119, 0.25);
|
||||||
|
}
|
||||||
|
|
||||||
|
.vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-right {
|
||||||
|
float: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-right .vicp-preview {
|
||||||
|
height: 150px;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-right .vicp-preview .vicp-preview-item {
|
||||||
|
position: relative;
|
||||||
|
padding: 5px;
|
||||||
|
width: 100px;
|
||||||
|
height: 100px;
|
||||||
|
float: left;
|
||||||
|
margin-right: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-right .vicp-preview .vicp-preview-item span {
|
||||||
|
position: absolute;
|
||||||
|
bottom: -30px;
|
||||||
|
width: 100%;
|
||||||
|
font-size: 14px;
|
||||||
|
color: #bbb;
|
||||||
|
display: block;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-right .vicp-preview .vicp-preview-item img {
|
||||||
|
position: absolute;
|
||||||
|
display: block;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
margin: auto;
|
||||||
|
padding: 3px;
|
||||||
|
background-color: #fff;
|
||||||
|
border: 1px solid rgba(0, 0, 0, 0.15);
|
||||||
|
overflow: hidden;
|
||||||
|
-webkit-user-select: none;
|
||||||
|
-moz-user-select: none;
|
||||||
|
-ms-user-select: none;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-right .vicp-preview .vicp-preview-item:last-child {
|
||||||
|
margin-right: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-right .vicp-preview .vicp-preview-item:last-child img {
|
||||||
|
border-radius: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vue-image-crop-upload .vicp-wrap .vicp-step3 .vicp-upload {
|
||||||
|
position: relative;
|
||||||
|
padding: 35px;
|
||||||
|
height: 200px;
|
||||||
|
background-color: rgba(0, 0, 0, 0.03);
|
||||||
|
text-align: center;
|
||||||
|
border: 1px dashed #ddd;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vue-image-crop-upload .vicp-wrap .vicp-step3 .vicp-upload .vicp-loading {
|
||||||
|
display: block;
|
||||||
|
padding: 15px;
|
||||||
|
font-size: 16px;
|
||||||
|
color: #999;
|
||||||
|
line-height: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vue-image-crop-upload .vicp-wrap .vicp-step3 .vicp-upload .vicp-progress-wrap {
|
||||||
|
margin-top: 12px;
|
||||||
|
background-color: rgba(0, 0, 0, 0.08);
|
||||||
|
border-radius: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vue-image-crop-upload .vicp-wrap .vicp-step3 .vicp-upload .vicp-progress-wrap .vicp-progress {
|
||||||
|
position: relative;
|
||||||
|
display: block;
|
||||||
|
height: 5px;
|
||||||
|
border-radius: 3px;
|
||||||
|
background-color: #4a7;
|
||||||
|
-webkit-box-shadow: 0 2px 6px 0 rgba(68, 170, 119, 0.3);
|
||||||
|
box-shadow: 0 2px 6px 0 rgba(68, 170, 119, 0.3);
|
||||||
|
-webkit-transition: width 0.15s linear;
|
||||||
|
transition: width 0.15s linear;
|
||||||
|
background-image: -webkit-linear-gradient(135deg, rgba(255, 255, 255, 0.2) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.2) 50%, rgba(255, 255, 255, 0.2) 75%, transparent 75%, transparent);
|
||||||
|
background-image: linear-gradient(-45deg, rgba(255, 255, 255, 0.2) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.2) 50%, rgba(255, 255, 255, 0.2) 75%, transparent 75%, transparent);
|
||||||
|
background-size: 40px 40px;
|
||||||
|
-webkit-animation: vicp_progress 0.5s linear infinite;
|
||||||
|
animation: vicp_progress 0.5s linear infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vue-image-crop-upload .vicp-wrap .vicp-step3 .vicp-upload .vicp-progress-wrap .vicp-progress::after {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
display: block;
|
||||||
|
top: -3px;
|
||||||
|
right: -3px;
|
||||||
|
width: 9px;
|
||||||
|
height: 9px;
|
||||||
|
border: 1px solid rgba(245, 246, 247, 0.7);
|
||||||
|
-webkit-box-shadow: 0 1px 4px 0 rgba(68, 170, 119, 0.7);
|
||||||
|
box-shadow: 0 1px 4px 0 rgba(68, 170, 119, 0.7);
|
||||||
|
border-radius: 100%;
|
||||||
|
background-color: #4a7;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vue-image-crop-upload .vicp-wrap .vicp-step3 .vicp-upload .vicp-error,
|
||||||
|
.vue-image-crop-upload .vicp-wrap .vicp-step3 .vicp-upload .vicp-success {
|
||||||
|
height: 100px;
|
||||||
|
line-height: 100px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vue-image-crop-upload .vicp-wrap .vicp-operate {
|
||||||
|
position: absolute;
|
||||||
|
right: 20px;
|
||||||
|
bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vue-image-crop-upload .vicp-wrap .vicp-operate a {
|
||||||
|
position: relative;
|
||||||
|
float: left;
|
||||||
|
display: block;
|
||||||
|
margin-left: 10px;
|
||||||
|
width: 100px;
|
||||||
|
height: 36px;
|
||||||
|
line-height: 36px;
|
||||||
|
text-align: center;
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 14px;
|
||||||
|
color: #4a7;
|
||||||
|
border-radius: 2px;
|
||||||
|
overflow: hidden;
|
||||||
|
-webkit-user-select: none;
|
||||||
|
-moz-user-select: none;
|
||||||
|
-ms-user-select: none;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vue-image-crop-upload .vicp-wrap .vicp-operate a:hover {
|
||||||
|
background-color: rgba(0, 0, 0, 0.03);
|
||||||
|
}
|
||||||
|
|
||||||
|
.vue-image-crop-upload .vicp-wrap .vicp-error,
|
||||||
|
.vue-image-crop-upload .vicp-wrap .vicp-success {
|
||||||
|
display: block;
|
||||||
|
font-size: 14px;
|
||||||
|
line-height: 24px;
|
||||||
|
height: 24px;
|
||||||
|
color: #d10;
|
||||||
|
text-align: center;
|
||||||
|
vertical-align: top;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vue-image-crop-upload .vicp-wrap .vicp-success {
|
||||||
|
color: #4a7;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vue-image-crop-upload .vicp-wrap .vicp-icon3 {
|
||||||
|
position: relative;
|
||||||
|
display: inline-block;
|
||||||
|
width: 20px;
|
||||||
|
height: 20px;
|
||||||
|
top: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vue-image-crop-upload .vicp-wrap .vicp-icon3::after {
|
||||||
|
position: absolute;
|
||||||
|
top: 3px;
|
||||||
|
left: 6px;
|
||||||
|
width: 6px;
|
||||||
|
height: 10px;
|
||||||
|
border-width: 0 2px 2px 0;
|
||||||
|
border-color: #4a7;
|
||||||
|
border-style: solid;
|
||||||
|
-webkit-transform: rotate(45deg);
|
||||||
|
-ms-transform: rotate(45deg);
|
||||||
|
transform: rotate(45deg);
|
||||||
|
content: '';
|
||||||
|
}
|
||||||
|
|
||||||
|
.vue-image-crop-upload .vicp-wrap .vicp-icon2 {
|
||||||
|
position: relative;
|
||||||
|
display: inline-block;
|
||||||
|
width: 20px;
|
||||||
|
height: 20px;
|
||||||
|
top: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vue-image-crop-upload .vicp-wrap .vicp-icon2::after, .vue-image-crop-upload .vicp-wrap .vicp-icon2::before {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
top: 9px;
|
||||||
|
left: 4px;
|
||||||
|
width: 13px;
|
||||||
|
height: 2px;
|
||||||
|
background-color: #d10;
|
||||||
|
-webkit-transform: rotate(45deg);
|
||||||
|
-ms-transform: rotate(45deg);
|
||||||
|
transform: rotate(45deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.vue-image-crop-upload .vicp-wrap .vicp-icon2::after {
|
||||||
|
-webkit-transform: rotate(-45deg);
|
||||||
|
-ms-transform: rotate(-45deg);
|
||||||
|
transform: rotate(-45deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.e-ripple {
|
||||||
|
position: absolute;
|
||||||
|
border-radius: 100%;
|
||||||
|
background-color: rgba(0, 0, 0, 0.15);
|
||||||
|
background-clip: padding-box;
|
||||||
|
pointer-events: none;
|
||||||
|
-webkit-user-select: none;
|
||||||
|
-moz-user-select: none;
|
||||||
|
-ms-user-select: none;
|
||||||
|
user-select: none;
|
||||||
|
-webkit-transform: scale(0);
|
||||||
|
-ms-transform: scale(0);
|
||||||
|
transform: scale(0);
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.e-ripple.z-active {
|
||||||
|
opacity: 0;
|
||||||
|
-webkit-transform: scale(2);
|
||||||
|
-ms-transform: scale(2);
|
||||||
|
transform: scale(2);
|
||||||
|
-webkit-transition: opacity 1.2s ease-out, -webkit-transform 0.6s ease-out;
|
||||||
|
transition: opacity 1.2s ease-out, -webkit-transform 0.6s ease-out;
|
||||||
|
transition: opacity 1.2s ease-out, transform 0.6s ease-out;
|
||||||
|
transition: opacity 1.2s ease-out, transform 0.6s ease-out, -webkit-transform 0.6s ease-out;
|
||||||
|
}
|
|
@ -0,0 +1,58 @@
|
||||||
|
/* eslint-disable */
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param e
|
||||||
|
* @param arg_opts
|
||||||
|
* @returns {boolean}
|
||||||
|
*/
|
||||||
|
export function effectRipple(e, arg_opts) {
|
||||||
|
let opts = Object.assign({
|
||||||
|
ele: e.target, // 波纹作用元素
|
||||||
|
type: 'hit', // hit点击位置扩散 center中心点扩展
|
||||||
|
bgc: 'rgba(0, 0, 0, 0.15)' // 波纹颜色
|
||||||
|
}, arg_opts),
|
||||||
|
target = opts.ele;
|
||||||
|
if (target) {
|
||||||
|
let rect = target.getBoundingClientRect(),
|
||||||
|
ripple = target.querySelector('.e-ripple');
|
||||||
|
if (!ripple) {
|
||||||
|
ripple = document.createElement('span');
|
||||||
|
ripple.className = 'e-ripple';
|
||||||
|
ripple.style.height = ripple.style.width = Math.max(rect.width, rect.height) + 'px';
|
||||||
|
target.appendChild(ripple);
|
||||||
|
} else {
|
||||||
|
ripple.className = 'e-ripple';
|
||||||
|
}
|
||||||
|
switch (opts.type) {
|
||||||
|
case 'center':
|
||||||
|
ripple.style.top = (rect.height / 2 - ripple.offsetHeight / 2) + 'px';
|
||||||
|
ripple.style.left = (rect.width / 2 - ripple.offsetWidth / 2) + 'px';
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ripple.style.top = (e.pageY - rect.top - ripple.offsetHeight / 2 - document.body.scrollTop) + 'px';
|
||||||
|
ripple.style.left = (e.pageX - rect.left - ripple.offsetWidth / 2 - document.body.scrollLeft) + 'px';
|
||||||
|
}
|
||||||
|
ripple.style.backgroundColor = opts.bgc;
|
||||||
|
ripple.className = 'e-ripple z-active';
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// database64文件格式转换为2进制
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param data
|
||||||
|
* @param mime
|
||||||
|
* @returns {*}
|
||||||
|
*/
|
||||||
|
export function data2blob(data, mime) {
|
||||||
|
// dataURL 的格式为 “data:image/png;base64,****”,逗号之前都是一些说明性的文字,我们只需要逗号之后的就行了
|
||||||
|
data = data.split(',')[1];
|
||||||
|
data = window.atob(data);
|
||||||
|
var ia = new Uint8Array(data.length);
|
||||||
|
for (var i = 0; i < data.length; i++) {
|
||||||
|
ia[i] = data.charCodeAt(i);
|
||||||
|
}
|
||||||
|
// canvas.toDataURL 返回的默认格式就是 image/png
|
||||||
|
return new Blob([ia], {type: mime});
|
||||||
|
};
|
|
@ -1,19 +0,0 @@
|
||||||
/**
|
|
||||||
* database64文件格式转换为2进制
|
|
||||||
*
|
|
||||||
* @param {[String]} data dataURL 的格式为 “data:image/png;base64,****”,逗号之前都是一些说明性的文字,我们只需要逗号之后的就行了
|
|
||||||
* @param {[String]} mime [description]
|
|
||||||
* @return {[blob]} [description]
|
|
||||||
*/
|
|
||||||
export default function(data, mime) {
|
|
||||||
data = data.split(',')[1]
|
|
||||||
data = window.atob(data)
|
|
||||||
var ia = new Uint8Array(data.length)
|
|
||||||
for (var i = 0; i < data.length; i++) {
|
|
||||||
ia[i] = data.charCodeAt(i)
|
|
||||||
}
|
|
||||||
// canvas.toDataURL 返回的默认格式就是 image/png
|
|
||||||
return new Blob([ia], {
|
|
||||||
type: mime
|
|
||||||
})
|
|
||||||
}
|
|
|
@ -1,39 +0,0 @@
|
||||||
/**
|
|
||||||
* 点击波纹效果
|
|
||||||
*
|
|
||||||
* @param {[event]} e [description]
|
|
||||||
* @param {[Object]} arg_opts [description]
|
|
||||||
* @return {[bollean]} [description]
|
|
||||||
*/
|
|
||||||
export default function(e, arg_opts) {
|
|
||||||
var opts = Object.assign({
|
|
||||||
ele: e.target, // 波纹作用元素
|
|
||||||
type: 'hit', // hit点击位置扩散center中心点扩展
|
|
||||||
bgc: 'rgba(0, 0, 0, 0.15)' // 波纹颜色
|
|
||||||
}, arg_opts)
|
|
||||||
var target = opts.ele
|
|
||||||
if (target) {
|
|
||||||
var rect = target.getBoundingClientRect()
|
|
||||||
var ripple = target.querySelector('.e-ripple')
|
|
||||||
if (!ripple) {
|
|
||||||
ripple = document.createElement('span')
|
|
||||||
ripple.className = 'e-ripple'
|
|
||||||
ripple.style.height = ripple.style.width = Math.max(rect.width, rect.height) + 'px'
|
|
||||||
target.appendChild(ripple)
|
|
||||||
} else {
|
|
||||||
ripple.className = 'e-ripple'
|
|
||||||
}
|
|
||||||
switch (opts.type) {
|
|
||||||
case 'center':
|
|
||||||
ripple.style.top = (rect.height / 2 - ripple.offsetHeight / 2) + 'px'
|
|
||||||
ripple.style.left = (rect.width / 2 - ripple.offsetWidth / 2) + 'px'
|
|
||||||
break
|
|
||||||
default:
|
|
||||||
ripple.style.top = (e.pageY - rect.top - ripple.offsetHeight / 2 - document.body.scrollTop) + 'px'
|
|
||||||
ripple.style.left = (e.pageX - rect.left - ripple.offsetWidth / 2 - document.body.scrollLeft) + 'px'
|
|
||||||
}
|
|
||||||
ripple.style.backgroundColor = opts.bgc
|
|
||||||
ripple.className = 'e-ripple z-active'
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,232 +0,0 @@
|
||||||
export default {
|
|
||||||
zh: {
|
|
||||||
hint: '点击,或拖动图片至此处',
|
|
||||||
loading: '正在上传……',
|
|
||||||
noSupported: '浏览器不支持该功能,请使用IE10以上或其他现在浏览器!',
|
|
||||||
success: '上传成功',
|
|
||||||
fail: '图片上传失败',
|
|
||||||
preview: '头像预览',
|
|
||||||
btn: {
|
|
||||||
off: '取消',
|
|
||||||
close: '关闭',
|
|
||||||
back: '上一步',
|
|
||||||
save: '保存'
|
|
||||||
},
|
|
||||||
error: {
|
|
||||||
onlyImg: '仅限图片格式',
|
|
||||||
outOfSize: '单文件大小不能超过 ',
|
|
||||||
lowestPx: '图片最低像素为(宽*高):'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
'zh-tw': {
|
|
||||||
hint: '點擊,或拖動圖片至此處',
|
|
||||||
loading: '正在上傳……',
|
|
||||||
noSupported: '瀏覽器不支持該功能,請使用IE10以上或其他現代瀏覽器!',
|
|
||||||
success: '上傳成功',
|
|
||||||
fail: '圖片上傳失敗',
|
|
||||||
preview: '頭像預覽',
|
|
||||||
btn: {
|
|
||||||
off: '取消',
|
|
||||||
close: '關閉',
|
|
||||||
back: '上一步',
|
|
||||||
save: '保存'
|
|
||||||
},
|
|
||||||
error: {
|
|
||||||
onlyImg: '僅限圖片格式',
|
|
||||||
outOfSize: '單文件大小不能超過 ',
|
|
||||||
lowestPx: '圖片最低像素為(寬*高):'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
en: {
|
|
||||||
hint: 'Click or drag the file here to upload',
|
|
||||||
loading: 'Uploading…',
|
|
||||||
noSupported: 'Browser is not supported, please use IE10+ or other browsers',
|
|
||||||
success: 'Upload success',
|
|
||||||
fail: 'Upload failed',
|
|
||||||
preview: 'Preview',
|
|
||||||
btn: {
|
|
||||||
off: 'Cancel',
|
|
||||||
close: 'Close',
|
|
||||||
back: 'Back',
|
|
||||||
save: 'Save'
|
|
||||||
},
|
|
||||||
error: {
|
|
||||||
onlyImg: 'Image only',
|
|
||||||
outOfSize: 'Image exceeds size limit: ',
|
|
||||||
lowestPx: 'Image\'s size is too low. Expected at least: '
|
|
||||||
}
|
|
||||||
},
|
|
||||||
ro: {
|
|
||||||
hint: 'Atinge sau trage fișierul aici',
|
|
||||||
loading: 'Se încarcă',
|
|
||||||
noSupported: 'Browser-ul tău nu suportă acest feature. Te rugăm încearcă cu alt browser.',
|
|
||||||
success: 'S-a încărcat cu succes',
|
|
||||||
fail: 'A apărut o problemă la încărcare',
|
|
||||||
preview: 'Previzualizează',
|
|
||||||
|
|
||||||
btn: {
|
|
||||||
off: 'Anulează',
|
|
||||||
close: 'Închide',
|
|
||||||
back: 'Înapoi',
|
|
||||||
save: 'Salvează'
|
|
||||||
},
|
|
||||||
|
|
||||||
error: {
|
|
||||||
onlyImg: 'Doar imagini',
|
|
||||||
outOfSize: 'Imaginea depășește limita de: ',
|
|
||||||
loewstPx: 'Imaginea este prea mică; Minim: '
|
|
||||||
}
|
|
||||||
},
|
|
||||||
ru: {
|
|
||||||
hint: 'Нажмите, или перетащите файл в это окно',
|
|
||||||
loading: 'Загружаю……',
|
|
||||||
noSupported: 'Ваш браузер не поддерживается, пожалуйста, используйте IE10 + или другие браузеры',
|
|
||||||
success: 'Загрузка выполнена успешно',
|
|
||||||
fail: 'Ошибка загрузки',
|
|
||||||
preview: 'Предпросмотр',
|
|
||||||
btn: {
|
|
||||||
off: 'Отменить',
|
|
||||||
close: 'Закрыть',
|
|
||||||
back: 'Назад',
|
|
||||||
save: 'Сохранить'
|
|
||||||
},
|
|
||||||
error: {
|
|
||||||
onlyImg: 'Только изображения',
|
|
||||||
outOfSize: 'Изображение превышает предельный размер: ',
|
|
||||||
lowestPx: 'Минимальный размер изображения: '
|
|
||||||
}
|
|
||||||
},
|
|
||||||
'pt-br': {
|
|
||||||
hint: 'Clique ou arraste o arquivo aqui para carregar',
|
|
||||||
loading: 'Carregando…',
|
|
||||||
noSupported: 'Browser não suportado, use o IE10+ ou outro browser',
|
|
||||||
success: 'Sucesso ao carregar imagem',
|
|
||||||
fail: 'Falha ao carregar imagem',
|
|
||||||
preview: 'Pré-visualizar',
|
|
||||||
btn: {
|
|
||||||
off: 'Cancelar',
|
|
||||||
close: 'Fechar',
|
|
||||||
back: 'Voltar',
|
|
||||||
save: 'Salvar'
|
|
||||||
},
|
|
||||||
error: {
|
|
||||||
onlyImg: 'Apenas imagens',
|
|
||||||
outOfSize: 'A imagem excede o limite de tamanho: ',
|
|
||||||
lowestPx: 'O tamanho da imagem é muito pequeno. Tamanho mínimo: '
|
|
||||||
}
|
|
||||||
},
|
|
||||||
fr: {
|
|
||||||
hint: 'Cliquez ou glissez le fichier ici.',
|
|
||||||
loading: 'Téléchargement…',
|
|
||||||
noSupported: 'Votre navigateur n\'est pas supporté. Utilisez IE10 + ou un autre navigateur s\'il vous plaît.',
|
|
||||||
success: 'Téléchargement réussit',
|
|
||||||
fail: 'Téléchargement echoué',
|
|
||||||
preview: 'Aperçu',
|
|
||||||
btn: {
|
|
||||||
off: 'Annuler',
|
|
||||||
close: 'Fermer',
|
|
||||||
back: 'Retour',
|
|
||||||
save: 'Enregistrer'
|
|
||||||
},
|
|
||||||
error: {
|
|
||||||
onlyImg: 'Image uniquement',
|
|
||||||
outOfSize: 'L\'image sélectionnée dépasse la taille maximum: ',
|
|
||||||
lowestPx: 'L\'image sélectionnée est trop petite. Dimensions attendues: '
|
|
||||||
}
|
|
||||||
},
|
|
||||||
nl: {
|
|
||||||
hint: 'Klik hier of sleep een afbeelding in dit vlak',
|
|
||||||
loading: 'Uploaden…',
|
|
||||||
noSupported: 'Je browser wordt helaas niet ondersteund. Gebruik IE10+ of een andere browser.',
|
|
||||||
success: 'Upload succesvol',
|
|
||||||
fail: 'Upload mislukt',
|
|
||||||
preview: 'Voorbeeld',
|
|
||||||
btn: {
|
|
||||||
off: 'Annuleren',
|
|
||||||
close: 'Sluiten',
|
|
||||||
back: 'Terug',
|
|
||||||
save: 'Opslaan'
|
|
||||||
},
|
|
||||||
error: {
|
|
||||||
onlyImg: 'Alleen afbeeldingen',
|
|
||||||
outOfSize: 'De afbeelding is groter dan: ',
|
|
||||||
lowestPx: 'De afbeelding is te klein! Minimale afmetingen: '
|
|
||||||
}
|
|
||||||
},
|
|
||||||
tr: {
|
|
||||||
hint: 'Tıkla veya yüklemek istediğini buraya sürükle',
|
|
||||||
loading: 'Yükleniyor…',
|
|
||||||
noSupported: 'Tarayıcı desteklenmiyor, lütfen IE10+ veya farklı tarayıcı kullanın',
|
|
||||||
success: 'Yükleme başarılı',
|
|
||||||
fail: 'Yüklemede hata oluştu',
|
|
||||||
preview: 'Önizle',
|
|
||||||
btn: {
|
|
||||||
off: 'İptal',
|
|
||||||
close: 'Kapat',
|
|
||||||
back: 'Geri',
|
|
||||||
save: 'Kaydet'
|
|
||||||
},
|
|
||||||
error: {
|
|
||||||
onlyImg: 'Sadece resim',
|
|
||||||
outOfSize: 'Resim yükleme limitini aşıyor: ',
|
|
||||||
lowestPx: 'Resmin boyutu çok küçük. En az olması gereken: '
|
|
||||||
}
|
|
||||||
},
|
|
||||||
'es-MX': {
|
|
||||||
hint: 'Selecciona o arrastra una imagen',
|
|
||||||
loading: 'Subiendo...',
|
|
||||||
noSupported: 'Tu navegador no es soportado, porfavor usa IE10+ u otros navegadores mas recientes',
|
|
||||||
success: 'Subido exitosamente',
|
|
||||||
fail: 'Sucedió un error',
|
|
||||||
preview: 'Vista previa',
|
|
||||||
btn: {
|
|
||||||
off: 'Cancelar',
|
|
||||||
close: 'Cerrar',
|
|
||||||
back: 'Atras',
|
|
||||||
save: 'Guardar'
|
|
||||||
},
|
|
||||||
error: {
|
|
||||||
onlyImg: 'Unicamente imagenes',
|
|
||||||
outOfSize: 'La imagen excede el tamaño maximo:',
|
|
||||||
lowestPx: 'La imagen es demasiado pequeño. Se espera por lo menos:'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
de: {
|
|
||||||
hint: 'Klick hier oder zieh eine Datei hier rein zum Hochladen',
|
|
||||||
loading: 'Hochladen…',
|
|
||||||
noSupported: 'Browser wird nicht unterstützt, bitte verwende IE10+ oder andere Browser',
|
|
||||||
success: 'Upload erfolgreich',
|
|
||||||
fail: 'Upload fehlgeschlagen',
|
|
||||||
preview: 'Vorschau',
|
|
||||||
btn: {
|
|
||||||
off: 'Abbrechen',
|
|
||||||
close: 'Schließen',
|
|
||||||
back: 'Zurück',
|
|
||||||
save: 'Speichern'
|
|
||||||
},
|
|
||||||
error: {
|
|
||||||
onlyImg: 'Nur Bilder',
|
|
||||||
outOfSize: 'Das Bild ist zu groß: ',
|
|
||||||
lowestPx: 'Das Bild ist zu klein. Mindestens: '
|
|
||||||
}
|
|
||||||
},
|
|
||||||
ja: {
|
|
||||||
hint: 'クリック・ドラッグしてファイルをアップロード',
|
|
||||||
loading: 'アップロード中...',
|
|
||||||
noSupported: 'このブラウザは対応されていません。IE10+かその他の主要ブラウザをお使いください。',
|
|
||||||
success: 'アップロード成功',
|
|
||||||
fail: 'アップロード失敗',
|
|
||||||
preview: 'プレビュー',
|
|
||||||
btn: {
|
|
||||||
off: 'キャンセル',
|
|
||||||
close: '閉じる',
|
|
||||||
back: '戻る',
|
|
||||||
save: '保存'
|
|
||||||
},
|
|
||||||
error: {
|
|
||||||
onlyImg: '画像のみ',
|
|
||||||
outOfSize: '画像サイズが上限を超えています。上限: ',
|
|
||||||
lowestPx: '画像が小さすぎます。最小サイズ: '
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,7 +0,0 @@
|
||||||
export default {
|
|
||||||
'jpg': 'image/jpeg',
|
|
||||||
'png': 'image/png',
|
|
||||||
'gif': 'image/gif',
|
|
||||||
'svg': 'image/svg+xml',
|
|
||||||
'psd': 'image/photoshop'
|
|
||||||
}
|
|
|
@ -1,6 +1,6 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="json-editor">
|
<div class="json-editor">
|
||||||
<textarea ref="textarea" />
|
<textarea ref="textarea"></textarea>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -15,18 +15,17 @@ import 'codemirror/addon/lint/lint'
|
||||||
import 'codemirror/addon/lint/json-lint'
|
import 'codemirror/addon/lint/json-lint'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'JsonEditor',
|
name: 'jsonEditor',
|
||||||
/* eslint-disable vue/require-prop-types */
|
|
||||||
props: ['value'],
|
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
jsonEditor: false
|
jsonEditor: false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
props: ['value'],
|
||||||
watch: {
|
watch: {
|
||||||
value(value) {
|
value(value) {
|
||||||
const editorValue = this.jsonEditor.getValue()
|
const editor_value = this.jsonEditor.getValue()
|
||||||
if (value !== editorValue) {
|
if (value !== editor_value) {
|
||||||
this.jsonEditor.setValue(JSON.stringify(this.value, null, 2))
|
this.jsonEditor.setValue(JSON.stringify(this.value, null, 2))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -54,24 +53,19 @@ export default {
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style scoped>
|
||||||
.json-editor {
|
.json-editor{
|
||||||
height: 100%;
|
height: 100%;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
}
|
||||||
::v-deep {
|
.json-editor >>> .CodeMirror {
|
||||||
.CodeMirror {
|
|
||||||
height: auto;
|
height: auto;
|
||||||
min-height: 300px;
|
min-height: 300px;
|
||||||
}
|
}
|
||||||
|
.json-editor >>> .CodeMirror-scroll{
|
||||||
.CodeMirror-scroll {
|
|
||||||
min-height: 300px;
|
min-height: 300px;
|
||||||
}
|
}
|
||||||
|
.json-editor >>> .cm-s-rubyblue span.cm-string {
|
||||||
.cm-s-rubyblue span.cm-string {
|
|
||||||
color: #F08047;
|
color: #F08047;
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|