mirror of https://github.com/jeecgboot/jeecg-boot
JeecgBoot 3.3.0 版本发布,基于代码生成器的企业级低代码平台
parent
55201e82eb
commit
0cbdc092d1
41
README.md
41
README.md
|
@ -7,19 +7,19 @@
|
||||||
JEECG BOOT 低代码开发平台(前后端分离版本)
|
JEECG BOOT 低代码开发平台(前后端分离版本)
|
||||||
===============
|
===============
|
||||||
|
|
||||||
当前最新版本: 3.2.0(发布日期:2022-04-25)
|
当前最新版本: 3.3.0(发布日期:2022-07-25)
|
||||||
|
|
||||||
|
|
||||||
[![AUR](https://img.shields.io/badge/license-Apache%20License%202.0-blue.svg)](https://github.com/zhangdaiscott/jeecg-boot/blob/master/LICENSE)
|
[![AUR](https://img.shields.io/badge/license-Apache%20License%202.0-blue.svg)](https://github.com/zhangdaiscott/jeecg-boot/blob/master/LICENSE)
|
||||||
[![](https://img.shields.io/badge/Author-北京国炬软件-orange.svg)](http://www.jeecg.com)
|
[![](https://img.shields.io/badge/Author-北京国炬软件-orange.svg)](http://www.jeecg.com)
|
||||||
[![](https://img.shields.io/badge/Blog-官方博客-blue.svg)](https://jeecg.blog.csdn.net)
|
[![](https://img.shields.io/badge/Blog-官方博客-blue.svg)](https://my.oschina.net/jeecg)
|
||||||
[![](https://img.shields.io/badge/version-3.2.0-brightgreen.svg)](https://github.com/zhangdaiscott/jeecg-boot)
|
[![](https://img.shields.io/badge/version-3.3.0-brightgreen.svg)](https://github.com/zhangdaiscott/jeecg-boot)
|
||||||
[![GitHub stars](https://img.shields.io/github/stars/zhangdaiscott/jeecg-boot.svg?style=social&label=Stars)](https://github.com/zhangdaiscott/jeecg-boot)
|
[![GitHub stars](https://img.shields.io/github/stars/zhangdaiscott/jeecg-boot.svg?style=social&label=Stars)](https://github.com/zhangdaiscott/jeecg-boot)
|
||||||
[![GitHub forks](https://img.shields.io/github/forks/zhangdaiscott/jeecg-boot.svg?style=social&label=Fork)](https://github.com/zhangdaiscott/jeecg-boot)
|
[![GitHub forks](https://img.shields.io/github/forks/zhangdaiscott/jeecg-boot.svg?style=social&label=Fork)](https://github.com/zhangdaiscott/jeecg-boot)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
项目介绍:
|
项目介绍
|
||||||
-----------------------------------
|
-----------------------------------
|
||||||
|
|
||||||
<h3 align="center">Java Low Code Platform for Enterprise web applications</h3>
|
<h3 align="center">Java Low Code Platform for Enterprise web applications</h3>
|
||||||
|
@ -34,12 +34,21 @@ JeecgBoot 提供了一系列`低代码模块`,实现在线开发`真正的零
|
||||||
`JEECG业务流程:` 采用工作流来实现、扩展出任务接口,供开发编写业务逻辑,表单提供多种解决方案: 表单设计器、online配置表单、编码表单。同时实现了流程与表单的分离设计(松耦合)、并支持任务节点灵活配置,既保证了公司流程的保密性,又减少了开发人员的工作量。
|
`JEECG业务流程:` 采用工作流来实现、扩展出任务接口,供开发编写业务逻辑,表单提供多种解决方案: 表单设计器、online配置表单、编码表单。同时实现了流程与表单的分离设计(松耦合)、并支持任务节点灵活配置,既保证了公司流程的保密性,又减少了开发人员的工作量。
|
||||||
|
|
||||||
|
|
||||||
|
项目源码
|
||||||
|
-----------------------------------
|
||||||
|
| 仓库 |前端源码Vue3版 | 前端源码Vue2版 | 后端源码 |
|
||||||
|
|-|-|-|-|
|
||||||
|
| Github | [jeecgboot-vue3](https://github.com/jeecgboot/jeecgboot-vue3) | [ant-design-vue-jeecg](https://github.com/jeecgboot/jeecg-boot/tree/master/ant-design-vue-jeecg) | [jeecg-boot](https://github.com/jeecgboot/jeecg-boot) |
|
||||||
|
| 码云 | [jeecgboot-vue3](https://gitee.com/jeecg/jeecgboot-vue3) | [ant-design-vue-jeecg](https://gitee.com/jeecg/jeecg-boot/tree/master/ant-design-vue-jeecg) | [jeecg-boot](https://gitee.com/jeecg/jeecg-boot) |
|
||||||
|
|
||||||
| 项目名 | 说明 | 传送门 |
|
|
||||||
|--------------------|------------------------|-------------------------------------------------------------------------------------------------------------------------------------|
|
##### 项目说明
|
||||||
| `jeecg-boot` | JAVA后台(支持微服务) | [Github](https://github.com/jeecgboot/jeecg-boot) [Gitee](https://gitee.com/jeecg/jeecg-boot) |
|
|
||||||
| `ant-design-vue-jeecg` |Vue2版前端代码(默认与主项目一起) | |
|
| 项目名 | 说明 |
|
||||||
| `jeecgboot-vue3` | Vue3版前端代码 | [Github](https://github.com/jeecgboot/jeecgboot-vue3) [Gitee](https://gitee.com/jeecg/jeecgboot-vue3) |
|
|--------------------|------------------------|
|
||||||
|
| `jeecg-boot` | SpringBoot后台源码(支持微服务) |
|
||||||
|
| `ant-design-vue-jeecg` |Vue2版前端源码(与主项目一起) |
|
||||||
|
| `jeecgboot-vue3` | Vue3版前端源码 |
|
||||||
|
|
||||||
|
|
||||||
适用项目
|
适用项目
|
||||||
|
@ -62,10 +71,10 @@ Jeecg-Boot低代码开发平台,可以应用在任何J2EE项目的开发中,
|
||||||
- 微服务开发: [单体切换为微服务](http://doc.jeecg.com/2704725)
|
- 微服务开发: [单体切换为微服务](http://doc.jeecg.com/2704725)
|
||||||
|
|
||||||
- QQ交流群 : ⑥730954414、VUE3群683903138、⑤860162132(满)、④774126647(满)、③816531124(满)、②769925425(满)、①284271917(满)
|
- QQ交流群 : ⑥730954414、VUE3群683903138、⑤860162132(满)、④774126647(满)、③816531124(满)、②769925425(满)、①284271917(满)
|
||||||
|
|
||||||
> ` 提醒:【QQ群是自助服务群,建议给帮助您解决问题的同学发送指定红包,表示感谢!】 `
|
> ` 提醒:【QQ群是自助服务群,建议给帮助您解决问题的同学发送指定红包,表示感谢!】 `
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
为什么选择JEECG-BOOT?
|
为什么选择JEECG-BOOT?
|
||||||
-----------------------------------
|
-----------------------------------
|
||||||
* 1.采用最新主流前后分离框架(Springboot+Mybatis+antd),容易上手; 代码生成器依赖性低,灵活的扩展能力,可快速实现二次开发;
|
* 1.采用最新主流前后分离框架(Springboot+Mybatis+antd),容易上手; 代码生成器依赖性低,灵活的扩展能力,可快速实现二次开发;
|
||||||
|
@ -340,16 +349,16 @@ Jeecg-Boot低代码开发平台,可以应用在任何J2EE项目的开发中,
|
||||||
│ ├─Online在线表单 - 功能已开放
|
│ ├─Online在线表单 - 功能已开放
|
||||||
│ ├─Online代码生成器 - 功能已开放
|
│ ├─Online代码生成器 - 功能已开放
|
||||||
│ ├─Online在线报表 - 功能已开放
|
│ ├─Online在线报表 - 功能已开放
|
||||||
│ ├─Online在线图表(商业功能)
|
│ ├─Online在线图表(未开源)
|
||||||
│ ├─Online图表模板配置(商业功能)
|
│ ├─Online图表模板配置(未开源)
|
||||||
│ ├─Online布局设计(商业功能)
|
│ ├─Online布局设计(未开源)
|
||||||
│ ├─多数据源管理 - 功能已开放
|
│ ├─多数据源管理 - 功能已开放
|
||||||
├─积木报表设计器(低代码)
|
├─积木报表设计器(低代码)
|
||||||
│ ├─打印设计器
|
│ ├─打印设计器
|
||||||
│ ├─数据报表设计
|
│ ├─数据报表设计
|
||||||
│ ├─图形报表设计(支持echart)
|
│ ├─图形报表设计(支持echart)
|
||||||
│ ├─大屏设计器(商业功能)
|
│ ├─大屏设计器(未开源)
|
||||||
│─流程模块功能 (商业功能)
|
│─流程模块功能 (未开源)
|
||||||
│ ├─流程设计器
|
│ ├─流程设计器
|
||||||
│ ├─表单设计器
|
│ ├─表单设计器
|
||||||
├─大屏设计器
|
├─大屏设计器
|
||||||
|
@ -364,7 +373,7 @@ Jeecg-Boot低代码开发平台,可以应用在任何J2EE项目的开发中,
|
||||||
│ └─我的抄送
|
│ └─我的抄送
|
||||||
│ └─流程委派、抄送、跳转
|
│ └─流程委派、抄送、跳转
|
||||||
│ └─。。。
|
│ └─。。。
|
||||||
│─OA办公组件 (商业功能)
|
│─OA办公组件 (未开源)
|
||||||
│ ├─更多功能
|
│ ├─更多功能
|
||||||
│ └─。。。
|
│ └─。。。
|
||||||
└─其他模块
|
└─其他模块
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
Ant Design Jeecg Vue
|
Ant Design Jeecg Vue
|
||||||
====
|
====
|
||||||
|
|
||||||
当前最新版本: 3.1.0(发布日期:20220301)
|
当前最新版本: 3.3.0(发布日期:20220725)
|
||||||
|
|
||||||
Overview
|
Overview
|
||||||
----
|
----
|
||||||
|
|
|
@ -10,8 +10,8 @@
|
||||||
"lint": "vue-cli-service lint"
|
"lint": "vue-cli-service lint"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"ant-design-vue": "^1.7.2",
|
|
||||||
"@jeecg/antd-online-mini": "3.1.0-beta",
|
"@jeecg/antd-online-mini": "3.1.0-beta",
|
||||||
|
"ant-design-vue": "^1.7.2",
|
||||||
"@antv/data-set": "^0.11.4",
|
"@antv/data-set": "^0.11.4",
|
||||||
"viser-vue": "^2.4.8",
|
"viser-vue": "^2.4.8",
|
||||||
"axios": "^0.18.0",
|
"axios": "^0.18.0",
|
||||||
|
@ -29,7 +29,7 @@
|
||||||
"vue-ls": "^3.2.0",
|
"vue-ls": "^3.2.0",
|
||||||
"vue-router": "^3.0.1",
|
"vue-router": "^3.0.1",
|
||||||
"vuex": "^3.1.0",
|
"vuex": "^3.1.0",
|
||||||
"vue-print-nb-jeecg": "^1.0.9",
|
"vue-print-nb-jeecg": "^1.0.11",
|
||||||
"clipboard": "^2.0.4",
|
"clipboard": "^2.0.4",
|
||||||
"vue-photo-preview": "^1.1.3",
|
"vue-photo-preview": "^1.1.3",
|
||||||
"vue-splitpane": "^1.0.4",
|
"vue-splitpane": "^1.0.4",
|
||||||
|
@ -45,7 +45,8 @@
|
||||||
"vxe-table": "2.9.13",
|
"vxe-table": "2.9.13",
|
||||||
"vxe-table-plugin-antd": "1.8.10",
|
"vxe-table-plugin-antd": "1.8.10",
|
||||||
"cron-parser": "^2.10.0",
|
"cron-parser": "^2.10.0",
|
||||||
"qiankun": "^2.5.1"
|
"qiankun": "^2.5.1",
|
||||||
|
"xss": "^1.0.13"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/polyfill": "^7.2.5",
|
"@babel/polyfill": "^7.2.5",
|
||||||
|
|
|
@ -69,7 +69,6 @@ export const ajaxGetDictItems = (code, params)=>getAction(`/sys/dict/getDictItem
|
||||||
function getDictItemsFromCache(dictCode) {
|
function getDictItemsFromCache(dictCode) {
|
||||||
if (Vue.ls.get(UI_CACHE_DB_DICT_DATA) && Vue.ls.get(UI_CACHE_DB_DICT_DATA)[dictCode]) {
|
if (Vue.ls.get(UI_CACHE_DB_DICT_DATA) && Vue.ls.get(UI_CACHE_DB_DICT_DATA)[dictCode]) {
|
||||||
let dictItems = Vue.ls.get(UI_CACHE_DB_DICT_DATA)[dictCode];
|
let dictItems = Vue.ls.get(UI_CACHE_DB_DICT_DATA)[dictCode];
|
||||||
//console.log("-----------getDictItemsFromCache----------dictCode="+dictCode+"---- dictItems=",dictItems)
|
|
||||||
return dictItems;
|
return dictItems;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -91,6 +90,7 @@ const loadCategoryData = (params)=>getAction("/sys/category/loadAllData",params)
|
||||||
const checkRuleByCode = (params) => getAction('/sys/checkRule/checkByCode', params)
|
const checkRuleByCode = (params) => getAction('/sys/checkRule/checkByCode', params)
|
||||||
//加载我的通告信息
|
//加载我的通告信息
|
||||||
const getUserNoticeInfo= (params)=>getAction("/sys/sysAnnouncementSend/getMyAnnouncementSend",params);
|
const getUserNoticeInfo= (params)=>getAction("/sys/sysAnnouncementSend/getMyAnnouncementSend",params);
|
||||||
|
//查询图表数据
|
||||||
const getTransitURL = url => `/sys/common/transitRESTful?url=${encodeURIComponent(url)}`
|
const getTransitURL = url => `/sys/common/transitRESTful?url=${encodeURIComponent(url)}`
|
||||||
// 中转HTTP请求
|
// 中转HTTP请求
|
||||||
export const transitRESTful = {
|
export const transitRESTful = {
|
||||||
|
@ -101,8 +101,6 @@ export const transitRESTful = {
|
||||||
}
|
}
|
||||||
|
|
||||||
export {
|
export {
|
||||||
// imgView,
|
|
||||||
// doMian,
|
|
||||||
addRole,
|
addRole,
|
||||||
editRole,
|
editRole,
|
||||||
checkRoleCode,
|
checkRoleCode,
|
||||||
|
|
|
@ -16,7 +16,9 @@ export default api
|
||||||
export function postAction(url,parameter) {
|
export function postAction(url,parameter) {
|
||||||
let sign = signMd5Utils.getSign(url, parameter);
|
let sign = signMd5Utils.getSign(url, parameter);
|
||||||
//将签名和时间戳,添加在请求接口 Header
|
//将签名和时间戳,添加在请求接口 Header
|
||||||
let signHeader = {"X-Sign": sign,"X-TIMESTAMP": signMd5Utils.getDateTimeToString()};
|
// update-begin--author:taoyan---date:20220421--for: VUEN-410【签名改造】 X-TIMESTAMP牵扯
|
||||||
|
let signHeader = {"X-Sign": sign,"X-TIMESTAMP": signMd5Utils.getTimestamp()};
|
||||||
|
// update-end--author:taoyan---date:20220421--for: VUEN-410【签名改造】 X-TIMESTAMP牵扯
|
||||||
|
|
||||||
return axios({
|
return axios({
|
||||||
url: url,
|
url: url,
|
||||||
|
@ -30,7 +32,9 @@ export function postAction(url,parameter) {
|
||||||
export function httpAction(url,parameter,method) {
|
export function httpAction(url,parameter,method) {
|
||||||
let sign = signMd5Utils.getSign(url, parameter);
|
let sign = signMd5Utils.getSign(url, parameter);
|
||||||
//将签名和时间戳,添加在请求接口 Header
|
//将签名和时间戳,添加在请求接口 Header
|
||||||
let signHeader = {"X-Sign": sign,"X-TIMESTAMP": signMd5Utils.getDateTimeToString()};
|
// update-begin--author:taoyan---date:20220421--for: VUEN-410【签名改造】 X-TIMESTAMP牵扯
|
||||||
|
let signHeader = {"X-Sign": sign,"X-TIMESTAMP": signMd5Utils.getTimestamp()};
|
||||||
|
// update-end--author:taoyan---date:20220421--for: VUEN-410【签名改造】 X-TIMESTAMP牵扯
|
||||||
|
|
||||||
return axios({
|
return axios({
|
||||||
url: url,
|
url: url,
|
||||||
|
@ -53,7 +57,9 @@ export function putAction(url,parameter) {
|
||||||
export function getAction(url,parameter) {
|
export function getAction(url,parameter) {
|
||||||
let sign = signMd5Utils.getSign(url, parameter);
|
let sign = signMd5Utils.getSign(url, parameter);
|
||||||
//将签名和时间戳,添加在请求接口 Header
|
//将签名和时间戳,添加在请求接口 Header
|
||||||
let signHeader = {"X-Sign": sign,"X-TIMESTAMP": signMd5Utils.getDateTimeToString()};
|
// update-begin--author:taoyan---date:20220421--for: VUEN-410【签名改造】 X-TIMESTAMP牵扯
|
||||||
|
let signHeader = {"X-Sign": sign,"X-TIMESTAMP": signMd5Utils.getTimestamp()};
|
||||||
|
// update-end--author:taoyan---date:20220421--for: VUEN-410【签名改造】 X-TIMESTAMP牵扯
|
||||||
|
|
||||||
return axios({
|
return axios({
|
||||||
url: url,
|
url: url,
|
||||||
|
@ -120,13 +126,23 @@ export function saveService(parameter) {
|
||||||
* @param parameter
|
* @param parameter
|
||||||
* @returns {*}
|
* @returns {*}
|
||||||
*/
|
*/
|
||||||
export function downFile(url,parameter){
|
export function downFile(url,parameter, method='get'){
|
||||||
return axios({
|
if(method=='get'){
|
||||||
url: url,
|
return axios({
|
||||||
params: parameter,
|
url: url,
|
||||||
method:'get' ,
|
params: parameter,
|
||||||
responseType: 'blob'
|
method: method ,
|
||||||
})
|
responseType: 'blob'
|
||||||
|
})
|
||||||
|
}else{
|
||||||
|
return axios({
|
||||||
|
url: url,
|
||||||
|
method: method,
|
||||||
|
data: parameter,
|
||||||
|
responseType: 'blob'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -387,7 +387,7 @@
|
||||||
<a-menu-item v-if="col.allowDownload!==false" @click="handleClickDownloadFile(id)">
|
<a-menu-item v-if="col.allowDownload!==false" @click="handleClickDownloadFile(id)">
|
||||||
<span><a-icon type="download"/> 下载</span>
|
<span><a-icon type="download"/> 下载</span>
|
||||||
</a-menu-item>
|
</a-menu-item>
|
||||||
<a-menu-item v-if="col.allowRemove!==false" @click="handleClickDelFile(id)">
|
<a-menu-item v-if="col.allowRemove!==false" @click="handleClickDelFile(id, row, col)">
|
||||||
<span><a-icon type="delete"/> 删除</span>
|
<span><a-icon type="delete"/> 删除</span>
|
||||||
</a-menu-item>
|
</a-menu-item>
|
||||||
</a-menu>
|
</a-menu>
|
||||||
|
@ -475,7 +475,7 @@
|
||||||
<a-menu-item v-if="col.allowDownload!==false" @click="handleClickDownFileByUrl(id)">
|
<a-menu-item v-if="col.allowDownload!==false" @click="handleClickDownFileByUrl(id)">
|
||||||
<span><a-icon type="download"/> 下载</span>
|
<span><a-icon type="download"/> 下载</span>
|
||||||
</a-menu-item>
|
</a-menu-item>
|
||||||
<a-menu-item @click="handleClickDelFile(id)">
|
<a-menu-item @click="handleClickDelFile(id, row, col)">
|
||||||
<span><a-icon type="delete"/> 删除</span>
|
<span><a-icon type="delete"/> 删除</span>
|
||||||
</a-menu-item>
|
</a-menu-item>
|
||||||
<a-menu-item @click="handleMoreOperation(id,col,col)">
|
<a-menu-item @click="handleMoreOperation(id,col,col)">
|
||||||
|
@ -532,7 +532,7 @@
|
||||||
<a-menu-item v-if="col.allowDownload!==false" @click="handleClickDownFileByUrl(id)">
|
<a-menu-item v-if="col.allowDownload!==false" @click="handleClickDownFileByUrl(id)">
|
||||||
<span><a-icon type="download"/> 下载</span>
|
<span><a-icon type="download"/> 下载</span>
|
||||||
</a-menu-item>
|
</a-menu-item>
|
||||||
<a-menu-item @click="handleClickDelFile(id)">
|
<a-menu-item @click="handleClickDelFile(id, row, col)">
|
||||||
<span><a-icon type="delete"/> 删除</span>
|
<span><a-icon type="delete"/> 删除</span>
|
||||||
</a-menu-item>
|
</a-menu-item>
|
||||||
<a-menu-item @click="handleMoreOperation(id,'img',col)">
|
<a-menu-item @click="handleMoreOperation(id,'img',col)">
|
||||||
|
@ -1865,6 +1865,8 @@
|
||||||
})
|
})
|
||||||
// 强制更新formValues
|
// 强制更新formValues
|
||||||
this.forceUpdateFormValues()
|
this.forceUpdateFormValues()
|
||||||
|
// 【issues/3828】重新计算统计列
|
||||||
|
this.recalcAllStatisticsColumns()
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
* 设置单个组件的值
|
* 设置单个组件的值
|
||||||
|
@ -2590,8 +2592,9 @@
|
||||||
return id;
|
return id;
|
||||||
},
|
},
|
||||||
|
|
||||||
handleClickDelFile(id) {
|
handleClickDelFile(id, row, col) {
|
||||||
this.uploadValues[id] = null
|
this.uploadValues[id] = null
|
||||||
|
this.elemValueChange(col.type, row, col, null);
|
||||||
},
|
},
|
||||||
handleClickDownloadFile(id) {
|
handleClickDownloadFile(id) {
|
||||||
let { path } = this.uploadValues[id] || {}
|
let { path } = this.uploadValues[id] || {}
|
||||||
|
@ -3074,7 +3077,11 @@
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
},
|
||||||
|
// 根据id获取dataSource中的一行数据
|
||||||
|
getOriginData(id){
|
||||||
|
return this.dataSource.filter(item=>item.id == id);
|
||||||
|
},
|
||||||
|
|
||||||
},
|
},
|
||||||
beforeDestroy() {
|
beforeDestroy() {
|
||||||
|
|
|
@ -68,6 +68,9 @@
|
||||||
branding: false,
|
branding: false,
|
||||||
menubar: false,
|
menubar: false,
|
||||||
toolbar_drawer: false,
|
toolbar_drawer: false,
|
||||||
|
//update-begin-author:taoyan date:2022-5-6 for: issues/I4BCC3 富文本编辑器在服务器图片上传是相对路径
|
||||||
|
convert_urls: false,
|
||||||
|
//update-end-author:taoyan date:2022-5-6 for: issues/I4BCC3 富文本编辑器在服务器图片上传是相对路径
|
||||||
images_upload_handler: (blobInfo, success) => {
|
images_upload_handler: (blobInfo, success) => {
|
||||||
let formData = new FormData()
|
let formData = new FormData()
|
||||||
formData.append('file', blobInfo.blob(), blobInfo.filename());
|
formData.append('file', blobInfo.blob(), blobInfo.filename());
|
||||||
|
|
|
@ -49,7 +49,8 @@
|
||||||
|
|
||||||
.jeecg-form-container-disabled .ant-upload-select{display:none}
|
.jeecg-form-container-disabled .ant-upload-select{display:none}
|
||||||
.jeecg-form-container-disabled .ant-upload-list{cursor:grabbing}
|
.jeecg-form-container-disabled .ant-upload-list{cursor:grabbing}
|
||||||
.jeecg-form-container-disabled fieldset[disabled] .ant-upload-list{
|
.jeecg-form-container-disabled fieldset[disabled] .ant-upload-list,
|
||||||
|
.jeecg-form-container-disabled fieldset[disabled] iframe{
|
||||||
-ms-pointer-events: auto !important;
|
-ms-pointer-events: auto !important;
|
||||||
pointer-events: auto !important;
|
pointer-events: auto !important;
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
v-on="$listeners"
|
v-on="$listeners"
|
||||||
@ok="handleOk"
|
@ok="handleOk"
|
||||||
@cancel="handleCancel"
|
@cancel="handleCancel"
|
||||||
destroyOnClose
|
:destroyOnClose="destroyOnClose"
|
||||||
>
|
>
|
||||||
|
|
||||||
<slot></slot>
|
<slot></slot>
|
||||||
|
@ -49,13 +49,17 @@
|
||||||
|
|
||||||
import { getClass, getStyle } from '@/utils/props-util'
|
import { getClass, getStyle } from '@/utils/props-util'
|
||||||
import { triggerWindowResizeEvent } from '@/utils/util'
|
import { triggerWindowResizeEvent } from '@/utils/util'
|
||||||
|
import ModalDragMixins from './ModalDragMixins'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'JModal',
|
name: 'JModal',
|
||||||
|
mixins: [ModalDragMixins],
|
||||||
props: {
|
props: {
|
||||||
title: String,
|
title: String,
|
||||||
// 可使用 .sync 修饰符
|
// 可使用 .sync 修饰符
|
||||||
visible: Boolean,
|
visible: Boolean,
|
||||||
|
// 是否开启拖拽
|
||||||
|
draggable: Boolean,
|
||||||
// 是否全屏弹窗,当全屏时无论如何都会禁止 body 滚动。可使用 .sync 修饰符
|
// 是否全屏弹窗,当全屏时无论如何都会禁止 body 滚动。可使用 .sync 修饰符
|
||||||
fullscreen: {
|
fullscreen: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
|
@ -71,6 +75,11 @@ export default {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: true
|
default: true
|
||||||
},
|
},
|
||||||
|
// 关闭时销毁弹窗内容
|
||||||
|
destroyOnClose: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
|
@ -162,6 +171,16 @@ export default {
|
||||||
toggleFullscreen() {
|
toggleFullscreen() {
|
||||||
this.innerFullscreen = !this.innerFullscreen
|
this.innerFullscreen = !this.innerFullscreen
|
||||||
triggerWindowResizeEvent()
|
triggerWindowResizeEvent()
|
||||||
|
// 全屏的时候禁止拖动
|
||||||
|
if (this.innerFullscreen) {
|
||||||
|
// 还原弹窗的位置为0,0
|
||||||
|
this.setModalPosition(0, 0, false)
|
||||||
|
this.dragSettings.headerEl.style.cursor = null
|
||||||
|
} else {
|
||||||
|
// 取消全屏的时候,将弹窗移动到上次记录的位置
|
||||||
|
this.resetModalPosition()
|
||||||
|
this.dragSettings.headerEl.style.cursor = 'move'
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,152 @@
|
||||||
|
import {getRefPromise} from '@/utils/util'
|
||||||
|
|
||||||
|
/** JModal 的拖拽混入 */
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
// 拖动配置
|
||||||
|
dragSettings: {
|
||||||
|
// 上次拖动top记录
|
||||||
|
top: null,
|
||||||
|
// 上次拖动left记录
|
||||||
|
left: null,
|
||||||
|
wrapEl: null,
|
||||||
|
dragEl: null,
|
||||||
|
headerEl: null,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
visible() {
|
||||||
|
if (!this.visible || !this.draggable) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.handleDrag()
|
||||||
|
},
|
||||||
|
draggable() {
|
||||||
|
if (!this.visible || !this.draggable) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.handleDrag()
|
||||||
|
},
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
async handleDrag() {
|
||||||
|
let modalRef = await getRefPromise(this, 'modal')
|
||||||
|
const dragWraps = modalRef.$el.querySelectorAll('.ant-modal-wrap')
|
||||||
|
let wrapEl = dragWraps[0]
|
||||||
|
if (!wrapEl) return
|
||||||
|
this.dragSettings.wrapEl = wrapEl
|
||||||
|
this.dragSettings.dragEl = wrapEl.querySelector('.ant-modal')
|
||||||
|
this.dragSettings.headerEl = wrapEl.querySelector('.ant-modal-header')
|
||||||
|
const display = getStyle(wrapEl, 'display')
|
||||||
|
const draggable = wrapEl.getAttribute('data-drag')
|
||||||
|
if (display !== 'none') {
|
||||||
|
// 拖拽位置
|
||||||
|
if (draggable === null || this.destroyOnClose) {
|
||||||
|
this.enableDrag(wrapEl)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
/** 启用拖拽 */
|
||||||
|
enableDrag() {
|
||||||
|
let {wrapEl, dragEl, headerEl} = this.dragSettings
|
||||||
|
if (!wrapEl) return
|
||||||
|
wrapEl.setAttribute('data-drag', this.draggable)
|
||||||
|
if (!headerEl || !dragEl || !this.draggable) return
|
||||||
|
|
||||||
|
// 还原上一次移动的位置
|
||||||
|
this.resetModalPosition()
|
||||||
|
|
||||||
|
headerEl.style.cursor = 'move'
|
||||||
|
headerEl.onmousedown = (e) => {
|
||||||
|
if (!e) return
|
||||||
|
// 鼠标按下,计算当前元素距离可视区的距离
|
||||||
|
const disX = e.clientX
|
||||||
|
const disY = e.clientY
|
||||||
|
const screenWidth = document.body.clientWidth // body当前宽度
|
||||||
|
const screenHeight = document.documentElement.clientHeight // 可见区域高度(应为body高度,可某些环境下无法获取)
|
||||||
|
|
||||||
|
const dragElWidth = dragEl.offsetWidth // 对话框宽度
|
||||||
|
const dragElHeight = dragEl.offsetHeight // 对话框高度
|
||||||
|
|
||||||
|
const minDragElLeft = dragEl.offsetLeft
|
||||||
|
|
||||||
|
const maxDragElLeft = screenWidth - dragEl.offsetLeft - dragElWidth
|
||||||
|
const minDragElTop = dragEl.offsetTop
|
||||||
|
const maxDragElTop = screenHeight - dragEl.offsetTop - dragElHeight
|
||||||
|
// 获取到的值带px 正则匹配替换
|
||||||
|
const domLeft = getStyle(dragEl, 'left')
|
||||||
|
const domTop = getStyle(dragEl, 'top')
|
||||||
|
let styL = +domLeft
|
||||||
|
let styT = +domTop
|
||||||
|
|
||||||
|
// 注意在ie中 第一次获取到的值为组件自带50% 移动之后赋值为px
|
||||||
|
if (domLeft.includes('%')) {
|
||||||
|
styL = +document.body.clientWidth * (+domLeft.replace(/%/g, '') / 100)
|
||||||
|
styT = +document.body.clientHeight * (+domTop.replace(/%/g, '') / 100)
|
||||||
|
} else {
|
||||||
|
styL = +domLeft.replace(/px/g, '')
|
||||||
|
styT = +domTop.replace(/px/g, '')
|
||||||
|
}
|
||||||
|
|
||||||
|
document.onmousemove = (e) => {
|
||||||
|
// 全屏时不触发移动方法
|
||||||
|
if (this.innerFullscreen) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// 通过事件委托,计算移动的距离
|
||||||
|
let left = e.clientX - disX
|
||||||
|
let top = e.clientY - disY
|
||||||
|
|
||||||
|
// 边界处理
|
||||||
|
if (-left > minDragElLeft) {
|
||||||
|
left = -minDragElLeft
|
||||||
|
} else if (left > maxDragElLeft) {
|
||||||
|
left = maxDragElLeft
|
||||||
|
}
|
||||||
|
|
||||||
|
if (-top > minDragElTop) {
|
||||||
|
top = -minDragElTop
|
||||||
|
} else if (top > maxDragElTop) {
|
||||||
|
top = maxDragElTop
|
||||||
|
}
|
||||||
|
|
||||||
|
this.setModalPosition(top + styT, left + styL)
|
||||||
|
}
|
||||||
|
|
||||||
|
document.onmouseup = () => {
|
||||||
|
document.onmousemove = null
|
||||||
|
document.onmouseup = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 移动弹窗位置
|
||||||
|
* @param top 顶部位置
|
||||||
|
* @param left 左侧位置
|
||||||
|
* @param remember 是否记录位置,默认 true
|
||||||
|
*/
|
||||||
|
setModalPosition(top, left, remember = true) {
|
||||||
|
// 记录移动位置
|
||||||
|
if (remember) {
|
||||||
|
this.dragSettings.top = top
|
||||||
|
this.dragSettings.left = left
|
||||||
|
}
|
||||||
|
// 移动当前元素
|
||||||
|
this.dragSettings.dragEl.style.cssText += `;left:${left}px;top:${top}px;`
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* 将弹窗移动到上次记录的位置
|
||||||
|
*/
|
||||||
|
resetModalPosition() {
|
||||||
|
this.setModalPosition(this.dragSettings.top, this.dragSettings.left, false)
|
||||||
|
},
|
||||||
|
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
function getStyle(dom, attr) {
|
||||||
|
return getComputedStyle(dom)[attr]
|
||||||
|
}
|
|
@ -29,6 +29,7 @@
|
||||||
@cancel="handleCancel"
|
@cancel="handleCancel"
|
||||||
:mask="false"
|
:mask="false"
|
||||||
:fullscreen="izMobile"
|
:fullscreen="izMobile"
|
||||||
|
draggable
|
||||||
class="j-super-query-modal"
|
class="j-super-query-modal"
|
||||||
style="top:5%;max-height: 95%;"
|
style="top:5%;max-height: 95%;"
|
||||||
>
|
>
|
||||||
|
@ -163,8 +164,10 @@
|
||||||
<a-time-picker v-else-if="item.type==='time'" :value="item.val ? moment(item.val,'HH:mm:ss') : null" format="HH:mm:ss" style="width: 100%" @change="(time,value)=>item.val=value"/>
|
<a-time-picker v-else-if="item.type==='time'" :value="item.val ? moment(item.val,'HH:mm:ss') : null" format="HH:mm:ss" style="width: 100%" @change="(time,value)=>item.val=value"/>
|
||||||
<a-input-number v-else-if=" item.type=='int'||item.type=='number' " style="width: 100%" placeholder="请输入数值" v-model="item.val"/>
|
<a-input-number v-else-if=" item.type=='int'||item.type=='number' " style="width: 100%" placeholder="请输入数值" v-model="item.val"/>
|
||||||
<a-select v-else-if="item.type=='switch'" placeholder="请选择" v-model="item.val">
|
<a-select v-else-if="item.type=='switch'" placeholder="请选择" v-model="item.val">
|
||||||
<a-select-option value="Y">是</a-select-option>
|
<!-- update-begin-author:taoyan for: VUEN-242【online表单 高级查询】开关组件设置扩展参数为[0,1] 时,高级查询选择后查询仍然是Y/N -->
|
||||||
<a-select-option value="N">否</a-select-option>
|
<a-select-option :value="item.extendOption[0]">是</a-select-option>
|
||||||
|
<a-select-option :value="item.extendOption[1]">否</a-select-option>
|
||||||
|
<!-- update-end-author:taoyan for: VUEN-242【online表单 高级查询】开关组件设置扩展参数为[0,1] 时,高级查询选择后查询仍然是Y/N -->
|
||||||
</a-select>
|
</a-select>
|
||||||
<a-input v-else v-model="item.val" placeholder="请输入值"/>
|
<a-input v-else v-model="item.val" placeholder="请输入值"/>
|
||||||
</a-col>
|
</a-col>
|
||||||
|
@ -426,10 +429,17 @@
|
||||||
item['dictCode'] = dictCode
|
item['dictCode'] = dictCode
|
||||||
item['dictTable'] = dictTable
|
item['dictTable'] = dictTable
|
||||||
item['dictText'] = dictText
|
item['dictText'] = dictText
|
||||||
|
//update-begin-author:taoyan for: VUEN-242【online表单 高级查询】开关组件设置扩展参数为[0,1] 时,高级查询选择后查询仍然是Y/N
|
||||||
|
item['extendOption'] = node.dataRef.extendOption || ['Y', 'N']
|
||||||
|
//update-begin-author:taoyan for: VUEN-242【online表单 高级查询】开关组件设置扩展参数为[0,1] 时,高级查询选择后查询仍然是Y/N
|
||||||
item['customReturnField'] = customReturnField
|
item['customReturnField'] = customReturnField
|
||||||
if (popup) {
|
if (popup) {
|
||||||
item['popup'] = popup
|
item['popup'] = popup
|
||||||
}
|
}
|
||||||
|
// 格式化字符串,一般用于高级查询的日期格式处理
|
||||||
|
if (node.dataRef.formatStr) {
|
||||||
|
item['formatStr'] = node.dataRef.formatStr
|
||||||
|
}
|
||||||
this.$set(item, 'val', undefined)
|
this.$set(item, 'val', undefined)
|
||||||
},
|
},
|
||||||
handleOpen() {
|
handleOpen() {
|
||||||
|
|
|
@ -71,6 +71,12 @@
|
||||||
let className = target.className || ''
|
let className = target.className || ''
|
||||||
className = typeof className === 'string' ? className : className.toString()
|
className = typeof className === 'string' ? className : className.toString()
|
||||||
|
|
||||||
|
// 获取 td 父级
|
||||||
|
let td = getParentNodeByTagName(target, 'td');
|
||||||
|
// 点击的是拖拽排序列,不做处理
|
||||||
|
if (td && td.querySelector('.j-vxe-ds-icons')) {
|
||||||
|
return
|
||||||
|
}
|
||||||
// 点击的是expand,不做处理
|
// 点击的是expand,不做处理
|
||||||
if (className.includes('vxe-table--expand-btn')) {
|
if (className.includes('vxe-table--expand-btn')) {
|
||||||
return
|
return
|
||||||
|
|
|
@ -763,6 +763,8 @@ export default {
|
||||||
console.warn(`JVxeTable.setValues:必须传递数组`)
|
console.warn(`JVxeTable.setValues:必须传递数组`)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
// 是否更新了数据
|
||||||
|
let updated = false
|
||||||
values.forEach((item, idx) => {
|
values.forEach((item, idx) => {
|
||||||
let {rowKey, values: record} = item
|
let {rowKey, values: record} = item
|
||||||
let {row} = this.getIfRowById(rowKey)
|
let {row} = this.getIfRowById(rowKey)
|
||||||
|
@ -775,6 +777,7 @@ export default {
|
||||||
let oldValue = row[colKey]
|
let oldValue = row[colKey]
|
||||||
let newValue = record[colKey]
|
let newValue = record[colKey]
|
||||||
if (newValue !== oldValue) {
|
if (newValue !== oldValue) {
|
||||||
|
updated = true
|
||||||
this.$set(row, colKey, newValue)
|
this.$set(row, colKey, newValue)
|
||||||
// 触发 valueChange 事件
|
// 触发 valueChange 事件
|
||||||
this.trigger('valueChange', {
|
this.trigger('valueChange', {
|
||||||
|
@ -791,6 +794,14 @@ export default {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
// 【issues/3828】数据更新后,重新计算统计列
|
||||||
|
if (updated && this.statistics.has) {
|
||||||
|
this.$nextTick(async () => {
|
||||||
|
let {xTable} = this.$refs.vxe.$refs;
|
||||||
|
await xTable.updateCache(true);
|
||||||
|
await xTable.updateData();
|
||||||
|
});
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
/** 获取所有的数据,包括values、deleteIds */
|
/** 获取所有的数据,包括values、deleteIds */
|
||||||
|
@ -1406,7 +1417,7 @@ const fooPatterns = [
|
||||||
{title: '字母', value: 's', pattern: /^[A-Z|a-z]+$/},
|
{title: '字母', value: 's', pattern: /^[A-Z|a-z]+$/},
|
||||||
{title: '数字', value: 'n', pattern: /^-?\d+(\.?\d+|\d?)$/},
|
{title: '数字', value: 'n', pattern: /^-?\d+(\.?\d+|\d?)$/},
|
||||||
{title: '整数', value: 'z', pattern: /^-?\d+$/},
|
{title: '整数', value: 'z', pattern: /^-?\d+$/},
|
||||||
{title: '金额', value: 'money', pattern: /^(([1-9][0-9]*)|([0]\.\d{0,2}|[1-9][0-9]*\.\d{0,2}))$/},
|
{title: '金额', value: 'money', pattern: /^(([1-9][0-9]*)|([0]\.\d{0,2}|[1-9][0-9]*\.\d{0,5}))$/},
|
||||||
]
|
]
|
||||||
|
|
||||||
/** 旧版handler转为新版Validator */
|
/** 旧版handler转为新版Validator */
|
||||||
|
|
|
@ -133,6 +133,10 @@
|
||||||
value['message'] = file.response.message || '未知错误'
|
value['message'] = file.response.message || '未知错误'
|
||||||
}
|
}
|
||||||
this.innerFile = value
|
this.innerFile = value
|
||||||
|
// issues/I5FTO6 JVxeTypes.upload 文件上传的时候,触发不了事件
|
||||||
|
if (value.path) {
|
||||||
|
this.handleChangeCommon(fileGetValue(value));
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
// handleClickPreviewFile(id) {
|
// handleClickPreviewFile(id) {
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
import store from '@/store/'
|
import store from '@/store/'
|
||||||
import { randomUUID } from '@/utils/util'
|
import { randomUUID } from '@/utils/util'
|
||||||
|
import Vue from 'vue'
|
||||||
|
import { ACCESS_TOKEN } from '@/store/mutation-types'
|
||||||
|
|
||||||
// vxe socket
|
// vxe socket
|
||||||
const vs = {
|
const vs = {
|
||||||
// 页面唯一 id,用于标识同一用户,不同页面的websocket
|
// 页面唯一 id,用于标识同一用户,不同页面的websocket
|
||||||
|
@ -52,7 +55,10 @@ const vs = {
|
||||||
const domain = window._CONFIG['domianURL'].replace('https://', 'wss://').replace('http://', 'ws://')
|
const domain = window._CONFIG['domianURL'].replace('https://', 'wss://').replace('http://', 'ws://')
|
||||||
const url = `${domain}/vxeSocket/${userId}/${this.pageId}`
|
const url = `${domain}/vxeSocket/${userId}/${this.pageId}`
|
||||||
|
|
||||||
this.ws = new WebSocket(url)
|
//update-begin-author:taoyan date:2022-4-22 for: v2.4.6 的 websocket 服务端,存在性能和安全问题。 #3278
|
||||||
|
let token = Vue.ls.get(ACCESS_TOKEN)
|
||||||
|
this.ws = new WebSocket(url, [token])
|
||||||
|
//update-end-author:taoyan date:2022-4-22 for: v2.4.6 的 websocket 服务端,存在性能和安全问题。 #3278
|
||||||
this.ws.onopen = this.on.open.bind(this)
|
this.ws.onopen = this.on.open.bind(this)
|
||||||
this.ws.onerror = this.on.error.bind(this)
|
this.ws.onerror = this.on.error.bind(this)
|
||||||
this.ws.onmessage = this.on.message.bind(this)
|
this.ws.onmessage = this.on.message.bind(this)
|
||||||
|
|
|
@ -7,12 +7,15 @@
|
||||||
<script>
|
<script>
|
||||||
import Vue from 'vue'
|
import Vue from 'vue'
|
||||||
import { ACCESS_TOKEN } from "@/store/mutation-types"
|
import { ACCESS_TOKEN } from "@/store/mutation-types"
|
||||||
|
import { TENANT_ID } from "@/store/mutation-types"
|
||||||
import PageLayout from '../page/PageLayout'
|
import PageLayout from '../page/PageLayout'
|
||||||
import RouteView from './RouteView'
|
import RouteView from './RouteView'
|
||||||
|
import {mixinDevice} from '@/utils/mixin'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "IframePageContent",
|
name: "IframePageContent",
|
||||||
inject:['closeCurrent'],
|
inject:['closeCurrent'],
|
||||||
|
mixins: [mixinDevice],
|
||||||
data () {
|
data () {
|
||||||
return {
|
return {
|
||||||
url: "",
|
url: "",
|
||||||
|
@ -47,10 +50,21 @@
|
||||||
} else {
|
} else {
|
||||||
this.url = url
|
this.url = url
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//update-begin---author:wangshuai ---date:20220711 for:[VUEN-1638]菜单tenantId需要动态生成------------
|
||||||
|
let tenantIdStr = '${tenantId}'
|
||||||
|
let tenantUrl = this.url
|
||||||
|
if (tenantUrl.indexOf(tenantIdStr) != -1) {
|
||||||
|
let tenantId = Vue.ls.get(TENANT_ID)
|
||||||
|
this.url = tenantUrl.replace(tenantIdStr, tenantId)
|
||||||
|
}
|
||||||
|
//update-end---author:wangshuai ---date:20220711 for:[VUEN-1638]菜单tenantId需要动态生成--------------
|
||||||
//-----------------------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// 是否允许打开外部页面,需要非Mobile模式且打开多页签模式
|
||||||
|
let allowOpen = !this.isMobile() && this.$store.state.app.multipage
|
||||||
/*update_begin author:wuxianquan date:20190908 for:判断打开方式,新窗口打开时this.$route.meta.internalOrExternal==true */
|
/*update_begin author:wuxianquan date:20190908 for:判断打开方式,新窗口打开时this.$route.meta.internalOrExternal==true */
|
||||||
if(this.$route.meta.internalOrExternal != undefined && this.$route.meta.internalOrExternal==true){
|
if(allowOpen && this.$route.meta.internalOrExternal === true){
|
||||||
this.closeCurrent();
|
this.closeCurrent();
|
||||||
window.open(this.url);
|
window.open(this.url);
|
||||||
}
|
}
|
||||||
|
|
|
@ -70,7 +70,9 @@
|
||||||
/* update_begin author:wuxianquan date:20190828 for: 关闭当前tab页,供子页面调用 ->望菜单能配置外链,直接弹出新页面而不是嵌入iframe #428 */
|
/* update_begin author:wuxianquan date:20190828 for: 关闭当前tab页,供子页面调用 ->望菜单能配置外链,直接弹出新页面而不是嵌入iframe #428 */
|
||||||
provide(){
|
provide(){
|
||||||
return{
|
return{
|
||||||
closeCurrent:this.closeCurrent
|
closeCurrent:this.closeCurrent,
|
||||||
|
changeTitle: this.changeTitle,
|
||||||
|
changeTabTitle: this.changeTabTitle,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
/* update_end author:wuxianquan date:20190828 for: 关闭当前tab页,供子页面调用->望菜单能配置外链,直接弹出新页面而不是嵌入iframe #428 */
|
/* update_end author:wuxianquan date:20190828 for: 关闭当前tab页,供子页面调用->望菜单能配置外链,直接弹出新页面而不是嵌入iframe #428 */
|
||||||
|
@ -176,6 +178,10 @@
|
||||||
// update-end-author:sunjianlei date:20191223 for: 修复从单页模式切换回多页模式后首页不居第一位的 BUG
|
// update-end-author:sunjianlei date:20191223 for: 修复从单页模式切换回多页模式后首页不居第一位的 BUG
|
||||||
|
|
||||||
// update-begin-author:sunjianlei date:20200120 for: 动态更改页面标题
|
// update-begin-author:sunjianlei date:20200120 for: 动态更改页面标题
|
||||||
|
/**
|
||||||
|
* 修改当前页面的窗口标题
|
||||||
|
* @param title 要修改的新标题
|
||||||
|
*/
|
||||||
changeTitle(title) {
|
changeTitle(title) {
|
||||||
let projectTitle = "Jeecg-Boot 企业级低代码平台"
|
let projectTitle = "Jeecg-Boot 企业级低代码平台"
|
||||||
// 首页特殊处理
|
// 首页特殊处理
|
||||||
|
@ -185,6 +191,19 @@
|
||||||
document.title = title + ' · ' + projectTitle
|
document.title = title + ' · ' + projectTitle
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
/**
|
||||||
|
* 修改tab标签的标题
|
||||||
|
* @param title 要修改的新标题
|
||||||
|
* @param fullPath 要修改的路由全路径,如果不填就是修改当前路由
|
||||||
|
*/
|
||||||
|
changeTabTitle(title, fullPath = '') {
|
||||||
|
if (title) {
|
||||||
|
let currentRoute = this.pageList.find((r) => r.fullPath === (fullPath ? fullPath : this.$route.fullPath))
|
||||||
|
if (currentRoute != null) {
|
||||||
|
currentRoute.meta = {...currentRoute.meta, title}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
// update-end-author:sunjianlei date:20200120 for: 动态更改页面标题
|
// update-end-author:sunjianlei date:20200120 for: 动态更改页面标题
|
||||||
|
|
||||||
changePage(key) {
|
changePage(key) {
|
||||||
|
|
|
@ -81,7 +81,8 @@
|
||||||
import ShowAnnouncement from './ShowAnnouncement'
|
import ShowAnnouncement from './ShowAnnouncement'
|
||||||
import store from '@/store/'
|
import store from '@/store/'
|
||||||
import DynamicNotice from './DynamicNotice'
|
import DynamicNotice from './DynamicNotice'
|
||||||
|
import Vue from 'vue'
|
||||||
|
import { ACCESS_TOKEN } from '@/store/mutation-types'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "HeaderNotice",
|
name: "HeaderNotice",
|
||||||
|
@ -107,6 +108,8 @@
|
||||||
stopTimer:false,
|
stopTimer:false,
|
||||||
websock: null,
|
websock: null,
|
||||||
lockReconnect:false,
|
lockReconnect:false,
|
||||||
|
//websocket错误连接次数
|
||||||
|
wsConnectErrorTime:1,
|
||||||
heartCheck:null,
|
heartCheck:null,
|
||||||
formData:{},
|
formData:{},
|
||||||
openPath:''
|
openPath:''
|
||||||
|
@ -201,7 +204,10 @@
|
||||||
var userId = store.getters.userInfo.id;
|
var userId = store.getters.userInfo.id;
|
||||||
var url = window._CONFIG['domianURL'].replace("https://","wss://").replace("http://","ws://")+"/websocket/"+userId;
|
var url = window._CONFIG['domianURL'].replace("https://","wss://").replace("http://","ws://")+"/websocket/"+userId;
|
||||||
//console.log(url);
|
//console.log(url);
|
||||||
this.websock = new WebSocket(url);
|
//update-begin-author:taoyan date:2022-4-22 for: v2.4.6 的 websocket 服务端,存在性能和安全问题。 #3278
|
||||||
|
let token = Vue.ls.get(ACCESS_TOKEN)
|
||||||
|
this.websock = new WebSocket(url, [token]);
|
||||||
|
//update-end-author:taoyan date:2022-4-22 for: v2.4.6 的 websocket 服务端,存在性能和安全问题。 #3278
|
||||||
this.websock.onopen = this.websocketOnopen;
|
this.websock.onopen = this.websocketOnopen;
|
||||||
this.websock.onerror = this.websocketOnerror;
|
this.websock.onerror = this.websocketOnerror;
|
||||||
this.websock.onmessage = this.websocketOnmessage;
|
this.websock.onmessage = this.websocketOnmessage;
|
||||||
|
@ -213,12 +219,21 @@
|
||||||
//this.heartCheck.reset().start();
|
//this.heartCheck.reset().start();
|
||||||
},
|
},
|
||||||
websocketOnerror: function (e) {
|
websocketOnerror: function (e) {
|
||||||
console.log("WebSocket连接发生错误");
|
console.log("WebSocket连接发生错误,第%s次",this.wsConnectErrorTime);
|
||||||
|
|
||||||
|
this.wsConnectErrorTime = this.wsConnectErrorTime + 1;
|
||||||
|
if(this.wsConnectErrorTime>5){
|
||||||
|
console.log("WebSocket连接错误超过5次,就不再重新连了!");
|
||||||
|
this.lockReconnect = true
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
this.reconnect();
|
this.reconnect();
|
||||||
},
|
},
|
||||||
websocketOnmessage: function (e) {
|
websocketOnmessage: function (e) {
|
||||||
console.log("-----接收消息-------",e.data);
|
console.log("-----接收消息-------",e.data);
|
||||||
var data = eval("(" + e.data + ")"); //解析对象
|
var data = eval("(" + e.data + ")"); //解析对象
|
||||||
|
this.voiceBroadcast(data.msgTxt)
|
||||||
if(data.cmd == "topic"){
|
if(data.cmd == "topic"){
|
||||||
//系统通知
|
//系统通知
|
||||||
this.loadData();
|
this.loadData();
|
||||||
|
@ -243,7 +258,13 @@
|
||||||
console.log("send failed (" + err.code + ")");
|
console.log("send failed (" + err.code + ")");
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
//语音播报系统通知
|
||||||
|
voiceBroadcast(text){
|
||||||
|
var url = "http://tts.baidu.com/text2audio?lan=zh&ie=UTF-8&text=" + encodeURI(text); // baidu文字转语音
|
||||||
|
var voiceContent = new Audio(url);
|
||||||
|
voiceContent.src = url;
|
||||||
|
voiceContent.play();
|
||||||
|
},
|
||||||
openNotification (data) {
|
openNotification (data) {
|
||||||
var text = data.msgTxt;
|
var text = data.msgTxt;
|
||||||
const key = `open${Date.now()}`;
|
const key = `open${Date.now()}`;
|
||||||
|
@ -275,7 +296,7 @@
|
||||||
console.info("尝试重连...");
|
console.info("尝试重连...");
|
||||||
that.initWebSocket();
|
that.initWebSocket();
|
||||||
that.lockReconnect = false;
|
that.lockReconnect = false;
|
||||||
}, 5000);
|
}, 20000);
|
||||||
},
|
},
|
||||||
heartCheckFun(){
|
heartCheckFun(){
|
||||||
var that = this;
|
var that = this;
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import xss from "xss"
|
||||||
<template>
|
<template>
|
||||||
<j-modal
|
<j-modal
|
||||||
:title="title"
|
:title="title"
|
||||||
|
@ -24,6 +25,7 @@
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import {getUserList} from '@/api/api'
|
import {getUserList} from '@/api/api'
|
||||||
|
import xss from 'xss'
|
||||||
export default {
|
export default {
|
||||||
name: "SysAnnouncementModal",
|
name: "SysAnnouncementModal",
|
||||||
components: {
|
components: {
|
||||||
|
@ -70,6 +72,11 @@
|
||||||
}
|
}
|
||||||
//update-end---author:wangshuai ---date:20220107 for:将其它页面传递过来的用户名改成用户真实姓名
|
//update-end---author:wangshuai ---date:20220107 for:将其它页面传递过来的用户名改成用户真实姓名
|
||||||
this.visible = true;
|
this.visible = true;
|
||||||
|
//update-begin-author:taoyan date:2022-7-14 for: VUEN-1702 【禁止问题】sql注入漏洞
|
||||||
|
if(record.msgContent){
|
||||||
|
record.msgContent = xss(record.msgContent)
|
||||||
|
}
|
||||||
|
//update-end-author:taoyan date:2022-7-14 for: VUEN-1702 【禁止问题】sql注入漏洞
|
||||||
this.record = record;
|
this.record = record;
|
||||||
},
|
},
|
||||||
handleCancel () {
|
handleCancel () {
|
||||||
|
|
|
@ -23,7 +23,9 @@ export const WebsocketMixin = {
|
||||||
this.socketUrl = this.socketUrl + '/'
|
this.socketUrl = this.socketUrl + '/'
|
||||||
}
|
}
|
||||||
var url = window._CONFIG['domianURL'].replace("https://","wss://").replace("http://","ws://") + this.socketUrl + userId + "/" + token;
|
var url = window._CONFIG['domianURL'].replace("https://","wss://").replace("http://","ws://") + this.socketUrl + userId + "/" + token;
|
||||||
this.websock = new WebSocket(url);
|
//update-begin-author:taoyan date:2022-4-22 for: v2.4.6 的 websocket 服务端,存在性能和安全问题。 #3278
|
||||||
|
this.websock = new WebSocket(url, [token]);
|
||||||
|
//update-end-author:taoyan date:2022-4-22 for: v2.4.6 的 websocket 服务端,存在性能和安全问题。 #3278
|
||||||
this.websock.onopen = this.websocketOnopen;
|
this.websock.onopen = this.websocketOnopen;
|
||||||
this.websock.onerror = this.websocketOnerror;
|
this.websock.onerror = this.websocketOnerror;
|
||||||
this.websock.onmessage = this.websocketOnmessage;
|
this.websock.onmessage = this.websocketOnmessage;
|
||||||
|
|
|
@ -104,23 +104,35 @@ export default class signMd5Utils {
|
||||||
return paramStr;
|
return paramStr;
|
||||||
};
|
};
|
||||||
|
|
||||||
static getDateTimeToString() {
|
/**
|
||||||
const date_ = new Date()
|
* 接口签名用 生成header中的时间戳
|
||||||
const year = date_.getFullYear()
|
* @returns {number}
|
||||||
let month = date_.getMonth() + 1
|
*/
|
||||||
let day = date_.getDate()
|
static getTimestamp(){
|
||||||
if (month < 10) month = '0' + month
|
return new Date().getTime()
|
||||||
if (day < 10) day = '0' + day
|
|
||||||
let hours = date_.getHours()
|
|
||||||
let mins = date_.getMinutes()
|
|
||||||
let secs = date_.getSeconds()
|
|
||||||
const msecs = date_.getMilliseconds()
|
|
||||||
if (hours < 10) hours = '0' + hours
|
|
||||||
if (mins < 10) mins = '0' + mins
|
|
||||||
if (secs < 10) secs = '0' + secs
|
|
||||||
if (msecs < 10) secs = '0' + msecs
|
|
||||||
return year + '' + month + '' + day + '' + hours + '' + mins + '' + secs
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// /**
|
||||||
|
// * 获取客户端时间(签名参数 X_TIMESTAMP)
|
||||||
|
// * @returns {string}
|
||||||
|
// */
|
||||||
|
// static getDateTimeToString() {
|
||||||
|
// const date_ = new Date()
|
||||||
|
// const year = date_.getFullYear()
|
||||||
|
// let month = date_.getMonth() + 1
|
||||||
|
// let day = date_.getDate()
|
||||||
|
// if (month < 10) month = '0' + month
|
||||||
|
// if (day < 10) day = '0' + day
|
||||||
|
// let hours = date_.getHours()
|
||||||
|
// let mins = date_.getMinutes()
|
||||||
|
// let secs = date_.getSeconds()
|
||||||
|
// const msecs = date_.getMilliseconds()
|
||||||
|
// if (hours < 10) hours = '0' + hours
|
||||||
|
// if (mins < 10) mins = '0' + mins
|
||||||
|
// if (secs < 10) secs = '0' + secs
|
||||||
|
// if (msecs < 10) secs = '0' + msecs
|
||||||
|
// return year + '' + month + '' + day + '' + hours + '' + mins + '' + secs
|
||||||
|
// }
|
||||||
// true:数值型的,false:非数值型
|
// true:数值型的,false:非数值型
|
||||||
static myIsNaN(value) {
|
static myIsNaN(value) {
|
||||||
return typeof value === 'number' && !isNaN(value);
|
return typeof value === 'number' && !isNaN(value);
|
||||||
|
|
|
@ -113,6 +113,11 @@ service.interceptors.request.use(config => {
|
||||||
const $route = router.currentRoute
|
const $route = router.currentRoute
|
||||||
if ($route && $route.name && $route.name.startsWith('low-app') && $route.params.appId) {
|
if ($route && $route.name && $route.name.startsWith('low-app') && $route.params.appId) {
|
||||||
config.headers['X-Low-App-ID'] = $route.params.appId
|
config.headers['X-Low-App-ID'] = $route.params.appId
|
||||||
|
// lowApp自定义筛选条件
|
||||||
|
if ($route.params.lowAppFilter) {
|
||||||
|
config.params = {...config.params, ...$route.params.lowAppFilter}
|
||||||
|
delete $route.params.lowAppFilter
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// update-end--author:sunjianlei---date:20200723---for 如果当前在low-app环境,并且携带了appId,就向Header里传递appId
|
// update-end--author:sunjianlei---date:20200723---for 如果当前在low-app环境,并且携带了appId,就向Header里传递appId
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,17 @@
|
||||||
const validateMobile = (rule, value, callback) => {
|
const validateMobile = (rule, value, callback) => {
|
||||||
let reg = /^1(3|4|5|7|8)\d{9}$/
|
let reg = /^1(3|4|5|7|8)\d{9}$/
|
||||||
if (!reg.test(value)) {
|
//update-beign-author:taoyan date:20220316 for: VUEN-329【bug】为什么不是失去焦点的时候,触发手机号校验
|
||||||
callback('请输入正确手机号')
|
if(!value && value!=='0'){
|
||||||
} else {
|
|
||||||
callback()
|
callback()
|
||||||
|
}else{
|
||||||
|
if (!reg.test(value)) {
|
||||||
|
callback('请输入正确手机号')
|
||||||
|
} else {
|
||||||
|
callback()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
//update-end-author:taoyan date:20220316 for: VUEN-329【bug】为什么不是失去焦点的时候,触发手机号校验
|
||||||
|
|
||||||
}
|
}
|
||||||
const validateEn = (rule, value, callback) => {
|
const validateEn = (rule, value, callback) => {
|
||||||
let reg = /^[_a-zA-Z0-9]+$/
|
let reg = /^[_a-zA-Z0-9]+$/
|
||||||
|
@ -24,6 +31,7 @@ export const rules = {
|
||||||
message: '请输入手机号',
|
message: '请输入手机号',
|
||||||
trigger: 'blur'
|
trigger: 'blur'
|
||||||
}, { validator: validateMobile, trigger: 'blur' }],
|
}, { validator: validateMobile, trigger: 'blur' }],
|
||||||
|
mobile2: [{ validator: validateMobile, trigger: 'blur' }],
|
||||||
userName: [{
|
userName: [{
|
||||||
required: true, message: '请输入用户名', trigger: 'blur'
|
required: true, message: '请输入用户名', trigger: 'blur'
|
||||||
}, { validator: validateEn }],
|
}, { validator: validateEn }],
|
||||||
|
|
|
@ -206,7 +206,7 @@ export function randomNumber() {
|
||||||
}
|
}
|
||||||
if (arguments.length === 1) {
|
if (arguments.length === 1) {
|
||||||
let [length] = arguments
|
let [length] = arguments
|
||||||
// 生成指定长度的随机数字,首位一定不是 0
|
// 生成指定长度的随机数字,首位一定不是 0
|
||||||
let nums = [...Array(length).keys()].map((i) => (i > 0 ? random(0, 9) : random(1, 9)))
|
let nums = [...Array(length).keys()].map((i) => (i > 0 ? random(0, 9) : random(1, 9)))
|
||||||
return parseInt(nums.join(''))
|
return parseInt(nums.join(''))
|
||||||
} else if (arguments.length >= 2) {
|
} else if (arguments.length >= 2) {
|
||||||
|
@ -627,3 +627,63 @@ export function aspectAroundFunction(obj, funcName, callback) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 休眠
|
||||||
|
* @param ms 毫秒
|
||||||
|
* @return {Promise<unknown>}
|
||||||
|
*/
|
||||||
|
export function sleep(ms) {
|
||||||
|
return new Promise(function (resolve) {
|
||||||
|
return setTimeout(resolve, ms);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取指定的 $refs 对象
|
||||||
|
* 有时候可能会遇到组件未挂载到页面中的情况,导致无法获取 $refs 中的某个对象
|
||||||
|
* 这个方法可以等待挂载完成之后再返回 $refs 的对象,避免报错
|
||||||
|
*
|
||||||
|
* 用法示例:let modalRef = getRefPromise(this, 'modal')
|
||||||
|
* @param vm vue实例
|
||||||
|
* @param name 要获取的ref名称
|
||||||
|
* @param noComment $el 标签不能是注释
|
||||||
|
**/
|
||||||
|
export function getRefPromise(vm, name, noComment = true) {
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
(function next() {
|
||||||
|
let ref = vm.$refs[name]
|
||||||
|
if (ref && (noComment && ref.$el.tagName)) {
|
||||||
|
resolve(ref)
|
||||||
|
} else {
|
||||||
|
setTimeout(() => {
|
||||||
|
if (noComment) {
|
||||||
|
vm.$forceUpdate()
|
||||||
|
}
|
||||||
|
next()
|
||||||
|
}, 10)
|
||||||
|
}
|
||||||
|
})()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 导出文件xlsx的mime-type
|
||||||
|
* xls: application/vnd.ms-excel
|
||||||
|
* @type {string}
|
||||||
|
*/
|
||||||
|
export const EXPORT_MIME_TYPE = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
|
||||||
|
/**
|
||||||
|
* 导出excel文件后缀
|
||||||
|
* @type {string}
|
||||||
|
*/
|
||||||
|
export const EXPORT_FILE_SUFFIX = ".xlsx";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 字符串是否为null或null字符串
|
||||||
|
* @param str
|
||||||
|
* @return {boolean}
|
||||||
|
*/
|
||||||
|
export function stringIsNull(str) {
|
||||||
|
return str == null || str === 'null' || str === 'undefined';
|
||||||
|
}
|
||||||
|
|
|
@ -538,6 +538,7 @@
|
||||||
superQuery: {
|
superQuery: {
|
||||||
fieldList: [
|
fieldList: [
|
||||||
{ type: 'input', value: 'name', text: '姓名', },
|
{ type: 'input', value: 'name', text: '姓名', },
|
||||||
|
{ type: 'switch', value: 'switch', text: '开关', },
|
||||||
{ type: 'select', value: 'sex', text: '性别', dictCode: 'sex' },
|
{ type: 'select', value: 'sex', text: '性别', dictCode: 'sex' },
|
||||||
{ type: 'number', value: 'age', text: '年龄', },
|
{ type: 'number', value: 'age', text: '年龄', },
|
||||||
{
|
{
|
||||||
|
|
|
@ -24,7 +24,7 @@
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-col :md="6" :sm="8">
|
<a-col :md="6" :sm="8">
|
||||||
<a-form-item label="模板类型">
|
<a-form-item label="模板类型">
|
||||||
<a-input placeholder="请输入模板类型" v-model="queryParam.templateType"></a-input>
|
<j-dict-select-tag placeholder="请选择模板类型" v-model="queryParam.templateType" dictCode="msgType"></j-dict-select-tag>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</a-col>
|
</a-col>
|
||||||
</template>
|
</template>
|
||||||
|
@ -51,7 +51,7 @@
|
||||||
@change="handleImportExcel">
|
@change="handleImportExcel">
|
||||||
<a-button type="primary" icon="import">导入</a-button>
|
<a-button type="primary" icon="import">导入</a-button>
|
||||||
</a-upload>
|
</a-upload>
|
||||||
<a-dropdown v-if="selectedRowKeys.length > 0">
|
<!-- <a-dropdown v-if="selectedRowKeys.length > 0">
|
||||||
<a-menu slot="overlay">
|
<a-menu slot="overlay">
|
||||||
<a-menu-item key="1" @click="batchDel">
|
<a-menu-item key="1" @click="batchDel">
|
||||||
<a-icon type="delete"/>
|
<a-icon type="delete"/>
|
||||||
|
@ -61,7 +61,7 @@
|
||||||
<a-button style="margin-left: 8px"> 批量操作
|
<a-button style="margin-left: 8px"> 批量操作
|
||||||
<a-icon type="down"/>
|
<a-icon type="down"/>
|
||||||
</a-button>
|
</a-button>
|
||||||
</a-dropdown>
|
</a-dropdown>-->
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- table区域-begin -->
|
<!-- table区域-begin -->
|
||||||
|
@ -91,14 +91,21 @@
|
||||||
|
|
||||||
|
|
||||||
<span slot="action" slot-scope="text, record">
|
<span slot="action" slot-scope="text, record">
|
||||||
<a @click="handleEdit(record)">编辑</a>
|
<a @click="handleMyEdit(record)">编辑</a>
|
||||||
|
|
||||||
<a-divider type="vertical"/>
|
<a-divider type="vertical"/>
|
||||||
<a-dropdown>
|
<a-dropdown>
|
||||||
<a class="ant-dropdown-link">更多 <a-icon type="down"/></a>
|
<a class="ant-dropdown-link">更多 <a-icon type="down"/></a>
|
||||||
<a-menu slot="overlay">
|
<a-menu slot="overlay">
|
||||||
<a-menu-item>
|
<a-menu-item>
|
||||||
<a-popconfirm title="确定删除吗?" @confirm="() => handleDelete(record.id)">
|
<a @click="handleUse(record)">应用</a>
|
||||||
|
</a-menu-item>
|
||||||
|
<a-menu-item>
|
||||||
|
<a @click="handleNotUse(record)">停用</a>
|
||||||
|
</a-menu-item>
|
||||||
|
|
||||||
|
<a-menu-item>
|
||||||
|
<a-popconfirm title="确定删除吗?" @confirm="() => handleDelete(record)">
|
||||||
<a>删除</a>
|
<a>删除</a>
|
||||||
</a-popconfirm>
|
</a-popconfirm>
|
||||||
</a-menu-item>
|
</a-menu-item>
|
||||||
|
@ -125,6 +132,10 @@
|
||||||
import SysMessageTestModal from './modules/SysMessageTestModal'
|
import SysMessageTestModal from './modules/SysMessageTestModal'
|
||||||
import {JeecgListMixin} from '@/mixins/JeecgListMixin'
|
import {JeecgListMixin} from '@/mixins/JeecgListMixin'
|
||||||
import JEllipsis from "@/components/jeecg/JEllipsis";
|
import JEllipsis from "@/components/jeecg/JEllipsis";
|
||||||
|
import {httpAction} from '@/api/manage'
|
||||||
|
import { deleteAction } from '@/api/manage'
|
||||||
|
import JDictSelectTag from '@/components/dict/JDictSelectTag.vue'
|
||||||
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "SysMessageTemplateList",
|
name: "SysMessageTemplateList",
|
||||||
|
@ -132,7 +143,8 @@
|
||||||
components: {
|
components: {
|
||||||
JEllipsis,
|
JEllipsis,
|
||||||
SysMessageTemplateModal,
|
SysMessageTemplateModal,
|
||||||
SysMessageTestModal
|
SysMessageTestModal,
|
||||||
|
JDictSelectTag
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
|
@ -171,16 +183,22 @@
|
||||||
dataIndex: 'templateType',
|
dataIndex: 'templateType',
|
||||||
customRender: function (text) {
|
customRender: function (text) {
|
||||||
if(text=='1') {
|
if(text=='1') {
|
||||||
return "短信";
|
return "文本";
|
||||||
}
|
}
|
||||||
if(text=='2') {
|
if(text=='2') {
|
||||||
return "邮件";
|
return "富文本";
|
||||||
}
|
}
|
||||||
if(text=='3') {
|
}
|
||||||
return "微信";
|
},
|
||||||
}
|
{
|
||||||
if(text=='4') {
|
title: '是否应用',
|
||||||
return "系统";
|
align: "center",
|
||||||
|
dataIndex: 'useStatus',
|
||||||
|
customRender: function (text) {
|
||||||
|
if(text=='1') {
|
||||||
|
return "是";
|
||||||
|
}else{
|
||||||
|
return '否'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -209,7 +227,59 @@
|
||||||
handleTest(record){
|
handleTest(record){
|
||||||
this.$refs.testModal.open(record);
|
this.$refs.testModal.open(record);
|
||||||
this.$refs.testModal.title = "发送测试";
|
this.$refs.testModal.title = "发送测试";
|
||||||
}
|
},
|
||||||
|
//update-begin-author:taoyan date:2022-7-8 for: 修改应用状态
|
||||||
|
updateUseStatus(record, useStatus){
|
||||||
|
let formData = {
|
||||||
|
id: record.id, useStatus: useStatus
|
||||||
|
}
|
||||||
|
httpAction("/sys/message/sysMessageTemplate/edit", formData, 'put').then((res) => {
|
||||||
|
if (res.success) {
|
||||||
|
this.$message.success(res.message);
|
||||||
|
} else {
|
||||||
|
this.$message.warning(res.message);
|
||||||
|
}
|
||||||
|
}).finally(() => {
|
||||||
|
this.loadData()
|
||||||
|
})
|
||||||
|
},
|
||||||
|
handleUse(record){
|
||||||
|
this.updateUseStatus(record, '1')
|
||||||
|
},
|
||||||
|
handleNotUse(record){
|
||||||
|
this.updateUseStatus(record, '0')
|
||||||
|
},
|
||||||
|
handleMyEdit(record){
|
||||||
|
if(record.useStatus == '1'){
|
||||||
|
this.$message.warning('此模板已被应用,禁止编辑!');
|
||||||
|
}else{
|
||||||
|
this.handleEdit(record);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
//update-end-author:taoyan date:2022-7-8 for: 修改应用状态
|
||||||
|
|
||||||
|
handleDelete: function (record) {
|
||||||
|
if(!this.url.delete){
|
||||||
|
this.$message.error("请设置url.delete属性!")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if(record.useStatus=='1'){
|
||||||
|
this.$message.error("该模板已被应用禁止删除!")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
let id = record.id;
|
||||||
|
var that = this;
|
||||||
|
deleteAction(that.url.delete, {id: id}).then((res) => {
|
||||||
|
if (res.success) {
|
||||||
|
//重新计算分页问题
|
||||||
|
that.reCalculatePage(1)
|
||||||
|
that.$message.success(res.message);
|
||||||
|
that.loadData();
|
||||||
|
} else {
|
||||||
|
that.$message.warning(res.message);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,6 +50,17 @@
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</a-col>
|
</a-col>
|
||||||
</a-row>
|
</a-row>
|
||||||
|
<a-row class="form-row" :gutter="24" >
|
||||||
|
<a-col :span="24" pull="2">
|
||||||
|
<a-form-item
|
||||||
|
:labelCol="labelCol"
|
||||||
|
:wrapperCol="wrapperCol"
|
||||||
|
label="是否应用"
|
||||||
|
style="margin-left: -15px">
|
||||||
|
<j-switch v-decorator="['useStatus', validatorRules.useStatus]" :options="['1', '0']"></j-switch>
|
||||||
|
</a-form-item>
|
||||||
|
</a-col>
|
||||||
|
</a-row>
|
||||||
<a-row class="form-row" :gutter="24">
|
<a-row class="form-row" :gutter="24">
|
||||||
<a-col :span="24" pull="4">
|
<a-col :span="24" pull="4">
|
||||||
<a-form-item
|
<a-form-item
|
||||||
|
@ -85,11 +96,13 @@
|
||||||
import pick from 'lodash.pick'
|
import pick from 'lodash.pick'
|
||||||
import { duplicateCheck } from '@/api/api'
|
import { duplicateCheck } from '@/api/api'
|
||||||
import JEditor from '@/components/jeecg/JEditor'
|
import JEditor from '@/components/jeecg/JEditor'
|
||||||
|
import JSwitch from '@/components/jeecg/JSwitch'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "SysMessageTemplateModal",
|
name: "SysMessageTemplateModal",
|
||||||
components:{
|
components:{
|
||||||
JEditor
|
JEditor,
|
||||||
|
JSwitch
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
|
@ -111,6 +124,7 @@
|
||||||
templateCode: {rules: [{required: true, message: '请输入模板CODE!' },{validator: this.validateTemplateCode}]},
|
templateCode: {rules: [{required: true, message: '请输入模板CODE!' },{validator: this.validateTemplateCode}]},
|
||||||
templateName: {rules: [{required: true, message: '请输入模板标题!'}]},
|
templateName: {rules: [{required: true, message: '请输入模板标题!'}]},
|
||||||
templateContent: {rules: []},
|
templateContent: {rules: []},
|
||||||
|
useStatus:{rules: []},
|
||||||
templateType: {rules: [{required: true, message: '请输入模板类型!'}]},
|
templateType: {rules: [{required: true, message: '请输入模板类型!'}]},
|
||||||
},
|
},
|
||||||
url: {
|
url: {
|
||||||
|
@ -140,9 +154,9 @@
|
||||||
this.visible = true;
|
this.visible = true;
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
if(this.useEditor){
|
if(this.useEditor){
|
||||||
this.form.setFieldsValue(pick(this.model, 'templateCode', 'templateName', 'templateTestJson', 'templateType'))
|
this.form.setFieldsValue(pick(this.model, 'useStatus', 'templateCode', 'templateName', 'templateTestJson', 'templateType'))
|
||||||
}else{
|
}else{
|
||||||
this.form.setFieldsValue(pick(this.model, 'templateCode', 'templateContent', 'templateName', 'templateTestJson', 'templateType'))
|
this.form.setFieldsValue(pick(this.model, 'useStatus', 'templateCode', 'templateContent', 'templateName', 'templateTestJson', 'templateType'))
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
|
@ -34,14 +34,15 @@
|
||||||
label="消息类型">
|
label="消息类型">
|
||||||
<j-dict-select-tag
|
<j-dict-select-tag
|
||||||
v-model="msgType"
|
v-model="msgType"
|
||||||
|
type="radio"
|
||||||
placeholder="请选择消息类型"
|
placeholder="请选择消息类型"
|
||||||
dictCode="msgType"/>
|
dictCode="messageType"/>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<a-form-item
|
<a-form-item
|
||||||
:labelCol="labelCol"
|
:labelCol="labelCol"
|
||||||
:wrapperCol="wrapperCol"
|
:wrapperCol="wrapperCol"
|
||||||
label="消息接收方">
|
label="消息接收方">
|
||||||
<a-input placeholder="请输入消息接收方" v-model="receiver"/>
|
<j-select-user-by-dep placeholder="请选择消息接收方" v-model="receiver"></j-select-user-by-dep>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</a-form>
|
</a-form>
|
||||||
</a-spin>
|
</a-spin>
|
||||||
|
@ -50,9 +51,13 @@
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import {httpAction} from '@/api/manage'
|
import {httpAction} from '@/api/manage'
|
||||||
|
import JSelectUserByDep from '@/components/jeecgbiz/JSelectUserByDep'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "SysMessageTestModal",
|
name: "SysMessageTestModal",
|
||||||
|
components:{
|
||||||
|
JSelectUserByDep
|
||||||
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
title: "操作",
|
title: "操作",
|
||||||
|
@ -74,7 +79,7 @@
|
||||||
templateName: "",
|
templateName: "",
|
||||||
templateContent: "",
|
templateContent: "",
|
||||||
receiver: "",
|
receiver: "",
|
||||||
msgType: "",
|
msgType: "system",
|
||||||
testData: "",
|
testData: "",
|
||||||
sendParams: {}
|
sendParams: {}
|
||||||
}
|
}
|
||||||
|
@ -89,7 +94,7 @@
|
||||||
},
|
},
|
||||||
close() {
|
close() {
|
||||||
this.receiver = "";
|
this.receiver = "";
|
||||||
this.msgType = "";
|
this.msgType = "system";
|
||||||
this.sendParams = {};
|
this.sendParams = {};
|
||||||
this.visible = false;
|
this.visible = false;
|
||||||
},
|
},
|
||||||
|
|
|
@ -110,10 +110,13 @@
|
||||||
</a-radio-group>
|
</a-radio-group>
|
||||||
</template>
|
</template>
|
||||||
</a-form-model-item>
|
</a-form-model-item>
|
||||||
|
<a-form-model-item :labelCol="labelCol" :wrapperCol="wrapperCol" label="部门负责人">
|
||||||
|
<j-select-multi-user v-model="model.directorUserIds" valueKey="id"></j-select-multi-user>
|
||||||
|
</a-form-model-item>
|
||||||
<a-form-model-item :labelCol="labelCol" :wrapperCol="wrapperCol" label="排序">
|
<a-form-model-item :labelCol="labelCol" :wrapperCol="wrapperCol" label="排序">
|
||||||
<a-input-number v-model="model.departOrder" />
|
<a-input-number v-model="model.departOrder" />
|
||||||
</a-form-model-item>
|
</a-form-model-item>
|
||||||
<a-form-model-item :labelCol="labelCol" :wrapperCol="wrapperCol" label="手机号">
|
<a-form-model-item :labelCol="labelCol" :wrapperCol="wrapperCol" label="手机号" prop="mobile">
|
||||||
<a-input placeholder="请输入手机号" v-model="model.mobile" />
|
<a-input placeholder="请输入手机号" v-model="model.mobile" />
|
||||||
</a-form-model-item>
|
</a-form-model-item>
|
||||||
<a-form-model-item :labelCol="labelCol" :wrapperCol="wrapperCol" label="地址">
|
<a-form-model-item :labelCol="labelCol" :wrapperCol="wrapperCol" label="地址">
|
||||||
|
@ -149,6 +152,7 @@
|
||||||
import {httpAction, deleteAction} from '@/api/manage'
|
import {httpAction, deleteAction} from '@/api/manage'
|
||||||
import {JeecgListMixin} from '@/mixins/JeecgListMixin'
|
import {JeecgListMixin} from '@/mixins/JeecgListMixin'
|
||||||
import DepartAuthModal from './modules/DepartAuthModal'
|
import DepartAuthModal from './modules/DepartAuthModal'
|
||||||
|
import Vue from 'vue'
|
||||||
// 表头
|
// 表头
|
||||||
const columns = [
|
const columns = [
|
||||||
{
|
{
|
||||||
|
@ -236,7 +240,7 @@
|
||||||
departName: [{required: true, message: '请输入机构/部门名称!'}],
|
departName: [{required: true, message: '请输入机构/部门名称!'}],
|
||||||
orgCode: [{required: true, message: '请输入机构编码!'}],
|
orgCode: [{required: true, message: '请输入机构编码!'}],
|
||||||
orgCategory:[{required: true, message: '请输入机构类型!'}],
|
orgCategory:[{required: true, message: '请输入机构类型!'}],
|
||||||
mobile:[{validator: this.validateMobile}]
|
mobile: Vue.prototype.rules.mobile2
|
||||||
},
|
},
|
||||||
url: {
|
url: {
|
||||||
delete: '/sys/sysDepart/delete',
|
delete: '/sys/sysDepart/delete',
|
||||||
|
@ -246,6 +250,7 @@
|
||||||
importExcelUrl: "sys/sysDepart/importExcel",
|
importExcelUrl: "sys/sysDepart/importExcel",
|
||||||
},
|
},
|
||||||
orgCategoryDisabled:false,
|
orgCategoryDisabled:false,
|
||||||
|
oldDirectorUserIds:""
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
@ -394,7 +399,13 @@
|
||||||
this.model.parentId = record.parentId
|
this.model.parentId = record.parentId
|
||||||
this.setValuesToForm(record)
|
this.setValuesToForm(record)
|
||||||
this.$refs.departAuth.show(record.id);
|
this.$refs.departAuth.show(record.id);
|
||||||
|
this.oldDirectorUserIds = record.directorUserIds
|
||||||
|
|
||||||
|
//update-beign-author:taoyan date:20220316 for: VUEN-329【bug】为什么不是失去焦点的时候,触发手机号校验
|
||||||
|
this.$nextTick(()=>{
|
||||||
|
this.$refs.form.validateField('mobile')
|
||||||
|
})
|
||||||
|
//update-end-author:taoyan date:20220316 for: VUEN-329【bug】为什么不是失去焦点的时候,触发手机号校验
|
||||||
},
|
},
|
||||||
// 触发onSelect事件时,为部门树右侧的form表单赋值
|
// 触发onSelect事件时,为部门树右侧的form表单赋值
|
||||||
setValuesToForm(record) {
|
setValuesToForm(record) {
|
||||||
|
@ -431,6 +442,10 @@
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//update-begin---author:wangshuai ---date:20200308 for:[JTC-119]在部门管理菜单下设置部门负责人
|
||||||
|
this.currSelected.oldDirectorUserIds = this.oldDirectorUserIds
|
||||||
|
//update-end---author:wangshuai ---date:20200308 for:[JTC-119]在部门管理菜单下设置部门负责人
|
||||||
|
|
||||||
httpAction(this.url.edit, this.currSelected, 'put').then((res) => {
|
httpAction(this.url.edit, this.currSelected, 'put').then((res) => {
|
||||||
if (res.success) {
|
if (res.success) {
|
||||||
this.$message.success('保存成功!')
|
this.$message.success('保存成功!')
|
||||||
|
|
|
@ -105,6 +105,9 @@
|
||||||
</a-radio-group>
|
</a-radio-group>
|
||||||
</template>
|
</template>
|
||||||
</a-form-model-item>
|
</a-form-model-item>
|
||||||
|
<a-form-model-item :labelCol="labelCol" :wrapperCol="wrapperCol" label="部门负责人">
|
||||||
|
<j-select-multi-user v-model="model.directorUserIds" valueKey="id"></j-select-multi-user>
|
||||||
|
</a-form-model-item>
|
||||||
<a-form-model-item :labelCol="labelCol" :wrapperCol="wrapperCol" label="排序" prop="departOrder">
|
<a-form-model-item :labelCol="labelCol" :wrapperCol="wrapperCol" label="排序" prop="departOrder">
|
||||||
<a-input-number v-model="model.departOrder"/>
|
<a-input-number v-model="model.departOrder"/>
|
||||||
</a-form-model-item>
|
</a-form-model-item>
|
||||||
|
@ -146,6 +149,7 @@
|
||||||
import DepartAuthModal from './modules/DepartAuthModal'
|
import DepartAuthModal from './modules/DepartAuthModal'
|
||||||
import { cloneObject } from '@/utils/util'
|
import { cloneObject } from '@/utils/util'
|
||||||
import JThirdAppButton from '@comp/jeecgbiz/thirdApp/JThirdAppButton'
|
import JThirdAppButton from '@comp/jeecgbiz/thirdApp/JThirdAppButton'
|
||||||
|
import Vue from 'vue'
|
||||||
// 表头
|
// 表头
|
||||||
const columns = [
|
const columns = [
|
||||||
{
|
{
|
||||||
|
@ -239,7 +243,7 @@
|
||||||
departName: [{required: true, message: '请输入机构/部门名称!'}],
|
departName: [{required: true, message: '请输入机构/部门名称!'}],
|
||||||
orgCode: [{required: true, message: '请输入机构编码!'}],
|
orgCode: [{required: true, message: '请输入机构编码!'}],
|
||||||
orgCategory: [{required: true, message: '请输入机构类型!'}],
|
orgCategory: [{required: true, message: '请输入机构类型!'}],
|
||||||
mobile: [{validator: this.validateMobile}]
|
mobile: Vue.prototype.rules.mobile2
|
||||||
},
|
},
|
||||||
url: {
|
url: {
|
||||||
delete: '/sys/sysDepart/delete',
|
delete: '/sys/sysDepart/delete',
|
||||||
|
@ -249,6 +253,7 @@
|
||||||
importExcelUrl: "sys/sysDepart/importExcel",
|
importExcelUrl: "sys/sysDepart/importExcel",
|
||||||
},
|
},
|
||||||
orgCategoryDisabled:false,
|
orgCategoryDisabled:false,
|
||||||
|
oldDirectorUserIds:"" //旧的负责人id
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
@ -435,7 +440,15 @@
|
||||||
this.model.parentId = record.parentId
|
this.model.parentId = record.parentId
|
||||||
this.setValuesToForm(record)
|
this.setValuesToForm(record)
|
||||||
this.$refs.departAuth.show(record.id);
|
this.$refs.departAuth.show(record.id);
|
||||||
|
//update-begin---author:wangshuai ---date:20220316 for:[JTC-119]在部门管理菜单下设置部门负责人
|
||||||
|
this.oldDirectorUserIds = record.directorUserIds
|
||||||
|
//update-end---author:wangshuai ---date:20220316 for:[JTC-119]在部门管理菜单下设置部门负责人
|
||||||
|
|
||||||
|
//update-beign-author:taoyan date:20220316 for: VUEN-329【bug】为什么不是失去焦点的时候,触发手机号校验
|
||||||
|
this.$nextTick(()=>{
|
||||||
|
this.$refs.form.validateField('mobile')
|
||||||
|
})
|
||||||
|
//update-end-author:taoyan date:20220316 for: VUEN-329【bug】为什么不是失去焦点的时候,触发手机号校验
|
||||||
},
|
},
|
||||||
// 触发onSelect事件时,为部门树右侧的form表单赋值
|
// 触发onSelect事件时,为部门树右侧的form表单赋值
|
||||||
setValuesToForm(record) {
|
setValuesToForm(record) {
|
||||||
|
@ -478,6 +491,9 @@
|
||||||
|
|
||||||
let formData = Object.assign(this.currSelected, this.model)
|
let formData = Object.assign(this.currSelected, this.model)
|
||||||
console.log('Received values of form: ', formData)
|
console.log('Received values of form: ', formData)
|
||||||
|
//update-begin---author:wangshuai ---date:20220316 for:[JTC-119]在部门管理菜单下设置部门负责人
|
||||||
|
formData.oldDirectorUserIds = this.oldDirectorUserIds
|
||||||
|
//update-end---author:wangshuai ---date:20220316 for:[JTC-119]在部门管理菜单下设置部门负责人
|
||||||
httpAction(this.url.edit, formData, 'put').then((res) => {
|
httpAction(this.url.edit, formData, 'put').then((res) => {
|
||||||
if (res.success) {
|
if (res.success) {
|
||||||
this.$message.success('保存成功!')
|
this.$message.success('保存成功!')
|
||||||
|
@ -598,16 +614,6 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
// <!---- author:os_chengtgen -- date:20190827 -- for:切换父子勾选模式 =======------>
|
// <!---- author:os_chengtgen -- date:20190827 -- for:切换父子勾选模式 =======------>
|
||||||
|
|
||||||
// 验证手机号
|
|
||||||
validateMobile(rule,value,callback){
|
|
||||||
if (!value || new RegExp(/^1([38][0-9]|4[579]|5[0-3,5-9]|6[6]|7[0135678]|9[89])\d{8}$/).test(value)){
|
|
||||||
callback();
|
|
||||||
}else{
|
|
||||||
callback("您的手机号码格式不正确!");
|
|
||||||
}
|
|
||||||
|
|
||||||
},
|
|
||||||
onSyncFinally({isToLocal}) {
|
onSyncFinally({isToLocal}) {
|
||||||
// 同步到本地时刷新下数据
|
// 同步到本地时刷新下数据
|
||||||
if (isToLocal) {
|
if (isToLocal) {
|
||||||
|
|
|
@ -63,7 +63,6 @@
|
||||||
<a @click="handleOpen(record)">用户</a>
|
<a @click="handleOpen(record)">用户</a>
|
||||||
<a-divider type="vertical"/>
|
<a-divider type="vertical"/>
|
||||||
|
|
||||||
|
|
||||||
<a-dropdown>
|
<a-dropdown>
|
||||||
<a class="ant-dropdown-link">
|
<a class="ant-dropdown-link">
|
||||||
更多 <a-icon type="down"/>
|
更多 <a-icon type="down"/>
|
||||||
|
@ -125,7 +124,7 @@
|
||||||
<a-menu slot="overlay">
|
<a-menu slot="overlay">
|
||||||
<a-menu-item key="1" @click="batchDel2">
|
<a-menu-item key="1" @click="batchDel2">
|
||||||
<a-icon type="delete"/>
|
<a-icon type="delete"/>
|
||||||
删除
|
取消关联
|
||||||
</a-menu-item>
|
</a-menu-item>
|
||||||
</a-menu>
|
</a-menu>
|
||||||
<a-button style="margin-left: 8px"> 批量操作
|
<a-button style="margin-left: 8px"> 批量操作
|
||||||
|
@ -161,8 +160,8 @@
|
||||||
</a>
|
</a>
|
||||||
<a-menu slot="overlay">
|
<a-menu slot="overlay">
|
||||||
<a-menu-item>
|
<a-menu-item>
|
||||||
<a-popconfirm title="确定删除吗?" @confirm="() => handleDelete2(record.id)">
|
<a-popconfirm title="确定取消关联吗?" @confirm="() => handleDelete2(record.id)">
|
||||||
<a>删除</a>
|
<a>取消关联</a>
|
||||||
</a-popconfirm>
|
</a-popconfirm>
|
||||||
</a-menu-item>
|
</a-menu-item>
|
||||||
</a-menu>
|
</a-menu>
|
||||||
|
@ -453,7 +452,7 @@
|
||||||
var that = this
|
var that = this
|
||||||
console.log(this.currentDeptId)
|
console.log(this.currentDeptId)
|
||||||
this.$confirm({
|
this.$confirm({
|
||||||
title: '确认删除',
|
title: '确认取消关联',
|
||||||
content: '是否删除选中数据?',
|
content: '是否删除选中数据?',
|
||||||
onOk: function() {
|
onOk: function() {
|
||||||
deleteAction(that.url.deleteBatch2, { roleId: that.currentRoleId, userIds: ids }).then((res) => {
|
deleteAction(that.url.deleteBatch2, { roleId: that.currentRoleId, userIds: ids }).then((res) => {
|
||||||
|
|
|
@ -115,7 +115,7 @@
|
||||||
align:"center",
|
align:"center",
|
||||||
dataIndex: 'id'
|
dataIndex: 'id'
|
||||||
},
|
},
|
||||||
{
|
/*{
|
||||||
title:'开始时间',
|
title:'开始时间',
|
||||||
align:"center",
|
align:"center",
|
||||||
dataIndex: 'beginDate'
|
dataIndex: 'beginDate'
|
||||||
|
@ -124,7 +124,7 @@
|
||||||
title:'结束时间',
|
title:'结束时间',
|
||||||
align:"center",
|
align:"center",
|
||||||
dataIndex: 'endDate'
|
dataIndex: 'endDate'
|
||||||
},
|
},*/
|
||||||
{
|
{
|
||||||
title:'状态',
|
title:'状态',
|
||||||
align:"center",
|
align:"center",
|
||||||
|
|
|
@ -66,7 +66,7 @@
|
||||||
<!-- 操作按钮区域 -->
|
<!-- 操作按钮区域 -->
|
||||||
<div class="table-operator" style="border-top: 5px">
|
<div class="table-operator" style="border-top: 5px">
|
||||||
<a-button @click="handleAdd" type="primary" icon="plus" >添加用户</a-button>
|
<a-button @click="handleAdd" type="primary" icon="plus" >添加用户</a-button>
|
||||||
<a-button type="primary" icon="download" @click="handleExportXls('用户信息')">导出</a-button>
|
<a-button type="primary" icon="download" @click="handleExportXls('用户信息')">导出</a-button>
|
||||||
<a-upload name="file" :showUploadList="false" :multiple="false" :headers="tokenHeader" :action="importExcelUrl" @change="handleImportExcel">
|
<a-upload name="file" :showUploadList="false" :multiple="false" :headers="tokenHeader" :action="importExcelUrl" @change="handleImportExcel">
|
||||||
<a-button type="primary" icon="import">导入</a-button>
|
<a-button type="primary" icon="import">导入</a-button>
|
||||||
</a-upload>
|
</a-upload>
|
||||||
|
@ -156,10 +156,6 @@
|
||||||
</a-popconfirm>
|
</a-popconfirm>
|
||||||
</a-menu-item>
|
</a-menu-item>
|
||||||
|
|
||||||
<a-menu-item>
|
|
||||||
<a href="javascript:;" @click="handleAgentSettings(record.username)">代理人</a>
|
|
||||||
</a-menu-item>
|
|
||||||
|
|
||||||
</a-menu>
|
</a-menu>
|
||||||
</a-dropdown>
|
</a-dropdown>
|
||||||
</span>
|
</span>
|
||||||
|
@ -378,10 +374,6 @@
|
||||||
handleChangePassword(username) {
|
handleChangePassword(username) {
|
||||||
this.$refs.passwordmodal.show(username);
|
this.$refs.passwordmodal.show(username);
|
||||||
},
|
},
|
||||||
handleAgentSettings(username){
|
|
||||||
this.$refs.sysUserAgentModal.agentSettings(username);
|
|
||||||
this.$refs.sysUserAgentModal.title = "用户代理人设置";
|
|
||||||
},
|
|
||||||
passwordModalOk() {
|
passwordModalOk() {
|
||||||
//TODO 密码修改完成 不需要刷新页面,可以把datasource中的数据更新一下
|
//TODO 密码修改完成 不需要刷新页面,可以把datasource中的数据更新一下
|
||||||
},
|
},
|
||||||
|
|
|
@ -53,6 +53,9 @@
|
||||||
</a-radio-group>
|
</a-radio-group>
|
||||||
</template>
|
</template>
|
||||||
</a-form-model-item>
|
</a-form-model-item>
|
||||||
|
<a-form-model-item :labelCol="labelCol" :wrapperCol="wrapperCol" label="部门负责人">
|
||||||
|
<j-select-multi-user v-model="model.directorUserIds" valueKey="id"></j-select-multi-user>
|
||||||
|
</a-form-model-item>
|
||||||
<a-form-model-item
|
<a-form-model-item
|
||||||
:labelCol="labelCol"
|
:labelCol="labelCol"
|
||||||
:wrapperCol="wrapperCol"
|
:wrapperCol="wrapperCol"
|
||||||
|
|
|
@ -281,6 +281,10 @@
|
||||||
this.$refs.modalForm.title = "编辑";
|
this.$refs.modalForm.title = "编辑";
|
||||||
this.$refs.modalForm.departDisabled = true;
|
this.$refs.modalForm.departDisabled = true;
|
||||||
this.$refs.modalForm.disableSubmit = false;
|
this.$refs.modalForm.disableSubmit = false;
|
||||||
|
//update-begin---author:wangshuai ---date:20220315 for:[issues/3472]给新建用户赋予角色的逻辑漏洞------------
|
||||||
|
//部门中角色信息隐藏掉
|
||||||
|
this.$refs.modalForm.roleDisabled = true
|
||||||
|
//update-end---author:wangshuai ---date:20220315 for:[issues/3472]给新建用户赋予角色的逻辑漏洞------------
|
||||||
this.$refs.modalForm.edit(record);
|
this.$refs.modalForm.edit(record);
|
||||||
},
|
},
|
||||||
handleAdd: function () {
|
handleAdd: function () {
|
||||||
|
@ -288,6 +292,10 @@
|
||||||
this.$message.error("请选择一个部门!")
|
this.$message.error("请选择一个部门!")
|
||||||
} else {
|
} else {
|
||||||
this.$refs.modalForm.departDisabled = true;
|
this.$refs.modalForm.departDisabled = true;
|
||||||
|
//update-begin---author:wangshuai ---date:20220315 for:[issues/3472]给新建用户赋予角色的逻辑漏洞------------
|
||||||
|
//部门中角色信息隐藏掉
|
||||||
|
this.$refs.modalForm.roleDisabled = true
|
||||||
|
//update-end---author:wangshuai ---date:20220315 for:[issues/3472]给新建用户赋予角色的逻辑漏洞------------
|
||||||
//初始化负责部门
|
//初始化负责部门
|
||||||
this.$refs.modalForm.nextDepartOptions=[{value:this.currentDept.key,label:this.currentDept.title}]
|
this.$refs.modalForm.nextDepartOptions=[{value:this.currentDept.key,label:this.currentDept.title}]
|
||||||
this.$refs.modalForm.title = "新增";
|
this.$refs.modalForm.title = "新增";
|
||||||
|
|
|
@ -164,7 +164,7 @@
|
||||||
param.id = this.model.id
|
param.id = this.model.id
|
||||||
}
|
}
|
||||||
if(value){
|
if(value){
|
||||||
let reg=new RegExp("[`_~!@#$^&*()=|{}'.<>《》/?!¥()—【】‘;:”“。,、?]")
|
let reg=new RegExp("[`~!@#$^&*()=|{}'.<>《》/?!¥()—【】‘;:”“。,、?]")
|
||||||
if(reg.test(value)){
|
if(reg.test(value)){
|
||||||
callback("数据值不能包含特殊字符!")
|
callback("数据值不能包含特殊字符!")
|
||||||
}else{
|
}else{
|
||||||
|
|
|
@ -99,7 +99,7 @@
|
||||||
edit: "/sys/annountCement/edit",
|
edit: "/sys/annountCement/edit",
|
||||||
},
|
},
|
||||||
userType:false,
|
userType:false,
|
||||||
userIds:[],
|
userIds:"",
|
||||||
selectedUser:[],
|
selectedUser:[],
|
||||||
disabled:false,
|
disabled:false,
|
||||||
msgContent:"",
|
msgContent:"",
|
||||||
|
@ -191,16 +191,19 @@
|
||||||
},
|
},
|
||||||
resetUser (){
|
resetUser (){
|
||||||
this.userType = false;
|
this.userType = false;
|
||||||
this.userIds = [];
|
//update-begin---author:wangshuai ---date:20220318 for:[issues/I4X63V]vue有些页面报错,但是在线演示的却没有-----
|
||||||
|
this.userIds ="";
|
||||||
|
//update-end---author:wangshuai ---date:20220318 for:[issues/I4X63V]vue有些页面报错,但是在线演示的却没有-----
|
||||||
this.disabled = false;
|
this.disabled = false;
|
||||||
this.$refs.UserListModal.edit(null,null);
|
|
||||||
},
|
},
|
||||||
chooseMsgType(e) {
|
chooseMsgType(e) {
|
||||||
if("USER" == e.target.value) {
|
if("USER" == e.target.value) {
|
||||||
this.userType = true;
|
this.userType = true;
|
||||||
} else {
|
} else {
|
||||||
this.userType = false;
|
this.userType = false;
|
||||||
this.userIds = [];
|
//update-begin---author:wangshuai ---date:20220318 for:[issues/I4X63V]vue有些页面报错,但是在线演示的却没有-----
|
||||||
|
this.userIds = "";
|
||||||
|
//update-end---author:wangshuai ---date:20220318 for:[issues/I4X63V]vue有些页面报错,但是在线演示的却没有-----
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
startTimeValidate(rule,value,callback){
|
startTimeValidate(rule,value,callback){
|
||||||
|
|
|
@ -79,7 +79,7 @@
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import pick from 'lodash.pick'
|
import pick from 'lodash.pick'
|
||||||
import { httpAction, postAction } from '@/api/manage'
|
import { httpAction, postAction,getAction } from '@/api/manage'
|
||||||
import { validateDuplicateValue } from '@/utils/util'
|
import { validateDuplicateValue } from '@/utils/util'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
@ -129,6 +129,7 @@
|
||||||
url: {
|
url: {
|
||||||
add: '/sys/dataSource/add',
|
add: '/sys/dataSource/add',
|
||||||
edit: '/sys/dataSource/edit',
|
edit: '/sys/dataSource/edit',
|
||||||
|
queryById: '/sys/dataSource/queryById',
|
||||||
},
|
},
|
||||||
dbDriverMap: {
|
dbDriverMap: {
|
||||||
// MySQL 数据库
|
// MySQL 数据库
|
||||||
|
@ -202,9 +203,17 @@
|
||||||
add() {
|
add() {
|
||||||
this.edit({})
|
this.edit({})
|
||||||
},
|
},
|
||||||
edit(record) {
|
async edit(record) {
|
||||||
this.form.resetFields()
|
this.form.resetFields()
|
||||||
this.model = Object.assign({}, record)
|
this.model = Object.assign({}, record)
|
||||||
|
//update-begin-author:liusq---date:20220705--for: 编辑时,查询获取解密后的密码 ---
|
||||||
|
if(record.id){
|
||||||
|
let res = await getAction(this.url.queryById, {id:record.id});
|
||||||
|
if (res.success) {
|
||||||
|
this.model = Object.assign({}, {...res.result})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//update-end-author:liusq---date:20220705--for: 编辑时,查询获取解密后的密码 ---
|
||||||
this.visible = true
|
this.visible = true
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
this.form.setFieldsValue(pick(this.model, 'code', 'name', 'remark', 'dbType', 'dbDriver', 'dbUrl', 'dbName', 'dbUsername', 'dbPassword'))
|
this.form.setFieldsValue(pick(this.model, 'code', 'name', 'remark', 'dbType', 'dbDriver', 'dbUrl', 'dbName', 'dbUsername', 'dbPassword'))
|
||||||
|
|
|
@ -55,6 +55,11 @@
|
||||||
ruleClass: [{ required: true, message: '规则实现类不能为空' }],
|
ruleClass: [{ required: true, message: '规则实现类不能为空' }],
|
||||||
ruleParams: [{
|
ruleParams: [{
|
||||||
validator: (rule, value, callback) => {
|
validator: (rule, value, callback) => {
|
||||||
|
//update-begin---author:wangshuai ---date:20220509 for:[VUEN-907]规则参数不是必填,如果为空不检验即可------------
|
||||||
|
if (!value) {
|
||||||
|
callback()
|
||||||
|
}
|
||||||
|
//update-end---author:wangshuai ---date:20220509 for:[VUEN-907]规则参数不是必填,如果为空不检验即可--------------
|
||||||
|
|
||||||
try {
|
try {
|
||||||
let json = JSON.parse(value)
|
let json = JSON.parse(value)
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
</a-form-model-item>
|
</a-form-model-item>
|
||||||
</a-col>
|
</a-col>
|
||||||
|
|
||||||
<a-col :span="24">
|
<!-- <a-col :span="24">
|
||||||
<a-form-model-item label="开始时间" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
<a-form-model-item label="开始时间" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||||
<j-date placeholder="请选择开始时间" v-model="model.beginDate" :show-time="true" date-format="YYYY-MM-DD HH:mm:ss" style="width: 100%"/>
|
<j-date placeholder="请选择开始时间" v-model="model.beginDate" :show-time="true" date-format="YYYY-MM-DD HH:mm:ss" style="width: 100%"/>
|
||||||
</a-form-model-item>
|
</a-form-model-item>
|
||||||
|
@ -24,7 +24,8 @@
|
||||||
<a-form-model-item label="结束时间" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
<a-form-model-item label="结束时间" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||||
<j-date placeholder="请选择结束时间" v-model="model.endDate" :show-time="true" date-format="YYYY-MM-DD HH:mm:ss" style="width: 100%"/>
|
<j-date placeholder="请选择结束时间" v-model="model.endDate" :show-time="true" date-format="YYYY-MM-DD HH:mm:ss" style="width: 100%"/>
|
||||||
</a-form-model-item>
|
</a-form-model-item>
|
||||||
</a-col>
|
</a-col>-->
|
||||||
|
|
||||||
<a-col :span="24">
|
<a-col :span="24">
|
||||||
<a-form-model-item label="状态" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
<a-form-model-item label="状态" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||||
<a-radio-group name="tenantStatus" v-model="model.status">
|
<a-radio-group name="tenantStatus" v-model="model.status">
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
<template>
|
<template>
|
||||||
<a-drawer
|
<a-drawer
|
||||||
:title="title"
|
:title="title"
|
||||||
:maskClosable="true"
|
:maskClosable="true"
|
||||||
:width="drawerWidth"
|
:width="drawerWidth"
|
||||||
placement="right"
|
placement="right"
|
||||||
:closable="true"
|
:closable="true"
|
||||||
@close="handleCancel"
|
@close="handleCancel"
|
||||||
:visible="visible"
|
:visible="visible"
|
||||||
style="height: 100%;">
|
style="height: 100%;">
|
||||||
|
|
||||||
<template slot="title">
|
<template slot="title">
|
||||||
<div style="width: 100%;">
|
<div style="width: 100%;">
|
||||||
|
@ -54,10 +54,10 @@
|
||||||
|
|
||||||
<a-form-model-item label="角色分配" :labelCol="labelCol" :wrapperCol="wrapperCol" v-show="!roleDisabled" >
|
<a-form-model-item label="角色分配" :labelCol="labelCol" :wrapperCol="wrapperCol" v-show="!roleDisabled" >
|
||||||
<j-multi-select-tag
|
<j-multi-select-tag
|
||||||
:disabled="disableSubmit"
|
:disabled="disableSubmit"
|
||||||
v-model="model.selectedroles"
|
v-model="model.selectedroles"
|
||||||
:options="rolesOptions"
|
:options="rolesOptions"
|
||||||
placeholder="请选择角色">
|
placeholder="请选择角色">
|
||||||
</j-multi-select-tag>
|
</j-multi-select-tag>
|
||||||
</a-form-model-item>
|
</a-form-model-item>
|
||||||
|
|
||||||
|
@ -69,10 +69,10 @@
|
||||||
<!--租户分配-->
|
<!--租户分配-->
|
||||||
<a-form-model-item label="租户分配" :labelCol="labelCol" :wrapperCol="wrapperCol" v-show="!departDisabled">
|
<a-form-model-item label="租户分配" :labelCol="labelCol" :wrapperCol="wrapperCol" v-show="!departDisabled">
|
||||||
<j-multi-select-tag
|
<j-multi-select-tag
|
||||||
:disabled="disableSubmit"
|
:disabled="disableSubmit"
|
||||||
v-model="model.relTenantIds"
|
v-model="model.relTenantIds"
|
||||||
:options="tenantsOptions"
|
:options="tenantsOptions"
|
||||||
placeholder="请选择租户">
|
placeholder="请选择租户">
|
||||||
</j-multi-select-tag>
|
</j-multi-select-tag>
|
||||||
</a-form-model-item>
|
</a-form-model-item>
|
||||||
|
|
||||||
|
@ -82,12 +82,12 @@
|
||||||
<a-radio :value="2">上级</a-radio>
|
<a-radio :value="2">上级</a-radio>
|
||||||
</a-radio-group>
|
</a-radio-group>
|
||||||
</a-form-model-item>
|
</a-form-model-item>
|
||||||
<a-form-model-item label="负责部门" :labelCol="labelCol" :wrapperCol="wrapperCol" v-if="departIdShow==true">
|
<a-form-model-item label="负责部门" :labelCol="labelCol" :wrapperCol="wrapperCol" v-show="departIdShow==true">
|
||||||
<j-multi-select-tag
|
<j-multi-select-tag
|
||||||
:disabled="disableSubmit"
|
:disabled="disableSubmit"
|
||||||
v-model="model.departIds"
|
v-model="model.departIds"
|
||||||
:options="nextDepartOptions"
|
:options="nextDepartOptions"
|
||||||
placeholder="请选择负责部门">
|
placeholder="请选择负责部门">
|
||||||
</j-multi-select-tag>
|
</j-multi-select-tag>
|
||||||
</a-form-model-item>
|
</a-form-model-item>
|
||||||
|
|
||||||
|
@ -97,11 +97,11 @@
|
||||||
|
|
||||||
<a-form-model-item label="生日" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
<a-form-model-item label="生日" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||||
<a-date-picker
|
<a-date-picker
|
||||||
style="width: 100%"
|
style="width: 100%"
|
||||||
placeholder="请选择生日"
|
placeholder="请选择生日"
|
||||||
v-model="model.birthday"
|
v-model="model.birthday"
|
||||||
:format="dateFormat"
|
:format="dateFormat"
|
||||||
:getCalendarContainer="node => node.parentNode"/>
|
:getCalendarContainer="node => node.parentNode"/>
|
||||||
</a-form-model-item>
|
</a-form-model-item>
|
||||||
|
|
||||||
<a-form-model-item label="性别" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
<a-form-model-item label="性别" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||||
|
@ -162,17 +162,17 @@
|
||||||
dateFormat:"YYYY-MM-DD",
|
dateFormat:"YYYY-MM-DD",
|
||||||
validatorRules:{
|
validatorRules:{
|
||||||
username:[{required: true, message: '请输入用户账号!'},
|
username:[{required: true, message: '请输入用户账号!'},
|
||||||
{validator: this.validateUsername,}],
|
{validator: this.validateUsername,}],
|
||||||
password: [{required: true,pattern:/^(?=.*[a-zA-Z])(?=.*\d)(?=.*[~!@#$%^&*()_+`\-={}:";'<>?,./]).{8,}$/,message: '密码由8位数字、大小写字母和特殊符号组成!'},
|
password: [{required: true,pattern:/^(?=.*[a-zA-Z])(?=.*\d)(?=.*[~!@#$%^&*()_+`\-={}:";'<>?,./]).{8,}$/,message: '密码由8位数字、大小写字母和特殊符号组成!'},
|
||||||
{validator: this.validateToNextPassword,trigger: 'change'}],
|
{validator: this.validateToNextPassword,trigger: 'change'}],
|
||||||
confirmpassword: [{required: true, message: '请重新输入登录密码!',},
|
confirmpassword: [{required: true, message: '请重新输入登录密码!',},
|
||||||
{ validator: this.compareToFirstPassword,}],
|
{ validator: this.compareToFirstPassword,}],
|
||||||
realname:[{ required: true, message: '请输入用户名称!' }],
|
realname:[{ required: true, message: '请输入用户名称!' }],
|
||||||
phone: [{required: true, message: '请输入手机号!'}, {validator: this.validatePhone}],
|
phone: [{required: true, message: '请输入手机号!'}, {validator: this.validatePhone}],
|
||||||
email: [{validator: this.validateEmail}],
|
email: [{validator: this.validateEmail}],
|
||||||
roles:{},
|
roles:{},
|
||||||
workNo:[ { required: true, message: '请输入工号' },
|
workNo:[ { required: true, message: '请输入工号' },
|
||||||
{ validator: this.validateWorkNo }],
|
{ validator: this.validateWorkNo }],
|
||||||
telephone: [{ pattern: /^0\d{2,3}-[1-9]\d{6,7}$/, message: '请输入正确的座机号码' },]
|
telephone: [{ pattern: /^0\d{2,3}-[1-9]\d{6,7}$/, message: '请输入正确的座机号码' },]
|
||||||
},
|
},
|
||||||
departIdShow:false,
|
departIdShow:false,
|
||||||
|
@ -441,11 +441,11 @@
|
||||||
};
|
};
|
||||||
duplicateCheck(params).then((res) => {
|
duplicateCheck(params).then((res) => {
|
||||||
if (res.success) {
|
if (res.success) {
|
||||||
callback()
|
callback()
|
||||||
} else {
|
} else {
|
||||||
callback("用户名已存在!")
|
callback("用户名已存在!")
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
validateWorkNo(rule, value, callback){
|
validateWorkNo(rule, value, callback){
|
||||||
var params = {
|
var params = {
|
||||||
|
@ -476,9 +476,9 @@
|
||||||
},
|
},
|
||||||
identityChange(e){
|
identityChange(e){
|
||||||
if(e.target.value===1){
|
if(e.target.value===1){
|
||||||
this.departIdShow=false;
|
this.departIdShow=false;
|
||||||
}else{
|
}else{
|
||||||
this.departIdShow=true;
|
this.departIdShow=true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,8 +43,8 @@
|
||||||
currdatetime: '',
|
currdatetime: '',
|
||||||
loginType: 0,
|
loginType: 0,
|
||||||
model:{
|
model:{
|
||||||
username: '',
|
username: 'admin',
|
||||||
password: '',
|
password: '123456',
|
||||||
inputCode: ''
|
inputCode: ''
|
||||||
},
|
},
|
||||||
validatorRules:{
|
validatorRules:{
|
||||||
|
@ -136,6 +136,11 @@
|
||||||
this.Login(loginParams).then((res) => {
|
this.Login(loginParams).then((res) => {
|
||||||
this.$emit('success', res.result)
|
this.$emit('success', res.result)
|
||||||
}).catch((err) => {
|
}).catch((err) => {
|
||||||
|
//update-begin-author: taoyan date:20220425 for: 登录页面,当输入验证码错误时,验证码图片要刷新一下,而不是保持旧的验证码图片不变 #41
|
||||||
|
if(err && err.code===412){
|
||||||
|
this.handleChangeCheckCode();
|
||||||
|
}
|
||||||
|
//update-end-author: taoyan date:20220425 for: 登录页面,当输入验证码错误时,验证码图片要刷新一下,而不是保持旧的验证码图片不变 #41
|
||||||
this.$emit('fail', err)
|
this.$emit('fail', err)
|
||||||
});
|
});
|
||||||
}else{
|
}else{
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
Jeecg-Boot 低代码开发平台
|
Jeecg-Boot 低代码开发平台
|
||||||
===============
|
===============
|
||||||
|
|
||||||
当前最新版本: 3.2.0(发布日期:20220425)
|
当前最新版本: 3.3.0(发布日期:20220725)
|
||||||
|
|
||||||
|
|
||||||
## 后端技术架构
|
## 后端技术架构
|
||||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -1,16 +0,0 @@
|
||||||
-- ----------------------------
|
|
||||||
-- Table structure for sys_role_index
|
|
||||||
-- ----------------------------
|
|
||||||
CREATE TABLE `sys_role_index` (
|
|
||||||
`id` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
|
|
||||||
`role_code` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '角色编码',
|
|
||||||
`url` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '路由地址',
|
|
||||||
`priority` int(11) NULL DEFAULT 0 COMMENT '优先级',
|
|
||||||
`status` varchar(2) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '0' COMMENT '状态0:无效 1:有效',
|
|
||||||
`create_by` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '创建人登录名称',
|
|
||||||
`create_time` datetime NULL DEFAULT NULL COMMENT '创建日期',
|
|
||||||
`update_by` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '更新人登录名称',
|
|
||||||
`update_time` datetime NULL DEFAULT NULL COMMENT '更新日期',
|
|
||||||
`sys_org_code` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '所属部门',
|
|
||||||
PRIMARY KEY (`id`) USING BTREE
|
|
||||||
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '角色首页表' ROW_FORMAT = Dynamic;
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
|
||||||
|
ALTER TABLE `sys_user`
|
||||||
|
MODIFY COLUMN `org_code` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '登录会话的机构编码' AFTER `phone`;
|
||||||
|
|
||||||
|
ALTER TABLE `sys_role_index`
|
||||||
|
ADD COLUMN `component` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '组件' AFTER `url`,
|
||||||
|
ADD COLUMN `is_route` tinyint(1) NULL DEFAULT 1 COMMENT '是否路由菜单: 0:不是 1:是(默认值1)' AFTER `component`;
|
||||||
|
|
||||||
|
ALTER TABLE `jeecg_order_main`
|
||||||
|
ADD COLUMN `bpm_status` varchar(3) NULL COMMENT '流程状态' AFTER `update_time`;
|
||||||
|
|
||||||
|
UPDATE `sys_dict_item` SET `dict_id` = '4f69be5f507accea8d5df5f11346181a', `item_text` = '文本', `item_value` = '1', `description` = '', `sort_order` = 1, `status` = 1, `create_by` = 'admin', `create_time` = '2023-02-28 10:50:36', `update_by` = 'admin', `update_time` = '2022-07-04 16:29:21' WHERE `id` = '222705e11ef0264d4214affff1fb4ff9';
|
||||||
|
UPDATE `sys_dict_item` SET `dict_id` = '4f69be5f507accea8d5df5f11346181a', `item_text` = '富文本', `item_value` = '2', `description` = '', `sort_order` = 2, `status` = 1, `create_by` = 'admin', `create_time` = '2031-02-28 10:50:44', `update_by` = 'admin', `update_time` = '2022-07-04 16:29:30' WHERE `id` = '6a7a9e1403a7943aba69e54ebeff9762';
|
||||||
|
delete from sys_dict_item where id in ('1199607547704647681', '8bccb963e1cd9e8d42482c54cc609ca2');
|
||||||
|
update sys_sms_template set template_type = '2' where template_type='4';
|
||||||
|
update sys_sms_template set template_type = '1' where template_type='3';
|
||||||
|
|
||||||
|
ALTER TABLE `sys_sms_template`
|
||||||
|
ADD COLUMN `use_status` varchar(1) NULL COMMENT '是否使用中 1是0否' AFTER `update_by`;
|
||||||
|
|
||||||
|
ALTER TABLE `sys_sms`
|
||||||
|
MODIFY COLUMN `es_type` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '发送方式:参考枚举MessageTypeEnum' AFTER `es_title`;
|
|
@ -5,7 +5,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<artifactId>jeecg-boot-base-api</artifactId>
|
<artifactId>jeecg-boot-base-api</artifactId>
|
||||||
<groupId>org.jeecgframework.boot</groupId>
|
<groupId>org.jeecgframework.boot</groupId>
|
||||||
<version>3.2.0</version>
|
<version>3.3.0</version>
|
||||||
</parent>
|
</parent>
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
|
|
@ -536,4 +536,17 @@ public interface ISysBaseAPI extends CommonAPI {
|
||||||
@GetMapping("/sys/api/translateDictFromTableByKeys")
|
@GetMapping("/sys/api/translateDictFromTableByKeys")
|
||||||
List<DictModel> translateDictFromTableByKeys(@RequestParam("table") String table, @RequestParam("text") String text, @RequestParam("code") String code, @RequestParam("keys") String keys);
|
List<DictModel> translateDictFromTableByKeys(@RequestParam("table") String table, @RequestParam("text") String text, @RequestParam("code") String code, @RequestParam("keys") String keys);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发送模板消息
|
||||||
|
*/
|
||||||
|
@PostMapping("/sys/api/sendTemplateMessage")
|
||||||
|
void sendTemplateMessage(@RequestBody MessageDTO message);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取模板内容
|
||||||
|
* @param code
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@GetMapping("/sys/api/getTemplateContent")
|
||||||
|
String getTemplateContent(@RequestParam("code") String code);
|
||||||
}
|
}
|
||||||
|
|
|
@ -278,6 +278,15 @@ public class SysBaseAPIFallback implements ISysBaseAPI {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void sendTemplateMessage(MessageDTO message) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getTemplateContent(String code) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void sendEmailMsg(String email,String title,String content) {
|
public void sendEmailMsg(String email,String title,String content) {
|
||||||
|
|
||||||
|
|
|
@ -101,7 +101,7 @@
|
||||||
// log.info(" Feign request params sign: {}",sign);
|
// log.info(" Feign request params sign: {}",sign);
|
||||||
// log.info("============================ [end] fegin api url ============================");
|
// log.info("============================ [end] fegin api url ============================");
|
||||||
// requestTemplate.header(CommonConstant.X_SIGN, sign);
|
// requestTemplate.header(CommonConstant.X_SIGN, sign);
|
||||||
// requestTemplate.header(CommonConstant.X_TIMESTAMP, DateUtils.getCurrentTimestamp().toString());
|
// requestTemplate.header(CommonConstant.X_TIMESTAMP, String.valueOf(System.currentTimeMillis()));
|
||||||
// } catch (IOException e) {
|
// } catch (IOException e) {
|
||||||
// e.printStackTrace();
|
// e.printStackTrace();
|
||||||
// }
|
// }
|
||||||
|
@ -146,7 +146,7 @@
|
||||||
// return new SpringEncoder(feignHttpMessageConverter());
|
// return new SpringEncoder(feignHttpMessageConverter());
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
// @Bean
|
// @Bean("apiFeignDecoder")
|
||||||
// public Decoder feignDecoder() {
|
// public Decoder feignDecoder() {
|
||||||
// return new SpringDecoder(feignHttpMessageConverter());
|
// return new SpringDecoder(feignHttpMessageConverter());
|
||||||
// }
|
// }
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<artifactId>jeecg-boot-base-api</artifactId>
|
<artifactId>jeecg-boot-base-api</artifactId>
|
||||||
<groupId>org.jeecgframework.boot</groupId>
|
<groupId>org.jeecgframework.boot</groupId>
|
||||||
<version>3.2.0</version>
|
<version>3.3.0</version>
|
||||||
</parent>
|
</parent>
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
|
|
@ -338,4 +338,17 @@ public interface ISysBaseAPI extends CommonAPI {
|
||||||
*/
|
*/
|
||||||
List<DictModel> loadDictItemByKeyword(String dictCode, String keyword, Integer pageSize);
|
List<DictModel> loadDictItemByKeyword(String dictCode, String keyword, Integer pageSize);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发送模板消息
|
||||||
|
* @param message
|
||||||
|
*/
|
||||||
|
void sendTemplateMessage(MessageDTO message);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据模板编码获取模板内容
|
||||||
|
* @param templateCode
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
String getTemplateContent(String templateCode);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<artifactId>jeecg-boot-base</artifactId>
|
<artifactId>jeecg-boot-base</artifactId>
|
||||||
<groupId>org.jeecgframework.boot</groupId>
|
<groupId>org.jeecgframework.boot</groupId>
|
||||||
<version>3.2.0</version>
|
<version>3.3.0</version>
|
||||||
</parent>
|
</parent>
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>org.jeecgframework.boot</groupId>
|
<groupId>org.jeecgframework.boot</groupId>
|
||||||
<artifactId>jeecg-boot-base</artifactId>
|
<artifactId>jeecg-boot-base</artifactId>
|
||||||
<version>3.2.0</version>
|
<version>3.3.0</version>
|
||||||
</parent>
|
</parent>
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,7 @@ import lombok.Data;
|
||||||
import org.jeecg.common.constant.CommonConstant;
|
import org.jeecg.common.constant.CommonConstant;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 普通消息
|
* 普通消息
|
||||||
|
@ -72,4 +73,18 @@ public class MessageDTO implements Serializable {
|
||||||
this.category = category;
|
this.category = category;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 模板消息对应的模板编码
|
||||||
|
*/
|
||||||
|
protected String templateCode;
|
||||||
|
/**
|
||||||
|
* 消息类型:org.jeecg.common.constant.enums.MessageTypeEnum
|
||||||
|
*/
|
||||||
|
protected String type;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 解析模板内容 对应的数据
|
||||||
|
*/
|
||||||
|
protected Map<String, Object> data;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,6 +40,8 @@ public class PermissionDataAspect {
|
||||||
@Autowired
|
@Autowired
|
||||||
private CommonAPI commonApi;
|
private CommonAPI commonApi;
|
||||||
|
|
||||||
|
private static final String SPOT_DO = ".do";
|
||||||
|
|
||||||
@Pointcut("@annotation(org.jeecg.common.aspect.annotation.PermissionData)")
|
@Pointcut("@annotation(org.jeecg.common.aspect.annotation.PermissionData)")
|
||||||
public void pointCut() {
|
public void pointCut() {
|
||||||
|
|
||||||
|
@ -113,7 +115,7 @@ public class PermissionDataAspect {
|
||||||
requestPath = requestPath.substring(0, requestPath.indexOf("&"));
|
requestPath = requestPath.substring(0, requestPath.indexOf("&"));
|
||||||
}
|
}
|
||||||
if(requestPath.indexOf(QueryRuleEnum.EQ.getValue())!=-1){
|
if(requestPath.indexOf(QueryRuleEnum.EQ.getValue())!=-1){
|
||||||
if(requestPath.indexOf(CommonConstant.SPOT_DO)!=-1){
|
if(requestPath.indexOf(SPOT_DO)!=-1){
|
||||||
requestPath = requestPath.substring(0,requestPath.indexOf(".do")+3);
|
requestPath = requestPath.substring(0,requestPath.indexOf(".do")+3);
|
||||||
}else{
|
}else{
|
||||||
requestPath = requestPath.substring(0,requestPath.indexOf("?"));
|
requestPath = requestPath.substring(0,requestPath.indexOf("?"));
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
package org.jeecg.common.aspect.annotation;
|
||||||
|
|
||||||
|
import java.lang.annotation.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 动态table切换
|
||||||
|
*
|
||||||
|
* @author :zyf
|
||||||
|
* @date:2020-04-25
|
||||||
|
*/
|
||||||
|
@Target(ElementType.METHOD)
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
@Documented
|
||||||
|
public @interface DynamicTable {
|
||||||
|
/**
|
||||||
|
* 需要动态解析的表名
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
String value();
|
||||||
|
}
|
|
@ -9,320 +9,321 @@ public interface CommonConstant {
|
||||||
/**
|
/**
|
||||||
* 正常状态
|
* 正常状态
|
||||||
*/
|
*/
|
||||||
public static final Integer STATUS_NORMAL = 0;
|
Integer STATUS_NORMAL = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 禁用状态
|
* 禁用状态
|
||||||
*/
|
*/
|
||||||
public static final Integer STATUS_DISABLE = -1;
|
Integer STATUS_DISABLE = -1;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 删除标志
|
* 删除标志
|
||||||
*/
|
*/
|
||||||
public static final Integer DEL_FLAG_1 = 1;
|
Integer DEL_FLAG_1 = 1;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 未删除
|
* 未删除
|
||||||
*/
|
*/
|
||||||
public static final Integer DEL_FLAG_0 = 0;
|
Integer DEL_FLAG_0 = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 系统日志类型: 登录
|
* 系统日志类型: 登录
|
||||||
*/
|
*/
|
||||||
public static final int LOG_TYPE_1 = 1;
|
int LOG_TYPE_1 = 1;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 系统日志类型: 操作
|
* 系统日志类型: 操作
|
||||||
*/
|
*/
|
||||||
public static final int LOG_TYPE_2 = 2;
|
int LOG_TYPE_2 = 2;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 操作日志类型: 查询
|
* 操作日志类型: 查询
|
||||||
*/
|
*/
|
||||||
public static final int OPERATE_TYPE_1 = 1;
|
int OPERATE_TYPE_1 = 1;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 操作日志类型: 添加
|
* 操作日志类型: 添加
|
||||||
*/
|
*/
|
||||||
public static final int OPERATE_TYPE_2 = 2;
|
int OPERATE_TYPE_2 = 2;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 操作日志类型: 更新
|
* 操作日志类型: 更新
|
||||||
*/
|
*/
|
||||||
public static final int OPERATE_TYPE_3 = 3;
|
int OPERATE_TYPE_3 = 3;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 操作日志类型: 删除
|
* 操作日志类型: 删除
|
||||||
*/
|
*/
|
||||||
public static final int OPERATE_TYPE_4 = 4;
|
int OPERATE_TYPE_4 = 4;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 操作日志类型: 倒入
|
* 操作日志类型: 倒入
|
||||||
*/
|
*/
|
||||||
public static final int OPERATE_TYPE_5 = 5;
|
int OPERATE_TYPE_5 = 5;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 操作日志类型: 导出
|
* 操作日志类型: 导出
|
||||||
*/
|
*/
|
||||||
public static final int OPERATE_TYPE_6 = 6;
|
int OPERATE_TYPE_6 = 6;
|
||||||
|
|
||||||
|
|
||||||
/** {@code 500 Server Error} (HTTP/1.0 - RFC 1945) */
|
/** {@code 500 Server Error} (HTTP/1.0 - RFC 1945) */
|
||||||
public static final Integer SC_INTERNAL_SERVER_ERROR_500 = 500;
|
Integer SC_INTERNAL_SERVER_ERROR_500 = 500;
|
||||||
/** {@code 200 OK} (HTTP/1.0 - RFC 1945) */
|
/** {@code 200 OK} (HTTP/1.0 - RFC 1945) */
|
||||||
public static final Integer SC_OK_200 = 200;
|
Integer SC_OK_200 = 200;
|
||||||
|
|
||||||
/**访问权限认证未通过 510*/
|
/**访问权限认证未通过 510*/
|
||||||
public static final Integer SC_JEECG_NO_AUTHZ=510;
|
Integer SC_JEECG_NO_AUTHZ=510;
|
||||||
|
|
||||||
/** 登录用户Shiro权限缓存KEY前缀 */
|
/** 登录用户Shiro权限缓存KEY前缀 */
|
||||||
public static String PREFIX_USER_SHIRO_CACHE = "shiro:cache:org.jeecg.config.shiro.ShiroRealm.authorizationCache:";
|
public static String PREFIX_USER_SHIRO_CACHE = "shiro:cache:org.jeecg.config.shiro.ShiroRealm.authorizationCache:";
|
||||||
/** 登录用户Token令牌缓存KEY前缀 */
|
/** 登录用户Token令牌缓存KEY前缀 */
|
||||||
public static final String PREFIX_USER_TOKEN = "prefix_user_token_";
|
String PREFIX_USER_TOKEN = "prefix_user_token_";
|
||||||
// /** Token缓存时间:3600秒即一小时 */
|
// /** Token缓存时间:3600秒即一小时 */
|
||||||
// public static final int TOKEN_EXPIRE_TIME = 3600;
|
// int TOKEN_EXPIRE_TIME = 3600;
|
||||||
|
|
||||||
/** 登录二维码 */
|
/** 登录二维码 */
|
||||||
public static final String LOGIN_QRCODE_PRE = "QRCODELOGIN:";
|
String LOGIN_QRCODE_PRE = "QRCODELOGIN:";
|
||||||
public static final String LOGIN_QRCODE = "LQ:";
|
String LOGIN_QRCODE = "LQ:";
|
||||||
/** 登录二维码token */
|
/** 登录二维码token */
|
||||||
public static final String LOGIN_QRCODE_TOKEN = "LQT:";
|
String LOGIN_QRCODE_TOKEN = "LQT:";
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 0:一级菜单
|
* 0:一级菜单
|
||||||
*/
|
*/
|
||||||
public static final Integer MENU_TYPE_0 = 0;
|
Integer MENU_TYPE_0 = 0;
|
||||||
/**
|
/**
|
||||||
* 1:子菜单
|
* 1:子菜单
|
||||||
*/
|
*/
|
||||||
public static final Integer MENU_TYPE_1 = 1;
|
Integer MENU_TYPE_1 = 1;
|
||||||
/**
|
/**
|
||||||
* 2:按钮权限
|
* 2:按钮权限
|
||||||
*/
|
*/
|
||||||
public static final Integer MENU_TYPE_2 = 2;
|
Integer MENU_TYPE_2 = 2;
|
||||||
|
|
||||||
/**通告对象类型(USER:指定用户,ALL:全体用户)*/
|
/**通告对象类型(USER:指定用户,ALL:全体用户)*/
|
||||||
public static final String MSG_TYPE_UESR = "USER";
|
String MSG_TYPE_UESR = "USER";
|
||||||
public static final String MSG_TYPE_ALL = "ALL";
|
String MSG_TYPE_ALL = "ALL";
|
||||||
|
|
||||||
/**发布状态(0未发布,1已发布,2已撤销)*/
|
/**发布状态(0未发布,1已发布,2已撤销)*/
|
||||||
public static final String NO_SEND = "0";
|
String NO_SEND = "0";
|
||||||
public static final String HAS_SEND = "1";
|
String HAS_SEND = "1";
|
||||||
public static final String HAS_CANCLE = "2";
|
String HAS_CANCLE = "2";
|
||||||
|
|
||||||
/**阅读状态(0未读,1已读)*/
|
/**阅读状态(0未读,1已读)*/
|
||||||
public static final String HAS_READ_FLAG = "1";
|
String HAS_READ_FLAG = "1";
|
||||||
public static final String NO_READ_FLAG = "0";
|
String NO_READ_FLAG = "0";
|
||||||
|
|
||||||
/**优先级(L低,M中,H高)*/
|
/**优先级(L低,M中,H高)*/
|
||||||
public static final String PRIORITY_L = "L";
|
String PRIORITY_L = "L";
|
||||||
public static final String PRIORITY_M = "M";
|
String PRIORITY_M = "M";
|
||||||
public static final String PRIORITY_H = "H";
|
String PRIORITY_H = "H";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 短信模板方式 0 .登录模板、1.注册模板、2.忘记密码模板
|
* 短信模板方式 0 .登录模板、1.注册模板、2.忘记密码模板
|
||||||
*/
|
*/
|
||||||
public static final String SMS_TPL_TYPE_0 = "0";
|
String SMS_TPL_TYPE_0 = "0";
|
||||||
public static final String SMS_TPL_TYPE_1 = "1";
|
String SMS_TPL_TYPE_1 = "1";
|
||||||
public static final String SMS_TPL_TYPE_2 = "2";
|
String SMS_TPL_TYPE_2 = "2";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 状态(0无效1有效)
|
* 状态(0无效1有效)
|
||||||
*/
|
*/
|
||||||
public static final String STATUS_0 = "0";
|
String STATUS_0 = "0";
|
||||||
public static final String STATUS_1 = "1";
|
String STATUS_1 = "1";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 同步工作流引擎1同步0不同步
|
* 同步工作流引擎1同步0不同步
|
||||||
*/
|
*/
|
||||||
public static final Integer ACT_SYNC_1 = 1;
|
Integer ACT_SYNC_1 = 1;
|
||||||
public static final Integer ACT_SYNC_0 = 0;
|
Integer ACT_SYNC_0 = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 消息类型1:通知公告2:系统消息
|
* 消息类型1:通知公告2:系统消息
|
||||||
*/
|
*/
|
||||||
public static final String MSG_CATEGORY_1 = "1";
|
String MSG_CATEGORY_1 = "1";
|
||||||
public static final String MSG_CATEGORY_2 = "2";
|
String MSG_CATEGORY_2 = "2";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 是否配置菜单的数据权限 1是0否
|
* 是否配置菜单的数据权限 1是0否
|
||||||
*/
|
*/
|
||||||
public static final Integer RULE_FLAG_0 = 0;
|
Integer RULE_FLAG_0 = 0;
|
||||||
public static final Integer RULE_FLAG_1 = 1;
|
Integer RULE_FLAG_1 = 1;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 是否用户已被冻结 1正常(解冻) 2冻结
|
* 是否用户已被冻结 1正常(解冻) 2冻结
|
||||||
*/
|
*/
|
||||||
public static final Integer USER_UNFREEZE = 1;
|
Integer USER_UNFREEZE = 1;
|
||||||
public static final Integer USER_FREEZE = 2;
|
Integer USER_FREEZE = 2;
|
||||||
|
|
||||||
/**字典翻译文本后缀*/
|
/**字典翻译文本后缀*/
|
||||||
public static final String DICT_TEXT_SUFFIX = "_dictText";
|
String DICT_TEXT_SUFFIX = "_dictText";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 表单设计器主表类型
|
* 表单设计器主表类型
|
||||||
*/
|
*/
|
||||||
public static final Integer DESIGN_FORM_TYPE_MAIN = 1;
|
Integer DESIGN_FORM_TYPE_MAIN = 1;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 表单设计器子表表类型
|
* 表单设计器子表表类型
|
||||||
*/
|
*/
|
||||||
public static final Integer DESIGN_FORM_TYPE_SUB = 2;
|
Integer DESIGN_FORM_TYPE_SUB = 2;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 表单设计器URL授权通过
|
* 表单设计器URL授权通过
|
||||||
*/
|
*/
|
||||||
public static final Integer DESIGN_FORM_URL_STATUS_PASSED = 1;
|
Integer DESIGN_FORM_URL_STATUS_PASSED = 1;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 表单设计器URL授权未通过
|
* 表单设计器URL授权未通过
|
||||||
*/
|
*/
|
||||||
public static final Integer DESIGN_FORM_URL_STATUS_NOT_PASSED = 2;
|
Integer DESIGN_FORM_URL_STATUS_NOT_PASSED = 2;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 表单设计器新增 Flag
|
* 表单设计器新增 Flag
|
||||||
*/
|
*/
|
||||||
public static final String DESIGN_FORM_URL_TYPE_ADD = "add";
|
String DESIGN_FORM_URL_TYPE_ADD = "add";
|
||||||
/**
|
/**
|
||||||
* 表单设计器修改 Flag
|
* 表单设计器修改 Flag
|
||||||
*/
|
*/
|
||||||
public static final String DESIGN_FORM_URL_TYPE_EDIT = "edit";
|
String DESIGN_FORM_URL_TYPE_EDIT = "edit";
|
||||||
/**
|
/**
|
||||||
* 表单设计器详情 Flag
|
* 表单设计器详情 Flag
|
||||||
*/
|
*/
|
||||||
public static final String DESIGN_FORM_URL_TYPE_DETAIL = "detail";
|
String DESIGN_FORM_URL_TYPE_DETAIL = "detail";
|
||||||
/**
|
/**
|
||||||
* 表单设计器复用数据 Flag
|
* 表单设计器复用数据 Flag
|
||||||
*/
|
*/
|
||||||
public static final String DESIGN_FORM_URL_TYPE_REUSE = "reuse";
|
String DESIGN_FORM_URL_TYPE_REUSE = "reuse";
|
||||||
/**
|
/**
|
||||||
* 表单设计器编辑 Flag (已弃用)
|
* 表单设计器编辑 Flag (已弃用)
|
||||||
*/
|
*/
|
||||||
public static final String DESIGN_FORM_URL_TYPE_VIEW = "view";
|
String DESIGN_FORM_URL_TYPE_VIEW = "view";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* online参数值设置(是:Y, 否:N)
|
* online参数值设置(是:Y, 否:N)
|
||||||
*/
|
*/
|
||||||
public static final String ONLINE_PARAM_VAL_IS_TURE = "Y";
|
String ONLINE_PARAM_VAL_IS_TURE = "Y";
|
||||||
public static final String ONLINE_PARAM_VAL_IS_FALSE = "N";
|
String ONLINE_PARAM_VAL_IS_FALSE = "N";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 文件上传类型(本地:local,Minio:minio,阿里云:alioss)
|
* 文件上传类型(本地:local,Minio:minio,阿里云:alioss)
|
||||||
*/
|
*/
|
||||||
public static final String UPLOAD_TYPE_LOCAL = "local";
|
String UPLOAD_TYPE_LOCAL = "local";
|
||||||
public static final String UPLOAD_TYPE_MINIO = "minio";
|
String UPLOAD_TYPE_MINIO = "minio";
|
||||||
public static final String UPLOAD_TYPE_OSS = "alioss";
|
String UPLOAD_TYPE_OSS = "alioss";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 文档上传自定义桶名称
|
* 文档上传自定义桶名称
|
||||||
*/
|
*/
|
||||||
public static final String UPLOAD_CUSTOM_BUCKET = "eoafile";
|
String UPLOAD_CUSTOM_BUCKET = "eoafile";
|
||||||
/**
|
/**
|
||||||
* 文档上传自定义路径
|
* 文档上传自定义路径
|
||||||
*/
|
*/
|
||||||
public static final String UPLOAD_CUSTOM_PATH = "eoafile";
|
String UPLOAD_CUSTOM_PATH = "eoafile";
|
||||||
/**
|
/**
|
||||||
* 文件外链接有效天数
|
* 文件外链接有效天数
|
||||||
*/
|
*/
|
||||||
public static final Integer UPLOAD_EFFECTIVE_DAYS = 1;
|
Integer UPLOAD_EFFECTIVE_DAYS = 1;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 员工身份 (1:普通员工 2:上级)
|
* 员工身份 (1:普通员工 2:上级)
|
||||||
*/
|
*/
|
||||||
public static final Integer USER_IDENTITY_1 = 1;
|
Integer USER_IDENTITY_1 = 1;
|
||||||
public static final Integer USER_IDENTITY_2 = 2;
|
Integer USER_IDENTITY_2 = 2;
|
||||||
|
|
||||||
/** sys_user 表 username 唯一键索引 */
|
/** sys_user 表 username 唯一键索引 */
|
||||||
public static final String SQL_INDEX_UNIQ_SYS_USER_USERNAME = "uniq_sys_user_username";
|
String SQL_INDEX_UNIQ_SYS_USER_USERNAME = "uniq_sys_user_username";
|
||||||
/** sys_user 表 work_no 唯一键索引 */
|
/** sys_user 表 work_no 唯一键索引 */
|
||||||
public static final String SQL_INDEX_UNIQ_SYS_USER_WORK_NO = "uniq_sys_user_work_no";
|
String SQL_INDEX_UNIQ_SYS_USER_WORK_NO = "uniq_sys_user_work_no";
|
||||||
/** sys_user 表 phone 唯一键索引 */
|
/** sys_user 表 phone 唯一键索引 */
|
||||||
public static final String SQL_INDEX_UNIQ_SYS_USER_PHONE = "uniq_sys_user_phone";
|
String SQL_INDEX_UNIQ_SYS_USER_PHONE = "uniq_sys_user_phone";
|
||||||
/** 达梦数据库升提示。违反表[SYS_USER]唯一性约束 */
|
/** 达梦数据库升提示。违反表[SYS_USER]唯一性约束 */
|
||||||
public static final String SQL_INDEX_UNIQ_SYS_USER = "唯一性约束";
|
String SQL_INDEX_UNIQ_SYS_USER = "唯一性约束";
|
||||||
|
|
||||||
/** sys_user 表 email 唯一键索引 */
|
/** sys_user 表 email 唯一键索引 */
|
||||||
public static final String SQL_INDEX_UNIQ_SYS_USER_EMAIL = "uniq_sys_user_email";
|
String SQL_INDEX_UNIQ_SYS_USER_EMAIL = "uniq_sys_user_email";
|
||||||
/** sys_quartz_job 表 job_class_name 唯一键索引 */
|
/** sys_quartz_job 表 job_class_name 唯一键索引 */
|
||||||
public static final String SQL_INDEX_UNIQ_JOB_CLASS_NAME = "uniq_job_class_name";
|
String SQL_INDEX_UNIQ_JOB_CLASS_NAME = "uniq_job_class_name";
|
||||||
/** sys_position 表 code 唯一键索引 */
|
/** sys_position 表 code 唯一键索引 */
|
||||||
public static final String SQL_INDEX_UNIQ_CODE = "uniq_code";
|
String SQL_INDEX_UNIQ_CODE = "uniq_code";
|
||||||
/** sys_role 表 code 唯一键索引 */
|
/** sys_role 表 code 唯一键索引 */
|
||||||
public static final String SQL_INDEX_UNIQ_SYS_ROLE_CODE = "uniq_sys_role_role_code";
|
String SQL_INDEX_UNIQ_SYS_ROLE_CODE = "uniq_sys_role_role_code";
|
||||||
/** sys_depart 表 code 唯一键索引 */
|
/** sys_depart 表 code 唯一键索引 */
|
||||||
public static final String SQL_INDEX_UNIQ_DEPART_ORG_CODE = "uniq_depart_org_code";
|
String SQL_INDEX_UNIQ_DEPART_ORG_CODE = "uniq_depart_org_code";
|
||||||
/** sys_category 表 code 唯一键索引 */
|
/** sys_category 表 code 唯一键索引 */
|
||||||
public static final String SQL_INDEX_UNIQ_CATEGORY_CODE = "idx_sc_code";
|
String SQL_INDEX_UNIQ_CATEGORY_CODE = "idx_sc_code";
|
||||||
/**
|
/**
|
||||||
* 在线聊天 是否为默认分组
|
* 在线聊天 是否为默认分组
|
||||||
*/
|
*/
|
||||||
public static final String IM_DEFAULT_GROUP = "1";
|
String IM_DEFAULT_GROUP = "1";
|
||||||
/**
|
/**
|
||||||
* 在线聊天 图片文件保存路径
|
* 在线聊天 图片文件保存路径
|
||||||
*/
|
*/
|
||||||
public static final String IM_UPLOAD_CUSTOM_PATH = "imfile";
|
String IM_UPLOAD_CUSTOM_PATH = "imfile";
|
||||||
/**
|
/**
|
||||||
* 在线聊天 用户状态
|
* 在线聊天 用户状态
|
||||||
*/
|
*/
|
||||||
public static final String IM_STATUS_ONLINE = "online";
|
String IM_STATUS_ONLINE = "online";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 在线聊天 SOCKET消息类型
|
* 在线聊天 SOCKET消息类型
|
||||||
*/
|
*/
|
||||||
public static final String IM_SOCKET_TYPE = "chatMessage";
|
String IM_SOCKET_TYPE = "chatMessage";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 在线聊天 是否开启默认添加好友 1是 0否
|
* 在线聊天 是否开启默认添加好友 1是 0否
|
||||||
*/
|
*/
|
||||||
public static final String IM_DEFAULT_ADD_FRIEND = "1";
|
String IM_DEFAULT_ADD_FRIEND = "1";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 在线聊天 用户好友缓存前缀
|
* 在线聊天 用户好友缓存前缀
|
||||||
*/
|
*/
|
||||||
public static final String IM_PREFIX_USER_FRIEND_CACHE = "sys:cache:im:im_prefix_user_friend_";
|
String IM_PREFIX_USER_FRIEND_CACHE = "sys:cache:im:im_prefix_user_friend_";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 考勤补卡业务状态 (1:同意 2:不同意)
|
* 考勤补卡业务状态 (1:同意 2:不同意)
|
||||||
*/
|
*/
|
||||||
public static final String SIGN_PATCH_BIZ_STATUS_1 = "1";
|
String SIGN_PATCH_BIZ_STATUS_1 = "1";
|
||||||
public static final String SIGN_PATCH_BIZ_STATUS_2 = "2";
|
String SIGN_PATCH_BIZ_STATUS_2 = "2";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 公文文档上传自定义路径
|
* 公文文档上传自定义路径
|
||||||
*/
|
*/
|
||||||
public static final String UPLOAD_CUSTOM_PATH_OFFICIAL = "officialdoc";
|
String UPLOAD_CUSTOM_PATH_OFFICIAL = "officialdoc";
|
||||||
/**
|
/**
|
||||||
* 公文文档下载自定义路径
|
* 公文文档下载自定义路径
|
||||||
*/
|
*/
|
||||||
public static final String DOWNLOAD_CUSTOM_PATH_OFFICIAL = "officaldown";
|
String DOWNLOAD_CUSTOM_PATH_OFFICIAL = "officaldown";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* WPS存储值类别(1 code文号 2 text(WPS模板还是公文发文模板))
|
* WPS存储值类别(1 code文号 2 text(WPS模板还是公文发文模板))
|
||||||
*/
|
*/
|
||||||
public static final String WPS_TYPE_1="1";
|
String WPS_TYPE_1="1";
|
||||||
public static final String WPS_TYPE_2="2";
|
String WPS_TYPE_2="2";
|
||||||
|
|
||||||
|
|
||||||
public final static String X_ACCESS_TOKEN = "X-Access-Token";
|
String X_ACCESS_TOKEN = "X-Access-Token";
|
||||||
public final static String X_SIGN = "X-Sign";
|
String X_SIGN = "X-Sign";
|
||||||
public final static String X_TIMESTAMP = "X-TIMESTAMP";
|
String X_TIMESTAMP = "X-TIMESTAMP";
|
||||||
public final static String TOKEN_IS_INVALID_MSG = "Token失效,请重新登录!";
|
String TOKEN_IS_INVALID_MSG = "Token失效,请重新登录!";
|
||||||
|
String X_FORWARDED_SCHEME = "X-Forwarded-Scheme";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 多租户 请求头
|
* 多租户 请求头
|
||||||
*/
|
*/
|
||||||
public final static String TENANT_ID = "tenant-id";
|
String TENANT_ID = "tenant-id";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 微服务读取配置文件属性 服务地址
|
* 微服务读取配置文件属性 服务地址
|
||||||
*/
|
*/
|
||||||
public final static String CLOUD_SERVER_KEY = "spring.cloud.nacos.discovery.server-addr";
|
String CLOUD_SERVER_KEY = "spring.cloud.nacos.discovery.server-addr";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 第三方登录 验证密码/创建用户 都需要设置一个操作码 防止被恶意调用
|
* 第三方登录 验证密码/创建用户 都需要设置一个操作码 防止被恶意调用
|
||||||
*/
|
*/
|
||||||
public final static String THIRD_LOGIN_CODE = "third_login_code";
|
String THIRD_LOGIN_CODE = "third_login_code";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 第三方APP同步方向:本地 --> 第三方APP
|
* 第三方APP同步方向:本地 --> 第三方APP
|
||||||
|
@ -361,16 +362,43 @@ public interface CommonConstant {
|
||||||
/**String 类型的空值*/
|
/**String 类型的空值*/
|
||||||
String STRING_NULL = "null";
|
String STRING_NULL = "null";
|
||||||
|
|
||||||
/**java.util.Date 包*/
|
/**前端vue3版本Header参数名*/
|
||||||
String JAVA_UTIL_DATE = "java.util.Date";
|
|
||||||
|
|
||||||
/**.do*/
|
|
||||||
String SPOT_DO = ".do";
|
|
||||||
|
|
||||||
|
|
||||||
/**前端vue版本标识*/
|
|
||||||
String VERSION="X-Version";
|
String VERSION="X-Version";
|
||||||
|
|
||||||
/**前端vue版本*/
|
/**存储在线程变量里的动态表名*/
|
||||||
String VERSION_VUE3="vue3";
|
String DYNAMIC_TABLE_NAME="DYNAMIC_TABLE_NAME";
|
||||||
|
/**
|
||||||
|
* http:// http协议
|
||||||
|
*/
|
||||||
|
String HTTP_PROTOCOL = "http://";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* https:// https协议
|
||||||
|
*/
|
||||||
|
String HTTPS_PROTOCOL = "https://";
|
||||||
|
|
||||||
|
/** 部门表唯一key,id */
|
||||||
|
String DEPART_KEY_ID = "id";
|
||||||
|
/** 部门表唯一key,orgCode */
|
||||||
|
String DEPART_KEY_ORG_CODE = "orgCode";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发消息 会传递一些信息到map
|
||||||
|
*/
|
||||||
|
String NOTICE_MSG_SUMMARY = "NOTICE_MSG_SUMMARY";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发消息 会传递一个业务ID到map
|
||||||
|
*/
|
||||||
|
String NOTICE_MSG_BUS_ID = "NOTICE_MSG_BUS_ID";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 邮箱消息中地址登录时地址后携带的token,需要替换成真实的token值
|
||||||
|
*/
|
||||||
|
String LOGIN_TOKEN = "{LOGIN_TOKEN}";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 模板消息中 跳转地址的对应的key
|
||||||
|
*/
|
||||||
|
String MSG_HREF_URL = "url";
|
||||||
}
|
}
|
||||||
|
|
|
@ -153,4 +153,14 @@ public interface DataBaseConstant {
|
||||||
* sql语句 where
|
* sql语句 where
|
||||||
*/
|
*/
|
||||||
String SQL_WHERE = "where";
|
String SQL_WHERE = "where";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* sql语句 asc
|
||||||
|
*/
|
||||||
|
String SQL_ASC = "asc";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* sqlserver数据库,中间有空格
|
||||||
|
*/
|
||||||
|
String DB_TYPE_SQL_SERVER_BLANK = "sql server";
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
package org.jeecg.common.constant;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 动态切换表配置常量
|
||||||
|
*
|
||||||
|
* @author: scott
|
||||||
|
* @date: 2022年04月25日 22:30
|
||||||
|
*/
|
||||||
|
public class DynamicTableConstant {
|
||||||
|
/**
|
||||||
|
* 角色首页配置表
|
||||||
|
* vue2表名: sys_role_index
|
||||||
|
* vue3表名: sys_role_index_vue3
|
||||||
|
*/
|
||||||
|
public static final String SYS_ROLE_INDEX = "sys_role_index";
|
||||||
|
}
|
|
@ -35,9 +35,13 @@ public class ProvinceCityArea {
|
||||||
this.initAreaList();
|
this.initAreaList();
|
||||||
if(areaList!=null && areaList.size()>0){
|
if(areaList!=null && areaList.size()>0){
|
||||||
for(int i=areaList.size()-1;i>=0;i--){
|
for(int i=areaList.size()-1;i>=0;i--){
|
||||||
if(text.indexOf(areaList.get(i).getText())>=0){
|
//update-begin-author:taoyan date:2022-5-24 for:VUEN-1088 online 导入 省市区导入后 导入数据错乱 北京市/市辖区/西城区-->山西省/晋城市/城区
|
||||||
|
String areaText = areaList.get(i).getText();
|
||||||
|
String cityText = areaList.get(i).getAheadText();
|
||||||
|
if(text.indexOf(areaText)>=0 && (cityText!=null && text.indexOf(cityText)>=0)){
|
||||||
return areaList.get(i).getId();
|
return areaList.get(i).getId();
|
||||||
}
|
}
|
||||||
|
//update-end-author:taoyan date:2022-5-24 for:VUEN-1088 online 导入 省市区导入后 导入数据错乱 北京市/市辖区/西城区-->山西省/晋城市/城区
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
|
@ -145,6 +149,9 @@ public class ProvinceCityArea {
|
||||||
for(String areaKey:areaJson.keySet()){
|
for(String areaKey:areaJson.keySet()){
|
||||||
//System.out.println("········"+areaKey);
|
//System.out.println("········"+areaKey);
|
||||||
Area area = new Area(areaKey,areaJson.getString(areaKey),cityKey);
|
Area area = new Area(areaKey,areaJson.getString(areaKey),cityKey);
|
||||||
|
//update-begin-author:taoyan date:2022-5-24 for:VUEN-1088 online 导入 省市区导入后 导入数据错乱 北京市/市辖区/西城区-->山西省/晋城市/城区
|
||||||
|
area.setAheadText(cityJson.getString(cityKey));
|
||||||
|
//update-end-author:taoyan date:2022-5-24 for:VUEN-1088 online 导入 省市区导入后 导入数据错乱 北京市/市辖区/西城区-->山西省/晋城市/城区
|
||||||
this.areaList.add(area);
|
this.areaList.add(area);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -180,6 +187,8 @@ public class ProvinceCityArea {
|
||||||
String id;
|
String id;
|
||||||
String text;
|
String text;
|
||||||
String pid;
|
String pid;
|
||||||
|
// 用于存储上级文本数据,区的上级文本 是市的数据
|
||||||
|
String aheadText;
|
||||||
|
|
||||||
public Area(String id,String text,String pid){
|
public Area(String id,String text,String pid){
|
||||||
this.id = id;
|
this.id = id;
|
||||||
|
@ -198,5 +207,12 @@ public class ProvinceCityArea {
|
||||||
public String getPid() {
|
public String getPid() {
|
||||||
return pid;
|
return pid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getAheadText() {
|
||||||
|
return aheadText;
|
||||||
|
}
|
||||||
|
public void setAheadText(String aheadText) {
|
||||||
|
this.aheadText = aheadText;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -86,4 +86,34 @@ public class SymbolConstant {
|
||||||
* 符号:和 &
|
* 符号:和 &
|
||||||
*/
|
*/
|
||||||
public static final String AND = "&";
|
public static final String AND = "&";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 符号:../
|
||||||
|
*/
|
||||||
|
public static final String SPOT_SINGLE_SLASH = "../";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 符号:..\\
|
||||||
|
*/
|
||||||
|
public static final String SPOT_DOUBLE_BACKSLASH = "..\\";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 系统变量前缀 #{
|
||||||
|
*/
|
||||||
|
public static final String SYS_VAR_PREFIX = "#{";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 符号 {{
|
||||||
|
*/
|
||||||
|
public static final String DOUBLE_LEFT_CURLY_BRACKET = "{{";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 符号:[
|
||||||
|
*/
|
||||||
|
public static final String SQUARE_BRACKETS_LEFT = "[";
|
||||||
|
/**
|
||||||
|
* 符号:]
|
||||||
|
*/
|
||||||
|
public static final String SQUARE_BRACKETS_RIGHT = "]";
|
||||||
|
|
||||||
}
|
}
|
|
@ -19,14 +19,15 @@ public enum CgformEnum {
|
||||||
* 多表
|
* 多表
|
||||||
*/
|
*/
|
||||||
MANY(2, "many", "/jeecg/code-template-online", "default.onetomany", "经典风格"),
|
MANY(2, "many", "/jeecg/code-template-online", "default.onetomany", "经典风格"),
|
||||||
/**
|
|
||||||
* 多表
|
|
||||||
*/
|
|
||||||
ERP(2, "erp", "/jeecg/code-template-online", "erp.onetomany", "ERP风格"),
|
|
||||||
/**
|
/**
|
||||||
* 多表(jvxe风格)
|
* 多表(jvxe风格)
|
||||||
* */
|
* */
|
||||||
JVXE_TABLE(2, "jvxe", "/jeecg/code-template-online", "jvxe.onetomany", "JVXE风格"),
|
JVXE_TABLE(2, "jvxe", "/jeecg/code-template-online", "jvxe.onetomany", "JVXE风格"),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 多表
|
||||||
|
*/
|
||||||
|
ERP(2, "erp", "/jeecg/code-template-online", "erp.onetomany", "ERP风格"),
|
||||||
/**
|
/**
|
||||||
* 多表(内嵌子表风格)
|
* 多表(内嵌子表风格)
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -15,6 +15,8 @@ public enum LowAppAopEnum {
|
||||||
* 删除方法(包含单个和批量删除)
|
* 删除方法(包含单个和批量删除)
|
||||||
*/
|
*/
|
||||||
DELETE,
|
DELETE,
|
||||||
|
/** 复制表单操作 */
|
||||||
|
COPY,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Online表单专用:数据库表转Online表单
|
* Online表单专用:数据库表转Online表单
|
||||||
|
|
|
@ -0,0 +1,68 @@
|
||||||
|
package org.jeecg.common.constant.enums;
|
||||||
|
|
||||||
|
import org.jeecg.common.system.annotation.EnumDict;
|
||||||
|
import org.jeecg.common.system.vo.DictModel;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 消息类型
|
||||||
|
* @author: jeecg-boot
|
||||||
|
*/
|
||||||
|
@EnumDict("messageType")
|
||||||
|
public enum MessageTypeEnum {
|
||||||
|
|
||||||
|
XT("system", "系统消息"),
|
||||||
|
YJ("email", "邮件消息"),
|
||||||
|
DD("dingtalk", "钉钉消息"),
|
||||||
|
QYWX("wechat_enterprise", "企业微信");
|
||||||
|
|
||||||
|
MessageTypeEnum(String type, String note){
|
||||||
|
this.type = type;
|
||||||
|
this.note = note;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 消息类型
|
||||||
|
*/
|
||||||
|
String type;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 类型说明
|
||||||
|
*/
|
||||||
|
String note;
|
||||||
|
|
||||||
|
public String getNote() {
|
||||||
|
return note;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNote(String note) {
|
||||||
|
this.note = note;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getType() {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setType(String type) {
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取字典数据
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static List<DictModel> getDictList(){
|
||||||
|
List<DictModel> list = new ArrayList<>();
|
||||||
|
DictModel dictModel = null;
|
||||||
|
for(MessageTypeEnum e: MessageTypeEnum.values()){
|
||||||
|
dictModel = new DictModel();
|
||||||
|
dictModel.setValue(e.getType());
|
||||||
|
dictModel.setText(e.getNote());
|
||||||
|
list.add(dictModel);
|
||||||
|
}
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
package org.jeecg.common.desensitization.annotation;
|
||||||
|
|
||||||
|
import java.lang.annotation.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 解密注解
|
||||||
|
*
|
||||||
|
* 在方法上定义 将方法返回对象中的敏感字段 解密,需要注意的是,如果没有加密过,解密会出问题,返回原字符串
|
||||||
|
*/
|
||||||
|
@Documented
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
@Target({ElementType.METHOD})
|
||||||
|
public @interface SensitiveDecode {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 指明需要脱敏的实体类class
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
Class entity() default Object.class;
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
package org.jeecg.common.desensitization.annotation;
|
||||||
|
|
||||||
|
import java.lang.annotation.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 加密注解
|
||||||
|
*
|
||||||
|
* 在方法上声明 将方法返回对象中的敏感字段 加密/格式化
|
||||||
|
*/
|
||||||
|
@Documented
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
@Target({ElementType.METHOD})
|
||||||
|
public @interface SensitiveEncode {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 指明需要脱敏的实体类class
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
Class entity() default Object.class;
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
package org.jeecg.common.desensitization.annotation;
|
||||||
|
|
||||||
|
|
||||||
|
import org.jeecg.common.desensitization.enums.SensitiveEnum;
|
||||||
|
|
||||||
|
import java.lang.annotation.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 在字段上定义 标识字段存储的信息是敏感的
|
||||||
|
*/
|
||||||
|
@Documented
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
@Target(ElementType.FIELD)
|
||||||
|
public @interface SensitiveField {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 不同类型处理不同
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
SensitiveEnum type() default SensitiveEnum.ENCODE;
|
||||||
|
}
|
|
@ -0,0 +1,81 @@
|
||||||
|
package org.jeecg.common.desensitization.aspect;
|
||||||
|
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.aspectj.lang.ProceedingJoinPoint;
|
||||||
|
import org.aspectj.lang.annotation.Around;
|
||||||
|
import org.aspectj.lang.annotation.Aspect;
|
||||||
|
import org.aspectj.lang.annotation.Pointcut;
|
||||||
|
import org.aspectj.lang.reflect.MethodSignature;
|
||||||
|
import org.jeecg.common.desensitization.annotation.SensitiveDecode;
|
||||||
|
import org.jeecg.common.desensitization.annotation.SensitiveEncode;
|
||||||
|
import org.jeecg.common.desensitization.util.SensitiveInfoUtil;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 敏感数据切面处理类
|
||||||
|
* @Author taoYan
|
||||||
|
* @Date 2022/4/20 17:45
|
||||||
|
**/
|
||||||
|
@Slf4j
|
||||||
|
@Aspect
|
||||||
|
@Component
|
||||||
|
public class SensitiveDataAspect {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 定义切点Pointcut
|
||||||
|
*/
|
||||||
|
@Pointcut("@annotation(org.jeecg.common.desensitization.annotation.SensitiveEncode) || @annotation(org.jeecg.common.desensitization.annotation.SensitiveDecode)")
|
||||||
|
public void sensitivePointCut() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Around("sensitivePointCut()")
|
||||||
|
public Object around(ProceedingJoinPoint point) throws Throwable {
|
||||||
|
// 处理结果
|
||||||
|
Object result = point.proceed();
|
||||||
|
if(result == null){
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
Class resultClass = result.getClass();
|
||||||
|
log.debug(" resultClass = {}" , resultClass);
|
||||||
|
|
||||||
|
if(resultClass.isPrimitive()){
|
||||||
|
//是基本类型 直接返回 不需要处理
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
// 获取方法注解信息:是哪个实体、是加密还是解密
|
||||||
|
boolean isEncode = true;
|
||||||
|
Class entity = null;
|
||||||
|
MethodSignature methodSignature = (MethodSignature) point.getSignature();
|
||||||
|
Method method = methodSignature.getMethod();
|
||||||
|
SensitiveEncode encode = method.getAnnotation(SensitiveEncode.class);
|
||||||
|
if(encode==null){
|
||||||
|
SensitiveDecode decode = method.getAnnotation(SensitiveDecode.class);
|
||||||
|
if(decode!=null){
|
||||||
|
entity = decode.entity();
|
||||||
|
isEncode = false;
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
entity = encode.entity();
|
||||||
|
}
|
||||||
|
|
||||||
|
long startTime=System.currentTimeMillis();
|
||||||
|
if(resultClass.equals(entity) || entity.equals(Object.class)){
|
||||||
|
// 方法返回实体和注解的entity一样,如果注解没有申明entity属性则认为是(方法返回实体和注解的entity一样)
|
||||||
|
SensitiveInfoUtil.handlerObject(result, isEncode);
|
||||||
|
} else if(result instanceof List){
|
||||||
|
// 方法返回List<实体>
|
||||||
|
SensitiveInfoUtil.handleList(result, entity, isEncode);
|
||||||
|
}else{
|
||||||
|
// 方法返回一个对象
|
||||||
|
SensitiveInfoUtil.handleNestedObject(result, entity, isEncode);
|
||||||
|
}
|
||||||
|
long endTime=System.currentTimeMillis();
|
||||||
|
log.info((isEncode ? "加密操作," : "解密操作,") + "Aspect程序耗时:" + (endTime - startTime) + "ms");
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,55 @@
|
||||||
|
package org.jeecg.common.desensitization.enums;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 敏感字段信息类型
|
||||||
|
*/
|
||||||
|
public enum SensitiveEnum {
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 加密
|
||||||
|
*/
|
||||||
|
ENCODE,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 中文名
|
||||||
|
*/
|
||||||
|
CHINESE_NAME,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 身份证号
|
||||||
|
*/
|
||||||
|
ID_CARD,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 座机号
|
||||||
|
*/
|
||||||
|
FIXED_PHONE,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 手机号
|
||||||
|
*/
|
||||||
|
MOBILE_PHONE,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 地址
|
||||||
|
*/
|
||||||
|
ADDRESS,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 电子邮件
|
||||||
|
*/
|
||||||
|
EMAIL,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 银行卡
|
||||||
|
*/
|
||||||
|
BANK_CARD,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 公司开户银行联号
|
||||||
|
*/
|
||||||
|
CNAPS_CODE;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,362 @@
|
||||||
|
package org.jeecg.common.desensitization.util;
|
||||||
|
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.jeecg.common.desensitization.annotation.SensitiveField;
|
||||||
|
import org.jeecg.common.desensitization.enums.SensitiveEnum;
|
||||||
|
import org.jeecg.common.util.encryption.AesEncryptUtil;
|
||||||
|
import org.jeecg.common.util.oConvertUtils;
|
||||||
|
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
import java.lang.reflect.ParameterizedType;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 敏感信息处理工具类
|
||||||
|
* @author taoYan
|
||||||
|
* @date 2022/4/20 18:01
|
||||||
|
**/
|
||||||
|
@Slf4j
|
||||||
|
public class SensitiveInfoUtil {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理嵌套对象
|
||||||
|
* @param obj 方法返回值
|
||||||
|
* @param entity 实体class
|
||||||
|
* @param isEncode 是否加密(true: 加密操作 / false:解密操作)
|
||||||
|
* @throws IllegalAccessException
|
||||||
|
*/
|
||||||
|
public static void handleNestedObject(Object obj, Class entity, boolean isEncode) throws IllegalAccessException {
|
||||||
|
Field[] fields = obj.getClass().getDeclaredFields();
|
||||||
|
for (Field field : fields) {
|
||||||
|
if(field.getType().isPrimitive()){
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if(field.getType().equals(entity)){
|
||||||
|
// 对象里面是实体
|
||||||
|
field.setAccessible(true);
|
||||||
|
Object nestedObject = field.get(obj);
|
||||||
|
handlerObject(nestedObject, isEncode);
|
||||||
|
break;
|
||||||
|
}else{
|
||||||
|
// 对象里面是List<实体>
|
||||||
|
if(field.getGenericType() instanceof ParameterizedType){
|
||||||
|
ParameterizedType pt = (ParameterizedType)field.getGenericType();
|
||||||
|
if(pt.getRawType().equals(List.class)){
|
||||||
|
if(pt.getActualTypeArguments()[0].equals(entity)){
|
||||||
|
field.setAccessible(true);
|
||||||
|
Object nestedObject = field.get(obj);
|
||||||
|
handleList(nestedObject, entity, isEncode);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理Object
|
||||||
|
* @param obj 方法返回值
|
||||||
|
* @param isEncode 是否加密(true: 加密操作 / false:解密操作)
|
||||||
|
* @return
|
||||||
|
* @throws IllegalAccessException
|
||||||
|
*/
|
||||||
|
public static Object handlerObject(Object obj, boolean isEncode) throws IllegalAccessException {
|
||||||
|
log.debug(" obj --> "+ obj.toString());
|
||||||
|
long startTime=System.currentTimeMillis();
|
||||||
|
if (oConvertUtils.isEmpty(obj)) {
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
// 判断是不是一个对象
|
||||||
|
Field[] fields = obj.getClass().getDeclaredFields();
|
||||||
|
for (Field field : fields) {
|
||||||
|
boolean isSensitiveField = field.isAnnotationPresent(SensitiveField.class);
|
||||||
|
if(isSensitiveField){
|
||||||
|
// 必须有SensitiveField注解 才作处理
|
||||||
|
if(field.getType().isAssignableFrom(String.class)){
|
||||||
|
//必须是字符串类型 才作处理
|
||||||
|
field.setAccessible(true);
|
||||||
|
String realValue = (String) field.get(obj);
|
||||||
|
if(realValue==null || "".equals(realValue)){
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
SensitiveField sf = field.getAnnotation(SensitiveField.class);
|
||||||
|
if(isEncode==true){
|
||||||
|
//加密
|
||||||
|
String value = SensitiveInfoUtil.getEncodeData(realValue, sf.type());
|
||||||
|
field.set(obj, value);
|
||||||
|
}else{
|
||||||
|
//解密只处理 encode类型的
|
||||||
|
if(sf.type().equals(SensitiveEnum.ENCODE)){
|
||||||
|
String value = SensitiveInfoUtil.getDecodeData(realValue);
|
||||||
|
field.set(obj, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//long endTime=System.currentTimeMillis();
|
||||||
|
//log.info((isEncode ? "加密操作," : "解密操作,") + "当前程序耗时:" + (endTime - startTime) + "ms");
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理 List<实体>
|
||||||
|
* @param obj
|
||||||
|
* @param entity
|
||||||
|
* @param isEncode(true: 加密操作 / false:解密操作)
|
||||||
|
*/
|
||||||
|
public static void handleList(Object obj, Class entity, boolean isEncode){
|
||||||
|
List list = (List)obj;
|
||||||
|
if(list.size()>0){
|
||||||
|
Object first = list.get(0);
|
||||||
|
if(first.getClass().equals(entity)){
|
||||||
|
for(int i=0; i<list.size(); i++){
|
||||||
|
Object temp = list.get(i);
|
||||||
|
try {
|
||||||
|
handlerObject(temp, isEncode);
|
||||||
|
} catch (IllegalAccessException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理数据 获取解密后的数据
|
||||||
|
* @param data
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static String getDecodeData(String data){
|
||||||
|
String result = null;
|
||||||
|
try {
|
||||||
|
result = AesEncryptUtil.desEncrypt(data);
|
||||||
|
} catch (Exception exception) {
|
||||||
|
log.warn("数据解密错误,原数据:"+data);
|
||||||
|
}
|
||||||
|
//解决debug模式下,加解密失效导致中文被解密变成空的问题
|
||||||
|
if(oConvertUtils.isEmpty(result) && oConvertUtils.isNotEmpty(data)){
|
||||||
|
result = data;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理数据 获取加密后的数据 或是格式化后的数据
|
||||||
|
* @param data 字符串
|
||||||
|
* @param sensitiveEnum 类型
|
||||||
|
* @return 处理后的字符串
|
||||||
|
*/
|
||||||
|
public static String getEncodeData(String data, SensitiveEnum sensitiveEnum){
|
||||||
|
String result;
|
||||||
|
switch (sensitiveEnum){
|
||||||
|
case ENCODE:
|
||||||
|
try {
|
||||||
|
result = AesEncryptUtil.encrypt(data);
|
||||||
|
} catch (Exception exception) {
|
||||||
|
log.error("数据加密错误", exception.getMessage());
|
||||||
|
result = data;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case CHINESE_NAME:
|
||||||
|
result = chineseName(data);
|
||||||
|
break;
|
||||||
|
case ID_CARD:
|
||||||
|
result = idCardNum(data);
|
||||||
|
break;
|
||||||
|
case FIXED_PHONE:
|
||||||
|
result = fixedPhone(data);
|
||||||
|
break;
|
||||||
|
case MOBILE_PHONE:
|
||||||
|
result = mobilePhone(data);
|
||||||
|
break;
|
||||||
|
case ADDRESS:
|
||||||
|
result = address(data, 3);
|
||||||
|
break;
|
||||||
|
case EMAIL:
|
||||||
|
result = email(data);
|
||||||
|
break;
|
||||||
|
case BANK_CARD:
|
||||||
|
result = bankCard(data);
|
||||||
|
break;
|
||||||
|
case CNAPS_CODE:
|
||||||
|
result = cnapsCode(data);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
result = data;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* [中文姓名] 只显示第一个汉字,其他隐藏为2个星号
|
||||||
|
* @param fullName 全名
|
||||||
|
* @return <例子:李**>
|
||||||
|
*/
|
||||||
|
private static String chineseName(String fullName) {
|
||||||
|
if (oConvertUtils.isEmpty(fullName)) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
return formatRight(fullName, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* [中文姓名] 只显示第一个汉字,其他隐藏为2个星号
|
||||||
|
* @param familyName 姓
|
||||||
|
* @param firstName 名
|
||||||
|
* @return <例子:李**>
|
||||||
|
*/
|
||||||
|
private static String chineseName(String familyName, String firstName) {
|
||||||
|
if (oConvertUtils.isEmpty(familyName) || oConvertUtils.isEmpty(firstName)) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
return chineseName(familyName + firstName);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* [身份证号] 显示最后四位,其他隐藏。共计18位或者15位。
|
||||||
|
* @param id 身份证号
|
||||||
|
* @return <例子:*************5762>
|
||||||
|
*/
|
||||||
|
private static String idCardNum(String id) {
|
||||||
|
if (oConvertUtils.isEmpty(id)) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
return formatLeft(id, 4);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* [固定电话] 后四位,其他隐藏
|
||||||
|
* @param num 固定电话
|
||||||
|
* @return <例子:****1234>
|
||||||
|
*/
|
||||||
|
private static String fixedPhone(String num) {
|
||||||
|
if (oConvertUtils.isEmpty(num)) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
return formatLeft(num, 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* [手机号码] 前三位,后四位,其他隐藏
|
||||||
|
* @param num 手机号码
|
||||||
|
* @return <例子:138******1234>
|
||||||
|
*/
|
||||||
|
private static String mobilePhone(String num) {
|
||||||
|
if (oConvertUtils.isEmpty(num)) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
int len = num.length();
|
||||||
|
if(len<11){
|
||||||
|
return num;
|
||||||
|
}
|
||||||
|
return formatBetween(num, 3, 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* [地址] 只显示到地区,不显示详细地址;我们要对个人信息增强保护
|
||||||
|
* @param address 地址
|
||||||
|
* @param sensitiveSize 敏感信息长度
|
||||||
|
* @return <例子:北京市海淀区****>
|
||||||
|
*/
|
||||||
|
private static String address(String address, int sensitiveSize) {
|
||||||
|
if (oConvertUtils.isEmpty(address)) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
int len = address.length();
|
||||||
|
if(len<sensitiveSize){
|
||||||
|
return address;
|
||||||
|
}
|
||||||
|
return formatRight(address, sensitiveSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* [电子邮箱] 邮箱前缀仅显示第一个字母,前缀其他隐藏,用星号代替,@及后面的地址显示
|
||||||
|
* @param email 电子邮箱
|
||||||
|
* @return <例子:g**@163.com>
|
||||||
|
*/
|
||||||
|
private static String email(String email) {
|
||||||
|
if (oConvertUtils.isEmpty(email)) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
int index = email.indexOf("@");
|
||||||
|
if (index <= 1){
|
||||||
|
return email;
|
||||||
|
}
|
||||||
|
String begin = email.substring(0, 1);
|
||||||
|
String end = email.substring(index);
|
||||||
|
String stars = "**";
|
||||||
|
return begin + stars + end;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* [银行卡号] 前六位,后四位,其他用星号隐藏每位1个星号
|
||||||
|
* @param cardNum 银行卡号
|
||||||
|
* @return <例子:6222600**********1234>
|
||||||
|
*/
|
||||||
|
private static String bankCard(String cardNum) {
|
||||||
|
if (oConvertUtils.isEmpty(cardNum)) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
return formatBetween(cardNum, 6, 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* [公司开户银行联号] 公司开户银行联行号,显示前两位,其他用星号隐藏,每位1个星号
|
||||||
|
* @param code 公司开户银行联号
|
||||||
|
* @return <例子:12********>
|
||||||
|
*/
|
||||||
|
private static String cnapsCode(String code) {
|
||||||
|
if (oConvertUtils.isEmpty(code)) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
return formatRight(code, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将右边的格式化成*
|
||||||
|
* @param str 字符串
|
||||||
|
* @param reservedLength 保留长度
|
||||||
|
* @return 格式化后的字符串
|
||||||
|
*/
|
||||||
|
private static String formatRight(String str, int reservedLength){
|
||||||
|
String name = str.substring(0, reservedLength);
|
||||||
|
String stars = String.join("", Collections.nCopies(str.length()-reservedLength, "*"));
|
||||||
|
return name + stars;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将左边的格式化成*
|
||||||
|
* @param str 字符串
|
||||||
|
* @param reservedLength 保留长度
|
||||||
|
* @return 格式化后的字符串
|
||||||
|
*/
|
||||||
|
private static String formatLeft(String str, int reservedLength){
|
||||||
|
int len = str.length();
|
||||||
|
String show = str.substring(len-reservedLength);
|
||||||
|
String stars = String.join("", Collections.nCopies(len-reservedLength, "*"));
|
||||||
|
return stars + show;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将中间的格式化成*
|
||||||
|
* @param str 字符串
|
||||||
|
* @param beginLen 开始保留长度
|
||||||
|
* @param endLen 结尾保留长度
|
||||||
|
* @return 格式化后的字符串
|
||||||
|
*/
|
||||||
|
private static String formatBetween(String str, int beginLen, int endLen){
|
||||||
|
int len = str.length();
|
||||||
|
String begin = str.substring(0, beginLen);
|
||||||
|
String end = str.substring(len-endLen);
|
||||||
|
String stars = String.join("", Collections.nCopies(len-beginLen-endLen, "*"));
|
||||||
|
return begin + stars + end;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -123,7 +123,8 @@ public class JeecgBootExceptionHandler {
|
||||||
@ExceptionHandler(DataIntegrityViolationException.class)
|
@ExceptionHandler(DataIntegrityViolationException.class)
|
||||||
public Result<?> handleDataIntegrityViolationException(DataIntegrityViolationException e) {
|
public Result<?> handleDataIntegrityViolationException(DataIntegrityViolationException e) {
|
||||||
log.error(e.getMessage(), e);
|
log.error(e.getMessage(), e);
|
||||||
return Result.error("字段太长,超出数据库字段的长度");
|
//【issues/3624】数据库执行异常handleDataIntegrityViolationException提示有误 #3624
|
||||||
|
return Result.error("执行数据库异常,违反了完整性例如:违反惟一约束、违反非空限制、字段内容超出长度等");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ExceptionHandler(PoolException.class)
|
@ExceptionHandler(PoolException.class)
|
||||||
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
package org.jeecg.common.system.annotation;
|
||||||
|
|
||||||
|
import java.lang.annotation.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将枚举类转化成字典数据
|
||||||
|
* @Author taoYan
|
||||||
|
* @Date 2022/7/8 10:34
|
||||||
|
**/
|
||||||
|
@Target(ElementType.TYPE)
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
@Documented
|
||||||
|
public @interface EnumDict {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 作为字典数据的唯一编码
|
||||||
|
*/
|
||||||
|
String value() default "";
|
||||||
|
}
|
|
@ -53,18 +53,14 @@ public class JeecgController<T, S extends IService<T>> {
|
||||||
QueryWrapper<T> queryWrapper = QueryGenerator.initQueryWrapper(object, request.getParameterMap());
|
QueryWrapper<T> queryWrapper = QueryGenerator.initQueryWrapper(object, request.getParameterMap());
|
||||||
LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
|
LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
|
||||||
|
|
||||||
// Step.2 获取导出数据
|
|
||||||
List<T> pageList = service.list(queryWrapper);
|
|
||||||
List<T> exportList = null;
|
|
||||||
|
|
||||||
// 过滤选中数据
|
// 过滤选中数据
|
||||||
String selections = request.getParameter("selections");
|
String selections = request.getParameter("selections");
|
||||||
if (oConvertUtils.isNotEmpty(selections)) {
|
if (oConvertUtils.isNotEmpty(selections)) {
|
||||||
List<String> selectionList = Arrays.asList(selections.split(","));
|
List<String> selectionList = Arrays.asList(selections.split(","));
|
||||||
exportList = pageList.stream().filter(item -> selectionList.contains(getId(item))).collect(Collectors.toList());
|
queryWrapper.in("id",selectionList);
|
||||||
} else {
|
|
||||||
exportList = pageList;
|
|
||||||
}
|
}
|
||||||
|
// Step.2 获取导出数据
|
||||||
|
List<T> exportList = service.list(queryWrapper);
|
||||||
|
|
||||||
// Step.3 AutoPoi 导出Excel
|
// Step.3 AutoPoi 导出Excel
|
||||||
ModelAndView mv = new ModelAndView(new JeecgEntityExcelView());
|
ModelAndView mv = new ModelAndView(new JeecgEntityExcelView());
|
||||||
|
@ -97,21 +93,20 @@ public class JeecgController<T, S extends IService<T>> {
|
||||||
// Step.2 计算分页sheet数据
|
// Step.2 计算分页sheet数据
|
||||||
double total = service.count();
|
double total = service.count();
|
||||||
int count = (int)Math.ceil(total/pageNum);
|
int count = (int)Math.ceil(total/pageNum);
|
||||||
// Step.3 多sheet处理
|
//update-begin-author:liusq---date:20220629--for: 多sheet导出根据选择导出写法调整 ---
|
||||||
|
// Step.3 过滤选中数据
|
||||||
|
String selections = request.getParameter("selections");
|
||||||
|
if (oConvertUtils.isNotEmpty(selections)) {
|
||||||
|
List<String> selectionList = Arrays.asList(selections.split(","));
|
||||||
|
queryWrapper.in("id",selectionList);
|
||||||
|
}
|
||||||
|
//update-end-author:liusq---date:20220629--for: 多sheet导出根据选择导出写法调整 ---
|
||||||
|
// Step.4 多sheet处理
|
||||||
List<Map<String, Object>> listMap = new ArrayList<Map<String, Object>>();
|
List<Map<String, Object>> listMap = new ArrayList<Map<String, Object>>();
|
||||||
for (int i = 1; i <=count ; i++) {
|
for (int i = 1; i <=count ; i++) {
|
||||||
Page<T> page = new Page<T>(i, pageNum);
|
Page<T> page = new Page<T>(i, pageNum);
|
||||||
IPage<T> pageList = service.page(page, queryWrapper);
|
IPage<T> pageList = service.page(page, queryWrapper);
|
||||||
List<T> records = pageList.getRecords();
|
List<T> exportList = pageList.getRecords();
|
||||||
List<T> exportList = null;
|
|
||||||
// 过滤选中数据
|
|
||||||
String selections = request.getParameter("selections");
|
|
||||||
if (oConvertUtils.isNotEmpty(selections)) {
|
|
||||||
List<String> selectionList = Arrays.asList(selections.split(","));
|
|
||||||
exportList = records.stream().filter(item -> selectionList.contains(getId(item))).collect(Collectors.toList());
|
|
||||||
} else {
|
|
||||||
exportList = records;
|
|
||||||
}
|
|
||||||
Map<String, Object> map = new HashMap<>(5);
|
Map<String, Object> map = new HashMap<>(5);
|
||||||
ExportParams exportParams=new ExportParams(title + "报表", "导出人:" + sysUser.getRealname(), title+i,upLoadPath);
|
ExportParams exportParams=new ExportParams(title + "报表", "导出人:" + sysUser.getRealname(), title+i,upLoadPath);
|
||||||
exportParams.setType(ExcelType.XSSF);
|
exportParams.setType(ExcelType.XSSF);
|
||||||
|
|
|
@ -16,6 +16,7 @@ import org.apache.commons.beanutils.PropertyUtils;
|
||||||
import org.jeecg.common.constant.CommonConstant;
|
import org.jeecg.common.constant.CommonConstant;
|
||||||
import org.jeecg.common.constant.DataBaseConstant;
|
import org.jeecg.common.constant.DataBaseConstant;
|
||||||
import org.jeecg.common.constant.SymbolConstant;
|
import org.jeecg.common.constant.SymbolConstant;
|
||||||
|
import org.jeecg.common.exception.JeecgBootException;
|
||||||
import org.jeecg.common.system.util.JeecgDataAutorUtils;
|
import org.jeecg.common.system.util.JeecgDataAutorUtils;
|
||||||
import org.jeecg.common.system.util.JwtUtil;
|
import org.jeecg.common.system.util.JwtUtil;
|
||||||
import org.jeecg.common.system.vo.SysPermissionDataRuleModel;
|
import org.jeecg.common.system.vo.SysPermissionDataRuleModel;
|
||||||
|
@ -192,7 +193,7 @@ public class QueryGenerator {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 排序逻辑 处理
|
// 排序逻辑 处理
|
||||||
doMultiFieldsOrder(queryWrapper, parameterMap);
|
doMultiFieldsOrder(queryWrapper, parameterMap, fieldColumnMap.keySet());
|
||||||
|
|
||||||
//高级查询
|
//高级查询
|
||||||
doSuperQuery(queryWrapper, parameterMap, fieldColumnMap);
|
doSuperQuery(queryWrapper, parameterMap, fieldColumnMap);
|
||||||
|
@ -228,8 +229,7 @@ public class QueryGenerator {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**多字段排序 TODO 需要修改前端*/
|
private static void doMultiFieldsOrder(QueryWrapper<?> queryWrapper,Map<String, String[]> parameterMap, Set<String> allFields) {
|
||||||
private static void doMultiFieldsOrder(QueryWrapper<?> queryWrapper,Map<String, String[]> parameterMap) {
|
|
||||||
String column=null,order=null;
|
String column=null,order=null;
|
||||||
if(parameterMap!=null&& parameterMap.containsKey(ORDER_COLUMN)) {
|
if(parameterMap!=null&& parameterMap.containsKey(ORDER_COLUMN)) {
|
||||||
column = parameterMap.get(ORDER_COLUMN)[0];
|
column = parameterMap.get(ORDER_COLUMN)[0];
|
||||||
|
@ -243,6 +243,15 @@ public class QueryGenerator {
|
||||||
if(column.endsWith(CommonConstant.DICT_TEXT_SUFFIX)) {
|
if(column.endsWith(CommonConstant.DICT_TEXT_SUFFIX)) {
|
||||||
column = column.substring(0, column.lastIndexOf(CommonConstant.DICT_TEXT_SUFFIX));
|
column = column.substring(0, column.lastIndexOf(CommonConstant.DICT_TEXT_SUFFIX));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//update-begin-author:taoyan date:2022-5-16 for: issues/3676 获取系统用户列表时,使用SQL注入生效
|
||||||
|
//判断column是不是当前实体的
|
||||||
|
log.info("当前字段有:"+ allFields);
|
||||||
|
if (!allColumnExist(column, allFields)) {
|
||||||
|
throw new JeecgBootException("请注意,将要排序的列字段不存在:" + column);
|
||||||
|
}
|
||||||
|
//update-end-author:taoyan date:2022-5-16 for: issues/3676 获取系统用户列表时,使用SQL注入生效
|
||||||
|
|
||||||
//SQL注入check
|
//SQL注入check
|
||||||
SqlInjectionUtil.filterContent(column);
|
SqlInjectionUtil.filterContent(column);
|
||||||
|
|
||||||
|
@ -265,6 +274,28 @@ public class QueryGenerator {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//update-begin-author:taoyan date:2022-5-23 for: issues/3676 获取系统用户列表时,使用SQL注入生效
|
||||||
|
/**
|
||||||
|
* 多字段排序 判断所传字段是否存在
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private static boolean allColumnExist(String columnStr, Set<String> allFields){
|
||||||
|
boolean exist = true;
|
||||||
|
if(columnStr.indexOf(COMMA)>=0){
|
||||||
|
String[] arr = columnStr.split(COMMA);
|
||||||
|
for(String column: arr){
|
||||||
|
if(!allFields.contains(column)){
|
||||||
|
exist = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
exist = allFields.contains(columnStr);
|
||||||
|
}
|
||||||
|
return exist;
|
||||||
|
}
|
||||||
|
//update-end-author:taoyan date:2022-5-23 for: issues/3676 获取系统用户列表时,使用SQL注入生效
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 高级查询
|
* 高级查询
|
||||||
* @param queryWrapper 查询对象
|
* @param queryWrapper 查询对象
|
||||||
|
@ -825,13 +856,13 @@ public class QueryGenerator {
|
||||||
res = field + " in "+getInConditionValue(value, isString);
|
res = field + " in "+getInConditionValue(value, isString);
|
||||||
break;
|
break;
|
||||||
case LIKE:
|
case LIKE:
|
||||||
res = field + " like "+getLikeConditionValue(value);
|
res = field + " like "+getLikeConditionValue(value, QueryRuleEnum.LIKE);
|
||||||
break;
|
break;
|
||||||
case LEFT_LIKE:
|
case LEFT_LIKE:
|
||||||
res = field + " like "+getLikeConditionValue(value);
|
res = field + " like "+getLikeConditionValue(value, QueryRuleEnum.LEFT_LIKE);
|
||||||
break;
|
break;
|
||||||
case RIGHT_LIKE:
|
case RIGHT_LIKE:
|
||||||
res = field + " like "+getLikeConditionValue(value);
|
res = field + " like "+getLikeConditionValue(value, QueryRuleEnum.RIGHT_LIKE);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
res = field+" = "+getFieldConditionValue(value, isString, dataBaseType);
|
res = field+" = "+getFieldConditionValue(value, isString, dataBaseType);
|
||||||
|
@ -915,7 +946,14 @@ public class QueryGenerator {
|
||||||
//update-end-author:taoyan date:20210628 for: 查询条件如果输入,导致sql报错
|
//update-end-author:taoyan date:20210628 for: 查询条件如果输入,导致sql报错
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String getLikeConditionValue(Object value) {
|
/**
|
||||||
|
* 先根据值判断 走左模糊还是右模糊
|
||||||
|
* 最后如果值不带任何标识(*或者%),则再根据ruleEnum判断
|
||||||
|
* @param value
|
||||||
|
* @param ruleEnum
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private static String getLikeConditionValue(Object value, QueryRuleEnum ruleEnum) {
|
||||||
String str = value.toString().trim();
|
String str = value.toString().trim();
|
||||||
if(str.startsWith(SymbolConstant.ASTERISK) && str.endsWith(SymbolConstant.ASTERISK)) {
|
if(str.startsWith(SymbolConstant.ASTERISK) && str.endsWith(SymbolConstant.ASTERISK)) {
|
||||||
if(DataBaseConstant.DB_TYPE_SQLSERVER.equals(getDbType())){
|
if(DataBaseConstant.DB_TYPE_SQLSERVER.equals(getDbType())){
|
||||||
|
@ -951,11 +989,30 @@ public class QueryGenerator {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}else {
|
}else {
|
||||||
if(DataBaseConstant.DB_TYPE_SQLSERVER.equals(getDbType())){
|
|
||||||
return "N'%"+str+"%'";
|
//update-begin-author:taoyan date:2022-6-30 for: issues/3810 数据权限规则问题
|
||||||
}else{
|
// 走到这里说明 value不带有任何模糊查询的标识(*或者%)
|
||||||
return "'%"+str+"%'";
|
if (ruleEnum == QueryRuleEnum.LEFT_LIKE) {
|
||||||
|
if (DataBaseConstant.DB_TYPE_SQLSERVER.equals(getDbType())) {
|
||||||
|
return "N'%" + str + "'";
|
||||||
|
} else {
|
||||||
|
return "'%" + str + "'";
|
||||||
|
}
|
||||||
|
} else if (ruleEnum == QueryRuleEnum.RIGHT_LIKE) {
|
||||||
|
if (DataBaseConstant.DB_TYPE_SQLSERVER.equals(getDbType())) {
|
||||||
|
return "N'" + str + "%'";
|
||||||
|
} else {
|
||||||
|
return "'" + str + "%'";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (DataBaseConstant.DB_TYPE_SQLSERVER.equals(getDbType())) {
|
||||||
|
return "N'%" + str + "%'";
|
||||||
|
} else {
|
||||||
|
return "'%" + str + "%'";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
//update-end-author:taoyan date:2022-6-30 for: issues/3810 数据权限规则问题
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,7 +54,7 @@ public class JwtUtil {
|
||||||
try {
|
try {
|
||||||
os = httpServletResponse.getOutputStream();
|
os = httpServletResponse.getOutputStream();
|
||||||
httpServletResponse.setCharacterEncoding("UTF-8");
|
httpServletResponse.setCharacterEncoding("UTF-8");
|
||||||
httpServletResponse.setStatus(401);
|
httpServletResponse.setStatus(code);
|
||||||
os.write(new ObjectMapper().writeValueAsString(jsonResult).getBytes("UTF-8"));
|
os.write(new ObjectMapper().writeValueAsString(jsonResult).getBytes("UTF-8"));
|
||||||
os.flush();
|
os.flush();
|
||||||
os.close();
|
os.close();
|
||||||
|
|
|
@ -0,0 +1,111 @@
|
||||||
|
package org.jeecg.common.system.util;
|
||||||
|
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.jeecg.common.system.annotation.EnumDict;
|
||||||
|
import org.jeecg.common.system.vo.DictModel;
|
||||||
|
import org.jeecg.common.util.oConvertUtils;
|
||||||
|
import org.springframework.core.io.Resource;
|
||||||
|
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
|
||||||
|
import org.springframework.core.io.support.ResourcePatternResolver;
|
||||||
|
import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
|
||||||
|
import org.springframework.core.type.classreading.MetadataReader;
|
||||||
|
import org.springframework.core.type.classreading.MetadataReaderFactory;
|
||||||
|
import org.springframework.util.ClassUtils;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 资源加载工具类
|
||||||
|
* @Author taoYan
|
||||||
|
* @Date 2022/7/8 10:40
|
||||||
|
**/
|
||||||
|
@Slf4j
|
||||||
|
public class ResourceUtil {
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 枚举字典数据
|
||||||
|
*/
|
||||||
|
private final static Map<String, List<DictModel>> enumDictData = new HashMap<>(5);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 所有java类
|
||||||
|
*/
|
||||||
|
private final static String CLASS_PATTERN="/**/*.class";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 包路径 org.jeecg
|
||||||
|
*/
|
||||||
|
private final static String BASE_PACKAGE = "org.jeecg";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 枚举类中获取字典数据的方法名
|
||||||
|
*/
|
||||||
|
private final static String METHOD_NAME = "getDictList";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取枚举类对应的字典数据 SysDictServiceImpl#queryAllDictItems()
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static Map<String, List<DictModel>> getEnumDictData(){
|
||||||
|
if(enumDictData.keySet().size()>0){
|
||||||
|
return enumDictData;
|
||||||
|
}
|
||||||
|
ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();
|
||||||
|
String pattern = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX + ClassUtils.convertClassNameToResourcePath(BASE_PACKAGE) + CLASS_PATTERN;
|
||||||
|
try {
|
||||||
|
Resource[] resources = resourcePatternResolver.getResources(pattern);
|
||||||
|
MetadataReaderFactory readerFactory = new CachingMetadataReaderFactory(resourcePatternResolver);
|
||||||
|
for (Resource resource : resources) {
|
||||||
|
MetadataReader reader = readerFactory.getMetadataReader(resource);
|
||||||
|
String classname = reader.getClassMetadata().getClassName();
|
||||||
|
Class<?> clazz = Class.forName(classname);
|
||||||
|
EnumDict enumDict = clazz.getAnnotation(EnumDict.class);
|
||||||
|
if (enumDict != null) {
|
||||||
|
EnumDict annotation = clazz.getAnnotation(EnumDict.class);
|
||||||
|
String key = annotation.value();
|
||||||
|
if(oConvertUtils.isNotEmpty(key)){
|
||||||
|
List<DictModel> list = (List<DictModel>) clazz.getDeclaredMethod(METHOD_NAME).invoke(null);
|
||||||
|
enumDictData.put(key, list);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}catch (Exception e){
|
||||||
|
log.error("获取枚举类字典数据异常", e.getMessage());
|
||||||
|
// e.printStackTrace();
|
||||||
|
}
|
||||||
|
return enumDictData;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用于后端字典翻译 SysDictServiceImpl#queryManyDictByKeys(java.util.List, java.util.List)
|
||||||
|
* @param dictCodeList
|
||||||
|
* @param keys
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static Map<String, List<DictModel>> queryManyDictByKeys(List<String> dictCodeList, List<String> keys){
|
||||||
|
if(enumDictData.keySet().size()==0){
|
||||||
|
getEnumDictData();
|
||||||
|
}
|
||||||
|
Map<String, List<DictModel>> map = new HashMap<>();
|
||||||
|
for (String code : enumDictData.keySet()) {
|
||||||
|
if(dictCodeList.indexOf(code)>=0){
|
||||||
|
List<DictModel> dictItemList = enumDictData.get(code);
|
||||||
|
for(DictModel dm: dictItemList){
|
||||||
|
String value = dm.getValue();
|
||||||
|
if(keys.indexOf(value)>=0){
|
||||||
|
List<DictModel> list = new ArrayList<>();
|
||||||
|
list.add(new DictModel(value, dm.getText()));
|
||||||
|
map.put(code,list);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -2,6 +2,7 @@ package org.jeecg.common.system.vo;
|
||||||
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
|
||||||
|
import org.jeecg.common.desensitization.annotation.SensitiveField;
|
||||||
import org.springframework.format.annotation.DateTimeFormat;
|
import org.springframework.format.annotation.DateTimeFormat;
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||||
|
@ -26,21 +27,25 @@ public class LoginUser {
|
||||||
/**
|
/**
|
||||||
* 登录人id
|
* 登录人id
|
||||||
*/
|
*/
|
||||||
|
@SensitiveField
|
||||||
private String id;
|
private String id;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 登录人账号
|
* 登录人账号
|
||||||
*/
|
*/
|
||||||
|
@SensitiveField
|
||||||
private String username;
|
private String username;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 登录人名字
|
* 登录人名字
|
||||||
*/
|
*/
|
||||||
|
@SensitiveField
|
||||||
private String realname;
|
private String realname;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 登录人密码
|
* 登录人密码
|
||||||
*/
|
*/
|
||||||
|
@SensitiveField
|
||||||
private String password;
|
private String password;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -50,11 +55,13 @@ public class LoginUser {
|
||||||
/**
|
/**
|
||||||
* 头像
|
* 头像
|
||||||
*/
|
*/
|
||||||
|
@SensitiveField
|
||||||
private String avatar;
|
private String avatar;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 生日
|
* 生日
|
||||||
*/
|
*/
|
||||||
|
@SensitiveField
|
||||||
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd")
|
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd")
|
||||||
@DateTimeFormat(pattern = "yyyy-MM-dd")
|
@DateTimeFormat(pattern = "yyyy-MM-dd")
|
||||||
private Date birthday;
|
private Date birthday;
|
||||||
|
@ -67,11 +74,13 @@ public class LoginUser {
|
||||||
/**
|
/**
|
||||||
* 电子邮件
|
* 电子邮件
|
||||||
*/
|
*/
|
||||||
|
@SensitiveField
|
||||||
private String email;
|
private String email;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 电话
|
* 电话
|
||||||
*/
|
*/
|
||||||
|
@SensitiveField
|
||||||
private String phone;
|
private String phone;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -103,11 +112,13 @@ public class LoginUser {
|
||||||
/**
|
/**
|
||||||
* 职务,关联职务表
|
* 职务,关联职务表
|
||||||
*/
|
*/
|
||||||
|
@SensitiveField
|
||||||
private String post;
|
private String post;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 座机号
|
* 座机号
|
||||||
*/
|
*/
|
||||||
|
@SensitiveField
|
||||||
private String telephone;
|
private String telephone;
|
||||||
|
|
||||||
/**多租户id配置,编辑用户的时候设置*/
|
/**多租户id配置,编辑用户的时候设置*/
|
||||||
|
|
|
@ -7,6 +7,7 @@ import com.baomidou.mybatisplus.extension.toolkit.JdbcUtils;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.jeecg.common.constant.CommonConstant;
|
import org.jeecg.common.constant.CommonConstant;
|
||||||
import org.jeecg.common.constant.DataBaseConstant;
|
import org.jeecg.common.constant.DataBaseConstant;
|
||||||
|
import org.jeecg.common.constant.ServiceNameConstants;
|
||||||
import org.jeecg.common.constant.SymbolConstant;
|
import org.jeecg.common.constant.SymbolConstant;
|
||||||
import org.jeecg.common.util.filter.FileTypeFilter;
|
import org.jeecg.common.util.filter.FileTypeFilter;
|
||||||
import org.jeecg.common.util.oss.OssBootUtil;
|
import org.jeecg.common.util.oss.OssBootUtil;
|
||||||
|
@ -314,14 +315,14 @@ public class CommonUtils {
|
||||||
*/
|
*/
|
||||||
public static String getBaseUrl(HttpServletRequest request) {
|
public static String getBaseUrl(HttpServletRequest request) {
|
||||||
//1.【兼容】兼容微服务下的 base path-------
|
//1.【兼容】兼容微服务下的 base path-------
|
||||||
String xGatewayBasePath = request.getHeader("X_GATEWAY_BASE_PATH");
|
String xGatewayBasePath = request.getHeader(ServiceNameConstants.X_GATEWAY_BASE_PATH);
|
||||||
if(oConvertUtils.isNotEmpty(xGatewayBasePath)){
|
if(oConvertUtils.isNotEmpty(xGatewayBasePath)){
|
||||||
log.info("x_gateway_base_path = "+ xGatewayBasePath);
|
log.info("x_gateway_base_path = "+ xGatewayBasePath);
|
||||||
return xGatewayBasePath;
|
return xGatewayBasePath;
|
||||||
}
|
}
|
||||||
//2.【兼容】SSL认证之后,request.getScheme()获取不到https的问题
|
//2.【兼容】SSL认证之后,request.getScheme()获取不到https的问题
|
||||||
// https://blog.csdn.net/weixin_34376986/article/details/89767950
|
// https://blog.csdn.net/weixin_34376986/article/details/89767950
|
||||||
String scheme = request.getHeader("X-Forwarded-Scheme");
|
String scheme = request.getHeader(CommonConstant.X_FORWARDED_SCHEME);
|
||||||
if(oConvertUtils.isEmpty(scheme)){
|
if(oConvertUtils.isEmpty(scheme)){
|
||||||
scheme = request.getScheme();
|
scheme = request.getScheme();
|
||||||
}
|
}
|
||||||
|
|
|
@ -214,7 +214,7 @@ public class RestUtil {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 拼接 url 参数
|
// 拼接 url 参数
|
||||||
if (variables != null) {
|
if (variables != null && !variables.isEmpty()) {
|
||||||
url += ("?" + asUrlVariables(variables));
|
url += ("?" + asUrlVariables(variables));
|
||||||
}
|
}
|
||||||
// 发送请求
|
// 发送请求
|
||||||
|
|
|
@ -4,6 +4,8 @@ import cn.hutool.crypto.SecureUtil;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.jeecg.common.exception.JeecgBootException;
|
import org.jeecg.common.exception.JeecgBootException;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -20,7 +22,11 @@ public class SqlInjectionUtil {
|
||||||
private final static String TABLE_DICT_SIGN_SALT = "20200501";
|
private final static String TABLE_DICT_SIGN_SALT = "20200501";
|
||||||
private final static String XSS_STR = "and |exec |insert |select |delete |update |drop |count |chr |mid |master |truncate |char |declare |;|or |+|user()";
|
private final static String XSS_STR = "and |exec |insert |select |delete |update |drop |count |chr |mid |master |truncate |char |declare |;|or |+|user()";
|
||||||
|
|
||||||
/**show tables*/
|
/**
|
||||||
|
* 正则 user() 匹配更严谨
|
||||||
|
*/
|
||||||
|
private final static String REGULAR_EXPRE_USER = "user[\\s]*\\([\\s]*\\)";
|
||||||
|
/**正则 show tables*/
|
||||||
private final static String SHOW_TABLES = "show\\s+tables";
|
private final static String SHOW_TABLES = "show\\s+tables";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -42,6 +48,13 @@ public class SqlInjectionUtil {
|
||||||
log.info(" 表字典,SQL注入漏洞签名校验成功!sign=" + sign + ",dictCode=" + dictCode);
|
log.info(" 表字典,SQL注入漏洞签名校验成功!sign=" + sign + ",dictCode=" + dictCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* sql注入过滤处理,遇到注入关键字抛异常
|
||||||
|
* @param value
|
||||||
|
*/
|
||||||
|
public static void filterContent(String value) {
|
||||||
|
filterContent(value, null);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* sql注入过滤处理,遇到注入关键字抛异常
|
* sql注入过滤处理,遇到注入关键字抛异常
|
||||||
|
@ -49,7 +62,7 @@ public class SqlInjectionUtil {
|
||||||
* @param value
|
* @param value
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public static void filterContent(String value) {
|
public static void filterContent(String value, String customXssString) {
|
||||||
if (value == null || "".equals(value)) {
|
if (value == null || "".equals(value)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -66,19 +79,39 @@ public class SqlInjectionUtil {
|
||||||
throw new RuntimeException("请注意,值可能存在SQL注入风险!--->" + value);
|
throw new RuntimeException("请注意,值可能存在SQL注入风险!--->" + value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(Pattern.matches(SHOW_TABLES, value)){
|
//update-begin-author:taoyan date:2022-7-13 for: 除了XSS_STR这些提前设置好的,还需要额外的校验比如 单引号
|
||||||
|
if (customXssString != null) {
|
||||||
|
String[] xssArr2 = customXssString.split("\\|");
|
||||||
|
for (int i = 0; i < xssArr2.length; i++) {
|
||||||
|
if (value.indexOf(xssArr2[i]) > -1) {
|
||||||
|
log.error("请注意,存在SQL注入关键词---> {}", xssArr2[i]);
|
||||||
|
log.error("请注意,值可能存在SQL注入风险!---> {}", value);
|
||||||
|
throw new RuntimeException("请注意,值可能存在SQL注入风险!--->" + value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//update-end-author:taoyan date:2022-7-13 for: 除了XSS_STR这些提前设置好的,还需要额外的校验比如 单引号
|
||||||
|
if(Pattern.matches(SHOW_TABLES, value) || Pattern.matches(REGULAR_EXPRE_USER, value)){
|
||||||
throw new RuntimeException("请注意,值可能存在SQL注入风险!--->" + value);
|
throw new RuntimeException("请注意,值可能存在SQL注入风险!--->" + value);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* sql注入过滤处理,遇到注入关键字抛异常
|
||||||
|
* @param values
|
||||||
|
*/
|
||||||
|
public static void filterContent(String[] values) {
|
||||||
|
filterContent(values, null);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* sql注入过滤处理,遇到注入关键字抛异常
|
* sql注入过滤处理,遇到注入关键字抛异常
|
||||||
*
|
*
|
||||||
* @param values
|
* @param values
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public static void filterContent(String[] values) {
|
public static void filterContent(String[] values, String customXssString) {
|
||||||
String[] xssArr = XSS_STR.split("\\|");
|
String[] xssArr = XSS_STR.split("\\|");
|
||||||
for (String value : values) {
|
for (String value : values) {
|
||||||
if (value == null || "".equals(value)) {
|
if (value == null || "".equals(value)) {
|
||||||
|
@ -96,7 +129,19 @@ public class SqlInjectionUtil {
|
||||||
throw new RuntimeException("请注意,值可能存在SQL注入风险!--->" + value);
|
throw new RuntimeException("请注意,值可能存在SQL注入风险!--->" + value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(Pattern.matches(SHOW_TABLES, value)){
|
//update-begin-author:taoyan date:2022-7-13 for: 除了XSS_STR这些提前设置好的,还需要额外的校验比如 单引号
|
||||||
|
if (customXssString != null) {
|
||||||
|
String[] xssArr2 = customXssString.split("\\|");
|
||||||
|
for (int i = 0; i < xssArr2.length; i++) {
|
||||||
|
if (value.indexOf(xssArr2[i]) > -1) {
|
||||||
|
log.error("请注意,存在SQL注入关键词---> {}", xssArr2[i]);
|
||||||
|
log.error("请注意,值可能存在SQL注入风险!---> {}", value);
|
||||||
|
throw new RuntimeException("请注意,值可能存在SQL注入风险!--->" + value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//update-end-author:taoyan date:2022-7-13 for: 除了XSS_STR这些提前设置好的,还需要额外的校验比如 单引号
|
||||||
|
if(Pattern.matches(SHOW_TABLES, value) || Pattern.matches(REGULAR_EXPRE_USER, value)){
|
||||||
throw new RuntimeException("请注意,值可能存在SQL注入风险!--->" + value);
|
throw new RuntimeException("请注意,值可能存在SQL注入风险!--->" + value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -111,8 +156,8 @@ public class SqlInjectionUtil {
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
//@Deprecated
|
//@Deprecated
|
||||||
public static void specialFilterContent(String value) {
|
public static void specialFilterContentForDictSql(String value) {
|
||||||
String specialXssStr = " exec | insert | select | delete | update | drop | count | chr | mid | master | truncate | char | declare |;|+|";
|
String specialXssStr = " exec | insert | select | delete | update | drop | count | chr | mid | master | truncate | char | declare |;|+|user()";
|
||||||
String[] xssArr = specialXssStr.split("\\|");
|
String[] xssArr = specialXssStr.split("\\|");
|
||||||
if (value == null || "".equals(value)) {
|
if (value == null || "".equals(value)) {
|
||||||
return;
|
return;
|
||||||
|
@ -129,7 +174,7 @@ public class SqlInjectionUtil {
|
||||||
throw new RuntimeException("请注意,值可能存在SQL注入风险!--->" + value);
|
throw new RuntimeException("请注意,值可能存在SQL注入风险!--->" + value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(Pattern.matches(SHOW_TABLES, value)){
|
if(Pattern.matches(SHOW_TABLES, value) || Pattern.matches(REGULAR_EXPRE_USER, value)){
|
||||||
throw new RuntimeException("请注意,值可能存在SQL注入风险!--->" + value);
|
throw new RuntimeException("请注意,值可能存在SQL注入风险!--->" + value);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
|
@ -144,7 +189,7 @@ public class SqlInjectionUtil {
|
||||||
*/
|
*/
|
||||||
//@Deprecated
|
//@Deprecated
|
||||||
public static void specialFilterContentForOnlineReport(String value) {
|
public static void specialFilterContentForOnlineReport(String value) {
|
||||||
String specialXssStr = " exec | insert | delete | update | drop | chr | mid | master | truncate | char | declare |";
|
String specialXssStr = " exec | insert | delete | update | drop | chr | mid | master | truncate | char | declare |user()";
|
||||||
String[] xssArr = specialXssStr.split("\\|");
|
String[] xssArr = specialXssStr.split("\\|");
|
||||||
if (value == null || "".equals(value)) {
|
if (value == null || "".equals(value)) {
|
||||||
return;
|
return;
|
||||||
|
@ -162,10 +207,53 @@ public class SqlInjectionUtil {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(Pattern.matches(SHOW_TABLES, value)){
|
if(Pattern.matches(SHOW_TABLES, value) || Pattern.matches(REGULAR_EXPRE_USER, value)){
|
||||||
throw new RuntimeException("请注意,值可能存在SQL注入风险!--->" + value);
|
throw new RuntimeException("请注意,值可能存在SQL注入风险!--->" + value);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断给定的字段是不是类中的属性
|
||||||
|
* @param field 字段名
|
||||||
|
* @param clazz 类对象
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static boolean isClassField(String field, Class clazz){
|
||||||
|
Field[] fields = clazz.getDeclaredFields();
|
||||||
|
for(int i=0;i<fields.length;i++){
|
||||||
|
String fieldName = fields[i].getName();
|
||||||
|
String tableColumnName = oConvertUtils.camelToUnderline(fieldName);
|
||||||
|
if(fieldName.equalsIgnoreCase(field) || tableColumnName.equalsIgnoreCase(field)){
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断给定的多个字段是不是类中的属性
|
||||||
|
* @param fieldSet 字段名set
|
||||||
|
* @param clazz 类对象
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static boolean isClassField(Set<String> fieldSet, Class clazz){
|
||||||
|
Field[] fields = clazz.getDeclaredFields();
|
||||||
|
for(String field: fieldSet){
|
||||||
|
boolean exist = false;
|
||||||
|
for(int i=0;i<fields.length;i++){
|
||||||
|
String fieldName = fields[i].getName();
|
||||||
|
String tableColumnName = oConvertUtils.camelToUnderline(fieldName);
|
||||||
|
if(fieldName.equalsIgnoreCase(field) || tableColumnName.equalsIgnoreCase(field)){
|
||||||
|
exist = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(!exist){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@ import org.apache.commons.lang3.StringUtils;
|
||||||
import org.jeecg.common.api.CommonAPI;
|
import org.jeecg.common.api.CommonAPI;
|
||||||
import org.jeecg.common.constant.CacheConstant;
|
import org.jeecg.common.constant.CacheConstant;
|
||||||
import org.jeecg.common.constant.CommonConstant;
|
import org.jeecg.common.constant.CommonConstant;
|
||||||
|
import org.jeecg.common.desensitization.util.SensitiveInfoUtil;
|
||||||
import org.jeecg.common.exception.JeecgBoot401Exception;
|
import org.jeecg.common.exception.JeecgBoot401Exception;
|
||||||
import org.jeecg.common.system.util.JwtUtil;
|
import org.jeecg.common.system.util.JwtUtil;
|
||||||
import org.jeecg.common.system.vo.LoginUser;
|
import org.jeecg.common.system.vo.LoginUser;
|
||||||
|
@ -106,9 +107,16 @@ public class TokenUtils {
|
||||||
public static LoginUser getLoginUser(String username, CommonAPI commonApi, RedisUtil redisUtil) {
|
public static LoginUser getLoginUser(String username, CommonAPI commonApi, RedisUtil redisUtil) {
|
||||||
LoginUser loginUser = null;
|
LoginUser loginUser = null;
|
||||||
String loginUserKey = CacheConstant.SYS_USERS_CACHE + "::" + username;
|
String loginUserKey = CacheConstant.SYS_USERS_CACHE + "::" + username;
|
||||||
if(redisUtil.hasKey(loginUserKey)){
|
//【重要】此处通过redis原生获取缓存用户,是为了解决微服务下system服务挂了,其他服务互调不通问题---
|
||||||
loginUser = (LoginUser) redisUtil.get(loginUserKey);
|
if (redisUtil.hasKey(loginUserKey)) {
|
||||||
}else{
|
try {
|
||||||
|
loginUser = (LoginUser) redisUtil.get(loginUserKey);
|
||||||
|
//解密用户
|
||||||
|
SensitiveInfoUtil.handlerObject(loginUser, false);
|
||||||
|
} catch (IllegalAccessException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
// 查询用户信息
|
// 查询用户信息
|
||||||
loginUser = commonApi.getUserByName(username);
|
loginUser = commonApi.getUserByName(username);
|
||||||
}
|
}
|
||||||
|
|
|
@ -66,22 +66,20 @@ public class AesEncryptUtil {
|
||||||
* @throws Exception
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
public static String desEncrypt(String data, String key, String iv) throws Exception {
|
public static String desEncrypt(String data, String key, String iv) throws Exception {
|
||||||
try {
|
//update-begin-author:taoyan date:2022-5-23 for:VUEN-1084 【vue3】online表单测试发现的新问题 6、解密报错 ---解码失败应该把异常抛出去,在外面处理
|
||||||
byte[] encrypted1 = Base64.decode(data);
|
byte[] encrypted1 = Base64.decode(data);
|
||||||
|
|
||||||
Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
|
Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
|
||||||
SecretKeySpec keyspec = new SecretKeySpec(key.getBytes(), "AES");
|
SecretKeySpec keyspec = new SecretKeySpec(key.getBytes(), "AES");
|
||||||
IvParameterSpec ivspec = new IvParameterSpec(iv.getBytes());
|
IvParameterSpec ivspec = new IvParameterSpec(iv.getBytes());
|
||||||
|
|
||||||
cipher.init(Cipher.DECRYPT_MODE, keyspec, ivspec);
|
cipher.init(Cipher.DECRYPT_MODE, keyspec, ivspec);
|
||||||
|
|
||||||
byte[] original = cipher.doFinal(encrypted1);
|
byte[] original = cipher.doFinal(encrypted1);
|
||||||
String originalString = new String(original);
|
String originalString = new String(original);
|
||||||
return originalString;
|
//加密解码后的字符串会出现\u0000
|
||||||
} catch (Exception e) {
|
return originalString.replaceAll("\\u0000", "");
|
||||||
e.printStackTrace();
|
//update-end-author:taoyan date:2022-5-23 for:VUEN-1084 【vue3】online表单测试发现的新问题 6、解密报错 ---解码失败应该把异常抛出去,在外面处理
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -168,7 +168,7 @@ public abstract class AbstractQueryBlackListHandler {
|
||||||
|
|
||||||
public String getError(){
|
public String getError(){
|
||||||
// TODO
|
// TODO
|
||||||
return "sql黑名单校验不通过,请联系管理员!";
|
return "系统设置了安全规则,敏感表和敏感字段禁止查询,联系管理员授权!";
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
package org.jeecg.config;
|
package org.jeecg.config;
|
||||||
|
|
||||||
|
import org.jeecg.config.vo.DomainUrl;
|
||||||
|
import org.jeecg.config.vo.Path;
|
||||||
import org.jeecg.config.vo.Shiro;
|
import org.jeecg.config.vo.Shiro;
|
||||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
@ -9,9 +11,15 @@ import org.springframework.stereotype.Component;
|
||||||
* 加载项目配置
|
* 加载项目配置
|
||||||
* @author: jeecg-boot
|
* @author: jeecg-boot
|
||||||
*/
|
*/
|
||||||
@Component("jeeccgBaseConfig")
|
@Component("jeecgBaseConfig")
|
||||||
@ConfigurationProperties(prefix = "jeecg")
|
@ConfigurationProperties(prefix = "jeecg")
|
||||||
public class JeeccgBaseConfig {
|
public class JeecgBaseConfig {
|
||||||
|
/**
|
||||||
|
* 签名密钥串(字典等敏感接口)
|
||||||
|
* @TODO 降低使用成本加的默认值,实际以 yml配置 为准
|
||||||
|
*/
|
||||||
|
private String signatureSecret = "dd05f1c54d63749eda95f9fa6d49v442a";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 是否启用安全模式
|
* 是否启用安全模式
|
||||||
*/
|
*/
|
||||||
|
@ -21,10 +29,16 @@ public class JeeccgBaseConfig {
|
||||||
*/
|
*/
|
||||||
private Shiro shiro;
|
private Shiro shiro;
|
||||||
/**
|
/**
|
||||||
* 签名密钥串(字典等敏感接口)
|
* 上传文件配置
|
||||||
* @TODO 降低使用成本加的默认值,实际以 yml配置 为准
|
|
||||||
*/
|
*/
|
||||||
private String signatureSecret = "dd05f1c54d63749eda95f9fa6d49v442a";
|
private Path path;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 前端页面访问地址
|
||||||
|
* pc: http://localhost:3100
|
||||||
|
* app: http://localhost:8051
|
||||||
|
*/
|
||||||
|
private DomainUrl domainUrl;
|
||||||
|
|
||||||
public Boolean getSafeMode() {
|
public Boolean getSafeMode() {
|
||||||
return safeMode;
|
return safeMode;
|
||||||
|
@ -49,4 +63,20 @@ public class JeeccgBaseConfig {
|
||||||
public void setShiro(Shiro shiro) {
|
public void setShiro(Shiro shiro) {
|
||||||
this.shiro = shiro;
|
this.shiro = shiro;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Path getPath() {
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPath(Path path) {
|
||||||
|
this.path = path;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DomainUrl getDomainUrl() {
|
||||||
|
return domainUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDomainUrl(DomainUrl domainUrl) {
|
||||||
|
this.domainUrl = domainUrl;
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -145,4 +145,13 @@ public class WebMvcConfiguration implements WebMvcConfigurer {
|
||||||
return () -> meterRegistryPostProcessor.postProcessAfterInitialization(prometheusMeterRegistry, "");
|
return () -> meterRegistryPostProcessor.postProcessAfterInitialization(prometheusMeterRegistry, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// /**
|
||||||
|
// * 注册拦截器【拦截器拦截参数,自动切换数据源——后期实现多租户切换数据源功能】
|
||||||
|
// * @param registry
|
||||||
|
// */
|
||||||
|
// @Override
|
||||||
|
// public void addInterceptors(InterceptorRegistry registry) {
|
||||||
|
// registry.addInterceptor(new DynamicDatasourceInterceptor()).addPathPatterns("/test/dynamic/**");
|
||||||
|
// }
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
package org.jeecg.config;
|
package org.jeecg.config;
|
||||||
|
|
||||||
|
import org.jeecg.config.filter.WebsocketFilter;
|
||||||
|
import org.springframework.boot.web.servlet.FilterRegistrationBean;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.web.socket.server.standard.ServerEndpointExporter;
|
import org.springframework.web.socket.server.standard.ServerEndpointExporter;
|
||||||
|
@ -19,4 +21,17 @@ public class WebSocketConfig {
|
||||||
return new ServerEndpointExporter();
|
return new ServerEndpointExporter();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public WebsocketFilter websocketFilter(){
|
||||||
|
return new WebsocketFilter();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public FilterRegistrationBean getFilterRegistrationBean(){
|
||||||
|
FilterRegistrationBean bean = new FilterRegistrationBean();
|
||||||
|
bean.setFilter(websocketFilter());
|
||||||
|
bean.addUrlPatterns("/websocket/*", "/eoaSocket/*", "/newsWebsocket/*", "/vxeSocket/*");
|
||||||
|
return bean;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,35 @@
|
||||||
|
package org.jeecg.config.filter;
|
||||||
|
|
||||||
|
import org.jeecg.common.constant.CommonConstant;
|
||||||
|
import org.jeecg.config.sign.util.BodyReaderHttpServletRequestWrapper;
|
||||||
|
|
||||||
|
import javax.servlet.*;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 针对post请求,将HttpServletRequest包一层 保留body里的参数
|
||||||
|
* @Author taoYan
|
||||||
|
* @Date 2022/4/25 19:19
|
||||||
|
**/
|
||||||
|
public class RequestBodyReserveFilter implements Filter {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
|
||||||
|
ServletRequest requestWrapper = null;
|
||||||
|
|
||||||
|
if(servletRequest instanceof HttpServletRequest) {
|
||||||
|
HttpServletRequest req = (HttpServletRequest) servletRequest;
|
||||||
|
// POST请求类型,才获取POST请求体
|
||||||
|
if(CommonConstant.HTTP_POST.equals(req.getMethod())){
|
||||||
|
requestWrapper = new BodyReaderHttpServletRequestWrapper(req);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(requestWrapper == null) {
|
||||||
|
filterChain.doFilter(servletRequest, servletResponse);
|
||||||
|
} else {
|
||||||
|
filterChain.doFilter(requestWrapper, servletResponse);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,52 @@
|
||||||
|
package org.jeecg.config.filter;
|
||||||
|
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.jeecg.common.api.CommonAPI;
|
||||||
|
import org.jeecg.common.util.RedisUtil;
|
||||||
|
import org.jeecg.common.util.SpringContextUtils;
|
||||||
|
import org.jeecg.common.util.TokenUtils;
|
||||||
|
|
||||||
|
import javax.servlet.*;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* websocket 前端将token放到子协议里传入 与后端建立连接时需要用到http协议,此处用于校验token的有效性
|
||||||
|
* @Author taoYan
|
||||||
|
* @Date 2022/4/21 17:01
|
||||||
|
**/
|
||||||
|
@Slf4j
|
||||||
|
public class WebsocketFilter implements Filter {
|
||||||
|
|
||||||
|
private static final String TOKEN_KEY = "Sec-WebSocket-Protocol";
|
||||||
|
|
||||||
|
private static CommonAPI commonApi;
|
||||||
|
|
||||||
|
private static RedisUtil redisUtil;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
|
||||||
|
if (commonApi == null) {
|
||||||
|
commonApi = SpringContextUtils.getBean(CommonAPI.class);
|
||||||
|
}
|
||||||
|
if (redisUtil == null) {
|
||||||
|
redisUtil = SpringContextUtils.getBean(RedisUtil.class);
|
||||||
|
}
|
||||||
|
HttpServletRequest request = (HttpServletRequest)servletRequest;
|
||||||
|
String token = request.getHeader(TOKEN_KEY);
|
||||||
|
|
||||||
|
log.info("websocket连接 Token安全校验,Path = {},token:{}", request.getRequestURI(), token);
|
||||||
|
|
||||||
|
try {
|
||||||
|
TokenUtils.verifyToken(token, commonApi, redisUtil);
|
||||||
|
} catch (Exception exception) {
|
||||||
|
log.error("websocket连接校验失败,{},token:{}", exception.getMessage(), token);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
HttpServletResponse response = (HttpServletResponse)servletResponse;
|
||||||
|
response.setHeader(TOKEN_KEY, token);
|
||||||
|
filterChain.doFilter(servletRequest, servletResponse);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -3,6 +3,9 @@ package org.jeecg.config.mybatis;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import cn.hutool.core.util.ObjectUtil;
|
||||||
|
import com.baomidou.mybatisplus.extension.plugins.inner.DynamicTableNameInnerInterceptor;
|
||||||
|
import org.jeecg.common.constant.CommonConstant;
|
||||||
import org.jeecg.common.util.oConvertUtils;
|
import org.jeecg.common.util.oConvertUtils;
|
||||||
import org.mybatis.spring.annotation.MapperScan;
|
import org.mybatis.spring.annotation.MapperScan;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
|
@ -71,9 +74,35 @@ public class MybatisPlusSaasConfig {
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
interceptor.addInnerInterceptor(new PaginationInnerInterceptor());
|
interceptor.addInnerInterceptor(new PaginationInnerInterceptor());
|
||||||
|
//update-begin-author:zyf date:20220425 for:【VUEN-606】注入动态表名适配拦截器解决多表名问题
|
||||||
|
interceptor.addInnerInterceptor(dynamicTableNameInnerInterceptor());
|
||||||
|
//update-end-author:zyf date:20220425 for:【VUEN-606】注入动态表名适配拦截器解决多表名问题
|
||||||
return interceptor;
|
return interceptor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 动态表名切换拦截器,用于适配vue2和vue3同一个表有多个的情况,如sys_role_index在vue3情况下表名为sys_role_index_v3
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private DynamicTableNameInnerInterceptor dynamicTableNameInnerInterceptor() {
|
||||||
|
DynamicTableNameInnerInterceptor dynamicTableNameInnerInterceptor = new DynamicTableNameInnerInterceptor();
|
||||||
|
dynamicTableNameInnerInterceptor.setTableNameHandler((sql, tableName) -> {
|
||||||
|
//获取需要动态解析的表名
|
||||||
|
String dynamicTableName = ThreadLocalDataHelper.get(CommonConstant.DYNAMIC_TABLE_NAME);
|
||||||
|
//当dynamicTableName不为空时才走动态表名处理逻辑,否则返回原始表名
|
||||||
|
if (ObjectUtil.isNotEmpty(dynamicTableName) && dynamicTableName.equals(tableName)) {
|
||||||
|
// 获取前端传递的版本号标识
|
||||||
|
Object version = ThreadLocalDataHelper.get(CommonConstant.VERSION);
|
||||||
|
if (ObjectUtil.isNotEmpty(version)) {
|
||||||
|
//拼接表名规则(原始表名+下划线+前端传递的版本号)
|
||||||
|
return tableName + "_" + version;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return tableName;
|
||||||
|
});
|
||||||
|
return dynamicTableNameInnerInterceptor;
|
||||||
|
}
|
||||||
|
|
||||||
// /**
|
// /**
|
||||||
// * 下个版本会删除,现在为了避免缓存出现问题不得不配置
|
// * 下个版本会删除,现在为了避免缓存出现问题不得不配置
|
||||||
// * @return
|
// * @return
|
||||||
|
|
|
@ -0,0 +1,62 @@
|
||||||
|
package org.jeecg.config.mybatis;
|
||||||
|
|
||||||
|
import cn.hutool.core.util.ObjectUtil;
|
||||||
|
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Description: 本地线程变量存储工具类
|
||||||
|
* @author: lsq
|
||||||
|
* @date: 2022年03月25日 11:42
|
||||||
|
*/
|
||||||
|
public class ThreadLocalDataHelper {
|
||||||
|
/**
|
||||||
|
* 线程的本地变量
|
||||||
|
*/
|
||||||
|
private static final ThreadLocal<ConcurrentHashMap> REQUEST_DATA = new ThreadLocal<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 存储本地参数
|
||||||
|
*/
|
||||||
|
private static final ConcurrentHashMap DATA_MAP = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置请求参数
|
||||||
|
*
|
||||||
|
* @param key 参数key
|
||||||
|
* @param value 参数值
|
||||||
|
*/
|
||||||
|
public static void put(String key, Object value) {
|
||||||
|
if(ObjectUtil.isNotEmpty(value)) {
|
||||||
|
DATA_MAP.put(key, value);
|
||||||
|
REQUEST_DATA.set(DATA_MAP);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取请求参数值
|
||||||
|
*
|
||||||
|
* @param key 请求参数
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static <T> T get(String key) {
|
||||||
|
ConcurrentHashMap dataMap = REQUEST_DATA.get();
|
||||||
|
if (CollectionUtils.isNotEmpty(dataMap)) {
|
||||||
|
return (T) dataMap.get(key);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取请求参数
|
||||||
|
*
|
||||||
|
* @return 请求参数 MAP 对象
|
||||||
|
*/
|
||||||
|
public static void clear() {
|
||||||
|
DATA_MAP.clear();
|
||||||
|
REQUEST_DATA.remove();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,55 @@
|
||||||
|
package org.jeecg.config.mybatis.aspect;
|
||||||
|
|
||||||
|
import org.aspectj.lang.ProceedingJoinPoint;
|
||||||
|
import org.aspectj.lang.annotation.Around;
|
||||||
|
import org.aspectj.lang.annotation.Aspect;
|
||||||
|
import org.aspectj.lang.annotation.Pointcut;
|
||||||
|
import org.aspectj.lang.reflect.MethodSignature;
|
||||||
|
import org.jeecg.common.aspect.annotation.DynamicTable;
|
||||||
|
import org.jeecg.common.constant.CommonConstant;
|
||||||
|
import org.jeecg.common.util.SpringContextUtils;
|
||||||
|
import org.jeecg.config.mybatis.ThreadLocalDataHelper;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 动态table切换 切面处理
|
||||||
|
*
|
||||||
|
* @author :zyf
|
||||||
|
* @date:2020-04-25
|
||||||
|
*/
|
||||||
|
@Aspect
|
||||||
|
@Component
|
||||||
|
public class DynamicTableAspect {
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 定义切面拦截切入点
|
||||||
|
*/
|
||||||
|
@Pointcut("@annotation(org.jeecg.common.aspect.annotation.DynamicTable)")
|
||||||
|
public void dynamicTable() {
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Around("dynamicTable()")
|
||||||
|
public Object around(ProceedingJoinPoint point) throws Throwable {
|
||||||
|
MethodSignature signature = (MethodSignature) point.getSignature();
|
||||||
|
Method method = signature.getMethod();
|
||||||
|
DynamicTable dynamicTable = method.getAnnotation(DynamicTable.class);
|
||||||
|
HttpServletRequest request = SpringContextUtils.getHttpServletRequest();
|
||||||
|
//获取前端传递的版本标记
|
||||||
|
String version = request.getHeader(CommonConstant.VERSION);
|
||||||
|
//存储版本号到本地线程变量
|
||||||
|
ThreadLocalDataHelper.put(CommonConstant.VERSION, version);
|
||||||
|
//存储表名到本地线程变量
|
||||||
|
ThreadLocalDataHelper.put(CommonConstant.DYNAMIC_TABLE_NAME, dynamicTable.value());
|
||||||
|
//执行方法
|
||||||
|
Object result = point.proceed();
|
||||||
|
//清空本地变量
|
||||||
|
ThreadLocalDataHelper.clear();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,55 @@
|
||||||
|
package org.jeecg.config.mybatis.interceptor;
|
||||||
|
|
||||||
|
import com.baomidou.dynamic.datasource.toolkit.DynamicDataSourceContextHolder;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.springframework.web.servlet.HandlerInterceptor;
|
||||||
|
import org.springframework.web.servlet.ModelAndView;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 动态数据源切换拦截器
|
||||||
|
*
|
||||||
|
* 测试:拦截参数,自动切换数据源
|
||||||
|
* 未来规划:后面通过此机制,实现多租户切换数据源功能
|
||||||
|
* @author zyf
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
public class DynamicDatasourceInterceptor implements HandlerInterceptor {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 在请求处理之前进行调用(Controller方法调用之前)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
|
||||||
|
String requestURI = request.getRequestURI();
|
||||||
|
log.info("经过多数据源Interceptor,当前路径是{}", requestURI);
|
||||||
|
//获取动态数据源名称
|
||||||
|
String dsName = request.getParameter("dsName");
|
||||||
|
String dsKey = "master";
|
||||||
|
if (StringUtils.isNotEmpty(dsName)) {
|
||||||
|
dsKey = dsName;
|
||||||
|
}
|
||||||
|
DynamicDataSourceContextHolder.push(dsKey);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 请求处理之后进行调用,但是在视图被渲染之前(Controller方法调用之后)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 在整个请求结束之后被调用,也就是在DispatcherServlet 渲染了对应的视图之后执行(主要是用于进行资源清理工作)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
|
||||||
|
DynamicDataSourceContextHolder.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -15,7 +15,7 @@ import org.crazycake.shiro.RedisClusterManager;
|
||||||
import org.crazycake.shiro.RedisManager;
|
import org.crazycake.shiro.RedisManager;
|
||||||
import org.jeecg.common.constant.CommonConstant;
|
import org.jeecg.common.constant.CommonConstant;
|
||||||
import org.jeecg.common.util.oConvertUtils;
|
import org.jeecg.common.util.oConvertUtils;
|
||||||
import org.jeecg.config.JeeccgBaseConfig;
|
import org.jeecg.config.JeecgBaseConfig;
|
||||||
import org.jeecg.config.shiro.filters.CustomShiroFilterFactoryBean;
|
import org.jeecg.config.shiro.filters.CustomShiroFilterFactoryBean;
|
||||||
import org.jeecg.config.shiro.filters.JwtFilter;
|
import org.jeecg.config.shiro.filters.JwtFilter;
|
||||||
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
|
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
|
||||||
|
@ -45,11 +45,11 @@ import java.util.*;
|
||||||
public class ShiroConfig {
|
public class ShiroConfig {
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
LettuceConnectionFactory lettuceConnectionFactory;
|
private LettuceConnectionFactory lettuceConnectionFactory;
|
||||||
@Autowired
|
@Autowired
|
||||||
private Environment env;
|
private Environment env;
|
||||||
@Autowired
|
@Resource
|
||||||
JeeccgBaseConfig jeeccgBaseConfig;
|
private JeecgBaseConfig jeecgBaseConfig;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Filter Chain定义说明
|
* Filter Chain定义说明
|
||||||
|
@ -64,11 +64,15 @@ public class ShiroConfig {
|
||||||
shiroFilterFactoryBean.setSecurityManager(securityManager);
|
shiroFilterFactoryBean.setSecurityManager(securityManager);
|
||||||
// 拦截器
|
// 拦截器
|
||||||
Map<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>();
|
Map<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>();
|
||||||
String shiroExcludeUrls = jeeccgBaseConfig.getShiro().getExcludeUrls();
|
|
||||||
if(oConvertUtils.isNotEmpty(shiroExcludeUrls)){
|
//支持yml方式,配置拦截排除
|
||||||
String[] permissionUrl = shiroExcludeUrls.split(",");
|
if(jeecgBaseConfig.getShiro()!=null){
|
||||||
for(String url : permissionUrl){
|
String shiroExcludeUrls = jeecgBaseConfig.getShiro().getExcludeUrls();
|
||||||
filterChainDefinitionMap.put(url,"anon");
|
if(oConvertUtils.isNotEmpty(shiroExcludeUrls)){
|
||||||
|
String[] permissionUrl = shiroExcludeUrls.split(",");
|
||||||
|
for(String url : permissionUrl){
|
||||||
|
filterChainDefinitionMap.put(url,"anon");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 配置不会被拦截的链接 顺序判断
|
// 配置不会被拦截的链接 顺序判断
|
||||||
|
@ -126,8 +130,10 @@ public class ShiroConfig {
|
||||||
filterChainDefinitionMap.put("/**/*.js.map", "anon");
|
filterChainDefinitionMap.put("/**/*.js.map", "anon");
|
||||||
filterChainDefinitionMap.put("/**/*.css.map", "anon");
|
filterChainDefinitionMap.put("/**/*.css.map", "anon");
|
||||||
|
|
||||||
//测试示例
|
//大屏模板例子
|
||||||
filterChainDefinitionMap.put("/test/bigScreen/**", "anon"); //大屏模板例子
|
filterChainDefinitionMap.put("/test/bigScreen/**", "anon");
|
||||||
|
filterChainDefinitionMap.put("/bigscreen/template1/**", "anon");
|
||||||
|
filterChainDefinitionMap.put("/bigscreen/template1/**", "anon");
|
||||||
//filterChainDefinitionMap.put("/test/jeecgDemo/rabbitMqClientTest/**", "anon"); //MQ测试
|
//filterChainDefinitionMap.put("/test/jeecgDemo/rabbitMqClientTest/**", "anon"); //MQ测试
|
||||||
//filterChainDefinitionMap.put("/test/jeecgDemo/html", "anon"); //模板页面
|
//filterChainDefinitionMap.put("/test/jeecgDemo/html", "anon"); //模板页面
|
||||||
//filterChainDefinitionMap.put("/test/jeecgDemo/redis/**", "anon"); //redis测试
|
//filterChainDefinitionMap.put("/test/jeecgDemo/redis/**", "anon"); //redis测试
|
||||||
|
@ -137,8 +143,6 @@ public class ShiroConfig {
|
||||||
filterChainDefinitionMap.put("/newsWebsocket/**", "anon");//CMS模块
|
filterChainDefinitionMap.put("/newsWebsocket/**", "anon");//CMS模块
|
||||||
filterChainDefinitionMap.put("/vxeSocket/**", "anon");//JVxeTable无痕刷新示例
|
filterChainDefinitionMap.put("/vxeSocket/**", "anon");//JVxeTable无痕刷新示例
|
||||||
|
|
||||||
//wps
|
|
||||||
filterChainDefinitionMap.put("/v1/**","anon");
|
|
||||||
|
|
||||||
//性能监控 TODO 存在安全漏洞泄露TOEKN(durid连接池也有)
|
//性能监控 TODO 存在安全漏洞泄露TOEKN(durid连接池也有)
|
||||||
filterChainDefinitionMap.put("/actuator/**", "anon");
|
filterChainDefinitionMap.put("/actuator/**", "anon");
|
||||||
|
|
|
@ -69,13 +69,13 @@ public class ShiroRealm extends AuthorizingRealm {
|
||||||
|
|
||||||
// 设置用户拥有的角色集合,比如“admin,test”
|
// 设置用户拥有的角色集合,比如“admin,test”
|
||||||
Set<String> roleSet = commonApi.queryUserRoles(username);
|
Set<String> roleSet = commonApi.queryUserRoles(username);
|
||||||
System.out.println(roleSet.toString());
|
//System.out.println(roleSet.toString());
|
||||||
info.setRoles(roleSet);
|
info.setRoles(roleSet);
|
||||||
|
|
||||||
// 设置用户拥有的权限集合,比如“sys:role:add,sys:user:add”
|
// 设置用户拥有的权限集合,比如“sys:role:add,sys:user:add”
|
||||||
Set<String> permissionSet = commonApi.queryUserAuths(username);
|
Set<String> permissionSet = commonApi.queryUserAuths(username);
|
||||||
info.addStringPermissions(permissionSet);
|
info.addStringPermissions(permissionSet);
|
||||||
System.out.println(permissionSet);
|
//System.out.println(permissionSet);
|
||||||
log.info("===============Shiro权限认证成功==============");
|
log.info("===============Shiro权限认证成功==============");
|
||||||
return info;
|
return info;
|
||||||
}
|
}
|
||||||
|
@ -123,7 +123,7 @@ public class ShiroRealm extends AuthorizingRealm {
|
||||||
|
|
||||||
// 查询用户信息
|
// 查询用户信息
|
||||||
log.debug("———校验token是否有效————checkUserTokenIsEffect——————— "+ token);
|
log.debug("———校验token是否有效————checkUserTokenIsEffect——————— "+ token);
|
||||||
LoginUser loginUser = TokenUtils.getLoginUser(username,commonApi,redisUtil);
|
LoginUser loginUser = TokenUtils.getLoginUser(username, commonApi, redisUtil);
|
||||||
//LoginUser loginUser = commonApi.getUserByName(username);
|
//LoginUser loginUser = commonApi.getUserByName(username);
|
||||||
if (loginUser == null) {
|
if (loginUser == null) {
|
||||||
throw new AuthenticationException("用户不存在!");
|
throw new AuthenticationException("用户不存在!");
|
||||||
|
|
|
@ -107,4 +107,18 @@ public class JwtFilter extends BasicHttpAuthenticationFilter {
|
||||||
|
|
||||||
return super.preHandle(request, response);
|
return super.preHandle(request, response);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* JwtFilter中ThreadLocal需要及时清除 #3634
|
||||||
|
*
|
||||||
|
* @param request
|
||||||
|
* @param response
|
||||||
|
* @param exception
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void afterCompletion(ServletRequest request, ServletResponse response, Exception exception) throws Exception {
|
||||||
|
//log.info("------清空线程中多租户的ID={}------",TenantContext.getTenant());
|
||||||
|
TenantContext.clear();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
package org.jeecg.config.sign.interceptor;
|
package org.jeecg.config.sign.interceptor;
|
||||||
|
|
||||||
|
import org.jeecg.config.filter.RequestBodyReserveFilter;
|
||||||
|
import org.springframework.boot.web.servlet.FilterRegistrationBean;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
|
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
|
||||||
|
@ -24,4 +26,22 @@ public class SignAuthConfiguration implements WebMvcConfigurer {
|
||||||
public void addInterceptors(InterceptorRegistry registry) {
|
public void addInterceptors(InterceptorRegistry registry) {
|
||||||
registry.addInterceptor(signAuthInterceptor()).addPathPatterns(SIGN_URL_LIST);
|
registry.addInterceptor(signAuthInterceptor()).addPathPatterns(SIGN_URL_LIST);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//update-begin-author:taoyan date:20220427 for: issues/I53J5E post请求X_SIGN签名拦截校验后报错, request body 为空
|
||||||
|
@Bean
|
||||||
|
public RequestBodyReserveFilter requestBodyReserveFilter(){
|
||||||
|
return new RequestBodyReserveFilter();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public FilterRegistrationBean reqBodyFilterRegistrationBean(){
|
||||||
|
FilterRegistrationBean registration = new FilterRegistrationBean();
|
||||||
|
registration.setFilter(requestBodyReserveFilter());
|
||||||
|
registration.setName("requestBodyReserveFilter");
|
||||||
|
// 建议此处只添加post请求地址而不是所有的都需要走过滤器
|
||||||
|
registration.addUrlPatterns(SIGN_URL_LIST);
|
||||||
|
return registration;
|
||||||
|
}
|
||||||
|
//update-end-author:taoyan date:20220427 for: issues/I53J5E post请求X_SIGN签名拦截校验后报错, request body 为空
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue