v3.9.0 里程碑版本发布

This commit is contained in:
JEECG
2025-11-26 11:14:47 +08:00
parent 1a923596db
commit 9571e0b169
272 changed files with 6596 additions and 105398 deletions

View File

@ -56,7 +56,7 @@ public class DictTableWhiteListHandlerImpl implements IDictTableWhiteListHandler
// 如果map为空则从数据库中查询
if (DictTableWhiteListHandlerImpl.whiteTablesRuleMap.isEmpty()) {
Map<String, String> ruleMap = sysTableWhiteListService.getAllConfigMap();
log.info("表字典白名单初始化完成:{}", ruleMap);
log.debug("表字典白名单初始化完成:{}", ruleMap);
DictTableWhiteListHandlerImpl.whiteTablesRuleMap.putAll(ruleMap);
}
}
@ -73,7 +73,7 @@ public class DictTableWhiteListHandlerImpl implements IDictTableWhiteListHandler
if (parsedMap == null) {
return true;
}
log.info("获取select sql信息 {} ", parsedMap);
log.debug("获取select sql信息 {} ", parsedMap);
// 遍历当前sql中的所有表名如果有其中一个表或表的字段不在白名单中则不通过
for (Map.Entry<String, SelectSqlInfo> entry : parsedMap.entrySet()) {
SelectSqlInfo sqlInfo = entry.getValue();
@ -124,7 +124,7 @@ public class DictTableWhiteListHandlerImpl implements IDictTableWhiteListHandler
fields = new String[]{"*"};
}
String sql = "select " + String.join(",", fields) + " from " + tableName;
log.info("字典拼接的查询SQL{}", sql);
log.debug("字典拼接的查询SQL{}", sql);
try {
// 进行SQL解析
MiniDaoUtil.parseSelectSqlInfo(sql);
@ -153,7 +153,7 @@ public class DictTableWhiteListHandlerImpl implements IDictTableWhiteListHandler
// 统一转成小写
tableName = tableName.toLowerCase();
String allowFieldStr = DictTableWhiteListHandlerImpl.whiteTablesRuleMap.get(tableName);
log.info("checkWhiteList tableName: {}", tableName);
log.debug("checkWhiteList tableName: {}", tableName);
if (oConvertUtils.isEmpty(allowFieldStr)) {
// 如果是dev模式自动向数据库里添加数据
if (this.isDev()) {
@ -192,7 +192,7 @@ public class DictTableWhiteListHandlerImpl implements IDictTableWhiteListHandler
if (!waitMergerFields.isEmpty()) {
this.autoAddWhiteList(tableName, String.join(",", waitMergerFields));
}
log.info("白名单校验:查询表\"{}\",查询字段 {} 通过校验", tableName, queryFields);
log.debug("白名单校验:查询表\"{}\",查询字段 {} 通过校验", tableName, queryFields);
return true;
}

View File

@ -205,10 +205,10 @@ public class JeecgBizToolsProvider implements JeecgToolsProvider {
qw.like("role_code", sysRole.getRoleCode());
}
// 未删除
List<SysRole> roles = sysRoleService.list(qw);
List<org.jeecg.modules.system.entity.SysRole> roles = sysRoleService.list(qw);
// 仅返回核心字段
JSONArray arr = new JSONArray();
for (SysRole r : roles) {
for (org.jeecg.modules.system.entity.SysRole r : roles) {
JSONObject o = new JSONObject();
o.put("id", r.getId());
o.put("roleName", r.getRoleName());
@ -242,10 +242,10 @@ public class JeecgBizToolsProvider implements JeecgToolsProvider {
JSONObject args = JSONObject.parseObject(toolExecutionRequest.arguments());
String userId = args.getString("userId");
String roleIdsStr = args.getString("roleIds");
if (StringUtils.isAnyBlank(userId, roleIdsStr)) {
if (org.apache.commons.lang3.StringUtils.isAnyBlank(userId, roleIdsStr)) {
return "参数缺失userId 或 roleIds";
}
SysUser user = sysUserService.getById(userId);
org.jeecg.modules.system.entity.SysUser user = sysUserService.getById(userId);
if (user == null) {
return "用户不存在:" + userId;
}
@ -254,9 +254,9 @@ public class JeecgBizToolsProvider implements JeecgToolsProvider {
for (String roleId : roleIds) {
roleId = roleId.trim();
if (roleId.isEmpty()) continue;
SysRole role = sysRoleService.getById(roleId);
org.jeecg.modules.system.entity.SysRole role = sysRoleService.getById(roleId);
if (role == null) { invalid++; continue; }
QueryWrapper<org.jeecg.modules.system.entity.SysUserRole> q = new QueryWrapper<>();
com.baomidou.mybatisplus.core.conditions.query.QueryWrapper<org.jeecg.modules.system.entity.SysUserRole> q = new com.baomidou.mybatisplus.core.conditions.query.QueryWrapper<>();
q.eq("role_id", roleId).eq("user_id", userId);
org.jeecg.modules.system.entity.SysUserRole one = sysUserRoleService.getOne(q);
if (one == null) {

View File

@ -5,6 +5,7 @@ import lombok.extern.slf4j.Slf4j;
import org.jeecg.common.api.dto.AiragFlowDTO;
import org.jeecg.common.api.dto.DataLogDTO;
import org.jeecg.common.api.dto.OnlineAuthDTO;
import org.jeecg.common.api.dto.PushMessageDTO;
import org.jeecg.common.api.dto.message.*;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.constant.enums.DySmsEnum;
@ -764,7 +765,6 @@ public class SystemApiController {
}
//update-begin---author:chenrui ---date:20231221 for[issues/#5643]解决分布式下表字典跨库无法查询问题------------
/**
* 【接口签名验证】
* 49 字典表的 翻译,可批量
@ -780,7 +780,6 @@ public class SystemApiController {
public List<DictModel> translateDictFromTableByKeys(@RequestParam("table") String table, @RequestParam("text") String text, @RequestParam("code") String code, @RequestParam("keys") String keys, @RequestParam("ds") String ds) {
return this.sysBaseApi.translateDictFromTableByKeys(table, text, code, keys, ds);
}
//update-end---author:chenrui ---date:20231221 for[issues/#5643]解决分布式下表字典跨库无法查询问题------------
/**
* 发送模板信息
@ -933,6 +932,16 @@ public class SystemApiController {
return sysBaseApi.queryUserIdsByDeptIds(deptIds);
}
/**
* 根据部门岗位ID查询用户ID
* @param deptPostIds
* @return
*/
@GetMapping("/queryUserIdsByDeptPostIds")
public List<String> queryUserIdsByDeptPostIds(@RequestParam("deptPostIds") List<String> deptPostIds){
return sysBaseApi.queryUserIdsByDeptPostIds(deptPostIds);
}
/**
* 根据部门ID查询用户ID
* @param deptIds
@ -953,6 +962,26 @@ public class SystemApiController {
return sysBaseApi.queryUserIdsByRoleds(roleCodes);
}
/**
* 根据用户ID查询用户名
* @param userIds
* @return
*/
@GetMapping("/queryUsernameByIds")
public List<String> queryUsernameByIds(@RequestParam("userIds") List<String> userIds){
return sysBaseApi.queryUsernameByIds(userIds);
}
/**
* 根据岗位的职级ID查询用户ID
* @param departPositIds
* @return
*/
@GetMapping("/queryUsernameByDepartPositIds")
public List<String> queryUsernameByDepartPositIds(@RequestParam("departPositIds") List<String> departPositIds){
return sysBaseApi.queryUsernameByDepartPositIds(departPositIds);
}
/**
* 根据职务ID查询用户ID
* @param positionIds
@ -1072,4 +1101,13 @@ public class SystemApiController {
public List<String> queryUserIdsByCascadeDeptIds(@RequestParam("deptIds") List<String> deptIds){
return sysBaseApi.queryUserIdsByCascadeDeptIds(deptIds);
}
/**
* 推送uniapp 消息
* @param pushMessageDTO
* @return
*/
@PostMapping("/uniPushMsgToUser")
public void uniPushMsgToUser(@RequestBody PushMessageDTO pushMessageDTO){
sysBaseApi.uniPushMsgToUser(pushMessageDTO);
}
}

View File

@ -78,7 +78,7 @@ public class CasClientController {
if(!result.isSuccess()) {
return result;
}
String token = JwtUtil.sign(sysUser.getUsername(), sysUser.getPassword());
String token = JwtUtil.sign(sysUser.getUsername(), sysUser.getPassword(), CommonConstant.CLIENT_TYPE_PC);
// 设置超时时间
redisUtil.set(CommonConstant.PREFIX_USER_TOKEN + token, token);
redisUtil.expire(CommonConstant.PREFIX_USER_TOKEN + token, JwtUtil.EXPIRE_TIME*2 / 1000);

View File

@ -292,12 +292,12 @@ public final class XmlUtils {
"</cas:serviceResponse>";
String error = XmlUtils.getTextForElement(errorRes, "authenticationFailure");
System.out.println("------"+error);
//System.out.println("------"+error);
String error2 = XmlUtils.getTextForElement(result, "authenticationFailure");
System.out.println("------"+error2);
//System.out.println("------"+error2);
String principal = XmlUtils.getTextForElement(result, "user");
System.out.println("---principal---"+principal);
//System.out.println("---principal---"+principal);
Map<String, Object> attributes = XmlUtils.extractCustomAttributes(result);
System.out.println("---attributes---"+attributes);
}

View File

@ -68,12 +68,11 @@ public class EmailSendMsgHandle implements ISendMsgHandle {
public void sendMsg(String esReceiver, String esTitle, String esContent) {
JavaMailSender mailSender = (JavaMailSender) SpringContextUtils.getBean("mailSender");
MimeMessage message = mailSender.createMimeMessage();
//update-begin-authortaoyan date:20200811 for:配置类数据获取
// 代码逻辑说明: 配置类数据获取
if(oConvertUtils.isEmpty(emailFrom)){
StaticConfig staticConfig = SpringContextUtils.getBean(StaticConfig.class);
setEmailFrom(staticConfig.getEmailFrom());
}
//update-end-authortaoyan date:20200811 for:配置类数据获取
cachedThreadPool.execute(()->{
try {
log.info("============> 开始邮件发送,接收人:"+esReceiver);
@ -95,12 +94,11 @@ public class EmailSendMsgHandle implements ISendMsgHandle {
public void sendMessage(MessageDTO messageDTO) {
String content = messageDTO.getContent();
String title = messageDTO.getTitle();
//update-begin---author:wangshuai---date:2024-11-20---for:【QQYUN-8523】敲敲云发邮件通知不稳定---
// 代码逻辑说明: 【QQYUN-8523】敲敲云发邮件通知不稳定---
boolean timeJobSendEmail = this.isTimeJobSendEmail(messageDTO.getToUser(), title, content);
if(timeJobSendEmail){
return;
}
//update-end---author:wangshuai---date:2024-11-20---for:【QQYUN-8523】敲敲云发邮件通知不稳定---
this.sendEmailMessage(messageDTO);
}
@ -125,7 +123,7 @@ public class EmailSendMsgHandle implements ISendMsgHandle {
sendMsg(email, title, content);
}
//update-begin-author:taoyan date:2023-6-20 for: QQYUN-5557【简流】通知节点 发送邮箱 表单上有一个邮箱字段,流程中,邮件发送节点,邮件接收人 不可选择邮箱
// 代码逻辑说明: QQYUN-5557【简流】通知节点 发送邮箱 表单上有一个邮箱字段,流程中,邮件发送节点,邮件接收人 不可选择邮箱
Set<String> toEmailList = messageDTO.getToEmailList();
if(toEmailList!=null && toEmailList.size()>0){
for(String email: toEmailList){
@ -136,7 +134,6 @@ public class EmailSendMsgHandle implements ISendMsgHandle {
sendMsg(email, title, content);
}
}
//update-end-author:taoyan date:2023-6-20 for: QQYUN-5557【简流】通知节点 发送邮箱 表单上有一个邮箱字段,流程中,邮件发送节点,邮件接收人 不可选择邮箱
//发送给抄送人
sendMessageToCopyUser(messageDTO);
@ -162,7 +159,7 @@ public class EmailSendMsgHandle implements ISendMsgHandle {
content=replaceContent(user,content);
log.info("邮件内容:" + content);
//update-begin-author:taoyan date:2023-6-20 for: QQYUN-5557【简流】通知节点 发送邮箱 表单上有一个邮箱字段,流程中,邮件发送节点,邮件接收人 不可选择邮箱
// 代码逻辑说明: QQYUN-5557【简流】通知节点 发送邮箱 表单上有一个邮箱字段,流程中,邮件发送节点,邮件接收人 不可选择邮箱
sendEmail(email, content, title);
}
@ -210,7 +207,6 @@ public class EmailSendMsgHandle implements ISendMsgHandle {
}
});
}
//update-end-author:taoyan date:2023-6-20 for: QQYUN-5557【简流】通知节点 发送邮箱 表单上有一个邮箱字段,流程中,邮件发送节点,邮件接收人 不可选择邮箱
/**
@ -241,7 +237,7 @@ public class EmailSendMsgHandle implements ISendMsgHandle {
*/
private String getToken(SysUser user) {
// 生成token
String token = JwtUtil.sign(user.getUsername(), user.getPassword());
String token = JwtUtil.sign(user.getUsername(), user.getPassword(), CommonConstant.CLIENT_TYPE_PC);
redisUtil.set(CommonConstant.PREFIX_USER_TOKEN + token, token);
// 设置超时时间 1个小时
redisUtil.expire(CommonConstant.PREFIX_USER_TOKEN + token, JwtUtil.EXPIRE_TIME * 1 / 1000);

View File

@ -75,9 +75,8 @@ public class SystemSendMsgHandle implements ISendMsgHandle {
Map<String,Object> data = messageDTO.getData();
String[] arr = messageDTO.getToUser().split(",");
for(String username: arr){
//update-begin---author:wangshuai---date:2025-06-26---for:【QQYUN-12162】OA项目改造系统重消息拆分目前消息都在一起 需按分类进行拆分---
// 代码逻辑说明: 【QQYUN-12162】OA项目改造系统重消息拆分目前消息都在一起 需按分类进行拆分---
doSend(title, content, fromUser, username, data, messageDTO.getNoticeType());
//update-end---author:wangshuai---date:2025-06-26---for:【QQYUN-12162】OA项目改造系统重消息拆分目前消息都在一起 需按分类进行拆分---
}
}

View File

@ -42,7 +42,7 @@ public class SendMsgJob implements Job {
System.out.println(sysMessages);
// 2.根据不同的类型走不通的发送实现类
for (SysMessage sysMessage : sysMessages) {
//update-begin-author:taoyan date:2022-7-8 for: 模板消息发送测试调用方法修改
// 代码逻辑说明: 模板消息发送测试调用方法修改
Integer sendNum = sysMessage.getEsSendNum();
try {
MessageDTO md = new MessageDTO();
@ -51,13 +51,11 @@ public class SendMsgJob implements Job {
md.setToUser(sysMessage.getEsReceiver());
md.setType(sysMessage.getEsType());
md.setToAll(false);
//update-begin---author:wangshuai---date:2024-11-12---for:【QQYUN-8523】敲敲云发邮件通知不稳定---
// 代码逻辑说明: 【QQYUN-8523】敲敲云发邮件通知不稳定---
md.setIsTimeJob(true);
//update-end---author:wangshuai---date:2024-11-12---for:【QQYUN-8523】敲敲云发邮件通知不稳定---
sysBaseAPI.sendTemplateMessage(md);
//发送消息成功
sysMessage.setEsSendStatus(SendMsgStatusEnum.SUCCESS.getCode());
//update-end-author:taoyan date:2022-7-8 for: 模板消息发送测试调用方法修改
} catch (Exception e) {
e.printStackTrace();
// 发送消息出现异常

View File

@ -73,12 +73,11 @@ public class WebSocket {
if (item.getKey().contains(userId)) {
Session session = item.getValue();
try {
//update-begin-author:taoyan date:20211012 for: websocket报错 https://gitee.com/jeecg/jeecg-boot/issues/I4C0MU
// 代码逻辑说明: websocket报错 https://gitee.com/jeecg/jeecg-boot/issues/I4C0MU
synchronized (session){
log.debug("【系统 WebSocket】推送单人消息:" + message);
session.getBasicRemote().sendText(message);
}
//update-end-author:taoyan date:20211012 for: websocket报错 https://gitee.com/jeecg/jeecg-boot/issues/I4C0MU
} catch (Exception e) {
log.error(e.getMessage(),e);
}
@ -114,9 +113,8 @@ public class WebSocket {
log.debug("【系统 WebSocket】收到客户端消息:" + message);
}else{
log.debug("【系统 WebSocket】收到客户端消息:" + message);
//update-begin---author:wangshuai---date:2024-05-07---for:【issues/1161】前端websocket因心跳导致监听不起作用---
// 代码逻辑说明: 【issues/1161】前端websocket因心跳导致监听不起作用---
this.sendMessage(userId, "ping");
//update-end---author:wangshuai---date:2024-05-07---for:【issues/1161】前端websocket因心跳导致监听不起作用---
}
// //------------------------------------------------------------------------------

View File

@ -36,7 +36,7 @@ public class ActuatorMemoryController {
result.put("memory.runtime.max", runtime.totalMemory() - runtime.freeMemory());
result.put("memory.runtime.free", runtime.maxMemory() - runtime.totalMemory() + runtime.freeMemory());
result.put("memory.runtime.usage", NumberUtil.div(runtime.totalMemory() - runtime.freeMemory(), runtime.totalMemory()));
//update-begin---author:chenrui ---date:20240705 for[TV360X-1695]内存信息-立即更新 功能报错 #6635------------
// 代码逻辑说明: [TV360X-1695]内存信息-立即更新 功能报错 #6635------------
OperatingSystemMXBean operatingSystemMXBean = ManagementFactory.getOperatingSystemMXBean();
if (operatingSystemMXBean instanceof com.sun.management.OperatingSystemMXBean) {
com.sun.management.OperatingSystemMXBean opBean = (com.sun.management.OperatingSystemMXBean) operatingSystemMXBean;
@ -49,7 +49,6 @@ public class ActuatorMemoryController {
result.put("memory.physical.free", usedPhysicalMemory);
result.put("memory.physical.usage", NumberUtil.div(usedPhysicalMemory, totalPhysicalMemory));
}
//update-end---author:chenrui ---date:20240705 for[TV360X-1695]内存信息-立即更新 功能报错 #6635------------
return Result.ok(result);
}

View File

@ -43,7 +43,6 @@ public class ActuatorRedisController {
return Result.ok(infoList);
}
//update-begin---author:chenrui ---date:20240514 for[QQYUN-9247]系统监控功能优化------------
/**
* Redis历史性能指标查询(过去一小时)
* @return
@ -56,7 +55,6 @@ public class ActuatorRedisController {
Map<String,List<Map<String,Object>>> metricsHistory = this.redisService.getMetricsHistory();
return Result.OK(metricsHistory);
}
//update-end---author:chenrui ---date:20240514 for[QQYUN-9247]系统监控功能优化------------
@GetMapping("/keysSize")
public Map<String, Object> getKeysSize() throws Exception {
@ -97,7 +95,6 @@ public class ActuatorRedisController {
return redisService.getMemoryInfo();
}
//update-begin--Author:zhangweijian Date:20190425 for获取磁盘信息
/**
* @功能:获取磁盘信息
* @param request
@ -134,5 +131,4 @@ public class ActuatorRedisController {
}
return res;
}
//update-end--Author:zhangweijian Date:20190425 for获取磁盘信息
}

View File

@ -128,7 +128,6 @@ public class RedisServiceImpl implements RedisService {
return mapJson;
}
//update-begin---author:chenrui ---date:20240514 for[QQYUN-9247]系统监控功能优化------------
/**
* 获取历史性能指标
* @return
@ -170,5 +169,4 @@ public class RedisServiceImpl implements RedisService {
}
list.add(getMemoryInfo());
}
//update-end---author:chenrui ---date:20240514 for[QQYUN-9247]系统监控功能优化------------
}

View File

@ -207,7 +207,7 @@ public class OpenApiController extends JeecgController<OpenApi, OpenApiService>
* @return
*/
private String getToken(String USERNAME, String PASSWORD) {
String token = JwtUtil.sign(USERNAME, PASSWORD);
String token = JwtUtil.sign(USERNAME, PASSWORD, CommonConstant.CLIENT_TYPE_PC);
redisUtil.set(CommonConstant.PREFIX_USER_TOKEN + token, token);
redisUtil.expire(CommonConstant.PREFIX_USER_TOKEN + token, 60);
return token;
@ -382,7 +382,7 @@ public class OpenApiController extends JeecgController<OpenApi, OpenApiService>
SwaggerInfo info = new SwaggerInfo();
info.setDescription("OpenAPI 接口列表");
info.setVersion("3.8.3");
info.setVersion("3.9.0");
info.setTitle("OpenAPI 接口列表");
info.setTermsOfService("https://jeecg.com");

View File

@ -30,10 +30,8 @@ public class OssFileServiceImpl extends ServiceImpl<OssFileMapper, OssFile> impl
if(oConvertUtils.isEmpty(url)){
throw new JeecgBootException("上传文件失败! ");
}
//update-begin--Author:scott Date:20201227 forJT-361【文件预览】阿里云原生域名可以文件预览自己映射域名kkfileview提示文件下载失败-------------------
// 返回阿里云原生域名前缀URL
ossFile.setUrl(OssBootUtil.getOriginalUrl(url));
//update-end--Author:scott Date:20201227 forJT-361【文件预览】阿里云原生域名可以文件预览自己映射域名kkfileview提示文件下载失败-------------------
this.save(ossFile);
}

View File

@ -220,10 +220,8 @@ public class QuartzJobController {
mv.addObject(NormalExcelConstants.FILE_NAME, "定时任务列表");
mv.addObject(NormalExcelConstants.CLASS, QuartzJob.class);
//获取当前登录用户
//update-begin---author:wangshuai ---date:20211227 for[JTC-116]导出人写死了------------
LoginUser user = (LoginUser) SecurityUtils.getSubject().getPrincipal();
mv.addObject(NormalExcelConstants.PARAMS, new ExportParams("定时任务列表数据", "导出人:"+user.getRealname(), "导出信息"));
//update-end---author:wangshuai ---date:20211227 for[JTC-116]导出人写死了------------
mv.addObject(NormalExcelConstants.DATA_LIST, pageList);
return mv;
}

View File

@ -104,9 +104,8 @@ public class QuartzJobServiceImpl extends ServiceImpl<QuartzJobMapper, QuartzJob
String ymd = DateUtils.date2Str(startDate,DateUtils.yyyymmddhhmmss.get());
String identity = jobName + ymd;
//3秒后执行 只执行一次
// update-begin--author:sunjianlei ---- date:20210511--- for定时任务立即执行延迟3秒改成0.1秒-------
// 代码逻辑说明: 定时任务立即执行延迟3秒改成0.1秒-------
startDate.setTime(startDate.getTime() + 100L);
// update-end--author:sunjianlei ---- date:20210511--- for定时任务立即执行延迟3秒改成0.1秒-------
// 定义一个Trigger
SimpleTrigger trigger = (SimpleTrigger)TriggerBuilder.newTrigger()
.withIdentity(identity, JOB_TEST_GROUP)

View File

@ -1,26 +1,29 @@
package org.jeecg.modules.system.controller;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.constant.CommonConstant;
import org.jeecg.common.constant.SymbolConstant;
import org.jeecg.common.constant.enums.FileTypeEnum;
import org.jeecg.common.exception.JeecgBootException;
import org.jeecg.common.util.CommonUtils;
import org.jeecg.common.util.filter.SsrfFileTypeFilter;
import org.jeecg.common.util.oConvertUtils;
import org.jeecg.modules.system.util.HttpFileToMultipartFileUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Lazy;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.FileCopyUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import org.springframework.web.servlet.HandlerMapping;
import org.springframework.web.servlet.ModelAndView;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.*;
/**
@ -80,6 +83,13 @@ public class CommonController {
savePath = CommonUtils.upload(file, bizPath, uploadType);
}
if(oConvertUtils.isNotEmpty(savePath)){
//添加到文件表
String orgName = file.getOriginalFilename();
// 获取文件名
orgName = CommonUtils.getFileName(orgName);
String type = orgName.substring(orgName.lastIndexOf(SymbolConstant.SPOT));
FileTypeEnum fileType = FileTypeEnum.getByType(type);
result.setMessage(savePath);
result.setSuccess(true);
}else {
@ -188,9 +198,8 @@ public class CommonController {
if (imgPath.endsWith(SymbolConstant.COMMA)) {
imgPath = imgPath.substring(0, imgPath.length() - 1);
}
//update-begin---author:liusq ---date:20230912 for检查下载文件类型--------------
// 代码逻辑说明: 检查下载文件类型--------------
SsrfFileTypeFilter.checkDownloadFileType(imgPath);
//update-end---author:liusq ---date:20230912 for检查下载文件类型--------------
String filePath = uploadpath + File.separator + imgPath;
File file = new File(filePath);
@ -303,4 +312,35 @@ public class CommonController {
return new AntPathMatcher().extractPathWithinPattern(bestMatchPattern, path);
}
/**
* 根据网路图片地址上传到服务器
* @param jsonObject
* @param request
* @return
*/
@PostMapping("/uploadImgByHttp")
public Result<String> uploadImgByHttp(@RequestBody JSONObject jsonObject, HttpServletRequest request){
String fileUrl = oConvertUtils.getString(jsonObject.get("fileUrl"));
String filename = oConvertUtils.getString(jsonObject.get("filename"));
String bizPath = oConvertUtils.getString(jsonObject.get("bizPath"));
try {
String savePath = "";
MultipartFile file = HttpFileToMultipartFileUtil.httpFileToMultipartFile(fileUrl, filename);
// 文件安全校验,防止上传漏洞文件
SsrfFileTypeFilter.checkUploadFileType(file, bizPath);
if (oConvertUtils.isEmpty(bizPath)) {
bizPath = CommonConstant.UPLOAD_TYPE_OSS.equals(uploadType) ? "upload" : "";
}
if(CommonConstant.UPLOAD_TYPE_LOCAL.equals(uploadType)){
savePath = this.uploadLocal(file,bizPath);
}else{
savePath = CommonUtils.upload(file, bizPath, uploadType);
}
return Result.OK(savePath);
} catch (Exception e) {
log.error(e.getMessage(), e);
return Result.error(e.getMessage());
}
}
}

View File

@ -5,8 +5,11 @@ import com.alibaba.fastjson.JSONObject;
import com.aliyuncs.exceptions.ClientException;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import io.swagger.v3.oas.annotations.tags.Tag;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authz.annotation.RequiresRoles;
@ -18,12 +21,13 @@ import org.jeecg.common.constant.enums.DySmsEnum;
import org.jeecg.common.system.util.JwtUtil;
import org.jeecg.common.system.vo.LoginUser;
import org.jeecg.common.util.*;
import org.jeecg.common.util.encryption.AesEncryptUtil;
import org.jeecg.common.util.encryption.EncryptedString;
import org.jeecg.config.JeecgBaseConfig;
import org.jeecg.config.shiro.IgnoreAuth;
import org.jeecg.modules.base.service.BaseCommonService;
import org.jeecg.modules.system.entity.SysDepart;
import org.jeecg.modules.system.entity.SysRoleIndex;
import org.jeecg.modules.system.entity.SysTenant;
import org.jeecg.modules.system.entity.SysUser;
import org.jeecg.modules.system.model.SysLoginModel;
import org.jeecg.modules.system.service.*;
@ -31,18 +35,13 @@ import org.jeecg.modules.system.service.impl.SysBaseApiImpl;
import org.jeecg.modules.system.util.RandImageUtil;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.task.AsyncTaskExecutor;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.*;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
/**
* @Author scott
@ -71,45 +70,36 @@ public class LoginController {
private BaseCommonService baseCommonService;
@Autowired
private JeecgBaseConfig jeecgBaseConfig;
private final String BASE_CHECK_CODES = "qwertyuiplkjhgfdsazxcvbnmQWERTYUPLKJHGFDSAZXCVBNM1234567890";
/**
* 线程池用于异步发送纪要
*/
public static ExecutorService cachedThreadPool = new ShiroThreadPoolExecutor(0, 1024, 60L, TimeUnit.SECONDS, new SynchronousQueue<>());
@Operation(summary="登录接口")
@RequestMapping(value = "/login", method = RequestMethod.POST)
public Result<JSONObject> login(@RequestBody SysLoginModel sysLoginModel, HttpServletRequest request){
Result<JSONObject> result = new Result<JSONObject>();
Result<JSONObject> result = new Result<>();
String username = sysLoginModel.getUsername();
String password = sysLoginModel.getPassword();
// 密码加密传输(尝试 AES解密失败视为明文)
String password = AesEncryptUtil.resolvePassword(sysLoginModel.getPassword());
log.debug("登录密码,原始密码:{},解密密码:{}" , sysLoginModel.getPassword(), password);
//step.1 登录失败超出次数5次锁定用户10分钟
if(isLoginFailOvertimes(username)){
return result.error500("该用户登录失败次数过多请于10分钟后再次登录");
}
// step.1 验证码check
String captcha = sysLoginModel.getCaptcha();
if(captcha==null){
result.error500("验证码无效");
// step.2 验证码check
String realKey = validateCaptcha(sysLoginModel, result);
if (realKey == null) {
return result;
}
String lowerCaseCaptcha = captcha.toLowerCase();
// 加入密钥作为混淆,避免简单的拼接,被外部利用,用户自定义该密钥即可
//update-begin---author:chenrui ---date:20250107 for[QQYUN-10775]验证码可以复用 #7674------------
String keyPrefix = Md5Util.md5Encode(sysLoginModel.getCheckKey()+jeecgBaseConfig.getSignatureSecret(), "utf-8");
String realKey = keyPrefix + lowerCaseCaptcha;
//update-end---author:chenrui ---date:20250107 for[QQYUN-10775]验证码可以复用 #7674------------
Object checkCode = redisUtil.get(realKey);
//当进入登录页时,有一定几率出现验证码错误 #1714
if(checkCode==null || !checkCode.toString().equals(lowerCaseCaptcha)) {
log.warn("验证码错误key= {} , Ui checkCode= {}, Redis checkCode = {}", sysLoginModel.getCheckKey(), lowerCaseCaptcha, checkCode);
result.error500("验证码错误");
// 改成特殊的code 便于前端判断
result.setCode(HttpStatus.PRECONDITION_FAILED.value());
return result;
}
// step.2 校验用户是否存在且有效
// step.3 校验用户是否存在且有效
LambdaQueryWrapper<SysUser> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(SysUser::getUsername,username);
SysUser sysUser = sysUserService.getOne(queryWrapper);
@ -118,7 +108,7 @@ public class LoginController {
return result;
}
// step.3 校验用户名或密码是否正确
// step.4 校验用户名或密码是否正确
String userpassword = PasswordUtil.encrypt(username, password, sysUser.getSalt());
String syspassword = sysUser.getPassword();
if (!syspassword.equals(userpassword)) {
@ -127,14 +117,16 @@ public class LoginController {
return result;
}
// step.4 登录成功获取用户信息
userInfo(sysUser, result, request);
// step.5 登录成功获取用户信息
String loginOrgCode = sysLoginModel.getLoginOrgCode();
sysUser.setLoginOrgCode(loginOrgCode);
userInfo(sysUser, result, request, CommonConstant.CLIENT_TYPE_PC);
// step.5 登录成功删除验证码
// step.6 登录成功删除验证码
redisUtil.del(realKey);
redisUtil.del(CommonConstant.LOGIN_FAIL + username);
// step.6 记录用户登录日志
// step.7 记录用户登录日志
LoginUser loginUser = new LoginUser();
BeanUtils.copyProperties(sysUser, loginUser);
baseCommonService.addLog("用户名: " + username + ",登录成功!", CommonConstant.LOG_TYPE_1, null,loginUser);
@ -154,11 +146,10 @@ public class LoginController {
// 根据用户名查询用户信息
SysUser sysUser = sysUserService.getUserByName(username);
JSONObject obj=new JSONObject();
log.info("1 获取用户信息耗时(用户基础信息)" + (System.currentTimeMillis() - start) + "毫秒");
log.debug("1 获取用户信息耗时(用户基础信息)" + (System.currentTimeMillis() - start) + "毫秒");
//update-begin---author:scott ---date:2022-06-20 forvue3前端支持自定义首页-----------
// 代码逻辑说明: vue3前端支持自定义首页-----------
String vue3Version = request.getHeader(CommonConstant.VERSION);
//update-begin---author:liusq ---date:2022-06-29 for接口返回值修改同步修改这里的判断逻辑-----------
SysRoleIndex roleIndex = sysUserService.getDynamicIndexByUserRole(username, vue3Version);
if (oConvertUtils.isNotEmpty(vue3Version) && roleIndex != null && oConvertUtils.isNotEmpty(roleIndex.getUrl())) {
String homePath = roleIndex.getUrl();
@ -167,18 +158,16 @@ public class LoginController {
}
sysUser.setHomePath(homePath);
}
//update-begin---author:liusq ---date:2022-06-29 for接口返回值修改同步修改这里的判断逻辑-----------
//update-end---author:scott ---date::2022-06-20 forvue3前端支持自定义首页--------------
log.info("2 获取用户信息耗时 (首页面配置)" + (System.currentTimeMillis() - start) + "毫秒");
log.debug("2 获取用户信息耗时 (首页面配置)" + (System.currentTimeMillis() - start) + "毫秒");
obj.put("userInfo",sysUser);
obj.put("sysAllDictItems", sysDictService.queryAllDictItems());
log.info("3 获取用户信息耗时 (字典数据)" + (System.currentTimeMillis() - start) + "毫秒");
log.debug("3 获取用户信息耗时 (字典数据)" + (System.currentTimeMillis() - start) + "毫秒");
result.setResult(obj);
result.success("");
}
log.info("end 获取用户信息耗时 " + (System.currentTimeMillis() - start) + "毫秒");
log.debug("end 获取用户信息耗时 " + (System.currentTimeMillis() - start) + "毫秒");
return result;
}
@ -209,7 +198,7 @@ public class LoginController {
/**
* 清理用户缓存
*
*
* @param token
* @param sysUser
*/
@ -221,12 +210,15 @@ public class LoginController {
redisUtil.del(CommonConstant.PREFIX_USER_SHIRO_CACHE + sysUser.getId());
//清空用户的缓存信息包括部门信息例如sys:cache:user::<username>
redisUtil.del(String.format("%s::%s", CacheConstant.SYS_USERS_CACHE, sysUser.getUsername()));
//清空是否允许同一账号多地同时登录缓存PC端和APP端
redisUtil.del(CommonConstant.PREFIX_USER_TOKEN_PC + sysUser.getUsername());
redisUtil.del(CommonConstant.PREFIX_USER_TOKEN_APP + sysUser.getUsername());
redisUtil.del(CommonConstant.PREFIX_USER_TOKEN_PHONE + sysUser.getUsername());
baseCommonService.addLog("用户名: "+sysUser.getRealname()+",退出成功!", CommonConstant.LOG_TYPE_1, null, sysUser);
log.info("【退出成功操作】异步处理,退出后,清理用户缓存: "+sysUser.getRealname());
log.debug("【退出成功操作】异步处理,退出后,清理用户缓存: "+sysUser.getRealname());
});
}
/**
* 获取访问量
* @return
@ -235,7 +227,6 @@ public class LoginController {
public Result<JSONObject> loginfo() {
Result<JSONObject> result = new Result<JSONObject>();
JSONObject obj = new JSONObject();
//update-begin--Author:zhangweijian Date:20190428 for传入开始时间结束时间参数
// 获取一天的开始和结束时间
Calendar calendar = new GregorianCalendar();
calendar.set(Calendar.HOUR_OF_DAY, 0);
@ -251,7 +242,6 @@ public class LoginController {
Long todayVisitCount = logService.findTodayVisitCount(dayStart,dayEnd);
obj.put("todayVisitCount", todayVisitCount);
Long todayIp = logService.findTodayIp(dayStart,dayEnd);
//update-end--Author:zhangweijian Date:20190428 for传入开始时间结束时间参数
obj.put("todayIp", todayIp);
result.setResult(obj);
result.success("登录成功");
@ -328,10 +318,9 @@ public class LoginController {
return result;
}
//update-begin-author:taoyan date:2022-9-13 for: VUEN-2245 【漏洞】发现新漏洞待处理20220906
// VUEN-2245【漏洞】发现新漏洞待处理20220906
String redisKey = CommonConstant.PHONE_REDIS_KEY_PRE+mobile;
Object object = redisUtil.get(redisKey);
//update-end-author:taoyan date:2022-9-13 for: VUEN-2245 【漏洞】发现新漏洞待处理20220906
if (object != null) {
result.setMessage("验证码10分钟内仍然有效");
@ -387,7 +376,7 @@ public class LoginController {
} else if(CommonConstant.SMS_TPL_TYPE_2.equals(smsmode)) {
//忘记密码模板
b = DySmsHelper.sendSms(mobile, obj, DySmsEnum.FORGET_PASSWORD_TEMPLATE_CODE);
//update-begin---author:wangshuai---date:2025-07-15---for:【issues/8567】严重修改密码存在水平越权问题。---
// 代码逻辑说明: 【issues/8567】严重修改密码存在水平越权问题。---
if(b){
String username = sysUser.getUsername();
obj.put("username",username);
@ -395,7 +384,6 @@ public class LoginController {
result.setSuccess(true);
return result;
}
//update-end---author:wangshuai---date:2025-07-15---for:【issues/8567】严重修改密码存在水平越权问题。---
}
}
@ -405,14 +393,8 @@ public class LoginController {
return result;
}
//update-begin-author:taoyan date:2022-9-13 for: VUEN-2245 【漏洞】发现新漏洞待处理20220906
//验证码10分钟内有效
redisUtil.set(redisKey, captcha, 600);
//update-end-author:taoyan date:2022-9-13 for: VUEN-2245 【漏洞】发现新漏洞待处理20220906
//update-begin--Author:scott Date:20190812 forissues#391
//result.setResult(captcha);
//update-end--Author:scott Date:20190812 forissues#391
result.setSuccess(true);
} catch (ClientException e) {
@ -435,11 +417,11 @@ public class LoginController {
public Result<JSONObject> phoneLogin(@RequestBody JSONObject jsonObject, HttpServletRequest request) {
Result<JSONObject> result = new Result<JSONObject>();
String phone = jsonObject.getString("mobile");
//update-begin-author:taoyan date:2022-11-7 for: issues/4109 平台用户登录失败锁定用户
// 平台用户登录失败锁定用户
if(isLoginFailOvertimes(phone)){
return result.error500("该用户登录失败次数过多请于10分钟后再次登录");
}
//update-end-author:taoyan date:2022-11-7 for: issues/4109 平台用户登录失败锁定用户
//校验用户有效性
SysUser sysUser = sysUserService.getUserByPhone(phone);
result = sysUserService.checkUserIsEffective(sysUser);
@ -449,19 +431,18 @@ public class LoginController {
String smscode = jsonObject.getString("captcha");
//update-begin-author:taoyan date:2022-9-13 for: VUEN-2245 【漏洞】发现新漏洞待处理20220906
// 代码逻辑说明: VUEN-2245 【漏洞】发现新漏洞待处理20220906
String redisKey = CommonConstant.PHONE_REDIS_KEY_PRE+phone;
Object code = redisUtil.get(redisKey);
//update-end-author:taoyan date:2022-9-13 for: VUEN-2245 【漏洞】发现新漏洞待处理20220906
if (!smscode.equals(code)) {
//update-begin-author:taoyan date:2022-11-7 for: issues/4109 平台用户登录失败锁定用户
addLoginFailOvertimes(phone);
//update-end-author:taoyan date:2022-11-7 for: issues/4109 平台用户登录失败锁定用户
return Result.error("手机验证码错误");
}
//用户信息
userInfo(sysUser, result, request);
String loginOrgCode = jsonObject.getString("loginOrgCode");
sysUser.setLoginOrgCode(loginOrgCode);
userInfo(sysUser, result, request, CommonConstant.CLIENT_TYPE_PHONE);
//添加日志
baseCommonService.addLog("用户名: " + sysUser.getUsername() + ",登录成功!", CommonConstant.LOG_TYPE_1, null);
redisUtil.removeAll(redisKey);
@ -476,19 +457,24 @@ public class LoginController {
* @param result
* @return
*/
private Result<JSONObject> userInfo(SysUser sysUser, Result<JSONObject> result, HttpServletRequest request) {
private Result<JSONObject> userInfo(SysUser sysUser, Result<JSONObject> result, HttpServletRequest request, String clientType) {
String username = sysUser.getUsername();
String syspassword = sysUser.getPassword();
// 获取用户部门信息
JSONObject obj = new JSONObject(new LinkedHashMap<>());
//1.生成token
String token = JwtUtil.sign(username, syspassword);
// 设置token缓存有效时间
//1.生成token,并设置超时时间
String token = JwtUtil.sign(username, syspassword, clientType);
redisUtil.set(CommonConstant.PREFIX_USER_TOKEN + token, token);
redisUtil.expire(CommonConstant.PREFIX_USER_TOKEN + token, JwtUtil.EXPIRE_TIME * 2 / 1000);
// 根据客户端类型设置对应的过期时间
long expireTime = CommonConstant.CLIENT_TYPE_APP.equalsIgnoreCase(clientType)
? JwtUtil.APP_EXPIRE_TIME * 2 / 1000
: JwtUtil.EXPIRE_TIME * 2 / 1000;
redisUtil.expire(CommonConstant.PREFIX_USER_TOKEN + token, expireTime);
obj.put("token", token);
// 是否允许同一账号多地同时登录,踢掉之前的登录
handleSingleSignOn(username, token, clientType);
//2.设置登录租户
Result<JSONObject> loginTenantError = sysUserService.setLoginTenant(sysUser, obj, username,result);
if (loginTenantError != null) {
@ -503,33 +489,95 @@ public class LoginController {
obj.put("departs", departs);
if (departs == null || departs.size() == 0) {
obj.put("multi_depart", 0);
sysUserService.updateUserDepart(username, null, null);
} else if (departs.size() == 1) {
sysUserService.updateUserDepart(username, departs.get(0).getOrgCode(),null);
obj.put("multi_depart", 1);
} else {
//查询当前是否有登录部门
// update-begin--Author:wangshuai Date:20200805 for如果用戶为选择部门数据库为存在上一次登录部门则取一条存进去
SysUser sysUserById = sysUserService.getById(sysUser.getId());
if(oConvertUtils.isEmpty(sysUserById.getOrgCode())){
sysUserService.updateUserDepart(username, departs.get(0).getOrgCode(),null);
//【部门切换】支持登录页面选择部门
String loginOrgCode = sysUser.getLoginOrgCode();
// 判断上次登录部门orgCode是否在departs中
boolean orgCodeInDeparts = departs.stream().anyMatch(d -> sysUserById.getOrgCode() != null && sysUserById.getOrgCode().equalsIgnoreCase(d.getOrgCode()));
if (!orgCodeInDeparts) {
sysUserById.setOrgCode(null);
}
// 如果未设置登录部门,则将登录部门设置为用户选择的 loginOrgCode优先否则设置为默认的第一个部门
if(oConvertUtils.isEmpty(sysUserById.getOrgCode())){
String orgCode = oConvertUtils.isNotEmpty(loginOrgCode) ? loginOrgCode : departs.get(0).getOrgCode();
sysUserService.updateUserDepart(username, orgCode, null);
} else {
// 已设置登录部门,若用户本次登录选择了不同的部门,则优先使用用户选择的 loginOrgCode 更新登录部门
String orgCode = sysUserById.getOrgCode();
if(oConvertUtils.isNotEmpty(loginOrgCode) && !orgCode.equalsIgnoreCase(loginOrgCode)){
sysUserService.updateUserDepart(username, loginOrgCode, null);
}
}
// update-end--Author:wangshuai Date:20200805 for如果用戶为选择部门数据库为存在上一次登录部门则取一条存进去
obj.put("multi_depart", 2);
}
//update-begin---author:scott ---date:2024-01-05 for【QQYUN-7802】前端在登录时加载了两次数据字典建议优化下避免数据字典太多时可能产生的性能问题 #956---
// login接口在vue3前端下不加载字典数据vue2下加载字典
// 5.vue3版本不加载字典数据vue2下加载字典
String vue3Version = request.getHeader(CommonConstant.VERSION);
if(oConvertUtils.isEmpty(vue3Version)){
obj.put("sysAllDictItems", sysDictService.queryAllDictItems());
}
//end-begin---author:scott ---date:2024-01-05 for【QQYUN-7802】前端在登录时加载了两次数据字典建议优化下避免数据字典太多时可能产生的性能问题 #956---
result.setResult(obj);
result.success("登录成功");
return result;
}
/**
* 同一账号在同一客户端类型只能登录一次
*
* @author scott
* @date 2025-10-31
* PC端、APP端、手机号登录分别独立互不影响
*
* @param username 用户名
* @param newToken 新生成的token
* @param clientType 客户端类型PC、APP、PHONE
*/
private void handleSingleSignOn(String username, String newToken, String clientType) {
// 检查是否允许并发登录
if (jeecgBaseConfig.getFirewall() == null || jeecgBaseConfig.getFirewall().getIsConcurrent()==null || Boolean.TRUE.equals(jeecgBaseConfig.getFirewall().getIsConcurrent())) {
// 允许并发登录只设置当前用户的token缓存不踢掉之前的登录
log.debug("并发登录已启用:用户[{}]在{}端允许多地同时登录", username, clientType);
return;
}
log.info("【并发登录限制已开启】 用户[{}]在{}端不允许多地同时登录", username, clientType);
// 根据客户端类型选择对应的Redis key前缀
String redisKeyPrefix;
if (CommonConstant.CLIENT_TYPE_APP.equalsIgnoreCase(clientType)) {
redisKeyPrefix = CommonConstant.PREFIX_USER_TOKEN_APP;
} else if (CommonConstant.CLIENT_TYPE_PHONE.equalsIgnoreCase(clientType)) {
redisKeyPrefix = CommonConstant.PREFIX_USER_TOKEN_PHONE;
} else {
redisKeyPrefix = CommonConstant.PREFIX_USER_TOKEN_PC;
}
String userTokenKey = redisKeyPrefix + username;
// 获取该用户在当前客户端类型下之前的token
Object oldTokenObj = redisUtil.get(userTokenKey);
if (oldTokenObj != null && !oldTokenObj.equals(newToken)) {
String oldToken = oldTokenObj.toString();
// 清除旧登录token的缓存设置 1 小时过期时间)
redisUtil.del(CommonConstant.PREFIX_USER_TOKEN + oldToken);
redisUtil.set(CommonConstant.PREFIX_USER_TOKEN_ERROR_MSG + oldToken, "不允许同一账号多地同时登录,当前登录被踢掉!", 60 * 1 * 60);
log.info("【并发登录限制已开启】用户[{}]在{}端的旧登录已被踢下线!", username, clientType);
log.info("【并发登录限制已开启】用户被踢下线新token: {}旧token{}", newToken, oldToken);
}
// 保存新的token到单点登录缓存
redisUtil.set(userTokenKey, newToken);
redisUtil.expire(userTokenKey, JwtUtil.EXPIRE_TIME * 2 / 1000);
}
/**
* 获取加密字符串
* @return
@ -554,22 +602,14 @@ public class LoginController {
public Result<String> randomImage(HttpServletResponse response,@PathVariable("key") String key){
Result<String> res = new Result<String>();
try {
//生成验证码
//生成验证码存到redis中
String code = RandomUtil.randomString(BASE_CHECK_CODES,4);
//存到redis中
String lowerCaseCode = code.toLowerCase();
//update-begin-author:taoyan date:2022-9-13 for: VUEN-2245 【漏洞】发现新漏洞待处理20220906
// 加入密钥作为混淆,避免简单的拼接,被外部利用,用户自定义该密钥即可
//update-begin---author:chenrui ---date:20250107 for[QQYUN-10775]验证码可以复用 #7674------------
String keyPrefix = Md5Util.md5Encode(key+jeecgBaseConfig.getSignatureSecret(), "utf-8");
String keyPrefix = Md5Util.md5Encode(key + jeecgBaseConfig.getSignatureSecret(), "utf-8");
String realKey = keyPrefix + lowerCaseCode;
//update-end-author:taoyan date:2022-9-13 for: VUEN-2245 【漏洞】发现新漏洞待处理20220906
redisUtil.removeAll(keyPrefix);
//update-end---author:chenrui ---date:20250107 for[QQYUN-10775]验证码可以复用 #7674------------
redisUtil.set(realKey, lowerCaseCode, 60);
log.info("获取验证码Redis key = {}checkCode = {}", realKey, code);
//返回前端
log.debug("获取验证码Redis key = {}checkCode = {}", realKey, code);
String base64 = RandImageUtil.generate(code);
res.setSuccess(true);
res.setResult(base64);
@ -581,16 +621,16 @@ public class LoginController {
return res;
}
/**
* 切换菜单表为vue3的表
*/
@RequiresRoles({"admin"})
@GetMapping(value = "/switchVue3Menu")
public Result<String> switchVue3Menu(HttpServletResponse response) {
Result<String> res = new Result<String>();
sysPermissionService.switchVue3Menu();
return res;
}
// /**
// * 切换菜单表为vue3的表
// */
// @RequiresRoles({"admin"})
// @GetMapping(value = "/switchVue3Menu")
// public Result<String> switchVue3Menu(HttpServletResponse response) {
// Result<String> res = new Result<String>();
// sysPermissionService.switchVue3Menu();
// return res;
// }
/**
* app登录
@ -599,74 +639,80 @@ public class LoginController {
* @throws Exception
*/
@RequestMapping(value = "/mLogin", method = RequestMethod.POST)
public Result<JSONObject> mLogin(@RequestBody SysLoginModel sysLoginModel) throws Exception {
public Result<JSONObject> mLogin(@RequestBody SysLoginModel sysLoginModel, HttpServletRequest request) throws Exception {
Result<JSONObject> result = new Result<JSONObject>();
String username = sysLoginModel.getUsername();
String password = sysLoginModel.getPassword();
// 密码加密传输(尝试 AES解密失败视为明文)
String password = AesEncryptUtil.resolvePassword(sysLoginModel.getPassword());
log.debug("登录密码,原始密码:{},解密密码:{}" , sysLoginModel.getPassword(), password);
JSONObject obj = new JSONObject();
//update-begin-author:taoyan date:2022-11-7 for: issues/4109 平台用户登录失败锁定用户
// 1.平台用户登录失败锁定用户
if(isLoginFailOvertimes(username)){
return result.error500("该用户登录失败次数过多请于10分钟后再次登录");
}
//update-end-author:taoyan date:2022-11-7 for: issues/4109 平台用户登录失败锁定用户
//1. 校验用户是否有效
// 2.校验用户是否有效
SysUser sysUser = sysUserService.getUserByName(username);
result = sysUserService.checkUserIsEffective(sysUser);
if(!result.isSuccess()) {
return result;
}
//2. 校验用户名或密码是否正确
// 3.校验用户名或密码是否正确
String userpassword = PasswordUtil.encrypt(username, password, sysUser.getSalt());
String syspassword = sysUser.getPassword();
if (!syspassword.equals(userpassword)) {
//update-begin-author:taoyan date:2022-11-7 for: issues/4109 平台用户登录失败锁定用户
addLoginFailOvertimes(username);
//update-end-author:taoyan date:2022-11-7 for: issues/4109 平台用户登录失败锁定用户
result.error500("用户名或密码错误");
return result;
}
//3.设置登录部门
//4.设置登录部门
String orgCode = sysUser.getOrgCode();
//登录设置的组织
String loginOrgCode = sysLoginModel.getLoginOrgCode();
if(oConvertUtils.isEmpty(orgCode)) {
//如果当前用户无选择部门 查看部门关联信息
List<SysDepart> departs = sysDepartService.queryUserDeparts(sysUser.getId());
//update-begin-author:taoyan date:20220117 for: JTC-1068【app】新建用户没有设置部门及角色点击登录提示暂未归属部一直在登录页面 使用手机号登录 可正常
if (departs == null || departs.size() == 0) {
/*result.error500("用户暂未归属部门,不可登录!");
return result;*/
if(oConvertUtils.isNotEmpty(loginOrgCode)){
sysUser.setOrgCode(loginOrgCode);
this.sysUserService.updateUserDepart(username, loginOrgCode,null);
}else{
orgCode = departs.get(0).getOrgCode();
sysUser.setOrgCode(orgCode);
this.sysUserService.updateUserDepart(username, orgCode,null);
List<SysDepart> departs = sysDepartService.queryUserDeparts(sysUser.getId());
if (departs != null && !departs.isEmpty()) {
orgCode = departs.get(0).getOrgCode();
sysUser.setOrgCode(orgCode);
this.sysUserService.updateUserDepart(username, orgCode,null);
}
}
}else{
if(oConvertUtils.isNotEmpty(loginOrgCode) && !orgCode.equalsIgnoreCase(loginOrgCode)){
sysUser.setOrgCode(loginOrgCode);
sysUserService.updateUserDepart(username, loginOrgCode,null);
}
//update-end-author:taoyan date:20220117 for: JTC-1068【app】新建用户没有设置部门及角色点击登录提示暂未归属部一直在登录页面 使用手机号登录 可正常
}
//4. 设置登录租户
//5. 设置登录租户
Result<JSONObject> loginTenantError = sysUserService.setLoginTenant(sysUser, obj, username, result);
if (loginTenantError != null) {
return loginTenantError;
}
//5. 设置登录用户信息
// 设置登录用户信息
obj.put("userInfo", sysUser);
//6. 生成token
String token = JwtUtil.sign(username, syspassword);
// 设置超时时间
redisUtil.set(CommonConstant.PREFIX_USER_TOKEN + token, token);
redisUtil.expire(CommonConstant.PREFIX_USER_TOKEN + token, JwtUtil.EXPIRE_TIME*2 / 1000);
//token 信息
//6. 生成token并设置超时时间
String token = JwtUtil.sign(username, syspassword, CommonConstant.CLIENT_TYPE_APP);
redisUtil.set(CommonConstant.PREFIX_USER_TOKEN + token, token);
redisUtil.expire(CommonConstant.PREFIX_USER_TOKEN + token, JwtUtil.APP_EXPIRE_TIME*2 / 1000);
obj.put("token", token);
result.setResult(obj);
result.setSuccess(true);
result.setCode(200);
// 7.是否允许同一账号多地同时登录(APP端登录踢掉之前的APP端登录)
handleSingleSignOn(username, token, CommonConstant.CLIENT_TYPE_APP);
// 8.登录成功记录日志
baseCommonService.addLog("用户名: " + username + ",登录成功[移动端]", CommonConstant.LOG_TYPE_1, null);
return result;
}
@ -818,11 +864,9 @@ public class LoginController {
result.setSuccess(false);
return result;
}
//验证码5分钟内有效
//update-begin---author:wangshuai---date:2025-07-15---for:【issues/8567】严重修改密码存在水平越权问题。---
//【issues/8567】严重修改密码存在水平越权问题
obj.put("username",username);
redisUtil.set(redisKey, obj.toJSONString(), 300);
//update-end---author:wangshuai---date:2025-07-15---for:【issues/8567】严重修改密码存在水平越权问题。---
result.setSuccess(true);
} catch (ClientException e) {
e.printStackTrace();
@ -857,5 +901,43 @@ public class LoginController {
redisUtil.removeAll(realKey);
return Result.ok();
}
/**
* 登录获取用户部门信息
*
* @param jsonObject
* @return
*/
@IgnoreAuth
@RequestMapping(value = "/loginGetUserDeparts", method = RequestMethod.POST)
public Result<JSONObject> loginGetUserDeparts(@RequestBody JSONObject jsonObject, HttpServletRequest request){
return sysUserService.loginGetUserDeparts(jsonObject);
}
/**
* 校验验证码工具方法校验失败直接返回Result校验通过返回realKey
*/
private String validateCaptcha(SysLoginModel sysLoginModel, Result<JSONObject> result) {
// 判断是否启用登录验证码校验
if (jeecgBaseConfig.getFirewall() != null && Boolean.FALSE.equals(jeecgBaseConfig.getFirewall().getEnableLoginCaptcha())) {
log.warn("关闭了登录验证码校验,跳过验证码校验!");
return "LoginWithoutVerifyCode";
}
String captcha = sysLoginModel.getCaptcha();
if (captcha == null) {
result.error500("验证码无效");
return null;
}
String lowerCaseCaptcha = captcha.toLowerCase();
String keyPrefix = Md5Util.md5Encode(sysLoginModel.getCheckKey() + jeecgBaseConfig.getSignatureSecret(), "utf-8");
String realKey = keyPrefix + lowerCaseCaptcha;
Object checkCode = redisUtil.get(realKey);
if (checkCode == null || !checkCode.toString().equals(lowerCaseCaptcha)) {
log.warn("验证码错误key= {} , Ui checkCode= {}, Redis checkCode = {}", sysLoginModel.getCheckKey(), lowerCaseCaptcha, checkCode);
result.error500("验证码错误");
result.setCode(HttpStatus.PRECONDITION_FAILED.value());
return null;
}
return realKey;
}
}

View File

@ -9,6 +9,7 @@ import com.jeecg.dingtalk.api.core.response.Response;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.jeecg.common.api.dto.PushMessageDTO;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.config.TenantContext;
import org.jeecg.common.constant.CommonConstant;
@ -49,10 +50,7 @@ import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.ThreadPoolExecutor;
@ -100,8 +98,8 @@ public class SysAnnouncementController {
/**
* QQYUN-5072【性能优化】线上通知消息打开有点慢
*/
public static ExecutorService cachedThreadPool = new ThreadPoolExecutor(0, 1024,60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>());
public static ExecutorService completeNoteThreadPool = new ThreadPoolExecutor(0, 1024,60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>());
public static ExecutorService cachedThreadPool = new ShiroThreadPoolExecutor(0, 1024,60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>());
public static ExecutorService completeNoteThreadPool = new ShiroThreadPoolExecutor(0, 1024,60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>());
/**
* 分页列表查询
@ -141,10 +139,9 @@ public class SysAnnouncementController {
public Result<SysAnnouncement> add(@RequestBody SysAnnouncement sysAnnouncement) {
Result<SysAnnouncement> result = new Result<SysAnnouncement>();
try {
// update-begin-author:liusq date:20210804 for:标题处理xss攻击的问题
// 代码逻辑说明: 标题处理xss攻击的问题
String title = XssUtils.scriptXss(sysAnnouncement.getTitile());
sysAnnouncement.setTitile(title);
// update-end-author:liusq date:20210804 for:标题处理xss攻击的问题
sysAnnouncement.setDelFlag(CommonConstant.DEL_FLAG_0.toString());
//未发布
sysAnnouncement.setSendStatus(CommonSendStatus.UNPUBLISHED_STATUS_0);
@ -173,10 +170,9 @@ public class SysAnnouncementController {
if(sysAnnouncementEntity==null) {
result.error500("未找到对应实体");
}else {
// update-begin-author:liusq date:20210804 for:标题处理xss攻击的问题
// 代码逻辑说明: 标题处理xss攻击的问题
String title = XssUtils.scriptXss(sysAnnouncement.getTitile());
sysAnnouncement.setTitile(title);
// update-end-author:liusq date:20210804 for:标题处理xss攻击的问题
sysAnnouncement.setNoticeType(NoticeTypeEnum.NOTICE_TYPE_SYSTEM.getValue());
boolean ok = sysAnnouncementService.upDateAnnouncement(sysAnnouncement);
//TODO 返回false说明什么
@ -306,6 +302,13 @@ public class SysAnnouncementController {
obj.put(WebsocketConst.MSG_TXT, sysAnnouncement.getTitile());
obj.put(CommonConstant.NOTICE_TYPE, sysAnnouncement.getNoticeType());
webSocket.sendMessage(obj.toJSONString());
//update-begin-author:liusq---date:2025-11-13--for: JHHB-827 【审批消息】移动端需要有推送 -全推送
PushMessageDTO pushMessageDTO = new PushMessageDTO();
pushMessageDTO.setTitle(sysAnnouncement.getTitile());
pushMessageDTO.setPushType(CommonConstant.MSG_TYPE_ALL);
pushMessageDTO.setContent(sysAnnouncement.getMsgAbstract());
sysBaseApi.uniPushMsgToUser(pushMessageDTO);
//update-begin-author:liusq---date:2025-11-13--for: JHHB-827 【审批消息】移动端需要有推送 -全推送
}else {
// 2.插入用户通告阅读标记表记录
String userId = sysAnnouncement.getUserIds();
@ -318,6 +321,13 @@ public class SysAnnouncementController {
obj.put(WebsocketConst.MSG_TXT, sysAnnouncement.getTitile());
obj.put(CommonConstant.NOTICE_TYPE, sysAnnouncement.getNoticeType());
webSocket.sendMessage(userIds, obj.toJSONString());
//update-begin-author:liusq---date:2025-11-13--for: JHHB-827 【审批消息】移动端需要有推送
PushMessageDTO pushMessageDTO = new PushMessageDTO();
pushMessageDTO.setTitle(sysAnnouncement.getTitile());
pushMessageDTO.setUserIds(Arrays.asList(userIds));
pushMessageDTO.setContent(sysAnnouncement.getMsgAbstract());
sysBaseApi.uniPushMsgToUser(pushMessageDTO);
//update-begin-author:liusq---date:2025-11-13--for: JHHB-827 【审批消息】移动端需要有推送
}
try {
// 同步企业微信、钉钉的消息通知
@ -382,11 +392,9 @@ public class SysAnnouncementController {
String userId = sysUser.getId();
//update-begin---author:scott ---date:2024-05-11 for【性能优化】优化系统通知只查近2个月的通知---
// 获取上个月的第一天(只查近两个月的通知)
Date lastMonthStartDay = DateRangeUtils.getLastMonthStartDay();
log.info("-----查询近两个月收到的未读通知-----近2月的第一天{}", lastMonthStartDay);
//update-end---author:scott ---date::2024-05-11 for【性能优化】优化系统通知只查近2个月的通知---
// //补推送数据(用户和通知的关系表)
// completeNoteThreadPool.execute(()->{
@ -428,8 +436,8 @@ public class SysAnnouncementController {
// 获取上个月的第一天(只查近两个月的通知)
Date lastMonthStartDay = DateRangeUtils.getLastMonthStartDay();
log.info(" ------查询近两个月收到的未读通知消息数量------近2月的第一天{}", lastMonthStartDay);
//update-begin---author:wangshuai---date:2025-06-26---for:【QQYUN-12162】OA项目改造系统重消息拆分目前消息都在一起 需按分类进行拆分---
log.debug(" ------查询近两个月收到的未读通知消息数量------近2月的第一天{}", lastMonthStartDay);
// 代码逻辑说明: 【QQYUN-12162】OA项目改造系统重消息拆分目前消息都在一起 需按分类进行拆分---
Map<String,Integer> unreadMessageCount = new HashMap<>();
//系统消息数量
Integer systemCount = sysAnnouncementService.getUnreadMessageCountByUserId(userId, lastMonthStartDay, NoticeTypeEnum.NOTICE_TYPE_SYSTEM.getValue());
@ -445,7 +453,6 @@ public class SysAnnouncementController {
unreadMessageCount.put("planCount",planCount);
Integer count = systemCount + flowCount + fileCount + planCount;
unreadMessageCount.put("count",count);
//update-end---author:wangshuai---date:2025-06-26---for:【QQYUN-12162】OA项目改造系统重消息拆分目前消息都在一起 需按分类进行拆分---
return Result.ok(unreadMessageCount);
}
@ -649,7 +656,7 @@ public class SysAnnouncementController {
// 4、性能统计耗时
long calEndTime = System.currentTimeMillis(); // 记录结束时间
long duration = calEndTime - calStartTime; // 计算耗时
log.info("耗时:" + duration + " 毫秒");
//System.out.println("耗时:" + duration + " 毫秒");
return Result.ok(ls);
}
@ -667,7 +674,7 @@ public class SysAnnouncementController {
// step.1 此接口过慢,可以采用缓存一小时方案
String keyString = String.format(CommonConstant.CACHE_KEY_USER_LAST_ANNOUNT_TIME_1HOUR + "_" + noticeType, userId);
if (redisTemplate.hasKey(keyString)) {
log.info("[SysAnnouncementSend Redis] 通过Redis缓存查询用户最后一次收到系统通知时间userId={}", userId);
log.debug("[SysAnnouncementSend Redis] 通过Redis缓存查询用户最后一次收到系统通知时间userId={}", userId);
Page<SysAnnouncementSend> pageList = (Page<SysAnnouncementSend>) redisTemplate.opsForValue().get(keyString);
result.setSuccess(true);
result.setResult(pageList);

View File

@ -138,9 +138,10 @@ public class SysAnnouncementSendController {
@DeleteMapping(value = "/delete")
public Result<SysAnnouncementSend> delete(@RequestParam(name="id",required=true) String id) {
Result<SysAnnouncementSend> result = new Result<SysAnnouncementSend>();
SysAnnouncementSend sysAnnouncementSend = sysAnnouncementSendService.getById(id);
if(sysAnnouncementSend==null) {
result.error500("未找到对应实体");
//根据用户id和通告阅读表的id获取当前用户已阅读的数量
long count = sysAnnouncementSendService.getReadCountByUserId(id);
if(0 == count) {
result.error500("删除失败,该数据不存在或尚未标记为“已读”");
}else {
boolean ok = sysAnnouncementSendService.removeById(id);
if(ok) {
@ -162,8 +163,8 @@ public class SysAnnouncementSendController {
if(ids==null || "".equals(ids.trim())) {
result.error500("参数不识别!");
}else {
this.sysAnnouncementSendService.removeByIds(Arrays.asList(ids.split(",")));
result.success("删除成功!");
this.sysAnnouncementSendService.deleteBatchByIds(ids);
result.success("已阅读的消息删除成功!");
}
return result;
}
@ -200,10 +201,9 @@ public class SysAnnouncementSendController {
LambdaUpdateWrapper<SysAnnouncementSend> updateWrapper = new UpdateWrapper().lambda();
updateWrapper.set(SysAnnouncementSend::getReadFlag, CommonConstant.HAS_READ_FLAG);
updateWrapper.set(SysAnnouncementSend::getReadTime, new Date());
//update-begin-author:liusq date:2023-09-04 for:系统模块存在的sql漏洞写法
// 代码逻辑说明: 系统模块存在的sql漏洞写法
updateWrapper.eq(SysAnnouncementSend::getAnntId,anntId);
updateWrapper.eq(SysAnnouncementSend::getUserId,userId);
//update-end-author:liusq date:2023-09-04 for: 系统模块存在的sql漏洞写法
//updateWrapper.last("where annt_id ='"+anntId+"' and user_id ='"+userId+"'");
SysAnnouncementSend announcementSend = new SysAnnouncementSend();
sysAnnouncementSendService.update(announcementSend, updateWrapper);
@ -225,14 +225,13 @@ public class SysAnnouncementSendController {
announcementSendModel.setUserId(userId);
announcementSendModel.setPageNo((pageNo-1)*pageSize);
announcementSendModel.setPageSize(pageSize);
//update-begin---author:wangshuai---date:2024-06-11---for:【TV360X-545】我的消息列表不能通过时间范围查询---
// 代码逻辑说明: 【TV360X-545】我的消息列表不能通过时间范围查询---
if(StringUtils.isNotEmpty(announcementSendModel.getSendTimeBegin())){
announcementSendModel.setSendTimeBegin(announcementSendModel.getSendTimeBegin() + " 00:00:00");
}
if(StringUtils.isNotEmpty(announcementSendModel.getSendTimeBegin())){
announcementSendModel.setSendTimeEnd(announcementSendModel.getSendTimeEnd() + " 23:59:59");
}
//update-end---author:wangshuai---date:2024-06-11---for:【TV360X-545】我的消息列表不能通过时间范围查询---
Page<AnnouncementSendModel> pageList = new Page<AnnouncementSendModel>(pageNo,pageSize);
pageList = sysAnnouncementSendService.getMyAnnouncementSendPage(pageList, announcementSendModel);
result.setResult(pageList);
@ -275,4 +274,25 @@ public class SysAnnouncementSendController {
AnnouncementSendModel model = sysAnnouncementSendService.getOne(sendId);
return Result.ok(model);
}
/**
* 根据业务类型和ID修改阅读状态
* @param busType
* @return
*/
@GetMapping(value = "/updateSysAnnounReadFlag")
public Result<AnnouncementSendModel> updateSysAnnounReadFlag(
@RequestParam(name="busId",required=true) String busId,
@RequestParam(name="busType",required=false) String busType) {
//更新阅读状态
sysAnnouncementSendService.updateReadFlagByBusId(busId,busType);
//刷新未读数量
JSONObject obj = new JSONObject();
obj.put(WebsocketConst.MSG_CMD, WebsocketConst.CMD_USER);
LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
webSocket.sendMessage(sysUser.getId(), obj.toJSONString());
return Result.ok();
}
}

View File

@ -25,6 +25,7 @@ import org.jeecgframework.poi.excel.ExcelImportUtil;
import org.jeecgframework.poi.excel.def.NormalExcelConstants;
import org.jeecgframework.poi.excel.entity.ExportParams;
import org.jeecgframework.poi.excel.entity.ImportParams;
import org.jeecgframework.poi.excel.entity.enmus.ExcelType;
import org.jeecgframework.poi.excel.view.JeecgEntityExcelView;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
@ -238,7 +239,13 @@ public class SysCategoryController {
mv.addObject(NormalExcelConstants.FILE_NAME, "分类字典列表");
mv.addObject(NormalExcelConstants.CLASS, SysCategory.class);
LoginUser user = (LoginUser) SecurityUtils.getSubject().getPrincipal();
mv.addObject(NormalExcelConstants.PARAMS, new ExportParams("分类字典列表数据", "导出人:"+user.getRealname(), "导出信息"));
//导出支持xlsx
mv.addObject(NormalExcelConstants.PARAMS, new ExportParams("分类字典列表数据", "导出人:"+user.getRealname(), "导出信息", ExcelType.XSSF));
//分类字典导出支持导出字段
String exportFields = request.getParameter(NormalExcelConstants.EXPORT_FIELDS);
if(oConvertUtils.isNotEmpty(exportFields)){
mv.addObject(NormalExcelConstants.EXPORT_FIELDS, exportFields);
}
return mv;
}
@ -265,9 +272,8 @@ public class SysCategoryController {
params.setNeedSave(true);
try {
List<SysCategory> listSysCategorys = ExcelImportUtil.importExcel(file.getInputStream(), SysCategory.class, params);
//update-begin---author:chenrui ---date:20250721 for[issues/8612]分类字典导入bug #8612 ------------
// 代码逻辑说明: [issues/8612]分类字典导入bug #8612 ------------
Set<String> parentCategoryIds = new HashSet<>();
//update-end---author:chenrui ---date:20250721 for[issues/8612]分类字典导入bug #8612 ------------
//按照编码长度排序
Collections.sort(listSysCategorys);
log.info("排序后的list====>",listSysCategorys);
@ -281,9 +287,7 @@ public class SysCategoryController {
log.info("pId====>",pId);
if(StringUtils.isNotBlank(pId)){
sysCategoryExcel.setPid(pId);
//update-begin---author:chenrui ---date:20250721 for[issues/8612]分类字典导入bug #8612 ------------
parentCategoryIds.add(pId);
//update-end---author:chenrui ---date:20250721 for[issues/8612]分类字典导入bug #8612 ------------
}
}else{
sysCategoryExcel.setPid("0");
@ -304,7 +308,7 @@ public class SysCategoryController {
}
}
}
//update-begin---author:chenrui ---date:20250721 for[issues/8612]分类字典导入bug #8612 ------------
// 代码逻辑说明: [issues/8612]分类字典导入bug #8612 ------------
if(oConvertUtils.isObjectNotEmpty(parentCategoryIds)){
for (String parentCategoryId : parentCategoryIds) {
SysCategory parentCategory = sysCategoryService.getById(parentCategoryId);
@ -314,7 +318,6 @@ public class SysCategoryController {
}
}
}
//update-end---author:chenrui ---date:20250721 for[issues/8612]分类字典导入bug #8612 ------------
} catch (Exception e) {
errorMessage.add("发生异常:" + e.getMessage());
log.error(e.getMessage(), e);
@ -338,12 +341,11 @@ public class SysCategoryController {
public Result<SysCategory> loadOne(@RequestParam(name="field") String field,@RequestParam(name="val") String val) {
Result<SysCategory> result = new Result<SysCategory>();
try {
//update-begin-author:taoyan date:2022-5-6 for: issues/3663 sql注入问题
// 代码逻辑说明: issues/3663 sql注入问题
boolean isClassField = ReflectHelper.isClassField(field, SysCategory.class);
if (!isClassField) {
return Result.error("字段无效,请检查!");
}
//update-end-author:taoyan date:2022-5-6 for: issues/3663 sql注入问题
QueryWrapper<SysCategory> query = new QueryWrapper<SysCategory>();
query.eq(field, val);
List<SysCategory> ls = this.sysCategoryService.list(query);

View File

@ -87,14 +87,13 @@ public class SysDataLogController {
QueryWrapper<SysDataLog> queryWrapper = new QueryWrapper<SysDataLog>();
queryWrapper.eq("data_table", dataTable);
queryWrapper.eq("data_id", dataId);
//update-begin-author:taoyan date:2022-7-26 for: 新增查询条件-type
// 代码逻辑说明: 新增查询条件-type
String type = req.getParameter("type");
if (oConvertUtils.isNotEmpty(type)) {
queryWrapper.eq("type", type);
}
// 按时间倒序排
queryWrapper.orderByDesc("create_time");
//update-end-author:taoyan date:2022-7-26 for:新增查询条件-type
List<SysDataLog> list = service.list(queryWrapper);
if(list==null||list.size()<=0) {

View File

@ -114,14 +114,13 @@ public class SysDataSourceController extends JeecgController<SysDataSource, ISys
@Operation(summary = "多数据源管理-添加")
@PostMapping(value = "/add")
public Result<?> add(@RequestBody SysDataSource sysDataSource) {
//update-begin-author:taoyan date:2022-8-10 for: jdbc连接地址漏洞问题
// 代码逻辑说明: jdbc连接地址漏洞问题
try {
JdbcSecurityUtil.validate(sysDataSource.getDbUrl());
}catch (JeecgBootException e){
log.error(e.toString());
return Result.error("操作失败:" + e.getMessage());
}
//update-end-author:taoyan date:2022-8-10 for: jdbc连接地址漏洞问题
return sysDataSourceService.saveDataSource(sysDataSource);
}
@ -135,14 +134,13 @@ public class SysDataSourceController extends JeecgController<SysDataSource, ISys
@Operation(summary = "多数据源管理-编辑")
@RequestMapping(value = "/edit", method ={RequestMethod.PUT, RequestMethod.POST})
public Result<?> edit(@RequestBody SysDataSource sysDataSource) {
//update-begin-author:taoyan date:2022-8-10 for: jdbc连接地址漏洞问题
// 代码逻辑说明: jdbc连接地址漏洞问题
try {
JdbcSecurityUtil.validate(sysDataSource.getDbUrl());
} catch (JeecgBootException e) {
log.error(e.toString());
return Result.error("操作失败:" + e.getMessage());
}
//update-end-author:taoyan date:2022-8-10 for: jdbc连接地址漏洞问题
return sysDataSourceService.editDataSource(sysDataSource);
}

View File

@ -2,10 +2,13 @@ package org.jeecg.modules.system.controller;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.apache.shiro.authz.annotation.RequiresRoles;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.config.TenantContext;
import org.jeecg.common.constant.CacheConstant;
@ -24,6 +27,7 @@ import org.jeecg.modules.system.model.SysDepartTreeModel;
import org.jeecg.modules.system.service.ISysDepartService;
import org.jeecg.modules.system.service.ISysUserDepartService;
import org.jeecg.modules.system.service.ISysUserService;
import org.jeecg.modules.system.vo.SysChangeDepartVo;
import org.jeecg.modules.system.vo.SysDepartExportVo;
import org.jeecg.modules.system.vo.SysPositionSelectTreeVo;
import org.jeecg.modules.system.vo.lowapp.ExportDepartVo;
@ -31,6 +35,7 @@ import org.jeecgframework.poi.excel.ExcelImportUtil;
import org.jeecgframework.poi.excel.def.NormalExcelConstants;
import org.jeecgframework.poi.excel.entity.ExportParams;
import org.jeecgframework.poi.excel.entity.ImportParams;
import org.jeecgframework.poi.excel.entity.enmus.ExcelType;
import org.jeecgframework.poi.excel.view.JeecgEntityExcelView;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
@ -78,13 +83,12 @@ public class SysDepartController {
LoginUser user = (LoginUser) SecurityUtils.getSubject().getPrincipal();
try {
if(oConvertUtils.isNotEmpty(user.getUserIdentity()) && user.getUserIdentity().equals( CommonConstant.USER_IDENTITY_2 )){
//update-begin--Author:liusq Date:20210624 for:部门查询ids为空后的前端显示问题 issues/I3UD06
// 代码逻辑说明: 部门查询ids为空后的前端显示问题 issues/I3UD06
String departIds = user.getDepartIds();
if(StringUtils.isNotBlank(departIds)){
List<SysDepartTreeModel> list = sysDepartService.queryMyDeptTreeList(departIds);
result.setResult(list);
}
//update-end--Author:liusq Date:20210624 for:部门查询ids为空后的前端显示问题 issues/I3UD06
result.setMessage(CommonConstant.USER_IDENTITY_2.toString());
result.setSuccess(true);
}else{
@ -382,7 +386,6 @@ public class SysDepartController {
}
//------------------------------------------------------------------------------------------------
//update-begin---author:wangshuai---date:2023-10-19---for:【QQYUN-5482】系统的部门导入导出也可以改成敲敲云模式的部门路径---
//// Step.1 组装查询条件
//QueryWrapper<SysDepart> queryWrapper = QueryGenerator.initQueryWrapper(sysDepart, request.getParameterMap());
//Step.1 AutoPoi 导出Excel
@ -403,9 +406,8 @@ public class SysDepartController {
}
//step.2 组装导出数据
Integer tenantId = sysDepart == null ? null : sysDepart.getTenantId();
//update-begin---author:wangshuai---date:2024-07-05---for:【TV360X-1671】部门管理不支持选中的记录导出---
// 代码逻辑说明: 【TV360X-1671】部门管理不支持选中的记录导出---
List<SysDepartExportVo> sysDepartExportVos = sysDepartService.getExportDepart(tenantId,idList);
//update-end---author:wangshuai---date:2024-07-05---for:【TV360X-1671】部门管理不支持选中的记录导出---
//导出文件名称
mv.addObject(NormalExcelConstants.FILE_NAME, "部门列表");
mv.addObject(NormalExcelConstants.CLASS, SysDepartExportVo.class);
@ -414,12 +416,11 @@ public class SysDepartController {
"1、标题为第三行部门路径和部门名称的标题不允许修改否则会匹配失败第四行为数据填写范围;\n" +
"2、部门路径用英文字符/分割,部门名称为部门路径的最后一位;\n" +
"3、部门从一级名称开始创建如果有同级就需要多添加一行如研发部/研发一部;研发部/研发二部;\n" +
"4、自定义的部门编码需要满足规则才能导入。如一级部门编码为A01,那么子部门为A01A01,同级子部门为A01A02,编码固定为三位首字母为A-Z,后两位为数字0-99依次递增;", "导出人:" + user.getRealname(), "导出信息");
"4、自定义的部门编码需要满足规则才能导入。如一级部门编码为A01,那么子部门为A01A01,同级子部门为A01A02,编码固定为三位首字母为A-Z,后两位为数字0-99依次递增;", "导出人:" + user.getRealname(), "导出信息", ExcelType.XSSF);
exportParams.setTitleHeight((short)70);
exportParams.setStyle(ExcelExportSysUserStyle.class);
mv.addObject(NormalExcelConstants.PARAMS, exportParams);
mv.addObject(NormalExcelConstants.DATA_LIST, sysDepartExportVos);
//update-end---author:wangshuai---date:2023-10-19---for:【QQYUN-5482】系统的部门导入导出也可以改成敲敲云模式的部门路径---
return mv;
}
@ -450,7 +451,6 @@ public class SysDepartController {
params.setHeadRows(1);
params.setNeedSave(true);
try {
//update-begin---author:wangshuai---date:2023-10-20---for: 注释掉原来的导入部门的逻辑---
// // orgCode编码长度
// int codeLength = YouBianCodeUtil.ZHANWEI_LENGTH;
// listSysDeparts = ExcelImportUtil.importExcel(file.getInputStream(), SysDepart.class, params);
@ -484,24 +484,18 @@ public class SysDepartController {
// }else{
// sysDepart.setParentId("");
// }
// //update-begin---author:liusq Date:20210223 for批量导入部门以后不能追加下一级部门 #2245------------
// sysDepart.setOrgType(sysDepart.getOrgCode().length()/codeLength+"");
// //update-end---author:liusq Date:20210223 for批量导入部门以后不能追加下一级部门 #2245------------
// sysDepart.setDelFlag(CommonConstant.DEL_FLAG_0.toString());
// //update-begin---author:wangshuai ---date:20220105 for[JTC-363]部门导入 机构类别没有时导入失败,赋默认值------------
// if(oConvertUtils.isEmpty(sysDepart.getOrgCategory())){
// sysDepart.setOrgCategory("1");
// }
// //update-end---author:wangshuai ---date:20220105 for[JTC-363]部门导入 机构类别没有时导入失败,赋默认值------------
// ImportExcelUtil.importDateSaveOne(sysDepart, ISysDepartService.class, errorMessageList, num, CommonConstant.SQL_INDEX_UNIQ_DEPART_ORG_CODE);
// num++;
// }
//update-end---author:wangshuai---date:2023-10-20---for: 注释掉原来的导入部门的逻辑---
//update-begin---author:wangshuai---date:2023-10-19---for:【QQYUN-5482】系统的部门导入导出也可以改成敲敲云模式的部门路径---
// 代码逻辑说明: 【QQYUN-5482】系统的部门导入导出也可以改成敲敲云模式的部门路径---
listSysDeparts = ExcelImportUtil.importExcel(file.getInputStream(), SysDepartExportVo.class, params);
sysDepartService.importSysDepart(listSysDeparts,errorMessageList);
//update-end---author:wangshuai---date:2023-10-19---for:【QQYUN-5482】系统的部门导入导出也可以改成敲敲云模式的部门路径---
//清空部门缓存
List<String> keys3 = redisUtil.scan(CacheConstant.SYS_DEPARTS_CACHE + "*");
@ -757,4 +751,45 @@ public class SysDepartController {
String departName = sysDepartService.getDepartPathNameByOrgCode(orgCode, depId);
return Result.OK(departName);
}
/**
* 根据部门id获取部门下的岗位id
*
* @param depIds 当前选择的公司、子公司、部门id
* @return
*/
@GetMapping("/getDepPostIdByDepId")
public Result<Map<String, String>> getDepPostIdByDepId(@RequestParam(name = "depIds") String depIds) {
String departIds = sysDepartService.getDepPostIdByDepId(depIds);
return Result.OK(departIds);
}
/**
* 更新改变后的部门数据
*
* @param changeDepartVo
* @return
*/
@PutMapping("/updateChangeDepart")
@RequiresPermissions("system:depart:updateChange")
@RequiresRoles({"admin"})
public Result<String> updateChangeDepart(@RequestBody SysChangeDepartVo changeDepartVo) {
sysDepartService.updateChangeDepart(changeDepartVo);
return Result.ok("调整部门位置成功!");
}
/**
* 获取部门负责人
*
* @param departId
* @return
*/
@GetMapping("/getDepartmentHead")
public Result<IPage<SysUser>> getDepartmentHead(@RequestParam(name = "departId") String departId,
@RequestParam(name="pageNo", defaultValue="1") Integer pageNo,
@RequestParam(name="pageSize", defaultValue="10") Integer pageSize){
Page<SysUser> page = new Page<>(pageNo, pageSize);
IPage<SysUser> pageList = sysDepartService.getDepartmentHead(departId,page);
return Result.OK(pageList);
}
}

View File

@ -259,10 +259,9 @@ public class SysDepartPermissionController extends JeecgController<SysDepartPerm
String lastPermissionIds = json.getString("lastpermissionIds");
this.sysDepartRolePermissionService.saveDeptRolePermission(roleId, permissionIds, lastPermissionIds);
result.success("保存成功!");
//update-begin---author:wangshuai ---date:20220316 for[VUEN-234]部门角色授权添加敏感日志------------
// 代码逻辑说明: [VUEN-234]部门角色授权添加敏感日志------------
LoginUser loginUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
baseCommonService.addLog("修改部门角色ID:"+roleId+"的权限配置,操作人: " +loginUser.getUsername() ,CommonConstant.LOG_TYPE_2, 2);
//update-end---author:wangshuai ---date:20220316 for[VUEN-234]部门角色授权添加敏感日志------------
log.info("======部门角色授权成功=====耗时:" + (System.currentTimeMillis() - start) + "毫秒");
} catch (Exception e) {
result.error500("授权失败!");

View File

@ -92,7 +92,7 @@ public class SysDepartRoleController extends JeecgController<SysDepartRole, ISys
// queryWrapper.in("depart_id",deptIds);
//我的部门,选中部门只能看当前部门下的角色
//update-begin---author:chenrui ---date:20250107 for[QQYUN-10775]验证码可以复用 #7674------------
// 代码逻辑说明: [QQYUN-10775]验证码可以复用 #7674------------
if(oConvertUtils.isNotEmpty(deptId)){
queryWrapper.eq("depart_id",deptId);
IPage<SysDepartRole> pageList = sysDepartRoleService.page(page, queryWrapper);
@ -100,7 +100,6 @@ public class SysDepartRoleController extends JeecgController<SysDepartRole, ISys
}else{
return Result.ok(null);
}
//update-end---author:chenrui ---date:20250107 for[QQYUN-10775]验证码可以复用 #7674------------
}
/**
@ -202,10 +201,9 @@ public class SysDepartRoleController extends JeecgController<SysDepartRole, ISys
String oldRoleId = json.getString("oldRoleId");
String userId = json.getString("userId");
departRoleUserService.deptRoleUserAdd(userId,newRoleId,oldRoleId);
//update-begin---author:wangshuai ---date:20220316 for[VUEN-234]部门角色分配添加敏感日志------------
// 代码逻辑说明: [VUEN-234]部门角色分配添加敏感日志------------
LoginUser loginUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
baseCommonService.addLog("给部门用户ID"+userId+"分配角色,操作人: " +loginUser.getUsername() ,CommonConstant.LOG_TYPE_2, 2);
//update-end---author:wangshuai ---date:20220316 for[VUEN-234]部门角色分配添加敏感日志------------
return Result.ok("添加成功!");
}

View File

@ -24,6 +24,7 @@ import org.jeecg.common.system.vo.LoginUser;
import org.jeecg.common.util.*;
import org.jeecg.config.mybatis.MybatisPlusSaasConfig;
import org.jeecg.config.shiro.ShiroRealm;
import org.jeecg.modules.system.constant.DefIndexConst;
import org.jeecg.modules.system.entity.SysDict;
import org.jeecg.modules.system.entity.SysDictItem;
import org.jeecg.modules.system.model.SysDictTree;
@ -37,6 +38,7 @@ import org.jeecgframework.poi.excel.ExcelImportUtil;
import org.jeecgframework.poi.excel.def.NormalExcelConstants;
import org.jeecgframework.poi.excel.entity.ExportParams;
import org.jeecgframework.poi.excel.entity.ImportParams;
import org.jeecgframework.poi.excel.entity.enmus.ExcelType;
import org.jeecgframework.poi.excel.view.JeecgEntityExcelView;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
@ -182,7 +184,7 @@ public class SysDictController {
*/
@RequestMapping(value = "/getDictItems/{dictCode}", method = RequestMethod.GET)
public Result<List<DictModel>> getDictItems(@PathVariable("dictCode") String dictCode, @RequestParam(value = "sign",required = false) String sign,HttpServletRequest request) {
log.info(" dictCode : "+ dictCode);
log.debug(" dictCode : "+ dictCode);
Result<List<DictModel>> result = new Result<List<DictModel>>();
try {
List<DictModel> ls = sysDictService.getDictItems(dictCode);
@ -215,7 +217,7 @@ public class SysDictController {
@RequestParam(name = "pageNo", defaultValue = "1", required = false) Integer pageNo,
@RequestParam(name = "pageSize", defaultValue = "10", required = false) Integer pageSize) {
//update-begin-author:taoyan date:2023-5-22 for: /issues/4905 因为中括号(%5)的问题导致的 表单生成器字段配置时,选择关联字段,在进行高级配置时,无法加载数据库列表,提示 Sgin签名校验错误 #4905 RouteToRequestUrlFilter
// 代码逻辑说明: /issues/4905 因为中括号(%5)的问题导致的 表单生成器字段配置时,选择关联字段,在进行高级配置时,无法加载数据库列表,提示 Sgin签名校验错误 #4905 RouteToRequestUrlFilter
if(keyword!=null && keyword.indexOf("%5")>=0){
try {
keyword = URLDecoder.decode(keyword, "UTF-8");
@ -223,7 +225,6 @@ public class SysDictController {
log.error("下拉搜索关键字解码失败", e);
}
}
//update-end-author:taoyan date:2023-5-22 for: /issues/4905 因为中括号(%5)的问题导致的 表单生成器字段配置时,选择关联字段,在进行高级配置时,无法加载数据库列表,提示 Sgin签名校验错误 #4905
log.info(" 加载字典表数据,加载关键字: "+ keyword);
Result<List<DictModel>> result = new Result<List<DictModel>>();
@ -490,7 +491,7 @@ public class SysDictController {
// redisTemplate.delete(keys6);
// redisTemplate.delete(keys7);
//update-begin-author:liusq date:20230404 for: [issue/4358]springCache中的清除缓存的操作使用了“keys”
// 代码逻辑说明: [issue/4358]springCache中的清除缓存的操作使用了“keys”
redisUtil.removeAll(CacheConstant.SYS_DICT_CACHE);
redisUtil.removeAll(CacheConstant.SYS_ENABLE_DICT_CACHE);
redisUtil.removeAll(CacheConstant.SYS_DICT_TABLE_CACHE);
@ -499,15 +500,15 @@ public class SysDictController {
redisUtil.removeAll(CacheConstant.SYS_DEPART_IDS_CACHE);
redisUtil.removeAll("jmreport:cache:dict");
redisUtil.removeAll("jmreport:cache:dictTable");
//update-end-author:liusq date:20230404 for: [issue/4358]springCache中的清除缓存的操作使用了“keys”
//update-begin---author:scott ---date:2024-06-18 for【TV360X-1320】分配权限必须退出重新登录才生效造成很多用户困扰---
// 清除当前用户的授权缓存信息
Subject currentUser = SecurityUtils.getSubject();
if (currentUser.isAuthenticated()) {
shiroRealm.clearCache(currentUser.getPrincipals());
}
//update-end---author:scott ---date::2024-06-18 for【TV360X-1320】分配权限必须退出重新登录才生效造成很多用户困扰---
// 清空默认首页缓存(开源版和商业版会串)
redisUtil.del(DefIndexConst.CACHE_KEY + "::" + DefIndexConst.DEF_INDEX_ALL);
return result;
}
@ -551,7 +552,7 @@ public class SysDictController {
mv.addObject(NormalExcelConstants.CLASS, SysDictPage.class);
// 自定义表格参数
LoginUser user = (LoginUser) SecurityUtils.getSubject().getPrincipal();
mv.addObject(NormalExcelConstants.PARAMS, new ExportParams("数据字典列表", "导出人:"+user.getRealname(), "数据字典"));
mv.addObject(NormalExcelConstants.PARAMS, new ExportParams("数据字典列表", "导出人:"+user.getRealname(), "数据字典", ExcelType.XSSF));
// 导出数据列表
mv.addObject(NormalExcelConstants.DATA_LIST, pageList);
return mv;
@ -594,21 +595,19 @@ public class SysDictController {
Integer integer = sysDictService.saveMain(po, list.get(i).getSysDictItemList());
if(integer>0){
successLines++;
//update-begin---author:wangshuai ---date:20220211 for[JTC-1168]如果字典项值为空,则字典项忽略导入------------
// 代码逻辑说明: [JTC-1168]如果字典项值为空,则字典项忽略导入------------
}else if(integer == -1){
errorLines++;
errorMessage.add("字典名称:" + po.getDictName() + ",对应字典列表的字典项值不能为空,忽略导入。");
}else{
//update-end---author:wangshuai ---date:20220211 for[JTC-1168]如果字典项值为空,则字典项忽略导入------------
errorLines++;
int lineNumber = i + 1;
//update-begin---author:wangshuai ---date:20220209 for[JTC-1168]字典编号不能为空------------
// 代码逻辑说明: [JTC-1168]字典编号不能为空------------
if(oConvertUtils.isEmpty(po.getDictCode())){
errorMessage.add("" + lineNumber + " 行:字典编码不能为空,忽略导入。");
}else{
errorMessage.add("" + lineNumber + " 行:字典编码已经存在,忽略导入。");
}
//update-end---author:wangshuai ---date:20220209 for[JTC-1168]字典编号不能为空------------
}
} catch (Exception e) {
errorLines++;

View File

@ -2,17 +2,26 @@ package org.jeecg.modules.system.controller;
import java.util.Arrays;
import java.util.List;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.system.base.controller.JeecgController;
import org.jeecg.common.system.query.QueryGenerator;
import org.jeecg.common.system.vo.LoginUser;
import org.jeecg.common.util.oConvertUtils;
import org.jeecg.config.JeecgBaseConfig;
import org.jeecg.modules.system.entity.SysLog;
import org.jeecg.modules.system.entity.SysRole;
import org.jeecg.modules.system.service.ISysLogService;
import org.jeecgframework.poi.excel.def.NormalExcelConstants;
import org.jeecgframework.poi.excel.entity.ExportParams;
import org.jeecgframework.poi.excel.view.JeecgEntityExcelView;
import org.jeecgframework.poi.handler.inter.IExcelExportServerEnhanced;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
@ -42,6 +51,12 @@ public class SysLogController extends JeecgController<SysLog, ISysLogService> {
@Autowired
private ISysLogService sysLogService;
/**
* for [issues/8699]AutoPoi在使用@ExcelEntity当设置show=true并且该项为null时报错
*/
@Resource
private JeecgBaseConfig jeecgBaseConfig;
/**
* 全部清除
*/
@ -72,10 +87,10 @@ public class SysLogController extends JeecgController<SysLog, ISysLogService> {
//TODO 一个强大的功能,前端传一个字段字符串,后台只返回这些字符串对应的字段
//创建时间/创建人的赋值
IPage<SysLog> pageList = sysLogService.page(page, queryWrapper);
log.info("查询当前页:"+pageList.getCurrent());
log.info("查询当前页数量:"+pageList.getSize());
log.info("查询结果数量:"+pageList.getRecords().size());
log.info("数据总数:"+pageList.getTotal());
// log.info("查询当前页:"+pageList.getCurrent());
// log.info("查询当前页数量:"+pageList.getSize());
// log.info("查询结果数量:"+pageList.getRecords().size());
// log.info("数据总数:"+pageList.getTotal());
result.setSuccess(true);
result.setResult(pageList);
return result;
@ -131,9 +146,74 @@ public class SysLogController extends JeecgController<SysLog, ISysLogService> {
* @param syslog
*/
@RequestMapping(value = "/exportXls")
public ModelAndView exportXls(HttpServletRequest request, SysLog syslog) {
return super.exportXlsForBigData(request, syslog, SysLog.class, "syslog", 10000);
}
public ModelAndView exportXls(HttpServletRequest request, SysLog syslog) {
// 复制参数移除排序相关键column/order 等)防止前端传入排序影响导出顺序
java.util.Map<String, String[]> rawMap = request.getParameterMap();
java.util.Map<String, String[]> paramMap = new java.util.HashMap<>(rawMap);
// 剔除自定义排序参数
paramMap.remove("column");
paramMap.remove("order");
// 组装查询条件(已剔除排序参数)
QueryWrapper<SysLog> queryWrapper = QueryGenerator.initQueryWrapper(syslog, paramMap);
LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
// 过滤选中数据
String selections = request.getParameter("selections");
if (oConvertUtils.isNotEmpty(selections)) {
List<String> selectionList = Arrays.asList(selections.split(","));
queryWrapper.in("id", selectionList);
}
// 定义IExcelExportServer
IExcelExportServerEnhanced<SysLog> excelExportServer = new IExcelExportServerEnhanced<>() {
@Override
public List<SysLog> selectListForExcelExport(Object queryParams, SysLog lastRecord, int pageSize) {
QueryWrapper<SysLog> originalWrapper = (QueryWrapper<SysLog>) queryParams;
// 克隆原始条件,避免多次迭代污染
QueryWrapper<SysLog> batchWrapper = null;
try {
batchWrapper = (QueryWrapper<SysLog>) originalWrapper.clone();
} catch (Exception e) {
batchWrapper = originalWrapper;
}
String lastId = null;
if (lastRecord != null) {
lastId = lastRecord.getId();
final String cursorLastId = lastId;
// 仅基于雪花ID全局唯一数值递增作为游标提升索引利用与性能
// 条件id < 上一批最后一条的ID实现“从大到小”倒序分页
batchWrapper.lt("id", cursorLastId);
}
// 排序:按 id DESC雪花ID递增倒序可获取最新数据
batchWrapper.orderByDesc("id");
Page<SysLog> cursorPage = new Page<>(1, pageSize);
List<SysLog> list = service.page(cursorPage, batchWrapper).getRecords();
log.info("系统日志游标导出(ID游标) - lastId: {} batchSize: {} 返回: {}", lastId, pageSize, list.size());
if (!list.isEmpty()) {
SysLog endRecord = list.get(list.size() - 1);
log.debug("本批次最后一条记录游标ID -> id: {}", endRecord.getId());
}
return list;
}
@Override
public int getPageSize() {
return 10000;
}
};
String title = "系统日志";
// AutoPoi 导出Excel
ModelAndView mv = new ModelAndView(new JeecgEntityExcelView());
//此处设置的filename无效 ,前端会重更新设置一下
mv.addObject(NormalExcelConstants.FILE_NAME, title);
mv.addObject(NormalExcelConstants.CLASS, SysLog.class);
ExportParams exportParams = new ExportParams(title + "报表", "导出人:" + sysUser.getRealname(), title, jeecgBaseConfig.getPath().getUpload());
mv.addObject(NormalExcelConstants.PARAMS, exportParams);
mv.addObject(NormalExcelConstants.EXPORT_SERVER, excelExportServer);
mv.addObject(NormalExcelConstants.QUERY_PARAMS, queryWrapper);
return mv;
}
}

View File

@ -111,7 +111,7 @@ public class SysPermissionController {
}
result.setResult(treeList);
result.setSuccess(true);
log.info("======获取全部菜单数据=====耗时:" + (System.currentTimeMillis() - start) + "毫秒");
log.debug("======获取全部菜单数据=====耗时:" + (System.currentTimeMillis() - start) + "毫秒");
} catch (Exception e) {
log.error(e.getMessage(), e);
}
@ -176,7 +176,6 @@ public class SysPermissionController {
}
/*update_end author:wuxianquan date:20190908 for:先查询一级菜单,当用户点击展开菜单时加载子菜单 */
// update_begin author:sunjianlei date:20200108 for: 新增批量根据父ID查询子级菜单的接口 -------------
/**
* 查询子菜单
*
@ -210,7 +209,6 @@ public class SysPermissionController {
return Result.error("批量查询子菜单失败:" + e.getMessage());
}
}
// update_end author:sunjianlei date:20200108 for: 新增批量根据父ID查询子级菜单的接口 -------------
// /**
// * 查询用户拥有的菜单权限和按钮权限(根据用户账号)
@ -251,15 +249,13 @@ public class SysPermissionController {
}
List<SysPermission> metaList = sysPermissionService.queryByUser(loginUser.getId());
//添加首页路由
//update-begin-author:taoyan date:20200211 for: TASK #3368 【路由缓存】首页的缓存设置有问题,需要根据后台的路由配置来实现是否缓存
//update-begin--Author:zyf Date:20220425 for:自定义首页地址 LOWCOD-1578
// 代码逻辑说明: 自定义首页地址 LOWCOD-1578
String version = request.getHeader(CommonConstant.VERSION);
SysRoleIndex defIndexCfg = sysUserService.getDynamicIndexByUserRole(loginUser.getUsername(), version);
if (defIndexCfg == null) {
defIndexCfg = sysRoleIndexService.initDefaultIndex();
}
//update-end--Author:zyf Date:20220425 for自定义首页地址 LOWCOD-1578
// 如果没有授权角色首页,则自动添加首页路由
if (!PermissionDataUtil.hasIndexPage(metaList, defIndexCfg)) {
@ -284,7 +280,6 @@ public class SysPermissionController {
}
metaList.add(0, indexMenu);
}
//update-end-author:taoyan date:20200211 for: TASK #3368 【路由缓存】首页的缓存设置有问题,需要根据后台的路由配置来实现是否缓存
/* TODO 注: 这段代码的主要作用是:把首页菜单的组件替换成角色菜单的组件,由于现在的逻辑如果角色菜单不存在则自动插入一条,所以这段代码暂时不需要
List<SysPermission> menus = metaList.stream().filter(sysPermission -> {
@ -293,7 +288,7 @@ public class SysPermissionController {
}
return defIndexCfg.getUrl().equals(sysPermission.getUrl());
}).collect(Collectors.toList());
//update-begin---author:liusq ---date:2022-06-29 for设置自定义首页地址和组件----------
// 代码逻辑说明: 设置自定义首页地址和组件----------
if (menus.size() == 1) {
String component = defIndexCfg.getComponent();
String routeUrl = defIndexCfg.getUrl();
@ -306,7 +301,6 @@ public class SysPermissionController {
menus.get(0).setComponent(component);
}
}
//update-end---author:liusq ---date:2022-06-29 for设置自定义首页地址和组件-----------
*/
JSONObject json = new JSONObject();
@ -596,20 +590,17 @@ public class SysPermissionController {
String permissionIds = json.getString("permissionIds");
String lastPermissionIds = json.getString("lastpermissionIds");
this.sysRolePermissionService.saveRolePermission(roleId, permissionIds, lastPermissionIds);
//update-begin---author:wangshuai ---date:20220316 for[VUEN-234]用户管理角色授权添加敏感日志------------
// 代码逻辑说明: [VUEN-234]用户管理角色授权添加敏感日志------------
LoginUser loginUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
baseCommonService.addLog("修改角色ID: "+roleId+" 的权限配置,操作人: " +loginUser.getUsername() ,CommonConstant.LOG_TYPE_2, 2);
//update-end---author:wangshuai ---date:20220316 for[VUEN-234]用户管理角色授权添加敏感日志------------
result.success("保存成功!");
log.info("======角色授权成功=====耗时:" + (System.currentTimeMillis() - start) + "毫秒");
//update-begin---author:scott ---date:2024-06-18 for【TV360X-1320】分配权限必须退出重新登录才生效造成很多用户困扰---
// 清除当前用户的授权缓存信息
Subject currentUser = SecurityUtils.getSubject();
if (currentUser.isAuthenticated()) {
shiroRealm.clearCache(currentUser.getPrincipals());
}
//update-end---author:scott ---date::2024-06-18 for【TV360X-1320】分配权限必须退出重新登录才生效造成很多用户困扰---
} catch (Exception e) {
result.error500("授权失败!");
@ -836,12 +827,11 @@ public class SysPermissionController {
meta.put("title", permission.getName());
//update-begin--Author:scott Date:20201015 for路由缓存问题关闭了tab页时再打开就不刷新 #842
// 代码逻辑说明: 路由缓存问题关闭了tab页时再打开就不刷新 #842
String component = permission.getComponent();
if(oConvertUtils.isNotEmpty(permission.getComponentName()) || oConvertUtils.isNotEmpty(component)){
meta.put("componentName", oConvertUtils.getString(permission.getComponentName(),component.substring(component.lastIndexOf("/")+1)));
}
//update-end--Author:scott Date:20201015 for路由缓存问题关闭了tab页时再打开就不刷新 #842
if (oConvertUtils.isEmpty(permission.getParentId())) {
// 一级菜单跳转地址
@ -857,11 +847,10 @@ public class SysPermissionController {
if (isWwwHttpUrl(permission.getUrl())) {
meta.put("url", permission.getUrl());
}
// update-begin--Author:sunjianlei Date:20210918 for新增适配vue3项目的隐藏tab功能
// 代码逻辑说明: 新增适配vue3项目的隐藏tab功能
if (permission.isHideTab()) {
meta.put("hideTab", true);
}
// update-end--Author:sunjianlei Date:20210918 for新增适配vue3项目的隐藏tab功能
json.put("meta", meta);
}

View File

@ -27,6 +27,7 @@ import org.jeecgframework.poi.excel.ExcelImportUtil;
import org.jeecgframework.poi.excel.def.NormalExcelConstants;
import org.jeecgframework.poi.excel.entity.ExportParams;
import org.jeecgframework.poi.excel.entity.ImportParams;
import org.jeecgframework.poi.excel.entity.enmus.ExcelType;
import org.jeecgframework.poi.excel.view.JeecgEntityExcelView;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
@ -111,13 +112,11 @@ public class SysPositionController {
public Result<SysPosition> add(@RequestBody SysPosition sysPosition) {
Result<SysPosition> result = new Result<SysPosition>();
try {
//update-begin---author:wangshuai ---date:20230313 for【QQYUN-4558】vue3职位功能调整去掉编码和级别可以先隐藏------------
//编号是空的,不需要判断多租户隔离了
if(oConvertUtils.isEmpty(sysPosition.getCode())){
//生成职位编码10位
sysPosition.setCode(RandomUtil.randomString(10));
}
//update-end---author:wangshuai ---date:20230313 for【QQYUN-4558】vue3职位功能调整去掉编码和级别可以先隐藏-------------
sysPositionService.save(sysPosition);
result.success("添加成功!");
} catch (Exception e) {
@ -240,12 +239,11 @@ public class SysPositionController {
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
//update-begin--Author:liusq Date:20240715 for[03]职务导出,如果选择数据则只导出相关数据--------------------
// 代码逻辑说明: [03]职务导出,如果选择数据则只导出相关数据--------------------
String selections = request.getParameter("selections");
if(!oConvertUtils.isEmpty(selections)){
queryWrapper.in("id",selections.split(","));
}
//update-end--Author:liusq Date:20240715 for[03]职务导出,如果选择数据则只导出相关数据----------------------
//Step.2 AutoPoi 导出Excel
ModelAndView mv = new ModelAndView(new JeecgEntityExcelView());
List<SysPosition> pageList = sysPositionService.list(queryWrapper);
@ -253,8 +251,14 @@ public class SysPositionController {
//导出文件名称
mv.addObject(NormalExcelConstants.FILE_NAME, "职务表列表");
mv.addObject(NormalExcelConstants.CLASS, SysPosition.class);
mv.addObject(NormalExcelConstants.PARAMS, new ExportParams("职务表列表数据", "导出人:"+user.getRealname(),"导出信息"));
//支持导出xlsx格式
mv.addObject(NormalExcelConstants.PARAMS, new ExportParams("职务表列表数据", "导出人:"+user.getRealname(),"导出信息", ExcelType.XSSF));
mv.addObject(NormalExcelConstants.DATA_LIST, pageList);
//职级导出支持导出字段
String exportFields = request.getParameter(NormalExcelConstants.EXPORT_FIELDS);
if(oConvertUtils.isNotEmpty(exportFields)){
mv.addObject(NormalExcelConstants.EXPORT_FIELDS, exportFields);
}
return mv;
}

View File

@ -33,6 +33,7 @@ import org.jeecg.modules.system.vo.SysUserRoleCountVo;
import org.jeecgframework.poi.excel.def.NormalExcelConstants;
import org.jeecgframework.poi.excel.entity.ExportParams;
import org.jeecgframework.poi.excel.entity.ImportParams;
import org.jeecgframework.poi.excel.entity.enmus.ExcelType;
import org.jeecgframework.poi.excel.view.JeecgEntityExcelView;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
@ -103,11 +104,10 @@ public class SysRoleController {
@RequestParam(name="pageSize", defaultValue="10") Integer pageSize,
@RequestParam(name="isMultiTranslate", required = false) Boolean isMultiTranslate,
HttpServletRequest req) {
//update-begin---author:wangshuai---date:2025-03-26---for:【issues/7948】角色解决根据id查询回显不对---
// 代码逻辑说明: 【issues/7948】角色解决根据id查询回显不对---
if(null != isMultiTranslate && isMultiTranslate){
pageSize = 100;
}
//update-end---author:wangshuai---date:2025-03-26---for:【issues/7948】角色解决根据id查询回显不对---
Result<IPage<SysRole>> result = new Result<IPage<SysRole>>();
//QueryWrapper<SysRole> queryWrapper = QueryGenerator.initQueryWrapper(role, req.getParameterMap());
//IPage<SysRole> pageList = sysRoleService.page(page, queryWrapper);
@ -157,9 +157,8 @@ public class SysRoleController {
Result<SysRole> result = new Result<SysRole>();
try {
//开启多租户隔离,角色id自动生成10位
//update-begin---author:wangshuai---date:2024-05-23---for:【TV360X-42】角色新增时设置的编码保存后不一致---
// 代码逻辑说明: 【TV360X-42】角色新增时设置的编码保存后不一致---
if(MybatisPlusSaasConfig.OPEN_SYSTEM_TENANT_CONTROL && oConvertUtils.isEmpty(role.getRoleCode())){
//update-end---author:wangshuai---date:2024-05-23---for:【TV360X-42】角色新增时设置的编码保存后不一致---
role.setRoleCode(RandomUtil.randomString(10));
}
role.setCreateTime(new Date());
@ -230,10 +229,8 @@ public class SysRoleController {
}
}
//update-begin---author:wangshuai---date:2024-01-16---for:【QQYUN-7974】禁止删除 admin 角色---
//是否存在admin角色
sysRoleService.checkAdminRoleRejectDel(id);
//update-end---author:wangshuai---date:2024-01-16---for:【QQYUN-7974】禁止删除 admin 角色---
sysRoleService.deleteRole(id);
@ -401,8 +398,14 @@ public class SysRoleController {
mv.addObject(NormalExcelConstants.FILE_NAME,"角色列表");
mv.addObject(NormalExcelConstants.CLASS,SysRole.class);
LoginUser user = (LoginUser) SecurityUtils.getSubject().getPrincipal();
mv.addObject(NormalExcelConstants.PARAMS,new ExportParams("角色列表数据","导出人:"+user.getRealname(),"导出信息"));
//导出支持xlsx
mv.addObject(NormalExcelConstants.PARAMS,new ExportParams("角色列表数据","导出人:"+user.getRealname(),"导出信息", ExcelType.XSSF));
mv.addObject(NormalExcelConstants.DATA_LIST,pageList);
//角色支持指定字段导出
String exportFields = request.getParameter(NormalExcelConstants.EXPORT_FIELDS);
if(oConvertUtils.isNotEmpty(exportFields)){
mv.addObject(NormalExcelConstants.EXPORT_FIELDS, exportFields);
}
return mv;
}

View File

@ -91,6 +91,8 @@ public class SysRoleIndexController extends JeecgController<SysRoleIndex, ISysRo
sysRoleIndex.setRelationType(CommonConstant.HOME_RELATION_ROLE);
}
sysRoleIndexService.save(sysRoleIndex);
//更新其他全局配置的状态
sysRoleIndexService.updateOtherDefaultStatus(sysRoleIndex.getRoleCode(),sysRoleIndex.getStatus(),sysRoleIndex.getId());
sysRoleIndexService.cleanDefaultIndexCache();
return Result.OK("添加成功!");
}
@ -112,6 +114,8 @@ public class SysRoleIndexController extends JeecgController<SysRoleIndex, ISysRo
sysRoleIndex.setRelationType(CommonConstant.HOME_RELATION_ROLE);
}
sysRoleIndexService.updateById(sysRoleIndex);
//更新其他全局配置的状态
sysRoleIndexService.updateOtherDefaultStatus(sysRoleIndex.getRoleCode(),sysRoleIndex.getStatus(),sysRoleIndex.getId());
sysRoleIndexService.cleanDefaultIndexCache();
return Result.OK("编辑成功!");
}
@ -236,7 +240,7 @@ public class SysRoleIndexController extends JeecgController<SysRoleIndex, ISysRo
String username = JwtUtil.getUserNameByToken(request);
sysRoleIndex.setRoleCode(username);
sysRoleIndexService.changeDefHome(sysRoleIndex);
//update-begin-author:liusq---date:2025-07-03--for: 切换完成后的homePath获取
// 代码逻辑说明: 切换完成后的homePath获取
String version = request.getHeader(CommonConstant.VERSION);
String homePath = null;
SysRoleIndex defIndexCfg = sysUserService.getDynamicIndexByUserRole(username, version);
@ -249,7 +253,6 @@ public class SysRoleIndexController extends JeecgController<SysRoleIndex, ISysRo
homePath = SymbolConstant.SINGLE_SLASH + homePath;
}
}
//update-end-author:liusq---date:2025-07-03--for:切换完成后的homePath获取
return Result.OK(homePath);
}
/**
@ -261,7 +264,7 @@ public class SysRoleIndexController extends JeecgController<SysRoleIndex, ISysRo
public Result<?> getCurrentHome(HttpServletRequest request) {
String username = JwtUtil.getUserNameByToken(request);
Object homeType = redisUtil.get(DefIndexConst.CACHE_TYPE + username);
return Result.OK(oConvertUtils.getString(homeType,DefIndexConst.HOME_TYPE_SYSTEM));
return Result.OK(oConvertUtils.getString(homeType,DefIndexConst.HOME_TYPE_MENU));
}
/**

View File

@ -248,10 +248,9 @@ public class SysTenantController {
idList.add(Integer.parseInt(id));
}
//update-begin---author:wangshuai ---date:20230710 for【QQYUN-5723】3、租户删除直接删除不删除中间表------------
// 代码逻辑说明: 【QQYUN-5723】3、租户删除直接删除不删除中间表------------
sysTenantService.removeByIds(idList);
result.success("删除成功!");
//update-end---author:wangshuai ---date:20220523 for【QQYUN-5723】3、租户删除直接删除不删除中间表------------
}
return result;
}
@ -386,11 +385,10 @@ public class SysTenantController {
Result<Map<String,Object>> result = new Result<Map<String,Object>>();
try {
LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
//update-begin---author:wangshuai ---date:20221223 for[QQYUN-3371]租户逻辑改造,改成关系表------------
// 代码逻辑说明: [QQYUN-3371]租户逻辑改造,改成关系表------------
List<Integer> tenantIdList = relationService.getTenantIdsByUserId(sysUser.getId());
Map<String,Object> map = new HashMap(5);
if (null!=tenantIdList && tenantIdList.size()>0) {
//update-end---author:wangshuai ---date:20221223 for[QQYUN-3371]租户逻辑改造,改成关系表------------
// 该方法仅查询有效的租户如果返回0个就说明所有的租户均无效。
List<SysTenant> tenantList = sysTenantService.queryEffectiveTenant(tenantIdList);
map.put("list", tenantList);
@ -530,7 +528,6 @@ public class SysTenantController {
}
}
//update-begin---author:wangshuai ---date:20230107 for[QQYUN-3725]申请加入租户,审核中状态增加接口------------
/**
* 分页获取租户用户数据(vue3用户租户页面)【低代码应用专用接口】
*
@ -615,7 +612,6 @@ public class SysTenantController {
sysTenantService.removeById(sysTenant.getId());
return Result.ok("注销成功");
}
//update-end---author:wangshuai ---date:20230107 for[QQYUN-3725]申请加入租户,审核中状态增加接口------------
/**
* 获取租户用户不同状态下的数量【低代码应用专用接口】
@ -877,13 +873,12 @@ public class SysTenantController {
@GetMapping("/getTenantCount")
public Result<Map<String,Long>> getTenantCount(HttpServletRequest request){
Map<String,Long> map = new HashMap<>();
//update-begin---author:wangshuai---date:2023-11-24---for:【QQYUN-7177】用户数量显示不正确---
// 代码逻辑说明: 【QQYUN-7177】用户数量显示不正确---
if(oConvertUtils.isEmpty(TokenUtils.getTenantIdByRequest(request))){
return Result.error("当前租户为空,禁止访问!");
}
Integer tenantId = oConvertUtils.getInt(TokenUtils.getTenantIdByRequest(request));
Long userCount = relationService.getUserCount(tenantId,CommonConstant.USER_TENANT_NORMAL);
//update-end---author:wangshuai---date:2023-11-24---for:【QQYUN-7177】用户数量显示不正确---
map.put("userCount",userCount);
LambdaQueryWrapper<SysDepart> departQuery = new LambdaQueryWrapper<>();
departQuery.eq(SysDepart::getDelFlag,String.valueOf(CommonConstant.DEL_FLAG_0));

View File

@ -3,6 +3,7 @@ package org.jeecg.modules.system.controller;
import cn.hutool.core.util.RandomUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
@ -12,16 +13,21 @@ import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.apache.shiro.authz.annotation.RequiresRoles;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.aspect.annotation.PermissionData;
import org.jeecg.common.base.BaseMap;
import org.jeecg.common.config.TenantContext;
import org.jeecg.common.constant.CacheConstant;
import org.jeecg.common.constant.CommonConstant;
import org.jeecg.common.constant.PasswordConstant;
import org.jeecg.common.constant.SymbolConstant;
import org.jeecg.common.modules.redis.client.JeecgRedisClient;
import org.jeecg.common.system.query.QueryGenerator;
import org.jeecg.common.system.util.JwtUtil;
import org.jeecg.common.system.vo.LoginUser;
import org.jeecg.common.util.*;
import org.jeecg.config.JeecgBaseConfig;
import org.jeecg.config.mybatis.MybatisPlusSaasConfig;
import org.jeecg.modules.base.service.BaseCommonService;
import org.jeecg.modules.system.entity.*;
@ -38,6 +44,7 @@ import org.jeecg.modules.system.vo.lowapp.DepartAndUserInfo;
import org.jeecg.modules.system.vo.lowapp.UpdateDepartInfo;
import org.jeecgframework.poi.excel.def.NormalExcelConstants;
import org.jeecgframework.poi.excel.entity.ExportParams;
import org.jeecgframework.poi.excel.entity.enmus.ExcelType;
import org.jeecgframework.poi.excel.view.JeecgEntityExcelView;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
@ -47,6 +54,8 @@ import org.springframework.web.servlet.ModelAndView;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.*;
import java.util.stream.Collectors;
@ -98,6 +107,8 @@ public class SysUserController {
@Autowired
private JeecgRedisClient jeecgRedisClient;
@Autowired
private JeecgBaseConfig jeecgBaseConfig;
/**
* 获取租户下用户数据(支持租户隔离)
@ -161,6 +172,7 @@ public class SysUserController {
user.setDelFlag(CommonConstant.DEL_FLAG_0);
//用户表字段org_code不能在这里设置他的值
user.setOrgCode(null);
user.setLastPwdUpdateTime(new Date());
// 保存用户走一个service 保证事务
//获取租户ids
String relTenantIds = jsonObject.getString("relTenantIds");
@ -200,7 +212,10 @@ public class SysUserController {
//获取租户ids
String relTenantIds = jsonObject.getString("relTenantIds");
String updateFromPage = jsonObject.getString("updateFromPage");
sysUserService.editUser(user, roles, departs, relTenantIds, updateFromPage);
//update-begin---author:wangshuai---date:2025-11-12---for:【JHHB-776】用户编辑应该从数据库查出老数据页面传递什么字段把这些字段覆盖数据库查询结果再更新---
oConvertUtils.copyNonNullFields(user, sysUser);
sysUserService.editUser(sysUser, roles, departs, relTenantIds, updateFromPage);
//update-end---author:wangshuai---date:2025-11-12---for:【JHHB-776】用户编辑应该从数据库查出老数据页面传递什么字段把这些字段覆盖数据库查询结果再更新---
result.success("修改成功!");
}
} catch (Exception e) {
@ -259,9 +274,8 @@ public class SysUserController {
String[] arr = ids.split(",");
for (String id : arr) {
if(oConvertUtils.isNotEmpty(id)) {
//update-begin---author:liusq ---date:20230620 for[QQYUN-5577]用户列表-冻结用户,再解冻之后,用户还是无法登陆,有缓存问题 #5066------------
// 代码逻辑说明: [QQYUN-5577]用户列表-冻结用户,再解冻之后,用户还是无法登陆,有缓存问题 #5066------------
sysUserService.updateStatus(id,status);
//update-end---author:liusq ---date:20230620 for[QQYUN-5577]用户列表-冻结用户,再解冻之后,用户还是无法登陆,有缓存问题 #5066------------
}
}
} catch (Exception e) {
@ -271,6 +285,26 @@ public class SysUserController {
result.success("操作成功!");
return result;
}
/**
* 重置为系统密码接口
* @param usernames
* @return
*/
@RequiresRoles({"admin"})
@RequiresPermissions("system:user:resetPassword")
@RequestMapping(value = "/resetPassword", method = RequestMethod.PUT)
public Result<SysUser> resetPassword(@RequestParam(name = "usernames") String usernames) {
Result<SysUser> result = new Result<SysUser>();
try {
sysUserService.resetToSysPassword(usernames);
result.success("操作成功!");
} catch (Exception e) {
log.error(e.getMessage(), e);
result.error500(e.getMessage());
}
return result;
}
@RequiresPermissions("system:user:queryById")
@ -342,16 +376,23 @@ public class SysUserController {
*/
@RequiresPermissions("system:user:changepwd")
@RequestMapping(value = "/changePassword", method = RequestMethod.PUT)
public Result<?> changePassword(@RequestBody SysUser sysUser) {
public Result<?> changePassword(@RequestBody SysUser sysUser, HttpServletRequest request) {
//-------------------------------------------------------------------------------------
//增加 check防止恶意刷短信接口
String clientIp = IpUtils.getIpAddr(request);
if(!DySmsLimit.canSendSms(clientIp)){
log.warn("-------- IP地址:{}, 短信接口请求太多,有攻击风险!", clientIp);
return Result.error("短信接口请求太多,请稍后再试!");
}
//-------------------------------------------------------------------------------------
SysUser u = this.sysUserService.getOne(new LambdaQueryWrapper<SysUser>().eq(SysUser::getUsername, sysUser.getUsername()));
if (u == null) {
return Result.error("用户不存在!");
}
sysUser.setId(u.getId());
//update-begin---author:wangshuai ---date:20220316 for[VUEN-234]修改密码添加敏感日志------------
// 代码逻辑说明: [VUEN-234]修改密码添加敏感日志------------
LoginUser loginUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
baseCommonService.addLog("修改用户 "+sysUser.getUsername()+" 的密码,操作人: " +loginUser.getUsername() ,CommonConstant.LOG_TYPE_2, 2);
//update-end---author:wangshuai ---date:20220316 for[VUEN-234]修改密码添加敏感日志------------
return sysUserService.changePassword(sysUser);
}
@ -392,7 +433,7 @@ public class SysUserController {
@RequestMapping(value = "/generateUserId", method = RequestMethod.GET)
public Result<String> generateUserId() {
Result<String> result = new Result<>();
System.out.println("我执行了,生成用户ID==============================");
//System.out.println("我执行了,生成用户ID==============================");
String userId = UUID.randomUUID().toString().replace("-", "");
result.setSuccess(true);
result.setResult(userId);
@ -450,10 +491,9 @@ public class SysUserController {
@RequestParam(name="username",required=false) String username,
@RequestParam(name="isMultiTranslate",required=false) String isMultiTranslate,
@RequestParam(name="id",required = false) String id) {
//update-begin-author:taoyan date:2022-7-14 for: VUEN-1702【禁止问题】sql注入漏洞
// 代码逻辑说明: VUEN-1702【禁止问题】sql注入漏洞
String[] arr = new String[]{departId, realname, username, id};
SqlInjectionUtil.filterContent(arr, SymbolConstant.SINGLE_QUOTATION_MARK);
//update-end-author:taoyan date:2022-7-14 for: VUEN-1702【禁止问题】sql注入漏洞
IPage<SysUser> pageList = sysUserDepartService.queryDepartUserPageList(departId, username, realname, pageSize, pageNo,id,isMultiTranslate);
return Result.OK(pageList);
}
@ -469,17 +509,34 @@ public class SysUserController {
public ModelAndView exportXls(SysUser sysUser,HttpServletRequest request) {
// Step.1 组装查询条件
QueryWrapper<SysUser> queryWrapper = QueryGenerator.initQueryWrapper(sysUser, request.getParameterMap());
queryWrapper.ne("username", "_reserve_user_external");
//Step.2 AutoPoi 导出Excel
ModelAndView mv = new ModelAndView(new JeecgEntityExcelView());
//update-begin--Author:kangxiaolin Date:20180825 for[03]用户导出,如果选择数据则只导出相关数据--------------------
// 代码逻辑说明: [03]用户导出,如果选择数据则只导出相关数据--------------------
String selections = request.getParameter("selections");
if(!oConvertUtils.isEmpty(selections)){
queryWrapper.in("id",selections.split(","));
}
//update-end--Author:kangxiaolin Date:20180825 for[03]用户导出,如果选择数据则只导出相关数据----------------------
List<SysUser> pageList = sysUserService.list(queryWrapper);
List<SysUserExportVo> list = sysUserService.getDepartAndRoleExportMsg(pageList);
//是否存在部门id
boolean izDepartId = true;
String departId = request.getParameter("departId");
if (oConvertUtils.isNotEmpty(departId)) {
LambdaQueryWrapper<SysUserDepart> query = new LambdaQueryWrapper<>();
query.in(SysUserDepart::getDepId, Arrays.asList(departId.split(",")));
List<SysUserDepart> list = sysUserDepartService.list(query);
List<String> userIds = list.stream().map(SysUserDepart::getUserId).collect(Collectors.toList());
if (oConvertUtils.listIsNotEmpty(userIds)) {
queryWrapper.in("id", userIds);
}else{
izDepartId = false;
}
}
List<SysUserExportVo> list = new ArrayList<>();
// 代码逻辑说明: 【JHHB-762】【用户管理】需要支持按组织架构查询用户---
if(izDepartId){
List<SysUser> pageList = sysUserService.list(queryWrapper);
list = sysUserService.getDepartAndRoleExportMsg(pageList);
}
//导出文件名称
mv.addObject(NormalExcelConstants.FILE_NAME, "用户列表");
mv.addObject(NormalExcelConstants.CLASS, SysUserExportVo.class);
@ -495,8 +552,15 @@ public class SysUserController {
exportParams.setTitleHeight((short)70);
exportParams.setStyle(ExcelExportSysUserStyle.class);
exportParams.setImageBasePath(upLoadPath);
//导出为xlsx
exportParams.setType(ExcelType.XSSF);
mv.addObject(NormalExcelConstants.PARAMS, exportParams);
mv.addObject(NormalExcelConstants.DATA_LIST, list);
//用户导出支持导出字段
String exportFields = request.getParameter(NormalExcelConstants.EXPORT_FIELDS);
if(oConvertUtils.isNotEmpty(exportFields)){
mv.addObject(NormalExcelConstants.EXPORT_FIELDS, exportFields);
}
return mv;
}
@ -577,10 +641,9 @@ public class SysUserController {
if(user==null) {
return Result.error("用户不存在!");
}
//update-begin---author:wangshuai ---date:20220316 for[VUEN-234]修改密码添加敏感日志------------
// 代码逻辑说明: [VUEN-234]修改密码添加敏感日志------------
LoginUser loginUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
baseCommonService.addLog("修改密码username " +loginUser.getUsername() ,CommonConstant.LOG_TYPE_2, 2);
//update-end---author:wangshuai ---date:20220316 for[VUEN-234]修改密码添加敏感日志------------
return sysUserService.resetPassword(username,oldpassword,password,confirmpassword);
}
@ -694,10 +757,9 @@ public class SysUserController {
if(oConvertUtils.isEmpty(depId)){
LoginUser user = (LoginUser) SecurityUtils.getSubject().getPrincipal();
int userIdentity = user.getUserIdentity() != null?user.getUserIdentity():CommonConstant.USER_IDENTITY_1;
//update-begin---author:chenrui ---date:20250107 for[QQYUN-10775]验证码可以复用 #7674------------
// 代码逻辑说明: [QQYUN-10775]验证码可以复用 #7674------------
if(oConvertUtils.isNotEmpty(userIdentity) && userIdentity == CommonConstant.USER_IDENTITY_2
&& oConvertUtils.isNotEmpty(user.getDepartIds())) {
//update-end---author:chenrui ---date:20250107 for[QQYUN-10775]验证码可以复用 #7674------------
subDepids = sysDepartService.getMySubDepIdsByDepId(user.getDepartIds());
}
}else{
@ -716,10 +778,8 @@ public class SysUserController {
item.setOrgCode(useDepNames.get(item.getId()));
});
}
//update-begin---author:wangshuai ---date:20221223 for[QQYUN-3371]租户逻辑改造,改成关系表------------
//设置租户id
page.setRecords(userTenantService.setUserTenantIds(page.getRecords()));
//update-end---author:wangshuai ---date:20221223 for[QQYUN-3371]租户逻辑改造,改成关系表------------
result.setSuccess(true);
result.setResult(pageList);
}else{
@ -746,7 +806,7 @@ public class SysUserController {
}
/**
* 根据 orgCode 查询用户,包括子部门下的用户
* 根据 orgCode 查询用户,包括子部门下的用户 【不包含岗位下的用户】
* 针对通讯录模块做的接口,将多个部门的用户合并成一条记录,并转成对前端友好的格式
*/
@GetMapping("/queryByOrgCodeForAddressList")
@ -755,12 +815,91 @@ public class SysUserController {
@RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize,
@RequestParam(name = "orgCode",required = false) String orgCode,
SysUser userParams
) {
IPage page = new Page(pageNo, pageSize);
IPage<SysUserSysDepartModel> pageList = sysUserService.queryUserByOrgCode(orgCode, userParams, page);
List<SysUserSysDepartModel> list = pageList.getRecords();
// 记录所有出现过的 user, key = userId
Map<String, JSONObject> hasUser = new HashMap<>(list.size());
JSONArray resultJson = new JSONArray(list.size());
for (SysUserSysDepartModel item : list) {
String userId = item.getId();
// userId
JSONObject getModel = hasUser.get(userId);
// 之前已存在过该用户,直接合并数据
if (getModel != null) {
String departName = getModel.get("departName").toString();
getModel.put("departName", (departName + " | " + item.getDepartName()));
} else {
// 将用户对象转换为json格式并将部门信息合并到 json 中
JSONObject json = JSON.parseObject(JSON.toJSONString(item));
json.remove("id");
json.put("userId", userId);
json.put("departId", item.getDepartId());
json.put("departName", item.getDepartName());
// json.put("avatar", item.getSysUser().getAvatar());
resultJson.add(json);
hasUser.put(userId, json);
}
}
IPage<JSONObject> result = new Page<>(pageNo, pageSize, pageList.getTotal());
result.setRecords(resultJson.toJavaList(JSONObject.class));
return Result.ok(result);
}
/**
* 根据 orgCode 查询用户,包括公司、子公司、岗位部门下的用户
*/
@GetMapping("/queryDepartPostByOrgCode")
public Result<?> queryDepartPostByOrgCode(@RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo,
@RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize,
@RequestParam(name = "orgCode",required = false) String orgCode,
SysUser userParams
) {
IPage page = new Page(pageNo, pageSize);
IPage<SysUserSysDepPostModel> pageList = sysUserService.queryDepartPostUserByOrgCode(orgCode, userParams, page);
return Result.ok(pageList);
}
/**
* 根据 orgCode 查询用户信息(部门全路径,主岗位和兼职岗位的信息),包括公司、子公司、部门
*/
@GetMapping("/queryDepartUserByOrgCode")
public Result<IPage<SysUserSysDepPostModel>> queryDepartUserByOrgCode(@RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo,
@RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize,
@RequestParam(name = "orgCode",required = false) String orgCode,
SysUser userParams
) {
IPage page = new Page(pageNo, pageSize);
IPage<SysUserSysDepPostModel> pageList = sysUserService.queryDepartUserByOrgCode(orgCode, userParams, page);
return Result.ok(pageList);
}
/**
* 通讯录点击用户获取用户详情(包含用户基本信息、部门全路径、主岗位兼职岗位全路径)
*
* @param userId
* @return
*/
@GetMapping("/getUserDetailByUserId")
public Result<SysUserSysDepPostModel> getUserDetailByUserId(@RequestParam(name = "userId") String userId) {
Result<SysUserSysDepPostModel> result = new Result<SysUserSysDepPostModel>();
try {
SysUserSysDepPostModel sysDepPostModel = sysUserService.getUserDetailByUserId(userId);
result.setSuccess(true);
result.setResult(sysDepPostModel);
} catch (Exception e) {
log.error(e.getMessage(), e);
result.setSuccess(false);
result.setMessage("查询失败: " + e.getMessage());
}
return result;
}
/**
* 给指定部门添加对应的用户
*/
@ -770,15 +909,21 @@ public class SysUserController {
Result<String> result = new Result<String>();
try {
String sysDepId = sysDepartUsersVO.getDepId();
boolean updated = false;
for(String sysUserId:sysDepartUsersVO.getUserIdList()) {
SysUserDepart sysUserDepart = new SysUserDepart(null,sysUserId,sysDepId);
QueryWrapper<SysUserDepart> queryWrapper = new QueryWrapper<SysUserDepart>();
queryWrapper.eq("dep_id", sysDepId).eq("user_id",sysUserId);
SysUserDepart one = sysUserDepartService.getOne(queryWrapper);
if(one==null){
updated = true;
sysUserDepartService.save(sysUserDepart);
}
}
// 【JHHB-737】更新关系后清空用户缓存
if (updated) {
redisUtil.removeAll(CacheConstant.SYS_USERS_CACHE);
}
result.setMessage("添加成功!");
result.setSuccess(true);
return result;
@ -887,10 +1032,9 @@ public class SysUserController {
String phone = jsonObject.getString("phone");
String smscode = jsonObject.getString("smscode");
//update-begin-author:taoyan date:2022-9-13 for: VUEN-2245 【漏洞】发现新漏洞待处理20220906
// 代码逻辑说明: VUEN-2245 【漏洞】发现新漏洞待处理20220906
String redisKey = CommonConstant.PHONE_REDIS_KEY_PRE+phone;
Object code = redisUtil.get(redisKey);
//update-end-author:taoyan date:2022-9-13 for: VUEN-2245 【漏洞】发现新漏洞待处理20220906
String username = jsonObject.getString("username");
//未设置用户名,则用手机号作为用户名
@ -953,6 +1097,7 @@ public class SysUserController {
user.setStatus(CommonConstant.USER_UNFREEZE);
user.setDelFlag(CommonConstant.DEL_FLAG_0);
user.setActivitiSync(CommonConstant.ACT_SYNC_1);
user.setLastPwdUpdateTime(new Date());
sysUserService.addUserWithRole(user,"");//默认临时角色 test
result.success("注册成功");
} catch (Exception e) {
@ -1005,10 +1150,10 @@ public class SysUserController {
Result<Map<String,String>> result = new Result<Map<String,String>>();
String phone = jsonObject.getString("phone");
String smscode = jsonObject.getString("smscode");
//update-begin-author:taoyan date:2022-9-13 for: VUEN-2245 【漏洞】发现新漏洞待处理20220906
// 代码逻辑说明: VUEN-2245 【漏洞】发现新漏洞待处理20220906
String redisKey = CommonConstant.PHONE_REDIS_KEY_PRE+phone;
Object code = redisUtil.get(redisKey);
//update-begin---author:wangshuai---date:2025-07-15---for:【issues/8567】严重修改密码存在水平越权问题。---
// 代码逻辑说明: 【issues/8567】严重修改密码存在水平越权问题。---
if (null == code) {
result.setMessage("短信验证码失效!");
result.setSuccess(false);
@ -1021,14 +1166,12 @@ public class SysUserController {
smsCode = code.toString();
}
if (!smscode.equals(smsCode)) {
//update-end---author:wangshuai---date:2025-07-15---for:【issues/8567】严重修改密码存在水平越权问题。---
result.setMessage("手机验证码错误");
result.setSuccess(false);
return result;
}
//设置有效时间
redisUtil.set(redisKey, code,600);
//update-end-author:taoyan date:2022-9-13 for: VUEN-2245 【漏洞】发现新漏洞待处理20220906
//新增查询用户名
LambdaQueryWrapper<SysUser> query = new LambdaQueryWrapper<>();
@ -1064,17 +1207,16 @@ public class SysUserController {
}
SysUser sysUser=new SysUser();
//update-begin-author:taoyan date:2022-9-13 for: VUEN-2245 【漏洞】发现新漏洞待处理20220906
// 代码逻辑说明: VUEN-2245 【漏洞】发现新漏洞待处理20220906
String redisKey = CommonConstant.PHONE_REDIS_KEY_PRE+phone;
Object object= redisUtil.get(redisKey);
//update-end-author:taoyan date:2022-9-13 for: VUEN-2245 【漏洞】发现新漏洞待处理20220906
if(null==object) {
result.setMessage("短信验证码失效!");
result.setSuccess(false);
return result;
}
//update-begin---author:wangshuai---date:2025-07-14---for:【issues/8567】严重修改密码存在水平越权问题。---
// 代码逻辑说明: 【issues/8567】严重修改密码存在水平越权问题。---
String redisUsername = "";
if(object.toString().contains("code")){
JSONObject jsonObject = JSONObject.parseObject(object.toString());
@ -1087,7 +1229,6 @@ public class SysUserController {
result.setSuccess(false);
return result;
}
//update-end---author:wangshuai---date:2025-07-14---for:【issues/8567】严重修改密码存在水平越权问题。---
if(!smscode.equals(object.toString())) {
result.setMessage("短信验证码不匹配!");
@ -1104,10 +1245,10 @@ public class SysUserController {
sysUser.setSalt(salt);
String passwordEncode = PasswordUtil.encrypt(sysUser.getUsername(), password, salt);
sysUser.setPassword(passwordEncode);
sysUser.setLastPwdUpdateTime(new Date());
this.sysUserService.updateById(sysUser);
//update-begin---author:wangshuai ---date:20220316 for[VUEN-234]密码重置添加敏感日志------------
// 代码逻辑说明: [VUEN-234]密码重置添加敏感日志------------
baseCommonService.addLog("重置 "+username+" 的密码,操作人: " +sysUser.getUsername() ,CommonConstant.LOG_TYPE_2, 2);
//update-end---author:wangshuai ---date:20220316 for[VUEN-234]密码重置添加敏感日志------------
result.setSuccess(true);
result.setMessage("密码重置完成!");
//修改完密码后清空redis
@ -1295,7 +1436,7 @@ public class SysUserController {
sysUser.setPhone(phone);
}
if(StringUtils.isNotBlank(email)){
//update-begin---author:wangshuai ---date:20220708 for[VUEN-1528]积木官网邮箱重复,应该提示准确------------
// 代码逻辑说明: [VUEN-1528]积木官网邮箱重复,应该提示准确------------
LambdaQueryWrapper<SysUser> emailQuery = new LambdaQueryWrapper<>();
emailQuery.eq(SysUser::getEmail,email);
long count = sysUserService.count(emailQuery);
@ -1303,7 +1444,6 @@ public class SysUserController {
result.error500("保存失败,邮箱已存在!");
return result;
}
//update-end---author:wangshuai ---date:20220708 for[VUEN-1528]积木官网邮箱重复,应该提示准确--------------
sysUser.setEmail(email);
}
if(null != birthday){
@ -1324,7 +1464,7 @@ public class SysUserController {
* @return
*/
@RequestMapping(value = "/saveClientId", method = RequestMethod.GET)
public Result<SysUser> saveClientId(HttpServletRequest request,@RequestParam("clientId")String clientId) {
public Result<SysUser> saveClientId(HttpServletRequest request,@RequestParam(value = "clientId",required = false)String clientId) {
Result<SysUser> result = new Result<SysUser>();
try {
String username = JwtUtil.getUserNameByToken(request);
@ -1332,8 +1472,7 @@ public class SysUserController {
if(sysUser==null) {
result.error500("未找到对应用户!");
}else {
sysUser.setClientId(clientId);
sysUserService.updateById(sysUser);
sysUserService.updateClientId(clientId,sysUser.getId());
}
} catch (Exception e) {
log.error(e.getMessage(), e);
@ -1391,7 +1530,7 @@ public class SysUserController {
@RequestParam(name="pageSize", defaultValue="10") Integer pageSize,HttpServletRequest request) {
Result<List<SysUser>> result = new Result<List<SysUser>>();
LambdaQueryWrapper<SysUser> queryWrapper =new LambdaQueryWrapper<SysUser>();
//TODO 外部模拟登陆临时账号,列表不显示
// 外部模拟登陆临时账号,列表不显示
queryWrapper.ne(SysUser::getUsername,"_reserve_user_external");
//增加 username传参
if(oConvertUtils.isNotEmpty(username)){
@ -1407,15 +1546,19 @@ public class SysUserController {
//是否开启系统管理模块的多租户数据隔离【SAAS多租户模式】
if (MybatisPlusSaasConfig.OPEN_SYSTEM_TENANT_CONTROL) {
String tenantId = oConvertUtils.getString(TokenUtils.getTenantIdByRequest(request),"-1");
//update-begin---author:wangshuai ---date:20221223 for[QQYUN-3371]租户逻辑改造,改成关系表------------
// 代码逻辑说明: [QQYUN-3371]租户逻辑改造,改成关系表------------
List<String> userIds = userTenantService.getUserIdsByTenantId(Integer.valueOf(tenantId));
if (oConvertUtils.listIsNotEmpty(userIds)) {
queryWrapper.in(SysUser::getId, userIds);
}
//update-end---author:wangshuai ---date:20221223 for[QQYUN-3371]租户逻辑改造,改成关系表------------
}
//------------------------------------------------------------------------------------------------
Page<SysUser> page = new Page<>(pageNo, pageSize);
// 代码逻辑说明: JHHB-812 【移动端】人员按照排序展示 选择人员,通讯录等 123正序排
queryWrapper.orderByAsc(SysUser::getSort);
queryWrapper.orderByDesc(SysUser::getCreateTime);
IPage<SysUser> pageList = this.sysUserService.page(page, queryWrapper);
//批量查询用户的所属部门
//step.1 先拿到全部的 useids
@ -1448,10 +1591,9 @@ public class SysUserController {
result.setSuccess(false);
return result;
}
//update-begin-author:taoyan date:2022-9-13 for: VUEN-2245 【漏洞】发现新漏洞待处理20220906
// 代码逻辑说明: VUEN-2245 【漏洞】发现新漏洞待处理20220906
String redisKey = CommonConstant.PHONE_REDIS_KEY_PRE+phone;
Object object= redisUtil.get(redisKey);
//update-end-author:taoyan date:2022-9-13 for: VUEN-2245 【漏洞】发现新漏洞待处理20220906
if(null==object) {
result.setMessage("短信验证码失效!");
result.setSuccess(false);
@ -1480,9 +1622,8 @@ public class SysUserController {
@GetMapping("/getMultiUser")
public List<SysUser> getMultiUser(SysUser sysUser){
QueryWrapper<SysUser> queryWrapper = QueryGenerator.initQueryWrapper(sysUser, null);
//update-begin---author:wangshuai ---date:20220104 for[JTC-297]已冻结用户仍可设置为代理人------------
// 代码逻辑说明: [JTC-297]已冻结用户仍可设置为代理人------------
queryWrapper.eq("status",Integer.parseInt(CommonConstant.STATUS_1));
//update-end---author:wangshuai ---date:20220104 for[JTC-297]已冻结用户仍可设置为代理人------------
List<SysUser> ls = this.sysUserService.list(queryWrapper);
for(SysUser user: ls){
user.setPassword(null);
@ -1529,6 +1670,7 @@ public class SysUserController {
@RequestParam(name = "roleId", required = false) String roleId,
@RequestParam(name="keyword",required=false) String keyword,
@RequestParam(name="excludeUserIdList",required = false) String excludeUserIdList,
@RequestParam(name="includeUsernameList",required = false) String includeUsernameList,
HttpServletRequest req) {
//------------------------------------------------------------------------------------------------
Integer tenantId = null;
@ -1539,10 +1681,9 @@ public class SysUserController {
log.info("---------简流中选择用户接口通过租户筛选租户ID={}", tenantId);
}
//------------------------------------------------------------------------------------------------
IPage<SysUser> pageList = sysUserDepartService.getUserInformation(tenantId, departId,roleId, keyword, pageSize, pageNo,excludeUserIdList);
IPage<SysUser> pageList = sysUserDepartService.getUserInformation(tenantId, departId,roleId, keyword, pageSize, pageNo,excludeUserIdList,includeUsernameList);
return Result.OK(pageList);
}
/**
* 获取被逻辑删除的用户列表,无分页【低代码应用专用接口】
@ -1564,6 +1705,23 @@ public class SysUserController {
return Result.ok(quitList);
}
/**
* 更新刪除状态和离职状态【低代码应用专用接口】
* @param jsonObject
* @return Result<String>
*/
@PutMapping("/putCancelQuit")
public Result<String> putCancelQuit(@RequestBody JSONObject jsonObject, HttpServletRequest request){
String userIds = jsonObject.getString("userIds");
String usernames = jsonObject.getString("usernames");
Integer tenantId = oConvertUtils.getInt(TokenUtils.getTenantIdByRequest(request),0);
//将状态改成未删除
if (StringUtils.isNotBlank(userIds)) {
userTenantService.putCancelQuit(Arrays.asList(userIds.split(SymbolConstant.COMMA)),tenantId);
}
return Result.ok("取消离职成功");
}
/**
* 获取用户信息(vue3用户设置专用)【低代码应用专用接口】
* @return
@ -1576,11 +1734,9 @@ public class SysUserController {
return Result.error("未找到该用户数据");
}
//update-begin---author:wangshuai ---date:20230220 for[QQYUN-3980]组织管理中 职位功能 职位表加租户id 加职位-用户关联表------------
//获取用户id通过职位数据
List<SysPosition> sysPositionList = sysPositionService.getPositionList(user.getId());
if(null != sysPositionList && sysPositionList.size()>0){
//update-end---author:wangshuai ---date:20230220 for[QQYUN-3980]组织管理中 职位功能 职位表加租户id 加职位-用户关联表------------
StringBuilder nameBuilder = new StringBuilder();
StringBuilder idBuilder = new StringBuilder();
String verticalBar = " | ";
@ -1686,42 +1842,6 @@ public class SysUserController {
return Result.ok();
}
/**
* 添加用户【后台租户模式专用,敲敲云不要用这个】
*
* @param jsonObject
* @return
*/
@RequiresPermissions("system:user:addTenantUser")
@RequestMapping(value = "/addTenantUser", method = RequestMethod.POST)
public Result<SysUser> addTenantUser(@RequestBody JSONObject jsonObject) {
Result<SysUser> result = new Result<SysUser>();
String selectedRoles = jsonObject.getString("selectedroles");
String selectedDeparts = jsonObject.getString("selecteddeparts");
try {
SysUser user = JSON.parseObject(jsonObject.toJSONString(), SysUser.class);
user.setCreateTime(new Date());//设置创建时间
String salt = oConvertUtils.randomGen(8);
user.setSalt(salt);
String passwordEncode = PasswordUtil.encrypt(user.getUsername(), user.getPassword(), salt);
user.setPassword(passwordEncode);
user.setStatus(1);
user.setDelFlag(CommonConstant.DEL_FLAG_0);
//用户表字段org_code不能在这里设置他的值
user.setOrgCode(null);
// 保存用户走一个service 保证事务
//获取租户ids
String relTenantIds = jsonObject.getString("relTenantIds");
sysUserService.saveUser(user, selectedRoles, selectedDeparts, relTenantIds, true);
baseCommonService.addLog("添加用户username " + user.getUsername(), CommonConstant.LOG_TYPE_2, 2);
result.success("添加成功!");
} catch (Exception e) {
log.error(e.getMessage(), e);
result.error500("操作失败");
}
return result;
}
/**
* 修改租户下的用户【低代码应用专用接口】
* @param sysUser
@ -1899,4 +2019,27 @@ public class SysUserController {
}
return Result.ok(progress);
}
/**
* 验证当前登录用户是否仍使用系统默认初始密码。
* 返回值说明:
* yes_{URL编码后的默认密码} -> 用户当前密码为默认初始密码,前端需弹出强制修改提示
* no -> 用户密码不是默认密码,或未开启默认密码检测开关
*/
@GetMapping("/verifyIzDefaultPwd")
public Result<String> verifyIzDefaultPwd() throws UnsupportedEncodingException {
// 未配置 Firewall 或已关闭默认密码检测开关 (enableDefaultPwdCheck=false) 时,直接返回 "no" 表示无需提示
if (jeecgBaseConfig.getFirewall() == null || Boolean.FALSE.equals((jeecgBaseConfig.getFirewall().getEnableDefaultPwdCheck()))) {
return Result.OK("no");
}
LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
SysUser user = sysUserService.getById(sysUser.getId());
String passwordEncode = PasswordUtil.encrypt(user.getUsername(), PasswordConstant.DEFAULT_PASSWORD, user.getSalt());
if(passwordEncode.equals(user.getPassword())){
String encode = URLEncoder.encode(PasswordConstant.DEFAULT_PASSWORD, "UTF-8");
return Result.OK("yes_" + encode);
}
return Result.OK("no");
}
}

View File

@ -61,7 +61,6 @@ public class SysUserOnlineController {
//TODO 改成一次性查询
LoginUser loginUser = sysBaseApi.getUserByName(JwtUtil.getUsername(token));
if (loginUser != null && !"_reserve_user_external".equals(loginUser.getUsername())) {
//update-begin---author:wangshuai ---date:20220104 for[JTC-382]在线用户查询无效------------
//验证用户名是否与传过来的用户名相同
boolean isMatchUsername=true;
//判断用户名是否为空并且当前循环的用户不包含传过来的用户名那么就设成false
@ -72,7 +71,6 @@ public class SysUserOnlineController {
BeanUtils.copyProperties(loginUser, online);
onlineList.add(online);
}
//update-end---author:wangshuai ---date:20220104 for[JTC-382]在线用户查询无效------------
}
}
}

View File

@ -89,7 +89,6 @@ public class ThirdAppController {
}
enabledMap.put("wechatEnterprise", qywxConfig);
enabledMap.put("dingtalk", dingConfig);
//update-end---author:wangshuai ---date:20230224 for[QQYUN-3440]通过租户模式隔离------------
return Result.OK(enabledMap);
}
@ -101,12 +100,11 @@ public class ThirdAppController {
*/
@GetMapping("/sync/wechatEnterprise/user/toApp")
public Result syncWechatEnterpriseUserToApp(@RequestParam(value = "ids", required = false) String ids) {
//update-begin---author:wangshuai ---date:20230224 for[QQYUN-3440]通过租户模式隔离 ------------
//获取企业微信配置
Integer tenantId = oConvertUtils.getInt(TenantContext.getTenant(),0);
SysThirdAppConfig config = appConfigService.getThirdConfigByThirdType(tenantId, MessageTypeEnum.QYWX.getType());
if (null != config) {
//update-begin---author:wangshuai ---date:20230224 for[QQYUN-3440]通过租户模式隔离 ------------
// 代码逻辑说明: [QQYUN-3440]通过租户模式隔离 ------------
SyncInfoVo syncInfo = wechatEnterpriseService.syncLocalUserToThirdApp(ids);
if (syncInfo.getFailInfo().size() == 0) {
return Result.OK("同步成功", syncInfo);
@ -295,22 +293,19 @@ public class ThirdAppController {
String title = "第三方APP消息测试";
MessageDTO message = new MessageDTO(fromUser, receiver, title, content);
message.setToAll(sendAll);
//update-begin---author:wangshuai ---date:20230224 for[QQYUN-3440]钉钉、企业微信通过租户模式隔离 ------------
// 代码逻辑说明: [QQYUN-3440]钉钉、企业微信通过租户模式隔离 ------------
String weChatType = MessageTypeEnum.QYWX.getType();
String dingType = MessageTypeEnum.DD.getType();
if (weChatType.toUpperCase().equals(app)) {
SysThirdAppConfig config = appConfigService.getThirdConfigByThirdType(tenantId, weChatType);
if (null != config) {
//update-end---author:wangshuai ---date:20230224 for[QQYUN-3440]钉钉、企业微信通过租户模式隔离 ------------
JSONObject response = wechatEnterpriseService.sendMessageResponse(message, false);
return Result.OK(response);
}
return Result.error("企业微信尚未配置,请配置企业微信");
//update-begin---author:wangshuai ---date:20230224 for[QQYUN-3440]钉钉、企业微信通过租户模式隔离 ------------
} else if (dingType.toUpperCase().equals(app)) {
SysThirdAppConfig config = appConfigService.getThirdConfigByThirdType(tenantId, dingType);
if (null != config) {
//update-end---author:wangshuai ---date:20230224 for[QQYUN-3440]钉钉、企业微信通过租户模式隔离 ------------
Response<String> response = dingtalkService.sendMessageResponse(message, false);
return Result.OK(response);
}

View File

@ -103,12 +103,11 @@ public class ThirdLoginController {
//构造第三方登录信息存储对象
ThirdLoginModel tlm = new ThirdLoginModel(source, uuid, username, avatar);
//判断有没有这个人
//update-begin-author:wangshuai date:20201118 for:修改成查询第三方账户表
// 代码逻辑说明: 修改成查询第三方账户表
LambdaQueryWrapper<SysThirdAccount> query = new LambdaQueryWrapper<SysThirdAccount>();
query.eq(SysThirdAccount::getThirdType, source);
//update-begin---author:wangshuai---date:2023-10-07---for:【QQYUN-6667】敲敲云线上解绑重新绑定一直提示这个---
// 代码逻辑说明: 【QQYUN-6667】敲敲云线上解绑重新绑定一直提示这个---
query.eq(SysThirdAccount::getTenantId, CommonConstant.TENANT_ID_DEFAULT_VALUE);
//update-end---author:wangshuai---date:2023-10-07---for:【QQYUN-6667】敲敲云线上解绑重新绑定一直提示这个---
query.and(q -> q.eq(SysThirdAccount::getThirdUserUuid, uuid).or().eq(SysThirdAccount::getThirdUserId, uuid));
List<SysThirdAccount> thridList = sysThirdAccountService.list(query);
SysThirdAccount user = null;
@ -120,7 +119,7 @@ public class ThirdLoginController {
user = thridList.get(0);
}
// 生成token
//update-begin-author:wangshuai date:20201118 for:从第三方登录查询是否存在用户id不存在绑定手机号
// 代码逻辑说明: 从第三方登录查询是否存在用户id不存在绑定手机号
if(oConvertUtils.isNotEmpty(user.getSysUserId())) {
String sysUserId = user.getSysUserId();
SysUser sysUser = sysUserService.getById(sysUserId);
@ -129,12 +128,9 @@ public class ThirdLoginController {
}else{
modelMap.addAttribute("token", "绑定手机号,"+""+uuid);
}
//update-end-author:wangshuai date:20201118 for:从第三方登录查询是否存在用户id不存在绑定手机号
//update-begin--Author:wangshuai Date:20200729 for接口在签名校验失败时返回失败的标识码 issues#1441--------------------
}else{
modelMap.addAttribute("token", "登录失败");
}
//update-end--Author:wangshuai Date:20200729 for接口在签名校验失败时返回失败的标识码 issues#1441--------------------
result.setSuccess(false);
result.setMessage("第三方登录异常,请联系管理员");
return "thirdLogin";
@ -157,14 +153,13 @@ public class ThirdLoginController {
return res;
}
//创建新账号
//update-begin-author:wangshuai date:20201118 for:修改成从第三方登录查出来的user_id在查询用户表尽行token
// 代码逻辑说明: 修改成从第三方登录查出来的user_id在查询用户表尽行token
SysThirdAccount user = sysThirdAccountService.saveThirdUser(model,CommonConstant.TENANT_ID_DEFAULT_VALUE);
if(oConvertUtils.isNotEmpty(user.getSysUserId())){
String sysUserId = user.getSysUserId();
SysUser sysUser = sysUserService.getById(sysUserId);
// 生成token
String token = saveToken(sysUser);
//update-end-author:wangshuai date:20201118 for:修改成从第三方登录查出来的user_id在查询用户表尽行token
res.setResult(token);
res.setSuccess(true);
}
@ -212,7 +207,7 @@ public class ThirdLoginController {
private String saveToken(SysUser user) {
// 生成token
String token = JwtUtil.sign(user.getUsername(), user.getPassword());
String token = JwtUtil.sign(user.getUsername(), user.getPassword(), CommonConstant.CLIENT_TYPE_PC);
redisUtil.set(CommonConstant.PREFIX_USER_TOKEN + token, token);
// 设置超时时间
redisUtil.expire(CommonConstant.PREFIX_USER_TOKEN + token, JwtUtil.EXPIRE_TIME * 2 / 1000);
@ -232,36 +227,33 @@ public class ThirdLoginController {
public Result<JSONObject> getThirdLoginUser(@PathVariable("token") String token,@PathVariable("thirdType") String thirdType,@PathVariable("tenantId") String tenantId) throws Exception {
Result<JSONObject> result = new Result<JSONObject>();
String username = JwtUtil.getUsername(token);
//update-begin---author:chenrui ---date:20250210 for[QQYUN-11021]三方登录接口通过token获取用户信息漏洞修复------------
// 代码逻辑说明: [QQYUN-11021]三方登录接口通过token获取用户信息漏洞修复------------
if (!TokenUtils.verifyToken(token, sysBaseAPI, redisUtil)) {
return Result.noauth("token验证失败");
}
//update-end---author:chenrui ---date:20250210 for[QQYUN-11021]三方登录接口通过token获取用户信息漏洞修复------------
//1. 校验用户是否有效
SysUser sysUser = sysUserService.getUserByName(username);
result = sysUserService.checkUserIsEffective(sysUser);
if(!result.isSuccess()) {
return result;
}
//update-begin-author:wangshuai date:20201118 for:如果真实姓名和头像不存在就取第三方登录的
// 代码逻辑说明: 如果真实姓名和头像不存在就取第三方登录的
LambdaQueryWrapper<SysThirdAccount> query = new LambdaQueryWrapper<>();
query.eq(SysThirdAccount::getSysUserId,sysUser.getId());
query.eq(SysThirdAccount::getThirdType,thirdType);
query.eq(SysThirdAccount::getTenantId,oConvertUtils.getInt(tenantId,CommonConstant.TENANT_ID_DEFAULT_VALUE));
//update-begin---author:wangshuai ---date:20230328 for[QQYUN-4883]钉钉auth登录同一个租户下有同一个用户id------------
// 代码逻辑说明: [QQYUN-4883]钉钉auth登录同一个租户下有同一个用户id------------
List<SysThirdAccount> accountList = sysThirdAccountService.list(query);
SysThirdAccount account = new SysThirdAccount();
if(CollectionUtil.isNotEmpty(accountList)){
account = accountList.get(0);
}
//update-end---author:wangshuai ---date:20230328 for[QQYUN-4883]钉钉auth登录同一个租户下有同一个用户id------------
if(oConvertUtils.isEmpty(sysUser.getRealname())){
sysUser.setRealname(account.getRealname());
}
if(oConvertUtils.isEmpty(sysUser.getAvatar())){
sysUser.setAvatar(account.getAvatar());
}
//update-end-author:wangshuai date:20201118 for:如果真实姓名和头像不存在就取第三方登录的
JSONObject obj = new JSONObject();
//第三方登确定登录租户和部门逻辑
this.setUserTenantAndDepart(sysUser,obj,result);
@ -292,10 +284,9 @@ public class ThirdLoginController {
String thirdUserUuid = jsonObject.getString("thirdUserUuid");
// 校验验证码
String captcha = jsonObject.getString("captcha");
//update-begin-author:taoyan date:2022-9-13 for: VUEN-2245 【漏洞】发现新漏洞待处理20220906
// 代码逻辑说明: VUEN-2245 【漏洞】发现新漏洞待处理20220906
String redisKey = CommonConstant.PHONE_REDIS_KEY_PRE+phone;
Object captchaCache = redisUtil.get(redisKey);
//update-end-author:taoyan date:2022-9-13 for: VUEN-2245 【漏洞】发现新漏洞待处理20220906
if (oConvertUtils.isEmpty(captcha) || !captcha.equals(captchaCache)) {
result.setMessage("验证码错误");
result.setSuccess(false);
@ -357,13 +348,11 @@ public class ThirdLoginController {
builder.append("#wechat_redirect");
url = builder.toString();
} else if (CommonConstant.DINGTALK.equalsIgnoreCase(source)) {
//update-begin---author:wangshuai ---date:20230224 for[QQYUN-3440]新建企业微信和钉钉配置表,通过租户模式隔离------------
//换成第三方app配置表
SysThirdAppConfig appConfig = appConfigService.getThirdConfigByThirdType(Integer.valueOf(tenantId), MessageTypeEnum.DD.getType());
if(null == appConfig){
return "还未配置钉钉应用,请配置钉钉应用";
}
//update-end---author:wangshuai ---date:20230224 for[QQYUN-3440]新建企业微信和钉钉配置表,通过租户模式隔离------------
StringBuilder builder = new StringBuilder();
// 构造钉钉OAuth2登录授权地址
builder.append("https://login.dingtalk.com/oauth2/auth");
@ -382,9 +371,8 @@ public class ThirdLoginController {
builder.append("&scope=openid");
// 跟随authCode原样返回。
builder.append("&state=").append(state);
//update-begin---author:wangshuai ---date:20220613 for[issues/I5BOUF]oauth2 钉钉无法登录------------
// 代码逻辑说明: [issues/I5BOUF]oauth2 钉钉无法登录------------
builder.append("&prompt=").append("consent");
//update-end---author:wangshuai ---date:20220613 for[issues/I5BOUF]oauth2 钉钉无法登录--------------
url = builder.toString();
} else {
return "不支持的source";
@ -430,8 +418,7 @@ public class ThirdLoginController {
return "不支持的source";
}
try {
//update-begin-author:taoyan date:2022-6-30 for: 工作流发送消息 点击消息链接跳转办理页面
// 代码逻辑说明: 工作流发送消息 点击消息链接跳转办理页面
String redirect = "";
if (state.indexOf("?") > 0) {
String[] arr = state.split("\\?");
@ -443,15 +430,13 @@ public class ThirdLoginController {
String token = saveToken(loginUser);
state += "/oauth2-app/login?oauth2LoginToken=" + URLEncoder.encode(token, "UTF-8") + "&tenantId=" + URLEncoder.encode(tenantId, "UTF-8");
//update-begin---author:wangshuai ---date:20220613 for[issues/I5BOUF]oauth2 钉钉无法登录------------
// 代码逻辑说明: [issues/I5BOUF]oauth2 钉钉无法登录------------
state += "&thirdType=" + source;
//state += "&thirdType=" + "wechat_enterprise";
if (redirect != null && redirect.length() > 0) {
state += "&" + redirect;
}
//update-end-author:taoyan date:2022-6-30 for: 工作流发送消息 点击消息链接跳转办理页面
//update-end---author:wangshuai ---date:20220613 for[issues/I5BOUF]oauth2 钉钉无法登录------------
log.info("OAuth2登录重定向地址: " + state);
try {
response.sendRedirect(state);

View File

@ -79,6 +79,9 @@ public class SysAppVersion implements Serializable {
/**热更新路径*/
@Schema(description = "热更新路径")
private String wgtUrl;
/**热更新路径*/
@Schema(description = "桌面端下载路径")
private String webDownloadUrl;
/**更新内容*/
@Schema(description = "更新内容")
private String updateNote;

View File

@ -84,12 +84,10 @@ public class SysDataLog implements Serializable {
private String dataVersion;
//update-begin-author:taoyan date:2022-7-26 for: 用于表单评论记录日志 区分数据
/**
* 类型
* 类型,用于表单评论记录日志 区分数据
*/
private String type;
//update-end-author:taoyan date:2022-7-26 for: 用于表单评论记录日志 区分数据
/**
* 通过 loginUser 设置 createName

View File

@ -240,7 +240,36 @@ public class SysUser implements Serializable {
/**
* 职务(字典)
*/
@Excel(name = "职务", width = 15, dicCode = "position_type")
@Dict(dicCode = "position_type")
@Excel(name = "职务", width = 15, dicCode = "user_position")
@Dict(dicCode = "user_position")
private String positionType;
/**
* 上一次修改密码的时间
*/
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date lastPwdUpdateTime;
/**
* 登录时,选择的部门,临时用,不持久化数据库(数据库字段不存在)
*/
@TableField(exist = false)
private String loginOrgCode;
/**
* 排序
*/
private Integer sort;
/**
* 是否隐藏联系方式 0否1是
*/
private String izHideContact;
/**
* 所属部门的id
*/
@TableField(exist = false)
private String belongDepIds;
}

View File

@ -0,0 +1,68 @@
package org.jeecg.modules.system.job;
import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import lombok.extern.slf4j.Slf4j;
import org.jeecg.common.api.dto.message.MessageDTO;
import org.jeecg.common.constant.enums.NoticeTypeEnum;
import org.jeecg.common.system.api.ISysBaseAPI;
import org.jeecg.modules.system.entity.SysUser;
import org.jeecg.modules.system.service.ISysUserService;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.springframework.beans.factory.annotation.Autowired;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.List;
/**
* @Description: 用户更新提醒job
*
* @author: wangshuai
* @date: 2025/9/13 16:20
*/
@Slf4j
public class UserUpadtePwdJob implements Job {
@Autowired
private ISysBaseAPI sysBaseAPI;
@Autowired
private ISysUserService userService;
@Override
public void execute(JobExecutionContext context) {
//获取当前时间5个月前的时间
// 获取当前日期
Calendar calendar = Calendar.getInstance();
// 减去5个月
calendar.add(Calendar.MONTH, -5);
// 格式化输出
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
String formattedDate = sdf.format(calendar.getTime());
String startTime = formattedDate + " 00:00:00";
String endTime = formattedDate + " 23:59:59";
LambdaQueryWrapper<SysUser> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.between(SysUser::getLastPwdUpdateTime, startTime, endTime);
queryWrapper.select(SysUser::getUsername,SysUser::getRealname);
List<SysUser> list = userService.list(queryWrapper);
if (CollectionUtil.isNotEmpty(list)){
for (SysUser sysUser : list) {
this.sendSysMessage(sysUser.getUsername(), sysUser.getRealname());
}
}
}
/**
* 发送系统消息
*/
private void sendSysMessage(String username, String realname) {
String fromUser = "system";
String title = "尊敬的"+realname+"您的密码已经5个月未修改了请修改密码";
MessageDTO messageDTO = new MessageDTO(fromUser, username, title, title);
messageDTO.setNoticeType(NoticeTypeEnum.NOTICE_TYPE_PLAN.getValue());
sysBaseAPI.sendSysAnnouncement(messageDTO);
}
}

View File

@ -3,6 +3,7 @@ package org.jeecg.modules.system.mapper;
import java.util.List;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import org.jeecg.modules.system.entity.SysAnnouncementSend;
import org.jeecg.modules.system.model.AnnouncementSendModel;
@ -43,4 +44,22 @@ public interface SysAnnouncementSendMapper extends BaseMapper<SysAnnouncementSen
* @param userId
*/
void clearAllUnReadMessage(@Param("userId") String userId);
/**
* 根据用户id和通告阅读表的id获取当前用户已阅读的数量
*
* @param id
* @param userId
*/
@Select("select count(1) from sys_announcement_send where id=#{id} and user_id = #{userId} and read_flag = 1")
long getReadCountByUserId(@Param("id") String id, @Param("userId") String userId);
/**
* 根据用户id和阅读表的id获取所有阅读的数据
*
* @param ids
* @param userId
* @return
*/
List<String> getReadAnnSendByUserId(@Param("ids") List<String> ids, @Param("userId") String userId);
}

View File

@ -7,6 +7,7 @@ import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Update;
import org.jeecg.modules.system.entity.SysDepart;
import org.jeecg.modules.system.entity.SysUser;
import org.jeecg.modules.system.model.SysUserSysDepPostModel;
import org.jeecg.modules.system.vo.SysDepartExportVo;
import org.jeecg.modules.system.vo.SysDepartPositionVo;
import org.jeecg.modules.system.vo.SysUserDepVo;
@ -209,7 +210,7 @@ public interface SysDepartMapper extends BaseMapper<SysDepart> {
* @param parentId
* @return
*/
@Select("select id, depart_name, parent_id, iz_leaf, org_category, org_code from sys_depart where parent_id = #{parentId} order by depart_order,create_time desc")
@Select("select id, depart_name, parent_id, iz_leaf, org_category, org_code, depart_order from sys_depart where parent_id = #{parentId} order by depart_order,create_time desc")
List<SysDepart> getDepartByParentId(@Param("parentId") String parentId);
/**
@ -251,4 +252,63 @@ public interface SysDepartMapper extends BaseMapper<SysDepart> {
* @return
*/
String getPostNameByPostId(@Param("depId") String depId);
/**
* 根据部门code获取部门数据
*
* @param orgCode
* @return
*/
@Select("select depart_name, id, iz_leaf, org_category, parent_id, org_code from sys_depart where org_code = #{orgCode} order by depart_order,create_time desc")
SysDepart queryDepartByOrgCode(@Param("orgCode") String orgCode);
/**
* 根据部门父id获取部门岗位数据
*
* @param parentIds
* @return
*/
List<SysDepart> getDepartPositionByParentIds(@Param("parentIds") List<String> parentIds);
/**
* 根据用户id集合获取用户的兼职岗位信息
*
* @param userIdList
* @return
*/
List<SysUserSysDepPostModel> getDepartOtherPostByUserIds(@Param("userIdList") List<String> userIdList);
/**
* 获取没有父级id的部门数据
*
* @return
*/
@Select("select id, org_code, depart_order from sys_depart where parent_id is null or parent_id = '' order by depart_order,create_time desc")
List<SysDepart> getDepartNoParent();
/**
* 根据父级id统计子节点数量
*
* @param parentId
* @return
*/
@Select("select count(1) from sys_depart where parent_id = #{parentId}")
long countByParentId(@Param("parentId") String parentId);
/**
* 根据用户名和分类查询
* @param username
* @param category
* @return
*/
List<SysDepart> queryDeptByUserAndCategory(@Param("username")String username, @Param("category")String category);
/**
* 获取负责部门
*
* @param page
* @param departId
* @return
*/
List<SysUser> getDepartmentHead(@Param("page") Page<SysUser> page, @Param("departId") String departId);
}

View File

@ -31,7 +31,6 @@ public interface SysLogMapper extends BaseMapper<SysLog> {
*/
Long findTotalVisitCount();
//update-begin--Author:zhangweijian Date:20190428 for传入开始时间结束时间参数
/**
* 获取系统今日访问次数
* @param dayStart 开始时间
@ -47,7 +46,6 @@ public interface SysLogMapper extends BaseMapper<SysLog> {
* @return Long
*/
Long findTodayIp(@Param("dayStart") Date dayStart, @Param("dayEnd") Date dayEnd);
//update-end--Author:zhangweijian Date:20190428 for传入开始时间结束时间参数
/**
* 首页:根据时间统计访问数量/ip数量

View File

@ -8,6 +8,7 @@ import org.apache.ibatis.annotations.Select;
import org.jeecg.modules.system.entity.SysUser;
import org.jeecg.modules.system.entity.SysUserDepart;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.jeecg.modules.system.model.SysUserSysDepPostModel;
/**
* @Description: 用户部门mapper接口
@ -98,4 +99,12 @@ public interface SysUserDepartMapper extends BaseMapper<SysUserDepart>{
*/
@Select("SELECT COUNT(*) FROM sys_user_depart WHERE user_id = #{userId} AND dep_id = #{departId}")
Long getCountByDepartIdAndUserId(String userId, String departId);
/**
* 通过用户id集合获取用户id和部门code
*
* @param userIdList
* @return
*/
List<SysUserSysDepPostModel> getUserDepPostByUserIds(@Param("userIdList") List<String> userIdList);
}

View File

@ -36,6 +36,13 @@ public interface SysUserMapper extends BaseMapper<SysUser> {
* @return
*/
public String getUserIdByName(@Param("username") String username);
/**
* 通过用户账号查询用户Id
* @param userIds
* @return
*/
public List<String> getUsernameByIds(@Param("userIds") List<String> userIds);
/**
* 根据部门Id查询用户信息
@ -254,4 +261,14 @@ public interface SysUserMapper extends BaseMapper<SysUser> {
* @return
*/
IPage<SysUser> getDepartPostListByIdUserRealName(@Param("page") Page<SysUser> page, @Param("username") String username, @Param("realname") String realname, @Param("orgCode") String orgCode);
/**
* 查询部门下的用户包括子部门下的用户
*
* @param page
* @param orgCode
* @param userParams
* @return
*/
List<SysUserSysDepPostModel> queryDepartUserByOrgCode(@Param("page") IPage page, @Param("orgCode") String orgCode, @Param("userParams") SysUser userParams);
}

View File

@ -40,7 +40,8 @@
sa.msg_abstract,
sa.files,
sa.visits_num,
sa.iz_top
sa.iz_top,
sa.notice_type
from sys_announcement_send sas
left join sys_announcement sa ON sas.annt_id = sa.id
where sa.send_status = '1'
@ -51,6 +52,15 @@
</if>
<if test="announcementSendModel.sender !=null and announcementSendModel.sender != ''">
and sa.sender LIKE concat(concat('%',#{announcementSendModel.sender}),'%')
</if>
<if test="announcementSendModel.noticeType !=null and announcementSendModel.noticeType != ''">
and sa.notice_type = #{announcementSendModel.noticeType}
</if>
<if test="announcementSendModel.noticeTypeList !=null and announcementSendModel.noticeTypeList.size() > 0">
and sa.notice_type in
<foreach collection="announcementSendModel.noticeTypeList" index="index" item="noticeType" open="(" separator="," close=")">
#{noticeType}
</foreach>
</if>
<if test="announcementSendModel.readFlag !=null">
and sas.read_flag = #{announcementSendModel.readFlag}
@ -115,4 +125,13 @@
where user_id = #{userId} and read_flag = 0
</update>
<!-- 根据用户id和阅读表的id获取所有阅读的数据 -->
<select id="getReadAnnSendByUserId" resultType="java.lang.String">
select id from sys_announcement_send
where user_id = #{userId} and read_flag = 1
and id in
<foreach collection="ids" index="index" item="id" open="(" separator="," close=")">
#{id}
</foreach>
</select>
</mapper>

View File

@ -32,6 +32,24 @@
)
</select>
<!-- 根据username和分类查询所拥有的部门/岗位/公司 -->
<select id="queryDeptByUserAndCategory" parameterType="String" resultType="org.jeecg.modules.system.entity.SysDepart">
SELECT *
FROM sys_depart
WHERE id IN (
SELECT dep_id
FROM sys_user_depart
WHERE user_id = (
SELECT id
FROM sys_user
WHERE username = #{username}
)
)
<if test="category != null and category != ''">
AND org_category = #{category}
</if>
</select>
<!-- 根据部门Id查询,当前和下级所有部门IDS -->
<select id="getSubDepIdsByDepId" resultType="java.lang.String">
select id from sys_depart where del_flag = '0' and org_code like concat((select org_code from sys_depart where id=#{departId}),'%')
@ -175,16 +193,13 @@
1=1
<if test="null != tenantId and 0 != tenantId">
AND tenant_id = #{tenantId}
</if>
AND
<choose>
<when test="parentId != null and parentId != ''">
parent_id = #{parentId}
</when>
<otherwise>
(parent_id IS NULL OR parent_id='')
</otherwise>
</choose>
</if>
<if test="parentId != null and parentId != '' and parentId != '-1'">
AND parent_id = #{parentId}
</if>
<if test="parentId == '-1'">
AND (parent_id IS NULL OR parent_id='')
</if>
<if test="idList != null and !idList.isEmpty()">
and id in
<foreach item="id" index="index" collection="idList" open="(" separator="," close=")">
@ -268,4 +283,35 @@
select sp.name from sys_depart sd join sys_position sp on sd.position_id = sp.id
where sd.id = #{depId}
</select>
<!-- 根据部门父id获取部门岗位数据 -->
<select id="getDepartPositionByParentIds" resultType="org.jeecg.modules.system.entity.SysDepart">
select sd.depart_name, sd.id, sd.iz_leaf, sd.org_category, sd.parent_id, sd.org_code from sys_depart sd left join sys_position sp on sd.position_id = sp.id
where sd.parent_id in
<foreach collection="parentIds" index="index" item="item" open="(" separator="," close=")">
#{item}
</foreach>
and sd.org_category = '3'
order by sd.depart_order,sd.create_time desc
</select>
<!-- 根据用户id集合获取用户的兼职岗位信息 -->
<select id="getDepartOtherPostByUserIds" resultType="org.jeecg.modules.system.model.SysUserSysDepPostModel">
select sudp.user_id as id, sudp.dep_id as otherDepPostId, sd.org_code
from sys_user_dep_post sudp
join sys_depart sd on sudp.dep_id = sd.id
where sudp.user_id in
<foreach collection="userIdList" index="index" item="item" open="(" separator="," close=")">
#{item}
</foreach>
</select>
<!-- 获取负责部门 -->
<select id="getDepartmentHead" resultType="org.jeecg.modules.system.entity.SysUser">
select id, realname, avatar, sex, telephone, phone, main_dep_post_id, iz_hide_contact, sort, create_time from sys_user
where status = 1 and del_flag = 0
<bind name="bindDepartId" value="departId+'%'"/>
and depart_ids like #{bindDepartId}
order by sort,create_time desc
</select>
</mapper>

View File

@ -147,6 +147,9 @@
<when test="key == 'tenant_id'">
and tenant_id = #{value}
</when>
<when test="key == '_tableFilterSql'">
and ${value}
</when>
<otherwise>
and ${key} LIKE #{value}
</otherwise>

View File

@ -37,6 +37,8 @@
<bind name="bindRealname" value="'%'+realname+'%'"/>
and a.realname like #{bindRealname}
</if>
ORDER BY
a.sort,a.create_time desc
</select>
<!--获取用户信息(聊天专用)-->
@ -82,6 +84,7 @@
#{userId}
</foreach>
</if>
order by a.sort, a.create_time desc
</select>
<!--获取租户下的部门-通过前台传过来的部门id-->
@ -125,4 +128,16 @@
select id from sys_depart where tenant_id = #{tenantId}
)
</delete>
<!-- 通过用户id集合获取用户id和部门code -->
<select id="getUserDepPostByUserIds" resultType="org.jeecg.modules.system.model.SysUserSysDepPostModel">
select su.id,sd.org_code from sys_user_depart sud
JOIN sys_user su ON sud.user_id = su.id
JOIN sys_depart sd ON sud.dep_id = sd.id
where
sud.user_id in
<foreach collection="userIdList" item="userId" open="(" close=")" separator=",">
#{userId}
</foreach>
</select>
</mapper>

View File

@ -11,6 +11,14 @@
<select id="getUserIdByName" resultType="String">
select id from sys_user where username = #{username} and del_flag = 0
</select>
<!-- 根据用户ids批量查询用户账号 -->
<select id="getUsernameByIds" resultType="String">
select username from sys_user where del_flag = 0 and a.status = 1 and id in
<foreach collection="userIds" index="index" item="id" open="(" separator="," close=")">
#{id}
</foreach>
</select>
<!-- 根据部门Id查询 -->
<select id="getUserByDepId" resultType="org.jeecg.modules.system.entity.SysUser">
@ -75,6 +83,9 @@
<if test="orgCode!=null and loginTenantId==null">
org_code = #{orgCode}
</if>
<if test="orgCode==null and loginTenantId==null">
org_code = #{orgCode}
</if>
where username = #{username}
</update>
@ -129,7 +140,7 @@
sys_depart.depart_name AS departName
<include refid="getUserByOrgCodeFromSql"/>
ORDER BY
sys_depart.org_code ASC
sys_user.sort,sys_user.create_time desc
</select>
<!-- 查询 getUserByOrgCode 的总数-->
@ -235,6 +246,7 @@
#{userId}
</foreach>
</if>
order by a.sort, a.create_time desc
</select>
<!--获取租户下的用户离职列表信息-->
@ -332,14 +344,14 @@
<select id="getDepPostListByIdUserName" resultType="org.jeecg.modules.system.entity.SysUser">
SELECT su.* from
(
SELECT su.create_time,su.realname,su.username,su.phone FROM sys_user su
SELECT su.create_time,su.realname,su.username,su.phone,su.iz_hide_contact,su.sort FROM sys_user su
<include refid="getDepPostListByIdUserNameSql"/>
union
select DISTINCT su.create_time,su.realname,su.username,su.phone FROM sys_user su
select DISTINCT su.create_time,su.realname,su.username,su.phone,su.iz_hide_contact,su.sort FROM sys_user su
JOIN sys_user_dep_post sudp ON su.id = sudp.user_id
<include refid="getDepPostListByIdUserNameSql"/>
) su
order by su.create_time desc
order by su.sort,su.create_time desc
</select>
<!-- SQL片段getDepartPostListByIdUserRealName WHERE部分 -->
@ -366,16 +378,16 @@
<select id="getDepartPostListByIdUserRealName" resultType="org.jeecg.modules.system.entity.SysUser">
SELECT su.* from
(
SELECT su.create_time,su.realname,su.username,su.phone FROM sys_user su
SELECT su.create_time,su.realname,su.username,su.phone,su.iz_hide_contact,su.sort FROM sys_user su
join sys_depart sd on su.main_dep_post_id = sd.id
<include refid="getDepartPostListByIdUserRealNameSql"/>
union
SELECT DISTINCT su.create_time,su.realname,su.username,su.phone FROM sys_user su
SELECT DISTINCT su.create_time,su.realname,su.username,su.phone,su.iz_hide_contact,su.sort FROM sys_user su
join sys_depart sd on su.main_dep_post_id = sd.id
join sys_user_dep_post sudp on su.id = sudp.user_id
<include refid="getDepartPostListByIdUserRealNameSql"/>
) su
order by su.create_time desc
order by su.sort,su.create_time desc
</select>
<!-- SQL片段queryDepartPostUserByOrgCode WHERE部分 -->
@ -404,22 +416,50 @@
SELECT su.* from
(
SELECT su.id, su.create_time, su.realname, su.username, su.phone, su.avatar, su.birthday, su.sex, su.email,
su.status, su.del_flag, su.telephone, su.activiti_sync, su.user_identity, su.depart_ids, su.main_dep_post_id
su.status, su.del_flag, su.telephone, su.activiti_sync, su.user_identity, su.depart_ids, su.main_dep_post_id,
su.sort,su.iz_hide_contact,su.position_type,su.work_no
FROM sys_user su join sys_user_depart sud on su.id = sud.user_id
join sys_depart sd on sud.dep_id = sd.id
<include refid="queryDepartPostUserByOrgCodeSql"/>
union
SELECT su.id, su.create_time, su.realname, su.username, su.phone, su.avatar, su.birthday, su.sex, su.email,
su.status, su.del_flag, su.telephone, su.activiti_sync, su.user_identity, su.depart_ids, su.main_dep_post_id
su.status, su.del_flag, su.telephone, su.activiti_sync, su.user_identity, su.depart_ids, su.main_dep_post_id,
su.sort,su.iz_hide_contact,su.position_type,su.work_no
FROM sys_user su join sys_depart sd on su.main_dep_post_id = sd.id
<include refid="queryDepartPostUserByOrgCodeSql"/>
union
SELECT su.id, su.create_time, su.realname, su.username, su.phone, su.avatar, su.birthday, su.sex, su.email,
su.status, su.del_flag, su.telephone, su.activiti_sync, su.user_identity, su.depart_ids, su.main_dep_post_id
su.status, su.del_flag, su.telephone, su.activiti_sync, su.user_identity, su.depart_ids, su.main_dep_post_id,
su.sort,su.iz_hide_contact,su.position_type,su.work_no
FROM sys_user su join sys_user_dep_post sudp on su.id = sudp.user_id
join sys_depart sd on sd.id = sudp.dep_id
<include refid="queryDepartPostUserByOrgCodeSql"/>
) su
order by su.create_time desc
order by su.sort,su.create_time desc
</select>
<!--查询部门下的用户包括子部门下的用户-->
<select id="queryDepartUserByOrgCode" resultType="org.jeecg.modules.system.model.SysUserSysDepPostModel">
SELECT DISTINCT su.id, su.realname, su.avatar, su.sex, su.birthday, su.telephone, su.email, su.phone, su.main_dep_post_id, su.iz_hide_contact, su.sort, su.create_time
FROM sys_user su join sys_user_depart sud on su.id = sud.user_id
join sys_depart sd on sud.dep_id = sd.id
where
su.status = 1
and su.del_flag = 0
and su.username <![CDATA[ != ]]> '_reserve_user_external'
<if test="orgCode == null">
<bind name="bindOrgCode" value="'%'"/>
</if>
<if test="orgCode != null">
<bind name="bindOrgCode" value="orgCode+'%'"/>
</if>
and sd.del_flag = 0 and sd.org_code LIKE #{bindOrgCode}
<if test="userParams != null">
<if test="userParams.realname != null and userParams.realname != ''">
<bind name="bindRealname" value="'%'+ userParams.realname +'%'"/>
and su.realname like #{bindRealname}
</if>
</if>
order by su.sort,su.create_time desc
</select>
</mapper>

View File

@ -7,6 +7,7 @@ import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;
import java.io.Serializable;
import java.util.List;
/**
* @Description: 用户通告阅读标记表
@ -95,4 +96,12 @@ public class AnnouncementSendModel implements Serializable {
* 是否置顶0否 1是
*/
private java.lang.Integer izTop;
/**
* 通知类型(plan:日程计划 | flow:流程消息 | meeting:会议 | file:知识库 | collab:协同通知 | supe:督办通知 | attendance:考勤)
*/
private java.lang.String noticeType;
/**
* 通告类型数组
*/
private List<String> noticeTypeList;
}

View File

@ -75,10 +75,10 @@ public class SysDepartTreeModel implements Serializable{
private Date updateTime;
//update-begin---author:wangshuai ---date:20200308 for[JTC-119]在部门管理菜单下设置部门负责人,新增字段部门负责人ids
/**部门负责人ids*/
/**部门负责人ids
* [JTC-119]在部门管理菜单下设置部门负责人,新增字段部门负责人ids
* */
private String directorUserIds;
//update-end---author:wangshuai ---date:20200308 for[JTC-119]在部门管理菜单下设置部门负责人新增字段部门负责人ids
/**职务*/
private String positionId;

View File

@ -15,6 +15,8 @@ public class SysLoginModel {
private String username;
@Schema(description = "密码")
private String password;
@Schema(description = "登录部门")
private String loginOrgCode;
@Schema(description = "验证码")
private String captcha;
@Schema(description = "验证码key")
@ -51,5 +53,12 @@ public class SysLoginModel {
public void setCheckKey(String checkKey) {
this.checkKey = checkKey;
}
public String getLoginOrgCode() {
return loginOrgCode;
}
public void setLoginOrgCode(String loginOrgCode) {
this.loginOrgCode = loginOrgCode;
}
}

View File

@ -21,11 +21,10 @@ public class SysUserSysDepPostModel {
* 用户ID
*/
private String id;
/**
* 登录账号
* 用户名
*/
@Excel(name = "登录账号", width = 15)
private String username;
/* 真实姓名 */
@ -143,4 +142,29 @@ public class SysUserSysDepPostModel {
* 职务
*/
private String post;
/**
* 部门编码
*/
private String orgCode;
/**
* 职务(字典)
*/
private String positionType;
/**
* 排序
*/
private Integer sort;
/**
* 是否隐藏联系方式 0否1是
*/
private String izHideContact;
/**
* 工号
*/
private String workNo;
}

View File

@ -52,19 +52,16 @@ public class CategoryCodeRule implements IFillRuleHandler {
* */
//找同类 确定上一个最大的code值
SysCategoryMapper baseMapper = (SysCategoryMapper) SpringContextUtils.getBean("sysCategoryMapper");
//update-begin---author:wangshuai ---date:20230424 for【issues/4846】开启saas多租户功能后租户管理员在添加分类字典时报错------------
// 代码逻辑说明: 【issues/4846】开启saas多租户功能后租户管理员在添加分类字典时报错------------
Page<SysCategory> page = new Page<>(1,1);
List<SysCategory> list = baseMapper.getMaxCategoryCodeByPage(page,categoryPid);
//update-end---author:wangshuai ---date:20230424 for【issues/4846】开启saas多租户功能后租户管理员在添加分类字典时报错------------
if (list == null || list.size() == 0) {
if (ROOT_PID_VALUE.equals(categoryPid)) {
//情况1
categoryCode = YouBianCodeUtil.getNextYouBianCode(null);
} else {
//情况2
//update-begin---author:wangshuai ---date:20230424 for【issues/4846】开启saas多租户功能后租户管理员在添加分类字典时报错------------
SysCategory parent = (SysCategory) baseMapper.selectSysCategoryById(categoryPid);
//update-end---author:wangshuai ---date:20230424 for【issues/4846】开启saas多租户功能后租户管理员在添加分类字典时报错------------
categoryCode = YouBianCodeUtil.getSubYouBianCode(parent.getCode(), null);
}
} else {

View File

@ -56,12 +56,11 @@ public class OrgCodeRule implements IFillRuleHandler {
if (StringUtil.isNullOrEmpty(parentId)) {
// 线判断数据库中的表是否为空,空则直接返回初始编码
//获取最大值code的部门信息
//update-begin---author:wangshuai ---date:20230211 for[QQYUN-4209]租户隔离下部门新建不了------------
// 代码逻辑说明: [QQYUN-4209]租户隔离下部门新建不了------------
Page<SysDepart> page = new Page<>(1,1);
IPage<SysDepart> pageList = sysDepartService.getMaxCodeDepart(page,"");
List<SysDepart> records = pageList.getRecords();
if (null==records || records.size()==0) {
//update-end---author:wangshuai ---date:20230211 for[QQYUN-4209]租户隔离下部门新建不了------------
strArray[0] = YouBianCodeUtil.getNextYouBianCode(null);
strArray[1] = "1";
return strArray;
@ -73,13 +72,12 @@ public class OrgCodeRule implements IFillRuleHandler {
}
} else {//反之则查询出所有同级的部门,获取结果后有两种情况,有同级和没有同级
//获取自己部门最大值orgCode部门信息
//update-begin---author:wangshuai ---date:20230211 for[QQYUN-4209]租户隔离下部门新建不了------------
// 代码逻辑说明: [QQYUN-4209]租户隔离下部门新建不了------------
Page<SysDepart> page = new Page<>(1,1);
IPage<SysDepart> pageList = sysDepartService.getMaxCodeDepart(page,parentId);
List<SysDepart> records = pageList.getRecords();
// 查询出父级部门
SysDepart depart = sysDepartService.getDepartById(parentId);
//update-end---author:wangshuai ---date:20230211 for[QQYUN-4209]租户隔离下部门新建不了------------
// 获取父级部门的Code
String parentCode = depart.getOrgCode();
// 根据父级部门类型算出当前部门的类型

View File

@ -31,4 +31,25 @@ public interface ISysAnnouncementSendService extends IService<SysAnnouncementSen
AnnouncementSendModel getOne(String sendId);
/**
* 获取当前用户已阅读的内容
*
* @param id
* @return
*/
long getReadCountByUserId(String id);
/**
* 根据多个id批量删除已阅读的数量
*
* @param ids
*/
void deleteBatchByIds(String ids);
/**
* 根据id更新阅读状态
* @param busId
* @param busType
*/
void updateReadFlagByBusId(String busId, String busType);
}

View File

@ -2,10 +2,10 @@ package org.jeecg.modules.system.service;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.jeecg.modules.system.entity.SysAnnouncement;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.util.Date;
import java.util.List;

View File

@ -5,13 +5,14 @@ import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;
import org.jeecg.modules.system.entity.SysDepart;
import org.jeecg.modules.system.entity.SysUser;
import org.jeecg.modules.system.model.DepartIdModel;
import org.jeecg.modules.system.model.SysDepartTreeModel;
import org.jeecg.modules.system.vo.SysChangeDepartVo;
import org.jeecg.modules.system.vo.SysDepartExportVo;
import org.jeecg.modules.system.vo.SysPositionSelectTreeVo;
import org.jeecg.modules.system.vo.lowapp.ExportDepartVo;
import jakarta.servlet.http.HttpServletRequest;
import java.util.List;
/**
@ -279,4 +280,29 @@ public interface ISysDepartService extends IService<SysDepart>{
* @return
*/
String getDepartPathNameByOrgCode(String orgCode, String depId);
/**
* 根据部门id获取部门下的岗位id
*
* @param depIds 当前选择的公司、子公司、部门id
* @return
*/
String getDepPostIdByDepId(String depIds);
/**
* 调整部门位置
*
* @param changeDepartVo
* @return
*/
void updateChangeDepart(SysChangeDepartVo changeDepartVo);
/**
* 获取部门负责人
*
* @param departId
* @param page
* @return
*/
IPage<SysUser> getDepartmentHead(String departId, Page<SysUser> page);
}

View File

@ -107,7 +107,6 @@ public interface ISysDictService extends IService<SysDict> {
@Deprecated
String queryTableDictTextByKey(String table, String text, String code, String key);
//update-begin---author:chenrui ---date:20231221 for[issues/#5643]解决分布式下表字典跨库无法查询问题------------
/**
* 通过查询指定table的 text code key 获取字典值,可批量查询
*
@ -119,7 +118,6 @@ public interface ISysDictService extends IService<SysDict> {
* @return
*/
List<DictModel> queryTableDictTextByKeys(String table, String text, String code, List<String> keys, String dataSource);
//update-end---author:chenrui ---date:20231221 for[issues/#5643]解决分布式下表字典跨库无法查询问题------------
/**
* 通过查询指定table的 text code key 获取字典值包含value

View File

@ -30,7 +30,6 @@ public interface ISysLogService extends IService<SysLog> {
*/
Long findTotalVisitCount();
//update-begin--Author:zhangweijian Date:20190428 for传入开始时间结束时间参数
/**
* 获取系统今日访问次数
* @param dayStart
@ -46,7 +45,6 @@ public interface ISysLogService extends IService<SysLog> {
* @return Long
*/
Long findTodayIp(Date dayStart, Date dayEnd);
//update-end--Author:zhangweijian Date:20190428 for传入开始时间结束时间参数
/**
* 首页:根据时间统计访问数量/ip数量

View File

@ -45,4 +45,13 @@ public interface ISysRoleIndexService extends IService<SysRoleIndex> {
* @param sysRoleIndex
*/
void changeDefHome(SysRoleIndex sysRoleIndex);
/**
* 更新其他全局默认的状态值
*
* @param roleCode
* @param status
* @param id
*/
void updateOtherDefaultStatus(String roleCode, String status, String id);
}

View File

@ -77,7 +77,7 @@ public interface ISysUserDepartService extends IService<SysUserDepart> {
* @param pageNo
* @return
*/
IPage<SysUser> getUserInformation(Integer tenantId,String departId,String roleId, String keyword, Integer pageSize, Integer pageNo, String excludeUserIdList);
IPage<SysUser> getUserInformation(Integer tenantId,String departId,String roleId, String keyword, Integer pageSize, Integer pageNo, String excludeUserIdList, String includeUsernameList);
/**
* 通过部门id和租户id获取多个用户

View File

@ -158,9 +158,7 @@ public interface ISysUserService extends IService<SysUser> {
* @param queryWrapper
* @return
*/
//update-begin-author:taoyan date:2022-9-13 for: VUEN-2245【漏洞】发现新漏洞待处理20220906 ----sql注入 方法没有使用,注掉
// public IPage<SysUser> getUserByDepartIdAndQueryWrapper(Page<SysUser> page, String departId, QueryWrapper<SysUser> queryWrapper);
//update-end-author:taoyan date:2022-9-13 for: VUEN-2245【漏洞】发现新漏洞待处理20220906 ----sql注入 方法没有使用,注掉
/**
* 根据 orgCode 查询用户,包括子部门下的用户
@ -503,4 +501,41 @@ public interface ISysUserService extends IService<SysUser> {
*/
IPage<SysUserSysDepPostModel> queryDepartPostUserByOrgCode(String orgCode, SysUser userParams, IPage page);
/**
* 根据 orgCode 查询用户信息(部门全路径,主岗位和兼职岗位的信息),包括公司、子公司、部门
*
* @param orgCode
* @param userParams
* @param page
* @return
*/
IPage<SysUserSysDepPostModel> queryDepartUserByOrgCode(String orgCode, SysUser userParams, IPage page);
/**
* 通讯录点击用户获取用户详情(包含用户基本信息、部门全路径、主岗位兼职岗位全路径)
*
* @param userId
* @return
*/
SysUserSysDepPostModel getUserDetailByUserId(String userId);
/**
* 登录获取用户部门信息
* @param jsonObject
* @return
*/
Result loginGetUserDeparts(JSONObject jsonObject);
/**
* 根据用户名查询重置成系统密码
* @param usernames
*/
void resetToSysPassword(String usernames);
/**
* 更新用户设备ID
* @param clientId
* @param userId
*/
void updateClientId(String clientId,String userId);
}

View File

@ -27,12 +27,11 @@ public class ImportFileServiceImpl implements ImportFileServiceI {
@Override
public String doUpload(byte[] data, String saveUrl) {
//update-begin---author:chenrui ---date:20250114 for[QQYUN-10902]AutoPoi Excel表格导入有问题还会报个错。 #7703------------
// 代码逻辑说明: [QQYUN-10902]AutoPoi Excel表格导入有问题还会报个错。 #7703------------
String bizPath = "import";
if(null != saveUrl && !saveUrl.isEmpty()){
bizPath = saveUrl;
}
return CommonUtils.uploadOnlineImage(data, upLoadPath, bizPath, uploadType);
//update-end---author:chenrui ---date:20250114 for[QQYUN-10902]AutoPoi Excel表格导入有问题还会报个错。 #7703------------
}
}

View File

@ -1,13 +1,27 @@
package org.jeecg.modules.system.service.impl;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import jakarta.annotation.Resource;
import org.apache.shiro.SecurityUtils;
import org.jeecg.common.constant.CommonConstant;
import org.jeecg.common.constant.SymbolConstant;
import org.jeecg.common.system.vo.LoginUser;
import org.jeecg.common.util.oConvertUtils;
import org.jeecg.modules.system.entity.SysAnnouncement;
import org.jeecg.modules.system.entity.SysAnnouncementSend;
import org.jeecg.modules.system.mapper.SysAnnouncementMapper;
import org.jeecg.modules.system.mapper.SysAnnouncementSendMapper;
import org.jeecg.modules.system.model.AnnouncementSendModel;
import org.jeecg.modules.system.service.ISysAnnouncementSendService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
@ -24,7 +38,10 @@ public class SysAnnouncementSendServiceImpl extends ServiceImpl<SysAnnouncementS
@Resource
private SysAnnouncementSendMapper sysAnnouncementSendMapper;
@Autowired
private SysAnnouncementMapper sysAnnouncementMapper;
@Override
public Page<AnnouncementSendModel> getMyAnnouncementSendPage(Page<AnnouncementSendModel> page,
AnnouncementSendModel announcementSendModel) {
@ -36,4 +53,51 @@ public class SysAnnouncementSendServiceImpl extends ServiceImpl<SysAnnouncementS
return sysAnnouncementSendMapper.getOne(sendId);
}
/**
* 获取当前用户已阅读数量
*
* @param id
* @return
*/
@Override
public long getReadCountByUserId(String id) {
LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
return sysAnnouncementSendMapper.getReadCountByUserId(id, sysUser.getId());
}
/**
* 根据多个id批量删除已阅读的数量
*
* @param ids
*/
@Override
public void deleteBatchByIds(String ids) {
LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
//根据用户id和阅读表的id获取所有阅读的数据
List<String> sendIds = sysAnnouncementSendMapper.getReadAnnSendByUserId(Arrays.asList(ids.split(SymbolConstant.COMMA)),sysUser.getId());
if(CollectionUtil.isNotEmpty(sendIds)){
this.removeByIds(sendIds);
}
}
/**
* 根据busId更新阅读状态
* @param busId
* @param busType
*/
@Override
public void updateReadFlagByBusId(String busId, String busType) {
SysAnnouncement announcement = sysAnnouncementMapper.selectOne(new QueryWrapper<SysAnnouncement>().eq("bus_type",busType).eq("bus_id",busId));
if(oConvertUtils.isNotEmpty(announcement)){
LoginUser sysUser = (LoginUser)SecurityUtils.getSubject().getPrincipal();
String userId = sysUser.getId();
LambdaUpdateWrapper<SysAnnouncementSend> updateWrapper = new UpdateWrapper().lambda();
updateWrapper.set(SysAnnouncementSend::getReadFlag, CommonConstant.HAS_READ_FLAG);
updateWrapper.set(SysAnnouncementSend::getReadTime, new Date());
updateWrapper.eq(SysAnnouncementSend::getAnntId,announcement.getId());
updateWrapper.eq(SysAnnouncementSend::getUserId,userId);
SysAnnouncementSend announcementSend = new SysAnnouncementSend();
sysAnnouncementSendMapper.update(announcementSend, updateWrapper);
}
}
}

View File

@ -4,8 +4,6 @@ import cn.hutool.core.io.IoUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.compress.archivers.zip.Zip64Mode;
import org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream;
@ -29,9 +27,11 @@ import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
import jakarta.annotation.Resource;
import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.SynchronousQueue;
@ -73,12 +73,11 @@ public class SysAnnouncementServiceImpl extends ServiceImpl<SysAnnouncementMappe
sysAnnouncementMapper.insert(sysAnnouncement);
// 2.插入用户通告阅读标记表记录
String userId = sysAnnouncement.getUserIds();
//update-begin-author:liusq---date:2023-10-31--for:[issues/5503]【公告】通知无法接收
// 代码逻辑说明: [issues/5503]【公告】通知无法接收
if(StringUtils.isNotBlank(userId) && userId.endsWith(",")){
userId = userId.substring(0, (userId.length()-1));
}
String[] userIds = userId.split(",");
//update-end-author:liusq---date:2023-10-31--for:[issues/5503]【公告】通知无法接收
String anntId = sysAnnouncement.getId();
Date refDate = new Date();
for(int i=0;i<userIds.length;i++) {
@ -216,7 +215,7 @@ public class SysAnnouncementServiceImpl extends ServiceImpl<SysAnnouncementMappe
// });
LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
log.info(" 获取登录人 LoginUser id: {}", sysUser.getId());
log.debug(" 获取登录人 LoginUser id: {}", sysUser.getId());
Page<SysAnnouncement> page = new Page<SysAnnouncement>(pageNo,pageSize);
List<SysAnnouncement> list = baseMapper.queryAllMessageList(page, sysUser.getId(), fromUser, starFlag, busType, msgCategory,beginDate, endDate, noticeType);
return list;

View File

@ -24,6 +24,7 @@ import org.apache.shiro.SecurityUtils;
import org.jeecg.common.api.dto.AiragFlowDTO;
import org.jeecg.common.api.dto.DataLogDTO;
import org.jeecg.common.api.dto.OnlineAuthDTO;
import org.jeecg.common.api.dto.PushMessageDTO;
import org.jeecg.common.api.dto.message.*;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.aspect.UrlMatchEnum;
@ -41,7 +42,6 @@ import org.jeecg.common.util.dynamic.db.FreemarkerParseFactory;
import org.jeecg.config.firewall.SqlInjection.IDictTableWhiteListHandler;
import org.jeecg.config.mybatis.MybatisPlusSaasConfig;
import org.jeecg.modules.airag.flow.service.IAiragFlowService;
import org.jeecg.modules.airag.flow.vo.api.FlowRunParams;
import org.jeecg.modules.message.entity.SysMessageTemplate;
import org.jeecg.modules.message.handle.impl.DdSendMsgHandle;
import org.jeecg.modules.message.handle.impl.EmailSendMsgHandle;
@ -56,7 +56,12 @@ import org.jeecg.modules.system.util.SecurityUtil;
import org.jeecg.modules.system.vo.lowapp.SysDictVo;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.ui.freemarker.FreeMarkerTemplateUtils;
import org.springframework.util.AntPathMatcher;
@ -64,6 +69,8 @@ import org.springframework.util.CollectionUtils;
import org.springframework.util.PathMatcher;
import jakarta.annotation.Resource;
import org.springframework.web.client.RestTemplate;
import javax.sql.DataSource;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
@ -86,6 +93,13 @@ public class SysBaseApiImpl implements ISysBaseAPI {
/** 当前系统数据库类型 */
private static String DB_TYPE = "";
// 云函数的 URL 化地址
@Value("${jeecg.unicloud.pushUrl:''}")
private String jeecgPushUrl;
@Autowired
private RestTemplate restTemplate;
@Autowired
private ISysMessageTemplateService sysMessageTemplateService;
@Resource
@ -112,6 +126,8 @@ public class SysBaseApiImpl implements ISysBaseAPI {
private ISysDataSourceService dataSourceService;
@Autowired
private ISysUserDepartService sysUserDepartService;
@Autowired
private ISysUserDepPostService sysUserDepPostService;
@Resource
private SysPermissionMapper sysPermissionMapper;
@Autowired
@ -149,11 +165,10 @@ public class SysBaseApiImpl implements ISysBaseAPI {
@Override
//@SensitiveDecode
public LoginUser getUserByName(String username) {
//update-begin-author:taoyan date:2022-6-6 for: VUEN-1276 【v3流程图】测试bug 1、通过我发起的流程或者流程实例查看历史流程图预览问题
// 代码逻辑说明: VUEN-1276 【v3流程图】测试bug 1、通过我发起的流程或者流程实例查看历史流程图预览问题
if (oConvertUtils.isEmpty(username)) {
return null;
}
//update-end-author:taoyan date:2022-6-6 for: VUEN-1276 【v3流程图】测试bug 1、通过我发起的流程或者流程实例查看历史流程图预览问题
LoginUser user = sysUserService.getEncodeUserInfo(username);
//相同类中方法间调用时脱敏解密 Aop会失效获取用户信息太重要此处采用原生解密方法不采用@SensitiveDecodeAble注解方式
@ -203,15 +218,14 @@ public class SysBaseApiImpl implements ISysBaseAPI {
query.eq(SysPermission::getMenuType,2);
query.eq(SysPermission::getDelFlag,0);
//update-begin-author:taoyan date:2023-2-21 for: 解决参数顺序问题
// 代码逻辑说明: 解决参数顺序问题
List<String> allPossiblePaths = this.getOnlinePossiblePaths(requestPath);
log.info("获取的菜单地址= {}", allPossiblePaths.toString());
log.debug("获取的菜单地址= {}", allPossiblePaths.toString());
if(allPossiblePaths.size()==1){
query.eq(SysPermission::getUrl, requestPath);
}else{
query.in(SysPermission::getUrl, allPossiblePaths);
}
//update-end-author:taoyan date:2023-2-21 for: 解决参数顺序问题
currentSyspermission = sysPermissionMapper.selectList(query);
//2.未找到 再通过自定义匹配URL 获取菜单
@ -219,9 +233,8 @@ public class SysBaseApiImpl implements ISysBaseAPI {
//通过自定义URL匹配规则 获取菜单(实现通过菜单配置数据权限规则,实际上针对获取数据接口进行数据规则控制)
String userMatchUrl = UrlMatchEnum.getMatchResultByUrl(requestPath);
LambdaQueryWrapper<SysPermission> queryQserMatch = new LambdaQueryWrapper<SysPermission>();
// update-begin-author:taoyan date:20211027 for: online菜单如果配置成一级菜单 权限查询不到 取消menuType = 1
// 代码逻辑说明: online菜单如果配置成一级菜单 权限查询不到 取消menuType = 1
//queryQserMatch.eq(SysPermission::getMenuType, 1);
// update-end-author:taoyan date:20211027 for: online菜单如果配置成一级菜单 权限查询不到 取消menuType = 1
queryQserMatch.eq(SysPermission::getDelFlag, 0);
queryQserMatch.eq(SysPermission::getUrl, userMatchUrl);
if(oConvertUtils.isNotEmpty(userMatchUrl)){
@ -240,13 +253,12 @@ public class SysBaseApiImpl implements ISysBaseAPI {
if(currentSyspermission!=null && currentSyspermission.size()>0){
List<SysPermissionDataRuleModel> dataRules = new ArrayList<SysPermissionDataRuleModel>();
for (SysPermission sysPermission : currentSyspermission) {
// update-begin--Author:scott Date:20191119 for数据权限规则编码不规范,项目存在相同包名和类名 #722
// 代码逻辑说明: 数据权限规则编码不规范,项目存在相同包名和类名 #722
List<SysPermissionDataRule> temp = sysPermissionDataRuleService.queryPermissionDataRules(username, sysPermission.getId());
if(temp!=null && temp.size()>0) {
//dataRules.addAll(temp);
dataRules = oConvertUtils.entityListToModelList(temp,SysPermissionDataRuleModel.class);
}
// update-end--Author:scott Date:20191119 for数据权限规则编码不规范项目存在相同包名和类名 #722
}
return dataRules;
}
@ -499,9 +511,8 @@ public class SysBaseApiImpl implements ISysBaseAPI {
announcement.setSendTime(new Date());
announcement.setMsgCategory(CommonConstant.MSG_CATEGORY_2);
announcement.setDelFlag(String.valueOf(CommonConstant.DEL_FLAG_0));
//update-begin-author:liusq---date:2025-07-01--for: [QQYUN-12999]系统通知,系统通知时间更新,但是排到下面了
// 代码逻辑说明: [QQYUN-12999]系统通知,系统通知时间更新,但是排到下面了
announcement.setIzTop(CommonConstant.IZ_TOP_0);
//update-end-author:liusq---date:2025-07-01--for: [QQYUN-12999]系统通知,系统通知时间更新,但是排到下面了
sysAnnouncementMapper.insert(announcement);
// 2.插入用户通告阅读标记表记录
String userId = toUser;
@ -572,9 +583,8 @@ public class SysBaseApiImpl implements ISysBaseAPI {
announcement.setMsgType(CommonConstant.MSG_TYPE_UESR);
announcement.setSendStatus(CommonConstant.HAS_SEND);
announcement.setSendTime(new Date());
//update-begin-author:liusq---date:2025-07-01--for: [QQYUN-12999]系统通知,系统通知时间更新,但是排到下面了
// 代码逻辑说明: [QQYUN-12999]系统通知,系统通知时间更新,但是排到下面了
announcement.setIzTop(CommonConstant.IZ_TOP_0);
//update-end-author:liusq---date:2025-07-01--for: [QQYUN-12999]系统通知,系统通知时间更新,但是排到下面了
if(tmplateParam!=null && oConvertUtils.isNotEmpty(tmplateParam.get(CommonSendStatus.MSG_ABSTRACT_JSON))){
announcement.setMsgAbstract(tmplateParam.get(CommonSendStatus.MSG_ABSTRACT_JSON));
}
@ -860,26 +870,45 @@ public class SysBaseApiImpl implements ISysBaseAPI {
@Override
public List<String> getDeptHeadByDepId(String deptId) {
QueryWrapper<SysUser> queryWrapper = new QueryWrapper<SysUser>().eq("status", 1).eq("del_flag", 0);
//支持逗号分割传递多个部门id
if (oConvertUtils.isNotEmpty(deptId) && deptId.contains(SymbolConstant.COMMA)) {
String[] vals = deptId.split(SymbolConstant.COMMA);
queryWrapper.and(andWrapper -> {
for (int i = 0; i < vals.length; i++) {
andWrapper.like("depart_ids", vals[i]);
andWrapper.or();
}
});
} else {
queryWrapper.like("depart_ids", deptId);
log.debug(" getDeptHeadByDepId 根据部门ID获取负责人deptId{}", deptId);
if(oConvertUtils.isEmpty(deptId)){
return null;
}
List<SysUser> userList = userMapper.selectList(queryWrapper);
List<String> list = new ArrayList<>();
for(SysUser user : userList){
list.add(user.getUsername());
QueryWrapper<SysUser> queryWrapper = new QueryWrapper<SysUser>().eq("status", 1).eq("del_flag", 0);
// 支持逗号分割传递多个部门id
if (oConvertUtils.isNotEmpty(deptId) && deptId.contains(SymbolConstant.COMMA)) {
String[] vals = deptId.split(SymbolConstant.COMMA);
// 先trim去除空格再过滤空字符串最后去重
List<String> validDeptIds = Arrays.stream(vals)
.map(String::trim)
.filter(oConvertUtils::isNotEmpty)
.distinct() // 去重处理
.collect(Collectors.toList());
if (!validDeptIds.isEmpty()) {
queryWrapper.and(andWrapper -> {
for (int i = 0; i < validDeptIds.size(); i++) {
andWrapper.like("depart_ids", validDeptIds.get(i));
if (i < validDeptIds.size() - 1) {
andWrapper.or();
}
}
});
}
} else if (oConvertUtils.isNotEmpty(deptId)) {
queryWrapper.like("depart_ids", deptId.trim()); // 单个值也要trim
}
return list;
List<SysUser> userList = userMapper.selectList(queryWrapper);
// 对结果也进行去重处理
return userList.stream()
.map(SysUser::getUsername)
.distinct()
.collect(Collectors.toList());
}
@Override
@ -941,7 +970,7 @@ public class SysBaseApiImpl implements ISysBaseAPI {
List<SysUser> list= sysUserService.list(queryWrapper);
if(ObjectUtils.isNotEmpty(list)){
//update-begin-author:taoyan date:2023-5-19 for: QQYUN-5326【简流】获取组织人员 单/多 筛选条件 没有部门筛选
// 代码逻辑说明: QQYUN-5326【简流】获取组织人员 单/多 筛选条件 没有部门筛选
String departKey = "depart";
QueryCondition departCondition = null;
try {
@ -971,7 +1000,6 @@ public class SysBaseApiImpl implements ISysBaseAPI {
if(flag){
result.add(userJson);
}
//update-end-author:taoyan date:2023-5-19 for: QQYUN-5326【简流】获取组织人员 单/多 筛选条件 没有部门筛选
}
}
@ -1139,7 +1167,7 @@ public class SysBaseApiImpl implements ISysBaseAPI {
public Set<String> getUserRoleSet(String username) {
// 查询用户拥有的角色集合
List<String> roles = sysUserRoleMapper.getRoleByUserName(username);
log.info("-------通过数据库读取用户拥有的角色Rules------username " + username + ",Roles size: " + (roles == null ? 0 : roles.size()));
log.debug("-------通过数据库读取用户拥有的角色Rules------username " + username + ",Roles size: " + (roles == null ? 0 : roles.size()));
return new HashSet<>(roles);
}
@ -1153,7 +1181,7 @@ public class SysBaseApiImpl implements ISysBaseAPI {
public Set<String> getUserRoleSetById(String useId) {
// 查询用户拥有的角色集合
List<String> roles = sysUserRoleMapper.getRoleCodeByUserId(useId);
log.info("-------通过数据库读取用户拥有的角色Rules------useId " + useId + ",Roles size: " + (roles == null ? 0 : roles.size()));
log.debug("-------通过数据库读取用户拥有的角色Rules------useId " + useId + ",Roles size: " + (roles == null ? 0 : roles.size()));
return new HashSet<>(roles);
}
@ -1184,7 +1212,7 @@ public class SysBaseApiImpl implements ISysBaseAPI {
permissionSet.add(po.getPerms());
}
}
log.info("-------通过数据库读取用户拥有的权限Perms------userId "+ userId+",Perms size: "+ (permissionSet==null?0:permissionSet.size()) );
log.debug("-------通过数据库读取用户拥有的权限Perms------userId "+ userId+",Perms size: "+ (permissionSet==null?0:permissionSet.size()) );
return permissionSet;
}
@ -1209,13 +1237,12 @@ public class SysBaseApiImpl implements ISysBaseAPI {
sysPermission.setUrl(onlineFormUrl);
int count = sysPermissionMapper.queryCountByUsername(username, sysPermission);
if(count<=0){
//update-begin---author:chenrui ---date:20240123 for[QQYUN-7992]【online】工单申请下的online表单未配置online表单开发菜单操作报错无权限------------
// 代码逻辑说明: [QQYUN-7992]【online】工单申请下的online表单未配置online表单开发菜单操作报错无权限------------
sysPermission.setUrl(onlineAuthDTO.getOnlineWorkOrderUrl());
count = sysPermissionMapper.queryCountByUsername(username, sysPermission);
if(count<=0) {
return false;
}
//update-end---author:chenrui ---date:20240123 for[QQYUN-7992]【online】工单申请下的online表单未配置online表单开发菜单操作报错无权限------------
}
} else {
//找到菜单了
@ -1230,13 +1257,12 @@ public class SysBaseApiImpl implements ISysBaseAPI {
sysPermission.setUrl(onlineFormUrl);
int count = sysPermissionMapper.queryCountByUsername(username, sysPermission);
if (count <= 0) {
//update-begin---author:chenrui ---date:20240123 for[QQYUN-7992]【online】工单申请下的online表单未配置online表单开发菜单操作报错无权限------------
// 代码逻辑说明: [QQYUN-7992]【online】工单申请下的online表单未配置online表单开发菜单操作报错无权限------------
sysPermission.setUrl(onlineAuthDTO.getOnlineWorkOrderUrl());
count = sysPermissionMapper.queryCountByUsername(username, sysPermission);
if (count > 0) {
has = true;
}
//update-end---author:chenrui ---date:20240123 for[QQYUN-7992]【online】工单申请下的online表单未配置online表单开发菜单操作报错无权限------------
} else {
has = true;
}
@ -1330,9 +1356,8 @@ public class SysBaseApiImpl implements ISysBaseAPI {
announcement.setSendTime(new Date());
announcement.setMsgCategory(setMsgCategory);
announcement.setDelFlag(String.valueOf(CommonConstant.DEL_FLAG_0));
//update-begin-author:liusq---date:2025-07-01--for: [QQYUN-12999]系统通知,系统通知时间更新,但是排到下面了
// 代码逻辑说明: [QQYUN-12999]系统通知,系统通知时间更新,但是排到下面了
announcement.setIzTop(CommonConstant.IZ_TOP_0);
//update-end-author:liusq---date:2025-07-01--for: [QQYUN-12999]系统通知,系统通知时间更新,但是排到下面了
if(oConvertUtils.isEmpty(noticeType)){
noticeType = NoticeTypeEnum.NOTICE_TYPE_SYSTEM.getValue();
}
@ -1389,17 +1414,20 @@ public class SysBaseApiImpl implements ISysBaseAPI {
announcement.setDelFlag(String.valueOf(CommonConstant.DEL_FLAG_0));
announcement.setBusId(busId);
announcement.setBusType(busType);
announcement.setOpenType(SysAnnmentTypeEnum.getByType(busType).getOpenType());
announcement.setOpenPage(SysAnnmentTypeEnum.getByType(busType).getOpenPage());
//update-begin---author:chenrui ---date:20250807 for[JHHB-136]【vue3】协同工作系统消息需要添加一个类型------------
// 代码逻辑说明: busType为空时报错
if(oConvertUtils.isNotEmpty(busType)){
announcement.setOpenType(SysAnnmentTypeEnum.getByType(busType).getOpenType());
announcement.setOpenPage(SysAnnmentTypeEnum.getByType(busType).getOpenPage());
}
// 代码逻辑说明: [JHHB-136]【vue3】协同工作系统消息需要添加一个类型------------
if(oConvertUtils.isEmpty(noticeType)){
noticeType = NoticeTypeEnum.NOTICE_TYPE_FLOW.getValue();
}
announcement.setNoticeType(noticeType);
//update-end---author:chenrui ---date:20250807 for[JHHB-136]【vue3】协同工作系统消息需要添加一个类型------------
//update-begin-author:liusq---date:2025-07-01--for: [QQYUN-12999]系统通知,系统通知时间更新,但是排到下面了
// 代码逻辑说明: [QQYUN-12999]系统通知,系统通知时间更新,但是排到下面了
announcement.setIzTop(CommonConstant.IZ_TOP_0);
//update-end-author:liusq---date:2025-07-01--for: [QQYUN-12999]系统通知,系统通知时间更新,但是排到下面了
sysAnnouncementMapper.insert(announcement);
// 2.插入用户通告阅读标记表记录
String userId = toUser;
@ -1618,17 +1646,15 @@ public class SysBaseApiImpl implements ISysBaseAPI {
public Map<String, List<DictModel>> translateManyDict(String dictCodes, String keys) {
List<String> dictCodeList = Arrays.asList(dictCodes.split(","));
List<String> values = Arrays.asList(keys.split(","));
//update-begin---author:chenrui ---date:20231221 for[issues/#5643]解决分布式下表字典跨库无法查询问题------------
// 代码逻辑说明: [issues/#5643]解决分布式下表字典跨库无法查询问题------------
return sysDictService.queryManyDictByKeys(dictCodeList, values);
//update-end---author:chenrui ---date:20231221 for[issues/#5643]解决分布式下表字典跨库无法查询问题------------
}
//update-begin---author:chenrui ---date:20231221 for[issues/#5643]解决分布式下表字典跨库无法查询问题------------
// 代码逻辑说明: [issues/#5643]解决分布式下表字典跨库无法查询问题------------
@Override
public List<DictModel> translateDictFromTableByKeys(String table, String text, String code, String keys, String dataSource) {
return sysDictService.queryTableDictTextByKeys(table, text, code, Arrays.asList(keys.split(",")), dataSource);
}
//update-end---author:chenrui ---date:20231221 for[issues/#5643]解决分布式下表字典跨库无法查询问题------------
//-------------------------------------流程节点发送模板消息-----------------------------------------------
@Autowired
@ -1647,7 +1673,7 @@ public class SysBaseApiImpl implements ISysBaseAPI {
public void sendTemplateMessage(MessageDTO message) {
String messageType = message.getType();
log.debug(" 【万能通用】推送消息 messageType = {}", messageType);
//update-begin-author:taoyan date:2022-7-9 for: 将模板解析代码移至消息发送, 而不是调用的地方
// 代码逻辑说明: 将模板解析代码移至消息发送, 而不是调用的地方
String templateCode = message.getTemplateCode();
if(oConvertUtils.isNotEmpty(templateCode)){
SysMessageTemplate templateEntity = getTemplateEntity(templateCode);
@ -1664,7 +1690,6 @@ public class SysBaseApiImpl implements ISysBaseAPI {
throw new JeecgBootException("发送消息失败,消息内容为空!");
}
//update-end-author:taoyan date:2022-7-9 for: 将模板解析代码移至消息发送, 而不是调用的地方
if(MessageTypeEnum.XT.getType().equals(messageType)){
if (message.isMarkdown()) {
// 系统消息要解析Markdown
@ -1676,13 +1701,12 @@ public class SysBaseApiImpl implements ISysBaseAPI {
// 邮件消息要解析Markdown
message.setContent(HTMLUtils.parseMarkdown(message.getContent()));
}
//update-begin---author:wangshuai---date:2024-11-20---for:【QQYUN-8523】敲敲云发邮件通知不稳定---
// 代码逻辑说明: 【QQYUN-8523】敲敲云发邮件通知不稳定---
if(message.getIsTimeJob() != null && message.getIsTimeJob()){
emailSendMsgHandle.sendEmailMessage(message);
}else{
emailSendMsgHandle.sendMessage(message);
}
//update-end---author:wangshuai---date:2024-11-20---for:【QQYUN-8523】敲敲云发邮件通知不稳定---
}else if(MessageTypeEnum.DD.getType().equals(messageType)){
ddSendMsgHandle.sendMessage(message);
}else if(MessageTypeEnum.QYWX.getType().equals(messageType)){
@ -1788,6 +1812,11 @@ public class SysBaseApiImpl implements ISysBaseAPI {
return sysUserDepartService.listObjs(queryWrapper,e->e.toString());
}
@Override
public List<String> queryUsernameByIds(List<String> userIds) {
return userMapper.getUsernameByIds(userIds);
}
@Override
public List<String> queryUserIdsByCascadeDeptIds(List<String> deptIds) {
Set<String> userIds = new HashSet<>();
@ -1822,14 +1851,61 @@ public class SysBaseApiImpl implements ISysBaseAPI {
return null;
}
@Override
public List<String> queryUserIdsByDeptPostIds(List<String> deptPostIds) {
// 1.查询兼职岗位对应的用户
QueryWrapper<SysUserDepPost> queryWrapper = new QueryWrapper<>();
queryWrapper.lambda().select(SysUserDepPost::getUserId).in(true,SysUserDepPost::getDepId,deptPostIds);
List<String> otherDepartPostUserIds = sysUserDepPostService.listObjs(queryWrapper,e->e.toString());
log.info("兼职岗位对应的用户 otherDepartPostUserIds = "+ JSON.toJSONString(otherDepartPostUserIds));
// 2.查询主岗位对应的用户
QueryWrapper<SysUser> mainQueryWrapper = new QueryWrapper<>();
mainQueryWrapper.lambda().select(SysUser::getId).eq(SysUser::getStatus,Integer.parseInt(CommonConstant.STATUS_1)).eq(SysUser::getDelFlag,CommonConstant.DEL_FLAG_0)
.and(wrapper -> wrapper.in(SysUser::getMainDepPostId, deptPostIds));
List<String> mainDepartPostUserIds = sysUserService.listObjs(mainQueryWrapper,e->e.toString());
log.info("主岗位对应的用户 mainDepartPostUserIds = "+ JSON.toJSONString(mainDepartPostUserIds));
// 3.合并主岗位和兼职岗位对应的用户
Set<String> userIdSet = new HashSet<>();
if (otherDepartPostUserIds != null && !otherDepartPostUserIds.isEmpty()) {
userIdSet.addAll(otherDepartPostUserIds);
}
if (mainDepartPostUserIds != null && !mainDepartPostUserIds.isEmpty()) {
userIdSet.addAll(mainDepartPostUserIds);
}
log.info("主岗位和兼职岗位,对应的用户 userIdSet = "+ JSON.toJSONString(userIdSet));
return new ArrayList<>(userIdSet);
}
@Override
public List<String> queryUsernameByDepartPositIds(List<String> deptPostIds) {
// 1.查询兼职岗位对应的用户
QueryWrapper<SysUserDepPost> otherQueryWrapper = new QueryWrapper<>();
otherQueryWrapper.lambda().select(SysUserDepPost::getUserId).in(true, SysUserDepPost::getDepId, deptPostIds);
List<String> otherUserIds = sysUserDepPostService.listObjs(otherQueryWrapper, e -> e.toString());
log.info("兼职岗位对应的用户 otherUserIds = {}size = {}" + JSON.toJSONString(otherUserIds), oConvertUtils.getCollectionSize(otherUserIds));
// 2.查询主岗位和兼职岗位,对应的用户
QueryWrapper<SysUser> mainQueryWrapper = new QueryWrapper<>();
mainQueryWrapper.lambda().select(SysUser::getUsername).eq(SysUser::getStatus, Integer.parseInt(CommonConstant.STATUS_1)).eq(SysUser::getDelFlag, CommonConstant.DEL_FLAG_0)
.and(wrapper -> wrapper
.in(SysUser::getMainDepPostId, deptPostIds)
.or()
.in(otherUserIds != null && !otherUserIds.isEmpty(), SysUser::getId, otherUserIds)
);
List<String> allUsernames = sysUserService.listObjs(mainQueryWrapper, e -> e.toString());
log.info("主岗位和兼职岗位,对应的用户账号 allUsernames = {}size = {}" ,JSON.toJSONString(allUsernames), oConvertUtils.getCollectionSize(allUsernames));
return allUsernames;
}
@Override
public List<String> queryUserIdsByPositionIds(List<String> positionIds) {
QueryWrapper<SysUserPosition> queryWrapper = new QueryWrapper<>();
queryWrapper.lambda().select(SysUserPosition::getUserId).in(true,SysUserPosition::getPositionId,positionIds);
return sysUserPositionService.listObjs(queryWrapper,e->e.toString());
}
//update-begin-author:taoyan date:2023-2-21 for: 解决参数顺序问题
/**
* 获取带参数的报表地址,因为多个参数可能顺序会变,所以要将参数顺序重排,获取所有可能的地址集合
* 如下参数顺序调整使用in查询就能查询出菜单数据
@ -1840,7 +1916,7 @@ public class SysBaseApiImpl implements ISysBaseAPI {
*/
private List<String> getOnlinePossiblePaths(String path){
List<String> result = new ArrayList<>();
log.info(" path = "+ path);
log.debug(" path = "+ path);
if (path.indexOf("?") >= 0 && (path.contains("/online/cgreport/") || path.contains("/online/cgformList/") || path.contains("/online/graphreport/"))) {
//包含?说明有多个参数
String[] pathArray = path.split("\\?");
@ -1898,7 +1974,6 @@ public class SysBaseApiImpl implements ISysBaseAPI {
}
return result;
}
//update-end-author:taoyan date:2023-2-21 for: 解决参数顺序问题
@Override
public List<String> getUserAccountsByDepCode(String orgCode) {
@ -2032,15 +2107,82 @@ public class SysBaseApiImpl implements ISysBaseAPI {
if(oConvertUtils.isEmpty(airagFlowDTO.getFlowId())) {
throw new JeecgBootException("流程ID不能为空");
}
FlowRunParams params = new FlowRunParams();
params.setFlowId(airagFlowDTO.getFlowId());
params.setInputParams(airagFlowDTO.getInputParams());
params.setResponseMode("blocking");
Result<Object> o = (Result<Object>)airagFlowService.runFlow(params);
Result<Object> o = (Result<Object>)airagFlowService.runFlow(airagFlowDTO);
return o.getResult();
}
/**
/**
* uniPush推送消息给APP用户
* @param pushMessageDTO
*/
@Override
public void uniPushMsgToUser(PushMessageDTO pushMessageDTO) {
if(oConvertUtils.isEmpty(jeecgPushUrl)){
log.warn("yml配置项: jeecg.unicloud.pushUrl 未设置APP消息UniPush推送功能未启用");
return;
}
// 获取推送的用户信息
List<String> usernames = pushMessageDTO.getUsernames();
List<String> userIds = pushMessageDTO.getUserIds();
// 构建clientIds
List<String> clientIds = getClientIds(usernames, userIds);
// 构建请求参数
Map<String, Object> requestBody = new HashMap<>();
requestBody.put("title", pushMessageDTO.getTitle());
requestBody.put("content", pushMessageDTO.getContent());
requestBody.put("data", pushMessageDTO.getPayload());
requestBody.put("request_id", String.valueOf(System.currentTimeMillis()));
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
// 全用户推送不需要clientIds指定用户推送需要设置clientIds
boolean isAllUserPush = CommonConstant.MSG_TYPE_ALL.equals(pushMessageDTO.getPushType());
if (!isAllUserPush) {
if (CollectionUtils.isEmpty(clientIds)) {
log.warn("UniPush消息推送clientIds为空");
return;
}
requestBody.put("cids", clientIds);
}
// 统一推送逻辑
HttpEntity<Map<String, Object>> request = new HttpEntity<>(requestBody, headers);
ResponseEntity<Map> response = restTemplate.postForEntity(jeecgPushUrl, request, Map.class);
// 统一处理响应
String pushType = isAllUserPush ? "全用户" : "单用户";
if (response.getStatusCode().is2xxSuccessful()) {
log.info("{} UniPush消息推送成功 返回response:{}", pushType, response.getBody());
} else {
log.error("{} UniPush消息推送失败 返回response:{}", pushType, response.getBody());
}
}
/**
* 根据用户名或用户ID获取clientIds
*/
private List<String> getClientIds(List<String> usernames, List<String> userIds) {
if (!CollectionUtils.isEmpty(usernames)) {
return extractClientIds(this.queryUsersByUsernames(String.join(",", usernames)));
} else if (!CollectionUtils.isEmpty(userIds)) {
return extractClientIds(this.queryUsersByIds(String.join(",", userIds)));
}
return Collections.emptyList();
}
/**
* 从用户信息中提取clientIds
*/
private List<String> extractClientIds(List<JSONObject> users) {
return users.stream()
.map(user -> user.getString("clientId"))
.filter(clientId -> oConvertUtils.isNotEmpty(clientId) && !clientId.trim().isEmpty())
.collect(Collectors.toList());
}
/**
* 根据orgCode找上级
*
* @param orgCode

View File

@ -47,11 +47,10 @@ public class SysCategoryServiceImpl extends ServiceImpl<SysCategoryMapper, SysCa
}
}
}
//update-begin--Author:baihailong Date:20191209 for分类字典编码规则生成器做成公用配置
// 代码逻辑说明: 分类字典编码规则生成器做成公用配置
JSONObject formData = new JSONObject();
formData.put("pid",categoryPid);
categoryCode = (String) FillRuleUtil.executeRule(FillRuleConstant.CATEGORY,formData);
//update-end--Author:baihailong Date:20191209 for分类字典编码规则生成器做成公用配置
sysCategory.setCode(categoryCode);
sysCategory.setPid(categoryPid);
baseMapper.insert(sysCategory);
@ -217,7 +216,7 @@ public class SysCategoryServiceImpl extends ServiceImpl<SysCategoryMapper, SysCa
List<SysCategory> list = super.list(query);
// 取出name并返回
List<String> textList;
// update-begin--author:sunjianlei--date:20210514--for新增delNotExist参数设为false不删除数据库里不存在的key ----
// 代码逻辑说明: 新增delNotExist参数设为false不删除数据库里不存在的key ----
if (delNotExist) {
textList = list.stream().map(SysCategory::getName).collect(Collectors.toList());
} else {
@ -227,7 +226,6 @@ public class SysCategoryServiceImpl extends ServiceImpl<SysCategoryMapper, SysCa
textList.add(res.size() > 0 ? res.get(0).getName() : id);
}
}
// update-end--author:sunjianlei--date:20210514--for新增delNotExist参数设为false不删除数据库里不存在的key ----
return textList;
}

View File

@ -197,7 +197,6 @@ public class SysCommentServiceImpl extends ServiceImpl<SysCommentMapper, SysComm
sysFormFileMapper.insert(sysFormFile);
// }
}
//update-end-author:taoyan date:2023-6-12 for: QQYUN-4310【文件】从文件库选择文件功能未做
}
/**
@ -271,7 +270,7 @@ public class SysCommentServiceImpl extends ServiceImpl<SysCommentMapper, SysComm
md.setFromUser("system");
md.setType(MessageTypeEnum.XT.getType());
// update-begin-author:taoyan date:2023-5-10 for: QQYUN-4744【系统通知】6、系统通知@人后,对方看不到是哪个表单@的,没有超链接
// 代码逻辑说明: QQYUN-4744【系统通知】6、系统通知@人后,对方看不到是哪个表单@的,没有超链接
String tableName = sysComment.getTableName();
String prefix = "desform:";
if (tableName != null) {
@ -299,7 +298,6 @@ public class SysCommentServiceImpl extends ServiceImpl<SysCommentMapper, SysComm
md.setData(data);
}
}
// update-end-author:taoyan date:2023-5-10 for: QQYUN-4744【系统通知】6、系统通知@人后,对方看不到是哪个表单@的,没有超链接
sysBaseApi.sendTemplateMessage(md);
}

View File

@ -67,9 +67,8 @@ public class SysDepartPermissionServiceImpl extends ServiceImpl<SysDepartPermiss
if(roleIds != null && roleIds.size()>0){
departRolePermissionMapper.delete(new LambdaQueryWrapper<SysDepartRolePermission>()
.eq(SysDepartRolePermission::getPermissionId,permissionId)
//update-begin-author:liusq---date:2023-10-08--for: [issue/#5339]部门管理下部门赋权代码逻辑缺少判断条件
// 代码逻辑说明: [issue/#5339]部门管理下部门赋权代码逻辑缺少判断条件
.in(SysDepartRolePermission::getRoleId,roleIds)
//update-end-author:liusq---date:2023-10-08--for: [issue/#5339]部门管理下部门赋权代码逻辑缺少判断条件
);
}
}

View File

@ -6,6 +6,7 @@ import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
@ -28,9 +29,7 @@ import org.jeecg.modules.system.model.DepartIdModel;
import org.jeecg.modules.system.model.SysDepartTreeModel;
import org.jeecg.modules.system.service.ISysDepartService;
import org.jeecg.modules.system.util.FindsDepartsChildrenUtil;
import org.jeecg.modules.system.vo.SysDepartExportVo;
import org.jeecg.modules.system.vo.SysDepartPositionVo;
import org.jeecg.modules.system.vo.SysPositionSelectTreeVo;
import org.jeecg.modules.system.vo.*;
import org.jeecg.modules.system.vo.lowapp.ExportDepartVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@ -70,17 +69,18 @@ public class SysDepartServiceImpl extends ServiceImpl<SysDepartMapper, SysDepart
private SysPositionMapper sysPositionMapper;
@Autowired
private RedisUtil redisUtil;
@Autowired
private SysUserDepPostMapper sysUserDepPostMapper;
@Override
public List<SysDepartTreeModel> queryMyDeptTreeList(String departIds) {
//根据部门id获取所负责部门
LambdaQueryWrapper<SysDepart> query = new LambdaQueryWrapper<SysDepart>();
String[] codeArr = this.getMyDeptParentOrgCode(departIds);
//update-begin---author:wangshuai---date:2023-12-01---for:【QQYUN-7320】查询部门没数据导致报错空指针---
// 代码逻辑说明: 【QQYUN-7320】查询部门没数据导致报错空指针---
if(ArrayUtil.isEmpty(codeArr)){
return null;
}
//update-end---author:wangshuai---date:2023-12-01---for:【QQYUN-7320】查询部门没数据导致报错空指针---
for(int i=0;i<codeArr.length;i++){
query.or().likeRight(SysDepart::getOrgCode,codeArr[i]);
}
@ -122,15 +122,12 @@ public class SysDepartServiceImpl extends ServiceImpl<SysDepartMapper, SysDepart
}
//------------------------------------------------------------------------------------------------
query.eq(SysDepart::getDelFlag, CommonConstant.DEL_FLAG_0.toString());
//update-begin---author:wangshuai---date:2025-08-18---for:【QQYUN-13427】部门选择组件修改:需要过滤掉岗位 只保留 公司 子公司 部门---
// 代码逻辑说明: 【QQYUN-13427】部门选择组件修改:需要过滤掉岗位 只保留 公司 子公司 部门---
query.ne(SysDepart::getOrgCategory, DepartCategoryEnum.DEPART_CATEGORY_POST.getValue());
//update-end---author:wangshuai---date:2025-08-18---for:【QQYUN-13427】部门选择组件修改:需要过滤掉岗位 只保留 公司 子公司 部门---
query.orderByAsc(SysDepart::getDepartOrder);
List<SysDepart> list = this.list(query);
//update-begin---author:wangshuai ---date:20220307 for[JTC-119]在部门管理菜单下设置部门负责人 创建用户的时候不需要处理
//设置用户id,让前台显示
this.setUserIdsByDepList(list);
//update-begin---author:wangshuai ---date:20220307 for[JTC-119]在部门管理菜单下设置部门负责人 创建用户的时候不需要处理
// 调用wrapTreeDataToTreeList方法生成树状数据
List<SysDepartTreeModel> listResult = FindsDepartsChildrenUtil.wrapTreeDataToTreeList(list);
return listResult;
@ -144,9 +141,8 @@ public class SysDepartServiceImpl extends ServiceImpl<SysDepartMapper, SysDepart
List<SysDepartTreeModel> listResult=new ArrayList<>();
LambdaQueryWrapper<SysDepart> query = new LambdaQueryWrapper<SysDepart>();
query.eq(SysDepart::getDelFlag, CommonConstant.DEL_FLAG_0.toString());
//update-begin---author:wangshuai---date:2025-08-18---for:【QQYUN-13427】部门选择组件修改:需要过滤掉岗位 只保留 公司 子公司 部门---
// 代码逻辑说明: 【QQYUN-13427】部门选择组件修改:需要过滤掉岗位 只保留 公司 子公司 部门---
query.ne(SysDepart::getOrgCategory,DepartCategoryEnum.DEPART_CATEGORY_POST.getValue());
//update-end---author:wangshuai---date:2025-08-18---for:【QQYUN-13427】部门选择组件修改:需要过滤掉岗位 只保留 公司 子公司 部门---
if(oConvertUtils.isNotEmpty(ids)){
query.in(true,SysDepart::getId,ids.split(","));
}
@ -190,24 +186,22 @@ public class SysDepartServiceImpl extends ServiceImpl<SysDepartMapper, SysDepart
@Transactional(rollbackFor = Exception.class)
public void saveDepartData(SysDepart sysDepart, String username) {
if (sysDepart != null && username != null) {
//update-begin---author:wangshuai ---date:20230216 for[QQYUN-4163]给部门表加个是否有子节点------------
// 代码逻辑说明: [QQYUN-4163]给部门表加个是否有子节点------------
if (oConvertUtils.isEmpty(sysDepart.getParentId())) {
sysDepart.setParentId("");
}else{
//将父部门的设成不是叶子结点
departMapper.setMainLeaf(sysDepart.getParentId(),CommonConstant.NOT_LEAF);
}
//update-end---author:wangshuai ---date:20230216 for[QQYUN-4163]给部门表加个是否有子节点------------
//String s = UUID.randomUUID().toString().replace("-", "");
sysDepart.setId(IdWorker.getIdStr(sysDepart));
// 先判断该对象有无父级ID,有则意味着不是最高级,否则意味着是最高级
// 获取父级ID
String parentId = sysDepart.getParentId();
//update-begin--Author:baihailong Date:20191209 for部门编码规则生成器做成公用配置
// 代码逻辑说明: 部门编码规则生成器做成公用配置
JSONObject formData = new JSONObject();
formData.put("parentId",parentId);
String[] codeArray = (String[]) FillRuleUtil.executeRule(FillRuleConstant.DEPART,formData);
//update-end--Author:baihailong Date:20191209 for部门编码规则生成器做成公用配置
sysDepart.setOrgCode(codeArray[0]);
String orgType = codeArray[1];
sysDepart.setOrgType(String.valueOf(orgType));
@ -224,12 +218,10 @@ public class SysDepartServiceImpl extends ServiceImpl<SysDepartMapper, SysDepart
}
}
this.save(sysDepart);
//update-begin---author:wangshuai ---date:20220307 for[JTC-119]在部门管理菜单下设置部门负责人 创建用户的时候不需要处理
//新增部门的时候新增负责部门
if(oConvertUtils.isNotEmpty(sysDepart.getDirectorUserIds())){
this.addDepartByUserIds(sysDepart,sysDepart.getDirectorUserIds());
}
//update-end---author:wangshuai ---date:20220307 for[JTC-119]在部门管理菜单下设置部门负责人 创建用户的时候不需要处理
}
}
@ -241,7 +233,7 @@ public class SysDepartServiceImpl extends ServiceImpl<SysDepartMapper, SysDepart
* @return
*/
private String[] generateOrgCode(String parentId) {
//update-begin--Author:Steve Date:20190201 for组织机构添加数据代码调整
// 代码逻辑说明: 组织机构添加数据代码调整
LambdaQueryWrapper<SysDepart> query = new LambdaQueryWrapper<SysDepart>();
LambdaQueryWrapper<SysDepart> query1 = new LambdaQueryWrapper<SysDepart>();
String[] strArray = new String[2];
@ -297,7 +289,6 @@ public class SysDepartServiceImpl extends ServiceImpl<SysDepartMapper, SysDepart
strArray[0] = newOrgCode;
strArray[1] = orgType;
return strArray;
//update-end--Author:Steve Date:20190201 for组织机构添加数据代码调整
}
@ -325,10 +316,10 @@ public class SysDepartServiceImpl extends ServiceImpl<SysDepartMapper, SysDepart
//验证部门类型
this.verifyOrgCategory(sysDepart);
this.updateById(sysDepart);
//update-begin---author:wangshuai ---date:20220307 for[JTC-119]在部门管理菜单下设置部门负责人 创建用户的时候不需要处理
//修改部门管理的时候,修改负责部门
this.updateChargeDepart(sysDepart);
//update-begin---author:wangshuai ---date:20220307 for[JTC-119]在部门管理菜单下设置部门负责人 创建用户的时候不需要处理
//redis清除缓存key
redisUtil.removeAll(CommonConstant.DEPART_NAME_REDIS_KEY_PRE);
return true;
} else {
return false;
@ -371,7 +362,6 @@ public class SysDepartServiceImpl extends ServiceImpl<SysDepartMapper, SysDepart
throw new JeecgBootBizTipException("当前子级存在子公司,无法变更为部门!");
}
}
//update-end---author:wangshuai---date:2025-08-21---for: 当部门类型为岗位的时候,需要查看是否存在下级,存在下级无法变更为岗位---
}
@Override
@ -385,20 +375,17 @@ public class SysDepartServiceImpl extends ServiceImpl<SysDepartMapper, SysDepart
idList.add(id);
//此步骤是为了删除子级
this.checkChildrenExists(id, idList);
//update-begin---author:wangshuai ---date:20230712 for【QQYUN-5757】批量删除部门时未正确置为叶子节点 ------------
// 代码逻辑说明: 【QQYUN-5757】批量删除部门时未正确置为叶子节点 ------------
SysDepart depart = this.getDepartById(id);
if (oConvertUtils.isNotEmpty(depart.getParentId())) {
if (!parentIdList.contains(depart.getParentId())) {
parentIdList.add(depart.getParentId());
}
}
//update-end---author:wangshuai ---date:20230712 for【QQYUN-5757】批量删除部门时未正确置为叶子节点 ------------
}
this.removeByIds(idList);
//update-begin---author:wangshuai ---date:20230712 for【QQYUN-5757】批量删除部门时未正确置为叶子节点 ------------
//再删除前需要获取父级id不然会一直为空
this.setParentDepartIzLeaf(parentIdList);
//update-end---author:wangshuai ---date:20230712 for【QQYUN-5757】批量删除部门时未正确置为叶子节点 ------------
//根据部门id获取部门角色id
List<String> roleIdList = new ArrayList<>();
LambdaQueryWrapper<SysDepartRole> query = new LambdaQueryWrapper<>();
@ -419,6 +406,8 @@ public class SysDepartServiceImpl extends ServiceImpl<SysDepartMapper, SysDepart
//根据角色id删除部门角色用户信息
departRoleUserMapper.delete(new LambdaQueryWrapper<SysDepartRoleUser>().in(SysDepartRoleUser::getDroleId,roleIdList));
}
//删除岗位信息
this.deleteDepartPostByDepIds(idList);
}
@Override
@ -453,7 +442,7 @@ public class SysDepartServiceImpl extends ServiceImpl<SysDepartMapper, SysDepart
}
//根据部门id获取所负责部门
String[] codeArr = this.getMyDeptParentOrgCode(departIds);
//update-begin-author:taoyan date:20220104 for:/issues/3311 当用户属于两个部门的时候,且这两个部门没有上下级关系,我的部门-部门名称查询条件模糊搜索失效!
// 代码逻辑说明: /issues/3311 当用户属于两个部门的时候,且这两个部门没有上下级关系,我的部门-部门名称查询条件模糊搜索失效!
if (codeArr != null && codeArr.length > 0) {
query.nested(i -> {
for (String s : codeArr) {
@ -461,11 +450,9 @@ public class SysDepartServiceImpl extends ServiceImpl<SysDepartMapper, SysDepart
}
});
}
//update-end-author:taoyan date:20220104 for:/issues/3311 当用户属于两个部门的时候,且这两个部门没有上下级关系,我的部门-部门名称查询条件模糊搜索失效!
query.eq(SysDepart::getDelFlag, CommonConstant.DEL_FLAG_0.toString());
}
query.like(SysDepart::getDepartName, keyWord);
//update-begin---author:wangshuai---date:2025-08-20---for:【QQYUN-13428】增加岗位选择组件---
//需要根据部门类型进行数据筛选
if(oConvertUtils.isNotEmpty(orgCategory)){
query.in(SysDepart::getOrgCategory, Arrays.asList(orgCategory.split(SymbolConstant.COMMA)));
@ -483,15 +470,13 @@ public class SysDepartServiceImpl extends ServiceImpl<SysDepartMapper, SysDepart
});
}
}
//update-end---author:wangshuai---date:2025-08-20---for:【QQYUN-13428】增加岗位选择组件---
//update-begin--Author:huangzhilin Date:20140417 for[bugfree号]组织机构搜索回显优化--------------------
// 代码逻辑说明: [bugfree号]组织机构搜索回显优化--------------------
SysDepartTreeModel model = new SysDepartTreeModel();
List<SysDepart> departList = this.list(query);
if(departList.size() > 0) {
for(SysDepart depart : departList) {
model = new SysDepartTreeModel(depart);
model.setChildren(null);
//update-end--Author:huangzhilin Date:20140417 for[bugfree号]组织机构搜索功回显优化----------------------
newList.add(model);
}
return newList;
@ -553,7 +538,18 @@ public class SysDepartServiceImpl extends ServiceImpl<SysDepartMapper, SysDepart
@Override
public List<SysDepart> queryUserDeparts(String userId) {
return baseMapper.queryUserDeparts(userId);
List<SysDepart> sysDeparts = baseMapper.queryUserDeparts(userId);
sysDeparts.stream()
.filter(depart -> oConvertUtils.isNotEmpty(depart) &&
oConvertUtils.isNotEmpty(depart.getOrgCode()))
.forEach(depart -> {
String orgCategory = depart.getOrgCategory();
if(DepartCategoryEnum.DEPART_CATEGORY_DEPART.getValue().equalsIgnoreCase(orgCategory)){
String departPathName = this.getDepartPathNameByOrgCode(depart.getOrgCode(), "");
depart.setDepartPathName(departPathName);
}
});
return sysDeparts;
}
@Override
@ -693,27 +689,22 @@ public class SysDepartServiceImpl extends ServiceImpl<SysDepartMapper, SysDepart
}
//------------------------------------------------------------------------------------------------
lqw.eq(true,SysDepart::getDelFlag,CommonConstant.DEL_FLAG_0.toString());
//update-begin---author:wangshuai---date:2025-08-18---for:【QQYUN-13427】部门选择组件修改:需要过滤掉岗位 只保留 公司 子公司 部门---
// 代码逻辑说明: 【QQYUN-13427】部门选择组件修改:需要过滤掉岗位 只保留 公司 子公司 部门---
lqw.ne(SysDepart::getOrgCategory,DepartCategoryEnum.DEPART_CATEGORY_POST.getValue());
//update-end---author:wangshuai---date:2025-08-18---for:【QQYUN-13427】部门选择组件修改:需要过滤掉岗位 只保留 公司 子公司 部门---
lqw.func(square);
//update-begin---author:wangshuai ---date:20220527 for[VUEN-1143]排序不对vue3和2应该都有问题应该按照升序排------------
// 代码逻辑说明: [VUEN-1143]排序不对vue3和2应该都有问题应该按照升序排------------
lqw.orderByAsc(SysDepart::getDepartOrder);
//update-end---author:wangshuai ---date:20220527 for[VUEN-1143]排序不对vue3和2应该都有问题应该按照升序排--------------
List<SysDepart> list = list(lqw);
//update-begin---author:wangshuai ---date:20220316 for[JTC-119]在部门管理菜单下设置部门负责人 创建用户的时候不需要处理
//设置用户id,让前台显示
this.setUserIdsByDepList(list);
//update-end---author:wangshuai ---date:20220316 for[JTC-119]在部门管理菜单下设置部门负责人 创建用户的时候不需要处理
List<SysDepartTreeModel> records = new ArrayList<>();
for (int i = 0; i < list.size(); i++) {
SysDepart depart = list.get(i);
//update-begin---author:wangshuai---date:2025-08-18---for:【QQYUN-13427】部门选择组件修改:需要过滤掉岗位 只保留 公司 子公司 部门---
// 代码逻辑说明: 【QQYUN-13427】部门选择组件修改:需要过滤掉岗位 只保留 公司 子公司 部门---
long count = getNoDepartPostCount(depart.getId());
if(count == 0){
depart.setIzLeaf(CommonConstant.IS_LEAF);
}
//update-end---author:wangshuai---date:2025-08-18---for:【QQYUN-13427】部门选择组件修改:需要过滤掉岗位 只保留 公司 子公司 部门---
SysDepartTreeModel treeModel = new SysDepartTreeModel(depart);
//TODO 异步树加载key拼接__+时间戳,以便于每次展开节点会刷新数据
//treeModel.setKey(treeModel.getKey()+"__"+System.currentTimeMillis());
@ -755,7 +746,7 @@ public class SysDepartServiceImpl extends ServiceImpl<SysDepartMapper, SysDepart
}
} else {
if(oConvertUtils.isEmpty(parentId)){
//update-begin---author:wangshuai---date:2025-08-20---for:如果前端传过来的部门id不为空的时候说明是系统用户根据所属部门选择主岗位或者兼职岗位---
// 代码逻辑说明: 如果前端传过来的部门id不为空的时候说明是系统用户根据所属部门选择主岗位或者兼职岗位---
if(oConvertUtils.isNotEmpty(departIds)){
i.in(SysDepart::getId,Arrays.asList(departIds.split(SymbolConstant.COMMA)));
}else{
@ -765,7 +756,6 @@ public class SysDepartServiceImpl extends ServiceImpl<SysDepartMapper, SysDepart
i.like(SysDepart::getDepartName, orgName);
}
}
//update-end---author:wangshuai---date:2025-08-20---for:如果前端传过来的部门id不为空的时候说明是系统用户根据所属部门选择主岗位或者兼职岗位---
}else{
i.eq(true,SysDepart::getParentId,parentId);
}
@ -884,7 +874,6 @@ public class SysDepartServiceImpl extends ServiceImpl<SysDepartMapper, SysDepart
}
}
//update-begin---author:wangshuai ---date:20200308 for[JTC-119]在部门管理菜单下设置部门负责人,新增方法添加部门负责人、删除负责部门负责人、查询部门对应的负责人
/**
* 通过用户id设置负责部门
* @param sysDepart SysDepart部门对象
@ -1008,7 +997,6 @@ public class SysDepartServiceImpl extends ServiceImpl<SysDepartMapper, SysDepart
}
}
}
//update-end---author:wangshuai ---date:20200308 for[JTC-119]在部门管理菜单下设置部门负责人,新增方法添加部门负责人、删除负责部门负责人、查询部门对应的负责人
/**
* 获取我的部门已加入的公司
@ -1270,12 +1258,11 @@ public class SysDepartServiceImpl extends ServiceImpl<SysDepartMapper, SysDepart
}
//查询部门名称是否已存在
SysDepart parentDept = null;
//update-begin---author:wangshuai ---date:20230721 for一个租户部门名称可能有多个------------
// 代码逻辑说明: 一个租户部门名称可能有多个------------
List<SysDepart> sysDepartList = departMapper.getDepartByName(departName,tenantId,parentId);
if(CollectionUtil.isNotEmpty(sysDepartList)){
parentDept = sysDepartList.get(0);
}
//update-end---author:wangshuai ---date:20230721 for一个租户部门名称可能有多个------------
if(null != parentDept) {
//部门名称已存在
errorMessageList.add("" + lineNumber + " 行:记录部门名称“"+departName+"”已存在,请检查!");
@ -1322,13 +1309,12 @@ public class SysDepartServiceImpl extends ServiceImpl<SysDepartMapper, SysDepart
*/
private String getDepartListByName(String departName, Integer tenantId, SysDepart sysDepart,String[] departNameUrls, int count, int departNum,String name,Map<String,SysDepart> departMap) {
//递归查找下一级
//update-begin---author:wangshuai ---date:20230721 for一个租户部门名称可能有多个------------
// 代码逻辑说明: 一个租户部门名称可能有多个------------
SysDepart parentDept = null;
List<SysDepart> departList = departMapper.getDepartByName(departName,tenantId,sysDepart.getId());
if(CollectionUtil.isNotEmpty(departList)){
parentDept = departList.get(0);
}
//update-end---author:wangshuai ---date:20230721 for一个租户部门名称可能有多个------------
//判断是否包含/
if(oConvertUtils.isNotEmpty(name)){
name = name + SymbolConstant.SINGLE_SLASH + departName;
@ -1387,8 +1373,13 @@ public class SysDepartServiceImpl extends ServiceImpl<SysDepartMapper, SysDepart
*/
@Override
public List<SysDepartExportVo> getExportDepart(Integer tenantId, List<String> idList) {
String parentId = "";
if(CollectionUtil.isEmpty(idList)){
//-1代表父级部门为空的数据
parentId = "-1";
}
//获取父级部门
List<SysDepartExportVo> parentDepart = departMapper.getSysDepartList("", tenantId, idList);
List<SysDepartExportVo> parentDepart = departMapper.getSysDepartList(parentId, tenantId, idList);
//子部门
List<SysDepartExportVo> childrenDepart = new ArrayList<>();
//把一级部门名称放在里面
@ -1396,6 +1387,9 @@ public class SysDepartServiceImpl extends ServiceImpl<SysDepartMapper, SysDepart
//存放部门一级id避免重复
List<String> departIdList = new ArrayList<>();
for (SysDepartExportVo sysDepart : parentDepart) {
if(CollectionUtil.isNotEmpty(departIdList) && departIdList.contains(sysDepart.getId())){
continue;
}
//step 1.添加第一级部门
departIdList.add(sysDepart.getId());
sysDepart.setDepartNameUrl(sysDepart.getDepartName());
@ -1404,8 +1398,9 @@ public class SysDepartServiceImpl extends ServiceImpl<SysDepartMapper, SysDepart
//创建路径
List<String> path = new ArrayList<>();
path.add(sysDepart.getDepartName());
//创建子部门路径
findSysDepartPath(sysDepart, path, tenantId, childrenDepart, departIdList, idList);
//创建子部门路径
// 代码逻辑说明: 【JHHB-222】导出选中最顶级部门只能导出选中的部门---
findSysDepartPath(sysDepart, path, tenantId, childrenDepart, departIdList);
path.clear();
}
exportDepartVoList.addAll(childrenDepart);
@ -1514,12 +1509,11 @@ public class SysDepartServiceImpl extends ServiceImpl<SysDepartMapper, SysDepart
* @param tenantId 租户id
* @param childrenDepart 子部门
* @param departIdList 部门id集合
* @param idList 需要查询sql的部门id集合
*/
private void findSysDepartPath(SysDepartExportVo departVo, List<String> path, Integer tenantId, List<SysDepartExportVo> childrenDepart, List<String> departIdList, List<String> idList) {
private void findSysDepartPath(SysDepartExportVo departVo, List<String> path, Integer tenantId, List<SysDepartExportVo> childrenDepart, List<String> departIdList) {
//step 1.查询子部门的数据
//获取租户id和部门父id获取的部门数据
List<SysDepartExportVo> departList = departMapper.getSysDepartList(departVo.getId(), tenantId, idList);
List<SysDepartExportVo> departList = departMapper.getSysDepartList(departVo.getId(), tenantId, null);
//部门为空判断
if (departList == null || departList.size() <= 0) {
//判断最后一个子部门是否已拼接
@ -1541,8 +1535,9 @@ public class SysDepartServiceImpl extends ServiceImpl<SysDepartMapper, SysDepart
childrenDepart.add(departVo);
}
//step 3.递归查询子路径,直到找不到为止
findSysDepartPath(exportDepartVo, cPath, tenantId, childrenDepart, departIdList, idList);
}
// 代码逻辑说明: 【JHHB-222】导出选中最顶级部门只能导出选中的部门---
findSysDepartPath(exportDepartVo, cPath, tenantId, childrenDepart, departIdList);
}
}
//========================end 系统下部门与人员导入 ==================================================================
@ -1567,82 +1562,50 @@ public class SysDepartServiceImpl extends ServiceImpl<SysDepartMapper, SysDepart
if(null == postLevel){
throw new JeecgBootBizTipException("当前选择职级的职务等级为空,请前往职务管理进行修改!");
}
//step3 查看是否为董事长
if (1 == postLevel) {
//step4 如果是董事长查询上级子公司或者总公司下部门的所有的岗位
return this.getChairmanDepartPosition(sysDepart, departId);
} else {
//step5 如果不是董事长组查询当前父级部门、公司和子公司的岗位 和当前部门下的岗位,但是必须比当前职务的级别高
return this.getNotChairmanDepartPosition(sysDepart, postLevel, departId);
}
return this.getParentDepartPosition(sysDepart, postLevel, departId);
}
/**
* 获取董事长职位
*
* @param sysDepart
* @param id
* @return
*/
private List<SysPositionSelectTreeVo> getChairmanDepartPosition(SysDepart sysDepart, String id) {
//step1 先递归获取为子公司或者总共司的id
String departId = getCompanyDepartId(sysDepart.getParentId());
if (oConvertUtils.isNotEmpty(departId)) {
SysDepart depart = baseMapper.getDepartById(departId);
//如果当前上级部门就是子公司或者总公司的情况下
if (DepartCategoryEnum.DEPART_CATEGORY_COMPANY.getValue().equals(sysDepart.getOrgCategory()) || DepartCategoryEnum.DEPART_CATEGORY_SUB_COMPANY.getValue().equals(sysDepart.getOrgCategory())) {
depart.setParentId(departId);
List<SysPositionSelectTreeVo> departPosition = getDepartPosition(depart, null, id);
if (CollectionUtil.isNotEmpty(departPosition)) {
if (CollectionUtil.isNotEmpty(departPosition)) {
//父级id不为空并且当前部门不是子公司或者总公司则需要寻上顶级公司
return getSuperiorCompany(departPosition);
}
}
return departPosition;
} else {
//step2 获取上一个子公司或者总公司下的岗位
String parentId = getCompanyDepartId(depart.getParentId());
if (oConvertUtils.isNotEmpty(departId)) {
depart = baseMapper.getDepartById(parentId);
if (null != depart) {
depart.setParentId(parentId);
List<SysPositionSelectTreeVo> departPosition = getDepartPosition(depart, null, id);
//step3 获取上级部门信息,一直获取到子公司或者总公司为止
if (CollectionUtil.isNotEmpty(departPosition)) {
//父级id不为空并且当前部门不是子公司或者总公司则需要寻上顶级公司
return getSuperiorCompany(departPosition);
}
return departPosition;
}
}
}
}
return null;
}
/*
* 获取不是董事长的数据
* 获取上级部门岗位 或者当前部门下级别高的
*
* @param sysDepart
* @param postLevel
* @param id
* @return
*/
private List<SysPositionSelectTreeVo> getNotChairmanDepartPosition(SysDepart sysDepart, Integer postLevel, String id) {
private List<SysPositionSelectTreeVo> getParentDepartPosition(SysDepart sysDepart, Integer postLevel, String id) {
//step1 先获取上级部门下的数据
List<SysPositionSelectTreeVo> departPosition = getDepartPosition(sysDepart, postLevel, id);
//已经存在的code
List<String> existCodeList = new ArrayList<>();
List<SysPositionSelectTreeVo> departPosition = getDepartPosition(sysDepart, postLevel, id, existCodeList);
//step2 获取上级部门信息,一直获取到子公司或者总公司为止
if (CollectionUtil.isNotEmpty(departPosition)) {
if (CollectionUtil.isNotEmpty(departPosition)) {
//父级id不为空并且当前部门不是子公司或者总公司则需要寻上顶级公司
return getSuperiorCompany(departPosition);
//父级id不为空并且当前部门不是子公司或者总公司则需要寻上顶级公司
// 代码逻辑说明: 【JHHB-501】三级子公司的董事长岗位存在向一级公司总经理汇报的职级关系现在无法配置---
String parentId = sysDepart.getParentId();
SysDepart depart = departMapper.getDepartById(parentId);
if(null != depart){
//获取长度
int codeNum = YouBianCodeUtil.ZHANWEI_LENGTH;
List<String> codeList = getCodeHierarchy(depart.getOrgCode(), codeNum);
if(null != codeList && codeList.size() > 1){
//需要将当前和上级部门的排除掉
existCodeList.add(codeList.get(codeList.size() - 1));
//从上向下找存在子级的code
List<SysPositionSelectTreeVo> parentDepartPost = this.getParentDepartPost(codeList, existCodeList);
//当前父级部门下存在职级必当前高的需要同事渲染
if (CollectionUtil.isNotEmpty(departPosition)) {
departPosition.addAll(parentDepartPost);
return buildTree(departPosition);
}else if(CollectionUtil.isNotEmpty(parentDepartPost)){
return buildTree(parentDepartPost);
}
}
return departPosition;
}
return departPosition;
// 代码逻辑说明: 【JHHB-501】三级子公司的董事长岗位存在向一级公司总经理汇报的职级关系现在无法配置---
if(CollectionUtil.isNotEmpty(departPosition)){
return getSuperiorCompany(departPosition);
}
return null;
}
/**
@ -1667,19 +1630,59 @@ public class SysDepartServiceImpl extends ServiceImpl<SysDepartMapper, SysDepart
}
}
/**
* 获取父级部门下的一级岗位
*
* @param codeList
* @param existCodeList 已存在的部门编码
*/
private List<SysPositionSelectTreeVo> getParentDepartPost(List<String> codeList, List<String> existCodeList) {
List<SysPositionSelectTreeVo> list = new ArrayList<>();
for (String orgCode : codeList){
if(existCodeList.contains(orgCode)){
continue;
}
//当前部门
SysDepart depart = departMapper.queryDepartByOrgCode(orgCode);
SysPositionSelectTreeVo sysPositionSelectTreeVo = new SysPositionSelectTreeVo(depart);
sysPositionSelectTreeVo.setLeaf(false);
list.add(sysPositionSelectTreeVo);
//查找当前部门下一级部门存在岗位的部门信息
List<SysDepart> departByParentId = departMapper.getDepartByParentId(depart.getId());
List<String> parentIds = new ArrayList<>();
for (SysDepart sysDepart : departByParentId) {
list.add(new SysPositionSelectTreeVo(sysDepart));
// 代码逻辑说明: 上级岗位太慢sql优化---
parentIds.add(sysDepart.getId());
}
// 代码逻辑说明: 上级岗位太慢sql优化---
if(CollectionUtil.isNotEmpty(parentIds)){
//根据父级id获取部门岗位信息
List<SysDepart> departPositionList = departMapper.getDepartPositionByParentIds(parentIds);
if(CollectionUtil.isNotEmpty(departPositionList)){
List<SysPositionSelectTreeVo> sysDepartTreeModels = sysDepartToTreeModel(departPositionList);
list.addAll(sysDepartTreeModels);
}
}
}
return list;
}
/**
* 获取部门职务
*
* @param sysDepart
* @param postLevel
* @param existCodeList
*/
private List<SysPositionSelectTreeVo> getDepartPosition(SysDepart sysDepart, Integer postLevel, String id) {
private List<SysPositionSelectTreeVo> getDepartPosition(SysDepart sysDepart, Integer postLevel, String id, List<String> existCodeList) {
//step1 获取部门下的所有部门
String parentId = sysDepart.getParentId();
List<SysDepart> departList = baseMapper.getDepartByParentId(parentId);
List<SysPositionSelectTreeVo> treeModels = new ArrayList<>();
for (int i = 0; i < departList.size(); i++) {
SysDepart depart = departList.get(i);
existCodeList.add(depart.getOrgCode());
//如果是叶子节点说明没有岗位直接跳出循环
if (depart.getIzLeaf() == 1) {
if (DepartCategoryEnum.DEPART_CATEGORY_POST.getValue().equals(depart.getOrgCategory())) {
@ -1800,36 +1803,44 @@ public class SysDepartServiceImpl extends ServiceImpl<SysDepartMapper, SysDepart
* 构建树形结构,只返回没有父级的一级节点
*/
public static List<SysPositionSelectTreeVo> buildTree(List<SysPositionSelectTreeVo> nodes) {
// 存储一级节点(没有父级的节点)
List<SysPositionSelectTreeVo> rootNodes = new ArrayList<>();
// 先找出所有一级节点parentId为null或空
for (SysPositionSelectTreeVo node : nodes) {
if (node.getParentId() == null || node.getParentId().trim().isEmpty()) {
rootNodes.add(node);
// 1. 去重根据ID去重保留第一个
Map<String, SysPositionSelectTreeVo> uniqueNodes = nodes.stream()
.filter(Objects::nonNull)
.filter(node -> node.getId() != null && !node.getId().trim().isEmpty())
.collect(Collectors.toMap(
SysPositionSelectTreeVo::getId,
node -> node,
(existing, replacement) -> existing,
LinkedHashMap::new
));
// 2. 初始化所有节点的children列表
uniqueNodes.values().forEach(node -> {
if (node.getChildren() == null) {
node.setChildren(new ArrayList<>());
}
});
// 3. 构建树形结构
List<SysPositionSelectTreeVo> rootNodes = new ArrayList<>();
for (SysPositionSelectTreeVo node : uniqueNodes.values()) {
String parentId = node.getParentId();
if (parentId == null || parentId.trim().isEmpty()) {
// 根节点
rootNodes.add(node);
} else {
// 子节点,查找父节点
SysPositionSelectTreeVo parent = uniqueNodes.get(parentId);
if (parent != null) {
parent.getChildren().add(node);
} else {
// 父节点不存在,当作根节点处理
rootNodes.add(node);
}
}
}
// 为每个一级节点递归设置子节点
for (SysPositionSelectTreeVo root : rootNodes) {
setChildren(root, nodes);
}
return rootNodes;
}
/**
* 递归为节点设置子节点
*/
private static void setChildren(SysPositionSelectTreeVo parentNode, List<SysPositionSelectTreeVo> allNodes) {
for (SysPositionSelectTreeVo node : allNodes) {
// 如果当前节点的父ID等于父节点的ID则是子节点
if (parentNode.getId().equals(node.getParentId())) {
// 递归为子节点设置它的子节点
setChildren(node, allNodes);
// 将子节点添加到父节点的子节点列表
parentNode.getChildren().add(node);
}
}
}
//=========================end 部门岗位改造 ==================================================================
@Override
@ -1859,7 +1870,8 @@ public class SysDepartServiceImpl extends ServiceImpl<SysDepartMapper, SysDepart
List<SysDepart> sysDepartList = departMapper.selectList(query);
if(!CollectionUtils.isEmpty(sysDepartList)){
//获取部门名称拼接返回给前台
List<String> departNameList = sysDepartList.stream().map(SysDepart::getDepartName).toList();
// 代码逻辑说明: 【JHHB-631】【部门管理】存在缩写使用缩写来显示---
List<String> departNameList = sysDepartList.stream().map(item-> oConvertUtils.getString(item.getDepartNameAbbr(),item.getDepartName())).toList();
String departNames = String.join("/", departNameList);
redisUtil.set(CommonConstant.DEPART_NAME_REDIS_KEY_PRE + orgCode,departNames);
return departNames;
@ -1889,4 +1901,355 @@ public class SysDepartServiceImpl extends ServiceImpl<SysDepartMapper, SysDepart
}
return hierarchy;
}
/**
* 根据多个部门id删除主岗位和兼职岗位
*
* @param idList
*/
private void deleteDepartPostByDepIds(List<String> idList) {
//更新用户主岗位位空使用LambdaUpdateWrapper避免为空时受全局 updateStrategy 影响导致误更新
LambdaUpdateWrapper<SysUser> userQuery = new LambdaUpdateWrapper<>();
userQuery.in(SysUser::getMainDepPostId, idList);
userQuery.set(SysUser::getMainDepPostId, null);
sysUserMapper.update(userQuery);
//删除兼职岗位
LambdaQueryWrapper<SysUserDepPost> postQuery = new LambdaQueryWrapper<>();
postQuery.in(SysUserDepPost::getDepId, idList);
sysUserDepPostMapper.delete(postQuery);
//redis清除缓存key
redisUtil.removeAll(CommonConstant.DEPART_NAME_REDIS_KEY_PRE);
}
/**
* 根据部门id获取部门下的岗位id
*
* @param depIds 当前选择的公司、子公司、部门id
* @return
*/
@Override
public String getDepPostIdByDepId(String depIds) {
if (oConvertUtils.isEmpty(depIds)) {
return "";
}
//step1 先根据部门id获取编码
List<SysUserDepVo> departIdList = departMapper.getDepartByIds(Arrays.asList(depIds.split(SymbolConstant.COMMA)));
if (CollectionUtil.isNotEmpty(departIdList)) {
//step2 根据部门编码查询岗位id
LambdaQueryWrapper<SysDepart> query = new LambdaQueryWrapper<>();
query.select(SysDepart::getId);
departIdList.forEach(item -> {
query.or(lq-> lq.likeRight(SysDepart::getOrgCode, item.getOrgCode()));
});
query.eq(SysDepart::getOrgCategory, DepartCategoryEnum.DEPART_CATEGORY_POST.getValue());
List<SysDepart> departList = departMapper.selectList(query);
//step3 返回部门id
if (CollectionUtil.isNotEmpty(departList)) {
return departList.stream().map(SysDepart::getId).collect(Collectors.joining(SymbolConstant.COMMA));
}
}
return "";
}
/**
* 变更部门位置
*
* @param changeDepartVo
* @return orgCode 部门id
*/
@Transactional(rollbackFor = Exception.class)
@Override
public void updateChangeDepart(SysChangeDepartVo changeDepartVo) {
String dragId = changeDepartVo.getDragId();
// 1. 获取被拖拽的部门
SysDepart dragDept = baseMapper.getDepartById(dragId);
if (null == dragDept) {
throw new JeecgBootBizTipException("被拖拽的部门不存在");
}
// 2. 获取目标部门
String dropId = changeDepartVo.getDropId();
SysDepart targetDept = baseMapper.getDepartById(dropId);
if (null == targetDept) {
throw new JeecgBootBizTipException("目标部门不存在");
}
//3. 验证拖拽操作是否合法
validateDragOperation(dragDept, targetDept, changeDepartVo.getDropPosition());
//4. 根据dropPosition调整部门顺序
Integer dropPosition = changeDepartVo.getDropPosition();
switch (dropPosition) {
case -1:
// 拖拽到上方
moveToAbove(dragDept, targetDept);
break;
case 0:
// 拖拽到内部(作为子部门)
moveAsChild(dragDept, targetDept);
break;
case 1:
//拖拽到下方
moveToBelow(dragDept, targetDept, changeDepartVo.getSort());
break;
default:
throw new RuntimeException("无效的拖拽位置");
}
//5. 清空缓存
redisUtil.removeAll(CommonConstant.DEPART_NAME_REDIS_KEY_PRE);
}
/**
* 验证拖拽操作是否合法
*
* @param dragDept 被拖拽的部门
* @param targetDept 目标部门
* @param dropPosition 拖拽位置
*/
private void validateDragOperation(SysDepart dragDept, SysDepart targetDept, Integer dropPosition) {
// 禁止拖拽到自身
if (dragDept.getId().equals(targetDept.getId())) {
throw new RuntimeException("不能拖拽到自身");
}
// 禁止拖拽到自身子部门
if (isDescendant(dragDept, targetDept.getId())) {
throw new RuntimeException("不能拖拽到自身子部门");
}
//公司岗位判断
String orgCategory = targetDept.getOrgCategory();
String oldOrgCategory = dragDept.getOrgCategory();
//部门为公司
if(0 != dropPosition && DepartCategoryEnum.DEPART_CATEGORY_COMPANY.getValue().equals(orgCategory)){
//当前部门不能为子公司、部门和岗位
if(!DepartCategoryEnum.DEPART_CATEGORY_COMPANY.getValue().equals(oldOrgCategory)){
throw new JeecgBootBizTipException("当前部门类型为【"+DepartCategoryEnum.getNameByValue(oldOrgCategory)+"】,不允许移动到公司");
}
}
//部门为岗位不允许移入
if(0 == dropPosition && DepartCategoryEnum.DEPART_CATEGORY_POST.getValue().equals(orgCategory)) {
throw new JeecgBootBizTipException("岗位不允许存在子级");
}
//公司不能做为子级
if(oConvertUtils.isNotEmpty(targetDept.getParentId()) && DepartCategoryEnum.DEPART_CATEGORY_COMPANY.getValue().equals(oldOrgCategory)){
throw new JeecgBootBizTipException("公司不允许作为子级");
}
}
/**
* 判断目标部门是否是被拖拽部门的子部门
*/
private boolean isDescendant(SysDepart dragDept, String targetId) {
List<SysDepart> children = departMapper.getDepartByParentId(dragDept.getId());
for (SysDepart child : children) {
if (child.getId().equals(targetId)) {
return true;
}
if (isDescendant(child, targetId)) {
return true;
}
}
return false;
}
/**
* 拖拽到上方:将部门移动到目标部门上方(只有最上级 即公司才会走这个逻辑)
* @param dragDept 被拖拽的部门
* @param targetDept 目标部门
*/
private void moveToAbove(SysDepart dragDept, SysDepart targetDept) {
// 获取目标部门同级的所有部门
List<SysDepart> siblings = departMapper.getDepartNoParent();
// 计算新的排序值
Integer newDepartOrder = targetDept.getDepartOrder();
// 更新被拖拽部门的排序值
dragDept.setDepartOrder(newDepartOrder);
// 更新被拖拽部门的排序值
dragDept.setDepartOrder(0);
if(CollectionUtil.isNotEmpty(siblings)){
// 计算新的排序值
this.computingSort(siblings,0,dragDept.getId());
// 保存所有更新的部门
this.updateBatchById(siblings);
}
departMapper.updateById(dragDept);
}
/**
* 拖拽到下方:将部门移动到目标部门下方
*
* @param dragDept 被拖拽的部门
* @param targetDept 目标部门
* @param sort 排序
*/
private void moveToBelow(SysDepart dragDept, SysDepart targetDept, Integer sort) {
String parentId = targetDept.getParentId();
List<SysDepart> siblings = null;
if(oConvertUtils.isNotEmpty(parentId)){
// 获取目标部门同级的所有部门
siblings = departMapper.getDepartByParentId(parentId);
}else{
siblings = departMapper.getDepartNoParent();
}
String oldParentId = dragDept.getParentId();
//判断父级部门id是否相同不同则更新为目标部门的父部门id
if(oConvertUtils.isNotEmpty(dragDept.getParentId()) &&
oConvertUtils.isNotEmpty(parentId) &&
!dragDept.getParentId().equals(parentId)){
String oldOrgCode = dragDept.getOrgCode();
//设置父级id和部门code
this.setDepartParentAndOrgCode(dragDept, parentId);
//修改子级的部门编码
this.updateChildOrgCode(dragDept.getOrgCode(), oldOrgCode);
}
// 更新被拖拽部门的排序值
dragDept.setDepartOrder(sort);
if(CollectionUtil.isNotEmpty(siblings)){
// 计算新的排序值
this.computingSort(siblings,sort,dragDept.getId());
// 保存所有更新的部门
this.updateBatchById(siblings);
}
departMapper.updateById(dragDept);
if(oConvertUtils.isNotEmpty(oldParentId)){
long count = departMapper.countByParentId(oldParentId);
if(count == 0){
this.updateIzLeaf(oldParentId,CommonConstant.IS_LEAF);
}
}
}
/**
* 拖拽到内部:将部门移动到目标部门内部(作为子部门)
*/
private void moveAsChild(SysDepart dragDept, SysDepart targetDept) {
// 更新父部门ID
String parentId = targetDept.getId();
String oldParentId = dragDept.getParentId();
// 获取目标部门同级的所有部门
List<SysDepart> siblings = departMapper.getDepartByParentId(parentId);
//判断父级部门id是否相同不同则更新为目标部门的父部门id
if(oConvertUtils.isNotEmpty(dragDept.getParentId()) &&
oConvertUtils.isNotEmpty(parentId) &&
!dragDept.getParentId().equals(parentId)){
String oldOrgCode = dragDept.getOrgCode();
//设置父级id和部门code
this.setDepartParentAndOrgCode(dragDept, parentId);
//修改子级的部门编码
this.updateChildOrgCode(dragDept.getOrgCode(), oldOrgCode);
}
//内部排序为0
Integer sort = 0;
// 设置新的排序值
dragDept.setDepartOrder(sort);
if(CollectionUtil.isNotEmpty(siblings)){
// 计算新的排序值
this.computingSort(siblings,sort,dragDept.getId());
// 保存所有更新的部门
this.updateBatchById(siblings);
}
departMapper.updateById(dragDept);
this.updateIzLeaf(parentId, CommonConstant.NOT_LEAF);
if(oConvertUtils.isNotEmpty(oldParentId)){
long count = departMapper.countByParentId(oldParentId);
if(count == 0){
this.updateIzLeaf(oldParentId,CommonConstant.IS_LEAF);
}
}
}
/**
* 计算排序值
*
* @param siblings
* @param sort
* @param id
*/
private void computingSort(List<SysDepart> siblings, Integer sort, String id) {
for (int i = 0; i < siblings.size(); i++) {
SysDepart depart = siblings.get(i);
if(id.equals(depart.getId())){
continue;
}
//如果当前循环的sort大等于传入的sort值 则需要+1
if(i >= sort){
depart.setDepartOrder(sort + 1);
sort++;
} else {
depart.setDepartOrder(i);
}
}
}
/**
* 设置被拖拽部门的父级id和部门编码
*
* @param dragDept 被拖拽的部门
* @param parentId 目标部门的父级id
*/
private void setDepartParentAndOrgCode(SysDepart dragDept, String parentId) {
// 更新父部门ID与目标部门相同
dragDept.setParentId(parentId);
Page<SysDepart> page = new Page<>(1, 1);
//需要获取父级id查看父级是否已经存在
//获取一级部门的最大orgCode
List<SysDepart> records = departMapper.getMaxCodeDepart(page, parentId);
String newOrgCode = "";
if (CollectionUtil.isNotEmpty(records)) {
newOrgCode = YouBianCodeUtil.getNextYouBianCode(records.get(0).getOrgCode());
} else {
//查询父id
if (oConvertUtils.isNotEmpty(parentId)) {
SysDepart departById = departMapper.getDepartById(parentId);
newOrgCode = YouBianCodeUtil.getSubYouBianCode(departById.getOrgCode(), null);
} else {
newOrgCode = YouBianCodeUtil.getNextYouBianCode(null);
}
}
dragDept.setOrgCode(newOrgCode);
}
/**
* 修改子级的部门编码
*
* @param newOrgCode 当前父级新的部门编码
* @param oldOrgCode 当前父级旧的部门编码
*/
private void updateChildOrgCode(String newOrgCode, String oldOrgCode) {
//查询当前部门下的所有子级部门
LambdaQueryWrapper<SysDepart> query = new LambdaQueryWrapper<>();
query.likeRight(SysDepart::getOrgCode, oldOrgCode);
query.orderByAsc(SysDepart::getDepartOrder);
query.orderByDesc(SysDepart::getCreateTime);
query.select(SysDepart::getId, SysDepart::getOrgCode);
List<SysDepart> childDeparts = departMapper.selectList(query);
if (CollectionUtil.isNotEmpty(childDeparts)) {
for (SysDepart depart : childDeparts) {
String orgCode = depart.getOrgCode();
if (orgCode.startsWith(oldOrgCode)) {
orgCode = newOrgCode + orgCode.substring(oldOrgCode.length());
}
depart.setOrgCode(orgCode);
}
}
this.updateBatchById(childDeparts);
}
/**
* 获取部门负责人
*
* @param departId
* @param page
* @return
*/
@Override
public IPage<SysUser> getDepartmentHead(String departId, Page<SysUser> page) {
List<SysUser> departmentHead = departMapper.getDepartmentHead(page, departId);
if(CollectionUtil.isNotEmpty(departmentHead)){
departmentHead.forEach(item->{
//兼职岗位
List<String> depPostList = sysUserDepPostMapper.getDepPostByUserId(item.getId());
if(CollectionUtil.isNotEmpty(depPostList)){
item.setOtherDepPostId(StringUtils.join(depPostList.toArray(), SymbolConstant.COMMA));
}
});
}
return page.setRecords(departmentHead);
}
}

View File

@ -95,11 +95,10 @@ public class SysDictServiceImpl extends ServiceImpl<SysDictMapper, SysDict> impl
// 4.执行SQL 查询是否存在值
try{
//update-begin---author:chenrui ---date:20240715 for[TV360X-49]postgres日期、年月日时分秒唯一校验报错------------
// 代码逻辑说明: [TV360X-49]postgres日期、年月日时分秒唯一校验报错------------
if(DbTypeUtils.dbTypeIsPostgre(CommonUtils.getDatabaseTypeEnum())){
duplicateCheckVo.setFieldName("CAST("+duplicateCheckVo.getFieldName()+" as text)");
}
//update-end---author:chenrui ---date:20240715 for[TV360X-49]postgres日期、年月日时分秒唯一校验报错------------
if (StringUtils.isNotBlank(duplicateCheckVo.getDataId())) {
// [1].编辑页面校验
count = sysDictMapper.duplicateCheckCountSql(duplicateCheckVo);
@ -151,9 +150,8 @@ public class SysDictServiceImpl extends ServiceImpl<SysDictMapper, SysDict> impl
for (DictModelMany dict : list) {
List<DictModel> dictItemList = dictMap.computeIfAbsent(dict.getDictCode(), i -> new ArrayList<>());
//update-begin-author:taoyan date:2023-4-28 for: QQYUN-5183【简流】多字段拼接-多选框、下拉框 等需要翻译的字段
// 代码逻辑说明: QQYUN-5183【简流】多字段拼接-多选框、下拉框 等需要翻译的字段
//dict.setDictCode(null);
//update-end-author:taoyan date:2023-4-28 for: QQYUN-5183【简流】多字段拼接-多选框、下拉框 等需要翻译的字段
dictItemList.add(new DictModel(dict.getValue(), dict.getText(), dict.getColor()));
}
@ -162,7 +160,7 @@ public class SysDictServiceImpl extends ServiceImpl<SysDictMapper, SysDict> impl
@Override
public Map<String, List<DictModel>> queryAllDictItems() {
log.info(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
log.debug(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
long start = System.currentTimeMillis();
Map<String, List<DictModel>> sysAllDictItems = new HashMap(5);
List<Integer> tenantIds = null;
@ -181,16 +179,16 @@ public class SysDictServiceImpl extends ServiceImpl<SysDictMapper, SysDict> impl
sysAllDictItems = sysDictItemList.stream()
.collect(Collectors.groupingBy(DictModelMany::getDictCode,
Collectors.mapping(d -> new DictModel(d.getValue(), d.getText(), d.getColor()), Collectors.toList())));
log.info(" >>> 1 获取系统字典项耗时SQL" + (System.currentTimeMillis() - start) + "毫秒");
log.debug(" >>> 1 获取系统字典项耗时SQL" + (System.currentTimeMillis() - start) + "毫秒");
Map<String, List<DictModel>> enumRes = ResourceUtil.getEnumDictData();
sysAllDictItems.putAll(enumRes);
log.info(" >>> 2 获取系统字典项耗时Enum" + (System.currentTimeMillis() - start) + "毫秒");
log.debug(" >>> 2 获取系统字典项耗时Enum" + (System.currentTimeMillis() - start) + "毫秒");
log.info(" >>> end 获取系统字典库总耗时:" + (System.currentTimeMillis() - start) + "毫秒");
log.info(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
log.debug(" >>> end 获取系统字典库总耗时:" + (System.currentTimeMillis() - start) + "毫秒");
log.debug(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
//log.info("-------登录加载系统字典-----" + sysAllDictItems.toString());
//log.debug("-------登录加载系统字典-----" + sysAllDictItems.toString());
return sysAllDictItems;
}
@ -216,10 +214,9 @@ public class SysDictServiceImpl extends ServiceImpl<SysDictMapper, SysDict> impl
List<DictModel> dictItemList = dictMap.computeIfAbsent(dict.getDictCode(), i -> new ArrayList<>());
dictItemList.add(new DictModel(dict.getValue(), dict.getText()));
}
//update-begin-author:taoyan date:2022-7-8 for: 系统字典数据应该包括自定义的java类-枚举
// 代码逻辑说明: 系统字典数据应该包括自定义的java类-枚举
Map<String, List<DictModel>> enumRes = ResourceUtil.queryManyDictByKeys(dictCodeList, keys);
dictMap.putAll(enumRes);
//update-end-author:taoyan date:2022-7-8 for: 系统字典数据应该包括自定义的java类-枚举
return dictMap;
}
@ -352,7 +349,6 @@ public class SysDictServiceImpl extends ServiceImpl<SysDictMapper, SysDict> impl
return null;
}
}
//update-end---author:chenrui ---date:20231221 for[issues/#5643]解决分布式下表字典跨库无法查询问题------------
// 2.分割SQL获取表名和条件
String filterSql = null;
@ -371,7 +367,6 @@ public class SysDictServiceImpl extends ServiceImpl<SysDictMapper, SysDict> impl
text = SqlInjectionUtil.getSqlInjectField(text);
code = SqlInjectionUtil.getSqlInjectField(code);
//update-begin---author:chenrui ---date:20231221 for[issues/#5643]解决分布式下表字典跨库无法查询问题------------
// 切换为字典表的数据源
if (isCustomDataSource) {
DynamicDataSourceContextHolder.push(dataSource);
@ -382,8 +377,6 @@ public class SysDictServiceImpl extends ServiceImpl<SysDictMapper, SysDict> impl
DynamicDataSourceContextHolder.clear();
}
return restData;
//update-end---author:chenrui ---date:20231221 for[issues/#5643]解决分布式下表字典跨库无法查询问题------------
//update-end-author:taoyan date:20220113 for: @dict注解支持 dicttable 设置where条件
}
@Override
@ -478,11 +471,10 @@ public class SysDictServiceImpl extends ServiceImpl<SysDictMapper, SysDict> impl
insert = sysDictMapper.insert(sysDict);
if (sysDictItemList != null) {
for (SysDictItem entity : sysDictItemList) {
//update-begin---author:wangshuai ---date:20220211 for[JTC-1168]如果字典项值为空,则字典项忽略导入------------
// 代码逻辑说明: [JTC-1168]如果字典项值为空,则字典项忽略导入------------
if(oConvertUtils.isEmpty(entity.getItemValue())){
return -1;
}
//update-end---author:wangshuai ---date:20220211 for[JTC-1168]如果字典项值为空,则字典项忽略导入------------
entity.setDictId(sysDict.getId());
entity.setStatus(1);
sysDictItemMapper.insert(entity);
@ -566,9 +558,8 @@ public class SysDictServiceImpl extends ServiceImpl<SysDictMapper, SysDict> impl
if (oConvertUtils.isNotEmpty(keyword)) {
// 判断是否是多选
if (keyword.contains(SymbolConstant.COMMA)) {
//update-begin--author:scott--date:20220105--forJTC-529【表单设计器】 编辑页面报错in参数采用双引号导致 ----
// 代码逻辑说明: JTC-529【表单设计器】 编辑页面报错in参数采用双引号导致 ----
String inKeywords = "'" + String.join("','", keyword.split(",")) + "'";
//update-end--author:scott--date:20220105--forJTC-529【表单设计器】 编辑页面报错in参数采用双引号导致----
keywordSql = "(" + text + " in (" + inKeywords + ") or " + code + " in (" + inKeywords + "))";
} else {
keywordSql = "("+text + " like '%"+keyword+"%' or "+ code + " like '%"+keyword+"%')";
@ -577,7 +568,7 @@ public class SysDictServiceImpl extends ServiceImpl<SysDictMapper, SysDict> impl
}
//下拉搜索组件 支持传入排序信息 查询排序
//update-begin---author:chenrui ---date:20240327 for[QQYUN-8514]Online表单中 下拉搜索框 搜索时报sql错误生成的SQL多了一个 “and" ------------
// 代码逻辑说明: [QQYUN-8514]Online表单中 下拉搜索框 搜索时报sql错误生成的SQL多了一个 “and" ------------
if (oConvertUtils.isNotEmpty(condition) && oConvertUtils.isNotEmpty(keywordSql)) {
filterSql += sqlWhere + (tableHasWhere ? sqlAnd : " ") + condition + sqlAnd + keywordSql;
} else if (oConvertUtils.isNotEmpty(condition)) {
@ -587,7 +578,6 @@ public class SysDictServiceImpl extends ServiceImpl<SysDictMapper, SysDict> impl
} else if (tableHasWhere) {
filterSql += sqlWhere;
}
//update-end---author:chenrui ---date:20240327 for[QQYUN-8514]Online表单中 下拉搜索框 搜索时报sql错误生成的SQL多了一个 “and" ------------
// 增加排序逻辑
if (oConvertUtils.isNotEmpty(orderField)) {
filterSql += " order by " + orderField + " " + orderType;
@ -626,7 +616,15 @@ public class SysDictServiceImpl extends ServiceImpl<SysDictMapper, SysDict> impl
public List<TreeSelectModel> queryTreeList(Map<String, String> query, String table, String text, String code, String pidField, String pid, String hasChildField, int converIsLeafVal) {
//为了防止sqljeecg提供了防注入的方法可以在拼接 SQL 语句时自动对参数进行转义避免SQL注入攻击
// 1.针对采用 ${}写法的表名和字段进行转义和check
table = SqlInjectionUtil.getSqlInjectTableName(table);
//update-begin---author:chenrui ---date:20251015 for[QQYUN-13741]【客户问题 南自】online表单自定义树 表后边加条件时 不生效------------
// 分割SQL获取表名和条件
String filterSql = null;
if(table.toLowerCase().indexOf(DataBaseConstant.SQL_WHERE)>0){
String[] arr = table.split(" (?i)where ");
table = arr[0];
filterSql = oConvertUtils.getString(arr[1], null);
}
table = SqlInjectionUtil.getSqlInjectTableName(table);
text = SqlInjectionUtil.getSqlInjectField(text);
code = SqlInjectionUtil.getSqlInjectField(code);
pidField = SqlInjectionUtil.getSqlInjectField(pidField);
@ -641,6 +639,7 @@ public class SysDictServiceImpl extends ServiceImpl<SysDictMapper, SysDict> impl
// 2.检测最终SQL是否存在SQL注入风险
String dictCode = table + "," + text + "," + code;
SqlInjectionUtil.filterContentMulti(dictCode);
SqlInjectionUtil.specialFilterContentForDictSql(filterSql);
// 【QQYUN-6533】表字典白名单check
sysBaseAPI.dictTableWhiteListCheckByDict(table, text, code);
@ -650,14 +649,17 @@ public class SysDictServiceImpl extends ServiceImpl<SysDictMapper, SysDict> impl
return null;
}
// 4.检测查询条件是否存在SQL注入
Map<String, String> queryParams = null;
Map<String, String> queryParams = queryParams = new HashMap<>(4);
if (query != null) {
queryParams = new HashMap<>(5);
for (Map.Entry<String, String> searchItem : query.entrySet()) {
String fieldName = searchItem.getKey();
queryParams.put(SqlInjectionUtil.getSqlInjectField(fieldName), searchItem.getValue());
}
}
// 代码逻辑说明: [QQYUN-13741]【客户问题 南自】online表单自定义树 表后边加条件时 不生效------------
if(oConvertUtils.isNotEmpty(filterSql)){
queryParams.put("_tableFilterSql", filterSql);
}
return baseMapper.queryTreeList(queryParams, table, text, code, pidField, pid, hasChildField, converIsLeafVal);
}
@ -675,14 +677,13 @@ public class SysDictServiceImpl extends ServiceImpl<SysDictMapper, SysDict> impl
@Override
public List<SysDict> queryDeleteList(String tenantId) {
//update-begin---author:wangshuai---date:2024-02-27---for:【QQYUN-8340】回收站查找软删除记录时没有判断是否启用多租户造成可以查找并回收其他租户的数据 #5907---
// 代码逻辑说明: 【QQYUN-8340】回收站查找软删除记录时没有判断是否启用多租户造成可以查找并回收其他租户的数据 #5907---
if(MybatisPlusSaasConfig.OPEN_SYSTEM_TENANT_CONTROL){
if(oConvertUtils.isEmpty(tenantId)){
return new ArrayList<>();
}
return baseMapper.queryDeleteListBtTenantId(oConvertUtils.getInt(tenantId));
}
//update-end---author:wangshuai---date:2024-02-27---for:【QQYUN-8340】回收站查找软删除记录时没有判断是否启用多租户造成可以查找并回收其他租户的数据 #5907---
return baseMapper.queryDeleteList();
}
@ -738,14 +739,13 @@ public class SysDictServiceImpl extends ServiceImpl<SysDictMapper, SysDict> impl
//字典表
ls = this.queryDictItemsByCode(dictCode);
}
//update-begin-author:taoyan date:2022-8-30 for: 字典获取可以获取枚举类的数据
// 代码逻辑说明: 字典获取可以获取枚举类的数据
if (ls == null || ls.size() == 0) {
Map<String, List<DictModel>> map = ResourceUtil.getEnumDictData();
if (map.containsKey(dictCode)) {
return map.get(dictCode);
}
}
//update-end-author:taoyan date:2022-8-30 for: 字典获取可以获取枚举类的数据
return ls;
}
@ -763,7 +763,7 @@ public class SysDictServiceImpl extends ServiceImpl<SysDictMapper, SysDict> impl
SqlInjectionUtil.specialFilterContentForDictSql(dictCode);
if (dictCode.contains(SymbolConstant.COMMA)) {
//update-begin-author:taoyan date:20210329 for: 下拉搜索不支持表名后加查询条件
// 代码逻辑说明: 下拉搜索不支持表名后加查询条件
String[] params = dictCode.split(",");
String condition = null;
if (params.length != 3 && params.length != 4) {
@ -771,11 +771,10 @@ public class SysDictServiceImpl extends ServiceImpl<SysDictMapper, SysDict> impl
return null;
} else if (params.length == 4) {
condition = params[3];
// update-begin-author:taoyan date:20220314 for: online表单下拉搜索框表字典配置#{sys_org_code}报错 #3500
// 代码逻辑说明: online表单下拉搜索框表字典配置#{sys_org_code}报错 #3500
if(condition.indexOf(SymbolConstant.SYS_VAR_PREFIX)>=0){
condition = QueryGenerator.getSqlRuleValue(condition);
}
// update-end-author:taoyan date:20220314 for: online表单下拉搜索框表字典配置#{sys_org_code}报错 #3500
}
// 字典Code格式不正确 [表名为空]
@ -788,7 +787,6 @@ public class SysDictServiceImpl extends ServiceImpl<SysDictMapper, SysDict> impl
} else {
ls = this.queryAllTableDictItems(params[0], params[1], params[2], condition, keyword);
}
//update-end-author:taoyan date:20210329 for: 下拉搜索不支持表名后加查询条件
return ls;
} else {
// 字典Code格式不正确

View File

@ -65,14 +65,13 @@ public class SysGatewayRouteServiceImpl extends ServiceImpl<SysGatewayRouteMappe
try {
json = json.getJSONObject("router");
String id = json.getString("id");
//update-begin-author:taoyan date:20211025 for: oracle路由网关新增小bug /issues/I4EV2J
// 代码逻辑说明: oracle路由网关新增小bug /issues/I4EV2J
SysGatewayRoute route;
if(oConvertUtils.isEmpty(id)){
route = new SysGatewayRoute();
}else{
route = getById(id);
}
//update-end-author:taoyan date:20211025 for: oracle路由网关新增小bug /issues/I4EV2J
if (ObjectUtil.isEmpty(route)) {
route = new SysGatewayRoute();
}

View File

@ -45,7 +45,6 @@ public class SysLogServiceImpl extends ServiceImpl<SysLogMapper, SysLog> impleme
return sysLogMapper.findTotalVisitCount();
}
//update-begin--Author:zhangweijian Date:20190428 for传入开始时间结束时间参数
@Override
public Long findTodayVisitCount(Date dayStart, Date dayEnd) {
return sysLogMapper.findTodayVisitCount(dayStart,dayEnd);
@ -55,7 +54,6 @@ public class SysLogServiceImpl extends ServiceImpl<SysLogMapper, SysLog> impleme
public Long findTodayIp(Date dayStart, Date dayEnd) {
return sysLogMapper.findTodayIp(dayStart,dayEnd);
}
//update-end--Author:zhangweijian Date:20190428 for传入开始时间结束时间参数
@Override
public List<Map<String,Object>> findVisitCount(Date dayStart, Date dayEnd) {

View File

@ -60,11 +60,10 @@ public class SysPermissionDataRuleImpl extends ServiceImpl<SysPermissionDataRule
@Override
public List<SysPermissionDataRule> queryPermissionDataRules(String username,String permissionId) {
List<String> idsList = this.baseMapper.queryDataRuleIds(username, permissionId);
//update-begin--Author:scott Date:20191119 for数据权限失效问题处理--------------------
// 代码逻辑说明: 数据权限失效问题处理--------------------
if(idsList==null || idsList.size()==0) {
return null;
}
//update-end--Author:scott Date:20191119 for数据权限失效问题处理--------------------
Set<String> set = new HashSet<String>();
for (String ids : idsList) {
if(oConvertUtils.isEmpty(ids)) {

View File

@ -242,14 +242,13 @@ public class SysPermissionServiceImpl extends ServiceImpl<SysPermissionMapper, S
permissionList = new ArrayList<>();
}
List<SysPermission> testRoleList = sysPermissionMapper.queryPermissionByTestRoleId();
//update-begin-author:liusq date:20230427 for: [QQYUN-5168]【vue3】为什么出现两个菜单 菜单根据id去重
// 代码逻辑说明: [QQYUN-5168]【vue3】为什么出现两个菜单 菜单根据id去重
for (SysPermission permission: testRoleList) {
boolean hasPerm = permissionList.stream().anyMatch(a->a.getId().equals(permission.getId()));
if(!hasPerm){
permissionList.add(permission);
}
}
//update-end-author:liusq date:20230427 for: [QQYUN-5168]【vue3】为什么出现两个菜单 菜单根据id去重
}
//================= end 开启租户的时候 如果没有test角色默认加入test角色================
return permissionList;

View File

@ -1,5 +1,6 @@
package org.jeecg.modules.system.service.impl;
import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.jeecg.common.constant.CommonConstant;
@ -32,6 +33,7 @@ public class SysRoleIndexServiceImpl extends ServiceImpl<SysRoleIndexMapper, Sys
public SysRoleIndex queryDefaultIndex() {
LambdaQueryWrapper<SysRoleIndex> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(SysRoleIndex::getRoleCode, DefIndexConst.DEF_INDEX_ALL);
queryWrapper.eq(SysRoleIndex::getStatus, CommonConstant.STATUS_1);
SysRoleIndex entity = super.getOne(queryWrapper);
// 保证不为空
if (entity == null) {
@ -150,4 +152,33 @@ public class SysRoleIndexServiceImpl extends ServiceImpl<SysRoleIndexMapper, Sys
redisUtil.set(DefIndexConst.CACHE_TYPE + username,type);
}
/**
* 更新其他全局默认的状态值
*
* @param roleCode
* @param status
* @param id
*/
@Override
public void updateOtherDefaultStatus(String roleCode, String status, String id) {
//roleCode是全局默认
if(oConvertUtils.isNotEmpty(roleCode) && DefIndexConst.DEF_INDEX_ALL.equals(roleCode)){
//状态为开启状态
if(oConvertUtils.isNotEmpty(status) && CommonConstant.STATUS_1.equals(status)){
LambdaQueryWrapper<SysRoleIndex> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(SysRoleIndex::getRoleCode,roleCode);
queryWrapper.eq(SysRoleIndex::getStatus,CommonConstant.STATUS_1);
queryWrapper.ne(SysRoleIndex::getId,id);
queryWrapper.select(SysRoleIndex::getId);
List<SysRoleIndex> list = this.list(queryWrapper);
if(CollectionUtil.isNotEmpty(list)){
list.forEach(sysRoleIndex -> {
sysRoleIndex.setStatus(CommonConstant.STATUS_0);
});
this.updateBatchById(list);
}
}
}
}
}

View File

@ -23,10 +23,7 @@ import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.transaction.annotation.Transactional;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.*;
import java.util.stream.Collectors;
/**
@ -90,7 +87,6 @@ public class SysTenantPackServiceImpl extends ServiceImpl<SysTenantPackMapper, S
if (null != tenantId && tenantId != 0) {
List<String> userIds = sysUserTenantMapper.getUserIdsByTenantId(tenantId);
if (CollectionUtil.isNotEmpty(userIds)) {
//update-begin---author:wangshuai---date:2025-09-03---for: 编辑时需要查看有没有未分配的用户---
// 查询已存在的用户
LambdaQueryWrapper<SysTenantPackUser> query = new LambdaQueryWrapper<>();
query.eq(SysTenantPackUser::getTenantId, tenantId);
@ -106,7 +102,6 @@ public class SysTenantPackServiceImpl extends ServiceImpl<SysTenantPackMapper, S
.filter(userId -> !existingUserIds.contains(userId))
.toList();
for (String userId : newUserIds) {
//update-end---author:wangshuai---date:2025-09-03---for: 编辑时需要查看有没有未分配的用户---
SysTenantPackUser tenantPackUser = new SysTenantPackUser(tenantId, packId, userId);
sysTenantPackUserMapper.insert(tenantPackUser);
}
@ -318,8 +313,11 @@ public class SysTenantPackServiceImpl extends ServiceImpl<SysTenantPackMapper, S
LambdaQueryWrapper<SysTenantPack> query = new LambdaQueryWrapper<>();
query.eq(SysTenantPack::getPackType,"default");
List<SysTenantPack> sysTenantPacks = sysTenantPackMapper.selectList(query);
// 取当前租户用户列表
List<String> userIds = sysUserTenantMapper.getUserIdsByTenantId(tenantId);
for (SysTenantPack sysTenantPack: sysTenantPacks) {
syncDefaultPack2CurrentTenant(tenantId, sysTenantPack);
// 代码逻辑说明: 【QQYUN-14007】演示系统初始化租户套餐很慢---
syncDefaultPack2CurrentTenant(tenantId, sysTenantPack, userIds);
}
}
@ -334,16 +332,24 @@ public class SysTenantPackServiceImpl extends ServiceImpl<SysTenantPackMapper, S
query.eq(SysTenantPack::getPackType,"custom");
query.eq(SysTenantPack::getTenantId, tenantId);
List<SysTenantPack> currentTenantPacks = sysTenantPackMapper.selectList(query);
Map<String, SysTenantPack> currentTenantPackMap = new HashMap<String, SysTenantPack>();
// 代码逻辑说明: 【QQYUN-14007】演示系统初始化租户套餐很慢---
Map<String, SysTenantPack> currentTenantPackMap;
if (oConvertUtils.listIsNotEmpty(currentTenantPacks)) {
currentTenantPackMap = currentTenantPacks.stream().collect(Collectors.toMap(SysTenantPack::getPackName, o -> o, (existing, replacement) -> existing));
} else {
currentTenantPackMap = new HashMap<String, SysTenantPack>();
}
// 添加不存在的套餐包
for (SysTenantPack defaultPacks : sysDefaultTenantPacks) {
if(!currentTenantPackMap.containsKey(defaultPacks.getPackName())){
syncDefaultPack2CurrentTenant(tenantId, defaultPacks);
}
}
// 预取当前租户用户列表,避免在循环中重复查询
List<String> userIds = sysUserTenantMapper.getUserIdsByTenantId(tenantId);
// 计算需要同步的默认套餐包列表
List<SysTenantPack> packsToSync = sysDefaultTenantPacks.stream()
.filter(p -> !currentTenantPackMap.containsKey(p.getPackName()))
.collect(Collectors.toList());
// 并行同步缺失的套餐包
packsToSync.parallelStream().forEach(defaultPacks -> {
syncDefaultPack2CurrentTenant(tenantId, defaultPacks, userIds);
});
}
/**
@ -354,7 +360,7 @@ public class SysTenantPackServiceImpl extends ServiceImpl<SysTenantPackMapper, S
* @author chenrui
* @date 2025/2/5 19:41
*/
private void syncDefaultPack2CurrentTenant(Integer tenantId, SysTenantPack defaultPacks) {
private void syncDefaultPack2CurrentTenant(Integer tenantId, SysTenantPack defaultPacks, List<String> userIds) {
SysTenantPack pack = new SysTenantPack();
BeanUtils.copyProperties(defaultPacks,pack);
pack.setTenantId(tenantId);
@ -362,22 +368,26 @@ public class SysTenantPackServiceImpl extends ServiceImpl<SysTenantPackMapper, S
pack.setId("");
sysTenantPackMapper.insert(pack);
List<String> permissionsByPackId = sysPackPermissionMapper.getPermissionsByPackId(defaultPacks.getId());
List<SysPackPermission> permissionList = new ArrayList<>();
for (String permission:permissionsByPackId) {
SysPackPermission packPermission = new SysPackPermission();
packPermission.setPackId(pack.getId());
packPermission.setPermissionId(permission);
sysPackPermissionMapper.insert(packPermission);
permissionList.add(packPermission);
}
if(CollectionUtil.isNotEmpty(permissionList)){
sysPackPermissionMapper.insert(permissionList);
}
//如果需要自动分配给用户时候再去添加用户与套餐的关系数据
if(oConvertUtils.isNotEmpty(defaultPacks.getIzSysn()) && CommonConstant.STATUS_1.equals(defaultPacks.getIzSysn())) {
//查询当前租户下的用户
List<String> userIds = sysUserTenantMapper.getUserIdsByTenantId(tenantId);
List<SysTenantPackUser> packUserList = new ArrayList<>();
if (oConvertUtils.isNotEmpty(userIds)) {
for (String userId : userIds) {
//根据租户id和套餐id添加用户与套餐关系数据
SysTenantPackUser tenantPackUser = new SysTenantPackUser(tenantId, pack.getId(), userId);
sysTenantPackUserMapper.insert(tenantPackUser);
packUserList.add(tenantPackUser);
}
sysTenantPackUserMapper.insert(packUserList);
}
}
}

View File

@ -109,7 +109,7 @@ public class SysTenantServiceImpl extends ServiceImpl<SysTenantMapper, SysTenant
String[] idArray = ids.split(SymbolConstant.COMMA);
String userId = null;
SysUser userByPhone = null;
//update-begin---author:wangshuai ---date:20230313 for【QQYUN-4605】后台的邀请谁加入租户没办法选不是租户下的用户通过手机号邀请------------
// 代码逻辑说明: 【QQYUN-4605】后台的邀请谁加入租户没办法选不是租户下的用户通过手机号邀请------------
if(oConvertUtils.isNotEmpty(phone)){
userByPhone = userService.getUserByPhone(phone);
//说明用户不存在
@ -128,7 +128,6 @@ public class SysTenantServiceImpl extends ServiceImpl<SysTenantMapper, SysTenant
//循环租户id
for (String id:idArray) {
//update-begin---author:wangshuai ---date:20221223 for[QQYUN-3371]租户逻辑改造,改成关系表------------
//获取被邀请人是否已存在
SysUserTenant userTenant = userTenantMapper.getUserTenantByTenantId(userId, Integer.valueOf(id));
if(null == userTenant){
@ -139,21 +138,14 @@ public class SysTenantServiceImpl extends ServiceImpl<SysTenantMapper, SysTenant
userTenantMapper.insert(relation);
//给当前用户添加租户下的所有套餐
this.addPackUser(userId,id);
//update-begin---author:wangshuai---date:2025-09-06---for:【QQYUN-13720】邀请用户加入租户没有系统提醒移除有---
//邀请用户加入租户,发送消息
this.sendInvitationTenantMessage(userByPhone,id);
//update-end---author:wangshuai---date:2025-09-06---for:【QQYUN-13720】邀请用户加入租户没有系统提醒移除有---
}else{
//update-begin---author:wangshuai ---date:20230711 for【QQYUN-5723】2、用户已经在租户里了再次要求提示成功应该提示用户已经存在------------
//update-begin---author:wangshuai ---date:20230724 for【QQYUN-5885】邀请用户加入提示不准确------------
// 代码逻辑说明: 【QQYUN-5885】邀请用户加入提示不准确------------
String tenantErrorInfo = getTenantErrorInfo(userTenant.getStatus());
String errMsg = "手机号用户:" + userByPhone.getPhone() + " 昵称:" + userByPhone.getRealname() + "" + tenantErrorInfo;
//update-end---author:wangshuai ---date:20230724 for【QQYUN-5885】邀请用户加入提示不准确------------
throw new JeecgBootException(errMsg);
//update-end---author:wangshuai ---date:20230711 for【QQYUN-5723】2、用户已经在租户里了再次要求提示成功应该提示用户已经存在------------
}
//update-end---author:wangshuai ---date:20221223 for[QQYUN-3371]租户逻辑改造,改成关系表------------
//update-end---author:wangshuai ---date:20230313 for【QQYUN-4605】后台的邀请谁加入租户没办法选不是租户下的用户通过手机号邀请------------
}
}
@ -186,19 +178,17 @@ public class SysTenantServiceImpl extends ServiceImpl<SysTenantMapper, SysTenant
public void leaveTenant(String userIds, String tenantId) {
String[] userIdArray = userIds.split(SymbolConstant.COMMA);
for (String userId:userIdArray) {
//update-begin---author:wangshuai ---date:20221223 for[QQYUN-3371]租户逻辑改造,改成关系表------------
// 代码逻辑说明: [QQYUN-3371]租户逻辑改造,改成关系表------------
LambdaQueryWrapper<SysUserTenant> query = new LambdaQueryWrapper<>();
query.eq(SysUserTenant::getTenantId,tenantId);
query.eq(SysUserTenant::getUserId,userId);
userTenantMapper.delete(query);
//update-end---author:wangshuai ---date:20221223 for[QQYUN-3371]租户逻辑改造,改成关系表------------
//update-begin---author:wangshuai---date:2025-09-06---for:【QQYUN-13720】移出用户当前租户没有系统提醒---
//代码逻辑说明: 【QQYUN-13720】移出用户当前租户没有系统提醒---
// 给移除人员发送消息
SysTenantPackUser sysTenantPackUser = new SysTenantPackUser();
sysTenantPackUser.setTenantId(Integer.valueOf(tenantId));
sysTenantPackUser.setUserId(userId);
sendMsgForDelete(sysTenantPackUser);
//update-end---author:wangshuai---date:2025-09-06---for:【QQYUN-13720】移出用户当前租户没有系统提醒---
}
//租户移除用户,直接删除用户租户产品包
sysTenantPackUserMapper.deletePackUserByTenantId(Integer.valueOf(tenantId),Arrays.asList(userIds.split(SymbolConstant.COMMA)));
@ -225,11 +215,10 @@ public class SysTenantServiceImpl extends ServiceImpl<SysTenantMapper, SysTenant
sysTenant.setHouseNumber(RandomUtil.randomStringUpper(6));
sysTenant.setDelFlag(CommonConstant.DEL_FLAG_0);
this.save(sysTenant);
//update-begin---author:wangshuai ---date:20230710 for【QQYUN-5723】1、把当前创建人加入到租户关系里面------------
//代码逻辑说明:【QQYUN-5723】1、把当前创建人加入到租户关系里面------------
//当前登录人的id
LoginUser loginUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
this.saveTenantRelation(sysTenant.getId(),loginUser.getId());
//update-end---author:wangshuai ---date:20230710 for【QQYUN-5723】1、把当前创建人加入到租户关系里面------------
}
@Override
@ -291,15 +280,11 @@ public class SysTenantServiceImpl extends ServiceImpl<SysTenantMapper, SysTenant
}
//删除租户
tenantMapper.deleteByTenantId(list);
//update-begin---author:wangshuai ---date:20230710 for【QQYUN-5723】3、租户彻底删除用户租户关系表也需要删除------------
//删除租户下的用户
userTenantMapper.deleteUserByTenantId(list);
//update-ennd---author:wangshuai ---date:20230710 for【QQYUN-5723】3、租户彻底删除用户租户关系表也需要删除------------
//update-begin---author:wangshuai ---date:20230710 for【QQYUN-5723】3、租户彻底删除用户租户关系表也需要删除------------
//删除租户下的产品包
this.deleteTenantPackByTenantId(list);
//update-ennd---author:wangshuai ---date:20230710 for【QQYUN-5723】3、租户彻底删除用户租户关系表也需要删除------------
}
@Override
@ -336,9 +321,8 @@ public class SysTenantServiceImpl extends ServiceImpl<SysTenantMapper, SysTenant
public int tenantIdGenerate(){
synchronized (this){
//获取最大值id
//update-begin---author:wangshuai ---date:20230424 for数据库没有租户的时候如果为空的话会报错sql返回类型不匹配------------
// 代码逻辑说明: 数据库没有租户的时候如果为空的话会报错sql返回类型不匹配------------
int maxTenantId = oConvertUtils.getInt(tenantMapper.getMaxTenantId(),0);
//update-end---author:wangshuai ---date:20230424 for数据库没有租户的时候如果为空的话会报错sql返回类型不匹配------------
if(maxTenantId >= 1000){
return maxTenantId + 1;
}else{
@ -362,10 +346,8 @@ public class SysTenantServiceImpl extends ServiceImpl<SysTenantMapper, SysTenant
//需要指配拥有者
throw new JeecgBootException("assignedOwen");
} else if (null != userIdsByTenantId && userIdsByTenantId.size() == 1) {
//update-begin---author:wangshuai ---date:20230426 for【QQYUN-5270】名下租户全部退出后再次登录提示租户全部冻结------------
//只有拥有者的时候需要去注销租户
throw new JeecgBootException("cancelTenant");
//update-end---author:wangshuai ---date:20230426 for【QQYUN-5270】名下租户全部退出后再次登录提示租户全部冻结------------
} else {
throw new JeecgBootException("退出租户失败,租户信息已不存在");
}
@ -379,14 +361,13 @@ public class SysTenantServiceImpl extends ServiceImpl<SysTenantMapper, SysTenant
@Override
public void changeOwenUserTenant(String userId, String tId) {
//查询当前用户是否存在该租户下
//update-begin---author:wangshuai ---date:20230705 for租户id应该是传过来的不应该是当前租户的------------
// 代码逻辑说明: 租户id应该是传过来的不应该是当前租户的------------
int tenantId = oConvertUtils.getInt(tId, 0);
SysTenant sysTenant = tenantMapper.selectById(tenantId);
if(null == sysTenant){
throw new JeecgBootException("退出租户失败,不存在此租户");
}
String createBy = sysTenant.getCreateBy();
//update-end---author:wangshuai ---date:20230705 for租户id应该是传过来的不应该是当前租户的------------
Integer count = userTenantMapper.userTenantIzExist(userId, tenantId);
if (count == 0) {
throw new JeecgBootException("退出租户失败,此租户下没有该用户");
@ -408,7 +389,6 @@ public class SysTenantServiceImpl extends ServiceImpl<SysTenantMapper, SysTenant
SysUserTenant userTenant = new SysUserTenant();
userTenant.setStatus(CommonConstant.USER_TENANT_QUIT);
userTenantMapper.update(userTenant,query);
//update-end---author:wangshuai ---date:20230705 for旧拥有者退出后需要将就拥有者的用户租户关系改成已离职------------
//离职流程
this.leveUserProcess(userId, String.valueOf(tenantId));
}
@ -471,13 +451,11 @@ public class SysTenantServiceImpl extends ServiceImpl<SysTenantMapper, SysTenant
result.setSuccess(true);
result.setMessage("邀请成员成功,成员同意后方可加入");
//update-begin---author:wangshuai ---date:20230329 for[QQYUN-4671]部门与用户,手机号邀请,没有在当前部门下,目前是在全组织中------------
//6.保存用户部门关系
if(oConvertUtils.isNotEmpty(departId)){
//保存用户部门关系
this.saveUserDepart(userByPhone.getId(),departId);
}
//update-end---author:wangshuai ---date:20230329 for[QQYUN-4671]部门与用户,手机号邀请,没有在当前部门下,目前是在全组织中------------
// QQYUN-4527【应用】邀请成员加入组织发送消息提醒
sendMsgForInvitation(userByPhone, tenantId, sysUser.getRealname());
@ -743,21 +721,18 @@ public class SysTenantServiceImpl extends ServiceImpl<SysTenantMapper, SysTenant
messageDTO.setToAll(false);
messageDTO.setToUser(user.getUsername());
messageDTO.setFromUser("system");
//update-begin---author:wangshuai ---date:20230706 for【QQYUN-5730】租户邀请加入提示消息应该显示邀请人的名字------------
// 代码逻辑说明: 【QQYUN-5730】租户邀请加入提示消息应该显示邀请人的名字------------
String title = realname + " 邀请您加入 "+sysTenant.getName()+"";
//update-end---author:wangshuai ---date:20230706 for【QQYUN-5730】租户邀请加入提示消息应该显示邀请人的名字------------
messageDTO.setTitle(title);
Map<String, Object> data = new HashMap<>();
messageDTO.setData(data);
messageDTO.setContent(title);
messageDTO.setType("system");
//update-begin---author:wangshuai---date:2023-11-24---for:【QQYUN-7168】邀请成员时会报错但实际已经邀请成功了---
// 代码逻辑说明: 【QQYUN-7168】邀请成员时会报错但实际已经邀请成功了---
messageDTO.setCategory(CommonConstant.MSG_CATEGORY_1);
//update-end---author:wangshuai---date:2023-11-24---for:【QQYUN-7168】邀请成员时会报错但实际已经邀请成功了---
//update-begin---author:wangshuai ---date:20230721 for【QQYUN-5726】邀请加入租户加个按钮直接跳转过去------------
// 代码逻辑说明: 【QQYUN-5726】邀请加入租户加个按钮直接跳转过去------------
messageDTO.setBusType(SysAnnmentTypeEnum.TENANT_INVITE.getType());
sysBaseApi.sendBusAnnouncement(messageDTO);
//update-end---author:wangshuai ---date:20230721 for【QQYUN-5726】邀请加入租户加个按钮直接跳转过去------------
}
@ -774,13 +749,11 @@ public class SysTenantServiceImpl extends ServiceImpl<SysTenantMapper, SysTenant
packUser.setRealname(sysTenantPackUser.getRealname());
currentService.addTenantPackUser(packUser);
//update-begin---author:wangshuai ---date:20230328 for[QQYUN-4674]租户管理员同意或拒绝成员没有系统通知------------
//超级管理员成功加入发送系统消息
SysTenant sysTenant = tenantMapper.selectById(sysTenantPackUser.getTenantId());
String content = " 您已成功加入"+sysTenant.getName()+"的超级管理员的成员。";
SysUser sysUser = userService.getById(sysTenantPackUser.getUserId());
this.sendMsgForAgreeAndRefuseJoin(sysUser,content);
//update-end---author:wangshuai ---date:20230328 for[QQYUN-4674]租户管理员同意或拒绝成员没有系统通知------------
}
}
@ -793,13 +766,11 @@ public class SysTenantServiceImpl extends ServiceImpl<SysTenantMapper, SysTenant
SysTenantPackUser packUser = sysTenantPackUserMapper.selectOne(query);
if(packUser!=null && packUser.getId()!=null && packUser.getStatus()==0){
sysTenantPackUserMapper.deleteById(packUser.getId());
//update-begin---author:wangshuai ---date:20230328 for[QQYUN-4674]租户管理员同意或拒绝成员没有系统通知------------
//超级管理员拒绝加入发送系统消息
SysTenant sysTenant = tenantMapper.selectById(sysTenantPackUser.getTenantId());
String content = " 管理员已拒绝您加入"+sysTenant.getName()+"的超级管理员的成员请求。";
SysUser sysUser = userService.getById(sysTenantPackUser.getUserId());
this.sendMsgForAgreeAndRefuseJoin(sysUser,content);
//update-end---author:wangshuai ---date:20230328 for[QQYUN-4674]租户管理员同意或拒绝成员没有系统通知------------
}
}
@ -946,9 +917,8 @@ public class SysTenantServiceImpl extends ServiceImpl<SysTenantMapper, SysTenant
throw new JeecgBootException("您不是该用户的创建人,无法删除!");
}
//update-begin---author:wangshuai---date:2025-04-11---for:【QQYUN-11839】删除用户需要输入被删除用户的密码这逻辑对吗不应该是管理员的密码吗---
// 代码逻辑说明: 【QQYUN-11839】删除用户需要输入被删除用户的密码这逻辑对吗不应该是管理员的密码吗---
this.verifyCreateTimeAndPassword(sysUserData,password);
//update-end---author:wangshuai---date:2025-04-11---for:【QQYUN-11839】删除用户需要输入被删除用户的密码这逻辑对吗不应该是管理员的密码吗---
//step5 逻辑删除用户
userService.deleteUser(userId);

View File

@ -166,7 +166,6 @@ public class SysThirdAccountServiceImpl extends ServiceImpl<SysThirdAccountMappe
user.setRealname(tlm.getUsername());
user.setThirdUserUuid(tlm.getUuid());
user.setTenantId(tenantId);
//update-begin---author:wangshuai ---date:20230306 for判断如果是钉钉的情况下需要将第三方的用户id查询出来发送模板的时候有用------------
//=============begin 判断如果是钉钉的情况下需要将第三方的用户id查询出来发送模板的时候有用==========
if(CommonConstant.DINGTALK.toLowerCase().equals(tlm.getSource())){
AccessToken accessToken = JdtBaseAPI.getAccessToken(dingTalkClientId, dingTalkClientSecret);
@ -180,7 +179,6 @@ public class SysThirdAccountServiceImpl extends ServiceImpl<SysThirdAccountMappe
}else{
user.setThirdUserId(tlm.getUuid());
}
//update-end---author:wangshuai ---date:20230306 for判断如果是钉钉的情况下需要将第三方的用户id查询出来发送模板的时候有用------------
super.save(user);
return user;
}
@ -216,13 +214,12 @@ public class SysThirdAccountServiceImpl extends ServiceImpl<SysThirdAccountMappe
public SysThirdAccount getOneByUuidAndThirdType(String unionid, String thirdType,Integer tenantId,String thirdUserId) {
LambdaQueryWrapper<SysThirdAccount> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(SysThirdAccount::getThirdType, thirdType);
//update-begin---author:wangshuai---date:2023-12-04---for: 如果第三方用户id为空那么就不走第三方用户查询逻辑因为扫码登录third_user_id是唯一的没有重复的情况---
// 代码逻辑说明: 如果第三方用户id为空那么就不走第三方用户查询逻辑因为扫码登录third_user_id是唯一的没有重复的情况---
if(oConvertUtils.isNotEmpty(thirdUserId)){
queryWrapper.and((wrapper) ->wrapper.eq(SysThirdAccount::getThirdUserUuid,unionid).or().eq(SysThirdAccount::getThirdUserId,thirdUserId));
}else{
queryWrapper.eq(SysThirdAccount::getThirdUserUuid, unionid);
}
//update-end---author:wangshuai---date:2023-12-04---for:如果第三方用户id为空那么就不走第三方用户查询逻辑因为扫码登录third_user_id是唯一的没有重复的情况---
queryWrapper.eq(SysThirdAccount::getTenantId, tenantId);
return super.getOne(queryWrapper);
}

View File

@ -69,12 +69,11 @@ public class SysUserDepartServiceImpl extends ServiceImpl<SysUserDepartMapper, S
depIdList.add(userDepart.getDepId());
}
//update-begin---author:wangshuai ---date:20230112 for判断是否开启租户saas模式开启需要根据当前租户查询------------
// 代码逻辑说明: 判断是否开启租户saas模式开启需要根据当前租户查询------------
if (MybatisPlusSaasConfig.OPEN_SYSTEM_TENANT_CONTROL) {
Integer tenantId = oConvertUtils.getInt(TenantContext.getTenant(), 0);
queryDep.eq(SysDepart::getTenantId,tenantId);
}
//update-end---author:wangshuai ---date:20230112 for判断是否开启租户saas模式开启需要根据当前租户查询------------
queryDep.in(SysDepart::getId, depIdList);
List<SysDepart> depList = sysDepartService.list(queryDep);
@ -109,12 +108,18 @@ public class SysUserDepartServiceImpl extends ServiceImpl<SysUserDepartMapper, S
userIdList.add(uDep.getUserId());
}
List<SysUser> userList = (List<SysUser>) sysUserMapper.selectBatchIds(userIdList);
//update-begin-author:taoyan date:201905047 for:接口调用查询返回结果不能返回密码相关信息
for (SysUser sysUser : userList) {
sysUser.setSalt("");
sysUser.setPassword("");
if(CollectionUtil.isNotEmpty(userList)){
// 代码逻辑说明: JHHB-812 人员按照排序展示
userList.sort(Comparator.comparing(SysUser::getSort,
Comparator.nullsFirst(Comparator.naturalOrder())));
// 代码逻辑说明: 接口调用查询返回结果不能返回密码相关信息
for (SysUser sysUser : userList) {
sysUser.setSalt("");
sysUser.setPassword("");
}
}
//update-end-author:taoyan date:201905047 for:接口调用查询返回结果不能返回密码相关信息
return userList;
}
return new ArrayList<SysUser>();
@ -125,7 +130,7 @@ public class SysUserDepartServiceImpl extends ServiceImpl<SysUserDepartMapper, S
*/
@Override
public List<SysUser> queryUserByDepCode(String depCode,String realname) {
//update-begin-author:taoyan date:20210422 for: 根据部门选择用户接口代码优化
// 代码逻辑说明: 根据部门选择用户接口代码优化
if(oConvertUtils.isNotEmpty(realname)){
realname = realname.trim();
}
@ -138,7 +143,6 @@ public class SysUserDepartServiceImpl extends ServiceImpl<SysUserDepartMapper, S
map.put(sysUser.getId(), sysUser);
}
return new ArrayList<SysUser>(map.values());
//update-end-author:taoyan date:20210422 for: 根据部门选择用户接口代码优化
}
@ -160,10 +164,9 @@ public class SysUserDepartServiceImpl extends ServiceImpl<SysUserDepartMapper, S
Page<SysUser> page = new Page<SysUser>(pageNo, pageSize);
if(oConvertUtils.isEmpty(departId)){
LambdaQueryWrapper<SysUser> query = new LambdaQueryWrapper<>();
//update-begin---author:wangshuai ---date:20220104 for[JTC-297]已冻结用户仍可设置为代理人------------
// 代码逻辑说明: [JTC-297]已冻结用户仍可设置为代理人------------
query.eq(SysUser::getStatus,Integer.parseInt(CommonConstant.STATUS_1));
//update-end---author:wangshuai ---date:20220104 for[JTC-297]已冻结用户仍可设置为代理人------------
//update-begin---author:liusq ---date:20231215 for逗号分割多个用户翻译问题------------
// 代码逻辑说明: 逗号分割多个用户翻译问题------------
if(oConvertUtils.isNotEmpty(username)){
String COMMA = ",";
if(oConvertUtils.isNotEmpty(isMultiTranslate) && username.contains(COMMA)){
@ -173,9 +176,8 @@ public class SysUserDepartServiceImpl extends ServiceImpl<SysUserDepartMapper, S
query.like(SysUser::getUsername, username);
}
}
//update-end---author:liusq ---date:20231215 for逗号分割多个用户翻译问题------------
//update-begin---author:liusq ---date:20250908 forJHHB-304 流程转办 人员选择时,加姓名搜索------------
// 代码逻辑说明: JHHB-304 流程转办 人员选择时,加姓名搜索------------
if(oConvertUtils.isNotEmpty(realname)){
String COMMA = ",";
if(oConvertUtils.isNotEmpty(isMultiTranslate) && realname.contains(COMMA)){
@ -185,11 +187,10 @@ public class SysUserDepartServiceImpl extends ServiceImpl<SysUserDepartMapper, S
query.like(SysUser::getRealname, realname);
}
}
//update-end---author:liusq ---date:20250908 forJHHB-304 流程转办 人员选择时,加姓名搜索------------
//update-begin---author:wangshuai ---date:20220608 for[VUEN-1238]邮箱回复时发送到显示的为用户id------------
// 代码逻辑说明: [VUEN-1238]邮箱回复时发送到显示的为用户id------------
if(oConvertUtils.isNotEmpty(id)){
//update-begin---author:wangshuai ---date:2024-06-25 for【TV360X-1482】写信选择用户后第一次回显没翻译------------
// 代码逻辑说明: 【TV360X-1482】写信选择用户后第一次回显没翻译------------
String COMMA = ",";
if(oConvertUtils.isNotEmpty(isMultiTranslate) && id.contains(COMMA)){
String[] idArr = id.split(COMMA);
@ -197,23 +198,21 @@ public class SysUserDepartServiceImpl extends ServiceImpl<SysUserDepartMapper, S
}else {
query.eq(SysUser::getId, id);
}
//update-end---author:wangshuai ---date:2024-06-25 for【TV360X-1482】写信选择用户后第一次回显没翻译------------
}
//update-end---author:wangshuai ---date:20220608 for[VUEN-1238]邮箱回复时发送到显示的为用户id------------
//update-begin---author:wangshuai ---date:20220902 for[VUEN-2121]临时用户不能直接显示------------
// 代码逻辑说明: [VUEN-2121]临时用户不能直接显示------------
query.ne(SysUser::getUsername,"_reserve_user_external");
//update-end---author:wangshuai ---date:20220902 for[VUEN-2121]临时用户不能直接显示------------
//------------------------------------------------------------------------------------------------
// 代码逻辑说明: 【JHHB-765】需要能设置排序---
query.orderByAsc(SysUser::getSort);
query.orderByDesc(SysUser::getCreateTime);
//------------------------------------------------------------------------------------------------
//是否开启系统管理模块的多租户数据隔离【SAAS多租户模式】
if (MybatisPlusSaasConfig.OPEN_SYSTEM_TENANT_CONTROL) {
String tenantId = oConvertUtils.getString(TenantContext.getTenant(), "0");
//update-begin---author:wangshuai ---date:20221223 for[QQYUN-3371]租户逻辑改造,改成关系表------------
// 代码逻辑说明: [QQYUN-3371]租户逻辑改造,改成关系表------------
List<String> userIdList = userTenantMapper.getUserIdsByTenantId(Integer.valueOf(tenantId));
if(null!=userIdList && userIdList.size()>0){
query.in(SysUser::getId,userIdList);
}
//update-end---author:wangshuai ---date:20221223 for[QQYUN-3371]租户逻辑改造,改成关系表------------
}
//------------------------------------------------------------------------------------------------
pageList = sysUserMapper.selectPage(page, query);
@ -225,7 +224,7 @@ public class SysUserDepartServiceImpl extends ServiceImpl<SysUserDepartMapper, S
List<SysUser> userList = pageList.getRecords();
if(userList!=null && userList.size()>0){
List<String> userIds = userList.stream().map(SysUser::getId).collect(Collectors.toList());
Map<String, SysUser> map = new HashMap(5);
Map<String, SysUser> map = new LinkedHashMap(5);
if(userIds!=null && userIds.size()>0){
// 查部门名称
Map<String,String> useDepNames = this.getDepNamesByUserIds(userIds);
@ -274,46 +273,47 @@ public class SysUserDepartServiceImpl extends ServiceImpl<SysUserDepartMapper, S
}else{
// 有部门ID 需要走自定义sql
SysDepart sysDepart = sysDepartService.getById(departId);
//update-begin---author:wangshuai ---date:20220908 for部门排除自己------------
// 代码逻辑说明: 部门排除自己------------
pageList = this.baseMapper.getUserInformation(page, sysDepart.getOrgCode(), keyword,sysUser.getId());
//update-end---author:wangshuai ---date:20220908 for部门排除自己--------------
}
return pageList;
}
@Override
public IPage<SysUser> getUserInformation(Integer tenantId, String departId,String roleId, String keyword, Integer pageSize, Integer pageNo, String excludeUserIdList) {
public IPage<SysUser> getUserInformation(Integer tenantId, String departId,String roleId, String keyword, Integer pageSize, Integer pageNo, String excludeUserIdList, String includeUsernameList) {
IPage<SysUser> pageList = null;
// 部门ID不存在 直接查询用户表即可
Page<SysUser> page = new Page<>(pageNo, pageSize);
LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
List<String> userIdList = new ArrayList<>();
List<String> inUsernameList = new ArrayList<>();
if(oConvertUtils.isNotEmpty(excludeUserIdList)){
userIdList = Arrays.asList(excludeUserIdList.split(SymbolConstant.COMMA));
}
if(oConvertUtils.isNotEmpty(includeUsernameList)){
inUsernameList = Arrays.asList(includeUsernameList.split(SymbolConstant.COMMA));
}
if(oConvertUtils.isNotEmpty(departId)){
// 有部门ID 需要走自定义sql
SysDepart sysDepart = sysDepartService.getById(departId);
//update-begin-author:taoyan date:2023-1-3 for: 用户选择组件 加载用户需要根据租户ID过滤
//update-begin---author:wangshuai---date:2024-02-02---for:【QQYUN-8239】用户角色添加用户 返回2页数据实际只显示一页---
//update-begin---author:wangshuai---date:2024-02-02---for:【QQYUN-8239】用户角色添加用户 返回2页数据实际只显示一页---
// 代码逻辑说明: 【QQYUN-8239】用户角色添加用户 返回2页数据实际只显示一页---
pageList = this.baseMapper.getProcessUserList(page, sysDepart.getOrgCode(), keyword, tenantId, userIdList);
//update-end---author:wangshuai---date:2024-02-02---for:【QQYUN-8239】用户角色添加用户 返回2页数据实际只显示一页---
} else if (oConvertUtils.isNotEmpty(roleId)) {
//update-begin---author:wangshuai---date:2024-02-02---for:【QQYUN-8239】用户角色添加用户 返回2页数据实际只显示一页---
// 代码逻辑说明: 【QQYUN-8239】用户角色添加用户 返回2页数据实际只显示一页---
pageList = this.sysUserMapper.selectUserListByRoleId(page, roleId, keyword, tenantId,userIdList);
//update-end---author:wangshuai---date:2024-02-02---for:【QQYUN-8239】用户角色添加用户 返回2页数据实际只显示一页---
//update-end-author:taoyan date:2023-1-3 for: 用户选择组件 加载用户需要根据租户ID过滤
} else{
LambdaQueryWrapper<SysUser> query = new LambdaQueryWrapper<>();
query.eq(SysUser::getStatus,Integer.parseInt(CommonConstant.STATUS_1));
query.ne(SysUser::getUsername,"_reserve_user_external");
//update-begin---author:wangshuai---date:2024-02-02---for:【QQYUN-8239】用户角色添加用户 返回2页数据实际只显示一页---
if(inUsernameList!=null && inUsernameList.size()>0){
query.in(SysUser::getUsername, inUsernameList);
}
// 代码逻辑说明: 【QQYUN-8239】用户角色添加用户 返回2页数据实际只显示一页---
if(oConvertUtils.isNotEmpty(excludeUserIdList)){
query.notIn(SysUser::getId,Arrays.asList(excludeUserIdList.split(SymbolConstant.COMMA)));
}
//update-end---author:wangshuai---date:2024-02-02---for:【QQYUN-8239】用户角色添加用户 返回2页数据实际只显示一页---
// 支持租户隔离
if (tenantId != null) {
List<String> userIds = userTenantMapper.getUserIdsByTenantId(tenantId);
@ -328,6 +328,10 @@ public class SysUserDepartServiceImpl extends ServiceImpl<SysUserDepartMapper, S
//这个语法可以将or用括号包起来避免数据查不到
query.and((wrapper) -> wrapper.like(SysUser::getUsername, keyword).or().like(SysUser::getRealname,keyword));
}
// 【JHHB-811】添加排序
query.orderByAsc(SysUser::getSort).orderByDesc(SysUser::getCreateTime);
pageList = sysUserMapper.selectPage(page, query);
}
// 批量查询用户的所属部门

View File

@ -32,12 +32,14 @@ import org.jeecg.common.exception.JeecgBootException;
import org.jeecg.common.system.vo.LoginUser;
import org.jeecg.common.system.vo.SysUserCacheInfo;
import org.jeecg.common.util.*;
import org.jeecg.common.util.encryption.AesEncryptUtil;
import org.jeecg.config.JeecgBaseConfig;
import org.jeecg.config.mybatis.MybatisPlusSaasConfig;
import org.jeecg.modules.base.service.BaseCommonService;
import org.jeecg.modules.jmreport.common.util.OkConvertUtils;
import org.jeecg.modules.message.handle.impl.SystemSendMsgHandle;
import org.jeecg.modules.system.entity.*;
import org.jeecg.modules.system.mapper.*;
import org.jeecg.modules.system.model.SysLoginModel;
import org.jeecg.modules.system.model.SysUserSysDepPostModel;
import org.jeecg.modules.system.model.SysUserSysDepartModel;
import org.jeecg.modules.system.service.*;
@ -59,6 +61,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.context.annotation.Lazy;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
@ -132,25 +135,37 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
@Autowired
private SysUserDepPostMapper depPostMapper;
@Autowired
private JeecgBaseConfig jeecgBaseConfig;
/**
* 管理员账号
*/
public static final String[] ADMIN_ACCOUNT = new String[]{"admin"};
@Override
public Result<IPage<SysUser>> queryPageList(HttpServletRequest req, QueryWrapper<SysUser> queryWrapper, Integer pageSize, Integer pageNo) {
Result<IPage<SysUser>> result = new Result<IPage<SysUser>>();
//update-begin-Author:wangshuai--Date:20211119--for:【vue3】通过部门id查询用户通过code查询id
//部门ID
String departId = req.getParameter("departId");
if (oConvertUtils.isNotEmpty(departId)) {
LambdaQueryWrapper<SysUserDepart> query = new LambdaQueryWrapper<>();
query.eq(SysUserDepart::getDepId, departId);
List<SysUserDepart> list = sysUserDepartMapper.selectList(query);
//代码逻辑说明:【JHHB-762】用户管理需要支持按组织架构查询用户支持多选---
//兼容多个部门id
LambdaQueryWrapper<SysUserDepart> query = new LambdaQueryWrapper<>();
if(departId.contains(SymbolConstant.COMMA)) {
query.in(SysUserDepart::getDepId, Arrays.asList(departId.split(SymbolConstant.COMMA)));
} else {
query.eq(SysUserDepart::getDepId, departId);
}
List<SysUserDepart> list = sysUserDepartMapper.selectList(query);
List<String> userIds = list.stream().map(SysUserDepart::getUserId).collect(Collectors.toList());
//update-begin---author:wangshuai ---date:20220322 for[issues/I4XTYB]查询用户时当部门id 下没有分配用户时接口报错------------
// 代码逻辑说明: [issues/I4XTYB]查询用户时当部门id 下没有分配用户时接口报错------------
if (oConvertUtils.listIsNotEmpty(userIds)) {
queryWrapper.in("id", userIds);
} else {
return Result.OK();
}
//update-end---author:wangshuai ---date:20220322 for[issues/I4XTYB]查询用户时当部门id 下没有分配用户时接口报错------------
}
//用户ID
String code = req.getParameter("code");
@ -158,16 +173,14 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
queryWrapper.in("id", Arrays.asList(code.split(",")));
pageSize = code.split(",").length;
}
//update-end-Author:wangshuai--Date:20211119--for:【vue3】通过部门id查询用户通过code查询id
//update-begin-author:taoyan--date:20220104--for: JTC-372 【用户冻结问题】 online授权、用户组件选择用户都能看到被冻结的用户
// 代码逻辑说明: JTC-372 【用户冻结问题】 online授权、用户组件选择用户都能看到被冻结的用户
String status = req.getParameter("status");
if (oConvertUtils.isNotEmpty(status)) {
queryWrapper.eq("status", Integer.parseInt(status));
}
//update-end-author:taoyan--date:20220104--for: JTC-372 【用户冻结问题】 online授权、用户组件选择用户都能看到被冻结的用户
//update-begin---author:wangshuai---date:2024-03-08---for:【QQYUN-8110】在线通讯录支持设置权限(只能看分配的技术支持)---
// 代码逻辑说明: 【QQYUN-8110】在线通讯录支持设置权限(只能看分配的技术支持)---
String tenantId = TokenUtils.getTenantIdByRequest(req);
String lowAppId = TokenUtils.getLowAppIdByRequest(req);
// Object bean = ResourceUtil.getImplementationClass(DataEnhanceEnum.getClassPath(tenantId,lowAppId));
@ -179,10 +192,12 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
// queryWrapper.in("id", userIds);
// }
// }
//update-end---author:wangshuai---date:2024-03-08---for:【QQYUN-8110】在线通讯录支持设置权限(只能看分配的技术支持)---
//TODO 外部模拟登陆临时账号,列表不显示
queryWrapper.ne("username", "_reserve_user_external");
// 代码逻辑说明: 【JHHB-765】需要能设置排序---
queryWrapper.orderByAsc("sort");
queryWrapper.orderByDesc("create_time");
Page<SysUser> page = new Page<SysUser>(pageNo, pageSize);
IPage<SysUser> pageList = this.page(page, queryWrapper);
@ -194,6 +209,11 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
Map<String, String> useDepNames = this.getDepNamesByUserIds(userIds);
pageList.getRecords().forEach(item -> {
item.setOrgCodeTxt(useDepNames.get(item.getId()));
//增加所属部门id,前台需要展示
List<String> departs = sysDepartMapper.queryDepartsByUserId(item.getId());
if(oConvertUtils.isNotEmpty(departs)){
item.setBelongDepIds(String.join(SymbolConstant.COMMA, departs));
}
//查询用户的租户ids
List<Integer> list = userTenantMapper.getTenantIdsByUserId(item.getId());
if (oConvertUtils.isNotEmpty(list)) {
@ -206,13 +226,10 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
posTenantId = oConvertUtils.getInt(TenantContext.getTenant(), 0);;
}
//查询用户职位关系表(获取租户下面的)
//update-begin---author:wangshuai---date:2023-11-15---for:【QQYUN-7028】用户职务保存后未回显---
// 代码逻辑说明: 【QQYUN-7028】用户职务保存后未回显---
List<String> positionList = sysUserPositionMapper.getPositionIdByUserTenantId(item.getId(),posTenantId);
//update-end---author:wangshuai---date:2023-11-15---for:【QQYUN-7028】用户职务保存后未回显---
//update-end---author:wangshuai ---date:20230228 for[QQYUN-4354]加入更多字段:当前加入时间应该取当前租户的/职位也是当前租户下的------------
item.setPost(CommonUtils.getSplitText(positionList,SymbolConstant.COMMA));
//update-begin---author:wangshuai---date:2023-10-08---for:【QQYUN-6668】钉钉部门和用户同步我怎么知道哪些用户是双向绑定成功的---
//是否根据租户隔离(敲敲云用户列表专用,用于展示是否同步钉钉)
if (MybatisPlusSaasConfig.OPEN_SYSTEM_TENANT_CONTROL) {
//查询账号表是否已同步钉钉
@ -227,14 +244,11 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
item.setIzBindThird(true);
}
}
//update-end---author:wangshuai---date:2023-10-08---for:【QQYUN-6668】钉钉部门和用户同步我怎么知道哪些用户是双向绑定成功的---
//update-begin---author:wangshuai---date:2025-09-06---for: 兼职岗位改造成中间表的方式---
//查询部门的兼职岗位
List<String> depPostList = depPostMapper.getDepPostByUserId(item.getId());
if(CollectionUtil.isNotEmpty(depPostList)){
item.setOtherDepPostId(StringUtils.join(depPostList.toArray(), SymbolConstant.COMMA));
}
//update-end---author:wangshuai---date:2025-09-06---for:兼职岗位改造成中间表的方式---
});
}
@ -272,6 +286,7 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
String password = sysUser.getPassword();
String passwordEncode = PasswordUtil.encrypt(sysUser.getUsername(), password, salt);
sysUser.setPassword(passwordEncode);
sysUser.setLastPwdUpdateTime(new Date());
this.userMapper.updateById(sysUser);
return Result.ok("密码修改成功!");
}
@ -280,11 +295,9 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
@CacheEvict(value={CacheConstant.SYS_USERS_CACHE}, allEntries=true)
@Transactional(rollbackFor = Exception.class)
public boolean deleteUser(String userId) {
//update-begin---author:wangshuai---date:2024-01-16---for:【QQYUN-7974】admin用户禁止删除---
//1.验证当前用户是管理员账号 admin
//验证用户是否为管理员
this.checkUserAdminRejectDel(userId);
//update-end---author:wangshuai---date:2024-01-16---for:【QQYUN-7974】admin用户禁止删除---
//2.删除用户
this.removeById(userId);
@ -366,7 +379,6 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
//只有 X-Version=v3 的时候才读取sys_role_index表获取角色首页配置
boolean isV3 = CommonConstant.VERSION_V3.equals(version);
if (isV3) {
//update-begin-author:liusq---date:2025-07-01--for: [QQYUN-12980] 【首页配置】首页自定义配置功能页面
//1.先查询 用户USER级别 的所有首页配置
if(oConvertUtils.isNotEmpty(username)){
LambdaQueryWrapper<SysRoleIndex> routeIndexUserQuery = new LambdaQueryWrapper<>();
@ -391,11 +403,10 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
String componentUrl = RoleIndexConfigEnum.getIndexByRoles(roles);
roleIndex = new SysRoleIndex(componentUrl);
//用户所有角色
//update-begin-author:liusq---date:2025-07-21--for: [QQYUN-13187]【新用户登录报错】没有添加角色时 报错
// 代码逻辑说明: [QQYUN-13187]【新用户登录报错】没有添加角色时 报错
if(CollectionUtil.isNotEmpty(roles)){
routeIndexQuery.in(SysRoleIndex::getRoleCode, roles);
}
//update-end-author:liusq---date:2025-07-21--for: [QQYUN-13187]【新用户登录报错】没有添加角色时 报错
//优先级正序排序
routeIndexQuery.orderByAsc(SysRoleIndex::getPriority);
list = sysRoleIndexService.list(routeIndexQuery);
@ -404,7 +415,6 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
}
}
}
//update-end-author:liusq---date:2025-07-01--for: [QQYUN-12980] 【首页配置】首页自定义配置功能页面
}
if (oConvertUtils.isEmpty(roleIndex.getComponent())) {
@ -552,7 +562,6 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
return res;
}
//update-begin-author:taoyan date:2022-9-13 for: VUEN-2245【漏洞】发现新漏洞待处理20220906 ----sql注入 方法没有使用,注掉
/* @Override
public IPage<SysUser> getUserByDepartIdAndQueryWrapper(Page<SysUser> page, String departId, QueryWrapper<SysUser> queryWrapper) {
LambdaQueryWrapper<SysUser> lambdaQueryWrapper = queryWrapper.lambda();
@ -562,7 +571,6 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
return userMapper.selectPage(page, lambdaQueryWrapper);
}*/
//update-end-author:taoyan date:2022-9-13 for: VUEN-2245【漏洞】发现新漏洞待处理20220906 ----sql注入 方法没有使用,注掉
@Override
public IPage<SysUserSysDepartModel> queryUserByOrgCode(String orgCode, SysUser userParams, IPage page) {
@ -590,7 +598,7 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
*/
@Override
public IPage<SysUser> getUserByRoleId(Page<SysUser> page, String roleId, String username, String realname) {
//update-begin---author:wangshuai ---date:20230220 for[QQYUN-3980]组织管理中 职位功能 职位表加租户id 加职位-用户关联表------------
// 代码逻辑说明: [QQYUN-3980]组织管理中 职位功能 职位表加租户id 加职位-用户关联表------------
IPage<SysUser> userRoleList = userMapper.getUserByRoleId(page, roleId, username,realname);
List<SysUser> records = userRoleList.getRecords();
if (null != records && records.size() > 0) {
@ -604,7 +612,6 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
}
}
return userRoleList;
//update-end---author:wangshuai ---date:20230220 for[QQYUN-3980]组织管理中 职位功能 职位表加租户id 加职位-用户关联表------------
}
@ -692,9 +699,8 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
return result;
}
//情况2根据用户信息查询该用户已注销
//update-begin---author:王帅 Date:20200601 forif条件永远为falsebug------------
// 代码逻辑说明: if条件永远为falsebug------------
if (CommonConstant.DEL_FLAG_1.equals(sysUser.getDelFlag())) {
//update-end---author:王帅 Date:20200601 forif条件永远为falsebug------------
baseCommonService.addLog("用户登录失败,用户名:" + sysUser.getUsername() + "已注销!", CommonConstant.LOG_TYPE_1, null);
result.error500("该用户已注销");
return result;
@ -710,11 +716,10 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
@Override
public List<SysUser> queryLogicDeleted() {
//update-begin---author:wangshuai ---date:20221116 for回收站查询未离职的------------
// 代码逻辑说明: 回收站查询未离职的------------
LambdaQueryWrapper<SysUser> wrapper = new LambdaQueryWrapper<>();
wrapper.ne(SysUser::getStatus, CommonConstant.USER_QUIT);
return this.queryLogicDeleted(wrapper);
//update-end---author:wangshuai ---date:20221116 for回收站查询未离职的--------------
}
@Override
@ -788,10 +793,13 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
@Override
@Transactional(rollbackFor = Exception.class)
public void saveUser(SysUser user, String selectedRoles, String selectedDeparts, String relTenantIds, boolean izSyncPack) {
//step.1 保存用户
if(null == user.getSort()){
user.setSort(CommonConstant.DEFAULT_USER_SORT);
}
//step.1 保存用户
this.save(user);
//获取用户保存前台传过来的租户id并添加到租户
this.saveUserTenant(user.getId(),relTenantIds, izSyncPack);
this.saveUserTenant(user.getId(),relTenantIds, izSyncPack);
//step.2 保存角色
if(oConvertUtils.isNotEmpty(selectedRoles)) {
String[] arr = selectedRoles.split(",");
@ -822,6 +830,9 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
public void editUser(SysUser user, String roles, String departs, String relTenantIds, String updateFromPage) {
//获取用户编辑前台传过来的租户id
this.editUserTenants(user.getId(),relTenantIds);
if(null == user.getSort()){
user.setSort(CommonConstant.DEFAULT_USER_SORT);
}
//step.1 修改用户基础信息
this.updateById(user);
//step.2 修改角色
@ -874,12 +885,11 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
//step.5 修改职位
this.editUserPosition(user.getId(),user.getPost());
//update-begin---author:wangshuai---date:2025-09-06---for:兼职岗位改造成中间表的方式---
//代码逻辑说明: 兼职岗位改造成中间表的方式---
//step6 修改兼职岗位
//先删后加
depPostMapper.delete(new QueryWrapper<SysUserDepPost>().lambda().eq(SysUserDepPost::getUserId, user.getId()));
this.saveUserOtherDepPost(user.getId(),user.getOtherDepPostId());
//update-end---author:wangshuai---date:2025-09-06---for:兼职岗位改造成中间表的方式---
}
@ -939,7 +949,7 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
if(null == sysUser){
throw new JeecgBootException("离职失败,该用户已不存在");
}
//update-begin---author:wangshuai ---date:20230111 for[QQYUN-3951]租户用户离职重构------------
// 代码逻辑说明: [QQYUN-3951]租户用户离职重构------------
int tenantId = oConvertUtils.getInt(TenantContext.getTenant(), 0);
//更新用户租户表的状态为离职状态
if(tenantId==0){
@ -951,7 +961,6 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
SysUserTenant userTenant = new SysUserTenant();
userTenant.setStatus(CommonConstant.USER_TENANT_QUIT);
userTenantMapper.update(userTenant,query);
//update-end---author:wangshuai ---date:20230111 for[QQYUN-3951]租户用户离职重构------------
}
@Override
@ -971,16 +980,12 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
*/
@Override
public Result<JSONObject> setLoginTenant(SysUser sysUser, JSONObject obj, String username, Result<JSONObject> result){
// update-begin--Author:sunjianlei Date:20210802 for获取用户租户信息
//用户有哪些租户
// List<SysTenant> tenantList = null;
//update-begin---author:wangshuai ---date:20221223 for[QQYUN-3371]租户逻辑改造,改成关系表------------
//update-begin---author:wangshuai ---date:20230427 for【QQYUN-5270】名下租户全部退出后再次登录出现租户冻结------------
// 代码逻辑说明: [QQYUN-3371]租户逻辑改造,改成关系表
List<SysTenant> tenantList = relationMapper.getTenantNoCancel(sysUser.getId());
obj.put("tenantList", tenantList);
//update-end---author:wangshuai ---date:20230427 for【QQYUN-5270】名下租户全部退出后再次登录出现租户冻结------------
// if (null!=tenantIdList && tenantIdList.size()>0) {
// //update-end---author:wangshuai ---date:20221223 for[QQYUN-3371]租户逻辑改造,改成关系表--------------
// //-------------------------------------------------------------------------------------
// //查询有效的租户集合
// LambdaQueryWrapper<SysTenant> queryWrapper = new LambdaQueryWrapper<>();
@ -995,8 +1000,6 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
// obj.put("tenantList", tenantList);
// }
// }
//update-end---author:wangshuai ---date:20221223 for[QQYUN-3371]租户逻辑改造,改成关系表--------------
// update-end--Author:sunjianlei Date:20210802 for获取用户租户信息
//登录会话租户ID有效性重置
@ -1016,7 +1019,7 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
}
//设置用户登录缓存租户
this.updateUserDepart(username, null,sysUser.getLoginTenantId());
log.info(" 登录接口用户的租户ID = {}", sysUser.getLoginTenantId());
log.debug(" 登录接口用户的租户ID = {}", sysUser.getLoginTenantId());
if(sysUser.getLoginTenantId()!=null){
//登录的时候需要手工设置下会话中的租户ID,不然登录接口无法通过租户隔离查询到数据
TenantContext.setTenant(sysUser.getLoginTenantId()+"");
@ -1073,7 +1076,7 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
}else{
//是否开启系统管理模块的多租户数据隔离【SAAS多租户模式】
if (MybatisPlusSaasConfig.OPEN_SYSTEM_TENANT_CONTROL) {
//update-begin---author:wangshuai ---date:20230220 for判断当前用户是否在当前租户里面,如果不存在在新增------------
// 代码逻辑说明: 判断当前用户是否在当前租户里面,如果不存在在新增------------
String tenantId = TenantContext.getTenant();
if(oConvertUtils.isNotEmpty(tenantId)){
Integer count = relationMapper.userTenantIzExist(userId, Integer.parseInt(tenantId));
@ -1090,7 +1093,6 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
}
}
}
//update-end---author:wangshuai ---date:20230220 for判断当前用户是否在当前租户里面如果不存在在新增------------
}
}
}
@ -1164,12 +1166,10 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
String workAddress = json.getString("workAddress");
//批量修改用户职位
if(oConvertUtils.isNotEmpty(post)) {
//update-begin---author:wangshuai ---date:20230220 for[QQYUN-3980]组织管理中 职位功能 职位表加租户id 加职位-用户关联表------------
//修改职位用户关系表
for (String userId:idList) {
this.editUserPosition(userId,post);
}
//update-end---author:wangshuai ---date:20230220 for[QQYUN-3980]组织管理中 职位功能 职位表加租户id 加职位-用户关联表------------
}
if(oConvertUtils.isNotEmpty(selecteddeparts)) {
//查询当前租户的部门列表
@ -1321,14 +1321,13 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
this.baseMapper.updateById(user);
}
}
//update-begin---author:wangshuai ---date:20230303 for部门负责人不能被删除------------
// 代码逻辑说明: 部门负责人不能被删除------------
this.removeDepartmentManager(departChargeUserIdList,departChargeUsers,departId);
}else{
if(CollectionUtil.isNotEmpty(departChargeUsers)){
//前端传过来用户列表id为空说明数据库的负责部门人员均需要删除
this.removeDepartmentManager(departChargeUserIdList,departChargeUsers,departId);
}
//update-end---author:wangshuai ---date:20230303 for部门负责人不能被删除------------
}
}
@ -1336,7 +1335,7 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
private List<SysUser> queryDepartChargePersons(String departId){
List<SysUser> result = new ArrayList<>();
//update-begin---author:wangshuai ---date:20230303 for部门负责人不能被删除------------
// 代码逻辑说明: 部门负责人不能被删除------------
LambdaQueryWrapper<SysUser> userQuery = new LambdaQueryWrapper<>();
userQuery.like(SysUser::getDepartIds,departId);
List<SysUser> userList = userMapper.selectList(userQuery);
@ -1349,7 +1348,6 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
if(deps.indexOf(departId)>=0){
result.add(user);
}
//update-end---author:wangshuai ---date:20230303 for部门负责人不能被删除------------
}
}
}
@ -1445,7 +1443,7 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
user.setWorkNo(sysUser.getWorkNo());
user.setId(sysUser.getId());
this.updateById(user);
//update-begin---author:wangshuai ---date:20230424 for【QQYUN-5251】人员与部门部门删除不掉------------
// 代码逻辑说明: 【QQYUN-5251】人员与部门部门删除不掉------------
if(oConvertUtils.isEmpty(departs)){
//直接删除用户下的的租户部门
sysUserDepartMapper.deleteUserDepart(user.getId(),tenantId);
@ -1453,7 +1451,6 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
//修改租户用户下的部门
this.updateTenantDepart(user, tenantId, departs);
}
//update-end---author:wangshuai ---date:20230424 for【QQYUN-5251】人员与部门部门删除不掉------------
//修改用户下的职位
this.editUserPosition(sysUser.getId(),sysUser.getPost());
}
@ -1648,11 +1645,10 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
for (SysUser sysUser : userList) {
AppExportUserVo exportUserVo = new AppExportUserVo();
BeanUtils.copyProperties(sysUser, exportUserVo);
//update-begin---author:wangshuai---date:2025-01-17---for:【QQYUN-10926】组织管理——用户导出时部门没有导出上下级关系---
// 代码逻辑说明: 【QQYUN-10926】组织管理——用户导出时部门没有导出上下级关系---
Map<String, String> departMap = this.getDepartNamesAndCategory(userDepVos, sysUser);
String departNames = departMap.get("departNames");
exportUserVo.setDepart(departNames.toString());
//update-end---author:wangshuai---date:2025-01-17---for:【QQYUN-10926】组织管理——用户导出时部门没有导出上下级关系---
String posNames = positionVos.stream().filter(item -> item.getUserId().equals(sysUser.getId())).map(SysUserPositionVo::getName).collect(Collectors.joining(SymbolConstant.SEMICOLON));
exportUserVo.setPosition(posNames);
exportUserVoList.add(exportUserVo);
@ -1721,12 +1717,11 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
}
departOrgCategorys.append(orgCatrgory);
}
//update-begin---author:wangshuai---date:2025-08-27---for:【QQYUN-13617】导入时 部门添加层级不对了---
// 代码逻辑说明: 【QQYUN-13617】导入时 部门添加层级不对了---
Map<String,String> map = new HashMap<>();
map.put("departNames", departNames.toString());
map.put("departOrgCategorys",departOrgCategorys.toString());
return map;
//update-end---author:wangshuai---date:2025-08-27---for:【QQYUN-13617】导入时 部门添加层级不对了---
}
/**
@ -2044,22 +2039,19 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
userTenant.setUserId(userId);
userTenant.setStatus(CommonConstant.USER_TENANT_INVITE);
userTenantMapper.insert(userTenant);
//update-begin---author:wangshuai ---date:20230710 for【QQYUN-5731】导入用户时没有提醒------------
//发送系统消息通知
LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
MessageDTO messageDTO = new MessageDTO();
String title = sysUser.getRealname() + " 邀请您加入 " + tenantName + "";
messageDTO.setTitle(title);
Map<String, Object> data = new HashMap<>();
//update-begin---author:wangshuai---date:2024-03-11---for:【QQYUN-8425】用户导入成功后 消息提醒 跳转至同意页面---
// 代码逻辑说明: 【QQYUN-8425】用户导入成功后 消息提醒 跳转至同意页面---
data.put(CommonConstant.NOTICE_MSG_BUS_TYPE,SysAnnmentTypeEnum.TENANT_INVITE.getType());
//update-end---author:wangshuai---date:2024-03-11---for:【QQYUN-8425】用户导入成功后 消息提醒 跳转至同意页面---
messageDTO.setData(data);
messageDTO.setContent(title);
messageDTO.setToUser(invitedUsername);
messageDTO.setFromUser("system");
systemSendMsgHandle.sendMessage(messageDTO);
//update-end---author:wangshuai ---date:20230710 for【QQYUN-5731】导入用户时没有提醒------------
}
//======================================= end 用户与部门 用户列表导入 =========================================
@ -2239,12 +2231,11 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
for (SysUser sysUser : userList) {
SysUserExportVo userExportVo = new SysUserExportVo();
BeanUtils.copyProperties(sysUser, userExportVo);
//update-begin---author:wangshuai---date:2025-08-27---for:【QQYUN-13617】导入时 部门添加层级不对了---
// 代码逻辑说明: 【QQYUN-13617】导入时 部门添加层级不对了---
Map<String, String> departMap = this.getDepartNamesAndCategory(userDepVos, sysUser);
String departNames = departMap.get("departNames");
userExportVo.setDepartNames(departNames);
userExportVo.setOrgCategorys(departMap.get("departOrgCategorys"));
//update-end---author:wangshuai---date:2025-08-27---for:【QQYUN-13617】导入时 部门添加层级不对了---
String departIds = sysUser.getDepartIds();
if (oConvertUtils.isNotEmpty(departIds)) {
List<SysUserDepVo> depVoList = sysDepartMapper.getDepartByIds(Arrays.asList(departIds.split(",")));
@ -2263,12 +2254,11 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
userExportVo.setPostName(postName);
postNameMap.put(sysUser.getMainDepPostId(), postName);
}
//update-begin---author:wangshuai---date:2025-09-06---for:兼职岗位改造成中间表的方式---
// 代码逻辑说明: 兼职岗位改造成中间表的方式---
List<String> depPost = depPostMapper.getDepPostByUserId(sysUser.getId());
if(CollectionUtil.isNotEmpty(depPost)){
userExportVo.setOtherDepPostId(String.join(SymbolConstant.COMMA, depPost));
}
//update-end---author:wangshuai---date:2025-09-06---for:兼职岗位改造成中间表的方式---
list.add(userExportVo);
}
}
@ -2303,7 +2293,7 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
SysUserImportVo sysUserExcel = listSysUsers.get(i);
SysUser sysUser = new SysUser();
BeanUtils.copyProperties(sysUserExcel, sysUser);
if (OkConvertUtils.isEmpty(sysUser.getUsername())) {
if (oConvertUtils.isEmpty(sysUser.getUsername())) {
errorLines += 1;
int lineNumber = i + 1;
errorMessage.add("" + lineNumber + " 行:用户账号为空,忽略导入。");
@ -2327,6 +2317,12 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
String passwordEncode = PasswordUtil.encrypt(sysUserExcel.getUsername(), sysUser.getPassword(), salt);
sysUser.setPassword(passwordEncode);
sysUser.setActivitiSync(CommonConstant.ACT_SYNC_1);
if(null == sysUser.getDelFlag()){
sysUser.setDelFlag(CommonConstant.DEL_FLAG_0);
}
if(null == sysUser.getStatus()){
sysUser.setStatus(CommonConstant.STATUS_1_INT);
}
this.save(sysUser);
}
//添加部门
@ -2335,9 +2331,9 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
//新增或编辑部门
Integer tenantIdInt = 0;
if (MybatisPlusSaasConfig.OPEN_SYSTEM_TENANT_CONTROL) {
tenantIdInt = OkConvertUtils.getInt(tenantId, 0);
tenantIdInt = oConvertUtils.getInt(tenantId, 0);
}
this.lowAddOrEditDepart(sysUser.getId(), departNames, tenantIdInt, departMap, orgCategorys, sysUserExcel.getPostName(), sysUserExcel.getMainDepPostId(),postMap,positionMap);
this.lowAddOrEditDepart(sysUser.getId(), departNames, tenantIdInt, departMap, orgCategorys, sysUserExcel.getPostName(), sysUserExcel.getMainDepPostId(),postMap,positionMap, sysUserExcel.getOtherDepPostId());
//新增或编辑角色
String roleNames = sysUserExcel.getRoleNames();
this.saveOrEditRole(sysUser.getId(), roleNames, tenantIdInt);
@ -2399,19 +2395,20 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
//================================================================ begin 【用户导入】导入时 部门添加层级不对了======================================================================
/**
* 低代码下添加部门和用户
*
* @Description 和敲敲云分割处理,原因:因低代码岗位等改造,有级别,故添加部门分开处理
*
* @param userId 用户id
* @param depart 部门名称
* @param tenantId 租户id
* @param departMap 存放部门的map;key为名称 value为SysDepart对象。
* @param orgCategorys 部门类型
* @param postName 职级名称
* @param mainDepPostName 岗位名称
* @param mainDepPostName 岗位名称
* @param postMap key: 岗位名称 + 部门id value岗位部门id
* @param positionMap key: 职级名称 value: 职级id
* @param otherDepPostName 兼职岗位名称
* @Description 和敲敲云分割处理,原因:因低代码岗位等改造,有级别,故添加部门分开处理
*/
private void lowAddOrEditDepart(String userId, String depart, Integer tenantId, Map<String, SysDepart> departMap, String orgCategorys, String postName, String mainDepPostName, Map<String, String> postMap, Map<String, String> positionMap) {
private void lowAddOrEditDepart(String userId, String depart, Integer tenantId, Map<String, SysDepart> departMap, String orgCategorys, String postName, String mainDepPostName, Map<String, String> postMap, Map<String, String> positionMap, String otherDepPostName) {
//批量将部门和用户信息建立关联关系
if (StringUtils.isNotEmpty(depart)) {
Page<SysDepart> page = new Page<>(1, 1);
@ -2426,6 +2423,8 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
departNameList = departNameList.stream().distinct().collect(Collectors.toList());
//当下部门循环下标
int index = 0;
//是否已导入岗位,岗位只导入第一个部门下
boolean izImportPost = false;
for (String departName : departNameList) {
//部门id
String parentId = "";
@ -2485,7 +2484,7 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
departMap.put(nameStr, sysDepart);
}
//最后一位新增部门用户关系表
if (i == names.length - 1) {
if (i == names.length - 1 && !izImportPost) {
Long count = sysUserDepartMapper.getCountByDepartIdAndUserId(userId, sysDepart.getId());
if (count == 0) {
SysUserDepart userDepart = new SysUserDepart(userId, sysDepart.getId());
@ -2495,6 +2494,11 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
if (oConvertUtils.isNotEmpty(mainDepPostName)) {
this.insertDepartPost(userId, parentId ,postName, mainDepPostName, postMap, tenantId, positionMap);
}
//添加兼职岗位
if(oConvertUtils.isNotEmpty(otherDepPostName)){
this.insertOtherDepartPost(userId,parentId,postName, otherDepPostName, postMap, tenantId, positionMap);
}
izImportPost = true;
}
}
index++;
@ -2524,35 +2528,8 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
String departId = sysDepartMapper.getDepIdByDepIdAndPostName(depId, postName);
//不存在新增岗位
if (oConvertUtils.isEmpty(departId) ) {
//新增岗位
SysDepart sysDepart = new SysDepart();
JSONObject formData = new JSONObject();
formData.put("parentId", depId);
String[] codeArray = (String[]) FillRuleUtil.executeRule(FillRuleConstant.DEPART, formData);
sysDepart.setParentId(depId);
sysDepart.setOrgCode(codeArray[0]);
sysDepart.setOrgType(codeArray[1]);
sysDepart.setTenantId(tenantId);
sysDepart.setDepartName(mainDepPostName);
sysDepart.setIzLeaf(CommonConstant.IS_LEAF);
sysDepart.setDelFlag(String.valueOf(CommonConstant.DEL_FLAG_0));
sysDepart.setStatus(CommonConstant.STATUS_1);
sysDepart.setOrgCategory(DepartCategoryEnum.DEPART_CATEGORY_POST.getValue());
//获取职级id
String positionId = "";
if(postionMap.containsKey(postName)){
positionId = postionMap.get(postName);
} else {
//根据租户id和职级名称获取职级id
positionId = this.getSysPosition(tenantId, postName);
}
sysDepart.setPositionId(positionId);
postionMap.put(postName, positionId);
sysDepartMapper.insert(sysDepart);
sysDepartMapper.setMainLeaf(depId, CommonConstant.NOT_LEAF);
postMap.put(mainDepPostName + depId, sysDepart.getId());
//需要将用户表的主岗位进行关联
departId = sysDepart.getId();
//添加部门岗位信息
departId = this.addCommontDepartPost(depId, tenantId, mainDepPostName, postionMap, postName, postMap);
}
if(oConvertUtils.isNotEmpty(departId)){
//更新用户主岗位
@ -2564,6 +2541,84 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
}
}
/**
* 导入通用添加部门岗位方法
*
* @param depId
* @param tenantId
* @param mainDepPostName
* @param postionMap
* @param postName
* @param map
* @param postMap
* @return
*/
private String addCommontDepartPost(String depId, Integer tenantId, String mainDepPostName, Map<String, String> postionMap, String postName, Map<String, String> postMap) {
//新增岗位
SysDepart sysDepart = new SysDepart();
JSONObject formData = new JSONObject();
formData.put("parentId", depId);
String[] codeArray = (String[]) FillRuleUtil.executeRule(FillRuleConstant.DEPART, formData);
sysDepart.setParentId(depId);
sysDepart.setOrgCode(codeArray[0]);
sysDepart.setOrgType(codeArray[1]);
sysDepart.setTenantId(tenantId);
sysDepart.setDepartName(mainDepPostName);
sysDepart.setIzLeaf(CommonConstant.IS_LEAF);
sysDepart.setDelFlag(String.valueOf(CommonConstant.DEL_FLAG_0));
sysDepart.setStatus(CommonConstant.STATUS_1);
sysDepart.setOrgCategory(DepartCategoryEnum.DEPART_CATEGORY_POST.getValue());
//获取职级id
String positionId = "";
if (postionMap.containsKey(postName)) {
positionId = postionMap.get(postName);
} else {
//根据租户id和职级名称获取职级id
positionId = this.getSysPosition(tenantId, postName);
}
sysDepart.setPositionId(positionId);
postionMap.put(postName, positionId);
sysDepartMapper.insert(sysDepart);
sysDepartMapper.setMainLeaf(depId, CommonConstant.NOT_LEAF);
postMap.put(mainDepPostName + depId, sysDepart.getId());
//需要将用户表的主岗位进行关联
return sysDepart.getId();
}
/**
* 添加兼职岗位
*
* @param userId 用户id
* @param departId 部门id【上级部门id】
* @param postName 职级名称
* @param otherDepPostName 兼职岗位名称
* @param postMap 岗位map key岗位名称 + 部门id value岗位部门id
* @param tenantId 租户id
* @param postionMap 职级map key: 职级名称 value: 职级id
*/
private void insertOtherDepartPost(String userId, String depId, String postName, String otherDepPostName, Map<String, String> postMap, Integer tenantId, Map<String, String> positionMap) {
String[] otherDepPostNames = otherDepPostName.split(SymbolConstant.SEMICOLON);
for (int i = 0; i < otherDepPostNames.length; i++) {
//当前部门下已经存在岗位就不需要再次添加岗位了
String departId = "";
if (null == postMap || !postMap.containsKey(otherDepPostNames[i] + depId)) {
//不存在时新增部门岗位
departId = this.addCommontDepartPost(depId, tenantId, otherDepPostNames[i], positionMap, postName, postMap);
} else {
departId = postMap.get(otherDepPostNames[i] + depId);
}
//插入用岗位第三方中间表
if (oConvertUtils.isNotEmpty(departId)) {
try {
SysUserDepPost depPost = new SysUserDepPost(userId, departId);
depPostMapper.insert(depPost);
} catch (Exception e) {
log.error("当前岗位插入失败:" + e.getMessage(), e);
}
}
}
}
/**
* 获取职务信息
*
@ -2584,7 +2639,7 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
private void saveChargeDepart(SysUser sysUser, String departIds, Map<String, SysDepart> departMap) {
//判断那些部门没有,即没有加入到部门,则不能成为负责部门人员
if (OkConvertUtils.isEmpty(departIds)) {
if (oConvertUtils.isEmpty(departIds)) {
return;
}
//多个部门用;分隔开
@ -2676,7 +2731,7 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
}
//step5 修改密码
String newPassWord = PasswordUtil.encrypt(username, password, user.getSalt());
this.userMapper.update(new SysUser().setPassword(newPassWord), new LambdaQueryWrapper<SysUser>().eq(SysUser::getId, user.getId()));
this.userMapper.update(new SysUser().setPassword(newPassWord).setLastPwdUpdateTime(new Date()), new LambdaQueryWrapper<SysUser>().eq(SysUser::getId, user.getId()));
}
/**
@ -2748,12 +2803,306 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
} else {
item.setRelTenantIds("");
}
Integer posTenantId = null;
if (MybatisPlusSaasConfig.OPEN_SYSTEM_TENANT_CONTROL) {
posTenantId = oConvertUtils.getInt(TenantContext.getTenant(), 0);;
//兼职岗位
List<String> depPostList = depPostMapper.getDepPostByUserId(item.getId());
if(CollectionUtil.isNotEmpty(depPostList)){
item.setOtherDepPostId(StringUtils.join(depPostList.toArray(), SymbolConstant.COMMA));
}
});
}
return page.setRecords(sysDepartModels);
}
/**
* 据 orgCode 查询用户信息(部门全路径,主岗位和兼职岗位的信息),包括公司、子公司、部门
*
* @param orgCode
* @param userParams
* @param page
* @return
*/
@Override
public IPage<SysUserSysDepPostModel> queryDepartUserByOrgCode(String orgCode, SysUser userParams, IPage page) {
List<SysUserSysDepPostModel> sysDepartModels = baseMapper.queryDepartUserByOrgCode(page, orgCode, userParams);
//用户id
List<String> userIdList = sysDepartModels.stream().map(SysUserSysDepPostModel::getId).toList();
if (CollectionUtil.isNotEmpty(userIdList)) {
//根据用户ids获取部门名称 key 用户id value 部门名称
Map<String, String> departNameMap = this.getDepartNamesByUserIds(userIdList, SymbolConstant.COMMA);
//获取兼职岗位
Map<String, String> departPostMap = this.getDepartOtherPostByUserIds(userIdList, SymbolConstant.COMMA);
ISysDepartService service = SpringContextUtils.getBean(SysDepartServiceImpl.class);
sysDepartModels.forEach(item -> {
item.setDepartName(departNameMap.get(item.getId()));
item.setOtherPostName(departPostMap.get(item.getId()));
//获取主岗位全路径
if (oConvertUtils.isNotEmpty(item.getMainDepPostId())) {
SysDepart departById = sysDepartMapper.getDepartById(item.getMainDepPostId());
if (null != departById) {
String departPathName = service.getDepartPathNameByOrgCode(departById.getOrgCode(), "");
item.setPostName(departPathName);
}
}
});
}
return page.setRecords(sysDepartModels);
}
/**
* 通讯录点击用户获取用户详情(包含用户基本信息、部门全路径、主岗位兼职岗位全路径)
*
* @param userId
* @return
*/
@Override
public SysUserSysDepPostModel getUserDetailByUserId(String userId) {
SysUser sysUser = baseMapper.selectById(userId);
if (null != sysUser) {
SysUserSysDepPostModel userModel = new SysUserSysDepPostModel();
BeanUtils.copyProperties(sysUser, userModel);
//获取部门名称
List<String> userIds = new ArrayList<>();
userIds.add(userId);
Map<String, String> departNameMap = this.getDepartNamesByUserIds(userIds, "__");
userModel.setDepartName(departNameMap.get(userId));
ISysDepartService service = SpringContextUtils.getBean(SysDepartServiceImpl.class);
//获取主岗位全路径
if (oConvertUtils.isNotEmpty(sysUser.getMainDepPostId())) {
SysDepart departById = sysDepartMapper.getDepartById(sysUser.getMainDepPostId());
if (null != departById) {
String departPathName = service.getDepartPathNameByOrgCode(departById.getOrgCode(), "");
userModel.setPostName(departPathName);
}
}
//获取兼职岗位全路径
Map<String, String> departPostMap = this.getDepartOtherPostByUserIds(userIds, "__");
userModel.setOtherPostName(departPostMap.get(userId));
return userModel;
}
return null;
}
/**
* 登录获取用户部门信息
* @param jsonObject
* @return
*/
@Override
public Result loginGetUserDeparts(JSONObject jsonObject) {
Result result = new Result<>();
//返回内容
JSONObject obj = new JSONObject(new LinkedHashMap<>());
// 登录方式 phone:手机 account:账号密码
String loginType = jsonObject.getString("loginType");
String username = jsonObject.getString("username");
String source = oConvertUtils.getString(jsonObject.getString("source"),"PC");
// 手机号登录校验
if("phone".equalsIgnoreCase(loginType)){
String phone = jsonObject.getString("mobile");
//1.校验用户有效性
SysUser sysUser = baseMapper.getUserByPhone(phone);
result = this.checkUserIsEffective(sysUser);
if(!result.isSuccess()) {
return result;
}
//2.校验验证码
String smscode = jsonObject.getString("smscode");
String redisKey = CommonConstant.PHONE_REDIS_KEY_PRE+phone;
Object code = redisUtil.get(redisKey);
if (!smscode.equals(code)) {
return Result.error("手机验证码错误");
}
//3.当前登录账号
username = sysUser.getUsername();
String orgCode = sysUser.getOrgCode();
obj.put("currentOrgCode", orgCode);
}else{
String password = AesEncryptUtil.resolvePassword(jsonObject.getString("password"));
log.debug("登录密码,原始密码:{},解密密码:{}" , jsonObject.getString("password"), password);
// 手机端没有验证码,不做校验
if(!"APP".equalsIgnoreCase(source)){
// step.1 验证码check
SysLoginModel sysLoginModel = new SysLoginModel();
String inputCode = jsonObject.getString("inputCode");
String checkKey = jsonObject.getString("checkKey");
sysLoginModel.setCaptcha(inputCode);
sysLoginModel.setCheckKey(checkKey);
if (inputCode == null) {
result.error500("验证码无效");
return result;
}
String lowerCaseCaptcha = inputCode.toLowerCase();
String keyPrefix = Md5Util.md5Encode(sysLoginModel.getCheckKey() + jeecgBaseConfig.getSignatureSecret(), "utf-8");
String realKey = keyPrefix + lowerCaseCaptcha;
Object checkCode = redisUtil.get(realKey);
if (checkCode == null || !checkCode.toString().equals(lowerCaseCaptcha)) {
log.warn("验证码错误key= {} , Ui checkCode= {}, Redis checkCode = {}", sysLoginModel.getCheckKey(), lowerCaseCaptcha, checkCode);
result.error500("验证码错误");
result.setCode(HttpStatus.PRECONDITION_FAILED.value());
return result;
}
}
// step.2 校验用户是否存在且有效
SysUser sysUser = baseMapper.getUserByName(username);
result = this.checkUserIsEffective(sysUser);
if(!result.isSuccess()) {
return result;
}
// step.3 校验用户名或密码是否正确
String userpassword = PasswordUtil.encrypt(username, password, sysUser.getSalt());
String syspassword = sysUser.getPassword();
if (!syspassword.equals(userpassword)) {
result.error500("用户名或密码错误");
return result;
}
String orgCode = sysUser.getOrgCode();
obj.put("currentOrgCode", orgCode);
}
// step.4 获取用户部门信息,仅限部门
List<SysDepart> departList = sysDepartMapper.queryDeptByUserAndCategory(username,DepartCategoryEnum.DEPART_CATEGORY_DEPART.getValue());
if (CollectionUtil.isNotEmpty(departList)) {
ISysDepartService service = SpringContextUtils.getBean(SysDepartServiceImpl.class);
List<Map<String, String>> departs = departList.stream()
.filter(depart -> oConvertUtils.isNotEmpty(depart) &&
oConvertUtils.isNotEmpty(depart.getOrgCode()))
.map(depart -> {
String departName = depart.getDepartNameAbbr();
//简称是空的情况下,查询全路径名称
if(oConvertUtils.isEmpty(departName)){
departName = service.getDepartPathNameByOrgCode(depart.getOrgCode(), "");
}
Map<String, String> map = new HashMap<>();
map.put("orgCode", depart.getOrgCode());
map.put("departName", departName);
return map;
})
.collect(Collectors.toList());
obj.put("departs", departs);
}
result.setResult(obj);
return result;
}
/**
* 批量重置密码为系统密码
* @param usernames
*/
@Override
public void resetToSysPassword(String usernames) {
//1.判断是否存在admin账户
if(hasAdminIntersection(usernames)){
throw new JeecgBootException("所选用户中包含管理员,管理员账号不允许重置密码!!");
}
List<String> userArr = Arrays.asList(usernames.split(","));
userArr.stream().forEach(username -> {
if(oConvertUtils.isNotEmpty(username)){
String salt = oConvertUtils.randomGen(8);
String passwordEncode = PasswordUtil.encrypt(username, PasswordConstant.DEFAULT_PASSWORD, salt);
//重置密码
UpdateWrapper<SysUser> updateWrapper = new UpdateWrapper<>();
updateWrapper
.eq("username", username)
.set("last_pwd_update_time", new Date())
.set("password", passwordEncode)
.set("salt", salt);
this.baseMapper.update(null, updateWrapper);
}
});
}
/**
* 更新设备信息
* @param clientId
* @param userId
*/
@Override
@Transactional(rollbackFor = Exception.class)
public void updateClientId(String clientId,String userId) {
//解绑之前的设备账户
if(oConvertUtils.isNotEmpty(clientId)){
UpdateWrapper<SysUser> updateWrapper = new UpdateWrapper<>();
updateWrapper
.eq("client_id", clientId)
.set("client_id", null);
this.baseMapper.update(null, updateWrapper);
}
//设置新的绑定
SysUser sysUser = new SysUser();
sysUser.setClientId(clientId);
sysUser.setId(userId);
this.baseMapper.updateById(sysUser);
}
/**
* 是否有交集
*/
public static boolean hasAdminIntersection(String usernames) {
if (oConvertUtils.isEmpty(usernames)) {
return false;
}
// 使用HashSet提高查找效率
Set<String> adminSet = Arrays.stream(ADMIN_ACCOUNT)
.map(String::toLowerCase)
.collect(Collectors.toSet());
return Arrays.stream(usernames.split(SymbolConstant.COMMA))
.map(String::trim)
.map(String::toLowerCase)
.anyMatch(adminSet::contains);
}
/**
* 根据用户ids获取部门名称
*
* @param userIdList
* @param symbol
* @return
*/
private Map<String, String> getDepartOtherPostByUserIds(List<String> userIdList, String symbol) {
Map<String, String> departPostMap = new HashMap<>();
List<SysUserSysDepPostModel> departPost = sysDepartMapper.getDepartOtherPostByUserIds(userIdList);
if (CollectionUtil.isNotEmpty(departPost)) {
ISysDepartService service = SpringContextUtils.getBean(SysDepartServiceImpl.class);
departPost.forEach(item -> {
if (oConvertUtils.isNotEmpty(item.getId()) && oConvertUtils.isNotEmpty(item.getOtherDepPostId())) {
String postName = service.getDepartPathNameByOrgCode(item.getOrgCode(), "");
if (departPostMap.containsKey(item.getId())) {
departPostMap.put(item.getId(), departPostMap.get(item.getId()) + symbol + postName);
} else {
departPostMap.put(item.getId(), postName);
}
}
});
}
return departPostMap;
}
/**
* 根据用户ids获取部门名称
*
* @param userIdList
* @param symbol
* @return
*/
private Map<String, String> getDepartNamesByUserIds(List<String> userIdList, String symbol) {
Map<String, String> userOrgCodeMap = new HashMap<>();
if (CollectionUtil.isNotEmpty(userIdList)) {
List<SysUserSysDepPostModel> userDepPosts = sysUserDepartMapper.getUserDepPostByUserIds(userIdList);
if (CollectionUtil.isNotEmpty(userDepPosts)) {
ISysDepartService service = SpringContextUtils.getBean(SysDepartServiceImpl.class);
userDepPosts.forEach(item -> {
if (oConvertUtils.isNotEmpty(item.getId()) && oConvertUtils.isNotEmpty(item.getOrgCode())) {
String departNamePath = service.getDepartPathNameByOrgCode(item.getOrgCode(), "");
if (userOrgCodeMap.containsKey(item.getId())) {
userOrgCodeMap.put(item.getId(), userOrgCodeMap.get(item.getId()) + symbol + departNamePath);
} else {
userOrgCodeMap.put(item.getId(), departNamePath);
}
}
});
}
}
return userOrgCodeMap;
}
}

View File

@ -91,7 +91,19 @@ public class SysUserTenantServiceImpl extends ServiceImpl<SysUserTenantMapper, S
@Override
public List<SysUserTenantVo> getTenantListByUserId(String userId, List<String> userTenantStatus) {
return userTenantMapper.getTenantListByUserId(userId, userTenantStatus);
List<SysUserTenantVo> tenantListByUserId = userTenantMapper.getTenantListByUserId(userId, userTenantStatus);
// 代码逻辑说明: 【QQYUN-7283】1.已经是会员的租户,不是管理员时,没有购买按钮---
String noVip = "default";
tenantListByUserId.forEach((item) ->{
if(oConvertUtils.isNotEmpty(item.getMemberType()) && !noVip.equals(item.getMemberType())){
//查询是不是管理员
Long count = packUserMapper.izHaveBuyAuth(item.getId(), Integer.valueOf(item.getTenantUserId()));
if(count!=0){
item.setTenantAdmin(true);
}
}
});
return tenantListByUserId;
}
@Override

View File

@ -87,13 +87,12 @@ public class ThirdAppDingtalkServiceImpl implements IThirdAppService {
@Override
public String getAccessToken() {
//update-begin---author:wangshuai ---date:20230224 for[QQYUN-3440]新建企业微信和钉钉配置表,通过租户模式隔离------------
// 代码逻辑说明: [QQYUN-3440]新建企业微信和钉钉配置表,通过租户模式隔离------------
SysThirdAppConfig config = getDingThirdAppConfig();
if(null != config){
return getTenantAccessToken(config);
}
log.warn("租户下未配置钉钉");
//update-end---author:wangshuai ---date:20230224 for[QQYUN-3440]新建企业微信和钉钉配置表,通过租户模式隔离------------
return null;
}
@ -229,9 +228,8 @@ public class ThirdAppDingtalkServiceImpl implements IThirdAppService {
for (JdtDepartmentTreeVo departmentTree : departmentTreeList) {
LambdaQueryWrapper<SysDepart> queryWrapper = new LambdaQueryWrapper<>();
// 根据 source_identifier 字段查询
//update-begin---author:wangshuai---date:2024-04-10---for:【issues/6017】钉钉同步部门时没有最顶层的部门名同步用户时用户没有部门信息---
// 代码逻辑说明: 【issues/6017】钉钉同步部门时没有最顶层的部门名同步用户时用户没有部门信息---
queryWrapper.and(item -> item.eq(SysDepart::getId, departmentTree.getSource_identifier()).or().eq(SysDepart::getDingIdentifier,departmentTree.getDept_id()));
//update-end---author:wangshuai---date:2024-04-10---for:【issues/6017】钉钉同步部门时没有最顶层的部门名同步用户时用户没有部门信息---
SysDepart sysDepart = sysDepartService.getOne(queryWrapper);
if (sysDepart != null) {
// 执行更新操作
@ -580,14 +578,12 @@ public class ThirdAppDingtalkServiceImpl implements IThirdAppService {
user.setTelephone(sysUser.getTelephone());
user.setJob_number(sysUser.getWorkNo());
// 职务翻译
//update-begin---author:wangshuai ---date:20230220 for[QQYUN-3980]组织管理中 职位功能 职位表加租户id 加职位-用户关联表------------
//获取用户职位名称
List<SysPosition> positionList = sysPositionService.getPositionList(sysUser.getId());
if(null != positionList && positionList.size()>0){
String positionName = positionList.stream().map(SysPosition::getName).collect(Collectors.joining(SymbolConstant.COMMA));
user.setTitle(positionName);
}
//update-end---author:wangshuai ---date:20230220 for[QQYUN-3980]组织管理中 职位功能 职位表加租户id 加职位-用户关联表------------
user.setEmail(sysUser.getEmail());
// 查询并同步用户部门关系
List<SysDepart> departList = this.getUserDepart(sysUser);
@ -636,9 +632,9 @@ public class ThirdAppDingtalkServiceImpl implements IThirdAppService {
String passwordEncode = PasswordUtil.encrypt(sysUser.getUsername(), password, salt);
sysUser.setSalt(salt);
sysUser.setPassword(passwordEncode);
// update-begin--Author:liusq Date:20210713 for钉钉同步到本地的人员没有状态,导致同步之后无法登录 #I3ZC2L
// 代码逻辑说明: 钉钉同步到本地的人员没有状态,导致同步之后无法登录 #I3ZC2L
sysUser.setStatus(1);
// update-end--Author:liusq Date:20210713 for钉钉同步到本地的人员没有状态导致同步之后无法登录 #I3ZC2L
sysUser.setLastPwdUpdateTime(new Date());
return this.dtUserToSysUser(dtUser, sysUser);
}
@ -754,9 +750,8 @@ public class ThirdAppDingtalkServiceImpl implements IThirdAppService {
}
int count = 0;
if (userIdList != null && userIdList.size() > 0) {
//update-begin---author:wangshuai ---date:20230209 for[QQYUN-3440]新建企业微信和钉钉配置表,通过租户模式隔离------------
// 代码逻辑说明: [QQYUN-3440]新建企业微信和钉钉配置表,通过租户模式隔离------------
String accessToken = this.getTenantAccessToken(appConfig);
//update-end---author:wangshuai ---date:20230209 for[QQYUN-3440]新建企业微信和钉钉配置表,通过租户模式隔离------------
if (accessToken == null) {
return count;
}
@ -881,7 +876,7 @@ public class ThirdAppDingtalkServiceImpl implements IThirdAppService {
* @return
*/
public Response<JSONObject> recallMessageResponse(String msgTaskId) {
//update-begin---author:wangshuai ---date:20230224 for[QQYUN-3440]新建企业微信和钉钉配置表,通过租户模式隔离------------
// 代码逻辑说明: [QQYUN-3440]新建企业微信和钉钉配置表,通过租户模式隔离------------
SysThirdAppConfig config = this.getDingThirdAppConfig();
String accessToken = this.getTenantAccessToken(config);
if (accessToken == null) {
@ -889,7 +884,6 @@ public class ThirdAppDingtalkServiceImpl implements IThirdAppService {
}
String agentId = config.getAgentId();
return JdtMessageAPI.recallMessage(agentId, msgTaskId, accessToken);
//update-end---author:wangshuai ---date:20230224 for[QQYUN-3440]新建企业微信和钉钉配置表,通过租户模式隔离------------
}
/**
@ -901,7 +895,7 @@ public class ThirdAppDingtalkServiceImpl implements IThirdAppService {
* @return
*/
public Response<String> sendActionCardMessage(SysAnnouncement announcement, String ddMobileUrl, boolean verifyConfig) {
//update-begin---author:wangshuai ---date:20230224 for[QQYUN-3440]新建企业微信和钉钉配置表,通过租户模式隔离------------
// 代码逻辑说明: [QQYUN-3440]新建企业微信和钉钉配置表,通过租户模式隔离------------
SysThirdAppConfig config = this.getDingThirdAppConfig();
if (verifyConfig && null == config) {
return null;
@ -911,7 +905,6 @@ public class ThirdAppDingtalkServiceImpl implements IThirdAppService {
return null;
}
String agentId = config.getAgentId();
//update-end---author:wangshuai ---date:20230224 for[QQYUN-3440]新建企业微信和钉钉配置表,通过租户模式隔离------------
String emptySuffix = null;
if (oConvertUtils.isNotEmpty(announcement.getMsgAbstract())) {
String msgAbstract = announcement.getMsgAbstract().trim();
@ -991,9 +984,8 @@ public class ThirdAppDingtalkServiceImpl implements IThirdAppService {
*/
public SysUser oauth2Login(String authCode,Integer tenantId) {
this.tenantIzExist(tenantId);
//update-begin---author:wangshuai ---date:20230224 for[QQYUN-3440]新建企业微信和钉钉配置表,通过租户模式隔离------------
// 代码逻辑说明: [QQYUN-3440]新建企业微信和钉钉配置表,通过租户模式隔离------------
SysThirdAppConfig dtConfig = configMapper.getThirdConfigByThirdType(tenantId, MessageTypeEnum.DD.getType());
//update-end---author:wangshuai ---date:20230224 for[QQYUN-3440]新建企业微信和钉钉配置表,通过租户模式隔离------------
// 1. 根据免登授权码获取用户 AccessToken
String userAccessToken = JdtOauth2API.getUserAccessToken(dtConfig.getClientId(), dtConfig.getClientSecret(), authCode);
if (userAccessToken == null) {
@ -1025,19 +1017,17 @@ public class ThirdAppDingtalkServiceImpl implements IThirdAppService {
LambdaQueryWrapper<SysThirdAccount> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(SysThirdAccount::getThirdType, THIRD_TYPE);
queryWrapper.eq(SysThirdAccount::getTenantId, tenantId);
//update-begin---author:wangshuai---date:2023-12-04---for: auth登录需要联查一下---
// 代码逻辑说明: auth登录需要联查一下---
queryWrapper.and((wrapper)->wrapper.eq(SysThirdAccount::getThirdUserUuid,appUserId).or().eq(SysThirdAccount::getThirdUserId,appUserId));
//update-end---author:wangshuai---date:2023-12-04---for: auth登录需要联查一下---
SysThirdAccount thirdAccount = sysThirdAccountService.getOne(queryWrapper);
if (thirdAccount != null) {
return this.getSysUserByThird(thirdAccount, null, appUserId, accessToken,tenantId);
} else {
// 直接创建新账号
User appUser = JdtUserAPI.getUserById(appUserId, accessToken).getResult();
//update-begin---author:wangshuai ---date:20230328 for[QQYUN-4883]钉钉auth登录同一个租户下有同一个用户id------------
//代码逻辑说明: [QQYUN-4883]钉钉auth登录同一个租户下有同一个用户id------------
//应该存uuid
ThirdLoginModel tlm = new ThirdLoginModel(THIRD_TYPE, appUser.getUnionid(), appUser.getName(), appUser.getAvatar());
//update-end---author:wangshuai ---date:20230328 for[QQYUN-4883]钉钉auth登录同一个租户下有同一个用户id------------
thirdAccount = sysThirdAccountService.saveThirdUser(tlm,tenantId);
return this.getSysUserByThird(thirdAccount, appUser, null, null,tenantId);
}
@ -1070,9 +1060,8 @@ public class ThirdAppDingtalkServiceImpl implements IThirdAppService {
thirdAccount.setAvatar(appUser.getAvatar());
thirdAccount.setRealname(appUser.getName());
thirdAccount.setThirdUserId(appUser.getUserid());
//update-begin---author:wangshuai ---date:20230328 for[QQYUN-4883]钉钉auth登录同一个租户下有同一个用户id------------
// 代码逻辑说明: [QQYUN-4883]钉钉auth登录同一个租户下有同一个用户id------------
thirdAccount.setThirdUserUuid(appUser.getUnionid());
//update-end---author:wangshuai ---date:20230328 for[QQYUN-4883]钉钉auth登录同一个租户下有同一个用户id------------
thirdAccount.setSysUserId(sysUser.getId());
sysThirdAccountService.updateById(thirdAccount);
return sysUser;
@ -1147,11 +1136,10 @@ public class ThirdAppDingtalkServiceImpl implements IThirdAppService {
}
// 获取【钉钉】所有的部门
List<Department> departments = JdtDepartmentAPI.listAll(accessToken);
//update-begin---author:wangshuai---date:2024-06-25---for:【TV360X-1316】钉钉同步提示消息不正确---
// 代码逻辑说明: 【TV360X-1316】钉钉同步提示消息不正确---
if(departments.isEmpty()){
throw new JeecgBootBizTipException("请查看配置参数和白名单是否配置!");
}
//update-end---author:wangshuai---date:2024-06-25---for:【TV360X-1316】钉钉同步提示消息不正确---
String username = JwtUtil.getUserNameByToken(SpringContextUtils.getHttpServletRequest());
List<JdtDepartmentTreeVo> departmentTreeList = JdtDepartmentTreeVo.listToTree(departments);
int tenantId = oConvertUtils.getInt(TenantContext.getTenant(), 0);
@ -1187,11 +1175,10 @@ public class ThirdAppDingtalkServiceImpl implements IThirdAppService {
try {
userMapper.updateById(updateSysUser);
String str = String.format("用户 %s(%s) 更新成功!", updateSysUser.getRealname(), updateSysUser.getUsername());
//update-begin---author:wangshuai---date:2024-06-24---for:【TV360X-1317】钉钉同步 同步成功之后 重复提示---
// 代码逻辑说明: 【TV360X-1317】钉钉同步 同步成功之后 重复提示---
if(!syncInfo.getSuccessInfo().contains(str)){
syncInfo.addSuccessInfo(str);
}
//update-end---author:wangshuai---date:2024-06-24---for:【TV360X-1317】钉钉同步 同步成功之后 重复提示---
} catch (Exception e) {
this.syncUserCollectErrInfo(e, user, syncInfo);
}

View File

@ -103,11 +103,10 @@ public class ThirdAppWechatEnterpriseServiceImpl implements IThirdAppService {
@Override
public String getAccessToken() {
//update-begin---author:wangshuai ---date:20230224 for[QQYUN-3440]新建企业微信和钉钉配置表,通过租户模式隔离------------
// 代码逻辑说明: [QQYUN-3440]新建企业微信和钉钉配置表,通过租户模式隔离------------
SysThirdAppConfig config = this.getWeChatThirdAppConfig();
String corpId = config.getClientId();
String secret = config.getClientSecret();
//update-end---author:wangshuai ---date:20230224 for[QQYUN-3440]新建企业微信和钉钉配置表,通过租户模式隔离------------
AccessToken accessToken = JwAccessTokenAPI.getAccessToken(corpId, secret);
if (accessToken != null) {
return accessToken.getAccesstoken();
@ -118,11 +117,10 @@ public class ThirdAppWechatEnterpriseServiceImpl implements IThirdAppService {
/** 获取APPToken新版企业微信的秘钥是分开的 */
public String getAppAccessToken(SysThirdAppConfig config) {
//update-begin---author:wangshuai ---date:20230224 for[QQYUN-3440]新建企业微信和钉钉配置表,通过租户模式隔离------------
// 代码逻辑说明: [QQYUN-3440]新建企业微信和钉钉配置表,通过租户模式隔离------------
String corpId = config.getClientId();
// 如果没有配置APP秘钥就说明是老企业可以通用秘钥
String secret = config.getClientSecret();
//update-end---author:wangshuai ---date:20230224 for[QQYUN-3440]新建企业微信和钉钉配置表,通过租户模式隔离------------
AccessToken accessToken = JwAccessTokenAPI.getAccessToken(corpId, secret);
if (accessToken != null) {
@ -282,9 +280,8 @@ public class ThirdAppWechatEnterpriseServiceImpl implements IThirdAppService {
if (sysDepart != null) {
// 执行更新操作
SysDepart updateSysDepart = this.qwDepartmentToSysDepart(departmentTree, sysDepart);
//update-begin---author:wangshuai---date:2024-04-10---for:【issues/6017】企业微信同步部门时没有最顶层的部门名同步用户时用户没有部门信息---
// 代码逻辑说明: 【issues/6017】企业微信同步部门时没有最顶层的部门名同步用户时用户没有部门信息---
if (sysParentId != null && !"0".equals(sysParentId)) {
//update-end---author:wangshuai---date:2024-04-10---for:【issues/6017】企业微信同步部门时没有最顶层的部门名同步用户时用户没有部门信息---
updateSysDepart.setParentId(sysParentId);
}
try {
@ -601,13 +598,12 @@ public class ThirdAppWechatEnterpriseServiceImpl implements IThirdAppService {
user.setIs_leader_in_dept(new Integer[]{0});
}
// 职务翻译
//update-begin---author:wangshuai ---date:20230220 for[QQYUN-3980]组织管理中 职位功能 职位表加租户id 加职位-用户关联表------------
// 代码逻辑说明: [QQYUN-3980]组织管理中 职位功能 职位表加租户id 加职位-用户关联表------------
List<SysPosition> positionList = sysPositionService.getPositionList(sysUser.getId());
if(null != positionList && positionList.size()>0){
String positionName = positionList.stream().map(SysPosition::getName).collect(Collectors.joining(SymbolConstant.COMMA));
user.setPosition(positionName);
}
//update-end---author:wangshuai ---date:20230220 for[QQYUN-3980]组织管理中 职位功能 职位表加租户id 加职位-用户关联表------------
if (sysUser.getSex() != null) {
user.setGender(sysUser.getSex().toString());
}
@ -625,11 +621,10 @@ public class ThirdAppWechatEnterpriseServiceImpl implements IThirdAppService {
// 座机号
user.setTelephone(sysUser.getTelephone());
// --- 企业微信没有逻辑删除的功能
// update-begin--Author:sunjianlei Date:20210520 for本地逻辑删除的用户,在企业微信里禁用 -----
// 代码逻辑说明: 本地逻辑删除的用户,在企业微信里禁用 -----
if (CommonConstant.DEL_FLAG_1.equals(sysUser.getDelFlag())) {
user.setEnable(0);
}
// update-end--Author:sunjianlei Date:20210520 for本地逻辑删除的用户在企业微信里冻结 -----
return user;
}
@ -893,7 +888,6 @@ public class ThirdAppWechatEnterpriseServiceImpl implements IThirdAppService {
entity.setDescription(oConvertUtils.getString(announcement.getMsgAbstract(),""));
entity.setUrl(geQywxtAnnouncementUrl(announcement));
}
//update-end---author:scott ---date::2025-08-05 for【QQYUN-13257】【h5】催办、抄送消息在企业微信中显示json乱码---
textCard.setTextcard(entity);
return JwMessageAPI.sendTextCardMessage(textCard, accessToken);
@ -963,10 +957,9 @@ public class ThirdAppWechatEnterpriseServiceImpl implements IThirdAppService {
if(ObjectUtil.isEmpty(count) || 0 == count){
throw new JeecgBootException("租户不存在!");
}
//update-begin---author:wangshuai ---date:20230224 for[QQYUN-3440]新建企业微信和钉钉配置表,通过租户模式隔离------------
// 代码逻辑说明: [QQYUN-3440]新建企业微信和钉钉配置表,通过租户模式隔离------------
SysThirdAppConfig config = configMapper.getThirdConfigByThirdType(tenantId, MessageTypeEnum.QYWX.getType());
String accessToken = this.getAppAccessToken(config);
//update-end---author:wangshuai ---date:20230224 for[QQYUN-3440]新建企业微信和钉钉配置表,通过租户模式隔离------------
if (accessToken == null) {
return null;
}

View File

@ -0,0 +1,96 @@
package org.jeecg.modules.system.util;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileItemFactory;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.jeecg.common.util.MyCommonsMultipartFile;
import org.springframework.web.multipart.MultipartFile;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
/**
* @Description: http文件转MultipartFile
* @author: wangshuai
* @date: 2025/11/5 17:55
*/
public class HttpFileToMultipartFileUtil {
/**
* 获取
*
* @param fileUrl
* @param filename
* @return
* @throws Exception
*/
public static MultipartFile httpFileToMultipartFile(String fileUrl, String filename) throws Exception {
byte[] bytes = downloadImageData(fileUrl);
return convertByteToMultipartFile(bytes, filename);
}
/**
* 下载图片数据
*/
private static byte[] downloadImageData(String fileUrl) throws IOException {
URL url = new URL(fileUrl);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET");
connection.setConnectTimeout(5000);
connection.setReadTimeout(10000);
connection.setRequestProperty("User-Agent",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36");
connection.setRequestProperty("Accept", "image/*");
int responseCode = connection.getResponseCode();
if (responseCode != HttpURLConnection.HTTP_OK) {
throw new IOException("HTTP请求失败响应码: " + responseCode);
}
try (InputStream inputStream = connection.getInputStream();
ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
byte[] buffer = new byte[4096];
int bytesRead;
while ((bytesRead = inputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, bytesRead);
}
return outputStream.toByteArray();
} finally {
connection.disconnect();
}
}
/**
* byte转 MultipartFile
*
* @param data
* @param fileName
* @return
*/
private static MultipartFile convertByteToMultipartFile(byte[] data, String fileName) {
FileItemFactory factory = new DiskFileItemFactory();
FileItem item = factory.createItem(fileName, "application/octet-stream", true, fileName);
try (OutputStream os = item.getOutputStream();
ByteArrayInputStream bis = new ByteArrayInputStream(data)) {
byte[] buffer = new byte[8192];
int bytesRead;
while ((bytesRead = bis.read(buffer)) != -1) {
os.write(buffer, 0, bytesRead);
}
} catch (IOException e) {
throw new RuntimeException("字节数组转换失败", e);
}
try {
return new MyCommonsMultipartFile(item);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}

View File

@ -13,142 +13,291 @@ import java.util.Random;
/**
* 登录验证码工具类
* @author: jeecg-boot
* @date 2025-09-11
* @author AI优化
*/
public class RandImageUtil {
// 静态初始化块,解决无头环境字体配置问题
static {
System.setProperty("java.awt.headless", "true");
}
public static final String KEY = "JEECG_LOGIN_KEY";
/**
* 定义图形大小
*/
/** 验证码图片宽度 */
private static final int WIDTH = 105;
/**
* 定义图形大小
*/
/** 验证码图片高度 */
private static final int HEIGHT = 35;
/**
* 定义干扰线数量
*/
private static final int COUNT = 200;
/**
* 干扰线的长度=1.414*lineWidth
*/
/** 干扰线数量 */
private static final int INTERFERENCE_LINE_COUNT = 200;
/** 干扰线宽度 */
private static final int LINE_WIDTH = 2;
/**
* 图片格式
*/
/** 图片格式 */
private static final String IMG_FORMAT = "JPEG";
/** base64 图片前缀 */
private static final String BASE64_PREFIX = "data:image/jpg;base64,";
/** 字符间距 */
private static final int CHAR_SPACING = 23;
/** 字体大小 */
private static final int FONT_SIZE = 24;
/** 字符Y轴偏移 */
private static final int CHAR_Y_OFFSET = 26;
/** 字符X轴起始偏移 */
private static final int CHAR_X_OFFSET = 8;
/**
* base64 图片前缀
* 直接通过response输出验证码图片
*
* @param response HTTP响应对象
* @param verifyCode 验证码字符串
* @throws IOException 输出异常
*/
private static final String BASE64_PRE = "data:image/jpg;base64,";
/**
* 直接通过response 返回图片
* @param response
* @param resultCode
* @throws IOException
*/
public static void generate(HttpServletResponse response, String resultCode) throws IOException {
BufferedImage image = getImageBuffer(resultCode);
// 输出图象到页面
ImageIO.write(image, IMG_FORMAT, response.getOutputStream());
}
/**
* 生成base64字符串
* @param resultCode
* @return
* @throws IOException
*/
public static String generate(String resultCode) throws IOException {
BufferedImage image = getImageBuffer(resultCode);
ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
//写入流中
ImageIO.write(image, IMG_FORMAT, byteStream);
//转换成字节
byte[] bytes = byteStream.toByteArray();
//转换成base64串
String base64 = Base64.getEncoder().encodeToString(bytes).trim();
//删除 \r\n
base64 = base64.replaceAll("\n", "").replaceAll("\r", "");
//写到指定位置
//ImageIO.write(bufferedImage, "png", new File(""));
return BASE64_PRE+base64;
}
private static BufferedImage getImageBuffer(String resultCode){
// 在内存中创建图象
final BufferedImage image = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB);
// 获取图形上下文
final Graphics2D graphics = (Graphics2D) image.getGraphics();
// 设定背景颜色
// ---1
graphics.setColor(Color.WHITE);
graphics.fillRect(0, 0, WIDTH, HEIGHT);
// 设定边框颜色
// graphics.setColor(getRandColor(100, 200)); // ---2
graphics.drawRect(0, 0, WIDTH - 1, HEIGHT - 1);
// SHA1PRNG是-种常用的随机数生成算法,处理弱随机数问题
SecureRandom random;
public static void generate(HttpServletResponse response, String verifyCode) throws IOException {
if (response == null || verifyCode == null || verifyCode.trim().isEmpty()) {
throw new IllegalArgumentException("参数不能为空");
}
try {
random = SecureRandom.getInstance("SHA1PRNG");
} catch (NoSuchAlgorithmException e) {
random = new SecureRandom();
BufferedImage image = createVerifyCodeImage(verifyCode);
ImageIO.write(image, IMG_FORMAT, response.getOutputStream());
} catch (Exception e) {
throw new IOException("生成验证码图片失败", e);
}
// 随机产生干扰线,使图象中的认证码不易被其它程序探测到
for (int i = 0; i < COUNT; i++) {
// ---3
graphics.setColor(getRandColor(150, 200));
}
// 保证画在边框之内
final int x = random.nextInt(WIDTH - LINE_WIDTH - 1) + 1;
final int y = random.nextInt(HEIGHT - LINE_WIDTH - 1) + 1;
final int xl = random.nextInt(LINE_WIDTH);
final int yl = random.nextInt(LINE_WIDTH);
graphics.drawLine(x, y, x + xl, y + yl);
/**
* 生成验证码的base64字符串
*
* @param verifyCode 验证码字符串
* @return base64编码的图片字符串
* @throws IOException 生成异常
*/
public static String generate(String verifyCode) throws IOException {
if (verifyCode == null || verifyCode.trim().isEmpty()) {
throw new IllegalArgumentException("验证码不能为空");
}
// 取随机产生的认证码
for (int i = 0; i < resultCode.length(); i++) {
// 将认证码显示到图象中,调用函数出来的颜色相同,可能是因为种子太接近,所以只能直接生成
// graphics.setColor(new Color(20 + random.nextInt(130), 20 + random
// .nextInt(130), 20 + random.nextInt(130)));
// 设置字体颜色
graphics.setColor(Color.BLACK);
// 设置字体样式
// graphics.setFont(new Font("Arial Black", Font.ITALIC, 18));
graphics.setFont(new Font("Times New Roman", Font.BOLD, 24));
// 设置字符,字符间距,上边距
graphics.drawString(String.valueOf(resultCode.charAt(i)), (23 * i) + 8, 26);
try {
BufferedImage image = createVerifyCodeImage(verifyCode);
try (ByteArrayOutputStream byteStream = new ByteArrayOutputStream()) {
ImageIO.write(image, IMG_FORMAT, byteStream);
byte[] bytes = byteStream.toByteArray();
String base64 = Base64.getEncoder().encodeToString(bytes).trim();
// 清理换行符
base64 = base64.replaceAll("[\r\n]", "");
return BASE64_PREFIX + base64;
}
} catch (Exception e) {
throw new IOException("生成验证码base64失败", e);
}
// 图象生效
graphics.dispose();
}
/**
* 创建验证码图像
*
* @param verifyCode 验证码字符串
* @return 验证码图像
*/
private static BufferedImage createVerifyCodeImage(String verifyCode) {
BufferedImage image = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB);
Graphics2D graphics = null;
try {
graphics = (Graphics2D) image.getGraphics();
// 设置图形渲染质量
setupRenderingHints(graphics);
// 绘制背景
drawBackground(graphics);
// 绘制边框
drawBorder(graphics);
// 获取安全的随机数生成器
SecureRandom random = createSecureRandom();
// 绘制干扰线
drawInterferenceLines(graphics, random);
// 绘制验证码字符
drawVerifyCodeText(graphics, verifyCode);
} catch (Exception e) {
// 如果绘制失败,创建简单的错误图像
return createErrorImage(verifyCode);
} finally {
if (graphics != null) {
graphics.dispose();
}
}
return image;
}
private static Color getRandColor(int fc, int bc) { // 取得给定范围随机颜色
final Random random = new Random();
int length = 255;
if (fc > length) {
fc = length;
}
if (bc > length) {
bc = length;
}
/**
* 设置图形渲染质量
*/
private static void setupRenderingHints(Graphics2D graphics) {
graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
graphics.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
graphics.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
}
final int r = fc + random.nextInt(bc - fc);
final int g = fc + random.nextInt(bc - fc);
final int b = fc + random.nextInt(bc - fc);
/**
* 绘制白色背景
*/
private static void drawBackground(Graphics2D graphics) {
graphics.setColor(Color.WHITE);
graphics.fillRect(0, 0, WIDTH, HEIGHT);
}
return new Color(r, g, b);
/**
* 绘制边框
*/
private static void drawBorder(Graphics2D graphics) {
graphics.setColor(Color.GRAY);
graphics.drawRect(0, 0, WIDTH - 1, HEIGHT - 1);
}
/**
* 创建安全的随机数生成器
*/
private static SecureRandom createSecureRandom() {
try {
return SecureRandom.getInstance("SHA1PRNG");
} catch (NoSuchAlgorithmException e) {
return new SecureRandom();
}
}
/**
* 绘制干扰线
*/
private static void drawInterferenceLines(Graphics2D graphics, SecureRandom random) {
for (int i = 0; i < INTERFERENCE_LINE_COUNT; i++) {
graphics.setColor(getRandomColor(150, 200, random));
// 确保干扰线在边框内
int x1 = random.nextInt(WIDTH - LINE_WIDTH - 1) + 1;
int y1 = random.nextInt(HEIGHT - LINE_WIDTH - 1) + 1;
int x2 = x1 + random.nextInt(LINE_WIDTH);
int y2 = y1 + random.nextInt(LINE_WIDTH);
graphics.drawLine(x1, y1, x2, y2);
}
}
/**
* 绘制验证码文本
*/
private static void drawVerifyCodeText(Graphics2D graphics, String verifyCode) {
graphics.setColor(Color.BLACK);
Font font = createSafeFont();
graphics.setFont(font);
for (int i = 0; i < verifyCode.length(); i++) {
char character = verifyCode.charAt(i);
int x = i * CHAR_SPACING + CHAR_X_OFFSET;
graphics.drawString(String.valueOf(character), x, CHAR_Y_OFFSET);
}
}
/**
* 创建安全的字体,避免字体配置问题
*/
private static Font createSafeFont() {
// 使用逻辑字体名称,在所有平台都可用
String[] safeFontNames = {Font.SERIF, Font.SANS_SERIF, Font.MONOSPACED, "Dialog"};
for (String fontName : safeFontNames) {
try {
Font font = new Font(fontName, Font.BOLD, FONT_SIZE);
if (font.getFamily() != null) {
return font;
}
} catch (Exception e) {
// 继续尝试下一个字体
}
}
// 最后的回退方案
return new Font(Font.MONOSPACED, Font.BOLD, FONT_SIZE);
}
/**
* 创建错误图像(当正常绘制失败时使用)
*/
private static BufferedImage createErrorImage(String verifyCode) {
BufferedImage errorImage = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB);
Graphics2D graphics = null;
try {
graphics = (Graphics2D) errorImage.getGraphics();
// 白色背景
graphics.setColor(Color.WHITE);
graphics.fillRect(0, 0, WIDTH, HEIGHT);
// 黑色边框
graphics.setColor(Color.BLACK);
graphics.drawRect(0, 0, WIDTH - 1, HEIGHT - 1);
// 尝试绘制验证码
try {
graphics.setFont(new Font(Font.MONOSPACED, Font.BOLD, 20));
graphics.setColor(Color.BLUE);
for (int i = 0; i < verifyCode.length(); i++) {
graphics.drawString(String.valueOf(verifyCode.charAt(i)),
i * CHAR_SPACING + CHAR_X_OFFSET, CHAR_Y_OFFSET);
}
} catch (Exception fontException) {
// 如果连基本字体都失败显示ERROR
graphics.setColor(Color.RED);
graphics.drawString("ERROR", 10, 20);
}
} finally {
if (graphics != null) {
graphics.dispose();
}
}
return errorImage;
}
/**
* 获取指定范围内的随机颜色
*
* @param minColorValue 最小颜色值
* @param maxColorValue 最大颜色值
* @param random 随机数生成器
* @return 随机颜色
*/
private static Color getRandomColor(int minColorValue, int maxColorValue, Random random) {
// 确保颜色值在有效范围内
int min = Math.max(0, Math.min(minColorValue, 255));
int max = Math.max(min, Math.min(maxColorValue, 255));
int range = max - min;
if (range == 0) {
return new Color(min, min, min);
}
int red = min + random.nextInt(range);
int green = min + random.nextInt(range);
int blue = min + random.nextInt(range);
return new Color(red, green, blue);
}
}

View File

@ -0,0 +1,32 @@
package org.jeecg.modules.system.vo;
import lombok.Data;
/**
* @Description: 部门修改替换类
*
* @author: wangshuai
* @date: 2025/9/28 18:52
*/
@Data
public class SysChangeDepartVo {
/**
* 最终停止的部门id
*/
private String dropId;
/**
* 拖拽的部门id
*/
private String dragId;
/**
* 拖拽位置(-1上方 1下方 0子级
*/
private Integer dropPosition;
/**
* 当前位置
*/
private Integer sort;
}

View File

@ -22,11 +22,9 @@ public class SysDepartUsersVO implements Serializable{
this.depId = depId;
this.userIdList = userIdList;
}
//update-begin--Author:kangxiaolin Date:20190908 for[512][部门管理]点击添加已有用户失败修复--------------------
public SysDepartUsersVO(){
}
//update-begin--Author:kangxiaolin Date:20190908 for[512][部门管理]点击添加已有用户失败修复--------------------
}

View File

@ -31,4 +31,9 @@ public class SysUserDepVo {
* 职级
*/
private String positionId;
/**
* 部门编码
*/
private String orgCode;
}

View File

@ -83,6 +83,12 @@ public class SysUserImportVo {
@Excel(name="主岗位",width = 15)
private String mainDepPostId;
/**
* 兼职岗位
*/
@Excel(name="兼职岗位",width = 15)
private String otherDepPostId;
/**
* 职级
*/

View File

@ -56,13 +56,12 @@ public class JdtDepartmentTreeVo extends Department {
department = departmentOptional.get();
}
getChildrenRecursion(treeList, allDepartment);
//update-begin---author:wangshuai---date:2024-04-10---for:【issues/6017】钉钉同步部门时没有最顶层的部门名同步用户时用户没有部门信息---
// 代码逻辑说明: 【issues/6017】钉钉同步部门时没有最顶层的部门名同步用户时用户没有部门信息---
JdtDepartmentTreeVo treeVo = new JdtDepartmentTreeVo(department);
treeVo.setChildren(treeList);
List<JdtDepartmentTreeVo> list = new ArrayList<>();
list.add(treeVo);
return list;
//update-end---author:wangshuai---date:2024-04-10---for:【issues/6017】钉钉同步部门时没有最顶层的部门名同步用户时用户没有部门信息---
}
private static List<JdtDepartmentTreeVo> getByParentId(Integer parentId, List<Department> allDepartment) {

View File

@ -56,13 +56,12 @@ public class JwDepartmentTreeVo extends Department {
department = departmentOptional.get();
}
getChildrenRecursion(treeList, allDepartment);
//update-begin---author:wangshuai---date:2024-04-10---for:【issues/6017】企业微信同步部门时没有最顶层的部门名同步用户时用户没有部门信息---
// 代码逻辑说明: 【issues/6017】企业微信同步部门时没有最顶层的部门名同步用户时用户没有部门信息---
JwDepartmentTreeVo treeVo = new JwDepartmentTreeVo(department);
treeVo.setChildren(treeList);
List<JwDepartmentTreeVo> list = new ArrayList<>();
list.add(treeVo);
return list;
//update-begin---author:wangshuai---date:2024-04-10---for:【issues/6017】企业微信部门时没有最顶层的部门名同步用户时用户没有部门信息---
}
private static List<JwDepartmentTreeVo> getByParentId(String parentId, List<Department> allDepartment) {

View File

@ -81,7 +81,7 @@
<#elseif po.classType=='cat_tree'>
<#assign need_category = true>
<j-category-select v-model:value="formData.${po.fieldName}" pcode="${po.dictField?default("")}" placeholder="请选择${po.filedComment}" <#if po.dictText?default("")?trim?length gt 1>back="${dashedToCamel(po.dictText)}"</#if> <#if po.readonly=='Y'>disabled</#if> @change="(value) => handleFormChange('${po.fieldName}', value)" allow-clear />
<#elseif po.fieldDbType=='int' || po.fieldDbType=='double' || po.fieldDbType=='BigDecimal'>
<#elseif po.fieldDbType=='int' || po.fieldDbType=='long' || po.fieldDbType=='double' || po.fieldDbType=='BigDecimal'>
<a-input-number v-model:value="formData.${po.fieldName}" placeholder="请输入${po.filedComment}" style="width: 100%" <#if po.readonly=='Y'>disabled</#if>/>
<#elseif po.classType=='file'>
<#assign need_upload = true>

View File

@ -74,7 +74,7 @@
<#else>
<#if query_field_no gt 1> </#if><a-input placeholder="请输入${po.filedComment}" v-model:value="queryParam.${po.fieldName}" allow-clear ></a-input>
</#if>
<#elseif po.fieldDbType=='int' || po.fieldDbType=='double' || po.fieldDbType=='BigDecimal'>
<#elseif po.fieldDbType=='int' || po.fieldDbType=='long' || po.fieldDbType=='double' || po.fieldDbType=='BigDecimal'>
<#if query_field_no gt 1> </#if><a-input-number placeholder="请输入${po.filedComment}" v-model:value="queryParam.${po.fieldName}"></a-input-number>
<#else>
<#if query_field_no gt 1> </#if><a-input placeholder="请输入${po.filedComment}" v-model:value="queryParam.${autoStringSuffixForModel(po)}" allow-clear ></a-input>

View File

@ -1,6 +1,6 @@
<#list columns as po>
<#if po.isShow == 'Y' && po.fieldName != 'id'>
<#if po.fieldDbType=='int' || po.fieldDbType=='double' || po.fieldDbType=='BigDecimal'>
<#if po.fieldDbType=='int' || po.fieldDbType=='long' || po.fieldDbType=='double' || po.fieldDbType=='BigDecimal'>
${po.fieldName}: <#if po.defaultVal??>${po.defaultVal}<#else>undefined</#if>,
<#elseif po.fieldDbType=='Blob'>
${po.fieldName}String: <#if po.defaultVal??>'${po.defaultVal}'<#else>''</#if>,

View File

@ -1,6 +1,6 @@
<#list columns as po>
<#if po.isShow == 'Y' && po.fieldName != 'id'>
<#if po.fieldDbType=='int' || po.fieldDbType=='double' || po.fieldDbType=='BigDecimal'>
<#if po.fieldDbType=='int' || po.fieldDbType=='long' || po.fieldDbType=='double' || po.fieldDbType=='BigDecimal'>
${po.fieldName}: <#if po.defaultVal??>${po.defaultVal}<#else>undefined</#if>,
<#elseif po.fieldDbType=='Blob'>
${po.fieldName}String: <#if po.defaultVal??>'${po.defaultVal}'<#else>''</#if>,

View File

@ -1,6 +1,6 @@
<#list sub.colums as po>
<#if po.isShow == 'Y' && po.fieldName != 'id'>
<#if po.fieldDbType=='int' || po.fieldDbType=='double' || po.fieldDbType=='BigDecimal'>
<#if po.fieldDbType=='int' || po.fieldDbType=='long' || po.fieldDbType=='double' || po.fieldDbType=='BigDecimal'>
${po.fieldName}: <#if po.defaultVal??>${po.defaultVal}<#else>undefined</#if>,
<#elseif po.fieldDbType=='Blob'>
${po.fieldName}String: <#if po.defaultVal??>'${po.defaultVal}'<#else>''</#if>,

Some files were not shown because too many files have changed in this diff Show More