Browse Source

提交人员相关接口

lixing 4 years ago
parent
commit
55222b1a0e
77 changed files with 2782 additions and 243 deletions
  1. 7 0
      fm-person/pom.xml
  2. 0 78
      fm-person/src/main/java/com/persagy/fm/common/jms/JmsConfig.java
  3. 26 0
      fm-person/src/main/java/com/persagy/fm/common/jms/MsgBaseHandler.java
  4. 20 0
      fm-person/src/main/java/com/persagy/fm/common/jms/model/BaseMsg.java
  5. 18 0
      fm-person/src/main/java/com/persagy/fm/department/constant/DepJmsTypeConstants.java
  6. 4 6
      fm-person/src/main/java/com/persagy/fm/department/constant/enums/DeptTypeEnum.java
  7. 2 2
      fm-person/src/main/java/com/persagy/fm/department/controller/IDepEnumController.java
  8. 16 0
      fm-person/src/main/java/com/persagy/fm/department/controller/DepartmentController.java
  9. 53 0
      fm-person/src/main/java/com/persagy/fm/department/jms/DepJmsConfig.java
  10. 98 0
      fm-person/src/main/java/com/persagy/fm/department/jms/handler/GroupMsgHandler.java
  11. 31 0
      fm-person/src/main/java/com/persagy/fm/department/jms/model/GroupCreateMsg.java
  12. 31 0
      fm-person/src/main/java/com/persagy/fm/department/jms/model/GroupUpdateMsg.java
  13. 14 3
      fm-person/src/main/java/com/persagy/fm/department/model/ConvertDepartmentTool.java
  14. 4 0
      fm-person/src/main/java/com/persagy/fm/department/model/dto/AddDepartmentDTO.java
  15. 10 10
      fm-person/src/main/java/com/persagy/fm/department/model/dto/QueryDepartmentDTO.java
  16. 7 1
      fm-person/src/main/java/com/persagy/fm/department/model/dto/QueryDepartmentTreeDTO.java
  17. 4 3
      fm-person/src/main/java/com/persagy/fm/department/model/dto/UpdateDepartmentDTO.java
  18. 24 0
      fm-person/src/main/java/com/persagy/fm/department/service/IDepProjectService.java
  19. 8 5
      fm-person/src/main/java/com/persagy/fm/department/service/impl/DepEnumServiceImpl.java
  20. 28 0
      fm-person/src/main/java/com/persagy/fm/department/service/impl/DepProjectServiceImpl.java
  21. 36 18
      fm-person/src/main/java/com/persagy/fm/department/service/impl/DepTreeServiceImpl.java
  22. 88 5
      fm-person/src/main/java/com/persagy/fm/department/service/impl/DepartmentServiceImpl.java
  23. 18 0
      fm-person/src/main/java/com/persagy/fm/person/constant/PersonJmsType.java
  24. 39 0
      fm-person/src/main/java/com/persagy/fm/person/constant/enums/CertificateTypeEnum.java
  25. 65 0
      fm-person/src/main/java/com/persagy/fm/person/controller/PersonController.java
  26. 53 0
      fm-person/src/main/java/com/persagy/fm/person/jms/PersonJmsConfig.java
  27. 95 0
      fm-person/src/main/java/com/persagy/fm/person/jms/handler/AccountMsgHandler.java
  28. 31 0
      fm-person/src/main/java/com/persagy/fm/person/jms/model/AccountCreateMsg.java
  29. 32 0
      fm-person/src/main/java/com/persagy/fm/person/jms/model/AccountUpdateMsg.java
  30. 39 3
      fm-person/src/main/java/com/persagy/fm/person/model/ConvertPersonTool.java
  31. 11 3
      fm-person/src/main/java/com/persagy/fm/person/model/Person.java
  32. 63 22
      fm-person/src/main/java/com/persagy/fm/person/model/dto/AddPersonDTO.java
  33. 40 0
      fm-person/src/main/java/com/persagy/fm/person/model/dto/BatchUpdatePersonDTO.java
  34. 25 0
      fm-person/src/main/java/com/persagy/fm/person/model/dto/NameQuickSearchDTO.java
  35. 12 9
      fm-person/src/main/java/com/persagy/fm/person/model/dto/QueryPersonDTO.java
  36. 65 23
      fm-person/src/main/java/com/persagy/fm/person/model/dto/UpdatePersonDTO.java
  37. 53 13
      fm-person/src/main/java/com/persagy/fm/person/model/vo/ResponsePersonItemVO.java
  38. 12 4
      fm-person/src/main/java/com/persagy/fm/person/model/vo/ResponsePersonListItemVO.java
  39. 21 0
      fm-person/src/main/java/com/persagy/fm/person/model/vo/SimplePersonListItemVO.java
  40. 23 0
      fm-person/src/main/java/com/persagy/fm/person/service/IPersonProjectService.java
  41. 55 0
      fm-person/src/main/java/com/persagy/fm/person/service/IPersonService.java
  42. 28 0
      fm-person/src/main/java/com/persagy/fm/person/service/impl/PersonProjectServiceImpl.java
  43. 45 10
      fm-person/src/main/java/com/persagy/fm/person/service/impl/PersonServiceImpl.java
  44. 73 0
      fm-person/src/main/java/com/persagy/fm/profession/controller/ProfessionController.java
  45. 16 0
      fm-person/src/main/java/com/persagy/fm/profession/dao/ProfessionMapper.java
  46. 74 0
      fm-person/src/main/java/com/persagy/fm/profession/model/ConvertProfessionTool.java
  47. 32 0
      fm-person/src/main/java/com/persagy/fm/profession/model/Profession.java
  48. 32 0
      fm-person/src/main/java/com/persagy/fm/profession/model/dto/AddProfessionDTO.java
  49. 20 0
      fm-person/src/main/java/com/persagy/fm/profession/model/dto/DeleteProfessionDTO.java
  50. 32 0
      fm-person/src/main/java/com/persagy/fm/profession/model/dto/UpdateProfessionDTO.java
  51. 40 0
      fm-person/src/main/java/com/persagy/fm/profession/model/vo/ResponseProfessionItemVO.java
  52. 40 0
      fm-person/src/main/java/com/persagy/fm/profession/model/vo/ResponseProfessionListItemVO.java
  53. 56 0
      fm-person/src/main/java/com/persagy/fm/profession/service/IProfessionService.java
  54. 127 0
      fm-person/src/main/java/com/persagy/fm/profession/service/impl/ProfessionServiceImpl.java
  55. 29 0
      fm-person/src/main/java/com/persagy/fm/saas/project/client/SaasProjectClient.java
  56. 16 0
      fm-person/src/main/java/com/persagy/fm/saas/project/client/fallback/SaasProjectClientFallbackFactory.java
  57. 11 0
      fm-person/src/main/java/com/persagy/fm/saas/project/constant/FeignClientNameConstants.java
  58. 14 0
      fm-person/src/main/java/com/persagy/fm/saas/project/model/dto/QuerySaasAreaDTO.java
  59. 24 0
      fm-person/src/main/java/com/persagy/fm/saas/project/model/vo/ProjectTreeItemVO.java
  60. 14 0
      fm-person/src/main/java/com/persagy/fm/saas/project/model/vo/SaasAreaListItemVO.java
  61. 23 0
      fm-person/src/main/java/com/persagy/fm/saas/project/service/ISaasProjectService.java
  62. 28 0
      fm-person/src/main/java/com/persagy/fm/saas/project/service/impl/SaasProjectServiceImpl.java
  63. 94 0
      fm-person/src/main/java/com/persagy/fm/saas/role/controller/SaasRoleController.java
  64. 74 0
      fm-person/src/main/java/com/persagy/fm/saas/role/model/ConvertSaasRoleTool.java
  65. 55 0
      fm-person/src/main/java/com/persagy/fm/saas/role/model/SaasRole.java
  66. 26 0
      fm-person/src/main/java/com/persagy/fm/saas/role/model/dto/AddSaasRoleDTO.java
  67. 20 0
      fm-person/src/main/java/com/persagy/fm/saas/role/model/dto/DeleteSaasRoleDTO.java
  68. 23 0
      fm-person/src/main/java/com/persagy/fm/saas/role/model/dto/PageQuerySaasRoleDTO.java
  69. 30 0
      fm-person/src/main/java/com/persagy/fm/saas/role/model/dto/UpdateSaasRoleDTO.java
  70. 43 0
      fm-person/src/main/java/com/persagy/fm/saas/role/model/vo/ResponseSaasRoleItemVO.java
  71. 24 0
      fm-person/src/main/java/com/persagy/fm/saas/role/model/vo/ResponseSaasRoleListItemVO.java
  72. 77 0
      fm-person/src/main/java/com/persagy/fm/saas/role/service/ISaasRoleService.java
  73. 207 0
      fm-person/src/main/java/com/persagy/fm/saas/role/service/impl/SaasRoleServiceImpl.java
  74. 4 1
      fm-person/src/main/java/com/persagy/fm/workresume/model/ConvertWorkResumeTool.java
  75. 17 7
      fm-person/src/main/resources/bootstrap.yml
  76. 17 17
      fm-person/src/main/resources/mapper/DepartmentMapper.xml
  77. 16 0
      fm-person/src/main/resources/mapper/ProfessionMapper.xml

+ 7 - 0
fm-person/pom.xml

@@ -71,6 +71,13 @@
             <version>2.5</version>
         </dependency>
 
+        <!-- gson json,java对象互转 -->
+        <dependency>
+            <groupId>com.google.code.gson</groupId>
+            <artifactId>gson</artifactId>
+            <version>2.8.6</version>
+        </dependency>
+
     </dependencies>
 
     <build>

+ 0 - 78
fm-person/src/main/java/com/persagy/fm/common/jms/JmsConfig.java

@@ -1,78 +0,0 @@
-package com.persagy.fm.common.jms;
-
-import com.rabbitmq.client.Channel;
-import org.springframework.amqp.core.*;
-import org.springframework.amqp.rabbit.annotation.RabbitListener;
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-
-import java.io.IOException;
-
-
-/**
- * 消息队列配置类
- *
- * @author lixing
- * @version V1.0 2021/3/17 9:38 上午
- **/
-@Configuration
-public class JmsConfig {
-    /**
-     * 运维平台exchange
-     */
-    @Value("${amqp.exchange.saas}")
-    private String saasExchange;
-
-    /**
-     * 运维平台routingKey
-     */
-    @Value("${amqp.routingKey.saas}")
-    private String saasRoutingKey;
-
-    /**
-     * 运维平台队列
-     */
-    @Value("${amqp.queue.saas}")
-    private String saasQueue;
-
-    @Bean
-    public TopicExchange saasExchange() {
-        return new TopicExchange(saasExchange);
-    }
-
-    @Bean
-    public Queue saasQueue(){
-        return new Queue(saasQueue);
-    }
-
-    @Bean
-    public Binding saasBinding() {
-        return BindingBuilder.bind(saasQueue()).to(saasExchange()).with(saasRoutingKey);
-    }
-
-    /**
-     * 监听saas队列
-     *
-     * @param message 消息体字符串
-     * @param channel 通道对象
-     * @param msg 消息对象
-     * @author lixing
-     * @version V1.0 2021/3/17 9:47 上午
-     */
-    @RabbitListener(queues = "${amqp.queue.saas}")
-    public void process(String message, Channel channel, Message msg) {
-        try {
-            // TODO: 2021/3/17 处理消息
-            // 手动确认消息已消费
-            channel.basicAck(msg.getMessageProperties().getDeliveryTag(),false);
-        } catch (Exception e) {
-            try {
-                // 将消费失败的消息移除消息队列,避免重复消费
-                channel.basicReject(msg.getMessageProperties().getDeliveryTag(),false);
-            } catch (IOException ex) {
-                // TODO: 2021/3/17 消息从队列中移除失败
-            }
-        }
-    }
-}

+ 26 - 0
fm-person/src/main/java/com/persagy/fm/common/jms/MsgBaseHandler.java

@@ -0,0 +1,26 @@
+package com.persagy.fm.common.jms;
+
+import com.google.gson.Gson;
+import com.persagy.fm.common.jms.model.BaseMsg;
+
+/**
+ * 消息处理基类
+ *
+ * @author lixing
+ * @version V1.0 2021/3/18 5:42 下午
+ **/
+public class MsgBaseHandler {
+    /**
+     * 获取消息类型
+     *
+     * @param message rabbitMQ消息
+     * @return 消息类型
+     * @author lixing
+     * @version V1.0 2021/3/18 6:16 下午
+     */
+    public String getMsgType(String message) {
+        Gson gson = new Gson();
+        BaseMsg baseMsg = gson.fromJson(message, BaseMsg.class);
+        return baseMsg.getType();
+    }
+}

+ 20 - 0
fm-person/src/main/java/com/persagy/fm/common/jms/model/BaseMsg.java

@@ -0,0 +1,20 @@
+package com.persagy.fm.common.jms.model;
+
+import lombok.Data;
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * 消息基础类
+ *
+ * @author lixing
+ * @version V1.0 2021/3/18 11:30 上午
+ **/
+@Setter
+@Getter
+public class BaseMsg {
+    /**
+     * 消息类型
+     */
+    private String type;
+}

+ 18 - 0
fm-person/src/main/java/com/persagy/fm/department/constant/DepJmsTypeConstants.java

@@ -0,0 +1,18 @@
+package com.persagy.fm.department.constant;
+
+/**
+ * 部门相关的消息类型
+ *
+ * @author lixing
+ * @version V1.0 2021/3/18 11:32 上午
+ **/
+public class DepJmsTypeConstants {
+    /**
+     * 超级管理员账号创建
+     */
+    public static final String GROUP_CREATE = "groupCreate";
+    /**
+     * 超级管理员账号更新
+     */
+    public static final String GROUP_UPDATE = "groupUpdate";
+}

+ 4 - 6
fm-person/src/main/java/com/persagy/fm/department/constant/enums/DeptTypeEnum.java

@@ -6,20 +6,18 @@ package com.persagy.fm.department.constant.enums;
  * @author lixing
  * @version V1.0 2021/3/12 3:00 下午
  */
-public enum DeptTypeEnum {
+public enum DepTypeEnum {
     /**
      * 部门类型
      */
     GROUP("0", "集团"),
-    CENTER("1", "中心"),
-    AREA("2", "区域"),
-    COMPANY("3", "分公司"),
-    DEPT("4", "部门");
+    COMPANY("1", "公司"),
+    DEPT("2", "部门");
 
     private String type;
     private String desc;
 
-    DeptTypeEnum(String type, String desc) {
+    DepTypeEnum(String type, String desc) {
         this.type = type;
         this.desc = desc;
     }

+ 2 - 2
fm-person/src/main/java/com/persagy/fm/department/controller/IDepEnumController.java

@@ -25,8 +25,8 @@ import java.util.List;
 @RestController
 @Validated
 @RequestMapping("/departments/enums")
-@Api(tags = "部门枚举控制层")
-public class IDepEnumController {
+@Api(tags = "部门枚举")
+public class DepEnumController {
     @Autowired
     IDepEnumService depEnumService;
 

+ 16 - 0
fm-person/src/main/java/com/persagy/fm/department/controller/DepartmentController.java

@@ -6,10 +6,12 @@ import com.persagy.fm.department.model.Department;
 import com.persagy.fm.department.model.vo.ResponseDepartmentItemVO;
 import com.persagy.fm.department.model.vo.ResponseDepartmentListItemVO;
 import com.persagy.fm.department.model.vo.ResponseDepartmentTreeItemVO;
+import com.persagy.fm.department.service.IDepProjectService;
 import com.persagy.fm.department.service.IDepTreeService;
 import com.persagy.fm.department.service.IDepartmentService;
 
 import com.persagy.fm.department.utils.DepDataUtil;
+import com.persagy.fm.saas.project.model.vo.ProjectTreeItemVO;
 import org.springframework.beans.factory.annotation.Autowired;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
@@ -24,6 +26,9 @@ import org.springframework.web.bind.annotation.RestController;
 
 
 import javax.validation.Valid;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLConnection;
 import java.util.List;
 import java.util.Map;
 import java.util.stream.Collectors;
@@ -43,6 +48,8 @@ public class DepartmentController {
     private IDepartmentService departmentService;
     @Autowired
     private IDepTreeService depTreeService;
+    @Autowired
+    private IDepProjectService depProjectService;
 
     @ApiOperation(value = "创建部门")
     @PostMapping("/create")
@@ -130,5 +137,14 @@ public class DepartmentController {
         List<ResponseDepartmentTreeItemVO> responseDepTreeItems = depTreeService.queryDepartmentTree(queryDepartmentTreeDTO);
         return FmResponseUtil.successContent(responseDepTreeItems);
     }
+
+    @ApiOperation(value = "部门项目树")
+    @PostMapping("/projects/tree")
+    public FmResponseContent<List<ProjectTreeItemVO>> queryDepProjectTree(
+            @Valid @RequestBody DeleteDepartmentDTO deleteDepartmentDTO) {
+        List<ProjectTreeItemVO> projectTreeItemVOList = depProjectService.queryDepProjectTree(deleteDepartmentDTO.getId());
+        return FmResponseUtil.successContent(projectTreeItemVOList);
+    }
+
 }
 

+ 53 - 0
fm-person/src/main/java/com/persagy/fm/department/jms/DepJmsConfig.java

@@ -0,0 +1,53 @@
+package com.persagy.fm.department.jms;
+
+import com.rabbitmq.client.Channel;
+import org.springframework.amqp.core.*;
+import org.springframework.amqp.rabbit.annotation.RabbitListener;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+import java.io.IOException;
+
+
+/**
+ * 部门消息队列配置类
+ *
+ * @author lixing
+ * @version V1.0 2021/3/17 9:38 上午
+ **/
+@Configuration
+public class DepJmsConfig {
+    /**
+     * 运维平台exchange
+     */
+    @Value("${dep.amqp.exchange.saas}")
+    private String depSaasExchange;
+
+    /**
+     * 运维平台routingKey
+     */
+    @Value("${dep.amqp.routingKey.saas}")
+    private String depSaasRoutingKey;
+
+    /**
+     * 运维平台队列
+     */
+    @Value("${dep.amqp.queue.saas}")
+    private String depSaasQueue;
+
+    @Bean
+    public TopicExchange depSaasExchange() {
+        return new TopicExchange(depSaasExchange);
+    }
+
+    @Bean
+    public Queue depSaasQueue(){
+        return new Queue(depSaasQueue);
+    }
+
+    @Bean
+    public Binding depSaasBinding() {
+        return BindingBuilder.bind(depSaasQueue()).to(depSaasExchange()).with(depSaasRoutingKey);
+    }
+}

+ 98 - 0
fm-person/src/main/java/com/persagy/fm/department/jms/handler/GroupMsgHandler.java

@@ -0,0 +1,98 @@
+package com.persagy.fm.department.jms.handler;
+
+import com.google.gson.Gson;
+import com.persagy.common.enums.ResponseCode;
+import com.persagy.common.exception.BusinessException;
+import com.persagy.fm.common.jms.MsgBaseHandler;
+import com.persagy.fm.common.model.RequiredParams;
+import com.persagy.fm.common.model.RequiredParamsStorage;
+import com.persagy.fm.department.constant.DepJmsTypeConstants;
+import com.persagy.fm.department.constant.enums.DepTypeEnum;
+import com.persagy.fm.department.constant.enums.ResourceFromEnum;
+import com.persagy.fm.department.jms.model.GroupCreateMsg;
+import com.persagy.fm.department.jms.model.GroupUpdateMsg;
+import com.persagy.fm.department.model.ConvertDepartmentTool;
+import com.persagy.fm.department.model.dto.AddDepartmentDTO;
+import com.persagy.fm.department.service.IDepartmentService;
+import com.rabbitmq.client.Channel;
+import org.springframework.amqp.core.Message;
+import org.springframework.amqp.rabbit.annotation.RabbitListener;
+import org.springframework.beans.factory.annotation.Autowired;
+
+import java.io.IOException;
+
+/**
+ * 集团消息处理类
+ *
+ * @author lixing
+ * @version V1.0 2021/3/18 6:18 下午
+ **/
+public class GroupMsgHandler extends MsgBaseHandler {
+    @Autowired
+    IDepartmentService departmentService;
+
+    /**
+     * 监听saas队列
+     *
+     * @param message 消息体字符串
+     * @param channel 通道对象
+     * @param msg 消息对象
+     * @author lixing
+     * @version V1.0 2021/3/17 9:47 上午
+     */
+    @RabbitListener(queues = "${dep.amqp.queue.saas}")
+    public void process(String message, Channel channel, Message msg) {
+        try {
+            String msgType = getMsgType(message);
+            Gson gson = new Gson();
+            switch (msgType) {
+                case DepJmsTypeConstants.GROUP_CREATE:
+                    GroupCreateMsg groupCreateMsg = gson.fromJson(message, GroupCreateMsg.class);
+                    createGroup(groupCreateMsg);
+                    break;
+                case DepJmsTypeConstants.GROUP_UPDATE:
+                    GroupUpdateMsg groupUpdateMsg = gson.fromJson(message, GroupUpdateMsg.class);
+                    updateGroup(groupUpdateMsg);
+                    break;
+                default:
+                    break;
+            }
+            // 手动确认消息已消费
+            channel.basicAck(msg.getMessageProperties().getDeliveryTag(),false);
+        } catch (Exception e) {
+            try {
+                // 将消费失败的消息移除消息队列,避免重复消费
+                channel.basicReject(msg.getMessageProperties().getDeliveryTag(),false);
+            } catch (IOException ex) {
+                throw new BusinessException(ResponseCode.C0001.getCode(),
+                        "部门消息从队列中移除失败," + ex.getMessage());
+            }
+        }
+    }
+
+    /**
+     * 更新集团
+     * @param groupUpdateMsg 集团更新消息
+     */
+    private void updateGroup(GroupUpdateMsg groupUpdateMsg) {
+
+    }
+
+    /**
+     * 创建集团
+     * @param groupCreateMsg 集团创建消息
+     */
+    private void createGroup(GroupCreateMsg groupCreateMsg) {
+        AddDepartmentDTO addDepartmentDTO = ConvertDepartmentTool.INSTANCE.convert2AddDto(groupCreateMsg);
+        addDepartmentDTO.setType(DepTypeEnum.GROUP.getType());
+        addDepartmentDTO.setResourceFrom(ResourceFromEnum.USER_CREATE.getType());
+        addDepartmentDTO.setFullPath(addDepartmentDTO.getName());
+
+        // 给RequiredParamsStorage赋值,调用接口时,会从RequiredParamsStorage中获取默认参数
+        RequiredParams requiredParams = new RequiredParams(
+                groupCreateMsg.getGroupCode(), "", "", "", groupCreateMsg.getUserId());
+        RequiredParamsStorage.set(requiredParams);
+
+        departmentService.createDepartment(addDepartmentDTO);
+    }
+}

+ 31 - 0
fm-person/src/main/java/com/persagy/fm/department/jms/model/GroupCreateMsg.java

@@ -0,0 +1,31 @@
+package com.persagy.fm.department.jms.model;
+
+import com.persagy.fm.common.jms.model.BaseMsg;
+import lombok.Data;
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * 集团创建消息
+ *
+ * @author lixing
+ * @version V1.0 2021/3/18 11:11 上午
+ **/
+@Setter
+@Getter
+public class GroupCreateMsg extends BaseMsg {
+    /**
+     * 集团编码
+     */
+    private String groupCode;
+
+    /**
+     * 集团名称
+     */
+    private String name;
+
+    /**
+     * 创建人
+     */
+    private String userId;
+}

+ 31 - 0
fm-person/src/main/java/com/persagy/fm/department/jms/model/GroupUpdateMsg.java

@@ -0,0 +1,31 @@
+package com.persagy.fm.department.jms.model;
+
+import com.persagy.fm.common.jms.model.BaseMsg;
+import lombok.Data;
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * 集团更新消息
+ *
+ * @author lixing
+ * @version V1.0 2021/3/18 11:11 上午
+ **/
+@Setter
+@Getter
+public class GroupUpdateMsg extends BaseMsg {
+    /**
+     * 集团编码
+     */
+    private String groupCode;
+
+    /**
+     * 集团名称
+     */
+    private String name;
+
+    /**
+     * 更新人
+     */
+    private String userId;
+}

+ 14 - 3
fm-person/src/main/java/com/persagy/fm/department/model/ConvertDepartmentTool.java

@@ -1,12 +1,12 @@
 package com.persagy.fm.department.model;
 
+import com.persagy.fm.department.jms.model.GroupCreateMsg;
 import com.persagy.fm.department.model.dto.AddDepartmentDTO;
 import com.persagy.fm.department.model.dto.UpdateDepartmentDTO;
 import com.persagy.fm.department.model.vo.ResponseDepartmentItemVO;
 import com.persagy.fm.department.model.vo.ResponseDepartmentListItemVO;
 import com.persagy.fm.department.model.vo.ResponseDepartmentTreeItemVO;
-import org.mapstruct.Mapper;
-import org.mapstruct.MappingTarget;
+import org.mapstruct.*;
 import org.mapstruct.factory.Mappers;
 
 import java.util.List;
@@ -17,7 +17,8 @@ import java.util.List;
  * @author lixing
  * @version V1.0 2021-03-11 15:09:19 2021-03-11 15:09:19
  */
-@Mapper
+@Mapper(nullValueMappingStrategy = NullValueMappingStrategy.RETURN_DEFAULT,
+        nullValueCheckStrategy = NullValueCheckStrategy.ALWAYS)
 public interface ConvertDepartmentTool {
 
     ConvertDepartmentTool INSTANCE = Mappers.getMapper(ConvertDepartmentTool.class);
@@ -92,5 +93,15 @@ public interface ConvertDepartmentTool {
      * @version V1.0 2021/3/12 4:40 下午
      */
     ResponseDepartmentTreeItemVO convert2TreeItemVO(Department department);
+
+    /**
+     * 集团创建消息转换为创建部门入参
+     *
+     * @param groupCreateMsg 集团创建消息
+     * @return 创建部门入参
+     * @author lixing
+     * @version V1.0 2021/3/18 6:38 下午
+     */
+    AddDepartmentDTO convert2AddDto(GroupCreateMsg groupCreateMsg);
 }
 

+ 4 - 0
fm-person/src/main/java/com/persagy/fm/department/model/dto/AddDepartmentDTO.java

@@ -1,9 +1,11 @@
 package com.persagy.fm.department.model.dto;
 
+import com.persagy.fm.common.constant.RegexConstants;
 import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
 
 import javax.validation.constraints.NotNull;
+import javax.validation.constraints.Pattern;
 
 import lombok.Data;
 import org.hibernate.validator.constraints.Length;
@@ -18,6 +20,8 @@ public class AddDepartmentDTO {
     @ApiModelProperty(value = "部门名称", required = true)
     @NotNull(message = "部门名称不能为空")
     @Length(max = 100, message = "部门名称长度不能超过100字")
+    @Pattern(regexp= RegexConstants.NAME_REGEX,
+            message = "部门名称" + RegexConstants.NAME_REGEX_WARNING)
     private String name;
 
     @ApiModelProperty(value = "部门类型", required = true)

+ 10 - 10
fm-person/src/main/java/com/persagy/fm/department/model/dto/QueryDepartmentDTO.java

@@ -11,28 +11,28 @@ import lombok.Data;
 @Data
 @ApiModel(value = "查询部门入参")
 public class QueryDepartmentDTO {
-    @ApiModelProperty(value = "部门名称", required = true)
+    @ApiModelProperty(value = "部门名称")
     private String name;
 
-    @ApiModelProperty(value = "部门类型", required = true)
+    @ApiModelProperty(value = "部门类型")
     private String type;
 
-    @ApiModelProperty(value = "上级部门id", required = true)
+    @ApiModelProperty(value = "上级部门id")
     private Long parentId;
 
-    @ApiModelProperty(value = "数据来源", required = true)
+    @ApiModelProperty(value = "数据来源")
     private String resourceFrom;
 
-//    @ApiModelProperty(value = "负责人", required = true)
+    @ApiModelProperty(value = "部门全路径, 模糊查询")
+    private String fullPath;
+
+//    @ApiModelProperty(value = "负责人")
 //    private String managers;
 //
-//    @ApiModelProperty(value = "部门全路径", required = true)
-//    private String fullPath;
-//
-//    @ApiModelProperty(value = "编制人数", required = true)
+//    @ApiModelProperty(value = "编制人数")
 //    private Integer staffCount;
 //
-//    @ApiModelProperty(value = "是否包含下级部门", required = true)
+//    @ApiModelProperty(value = "是否包含下级部门")
 //    private String hasChildren;
 
 }

+ 7 - 1
fm-person/src/main/java/com/persagy/fm/department/model/dto/QueryDepartmentTreeDTO.java

@@ -4,6 +4,8 @@ import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
 import lombok.Data;
 
+import javax.validation.constraints.Min;
+
 /**
  * @author lixing
  * @version V1.0 2021/3/12 4:31 下午
@@ -11,6 +13,10 @@ import lombok.Data;
 @Data
 @ApiModel(value = "查询部门树入参")
 public class QueryDepartmentTreeDTO {
-    @ApiModelProperty("选中的树节点")
+    @ApiModelProperty(value = "选中的树节点")
     private Long checkedId;
+
+    @ApiModelProperty(value = "需要展示的层级")
+    @Min(value = 1, message = "需要展示的层级最小为1")
+    private Integer showLevel;
 }

+ 4 - 3
fm-person/src/main/java/com/persagy/fm/department/model/dto/UpdateDepartmentDTO.java

@@ -1,9 +1,11 @@
 package com.persagy.fm.department.model.dto;
 
+import com.persagy.fm.common.constant.RegexConstants;
 import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
 
 import javax.validation.constraints.NotNull;
+import javax.validation.constraints.Pattern;
 
 import lombok.Data;
 import org.hibernate.validator.constraints.Length;
@@ -20,16 +22,15 @@ public class UpdateDepartmentDTO {
     private Long id;
 
     @ApiModelProperty(value = "部门名称", required = true)
-    @NotNull(message = "部门名称不能为空")
     @Length(max = 100, message = "部门名称长度不能超过100字")
+    @Pattern(regexp= RegexConstants.NAME_REGEX,
+            message = "部门名称" + RegexConstants.NAME_REGEX_WARNING)
     private String name;
 
     @ApiModelProperty(value = "部门类型", required = true)
-    @NotNull(message = "部门类型不能为空")
     private String type;
 
     @ApiModelProperty(value = "上级部门id", required = true)
-    @NotNull(message = "上级部门id不能为空")
     private String parentId;
 
     @ApiModelProperty(value = "数据来源", required = true)

+ 24 - 0
fm-person/src/main/java/com/persagy/fm/department/service/IDepProjectService.java

@@ -0,0 +1,24 @@
+package com.persagy.fm.department.service;
+
+import com.persagy.fm.saas.project.model.vo.ProjectTreeItemVO;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+/**
+ * 部门关联的项目接口
+ *
+ * @author lixing
+ * @version V1.0 2021/3/22 11:54 上午
+ **/
+public interface IDepProjectService {
+    /**
+     * 获取部门关联的项目树
+     *
+     * @param depId 部门id
+     * @return 部门关联的项目树
+     * @author lixing
+     * @version V1.0 2021/3/22 3:58 下午
+     */
+    List<ProjectTreeItemVO> queryDepProjectTree(Long depId);
+}

+ 8 - 5
fm-person/src/main/java/com/persagy/fm/department/service/impl/DepEnumServiceImpl.java

@@ -1,7 +1,7 @@
 package com.persagy.fm.department.service.impl;
 
 import com.persagy.fm.common.model.vo.EnumVO;
-import com.persagy.fm.department.constant.enums.DeptTypeEnum;
+import com.persagy.fm.department.constant.enums.DepTypeEnum;
 import com.persagy.fm.department.constant.enums.ResourceFromEnum;
 import com.persagy.fm.department.service.IDepEnumService;
 import org.springframework.stereotype.Service;
@@ -20,11 +20,14 @@ import java.util.List;
 public class DepEnumServiceImpl implements IDepEnumService {
     @Override
     public List<EnumVO> queryDepTypeEnum() {
-        List<EnumVO> resultList = new ArrayList<>(DeptTypeEnum.values().length);
-        Arrays.asList(DeptTypeEnum.values()).forEach(deptTypeEnum -> {
+        List<EnumVO> resultList = new ArrayList<>(DepTypeEnum.values().length);
+        Arrays.asList(DepTypeEnum.values()).forEach(depTypeEnum -> {
+            if (depTypeEnum == DepTypeEnum.GROUP) {
+                return;
+            }
             EnumVO enumVO = new EnumVO();
-            enumVO.setKey(deptTypeEnum.getType());
-            enumVO.setValue(deptTypeEnum.getDesc());
+            enumVO.setKey(depTypeEnum.getType());
+            enumVO.setValue(depTypeEnum.getDesc());
             resultList.add(enumVO);
         });
         return resultList;

+ 28 - 0
fm-person/src/main/java/com/persagy/fm/department/service/impl/DepProjectServiceImpl.java

@@ -0,0 +1,28 @@
+package com.persagy.fm.department.service.impl;
+
+import com.persagy.fm.department.service.IDepProjectService;
+import com.persagy.fm.saas.project.model.vo.ProjectTreeItemVO;
+import com.persagy.fm.saas.project.service.ISaasProjectService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+/**
+ * 部门关联的项目service层
+ *
+ * @author lixing
+ * @version V1.0 2021/3/22 11:54 上午
+ **/
+@Service
+public class DepProjectServiceImpl implements IDepProjectService {
+    @Autowired
+    ISaasProjectService saasProjectService;
+    @Override
+    public List<ProjectTreeItemVO> queryDepProjectTree(Long depId) {
+        // 部门id 为 0, 加载整颗区域项目树,否则根据部门id查询部门关联的项目,然后组装项目树
+        // TODO: 2021/3/22 查询部门关联的项目
+        List<String> projectIds = null;
+        return saasProjectService.queryProjectTree(projectIds);
+    }
+}

+ 36 - 18
fm-person/src/main/java/com/persagy/fm/department/service/impl/DepTreeServiceImpl.java

@@ -26,11 +26,6 @@ import java.util.stream.Collectors;
  */
 @Service
 public class DepTreeServiceImpl implements IDepTreeService {
-    /**
-     * 部门树默认显示3级
-     */
-    private static final int SHOW_LEVEL = 3;
-
     @Autowired
     private IDepartmentService departmentService;
 
@@ -46,8 +41,22 @@ public class DepTreeServiceImpl implements IDepTreeService {
             // TODO: 2021/3/9
             return null;
         } else {
-            return initDefaultTreeData();
+            return initDefaultTreeData(getShowLevel(queryDepartmentTreeDTO));
+        }
+    }
+
+    /**
+     * 获取前端传入的需要展示的层级,如果没有传入默认展示为2层
+     *
+     * @param queryDepartmentTreeDTO 部门树查询条件
+     * @return 需要展示的层级
+     */
+    private int getShowLevel(QueryDepartmentTreeDTO queryDepartmentTreeDTO) {
+        Integer showLevel = queryDepartmentTreeDTO.getShowLevel();
+        if (showLevel == null) {
+            showLevel = 2;
         }
+        return showLevel;
     }
 
     /**
@@ -57,15 +66,15 @@ public class DepTreeServiceImpl implements IDepTreeService {
      * @author lixing
      * @version V1.0 2021/3/12 12:00 下午
      */
-    private Map<Integer, List<Department>> initDefaultTreeData() {
-        Map<Integer, List<Department>> levelDepListMap = new HashMap<>(SHOW_LEVEL);
+    private Map<Integer, List<Department>> initDefaultTreeData(Integer showLevel) {
+        Map<Integer, List<Department>> levelDepListMap = new HashMap<>(showLevel);
 
         // TODO: 2021/3/9 根据当前登录人获取根节点
         // 部门树根节点的父节点id
         Long rootParentId = 0L;
         List<Long> rootDeps = Lists.newArrayList(rootParentId);
 
-        return initDefaultTreeData(levelDepListMap, 0, rootDeps);
+        return initDefaultTreeData(levelDepListMap, 0, rootDeps, showLevel);
     }
 
     /**
@@ -74,22 +83,26 @@ public class DepTreeServiceImpl implements IDepTreeService {
      * @param levelDepListMap level -> depList
      * @param level           当前层级
      * @param parentDepIdList 上一层部门Id列表
+     * @param showLevel 前端传入的要展示的层级
      * @return 需要展示的每一层级的部门:level -> depList
      * @author lixing
      * @version V1.0 2021/3/12 12:02 下午
      */
     public Map<Integer, List<Department>> initDefaultTreeData(
-            Map<Integer, List<Department>> levelDepListMap, int level, List<Long> parentDepIdList) {
+            Map<Integer, List<Department>> levelDepListMap,
+            int level,
+            List<Long> parentDepIdList,
+            int showLevel) {
         if (CollectionUtils.isEmpty(parentDepIdList)) {
             return levelDepListMap;
         }
         levelDepListMap.put(level, departmentService.queryDepListByParentIds(parentDepIdList));
 
-        if (level < SHOW_LEVEL) {
+        if (level < showLevel) {
             List<Department> departments = levelDepListMap.get(level);
             departments = departments == null ? Lists.newArrayList() : departments;
             List<Long> depIds = departments.stream().map(Department::getId).collect(Collectors.toList());
-            initDefaultTreeData(levelDepListMap, level + 1, depIds);
+            initDefaultTreeData(levelDepListMap, level + 1, depIds, showLevel);
         }
 
         return levelDepListMap;
@@ -101,12 +114,15 @@ public class DepTreeServiceImpl implements IDepTreeService {
      * @param levelParentIdMap level -> { parentId -> depList }
      * @param treeItem 节点
      * @param level 节点的下一级,例如根节点的下一级为 1
+     * @param showLevel 前端传入的需要展示的层级
      * @author lixing
      * @version V1.0 2021/3/12 3:12 下午
      */
     public void setChildren(
             Map<Integer, Map<Long, List<Department>>> levelParentIdMap,
-            ResponseDepartmentTreeItemVO treeItem, int level) {
+            ResponseDepartmentTreeItemVO treeItem,
+            int level,
+            int showLevel) {
         Map<Long, List<Department>> parentIdMap = levelParentIdMap.get(level);
         parentIdMap = parentIdMap != null ? parentIdMap : new HashMap<>(0);
         List<Department> departments = parentIdMap.get(treeItem.getId());
@@ -119,13 +135,13 @@ public class DepTreeServiceImpl implements IDepTreeService {
         }
 
         // 如果目前显示等级已经大于预设的显示等级,或者当前节点没有子节点了,就停止递归
-        if (level >= SHOW_LEVEL || CollectionUtils.isEmpty(children)) {
+        if (level >= showLevel || CollectionUtils.isEmpty(children)) {
             return;
         }
 
         treeItem.setChildren(children);
         for (ResponseDepartmentTreeItemVO child : children) {
-            setChildren(levelParentIdMap, child, level + 1);
+            setChildren(levelParentIdMap, child, level + 1, showLevel);
         }
     }
 
@@ -141,8 +157,10 @@ public class DepTreeServiceImpl implements IDepTreeService {
 
         Map<Integer, List<Department>> levelDeptListMap = initTreeData(queryDepartmentTreeDTO);
 
-        // 如果checkedId为空,默认展示三级节点
-        // 如果checkedId不为空,展示到选中的节点所在等级 (>=3级)
+        /* checkedId为空,按查询条件中的展示层数要求加载数据
+         * checkedId不为空,如果选中节点所在层级小于查询条件中的展示层数,按查询条件中的展示层数要求加载数据;
+         * 否则,展示到选中的节点所在层级
+         */
         if (CollectionUtils.isEmpty(levelDeptListMap)) {
             return Lists.newArrayList();
         }
@@ -156,7 +174,7 @@ public class DepTreeServiceImpl implements IDepTreeService {
 
         List<ResponseDepartmentTreeItemVO> result = ConvertDepartmentTool.INSTANCE.convert2Tree(rootList);
         result.forEach(treeItem -> {
-            setChildren(levelParentIdMap, treeItem, 1);
+            setChildren(levelParentIdMap, treeItem, 1, getShowLevel(queryDepartmentTreeDTO));
         });
 
         return result;

+ 88 - 5
fm-person/src/main/java/com/persagy/fm/department/service/impl/DepartmentServiceImpl.java

@@ -8,20 +8,22 @@ import com.google.common.base.CaseFormat;
 import com.google.common.collect.Lists;
 import com.persagy.common.enums.ResponseCode;
 import com.persagy.common.exception.BusinessException;
-import com.persagy.fm.department.model.ConvertDepartmentTool;
-import com.persagy.fm.department.model.dto.AddDepartmentDTO;
-import com.persagy.fm.department.service.IDepartmentService;
 import com.persagy.fm.common.constant.enums.ValidEnum;
 import com.persagy.fm.common.model.RequiredParamsStorage;
 import com.persagy.fm.common.model.dto.Sort;
+import com.persagy.fm.department.constant.enums.DepTypeEnum;
 import com.persagy.fm.department.constant.enums.ResourceFromEnum;
 import com.persagy.fm.department.dao.DepartmentMapper;
+import com.persagy.fm.department.model.ConvertDepartmentTool;
 import com.persagy.fm.department.model.Department;
+import com.persagy.fm.department.model.dto.AddDepartmentDTO;
 import com.persagy.fm.department.model.dto.PageQueryDepartmentDTO;
 import com.persagy.fm.department.model.dto.QueryDepartmentDTO;
 import com.persagy.fm.department.model.dto.UpdateDepartmentDTO;
+import com.persagy.fm.department.service.IDepartmentService;
 import org.apache.commons.lang.StringUtils;
 import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
 import org.springframework.util.CollectionUtils;
 
 import java.util.List;
@@ -38,20 +40,51 @@ public class DepartmentServiceImpl extends ServiceImpl<DepartmentMapper, Departm
         implements IDepartmentService {
 
     @Override
+    @Transactional
     public Long createDepartment(AddDepartmentDTO addDepartmentDTO) {
         // 校验部门名称重复
         checkDuplicateDeptName(addDepartmentDTO);
+        // 同一集团下只能有一个类型为集团的部门
+        checkDuplicateGroup(addDepartmentDTO);
 
         Department department = ConvertDepartmentTool.INSTANCE.convertAddDto2Entity(addDepartmentDTO);
 
         // 设置默认值
         setDefaultValue(department);
 
+        // 获取部门的上级部门,拼装部门的全路径
+        Long parentId = department.getParentId();
+        if (parentId == 0L) {
+            department.setFullPath(department.getName());
+        } else {
+            Department parentDep = queryDepartmentDetail(parentId);
+            department.setFullPath(parentDep.getFullPath() + "-" + department.getName());
+        }
+
         save(department);
         return department.getId();
     }
 
     /**
+     * 校验同一集团下是否只有一个类型为集团的部门
+     *
+     * @param addDepartmentDTO 创建部门入参
+     * @author lixing
+     * @version V1.0 2021/3/18 7:06 下午
+     */
+    private void checkDuplicateGroup(AddDepartmentDTO addDepartmentDTO) {
+        if (DepTypeEnum.GROUP.getType().equals(addDepartmentDTO.getType())) {
+            QueryDepartmentDTO queryDepartmentDTO = new QueryDepartmentDTO();
+            queryDepartmentDTO.setType(DepTypeEnum.GROUP.getType());
+            List<Department> departments = queryDepartmentList(queryDepartmentDTO);
+            if (!CollectionUtils.isEmpty(departments)) {
+                throw new BusinessException(ResponseCode.B0300.getCode(),
+                        "创建部门失败,同一集团下只能存在一个类型为集团的部门");
+            }
+        }
+    }
+
+    /**
      * 如果某些字段没有赋值,使用默认的值
      *
      * @param department 部门实体
@@ -101,14 +134,55 @@ public class DepartmentServiceImpl extends ServiceImpl<DepartmentMapper, Departm
     }
 
     @Override
+    @Transactional
     public void updateDepartment(UpdateDepartmentDTO updateDepartmentDTO) {
+        // TODO: 2021/3/22 上级部门只能选择大于等于当前部门等级的部门,通过fullPath包含的分隔符个数判断
         Department department = getById(updateDepartmentDTO.getId());
+        String nameBeforeChange = department.getName();
         department = ConvertDepartmentTool.INSTANCE.convertUpdateDto2Entity(department, updateDepartmentDTO);
+        // 如果部门名称发生变化,级联更新自己和子部门的全路径
+        if (!nameBeforeChange.equals(updateDepartmentDTO.getName())) {
+            cascadeUpdateFullPathWhenNameChange(department, nameBeforeChange);
+        }
         department.setModifier(RequiredParamsStorage.getUserId());
         updateById(department);
     }
 
     /**
+     * 部门名称发生变化,级联更新自己和子部门的全路径
+     *
+     * @param department       名称发生变更的部门
+     * @param nameBeforeChange 修改之前的部门名称
+     * @author lixing
+     * @version V1.0 2021/3/19 10:53 上午
+     */
+    private void cascadeUpdateFullPathWhenNameChange(Department department, String nameBeforeChange) {
+        String fullPathBeforeChange = department.getFullPath();
+
+        // 根据部门全路径查询子部门
+        QueryDepartmentDTO queryDepartmentDTO = new QueryDepartmentDTO();
+        queryDepartmentDTO.setFullPath(fullPathBeforeChange + "-");
+        List<Department> sonDeps = queryDepartmentList(queryDepartmentDTO);
+
+
+        String fullPathAfterChange = fullPathBeforeChange;
+        int i = fullPathBeforeChange.lastIndexOf(nameBeforeChange);
+        if (i != -1) {
+            fullPathAfterChange = fullPathBeforeChange.substring(0, i) + department.getName();
+            department.setFullPath(fullPathAfterChange);
+        }
+
+        // 修改子部门全路径
+        for (Department sonDep : sonDeps) {
+            String tmpFullPath = sonDep.getFullPath();
+            tmpFullPath = tmpFullPath.replaceFirst(fullPathBeforeChange + "-", fullPathAfterChange + "-");
+            sonDep.setFullPath(tmpFullPath);
+        }
+
+        updateBatchById(sonDeps);
+    }
+
+    /**
      * 校验部门是否可删除
      *
      * @param id 部门主键
@@ -118,7 +192,7 @@ public class DepartmentServiceImpl extends ServiceImpl<DepartmentMapper, Departm
      */
     public Department checkDeletable(Long id) {
         if (id == null) {
-            throw new IllegalArgumentException("删除Department时发生异常,主键为空");
+            throw new IllegalArgumentException("删除Department时发生异常,主键为空");
         }
 
         Department department = getById(id);
@@ -127,13 +201,17 @@ public class DepartmentServiceImpl extends ServiceImpl<DepartmentMapper, Departm
             throw new IllegalArgumentException("删除Department时发生异常,找不到要删除的数据,id:" + id);
         }
 
+        if (DepTypeEnum.GROUP.getType().equals(department.getType())) {
+            throw new IllegalArgumentException("集团不能删除!");
+        }
+
         // 查询部门是否有子部门
         QueryDepartmentDTO queryDepartmentDTO = new QueryDepartmentDTO();
         queryDepartmentDTO.setParentId(id);
         List<Department> departments = queryDepartmentList(queryDepartmentDTO);
 
         if (!CollectionUtils.isEmpty(departments)) {
-            throw new BusinessException(ResponseCode.A10000.getCode(), "当前部门包含子部门,不可删除");
+            throw new IllegalArgumentException("当前部门包含子部门,不可删除");
         }
 
         // TODO: 2021/3/9   部门包含员工时,不可删除
@@ -142,6 +220,7 @@ public class DepartmentServiceImpl extends ServiceImpl<DepartmentMapper, Departm
     }
 
     @Override
+    @Transactional
     public void deleteDepartment(Long id) {
         // 校验部门是否可删除
         Department department = checkDeletable(id);
@@ -173,6 +252,10 @@ public class DepartmentServiceImpl extends ServiceImpl<DepartmentMapper, Departm
             if (StringUtils.isNotEmpty(queryDepartmentDTO.getResourceFrom())) {
                 queryWrapper.eq(Department.PROP_RESOURCE_FROM, queryDepartmentDTO.getResourceFrom());
             }
+
+            if (StringUtils.isNotEmpty(queryDepartmentDTO.getFullPath())) {
+                queryWrapper.like(Department.PROP_FULL_PATH, queryDepartmentDTO.getFullPath());
+            }
         }
         return list(queryWrapper);
     }

+ 18 - 0
fm-person/src/main/java/com/persagy/fm/person/constant/PersonJmsType.java

@@ -0,0 +1,18 @@
+package com.persagy.fm.person.constant;
+
+/**
+ * 人员相关的消息类型
+ *
+ * @author lixing
+ * @version V1.0 2021/3/18 11:32 上午
+ **/
+public class PersonJmsType {
+    /**
+     * 超级管理员账号创建
+     */
+    public static final String ACCOUNT_CREATE = "accountCreate";
+    /**
+     * 超级管理员账号更新
+     */
+    public static final String ACCOUNT_UPDATE = "accountUpdate";
+}

+ 39 - 0
fm-person/src/main/java/com/persagy/fm/person/constant/enums/CertificateTypeEnum.java

@@ -0,0 +1,39 @@
+package com.persagy.fm.person.constant.enums;
+
+/**
+ * 证件类型
+ *
+ * @author lixing
+ * @version V1.0 2021/3/19 6:14 下午
+ **/
+public enum CertificateTypeEnum {
+    /**
+     * 证件类型
+     */
+    ID_CARD("1", "身份证"),
+    OTHER("2", "其他");
+
+    private String type;
+    private String desc;
+
+    CertificateTypeEnum(String type, String desc) {
+        this.type = type;
+        this.desc = desc;
+    }
+
+    public String getType() {
+        return type;
+    }
+
+    public void setType(String type) {
+        this.type = type;
+    }
+
+    public String getDesc() {
+        return desc;
+    }
+
+    public void setDesc(String desc) {
+        this.desc = desc;
+    }
+}

+ 65 - 0
fm-person/src/main/java/com/persagy/fm/person/controller/PersonController.java

@@ -1,5 +1,8 @@
 package com.persagy.fm.person.controller;
 
+import com.persagy.fm.department.model.dto.DeleteDepartmentDTO;
+import com.persagy.fm.person.model.vo.SimplePersonListItemVO;
+import com.persagy.fm.person.service.IPersonProjectService;
 import com.persagy.fm.person.service.IPersonService;
 
 import com.persagy.fm.person.model.ConvertPersonTool;
@@ -7,6 +10,8 @@ import com.persagy.fm.person.model.Person;
 import com.persagy.fm.person.model.vo.ResponsePersonItemVO;
 import com.persagy.fm.person.model.vo.ResponsePersonListItemVO;
 import com.persagy.fm.person.model.dto.*;
+import com.persagy.fm.saas.project.model.vo.ProjectTreeItemVO;
+import org.checkerframework.checker.units.qual.A;
 import org.springframework.beans.factory.annotation.Autowired;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
@@ -30,6 +35,8 @@ import java.util.List;
 public class PersonController {
     @Autowired
     private IPersonService personService;
+    @Autowired
+    private IPersonProjectService personProjectService;
 
     @ApiOperation(value = "创建人员")
     @PostMapping("/create")
@@ -76,6 +83,16 @@ public class PersonController {
         return FmResponseUtil.successContent(resultList);
     }
 
+    @ApiOperation(value = "查找人名")
+    @PostMapping("/name_quick_search")
+    public FmResponseContent<List<SimplePersonListItemVO>> nameQuickSearch(
+            @Valid @RequestBody NameQuickSearchDTO nameQuickSearchDTO) {
+        List<Person> personList = personService.nameQuickSearch(nameQuickSearchDTO);
+        List<SimplePersonListItemVO> resultList = ConvertPersonTool.INSTANCE.convert2SimpleList(personList);
+        return FmResponseUtil.successContent(resultList);
+    }
+
+
     //@ApiOperation(value = "人员列表, 分页查询")
     //@PostMapping("/query")
     //public FmResponseContent<List<ResponsePersonListItemVO>> queryPerson(
@@ -90,5 +107,53 @@ public class PersonController {
     //    });
     //    return FmResponseUtil.successContent(pagedResultList);;
     //}
+
+    @ApiOperation(value = "重置密码")
+    @PostMapping("/password/reset")
+    public FmResponseMsg resetPassword(
+            @Valid @RequestBody DeletePersonDTO deletePersonDTO) {
+        personService.resetPassWord(deletePersonDTO.getId());
+        return FmResponseUtil.successMsg("重置成功");
+    }
+
+    @ApiOperation(value = "禁用人员")
+    @PostMapping("/disable")
+    public FmResponseItem<FmResponseUpsertVO> disablePerson(
+            @Valid @RequestBody DeletePersonDTO deletePersonDTO) {
+        personService.disablePerson(deletePersonDTO.getId());
+        return FmResponseUtil.successItem(new FmResponseUpsertVO(deletePersonDTO.getId()));
+    }
+
+    @ApiOperation(value = "离职人员")
+    @PostMapping("/dismiss")
+    public FmResponseItem<FmResponseUpsertVO> dismissPerson(
+            @Valid @RequestBody DeletePersonDTO deletePersonDTO) {
+        personService.dismissPerson(deletePersonDTO.getId());
+        return FmResponseUtil.successItem(new FmResponseUpsertVO(deletePersonDTO.getId()));
+    }
+
+    @ApiOperation(value = "人员恢复在职")
+    @PostMapping("/rejoin")
+    public FmResponseItem<FmResponseUpsertVO> rejoinPerson(
+            @Valid @RequestBody DeletePersonDTO deletePersonDTO) {
+        personService.rejoinPerson(deletePersonDTO.getId());
+        return FmResponseUtil.successItem(new FmResponseUpsertVO(deletePersonDTO.getId()));
+    }
+
+    @ApiOperation(value = "批量更新")
+    @PostMapping("/batch_update")
+    public FmResponseMsg batchUpdatePeople(
+            @Valid @RequestBody BatchUpdatePersonDTO batchUpdatePersonDTO) {
+        personService.batchUpdatePeople(batchUpdatePersonDTO);
+        return FmResponseUtil.successMsg("批量更新成功");
+    }
+
+    @ApiOperation(value = "人员项目树")
+    @PostMapping("/projects/tree")
+    public FmResponseContent<List<ProjectTreeItemVO>> queryPersonProjectTree(
+            @Valid @RequestBody DeletePersonDTO deletePersonDTO) {
+        List<ProjectTreeItemVO> projectTreeItemVOList = personProjectService.queryPersonProjectTree(deletePersonDTO.getId());
+        return FmResponseUtil.successContent(projectTreeItemVOList);
+    }
 }
 

+ 53 - 0
fm-person/src/main/java/com/persagy/fm/person/jms/PersonJmsConfig.java

@@ -0,0 +1,53 @@
+package com.persagy.fm.person.jms;
+
+import org.springframework.amqp.core.Binding;
+import org.springframework.amqp.core.BindingBuilder;
+import org.springframework.amqp.core.Queue;
+import org.springframework.amqp.core.TopicExchange;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+
+/**
+ * 人员消息队列配置类
+ *
+ * @author lixing
+ * @version V1.0 2021/3/17 9:38 上午
+ **/
+@Configuration
+public class PersonJmsConfig {
+
+    /**
+     * 运维平台exchange
+     */
+    @Value("${person.amqp.exchange.saas}")
+    private String personSaasExchange;
+
+    /**
+     * 运维平台routingKey
+     */
+    @Value("${person.amqp.routingKey.saas}")
+    private String personSaasRoutingKey;
+
+    /**
+     * 运维平台队列
+     */
+    @Value("${person.amqp.queue.saas}")
+    private String personSaasQueue;
+
+    @Bean
+    public TopicExchange personSaasExchange() {
+        return new TopicExchange(personSaasExchange);
+    }
+
+    @Bean
+    public Queue personSaasQueue(){
+        return new Queue(personSaasQueue);
+    }
+
+    @Bean
+    public Binding saasBinding() {
+        return BindingBuilder.bind(personSaasQueue()).to(personSaasExchange()).with(personSaasRoutingKey);
+    }
+}

+ 95 - 0
fm-person/src/main/java/com/persagy/fm/person/jms/handler/AccountMsgHandler.java

@@ -0,0 +1,95 @@
+package com.persagy.fm.person.jms.handler;
+
+import com.google.gson.Gson;
+import com.persagy.common.enums.ResponseCode;
+import com.persagy.common.exception.BusinessException;
+import com.persagy.fm.common.jms.MsgBaseHandler;
+import com.persagy.fm.common.jms.model.BaseMsg;
+import com.persagy.fm.person.constant.PersonJmsType;
+import com.persagy.fm.person.jms.model.AccountCreateMsg;
+import com.persagy.fm.person.jms.model.AccountUpdateMsg;
+import com.persagy.fm.person.model.ConvertPersonTool;
+import com.persagy.fm.person.model.dto.AddPersonDTO;
+import com.persagy.fm.person.service.IPersonService;
+import com.rabbitmq.client.Channel;
+import org.springframework.amqp.core.Message;
+import org.springframework.amqp.rabbit.annotation.RabbitListener;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.io.IOException;
+
+/**
+ * 账号消息处理类
+ *
+ * @author lixing
+ * @version V1.0 2021/3/18 11:38 上午
+ **/
+@Service
+public class AccountMsgHandler extends MsgBaseHandler {
+    @Autowired
+    private IPersonService personService;
+
+    /**
+     * 处理账号创建消息
+     *
+     * @param accountCreateMsg 账号创建消息
+     * @author lixing
+     * @version V1.0 2021/3/18 11:40 上午
+     */
+    public void createAccount(AccountCreateMsg accountCreateMsg) {
+        AddPersonDTO addPersonDTO = ConvertPersonTool.INSTANCE.convert2AddDTO(accountCreateMsg);
+        personService.createPerson(addPersonDTO);
+    }
+
+    /**
+     * 处理账号更新消息
+     *
+     * @param accountUpdateMsg 账号更新消息
+     * @author lixing
+     * @version V1.0 2021/3/18 11:40 上午
+     */
+    public void updateAccount(AccountUpdateMsg accountUpdateMsg) {
+        // 根据账号id找到对应的人员信息
+        // 更细人员的账号信息
+    }
+
+    /**
+     * 监听saas队列
+     *
+     * @param message 消息体字符串
+     * @param channel 通道对象
+     * @param msg 消息对象
+     * @author lixing
+     * @version V1.0 2021/3/17 9:47 上午
+     */
+    @RabbitListener(queues = "${person.amqp.queue.saas}")
+    public void process(String message, Channel channel, Message msg) {
+        try {
+            String msgType = getMsgType(message);
+            Gson gson = new Gson();
+            switch (msgType) {
+                case PersonJmsType.ACCOUNT_CREATE:
+                    AccountCreateMsg accountCreateMsg = gson.fromJson(message, AccountCreateMsg.class);
+                    createAccount(accountCreateMsg);
+                    break;
+                case PersonJmsType.ACCOUNT_UPDATE:
+                    AccountUpdateMsg accountUpdateMsg = gson.fromJson(message, AccountUpdateMsg.class);
+                    updateAccount(accountUpdateMsg);
+                    break;
+                default:
+                    break;
+            }
+            // 手动确认消息已消费
+            channel.basicAck(msg.getMessageProperties().getDeliveryTag(),false);
+        } catch (Exception e) {
+            try {
+                // 将消费失败的消息移除消息队列,避免重复消费
+                channel.basicReject(msg.getMessageProperties().getDeliveryTag(),false);
+            } catch (IOException ex) {
+                throw new BusinessException(ResponseCode.C0001.getCode(),
+                        "账号消息从队列中移除失败," + ex.getMessage());
+            }
+        }
+    }
+}

+ 31 - 0
fm-person/src/main/java/com/persagy/fm/person/jms/model/AccountCreateMsg.java

@@ -0,0 +1,31 @@
+package com.persagy.fm.person.jms.model;
+
+import com.persagy.fm.common.jms.model.BaseMsg;
+import lombok.Data;
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * 账号创建消息
+ *
+ * @author lixing
+ * @version V1.0 2021/3/18 11:14 上午
+ **/
+@Setter
+@Getter
+public class AccountCreateMsg extends BaseMsg {
+    /**
+     * 集团编码
+     */
+    private String groupCode;
+
+    /**
+     * 账号id
+     */
+    private String id;
+
+    /**
+     * 账号
+     */
+    private String accountName;
+}

+ 32 - 0
fm-person/src/main/java/com/persagy/fm/person/jms/model/AccountUpdateMsg.java

@@ -0,0 +1,32 @@
+package com.persagy.fm.person.jms.model;
+
+import com.persagy.fm.common.jms.model.BaseMsg;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * 账号更新消息
+ *
+ * @author lixing
+ * @version V1.0 2021/3/18 11:14 上午
+ **/
+@Setter
+@Getter
+public class AccountUpdateMsg extends BaseMsg {
+    /**
+     * 集团编码
+     */
+    private String groupCode;
+
+    /**
+     * 账号id
+     */
+    private String id;
+
+    /**
+     * 账号
+     */
+    private String accountName;
+}

+ 39 - 3
fm-person/src/main/java/com/persagy/fm/person/model/ConvertPersonTool.java

@@ -1,13 +1,14 @@
 package com.persagy.fm.person.model;
 
+import com.persagy.fm.person.jms.model.AccountCreateMsg;
 import com.persagy.fm.person.model.dto.AddPersonDTO;
 import com.persagy.fm.person.model.dto.PageQueryPersonByDepDTO;
 import com.persagy.fm.person.model.dto.UpdatePersonDTO;
 import com.persagy.fm.person.model.vo.ResponsePersonItemVO;
 import com.persagy.fm.person.model.vo.ResponsePersonListItemVO;
+import com.persagy.fm.person.model.vo.SimplePersonListItemVO;
 import com.persagy.fm.workresume.model.dto.PageQueryWorkResumeDTO;
-import org.mapstruct.Mapper;
-import org.mapstruct.MappingTarget;
+import org.mapstruct.*;
 import org.mapstruct.factory.Mappers;
 
 import java.util.List;
@@ -18,7 +19,8 @@ import java.util.List;
  * @author lixing
  * @version V1.0 2021-03-15 17:20:33 2021-03-15 17:20:33
  */
-@Mapper
+@Mapper(nullValueMappingStrategy = NullValueMappingStrategy.RETURN_DEFAULT,
+        nullValueCheckStrategy = NullValueCheckStrategy.ALWAYS)
 public interface ConvertPersonTool {
 
     ConvertPersonTool INSTANCE = Mappers.getMapper(ConvertPersonTool.class);
@@ -83,5 +85,39 @@ public interface ConvertPersonTool {
      * @version V1.0 2021/3/15 5:32 下午
      */
     PageQueryWorkResumeDTO convert2PageQueryWorkResumeDTO(PageQueryPersonByDepDTO pageQueryPersonByDepDTO);
+
+    /**
+     * 账号创建消息转换为创建人员入参
+     *
+     * @param accountCreateMsg 账号创建消息
+     * @return 创建人员入参
+     * @author lixing
+     * @version V1.0 2021/3/22 7:59 下午
+     */
+    @Mappings({
+            @Mapping(source = "id", target = "username"),
+            @Mapping(source = "accountName", target = "name")
+    })
+    AddPersonDTO convert2AddDTO(AccountCreateMsg accountCreateMsg);
+
+    /**
+     * 实体对象列表转换为SimplePersonListItemVO列表
+     *
+     * @param personList 人员对象列表
+     * @return 人名列表
+     * @author lixing
+     * @version V1.0 2021/3/22 7:58 下午
+     */
+    List<SimplePersonListItemVO> convert2SimpleList(List<Person> personList);
+
+    /**
+     * 实体对象转换为SimplePersonListItemVO
+     *
+     * @param person 实体对象
+     * @return SimplePersonListItemVO
+     * @author lixing
+     * @version V1.0 2021/3/22 8:01 下午
+     */
+    SimplePersonListItemVO convert2SimpleListItem(Person person);
 }
 

+ 11 - 3
fm-person/src/main/java/com/persagy/fm/person/model/Person.java

@@ -25,17 +25,23 @@ public class Person extends AuditableEntity<Person> implements Serializable {
     @ApiModelProperty("账号")
     private String username;
 
+    @ApiModelProperty("账号id")
+    private String accountId;
+
     @ApiModelProperty("证件号码")
     private String idNumber;
 
+    @ApiModelProperty("证件类型")
+    private String certificateType;
+
     @ApiModelProperty("性别")
     private Integer gender;
 
     @ApiModelProperty("生日")
     private Date birthday;
 
-    @ApiModelProperty("第三方账号")
-    private String otherAccount;
+    @ApiModelProperty("号")
+    private String jobNumber;
 
     @ApiModelProperty("账号来源")
     private String userFrom;
@@ -49,13 +55,15 @@ public class Person extends AuditableEntity<Person> implements Serializable {
     @ApiModelProperty("专业")
     private String profession;
 
+    @ApiModelProperty("直接领导")
+    private String leader;
 
     public static String PROP_NAME = "name";
     public static String PROP_USERNAME = "username";
     public static String PROP_ID_NUMBER = "id_number";
     public static String PROP_GENDER = "gender";
     public static String PROP_BIRTHDAY = "birthday";
-    public static String PROP_OTHER_ACCOUNT = "other_account";
+    public static String PROP_JOB_NUMBER = "job_number";
     public static String PROP_USER_FROM = "user_from";
     public static String PROP_REMARK = "remark";
     public static String PROP_PROFESSION = "profession";

+ 63 - 22
fm-person/src/main/java/com/persagy/fm/person/model/dto/AddPersonDTO.java

@@ -6,8 +6,10 @@ import io.swagger.annotations.ApiModelProperty;
 import javax.validation.constraints.NotNull;
 
 import lombok.Data;
+import org.hibernate.validator.constraints.Length;
 
 import java.util.Date;
+import java.util.List;
 
 /**
  * @author lixing
@@ -17,39 +19,78 @@ import java.util.Date;
 @ApiModel(value = "创建人员入参")
 public class AddPersonDTO {
     @ApiModelProperty(value = "姓名", required = true)
-    @NotNull(message = "姓名不能为空") // todo 更新校验规则
+    @NotNull(message = "姓名不能为空")
+    @Length(max = 20, message = "姓名长度不能大于20")
+    // TODO: 2021/3/22 只能输入文本格式
     private String name;
 
-    @ApiModelProperty(value = "账号", required = true)
-    @NotNull(message = "账号不能为空") // todo 更新校验规则
-    private String username;
+    // TODO: 2021/3/22 数字和字母
+    @Length(max = 50, message = "工号长度不能大于50")
+    @ApiModelProperty(value = "工号")
+    private String jobNumber;
 
-    @ApiModelProperty(value = "证件号码", required = true)
-    @NotNull(message = "证件号码不能为空") // todo 更新校验规则
-    private String idNumber;
+    @ApiModelProperty(value = "生日")
+    private Date birthday;
 
-    @ApiModelProperty(value = "性别", required = true)
-    @NotNull(message = "性别不能为空") // todo 更新校验规则
+    @ApiModelProperty(value = "性别")
     private Integer gender;
 
-    @ApiModelProperty(value = "生日", required = true)
-    @NotNull(message = "生日不能为空") // todo 更新校验规则
-    private Date birthday;
+    @ApiModelProperty(value = "员工类型")
+    private String type;
 
-    @ApiModelProperty(value = "第三方账号", required = true)
-    @NotNull(message = "第三方账号不能为空") // todo 更新校验规则
-    private String otherAccount;
+    // TODO: 2021/3/22 手机号码合法校验
+    @Length(max = 11, message = "手机号码长度不能大于11")
+    @ApiModelProperty(value = "手机号码")
+    private String phoneNum;
 
-    @ApiModelProperty(value = "账号来源", required = true)
-    @NotNull(message = "账号来源不能为空") // todo 更新校验规则
-    private String userFrom;
+    @ApiModelProperty(value = "证件类型")
+    private String certificateType;
+
+    // TODO: 2021/3/22 身份证合法校验
+    @Length(max = 11, message = "证件号码长度不能大于18")
+    @ApiModelProperty(value = "证件号码")
+    private String idNumber;
 
-    @ApiModelProperty(value = "备注", required = true)
-    @NotNull(message = "备注不能为空") // todo 更新校验规则
+    // TODO: 2021/3/22 邮箱合法校验
+    @ApiModelProperty(value = "邮箱")
+    private String mail;
+
+    @Length(max = 50, message = "备注长度不能大于50")
+    @ApiModelProperty(value = "备注")
     private String remark;
 
-    @ApiModelProperty(value = "专业", required = true)
-    @NotNull(message = "专业不能为空") // todo 更新校验规则
+    @NotNull(message = "部门不能为空")
+    @ApiModelProperty(value = "所属部门id", required = true)
+    private List<Long> depIds;
+
+    @NotNull(message = "项目权限不能为空")
+    @ApiModelProperty(value = "关联的项目id", required = true)
+    private List<String> projectIds;
+
+    @ApiModelProperty(value = "主岗")
+    private String mainDuty;
+
+    @ApiModelProperty(value = "副岗")
+    private List<String> otherDuties;
+
+    @ApiModelProperty(value = "直接上级")
+    private Long leader;
+
+    @ApiModelProperty(value = "专业")
     private String profession;
 
+    @ApiModelProperty(value = "附加权限")
+    private List<String> otherRoles;
+
+    // TODO: 2021/3/22 不包含中文,不包含指定字符外的特殊字符,不包含空格
+    @Length(max = 30, message = "账号长度不能大于30")
+    @ApiModelProperty(value = "账号", required = true)
+    @NotNull(message = "账号不能为空")
+    private String username;
+
+    @ApiModelProperty("登录权限(年.月.日/永久)")
+    private String expireDate;
+
+    @ApiModelProperty(value = "账号来源", required = true)
+    private String userFrom;
 }

+ 40 - 0
fm-person/src/main/java/com/persagy/fm/person/model/dto/BatchUpdatePersonDTO.java

@@ -0,0 +1,40 @@
+package com.persagy.fm.person.model.dto;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import org.hibernate.validator.constraints.Length;
+
+import javax.validation.constraints.NotNull;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * @author lixing
+ * @version V1.0 2021-03-15 17:20:32
+ */
+@Data
+@ApiModel(value = "批量更新人员入参")
+public class BatchUpdatePersonDTO {
+    @ApiModelProperty(value = "ids", required = true)
+    @NotNull(message = "人员主键不能为空")
+    private List<Long> ids;
+
+    @ApiModelProperty(value = "主岗")
+    private String mainDuty;
+
+    @ApiModelProperty(value = "副岗")
+    private List<String> otherDuties;
+
+    @ApiModelProperty(value = "专业")
+    private String profession;
+
+    @ApiModelProperty(value = "所属部门id", required = true)
+    private List<Long> depIds;
+
+    @ApiModelProperty(value = "关联的项目id", required = true)
+    private List<String> projectIds;
+
+    @ApiModelProperty(value = "附加权限")
+    private List<String> otherRoles;
+}

+ 25 - 0
fm-person/src/main/java/com/persagy/fm/person/model/dto/NameQuickSearchDTO.java

@@ -0,0 +1,25 @@
+package com.persagy.fm.person.model.dto;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.util.Date;
+
+/**
+ * @author lixing
+ * @version V1.0 2021-03-15 17:20:33
+ */
+@Data
+@ApiModel(value = "快速查询姓名入参")
+public class NameQuickSearchDTO {
+    @ApiModelProperty(value = "姓名")
+    private String name;
+
+//    @ApiModelProperty(value = "账号")
+//    private String username;
+
+    @ApiModelProperty(value = "部门id")
+    private String depId;
+
+}

+ 12 - 9
fm-person/src/main/java/com/persagy/fm/person/model/dto/QueryPersonDTO.java

@@ -13,31 +13,34 @@ import java.util.Date;
 @Data
 @ApiModel(value = "查询人员入参")
 public class QueryPersonDTO {
-    @ApiModelProperty(value = "姓名", required = true)
+    @ApiModelProperty(value = "姓名")
     private String name;
 
-    @ApiModelProperty(value = "账号", required = true)
+    @ApiModelProperty(value = "账号")
     private String username;
 
-    @ApiModelProperty(value = "证件号码", required = true)
+    @ApiModelProperty(value = "证件号码")
     private String idNumber;
 
-    @ApiModelProperty(value = "性别", required = true)
+    @ApiModelProperty(value = "性别")
     private Integer gender;
 
-    @ApiModelProperty(value = "生日", required = true)
+    @ApiModelProperty(value = "生日")
     private Date birthday;
 
-    @ApiModelProperty(value = "第三方账号", required = true)
+    @ApiModelProperty(value = "第三方账号")
     private String otherAccount;
 
-    @ApiModelProperty(value = "账号来源", required = true)
+    @ApiModelProperty(value = "账号来源")
     private String userFrom;
 
-    @ApiModelProperty(value = "备注", required = true)
+    @ApiModelProperty(value = "备注")
     private String remark;
 
-    @ApiModelProperty(value = "专业", required = true)
+    @ApiModelProperty(value = "专业")
     private String profession;
 
+    @ApiModelProperty(value = "部门id")
+    private String depId;
+
 }

+ 65 - 23
fm-person/src/main/java/com/persagy/fm/person/model/dto/UpdatePersonDTO.java

@@ -6,8 +6,10 @@ import io.swagger.annotations.ApiModelProperty;
 import javax.validation.constraints.NotNull;
 
 import lombok.Data;
+import org.hibernate.validator.constraints.Length;
 
 import java.util.Date;
+import java.util.List;
 
 /**
  * @author lixing
@@ -17,43 +19,83 @@ import java.util.Date;
 @ApiModel(value = "更新人员入参")
 public class UpdatePersonDTO {
     @ApiModelProperty(value = "id", required = true)
-    @NotNull(message = "id不能为空") // todo 更新校验规则
+    @NotNull(message = "id不能为空") 
     private Long id;
 
     @ApiModelProperty(value = "姓名", required = true)
-    @NotNull(message = "姓名不能为空") // todo 更新校验规则
+    @NotNull(message = "姓名不能为空")
+    @Length(max = 20, message = "姓名长度不能大于20")
+    // TODO: 2021/3/22 只能输入文本格式
     private String name;
 
-    @ApiModelProperty(value = "账号", required = true)
-    @NotNull(message = "账号不能为空") // todo 更新校验规则
-    private String username;
+    // TODO: 2021/3/22 数字和字母
+    @Length(max = 50, message = "工号长度不能大于50")
+    @ApiModelProperty(value = "工号")
+    private String jobNumber;
 
-    @ApiModelProperty(value = "证件号码", required = true)
-    @NotNull(message = "证件号码不能为空") // todo 更新校验规则
-    private String idNumber;
+    @ApiModelProperty(value = "生日")
+    private Date birthday;
 
-    @ApiModelProperty(value = "性别", required = true)
-    @NotNull(message = "性别不能为空") // todo 更新校验规则
+    @ApiModelProperty(value = "性别")
     private Integer gender;
 
-    @ApiModelProperty(value = "生日", required = true)
-    @NotNull(message = "生日不能为空") // todo 更新校验规则
-    private Date birthday;
+    @ApiModelProperty(value = "员工类型")
+    private String type;
 
-    @ApiModelProperty(value = "第三方账号", required = true)
-    @NotNull(message = "第三方账号不能为空") // todo 更新校验规则
-    private String otherAccount;
+    // TODO: 2021/3/22 手机号码合法校验
+    @Length(max = 11, message = "手机号码长度不能大于11")
+    @ApiModelProperty(value = "手机号码")
+    private String phoneNum;
 
-    @ApiModelProperty(value = "账号来源", required = true)
-    @NotNull(message = "账号来源不能为空") // todo 更新校验规则
-    private String userFrom;
+    @ApiModelProperty(value = "证件类型")
+    private String certificateType;
+
+    // TODO: 2021/3/22 身份证合法校验
+    @Length(max = 11, message = "证件号码长度不能大于18")
+    @ApiModelProperty(value = "证件号码")
+    private String idNumber;
 
-    @ApiModelProperty(value = "备注", required = true)
-    @NotNull(message = "备注不能为空") // todo 更新校验规则
+    // TODO: 2021/3/22 邮箱合法校验
+    @ApiModelProperty(value = "邮箱")
+    private String mail;
+
+    @Length(max = 50, message = "备注长度不能大于50")
+    @ApiModelProperty(value = "备注")
     private String remark;
 
-    @ApiModelProperty(value = "专业", required = true)
-    @NotNull(message = "专业不能为空") // todo 更新校验规则
+    @NotNull(message = "部门不能为空")
+    @ApiModelProperty(value = "所属部门id", required = true)
+    private List<Long> depIds;
+
+    @NotNull(message = "项目权限不能为空")
+    @ApiModelProperty(value = "关联的项目id", required = true)
+    private List<String> projectIds;
+
+    @ApiModelProperty(value = "主岗")
+    private String mainDuty;
+
+    @ApiModelProperty(value = "副岗")
+    private List<String> otherDuties;
+
+    @ApiModelProperty(value = "直接上级")
+    private Long leader;
+
+    @ApiModelProperty(value = "专业")
     private String profession;
 
+    @ApiModelProperty(value = "附加权限")
+    private List<String> otherRoles;
+
+    // TODO: 2021/3/22 不包含中文,不包含指定字符外的特殊字符,不包含空格
+    @Length(max = 30, message = "账号长度不能大于30")
+    @ApiModelProperty(value = "账号", required = true)
+    @NotNull(message = "账号不能为空")
+    private String username;
+
+    @ApiModelProperty("登录权限(年.月.日/永久)")
+    private String expireDate;
+
+    @ApiModelProperty(value = "账号来源", required = true)
+    private String userFrom;
+
 }

+ 53 - 13
fm-person/src/main/java/com/persagy/fm/person/model/vo/ResponsePersonItemVO.java

@@ -5,6 +5,7 @@ import io.swagger.annotations.ApiModelProperty;
 import lombok.Data;
 
 import java.util.Date;
+import java.util.List;
 
 import com.fasterxml.jackson.annotation.JsonInclude;
 
@@ -22,30 +23,69 @@ public class ResponsePersonItemVO {
     @ApiModelProperty("姓名")
     private String name;
 
-    @ApiModelProperty("账号")
-    private String username;
+    @ApiModelProperty(value = "工号")
+    private String jobNumber;
 
-    @ApiModelProperty("证件号码")
-    private String idNumber;
+    @ApiModelProperty(value = "生日")
+    private Date birthday;
 
-    @ApiModelProperty("性别")
+    @ApiModelProperty(value = "性别")
     private Integer gender;
 
-    @ApiModelProperty("生日")
-    private Date birthday;
+    @ApiModelProperty(value = "员工类型")
+    private String type;
 
-    @ApiModelProperty("第三方账号")
-    private String otherAccount;
+    @ApiModelProperty(value = "手机号码")
+    private String phoneNum;
 
-    @ApiModelProperty("账号来源")
-    private String userFrom;
+    @ApiModelProperty(value = "证件类型")
+    private String certificateType;
+
+    @ApiModelProperty("证件号码")
+    private String idNumber;
 
-    @ApiModelProperty("备注")
+    @ApiModelProperty(value = "邮箱")
+    private String mail;
+
+    @ApiModelProperty(value = "备注")
     private String remark;
 
-    @ApiModelProperty("专业")
+    @ApiModelProperty(value = "所属部门id")
+    private List<Long> depIds;
+
+    @ApiModelProperty(value = "所属部门名称")
+    private List<Long> depsShowName;
+
+    @ApiModelProperty(value = "关联的项目id")
+    private List<String> projectIds;
+
+    @ApiModelProperty(value = "关联的项目名称")
+    private List<String> projectsShowName;
+
+    @ApiModelProperty(value = "主岗")
+    private String mainDuty;
+
+    @ApiModelProperty(value = "副岗")
+    private List<String> otherDuties;
+
+    @ApiModelProperty(value = "直接上级")
+    private Long leader;
+
+    @ApiModelProperty(value = "专业")
     private String profession;
 
+    @ApiModelProperty(value = "附加权限")
+    private List<String> otherRoles;
+
+    @ApiModelProperty("账号")
+    private String username;
+
+    @ApiModelProperty("登录权限(年.月.日/永久)")
+    private String expireDate;
+
+    @ApiModelProperty("账号来源")
+    private String userFrom;
+
     @ApiModelProperty("创建时间")
     private Date creationTime;
 

+ 12 - 4
fm-person/src/main/java/com/persagy/fm/person/model/vo/ResponsePersonListItemVO.java

@@ -5,6 +5,8 @@ import io.swagger.annotations.ApiModelProperty;
 import lombok.Data;
 import com.fasterxml.jackson.annotation.JsonInclude;
 
+import java.util.List;
+
 /**
  * @author lixing
  * @version V1.0 2021-03-15 17:20:33
@@ -19,20 +21,26 @@ public class ResponsePersonListItemVO {
     @ApiModelProperty("姓名")
     private String name;
 
+    @ApiModelProperty("员工类型编码")
+    private String type;
+
+    @ApiModelProperty("员工类型名称")
+    private String typeShowName;
+
     @ApiModelProperty("账号")
     private String username;
 
     @ApiModelProperty("主岗id")
-    private String mainRoleId;
+    private String mainDuty;
 
     @ApiModelProperty("主岗名称")
-    private String mainRoleShowName;
+    private String mainDutyShowName;
 
     @ApiModelProperty("副岗id")
-    private String otherRoleIds;
+    private List<String> otherDuties;
 
     @ApiModelProperty("副岗名称")
-    private String otherRolesShowName;
+    private List<String> otherDutiesShowName;
 
     @ApiModelProperty("专业id")
     private String profession;

+ 21 - 0
fm-person/src/main/java/com/persagy/fm/person/model/vo/SimplePersonListItemVO.java

@@ -0,0 +1,21 @@
+package com.persagy.fm.person.model.vo;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.util.List;
+
+/**
+ * @author lixing
+ * @version V1.0 2021-03-15 17:20:33
+ */
+@Data
+@ApiModel(value = "缩减的人员列表返回结果参数")
+@JsonInclude(JsonInclude.Include.NON_NULL)
+public class SimplePersonListItemVO {
+
+    @ApiModelProperty("姓名")
+    private String name;
+}

+ 23 - 0
fm-person/src/main/java/com/persagy/fm/person/service/IPersonProjectService.java

@@ -0,0 +1,23 @@
+package com.persagy.fm.person.service;
+
+import com.persagy.fm.saas.project.model.vo.ProjectTreeItemVO;
+
+import java.util.List;
+
+/**
+ * 人员关联的项目接口
+ *
+ * @author lixing
+ * @version V1.0 2021/3/22 11:54 上午
+ **/
+public interface IPersonProjectService {
+    /**
+     * 获取人员关联的项目树
+     *
+     * @param personId 人员id
+     * @return 人员关联的项目树
+     * @author lixing
+     * @version V1.0 2021/3/22 3:58 下午
+     */
+    List<ProjectTreeItemVO> queryPersonProjectTree(Long personId);
+}

+ 55 - 0
fm-person/src/main/java/com/persagy/fm/person/service/IPersonService.java

@@ -82,4 +82,59 @@ public interface IPersonService {
      * @version V1.0 2021-03-15 17:20:31
      */
     IPage<Person> pageQueryPerson(PageQueryPersonDTO pageQueryPersonDTO);
+
+    /**
+     * 重置人员账号的密码
+     *
+     * @param personId 人员id
+     * @author lixing
+     * @version V1.0 2021/3/22 10:28 上午
+     */
+    void resetPassWord(Long personId);
+
+    /**
+     * 禁用人员
+     *
+     * @param personId 人员id
+     * @author lixing
+     * @version V1.0 2021/3/22 10:39 上午
+     */
+    void disablePerson(Long personId);
+
+    /**
+     * 解雇人员
+     *
+     * @param personId 人员id
+     * @author lixing
+     * @version V1.0 2021/3/22 10:39 上午
+     */
+    void dismissPerson(Long personId);
+
+    /**
+     * 恢复入职
+     *
+     * @param personId 人员id
+     * @author lixing
+     * @version V1.0 2021/3/22 10:44 上午
+     */
+    void rejoinPerson(Long personId);
+
+    /**
+     * 批量更新人员信息
+     *
+     * @param batchUpdatePersonDTO 批量更新参数
+     * @author lixing
+     * @version V1.0 2021/3/22 11:06 上午
+     */
+    void batchUpdatePeople(BatchUpdatePersonDTO batchUpdatePersonDTO);
+
+    /**
+     * 快速查询人名
+     *
+     * @param nameQuickSearchDTO 快速查询人名入参
+     * @return 匹配到的人名列表
+     * @author lixing
+     * @version V1.0 2021/3/22 7:57 下午
+     */
+    List<Person> nameQuickSearch(NameQuickSearchDTO nameQuickSearchDTO);
 }

+ 28 - 0
fm-person/src/main/java/com/persagy/fm/person/service/impl/PersonProjectServiceImpl.java

@@ -0,0 +1,28 @@
+package com.persagy.fm.person.service.impl;
+
+import com.persagy.fm.person.service.IPersonProjectService;
+import com.persagy.fm.saas.project.model.vo.ProjectTreeItemVO;
+import com.persagy.fm.saas.project.service.ISaasProjectService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+/**
+ * 人员关联的项目service层
+ *
+ * @author lixing
+ * @version V1.0 2021/3/22 11:54 上午
+ **/
+@Service
+public class PersonProjectServiceImpl implements IPersonProjectService {
+    @Autowired
+    ISaasProjectService saasProjectService;
+    @Override
+    public List<ProjectTreeItemVO> queryPersonProjectTree(Long personId) {
+        // 根据人员id查询人员关联的项目,然后组装项目树
+        // TODO: 2021/3/22 查询人员关联的项目
+        List<String> projectIds = null;
+        return saasProjectService.queryProjectTree(projectIds);
+    }
+}

+ 45 - 10
fm-person/src/main/java/com/persagy/fm/person/service/impl/PersonServiceImpl.java

@@ -48,6 +48,7 @@ public class PersonServiceImpl extends ServiceImpl<PersonMapper, Person>
     @Override
     public Long createPerson(AddPersonDTO addPersonDTO) {
         Person person = ConvertPersonTool.INSTANCE.convertAddDto2Entity(addPersonDTO);
+        checkDuplicate(addPersonDTO);
         // 设置默认值
         setDefaultValue(person);
         save(person);
@@ -55,6 +56,19 @@ public class PersonServiceImpl extends ServiceImpl<PersonMapper, Person>
     }
 
     /**
+     * 校验重复项,手机号码,身份证
+     *
+     * @param addPersonDTO
+     * @return void
+     * @exception
+     * @author lixing
+     * @version V1.0 2021/3/22 9:53 上午
+     */
+    private void checkDuplicate(AddPersonDTO addPersonDTO) {
+        // TODO: 2021/3/22 手机号,身份证号,账号
+    }
+
+    /**
      * 如果某些字段没有赋值,使用默认的值
      *
      * @param person 人员实体
@@ -176,11 +190,6 @@ public class PersonServiceImpl extends ServiceImpl<PersonMapper, Person>
             }
 
             // todo 需判断使用like还是eq
-            if (StringUtils.isNotEmpty(queryPersonDTO.getOtherAccount())) {
-                queryWrapper.like(Person.PROP_OTHER_ACCOUNT, queryPersonDTO.getOtherAccount());
-            }
-
-            // todo 需判断使用like还是eq
             if (StringUtils.isNotEmpty(queryPersonDTO.getUserFrom())) {
                 queryWrapper.like(Person.PROP_USER_FROM, queryPersonDTO.getUserFrom());
             }
@@ -280,11 +289,6 @@ public class PersonServiceImpl extends ServiceImpl<PersonMapper, Person>
         }
 
         // todo 需判断使用like还是eq
-        if (StringUtils.isNotEmpty(pageQueryPersonDTO.getOtherAccount())) {
-            queryWrapper.like(Person.PROP_OTHER_ACCOUNT, pageQueryPersonDTO.getOtherAccount());
-        }
-
-        // todo 需判断使用like还是eq
         if (StringUtils.isNotEmpty(pageQueryPersonDTO.getUserFrom())) {
             queryWrapper.like(Person.PROP_USER_FROM, pageQueryPersonDTO.getUserFrom());
         }
@@ -301,4 +305,35 @@ public class PersonServiceImpl extends ServiceImpl<PersonMapper, Person>
 
         return getBaseMapper().selectPage(pageParam, queryWrapper);
     }
+
+    @Override
+    public void resetPassWord(Long personId) {
+        // TODO: 2021/3/22 重置人员账号的密码
+    }
+
+    @Override
+    public void disablePerson(Long personId) {
+        // TODO: 2021/3/22 禁用账号
+    }
+
+    @Override
+    public void dismissPerson(Long personId) {
+        // TODO: 2021/3/22 人员离职
+    }
+
+    @Override
+    public void rejoinPerson(Long personId) {
+        // TODO: 2021/3/22 恢复入职
+    }
+
+    @Override
+    public void batchUpdatePeople(BatchUpdatePersonDTO batchUpdatePersonDTO) {
+        // TODO: 2021/3/22 批量更新人员
+    }
+
+    @Override
+    public List<Person> nameQuickSearch(NameQuickSearchDTO nameQuickSearchDTO) {
+        // TODO: 2021/3/22 快速查询人名
+        return null;
+    }
 }

+ 73 - 0
fm-person/src/main/java/com/persagy/fm/profession/controller/ProfessionController.java

@@ -0,0 +1,73 @@
+package com.persagy.fm.profession.controller;
+
+import com.persagy.fm.common.response.*;
+import com.persagy.fm.profession.model.ConvertProfessionTool;
+import com.persagy.fm.profession.model.Profession;
+import com.persagy.fm.profession.model.dto.AddProfessionDTO;
+import com.persagy.fm.profession.model.dto.DeleteProfessionDTO;
+import com.persagy.fm.profession.model.dto.UpdateProfessionDTO;
+import com.persagy.fm.profession.model.vo.ResponseProfessionListItemVO;
+import com.persagy.fm.profession.service.IProfessionService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.validation.annotation.Validated;
+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 javax.validation.Valid;
+import java.util.List;
+
+/**
+ * 专业控制层
+ *
+ * @author lixing
+ * @version V1.0 2021-03-19 16:38:18
+ */
+@Api(tags = "专业")
+@Validated
+@RestController
+@RequestMapping("professions")
+public class ProfessionController {
+    @Autowired
+    private IProfessionService professionService;
+
+    @ApiOperation(value = "创建专业")
+    @PostMapping("/create")
+    public FmResponseItem<FmResponseUpsertVO> createProfession(
+            @Valid @RequestBody AddProfessionDTO addProfessionDTO) {
+        Long id = professionService.createProfession(addProfessionDTO);
+        return FmResponseUtil.successItem(new FmResponseUpsertVO(id));
+    }
+
+
+    @ApiOperation(value = "更新专业")
+    @PostMapping("/update")
+    public FmResponseItem<FmResponseUpsertVO> updateProfession(
+            @Valid @RequestBody UpdateProfessionDTO updateProfessionDTO) {
+        professionService.updateProfession(updateProfessionDTO);
+        return FmResponseUtil.successItem(new FmResponseUpsertVO(updateProfessionDTO.getId()));
+    }
+
+
+    @ApiOperation(value = "删除专业")
+    @PostMapping("/delete")
+    public FmResponseMsg deleteProfession(
+            @RequestBody @Valid DeleteProfessionDTO deleteProfessionDTO) {
+        professionService.deleteProfession(deleteProfessionDTO.getId());
+        return FmResponseUtil.successMsg("删除成功");
+    }
+
+
+    @ApiOperation(value = "专业列表")
+    @PostMapping("/query")
+    public FmResponseContent<List<ResponseProfessionListItemVO>> queryProfession() {
+        List<Profession> professionList = professionService.queryProfessionList();
+        List<ResponseProfessionListItemVO> resultList = ConvertProfessionTool.INSTANCE.convert2List(professionList);
+        return FmResponseUtil.successContent(resultList);
+    }
+
+}
+

+ 16 - 0
fm-person/src/main/java/com/persagy/fm/profession/dao/ProfessionMapper.java

@@ -0,0 +1,16 @@
+package com.persagy.fm.profession.dao;
+
+import com.persagy.fm.profession.model.Profession;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * 专业(Profession)dao层
+ *
+ * @author lixing
+ * @version V1.0 2021-03-19 16:38:19
+ */
+@Mapper
+public interface ProfessionMapper extends BaseMapper<Profession> {
+
+}

+ 74 - 0
fm-person/src/main/java/com/persagy/fm/profession/model/ConvertProfessionTool.java

@@ -0,0 +1,74 @@
+package com.persagy.fm.profession.model;
+
+import org.mapstruct.*;
+import org.mapstruct.MappingTarget;
+import org.mapstruct.factory.Mappers;
+import com.persagy.fm.profession.model.vo.*;
+import com.persagy.fm.profession.model.dto.*;
+
+import java.util.List;
+
+/**
+ * 专业(Profession) dto、vo、do转换工具类
+ *
+ * @author lixing
+ * @version V1.0 2021-03-19 16:38:21 2021-03-19 16:38:21
+ */
+@Mapper(nullValueMappingStrategy = NullValueMappingStrategy.RETURN_DEFAULT,
+        nullValueCheckStrategy = NullValueCheckStrategy.ALWAYS)
+public interface ConvertProfessionTool {
+
+    ConvertProfessionTool INSTANCE = Mappers.getMapper(ConvertProfessionTool.class);
+
+    /**
+     * do转换为ResponseItemVO
+     *
+     * @param profession do对象
+     * @return ResponseItemVO
+     * @author lixing
+     * @version V1.0 2021-03-19 16:38:21
+     */
+    ResponseProfessionItemVO convert2ResponseItemDTO(Profession profession);
+
+    /**
+     * do转换为ResponseListItemVO
+     *
+     * @param profession do对象
+     * @return ResponseListItemVO
+     * @author lixing
+     * @version V1.0 2021-03-19 16:38:21
+     */
+    ResponseProfessionListItemVO convert2ResponseListItemDTO(Profession profession);
+
+    /**
+     * do列表转换为ResponseListItemVO列表
+     *
+     * @param professionList do列表
+     * @return ResponseListItemVO列表
+     * @author lixing
+     * @version V1.0 2021-03-19 16:38:21
+     */
+    List<ResponseProfessionListItemVO> convert2List(List<Profession> professionList);
+
+    /**
+     * addDTO转换为do
+     *
+     * @param addProfessionDTO addDTO
+     * @return 要创建的do对象
+     * @author lixing
+     * @version V1.0 2021-03-19 16:38:21
+     */
+    Profession convertAddDto2Entity(AddProfessionDTO addProfessionDTO);
+
+    /**
+     * updateDTO转换为实体
+     *
+     * @param profession          更新前的do对象
+     * @param updateProfessionDTO updateDTO
+     * @return 更新后的do对象
+     * @author lixing
+     * @version V1.0 2021-03-19 16:38:21
+     */
+    Profession convertUpdateDto2Entity(@MappingTarget Profession profession, UpdateProfessionDTO updateProfessionDTO);
+}
+

+ 32 - 0
fm-person/src/main/java/com/persagy/fm/profession/model/Profession.java

@@ -0,0 +1,32 @@
+package com.persagy.fm.profession.model;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import com.persagy.fm.common.model.entity.AuditableEntity;
+
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * 专业(Profession)实体类
+ *
+ * @author lixing
+ * @version V1.0 2021-03-19 16:38:20
+ */
+@Data
+@ApiModel(description = "专业")
+public class Profession extends AuditableEntity<Profession> implements Serializable {
+    private static final long serialVersionUID = -51114072842935170L;
+
+    @ApiModelProperty("专业名称")
+    private String name;
+
+    @ApiModelProperty("是否可编辑")
+    private String editable;
+
+
+    public static String PROP_NAME = "name";
+    public static String PROP_EDITABLE = "editable";
+
+}

+ 32 - 0
fm-person/src/main/java/com/persagy/fm/profession/model/dto/AddProfessionDTO.java

@@ -0,0 +1,32 @@
+package com.persagy.fm.profession.model.dto;
+
+import com.persagy.fm.common.constant.RegexConstants;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+
+import javax.validation.constraints.NotNull;
+import javax.validation.constraints.Pattern;
+
+import lombok.Data;
+import org.hibernate.validator.constraints.Length;
+
+import java.util.Date;
+
+/**
+ * @author lixing
+ * @version V1.0 2021-03-19 16:38:20
+ */
+@Data
+@ApiModel(value = "创建专业入参")
+public class AddProfessionDTO {
+    @ApiModelProperty(value = "专业名称", required = true)
+    @NotNull(message = "专业名称不能为空")
+    @Length(max = 20, message = "专业名称长度不能超过20位")
+    @Pattern(regexp = RegexConstants.NAME_REGEX,
+            message = "专业名称" + RegexConstants.NAME_REGEX_WARNING)
+    private String name;
+
+    @ApiModelProperty(value = "是否可编辑", required = true)
+    private String editable;
+
+}

+ 20 - 0
fm-person/src/main/java/com/persagy/fm/profession/model/dto/DeleteProfessionDTO.java

@@ -0,0 +1,20 @@
+package com.persagy.fm.profession.model.dto;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import javax.validation.constraints.NotNull;
+
+/**
+ * @author lixing
+ * @version V1.0 2021-03-19 16:38:20
+ */
+@Data
+@ApiModel(value = "删除专业入参")
+public class DeleteProfessionDTO {
+    @NotNull(message = "id不能为空")
+    @ApiModelProperty(value = "主键", required = true)
+    private Long id;
+
+}

+ 32 - 0
fm-person/src/main/java/com/persagy/fm/profession/model/dto/UpdateProfessionDTO.java

@@ -0,0 +1,32 @@
+package com.persagy.fm.profession.model.dto;
+
+import com.persagy.fm.common.constant.RegexConstants;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+
+import javax.validation.constraints.NotNull;
+import javax.validation.constraints.Pattern;
+
+import lombok.Data;
+import org.hibernate.validator.constraints.Length;
+
+import java.util.Date;
+
+/**
+ * @author lixing
+ * @version V1.0 2021-03-19 16:38:20
+ */
+@Data
+@ApiModel(value = "更新专业入参")
+public class UpdateProfessionDTO {
+    @ApiModelProperty(value = "主键", required = true)
+    @NotNull(message = "主键不能为空")
+    private Long id;
+
+    @ApiModelProperty(value = "专业名称", required = true)
+    @NotNull(message = "专业名称不能为空")
+    @Length(max = 20, message = "专业名称长度不能超过20位")
+    @Pattern(regexp = RegexConstants.NAME_REGEX,
+            message = "专业名称" + RegexConstants.NAME_REGEX_WARNING)
+    private String name;
+}

+ 40 - 0
fm-person/src/main/java/com/persagy/fm/profession/model/vo/ResponseProfessionItemVO.java

@@ -0,0 +1,40 @@
+package com.persagy.fm.profession.model.vo;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.util.Date;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+
+/**
+ * @author lixing
+ * @version V1.0 2021-03-19 16:38:20
+ */
+@Data
+@ApiModel(value = "专业返回结果参数")
+@JsonInclude(JsonInclude.Include.NON_NULL)
+public class ResponseProfessionItemVO {
+    @ApiModelProperty("主键")
+    private Long id;
+
+    @ApiModelProperty("专业名称")
+    private String name;
+
+    @ApiModelProperty("是否可编辑")
+    private String editable;
+
+    @ApiModelProperty("创建人")
+    private String creator;
+
+    @ApiModelProperty("创建时间")
+    private Date creationTime;
+
+    @ApiModelProperty("最后修改人")
+    private String modifier;
+
+    @ApiModelProperty("最后修改时间")
+    private Date modifiedTime;
+
+}

+ 40 - 0
fm-person/src/main/java/com/persagy/fm/profession/model/vo/ResponseProfessionListItemVO.java

@@ -0,0 +1,40 @@
+package com.persagy.fm.profession.model.vo;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.util.Date;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+
+/**
+ * @author lixing
+ * @version V1.0 2021-03-19 16:38:20
+ */
+@Data
+@ApiModel(value = "专业列表返回结果参数")
+@JsonInclude(JsonInclude.Include.NON_NULL)
+public class ResponseProfessionListItemVO {
+    @ApiModelProperty("主键")
+    private Long id;
+
+    @ApiModelProperty("专业名称")
+    private String name;
+
+    @ApiModelProperty("是否可编辑")
+    private String editable;
+
+    @ApiModelProperty("创建人")
+    private String creator;
+
+    @ApiModelProperty("创建时间")
+    private Date creationTime;
+
+    @ApiModelProperty("最后修改人")
+    private String modifier;
+
+    @ApiModelProperty("最后修改时间")
+    private Date modifiedTime;
+
+}

+ 56 - 0
fm-person/src/main/java/com/persagy/fm/profession/service/IProfessionService.java

@@ -0,0 +1,56 @@
+package com.persagy.fm.profession.service;
+
+import com.persagy.fm.profession.model.*;
+import com.persagy.fm.profession.model.dto.*;
+
+import java.util.List;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+
+/**
+ * 专业(Profession) service接口
+ *
+ * @author lixing
+ * @version V1.0 2021-03-19 16:38:19
+ */
+public interface IProfessionService {
+
+    /**
+     * 创建专业
+     *
+     * @param addProfessionDTO addDTO
+     * @return 专业主键
+     * @author lixing
+     * @version V1.0 2021-03-19 16:38:19
+     */
+    Long createProfession(AddProfessionDTO addProfessionDTO);
+
+    /**
+     * 更新专业
+     *
+     * @param updateProfessionDTO updateDTO
+     * @author lixing
+     * @version V1.0 2021-03-19 16:38:19
+     */
+    void updateProfession(UpdateProfessionDTO updateProfessionDTO);
+
+    /**
+     * 删除专业
+     *
+     * @param id 主键
+     * @author lixing
+     * @version V1.0 2021-03-19 16:38:19
+     */
+    void deleteProfession(Long id);
+
+    /**
+     * 查询专业
+     *
+     * @return List<Profession>
+     * @author lixing
+     * @version V1.0 2021-03-19 16:38:19
+     */
+    List<Profession> queryProfessionList();
+}

+ 127 - 0
fm-person/src/main/java/com/persagy/fm/profession/service/impl/ProfessionServiceImpl.java

@@ -0,0 +1,127 @@
+package com.persagy.fm.profession.service.impl;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.persagy.fm.common.constant.enums.BoolEnum;
+import com.persagy.fm.common.constant.enums.ValidEnum;
+import com.persagy.fm.common.model.RequiredParamsStorage;
+import com.persagy.fm.profession.dao.ProfessionMapper;
+import com.persagy.fm.profession.model.ConvertProfessionTool;
+import com.persagy.fm.profession.model.Profession;
+import com.persagy.fm.profession.model.dto.AddProfessionDTO;
+import com.persagy.fm.profession.model.dto.UpdateProfessionDTO;
+import com.persagy.fm.profession.service.IProfessionService;
+import org.apache.commons.lang.StringUtils;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+/**
+ * 专业(Profession) service层
+ *
+ * @author lixing
+ * @version V1.0 2021-03-19 16:38:19
+ */
+@Service
+public class ProfessionServiceImpl extends ServiceImpl<ProfessionMapper, Profession>
+        implements IProfessionService {
+
+    /**
+     * 创建专业
+     *
+     * @return Long 专业主键
+     * @author lixing
+     * @version V1.0 2021-03-19 16:38:19
+     */
+    @Override
+    public Long createProfession(AddProfessionDTO addProfessionDTO) {
+        Profession profession = ConvertProfessionTool.INSTANCE.convertAddDto2Entity(addProfessionDTO);
+        // 设置默认值
+        setDefaultValue(profession);
+        save(profession);
+        return profession.getId();
+    }
+
+    /**
+     * 如果某些字段没有赋值,使用默认的值
+     *
+     * @param profession 专业实体
+     * @author lixing
+     * @version V1.0 2021/3/12 12:29 下午
+     */
+    private void setDefaultValue(Profession profession) {
+        profession.setCreator(RequiredParamsStorage.getUserId());
+        if (profession.getEditable() == null) {
+            profession.setEditable(BoolEnum.TRUE.getType());
+        }
+    }
+
+    /**
+     * 更新专业
+     *
+     * @author lixing
+     * @version V1.0 2021-03-19 16:38:19
+     */
+    @Override
+    public void updateProfession(UpdateProfessionDTO updateProfessionDTO) {
+        Profession profession = getById(updateProfessionDTO.getId());
+        profession = ConvertProfessionTool.INSTANCE.convertUpdateDto2Entity(profession, updateProfessionDTO);
+        profession.setModifier(RequiredParamsStorage.getUserId());
+        updateById(profession);
+    }
+
+    /**
+     * 校验专业是否可删除
+     *
+     * @param id 专业主键
+     * @return 专业do类
+     * @author lixing
+     * @version V1.0 2021-03-19 16:38:19
+     */
+    public Profession checkDeletable(Long id) {
+        if (id == null) {
+            throw new IllegalArgumentException("删除Profession时发生异常,主键为空");
+        }
+
+        Profession profession = getById(id);
+
+        if (profession == null) {
+            throw new IllegalArgumentException("删除Profession时发生异常,找不到要删除的数据,id:" + id);
+        }
+
+        return profession;
+    }
+
+    /**
+     * 删除专业
+     *
+     * @param id 主键
+     * @author lixing
+     * @version V1.0 2021-03-19 16:38:19
+     */
+    @Override
+    public void deleteProfession(Long id) {
+        // 校验是否可删除
+        Profession profession = checkDeletable(id);
+
+        profession.setValid(ValidEnum.FALSE.getType());
+        updateById(profession);
+    }
+
+    /**
+     * 查询专业
+     *
+     * @return List<Profession>
+     * @author lixing
+     * @version V1.0 2021-03-19 16:38:19
+     */
+    @Override
+    public List<Profession> queryProfessionList() {
+        QueryWrapper<Profession> queryWrapper = new QueryWrapper<>();
+        queryWrapper.eq(Profession.PROP_VALID, ValidEnum.TRUE.getType());
+        // 默认按创建时间倒序排序
+        queryWrapper.orderBy(true, false, Profession.PROP_CREATIONTIME);
+        return list(queryWrapper);
+    }
+
+}

+ 29 - 0
fm-person/src/main/java/com/persagy/fm/saas/project/client/SaasProjectClient.java

@@ -0,0 +1,29 @@
+package com.persagy.fm.saas.project.client;
+
+import com.persagy.fm.common.client.FeignConfig;
+import com.persagy.fm.common.model.dto.DmpRequiredParam;
+import com.persagy.fm.common.response.FmResponseContent;
+import com.persagy.fm.saas.project.client.fallback.SaasProjectClientFallbackFactory;
+import com.persagy.fm.saas.project.constant.FeignClientNameConstants;
+import com.persagy.fm.saas.project.model.dto.QuerySaasAreaDTO;
+import com.persagy.fm.saas.project.model.vo.SaasAreaListItemVO;
+import org.springframework.cloud.openfeign.FeignClient;
+import org.springframework.cloud.openfeign.SpringQueryMap;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+
+import java.util.List;
+
+/**
+ * 接口说明
+ *
+ * @author lixing
+ * @version V1.0 2021/3/22 2:13 下午
+ **/
+//@FeignClient(name = FeignClientNameConstants.SAAS, fallbackFactory = SaasProjectClientFallbackFactory.class,
+//        configuration = FeignConfig.class)
+public interface SaasProjectClient {
+    @RequestMapping("/saas-account/area/querySaasAreaList")
+    FmResponseContent<List<SaasAreaListItemVO>> querySaasAreaList(
+            @SpringQueryMap DmpRequiredParam dmpRequiredParam, @RequestBody QuerySaasAreaDTO querySaasAreaDTO);
+}

+ 16 - 0
fm-person/src/main/java/com/persagy/fm/saas/project/client/fallback/SaasProjectClientFallbackFactory.java

@@ -0,0 +1,16 @@
+package com.persagy.fm.saas.project.client.fallback;
+
+import com.persagy.fm.saas.project.client.SaasProjectClient;
+import feign.hystrix.FallbackFactory;
+import org.springframework.stereotype.Component;
+
+/**
+ * @author drx
+ */
+@Component
+public class SaasProjectClientFallbackFactory implements FallbackFactory<SaasProjectClient> {
+    @Override
+    public SaasProjectClient create(Throwable throwable) {
+        return null;
+    }
+}

+ 11 - 0
fm-person/src/main/java/com/persagy/fm/saas/project/constant/FeignClientNameConstants.java

@@ -0,0 +1,11 @@
+package com.persagy.fm.saas.project.constant;
+
+/**
+ * feign客户端名称
+ *
+ * @author lixing
+ * @version V1.0 2021/3/22 2:15 下午
+ **/
+public class FeignClientNameConstants {
+    public static final String SAAS = "saas";
+}

+ 14 - 0
fm-person/src/main/java/com/persagy/fm/saas/project/model/dto/QuerySaasAreaDTO.java

@@ -0,0 +1,14 @@
+package com.persagy.fm.saas.project.model.dto;
+
+import lombok.Data;
+
+/**
+ * 查询"saas-区域"参数
+ *
+ * @author lixing
+ * @version V1.0 2021/3/22 2:23 下午
+ **/
+@Data
+public class QuerySaasAreaDTO {
+    // TODO: 2021/3/22 配置属性
+}

+ 24 - 0
fm-person/src/main/java/com/persagy/fm/saas/project/model/vo/ProjectTreeItemVO.java

@@ -0,0 +1,24 @@
+package com.persagy.fm.saas.project.model.vo;
+
+import lombok.Data;
+
+import java.util.List;
+
+/**
+ * 区域项目树条目vo
+ *
+ * @author lixing
+ * @version V1.0 2021/3/22 2:25 下午
+ **/
+@Data
+public class ProjectTreeItemVO {
+
+    private String id;
+    private String name;
+    /**
+     * 是否为项目,条目可能是区域或项目
+     */
+    private String isProject;
+    private List<ProjectTreeItemVO> children;
+}
+

+ 14 - 0
fm-person/src/main/java/com/persagy/fm/saas/project/model/vo/SaasAreaListItemVO.java

@@ -0,0 +1,14 @@
+package com.persagy.fm.saas.project.model.vo;
+
+import lombok.Data;
+
+/**
+ * saas 区域列表条目对象
+ *
+ * @author lixing
+ * @version V1.0 2021/3/22 2:22 下午
+ **/
+@Data
+public class SaasAreaListItemVO {
+    // TODO: 2021/3/22 设置参数
+}

+ 23 - 0
fm-person/src/main/java/com/persagy/fm/saas/project/service/ISaasProjectService.java

@@ -0,0 +1,23 @@
+package com.persagy.fm.saas.project.service;
+
+import com.persagy.fm.saas.project.model.vo.ProjectTreeItemVO;
+
+import java.util.List;
+
+/**
+ * 项目接口
+ *
+ * @author lixing
+ * @version V1.0 2021/3/22 2:05 下午
+ **/
+public interface ISaasProjectService {
+    /**
+     * 传入一组项目id,获取相应的项目树
+     *
+     * @param projectIds 一组项目id
+     * @return 项目树
+     * @author lixing
+     * @version V1.0 2021/3/22 2:29 下午
+     */
+    List<ProjectTreeItemVO> queryProjectTree(List<String> projectIds);
+}

+ 28 - 0
fm-person/src/main/java/com/persagy/fm/saas/project/service/impl/SaasProjectServiceImpl.java

@@ -0,0 +1,28 @@
+package com.persagy.fm.saas.project.service.impl;
+
+import com.persagy.fm.saas.project.client.SaasProjectClient;
+import com.persagy.fm.saas.project.model.vo.ProjectTreeItemVO;
+import com.persagy.fm.saas.project.service.ISaasProjectService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+/**
+ * 项目service层
+ *
+ * @author lixing
+ * @version V1.0 2021/3/22 2:05 下午
+ **/
+@Service
+public class SaasProjectServiceImpl implements ISaasProjectService {
+//    @Autowired
+//    SaasProjectClient saasProjectClient;
+
+
+    @Override
+    public List<ProjectTreeItemVO> queryProjectTree(List<String> projectIds) {
+        // TODO: 2021/3/22 给定一组项目id,返回一颗项目树(为了性能,先查询所有的区域,然后在本地拼装成树)
+        return null;
+    }
+}

+ 94 - 0
fm-person/src/main/java/com/persagy/fm/saas/role/controller/SaasRoleController.java

@@ -0,0 +1,94 @@
+package com.persagy.fm.saas.role.controller;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.persagy.fm.saas.role.service.ISaasRoleService;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiParam;
+import com.persagy.fm.saas.role.model.*;
+import com.persagy.fm.saas.role.model.vo.*;
+import com.persagy.fm.saas.role.model.dto.*;
+import com.persagy.fm.common.response.*;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import javax.validation.Valid;
+import java.util.List;
+
+/**
+ * 控制层
+ *
+ * @author lixing
+ * @version V1.0 2021-03-22 19:04:01
+ */
+@Api(tags = "")
+@Validated
+@RestController
+@RequestMapping("saasRoles")
+public class SaasRoleController {
+    @Autowired
+    private ISaasRoleService saasRoleService;
+
+    @ApiOperation(value = "创建")
+    @PostMapping("/create")
+    public FmResponseMsg createSaasRole(
+            @Valid @RequestBody AddSaasRoleDTO addSaasRoleDTO) {
+        saasRoleService.createSaasRole(addSaasRoleDTO);
+        return FmResponseUtil.successMsg("创建成功");
+    }
+
+//    @ApiOperation(value = "详情")
+//    @PostMapping("/get")
+//    public FmResponseItem<ResponseSaasRoleItemVO> querySaasRoleDetail(
+//            @Valid @RequestBody QuerySaasRoleDetailDTO querySaasRoleDetailDTO) {
+//        SaasRole saasRole = saasRoleService.querySaasRoleDetail(querySaasRoleDetailDTO.getId());
+//        ResponseSaasRoleItemVO responseSaasRoleItemVO = ConvertSaasRoleTool.INSTANCE.convert2ResponseItemDTO(saasRole);
+//        return FmResponseUtil.successItem(responseSaasRoleItemVO);
+//    }
+
+
+    @ApiOperation(value = "更新")
+    @PostMapping("/update")
+    public FmResponseMsg updateSaasRole(
+            @Valid @RequestBody UpdateSaasRoleDTO updateSaasRoleDTO) {
+        saasRoleService.updateSaasRole(updateSaasRoleDTO);
+        return FmResponseUtil.successMsg("更新成功");
+    }
+
+
+    @ApiOperation(value = "删除")
+    @PostMapping("/delete")
+    public FmResponseMsg deleteSaasRole(
+            @RequestBody @Valid DeleteSaasRoleDTO deleteSaasRoleDTO) {
+        saasRoleService.deleteSaasRole(deleteSaasRoleDTO.getId());
+        return FmResponseUtil.successMsg("删除成功");
+    }
+
+
+//    @ApiOperation(value = "列表")
+//    @PostMapping("/query")
+//    public FmResponseContent<List<ResponseSaasRoleListItemVO>> querySaasRole(
+//            @Valid @RequestBody QuerySaasRoleDTO querySaasRoleDTO) {
+//        List<SaasRole> saasRoleList = saasRoleService.querySaasRoleList(querySaasRoleDTO);
+//        List<ResponseSaasRoleListItemVO> resultList = ConvertSaasRoleTool.INSTANCE.convert2List(saasRoleList);
+//        return FmResponseUtil.successContent(resultList);
+//    }
+
+    @ApiOperation(value = "列表, 分页查询")
+    @PostMapping("/query")
+    public FmResponseContent<List<ResponseSaasRoleListItemVO>> querySaasRole(
+            @Valid @RequestBody PageQuerySaasRoleDTO pageQuerySaasRoleDTO) {
+        IPage<SaasRole> pagedList = saasRoleService.pageQuerySaasRole(pageQuerySaasRoleDTO);
+        IPage<ResponseSaasRoleListItemVO> pagedResultList = pagedList.convert(item -> {
+            try {
+               return ConvertSaasRoleTool.INSTANCE.convert2ResponseListItemDTO(item);
+            } catch (Exception e) {
+                throw new IllegalArgumentException("分页查询,SaasRole实体类转换为列表对象发生异常", e);
+            }
+        });
+        return FmResponseUtil.successContent(pagedResultList);
+    }
+}
+

+ 74 - 0
fm-person/src/main/java/com/persagy/fm/saas/role/model/ConvertSaasRoleTool.java

@@ -0,0 +1,74 @@
+package com.persagy.fm.saas.role.model;
+
+import org.mapstruct.*;
+import org.mapstruct.MappingTarget;
+import org.mapstruct.factory.Mappers;
+import com.persagy.fm.saas.role.model.vo.*;
+import com.persagy.fm.saas.role.model.dto.*;
+
+import java.util.List;
+
+/**
+ * (SaasRole) dto、vo、do转换工具类
+ *
+ * @author lixing
+ * @version V1.0 2021-03-22 19:04:28 2021-03-22 19:04:28
+ */
+@Mapper(nullValueMappingStrategy = NullValueMappingStrategy.RETURN_DEFAULT,
+        nullValueCheckStrategy = NullValueCheckStrategy.ALWAYS)
+public interface ConvertSaasRoleTool {
+
+    ConvertSaasRoleTool INSTANCE = Mappers.getMapper(ConvertSaasRoleTool.class);
+
+    /**
+     * do转换为ResponseItemVO
+     *
+     * @param saasRole do对象
+     * @return ResponseItemVO
+     * @author lixing
+     * @version V1.0 2021-03-22 19:04:28
+     */
+    ResponseSaasRoleItemVO convert2ResponseItemDTO(SaasRole saasRole);
+
+    /**
+     * do转换为ResponseListItemVO
+     *
+     * @param saasRole do对象
+     * @return ResponseListItemVO
+     * @author lixing
+     * @version V1.0 2021-03-22 19:04:28
+     */
+    ResponseSaasRoleListItemVO convert2ResponseListItemDTO(SaasRole saasRole);
+
+    /**
+     * do列表转换为ResponseListItemVO列表
+     *
+     * @param saasRoleList do列表
+     * @return ResponseListItemVO列表
+     * @author lixing
+     * @version V1.0 2021-03-22 19:04:28
+     */
+    List<ResponseSaasRoleListItemVO> convert2List(List<SaasRole> saasRoleList);
+
+    /**
+     * addDTO转换为do
+     *
+     * @param addSaasRoleDTO addDTO
+     * @return 要创建的do对象
+     * @author lixing
+     * @version V1.0 2021-03-22 19:04:28
+     */
+    SaasRole convertAddDto2Entity(AddSaasRoleDTO addSaasRoleDTO);
+
+    /**
+     * updateDTO转换为实体
+     *
+     * @param saasRole          更新前的do对象
+     * @param updateSaasRoleDTO updateDTO
+     * @return 更新后的do对象
+     * @author lixing
+     * @version V1.0 2021-03-22 19:04:28
+     */
+    SaasRole convertUpdateDto2Entity(@MappingTarget SaasRole saasRole, UpdateSaasRoleDTO updateSaasRoleDTO);
+}
+

+ 55 - 0
fm-person/src/main/java/com/persagy/fm/saas/role/model/SaasRole.java

@@ -0,0 +1,55 @@
+package com.persagy.fm.saas.role.model;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import com.persagy.fm.common.model.entity.AuditableEntity;
+
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * (SaasRole)实体类
+ *
+ * @author lixing
+ * @version V1.0 2021-03-22 19:04:59
+ */
+@Data
+@ApiModel(description = "")
+public class SaasRole implements Serializable {
+    private static final long serialVersionUID = -13451619873751031L;
+
+    @ApiModelProperty("主键")
+    private String id;
+
+    @ApiModelProperty("角色编码")
+    private String roleCode;
+
+    @ApiModelProperty("角色名称")
+    private String roleName;
+
+    @ApiModelProperty("角色类型")
+    private String roleType;
+
+    @ApiModelProperty("账号所属")
+    private String accountBelong;
+
+    @ApiModelProperty("账号id")
+    private String accountId;
+
+    @ApiModelProperty("应用id")
+    private String appId;
+
+    @ApiModelProperty("备注")
+    private String remark;
+
+
+    public static String PROP_ROLE_CODE = "role_code";
+    public static String PROP_ROLE_NAME = "role_name";
+    public static String PROP_ROLE_TYPE = "role_type";
+    public static String PROP_ACCOUNT_BELONG = "account_belong";
+    public static String PROP_ACCOUNT_ID = "account_id";
+    public static String PROP_APP_ID = "app_id";
+    public static String PROP_REMARK = "remark";
+
+}

+ 26 - 0
fm-person/src/main/java/com/persagy/fm/saas/role/model/dto/AddSaasRoleDTO.java

@@ -0,0 +1,26 @@
+package com.persagy.fm.saas.role.model.dto;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+
+import javax.validation.constraints.NotNull;
+
+import lombok.Data;
+
+import java.util.Date;
+
+/**
+ * @author lixing
+ * @version V1.0 2021-03-22 19:04:19
+ */
+@Data
+@ApiModel(value = "创建入参")
+public class AddSaasRoleDTO {
+    @ApiModelProperty(value = "角色名称", required = true)
+    @NotNull(message = "角色名称不能为空")
+    private String roleName;
+
+    @ApiModelProperty(value = "角色类型", required = true)
+    @NotNull(message = "角色类型不能为空")
+    private String roleType;
+}

+ 20 - 0
fm-person/src/main/java/com/persagy/fm/saas/role/model/dto/DeleteSaasRoleDTO.java

@@ -0,0 +1,20 @@
+package com.persagy.fm.saas.role.model.dto;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import javax.validation.constraints.NotNull;
+
+/**
+ * @author lixing
+ * @version V1.0 2021-03-22 19:04:22
+ */
+@Data
+@ApiModel(value = "删除入参")
+public class DeleteSaasRoleDTO {
+    @NotNull(message = "id不能为空")
+    @ApiModelProperty(value = "主键", required = true)
+    private String id;
+
+}

+ 23 - 0
fm-person/src/main/java/com/persagy/fm/saas/role/model/dto/PageQuerySaasRoleDTO.java

@@ -0,0 +1,23 @@
+package com.persagy.fm.saas.role.model.dto;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+
+import java.util.Date;
+
+import com.persagy.fm.common.model.dto.PageDTO;
+import lombok.Data;
+
+/**
+ * @author lixing
+ * @version V1.0 2021-03-22 19:04:24
+ */
+@Data
+@ApiModel(value = "分页查询入参")
+public class PageQuerySaasRoleDTO extends PageDTO {
+    @ApiModelProperty(value = "角色名称", required = true)
+    private String roleName;
+
+    @ApiModelProperty(value = "角色类型", required = true)
+    private String roleType;
+}

+ 30 - 0
fm-person/src/main/java/com/persagy/fm/saas/role/model/dto/UpdateSaasRoleDTO.java

@@ -0,0 +1,30 @@
+package com.persagy.fm.saas.role.model.dto;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+
+import javax.validation.constraints.NotNull;
+
+import lombok.Data;
+
+import java.util.Date;
+
+/**
+ * @author lixing
+ * @version V1.0 2021-03-22 19:04:21
+ */
+@Data
+@ApiModel(value = "更新入参")
+public class UpdateSaasRoleDTO {
+    @ApiModelProperty(value = "主键", required = true)
+    @NotNull(message = "主键不能为空") 
+    private String id;
+
+    @ApiModelProperty(value = "角色名称", required = true)
+    @NotNull(message = "角色名称不能为空") 
+    private String roleName;
+
+    @ApiModelProperty(value = "角色类型", required = true)
+    @NotNull(message = "角色类型不能为空") 
+    private String roleType;
+}

+ 43 - 0
fm-person/src/main/java/com/persagy/fm/saas/role/model/vo/ResponseSaasRoleItemVO.java

@@ -0,0 +1,43 @@
+package com.persagy.fm.saas.role.model.vo;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.util.Date;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+
+/**
+ * @author lixing
+ * @version V1.0 2021-03-22 19:04:25
+ */
+@Data
+@ApiModel(value = "返回结果参数")
+@JsonInclude(JsonInclude.Include.NON_NULL)
+public class ResponseSaasRoleItemVO {
+    @ApiModelProperty("主键")
+    private String id;
+
+    @ApiModelProperty("角色编码")
+    private String roleCode;
+
+    @ApiModelProperty("角色名称")
+    private String roleName;
+
+    @ApiModelProperty("角色类型")
+    private String roleType;
+
+    @ApiModelProperty("账号所属")
+    private String accountBelong;
+
+    @ApiModelProperty("账号id")
+    private String accountId;
+
+    @ApiModelProperty("应用id")
+    private String appId;
+
+    @ApiModelProperty("备注")
+    private String remark;
+
+}

+ 24 - 0
fm-person/src/main/java/com/persagy/fm/saas/role/model/vo/ResponseSaasRoleListItemVO.java

@@ -0,0 +1,24 @@
+package com.persagy.fm.saas.role.model.vo;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.util.Date;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+
+/**
+ * @author lixing
+ * @version V1.0 2021-03-22 19:04:27
+ */
+@Data
+@ApiModel(value = "列表返回结果参数")
+@JsonInclude(JsonInclude.Include.NON_NULL)
+public class ResponseSaasRoleListItemVO {
+    @ApiModelProperty("主键")
+    private String id;
+
+    @ApiModelProperty("角色名称")
+    private String roleName;
+}

+ 77 - 0
fm-person/src/main/java/com/persagy/fm/saas/role/service/ISaasRoleService.java

@@ -0,0 +1,77 @@
+package com.persagy.fm.saas.role.service;
+
+import com.persagy.fm.saas.role.model.*;
+import com.persagy.fm.saas.role.model.dto.*;
+
+import java.util.List;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+
+/**
+ * (SaasRole) service接口
+ *
+ * @author lixing
+ * @version V1.0 2021-03-22 19:04:15
+ */
+public interface ISaasRoleService {
+
+    /**
+     * 创建
+     *
+     * @param addSaasRoleDTO addDTO
+     * @return 主键
+     * @author lixing
+     * @version V1.0 2021-03-22 19:04:15
+     */
+    String createSaasRole(AddSaasRoleDTO addSaasRoleDTO);
+
+//    /**
+//     * 详情
+//     *
+//     * @param id 主键
+//     * @return do对象
+//     * @author lixing
+//     * @version V1.0 2021-03-22 19:04:15
+//     */
+//    SaasRole querySaasRoleDetail(String id);
+
+    /**
+     * 更新
+     *
+     * @param updateSaasRoleDTO updateDTO
+     * @author lixing
+     * @version V1.0 2021-03-22 19:04:15
+     */
+    void updateSaasRole(UpdateSaasRoleDTO updateSaasRoleDTO);
+
+    /**
+     * 删除
+     *
+     * @param id 主键
+     * @author lixing
+     * @version V1.0 2021-03-22 19:04:15
+     */
+    void deleteSaasRole(String id);
+
+//    /**
+//     * 查询
+//     *
+//     * @param querySaasRoleDTO queryDTO
+//     * @return List<SaasRole>
+//     * @author lixing
+//     * @version V1.0 2021-03-22 19:04:15
+//     */
+//    List<SaasRole> querySaasRoleList(QuerySaasRoleDTO querySaasRoleDTO);
+
+    /**
+     * 分页查询
+     *
+     * @param pageQuerySaasRoleDTO pageQueryDTO
+     * @return IPage<SaasRole>
+     * @author lixing
+     * @version V1.0 2021-03-22 19:04:15
+     */
+    IPage<SaasRole> pageQuerySaasRole(PageQuerySaasRoleDTO pageQuerySaasRoleDTO);
+}

+ 207 - 0
fm-person/src/main/java/com/persagy/fm/saas/role/service/impl/SaasRoleServiceImpl.java

@@ -0,0 +1,207 @@
+package com.persagy.fm.saas.role.service.impl;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.google.common.base.CaseFormat;
+import com.persagy.fm.common.model.dto.Sort;
+import com.persagy.fm.saas.role.model.ConvertSaasRoleTool;
+import com.persagy.fm.saas.role.model.SaasRole;
+import com.persagy.fm.saas.role.model.dto.AddSaasRoleDTO;
+import com.persagy.fm.saas.role.model.dto.PageQuerySaasRoleDTO;
+import com.persagy.fm.saas.role.model.dto.UpdateSaasRoleDTO;
+import com.persagy.fm.saas.role.service.ISaasRoleService;
+import org.apache.commons.lang.StringUtils;
+import org.springframework.stereotype.Service;
+import org.springframework.util.CollectionUtils;
+
+import java.util.List;
+
+/**
+ * (SaasRole) service层
+ *
+ * @author lixing
+ * @version V1.0 2021-03-22 19:04:17
+ */
+@Service
+public class SaasRoleServiceImpl implements ISaasRoleService {
+
+    /**
+     * 创建
+     *
+     * @return String 主键
+     * @author lixing
+     * @version V1.0 2021-03-22 19:04:17
+     */
+    @Override
+    public String createSaasRole(AddSaasRoleDTO addSaasRoleDTO) {
+        SaasRole saasRole = ConvertSaasRoleTool.INSTANCE.convertAddDto2Entity(addSaasRoleDTO);
+        // 设置默认值
+        setDefaultValue(saasRole);
+        return saasRole.getId();
+    }
+
+    /**
+     * 如果某些字段没有赋值,使用默认的值
+     *
+     * @param saasRole 实体
+     * @author lixing
+     * @version V1.0 2021/3/12 12:29 下午
+     */
+    private void setDefaultValue(SaasRole saasRole) {
+        // todo 其他默认的属性
+
+    }
+
+//    /**
+//     * 详情
+//     *
+//     * @param id 主键
+//     * @return 部门do类
+//     * @author lixing
+//     * @version V1.0 2021-03-22 19:04:17
+//     */
+//    @Override
+//    public SaasRole querySaasRoleDetail(String id) {
+//        SaasRole saasRole = null;
+//        if (saasRole == null) {
+//            throw new IllegalArgumentException("查看SaasRole详情时发生异常,找不到要查看的记录,id=" + id);
+//        }
+//        return saasRole;
+//    }
+
+    /**
+     * 更新
+     *
+     * @author lixing
+     * @version V1.0 2021-03-22 19:04:17
+     */
+    @Override
+    public void updateSaasRole(UpdateSaasRoleDTO updateSaasRoleDTO) {
+        SaasRole saasRole = null;
+        saasRole = ConvertSaasRoleTool.INSTANCE.convertUpdateDto2Entity(saasRole, updateSaasRoleDTO);
+    }
+
+    /**
+     * 校验是否可删除
+     *
+     * @param id 主键
+     * @return do类
+     * @author lixing
+     * @version V1.0 2021-03-22 19:04:17
+     */
+    public SaasRole checkDeletable(String id) {
+        if (id == null) {
+            throw new IllegalArgumentException("删除SaasRole时发生异常,主键为空");
+        }
+
+        SaasRole saasRole = null;
+
+        if (saasRole == null) {
+            throw new IllegalArgumentException("删除SaasRole时发生异常,找不到要删除的数据,id:" + id);
+        }
+
+        return saasRole;
+    }
+
+    /**
+     * 删除
+     *
+     * @param id 主键
+     * @author lixing
+     * @version V1.0 2021-03-22 19:04:17
+     */
+    @Override
+    public void deleteSaasRole(String id) {
+        // 校验是否可删除
+        SaasRole saasRole = checkDeletable(id);
+
+    }
+
+//    /**
+//     * 查询
+//     *
+//     * @return List<SaasRole>
+//     * @author lixing
+//     * @version V1.0 2021-03-22 19:04:17
+//     */
+//    @Override
+//    public List<SaasRole> querySaasRoleList(QuerySaasRoleDTO querySaasRoleDTO) {
+//        QueryWrapper<SaasRole> queryWrapper = new QueryWrapper<>();
+//        // 默认按创建时间倒序排序
+//
+//        if (querySaasRoleDTO != null) {
+//
+//            // todo 需判断使用like还是eq
+//            if (StringUtils.isNotEmpty(querySaasRoleDTO.getRoleCode())) {
+//                queryWrapper.like(SaasRole.PROP_ROLE_CODE, querySaasRoleDTO.getRoleCode());
+//            }
+//
+//            // todo 需判断使用like还是eq
+//            if (StringUtils.isNotEmpty(querySaasRoleDTO.getRoleName())) {
+//                queryWrapper.like(SaasRole.PROP_ROLE_NAME, querySaasRoleDTO.getRoleName());
+//            }
+//
+//            // todo 需判断使用like还是eq
+//            if (StringUtils.isNotEmpty(querySaasRoleDTO.getRoleType())) {
+//                queryWrapper.like(SaasRole.PROP_ROLE_TYPE, querySaasRoleDTO.getRoleType());
+//            }
+//
+//            // todo 需判断使用like还是eq
+//            if (StringUtils.isNotEmpty(querySaasRoleDTO.getAccountBelong())) {
+//                queryWrapper.like(SaasRole.PROP_ACCOUNT_BELONG, querySaasRoleDTO.getAccountBelong());
+//            }
+//
+//            // todo 需判断使用like还是eq
+//            if (StringUtils.isNotEmpty(querySaasRoleDTO.getAccountId())) {
+//                queryWrapper.like(SaasRole.PROP_ACCOUNT_ID, querySaasRoleDTO.getAccountId());
+//            }
+//
+//            // todo 需判断使用like还是eq
+//            if (StringUtils.isNotEmpty(querySaasRoleDTO.getAppId())) {
+//                queryWrapper.like(SaasRole.PROP_APP_ID, querySaasRoleDTO.getAppId());
+//            }
+//
+//            // todo 需判断使用like还是eq
+//            if (StringUtils.isNotEmpty(querySaasRoleDTO.getRemark())) {
+//                queryWrapper.like(SaasRole.PROP_REMARK, querySaasRoleDTO.getRemark());
+//            }
+//
+//        }
+//
+//        return null;
+//    }
+
+    /**
+     * 分页查询
+     *
+     * @return IPage<SaasRole>
+     * @author lixing
+     * @version V1.0 2021-03-22 19:04:17
+     */
+    @Override
+    public IPage<SaasRole> pageQuerySaasRole(PageQuerySaasRoleDTO pageQuerySaasRoleDTO) {
+        QueryWrapper<SaasRole> queryWrapper = new QueryWrapper<>();
+        // 这里认为pageQueryDTO是经过校验的,肯定包含分页信息
+        IPage<SaasRole> pageParam = new Page<>(pageQuerySaasRoleDTO.getPage(), pageQuerySaasRoleDTO.getSize(), true);
+        // 排序信息
+        if (!CollectionUtils.isEmpty(pageQuerySaasRoleDTO.getOrders())) {
+            List<Sort> orders = pageQuerySaasRoleDTO.getOrders();
+            for (Sort sort : orders) {
+                // 将驼峰转换为下划线格式
+                sort.setColumn(CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, sort.getColumn()));
+                queryWrapper.orderBy(true, sort.isAsc(), sort.getColumn());
+            }
+        }
+
+        if (StringUtils.isNotEmpty(pageQuerySaasRoleDTO.getRoleName())) {
+            queryWrapper.like(SaasRole.PROP_ROLE_NAME, pageQuerySaasRoleDTO.getRoleName());
+        }
+
+        if (StringUtils.isNotEmpty(pageQuerySaasRoleDTO.getRoleType())) {
+            queryWrapper.eq(SaasRole.PROP_ROLE_TYPE, pageQuerySaasRoleDTO.getRoleType());
+        }
+
+        return null;
+    }
+}

+ 4 - 1
fm-person/src/main/java/com/persagy/fm/workresume/model/ConvertWorkResumeTool.java

@@ -6,6 +6,8 @@ import com.persagy.fm.workresume.model.vo.ResponseWorkResumeItemVO;
 import com.persagy.fm.workresume.model.vo.ResponseWorkResumeListItemVO;
 import org.mapstruct.Mapper;
 import org.mapstruct.MappingTarget;
+import org.mapstruct.NullValueCheckStrategy;
+import org.mapstruct.NullValueMappingStrategy;
 import org.mapstruct.factory.Mappers;
 
 import java.util.List;
@@ -16,7 +18,8 @@ import java.util.List;
  * @author lixing
  * @version V1.0 2021-03-15 17:20:08 2021-03-15 17:20:08
  */
-@Mapper
+@Mapper(nullValueMappingStrategy = NullValueMappingStrategy.RETURN_DEFAULT,
+        nullValueCheckStrategy = NullValueCheckStrategy.ALWAYS)
 public interface ConvertWorkResumeTool {
 
     ConvertWorkResumeTool INSTANCE = Mappers.getMapper(ConvertWorkResumeTool.class);

+ 17 - 7
fm-person/src/main/resources/bootstrap.yml

@@ -5,13 +5,23 @@ spring:
 server:
   port: ${SERVER_PORT:8814}
 
-amqp:
-  exchange:
-    saas: saas-exchange
-  routingKey:
-    saas: saas-routingKey
-  queue:
-    saas: saas-queue
+dep:
+  amqp:
+    exchange:
+      saas: saas.common.topic
+    routingKey:
+      saas: saas.common.group
+    queue:
+      saas: dep.saas.queue
+
+person:
+  amqp:
+    exchange:
+      saas: saas.common.topic
+    routingKey:
+      saas: saas.common.account
+    queue:
+      saas: person.saas.queue
 
 #mybatis-plus:
 #  mapper-locations: classpath*:/mapper/*Mapper.xml

+ 17 - 17
fm-person/src/main/resources/mapper/DepartmentMapper.xml

@@ -1,22 +1,22 @@
 <?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.persagy.fm.department.dao.DepartmentDao">
-    <resultMap id="DepartmentMap" type="com.persagy.fm.department.model.Department">
-        <result column="id" property="id"/>
-        <result column="name" property="name"/>
-        <result column="type" property="type"/>
-        <result column="parent_id" property="parentId"/>
-        <result column="resource_from" property="resourceFrom"/>
-        <result column="managers" property="managers"/>
-        <result column="full_path" property="fullPath"/>
-        <result column="staff_count" property="staffCount"/>
-        <result column="has_children" property="hasChildren"/>
-        <result column="ts" property="ts"/>
-        <result column="creator" property="creator"/>
-        <result column="creation_time" property="creationTime"/>
-        <result column="modifier" property="modifier"/>
-        <result column="modified_time" property="modifiedTime"/>
-        <result column="valid" property="valid"/>
-    </resultMap>
+<!--    <resultMap id="DepartmentMap" type="com.persagy.fm.department.model.Department">-->
+<!--        <result column="id" property="id"/>-->
+<!--        <result column="name" property="name"/>-->
+<!--        <result column="type" property="type"/>-->
+<!--        <result column="parent_id" property="parentId"/>-->
+<!--        <result column="resource_from" property="resourceFrom"/>-->
+<!--        <result column="managers" property="managers"/>-->
+<!--        <result column="full_path" property="fullPath"/>-->
+<!--        <result column="staff_count" property="staffCount"/>-->
+<!--        <result column="has_children" property="hasChildren"/>-->
+<!--        <result column="ts" property="ts"/>-->
+<!--        <result column="creator" property="creator"/>-->
+<!--        <result column="creation_time" property="creationTime"/>-->
+<!--        <result column="modifier" property="modifier"/>-->
+<!--        <result column="modified_time" property="modifiedTime"/>-->
+<!--        <result column="valid" property="valid"/>-->
+<!--    </resultMap>-->
 </mapper>
 

+ 16 - 0
fm-person/src/main/resources/mapper/ProfessionMapper.xml

@@ -0,0 +1,16 @@
+<?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.persagy.fm.profession.dao.ProfessionDao">
+    <resultMap id="ProfessionMap" type="com.persagy.fm.profession.model.Profession">
+        <result column="id" property="id"/>
+        <result column="name" property="name"/>
+        <result column="editable" property="editable"/>
+        <result column="ts" property="ts"/>
+        <result column="creator" property="creator"/>
+        <result column="creation_time" property="creationTime"/>
+        <result column="modifier" property="modifier"/>
+        <result column="modified_time" property="modifiedTime"/>
+        <result column="valid" property="valid"/>
+    </resultMap>
+</mapper>
+