mirror of
https://github.com/jeecgboot/JeecgBoot.git
synced 2025-12-08 17:12:28 +08:00
jeecg-boot 1.0版本发布
This commit is contained in:
147
README.md
Normal file
147
README.md
Normal file
@ -0,0 +1,147 @@
|
|||||||
|
Jeecg-Boot 快速开发平台(前后端分离版本)
|
||||||
|
===============
|
||||||
|
|
||||||
|
当前最新版本: 1.0(发布日期:20190225)
|
||||||
|
|
||||||
|
项目介绍:
|
||||||
|
-----------------------------------
|
||||||
|
Jeecg-boot 一个全新的版本,采用前后端分离方案,提供强大代码生成器的快速开发平台
|
||||||
|
前端页面代码和后端功能代码一键生成,不需要写任何代码,保持jeecg一贯的强大!!
|
||||||
|
|
||||||
|
|
||||||
|
技术架构:
|
||||||
|
-----------------------------------
|
||||||
|
后端技术: SpringBoot + Mybatis-plus + Shiro + Jwt + Swagger-ui + Redis
|
||||||
|
前端技术: Ant-design-vue + Vue + Webpack
|
||||||
|
其他技术: Druid(数据库连接池)、Logback(日志工具) 、poi(Excel工具)、
|
||||||
|
Quartz(定时任务)、lombok(简化代码)
|
||||||
|
项目构建: Maven、Jdk8
|
||||||
|
|
||||||
|
|
||||||
|
前端开发必读文档:
|
||||||
|
|
||||||
|
前端UI组件: Ant Design of Vue
|
||||||
|
https://vuecomponent.github.io/ant-design-vue/docs/vue/introduce-cn
|
||||||
|
报表UI组件:viser-vue
|
||||||
|
https://viserjs.github.io/demo.html#/viser/bar/basic-bar
|
||||||
|
VUE基础知识:
|
||||||
|
https://cn.vuejs.org/v2/guide
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Overview
|
||||||
|
----
|
||||||
|
|
||||||
|
基于 [Ant Design of Vue](https://vuecomponent.github.io/ant-design-vue/docs/vue/introduce-cn/) 实现的 Vue 版
|
||||||
|
|
||||||
|
[预览地址](http://boot.jeecg.org) **附带一些后台基础用到的列表展示例子**
|
||||||
|
效果抢先看:
|
||||||
|
|
||||||
|
1. 系统效果
|
||||||
|

|
||||||
|

|
||||||
|

|
||||||
|

|
||||||
|

|
||||||
|

|
||||||
|

|
||||||
|

|
||||||
|

|
||||||
|

|
||||||
|

|
||||||
|

|
||||||
|
|
||||||
|
|
||||||
|
技术文档
|
||||||
|
-----------------------------------
|
||||||
|
* [在线演示](http://boot.jeecg.org)
|
||||||
|
* [官方文档](http://jeecg-boot.mydoc.io)
|
||||||
|
* QQ交流群:284271917
|
||||||
|
|
||||||
|
|
||||||
|
前端开发环境和依赖
|
||||||
|
----
|
||||||
|
- node
|
||||||
|
- yarn
|
||||||
|
- webpack
|
||||||
|
- eslint
|
||||||
|
- @vue/cli 3.2.1
|
||||||
|
- [ant-design-vue](https://github.com/vueComponent/ant-design-vue) - Ant Design Of Vue 实现
|
||||||
|
- [vue-cropper](https://github.com/xyxiao001/vue-cropper) - 头像裁剪组件
|
||||||
|
- [@antv/g2](https://antv.alipay.com/zh-cn/index.html) - Alipay AntV 数据可视化图表
|
||||||
|
- [Viser-vue](https://viserjs.github.io/docs.html#/viser/guide/installation) - antv/g2 封装实现
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
项目下载和运行
|
||||||
|
----
|
||||||
|
|
||||||
|
- 拉取项目代码
|
||||||
|
```bash
|
||||||
|
git clone https://github.com/zhangdaiscott/jeecg-boot.git
|
||||||
|
cd jeecg-boot/ant-design-jeecg-vue
|
||||||
|
```
|
||||||
|
|
||||||
|
- 安装依赖
|
||||||
|
```
|
||||||
|
yarn install
|
||||||
|
```
|
||||||
|
|
||||||
|
- 开发模式运行
|
||||||
|
```
|
||||||
|
yarn run serve
|
||||||
|
```
|
||||||
|
|
||||||
|
- 编译项目
|
||||||
|
```
|
||||||
|
yarn run build
|
||||||
|
```
|
||||||
|
|
||||||
|
- Lints and fixes files
|
||||||
|
```
|
||||||
|
yarn run lint
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
其他说明
|
||||||
|
----
|
||||||
|
|
||||||
|
- 项目使用的 [vue-cli3](https://cli.vuejs.org/guide/), 请更新您的 cli
|
||||||
|
|
||||||
|
- 关闭 Eslint (不推荐) 移除 `package.json` 中 `eslintConfig` 整个节点代码
|
||||||
|
|
||||||
|
- 修改 Ant Design 配色,在文件 `vue.config.js` 中,其他 less 变量覆盖参考 [ant design](https://ant.design/docs/react/customize-theme-cn) 官方说明
|
||||||
|
```ecmascript 6
|
||||||
|
css: {
|
||||||
|
loaderOptions: {
|
||||||
|
less: {
|
||||||
|
modifyVars: {
|
||||||
|
/* less 变量覆盖,用于自定义 ant design 主题 */
|
||||||
|
|
||||||
|
'primary-color': '#F5222D',
|
||||||
|
'link-color': '#F5222D',
|
||||||
|
'border-radius-base': '4px',
|
||||||
|
},
|
||||||
|
javascriptEnabled: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
附属文档
|
||||||
|
----
|
||||||
|
|
||||||
|
- [路由/菜单说明](https://github.com/sendya/ant-design-pro-vue/blob/master/src/router/README.md)
|
||||||
|
|
||||||
|
- [ANTD 默认配置项](https://github.com/sendya/ant-design-pro-vue/blob/master/src/defaultSettings.js)
|
||||||
|
|
||||||
|
- 其他待补充...
|
||||||
|
|
||||||
|
|
||||||
|
备注
|
||||||
|
----
|
||||||
|
|
||||||
|
> @vue/cli 升级后,eslint 规则更新了。由于影响到全部 .vue 文件,需要逐个验证。既暂时关闭部分原本不验证的规则,后期维护时,在逐步修正这些 rules
|
||||||
39
ant-design-jeecg-vue/.editorconfig
Normal file
39
ant-design-jeecg-vue/.editorconfig
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
[*]
|
||||||
|
charset=utf-8
|
||||||
|
end_of_line=crlf
|
||||||
|
insert_final_newline=false
|
||||||
|
indent_style=space
|
||||||
|
indent_size=2
|
||||||
|
|
||||||
|
[{*.ng,*.sht,*.html,*.shtm,*.shtml,*.htm}]
|
||||||
|
indent_style=space
|
||||||
|
indent_size=2
|
||||||
|
|
||||||
|
[{*.jhm,*.xslt,*.xul,*.rng,*.xsl,*.xsd,*.ant,*.tld,*.fxml,*.jrxml,*.xml,*.jnlp,*.wsdl}]
|
||||||
|
indent_style=space
|
||||||
|
indent_size=2
|
||||||
|
|
||||||
|
[{.babelrc,.stylelintrc,jest.config,.eslintrc,.prettierrc,*.json,*.jsb3,*.jsb2,*.bowerrc}]
|
||||||
|
indent_style=space
|
||||||
|
indent_size=2
|
||||||
|
|
||||||
|
[*.svg]
|
||||||
|
indent_style=space
|
||||||
|
indent_size=2
|
||||||
|
|
||||||
|
[*.js.map]
|
||||||
|
indent_style=space
|
||||||
|
indent_size=2
|
||||||
|
|
||||||
|
[*.less]
|
||||||
|
indent_style=space
|
||||||
|
indent_size=2
|
||||||
|
|
||||||
|
[*.vue]
|
||||||
|
indent_style=space
|
||||||
|
indent_size=2
|
||||||
|
|
||||||
|
[{.analysis_options,*.yml,*.yaml}]
|
||||||
|
indent_style=space
|
||||||
|
indent_size=2
|
||||||
|
|
||||||
1
ant-design-jeecg-vue/.gitattributes
vendored
Normal file
1
ant-design-jeecg-vue/.gitattributes
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
public/* linguist-vendored
|
||||||
21
ant-design-jeecg-vue/.gitignore
vendored
Normal file
21
ant-design-jeecg-vue/.gitignore
vendored
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
.DS_Store
|
||||||
|
node_modules
|
||||||
|
/dist
|
||||||
|
|
||||||
|
# local env files
|
||||||
|
.env.local
|
||||||
|
.env.*.local
|
||||||
|
|
||||||
|
# Log files
|
||||||
|
npm-debug.log*
|
||||||
|
yarn-debug.log*
|
||||||
|
yarn-error.log*
|
||||||
|
|
||||||
|
# Editor directories and files
|
||||||
|
.idea
|
||||||
|
.vscode
|
||||||
|
*.suo
|
||||||
|
*.ntvs*
|
||||||
|
*.njsproj
|
||||||
|
*.sln
|
||||||
|
*.sw*
|
||||||
5
ant-design-jeecg-vue/.prettierrc
Normal file
5
ant-design-jeecg-vue/.prettierrc
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"printWidth": 120,
|
||||||
|
"semi": false,
|
||||||
|
"singleQuote": true
|
||||||
|
}
|
||||||
21
ant-design-jeecg-vue/LICENSE
Normal file
21
ant-design-jeecg-vue/LICENSE
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2018 Anan Yang
|
||||||
|
|
||||||
|
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.
|
||||||
147
ant-design-jeecg-vue/README.md
Normal file
147
ant-design-jeecg-vue/README.md
Normal file
@ -0,0 +1,147 @@
|
|||||||
|
Jeecg-Boot 快速开发平台(前后端分离版本)
|
||||||
|
===============
|
||||||
|
|
||||||
|
当前最新版本: 1.0(发布日期:20190225)
|
||||||
|
|
||||||
|
项目介绍:
|
||||||
|
-----------------------------------
|
||||||
|
Jeecg-boot 一个全新的版本,采用前后端分离方案,提供强大代码生成器的快速开发平台
|
||||||
|
前端页面代码和后端功能代码一键生成,不需要写任何代码,保持jeecg一贯的强大!!
|
||||||
|
|
||||||
|
|
||||||
|
技术架构:
|
||||||
|
-----------------------------------
|
||||||
|
后端技术: SpringBoot + Mybatis-plus + Shiro + Jwt + Swagger-ui + Redis
|
||||||
|
前端技术: Ant-design-vue + Vue + Webpack
|
||||||
|
其他技术: Druid(数据库连接池)、Logback(日志工具) 、poi(Excel工具)、
|
||||||
|
Quartz(定时任务)、lombok(简化代码)
|
||||||
|
项目构建: Maven、Jdk8
|
||||||
|
|
||||||
|
|
||||||
|
前端开发必读文档:
|
||||||
|
|
||||||
|
前端UI组件: Ant Design of Vue
|
||||||
|
https://vuecomponent.github.io/ant-design-vue/docs/vue/introduce-cn
|
||||||
|
报表UI组件:viser-vue
|
||||||
|
https://viserjs.github.io/demo.html#/viser/bar/basic-bar
|
||||||
|
VUE基础知识:
|
||||||
|
https://cn.vuejs.org/v2/guide
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Overview
|
||||||
|
----
|
||||||
|
|
||||||
|
基于 [Ant Design of Vue](https://vuecomponent.github.io/ant-design-vue/docs/vue/introduce-cn/) 实现的 Vue 版
|
||||||
|
|
||||||
|
[预览地址](http://boot.jeecg.org) **附带一些后台基础用到的列表展示例子**
|
||||||
|
效果抢先看:
|
||||||
|
|
||||||
|
1. 系统效果
|
||||||
|

|
||||||
|

|
||||||
|

|
||||||
|

|
||||||
|

|
||||||
|

|
||||||
|

|
||||||
|

|
||||||
|

|
||||||
|

|
||||||
|

|
||||||
|

|
||||||
|
|
||||||
|
|
||||||
|
技术文档
|
||||||
|
-----------------------------------
|
||||||
|
* [在线演示](http://boot.jeecg.org)
|
||||||
|
* [官方文档](http://jeecg-boot.mydoc.io)
|
||||||
|
* QQ交流群:284271917
|
||||||
|
|
||||||
|
|
||||||
|
前端开发环境和依赖
|
||||||
|
----
|
||||||
|
- node
|
||||||
|
- yarn
|
||||||
|
- webpack
|
||||||
|
- eslint
|
||||||
|
- @vue/cli 3.2.1
|
||||||
|
- [ant-design-vue](https://github.com/vueComponent/ant-design-vue) - Ant Design Of Vue 实现
|
||||||
|
- [vue-cropper](https://github.com/xyxiao001/vue-cropper) - 头像裁剪组件
|
||||||
|
- [@antv/g2](https://antv.alipay.com/zh-cn/index.html) - Alipay AntV 数据可视化图表
|
||||||
|
- [Viser-vue](https://viserjs.github.io/docs.html#/viser/guide/installation) - antv/g2 封装实现
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
项目下载和运行
|
||||||
|
----
|
||||||
|
|
||||||
|
- 拉取项目代码
|
||||||
|
```bash
|
||||||
|
git clone https://github.com/zhangdaiscott/jeecg-boot.git
|
||||||
|
cd jeecg-boot/ant-design-jeecg-vue
|
||||||
|
```
|
||||||
|
|
||||||
|
- 安装依赖
|
||||||
|
```
|
||||||
|
yarn install
|
||||||
|
```
|
||||||
|
|
||||||
|
- 开发模式运行
|
||||||
|
```
|
||||||
|
yarn run serve
|
||||||
|
```
|
||||||
|
|
||||||
|
- 编译项目
|
||||||
|
```
|
||||||
|
yarn run build
|
||||||
|
```
|
||||||
|
|
||||||
|
- Lints and fixes files
|
||||||
|
```
|
||||||
|
yarn run lint
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
其他说明
|
||||||
|
----
|
||||||
|
|
||||||
|
- 项目使用的 [vue-cli3](https://cli.vuejs.org/guide/), 请更新您的 cli
|
||||||
|
|
||||||
|
- 关闭 Eslint (不推荐) 移除 `package.json` 中 `eslintConfig` 整个节点代码
|
||||||
|
|
||||||
|
- 修改 Ant Design 配色,在文件 `vue.config.js` 中,其他 less 变量覆盖参考 [ant design](https://ant.design/docs/react/customize-theme-cn) 官方说明
|
||||||
|
```ecmascript 6
|
||||||
|
css: {
|
||||||
|
loaderOptions: {
|
||||||
|
less: {
|
||||||
|
modifyVars: {
|
||||||
|
/* less 变量覆盖,用于自定义 ant design 主题 */
|
||||||
|
|
||||||
|
'primary-color': '#F5222D',
|
||||||
|
'link-color': '#F5222D',
|
||||||
|
'border-radius-base': '4px',
|
||||||
|
},
|
||||||
|
javascriptEnabled: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
附属文档
|
||||||
|
----
|
||||||
|
|
||||||
|
- [路由/菜单说明](https://github.com/sendya/ant-design-pro-vue/blob/master/src/router/README.md)
|
||||||
|
|
||||||
|
- [ANTD 默认配置项](https://github.com/sendya/ant-design-pro-vue/blob/master/src/defaultSettings.js)
|
||||||
|
|
||||||
|
- 其他待补充...
|
||||||
|
|
||||||
|
|
||||||
|
备注
|
||||||
|
----
|
||||||
|
|
||||||
|
> @vue/cli 升级后,eslint 规则更新了。由于影响到全部 .vue 文件,需要逐个验证。既暂时关闭部分原本不验证的规则,后期维护时,在逐步修正这些 rules
|
||||||
5
ant-design-jeecg-vue/babel.config.js
Normal file
5
ant-design-jeecg-vue/babel.config.js
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
module.exports = {
|
||||||
|
presets: [
|
||||||
|
'@vue/app'
|
||||||
|
]
|
||||||
|
}
|
||||||
24
ant-design-jeecg-vue/idea.config.js
Normal file
24
ant-design-jeecg-vue/idea.config.js
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
'use strict'
|
||||||
|
const path = require('path')
|
||||||
|
|
||||||
|
function resolve (dir) {
|
||||||
|
return path.join(__dirname, '.', dir)
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
context: path.resolve(__dirname, './'),
|
||||||
|
resolve: {
|
||||||
|
extensions: ['.js', '.vue', '.json'],
|
||||||
|
alias: {
|
||||||
|
'config': resolve('config'),
|
||||||
|
'@': resolve('src'),
|
||||||
|
'@views': resolve('src/views'),
|
||||||
|
'@comp': resolve('src/components'),
|
||||||
|
'@core': resolve('src/core'),
|
||||||
|
'@utils': resolve('src/utils'),
|
||||||
|
'@entry': resolve('src/entry'),
|
||||||
|
'@router': resolve('src/router'),
|
||||||
|
'@store': resolve('src/store')
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
98
ant-design-jeecg-vue/package.json
Normal file
98
ant-design-jeecg-vue/package.json
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
{
|
||||||
|
"name": "vue-antd-pro",
|
||||||
|
"version": "1.1.0",
|
||||||
|
"private": true,
|
||||||
|
"scripts": {
|
||||||
|
"serve": "vue-cli-service serve --open",
|
||||||
|
"build": "vue-cli-service build",
|
||||||
|
"lint": "vue-cli-service lint",
|
||||||
|
"test:unit": "vue-cli-service test:unit",
|
||||||
|
"test:e2e": "vue-cli-service test:e2e"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@antv/data-set": "^0.10.1",
|
||||||
|
"ant-design-vue": "^1.3.1",
|
||||||
|
"axios": "^0.18.0",
|
||||||
|
"dayjs": "^1.8.0",
|
||||||
|
"enquire.js": "^2.1.6",
|
||||||
|
"js-cookie": "^2.2.0",
|
||||||
|
"lodash.get": "^4.4.2",
|
||||||
|
"lodash.pick": "^4.4.0",
|
||||||
|
"md5": "^2.2.1",
|
||||||
|
"nprogress": "^0.2.0",
|
||||||
|
"viser-vue": "^2.4.4",
|
||||||
|
"vue": "^2.5.22",
|
||||||
|
"vue-class-component": "^6.0.0",
|
||||||
|
"vue-cropper": "^0.4.8",
|
||||||
|
"vue-i18n": "^8.7.0",
|
||||||
|
"vue-ls": "^3.2.0",
|
||||||
|
"vue-print-nb": "^1.0.3",
|
||||||
|
"vue-property-decorator": "^7.3.0",
|
||||||
|
"vue-router": "^3.0.1",
|
||||||
|
"vuex": "^3.0.1",
|
||||||
|
"vuex-class": "^0.3.1"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@babel/polyfill": "^7.2.5",
|
||||||
|
"@vue/cli-plugin-babel": "^3.3.0",
|
||||||
|
"@vue/cli-plugin-eslint": "^3.3.0",
|
||||||
|
"@vue/cli-service": "^3.3.0",
|
||||||
|
"@vue/eslint-config-standard": "^4.0.0",
|
||||||
|
"babel-eslint": "^10.0.1",
|
||||||
|
"eslint": "^5.12.0",
|
||||||
|
"eslint-plugin-vue": "^5.1.0",
|
||||||
|
"less": "^3.8.1",
|
||||||
|
"less-loader": "^4.1.0",
|
||||||
|
"node-sass": "^4.11.0",
|
||||||
|
"sass-loader": "^7.0.1",
|
||||||
|
"vue-template-compiler": "^2.5.22"
|
||||||
|
},
|
||||||
|
"eslintConfig": {
|
||||||
|
"root": true,
|
||||||
|
"env": {
|
||||||
|
"node": true
|
||||||
|
},
|
||||||
|
"extends": [
|
||||||
|
"plugin:vue/strongly-recommended",
|
||||||
|
"eslint:recommended"
|
||||||
|
],
|
||||||
|
"parserOptions": {
|
||||||
|
"parser": "babel-eslint"
|
||||||
|
},
|
||||||
|
"rules": {
|
||||||
|
"generator-star-spacing": "off",
|
||||||
|
"no-mixed-operators": 0,
|
||||||
|
"vue/max-attributes-per-line": [
|
||||||
|
2,
|
||||||
|
{
|
||||||
|
"singleline": 5,
|
||||||
|
"multiline": {
|
||||||
|
"max": 1,
|
||||||
|
"allowFirstLine": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"vue/attribute-hyphenation": 0,
|
||||||
|
"vue/html-self-closing": 0,
|
||||||
|
"vue/component-name-in-template-casing": 0,
|
||||||
|
"vue/html-closing-bracket-spacing": 0,
|
||||||
|
"vue/singleline-html-element-content-newline": 0,
|
||||||
|
"vue/no-unused-components": 0,
|
||||||
|
"vue/multiline-html-element-content-newline": 0,
|
||||||
|
"vue/no-use-v-if-with-v-for": 0,
|
||||||
|
"vue/html-closing-bracket-newline": 0,
|
||||||
|
"vue/no-parsing-error": 0,
|
||||||
|
"no-console": 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"postcss": {
|
||||||
|
"plugins": {
|
||||||
|
"autoprefixer": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"browserslist": [
|
||||||
|
"> 1%",
|
||||||
|
"last 2 versions",
|
||||||
|
"not ie <= 8"
|
||||||
|
]
|
||||||
|
}
|
||||||
BIN
ant-design-jeecg-vue/public/avatar2.jpg
vendored
Normal file
BIN
ant-design-jeecg-vue/public/avatar2.jpg
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 78 KiB |
7684
ant-design-jeecg-vue/public/color.less
vendored
Normal file
7684
ant-design-jeecg-vue/public/color.less
vendored
Normal file
File diff suppressed because it is too large
Load Diff
238
ant-design-jeecg-vue/public/index.html
vendored
Normal file
238
ant-design-jeecg-vue/public/index.html
vendored
Normal file
@ -0,0 +1,238 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh-cmn-Hans">
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
|
<meta name="viewport" content="width=device-width,initial-scale=1.0">
|
||||||
|
<title>Jeecg-Boot 快速开发平台(Ant Design Vue)</title>
|
||||||
|
<link rel="icon" href="<%= BASE_URL %>logo.png">
|
||||||
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-polyfill/7.2.5/polyfill.js"></script>
|
||||||
|
<style>
|
||||||
|
html,
|
||||||
|
body,
|
||||||
|
#app {
|
||||||
|
height: 100%;
|
||||||
|
margin: 0px;
|
||||||
|
padding: 0px;
|
||||||
|
}
|
||||||
|
.chromeframe {
|
||||||
|
margin: 0.2em 0;
|
||||||
|
background: #ccc;
|
||||||
|
color: #000;
|
||||||
|
padding: 0.2em 0;
|
||||||
|
}
|
||||||
|
#loader-wrapper {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
z-index: 999999;
|
||||||
|
}
|
||||||
|
#loader {
|
||||||
|
display: block;
|
||||||
|
position: relative;
|
||||||
|
left: 50%;
|
||||||
|
top: 50%;
|
||||||
|
width: 120px;
|
||||||
|
height: 120px;
|
||||||
|
margin: -75px 0 0 -75px;
|
||||||
|
border-radius: 50%;
|
||||||
|
border: 3px solid transparent;
|
||||||
|
/* COLOR 1 */
|
||||||
|
border-top-color: #FFF;
|
||||||
|
-webkit-animation: spin 2s linear infinite;
|
||||||
|
/* Chrome, Opera 15+, Safari 5+ */
|
||||||
|
-ms-animation: spin 2s linear infinite;
|
||||||
|
/* Chrome, Opera 15+, Safari 5+ */
|
||||||
|
-moz-animation: spin 2s linear infinite;
|
||||||
|
/* Chrome, Opera 15+, Safari 5+ */
|
||||||
|
-o-animation: spin 2s linear infinite;
|
||||||
|
/* Chrome, Opera 15+, Safari 5+ */
|
||||||
|
animation: spin 2s linear infinite;
|
||||||
|
/* Chrome, Firefox 16+, IE 10+, Opera */
|
||||||
|
z-index: 1001;
|
||||||
|
}
|
||||||
|
#loader:before {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
top: 5px;
|
||||||
|
left: 5px;
|
||||||
|
right: 5px;
|
||||||
|
bottom: 5px;
|
||||||
|
border-radius: 50%;
|
||||||
|
border: 3px solid transparent;
|
||||||
|
/* COLOR 2 */
|
||||||
|
border-top-color: #FFF;
|
||||||
|
-webkit-animation: spin 3s linear infinite;
|
||||||
|
/* Chrome, Opera 15+, Safari 5+ */
|
||||||
|
-moz-animation: spin 3s linear infinite;
|
||||||
|
/* Chrome, Opera 15+, Safari 5+ */
|
||||||
|
-o-animation: spin 3s linear infinite;
|
||||||
|
/* Chrome, Opera 15+, Safari 5+ */
|
||||||
|
-ms-animation: spin 3s linear infinite;
|
||||||
|
/* Chrome, Opera 15+, Safari 5+ */
|
||||||
|
animation: spin 3s linear infinite;
|
||||||
|
/* Chrome, Firefox 16+, IE 10+, Opera */
|
||||||
|
}
|
||||||
|
#loader:after {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
top: 15px;
|
||||||
|
left: 15px;
|
||||||
|
right: 15px;
|
||||||
|
bottom: 15px;
|
||||||
|
border-radius: 50%;
|
||||||
|
border: 3px solid transparent;
|
||||||
|
border-top-color: #FFF;
|
||||||
|
/* COLOR 3 */
|
||||||
|
-moz-animation: spin 1.5s linear infinite;
|
||||||
|
/* Chrome, Opera 15+, Safari 5+ */
|
||||||
|
-o-animation: spin 1.5s linear infinite;
|
||||||
|
/* Chrome, Opera 15+, Safari 5+ */
|
||||||
|
-ms-animation: spin 1.5s linear infinite;
|
||||||
|
/* Chrome, Opera 15+, Safari 5+ */
|
||||||
|
-webkit-animation: spin 1.5s linear infinite;
|
||||||
|
/* Chrome, Opera 15+, Safari 5+ */
|
||||||
|
animation: spin 1.5s linear infinite;
|
||||||
|
/* Chrome, Firefox 16+, IE 10+, Opera */
|
||||||
|
}
|
||||||
|
@-webkit-keyframes spin {
|
||||||
|
0% {
|
||||||
|
-webkit-transform: rotate(0deg);
|
||||||
|
/* Chrome, Opera 15+, Safari 3.1+ */
|
||||||
|
-ms-transform: rotate(0deg);
|
||||||
|
/* IE 9 */
|
||||||
|
transform: rotate(0deg);
|
||||||
|
/* Firefox 16+, IE 10+, Opera */
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
-webkit-transform: rotate(360deg);
|
||||||
|
/* Chrome, Opera 15+, Safari 3.1+ */
|
||||||
|
-ms-transform: rotate(360deg);
|
||||||
|
/* IE 9 */
|
||||||
|
transform: rotate(360deg);
|
||||||
|
/* Firefox 16+, IE 10+, Opera */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@keyframes spin {
|
||||||
|
0% {
|
||||||
|
-webkit-transform: rotate(0deg);
|
||||||
|
/* Chrome, Opera 15+, Safari 3.1+ */
|
||||||
|
-ms-transform: rotate(0deg);
|
||||||
|
/* IE 9 */
|
||||||
|
transform: rotate(0deg);
|
||||||
|
/* Firefox 16+, IE 10+, Opera */
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
-webkit-transform: rotate(360deg);
|
||||||
|
/* Chrome, Opera 15+, Safari 3.1+ */
|
||||||
|
-ms-transform: rotate(360deg);
|
||||||
|
/* IE 9 */
|
||||||
|
transform: rotate(360deg);
|
||||||
|
/* Firefox 16+, IE 10+, Opera */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#loader-wrapper .loader-section {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
width: 51%;
|
||||||
|
height: 100%;
|
||||||
|
background: #49a9ee;
|
||||||
|
/* Old browsers */
|
||||||
|
z-index: 1000;
|
||||||
|
-webkit-transform: translateX(0);
|
||||||
|
/* Chrome, Opera 15+, Safari 3.1+ */
|
||||||
|
-ms-transform: translateX(0);
|
||||||
|
/* IE 9 */
|
||||||
|
transform: translateX(0);
|
||||||
|
/* Firefox 16+, IE 10+, Opera */
|
||||||
|
}
|
||||||
|
#loader-wrapper .loader-section.section-left {
|
||||||
|
left: 0;
|
||||||
|
}
|
||||||
|
#loader-wrapper .loader-section.section-right {
|
||||||
|
right: 0;
|
||||||
|
}
|
||||||
|
/* Loaded */
|
||||||
|
.loaded #loader-wrapper .loader-section.section-left {
|
||||||
|
-webkit-transform: translateX(-100%);
|
||||||
|
/* Chrome, Opera 15+, Safari 3.1+ */
|
||||||
|
-ms-transform: translateX(-100%);
|
||||||
|
/* IE 9 */
|
||||||
|
transform: translateX(-100%);
|
||||||
|
/* Firefox 16+, IE 10+, Opera */
|
||||||
|
-webkit-transition: all 0.7s 0.3s cubic-bezier(0.645, 0.045, 0.355, 1.000);
|
||||||
|
transition: all 0.7s 0.3s cubic-bezier(0.645, 0.045, 0.355, 1.000);
|
||||||
|
}
|
||||||
|
.loaded #loader-wrapper .loader-section.section-right {
|
||||||
|
-webkit-transform: translateX(100%);
|
||||||
|
/* Chrome, Opera 15+, Safari 3.1+ */
|
||||||
|
-ms-transform: translateX(100%);
|
||||||
|
/* IE 9 */
|
||||||
|
transform: translateX(100%);
|
||||||
|
/* Firefox 16+, IE 10+, Opera */
|
||||||
|
-webkit-transition: all 0.7s 0.3s cubic-bezier(0.645, 0.045, 0.355, 1.000);
|
||||||
|
transition: all 0.7s 0.3s cubic-bezier(0.645, 0.045, 0.355, 1.000);
|
||||||
|
}
|
||||||
|
.loaded #loader {
|
||||||
|
opacity: 0;
|
||||||
|
-webkit-transition: all 0.3s ease-out;
|
||||||
|
transition: all 0.3s ease-out;
|
||||||
|
}
|
||||||
|
.loaded #loader-wrapper {
|
||||||
|
visibility: hidden;
|
||||||
|
-webkit-transform: translateY(-100%);
|
||||||
|
/* Chrome, Opera 15+, Safari 3.1+ */
|
||||||
|
-ms-transform: translateY(-100%);
|
||||||
|
/* IE 9 */
|
||||||
|
transform: translateY(-100%);
|
||||||
|
/* Firefox 16+, IE 10+, Opera */
|
||||||
|
-webkit-transition: all 0.3s 1s ease-out;
|
||||||
|
transition: all 0.3s 1s ease-out;
|
||||||
|
}
|
||||||
|
/* JavaScript Turned Off */
|
||||||
|
.no-js #loader-wrapper {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.no-js h1 {
|
||||||
|
color: #222222;
|
||||||
|
}
|
||||||
|
#loader-wrapper .load_title {
|
||||||
|
font-family: 'Open Sans';
|
||||||
|
color: #FFF;
|
||||||
|
font-size: 14px;
|
||||||
|
width: 100%;
|
||||||
|
text-align: center;
|
||||||
|
z-index: 9999999999999;
|
||||||
|
position: absolute;
|
||||||
|
top: 60%;
|
||||||
|
opacity: 1;
|
||||||
|
line-height: 30px;
|
||||||
|
}
|
||||||
|
#loader-wrapper .load_title span {
|
||||||
|
font-weight: normal;
|
||||||
|
font-style: italic;
|
||||||
|
font-size: 14px;
|
||||||
|
color: #FFF;
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<!-- built files will be auto injected -->
|
||||||
|
<div id="app">
|
||||||
|
<div id="loader-wrapper">
|
||||||
|
<div id="loader"></div>
|
||||||
|
<div class="loader-section section-left"></div>
|
||||||
|
<div class="loader-section section-right"></div>
|
||||||
|
<div class="load_title">正在加载 Jeecg-Boot 快速开发平台(Ant Design Vue),请耐心等待
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
||||||
BIN
ant-design-jeecg-vue/public/logo.png
vendored
Normal file
BIN
ant-design-jeecg-vue/public/logo.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 20 KiB |
1
ant-design-jeecg-vue/public/v2.js
vendored
Normal file
1
ant-design-jeecg-vue/public/v2.js
vendored
Normal file
File diff suppressed because one or more lines are too long
44
ant-design-jeecg-vue/src/App.vue
Normal file
44
ant-design-jeecg-vue/src/App.vue
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
<template>
|
||||||
|
<a-locale-provider :locale="locale">
|
||||||
|
<div id="app">
|
||||||
|
<router-view/>
|
||||||
|
</div>
|
||||||
|
</a-locale-provider>
|
||||||
|
</template>
|
||||||
|
<script>
|
||||||
|
import zhCN from 'ant-design-vue/lib/locale-provider/zh_CN'
|
||||||
|
import enquireScreen from '@/utils/device'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
locale: zhCN,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created () {
|
||||||
|
let that = this
|
||||||
|
enquireScreen(deviceType => {
|
||||||
|
// tablet
|
||||||
|
if (deviceType === 0) {
|
||||||
|
that.$store.commit('TOGGLE_DEVICE', 'mobile')
|
||||||
|
that.$store.dispatch('setSidebar', false)
|
||||||
|
}
|
||||||
|
// mobile
|
||||||
|
else if (deviceType === 1) {
|
||||||
|
that.$store.commit('TOGGLE_DEVICE', 'mobile')
|
||||||
|
that.$store.dispatch('setSidebar', false)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
that.$store.commit('TOGGLE_DEVICE', 'desktop')
|
||||||
|
that.$store.dispatch('setSidebar', true)
|
||||||
|
}
|
||||||
|
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style>
|
||||||
|
#app {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
129
ant-design-jeecg-vue/src/api/api.js
Normal file
129
ant-design-jeecg-vue/src/api/api.js
Normal file
@ -0,0 +1,129 @@
|
|||||||
|
import { getAction,deleteAction,putAction,postAction} from '@/api/manage'
|
||||||
|
|
||||||
|
//根路径
|
||||||
|
const doMian = "/jeecg-boot/";
|
||||||
|
//图片预览请求地址
|
||||||
|
const imgView = "http://127.0.0.1:8080/jeecg-boot/sys/common/view/";
|
||||||
|
|
||||||
|
|
||||||
|
//角色管理
|
||||||
|
const addRole = (params)=>postAction("/sys/role/add",params);
|
||||||
|
const editRole = (params)=>putAction("/sys/role/edit",params);
|
||||||
|
const getRoleList = (params)=>getAction("/sys/role/list",params);
|
||||||
|
const deleteRole = (params)=>deleteAction("/sys/role/delete",params);
|
||||||
|
const deleteRoleList = (params)=>deleteAction("/sys/role/deleteBatch",params);
|
||||||
|
const checkRoleCode = (params)=>getAction("/sys/role/checkRoleCode",params);
|
||||||
|
const queryall = (params)=>getAction("/sys/role/queryall",params);
|
||||||
|
|
||||||
|
//用户管理
|
||||||
|
const addUser = (params)=>postAction("/sys/user/add",params);
|
||||||
|
const editUser = (params)=>putAction("/sys/user/edit",params);
|
||||||
|
const queryUserRole = (params)=>getAction("/sys/user/queryUserRole",params);
|
||||||
|
const getUserList = (params)=>getAction("/sys/user/list",params);
|
||||||
|
const deleteUser = (params)=>deleteAction("/sys/user/delete",params);
|
||||||
|
const deleteUserList = (params)=>deleteAction("/sys/user/deleteBatch",params);
|
||||||
|
const frozenBatch = (params)=>putAction("/sys/user/frozenBatch",params);
|
||||||
|
//验证用户账号是否唯一
|
||||||
|
const checkUsername = (params)=>getAction("/sys/user/checkOnlyUser",params);
|
||||||
|
//改变密码
|
||||||
|
const changPassword = (params)=>putAction("/sys/user/changPassword",params);
|
||||||
|
|
||||||
|
//权限管理
|
||||||
|
const addPermission= (params)=>postAction("/sys/permission/add",params);
|
||||||
|
const editPermission= (params)=>putAction("/sys/permission/edit",params);
|
||||||
|
const getPermissionList = (params)=>getAction("/sys/permission/list",params);
|
||||||
|
const deletePermission = (params)=>deleteAction("/sys/permission/delete",params);
|
||||||
|
const deletePermissionList = (params)=>deleteAction("/sys/permission/deleteBatch",params);
|
||||||
|
const queryTreeList = (params)=>getAction("/sys/permission/queryTreeList",params);
|
||||||
|
const queryListAsync = (params)=>getAction("/sys/permission/queryListAsync",params);
|
||||||
|
const queryRolePermission = (params)=>getAction("/sys/permission/queryRolePermission",params);
|
||||||
|
const saveRolePermission = (params)=>postAction("/sys/permission/saveRolePermission",params);
|
||||||
|
const queryPermissionsByUser = (params)=>getAction("/sys/permission/queryByUser",params);
|
||||||
|
const loadAllRoleIds = (params)=>getAction("/sys/permission/loadAllRoleIds",params);
|
||||||
|
|
||||||
|
// 部门管理
|
||||||
|
const queryDepartTreeList = (params)=>getAction("/sysdepart/sysDepart/queryTreeList",params);
|
||||||
|
const queryIdTree = (params)=>getAction("/sysdepart/sysDepart/queryIdTree",params);
|
||||||
|
const queryParentName = (params)=>getAction("/sysdepart/sysDepart/queryParentName",params);
|
||||||
|
const searchByKeywords = (params)=>getAction("/sysdepart/sysDepart/searchBy",params);
|
||||||
|
|
||||||
|
//日志管理
|
||||||
|
const getLogList = (params)=>getAction("/sys/log/list",params);
|
||||||
|
const deleteLog = (params)=>deleteAction("/sys/log/delete",params);
|
||||||
|
const deleteLogList = (params)=>deleteAction("/sys/log/deleteBatch",params);
|
||||||
|
|
||||||
|
//数据字典
|
||||||
|
const addDict = (params)=>postAction("/sys/dict/add",params);
|
||||||
|
const editDict = (params)=>putAction("/sys/dict/edit",params);
|
||||||
|
const getDictList = (params)=>getAction("/sys/dict/list",params);
|
||||||
|
const treeList = (params)=>getAction("/sys/dict/treeList",params);
|
||||||
|
const delDict = (params)=>deleteAction("/sys/dict/delete",params);
|
||||||
|
const getDictItemList = (params)=>getAction("/sys/dictItem/list",params);
|
||||||
|
const addDictItem = (params)=>postAction("/sys/dictItem/add",params);
|
||||||
|
const editDictItem = (params)=>putAction("/sys/dictItem/edit",params);
|
||||||
|
const delDictItem = (params)=>deleteAction("/sys/dictItem/delete",params);
|
||||||
|
const delDictItemList = (params)=>deleteAction("/sys/dictItem/deleteBatch",params);
|
||||||
|
|
||||||
|
//字典标签专用(通过code获取字典数组)
|
||||||
|
export const ajaxGetDictItems = (code, params)=>getAction(`/sys/dict/getDictItems/${code}`,params);
|
||||||
|
|
||||||
|
//系统通告
|
||||||
|
const doReleaseData = (params)=>getAction("/sys/annountCement/doReleaseData",params);
|
||||||
|
const doReovkeData = (params)=>getAction("/sys/annountCement/doReovkeData",params);
|
||||||
|
//获取系统访问量
|
||||||
|
const getLoginfo = (params)=>getAction("/sys/loginfo",params);
|
||||||
|
|
||||||
|
export {
|
||||||
|
imgView,
|
||||||
|
doMian,
|
||||||
|
addRole,
|
||||||
|
editRole,
|
||||||
|
getRoleList,
|
||||||
|
deleteRole,
|
||||||
|
deleteRoleList,
|
||||||
|
checkRoleCode,
|
||||||
|
addUser,
|
||||||
|
editUser,
|
||||||
|
queryUserRole,
|
||||||
|
queryall,
|
||||||
|
getUserList,
|
||||||
|
deleteUser,
|
||||||
|
deleteUserList,
|
||||||
|
frozenBatch,
|
||||||
|
checkUsername,
|
||||||
|
changPassword,
|
||||||
|
getPermissionList,
|
||||||
|
deletePermission,
|
||||||
|
deletePermissionList,
|
||||||
|
addPermission,
|
||||||
|
editPermission,
|
||||||
|
queryTreeList,
|
||||||
|
queryListAsync,
|
||||||
|
queryRolePermission,
|
||||||
|
saveRolePermission,
|
||||||
|
queryPermissionsByUser,
|
||||||
|
loadAllRoleIds,
|
||||||
|
queryDepartTreeList,
|
||||||
|
queryIdTree,
|
||||||
|
queryParentName,
|
||||||
|
searchByKeywords,
|
||||||
|
getLogList,
|
||||||
|
deleteLog,
|
||||||
|
deleteLogList,
|
||||||
|
getDictList,
|
||||||
|
addDict,
|
||||||
|
editDict,
|
||||||
|
delDict,
|
||||||
|
treeList,
|
||||||
|
getDictItemList,
|
||||||
|
addDictItem,
|
||||||
|
editDictItem,
|
||||||
|
delDictItem,
|
||||||
|
delDictItemList,
|
||||||
|
doReleaseData,
|
||||||
|
doReovkeData,
|
||||||
|
getLoginfo
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
10
ant-design-jeecg-vue/src/api/index.js
Normal file
10
ant-design-jeecg-vue/src/api/index.js
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
const api = {
|
||||||
|
Login: '/sys/login',
|
||||||
|
Logout: '/auth/logout',
|
||||||
|
ForgePassword: '/auth/forge-password',
|
||||||
|
Register: '/auth/register',
|
||||||
|
SendSms: '/account/sms',
|
||||||
|
// get my info
|
||||||
|
UserInfo: '/user/info'
|
||||||
|
}
|
||||||
|
export default api
|
||||||
49
ant-design-jeecg-vue/src/api/login.js
Normal file
49
ant-design-jeecg-vue/src/api/login.js
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
import api from './index'
|
||||||
|
import { axios } from '@/utils/request'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* login func
|
||||||
|
* parameter: {
|
||||||
|
* username: '',
|
||||||
|
* password: '',
|
||||||
|
* remember_me: true,
|
||||||
|
* captcha: '12345'
|
||||||
|
* }
|
||||||
|
* @param parameter
|
||||||
|
* @returns {*}
|
||||||
|
*/
|
||||||
|
export function login(parameter) {
|
||||||
|
return axios({
|
||||||
|
url: '/sys/login',
|
||||||
|
method: 'post',
|
||||||
|
data: parameter
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getSmsCaptcha(parameter) {
|
||||||
|
return axios({
|
||||||
|
url: api.SendSms,
|
||||||
|
method: 'post',
|
||||||
|
data: parameter
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getInfo() {
|
||||||
|
return axios({
|
||||||
|
url: '/api/user/info',
|
||||||
|
method: 'get',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json;charset=UTF-8'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function logout() {
|
||||||
|
return axios({
|
||||||
|
url: '/api/auth/logout',
|
||||||
|
method: 'post',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json;charset=UTF-8'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
99
ant-design-jeecg-vue/src/api/manage.js
Normal file
99
ant-design-jeecg-vue/src/api/manage.js
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
import { axios } from '@/utils/request'
|
||||||
|
|
||||||
|
const api = {
|
||||||
|
user: '/api/user',
|
||||||
|
role: '/api/role',
|
||||||
|
service: '/api/service',
|
||||||
|
permission: '/api/permission',
|
||||||
|
permissionNoPager: '/api/permission/no-pager'
|
||||||
|
}
|
||||||
|
|
||||||
|
export default api
|
||||||
|
|
||||||
|
//post
|
||||||
|
export function postAction(url,parameter) {
|
||||||
|
return axios({
|
||||||
|
url: url,
|
||||||
|
method:'post' ,
|
||||||
|
data: parameter
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
//post method= {post | put}
|
||||||
|
export function httpAction(url,parameter,method) {
|
||||||
|
return axios({
|
||||||
|
url: url,
|
||||||
|
method:method ,
|
||||||
|
data: parameter
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
//put
|
||||||
|
export function putAction(url,parameter) {
|
||||||
|
return axios({
|
||||||
|
url: url,
|
||||||
|
method:'put',
|
||||||
|
data: parameter
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
//get
|
||||||
|
export function getAction(url,parameter) {
|
||||||
|
return axios({
|
||||||
|
url: url,
|
||||||
|
method: 'get',
|
||||||
|
params: parameter
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
//deleteAction
|
||||||
|
export function deleteAction(url,parameter) {
|
||||||
|
return axios({
|
||||||
|
url: url,
|
||||||
|
method: 'delete',
|
||||||
|
params: parameter
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getUserList(parameter) {
|
||||||
|
return axios({
|
||||||
|
url: api.user,
|
||||||
|
method: 'get',
|
||||||
|
params: parameter
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getRoleList(parameter) {
|
||||||
|
return axios({
|
||||||
|
url: api.role,
|
||||||
|
method: 'get',
|
||||||
|
params: parameter
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getServiceList(parameter) {
|
||||||
|
return axios({
|
||||||
|
url: api.service,
|
||||||
|
method: 'get',
|
||||||
|
params: parameter
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getPermissions(parameter) {
|
||||||
|
return axios({
|
||||||
|
url: api.permissionNoPager,
|
||||||
|
method: 'get',
|
||||||
|
params: parameter
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// id == 0 add post
|
||||||
|
// id != 0 update put
|
||||||
|
export function saveService(parameter) {
|
||||||
|
return axios({
|
||||||
|
url: api.service,
|
||||||
|
method: parameter.id == 0 ? 'post' : 'put',
|
||||||
|
data: parameter
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
69
ant-design-jeecg-vue/src/assets/background.svg
Normal file
69
ant-design-jeecg-vue/src/assets/background.svg
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<svg width="1361px" height="609px" viewBox="0 0 1361 609" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||||
|
<!-- Generator: Sketch 46.2 (44496) - http://www.bohemiancoding.com/sketch -->
|
||||||
|
<title>Group 21</title>
|
||||||
|
<desc>Created with Sketch.</desc>
|
||||||
|
<defs></defs>
|
||||||
|
<g id="Ant-Design-Pro-3.0" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||||
|
<g id="账户密码登录-校验" transform="translate(-79.000000, -82.000000)">
|
||||||
|
<g id="Group-21" transform="translate(77.000000, 73.000000)">
|
||||||
|
<g id="Group-18" opacity="0.8" transform="translate(74.901416, 569.699158) rotate(-7.000000) translate(-74.901416, -569.699158) translate(4.901416, 525.199158)">
|
||||||
|
<ellipse id="Oval-11" fill="#CFDAE6" opacity="0.25" cx="63.5748792" cy="32.468367" rx="21.7830479" ry="21.766008"></ellipse>
|
||||||
|
<ellipse id="Oval-3" fill="#CFDAE6" opacity="0.599999964" cx="5.98746479" cy="13.8668601" rx="5.2173913" ry="5.21330997"></ellipse>
|
||||||
|
<path d="M38.1354514,88.3520215 C43.8984227,88.3520215 48.570234,83.6838647 48.570234,77.9254015 C48.570234,72.1669383 43.8984227,67.4987816 38.1354514,67.4987816 C32.3724801,67.4987816 27.7006688,72.1669383 27.7006688,77.9254015 C27.7006688,83.6838647 32.3724801,88.3520215 38.1354514,88.3520215 Z" id="Oval-3-Copy" fill="#CFDAE6" opacity="0.45"></path>
|
||||||
|
<path d="M64.2775582,33.1704963 L119.185836,16.5654915" id="Path-12" stroke="#CFDAE6" stroke-width="1.73913043" stroke-linecap="round" stroke-linejoin="round"></path>
|
||||||
|
<path d="M42.1431708,26.5002681 L7.71190162,14.5640702" id="Path-16" stroke="#E0B4B7" stroke-width="0.702678964" opacity="0.7" stroke-linecap="round" stroke-linejoin="round" stroke-dasharray="1.405357899873153,2.108036953469981"></path>
|
||||||
|
<path d="M63.9262187,33.521561 L43.6721326,69.3250951" id="Path-15" stroke="#BACAD9" stroke-width="0.702678964" stroke-linecap="round" stroke-linejoin="round" stroke-dasharray="1.405357899873153,2.108036953469981"></path>
|
||||||
|
<g id="Group-17" transform="translate(126.850922, 13.543654) rotate(30.000000) translate(-126.850922, -13.543654) translate(117.285705, 4.381889)" fill="#CFDAE6">
|
||||||
|
<ellipse id="Oval-4" opacity="0.45" cx="9.13482653" cy="9.12768076" rx="9.13482653" ry="9.12768076"></ellipse>
|
||||||
|
<path d="M18.2696531,18.2553615 C18.2696531,13.2142826 14.1798519,9.12768076 9.13482653,9.12768076 C4.08980114,9.12768076 0,13.2142826 0,18.2553615 L18.2696531,18.2553615 Z" id="Oval-4" transform="translate(9.134827, 13.691521) scale(-1, -1) translate(-9.134827, -13.691521) "></path>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
<g id="Group-14" transform="translate(216.294700, 123.725600) rotate(-5.000000) translate(-216.294700, -123.725600) translate(106.294700, 35.225600)">
|
||||||
|
<ellipse id="Oval-2" fill="#CFDAE6" opacity="0.25" cx="29.1176471" cy="29.1402439" rx="29.1176471" ry="29.1402439"></ellipse>
|
||||||
|
<ellipse id="Oval-2" fill="#CFDAE6" opacity="0.3" cx="29.1176471" cy="29.1402439" rx="21.5686275" ry="21.5853659"></ellipse>
|
||||||
|
<ellipse id="Oval-2-Copy" stroke="#CFDAE6" opacity="0.4" cx="179.019608" cy="138.146341" rx="23.7254902" ry="23.7439024"></ellipse>
|
||||||
|
<ellipse id="Oval-2" fill="#BACAD9" opacity="0.5" cx="29.1176471" cy="29.1402439" rx="10.7843137" ry="10.7926829"></ellipse>
|
||||||
|
<path d="M29.1176471,39.9329268 L29.1176471,18.347561 C23.1616351,18.347561 18.3333333,23.1796097 18.3333333,29.1402439 C18.3333333,35.1008781 23.1616351,39.9329268 29.1176471,39.9329268 Z" id="Oval-2" fill="#BACAD9"></path>
|
||||||
|
<g id="Group-9" opacity="0.45" transform="translate(172.000000, 131.000000)" fill="#E6A1A6">
|
||||||
|
<ellipse id="Oval-2-Copy-2" cx="7.01960784" cy="7.14634146" rx="6.47058824" ry="6.47560976"></ellipse>
|
||||||
|
<path d="M0.549019608,13.6219512 C4.12262681,13.6219512 7.01960784,10.722722 7.01960784,7.14634146 C7.01960784,3.56996095 4.12262681,0.670731707 0.549019608,0.670731707 L0.549019608,13.6219512 Z" id="Oval-2-Copy-2" transform="translate(3.784314, 7.146341) scale(-1, 1) translate(-3.784314, -7.146341) "></path>
|
||||||
|
</g>
|
||||||
|
<ellipse id="Oval-10" fill="#CFDAE6" cx="218.382353" cy="138.685976" rx="1.61764706" ry="1.61890244"></ellipse>
|
||||||
|
<ellipse id="Oval-10-Copy-2" fill="#E0B4B7" opacity="0.35" cx="179.558824" cy="175.381098" rx="1.61764706" ry="1.61890244"></ellipse>
|
||||||
|
<ellipse id="Oval-10-Copy" fill="#E0B4B7" opacity="0.35" cx="180.098039" cy="102.530488" rx="2.15686275" ry="2.15853659"></ellipse>
|
||||||
|
<path d="M28.9985381,29.9671598 L171.151018,132.876024" id="Path-11" stroke="#CFDAE6" opacity="0.8"></path>
|
||||||
|
</g>
|
||||||
|
<g id="Group-10" opacity="0.799999952" transform="translate(1054.100635, 36.659317) rotate(-11.000000) translate(-1054.100635, -36.659317) translate(1026.600635, 4.659317)">
|
||||||
|
<ellipse id="Oval-7" stroke="#CFDAE6" stroke-width="0.941176471" cx="43.8135593" cy="32" rx="11.1864407" ry="11.2941176"></ellipse>
|
||||||
|
<g id="Group-12" transform="translate(34.596774, 23.111111)" fill="#BACAD9">
|
||||||
|
<ellipse id="Oval-7" opacity="0.45" cx="9.18534718" cy="8.88888889" rx="8.47457627" ry="8.55614973"></ellipse>
|
||||||
|
<path d="M9.18534718,17.4450386 C13.8657264,17.4450386 17.6599235,13.6143199 17.6599235,8.88888889 C17.6599235,4.16345787 13.8657264,0.332739156 9.18534718,0.332739156 L9.18534718,17.4450386 Z" id="Oval-7"></path>
|
||||||
|
</g>
|
||||||
|
<path d="M34.6597385,24.809694 L5.71666084,4.76878945" id="Path-2" stroke="#CFDAE6" stroke-width="0.941176471"></path>
|
||||||
|
<ellipse id="Oval" stroke="#CFDAE6" stroke-width="0.941176471" cx="3.26271186" cy="3.29411765" rx="3.26271186" ry="3.29411765"></ellipse>
|
||||||
|
<ellipse id="Oval-Copy" fill="#F7E1AD" cx="2.79661017" cy="61.1764706" rx="2.79661017" ry="2.82352941"></ellipse>
|
||||||
|
<path d="M34.6312443,39.2922712 L5.06366663,59.785082" id="Path-10" stroke="#CFDAE6" stroke-width="0.941176471"></path>
|
||||||
|
</g>
|
||||||
|
<g id="Group-19" opacity="0.33" transform="translate(1282.537219, 446.502867) rotate(-10.000000) translate(-1282.537219, -446.502867) translate(1142.537219, 327.502867)">
|
||||||
|
<g id="Group-17" transform="translate(141.333539, 104.502742) rotate(275.000000) translate(-141.333539, -104.502742) translate(129.333539, 92.502742)" fill="#BACAD9">
|
||||||
|
<circle id="Oval-4" opacity="0.45" cx="11.6666667" cy="11.6666667" r="11.6666667"></circle>
|
||||||
|
<path d="M23.3333333,23.3333333 C23.3333333,16.8900113 18.1099887,11.6666667 11.6666667,11.6666667 C5.22334459,11.6666667 0,16.8900113 0,23.3333333 L23.3333333,23.3333333 Z" id="Oval-4" transform="translate(11.666667, 17.500000) scale(-1, -1) translate(-11.666667, -17.500000) "></path>
|
||||||
|
</g>
|
||||||
|
<circle id="Oval-5-Copy-6" fill="#CFDAE6" cx="201.833333" cy="87.5" r="5.83333333"></circle>
|
||||||
|
<path d="M143.5,88.8126685 L155.070501,17.6038544" id="Path-17" stroke="#BACAD9" stroke-width="1.16666667"></path>
|
||||||
|
<path d="M17.5,37.3333333 L127.466252,97.6449735" id="Path-18" stroke="#BACAD9" stroke-width="1.16666667"></path>
|
||||||
|
<polyline id="Path-19" stroke="#CFDAE6" stroke-width="1.16666667" points="143.902597 120.302281 174.935455 231.571342 38.5 147.510847 126.366941 110.833333"></polyline>
|
||||||
|
<path d="M159.833333,99.7453842 L195.416667,89.25" id="Path-20" stroke="#E0B4B7" stroke-width="1.16666667" opacity="0.6"></path>
|
||||||
|
<path d="M205.333333,82.1372105 L238.719406,36.1666667" id="Path-24" stroke="#BACAD9" stroke-width="1.16666667"></path>
|
||||||
|
<path d="M266.723424,132.231988 L207.083333,90.4166667" id="Path-25" stroke="#CFDAE6" stroke-width="1.16666667"></path>
|
||||||
|
<circle id="Oval-5" fill="#C1D1E0" cx="156.916667" cy="8.75" r="8.75"></circle>
|
||||||
|
<circle id="Oval-5-Copy-3" fill="#C1D1E0" cx="39.0833333" cy="148.75" r="5.25"></circle>
|
||||||
|
<circle id="Oval-5-Copy-2" fill-opacity="0.6" fill="#D1DEED" cx="8.75" cy="33.25" r="8.75"></circle>
|
||||||
|
<circle id="Oval-5-Copy-4" fill-opacity="0.6" fill="#D1DEED" cx="243.833333" cy="30.3333333" r="5.83333333"></circle>
|
||||||
|
<circle id="Oval-5-Copy-5" fill="#E0B4B7" cx="175.583333" cy="232.75" r="5.25"></circle>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 8.7 KiB |
21
ant-design-jeecg-vue/src/assets/less/index.less
Normal file
21
ant-design-jeecg-vue/src/assets/less/index.less
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
.search{
|
||||||
|
margin-bottom: 54px;
|
||||||
|
}
|
||||||
|
.fold{
|
||||||
|
width: calc(100% - 216px);
|
||||||
|
display: inline-block
|
||||||
|
}
|
||||||
|
.operator{
|
||||||
|
margin-bottom: 18px;
|
||||||
|
}
|
||||||
|
@media screen and (max-width: 900px) {
|
||||||
|
.fold {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.operator button {
|
||||||
|
margin-right: 5px;
|
||||||
|
}
|
||||||
|
i {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
BIN
ant-design-jeecg-vue/src/assets/logo.png
Normal file
BIN
ant-design-jeecg-vue/src/assets/logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 20 KiB |
43
ant-design-jeecg-vue/src/assets/logo.svg
Normal file
43
ant-design-jeecg-vue/src/assets/logo.svg
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<svg width="200px" height="200px" viewBox="0 0 200 200" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||||
|
<!-- Generator: Sketch 47.1 (45422) - http://www.bohemiancoding.com/sketch -->
|
||||||
|
<title>Group 28 Copy 5</title>
|
||||||
|
<desc>Created with Sketch.</desc>
|
||||||
|
<defs>
|
||||||
|
<linearGradient x1="62.1023273%" y1="0%" x2="108.19718%" y2="37.8635764%" id="linearGradient-1">
|
||||||
|
<stop stop-color="#4285EB" offset="0%"></stop>
|
||||||
|
<stop stop-color="#2EC7FF" offset="100%"></stop>
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient x1="69.644116%" y1="0%" x2="54.0428975%" y2="108.456714%" id="linearGradient-2">
|
||||||
|
<stop stop-color="#29CDFF" offset="0%"></stop>
|
||||||
|
<stop stop-color="#148EFF" offset="37.8600687%"></stop>
|
||||||
|
<stop stop-color="#0A60FF" offset="100%"></stop>
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient x1="69.6908165%" y1="-12.9743587%" x2="16.7228981%" y2="117.391248%" id="linearGradient-3">
|
||||||
|
<stop stop-color="#FA816E" offset="0%"></stop>
|
||||||
|
<stop stop-color="#F74A5C" offset="41.472606%"></stop>
|
||||||
|
<stop stop-color="#F51D2C" offset="100%"></stop>
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient x1="68.1279872%" y1="-35.6905737%" x2="30.4400914%" y2="114.942679%" id="linearGradient-4">
|
||||||
|
<stop stop-color="#FA8E7D" offset="0%"></stop>
|
||||||
|
<stop stop-color="#F74A5C" offset="51.2635191%"></stop>
|
||||||
|
<stop stop-color="#F51D2C" offset="100%"></stop>
|
||||||
|
</linearGradient>
|
||||||
|
</defs>
|
||||||
|
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||||
|
<g id="logo" transform="translate(-20.000000, -20.000000)">
|
||||||
|
<g id="Group-28-Copy-5" transform="translate(20.000000, 20.000000)">
|
||||||
|
<g id="Group-27-Copy-3">
|
||||||
|
<g id="Group-25" fill-rule="nonzero">
|
||||||
|
<g id="2">
|
||||||
|
<path d="M91.5880863,4.17652823 L4.17996544,91.5127728 C-0.519240605,96.2081146 -0.519240605,103.791885 4.17996544,108.487227 L91.5880863,195.823472 C96.2872923,200.518814 103.877304,200.518814 108.57651,195.823472 L145.225487,159.204632 C149.433969,154.999611 149.433969,148.181924 145.225487,143.976903 C141.017005,139.771881 134.193707,139.771881 129.985225,143.976903 L102.20193,171.737352 C101.032305,172.906015 99.2571609,172.906015 98.0875359,171.737352 L28.285908,101.993122 C27.1162831,100.824459 27.1162831,99.050775 28.285908,97.8821118 L98.0875359,28.1378823 C99.2571609,26.9692191 101.032305,26.9692191 102.20193,28.1378823 L129.985225,55.8983314 C134.193707,60.1033528 141.017005,60.1033528 145.225487,55.8983314 C149.433969,51.69331 149.433969,44.8756232 145.225487,40.6706018 L108.58055,4.05574592 C103.862049,-0.537986846 96.2692618,-0.500797906 91.5880863,4.17652823 Z" id="Shape" fill="url(#linearGradient-1)"></path>
|
||||||
|
<path d="M91.5880863,4.17652823 L4.17996544,91.5127728 C-0.519240605,96.2081146 -0.519240605,103.791885 4.17996544,108.487227 L91.5880863,195.823472 C96.2872923,200.518814 103.877304,200.518814 108.57651,195.823472 L145.225487,159.204632 C149.433969,154.999611 149.433969,148.181924 145.225487,143.976903 C141.017005,139.771881 134.193707,139.771881 129.985225,143.976903 L102.20193,171.737352 C101.032305,172.906015 99.2571609,172.906015 98.0875359,171.737352 L28.285908,101.993122 C27.1162831,100.824459 27.1162831,99.050775 28.285908,97.8821118 L98.0875359,28.1378823 C100.999864,25.6271836 105.751642,20.541824 112.729652,19.3524487 C117.915585,18.4685261 123.585219,20.4140239 129.738554,25.1889424 C125.624663,21.0784292 118.571995,14.0340304 108.58055,4.05574592 C103.862049,-0.537986846 96.2692618,-0.500797906 91.5880863,4.17652823 Z" id="Shape" fill="url(#linearGradient-2)"></path>
|
||||||
|
</g>
|
||||||
|
<path d="M153.685633,135.854579 C157.894115,140.0596 164.717412,140.0596 168.925894,135.854579 L195.959977,108.842726 C200.659183,104.147384 200.659183,96.5636133 195.960527,91.8688194 L168.690777,64.7181159 C164.472332,60.5180858 157.646868,60.5241425 153.435895,64.7316526 C149.227413,68.936674 149.227413,75.7543607 153.435895,79.9593821 L171.854035,98.3623765 C173.02366,99.5310396 173.02366,101.304724 171.854035,102.473387 L153.685633,120.626849 C149.47715,124.83187 149.47715,131.649557 153.685633,135.854579 Z" id="Shape" fill="url(#linearGradient-3)"></path>
|
||||||
|
</g>
|
||||||
|
<ellipse id="Combined-Shape" fill="url(#linearGradient-4)" cx="100.519339" cy="100.436681" rx="23.6001926" ry="23.580786"></ellipse>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 4.6 KiB |
46
ant-design-jeecg-vue/src/components/AvatarList/Item.vue
Normal file
46
ant-design-jeecg-vue/src/components/AvatarList/Item.vue
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
<template>
|
||||||
|
<tooltip v-if="tips !== ''">
|
||||||
|
<template slot="title">{{ tips }}</template>
|
||||||
|
<avatar :size="avatarSize" :src="src" />
|
||||||
|
</tooltip>
|
||||||
|
<avatar v-else :size="avatarSize" :src="src" />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import Avatar from 'ant-design-vue/es/avatar'
|
||||||
|
import Tooltip from 'ant-design-vue/es/tooltip'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "AvatarItem",
|
||||||
|
components: {
|
||||||
|
Avatar,
|
||||||
|
Tooltip
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
tips: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
required: false
|
||||||
|
},
|
||||||
|
src: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
size: this.$parent.size
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
avatarSize () {
|
||||||
|
return this.size !== 'mini' && this.size || 20
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
'$parent.size' (val) {
|
||||||
|
this.size = val
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
100
ant-design-jeecg-vue/src/components/AvatarList/List.vue
Normal file
100
ant-design-jeecg-vue/src/components/AvatarList/List.vue
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
<!--
|
||||||
|
<template>
|
||||||
|
<div :class="[prefixCls]">
|
||||||
|
<ul>
|
||||||
|
<slot></slot>
|
||||||
|
<template v-for="item in filterEmpty($slots.default).slice(0, 3)"></template>
|
||||||
|
|
||||||
|
|
||||||
|
<template v-if="maxLength > 0 && filterEmpty($slots.default).length > maxLength">
|
||||||
|
<avatar-item :size="size">
|
||||||
|
<avatar :size="size !== 'mini' && size || 20" :style="excessItemsStyle">{{ `+${maxLength}` }}</avatar>
|
||||||
|
</avatar-item>
|
||||||
|
</template>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
-->
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import Avatar from 'ant-design-vue/es/avatar'
|
||||||
|
import AvatarItem from './Item'
|
||||||
|
import { filterEmpty } from '@/components/_util/util'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
AvatarItem,
|
||||||
|
name: "AvatarList",
|
||||||
|
components: {
|
||||||
|
Avatar,
|
||||||
|
AvatarItem
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
prefixCls: {
|
||||||
|
type: String,
|
||||||
|
default: 'ant-pro-avatar-list'
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* 头像大小 类型: large、small 、mini, default
|
||||||
|
* 默认值: default
|
||||||
|
*/
|
||||||
|
size: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: 'default'
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* 要显示的最大项目
|
||||||
|
*/
|
||||||
|
maxLength: {
|
||||||
|
type: Number,
|
||||||
|
default: 0
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* 多余的项目风格
|
||||||
|
*/
|
||||||
|
excessItemsStyle: {
|
||||||
|
type: Object,
|
||||||
|
default: () => {
|
||||||
|
return {
|
||||||
|
color: '#f56a00',
|
||||||
|
backgroundColor: '#fde3cf'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data () {
|
||||||
|
return {}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
getItems(items) {
|
||||||
|
const classString = {
|
||||||
|
[`${this.prefixCls}-item`]: true,
|
||||||
|
[`${this.size}`]: true
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.maxLength > 0) {
|
||||||
|
items = items.slice(0, this.maxLength)
|
||||||
|
items.push((<Avatar size={ this.size } style={ this.excessItemsStyle }>{`+${this.maxLength}`}</Avatar>))
|
||||||
|
}
|
||||||
|
const itemList = items.map((item) => (
|
||||||
|
<li class={ classString }>{ item }</li>
|
||||||
|
))
|
||||||
|
return itemList
|
||||||
|
}
|
||||||
|
},
|
||||||
|
render () {
|
||||||
|
const { prefixCls, size } = this.$props
|
||||||
|
const classString = {
|
||||||
|
[`${prefixCls}`]: true,
|
||||||
|
[`${size}`]: true,
|
||||||
|
}
|
||||||
|
const items = filterEmpty(this.$slots.default)
|
||||||
|
const itemsDom = items && items.length ? <ul class={`${prefixCls}-items`}>{ this.getItems(items) }</ul> : null
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div class={ classString }>
|
||||||
|
{ itemsDom }
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
4
ant-design-jeecg-vue/src/components/AvatarList/index.js
Normal file
4
ant-design-jeecg-vue/src/components/AvatarList/index.js
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
import AvatarList from './List'
|
||||||
|
import "./index.less"
|
||||||
|
|
||||||
|
export default AvatarList
|
||||||
60
ant-design-jeecg-vue/src/components/AvatarList/index.less
Normal file
60
ant-design-jeecg-vue/src/components/AvatarList/index.less
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
@import "../index";
|
||||||
|
|
||||||
|
@avatar-list-prefix-cls: ~"@{ant-pro-prefix}-avatar-list";
|
||||||
|
@avatar-list-item-prefix-cls: ~"@{ant-pro-prefix}-avatar-list-item";
|
||||||
|
|
||||||
|
.@{avatar-list-prefix-cls} {
|
||||||
|
display: inline-block;
|
||||||
|
|
||||||
|
ul {
|
||||||
|
list-style: none;
|
||||||
|
display: inline-block;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0 0 0 8px;
|
||||||
|
font-size: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.@{avatar-list-item-prefix-cls} {
|
||||||
|
display: inline-block;
|
||||||
|
font-size: @font-size-base;
|
||||||
|
margin-left: -8px;
|
||||||
|
width: @avatar-size-base;
|
||||||
|
height: @avatar-size-base;
|
||||||
|
|
||||||
|
:global {
|
||||||
|
.ant-avatar {
|
||||||
|
border: 1px solid #fff;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.large {
|
||||||
|
width: @avatar-size-lg;
|
||||||
|
height: @avatar-size-lg;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.small {
|
||||||
|
width: @avatar-size-sm;
|
||||||
|
height: @avatar-size-sm;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.mini {
|
||||||
|
width: 20px;
|
||||||
|
height: 20px;
|
||||||
|
|
||||||
|
:global {
|
||||||
|
.ant-avatar {
|
||||||
|
width: 20px;
|
||||||
|
height: 20px;
|
||||||
|
line-height: 20px;
|
||||||
|
|
||||||
|
.ant-avatar-string {
|
||||||
|
font-size: 12px;
|
||||||
|
line-height: 18px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
111
ant-design-jeecg-vue/src/components/ChartCard.vue
Normal file
111
ant-design-jeecg-vue/src/components/ChartCard.vue
Normal file
@ -0,0 +1,111 @@
|
|||||||
|
<template>
|
||||||
|
<a-card :loading="loading" :body-style="{ padding: '20px 24px 8px' }" :bordered="false">
|
||||||
|
<div class="chart-card-header">
|
||||||
|
<div class="meta">
|
||||||
|
<span class="chart-card-title">{{ title }}</span>
|
||||||
|
<span class="chart-card-action">
|
||||||
|
<slot name="action"></slot>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div class="total"><span>{{ total }}</span></div>
|
||||||
|
</div>
|
||||||
|
<div class="chart-card-content">
|
||||||
|
<div class="content-fix">
|
||||||
|
<slot></slot>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="chart-card-footer">
|
||||||
|
<div class="field">
|
||||||
|
<slot name="footer"></slot>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</a-card>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: "ChartCard",
|
||||||
|
props: {
|
||||||
|
title: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
total: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
loading: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.chart-card-header {
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
.meta {
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
width: 100%;
|
||||||
|
color: rgba(0, 0, 0, .45);
|
||||||
|
font-size: 14px;
|
||||||
|
line-height: 22px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.chart-card-action {
|
||||||
|
cursor: pointer;
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chart-card-footer {
|
||||||
|
border-top: 1px solid #e8e8e8;
|
||||||
|
padding-top: 9px;
|
||||||
|
margin-top: 8px;
|
||||||
|
|
||||||
|
> * {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.field {
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.chart-card-content {
|
||||||
|
margin-bottom: 12px;
|
||||||
|
position: relative;
|
||||||
|
height: 46px;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
.content-fix {
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
bottom: 0;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.total {
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
word-break: break-all;
|
||||||
|
white-space: nowrap;
|
||||||
|
color: #000;
|
||||||
|
margin-top: 4px;
|
||||||
|
margin-bottom: 0;
|
||||||
|
font-size: 30px;
|
||||||
|
line-height: 38px;
|
||||||
|
height: 38px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
103
ant-design-jeecg-vue/src/components/CountDown/CountDown.vue
Normal file
103
ant-design-jeecg-vue/src/components/CountDown/CountDown.vue
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
<template>
|
||||||
|
<span>
|
||||||
|
{{ lastTime | format }}
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
|
||||||
|
function fixedZero(val) {
|
||||||
|
return val * 1 < 10 ? `0${val}` : val;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "CountDown",
|
||||||
|
props: {
|
||||||
|
format: {
|
||||||
|
type: Function,
|
||||||
|
default: undefined
|
||||||
|
},
|
||||||
|
target: {
|
||||||
|
type: [Date, Number],
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
onEnd: {
|
||||||
|
type: Function,
|
||||||
|
default: () => {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
dateTime: '0',
|
||||||
|
originTargetTime: 0,
|
||||||
|
lastTime: 0,
|
||||||
|
timer: 0,
|
||||||
|
interval: 1000
|
||||||
|
}
|
||||||
|
},
|
||||||
|
filters: {
|
||||||
|
format(time) {
|
||||||
|
const hours = 60 * 60 * 1000;
|
||||||
|
const minutes = 60 * 1000;
|
||||||
|
|
||||||
|
const h = Math.floor(time / hours);
|
||||||
|
const m = Math.floor((time - h * hours) / minutes);
|
||||||
|
const s = Math.floor((time - h * hours - m * minutes) / 1000);
|
||||||
|
return `${fixedZero(h)}:${fixedZero(m)}:${fixedZero(s)}`
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
this.initTime()
|
||||||
|
this.tick()
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
initTime() {
|
||||||
|
let lastTime = 0;
|
||||||
|
let targetTime = 0;
|
||||||
|
this.originTargetTime = this.target
|
||||||
|
try {
|
||||||
|
if (Object.prototype.toString.call(this.target) === '[object Date]') {
|
||||||
|
targetTime = this.target
|
||||||
|
} else {
|
||||||
|
targetTime = new Date(this.target).getTime()
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
throw new Error('invalid target prop')
|
||||||
|
}
|
||||||
|
|
||||||
|
lastTime = targetTime - new Date().getTime();
|
||||||
|
|
||||||
|
this.lastTime = lastTime < 0 ? 0 : lastTime
|
||||||
|
},
|
||||||
|
tick() {
|
||||||
|
const {onEnd} = this
|
||||||
|
|
||||||
|
this.timer = setTimeout(() => {
|
||||||
|
if (this.lastTime < this.interval) {
|
||||||
|
clearTimeout(this.timer)
|
||||||
|
this.lastTime = 0
|
||||||
|
if (typeof onEnd === 'function') {
|
||||||
|
onEnd();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.lastTime -= this.interval
|
||||||
|
this.tick()
|
||||||
|
}
|
||||||
|
}, this.interval)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
beforeUpdate () {
|
||||||
|
if (this.originTargetTime !== this.target) {
|
||||||
|
this.initTime()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
beforeDestroy() {
|
||||||
|
clearTimeout(this.timer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
</style>
|
||||||
3
ant-design-jeecg-vue/src/components/CountDown/index.js
Normal file
3
ant-design-jeecg-vue/src/components/CountDown/index.js
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
import CountDown from './CountDown'
|
||||||
|
|
||||||
|
export default CountDown
|
||||||
63
ant-design-jeecg-vue/src/components/Ellipsis/Ellipsis.vue
Normal file
63
ant-design-jeecg-vue/src/components/Ellipsis/Ellipsis.vue
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
<script>
|
||||||
|
import Tooltip from 'ant-design-vue/es/tooltip'
|
||||||
|
import { cutStrByFullLength, getStrFullLength } from '@/components/_util/StringUtil'
|
||||||
|
/*
|
||||||
|
const isSupportLineClamp = document.body.style.webkitLineClamp !== undefined;
|
||||||
|
|
||||||
|
const TooltipOverlayStyle = {
|
||||||
|
overflowWrap: 'break-word',
|
||||||
|
wordWrap: 'break-word',
|
||||||
|
};
|
||||||
|
*/
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'Ellipsis',
|
||||||
|
components: {
|
||||||
|
Tooltip
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
prefixCls: {
|
||||||
|
type: String,
|
||||||
|
default: 'ant-pro-ellipsis'
|
||||||
|
},
|
||||||
|
tooltip: {
|
||||||
|
type: Boolean
|
||||||
|
},
|
||||||
|
length: {
|
||||||
|
type: Number,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
lines: {
|
||||||
|
type: Number,
|
||||||
|
default: 1
|
||||||
|
},
|
||||||
|
fullWidthRecognition: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
getStrDom (str) {
|
||||||
|
return (
|
||||||
|
<span>{ cutStrByFullLength(str, this.length) + '...' }</span>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
getTooltip ( fullStr) {
|
||||||
|
return (
|
||||||
|
<Tooltip>
|
||||||
|
<template slot="title">{ fullStr }</template>
|
||||||
|
{ this.getStrDom(fullStr) }
|
||||||
|
</Tooltip>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
render () {
|
||||||
|
const { tooltip, length } = this.$props
|
||||||
|
let str = this.$slots.default.map(vNode => vNode.text).join("")
|
||||||
|
const strDom = tooltip && getStrFullLength(str) > length ? this.getTooltip(str) : this.getStrDom(str);
|
||||||
|
return (
|
||||||
|
strDom
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
3
ant-design-jeecg-vue/src/components/Ellipsis/index.js
Normal file
3
ant-design-jeecg-vue/src/components/Ellipsis/index.js
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
import Ellipsis from './Ellipsis'
|
||||||
|
|
||||||
|
export default Ellipsis
|
||||||
@ -0,0 +1,54 @@
|
|||||||
|
<template>
|
||||||
|
<div :class="[prefixCls]">
|
||||||
|
<slot name="subtitle">
|
||||||
|
<div :class="[`${prefixCls}-subtitle`]">{{ typeof subTitle === 'string' ? subTitle : subTitle() }}</div>
|
||||||
|
</slot>
|
||||||
|
<div class="number-info-value">
|
||||||
|
<span>{{ total }}</span>
|
||||||
|
<span class="sub-total">
|
||||||
|
{{ subTotal }}
|
||||||
|
<icon :type="`caret-${status}`" />
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import Icon from 'ant-design-vue/es/icon'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'NumberInfo',
|
||||||
|
props: {
|
||||||
|
prefixCls: {
|
||||||
|
type: String,
|
||||||
|
default: 'ant-pro-number-info'
|
||||||
|
},
|
||||||
|
total: {
|
||||||
|
type: Number,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
subTotal: {
|
||||||
|
type: Number,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
subTitle: {
|
||||||
|
type: [String, Function],
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
status: {
|
||||||
|
type: String,
|
||||||
|
default: 'up'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
components: {
|
||||||
|
Icon
|
||||||
|
},
|
||||||
|
data () {
|
||||||
|
return {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
@import "index";
|
||||||
|
</style>
|
||||||
3
ant-design-jeecg-vue/src/components/NumberInfo/index.js
Normal file
3
ant-design-jeecg-vue/src/components/NumberInfo/index.js
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
import NumberInfo from './NumberInfo'
|
||||||
|
|
||||||
|
export default NumberInfo
|
||||||
55
ant-design-jeecg-vue/src/components/NumberInfo/index.less
Normal file
55
ant-design-jeecg-vue/src/components/NumberInfo/index.less
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
@import "../index";
|
||||||
|
|
||||||
|
@numberInfo-prefix-cls: ~"@{ant-pro-prefix}-number-info";
|
||||||
|
|
||||||
|
.@{numberInfo-prefix-cls} {
|
||||||
|
|
||||||
|
.ant-pro-number-info-subtitle {
|
||||||
|
color: @text-color-secondary;
|
||||||
|
font-size: @font-size-base;
|
||||||
|
height: 22px;
|
||||||
|
line-height: 22px;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
word-break: break-all;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.number-info-value {
|
||||||
|
margin-top: 4px;
|
||||||
|
font-size: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
word-break: break-all;
|
||||||
|
white-space: nowrap;
|
||||||
|
|
||||||
|
& > span {
|
||||||
|
color: @heading-color;
|
||||||
|
display: inline-block;
|
||||||
|
line-height: 32px;
|
||||||
|
height: 32px;
|
||||||
|
font-size: 24px;
|
||||||
|
margin-right: 32px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sub-total {
|
||||||
|
color: @text-color-secondary;
|
||||||
|
font-size: @font-size-lg;
|
||||||
|
vertical-align: top;
|
||||||
|
margin-right: 0;
|
||||||
|
i {
|
||||||
|
font-size: 12px;
|
||||||
|
transform: scale(0.82);
|
||||||
|
margin-left: 4px;
|
||||||
|
}
|
||||||
|
:global {
|
||||||
|
.anticon-caret-up {
|
||||||
|
color: @red-6;
|
||||||
|
}
|
||||||
|
.anticon-caret-down {
|
||||||
|
color: @green-6;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
41
ant-design-jeecg-vue/src/components/Trend/Trend.vue
Normal file
41
ant-design-jeecg-vue/src/components/Trend/Trend.vue
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
<template>
|
||||||
|
<div :class="[prefixCls, reverseColor && 'reverse-color' ]">
|
||||||
|
<span>
|
||||||
|
<slot name="term"></slot>
|
||||||
|
<span class="item-text">
|
||||||
|
<slot></slot>
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
<span :class="[flag]"><a-icon :type="`caret-${flag}`"/></span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: "Trend",
|
||||||
|
props: {
|
||||||
|
prefixCls: {
|
||||||
|
type: String,
|
||||||
|
default: 'ant-pro-trend'
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* 上升下降标识:up|down
|
||||||
|
*/
|
||||||
|
flag: {
|
||||||
|
type: String,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* 颜色反转
|
||||||
|
*/
|
||||||
|
reverseColor: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
@import "index";
|
||||||
|
</style>
|
||||||
3
ant-design-jeecg-vue/src/components/Trend/index.js
Normal file
3
ant-design-jeecg-vue/src/components/Trend/index.js
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
import Trend from './Trend.vue'
|
||||||
|
|
||||||
|
export default Trend
|
||||||
42
ant-design-jeecg-vue/src/components/Trend/index.less
Normal file
42
ant-design-jeecg-vue/src/components/Trend/index.less
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
@import "../index";
|
||||||
|
|
||||||
|
@trend-prefix-cls: ~"@{ant-pro-prefix}-trend";
|
||||||
|
|
||||||
|
.@{trend-prefix-cls} {
|
||||||
|
display: inline-block;
|
||||||
|
font-size: @font-size-base;
|
||||||
|
line-height: 22px;
|
||||||
|
|
||||||
|
.up,
|
||||||
|
.down {
|
||||||
|
margin-left: 4px;
|
||||||
|
position: relative;
|
||||||
|
top: 1px;
|
||||||
|
|
||||||
|
i {
|
||||||
|
font-size: 12px;
|
||||||
|
transform: scale(0.83);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.item-text {
|
||||||
|
display: inline-block;
|
||||||
|
margin-left: 8px;
|
||||||
|
color: rgba(0,0,0,.85);
|
||||||
|
}
|
||||||
|
|
||||||
|
.up {
|
||||||
|
color: @red-6;
|
||||||
|
}
|
||||||
|
.down {
|
||||||
|
color: @green-6;
|
||||||
|
top: -1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.reverse-color .up {
|
||||||
|
color: @green-6;
|
||||||
|
}
|
||||||
|
&.reverse-color .down {
|
||||||
|
color: @red-6;
|
||||||
|
}
|
||||||
|
}
|
||||||
25
ant-design-jeecg-vue/src/components/_util/StringUtil.js
Normal file
25
ant-design-jeecg-vue/src/components/_util/StringUtil.js
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
|
||||||
|
export const getStrFullLength = (str = '') =>
|
||||||
|
str.split('').reduce((pre, cur) => {
|
||||||
|
const charCode = cur.charCodeAt(0)
|
||||||
|
if (charCode >= 0 && charCode <= 128) {
|
||||||
|
return pre + 1
|
||||||
|
}
|
||||||
|
return pre + 2
|
||||||
|
}, 0)
|
||||||
|
|
||||||
|
export const cutStrByFullLength = (str = '', maxLength) => {
|
||||||
|
let showLength = 0
|
||||||
|
return str.split('').reduce((pre, cur) => {
|
||||||
|
const charCode = cur.charCodeAt(0)
|
||||||
|
if (charCode >= 0 && charCode <= 128) {
|
||||||
|
showLength += 1
|
||||||
|
} else {
|
||||||
|
showLength += 2
|
||||||
|
}
|
||||||
|
if (showLength <= maxLength) {
|
||||||
|
return pre + cur
|
||||||
|
}
|
||||||
|
return pre
|
||||||
|
}, '')
|
||||||
|
}
|
||||||
12
ant-design-jeecg-vue/src/components/_util/util.js
Normal file
12
ant-design-jeecg-vue/src/components/_util/util.js
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
/**
|
||||||
|
* components util
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 清理空值,对象
|
||||||
|
* @param children
|
||||||
|
* @returns {*[]}
|
||||||
|
*/
|
||||||
|
export function filterEmpty (children = []) {
|
||||||
|
return children.filter(c => c.tag || (c.text && c.text.trim() !== ''))
|
||||||
|
}
|
||||||
57
ant-design-jeecg-vue/src/components/chart/Bar.vue
Normal file
57
ant-design-jeecg-vue/src/components/chart/Bar.vue
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
<template>
|
||||||
|
<div :style="{ padding: '0 0 32px 32px' }">
|
||||||
|
<h4 :style="{ marginBottom: '20px' }">{{ title }}</h4>
|
||||||
|
<v-chart
|
||||||
|
height="254"
|
||||||
|
:data="data"
|
||||||
|
:forceFit="true"
|
||||||
|
:padding="['auto', 'auto', '40', '50']">
|
||||||
|
<v-tooltip />
|
||||||
|
<v-axis />
|
||||||
|
<v-bar position="x*y"/>
|
||||||
|
</v-chart>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
const data = []
|
||||||
|
for (let i = 0; i < 12; i += 1) {
|
||||||
|
data.push({
|
||||||
|
x: `${i + 1}月`,
|
||||||
|
y: Math.floor(Math.random() * 1000) + 200
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const tooltip = [
|
||||||
|
'x*y',
|
||||||
|
(x, y) => ({
|
||||||
|
name: x,
|
||||||
|
value: y
|
||||||
|
})
|
||||||
|
]
|
||||||
|
const scale = [{
|
||||||
|
dataKey: 'x',
|
||||||
|
min: 2
|
||||||
|
}, {
|
||||||
|
dataKey: 'y',
|
||||||
|
title: '时间',
|
||||||
|
min: 1,
|
||||||
|
max: 22
|
||||||
|
}]
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "Bar",
|
||||||
|
props: {
|
||||||
|
title: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
data,
|
||||||
|
scale,
|
||||||
|
tooltip
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
67
ant-design-jeecg-vue/src/components/chart/Liquid.vue
Normal file
67
ant-design-jeecg-vue/src/components/chart/Liquid.vue
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<v-chart
|
||||||
|
:forceFit="true"
|
||||||
|
:height="height"
|
||||||
|
:width="width"
|
||||||
|
:data="data"
|
||||||
|
:scale="scale"
|
||||||
|
:padding="0">
|
||||||
|
<v-tooltip />
|
||||||
|
<v-interval
|
||||||
|
:shape="['liquid-fill-gauge']"
|
||||||
|
position="transfer*value"
|
||||||
|
color=""
|
||||||
|
:v-style="{
|
||||||
|
lineWidth: 10,
|
||||||
|
opacity: 0.75
|
||||||
|
}"
|
||||||
|
:tooltip="[
|
||||||
|
'transfer*value',
|
||||||
|
(transfer, value) => {
|
||||||
|
return {
|
||||||
|
name: transfer,
|
||||||
|
value,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
]"
|
||||||
|
></v-interval>
|
||||||
|
<v-guide
|
||||||
|
v-for="(row, index) in data"
|
||||||
|
:key="index"
|
||||||
|
type="text"
|
||||||
|
:top="true"
|
||||||
|
:position="{
|
||||||
|
gender: row.transfer,
|
||||||
|
value: 45
|
||||||
|
}"
|
||||||
|
:content="row.value + '%'"
|
||||||
|
:v-style="{
|
||||||
|
fontSize: 100,
|
||||||
|
textAlign: 'center',
|
||||||
|
opacity: 0.75,
|
||||||
|
}"
|
||||||
|
/>
|
||||||
|
</v-chart>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: "Liquid",
|
||||||
|
props: {
|
||||||
|
height: {
|
||||||
|
type: Number,
|
||||||
|
default: 0
|
||||||
|
},
|
||||||
|
width: {
|
||||||
|
type: Number,
|
||||||
|
default: 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
</style>
|
||||||
67
ant-design-jeecg-vue/src/components/chart/MiniArea.vue
Normal file
67
ant-design-jeecg-vue/src/components/chart/MiniArea.vue
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
<template>
|
||||||
|
<div class="antv-chart-mini">
|
||||||
|
<div class="chart-wrapper" :style="{ height: 46 }">
|
||||||
|
<v-chart :force-fit="true" :height="height" :data="datasource" :padding="[36, 0, 18, 0]">
|
||||||
|
<v-tooltip />
|
||||||
|
<v-smooth-area position="x*y" />
|
||||||
|
</v-chart>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import moment from 'dayjs'
|
||||||
|
const data = []
|
||||||
|
const beginDay = new Date().getTime()
|
||||||
|
|
||||||
|
for (let i = 0; i < 10; i++) {
|
||||||
|
data.push({
|
||||||
|
x: moment(new Date(beginDay + 1000 * 60 * 60 * 24 * i)).format('YYYY-MM-DD'),
|
||||||
|
y: Math.round(Math.random() * 10)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log("123321",data)
|
||||||
|
const tooltip = [
|
||||||
|
'x*y',
|
||||||
|
(x, y) => ({
|
||||||
|
name: x,
|
||||||
|
value: y
|
||||||
|
})
|
||||||
|
]
|
||||||
|
const scale = [{
|
||||||
|
dataKey: 'x',
|
||||||
|
min: 2
|
||||||
|
}, {
|
||||||
|
dataKey: 'y',
|
||||||
|
title: '时间',
|
||||||
|
min: 1,
|
||||||
|
max: 22
|
||||||
|
}]
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "MiniArea",
|
||||||
|
props:{
|
||||||
|
datasource:{
|
||||||
|
type: Array,
|
||||||
|
default:()=>[]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created(){
|
||||||
|
if(this.datasource.length==0){
|
||||||
|
this.datasource = data;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
tooltip,
|
||||||
|
scale,
|
||||||
|
height: 100
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
@import "chart";
|
||||||
|
</style>
|
||||||
68
ant-design-jeecg-vue/src/components/chart/MiniBar.vue
Normal file
68
ant-design-jeecg-vue/src/components/chart/MiniBar.vue
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
<template>
|
||||||
|
<div class="antv-chart-mini">
|
||||||
|
<div class="chart-wrapper" :style="{ height: 46 }">
|
||||||
|
<v-chart :force-fit="true" :height="height" :data="datasource" :padding="[36, 5, 18, 5]">
|
||||||
|
<v-tooltip />
|
||||||
|
<v-bar position="x*y" />
|
||||||
|
</v-chart>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import moment from 'dayjs'
|
||||||
|
const data = []
|
||||||
|
const beginDay = new Date().getTime()
|
||||||
|
|
||||||
|
for (let i = 0; i < 10; i++) {
|
||||||
|
data.push({
|
||||||
|
x: moment(new Date(beginDay + 1000 * 60 * 60 * 24 * i)).format('YYYY-MM-DD'),
|
||||||
|
y: Math.round(Math.random() * 10)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const tooltip = [
|
||||||
|
'x*y',
|
||||||
|
(x, y) => ({
|
||||||
|
name: x,
|
||||||
|
value: y
|
||||||
|
})
|
||||||
|
]
|
||||||
|
|
||||||
|
const scale = [{
|
||||||
|
dataKey: 'x',
|
||||||
|
min: 2
|
||||||
|
}, {
|
||||||
|
dataKey: 'y',
|
||||||
|
title: '时间',
|
||||||
|
min: 1,
|
||||||
|
max: 30
|
||||||
|
}]
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "MiniBar",
|
||||||
|
props:{
|
||||||
|
datasource:{
|
||||||
|
type: Array,
|
||||||
|
default:()=>[]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created(){
|
||||||
|
if(this.datasource.length==0){
|
||||||
|
this.datasource = data;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
data,
|
||||||
|
tooltip,
|
||||||
|
scale,
|
||||||
|
height: 100
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
@import "chart";
|
||||||
|
</style>
|
||||||
75
ant-design-jeecg-vue/src/components/chart/MiniProgress.vue
Normal file
75
ant-design-jeecg-vue/src/components/chart/MiniProgress.vue
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
<template>
|
||||||
|
<div class="chart-mini-progress">
|
||||||
|
<div class="target" :style="{ left: target + '%'}">
|
||||||
|
<span :style="{ backgroundColor: color }" />
|
||||||
|
<span :style="{ backgroundColor: color }"/>
|
||||||
|
</div>
|
||||||
|
<div class="progress-wrapper">
|
||||||
|
<div class="progress" :style="{ backgroundColor: color, width: percentage + '%', height: height }"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: "MiniProgress",
|
||||||
|
props: {
|
||||||
|
target: {
|
||||||
|
type: Number,
|
||||||
|
default: 0
|
||||||
|
},
|
||||||
|
height: {
|
||||||
|
type: String,
|
||||||
|
default: '10px'
|
||||||
|
},
|
||||||
|
color: {
|
||||||
|
type: String,
|
||||||
|
default: '#13C2C2'
|
||||||
|
},
|
||||||
|
percentage: {
|
||||||
|
type: Number,
|
||||||
|
default: 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.chart-mini-progress {
|
||||||
|
padding: 5px 0;
|
||||||
|
position: relative;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
.target {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
|
||||||
|
span {
|
||||||
|
border-radius: 100px;
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
height: 4px;
|
||||||
|
width: 2px;
|
||||||
|
|
||||||
|
&:last-child {
|
||||||
|
top: auto;
|
||||||
|
bottom: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.progress-wrapper {
|
||||||
|
background-color: #f5f5f5;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
.progress {
|
||||||
|
transition: all .4s cubic-bezier(.08,.82,.17,1) 0s;
|
||||||
|
border-radius: 1px 0 0 1px;
|
||||||
|
background-color: #1890ff;
|
||||||
|
width: 0;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
68
ant-design-jeecg-vue/src/components/chart/Radar.vue
Normal file
68
ant-design-jeecg-vue/src/components/chart/Radar.vue
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
<template>
|
||||||
|
<v-chart :forceFit="true" height="400" :data="data" :padding="[20, 20, 95, 20]" :scale="scale">
|
||||||
|
<v-tooltip></v-tooltip>
|
||||||
|
<v-axis :dataKey="axis1Opts.dataKey" :line="axis1Opts.line" :tickLine="axis1Opts.tickLine" :grid="axis1Opts.grid" />
|
||||||
|
<v-axis :dataKey="axis2Opts.dataKey" :line="axis2Opts.line" :tickLine="axis2Opts.tickLine" :grid="axis2Opts.grid" />
|
||||||
|
<v-legend dataKey="user" marker="circle" :offset="30" />
|
||||||
|
<v-coord type="polar" radius="0.8" />
|
||||||
|
<v-line position="item*score" color="user" :size="2" />
|
||||||
|
<v-point position="item*score" color="user" :size="4" shape="circle" />
|
||||||
|
</v-chart>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
const axis1Opts = {
|
||||||
|
dataKey: 'item',
|
||||||
|
line: null,
|
||||||
|
tickLine: null,
|
||||||
|
grid: {
|
||||||
|
lineStyle: {
|
||||||
|
lineDash: null
|
||||||
|
},
|
||||||
|
hideFirstLine: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const axis2Opts = {
|
||||||
|
dataKey: 'score',
|
||||||
|
line: null,
|
||||||
|
tickLine: null,
|
||||||
|
grid: {
|
||||||
|
type: 'polygon',
|
||||||
|
lineStyle: {
|
||||||
|
lineDash: null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const scale = [
|
||||||
|
{
|
||||||
|
dataKey: 'score',
|
||||||
|
min: 0,
|
||||||
|
max: 80
|
||||||
|
}, {
|
||||||
|
dataKey: 'user',
|
||||||
|
alias: '类型'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'Radar',
|
||||||
|
props: {
|
||||||
|
data: {
|
||||||
|
type: Array,
|
||||||
|
default: null,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
axis1Opts,
|
||||||
|
axis2Opts,
|
||||||
|
scale
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
</style>
|
||||||
77
ant-design-jeecg-vue/src/components/chart/RankList.vue
Normal file
77
ant-design-jeecg-vue/src/components/chart/RankList.vue
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
<template>
|
||||||
|
<div class="rank">
|
||||||
|
<h4 class="title">{{ title }}</h4>
|
||||||
|
<ul class="list">
|
||||||
|
<li :key="index" v-for="(item, index) in list">
|
||||||
|
<span :class="index < 3 ? 'active' : null">{{ index + 1 }}</span>
|
||||||
|
<span>{{ item.name }}</span>
|
||||||
|
<span>{{ item.total }}</span>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: "RankList",
|
||||||
|
// ['title', 'list']
|
||||||
|
props: {
|
||||||
|
title: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
list: {
|
||||||
|
type: Array,
|
||||||
|
default: null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
|
||||||
|
.rank {
|
||||||
|
padding: 0 32px 32px 72px;
|
||||||
|
|
||||||
|
.list {
|
||||||
|
margin: 25px 0 0;
|
||||||
|
padding: 0;
|
||||||
|
list-style: none;
|
||||||
|
|
||||||
|
li {
|
||||||
|
margin-top: 16px;
|
||||||
|
|
||||||
|
span {
|
||||||
|
color: rgba(0, 0, 0, .65);
|
||||||
|
font-size: 14px;
|
||||||
|
line-height: 22px;
|
||||||
|
|
||||||
|
&:first-child {
|
||||||
|
background-color: #f5f5f5;
|
||||||
|
border-radius: 20px;
|
||||||
|
display: inline-block;
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 600;
|
||||||
|
margin-right: 24px;
|
||||||
|
height: 20px;
|
||||||
|
line-height: 20px;
|
||||||
|
width: 20px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
&.active {
|
||||||
|
background-color: #314659;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
&:last-child {
|
||||||
|
float: right;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.mobile .rank {
|
||||||
|
padding: 0 32px 32px 32px;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
64
ant-design-jeecg-vue/src/components/chart/TransferBar.vue
Normal file
64
ant-design-jeecg-vue/src/components/chart/TransferBar.vue
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
<template>
|
||||||
|
<div :style="{ padding: '0 0 32px 32px' }">
|
||||||
|
<h4 :style="{ marginBottom: '20px' }">{{ title }}</h4>
|
||||||
|
<v-chart
|
||||||
|
height="254"
|
||||||
|
:data="data"
|
||||||
|
:scale="scale"
|
||||||
|
:forceFit="true"
|
||||||
|
:padding="['auto', 'auto', '40', '50']">
|
||||||
|
<v-tooltip />
|
||||||
|
<v-axis />
|
||||||
|
<v-bar position="x*y"/>
|
||||||
|
</v-chart>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
const tooltip = [
|
||||||
|
'x*y',
|
||||||
|
(x, y) => ({
|
||||||
|
name: x,
|
||||||
|
value: y
|
||||||
|
})
|
||||||
|
]
|
||||||
|
const scale = [{
|
||||||
|
dataKey: 'x',
|
||||||
|
title: '日期(天)',
|
||||||
|
alias: '日期(天)',
|
||||||
|
min: 2
|
||||||
|
}, {
|
||||||
|
dataKey: 'y',
|
||||||
|
title: '流量(Gb)',
|
||||||
|
alias: '流量(Gb)',
|
||||||
|
min: 1
|
||||||
|
}]
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "Bar",
|
||||||
|
props: {
|
||||||
|
title: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
data: [],
|
||||||
|
scale,
|
||||||
|
tooltip
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created () {
|
||||||
|
this.getMonthBar()
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
getMonthBar() {
|
||||||
|
this.$http.get('/analysis/month-bar')
|
||||||
|
.then(res => {
|
||||||
|
this.data = res.result
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
82
ant-design-jeecg-vue/src/components/chart/Trend.vue
Normal file
82
ant-design-jeecg-vue/src/components/chart/Trend.vue
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
<template>
|
||||||
|
<div class="chart-trend">
|
||||||
|
{{ term }}
|
||||||
|
<span>{{ rate }}%</span>
|
||||||
|
<span :class="['trend-icon', trend]"><a-icon :type="'caret-' + trend"/></span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: "Trend",
|
||||||
|
props: {
|
||||||
|
term: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
percentage: {
|
||||||
|
type: Number,
|
||||||
|
default: null
|
||||||
|
},
|
||||||
|
type: {
|
||||||
|
type: Boolean,
|
||||||
|
default: null
|
||||||
|
},
|
||||||
|
target: {
|
||||||
|
type: Number,
|
||||||
|
default: 0
|
||||||
|
},
|
||||||
|
value: {
|
||||||
|
type: Number,
|
||||||
|
default: 0
|
||||||
|
},
|
||||||
|
fixed: {
|
||||||
|
type: Number,
|
||||||
|
default: 2
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
trend: this.type && 'up' || 'down',
|
||||||
|
rate: this.percentage
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created () {
|
||||||
|
let type = this.type === null ? this.value >= this.target : this.type
|
||||||
|
this.trend = type ? 'up' : 'down';
|
||||||
|
this.rate = (this.percentage === null ? Math.abs(this.value - this.target) * 100 / this.target : this.percentage).toFixed(this.fixed)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.chart-trend {
|
||||||
|
display: inline-block;
|
||||||
|
font-size: 14px;
|
||||||
|
line-height: 22px;
|
||||||
|
|
||||||
|
.trend-icon {
|
||||||
|
font-size: 12px;
|
||||||
|
|
||||||
|
&.up, &.down {
|
||||||
|
margin-left: 4px;
|
||||||
|
position: relative;
|
||||||
|
top: 1px;
|
||||||
|
|
||||||
|
i {
|
||||||
|
font-size: 12px;
|
||||||
|
transform: scale(.83);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.up {
|
||||||
|
color: #f5222d;
|
||||||
|
}
|
||||||
|
&.down {
|
||||||
|
color: #52c41a;
|
||||||
|
top: -1px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
13
ant-design-jeecg-vue/src/components/chart/chart.scss
Normal file
13
ant-design-jeecg-vue/src/components/chart/chart.scss
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
.antv-chart-mini {
|
||||||
|
position: relative;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
.chart-wrapper {
|
||||||
|
position: absolute;
|
||||||
|
bottom: -28px;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
/* margin: 0 -5px;
|
||||||
|
overflow: hidden;*/
|
||||||
|
}
|
||||||
|
}
|
||||||
47
ant-design-jeecg-vue/src/components/dict/DictSelectTag.vue
Normal file
47
ant-design-jeecg-vue/src/components/dict/DictSelectTag.vue
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
<template>
|
||||||
|
<a-select :placeholder="placeholder" :value="value" @change="handleInput">
|
||||||
|
<a-select-option value="">请选择</a-select-option>
|
||||||
|
<a-select-option v-for="(item, key) in dictOptions" :key="key" :value="item.value">{{ item.text }}</a-select-option>
|
||||||
|
</a-select>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import {ajaxGetDictItems} from '@/api/api'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "DictSelectTag",
|
||||||
|
props: {
|
||||||
|
dictCode: String,
|
||||||
|
placeholder: String,
|
||||||
|
value: String,// 1.接收一个 value prop
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
dictOptions: [],
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
console.log(this.dictCode);
|
||||||
|
//获取字典数据
|
||||||
|
this.initDictData();
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
initDictData() {
|
||||||
|
//根据字典Code, 初始化字典数组
|
||||||
|
ajaxGetDictItems(this.dictCode, null).then((res) => {
|
||||||
|
if (res.success) {
|
||||||
|
// console.log(res.result);
|
||||||
|
this.dictOptions = res.result;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
handleInput(val) {
|
||||||
|
console.log(val);
|
||||||
|
this.$emit('input', val); // 2.触发 input 事件,并传入新值
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
</style>
|
||||||
61
ant-design-jeecg-vue/src/components/dict/DictSelectUtil.js
Normal file
61
ant-design-jeecg-vue/src/components/dict/DictSelectUtil.js
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
/**
|
||||||
|
* 字典 util
|
||||||
|
* author: scott
|
||||||
|
* date: 20190109
|
||||||
|
*/
|
||||||
|
|
||||||
|
import {ajaxGetDictItems} from '@/api/api'
|
||||||
|
import {getAction} from '@/api/manage'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取字典数组
|
||||||
|
* @param dictCode 字典Code
|
||||||
|
* @return List<Map>
|
||||||
|
*/
|
||||||
|
export async function initDictOptions(dictCode) {
|
||||||
|
if (!dictCode) {
|
||||||
|
return '字典Code不能为空!';
|
||||||
|
}
|
||||||
|
//获取字典数组
|
||||||
|
let res = await ajaxGetDictItems(dictCode);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 字典值替换文本通用方法
|
||||||
|
* @param dictOptions 字典数组
|
||||||
|
* @param text 字典值
|
||||||
|
* @return String
|
||||||
|
*/
|
||||||
|
export function filterDictText(dictOptions, text) {
|
||||||
|
let re = "";
|
||||||
|
dictOptions.forEach(function (option) {
|
||||||
|
if (text === option.value) {
|
||||||
|
re = option.text;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return re;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 翻译字段值对应的文本
|
||||||
|
* @param children
|
||||||
|
* @returns string
|
||||||
|
*/
|
||||||
|
export async function ajaxFilterDictText(dictCode, key) {
|
||||||
|
if (!dictCode) {
|
||||||
|
return '字典Code不能为空!';
|
||||||
|
}
|
||||||
|
//console.log(`key : ${key}`);
|
||||||
|
if (!key) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
//通过请求读取字典文本
|
||||||
|
let res = await getAction(`/sys/dict/getDictText/${dictCode}/${key}`);
|
||||||
|
if (res.success) {
|
||||||
|
// console.log('restult: '+ res.result);
|
||||||
|
return res.result;
|
||||||
|
} else {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
}
|
||||||
36
ant-design-jeecg-vue/src/components/dict/README.md
Normal file
36
ant-design-jeecg-vue/src/components/dict/README.md
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
DictSelectTag 组件说明
|
||||||
|
===
|
||||||
|
|
||||||
|
例子
|
||||||
|
----
|
||||||
|
<DictSelectTag v-model="queryParam.sex" placeholder="请输入用户性别" dictCode="sex"/>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
DictSelectUtil.js 列表字典函数用法说明
|
||||||
|
===
|
||||||
|
|
||||||
|
例子
|
||||||
|
----
|
||||||
|
|
||||||
|
第一步: 引入依赖方法
|
||||||
|
import {initDictOptions, filterDictText} from '@/components/dict/DictSelectUtil'
|
||||||
|
|
||||||
|
第二步: 在created()初始化方法执行字典配置方法
|
||||||
|
//初始化字典配置
|
||||||
|
this.initDictConfig();
|
||||||
|
第三步: 实现initDictConfig方法,加载列表所需要的字典(列表上有多个字典项,就执行多次initDictOptions方法)
|
||||||
|
//sexDictOptions 自行定义
|
||||||
|
initDictConfig() {
|
||||||
|
//初始化字典 - 性别
|
||||||
|
initDictOptions('sex').then((res) => {
|
||||||
|
if (res.success) {
|
||||||
|
this.sexDictOptions = res.result;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
第四步:实现字段的customRender方法
|
||||||
|
customRender: (text, record, index) => {
|
||||||
|
//字典值替换通用方法
|
||||||
|
return filterDictText(this.sexDictOptions, text);
|
||||||
|
}
|
||||||
22
ant-design-jeecg-vue/src/components/dict/UserInfoTag.vue
Normal file
22
ant-design-jeecg-vue/src/components/dict/UserInfoTag.vue
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
<template>
|
||||||
|
<span>
|
||||||
|
<!--// 1、当有数据输入时触发了该组件的input事件-->
|
||||||
|
<!--<input type="text" :value="value" @input="updateVal($event.target.value)">-->
|
||||||
|
<a-input :placeholder="placeholder" :value="value" @input="updateVal($event.target.value)"></a-input>
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
value: String,
|
||||||
|
placeholder: String
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
updateVal: function(val) {
|
||||||
|
// 2、手动触发父组件的input事件并将值传给父组件
|
||||||
|
this.$emit('input', val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
7
ant-design-jeecg-vue/src/components/dict/index.js
Normal file
7
ant-design-jeecg-vue/src/components/dict/index.js
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
import T from './DictSelectTag.vue'
|
||||||
|
const DictSelectTag = {
|
||||||
|
install: function (Vue) {
|
||||||
|
Vue.component('DictSelectTag',T);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
export default DictSelectTag;
|
||||||
4
ant-design-jeecg-vue/src/components/index.less
Normal file
4
ant-design-jeecg-vue/src/components/index.less
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
@import "~ant-design-vue/lib/style/index";
|
||||||
|
|
||||||
|
// The prefix to use on all css classes from ant-pro.
|
||||||
|
@ant-pro-prefix : ant-pro;
|
||||||
74
ant-design-jeecg-vue/src/components/jeecg/JDate.vue
Normal file
74
ant-design-jeecg-vue/src/components/jeecg/JDate.vue
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
<template>
|
||||||
|
<a-date-picker
|
||||||
|
:disabled="readOnly"
|
||||||
|
:placeholder="placeholder"
|
||||||
|
@change="handleDateChange"
|
||||||
|
:value="momVal"
|
||||||
|
:showTime="showTime"
|
||||||
|
:format="dateFormat"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
<script>
|
||||||
|
import moment from 'moment'
|
||||||
|
export default {
|
||||||
|
name: 'JDate',
|
||||||
|
props: {
|
||||||
|
placeholder:{
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
required: false
|
||||||
|
},
|
||||||
|
value:{
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
required: false
|
||||||
|
},
|
||||||
|
dateFormat:{
|
||||||
|
type: String,
|
||||||
|
default: 'YYYY-MM-DD',
|
||||||
|
required: false
|
||||||
|
},
|
||||||
|
triggerChange:{
|
||||||
|
type: Boolean,
|
||||||
|
required: false,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
readOnly:{
|
||||||
|
type: Boolean,
|
||||||
|
required: false,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
showTime:{
|
||||||
|
type: Boolean,
|
||||||
|
required: false,
|
||||||
|
default: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data () {
|
||||||
|
let dateStr = this.value;
|
||||||
|
return {
|
||||||
|
decorator:"",
|
||||||
|
momVal:!dateStr?null:moment(dateStr,this.dateFormat)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
value (val) {
|
||||||
|
if(!val){
|
||||||
|
this.momVal = null
|
||||||
|
}else{
|
||||||
|
this.momVal = moment(val,this.dateFormat)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
moment,
|
||||||
|
handleDateChange(mom,dateStr){
|
||||||
|
if(this.triggerChange){
|
||||||
|
this.$emit('change', dateStr);
|
||||||
|
}else{
|
||||||
|
this.$emit('input', dateStr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
43
ant-design-jeecg-vue/src/components/jeecg/README.md
Normal file
43
ant-design-jeecg-vue/src/components/jeecg/README.md
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
日期组件
|
||||||
|
说明:antd-vue日期组件需要用moment中转一下,用起来不是很方便,特二次封装,使用时只需要传字符串即可
|
||||||
|
====
|
||||||
|
|
||||||
|
参数说明
|
||||||
|
----
|
||||||
|
placeholder:placeholder
|
||||||
|
readOnly:true/false
|
||||||
|
value:绑定v-model或是v-decorator后不需要设置
|
||||||
|
showTime:是否展示时间true/false
|
||||||
|
dateFormat:日期格式 默认'YYYY-MM-DD' 若showTime设置为true则需要将其设置成对应的时间格式(如:YYYY-MM-DD HH:mm:ss)
|
||||||
|
triggerChange:触发组件值改变的事件是否是change,当使用v-decorator时且没有设置decorator的option.trigger为input需要设置该值为true
|
||||||
|
|
||||||
|
使用示例
|
||||||
|
----
|
||||||
|
1.组件带有v-model的使用方法
|
||||||
|
<j-date v-model="dateStr"></j-date>
|
||||||
|
|
||||||
|
2.组件带有v-decorator的使用方法
|
||||||
|
a).设置trigger-change属性为true
|
||||||
|
<j-date :trigger-change="true" v-decorator="['dateStr',{}]"></j-date>
|
||||||
|
b).设置decorator的option.trigger为input
|
||||||
|
<j-date v-decorator="['dateStr',{trigger:'input'}]"></j-date>
|
||||||
|
|
||||||
|
3.其他使用
|
||||||
|
添加style
|
||||||
|
<j-date v-model="dateStr" style="width:100%"></j-date>
|
||||||
|
添加placeholder
|
||||||
|
<j-date v-model="dateStr" placeholder="请输入dateStr"></j-date>
|
||||||
|
添加readOnly
|
||||||
|
<j-date v-model="dateStr" :read-only="true"></j-date>
|
||||||
|
|
||||||
|
备注:
|
||||||
|
script内需引入jdate
|
||||||
|
<script>
|
||||||
|
import JDate from '@/components/jeecg/JDate'
|
||||||
|
export default {
|
||||||
|
name: "demo",
|
||||||
|
components: {
|
||||||
|
JDate
|
||||||
|
},
|
||||||
|
....
|
||||||
|
</script>
|
||||||
60
ant-design-jeecg-vue/src/components/layouts/BasicLayout.vue
Normal file
60
ant-design-jeecg-vue/src/components/layouts/BasicLayout.vue
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
<template>
|
||||||
|
<global-layout>
|
||||||
|
<transition name="page-transition">
|
||||||
|
<keep-alive v-if="keepAlive">
|
||||||
|
<router-view />
|
||||||
|
</keep-alive>
|
||||||
|
<router-view v-else />
|
||||||
|
</transition>
|
||||||
|
</global-layout>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import GlobalLayout from '@/components/page/GlobalLayout'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "BasicLayout",
|
||||||
|
components: {
|
||||||
|
GlobalLayout
|
||||||
|
},
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
keepAlive () {
|
||||||
|
return this.$route.meta.keepAlive
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The following styles are auto-applied to elements with
|
||||||
|
* transition="page-transition" when their visibility is toggled
|
||||||
|
* by Vue.js.
|
||||||
|
*
|
||||||
|
* You can easily play with the page transition by editing
|
||||||
|
* these styles.
|
||||||
|
*/
|
||||||
|
|
||||||
|
.page-transition-enter {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-transition-leave-active {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-transition-enter .page-transition-container,
|
||||||
|
.page-transition-leave-active .page-transition-container {
|
||||||
|
-webkit-transform: scale(1.1);
|
||||||
|
transform: scale(1.1);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
16
ant-design-jeecg-vue/src/components/layouts/BlankLayout.vue
Normal file
16
ant-design-jeecg-vue/src/components/layouts/BlankLayout.vue
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<router-view />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "BlankLayout",
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
</style>
|
||||||
@ -0,0 +1,47 @@
|
|||||||
|
<template>
|
||||||
|
|
||||||
|
<iframe :id="id" :src="url" frameborder="0" width="100%" height="800px" scrolling="auto"></iframe>
|
||||||
|
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import PageLayout from '../page/PageLayout'
|
||||||
|
import RouteView from './RouteView'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "IframePageContent",
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
url: "",
|
||||||
|
id:""
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created () {
|
||||||
|
this.goUrl()
|
||||||
|
},
|
||||||
|
updated () {
|
||||||
|
this.goUrl()
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
$route(to, from) {
|
||||||
|
this.goUrl();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
goUrl () {
|
||||||
|
let url = this.$route.meta.url
|
||||||
|
let id = this.$route.path
|
||||||
|
this.id = id
|
||||||
|
//url = "http://www.baidu.com"
|
||||||
|
console.log("------url------"+url)
|
||||||
|
if (url !== null && url !== undefined) {
|
||||||
|
this.url = url;
|
||||||
|
//window.open(this.url);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
</style>
|
||||||
85
ant-design-jeecg-vue/src/components/layouts/PageView.vue
Normal file
85
ant-design-jeecg-vue/src/components/layouts/PageView.vue
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
<template>
|
||||||
|
<page-layout :desc="description" :title="getTitle" :link-list="linkList" :search="search" :tabs="tabs">
|
||||||
|
<div slot="extra" class="extra-img">
|
||||||
|
<img :src="extraImage"/>
|
||||||
|
</div>
|
||||||
|
<!-- keep-alive -->
|
||||||
|
<route-view ref="content"></route-view>
|
||||||
|
</page-layout>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import PageLayout from '../page/PageLayout'
|
||||||
|
import RouteView from './RouteView'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "PageContent",
|
||||||
|
components: {
|
||||||
|
RouteView,
|
||||||
|
PageLayout
|
||||||
|
},
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
title: '',
|
||||||
|
description: '',
|
||||||
|
linkList: [],
|
||||||
|
extraImage: '',
|
||||||
|
search: false,
|
||||||
|
tabs: {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted () {
|
||||||
|
this.getPageHeaderInfo()
|
||||||
|
},
|
||||||
|
updated () {
|
||||||
|
this.getPageHeaderInfo()
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
|
||||||
|
getTitle () {
|
||||||
|
return this.$route.meta.title
|
||||||
|
}
|
||||||
|
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
getPageHeaderInfo () {
|
||||||
|
// eslint-disable-next-line
|
||||||
|
this.title = this.$route.meta.title
|
||||||
|
// 因为套用了一层 route-view 所以要取 ref 对象下的子节点的第一个对象
|
||||||
|
const content = this.$refs.content && this.$refs.content.$children[0]
|
||||||
|
|
||||||
|
if (content) {
|
||||||
|
this.description = content.description
|
||||||
|
this.linkList = content.linkList
|
||||||
|
this.extraImage = content.extraImage
|
||||||
|
this.search = content.search == true ? true : false
|
||||||
|
this.tabs = content.tabs
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.extra-img {
|
||||||
|
margin-top: -60px;
|
||||||
|
text-align: center;
|
||||||
|
width: 195px;
|
||||||
|
|
||||||
|
img {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.mobile {
|
||||||
|
.extra-img{
|
||||||
|
margin-top: 0;
|
||||||
|
text-align: center;
|
||||||
|
width: 96px;
|
||||||
|
|
||||||
|
img{
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
17
ant-design-jeecg-vue/src/components/layouts/RouteView.vue
Normal file
17
ant-design-jeecg-vue/src/components/layouts/RouteView.vue
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
<template>
|
||||||
|
<keep-alive v-if="keepAlive">
|
||||||
|
<router-view />
|
||||||
|
</keep-alive>
|
||||||
|
<router-view v-else />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: "RouteView",
|
||||||
|
computed: {
|
||||||
|
keepAlive () {
|
||||||
|
return this.$route.meta.keepAlive
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
213
ant-design-jeecg-vue/src/components/layouts/TabLayout.vue
Normal file
213
ant-design-jeecg-vue/src/components/layouts/TabLayout.vue
Normal file
@ -0,0 +1,213 @@
|
|||||||
|
<template>
|
||||||
|
<global-layout>
|
||||||
|
<contextmenu :itemList="menuItemList" :visible.sync="menuVisible" @select="onMenuSelect" />
|
||||||
|
<a-tabs
|
||||||
|
@contextmenu.native="e => onContextmenu(e)"
|
||||||
|
v-if="multipage"
|
||||||
|
:active-key="activePage"
|
||||||
|
style="margin-top: -8px; margin-bottom: -10px"
|
||||||
|
:hide-add="true"
|
||||||
|
type="editable-card"
|
||||||
|
@change="changePage"
|
||||||
|
@edit="editPage">
|
||||||
|
<a-tab-pane :id="page.fullPath" :key="page.fullPath" v-for="page in pageList">
|
||||||
|
<span slot="tab" :pagekey="page.fullPath">{{ page.meta.title }}</span>
|
||||||
|
</a-tab-pane>
|
||||||
|
</a-tabs>
|
||||||
|
<transition name="page-toggle">
|
||||||
|
<keep-alive v-if="multipage">
|
||||||
|
<router-view />
|
||||||
|
</keep-alive>
|
||||||
|
<router-view v-else />
|
||||||
|
</transition>
|
||||||
|
</global-layout>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import GlobalLayout from '@/components/page/GlobalLayout'
|
||||||
|
import Contextmenu from '@/components/menu/Contextmenu'
|
||||||
|
const indexKey="/dashboard/analysis"
|
||||||
|
export default {
|
||||||
|
name: "TabLayout",
|
||||||
|
components: {
|
||||||
|
GlobalLayout,
|
||||||
|
Contextmenu
|
||||||
|
},
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
pageList: [],
|
||||||
|
linkList: [],
|
||||||
|
activePage: '',
|
||||||
|
menuVisible: false,
|
||||||
|
menuItemList: [
|
||||||
|
{ key: '1', icon: 'arrow-left', text: '关闭左侧' },
|
||||||
|
{ key: '2', icon: 'arrow-right', text: '关闭右侧' },
|
||||||
|
{ key: '3', icon: 'close', text: '关闭其它' }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
multipage () {
|
||||||
|
return this.$store.state.app.multipage
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created () {
|
||||||
|
this.pageList.push(this.$route)
|
||||||
|
this.linkList.push(this.$route.fullPath)
|
||||||
|
this.activePage = this.$route.fullPath
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
'$route': function (newRoute) {
|
||||||
|
this.activePage = newRoute.fullPath
|
||||||
|
if (!this.multipage) {
|
||||||
|
this.linkList = [newRoute.fullPath]
|
||||||
|
this.pageList = [newRoute]
|
||||||
|
} else if (this.linkList.indexOf(newRoute.fullPath) < 0) {
|
||||||
|
this.linkList.push(newRoute.fullPath)
|
||||||
|
this.pageList.push(newRoute)
|
||||||
|
}else if(this.linkList.indexOf(newRoute.fullPath) >= 0){
|
||||||
|
let oldIndex = this.linkList.indexOf(newRoute.fullPath);
|
||||||
|
this.pageList.splice(oldIndex,1,newRoute);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'activePage': function (key) {
|
||||||
|
let index = this.linkList.lastIndexOf(key);
|
||||||
|
var waitRouter = this.pageList[index];
|
||||||
|
this.$router.push({
|
||||||
|
path: waitRouter.path,
|
||||||
|
name: waitRouter.name,
|
||||||
|
params: waitRouter.params
|
||||||
|
});
|
||||||
|
},
|
||||||
|
'multipage': function (newVal) {
|
||||||
|
if (!newVal) {
|
||||||
|
this.linkList = [this.$route.fullPath]
|
||||||
|
this.pageList = [this.$route]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
changePage (key) {
|
||||||
|
this.activePage = key
|
||||||
|
},
|
||||||
|
editPage (key, action) {
|
||||||
|
this[action](key)
|
||||||
|
},
|
||||||
|
remove (key) {
|
||||||
|
if(key==indexKey){
|
||||||
|
this.$message.warning('首页不能关闭!')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (this.pageList.length === 1) {
|
||||||
|
this.$message.warning('这是最后一页,不能再关闭了啦')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.pageList = this.pageList.filter(item => item.fullPath !== key)
|
||||||
|
let index = this.linkList.indexOf(key)
|
||||||
|
this.linkList = this.linkList.filter(item => item !== key)
|
||||||
|
index = index >= this.linkList.length ? this.linkList.length - 1 : index
|
||||||
|
this.activePage = this.linkList[index]
|
||||||
|
},
|
||||||
|
onContextmenu (e) {
|
||||||
|
const pagekey = this.getPageKey(e.target)
|
||||||
|
if (pagekey !== null) {
|
||||||
|
e.preventDefault()
|
||||||
|
this.menuVisible = true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
getPageKey (target, depth) {
|
||||||
|
depth = depth || 0
|
||||||
|
if (depth > 2) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
let pageKey = target.getAttribute('pagekey')
|
||||||
|
pageKey = pageKey || (target.previousElementSibling ? target.previousElementSibling.getAttribute('pagekey') : null)
|
||||||
|
return pageKey || (target.firstElementChild ? this.getPageKey(target.firstElementChild, ++depth) : null)
|
||||||
|
},
|
||||||
|
onMenuSelect (key, target) {
|
||||||
|
let pageKey = this.getPageKey(target)
|
||||||
|
switch (key) {
|
||||||
|
case '1':
|
||||||
|
this.closeLeft(pageKey)
|
||||||
|
break
|
||||||
|
case '2':
|
||||||
|
this.closeRight(pageKey)
|
||||||
|
break
|
||||||
|
case '3':
|
||||||
|
this.closeOthers(pageKey)
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
},
|
||||||
|
closeOthers (pageKey) {
|
||||||
|
let index = this.linkList.indexOf(pageKey)
|
||||||
|
if(pageKey==indexKey){
|
||||||
|
this.linkList = this.linkList.slice(index, index + 1)
|
||||||
|
this.pageList = this.pageList.slice(index, index + 1)
|
||||||
|
this.activePage = this.linkList[0]
|
||||||
|
}else{
|
||||||
|
let indexContent = this.pageList.slice(0,1)[0]
|
||||||
|
this.linkList = this.linkList.slice(index, index + 1)
|
||||||
|
this.pageList = this.pageList.slice(index, index + 1)
|
||||||
|
this.linkList.unshift(indexKey)
|
||||||
|
this.pageList.unshift(indexContent)
|
||||||
|
this.activePage = this.linkList[1]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
closeLeft (pageKey) {
|
||||||
|
if(pageKey==indexKey){
|
||||||
|
return
|
||||||
|
}
|
||||||
|
let tempList = [...this.pageList];
|
||||||
|
let indexContent = tempList.slice(0,1)[0]
|
||||||
|
let index = this.linkList.indexOf(pageKey)
|
||||||
|
this.linkList = this.linkList.slice(index)
|
||||||
|
this.pageList = this.pageList.slice(index)
|
||||||
|
this.linkList.unshift(indexKey)
|
||||||
|
this.pageList.unshift(indexContent)
|
||||||
|
if (this.linkList.indexOf(this.activePage) < 0) {
|
||||||
|
this.activePage = this.linkList[0]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
closeRight (pageKey) {
|
||||||
|
let index = this.linkList.indexOf(pageKey)
|
||||||
|
this.linkList = this.linkList.slice(0, index + 1)
|
||||||
|
this.pageList = this.pageList.slice(0, index + 1)
|
||||||
|
if (this.linkList.indexOf(this.activePage < 0)) {
|
||||||
|
this.activePage = this.linkList[this.linkList.length - 1]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The following styles are auto-applied to elements with
|
||||||
|
* transition="page-transition" when their visibility is toggled
|
||||||
|
* by Vue.js.
|
||||||
|
*
|
||||||
|
* You can easily play with the page transition by editing
|
||||||
|
* these styles.
|
||||||
|
*/
|
||||||
|
|
||||||
|
.page-transition-enter {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-transition-leave-active {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-transition-enter .page-transition-container,
|
||||||
|
.page-transition-leave-active .page-transition-container {
|
||||||
|
-webkit-transform: scale(1.1);
|
||||||
|
transform: scale(1.1);
|
||||||
|
}
|
||||||
|
/*美化弹出Tab样式*/
|
||||||
|
.ant-tabs-nav-container {
|
||||||
|
margin-top: 4px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
150
ant-design-jeecg-vue/src/components/layouts/UserLayout.vue
Normal file
150
ant-design-jeecg-vue/src/components/layouts/UserLayout.vue
Normal file
@ -0,0 +1,150 @@
|
|||||||
|
<template>
|
||||||
|
<div id="userLayout" :class="['user-layout-wrapper', device]">
|
||||||
|
<div class="container">
|
||||||
|
<div class="top">
|
||||||
|
<div class="header">
|
||||||
|
<a href="/">
|
||||||
|
<img src="~@/assets/logo.svg" class="logo" alt="logo">
|
||||||
|
<span class="title">Jeecg Boot</span>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<div class="desc">
|
||||||
|
Jeecg Boot 是中国最具影响力的 企业级 快速开发平台
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<route-view></route-view>
|
||||||
|
|
||||||
|
<div class="footer">
|
||||||
|
<div class="links">
|
||||||
|
<a href="_self">帮助</a>
|
||||||
|
<a href="_self">隐私</a>
|
||||||
|
<a href="_self">条款</a>
|
||||||
|
</div>
|
||||||
|
<div class="copyright">
|
||||||
|
Copyright © 2019 <a href="http://www.jeecg.org" target="_blank">JEECG开源社区</a> 出品
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import RouteView from "@/components/layouts/RouteView"
|
||||||
|
import { mixinDevice } from '@/utils/mixin.js'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "UserLayout",
|
||||||
|
components: { RouteView },
|
||||||
|
mixins: [mixinDevice],
|
||||||
|
data () {
|
||||||
|
return {}
|
||||||
|
},
|
||||||
|
mounted () {
|
||||||
|
document.body.classList.add('userLayout')
|
||||||
|
},
|
||||||
|
beforeDestroy () {
|
||||||
|
document.body.classList.remove('userLayout')
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
#userLayout.user-layout-wrapper {
|
||||||
|
height: 100%;
|
||||||
|
|
||||||
|
&.mobile {
|
||||||
|
.container {
|
||||||
|
.main {
|
||||||
|
max-width: 368px;
|
||||||
|
width: 98%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.container {
|
||||||
|
width: 100%;
|
||||||
|
min-height: 100%;
|
||||||
|
background: #f0f2f5 url(~@/assets/background.svg) no-repeat 50%;
|
||||||
|
background-size: 100%;
|
||||||
|
padding: 110px 0 144px;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
a {
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.top {
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
|
.header {
|
||||||
|
height: 44px;
|
||||||
|
line-height: 44px;
|
||||||
|
|
||||||
|
.badge {
|
||||||
|
position: absolute;
|
||||||
|
display: inline-block;
|
||||||
|
line-height: 1;
|
||||||
|
vertical-align: middle;
|
||||||
|
margin-left: -12px;
|
||||||
|
margin-top: -10px;
|
||||||
|
opacity: 0.8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo {
|
||||||
|
height: 44px;
|
||||||
|
vertical-align: top;
|
||||||
|
margin-right: 16px;
|
||||||
|
border-style: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title {
|
||||||
|
font-size: 33px;
|
||||||
|
color: rgba(0, 0, 0, .85);
|
||||||
|
font-family: "Chinese Quote", -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "Helvetica Neue", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
|
||||||
|
font-weight: 600;
|
||||||
|
position: relative;
|
||||||
|
top: 2px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.desc {
|
||||||
|
font-size: 14px;
|
||||||
|
color: rgba(0, 0, 0, 0.45);
|
||||||
|
margin-top: 12px;
|
||||||
|
margin-bottom: 40px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.main {
|
||||||
|
min-width: 260px;
|
||||||
|
width: 368px;
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer {
|
||||||
|
position: absolute;
|
||||||
|
width: 100%;
|
||||||
|
bottom: 0;
|
||||||
|
padding: 0 16px;
|
||||||
|
margin: 48px 0 24px;
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
|
.links {
|
||||||
|
margin-bottom: 8px;
|
||||||
|
font-size: 14px;
|
||||||
|
a {
|
||||||
|
color: rgba(0, 0, 0, 0.45);
|
||||||
|
transition: all 0.3s;
|
||||||
|
&:not(:last-child) {
|
||||||
|
margin-right: 40px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.copyright {
|
||||||
|
color: rgba(0, 0, 0, 0.45);
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
8
ant-design-jeecg-vue/src/components/layouts/index.js
Normal file
8
ant-design-jeecg-vue/src/components/layouts/index.js
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
import UserLayout from '@/components/layouts/UserLayout'
|
||||||
|
import BlankLayout from '@/components/layouts/BlankLayout'
|
||||||
|
import BasicLayout from '@/components/layouts/BasicLayout'
|
||||||
|
import RouteView from '@/components/layouts/RouteView'
|
||||||
|
import PageView from '@/components/layouts/PageView'
|
||||||
|
import TabLayout from '@/components/layouts/TabLayout'
|
||||||
|
|
||||||
|
export { UserLayout, BasicLayout, BlankLayout, RouteView, PageView, TabLayout }
|
||||||
71
ant-design-jeecg-vue/src/components/menu/Contextmenu.vue
Normal file
71
ant-design-jeecg-vue/src/components/menu/Contextmenu.vue
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
<template>
|
||||||
|
<a-menu :style="style" class="contextmenu" v-show="visible" @click="handleClick" :selectedKeys="selectedKeys">
|
||||||
|
<a-menu-item :key="item.key" v-for="item in itemList">
|
||||||
|
<a-icon role="menuitemicon" v-if="item.icon" :type="item.icon" />{{ item.text }}
|
||||||
|
</a-menu-item>
|
||||||
|
</a-menu>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'Contextmenu',
|
||||||
|
props: {
|
||||||
|
visible: {
|
||||||
|
type: Boolean,
|
||||||
|
required: false,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
itemList: {
|
||||||
|
type: Array,
|
||||||
|
required: true,
|
||||||
|
default: () => []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
left: 0,
|
||||||
|
top: 0,
|
||||||
|
target: null,
|
||||||
|
selectedKeys: []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
style () {
|
||||||
|
return {
|
||||||
|
left: this.left + 'px',
|
||||||
|
top: this.top + 'px'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created () {
|
||||||
|
window.addEventListener('mousedown', e => this.closeMenu(e))
|
||||||
|
window.addEventListener('contextmenu', e => this.setPosition(e))
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
closeMenu (e) {
|
||||||
|
if (['menuitemicon', 'menuitem'].indexOf(e.target.getAttribute('role')) < 0) {
|
||||||
|
this.$emit('update:visible', false)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
setPosition (e) {
|
||||||
|
this.left = e.clientX
|
||||||
|
this.top = e.clientY
|
||||||
|
this.target = e.target
|
||||||
|
},
|
||||||
|
handleClick ({key}) {
|
||||||
|
this.$emit('select', key, this.target)
|
||||||
|
this.$emit('update:visible', false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
.contextmenu{
|
||||||
|
position: fixed;
|
||||||
|
z-index: 1;
|
||||||
|
border: 1px solid #9e9e9e;
|
||||||
|
border-radius: 4px;
|
||||||
|
box-shadow: 2px 2px 10px #aaaaaa !important;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
62
ant-design-jeecg-vue/src/components/menu/SideMenu.vue
Normal file
62
ant-design-jeecg-vue/src/components/menu/SideMenu.vue
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
<template>
|
||||||
|
<a-layout-sider
|
||||||
|
:class="['sider', isDesktop() ? null : 'shadow', theme, fixSiderbar ? 'ant-fixed-sidemenu' : null ]"
|
||||||
|
width="248px"
|
||||||
|
:collapsible="collapsible"
|
||||||
|
v-model="collapsed"
|
||||||
|
:trigger="null">
|
||||||
|
<logo />
|
||||||
|
<s-menu
|
||||||
|
:collapsed="collapsed"
|
||||||
|
:menu="menus"
|
||||||
|
:theme="theme"
|
||||||
|
@select="onSelect"
|
||||||
|
:mode="mode"
|
||||||
|
style="padding: 16px 0px;"></s-menu>
|
||||||
|
</a-layout-sider>
|
||||||
|
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import ALayoutSider from "ant-design-vue/es/layout/Sider"
|
||||||
|
import Logo from '../tools/Logo'
|
||||||
|
import SMenu from './index'
|
||||||
|
import { mixin, mixinDevice } from '@/utils/mixin.js'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "SideMenu",
|
||||||
|
components: { ALayoutSider, Logo, SMenu },
|
||||||
|
mixins: [mixin, mixinDevice],
|
||||||
|
props: {
|
||||||
|
mode: {
|
||||||
|
type: String,
|
||||||
|
required: false,
|
||||||
|
default: 'inline'
|
||||||
|
},
|
||||||
|
theme: {
|
||||||
|
type: String,
|
||||||
|
required: false,
|
||||||
|
default: 'dark'
|
||||||
|
},
|
||||||
|
collapsible: {
|
||||||
|
type: Boolean,
|
||||||
|
required: false,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
collapsed: {
|
||||||
|
type: Boolean,
|
||||||
|
required: false,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
menus: {
|
||||||
|
type: Array,
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
onSelect (obj) {
|
||||||
|
this.$emit('menuSelect', obj)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
162
ant-design-jeecg-vue/src/components/menu/index.js
Normal file
162
ant-design-jeecg-vue/src/components/menu/index.js
Normal file
@ -0,0 +1,162 @@
|
|||||||
|
import Menu from 'ant-design-vue/es/menu'
|
||||||
|
import Icon from 'ant-design-vue/es/icon'
|
||||||
|
|
||||||
|
const { Item, SubMenu } = Menu
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'SMenu',
|
||||||
|
props: {
|
||||||
|
menu: {
|
||||||
|
type: Array,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
theme: {
|
||||||
|
type: String,
|
||||||
|
required: false,
|
||||||
|
default: 'dark'
|
||||||
|
},
|
||||||
|
mode: {
|
||||||
|
type: String,
|
||||||
|
required: false,
|
||||||
|
default: 'inline'
|
||||||
|
},
|
||||||
|
collapsed: {
|
||||||
|
type: Boolean,
|
||||||
|
required: false,
|
||||||
|
default: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
openKeys: [],
|
||||||
|
selectedKeys: [],
|
||||||
|
cachedOpenKeys: []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
rootSubmenuKeys: (vm) => {
|
||||||
|
let keys = []
|
||||||
|
vm.menu.forEach(item => keys.push(item.path))
|
||||||
|
return keys
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created () {
|
||||||
|
this.updateMenu()
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
collapsed (val) {
|
||||||
|
if (val) {
|
||||||
|
this.cachedOpenKeys = this.openKeys
|
||||||
|
this.openKeys = []
|
||||||
|
} else {
|
||||||
|
this.openKeys = this.cachedOpenKeys
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'$route': function () {
|
||||||
|
this.updateMenu()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
renderIcon: function (h, icon) {
|
||||||
|
return icon === 'none' || icon === undefined ? null
|
||||||
|
: h(Icon, { props: { type: icon !== undefined ? icon : '' } })
|
||||||
|
},
|
||||||
|
renderMenuItem: function (h, menu, pIndex, index) {
|
||||||
|
return h(Item, { key: menu.path ? menu.path : 'item_' + pIndex + '_' + index },
|
||||||
|
[
|
||||||
|
h(
|
||||||
|
'router-link',
|
||||||
|
{ attrs: { to: { name: menu.name } } },
|
||||||
|
[
|
||||||
|
this.renderIcon(h, menu.meta.icon),
|
||||||
|
h('span', [ menu.meta.title ])
|
||||||
|
]
|
||||||
|
)
|
||||||
|
]
|
||||||
|
)
|
||||||
|
},
|
||||||
|
renderSubMenu: function (h, menu, pIndex, index) {
|
||||||
|
const this2_ = this;
|
||||||
|
let subItem = [ h('span',
|
||||||
|
{ slot: 'title' },
|
||||||
|
[
|
||||||
|
this.renderIcon(h, menu.meta.icon),
|
||||||
|
h('span', [ menu.meta.title ])
|
||||||
|
]
|
||||||
|
) ]
|
||||||
|
let itemArr = []
|
||||||
|
let pIndex_ = pIndex + '_' + index
|
||||||
|
if (!menu.alwaysShow) {
|
||||||
|
menu.children.forEach(function (item, i) {
|
||||||
|
itemArr.push(this2_.renderItem(h, item, pIndex_, i))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return h(
|
||||||
|
SubMenu,
|
||||||
|
{ key: menu.path ? menu.path : 'submenu_' + pIndex + '_' + index },
|
||||||
|
subItem.concat(itemArr)
|
||||||
|
)
|
||||||
|
},
|
||||||
|
renderItem: function (h, menu, pIndex, index) {
|
||||||
|
if (!menu.hidden) {
|
||||||
|
return menu.children && !menu.alwaysShow ? this.renderSubMenu(h, menu, pIndex, index) : this.renderMenuItem(h, menu, pIndex, index)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
renderMenu: function (h, menuTree) {
|
||||||
|
const this2_ = this
|
||||||
|
let menuArr = []
|
||||||
|
menuTree.forEach(function (menu, i) {
|
||||||
|
if (!menu.hidden) {
|
||||||
|
menuArr.push(this2_.renderItem(h, menu, '0', i))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return menuArr
|
||||||
|
},
|
||||||
|
onOpenChange (openKeys) {
|
||||||
|
const latestOpenKey = openKeys.find(key => this.openKeys.indexOf(key) === -1)
|
||||||
|
if (this.rootSubmenuKeys.indexOf(latestOpenKey) === -1) {
|
||||||
|
this.openKeys = openKeys
|
||||||
|
} else {
|
||||||
|
this.openKeys = latestOpenKey ? [ latestOpenKey ] : []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
updateMenu () {
|
||||||
|
let routes = this.$route.matched.concat()
|
||||||
|
if (routes.length >= 4 && this.$route.meta.hidden) {
|
||||||
|
routes.pop()
|
||||||
|
this.selectedKeys = [ routes[2].path ]
|
||||||
|
} else {
|
||||||
|
this.selectedKeys = [ routes.pop().path ]
|
||||||
|
}
|
||||||
|
|
||||||
|
let openKeys = []
|
||||||
|
if (this.mode === 'inline') {
|
||||||
|
routes.forEach((item) => {
|
||||||
|
openKeys.push(item.path)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
this.collapsed ? this.cachedOpenKeys = openKeys : this.openKeys = openKeys
|
||||||
|
}
|
||||||
|
},
|
||||||
|
render (h) {
|
||||||
|
return h(
|
||||||
|
Menu,
|
||||||
|
{
|
||||||
|
props: {
|
||||||
|
theme: this.$props.theme,
|
||||||
|
mode: this.$props.mode,
|
||||||
|
openKeys: this.openKeys,
|
||||||
|
selectedKeys: this.selectedKeys
|
||||||
|
},
|
||||||
|
on: {
|
||||||
|
openChange: this.onOpenChange,
|
||||||
|
select: (obj) => {
|
||||||
|
this.selectedKeys = obj.selectedKeys
|
||||||
|
this.$emit('select', obj)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, this.renderMenu(h, this.menu)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
51
ant-design-jeecg-vue/src/components/page/GlobalFooter.vue
Normal file
51
ant-design-jeecg-vue/src/components/page/GlobalFooter.vue
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
<template>
|
||||||
|
<div class="footer">
|
||||||
|
<div class="links">
|
||||||
|
<a href="http://www.jeecg.org" target="_blank">JEECG 首页</a>
|
||||||
|
<a href="https://github.com/zhangdaiscott/jeecg-boot" target="_blank">
|
||||||
|
<a-icon type="github"/>
|
||||||
|
</a>
|
||||||
|
<a href="https://ant.design/">Ant Design</a>
|
||||||
|
<a href="https://vuecomponent.github.io/ant-design-vue/docs/vue/introduce-cn/">Vue Antd</a>
|
||||||
|
</div>
|
||||||
|
<div class="copyright">
|
||||||
|
Copyright
|
||||||
|
<a-icon type="copyright"/>
|
||||||
|
2019 <span>JEECG开源社区 出品</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: "LayoutFooter"
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.footer {
|
||||||
|
padding: 0 16px;
|
||||||
|
margin: 48px 0 24px;
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
|
.links {
|
||||||
|
margin-bottom: 8px;
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: rgba(0, 0, 0, .45);
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: rgba(0, 0, 0, .65);
|
||||||
|
}
|
||||||
|
|
||||||
|
&:not(:last-child) {
|
||||||
|
margin-right: 40px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.copyright {
|
||||||
|
color: rgba(0, 0, 0, .45);
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
127
ant-design-jeecg-vue/src/components/page/GlobalHeader.vue
Normal file
127
ant-design-jeecg-vue/src/components/page/GlobalHeader.vue
Normal file
@ -0,0 +1,127 @@
|
|||||||
|
<template>
|
||||||
|
<!-- , width: fixedHeader ? `calc(100% - ${sidebarOpened ? 256 : 80}px)` : '100%' -->
|
||||||
|
<a-layout-header v-if="!headerBarFixed" :class="[fixedHeader && 'ant-header-fixedHeader', sidebarOpened ? 'ant-header-side-opened' : 'ant-header-side-closed', ]" :style="{ padding: '0' }">
|
||||||
|
<div v-if="mode === 'sidemenu'" class="header">
|
||||||
|
<a-icon
|
||||||
|
v-if="device==='mobile'"
|
||||||
|
class="trigger"
|
||||||
|
:type="collapsed ? 'menu-fold' : 'menu-unfold'"
|
||||||
|
@click.native="toggle"></a-icon>
|
||||||
|
<a-icon
|
||||||
|
v-else
|
||||||
|
class="trigger"
|
||||||
|
:type="collapsed ? 'menu-unfold' : 'menu-fold'"
|
||||||
|
@click.native="toggle"/>
|
||||||
|
<span>欢迎进入 Jeecg-Boot 企业级快速开发平台</span>
|
||||||
|
<user-menu></user-menu>
|
||||||
|
</div>
|
||||||
|
<div v-else :class="['top-nav-header-index', theme]">
|
||||||
|
<div class="header-index-wide">
|
||||||
|
<div class="header-index-left">
|
||||||
|
<logo class="top-nav-header" :show-title="device !== 'mobile'" />
|
||||||
|
<s-menu
|
||||||
|
v-if="device !== 'mobile'"
|
||||||
|
mode="horizontal"
|
||||||
|
:menu="menus"
|
||||||
|
:theme="theme"
|
||||||
|
></s-menu>
|
||||||
|
<a-icon
|
||||||
|
v-else
|
||||||
|
class="trigger"
|
||||||
|
:type="collapsed ? 'menu-fold' : 'menu-unfold'"
|
||||||
|
@click.native="toggle"></a-icon>
|
||||||
|
</div>
|
||||||
|
<user-menu class="header-index-right"></user-menu>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</a-layout-header>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import UserMenu from '../tools/UserMenu'
|
||||||
|
import SMenu from '../menu/'
|
||||||
|
import Logo from '../tools/Logo'
|
||||||
|
|
||||||
|
import { mixin } from '@/utils/mixin.js'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "GlobalHeader",
|
||||||
|
components: {
|
||||||
|
UserMenu,
|
||||||
|
SMenu,
|
||||||
|
Logo
|
||||||
|
},
|
||||||
|
mixins: [mixin],
|
||||||
|
props: {
|
||||||
|
mode: {
|
||||||
|
type: String,
|
||||||
|
// sidemenu, topmenu
|
||||||
|
default: 'sidemenu'
|
||||||
|
},
|
||||||
|
menus: {
|
||||||
|
type: Array,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
theme: {
|
||||||
|
type: String,
|
||||||
|
required: false,
|
||||||
|
default: 'dark'
|
||||||
|
},
|
||||||
|
collapsed: {
|
||||||
|
type: Boolean,
|
||||||
|
required: false,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
device: {
|
||||||
|
type: String,
|
||||||
|
required: false,
|
||||||
|
default: 'desktop'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
headerBarFixed: false,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted () {
|
||||||
|
window.addEventListener('scroll', this.handleScroll)
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
handleScroll () {
|
||||||
|
if (this.autoHideHeader) {
|
||||||
|
let scrollTop = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop
|
||||||
|
if (scrollTop > 100) {
|
||||||
|
this.headerBarFixed = true
|
||||||
|
} else {
|
||||||
|
this.headerBarFixed = false
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.headerBarFixed = false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
toggle() {
|
||||||
|
this.$emit('toggle')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
/* update_begin author:scott date:20190220 for: 缩小首页布局顶部的高度*/
|
||||||
|
.layout .top-nav-header-index .header-index-wide {
|
||||||
|
margin-left: 20px
|
||||||
|
}
|
||||||
|
.layout .header {
|
||||||
|
height: 59px;
|
||||||
|
}
|
||||||
|
.ant-layout-header {
|
||||||
|
height: 59px;
|
||||||
|
line-height: 59px;
|
||||||
|
}
|
||||||
|
.layout .top-nav-header-index .header-index-wide .ant-menu.ant-menu-horizontal {
|
||||||
|
height: 59px;
|
||||||
|
line-height: 59px;
|
||||||
|
}
|
||||||
|
/* update_end author:scott date:20190220 for: 缩小首页布局顶部的高度*/
|
||||||
|
</style>
|
||||||
596
ant-design-jeecg-vue/src/components/page/GlobalLayout.vue
Normal file
596
ant-design-jeecg-vue/src/components/page/GlobalLayout.vue
Normal file
@ -0,0 +1,596 @@
|
|||||||
|
<template>
|
||||||
|
<a-layout class="layout" :class="[device]">
|
||||||
|
|
||||||
|
<template v-if="layoutMode === 'sidemenu'">
|
||||||
|
<a-drawer
|
||||||
|
v-if="device === 'mobile'"
|
||||||
|
:wrapClassName="'drawer-sider ' + navTheme"
|
||||||
|
placement="left"
|
||||||
|
@close="() => this.collapsed = false"
|
||||||
|
:closable="false"
|
||||||
|
:visible="collapsed"
|
||||||
|
>
|
||||||
|
<side-menu
|
||||||
|
mode="inline"
|
||||||
|
:menus="menus"
|
||||||
|
@menuSelect="menuSelect"
|
||||||
|
:theme="navTheme"
|
||||||
|
:collapsed="false"
|
||||||
|
:collapsible="true"></side-menu>
|
||||||
|
</a-drawer>
|
||||||
|
|
||||||
|
<side-menu
|
||||||
|
v-else
|
||||||
|
mode="inline"
|
||||||
|
:menus="menus"
|
||||||
|
:theme="navTheme"
|
||||||
|
:collapsed="collapsed"
|
||||||
|
:collapsible="true"></side-menu>
|
||||||
|
</template>
|
||||||
|
<!-- 下次优化这些代码 -->
|
||||||
|
<template v-else>
|
||||||
|
<a-drawer
|
||||||
|
v-if="device === 'mobile'"
|
||||||
|
:wrapClassName="'drawer-sider ' + navTheme"
|
||||||
|
placement="left"
|
||||||
|
@close="() => this.collapsed = false"
|
||||||
|
:closable="false"
|
||||||
|
:visible="collapsed"
|
||||||
|
>
|
||||||
|
<side-menu
|
||||||
|
mode="inline"
|
||||||
|
:menus="menus"
|
||||||
|
@menuSelect="menuSelect"
|
||||||
|
:theme="navTheme"
|
||||||
|
:collapsed="false"
|
||||||
|
:collapsible="true"></side-menu>
|
||||||
|
</a-drawer>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<a-layout :class="[layoutMode, `content-width-${contentWidth}`]" :style="{ paddingLeft: fixSiderbar && isDesktop() ? `${sidebarOpened ? 256 : 80}px` : '0' }">
|
||||||
|
<!-- layout header -->
|
||||||
|
<global-header
|
||||||
|
:mode="layoutMode"
|
||||||
|
:menus="menus"
|
||||||
|
:theme="navTheme"
|
||||||
|
:collapsed="collapsed"
|
||||||
|
:device="device"
|
||||||
|
@toggle="toggle"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<!-- layout content -->
|
||||||
|
<a-layout-content :style="{ margin: '10px 24px 0', height: '100%', paddingTop: fixedHeader ? '64px' : '0' }">
|
||||||
|
<slot></slot>
|
||||||
|
</a-layout-content>
|
||||||
|
|
||||||
|
<!-- layout footer -->
|
||||||
|
<a-layout-footer style="padding: 0px">
|
||||||
|
<global-footer />
|
||||||
|
</a-layout-footer>
|
||||||
|
</a-layout>
|
||||||
|
|
||||||
|
<setting-drawer></setting-drawer>
|
||||||
|
</a-layout>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import SideMenu from '@/components/menu/SideMenu'
|
||||||
|
import GlobalHeader from '@/components/page/GlobalHeader'
|
||||||
|
import GlobalFooter from '@/components/page/GlobalFooter'
|
||||||
|
import SettingDrawer from '@/components/setting/SettingDrawer'
|
||||||
|
import { triggerWindowResizeEvent } from '@/utils/util'
|
||||||
|
import { mapState, mapActions } from 'vuex'
|
||||||
|
import { mixin, mixinDevice } from '@/utils/mixin.js'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "GlobalLayout",
|
||||||
|
components: {
|
||||||
|
SideMenu,
|
||||||
|
GlobalHeader,
|
||||||
|
GlobalFooter,
|
||||||
|
SettingDrawer
|
||||||
|
},
|
||||||
|
mixins: [mixin, mixinDevice],
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
collapsed: false,
|
||||||
|
menus: []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
...mapState({
|
||||||
|
// 主路由
|
||||||
|
mainMenu: state => state.permission.addRouters,
|
||||||
|
})
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
sidebarOpened(val) {
|
||||||
|
this.collapsed = !val
|
||||||
|
},
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
this.menus = this.mainMenu.find((item) => item.path === '/').children
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
...mapActions(['setSidebar']),
|
||||||
|
toggle() {
|
||||||
|
this.collapsed = !this.collapsed
|
||||||
|
this.setSidebar(!this.collapsed)
|
||||||
|
triggerWindowResizeEvent()
|
||||||
|
},
|
||||||
|
menuSelect() {
|
||||||
|
if (!this.isDesktop()) {
|
||||||
|
this.collapsed = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
body {
|
||||||
|
// 打开滚动条固定显示
|
||||||
|
overflow-y: scroll;
|
||||||
|
|
||||||
|
&.colorWeak {
|
||||||
|
filter: invert(80%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.layout {
|
||||||
|
min-height: 100vh;
|
||||||
|
overflow-x: hidden;
|
||||||
|
|
||||||
|
&.mobile {
|
||||||
|
|
||||||
|
.ant-layout-content {
|
||||||
|
|
||||||
|
.content {
|
||||||
|
margin: 24px 0 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ant-table-wrapper
|
||||||
|
* 覆盖的表格手机模式样式,如果想修改在手机上表格最低宽度,可以在这里改动
|
||||||
|
*/
|
||||||
|
.ant-table-wrapper {
|
||||||
|
.ant-table-content {
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
.ant-table-body {
|
||||||
|
min-width: 800px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.sidemenu {
|
||||||
|
.ant-header-fixedHeader {
|
||||||
|
|
||||||
|
&.ant-header-side-opened, &.ant-header-side-closed {
|
||||||
|
width: 100%
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.topmenu {
|
||||||
|
/* 必须为 topmenu 才能启用流式布局 */
|
||||||
|
&.content-width-Fluid {
|
||||||
|
.header-index-wide {
|
||||||
|
margin-left: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.ant-layout-has-sider {
|
||||||
|
flex-direction: row;
|
||||||
|
}
|
||||||
|
|
||||||
|
.trigger {
|
||||||
|
font-size: 20px;
|
||||||
|
line-height: 64px;
|
||||||
|
padding: 0 24px;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: color .3s;
|
||||||
|
&:hover {
|
||||||
|
background: rgba(0, 0, 0, 0.025);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.topmenu {
|
||||||
|
.ant-header-fixedHeader {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
z-index: 9;
|
||||||
|
width: 100%;
|
||||||
|
transition: width .2s;
|
||||||
|
|
||||||
|
&.ant-header-side-opened {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.ant-header-side-closed {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* 必须为 topmenu 才能启用流式布局 */
|
||||||
|
&.content-width-Fluid {
|
||||||
|
.header-index-wide {
|
||||||
|
max-width: unset;
|
||||||
|
margin-left: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-header-index-wide {
|
||||||
|
max-width: unset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidemenu {
|
||||||
|
.ant-header-fixedHeader {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
z-index: 9;
|
||||||
|
width: 100%;
|
||||||
|
transition: width .2s;
|
||||||
|
|
||||||
|
&.ant-header-side-opened {
|
||||||
|
width: calc(100% - 256px)
|
||||||
|
}
|
||||||
|
|
||||||
|
&.ant-header-side-closed {
|
||||||
|
width: calc(100% - 80px)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.header {
|
||||||
|
height: 64px;
|
||||||
|
padding: 0 12px 0 0;
|
||||||
|
background: #fff;
|
||||||
|
box-shadow: 0 1px 4px rgba(0, 21, 41, .08);
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header, .top-nav-header-index {
|
||||||
|
|
||||||
|
.user-wrapper {
|
||||||
|
float: right;
|
||||||
|
height: 100%;
|
||||||
|
|
||||||
|
.action {
|
||||||
|
cursor: pointer;
|
||||||
|
padding: 0 12px;
|
||||||
|
display: inline-block;
|
||||||
|
transition: all .3s;
|
||||||
|
height: 100%;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: rgba(0, 0, 0, 0.025);
|
||||||
|
}
|
||||||
|
|
||||||
|
.avatar {
|
||||||
|
margin: 20px 8px 20px 0;
|
||||||
|
color: #1890ff;
|
||||||
|
background: hsla(0, 0%, 100%, .85);
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
font-size: 16px;
|
||||||
|
padding: 4px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.dark {
|
||||||
|
.user-wrapper {
|
||||||
|
|
||||||
|
.action {
|
||||||
|
color: rgba(255, 255, 255, 0.85);
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: rgba(255, 255, 255, 0.16);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.mobile {
|
||||||
|
.top-nav-header-index {
|
||||||
|
|
||||||
|
.header-index-wide {
|
||||||
|
|
||||||
|
.header-index-left {
|
||||||
|
|
||||||
|
.trigger {
|
||||||
|
color: rgba(255, 255, 255, 0.85);
|
||||||
|
padding: 0 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo.top-nav-header {
|
||||||
|
text-align: center;
|
||||||
|
width: 56px;
|
||||||
|
line-height: 58px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.light {
|
||||||
|
|
||||||
|
.header-index-wide {
|
||||||
|
|
||||||
|
.header-index-left {
|
||||||
|
.trigger {
|
||||||
|
color: rgba(0, 0, 0, 0.65);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.tablet {
|
||||||
|
// overflow: hidden; text-overflow:ellipsis; white-space: nowrap;
|
||||||
|
.top-nav-header-index {
|
||||||
|
|
||||||
|
.header-index-wide {
|
||||||
|
|
||||||
|
.header-index-left {
|
||||||
|
.logo > a {
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow:ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.top-nav-header-index {
|
||||||
|
box-shadow: 0 1px 4px rgba(0,21,41,.08);
|
||||||
|
position: relative;
|
||||||
|
transition: background .3s,width .2s;
|
||||||
|
|
||||||
|
.header-index-wide {
|
||||||
|
max-width: 1200px;
|
||||||
|
margin: auto;
|
||||||
|
padding-left: 0;
|
||||||
|
display: flex;
|
||||||
|
height: 64px;
|
||||||
|
|
||||||
|
.ant-menu.ant-menu-horizontal {
|
||||||
|
border: none;
|
||||||
|
height: 64px;
|
||||||
|
line-height: 64px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-index-left {
|
||||||
|
flex: 1 1;
|
||||||
|
display: flex;
|
||||||
|
|
||||||
|
.logo.top-nav-header {
|
||||||
|
width: 165px;
|
||||||
|
height: 64px;
|
||||||
|
position: relative;
|
||||||
|
line-height: 64px;
|
||||||
|
transition: all .3s;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
img {
|
||||||
|
display: inline-block;
|
||||||
|
vertical-align: middle;
|
||||||
|
height: 32px;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
color: #fff;
|
||||||
|
display: inline-block;
|
||||||
|
vertical-align: top;
|
||||||
|
font-size: 16px;
|
||||||
|
margin: 0 0 0 12px;
|
||||||
|
font-weight: 400;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-index-right {
|
||||||
|
float: right;
|
||||||
|
height: 64px;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.light {
|
||||||
|
background-color: #fff;
|
||||||
|
|
||||||
|
.header-index-wide {
|
||||||
|
.header-index-left {
|
||||||
|
.logo {
|
||||||
|
h1 {
|
||||||
|
color: #002140;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 内容区
|
||||||
|
.layout-content {
|
||||||
|
margin: 24px 24px 0px;
|
||||||
|
height: 100%;
|
||||||
|
height: 64px;
|
||||||
|
padding: 0 12px 0 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.topmenu {
|
||||||
|
.page-header-index-wide {
|
||||||
|
max-width: 1200px;
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// drawer-sider 自定义
|
||||||
|
.ant-drawer.drawer-sider {
|
||||||
|
.sider {
|
||||||
|
box-shadow: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.dark {
|
||||||
|
.ant-drawer-content {
|
||||||
|
background-color: rgb(0, 21, 41);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&.light {
|
||||||
|
box-shadow: none;
|
||||||
|
.ant-drawer-content {
|
||||||
|
background-color: #fff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-drawer-body {
|
||||||
|
padding: 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 菜单样式
|
||||||
|
.sider {
|
||||||
|
box-shadow: 2px 0 6px rgba(0, 21, 41, .35);
|
||||||
|
position: relative;
|
||||||
|
z-index: 10;
|
||||||
|
|
||||||
|
&.ant-fixed-sidemenu {
|
||||||
|
position: fixed;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo {
|
||||||
|
height: 64px;
|
||||||
|
position: relative;
|
||||||
|
line-height: 64px;
|
||||||
|
padding-left: 24px;
|
||||||
|
-webkit-transition: all .3s;
|
||||||
|
transition: all .3s;
|
||||||
|
background: #002140;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
img, h1 {
|
||||||
|
display: inline-block;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
|
||||||
|
img {
|
||||||
|
height: 32px;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
color: #fff;
|
||||||
|
font-size: 20px;
|
||||||
|
margin: 0 0 0 12px;
|
||||||
|
font-family: "Chinese Quote", -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "Helvetica Neue", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.light {
|
||||||
|
background-color: #fff;
|
||||||
|
box-shadow: 2px 0px 8px 0px rgba(29, 35, 41, 0.05);
|
||||||
|
|
||||||
|
.logo {
|
||||||
|
background: #fff;
|
||||||
|
box-shadow: 1px 1px 0px 0px #e8e8e8;
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
color: unset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-menu-light {
|
||||||
|
border-right-color: transparent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// 外置的样式控制
|
||||||
|
.user-dropdown-menu-wrapper.ant-dropdown-menu {
|
||||||
|
padding: 4px 0;
|
||||||
|
|
||||||
|
.ant-dropdown-menu-item {
|
||||||
|
width: 160px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-dropdown-menu-item > .anticon:first-child,
|
||||||
|
.ant-dropdown-menu-item > a > .anticon:first-child,
|
||||||
|
.ant-dropdown-menu-submenu-title > .anticon:first-child
|
||||||
|
.ant-dropdown-menu-submenu-title > a > .anticon:first-child {
|
||||||
|
min-width: 12px;
|
||||||
|
margin-right: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// 数据列表 样式
|
||||||
|
.table-alert {
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-page-search-wrapper {
|
||||||
|
|
||||||
|
.ant-form-inline {
|
||||||
|
|
||||||
|
.ant-form-item {
|
||||||
|
display: flex;
|
||||||
|
margin-bottom: 24px;
|
||||||
|
margin-right: 0;
|
||||||
|
|
||||||
|
.ant-form-item-control-wrapper {
|
||||||
|
flex: 1 1;
|
||||||
|
display: inline-block;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
|
||||||
|
>.ant-form-item-label {
|
||||||
|
line-height: 32px;
|
||||||
|
padding-right: 8px;
|
||||||
|
width: auto;
|
||||||
|
}
|
||||||
|
.ant-form-item-control {
|
||||||
|
height: 32px;
|
||||||
|
line-height: 32px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-page-search-submitButtons {
|
||||||
|
display: block;
|
||||||
|
margin-bottom: 24px;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.content {
|
||||||
|
|
||||||
|
.table-operator {
|
||||||
|
margin-bottom: 18px;
|
||||||
|
|
||||||
|
button {
|
||||||
|
margin-right: 8px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
238
ant-design-jeecg-vue/src/components/page/PageHeader.vue
Normal file
238
ant-design-jeecg-vue/src/components/page/PageHeader.vue
Normal file
@ -0,0 +1,238 @@
|
|||||||
|
<template>
|
||||||
|
<div class="page-header">
|
||||||
|
<div class="page-header-index-wide">
|
||||||
|
<a-breadcrumb class="breadcrumb">
|
||||||
|
<a-breadcrumb-item v-for="(item, index) in breadList" :key="index">
|
||||||
|
<router-link v-if="item.name != name" :to="{ path: item.path }">
|
||||||
|
{{ item.meta.title }}
|
||||||
|
</router-link>
|
||||||
|
<span v-else>{{ item.meta.title }}</span>
|
||||||
|
</a-breadcrumb-item>
|
||||||
|
</a-breadcrumb>
|
||||||
|
|
||||||
|
<div class="detail">
|
||||||
|
<div class="main" v-if="!$route.meta.hiddenHeaderContent">
|
||||||
|
<div class="row">
|
||||||
|
<img v-if="logo" :src="logo" class="logo"/>
|
||||||
|
<h1 v-if="title" class="title">{{ title }}</h1>
|
||||||
|
<div class="action">
|
||||||
|
<slot name="action"></slot>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div v-if="avatar" class="avatar">
|
||||||
|
<a-avatar :src="avatar"/>
|
||||||
|
</div>
|
||||||
|
<div v-if="this.$slots.content" class="headerContent">
|
||||||
|
<slot name="content"></slot>
|
||||||
|
</div>
|
||||||
|
<div v-if="this.$slots.extra" class="extra">
|
||||||
|
<slot name="extra"></slot>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<slot name="pageMenu"></slot>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import Breadcrumb from '@/components/tools/Breadcrumb'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "PageHeader",
|
||||||
|
components: {
|
||||||
|
"s-breadcrumb": Breadcrumb
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
title: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
required: false
|
||||||
|
},
|
||||||
|
breadcrumb: {
|
||||||
|
type: Array,
|
||||||
|
default: null,
|
||||||
|
required: false
|
||||||
|
},
|
||||||
|
logo: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
required: false
|
||||||
|
},
|
||||||
|
avatar: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
required: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
name: '',
|
||||||
|
breadList: [],
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
this.getBreadcrumb()
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
getBreadcrumb() {
|
||||||
|
|
||||||
|
this.breadList = []
|
||||||
|
// this.breadList.push({name: 'index', path: '/dashboard/', meta: {title: '首页'}})
|
||||||
|
|
||||||
|
this.name = this.$route.name
|
||||||
|
this.$route.matched.forEach((item) => {
|
||||||
|
// item.name !== 'index' && this.breadList.push(item)
|
||||||
|
this.breadList.push(item)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
$route() {
|
||||||
|
this.getBreadcrumb()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
|
||||||
|
.page-header {
|
||||||
|
background: #fff;
|
||||||
|
padding: 16px 32px 0;
|
||||||
|
border-bottom: 1px solid #e8e8e8;
|
||||||
|
|
||||||
|
.breadcrumb {
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail {
|
||||||
|
display: flex;
|
||||||
|
/*margin-bottom: 16px;*/
|
||||||
|
|
||||||
|
.avatar {
|
||||||
|
flex: 0 1 72px;
|
||||||
|
margin: 0 24px 8px 0;
|
||||||
|
|
||||||
|
& > span {
|
||||||
|
border-radius: 72px;
|
||||||
|
display: block;
|
||||||
|
width: 72px;
|
||||||
|
height: 72px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.main {
|
||||||
|
width: 100%;
|
||||||
|
flex: 0 1 auto;
|
||||||
|
|
||||||
|
.row {
|
||||||
|
display: flex;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
.avatar {
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.title {
|
||||||
|
font-size: 20px;
|
||||||
|
font-weight: 500;
|
||||||
|
|
||||||
|
font-size: 20px;
|
||||||
|
line-height: 28px;
|
||||||
|
font-weight: 500;
|
||||||
|
color: rgba(0,0,0,.85);
|
||||||
|
margin-bottom: 16px;
|
||||||
|
flex: auto;
|
||||||
|
|
||||||
|
}
|
||||||
|
.logo {
|
||||||
|
width: 28px;
|
||||||
|
height: 28px;
|
||||||
|
border-radius: 4px;
|
||||||
|
margin-right: 16px;
|
||||||
|
}
|
||||||
|
.content, .headerContent {
|
||||||
|
flex: auto;
|
||||||
|
color: rgba(0,0,0,.45);
|
||||||
|
line-height: 22px;
|
||||||
|
|
||||||
|
.link {
|
||||||
|
margin-top: 16px;
|
||||||
|
line-height: 24px;
|
||||||
|
|
||||||
|
a {
|
||||||
|
font-size: 14px;
|
||||||
|
margin-right: 32px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.extra {
|
||||||
|
flex: 0 1 auto;
|
||||||
|
margin-left: 88px;
|
||||||
|
min-width: 242px;
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
.action {
|
||||||
|
margin-left: 56px;
|
||||||
|
min-width: 266px;
|
||||||
|
flex: 0 1 auto;
|
||||||
|
text-align: right;
|
||||||
|
&:empty {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.mobile .page-header {
|
||||||
|
|
||||||
|
.main {
|
||||||
|
|
||||||
|
.row {
|
||||||
|
flex-wrap: wrap;
|
||||||
|
|
||||||
|
.avatar {
|
||||||
|
flex: 0 1 25%;
|
||||||
|
margin: 0 2% 8px 0;
|
||||||
|
}
|
||||||
|
.content, .headerContent {
|
||||||
|
flex: 0 1 70%;
|
||||||
|
|
||||||
|
.link {
|
||||||
|
margin-top: 16px;
|
||||||
|
line-height: 24px;
|
||||||
|
|
||||||
|
a {
|
||||||
|
font-size: 14px;
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.extra {
|
||||||
|
flex: 1 1 auto;
|
||||||
|
margin-left: 0;
|
||||||
|
min-width: 0;
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
.action {
|
||||||
|
margin-left: unset;
|
||||||
|
min-width: 266px;
|
||||||
|
flex: 0 1 auto;
|
||||||
|
text-align: left;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
&:empty {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
127
ant-design-jeecg-vue/src/components/page/PageLayout.vue
Normal file
127
ant-design-jeecg-vue/src/components/page/PageLayout.vue
Normal file
@ -0,0 +1,127 @@
|
|||||||
|
<template>
|
||||||
|
<div :style="!$route.meta.pageHeader ? 'margin: -16px -24px 0px;' : null">
|
||||||
|
<!-- pageHeader , route meta hideHeader:true on hide -->
|
||||||
|
<page-header v-if="!$route.meta.pageHeader" :title="title" :logo="logo" :avatar="avatar">
|
||||||
|
<slot slot="action" name="action"></slot>
|
||||||
|
<slot slot="content" name="headerContent"></slot>
|
||||||
|
<div slot="content" v-if="!this.$slots.headerContent && desc">
|
||||||
|
<p style="font-size: 14px;color: rgba(0,0,0,.65)">{{ desc }}</p>
|
||||||
|
<div class="link">
|
||||||
|
<template v-for="(link, index) in linkList">
|
||||||
|
<a :key="index" :href="link.href">
|
||||||
|
<a-icon :type="link.icon"/>
|
||||||
|
<span>{{ link.title }}</span>
|
||||||
|
</a>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<slot slot="extra" name="extra"></slot>
|
||||||
|
<div slot="pageMenu">
|
||||||
|
<div class="page-menu-search" v-if="search">
|
||||||
|
<a-input-search style="width: 80%; max-width: 522px;" placeholder="请输入..." size="large" enterButton="搜索" />
|
||||||
|
</div>
|
||||||
|
<div class="page-menu-tabs" v-if="tabs && tabs.items">
|
||||||
|
<!-- @change="callback" :activeKey="activeKey" -->
|
||||||
|
<a-tabs :tabBarStyle="{margin: 0}" @change="tabs.callback" :activeKey="tabs.active()">
|
||||||
|
<a-tab-pane v-for="item in tabs.items" :tab="item.title" :key="item.key"></a-tab-pane>
|
||||||
|
</a-tabs>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</page-header>
|
||||||
|
<div class="content">
|
||||||
|
<div :class="['page-header-index-wide']">
|
||||||
|
<slot></slot>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import PageHeader from './PageHeader'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "LayoutContent",
|
||||||
|
components: {
|
||||||
|
PageHeader
|
||||||
|
},
|
||||||
|
// ['desc', 'logo', 'title', 'avatar', 'linkList', 'extraImage']
|
||||||
|
props: {
|
||||||
|
desc: {
|
||||||
|
type: String,
|
||||||
|
default: null
|
||||||
|
},
|
||||||
|
logo: {
|
||||||
|
type: String,
|
||||||
|
default: null
|
||||||
|
},
|
||||||
|
title: {
|
||||||
|
type: String,
|
||||||
|
default: null
|
||||||
|
},
|
||||||
|
avatar: {
|
||||||
|
type: String,
|
||||||
|
default: null
|
||||||
|
},
|
||||||
|
linkList: {
|
||||||
|
type: Array,
|
||||||
|
default: null
|
||||||
|
},
|
||||||
|
extraImage: {
|
||||||
|
type: String,
|
||||||
|
default: null
|
||||||
|
},
|
||||||
|
search: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
tabs: {
|
||||||
|
type: Object,
|
||||||
|
default: () => {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.content {
|
||||||
|
margin: 24px 24px 0;
|
||||||
|
|
||||||
|
.link {
|
||||||
|
margin-top: 16px;
|
||||||
|
|
||||||
|
&:not(:empty) {
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
a {
|
||||||
|
margin-right: 32px;
|
||||||
|
height: 24px;
|
||||||
|
line-height: 24px;
|
||||||
|
display: inline-block;
|
||||||
|
|
||||||
|
i {
|
||||||
|
font-size: 24px;
|
||||||
|
margin-right: 8px;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
span {
|
||||||
|
height: 24px;
|
||||||
|
line-height: 24px;
|
||||||
|
display: inline-block;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.page-menu-search {
|
||||||
|
text-align: center;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
.page-menu-tabs {
|
||||||
|
margin-top: 48px;
|
||||||
|
}
|
||||||
|
.page-header[data-v-6740ec88] {
|
||||||
|
margin: 0px 24px 0;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
58
ant-design-jeecg-vue/src/components/page/SHeaderNotice.vue
Normal file
58
ant-design-jeecg-vue/src/components/page/SHeaderNotice.vue
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
<template>
|
||||||
|
<a-popover trigger="click" placement="bottomRight" :overlayStyle="{ width: '300px' }">
|
||||||
|
<template slot="content">
|
||||||
|
<a-spin :spinning="loadding">
|
||||||
|
<a-tabs>
|
||||||
|
<a-tab-pane v-for="(tab, k) in tabs" :tab="tab.title" :key="k">
|
||||||
|
|
||||||
|
</a-tab-pane>
|
||||||
|
</a-tabs>
|
||||||
|
</a-spin>
|
||||||
|
</template>
|
||||||
|
<span @click="fetchNotice" class="header-notice">
|
||||||
|
<a-badge count="12">
|
||||||
|
<a-icon style="font-size: 16px; padding: 4px" type="bell" />
|
||||||
|
</a-badge>
|
||||||
|
</span>
|
||||||
|
</a-popover>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: "HeaderNotice",
|
||||||
|
props: {
|
||||||
|
tabs: {
|
||||||
|
type: Array,
|
||||||
|
default: null,
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
loadding: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
fetchNotice () {
|
||||||
|
if (this.loadding) {
|
||||||
|
this.loadding = false
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.loadding = true
|
||||||
|
setTimeout(() => {
|
||||||
|
this.loadding = false
|
||||||
|
}, 2000)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.header-notice{
|
||||||
|
display: inline-block;
|
||||||
|
transition: all 0.3s;
|
||||||
|
span {
|
||||||
|
vertical-align: initial;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
314
ant-design-jeecg-vue/src/components/setting/SettingDrawer.vue
Normal file
314
ant-design-jeecg-vue/src/components/setting/SettingDrawer.vue
Normal file
@ -0,0 +1,314 @@
|
|||||||
|
<template>
|
||||||
|
<div class="setting-drawer">
|
||||||
|
<a-drawer
|
||||||
|
width="300"
|
||||||
|
placement="right"
|
||||||
|
:closable="false"
|
||||||
|
@close="onClose"
|
||||||
|
:visible="visible"
|
||||||
|
:style="{}"
|
||||||
|
>
|
||||||
|
<div class="setting-drawer-index-content">
|
||||||
|
|
||||||
|
<div :style="{ marginBottom: '24px' }">
|
||||||
|
<h3 class="setting-drawer-index-title">整体风格设置</h3>
|
||||||
|
|
||||||
|
<div class="setting-drawer-index-blockChecbox">
|
||||||
|
<a-tooltip>
|
||||||
|
<template slot="title">
|
||||||
|
暗色菜单风格
|
||||||
|
</template>
|
||||||
|
<div class="setting-drawer-index-item" @click="handleMenuTheme('dark')">
|
||||||
|
<img src="https://gw.alipayobjects.com/zos/rmsportal/LCkqqYNmvBEbokSDscrm.svg" alt="dark">
|
||||||
|
<div class="setting-drawer-index-selectIcon" v-if="navTheme === 'dark'">
|
||||||
|
<a-icon type="check"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</a-tooltip>
|
||||||
|
|
||||||
|
<a-tooltip>
|
||||||
|
<template slot="title">
|
||||||
|
亮色菜单风格
|
||||||
|
</template>
|
||||||
|
<div class="setting-drawer-index-item" @click="handleMenuTheme('light')">
|
||||||
|
<img src="https://gw.alipayobjects.com/zos/rmsportal/jpRkZQMyYRryryPNtyIC.svg" alt="light">
|
||||||
|
<div class="setting-drawer-index-selectIcon" v-if="navTheme !== 'dark'">
|
||||||
|
<a-icon type="check"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</a-tooltip>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div :style="{ marginBottom: '24px' }">
|
||||||
|
<h3 class="setting-drawer-index-title">主题色</h3>
|
||||||
|
|
||||||
|
<div style="height: 20px">
|
||||||
|
<a-tooltip class="setting-drawer-theme-color-colorBlock" v-for="(item, index) in colorList" :key="index">
|
||||||
|
<template slot="title">
|
||||||
|
{{ item.key }}
|
||||||
|
</template>
|
||||||
|
<a-tag :color="item.color" @click="changeColor(item.color)">
|
||||||
|
<a-icon type="check" v-if="item.color === primaryColor"></a-icon>
|
||||||
|
</a-tag>
|
||||||
|
</a-tooltip>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<a-divider />
|
||||||
|
|
||||||
|
<div :style="{ marginBottom: '24px' }">
|
||||||
|
<h3 class="setting-drawer-index-title">导航模式</h3>
|
||||||
|
|
||||||
|
<div class="setting-drawer-index-blockChecbox">
|
||||||
|
<a-tooltip>
|
||||||
|
<template slot="title">
|
||||||
|
侧边栏导航
|
||||||
|
</template>
|
||||||
|
<div class="setting-drawer-index-item" @click="handleLayout('sidemenu')">
|
||||||
|
<img src="https://gw.alipayobjects.com/zos/rmsportal/JopDzEhOqwOjeNTXkoje.svg" alt="sidemenu">
|
||||||
|
<div class="setting-drawer-index-selectIcon" v-if="layoutMode === 'sidemenu'">
|
||||||
|
<a-icon type="check"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</a-tooltip>
|
||||||
|
|
||||||
|
<a-tooltip>
|
||||||
|
<template slot="title">
|
||||||
|
顶部栏导航
|
||||||
|
</template>
|
||||||
|
<div class="setting-drawer-index-item" @click="handleLayout('topmenu')">
|
||||||
|
<img src="https://gw.alipayobjects.com/zos/rmsportal/KDNDBbriJhLwuqMoxcAr.svg" alt="topmenu">
|
||||||
|
<div class="setting-drawer-index-selectIcon" v-if="layoutMode !== 'sidemenu'">
|
||||||
|
<a-icon type="check"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</a-tooltip>
|
||||||
|
</div>
|
||||||
|
<div :style="{ marginTop: '24px' }">
|
||||||
|
<a-list :split="false">
|
||||||
|
<a-list-item>
|
||||||
|
<a-tooltip slot="actions">
|
||||||
|
<template slot="title">
|
||||||
|
该设定仅 [顶部栏导航] 时有效
|
||||||
|
</template>
|
||||||
|
<a-select size="small" style="width: 80px;" :defaultValue="contentWidth" @change="handleContentWidthChange">
|
||||||
|
<a-select-option value="Fixed">固定</a-select-option>
|
||||||
|
<a-select-option value="Fluid" v-if="layoutMode !== 'sidemenu'">流式</a-select-option>
|
||||||
|
</a-select>
|
||||||
|
</a-tooltip>
|
||||||
|
<a-list-item-meta>
|
||||||
|
<div slot="title">内容区域宽度</div>
|
||||||
|
</a-list-item-meta>
|
||||||
|
</a-list-item>
|
||||||
|
<a-list-item>
|
||||||
|
<a-switch slot="actions" size="small" :defaultChecked="fixedHeader" @change="handleFixedHeader" />
|
||||||
|
<a-list-item-meta>
|
||||||
|
<div slot="title">固定 Header</div>
|
||||||
|
</a-list-item-meta>
|
||||||
|
</a-list-item>
|
||||||
|
<a-list-item>
|
||||||
|
<a-switch slot="actions" size="small" :disabled="!fixedHeader" :defaultChecked="autoHideHeader" @change="handleFixedHeaderHidden" />
|
||||||
|
<a-list-item-meta>
|
||||||
|
<div slot="title" :style="{ textDecoration: !fixedHeader ? 'line-through' : 'unset' }">下滑时隐藏 Header</div>
|
||||||
|
</a-list-item-meta>
|
||||||
|
</a-list-item>
|
||||||
|
<a-list-item >
|
||||||
|
<a-switch slot="actions" size="small" :disabled="(layoutMode === 'topmenu')" :defaultChecked="fixSiderbar" @change="handleFixSiderbar" />
|
||||||
|
<a-list-item-meta>
|
||||||
|
<div slot="title" :style="{ textDecoration: layoutMode === 'topmenu' ? 'line-through' : 'unset' }">固定侧边菜单</div>
|
||||||
|
</a-list-item-meta>
|
||||||
|
</a-list-item>
|
||||||
|
</a-list>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<a-divider />
|
||||||
|
|
||||||
|
<div :style="{ marginBottom: '24px' }">
|
||||||
|
<h3 class="setting-drawer-index-title">其他设置</h3>
|
||||||
|
<div>
|
||||||
|
<a-list :split="false">
|
||||||
|
<a-list-item>
|
||||||
|
<a-switch slot="actions" size="small" :defaultChecked="colorWeak" @change="onColorWeak" />
|
||||||
|
<a-list-item-meta>
|
||||||
|
<div slot="title">色弱模式</div>
|
||||||
|
</a-list-item-meta>
|
||||||
|
</a-list-item>
|
||||||
|
</a-list>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<a-divider />
|
||||||
|
<div :style="{ marginBottom: '24px' }">
|
||||||
|
<a-alert type="warning">
|
||||||
|
<span slot="message">
|
||||||
|
配置栏只在开发环境用于预览,生产环境不会展现,请手动修改配置文件
|
||||||
|
<a href="https://github.com/sendya/ant-design-pro-vue/blob/master/src/defaultSettings.js" target="_blank">src/defaultSettings.js</a>
|
||||||
|
</span>
|
||||||
|
</a-alert>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="setting-drawer-index-handle" @click="toggle">
|
||||||
|
<a-icon type="setting" v-if="!visible"/>
|
||||||
|
<a-icon type="close" v-else/>
|
||||||
|
</div>
|
||||||
|
</a-drawer>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import DetailList from '@/components/tools/DetailList'
|
||||||
|
import SettingItem from '@/components/setting/SettingItem'
|
||||||
|
import config from '@/defaultSettings'
|
||||||
|
import { updateTheme, updateColorWeak, colorList } from '@/components/tools/setting'
|
||||||
|
import { mixin, mixinDevice } from '@/utils/mixin.js'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
components: {
|
||||||
|
DetailList,
|
||||||
|
SettingItem
|
||||||
|
},
|
||||||
|
mixins: [mixin, mixinDevice],
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
visible: true,
|
||||||
|
colorList,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
|
||||||
|
},
|
||||||
|
mounted () {
|
||||||
|
const vm = this
|
||||||
|
setTimeout(() => {
|
||||||
|
vm.visible = false
|
||||||
|
}, 16)
|
||||||
|
// 当主题色不是默认色时,才进行主题编译
|
||||||
|
if (this.primaryColor !== config.primaryColor) {
|
||||||
|
updateTheme(this.primaryColor)
|
||||||
|
}
|
||||||
|
if (this.colorWeak !== config.colorWeak) {
|
||||||
|
updateColorWeak(this.colorWeak)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
showDrawer() {
|
||||||
|
this.visible = true
|
||||||
|
},
|
||||||
|
onClose() {
|
||||||
|
this.visible = false
|
||||||
|
},
|
||||||
|
toggle() {
|
||||||
|
this.visible = !this.visible
|
||||||
|
},
|
||||||
|
onColorWeak (checked) {
|
||||||
|
this.$store.dispatch('ToggleWeak', checked)
|
||||||
|
updateColorWeak(checked)
|
||||||
|
},
|
||||||
|
handleMenuTheme (theme) {
|
||||||
|
this.$store.dispatch('ToggleTheme', theme)
|
||||||
|
},
|
||||||
|
handleLayout (mode) {
|
||||||
|
this.$store.dispatch('ToggleLayoutMode', mode)
|
||||||
|
// 因为顶部菜单不能固定左侧菜单栏,所以强制关闭
|
||||||
|
//
|
||||||
|
this.handleFixSiderbar(false);
|
||||||
|
},
|
||||||
|
handleContentWidthChange (type) {
|
||||||
|
this.$store.dispatch('ToggleContentWidth', type)
|
||||||
|
},
|
||||||
|
changeColor (color) {
|
||||||
|
if (this.primaryColor !== color) {
|
||||||
|
this.$store.dispatch('ToggleColor', color)
|
||||||
|
updateTheme(color)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
handleFixedHeader (fixed) {
|
||||||
|
this.$store.dispatch('ToggleFixedHeader', fixed)
|
||||||
|
},
|
||||||
|
handleFixedHeaderHidden (autoHidden) {
|
||||||
|
this.$store.dispatch('ToggleFixedHeaderHidden', autoHidden)
|
||||||
|
},
|
||||||
|
handleFixSiderbar (fixed) {
|
||||||
|
if (this.layoutMode === 'topmenu') {
|
||||||
|
this.$store.dispatch('ToggleFixSiderbar', false)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.$store.dispatch('ToggleFixSiderbar', fixed)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
|
||||||
|
.setting-drawer-index-content {
|
||||||
|
|
||||||
|
.setting-drawer-index-blockChecbox {
|
||||||
|
display: flex;
|
||||||
|
|
||||||
|
.setting-drawer-index-item {
|
||||||
|
margin-right: 16px;
|
||||||
|
position: relative;
|
||||||
|
border-radius: 4px;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
img {
|
||||||
|
width: 48px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.setting-drawer-index-selectIcon {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
width: 100%;
|
||||||
|
padding-top: 15px;
|
||||||
|
padding-left: 24px;
|
||||||
|
height: 100%;
|
||||||
|
color: #1890ff;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.setting-drawer-theme-color-colorBlock {
|
||||||
|
width: 20px;
|
||||||
|
height: 20px;
|
||||||
|
border-radius: 2px;
|
||||||
|
float: left;
|
||||||
|
cursor: pointer;
|
||||||
|
margin-right: 8px;
|
||||||
|
padding-left: 0px;
|
||||||
|
padding-right: 0px;
|
||||||
|
text-align: center;
|
||||||
|
color: #fff;
|
||||||
|
font-weight: 700;
|
||||||
|
|
||||||
|
i {
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.setting-drawer-index-handle {
|
||||||
|
position: absolute;
|
||||||
|
top: 240px;
|
||||||
|
background: #1890ff;
|
||||||
|
width: 48px;
|
||||||
|
height: 48px;
|
||||||
|
right: 300px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
cursor: pointer;
|
||||||
|
pointer-events: auto;
|
||||||
|
z-index: 1001;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 16px;
|
||||||
|
border-radius: 4px 0 0 4px;
|
||||||
|
|
||||||
|
i {
|
||||||
|
color: rgb(255, 255, 255);
|
||||||
|
font-size: 20px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
38
ant-design-jeecg-vue/src/components/setting/SettingItem.vue
Normal file
38
ant-design-jeecg-vue/src/components/setting/SettingItem.vue
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
<template>
|
||||||
|
<div class="setting-drawer-index-item">
|
||||||
|
<h3 class="setting-drawer-index-title">{{ title }}</h3>
|
||||||
|
<slot></slot>
|
||||||
|
<a-divider v-if="divider"/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: "SettingItem",
|
||||||
|
props: {
|
||||||
|
title: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
divider: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
|
||||||
|
.setting-drawer-index-item {
|
||||||
|
margin-bottom: 24px;
|
||||||
|
|
||||||
|
.setting-drawer-index-title {
|
||||||
|
font-size: 14px;
|
||||||
|
color: rgba(0, 0, 0, .85);
|
||||||
|
line-height: 22px;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
</style>
|
||||||
292
ant-design-jeecg-vue/src/components/table/README.md
Normal file
292
ant-design-jeecg-vue/src/components/table/README.md
Normal file
@ -0,0 +1,292 @@
|
|||||||
|
Table 重封装组件说明
|
||||||
|
====
|
||||||
|
|
||||||
|
|
||||||
|
封装说明
|
||||||
|
----
|
||||||
|
|
||||||
|
> 基础的使用方式与 API 与 [官方版(Table)](https://vuecomponent.github.io/ant-design-vue/components/table-cn/) 本一致,在其基础上,封装了加载数据的方法。
|
||||||
|
>
|
||||||
|
> 你无需在你是用表格的页面进行分页逻辑处理,仅需向 Table 组件传递绑定 `:data="Promise"` 对象即可
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
例子1
|
||||||
|
----
|
||||||
|
(基础使用)
|
||||||
|
|
||||||
|
```vue
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<s-table
|
||||||
|
ref="table"
|
||||||
|
:rowKey="(record) => record.data.id"
|
||||||
|
size="default"
|
||||||
|
:columns="columns"
|
||||||
|
:data="loadData"
|
||||||
|
>
|
||||||
|
</s-table>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import STable from '@/components/table/'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
components: {
|
||||||
|
STable
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
title: '规则编号',
|
||||||
|
dataIndex: 'no'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '描述',
|
||||||
|
dataIndex: 'description'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '服务调用次数',
|
||||||
|
dataIndex: 'callNo',
|
||||||
|
sorter: true,
|
||||||
|
needTotal: true,
|
||||||
|
customRender: (text) => text + ' 次'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '状态',
|
||||||
|
dataIndex: 'status',
|
||||||
|
needTotal: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '更新时间',
|
||||||
|
dataIndex: 'updatedAt',
|
||||||
|
sorter: true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
// 查询条件参数
|
||||||
|
queryParam: {},
|
||||||
|
// 加载数据方法 必须为 Promise 对象
|
||||||
|
loadData: parameter => {
|
||||||
|
return this.$http.get('/service', {
|
||||||
|
params: Object.assign(parameter, this.queryParam)
|
||||||
|
}).then(res => {
|
||||||
|
return res.result
|
||||||
|
})
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
例子2
|
||||||
|
----
|
||||||
|
|
||||||
|
(简单的表格,最后一列是各种操作)
|
||||||
|
|
||||||
|
```vue
|
||||||
|
<template>
|
||||||
|
<s-table
|
||||||
|
ref="table"
|
||||||
|
size="default"
|
||||||
|
:columns="columns"
|
||||||
|
:data="loadData"
|
||||||
|
>
|
||||||
|
<span slot="action" slot-scope="text, record">
|
||||||
|
<a>编辑</a>
|
||||||
|
<a-divider type="vertical"/>
|
||||||
|
<a-dropdown>
|
||||||
|
<a class="ant-dropdown-link">
|
||||||
|
更多 <a-icon type="down"/>
|
||||||
|
</a>
|
||||||
|
<a-menu slot="overlay">
|
||||||
|
<a-menu-item>
|
||||||
|
<a href="javascript:;">1st menu item</a>
|
||||||
|
</a-menu-item>
|
||||||
|
<a-menu-item>
|
||||||
|
<a href="javascript:;">2nd menu item</a>
|
||||||
|
</a-menu-item>
|
||||||
|
<a-menu-item>
|
||||||
|
<a href="javascript:;">3rd menu item</a>
|
||||||
|
</a-menu-item>
|
||||||
|
</a-menu>
|
||||||
|
</a-dropdown>
|
||||||
|
</span>
|
||||||
|
</s-table>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import STable from '@/components/table/'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
components: {
|
||||||
|
STable
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
title: '规则编号',
|
||||||
|
dataIndex: 'no'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '描述',
|
||||||
|
dataIndex: 'description'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '服务调用次数',
|
||||||
|
dataIndex: 'callNo',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '状态',
|
||||||
|
dataIndex: 'status',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '更新时间',
|
||||||
|
dataIndex: 'updatedAt',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
table: '操作',
|
||||||
|
dataIndex: 'action',
|
||||||
|
scopedSlots: {customRender: 'action'},
|
||||||
|
}
|
||||||
|
],
|
||||||
|
// 查询条件参数
|
||||||
|
queryParam: {},
|
||||||
|
// 加载数据方法 必须为 Promise 对象
|
||||||
|
loadData: parameter => {
|
||||||
|
return this.$http.get('/service', {
|
||||||
|
params: Object.assign(parameter, this.queryParam)
|
||||||
|
}).then(res => {
|
||||||
|
return res.result
|
||||||
|
})
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
edit(row) {
|
||||||
|
// axios 发送数据到后端 修改数据成功后
|
||||||
|
// 调用 refresh() 重新加载列表数据
|
||||||
|
// 这里 setTimeout 模拟发起请求的网络延迟..
|
||||||
|
setTimeout(() => {
|
||||||
|
this.$refs.table.refresh()
|
||||||
|
}, 1500)
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
内置方法
|
||||||
|
----
|
||||||
|
|
||||||
|
通过 `this.$refs.table` 调用
|
||||||
|
|
||||||
|
`this.$refs.table.refresh()` 刷新列表 (用户新增/修改数据后,重载列表数据)
|
||||||
|
|
||||||
|
> 注意:要调用 `refresh()` 需要给表格组件设定 `ref` 值
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
注意事项
|
||||||
|
----
|
||||||
|
|
||||||
|
> 你可能需要为了与后端提供的接口返回结果一致而去修改以下代码:
|
||||||
|
(需要注意的是,这里的修改是全局性的,意味着整个项目所有使用该 table 组件都需要遵守这个返回结果定义的字段。)
|
||||||
|
|
||||||
|
修改 `@/components/table/index.js` 第 106 行起
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
result.then(r => {
|
||||||
|
this.localPagination = Object.assign({}, this.localPagination, {
|
||||||
|
current: r.pageNo, // 返回结果中的当前分页数
|
||||||
|
total: r.totalCount, // 返回结果中的总记录数
|
||||||
|
showSizeChanger: this.showSizeChanger,
|
||||||
|
pageSize: (pagination && pagination.pageSize) ||
|
||||||
|
this.localPagination.pageSize
|
||||||
|
});
|
||||||
|
|
||||||
|
!r.totalCount && ['auto', false].includes(this.showPagination) && (this.localPagination = false)
|
||||||
|
this.localDataSource = r.data; // 返回结果中的数组数据
|
||||||
|
this.localLoading = false
|
||||||
|
});
|
||||||
|
```
|
||||||
|
返回 JSON 例子:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"message": "",
|
||||||
|
"result": {
|
||||||
|
"data": [{
|
||||||
|
id: 1,
|
||||||
|
cover: 'https://gw.alipayobjects.com/zos/rmsportal/WdGqmHpayyMjiEhcKoVE.png',
|
||||||
|
title: 'Alipay',
|
||||||
|
description: '那是一种内在的东西, 他们到达不了,也无法触及的',
|
||||||
|
status: 1,
|
||||||
|
updatedAt: '2018-07-26 00:00:00'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 2,
|
||||||
|
cover: 'https://gw.alipayobjects.com/zos/rmsportal/zOsKZmFRdUtvpqCImOVY.png',
|
||||||
|
title: 'Angular',
|
||||||
|
description: '希望是一个好东西,也许是最好的,好东西是不会消亡的',
|
||||||
|
status: 1,
|
||||||
|
updatedAt: '2018-07-26 00:00:00'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 3,
|
||||||
|
cover: 'https://gw.alipayobjects.com/zos/rmsportal/dURIMkkrRFpPgTuzkwnB.png',
|
||||||
|
title: 'Ant Design',
|
||||||
|
description: '城镇中有那么多的酒馆,她却偏偏走进了我的酒馆',
|
||||||
|
status: 1,
|
||||||
|
updatedAt: '2018-07-26 00:00:00'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 4,
|
||||||
|
cover: 'https://gw.alipayobjects.com/zos/rmsportal/sfjbOqnsXXJgNCjCzDBL.png',
|
||||||
|
title: 'Ant Design Pro',
|
||||||
|
description: '那时候我只会想自己想要什么,从不想自己拥有什么',
|
||||||
|
status: 1,
|
||||||
|
updatedAt: '2018-07-26 00:00:00'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 5,
|
||||||
|
cover: 'https://gw.alipayobjects.com/zos/rmsportal/siCrBXXhmvTQGWPNLBow.png',
|
||||||
|
title: 'Bootstrap',
|
||||||
|
description: '凛冬将至',
|
||||||
|
status: 1,
|
||||||
|
updatedAt: '2018-07-26 00:00:00'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 6,
|
||||||
|
cover: 'https://gw.alipayobjects.com/zos/rmsportal/ComBAopevLwENQdKWiIn.png',
|
||||||
|
title: 'Vue',
|
||||||
|
description: '生命就像一盒巧克力,结果往往出人意料',
|
||||||
|
status: 1,
|
||||||
|
updatedAt: '2018-07-26 00:00:00'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"pageSize": 10,
|
||||||
|
"pageNo": 0,
|
||||||
|
"totalPage": 6,
|
||||||
|
"totalCount": 57
|
||||||
|
},
|
||||||
|
"status": 200,
|
||||||
|
"timestamp": 1534955098193
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
更新时间
|
||||||
|
----
|
||||||
|
|
||||||
|
该文档最后更新于: 2018-10-31 PM 08:15
|
||||||
252
ant-design-jeecg-vue/src/components/table/StandardTable.vue
Normal file
252
ant-design-jeecg-vue/src/components/table/StandardTable.vue
Normal file
@ -0,0 +1,252 @@
|
|||||||
|
<template>
|
||||||
|
<div class="standard-table">
|
||||||
|
<div class="alert">
|
||||||
|
<a-alert type="info" :show-icon="true">
|
||||||
|
<div slot="message">
|
||||||
|
已选择 <a style="font-weight: 600">{{ selectedRows.length }}</a>
|
||||||
|
<template v-for="(item, index) in needTotalList" v-if="item.needTotal">
|
||||||
|
{{ item.title }} 总计
|
||||||
|
<a :key="index" style="font-weight: 600">
|
||||||
|
{{ item.customRender ? item.customRender(item.total) : item.total }}
|
||||||
|
</a>
|
||||||
|
</template>
|
||||||
|
<a style="margin-left: 24px" @click="onClearSelected">清空</a>
|
||||||
|
</div>
|
||||||
|
</a-alert>
|
||||||
|
</div>
|
||||||
|
<a-table
|
||||||
|
:size="size"
|
||||||
|
:bordered="bordered"
|
||||||
|
:loading="loading"
|
||||||
|
:columns="columns"
|
||||||
|
:dataSource="current"
|
||||||
|
:rowKey="rowKey"
|
||||||
|
:pagination="pagination"
|
||||||
|
:rowSelection="{ selectedRowKeys: selectedRowKeys, onChange: updateSelect }"
|
||||||
|
>
|
||||||
|
</a-table>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: "StandardTable",
|
||||||
|
// props: ['bordered', 'loading', 'columns', 'data', 'rowKey', 'pagination', 'selectedRows'],
|
||||||
|
props: {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 数据加载函数,返回值必须是 Promise
|
||||||
|
* 默认情况下必须传递 data 参数;
|
||||||
|
* 如果使用本地数据渲染表格,业务代码中将获取本地数据包装为 Promise 即可。
|
||||||
|
*
|
||||||
|
* currentData 用于向外暴露表格当前渲染的数据,
|
||||||
|
* 业务开发中也可以直接修改 currentData,从而重新渲染表格(仅推荐用于客户端排序、数据过滤等场景)
|
||||||
|
*/
|
||||||
|
data: {
|
||||||
|
type: Function,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
dataSource: {
|
||||||
|
type: Array,
|
||||||
|
default () {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
columns: {
|
||||||
|
type: Array,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
/* pagination: {
|
||||||
|
type: Object,
|
||||||
|
default () {
|
||||||
|
return {}
|
||||||
|
}
|
||||||
|
},*/
|
||||||
|
pageSize: {
|
||||||
|
type: Number,
|
||||||
|
default: 10
|
||||||
|
},
|
||||||
|
pageNum: {
|
||||||
|
type: Number,
|
||||||
|
default: 1
|
||||||
|
},
|
||||||
|
pageSizeOptions: {
|
||||||
|
type: Array,
|
||||||
|
default () {
|
||||||
|
return ['10', '20', '30', '40', '50']
|
||||||
|
}
|
||||||
|
},
|
||||||
|
responseParamsName: {
|
||||||
|
type: Object,
|
||||||
|
default () {
|
||||||
|
return {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
bordered: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* 表格大小风格,default, middle, small
|
||||||
|
*/
|
||||||
|
size: {
|
||||||
|
type: String,
|
||||||
|
default: 'default'
|
||||||
|
},
|
||||||
|
rowKey: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
selectedRows: {
|
||||||
|
type: Array,
|
||||||
|
default: null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
needTotalList: [],
|
||||||
|
selectedRowKeys: [],
|
||||||
|
|
||||||
|
loading: true,
|
||||||
|
|
||||||
|
total: 0,
|
||||||
|
pageNumber: this.pageNum,
|
||||||
|
currentPageSize: this.pageSize,
|
||||||
|
defaultCurrent: 1,
|
||||||
|
sortParams: {},
|
||||||
|
|
||||||
|
current: [],
|
||||||
|
pagination: {},
|
||||||
|
paramsName: {},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created () {
|
||||||
|
//数据请求参数配置
|
||||||
|
this.paramsName = Object.assign(
|
||||||
|
{},
|
||||||
|
{
|
||||||
|
pageNumber: "pageNo",
|
||||||
|
pageSize: "pageSize",
|
||||||
|
total: "totalCount",
|
||||||
|
results: "data",
|
||||||
|
sortColumns: "sortColumns"
|
||||||
|
},
|
||||||
|
this.responseParamsName
|
||||||
|
);
|
||||||
|
|
||||||
|
this.needTotalList = this.initTotalList(this.columns)
|
||||||
|
|
||||||
|
// load data
|
||||||
|
this.loadData( { pageNum: this.pageNumber } )
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
updateSelect (selectedRowKeys, selectedRows) {
|
||||||
|
this.selectedRowKeys = selectedRowKeys
|
||||||
|
let list = this.needTotalList
|
||||||
|
this.needTotalList = list.map(item => {
|
||||||
|
return {
|
||||||
|
...item,
|
||||||
|
total: selectedRows.reduce((sum, val) => {
|
||||||
|
return sum + val[item.dataIndex]
|
||||||
|
}, 0)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
this.$emit('change', selectedRowKeys, selectedRows)
|
||||||
|
},
|
||||||
|
initTotalList (columns) {
|
||||||
|
const totalList = []
|
||||||
|
columns.forEach(column => {
|
||||||
|
if (column.needTotal) {
|
||||||
|
totalList.push({ ...column, total: 0 })
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return totalList
|
||||||
|
},
|
||||||
|
|
||||||
|
loadData (params) {
|
||||||
|
let that = this
|
||||||
|
that.loading = true
|
||||||
|
params = Object.assign({}, params)
|
||||||
|
const remoteParams = Object.assign({}, that.sortParams)
|
||||||
|
remoteParams[that.paramsName.pageNumber] = params.pageNum || that.pageNumber
|
||||||
|
remoteParams[that.paramsName.pageSize] = params.pageSize || that.currentPageSize
|
||||||
|
|
||||||
|
if (params.pageNum) {
|
||||||
|
that.pageNumber = params.pageNum
|
||||||
|
}
|
||||||
|
if (params.pageSize) {
|
||||||
|
that.currentPageSize = params.pageSize
|
||||||
|
}
|
||||||
|
|
||||||
|
let dataPromise = that.data(remoteParams)
|
||||||
|
|
||||||
|
dataPromise.then( response => {
|
||||||
|
if (!response) {
|
||||||
|
that.loading = false
|
||||||
|
return
|
||||||
|
}
|
||||||
|
let results = response[that.paramsName.results]
|
||||||
|
results = (results instanceof Array && results) || []
|
||||||
|
|
||||||
|
that.current = results
|
||||||
|
|
||||||
|
that.$emit("update:currentData", that.current.slice())
|
||||||
|
that.$emit("dataloaded", that.current.slice())
|
||||||
|
|
||||||
|
that.total = response[that.paramsName.total] * 1
|
||||||
|
that.pagination = that.pager()
|
||||||
|
that.loading = false
|
||||||
|
}, () => {
|
||||||
|
// error callback
|
||||||
|
that.loading = false
|
||||||
|
})
|
||||||
|
},
|
||||||
|
// eslint-disable-next-line
|
||||||
|
onPagerChange (page, pageSize) {
|
||||||
|
this.pageNumber = page
|
||||||
|
this.loadData({ pageNum: page })
|
||||||
|
},
|
||||||
|
onPagerSizeChange (current, size) {
|
||||||
|
this.currentPageSize = size
|
||||||
|
/*
|
||||||
|
if (current === this.pageNumber) this.loadData()
|
||||||
|
console.log('page-size-change', current, size)
|
||||||
|
*/
|
||||||
|
},
|
||||||
|
onClearSelected () {
|
||||||
|
this.selectedRowKeys = []
|
||||||
|
this.updateSelect([], [])
|
||||||
|
},
|
||||||
|
pager () {
|
||||||
|
return {
|
||||||
|
total: this.total,
|
||||||
|
showTotal: total => `共有 ${total} 条`,
|
||||||
|
showSizeChanger: true,
|
||||||
|
pageSizeOptions: this.pageSizeOptions,
|
||||||
|
pageSize: this.pageSize,
|
||||||
|
defaultCurrent: this.defaultCurrent,
|
||||||
|
onChange: this.onPagerChange,
|
||||||
|
onShowSizeChange: this.onPagerSizeChange
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
'selectedRows': function (selectedRows) {
|
||||||
|
this.needTotalList = this.needTotalList.map(item => {
|
||||||
|
return {
|
||||||
|
...item,
|
||||||
|
total: selectedRows.reduce( (sum, val) => {
|
||||||
|
return sum + val[item.dataIndex]
|
||||||
|
}, 0)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.alert {
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
265
ant-design-jeecg-vue/src/components/table/index.js
Normal file
265
ant-design-jeecg-vue/src/components/table/index.js
Normal file
@ -0,0 +1,265 @@
|
|||||||
|
import T from "ant-design-vue/es/table/Table";
|
||||||
|
import get from "lodash.get"
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
needTotalList: [],
|
||||||
|
|
||||||
|
selectedRows: [],
|
||||||
|
selectedRowKeys: [],
|
||||||
|
|
||||||
|
localLoading: false,
|
||||||
|
localDataSource: [],
|
||||||
|
localPagination: Object.assign({}, T.props.pagination)
|
||||||
|
};
|
||||||
|
},
|
||||||
|
props: Object.assign({}, T.props, {
|
||||||
|
rowKey: {
|
||||||
|
type: [String, Function],
|
||||||
|
default: 'id'
|
||||||
|
},
|
||||||
|
data: {
|
||||||
|
type: Function,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
pageNum: {
|
||||||
|
type: Number,
|
||||||
|
default: 1
|
||||||
|
},
|
||||||
|
pageSize: {
|
||||||
|
type: Number,
|
||||||
|
default: 10
|
||||||
|
},
|
||||||
|
showSizeChanger: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
showAlertInfo: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
showPagination: {
|
||||||
|
default: 'auto'
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
watch: {
|
||||||
|
'localPagination.current'(val) {
|
||||||
|
this.$router.push({
|
||||||
|
name: this.$route.name,
|
||||||
|
params: Object.assign({}, this.$route.params, {
|
||||||
|
pageNo: val
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
},
|
||||||
|
pageNum(val) {
|
||||||
|
Object.assign(this.localPagination, {
|
||||||
|
current: val
|
||||||
|
});
|
||||||
|
},
|
||||||
|
pageSize(val) {
|
||||||
|
console.log('pageSize:', val)
|
||||||
|
Object.assign(this.localPagination, {
|
||||||
|
pageSize: val
|
||||||
|
});
|
||||||
|
},
|
||||||
|
showSizeChanger(val) {
|
||||||
|
console.log('showSizeChanger', val)
|
||||||
|
Object.assign(this.localPagination, {
|
||||||
|
showSizeChanger: val
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
this.localPagination = ['auto', true].includes(this.showPagination) && Object.assign({}, this.localPagination, {
|
||||||
|
current: this.pageNum,
|
||||||
|
pageSize: this.pageSize,
|
||||||
|
showSizeChanger: this.showSizeChanger
|
||||||
|
});
|
||||||
|
this.needTotalList = this.initTotalList(this.columns)
|
||||||
|
this.loadData();
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
refresh() {
|
||||||
|
this.loadData();
|
||||||
|
},
|
||||||
|
loadData(pagination, filters, sorter) {
|
||||||
|
|
||||||
|
this.localLoading = true
|
||||||
|
var result = this.data(
|
||||||
|
Object.assign({
|
||||||
|
pageNo: (pagination && pagination.current) ||
|
||||||
|
this.localPagination.current,
|
||||||
|
pageSize: (pagination && pagination.pageSize) ||
|
||||||
|
this.localPagination.pageSize
|
||||||
|
},
|
||||||
|
(sorter && sorter.field && {
|
||||||
|
sortField: sorter.field
|
||||||
|
}) || {},
|
||||||
|
(sorter && sorter.order && {
|
||||||
|
sortOrder: sorter.order
|
||||||
|
}) || {}, {
|
||||||
|
...filters
|
||||||
|
}
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (result instanceof Promise) {
|
||||||
|
result.then(r => {
|
||||||
|
this.localPagination = Object.assign({}, this.localPagination, {
|
||||||
|
current: r.pageNo, // 返回结果中的当前分页数
|
||||||
|
total: r.totalCount, // 返回结果中的总记录数
|
||||||
|
showSizeChanger: this.showSizeChanger,
|
||||||
|
pageSize: (pagination && pagination.pageSize) ||
|
||||||
|
this.localPagination.pageSize
|
||||||
|
});
|
||||||
|
|
||||||
|
!r.totalCount && ['auto', false].includes(this.showPagination) && (this.localPagination = false)
|
||||||
|
this.localDataSource = r.data; // 返回结果中的数组数据
|
||||||
|
this.localLoading = false
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
initTotalList(columns) {
|
||||||
|
const totalList = []
|
||||||
|
columns && columns instanceof Array && columns.forEach(column => {
|
||||||
|
if (column.needTotal) {
|
||||||
|
totalList.push({ ...column,
|
||||||
|
total: 0
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return totalList
|
||||||
|
},
|
||||||
|
updateSelect(selectedRowKeys, selectedRows) {
|
||||||
|
this.selectedRowKeys = selectedRowKeys
|
||||||
|
this.selectedRows = selectedRows
|
||||||
|
let list = this.needTotalList
|
||||||
|
this.needTotalList = list.map(item => {
|
||||||
|
return {
|
||||||
|
...item,
|
||||||
|
total: selectedRows.reduce((sum, val) => {
|
||||||
|
let total = sum + get(val, item.dataIndex)
|
||||||
|
return isNaN(total) ? 0 : total
|
||||||
|
}, 0)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
// this.$emit('change', selectedRowKeys, selectedRows)
|
||||||
|
},
|
||||||
|
updateEdit() {
|
||||||
|
this.selectedRows = []
|
||||||
|
},
|
||||||
|
onClearSelected() {
|
||||||
|
this.selectedRowKeys = []
|
||||||
|
this.updateSelect([], [])
|
||||||
|
},
|
||||||
|
renderMsg(h) {
|
||||||
|
const _vm = this
|
||||||
|
let d = []
|
||||||
|
// 构建 已选择
|
||||||
|
d.push(
|
||||||
|
h('span', {
|
||||||
|
style: {
|
||||||
|
marginRight: '12px'
|
||||||
|
}
|
||||||
|
}, ['已选择 ', h('a', {
|
||||||
|
style: {
|
||||||
|
fontWeight: 600
|
||||||
|
}
|
||||||
|
}, this.selectedRows.length)])
|
||||||
|
);
|
||||||
|
|
||||||
|
// 构建 列统计
|
||||||
|
this.needTotalList.map(item => {
|
||||||
|
d.push(h('span', {
|
||||||
|
style: {
|
||||||
|
marginRight: '12px'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[
|
||||||
|
`${ item.title }总计 `,
|
||||||
|
h('a', {
|
||||||
|
style: {
|
||||||
|
fontWeight: 600
|
||||||
|
}
|
||||||
|
}, `${ !item.customRender ? item.total : item.customRender(item.total) }`)
|
||||||
|
]))
|
||||||
|
});
|
||||||
|
|
||||||
|
// 构建 清空选择
|
||||||
|
d.push(h('a', {
|
||||||
|
style: {
|
||||||
|
marginLeft: '24px'
|
||||||
|
},
|
||||||
|
on: {
|
||||||
|
click: _vm.onClearSelected
|
||||||
|
}
|
||||||
|
}, '清空'))
|
||||||
|
|
||||||
|
return d
|
||||||
|
},
|
||||||
|
renderAlert(h) {
|
||||||
|
return h('span', {
|
||||||
|
slot: 'message'
|
||||||
|
}, this.renderMsg(h))
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
render(h) {
|
||||||
|
const _vm = this
|
||||||
|
|
||||||
|
let props = {},
|
||||||
|
localKeys = Object.keys(this.$data);
|
||||||
|
|
||||||
|
Object.keys(T.props).forEach(k => {
|
||||||
|
let localKey = `local${k.substring(0,1).toUpperCase()}${k.substring(1)}`;
|
||||||
|
if (localKeys.includes(localKey)) {
|
||||||
|
return props[k] = _vm[localKey];
|
||||||
|
}
|
||||||
|
return props[k] = _vm[k];
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
// 显示信息提示
|
||||||
|
if (this.showAlertInfo) {
|
||||||
|
|
||||||
|
props.rowSelection = {
|
||||||
|
selectedRowKeys: this.selectedRowKeys,
|
||||||
|
onChange: (selectedRowKeys, selectedRows) => {
|
||||||
|
_vm.updateSelect(selectedRowKeys, selectedRows)
|
||||||
|
_vm.$emit('onSelect', { selectedRowKeys: selectedRowKeys, selectedRows: selectedRows })
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return h('div', {}, [
|
||||||
|
h("a-alert", {
|
||||||
|
style: {
|
||||||
|
marginBottom: '16px'
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
type: 'info',
|
||||||
|
showIcon: true
|
||||||
|
}
|
||||||
|
}, [_vm.renderAlert(h)]),
|
||||||
|
h("a-table", {
|
||||||
|
tag: "component",
|
||||||
|
attrs: props,
|
||||||
|
on: {
|
||||||
|
change: _vm.loadData
|
||||||
|
},
|
||||||
|
scopedSlots: this.$scopedSlots
|
||||||
|
}, this.$slots.default)
|
||||||
|
]);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return h("a-table", {
|
||||||
|
tag: "component",
|
||||||
|
attrs: props,
|
||||||
|
on: {
|
||||||
|
change: _vm.loadData
|
||||||
|
},
|
||||||
|
scopedSlots: this.$scopedSlots
|
||||||
|
}, this.$slots.default);
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
48
ant-design-jeecg-vue/src/components/tools/Breadcrumb.vue
Normal file
48
ant-design-jeecg-vue/src/components/tools/Breadcrumb.vue
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
<template>
|
||||||
|
<a-breadcrumb class="breadcrumb">
|
||||||
|
<a-breadcrumb-item v-for="(item, index) in breadList" :key="index">
|
||||||
|
<router-link v-if="item.name != name" :to="{ path: item.path }">
|
||||||
|
{{ item.meta.title }}
|
||||||
|
</router-link>
|
||||||
|
<span v-else>{{ item.meta.title }}</span>
|
||||||
|
</a-breadcrumb-item>
|
||||||
|
</a-breadcrumb>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
name: '',
|
||||||
|
breadList: [],
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created () {
|
||||||
|
this.getBreadcrumb()
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
getBreadcrumb() {
|
||||||
|
|
||||||
|
console.log('this.$route.matched', this.$route.matched)
|
||||||
|
|
||||||
|
this.breadList = []
|
||||||
|
this.breadList.push({ name: 'dashboard', path: '/dashboard/', meta: { title: '首页' } })
|
||||||
|
|
||||||
|
this.name = this.$route.name
|
||||||
|
this.$route.matched.forEach((item) => {
|
||||||
|
// item.meta.name === 'dashboard' ? item.path = '/dashboard' : this.$route.path === item.path
|
||||||
|
this.breadList.push(item)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
$route() {
|
||||||
|
this.getBreadcrumb()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
</style>
|
||||||
147
ant-design-jeecg-vue/src/components/tools/DetailList.vue
Normal file
147
ant-design-jeecg-vue/src/components/tools/DetailList.vue
Normal file
@ -0,0 +1,147 @@
|
|||||||
|
<template>
|
||||||
|
<div :class="['detail-list', size, layout === 'vertical' ? 'vertical': 'horizontal']">
|
||||||
|
<div v-if="title" class="title">{{ title }}</div>
|
||||||
|
<a-row>
|
||||||
|
<slot></slot>
|
||||||
|
</a-row>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { Col } from 'ant-design-vue/es/grid/'
|
||||||
|
|
||||||
|
const Item = {
|
||||||
|
name: 'DetailListItem',
|
||||||
|
props: {
|
||||||
|
term: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
required: false
|
||||||
|
},
|
||||||
|
},
|
||||||
|
inject: {
|
||||||
|
col: {
|
||||||
|
type: Number
|
||||||
|
}
|
||||||
|
},
|
||||||
|
render () {
|
||||||
|
return (
|
||||||
|
<Col {...{props: responsive[this.col]}}>
|
||||||
|
<div class="term">{this.$props.term}</div>
|
||||||
|
<div class="content">{this.$slots.default}</div>
|
||||||
|
</Col>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const responsive = {
|
||||||
|
1: { xs: 24 },
|
||||||
|
2: { xs: 24, sm: 12 },
|
||||||
|
3: { xs: 24, sm: 12, md: 8 },
|
||||||
|
4: { xs: 24, sm: 12, md: 6 }
|
||||||
|
}
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "DetailList",
|
||||||
|
Item: Item,
|
||||||
|
components: {
|
||||||
|
Col
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
title: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
required: false
|
||||||
|
},
|
||||||
|
col: {
|
||||||
|
type: Number,
|
||||||
|
required: false,
|
||||||
|
default: 3
|
||||||
|
},
|
||||||
|
size: {
|
||||||
|
type: String,
|
||||||
|
required: false,
|
||||||
|
default: 'large'
|
||||||
|
},
|
||||||
|
layout: {
|
||||||
|
type: String,
|
||||||
|
required: false,
|
||||||
|
default: 'horizontal'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
provide () {
|
||||||
|
return {
|
||||||
|
col: this.col > 4 ? 4 : this.col
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
|
||||||
|
.detail-list {
|
||||||
|
|
||||||
|
.title {
|
||||||
|
color: rgba(0,0,0,.85);
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 500;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.term {
|
||||||
|
color: rgba(0,0,0,.85);
|
||||||
|
display: table-cell;
|
||||||
|
line-height: 20px;
|
||||||
|
margin-right: 8px;
|
||||||
|
padding-bottom: 16px;
|
||||||
|
white-space: nowrap;
|
||||||
|
|
||||||
|
&:after {
|
||||||
|
content: ":";
|
||||||
|
margin: 0 8px 0 2px;
|
||||||
|
position: relative;
|
||||||
|
top: -.5px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.content {
|
||||||
|
color: rgba(0,0,0,.65);
|
||||||
|
display: table-cell;
|
||||||
|
line-height: 22px;
|
||||||
|
padding-bottom: 16px;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.small {
|
||||||
|
|
||||||
|
.title {
|
||||||
|
font-size: 14px;
|
||||||
|
color: rgba(0, 0, 0, .65);
|
||||||
|
font-weight: normal;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
.term, .content {
|
||||||
|
padding-bottom: 8px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.large {
|
||||||
|
.term, .content {
|
||||||
|
padding-bottom: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title {
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.vertical {
|
||||||
|
.term {
|
||||||
|
padding-bottom: 8px;
|
||||||
|
}
|
||||||
|
.term, .content {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
32
ant-design-jeecg-vue/src/components/tools/FooterToolBar.vue
Normal file
32
ant-design-jeecg-vue/src/components/tools/FooterToolBar.vue
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
<template>
|
||||||
|
<div class="toolbar">
|
||||||
|
<div style="float: left">
|
||||||
|
<slot name="extra"></slot>
|
||||||
|
</div>
|
||||||
|
<div style="float: right">
|
||||||
|
<slot></slot>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: "FooterToolBar"
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.toolbar {
|
||||||
|
position: fixed;
|
||||||
|
width: 100%;
|
||||||
|
bottom: 0;
|
||||||
|
right: 0;
|
||||||
|
height: 56px;
|
||||||
|
line-height: 56px;
|
||||||
|
box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.03);
|
||||||
|
background: #fff;
|
||||||
|
border-top: 1px solid #e8e8e8;
|
||||||
|
padding: 0 24px;
|
||||||
|
z-index: 9;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
67
ant-design-jeecg-vue/src/components/tools/HeadInfo.vue
Normal file
67
ant-design-jeecg-vue/src/components/tools/HeadInfo.vue
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
<template>
|
||||||
|
<div class="head-info" :class="center && 'center'">
|
||||||
|
<span>{{ title }}</span>
|
||||||
|
<p>{{ content }}</p>
|
||||||
|
<em v-if="bordered"/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: "HeadInfo",
|
||||||
|
props: {
|
||||||
|
title: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
content: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
bordered: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
center: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.head-info {
|
||||||
|
position: relative;
|
||||||
|
text-align: left;
|
||||||
|
padding: 0 32px 0 0;
|
||||||
|
min-width: 125px;
|
||||||
|
|
||||||
|
&.center {
|
||||||
|
text-align: center;
|
||||||
|
padding: 0 32px;
|
||||||
|
}
|
||||||
|
|
||||||
|
span {
|
||||||
|
color: rgba(0, 0, 0, .45);
|
||||||
|
display: inline-block;
|
||||||
|
font-size: 14px;
|
||||||
|
line-height: 22px;
|
||||||
|
margin-bottom: 4px;
|
||||||
|
}
|
||||||
|
p {
|
||||||
|
color: rgba(0, 0, 0, .85);
|
||||||
|
font-size: 24px;
|
||||||
|
line-height: 32px;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
em {
|
||||||
|
background-color: #e8e8e8;
|
||||||
|
position: absolute;
|
||||||
|
height: 56px;
|
||||||
|
width: 1px;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
85
ant-design-jeecg-vue/src/components/tools/HeaderNotice.vue
Normal file
85
ant-design-jeecg-vue/src/components/tools/HeaderNotice.vue
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
<template>
|
||||||
|
<a-popover
|
||||||
|
trigger="click"
|
||||||
|
placement="bottomRight"
|
||||||
|
:autoAdjustOverflow="true"
|
||||||
|
:arrowPointAtCenter="true"
|
||||||
|
overlayClassName="header-notice-wrapper"
|
||||||
|
:overlayStyle="{ width: '300px', top: '50px' }">
|
||||||
|
<template slot="content">
|
||||||
|
<a-spin :spinning="loadding">
|
||||||
|
<a-tabs>
|
||||||
|
<a-tab-pane tab="通知" key="1">
|
||||||
|
<a-list>
|
||||||
|
<a-list-item>
|
||||||
|
<a-list-item-meta title="你收到了 14 份新周报" description="一年前">
|
||||||
|
<a-avatar style="background-color: white" slot="avatar" src="https://gw.alipayobjects.com/zos/rmsportal/ThXAXghbEsBCCSDihZxY.png"/>
|
||||||
|
</a-list-item-meta>
|
||||||
|
</a-list-item>
|
||||||
|
<a-list-item>
|
||||||
|
<a-list-item-meta title="你推荐的 曲妮妮 已通过第三轮面试" description="一年前">
|
||||||
|
<a-avatar style="background-color: white" slot="avatar" src="https://gw.alipayobjects.com/zos/rmsportal/OKJXDXrmkNshAMvwtvhu.png"/>
|
||||||
|
</a-list-item-meta>
|
||||||
|
</a-list-item>
|
||||||
|
<a-list-item>
|
||||||
|
<a-list-item-meta title="这种模板可以区分多种通知类型" description="一年前">
|
||||||
|
<a-avatar style="background-color: white" slot="avatar" src="https://gw.alipayobjects.com/zos/rmsportal/kISTdvpyTAhtGxpovNWd.png"/>
|
||||||
|
</a-list-item-meta>
|
||||||
|
</a-list-item>
|
||||||
|
</a-list>
|
||||||
|
</a-tab-pane>
|
||||||
|
<a-tab-pane tab="消息" key="2">
|
||||||
|
123
|
||||||
|
</a-tab-pane>
|
||||||
|
<a-tab-pane tab="待办" key="3">
|
||||||
|
123
|
||||||
|
</a-tab-pane>
|
||||||
|
</a-tabs>
|
||||||
|
</a-spin>
|
||||||
|
</template>
|
||||||
|
<span @click="fetchNotice" class="header-notice">
|
||||||
|
<a-badge count="12">
|
||||||
|
<a-icon style="font-size: 16px; padding: 4px" type="bell" />
|
||||||
|
</a-badge>
|
||||||
|
</span>
|
||||||
|
</a-popover>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: "HeaderNotice",
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
loadding: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
fetchNotice () {
|
||||||
|
if (this.loadding) {
|
||||||
|
this.loadding = false
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.loadding = true
|
||||||
|
setTimeout(() => {
|
||||||
|
this.loadding = false
|
||||||
|
}, 2000)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="css">
|
||||||
|
.header-notice-wrapper {
|
||||||
|
top: 50px !important;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.header-notice{
|
||||||
|
display: inline-block;
|
||||||
|
transition: all 0.3s;
|
||||||
|
|
||||||
|
span {
|
||||||
|
vertical-align: initial;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
33
ant-design-jeecg-vue/src/components/tools/Logo.vue
Normal file
33
ant-design-jeecg-vue/src/components/tools/Logo.vue
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
<template>
|
||||||
|
<div class="logo">
|
||||||
|
<router-link :to="{name:'dashboard'}">
|
||||||
|
<img src="~@/assets/logo.svg" alt="logo">
|
||||||
|
<h1 v-if="showTitle">{{ title }}</h1>
|
||||||
|
</router-link>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: "Logo",
|
||||||
|
props: {
|
||||||
|
title: {
|
||||||
|
type: String,
|
||||||
|
default: 'Jeecg-Boot Pro',
|
||||||
|
required: false
|
||||||
|
},
|
||||||
|
showTitle: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true,
|
||||||
|
required: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
/*缩小首页布 局顶部的高度*/
|
||||||
|
.sider .logo {
|
||||||
|
height: 59px!important;
|
||||||
|
line-height: 59px!important;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
89
ant-design-jeecg-vue/src/components/tools/TwoStepCaptcha.vue
Normal file
89
ant-design-jeecg-vue/src/components/tools/TwoStepCaptcha.vue
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
<template>
|
||||||
|
<!-- 两步验证 -->
|
||||||
|
<a-modal
|
||||||
|
centered
|
||||||
|
v-model="visible"
|
||||||
|
@cancel="handleCancel"
|
||||||
|
:maskClosable="false"
|
||||||
|
>
|
||||||
|
<div slot="title" :style="{ textAlign: 'center' }">两步验证</div>
|
||||||
|
<template slot="footer">
|
||||||
|
<div :style="{ textAlign: 'center' }">
|
||||||
|
<a-button key="back" @click="handleCancel">返回</a-button>
|
||||||
|
<a-button key="submit" type="primary" :loading="stepLoading" @click="handleStepOk">
|
||||||
|
继续
|
||||||
|
</a-button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<a-spin :spinning="stepLoading">
|
||||||
|
<a-form layout="vertical" :auto-form-create="(form)=>{this.form = form}">
|
||||||
|
<div class="step-form-wrapper">
|
||||||
|
<p style="text-align: center" v-if="!stepLoading">请在手机中打开 Google Authenticator 或两步验证 APP<br />输入 6 位动态码</p>
|
||||||
|
<p style="text-align: center" v-else>正在验证..<br/>请稍后</p>
|
||||||
|
<a-form-item
|
||||||
|
:style="{ textAlign: 'center' }"
|
||||||
|
hasFeedback
|
||||||
|
fieldDecoratorId="stepCode"
|
||||||
|
:fieldDecoratorOptions="{rules: [{ required: true, message: '请输入 6 位动态码!', pattern: /^\d{6}$/, len: 6 }]}"
|
||||||
|
>
|
||||||
|
<a-input :style="{ textAlign: 'center' }" @keyup.enter.native="handleStepOk" placeholder="000000" />
|
||||||
|
</a-form-item>
|
||||||
|
<p style="text-align: center">
|
||||||
|
<a @click="onForgeStepCode">遗失手机?</a>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</a-form>
|
||||||
|
</a-spin>
|
||||||
|
</a-modal>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
visible: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
stepLoading: false,
|
||||||
|
|
||||||
|
form: null
|
||||||
|
};
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
handleStepOk() {
|
||||||
|
const vm = this
|
||||||
|
this.stepLoading = true
|
||||||
|
this.form.validateFields((err, values) => {
|
||||||
|
if (!err) {
|
||||||
|
console.log('values', values)
|
||||||
|
setTimeout( () => {
|
||||||
|
vm.stepLoading = false
|
||||||
|
vm.$emit('success', { values })
|
||||||
|
}, 2000)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.stepLoading = false
|
||||||
|
this.$emit('error', { err })
|
||||||
|
})
|
||||||
|
},
|
||||||
|
handleCancel () {
|
||||||
|
this.visible = false
|
||||||
|
this.$emit('cancel')
|
||||||
|
},
|
||||||
|
onForgeStepCode() {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.step-form-wrapper {
|
||||||
|
margin: 0 auto;
|
||||||
|
width: 80%;
|
||||||
|
max-width: 400px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
93
ant-design-jeecg-vue/src/components/tools/UserMenu.vue
Normal file
93
ant-design-jeecg-vue/src/components/tools/UserMenu.vue
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
<template>
|
||||||
|
<div class="user-wrapper">
|
||||||
|
<span class="action">
|
||||||
|
<a-icon type="question-circle-o"></a-icon>
|
||||||
|
</span>
|
||||||
|
<header-notice class="action"/>
|
||||||
|
<a-dropdown>
|
||||||
|
<span class="action ant-dropdown-link user-dropdown-menu">
|
||||||
|
<a-avatar class="avatar" size="small" :src="getAvatar()"/>
|
||||||
|
<span>欢迎您,{{ nickname() }}</span>
|
||||||
|
</span>
|
||||||
|
<a-menu slot="overlay" class="user-dropdown-menu-wrapper">
|
||||||
|
<a-menu-item key="0">
|
||||||
|
<router-link :to="{ name: 'account-center' }">
|
||||||
|
<a-icon type="user"/>
|
||||||
|
<span>个人中心</span>
|
||||||
|
</router-link>
|
||||||
|
</a-menu-item>
|
||||||
|
<a-menu-item key="1">
|
||||||
|
<router-link :to="{ name: 'account-settings' }">
|
||||||
|
<a-icon type="setting"/>
|
||||||
|
<span>账户设置</span>
|
||||||
|
</router-link>
|
||||||
|
</a-menu-item>
|
||||||
|
<!-- <a-menu-item key="2" disabled>
|
||||||
|
<a-icon type="setting"/>
|
||||||
|
<span>测试</span>
|
||||||
|
</a-menu-item>
|
||||||
|
<a-menu-divider/>
|
||||||
|
<a-menu-item key="3">
|
||||||
|
<a href="javascript:;" @click="handleLogout">
|
||||||
|
<a-icon type="logout"/>
|
||||||
|
<span>退出登录</span>
|
||||||
|
</a>
|
||||||
|
</a-menu-item>-->
|
||||||
|
</a-menu>
|
||||||
|
</a-dropdown>
|
||||||
|
<span class="action">
|
||||||
|
<a class="logout_title" href="javascript:;" @click="handleLogout">
|
||||||
|
<a-icon type="logout"/>
|
||||||
|
<span> 退出登录</span>
|
||||||
|
</a>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import HeaderNotice from './HeaderNotice'
|
||||||
|
import { mapActions, mapGetters } from 'vuex'
|
||||||
|
import {imgView} from '@/api/api'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "UserMenu",
|
||||||
|
components: {
|
||||||
|
HeaderNotice
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
...mapActions(["Logout"]),
|
||||||
|
...mapGetters(["nickname", "avatar"]),
|
||||||
|
getAvatar(){
|
||||||
|
console.log('url = '+ imgView+this.avatar())
|
||||||
|
return imgView+this.avatar()
|
||||||
|
},
|
||||||
|
handleLogout() {
|
||||||
|
const that = this
|
||||||
|
|
||||||
|
this.$confirm({
|
||||||
|
title: '提示',
|
||||||
|
content: '真的要注销登录吗 ?',
|
||||||
|
onOk() {
|
||||||
|
return that.Logout({}).then(() => {
|
||||||
|
window.location.reload()
|
||||||
|
}).catch(err => {
|
||||||
|
that.$message.error({
|
||||||
|
title: '错误',
|
||||||
|
description: err.message
|
||||||
|
})
|
||||||
|
})
|
||||||
|
},
|
||||||
|
onCancel() {
|
||||||
|
},
|
||||||
|
});
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.logout_title{
|
||||||
|
color: rgba(0, 0, 0, 0.65);
|
||||||
|
text-decoration:none;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
95
ant-design-jeecg-vue/src/components/tools/setting.js
Normal file
95
ant-design-jeecg-vue/src/components/tools/setting.js
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
import { message } from 'ant-design-vue/es';
|
||||||
|
// import defaultSettings from '../defaultSettings';
|
||||||
|
|
||||||
|
let lessNodesAppended;
|
||||||
|
|
||||||
|
const colorList = [
|
||||||
|
{
|
||||||
|
key: '薄暮', color: '#F5222D',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: '火山', color: '#FA541C',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: '日暮', color: '#FAAD14',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: '明青', color: '#13C2C2',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: '极光绿', color: '#52C41A',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: '拂晓蓝(默认)', color: '#1890FF',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: '极客蓝', color: '#2F54EB',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: '酱紫', color: '#722ED1',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const updateTheme = primaryColor => {
|
||||||
|
// Don't compile less in production!
|
||||||
|
/* if (process.env.NODE_ENV === 'production') {
|
||||||
|
return;
|
||||||
|
} */
|
||||||
|
// Determine if the component is remounted
|
||||||
|
if (!primaryColor) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const hideMessage = message.loading('正在编译主题!', 0);
|
||||||
|
function buildIt() {
|
||||||
|
if (!window.less) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setTimeout(() => {
|
||||||
|
window.less
|
||||||
|
.modifyVars({
|
||||||
|
'@primary-color': primaryColor,
|
||||||
|
})
|
||||||
|
.then(() => {
|
||||||
|
hideMessage();
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
message.error('Failed to update theme');
|
||||||
|
hideMessage();
|
||||||
|
});
|
||||||
|
}, 200);
|
||||||
|
}
|
||||||
|
if (!lessNodesAppended) {
|
||||||
|
// insert less.js and color.less
|
||||||
|
const lessStyleNode = document.createElement('link');
|
||||||
|
const lessConfigNode = document.createElement('script');
|
||||||
|
const lessScriptNode = document.createElement('script');
|
||||||
|
lessStyleNode.setAttribute('rel', 'stylesheet/less');
|
||||||
|
lessStyleNode.setAttribute('href', '/color.less');
|
||||||
|
lessConfigNode.innerHTML = `
|
||||||
|
window.less = {
|
||||||
|
async: true,
|
||||||
|
env: 'production',
|
||||||
|
javascriptEnabled: true
|
||||||
|
};
|
||||||
|
`;
|
||||||
|
lessScriptNode.src = 'https://gw.alipayobjects.com/os/lib/less.js/3.8.1/less.min.js';
|
||||||
|
lessScriptNode.async = true;
|
||||||
|
lessScriptNode.onload = () => {
|
||||||
|
buildIt();
|
||||||
|
lessScriptNode.onload = null;
|
||||||
|
};
|
||||||
|
document.body.appendChild(lessStyleNode);
|
||||||
|
document.body.appendChild(lessConfigNode);
|
||||||
|
document.body.appendChild(lessScriptNode);
|
||||||
|
lessNodesAppended = true;
|
||||||
|
} else {
|
||||||
|
buildIt();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const updateColorWeak = colorWeak => {
|
||||||
|
// document.body.className = colorWeak ? 'colorWeak' : '';
|
||||||
|
colorWeak ? document.body.classList.add('colorWeak') : document.body.classList.remove('colorWeak')
|
||||||
|
};
|
||||||
|
|
||||||
|
export { updateTheme, colorList, updateColorWeak }
|
||||||
394
ant-design-jeecg-vue/src/config/router.config.js
Normal file
394
ant-design-jeecg-vue/src/config/router.config.js
Normal file
@ -0,0 +1,394 @@
|
|||||||
|
import { UserLayout, TabLayout, RouteView, BlankLayout, PageView } from '@/components/layouts'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 走菜单,走权限控制
|
||||||
|
* @type {[null,null]}
|
||||||
|
*/
|
||||||
|
export const asyncRouterMap = [
|
||||||
|
|
||||||
|
{
|
||||||
|
path: '/',
|
||||||
|
name: 'index',
|
||||||
|
component: TabLayout,
|
||||||
|
meta: { title: '首页' },
|
||||||
|
redirect: '/dashboard/workplace',
|
||||||
|
children: [
|
||||||
|
|
||||||
|
//系统管理
|
||||||
|
{
|
||||||
|
path: '/system',
|
||||||
|
name: 'system',
|
||||||
|
redirect: '/isystem/user',
|
||||||
|
component: RouteView,
|
||||||
|
meta: { title: '系统管理', icon: 'dashboard', permission: [ 'dashboard' ] },
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: '/system/user',
|
||||||
|
name: 'user',
|
||||||
|
component: () => import('@/views/system/UserList'),
|
||||||
|
meta: { title: '用户管理', permission: [ 'dashboard' ] }
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
path: '/system/role',
|
||||||
|
name: 'role',
|
||||||
|
component: () => import('@/views/system/RoleList'),
|
||||||
|
meta: { title: '角色管理', permission: [ 'dashboard' ] }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/system/log',
|
||||||
|
name: 'log',
|
||||||
|
component: () => import('@/views/system/LogList'),
|
||||||
|
meta: { title: '日志管理', permission: [ 'dashboard' ] }
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
]
|
||||||
|
},
|
||||||
|
|
||||||
|
// dashboard
|
||||||
|
{
|
||||||
|
path: '/dashboard',
|
||||||
|
name: 'dashboard',
|
||||||
|
redirect: '/dashboard/workplace',
|
||||||
|
component: RouteView,
|
||||||
|
meta: { title: '仪表盘', icon: 'dashboard', permission: [ 'dashboard' ] },
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: '/dashboard/analysis',
|
||||||
|
name: 'Analysis',
|
||||||
|
component: () => import('@/views/dashboard/Analysis'),
|
||||||
|
meta: { title: '分析页', permission: [ 'dashboard' ] }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/dashboard/monitor',
|
||||||
|
name: 'Monitor',
|
||||||
|
hidden: true,
|
||||||
|
component: () => import('@/views/dashboard/Monitor'),
|
||||||
|
meta: { title: '监控页', permission: [ 'dashboard' ] }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/dashboard/workplace',
|
||||||
|
name: 'Workplace',
|
||||||
|
component: () => import('@/views/dashboard/Workplace'),
|
||||||
|
meta: { title: '工作台', permission: [ 'dashboard' ] }
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
|
||||||
|
//jeecg
|
||||||
|
{
|
||||||
|
path: '/jeecg',
|
||||||
|
name: 'jeecg',
|
||||||
|
redirect: '/jeecg',
|
||||||
|
component: RouteView,
|
||||||
|
meta: { title: 'JEECG案例', icon: 'dashboard', permission: [ 'dashboard' ] },
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: '/jeecg/JeecgDemoList',
|
||||||
|
name: 'DemoList',
|
||||||
|
component: () => import('@/views/jeecg/JeecgDemoList'),
|
||||||
|
meta: { title: '列表例子', permission: [ 'dashboard' ] }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/jeecg/helloworld',
|
||||||
|
name: 'helloworld',
|
||||||
|
hidden : true,
|
||||||
|
component: () => import('@/views/jeecg/helloworld'),
|
||||||
|
meta: { title: 'helloworld', permission: [ 'dashboard' ] }
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
// forms
|
||||||
|
{
|
||||||
|
path: '/form',
|
||||||
|
redirect: '/form/basic-form',
|
||||||
|
component: PageView,
|
||||||
|
meta: { title: '表单页', icon: 'form', permission: [ 'form' ] },
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: '/form/base-form',
|
||||||
|
name: 'BaseForm',
|
||||||
|
component: () => import('@/views/form/BasicForm'),
|
||||||
|
meta: { title: '基础表单', permission: [ 'form' ] }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/form/step-form',
|
||||||
|
name: 'StepForm',
|
||||||
|
component: () => import('@/views/form/stepForm/StepForm'),
|
||||||
|
meta: { title: '分步表单', permission: [ 'form' ] }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/form/advanced-form',
|
||||||
|
name: 'AdvanceForm',
|
||||||
|
component: () => import('@/views/form/advancedForm/AdvancedForm'),
|
||||||
|
meta: { title: '高级表单', permission: [ 'form' ] }
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
|
||||||
|
// list
|
||||||
|
{
|
||||||
|
path: '/list',
|
||||||
|
name: 'list',
|
||||||
|
component: PageView,
|
||||||
|
redirect: '/list/query-list',
|
||||||
|
meta: { title: '列表页', icon: 'table', permission: [ 'table' ] },
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: '/list/query-list',
|
||||||
|
name: 'QueryList',
|
||||||
|
component: () => import('@/views/list/TableList'),
|
||||||
|
meta: { title: '查询表格', permission: [ 'table' ] }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/list/edit-table',
|
||||||
|
name: 'EditList',
|
||||||
|
component: () => import('@/views/list/TableInnerEditList'),
|
||||||
|
meta: { title: '内联编辑表格', permission: [ 'table' ] }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/list/user-list',
|
||||||
|
name: 'UserList',
|
||||||
|
component: () => import('@/views/list/UserList'),
|
||||||
|
meta: { title: '用户列表', permission: [ 'table' ] }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/list/role-list',
|
||||||
|
name: 'RoleList',
|
||||||
|
component: () => import('@/views/list/RoleList'),
|
||||||
|
meta: { title: '角色列表', permission: [ 'table' ] }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/list/permission-list',
|
||||||
|
name: 'PermissionList',
|
||||||
|
component: () => import('@/views/list/PermissionList'),
|
||||||
|
meta: { title: '权限列表', permission: [ 'table' ] }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/list/basic-list',
|
||||||
|
name: 'BasicList',
|
||||||
|
component: () => import('@/views/list/StandardList'),
|
||||||
|
meta: { title: '标准列表', permission: [ 'table' ] }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/list/card',
|
||||||
|
name: 'CardList',
|
||||||
|
component: () => import('@/views/list/CardList'),
|
||||||
|
meta: { title: '卡片列表', permission: [ 'table' ] }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/list/search',
|
||||||
|
name: 'SearchList',
|
||||||
|
component: () => import('@/views/list/search/SearchLayout'),
|
||||||
|
redirect: '/list/search/article',
|
||||||
|
meta: { title: '搜索列表', permission: [ 'table' ] },
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: '/list/search/article',
|
||||||
|
name: 'SearchArticles',
|
||||||
|
component: () => import('../views/list/TableList'),
|
||||||
|
meta: { title: '搜索列表(文章)', permission: [ 'table' ] }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/list/search/project',
|
||||||
|
name: 'SearchProjects',
|
||||||
|
component: () => import('../views/list/TableList'),
|
||||||
|
meta: { title: '搜索列表(项目)', permission: [ 'table' ] }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/list/search/application',
|
||||||
|
name: 'SearchApplications',
|
||||||
|
component: () => import('../views/list/TableList'),
|
||||||
|
meta: { title: '搜索列表(应用)', permission: [ 'table' ] }
|
||||||
|
},
|
||||||
|
]
|
||||||
|
},
|
||||||
|
]
|
||||||
|
},
|
||||||
|
|
||||||
|
// profile
|
||||||
|
{
|
||||||
|
path: '/profile',
|
||||||
|
name: 'profile',
|
||||||
|
component: RouteView,
|
||||||
|
redirect: '/profile/basic',
|
||||||
|
meta: { title: '详情页', icon: 'profile', permission: [ 'profile' ] },
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: '/profile/basic',
|
||||||
|
name: 'ProfileBasic',
|
||||||
|
component: () => import('@/views/profile/basic/Index'),
|
||||||
|
meta: { title: '基础详情页', permission: [ 'profile' ] }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/profile/advanced',
|
||||||
|
name: 'ProfileAdvanced',
|
||||||
|
component: () => import('@/views/profile/advanced/Advanced'),
|
||||||
|
meta: { title: '高级详情页', permission: [ 'profile' ] }
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
|
||||||
|
// result
|
||||||
|
{
|
||||||
|
path: '/result',
|
||||||
|
name: 'result',
|
||||||
|
component: PageView,
|
||||||
|
redirect: '/result/success',
|
||||||
|
meta: { title: '结果页', icon: 'check-circle-o', permission: [ 'result' ] },
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: '/result/success',
|
||||||
|
name: 'ResultSuccess',
|
||||||
|
component: () => import(/* webpackChunkName: "result" */ '@/views/result/Success'),
|
||||||
|
meta: { title: '成功', hiddenHeaderContent: true, permission: [ 'result' ] }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/result/fail',
|
||||||
|
name: 'ResultFail',
|
||||||
|
component: () => import(/* webpackChunkName: "result" */ '@/views/result/Error'),
|
||||||
|
meta: { title: '失败', hiddenHeaderContent: true, permission: [ 'result' ] }
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
|
||||||
|
// Exception
|
||||||
|
{
|
||||||
|
path: '/exception',
|
||||||
|
name: 'exception',
|
||||||
|
component: RouteView,
|
||||||
|
redirect: '/exception/403',
|
||||||
|
meta: { title: '异常页', icon: 'warning', permission: [ 'exception' ] },
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: '/exception/403',
|
||||||
|
name: 'Exception403',
|
||||||
|
component: () => import(/* webpackChunkName: "fail" */ '@/views/exception/403'),
|
||||||
|
meta: { title: '403', permission: [ 'exception' ] }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/exception/404',
|
||||||
|
name: 'Exception404',
|
||||||
|
component: () => import(/* webpackChunkName: "fail" */ '@/views/exception/404'),
|
||||||
|
meta: { title: '404', permission: [ 'exception' ] }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/exception/500',
|
||||||
|
name: 'Exception500',
|
||||||
|
component: () => import(/* webpackChunkName: "fail" */ '@/views/exception/500'),
|
||||||
|
meta: { title: '500', permission: [ 'exception' ] }
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
|
||||||
|
// account
|
||||||
|
{
|
||||||
|
path: '/account',
|
||||||
|
component: RouteView,
|
||||||
|
name: 'account',
|
||||||
|
meta: { title: '个人页', icon: 'user', keepAlive: true, permission: [ 'user' ] },
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: '/account/center',
|
||||||
|
name: 'center',
|
||||||
|
component: () => import('@/views/account/center/Index'),
|
||||||
|
meta: { title: '个人中心', keepAlive: true, permission: [ 'user' ] }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/account/settings',
|
||||||
|
name: 'settings',
|
||||||
|
component: () => import('@/views/account/settings/Index'),
|
||||||
|
meta: { title: '个人设置', hideHeader: true, keepAlive: true, permission: [ 'user' ] },
|
||||||
|
redirect: '/account/settings/base',
|
||||||
|
alwaysShow: true,
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: '/account/settings/base',
|
||||||
|
name: 'BaseSettings',
|
||||||
|
component: () => import('@/views/account/settings/BaseSetting'),
|
||||||
|
meta: { title: '基本设置', hidden: true, keepAlive: true, permission: [ 'user' ] }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/account/settings/security',
|
||||||
|
name: 'SecuritySettings',
|
||||||
|
component: () => import('@/views/account/settings/Security'),
|
||||||
|
meta: { title: '安全设置', hidden: true, keepAlive: true, permission: [ 'user' ] }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/account/settings/custom',
|
||||||
|
name: 'CustomSettings',
|
||||||
|
component: () => import('@/views/account/settings/Custom'),
|
||||||
|
meta: { title: '个性化设置', hidden: true, keepAlive: true, permission: [ 'user' ] }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/account/settings/binding',
|
||||||
|
name: 'BindingSettings',
|
||||||
|
component: () => import('@/views/account/settings/Binding'),
|
||||||
|
meta: { title: '账户绑定', hidden: true, keepAlive: true, permission: [ 'user' ] }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/account/settings/notification',
|
||||||
|
name: 'NotificationSettings',
|
||||||
|
component: () => import('@/views/account/settings/Notification'),
|
||||||
|
meta: { title: '新消息通知', hidden: true, keepAlive: true, permission: [ 'user' ] }
|
||||||
|
},
|
||||||
|
]
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '*', redirect: '/404', hidden: true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 基础路由
|
||||||
|
* @type { *[] }
|
||||||
|
*/
|
||||||
|
export const constantRouterMap = [
|
||||||
|
{
|
||||||
|
path: '/user',
|
||||||
|
component: UserLayout,
|
||||||
|
redirect: '/user/login',
|
||||||
|
hidden: true,
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: 'login',
|
||||||
|
name: 'login',
|
||||||
|
component: () => import(/* webpackChunkName: "user" */ '@/views/user/Login')
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'register',
|
||||||
|
name: 'register',
|
||||||
|
component: () => import(/* webpackChunkName: "user" */ '@/views/user/Register')
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'register-result',
|
||||||
|
name: 'registerResult',
|
||||||
|
component: () => import(/* webpackChunkName: "user" */ '@/views/user/RegisterResult')
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
path: '/test',
|
||||||
|
component: BlankLayout,
|
||||||
|
redirect: '/test/home',
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: 'home',
|
||||||
|
name: 'TestHome',
|
||||||
|
component: () => import('@/views/Home')
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
path: '/404',
|
||||||
|
component: () => import(/* webpackChunkName: "fail" */ '@/views/exception/404')
|
||||||
|
},
|
||||||
|
|
||||||
|
]
|
||||||
31
ant-design-jeecg-vue/src/defaultSettings.js
Normal file
31
ant-design-jeecg-vue/src/defaultSettings.js
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
/**
|
||||||
|
* 项目默认配置项
|
||||||
|
* primaryColor - 默认主题色
|
||||||
|
* navTheme - sidebar theme ['dark', 'light'] 两种主题
|
||||||
|
* colorWeak - 色盲模式
|
||||||
|
* layout - 整体布局方式 ['sidemenu', 'topmenu'] 两种布局
|
||||||
|
* fixedHeader - 固定 Header : boolean
|
||||||
|
* fixSiderbar - 固定左侧菜单栏 : boolean
|
||||||
|
* autoHideHeader - 向下滚动时,隐藏 Header : boolean
|
||||||
|
* contentWidth - 内容区布局: 流式 | 固定
|
||||||
|
*
|
||||||
|
* storageOptions: {} - Vue-ls 插件配置项 (localStorage/sessionStorage)
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
export default {
|
||||||
|
primaryColor: '#1890FF', // primary color of ant design
|
||||||
|
navTheme: 'light', // theme for nav menu
|
||||||
|
layout: 'sidemenu', // nav menu position: sidemenu or topmenu
|
||||||
|
contentWidth: 'Fixed', // layout of content: Fluid or Fixed, only works when layout is topmenu
|
||||||
|
fixedHeader: false, // sticky header
|
||||||
|
fixSiderbar: false, // sticky siderbar
|
||||||
|
autoHideHeader: false, // auto hide header
|
||||||
|
colorWeak: false,
|
||||||
|
// vue-ls options
|
||||||
|
storageOptions: {
|
||||||
|
namespace: 'pro__', // key prefix
|
||||||
|
name: 'ls', // name variable Vue.[ls] or this.[$ls],
|
||||||
|
storage: 'local', // storage name session, local, memory
|
||||||
|
}
|
||||||
|
}
|
||||||
61
ant-design-jeecg-vue/src/main.js
Normal file
61
ant-design-jeecg-vue/src/main.js
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
import Vue from 'vue'
|
||||||
|
import App from './App.vue'
|
||||||
|
import Storage from 'vue-ls'
|
||||||
|
import router from './router'
|
||||||
|
import store from './store/'
|
||||||
|
|
||||||
|
import { VueAxios } from "@/utils/request"
|
||||||
|
|
||||||
|
import Antd from 'ant-design-vue'
|
||||||
|
import Viser from 'viser-vue'
|
||||||
|
import 'ant-design-vue/dist/antd.less'; // or 'ant-design-vue/dist/antd.less'
|
||||||
|
|
||||||
|
import '@/permission' // permission control
|
||||||
|
import '@/utils/filter' // base filter
|
||||||
|
import DictSelectTag from './components/dict/index.js'
|
||||||
|
import Print from 'vue-print-nb'
|
||||||
|
/*import '@babel/polyfill'*/
|
||||||
|
|
||||||
|
import {
|
||||||
|
ACCESS_TOKEN,
|
||||||
|
DEFAULT_COLOR,
|
||||||
|
DEFAULT_THEME,
|
||||||
|
DEFAULT_LAYOUT_MODE,
|
||||||
|
DEFAULT_COLOR_WEAK,
|
||||||
|
SIDEBAR_TYPE,
|
||||||
|
DEFAULT_FIXED_HEADER,
|
||||||
|
DEFAULT_FIXED_HEADER_HIDDEN,
|
||||||
|
DEFAULT_FIXED_SIDEMENU,
|
||||||
|
DEFAULT_CONTENT_WIDTH_TYPE
|
||||||
|
} from "@/store/mutation-types"
|
||||||
|
import config from '@/defaultSettings'
|
||||||
|
|
||||||
|
import hasPermission from '@/utils/hasPermission'
|
||||||
|
|
||||||
|
Vue.config.productionTip = false
|
||||||
|
|
||||||
|
Vue.use(Storage, config.storageOptions)
|
||||||
|
Vue.use(Antd)
|
||||||
|
Vue.use(VueAxios, router)
|
||||||
|
Vue.use(Viser)
|
||||||
|
Vue.use(hasPermission)
|
||||||
|
Vue.use(DictSelectTag)
|
||||||
|
Vue.use(Print)
|
||||||
|
|
||||||
|
new Vue({
|
||||||
|
router,
|
||||||
|
store,
|
||||||
|
mounted () {
|
||||||
|
store.commit('SET_SIDEBAR_TYPE', Vue.ls.get(SIDEBAR_TYPE, true))
|
||||||
|
store.commit('TOGGLE_THEME', Vue.ls.get(DEFAULT_THEME, config.navTheme))
|
||||||
|
store.commit('TOGGLE_LAYOUT_MODE', Vue.ls.get(DEFAULT_LAYOUT_MODE, config.layout))
|
||||||
|
store.commit('TOGGLE_FIXED_HEADER', Vue.ls.get(DEFAULT_FIXED_HEADER, config.fixedHeader))
|
||||||
|
store.commit('TOGGLE_FIXED_SIDERBAR', Vue.ls.get(DEFAULT_FIXED_SIDEMENU, config.fixSiderbar))
|
||||||
|
store.commit('TOGGLE_CONTENT_WIDTH', Vue.ls.get(DEFAULT_CONTENT_WIDTH_TYPE, config.contentWidth))
|
||||||
|
store.commit('TOGGLE_FIXED_HEADER_HIDDEN', Vue.ls.get(DEFAULT_FIXED_HEADER_HIDDEN, config.autoHideHeader))
|
||||||
|
store.commit('TOGGLE_WEAK', Vue.ls.get(DEFAULT_COLOR_WEAK, config.colorWeak))
|
||||||
|
store.commit('TOGGLE_COLOR', Vue.ls.get(DEFAULT_COLOR, config.primaryColor))
|
||||||
|
store.commit('SET_TOKEN', Vue.ls.get(ACCESS_TOKEN))
|
||||||
|
},
|
||||||
|
render: h => h(App)
|
||||||
|
}).$mount('#app')
|
||||||
75
ant-design-jeecg-vue/src/permission.js
Normal file
75
ant-design-jeecg-vue/src/permission.js
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
import Vue from 'vue'
|
||||||
|
import router from './router'
|
||||||
|
import store from './store'
|
||||||
|
import NProgress from 'nprogress' // progress bar
|
||||||
|
import 'nprogress/nprogress.css' // progress bar style
|
||||||
|
import notification from 'ant-design-vue/es/notification'
|
||||||
|
import { ACCESS_TOKEN } from '@/store/mutation-types'
|
||||||
|
import { generateIndexRouter } from "@/utils/util"
|
||||||
|
|
||||||
|
NProgress.configure({ showSpinner: false }) // NProgress Configuration
|
||||||
|
|
||||||
|
const whiteList = ['/user/login', '/user/register', '/user/register-result'] // no redirect whitelist
|
||||||
|
|
||||||
|
router.beforeEach((to, from, next) => {
|
||||||
|
NProgress.start() // start progress bar
|
||||||
|
|
||||||
|
if (Vue.ls.get(ACCESS_TOKEN)) {
|
||||||
|
/* has token */
|
||||||
|
if (to.path === '/user/login') {
|
||||||
|
next({ path: '/dashboard/workplace' })
|
||||||
|
NProgress.done()
|
||||||
|
} else {
|
||||||
|
if (store.getters.permissionList.length === 0) {
|
||||||
|
store.dispatch('GetPermissionList').then(res => {
|
||||||
|
const menuData = res.result;
|
||||||
|
console.log(res.message)
|
||||||
|
if (menuData === null || menuData === "" || menuData === undefined) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let constRoutes = [];
|
||||||
|
constRoutes = generateIndexRouter(menuData);
|
||||||
|
// 添加主界面路由
|
||||||
|
store.dispatch('UpdateAppRouter', { constRoutes }).then(() => {
|
||||||
|
// 根据roles权限生成可访问的路由表
|
||||||
|
// 动态添加可访问路由表
|
||||||
|
router.addRoutes(store.getters.addRouters)
|
||||||
|
const redirect = decodeURIComponent(from.query.redirect || to.path)
|
||||||
|
if (to.path === redirect) {
|
||||||
|
// hack方法 确保addRoutes已完成 ,set the replace: true so the navigation will not leave a history record
|
||||||
|
next({ ...to, replace: true })
|
||||||
|
} else {
|
||||||
|
// 跳转到目的路由
|
||||||
|
next({ path: redirect })
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
notification.error({
|
||||||
|
message: '系统提示',
|
||||||
|
description: '请求用户信息失败,请重试!'
|
||||||
|
})
|
||||||
|
// update-begin- --- author:scott ------ date:20190225 ---- for:Token失效跳转登录逻辑修改----
|
||||||
|
// store.dispatch('Logout').then(() => {
|
||||||
|
// next({ path: '/user/login', query: { redirect: to.fullPath } })
|
||||||
|
// })
|
||||||
|
// update-end- --- author:scott ------ date:20190225 ---- for:Token失效跳转登录逻辑修改----
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
next()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (whiteList.indexOf(to.path) !== -1) {
|
||||||
|
// 在免登录白名单,直接进入
|
||||||
|
next()
|
||||||
|
} else {
|
||||||
|
next({ path: '/user/login', query: { redirect: to.fullPath } })
|
||||||
|
NProgress.done() // if current page is login will not trigger afterEach hook, so manually handle it
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
router.afterEach(() => {
|
||||||
|
NProgress.done() // finish progress bar
|
||||||
|
})
|
||||||
139
ant-design-jeecg-vue/src/router/README.md
Normal file
139
ant-design-jeecg-vue/src/router/README.md
Normal file
@ -0,0 +1,139 @@
|
|||||||
|
路由/菜单说明
|
||||||
|
====
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
配置文件路径
|
||||||
|
----
|
||||||
|
|
||||||
|
`@/config/router.config.js`
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
格式和说明
|
||||||
|
----
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
/**
|
||||||
|
* 路由配置说明:
|
||||||
|
* 建议:sider menu 请不要超过三级菜单,若超过三级菜单,则应该设计为顶部主菜单 配合左侧次级菜单
|
||||||
|
*
|
||||||
|
**/
|
||||||
|
{
|
||||||
|
redirect: noredirect,
|
||||||
|
name: 'router-name',
|
||||||
|
hidden: true,
|
||||||
|
meta: {
|
||||||
|
title: 'title',
|
||||||
|
icon: 'a-icon',
|
||||||
|
keepAlive: true,
|
||||||
|
hiddenHeaderContent: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
`{ Route }` 对象
|
||||||
|
|
||||||
|
| 参数 | 说明 | 类型 | 默认值 |
|
||||||
|
| -------- | ----------------------------------------- | ------- | ------ |
|
||||||
|
| hidden | 控制路由是否显示在 sidebar | boolean | falase |
|
||||||
|
| redirect | 重定向地址, 访问这个路由时,自定进行重定向 | string | - |
|
||||||
|
| name | 路由名称, 建议设置,且不能重名 | string | - |
|
||||||
|
| meta | 路由元信息(路由附带扩展信息) | object | {} |
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
`{ Meta }` 路由元信息对象
|
||||||
|
|
||||||
|
| 参数 | 说明 | 类型 | 默认值 |
|
||||||
|
| ------------------- | ------------------------------------------------------------ | ------- | ------ |
|
||||||
|
| title | 路由标题, 用于显示面包屑, 页面标题 *推荐设置 | string | - |
|
||||||
|
| icon | 路由在 menu 上显示的图标 | string | - |
|
||||||
|
| keepAlive | 缓存该路由 | boolean | false |
|
||||||
|
| hiddenHeaderContent | *特殊 隐藏 [PageHeader](https://github.com/sendya/ant-design-pro-vue/blob/master/src/components/layout/PageHeader.vue#L14) 组件中的页面带的 面包屑和页面标题栏 | boolean | false |
|
||||||
|
| permission | 与项目提供的权限拦截匹配的权限,如果不匹配,则会被禁止访问该路由页面 | array | [] |
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
路由例子
|
||||||
|
----
|
||||||
|
|
||||||
|
```ecmascript 6
|
||||||
|
const asyncRouterMap = [
|
||||||
|
{
|
||||||
|
path: '/',
|
||||||
|
name: 'index',
|
||||||
|
component: BasicLayout,
|
||||||
|
meta: { title: '首页' },
|
||||||
|
redirect: '/dashboard/analysis',
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: '/dashboard',
|
||||||
|
component: Layout,
|
||||||
|
name: 'dashboard',
|
||||||
|
redirect: '/dashboard/workplace',
|
||||||
|
meta: {title: '仪表盘', icon: 'dashboard', permission: ['dashboard']},
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: '/dashboard/analysis',
|
||||||
|
name: 'Analysis',
|
||||||
|
component: () => import('@/views/dashboard/Analysis'),
|
||||||
|
meta: {title: '分析页', permission: ['dashboard']}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/dashboard/monitor',
|
||||||
|
name: 'Monitor',
|
||||||
|
hidden: true,
|
||||||
|
component: () => import('@/views/dashboard/Monitor'),
|
||||||
|
meta: {title: '监控页', permission: ['dashboard']}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/dashboard/workplace',
|
||||||
|
name: 'Workplace',
|
||||||
|
component: () => import('@/views/dashboard/Workplace'),
|
||||||
|
meta: {title: '工作台', permission: ['dashboard']}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
|
||||||
|
// result
|
||||||
|
{
|
||||||
|
path: '/result',
|
||||||
|
name: 'result',
|
||||||
|
component: PageView,
|
||||||
|
redirect: '/result/success',
|
||||||
|
meta: { title: '结果页', icon: 'check-circle-o', permission: [ 'result' ] },
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: '/result/success',
|
||||||
|
name: 'ResultSuccess',
|
||||||
|
component: () => import(/* webpackChunkName: "result" */ '@/views/result/Success'),
|
||||||
|
// 该页面隐藏面包屑和页面标题栏
|
||||||
|
meta: { title: '成功', hiddenHeaderContent: true, permission: [ 'result' ] }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/result/fail',
|
||||||
|
name: 'ResultFail',
|
||||||
|
component: () => import(/* webpackChunkName: "result" */ '@/views/result/Error'),
|
||||||
|
// 该页面隐藏面包屑和页面标题栏
|
||||||
|
meta: { title: '失败', hiddenHeaderContent: true, permission: [ 'result' ] }
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
...
|
||||||
|
]
|
||||||
|
},
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
> 1. 请注意 `component: () => import('..') ` 方式引入路由的页面组件为 懒加载模式。具体可以看 [Vue 官方文档](https://router.vuejs.org/zh/guide/advanced/lazy-loading.html)
|
||||||
|
> 2. 增加新的路由应该增加在 '/' (index) 路由的 `children` 内
|
||||||
|
> 3. `permission` 可以进行自定义修改,只需要对这个模块进行自定义修改即可 [src/store/modules/permission.js#L10](https://github.com/sendya/ant-design-pro-vue/blob/master/src/store/modules/permission.js#L10)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
附权限路由结构:
|
||||||
|
|
||||||
|

|
||||||
12
ant-design-jeecg-vue/src/router/index.js
Normal file
12
ant-design-jeecg-vue/src/router/index.js
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
import Vue from 'vue'
|
||||||
|
import Router from 'vue-router'
|
||||||
|
import { constantRouterMap } from '@/config/router.config'
|
||||||
|
|
||||||
|
Vue.use(Router)
|
||||||
|
|
||||||
|
export default new Router({
|
||||||
|
mode: 'history',
|
||||||
|
base: process.env.BASE_URL,
|
||||||
|
scrollBehavior: () => ({ y: 0 }),
|
||||||
|
routes: constantRouterMap
|
||||||
|
})
|
||||||
17
ant-design-jeecg-vue/src/store/getters.js
Normal file
17
ant-design-jeecg-vue/src/store/getters.js
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
import Vue from 'vue'
|
||||||
|
import { USER_INFO} from "@/store/mutation-types"
|
||||||
|
const getters = {
|
||||||
|
device: state => state.app.device,
|
||||||
|
theme: state => state.app.theme,
|
||||||
|
color: state => state.app.color,
|
||||||
|
token: state => state.user.token,
|
||||||
|
avatar: state => {state.user.avatar = Vue.ls.get(USER_INFO).avatar; return state.user.avatar},
|
||||||
|
username: state => state.user.username,
|
||||||
|
nickname: state => {state.user.realname = Vue.ls.get(USER_INFO).realname; return state.user.realname},
|
||||||
|
welcome: state => state.user.welcome,
|
||||||
|
permissionList: state => state.user.permissionList,
|
||||||
|
userInfo: state => {state.user.info = Vue.ls.get(USER_INFO); return state.user.info},
|
||||||
|
addRouters: state => state.permission.addRouters
|
||||||
|
}
|
||||||
|
|
||||||
|
export default getters
|
||||||
27
ant-design-jeecg-vue/src/store/index.js
Normal file
27
ant-design-jeecg-vue/src/store/index.js
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
import Vue from 'vue'
|
||||||
|
import Vuex from 'vuex'
|
||||||
|
|
||||||
|
import app from './modules/app'
|
||||||
|
import user from './modules/user'
|
||||||
|
import permission from './modules/permission'
|
||||||
|
import getters from './getters'
|
||||||
|
|
||||||
|
Vue.use(Vuex)
|
||||||
|
|
||||||
|
export default new Vuex.Store({
|
||||||
|
modules: {
|
||||||
|
app,
|
||||||
|
user,
|
||||||
|
permission
|
||||||
|
},
|
||||||
|
state: {
|
||||||
|
|
||||||
|
},
|
||||||
|
mutations: {
|
||||||
|
|
||||||
|
},
|
||||||
|
actions: {
|
||||||
|
|
||||||
|
},
|
||||||
|
getters
|
||||||
|
})
|
||||||
121
ant-design-jeecg-vue/src/store/modules/app.js
Normal file
121
ant-design-jeecg-vue/src/store/modules/app.js
Normal file
@ -0,0 +1,121 @@
|
|||||||
|
import Vue from 'vue'
|
||||||
|
import {
|
||||||
|
SIDEBAR_TYPE,
|
||||||
|
DEFAULT_THEME,
|
||||||
|
DEFAULT_LAYOUT_MODE,
|
||||||
|
DEFAULT_COLOR,
|
||||||
|
DEFAULT_COLOR_WEAK,
|
||||||
|
DEFAULT_FIXED_HEADER,
|
||||||
|
DEFAULT_FIXED_SIDEMENU,
|
||||||
|
DEFAULT_FIXED_HEADER_HIDDEN,
|
||||||
|
DEFAULT_CONTENT_WIDTH_TYPE
|
||||||
|
} from "@/store/mutation-types"
|
||||||
|
|
||||||
|
const app = {
|
||||||
|
state: {
|
||||||
|
sidebar: {
|
||||||
|
opened: true,
|
||||||
|
withoutAnimation: false
|
||||||
|
},
|
||||||
|
device: 'desktop',
|
||||||
|
theme: '',
|
||||||
|
layout: '',
|
||||||
|
contentWidth: '',
|
||||||
|
fixedHeader: false,
|
||||||
|
fixSiderbar: false,
|
||||||
|
autoHideHeader: false,
|
||||||
|
color: null,
|
||||||
|
weak: false,
|
||||||
|
multipage: true
|
||||||
|
},
|
||||||
|
mutations: {
|
||||||
|
SET_SIDEBAR_TYPE: (state, type) => {
|
||||||
|
state.sidebar.opened = type
|
||||||
|
Vue.ls.set(SIDEBAR_TYPE, type)
|
||||||
|
},
|
||||||
|
CLOSE_SIDEBAR: (state, withoutAnimation) => {
|
||||||
|
Vue.ls.set(SIDEBAR_TYPE, true)
|
||||||
|
state.sidebar.opened = false
|
||||||
|
state.sidebar.withoutAnimation = withoutAnimation
|
||||||
|
},
|
||||||
|
TOGGLE_DEVICE: (state, device) => {
|
||||||
|
state.device = device
|
||||||
|
},
|
||||||
|
TOGGLE_THEME: (state, theme) => {
|
||||||
|
// setStore('_DEFAULT_THEME', theme)
|
||||||
|
Vue.ls.set(DEFAULT_THEME, theme)
|
||||||
|
state.theme = theme
|
||||||
|
},
|
||||||
|
TOGGLE_LAYOUT_MODE: (state, layout) => {
|
||||||
|
Vue.ls.set(DEFAULT_LAYOUT_MODE, layout)
|
||||||
|
state.layout = layout
|
||||||
|
},
|
||||||
|
TOGGLE_FIXED_HEADER: (state, fixed) => {
|
||||||
|
Vue.ls.set(DEFAULT_FIXED_HEADER, fixed)
|
||||||
|
state.fixedHeader = fixed
|
||||||
|
},
|
||||||
|
TOGGLE_FIXED_SIDERBAR: (state, fixed) => {
|
||||||
|
Vue.ls.set(DEFAULT_FIXED_SIDEMENU, fixed)
|
||||||
|
state.fixSiderbar = fixed
|
||||||
|
},
|
||||||
|
TOGGLE_FIXED_HEADER_HIDDEN: (state, show) => {
|
||||||
|
Vue.ls.set(DEFAULT_FIXED_HEADER_HIDDEN, show)
|
||||||
|
state.autoHideHeader = show
|
||||||
|
},
|
||||||
|
TOGGLE_CONTENT_WIDTH: (state, type) => {
|
||||||
|
Vue.ls.set(DEFAULT_CONTENT_WIDTH_TYPE, type)
|
||||||
|
state.contentWidth = type
|
||||||
|
},
|
||||||
|
TOGGLE_COLOR: (state, color) => {
|
||||||
|
Vue.ls.set(DEFAULT_COLOR, color)
|
||||||
|
state.color = color
|
||||||
|
},
|
||||||
|
TOGGLE_WEAK: (state, flag) => {
|
||||||
|
Vue.ls.set(DEFAULT_COLOR_WEAK, flag)
|
||||||
|
state.weak = flag
|
||||||
|
},
|
||||||
|
setMultipage (state, multipage) {
|
||||||
|
state.multipage = multipage
|
||||||
|
}
|
||||||
|
},
|
||||||
|
actions: {
|
||||||
|
setSidebar: ({ commit }, type) => {
|
||||||
|
commit('SET_SIDEBAR_TYPE', type)
|
||||||
|
},
|
||||||
|
CloseSidebar({ commit }, { withoutAnimation }) {
|
||||||
|
commit('CLOSE_SIDEBAR', withoutAnimation)
|
||||||
|
},
|
||||||
|
ToggleDevice({ commit }, device) {
|
||||||
|
commit('TOGGLE_DEVICE', device)
|
||||||
|
},
|
||||||
|
ToggleTheme({ commit }, theme) {
|
||||||
|
commit('TOGGLE_THEME', theme)
|
||||||
|
},
|
||||||
|
ToggleLayoutMode({ commit }, mode) {
|
||||||
|
commit('TOGGLE_LAYOUT_MODE', mode)
|
||||||
|
},
|
||||||
|
ToggleFixedHeader({ commit }, fixedHeader) {
|
||||||
|
if (!fixedHeader) {
|
||||||
|
commit('TOGGLE_FIXED_HEADER_HIDDEN', false)
|
||||||
|
}
|
||||||
|
commit('TOGGLE_FIXED_HEADER', fixedHeader)
|
||||||
|
},
|
||||||
|
ToggleFixSiderbar({ commit }, fixSiderbar) {
|
||||||
|
commit( 'TOGGLE_FIXED_SIDERBAR', fixSiderbar)
|
||||||
|
},
|
||||||
|
ToggleFixedHeaderHidden({ commit }, show) {
|
||||||
|
commit('TOGGLE_FIXED_HEADER_HIDDEN', show)
|
||||||
|
},
|
||||||
|
ToggleContentWidth({ commit }, type) {
|
||||||
|
commit('TOGGLE_CONTENT_WIDTH', type)
|
||||||
|
},
|
||||||
|
ToggleColor({ commit }, color) {
|
||||||
|
commit('TOGGLE_COLOR', color)
|
||||||
|
},
|
||||||
|
ToggleWeak({ commit }, weakFlag) {
|
||||||
|
commit('TOGGLE_WEAK', weakFlag)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default app
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user