Bläddra i källkod

feat:部门、部门与用户关系迁移本地实现

wangbo 2 år sedan
förälder
incheckning
2ba0e5434d
24 ändrade filer med 1030 tillägg och 24 borttagningar
  1. 7 19
      smsb-customer-manager-adapter/src/main/java/com/inspur/customer/web/controller/keyclaok/KeycloakController.java
  2. 75 0
      smsb-customer-manager-adapter/src/main/java/com/inspur/customer/web/controller/org/SmsbDepartmentController.java
  3. 66 2
      smsb-customer-manager-app/src/main/java/com/inspur/customer/service/keycloak/KeycloakServiceImpl.java
  4. 208 0
      smsb-customer-manager-app/src/main/java/com/inspur/customer/service/org/SmsbDepartmentServiceImpl.java
  5. 48 0
      smsb-customer-manager-app/src/main/java/com/inspur/customer/service/org/SmsbDepartmentUserServiceImpl.java
  6. 42 3
      smsb-customer-manager-client/src/main/java/com/inspur/customer/client/keycloak/KeycloakService.java
  7. 94 0
      smsb-customer-manager-client/src/main/java/com/inspur/customer/client/org/SmsbDepartmentService.java
  8. 37 0
      smsb-customer-manager-client/src/main/java/com/inspur/customer/client/org/SmsbDepartmentUserService.java
  9. 15 0
      smsb-customer-manager-client/src/main/java/com/inspur/customer/constant/Constant.java
  10. 24 0
      smsb-customer-manager-client/src/main/java/com/inspur/customer/object/org/OperationAuthority.java
  11. 29 0
      smsb-customer-manager-client/src/main/java/com/inspur/customer/object/org/SmsbDepartmentAdd.java
  12. 74 0
      smsb-customer-manager-client/src/main/java/com/inspur/customer/object/org/SmsbDepartmentCO.java
  13. 22 0
      smsb-customer-manager-client/src/main/java/com/inspur/customer/object/org/SmsbDepartmentCmd.java
  14. 30 0
      smsb-customer-manager-client/src/main/java/com/inspur/customer/object/org/SmsbDepartmentUpdate.java
  15. 23 0
      smsb-customer-manager-client/src/main/java/com/inspur/customer/object/org/SmsbRegrouping.java
  16. 37 0
      smsb-customer-manager-client/src/main/java/com/inspur/customer/object/org/SmsbUserAdd.java
  17. 10 0
      smsb-customer-manager-infrastructure/pom.xml
  18. 28 0
      smsb-customer-manager-infrastructure/src/main/java/com/inspur/customer/infrastructure/convertor/SmsbDepartmentConvertor.java
  19. 14 0
      smsb-customer-manager-infrastructure/src/main/java/com/inspur/customer/infrastructure/mapper/org/SmsbDepartmentMapper.java
  20. 15 0
      smsb-customer-manager-infrastructure/src/main/java/com/inspur/customer/infrastructure/mapper/org/SmsbDepartmentUserMapper.java
  21. 88 0
      smsb-customer-manager-infrastructure/src/main/java/com/inspur/customer/infrastructure/object/org/SmsbDepartmentDO.java
  22. 34 0
      smsb-customer-manager-infrastructure/src/main/java/com/inspur/customer/infrastructure/object/org/SmsbDepartmentUserDO.java
  23. 5 0
      smsb-customer-manager-infrastructure/src/main/resources/mapper/org/SmsbDepartmentMapper.xml
  24. 5 0
      smsb-customer-manager-infrastructure/src/main/resources/mapper/org/SmsbDepartmentUserMapper.xml

+ 7 - 19
smsb-customer-manager-adapter/src/main/java/com/inspur/customer/web/controller/keyclaok/KeycloakController.java

@@ -23,6 +23,7 @@ import org.springframework.scheduling.annotation.Scheduled;
 import org.springframework.util.CollectionUtils;
 import org.springframework.web.bind.annotation.*;
 
+import java.util.Collections;
 import java.util.List;
 import java.util.Objects;
 
@@ -109,19 +110,6 @@ public class KeycloakController {
         return keycloakService.removeGroup(id);
     }
 
-    @PostMapping("/admin/users")
-    public Response addKeyClaokUser(@RequestBody UserRepresentation userRepresentation){
-        if(StringUtils.isEmpty(userRepresentation.getUsername())){
-            return Response.buildFailure("500","userName不能为空!");
-        }
-        if(CollectionUtils.isEmpty(userRepresentation.getGroups())){
-            return Response.buildFailure("500","groups不能为空!");
-        }
-        if(CollectionUtils.isEmpty(userRepresentation.getCredentials())){
-            return Response.buildFailure("500","credentials不能为空!");
-        }
-        return keycloakService.addKeyClaokUser(userRepresentation);
-    }
 
     @PutMapping("/admin/users/{userId}")
     public Response enableSwitch(@PathVariable("userId") String userId, @RequestBody SwitchDTO switchDTO){
@@ -145,12 +133,6 @@ public class KeycloakController {
         return keycloakService.removeUser(userId);
     }
 
-    @PutMapping("/admin/users/{userId}/groups/{groupId}")
-    public Response regrouping(@PathVariable("userId")String userId,
-                               @PathVariable("groupId")String groupId){
-        return keycloakService.regrouping(userId , groupId);
-    }
-
     @PutMapping("/admin/users/role/configure")
     public Response roleMapping(@RequestBody UsersRoleMappingDTO ssersRoleMappingDTO){
         return keycloakService.roleMapping(ssersRoleMappingDTO);
@@ -188,4 +170,10 @@ public class KeycloakController {
         return keycloakService.removeGroup(id);
     }
 
+
+    @PostMapping("/super/admin/test")
+    public Response keycloakTest(@RequestBody UserRepresentation userRepresentation){
+        return SingleResponse.of(keycloakService.getUserListByIds("inspur" , Collections.singletonList("f3f27e4b-8dee-4168-97ad-69392ef68af2")));
+    }
+
 }

+ 75 - 0
smsb-customer-manager-adapter/src/main/java/com/inspur/customer/web/controller/org/SmsbDepartmentController.java

@@ -0,0 +1,75 @@
+package com.inspur.customer.web.controller.org;
+
+import com.alibaba.cola.dto.Response;
+import com.alibaba.cola.dto.SingleResponse;
+import com.inspur.customer.client.org.SmsbDepartmentService;
+import com.inspur.customer.object.org.*;
+import org.apache.dubbo.config.annotation.DubboReference;
+import org.springframework.web.bind.annotation.*;
+
+import javax.validation.Valid;
+import java.util.Collections;
+
+/**
+ * @Author wangbo13
+ * @Date 2022/11/25 15:09
+ * @Version 1.0
+ */
+@RestController
+public class SmsbDepartmentController {
+
+    @DubboReference
+    private SmsbDepartmentService departmentService;
+
+    @PostMapping("/admin/department")
+    public Response addDepartment(@RequestHeader String userId, @Valid @RequestBody SmsbDepartmentAdd smsbDepartmentAdd){
+        Response checkResult = departmentService.checkOperationAuthority(userId, smsbDepartmentAdd.getTenant());
+        if(!checkResult.isSuccess()){return checkResult;}
+        return departmentService.addDepartment(userId ,smsbDepartmentAdd);
+    }
+
+    @DeleteMapping("/admin/department/{id}")
+    public Response DeleteDepartment(@RequestHeader String userId , @PathVariable("id")Long id){
+        Response checkResponse = departmentService.checkOperationAuthority(userId, departmentService.getOneById(id).getTenant());
+        if(!checkResponse.isSuccess()){return checkResponse;}
+        departmentService.deleteDepartment(userId , Collections.singletonList(id));
+        return SingleResponse.buildSuccess();
+    }
+
+    @PutMapping("/admin/department")
+    public Response updateDepartment(@RequestHeader String userId , @Valid @RequestBody SmsbDepartmentUpdate departmentUpdate){
+        Response checkResponse = departmentService.checkOperationAuthority(userId, departmentService.getOneById(departmentUpdate.getId()).getTenant());
+        if(!checkResponse.isSuccess()){return checkResponse;}
+        return departmentService.updateDepartment(userId , departmentUpdate);
+    }
+
+    @PostMapping("/admin/department/list")
+    public Response queryDepartmentList(@RequestHeader String userId , @Valid @RequestBody OperationAuthority operationAuthority){
+        Response checkResponse = departmentService.checkOperationAuthority(userId, operationAuthority.getTenant());
+        if(!checkResponse.isSuccess()){return checkResponse;}
+        return departmentService.queryDepartmentList(operationAuthority.getTenant());
+    }
+
+    @PostMapping("/admin/department/user/list")
+    public Response queryDepartmentUserList(@RequestHeader String userId , @Valid @RequestBody SmsbDepartmentCmd departmentCmd){
+        Response checkResponse = departmentService.checkOperationAuthority(userId, departmentCmd.getTenant());
+        if(!checkResponse.isSuccess()){return checkResponse;}
+        return departmentService.queryDepartmentUserList(departmentCmd);
+    }
+
+    @PostMapping("/admin/users")
+    public Response addKeyClaokUser(@RequestHeader String userId ,@Valid @RequestBody SmsbUserAdd smsbUserAdd){
+        Response checkResponse = departmentService.checkOperationAuthority(userId, smsbUserAdd.getTenant());
+        if(!checkResponse.isSuccess()){return checkResponse;}
+        return departmentService.addKeyClaokUser(userId ,smsbUserAdd);
+    }
+
+    @PutMapping("/admin/users/regrouping")
+    public Response regrouping(@RequestHeader String userId,
+                               @Valid @RequestBody SmsbRegrouping smsbRegrouping){
+        Response checkResponse = departmentService.checkOperationAuthority(userId, smsbRegrouping.getTenant());
+        if(!checkResponse.isSuccess()){return checkResponse;}
+        return departmentService.regrouping(smsbRegrouping);
+    }
+
+}

+ 66 - 2
smsb-customer-manager-app/src/main/java/com/inspur/customer/service/keycloak/KeycloakServiceImpl.java

@@ -265,8 +265,34 @@ public class KeycloakServiceImpl implements KeycloakService {
     }
 
     @Override
-    public Response addKeyClaokUser(UserRepresentation userRepresentation) {
-        return SingleResponse.of(realmResource.users().create(userRepresentation).getDate());
+    public SingleResponse addKeyClaokUser(String userName , String tenant , List<CredentialRepresentation> credentials) {
+        UserRepresentation userRepresentation = new UserRepresentation();
+        userRepresentation.setUsername(userName);
+        userRepresentation.setGroups(Collections.singletonList(tenant));
+        userRepresentation.setEnabled(Boolean.TRUE);
+        userRepresentation.setCredentials(credentials);
+        if(Objects.nonNull(getUserIdByName(userRepresentation.getUsername()))){
+            return SingleResponse.buildFailure("400","该用户名已存在!");
+        }
+        int status = realmResource.users().create(userRepresentation).getStatus();
+        if(status != 201){
+            return SingleResponse.buildFailure("400","账号创建失败!");
+        }
+        return SingleResponse.of(getUserIdByName(userRepresentation.getUsername()));
+    }
+
+    /**
+     * 通过用户名获取用户id
+     *
+     * @param username
+     * @return
+     */
+    private String getUserIdByName(String username){
+        Optional<String> optional = realmResource.users().search(username)
+            .stream().filter(user -> user.getUsername().equals(username))
+            .map(i -> i.getId())
+            .findFirst();
+        return optional.isEmpty()?null:optional.get();
     }
 
     @Override
@@ -347,4 +373,42 @@ public class KeycloakServiceImpl implements KeycloakService {
     public Response addKeyclaokTenant(GroupRepresentation groupRepresentation) {
         return SingleResponse.of(realmResource.groups().add(groupRepresentation).getDate());
     }
+
+    @Override
+    public Boolean isExitTargetRole(String userId ,String role) {
+        List<String> roleList = realmResource.users().get(userId).roles().realmLevel().listAll()
+            .stream().map(i -> i.getName()).collect(Collectors.toList());
+        return roleList.contains(role);
+    }
+
+    @Override
+    @Cacheable(value = "msr:user:tenant", key = "#userId")
+    public String queryUserTenant(String userId) {
+        List<GroupRepresentation> groupList = realmResource.users().get(userId).groups()
+            .stream()
+            .sorted(Comparator.comparing(i -> i.getPath().length()))
+            .collect(Collectors.toList());
+        return CollectionUtils.isEmpty(groupList) ? null : groupList.stream().findFirst().get().getPath();
+    }
+
+    @Override
+    public Boolean addAttributesByUserId(String userId, String key, List<String> values) {
+        UserResource userResource = realmResource.users().get(userId);
+        UserRepresentation user = userResource.toRepresentation();
+        Map<String, List<String>> attributes = Optional.ofNullable(user.getAttributes()).orElse(new HashMap<>());
+        attributes.put(key ,values);
+        user.setAttributes(attributes);
+        userResource.update(user);
+        return Boolean.TRUE;
+    }
+
+    @Override
+    public List<UserRepresentation> getUserListByIds(String tenant ,List<String> userId) {
+        return realmResource.groups()
+            .group(realmResource.getGroupByPath(tenant).getId())
+            .members()
+            .stream()
+            .filter(i -> userId.contains(i.getId()))
+            .collect(Collectors.toList());
+    }
 }

+ 208 - 0
smsb-customer-manager-app/src/main/java/com/inspur/customer/service/org/SmsbDepartmentServiceImpl.java

@@ -0,0 +1,208 @@
+package com.inspur.customer.service.org;
+
+import com.alibaba.cola.dto.Response;
+import com.alibaba.cola.dto.SingleResponse;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.google.common.collect.Lists;
+import com.inspur.customer.client.keycloak.KeycloakService;
+import com.inspur.customer.client.org.SmsbDepartmentService;
+import com.inspur.customer.client.org.SmsbDepartmentUserService;
+import com.inspur.customer.constant.Constant;
+import com.inspur.customer.infrastructure.convertor.SmsbDepartmentConvertor;
+import com.inspur.customer.infrastructure.mapper.org.SmsbDepartmentMapper;
+import com.inspur.customer.infrastructure.object.org.SmsbDepartmentDO;
+import com.inspur.customer.object.org.*;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.dubbo.config.annotation.DubboReference;
+import org.apache.dubbo.config.annotation.DubboService;
+import org.springframework.beans.BeanUtils;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.util.CollectionUtils;
+
+import java.time.LocalDateTime;
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+import java.util.stream.Collectors;
+
+/**
+ * @Author wangbo13
+ * @Date 2022/11/25 14:58
+ * @Version 1.0
+ */
+@Slf4j
+@DubboService(interfaceClass = SmsbDepartmentService.class)
+public class SmsbDepartmentServiceImpl extends ServiceImpl<SmsbDepartmentMapper , SmsbDepartmentDO> implements SmsbDepartmentService {
+
+    @DubboReference
+    private SmsbDepartmentUserService departmentUserService;
+    @DubboReference
+    private KeycloakService service;
+    @DubboReference
+    private SmsbDepartmentUserService userService;
+
+    @Override
+    public Response addDepartment(String userId , SmsbDepartmentAdd smsbDepartmentAdd) {
+        List<SmsbDepartmentDO> departments = this.list(new LambdaQueryWrapper<>(SmsbDepartmentDO.class)
+            .eq(SmsbDepartmentDO::getTenant, smsbDepartmentAdd.getTenant())
+            .eq(SmsbDepartmentDO::getMark, smsbDepartmentAdd.getMark()));
+        if(!CollectionUtils.isEmpty(departments)){return Response.buildFailure("500",
+            "部门标识["+smsbDepartmentAdd.getMark()+"]在租户["+smsbDepartmentAdd.getTenant()+"]中已存在!");}
+        SmsbDepartmentDO department = SmsbDepartmentConvertor.toDataObjectForCreate(userId, smsbDepartmentAdd);
+        department.setPath(pathFactory(smsbDepartmentAdd.getParentId(),smsbDepartmentAdd.getMark()));
+        department.setOrderNo(orderNmFactory(smsbDepartmentAdd.getParentId()));
+        super.save(department);
+        return SingleResponse.of(department);
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public void deleteDepartment(String userId, List<Long> ids) {
+        super.update(new LambdaUpdateWrapper<>(SmsbDepartmentDO.class)
+            .set(SmsbDepartmentDO::getIsDel , 1)
+            .set(SmsbDepartmentDO::getUpdateBy , userId)
+            .set(SmsbDepartmentDO::getUpdateTime , LocalDateTime.now())
+            .in(SmsbDepartmentDO::getId , ids));
+        List<SmsbDepartmentDO> nextDepartment = super.list(new LambdaQueryWrapper<>(SmsbDepartmentDO.class)
+            .in(SmsbDepartmentDO::getParentId, ids));
+        if(!CollectionUtils.isEmpty(nextDepartment)){
+            deleteDepartment(userId , nextDepartment.stream().map(i -> i.getId()).collect(Collectors.toList()));
+        }
+    }
+
+    @Override
+    public Response updateDepartment(String userId, SmsbDepartmentUpdate departmentUpdate) {
+        boolean flag = super.update(new LambdaUpdateWrapper<>(SmsbDepartmentDO.class)
+            .set(StringUtils.isNotBlank(departmentUpdate.getName()), SmsbDepartmentDO::getName, departmentUpdate.getName())
+            .set(SmsbDepartmentDO::getUpdateBy, userId)
+            .set(SmsbDepartmentDO::getUpdateTime, LocalDateTime.now())
+            .eq(SmsbDepartmentDO::getId, departmentUpdate.getId()));
+        return flag ? Response.buildSuccess() : Response.buildFailure("500","部门更新失败!");
+    }
+
+    /**
+     * 获取当前部门路径
+     *
+     * @param parentId 父节点id(可为空)
+     * @param mark 当前节点名称
+     * @return 当前路径
+     */
+    private String pathFactory(Long parentId , String mark){
+        if(Objects.isNull(parentId)){
+            return Constant.OBLIQUE_LINE.concat(mark);
+        }else{
+            SmsbDepartmentDO department = super.getById(parentId);
+            return pathFactory(department.getParentId() , department.getMark().concat(Constant.OBLIQUE_LINE).concat(mark));
+        }
+    }
+
+    /**
+     * 获取序号
+     *
+     * @param parentId
+     * @return
+     */
+    private Integer orderNmFactory(Long parentId){
+        if(Objects.isNull(parentId)) return 1;
+        SmsbDepartmentDO department = super.getOne(new LambdaQueryWrapper<>(SmsbDepartmentDO.class)
+            .eq(SmsbDepartmentDO::getParentId, parentId)
+            .orderByDesc(SmsbDepartmentDO::getOrderNo)
+            .last("limit 1"));
+        return Objects.isNull(department)?1:department.getOrderNo()+1;
+    }
+
+    @Override
+    public Response queryDepartmentList(String tenant) {
+        SmsbDepartmentDO department = super.getOne(new LambdaQueryWrapper<>(SmsbDepartmentDO.class)
+            .eq(SmsbDepartmentDO::getTenant, tenant)
+            .isNull(SmsbDepartmentDO::getParentId)
+            .last("LIMIT 1"));
+        SmsbDepartmentCO smsbDepartmentCO = new SmsbDepartmentCO();
+        BeanUtils.copyProperties(department , smsbDepartmentCO);
+        smsbDepartmentCO.setChildren(this.getChilde(department.getId()));
+        return SingleResponse.of(smsbDepartmentCO);
+    }
+
+    @Override
+    public Response queryDepartmentUserList(SmsbDepartmentCmd departmentCmd) {
+        List<Long> departmentIds = super.list(new LambdaQueryWrapper<>(SmsbDepartmentDO.class)
+                .eq(SmsbDepartmentDO::getTenant, departmentCmd.getTenant())
+                .eq(Objects.nonNull(departmentCmd.getDepartmentId()), SmsbDepartmentDO::getId, departmentCmd.getDepartmentId()))
+            .stream().map(i -> i.getId())
+            .collect(Collectors.toList());
+        List<String> userIds = departmentUserService.queryUserIdByDeprIds(departmentIds);
+        return SingleResponse.of(service.getUserListByIds(departmentCmd.getTenant() ,userIds));
+    }
+
+    private List<SmsbDepartmentCO> getChilde(Long id){
+        List<SmsbDepartmentDO> childList = this.list(new LambdaQueryWrapper<>(SmsbDepartmentDO.class)
+            .eq(SmsbDepartmentDO::getParentId, id));
+        List<SmsbDepartmentCO> finalChilds = Lists.newArrayList();
+        childList.forEach(child ->{
+            SmsbDepartmentCO smsbDepartmentCO = new SmsbDepartmentCO();
+            BeanUtils.copyProperties(child , smsbDepartmentCO);
+            smsbDepartmentCO.setChildren(this.getChilde(child.getId()));
+            finalChilds.add(smsbDepartmentCO);
+        });
+        return finalChilds;
+    }
+
+    /**
+     * 鉴权
+     *
+     * @param tenant
+     * @param userId
+     * @return
+     */
+    @Override
+    public Response checkOperationAuthority(String userId , String tenant){
+        String real = service.queryUserTenant(userId);
+        if(service.isExitTargetRole(userId ,Constant.SUPER_ADMIN) ||
+            (StringUtils.isNotEmpty(real) && real.equals(tenant) && service.isExitTargetRole(userId , Constant.ROLE_ADMIN))){
+            return Response.buildSuccess();
+        }
+        return Response.buildFailure("401","无权操作!");
+    }
+
+    @Override
+    public SmsbDepartmentCO getOneById(Long id) {
+        SmsbDepartmentDO department = super.getById(id);
+        SmsbDepartmentCO departmentDO = new SmsbDepartmentCO();
+        BeanUtils.copyProperties(department , departmentDO);
+        return departmentDO;
+    }
+
+    @Override
+    public Response addKeyClaokUser(String userId ,SmsbUserAdd smsbUserAdd) {
+        // 1、keycloak新增账号
+        SingleResponse addUserResponse = service.addKeyClaokUser(smsbUserAdd.getUsername(),smsbUserAdd.getTenant() ,smsbUserAdd.getCredentials());
+        if(!addUserResponse.isSuccess()){return addUserResponse;}
+        String addUserId = (String)addUserResponse.getData();
+        log.info("new user id:{}",addUserId);
+        // 2、是否传递所属部门,不传递不做处理
+        if(Objects.nonNull(smsbUserAdd.getDepartmentId())){
+            // 3、保存用户与部门关系
+            userService.addUserDepartment(addUserId , smsbUserAdd.getDepartmentId());
+            // 4、将部门信息写入keucloak的attibute中
+            service.addAttributesByUserId(addUserId , "org" , Collections.singletonList(super.getById(smsbUserAdd.getDepartmentId()).getPath()));
+        }
+        return SingleResponse.of(addUserId);
+    }
+
+    @Override
+    public Response regrouping(SmsbRegrouping smsbRegrouping) {
+        // 1、清空原绑定关系,建立新绑定关系
+        Boolean result = departmentUserService.clearAndCreateRelation(smsbRegrouping.getUserId(), smsbRegrouping.getDepartmentId());
+        // 2、更新attribute
+        if(result){
+            service.addAttributesByUserId(smsbRegrouping.getUserId() , "org" , Collections.singletonList(
+                super.getById(smsbRegrouping.getDepartmentId()).getPath()));
+            return Response.buildSuccess();
+        }else{
+            return Response.buildFailure("500","用户重分组失败!");
+        }
+    }
+}

+ 48 - 0
smsb-customer-manager-app/src/main/java/com/inspur/customer/service/org/SmsbDepartmentUserServiceImpl.java

@@ -0,0 +1,48 @@
+package com.inspur.customer.service.org;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.google.common.collect.Lists;
+import com.inspur.customer.client.org.SmsbDepartmentUserService;
+import com.inspur.customer.infrastructure.mapper.org.SmsbDepartmentUserMapper;
+import com.inspur.customer.infrastructure.object.org.SmsbDepartmentUserDO;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.dubbo.config.annotation.DubboService;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * @Author wangbo13
+ * @Date 2022/11/25 15:06
+ * @Version 1.0
+ */
+@Slf4j
+@DubboService(interfaceClass = SmsbDepartmentUserService.class)
+public class SmsbDepartmentUserServiceImpl extends ServiceImpl<SmsbDepartmentUserMapper, SmsbDepartmentUserDO> implements  SmsbDepartmentUserService{
+
+    @Override
+    public Boolean addUserDepartment(String userId, Long departmentId) {
+        SmsbDepartmentUserDO userRelation = new SmsbDepartmentUserDO();
+        userRelation.setUserId(userId);
+        userRelation.setDepartmentId(departmentId);
+        return super.save(userRelation);
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public Boolean clearAndCreateRelation(String userId, Long departmentId) {
+        super.remove(new LambdaQueryWrapper<>(SmsbDepartmentUserDO.class).eq(SmsbDepartmentUserDO::getUserId ,userId));
+        return this.addUserDepartment(userId ,departmentId);
+    }
+
+    @Override
+    public List<String> queryUserIdByDeprIds(List<Long> departments) {
+        return super.list(new LambdaQueryWrapper<>(SmsbDepartmentUserDO.class)
+            .in(SmsbDepartmentUserDO::getDepartmentId , departments))
+            .stream().map(j -> j.getUserId())
+            .distinct()
+            .collect(Collectors.toList());
+    }
+}

+ 42 - 3
smsb-customer-manager-client/src/main/java/com/inspur/customer/client/keycloak/KeycloakService.java

@@ -1,5 +1,6 @@
 package com.inspur.customer.client.keycloak;
 import com.alibaba.cola.dto.Response;
+import com.alibaba.cola.dto.SingleResponse;
 import com.inspur.customer.object.keycloak.KeycloakUserCO;
 import com.inspur.customer.object.keycloak.UsersRoleMappingDTO;
 import com.inspur.customer.object.wechat.Pair;
@@ -114,12 +115,14 @@ public interface KeycloakService {
     Response removeGroup(String id);
 
     /**
-     * 添加用户到某部门
+     * 添加用户
      *
-     * @param userRepresentation
+     * @param userName
+     * @param tenant
+     * @param credentials
      * @return
      */
-    Response addKeyClaokUser(UserRepresentation userRepresentation);
+    SingleResponse addKeyClaokUser(String userName ,String tenant , List<CredentialRepresentation> credentials);
 
     /**
      * 更新用户信息
@@ -180,4 +183,40 @@ public interface KeycloakService {
      * @return
      */
     Response addKeyclaokTenant(GroupRepresentation groupRepresentation);
+
+    /**
+     * 判断用户是否具有某角色
+     *
+     * @param userId
+     * @param role
+     * @return
+     */
+    Boolean isExitTargetRole(String userId ,String role);
+
+    /**
+     * 获取用户所属租户
+     *
+     * @param userId
+     * @return 租户
+     */
+    String queryUserTenant(String userId);
+
+    /**
+     * 新增或修改用户attributes
+     *
+     * @param userId
+     * @param key key
+     * @param values values
+     * @return if success
+     */
+    Boolean addAttributesByUserId(String userId , String key , List<String> values);
+
+    /**
+     * 获取用户列表
+     *
+     * @param tenant
+     * @param userId
+     * @return
+     */
+    List<UserRepresentation> getUserListByIds(String tenant ,List<String> userId);
 }

+ 94 - 0
smsb-customer-manager-client/src/main/java/com/inspur/customer/client/org/SmsbDepartmentService.java

@@ -0,0 +1,94 @@
+package com.inspur.customer.client.org;
+
+import com.alibaba.cola.dto.Response;
+import com.inspur.customer.object.org.*;
+import org.keycloak.representations.idm.UserRepresentation;
+
+import java.util.List;
+
+/**
+ * @Author wangbo13
+ * 需要检验用户是否租户权限,租户是否一致
+ * 或是否具备超级用户权限
+ *
+ * @Date 2022/11/25 14:57
+ * @Version 1.0
+ */
+public interface SmsbDepartmentService {
+
+    /**
+     * 新增部门
+     *
+     * @param userId
+     * @param smsbDepartmentAdd
+     * @return
+     */
+    Response addDepartment(String userId , SmsbDepartmentAdd smsbDepartmentAdd);
+
+    /**
+     * 删除部门
+     *
+     * @param userId
+     * @param ids
+     */
+    void deleteDepartment(String userId , List<Long> ids);
+
+    /**
+     * 修改部门
+     *
+     * @param userId
+     * @param departmentUpdate
+     * @return
+     */
+    Response updateDepartment(String userId , SmsbDepartmentUpdate departmentUpdate);
+
+    /**
+     * 获取部门树
+     *
+     * @param tenant
+     * @return
+     */
+    Response queryDepartmentList(String tenant);
+
+    /**
+     * 获取员工列表
+     *
+     * @param departmentCmd
+     * @return
+     */
+    Response queryDepartmentUserList(SmsbDepartmentCmd departmentCmd);
+
+    /**
+     * 检查用户是否超级管理员以及该租户权限
+     *
+     * @param userId
+     * @param tenant
+     * @return
+     */
+    Response checkOperationAuthority(String userId , String tenant);
+
+    /**
+     * 通过id获取一条
+     *
+     * @param id
+     * @return
+     */
+    SmsbDepartmentCO getOneById(Long id);
+
+    /**
+     * 添加用户到某部门
+     *
+     * @param userId
+     * @param smsbUserAdd
+     * @return
+     */
+    Response addKeyClaokUser(String userId ,SmsbUserAdd smsbUserAdd);
+
+    /**
+     * 用户重分组
+     *
+     * @param smsbRegrouping
+     * @return
+     */
+    Response regrouping(SmsbRegrouping smsbRegrouping);
+}

+ 37 - 0
smsb-customer-manager-client/src/main/java/com/inspur/customer/client/org/SmsbDepartmentUserService.java

@@ -0,0 +1,37 @@
+package com.inspur.customer.client.org;
+
+import java.util.List;
+
+/**
+ * @Author wangbo13
+ * @Date 2022/11/25 15:06
+ * @Version 1.0
+ */
+public interface SmsbDepartmentUserService {
+
+    /**
+     * 保存
+     *
+     * @param userId
+     * @param departmentId
+     * @return
+     */
+    Boolean addUserDepartment(String userId , Long departmentId);
+
+    /**
+     * 清空并建立新绑定关系
+     *
+     * @param userId
+     * @param departmentId
+     * @return
+     */
+    Boolean clearAndCreateRelation(String userId, Long departmentId);
+
+    /**
+     * 通过部门id获取用户id
+     *
+     * @param departments
+     * @return
+     */
+    List<String> queryUserIdByDeprIds(List<Long> departments);
+}

+ 15 - 0
smsb-customer-manager-client/src/main/java/com/inspur/customer/constant/Constant.java

@@ -28,4 +28,19 @@ public final class Constant {
      */
     public static final String type = "password";
 
+    /**
+     * 斜线
+     */
+    public static final String OBLIQUE_LINE = "/";
+
+    /**
+     * 超级管理员角色
+     */
+    public static final String SUPER_ADMIN = "ROLE_SUPER_ADMIN";
+
+    /**
+     * 租户管理员角色
+     */
+    public static final String ROLE_ADMIN = "ROLE_ADMIN";
+
 }

+ 24 - 0
smsb-customer-manager-client/src/main/java/com/inspur/customer/object/org/OperationAuthority.java

@@ -0,0 +1,24 @@
+package com.inspur.customer.object.org;
+
+import com.alibaba.cola.dto.Command;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import javax.validation.constraints.NotNull;
+
+/**
+ * @Author wangbo13
+ * @Date 2022/11/30 16:10
+ * @Version 1.0
+ */
+@EqualsAndHashCode(callSuper = true)
+@Data
+public class OperationAuthority extends Command {
+    private static final long serialVersionUID = 9032048848393075367L;
+
+    /**
+     * 租户
+     */
+    @NotNull(message = "tenant不能为空")
+    private String tenant;
+}

+ 29 - 0
smsb-customer-manager-client/src/main/java/com/inspur/customer/object/org/SmsbDepartmentAdd.java

@@ -0,0 +1,29 @@
+package com.inspur.customer.object.org;
+
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import javax.validation.constraints.NotNull;
+
+/**
+ * @Author wangbo13
+ * @Date 2022/11/25 16:16
+ * @Version 1.0
+ */
+@EqualsAndHashCode(callSuper = true)
+@Data
+public class SmsbDepartmentAdd extends OperationAuthority {
+
+    private Long parentId;
+    /**
+     * 部门中文名称
+     */
+    @NotNull(message = "name不能为空")
+    private String name;
+
+    /**
+     * 部门唯一标识
+     */
+    @NotNull(message = "mark不能为空")
+    private String mark;
+}

+ 74 - 0
smsb-customer-manager-client/src/main/java/com/inspur/customer/object/org/SmsbDepartmentCO.java

@@ -0,0 +1,74 @@
+package com.inspur.customer.object.org;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import lombok.Data;
+import java.io.Serializable;
+import java.time.LocalDateTime;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @Author wangbo13
+ * @Date 2022/11/29 18:10
+ * @Version 1.0
+ */
+@Data
+public class SmsbDepartmentCO implements Serializable {
+    private static final long serialVersionUID = 2989462647060311429L;
+
+    private Long id;
+    /**
+     * 父节点id
+     */
+    private Long parentId;
+    /**
+     * 部门中文名称
+     */
+    private String name;
+    /**
+     * 部门唯一标识
+     */
+    private String mark;
+
+    /**
+     * 路径
+     */
+    private String path;
+    /**
+     * 序号
+     */
+    private Integer orderNo;
+
+    /**
+     * 租户
+     */
+    private String tenant;
+
+    /**
+     * 删除标识
+     */
+    private Integer isDel;
+
+    /**
+     * 创建人
+     */
+    private String createBy;
+
+    /**
+     * 创建时间
+     */
+    private LocalDateTime createTime;
+
+    /**
+     * 修改人
+     */
+    private String updateBy;
+
+    /**
+     * 修改时间
+     */
+    private LocalDateTime updateTime;
+
+    @JsonInclude(JsonInclude.Include.NON_NULL)
+    private List<SmsbDepartmentCO> children = new ArrayList<>();
+}

+ 22 - 0
smsb-customer-manager-client/src/main/java/com/inspur/customer/object/org/SmsbDepartmentCmd.java

@@ -0,0 +1,22 @@
+package com.inspur.customer.object.org;
+
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import javax.validation.constraints.NotNull;
+
+/**
+ * @Author wangbo13
+ * @Date 2022/11/29 18:20
+ * @Version 1.0
+ */
+@EqualsAndHashCode(callSuper = true)
+@Data
+public class SmsbDepartmentCmd extends OperationAuthority {
+    private static final long serialVersionUID = 5431163674119912344L;
+
+    /**
+     * 部门id
+     */
+    private Long departmentId;
+}

+ 30 - 0
smsb-customer-manager-client/src/main/java/com/inspur/customer/object/org/SmsbDepartmentUpdate.java

@@ -0,0 +1,30 @@
+package com.inspur.customer.object.org;
+
+import com.alibaba.cola.dto.Command;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import javax.validation.constraints.NotNull;
+
+/**
+ * @Author wangbo13
+ * @Date 2022/11/28 18:20
+ * @Version 1.0
+ */
+@EqualsAndHashCode(callSuper = true)
+@Data
+public class SmsbDepartmentUpdate extends Command {
+    private static final long serialVersionUID = 2058133250023880231L;
+
+    /**
+     * 主键
+     */
+    @NotNull(message = "id不能为空")
+    private Long id;
+
+    /**
+     * 部门名称
+     */
+    @NotNull(message = "name不能为空")
+    private String name;
+}

+ 23 - 0
smsb-customer-manager-client/src/main/java/com/inspur/customer/object/org/SmsbRegrouping.java

@@ -0,0 +1,23 @@
+package com.inspur.customer.object.org;
+
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import javax.validation.constraints.NotNull;
+
+/**
+ * @Author wangbo13
+ * @Date 2022/11/30 16:40
+ * @Version 1.0
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class SmsbRegrouping extends OperationAuthority{
+    private static final long serialVersionUID = 6339187897255504048L;
+
+    @NotNull(message = "userId不能为空")
+    private String userId;
+
+    @NotNull(message = "departmentId不能为空")
+    private Long departmentId;
+}

+ 37 - 0
smsb-customer-manager-client/src/main/java/com/inspur/customer/object/org/SmsbUserAdd.java

@@ -0,0 +1,37 @@
+package com.inspur.customer.object.org;
+
+import com.alibaba.cola.dto.Command;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.keycloak.representations.idm.CredentialRepresentation;
+
+import javax.validation.constraints.NotNull;
+import java.util.List;
+
+/**
+ * @Author wangbo13
+ * @Date 2022/11/30 9:40
+ * @Version 1.0
+ */
+@EqualsAndHashCode(callSuper = true)
+@Data
+public class SmsbUserAdd extends OperationAuthority {
+    private static final long serialVersionUID = 8931489400099446732L;
+
+    /**
+     * 账号
+     */
+    @NotNull(message = "username不能为空")
+    private String username;
+
+    /**
+     * 部门id
+     */
+    private Long departmentId;
+
+    /**
+     * 权证
+     */
+    @NotNull(message = "credentials不能为空")
+    private List<CredentialRepresentation> credentials;
+}

+ 10 - 0
smsb-customer-manager-infrastructure/pom.xml

@@ -26,6 +26,16 @@
             <groupId>mysql</groupId>
             <artifactId>mysql-connector-java</artifactId>
         </dependency>
+        <dependency>
+            <groupId>com.fasterxml.jackson.core</groupId>
+            <artifactId>jackson-annotations</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.inspur</groupId>
+            <artifactId>smsb-customer-manager-client</artifactId>
+            <version>0.0.1-SNAPSHOT</version>
+            <scope>compile</scope>
+        </dependency>
     </dependencies>
 
 </project>

+ 28 - 0
smsb-customer-manager-infrastructure/src/main/java/com/inspur/customer/infrastructure/convertor/SmsbDepartmentConvertor.java

@@ -0,0 +1,28 @@
+package com.inspur.customer.infrastructure.convertor;
+
+import com.inspur.customer.infrastructure.object.org.SmsbDepartmentDO;
+import com.inspur.customer.object.org.SmsbDepartmentAdd;
+import org.springframework.beans.BeanUtils;
+
+import java.time.LocalDateTime;
+
+/**
+ * @Author wangbo13
+ * @Date 2022/11/28 17:08
+ * @Version 1.0
+ */
+public class SmsbDepartmentConvertor {
+    private SmsbDepartmentConvertor() {
+        throw new IllegalStateException("Utility class");
+    }
+
+    public static SmsbDepartmentDO toDataObjectForCreate(String userId ,SmsbDepartmentAdd smsbDepartmentAdd){
+        SmsbDepartmentDO department = new SmsbDepartmentDO();
+        BeanUtils.copyProperties(smsbDepartmentAdd , department);
+        department.setCreateBy(userId);
+        department.setUpdateBy(userId);
+        department.setCreateTime(LocalDateTime.now());
+        department.setUpdateTime(LocalDateTime.now());
+        return department;
+    }
+}

+ 14 - 0
smsb-customer-manager-infrastructure/src/main/java/com/inspur/customer/infrastructure/mapper/org/SmsbDepartmentMapper.java

@@ -0,0 +1,14 @@
+package com.inspur.customer.infrastructure.mapper.org;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.inspur.customer.infrastructure.object.org.SmsbDepartmentDO;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * @Author wangbo13
+ * @Date 2022/11/25 14:49
+ * @Version 1.0
+ */
+@Mapper
+public interface SmsbDepartmentMapper extends BaseMapper<SmsbDepartmentDO> {
+}

+ 15 - 0
smsb-customer-manager-infrastructure/src/main/java/com/inspur/customer/infrastructure/mapper/org/SmsbDepartmentUserMapper.java

@@ -0,0 +1,15 @@
+package com.inspur.customer.infrastructure.mapper.org;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.inspur.customer.infrastructure.object.org.SmsbDepartmentUserDO;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * @Author wangbo13
+ * @Date 2022/11/25 14:49
+ * @Version 1.0
+ */
+@Mapper
+public interface SmsbDepartmentUserMapper extends BaseMapper<SmsbDepartmentUserDO> {
+
+}

+ 88 - 0
smsb-customer-manager-infrastructure/src/main/java/com/inspur/customer/infrastructure/object/org/SmsbDepartmentDO.java

@@ -0,0 +1,88 @@
+package com.inspur.customer.infrastructure.object.org;
+
+import com.baomidou.mybatisplus.annotation.FieldFill;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import lombok.Data;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.io.Serializable;
+import java.time.LocalDateTime;
+
+/**
+ * @Author wangbo13
+ * @Date 2022/11/25 14:23
+ * @Version 1.0
+ */
+@Data
+@TableName("smsb_department")
+public class SmsbDepartmentDO implements Serializable {
+    private static final long serialVersionUID = -2282747602419984961L;
+
+    @TableId
+    private Long id;
+    /**
+     * 父节点id
+     */
+    @TableField("parent_id")
+    private Long parentId;
+    /**
+     * 部门中文名称
+     */
+    private String name;
+    /**
+     * 部门唯一标识
+     */
+    private String mark;
+
+    /**
+     * 路径
+     */
+    private String path;
+    /**
+     * 序号
+     */
+    @TableField("order_no")
+    private Integer orderNo;
+
+    /**
+     * 租户
+     */
+    private String tenant;
+
+    /**
+     * 删除标识
+     */
+    @TableField("is_del")
+    private Integer isDel;
+
+    /**
+     * 创建人
+     */
+    @TableField("create_by")
+    private String createBy;
+
+    /**
+     * 创建时间
+     */
+    @JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
+    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    @TableField(value = "create_time", fill = FieldFill.INSERT)
+    private LocalDateTime createTime;
+
+    /**
+     * 修改人
+     */
+    @TableField("update_by")
+    private String updateBy;
+
+    /**
+     * 修改时间
+     */
+    @JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
+    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    @TableField(value = "update_time", fill = FieldFill.INSERT_UPDATE)
+    private LocalDateTime updateTime;
+}

+ 34 - 0
smsb-customer-manager-infrastructure/src/main/java/com/inspur/customer/infrastructure/object/org/SmsbDepartmentUserDO.java

@@ -0,0 +1,34 @@
+package com.inspur.customer.infrastructure.object.org;
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ * @Author wangbo13
+ * @Date 2022/11/25 14:40
+ * @Version 1.0
+ */
+@Data
+@TableName("smsb_department_user")
+public class SmsbDepartmentUserDO implements Serializable {
+    private static final long serialVersionUID = 814979903754300618L;
+
+    @TableId
+    private Long id;
+
+    /**
+     * 部门id
+     */
+    @TableField("department_id")
+    private Long departmentId;
+
+    /**
+     * 用户id
+     */
+    @TableField("user_id")
+    private String userId;
+}

+ 5 - 0
smsb-customer-manager-infrastructure/src/main/resources/mapper/org/SmsbDepartmentMapper.xml

@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.inspur.customer.infrastructure.mapper.org.SmsbDepartmentMapper">
+
+</mapper>

+ 5 - 0
smsb-customer-manager-infrastructure/src/main/resources/mapper/org/SmsbDepartmentUserMapper.xml

@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.inspur.customer.infrastructure.mapper.org.SmsbDepartmentUserMapper">
+
+</mapper>