云
2026-09-29 f87ce86307056f63f79312178037cc8714eb2b13
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
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
package cn.iocoder.yudao.module.archive.service.category;
 
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.module.archive.controller.admin.category.vo.ArchiveCategoryListReqVO;
import cn.iocoder.yudao.module.archive.controller.admin.category.vo.ArchiveCategorySaveReqVO;
import cn.iocoder.yudao.module.archive.dal.dataobject.category.ArchiveCategoryDO;
import cn.iocoder.yudao.module.archive.dal.mysql.category.ArchiveCategoryMapper;
import cn.iocoder.yudao.module.archive.dal.mysql.document.ArchiveDocumentMapper;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
 
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;
 
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.archive.enums.ErrorCodeConstants.*;
 
/**
 * 档案分类 Service 实现类
 *
 * @author 超级管理员
 */
@Service
@Validated
public class ArchiveCategoryServiceImpl implements ArchiveCategoryService {
 
    /** 顶级分类的父分类编号 */
    private static final Long ROOT_PARENT_ID = 0L;
 
    @Resource
    private ArchiveCategoryMapper categoryMapper;
 
    @Resource
    private ArchiveDocumentMapper documentMapper;
 
    @Override
    public Long createCategory(ArchiveCategorySaveReqVO createReqVO) {
        // 1.1 校验父分类存在
        validateParentCategory(createReqVO.getParentId(), createReqVO.getName());
        // 1.2 校验同级分类名称不重复、分类编码不重复
        validateNameUnique(createReqVO.getName(), createReqVO.getParentId(), null);
        validateCodeUnique(createReqVO.getCode(), null);
 
        // 2. 插入(补默认值)
        ArchiveCategoryDO category = BeanUtils.toBean(createReqVO, ArchiveCategoryDO.class);
        category.setId(null);
        if (category.getSort() == null) {
            category.setSort(0);
        }
        if (category.getDefaultSecretLevel() == null) {
            category.setDefaultSecretLevel(1);
        }
        if (category.getStatus() == null) {
            category.setStatus(0);
        }
        categoryMapper.insert(category);
        return category.getId();
    }
 
    @Override
    public void updateCategory(ArchiveCategorySaveReqVO updateReqVO) {
        // 1.1 校验分类存在
        ArchiveCategoryDO oldCategory = validateCategoryExists(updateReqVO.getId());
        // 1.2 校验父分类存在,且不能把分类挂到自身或其子孙下(避免形成环)
        validateParentCategory(updateReqVO.getParentId(), updateReqVO.getName());
        validateParentNotSelfOrDescendant(oldCategory, updateReqVO.getParentId());
        // 1.3 校验同级名称不重复、编码不重复
        validateNameUnique(updateReqVO.getName(), updateReqVO.getParentId(), updateReqVO.getId());
        validateCodeUnique(updateReqVO.getCode(), updateReqVO.getId());
 
        // 2. 更新
        ArchiveCategoryDO updateObj = BeanUtils.toBean(updateReqVO, ArchiveCategoryDO.class);
        categoryMapper.updateById(updateObj);
    }
 
    @Override
    public void deleteCategory(Long id) {
        // 1.1 校验分类存在
        ArchiveCategoryDO category = validateCategoryExists(id);
        // 1.2 存在子分类时不允许删除
        List<ArchiveCategoryDO> children = categoryMapper.selectListByParentId(id);
        if (CollUtil.isNotEmpty(children)) {
            throw exception(CATEGORY_HAS_CHILDREN, category.getName(), children.size());
        }
        // 1.3 分类下存在档案时不允许删除
        Long documentCount = documentMapper.selectCountByCategoryId(id);
        if (documentCount != null && documentCount > 0) {
            throw exception(CATEGORY_HAS_DOCUMENT, category.getName(), documentCount);
        }
 
        categoryMapper.deleteById(id);
    }
 
    @Override
    public ArchiveCategoryDO getCategory(Long id) {
        return categoryMapper.selectById(id);
    }
 
    @Override
    public List<ArchiveCategoryDO> getCategoryList(ArchiveCategoryListReqVO reqVO) {
        return categoryMapper.selectList(new LambdaQueryWrapperX<ArchiveCategoryDO>()
                .likeIfPresent(ArchiveCategoryDO::getName, reqVO.getName())
                .eqIfPresent(ArchiveCategoryDO::getStatus, reqVO.getStatus())
                .orderByAsc(ArchiveCategoryDO::getSort)
                .orderByAsc(ArchiveCategoryDO::getId));
    }
 
    @Override
    public List<ArchiveCategoryDO> getCategoryList() {
        return categoryMapper.selectListOrdered();
    }
 
    @Override
    public ArchiveCategoryDO getCategoryByCode(String code) {
        if (StrUtil.isBlank(code)) {
            return null;
        }
        return categoryMapper.selectByCode(code);
    }
 
    // ==================== 校验逻辑 ====================
 
    /** 校验分类存在,不存在时抛出精确提示 */
    private ArchiveCategoryDO validateCategoryExists(Long id) {
        ArchiveCategoryDO category = id != null ? categoryMapper.selectById(id) : null;
        if (category == null) {
            throw exception(CATEGORY_NOT_EXISTS);
        }
        return category;
    }
 
    /** 校验父分类:0 表示顶级;非 0 时必须存在 */
    private void validateParentCategory(Long parentId, String categoryName) {
        if (parentId == null) {
            throw exception(CATEGORY_PARENT_INVALID, categoryName);
        }
        if (Objects.equals(parentId, ROOT_PARENT_ID)) {
            return;
        }
        if (categoryMapper.selectById(parentId) == null) {
            throw exception(CATEGORY_PARENT_INVALID, categoryName);
        }
    }
 
    /** 校验父分类不能是自身,也不能是自己的子孙分类 */
    private void validateParentNotSelfOrDescendant(ArchiveCategoryDO category, Long parentId) {
        if (Objects.equals(category.getId(), parentId)) {
            throw exception(CATEGORY_PARENT_INVALID, category.getName());
        }
        Set<Long> descendantIds = collectDescendantIds(category.getId());
        if (descendantIds.contains(parentId)) {
            throw exception(CATEGORY_PARENT_INVALID, category.getName());
        }
    }
 
    /** 收集分类的全部子孙分类编号(含自身) */
    private Set<Long> collectDescendantIds(Long id) {
        List<ArchiveCategoryDO> all = categoryMapper.selectListOrdered();
        Set<Long> result = new HashSet<>();
        result.add(id);
        boolean changed = true;
        while (changed) {
            changed = false;
            for (ArchiveCategoryDO category : all) {
                if (result.contains(category.getParentId()) && result.add(category.getId())) {
                    changed = true;
                }
            }
        }
        return result;
    }
 
    private void validateNameUnique(String name, Long parentId, Long excludeId) {
        Long count = categoryMapper.selectCountByName(name, parentId, excludeId);
        if (count != null && count > 0) {
            throw exception(CATEGORY_NAME_DUPLICATE, name);
        }
    }
 
    private void validateCodeUnique(String code, Long excludeId) {
        Long count = categoryMapper.selectCountByCode(code, excludeId);
        if (count != null && count > 0) {
            ArchiveCategoryDO exists = categoryMapper.selectByCode(code);
            throw exception(CATEGORY_CODE_DUPLICATE, code, exists != null ? exists.getName() : code);
        }
    }
 
}