提交修改
This commit is contained in:
1 parent
df38590dbf
commit
b0375f801c
18 files changed
+3625
-285
No files matched your search
+20
-11
@@ -41,29 +41,30 @@ public interface CwApprovalRecordMapper extends BaseMapperPlus<CwApprovalRecord,
|
||||
* @param nodeStatus 节点状态
|
||||
* @return 审批记录列表
|
||||
*/
|
||||
List<CwApprovalRecordVo> selectPendingByApproverId(@Param("approverId") Long approverId, @Param("nodeStatus") String nodeStatus);
|
||||
List<CwApprovalRecordVo> selectPendingByApproverId(@Param("approverId") Long approverId,
|
||||
@Param("nodeStatus") String nodeStatus);
|
||||
|
||||
/**
|
||||
* 根据审批人ID和节点编码查询审批记录
|
||||
*
|
||||
* @param approverId 审批人ID
|
||||
* @param nodeCode 节点编码
|
||||
* @param nodeCode 节点编码
|
||||
* @param nodeStatus 节点状态
|
||||
* @return 审批记录列表
|
||||
*/
|
||||
List<CwApprovalRecordVo> selectByApproverAndNode(@Param("approverId") Long approverId,
|
||||
@Param("nodeCode") String nodeCode,
|
||||
@Param("nodeStatus") String nodeStatus);
|
||||
@Param("nodeCode") String nodeCode,
|
||||
@Param("nodeStatus") String nodeStatus);
|
||||
|
||||
/**
|
||||
* 根据节点编码查询审批记录
|
||||
*
|
||||
* @param nodeCode 节点编码
|
||||
* @param nodeCode 节点编码
|
||||
* @param nodeStatus 节点状态
|
||||
* @return 审批记录列表
|
||||
*/
|
||||
List<CwApprovalRecordVo> selectByNode(@Param("nodeCode") String nodeCode,
|
||||
@Param("nodeStatus") String nodeStatus);
|
||||
@Param("nodeStatus") String nodeStatus);
|
||||
|
||||
/**
|
||||
* 查询财务审批节点的待审批记录(包含waiting和pending状态)
|
||||
@@ -91,11 +92,11 @@ public interface CwApprovalRecordMapper extends BaseMapperPlus<CwApprovalRecord,
|
||||
* 根据申报ID和节点编码查询审批记录
|
||||
*
|
||||
* @param applicationId 申报ID
|
||||
* @param nodeCode 节点编码
|
||||
* @param nodeCode 节点编码
|
||||
* @return 审批记录
|
||||
*/
|
||||
CwApprovalRecordVo selectByApplicationAndNode(@Param("applicationId") Long applicationId,
|
||||
@Param("nodeCode") String nodeCode);
|
||||
@Param("nodeCode") String nodeCode);
|
||||
|
||||
/**
|
||||
* 根据申报ID删除审批记录
|
||||
@@ -109,11 +110,11 @@ public interface CwApprovalRecordMapper extends BaseMapperPlus<CwApprovalRecord,
|
||||
* 查询当前审批节点记录
|
||||
*
|
||||
* @param applicationId 申报ID
|
||||
* @param nodeStatus 节点状态
|
||||
* @param nodeStatus 节点状态
|
||||
* @return 当前审批节点记录
|
||||
*/
|
||||
CwApprovalRecordVo selectCurrentApprovalNode(@Param("applicationId") Long applicationId,
|
||||
@Param("nodeStatus") String nodeStatus);
|
||||
@Param("nodeStatus") String nodeStatus);
|
||||
|
||||
/**
|
||||
* 批量插入审批记录
|
||||
@@ -127,7 +128,7 @@ public interface CwApprovalRecordMapper extends BaseMapperPlus<CwApprovalRecord,
|
||||
* 分页查询审批记录(支持关联查询)
|
||||
*
|
||||
* @param page 分页参数
|
||||
* @param bo 查询条件
|
||||
* @param bo 查询条件
|
||||
* @return 分页结果
|
||||
*/
|
||||
IPage<CwApprovalRecordVo> selectPageWithJoin(IPage<CwApprovalRecordVo> page, @Param("bo") CwApprovalRecordBo bo);
|
||||
@@ -140,4 +141,12 @@ public interface CwApprovalRecordMapper extends BaseMapperPlus<CwApprovalRecord,
|
||||
*/
|
||||
CwApprovalRecordVo selectByIdWithJoin(@Param("id") Long id);
|
||||
|
||||
/**
|
||||
* 查询具有院领导审批权限的用户列表
|
||||
* 查找具有 'cw:approval:leader' 权限的用户
|
||||
*
|
||||
* @return 可选审批人列表
|
||||
*/
|
||||
List<java.util.Map<String, Object>> selectAvailableApprovers();
|
||||
|
||||
}
|
||||
+103
-132
@@ -37,7 +37,6 @@ import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
import org.dromara.common.core.utils.SpringUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
|
||||
/**
|
||||
* 审批记录Service业务层处理
|
||||
@@ -56,9 +55,6 @@ public class CwApprovalRecordServiceImpl implements ICwApprovalRecordService {
|
||||
private final ISysUserService sysUserService;
|
||||
private final ISysDeptService sysDeptService;
|
||||
|
||||
@Autowired
|
||||
private JdbcTemplate jdbcTemplate;
|
||||
|
||||
/**
|
||||
* 根据主键查询审批记录
|
||||
*/
|
||||
@@ -90,7 +86,8 @@ public class CwApprovalRecordServiceImpl implements ICwApprovalRecordService {
|
||||
*/
|
||||
@Override
|
||||
public TableDataInfo<CwApprovalRecordVo> queryPageList(CwApprovalRecordBo bo, PageQuery pageQuery) {
|
||||
log.info("🔍 开始查询审批记录,查询参数:deptId={}, pageNum={}, pageSize={}", bo.getDeptId(), pageQuery.getPageNum(), pageQuery.getPageSize());
|
||||
log.info("🔍 开始查询审批记录,查询参数:deptId={}, pageNum={}, pageSize={}", bo.getDeptId(), pageQuery.getPageNum(),
|
||||
pageQuery.getPageSize());
|
||||
|
||||
// 🔧 使用新的关联查询方法(支持完整字段显示)
|
||||
Page<CwApprovalRecordVo> page = pageQuery.build();
|
||||
@@ -167,7 +164,7 @@ public class CwApprovalRecordServiceImpl implements ICwApprovalRecordService {
|
||||
for (int i = 0; i < Math.min(result.getRecords().size(), 2); i++) {
|
||||
CwApprovalRecordVo record = result.getRecords().get(i);
|
||||
log.info("📋 记录{}详情:id={}, 申报编号={}, 项目名称={}, 申报人={}, 部门={}, 总投资={}, 当前审批人={}, 状态={}",
|
||||
i+1, record.getId(), record.getApplicationNo(), record.getProjectName(),
|
||||
i + 1, record.getId(), record.getApplicationNo(), record.getProjectName(),
|
||||
record.getApplicantName(), record.getDeptName(), record.getTotalInvestment(),
|
||||
record.getCurrentApproverName(), record.getApprovalStatus());
|
||||
}
|
||||
@@ -196,7 +193,8 @@ public class CwApprovalRecordServiceImpl implements ICwApprovalRecordService {
|
||||
private LambdaQueryWrapper<CwApprovalRecord> buildQueryWrapper(CwApprovalRecordBo bo) {
|
||||
LambdaQueryWrapper<CwApprovalRecord> lqw = Wrappers.lambdaQuery();
|
||||
lqw.eq(bo.getApplicationId() != null, CwApprovalRecord::getApplicationId, bo.getApplicationId());
|
||||
lqw.eq(StringUtils.isNotBlank(bo.getApplicationNo()), CwApprovalRecord::getApplicationNo, bo.getApplicationNo());
|
||||
lqw.eq(StringUtils.isNotBlank(bo.getApplicationNo()), CwApprovalRecord::getApplicationNo,
|
||||
bo.getApplicationNo());
|
||||
lqw.eq(StringUtils.isNotBlank(bo.getNodeCode()), CwApprovalRecord::getNodeCode, bo.getNodeCode());
|
||||
lqw.eq(StringUtils.isNotBlank(bo.getNodeStatus()), CwApprovalRecord::getNodeStatus, bo.getNodeStatus());
|
||||
lqw.eq(bo.getApproverId() != null, CwApprovalRecord::getApproverId, bo.getApproverId());
|
||||
@@ -212,7 +210,8 @@ public class CwApprovalRecordServiceImpl implements ICwApprovalRecordService {
|
||||
if (currentDeptId != null) {
|
||||
// 查询该部门的项目申报ID列表
|
||||
lqw.inSql(CwApprovalRecord::getApplicationId,
|
||||
"SELECT id FROM cw_project_application WHERE department_id = " + currentDeptId + " AND deleted = 0");
|
||||
"SELECT id FROM cw_project_application WHERE department_id = " + currentDeptId
|
||||
+ " AND deleted = 0");
|
||||
|
||||
// 只显示部门审批节点的记录
|
||||
lqw.eq(CwApprovalRecord::getNodeCode, "dept_approve");
|
||||
@@ -234,7 +233,8 @@ public class CwApprovalRecordServiceImpl implements ICwApprovalRecordService {
|
||||
try {
|
||||
Long deptId = Long.valueOf(bo.getDeptId());
|
||||
lqw.in(CwApprovalRecord::getApplicationId,
|
||||
"SELECT id FROM cw_project_application WHERE department_id = " + deptId + " AND deleted = 0");
|
||||
"SELECT id FROM cw_project_application WHERE department_id = " + deptId
|
||||
+ " AND deleted = 0");
|
||||
} catch (NumberFormatException e) {
|
||||
log.warn("无效的部门ID格式:{}", bo.getDeptId());
|
||||
}
|
||||
@@ -245,11 +245,11 @@ public class CwApprovalRecordServiceImpl implements ICwApprovalRecordService {
|
||||
|
||||
// 其他查询条件 - 暂时注释掉,避免复杂的关联查询导致编译错误
|
||||
// if (StringUtils.isNotBlank(bo.getProjectName())) {
|
||||
// // 项目名称查询需要关联查询,暂时跳过
|
||||
// // 项目名称查询需要关联查询,暂时跳过
|
||||
// }
|
||||
|
||||
// if (StringUtils.isNotBlank(bo.getApplicantName())) {
|
||||
// // 申报人姓名查询需要关联查询,暂时跳过
|
||||
// // 申报人姓名查询需要关联查询,暂时跳过
|
||||
// }
|
||||
|
||||
if (StringUtils.isNotBlank(bo.getApproverName())) {
|
||||
@@ -304,8 +304,8 @@ public class CwApprovalRecordServiceImpl implements ICwApprovalRecordService {
|
||||
if (deptId != null) {
|
||||
// 通过关联查询,只显示本部门用户提交的申报对应的审批记录
|
||||
lqw.exists("SELECT 1 FROM cw_project_application a " +
|
||||
"WHERE a.id = cw_approval_record.application_id " +
|
||||
"AND a.department_id = " + deptId);
|
||||
"WHERE a.id = cw_approval_record.application_id " +
|
||||
"AND a.department_id = " + deptId);
|
||||
// 🔧 关键修复:部门领导也需要过滤为自己作为审批人的记录
|
||||
lqw.eq(CwApprovalRecord::getApproverId, currentUserId);
|
||||
log.debug("部门领导权限过滤完成:deptId={}, approverId={}", deptId, currentUserId);
|
||||
@@ -383,8 +383,8 @@ public class CwApprovalRecordServiceImpl implements ICwApprovalRecordService {
|
||||
// 查询当前用户已审批的记录(精确匹配已完成的状态)
|
||||
LambdaQueryWrapper<CwApprovalRecord> queryWrapper = Wrappers.lambdaQuery();
|
||||
queryWrapper.eq(CwApprovalRecord::getApproverId, currentUserId)
|
||||
.in(CwApprovalRecord::getNodeStatus, Arrays.asList("approved", "rejected", "returned"))
|
||||
.orderByDesc(CwApprovalRecord::getEndTime);
|
||||
.in(CwApprovalRecord::getNodeStatus, Arrays.asList("approved", "rejected", "returned"))
|
||||
.orderByDesc(CwApprovalRecord::getEndTime);
|
||||
|
||||
return baseMapper.selectList(queryWrapper);
|
||||
});
|
||||
@@ -544,8 +544,8 @@ public class CwApprovalRecordServiceImpl implements ICwApprovalRecordService {
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW)
|
||||
public Boolean createApprovalProcess(Long applicationId, String applicationNo,
|
||||
Long currentUserId, String currentUserName,
|
||||
Long currentDeptId, String currentTenantId) {
|
||||
Long currentUserId, String currentUserName,
|
||||
Long currentDeptId, String currentTenantId) {
|
||||
log.info("🚀 开始创建审批流程:applicationId={}, applicationNo={}", applicationId, applicationNo);
|
||||
log.info("📋 使用用户上下文:userId={}, userName={}, deptId={}, tenantId={}",
|
||||
currentUserId, currentUserName, currentDeptId, currentTenantId);
|
||||
@@ -565,15 +565,15 @@ public class CwApprovalRecordServiceImpl implements ICwApprovalRecordService {
|
||||
log.error("❌ 申报记录不存在:applicationId={}", applicationId);
|
||||
throw new RuntimeException("申报记录不存在");
|
||||
}
|
||||
log.info("✅ 成功获取申报信息:projectName={}, status={}", application.getProjectName(), application.getApprovalStatus());
|
||||
log.info("✅ 成功获取申报信息:projectName={}, status={}", application.getProjectName(),
|
||||
application.getApprovalStatus());
|
||||
|
||||
// 🔧 重要修复:清理该申报的旧审批记录(避免重复数据)
|
||||
log.info("🧹 开始清理申报ID={}的旧审批记录...", applicationId);
|
||||
try {
|
||||
int deletedCount = baseMapper.delete(
|
||||
Wrappers.<CwApprovalRecord>lambdaQuery()
|
||||
.eq(CwApprovalRecord::getApplicationId, applicationId)
|
||||
);
|
||||
Wrappers.<CwApprovalRecord>lambdaQuery()
|
||||
.eq(CwApprovalRecord::getApplicationId, applicationId));
|
||||
log.info("✅ 清理旧审批记录完成:删除{}条记录", deletedCount);
|
||||
} catch (Exception e) {
|
||||
log.error("❌ 清理旧审批记录失败:applicationId={}, error={}", applicationId, e.getMessage(), e);
|
||||
@@ -587,8 +587,8 @@ public class CwApprovalRecordServiceImpl implements ICwApprovalRecordService {
|
||||
|
||||
// 第1节点:部门审批(提交时只创建这一个记录)
|
||||
CwApprovalRecord deptRecord = createApprovalRecord(applicationId, applicationNo,
|
||||
"dept_approve", "部门审批", 1, "waiting",
|
||||
currentUserId, currentUserName, currentDeptId, currentTenantId);
|
||||
"dept_approve", "部门审批", 1, "waiting",
|
||||
currentUserId, currentUserName, currentDeptId, currentTenantId);
|
||||
records.add(deptRecord);
|
||||
log.info("✅ 创建部门审批记录:ID={}, 审批人={}", deptRecord.getId(), deptRecord.getApproverName());
|
||||
|
||||
@@ -602,8 +602,8 @@ public class CwApprovalRecordServiceImpl implements ICwApprovalRecordService {
|
||||
for (int i = 0; i < records.size(); i++) {
|
||||
CwApprovalRecord record = records.get(i);
|
||||
log.info("📋 记录{}详情: ID={}, ApplicationId={}, NodeCode={}, ApproverId={}, CreateBy={}, TenantId={}",
|
||||
i+1, record.getId(), record.getApplicationId(), record.getNodeCode(),
|
||||
record.getApproverId(), record.getCreateBy(), record.getTenantId());
|
||||
i + 1, record.getId(), record.getApplicationId(), record.getNodeCode(),
|
||||
record.getApproverId(), record.getCreateBy(), record.getTenantId());
|
||||
}
|
||||
|
||||
// 批量插入审批记录
|
||||
@@ -626,11 +626,10 @@ public class CwApprovalRecordServiceImpl implements ICwApprovalRecordService {
|
||||
try {
|
||||
// 直接使用Mapper在当前事务中更新,避免调用Service层的新事务
|
||||
int updateCount = applicationMapper.update(null,
|
||||
Wrappers.<CwProjectApplication>lambdaUpdate()
|
||||
.set(CwProjectApplication::getApprovalStatus, "approving")
|
||||
.set(CwProjectApplication::getUpdateTime, new Date())
|
||||
.eq(CwProjectApplication::getId, applicationId)
|
||||
);
|
||||
Wrappers.<CwProjectApplication>lambdaUpdate()
|
||||
.set(CwProjectApplication::getApprovalStatus, "approving")
|
||||
.set(CwProjectApplication::getUpdateTime, new Date())
|
||||
.eq(CwProjectApplication::getId, applicationId));
|
||||
|
||||
if (updateCount > 0) {
|
||||
log.info("✅ 申报状态直接更新成功:applicationId={} -> approving, 影响行数={}", applicationId, updateCount);
|
||||
@@ -673,10 +672,10 @@ public class CwApprovalRecordServiceImpl implements ICwApprovalRecordService {
|
||||
}
|
||||
|
||||
private CwApprovalRecord createApprovalRecord(Long applicationId, String applicationNo,
|
||||
String nodeCode, String nodeName,
|
||||
Integer nodeOrder, String nodeStatus,
|
||||
Long currentUserId, String currentUserName,
|
||||
Long currentDeptId, String currentTenantId) {
|
||||
String nodeCode, String nodeName,
|
||||
Integer nodeOrder, String nodeStatus,
|
||||
Long currentUserId, String currentUserName,
|
||||
Long currentDeptId, String currentTenantId) {
|
||||
CwApprovalRecord record = new CwApprovalRecord();
|
||||
|
||||
// 生成唯一ID(批量插入需要手动生成)
|
||||
@@ -709,7 +708,7 @@ public class CwApprovalRecordServiceImpl implements ICwApprovalRecordService {
|
||||
record.setCreateDept(currentDeptId);
|
||||
record.setTenantId(currentTenantId);
|
||||
|
||||
// 设置其他必需字段(为批量插入提供完整数据)
|
||||
// 设置其他必需字段(为批量插入提供完整数据)
|
||||
record.setIsDelegate(false);
|
||||
record.setIsOvertime(false);
|
||||
|
||||
@@ -748,7 +747,7 @@ public class CwApprovalRecordServiceImpl implements ICwApprovalRecordService {
|
||||
* 根据节点类型设置审批人
|
||||
*/
|
||||
private void setApproverByNodeCode(CwApprovalRecord record, String nodeCode,
|
||||
Long currentUserId, String currentUserName) {
|
||||
Long currentUserId, String currentUserName) {
|
||||
// 根据审批节点类型查找正确的审批人,而不是使用申报人
|
||||
try {
|
||||
switch (nodeCode) {
|
||||
@@ -875,12 +874,12 @@ public class CwApprovalRecordServiceImpl implements ICwApprovalRecordService {
|
||||
try {
|
||||
// SQL查询:查找该部门内具有project_dept_manage角色的用户
|
||||
String sql = "SELECT ur.user_id FROM sys_user_role ur " +
|
||||
"INNER JOIN sys_role r ON ur.role_id = r.role_id " +
|
||||
"INNER JOIN sys_user u ON ur.user_id = u.user_id " +
|
||||
"WHERE r.role_key = 'project_dept_manage' " +
|
||||
"AND u.dept_id = " + deptId + " " +
|
||||
"AND u.del_flag = 0 AND u.status = 0 " +
|
||||
"LIMIT 1";
|
||||
"INNER JOIN sys_role r ON ur.role_id = r.role_id " +
|
||||
"INNER JOIN sys_user u ON ur.user_id = u.user_id " +
|
||||
"WHERE r.role_key = 'project_dept_manage' " +
|
||||
"AND u.dept_id = " + deptId + " " +
|
||||
"AND u.del_flag = 0 AND u.status = 0 " +
|
||||
"LIMIT 1";
|
||||
|
||||
log.info("查找部门审批人SQL:{}", sql);
|
||||
|
||||
@@ -958,8 +957,8 @@ public class CwApprovalRecordServiceImpl implements ICwApprovalRecordService {
|
||||
// 更新当前审批记录
|
||||
CwApprovalRecordBo updateBo = new CwApprovalRecordBo();
|
||||
updateBo.setId(currentRecord.getId());
|
||||
updateBo.setNodeStatus("approve".equals(approveAction) ? "approved" :
|
||||
"reject".equals(approveAction) ? "rejected" : "returned");
|
||||
updateBo.setNodeStatus("approve".equals(approveAction) ? "approved"
|
||||
: "reject".equals(approveAction) ? "rejected" : "returned");
|
||||
updateBo.setApproveAction(approveAction);
|
||||
updateBo.setApproveOpinion(approveOpinion);
|
||||
updateBo.setEndTime(new Date());
|
||||
@@ -974,7 +973,7 @@ public class CwApprovalRecordServiceImpl implements ICwApprovalRecordService {
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("处理审批失败:applicationId={}, nodeCode={}, error={}",
|
||||
applicationId, nodeCode, e.getMessage(), e);
|
||||
applicationId, nodeCode, e.getMessage(), e);
|
||||
throw new RuntimeException("处理审批失败:" + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
@@ -1020,8 +1019,8 @@ public class CwApprovalRecordServiceImpl implements ICwApprovalRecordService {
|
||||
|
||||
// 根据节点类型创建对应的审批记录
|
||||
CwApprovalRecord newRecord = createApprovalRecordForNode(applicationId, application.getApplicationNo(),
|
||||
nextNodeCode, application.getCreateBy(), application.getApplicantName(),
|
||||
application.getDepartmentId(), LoginHelper.getTenantId());
|
||||
nextNodeCode, application.getCreateBy(), application.getApplicantName(),
|
||||
application.getDepartmentId(), LoginHelper.getTenantId());
|
||||
|
||||
if (newRecord != null) {
|
||||
// 插入新的审批记录
|
||||
@@ -1046,7 +1045,7 @@ public class CwApprovalRecordServiceImpl implements ICwApprovalRecordService {
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
log.error("启动下一个审批节点失败:applicationId={}, nodeCode={}, error={}",
|
||||
applicationId, nextNodeCode, e.getMessage(), e);
|
||||
applicationId, nextNodeCode, e.getMessage(), e);
|
||||
throw new RuntimeException("启动下一个审批节点失败:" + e.getMessage());
|
||||
}
|
||||
}
|
||||
@@ -1055,8 +1054,8 @@ public class CwApprovalRecordServiceImpl implements ICwApprovalRecordService {
|
||||
* 动态创建指定节点的审批记录
|
||||
*/
|
||||
private CwApprovalRecord createApprovalRecordForNode(Long applicationId, String applicationNo,
|
||||
String nodeCode, Long createBy, String createByName,
|
||||
Long deptId, String tenantId) {
|
||||
String nodeCode, Long createBy, String createByName,
|
||||
Long deptId, String tenantId) {
|
||||
try {
|
||||
String nodeName;
|
||||
Integer nodeOrder;
|
||||
@@ -1077,11 +1076,11 @@ public class CwApprovalRecordServiceImpl implements ICwApprovalRecordService {
|
||||
|
||||
// 创建审批记录
|
||||
CwApprovalRecord record = createApprovalRecord(applicationId, applicationNo,
|
||||
nodeCode, nodeName, nodeOrder, "waiting",
|
||||
createBy, createByName, deptId, tenantId);
|
||||
nodeCode, nodeName, nodeOrder, "waiting",
|
||||
createBy, createByName, deptId, tenantId);
|
||||
|
||||
log.info("✅ 动态创建审批记录:nodeCode={}, nodeName={}, approverId={}",
|
||||
nodeCode, nodeName, record.getApproverId());
|
||||
nodeCode, nodeName, record.getApproverId());
|
||||
|
||||
return record;
|
||||
} catch (Exception e) {
|
||||
@@ -1124,7 +1123,7 @@ public class CwApprovalRecordServiceImpl implements ICwApprovalRecordService {
|
||||
return checkApprovalPermission(applicationId, "dept_approve");
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* 获取可选审批人列表(院领导)
|
||||
* 修改为基于权限角色查找:查找具有cw:approval:leader权限的用户
|
||||
*/
|
||||
@@ -1135,46 +1134,22 @@ public class CwApprovalRecordServiceImpl implements ICwApprovalRecordService {
|
||||
List<Map<String, Object>> approvers = new ArrayList<>();
|
||||
|
||||
try {
|
||||
// 使用原生SQL查询具有cw:approval:leader权限的用户
|
||||
String sql = """
|
||||
SELECT DISTINCT
|
||||
u.user_id,
|
||||
u.user_name,
|
||||
u.nick_name,
|
||||
COALESCE(d.dept_name, '未分配部门') as dept_name,
|
||||
COALESCE(d.dept_id, 0) as dept_id
|
||||
FROM sys_user u
|
||||
LEFT JOIN sys_dept d ON u.dept_id = d.dept_id
|
||||
INNER JOIN sys_user_role ur ON u.user_id = ur.user_id
|
||||
INNER JOIN sys_role r ON ur.role_id = r.role_id
|
||||
INNER JOIN sys_role_menu rm ON r.role_id = rm.role_id
|
||||
INNER JOIN sys_menu m ON rm.menu_id = m.menu_id
|
||||
WHERE m.perms = 'cw:approval:leader'
|
||||
AND u.status = '0'
|
||||
AND u.del_flag = '0'
|
||||
AND r.status = '0'
|
||||
ORDER BY u.user_name
|
||||
""";
|
||||
// 🔧 使用Mapper方法查询具有cw:approval:leader权限的用户
|
||||
log.info("执行Mapper查询查找具有cw:approval:leader权限的用户");
|
||||
|
||||
log.info("执行权限查询SQL查找具有cw:approval:leader权限的用户");
|
||||
// 直接调用Mapper方法,不需要手动转换结果
|
||||
List<Map<String, Object>> results = baseMapper.selectAvailableApprovers();
|
||||
|
||||
// 执行SQL查询
|
||||
List<Map<String, Object>> results = jdbcTemplate.queryForList(sql);
|
||||
log.info("Mapper查询结果:找到 {} 个具有院领导审批权限的用户", results.size());
|
||||
|
||||
log.info("SQL查询结果:找到 {} 个具有院领导审批权限的用户", results.size());
|
||||
|
||||
// 转换查询结果为返回格式
|
||||
for (Map<String, Object> row : results) {
|
||||
Map<String, Object> approver = new HashMap<>();
|
||||
approver.put("userId", row.get("user_id"));
|
||||
approver.put("userName", row.get("user_name"));
|
||||
approver.put("nickName", row.get("nick_name"));
|
||||
approver.put("deptName", row.get("dept_name"));
|
||||
approver.put("deptId", row.get("dept_id"));
|
||||
approvers.add(approver);
|
||||
// 直接使用查询结果,Mapper已经处理了字段映射
|
||||
approvers.addAll(results);
|
||||
|
||||
// 记录查询到的审批人信息
|
||||
for (Map<String, Object> approver : approvers) {
|
||||
log.info("添加院领导审批人: userId={}, userName={}, nickName={}, deptName={}",
|
||||
row.get("user_id"), row.get("user_name"), row.get("nick_name"), row.get("dept_name"));
|
||||
approver.get("userId"), approver.get("userName"), approver.get("nickName"),
|
||||
approver.get("deptName"));
|
||||
}
|
||||
|
||||
// 如果基于权限查询没有找到用户,使用原有的部门查询作为备选方案
|
||||
@@ -1230,11 +1205,10 @@ public class CwApprovalRecordServiceImpl implements ICwApprovalRecordService {
|
||||
|
||||
// 1. 查找当前用户的待审批记录
|
||||
CwApprovalRecord currentRecord = baseMapper.selectOne(
|
||||
Wrappers.lambdaQuery(CwApprovalRecord.class)
|
||||
.eq(CwApprovalRecord::getApplicationId, applicationId)
|
||||
.eq(CwApprovalRecord::getApproverId, currentUserId)
|
||||
.eq(CwApprovalRecord::getNodeStatus, "waiting")
|
||||
);
|
||||
Wrappers.lambdaQuery(CwApprovalRecord.class)
|
||||
.eq(CwApprovalRecord::getApplicationId, applicationId)
|
||||
.eq(CwApprovalRecord::getApproverId, currentUserId)
|
||||
.eq(CwApprovalRecord::getNodeStatus, "waiting"));
|
||||
|
||||
if (currentRecord == null) {
|
||||
throw new RuntimeException("未找到待审批记录或您没有审批权限");
|
||||
@@ -1263,7 +1237,7 @@ public class CwApprovalRecordServiceImpl implements ICwApprovalRecordService {
|
||||
throw new RuntimeException("更新审批记录失败");
|
||||
}
|
||||
|
||||
// 3. 更新项目申请状态
|
||||
// 3. 更新项目申请状态
|
||||
String newStatus;
|
||||
if ("approve".equals(approveAction)) {
|
||||
// 分管领导审批通过,整个审批流程完成
|
||||
@@ -1292,7 +1266,8 @@ public class CwApprovalRecordServiceImpl implements ICwApprovalRecordService {
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void financeApproval(Long applicationId, String approveAction, String approveOpinion, Long selectedApproverId) {
|
||||
public void financeApproval(Long applicationId, String approveAction, String approveOpinion,
|
||||
Long selectedApproverId) {
|
||||
Long currentUserId = LoginHelper.getUserId();
|
||||
log.info("🔍 财务审批开始:applicationId={}, userId={}, action={}, selectedApproverId={}",
|
||||
applicationId, currentUserId, approveAction, selectedApproverId);
|
||||
@@ -1306,24 +1281,22 @@ public class CwApprovalRecordServiceImpl implements ICwApprovalRecordService {
|
||||
log.info("🔍 查询财务审批记录:applicationId={}, nodeCode=finance_approve, nodeStatus=waiting", applicationId);
|
||||
|
||||
List<CwApprovalRecord> records = baseMapper.selectList(
|
||||
Wrappers.lambdaQuery(CwApprovalRecord.class)
|
||||
.eq(CwApprovalRecord::getApplicationId, applicationId)
|
||||
.eq(CwApprovalRecord::getNodeCode, "finance_approve")
|
||||
.eq(CwApprovalRecord::getNodeStatus, "waiting")
|
||||
.orderByDesc(CwApprovalRecord::getCreateTime)
|
||||
);
|
||||
Wrappers.lambdaQuery(CwApprovalRecord.class)
|
||||
.eq(CwApprovalRecord::getApplicationId, applicationId)
|
||||
.eq(CwApprovalRecord::getNodeCode, "finance_approve")
|
||||
.eq(CwApprovalRecord::getNodeStatus, "waiting")
|
||||
.orderByDesc(CwApprovalRecord::getCreateTime));
|
||||
|
||||
if (records.isEmpty()) {
|
||||
log.error("❌ 未找到财务审批记录:applicationId={}", applicationId);
|
||||
// 查询所有相关记录用于调试
|
||||
List<CwApprovalRecord> allRecords = baseMapper.selectList(
|
||||
Wrappers.lambdaQuery(CwApprovalRecord.class)
|
||||
.eq(CwApprovalRecord::getApplicationId, applicationId)
|
||||
);
|
||||
Wrappers.lambdaQuery(CwApprovalRecord.class)
|
||||
.eq(CwApprovalRecord::getApplicationId, applicationId));
|
||||
log.error("📋 该申请的所有审批记录:{}", allRecords.size());
|
||||
for (CwApprovalRecord record : allRecords) {
|
||||
log.error("📋 记录详情:nodeCode={}, nodeStatus={}, approverId={}",
|
||||
record.getNodeCode(), record.getNodeStatus(), record.getApproverId());
|
||||
record.getNodeCode(), record.getNodeStatus(), record.getApproverId());
|
||||
}
|
||||
throw new RuntimeException("未找到待审批记录或该申请已被处理");
|
||||
}
|
||||
@@ -1335,7 +1308,8 @@ public class CwApprovalRecordServiceImpl implements ICwApprovalRecordService {
|
||||
}
|
||||
|
||||
log.info("✅ 找到财务审批记录:recordId={}, nodeCode={}, nodeStatus={}, approverId={}",
|
||||
currentRecord.getId(), currentRecord.getNodeCode(), currentRecord.getNodeStatus(), currentRecord.getApproverId());
|
||||
currentRecord.getId(), currentRecord.getNodeCode(), currentRecord.getNodeStatus(),
|
||||
currentRecord.getApproverId());
|
||||
|
||||
// 3. 更新当前审批记录
|
||||
Date now = new Date();
|
||||
@@ -1392,23 +1366,21 @@ public class CwApprovalRecordServiceImpl implements ICwApprovalRecordService {
|
||||
private void updateLeaderApproverAndStart(Long applicationId, Long selectedApproverId) {
|
||||
// 1. 查找分管领导审批记录(先按waiting状态查找)
|
||||
CwApprovalRecord leaderRecord = baseMapper.selectOne(
|
||||
Wrappers.lambdaQuery(CwApprovalRecord.class)
|
||||
.eq(CwApprovalRecord::getApplicationId, applicationId)
|
||||
.eq(CwApprovalRecord::getNodeCode, "leader_approve")
|
||||
.eq(CwApprovalRecord::getNodeStatus, "waiting")
|
||||
);
|
||||
Wrappers.lambdaQuery(CwApprovalRecord.class)
|
||||
.eq(CwApprovalRecord::getApplicationId, applicationId)
|
||||
.eq(CwApprovalRecord::getNodeCode, "leader_approve")
|
||||
.eq(CwApprovalRecord::getNodeStatus, "waiting"));
|
||||
|
||||
// 2. 如果waiting状态未找到,尝试查找pending状态(兼容处理)
|
||||
if (leaderRecord == null) {
|
||||
leaderRecord = baseMapper.selectOne(
|
||||
Wrappers.lambdaQuery(CwApprovalRecord.class)
|
||||
.eq(CwApprovalRecord::getApplicationId, applicationId)
|
||||
.eq(CwApprovalRecord::getNodeCode, "leader_approve")
|
||||
.eq(CwApprovalRecord::getNodeStatus, "pending")
|
||||
);
|
||||
Wrappers.lambdaQuery(CwApprovalRecord.class)
|
||||
.eq(CwApprovalRecord::getApplicationId, applicationId)
|
||||
.eq(CwApprovalRecord::getNodeCode, "leader_approve")
|
||||
.eq(CwApprovalRecord::getNodeStatus, "pending"));
|
||||
}
|
||||
|
||||
// 3. 如果仍未找到,动态创建分管领导审批记录
|
||||
// 3. 如果仍未找到,动态创建分管领导审批记录
|
||||
if (leaderRecord == null) {
|
||||
log.warn("未找到分管领导审批记录,开始动态创建:applicationId={}", applicationId);
|
||||
|
||||
@@ -1426,17 +1398,16 @@ public class CwApprovalRecordServiceImpl implements ICwApprovalRecordService {
|
||||
|
||||
// 创建分管领导审批记录
|
||||
leaderRecord = createApprovalRecord(
|
||||
applicationId,
|
||||
applicationVo.getApplicationNo(),
|
||||
"leader_approve",
|
||||
"分管领导审批",
|
||||
3, // leader_approve 节点顺序
|
||||
"waiting",
|
||||
currentUserId,
|
||||
currentUserName,
|
||||
currentDeptId,
|
||||
currentTenantId
|
||||
);
|
||||
applicationId,
|
||||
applicationVo.getApplicationNo(),
|
||||
"leader_approve",
|
||||
"分管领导审批",
|
||||
3, // leader_approve 节点顺序
|
||||
"waiting",
|
||||
currentUserId,
|
||||
currentUserName,
|
||||
currentDeptId,
|
||||
currentTenantId);
|
||||
|
||||
// 保存到数据库
|
||||
int result = baseMapper.insert(leaderRecord);
|
||||
@@ -1447,7 +1418,7 @@ public class CwApprovalRecordServiceImpl implements ICwApprovalRecordService {
|
||||
log.info("✅ 动态创建分管领导审批记录成功:recordId={}", leaderRecord.getId());
|
||||
}
|
||||
|
||||
// 2. 获取选择的院领导信息
|
||||
// 2. 获取选择的院领导信息
|
||||
try {
|
||||
SysUserVo selectedUser = sysUserService.selectUserById(selectedApproverId);
|
||||
if (selectedUser == null) {
|
||||
@@ -1470,12 +1441,12 @@ public class CwApprovalRecordServiceImpl implements ICwApprovalRecordService {
|
||||
throw new RuntimeException("更新分管领导审批记录失败");
|
||||
}
|
||||
|
||||
log.info("✅ 成功指定院领导审批人:userId={}, userName={}",
|
||||
log.info("✅ 成功指定院领导审批人:userId={}, userName={}",
|
||||
selectedApproverId, selectedUser.getUserName());
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("❌ 更新分管领导审批人失败:applicationId={}, selectedApproverId={}, error={}",
|
||||
applicationId, selectedApproverId, e.getMessage(), e);
|
||||
applicationId, selectedApproverId, e.getMessage(), e);
|
||||
throw new RuntimeException("指定院领导审批人失败:" + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -234,4 +234,25 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
ORDER BY ar.create_time DESC
|
||||
</select>
|
||||
|
||||
<!-- 查询具有院领导审批权限的用户列表 -->
|
||||
<select id="selectAvailableApprovers" resultType="java.util.Map">
|
||||
SELECT DISTINCT
|
||||
u.user_id as userId,
|
||||
u.user_name as userName,
|
||||
u.nick_name as nickName,
|
||||
COALESCE(d.dept_name, '未分配部门') as deptName,
|
||||
COALESCE(d.dept_id, 0) as deptId
|
||||
FROM sys_user u
|
||||
LEFT JOIN sys_dept d ON u.dept_id = d.dept_id
|
||||
INNER JOIN sys_user_role ur ON u.user_id = ur.user_id
|
||||
INNER JOIN sys_role r ON ur.role_id = r.role_id
|
||||
INNER JOIN sys_role_menu rm ON r.role_id = rm.role_id
|
||||
INNER JOIN sys_menu m ON rm.menu_id = m.menu_id
|
||||
WHERE m.perms = 'cw:approval:leader'
|
||||
AND u.status = '0'
|
||||
AND u.del_flag = '0'
|
||||
AND r.status = '0'
|
||||
ORDER BY u.user_name
|
||||
</select>
|
||||
|
||||
</mapper>
|
||||
+188
-141
@@ -70,6 +70,7 @@ public class JcbtScholarshipApplicationServiceImpl implements IJcbtScholarshipAp
|
||||
* 查询奖学金申请记录详情
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public JcbtScholarshipApplicationVo queryById(Long id) {
|
||||
return baseMapper.selectByIdWithRelations(id);
|
||||
}
|
||||
@@ -78,10 +79,13 @@ public class JcbtScholarshipApplicationServiceImpl implements IJcbtScholarshipAp
|
||||
* 查询奖学金申请记录分页列表
|
||||
*/
|
||||
@Override
|
||||
public TableDataInfo<JcbtScholarshipApplicationVo> queryPageList(JcbtScholarshipApplicationBo bo, PageQuery pageQuery) {
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public TableDataInfo<JcbtScholarshipApplicationVo> queryPageList(JcbtScholarshipApplicationBo bo,
|
||||
PageQuery pageQuery) {
|
||||
LambdaQueryWrapper<JcbtScholarshipApplication> lqw = buildQueryWrapper(bo);
|
||||
// 使用自定义分页查询(包含关联表信息)
|
||||
Page<JcbtScholarshipApplicationVo> result = baseMapper.selectJcbtScholarshipApplicationPage(pageQuery.build(), lqw);
|
||||
Page<JcbtScholarshipApplicationVo> result = baseMapper.selectJcbtScholarshipApplicationPage(pageQuery.build(),
|
||||
lqw);
|
||||
return TableDataInfo.build(result);
|
||||
}
|
||||
|
||||
@@ -89,6 +93,7 @@ public class JcbtScholarshipApplicationServiceImpl implements IJcbtScholarshipAp
|
||||
* 查询奖学金申请记录列表
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public List<JcbtScholarshipApplicationVo> queryList(JcbtScholarshipApplicationBo bo) {
|
||||
LambdaQueryWrapper<JcbtScholarshipApplication> lqw = buildQueryWrapper(bo);
|
||||
return baseMapper.selectVoList(lqw);
|
||||
@@ -98,18 +103,21 @@ public class JcbtScholarshipApplicationServiceImpl implements IJcbtScholarshipAp
|
||||
Map<String, Object> params = bo.getParams();
|
||||
LambdaQueryWrapper<JcbtScholarshipApplication> lqw = Wrappers.lambdaQuery();
|
||||
lqw.eq(ObjectUtil.isNotNull(bo.getBatchId()), JcbtScholarshipApplication::getBatchId, bo.getBatchId());
|
||||
lqw.eq(ObjectUtil.isNotNull(bo.getScholarshipTypeId()), JcbtScholarshipApplication::getScholarshipTypeId, bo.getScholarshipTypeId());
|
||||
lqw.eq(ObjectUtil.isNotNull(bo.getScholarshipTypeId()), JcbtScholarshipApplication::getScholarshipTypeId,
|
||||
bo.getScholarshipTypeId());
|
||||
lqw.eq(StringUtils.isNotBlank(bo.getStudentNo()), JcbtScholarshipApplication::getStudentNo, bo.getStudentNo());
|
||||
lqw.like(StringUtils.isNotBlank(bo.getStudentName()), JcbtScholarshipApplication::getStudentName, bo.getStudentName());
|
||||
lqw.like(StringUtils.isNotBlank(bo.getStudentName()), JcbtScholarshipApplication::getStudentName,
|
||||
bo.getStudentName());
|
||||
lqw.eq(ObjectUtil.isNotNull(bo.getStudentId()), JcbtScholarshipApplication::getStudentId, bo.getStudentId());
|
||||
lqw.eq(ObjectUtil.isNotNull(bo.getDeptId()), JcbtScholarshipApplication::getDeptId, bo.getDeptId());
|
||||
lqw.eq(ObjectUtil.isNotNull(bo.getClassId()), JcbtScholarshipApplication::getClassId, bo.getClassId());
|
||||
// 已删除 applicantType 和 applicantId 字段
|
||||
lqw.eq(StringUtils.isNotBlank(bo.getStatus()), JcbtScholarshipApplication::getCurrentStatus, bo.getStatus());
|
||||
// 支持前端 applicationStatus 查询参数
|
||||
lqw.eq(StringUtils.isNotBlank(bo.getApplicationStatus()), JcbtScholarshipApplication::getCurrentStatus, bo.getApplicationStatus());
|
||||
lqw.eq(StringUtils.isNotBlank(bo.getApplicationStatus()), JcbtScholarshipApplication::getCurrentStatus,
|
||||
bo.getApplicationStatus());
|
||||
lqw.between(params.get("beginCreateTime") != null && params.get("endCreateTime") != null,
|
||||
JcbtScholarshipApplication::getCreateTime, params.get("beginCreateTime"), params.get("endCreateTime"));
|
||||
JcbtScholarshipApplication::getCreateTime, params.get("beginCreateTime"), params.get("endCreateTime"));
|
||||
// 注意:排序在XML中处理,避免SQL语法错误
|
||||
// lqw.orderByDesc(JcbtScholarshipApplication::getCreateTime);
|
||||
return lqw;
|
||||
@@ -122,7 +130,8 @@ public class JcbtScholarshipApplicationServiceImpl implements IJcbtScholarshipAp
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public Boolean insertByBo(JcbtScholarshipApplicationBo bo) {
|
||||
// 检查申请资格
|
||||
Map<String, Object> eligibilityCheck = checkStudentEligibility(bo.getStudentId(), bo.getBatchId(), bo.getScholarshipTypeId());
|
||||
Map<String, Object> eligibilityCheck = checkStudentEligibility(bo.getStudentId(), bo.getBatchId(),
|
||||
bo.getScholarshipTypeId());
|
||||
if (!(Boolean) eligibilityCheck.get("eligible")) {
|
||||
throw new RuntimeException((String) eligibilityCheck.get("message"));
|
||||
}
|
||||
@@ -254,15 +263,14 @@ public class JcbtScholarshipApplicationServiceImpl implements IJcbtScholarshipAp
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public Boolean batchSubmitApplicationsByTeacher(Long batchId, Long scholarshipTypeId, Long classId,
|
||||
List<JcbtScholarshipApplicationBo> studentApplications) {
|
||||
List<JcbtScholarshipApplicationBo> studentApplications) {
|
||||
// 检查班级名额 - 使用和前端一致的查询方法
|
||||
log.info("开始检查班级名额 - 批次ID: {}, 奖学金类型ID: {}, 班级ID: {}, 申请人数: {}",
|
||||
batchId, scholarshipTypeId, classId, studentApplications.size());
|
||||
|
||||
// 使用和前端getScholarshipTypesWithQuota一致的查询方法
|
||||
JcbtScholarshipQuotaVo classQuota = quotaService.selectClassQuota(classId, scholarshipTypeId, batchId);
|
||||
log.info("班级名额查询结果: {}", classQuota != null ?
|
||||
String.format("ID=%s, 总名额=%s, 已用=%s, 可用=%s, 状态=%s",
|
||||
log.info("班级名额查询结果: {}", classQuota != null ? String.format("ID=%s, 总名额=%s, 已用=%s, 可用=%s, 状态=%s",
|
||||
classQuota.getId(), classQuota.getTotalQuota(), classQuota.getUsedQuota(),
|
||||
classQuota.getAvailableQuota(), classQuota.getStatus()) : "null");
|
||||
|
||||
@@ -306,7 +314,8 @@ public class JcbtScholarshipApplicationServiceImpl implements IJcbtScholarshipAp
|
||||
if (classQuota != null) {
|
||||
// 有班级名额分配,更新班级名额
|
||||
log.info("更新班级名额使用情况 - ID: {}, 原已用: {}, 原可用: {}, 新增申请: {}",
|
||||
classQuota.getId(), classQuota.getUsedQuota(), classQuota.getAvailableQuota(), studentApplications.size());
|
||||
classQuota.getId(), classQuota.getUsedQuota(), classQuota.getAvailableQuota(),
|
||||
studentApplications.size());
|
||||
|
||||
// 注意:这里需要调用全校名额表的更新方法,而不是班级名额表的方法
|
||||
quotaService.updateQuotaUsage(classQuota.getId(), studentApplications.size());
|
||||
@@ -334,6 +343,7 @@ public class JcbtScholarshipApplicationServiceImpl implements IJcbtScholarshipAp
|
||||
* 查询班主任负责班级的申请记录
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public List<JcbtScholarshipApplicationVo> queryApplicationsByApplicant(Long applicantId, Long batchId) {
|
||||
// TODO: 重新设计查询逻辑,因为applicantId字段已删除
|
||||
// 可能需要通过班级ID或其他方式查询班主任负责的申请记录
|
||||
@@ -344,6 +354,7 @@ public class JcbtScholarshipApplicationServiceImpl implements IJcbtScholarshipAp
|
||||
* 查询班级的申请记录
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public List<JcbtScholarshipApplicationVo> queryApplicationsByClass(Long classId, Long batchId) {
|
||||
return baseMapper.selectApplicationsByClass(classId, batchId);
|
||||
}
|
||||
@@ -352,6 +363,7 @@ public class JcbtScholarshipApplicationServiceImpl implements IJcbtScholarshipAp
|
||||
* 查询待审核的申请记录
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public List<JcbtScholarshipApplicationVo> queryPendingApplications(Long reviewerId, String status) {
|
||||
return baseMapper.selectPendingApplications(reviewerId, status);
|
||||
}
|
||||
@@ -360,6 +372,7 @@ public class JcbtScholarshipApplicationServiceImpl implements IJcbtScholarshipAp
|
||||
* 检查学生申请资格和限制
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public Map<String, Object> checkStudentEligibility(Long studentId, Long batchId, Long scholarshipTypeId) {
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
|
||||
@@ -383,7 +396,7 @@ public class JcbtScholarshipApplicationServiceImpl implements IJcbtScholarshipAp
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public Boolean batchReviewApplications(List<Long> applicationIds, String status, Long reviewerId,
|
||||
String reviewerName, String reviewComment) {
|
||||
String reviewerName, String reviewComment) {
|
||||
return baseMapper.batchUpdateStatus(applicationIds, status, reviewerId, reviewerName, reviewComment) > 0;
|
||||
}
|
||||
|
||||
@@ -429,6 +442,7 @@ public class JcbtScholarshipApplicationServiceImpl implements IJcbtScholarshipAp
|
||||
* 获取申请统计数据
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public Map<String, Object> getApplicationStatistics(Long batchId, Long deptId) {
|
||||
List<JcbtScholarshipApplicationVo> statistics = baseMapper.selectApplicationStatistics(batchId, deptId);
|
||||
|
||||
@@ -443,6 +457,7 @@ public class JcbtScholarshipApplicationServiceImpl implements IJcbtScholarshipAp
|
||||
* 查询可申请的奖学金类型列表
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public List<Map<String, Object>> queryAvailableScholarshipTypes(Long classId, Long batchId) {
|
||||
// 查询该班级在该批次的名额分配情况
|
||||
List<JcbtScholarshipClassQuotaVo> quotas = classQuotaService.queryQuotasByClass(classId, batchId);
|
||||
@@ -466,6 +481,7 @@ public class JcbtScholarshipApplicationServiceImpl implements IJcbtScholarshipAp
|
||||
* 获取班级名额使用情况
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public Map<String, Object> getClassQuotaUsage(Long classId, Long batchId) {
|
||||
List<JcbtScholarshipClassQuotaVo> quotas = classQuotaService.queryQuotasByClass(classId, batchId);
|
||||
|
||||
@@ -485,7 +501,7 @@ public class JcbtScholarshipApplicationServiceImpl implements IJcbtScholarshipAp
|
||||
|
||||
// ========== 班主任申请专用接口实现 ==========
|
||||
|
||||
/**
|
||||
/**
|
||||
* 根据班主任用户ID获取完整的班级信息
|
||||
* 自包含方法,避免跨模块调用,直接使用SQL查询
|
||||
*/
|
||||
@@ -493,26 +509,26 @@ public class JcbtScholarshipApplicationServiceImpl implements IJcbtScholarshipAp
|
||||
try {
|
||||
// 使用自定义SQL一次性关联查询所有需要的信息
|
||||
String sql = """
|
||||
SELECT
|
||||
cm.id as class_id,
|
||||
cm.class_name,
|
||||
cm.class_code,
|
||||
cm.grade,
|
||||
cm.college_id,
|
||||
cm.college_name,
|
||||
cm.major_id,
|
||||
cm.major_name,
|
||||
cm.class_teacher_id,
|
||||
cm.class_teacher_name,
|
||||
cm.current_student_count,
|
||||
cm.class_status,
|
||||
cm.class_type
|
||||
FROM xg_class_msg cm
|
||||
WHERE cm.class_teacher_id = ?
|
||||
AND cm.deleted = 0
|
||||
AND cm.class_status = '1'
|
||||
ORDER BY cm.grade DESC, cm.class_name ASC
|
||||
""";
|
||||
SELECT
|
||||
cm.id as class_id,
|
||||
cm.class_name,
|
||||
cm.class_code,
|
||||
cm.grade,
|
||||
cm.college_id,
|
||||
cm.college_name,
|
||||
cm.major_id,
|
||||
cm.major_name,
|
||||
cm.class_teacher_id,
|
||||
cm.class_teacher_name,
|
||||
cm.current_student_count,
|
||||
cm.class_status,
|
||||
cm.class_type
|
||||
FROM xg_class_msg cm
|
||||
WHERE cm.class_teacher_id = ?
|
||||
AND cm.deleted = 0
|
||||
AND cm.class_status = '1'
|
||||
ORDER BY cm.grade DESC, cm.class_name ASC
|
||||
""";
|
||||
|
||||
// 执行查询
|
||||
List<Map<String, Object>> result = jdbcTemplate.queryForList(sql, teacherId);
|
||||
@@ -530,6 +546,7 @@ public class JcbtScholarshipApplicationServiceImpl implements IJcbtScholarshipAp
|
||||
* 重构后的获取班级信息方法 - 自包含,无跨模块依赖
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public Map<String, Object> getClassInfoByTeacher(Long userId) {
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
|
||||
@@ -582,8 +599,9 @@ public class JcbtScholarshipApplicationServiceImpl implements IJcbtScholarshipAp
|
||||
/**
|
||||
* 从Map构建班级结果信息
|
||||
*/
|
||||
private void buildClassResultFromMap(Map<String, Object> result, Long teacherId, String teacherName, Map<String, Object> classInfo) {
|
||||
result.put("teacherId", teacherId.toString());
|
||||
private void buildClassResultFromMap(Map<String, Object> result, Long teacherId, String teacherName,
|
||||
Map<String, Object> classInfo) {
|
||||
result.put("teacherId", teacherId.toString());
|
||||
result.put("teacherName", teacherName);
|
||||
result.put("classId", classInfo.get("class_id") != null ? classInfo.get("class_id").toString() : "");
|
||||
result.put("className", (String) classInfo.get("class_name"));
|
||||
@@ -613,36 +631,37 @@ public class JcbtScholarshipApplicationServiceImpl implements IJcbtScholarshipAp
|
||||
return option;
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* 确认选择班级(当用户从多个班级中选择一个时调用)
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public Map<String, Object> confirmClassSelection(Long teacherId, Long classId) {
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
|
||||
try {
|
||||
// 验证该班级确实属于该老师 - 使用自包含查询
|
||||
String sql = """
|
||||
SELECT
|
||||
cm.id as class_id,
|
||||
cm.class_name,
|
||||
cm.class_code,
|
||||
cm.grade,
|
||||
cm.college_id,
|
||||
cm.college_name,
|
||||
cm.major_id,
|
||||
cm.major_name,
|
||||
cm.class_teacher_id,
|
||||
cm.class_teacher_name,
|
||||
cm.current_student_count,
|
||||
cm.class_status,
|
||||
cm.class_type
|
||||
FROM xg_class_msg cm
|
||||
WHERE cm.class_teacher_id = ?
|
||||
AND cm.id = ?
|
||||
AND cm.deleted = 0
|
||||
AND cm.class_status = '1'
|
||||
""";
|
||||
SELECT
|
||||
cm.id as class_id,
|
||||
cm.class_name,
|
||||
cm.class_code,
|
||||
cm.grade,
|
||||
cm.college_id,
|
||||
cm.college_name,
|
||||
cm.major_id,
|
||||
cm.major_name,
|
||||
cm.class_teacher_id,
|
||||
cm.class_teacher_name,
|
||||
cm.current_student_count,
|
||||
cm.class_status,
|
||||
cm.class_type
|
||||
FROM xg_class_msg cm
|
||||
WHERE cm.class_teacher_id = ?
|
||||
AND cm.id = ?
|
||||
AND cm.deleted = 0
|
||||
AND cm.class_status = '1'
|
||||
""";
|
||||
|
||||
List<Map<String, Object>> classList = jdbcTemplate.queryForList(sql, teacherId, classId);
|
||||
|
||||
@@ -663,38 +682,39 @@ public class JcbtScholarshipApplicationServiceImpl implements IJcbtScholarshipAp
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* 获取班级学生列表(用于勾选)- 使用自包含查询
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public List<Map<String, Object>> getClassStudents(Long classId) {
|
||||
List<Map<String, Object>> students = new ArrayList<>();
|
||||
|
||||
try {
|
||||
// 使用自包含查询获取学生列表,关联班级表获取学院和专业信息
|
||||
String sql = """
|
||||
SELECT
|
||||
sm.id,
|
||||
sm.student_no,
|
||||
sm.name,
|
||||
sm.gender,
|
||||
sm.phone,
|
||||
sm.email,
|
||||
sm.student_status,
|
||||
cm.college_id,
|
||||
cm.college_name,
|
||||
cm.major_id,
|
||||
cm.major_name,
|
||||
cm.class_name,
|
||||
cm.grade
|
||||
FROM xg_student_msg sm
|
||||
LEFT JOIN xg_class_msg cm ON sm.class_id = cm.id
|
||||
WHERE sm.class_id = ?
|
||||
AND sm.deleted = 0
|
||||
AND sm.student_status = '1'
|
||||
AND (cm.deleted IS NULL OR cm.deleted = 0)
|
||||
ORDER BY sm.student_no ASC
|
||||
""";
|
||||
SELECT
|
||||
sm.id,
|
||||
sm.student_no,
|
||||
sm.name,
|
||||
sm.gender,
|
||||
sm.phone,
|
||||
sm.email,
|
||||
sm.student_status,
|
||||
cm.college_id,
|
||||
cm.college_name,
|
||||
cm.major_id,
|
||||
cm.major_name,
|
||||
cm.class_name,
|
||||
cm.grade
|
||||
FROM xg_student_msg sm
|
||||
LEFT JOIN xg_class_msg cm ON sm.class_id = cm.id
|
||||
WHERE sm.class_id = ?
|
||||
AND sm.deleted = 0
|
||||
AND sm.student_status = '1'
|
||||
AND (cm.deleted IS NULL OR cm.deleted = 0)
|
||||
ORDER BY sm.student_no ASC
|
||||
""";
|
||||
|
||||
List<Map<String, Object>> studentList = jdbcTemplate.queryForList(sql, classId);
|
||||
|
||||
@@ -702,7 +722,8 @@ public class JcbtScholarshipApplicationServiceImpl implements IJcbtScholarshipAp
|
||||
for (Map<String, Object> student : studentList) {
|
||||
Map<String, Object> studentMap = new HashMap<>();
|
||||
studentMap.put("id", student.get("id"));
|
||||
studentMap.put("studentCode", student.get("student_no") != null ? student.get("student_no").toString() : "");
|
||||
studentMap.put("studentCode",
|
||||
student.get("student_no") != null ? student.get("student_no").toString() : "");
|
||||
studentMap.put("studentName", student.get("name") != null ? student.get("name").toString() : "");
|
||||
|
||||
// 性别转换:0-男,1-女
|
||||
@@ -715,14 +736,20 @@ public class JcbtScholarshipApplicationServiceImpl implements IJcbtScholarshipAp
|
||||
|
||||
studentMap.put("phone", student.get("phone") != null ? student.get("phone").toString() : "");
|
||||
studentMap.put("email", student.get("email") != null ? student.get("email").toString() : "");
|
||||
studentMap.put("status", student.get("student_status") != null ? student.get("student_status").toString() : "1");
|
||||
studentMap.put("status",
|
||||
student.get("student_status") != null ? student.get("student_status").toString() : "1");
|
||||
|
||||
// 添加学院和专业信息
|
||||
studentMap.put("collegeId", student.get("college_id") != null ? student.get("college_id").toString() : "");
|
||||
studentMap.put("collegeName", student.get("college_name") != null ? student.get("college_name").toString() : "");
|
||||
studentMap.put("majorId", student.get("major_id") != null ? student.get("major_id").toString() : "");
|
||||
studentMap.put("majorName", student.get("major_name") != null ? student.get("major_name").toString() : "");
|
||||
studentMap.put("className", student.get("class_name") != null ? student.get("class_name").toString() : "");
|
||||
studentMap.put("collegeId",
|
||||
student.get("college_id") != null ? student.get("college_id").toString() : "");
|
||||
studentMap.put("collegeName",
|
||||
student.get("college_name") != null ? student.get("college_name").toString() : "");
|
||||
studentMap.put("majorId",
|
||||
student.get("major_id") != null ? student.get("major_id").toString() : "");
|
||||
studentMap.put("majorName",
|
||||
student.get("major_name") != null ? student.get("major_name").toString() : "");
|
||||
studentMap.put("className",
|
||||
student.get("class_name") != null ? student.get("class_name").toString() : "");
|
||||
studentMap.put("grade", student.get("grade") != null ? student.get("grade").toString() : "");
|
||||
|
||||
students.add(studentMap);
|
||||
@@ -739,10 +766,11 @@ public class JcbtScholarshipApplicationServiceImpl implements IJcbtScholarshipAp
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* 根据批次获取可申请的奖学金类型
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public List<Map<String, Object>> getScholarshipTypesByBatch(Long batchId) {
|
||||
List<Map<String, Object>> scholarshipTypes = new ArrayList<>();
|
||||
|
||||
@@ -752,21 +780,24 @@ public class JcbtScholarshipApplicationServiceImpl implements IJcbtScholarshipAp
|
||||
|
||||
if (batchTypeIds != null && !batchTypeIds.isEmpty()) {
|
||||
for (Long scholarshipTypeId : batchTypeIds) {
|
||||
// 查询奖学金类型基本信息
|
||||
JcbtScholarshipTypeVo typeInfo = scholarshipTypeService.queryById(scholarshipTypeId);
|
||||
// 查询奖学金类型基本信息
|
||||
JcbtScholarshipTypeVo typeInfo = scholarshipTypeService.queryById(scholarshipTypeId);
|
||||
if (typeInfo != null && typeInfo.getStatus() == 1) { // 只返回启用的类型
|
||||
Map<String, Object> scholarshipType = new HashMap<>();
|
||||
scholarshipType.put("id", scholarshipTypeId);
|
||||
scholarshipType.put("name", typeInfo.getTypeName());
|
||||
scholarshipType.put("amount", typeInfo.getAwardAmount());
|
||||
scholarshipType.put("description", typeInfo.getDescription());
|
||||
scholarshipType.put("typeCategory", typeInfo.getTypeCategory());
|
||||
scholarshipType.put("levelType", typeInfo.getLevelType());
|
||||
Map<String, Object> scholarshipType = new HashMap<>();
|
||||
scholarshipType.put("id", scholarshipTypeId);
|
||||
scholarshipType.put("name", typeInfo.getTypeName());
|
||||
scholarshipType.put("amount", typeInfo.getAwardAmount());
|
||||
scholarshipType.put("description", typeInfo.getDescription());
|
||||
scholarshipType.put("typeCategory", typeInfo.getTypeCategory());
|
||||
scholarshipType.put("levelType", typeInfo.getLevelType());
|
||||
|
||||
// 查询该类型在该批次下的名额统计信息
|
||||
List<JcbtScholarshipQuotaVo> quotaList = quotaService.queryListByBatchAndType(batchId, scholarshipTypeId);
|
||||
int totalQuota = quotaList.stream().mapToInt(q -> q.getTotalQuota() != null ? q.getTotalQuota() : 0).sum();
|
||||
int usedQuota = quotaList.stream().mapToInt(q -> q.getUsedQuota() != null ? q.getUsedQuota() : 0).sum();
|
||||
List<JcbtScholarshipQuotaVo> quotaList = quotaService.queryListByBatchAndType(batchId,
|
||||
scholarshipTypeId);
|
||||
int totalQuota = quotaList.stream()
|
||||
.mapToInt(q -> q.getTotalQuota() != null ? q.getTotalQuota() : 0).sum();
|
||||
int usedQuota = quotaList.stream()
|
||||
.mapToInt(q -> q.getUsedQuota() != null ? q.getUsedQuota() : 0).sum();
|
||||
int availableQuota = totalQuota - usedQuota;
|
||||
|
||||
scholarshipType.put("totalQuota", totalQuota);
|
||||
@@ -805,6 +836,7 @@ public class JcbtScholarshipApplicationServiceImpl implements IJcbtScholarshipAp
|
||||
* 根据批次和班级获取带名额信息的奖学金类型(班主任专用)
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public List<Map<String, Object>> getScholarshipTypesWithQuota(Long batchId, Long classId) {
|
||||
List<Map<String, Object>> scholarshipTypes = new ArrayList<>();
|
||||
|
||||
@@ -822,8 +854,7 @@ public class JcbtScholarshipApplicationServiceImpl implements IJcbtScholarshipAp
|
||||
|
||||
// 查询奖学金类型基本信息
|
||||
JcbtScholarshipTypeVo typeInfo = scholarshipTypeService.queryById(scholarshipTypeId);
|
||||
log.info("奖学金类型基本信息: {}", typeInfo != null ?
|
||||
String.format("ID=%s, 名称=%s, 状态=%s, 金额=%s, 等级=%s",
|
||||
log.info("奖学金类型基本信息: {}", typeInfo != null ? String.format("ID=%s, 名称=%s, 状态=%s, 金额=%s, 等级=%s",
|
||||
typeInfo.getId(), typeInfo.getTypeName(), typeInfo.getStatus(),
|
||||
typeInfo.getAwardAmount(), typeInfo.getLevelType()) : "null");
|
||||
|
||||
@@ -837,14 +868,18 @@ public class JcbtScholarshipApplicationServiceImpl implements IJcbtScholarshipAp
|
||||
scholarshipType.put("levelType", typeInfo.getLevelType());
|
||||
|
||||
// 查询该班级在该奖学金类型下的名额分配信息(从jcbt_scholarship_quota表查询)
|
||||
log.info("开始查询班级名额 - SQL参数: classId={}, scholarshipTypeId={}, batchId={}", classId, scholarshipTypeId, batchId);
|
||||
log.info("执行SQL: SELECT * FROM jcbt_scholarship_quota WHERE allocation_level = 'CLASS' AND target_dept_id = {} AND scholarship_type_id = {} AND batch_id = {} AND status = 'ACTIVE'", classId, scholarshipTypeId, batchId);
|
||||
log.info("开始查询班级名额 - SQL参数: classId={}, scholarshipTypeId={}, batchId={}", classId,
|
||||
scholarshipTypeId, batchId);
|
||||
log.info(
|
||||
"执行SQL: SELECT * FROM jcbt_scholarship_quota WHERE allocation_level = 'CLASS' AND target_dept_id = {} AND scholarship_type_id = {} AND batch_id = {} AND status = 'ACTIVE'",
|
||||
classId, scholarshipTypeId, batchId);
|
||||
|
||||
JcbtScholarshipQuotaVo classQuota = quotaService.selectClassQuota(classId, scholarshipTypeId, batchId);
|
||||
log.info("班级名额查询结果: {}", classQuota != null ?
|
||||
String.format("ID=%s, 总名额=%s, 已用=%s, 可用=%s, 状态=%s",
|
||||
classQuota.getId(), classQuota.getTotalQuota(), classQuota.getUsedQuota(),
|
||||
classQuota.getAvailableQuota(), classQuota.getStatus()) : "null");
|
||||
JcbtScholarshipQuotaVo classQuota = quotaService.selectClassQuota(classId, scholarshipTypeId,
|
||||
batchId);
|
||||
log.info("班级名额查询结果: {}",
|
||||
classQuota != null ? String.format("ID=%s, 总名额=%s, 已用=%s, 可用=%s, 状态=%s",
|
||||
classQuota.getId(), classQuota.getTotalQuota(), classQuota.getUsedQuota(),
|
||||
classQuota.getAvailableQuota(), classQuota.getStatus()) : "null");
|
||||
|
||||
if (classQuota != null) {
|
||||
// 有班级名额分配
|
||||
@@ -852,7 +887,8 @@ public class JcbtScholarshipApplicationServiceImpl implements IJcbtScholarshipAp
|
||||
scholarshipType.put("hasQuota", true);
|
||||
int totalQuota = classQuota.getTotalQuota() != null ? classQuota.getTotalQuota() : 0;
|
||||
int usedQuota = classQuota.getUsedQuota() != null ? classQuota.getUsedQuota() : 0;
|
||||
int availableQuota = classQuota.getAvailableQuota() != null ? classQuota.getAvailableQuota() : Math.max(0, totalQuota - usedQuota);
|
||||
int availableQuota = classQuota.getAvailableQuota() != null ? classQuota.getAvailableQuota()
|
||||
: Math.max(0, totalQuota - usedQuota);
|
||||
|
||||
scholarshipType.put("totalQuota", totalQuota);
|
||||
scholarshipType.put("usedQuota", usedQuota);
|
||||
@@ -860,44 +896,49 @@ public class JcbtScholarshipApplicationServiceImpl implements IJcbtScholarshipAp
|
||||
scholarshipType.put("quotaStatus", availableQuota > 0 ? "available" : "full");
|
||||
|
||||
log.info("班级名额处理结果 - 类型: {}, 总名额: {}, 已用: {}, 可用: {}, 状态: {}",
|
||||
typeInfo.getTypeName(), totalQuota, usedQuota, availableQuota, availableQuota > 0 ? "available" : "full");
|
||||
typeInfo.getTypeName(), totalQuota, usedQuota, availableQuota,
|
||||
availableQuota > 0 ? "available" : "full");
|
||||
} else {
|
||||
// 没有班级名额分配,查询全校统计信息
|
||||
log.info("未找到班级名额分配,开始查询全校名额");
|
||||
log.info("执行全校名额查询SQL - 参数: batchId={}, scholarshipTypeId={}", batchId, scholarshipTypeId);
|
||||
|
||||
List<JcbtScholarshipQuotaVo> quotaList = quotaService.queryListByBatchAndType(batchId, scholarshipTypeId);
|
||||
List<JcbtScholarshipQuotaVo> quotaList = quotaService.queryListByBatchAndType(batchId,
|
||||
scholarshipTypeId);
|
||||
log.info("全校名额查询结果数量: {}", quotaList != null ? quotaList.size() : 0);
|
||||
|
||||
if (quotaList != null && !quotaList.isEmpty()) {
|
||||
for (int i = 0; i < quotaList.size(); i++) {
|
||||
JcbtScholarshipQuotaVo quota = quotaList.get(i);
|
||||
log.info("全校名额[{}]: ID={}, 分配级别={}, 目标部门={}, 总名额={}, 已用={}, 可用={}",
|
||||
i, quota.getId(), quota.getAllocationLevel(), quota.getTargetDeptName(),
|
||||
quota.getTotalQuota(), quota.getUsedQuota(), quota.getAvailableQuota());
|
||||
i, quota.getId(), quota.getAllocationLevel(), quota.getTargetDeptName(),
|
||||
quota.getTotalQuota(), quota.getUsedQuota(), quota.getAvailableQuota());
|
||||
}
|
||||
}
|
||||
|
||||
int totalQuota = quotaList.stream().mapToInt(q -> q.getTotalQuota() != null ? q.getTotalQuota() : 0).sum();
|
||||
int usedQuota = quotaList.stream().mapToInt(q -> q.getUsedQuota() != null ? q.getUsedQuota() : 0).sum();
|
||||
int totalQuota = quotaList.stream()
|
||||
.mapToInt(q -> q.getTotalQuota() != null ? q.getTotalQuota() : 0).sum();
|
||||
int usedQuota = quotaList.stream()
|
||||
.mapToInt(q -> q.getUsedQuota() != null ? q.getUsedQuota() : 0).sum();
|
||||
int availableQuota = Math.max(0, totalQuota - usedQuota);
|
||||
|
||||
scholarshipType.put("hasQuota", false);
|
||||
scholarshipType.put("totalQuota", totalQuota);
|
||||
scholarshipType.put("usedQuota", usedQuota);
|
||||
scholarshipType.put("availableQuota", availableQuota);
|
||||
scholarshipType.put("quotaStatus", totalQuota > 0 ? (availableQuota > 0 ? "available" : "full") : "unlimited");
|
||||
scholarshipType.put("quotaStatus",
|
||||
totalQuota > 0 ? (availableQuota > 0 ? "available" : "full") : "unlimited");
|
||||
|
||||
log.info("全校名额统计结果 - 类型: {} (全校), 总名额: {}, 已用: {}, 可用: {}, 状态: {}",
|
||||
typeInfo.getTypeName(), totalQuota, usedQuota, availableQuota,
|
||||
totalQuota > 0 ? (availableQuota > 0 ? "available" : "full") : "unlimited");
|
||||
typeInfo.getTypeName(), totalQuota, usedQuota, availableQuota,
|
||||
totalQuota > 0 ? (availableQuota > 0 ? "available" : "full") : "unlimited");
|
||||
}
|
||||
|
||||
scholarshipTypes.add(scholarshipType);
|
||||
log.info("奖学金类型 {} 处理完成,添加到结果列表", typeInfo.getTypeName());
|
||||
} else {
|
||||
log.warn("奖学金类型被跳过 - ID: {}, 原因: {}", scholarshipTypeId,
|
||||
typeInfo == null ? "类型信息不存在" : "状态未启用(status=" + typeInfo.getStatus() + ")");
|
||||
typeInfo == null ? "类型信息不存在" : "状态未启用(status=" + typeInfo.getStatus() + ")");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -928,7 +969,8 @@ public class JcbtScholarshipApplicationServiceImpl implements IJcbtScholarshipAp
|
||||
for (int i = 0; i < scholarshipTypes.size(); i++) {
|
||||
Map<String, Object> type = scholarshipTypes.get(i);
|
||||
log.info("结果[{}]: 名称={}, 状态={}, 总名额={}, 可用名额={}",
|
||||
i, type.get("name"), type.get("quotaStatus"), type.get("totalQuota"), type.get("availableQuota"));
|
||||
i, type.get("name"), type.get("quotaStatus"), type.get("totalQuota"),
|
||||
type.get("availableQuota"));
|
||||
}
|
||||
} else {
|
||||
log.warn("批次 {} 未关联任何奖学金类型", batchId);
|
||||
@@ -948,6 +990,7 @@ public class JcbtScholarshipApplicationServiceImpl implements IJcbtScholarshipAp
|
||||
* 测试班级名额查询(用于SQL日志调试)
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public Map<String, Object> testClassQuotaQuery(Long classId, Long scholarshipTypeId, Long batchId) {
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
|
||||
@@ -960,7 +1003,8 @@ public class JcbtScholarshipApplicationServiceImpl implements IJcbtScholarshipAp
|
||||
|
||||
// 执行查询
|
||||
log.info("💾 执行班级名额查询...");
|
||||
JcbtScholarshipClassQuotaVo classQuota = classQuotaService.queryAvailableQuota(classId, scholarshipTypeId, batchId);
|
||||
JcbtScholarshipClassQuotaVo classQuota = classQuotaService.queryAvailableQuota(classId, scholarshipTypeId,
|
||||
batchId);
|
||||
|
||||
// 记录查询结束时间
|
||||
long endTime = System.currentTimeMillis();
|
||||
@@ -971,23 +1015,24 @@ public class JcbtScholarshipApplicationServiceImpl implements IJcbtScholarshipAp
|
||||
if (classQuota != null) {
|
||||
log.info("✅ 查询成功,找到班级名额记录");
|
||||
log.info("📊 名额详情: ID={}, 批次ID={}, 奖学金类型ID={}, 班级ID={}",
|
||||
classQuota.getId(), classQuota.getBatchId(), classQuota.getScholarshipTypeId(), classQuota.getClassId());
|
||||
classQuota.getId(), classQuota.getBatchId(), classQuota.getScholarshipTypeId(),
|
||||
classQuota.getClassId());
|
||||
log.info("📈 名额数据: 总名额={}, 已用名额={}, 可用名额={}, 状态={}",
|
||||
classQuota.getTotalQuota(), classQuota.getUsedQuota(), classQuota.getAvailableQuota(), classQuota.getStatus());
|
||||
classQuota.getTotalQuota(), classQuota.getUsedQuota(), classQuota.getAvailableQuota(),
|
||||
classQuota.getStatus());
|
||||
|
||||
result.put("found", true);
|
||||
result.put("data", Map.of(
|
||||
"id", classQuota.getId(),
|
||||
"batchId", classQuota.getBatchId(),
|
||||
"scholarshipTypeId", classQuota.getScholarshipTypeId(),
|
||||
"classId", classQuota.getClassId(),
|
||||
"totalQuota", classQuota.getTotalQuota(),
|
||||
"usedQuota", classQuota.getUsedQuota(),
|
||||
"availableQuota", classQuota.getAvailableQuota(),
|
||||
"status", classQuota.getStatus(),
|
||||
"createTime", classQuota.getCreateTime(),
|
||||
"updateTime", classQuota.getUpdateTime()
|
||||
));
|
||||
"id", classQuota.getId(),
|
||||
"batchId", classQuota.getBatchId(),
|
||||
"scholarshipTypeId", classQuota.getScholarshipTypeId(),
|
||||
"classId", classQuota.getClassId(),
|
||||
"totalQuota", classQuota.getTotalQuota(),
|
||||
"usedQuota", classQuota.getUsedQuota(),
|
||||
"availableQuota", classQuota.getAvailableQuota(),
|
||||
"status", classQuota.getStatus(),
|
||||
"createTime", classQuota.getCreateTime(),
|
||||
"updateTime", classQuota.getUpdateTime()));
|
||||
} else {
|
||||
log.warn("⚠️ 未找到班级名额记录");
|
||||
log.info("🔍 可能原因:");
|
||||
@@ -1033,6 +1078,7 @@ public class JcbtScholarshipApplicationServiceImpl implements IJcbtScholarshipAp
|
||||
* 测试全校名额查询(用于SQL日志调试)
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public Map<String, Object> testSchoolQuotaQuery(Long batchId, Long scholarshipTypeId) {
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
|
||||
@@ -1063,9 +1109,11 @@ public class JcbtScholarshipApplicationServiceImpl implements IJcbtScholarshipAp
|
||||
for (int i = 0; i < quotaList.size(); i++) {
|
||||
JcbtScholarshipQuotaVo quota = quotaList.get(i);
|
||||
log.info("📈 记录[{}]: ID={}, 分配级别={}, 目标部门ID={}, 目标部门={}",
|
||||
i, quota.getId(), quota.getAllocationLevel(), quota.getTargetDeptId(), quota.getTargetDeptName());
|
||||
i, quota.getId(), quota.getAllocationLevel(), quota.getTargetDeptId(),
|
||||
quota.getTargetDeptName());
|
||||
log.info("📊 名额[{}]: 总名额={}, 已用={}, 预留={}, 可用={}, 状态={}",
|
||||
i, quota.getTotalQuota(), quota.getUsedQuota(), quota.getReservedQuota(), quota.getAvailableQuota(), quota.getStatus());
|
||||
i, quota.getTotalQuota(), quota.getUsedQuota(), quota.getReservedQuota(),
|
||||
quota.getAvailableQuota(), quota.getStatus());
|
||||
|
||||
Map<String, Object> quotaDetail = new HashMap<>();
|
||||
quotaDetail.put("id", quota.getId());
|
||||
@@ -1099,11 +1147,10 @@ public class JcbtScholarshipApplicationServiceImpl implements IJcbtScholarshipAp
|
||||
result.put("count", quotaList.size());
|
||||
result.put("details", quotaDetails);
|
||||
result.put("summary", Map.of(
|
||||
"totalQuota", totalQuota,
|
||||
"usedQuota", usedQuota,
|
||||
"availableQuota", availableQuota,
|
||||
"calculatedAvailable", Math.max(0, totalQuota - usedQuota)
|
||||
));
|
||||
"totalQuota", totalQuota,
|
||||
"usedQuota", usedQuota,
|
||||
"availableQuota", availableQuota,
|
||||
"calculatedAvailable", Math.max(0, totalQuota - usedQuota)));
|
||||
|
||||
} else {
|
||||
log.warn("⚠️ 未找到全校名额记录");
|
||||
|
||||
+12
@@ -23,6 +23,7 @@ import org.dromara.xg.domain.bo.XgDormBedBatchAllocateBo;
|
||||
import org.dromara.xg.service.IXgDormBedStudentService;
|
||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||
import org.dromara.xg.domain.bo.XgDormBedBatchRecallBo;
|
||||
import org.dromara.xg.domain.vo.DormBuildingTreeVo;
|
||||
|
||||
/**
|
||||
* 床位学生分配关系
|
||||
@@ -126,4 +127,15 @@ public class XgDormBedStudentController extends BaseController {
|
||||
public R<Void> batchRecallBeds(@Validated(AddGroup.class) @RequestBody XgDormBedBatchRecallBo bo) {
|
||||
return toAjax(xgDormBedStudentService.batchRecallBeds(bo));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前用户二级学院的宿舍楼树形结构
|
||||
* 校区-宿舍区-宿舍楼三级结构,校区和宿舍区不可选,只有宿舍楼可以选择
|
||||
*/
|
||||
@SaCheckPermission("dormBedStudent:dormBedStudent:list")
|
||||
@GetMapping("/currentUserCollegeDormTree")
|
||||
public R<List<DormBuildingTreeVo>> getCurrentUserCollegeDormBuildingTree() {
|
||||
List<DormBuildingTreeVo> treeData = xgDormBedStudentService.getCurrentUserCollegeDormBuildingTree();
|
||||
return R.ok(treeData);
|
||||
}
|
||||
}
|
||||
+11
@@ -1286,4 +1286,15 @@ public class XgStudentMsgController extends BaseController {
|
||||
List<XgStudentTreeVo> studentTree = xgStudentMsgService.getStudentTree(secondaryCollegeId);
|
||||
return R.ok(studentTree);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前用户所在学院的学生信息树
|
||||
*/
|
||||
@SaCheckPermission("studentMsg:studentMsg:list")
|
||||
@GetMapping("/getCurrentUserStudentTree")
|
||||
public R<List<XgStudentTreeVo>> getCurrentUserStudentTree() {
|
||||
log.info("获取当前用户所在学院的学生信息树");
|
||||
List<XgStudentTreeVo> studentTree = xgStudentMsgService.getCurrentUserStudentTree();
|
||||
return R.ok(studentTree);
|
||||
}
|
||||
}
|
||||
+9
@@ -10,6 +10,7 @@ import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import org.dromara.xg.domain.bo.XgDormBedBatchRecallBo;
|
||||
import org.dromara.xg.domain.vo.DormBuildingTreeVo;
|
||||
|
||||
/**
|
||||
* 床位学生分配关系Service接口
|
||||
@@ -85,4 +86,12 @@ public interface IXgDormBedStudentService {
|
||||
* @return 是否成功
|
||||
*/
|
||||
Boolean batchRecallBeds(XgDormBedBatchRecallBo bo);
|
||||
|
||||
/**
|
||||
* 获取当前用户二级学院的宿舍楼树形结构
|
||||
* 校区-宿舍区-宿舍楼三级结构,校区和宿舍区不可选,只有宿舍楼可以选择
|
||||
*
|
||||
* @return 宿舍楼树形结构数据
|
||||
*/
|
||||
List<DormBuildingTreeVo> getCurrentUserCollegeDormBuildingTree();
|
||||
}
|
||||
+7
@@ -161,4 +161,11 @@ public interface IXgStudentMsgService {
|
||||
* @return 学生信息树
|
||||
*/
|
||||
List<XgStudentTreeVo> getStudentTree(Long secondaryCollegeId);
|
||||
|
||||
/**
|
||||
* 获取当前用户所在学院的学生信息树
|
||||
*
|
||||
* @return 学生信息树
|
||||
*/
|
||||
List<XgStudentTreeVo> getCurrentUserStudentTree();
|
||||
}
|
||||
+238
@@ -36,6 +36,15 @@ import org.dromara.xg.mapper.XgStudentMsgMapper;
|
||||
import org.dromara.xg.domain.XgStudentMsg;
|
||||
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||
import org.dromara.common.satoken.utils.LoginHelper;
|
||||
import org.dromara.xg.domain.vo.DormBuildingTreeVo;
|
||||
import org.dromara.xg.domain.XgDormCampus;
|
||||
import org.dromara.xg.domain.XgDormArea;
|
||||
import org.dromara.xg.mapper.XgDormCampusMapper;
|
||||
import org.dromara.xg.mapper.XgDormAreaMapper;
|
||||
import org.dromara.xg.mapper.XgSysDeptMapper;
|
||||
import org.dromara.xg.domain.XgSysDept;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.LinkedHashMap;
|
||||
|
||||
/**
|
||||
* 床位学生分配关系Service业务层处理
|
||||
@@ -53,6 +62,9 @@ public class XgDormBedStudentServiceImpl implements IXgDormBedStudentService {
|
||||
private final XgDormBuildingMapper xgDormBuildingMapper;
|
||||
private final XgDormRoomMapper xgDormRoomMapper;
|
||||
private final XgStudentMsgMapper xgStudentMsgMapper;
|
||||
private final XgDormCampusMapper xgDormCampusMapper;
|
||||
private final XgDormAreaMapper xgDormAreaMapper;
|
||||
private final XgSysDeptMapper xgSysDeptMapper;
|
||||
|
||||
/**
|
||||
* 查询床位学生分配关系
|
||||
@@ -491,4 +503,230 @@ public class XgDormBedStudentServiceImpl implements IXgDormBedStudentService {
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前用户二级学院的宿舍楼树形结构
|
||||
* 校区-宿舍区-宿舍楼三级结构,校区和宿舍区不可选,只有宿舍楼可以选择
|
||||
*
|
||||
* @return 宿舍楼树形结构数据
|
||||
*/
|
||||
@Override
|
||||
public List<DormBuildingTreeVo> getCurrentUserCollegeDormBuildingTree() {
|
||||
try {
|
||||
// 1. 获取当前用户的二级学院ID
|
||||
Long collegeId = getCurrentUserCollegeId();
|
||||
if (collegeId == null) {
|
||||
log.warn("无法获取当前用户的二级学院信息");
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
// 2. 通过xg_dorm_bed_student表获取分配给该学院的宿舍楼ID列表
|
||||
Set<Long> buildingIds = getCollegeAllocatedBuildingIds(collegeId);
|
||||
if (buildingIds.isEmpty()) {
|
||||
log.info("学院 {} 还没有分配任何宿舍楼", collegeId);
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
// 3. 获取宿舍楼信息并构建树形结构
|
||||
return buildDormBuildingTree(buildingIds);
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("获取当前用户二级学院宿舍楼树失败", e);
|
||||
return new ArrayList<>();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前用户的二级学院ID
|
||||
* 通过当前用户的部门id,向上寻找包括他自己,找到dept_category前几位是xy-的就是二级学院
|
||||
* 或者parent_id = 101的部门就是二级学院
|
||||
*/
|
||||
private Long getCurrentUserCollegeId() {
|
||||
try {
|
||||
Long currentUserId = LoginHelper.getUserId();
|
||||
Long currentDeptId = LoginHelper.getDeptId();
|
||||
|
||||
if (currentUserId == null || currentDeptId == null) {
|
||||
log.warn("用户未登录或没有部门信息");
|
||||
return null;
|
||||
}
|
||||
|
||||
// 首先查找parent_id = 101的部门(使用LambdaQueryWrapper)
|
||||
LambdaQueryWrapper<XgSysDept> parentQuery = Wrappers.lambdaQuery();
|
||||
parentQuery.eq(XgSysDept::getParentId, 101L)
|
||||
.eq(XgSysDept::getStatus, "0")
|
||||
.eq(XgSysDept::getDelFlag, "0")
|
||||
.and(wrapper -> wrapper.eq(XgSysDept::getDeptId, currentDeptId)
|
||||
.or().like(XgSysDept::getAncestors, "," + currentDeptId + ",") // 中间位置
|
||||
.or().likeRight(XgSysDept::getAncestors, currentDeptId + ",") // 开头位置
|
||||
.or().likeLeft(XgSysDept::getAncestors, "," + currentDeptId) // 末尾位置
|
||||
.or().eq(XgSysDept::getAncestors, currentDeptId.toString())) // 单独一个值
|
||||
.last("LIMIT 1");
|
||||
|
||||
List<XgSysDept> parentColleges = xgSysDeptMapper.selectList(parentQuery);
|
||||
if (!parentColleges.isEmpty()) {
|
||||
return parentColleges.get(0).getDeptId();
|
||||
}
|
||||
|
||||
// 如果上面的查询没找到,尝试通过dept_category查找
|
||||
LambdaQueryWrapper<XgSysDept> categoryQuery = Wrappers.lambdaQuery();
|
||||
categoryQuery.likeRight(XgSysDept::getDeptCategory, "xy-")
|
||||
.eq(XgSysDept::getStatus, "0")
|
||||
.eq(XgSysDept::getDelFlag, "0")
|
||||
.and(wrapper -> wrapper.eq(XgSysDept::getDeptId, currentDeptId)
|
||||
.or().like(XgSysDept::getAncestors, "," + currentDeptId + ",") // 中间位置
|
||||
.or().likeRight(XgSysDept::getAncestors, currentDeptId + ",") // 开头位置
|
||||
.or().likeLeft(XgSysDept::getAncestors, "," + currentDeptId) // 末尾位置
|
||||
.or().eq(XgSysDept::getAncestors, currentDeptId.toString())) // 单独一个值
|
||||
.last("LIMIT 1");
|
||||
|
||||
List<XgSysDept> categoryColleges = xgSysDeptMapper.selectList(categoryQuery);
|
||||
return categoryColleges.isEmpty() ? null : categoryColleges.get(0).getDeptId();
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("获取当前用户二级学院ID失败", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取分配给指定学院的宿舍楼ID列表
|
||||
*/
|
||||
private Set<Long> getCollegeAllocatedBuildingIds(Long collegeId) {
|
||||
try {
|
||||
LambdaQueryWrapper<XgDormBedStudent> queryWrapper = Wrappers.lambdaQuery();
|
||||
queryWrapper.select(XgDormBedStudent::getBuildingId)
|
||||
.eq(XgDormBedStudent::getCollegeId, collegeId)
|
||||
.eq(XgDormBedStudent::getStatus, "0")
|
||||
.eq(XgDormBedStudent::getDeleted, "0")
|
||||
.isNotNull(XgDormBedStudent::getBuildingId)
|
||||
.groupBy(XgDormBedStudent::getBuildingId);
|
||||
|
||||
List<XgDormBedStudent> buildingRecords = baseMapper.selectList(queryWrapper);
|
||||
return buildingRecords.stream()
|
||||
.map(XgDormBedStudent::getBuildingId)
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("获取学院 {} 分配的宿舍楼ID列表失败", collegeId, e);
|
||||
return Set.of();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据宿舍楼ID列表构建宿舍楼树形结构
|
||||
*/
|
||||
private List<DormBuildingTreeVo> buildDormBuildingTree(Set<Long> buildingIds) {
|
||||
if (buildingIds.isEmpty()) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
try {
|
||||
// 获取宿舍楼信息
|
||||
LambdaQueryWrapper<XgDormBuilding> buildingWrapper = Wrappers.lambdaQuery();
|
||||
buildingWrapper.in(XgDormBuilding::getId, buildingIds)
|
||||
.eq(XgDormBuilding::getDeleted, "0")
|
||||
.orderByAsc(XgDormBuilding::getSortOrder, XgDormBuilding::getId);
|
||||
List<XgDormBuilding> buildings = xgDormBuildingMapper.selectList(buildingWrapper);
|
||||
|
||||
if (buildings.isEmpty()) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
// 获取涉及的宿舍区ID
|
||||
Set<Long> areaIds = buildings.stream()
|
||||
.map(XgDormBuilding::getAreaId)
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
// 获取宿舍区信息
|
||||
LambdaQueryWrapper<XgDormArea> areaWrapper = Wrappers.lambdaQuery();
|
||||
areaWrapper.in(XgDormArea::getId, areaIds)
|
||||
.eq(XgDormArea::getDeleted, "0")
|
||||
.orderByAsc(XgDormArea::getSortOrder, XgDormArea::getId);
|
||||
List<XgDormArea> areas = xgDormAreaMapper.selectList(areaWrapper);
|
||||
|
||||
// 获取涉及的校区ID
|
||||
Set<Long> campusIds = areas.stream()
|
||||
.map(XgDormArea::getCampusId)
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
// 获取校区信息
|
||||
LambdaQueryWrapper<XgDormCampus> campusWrapper = Wrappers.lambdaQuery();
|
||||
campusWrapper.in(XgDormCampus::getId, campusIds)
|
||||
.eq(XgDormCampus::getDeleted, "0")
|
||||
.orderByAsc(XgDormCampus::getSortOrder, XgDormCampus::getId);
|
||||
List<XgDormCampus> campuses = xgDormCampusMapper.selectList(campusWrapper);
|
||||
|
||||
// 构建树形结构
|
||||
return buildTreeStructure(campuses, areas, buildings);
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("构建宿舍楼树形结构失败", e);
|
||||
return new ArrayList<>();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建树形结构:校区-宿舍区-宿舍楼
|
||||
*/
|
||||
private List<DormBuildingTreeVo> buildTreeStructure(List<XgDormCampus> campuses,
|
||||
List<XgDormArea> areas,
|
||||
List<XgDormBuilding> buildings) {
|
||||
|
||||
// 构建校区节点(第一层)
|
||||
Map<Long, DormBuildingTreeVo> campusMap = new LinkedHashMap<>();
|
||||
for (XgDormCampus campus : campuses) {
|
||||
// 只保留有宿舍楼的校区
|
||||
if (areas.stream().anyMatch(a -> a.getCampusId().equals(campus.getId()))) {
|
||||
DormBuildingTreeVo campusNode = new DormBuildingTreeVo();
|
||||
campusNode.setId(campus.getId());
|
||||
campusNode.setLabel(campus.getCampusName());
|
||||
campusNode.setType("campus");
|
||||
campusNode.setDisabled(true); // 校区节点禁止点击
|
||||
campusNode.setChildren(new ArrayList<>());
|
||||
campusMap.put(campus.getId(), campusNode);
|
||||
}
|
||||
}
|
||||
|
||||
// 构建宿舍区节点(第二层)
|
||||
Map<Long, DormBuildingTreeVo> areaMap = new LinkedHashMap<>();
|
||||
for (XgDormArea area : areas) {
|
||||
// 只保留有宿舍楼的宿舍区
|
||||
if (buildings.stream().anyMatch(b -> b.getAreaId().equals(area.getId()))) {
|
||||
DormBuildingTreeVo areaNode = new DormBuildingTreeVo();
|
||||
areaNode.setId(area.getId());
|
||||
areaNode.setLabel(area.getAreaName());
|
||||
areaNode.setType("area");
|
||||
areaNode.setDisabled(true); // 宿舍区节点禁止点击
|
||||
areaNode.setChildren(new ArrayList<>());
|
||||
areaMap.put(area.getId(), areaNode);
|
||||
|
||||
// 添加到对应的校区下
|
||||
DormBuildingTreeVo campusNode = campusMap.get(area.getCampusId());
|
||||
if (campusNode != null) {
|
||||
campusNode.getChildren().add(areaNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 构建宿舍楼节点(第三层)
|
||||
for (XgDormBuilding building : buildings) {
|
||||
DormBuildingTreeVo buildingNode = new DormBuildingTreeVo();
|
||||
buildingNode.setId(building.getId());
|
||||
buildingNode.setLabel(building.getBuildingName());
|
||||
buildingNode.setType("building");
|
||||
buildingNode.setDisabled(false); // 宿舍楼节点可以点击
|
||||
buildingNode.setBuildingFloors(building.getFloors());
|
||||
buildingNode.setBuildingType(building.getBuildingType());
|
||||
buildingNode.setChildren(new ArrayList<>());
|
||||
|
||||
// 添加到对应的宿舍区下
|
||||
DormBuildingTreeVo areaNode = areaMap.get(building.getAreaId());
|
||||
if (areaNode != null) {
|
||||
areaNode.getChildren().add(buildingNode);
|
||||
}
|
||||
}
|
||||
|
||||
return new ArrayList<>(campusMap.values());
|
||||
}
|
||||
}
|
||||
+2
@@ -167,6 +167,7 @@ public class XgStudentManagerSourceServiceImpl implements IXgStudentManagerSourc
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(readOnly = true)
|
||||
public List<String> getAuthSourceNames(Long managerId) {
|
||||
// 1. 查询xg_student_manager_source表,manager_id=managerId, deleted=0,
|
||||
// status=0,获取auth_source
|
||||
@@ -190,6 +191,7 @@ public class XgStudentManagerSourceServiceImpl implements IXgStudentManagerSourc
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(readOnly = true)
|
||||
public List<XgStudentManagerDeptTreeVo> getCurrentUserAuthDeptTree() {
|
||||
// 获取当前登录用户ID
|
||||
Long currentUserId = LoginHelper.getUserId();
|
||||
|
||||
+82
@@ -37,11 +37,13 @@ import org.dromara.xg.mapper.XgStudentManagerSourceMapper;
|
||||
import org.dromara.xg.mapper.XgClassTeacherCounselorRelMapper;
|
||||
import org.dromara.xg.mapper.XgClassMsgMapper;
|
||||
import org.dromara.xg.mapper.XgDormBedStudentMapper;
|
||||
import org.dromara.xg.mapper.XgSysDeptMapper;
|
||||
import org.dromara.xg.domain.XgStudentManager;
|
||||
import org.dromara.xg.domain.XgStudentManagerSource;
|
||||
import org.dromara.xg.domain.XgClassTeacherCounselorRel;
|
||||
import org.dromara.xg.domain.XgClassMsg;
|
||||
import org.dromara.xg.domain.XgDormBedStudent;
|
||||
import org.dromara.xg.domain.XgSysDept;
|
||||
import org.dromara.common.satoken.utils.LoginHelper;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@@ -73,6 +75,7 @@ public class XgStudentMsgServiceImpl implements IXgStudentMsgService {
|
||||
private final XgClassTeacherCounselorRelMapper xgClassTeacherCounselorRelMapper;
|
||||
private final XgClassMsgMapper xgClassMsgMapper;
|
||||
private final XgDormBedStudentMapper xgDormBedStudentMapper;
|
||||
private final XgSysDeptMapper xgSysDeptMapper;
|
||||
|
||||
/**
|
||||
* 查询学生信息
|
||||
@@ -1317,4 +1320,83 @@ public class XgStudentMsgServiceImpl implements IXgStudentMsgService {
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前用户所在学院的学生信息树
|
||||
*
|
||||
* @return 学生信息树
|
||||
*/
|
||||
@Override
|
||||
public List<XgStudentTreeVo> getCurrentUserStudentTree() {
|
||||
try {
|
||||
// 1. 获取当前用户的二级学院ID
|
||||
Long collegeId = getCurrentUserCollegeId();
|
||||
if (collegeId == null) {
|
||||
log.warn("无法获取当前用户的二级学院信息");
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
log.info("获取到当前用户的学院ID: {}", collegeId);
|
||||
|
||||
// 2. 调用现有的getStudentTree方法
|
||||
return getStudentTree(collegeId);
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("获取当前用户学院的学生信息树失败", e);
|
||||
return new ArrayList<>();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前用户的二级学院ID
|
||||
* 通过当前用户的部门id,向上寻找包括他自己,找到dept_category前几位是xy-的就是二级学院
|
||||
* 或者parent_id = 101的部门就是二级学院
|
||||
*/
|
||||
private Long getCurrentUserCollegeId() {
|
||||
try {
|
||||
Long currentUserId = LoginHelper.getUserId();
|
||||
Long currentDeptId = LoginHelper.getDeptId();
|
||||
|
||||
if (currentUserId == null || currentDeptId == null) {
|
||||
log.warn("用户未登录或没有部门信息");
|
||||
return null;
|
||||
}
|
||||
|
||||
// 首先查找parent_id = 101的部门(使用LambdaQueryWrapper)
|
||||
LambdaQueryWrapper<XgSysDept> parentQuery = Wrappers.lambdaQuery();
|
||||
parentQuery.eq(XgSysDept::getParentId, 101L)
|
||||
.eq(XgSysDept::getStatus, "0")
|
||||
.eq(XgSysDept::getDelFlag, "0")
|
||||
.and(wrapper -> wrapper.eq(XgSysDept::getDeptId, currentDeptId)
|
||||
.or().like(XgSysDept::getAncestors, "," + currentDeptId + ",") // 中间位置
|
||||
.or().likeRight(XgSysDept::getAncestors, currentDeptId + ",") // 开头位置
|
||||
.or().likeLeft(XgSysDept::getAncestors, "," + currentDeptId) // 末尾位置
|
||||
.or().eq(XgSysDept::getAncestors, currentDeptId.toString())) // 单独一个值
|
||||
.last("LIMIT 1");
|
||||
|
||||
List<XgSysDept> parentColleges = xgSysDeptMapper.selectList(parentQuery);
|
||||
if (!parentColleges.isEmpty()) {
|
||||
return parentColleges.get(0).getDeptId();
|
||||
}
|
||||
|
||||
// 如果上面的查询没找到,尝试通过dept_category查找
|
||||
LambdaQueryWrapper<XgSysDept> categoryQuery = Wrappers.lambdaQuery();
|
||||
categoryQuery.likeRight(XgSysDept::getDeptCategory, "xy-")
|
||||
.eq(XgSysDept::getStatus, "0")
|
||||
.eq(XgSysDept::getDelFlag, "0")
|
||||
.and(wrapper -> wrapper.eq(XgSysDept::getDeptId, currentDeptId)
|
||||
.or().like(XgSysDept::getAncestors, "," + currentDeptId + ",") // 中间位置
|
||||
.or().likeRight(XgSysDept::getAncestors, currentDeptId + ",") // 开头位置
|
||||
.or().likeLeft(XgSysDept::getAncestors, "," + currentDeptId) // 末尾位置
|
||||
.or().eq(XgSysDept::getAncestors, currentDeptId.toString())) // 单独一个值
|
||||
.last("LIMIT 1");
|
||||
|
||||
List<XgSysDept> categoryColleges = xgSysDeptMapper.selectList(categoryQuery);
|
||||
return categoryColleges.isEmpty() ? null : categoryColleges.get(0).getDeptId();
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("获取当前用户二级学院ID失败", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
import request from '@/utils/request';
|
||||
import { AxiosPromise } from 'axios';
|
||||
import { DormBedStudentVO, DormBedStudentForm, DormBedStudentQuery } from '@/api/xg/xgss/dormBedStudent/dormBedStudent/types';
|
||||
import { DormBedStudentVO, DormBedStudentForm, DormBedStudentQuery, DormBuildingTreeVO } from '@/api/xg/xgss/dormBedStudent/dormBedStudent/types';
|
||||
|
||||
/**
|
||||
* 查询床位学生分配关系列表
|
||||
@@ -72,3 +72,14 @@ export const batchRecallDormBeds = (data: { bedIds: Array<string | number> }) =>
|
||||
data
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 获取当前用户二级学院的宿舍楼树形结构
|
||||
* 校区-宿舍区-宿舍楼三级结构,校区和宿舍区不可选,只有宿舍楼可以选择
|
||||
*/
|
||||
export const getCurrentUserCollegeDormTree = (): AxiosPromise<DormBuildingTreeVO[]> => {
|
||||
return request({
|
||||
url: '/dormBedStudent/dormBedStudent/currentUserCollegeDormTree',
|
||||
method: 'get'
|
||||
});
|
||||
};
|
||||
@@ -223,3 +223,43 @@ export interface DormBedStudentQuery extends PageQuery {
|
||||
*/
|
||||
params?: any;
|
||||
}
|
||||
|
||||
/**
|
||||
* 宿舍楼树形结构VO
|
||||
*/
|
||||
export interface DormBuildingTreeVO {
|
||||
/**
|
||||
* 节点ID
|
||||
*/
|
||||
id: string | number;
|
||||
|
||||
/**
|
||||
* 节点名称
|
||||
*/
|
||||
label: string;
|
||||
|
||||
/**
|
||||
* 节点类型 (campus:校区, area:宿舍区, building:宿舍楼)
|
||||
*/
|
||||
type: string;
|
||||
|
||||
/**
|
||||
* 是否禁用节点(校区和宿舍区节点禁用点击)
|
||||
*/
|
||||
disabled?: boolean;
|
||||
|
||||
/**
|
||||
* 宿舍楼层数(仅宿舍楼节点有此字段)
|
||||
*/
|
||||
buildingFloors?: number;
|
||||
|
||||
/**
|
||||
* 宿舍楼类型(1男生楼 2女生楼 3混合楼)(仅宿舍楼节点有此字段)
|
||||
*/
|
||||
buildingType?: string;
|
||||
|
||||
/**
|
||||
* 子节点
|
||||
*/
|
||||
children?: DormBuildingTreeVO[];
|
||||
}
|
||||
@@ -207,6 +207,14 @@ export function getStudentTree(secondaryCollegeId: number = 101): AxiosPromise<R
|
||||
});
|
||||
}
|
||||
|
||||
// 获取当前用户所在学院的学生信息树
|
||||
export function getCurrentUserStudentTree(): AxiosPromise<R<XgStudentTreeVO[]>> {
|
||||
return request({
|
||||
url: '/studentMsg/studentMsg/getCurrentUserStudentTree',
|
||||
method: 'get'
|
||||
});
|
||||
}
|
||||
|
||||
// 学生状态修改
|
||||
export function changeStudentStatus(studentId: string | number, status: string): AxiosPromise<R<any>> {
|
||||
// 实际使用时连接后端接口
|
||||
|
||||
@@ -0,0 +1,150 @@
|
||||
<template>
|
||||
<el-dialog v-model="visible" :title="title" width="500px" append-to-body @close="closeDialog">
|
||||
<el-form ref="formRef" :model="form" :rules="rules" label-width="80px">
|
||||
<el-form-item label="床位编号" prop="bedCode">
|
||||
<el-input v-model="form.bedCode" placeholder="请输入床位编号" maxlength="20" />
|
||||
</el-form-item>
|
||||
<el-form-item label="床位名称" prop="bedName">
|
||||
<el-input v-model="form.bedName" placeholder="请输入床位名称" maxlength="20" />
|
||||
</el-form-item>
|
||||
<el-form-item label="床位状态" prop="bedStatus">
|
||||
<el-radio-group v-model="form.bedStatus">
|
||||
<el-radio label="0">空闲</el-radio>
|
||||
<el-radio label="1" disabled>已分配</el-radio>
|
||||
<el-radio label="2">维修中</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="床位类型" prop="bedType">
|
||||
<el-radio-group v-model="form.bedType">
|
||||
<el-radio label="1">下铺</el-radio>
|
||||
<el-radio label="2">上铺</el-radio>
|
||||
<el-radio label="3">中铺</el-radio>
|
||||
<el-radio label="4">独立床</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="备注" prop="remark">
|
||||
<el-input v-model="form.remark" type="textarea" placeholder="请输入备注内容" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button type="primary" @click="submitForm">确 定</el-button>
|
||||
<el-button @click="visible = false">取 消</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, reactive, watch } from 'vue';
|
||||
import type { FormInstance, FormRules } from 'element-plus';
|
||||
import { DormBedForm } from '@/api/xg/xgss/dormBed/types';
|
||||
import { addDormBed, updateDormBed, getDormBed } from '@/api/xg/xgss/dormBed';
|
||||
|
||||
const props = defineProps<{
|
||||
modelValue: boolean;
|
||||
title: string;
|
||||
bedId?: string | number;
|
||||
roomId: string | number;
|
||||
}>();
|
||||
|
||||
const emit = defineEmits(['update:modelValue', 'success']);
|
||||
|
||||
const formRef = ref<FormInstance>();
|
||||
const visible = ref(false);
|
||||
|
||||
// 表单数据
|
||||
const initFormData: DormBedForm = {
|
||||
id: '',
|
||||
bedCode: '',
|
||||
bedName: '',
|
||||
roomId: '',
|
||||
bedStatus: '0',
|
||||
bedType: '4',
|
||||
remark: ''
|
||||
};
|
||||
|
||||
const form = reactive<DormBedForm>({ ...initFormData });
|
||||
|
||||
// 表单校验规则
|
||||
const rules = reactive<FormRules>({
|
||||
bedCode: [{ required: true, message: '床位编号不能为空', trigger: 'blur' }],
|
||||
bedName: [{ required: true, message: '床位名称不能为空', trigger: 'blur' }],
|
||||
bedStatus: [{ required: true, message: '床位状态不能为空', trigger: 'change' }],
|
||||
bedType: [{ required: true, message: '床位类型不能为空', trigger: 'change' }]
|
||||
});
|
||||
|
||||
// 监听visible属性变化
|
||||
watch(
|
||||
() => props.modelValue,
|
||||
(val) => {
|
||||
visible.value = val;
|
||||
if (val) {
|
||||
resetForm();
|
||||
// 设置表单初始值
|
||||
form.roomId = props.roomId;
|
||||
// 编辑模式,获取床位详情
|
||||
if (props.bedId) {
|
||||
console.log('开始获取床位详情, bedId:', props.bedId);
|
||||
getDormBed(props.bedId)
|
||||
.then((res) => {
|
||||
console.log('获取床位详情成功:', res.data);
|
||||
if (res.data) {
|
||||
Object.assign(form, res.data);
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error('获取床位详情失败', error);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// 监听visible变化,同步回父组件
|
||||
watch(
|
||||
() => visible.value,
|
||||
(val) => {
|
||||
emit('update:modelValue', val);
|
||||
}
|
||||
);
|
||||
|
||||
// 关闭对话框
|
||||
const closeDialog = () => {
|
||||
visible.value = false;
|
||||
resetForm();
|
||||
};
|
||||
|
||||
// 重置表单
|
||||
const resetForm = () => {
|
||||
Object.assign(form, { ...initFormData });
|
||||
formRef.value?.resetFields();
|
||||
};
|
||||
|
||||
// 提交表单
|
||||
const submitForm = () => {
|
||||
formRef.value?.validate(async (valid) => {
|
||||
if (valid) {
|
||||
try {
|
||||
if (props.bedId) {
|
||||
// 修改
|
||||
form.id = props.bedId;
|
||||
await updateDormBed(form);
|
||||
} else {
|
||||
// 新增
|
||||
await addDormBed(form);
|
||||
}
|
||||
closeDialog();
|
||||
emit('success');
|
||||
} catch (error) {
|
||||
console.error('操作失败', error);
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// 添加默认导出以支持导入
|
||||
defineOptions({
|
||||
name: 'BedDialog'
|
||||
});
|
||||
</script>
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,171 @@
|
||||
<template>
|
||||
<el-dialog v-model="visible" :title="title" width="500px" append-to-body @close="closeDialog">
|
||||
<el-form ref="formRef" :model="form" :rules="rules" label-width="80px">
|
||||
<el-form-item label="楼层" prop="floorNum">
|
||||
<el-input v-model="form.floorNum" placeholder="请输入楼层" :disabled="true" />
|
||||
</el-form-item>
|
||||
<el-form-item label="房间编号" prop="roomCode">
|
||||
<el-input v-model="form.roomCode" placeholder="请输入房间编号" maxlength="20" />
|
||||
</el-form-item>
|
||||
<el-form-item label="房间名称" prop="roomName">
|
||||
<el-input v-model="form.roomName" placeholder="请输入房间名称" maxlength="20" />
|
||||
</el-form-item>
|
||||
<el-form-item label="房间类型" prop="roomType">
|
||||
<el-select v-model="form.roomType" placeholder="请选择房间类型" clearable style="width: 100%">
|
||||
<el-option label="标准间" value="1" />
|
||||
<el-option label="单人间" value="2" />
|
||||
<el-option label="套间" value="3" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="床位数量" prop="actualBeds">
|
||||
<el-input-number v-model="form.actualBeds" :min="1" :max="8" controls-position="right" style="width: 100%" />
|
||||
</el-form-item>
|
||||
<el-form-item label="房间面积" prop="roomArea">
|
||||
<el-input v-model="form.roomArea" placeholder="请输入房间面积" maxlength="20">
|
||||
<template #append>
|
||||
<span style="color: #000; background: transparent">平方米</span>
|
||||
</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="房间状态" prop="roomStatus">
|
||||
<el-radio-group v-model="form.roomStatus">
|
||||
<el-radio label="0">正常</el-radio>
|
||||
<el-radio label="1">维修中</el-radio>
|
||||
<el-radio label="2">停用</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="备注" prop="remark">
|
||||
<el-input v-model="form.remark" type="textarea" placeholder="请输入备注内容" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button type="primary" @click="submitForm">确 定</el-button>
|
||||
<el-button @click="visible = false">取 消</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, reactive, watch } from 'vue';
|
||||
import type { FormInstance, FormRules } from 'element-plus';
|
||||
import { DormRoomForm, DormRoomVO } from '@/api/xg/xgss/dormRoom/types';
|
||||
import { addDormRoom, updateDormRoom } from '@/api/xg/xgss/dormRoom';
|
||||
|
||||
const props = defineProps<{
|
||||
modelValue: boolean;
|
||||
title: string;
|
||||
roomId?: string | number;
|
||||
floorNum: number;
|
||||
buildingId: string | number;
|
||||
room?: DormRoomVO;
|
||||
}>();
|
||||
|
||||
const emit = defineEmits(['update:modelValue', 'success']);
|
||||
|
||||
const formRef = ref<FormInstance>();
|
||||
const visible = ref(false);
|
||||
|
||||
// 表单数据
|
||||
const initFormData: DormRoomForm = {
|
||||
id: undefined,
|
||||
roomCode: '',
|
||||
roomName: '',
|
||||
floorNum: 1,
|
||||
buildingId: '',
|
||||
actualBeds: 4,
|
||||
roomArea: 0,
|
||||
roomType: '1',
|
||||
roomStatus: '0',
|
||||
remark: ''
|
||||
};
|
||||
|
||||
const form = reactive<DormRoomForm>({ ...initFormData });
|
||||
|
||||
// 表单校验规则
|
||||
const rules = reactive<FormRules>({
|
||||
roomCode: [{ required: true, message: '房间编号不能为空', trigger: 'blur' }],
|
||||
roomName: [{ required: true, message: '房间名称不能为空', trigger: 'blur' }],
|
||||
floorNum: [{ required: true, message: '楼层不能为空', trigger: 'blur' }],
|
||||
actualBeds: [{ required: true, message: '床位数量不能为空', trigger: 'change' }],
|
||||
roomType: [{ required: true, message: '房间类型不能为空', trigger: 'change' }],
|
||||
roomStatus: [{ required: true, message: '房间状态不能为空', trigger: 'change' }]
|
||||
});
|
||||
|
||||
// 监听visible属性变化
|
||||
watch(
|
||||
() => props.modelValue,
|
||||
(val) => {
|
||||
visible.value = val;
|
||||
if (val) {
|
||||
// 完全重置表单,确保没有残留数据
|
||||
resetForm();
|
||||
|
||||
// 重新设置基本参数
|
||||
form.floorNum = props.floorNum;
|
||||
form.buildingId = props.buildingId;
|
||||
|
||||
// 如果是编辑模式且有room数据,填充表单数据
|
||||
if (props.room) {
|
||||
Object.keys(form).forEach((key) => {
|
||||
if (key in props.room) {
|
||||
form[key] = props.room[key];
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// 监听visible变化,同步回父组件
|
||||
watch(
|
||||
() => visible.value,
|
||||
(val) => {
|
||||
emit('update:modelValue', val);
|
||||
}
|
||||
);
|
||||
|
||||
// 关闭对话框
|
||||
const closeDialog = () => {
|
||||
visible.value = false;
|
||||
resetForm();
|
||||
};
|
||||
|
||||
// 重置表单
|
||||
const resetForm = () => {
|
||||
// 使用深拷贝确保完全重置
|
||||
Object.keys(form).forEach((key) => {
|
||||
form[key] = initFormData[key];
|
||||
});
|
||||
formRef.value?.resetFields();
|
||||
};
|
||||
|
||||
// 提交表单
|
||||
const submitForm = () => {
|
||||
formRef.value?.validate(async (valid) => {
|
||||
if (valid) {
|
||||
try {
|
||||
console.log(props.roomId);
|
||||
if (props.roomId) {
|
||||
// 修改
|
||||
form.id = props.roomId;
|
||||
await updateDormRoom(form);
|
||||
} else {
|
||||
// 新增
|
||||
await addDormRoom(form);
|
||||
}
|
||||
closeDialog();
|
||||
emit('success');
|
||||
} catch (error) {
|
||||
console.error('操作失败', error);
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// 添加默认导出以支持导入
|
||||
defineOptions({
|
||||
name: 'RoomDialog'
|
||||
});
|
||||
</script>
|
||||
File diff suppressed because it is too large.
Load diff
Reference in new issue
Block a user