fix(dorm): 人文学院宿舍分配班级树以班级表为准合并全校一年级
班级树改为 xg_class_msg 主数据源(无住宿生也可见),统一入学年口径与学院向上解析,避免代理院一年级列表不全或挂错。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
1 parent
04d12bbce1
commit
a0bb39d069
10 files changed
+324
-330
No files matched your search
+89
@@ -0,0 +1,89 @@
|
||||
package org.dromara.xg.helper;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.dromara.common.core.utils.StringUtils;
|
||||
import org.dromara.common.satoken.utils.LoginHelper;
|
||||
import org.dromara.xg.domain.XgSysDept;
|
||||
import org.dromara.xg.mapper.XgSysDeptMapper;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* 解析当前登录用户所属二级学院(沿部门祖先链向上查找)。
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class CurrentUserCollegeHelper {
|
||||
|
||||
private static final Long SECONDARY_COLLEGE_PARENT_ID = 101L;
|
||||
|
||||
private final XgSysDeptMapper xgSysDeptMapper;
|
||||
|
||||
/**
|
||||
* 从当前用户部门向上找二级学院:自身或 ancestors 中 parent_id=101 / dept_category 以 xy- 开头。
|
||||
*
|
||||
* @return 二级学院 dept_id;无法识别时返回 null
|
||||
*/
|
||||
public Long resolveCurrentUserCollegeId() {
|
||||
try {
|
||||
Long currentDeptId = LoginHelper.getDeptId();
|
||||
if (currentDeptId == null) {
|
||||
log.warn("用户未登录或没有部门信息");
|
||||
return null;
|
||||
}
|
||||
|
||||
XgSysDept currentDept = xgSysDeptMapper.selectById(currentDeptId);
|
||||
if (currentDept == null || !isActiveDept(currentDept)) {
|
||||
log.warn("当前用户部门不存在或已停用/删除, deptId={}", currentDeptId);
|
||||
return null;
|
||||
}
|
||||
|
||||
if (isSecondaryCollege(currentDept)) {
|
||||
return currentDept.getDeptId();
|
||||
}
|
||||
|
||||
String ancestors = currentDept.getAncestors();
|
||||
if (StringUtils.isBlank(ancestors)) {
|
||||
log.warn("当前用户部门无祖先链, deptId={}", currentDeptId);
|
||||
return null;
|
||||
}
|
||||
|
||||
String[] parts = ancestors.split(",");
|
||||
for (int i = parts.length - 1; i >= 0; i--) {
|
||||
String part = parts[i] == null ? "" : parts[i].trim();
|
||||
if (part.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
Long ancestorId;
|
||||
try {
|
||||
ancestorId = Long.valueOf(part);
|
||||
} catch (NumberFormatException e) {
|
||||
continue;
|
||||
}
|
||||
XgSysDept ancestor = xgSysDeptMapper.selectById(ancestorId);
|
||||
if (ancestor != null && isActiveDept(ancestor) && isSecondaryCollege(ancestor)) {
|
||||
return ancestor.getDeptId();
|
||||
}
|
||||
}
|
||||
|
||||
log.warn("未能从部门祖先链解析二级学院, deptId={}, ancestors={}", currentDeptId, ancestors);
|
||||
return null;
|
||||
} catch (Exception e) {
|
||||
log.error("获取当前用户二级学院ID失败", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isActiveDept(XgSysDept dept) {
|
||||
return "0".equals(dept.getStatus()) && "0".equals(dept.getDelFlag());
|
||||
}
|
||||
|
||||
private boolean isSecondaryCollege(XgSysDept dept) {
|
||||
if (SECONDARY_COLLEGE_PARENT_ID.equals(dept.getParentId())) {
|
||||
return true;
|
||||
}
|
||||
String category = dept.getDeptCategory();
|
||||
return StringUtils.isNotBlank(category) && category.startsWith("xy-");
|
||||
}
|
||||
}
|
||||
+21
-1
@@ -41,7 +41,7 @@ public class FreshmanCollegeProxyHelper {
|
||||
}
|
||||
|
||||
/**
|
||||
* 读取代理学院;未配置时返回 null(宿舍树降级为原逻辑,避免拖垮其它功能)。
|
||||
* 读取代理学院;未配置时返回 null(宿舍树按非代理处理:本院排除一年级)。
|
||||
*/
|
||||
public Long resolveProxyCollegeIdOrNull() {
|
||||
String configValue = configService.getConfigValue(
|
||||
@@ -74,4 +74,24 @@ public class FreshmanCollegeProxyHelper {
|
||||
return FreshmanCollegeProxySupport.canOperateClassForDormAllocation(
|
||||
operatorCollegeId, classCollegeId, enrollmentYear, resolveProxyCollegeIdOrNull());
|
||||
}
|
||||
|
||||
/**
|
||||
* 写路径校验:班级入学年必填,且符合一年级代理规则。
|
||||
*
|
||||
* @param className 班级名称(用于异常文案)
|
||||
*/
|
||||
public void assertCanOperateClassForDormAllocation(Long operatorCollegeId,
|
||||
Long classCollegeId,
|
||||
Long enrollmentYear,
|
||||
String className) {
|
||||
String displayName = StringUtils.blankToDefault(className, "");
|
||||
if (enrollmentYear == null) {
|
||||
throw new ServiceException("班级「" + displayName
|
||||
+ "」入学年信息不完整,无法分配/回收宿舍,请先维护班级入学年份");
|
||||
}
|
||||
if (!canOperateClassForDormAllocation(operatorCollegeId, classCollegeId, enrollmentYear)) {
|
||||
throw new ServiceException("无权操作班级「" + displayName
|
||||
+ "」的宿舍分配(一年级由人文学院代理,其它年级仅本学院可操作)");
|
||||
}
|
||||
}
|
||||
}
|
||||
+6
-6
@@ -103,18 +103,18 @@ public interface XgStudentMsgMapper extends BaseMapperPlus<XgStudentMsg, XgStude
|
||||
List<Map<String, Object>> getCollegeStudentStats(@Param("secondaryCollegeId") Long secondaryCollegeId);
|
||||
|
||||
/**
|
||||
* 查询二级学院下的学院、专业、班级学生统计信息(按床位分配统计)
|
||||
* 本院全部有效班级树统计(宿舍分配到班级,以 xg_class_msg 为准)
|
||||
*
|
||||
* @param secondaryCollegeId 二级学院ID
|
||||
* @return 学生统计信息列表
|
||||
* @param collegeId 二级学院ID(班级 college_id)
|
||||
* @return 班级统计行(含 enrollment_year;无住宿生人数可为 0)
|
||||
*/
|
||||
List<Map<String, Object>> getCollegeStudentStatsByClass(@Param("secondaryCollegeId") Long secondaryCollegeId);
|
||||
List<Map<String, Object>> getCollegeStudentStatsByClass(@Param("collegeId") Long collegeId);
|
||||
|
||||
/**
|
||||
* 按入学年查询全校一年级班级学生统计(宿舍分配到班级:代理学院可见)
|
||||
* 全校一年级班级树统计(宿舍分配到班级:代理学院可见,以班级 enrollment_year 为准)
|
||||
*
|
||||
* @param enrollmentYear 入学年(当前届)
|
||||
* @return 学生统计信息列表(含 enrollment_year)
|
||||
* @return 班级统计行(含 enrollment_year;无住宿生人数可为 0)
|
||||
*/
|
||||
List<Map<String, Object>> getFreshmanStudentStatsByClass(@Param("enrollmentYear") Integer enrollmentYear);
|
||||
|
||||
|
||||
+4
-52
@@ -16,15 +16,13 @@ import org.dromara.xg.domain.vo.XgDormBedDetailVo;
|
||||
import org.dromara.xg.domain.XgDormBed;
|
||||
import org.dromara.xg.domain.XgDormRoom;
|
||||
import org.dromara.xg.domain.XgDormBedStudent;
|
||||
import org.dromara.xg.domain.XgSysDept;
|
||||
import org.dromara.xg.domain.vo.XgStudentLeaveVo;
|
||||
import org.dromara.xg.mapper.XgDormBedMapper;
|
||||
import org.dromara.xg.mapper.XgDormRoomMapper;
|
||||
import org.dromara.xg.mapper.XgDormBedStudentMapper;
|
||||
import org.dromara.xg.mapper.XgSysDeptMapper;
|
||||
import org.dromara.xg.service.IXgDormBedService;
|
||||
import org.dromara.xg.service.IXgStudentLeaveService;
|
||||
import org.dromara.common.satoken.utils.LoginHelper;
|
||||
import org.dromara.xg.helper.CurrentUserCollegeHelper;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -49,8 +47,8 @@ public class XgDormBedServiceImpl implements IXgDormBedService {
|
||||
private final XgDormBedMapper baseMapper;
|
||||
private final XgDormRoomMapper xgDormRoomMapper;
|
||||
private final XgDormBedStudentMapper xgDormBedStudentMapper;
|
||||
private final XgSysDeptMapper xgSysDeptMapper;
|
||||
private final IXgStudentLeaveService xgStudentLeaveService;
|
||||
private final CurrentUserCollegeHelper currentUserCollegeHelper;
|
||||
|
||||
/**
|
||||
* 查询宿舍床位信息
|
||||
@@ -245,56 +243,10 @@ public class XgDormBedServiceImpl implements IXgDormBedService {
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前用户的二级学院ID
|
||||
* 通过当前用户的部门id,向上寻找包括他自己,找到dept_category前几位是xy-的就是二级学院
|
||||
* 或者parent_id = 101的部门就是二级学院
|
||||
* 获取当前用户的二级学院ID(沿部门祖先链向上解析)。
|
||||
*/
|
||||
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;
|
||||
}
|
||||
return currentUserCollegeHelper.resolveCurrentUserCollegeId();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+9
-62
@@ -49,8 +49,6 @@ 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;
|
||||
import org.dromara.xg.domain.bo.XgDormBedBatchAllocateToClassBo;
|
||||
@@ -59,6 +57,7 @@ import org.dromara.xg.domain.XgClassMsg;
|
||||
import org.dromara.xg.domain.vo.XgDormBedDetailVo;
|
||||
import org.dromara.xg.domain.bo.XgDormSelectiveAllocationBo;
|
||||
import org.dromara.xg.helper.FreshmanCollegeProxyHelper;
|
||||
import org.dromara.xg.helper.CurrentUserCollegeHelper;
|
||||
|
||||
/**
|
||||
* 床位学生分配关系Service业务层处理
|
||||
@@ -78,10 +77,10 @@ public class XgDormBedStudentServiceImpl implements IXgDormBedStudentService {
|
||||
private final XgStudentMsgMapper xgStudentMsgMapper;
|
||||
private final XgDormCampusMapper xgDormCampusMapper;
|
||||
private final XgDormAreaMapper xgDormAreaMapper;
|
||||
private final XgSysDeptMapper xgSysDeptMapper;
|
||||
private final XgClassMsgMapper xgClassMsgMapper;
|
||||
private final IXgStudentLeaveService xgStudentLeaveService;
|
||||
private final FreshmanCollegeProxyHelper freshmanCollegeProxyHelper;
|
||||
private final CurrentUserCollegeHelper currentUserCollegeHelper;
|
||||
|
||||
/**
|
||||
* 查询床位学生分配关系
|
||||
@@ -697,13 +696,10 @@ public class XgDormBedStudentServiceImpl implements IXgDormBedStudentService {
|
||||
throw new ServiceException("部分班级信息不存在,请检查班级ID");
|
||||
}
|
||||
|
||||
// 6.1 安全:一年级仅代理学院可分;非一年级仅本学院可分
|
||||
// 6.1 安全:入学年必填;一年级仅代理学院可分;非一年级仅本学院可分
|
||||
for (XgClassMsg clazz : classes) {
|
||||
if (!freshmanCollegeProxyHelper.canOperateClassForDormAllocation(
|
||||
operatorCollegeId, clazz.getCollegeId(), clazz.getEnrollmentYear())) {
|
||||
throw new ServiceException("无权将床位分配给班级「" + clazz.getClassName()
|
||||
+ "」(一年级由人文学院代理,其它年级仅本学院可操作)");
|
||||
}
|
||||
freshmanCollegeProxyHelper.assertCanOperateClassForDormAllocation(
|
||||
operatorCollegeId, clazz.getCollegeId(), clazz.getEnrollmentYear(), clazz.getClassName());
|
||||
}
|
||||
|
||||
// 建立班级ID到班级信息的映射
|
||||
@@ -1091,56 +1087,10 @@ public class XgDormBedStudentServiceImpl implements IXgDormBedStudentService {
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前用户的二级学院ID
|
||||
* 通过当前用户的部门id,向上寻找包括他自己,找到dept_category前几位是xy-的就是二级学院
|
||||
* 或者parent_id = 101的部门就是二级学院
|
||||
* 获取当前用户的二级学院ID(沿部门祖先链向上解析)。
|
||||
*/
|
||||
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;
|
||||
}
|
||||
return currentUserCollegeHelper.resolveCurrentUserCollegeId();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1169,11 +1119,8 @@ public class XgDormBedStudentServiceImpl implements IXgDormBedStudentService {
|
||||
if (clazz == null) {
|
||||
throw new ServiceException("床位关联班级不存在,禁止回收");
|
||||
}
|
||||
if (!freshmanCollegeProxyHelper.canOperateClassForDormAllocation(
|
||||
operatorCollegeId, clazz.getCollegeId(), clazz.getEnrollmentYear())) {
|
||||
throw new ServiceException("无权回收班级「" + clazz.getClassName()
|
||||
+ "」的宿舍分配(一年级由人文学院代理)");
|
||||
}
|
||||
freshmanCollegeProxyHelper.assertCanOperateClassForDormAllocation(
|
||||
operatorCollegeId, clazz.getCollegeId(), clazz.getEnrollmentYear(), clazz.getClassName());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+4
-52
@@ -14,12 +14,10 @@ import org.dromara.xg.domain.bo.XgDormRoomBo;
|
||||
import org.dromara.xg.domain.vo.XgDormRoomVo;
|
||||
import org.dromara.xg.domain.XgDormRoom;
|
||||
import org.dromara.xg.domain.XgDormBedStudent;
|
||||
import org.dromara.xg.domain.XgSysDept;
|
||||
import org.dromara.xg.mapper.XgDormRoomMapper;
|
||||
import org.dromara.xg.mapper.XgDormBedStudentMapper;
|
||||
import org.dromara.xg.mapper.XgSysDeptMapper;
|
||||
import org.dromara.xg.service.IXgDormRoomService;
|
||||
import org.dromara.common.satoken.utils.LoginHelper;
|
||||
import org.dromara.xg.helper.CurrentUserCollegeHelper;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -58,8 +56,8 @@ public class XgDormRoomServiceImpl implements IXgDormRoomService {
|
||||
|
||||
private final XgDormRoomMapper baseMapper;
|
||||
private final XgDormBedStudentMapper xgDormBedStudentMapper;
|
||||
private final XgSysDeptMapper xgSysDeptMapper;
|
||||
private final XgDormBedMapper xgDormBedMapper;
|
||||
private final CurrentUserCollegeHelper currentUserCollegeHelper;
|
||||
|
||||
/**
|
||||
* 查询宿舍房间信息
|
||||
@@ -234,56 +232,10 @@ public class XgDormRoomServiceImpl implements IXgDormRoomService {
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前用户的二级学院ID
|
||||
* 通过当前用户的部门id,向上寻找包括他自己,找到dept_category前几位是xy-的就是二级学院
|
||||
* 或者parent_id = 101的部门就是二级学院
|
||||
* 获取当前用户的二级学院ID(沿部门祖先链向上解析)。
|
||||
*/
|
||||
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;
|
||||
}
|
||||
return currentUserCollegeHelper.resolveCurrentUserCollegeId();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+14
-57
@@ -38,14 +38,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.xg.helper.FreshmanCollegeProxyHelper;
|
||||
import org.dromara.xg.helper.CurrentUserCollegeHelper;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import java.util.List;
|
||||
@@ -80,8 +79,8 @@ public class XgStudentMsgServiceImpl implements IXgStudentMsgService {
|
||||
private final XgClassTeacherCounselorRelMapper xgClassTeacherCounselorRelMapper;
|
||||
private final XgClassMsgMapper xgClassMsgMapper;
|
||||
private final XgDormBedStudentMapper xgDormBedStudentMapper;
|
||||
private final XgSysDeptMapper xgSysDeptMapper;
|
||||
private final FreshmanCollegeProxyHelper freshmanCollegeProxyHelper;
|
||||
private final CurrentUserCollegeHelper currentUserCollegeHelper;
|
||||
|
||||
/**
|
||||
* 查询学生信息
|
||||
@@ -1344,11 +1343,11 @@ public class XgStudentMsgServiceImpl implements IXgStudentMsgService {
|
||||
/**
|
||||
* 获取当前用户所在学院的学生信息树(宿舍「分配到班级」专用入口)。
|
||||
* <p>
|
||||
* 一年级代理规则(不改班级真实学院归属):
|
||||
* 一年级代理规则(不改班级真实学院归属;班级树以 xg_class_msg 为准):
|
||||
* <ul>
|
||||
* <li>代理学院(人文学院):本院全部班级 + 全校一年级班级</li>
|
||||
* <li>其他学院:本院非一年级班级(一年级隐藏,防双头操作)</li>
|
||||
* <li>代理学院未配置:保持原逻辑,仅本院班级</li>
|
||||
* <li>代理学院未配置:按非代理处理(本院 − 一年级),并打警告日志</li>
|
||||
* </ul>
|
||||
*/
|
||||
@Override
|
||||
@@ -1362,14 +1361,18 @@ public class XgStudentMsgServiceImpl implements IXgStudentMsgService {
|
||||
|
||||
Long proxyCollegeId = freshmanCollegeProxyHelper.resolveProxyCollegeIdOrNull();
|
||||
int cohortYear = freshmanCollegeProxyHelper.currentCohortYear();
|
||||
log.info("宿舍班级树:userCollegeId={}, proxyCollegeId={}, cohortYear={}",
|
||||
collegeId, proxyCollegeId, cohortYear);
|
||||
List<Map<String, Object>> collegeStats = baseMapper.getCollegeStudentStatsByClass(collegeId);
|
||||
log.info("宿舍班级树:userCollegeId={}, proxyCollegeId={}, cohortYear={}, ownClassRows={}",
|
||||
collegeId, proxyCollegeId, cohortYear, collegeStats.size());
|
||||
|
||||
if (proxyCollegeId == null) {
|
||||
return getStudentTreeByClass(collegeId);
|
||||
log.warn("一年级宿舍代理学院未配置,宿舍班级树按非代理处理(本院排除一年级)");
|
||||
List<Map<String, Object>> nonFreshmanStats = collegeStats.stream()
|
||||
.filter(item -> !isFreshmanStatRow(item, cohortYear))
|
||||
.collect(Collectors.toList());
|
||||
return buildStudentTreeFromClassStats(nonFreshmanStats);
|
||||
}
|
||||
|
||||
List<Map<String, Object>> collegeStats = baseMapper.getCollegeStudentStatsByClass(collegeId);
|
||||
if (proxyCollegeId.equals(collegeId)) {
|
||||
List<Map<String, Object>> freshmanStats =
|
||||
baseMapper.getFreshmanStudentStatsByClass(cohortYear);
|
||||
@@ -1549,55 +1552,9 @@ public class XgStudentMsgServiceImpl implements IXgStudentMsgService {
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前用户的二级学院ID
|
||||
* 通过当前用户的部门id,向上寻找包括他自己,找到dept_category前几位是xy-的就是二级学院
|
||||
* 或者parent_id = 101的部门就是二级学院
|
||||
* 获取当前用户的二级学院ID(沿部门祖先链向上解析)。
|
||||
*/
|
||||
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;
|
||||
}
|
||||
return currentUserCollegeHelper.resolveCurrentUserCollegeId();
|
||||
}
|
||||
}
|
||||
+73
-95
@@ -218,107 +218,85 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
ORDER BY c.grade DESC, sm.college_name, sm.major_name, sm.class_name, MAX(sm.create_time) DESC
|
||||
</select>
|
||||
|
||||
<!-- 查询二级学院下的学院、专业、班级学生统计信息(按床位分配统计) -->
|
||||
<!--
|
||||
宿舍「分配到班级」班级树:以 xg_class_msg 为主数据源(无住宿生也出班节点)。
|
||||
住宿生人数 / 已分配床位仅 LEFT JOIN 统计。
|
||||
-->
|
||||
<sql id="dormClassTreeSelectColumns">
|
||||
c.grade,
|
||||
c.enrollment_year AS enrollment_year,
|
||||
c.college_id,
|
||||
COALESCE(dc.dept_name, c.college_name) AS college_name,
|
||||
c.major_id,
|
||||
COALESCE(dm.dept_name, c.major_name) AS major_name,
|
||||
c.id AS class_id,
|
||||
c.class_name,
|
||||
COALESCE(SUM(CASE WHEN sm.id IS NOT NULL AND sm.gender = '0' AND sm.is_boarder = 1 THEN 1 ELSE 0 END), 0) AS male_total,
|
||||
COALESCE(SUM(CASE WHEN sm.id IS NOT NULL AND sm.gender = '1' AND sm.is_boarder = 1 THEN 1 ELSE 0 END), 0) AS female_total,
|
||||
COALESCE((
|
||||
SELECT COUNT(DISTINCT dbs.bed_id)
|
||||
FROM xg_dorm_bed_student dbs
|
||||
LEFT JOIN xg_dorm_bed db ON dbs.bed_id = db.id
|
||||
LEFT JOIN xg_dorm_room dr ON db.room_id = dr.id
|
||||
LEFT JOIN xg_dorm_building dbuild ON dr.building_id = dbuild.id
|
||||
WHERE dbs.class_id = c.id
|
||||
AND dbs.deleted = '0'
|
||||
AND dbs.status = '0'
|
||||
AND db.deleted = '0'
|
||||
AND dbuild.building_type = '1'
|
||||
), 0) AS male_assigned,
|
||||
COALESCE((
|
||||
SELECT COUNT(DISTINCT dbs.bed_id)
|
||||
FROM xg_dorm_bed_student dbs
|
||||
LEFT JOIN xg_dorm_bed db ON dbs.bed_id = db.id
|
||||
LEFT JOIN xg_dorm_room dr ON db.room_id = dr.id
|
||||
LEFT JOIN xg_dorm_building dbuild ON dr.building_id = dbuild.id
|
||||
WHERE dbs.class_id = c.id
|
||||
AND dbs.deleted = '0'
|
||||
AND dbs.status = '0'
|
||||
AND db.deleted = '0'
|
||||
AND dbuild.building_type = '2'
|
||||
), 0) AS female_assigned
|
||||
</sql>
|
||||
|
||||
<sql id="dormClassTreeFromJoin">
|
||||
FROM xg_class_msg c
|
||||
LEFT JOIN sys_dept dc ON c.college_id = dc.dept_id
|
||||
LEFT JOIN sys_dept dm ON c.major_id = dm.dept_id
|
||||
LEFT JOIN xg_student_msg sm ON sm.class_id = c.id
|
||||
AND sm.deleted = 0
|
||||
AND sm.student_status = '1'
|
||||
</sql>
|
||||
|
||||
<sql id="dormClassTreeGroupBy">
|
||||
GROUP BY c.grade, c.enrollment_year, c.college_id, COALESCE(dc.dept_name, c.college_name),
|
||||
c.major_id, COALESCE(dm.dept_name, c.major_name), c.id, c.class_name
|
||||
</sql>
|
||||
|
||||
<!-- 本院全部有效班级(宿舍分配到班级) -->
|
||||
<select id="getCollegeStudentStatsByClass" resultType="java.util.Map">
|
||||
SELECT
|
||||
c.grade,
|
||||
COALESCE(c.enrollment_year, sm.enrollment_year) AS enrollment_year,
|
||||
sm.college_id,
|
||||
sm.college_name,
|
||||
sm.major_id,
|
||||
sm.major_name,
|
||||
sm.class_id,
|
||||
sm.class_name,
|
||||
COALESCE(SUM(CASE WHEN sm.gender = '0' AND sm.is_boarder = 1 THEN 1 ELSE 0 END), 0) AS male_total,
|
||||
COALESCE(SUM(CASE WHEN sm.gender = '1' AND sm.is_boarder = 1 THEN 1 ELSE 0 END), 0) AS female_total,
|
||||
COALESCE((
|
||||
SELECT COUNT(DISTINCT dbs.bed_id)
|
||||
FROM xg_dorm_bed_student dbs
|
||||
LEFT JOIN xg_dorm_bed db ON dbs.bed_id = db.id
|
||||
LEFT JOIN xg_dorm_room dr ON db.room_id = dr.id
|
||||
LEFT JOIN xg_dorm_building dbuild ON dr.building_id = dbuild.id
|
||||
WHERE dbs.class_id = sm.class_id
|
||||
AND dbs.deleted = '0'
|
||||
AND dbs.status = '0'
|
||||
AND db.deleted = '0'
|
||||
AND dbuild.building_type = '1'
|
||||
), 0) AS male_assigned,
|
||||
COALESCE((
|
||||
SELECT COUNT(DISTINCT dbs.bed_id)
|
||||
FROM xg_dorm_bed_student dbs
|
||||
LEFT JOIN xg_dorm_bed db ON dbs.bed_id = db.id
|
||||
LEFT JOIN xg_dorm_room dr ON db.room_id = dr.id
|
||||
LEFT JOIN xg_dorm_building dbuild ON dr.building_id = dbuild.id
|
||||
WHERE dbs.class_id = sm.class_id
|
||||
AND dbs.deleted = '0'
|
||||
AND dbs.status = '0'
|
||||
AND db.deleted = '0'
|
||||
AND dbuild.building_type = '2'
|
||||
), 0) AS female_assigned
|
||||
FROM xg_student_msg sm
|
||||
LEFT JOIN xg_class_msg c ON sm.class_id = c.id
|
||||
LEFT JOIN sys_dept d ON sm.college_id = d.dept_id
|
||||
WHERE sm.deleted = 0
|
||||
AND sm.student_status = '1'
|
||||
AND sm.is_boarder = 1
|
||||
AND (d.parent_id = #{secondaryCollegeId} OR d.dept_id = #{secondaryCollegeId} OR FIND_IN_SET(#{secondaryCollegeId}, d.ancestors))
|
||||
AND sm.college_id IS NOT NULL
|
||||
AND sm.major_id IS NOT NULL
|
||||
AND sm.class_id IS NOT NULL
|
||||
GROUP BY c.grade, COALESCE(c.enrollment_year, sm.enrollment_year),
|
||||
sm.college_id, sm.college_name, sm.major_id, sm.major_name, sm.class_id, sm.class_name
|
||||
ORDER BY c.grade DESC, sm.college_name, sm.major_name, sm.class_name, MAX(sm.create_time) DESC
|
||||
<include refid="dormClassTreeSelectColumns"/>
|
||||
<include refid="dormClassTreeFromJoin"/>
|
||||
WHERE c.deleted = 0
|
||||
AND c.college_id = #{collegeId}
|
||||
AND c.college_id IS NOT NULL
|
||||
AND c.major_id IS NOT NULL
|
||||
<include refid="dormClassTreeGroupBy"/>
|
||||
ORDER BY c.grade DESC, college_name, major_name, c.class_name
|
||||
</select>
|
||||
|
||||
<!-- 全校一年级班级统计(宿舍分配到班级:人文学院代理可见) -->
|
||||
<!-- 全校一年级班级(宿舍分配到班级:人文学院代理可见;以班级 enrollment_year 为准) -->
|
||||
<select id="getFreshmanStudentStatsByClass" resultType="java.util.Map">
|
||||
SELECT
|
||||
c.grade,
|
||||
COALESCE(c.enrollment_year, sm.enrollment_year) AS enrollment_year,
|
||||
sm.college_id,
|
||||
sm.college_name,
|
||||
sm.major_id,
|
||||
sm.major_name,
|
||||
sm.class_id,
|
||||
sm.class_name,
|
||||
COALESCE(SUM(CASE WHEN sm.gender = '0' AND sm.is_boarder = 1 THEN 1 ELSE 0 END), 0) AS male_total,
|
||||
COALESCE(SUM(CASE WHEN sm.gender = '1' AND sm.is_boarder = 1 THEN 1 ELSE 0 END), 0) AS female_total,
|
||||
COALESCE((
|
||||
SELECT COUNT(DISTINCT dbs.bed_id)
|
||||
FROM xg_dorm_bed_student dbs
|
||||
LEFT JOIN xg_dorm_bed db ON dbs.bed_id = db.id
|
||||
LEFT JOIN xg_dorm_room dr ON db.room_id = dr.id
|
||||
LEFT JOIN xg_dorm_building dbuild ON dr.building_id = dbuild.id
|
||||
WHERE dbs.class_id = sm.class_id
|
||||
AND dbs.deleted = '0'
|
||||
AND dbs.status = '0'
|
||||
AND db.deleted = '0'
|
||||
AND dbuild.building_type = '1'
|
||||
), 0) AS male_assigned,
|
||||
COALESCE((
|
||||
SELECT COUNT(DISTINCT dbs.bed_id)
|
||||
FROM xg_dorm_bed_student dbs
|
||||
LEFT JOIN xg_dorm_bed db ON dbs.bed_id = db.id
|
||||
LEFT JOIN xg_dorm_room dr ON db.room_id = dr.id
|
||||
LEFT JOIN xg_dorm_building dbuild ON dr.building_id = dbuild.id
|
||||
WHERE dbs.class_id = sm.class_id
|
||||
AND dbs.deleted = '0'
|
||||
AND dbs.status = '0'
|
||||
AND db.deleted = '0'
|
||||
AND dbuild.building_type = '2'
|
||||
), 0) AS female_assigned
|
||||
FROM xg_student_msg sm
|
||||
LEFT JOIN xg_class_msg c ON sm.class_id = c.id
|
||||
WHERE sm.deleted = 0
|
||||
AND sm.student_status = '1'
|
||||
AND sm.is_boarder = 1
|
||||
AND sm.college_id IS NOT NULL
|
||||
AND sm.major_id IS NOT NULL
|
||||
AND sm.class_id IS NOT NULL
|
||||
AND COALESCE(c.enrollment_year, sm.enrollment_year) = #{enrollmentYear}
|
||||
GROUP BY c.grade, COALESCE(c.enrollment_year, sm.enrollment_year),
|
||||
sm.college_id, sm.college_name, sm.major_id, sm.major_name, sm.class_id, sm.class_name
|
||||
ORDER BY sm.college_name, sm.major_name, sm.class_name, MAX(sm.create_time) DESC
|
||||
<include refid="dormClassTreeSelectColumns"/>
|
||||
<include refid="dormClassTreeFromJoin"/>
|
||||
WHERE c.deleted = 0
|
||||
AND c.college_id IS NOT NULL
|
||||
AND c.major_id IS NOT NULL
|
||||
AND c.enrollment_year = #{enrollmentYear}
|
||||
<include refid="dormClassTreeGroupBy"/>
|
||||
ORDER BY college_name, major_name, c.class_name
|
||||
</select>
|
||||
|
||||
<!-- 查询二级学院下的学院床位分配统计信息(基于学生表统计需求,基于床位分配表统计已分配) -->
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
-- =============================================================================
|
||||
-- 宿舍「分配到班级」一年级代理:上线前只读核对
|
||||
-- 日期:2026-10-14
|
||||
-- =============================================================================
|
||||
|
||||
-- 1) 代理配置 vs 人文学院 dept_id
|
||||
SELECT config_key, config_value, remark
|
||||
FROM sys_config
|
||||
WHERE config_key = 'xg.studentLeave.freshmanProxyCollegeId';
|
||||
|
||||
SELECT dept_id, dept_name, parent_id, dept_category, status, del_flag
|
||||
FROM sys_dept
|
||||
WHERE dept_name = '人文学院'
|
||||
AND del_flag = '0';
|
||||
|
||||
-- 2) 当前届一年级班级数量(9 月 1 日切届)
|
||||
SET @cohort_year = YEAR(CURDATE()) - IF(MONTH(CURDATE()) >= 9, 0, 1);
|
||||
SELECT @cohort_year AS cohort_year,
|
||||
COUNT(*) AS freshman_class_cnt
|
||||
FROM xg_class_msg
|
||||
WHERE deleted = 0
|
||||
AND enrollment_year = @cohort_year;
|
||||
|
||||
-- 3) 入学年缺失
|
||||
SELECT id, class_name, grade, enrollment_year, college_id, college_name
|
||||
FROM xg_class_msg
|
||||
WHERE deleted = 0
|
||||
AND enrollment_year IS NULL
|
||||
LIMIT 200;
|
||||
|
||||
-- 4) 学生学院与班级学院漂移(可选治理)
|
||||
SELECT sm.id,
|
||||
sm.student_no,
|
||||
sm.name,
|
||||
sm.college_id AS stu_college,
|
||||
c.college_id AS class_college,
|
||||
c.class_name
|
||||
FROM xg_student_msg sm
|
||||
JOIN xg_class_msg c ON sm.class_id = c.id AND c.deleted = 0
|
||||
WHERE sm.deleted = 0
|
||||
AND sm.student_status = '1'
|
||||
AND sm.college_id IS NOT NULL
|
||||
AND c.college_id IS NOT NULL
|
||||
AND CAST(sm.college_id AS CHAR) <> CAST(c.college_id AS CHAR)
|
||||
LIMIT 200;
|
||||
@@ -6,26 +6,80 @@
|
||||
- **不修改**班级/学生真实 `college_id`。
|
||||
- 一年级床位须先在「分配到学院」分给人文学院,人文学院才能看到楼/房/床。
|
||||
- 其他学院在「分配到班级」中**看不到也不可操作**一年级班级(防双头)。
|
||||
- 一年级判定:`enrollment_year`,每年 **9 月 1 日**切届(与请假一致)。
|
||||
- 一年级判定:班级表 `xg_class_msg.enrollment_year`,每年 **9 月 1 日**切届(与请假一致)。
|
||||
- 配置键(复用请假):`xg.studentLeave.freshmanProxyCollegeId`
|
||||
|
||||
## 实现要点
|
||||
|
||||
| 能力 | 说明 |
|
||||
|------|------|
|
||||
| 班级树 | `getCurrentUserStudentTree`:代理院=本院∪全校一年级;其它院=本院−一年级 |
|
||||
| 写校验 | `batchAllocateBedsToClass` / `batchRecallClassAllocation`:床位须属操作人学院;班级权限按一年级代理规则 |
|
||||
| 班级树主数据 | 以 `xg_class_msg` 为准;无住宿生的班级也出节点(需求人数可为 0) |
|
||||
| 班级树 | `getCurrentUserStudentTree`:代理院=本院全部 ∪ 全校一年级;其它院=本院−一年级;配置缺失时按非代理处理并打 warn |
|
||||
| 展示归属 | 使用班级 `college_id` / 专业维度,不用学生冗余 `sm.college_*` |
|
||||
| 写校验 | `batchAllocateBedsToClass` / `batchRecallClassAllocation`:床位须属操作人学院;班级入学年必填;权限按一年级代理规则 |
|
||||
| 学院解析 | `CurrentUserCollegeHelper`:沿用户部门 ancestors **向上**找 `parent_id=101` 或 `xy-` |
|
||||
| 公共逻辑 | `FreshmanCollegeProxyHelper` / `FreshmanCollegeProxySupport` |
|
||||
|
||||
## 上线前数据核对(只读)
|
||||
|
||||
```sql
|
||||
-- 1) 代理配置 = 现网人文学院 dept_id
|
||||
SELECT config_key, config_value
|
||||
FROM sys_config
|
||||
WHERE config_key = 'xg.studentLeave.freshmanProxyCollegeId';
|
||||
|
||||
SELECT dept_id, dept_name, parent_id, dept_category
|
||||
FROM sys_dept
|
||||
WHERE dept_name = '人文学院' AND del_flag = '0';
|
||||
|
||||
-- 2) 当前届一年级班级数量(2026-09-01 后 enrollment_year = 当年)
|
||||
SELECT COUNT(*) AS freshman_class_cnt
|
||||
FROM xg_class_msg
|
||||
WHERE deleted = 0
|
||||
AND enrollment_year = YEAR(CURDATE()) - IF(MONTH(CURDATE()) >= 9, 0, 1);
|
||||
|
||||
-- 3) 入学年缺失或疑似冲突
|
||||
SELECT id, class_name, grade, enrollment_year, college_id, college_name
|
||||
FROM xg_class_msg
|
||||
WHERE deleted = 0
|
||||
AND (enrollment_year IS NULL
|
||||
OR (grade IS NOT NULL AND grade NOT LIKE CONCAT('%', enrollment_year, '%')))
|
||||
LIMIT 200;
|
||||
|
||||
-- 4) 学生学院与班级学院漂移(树已不再依赖学生学院挂载,仍建议治理)
|
||||
SELECT sm.id, sm.student_no, sm.name, sm.college_id AS stu_college,
|
||||
c.college_id AS class_college, c.class_name
|
||||
FROM xg_student_msg sm
|
||||
JOIN xg_class_msg c ON sm.class_id = c.id AND c.deleted = 0
|
||||
WHERE sm.deleted = 0
|
||||
AND sm.student_status = '1'
|
||||
AND sm.college_id IS NOT NULL
|
||||
AND c.college_id IS NOT NULL
|
||||
AND CAST(sm.college_id AS CHAR) <> CAST(c.college_id AS CHAR)
|
||||
LIMIT 200;
|
||||
```
|
||||
|
||||
核对后:若配置值与人文 `dept_id` 不一致,更新 `sys_config` 并刷新参数缓存 / 重启后端。
|
||||
|
||||
## 运营注意
|
||||
|
||||
1. 系统参数中确认人文学院 `dept_id` 已配置。
|
||||
1. 系统参数中确认人文学院 `dept_id` 已配置且与账号解析出的学院 ID 一致。
|
||||
2. 一年级床位在 `xsssfpejxy` 分给人文学院。
|
||||
3. 切届后:树自动切回本学院;若床位 `college_id` 仍挂人文,需另行移交(本期未自动迁移)。
|
||||
4. 班级 `enrollment_year` 为空时:不计入一年级树;分配/回收会报错,需先维护入学年。
|
||||
|
||||
## 验收用例
|
||||
|
||||
1. **人文账号**:看见本院全部班级 + 全校当前届一年级班级;可对一年级分配/回收。
|
||||
2. **其它学院账号**:只见本院非一年级;操作一年级被拒。
|
||||
3. **人文下级科室账号**:解析学院仍为人文学院,代理分支生效(可见全校一年级)。
|
||||
4. **无住宿生的一年级空班**:树中可见,男女需求可为 0,仍可分配床位。
|
||||
|
||||
## 相关代码
|
||||
|
||||
- `backend/ruoyi-modules/ruoyi-xg/.../helper/CurrentUserCollegeHelper.java`
|
||||
- `backend/ruoyi-modules/ruoyi-xg/.../helper/FreshmanCollegeProxyHelper.java`
|
||||
- `backend/ruoyi-modules/ruoyi-xg/.../service/impl/XgStudentMsgServiceImpl.java`
|
||||
- `backend/ruoyi-modules/ruoyi-xg/.../service/impl/XgDormBedStudentServiceImpl.java`
|
||||
- `web/src/views/xg/xgss/ejxyfp/`(前端仍调原 API,无强制改动)
|
||||
- `backend/ruoyi-modules/ruoyi-xg/.../resources/mapper/studentMsg/XgStudentMsgMapper.xml`
|
||||
- `web/src/views/xg/xgss/ejxyfp/`(前端仍调原 API)
|
||||
Reference in new issue
Block a user