Compare commits
No commits in common. "master" and "webpack3" have entirely different histories.
|
@ -0,0 +1,17 @@
|
||||||
|
{
|
||||||
|
"presets": [
|
||||||
|
["env", {
|
||||||
|
"modules": false,
|
||||||
|
"targets": {
|
||||||
|
"browsers": ["> 1%", "last 2 versions", "not ie <= 8"]
|
||||||
|
}
|
||||||
|
}],
|
||||||
|
"stage-2"
|
||||||
|
],
|
||||||
|
"plugins": ["transform-vue-jsx", "transform-runtime"],
|
||||||
|
"env": {
|
||||||
|
"development":{
|
||||||
|
"plugins": ["dynamic-import-node"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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
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:
|
|
|
@ -6,8 +6,8 @@ yarn-debug.log*
|
||||||
yarn-error.log*
|
yarn-error.log*
|
||||||
**/*.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
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
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
|
|
127
README.md
127
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.3.2-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,113 +18,64 @@
|
||||||
<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](http://panjiachen.github.io/vue-element-admin) is a front-end management background integration solution. It based on [vue](https://github.com/vuejs/vue) and use the UI Toolkit [element](https://github.com/ElemeFE/element).
|
||||||
|
|
||||||
[vue-element-admin](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.
|
It is a magical vue admin based on the newest development stack of vue, built-in i18n solution, typical templates for enterprise applications, lots of awesome features. It helps you build a large complex Single-Page Applications. I believe whatever your needs are, this project will help you.
|
||||||
|
|
||||||
- [Preview](https://panjiachen.github.io/vue-element-admin)
|
- [Preview](http://panjiachen.github.io/vue-element-admin)
|
||||||
|
|
||||||
- [Documentation](https://panjiachen.github.io/vue-element-admin-site/)
|
- [Documentation](https://panjiachen.github.io/vue-element-admin-site/)
|
||||||
|
|
||||||
- [Gitter](https://gitter.im/vue-element-admin/discuss)
|
- [Gitter](https://gitter.im/vue-element-admin/discuss)
|
||||||
|
|
||||||
- [Donate](https://panjiachen.github.io/vue-element-admin-site/donate/)
|
|
||||||
|
|
||||||
- [Wiki](https://github.com/PanJiaChen/vue-element-admin/wiki)
|
- [Wiki](https://github.com/PanJiaChen/vue-element-admin/wiki)
|
||||||
|
|
||||||
|
- [Donate](https://panjiachen.github.io/vue-element-admin-site/donate/)
|
||||||
|
|
||||||
- [Gitee](https://panjiachen.gitee.io/vue-element-admin/) 国内用户可访问该地址在线预览
|
- [Gitee](https://panjiachen.gitee.io/vue-element-admin/) 国内用户可访问该地址在线预览
|
||||||
|
|
||||||
- Base template recommends using: [vue-admin-template](https://github.com/PanJiaChen/vue-admin-template)
|
**This project is positioned as a background integration solution and is not suitable for secondary development as a basic 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**
|
- Base template recommends using: [vueAdmin-template](https://github.com/PanJiaChen/vueAdmin-template)
|
||||||
|
- Desktop: [electron-vue-admin](https://github.com/PanJiaChen/electron-vue-admin)
|
||||||
**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/), [axios](https://github.com/axios/axios) and [element-ui](https://github.com/ElemeFE/element), all request data is simulated using [Mock.js](https://github.com/nuysoft/Mock).
|
||||||
Understanding and learning this knowledge in advance will greatly help the use of this project.
|
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 does not support low version browsers (e.g. IE). Please add polyfill yourself if you need them.**
|
||||||
|
|
||||||
<p align="center">
|
**Note: This project uses element-ui@2.3.0+ version, so the minimum compatible vue@2.5.0+**
|
||||||
|
|
||||||
|
<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
|
- Page permission
|
||||||
- Directive permission
|
- Directive permission
|
||||||
- Permission configuration page
|
|
||||||
- Two-step login
|
- Two-step login
|
||||||
|
|
||||||
- Multi-environment build
|
- Multi-environment build
|
||||||
- Develop (dev)
|
- dev sit stage prod
|
||||||
- sit
|
|
||||||
- Stage Test (stage)
|
|
||||||
- Production (prod)
|
|
||||||
|
|
||||||
- Global Features
|
- Global Features
|
||||||
- I18n
|
- I18n
|
||||||
- Multiple dynamic themes
|
- Multiple dynamic themes
|
||||||
- Dynamic sidebar (supports multi-level routing)
|
- Dynamic sidebar (supports multi-level routing)
|
||||||
- Dynamic breadcrumb
|
- Dynamic breadcrumb
|
||||||
- Tags-view (Tab page Support right-click operation)
|
- Tags-view(Tab page Support right-click operation)
|
||||||
- Svg Sprite
|
- Svg Sprite
|
||||||
- Mock data
|
- Mock data
|
||||||
- Screenfull
|
- Screenfull
|
||||||
|
@ -137,13 +88,14 @@ Become a sponsor and get your logo on our README on GitHub with a link to your s
|
||||||
|
|
||||||
- Excel
|
- Excel
|
||||||
- Export Excel
|
- Export Excel
|
||||||
|
- Export zip
|
||||||
- Upload Excel
|
- Upload Excel
|
||||||
- Visualization Excel
|
- Visualization Excel
|
||||||
- Export zip
|
|
||||||
|
|
||||||
- Table
|
- Table
|
||||||
- Dynamic Table
|
- Dynamic Table
|
||||||
- Drag And Drop Table
|
- Drag And Drop Table
|
||||||
|
- Tree Table
|
||||||
- Inline Edit Table
|
- Inline Edit Table
|
||||||
|
|
||||||
- Error Page
|
- Error Page
|
||||||
|
@ -154,7 +106,6 @@ Become a sponsor and get your logo on our README on GitHub with a link to your s
|
||||||
- Avatar Upload
|
- Avatar Upload
|
||||||
- Back To Top
|
- Back To Top
|
||||||
- Drag Dialog
|
- Drag Dialog
|
||||||
- Drag Select
|
|
||||||
- Drag Kanban
|
- Drag Kanban
|
||||||
- Drag List
|
- Drag List
|
||||||
- SplitPane
|
- SplitPane
|
||||||
|
@ -166,7 +117,7 @@ Become a sponsor and get your logo on our README on GitHub with a link to your s
|
||||||
- Error Log
|
- Error Log
|
||||||
- Dashboard
|
- Dashboard
|
||||||
- Guide Page
|
- Guide Page
|
||||||
- ECharts
|
- Echarts
|
||||||
- Clipboard
|
- Clipboard
|
||||||
- Markdown to html
|
- Markdown to html
|
||||||
```
|
```
|
||||||
|
@ -177,9 +128,6 @@ Become a sponsor and get your logo on our README on GitHub with a link to your s
|
||||||
# clone the project
|
# clone the project
|
||||||
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,46 +135,41 @@ 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/guide/essentials/deploy.html) 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)
|
||||||
|
@ -235,14 +178,6 @@ If you find this project useful, you can buy author a glass of juice :tropical_d
|
||||||
|
|
||||||
[Buy me a coffee](https://www.buymeacoffee.com/Pan)
|
[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)
|
||||||
|
|
166
README.zh-CN.md
166
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.3.2-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,121 +18,69 @@
|
||||||
<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](http://panjiachen.github.io/vue-element-admin) 是一个后台集成解决方案,它基于 [vue](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/zh/)
|
||||||
|
|
||||||
- [Gitter 讨论组](https://gitter.im/vue-element-admin/discuss)
|
- [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)
|
- [Wiki](https://github.com/PanJiaChen/vue-element-admin/wiki)
|
||||||
|
|
||||||
- [Gitee](https://panjiachen.gitee.io/vue-element-admin/) 在线预览(国内用户可访问该地址)
|
- [Donate](https://panjiachen.github.io/vue-element-admin-site/zh/donate/)
|
||||||
|
|
||||||
- [国内访问文档](https://panjiachen.gitee.io/vue-element-admin-site/zh/) 文档(方便没翻墙的用户查看)
|
- [Gitee](https://panjiachen.gitee.io/vue-element-admin/) 国内用户可访问该地址在线预览
|
||||||
|
|
||||||
- 基础模板建议使用: [vue-admin-template](https://github.com/PanJiaChen/vue-admin-template)
|
**本项目的定位是后台集成方案,不适合当基础模板来开发。**
|
||||||
- 桌面端: [electron-vue-admin](https://github.com/PanJiaChen/electron-vue-admin)
|
- 模板建议使用: [vueAdmin-template](https://github.com/PanJiaChen/vueAdmin-template)
|
||||||
- Typescript 版: [vue-typescript-admin-template](https://github.com/Armour/vue-typescript-admin-template) (鸣谢: [@Armour](https://github.com/Armour))
|
- 桌面端: [electron-vue-admin](https://github.com/PanJiaChen/electron-vue-admin)
|
||||||
- [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/) 、[axios](https://github.com/axios/axios) 和 [element-ui](https://github.com/ElemeFE/element),所有的请求数据都使用[Mock.js](https://github.com/nuysoft/Mock)模拟,提前了解和学习这些知识会对使用本项目有很大的帮助。
|
||||||
|
|
||||||
同时配套了系列教程文章,如何从零构建后一个完整的后台项目,建议大家先看完这些文章再来实践本项目
|
同时配套一个系列的教程文章,如何从零构建后一个完整的后台项目,建议大家先看完这些文章再来实践本项目
|
||||||
|
- [手摸手,带你用 vue 撸后台 系列一(基础篇)](https://juejin.im/post/59097cd7a22b9d0065fb61d2)
|
||||||
|
- [手摸手,带你用 vue 撸后台 系列二(登录权限篇)](https://juejin.im/post/591aa14f570c35006961acac)
|
||||||
|
- [手摸手,带你用 vue 撸后台 系列三 (实战篇)](https://juejin.im/post/593121aa0ce4630057f70d35)
|
||||||
|
- [手摸手,带你用 vue 撸后台 系列四(vueAdmin 一个极简的后台基础模板)](https://juejin.im/post/595b4d776fb9a06bbe7dba56)
|
||||||
|
- [手摸手,带你封装一个 vue component](https://segmentfault.com/a/1190000009090836)
|
||||||
|
- [手摸手,带你优雅的使用 icon](https://juejin.im/post/59bb864b5188257e7a427c09)
|
||||||
|
- [手摸手,带你用合理的姿势使用webpack4(上)](https://juejin.im/post/5b56909a518825195f499806)
|
||||||
|
- [手摸手,带你用合理的姿势使用webpack4(下)](https://juejin.im/post/5b5d6d6f6fb9a04fea58aabc)
|
||||||
|
|
||||||
- [手摸手,带你用 vue 撸后台 系列一(基础篇)](https://juejin.im/post/59097cd7a22b9d0065fb61d2)
|
或者加入该群主 **[圈子](https://jianshiapp.com/circles/1209)** 楼主会经常分享一些技术相关的东西
|
||||||
- [手摸手,带你用 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**
|
**如有问题请先看上述使用文档和文章,若不能满足,欢迎 issue 和 pr**
|
||||||
|
|
||||||
[![Edit on CodeSandbox](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/s/github/PanJiaChen/vue-element-admin/tree/CodeSandbox)
|
**本项目并不是一个脚手架,更倾向于是一个集成解决方案**
|
||||||
|
|
||||||
<p align="center">
|
**注意:该项目使用 element-ui@2.3.0+ 版本,所以最低兼容 vue@2.5.0+**
|
||||||
|
|
||||||
|
**该项目不支持低版本浏览器(如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
|
- dev sit stage prod
|
||||||
- sit
|
|
||||||
- stage
|
|
||||||
- prod
|
|
||||||
|
|
||||||
- 全局功能
|
- 全局功能
|
||||||
- 国际化多语言
|
- 国际化多语言
|
||||||
|
@ -141,7 +89,7 @@ Become a sponsor and get your logo on our README on GitHub with a link to your s
|
||||||
- 动态面包屑
|
- 动态面包屑
|
||||||
- 快捷导航(标签页)
|
- 快捷导航(标签页)
|
||||||
- Svg Sprite 图标
|
- Svg Sprite 图标
|
||||||
- 本地/后端 mock 数据
|
- 本地mock数据
|
||||||
- Screenfull全屏
|
- Screenfull全屏
|
||||||
- 自适应收缩侧边栏
|
- 自适应收缩侧边栏
|
||||||
|
|
||||||
|
@ -152,13 +100,14 @@ Become a sponsor and get your logo on our README on GitHub with a link to your s
|
||||||
|
|
||||||
- Excel
|
- Excel
|
||||||
- 导出excel
|
- 导出excel
|
||||||
|
- 导出zip
|
||||||
- 导入excel
|
- 导入excel
|
||||||
- 前端可视化excel
|
- 前端可视化excel
|
||||||
- 导出zip
|
|
||||||
|
|
||||||
- 表格
|
- 表格
|
||||||
- 动态表格
|
- 动态表格
|
||||||
- 拖拽表格
|
- 拖拽表格
|
||||||
|
- 树形表格
|
||||||
- 内联编辑
|
- 内联编辑
|
||||||
|
|
||||||
- 错误页面
|
- 错误页面
|
||||||
|
@ -169,7 +118,6 @@ Become a sponsor and get your logo on our README on GitHub with a link to your s
|
||||||
- 头像上传
|
- 头像上传
|
||||||
- 返回顶部
|
- 返回顶部
|
||||||
- 拖拽Dialog
|
- 拖拽Dialog
|
||||||
- 拖拽Select
|
|
||||||
- 拖拽看板
|
- 拖拽看板
|
||||||
- 列表拖拽
|
- 列表拖拽
|
||||||
- SplitPane
|
- SplitPane
|
||||||
|
@ -181,91 +129,65 @@ Become a sponsor and get your logo on our README on GitHub with a link to your s
|
||||||
- 错误日志
|
- 错误日志
|
||||||
- Dashboard
|
- Dashboard
|
||||||
- 引导页
|
- 引导页
|
||||||
- ECharts 图表
|
- Echarts 图表
|
||||||
- Clipboard(剪贴复制)
|
- Clipboard(剪贴复制)
|
||||||
- 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/zh/)
|
||||||
|
|
||||||
## 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,56 @@
|
||||||
|
'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')
|
||||||
|
var connect = require('connect');
|
||||||
|
var serveStatic = require('serve-static')
|
||||||
|
|
||||||
|
const 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) {
|
||||||
|
const port = 9526
|
||||||
|
const host = "http://localhost:" + port
|
||||||
|
const basePath = config.build.assetsPublicPath
|
||||||
|
const app = connect()
|
||||||
|
|
||||||
|
app.use(basePath, serveStatic('./dist', {
|
||||||
|
'index': ['index.html', '/']
|
||||||
|
}))
|
||||||
|
|
||||||
|
app.listen(port, function () {
|
||||||
|
console.log(chalk.green(`> Listening at http://localhost:${port}${basePath}`))
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
|
@ -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}`)
|
|
||||||
}
|
|
Binary file not shown.
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,100 @@
|
||||||
|
'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: {
|
||||||
|
'@': 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,91 @@
|
||||||
|
'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
|
||||||
|
|
||||||
|
// can be overwritten by process.env.HOST
|
||||||
|
// if you want dev by ip, please set host: '0.0.0.0'
|
||||||
|
host: 'localhost',
|
||||||
|
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
|
||||||
|
* You will need to set this if you plan to deploy your site under a sub path,
|
||||||
|
* for example GitHub pages. If you plan to deploy your site to https://foo.github.io/bar/,
|
||||||
|
* then assetsPublicPath should be set to "/bar/".
|
||||||
|
* In most cases please use '/' !!!
|
||||||
|
*/
|
||||||
|
assetsPublicPath: '/vue-element-admin/', // If you are deployed on the root path, please use '/'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 |
|
@ -5,10 +5,10 @@
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
||||||
<meta name="renderer" content="webkit">
|
<meta name="renderer" content="webkit">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
|
<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>vue-element-admin</title>
|
||||||
<title><%= webpackConfig.name %></title>
|
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
<script src=<%= htmlWebpackPlugin.options.path %>/tinymce4.7.5/tinymce.min.js></script>
|
||||||
<div id="app"></div>
|
<div id="app"></div>
|
||||||
<!-- built files will be auto injected -->
|
<!-- built files will be auto injected -->
|
||||||
</body>
|
</body>
|
|
@ -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
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
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
|
|
||||||
}
|
|
209
package.json
209
package.json
|
@ -1,111 +1,126 @@
|
||||||
{
|
{
|
||||||
"name": "vue-element-admin",
|
"name": "vue-element-admin",
|
||||||
"version": "4.4.0",
|
"version": "3.7.3",
|
||||||
"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>",
|
||||||
"scripts": {
|
|
||||||
"dev": "vue-cli-service serve",
|
|
||||||
"lint": "eslint --ext .js,.vue src",
|
|
||||||
"build:prod": "vue-cli-service build",
|
|
||||||
"build:stage": "vue-cli-service build --mode staging",
|
|
||||||
"preview": "node build/index.js --preview",
|
|
||||||
"new": "plop",
|
|
||||||
"svgo": "svgo -f src/icons/svg --config=src/icons/svgo.yml",
|
|
||||||
"test:unit": "jest --clearCache && vue-cli-service test:unit",
|
|
||||||
"test:ci": "npm run lint && npm run test:unit"
|
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"axios": "0.18.1",
|
|
||||||
"clipboard": "2.0.4",
|
|
||||||
"codemirror": "5.45.0",
|
|
||||||
"core-js": "3.6.5",
|
|
||||||
"driver.js": "0.9.5",
|
|
||||||
"dropzone": "5.5.1",
|
|
||||||
"echarts": "4.2.1",
|
|
||||||
"element-ui": "2.13.2",
|
|
||||||
"file-saver": "2.0.1",
|
|
||||||
"fuse.js": "3.4.4",
|
|
||||||
"js-cookie": "2.2.0",
|
|
||||||
"jsonlint": "1.6.3",
|
|
||||||
"jszip": "3.2.1",
|
|
||||||
"normalize.css": "7.0.0",
|
|
||||||
"nprogress": "0.2.0",
|
|
||||||
"path-to-regexp": "2.4.0",
|
|
||||||
"screenfull": "4.2.0",
|
|
||||||
"script-loader": "0.7.2",
|
|
||||||
"sortablejs": "1.8.4",
|
|
||||||
"tui-editor": "1.3.3",
|
|
||||||
"vue": "2.6.10",
|
|
||||||
"vue-count-to": "1.0.13",
|
|
||||||
"vue-router": "3.0.2",
|
|
||||||
"vue-splitpane": "1.0.4",
|
|
||||||
"vuedraggable": "2.20.0",
|
|
||||||
"vuex": "3.1.0",
|
|
||||||
"xlsx": "0.14.1"
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
|
||||||
"@vue/cli-plugin-babel": "4.4.4",
|
|
||||||
"@vue/cli-plugin-eslint": "4.4.4",
|
|
||||||
"@vue/cli-plugin-unit-jest": "4.4.4",
|
|
||||||
"@vue/cli-service": "4.4.4",
|
|
||||||
"@vue/test-utils": "1.0.0-beta.29",
|
|
||||||
"autoprefixer": "9.5.1",
|
|
||||||
"babel-eslint": "10.1.0",
|
|
||||||
"babel-jest": "23.6.0",
|
|
||||||
"babel-plugin-dynamic-import-node": "2.3.3",
|
|
||||||
"chalk": "2.4.2",
|
|
||||||
"chokidar": "2.1.5",
|
|
||||||
"connect": "3.6.6",
|
|
||||||
"eslint": "6.7.2",
|
|
||||||
"eslint-plugin-vue": "6.2.2",
|
|
||||||
"html-webpack-plugin": "3.2.0",
|
|
||||||
"husky": "1.3.1",
|
|
||||||
"lint-staged": "8.1.5",
|
|
||||||
"mockjs": "1.0.1-beta3",
|
|
||||||
"plop": "2.3.0",
|
|
||||||
"runjs": "4.3.2",
|
|
||||||
"sass": "1.26.2",
|
|
||||||
"sass-loader": "8.0.2",
|
|
||||||
"script-ext-html-webpack-plugin": "2.1.3",
|
|
||||||
"serve-static": "1.13.2",
|
|
||||||
"svg-sprite-loader": "4.1.3",
|
|
||||||
"svgo": "1.2.0",
|
|
||||||
"vue-template-compiler": "2.6.10"
|
|
||||||
},
|
|
||||||
"browserslist": [
|
|
||||||
"> 1%",
|
|
||||||
"last 2 versions"
|
|
||||||
],
|
|
||||||
"bugs": {
|
|
||||||
"url": "https://github.com/PanJiaChen/vue-element-admin/issues"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=8.9",
|
|
||||||
"npm": ">= 3.0.0"
|
|
||||||
},
|
|
||||||
"keywords": [
|
|
||||||
"vue",
|
|
||||||
"admin",
|
|
||||||
"dashboard",
|
|
||||||
"element-ui",
|
|
||||||
"boilerplate",
|
|
||||||
"admin-template",
|
|
||||||
"management-system"
|
|
||||||
],
|
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"scripts": {
|
||||||
|
"dev": "cross-env BABEL_ENV=development 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",
|
||||||
|
"test": "npm run lint",
|
||||||
|
"precommit": "lint-staged"
|
||||||
|
},
|
||||||
"lint-staged": {
|
"lint-staged": {
|
||||||
"src/**/*.{js,vue}": [
|
"src/**/*.{js,vue}": [
|
||||||
"eslint --fix",
|
"eslint --fix",
|
||||||
"git add"
|
"git add"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"husky": {
|
"keywords": [
|
||||||
"hooks": {
|
"vue",
|
||||||
"pre-commit": "lint-staged"
|
"element-ui",
|
||||||
}
|
"admin",
|
||||||
},
|
"management-system",
|
||||||
|
"admin-template"
|
||||||
|
],
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "git+https://github.com/PanJiaChen/vue-element-admin.git"
|
"url": "git+https://github.com/PanJiaChen/vue-element-admin.git"
|
||||||
}
|
},
|
||||||
|
"bugs": {
|
||||||
|
"url": "https://github.com/PanJiaChen/vue-element-admin/issues"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"axios": "0.17.1",
|
||||||
|
"clipboard": "1.7.1",
|
||||||
|
"codemirror": "5.32.0",
|
||||||
|
"connect": "3.6.6",
|
||||||
|
"driver.js": "0.5.2",
|
||||||
|
"dropzone": "5.2.0",
|
||||||
|
"echarts": "3.8.5",
|
||||||
|
"element-ui": "2.3.2",
|
||||||
|
"file-saver": "1.3.3",
|
||||||
|
"font-awesome": "4.7.0",
|
||||||
|
"js-cookie": "2.2.0",
|
||||||
|
"jsonlint": "1.6.3",
|
||||||
|
"jszip": "3.1.5",
|
||||||
|
"mockjs": "1.0.1-beta3",
|
||||||
|
"normalize.css": "7.0.0",
|
||||||
|
"nprogress": "0.2.0",
|
||||||
|
"screenfull": "3.3.2",
|
||||||
|
"serve-static": "1.13.2",
|
||||||
|
"showdown": "1.8.5",
|
||||||
|
"simplemde": "1.11.2",
|
||||||
|
"sortablejs": "1.7.0",
|
||||||
|
"vue": "2.5.10",
|
||||||
|
"vue-count-to": "1.0.13",
|
||||||
|
"vue-i18n": "7.3.2",
|
||||||
|
"vue-multiselect": "2.0.8",
|
||||||
|
"vue-router": "3.0.1",
|
||||||
|
"vue-splitpane": "1.0.2",
|
||||||
|
"vuedraggable": "^2.16.0",
|
||||||
|
"vuex": "3.0.1",
|
||||||
|
"xlsx": "^0.11.16"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"autoprefixer": "7.2.3",
|
||||||
|
"babel-core": "6.26.0",
|
||||||
|
"babel-eslint": "8.0.3",
|
||||||
|
"babel-helper-vue-jsx-merge-props": "2.0.3",
|
||||||
|
"babel-loader": "7.1.2",
|
||||||
|
"babel-plugin-dynamic-import-node": "^1.2.0",
|
||||||
|
"babel-plugin-syntax-jsx": "6.18.0",
|
||||||
|
"babel-plugin-transform-runtime": "6.23.0",
|
||||||
|
"babel-plugin-transform-vue-jsx": "3.5.0",
|
||||||
|
"babel-preset-env": "1.6.1",
|
||||||
|
"babel-preset-stage-2": "6.24.1",
|
||||||
|
"chalk": "2.3.0",
|
||||||
|
"copy-webpack-plugin": "4.3.0",
|
||||||
|
"cross-env": "5.1.1",
|
||||||
|
"css-loader": "0.28.7",
|
||||||
|
"eslint": "4.13.1",
|
||||||
|
"eslint-friendly-formatter": "3.0.0",
|
||||||
|
"eslint-loader": "1.9.0",
|
||||||
|
"eslint-plugin-html": "4.0.1",
|
||||||
|
"extract-text-webpack-plugin": "3.0.2",
|
||||||
|
"file-loader": "1.1.5",
|
||||||
|
"friendly-errors-webpack-plugin": "1.6.1",
|
||||||
|
"html-webpack-plugin": "2.30.1",
|
||||||
|
"husky": "0.14.3",
|
||||||
|
"lint-staged": "7.2.0",
|
||||||
|
"node-notifier": "5.1.2",
|
||||||
|
"node-sass": "^4.7.2",
|
||||||
|
"optimize-css-assets-webpack-plugin": "3.2.0",
|
||||||
|
"ora": "1.3.0",
|
||||||
|
"portfinder": "1.0.13",
|
||||||
|
"postcss-import": "11.0.0",
|
||||||
|
"postcss-loader": "2.0.9",
|
||||||
|
"postcss-url": "7.3.0",
|
||||||
|
"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.7.2",
|
||||||
|
"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": [
|
||||||
|
"> 1%",
|
||||||
|
"last 2 versions",
|
||||||
|
"not ie <= 8"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,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,7 +2,7 @@ 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
|
||||||
})
|
})
|
||||||
|
@ -10,7 +10,7 @@ export function fetchList(query) {
|
||||||
|
|
||||||
export function fetchArticle(id) {
|
export function fetchArticle(id) {
|
||||||
return request({
|
return request({
|
||||||
url: '/vue-element-admin/article/detail',
|
url: '/article/detail',
|
||||||
method: 'get',
|
method: 'get',
|
||||||
params: { id }
|
params: { id }
|
||||||
})
|
})
|
||||||
|
@ -18,7 +18,7 @@ export function fetchArticle(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 +26,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 +34,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>
|
||||||
|
@ -40,8 +45,7 @@ export default {
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
visible: false,
|
visible: false,
|
||||||
interval: null,
|
interval: null
|
||||||
isMoving: false
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
|
@ -58,16 +62,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 +84,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,152 @@
|
||||||
|
<template>
|
||||||
|
<div :class="className" :id="id" :style="{height:height,width:width}"></div>
|
||||||
|
</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',
|
||||||
|
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,5 +1,5 @@
|
||||||
<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>
|
||||||
|
@ -80,8 +80,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,5 +1,5 @@
|
||||||
<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>
|
||||||
|
@ -75,10 +75,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 +1,15 @@
|
||||||
import { debounce } from '@/utils'
|
import { debounce } from '@/utils'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
$_sidebarElm: null,
|
|
||||||
$_resizeHandler: null
|
|
||||||
}
|
|
||||||
},
|
|
||||||
mounted() {
|
mounted() {
|
||||||
this.initListener()
|
this.__resizeHanlder = debounce(() => {
|
||||||
},
|
if (this.chart) {
|
||||||
activated() {
|
this.chart.resize()
|
||||||
if (!this.$_resizeHandler) {
|
|
||||||
// avoid duplication init
|
|
||||||
this.initListener()
|
|
||||||
}
|
}
|
||||||
|
}, 100)
|
||||||
// when keep-alive chart activated, auto resize
|
window.addEventListener('resize', this.__resizeHanlder)
|
||||||
this.resize()
|
|
||||||
},
|
},
|
||||||
beforeDestroy() {
|
beforeDestroy() {
|
||||||
this.destroyListener()
|
window.removeEventListener('resize', this.__resizeHanlder)
|
||||||
},
|
|
||||||
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;"
|
||||||
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="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>
|
|
File diff suppressed because it is too large
Load Diff
|
@ -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>
|
||||||
|
|
|
@ -1,26 +1,23 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="board-column">
|
<div class="board-column">
|
||||||
<div class="board-column-header">
|
<div class="board-column-header">
|
||||||
{{ headerText }}
|
{{headerText}}
|
||||||
</div>
|
</div>
|
||||||
<draggable
|
<draggable
|
||||||
:list="list"
|
|
||||||
v-bind="$attrs"
|
|
||||||
class="board-column-content"
|
class="board-column-content"
|
||||||
:set-data="setData"
|
:list="list"
|
||||||
>
|
:options="options">
|
||||||
<div v-for="element in list" :key="element.id" class="board-item">
|
<div class="board-item" v-for="element in list" :key="element.id">
|
||||||
{{ element.name }} {{ element.id }}
|
{{element.name}} {{element.id}}
|
||||||
</div>
|
</div>
|
||||||
</draggable>
|
</draggable>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import draggable from 'vuedraggable'
|
import draggable from 'vuedraggable'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'DragKanbanDemo',
|
name: 'dragKanban-demo',
|
||||||
components: {
|
components: {
|
||||||
draggable
|
draggable
|
||||||
},
|
},
|
||||||
|
@ -41,17 +38,10 @@ export default {
|
||||||
return []
|
return []
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
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 lang="scss">
|
||||||
.board-column {
|
.board-column {
|
||||||
min-width: 300px;
|
min-width: 300px;
|
||||||
min-height: 100px;
|
min-height: 100px;
|
||||||
|
@ -91,7 +81,7 @@ export default {
|
||||||
line-height: 54px;
|
line-height: 54px;
|
||||||
padding: 5px 10px;
|
padding: 5px 10px;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
box-shadow: 0px 1px 3px 0 rgba(0, 0, 0, 0.2);
|
box-shadow: 0px 1px 3px 0 rgba(0,0,0,0.2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,41 @@
|
||||||
|
<template>
|
||||||
|
<el-dropdown trigger="click" class='international' @command="handleSetLanguage">
|
||||||
|
<div>
|
||||||
|
<svg-icon class-name='international-icon' icon-class="language" />
|
||||||
|
</div>
|
||||||
|
<el-dropdown-menu slot="dropdown">
|
||||||
|
<el-dropdown-item command="zh" :disabled="language==='zh'">中文</el-dropdown-item>
|
||||||
|
<el-dropdown-item command="en" :disabled="language==='en'">English</el-dropdown-item>
|
||||||
|
</el-dropdown-menu>
|
||||||
|
</el-dropdown>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
computed: {
|
||||||
|
language() {
|
||||||
|
return this.$store.getters.language
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
handleSetLanguage(lang) {
|
||||||
|
this.$i18n.locale = lang
|
||||||
|
this.$store.dispatch('setLanguage', lang)
|
||||||
|
this.$message({
|
||||||
|
message: 'switch language success',
|
||||||
|
type: 'success'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.international-icon {
|
||||||
|
font-size: 20px;
|
||||||
|
cursor: pointer;
|
||||||
|
vertical-align: -5px!important;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
|
|
@ -1,109 +1,28 @@
|
||||||
<template>
|
<template>
|
||||||
<div :class="computedClasses" class="material-input__component">
|
<div class="material-input__component" :class="computedClasses">
|
||||||
<div :class="{iconClass:icon}">
|
<div :class="{iconClass:icon}">
|
||||||
<i v-if="icon" :class="['el-icon-' + icon]" class="el-input__icon material-input__icon" />
|
<i class="el-input__icon material-input__icon" :class="['el-icon-' + icon]" v-if="icon"></i>
|
||||||
<input
|
<input v-if="type === 'email'" type="email" class="material-input" :name="name" :placeholder="fillPlaceHolder" v-model="currentValue"
|
||||||
v-if="type === 'email'"
|
:readonly="readonly" :disabled="disabled" :autoComplete="autoComplete" :required="required" @focus="handleMdFocus"
|
||||||
v-model="currentValue"
|
@blur="handleMdBlur" @input="handleModelInput">
|
||||||
:name="name"
|
<input v-if="type === 'url'" type="url" class="material-input" :name="name" :placeholder="fillPlaceHolder" v-model="currentValue"
|
||||||
:placeholder="fillPlaceHolder"
|
:readonly="readonly" :disabled="disabled" :autoComplete="autoComplete" :required="required" @focus="handleMdFocus"
|
||||||
:readonly="readonly"
|
@blur="handleMdBlur" @input="handleModelInput">
|
||||||
:disabled="disabled"
|
<input v-if="type === 'number'" type="number" class="material-input" :name="name" :placeholder="fillPlaceHolder" v-model="currentValue"
|
||||||
:autocomplete="autoComplete"
|
:step="step" :readonly="readonly" :disabled="disabled" :autoComplete="autoComplete" :max="max" :min="min" :minlength="minlength"
|
||||||
:required="required"
|
:maxlength="maxlength" :required="required" @focus="handleMdFocus" @blur="handleMdBlur" @input="handleModelInput">
|
||||||
type="email"
|
<input v-if="type === 'password'" type="password" class="material-input" :name="name" :placeholder="fillPlaceHolder" v-model="currentValue"
|
||||||
class="material-input"
|
:readonly="readonly" :disabled="disabled" :autoComplete="autoComplete" :max="max" :min="min" :required="required" @focus="handleMdFocus"
|
||||||
@focus="handleMdFocus"
|
@blur="handleMdBlur" @input="handleModelInput">
|
||||||
@blur="handleMdBlur"
|
<input v-if="type === 'tel'" type="tel" class="material-input" :name="name" :placeholder="fillPlaceHolder" v-model="currentValue"
|
||||||
@input="handleModelInput"
|
:readonly="readonly" :disabled="disabled" :autoComplete="autoComplete" :required="required" @focus="handleMdFocus"
|
||||||
>
|
@blur="handleMdBlur" @input="handleModelInput">
|
||||||
<input
|
<input v-if="type === 'text'" type="text" class="material-input" :name="name" :placeholder="fillPlaceHolder" v-model="currentValue"
|
||||||
v-if="type === 'url'"
|
:readonly="readonly" :disabled="disabled" :autoComplete="autoComplete" :minlength="minlength" :maxlength="maxlength"
|
||||||
v-model="currentValue"
|
:required="required" @focus="handleMdFocus" @blur="handleMdBlur" @input="handleModelInput">
|
||||||
:name="name"
|
<span class="material-input-bar"></span>
|
||||||
:placeholder="fillPlaceHolder"
|
|
||||||
:readonly="readonly"
|
|
||||||
:disabled="disabled"
|
|
||||||
:autocomplete="autoComplete"
|
|
||||||
:required="required"
|
|
||||||
type="url"
|
|
||||||
class="material-input"
|
|
||||||
@focus="handleMdFocus"
|
|
||||||
@blur="handleMdBlur"
|
|
||||||
@input="handleModelInput"
|
|
||||||
>
|
|
||||||
<input
|
|
||||||
v-if="type === 'number'"
|
|
||||||
v-model="currentValue"
|
|
||||||
:name="name"
|
|
||||||
:placeholder="fillPlaceHolder"
|
|
||||||
:step="step"
|
|
||||||
:readonly="readonly"
|
|
||||||
:disabled="disabled"
|
|
||||||
:autocomplete="autoComplete"
|
|
||||||
:max="max"
|
|
||||||
:min="min"
|
|
||||||
:minlength="minlength"
|
|
||||||
:maxlength="maxlength"
|
|
||||||
:required="required"
|
|
||||||
type="number"
|
|
||||||
class="material-input"
|
|
||||||
@focus="handleMdFocus"
|
|
||||||
@blur="handleMdBlur"
|
|
||||||
@input="handleModelInput"
|
|
||||||
>
|
|
||||||
<input
|
|
||||||
v-if="type === 'password'"
|
|
||||||
v-model="currentValue"
|
|
||||||
:name="name"
|
|
||||||
:placeholder="fillPlaceHolder"
|
|
||||||
:readonly="readonly"
|
|
||||||
:disabled="disabled"
|
|
||||||
:autocomplete="autoComplete"
|
|
||||||
:max="max"
|
|
||||||
:min="min"
|
|
||||||
:required="required"
|
|
||||||
type="password"
|
|
||||||
class="material-input"
|
|
||||||
@focus="handleMdFocus"
|
|
||||||
@blur="handleMdBlur"
|
|
||||||
@input="handleModelInput"
|
|
||||||
>
|
|
||||||
<input
|
|
||||||
v-if="type === 'tel'"
|
|
||||||
v-model="currentValue"
|
|
||||||
:name="name"
|
|
||||||
:placeholder="fillPlaceHolder"
|
|
||||||
:readonly="readonly"
|
|
||||||
:disabled="disabled"
|
|
||||||
:autocomplete="autoComplete"
|
|
||||||
:required="required"
|
|
||||||
type="tel"
|
|
||||||
class="material-input"
|
|
||||||
@focus="handleMdFocus"
|
|
||||||
@blur="handleMdBlur"
|
|
||||||
@input="handleModelInput"
|
|
||||||
>
|
|
||||||
<input
|
|
||||||
v-if="type === 'text'"
|
|
||||||
v-model="currentValue"
|
|
||||||
:name="name"
|
|
||||||
:placeholder="fillPlaceHolder"
|
|
||||||
:readonly="readonly"
|
|
||||||
:disabled="disabled"
|
|
||||||
:autocomplete="autoComplete"
|
|
||||||
:minlength="minlength"
|
|
||||||
:maxlength="maxlength"
|
|
||||||
:required="required"
|
|
||||||
type="text"
|
|
||||||
class="material-input"
|
|
||||||
@focus="handleMdFocus"
|
|
||||||
@blur="handleMdBlur"
|
|
||||||
@input="handleModelInput"
|
|
||||||
>
|
|
||||||
<span class="material-input-bar" />
|
|
||||||
<label class="material-label">
|
<label class="material-label">
|
||||||
<slot />
|
<slot></slot>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -113,9 +32,8 @@
|
||||||
// source:https://github.com/wemake-services/vue-material-input/blob/master/src/components/MaterialInput.vue
|
// source:https://github.com/wemake-services/vue-material-input/blob/master/src/components/MaterialInput.vue
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'MdInput',
|
name: 'md-input',
|
||||||
props: {
|
props: {
|
||||||
/* eslint-disable */
|
|
||||||
icon: String,
|
icon: String,
|
||||||
name: String,
|
name: String,
|
||||||
type: {
|
type: {
|
||||||
|
@ -144,13 +62,6 @@ export default {
|
||||||
default: true
|
default: true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
currentValue: this.value,
|
|
||||||
focus: false,
|
|
||||||
fillPlaceHolder: null
|
|
||||||
}
|
|
||||||
},
|
|
||||||
computed: {
|
computed: {
|
||||||
computedClasses() {
|
computedClasses() {
|
||||||
return {
|
return {
|
||||||
|
@ -165,6 +76,13 @@ export default {
|
||||||
this.currentValue = newValue
|
this.currentValue = newValue
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
currentValue: this.value,
|
||||||
|
focus: false,
|
||||||
|
fillPlaceHolder: null
|
||||||
|
}
|
||||||
|
},
|
||||||
methods: {
|
methods: {
|
||||||
handleModelInput(event) {
|
handleModelInput(event) {
|
||||||
const value = event.target.value
|
const value = event.target.value
|
||||||
|
@ -197,7 +115,7 @@ export default {
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style rel="stylesheet/scss" lang="scss" scoped>
|
||||||
// Fonts:
|
// Fonts:
|
||||||
$font-size-base: 16px;
|
$font-size-base: 16px;
|
||||||
$font-size-small: 18px;
|
$font-size-small: 18px;
|
||||||
|
|
|
@ -1,31 +0,0 @@
|
||||||
// doc: https://nhnent.github.io/tui.editor/api/latest/ToastUIEditor.html#ToastUIEditor
|
|
||||||
export default {
|
|
||||||
minHeight: '200px',
|
|
||||||
previewStyle: 'vertical',
|
|
||||||
useCommandShortcut: true,
|
|
||||||
useDefaultHTMLSanitizer: true,
|
|
||||||
usageStatistics: false,
|
|
||||||
hideModeSwitch: false,
|
|
||||||
toolbarItems: [
|
|
||||||
'heading',
|
|
||||||
'bold',
|
|
||||||
'italic',
|
|
||||||
'strike',
|
|
||||||
'divider',
|
|
||||||
'hr',
|
|
||||||
'quote',
|
|
||||||
'divider',
|
|
||||||
'ul',
|
|
||||||
'ol',
|
|
||||||
'task',
|
|
||||||
'indent',
|
|
||||||
'outdent',
|
|
||||||
'divider',
|
|
||||||
'table',
|
|
||||||
'image',
|
|
||||||
'link',
|
|
||||||
'divider',
|
|
||||||
'code',
|
|
||||||
'codeblock'
|
|
||||||
]
|
|
||||||
}
|
|
|
@ -1,118 +1,116 @@
|
||||||
<template>
|
<template>
|
||||||
<div :id="id" />
|
<div class="simplemde-container" :style="{height:height+'px',zIndex:zIndex}">
|
||||||
|
<textarea :id="id">
|
||||||
|
</textarea>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
// deps for editor
|
import 'font-awesome/css/font-awesome.min.css'
|
||||||
import 'codemirror/lib/codemirror.css' // codemirror
|
import 'simplemde/dist/simplemde.min.css'
|
||||||
import 'tui-editor/dist/tui-editor.css' // editor ui
|
import SimpleMDE from 'simplemde'
|
||||||
import 'tui-editor/dist/tui-editor-contents.css' // editor content
|
|
||||||
|
|
||||||
import Editor from 'tui-editor'
|
|
||||||
import defaultOptions from './default-options'
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'MarkdownEditor',
|
name: 'simplemde-md',
|
||||||
props: {
|
props: {
|
||||||
value: {
|
value: String,
|
||||||
|
id: {
|
||||||
|
type: String
|
||||||
|
},
|
||||||
|
autofocus: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
placeholder: {
|
||||||
type: String,
|
type: String,
|
||||||
default: ''
|
default: ''
|
||||||
},
|
},
|
||||||
id: {
|
|
||||||
type: String,
|
|
||||||
required: false,
|
|
||||||
default() {
|
|
||||||
return 'markdown-editor-' + +new Date() + ((Math.random() * 1000).toFixed(0) + '')
|
|
||||||
}
|
|
||||||
},
|
|
||||||
options: {
|
|
||||||
type: Object,
|
|
||||||
default() {
|
|
||||||
return defaultOptions
|
|
||||||
}
|
|
||||||
},
|
|
||||||
mode: {
|
|
||||||
type: String,
|
|
||||||
default: 'markdown'
|
|
||||||
},
|
|
||||||
height: {
|
height: {
|
||||||
type: String,
|
type: Number,
|
||||||
required: false,
|
default: 150
|
||||||
default: '300px'
|
|
||||||
},
|
},
|
||||||
language: {
|
zIndex: {
|
||||||
type: String,
|
type: Number,
|
||||||
required: false,
|
default: 10
|
||||||
default: 'en_US' // https://github.com/nhnent/tui.editor/tree/master/src/js/langs
|
},
|
||||||
|
toolbar: {
|
||||||
|
type: Array
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
editor: null
|
simplemde: null,
|
||||||
}
|
hasChange: false
|
||||||
},
|
|
||||||
computed: {
|
|
||||||
editorOptions() {
|
|
||||||
const options = Object.assign({}, defaultOptions, this.options)
|
|
||||||
options.initialEditType = this.mode
|
|
||||||
options.height = this.height
|
|
||||||
options.language = this.language
|
|
||||||
return options
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
value(newValue, preValue) {
|
value(val) {
|
||||||
if (newValue !== preValue && newValue !== this.editor.getValue()) {
|
if (val === this.simplemde.value() && !this.hasChange) return
|
||||||
this.editor.setValue(newValue)
|
this.simplemde.value(val)
|
||||||
}
|
|
||||||
},
|
|
||||||
language(val) {
|
|
||||||
this.destroyEditor()
|
|
||||||
this.initEditor()
|
|
||||||
},
|
|
||||||
height(newValue) {
|
|
||||||
this.editor.height(newValue)
|
|
||||||
},
|
|
||||||
mode(newValue) {
|
|
||||||
this.editor.changeMode(newValue)
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
this.initEditor()
|
this.simplemde = new SimpleMDE({
|
||||||
|
element: document.getElementById(this.id || 'markdown-editor-' + +new Date()),
|
||||||
|
autoDownloadFontAwesome: false,
|
||||||
|
autofocus: this.autofocus,
|
||||||
|
toolbar: this.toolbar,
|
||||||
|
spellChecker: false,
|
||||||
|
insertTexts: {
|
||||||
|
link: ['[', ']( )']
|
||||||
},
|
},
|
||||||
destroyed() {
|
// hideIcons: ['guide', 'heading', 'quote', 'image', 'preview', 'side-by-side', 'fullscreen'],
|
||||||
this.destroyEditor()
|
placeholder: this.placeholder
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
initEditor() {
|
|
||||||
this.editor = new Editor({
|
|
||||||
el: document.getElementById(this.id),
|
|
||||||
...this.editorOptions
|
|
||||||
})
|
})
|
||||||
if (this.value) {
|
if (this.value) {
|
||||||
this.editor.setValue(this.value)
|
this.simplemde.value(this.value)
|
||||||
}
|
}
|
||||||
this.editor.on('change', () => {
|
this.simplemde.codemirror.on('change', () => {
|
||||||
this.$emit('input', this.editor.getValue())
|
if (this.hasChange) {
|
||||||
|
this.hasChange = true
|
||||||
|
}
|
||||||
|
this.$emit('input', this.simplemde.value())
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
destroyEditor() {
|
destroyed() {
|
||||||
if (!this.editor) return
|
this.simplemde.toTextArea()
|
||||||
this.editor.off('change')
|
this.simplemde = null
|
||||||
this.editor.remove()
|
|
||||||
},
|
|
||||||
setValue(value) {
|
|
||||||
this.editor.setValue(value)
|
|
||||||
},
|
|
||||||
getValue() {
|
|
||||||
return this.editor.getValue()
|
|
||||||
},
|
|
||||||
setHtml(value) {
|
|
||||||
this.editor.setHtml(value)
|
|
||||||
},
|
|
||||||
getHtml() {
|
|
||||||
return this.editor.getHtml()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.simplemde-container>>>.CodeMirror {
|
||||||
|
min-height: 150px;
|
||||||
|
line-height: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.simplemde-container>>>.CodeMirror-scroll {
|
||||||
|
min-height: 150px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.simplemde-container>>>.CodeMirror-code {
|
||||||
|
padding-bottom: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.simplemde-container>>>.editor-statusbar {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.simplemde-container>>>.CodeMirror .CodeMirror-code .cm-link {
|
||||||
|
color: #1890ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.simplemde-container>>>.CodeMirror .CodeMirror-code .cm-string.cm-url {
|
||||||
|
color: #2d3b4d;
|
||||||
|
}
|
||||||
|
|
||||||
|
.simplemde-container>>>.CodeMirror .CodeMirror-code .cm-formatting-link-string.cm-url {
|
||||||
|
padding: 0 2px;
|
||||||
|
color: #E61E1E;
|
||||||
|
}
|
||||||
|
.simplemde-container >>> .editor-toolbar.fullscreen,
|
||||||
|
.simplemde-container >>> .CodeMirror-fullscreen {
|
||||||
|
z-index: 1003;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
|
@ -1,101 +0,0 @@
|
||||||
<template>
|
|
||||||
<div :class="{'hidden':hidden}" class="pagination-container">
|
|
||||||
<el-pagination
|
|
||||||
:background="background"
|
|
||||||
:current-page.sync="currentPage"
|
|
||||||
:page-size.sync="pageSize"
|
|
||||||
:layout="layout"
|
|
||||||
:page-sizes="pageSizes"
|
|
||||||
:total="total"
|
|
||||||
v-bind="$attrs"
|
|
||||||
@size-change="handleSizeChange"
|
|
||||||
@current-change="handleCurrentChange"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import { scrollTo } from '@/utils/scroll-to'
|
|
||||||
|
|
||||||
export default {
|
|
||||||
name: 'Pagination',
|
|
||||||
props: {
|
|
||||||
total: {
|
|
||||||
required: true,
|
|
||||||
type: Number
|
|
||||||
},
|
|
||||||
page: {
|
|
||||||
type: Number,
|
|
||||||
default: 1
|
|
||||||
},
|
|
||||||
limit: {
|
|
||||||
type: Number,
|
|
||||||
default: 20
|
|
||||||
},
|
|
||||||
pageSizes: {
|
|
||||||
type: Array,
|
|
||||||
default() {
|
|
||||||
return [10, 20, 30, 50]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
layout: {
|
|
||||||
type: String,
|
|
||||||
default: 'total, sizes, prev, pager, next, jumper'
|
|
||||||
},
|
|
||||||
background: {
|
|
||||||
type: Boolean,
|
|
||||||
default: true
|
|
||||||
},
|
|
||||||
autoScroll: {
|
|
||||||
type: Boolean,
|
|
||||||
default: true
|
|
||||||
},
|
|
||||||
hidden: {
|
|
||||||
type: Boolean,
|
|
||||||
default: false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
computed: {
|
|
||||||
currentPage: {
|
|
||||||
get() {
|
|
||||||
return this.page
|
|
||||||
},
|
|
||||||
set(val) {
|
|
||||||
this.$emit('update:page', val)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
pageSize: {
|
|
||||||
get() {
|
|
||||||
return this.limit
|
|
||||||
},
|
|
||||||
set(val) {
|
|
||||||
this.$emit('update:limit', val)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
handleSizeChange(val) {
|
|
||||||
this.$emit('pagination', { page: this.currentPage, limit: val })
|
|
||||||
if (this.autoScroll) {
|
|
||||||
scrollTo(0, 800)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
handleCurrentChange(val) {
|
|
||||||
this.$emit('pagination', { page: val, limit: this.pageSize })
|
|
||||||
if (this.autoScroll) {
|
|
||||||
scrollTo(0, 800)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
.pagination-container {
|
|
||||||
background: #fff;
|
|
||||||
padding: 32px 16px;
|
|
||||||
}
|
|
||||||
.pagination-container.hidden {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
</style>
|
|
|
@ -1,12 +1,11 @@
|
||||||
<template>
|
<template>
|
||||||
<div :style="{zIndex:zIndex,height:height,width:width}" class="pan-item">
|
<div class="pan-item" :style="{zIndex:zIndex,height:height,width:width}">
|
||||||
<div class="pan-info">
|
<div class="pan-info">
|
||||||
<div class="pan-info-roles-container">
|
<div class="pan-info-roles-container">
|
||||||
<slot />
|
<slot></slot>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- eslint-disable-next-line -->
|
<img class="pan-thumb" :src="image">
|
||||||
<div :style="{backgroundImage: `url(${image})`}" class="pan-thumb"></div>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -53,8 +52,7 @@ export default {
|
||||||
.pan-thumb {
|
.pan-thumb {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
background-position: center center;
|
background-size: 100%;
|
||||||
background-size: cover;
|
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
@ -62,7 +60,7 @@ export default {
|
||||||
transition: all 0.3s ease-in-out;
|
transition: all 0.3s ease-in-out;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* .pan-thumb:after {
|
.pan-thumb:after {
|
||||||
content: '';
|
content: '';
|
||||||
width: 8px;
|
width: 8px;
|
||||||
height: 8px;
|
height: 8px;
|
||||||
|
@ -73,7 +71,7 @@ export default {
|
||||||
margin: -4px 0 0 -4px;
|
margin: -4px 0 0 -4px;
|
||||||
background: radial-gradient(ellipse at center, rgba(14, 14, 14, 1) 0%, rgba(125, 126, 125, 1) 100%);
|
background: radial-gradient(ellipse at center, rgba(14, 14, 14, 1) 0%, rgba(125, 126, 125, 1) 100%);
|
||||||
box-shadow: 0 0 1px rgba(255, 255, 255, 0.9);
|
box-shadow: 0 0 1px rgba(255, 255, 255, 0.9);
|
||||||
} */
|
}
|
||||||
|
|
||||||
.pan-info {
|
.pan-info {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
|
|
@ -1,145 +0,0 @@
|
||||||
<template>
|
|
||||||
<div ref="rightPanel" :class="{show:show}" class="rightPanel-container">
|
|
||||||
<div class="rightPanel-background" />
|
|
||||||
<div class="rightPanel">
|
|
||||||
<div class="handle-button" :style="{'top':buttonTop+'px','background-color':theme}" @click="show=!show">
|
|
||||||
<i :class="show?'el-icon-close':'el-icon-setting'" />
|
|
||||||
</div>
|
|
||||||
<div class="rightPanel-items">
|
|
||||||
<slot />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import { addClass, removeClass } from '@/utils'
|
|
||||||
|
|
||||||
export default {
|
|
||||||
name: 'RightPanel',
|
|
||||||
props: {
|
|
||||||
clickNotClose: {
|
|
||||||
default: false,
|
|
||||||
type: Boolean
|
|
||||||
},
|
|
||||||
buttonTop: {
|
|
||||||
default: 250,
|
|
||||||
type: Number
|
|
||||||
}
|
|
||||||
},
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
show: false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
computed: {
|
|
||||||
theme() {
|
|
||||||
return this.$store.state.settings.theme
|
|
||||||
}
|
|
||||||
},
|
|
||||||
watch: {
|
|
||||||
show(value) {
|
|
||||||
if (value && !this.clickNotClose) {
|
|
||||||
this.addEventClick()
|
|
||||||
}
|
|
||||||
if (value) {
|
|
||||||
addClass(document.body, 'showRightPanel')
|
|
||||||
} else {
|
|
||||||
removeClass(document.body, 'showRightPanel')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
mounted() {
|
|
||||||
this.insertToBody()
|
|
||||||
},
|
|
||||||
beforeDestroy() {
|
|
||||||
const elx = this.$refs.rightPanel
|
|
||||||
elx.remove()
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
addEventClick() {
|
|
||||||
window.addEventListener('click', this.closeSidebar)
|
|
||||||
},
|
|
||||||
closeSidebar(evt) {
|
|
||||||
const parent = evt.target.closest('.rightPanel')
|
|
||||||
if (!parent) {
|
|
||||||
this.show = false
|
|
||||||
window.removeEventListener('click', this.closeSidebar)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
insertToBody() {
|
|
||||||
const elx = this.$refs.rightPanel
|
|
||||||
const body = document.querySelector('body')
|
|
||||||
body.insertBefore(elx, body.firstChild)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
.showRightPanel {
|
|
||||||
overflow: hidden;
|
|
||||||
position: relative;
|
|
||||||
width: calc(100% - 15px);
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
|
||||||
.rightPanel-background {
|
|
||||||
position: fixed;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
opacity: 0;
|
|
||||||
transition: opacity .3s cubic-bezier(.7, .3, .1, 1);
|
|
||||||
background: rgba(0, 0, 0, .2);
|
|
||||||
z-index: -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.rightPanel {
|
|
||||||
width: 100%;
|
|
||||||
max-width: 260px;
|
|
||||||
height: 100vh;
|
|
||||||
position: fixed;
|
|
||||||
top: 0;
|
|
||||||
right: 0;
|
|
||||||
box-shadow: 0px 0px 15px 0px rgba(0, 0, 0, .05);
|
|
||||||
transition: all .25s cubic-bezier(.7, .3, .1, 1);
|
|
||||||
transform: translate(100%);
|
|
||||||
background: #fff;
|
|
||||||
z-index: 40000;
|
|
||||||
}
|
|
||||||
|
|
||||||
.show {
|
|
||||||
transition: all .3s cubic-bezier(.7, .3, .1, 1);
|
|
||||||
|
|
||||||
.rightPanel-background {
|
|
||||||
z-index: 20000;
|
|
||||||
opacity: 1;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.rightPanel {
|
|
||||||
transform: translate(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.handle-button {
|
|
||||||
width: 48px;
|
|
||||||
height: 48px;
|
|
||||||
position: absolute;
|
|
||||||
left: -48px;
|
|
||||||
text-align: center;
|
|
||||||
font-size: 24px;
|
|
||||||
border-radius: 6px 0 0 6px !important;
|
|
||||||
z-index: 0;
|
|
||||||
pointer-events: auto;
|
|
||||||
cursor: pointer;
|
|
||||||
color: #fff;
|
|
||||||
line-height: 48px;
|
|
||||||
i {
|
|
||||||
font-size: 24px;
|
|
||||||
line-height: 48px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
|
@ -1,6 +1,16 @@
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<svg-icon :icon-class="isFullscreen?'exit-fullscreen':'fullscreen'" @click="click" />
|
<svg t="1508738709248" @click='click' class="screenfull-svg" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"
|
||||||
|
p-id="2069" xmlns:xlink="http://www.w3.org/1999/xlink" width="32" height="32">
|
||||||
|
<path d="M333.493443 428.647617 428.322206 333.832158 262.572184 168.045297 366.707916 64.444754 64.09683 64.444754 63.853283 366.570793 167.283957 262.460644Z"
|
||||||
|
p-id="2070"></path>
|
||||||
|
<path d="M854.845439 760.133334 688.61037 593.95864 593.805144 688.764889 759.554142 854.56096 655.44604 958.161503 958.055079 958.161503 958.274066 656.035464Z"
|
||||||
|
p-id="2071"></path>
|
||||||
|
<path d="M688.535669 428.550403 854.31025 262.801405 957.935352 366.921787 957.935352 64.34754 655.809313 64.081481 759.919463 167.535691 593.70793 333.731874Z"
|
||||||
|
p-id="2072"></path>
|
||||||
|
<path d="M333.590658 594.033341 167.8171 759.804852 64.218604 655.67219 64.218604 958.270996 366.342596 958.502263 262.234493 855.071589 428.421466 688.86108Z"
|
||||||
|
p-id="2073"></path>
|
||||||
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -8,18 +18,26 @@
|
||||||
import screenfull from 'screenfull'
|
import screenfull from 'screenfull'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'Screenfull',
|
name: 'screenfull',
|
||||||
|
props: {
|
||||||
|
width: {
|
||||||
|
type: Number,
|
||||||
|
default: 22
|
||||||
|
},
|
||||||
|
height: {
|
||||||
|
type: Number,
|
||||||
|
default: 22
|
||||||
|
},
|
||||||
|
fill: {
|
||||||
|
type: String,
|
||||||
|
default: '#48576a'
|
||||||
|
}
|
||||||
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
isFullscreen: false
|
isFullscreen: false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
|
||||||
this.init()
|
|
||||||
},
|
|
||||||
beforeDestroy() {
|
|
||||||
this.destroy()
|
|
||||||
},
|
|
||||||
methods: {
|
methods: {
|
||||||
click() {
|
click() {
|
||||||
if (!screenfull.enabled) {
|
if (!screenfull.enabled) {
|
||||||
|
@ -30,19 +48,6 @@ export default {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
screenfull.toggle()
|
screenfull.toggle()
|
||||||
},
|
|
||||||
change() {
|
|
||||||
this.isFullscreen = screenfull.isFullscreen
|
|
||||||
},
|
|
||||||
init() {
|
|
||||||
if (screenfull.enabled) {
|
|
||||||
screenfull.on('change', this.change)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
destroy() {
|
|
||||||
if (screenfull.enabled) {
|
|
||||||
screenfull.off('change', this.change)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,72 @@
|
||||||
|
<template>
|
||||||
|
<div class="scroll-container" ref="scrollContainer" @wheel.prevent="handleScroll">
|
||||||
|
<div class="scroll-wrapper" ref="scrollWrapper" :style="{left: left + 'px'}">
|
||||||
|
<slot></slot>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
const padding = 15 // tag's padding
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'scrollPane',
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
left: 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
handleScroll(e) {
|
||||||
|
const eventDelta = e.wheelDelta || -e.deltaY * 3
|
||||||
|
const $container = this.$refs.scrollContainer
|
||||||
|
const $containerWidth = $container.offsetWidth
|
||||||
|
const $wrapper = this.$refs.scrollWrapper
|
||||||
|
const $wrapperWidth = $wrapper.offsetWidth
|
||||||
|
|
||||||
|
if (eventDelta > 0) {
|
||||||
|
this.left = Math.min(0, this.left + eventDelta)
|
||||||
|
} else {
|
||||||
|
if ($containerWidth - padding < $wrapperWidth) {
|
||||||
|
if (this.left < -($wrapperWidth - $containerWidth + padding)) {
|
||||||
|
this.left = this.left
|
||||||
|
} else {
|
||||||
|
this.left = Math.max(this.left + eventDelta, $containerWidth - $wrapperWidth - padding)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.left = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
moveToTarget($target) {
|
||||||
|
const $container = this.$refs.scrollContainer
|
||||||
|
const $containerWidth = $container.offsetWidth
|
||||||
|
const $targetLeft = $target.offsetLeft
|
||||||
|
const $targetWidth = $target.offsetWidth
|
||||||
|
|
||||||
|
if ($targetLeft < -this.left) {
|
||||||
|
// tag in the left
|
||||||
|
this.left = -$targetLeft + padding
|
||||||
|
} else if ($targetLeft + padding > -this.left && $targetLeft + $targetWidth < -this.left + $containerWidth - padding) {
|
||||||
|
// tag in the current view
|
||||||
|
// eslint-disable-line
|
||||||
|
} else {
|
||||||
|
// tag in the right
|
||||||
|
this.left = -($targetLeft - ($containerWidth - $targetWidth) + padding)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style rel="stylesheet/scss" lang="scss" scoped>
|
||||||
|
.scroll-container {
|
||||||
|
white-space: nowrap;
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
width: 100%;
|
||||||
|
.scroll-wrapper {
|
||||||
|
position: absolute;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -1,10 +1,10 @@
|
||||||
<template>
|
<template>
|
||||||
<div :class="{active:isActive}" class="share-dropdown-menu">
|
<div class="share-dropdown-menu" :class="{active:isActive}">
|
||||||
<div class="share-dropdown-menu-wrapper">
|
<div class="share-dropdown-menu-wrapper">
|
||||||
<span class="share-dropdown-menu-title" @click.self="clickTitle">{{ title }}</span>
|
<span class="share-dropdown-menu-title" @click.self="clickTitle">{{title}}</span>
|
||||||
<div v-for="(item,index) of items" :key="index" class="share-dropdown-menu-item">
|
<div class="share-dropdown-menu-item" v-for="(item,index) of items" :key='index'>
|
||||||
<a v-if="item.href" :href="item.href" target="_blank">{{ item.title }}</a>
|
<a v-if="item.href" :href="item.href" target="_blank">{{item.title}}</a>
|
||||||
<span v-else>{{ item.title }}</span>
|
<span v-else>{{item.title}}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -14,10 +14,7 @@
|
||||||
export default {
|
export default {
|
||||||
props: {
|
props: {
|
||||||
items: {
|
items: {
|
||||||
type: Array,
|
type: Array
|
||||||
default: function() {
|
|
||||||
return []
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
title: {
|
title: {
|
||||||
type: String,
|
type: String,
|
||||||
|
@ -37,14 +34,13 @@ export default {
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" >
|
<style rel="stylesheet/scss" lang="scss" >
|
||||||
$n: 9; //和items.length 相同
|
$n: 8; //和items.length 相同
|
||||||
$t: .1s;
|
$t: .1s;
|
||||||
.share-dropdown-menu {
|
.share-dropdown-menu {
|
||||||
width: 250px;
|
width: 250px;
|
||||||
position: relative;
|
position: relative;
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
height: auto!important;
|
|
||||||
&-title {
|
&-title {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
display: block;
|
display: block;
|
||||||
|
@ -66,12 +62,10 @@ $t: .1s;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
background: #e0e0e0;
|
background: #e0e0e0;
|
||||||
color: #000;
|
|
||||||
line-height: 60px;
|
line-height: 60px;
|
||||||
height: 60px;
|
height: 60px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
font-size: 18px;
|
font-size: 20px;
|
||||||
overflow: hidden;
|
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
transition: transform 0.28s ease;
|
transition: transform 0.28s ease;
|
||||||
&:hover {
|
&:hover {
|
|
@ -1,57 +0,0 @@
|
||||||
<template>
|
|
||||||
<el-dropdown trigger="click" @command="handleSetSize">
|
|
||||||
<div>
|
|
||||||
<svg-icon class-name="size-icon" icon-class="size" />
|
|
||||||
</div>
|
|
||||||
<el-dropdown-menu slot="dropdown">
|
|
||||||
<el-dropdown-item v-for="item of sizeOptions" :key="item.value" :disabled="size===item.value" :command="item.value">
|
|
||||||
{{
|
|
||||||
item.label }}
|
|
||||||
</el-dropdown-item>
|
|
||||||
</el-dropdown-menu>
|
|
||||||
</el-dropdown>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
export default {
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
sizeOptions: [
|
|
||||||
{ label: 'Default', value: 'default' },
|
|
||||||
{ label: 'Medium', value: 'medium' },
|
|
||||||
{ label: 'Small', value: 'small' },
|
|
||||||
{ label: 'Mini', value: 'mini' }
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
computed: {
|
|
||||||
size() {
|
|
||||||
return this.$store.getters.size
|
|
||||||
}
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
handleSetSize(size) {
|
|
||||||
this.$ELEMENT.size = size
|
|
||||||
this.$store.dispatch('app/setSize', size)
|
|
||||||
this.refreshView()
|
|
||||||
this.$message({
|
|
||||||
message: 'Switch Size Success',
|
|
||||||
type: 'success'
|
|
||||||
})
|
|
||||||
},
|
|
||||||
refreshView() {
|
|
||||||
// In order to make the cached page re-rendered
|
|
||||||
this.$store.dispatch('tagsView/delAllCachedViews', this.$route)
|
|
||||||
|
|
||||||
const { fullPath } = this.$route
|
|
||||||
|
|
||||||
this.$nextTick(() => {
|
|
||||||
this.$router.replace({
|
|
||||||
path: '/redirect' + fullPath
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
</script>
|
|
|
@ -1,9 +1,6 @@
|
||||||
<template>
|
<template>
|
||||||
<div :style="{height:height+'px',zIndex:zIndex}">
|
<div :style="{height:height+'px',zIndex:zIndex}">
|
||||||
<div
|
<div :class="className" :style="{top:stickyTop+'px',zIndex:zIndex,position:position,width:width,height:height+'px'}">
|
||||||
:class="className"
|
|
||||||
:style="{top:(isSticky ? stickyTop +'px' : ''),zIndex:zIndex,position:position,width:width,height:height+'px'}"
|
|
||||||
>
|
|
||||||
<slot>
|
<slot>
|
||||||
<div>sticky</div>
|
<div>sticky</div>
|
||||||
</slot>
|
</slot>
|
||||||
|
@ -24,8 +21,7 @@ export default {
|
||||||
default: 1
|
default: 1
|
||||||
},
|
},
|
||||||
className: {
|
className: {
|
||||||
type: String,
|
type: String
|
||||||
default: ''
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
|
@ -40,14 +36,14 @@ export default {
|
||||||
mounted() {
|
mounted() {
|
||||||
this.height = this.$el.getBoundingClientRect().height
|
this.height = this.$el.getBoundingClientRect().height
|
||||||
window.addEventListener('scroll', this.handleScroll)
|
window.addEventListener('scroll', this.handleScroll)
|
||||||
window.addEventListener('resize', this.handleResize)
|
window.addEventListener('resize', this.handleReize)
|
||||||
},
|
},
|
||||||
activated() {
|
activated() {
|
||||||
this.handleScroll()
|
this.handleScroll()
|
||||||
},
|
},
|
||||||
destroyed() {
|
destroyed() {
|
||||||
window.removeEventListener('scroll', this.handleScroll)
|
window.removeEventListener('scroll', this.handleScroll)
|
||||||
window.removeEventListener('resize', this.handleResize)
|
window.removeEventListener('resize', this.handleReize)
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
sticky() {
|
sticky() {
|
||||||
|
@ -59,29 +55,25 @@ export default {
|
||||||
this.width = this.width + 'px'
|
this.width = this.width + 'px'
|
||||||
this.isSticky = true
|
this.isSticky = true
|
||||||
},
|
},
|
||||||
handleReset() {
|
reset() {
|
||||||
if (!this.active) {
|
if (!this.active) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
this.reset()
|
|
||||||
},
|
|
||||||
reset() {
|
|
||||||
this.position = ''
|
this.position = ''
|
||||||
this.width = 'auto'
|
this.width = 'auto'
|
||||||
this.active = false
|
this.active = false
|
||||||
this.isSticky = false
|
this.isSticky = false
|
||||||
},
|
},
|
||||||
handleScroll() {
|
handleScroll() {
|
||||||
const width = this.$el.getBoundingClientRect().width
|
this.width = this.$el.getBoundingClientRect().width
|
||||||
this.width = width || 'auto'
|
|
||||||
const offsetTop = this.$el.getBoundingClientRect().top
|
const offsetTop = this.$el.getBoundingClientRect().top
|
||||||
if (offsetTop < this.stickyTop) {
|
if (offsetTop < this.stickyTop) {
|
||||||
this.sticky()
|
this.sticky()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
this.handleReset()
|
this.reset()
|
||||||
},
|
},
|
||||||
handleResize() {
|
handleReize() {
|
||||||
if (this.isSticky) {
|
if (this.isSticky) {
|
||||||
this.width = this.$el.getBoundingClientRect().width + 'px'
|
this.width = this.$el.getBoundingClientRect().width + 'px'
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,30 +1,22 @@
|
||||||
<template>
|
<template>
|
||||||
<div v-if="isExternal" :style="styleExternalIcon" class="svg-external-icon svg-icon" v-on="$listeners" />
|
<svg :class="svgClass" aria-hidden="true">
|
||||||
<svg v-else :class="svgClass" aria-hidden="true" v-on="$listeners">
|
<use :xlink:href="iconName"></use>
|
||||||
<use :xlink:href="iconName" />
|
|
||||||
</svg>
|
</svg>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
// doc: https://panjiachen.github.io/vue-element-admin-site/feature/component/svg-icon.html#usage
|
|
||||||
import { isExternal } from '@/utils/validate'
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'SvgIcon',
|
name: 'svg-icon',
|
||||||
props: {
|
props: {
|
||||||
iconClass: {
|
iconClass: {
|
||||||
type: String,
|
type: String,
|
||||||
required: true
|
required: true
|
||||||
},
|
},
|
||||||
className: {
|
className: {
|
||||||
type: String,
|
type: String
|
||||||
default: ''
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
isExternal() {
|
|
||||||
return isExternal(this.iconClass)
|
|
||||||
},
|
|
||||||
iconName() {
|
iconName() {
|
||||||
return `#icon-${this.iconClass}`
|
return `#icon-${this.iconClass}`
|
||||||
},
|
},
|
||||||
|
@ -34,12 +26,6 @@ export default {
|
||||||
} else {
|
} else {
|
||||||
return 'svg-icon'
|
return 'svg-icon'
|
||||||
}
|
}
|
||||||
},
|
|
||||||
styleExternalIcon() {
|
|
||||||
return {
|
|
||||||
mask: `url(${this.iconClass}) no-repeat 50% 50%`,
|
|
||||||
'-webkit-mask': `url(${this.iconClass}) no-repeat 50% 50%`
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -53,10 +39,4 @@ export default {
|
||||||
fill: currentColor;
|
fill: currentColor;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
.svg-external-icon {
|
|
||||||
background-color: currentColor;
|
|
||||||
mask-size: cover!important;
|
|
||||||
display: inline-block;
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
<template>
|
<template>
|
||||||
<a :class="className" class="link--mallki" href="#">
|
<a class="link--mallki" :class="className" href="#">
|
||||||
{{ text }}
|
{{text}}
|
||||||
<span :data-letters="text" />
|
<span :data-letters="text"></span>
|
||||||
<span :data-letters="text" />
|
<span :data-letters="text"></span>
|
||||||
</a>
|
</a>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -10,8 +10,7 @@
|
||||||
export default {
|
export default {
|
||||||
props: {
|
props: {
|
||||||
className: {
|
className: {
|
||||||
type: String,
|
type: String
|
||||||
default: ''
|
|
||||||
},
|
},
|
||||||
text: {
|
text: {
|
||||||
type: String,
|
type: String,
|
||||||
|
@ -21,6 +20,7 @@ export default {
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
/* Mallki */
|
/* Mallki */
|
||||||
|
|
||||||
|
|
|
@ -1,13 +1,12 @@
|
||||||
<template>
|
<template>
|
||||||
<el-color-picker
|
<el-color-picker
|
||||||
v-model="theme"
|
|
||||||
:predefine="['#409EFF', '#1890ff', '#304156','#212121','#11a983', '#13c2c2', '#6959CD', '#f5222d', ]"
|
|
||||||
class="theme-picker"
|
class="theme-picker"
|
||||||
popper-class="theme-picker-dropdown"
|
popper-class="theme-picker-dropdown"
|
||||||
/>
|
v-model="theme"></el-color-picker>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
|
||||||
const version = require('element-ui/package.json').version // element-ui version from node_modules
|
const version = require('element-ui/package.json').version // element-ui version from node_modules
|
||||||
const ORIGINAL_THEME = '#409EFF' // default color
|
const ORIGINAL_THEME = '#409EFF' // default color
|
||||||
|
|
||||||
|
@ -15,36 +14,15 @@ export default {
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
chalk: '', // content of theme-chalk css
|
chalk: '', // content of theme-chalk css
|
||||||
theme: ''
|
theme: ORIGINAL_THEME
|
||||||
}
|
|
||||||
},
|
|
||||||
computed: {
|
|
||||||
defaultTheme() {
|
|
||||||
return this.$store.state.settings.theme
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
defaultTheme: {
|
theme(val, oldVal) {
|
||||||
handler: function(val, oldVal) {
|
|
||||||
this.theme = val
|
|
||||||
},
|
|
||||||
immediate: true
|
|
||||||
},
|
|
||||||
async theme(val) {
|
|
||||||
const oldVal = this.chalk ? this.theme : ORIGINAL_THEME
|
|
||||||
if (typeof val !== 'string') return
|
if (typeof val !== 'string') return
|
||||||
const themeCluster = this.getThemeCluster(val.replace('#', ''))
|
const themeCluster = this.getThemeCluster(val.replace('#', ''))
|
||||||
const originalCluster = this.getThemeCluster(oldVal.replace('#', ''))
|
const originalCluster = this.getThemeCluster(oldVal.replace('#', ''))
|
||||||
console.log(themeCluster, originalCluster)
|
console.log(themeCluster, originalCluster)
|
||||||
|
|
||||||
const $message = this.$message({
|
|
||||||
message: ' Compiling the theme',
|
|
||||||
customClass: 'theme-message',
|
|
||||||
type: 'success',
|
|
||||||
duration: 0,
|
|
||||||
iconClass: 'el-icon-loading'
|
|
||||||
})
|
|
||||||
|
|
||||||
const getHandler = (variable, id) => {
|
const getHandler = (variable, id) => {
|
||||||
return () => {
|
return () => {
|
||||||
const originalCluster = this.getThemeCluster(ORIGINAL_THEME.replace('#', ''))
|
const originalCluster = this.getThemeCluster(ORIGINAL_THEME.replace('#', ''))
|
||||||
|
@ -60,14 +38,14 @@ export default {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this.chalk) {
|
|
||||||
const url = `https://unpkg.com/element-ui@${version}/lib/theme-chalk/index.css`
|
|
||||||
await this.getCSSString(url, 'chalk')
|
|
||||||
}
|
|
||||||
|
|
||||||
const chalkHandler = getHandler('chalk', 'chalk-style')
|
const chalkHandler = getHandler('chalk', 'chalk-style')
|
||||||
|
|
||||||
|
if (!this.chalk) {
|
||||||
|
const url = `https://unpkg.com/element-ui@${version}/lib/theme-chalk/index.css`
|
||||||
|
this.getCSSString(url, chalkHandler, 'chalk')
|
||||||
|
} else {
|
||||||
chalkHandler()
|
chalkHandler()
|
||||||
|
}
|
||||||
|
|
||||||
const styles = [].slice.call(document.querySelectorAll('style'))
|
const styles = [].slice.call(document.querySelectorAll('style'))
|
||||||
.filter(style => {
|
.filter(style => {
|
||||||
|
@ -79,10 +57,10 @@ export default {
|
||||||
if (typeof innerText !== 'string') return
|
if (typeof innerText !== 'string') return
|
||||||
style.innerText = this.updateStyle(innerText, originalCluster, themeCluster)
|
style.innerText = this.updateStyle(innerText, originalCluster, themeCluster)
|
||||||
})
|
})
|
||||||
|
this.$message({
|
||||||
this.$emit('change', val)
|
message: '换肤成功',
|
||||||
|
type: 'success'
|
||||||
$message.close()
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -95,18 +73,16 @@ export default {
|
||||||
return newStyle
|
return newStyle
|
||||||
},
|
},
|
||||||
|
|
||||||
getCSSString(url, variable) {
|
getCSSString(url, callback, variable) {
|
||||||
return new Promise(resolve => {
|
|
||||||
const xhr = new XMLHttpRequest()
|
const xhr = new XMLHttpRequest()
|
||||||
xhr.onreadystatechange = () => {
|
xhr.onreadystatechange = () => {
|
||||||
if (xhr.readyState === 4 && xhr.status === 200) {
|
if (xhr.readyState === 4 && xhr.status === 200) {
|
||||||
this[variable] = xhr.responseText.replace(/@font-face{[^}]+}/, '')
|
this[variable] = xhr.responseText.replace(/@font-face{[^}]+}/, '')
|
||||||
resolve()
|
callback()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
xhr.open('GET', url)
|
xhr.open('GET', url)
|
||||||
xhr.send()
|
xhr.send()
|
||||||
})
|
|
||||||
},
|
},
|
||||||
|
|
||||||
getThemeCluster(theme) {
|
getThemeCluster(theme) {
|
||||||
|
@ -158,15 +134,8 @@ export default {
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
.theme-message,
|
|
||||||
.theme-picker-dropdown {
|
|
||||||
z-index: 99999 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.theme-picker .el-color-picker__trigger {
|
.theme-picker .el-color-picker__trigger {
|
||||||
height: 26px !important;
|
vertical-align: middle;
|
||||||
width: 26px !important;
|
|
||||||
padding: 2px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.theme-picker-dropdown .el-color-dropdown__link-btn {
|
.theme-picker-dropdown .el-color-dropdown__link-btn {
|
||||||
|
|
|
@ -1,30 +1,14 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="upload-container">
|
<div class="upload-container">
|
||||||
<el-button :style="{background:color,borderColor:color}" icon="el-icon-upload" size="mini" type="primary" @click=" dialogVisible=true">
|
<el-button icon='el-icon-upload' size="mini" :style="{background:color,borderColor:color}" @click=" dialogVisible=true" type="primary">上传图片
|
||||||
upload
|
|
||||||
</el-button>
|
</el-button>
|
||||||
<el-dialog :visible.sync="dialogVisible">
|
<el-dialog :visible.sync="dialogVisible">
|
||||||
<el-upload
|
<el-upload class="editor-slide-upload" action="https://httpbin.org/post" :multiple="true" :file-list="fileList" :show-file-list="true"
|
||||||
:multiple="true"
|
list-type="picture-card" :on-remove="handleRemove" :on-success="handleSuccess" :before-upload="beforeUpload">
|
||||||
:file-list="fileList"
|
<el-button size="small" type="primary">点击上传</el-button>
|
||||||
:show-file-list="true"
|
|
||||||
:on-remove="handleRemove"
|
|
||||||
:on-success="handleSuccess"
|
|
||||||
:before-upload="beforeUpload"
|
|
||||||
class="editor-slide-upload"
|
|
||||||
action="https://httpbin.org/post"
|
|
||||||
list-type="picture-card"
|
|
||||||
>
|
|
||||||
<el-button size="small" type="primary">
|
|
||||||
Click upload
|
|
||||||
</el-button>
|
|
||||||
</el-upload>
|
</el-upload>
|
||||||
<el-button @click="dialogVisible = false">
|
<el-button @click="dialogVisible = false">取 消</el-button>
|
||||||
Cancel
|
<el-button type="primary" @click="handleSubmit">确 定</el-button>
|
||||||
</el-button>
|
|
||||||
<el-button type="primary" @click="handleSubmit">
|
|
||||||
Confirm
|
|
||||||
</el-button>
|
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
@ -33,7 +17,7 @@
|
||||||
// import { getToken } from 'api/qiniu'
|
// import { getToken } from 'api/qiniu'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'EditorSlideUpload',
|
name: 'editorSlideUpload',
|
||||||
props: {
|
props: {
|
||||||
color: {
|
color: {
|
||||||
type: String,
|
type: String,
|
||||||
|
@ -54,9 +38,10 @@ export default {
|
||||||
handleSubmit() {
|
handleSubmit() {
|
||||||
const arr = Object.keys(this.listObj).map(v => this.listObj[v])
|
const arr = Object.keys(this.listObj).map(v => this.listObj[v])
|
||||||
if (!this.checkAllSuccess()) {
|
if (!this.checkAllSuccess()) {
|
||||||
this.$message('Please wait for all images to be uploaded successfully. If there is a network problem, please refresh the page and upload again!')
|
this.$message('请等待所有图片上传成功 或 出现了网络问题,请刷新页面重新上传!')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
console.log(arr)
|
||||||
this.$emit('successCBK', arr)
|
this.$emit('successCBK', arr)
|
||||||
this.listObj = {}
|
this.listObj = {}
|
||||||
this.fileList = []
|
this.fileList = []
|
||||||
|
@ -101,10 +86,10 @@ export default {
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style rel="stylesheet/scss" lang="scss" scoped>
|
||||||
.editor-slide-upload {
|
.editor-slide-upload {
|
||||||
margin-bottom: 20px;
|
margin-bottom: 20px;
|
||||||
::v-deep .el-upload--picture-card {
|
/deep/ .el-upload--picture-card {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,59 +0,0 @@
|
||||||
let callbacks = []
|
|
||||||
|
|
||||||
function loadedTinymce() {
|
|
||||||
// to fixed https://github.com/PanJiaChen/vue-element-admin/issues/2144
|
|
||||||
// check is successfully downloaded script
|
|
||||||
return window.tinymce
|
|
||||||
}
|
|
||||||
|
|
||||||
const dynamicLoadScript = (src, callback) => {
|
|
||||||
const existingScript = document.getElementById(src)
|
|
||||||
const cb = callback || function() {}
|
|
||||||
|
|
||||||
if (!existingScript) {
|
|
||||||
const script = document.createElement('script')
|
|
||||||
script.src = src // src url for the third-party library being loaded.
|
|
||||||
script.id = src
|
|
||||||
document.body.appendChild(script)
|
|
||||||
callbacks.push(cb)
|
|
||||||
const onEnd = 'onload' in script ? stdOnEnd : ieOnEnd
|
|
||||||
onEnd(script)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (existingScript && cb) {
|
|
||||||
if (loadedTinymce()) {
|
|
||||||
cb(null, existingScript)
|
|
||||||
} else {
|
|
||||||
callbacks.push(cb)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function stdOnEnd(script) {
|
|
||||||
script.onload = function() {
|
|
||||||
// this.onload = null here is necessary
|
|
||||||
// because even IE9 works not like others
|
|
||||||
this.onerror = this.onload = null
|
|
||||||
for (const cb of callbacks) {
|
|
||||||
cb(null, script)
|
|
||||||
}
|
|
||||||
callbacks = null
|
|
||||||
}
|
|
||||||
script.onerror = function() {
|
|
||||||
this.onerror = this.onload = null
|
|
||||||
cb(new Error('Failed to load ' + src), script)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function ieOnEnd(script) {
|
|
||||||
script.onreadystatechange = function() {
|
|
||||||
if (this.readyState !== 'complete' && this.readyState !== 'loaded') return
|
|
||||||
this.onreadystatechange = null
|
|
||||||
for (const cb of callbacks) {
|
|
||||||
cb(null, script) // there is no way to catch loading errors in IE8
|
|
||||||
}
|
|
||||||
callbacks = null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default dynamicLoadScript
|
|
|
@ -1,34 +1,23 @@
|
||||||
<template>
|
<template>
|
||||||
<div :class="{fullscreen:fullscreen}" class="tinymce-container" :style="{width:containerWidth}">
|
<div class="tinymce-container editor-container" :class="{fullscreen:fullscreen}">
|
||||||
<textarea :id="tinymceId" class="tinymce-textarea" />
|
<textarea class="tinymce-textarea" :id="tinymceId"></textarea>
|
||||||
<div class="editor-custom-btn-container">
|
<div class="editor-custom-btn-container">
|
||||||
<editorImage color="#1890ff" class="editor-upload-btn" @successCBK="imageSuccessCBK" />
|
<editorImage color="#1890ff" class="editor-upload-btn" @successCBK="imageSuccessCBK"></editorImage>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
/**
|
import editorImage from './components/editorImage'
|
||||||
* docs:
|
|
||||||
* https://panjiachen.github.io/vue-element-admin-site/feature/component/rich-editor.html#tinymce
|
|
||||||
*/
|
|
||||||
import editorImage from './components/EditorImage'
|
|
||||||
import plugins from './plugins'
|
import plugins from './plugins'
|
||||||
import toolbar from './toolbar'
|
import toolbar from './toolbar'
|
||||||
import load from './dynamicLoadScript'
|
|
||||||
|
|
||||||
// why use this cdn, detail see https://github.com/PanJiaChen/tinymce-all-in-one
|
|
||||||
const tinymceCDN = 'https://cdn.jsdelivr.net/npm/tinymce-all-in-one@4.9.3/tinymce.min.js'
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'Tinymce',
|
name: 'tinymce',
|
||||||
components: { editorImage },
|
components: { editorImage },
|
||||||
props: {
|
props: {
|
||||||
id: {
|
id: {
|
||||||
type: String,
|
type: String
|
||||||
default: function() {
|
|
||||||
return 'vue-tinymce-' + +new Date() + ((Math.random() * 1000).toFixed(0) + '')
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
value: {
|
value: {
|
||||||
type: String,
|
type: String,
|
||||||
|
@ -42,41 +31,20 @@ export default {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
menubar: {
|
menubar: {
|
||||||
type: String,
|
|
||||||
default: 'file edit insert view format table'
|
default: 'file edit insert view format table'
|
||||||
},
|
},
|
||||||
height: {
|
height: {
|
||||||
type: [Number, String],
|
type: Number,
|
||||||
required: false,
|
required: false,
|
||||||
default: 360
|
default: 360
|
||||||
},
|
|
||||||
width: {
|
|
||||||
type: [Number, String],
|
|
||||||
required: false,
|
|
||||||
default: 'auto'
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
hasChange: false,
|
hasChange: false,
|
||||||
hasInit: false,
|
hasInit: false,
|
||||||
tinymceId: this.id,
|
tinymceId: this.id || 'vue-tinymce-' + +new Date(),
|
||||||
fullscreen: false,
|
fullscreen: false
|
||||||
languageTypeList: {
|
|
||||||
'en': 'en',
|
|
||||||
'zh': 'zh_CN',
|
|
||||||
'es': 'es_MX',
|
|
||||||
'ja': 'ja'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
computed: {
|
|
||||||
containerWidth() {
|
|
||||||
const width = this.width
|
|
||||||
if (/^[\d]+(\.[\d]+)?$/.test(width)) { // matches `100`, `'100'`
|
|
||||||
return `${width}px`
|
|
||||||
}
|
|
||||||
return width
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
|
@ -88,35 +56,19 @@ export default {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
this.init()
|
this.initTinymce()
|
||||||
},
|
},
|
||||||
activated() {
|
activated() {
|
||||||
if (window.tinymce) {
|
|
||||||
this.initTinymce()
|
this.initTinymce()
|
||||||
}
|
|
||||||
},
|
},
|
||||||
deactivated() {
|
deactivated() {
|
||||||
this.destroyTinymce()
|
this.destroyTinymce()
|
||||||
},
|
},
|
||||||
destroyed() {
|
|
||||||
this.destroyTinymce()
|
|
||||||
},
|
|
||||||
methods: {
|
methods: {
|
||||||
init() {
|
|
||||||
// dynamic load tinymce from cdn
|
|
||||||
load(tinymceCDN, (err) => {
|
|
||||||
if (err) {
|
|
||||||
this.$message.error(err.message)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
this.initTinymce()
|
|
||||||
})
|
|
||||||
},
|
|
||||||
initTinymce() {
|
initTinymce() {
|
||||||
const _this = this
|
const _this = this
|
||||||
window.tinymce.init({
|
window.tinymce.init({
|
||||||
selector: `#${this.tinymceId}`,
|
selector: `#${this.tinymceId}`,
|
||||||
language: this.languageTypeList['en'],
|
|
||||||
height: this.height,
|
height: this.height,
|
||||||
body_class: 'panel-body ',
|
body_class: 'panel-body ',
|
||||||
object_resizing: false,
|
object_resizing: false,
|
||||||
|
@ -147,11 +99,7 @@ export default {
|
||||||
editor.on('FullscreenStateChanged', (e) => {
|
editor.on('FullscreenStateChanged', (e) => {
|
||||||
_this.fullscreen = e.state
|
_this.fullscreen = e.state
|
||||||
})
|
})
|
||||||
},
|
}
|
||||||
// it will try to keep these URLs intact
|
|
||||||
// https://www.tiny.cloud/docs-3x/reference/configuration/Configuration3x@convert_urls/
|
|
||||||
// https://stackoverflow.com/questions/5196205/disable-tinymce-absolute-to-relative-url-conversions
|
|
||||||
convert_urls: false
|
|
||||||
// 整合七牛上传
|
// 整合七牛上传
|
||||||
// images_dataimg_filter(img) {
|
// images_dataimg_filter(img) {
|
||||||
// setTimeout(() => {
|
// setTimeout(() => {
|
||||||
|
@ -188,13 +136,8 @@ export default {
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
destroyTinymce() {
|
destroyTinymce() {
|
||||||
const tinymce = window.tinymce.get(this.tinymceId)
|
if (window.tinymce.get(this.tinymceId)) {
|
||||||
if (this.fullscreen) {
|
window.tinymce.get(this.tinymceId).destroy()
|
||||||
tinymce.execCommand('mceFullScreen')
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tinymce) {
|
|
||||||
tinymce.destroy()
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
setContent(value) {
|
setContent(value) {
|
||||||
|
@ -204,43 +147,39 @@ export default {
|
||||||
window.tinymce.get(this.tinymceId).getContent()
|
window.tinymce.get(this.tinymceId).getContent()
|
||||||
},
|
},
|
||||||
imageSuccessCBK(arr) {
|
imageSuccessCBK(arr) {
|
||||||
arr.forEach(v => window.tinymce.get(this.tinymceId).insertContent(`<img class="wscnph" src="${v.url}" >`))
|
const _this = this
|
||||||
|
arr.forEach(v => {
|
||||||
|
window.tinymce.get(_this.tinymceId).insertContent(`<img class="wscnph" src="${v.url}" >`)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
destroyed() {
|
||||||
|
this.destroyTinymce()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style scoped>
|
||||||
.tinymce-container {
|
.tinymce-container {
|
||||||
position: relative;
|
position: relative;
|
||||||
line-height: normal;
|
|
||||||
}
|
}
|
||||||
|
.tinymce-container>>>.mce-fullscreen {
|
||||||
.tinymce-container {
|
|
||||||
::v-deep {
|
|
||||||
.mce-fullscreen {
|
|
||||||
z-index: 10000;
|
z-index: 10000;
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.tinymce-textarea {
|
.tinymce-textarea {
|
||||||
visibility: hidden;
|
visibility: hidden;
|
||||||
z-index: -1;
|
z-index: -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.editor-custom-btn-container {
|
.editor-custom-btn-container {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
right: 4px;
|
right: 4px;
|
||||||
top: 4px;
|
top: 4px;
|
||||||
/*z-index: 2005;*/
|
/*z-index: 2005;*/
|
||||||
}
|
}
|
||||||
|
|
||||||
.fullscreen .editor-custom-btn-container {
|
.fullscreen .editor-custom-btn-container {
|
||||||
z-index: 10000;
|
z-index: 10000;
|
||||||
position: fixed;
|
position: fixed;
|
||||||
}
|
}
|
||||||
|
|
||||||
.editor-upload-btn {
|
.editor-upload-btn {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,6 @@
|
||||||
// Detail plugins list see https://www.tinymce.com/docs/plugins/
|
// Detail plugins list see https://www.tinymce.com/docs/plugins/
|
||||||
// Custom builds see https://www.tinymce.com/download/custom-builds/
|
// Custom builds see https://www.tinymce.com/download/custom-builds/
|
||||||
|
|
||||||
const plugins = ['advlist anchor autolink autosave code codesample colorpicker colorpicker contextmenu directionality emoticons fullscreen hr image imagetools insertdatetime link lists media nonbreaking noneditable pagebreak paste preview print save searchreplace spellchecker tabfocus table template textcolor textpattern visualblocks visualchars wordcount']
|
const plugins = ['advlist anchor autolink autosave code codesample colorpicker colorpicker contextmenu directionality emoticons fullscreen hr image imagetools importcss insertdatetime link lists media nonbreaking noneditable pagebreak paste preview print save searchreplace spellchecker tabfocus table template textcolor textpattern visualblocks visualchars wordcount']
|
||||||
|
|
||||||
export default plugins
|
export default plugins
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// Here is a list of the toolbar
|
// Here is a list of the toolbar
|
||||||
// Detail list see https://www.tinymce.com/docs/advanced/editor-control-identifiers/#toolbarcontrols
|
// Detail list see https://www.tinymce.com/docs/advanced/editor-control-identifiers/#toolbarcontrols
|
||||||
|
|
||||||
const toolbar = ['searchreplace bold italic underline strikethrough alignleft aligncenter alignright outdent indent blockquote undo redo removeformat subscript superscript code codesample', 'hr bullist numlist link image charmap preview anchor pagebreak insertdatetime media table emoticons forecolor backcolor fullscreen']
|
const toolbar = ['bold italic underline strikethrough alignleft aligncenter alignright outdent indent blockquote undo redo removeformat subscript superscript code codesample', 'hr bullist numlist link image charmap preview anchor pagebreak insertdatetime media table emoticons forecolor backcolor fullscreen']
|
||||||
|
|
||||||
export default toolbar
|
export default toolbar
|
||||||
|
|
|
@ -0,0 +1,29 @@
|
||||||
|
/**
|
||||||
|
* @Author: jianglei
|
||||||
|
* @Date: 2017-10-12 12:06:49
|
||||||
|
*/
|
||||||
|
'use strict'
|
||||||
|
import Vue from 'vue'
|
||||||
|
export default function treeToArray(data, expandAll, parent = null, level = null) {
|
||||||
|
let tmp = []
|
||||||
|
Array.from(data).forEach(function(record) {
|
||||||
|
if (record._expanded === undefined) {
|
||||||
|
Vue.set(record, '_expanded', expandAll)
|
||||||
|
}
|
||||||
|
let _level = 1
|
||||||
|
if (level !== undefined && level !== null) {
|
||||||
|
_level = level + 1
|
||||||
|
}
|
||||||
|
Vue.set(record, '_level', _level)
|
||||||
|
// 如果有父元素
|
||||||
|
if (parent) {
|
||||||
|
Vue.set(record, 'parent', parent)
|
||||||
|
}
|
||||||
|
tmp.push(record)
|
||||||
|
if (record.children && record.children.length > 0) {
|
||||||
|
const children = treeToArray(record.children, expandAll, record, _level)
|
||||||
|
tmp = tmp.concat(children)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return tmp
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue