Commit 3b360dbc authored by qinj's avatar qinj

紫光项目

parent caa7de9e
Pipeline #898 failed with stages
# https://editorconfig.org
root = true
[*]
charset = utf-8
indent_style = space
indent_size = 2
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
[*.md]
insert_final_newline = false
trim_trailing_whitespace = false
# just a flag
ENV = 'development'
# base api
VUE_APP_BASE_API = '/portal'
VUE_APP_JOB_API = '/job'
# just a flag
ENV = 'production'
# base api
VUE_APP_BASE_API = '/portal'
VUE_APP_JOB_API = '/job'
NODE_ENV = production
# just a flag
ENV = 'staging'
# base api
VUE_APP_BASE_API = '/stage-api'
build/*.js
src/assets
public
dist
module.exports = {
root: true,
parserOptions: {
parser: 'babel-eslint',
sourceType: 'module'
},
env: {
browser: true,
node: true,
es6: true,
},
extends: ['plugin:vue/recommended', 'eslint:recommended'],
// add your custom rules here
//it is base on https://github.com/vuejs/eslint-config-vue
rules: {
"vue/max-attributes-per-line": [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,
'arrow-spacing': [2, {
'before': true,
'after': true
}],
'block-spacing': [2, 'always'],
'brace-style': [2, '1tbs', {
'allowSingleLine': true
}],
'camelcase': [0, {
'properties': 'always'
}],
'comma-dangle': [2, 'never'],
'comma-spacing': [2, {
'before': false,
'after': true
}],
'comma-style': [2, 'last'],
'constructor-super': 2,
'curly': [2, 'multi-line'],
'dot-location': [2, 'property'],
'eol-last': 2,
'eqeqeq': ["error", "always", { "null": "ignore" }],
'generator-star-spacing': [2, {
'before': true,
'after': true
}],
'handle-callback-err': [2, '^(err|error)$'],
'indent': [2, 2, {
'SwitchCase': 1
}],
'jsx-quotes': [2, 'prefer-single'],
'key-spacing': [2, {
'beforeColon': false,
'afterColon': true
}],
'keyword-spacing': [2, {
'before': true,
'after': true
}],
'new-cap': [2, {
'newIsCap': true,
'capIsNew': false
}],
'new-parens': 2,
'no-array-constructor': 2,
'no-caller': 2,
'no-console': 'off',
'no-class-assign': 2,
'no-cond-assign': 2,
'no-const-assign': 2,
'no-control-regex': 0,
'no-delete-var': 2,
'no-dupe-args': 2,
'no-dupe-class-members': 2,
'no-dupe-keys': 2,
'no-duplicate-case': 2,
'no-empty-character-class': 2,
'no-empty-pattern': 2,
'no-eval': 2,
'no-ex-assign': 2,
'no-extend-native': 2,
'no-extra-bind': 2,
'no-extra-boolean-cast': 2,
'no-extra-parens': [2, 'functions'],
'no-fallthrough': 2,
'no-floating-decimal': 2,
'no-func-assign': 2,
'no-implied-eval': 2,
'no-inner-declarations': [2, 'functions'],
'no-invalid-regexp': 2,
'no-irregular-whitespace': 2,
'no-iterator': 2,
'no-label-var': 2,
'no-labels': [2, {
'allowLoop': false,
'allowSwitch': false
}],
'no-lone-blocks': 2,
'no-mixed-spaces-and-tabs': 2,
'no-multi-spaces': 2,
'no-multi-str': 2,
'no-multiple-empty-lines': [2, {
'max': 1
}],
'no-native-reassign': 2,
'no-negated-in-lhs': 2,
'no-new-object': 2,
'no-new-require': 2,
'no-new-symbol': 2,
'no-new-wrappers': 2,
'no-obj-calls': 2,
'no-octal': 2,
'no-octal-escape': 2,
'no-path-concat': 2,
'no-proto': 2,
'no-redeclare': 2,
'no-regex-spaces': 2,
'no-return-assign': [2, 'except-parens'],
'no-self-assign': 2,
'no-self-compare': 2,
'no-sequences': 2,
'no-shadow-restricted-names': 2,
'no-spaced-func': 2,
'no-sparse-arrays': 2,
'no-this-before-super': 2,
'no-throw-literal': 2,
'no-trailing-spaces': 2,
'no-undef': 2,
'no-undef-init': 2,
'no-unexpected-multiline': 2,
'no-unmodified-loop-condition': 2,
'no-unneeded-ternary': [2, {
'defaultAssignment': false
}],
'no-unreachable': 2,
'no-unsafe-finally': 2,
'no-unused-vars': [2, {
'vars': 'all',
'args': 'none'
}],
'no-useless-call': 2,
'no-useless-computed-key': 2,
'no-useless-constructor': 2,
'no-useless-escape': 0,
'no-whitespace-before-property': 2,
'no-with': 2,
'one-var': [2, {
'initialized': 'never'
}],
'operator-linebreak': [2, 'after', {
'overrides': {
'?': 'before',
':': 'before'
}
}],
'padded-blocks': [2, 'never'],
'quotes': [2, 'single', {
'avoidEscape': true,
'allowTemplateLiterals': true
}],
'semi': [2, 'never'],
'semi-spacing': [2, {
'before': false,
'after': true
}],
'space-before-blocks': [2, 'always'],
'space-before-function-paren': [2, 'never'],
'space-in-parens': [2, 'never'],
'space-infix-ops': 2,
'space-unary-ops': [2, {
'words': true,
'nonwords': false
}],
'spaced-comment': [2, 'always', {
'markers': ['global', 'globals', 'eslint', 'eslint-disable', '*package', '!', ',']
}],
'template-curly-spacing': [2, 'never'],
'use-isnan': 2,
'valid-typeof': 2,
'wrap-iife': [2, 'any'],
'yield-star-spacing': [2, 'both'],
'yoda': [2, 'never'],
'prefer-const': 2,
'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0,
'object-curly-spacing': [2, 'always', {
objectsInObjects: true
}],
'array-bracket-spacing': [2, 'never']
}
}
.DS_Store
node_modules/
dist/
npm-debug.log*
yarn-debug.log*
yarn-error.log*
**/*.log
tests/**/coverage/
tests/e2e/reports
selenium-debug.log
# Editor directories and files
.idea
.vscode
*.suo
*.ntvs*
*.njsproj
*.sln
*.local
package-lock.json
yarn.lock
language: node_js
node_js: 10
script: npm run test
notifications:
email: false
MIT License
Copyright (c) 2017-present PanJiaChen
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
<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>Java backend integration</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
<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>Java backend integration</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 -b i18n git@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
# portalhtml
<p align="center">
<img width="320" src="https://wpimg.wallstcn.com/ecc53a42-d79b-42e2-8852-5126b810a4c8.svg">
</p>
紫光前端代码
\ No newline at end of file
<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.github.io/vue-element-admin-site/donate">
<img src="https://img.shields.io/badge/%24-donate-ff69b4.svg" alt="donate">
</a>
</p>
English | [简体中文](./README.zh-CN.md) | [日本語](./README.ja.md) | [Spanish](./README.es.md)
## 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](https://panjiachen.github.io/vue-element-admin) is based on the newest development stack of vue and it has a built-in i18n solution, typical templates for enterprise applications, and lots of awesome features. It helps you build large and complex Single-Page Applications. I believe whatever your needs are, this project will help you.
- [Preview](https://panjiachen.github.io/vue-element-admin)
- [Documentation](https://panjiachen.github.io/vue-element-admin-site/)
- [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)
- [Gitee](https://panjiachen.gitee.io/vue-element-admin/) 国内用户可访问该地址在线预览
- Base template recommends using: [vue-admin-template](https://github.com/PanJiaChen/vue-admin-template)
- Desktop: [electron-vue-admin](https://github.com/PanJiaChen/electron-vue-admin)
- Typescript: [vue-typescript-admin-template](https://github.com/Armour/vue-typescript-admin-template) (Credits: [@Armour](https://github.com/Armour))
- [awesome-project](https://github.com/PanJiaChen/vue-element-admin/issues/2312)
**After the `v4.1.0+` version, the default master branch will not support i18n. Please use [i18n Branch](https://github.com/PanJiaChen/vue-element-admin/tree/i18n), it will keep up with the master update**
**The current version is `v4.0+` build on `vue-cli`. If you find a problem, please put [issue](https://github.com/PanJiaChen/vue-element-admin/issues/new). If you want to use the old version , you can switch branch to [tag/3.11.0](https://github.com/PanJiaChen/vue-element-admin/tree/tag/3.11.0), it does not rely on `vue-cli`**
**This project does not support low version browsers (e.g. IE). Please add polyfill by yourself.**
## Preparation
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).
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)
<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>Java backend integration</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
```
- Login / Logout
- Permission Authentication
- Page permission
- Directive permission
- Permission configuration page
- Two-step login
- Multi-environment build
- Develop (dev)
- sit
- Stage Test (stage)
- Production (prod)
- Global Features
- I18n
- Multiple dynamic themes
- Dynamic sidebar (supports multi-level routing)
- Dynamic breadcrumb
- Tags-view (Tab page Support right-click operation)
- Svg Sprite
- Mock data
- Screenfull
- Responsive Sidebar
- Editor
- Rich Text Editor
- Markdown Editor
- JSON Editor
- Excel
- Export Excel
- Upload Excel
- Visualization Excel
- Export zip
- Table
- Dynamic Table
- Drag And Drop Table
- Inline Edit Table
- Error Page
- 401
- 404
- Components
- Avatar Upload
- Back To Top
- Drag Dialog
- Drag Select
- Drag Kanban
- Drag List
- SplitPane
- Dropzone
- Sticky
- CountTo
- Advanced Example
- Error Log
- Dashboard
- Guide Page
- ECharts
- Clipboard
- Markdown to html
```
## Getting started
```bash
# clone the project
git clone -b i18n git@github.com:PanJiaChen/vue-element-admin.git
# enter the project directory
cd vue-element-admin
# install dependency
npm install
# develop
npm run dev
```
This will automatically open 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
```
Refer to [Documentation](https://panjiachen.github.io/vue-element-admin-site/guide/essentials/deploy.html) for more information
## Changelog
Detailed changes for each release are documented in the [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
This diff is collapsed.
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']
}
}
}
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}`)
}
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/'
}
{
"compilerOptions": {
"baseUrl": "./",
"paths": {
"@/*": ["src/*"]
}
},
"exclude": ["node_modules", "dist"]
}
\ No newline at end of file
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'
}
}
}
]
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
}
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))
}
}
})
}
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']
}]
}
}
}
}
]
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'
}
}
}
]
// 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 }
}
]
}
]
const asyncRoutes = [
{
path: '/permission',
component: 'layout/Layout',
redirect: '/permission/index',
alwaysShow: true,
meta: {
title: 'permission',
icon: 'lock',
roles: ['admin', 'editor']
},
children: [
{
path: 'page',
component: 'views/permission/page',
name: 'PagePermission',
meta: {
title: 'pagePermission',
roles: ['admin']
}
},
{
path: 'directive',
component: 'views/permission/directive',
name: 'DirectivePermission',
meta: {
title: 'directivePermission'
}
},
{
path: 'role',
component: 'views/permission/role',
name: 'RolePermission',
meta: {
title: 'rolePermission',
roles: ['admin']
}
}
]
},
{
path: '/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: '/error',
component: 'layout/Layout',
redirect: 'noRedirect',
name: 'ErrorPages',
meta: {
title: 'errorPages',
icon: '404'
},
children: [
{
path: '401',
component: 'views/error-page/401',
name: 'Page401',
meta: { title: 'page401', noCache: true }
},
{
path: '404',
component: 'views/error-page/404',
name: 'Page404',
meta: { title: 'page404', noCache: true }
}
]
},
{ path: '*', redirect: '/404', hidden: true }
]
module.exports = {
constantRoutes,
asyncRoutes
}
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'
}
}
}
]
/**
* @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
}
{
"name": "vue-element-admin",
"version": "4.3.1",
"description": "A magical vue admin. An out-of-box UI solution for enterprise applications. Newest development stack of vue. Lots of awesome features",
"author": "Pan <panfree23@gmail.com>",
"scripts": {
"dev": "vue-cli-service serve",
"lint": "eslint --ext .js,.vue src",
"lint-fix": "eslint --fix --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",
"dayjs": "1.10.6",
"driver.js": "0.9.5",
"dropzone": "5.5.1",
"echarts": "4.2.1",
"ele-table-editor": "0.5.0",
"element-ui": "^2.15.6",
"file-saver": "2.0.1",
"fuse.js": "3.4.4",
"js-cookie": "2.2.0",
"jsonlint": "1.6.3",
"jszip": "3.2.1",
"minio": "^7.0.19",
"normalize.css": "7.0.0",
"nprogress": "0.2.0",
"path-to-regexp": "2.4.0",
"pinyin": "2.9.0",
"pretty-bytes": "^5.6.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-ele-form-codemirror": "^0.1.3",
"vue-i18n": "7.3.2",
"vue-router": "3.0.2",
"vue-splitpane": "1.0.4",
"vuedraggable": "2.20.0",
"vuex": "3.1.0",
"xlsx": "0.14.1"
},
"devDependencies": {
"@fullcalendar/core": "^5.9.0",
"@fullcalendar/daygrid": "^5.9.0",
"@fullcalendar/timegrid": "^5.9.0",
"@fullcalendar/vue": "^5.9.0",
"@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",
"lint-staged": {
"src/**/*.{js,vue}": [
"eslint --fix",
"git add"
]
},
"husky": {
"hooks": {
"pre-commit": "lint-staged"
}
},
"repository": {
"type": "git",
"url": "git+https://github.com/PanJiaChen/vue-element-admin.git"
}
}
{{#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}}
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
}
}
{{#if state}}
const state = {}
{{/if}}
{{#if mutations}}
const mutations = {}
{{/if}}
{{#if actions}}
const actions = {}
{{/if}}
export default {
namespaced: true,
{{options}}
}
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
}
}
exports.notEmpty = name => v =>
!v || v.trim() === '' ? `${name} is required` : true
{{#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}}
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
}
}
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)
}
module.exports = {
plugins: {
autoprefixer: {}
}
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="renderer" content="webkit">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
<title><%= webpackConfig.name %></title>
</head>
<body>
<div id="app"></div>
<!-- built files will be auto injected -->
</body>
</html>
<template>
<div id="app">
<router-view v-if="isRouterAlive" />
</div>
</template>
<script>
export default {
name: 'App',
provide() {
return {
reload: this.reload
}
},
data() {
return {
isRouterAlive: true
}
},
methods: {
reload() {
this.isRouterAlive = false
this.$nextTick(function() {
this.isRouterAlive = true
})
}
}
}
</script>
// 员工
export const employee = {
createUrl: '/employee/create',
searchUrl: '/employee/search',
detailUrl: '/employee/getOne',
updateUrl: '/employee/update',
confirmUpdateUrl: '/employee/confirmUpdate',
cancelUpdateUrl: '/employee/cancelUpdate'
}
// 角色
export const role = {
createUrl: '/roleToMenu/create',
searchUrl: '/roleToMenu/search',
detailUrl: '/roleToMenu/getOne',
updateUrl: '/roleToMenu/update',
deleteUrl: '/roleToMenu/delete'
}
import request from '@/utils/request'
export function fetchList(query) {
return request({
url: '/vue-element-admin/article/list',
method: 'get',
params: query
})
}
export function fetchArticle(id) {
return request({
url: '/vue-element-admin/article/detail',
method: 'get',
params: { id }
})
}
export function fetchPv(pv) {
return request({
url: '/vue-element-admin/article/pv',
method: 'get',
params: { pv }
})
}
export function createArticle(data) {
return request({
url: '/vue-element-admin/article/create',
method: 'post',
data
})
}
export function updateArticle(data) {
return request({
url: '/vue-element-admin/article/update',
method: 'post',
data
})
}
// 回款模块
export const collection = {
createUrl: '/collection/create',
searchUrl: '/collection/search',
detailUrl: '/collection/getOne',
updateUrl: '/collection/update',
cancelEntryUrl: '/collection/cancelEntryUrl', // 取消认领
createCollectionDetailRecordUrl: '/collection/createCollectionDetailRecord', // 分配明细记录
searchEntryUrl: '/collection/searchEntry' // 回款认领查询
}
// 竞争对手
export const competitor = {
createUrl: '/competitor/create',
searchUrl: '/competitor/search',
detailUrl: '/competitor/getOne',
updateUrl: '/competitor/update',
deleteUrl: '/competitor/delete'
}
// 竞争对手产品
export const competitorProduct = {
createUrl: '/competitorProduct/create',
createPriceUrl: '/competitorProduct/createPrice',
searchUrl: '/competitorProduct/search',
searchPriceUrl: '/competitorProduct/searchPrice',
detailUrl: '/competitorProduct/getOne',
updateUrl: '/competitorProduct/update'
}
// 我司对标产品
export const ourCompanyCompetitorProduct = {
createUrl: '/ourCompanyCompetitorProduct/create',
searchUrl: '/ourCompanyCompetitorProduct/search',
detailUrl: '/ourCompanyCompetitorProduct/getOne',
updateUrl: '/ourCompanyCompetitorProduct/update',
deleteUrl: '/ourCompanyCompetitorProduct/delete'
}
// 投诉与建议
export const complaint = {
createUrl: '/complaintsAndSuggestions/create',
searchUrl: '/complaintsAndSuggestions/search',
detailUrl: '/complaintsAndSuggestions/getOneDetail'
}
import request from '@/utils/request'
// 合同
export const contract = {
createUrl: '/contract/create',
searchUrl: '/contract/search',
detailUrl: '/contract/getOne',
updateUrl: '/contract/update',
deleteUrl: '/contract/delete',
generateHomePage: '/contract/generateHomePage'
}
// 合同模板
export const contractTemplate = {
createUrl: '/contractTemplate/create',
searchUrl: '/contractTemplate/search',
detailUrl: '/contractTemplate/getOne',
updateUrl: '/contractTemplate/update',
deleteUrl: '/contractTemplate/delete'
}
// 合同类别
export function fetchContractCategory() {
return request({
method: 'post',
url: '/contractCategory/search',
data: {}
})
}
// 合同类型
export function fetchContractType(data) {
return request({
method: 'post',
url: '/contractType/search',
data
})
}
import request from '@/utils/request'
// 客户模块
export const customer = {
createUrl: '/customer/create',
searchUrl: '/customer/search',
detailUrl: '/customer/getOne',
updateUrl: '/customer/update',
deleteUrl: '/customer/delete',
endFollowUrl: '/customer/endFollowup', // 取消跟进
toPoolUrl: '/customer/toResourcePool' // 移入资源池
}
// 客户发布记录
export const releaseRecord = {
createUrl: '/releaserecord/create',
searchUrl: '/releaserecord/search',
updateUrl: '/releaserecord/update',
customerListUrl: '/releaserecord/searchCustomerDetail' // 客户清单查询
}
// 客户申请记录
export const applicationRecord = {
searchUrl: '/releaserecord/searchApplicationRecordDetail',
createUrl: '/releaserecord/createApplicationRecord'
}
// 客户审批记录
export const approvalRecord = {
searchUrl: '/releaserecord/searchApplicationRecordDetail',
createUrl: '/releaserecord/applicationRecordApproval',
updateUrl: '/releaserecord/updateApplicationRecord'
}
// 查询客户详情
export function fetchPotentialCustomerDetail(data) {
return request({
url: '/customer/getOne',
method: 'post',
data
})
}
// 新增客户基本信息
export function addPotentialCustomer(data) {
return request({
url: '/customer/create',
method: 'POST',
data
})
}
// 更新客户基本信息
export function updatePotentialCustomer(data) {
return request({
url: '/customer/update',
method: 'post',
data
})
}
// 一级分类
export function fetchFirstLevelClassification() {
return request({
method: 'post',
url: '/levelClassification/searchAllOne'
})
}
// 二级分类
export function fetchSecondLevelClassification(data) {
return request({
method: 'post',
url: '/levelClassification/searchAllTwo',
data
})
}
// 三级分类
export function fetchThirdLevelClassification(data) {
return request({
method: 'post',
url: '/levelClassification/searchThree',
data
})
}
// 客户项目信息
export const project = {
createUrl: '/project/create',
searchUrl: '/project/search',
detailUrl: '/project/getOne',
updateUrl: '/project/update',
deleteUrl: '/project/delete'
}
// 客户市场信息
export const market = {
createUrl: '/market/create',
searchUrl: '/market/search',
// detailUrl: '/market/getOne',
updateUrl: '/market/update',
deleteUrl: '/market/delete'
}
// 客户地址信息
export const address = {
createUrl: '/address/createByCustomer',
searchUrl: '/address/search',
// detailUrl: '/address/getOne',
updateUrl: '/address/update',
deleteUrl: '/address/delete'
}
// 客户联系人信息
export const contact = {
createUrl: '/contact/create',
searchUrl: '/contact/search',
// detailUrl: '/contact/getOne',
updateUrl: '/contact/update'
// deleteUrl: '/contact/delete'
}
// 客户行业信息
export const industry = {
createUrl: '/industry/create',
searchUrl: '/industry/search',
// detailUrl: '/industry/getOne',
updateUrl: '/industry/update',
deleteUrl: '/industry/delete'
}
// 客户督办
export const supervise = {
createUrl: '/supervisiontask/create',
searchUrl: '/supervisiontask/search',
// detailUrl: '/supervisiontask/getOne',
updateUrl: '/supervisiontask/update',
deleteUrl: '/supervisiontask/delete'
}
// 客户跟进记录
export const followRecord = {
createUrl: '/followupRecord/create',
searchUrl: '/followupRecord/search'
}
// 客户跟进任务
export const followTask = {
createUrl: '/task/create',
searchUrl: '/task/search',
detailUrl: '/task/getOne',
updateUrl: '/task/update',
// deleteUrl: '/task/delete'
}
// 客户开票
export const billing = {
createUrl: '/billing/create',
searchUrl: '/billing/search',
// detailUrl: '/billing/getOne',
updateUrl: '/billing/update',
deleteUrl: '/billing/delete'
}
// 客户商务交货说明
export const deliveryinstruction = {
createUrl: '/deliveryinstruction/create',
searchUrl: '/deliveryinstruction/search',
// detailUrl: '/deliveryinstruction/getOne',
updateUrl: '/deliveryinstruction/update',
deleteUrl: '/deliveryinstruction/delete'
}
// 客户银行
export const customerBank = {
createUrl: '/customerBank/create',
searchUrl: '/customerBank/searchAll',
// detailUrl: '/customerBank/getOne',
updateUrl: '/customerBank/update',
deleteUrl: '/customerBank/delete'
}
// 客户收付款银行
export const collectionAndPaymentbank = {
createUrl: '/collectionAndPaymentbank/create',
searchUrl: '/collectionAndPaymentbank/searchAll',
// detailUrl: '/collectionAndPaymentbank/getOne',
updateUrl: '/collectionAndPaymentbank/update',
deleteUrl: '/collectionAndPaymentbank/delete'
}
// 客户付款条件
export const paymentTerm = {
createUrl: '/paymentTerm/create',
searchUrl: '/paymentTerm/searchAll',
// detailUrl: '/paymentTerm/getOne',
updateUrl: '/paymentTerm/update',
deleteUrl: '/paymentTerm/delete'
}
// 客户付款明细
export const paymentTermDetail = {
searchUrl: '/paymentTerm/searchAllDetail',
updateUrl: '/paymentTerm/updateDetail'
}
// 客户附件
export const file = {
createUrl: '/file/create',
searchUrl: '/file/search',
detailUrl: '/file/getOne',
updateUrl: '/file/update',
deleteUrl: '/file/delete',
deleteDetailUrl: '/file/deleteDetail'
}
export const businessLog = {
searchUrl: '/businessLog/search'
}
// 拜访
export const visit = {
createUrl: '/visit/create',
searchUrl: '/visit/search',
detailUrl: '/visit/getOne',
updateUrl: '/visit/update',
deleteUrl: '/visit/delete',
startVisitUrl: '/visit/startVisit',
endVisitUrl: '/visit/endVisit',
cancelVisitUrl: '/visit/cancelVisit'
}
// 拜访同行人
export const fellowTravelerPeople = {
createUrl: '/fellowTravelerPeople/create',
searchUrl: '/fellowTravelerPeople/search',
detailUrl: '/fellowTravelerPeople/getOne',
updateUrl: '/fellowTravelerPeople/update',
deleteUrl: '/fellowTravelerPeople/delete'
}
// 拜访报告
export const visitReport = {
createUrl: '/visitReport/create',
searchUrl: '/visitReport/search',
detailUrl: '/visitReport/getOne',
updateUrl: '/visitReport/update',
deleteUrl: '/visitReport/delete'
}
// 周报
export const weekly = {
searchUrl: '/weekly/search',
detailUrl: '/weekly/getOne',
updateUrl: '/weekly/update',
submitUrl: '/weekly/submit'
}
// 月报
export const monthly = {
searchUrl: '/monthly/search',
detailUrl: '/monthly/getOne',
updateUrl: '/monthly/update',
submitUrl: '/monthly/submit'
}
// 月历、周历
export const calendar = {
searchUrl: '/calendar/search'
}
This diff is collapsed.
import request from '@/utils/request'
// 增删改查共用,根据具体请求方法实现
export const baseUrl = '/flow/condition'
export function add(data) {
return request({
url: baseUrl + '/add',
method: 'POST',
data
})
}
export function update(data) {
return request({
url: baseUrl + '/update',
method: 'POST',
data
})
}
export function remove(data) {
return request({
url: baseUrl + '/remove',
method: 'POST',
data
})
}
import request from '@/utils/request'
// 增删改查共用,根据具体请求方法实现
export const baseUrl = '/flow/definition'
export function add(data) {
return request({
url: baseUrl + '/add',
method: 'POST',
data
})
}
export function update(data) {
return request({
url: baseUrl + '/update',
method: 'POST',
data
})
}
export function deploy(data) {
return request({
url: baseUrl + '/deploy',
method: 'POST',
data
})
}
export function remove(data) {
return request({
url: baseUrl + '/remove',
method: 'POST',
data
})
}
import request from '@/utils/request'
// 增删改查共用,根据具体请求方法实现
export const baseUrl = '/flow/deployment'
export function add(data) {
return request({
url: baseUrl + '/add',
method: 'POST',
data
})
}
export function update(data) {
return request({
url: baseUrl + '/update',
method: 'POST',
data
})
}
export function remove(data) {
return request({
url: baseUrl + '/remove',
method: 'POST',
data
})
}
import request from '@/utils/request'
// 增删改查共用,根据具体请求方法实现
export const baseUrl = '/flow/history'
export function add(data) {
return request({
url: baseUrl + '/add',
method: 'POST',
data
})
}
export function update(data) {
return request({
url: baseUrl + '/update',
method: 'POST',
data
})
}
export function remove(data) {
return request({
url: baseUrl + '/remove',
method: 'POST',
data
})
}
export function queryAllHistoryByRuntime(data) {
return request({
url: baseUrl + '/queryAllHistoryByRuntime',
method: 'POST',
data
})
}
import request from '@/utils/request'
// 增删改查共用,根据具体请求方法实现
export const baseUrl = '/flow/node'
export function add(data) {
return request({
url: baseUrl + '/add',
method: 'POST',
data
})
}
export function update(data) {
return request({
url: baseUrl + '/update',
method: 'POST',
data
})
}
export function remove(data) {
return request({
url: baseUrl + '/remove',
method: 'POST',
data
})
}
export function getAllEnumByDefinitionId(definitionId) {
return request({
url: baseUrl + '/getAllEnumByDefinitionId?definitionId=' + definitionId,
method: 'GET'
})
}
import request from '@/utils/request'
// 增删改查共用,根据具体请求方法实现
export const baseUrl = '/flow/runtime'
export function add(data) {
return request({
url: baseUrl + '/add',
method: 'POST',
data
})
}
export function update(data) {
return request({
url: baseUrl + '/update',
method: 'POST',
data
})
}
export function remove(data) {
return request({
url: baseUrl + '/remove',
method: 'POST',
data
})
}
export function nodeComplete(data) {
return request({
url: baseUrl + '/nodeComplete',
method: 'POST',
data
})
}
// 基础数据
export const salesForecast = {
createUrl: '/salesForecast/create',
searchUrl: '/salesForecast/search',
detailUrl: '/salesForecast/getOne',
updateUrl: '/salesForecast/update',
deleteUrl: '/salesForecast/delete'
}
// 报表基础数据
export const salesForecastReport = {
createUrl: '/salesForecastReport/create',
searchUrl: '/salesForecastReport/search',
detailUrl: '/salesForecastReport/getOne',
updateUrl: '/salesForecastReport/update',
deleteUrl: '/salesForecastReport/delete'
}
// 库存模块
export const inventory = {
createUrl: '/inventory/create',
searchUrl: '/inventory/search',
detailUrl: '/inventory/getOne',
updateUrl: '/inventory/update'
}
// 库存上传模块
export const inventoryReport = {
searchUrl: '/inventoryReport/search'
}
import request from '@/utils/request'
export const invoiceApply = {
searchUrl: '/invoiceApply/search', // 开票申请单-分页查询
detailUrl: '/invoiceApply/getOne' // 开票申请单-查询单条
}
export const billingMessage = {
searchUrl: '/billingMessage/search', // 开票信息-分页查询
detailUrl: '/billingMessage/getOne' // 开票信息--查询一条数据
}
// 开票申请单-查询一条数据
export function invoiceApplyGetOne(data) {
return request({
url: '/invoiceApply/getOne',
method: 'post',
data: data
})
}
// 开票申请单-更新一条数据
export function invoiceApplyUpdate(data) {
return request({
url: '/invoiceApply/update',
method: 'post',
data: data
})
}
// 开票申请单-创建
export function invoiceApplyCreate(data) {
return request({
url: '/invoiceApply/create',
method: 'post',
data: data
})
}
// 开票信息-查询一条数据
export function billingMessageGetOne(data) {
return request({
url: '/billingMessage/getOne',
method: 'post',
data: data
})
}
// 开票信息-更新一条数据
export function billingMessageUpdate(data) {
return request({
url: '/billingMessage/update',
method: 'post',
data: data
})
}
import dictionary from '@/api/dictionary'
/**
* ele-form里面lov组件的配置
Key: {
type: 'lov', // 类型,必填,固定值为lov
code: 'customer', // lov配置码,必填,用于生成lov配置,具体实现见下面customer
searchUrl: '', // 表格数据请求地址,选填,若不填,使用`/${code}/search`请求数据
displayKey: '', // 展示的字段,选填,不填的话展示弹出表格的第一列字段
initialParams: {
roleCode: 'BUP002'
}, // lov初始配置传参
returnFn: function(row) {
return {
ParentAccountID: row.ObjectID,
ParentAccountText: row.Name
}
} // 返回值处理,选填,返回格式必须为object,若不填只会返回lov显示的值
}
**/
export default {
// 客户
customer: {
searchUrl: '', // 若为空,直接对象key+/search值作为请求url,这里为customer/search
formDesc: {
Name: {
label: '客户名称',
type: 'input',
layout: 12
},
Ext_CustomerType_KUT: {
label: '客户类型',
type: 'select',
value: 'Ext_CustomerType_KUTText',
options: dictionary.customerType,
layout: 12
}
}
},
// 合同
contract: {
searchUrl: '',
formDesc: {
ID: {
label: '合同编号',
type: 'input',
layout: 12
},
Name: {
label: '合同标题',
type: 'input',
layout: 12
}
}
},
// 员工选择器
employee: {
formDesc: {
Ext_EmployeeUserName_KUT: {
label: '账号',
type: 'input',
layout: 12
},
LastName: {
label: '姓名',
type: 'input',
layout: 12
}
}
},
quotationModel: {
searchUrl: '/model/search',
formDesc: {
ProductModel: {
label: '产品型号',
type: 'input',
layout: 12
}
}
},
// 型号
model: {
formDesc: {
ProjectName: {
label: '项目名称',
type: 'input',
layout: 12
},
ProductVersion: {
label: '产品版本',
type: 'input',
layout: 12
},
ProductSeries: {
label: '产品系列',
type: 'input',
layout: 12
},
ProductModel: {
label: '产品型号',
type: 'input',
layout: 12
}
}
},
// 竞争对手
competitor: {
formDesc: {
Name: {
label: '竞争对手名称',
type: 'input',
layout: 12
}
}
},
// 公司
company: {
formDesc: {
CompanyID: {
label: '公司编码',
type: 'input',
layout: 12
},
Name: {
label: '公司名称',
type: 'input',
layout: 12
}
}
},
// 部门
department: {
formDesc: {
CompanyName: {
label: '公司名称',
type: 'input',
layout: 12
},
Name: {
label: '部门名称',
type: 'input',
layout: 12
}
}
},
// 角色
roleToMenu: {
formDesc: {
ID: {
label: 'ID',
type: 'input',
layout: 12
},
Name: {
label: '角色名称',
type: 'input',
layout: 12
}
}
},
// 客户付款银行
customerBank: {
formDesc: {
DepositBank: {
label: '开户行',
type: 'input',
layout: 12
},
BankAccount: {
label: '银行账户',
type: 'input',
layout: 12
}
}
}
}
// 公告
export const notice = {
createUrl: '/notice/create',
searchUrl: '/notice/search',
detailUrl: '/notice/getOneDetail',
updateUrl: '/notice/update',
deleteUrl: '/notice/delete',
detailOrgUrl: '/notice/getOneDetailWithOrganization', // 有发布对象的getOne
getOrganizationUrl: '/notice/getOrganization', // 发布对象组织
createPublishUrl: '/notice/createPublish', // 发布对象更新
updateTimeUrl: '/notice/updateTime', // 发布接口
myPublishUrl: '/notice/myPublish', // 查询已发布公告
searchPublishUrl: '/notice/searchPublish', // 查询已发布公告
updatePublishUrl: '/notice/updatePublish' // 更新已发布公告(阅读状态、确认状态)
}
// 订单
export const GMOrder = {
createUrl: '/GMOrder/create',
searchUrl: '/GMOrder/search',
detailUrl: '/GMOrder/getOne',
updateUrl: '/GMOrder/update',
deleteUrl: '/GMOrder/delete'
}
// 需求单
export const GMOrderRequest = {
createUrl: '/GMOrderRequest/create',
searchUrl: '/GMOrderRequest/search',
detailUrl: '/GMOrderRequest/getOne',
updateUrl: '/GMOrderRequest/update',
deleteUrl: '/GMOrderRequest/delete',
batchDeleteUrl: '/GMOrderRequest/batchDelete'
}
// 公司管理
export const company = {
createUrl: '/company/create',
searchUrl: '/company/search',
updateUrl: '/company/update',
getOrganizationUrl: '/company/getOrganization'
}
// 部门
export const department = {
createUrl: '/department/create',
searchUrl: '/department/search',
updateUrl: '/department/update',
deleteUrl: '/department/delete'
}
// 研发项目
export const rdproject = {
createUrl: '/rdproject/create',
searchUrl: '/rdproject/search',
detailUrl: '/rdproject/getOne',
updateUrl: '/rdproject/update',
deleteUrl: '/rdproject/allDelete'
}
// 研发项目-版本
export const version = {
createUrl: '/version/create',
searchUrl: '/version/search',
searchAllUrl: '/version/searchAll',
detailUrl: '/version/getOne',
updateUrl: '/version/update',
deleteUrl: '/version/delete',
statusUrl: '/version/batchStatus',
copyUrl: '/version/copy'
}
// 研发项目-系列
export const series = {
createUrl: '/series/create',
searchUrl: '/series/search',
detailUrl: '/series/getOne',
updateUrl: '/series/update',
deleteUrl: '/series/delete',
statusUrl: '/series/batchStatus'
}
// 研发项目-型号
export const model = {
createUrl: '/model/create',
searchUrl: '/model/search',
detailUrl: '/model/getOne',
updateUrl: '/model/update',
deleteUrl: '/model/delete',
statusUrl: '/model/batchStatus'
}
// ERP物料
export const eRPProductInformation = {
searchUrl: '/eRPProductInformation/search',
detailUrl: '/eRPProductInformation/getOne',
updateUrl: '/eRPProductInformation/update'
}
// 产品价格
export const productModelPrice = {
searchUrl: '/productModelPrice/search',
detailUrl: '/productModelPrice/getOne',
updateUrl: '/productModelPrice/update'
}
import request from '@/utils/request'
export function getToken() {
return request({
url: '/qiniu/upload/token', // 假地址 自行替换
method: 'get'
})
}
import request from '@/utils/request'
export const quotedPriceUrl = {
searchUrl: '/salesQuote/search',
detailUrl: '/salesQuote/getOne',
createUrl: '/salesQuote/create',
updateUrl: '/salesQuote/update',
deleteUrl: '/salesQuote/delete'
}
// 查询全部
export function getAllData(data) {
return request({
url: '/salesQuote/search',
method: 'post',
data
})
}
// 查询单条数据
export function getOneData(data) {
return request({
url: '/salesQuote/getOne',
method: 'post',
data: data
})
}
// 新建数据
export function createData(data) {
return request({
url: '/salesQuote/create',
method: 'post',
data: data
})
}
// 更新数据
export function updateData(data) {
return request({
url: '/salesQuote/update',
method: 'post',
data: data
})
}
// 删除数据
export function deleteData(data) {
return request({
url: '/salesQuote/delete',
method: 'post',
data: data
})
}
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
})
}
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'
})
}
// 定时任务
export const cronjob = {
createUrl: '/cronjob/add',
searchUrl: '/cronjob/search',
detailUrl: '/cronjob/getOne',
updateUrl: '/cronjob/update',
deleteUrl: '/cronjob/remove',
triggerUrl: '/cronjob/trigger',
triggerAllUrl: '/cronjob/triggerAll',
cancelUrl: '/cronjob/cancel',
cancelAllUrl: '/cronjob/cancelAll'
}
import request from '@/utils/request'
export function test() {
return request({
url: '/debug/user',
method: 'get'
})
}
// 101-Customer
// 111-Competitor
// 121-CompetitorProduct
// 131-Visit
export const uploadCode = {
customer: '101',
competitor: '111',
competitorProduct: '121',
visit: '131',
product: '141',
notice: '151',
visitReport: '161',
weekly: '171',
monthly: '181',
task: '191',
contract: '211',
contractTemplate: '221'
}
// path传模块编号
// 竞争对手:Ext_CompetitorID_KUT
// 竞争对手产品:Ext_CompetitorProductID_KUT
// 合同:Ext_ContractID_KUT
// 报价:Ext_QuoteID_KUT
// 拜访:Ext_VisitID_KUT
// 任务:Ext_CustomerTaskID_KUT
// 研发项目:ProjectID
// 周报:WeeklyID
// 月报:MonthlyID
// 附件
export const upload = {
createUrl: process.env.VUE_APP_BASE_API + '/file/uploadFile',
deleteUrl: process.env.VUE_APP_BASE_API + '/file/deleteDetail'
}
import request from '@/utils/request'
export function login(data) {
return request({
url: '/index/login',
method: 'post',
data
})
}
// export function getInfo(token) {
// return request({
// url: '/vue-element-admin/user/info',
// method: 'get',
// params: { token }
// })
// }
export function logout() {
return request({
url: '/index/logout',
method: 'get'
})
}
export function test() {
return request({
url: '/sap/c4c/odata/v1/pcmportal/get_partner_contact?$format=json',
method: 'get'
})
}
This diff is collapsed.
<template>
<transition :name="transitionName">
<div v-show="visible" :style="customStyle" class="back-to-ceiling" @click="backToTop">
<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>
</div>
</transition>
</template>
<script>
export default {
name: 'BackToTop',
props: {
visibilityHeight: {
type: Number,
default: 400
},
backPosition: {
type: Number,
default: 0
},
customStyle: {
type: Object,
default: function() {
return {
right: '50px',
bottom: '50px',
width: '40px',
height: '40px',
'border-radius': '4px',
'line-height': '45px',
background: '#e7eaf1'
}
}
},
transitionName: {
type: String,
default: 'fade'
}
},
data() {
return {
visible: false,
interval: null,
isMoving: false
}
},
mounted() {
window.addEventListener('scroll', this.handleScroll)
},
beforeDestroy() {
window.removeEventListener('scroll', this.handleScroll)
if (this.interval) {
clearInterval(this.interval)
}
},
methods: {
handleScroll() {
this.visible = window.pageYOffset > this.visibilityHeight
},
backToTop() {
if (this.isMoving) return
const start = window.pageYOffset
let i = 0
this.isMoving = true
this.interval = setInterval(() => {
const next = Math.floor(this.easeInOutQuad(10 * i, start, -start, 500))
if (next <= this.backPosition) {
window.scrollTo(0, this.backPosition)
clearInterval(this.interval)
this.isMoving = false
} else {
window.scrollTo(0, next)
}
i++
}, 16.7)
},
easeInOutQuad(t, b, c, d) {
if ((t /= d / 2) < 1) return c / 2 * t * t + b
return -c / 2 * (--t * (t - 2) - 1) + b
}
}
}
</script>
<style scoped>
.back-to-ceiling {
position: fixed;
display: inline-block;
text-align: center;
cursor: pointer;
}
.back-to-ceiling:hover {
background: #d5dbe7;
}
.fade-enter-active,
.fade-leave-active {
transition: opacity .5s;
}
.fade-enter,
.fade-leave-to {
opacity: 0
}
.back-to-ceiling .Icon {
fill: #9aaabf;
background: none;
}
</style>
<template>
<el-breadcrumb class="app-breadcrumb" separator="/">
<transition-group name="breadcrumb">
<el-breadcrumb-item v-for="(item,index) in levelList" :key="item.path">
<span v-if="item.redirect==='noRedirect'||index==levelList.length-1" class="no-redirect">
{{ generateTitle(item.meta.title) }}
</span>
<a v-else @click.prevent="handleLink(item)">{{ generateTitle(item.meta.title) }}</a>
</el-breadcrumb-item>
</transition-group>
</el-breadcrumb>
</template>
<script>
import { generateTitle } from '@/utils/i18n'
import pathToRegexp from 'path-to-regexp'
export default {
data() {
return {
levelList: null
}
},
watch: {
$route(route) {
// if you go to the redirect page, do not update the breadcrumbs
if (route.path.startsWith('/redirect/')) {
return
}
this.getBreadcrumb()
}
},
created() {
this.getBreadcrumb()
},
methods: {
generateTitle,
getBreadcrumb() {
// only show routes with meta.title
let matched = this.$route.matched.filter(item => item.meta && item.meta.title)
const first = matched[0]
if (!this.isDashboard(first)) {
matched = [{ path: '/dashboard', meta: { title: 'dashboard' } }].concat(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>
<style lang="scss" scoped>
.app-breadcrumb.el-breadcrumb {
display: inline-block;
font-size: 14px;
line-height: 50px;
margin-left: 8px;
.no-redirect {
color: #97a8be;
cursor: text;
}
}
</style>
import BusinessTable from './index.vue'
BusinessTable.install = function(Vue) {
Vue.component(BusinessTable.name, BusinessTable)
}
export default BusinessTable
<template>
<div class="table-container">
<form-title :title="tableConfig.tableTitle">
<div>
<slot
name="btn"
:selection="selection"
/>
<el-button
v-if="createUrl"
type="primary"
icon="el-icon-plus"
@click="handleAdd()"
>添加</el-button>
<el-button
v-if="deleteUrl"
type="danger"
icon="el-icon-delete"
@click="handleBatchDelete()"
>删除</el-button>
</div>
</form-title>
<ele-table
ref="eleTable"
:listeners="tableListeners"
v-bind="tableConfig"
:expand-params="expandParams"
@handleSelectionChange="handleSelectionChange"
/>
<ele-form-dialog
v-model="formData"
:title="dialogTitle"
:request-fn="handleSave"
:visible.sync="dialogFormVisible"
v-bind="formConfig"
:loading="loading"
/>
</div>
</template>
<script>
export default {
name: 'BusinessTable',
props: {
tableConfig: {
type: Object,
default: () => { }
},
formConfig: {
type: Object,
default: () => {
return {
formDesc: {}
}
}
},
expandParams: {
type: Object,
default: () => { }
},
// 新建接口地址
createUrl: {
type: String,
default: ''
},
// 更新接口地址
updateUrl: {
type: String,
default: ''
},
// 查行详情地址
detailUrl: {
type: String,
default: ''
},
// 删除接口地址
deleteUrl: {
type: String,
default: ''
}
},
data() {
return {
desc: {},
tableListeners: {}, // 事件监听对象,供ele-table内部调用
formData: {},
$index: -1,
selection: [],
dialogFormVisible: false,
dialogTitle: '',
loading: false
}
},
created() {
this.init()
},
methods: {
init() {
const tableTitle = this.tableConfig.tableTitle
this.desc = {
add: '创建' + tableTitle,
edit: '编辑' + tableTitle
}
this.tableListeners = {
handleCheck: this.handleCheck,
handleEdit: this.handleEdit,
handleDelete: this.handleDelete
}
},
search() {
this.$refs.eleTable.handleSearch()
},
handleCheck(...rest) {
this.$emit('handleCheck', rest)
},
handleAdd() {
this.dialogTitle = this.desc.add
this.formData = {}
this.dialogFormVisible = true
},
handleEdit(row, index, isRequest = false) {
this.dialogTitle = this.desc.edit
this.$index = index
if (isRequest && this.detailUrl) {
this.loading = true
this.$request(this.detailUrl, { objectID: row.ObjectID }).then(res => {
this.formData = res.results[0]
this.loading = false
})
} else {
this.formData = JSON.parse(JSON.stringify(row))
}
this.dialogFormVisible = true
},
handleSave() {
this.loading = true
const formData = this.$translateToC4CData(this.formData)
if (this.dialogTitle === this.desc.add) {
const accountID = this.$route.query.objectID || this.tableConfig.initialParams.objectID
formData.accountID = accountID
this.$request(this.createUrl, [formData]).then(res => {
this.formData.objectID = res.results[0]
if (this.tableConfig.url) {
this.search()
} else {
this.$refs.eleTable.add(this.formData)
}
this.dialogFormVisible = false
this.loading = false
}).catch(() => {
this.loading = false
})
} else {
this.updateUrl && this.$request(this.updateUrl, formData).then(res => {
if (this.tableConfig.url) {
this.search()
} else {
this.$refs.eleTable.edit(this.$index, this.formData)
}
this.dialogFormVisible = false
this.loading = false
}).catch(() => {
this.loading = false
})
}
},
handleSelectionChange(selection) {
this.selection = selection
},
handleBatchDelete() {
var selection = this.selection
if (selection.length === 0) {
this.$message.warning('请先选择一行数据')
return
} else if (selection.length === 1) {
selection = this.$translateToC4CData(selection[0])
} else {
selection = selection.map(item => {
return this.$translateToC4CData(item)
})
}
this.$confirm('此操作将永久删除该数据, 是否继续?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
this.$request(this.deleteUrl, selection).then(res => {
this.$message({
type: 'success',
message: '删除成功!'
})
this.search()
})
})
},
handleDelete() {
}
}
}
</script>
<style>
</style>
import DescriptionTable from './index.vue'
DescriptionTable.install = function(Vue) {
Vue.component(DescriptionTable.name, DescriptionTable)
}
export default DescriptionTable
<template>
<div class="description-table">
<form-title
v-if="tableConfig.tableTitle"
:title="tableConfig.tableTitle"
>
<el-button
v-if="tableConfig.isShowEditBtn"
type="text"
icon="el-icon-edit"
@click="handleEdit"
>{{
$t('table.edit')
}}</el-button>
</form-title>
<div>
<el-descriptions
:column="2"
size="small"
border
>
<el-descriptions-item
v-for="(item, key) in formConfig"
:key="key"
:label="item.label+':'"
>
{{ item.value ? tableDataLocal[item.value] : tableDataLocal[key] }}
</el-descriptions-item>
<el-descriptions-item v-if="Object.keys(formConfig).length % 2 === 1" />
</el-descriptions>
</div>
<ele-form-dialog
v-model="formData"
:title="tableConfig.dialogTitle || '编辑' + tableConfig.tableTitle"
:request-fn="handleSave"
:visible.sync="dialogFormVisible"
v-bind="tableConfig"
:loading="loading"
/>
</div>
</template>
<script>
export default {
name: 'DescriptionTable',
props: {
tableConfig: {
type: Object,
default: () => { }
},
tableData: {
type: Object,
default: () => { }
}
},
data() {
return {
loading: false,
formConfig: this.tableConfig.formDesc,
tableDataLocal: {},
formData: {},
dialogFormVisible: false,
}
},
watch: {
tableData: {
handler(newVal) {
this.tableDataLocal = newVal || {}
},
immediate: true,
deep: true
}
},
created() {
},
methods: {
handleEdit() {
this.formData = JSON.parse(JSON.stringify(this.tableDataLocal))
this.dialogFormVisible = true
},
// 弹窗【保存】 更新单条数据
handleSave() {
const fd = this.$getUpdateChange(this.tableDataLocal, this.formData, false)
const formData = this.$translateToC4CData(fd)
this.loading = true
this.$request(this.tableConfig.updateUrl, formData).then(() => {
this.loading = false
this.$message.success('更新成功')
this.tableDataLocal = this.formData
this.dialogFormVisible = false
})
}
}
}
</script>
<style lang="scss" scoped>
.description-table {
margin: 20px;
::v-deep .el-descriptions-item__label {
width: 150px;
text-align: right;
padding-right: 4px;
}
}
</style>
import DetailTable from './index.vue'
DetailTable.install = function(Vue) {
Vue.component(DetailTable.name, DetailTable)
}
export default DetailTable
<template>
<div
class="details-area"
:class="{ noTitle: !tableConfig.tableTitle, noEdit: !tableConfig.isShowEditBtn }"
>
<form-title
v-if="tableConfig.tableTitle"
:title="tableConfig.tableTitle"
/>
<div
v-if="tableConfig.isShowEditBtn"
class="right-btn"
>
<el-button
type="text"
icon="el-icon-edit"
@click="handleEdit"
>{{
$t('table.edit')
}}</el-button>
</div>
<!-- <div class="details-table">
<div
v-for="(value, name) in formConfig"
:key="name"
class="panel-item"
>
<div class="label">{{ value.label }}</div>
<div
v-if="value.value"
class="value"
>{{ tableDataLocal[value.value] }}</div>
<div
v-else-if="value.isOptions"
class="value"
>{{ Array.isArray(value.options) && value.options.find(it => it.value === tableDataLocal[name]).text }}</div>
<div
v-else
class="value"
>{{ tableDataLocal[name] }}</div>
</div>
<div
v-if="Object.keys(formConfig).length % 2 === 1"
class="panel-item"
>
<div class="label" />
<div class="value" />
</div>
</div> -->
<div class="description-table">
<el-descriptions
:column="column"
size="small"
border
>
<el-descriptions-item
v-for="(item, key) in formConfig"
:key="key"
:label="item.label+':'"
>
<div v-if="item.value">{{ tableDataLocal[item.value] }}</div>
<div v-else-if="item.isOptions">{{ Array.isArray(item.options) && item.options.find(it => it.value === tableDataLocal[key]).text }}</div>
<div v-else>
{{ tableDataLocal[key] }}
</div>
</el-descriptions-item>
<el-descriptions-item v-if="Object.keys(formConfig).length % column !== 0" />
</el-descriptions>
</div>
<ele-form-dialog
v-model="formData"
:title="tableConfig.dialogTitle || '编辑' + tableConfig.tableTitle"
:request-fn="handleSave"
:visible.sync="dialogFormVisible"
v-bind="tableConfig"
:loading="loading"
/>
</div>
</template>
<script>
import rowMixin from '@/mixins/row'
export default {
name: 'DetailTable',
mixins: [rowMixin],
props: {
tableConfig: {
type: Object,
default: () => { }
},
tableData: {
type: Object,
default: () => { }
},
editUrl: {
type: String,
default: ''
},
column: {
type: Number,
default: 2
}
},
data() {
return {
loading: false,
formConfig: this.tableConfig.formDesc,
tableDataLocal: {},
formData: {},
dialogFormVisible: false,
sessionRowName: null
}
},
watch: {
tableData: {
handler(newVal) {
this.tableDataLocal = newVal || {}
},
immediate: true,
deep: true
}
},
created() {
if (Object.keys(this.tableData).length === 0) {
this.sessionRowName =
this.$route.query.sessionRowName || this.tableConfig.sessionRowName
this.getLocalData()
} else {
this.tableDataLocal = this.tableData
}
},
methods: {
// 先获取本地数据
getLocalData() {
const data = sessionStorage.getItem(this.sessionRowName)
const formData = this.sessionRowName && data && data !== 'undefined' ? JSON.parse(data) : null
if (formData) {
this.tableDataLocal = formData
} else if (this.$route.query.objectID) {
this.getOne()
}
},
// 根据objectID获取单条数据
getOne() {
this.loading = true
this.$request(this.tableConfig.detailUrl, {
objectID: this.$route.query.objectID
}).then((res) => {
this.loading = false
const formData = res.results[0]
this.tableDataLocal = formData
sessionStorage.setItem(this.sessionRowName, JSON.stringify(formData))
})
},
handleEdit() {
if (this.editUrl) {
this.$router.push({
path: this.editUrl,
query: {
objectID: this.formData.ObjectID
}
})
}
this.formData = JSON.parse(JSON.stringify(this.tableDataLocal))
this.dialogFormVisible = true
},
// 弹窗【保存】 更新单条数据
handleSave() {
const fd = this.$getUpdateChange(this.tableDataLocal, this.formData, false)
const formData = this.$translateToC4CData(fd)
this.loading = true
this.$request(this.tableConfig.updateUrl, formData).then(() => {
this.loading = false
this.$message.success('更新成功!')
Object.assign(this.tableDataLocal, fd)
sessionStorage.setItem(
this.sessionRowName,
JSON.stringify(this.tableDataLocal)
)
this.dialogFormVisible = false
})
}
}
}
</script>
<style lang="scss" scoped>
.details-area {
position: relative;
.form-title {
margin: 24px 20px;
}
.right-btn {
position: absolute;
right: 20px;
top: 0;
}
}
.noTitle:not(.noEdit) {
padding-top: 50px;
.right-btn {
top: 15px;
}
}
.details-table {
margin: 10px 20px;
display: flex;
flex-wrap: wrap;
border: 0.5px solid #ddd;
> div {
border: 0.5px solid #ddd;
}
.panel-item {
display: flex;
width: 50%;
color: #666;
font-size: 12px;
}
.panel-item > div {
min-height: 46px;
line-height: 26px;
padding: 10px 20px;
}
.label {
width: 28%;
font-weight: 700;
text-align: right;
background-color: #f5f5f5;
border-right: 1px solid #ddd;
}
.value {
flex: 1;
}
}
.description-table {
margin: 0 20px;
::v-deep .el-descriptions-item__label {
width: 150px;
text-align: right;
padding-right: 4px;
}
}
</style>
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
<template>
<el-tabs
v-model="currentGroupId"
v-bind="attrs"
v-on="tabOn"
>
<template v-for="item of computedGroups">
<el-tab-pane
v-if="getVif(item)"
:key="item.groupId"
:label="item.groupLabel"
:name="item.groupId"
>
<ele-form
v-if="item.groupId === currentGroupId"
ref="ele-form"
v-bind="item.form"
v-on="item.on"
>
<template
v-for="(formItem, key, index) of item.form.formDesc"
v-slot:[key]="{ desc, props, field, formData }"
>
<slot
:data="formData[field]"
:desc="desc"
:props="props"
:field="field"
:formData="formData"
:name="item.groupId + '-' + field"
:disabled="desc._disabled"
:type="desc._type"
:options="desc._options"
>
<component
:is="desc._type"
:ref="field"
:key="index"
:disabled="desc._disabled"
:desc="desc"
:options="desc._options"
:form-data="formData"
:readonly="props.readonly"
:field="field"
:value="getValue(field)"
:_disabled="desc._disabled"
@input="setValue(field, $event)"
/>
</slot>
</template>
<!-- 按钮插槽 -->
<template v-slot:form-btn="{ btns }">
<slot
:btns="btns"
:name="item.groupId + '-form-btn'"
/>
</template>
</ele-form>
</el-tab-pane>
</template>
</el-tabs>
</template>
<script>
import { isDef } from './tools/utils'
export default {
name: 'EleFormGroup',
inheritAttrs: false,
props: {
// 自定义tab属性, 具体参考:https://element.eleme.cn/#/zh-CN/component/tabs#tabs-attributes
tabAttrs: {
type: Object,
default: () => { }
},
// tab的事件, 具体参考:https://element.eleme.cn/#/zh-CN/component/tabs#tabs-events
tabOn: {
type: Object,
default: () => { }
},
// 分组
groups: {
type: Array,
required: true
},
// 默认激活的tab
activeGroupId: {
type: [String, Number],
default: ''
}
},
data() {
return {
getDeepFormDesc: null,
currentGroupId: ''
}
},
computed: {
// 所有组的表单值
allFormData() {
return this.computedGroups.reduce(
(acc, group) => Object.assign(acc, group.form.formData),
{}
)
},
// tabs的属性
attrs() {
return Object.assign({}, { type: 'border-card' }, this.tabAttrs)
},
// 修改form属性
computedGroups() {
return this.groups.map(item => {
item.form = Object.assign({}, this.$attrs, item.form)
item.on = Object.assign({}, this.$listeners, item.on)
return item
})
}
},
mounted() {
// 获取默认激活的分组
if (isDef(this.activeGroupId)) {
this.currentGroupId = this.activeGroupId
} else {
// 使用groups中的第一个
if (this.groups.length) {
this.currentGroupId = this.groups[0].groupId
}
}
},
methods: {
getValue(val, index) {
if (this.$refs['ele-form'] && this.$refs['ele-form'][0]) {
return this.$refs['ele-form'][0].getValue(val)
}
},
setValue(field, $event) {
this.$refs['ele-form'][0].setValue(field, $event)
},
getVif(group) {
if (typeof group.vif === 'function') {
return group.vif(this.allFormData)
} else if (typeof group.vif === 'boolean') {
return group.vif
} else {
return true
}
}
}
}
</script>
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment