From 620bb4712a31791231c4381581f0f60088f079fe Mon Sep 17 00:00:00 2001
From: 云 <2163098428@qq.com>
Date: 星期三, 27 五月 2026 14:03:45 +0800
Subject: [PATCH] Merge branch 'refs/heads/dev_New_pro' into dev_宁夏_英泽防锈

---
 src/main/java/com/ruoyi/collaborativeApproval/service/impl/EnterpriseNewsServiceImpl.java |  409 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 409 insertions(+), 0 deletions(-)

diff --git a/src/main/java/com/ruoyi/collaborativeApproval/service/impl/EnterpriseNewsServiceImpl.java b/src/main/java/com/ruoyi/collaborativeApproval/service/impl/EnterpriseNewsServiceImpl.java
new file mode 100644
index 0000000..4a4d9c1
--- /dev/null
+++ b/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("姝f枃涓嶈兘涓虹┖");
+        }
+
+        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);
+    }
+}

--
Gitblit v1.9.3