diff --git a/backend/src/main/java/com/qqchen/deploy/backend/api/DepartmentApiController.java b/backend/src/main/java/com/qqchen/deploy/backend/api/DepartmentApiController.java index a8fead50..a17cca82 100644 --- a/backend/src/main/java/com/qqchen/deploy/backend/api/DepartmentApiController.java +++ b/backend/src/main/java/com/qqchen/deploy/backend/api/DepartmentApiController.java @@ -10,8 +10,12 @@ 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 jakarta.servlet.http.HttpServletResponse; import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PutMapping; import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import java.util.List; @@ -27,11 +31,11 @@ public class DepartmentApiController extends BaseController> getTree() { - return Response.success(departmentService.getTree()); + return Response.success(((IDepartmentService) service).getTree()); } @Override - protected void exportData(jakarta.servlet.http.HttpServletResponse response, List data) { + protected void exportData(HttpServletResponse response, List data) { // TODO: 实现导出功能 } } \ No newline at end of file diff --git a/backend/src/main/java/com/qqchen/deploy/backend/api/RoleApiController.java b/backend/src/main/java/com/qqchen/deploy/backend/api/RoleApiController.java index f161cccc..e9233f58 100644 --- a/backend/src/main/java/com/qqchen/deploy/backend/api/RoleApiController.java +++ b/backend/src/main/java/com/qqchen/deploy/backend/api/RoleApiController.java @@ -3,6 +3,7 @@ package com.qqchen.deploy.backend.api; import com.qqchen.deploy.backend.entity.Role; import com.qqchen.deploy.backend.framework.api.Response; import com.qqchen.deploy.backend.framework.controller.BaseController; +import com.qqchen.deploy.backend.model.PermissionDTO; import com.qqchen.deploy.backend.model.RoleDTO; import com.qqchen.deploy.backend.model.query.RoleQuery; import com.qqchen.deploy.backend.service.IRoleService; @@ -10,11 +11,7 @@ import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.annotation.Resource; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.*; import java.util.List; @@ -33,7 +30,6 @@ public class RoleApiController extends BaseController assignRoles( @@ -44,6 +40,24 @@ public class RoleApiController extends BaseController> getRolePermissions( + @Parameter(description = "角色ID", required = true) @PathVariable Long id + ) { + return Response.success(roleService.listRolePermissions(id)); + } + + @Operation(summary = "分配权限") + @PostMapping("/{id}/permissions") + public Response assignPermissions( + @Parameter(description = "角色ID", required = true) @PathVariable Long id, + @Parameter(description = "权限ID列表", required = true) @RequestBody List permissionIds + ) { + roleService.assignPermissions(id, permissionIds); + return Response.success(); + } + @Override protected void exportData(jakarta.servlet.http.HttpServletResponse response, List data) { // TODO: 实现导出功能 diff --git a/backend/src/main/java/com/qqchen/deploy/backend/api/UserApiController.java b/backend/src/main/java/com/qqchen/deploy/backend/api/UserApiController.java index bdaafaff..72ca98b7 100644 --- a/backend/src/main/java/com/qqchen/deploy/backend/api/UserApiController.java +++ b/backend/src/main/java/com/qqchen/deploy/backend/api/UserApiController.java @@ -2,6 +2,7 @@ package com.qqchen.deploy.backend.api; import com.qqchen.deploy.backend.model.RoleDTO; import com.qqchen.deploy.backend.model.query.UserQuery; +import com.qqchen.deploy.backend.model.request.DepartmentAssignRequest; import com.qqchen.deploy.backend.model.request.UserRequest; import com.qqchen.deploy.backend.framework.controller.BaseController; import com.qqchen.deploy.backend.framework.api.Response; @@ -47,6 +48,16 @@ public class UserApiController extends BaseController assignDepartment( + @PathVariable Long id, // 用户ID + @RequestBody DepartmentAssignRequest request + ) { + userService.assignDepartment(id, request.getDepartmentId()); + return Response.success(); + } + @Override protected void exportData(HttpServletResponse response, List data) { response.setContentType("application/vnd.ms-excel"); diff --git a/backend/src/main/java/com/qqchen/deploy/backend/converter/PermissionConverter.java b/backend/src/main/java/com/qqchen/deploy/backend/converter/PermissionConverter.java new file mode 100644 index 00000000..5c5d0ee7 --- /dev/null +++ b/backend/src/main/java/com/qqchen/deploy/backend/converter/PermissionConverter.java @@ -0,0 +1,10 @@ +package com.qqchen.deploy.backend.converter; + +import com.qqchen.deploy.backend.entity.Permission; +import com.qqchen.deploy.backend.framework.converter.BaseConverter; +import com.qqchen.deploy.backend.model.PermissionDTO; +import org.mapstruct.Mapper; + +@Mapper(config = BaseConverter.class) +public interface PermissionConverter extends BaseConverter { +} \ No newline at end of file diff --git a/backend/src/main/java/com/qqchen/deploy/backend/converter/UserConverter.java b/backend/src/main/java/com/qqchen/deploy/backend/converter/UserConverter.java index ef737b9f..d6d5fef2 100644 --- a/backend/src/main/java/com/qqchen/deploy/backend/converter/UserConverter.java +++ b/backend/src/main/java/com/qqchen/deploy/backend/converter/UserConverter.java @@ -15,10 +15,14 @@ public interface UserConverter extends BaseConverter { @Mapping(target = "token", ignore = true) @Mapping(target = "id", ignore = true) + @Mapping(target = "departmentId", source = "department.id") + @Mapping(target = "departmentName", source = "department.name") LoginResponse toLoginResponse(User user); @Mapping(target = "token", source = "token") @Mapping(target = "id", ignore = true) + @Mapping(target = "departmentId", source = "user.department.id") + @Mapping(target = "departmentName", source = "user.department.name") LoginResponse toLoginResponse(User user, String token); @Mapping(target = "token", ignore = true) @@ -35,8 +39,13 @@ public interface UserConverter extends BaseConverter { @Mapping(target = "updateTime", ignore = true), @Mapping(target = "updateBy", ignore = true), @Mapping(target = "version", ignore = true), - @Mapping(target = "deleted", ignore = true) + @Mapping(target = "deleted", ignore = true), + @Mapping(target = "department", ignore = true) }) void updateEntity(@MappingTarget User entity, UserDTO dto); + @Override + @Mapping(target = "departmentId", source = "department.id") + @Mapping(target = "departmentName", source = "department.name") + UserDTO toDto(User entity); } \ No newline at end of file diff --git a/backend/src/main/java/com/qqchen/deploy/backend/entity/Department.java b/backend/src/main/java/com/qqchen/deploy/backend/entity/Department.java index f913ea7b..4d69b954 100644 --- a/backend/src/main/java/com/qqchen/deploy/backend/entity/Department.java +++ b/backend/src/main/java/com/qqchen/deploy/backend/entity/Department.java @@ -3,10 +3,14 @@ package com.qqchen.deploy.backend.entity; import com.qqchen.deploy.backend.framework.annotation.LogicDelete; import com.qqchen.deploy.backend.framework.domain.Entity; import jakarta.persistence.Column; +import jakarta.persistence.FetchType; import jakarta.persistence.Table; import jakarta.validation.constraints.NotBlank; import lombok.Data; import lombok.EqualsAndHashCode; +import jakarta.persistence.OneToMany; +import java.util.HashSet; +import java.util.Set; @Data @EqualsAndHashCode(callSuper = true) @@ -40,4 +44,7 @@ public class Department extends Entity { @Column(name = "leader_name") private String leaderName; + @OneToMany(mappedBy = "department", fetch = FetchType.LAZY) + private Set users = new HashSet<>(); + } \ No newline at end of file diff --git a/backend/src/main/java/com/qqchen/deploy/backend/entity/Permission.java b/backend/src/main/java/com/qqchen/deploy/backend/entity/Permission.java new file mode 100644 index 00000000..7db45a9f --- /dev/null +++ b/backend/src/main/java/com/qqchen/deploy/backend/entity/Permission.java @@ -0,0 +1,42 @@ +package com.qqchen.deploy.backend.entity; + +import com.qqchen.deploy.backend.framework.annotation.LogicDelete; +import com.qqchen.deploy.backend.framework.domain.Entity; +import jakarta.persistence.*; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.util.HashSet; +import java.util.Set; + +@Data +@EqualsAndHashCode(callSuper = true) +@jakarta.persistence.Entity +@Table(name = "sys_permission") +@LogicDelete +public class Permission extends Entity { + + @Column(name = "menu_id") + private Long menuId; + + @Column(nullable = false, unique = true, length = 100) + private String code; + + @Column(nullable = false, length = 50) + private String name; + + @Column(nullable = false, length = 20) + private String type; + + @Column(nullable = false) + private Boolean enabled = true; + + @Column(nullable = false) + private Integer sort = 0; + + @Column(length = 200) + private String description; + + @ManyToMany(mappedBy = "permissions") + private Set roles = new HashSet<>(); +} \ No newline at end of file diff --git a/backend/src/main/java/com/qqchen/deploy/backend/entity/Role.java b/backend/src/main/java/com/qqchen/deploy/backend/entity/Role.java index 5868efea..6c5cc811 100644 --- a/backend/src/main/java/com/qqchen/deploy/backend/entity/Role.java +++ b/backend/src/main/java/com/qqchen/deploy/backend/entity/Role.java @@ -47,4 +47,12 @@ public class Role extends Entity { inverseJoinColumns = @JoinColumn(name = "tag_id") ) private Set tags = new HashSet<>(); + + @ManyToMany(fetch = FetchType.LAZY) + @JoinTable( + name = "sys_role_permission", + joinColumns = @JoinColumn(name = "role_id"), + inverseJoinColumns = @JoinColumn(name = "permission_id") + ) + private Set permissions; } \ No newline at end of file diff --git a/backend/src/main/java/com/qqchen/deploy/backend/entity/User.java b/backend/src/main/java/com/qqchen/deploy/backend/entity/User.java index 142e39ef..76a78f9f 100644 --- a/backend/src/main/java/com/qqchen/deploy/backend/entity/User.java +++ b/backend/src/main/java/com/qqchen/deploy/backend/entity/User.java @@ -12,6 +12,7 @@ import jakarta.persistence.JoinTable; import jakarta.persistence.JoinColumn; import java.util.HashSet; import java.util.Set; +import jakarta.persistence.ManyToOne; @Data @EqualsAndHashCode(callSuper = true) @@ -44,4 +45,7 @@ public class User extends Entity { ) private Set roles = new HashSet<>(); + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "department_id") + private Department department; } \ No newline at end of file diff --git a/backend/src/main/java/com/qqchen/deploy/backend/framework/enums/ResponseCode.java b/backend/src/main/java/com/qqchen/deploy/backend/framework/enums/ResponseCode.java index c52ca6c7..08c0afb4 100644 --- a/backend/src/main/java/com/qqchen/deploy/backend/framework/enums/ResponseCode.java +++ b/backend/src/main/java/com/qqchen/deploy/backend/framework/enums/ResponseCode.java @@ -56,7 +56,14 @@ public enum ResponseCode { 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"); + DEPARTMENT_HAS_CHILDREN(2304, "department.has.children"), + + // 权限相关错误码 (2400-2499) + PERMISSION_NOT_FOUND(2400, "permission.not.found"), + PERMISSION_CODE_EXISTS(2401, "permission.code.exists"), + PERMISSION_NAME_EXISTS(2402, "permission.name.exists"), + PERMISSION_ALREADY_ASSIGNED(2403, "permission.already.assigned"), + PERMISSION_ASSIGN_FAILED(2404, "permission.assign.failed"); private final int code; private final String messageKey; // 国际化消息key diff --git a/backend/src/main/java/com/qqchen/deploy/backend/model/PermissionDTO.java b/backend/src/main/java/com/qqchen/deploy/backend/model/PermissionDTO.java new file mode 100644 index 00000000..6d68b941 --- /dev/null +++ b/backend/src/main/java/com/qqchen/deploy/backend/model/PermissionDTO.java @@ -0,0 +1,22 @@ +package com.qqchen.deploy.backend.model; + +import com.qqchen.deploy.backend.framework.dto.BaseDTO; +import lombok.Data; + +@Data +public class PermissionDTO extends BaseDTO { + + private Long menuId; + + private String code; + + private String name; + + private String type; + + private Boolean enabled; + + private Integer sort; + + private String menuName; // 关联的菜单名称 +} \ No newline at end of file diff --git a/backend/src/main/java/com/qqchen/deploy/backend/model/UserDTO.java b/backend/src/main/java/com/qqchen/deploy/backend/model/UserDTO.java index 025e7b27..863200ff 100644 --- a/backend/src/main/java/com/qqchen/deploy/backend/model/UserDTO.java +++ b/backend/src/main/java/com/qqchen/deploy/backend/model/UserDTO.java @@ -23,4 +23,14 @@ public class UserDTO extends BaseDTO { private Boolean enabled; private Set roles; + + /** + * 部门ID + */ + private Long departmentId; + + /** + * 部门名称 + */ + private String departmentName; } \ No newline at end of file diff --git a/backend/src/main/java/com/qqchen/deploy/backend/model/request/DepartmentAssignRequest.java b/backend/src/main/java/com/qqchen/deploy/backend/model/request/DepartmentAssignRequest.java new file mode 100644 index 00000000..e32ab153 --- /dev/null +++ b/backend/src/main/java/com/qqchen/deploy/backend/model/request/DepartmentAssignRequest.java @@ -0,0 +1,11 @@ +package com.qqchen.deploy.backend.model.request; + +import lombok.Data; + +@Data +public class DepartmentAssignRequest { + /** + * 部门ID + */ + private Long departmentId; +} \ No newline at end of file diff --git a/backend/src/main/java/com/qqchen/deploy/backend/model/request/UserRequest.java b/backend/src/main/java/com/qqchen/deploy/backend/model/request/UserRequest.java index 5342bb06..e737798b 100644 --- a/backend/src/main/java/com/qqchen/deploy/backend/model/request/UserRequest.java +++ b/backend/src/main/java/com/qqchen/deploy/backend/model/request/UserRequest.java @@ -27,4 +27,6 @@ public class UserRequest { private String nickname; private String phone; + + private Long departmentId; } \ No newline at end of file diff --git a/backend/src/main/java/com/qqchen/deploy/backend/model/response/UserResponse.java b/backend/src/main/java/com/qqchen/deploy/backend/model/response/UserResponse.java index e9669cce..2079339e 100644 --- a/backend/src/main/java/com/qqchen/deploy/backend/model/response/UserResponse.java +++ b/backend/src/main/java/com/qqchen/deploy/backend/model/response/UserResponse.java @@ -21,4 +21,14 @@ public class UserResponse extends BaseResponse { private Boolean enabled; + /** + * 部门ID + */ + private Long departmentId; + + /** + * 部门名称 + */ + private String departmentName; + } \ No newline at end of file diff --git a/backend/src/main/java/com/qqchen/deploy/backend/repository/IPermissionRepository.java b/backend/src/main/java/com/qqchen/deploy/backend/repository/IPermissionRepository.java new file mode 100644 index 00000000..d53c9241 --- /dev/null +++ b/backend/src/main/java/com/qqchen/deploy/backend/repository/IPermissionRepository.java @@ -0,0 +1,18 @@ +package com.qqchen.deploy.backend.repository; + +import com.qqchen.deploy.backend.entity.Permission; +import com.qqchen.deploy.backend.framework.repository.IBaseRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.stereotype.Repository; + +import java.util.List; + +@Repository +public interface IPermissionRepository extends IBaseRepository { + List findByMenuIdAndEnabledTrue(Long menuId); + + @Query("SELECT p FROM Permission p WHERE p.enabled = true ORDER BY p.menuId, p.sort") + List findAllEnabledOrderByMenuAndSort(); + + List findByIdIn(List ids); +} \ No newline at end of file diff --git a/backend/src/main/java/com/qqchen/deploy/backend/service/IDepartmentService.java b/backend/src/main/java/com/qqchen/deploy/backend/service/IDepartmentService.java index a162d502..9be06296 100644 --- a/backend/src/main/java/com/qqchen/deploy/backend/service/IDepartmentService.java +++ b/backend/src/main/java/com/qqchen/deploy/backend/service/IDepartmentService.java @@ -13,4 +13,5 @@ public interface IDepartmentService extends IBaseService getTree(); + } \ No newline at end of file diff --git a/backend/src/main/java/com/qqchen/deploy/backend/service/IPermissionService.java b/backend/src/main/java/com/qqchen/deploy/backend/service/IPermissionService.java new file mode 100644 index 00000000..22dcbcb0 --- /dev/null +++ b/backend/src/main/java/com/qqchen/deploy/backend/service/IPermissionService.java @@ -0,0 +1,12 @@ +package com.qqchen.deploy.backend.service; + +import com.qqchen.deploy.backend.entity.Permission; +import com.qqchen.deploy.backend.framework.service.IBaseService; +import com.qqchen.deploy.backend.model.PermissionDTO; +import java.util.List; + +public interface IPermissionService extends IBaseService { + List listAllEnabled(); + List listByMenuId(Long menuId); + List listByIds(List ids); +} \ No newline at end of file diff --git a/backend/src/main/java/com/qqchen/deploy/backend/service/IRoleService.java b/backend/src/main/java/com/qqchen/deploy/backend/service/IRoleService.java index 7e2bacc7..0a8d6db7 100644 --- a/backend/src/main/java/com/qqchen/deploy/backend/service/IRoleService.java +++ b/backend/src/main/java/com/qqchen/deploy/backend/service/IRoleService.java @@ -3,6 +3,7 @@ package com.qqchen.deploy.backend.service; import com.qqchen.deploy.backend.framework.service.IBaseService; import com.qqchen.deploy.backend.entity.Role; import com.qqchen.deploy.backend.model.RoleDTO; +import com.qqchen.deploy.backend.model.PermissionDTO; import java.util.List; @@ -32,4 +33,14 @@ public interface IRoleService extends IBaseService { * 分配角色 */ void assignRoles(Long userId, List roleIds); + + /** + * 获取角色的权限列表 + */ + List listRolePermissions(Long roleId); + + /** + * 分配权限给角色 + */ + void assignPermissions(Long roleId, List permissionIds); } \ No newline at end of file diff --git a/backend/src/main/java/com/qqchen/deploy/backend/service/IUserService.java b/backend/src/main/java/com/qqchen/deploy/backend/service/IUserService.java index 80162f34..ef585181 100644 --- a/backend/src/main/java/com/qqchen/deploy/backend/service/IUserService.java +++ b/backend/src/main/java/com/qqchen/deploy/backend/service/IUserService.java @@ -42,4 +42,12 @@ public interface IUserService extends IBaseService { @Transactional(readOnly = false) @Audited(action = "RESET_PASSWORD", detail = "重置密码") void resetPassword(Long userId, String newPassword); + + /** + * 分配用户部门 + * @param userId 用户ID + * @param departmentId 部门ID + */ + @Transactional(readOnly = false) + void assignDepartment(Long userId, Long departmentId); } \ No newline at end of file diff --git a/backend/src/main/java/com/qqchen/deploy/backend/service/impl/DepartmentServiceImpl.java b/backend/src/main/java/com/qqchen/deploy/backend/service/impl/DepartmentServiceImpl.java index 997efee7..35373853 100644 --- a/backend/src/main/java/com/qqchen/deploy/backend/service/impl/DepartmentServiceImpl.java +++ b/backend/src/main/java/com/qqchen/deploy/backend/service/impl/DepartmentServiceImpl.java @@ -2,17 +2,21 @@ 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.entity.User; import com.qqchen.deploy.backend.framework.enums.ResponseCode; +import com.qqchen.deploy.backend.framework.exception.BusinessException; 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.model.response.DepartmentResponse; import com.qqchen.deploy.backend.repository.IDepartmentRepository; +import com.qqchen.deploy.backend.repository.IUserRepository; 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 org.springframework.transaction.annotation.Transactional; import java.util.*; @@ -26,6 +30,9 @@ public class DepartmentServiceImpl extends BaseServiceImpl implements IPermissionService { + + @Resource + private IPermissionRepository permissionRepository; + + @Resource + private IMenuRepository menuRepository; + + @Resource + private PermissionConverter permissionConverter; + + @Override + public List listAllEnabled() { + List permissions = permissionRepository.findAllEnabledOrderByMenuAndSort(); + List menuIds = permissions.stream().map(Permission::getMenuId).distinct().collect(Collectors.toList()); + Map menuNameMap = menuRepository.findAllById(menuIds).stream() + .collect(Collectors.toMap(Menu::getId, Menu::getName)); + + return permissions.stream().map(p -> convertToDTO(p, menuNameMap.get(p.getMenuId()))) + .collect(Collectors.toList()); + } + + @Override + public List listByMenuId(Long menuId) { + List permissions = permissionRepository.findByMenuIdAndEnabledTrue(menuId); + String menuName = menuRepository.findById(menuId).map(Menu::getName).orElse(null); + return permissions.stream().map(p -> convertToDTO(p, menuName)).collect(Collectors.toList()); + } + + @Override + public List listByIds(List ids) { + List permissions = permissionRepository.findByIdIn(ids); + List menuIds = permissions.stream().map(Permission::getMenuId).distinct().collect(Collectors.toList()); + Map menuNameMap = menuRepository.findAllById(menuIds).stream() + .collect(Collectors.toMap(Menu::getId, Menu::getName)); + + return permissions.stream().map(p -> convertToDTO(p, menuNameMap.get(p.getMenuId()))) + .collect(Collectors.toList()); + } + + private PermissionDTO convertToDTO(Permission permission, String menuName) { + PermissionDTO dto = permissionConverter.toDto(permission); + dto.setMenuName(menuName); + return dto; + } +} \ No newline at end of file diff --git a/backend/src/main/java/com/qqchen/deploy/backend/service/impl/RoleServiceImpl.java b/backend/src/main/java/com/qqchen/deploy/backend/service/impl/RoleServiceImpl.java index 3bc271b9..6d3091fa 100644 --- a/backend/src/main/java/com/qqchen/deploy/backend/service/impl/RoleServiceImpl.java +++ b/backend/src/main/java/com/qqchen/deploy/backend/service/impl/RoleServiceImpl.java @@ -1,19 +1,25 @@ package com.qqchen.deploy.backend.service.impl; +import com.qqchen.deploy.backend.converter.PermissionConverter; +import com.qqchen.deploy.backend.entity.Menu; +import com.qqchen.deploy.backend.entity.Permission; import com.qqchen.deploy.backend.entity.Role; import com.qqchen.deploy.backend.entity.RoleTag; import com.qqchen.deploy.backend.entity.User; import com.qqchen.deploy.backend.framework.enums.ResponseCode; import com.qqchen.deploy.backend.framework.exception.BusinessException; import com.qqchen.deploy.backend.framework.exception.UniqueConstraintException; -import com.qqchen.deploy.backend.model.RoleDTO; import com.qqchen.deploy.backend.framework.service.impl.BaseServiceImpl; +import com.qqchen.deploy.backend.model.PermissionDTO; +import com.qqchen.deploy.backend.model.RoleDTO; +import com.qqchen.deploy.backend.repository.IMenuRepository; +import com.qqchen.deploy.backend.repository.IPermissionRepository; import com.qqchen.deploy.backend.repository.IRoleRepository; import com.qqchen.deploy.backend.repository.IRoleTagRepository; import com.qqchen.deploy.backend.repository.IUserRepository; import com.qqchen.deploy.backend.service.IRoleService; import com.qqchen.deploy.backend.framework.annotation.ServiceType; -import com.qqchen.deploy.backend.service.IUserService; +import com.qqchen.deploy.backend.service.IPermissionService; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import jakarta.annotation.Resource; @@ -40,6 +46,18 @@ public class RoleServiceImpl extends BaseServiceImpl implem @Resource private IUserRepository userRepository; + @Resource + private IPermissionService permissionService; + + @Resource + private IMenuRepository menuRepository; + + @Resource + private PermissionConverter permissionConverter; + + @Resource + private IPermissionRepository permissionRepository; + @Override public List getUserRoleIds(Long userId) { return roleRepository.findRoleIdsByUserId(userId); @@ -106,10 +124,45 @@ public class RoleServiceImpl extends BaseServiceImpl implem throw new BusinessException(ResponseCode.ROLE_NOT_FOUND); } - // 设置用户角色 + // 设置用���角色 user.setRoles(new HashSet<>(roles)); // 保存更新 userRepository.save(user); } + + @Override + public List listRolePermissions(Long roleId) { + Role role = roleRepository.findById(roleId) + .orElseThrow(() -> new BusinessException(ResponseCode.ROLE_NOT_FOUND)); + + return role.getPermissions().stream() + .map(permission -> { + PermissionDTO dto = permissionConverter.toDto(permission); + String menuName = menuRepository.findById(permission.getMenuId()) + .map(Menu::getName) + .orElse(null); + dto.setMenuName(menuName); + return dto; + }) + .collect(Collectors.toList()); + } + + @Override + @Transactional + public void assignPermissions(Long roleId, List permissionIds) { + Role role = roleRepository.findById(roleId) + .orElseThrow(() -> new BusinessException(ResponseCode.ROLE_NOT_FOUND)); + + Set permissions = permissionRepository.findByIdIn(permissionIds) + .stream() + .collect(Collectors.toSet()); + + if (permissions.size() != permissionIds.size()) { + throw new BusinessException(ResponseCode.PERMISSION_NOT_FOUND); + } + + role.setPermissions(permissions); + roleRepository.save(role); + } } \ No newline at end of file diff --git a/backend/src/main/java/com/qqchen/deploy/backend/service/impl/UserServiceImpl.java b/backend/src/main/java/com/qqchen/deploy/backend/service/impl/UserServiceImpl.java index eec30a36..9171cada 100644 --- a/backend/src/main/java/com/qqchen/deploy/backend/service/impl/UserServiceImpl.java +++ b/backend/src/main/java/com/qqchen/deploy/backend/service/impl/UserServiceImpl.java @@ -19,6 +19,8 @@ import com.qqchen.deploy.backend.service.IUserService; import com.qqchen.deploy.backend.converter.RoleConverter; import com.qqchen.deploy.backend.model.UserDTO; import com.qqchen.deploy.backend.model.RoleDTO; +import com.qqchen.deploy.backend.repository.IDepartmentRepository; +import com.qqchen.deploy.backend.entity.Department; import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; import org.hibernate.Hibernate; @@ -55,6 +57,9 @@ public class UserServiceImpl extends BaseServiceImpl implem @Resource private JwtTokenUtil jwtTokenUtil; + @Resource + private IDepartmentRepository departmentRepository; + @Override @Transactional(readOnly = false) @Audited(action = "REGISTER", detail = "用户注册") @@ -163,6 +168,22 @@ public class UserServiceImpl extends BaseServiceImpl implem log.info("用户 {} 密码已重置", user.getUsername()); } + @Override + @Transactional + @Audited(action = "ASSIGN_DEPARTMENT", detail = "分配部门") + public void assignDepartment(Long userId, Long departmentId) { + // 获取用户 + User user = findEntityById(userId); + // 获取部门 + Department department = departmentRepository.findById(departmentId) + .orElseThrow(() -> new BusinessException(ResponseCode.DEPARTMENT_NOT_FOUND)); + // 设置用户部门 + user.setDepartment(department); + userRepository.save(user); + + log.info("用户 {} 已分配到部门 {}", user.getUsername(), department.getName()); + } + @Override protected void validateUniqueConstraints(UserDTO dto) { // 检查用户名唯一性(包括已删除的记录) @@ -175,4 +196,31 @@ public class UserServiceImpl extends BaseServiceImpl implem throw new UniqueConstraintException(ResponseCode.EMAIL_EXISTS, "email", dto.getEmail()); } } + + @Override + @Transactional + public UserDTO update(Long id, UserDTO dto) { + User user = findEntityById(id); + + // 更新基本信息 + userConverter.updateEntity(user, dto); + + // 如果指定了部门ID,更新用户部门 + if (dto.getDepartmentId() != null) { + Department department = departmentRepository.findById(dto.getDepartmentId()) + .orElseThrow(() -> new BusinessException(ResponseCode.DEPARTMENT_NOT_FOUND)); + user.setDepartment(department); + log.info("用户 {} 已分配到部门 {}", user.getUsername(), department.getName()); + } + + // 保存更新 + userRepository.save(user); + + // 转换为DTO并返回 + UserDTO result = userConverter.toDto(user); + if (user.getDepartment() != null) { + result.setDepartmentId(user.getDepartment().getId()); + } + return result; + } } \ No newline at end of file diff --git a/backend/src/main/resources/db/migration/V1.0.0__init_schema.sql b/backend/src/main/resources/db/migration/V1.0.0__init_schema.sql index 8036acae..bbd156ae 100644 --- a/backend/src/main/resources/db/migration/V1.0.0__init_schema.sql +++ b/backend/src/main/resources/db/migration/V1.0.0__init_schema.sql @@ -17,6 +17,26 @@ CREATE TABLE IF NOT EXISTS sys_tenant ( CONSTRAINT UK_tenant_code UNIQUE (code) ); +-- 创建部门表 +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_department_code UNIQUE (code) +); + -- 创建用户表 CREATE TABLE IF NOT EXISTS sys_user ( id BIGINT AUTO_INCREMENT PRIMARY KEY, @@ -32,7 +52,9 @@ CREATE TABLE IF NOT EXISTS sys_user ( password VARCHAR(255) NOT NULL, phone VARCHAR(255) NULL, username VARCHAR(255) NOT NULL, - CONSTRAINT UK_user_username UNIQUE (username) + department_id BIGINT NULL, + CONSTRAINT UK_user_username UNIQUE (username), + CONSTRAINT FK_user_department FOREIGN KEY (department_id) REFERENCES sys_department(id) ); -- 创建系统参数表 @@ -175,23 +197,64 @@ CREATE TABLE sys_template_menu ( CONSTRAINT FK_template_menu_menu FOREIGN KEY (menu_id) REFERENCES sys_menu (id) ) COMMENT '模板菜单关联表'; --- 创建部门表 -CREATE TABLE sys_department ( +-- 创建权限表 +CREATE TABLE sys_permission ( 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) -); + create_by VARCHAR(255) NULL, + create_time DATETIME(6) NULL, + deleted BIT NOT NULL, + update_by VARCHAR(255) NULL, + update_time DATETIME(6) NULL, + version INT NOT NULL, + + menu_id BIGINT NOT NULL COMMENT '关联的菜单ID', + code VARCHAR(100) NOT NULL COMMENT '权限编码', + name VARCHAR(100) NOT NULL COMMENT '权限名称', + type VARCHAR(50) NOT NULL DEFAULT 'FUNCTION' COMMENT '权限类型:MENU/FUNCTION/API', + enabled BIT NOT NULL DEFAULT TRUE COMMENT '是否启用', + sort INT NULL COMMENT '排序', + + UNIQUE KEY UK_CODE (CODE), + KEY IDX_MENU_ID (MENU_ID) +) COMMENT '系统权限表'; + +-- 创建三方系统表 +CREATE TABLE sys_external_system ( + id BIGINT AUTO_INCREMENT PRIMARY KEY, + create_by VARCHAR(255) NULL, + create_time DATETIME(6) NULL, + deleted BIT NOT NULL, + update_by VARCHAR(255) NULL, + update_time DATETIME(6) NULL, + version INT NOT NULL, + + name VARCHAR(255) NOT NULL COMMENT '系统名称', + type VARCHAR(50) NOT NULL COMMENT '系统类型:JENKINS/GIT/ZENTAO等', + url VARCHAR(255) NOT NULL COMMENT '系统访问地址', + remark TEXT NULL COMMENT '备注说明', + sort INT NULL COMMENT '排序', + enabled BIT NOT NULL DEFAULT TRUE COMMENT '是否启用', + + auth_type VARCHAR(50) NOT NULL COMMENT '认证方式:BASIC/TOKEN/OAUTH等', + username VARCHAR(255) NULL COMMENT '用户名', + password VARCHAR(255) NULL COMMENT '密码/密钥', + token VARCHAR(255) NULL COMMENT '访问令牌', + + sync_status ENUM ('SUCCESS', 'FAILED', 'RUNNING') NULL COMMENT '最后同步状态', + last_sync_time DATETIME(6) NULL COMMENT '最后同步时间', + + config JSON NULL COMMENT '系统特有配置,JSON格式', + + UNIQUE KEY UK_NAME (NAME), + UNIQUE KEY UK_TYPE_URL (TYPE, URL) +) COMMENT '第三方系统配置'; + +-- 创建角色权限关联表 +CREATE TABLE sys_role_permission ( + role_id BIGINT NOT NULL COMMENT '角色ID', + permission_id BIGINT NOT NULL COMMENT '权限ID', + PRIMARY KEY (role_id, permission_id), + CONSTRAINT FK_role_permission_role FOREIGN KEY (role_id) REFERENCES sys_role (id), + CONSTRAINT FK_role_permission_permission FOREIGN KEY (permission_id) REFERENCES sys_permission (id) +) COMMENT '角色权限关联表'; \ No newline at end of file diff --git a/backend/src/main/resources/db/migration/V1.0.1__init_data.sql b/backend/src/main/resources/db/migration/V1.0.1__init_data.sql index d08e8c1c..d3136d82 100644 --- a/backend/src/main/resources/db/migration/V1.0.1__init_data.sql +++ b/backend/src/main/resources/db/migration/V1.0.1__init_data.sql @@ -1,174 +1,130 @@ --- 初始化租户 -INSERT INTO sys_tenant -(create_by, create_time, deleted, update_by, update_time, version, -address, code, contact_name, contact_phone, email, enabled, name) -VALUES -('system', '2024-01-01 00:00:00', 0, 'system', '2024-01-01 00:00:00', 0, -'北京市朝阳区望京SOHO T1 C座', 'default', '张三', '13900000001', -'admin@deploy-ease.com', 1, '默认租户'); - --- 系统参数初始化 -INSERT INTO sys_param (code, name, value, type, description, enabled, create_by, create_time, deleted, version) -VALUES -('SYSTEM_NAME', '系统名称', 'DevOps平台', 'TEXT', '系统显示名称', 1, 'system', '2024-01-01 00:00:00', 0, 0), -('SYSTEM_LOGO', '系统Logo', '/logo.png', 'TEXT', '系统Logo路径', 1, 'system', '2024-01-01 00:00:00', 0, 0), -('GENDER_ENUM', '性别枚举', '[{"code":"1","name":"男"},{"code":"2","name":"女"}]', 'ENUM', '性别枚举值', 1, 'system', '2024-01-01 00:00:00', 0, 0), -('USER_STATUS_ENUM', '用户状态枚举', '[{"code":"0","name":"禁用"},{"code":"1","name":"启用"}]', 'ENUM', '用户状态枚举值', 1, 'system', '2024-01-01 00:00:00', 0, 0); - --- 初始化系统管理菜单 -INSERT INTO sys_menu (id, create_by, create_time, deleted, update_by, update_time, version, - name, path, component, icon, type, parent_id, sort, hidden, enabled) -VALUES --- 系统管理 -(1, 'system', '2024-01-01 00:00:00', 0, 'system', '2024-01-01 00:00:00', 0, - '系统管理', '/system', null, 'setting', 1, null, 1, 0, 1), - --- 用户管理 -(2, 'system', '2024-01-01 00:00:00', 0, 'system', '2024-01-01 00:00:00', 0, - '用户管理', '/system/user', '/System/User', 'user', 2, 1, 1, 0, 1), - --- 角色管理 -(3, 'system', '2024-01-01 00:00:00', 0, 'system', '2024-01-01 00:00:00', 0, - '角色管理', '/system/role', '/System/Role', 'team', 2, 1, 2, 0, 1), - --- 菜单管理 -(4, 'system', '2024-01-01 00:00:00', 0, 'system', '2024-01-01 00:00:00', 0, - '菜单管理', '/system/menu', '/System/Menu', 'menu', 2, 1, 3, 0, 1), - --- 部门管理 -(5, 'system', '2024-01-01 00:00:00', 0, 'system', '2024-01-01 00:00:00', 0, - '部门管理', '/system/department', '/System/Department', 'apartment', 2, 1, 4, 0, 1), - --- 租户管理 -(6, 'system', '2024-01-01 00:00:00', 0, 'system', '2024-01-01 00:00:00', 0, - '租户管理', '/system/tenant', '/System/Tenant', 'cluster', 2, 1, 5, 0, 1), - --- Jenkins管理 -(7, 'system', '2024-01-01 00:00:00', 0, 'system', '2024-01-01 00:00:00', 0, - 'Jenkins管理', '/system/jenkins', '/System/Jenkins', 'cloud-server', 2, 1, 6, 0, 1), - --- 代码仓库 -(8, 'system', '2024-01-01 00:00:00', 0, 'system', '2024-01-01 00:00:00', 0, - '代码仓库', '/system/repository', '/System/Repository', 'code', 2, 1, 7, 0, 1); +-- 初始化系统参数 +INSERT INTO sys_param (id, code, name, value, type, description, enabled, create_by, create_time, version, deleted) +VALUES (1, 'USER_STATUS_ENUM', '用户状态枚举', '[{"code":"0","name":"禁用"},{"code":"1","name":"启用"}]', 'ENUM', '用户状态枚举值', true, 'system', '2024-01-01 00:00:00', 0, false); -- 初始化角色标签 -INSERT INTO sys_role_tag (id, name, color, create_by, create_time, deleted, version) VALUES -(1, '研发', '#1890FF', 'system', '2024-01-01 00:00:00', 0, 0), -(2, '运维', '#52C41A', 'system', '2024-01-01 00:00:00', 0, 0), -(3, '安全', '#FF4D4F', 'system', '2024-01-01 00:00:00', 0, 0), -(4, '临时', '#FAAD14', 'system', '2024-01-01 00:00:00', 0, 0), -(5, '外部', '#722ED1', 'system', '2024-01-01 00:00:00', 0, 0); +INSERT INTO sys_role_tag (id, name, color, create_by, create_time, deleted, version) +VALUES (1, '研发', '#1890FF', 'system', '2024-01-01 00:00:00', false, 0), + (2, '运维', '#52C41A', 'system', '2024-01-01 00:00:00', false, 0), + (3, '安全', '#FF4D4F', 'system', '2024-01-01 00:00:00', false, 0), + (4, '临时', '#FAAD14', 'system', '2024-01-01 00:00:00', false, 0), + (5, '外部', '#722ED1', 'system', '2024-01-01 00:00:00', false, 0); --- 初始化用户 -INSERT INTO sys_user (id, username, password, nickname, email, phone, enabled, create_by, create_time, deleted, version) -VALUES -(1, 'admin', '$2a$10$zXuXOF3C.w/ZpjayaE1P/eFRov/3vJAAOBs.uy2kHUoK3SyuR/Wte', '超级管理员', 'admin@deploy-ease.com', '13800138000', 1, 'system', '2024-01-01 00:00:00', 0, 0), -(2, 'dev_manager', '$2a$10$zXuXOF3C.w/ZpjayaE1P/eFRov/3vJAAOBs.uy2kHUoK3SyuR/Wte', '开发主管', 'dev@deploy-ease.com', '13800138001', 1, 'system', '2024-01-01 00:00:00', 0, 0), -(3, 'ops_manager', '$2a$10$zXuXOF3C.w/ZpjayaE1P/eFRov/3vJAAOBs.uy2kHUoK3SyuR/Wte', '运维主管', 'ops@deploy-ease.com', '13800138002', 1, 'system', '2024-01-01 00:00:00', 0, 0); +-- 初始化菜单数据 +INSERT INTO sys_menu (id, name, path, component, icon, type, parent_id, sort, hidden, enabled, create_by, create_time, version, deleted) +VALUES +-- 系统管理 +(1, '系统管理', '/system', 'LAYOUT', 'setting', 1, null, 1, false, true, 'system', '2024-01-01 00:00:00', 0, false), +-- 用户管理 +(2, '用户管理', '/system/user', '/System/User/index', 'user', 2, 1, 10, false, true, 'system', '2024-01-01 00:00:00', 0, false), +-- 角色管理 +(3, '角色管理', '/system/role', '/System/Role/index', 'peoples', 2, 1, 20, false, true, 'system', '2024-01-01 00:00:00', 0, false), +-- 菜单管理 +(4, '菜单管理', '/system/menu', '/System/Menu/index', 'tree-table', 2, 1, 30, false, true, 'system', '2024-01-01 00:00:00', 0, false), +-- 部门管理 +(5, '部门管理', '/system/department', '/System/Department/index', 'tree', 2, 1, 40, false, true, 'system', '2024-01-01 00:00:00', 0, false), +-- 三方系统 +(70, '三方系统', '/system/external', '/System/External/index', 'api', 2, 1, 70, false, true, 'system', '2024-01-01 00:00:00', 0, false); --- 初始化角色 -INSERT INTO sys_role (id, code, name, type, description, sort, enabled, create_by, create_time, deleted, version) -VALUES -(1, 'SUPER_ADMIN', '超级管理员', 1, '系统超级管理员', 1, 1, 'system', '2024-01-01 00:00:00', 0, 0), -(2, 'DEV_MANAGER', '开发主管', 2, '开发团队主管', 2, 1, 'system', '2024-01-01 00:00:00', 0, 0), -(3, 'OPS_MANAGER', '运维主管', 2, '运维团队主管', 3, 1, 'system', '2024-01-01 00:00:00', 0, 0); - --- 用户角色关联 -INSERT INTO sys_user_role (user_id, role_id, create_by, create_time) -VALUES -(1, 1, 'system', '2024-01-01 00:00:00'), -- 超级管理员 -> 超级管理员角色 -(2, 2, 'system', '2024-01-01 00:00:00'), -- 开发主管 -> 开发主管角色 -(3, 3, 'system', '2024-01-01 00:00:00'); -- 运维主管 -> 运维主管角色 - --- 角色菜单关联 -INSERT INTO sys_role_menu (role_id, menu_id) -VALUES --- 超级管理员拥有所有菜单权限 -(1, 1), (1, 2), (1, 3), (1, 4), (1, 5), (1, 6), (1, 7), (1, 8), --- 开发主管权限 -(2, 7), (2, 8), --- 运维主管权限 -(3, 7), (3, 8); - --- 角色标签关联 -INSERT INTO sys_role_tag_relation (role_id, tag_id) -VALUES -(1, 3), -- 超级管理员 -> 安全标签 -(2, 1), -- 开发主管 -> 研发标签 -(3, 2); -- 运维主管 -> 运维标签 +-- 初始化角色数据 +INSERT INTO sys_role (id, code, name, type, description, sort, enabled, create_by, create_time, version, deleted) +VALUES (1, 'SUPER_ADMIN', '超级管理员', 1, '系统超级管理员', 1, true, 'system', '2024-01-01 00:00:00', 0, false), + (2, 'DEV_MANAGER', '开发主管', 2, '开发团队主管', 2, true, 'system', '2024-01-01 00:00:00', 0, false), + (3, 'OPS_MANAGER', '运维主管', 2, '运维团队主管', 3, true, 'system', '2024-01-01 00:00:00', 0, false); -- 初始化部门数据 -INSERT INTO sys_department (id, code, name, parent_id, sort, enabled, create_by, create_time, update_by, update_time, version, deleted) VALUES --- 总公司 -(1, 'HQ', '总公司', 0, 1, 1, 'system', '2024-01-01 00:00:00', 'system', '2024-01-01 00:00:00', 0, 0), +INSERT INTO sys_department (id, code, name, description, enabled, sort, parent_id, create_by, create_time, version, deleted) +VALUES (1, 'TECH', '技术部', '技术研发部门', true, 1, null, 'system', '2024-01-01 00:00:00', 0, false), + (2, 'DEV', '研发组', '研发团队', true, 1, 1, 'system', '2024-01-01 00:00:00', 0, false), + (3, 'OPS', '运维组', '运维团队', true, 2, 1, 'system', '2024-01-01 00:00:00', 0, false); --- 技术部门 -(2, 'TECH', '技术部', 1, 1, 1, 'system', '2024-01-01 00:00:00', 'system', '2024-01-01 00:00:00', 0, 0), -(3, 'DEV', '研发部', 2, 1, 1, 'system', '2024-01-01 00:00:00', 'system', '2024-01-01 00:00:00', 0, 0), -(4, 'TEST', '测试部', 2, 2, 1, 'system', '2024-01-01 00:00:00', 'system', '2024-01-01 00:00:00', 0, 0), -(5, 'OPS', '运维部', 2, 3, 1, 'system', '2024-01-01 00:00:00', 'system', '2024-01-01 00:00:00', 0, 0), +-- 初始化用户数据 +INSERT INTO sys_user (id, username, password, nickname, email, phone, enabled, department_id, create_by, create_time, version, deleted) +VALUES (1, 'admin', '$2a$10$VTbMVv3M.gVaMcLsELtBZuHxGrHyFqf3CYfSFQhcBn0A6pBTvThSy', '系统管理员', 'admin@example.com', '13800138000', true, null, 'system', '2024-01-01 00:00:00', 0, false), + (2, 'dev_manager', '$2a$10$VTbMVv3M.gVaMcLsELtBZuHxGrHyFqf3CYfSFQhcBn0A6pBTvThSy', '开发主管', 'dev@example.com', '13800138001', true, 2, 'system', '2024-01-01 00:00:00', 0, false), + (3, 'ops_manager', '$2a$10$VTbMVv3M.gVaMcLsELtBZuHxGrHyFqf3CYfSFQhcBn0A6pBTvThSy', '运维主管', 'ops@example.com', '13800138002', true, 3, 'system', '2024-01-01 00:00:00', 0, false); --- 人力资源部门 -(6, 'HR', '人力资源部', 1, 2, 1, 'system', '2024-01-01 00:00:00', 'system', '2024-01-01 00:00:00', 0, 0), -(7, 'REC', '招聘部', 6, 1, 1, 'system', '2024-01-01 00:00:00', 'system', '2024-01-01 00:00:00', 0, 0), -(8, 'TRAIN', '培训部', 6, 2, 1, 'system', '2024-01-01 00:00:00', 'system', '2024-01-01 00:00:00', 0, 0), +-- 初始化用户角色关联数据 +INSERT INTO sys_user_role (user_id, role_id, create_by, create_time, version, deleted) +VALUES (1, 1, 'system', '2024-01-01 00:00:00', 0, false), -- 超级管理员 -> 超级管理员角色 + (2, 2, 'system', '2024-01-01 00:00:00', 0, false), -- 开发主管 -> 开发主管角色 + (3, 3, 'system', '2024-01-01 00:00:00', 0, false); -- 运维主管 -> 运维主管角色 --- 其他部门 -(9, 'FIN', '财务部', 1, 3, 1, 'system', '2024-01-01 00:00:00', 'system', '2024-01-01 00:00:00', 0, 0), -(10, 'MKT', '市场部', 1, 4, 1, 'system', '2024-01-01 00:00:00', 'system', '2024-01-01 00:00:00', 0, 0), -(11, 'SALES', '销售部', 10, 1, 1, 'system', '2024-01-01 00:00:00', 'system', '2024-01-01 00:00:00', 0, 0), -(12, 'PR', '公关部', 10, 2, 1, 'system', '2024-01-01 00:00:00', 'system', '2024-01-01 00:00:00', 0, 0); +-- 初始化角色标签关联数据 +INSERT INTO sys_role_tag_relation (role_id, tag_id) +VALUES (1, 3), -- 超级管理员 -> 安全标签 + (2, 1), -- 开发主管 -> 研发标签 + (3, 2); -- 运维主管 -> 运维标签 --- 系统管理菜单按钮权限 -INSERT INTO sys_menu (id, create_by, create_time, deleted, update_by, update_time, version, - name, path, component, icon, type, parent_id, sort, hidden, enabled, permission) -VALUES --- 用户管理按钮 -(21, 'system', '2024-01-01 00:00:00', 0, 'system', '2024-01-01 00:00:00', 0, - '用户新增', '', null, null, 3, 2, 1, 0, 1, 'system:user:add'), -(22, 'system', '2024-01-01 00:00:00', 0, 'system', '2024-01-01 00:00:00', 0, - '用户编辑', '', null, null, 3, 2, 2, 0, 1, 'system:user:edit'), -(23, 'system', '2024-01-01 00:00:00', 0, 'system', '2024-01-01 00:00:00', 0, - '用户删除', '', null, null, 3, 2, 3, 0, 1, 'system:user:delete'), -(24, 'system', '2024-01-01 00:00:00', 0, 'system', '2024-01-01 00:00:00', 0, - '重置密码', '', null, null, 3, 2, 4, 0, 1, 'system:user:reset-password'), -(25, 'system', '2024-01-01 00:00:00', 0, 'system', '2024-01-01 00:00:00', 0, - '分配角色', '', null, null, 3, 2, 5, 0, 1, 'system:user:assign-roles'), - --- 角色管理按钮 -(31, 'system', '2024-01-01 00:00:00', 0, 'system', '2024-01-01 00:00:00', 0, - '角色新增', '', null, null, 3, 3, 1, 0, 1, 'system:role:add'), -(32, 'system', '2024-01-01 00:00:00', 0, 'system', '2024-01-01 00:00:00', 0, - '角色编辑', '', null, null, 3, 3, 2, 0, 1, 'system:role:edit'), -(33, 'system', '2024-01-01 00:00:00', 0, 'system', '2024-01-01 00:00:00', 0, - '角色删除', '', null, null, 3, 3, 3, 0, 1, 'system:role:delete'), -(34, 'system', '2024-01-01 00:00:00', 0, 'system', '2024-01-01 00:00:00', 0, - '分配标签', '', null, null, 3, 3, 4, 0, 1, 'system:role:assign-tags'), - --- 菜单管理按钮 -(41, 'system', '2024-01-01 00:00:00', 0, 'system', '2024-01-01 00:00:00', 0, - '菜单新增', '', null, null, 3, 4, 1, 0, 1, 'system:menu:add'), -(42, 'system', '2024-01-01 00:00:00', 0, 'system', '2024-01-01 00:00:00', 0, - '菜单编辑', '', null, null, 3, 4, 2, 0, 1, 'system:menu:edit'), -(43, 'system', '2024-01-01 00:00:00', 0, 'system', '2024-01-01 00:00:00', 0, - '菜单删除', '', null, null, 3, 4, 3, 0, 1, 'system:menu:delete'), - --- 部门管理按钮 -(51, 'system', '2024-01-01 00:00:00', 0, 'system', '2024-01-01 00:00:00', 0, - '部门新增', '', null, null, 3, 5, 1, 0, 1, 'system:department:add'), -(52, 'system', '2024-01-01 00:00:00', 0, 'system', '2024-01-01 00:00:00', 0, - '部门编辑', '', null, null, 3, 5, 2, 0, 1, 'system:department:edit'), -(53, 'system', '2024-01-01 00:00:00', 0, 'system', '2024-01-01 00:00:00', 0, - '部门删除', '', null, null, 3, 5, 3, 0, 1, 'system:department:delete'); - --- 为超级管理员角色分配所有按钮权限 +-- 初始化角色菜单关联数据 INSERT INTO sys_role_menu (role_id, menu_id) -VALUES --- 用户管理按钮权限 +VALUES +-- 超级管理员拥有所有菜单权限 +(1, 1), (1, 2), (1, 3), (1, 4), (1, 5), (1, 70), +-- 开发主管权限 +(2, 70), +-- 运维主管权限 +(3, 70); + +-- 初始化权限数据 +INSERT INTO sys_permission (id, menu_id, code, name, type, enabled, sort, create_by, create_time, update_by, update_time, version, deleted) +VALUES +-- 用户管理权限 +(21, 2, 'system:user:add', '用户新增', 'FUNCTION', true, 1, 'system', '2024-01-01 00:00:00', 'system', '2024-01-01 00:00:00', 0, false), +(22, 2, 'system:user:edit', '用户编辑', 'FUNCTION', true, 2, 'system', '2024-01-01 00:00:00', 'system', '2024-01-01 00:00:00', 0, false), +(23, 2, 'system:user:delete', '用户删除', 'FUNCTION', true, 3, 'system', '2024-01-01 00:00:00', 'system', '2024-01-01 00:00:00', 0, false), +(24, 2, 'system:user:reset-password', '重置密码', 'FUNCTION', true, 4, 'system', '2024-01-01 00:00:00', 'system', '2024-01-01 00:00:00', 0, false), +(25, 2, 'system:user:assign-roles', '分配角色', 'FUNCTION', true, 5, 'system', '2024-01-01 00:00:00', 'system', '2024-01-01 00:00:00', 0, false), + +-- 角色管理权限 +(31, 3, 'system:role:add', '角色新增', 'FUNCTION', true, 1, 'system', '2024-01-01 00:00:00', 'system', '2024-01-01 00:00:00', 0, false), +(32, 3, 'system:role:edit', '角色编辑', 'FUNCTION', true, 2, 'system', '2024-01-01 00:00:00', 'system', '2024-01-01 00:00:00', 0, false), +(33, 3, 'system:role:delete', '角色删除', 'FUNCTION', true, 3, 'system', '2024-01-01 00:00:00', 'system', '2024-01-01 00:00:00', 0, false), +(34, 3, 'system:role:assign-tags', '分配标签', 'FUNCTION', true, 4, 'system', '2024-01-01 00:00:00', 'system', '2024-01-01 00:00:00', 0, false), +(35, 3, 'system:role:assign-permissions', '分配权限', 'FUNCTION', true, 5, 'system', '2024-01-01 00:00:00', 'system', '2024-01-01 00:00:00', 0, false), +(36, 3, 'system:role:permission-list', '权限列表', 'FUNCTION', true, 6, 'system', '2024-01-01 00:00:00', 'system', '2024-01-01 00:00:00', 0, false), + +-- 菜单管理权限 +(41, 4, 'system:menu:add', '菜单新增', 'FUNCTION', true, 1, 'system', '2024-01-01 00:00:00', 'system', '2024-01-01 00:00:00', 0, false), +(42, 4, 'system:menu:edit', '菜单编辑', 'FUNCTION', true, 2, 'system', '2024-01-01 00:00:00', 'system', '2024-01-01 00:00:00', 0, false), +(43, 4, 'system:menu:delete', '菜单删除', 'FUNCTION', true, 3, 'system', '2024-01-01 00:00:00', 'system', '2024-01-01 00:00:00', 0, false), + +-- 部门管理权限 +(51, 5, 'system:department:add', '部门新增', 'FUNCTION', true, 1, 'system', '2024-01-01 00:00:00', 'system', '2024-01-01 00:00:00', 0, false), +(52, 5, 'system:department:edit', '部门编辑', 'FUNCTION', true, 2, 'system', '2024-01-01 00:00:00', 'system', '2024-01-01 00:00:00', 0, false), +(53, 5, 'system:department:delete', '部门删除', 'FUNCTION', true, 3, 'system', '2024-01-01 00:00:00', 'system', '2024-01-01 00:00:00', 0, false), + +-- 三方系统管理权限 +(71, 70, 'system:external:list', '查看三方系统', 'FUNCTION', true, 1, 'system', '2024-01-01 00:00:00', 'system', '2024-01-01 00:00:00', 0, false), +(72, 70, 'system:external:create', '新增三方系统', 'FUNCTION', true, 2, 'system', '2024-01-01 00:00:00', 'system', '2024-01-01 00:00:00', 0, false), +(73, 70, 'system:external:update', '编辑三方系统', 'FUNCTION', true, 3, 'system', '2024-01-01 00:00:00', 'system', '2024-01-01 00:00:00', 0, false), +(74, 70, 'system:external:delete', '删除三方系统', 'FUNCTION', true, 4, 'system', '2024-01-01 00:00:00', 'system', '2024-01-01 00:00:00', 0, false), +(75, 70, 'system:external:sync', '同步三方系统', 'FUNCTION', true, 5, 'system', '2024-01-01 00:00:00', 'system', '2024-01-01 00:00:00', 0, false); + +-- 初始化角色权限关联数据 +INSERT INTO sys_role_permission (role_id, permission_id) +VALUES +-- 用户管理权限 (1, 21), (1, 22), (1, 23), (1, 24), (1, 25), --- 角色管理按钮权限 -(1, 31), (1, 32), (1, 33), (1, 34), --- 菜单管理按钮权限 +-- 角色管理权限(包含权限管理功能) +(1, 31), (1, 32), (1, 33), (1, 34), (1, 35), (1, 36), +-- 菜单管理权限 (1, 41), (1, 42), (1, 43), --- 部门管理按钮权限 -(1, 51), (1, 52), (1, 53); \ No newline at end of file +-- 部门管理权限 +(1, 51), (1, 52), (1, 53), +-- 三方系统管理权限 +(1, 71), (1, 72), (1, 73), (1, 74), (1, 75); + +-- 初始化三方系统数据 +INSERT INTO sys_external_system (id, name, type, url, auth_type, username, password, enabled, sort, create_by, create_time, version, deleted, remark) +VALUES +-- Jenkins示例 +(1, 'Jenkins-开发环境', 'JENKINS', 'http://jenkins-dev.example.com', 'BASIC', 'admin', 'password123', true, 1, 'system', '2024-01-01 00:00:00', 0, false, 'Jenkins开发环境'), +(2, 'Jenkins-测试环境', 'JENKINS', 'http://jenkins-test.example.com', 'BASIC', 'admin', 'password123', true, 2, 'system', '2024-01-01 00:00:00', 0, false, 'Jenkins测试环境'), + +-- Git仓库示例 +(3, 'GitLab-主库', 'GIT', 'http://gitlab.example.com', 'TOKEN', null, null, true, 3, 'system', '2024-01-01 00:00:00', 0, false, '公司GitLab主库'), +(4, 'GitHub', 'GIT', 'https://github.com', 'OAUTH', null, null, true, 4, 'system', '2024-01-01 00:00:00', 0, false, 'GitHub仓库'), + +-- 禅道示例 +(5, '禅道-项目管理', 'ZENTAO', 'http://zentao.example.com', 'BASIC', 'admin', 'password123', true, 5, 'system', '2024-01-01 00:00:00', 0, false, '禅道项目管理系统'); \ No newline at end of file diff --git a/backend/src/main/resources/messages.properties b/backend/src/main/resources/messages.properties index cb5cb426..e14315ef 100644 --- a/backend/src/main/resources/messages.properties +++ b/backend/src/main/resources/messages.properties @@ -1,59 +1,66 @@ -# \u901A\u7528\u54CD\u5E94 -response.success=\u64CD\u4F5C\u6210\u529F -response.error=\u7CFB\u7EDF\u9519\u8BEF -response.invalid.param=\u65E0\u6548\u7684\u53C2\u6570 -response.unauthorized=\u672A\u6388\u6743 -response.forbidden=\u7981\u6B62\u8BBF\u95EE -response.not.found=\u8D44\u6E90\u672A\u627E\u5230 -response.conflict=\u8D44\u6E90\u51B2\u7A81 -response.unauthorized.full=\u8BBF\u95EE\u6B64\u8D44\u6E90\u9700\u8981\u5B8C\u5168\u8EAB\u4EFD\u9A8C\u8BC1 +# 通用响应 +response.success=操作成功 +response.error=系统错误 +response.invalid.param=无效的参数 +response.unauthorized=未授权 +response.forbidden=禁止访问 +response.not.found=资源未找到 +response.conflict=资源冲突 +response.unauthorized.full=访问此资源需要完全身份验证 -# \u4E1A\u52A1\u9519\u8BEF -tenant.not.found=\u79DF\u6237\u4E0D\u5B58\u5728 -data.not.found=\u627E\u4E0D\u5230ID\u4E3A{0}\u7684{1} +# 业务错误 +tenant.not.found=租户不存在 +data.not.found=找不到ID为{0}的{1} -# \u7528\u6237\u76F8\u5173 -user.not.found=\u7528\u6237\u4E0D\u5B58\u5728 -user.username.exists=\u7528\u6237\u540D"{0}"\u5DF2\u5B58\u5728 -user.email.exists=\u90AE\u7BB1"{0}"\u5DF2\u5B58\u5728 -user.login.error=\u7528\u6237\u540D\u6216\u5BC6\u7801\u9519\u8BEF +# 用户相关 +user.not.found=用户不存在 +user.username.exists=用户名"{0}"已存在 +user.email.exists=邮箱"{0}"已存在 +user.login.error=用户名或密码错误 -# \u7CFB\u7EDF\u5F02\u5E38\u6D88\u606F -system.optimistic.lock.error=\u6570\u636E\u5DF2\u88AB\u5176\u4ED6\u7528\u6237\u4FEE\u6539\uFF0C\u8BF7\u5237\u65B0\u540E\u91CD\u8BD5 -system.pessimistic.lock.error=\u6570\u636E\u6B63\u88AB\u5176\u4ED6\u7528\u6237\u64CD\u4F5C\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5 -system.concurrent.update.error=\u5E76\u53D1\u66F4\u65B0\u51B2\u7A81\uFF0C\u8BF7\u91CD\u8BD5 -system.retry.exceeded.error=\u64CD\u4F5C\u91CD\u8BD5\u6B21\u6570\u8D85\u9650\uFF0C\u8BF7\u7A0D\u540E\u518D\u8BD5 +# 系统异常消息 +system.optimistic.lock.error=数据已被其他用户修改,请刷新后重试 +system.pessimistic.lock.error=数据正被其他用户操作,请稍后重试 +system.concurrent.update.error=并发更新冲突,请重试 +system.retry.exceeded.error=操作重试次数超限,请稍后再试 # Entity Not Found Messages -entity.not.found.id=\u627E\u4E0D\u5230ID\u4E3A{0}\u7684\u5B9E\u4F53 +entity.not.found.id=找不到ID为{0}的实体 entity.not.found.message={0} -entity.not.found.name.id=\u627E\u4E0D\u5230ID\u4E3A{1}\u7684{0} +entity.not.found.name.id=找不到ID为{1}的{0} -# \u4F9D\u8D56\u6CE8\u5165\u76F8\u5173 -dependency.injection.service.not.found=\u627E\u4E0D\u5230\u5B9E\u4F53 {0} \u5BF9\u5E94\u7684\u670D\u52A1 (\u5C1D\u8BD5\u8FC7\u7684bean\u540D\u79F0: {1}) -dependency.injection.repository.not.found=\u627E\u4E0D\u5230\u5B9E\u4F53 {0} \u5BF9\u5E94\u7684Repository: {1} -dependency.injection.converter.not.found=\u627E\u4E0D\u5230\u5B9E\u4F53 {0} \u5BF9\u5E94\u7684Converter: {1} -dependency.injection.entitypath.failed=\u521D\u59CB\u5316\u5B9E\u4F53 {0} \u7684EntityPath\u5931\u8D25: {1} +# 依赖注入相关 +dependency.injection.service.not.found=找不到实体 {0} 对应的服务 (尝试过的bean名称: {1}) +dependency.injection.repository.not.found=找不到实体 {0} 对应的Repository: {1} +dependency.injection.converter.not.found=找不到实体 {0} 对应的Converter: {1} +dependency.injection.entitypath.failed=初始化实体 {0} 的EntityPath失败: {1} -# JWT\u76F8\u5173 -jwt.token.expired=\u767B\u5F55\u5DF2\u8FC7\u671F\uFF0C\u8BF7\u91CD\u65B0\u767B\u5F55 -jwt.token.invalid=\u65E0\u6548\u7684\u767B\u5F55\u51ED\u8BC1 -jwt.token.missing=\u672A\u63D0\u4F9B\u767B\u5F55\u51ED\u8BC1 +# JWT相关 +jwt.token.expired=登录已过期,请重新登录 +jwt.token.invalid=无效的登录凭证 +jwt.token.missing=未提供登录凭证 -# \u89D2\u8272\u76F8\u5173\u9519\u8BEF\u6D88\u606F -role.not.found=\u89D2\u8272\u4E0D\u5B58\u5728 -role.code.exists=\u89D2\u8272\u7F16\u7801"{0}"\u5DF2\u5B58\u5728 -role.name.exists=\u89D2\u8272\u540D\u79F0"{0}"\u5DF2\u5B58\u5728 -role.in.use=\u89D2\u8272\u6B63\u5728\u4F7F\u7528\u4E2D\uFF0C\u65E0\u6CD5\u5220\u9664 -role.admin.cannot.delete=\u4E0D\u80FD\u5220\u9664\u8D85\u7EA7\u7BA1\u7406\u5458\u89D2\u8272 -role.admin.cannot.update=\u4E0D\u80FD\u4FEE\u6539\u8D85\u7EA7\u7BA1\u7406\u5458\u89D2\u8272 -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 +# 角色相关错误消息 +role.not.found=角色不存在 +role.code.exists=角色编码"{0}"已存在 +role.name.exists=角色名称"{0}"已存在 +role.in.use=角色正在使用中,无法删除 +role.admin.cannot.delete=不能删除超级管理员角色 +role.admin.cannot.update=不能修改超级管理员角色 +role.tag.name.exists=标签名称已存在 +role.tag.not.found=标签不存在 +role.tag.in.use=标签正在使用中,无法删除 # 部门相关 department.not.found=部门不存在 department.code.exists=部门编码已存在 department.name.exists=部门名称已存在 department.parent.not.found=上级部门不存在 -department.has.children=该部门下有子部门,无法删除 \ No newline at end of file +department.has.children=该部门下有子部门,无法删除 + +# 权限相关 +permission.not.found=权限不存在 +permission.code.exists=权限编码{0}已存在 +permission.name.exists=权限名称{0}已存在 +permission.already.assigned=该权限已分配给角色 +permission.assign.failed=权限分配失败 \ No newline at end of file diff --git a/backend/src/main/resources/messages_zh_CN.properties b/backend/src/main/resources/messages_zh_CN.properties index 1a7584b2..e57a72df 100644 --- a/backend/src/main/resources/messages_zh_CN.properties +++ b/backend/src/main/resources/messages_zh_CN.properties @@ -51,4 +51,11 @@ department.not.found=部门不存在 department.code.exists=部门编码已存在 department.name.exists=部门名称已存在 department.parent.not.found=上级部门不存在 -department.has.children=该部门下有子部门,无法删除 \ No newline at end of file +department.has.children=该部门下有子部门,无法删除 + +# Permission messages +permission.not.found=权限不存在 +permission.code.exists=权限编码 {0} 已存在 +permission.name.exists=权限名称 {0} 已存在 +permission.already.assigned=该权限已分配给角色 +permission.assign.failed=权限分配失败 \ No newline at end of file