@@ -106,14 +106,41 @@ public class DormController {
|
|||||||
dormService.setMonitor(roomId, studentId);
|
dormService.setMonitor(roomId, studentId);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 从 bschclass 学籍导入全校学生到待安排池(幂等),返回新增人数。 */
|
/** 可添加学生名单:bschclass 在册学生,排除已保存到 dorm_student 的(供前端勾选)。 */
|
||||||
@PostMapping("ImportStudents")
|
@GetMapping("AvailableStudents")
|
||||||
public Map<String, Object> importStudents() {
|
public List<Map<String, Object>> availableStudents(@RequestParam(required = false) String keyword) {
|
||||||
|
return dormService.availableStudents(keyword);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 保存前端勾选的学生到待安排池(roomId=0),返回新增人数。 */
|
||||||
|
@PostMapping("SaveStudents")
|
||||||
|
public Map<String, Object> saveStudents(@RequestParam String studentIds) {
|
||||||
Map<String, Object> r = new java.util.LinkedHashMap<>();
|
Map<String, Object> r = new java.util.LinkedHashMap<>();
|
||||||
r.put("added", dormService.importStudentsFromBschclass());
|
r.put("added", dormService.saveStudents(parseIds(studentIds)));
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** 手动删除已保存的学生(在住者重排该房床位),返回删除人数。 */
|
||||||
|
@PostMapping("DeleteStudents")
|
||||||
|
public Map<String, Object> deleteStudents(@RequestParam String studentIds) {
|
||||||
|
Map<String, Object> r = new java.util.LinkedHashMap<>();
|
||||||
|
r.put("removed", dormService.deleteStudents(parseIds(studentIds)));
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List<Integer> parseIds(String csv) {
|
||||||
|
List<Integer> ids = new java.util.ArrayList<>();
|
||||||
|
if (csv != null) {
|
||||||
|
for (String s : csv.split(",")) {
|
||||||
|
String t = s.trim();
|
||||||
|
if (!t.isEmpty()) {
|
||||||
|
ids.add(Integer.parseInt(t));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ids;
|
||||||
|
}
|
||||||
|
|
||||||
private static Map<String, Object> toObj(Map<String, String> src) {
|
private static Map<String, Object> toObj(Map<String, String> src) {
|
||||||
return src.entrySet().stream().collect(java.util.stream.Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
|
return src.entrySet().stream().collect(java.util.stream.Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,6 +41,15 @@ public interface IDormService {
|
|||||||
/** 楼栋→楼层→房间树(ztree,供发布选房间;对应 base/GetDormTree)。 */
|
/** 楼栋→楼层→房间树(ztree,供发布选房间;对应 base/GetDormTree)。 */
|
||||||
List<Map<String, Object>> dormTree();
|
List<Map<String, Object>> dormTree();
|
||||||
|
|
||||||
/** 从 bschclass 学籍导入全校学生到「待安排池」(roomId=0),幂等;返回新增人数。 */
|
/**
|
||||||
int importStudentsFromBschclass();
|
* 可添加学生名单:从 bschclass 学籍拉取本校在册学生,排除已保存到 dorm_student 的,供前端勾选。
|
||||||
|
* 返回项:{studentId, studentName, className}。
|
||||||
|
*/
|
||||||
|
List<Map<String, Object>> availableStudents(String keyword);
|
||||||
|
|
||||||
|
/** 保存前端勾选的学生到 dorm_student(roomId=0 待安排池),已存在的跳过;返回新增人数。 */
|
||||||
|
int saveStudents(List<Integer> studentIds);
|
||||||
|
|
||||||
|
/** 手动删除 dorm_student 中的学生(在住者删除后重排该房床位);返回删除人数。 */
|
||||||
|
int deleteStudents(List<Integer> studentIds);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -108,19 +108,8 @@ public class DormService implements IDormService {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<Map<String, Object>> pendingStudents(String keyword, String gender) {
|
public List<Map<String, Object>> pendingStudents(String keyword, String gender) {
|
||||||
// 待安排池:dorm_student 中 roomId=0/null。池空时惰性从 bschclass 学籍导入一次,
|
// 待安排池:dorm_student 中 roomId=0(由「添加学生」手动保存进来的在册学生)
|
||||||
// 让「安排入住」有数据源;导入失败(平台不可达等)不影响页面,返回空池。
|
|
||||||
List<DormStudent> raw = studentRepository.findByRoomIdOrderByIdAsc(0);
|
List<DormStudent> raw = studentRepository.findByRoomIdOrderByIdAsc(0);
|
||||||
if (raw.isEmpty()) {
|
|
||||||
try {
|
|
||||||
int n = importStudentsFromBschclass();
|
|
||||||
if (n > 0) {
|
|
||||||
raw = studentRepository.findByRoomIdOrderByIdAsc(0);
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
log.warn("[pendingStudents] 从 bschclass 导入学生失败,返回空池: {}", e.getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
List<DormStudent> pool = raw.stream()
|
List<DormStudent> pool = raw.stream()
|
||||||
.filter(s -> !StringUtils.hasText(gender) || gender.equals(s.getGender()))
|
.filter(s -> !StringUtils.hasText(gender) || gender.equals(s.getGender()))
|
||||||
.filter(s -> !StringUtils.hasText(keyword)
|
.filter(s -> !StringUtils.hasText(keyword)
|
||||||
@@ -378,45 +367,98 @@ public class DormService implements IDormService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============================ bschclass 学籍导入 ============================
|
// ============================ bschclass 学籍(前端选择保存) ============================
|
||||||
|
|
||||||
@Override
|
private static final class Roster {
|
||||||
@Transactional
|
final List<SchStudentDto> students;
|
||||||
public int importStudentsFromBschclass() {
|
final Map<Integer, String> classNames;
|
||||||
|
Roster(List<SchStudentDto> students, Map<Integer, String> classNames) {
|
||||||
|
this.students = students;
|
||||||
|
this.classNames = classNames;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 拉取本校在册学生 + 班级名映射;无学校上下文/失败/空返回 null(调用方按空处理)。 */
|
||||||
|
private Roster fetchRoster() {
|
||||||
Integer schId = UserContext.getSchId();
|
Integer schId = UserContext.getSchId();
|
||||||
if (schId == null) {
|
if (schId == null) {
|
||||||
throw new BizException(ErrorCode.PARAM_ERROR, "未获取到学校上下文,无法导入学生");
|
return null;
|
||||||
}
|
}
|
||||||
SchInfoDto info = classService.getSchFirst(schId);
|
SchInfoDto info = classService.getSchFirst(schId);
|
||||||
if (info == null || !StringUtils.hasText(info.getSchSerId())) {
|
if (info == null || !StringUtils.hasText(info.getSchSerId())) {
|
||||||
log.warn("[importStudents] schId={} 未取到 bschclass SchSerId", schId);
|
log.warn("[dorm] schId={} 未取到 bschclass SchSerId", schId);
|
||||||
return 0;
|
return null;
|
||||||
}
|
}
|
||||||
String schSerId = info.getSchSerId();
|
List<SchStudentDto> stus = classService.getSchStuList(info.getSchSerId());
|
||||||
List<SchStudentDto> stus = classService.getSchStuList(schSerId);
|
|
||||||
if (stus == null || stus.isEmpty()) {
|
if (stus == null || stus.isEmpty()) {
|
||||||
return 0;
|
return null;
|
||||||
}
|
}
|
||||||
Map<Integer, String> classNames = new HashMap<>();
|
Map<Integer, String> classNames = new HashMap<>();
|
||||||
try {
|
try {
|
||||||
for (SchClassDto c : classService.getSchClassList(schSerId)) {
|
for (SchClassDto c : classService.getSchClassList(info.getSchSerId())) {
|
||||||
classNames.put(c.getClassId(), c.getClassName());
|
classNames.put(c.getClassId(), c.getClassName());
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.warn("[importStudents] 取班级名单失败(班级名留空): {}", e.getMessage());
|
log.warn("[dorm] 取班级名单失败(班级名留空): {}", e.getMessage());
|
||||||
}
|
}
|
||||||
int added = 0;
|
return new Roster(stus, classNames);
|
||||||
for (SchStudentDto s : stus) {
|
}
|
||||||
if (s.getStuId() == null) {
|
|
||||||
|
@Override
|
||||||
|
public List<Map<String, Object>> availableStudents(String keyword) {
|
||||||
|
List<Map<String, Object>> out = new ArrayList<>();
|
||||||
|
Roster roster = fetchRoster();
|
||||||
|
if (roster == null) {
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
Set<Integer> savedIds = studentRepository.findAll().stream()
|
||||||
|
.map(DormStudent::getStudentId).filter(Objects::nonNull).collect(Collectors.toSet());
|
||||||
|
String kw = keyword == null ? "" : keyword.trim();
|
||||||
|
for (SchStudentDto s : roster.students) {
|
||||||
|
if (s.getStuId() == null || savedIds.contains(s.getStuId())) {
|
||||||
|
continue; // 排除已保存到 dorm_student 的
|
||||||
|
}
|
||||||
|
if (!kw.isEmpty() && !String.valueOf(s.getStuName()).contains(kw)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (studentRepository.findByStudentId(s.getStuId()).isPresent()) {
|
Map<String, Object> m = new LinkedHashMap<>();
|
||||||
continue; // 已存在(在住或已在池)跳过,幂等
|
m.put("studentId", s.getStuId());
|
||||||
|
m.put("studentName", s.getStuName());
|
||||||
|
m.put("className", roster.classNames.get(s.getClassId()));
|
||||||
|
out.add(m);
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional
|
||||||
|
public int saveStudents(List<Integer> studentIds) {
|
||||||
|
if (studentIds == null || studentIds.isEmpty()) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
Integer schId = UserContext.getSchId();
|
||||||
|
// 用最新在册名单补全姓名/班级(拿不到也不阻断,按 id 落库)
|
||||||
|
Map<Integer, SchStudentDto> rosterById = new HashMap<>();
|
||||||
|
Map<Integer, String> classNames = new HashMap<>();
|
||||||
|
Roster roster = fetchRoster();
|
||||||
|
if (roster != null) {
|
||||||
|
for (SchStudentDto s : roster.students) {
|
||||||
|
if (s.getStuId() != null) {
|
||||||
|
rosterById.put(s.getStuId(), s);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
classNames = roster.classNames;
|
||||||
|
}
|
||||||
|
int added = 0;
|
||||||
|
for (Integer id : studentIds) {
|
||||||
|
if (id == null || studentRepository.findByStudentId(id).isPresent()) {
|
||||||
|
continue; // 已存在跳过,幂等
|
||||||
|
}
|
||||||
|
SchStudentDto s = rosterById.get(id);
|
||||||
DormStudent d = new DormStudent();
|
DormStudent d = new DormStudent();
|
||||||
d.setStudentId(s.getStuId());
|
d.setStudentId(id);
|
||||||
d.setStudentName(s.getStuName());
|
d.setStudentName(s != null ? s.getStuName() : null);
|
||||||
d.setClassName(classNames.get(s.getClassId()));
|
d.setClassName(s != null ? classNames.get(s.getClassId()) : null);
|
||||||
d.setRoomId(0);
|
d.setRoomId(0);
|
||||||
d.setIsMonitor(false);
|
d.setIsMonitor(false);
|
||||||
d.setSourceDesc("学籍在册未分配床位");
|
d.setSourceDesc("学籍在册未分配床位");
|
||||||
@@ -424,10 +466,39 @@ public class DormService implements IDormService {
|
|||||||
studentRepository.save(d);
|
studentRepository.save(d);
|
||||||
added++;
|
added++;
|
||||||
}
|
}
|
||||||
log.info("[importStudents] schId={} schSerId={} 学籍 {} 人,新导入待安排 {} 人", schId, schSerId, stus.size(), added);
|
log.info("[saveStudents] schId={} 勾选 {} 人,新增保存 {} 人", schId, studentIds.size(), added);
|
||||||
return added;
|
return added;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional
|
||||||
|
public int deleteStudents(List<Integer> studentIds) {
|
||||||
|
if (studentIds == null || studentIds.isEmpty()) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
int removed = 0;
|
||||||
|
Set<Integer> roomsToRenumber = new HashSet<>();
|
||||||
|
for (Integer id : studentIds) {
|
||||||
|
if (id == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
Optional<DormStudent> opt = studentRepository.findByStudentId(id);
|
||||||
|
if (opt.isPresent()) {
|
||||||
|
Integer rid = opt.get().getRoomId();
|
||||||
|
studentRepository.delete(opt.get());
|
||||||
|
if (rid != null && rid > 0) {
|
||||||
|
roomsToRenumber.add(rid);
|
||||||
|
}
|
||||||
|
removed++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (Integer rid : roomsToRenumber) {
|
||||||
|
renumberBeds(rid);
|
||||||
|
}
|
||||||
|
log.info("[deleteStudents] 手动删除 {} 人", removed);
|
||||||
|
return removed;
|
||||||
|
}
|
||||||
|
|
||||||
// ============================ 辅助 ============================
|
// ============================ 辅助 ============================
|
||||||
|
|
||||||
private List<DormBuilding> buildingsOfSch() {
|
private List<DormBuilding> buildingsOfSch() {
|
||||||
|
|||||||
Reference in New Issue
Block a user