增加部门

This commit is contained in:
戚辰先生 2024-12-01 14:37:03 +08:00
parent 9c949fe5c7
commit 9975d4508e
12 changed files with 285 additions and 127 deletions

View File

@ -0,0 +1,36 @@
package com.qqchen.deploy.backend.api;
import com.qqchen.deploy.backend.entity.Department;
import com.qqchen.deploy.backend.framework.api.Response;
import com.qqchen.deploy.backend.framework.controller.BaseController;
import com.qqchen.deploy.backend.model.DepartmentDTO;
import com.qqchen.deploy.backend.model.query.DepartmentQuery;
import com.qqchen.deploy.backend.service.IDepartmentService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@Tag(name = "部门管理")
@RestController
@RequestMapping("/api/v1/department")
public class DepartmentApiController extends BaseController<Department, DepartmentDTO, Long, DepartmentQuery> {
@Resource
private IDepartmentService departmentService;
@Operation(summary = "获取部门树")
@GetMapping("/tree")
public Response<List<DepartmentDTO>> getTree() {
return Response.success(departmentService.getTree());
}
@Override
protected void exportData(jakarta.servlet.http.HttpServletResponse response, List<DepartmentDTO> data) {
// TODO: 实现导出功能
}
}

View File

@ -0,0 +1,12 @@
package com.qqchen.deploy.backend.converter;
import com.qqchen.deploy.backend.entity.Department;
import com.qqchen.deploy.backend.framework.converter.BaseConverter;
import com.qqchen.deploy.backend.model.DepartmentDTO;
import org.mapstruct.Mapper;
import org.mapstruct.ReportingPolicy;
@Mapper(componentModel = "spring", unmappedTargetPolicy = ReportingPolicy.IGNORE)
public interface DepartmentConverter extends BaseConverter<Department, DepartmentDTO> {
// 继承了 BaseConverter 的方法不需要再声明
}

View File

@ -49,7 +49,14 @@ public enum ResponseCode {
// 角色标签相关错误码 (4300-4399)
ROLE_TAG_NAME_EXISTS(4300, "role.tag.name.exists"),
ROLE_TAG_NOT_FOUND(4301, "role.tag.not.found"),
ROLE_TAG_IN_USE(4302, "role.tag.in.use");
ROLE_TAG_IN_USE(4302, "role.tag.in.use"),
// 部门相关错误码 (2300-2399)
DEPARTMENT_NOT_FOUND(2300, "department.not.found"),
DEPARTMENT_CODE_EXISTS(2301, "department.code.exists"),
DEPARTMENT_NAME_EXISTS(2302, "department.name.exists"),
DEPARTMENT_PARENT_NOT_FOUND(2303, "department.parent.not.found"),
DEPARTMENT_HAS_CHILDREN(2304, "department.has.children");
private final int code;
private final String messageKey; // 国际化消息key

View File

@ -0,0 +1,30 @@
package com.qqchen.deploy.backend.model;
import com.qqchen.deploy.backend.framework.dto.BaseDTO;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.util.List;
@Data
@EqualsAndHashCode(callSuper = true)
public class DepartmentDTO extends BaseDTO {
private String code;
private String name;
private String description;
private Boolean enabled;
private Long leaderId;
private String leaderName;
private Long parentId;
private Integer sort;
private List<DepartmentDTO> children;
}

View File

@ -0,0 +1,40 @@
package com.qqchen.deploy.backend.model.query;
import com.qqchen.deploy.backend.framework.query.BaseQuery;
import lombok.Data;
import lombok.EqualsAndHashCode;
@Data
@EqualsAndHashCode(callSuper = true)
public class DepartmentQuery extends BaseQuery {
/**
* 部门编码
*/
private String code;
/**
* 部门名称
*/
private String name;
/**
* 上级部门ID
*/
private Long parentId;
/**
* 是否启用
*/
private Boolean enabled;
/**
* 部门负责人ID
*/
private Long leaderId;
/**
* 部门负责人姓名
*/
private String leaderName;
}

View File

@ -1,18 +1,15 @@
//package com.qqchen.deploy.backend.service;
//
//
//import com.qqchen.deploy.backend.framework.service.IBaseService;
//import com.qqchen.deploy.backend.entity.Department;
//
//import java.util.List;
//
//public interface IDepartmentService extends IBaseService<Department, Long> {
//
// List<Department> getTree();
//
// void validateCode(String code);
//
// void validateName(String name);
//
// Integer getNextSort(Long parentId);
//}
package com.qqchen.deploy.backend.service;
import com.qqchen.deploy.backend.entity.Department;
import com.qqchen.deploy.backend.framework.service.IBaseService;
import com.qqchen.deploy.backend.model.DepartmentDTO;
import java.util.List;
public interface IDepartmentService extends IBaseService<Department, DepartmentDTO, Long> {
/**
* 获取部门树
*/
List<DepartmentDTO> getTree();
}

View File

@ -1,105 +1,76 @@
//package com.qqchen.deploy.backend.service.impl;
//
//import com.qqchen.deploy.backend.framework.service.impl.BaseServiceImpl;
//import com.qqchen.deploy.backend.entity.Department;
//import com.qqchen.deploy.backend.repository.IDepartmentRepository;
//import com.qqchen.deploy.backend.service.IDepartmentService;
//import org.springframework.beans.factory.annotation.Autowired;
//import org.springframework.stereotype.Service;
//import jakarta.transaction.Transactional;
//import java.util.ArrayList;
//import java.util.List;
//import java.util.Map;
//import java.util.stream.Collectors;
//
//@Service
//@Transactional
//public class DepartmentServiceImpl extends BaseServiceImpl<Department, Long> implements IDepartmentService {
//
// private final IDepartmentRepository repository;
//
// @Autowired
// public DepartmentServiceImpl(IDepartmentRepository repository) {
// super(repository);
// this.repository = repository;
// }
//
// @Override
// public Department create(Department entity) {
// validateCode(entity.getCode());
// validateName(entity.getName());
// return repository.save(entity);
// }
//
// public Department update(Long id, Department entity) {
// Department existing = repository.findById(id)
// .orElseThrow(() -> new RuntimeException("部门不存在"));
//
// entity.setVersion(existing.getVersion());
// entity.setId(id);
//
// if (!existing.getCode().equals(entity.getCode())) {
// if (repository.existsByCodeAndDeletedFalse(entity.getCode())) {
// throw new RuntimeException("部门编码已存在");
// }
// }
//
// if (!existing.getName().equals(entity.getName())) {
// if (repository.existsByNameAndDeletedFalse(entity.getName())) {
// throw new RuntimeException("部门名称已存在");
// }
// }
//
// entity.setCreateTime(existing.getCreateTime());
// entity.setCreateBy(existing.getCreateBy());
// entity.setDeleted(existing.getDeleted());
//
// return repository.save(entity);
// }
//
// @Override
// public List<Department> getTree() {
// List<Department> departments = repository.findByDeletedFalseOrderBySort();
// return buildTree(departments);
// }
//
// @Override
// public void validateCode(String code) {
// if (repository.existsByCodeAndDeletedFalse(code)) {
// throw new RuntimeException("部门编码已存在");
// }
// }
//
// @Override
// public void validateName(String name) {
// if (repository.existsByNameAndDeletedFalse(name)) {
// throw new RuntimeException("部门名称已存在");
// }
// }
//
// @Override
// public Integer getNextSort(Long parentId) {
// return repository.findMaxSortByParentId(parentId) + 1;
// }
//
// private List<Department> buildTree(List<Department> departments) {
// Map<Long, List<Department>> parentIdMap = departments.stream()
// .collect(Collectors.groupingBy(d -> d.getParentId() == null ? 0L : d.getParentId()));
//
// return buildTreeNodes(0L, parentIdMap);
// }
//
// private List<Department> buildTreeNodes(Long parentId, Map<Long, List<Department>> parentIdMap) {
// List<Department> nodes = new ArrayList<>();
//
// List<Department> children = parentIdMap.get(parentId);
// if (children != null) {
// for (Department child : children) {
//// child.setChildren(buildTreeNodes(child.getId(), parentIdMap));
//// nodes.add(child);
// }
// }
//
// return nodes;
// }
//}
package com.qqchen.deploy.backend.service.impl;
import com.qqchen.deploy.backend.converter.DepartmentConverter;
import com.qqchen.deploy.backend.entity.Department;
import com.qqchen.deploy.backend.framework.enums.ResponseCode;
import com.qqchen.deploy.backend.framework.exception.UniqueConstraintException;
import com.qqchen.deploy.backend.framework.service.impl.BaseServiceImpl;
import com.qqchen.deploy.backend.model.DepartmentDTO;
import com.qqchen.deploy.backend.repository.IDepartmentRepository;
import com.qqchen.deploy.backend.service.IDepartmentService;
import com.qqchen.deploy.backend.framework.annotation.ServiceType;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import jakarta.annotation.Resource;
import java.util.*;
import static com.qqchen.deploy.backend.framework.annotation.ServiceType.Type.DATABASE;
@Slf4j
@Service
@ServiceType(DATABASE)
public class DepartmentServiceImpl extends BaseServiceImpl<Department, DepartmentDTO, Long> implements IDepartmentService {
@Resource
private IDepartmentRepository departmentRepository;
@Resource
private DepartmentConverter departmentConverter;
@Override
protected void validateUniqueConstraints(DepartmentDTO dto) {
// 检查部门编码唯一性
if (departmentRepository.existsByCodeAndDeletedFalse(dto.getCode())) {
throw new UniqueConstraintException(ResponseCode.DEPARTMENT_CODE_EXISTS, "code", dto.getCode());
}
// 检查部门名称唯一性
if (departmentRepository.existsByNameAndDeletedFalse(dto.getName())) {
throw new UniqueConstraintException(ResponseCode.DEPARTMENT_NAME_EXISTS, "name", dto.getName());
}
}
@Override
public List<DepartmentDTO> getTree() {
List<Department> departments = departmentRepository.findByDeletedFalseOrderBySort();
return buildTree(departments);
}
private List<DepartmentDTO> buildTree(List<Department> departments) {
Map<Long, DepartmentDTO> dtoMap = new HashMap<>();
List<DepartmentDTO> roots = new ArrayList<>();
// 转换为DTO并建立映射
departments.forEach(dept -> {
DepartmentDTO dto = departmentConverter.toDto(dept);
dto.setChildren(new ArrayList<>());
dtoMap.put(dto.getId(), dto);
});
// 构建树形结构
departments.forEach(dept -> {
DepartmentDTO dto = dtoMap.get(dept.getId());
if (dept.getParentId() == null || dept.getParentId() == 0) {
roots.add(dto);
} else {
DepartmentDTO parent = dtoMap.get(dept.getParentId());
if (parent != null) {
parent.getChildren().add(dto);
}
}
});
return roots;
}
}

View File

@ -175,3 +175,23 @@ CREATE TABLE sys_template_menu (
CONSTRAINT FK_template_menu_menu FOREIGN KEY (menu_id) REFERENCES sys_menu (id)
) COMMENT '模板菜单关联表';
-- 创建部门表
CREATE TABLE sys_department (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
create_by VARCHAR(255) NULL,
create_time DATETIME(6) NULL,
deleted BIT NOT NULL DEFAULT 0,
update_by VARCHAR(255) NULL,
update_time DATETIME(6) NULL,
version INT NOT NULL DEFAULT 0,
code VARCHAR(255) NOT NULL,
description VARCHAR(255) NULL,
enabled BIT NOT NULL DEFAULT 1,
leader_id BIGINT NULL,
leader_name VARCHAR(255) NULL,
name VARCHAR(255) NOT NULL,
parent_id BIGINT NULL,
sort INT NOT NULL DEFAULT 0,
CONSTRAINT UK_mho5hjhq35wmm63mswah975ic UNIQUE (code)
);

View File

@ -96,3 +96,28 @@ VALUES
(1, 3), -- 超级管理员 -> 安全标签
(2, 1), -- 开发主管 -> 研发标签
(3, 2); -- 运维主管 -> 运维标签
-- 初始化部门数据
INSERT INTO sys_department (id, create_time, update_time, deleted, version, code, name, description, parent_id, sort, enabled, leader_id, leader_name)
VALUES
-- 总公司
(1, NOW(), NOW(), false, 1, 'HQ', '总公司', '公司总部', null, 1, true, null, null),
-- 一级部门
(2, NOW(), NOW(), false, 1, 'TECH', '技术部', '负责公司技术研发', 1, 1, true, null, null),
(3, NOW(), NOW(), false, 1, 'HR', '人力资源部', '负责人力资源管理', 1, 2, true, null, null),
(4, NOW(), NOW(), false, 1, 'FIN', '财务部', '负责公司财务管理', 1, 3, true, null, null),
(5, NOW(), NOW(), false, 1, 'MKT', '市场部', '负责市场营销', 1, 4, true, null, null),
-- 技术部下属部门
(6, NOW(), NOW(), false, 1, 'DEV', '研发部', '负责产品研发', 2, 1, true, null, null),
(7, NOW(), NOW(), false, 1, 'TEST', '测试部', '负责产品测试', 2, 2, true, null, null),
(8, NOW(), NOW(), false, 1, 'OPS', '运维部', '负责系统运维', 2, 3, true, null, null),
-- 人力资源部下属部门
(9, NOW(), NOW(), false, 1, 'REC', '招聘部', '负责人员招聘', 3, 1, true, null, null),
(10, NOW(), NOW(), false, 1, 'TRAIN', '培训部', '负责员工培训', 3, 2, true, null, null),
-- 市场部下属部门
(11, NOW(), NOW(), false, 1, 'SALES', '销售部', '负责产品销售', 5, 1, true, null, null),
(12, NOW(), NOW(), false, 1, 'PR', '公关部', '负责公共关系', 5, 2, true, null, null);

View File

@ -50,3 +50,10 @@ role.admin.cannot.update=\u4E0D\u80FD\u4FEE\u6539\u8D85\u7EA7\u7BA1\u7406\u5458\
role.tag.name.exists=\u6807\u7B7E\u540D\u79F0\u5DF2\u5B58\u5728
role.tag.not.found=\u6807\u7B7E\u4E0D\u5B58\u5728
role.tag.in.use=\u6807\u7B7E\u6B63\u5728\u4F7F\u7528\u4E2D\uFF0C\u65E0\u6CD5\u5220\u9664
# 部门相关
department.not.found=部门不存在
department.code.exists=部门编码已存在
department.name.exists=部门名称已存在
department.parent.not.found=上级部门不存在
department.has.children=该部门下有子部门,无法删除

View File

@ -0,0 +1,6 @@
# Department
department.not.found=Department not found
department.code.exists=Department code already exists
department.name.exists=Department name already exists
department.parent.not.found=Parent department not found
department.has.children=Cannot delete department with children

View File

@ -45,3 +45,10 @@ role.admin.cannot.update=\u4E0D\u80FD\u4FEE\u6539\u8D85\u7EA7\u7BA1\u7406\u5458\
role.tag.name.exists=\u6807\u7B7E\u540D\u79F0\u5DF2\u5B58\u5728
role.tag.not.found=\u6807\u7B7E\u4E0D\u5B58\u5728
role.tag.in.use=\u6807\u7B7E\u6B63\u5728\u4F7F\u7528\u4E2D\uFF0C\u65E0\u6CD5\u5220\u9664
# 部门相关
department.not.found=部门不存在
department.code.exists=部门编码已存在
department.name.exists=部门名称已存在
department.parent.not.found=上级部门不存在
department.has.children=该部门下有子部门,无法删除