feat: 重构学校管理模块 - 按需求文档实现树形展示

根据需求文档完全重构学校管理页面:
- 按区域树形展示学校、年级、班级结构
- 新增后端接口 /business/school/tree 返回树形数据
- 新增后端接口删除年级/班级
- 前端使用树形表格展示层级结构
- 弹窗标题按需求文档:编辑-学校、新增-年级、新增-班级
- 操作按钮:学校(编辑/新增年级/删除)、年级(新增班级/删除)、班级(删除)
- 删除时提示是否有子级
This commit is contained in:
神码-方晓辉 2026-02-02 17:41:22 +08:00
parent bb14acd923
commit b42aab4a8f
8 changed files with 392 additions and 116 deletions

View File

@ -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<List<SchoolTreeNode>> tree(PgSchool school) {
return R.ok(schoolService.selectSchoolTree(school));
}
@SaCheckPermission("business:school:query")
@GetMapping("/{schoolId}")
public R<PgSchool> getInfo(@PathVariable Long schoolId) {
@ -103,4 +113,24 @@ public class PgSchoolController extends BaseController {
List<Long> classIds = (List<Long>) params.get("classIds");
return toAjax(schoolService.addGradeClasses(schoolId, schoolGradeId, classIds));
}
/**
* 删除学校下的年级
*/
@SaCheckPermission("business:school:edit")
@Log(title = "学校年级管理", businessType = BusinessType.DELETE)
@DeleteMapping("/grade/{schoolGradeId}")
public R<Void> removeSchoolGrade(@PathVariable Long schoolGradeId) {
return toAjax(schoolService.removeSchoolGrade(schoolGradeId));
}
/**
* 删除年级下的班级
*/
@SaCheckPermission("business:school:edit")
@Log(title = "学校班级管理", businessType = BusinessType.DELETE)
@DeleteMapping("/class/{schoolClassId}")
public R<Void> removeGradeClass(@PathVariable Long schoolClassId) {
return toAjax(schoolService.removeGradeClass(schoolClassId));
}
}

View File

@ -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<SchoolTreeNode> children;
/**
* 父节点ID用于前端判断层级
*/
private Long parentId;
/**
* 学校ID年级和班级节点需要
*/
private Long schoolId;
/**
* 学校年级关联ID班级节点需要
*/
private Long schoolGradeId;
}

View File

@ -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<Long> classIds);
/**
* 获取学校树形结构包含年级和班级
*/
List<SchoolTreeNode> selectSchoolTree(PgSchool school);
/**
* 删除学校下的年级同时删除该年级下的班级
*/
int removeSchoolGrade(Long schoolGradeId);
/**
* 删除年级下的班级
*/
int removeGradeClass(Long schoolClassId);
}

View File

@ -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<PgSchoolClass>()
.eq(PgSchoolClass::getSchoolGradeId, schoolGradeId)
);
// 再删除年级
return schoolGradeMapper.deleteById(schoolGradeId);
}
@Override
public int removeGradeClass(Long schoolClassId) {
return schoolClassMapper.deleteById(schoolClassId);
}
private LambdaQueryWrapper<PgSchool> buildQueryWrapper(PgSchool school) {
LambdaQueryWrapper<PgSchool> 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<SchoolTreeNode> selectSchoolTree(PgSchool school) {
// 查询学校列表
List<PgSchool> schools = baseMapper.selectList(buildQueryWrapper(school));
fillRegionName(schools);
if (schools.isEmpty()) {
return new ArrayList<>();
}
// 收集所有学校ID
List<Long> schoolIds = schools.stream().map(PgSchool::getSchoolId).toList();
// 查询所有学校的年级
List<PgSchoolGrade> allSchoolGrades = schoolGradeMapper.selectList(
new LambdaQueryWrapper<PgSchoolGrade>().in(PgSchoolGrade::getSchoolId, schoolIds)
);
// 查询年级名称
Set<Long> gradeIds = allSchoolGrades.stream().map(PgSchoolGrade::getGradeId).collect(java.util.stream.Collectors.toSet());
Map<Long, String> gradeNameMap = new HashMap<>();
if (!gradeIds.isEmpty()) {
List<PgGrade> grades = gradeMapper.selectBatchIds(gradeIds);
gradeNameMap = grades.stream().collect(java.util.stream.Collectors.toMap(PgGrade::getGradeId, PgGrade::getGradeName));
}
// 收集所有学校年级关联ID
List<Long> schoolGradeIds = allSchoolGrades.stream().map(PgSchoolGrade::getId).toList();
// 查询所有班级
final List<PgSchoolClass> allSchoolClasses;
if (!schoolGradeIds.isEmpty()) {
allSchoolClasses = schoolClassMapper.selectList(
new LambdaQueryWrapper<PgSchoolClass>().in(PgSchoolClass::getSchoolGradeId, schoolGradeIds)
);
} else {
allSchoolClasses = new ArrayList<>();
}
// 查询班级名称
Set<Long> classIds = allSchoolClasses.stream().map(PgSchoolClass::getClassId).collect(java.util.stream.Collectors.toSet());
Map<Long, String> classNameMap = new HashMap<>();
if (!classIds.isEmpty()) {
List<PgClass> 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<SchoolTreeNode> 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<Long, String> finalGradeNameMap = gradeNameMap;
Map<Long, String> finalClassNameMap = classNameMap;
List<SchoolTreeNode> 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<SchoolTreeNode> 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;
}
}

View File

@ -1,28 +1,17 @@
<template>
<el-dialog
v-model="dialogVisible"
title="新增班级"
title="新增-班级"
width="500px"
:close-on-click-modal="false"
destroy-on-close
>
<div style="margin-bottom: 16px;">
<span style="font-weight: bold;">学校</span>
<span>{{ currentSchool?.schoolName }}</span>
<div><span style="font-weight: bold;">学校</span><span>{{ currentSchool?.schoolName }}</span></div>
<div><span style="font-weight: bold;">年级</span><span>{{ currentSchool?.gradeName }}</span></div>
</div>
<el-form ref="formRef" :model="form" label-width="80px">
<el-form-item label="选择年级" prop="schoolGradeId">
<el-select v-model="form.schoolGradeId" placeholder="请先选择年级" style="width: 100%">
<el-option
v-for="item in schoolGradeOptions"
:key="item.id"
:label="item.gradeName"
:value="item.id"
/>
</el-select>
</el-form-item>
<el-form-item label="选择班级" prop="classIds">
<el-checkbox-group v-model="form.classIds">
<el-row :gutter="10">
@ -45,13 +34,12 @@
<script setup>
/**
* 新增班级弹窗
* 新增班级弹窗为年级挂载班级
* @author pangu
*/
import { ElMessage } from 'element-plus'
import { onMounted, ref } from 'vue'
import request from '@/utils/request'
import { addGradeClass, getClassOptions, getSchoolGradeTree } from '@/api/pangu/school'
import { addGradeClass, getClassOptions } from '@/api/pangu/school'
const emit = defineEmits(['success'])
@ -59,7 +47,6 @@ const dialogVisible = ref(false)
const submitLoading = ref(false)
const formRef = ref(null)
const currentSchool = ref(null)
const schoolGradeOptions = ref([])
const classOptions = ref([])
//
@ -69,19 +56,6 @@ const form = ref({
classIds: []
})
//
const fetchSchoolGrades = async (schoolId) => {
try {
const res = await getSchoolGradeTree(schoolId)
if (res.code === 200) {
// res.data PgSchoolGrade id(ID)gradeIdgradeName
schoolGradeOptions.value = res.data || []
}
} catch (error) {
console.error('获取学校年级失败:', error)
}
}
//
const fetchClassOptions = async () => {
try {
@ -100,24 +74,19 @@ const fetchClassOptions = async () => {
}
//
const open = (school) => {
// schoolData: { schoolId, schoolName, schoolGradeId, gradeName }
const open = (schoolData) => {
dialogVisible.value = true
currentSchool.value = school
currentSchool.value = schoolData
form.value = {
schoolId: school.schoolId,
schoolGradeId: null,
schoolId: schoolData.schoolId,
schoolGradeId: schoolData.schoolGradeId,
classIds: []
}
//
fetchSchoolGrades(school.schoolId)
}
//
const handleSubmit = async () => {
if (!form.value.schoolGradeId) {
ElMessage.warning('请选择年级')
return
}
if (form.value.classIds.length === 0) {
ElMessage.warning('请至少选择一个班级')
return

View File

@ -1,7 +1,7 @@
<template>
<el-dialog
v-model="dialogVisible"
title="新增年级"
title="新增-年级"
width="500px"
:close-on-click-modal="false"
destroy-on-close

View File

@ -96,8 +96,8 @@ const form = ref({
status: '0'
})
//
const dialogTitle = computed(() => isEdit.value ? '编辑学校' : '新增学校')
// - -
const dialogTitle = computed(() => isEdit.value ? '编辑-学校' : '新增学校')
//
const rules = {
@ -141,7 +141,9 @@ const handleRegionChange = (value) => {
}
//
const open = (row) => {
// row: null
// defaultRegionId: ID
const open = (row, defaultRegionId = null) => {
dialogVisible.value = true
isEdit.value = !!row
@ -158,15 +160,16 @@ const open = (row) => {
status: row.status
}
} else {
//
//
const regionIds = defaultRegionId ? getRegionIdPath(defaultRegionId) : []
form.value = {
schoolId: null,
schoolCode: '',
schoolName: '',
schoolType: '',
regionId: null,
regionIds: [],
regionName: '',
regionId: defaultRegionId,
regionIds: regionIds,
regionName: defaultRegionId ? getRegionPath(regionIds, props.regionTree) : '',
status: '0'
}
}

View File

@ -15,6 +15,7 @@
:props="{ label: 'regionName', children: 'children' }"
node-key="regionId"
highlight-current
default-expand-all
:filter-node-method="filterNode"
@node-click="handleNodeClick"
/>
@ -51,50 +52,61 @@
</el-col>
</el-row>
<el-table v-loading="loading" :data="tableData" border stripe :header-cell-style="{ background: '#f5f7fa', color: '#606266' }" style="width: 100%">
<!-- 树形表格展示学校/年级/班级 -->
<el-table
v-loading="loading"
:data="treeData"
row-key="id"
border
default-expand-all
:tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
:header-cell-style="{ background: '#f5f7fa', color: '#606266' }"
style="width: 100%"
>
<el-table-column prop="name" label="学校名称" min-width="200" show-overflow-tooltip />
<el-table-column prop="schoolCode" label="学校编码" width="130" />
<el-table-column prop="schoolName" label="学校名称" min-width="150" show-overflow-tooltip />
<el-table-column prop="schoolType" label="学校类型" width="100" align="center">
<template #default="{ row }">
{{ schoolTypeMap[row.schoolType] || row.schoolType }}
<span v-if="row.type === 'school'">{{ schoolTypeMap[row.schoolType] || '-' }}</span>
</template>
</el-table-column>
<el-table-column prop="regionName" label="所属区域" min-width="150" show-overflow-tooltip />
<el-table-column prop="regionName" label="所属区域" min-width="120" show-overflow-tooltip />
<el-table-column prop="status" label="状态" width="80" align="center">
<template #default="{ row }">
<el-tag :type="row.status === '0' ? 'success' : 'danger'">
{{ row.status === '0' ? '正常' : '停用' }}
</el-tag>
<template v-if="row.type === 'school'">
<el-tag :type="row.status === '0' ? 'success' : 'danger'" size="small">
{{ row.status === '0' ? '正常' : '停用' }}
</el-tag>
</template>
</template>
</el-table-column>
<el-table-column prop="createTime" label="创建时间" width="160" />
<el-table-column prop="createBy" label="创建人" width="100" />
<el-table-column label="操作" width="280" fixed="right" align="center">
<el-table-column label="操作" width="220" fixed="right" align="center">
<template #default="{ row }">
<el-button type="primary" link :icon="Edit" @click="handleEdit(row)">编辑</el-button>
<el-button type="primary" link :icon="Collection" @click="handleAddGrade(row)">新增年级</el-button>
<el-button type="primary" link :icon="Files" @click="handleAddClass(row)">新增班级</el-button>
<el-button type="danger" link :icon="Delete" @click="handleDelete(row)">删除</el-button>
<!-- 学校操作编辑新增年级删除 -->
<template v-if="row.type === 'school'">
<el-button type="primary" link size="small" @click="handleEdit(row)">编辑</el-button>
<el-button type="primary" link size="small" @click="handleAddGrade(row)">新增年级</el-button>
<el-button type="danger" link size="small" @click="handleDelete(row, 'school')">删除</el-button>
</template>
<!-- 年级操作新增班级删除 -->
<template v-else-if="row.type === 'grade'">
<el-button type="primary" link size="small" @click="handleAddClass(row)">新增班级</el-button>
<el-button type="danger" link size="small" @click="handleDelete(row, 'grade')">删除</el-button>
</template>
<!-- 班级操作删除 -->
<template v-else>
<el-button type="danger" link size="small" @click="handleDelete(row, 'class')">删除</el-button>
</template>
</template>
</el-table-column>
</el-table>
<!-- 分页 -->
<el-pagination
v-model:current-page="queryParams.pageNum"
v-model:page-size="queryParams.pageSize"
:page-sizes="[10, 20, 50, 100]"
:total="total"
layout="total, sizes, prev, pager, next, jumper"
style="margin-top: 16px; justify-content: flex-end"
@size-change="handleQuery"
@current-change="handleQuery"
/>
</el-card>
</el-col>
</el-row>
<!-- 新增/编辑弹窗 -->
<!-- 编辑学校弹窗 -->
<SchoolDialog ref="schoolDialogRef" :region-tree="regionTree" @success="handleQuery" />
<!-- 新增年级弹窗 -->
@ -108,9 +120,10 @@
<script setup>
/**
* 学校管理页面
* 按区域树形展示学校年级班级结构
* @author pangu
*/
import { Collection, Delete, Edit, Files, Plus, Refresh, Search } from '@element-plus/icons-vue'
import { Plus, Refresh, Search } from '@element-plus/icons-vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import { onMounted, ref, watch } from 'vue'
import request from '@/utils/request'
@ -135,13 +148,10 @@ const selectedRegionId = ref(null)
//
const loading = ref(false)
const tableData = ref([])
const total = ref(0)
const treeData = ref([])
//
const queryParams = ref({
pageNum: 1,
pageSize: 10,
schoolName: '',
status: '',
regionId: ''
@ -171,86 +181,125 @@ const getRegionTree = async () => {
}
}
//
const getList = async () => {
//
const getSchoolTree = async () => {
loading.value = true
try {
const res = await request.get('/business/school/list', { params: queryParams.value })
const res = await request.get('/business/school/tree', { params: queryParams.value })
if (res.code === 200) {
tableData.value = res.rows
total.value = res.total
treeData.value = res.data
}
} finally {
loading.value = false
}
}
//
// -
const handleNodeClick = (data) => {
selectedRegionId.value = data.regionId
queryParams.value.regionId = data.regionId
queryParams.value.pageNum = 1
getList()
getSchoolTree()
}
//
const handleQuery = () => {
queryParams.value.pageNum = 1
getList()
getSchoolTree()
}
//
const resetQuery = () => {
queryParams.value = {
pageNum: 1,
pageSize: 10,
schoolName: '',
status: '',
regionId: ''
}
selectedRegionId.value = null
treeRef.value?.setCurrentKey(null)
getList()
getSchoolTree()
}
//
// -
const handleAdd = () => {
schoolDialogRef.value?.open()
schoolDialogRef.value?.open(null, selectedRegionId.value)
}
//
//
const handleEdit = (row) => {
schoolDialogRef.value?.open(row)
const schoolData = {
schoolId: row.id,
schoolCode: row.schoolCode,
schoolName: row.name,
schoolType: row.schoolType,
regionId: row.regionId,
regionName: row.regionName,
status: row.status
}
schoolDialogRef.value?.open(schoolData)
}
//
const handleDelete = (row) => {
ElMessageBox.confirm(`确定要删除学校"${row.schoolName}"吗?`, '提示', {
// -
const handleAddGrade = (row) => {
const schoolData = {
schoolId: row.id,
schoolName: row.name
}
gradeDialogRef.value?.open(schoolData)
}
// -
const handleAddClass = (row) => {
// treeData
const school = treeData.value.find(s => s.id === row.schoolId)
const schoolData = {
schoolId: row.schoolId,
schoolName: school ? school.name : '',
schoolGradeId: row.id,
gradeName: row.name
}
classDialogRef.value?.open(schoolData)
}
// -
const handleDelete = (row, type) => {
let message = ''
let url = ''
if (type === 'school') {
//
if (row.children && row.children.length > 0) {
message = `学校"${row.name}"下有年级/班级,确定要删除吗?删除后其下的年级和班级也将被删除。`
} else {
message = `确定要删除学校"${row.name}"吗?`
}
url = `/business/school/${row.id}`
} else if (type === 'grade') {
if (row.children && row.children.length > 0) {
message = `年级"${row.name}"下有班级,确定要删除吗?其下的班级也将被删除。`
} else {
message = `确定要删除年级"${row.name}"吗?`
}
url = `/business/school/grade/${row.id}`
} else {
message = `确定要删除班级"${row.name}"吗?`
url = `/business/school/class/${row.id}`
}
ElMessageBox.confirm(message, '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(async () => {
const res = await request.delete(`/business/school/${row.schoolId}`)
const res = await request.delete(url)
if (res.code === 200) {
ElMessage.success('删除成功')
getList()
getSchoolTree()
}
}).catch(() => {})
}
//
const handleAddGrade = (row) => {
gradeDialogRef.value?.open(row)
}
//
const handleAddClass = (row) => {
classDialogRef.value?.open(row)
}
onMounted(() => {
getRegionTree()
getList()
getSchoolTree()
})
</script>