246 lines
9.9 KiB
Java
246 lines
9.9 KiB
Java
package com.yunhai.bschclassmanage.service.impl;
|
||
|
||
import com.alibaba.fastjson.JSON;
|
||
import com.yunhai.bschclassmanage.Repository.SchClassRepository;
|
||
import com.yunhai.bschclassmanage.Repository.SchDicCampusRepository;
|
||
import com.yunhai.bschclassmanage.annotation.OperationLog;
|
||
import com.yunhai.bschclassmanage.entity.SchDicCampus;
|
||
import com.yunhai.bschclassmanage.model.constant.LogModule;
|
||
import com.yunhai.bschclassmanage.model.entityField.EntityFieldNames;
|
||
import com.yunhai.bschclassmanage.model.vo.SelectIntVO;
|
||
import com.yunhai.bschclassmanage.service.ISchDicCampusService;
|
||
import com.yunhai.bschclassmanage.utils.*;
|
||
import com.yunhai.platform.utils.exception.DException;
|
||
import lombok.extern.slf4j.Slf4j;
|
||
import org.springframework.beans.BeanUtils;
|
||
import org.springframework.beans.factory.annotation.Autowired;
|
||
import org.springframework.data.jpa.domain.Specification;
|
||
import org.springframework.stereotype.Service;
|
||
import org.springframework.transaction.annotation.Transactional;
|
||
|
||
import javax.persistence.criteria.Predicate;
|
||
import java.util.*;
|
||
import java.util.function.Function;
|
||
import java.util.stream.Collectors;
|
||
|
||
@Slf4j
|
||
@Service
|
||
public class SchDicCampusService implements ISchDicCampusService {
|
||
|
||
@Autowired
|
||
private SchDicCampusRepository schDicCampusRepository;
|
||
|
||
|
||
@Autowired
|
||
private SchClassRepository schClassRepository;
|
||
|
||
@Autowired
|
||
private RedisUtil redisUtil;
|
||
|
||
|
||
public List<SchDicCampus> getSchDicCampusList(Integer schId) {
|
||
Specification<SchDicCampus> spec = (root, query, cb) -> {
|
||
List<Predicate> predicates = new ArrayList<>();
|
||
predicates.add(cb.equal(root.get(EntityFieldNames.schId), schId));
|
||
return cb.and(predicates.toArray(new Predicate[0]));
|
||
};
|
||
return schDicCampusRepository.findAll(spec);
|
||
}
|
||
|
||
// 获取学校院校列表(带缓存)
|
||
public List<SchDicCampus> getSchDicCampusCacheList(Integer schId) {
|
||
String cacheKey = RedisConstants.SCHOOL_CAMPUS + "_" + schId;
|
||
if (redisUtil.hasKey(cacheKey)) {
|
||
// 注意:返回副本或不可变列表,避免外部修改影响缓存
|
||
return redisUtil.getList(cacheKey,SchDicCampus.class);
|
||
}
|
||
// 同步查询数据库,防止缓存击穿
|
||
synchronized (this) {
|
||
if (redisUtil.hasKey(cacheKey)) {
|
||
return redisUtil.getList(cacheKey,SchDicCampus.class);
|
||
}
|
||
List<SchDicCampus> list = getSchDicCampusList(schId);
|
||
|
||
// 根据 sort 字段升序排序,null 值排在最后
|
||
list.sort(Comparator.comparing(SchDicCampus::getSort,
|
||
Comparator.nullsLast(Comparator.naturalOrder())));
|
||
|
||
redisUtil.set(cacheKey, new ArrayList<>(list), RedisConstants.CACHE_EXPIRE_30D);
|
||
return list;
|
||
}
|
||
}
|
||
|
||
|
||
@OperationLog(module = LogModule.CAMPUS)
|
||
@Transactional(rollbackFor = Exception.class)
|
||
public void saveSchCampus(UserContext.UserInfo user, SchDicCampus entity) {
|
||
|
||
Integer schId=user.getSchId();
|
||
|
||
boolean isNew=entity.getId() == null || entity.getId() == 0;
|
||
// 参数校验
|
||
if (entity.getName() == null || entity.getName().trim().isEmpty())
|
||
throw new DException("校区名称不能为空");
|
||
|
||
boolean nameExists;
|
||
SchDicCampus oldEntity=null;
|
||
|
||
if (isNew) {
|
||
// 新增:检查同名校区
|
||
nameExists = schDicCampusRepository.existsBySchIdAndName(schId, entity.getName());
|
||
if (nameExists) {
|
||
throw new DException("校区名称已存在:" + entity.getName());
|
||
}
|
||
OtherUtil.setBaseEntityValue(user, entity);
|
||
|
||
schDicCampusRepository.save(entity);
|
||
} else {
|
||
// 更新:排除自身,检查其他校区同名
|
||
nameExists = schDicCampusRepository.existsBySchIdAndNameAndIdNot(schId, entity.getName(), entity.getId());
|
||
if (nameExists) {
|
||
throw new DException("校区名称已存在:" + entity.getName());
|
||
}
|
||
Integer entityId=entity.getId();
|
||
SchDicCampus existing = schDicCampusRepository.findById(entityId)
|
||
.orElseThrow(() -> new DException("校区不存在,ID=" + entityId));
|
||
|
||
oldEntity=OtherUtil.deepCopy(existing,SchDicCampus.class);
|
||
|
||
OtherUtil.setBaseEntityValue(user, entity);
|
||
|
||
BeanUtils.copyProperties(entity, existing,
|
||
EntityFieldNames.id,
|
||
EntityFieldNames.schId,
|
||
EntityFieldNames.code,
|
||
EntityFieldNames.createDate,
|
||
EntityFieldNames.createUserId);
|
||
|
||
entity=schDicCampusRepository.save(existing);
|
||
}
|
||
|
||
// 清除缓存
|
||
String cacheKey = RedisConstants.SCHOOL_CAMPUS + "_" + schId;
|
||
redisUtil.del(cacheKey);
|
||
|
||
{
|
||
String description = buildCampusLogDescription(entity,isNew,oldEntity);
|
||
LogContextHolder.setDescription(description);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 构建学部操作的详细日志描述
|
||
*/
|
||
private String buildCampusLogDescription(SchDicCampus newEntity,boolean isNew,SchDicCampus oldEntity) {
|
||
if (isNew) {
|
||
return String.format("新增校区:%s(序号:%d)",
|
||
newEntity.getName(),
|
||
newEntity.getSort() != null ? newEntity.getSort() : 0);
|
||
} else {
|
||
List<String> changes = new ArrayList<>();
|
||
if (!Objects.equals(oldEntity.getName(), newEntity.getName())) {
|
||
changes.add(String.format("名称从 '%s' 修改为 '%s'", oldEntity.getName(), newEntity.getName()));
|
||
}
|
||
if (!Objects.equals(oldEntity.getSort(), newEntity.getSort())) {
|
||
changes.add(String.format("序号从 %d 修改为 %d", oldEntity.getSort(), newEntity.getSort()));
|
||
}
|
||
if (changes.isEmpty()) {
|
||
return "更新校区:无实际变更";
|
||
}
|
||
return "更新校区:" + String.join(";", changes);
|
||
}
|
||
}
|
||
|
||
@OperationLog(module = LogModule.CAMPUS)
|
||
@Transactional(rollbackFor = Exception.class)
|
||
public void sortSchCampus(UserContext.UserInfo user,List<Integer> ids)
|
||
{
|
||
List<SchDicCampus> campusList = getSchDicCampusCacheList(user.getSchId());
|
||
Map<Integer, SchDicCampus> campusMap = campusList.stream()
|
||
.collect(Collectors.toMap(SchDicCampus::getId, Function.identity()));
|
||
|
||
Date now = new Date();
|
||
// 1. 按传入顺序更新 sort 值
|
||
int sortOrder = 1;
|
||
for (Integer id : ids) {
|
||
SchDicCampus campus = campusMap.get(id);
|
||
if (campus != null) {
|
||
campus.setSort(sortOrder++);
|
||
campus.setUpdateDate(now);
|
||
campus.setUpdateUserId(user.getUserId());
|
||
}
|
||
}
|
||
|
||
// 2. 处理未出现在排序列表中的校区(设置 sort = null 或一个大值)
|
||
for (SchDicCampus campus : campusList) {
|
||
if (!ids.contains(campus.getId())) {
|
||
campus.setSort(null); // 或者设置一个最大值,比如 999
|
||
campus.setUpdateDate(now);
|
||
campus.setUpdateUserId(user.getUserId());
|
||
}
|
||
}
|
||
// 批量保存
|
||
schDicCampusRepository.saveAll(campusList);
|
||
String cacheKey = RedisConstants.SCHOOL_CAMPUS + "_" + user.getSchId();
|
||
redisUtil.del(cacheKey);
|
||
{
|
||
String names = ids.stream()
|
||
.map(id -> {
|
||
SchDicCampus m = campusMap.get(id);
|
||
return m != null ? m.getName() : String.valueOf(id);
|
||
})
|
||
.collect(Collectors.joining("、"));
|
||
String description = String.format("调整校区排序:共 %d 个专业(列表:%s)", ids.size(), names);
|
||
LogContextHolder.setDescription(description);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 删除校区
|
||
* 1. 参数非空校验
|
||
* 2. 校验校区是否存在(匹配学校+校区ID,防止跨学校删除)
|
||
* 3. 校验校区是否绑定班级,存在关联则禁止删除
|
||
* 4. 删除数据库数据 + 清除对应学校校区缓存
|
||
* @param id 校区ID
|
||
*/
|
||
|
||
@OperationLog(module = LogModule.CAMPUS)
|
||
@Transactional(rollbackFor = Exception.class)
|
||
public void delete(UserContext.UserInfo user, Integer id) {
|
||
// 1. 参数合法性校验
|
||
if (user.getSchId() == null || id == null) {
|
||
throw new DException("学校ID、校区ID不能为空");
|
||
}
|
||
|
||
// 2. 校验当前学校下该校区是否存在,防止越权删除其他学校校区
|
||
SchDicCampus campus = schDicCampusRepository.findByIdAndSchId(id, user.getSchId())
|
||
.orElseThrow(() -> new DException("校区不存在,无法删除"));
|
||
|
||
// 3. 业务校验:判断校区是否关联班级,有班级则禁止删除
|
||
long bindClassCount = schClassRepository.countByCampusId(id);
|
||
if (bindClassCount > 0) {
|
||
throw new DException(String.format("该校区下存在%s个班级,不可删除,请先移除班级关联", bindClassCount));
|
||
}
|
||
|
||
// 4. 删除数据
|
||
schDicCampusRepository.delete(campus);
|
||
|
||
// 5. 清除当前学校校区缓存
|
||
String cacheKey = RedisConstants.SCHOOL_CAMPUS + "_" + user.getSchId();
|
||
redisUtil.del(cacheKey);
|
||
|
||
LogContextHolder.setDescription("删除校区:"+campus.getName());
|
||
log.debug("操作人:{},删除校区日志:{}", user.getUserName(), JSON.toJSONString(campus));
|
||
}
|
||
|
||
public List<SelectIntVO> select(Integer schId) {
|
||
List<SchDicCampus> list = getSchDicCampusCacheList(schId);
|
||
return ModelMapperUtil.toSelectIntVOList(list, SchDicCampus::getId, SchDicCampus::getName);
|
||
}
|
||
|
||
public Map<Integer, String> toIdAndNameMap(Integer schId) {
|
||
List<SchDicCampus> list = getSchDicCampusCacheList(schId);
|
||
return ModelMapperUtil.toMap(list, SchDicCampus::getId, SchDicCampus::getName);
|
||
}
|
||
}
|