“培训审批修改1105”
This commit is contained in:
1 parent
9af67076a1
commit
8a42f07cc5
13 files changed
+1349
-297
No files matched your search
@@ -12,10 +12,16 @@ server:
|
||||
# HTTP post内容的最大大小。当值为-1时,默认值为大小是无限的
|
||||
max-http-post-size: -1
|
||||
# 以下的配置会影响buffer,这些buffer会用于服务器连接的IO操作,有点类似netty的池化内存管理
|
||||
# 每块buffer的空间大小,越小的空间被利用越充分
|
||||
buffer-size: 512
|
||||
# 每块buffer的空间大小(标准配置:16KB,提升文件上传性能)
|
||||
buffer-size: 16384
|
||||
# 是否分配的直接内存
|
||||
direct-buffers: true
|
||||
# 请求处理超时时间(毫秒),0表示无限制,建议设置合理超时避免长时间阻塞
|
||||
no-request-timeout: 600000
|
||||
# 🔧 修复文件上传超时:阻塞写操作超时时间(毫秒),适用于大文件上传或慢网络环境
|
||||
options:
|
||||
# 阻塞写操作超时时间设置为10分钟,避免上传大文件时触发默认300秒超时
|
||||
blocking-write-timeout: 600000
|
||||
threads:
|
||||
# 设置IO线程数, 它主要执行非阻塞的任务,它们会负责多个连接, 默认设置每个CPU核心一个线程
|
||||
io: 8
|
||||
@@ -75,10 +81,16 @@ spring:
|
||||
# 文件上传
|
||||
servlet:
|
||||
multipart:
|
||||
# 是否启用文件上传
|
||||
enabled: true
|
||||
# 单个文件大小
|
||||
max-file-size: 10MB
|
||||
# 设置总上传的文件大小
|
||||
max-request-size: 20MB
|
||||
# 上传文件的临时目录
|
||||
location: ${java.io.tmpdir}
|
||||
# 文件大小阈值,超过该阈值将写入磁盘而非内存(0表示始终写入磁盘)
|
||||
file-size-threshold: 0
|
||||
mvc:
|
||||
# 设置静态资源路径 防止所有请求都去查静态资源
|
||||
static-path-pattern: /static/**
|
||||
|
||||
+24
-21
@@ -21,6 +21,8 @@ import software.amazon.awssdk.regions.Region;
|
||||
import software.amazon.awssdk.services.s3.S3AsyncClient;
|
||||
import software.amazon.awssdk.services.s3.S3Configuration;
|
||||
import software.amazon.awssdk.services.s3.model.GetObjectResponse;
|
||||
import software.amazon.awssdk.services.s3.model.PutObjectRequest;
|
||||
import software.amazon.awssdk.services.s3.model.PutObjectResponse;
|
||||
import software.amazon.awssdk.services.s3.presigner.S3Presigner;
|
||||
import software.amazon.awssdk.transfer.s3.S3TransferManager;
|
||||
import software.amazon.awssdk.transfer.s3.model.*;
|
||||
@@ -32,6 +34,7 @@ import java.net.URL;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.time.Duration;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
@@ -93,10 +96,10 @@ public class OssClient {
|
||||
.httpClient(NettyNioAsyncHttpClient.builder()
|
||||
// 🚀 优化:连接超时时间(60秒)
|
||||
.connectionTimeout(Duration.ofSeconds(60))
|
||||
// 🚀 优化:读取超时时间(300秒,适合大文件下载)
|
||||
.readTimeout(Duration.ofSeconds(300))
|
||||
// 🚀 优化:写入超时时间(300秒,适合大文件上传)
|
||||
.writeTimeout(Duration.ofSeconds(300))
|
||||
// 🚀 优化:读取超时时间(600秒,适合大文件下载和慢网络环境)
|
||||
.readTimeout(Duration.ofSeconds(600))
|
||||
// 🚀 优化:写入超时时间(600秒,适合大文件上传和慢网络环境)
|
||||
.writeTimeout(Duration.ofSeconds(600))
|
||||
.build())
|
||||
.build();
|
||||
|
||||
@@ -184,31 +187,31 @@ public class OssClient {
|
||||
inputStream = new ByteArrayInputStream(IoUtil.readBytes(inputStream));
|
||||
}
|
||||
try {
|
||||
// 创建异步请求体(length如果为空会报错)
|
||||
// 🔧 修复:创建异步请求体,设置超时时间为600秒(10分钟),适应慢网络环境
|
||||
BlockingInputStreamAsyncRequestBody body = BlockingInputStreamAsyncRequestBody.builder()
|
||||
.contentLength(length)
|
||||
.subscribeTimeout(Duration.ofSeconds(30))
|
||||
.subscribeTimeout(Duration.ofSeconds(600))
|
||||
.build();
|
||||
|
||||
// 使用 transferManager 进行上传
|
||||
Upload upload = transferManager.upload(
|
||||
x -> x.requestBody(body)
|
||||
.putObjectRequest(
|
||||
y -> y.bucket(properties.getBucketName())
|
||||
.key(key)
|
||||
.contentType(contentType)
|
||||
// 用于设置对象的访问控制列表(ACL)。不同云厂商对ACL的支持和实现方式有所不同,
|
||||
// 因此根据具体的云服务提供商,你可能需要进行不同的配置(自行开启,阿里云有acl权限配置,腾讯云没有acl权限配置)
|
||||
// .acl(getAccessPolicy().getObjectCannedACL())
|
||||
.build())
|
||||
.build());
|
||||
// 🔧 修复:构建上传请求对象
|
||||
PutObjectRequest putObjectRequest = PutObjectRequest.builder()
|
||||
.bucket(properties.getBucketName())
|
||||
.key(key)
|
||||
.contentType(contentType)
|
||||
// 用于设置对象的访问控制列表(ACL)。不同云厂商对ACL的支持和实现方式有所不同,
|
||||
// 因此根据具体的云服务提供商,你可能需要进行不同的配置(自行开启,阿里云有acl权限配置,腾讯云没有acl权限配置)
|
||||
// .acl(getAccessPolicy().getObjectCannedACL())
|
||||
.build();
|
||||
|
||||
// 将输入流写入请求体
|
||||
// 🔧 修复:先发起上传请求(重要!必须在writeInputStream之前)
|
||||
CompletableFuture<PutObjectResponse> future = client.putObject(putObjectRequest, body);
|
||||
|
||||
// 🔧 修复:在发起请求后立即写入数据流(正确顺序)
|
||||
body.writeInputStream(inputStream);
|
||||
|
||||
// 等待文件上传操作完成
|
||||
CompletedUpload uploadResult = upload.completionFuture().join();
|
||||
String eTag = uploadResult.response().eTag();
|
||||
PutObjectResponse response = future.join();
|
||||
String eTag = response.eTag();
|
||||
|
||||
// 提取上传结果中的 ETag,并构建一个自定义的 UploadResult 对象
|
||||
return UploadResult.builder().url(getUrl() + StringUtils.SLASH + key).filename(key).eTag(eTag).build();
|
||||
|
||||
+92
@@ -347,4 +347,96 @@ public class RsTrainingApplicationController extends BaseController {
|
||||
log.info("重新提交被拒绝的培训申请: applicationId={}", applicationId);
|
||||
return toAjax(trainingApplicationService.resubmitApplication(applicationId, application));
|
||||
}
|
||||
|
||||
// ========================================
|
||||
// 7级审批接口(OR模式权限)
|
||||
// ========================================
|
||||
|
||||
/**
|
||||
* 审批培训申请(7级审批制度)
|
||||
* 🔴 支持7级审批权限:满足任一级别权限即可访问接口,具体级别在Service层验证
|
||||
*
|
||||
* 审批级别:
|
||||
* - 第1级:部门负责人 (rs:training:approve1)
|
||||
* - 第2A级:教务处 (rs:training:approve2a) - 培训类型=教学
|
||||
* - 第2B级:学生处 (rs:training:approve2b) - 培训类型=德育
|
||||
* - 第3级:计划财务处 (rs:training:approve3)
|
||||
* - 第4级:人事处 (rs:training:approve4)
|
||||
* - 第5级:业务分管领导 (rs:training:approve5)
|
||||
* - 第6级:人事分管院领导 (rs:training:approve6)
|
||||
* - 第7级:院长 (rs:training:approve7) - 最终审批
|
||||
*/
|
||||
@SaCheckPermission(value = {
|
||||
"rs:training:approve", // 通用审批权限(超级管理员)
|
||||
"rs:training:approve1", // 第1级:部门负责人
|
||||
"rs:training:approve2a", // 第2A级:教务处
|
||||
"rs:training:approve2b", // 第2B级:学生处
|
||||
"rs:training:approve3", // 第3级:计划财务处
|
||||
"rs:training:approve4", // 第4级:人事处
|
||||
"rs:training:approve5", // 第5级:业务分管领导
|
||||
"rs:training:approve6", // 第6级:人事分管院领导
|
||||
"rs:training:approve7" // 第7级:院长
|
||||
}, mode = cn.dev33.satoken.annotation.SaMode.OR) // 🔴 关键:OR模式,满足任一权限即可通过
|
||||
@Log(title = "审批培训申请", businessType = BusinessType.UPDATE)
|
||||
@PostMapping("/approve")
|
||||
public R<Void> approve(@RequestBody java.util.Map<String, Object> request) {
|
||||
try {
|
||||
// 解析请求参数
|
||||
Long applicationId = Long.parseLong(request.get("applicationId").toString());
|
||||
String approvalStatus = request.get("approvalStatus").toString();
|
||||
String approvalOpinion = request.get("approvalOpinion") != null ? request.get("approvalOpinion").toString()
|
||||
: "";
|
||||
String approvalSignature = request.get("approvalSignature") != null
|
||||
? request.get("approvalSignature").toString()
|
||||
: "";
|
||||
|
||||
// 获取当前审批人信息
|
||||
Long approverId = LoginHelper.getUserId();
|
||||
String approverName = LoginHelper.getUsername();
|
||||
|
||||
log.info("审批培训申请 - 申请ID: {}, 审批人: {} ({}), 审批状态: {}",
|
||||
applicationId, approverName, approverId, approvalStatus);
|
||||
|
||||
// 调用Service层审批方法
|
||||
Boolean result = trainingApplicationService.approveApplication(
|
||||
applicationId, approverId, approverName,
|
||||
approvalStatus, approvalOpinion, approvalSignature);
|
||||
|
||||
return result ? R.ok() : R.fail("审批失败");
|
||||
} catch (Exception e) {
|
||||
log.error("审批培训申请失败: {}", e.getMessage(), e);
|
||||
return R.fail("审批失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询当前用户的待审批申请列表(动态权限方案 + 部门过滤)
|
||||
*
|
||||
* 权限说明:
|
||||
* - 第1级审批人:只能看到本部门员工的待审批申请
|
||||
* - 第2-7级审批人:可以看到全校的待审批申请
|
||||
*/
|
||||
@SaCheckPermission(value = {
|
||||
"rs:training:approve",
|
||||
"rs:training:approve1",
|
||||
"rs:training:approve2a",
|
||||
"rs:training:approve2b",
|
||||
"rs:training:approve3",
|
||||
"rs:training:approve4",
|
||||
"rs:training:approve5",
|
||||
"rs:training:approve6",
|
||||
"rs:training:approve7"
|
||||
}, mode = cn.dev33.satoken.annotation.SaMode.OR)
|
||||
@GetMapping("/pending")
|
||||
public R<List<RsTrainingApplication>> queryPending() {
|
||||
try {
|
||||
List<RsTrainingApplication> result = trainingApplicationService.queryPendingByCurrentUser();
|
||||
log.info("查询待审批申请 - 用户: {}, 待审批数量: {}",
|
||||
LoginHelper.getUsername(), result.size());
|
||||
return R.ok(result);
|
||||
} catch (Exception e) {
|
||||
log.error("查询待审批申请失败: {}", e.getMessage(), e);
|
||||
return R.fail("查询失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
+29
-7
@@ -51,6 +51,12 @@ public class RsTrainingApplication extends BaseEntity {
|
||||
*/
|
||||
private String userName;
|
||||
|
||||
/**
|
||||
* 申请人昵称(用户真实姓名,非数据库字段)
|
||||
*/
|
||||
@TableField(exist = false)
|
||||
private String nickName;
|
||||
|
||||
/**
|
||||
* 所属部门
|
||||
*/
|
||||
@@ -127,23 +133,23 @@ public class RsTrainingApplication extends BaseEntity {
|
||||
* 当前审批人
|
||||
*/
|
||||
private String currentApprover;
|
||||
|
||||
|
||||
/**
|
||||
* 培训地点
|
||||
*/
|
||||
private String location;
|
||||
|
||||
|
||||
/**
|
||||
* 学时
|
||||
*/
|
||||
private Integer duration;
|
||||
|
||||
|
||||
/**
|
||||
* 开始时间
|
||||
*/
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date startTime;
|
||||
|
||||
|
||||
/**
|
||||
* 结束时间
|
||||
*/
|
||||
@@ -154,7 +160,7 @@ public class RsTrainingApplication extends BaseEntity {
|
||||
* 租户ID
|
||||
*/
|
||||
private String tenantId;
|
||||
|
||||
|
||||
/**
|
||||
* 拒绝时间
|
||||
*/
|
||||
@@ -165,10 +171,26 @@ public class RsTrainingApplication extends BaseEntity {
|
||||
* 附件ID列表(逗号分隔)
|
||||
*/
|
||||
private String attachmentIds;
|
||||
|
||||
|
||||
/**
|
||||
* 当前审批级别(1-7,2a-教务处,2b-学生处)
|
||||
*/
|
||||
private String approvalLevel;
|
||||
|
||||
/**
|
||||
* 当前审批人ID
|
||||
*/
|
||||
private Long currentApproverId;
|
||||
|
||||
/**
|
||||
* 审批完成时间
|
||||
*/
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date approvalTime;
|
||||
|
||||
/**
|
||||
* 排除状态(查询时排除指定状态,不存储到数据库)
|
||||
*/
|
||||
@TableField(exist = false)
|
||||
private String excludeStatus;
|
||||
}
|
||||
}
|
||||
+33
-21
@@ -9,6 +9,7 @@ import org.dromara.common.mybatis.core.domain.BaseEntity;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 培训审批对象 rs_training_approval
|
||||
@@ -69,70 +70,81 @@ public class RsTrainingApproval extends BaseEntity {
|
||||
* 租户ID
|
||||
*/
|
||||
private String tenantId;
|
||||
|
||||
|
||||
/** 非数据库字段 - 审批记录列表显示 **/
|
||||
@TableField(exist = false)
|
||||
private String applicationUserName;
|
||||
|
||||
|
||||
@TableField(exist = false)
|
||||
private String courseTitle;
|
||||
|
||||
|
||||
/** 非数据库字段 - 审批记录详情显示 **/
|
||||
@TableField(exist = false)
|
||||
private String userName;
|
||||
|
||||
|
||||
@TableField(exist = false)
|
||||
private String department;
|
||||
|
||||
|
||||
@TableField(exist = false)
|
||||
private String currentTitle;
|
||||
|
||||
|
||||
@TableField(exist = false)
|
||||
private String currentPosition;
|
||||
|
||||
|
||||
@TableField(exist = false)
|
||||
@JsonFormat(pattern = "yyyy-MM-dd")
|
||||
private Date workStartTime;
|
||||
|
||||
|
||||
@TableField(exist = false)
|
||||
private String phone;
|
||||
|
||||
|
||||
@TableField(exist = false)
|
||||
private String organizerUnit;
|
||||
|
||||
|
||||
@TableField(exist = false)
|
||||
private String courseName;
|
||||
|
||||
|
||||
@TableField(exist = false)
|
||||
private String location;
|
||||
|
||||
|
||||
@TableField(exist = false)
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date startTime;
|
||||
|
||||
|
||||
@TableField(exist = false)
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date endTime;
|
||||
|
||||
|
||||
@TableField(exist = false)
|
||||
private String trainingType;
|
||||
|
||||
|
||||
@TableField(exist = false)
|
||||
private Double trainingFee;
|
||||
|
||||
|
||||
@TableField(exist = false)
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date applyTime;
|
||||
|
||||
|
||||
@TableField(exist = false)
|
||||
private String companions;
|
||||
|
||||
|
||||
@TableField(exist = false)
|
||||
private String trainingPurpose;
|
||||
|
||||
|
||||
@TableField(exist = false)
|
||||
private String reason;
|
||||
|
||||
|
||||
@TableField(exist = false)
|
||||
private String attachmentIds;
|
||||
}
|
||||
|
||||
/** 非数据库字段 - 权限过滤辅助字段 **/
|
||||
@TableField(exist = false)
|
||||
private Long applicantId; // 申请人ID(用于权限过滤)
|
||||
|
||||
@TableField(exist = false)
|
||||
private Long deptId; // 部门ID(用于部门权限过滤)
|
||||
|
||||
/** 🆕 新增:审批级别列表(用于多级审批过滤) **/
|
||||
@TableField(exist = false)
|
||||
private List<String> approvalLevels; // 审批级别列表,例如:["1", "4"]
|
||||
}
|
||||
+39
-15
@@ -17,10 +17,11 @@ public interface IRsTrainingApplicationService {
|
||||
* 查询培训申请列表
|
||||
*
|
||||
* @param application 培训申请
|
||||
* @param pageQuery 分页参数
|
||||
* @param pageQuery 分页参数
|
||||
* @return 培训申请分页列表
|
||||
*/
|
||||
TableDataInfo<RsTrainingApplication> selectPageRsTrainingApplicationList(RsTrainingApplication application, PageQuery pageQuery);
|
||||
TableDataInfo<RsTrainingApplication> selectPageRsTrainingApplicationList(RsTrainingApplication application,
|
||||
PageQuery pageQuery);
|
||||
|
||||
/**
|
||||
* 查询培训申请列表
|
||||
@@ -33,22 +34,24 @@ public interface IRsTrainingApplicationService {
|
||||
/**
|
||||
* 查询指定课程的培训申请列表
|
||||
*
|
||||
* @param courseId 课程ID
|
||||
* @param courseId 课程ID
|
||||
* @param application 培训申请
|
||||
* @param pageQuery 分页参数
|
||||
* @param pageQuery 分页参数
|
||||
* @return 培训申请分页列表
|
||||
*/
|
||||
TableDataInfo<RsTrainingApplication> selectPageApplicationsByCourse(Long courseId, RsTrainingApplication application, PageQuery pageQuery);
|
||||
|
||||
TableDataInfo<RsTrainingApplication> selectPageApplicationsByCourse(Long courseId,
|
||||
RsTrainingApplication application, PageQuery pageQuery);
|
||||
|
||||
/**
|
||||
* 查询我的培训申请列表
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @param userId 用户ID
|
||||
* @param application 培训申请
|
||||
* @param pageQuery 分页参数
|
||||
* @param pageQuery 分页参数
|
||||
* @return 培训申请分页列表
|
||||
*/
|
||||
TableDataInfo<RsTrainingApplication> selectPageMyApplications(Long userId, RsTrainingApplication application, PageQuery pageQuery);
|
||||
TableDataInfo<RsTrainingApplication> selectPageMyApplications(Long userId, RsTrainingApplication application,
|
||||
PageQuery pageQuery);
|
||||
|
||||
/**
|
||||
* 查询培训申请详细信息
|
||||
@@ -89,7 +92,7 @@ public interface IRsTrainingApplicationService {
|
||||
* @return 结果
|
||||
*/
|
||||
int deleteRsTrainingApplicationById(Long applicationId);
|
||||
|
||||
|
||||
/**
|
||||
* 取消培训申请
|
||||
*
|
||||
@@ -97,22 +100,43 @@ public interface IRsTrainingApplicationService {
|
||||
* @return 结果
|
||||
*/
|
||||
int cancelApplication(Long applicationId);
|
||||
|
||||
|
||||
/**
|
||||
* 更新申请状态
|
||||
*
|
||||
* @param applicationId 培训申请ID
|
||||
* @param status 状态
|
||||
* @param status 状态
|
||||
* @return 结果
|
||||
*/
|
||||
int updateApplicationStatus(Long applicationId, String status);
|
||||
|
||||
|
||||
/**
|
||||
* 重新提交已被拒绝的申请
|
||||
*
|
||||
* @param applicationId 培训申请ID
|
||||
* @param application 培训申请更新数据
|
||||
* @param application 培训申请更新数据
|
||||
* @return 结果
|
||||
*/
|
||||
int resubmitApplication(Long applicationId, RsTrainingApplication application);
|
||||
}
|
||||
|
||||
/**
|
||||
* 审批培训申请(7级审批)
|
||||
*
|
||||
* @param applicationId 申请ID
|
||||
* @param approverId 审批人ID
|
||||
* @param approverName 审批人姓名
|
||||
* @param approvalStatus 审批状态(1-通过,2-拒绝)
|
||||
* @param approvalOpinion 审批意见
|
||||
* @param approvalSignature 审批签字(base64格式)
|
||||
* @return 结果
|
||||
*/
|
||||
Boolean approveApplication(Long applicationId, Long approverId, String approverName,
|
||||
String approvalStatus, String approvalOpinion, String approvalSignature);
|
||||
|
||||
/**
|
||||
* 查询当前用户的待审批申请列表(动态权限方案 + 部门过滤)
|
||||
*
|
||||
* @return 待审批申请列表
|
||||
*/
|
||||
List<RsTrainingApplication> queryPendingByCurrentUser();
|
||||
}
|
||||
+510
-104
@@ -18,14 +18,21 @@ import org.dromara.rs.domain.RsTrainingRecord;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.dromara.rs.domain.RsTrainingApproval;
|
||||
import org.dromara.rs.mapper.RsTrainingApplicationMapper;
|
||||
import org.dromara.rs.mapper.RsTrainingApprovalMapper;
|
||||
import org.dromara.rs.service.IRsTrainingApplicationService;
|
||||
import org.dromara.rs.service.IRsTrainingRecordService;
|
||||
import org.dromara.system.domain.vo.SysUserVo;
|
||||
import org.dromara.system.service.ISysUserService;
|
||||
import org.dromara.common.core.exception.ServiceException;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
@@ -39,23 +46,30 @@ import java.util.List;
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class RsTrainingApplicationServiceImpl implements IRsTrainingApplicationService {
|
||||
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(RsTrainingApplicationServiceImpl.class);
|
||||
|
||||
|
||||
private final RsTrainingApplicationMapper trainingApplicationMapper;
|
||||
|
||||
|
||||
@Autowired
|
||||
private IRsTrainingRecordService trainingRecordService;
|
||||
|
||||
@Autowired
|
||||
private RsTrainingApprovalMapper approvalMapper;
|
||||
|
||||
@Autowired
|
||||
private ISysUserService userService;
|
||||
|
||||
/**
|
||||
* 查询培训申请列表
|
||||
*
|
||||
* @param application 培训申请
|
||||
* @param pageQuery 分页参数
|
||||
* @param pageQuery 分页参数
|
||||
* @return 培训申请分页列表
|
||||
*/
|
||||
@Override
|
||||
public TableDataInfo<RsTrainingApplication> selectPageRsTrainingApplicationList(RsTrainingApplication application, PageQuery pageQuery) {
|
||||
public TableDataInfo<RsTrainingApplication> selectPageRsTrainingApplicationList(RsTrainingApplication application,
|
||||
PageQuery pageQuery) {
|
||||
// 创建分页对象
|
||||
Page<RsTrainingApplication> page = pageQuery.build();
|
||||
// 获取分页参数
|
||||
@@ -68,7 +82,7 @@ public class RsTrainingApplicationServiceImpl implements IRsTrainingApplicationS
|
||||
if (application.getTenantId() == null || application.getTenantId().isEmpty()) {
|
||||
application.setTenantId(LoginHelper.getTenantId());
|
||||
}
|
||||
|
||||
|
||||
// ===== 业务逻辑层权限过滤 =====
|
||||
// 根据用户角色进行数据权限过滤
|
||||
if (!LoginHelper.isSuperAdmin()) {
|
||||
@@ -76,7 +90,7 @@ public class RsTrainingApplicationServiceImpl implements IRsTrainingApplicationS
|
||||
Long currentUserId = LoginHelper.getUserId();
|
||||
Long currentDeptId = LoginHelper.getDeptId();
|
||||
String username = LoginHelper.getUsername();
|
||||
|
||||
|
||||
// 检查用户角色并应用相应的数据过滤
|
||||
if (StpUtil.hasRole("rs-Applicant")) {
|
||||
// 申请人只能看到自己的申请
|
||||
@@ -92,24 +106,25 @@ public class RsTrainingApplicationServiceImpl implements IRsTrainingApplicationS
|
||||
application.setCreateBy(currentUserId);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 查询总数
|
||||
long total = trainingApplicationMapper.selectCount(buildQueryWrapper(application));
|
||||
|
||||
|
||||
// 使用自定义分页查询获取列表数据
|
||||
List<RsTrainingApplication> list = trainingApplicationMapper.selectRsTrainingApplicationListPage(application, offset, size);
|
||||
|
||||
List<RsTrainingApplication> list = trainingApplicationMapper.selectRsTrainingApplicationListPage(application,
|
||||
offset, size);
|
||||
|
||||
// 处理自定义培训课程的情况
|
||||
for (RsTrainingApplication app : list) {
|
||||
if (app.getCourseName() == null || app.getCourseName().isEmpty()) {
|
||||
app.setCourseName("自定义培训");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 构建分页对象
|
||||
page.setRecords(list);
|
||||
page.setTotal(total);
|
||||
|
||||
|
||||
return TableDataInfo.build(page);
|
||||
}
|
||||
|
||||
@@ -121,69 +136,133 @@ public class RsTrainingApplicationServiceImpl implements IRsTrainingApplicationS
|
||||
*/
|
||||
@Override
|
||||
public List<RsTrainingApplication> selectRsTrainingApplicationList(RsTrainingApplication application) {
|
||||
// ===== 业务逻辑层权限过滤 =====
|
||||
// 根据用户角色进行数据权限过滤
|
||||
log.info("🔍 ==================== 开始培训申请列表查询 ====================");
|
||||
log.info("🔍 当前登录用户ID: {}", LoginHelper.getUserId());
|
||||
log.info("🔍 是否超级管理员: {}", LoginHelper.isSuperAdmin());
|
||||
log.info("🔍 用户角色: rs-Applicant={}, rs-admin={}",
|
||||
StpUtil.hasRole("rs-Applicant"),
|
||||
StpUtil.hasRole("rs-admin"));
|
||||
|
||||
// ===== 审批权限过滤 =====
|
||||
if (!LoginHelper.isSuperAdmin()) {
|
||||
// 获取当前登录用户信息
|
||||
Long currentUserId = LoginHelper.getUserId();
|
||||
Long currentDeptId = LoginHelper.getDeptId();
|
||||
|
||||
// 检查用户角色并应用相应的数据过滤
|
||||
log.info("🔍 当前用户部门ID: {}", currentDeptId);
|
||||
|
||||
// 判断用户角色
|
||||
if (StpUtil.hasRole("rs-Applicant")) {
|
||||
// 申请人只能看到自己的申请
|
||||
application.setUserId(currentUserId);
|
||||
} else if (StpUtil.hasRole("rs-admin")) {
|
||||
// 人事管理员可以看到所有申请(包括审批和部门管理功能)
|
||||
// 不设置额外过滤条件,让管理员能看到所有申请
|
||||
// 人事管理员可以看到所有申请
|
||||
// 不设置额外过滤条件
|
||||
} else {
|
||||
// 默认情况:只能看到自己创建的申请
|
||||
application.setCreateBy(currentUserId);
|
||||
// 审批人权限过滤:根据审批级别权限过滤数据
|
||||
List<String> approvalLevels = getApprovalLevelsByUser(currentUserId);
|
||||
|
||||
if (approvalLevels.isEmpty()) {
|
||||
// 没有审批权限,只能看到自己创建的申请
|
||||
application.setCreateBy(currentUserId);
|
||||
} else {
|
||||
// 🔴 有审批权限,需要在数据库层面过滤
|
||||
// 这里需要在 Mapper XML 中添加审批权限的过滤逻辑
|
||||
// 暂时先在代码层面过滤
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 使用自定义的Mapper方法查询,已经关联了课程表获取课程名称
|
||||
|
||||
// 使用自定义的Mapper方法查询
|
||||
List<RsTrainingApplication> list = trainingApplicationMapper.selectRsTrainingApplicationList(application);
|
||||
|
||||
|
||||
// 🔴 在代码层面进行审批权限过滤(临时方案)
|
||||
log.info("🔍 准备进行审批权限过滤,查询到的数据总数: {}", list.size());
|
||||
|
||||
if (!LoginHelper.isSuperAdmin() &&
|
||||
!StpUtil.hasRole("rs-Applicant") &&
|
||||
!StpUtil.hasRole("rs-admin")) {
|
||||
|
||||
log.info("🔍 触发审批权限过滤逻辑(非超管、非申请人、非人事管理员)");
|
||||
|
||||
Long currentUserId = LoginHelper.getUserId();
|
||||
Long currentDeptId = LoginHelper.getDeptId();
|
||||
List<String> approvalLevels = getApprovalLevelsByUser(currentUserId);
|
||||
|
||||
log.info("🔍 当前用户可审批级别: {}", approvalLevels);
|
||||
|
||||
if (!approvalLevels.isEmpty()) {
|
||||
log.info("🔍 开始按审批级别过滤数据...");
|
||||
// 按审批权限过滤
|
||||
list = list.stream().filter(app -> {
|
||||
String appLevel = app.getApprovalLevel();
|
||||
if (appLevel == null)
|
||||
return false;
|
||||
|
||||
// 检查是否有该级别的审批权限
|
||||
if (!approvalLevels.contains(appLevel)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 第1-3级需要检查部门权限
|
||||
if (appLevel.equals("1") || appLevel.equals("2a") || appLevel.equals("2b")
|
||||
|| appLevel.equals("3")) {
|
||||
return app.getCreateDept() != null && app.getCreateDept().equals(currentDeptId);
|
||||
}
|
||||
|
||||
// 第4-7级可以跨部门审批
|
||||
return true;
|
||||
}).collect(java.util.stream.Collectors.toList());
|
||||
|
||||
log.info("🔍 审批权限过滤完成,过滤后数据数量: {}", list.size());
|
||||
} else {
|
||||
log.info("🔍 用户没有审批权限,不进行过滤");
|
||||
}
|
||||
} else {
|
||||
log.info("🔍 跳过审批权限过滤(超管/申请人/人事管理员)");
|
||||
}
|
||||
|
||||
// 处理自定义培训课程(courseId=0)的情况
|
||||
for (RsTrainingApplication app : list) {
|
||||
if (app.getCourseId() != null && app.getCourseId() == 0 && (app.getCourseName() == null || app.getCourseName().isEmpty())) {
|
||||
if (app.getCourseId() != null && app.getCourseId() == 0
|
||||
&& (app.getCourseName() == null || app.getCourseName().isEmpty())) {
|
||||
app.setCourseName("自定义培训");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询指定课程的培训申请列表
|
||||
*
|
||||
* @param courseId 课程ID
|
||||
* @param courseId 课程ID
|
||||
* @param application 培训申请
|
||||
* @param pageQuery 分页参数
|
||||
* @param pageQuery 分页参数
|
||||
* @return 培训申请分页列表
|
||||
*/
|
||||
@Override
|
||||
public TableDataInfo<RsTrainingApplication> selectPageApplicationsByCourse(Long courseId, RsTrainingApplication application, PageQuery pageQuery) {
|
||||
public TableDataInfo<RsTrainingApplication> selectPageApplicationsByCourse(Long courseId,
|
||||
RsTrainingApplication application, PageQuery pageQuery) {
|
||||
LambdaQueryWrapper<RsTrainingApplication> lqw = buildQueryWrapper(application);
|
||||
lqw.eq(RsTrainingApplication::getCourseId, courseId);
|
||||
return TableDataInfo.build(trainingApplicationMapper.selectPage(pageQuery.build(), lqw));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 查询我的培训申请列表
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @param userId 用户ID
|
||||
* @param application 培训申请
|
||||
* @param pageQuery 分页参数
|
||||
* @param pageQuery 分页参数
|
||||
* @return 培训申请分页列表
|
||||
*/
|
||||
@Override
|
||||
public TableDataInfo<RsTrainingApplication> selectPageMyApplications(Long userId, RsTrainingApplication application, PageQuery pageQuery) {
|
||||
public TableDataInfo<RsTrainingApplication> selectPageMyApplications(Long userId, RsTrainingApplication application,
|
||||
PageQuery pageQuery) {
|
||||
LambdaQueryWrapper<RsTrainingApplication> lqw = buildQueryWrapper(application);
|
||||
lqw.eq(RsTrainingApplication::getUserId, userId);
|
||||
return TableDataInfo.build(trainingApplicationMapper.selectPage(pageQuery.build(), lqw));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 构建查询条件
|
||||
*/
|
||||
@@ -200,9 +279,11 @@ public class RsTrainingApplicationServiceImpl implements IRsTrainingApplicationS
|
||||
lqw.like(application.getLocation() != null, RsTrainingApplication::getLocation, application.getLocation());
|
||||
lqw.eq(application.getDuration() != null, RsTrainingApplication::getDuration, application.getDuration());
|
||||
// 课程名称搜索:搜索自定义课程名称字段
|
||||
lqw.like(application.getCourseName() != null, RsTrainingApplication::getCourseName, application.getCourseName());
|
||||
lqw.like(application.getCourseName() != null, RsTrainingApplication::getCourseName,
|
||||
application.getCourseName());
|
||||
// 排除指定状态的条件(用于待审批接口)
|
||||
lqw.ne(application.getExcludeStatus() != null, RsTrainingApplication::getStatus, application.getExcludeStatus());
|
||||
lqw.ne(application.getExcludeStatus() != null, RsTrainingApplication::getStatus,
|
||||
application.getExcludeStatus());
|
||||
return lqw;
|
||||
}
|
||||
|
||||
@@ -216,15 +297,15 @@ public class RsTrainingApplicationServiceImpl implements IRsTrainingApplicationS
|
||||
public RsTrainingApplication selectRsTrainingApplicationById(Long applicationId) {
|
||||
// 使用自定义的Mapper方法查询,已经关联了课程表获取课程名称
|
||||
RsTrainingApplication application = trainingApplicationMapper.selectRsTrainingApplicationById(applicationId);
|
||||
|
||||
|
||||
// ===== 业务逻辑层权限过滤 =====
|
||||
// 检查当前用户是否有权限查看此申请
|
||||
if (application != null && !LoginHelper.isSuperAdmin()) {
|
||||
Long currentUserId = LoginHelper.getUserId();
|
||||
Long currentDeptId = LoginHelper.getDeptId();
|
||||
|
||||
|
||||
boolean hasPermission = false;
|
||||
|
||||
|
||||
// 检查用户角色权限
|
||||
if (StpUtil.hasRole("rs-Applicant")) {
|
||||
// 申请人只能查看自己的申请
|
||||
@@ -234,23 +315,23 @@ public class RsTrainingApplicationServiceImpl implements IRsTrainingApplicationS
|
||||
hasPermission = true;
|
||||
} else {
|
||||
// 默认情况:只能查看自己创建的申请
|
||||
hasPermission = application.getCreateBy() != null &&
|
||||
application.getCreateBy().equals(currentUserId);
|
||||
hasPermission = application.getCreateBy() != null &&
|
||||
application.getCreateBy().equals(currentUserId);
|
||||
}
|
||||
|
||||
|
||||
// 如果没有权限,返回null
|
||||
if (!hasPermission) {
|
||||
log.warn("用户 {} 尝试访问无权限的培训申请: {}", currentUserId, applicationId);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 处理自定义培训课程(courseId=0)的情况
|
||||
if (application != null && application.getCourseId() != null && application.getCourseId() == 0
|
||||
&& (application.getCourseName() == null || application.getCourseName().isEmpty())) {
|
||||
if (application != null && application.getCourseId() != null && application.getCourseId() == 0
|
||||
&& (application.getCourseName() == null || application.getCourseName().isEmpty())) {
|
||||
application.setCourseName("自定义培训");
|
||||
}
|
||||
|
||||
|
||||
return application;
|
||||
}
|
||||
|
||||
@@ -267,7 +348,7 @@ public class RsTrainingApplicationServiceImpl implements IRsTrainingApplicationS
|
||||
if (application.getApplicationId() == null) {
|
||||
application.setApplicationId(System.currentTimeMillis());
|
||||
}
|
||||
|
||||
|
||||
// 处理自定义培训课程的情况(courseId = 0 或 null)
|
||||
// 确保courseName不为空
|
||||
if (application.getCourseName() == null || application.getCourseName().isEmpty()) {
|
||||
@@ -277,9 +358,10 @@ public class RsTrainingApplicationServiceImpl implements IRsTrainingApplicationS
|
||||
application.setCreateTime(now);
|
||||
application.setApplyTime(now);
|
||||
application.setStatus("0"); // 待审核状态
|
||||
application.setApprovalLevel("1"); // 🔴 初始化为第1级审批(部门负责人)
|
||||
application.setTenantId(LoginHelper.getTenantId()); // 设置当前用户租户ID
|
||||
return trainingApplicationMapper.insert(application);
|
||||
|
||||
|
||||
// 以上代码已处理所有情况
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
@@ -308,13 +390,14 @@ public class RsTrainingApplicationServiceImpl implements IRsTrainingApplicationS
|
||||
@Override
|
||||
public int deleteRsTrainingApplicationByIds(Long[] applicationIds) {
|
||||
// 查询所有要删除的申请
|
||||
List<RsTrainingApplication> applications = trainingApplicationMapper.selectBatchIds(Arrays.asList(applicationIds));
|
||||
|
||||
List<RsTrainingApplication> applications = trainingApplicationMapper
|
||||
.selectBatchIds(Arrays.asList(applicationIds));
|
||||
|
||||
// 对每个申请,减少对应课程的当前报名人数
|
||||
for (RsTrainingApplication app : applications) {
|
||||
// 培训课程功能已移除,无需更新课程报名人数
|
||||
// 培训课程功能已移除,无需更新课程报名人数
|
||||
}
|
||||
|
||||
|
||||
return trainingApplicationMapper.deleteBatchIds(Arrays.asList(applicationIds));
|
||||
}
|
||||
|
||||
@@ -331,10 +414,10 @@ public class RsTrainingApplicationServiceImpl implements IRsTrainingApplicationS
|
||||
if (application != null) {
|
||||
// 培训课程功能已移除,无需更新课程报名人数
|
||||
}
|
||||
|
||||
|
||||
return trainingApplicationMapper.deleteById(applicationId);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 取消培训申请
|
||||
*
|
||||
@@ -348,40 +431,40 @@ public class RsTrainingApplicationServiceImpl implements IRsTrainingApplicationS
|
||||
if (application != null) {
|
||||
// 只有待审核状态的申请才能取消
|
||||
if ("0".equals(application.getStatus())) {
|
||||
// 更新状态为已取消
|
||||
application.setStatus("3");
|
||||
application.setUpdateTime(DateUtils.getNowDate());
|
||||
|
||||
// 培训课程功能已移除,无需更新课程报名人数
|
||||
|
||||
// 更新状态为已取消
|
||||
application.setStatus("3");
|
||||
application.setUpdateTime(DateUtils.getNowDate());
|
||||
|
||||
// 培训课程功能已移除,无需更新课程报名人数
|
||||
|
||||
return trainingApplicationMapper.updateById(application);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 更新申请状态
|
||||
*
|
||||
* @param applicationId 培训申请ID
|
||||
* @param status 状态
|
||||
* @param status 状态
|
||||
* @return 结果
|
||||
*/
|
||||
@Override
|
||||
public int updateApplicationStatus(Long applicationId, String status) {
|
||||
RsTrainingApplication application = trainingApplicationMapper.selectById(applicationId);
|
||||
if (application != null) {
|
||||
application.setStatus(status);
|
||||
Date now = DateUtils.getNowDate();
|
||||
application.setUpdateTime(now);
|
||||
|
||||
// 如果是拒绝,记录被拒绝时间
|
||||
if ("2".equals(status)) {
|
||||
application.setRejectTime(now);
|
||||
}
|
||||
|
||||
if (application != null) {
|
||||
application.setStatus(status);
|
||||
Date now = DateUtils.getNowDate();
|
||||
application.setUpdateTime(now);
|
||||
|
||||
// 如果是拒绝,记录被拒绝时间
|
||||
if ("2".equals(status)) {
|
||||
application.setRejectTime(now);
|
||||
}
|
||||
|
||||
int result = trainingApplicationMapper.updateById(application);
|
||||
|
||||
|
||||
// 如果申请通过,自动创建培训记录
|
||||
if ("1".equals(status)) {
|
||||
try {
|
||||
@@ -391,16 +474,16 @@ public class RsTrainingApplicationServiceImpl implements IRsTrainingApplicationS
|
||||
// 不影响申请状态更新的结果
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return result;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 重新提交已被拒绝的申请
|
||||
*
|
||||
* @param applicationId 培训申请ID
|
||||
* @param applicationId 培训申请ID
|
||||
* @param applicationData 培训申请更新数据
|
||||
* @return 结果
|
||||
*/
|
||||
@@ -411,14 +494,12 @@ public class RsTrainingApplicationServiceImpl implements IRsTrainingApplicationS
|
||||
if (existingApp == null) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// 只有状态为已拒绝的申请才能重新提交
|
||||
if (!"2".equals(existingApp.getStatus())) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// 更新申请数据
|
||||
if (applicationData.getReason() != null) {
|
||||
existingApp.setReason(applicationData.getReason());
|
||||
@@ -438,18 +519,17 @@ public class RsTrainingApplicationServiceImpl implements IRsTrainingApplicationS
|
||||
if (applicationData.getCourseName() != null) {
|
||||
existingApp.setCourseName(applicationData.getCourseName());
|
||||
}
|
||||
|
||||
// 重置为待审核状态
|
||||
existingApp.setStatus("0");
|
||||
Date now = DateUtils.getNowDate();
|
||||
existingApp.setUpdateTime(now);
|
||||
existingApp.setApplyTime(now); // 更新申请时间
|
||||
|
||||
|
||||
|
||||
|
||||
// 重置为待审核状态
|
||||
existingApp.setStatus("0");
|
||||
existingApp.setApprovalLevel("1"); // 🔴 重新提交时重置为第1级审批
|
||||
Date now = DateUtils.getNowDate();
|
||||
existingApp.setUpdateTime(now);
|
||||
existingApp.setApplyTime(now); // 更新申请时间
|
||||
|
||||
return trainingApplicationMapper.updateById(existingApp);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 根据培训申请创建培训记录
|
||||
*
|
||||
@@ -458,13 +538,14 @@ public class RsTrainingApplicationServiceImpl implements IRsTrainingApplicationS
|
||||
private void createTrainingRecordFromApplication(RsTrainingApplication application) {
|
||||
try {
|
||||
// 检查是否已存在培训记录
|
||||
RsTrainingRecord existingRecord = trainingRecordService.selectByApplicationId(application.getApplicationId());
|
||||
RsTrainingRecord existingRecord = trainingRecordService
|
||||
.selectByApplicationId(application.getApplicationId());
|
||||
if (existingRecord != null) {
|
||||
log.info("培训记录已存在,不重复创建: applicationId={}, recordId={}",
|
||||
application.getApplicationId(), existingRecord.getRecordId());
|
||||
log.info("培训记录已存在,不重复创建: applicationId={}, recordId={}",
|
||||
application.getApplicationId(), existingRecord.getRecordId());
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// 创建新的培训记录
|
||||
RsTrainingRecord record = new RsTrainingRecord();
|
||||
record.setApplicationId(application.getApplicationId());
|
||||
@@ -483,30 +564,355 @@ public class RsTrainingApplicationServiceImpl implements IRsTrainingApplicationS
|
||||
record.setStartTime(application.getStartTime());
|
||||
record.setEndTime(application.getEndTime());
|
||||
record.setCompletionStatus("0"); // 0=进行中
|
||||
|
||||
|
||||
// 设置基础字段 - 修复字段缺失问题
|
||||
Date now = DateUtils.getNowDate();
|
||||
record.setCreateTime(now);
|
||||
record.setUpdateTime(now);
|
||||
|
||||
|
||||
// 设置租户和用户信息
|
||||
record.setTenantId(application.getTenantId() != null ? application.getTenantId() : LoginHelper.getTenantId());
|
||||
record.setTenantId(
|
||||
application.getTenantId() != null ? application.getTenantId() : LoginHelper.getTenantId());
|
||||
record.setCreateBy(application.getUserId()); // 创建者设为申请人
|
||||
record.setUpdateBy(application.getUserId()); // 更新者设为申请人
|
||||
record.setCreateDept(application.getCreateDept() != null ? application.getCreateDept() : 1L); // 使用createDept,如果没有则设为默认值
|
||||
record.setDeptId(application.getCreateDept() != null ? application.getCreateDept() : 1L); // 设置部门ID
|
||||
|
||||
|
||||
int result = trainingRecordService.insertRsTrainingRecord(record);
|
||||
if (result > 0) {
|
||||
log.info("培训记录创建成功: applicationId={}, recordId={}",
|
||||
application.getApplicationId(), record.getRecordId());
|
||||
log.info("培训记录创建成功: applicationId={}, recordId={}",
|
||||
application.getApplicationId(), record.getRecordId());
|
||||
} else {
|
||||
log.error("培训记录创建失败: applicationId={}", application.getApplicationId());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("创建培训记录时发生异常: applicationId={}, error={}",
|
||||
application.getApplicationId(), e.getMessage(), e);
|
||||
log.error("创建培训记录时发生异常: applicationId={}, error={}",
|
||||
application.getApplicationId(), e.getMessage(), e);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ========================================
|
||||
// 7级审批核心逻辑(支持培训类型分流)
|
||||
// ========================================
|
||||
|
||||
/**
|
||||
* 审批培训申请(7级审批制度)
|
||||
*
|
||||
* @param applicationId 申请ID
|
||||
* @param approverId 审批人ID
|
||||
* @param approverName 审批人姓名
|
||||
* @param approvalStatus 审批状态(1-通过,2-拒绝)
|
||||
* @param approvalOpinion 审批意见
|
||||
* @param approvalSignature 审批签字(base64格式)
|
||||
* @return 结果
|
||||
*/
|
||||
@Override
|
||||
@Transactional
|
||||
public Boolean approveApplication(Long applicationId, Long approverId, String approverName,
|
||||
String approvalStatus, String approvalOpinion, String approvalSignature) {
|
||||
RsTrainingApplication application = trainingApplicationMapper.selectById(applicationId);
|
||||
if (application == null) {
|
||||
throw new RuntimeException("申请不存在");
|
||||
}
|
||||
if (!"0".equals(application.getStatus())) {
|
||||
throw new RuntimeException("只有待审核状态的申请才能审批");
|
||||
}
|
||||
|
||||
// 🔴 验证审批人权限级别
|
||||
String currentApprovalLevel = application.getApprovalLevel() != null ? application.getApprovalLevel() : "1";
|
||||
if (!validateApproverLevel(approverId, currentApprovalLevel)) {
|
||||
throw new ServiceException(String.format(
|
||||
"您没有第%s级审批权限,当前申请需要第%s级审批人审批",
|
||||
currentApprovalLevel, currentApprovalLevel));
|
||||
}
|
||||
log.info("✅ 审批人 {} 拥有第{}级审批权限验证通过", approverName, currentApprovalLevel);
|
||||
|
||||
// 创建审批记录
|
||||
RsTrainingApproval approval = new RsTrainingApproval();
|
||||
approval.setApplicationId(applicationId);
|
||||
approval.setApproverId(approverId);
|
||||
approval.setApproverName(approverName);
|
||||
approval.setApprovalLevel(Integer.parseInt(currentApprovalLevel.replaceAll("[^0-9]", ""))); // 转换为数字
|
||||
approval.setStatus(approvalStatus);
|
||||
approval.setOpinion(approvalOpinion);
|
||||
approval.setApprovalTime(new Date());
|
||||
|
||||
// 日志记录签字数据
|
||||
if (approvalSignature != null && !approvalSignature.trim().isEmpty()) {
|
||||
log.info("✅ 保存审批签字数据,长度: {} 字符", approvalSignature.length());
|
||||
} else {
|
||||
log.info("ℹ️ 未提供审批签字");
|
||||
}
|
||||
|
||||
// 手动设置多租户和删除标志字段
|
||||
if (approval.getTenantId() == null || approval.getTenantId().isEmpty()) {
|
||||
approval.setTenantId(LoginHelper.getTenantId());
|
||||
}
|
||||
|
||||
approvalMapper.insert(approval);
|
||||
|
||||
// 更新申请状态(7级审批流转逻辑)
|
||||
if ("1".equals(approvalStatus)) {
|
||||
// 审批通过
|
||||
String nextLevel = getNextApprovalLevel(currentApprovalLevel, application.getTrainingType());
|
||||
if (nextLevel != null) {
|
||||
// 进入下一级审批
|
||||
application.setApprovalLevel(nextLevel);
|
||||
application.setCurrentApproverId(null); // 不再设置固定审批人ID
|
||||
application.setCurrentApprover(getApprovalLevelDescription(nextLevel));
|
||||
|
||||
log.info("✅ 审批流转到第{}级,申请ID: {}, 审批人根据权限动态查询",
|
||||
nextLevel, applicationId);
|
||||
} else {
|
||||
// 所有级别审批完成
|
||||
try {
|
||||
// 创建培训记录
|
||||
log.info("开始最终审批处理,申请ID: {}, 当前状态: {}, 申请人: {}",
|
||||
applicationId, application.getStatus(), application.getUserName());
|
||||
|
||||
createTrainingRecordFromApplication(application);
|
||||
log.info("审批通过,成功创建培训记录,申请ID: {}", applicationId);
|
||||
|
||||
// 更新申请状态为通过
|
||||
application.setStatus("1");
|
||||
application.setApprovalTime(new Date());
|
||||
} catch (Exception e) {
|
||||
log.error("审批通过后创建培训记录失败,申请ID: {}, 错误: {}", applicationId, e.getMessage(), e);
|
||||
throw new RuntimeException("审批处理失败:创建培训记录时发生错误 - " + e.getMessage());
|
||||
}
|
||||
}
|
||||
} else if ("2".equals(approvalStatus)) {
|
||||
// 审批拒绝
|
||||
application.setStatus("2");
|
||||
application.setApprovalTime(new Date());
|
||||
}
|
||||
|
||||
// 更新申请状态到数据库
|
||||
boolean updateResult = trainingApplicationMapper.updateById(application) > 0;
|
||||
|
||||
return updateResult;
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询当前用户的待审批申请列表(动态权限方案 + 部门过滤)
|
||||
*
|
||||
* @return 待审批申请列表
|
||||
*/
|
||||
@Override
|
||||
public List<RsTrainingApplication> queryPendingByCurrentUser() {
|
||||
Long currentUserId = LoginHelper.getUserId();
|
||||
String currentUserName = LoginHelper.getUsername();
|
||||
|
||||
log.info("🔍 查询用户待审批申请 - 用户ID: {}, 用户名: {}", currentUserId, currentUserName);
|
||||
|
||||
// 1. 获取当前用户的审批级别列表(基于权限动态查询)
|
||||
List<String> approvalLevels = getApprovalLevelsByUser(currentUserId);
|
||||
|
||||
if (approvalLevels == null || approvalLevels.isEmpty()) {
|
||||
log.warn("❌ 用户 {} 没有任何培训审批权限,返回空列表", currentUserName);
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
log.info("✅ 用户 {} 拥有审批级别: {}", currentUserName, approvalLevels);
|
||||
|
||||
// 2. 对每个级别单独查询并合并
|
||||
List<RsTrainingApplication> result = new ArrayList<>();
|
||||
|
||||
for (String level : approvalLevels) {
|
||||
Long deptIdForFilter = null;
|
||||
|
||||
// 🔴 关键:只对 level=1 进行部门过滤
|
||||
if ("1".equals(level)) {
|
||||
SysUserVo currentUser = userService.selectUserById(currentUserId);
|
||||
if (currentUser != null && currentUser.getDeptId() != null) {
|
||||
deptIdForFilter = currentUser.getDeptId();
|
||||
log.info("🔒 [部门权限过滤] 级别1,用户: {}, 部门ID: {}, 只查看本部门待审批",
|
||||
currentUserName, deptIdForFilter);
|
||||
} else {
|
||||
log.warn("⚠️ 用户 {} 是部门负责人但没有部门信息,无法过滤", currentUserName);
|
||||
}
|
||||
} else {
|
||||
log.info("✅ [全校权限] 级别{}, 用户 {}, 查看全校待审批", level, currentUserName);
|
||||
}
|
||||
|
||||
// 3. 构建查询条件
|
||||
LambdaQueryWrapper<RsTrainingApplication> lqw = new LambdaQueryWrapper<>();
|
||||
lqw.eq(RsTrainingApplication::getStatus, "0"); // 待审核状态
|
||||
lqw.eq(RsTrainingApplication::getApprovalLevel, level);
|
||||
if (deptIdForFilter != null) {
|
||||
lqw.eq(RsTrainingApplication::getCreateDept, deptIdForFilter);
|
||||
}
|
||||
lqw.eq(RsTrainingApplication::getTenantId, LoginHelper.getTenantId());
|
||||
|
||||
// 4. 查询该级别的待审批申请
|
||||
List<RsTrainingApplication> levelApplications = trainingApplicationMapper.selectList(lqw);
|
||||
|
||||
log.info("📋 级别{} 查询到 {} 条待审批申请", level, levelApplications.size());
|
||||
|
||||
result.addAll(levelApplications);
|
||||
}
|
||||
|
||||
log.info("📋 用户 {} 总共查询到 {} 条待审批申请", currentUserName, result.size());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取下一级审批级别(根据培训类型动态路由)
|
||||
*
|
||||
* 7级审批制度:
|
||||
* 1-部门负责人 → 2a-教务处/2b-学生处/3-计划财务处(根据培训类型)
|
||||
* 2a-教务处 → 3-计划财务处
|
||||
* 2b-学生处 → 3-计划财务处
|
||||
* 3-计划财务处 → 4-人事处
|
||||
* 4-人事处 → 5-业务分管领导
|
||||
* 5-业务分管领导 → 6-人事分管院领导
|
||||
* 6-人事分管院领导 → 7-院长
|
||||
* 7-院长 → 审批完成
|
||||
*
|
||||
* @param currentLevel 当前审批级别
|
||||
* @param trainingType 培训类型
|
||||
* @return 下一级审批级别
|
||||
*/
|
||||
private String getNextApprovalLevel(String currentLevel, String trainingType) {
|
||||
switch (currentLevel) {
|
||||
case "1":
|
||||
// 部门负责人审批后,根据培训类型分流
|
||||
if ("教学".equals(trainingType)) {
|
||||
return "2a"; // 教务处
|
||||
} else if ("德育".equals(trainingType)) {
|
||||
return "2b"; // 学生处
|
||||
} else {
|
||||
// 行政、管理、其他 → 直接到计划财务处
|
||||
return "3";
|
||||
}
|
||||
case "2a": // 教务处 → 计划财务处
|
||||
case "2b": // 学生处 → 计划财务处
|
||||
return "3";
|
||||
case "3":
|
||||
return "4"; // 计划财务处 → 人事处
|
||||
case "4":
|
||||
return "5"; // 人事处 → 业务分管领导
|
||||
case "5":
|
||||
return "6"; // 业务分管领导 → 人事分管院领导
|
||||
case "6":
|
||||
return "7"; // 人事分管院领导 → 院长
|
||||
case "7":
|
||||
return null; // 院长审批完成
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据审批级别获取审批环节描述
|
||||
*
|
||||
* @param approvalLevel 审批级别
|
||||
* @return 审批环节描述
|
||||
*/
|
||||
private String getApprovalLevelDescription(String approvalLevel) {
|
||||
switch (approvalLevel) {
|
||||
case "1":
|
||||
return "待部门负责人审批";
|
||||
case "2a":
|
||||
return "待教务处审批";
|
||||
case "2b":
|
||||
return "待学生处审批";
|
||||
case "3":
|
||||
return "待计划财务处审批";
|
||||
case "4":
|
||||
return "待人事处审批";
|
||||
case "5":
|
||||
return "待业务分管领导审批";
|
||||
case "6":
|
||||
return "待人事分管院领导审批";
|
||||
case "7":
|
||||
return "待院长审批";
|
||||
default:
|
||||
return "待审批";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据当前登录用户的审批权限,获取其可审批的级别列表
|
||||
*
|
||||
* 权限到级别的映射:
|
||||
* - rs:training:approve1 → 审批级别 "1" (部门负责人)
|
||||
* - rs:training:approve2a → 审批级别 "2a" (教务处)
|
||||
* - rs:training:approve2b → 审批级别 "2b" (学生处)
|
||||
* - rs:training:approve3 → 审批级别 "3" (计划财务处)
|
||||
* - rs:training:approve4 → 审批级别 "4" (人事处)
|
||||
* - rs:training:approve5 → 审批级别 "5" (业务分管领导)
|
||||
* - rs:training:approve6 → 审批级别 "6" (人事分管院领导)
|
||||
* - rs:training:approve7 → 审批级别 "7" (院长)
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @return 可审批的级别列表
|
||||
*/
|
||||
private List<String> getApprovalLevelsByUser(Long userId) {
|
||||
try {
|
||||
List<String> approvalLevels = new ArrayList<>();
|
||||
|
||||
// 检查7个审批级别的权限(1, 2a, 2b, 3, 4, 5, 6, 7)
|
||||
String[] levels = { "1", "2a", "2b", "3", "4", "5", "6", "7" };
|
||||
for (String level : levels) {
|
||||
String permission = "rs:training:approve" + level;
|
||||
if (StpUtil.hasPermission(permission)) {
|
||||
approvalLevels.add(level);
|
||||
log.info("✅ 用户 {} 拥有第{}级审批权限: {}", userId, level, permission);
|
||||
}
|
||||
}
|
||||
|
||||
// 检查通用审批权限(超级管理员)
|
||||
if (StpUtil.hasPermission("rs:training:approve")) {
|
||||
log.info("✅ 用户 {} 拥有通用审批权限,可审批所有级别", userId);
|
||||
approvalLevels.clear();
|
||||
for (String level : levels) {
|
||||
approvalLevels.add(level);
|
||||
}
|
||||
}
|
||||
|
||||
if (approvalLevels.isEmpty()) {
|
||||
log.warn("❌ 用户 {} 没有任何培训审批权限", userId);
|
||||
} else {
|
||||
log.info("📋 用户 {} 可审批的级别: {}", userId, approvalLevels);
|
||||
}
|
||||
|
||||
return approvalLevels;
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("获取用户审批级别失败,用户ID: {}, 错误: {}", userId, e.getMessage(), e);
|
||||
return new ArrayList<>();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证审批人权限级别
|
||||
*
|
||||
* @param approverId 审批人ID
|
||||
* @param approvalLevel 审批级别
|
||||
* @return 是否有权限
|
||||
*/
|
||||
private boolean validateApproverLevel(Long approverId, String approvalLevel) {
|
||||
// 检查通用审批权限(超级管理员)
|
||||
if (StpUtil.hasPermission("rs:training:approve")) {
|
||||
log.info("用户 {} 拥有通用审批权限 rs:training:approve", approverId);
|
||||
return true;
|
||||
}
|
||||
|
||||
// 检查分级审批权限
|
||||
String requiredPermission = "rs:training:approve" + approvalLevel;
|
||||
boolean hasPermission = StpUtil.hasPermission(requiredPermission);
|
||||
|
||||
if (hasPermission) {
|
||||
log.info("用户 {} 拥有第{}级审批权限 {}",
|
||||
approverId, approvalLevel, requiredPermission);
|
||||
} else {
|
||||
log.warn("用户 {} 缺少第{}级审批权限 {},权限验证失败",
|
||||
approverId, approvalLevel, requiredPermission);
|
||||
}
|
||||
|
||||
return hasPermission;
|
||||
}
|
||||
}
|
||||
+242
-35
@@ -1,5 +1,6 @@
|
||||
package org.dromara.rs.service.impl;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
@@ -18,6 +19,8 @@ import org.dromara.rs.domain.RsTrainingApproval;
|
||||
import org.dromara.rs.domain.RsTrainingApplication;
|
||||
import org.dromara.rs.service.IRsTrainingApprovalService;
|
||||
import org.dromara.rs.service.IRsTrainingApplicationService;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* 培训审批服务实现类
|
||||
@@ -27,26 +30,30 @@ import org.dromara.rs.service.IRsTrainingApplicationService;
|
||||
*/
|
||||
@Service
|
||||
public class RsTrainingApprovalServiceImpl implements IRsTrainingApprovalService {
|
||||
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(RsTrainingApprovalServiceImpl.class);
|
||||
|
||||
@Autowired
|
||||
private RsTrainingApprovalMapper trainingApprovalMapper;
|
||||
|
||||
|
||||
@Autowired
|
||||
private RsTrainingApplicationMapper trainingApplicationMapper;
|
||||
|
||||
|
||||
@Autowired
|
||||
private IRsTrainingApplicationService trainingApplicationService;
|
||||
|
||||
/**
|
||||
* 查询培训审批列表
|
||||
*
|
||||
* @param approval 培训审批
|
||||
* @param approval 培训审批
|
||||
* @param pageQuery 分页参数
|
||||
* @return 培训审批分页列表
|
||||
*/
|
||||
@Override
|
||||
public TableDataInfo<RsTrainingApproval> selectPageRsTrainingApprovalList(RsTrainingApproval approval, PageQuery pageQuery) {
|
||||
com.baomidou.mybatisplus.extension.plugins.pagination.Page<RsTrainingApproval> page = trainingApprovalMapper.selectPage(pageQuery.build(), buildQueryWrapper(approval));
|
||||
public TableDataInfo<RsTrainingApproval> selectPageRsTrainingApprovalList(RsTrainingApproval approval,
|
||||
PageQuery pageQuery) {
|
||||
com.baomidou.mybatisplus.extension.plugins.pagination.Page<RsTrainingApproval> page = trainingApprovalMapper
|
||||
.selectPage(pageQuery.build(), buildQueryWrapper(approval));
|
||||
return TableDataInfo.build(page);
|
||||
}
|
||||
|
||||
@@ -60,37 +67,39 @@ public class RsTrainingApprovalServiceImpl implements IRsTrainingApprovalService
|
||||
public List<RsTrainingApproval> selectRsTrainingApprovalList(RsTrainingApproval approval) {
|
||||
return trainingApprovalMapper.selectList(buildQueryWrapper(approval));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 构建查询条件
|
||||
*/
|
||||
private LambdaQueryWrapper<RsTrainingApproval> buildQueryWrapper(RsTrainingApproval approval) {
|
||||
LambdaQueryWrapper<RsTrainingApproval> lqw = new LambdaQueryWrapper<>();
|
||||
|
||||
|
||||
// ===== 业务逻辑层权限过滤 =====
|
||||
// 根据用户角色进行数据权限过滤
|
||||
if (!LoginHelper.isSuperAdmin()) {
|
||||
// 获取当前登录用户信息
|
||||
Long currentUserId = LoginHelper.getUserId();
|
||||
|
||||
|
||||
// 检查用户角色并应用相应的数据过滤
|
||||
if (StpUtil.hasRole("rs-Applicant")) {
|
||||
// 申请人只能看到与自己相关的审批记录
|
||||
// 这里需要通过申请表关联查询
|
||||
lqw.exists("SELECT 1 FROM rs_training_application app WHERE app.application_id = rs_training_approval.application_id AND app.user_id = " + currentUserId);
|
||||
lqw.exists(
|
||||
"SELECT 1 FROM rs_training_application app WHERE app.application_id = rs_training_approval.application_id AND app.user_id = "
|
||||
+ currentUserId);
|
||||
} else if (StpUtil.hasRole("rs-admin") || StpUtil.hasRole("rs-Approver")) {
|
||||
// 人事管理员和审批人可以看到所有审批记录
|
||||
// 不设置额外过滤条件,让管理员和审批人能看到所有审批
|
||||
} else {
|
||||
// 默认情况:只能看到自己创建或处理的审批
|
||||
lqw.and(wrapper -> wrapper.eq(RsTrainingApproval::getCreateBy, currentUserId)
|
||||
.or().eq(RsTrainingApproval::getApproverId, currentUserId));
|
||||
.or().eq(RsTrainingApproval::getApproverId, currentUserId));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 添加租户过滤
|
||||
lqw.eq(RsTrainingApproval::getTenantId, LoginHelper.getTenantId());
|
||||
|
||||
|
||||
lqw.eq(approval.getApplicationId() != null, RsTrainingApproval::getApplicationId, approval.getApplicationId());
|
||||
lqw.eq(approval.getApproverId() != null, RsTrainingApproval::getApproverId, approval.getApproverId());
|
||||
lqw.eq(approval.getApprovalLevel() != null, RsTrainingApproval::getApprovalLevel, approval.getApprovalLevel());
|
||||
@@ -119,14 +128,15 @@ public class RsTrainingApprovalServiceImpl implements IRsTrainingApprovalService
|
||||
* 查询待我审批的列表
|
||||
*
|
||||
* @param approverId 审批人ID
|
||||
* @param approval 培训审批
|
||||
* @param pageQuery 分页参数
|
||||
* @param approval 培训审批
|
||||
* @param pageQuery 分页参数
|
||||
* @return 培训审批分页列表
|
||||
*/
|
||||
@Override
|
||||
public TableDataInfo<RsTrainingApproval> selectPagePendingApprovals(Long approverId, RsTrainingApproval approval, PageQuery pageQuery) {
|
||||
public TableDataInfo<RsTrainingApproval> selectPagePendingApprovals(Long approverId, RsTrainingApproval approval,
|
||||
PageQuery pageQuery) {
|
||||
LambdaQueryWrapper<RsTrainingApproval> lqw = buildQueryWrapper(approval);
|
||||
|
||||
|
||||
// 简化权限模型:审批人和管理员可以看到所有待审核记录
|
||||
if (StpUtil.hasRole("rs-admin") || StpUtil.hasRole("rs-Approver")) {
|
||||
// 管理员和审批人可以看到所有待审核记录,不限制approverId
|
||||
@@ -134,9 +144,10 @@ public class RsTrainingApprovalServiceImpl implements IRsTrainingApprovalService
|
||||
// 其他角色只能看到指派给自己的待审核记录
|
||||
lqw.eq(RsTrainingApproval::getApproverId, approverId);
|
||||
}
|
||||
|
||||
|
||||
lqw.eq(RsTrainingApproval::getStatus, "0"); // 待审核状态
|
||||
com.baomidou.mybatisplus.extension.plugins.pagination.Page<RsTrainingApproval> page = trainingApprovalMapper.selectPage(pageQuery.build(), lqw);
|
||||
com.baomidou.mybatisplus.extension.plugins.pagination.Page<RsTrainingApproval> page = trainingApprovalMapper
|
||||
.selectPage(pageQuery.build(), lqw);
|
||||
return TableDataInfo.build(page);
|
||||
}
|
||||
|
||||
@@ -178,12 +189,27 @@ public class RsTrainingApprovalServiceImpl implements IRsTrainingApprovalService
|
||||
/**
|
||||
* 查询带详细信息的审批记录列表(关联申请人和课程信息)
|
||||
*
|
||||
* @param approval 培训审批
|
||||
* @param approval 培训审批
|
||||
* @param pageQuery 分页参数
|
||||
* @return 培训审批分页列表
|
||||
*/
|
||||
@Override
|
||||
public TableDataInfo<RsTrainingApproval> selectPageRsTrainingApprovalWithDetailsList(RsTrainingApproval approval, PageQuery pageQuery) {
|
||||
public TableDataInfo<RsTrainingApproval> selectPageRsTrainingApprovalWithDetailsList(RsTrainingApproval approval,
|
||||
PageQuery pageQuery) {
|
||||
log.info("==================== 查询培训审批列表 ====================");
|
||||
log.info("原始查询参数: applicationId={}, approverId={}", approval.getApplicationId(), approval.getApproverId());
|
||||
|
||||
// 🔧 应用数据权限过滤
|
||||
try {
|
||||
applyDataPermissionFilter(approval);
|
||||
log.info("权限过滤后查询参数: applicationId={}, approverId={}, applicantId={}, deptId={}",
|
||||
approval.getApplicationId(), approval.getApproverId(), approval.getApplicantId(),
|
||||
approval.getDeptId());
|
||||
} catch (Exception e) {
|
||||
log.error("❌ 权限过滤异常:", e);
|
||||
throw e;
|
||||
}
|
||||
|
||||
// 创建分页对象
|
||||
com.baomidou.mybatisplus.extension.plugins.pagination.Page<RsTrainingApproval> page = pageQuery.build();
|
||||
// 获取分页参数
|
||||
@@ -196,13 +222,15 @@ public class RsTrainingApprovalServiceImpl implements IRsTrainingApprovalService
|
||||
if (approval.getTenantId() == null || approval.getTenantId().isEmpty()) {
|
||||
approval.setTenantId(LoginHelper.getTenantId());
|
||||
}
|
||||
|
||||
|
||||
// 查询总数 - 使用与列表查询相同的条件
|
||||
long total = trainingApprovalMapper.selectRsTrainingApprovalWithDetailsCount(approval);
|
||||
|
||||
|
||||
// 使用自定义分页查询获取列表数据
|
||||
List<RsTrainingApproval> list = trainingApprovalMapper.selectRsTrainingApprovalWithDetailsList(approval);
|
||||
|
||||
|
||||
log.info("查询结果数量: total={}, list.size={}", total, list.size());
|
||||
|
||||
// 手动分页处理
|
||||
int start = (int) offset;
|
||||
int end = Math.min(start + (int) size, list.size());
|
||||
@@ -211,11 +239,14 @@ public class RsTrainingApprovalServiceImpl implements IRsTrainingApprovalService
|
||||
} else {
|
||||
list = list.subList(start, end);
|
||||
}
|
||||
|
||||
|
||||
// 构建分页对象
|
||||
page.setRecords(list);
|
||||
page.setTotal(total);
|
||||
|
||||
|
||||
log.info("分页结果: 总数={}, 当前页={}, 每页={}, 返回={}", total, current, size, list.size());
|
||||
log.info("==================== 查询完成 ====================");
|
||||
|
||||
return TableDataInfo.build(page);
|
||||
}
|
||||
|
||||
@@ -240,13 +271,13 @@ public class RsTrainingApprovalServiceImpl implements IRsTrainingApprovalService
|
||||
public int deleteRsTrainingApprovalById(Long approvalId) {
|
||||
return trainingApprovalMapper.deleteById(approvalId);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 处理审批
|
||||
*
|
||||
* @param applicationId 申请ID
|
||||
* @param status 审批状态
|
||||
* @param opinion 审批意见
|
||||
* @param status 审批状态
|
||||
* @param opinion 审批意见
|
||||
* @return 结果
|
||||
*/
|
||||
@Override
|
||||
@@ -257,11 +288,11 @@ public class RsTrainingApprovalServiceImpl implements IRsTrainingApprovalService
|
||||
if (application == null) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// 获取当前用户信息
|
||||
Long userId = LoginHelper.getUserId();
|
||||
String userName = LoginHelper.getUsername();
|
||||
|
||||
|
||||
// 创建审批记录 - MyBatis-Plus自动生成雪花ID
|
||||
RsTrainingApproval approval = new RsTrainingApproval();
|
||||
// 不需要手动设置ID,MyBatis-Plus会自动生成雪花ID
|
||||
@@ -273,14 +304,190 @@ public class RsTrainingApprovalServiceImpl implements IRsTrainingApprovalService
|
||||
approval.setOpinion(opinion); // 审批意见
|
||||
approval.setApprovalTime(DateUtils.getNowDate());
|
||||
approval.setCreateTime(DateUtils.getNowDate());
|
||||
|
||||
|
||||
// 插入审批记录 - 无论通过还是拒绝,都创建独立审批记录
|
||||
int result = trainingApprovalMapper.insert(approval);
|
||||
System.out.println("创建审批记录 - applicationId: " + applicationId + ", status: " + status + ", result: " + result);
|
||||
|
||||
|
||||
// 更新申请状态
|
||||
trainingApplicationService.updateApplicationStatus(applicationId, status);
|
||||
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 应用数据权限过滤
|
||||
*/
|
||||
private void applyDataPermissionFilter(RsTrainingApproval approval) {
|
||||
Long currentUserId = StpUtil.getLoginIdAsLong();
|
||||
String currentUsername = LoginHelper.getUsername();
|
||||
Long currentDeptId = LoginHelper.getDeptId();
|
||||
boolean isSuperAdmin = LoginHelper.isSuperAdmin();
|
||||
|
||||
log.info("==================== 开始应用数据权限过滤 ====================");
|
||||
log.info("当前用户: {}, ID: {}, 部门ID: {}, 超级管理员: {}",
|
||||
currentUsername, currentUserId, currentDeptId, isSuperAdmin);
|
||||
|
||||
// 超级管理员不需要过滤
|
||||
if (isSuperAdmin) {
|
||||
log.info("→ 权限结果:超级管理员,跳过所有过滤");
|
||||
log.info("==================== 权限过滤结束 ====================");
|
||||
return;
|
||||
}
|
||||
|
||||
// 申请人只能看到自己的申请
|
||||
boolean hasApplicantRole = StpUtil.hasRole("rs-Applicant");
|
||||
log.info("✓ 角色检查 [rs-Applicant]: {}", hasApplicantRole);
|
||||
if (hasApplicantRole) {
|
||||
approval.setApplicantId(currentUserId);
|
||||
log.info("→ 权限结果:申请人角色,设置申请人过滤 applicantId={}", currentUserId);
|
||||
log.info("==================== 权限过滤结束 ====================");
|
||||
return;
|
||||
}
|
||||
|
||||
// 人事管理员可以看到所有申请
|
||||
boolean hasAdminRole = StpUtil.hasRole("rs-admin");
|
||||
log.info("✓ 角色检查 [rs-admin]: {}", hasAdminRole);
|
||||
if (hasAdminRole) {
|
||||
log.info("→ 权限结果:管理员角色,不设置过滤(可查看所有数据)");
|
||||
log.info("==================== 权限过滤结束 ====================");
|
||||
return; // 全局权限
|
||||
}
|
||||
|
||||
// 🔧 检查部门负责人权限(但不能与其他审批权限冲突)
|
||||
boolean isDeptApprover = isDeptApprover(currentUserId);
|
||||
log.info("✓ 部门负责人检查结果: {}", isDeptApprover);
|
||||
|
||||
// 🆕 动态查询用户的审批级别
|
||||
List<String> approvalLevels = getApprovalLevelsByUser(currentUserId);
|
||||
|
||||
if (approvalLevels == null || approvalLevels.isEmpty()) {
|
||||
log.warn("❌ 用户 {} 没有任何培训审批权限,返回空列表", currentUsername);
|
||||
approval.setApproverId(-1L); // 设置一个不存在的ID,确保查不到数据
|
||||
log.info("==================== 权限过滤结束 ====================");
|
||||
return;
|
||||
}
|
||||
|
||||
log.info("✅ 用户 {} 拥有审批级别: {}", currentUsername, approvalLevels);
|
||||
|
||||
// 🔴 关键改进:将审批级别列表存储到审批对象中
|
||||
approval.setApprovalLevels(approvalLevels);
|
||||
|
||||
// 🔴 关键改进:只对 level=1(部门负责人)进行部门过滤
|
||||
if (approvalLevels.contains("1")) {
|
||||
// 如果用户有第1级审批权限,需要特殊处理部门过滤
|
||||
// 但不能直接设置deptId,因为可能同时有其他级别的审批权限
|
||||
// 解决方案:在Mapper中根据approvalLevel动态应用部门过滤
|
||||
approval.setDeptId(currentDeptId);
|
||||
log.info("✅ 用户拥有第1级审批权限(部门负责人),设置部门过滤 deptId={}", currentDeptId);
|
||||
}
|
||||
|
||||
log.info("→ 权限结果:多级审批权限,审批级别={}", approvalLevels);
|
||||
log.info("==================== 权限过滤结束 ====================");
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断用户是否为部门负责人(第1级审批权限)
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @return 是否为部门负责人
|
||||
*/
|
||||
private boolean isDeptApprover(Long userId) {
|
||||
// 检查是否有第1级审批权限(部门负责人)
|
||||
if (StpUtil.hasPermission("rs:training:approve1")) {
|
||||
log.info("✓ 检测到部门负责人权限: rs:training:approve1");
|
||||
return true;
|
||||
}
|
||||
// 检查是否有部门负责人角色
|
||||
if (StpUtil.hasRole("dept_head_role")) {
|
||||
log.info("✓ 检测到部门负责人角色: dept_head_role");
|
||||
return true;
|
||||
}
|
||||
// 兼容旧版权限标识符
|
||||
if (StpUtil.hasPermission("training:application:dept_head:approve")) {
|
||||
log.info("✓ 检测到旧版部门负责人权限: training:application:dept_head:approve");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 🆕 动态获取用户的审批级别列表(培训审批)
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @return 可审批的级别列表,例如:["1", "4"]
|
||||
*/
|
||||
private List<String> getApprovalLevelsByUser(Long userId) {
|
||||
try {
|
||||
List<String> approvalLevels = new ArrayList<>();
|
||||
|
||||
// 检查7个审批级别的权限(1-7级,2a-教务处,2b-学生处)
|
||||
// 第1级:部门负责人
|
||||
if (StpUtil.hasPermission("rs:training:approve1")) {
|
||||
approvalLevels.add("1");
|
||||
log.info("✅ 用户 {} 拥有第1级审批权限(部门负责人)", userId);
|
||||
}
|
||||
|
||||
// 第2a级:教务处
|
||||
if (StpUtil.hasPermission("rs:training:approve2a")) {
|
||||
approvalLevels.add("2a");
|
||||
log.info("✅ 用户 {} 拥有第2a级审批权限(教务处)", userId);
|
||||
}
|
||||
|
||||
// 第2b级:学生处
|
||||
if (StpUtil.hasPermission("rs:training:approve2b")) {
|
||||
approvalLevels.add("2b");
|
||||
log.info("✅ 用户 {} 拥有第2b级审批权限(学生处)", userId);
|
||||
}
|
||||
|
||||
// 第3级:计划财务处
|
||||
if (StpUtil.hasPermission("rs:training:approve3")) {
|
||||
approvalLevels.add("3");
|
||||
log.info("✅ 用户 {} 拥有第3级审批权限(计划财务处)", userId);
|
||||
}
|
||||
|
||||
// 第4级:人事处
|
||||
if (StpUtil.hasPermission("rs:training:approve4")) {
|
||||
approvalLevels.add("4");
|
||||
log.info("✅ 用户 {} 拥有第4级审批权限(人事处)", userId);
|
||||
}
|
||||
|
||||
// 第5级:业务分管领导
|
||||
if (StpUtil.hasPermission("rs:training:approve5")) {
|
||||
approvalLevels.add("5");
|
||||
log.info("✅ 用户 {} 拥有第5级审批权限(业务分管领导)", userId);
|
||||
}
|
||||
|
||||
// 第6级:人事分管院领导
|
||||
if (StpUtil.hasPermission("rs:training:approve6")) {
|
||||
approvalLevels.add("6");
|
||||
log.info("✅ 用户 {} 拥有第6级审批权限(人事分管院领导)", userId);
|
||||
}
|
||||
|
||||
// 第7级:院长
|
||||
if (StpUtil.hasPermission("rs:training:approve7")) {
|
||||
approvalLevels.add("7");
|
||||
log.info("✅ 用户 {} 拥有第7级审批权限(院长)", userId);
|
||||
}
|
||||
|
||||
// 检查通用审批权限(超级管理员)
|
||||
if (StpUtil.hasPermission("rs:training:approve")) {
|
||||
log.info("✅ 用户 {} 拥有通用审批权限,可审批所有级别", userId);
|
||||
approvalLevels.clear();
|
||||
approvalLevels.addAll(Arrays.asList("1", "2a", "2b", "3", "4", "5", "6", "7"));
|
||||
}
|
||||
|
||||
if (approvalLevels.isEmpty()) {
|
||||
log.warn("❌ 用户 {} 没有任何培训审批权限", userId);
|
||||
} else {
|
||||
log.info("📋 用户 {} 可审批的级别: {}", userId, approvalLevels);
|
||||
}
|
||||
|
||||
return approvalLevels;
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("❌ 获取用户 {} 的审批级别失败", userId, e);
|
||||
return new ArrayList<>();
|
||||
}
|
||||
}
|
||||
}
|
||||
+7
-2
@@ -9,6 +9,7 @@
|
||||
<result property="courseId" column="course_id"/>
|
||||
<result property="userId" column="user_id"/>
|
||||
<result property="userName" column="user_name"/>
|
||||
<result property="nickName" column="nick_name"/>
|
||||
<result property="department" column="department"/>
|
||||
<result property="position" column="position"/>
|
||||
<result property="currentTitle" column="current_title"/>
|
||||
@@ -25,6 +26,7 @@
|
||||
<result property="status" column="status"/>
|
||||
<result property="applyTime" column="apply_time"/>
|
||||
<result property="currentApprover" column="current_approver"/>
|
||||
<result property="approvalLevel" column="approval_level"/>
|
||||
<result property="location" column="location"/>
|
||||
<result property="duration" column="duration"/>
|
||||
<result property="startTime" column="start_time"/>
|
||||
@@ -41,10 +43,12 @@
|
||||
|
||||
<sql id="selectRsTrainingApplicationVo">
|
||||
SELECT
|
||||
a.application_id, a.course_id, a.course_name as custom_course_name, a.user_id, a.user_name, a.department, a.position,
|
||||
a.application_id, a.course_id, a.course_name as custom_course_name, a.user_id, a.user_name,
|
||||
u.nick_name,
|
||||
a.department, a.position,
|
||||
a.current_title, a.current_position, a.work_start_time, a.phone, a.organizer_unit,
|
||||
a.training_type, a.training_fee, a.companions, a.training_purpose, a.attachment_ids,
|
||||
a.reason, a.status, a.apply_time, a.current_approver, a.location, a.duration, a.start_time, a.end_time,
|
||||
a.reason, a.status, a.apply_time, a.current_approver, a.approval_level, a.location, a.duration, a.start_time, a.end_time,
|
||||
a.tenant_id, a.create_dept, a.reject_time, a.create_by, a.create_time, a.update_by, a.update_time,
|
||||
CASE
|
||||
WHEN a.course_id = 0 THEN a.course_name
|
||||
@@ -52,6 +56,7 @@
|
||||
END as course_name
|
||||
FROM rs_training_application a
|
||||
LEFT JOIN rs_training_course c ON a.course_id = c.course_id
|
||||
LEFT JOIN sys_user u ON a.user_id = u.user_id
|
||||
</sql>
|
||||
|
||||
<select id="selectRsTrainingApplicationList" parameterType="org.dromara.rs.domain.RsTrainingApplication" resultMap="RsTrainingApplicationResult">
|
||||
|
||||
+86
-8
@@ -94,7 +94,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
order by approval_level asc, create_time desc
|
||||
</select>
|
||||
|
||||
<!-- 查询带详细信息的审批记录列表(关联申请人和课程信息) -->
|
||||
<!-- 查询带详细信息的审批记录列表(关联申请人和课程信息)- 🆕 支持多级审批过滤 -->
|
||||
<select id="selectRsTrainingApprovalWithDetailsList" parameterType="RsTrainingApproval" resultMap="RsTrainingApprovalWithDetailsResult">
|
||||
SELECT
|
||||
a.approval_id, a.application_id, a.approver_id, a.approver_name,
|
||||
@@ -130,9 +130,44 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
<if test="applicationId != null">
|
||||
AND a.application_id = #{applicationId}
|
||||
</if>
|
||||
<if test="approverId != null">
|
||||
AND a.approver_id = #{approverId}
|
||||
</if>
|
||||
|
||||
<!-- 🆕 关键改进:多级审批过滤逻辑 -->
|
||||
<choose>
|
||||
<!-- 情况1:有审批级别列表(多级审批用户) -->
|
||||
<when test="approvalLevels != null and approvalLevels.size() > 0">
|
||||
AND (
|
||||
<!-- 遍历每个审批级别 -->
|
||||
<foreach collection="approvalLevels" item="level" separator=" OR ">
|
||||
<choose>
|
||||
<!-- level=1(部门负责人):需要同时满足审批级别=1 AND 申请人部门=当前用户部门 -->
|
||||
<when test="level == '1'">
|
||||
(
|
||||
app.approval_level = '1'
|
||||
<if test="deptId != null">
|
||||
AND EXISTS (
|
||||
SELECT 1 FROM sys_user u
|
||||
WHERE u.user_id = app.user_id
|
||||
AND u.dept_id = #{deptId}
|
||||
AND u.deleted = '0'
|
||||
)
|
||||
</if>
|
||||
)
|
||||
</when>
|
||||
<!-- 其他级别(2a/2b/3/4/5/6/7):只需要审批级别匹配即可 -->
|
||||
<otherwise>
|
||||
app.approval_level = #{level}
|
||||
</otherwise>
|
||||
</choose>
|
||||
</foreach>
|
||||
)
|
||||
</when>
|
||||
|
||||
<!-- 情况2:旧逻辑兼容(单一审批人ID过滤) -->
|
||||
<when test="approverId != null">
|
||||
AND a.approver_id = #{approverId}
|
||||
</when>
|
||||
</choose>
|
||||
|
||||
<if test="approverName != null and approverName != ''">
|
||||
AND a.approver_name like concat('%', #{approverName}, '%')
|
||||
</if>
|
||||
@@ -156,11 +191,15 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
<if test="courseTitle != null and courseTitle != ''">
|
||||
AND (app.course_name like concat('%', #{courseTitle}, '%') OR c.title like concat('%', #{courseTitle}, '%'))
|
||||
</if>
|
||||
<!-- 申请人权限过滤:只显示指定申请人的审批记录 -->
|
||||
<if test="applicantId != null">
|
||||
AND app.user_id = #{applicantId}
|
||||
</if>
|
||||
</where>
|
||||
ORDER BY a.approval_time DESC
|
||||
</select>
|
||||
|
||||
<!-- 查询带详细信息的审批记录数量(关联申请人和课程信息) -->
|
||||
<!-- 查询带详细信息的审批记录数量(关联申请人和课程信息)- 🆕 支持多级审批过滤 -->
|
||||
<select id="selectRsTrainingApprovalWithDetailsCount" parameterType="RsTrainingApproval" resultType="long">
|
||||
SELECT COUNT(1)
|
||||
FROM rs_training_approval a
|
||||
@@ -171,9 +210,44 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
<if test="applicationId != null">
|
||||
AND a.application_id = #{applicationId}
|
||||
</if>
|
||||
<if test="approverId != null">
|
||||
AND a.approver_id = #{approverId}
|
||||
</if>
|
||||
|
||||
<!-- 🆕 关键改进:多级审批过滤逻辑(与列表查询保持一致) -->
|
||||
<choose>
|
||||
<!-- 情况1:有审批级别列表(多级审批用户) -->
|
||||
<when test="approvalLevels != null and approvalLevels.size() > 0">
|
||||
AND (
|
||||
<!-- 遍历每个审批级别 -->
|
||||
<foreach collection="approvalLevels" item="level" separator=" OR ">
|
||||
<choose>
|
||||
<!-- level=1(部门负责人):需要同时满足审批级别=1 AND 申请人部门=当前用户部门 -->
|
||||
<when test="level == '1'">
|
||||
(
|
||||
app.approval_level = '1'
|
||||
<if test="deptId != null">
|
||||
AND EXISTS (
|
||||
SELECT 1 FROM sys_user u
|
||||
WHERE u.user_id = app.user_id
|
||||
AND u.dept_id = #{deptId}
|
||||
AND u.deleted = '0'
|
||||
)
|
||||
</if>
|
||||
)
|
||||
</when>
|
||||
<!-- 其他级别(2a/2b/3/4/5/6/7):只需要审批级别匹配即可 -->
|
||||
<otherwise>
|
||||
app.approval_level = #{level}
|
||||
</otherwise>
|
||||
</choose>
|
||||
</foreach>
|
||||
)
|
||||
</when>
|
||||
|
||||
<!-- 情况2:旧逻辑兼容(单一审批人ID过滤) -->
|
||||
<when test="approverId != null">
|
||||
AND a.approver_id = #{approverId}
|
||||
</when>
|
||||
</choose>
|
||||
|
||||
<if test="approverName != null and approverName != ''">
|
||||
AND a.approver_name like concat('%', #{approverName}, '%')
|
||||
</if>
|
||||
@@ -197,6 +271,10 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
<if test="courseTitle != null and courseTitle != ''">
|
||||
AND (app.course_name like concat('%', #{courseTitle}, '%') OR c.title like concat('%', #{courseTitle}, '%'))
|
||||
</if>
|
||||
<!-- 申请人权限过滤:只显示指定申请人的审批记录 -->
|
||||
<if test="applicantId != null">
|
||||
AND app.user_id = #{applicantId}
|
||||
</if>
|
||||
</where>
|
||||
</select>
|
||||
|
||||
|
||||
+25
-28
@@ -7,7 +7,6 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.dromara.common.core.constant.SystemConstants;
|
||||
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||
import org.dromara.system.domain.SysUser;
|
||||
@@ -88,10 +87,10 @@ public class SysTeacherServiceImpl implements ISysTeacherService {
|
||||
public List<SysDeptTreeVo> getDeptTreeData() {
|
||||
// 获取有教师的部门
|
||||
List<SysDeptTreeVo> teacherDepts = baseMapper.selectDeptTreeWithTeachers();
|
||||
|
||||
|
||||
// 补全父级部门
|
||||
List<SysDeptTreeVo> completeDepts = completeParentDepts(teacherDepts);
|
||||
|
||||
|
||||
// 构建树形结构
|
||||
return buildDeptTree(completeDepts, 0L);
|
||||
}
|
||||
@@ -105,7 +104,7 @@ public class SysTeacherServiceImpl implements ISysTeacherService {
|
||||
private List<SysDeptTreeVo> completeParentDepts(List<SysDeptTreeVo> teacherDepts) {
|
||||
Set<Long> allDeptIds = new HashSet<>();
|
||||
Set<Long> parentIds = new HashSet<>();
|
||||
|
||||
|
||||
// 收集所有部门ID和父级ID
|
||||
for (SysDeptTreeVo dept : teacherDepts) {
|
||||
allDeptIds.add(dept.getId());
|
||||
@@ -113,7 +112,7 @@ public class SysTeacherServiceImpl implements ISysTeacherService {
|
||||
collectParentIds(dept.getParentId(), parentIds);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 找出缺失的父级部门ID
|
||||
Set<Long> missingParentIds = new HashSet<>();
|
||||
for (Long parentId : parentIds) {
|
||||
@@ -121,13 +120,13 @@ public class SysTeacherServiceImpl implements ISysTeacherService {
|
||||
missingParentIds.add(parentId);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 查询缺失的父级部门
|
||||
List<SysDeptTreeVo> completeDepts = new ArrayList<>(teacherDepts);
|
||||
if (!missingParentIds.isEmpty()) {
|
||||
List<SysDeptTreeVo> parentDepts = baseMapper.selectDeptsByIds(new ArrayList<>(missingParentIds));
|
||||
completeDepts.addAll(parentDepts);
|
||||
|
||||
|
||||
// 递归补全更上级的父级部门
|
||||
List<SysDeptTreeVo> moreParents = completeParentDepts(parentDepts);
|
||||
for (SysDeptTreeVo parent : moreParents) {
|
||||
@@ -136,14 +135,14 @@ public class SysTeacherServiceImpl implements ISysTeacherService {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return completeDepts;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 递归收集所有父级部门ID
|
||||
*
|
||||
* @param parentId 父级部门ID
|
||||
* @param parentId 父级部门ID
|
||||
* @param parentIds 父级ID集合
|
||||
*/
|
||||
private void collectParentIds(Long parentId, Set<Long> parentIds) {
|
||||
@@ -161,7 +160,7 @@ public class SysTeacherServiceImpl implements ISysTeacherService {
|
||||
*/
|
||||
private List<SysDeptTreeVo> buildDeptTree(List<SysDeptTreeVo> flatList, Long parentId) {
|
||||
List<SysDeptTreeVo> tree = new ArrayList<>();
|
||||
|
||||
|
||||
for (SysDeptTreeVo dept : flatList) {
|
||||
if (ObjectUtil.equal(dept.getParentId(), parentId)) {
|
||||
List<SysDeptTreeVo> children = buildDeptTree(flatList, dept.getId());
|
||||
@@ -169,7 +168,7 @@ public class SysTeacherServiceImpl implements ISysTeacherService {
|
||||
tree.add(dept);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return tree;
|
||||
}
|
||||
|
||||
@@ -198,10 +197,10 @@ public class SysTeacherServiceImpl implements ISysTeacherService {
|
||||
if (ObjectUtil.isNull(userId)) {
|
||||
return null;
|
||||
}
|
||||
// ⚠️ 注意:基础条件(del_flag='0' 和 account_type='1')已在Mapper的SQL中定义
|
||||
// 这里只添加userId条件,避免生成重复的WHERE子句
|
||||
LambdaQueryWrapper<SysUser> lqw = Wrappers.lambdaQuery();
|
||||
lqw.eq(SysUser::getUserId, userId);
|
||||
lqw.eq(SysUser::getDelFlag, SystemConstants.NORMAL);
|
||||
lqw.eq(SysUser::getAccountType, "1"); // 教师账号类型
|
||||
List<SysTeacherVo> list = baseMapper.selectTeacherList(lqw);
|
||||
return CollUtil.isNotEmpty(list) ? list.get(0) : null;
|
||||
}
|
||||
@@ -214,11 +213,10 @@ public class SysTeacherServiceImpl implements ISysTeacherService {
|
||||
*/
|
||||
private LambdaQueryWrapper<SysUser> buildQueryWrapper(SysTeacherBo bo) {
|
||||
LambdaQueryWrapper<SysUser> lqw = Wrappers.lambdaQuery();
|
||||
|
||||
// 基础条件:未删除的教师用户
|
||||
lqw.eq(SysUser::getDelFlag, SystemConstants.NORMAL);
|
||||
lqw.eq(SysUser::getAccountType, "1"); // 教师账号类型
|
||||
|
||||
|
||||
// ⚠️ 注意:基础条件(del_flag='0' 和 account_type='1')已在Mapper的SQL中定义
|
||||
// 这里只添加动态查询条件,避免生成重复的WHERE子句
|
||||
|
||||
// 动态查询条件
|
||||
lqw.eq(ObjectUtil.isNotNull(bo.getUserId()), SysUser::getUserId, bo.getUserId());
|
||||
lqw.like(StrUtil.isNotBlank(bo.getUserName()), SysUser::getUserName, bo.getUserName());
|
||||
@@ -228,19 +226,18 @@ public class SysTeacherServiceImpl implements ISysTeacherService {
|
||||
lqw.eq(ObjectUtil.isNotNull(bo.getDeptId()), SysUser::getDeptId, bo.getDeptId());
|
||||
lqw.eq(StrUtil.isNotBlank(bo.getSex()), SysUser::getSex, bo.getSex());
|
||||
lqw.eq(StrUtil.isNotBlank(bo.getStatus()), SysUser::getStatus, bo.getStatus());
|
||||
|
||||
|
||||
// 搜索关键词(支持姓名、账号、手机号)
|
||||
if (StrUtil.isNotBlank(bo.getSearchKeyword())) {
|
||||
String keyword = bo.getSearchKeyword();
|
||||
lqw.and(wrapper -> wrapper
|
||||
.like(SysUser::getNickName, keyword)
|
||||
.or()
|
||||
.like(SysUser::getUserName, keyword)
|
||||
.or()
|
||||
.like(SysUser::getPhonenumber, keyword)
|
||||
);
|
||||
.like(SysUser::getNickName, keyword)
|
||||
.or()
|
||||
.like(SysUser::getUserName, keyword)
|
||||
.or()
|
||||
.like(SysUser::getPhonenumber, keyword));
|
||||
}
|
||||
|
||||
|
||||
return lqw;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user