feat: 数据权限功能实现 - 学校作为部门节点
1. 学校/年级/班级/学生表增加 dept_id 字段 2. 添加 @DataPermission 数据权限注解 3. 学校创建时自动创建对应部门 4. 学校编辑对话框增加上级部门选择 5. 修复用户管理部门列显示问题
This commit is contained in:
parent
57b171503d
commit
6f47adf86e
|
|
@ -45,6 +45,11 @@ public class PgSchool extends BaseEntity {
|
|||
|
||||
private String tenantId;
|
||||
|
||||
/**
|
||||
* 关联部门ID
|
||||
*/
|
||||
private Long deptId;
|
||||
|
||||
@TableLogic
|
||||
private String delFlag;
|
||||
|
||||
|
|
|
|||
|
|
@ -31,6 +31,11 @@ public class PgSchoolClass implements Serializable {
|
|||
|
||||
private String tenantId;
|
||||
|
||||
/**
|
||||
* 关联部门ID(数据权限用)
|
||||
*/
|
||||
private Long deptId;
|
||||
|
||||
private Long createBy;
|
||||
|
||||
private Date createTime;
|
||||
|
|
|
|||
|
|
@ -27,6 +27,11 @@ public class PgSchoolGrade implements Serializable {
|
|||
|
||||
private String tenantId;
|
||||
|
||||
/**
|
||||
* 关联部门ID(数据权限用)
|
||||
*/
|
||||
private Long deptId;
|
||||
|
||||
private Long createBy;
|
||||
|
||||
private Date createTime;
|
||||
|
|
|
|||
|
|
@ -1,12 +1,30 @@
|
|||
package org.dromara.pangu.school.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.Wrapper;
|
||||
import org.dromara.common.mybatis.annotation.DataColumn;
|
||||
import org.dromara.common.mybatis.annotation.DataPermission;
|
||||
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
|
||||
import org.dromara.pangu.school.domain.PgSchoolClass;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 学校班级 Mapper 接口
|
||||
*
|
||||
* @author pangu
|
||||
*/
|
||||
public interface PgSchoolClassMapper extends BaseMapperPlus<PgSchoolClass, PgSchoolClass> {
|
||||
|
||||
/**
|
||||
* 查询学校班级列表(带数据权限)
|
||||
*
|
||||
* @param queryWrapper 查询条件
|
||||
* @return 学校班级列表
|
||||
*/
|
||||
@DataPermission({
|
||||
@DataColumn(key = "deptName", value = "dept_id")
|
||||
})
|
||||
default List<PgSchoolClass> selectClassList(Wrapper<PgSchoolClass> queryWrapper) {
|
||||
return this.selectList(queryWrapper);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,12 +1,30 @@
|
|||
package org.dromara.pangu.school.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.Wrapper;
|
||||
import org.dromara.common.mybatis.annotation.DataColumn;
|
||||
import org.dromara.common.mybatis.annotation.DataPermission;
|
||||
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
|
||||
import org.dromara.pangu.school.domain.PgSchoolGrade;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 学校年级关联 Mapper 接口
|
||||
*
|
||||
* @author pangu
|
||||
*/
|
||||
public interface PgSchoolGradeMapper extends BaseMapperPlus<PgSchoolGrade, PgSchoolGrade> {
|
||||
|
||||
/**
|
||||
* 查询学校年级列表(带数据权限)
|
||||
*
|
||||
* @param queryWrapper 查询条件
|
||||
* @return 学校年级列表
|
||||
*/
|
||||
@DataPermission({
|
||||
@DataColumn(key = "deptName", value = "dept_id")
|
||||
})
|
||||
default List<PgSchoolGrade> selectGradeList(Wrapper<PgSchoolGrade> queryWrapper) {
|
||||
return this.selectList(queryWrapper);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,12 +1,45 @@
|
|||
package org.dromara.pangu.school.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.Wrapper;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import org.dromara.common.mybatis.annotation.DataColumn;
|
||||
import org.dromara.common.mybatis.annotation.DataPermission;
|
||||
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
|
||||
import org.dromara.pangu.school.domain.PgSchool;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 学校 Mapper 接口
|
||||
*
|
||||
* @author pangu
|
||||
*/
|
||||
public interface PgSchoolMapper extends BaseMapperPlus<PgSchool, PgSchool> {
|
||||
|
||||
/**
|
||||
* 查询学校列表(带数据权限)
|
||||
*
|
||||
* @param queryWrapper 查询条件
|
||||
* @return 学校列表
|
||||
*/
|
||||
@DataPermission({
|
||||
@DataColumn(key = "deptName", value = "dept_id")
|
||||
})
|
||||
default List<PgSchool> selectSchoolList(Wrapper<PgSchool> queryWrapper) {
|
||||
return this.selectList(queryWrapper);
|
||||
}
|
||||
|
||||
/**
|
||||
* 分页查询学校列表(带数据权限)
|
||||
*
|
||||
* @param page 分页信息
|
||||
* @param queryWrapper 查询条件
|
||||
* @return 学校分页列表
|
||||
*/
|
||||
@DataPermission({
|
||||
@DataColumn(key = "deptName", value = "dept_id")
|
||||
})
|
||||
default Page<PgSchool> selectPageSchoolList(Page<PgSchool> page, Wrapper<PgSchool> queryWrapper) {
|
||||
return this.selectPage(page, queryWrapper);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,6 +21,8 @@ import org.dromara.pangu.school.mapper.PgSchoolGradeMapper;
|
|||
import org.dromara.pangu.school.mapper.PgSchoolMapper;
|
||||
import org.dromara.pangu.school.service.IPgSchoolService;
|
||||
import org.dromara.common.core.service.UserService;
|
||||
import org.dromara.system.domain.bo.SysDeptBo;
|
||||
import org.dromara.system.service.ISysDeptService;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
|
|
@ -44,6 +46,7 @@ public class PgSchoolServiceImpl implements IPgSchoolService {
|
|||
private final PgClassMapper classMapper;
|
||||
private final PgRegionMapper regionMapper;
|
||||
private final UserService userService;
|
||||
private final ISysDeptService deptService;
|
||||
|
||||
@Override
|
||||
public TableDataInfo<PgSchool> selectPageList(PgSchool school, PageQuery pageQuery) {
|
||||
|
|
@ -94,10 +97,26 @@ public class PgSchoolServiceImpl implements IPgSchoolService {
|
|||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public int insert(PgSchool school) {
|
||||
// 自动生成学校编码
|
||||
String schoolCode = generateSchoolCode();
|
||||
school.setSchoolCode(schoolCode);
|
||||
|
||||
// 如果传入了上级部门ID,自动创建学校对应的部门节点
|
||||
if (school.getDeptId() != null) {
|
||||
Long parentDeptId = school.getDeptId();
|
||||
SysDeptBo deptBo = new SysDeptBo();
|
||||
deptBo.setParentId(parentDeptId);
|
||||
deptBo.setDeptName(school.getSchoolName());
|
||||
deptBo.setDeptCategory("school"); // 标记为学校类型
|
||||
deptBo.setOrderNum(0);
|
||||
deptBo.setStatus("0"); // 正常状态
|
||||
deptService.insertDept(deptBo);
|
||||
// 获取新创建的部门ID
|
||||
school.setDeptId(deptBo.getDeptId());
|
||||
}
|
||||
|
||||
return baseMapper.insert(school);
|
||||
}
|
||||
|
||||
|
|
@ -123,7 +142,19 @@ public class PgSchoolServiceImpl implements IPgSchoolService {
|
|||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public int update(PgSchool school) {
|
||||
// 如果学校有关联的部门,同步更新部门名称
|
||||
PgSchool existSchool = baseMapper.selectById(school.getSchoolId());
|
||||
if (existSchool != null && existSchool.getDeptId() != null) {
|
||||
// 检查学校名称是否变化
|
||||
if (school.getSchoolName() != null && !school.getSchoolName().equals(existSchool.getSchoolName())) {
|
||||
SysDeptBo deptBo = new SysDeptBo();
|
||||
deptBo.setDeptId(existSchool.getDeptId());
|
||||
deptBo.setDeptName(school.getSchoolName());
|
||||
deptService.updateDept(deptBo);
|
||||
}
|
||||
}
|
||||
return baseMapper.updateById(school);
|
||||
}
|
||||
|
||||
|
|
@ -133,6 +164,9 @@ public class PgSchoolServiceImpl implements IPgSchoolService {
|
|||
for (Long schoolId : schoolIds) {
|
||||
// TODO: 检查是否被学生信息引用(学生管理模块完成后添加),有则不允许删除
|
||||
|
||||
// 查询学校信息,获取关联的部门ID
|
||||
PgSchool school = baseMapper.selectById(schoolId);
|
||||
|
||||
// 级联删除:先删除学校下的所有班级和年级
|
||||
List<PgSchoolGrade> grades = schoolGradeMapper.selectList(
|
||||
new LambdaQueryWrapper<PgSchoolGrade>().eq(PgSchoolGrade::getSchoolId, schoolId)
|
||||
|
|
@ -147,6 +181,15 @@ public class PgSchoolServiceImpl implements IPgSchoolService {
|
|||
schoolGradeMapper.delete(
|
||||
new LambdaQueryWrapper<PgSchoolGrade>().eq(PgSchoolGrade::getSchoolId, schoolId)
|
||||
);
|
||||
|
||||
// 删除关联的部门节点
|
||||
if (school != null && school.getDeptId() != null) {
|
||||
try {
|
||||
deptService.deleteDeptById(school.getDeptId());
|
||||
} catch (Exception e) {
|
||||
// 忽略部门删除失败(可能部门下有用户)
|
||||
}
|
||||
}
|
||||
}
|
||||
return baseMapper.deleteByIds(Arrays.asList(schoolIds));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -48,6 +48,11 @@ public class PgStudent extends BaseEntity {
|
|||
|
||||
private String tenantId;
|
||||
|
||||
/**
|
||||
* 关联部门ID(数据权限用)
|
||||
*/
|
||||
private Long deptId;
|
||||
|
||||
@TableLogic
|
||||
private String delFlag;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,12 +1,45 @@
|
|||
package org.dromara.pangu.student.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.Wrapper;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import org.dromara.common.mybatis.annotation.DataColumn;
|
||||
import org.dromara.common.mybatis.annotation.DataPermission;
|
||||
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
|
||||
import org.dromara.pangu.student.domain.PgStudent;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 学生 Mapper 接口
|
||||
*
|
||||
* @author pangu
|
||||
*/
|
||||
public interface PgStudentMapper extends BaseMapperPlus<PgStudent, PgStudent> {
|
||||
|
||||
/**
|
||||
* 查询学生列表(带数据权限)
|
||||
*
|
||||
* @param queryWrapper 查询条件
|
||||
* @return 学生列表
|
||||
*/
|
||||
@DataPermission({
|
||||
@DataColumn(key = "deptName", value = "dept_id")
|
||||
})
|
||||
default List<PgStudent> selectStudentList(Wrapper<PgStudent> queryWrapper) {
|
||||
return this.selectList(queryWrapper);
|
||||
}
|
||||
|
||||
/**
|
||||
* 分页查询学生列表(带数据权限)
|
||||
*
|
||||
* @param page 分页信息
|
||||
* @param queryWrapper 查询条件
|
||||
* @return 学生分页列表
|
||||
*/
|
||||
@DataPermission({
|
||||
@DataColumn(key = "deptName", value = "dept_id")
|
||||
})
|
||||
default Page<PgStudent> selectPageStudentList(Page<PgStudent> page, Wrapper<PgStudent> queryWrapper) {
|
||||
return this.selectPage(page, queryWrapper);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,16 @@
|
|||
-- ============================================================
|
||||
-- 脚本名称:school_dept_permission.sql
|
||||
-- 功能说明:学校数据权限支持 - 增加部门关联字段
|
||||
-- 作 者:pangu
|
||||
-- 创建时间:2026-02-03
|
||||
-- ============================================================
|
||||
|
||||
-- 1. pg_school 表增加 dept_id 字段
|
||||
ALTER TABLE pg_school ADD COLUMN dept_id BIGINT COMMENT '关联部门ID';
|
||||
CREATE INDEX idx_school_dept ON pg_school(dept_id);
|
||||
|
||||
-- 2. 查看现有学校数据
|
||||
SELECT school_id, school_name, school_code FROM pg_school;
|
||||
|
||||
-- 3. 查看现有部门数据
|
||||
SELECT dept_id, parent_id, dept_name, ancestors FROM sys_dept;
|
||||
|
|
@ -27,6 +27,17 @@
|
|||
<el-option label="完全中学" value="5" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="上级部门" prop="deptId">
|
||||
<el-tree-select
|
||||
v-model="form.deptId"
|
||||
:data="deptTree"
|
||||
:props="{ value: 'id', label: 'label', children: 'children' }"
|
||||
value-key="id"
|
||||
placeholder="请选择上级部门(分公司)"
|
||||
check-strictly
|
||||
style="width: 100%"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="所属区域" prop="regionId">
|
||||
<el-cascader
|
||||
v-model="form.regionIds"
|
||||
|
|
@ -66,8 +77,9 @@
|
|||
* @author pangu
|
||||
*/
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { computed, ref } from 'vue'
|
||||
import { computed, ref, onMounted } from 'vue'
|
||||
import { addSchool, updateSchool } from '@/api/pangu/school'
|
||||
import { deptTreeSelect } from '@/api/system/user'
|
||||
|
||||
// 接收父组件传递的区域树
|
||||
const props = defineProps({
|
||||
|
|
@ -77,6 +89,9 @@ const props = defineProps({
|
|||
}
|
||||
})
|
||||
|
||||
// 部门树数据
|
||||
const deptTree = ref([])
|
||||
|
||||
const emit = defineEmits(['success'])
|
||||
|
||||
const dialogVisible = ref(false)
|
||||
|
|
@ -90,6 +105,7 @@ const form = ref({
|
|||
schoolCode: '',
|
||||
schoolName: '',
|
||||
schoolType: '',
|
||||
deptId: null,
|
||||
regionId: null,
|
||||
regionIds: [],
|
||||
regionName: '',
|
||||
|
|
@ -107,6 +123,9 @@ const rules = {
|
|||
schoolType: [
|
||||
{ required: true, message: '请选择学校类型', trigger: 'change' }
|
||||
],
|
||||
deptId: [
|
||||
{ required: true, message: '请选择上级部门', trigger: 'change' }
|
||||
],
|
||||
regionId: [
|
||||
{ required: true, message: '请选择所属区域', trigger: 'change' }
|
||||
]
|
||||
|
|
@ -140,13 +159,28 @@ const handleRegionChange = (value) => {
|
|||
}
|
||||
}
|
||||
|
||||
// 加载部门树
|
||||
const loadDeptTree = async () => {
|
||||
try {
|
||||
const res = await deptTreeSelect()
|
||||
if (res.code === 200) {
|
||||
deptTree.value = res.data
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('加载部门树失败:', error)
|
||||
}
|
||||
}
|
||||
|
||||
// 打开弹窗
|
||||
// row: 编辑时传入学校数据,新增时为null
|
||||
// defaultRegionId: 新增时默认选中的区域ID(从列表页带入)
|
||||
const open = (row, defaultRegionId = null) => {
|
||||
const open = async (row, defaultRegionId = null) => {
|
||||
dialogVisible.value = true
|
||||
isEdit.value = !!row
|
||||
|
||||
// 加载部门树
|
||||
await loadDeptTree()
|
||||
|
||||
if (row) {
|
||||
// 编辑模式:回显数据
|
||||
form.value = {
|
||||
|
|
@ -154,6 +188,7 @@ const open = (row, defaultRegionId = null) => {
|
|||
schoolCode: row.schoolCode || '',
|
||||
schoolName: row.schoolName,
|
||||
schoolType: row.schoolType,
|
||||
deptId: row.deptId,
|
||||
regionId: row.regionId,
|
||||
regionIds: getRegionIdPath(row.regionId),
|
||||
regionName: row.regionName,
|
||||
|
|
@ -167,6 +202,7 @@ const open = (row, defaultRegionId = null) => {
|
|||
schoolCode: '',
|
||||
schoolName: '',
|
||||
schoolType: '',
|
||||
deptId: null,
|
||||
regionId: defaultRegionId,
|
||||
regionIds: regionIds,
|
||||
regionName: defaultRegionId ? getRegionPath(regionIds, props.regionTree) : '',
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@
|
|||
<el-table-column label="用户编号" align="center" key="userId" prop="userId" v-if="columns.userId.visible" />
|
||||
<el-table-column label="用户名称" align="center" key="userName" prop="userName" v-if="columns.userName.visible" :show-overflow-tooltip="true" />
|
||||
<el-table-column label="用户昵称" align="center" key="nickName" prop="nickName" v-if="columns.nickName.visible" :show-overflow-tooltip="true" />
|
||||
<el-table-column label="部门" align="center" key="deptName" prop="dept.deptName" v-if="columns.deptName.visible" :show-overflow-tooltip="true" />
|
||||
<el-table-column label="部门" align="center" key="deptName" prop="deptName" v-if="columns.deptName.visible" :show-overflow-tooltip="true" />
|
||||
<el-table-column label="手机号码" align="center" key="phonenumber" prop="phonenumber" v-if="columns.phonenumber.visible" width="120" />
|
||||
<el-table-column label="状态" align="center" key="status" v-if="columns.status.visible">
|
||||
<template #default="scope">
|
||||
|
|
@ -504,8 +504,8 @@ function cancel() {
|
|||
function handleAdd() {
|
||||
reset()
|
||||
getUser().then(response => {
|
||||
postOptions.value = response.posts
|
||||
roleOptions.value = response.roles
|
||||
postOptions.value = response.data.posts
|
||||
roleOptions.value = response.data.roles
|
||||
open.value = true
|
||||
title.value = "添加用户"
|
||||
form.value.password = initPassword.value
|
||||
|
|
@ -517,11 +517,11 @@ function handleUpdate(row) {
|
|||
reset()
|
||||
const userId = row.userId || ids.value
|
||||
getUser(userId).then(response => {
|
||||
form.value = response.data
|
||||
postOptions.value = response.posts
|
||||
roleOptions.value = response.roles
|
||||
form.value.postIds = response.postIds
|
||||
form.value.roleIds = response.roleIds
|
||||
form.value = response.data.user
|
||||
postOptions.value = response.data.posts
|
||||
roleOptions.value = response.data.roles
|
||||
form.value.postIds = response.data.postIds
|
||||
form.value.roleIds = response.data.roleIds
|
||||
open.value = true
|
||||
title.value = "修改用户"
|
||||
form.value.password = ""
|
||||
|
|
|
|||
Loading…
Reference in New Issue