1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
package cn.iocoder.yudao.module.mes.service.safety;
 
import cn.hutool.core.collection.CollUtil;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.module.mes.controller.admin.safety.vo.org.SafetyOrgRespVO;
import cn.iocoder.yudao.module.mes.controller.admin.safety.vo.org.SafetyOrgSaveReqVO;
import cn.iocoder.yudao.module.mes.dal.dataobject.safety.SafetyOrgDO;
import cn.iocoder.yudao.module.mes.dal.mysql.safety.SafetyOrgMapper;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
 
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
 
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.mes.enums.SafetyErrorCodeConstants.*;
 
/**
 * 安全生产 - 安全组织架构 Service
 *
 * @author 超级管理员
 */
@Service
@Validated
public class SafetyOrgService {
 
    @Resource
    private SafetyOrgMapper safetyOrgMapper;
    @Resource
    private SafetyRefResolver refResolver;
 
    public Long createOrg(SafetyOrgSaveReqVO reqVO) {
        reqVO.setId(null);
        validateParent(reqVO.getParentId(), null);
        SafetyOrgDO org = BeanUtils.toBean(reqVO, SafetyOrgDO.class);
        org.setParentId(reqVO.getParentId() == null ? 0L : reqVO.getParentId());
        applyLeader(org, reqVO.getLeaderId());
        safetyOrgMapper.insert(org);
        return org.getId();
    }
 
    public void updateOrg(SafetyOrgSaveReqVO reqVO) {
        validateOrgExists(reqVO.getId());
        validateParent(reqVO.getParentId(), reqVO.getId());
        SafetyOrgDO org = BeanUtils.toBean(reqVO, SafetyOrgDO.class);
        org.setParentId(reqVO.getParentId() == null ? 0L : reqVO.getParentId());
        applyLeader(org, reqVO.getLeaderId());
        safetyOrgMapper.updateById(org);
    }
 
    /**
     * 负责人:从员工档案带出姓名与电话并落快照
     */
    private void applyLeader(SafetyOrgDO org, Long leaderId) {
        org.setLeaderId(leaderId);
        if (leaderId == null) {
            org.setLeaderName("");
            return;
        }
        var employee = refResolver.requireEmployee(leaderId, SAFETY_EMPLOYEE_REQUIRED);
        org.setLeaderName(employee.getName());
        org.setLeaderPhone(employee.getPhone());
    }
 
    public void deleteOrg(Long id) {
        validateOrgExists(id);
        if (safetyOrgMapper.selectCountByParentId(id) > 0) {
            throw exception(SAFETY_ORG_HAS_CHILDREN);
        }
        safetyOrgMapper.deleteById(id);
    }
 
    public SafetyOrgDO getOrg(Long id) {
        return validateOrgExists(id);
    }
 
    /**
     * 取负责人最新档案(供单条查询回填用)
     */
    public cn.iocoder.yudao.module.hrm.api.employee.dto.HrmEmployeeSimpleDTO getLeader(Long leaderId) {
        return refResolver.findEmployee(leaderId);
    }
 
    /**
     * 查询组织树
     */
    public List<SafetyOrgRespVO> getOrgTree() {
        List<SafetyOrgDO> all = safetyOrgMapper.selectListOrdered();
        List<SafetyOrgRespVO> nodes = BeanUtils.toBean(all, SafetyOrgRespVO.class);
        // 负责人用员工档案最新姓名覆盖快照,员工改名/调岗后树也同步
        var employeeMap = refResolver.employeeMap(
                all.stream().map(SafetyOrgDO::getLeaderId).toList());
        nodes.forEach(node -> {
            var employee = employeeMap.get(node.getLeaderId());
            if (employee != null) {
                node.setLeaderName(employee.getName());
            }
        });
        Map<Long, List<SafetyOrgRespVO>> grouped = nodes.stream()
                .collect(Collectors.groupingBy(SafetyOrgRespVO::getParentId, Collectors.toList()));
        nodes.forEach(node -> node.setChildren(grouped.getOrDefault(node.getId(), new ArrayList<>())));
        List<SafetyOrgRespVO> roots = grouped.getOrDefault(0L, new ArrayList<>());
        if (CollUtil.isEmpty(roots)) {
            // 兼容 parentId 为空的脏数据
            roots = nodes.stream().filter(n -> n.getParentId() == null || n.getParentId() == 0L).toList();
        }
        return roots;
    }
 
    private void validateParent(Long parentId, Long selfId) {
        if (parentId == null || parentId == 0L) {
            return;
        }
        if (parentId.equals(selfId)) {
            throw exception(SAFETY_ORG_PARENT_IS_SELF);
        }
        SafetyOrgDO parent = safetyOrgMapper.selectById(parentId);
        if (parent == null) {
            throw exception(SAFETY_ORG_PARENT_NOT_EXISTS);
        }
        // 防止把父节点挂到自己的子孙下,形成环
        if (selfId != null && isDescendant(parentId, selfId)) {
            throw exception(SAFETY_ORG_PARENT_IS_CHILD);
        }
    }
 
    private boolean isDescendant(Long candidateId, Long ancestorId) {
        Long current = candidateId;
        int guard = 0;
        while (current != null && current != 0L && guard++ < 100) {
            if (current.equals(ancestorId)) {
                return true;
            }
            SafetyOrgDO node = safetyOrgMapper.selectById(current);
            if (node == null) {
                return false;
            }
            current = node.getParentId();
        }
        return false;
    }
 
    private SafetyOrgDO validateOrgExists(Long id) {
        if (id == null) {
            throw exception(SAFETY_ORG_NOT_EXISTS);
        }
        SafetyOrgDO org = safetyOrgMapper.selectById(id);
        if (org == null) {
            throw exception(SAFETY_ORG_NOT_EXISTS);
        }
        return org;
    }
 
}