diff --git a/src/main/java/com/yunhai/homework/model/homework/HomeworkVo.java b/src/main/java/com/yunhai/homework/model/homework/HomeworkVo.java index 811b822..bbc51fa 100644 --- a/src/main/java/com/yunhai/homework/model/homework/HomeworkVo.java +++ b/src/main/java/com/yunhai/homework/model/homework/HomeworkVo.java @@ -48,6 +48,9 @@ public class HomeworkVo { /** 接收人列表(JSON) */ private String receiveList; + /** 班级展示文本(年级名前缀,如「高一1班、高一2班」;前端「班级」列直接展示) */ + private String receiveText; + /** 附件ID串("1,2,3",列表页下载入口使用;对齐旧 .NET UpFile 字段) */ private String UpFile; diff --git a/src/main/java/com/yunhai/homework/service/impl/HomeworkService.java b/src/main/java/com/yunhai/homework/service/impl/HomeworkService.java index 1172a84..1dd42f6 100644 --- a/src/main/java/com/yunhai/homework/service/impl/HomeworkService.java +++ b/src/main/java/com/yunhai/homework/service/impl/HomeworkService.java @@ -95,6 +95,9 @@ public class HomeworkService implements IHomeworkService { @Autowired private SubjectDictService subjectDictService; + @Autowired + private RosterService rosterService; + private static final int PUBLISHED = HomeworkStatusEnum.PUBLISHED.getCode(); // ============================ 发作业 ============================ @@ -338,11 +341,43 @@ public class HomeworkService implements IHomeworkService { List fids = fileMap.getOrDefault(vo.getId(), Collections.emptyList()); vo.setUpFile(fids.stream().map(String::valueOf).collect(Collectors.joining(","))); } + fillReceiveText(content); fillProgress(content); } return PageUtils.toResult(new PageImpl<>(content, pageable, page.getTotalElements())); } + /** + * 批量回填列表页「班级」列展示文本(年级名前缀,如「高一1班、高一2班」): + * receiveList 为 ALL/空 → 「全部班级」;其余按 homework_class 关联实时解析 + * (RosterService 映射含年级前缀),班级名快照兜底、再退班级ID;一次批量查询 + 一次 bschclass 外呼。 + * 无班级关联的行保持 null(前端回退「-」)。 + */ + private void fillReceiveText(List content) { + List homeworkIds = content.stream().map(HomeworkVo::getId).collect(Collectors.toList()); + Map> byHw = homeworkClassRepository.findByHomeworkIds(homeworkIds).stream() + .collect(Collectors.groupingBy(HomeworkClass::getHomeworkId)); + Map classNames = rosterService.classNames(byHw.values().stream() + .flatMap(List::stream) + .map(HomeworkClass::getClassId) + .distinct() + .collect(Collectors.toList())); + for (HomeworkVo vo : content) { + String rl = vo.getReceiveList(); + if (rl == null || rl.trim().isEmpty() || "ALL".equalsIgnoreCase(rl.trim())) { + vo.setReceiveText("全部班级"); + continue; + } + List classes = byHw.getOrDefault(vo.getId(), Collections.emptyList()); + if (classes.isEmpty()) { + continue; + } + vo.setReceiveText(classes.stream() + .map(c -> RosterService.displayOr(classNames.get(c.getClassId()), c.getClassName(), c.getClassId())) + .collect(Collectors.joining("、"))); + } + } + /** * 批量回填列表页提交/批改进度(「全部作业」页的 提交进度 / 未读未交 / 批改 列)。 *

口径与 V2 一致:草稿两态与仅查阅型作业不计(progress 保持 null,前端显示「—」); @@ -889,23 +924,19 @@ public class HomeworkService implements IHomeworkService { } /** - * 接收对象可读文本:优先用 homework_class 的班级名快照("高一(1)班、高一(2)班")。 - * 快照缺失时退回 id 串,保证「接收班级」标签不显示空白。 + * 接收对象可读文本(年级名前缀,如「高一(1)班、高一(2)班」):实时解析 + * (RosterService 映射含年级前缀),班级名快照兜底、再退 id 串,保证「接收班级」标签不显示空白。 */ private String receiveText(Integer homeworkId) { List classes = homeworkClassRepository.findByHomeworkId(homeworkId); if (classes.isEmpty()) { return null; } - String names = classes.stream() - .map(HomeworkClass::getClassName) - .filter(StringUtils::hasText) - .collect(Collectors.joining("、")); - if (StringUtils.hasText(names)) { - return names; - } + Map classNames = rosterService.classNames(classes.stream() + .map(HomeworkClass::getClassId) + .collect(Collectors.toList())); return classes.stream() - .map(c -> String.valueOf(c.getClassId())) + .map(c -> RosterService.displayOr(classNames.get(c.getClassId()), c.getClassName(), c.getClassId())) .collect(Collectors.joining("、")); } diff --git a/src/main/java/com/yunhai/homework/service/impl/RosterService.java b/src/main/java/com/yunhai/homework/service/impl/RosterService.java index 62ba227..72bc487 100644 --- a/src/main/java/com/yunhai/homework/service/impl/RosterService.java +++ b/src/main/java/com/yunhai/homework/service/impl/RosterService.java @@ -1,6 +1,7 @@ package com.yunhai.homework.service.impl; import com.yunhai.homework.model.bsch.SchClassDto; +import com.yunhai.homework.model.bsch.SchGradeDto; import com.yunhai.homework.model.bsch.SchInfoDto; import com.yunhai.homework.model.bsch.SchStudentDto; import com.yunhai.homework.service.IClassService; @@ -88,7 +89,8 @@ public class RosterService { } /** - * 班级ID → 班级名(bschclass GetVClassList 映射)。 + * 班级ID → 班级展示名(bschclass GetVClassList 映射,前缀年级名,如「高一1班」; + * 班级名已含年级前缀时不重复拼接)。年级列表拉取失败时退化为原班级名, * 远端不可用或无学校身份时降级为空映射,由调用方回退班级ID展示,不阻断名单本身。 */ public Map classNames(Collection classIds) { @@ -102,19 +104,25 @@ public class RosterService { return names; } Set pending = new LinkedHashSet<>(classIds); + Map matched = new LinkedHashMap<>(); for (SchClassDto c : classService.getSchClassList(schSerId)) { if (c != null && c.getClassId() != null && pending.remove(c.getClassId()) && StringUtils.hasText(c.getClassName())) { - names.put(c.getClassId(), c.getClassName()); + matched.put(c.getClassId(), c); } } + Map grades = matched.isEmpty() ? Collections.emptyMap() : gradeNames(schSerId); + for (Map.Entry e : matched.entrySet()) { + SchClassDto c = e.getValue(); + names.put(e.getKey(), displayName(c.getClassName(), c.getGradeId(), grades)); + } } catch (BizException e) { log.warn("[roster] 班级名称映射失败, 回退班级ID展示: {}", e.getMessage()); } return names; } - /** 班级ID → 班级名(单班便捷方法,缺失回退班级ID) */ + /** 班级ID → 班级展示名(单班便捷方法,缺失回退班级ID) */ public String className(Integer classId) { if (classId == null) { return null; @@ -123,6 +131,45 @@ public class RosterService { return StringUtils.hasText(name) ? name : String.valueOf(classId); } + /** + * 班级展示名合成:年级名 + 班级名(如「高一」+「1班」=「高一1班」), + * 班级名已以年级名开头时不重复拼接;缺年级或无班级名时原样返回。 + */ + public static String displayName(String className, Integer gradeId, Map gradeNames) { + if (!StringUtils.hasText(className) || gradeId == null + || gradeNames == null || gradeNames.isEmpty()) { + return className; + } + String gradeName = gradeNames.get(gradeId); + if (!StringUtils.hasText(gradeName) || className.startsWith(gradeName)) { + return className; + } + return gradeName + className; + } + + /** 列表展示名兜底:实时名(含年级前缀)优先,其次班级名快照,最后班级ID */ + public static String displayOr(String liveName, String snapshotName, Integer classId) { + if (StringUtils.hasText(liveName)) { + return liveName; + } + return StringUtils.hasText(snapshotName) ? snapshotName : String.valueOf(classId); + } + + /** 年级ID → 年级名(bschclass GetSchLenLevellist;失败降级空映射,仅退化为不带年级前缀) */ + private Map gradeNames(String schSerId) { + Map names = new LinkedHashMap<>(); + try { + for (SchGradeDto g : classService.getSchGradeList(schSerId)) { + if (g != null && g.getId() != null && StringUtils.hasText(g.getName())) { + names.put(g.getId(), g.getName()); + } + } + } catch (BizException e) { + log.warn("[roster] 年级列表拉取失败, 班级名退化为不带年级前缀: {}", e.getMessage()); + } + return names; + } + /** * 当前登录学生所在班级条目(实时 bschclass 全校学生按登录人用户ID过滤)。 * 学生ID = 登录人用户中心数字ID;一人多班各一条。 diff --git a/src/main/java/com/yunhai/homework/service/impl/StudentHomeworkService.java b/src/main/java/com/yunhai/homework/service/impl/StudentHomeworkService.java index 980add9..3828553 100644 --- a/src/main/java/com/yunhai/homework/service/impl/StudentHomeworkService.java +++ b/src/main/java/com/yunhai/homework/service/impl/StudentHomeworkService.java @@ -158,9 +158,7 @@ public class StudentHomeworkService { vo.setDescription(homework.getContent()); vo.setAttachments(homeworkAttachmentRepository.findByHomeworkIdOrderBySortAscIdAsc(id).stream() .map(this::toAttachmentItem).collect(Collectors.toList())); - vo.setClasses(homeworkClassRepository.findByHomeworkId(id).stream() - .map(c -> new ClassItem(c.getClassId(), c.getClassName())) - .collect(Collectors.toList())); + vo.setClasses(classDisplayItems(homeworkClassRepository.findByHomeworkId(id))); if (latest != null) { vo.setMyText(latest.getText()); vo.setMyAttachments(submissionAttachmentRepository @@ -408,6 +406,19 @@ public class StudentHomeworkService { return vo; } + /** + * 参与班级条目:展示名实时解析(bschclass 映射,含年级前缀), + * 实时名缺失回退作业上的班级名快照,再退班级ID。 + */ + private List classDisplayItems(List classes) { + Map classNames = rosterService.classNames( + classes.stream().map(HomeworkClass::getClassId).collect(Collectors.toList())); + return classes.stream() + .map(c -> new ClassItem(c.getClassId(), + RosterService.displayOr(classNames.get(c.getClassId()), c.getClassName(), c.getClassId()))) + .collect(Collectors.toList()); + } + private void copyBase(StudentHomeworkVo vo, Homework h, HomeworkSubmission latest, Map subjectNames) { vo.setId(h.getId()); diff --git a/src/main/java/com/yunhai/homework/service/impl/TeacherHomeworkV2Service.java b/src/main/java/com/yunhai/homework/service/impl/TeacherHomeworkV2Service.java index 5f0c0ee..253c048 100644 --- a/src/main/java/com/yunhai/homework/service/impl/TeacherHomeworkV2Service.java +++ b/src/main/java/com/yunhai/homework/service/impl/TeacherHomeworkV2Service.java @@ -258,7 +258,10 @@ public class TeacherHomeworkV2Service { query), PageUtils.toPageable(query, sort == null ? Sort.by(Sort.Direction.DESC, "updateTime") : sort)); Map subjectNames = subjectDictService.nameMap(); - return PageUtils.toResult(page.map(h -> toVo(h, false, false, subjectNames))); + Map> classesByHw = classesByHomework(page.getContent()); + Map classNames = rosterService.classNames(allClassIds(classesByHw)); + return PageUtils.toResult(page.map(h -> toVo(h, false, false, subjectNames, + classesByHw.getOrDefault(h.getId(), Collections.emptyList()), classNames))); } // ============================ 页 3:已发布列表 ============================ @@ -276,7 +279,10 @@ public class TeacherHomeworkV2Service { ownedStatusSpec(UserContext.getUserId(), statuses, query), PageUtils.toPageable(query, sort == null ? Sort.by(Sort.Direction.DESC, "publishedAt") : sort)); Map subjectNames = subjectDictService.nameMap(); - return PageUtils.toResult(page.map(h -> toVo(h, false, true, subjectNames))); + Map> classesByHw = classesByHomework(page.getContent()); + Map classNames = rosterService.classNames(allClassIds(classesByHw)); + return PageUtils.toResult(page.map(h -> toVo(h, false, true, subjectNames, + classesByHw.getOrDefault(h.getId(), Collections.emptyList()), classNames))); } private Specification ownedStatusSpec(Integer publisherId, List statuses, TeacherHomeworkQuery query) { @@ -396,7 +402,10 @@ public class TeacherHomeworkV2Service { @Transactional(readOnly = true) public HomeworkV2Vo detail(Integer id) { Homework homework = stateService.requireOwned(id, UserContext.getUserId()); - return toVo(homework, true, !HwStatusEnum.of(homework.getHwStatus()).isDraft(), subjectDictService.nameMap()); + List classes = homeworkClassRepository.findByHomeworkId(id); + Map classNames = rosterService.classNames(classIds(classes)); + return toVo(homework, true, !HwStatusEnum.of(homework.getHwStatus()).isDraft(), + subjectDictService.nameMap(), classes, classNames); } /** @@ -934,7 +943,7 @@ public class TeacherHomeworkV2Service { return ids; } - /** 学校年级ID → 年级名(bschclass GetSchLenLevellist;远端失败降级空映射,班级归入「未分组」) */ + /** 学校年级ID → 年级名(bschclass GetSchLenLevellist;远端失败降级空映射,班级归入「未分组」/不带前缀) */ private Map gradeNames(String schSerId) { Map names = new java.util.LinkedHashMap<>(); try { @@ -944,7 +953,7 @@ public class TeacherHomeworkV2Service { } } } catch (BizException e) { - log.warn("[classTree] 年级列表拉取失败, 降级「未分组」展示: {}", e.getMessage()); + log.warn("[gradeNames] 年级列表拉取失败, 降级不带年级前缀展示: {}", e.getMessage()); } return names; } @@ -1011,12 +1020,14 @@ public class TeacherHomeworkV2Service { if (classIds.isEmpty()) { return new ArrayList<>(); } + Map gradeNames = gradeNames(schSerId); List result = new ArrayList<>(); try { for (SchClassDto schClass : classService.getSchClassList(schSerId)) { Integer classId = schClass.getClassId(); if (classId != null && classIds.remove(classId)) { - result.add(teachingClassVo(classId, schClass.getClassName())); + result.add(teachingClassVo(classId, RosterService.displayName( + schClass.getClassName(), schClass.getGradeId(), gradeNames))); } } } catch (BizException e) { @@ -1113,7 +1124,8 @@ public class TeacherHomeworkV2Service { // ============================ VO 组装 ============================ private HomeworkV2Vo toVo(Homework h, boolean withAttachments, boolean withProgress, - Map subjectNames) { + Map subjectNames, List classes, + Map classNames) { HomeworkV2Vo vo = new HomeworkV2Vo(); vo.setId(h.getId()); vo.setTitle(h.getTitle()); @@ -1130,8 +1142,10 @@ public class TeacherHomeworkV2Service { vo.setAllowLate(h.getAllowLate()); vo.setRemind1d(h.getRemind1d()); vo.setRemind1h(h.getRemind1h()); - vo.setClasses(homeworkClassRepository.findByHomeworkId(h.getId()).stream() - .map(c -> new ClassItem(c.getClassId(), c.getClassName())) + // 班级展示名实时解析(含年级前缀),存量快照仅作兜底 + vo.setClasses(classes.stream() + .map(c -> new ClassItem(c.getClassId(), + RosterService.displayOr(classNames.get(c.getClassId()), c.getClassName(), c.getClassId()))) .collect(Collectors.toList())); if (withAttachments) { vo.setAttachments(homeworkAttachmentRepository.findByHomeworkIdOrderBySortAscIdAsc(h.getId()).stream() @@ -1150,11 +1164,31 @@ public class TeacherHomeworkV2Service { vo.setCreateTime(h.getCreateTime()); vo.setUpdateTime(h.getUpdateTime()); if (withProgress && !HwStatusEnum.of(h.getHwStatus()).isDraft()) { - vo.setProgress(progressCalculator.compute(h.getId(), classIds(homeworkClassRepository.findByHomeworkId(h.getId()))).total); + vo.setProgress(progressCalculator.compute(h.getId(), classIds(classes)).total); } return vo; } + /** + * 页内作业的班级关联分组(findByHomeworkIds 批量一次查询,避免逐行 N+1)。 + */ + private Map> classesByHomework(List homeworks) { + List ids = homeworks.stream().map(Homework::getId).collect(Collectors.toList()); + if (ids.isEmpty()) { + return Collections.emptyMap(); + } + return homeworkClassRepository.findByHomeworkIds(ids).stream() + .collect(Collectors.groupingBy(HomeworkClass::getHomeworkId)); + } + + private static List allClassIds(Map> classesByHw) { + return classesByHw.values().stream() + .flatMap(List::stream) + .map(HomeworkClass::getClassId) + .distinct() + .collect(Collectors.toList()); + } + // ============================ 名册辅助 ============================ /** 参与班级在班学生 id 集合(实时 bschclass 名册) */