diff --git a/cf-module-system/cf-module-system-api/src/main/java/com/cf/imes/module/system/enums/ErrorCodeConstants.java b/cf-module-system/cf-module-system-api/src/main/java/com/cf/imes/module/system/enums/ErrorCodeConstants.java index 9cb9ac62f..149025974 100644 --- a/cf-module-system/cf-module-system-api/src/main/java/com/cf/imes/module/system/enums/ErrorCodeConstants.java +++ b/cf-module-system/cf-module-system-api/src/main/java/com/cf/imes/module/system/enums/ErrorCodeConstants.java @@ -71,6 +71,7 @@ public class ErrorCodeConstants { public static final ErrorCode DEPT_NOT_ENABLE = new ErrorCode(1_002_004_006, "部门({})不处于开启状态,不允许选择"); public static final ErrorCode DEPT_PARENT_IS_CHILD = new ErrorCode(1_002_004_007, "不能设置自己的子部门为父部门"); public static final ErrorCode DEPT_USER_OPER_NOT_ALLOW = new ErrorCode(1_002_015_008, "不允许操作用户自身部门"); + public static final ErrorCode PARENT_DEPT_USER_OPER_NOT_ALLOW = new ErrorCode(1_002_015_008, "不允许操作用户自身部门及其上级部门"); public static final ErrorCode DEPT_DISABLE = new ErrorCode(1_002_004_006, "部门({})已被禁用"); // ========== 岗位模块 1-002-005-000 ========== @@ -94,6 +95,7 @@ public class ErrorCodeConstants { // ========== 通知公告 1-002-008-000 ========== public static final ErrorCode NOTICE_NOT_FOUND = new ErrorCode(1_002_008_001, "当前通知公告不存在"); public static final ErrorCode NOTICE_NAME_UNIQE_ERROR = new ErrorCode(1_002_008_002, "公告标题已存在,请编辑后重试"); + public static final ErrorCode NOTICE_BUILDIN_MODIFY_PERMISSION_ERROR = new ErrorCode(1_002_008_003, "内置通知公告编辑权限不足"); // ========== 短信渠道 1-002-011-000 ========== public static final ErrorCode SMS_CHANNEL_NOT_EXISTS = new ErrorCode(1_002_011_000, "短信渠道不存在"); diff --git a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/controller/admin/notice/vo/NoticePageReqVO.java b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/controller/admin/notice/vo/NoticePageReqVO.java index 1de067edc..8fedeaf26 100644 --- a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/controller/admin/notice/vo/NoticePageReqVO.java +++ b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/controller/admin/notice/vo/NoticePageReqVO.java @@ -21,4 +21,9 @@ public class NoticePageReqVO extends PageParam { @CommonStatus private Integer status; + @Schema(description = "组织id") + private Long organId; + + @Schema(description = "通知公告来源") + private Integer source; } diff --git a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/controller/admin/notice/vo/NoticeSaveReqVO.java b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/controller/admin/notice/vo/NoticeSaveReqVO.java index 47cc6c34a..5dc9113b6 100644 --- a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/controller/admin/notice/vo/NoticeSaveReqVO.java +++ b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/controller/admin/notice/vo/NoticeSaveReqVO.java @@ -25,6 +25,7 @@ public class NoticeSaveReqVO { private Integer type; @Schema(description = "公告内容", requiredMode = Schema.RequiredMode.REQUIRED, example = "半生编码") + @NotBlank(message = "公告内容不能为空") private String content; @Schema(description = "状态,参见 CommonStatusEnum 枚举类", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") diff --git a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/dal/dataobject/notice/NoticeDO.java b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/dal/dataobject/notice/NoticeDO.java index 02ffc404b..380ad33a7 100644 --- a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/dal/dataobject/notice/NoticeDO.java +++ b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/dal/dataobject/notice/NoticeDO.java @@ -1,7 +1,10 @@ package com.cf.imes.module.system.dal.dataobject.notice; +import com.baomidou.mybatisplus.annotation.FieldFill; +import com.baomidou.mybatisplus.annotation.TableField; import com.cf.imes.framework.common.enums.CommonStatusEnum; import com.cf.imes.framework.mybatis.core.dataobject.BaseDO; +import com.cf.imes.module.system.enums.notice.NoticeSourceEnum; import com.cf.imes.module.system.enums.notice.NoticeTypeEnum; import com.baomidou.mybatisplus.annotation.KeySequence; import com.baomidou.mybatisplus.annotation.TableName; @@ -33,6 +36,14 @@ public class NoticeDO extends BaseDO { * 枚举 {@link NoticeTypeEnum} */ private Integer type; + + /** + * 公告来源 + *

+ * 枚举 {@link NoticeSourceEnum} + */ + private NoticeSourceEnum source; + /** * 公告内容 */ @@ -44,4 +55,9 @@ public class NoticeDO extends BaseDO { */ private Integer status; + /** + * 组织ID + */ + @TableField(fill = FieldFill.INSERT_UPDATE) + private Long organId; } diff --git a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/dal/mysql/notice/NoticeMapper.java b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/dal/mysql/notice/NoticeMapper.java index 8b36d8ca3..7a7af7993 100644 --- a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/dal/mysql/notice/NoticeMapper.java +++ b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/dal/mysql/notice/NoticeMapper.java @@ -3,18 +3,33 @@ package com.cf.imes.module.system.dal.mysql.notice; import com.cf.imes.framework.common.pojo.PageResult; import com.cf.imes.framework.mybatis.core.mapper.BaseMapperX; import com.cf.imes.framework.mybatis.core.query.LambdaQueryWrapperX; +import com.cf.imes.framework.organ.core.context.OrganContextHolder; import com.cf.imes.module.system.controller.admin.notice.vo.NoticePageReqVO; import com.cf.imes.module.system.dal.dataobject.notice.NoticeDO; +import com.cf.imes.module.system.enums.notice.NoticeSourceEnum; import org.apache.ibatis.annotations.Mapper; @Mapper public interface NoticeMapper extends BaseMapperX { default PageResult selectPage(NoticePageReqVO reqVO) { + if (NoticeSourceEnum.SYSTEM.getSource().equals(reqVO.getSource())) { + // 超管只看内置的 + return selectPage(reqVO, new LambdaQueryWrapperX() + .likeIfPresent(NoticeDO::getTitle, reqVO.getTitle()) + .eqIfPresent(NoticeDO::getStatus, reqVO.getStatus()) + .eqIfPresent(NoticeDO::getSource, NoticeSourceEnum.SYSTEM) + .orderByDesc(NoticeDO::getId)); + } + // 普通用户查机构下的和内置的 return selectPage(reqVO, new LambdaQueryWrapperX() .likeIfPresent(NoticeDO::getTitle, reqVO.getTitle()) .eqIfPresent(NoticeDO::getStatus, reqVO.getStatus()) - .orderByDesc(NoticeDO::getId)); + .and(wr -> wr.or(wrapper -> wrapper + .eq(NoticeDO::getOrganId, OrganContextHolder.getOrganId()) + .eq(NoticeDO::getSource, NoticeSourceEnum.CUSTOM)) + .or(wrapper -> wrapper.eq(NoticeDO::getSource, NoticeSourceEnum.SYSTEM))) + .orderByDesc(NoticeDO::getId)); } } diff --git a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/enums/notice/NoticeSourceEnum.java b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/enums/notice/NoticeSourceEnum.java new file mode 100644 index 000000000..d2de57e1e --- /dev/null +++ b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/enums/notice/NoticeSourceEnum.java @@ -0,0 +1,38 @@ +package com.cf.imes.module.system.enums.notice; + +import com.baomidou.mybatisplus.annotation.EnumValue; +import com.fasterxml.jackson.annotation.JsonCreator; +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 通知公告来源 + * + * @author Gqr + * @since 2024/7/5 9:25 + */ +@Getter +@AllArgsConstructor +public enum NoticeSourceEnum { + /** + * 内置 + */ + SYSTEM(0), + /** + * 自定义 + */ + CUSTOM(1); + + @EnumValue + private final Integer source; + + @JsonCreator + public static NoticeSourceEnum fromSource(Integer source) { + for (NoticeSourceEnum value : values()) { + if (value.getSource().equals(source)) { + return value; + } + } + return null; + } +} diff --git a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/service/dept/DeptServiceImpl.java b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/service/dept/DeptServiceImpl.java index 88ba11fd9..f391c6fef 100644 --- a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/service/dept/DeptServiceImpl.java +++ b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/service/dept/DeptServiceImpl.java @@ -36,6 +36,7 @@ import static com.cf.imes.framework.common.exception.util.ServiceExceptionUtil.e import static com.cf.imes.framework.common.util.collection.CollectionUtils.convertSet; import static com.cf.imes.module.system.dal.redis.RedisKeyConstants.OAUTH2_ACCESS_TOKEN; import static com.cf.imes.module.system.enums.ErrorCodeConstants.DEPT_USER_OPER_NOT_ALLOW; +import static com.cf.imes.module.system.enums.ErrorCodeConstants.PARENT_DEPT_USER_OPER_NOT_ALLOW; /** * 部门 Service 实现类 @@ -105,14 +106,14 @@ public class DeptServiceImpl implements DeptService { @CacheEvict(cacheNames = RedisKeyConstants.DEPT_CHILDREN_ID_LIST, allEntries = true) // allEntries 清空所有缓存,因为操作一个部门,涉及到多个缓存 public void deleteDept(Long id) { - // 校验部门内用户操作 - checkCurrentWhenOperate(id); // 校验是否存在 validateDeptExists(id); // 校验是否有子部门 if (deptMapper.selectCountByParentId(id) > 0) { throw ServiceExceptionUtil.exception(ErrorCodeConstants.DEPT_EXITS_CHILDREN); } + // 校验部门内用户操作 + checkCurrentWhenOperate(id); // 删除部门 deptMapper.deleteById(id); // 删除关联的用户 @@ -153,9 +154,15 @@ public class DeptServiceImpl implements DeptService { */ private void checkCurrentWhenOperate(Long deptId) { LoginUser loginUser = SecurityFrameworkUtils.getLoginUser(); - if (ObjectUtil.isNotNull(loginUser) && ObjectUtil.equal(deptId, loginUser.getDeptId())) { + Long currentDeptId = loginUser.getDeptId(); + if (ObjectUtil.isNotNull(loginUser) && ObjectUtil.equal(deptId, currentDeptId)) { throw exception(DEPT_USER_OPER_NOT_ALLOW); } + // 递归查询所有下级,如果当前用户在范围内不允许操作 + List childDeptList = getChildDeptList(deptId); + childDeptList.stream().filter(d -> d.getId().equals(currentDeptId)).findAny().ifPresent(deptDO -> { + throw exception(PARENT_DEPT_USER_OPER_NOT_ALLOW); + }); } @VisibleForTesting diff --git a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/service/notice/NoticeServiceImpl.java b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/service/notice/NoticeServiceImpl.java index 2e7accf72..b852545c6 100644 --- a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/service/notice/NoticeServiceImpl.java +++ b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/service/notice/NoticeServiceImpl.java @@ -1,17 +1,21 @@ package com.cf.imes.module.system.service.notice; import cn.hutool.core.util.ObjectUtil; +import cn.hutool.extra.spring.SpringUtil; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.cf.imes.framework.common.exception.util.ServiceExceptionUtil; import com.cf.imes.framework.common.pojo.PageResult; import com.cf.imes.framework.common.util.object.BeanUtils; import com.cf.imes.framework.mybatis.core.query.LambdaQueryWrapperX; +import com.cf.imes.framework.organ.core.aop.OrganIgnore; +import com.cf.imes.framework.organ.core.context.OrganContextHolder; +import com.cf.imes.framework.security.core.util.SecurityFrameworkUtils; import com.cf.imes.module.system.controller.admin.notice.vo.NoticePageReqVO; import com.cf.imes.module.system.controller.admin.notice.vo.NoticeSaveReqVO; import com.cf.imes.module.system.dal.dataobject.notice.NoticeDO; import com.cf.imes.module.system.dal.mysql.notice.NoticeMapper; import com.cf.imes.module.system.enums.ErrorCodeConstants; -import com.google.common.annotations.VisibleForTesting; +import com.cf.imes.module.system.enums.notice.NoticeSourceEnum; import org.springframework.stereotype.Service; import javax.annotation.Resource; @@ -30,11 +34,19 @@ public class NoticeServiceImpl implements NoticeService { @Resource private NoticeMapper noticeMapper; + + private NoticeServiceImpl getSelf() { + return SpringUtil.getBean(getClass()); + } + @Override public Long createNotice(NoticeSaveReqVO createReqVO) { // 标题唯一性校验 validateNameExists(createReqVO); NoticeDO notice = BeanUtils.toBean(createReqVO, NoticeDO.class); + + // 超管创建的都是内置公告 + modifySource(notice); noticeMapper.insert(notice); return notice.getId(); } @@ -42,24 +54,32 @@ public class NoticeServiceImpl implements NoticeService { @Override public void updateNotice(NoticeSaveReqVO updateReqVO) { // 校验是否存在 - validateNoticeExists(updateReqVO.getId()); + getSelf().validateNoticeExists(updateReqVO.getId()); // 标题唯一性校验 - validateNameExists(updateReqVO); + getSelf().validateNameExists(updateReqVO); // 更新通知公告 NoticeDO updateObj = BeanUtils.toBean(updateReqVO, NoticeDO.class); + // 超管创建的都是内置公告 + modifySource(updateObj); noticeMapper.updateById(updateObj); } @Override public void deleteNotice(Long id) { // 校验是否存在 - validateNoticeExists(id); + getSelf().validateNoticeExists(id); // 删除通知公告 noticeMapper.deleteById(id); } @Override + @OrganIgnore public PageResult getNoticePage(NoticePageReqVO reqVO) { + boolean isSuperAdmin = SecurityFrameworkUtils.isSuperAdmin(); + // 超管查看内置公告 + if (isSuperAdmin) { + reqVO.setSource(NoticeSourceEnum.SYSTEM.getSource()); + } return noticeMapper.selectPage(reqVO); } @@ -68,7 +88,7 @@ public class NoticeServiceImpl implements NoticeService { return noticeMapper.selectById(id); } - @VisibleForTesting + @OrganIgnore public void validateNoticeExists(Long id) { if (id == null) { return; @@ -77,6 +97,13 @@ public class NoticeServiceImpl implements NoticeService { if (notice == null) { throw ServiceExceptionUtil.exception(ErrorCodeConstants.NOTICE_NOT_FOUND); } + if (!NoticeSourceEnum.SYSTEM.equals(notice.getSource()) && !notice.getOrganId().equals(OrganContextHolder.getOrganId())) { + throw ServiceExceptionUtil.exception(ErrorCodeConstants.NOTICE_NOT_FOUND); + } + // 只有超管可以操作内置公告 + if (NoticeSourceEnum.SYSTEM.equals(notice.getSource()) && !SecurityFrameworkUtils.isSuperAdmin()) { + throw ServiceExceptionUtil.exception(ErrorCodeConstants.NOTICE_BUILDIN_MODIFY_PERMISSION_ERROR); + } } /** @@ -84,14 +111,35 @@ public class NoticeServiceImpl implements NoticeService { * * @param reqVO */ + @OrganIgnore public void validateNameExists(NoticeSaveReqVO reqVO) { + boolean isSuperAdmin = SecurityFrameworkUtils.isSuperAdmin(); + Long noticeId = reqVO.getId(); LambdaQueryWrapper wrapper = new LambdaQueryWrapperX().eq(NoticeDO::getTitle, reqVO.getTitle()); if (ObjectUtil.isNotNull(noticeId)) { wrapper.ne(NoticeDO::getId, noticeId); } + if (isSuperAdmin) { + wrapper.eq(NoticeDO::getSource, NoticeSourceEnum.SYSTEM); + } else { + wrapper.eq(NoticeDO::getOrganId, OrganContextHolder.getOrganId()); + } if (noticeMapper.exists(wrapper)) { throw exception(NOTICE_NAME_UNIQE_ERROR); } } + + /** + * 公告来源赋值 + * + * @param notice + */ + private void modifySource(NoticeDO notice) { + if (SecurityFrameworkUtils.isSuperAdmin()) { + notice.setSource(NoticeSourceEnum.SYSTEM); + } else { + notice.setSource(NoticeSourceEnum.CUSTOM); + } + } }