11 小时以前 620bb4712a31791231c4381581f0f60088f079fe
src/main/java/com/ruoyi/collaborativeApproval/service/impl/EnterpriseNewsServiceImpl.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,409 @@
package com.ruoyi.collaborativeApproval.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.approve.mapper.ApprovalInstanceMapper;
import com.ruoyi.approve.mapper.ApprovalTemplateMapper;
import com.ruoyi.approve.pojo.ApprovalInstance;
import com.ruoyi.approve.pojo.ApprovalTask;
import com.ruoyi.approve.pojo.ApprovalTemplate;
import com.ruoyi.approve.service.ApprovalInstanceService;
import com.ruoyi.approve.utils.ApproveProcessConfigNodeUtils;
import com.ruoyi.basic.enums.ApplicationTypeEnum;
import com.ruoyi.basic.enums.RecordTypeEnum;
import com.ruoyi.basic.utils.FileUtil;
import com.ruoyi.collaborativeApproval.dto.EnterpriseNewsDto;
import com.ruoyi.collaborativeApproval.mapper.EnterpriseNewsMapper;
import com.ruoyi.collaborativeApproval.pojo.EnterpriseNews;
import com.ruoyi.collaborativeApproval.pojo.EnterpriseNewsScopeDept;
import com.ruoyi.collaborativeApproval.pojo.EnterpriseNewsScopeUser;
import com.ruoyi.collaborativeApproval.service.EnterpriseNewsScopeDeptService;
import com.ruoyi.collaborativeApproval.service.EnterpriseNewsScopeUserService;
import com.ruoyi.collaborativeApproval.service.EnterpriseNewsService;
import com.ruoyi.collaborativeApproval.vo.EnterpriseNewsVo;
import com.ruoyi.common.enums.TypeEnums;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.OrderUtils;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.project.system.domain.SysDept;
import com.ruoyi.project.system.domain.SysUser;
import com.ruoyi.project.system.mapper.SysDeptMapper;
import com.ruoyi.project.system.mapper.SysUserDeptMapper;
import com.ruoyi.project.system.mapper.SysUserMapper;
import com.ruoyi.project.system.service.ISysNoticeService;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
/**
 * ä¼ä¸šæ–°é—»è¡¨æœåŠ¡å®žçŽ°ç±»
 *
 * @author èŠ¯å¯¼è½¯ä»¶ï¼ˆæ±Ÿè‹ï¼‰æœ‰é™å…¬å¸
 * @since 2026-05-20 11:50:59
 */
@Service
@RequiredArgsConstructor
public class EnterpriseNewsServiceImpl extends ServiceImpl<EnterpriseNewsMapper, EnterpriseNews> implements EnterpriseNewsService {
    private static final String READ_SCOPE_ALL = "all";
    private static final String READ_SCOPE_DEPT = "dept";
    private static final String READ_SCOPE_CUSTOM = "custom";
    private static final String STATUS_DRAFT = "DRAFT";
    private static final String STATUS_PENDING = "PENDING";
    private static final String STATUS_PUBLISHED = "PUBLISHED";
    private static final String STATUS_REJECTED = "REJECTED";
    private static final String STATUS_OFFLINE = "OFFLINE";
    private final EnterpriseNewsMapper enterpriseNewsMapper;
    private final EnterpriseNewsScopeDeptService enterpriseNewsScopeDeptService;
    private final EnterpriseNewsScopeUserService enterpriseNewsScopeUserService;
    private final SysUserMapper sysUserMapper;
    private final SysDeptMapper sysDeptMapper;
    private final SysUserDeptMapper sysUserDeptMapper;
    private final ApprovalInstanceMapper approvalInstanceMapper;
    private final ApprovalInstanceService approvalInstanceService;
    private final ApprovalTemplateMapper approvalTemplateMapper;
    private final ApproveProcessConfigNodeUtils approveProcessConfigNodeUtils;
    private final ISysNoticeService sysNoticeService;
    private final FileUtil fileUtil;
    @Override
    public IPage<EnterpriseNewsVo> listPage(Page<EnterpriseNewsVo> page, EnterpriseNewsDto enterpriseNewsDto) {
        IPage<EnterpriseNewsVo> enterpriseNewsVoIPage = enterpriseNewsMapper.listPage(page, enterpriseNewsDto);
        enterpriseNewsVoIPage.getRecords().forEach(enterpriseNewsVo -> {
            enterpriseNewsVo.setStorageBlobDTOs(fileUtil.getStorageBlobVOsByRecordTypeAndRecordId(RecordTypeEnum.ENTERPRISE_NEWS, enterpriseNewsVo.getId()));
        });
        return enterpriseNewsVoIPage;
    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean add(EnterpriseNewsDto enterpriseNewsDto) {
        validateForSave(enterpriseNewsDto);
        String readScope = normalizeReadScope(enterpriseNewsDto.getReadScope());
        List<Long> deptIds = distinctIds(enterpriseNewsDto.getDeptIds());
        List<Long> userIds = distinctIds(enterpriseNewsDto.getUserIds());
        EnterpriseNews enterpriseNews = new EnterpriseNews();
        BeanUtils.copyProperties(enterpriseNewsDto, enterpriseNews);
        enterpriseNews.setReadScope(readScope);
        enterpriseNews.setIsRequired(enterpriseNewsDto.getIsRequired() == null ? (byte) 0 : enterpriseNewsDto.getIsRequired());
        enterpriseNews.setStatus(normalizeStatus(enterpriseNewsDto.getStatus(), STATUS_DRAFT));
        enterpriseNews.setReadCount(0);
        enterpriseNews.setRequiredReadCount(calculateRequiredReadCount(readScope, deptIds, userIds));
        Long[] loginDeptIds = SecurityUtils.getDeptId();
        if (StringUtils.isNotEmpty(loginDeptIds)) {
            enterpriseNews.setDeptId(loginDeptIds[0]);
        }
        if (!save(enterpriseNews) || enterpriseNews.getId() == null) {
            throw new ServiceException("新增企业新闻失败");
        }
        saveReadScopeRelations(enterpriseNews.getId(), readScope, deptIds, userIds);
        if (STATUS_PENDING.equals(enterpriseNews.getStatus())) {
            startEnterpriseNewsApproval(enterpriseNews, enterpriseNewsDto);
        }
        //添加附件
        fileUtil.saveStorageAttachment(ApplicationTypeEnum.FILE, RecordTypeEnum.ENTERPRISE_NEWS, enterpriseNews.getId(), enterpriseNewsDto.getStorageBlobDTOs());
        return true;
    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean updateEnterpriseNewsDto(EnterpriseNewsDto enterpriseNewsDto) {
        if (enterpriseNewsDto == null || enterpriseNewsDto.getId() == null) {
            throw new ServiceException("企业新闻ID不能为空");
        }
        EnterpriseNews oldEnterpriseNews = getById(enterpriseNewsDto.getId());
        if (oldEnterpriseNews == null) {
            throw new ServiceException("企业新闻不存在");
        }
        if (!STATUS_DRAFT.equals(oldEnterpriseNews.getStatus())
                && !STATUS_REJECTED.equals(oldEnterpriseNews.getStatus())) {
            throw new ServiceException("待审批或已发布的企业新闻不允许修改");
        }
        validateForSave(enterpriseNewsDto);
        String readScope = normalizeReadScope(enterpriseNewsDto.getReadScope());
        List<Long> deptIds = distinctIds(enterpriseNewsDto.getDeptIds());
        List<Long> userIds = distinctIds(enterpriseNewsDto.getUserIds());
        EnterpriseNews enterpriseNews = new EnterpriseNews();
        BeanUtils.copyProperties(enterpriseNewsDto, enterpriseNews);
        enterpriseNews.setReadScope(readScope);
        enterpriseNews.setIsRequired(enterpriseNewsDto.getIsRequired() == null ? oldEnterpriseNews.getIsRequired() : enterpriseNewsDto.getIsRequired());
        enterpriseNews.setStatus(normalizeStatus(enterpriseNewsDto.getStatus(), oldEnterpriseNews.getStatus()));
        enterpriseNews.setReadCount(oldEnterpriseNews.getReadCount());
        enterpriseNews.setRequiredReadCount(calculateRequiredReadCount(readScope, deptIds, userIds));
        enterpriseNews.setCreateUser(oldEnterpriseNews.getCreateUser());
        enterpriseNews.setCreateTime(oldEnterpriseNews.getCreateTime());
        enterpriseNews.setDeptId(oldEnterpriseNews.getDeptId());
        if (!updateById(enterpriseNews)) {
            throw new ServiceException("修改企业新闻失败");
        }
        clearReadScopeRelations(enterpriseNews.getId());
        saveReadScopeRelations(enterpriseNews.getId(), readScope, deptIds, userIds);
        fileUtil.saveStorageAttachment(ApplicationTypeEnum.FILE, RecordTypeEnum.ENTERPRISE_NEWS, enterpriseNews.getId(), enterpriseNewsDto.getStorageBlobDTOs());
        if (STATUS_PENDING.equals(enterpriseNews.getStatus())) {
            resetEnterpriseNewsApprovalFlow(oldEnterpriseNews);
            startEnterpriseNewsApproval(enterpriseNews, enterpriseNewsDto);
        }
        return true;
    }
    @Override
    public Boolean delete(List<Long> ids) {
        if (ids == null || ids.isEmpty()) {
            return false;
        }
        if (!removeByIds(ids)) {
            throw new ServiceException("删除企业新闻失败");
        }
        ids.forEach(this::clearReadScopeRelations);
        return true;
    }
    private void validateForSave(EnterpriseNewsDto enterpriseNewsDto) {
        if (enterpriseNewsDto == null) {
            throw new ServiceException("企业新闻数据不能为空");
        }
        if (StringUtils.isEmpty(enterpriseNewsDto.getTitle())) {
            throw new ServiceException("标题不能为空");
        }
        if (StringUtils.isEmpty(enterpriseNewsDto.getContent())) {
            throw new ServiceException("正文不能为空");
        }
        normalizeStatus(enterpriseNewsDto.getStatus(), STATUS_DRAFT);
        String readScope = normalizeReadScope(enterpriseNewsDto.getReadScope());
        List<Long> deptIds = distinctIds(enterpriseNewsDto.getDeptIds());
        List<Long> userIds = distinctIds(enterpriseNewsDto.getUserIds());
        if (READ_SCOPE_DEPT.equals(readScope) && StringUtils.isEmpty(deptIds)) {
            throw new ServiceException("请选择阅读范围部门");
        }
        if (READ_SCOPE_CUSTOM.equals(readScope) && StringUtils.isEmpty(userIds)) {
            throw new ServiceException("请选择自定义阅读人员");
        }
        validateDeptIds(deptIds);
        validateUserIds(userIds);
    }
    private String normalizeReadScope(String readScope) {
        String normalized = StringUtils.isEmpty(readScope) ? READ_SCOPE_ALL : readScope.trim();
        if (!READ_SCOPE_ALL.equals(normalized)
                && !READ_SCOPE_DEPT.equals(normalized)
                && !READ_SCOPE_CUSTOM.equals(normalized)) {
            throw new ServiceException("阅读范围不合法");
        }
        return normalized;
    }
    private String normalizeStatus(String status, String defaultStatus) {
        String normalized = StringUtils.isEmpty(status) ? defaultStatus : status.trim().toUpperCase();
        if (!STATUS_DRAFT.equals(normalized)
                && !STATUS_PENDING.equals(normalized)
                && !STATUS_PUBLISHED.equals(normalized)
                && !STATUS_REJECTED.equals(normalized)
                && !STATUS_OFFLINE.equals(normalized)) {
            throw new ServiceException("企业新闻状态不合法");
        }
        return normalized;
    }
    private void validateDeptIds(List<Long> deptIds) {
        if (StringUtils.isEmpty(deptIds)) {
            return;
        }
        for (Long deptId : deptIds) {
            SysDept sysDept = sysDeptMapper.selectDeptById(deptId);
            if (deptId == null || sysDept == null) {
                throw new ServiceException("阅读范围部门不存在");
            }
        }
    }
    private void validateUserIds(List<Long> userIds) {
        if (StringUtils.isEmpty(userIds)) {
            return;
        }
        List<SysUser> users = sysUserMapper.selectUsersByIds(userIds);
        if (users.size() != userIds.size()) {
            throw new ServiceException("自定义阅读人员包含无效用户");
        }
    }
    private Integer calculateRequiredReadCount(String readScope, List<Long> deptIds, List<Long> userIds) {
        if (READ_SCOPE_ALL.equals(readScope)) {
            Long count = sysUserMapper.selectCount(new LambdaQueryWrapper<SysUser>()
                    .eq(SysUser::getDelFlag, "0"));
            return count == null ? 0 : count.intValue();
        }
        if (READ_SCOPE_DEPT.equals(readScope)) {
            List<Long> allDeptIds = collectDeptIdsWithChildren(deptIds);
            if (StringUtils.isEmpty(allDeptIds)) {
                return 0;
            }
            Long count = sysUserDeptMapper.countDistinctUserIdsByDeptIds(allDeptIds);
            return count == null ? 0 : count.intValue();
        }
        return userIds.size();
    }
    private List<Long> collectDeptIdsWithChildren(List<Long> deptIds) {
        Set<Long> allDeptIds = new LinkedHashSet<>();
        for (Long deptId : deptIds) {
            if (deptId == null) {
                continue;
            }
            allDeptIds.add(deptId);
            List<SysDept> children = sysDeptMapper.selectChildrenDeptById(deptId);
            if (StringUtils.isNotEmpty(children)) {
                for (SysDept child : children) {
                    allDeptIds.add(child.getDeptId());
                }
            }
        }
        return new ArrayList<>(allDeptIds);
    }
    private void saveReadScopeRelations(Long newsId, String readScope, List<Long> deptIds, List<Long> userIds) {
        if (READ_SCOPE_DEPT.equals(readScope)) {
            List<EnterpriseNewsScopeDept> scopeDeptList = new ArrayList<>();
            for (Long deptId : deptIds) {
                EnterpriseNewsScopeDept scopeDept = new EnterpriseNewsScopeDept();
                scopeDept.setNewsId(newsId);
                scopeDept.setDeptId(deptId);
                scopeDeptList.add(scopeDept);
            }
            if (StringUtils.isNotEmpty(scopeDeptList)) {
                enterpriseNewsScopeDeptService.saveBatch(scopeDeptList);
            }
            return;
        }
        if (READ_SCOPE_CUSTOM.equals(readScope)) {
            List<EnterpriseNewsScopeUser> scopeUserList = new ArrayList<>();
            for (Long userId : userIds) {
                EnterpriseNewsScopeUser scopeUser = new EnterpriseNewsScopeUser();
                scopeUser.setNewsId(newsId);
                scopeUser.setUserId(userId);
                scopeUserList.add(scopeUser);
            }
            if (StringUtils.isNotEmpty(scopeUserList)) {
                enterpriseNewsScopeUserService.saveBatch(scopeUserList);
            }
        }
    }
    private void clearReadScopeRelations(Long newsId) {
        enterpriseNewsScopeDeptService.remove(new LambdaQueryWrapper<EnterpriseNewsScopeDept>()
                .eq(EnterpriseNewsScopeDept::getNewsId, newsId));
        enterpriseNewsScopeUserService.remove(new LambdaQueryWrapper<EnterpriseNewsScopeUser>()
                .eq(EnterpriseNewsScopeUser::getNewsId, newsId));
    }
    private void resetEnterpriseNewsApprovalFlow(EnterpriseNews oldEnterpriseNews) {
        if (oldEnterpriseNews == null || !STATUS_DRAFT.equals(oldEnterpriseNews.getStatus())) {
            return;
        }
        List<Long> approvalInstanceIds = approvalInstanceMapper.selectList(new LambdaQueryWrapper<ApprovalInstance>()
                        .eq(ApprovalInstance::getBusinessId, oldEnterpriseNews.getId())
                        .eq(ApprovalInstance::getBusinessType, TypeEnums.ENTERPRISE_NEWS_APPROVAL.getCode())
                        .eq(ApprovalInstance::getDeleted, (byte) 0))
                .stream()
                .map(ApprovalInstance::getId)
                .filter(id -> id != null && id > 0)
                .collect(Collectors.toList());
        if (StringUtils.isEmpty(approvalInstanceIds)) {
            return;
        }
        approvalInstanceService.delete(approvalInstanceIds);
    }
    private List<Long> distinctIds(List<Long> ids) {
        if (StringUtils.isEmpty(ids)) {
            return new ArrayList<>();
        }
        Set<Long> distinctSet = new LinkedHashSet<>();
        for (Long id : ids) {
            if (id != null) {
                distinctSet.add(id);
            }
        }
        return new ArrayList<>(distinctSet);
    }
    private void startEnterpriseNewsApproval(EnterpriseNews enterpriseNews, EnterpriseNewsDto enterpriseNewsDto) {
        if (enterpriseNewsDto.getTemplateId() == null) {
            throw new ServiceException("审批模板不能为空");
        }
        String templateName = enterpriseNewsDto.getTemplateName();
        if (StringUtils.isEmpty(templateName)) {
            ApprovalTemplate approvalTemplate = approvalTemplateMapper.selectById(enterpriseNewsDto.getTemplateId());
            if (approvalTemplate == null) {
                throw new ServiceException("审批模板不存在");
            }
            templateName = approvalTemplate.getTemplateName();
        }
        ApprovalInstance approvalInstance = new ApprovalInstance();
        approvalInstance.setInstanceNo(OrderUtils.countTodayByCreateTime(approvalInstanceMapper, "SP", "instance_no", enterpriseNews.getCreateTime() != null ? enterpriseNews.getCreateTime() : LocalDateTime.now()));
        approvalInstance.setTemplateId(enterpriseNewsDto.getTemplateId());
        approvalInstance.setTemplateName(templateName);
        approvalInstance.setBusinessId(enterpriseNews.getId());
        approvalInstance.setBusinessType(TypeEnums.ENTERPRISE_NEWS_APPROVAL.getCode());
        approvalInstance.setTitle(enterpriseNews.getTitle());
        approvalInstance.setStatus("PENDING");
        approvalInstance.setCurrentLevel(1);
        approvalInstance.setApplicantId(SecurityUtils.getUserId());
        approvalInstance.setApplicantName(SecurityUtils.getLoginUser().getNickName());
        approvalInstance.setApplyTime(LocalDateTime.now());
        approvalInstance.setDeleted((byte) 0);
        approvalInstance.setCreateUser(SecurityUtils.getUserId());
        approvalInstance.setUpdateUser(SecurityUtils.getUserId());
        approvalInstance.setDeptId(enterpriseNews.getDeptId());
        approvalInstanceMapper.insert(approvalInstance);
        approveProcessConfigNodeUtils.createCurrentNodeAndTasks(approvalInstance);
        sendApproveNotice(approvalInstance, approveProcessConfigNodeUtils.getCurrentPendingTasks(approvalInstance.getId()));
    }
    private void sendApproveNotice(ApprovalInstance instance, List<ApprovalTask> tasks) {
        if (instance == null || tasks == null || tasks.isEmpty()) {
            return;
        }
        List<Long> approverIds = tasks.stream()
                .map(ApprovalTask::getApproverId)
                .filter(id -> id != null && id > 0)
                .distinct()
                .collect(Collectors.toList());
        if (approverIds.isEmpty()) {
            return;
        }
        String title = StringUtils.isNotEmpty(instance.getTemplateName()) ? instance.getTemplateName() : "审批提醒";
        String message = "审批单号 " + instance.getInstanceNo() + " éœ€è¦æ‚¨å®¡æ‰¹";
        String jumpPath = "/officeProcessAutomation/ApproveManage/approve-list/?id=" + instance.getId();
        sysNoticeService.simpleNoticeByUser(title, message, approverIds, jumpPath);
    }
}