feat: 新增学校自动添加年级 + 修复区域层级查询 + 清理区域数据

1. 新增学校时根据学段自动添加对应年级
2. 修复选择省/市时无法显示学校的bug(支持区域层级查询)
3. 区域树默认展开湖北省,平行显示市级
4. 新增区域数据清理SQL脚本(仅保留湖北省)
This commit is contained in:
神码-方晓辉 2026-02-05 11:21:58 +08:00
parent 72cb6668f3
commit add00c9992
8 changed files with 199 additions and 6 deletions

View File

@ -1,6 +1,7 @@
package org.dromara.pangu.base.controller;
import cn.dev33.satoken.annotation.SaCheckPermission;
import cn.hutool.core.util.StrUtil;
import lombok.RequiredArgsConstructor;
import org.dromara.common.core.domain.R;
import org.dromara.common.log.annotation.Log;
@ -13,6 +14,7 @@ import org.dromara.pangu.base.service.IPgGradeService;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.util.Arrays;
import java.util.List;
/**
@ -39,9 +41,16 @@ public class PgGradeController extends BaseController {
/**
* 查询年级列表不分页
* @param grade 查询条件
* @param stages 学段列表逗号分隔1,2 表示小学和初中
*/
@GetMapping("/listAll")
public R<List<PgGrade>> listAll(PgGrade grade) {
public R<List<PgGrade>> listAll(PgGrade grade,
@RequestParam(required = false) String stages) {
if (StrUtil.isNotBlank(stages)) {
List<String> stageList = Arrays.asList(stages.split(","));
return R.ok(gradeService.selectListByStages(stageList));
}
return R.ok(gradeService.selectList(grade));
}

View File

@ -42,4 +42,10 @@ public interface IPgGradeService {
* 批量删除年级
*/
int deleteByIds(Long[] gradeIds);
/**
* 根据学段列表查询年级
* @param stages 学段列表1小学 2初中 3高中 4中专 5大学
*/
List<PgGrade> selectListByStages(List<String> stages);
}

View File

@ -57,6 +57,19 @@ public class PgGradeServiceImpl implements IPgGradeService {
return baseMapper.deleteByIds(Arrays.asList(gradeIds));
}
@Override
public List<PgGrade> selectListByStages(List<String> stages) {
if (stages == null || stages.isEmpty()) {
return List.of();
}
return baseMapper.selectList(
new LambdaQueryWrapper<PgGrade>()
.in(PgGrade::getStage, stages)
.eq(PgGrade::getStatus, "0")
.orderByAsc(PgGrade::getOrderNum)
);
}
private LambdaQueryWrapper<PgGrade> buildQueryWrapper(PgGrade grade) {
LambdaQueryWrapper<PgGrade> lqw = new LambdaQueryWrapper<>();
lqw.like(StrUtil.isNotBlank(grade.getGradeName()), PgGrade::getGradeName, grade.getGradeName());

View File

@ -60,4 +60,10 @@ public class PgSchool extends BaseEntity {
*/
@TableField(exist = false)
private String regionName;
/**
* 初始年级ID列表非数据库字段用于新增时批量添加年级
*/
@TableField(exist = false)
private java.util.List<Long> gradeIds;
}

View File

@ -119,7 +119,14 @@ public class PgSchoolServiceImpl implements IPgSchoolService {
school.setDeptId(deptBo.getDeptId());
}
return baseMapper.insert(school);
int result = baseMapper.insert(school);
// 如果传入了初始年级ID列表批量添加到学校
if (school.getGradeIds() != null && !school.getGradeIds().isEmpty()) {
addSchoolGrades(school.getSchoolId(), school.getGradeIds());
}
return result;
}
/**
@ -295,11 +302,39 @@ public class PgSchoolServiceImpl implements IPgSchoolService {
LambdaQueryWrapper<PgSchool> lqw = new LambdaQueryWrapper<>();
lqw.like(StrUtil.isNotBlank(school.getSchoolName()), PgSchool::getSchoolName, school.getSchoolName());
lqw.eq(StrUtil.isNotBlank(school.getSchoolType()), PgSchool::getSchoolType, school.getSchoolType());
lqw.eq(school.getRegionId() != null, PgSchool::getRegionId, school.getRegionId());
// 区域查询支持查询选定区域及其所有下级区域的学校
if (school.getRegionId() != null) {
List<Long> regionIds = getRegionIdsWithChildren(school.getRegionId());
if (!regionIds.isEmpty()) {
lqw.in(PgSchool::getRegionId, regionIds);
}
}
lqw.eq(StrUtil.isNotBlank(school.getStatus()), PgSchool::getStatus, school.getStatus());
return lqw;
}
/**
* 获取指定区域及其所有下级区域的ID列表
* @param regionId 区域ID
* @return 包含该区域及所有下级区域的ID列表
*/
private List<Long> getRegionIdsWithChildren(Long regionId) {
List<Long> result = new ArrayList<>();
result.add(regionId);
// 递归查询下级区域
List<PgRegion> children = regionMapper.selectList(
new LambdaQueryWrapper<PgRegion>().eq(PgRegion::getParentId, regionId)
);
for (PgRegion child : children) {
result.addAll(getRegionIdsWithChildren(child.getRegionId()));
}
return result;
}
@Override
public List<SchoolTreeNode> selectSchoolTree(PgSchool school) {
// 查询学校列表使用带数据权限的查询方法

View File

@ -63,6 +63,26 @@
inactive-text="停用"
/>
</el-form-item>
<!-- 新增时显示年级选择区域 -->
<el-form-item v-if="!isEdit && gradeList.length > 0" label="初始年级">
<div class="grade-select-wrapper">
<el-checkbox-group v-model="selectedGradeIds">
<el-checkbox
v-for="grade in gradeList"
:key="grade.gradeId"
:value="grade.gradeId"
:label="grade.gradeId"
>
{{ grade.gradeName }}
</el-checkbox>
</el-checkbox-group>
<div class="grade-tip">
<el-text type="info" size="small">
已选择 {{ selectedGradeIds.length }} 个年级将在学校创建后自动添加
</el-text>
</div>
</div>
</el-form-item>
</el-form>
<template #footer>
<el-button @click="dialogVisible = false">取消</el-button>
@ -77,9 +97,10 @@
* @author pangu
*/
import { ElMessage } from 'element-plus'
import { computed, ref, onMounted } from 'vue'
import { computed, ref, watch } from 'vue'
import { addSchool, updateSchool } from '@/api/pangu/school'
import { deptTreeSelect } from '@/api/system/user'
import request from '@/utils/request'
//
const props = defineProps({
@ -99,6 +120,10 @@ const submitLoading = ref(false)
const formRef = ref(null)
const isEdit = ref(false)
// ID
const gradeList = ref([])
const selectedGradeIds = ref([])
//
const form = ref({
schoolId: null,
@ -159,6 +184,51 @@ const handleRegionChange = (value) => {
}
}
//
const getStagesBySchoolType = (schoolType) => {
const map = {
'1': ['1'], //
'2': ['2'], //
'3': ['3'], //
'4': ['1', '2'], //
'5': ['2', '3'] //
}
return map[schoolType] || []
}
//
const loadGradesBySchoolType = async (schoolType) => {
const stages = getStagesBySchoolType(schoolType)
if (stages.length === 0) {
gradeList.value = []
selectedGradeIds.value = []
return
}
try {
const res = await request.get('/business/grade/listAll', {
params: { stages: stages.join(',') }
})
if (res.code === 200) {
gradeList.value = res.data || []
//
selectedGradeIds.value = gradeList.value.map(g => g.gradeId)
}
} catch (error) {
console.error('加载年级列表失败:', error)
}
}
//
watch(() => form.value.schoolType, async (newType) => {
if (!isEdit.value && newType) {
await loadGradesBySchoolType(newType)
} else if (!newType) {
gradeList.value = []
selectedGradeIds.value = []
}
})
//
const loadDeptTree = async () => {
try {
@ -208,6 +278,9 @@ const open = async (row, defaultRegionId = null) => {
regionName: defaultRegionId ? getRegionPath(regionIds, props.regionTree) : '',
status: '0'
}
//
gradeList.value = []
selectedGradeIds.value = []
}
}
@ -246,7 +319,8 @@ const handleSubmit = async () => {
try {
const submitData = {
...form.value,
regionIds: undefined //
regionIds: undefined, //
gradeIds: isEdit.value ? undefined : selectedGradeIds.value // ID
}
const res = form.value.schoolId
@ -254,7 +328,11 @@ const handleSubmit = async () => {
: await addSchool(submitData)
if (res.code === 200) {
ElMessage.success(isEdit.value ? '修改成功' : '新增成功')
const gradeCount = selectedGradeIds.value.length
const msg = isEdit.value
? '修改成功'
: (gradeCount > 0 ? `新增成功,已自动添加 ${gradeCount} 个年级` : '新增成功')
ElMessage.success(msg)
dialogVisible.value = false
emit('success')
}
@ -269,3 +347,16 @@ const handleSubmit = async () => {
//
defineExpose({ open })
</script>
<style scoped>
.grade-select-wrapper {
width: 100%;
}
.grade-select-wrapper .el-checkbox {
margin-right: 16px;
margin-bottom: 8px;
}
.grade-tip {
margin-top: 8px;
}
</style>

View File

@ -15,6 +15,7 @@
:props="{ label: 'regionName', children: 'children' }"
node-key="regionId"
highlight-current
:default-expanded-keys="defaultExpandedKeys"
:filter-node-method="filterNode"
@node-click="handleNodeClick"
/>
@ -140,6 +141,8 @@ const treeRef = ref()
const treeFilterText = ref('')
const regionTree = ref([])
const selectedRegionId = ref(null)
// regionId=42
const defaultExpandedKeys = ref([42])
//
const loading = ref(false)

View File

@ -0,0 +1,30 @@
-- ================================================================
-- V1.0.5 清理非湖北省区域数据
-- 执行说明先检查湖北省的region_id确认为42后再执行删除
-- 执行时间:需在业务低峰期执行
-- ================================================================
-- 0. 首先确认湖北省的region_id
SELECT region_id, region_name, parent_id, ancestors FROM pg_region WHERE region_name = '湖北省';
-- 预期结果region_id = 42
-- 1. 查看要删除的数据量(预检查,不会执行删除)
SELECT COUNT(*) as '待删除的区域数量' FROM pg_region
WHERE region_id != 42
AND ancestors NOT LIKE '0,42%';
-- 2. 物理删除非湖北省的区域数据
-- 删除所有ancestors不以"0,42"开头的区域(即非湖北省及其下级区域)
-- 同时排除湖北省本身(region_id=42)
DELETE FROM pg_region
WHERE region_id != 42
AND ancestors NOT LIKE '0,42%';
-- 3. 删除其他省份的根节点parent_id = 0 且 region_id != 42
DELETE FROM pg_region
WHERE parent_id = 0
AND region_id != 42;
-- 4. 验证结果
SELECT COUNT(*) as '剩余区域数量' FROM pg_region;
SELECT region_name, level, COUNT(*) as '数量' FROM pg_region GROUP BY level, region_name LIMIT 20;