diff --git a/backend/ruoyi-modules/pangu-business/src/main/java/org/dromara/pangu/school/controller/PgSchoolController.java b/backend/ruoyi-modules/pangu-business/src/main/java/org/dromara/pangu/school/controller/PgSchoolController.java index ab60fab..ff74a18 100644 --- a/backend/ruoyi-modules/pangu-business/src/main/java/org/dromara/pangu/school/controller/PgSchoolController.java +++ b/backend/ruoyi-modules/pangu-business/src/main/java/org/dromara/pangu/school/controller/PgSchoolController.java @@ -11,6 +11,7 @@ import org.dromara.common.web.core.BaseController; import org.dromara.pangu.school.domain.PgSchool; import org.dromara.pangu.school.domain.PgSchoolClass; import org.dromara.pangu.school.domain.PgSchoolGrade; +import org.dromara.pangu.school.domain.vo.SchoolTreeNode; import org.dromara.pangu.school.service.IPgSchoolService; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; @@ -42,6 +43,15 @@ public class PgSchoolController extends BaseController { return R.ok(schoolService.selectList(school)); } + /** + * 获取学校树形结构(包含年级和班级) + */ + @SaCheckPermission("business:school:list") + @GetMapping("/tree") + public R> tree(PgSchool school) { + return R.ok(schoolService.selectSchoolTree(school)); + } + @SaCheckPermission("business:school:query") @GetMapping("/{schoolId}") public R getInfo(@PathVariable Long schoolId) { @@ -103,4 +113,24 @@ public class PgSchoolController extends BaseController { List classIds = (List) params.get("classIds"); return toAjax(schoolService.addGradeClasses(schoolId, schoolGradeId, classIds)); } + + /** + * 删除学校下的年级 + */ + @SaCheckPermission("business:school:edit") + @Log(title = "学校年级管理", businessType = BusinessType.DELETE) + @DeleteMapping("/grade/{schoolGradeId}") + public R removeSchoolGrade(@PathVariable Long schoolGradeId) { + return toAjax(schoolService.removeSchoolGrade(schoolGradeId)); + } + + /** + * 删除年级下的班级 + */ + @SaCheckPermission("business:school:edit") + @Log(title = "学校班级管理", businessType = BusinessType.DELETE) + @DeleteMapping("/class/{schoolClassId}") + public R removeGradeClass(@PathVariable Long schoolClassId) { + return toAjax(schoolService.removeGradeClass(schoolClassId)); + } } diff --git a/backend/ruoyi-modules/pangu-business/src/main/java/org/dromara/pangu/school/domain/vo/SchoolTreeNode.java b/backend/ruoyi-modules/pangu-business/src/main/java/org/dromara/pangu/school/domain/vo/SchoolTreeNode.java new file mode 100644 index 0000000..806afc2 --- /dev/null +++ b/backend/ruoyi-modules/pangu-business/src/main/java/org/dromara/pangu/school/domain/vo/SchoolTreeNode.java @@ -0,0 +1,84 @@ +package org.dromara.pangu.school.domain.vo; + +import lombok.Data; + +import java.util.List; + +/** + * 学校树节点(学校/年级/班级统一结构) + * + * @author pangu + */ +@Data +public class SchoolTreeNode { + + /** + * 节点ID + */ + private Long id; + + /** + * 节点名称 + */ + private String name; + + /** + * 节点类型:school-学校, grade-年级, class-班级 + */ + private String type; + + /** + * 学校编码(仅学校节点有值) + */ + private String schoolCode; + + /** + * 学校类型(仅学校节点有值) + */ + private String schoolType; + + /** + * 区域名称(仅学校节点有值) + */ + private String regionName; + + /** + * 区域ID(仅学校节点有值) + */ + private Long regionId; + + /** + * 状态(0正常 1停用) + */ + private String status; + + /** + * 创建时间 + */ + private String createTime; + + /** + * 创建人 + */ + private String createBy; + + /** + * 子节点 + */ + private List children; + + /** + * 父节点ID(用于前端判断层级) + */ + private Long parentId; + + /** + * 学校ID(年级和班级节点需要) + */ + private Long schoolId; + + /** + * 学校年级关联ID(班级节点需要) + */ + private Long schoolGradeId; +} diff --git a/backend/ruoyi-modules/pangu-business/src/main/java/org/dromara/pangu/school/service/IPgSchoolService.java b/backend/ruoyi-modules/pangu-business/src/main/java/org/dromara/pangu/school/service/IPgSchoolService.java index dcf7132..6c19f34 100644 --- a/backend/ruoyi-modules/pangu-business/src/main/java/org/dromara/pangu/school/service/IPgSchoolService.java +++ b/backend/ruoyi-modules/pangu-business/src/main/java/org/dromara/pangu/school/service/IPgSchoolService.java @@ -4,6 +4,7 @@ import org.dromara.common.mybatis.core.page.PageQuery; import org.dromara.common.mybatis.core.page.TableDataInfo; import org.dromara.pangu.school.domain.PgSchool; import org.dromara.pangu.school.domain.PgSchoolGrade; +import org.dromara.pangu.school.domain.vo.SchoolTreeNode; import java.util.List; @@ -34,4 +35,19 @@ public interface IPgSchoolService { * 为年级添加班级(批量挂载) */ int addGradeClasses(Long schoolId, Long schoolGradeId, List classIds); + + /** + * 获取学校树形结构(包含年级和班级) + */ + List selectSchoolTree(PgSchool school); + + /** + * 删除学校下的年级(同时删除该年级下的班级) + */ + int removeSchoolGrade(Long schoolGradeId); + + /** + * 删除年级下的班级 + */ + int removeGradeClass(Long schoolClassId); } diff --git a/backend/ruoyi-modules/pangu-business/src/main/java/org/dromara/pangu/school/service/impl/PgSchoolServiceImpl.java b/backend/ruoyi-modules/pangu-business/src/main/java/org/dromara/pangu/school/service/impl/PgSchoolServiceImpl.java index 512ed13..9d1f50f 100644 --- a/backend/ruoyi-modules/pangu-business/src/main/java/org/dromara/pangu/school/service/impl/PgSchoolServiceImpl.java +++ b/backend/ruoyi-modules/pangu-business/src/main/java/org/dromara/pangu/school/service/impl/PgSchoolServiceImpl.java @@ -6,13 +6,16 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import lombok.RequiredArgsConstructor; import org.dromara.common.mybatis.core.page.PageQuery; import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.pangu.base.domain.PgClass; import org.dromara.pangu.base.domain.PgGrade; import org.dromara.pangu.base.domain.PgRegion; +import org.dromara.pangu.base.mapper.PgClassMapper; import org.dromara.pangu.base.mapper.PgGradeMapper; import org.dromara.pangu.base.mapper.PgRegionMapper; import org.dromara.pangu.school.domain.PgSchool; import org.dromara.pangu.school.domain.PgSchoolClass; import org.dromara.pangu.school.domain.PgSchoolGrade; +import org.dromara.pangu.school.domain.vo.SchoolTreeNode; import org.dromara.pangu.school.mapper.PgSchoolClassMapper; import org.dromara.pangu.school.mapper.PgSchoolGradeMapper; import org.dromara.pangu.school.mapper.PgSchoolMapper; @@ -20,10 +23,8 @@ import org.dromara.pangu.school.service.IPgSchoolService; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import java.util.Arrays; -import java.util.List; -import java.util.Map; -import java.util.Set; +import java.text.SimpleDateFormat; +import java.util.*; import java.util.stream.Collectors; /** @@ -39,6 +40,7 @@ public class PgSchoolServiceImpl implements IPgSchoolService { private final PgSchoolGradeMapper schoolGradeMapper; private final PgSchoolClassMapper schoolClassMapper; private final PgGradeMapper gradeMapper; + private final PgClassMapper classMapper; private final PgRegionMapper regionMapper; @Override @@ -188,6 +190,23 @@ public class PgSchoolServiceImpl implements IPgSchoolService { return count; } + @Override + @Transactional(rollbackFor = Exception.class) + public int removeSchoolGrade(Long schoolGradeId) { + // 先删除该年级下的所有班级 + schoolClassMapper.delete( + new LambdaQueryWrapper() + .eq(PgSchoolClass::getSchoolGradeId, schoolGradeId) + ); + // 再删除年级 + return schoolGradeMapper.deleteById(schoolGradeId); + } + + @Override + public int removeGradeClass(Long schoolClassId) { + return schoolClassMapper.deleteById(schoolClassId); + } + private LambdaQueryWrapper buildQueryWrapper(PgSchool school) { LambdaQueryWrapper lqw = new LambdaQueryWrapper<>(); lqw.like(StrUtil.isNotBlank(school.getSchoolName()), PgSchool::getSchoolName, school.getSchoolName()); @@ -196,4 +215,110 @@ public class PgSchoolServiceImpl implements IPgSchoolService { lqw.eq(StrUtil.isNotBlank(school.getStatus()), PgSchool::getStatus, school.getStatus()); return lqw; } + + @Override + public List selectSchoolTree(PgSchool school) { + // 查询学校列表 + List schools = baseMapper.selectList(buildQueryWrapper(school)); + fillRegionName(schools); + + if (schools.isEmpty()) { + return new ArrayList<>(); + } + + // 收集所有学校ID + List schoolIds = schools.stream().map(PgSchool::getSchoolId).toList(); + + // 查询所有学校的年级 + List allSchoolGrades = schoolGradeMapper.selectList( + new LambdaQueryWrapper().in(PgSchoolGrade::getSchoolId, schoolIds) + ); + + // 查询年级名称 + Set gradeIds = allSchoolGrades.stream().map(PgSchoolGrade::getGradeId).collect(java.util.stream.Collectors.toSet()); + Map gradeNameMap = new HashMap<>(); + if (!gradeIds.isEmpty()) { + List grades = gradeMapper.selectBatchIds(gradeIds); + gradeNameMap = grades.stream().collect(java.util.stream.Collectors.toMap(PgGrade::getGradeId, PgGrade::getGradeName)); + } + + // 收集所有学校年级关联ID + List schoolGradeIds = allSchoolGrades.stream().map(PgSchoolGrade::getId).toList(); + + // 查询所有班级 + final List allSchoolClasses; + if (!schoolGradeIds.isEmpty()) { + allSchoolClasses = schoolClassMapper.selectList( + new LambdaQueryWrapper().in(PgSchoolClass::getSchoolGradeId, schoolGradeIds) + ); + } else { + allSchoolClasses = new ArrayList<>(); + } + + // 查询班级名称 + Set classIds = allSchoolClasses.stream().map(PgSchoolClass::getClassId).collect(java.util.stream.Collectors.toSet()); + Map classNameMap = new HashMap<>(); + if (!classIds.isEmpty()) { + List classes = classMapper.selectBatchIds(classIds); + classNameMap = classes.stream().collect(java.util.stream.Collectors.toMap(PgClass::getClassId, PgClass::getClassName)); + } + + // 构建树形结构 + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + List result = new ArrayList<>(); + + for (PgSchool s : schools) { + SchoolTreeNode schoolNode = new SchoolTreeNode(); + schoolNode.setId(s.getSchoolId()); + schoolNode.setName(s.getSchoolName()); + schoolNode.setType("school"); + schoolNode.setSchoolCode(s.getSchoolCode()); + schoolNode.setSchoolType(s.getSchoolType()); + schoolNode.setRegionName(s.getRegionName()); + schoolNode.setRegionId(s.getRegionId()); + schoolNode.setStatus(s.getStatus()); + schoolNode.setCreateTime(s.getCreateTime() != null ? sdf.format(s.getCreateTime()) : null); + schoolNode.setCreateBy(s.getCreateBy() != null ? s.getCreateBy().toString() : null); + schoolNode.setSchoolId(s.getSchoolId()); + + // 查找该学校的年级 + Map finalGradeNameMap = gradeNameMap; + Map finalClassNameMap = classNameMap; + List gradeNodes = allSchoolGrades.stream() + .filter(sg -> sg.getSchoolId().equals(s.getSchoolId())) + .map(sg -> { + SchoolTreeNode gradeNode = new SchoolTreeNode(); + gradeNode.setId(sg.getId()); // 使用学校年级关联表ID + gradeNode.setName(finalGradeNameMap.getOrDefault(sg.getGradeId(), "")); + gradeNode.setType("grade"); + gradeNode.setSchoolId(sg.getSchoolId()); + gradeNode.setParentId(s.getSchoolId()); + gradeNode.setSchoolGradeId(sg.getId()); + + // 查找该年级的班级 + List classNodes = allSchoolClasses.stream() + .filter(sc -> sc.getSchoolGradeId().equals(sg.getId())) + .map(sc -> { + SchoolTreeNode classNode = new SchoolTreeNode(); + classNode.setId(sc.getId()); // 使用学校班级关联表ID + classNode.setName(finalClassNameMap.getOrDefault(sc.getClassId(), "")); + classNode.setType("class"); + classNode.setSchoolId(sc.getSchoolId()); + classNode.setSchoolGradeId(sc.getSchoolGradeId()); + classNode.setParentId(sg.getId()); + return classNode; + }) + .toList(); + + gradeNode.setChildren(classNodes.isEmpty() ? null : new ArrayList<>(classNodes)); + return gradeNode; + }) + .toList(); + + schoolNode.setChildren(gradeNodes.isEmpty() ? null : new ArrayList<>(gradeNodes)); + result.add(schoolNode); + } + + return result; + } } diff --git a/frontend/ruoyi-ui/src/views/business/school/components/ClassDialog.vue b/frontend/ruoyi-ui/src/views/business/school/components/ClassDialog.vue index 2bc4f67..f621ad5 100644 --- a/frontend/ruoyi-ui/src/views/business/school/components/ClassDialog.vue +++ b/frontend/ruoyi-ui/src/views/business/school/components/ClassDialog.vue @@ -1,28 +1,17 @@