DESKTOP-2HCHTFV\Xu 5 ヶ月 前
コミット
8e0375b693
74 ファイル変更1952 行追加341 行削除
  1. 28 0
      pom.xml
  2. 30 0
      src/main/java/com/loan/system/config/FileUploadConfig.java
  3. 5 3
      src/main/java/com/loan/system/config/WebMvcConfiguration.java
  4. 1 0
      src/main/java/com/loan/system/constant/JwtClaimsConstant.java
  5. 393 0
      src/main/java/com/loan/system/controller/ApprovalController.java
  6. 123 86
      src/main/java/com/loan/system/controller/wechat/UploadController.java
  7. 140 9
      src/main/java/com/loan/system/controller/wechat/UserController.java
  8. 14 0
      src/main/java/com/loan/system/domain/WXAuth.java
  9. 14 0
      src/main/java/com/loan/system/domain/dto/ApprovalDTO.java
  10. 16 0
      src/main/java/com/loan/system/domain/dto/CustomerLoginDTO.java
  11. 20 0
      src/main/java/com/loan/system/domain/dto/DocumentDTO.java
  12. 15 0
      src/main/java/com/loan/system/domain/dto/PreApprovalDTO.java
  13. 2 1
      src/main/java/com/loan/system/domain/dto/UserLoginDTO.java
  14. 11 0
      src/main/java/com/loan/system/domain/dto/WeChatLoginDTO.java
  15. 2 2
      src/main/java/com/loan/system/domain/entity/ApprovalRecord.java
  16. 5 2
      src/main/java/com/loan/system/domain/entity/BizRecommender.java
  17. 11 2
      src/main/java/com/loan/system/domain/entity/Collateral.java
  18. 12 3
      src/main/java/com/loan/system/domain/entity/Contract.java
  19. 5 2
      src/main/java/com/loan/system/domain/entity/Customer.java
  20. 2 2
      src/main/java/com/loan/system/domain/entity/CustomersOther.java
  21. 1 1
      src/main/java/com/loan/system/domain/entity/DictAttribute.java
  22. 1 1
      src/main/java/com/loan/system/domain/entity/DictBusinessType.java
  23. 1 1
      src/main/java/com/loan/system/domain/entity/DictChannel.java
  24. 1 1
      src/main/java/com/loan/system/domain/entity/DictLocation.java
  25. 1 1
      src/main/java/com/loan/system/domain/entity/DictMessage.java
  26. 1 1
      src/main/java/com/loan/system/domain/entity/DictStep.java
  27. 1 1
      src/main/java/com/loan/system/domain/entity/DictType.java
  28. 2 2
      src/main/java/com/loan/system/domain/entity/Disbursement.java
  29. 1 1
      src/main/java/com/loan/system/domain/entity/DisbursementRecord.java
  30. 13 4
      src/main/java/com/loan/system/domain/entity/Document.java
  31. 11 8
      src/main/java/com/loan/system/domain/entity/LoanCase.java
  32. 2 2
      src/main/java/com/loan/system/domain/entity/Repayment.java
  33. 1 1
      src/main/java/com/loan/system/domain/entity/RepaymentRecord.java
  34. 9 0
      src/main/java/com/loan/system/domain/entity/Role.java
  35. 1 1
      src/main/java/com/loan/system/domain/entity/StatBusinessSnapshot.java
  36. 1 1
      src/main/java/com/loan/system/domain/entity/StatFundEfficiency.java
  37. 4 7
      src/main/java/com/loan/system/domain/entity/Step.java
  38. 16 0
      src/main/java/com/loan/system/domain/entity/TemplateMessage.java
  39. 2 5
      src/main/java/com/loan/system/domain/entity/User.java
  40. 26 0
      src/main/java/com/loan/system/domain/enums/DecisionEnum.java
  41. 3 0
      src/main/java/com/loan/system/domain/enums/ExceptionEnum.java
  42. 1 1
      src/main/java/com/loan/system/domain/enums/StepEnum.java
  43. 55 23
      src/main/java/com/loan/system/domain/enums/StepPropertyEnum.java
  44. 20 0
      src/main/java/com/loan/system/domain/vo/CustomerLoginVO.java
  45. 23 0
      src/main/java/com/loan/system/domain/vo/DocumentVO.java
  46. 18 0
      src/main/java/com/loan/system/domain/vo/LoanCasePreApprovalVo.java
  47. 25 0
      src/main/java/com/loan/system/domain/vo/StepVO.java
  48. 3 0
      src/main/java/com/loan/system/domain/vo/UserLoginVO.java
  49. 72 1
      src/main/java/com/loan/system/interceptor/JwtTokenUserInterceptor.java
  50. 22 0
      src/main/java/com/loan/system/repository/ApprovalRepository.java
  51. 25 0
      src/main/java/com/loan/system/repository/CustomerRepository.java
  52. 14 0
      src/main/java/com/loan/system/repository/DocumentRepository.java
  53. 24 0
      src/main/java/com/loan/system/repository/LoanCaseRepository.java
  54. 52 0
      src/main/java/com/loan/system/repository/StepRepository.java
  55. 7 6
      src/main/java/com/loan/system/repository/UserRepository.java
  56. 16 0
      src/main/java/com/loan/system/service/ApprovalService.java
  57. 10 0
      src/main/java/com/loan/system/service/CustomerService.java
  58. 13 0
      src/main/java/com/loan/system/service/DocumentService.java
  59. 34 0
      src/main/java/com/loan/system/service/Impl/ApprovalServiceImpl.java
  60. 30 0
      src/main/java/com/loan/system/service/Impl/CustomerServiceImpl.java
  61. 31 0
      src/main/java/com/loan/system/service/Impl/DocumentServiceImpl.java
  62. 30 0
      src/main/java/com/loan/system/service/Impl/LoanCaseServiceImpl.java
  63. 52 17
      src/main/java/com/loan/system/service/Impl/PermissionService.java
  64. 139 0
      src/main/java/com/loan/system/service/Impl/StepServiceImpl.java
  65. 106 3
      src/main/java/com/loan/system/service/Impl/UserServiceImpl.java
  66. 107 0
      src/main/java/com/loan/system/service/Impl/WxServiceImpl.java
  67. 11 0
      src/main/java/com/loan/system/service/LoanCaseService.java
  68. 30 0
      src/main/java/com/loan/system/service/StepService.java
  69. 6 1
      src/main/java/com/loan/system/service/UserService.java
  70. 10 0
      src/main/java/com/loan/system/service/WxService.java
  71. 4 1
      src/main/java/com/loan/system/utils/JwtTokenUtil.java
  72. 0 122
      src/main/java/com/loan/system/utils/WeChatUtil.java
  73. 5 6
      src/main/resources/application-dev.yaml
  74. 9 9
      src/main/resources/application.yaml

+ 28 - 0
pom.xml

@@ -22,6 +22,32 @@
     </properties>
     </properties>
 
 
     <dependencies>
     <dependencies>
+        <dependency>
+            <groupId>org.json</groupId>
+            <artifactId>json</artifactId>
+            <version>20231013</version> <!-- 使用最新版本 -->
+        </dependency>
+        <dependency>
+            <groupId>cn.hutool</groupId>
+            <artifactId>hutool-all</artifactId>
+            <version>5.8.11</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.httpcomponents</groupId>
+            <artifactId>httpclient</artifactId>
+            <version>4.5.13</version>
+        </dependency>
+        <dependency>
+            <groupId>com.alibaba</groupId>
+            <artifactId>fastjson</artifactId>
+            <version>1.2.83</version>
+        </dependency>
+        <dependency>
+            <groupId>com.squareup.okhttp3</groupId>
+            <artifactId>okhttp</artifactId>
+            <version>4.10.0</version>
+        </dependency>
+
         <dependency>
         <dependency>
             <groupId>javax.annotation</groupId>
             <groupId>javax.annotation</groupId>
             <artifactId>jsr250-api</artifactId>
             <artifactId>jsr250-api</artifactId>
@@ -270,6 +296,8 @@
                             <version>${org.lombok.version}</version>
                             <version>${org.lombok.version}</version>
                         </path>
                         </path>
                     </annotationProcessorPaths>
                     </annotationProcessorPaths>
+                    <source>8</source>
+                    <target>8</target>
                 </configuration>
                 </configuration>
             </plugin>
             </plugin>
         </plugins>
         </plugins>

+ 30 - 0
src/main/java/com/loan/system/config/FileUploadConfig.java

@@ -0,0 +1,30 @@
+package com.loan.system.config;
+
+import org.springframework.context.annotation.Configuration;
+import org.springframework.beans.factory.annotation.Value; // 添加此行
+
+import java.util.Arrays;
+import java.util.Locale;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+@Configuration
+public class FileUploadConfig {
+
+    @Value("${upload.location}")
+    private String uploadDir;
+
+    @Value("${upload.extensions}")
+    private String allowedExtensions;
+
+    public String getUploadDir() {
+        return uploadDir.endsWith("/")? uploadDir : uploadDir + "/";
+    }
+
+    /** 把 yml 中的扩展名字符串解析成 Set<String> */
+    public Set<String> getAllowedExtensions() {
+        return Arrays.stream(allowedExtensions.split(","))
+                .map(s -> s.toLowerCase(Locale.ROOT).trim())
+                .collect(Collectors.toSet());
+    }
+}

+ 5 - 3
src/main/java/com/loan/system/config/WebMvcConfiguration.java

@@ -8,6 +8,7 @@ import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
 import org.springframework.context.annotation.Configuration;
 import org.springframework.http.converter.HttpMessageConverter;
 import org.springframework.http.converter.HttpMessageConverter;
 import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
 import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
+import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
 import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
 import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
 import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
 import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
 import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
 import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
@@ -25,13 +26,14 @@ import java.util.List;
  */
  */
 @Configuration//配置文件类会在程序运行时自动加载
 @Configuration//配置文件类会在程序运行时自动加载
 @Slf4j
 @Slf4j
+@EnableGlobalMethodSecurity(prePostEnabled = true)
 public class WebMvcConfiguration extends WebMvcConfigurationSupport {
 public class WebMvcConfiguration extends WebMvcConfigurationSupport {
 
 
 //    @Autowired
 //    @Autowired
 //    private JwtTokenAdminInterceptor jwtTokenAdminInterceptor;
 //    private JwtTokenAdminInterceptor jwtTokenAdminInterceptor;
     @Autowired
     @Autowired
     private JwtTokenUserInterceptor jwtTokenUserInterceptor;
     private JwtTokenUserInterceptor jwtTokenUserInterceptor;
-
+//
     /*
     /*
      * 注册自定义拦截器
      * 注册自定义拦截器
      * @param registry
      * @param registry
@@ -43,7 +45,7 @@ public class WebMvcConfiguration extends WebMvcConfigurationSupport {
 //                .excludePathPatterns("/admin/employee/login");
 //                .excludePathPatterns("/admin/employee/login");
 
 
         registry.addInterceptor(jwtTokenUserInterceptor)
         registry.addInterceptor(jwtTokenUserInterceptor)
-                .addPathPatterns("/wechat/**")
+                .addPathPatterns("/wechat/**","/User/**")
                 .excludePathPatterns("/wechat/login");
                 .excludePathPatterns("/wechat/login");
     }
     }
 
 
@@ -86,7 +88,7 @@ public class WebMvcConfiguration extends WebMvcConfigurationSupport {
                 .apiInfo(apiInfo)
                 .apiInfo(apiInfo)
                 .select()
                 .select()
                 //最重要:确定要扫描的包
                 //最重要:确定要扫描的包
-                .apis(RequestHandlerSelectors.basePackage("com.loan.system.controller.wechat"))
+                .apis(RequestHandlerSelectors.basePackage("com.loan.system.controller"))
                 .paths(PathSelectors.any())
                 .paths(PathSelectors.any())
                 .build();
                 .build();
         return docket;
         return docket;

+ 1 - 0
src/main/java/com/loan/system/constant/JwtClaimsConstant.java

@@ -4,6 +4,7 @@ public class JwtClaimsConstant {
 
 
     public static final String EMP_ID = "empId";
     public static final String EMP_ID = "empId";
     public static final String USER_ID = "userId";
     public static final String USER_ID = "userId";
+    public static final String CUSTOMER_ID = "customerId";
     public static final String PHONE = "phone";
     public static final String PHONE = "phone";
     public static final String USERNAME = "username";
     public static final String USERNAME = "username";
     public static final String NAME = "name";
     public static final String NAME = "name";

+ 393 - 0
src/main/java/com/loan/system/controller/ApprovalController.java

@@ -0,0 +1,393 @@
+package com.loan.system.controller;
+
+import com.loan.system.domain.dto.ApprovalDTO;
+import com.loan.system.domain.dto.PreApprovalDTO;
+import com.loan.system.domain.entity.*;
+import com.loan.system.domain.enums.DecisionEnum;
+import com.loan.system.domain.enums.StepEnum;
+import com.loan.system.domain.enums.StepPropertyEnum;
+import com.loan.system.domain.pojo.Result;
+import com.loan.system.domain.vo.LoanCasePreApprovalVo;
+import com.loan.system.properties.JwtProperties;
+import com.loan.system.service.*;
+import com.loan.system.service.Impl.UserServiceImpl;
+import com.loan.system.utils.JwtUtil;
+import com.loan.system.utils.ResultUtil;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import javax.servlet.http.HttpServletRequest;
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+import java.util.List;
+
+import static com.loan.system.domain.enums.ExceptionEnum.*;
+
+@RestController
+@RequestMapping("/User")
+@Api(tags = "业务审核接口")
+public class ApprovalController {
+    private static final Logger log = LoggerFactory.getLogger(UserServiceImpl.class);
+    @Autowired
+    private UserService userService;
+    @Autowired
+    private CustomerService customerService;
+    @Autowired
+    private LoanCaseService  loanCaseService;
+    @Autowired
+    private ApprovalService approvalService;
+    @Autowired
+    private DocumentService documentService;
+    @Autowired
+    private StepService stepService;
+    @Autowired
+    private JwtProperties jwtProperties;
+    @Autowired
+    private WxService wxService;
+
+    @GetMapping("/loan_case/{id}")
+    @ApiOperation("获取业务客户信息")
+    //TODO:给前端展示的VO补充完整
+    public Result info(@PathVariable Long id) {
+        log.info("获取业务客户信息: {}", id);
+        LoanCase loanCase = loanCaseService.findByIdAndIsDelete(id);
+        Customer customer = customerService.findByIdAndIsDelete(loanCase.getCustomerId());
+        Step step = stepService.findByStepNameAndCaseId(StepPropertyEnum.PRE_TRIAL.getLabel(),id);
+        //List<Document> documentList = documentService.findDocumentByCaseIdAndIsDelete(customer.getId());
+        User user1= userService.findByIdAndIsDelete(step.getUserId1());
+        User user2= userService.findByIdAndIsDelete(step.getUserId2());
+        LoanCasePreApprovalVo loanCasePreApprovalVo = new LoanCasePreApprovalVo();
+        if(user1!=null){
+            loanCasePreApprovalVo.setLead_Sales(user1.getRealName());
+        }
+        if(user2!=null){
+            loanCasePreApprovalVo.setAssist_Sales(user2.getRealName());
+        }
+        //TODO 补充业务信息、客户信息
+
+
+        return ResultUtil.success("success",loanCasePreApprovalVo);
+    }
+    @PostMapping("/preapproval-assist/{caseId}/pass")
+    @PreAuthorize("@pms.hasRole('ASSIST_SALES')")
+    @ApiOperation("副业务员审核")
+    public Result pre_approval_save_primary(PreApprovalDTO preApprovalDTO, HttpServletRequest request) {
+        //请求头根据token获取用户信息
+        //String token = request.getHeader("Authorization").substring(7); // 去掉"Bearer "前缀
+        String token = request.getHeader("Authorization");
+        Long userId=Long.parseLong(JwtUtil.parseJWT(jwtProperties.getUserSecretKey(),token).get("userId").toString());
+        log.info("用户id: {}", userId);
+        User user = userService.findByIdAndIsDelete(userId);
+        log.info("用户: {}", user.getMobile());
+        LoanCase loanCase = loanCaseService.findByIdAndIsDelete(preApprovalDTO.getCaseId());
+        if(loanCase == null||loanCase.getIsDelete()){
+            return ResultUtil.error(PROJECT_NOT_EXIST.getCode(), PROJECT_NOT_EXIST.getMsg());
+        }
+        Step step = stepService.findByStepNameAndCaseId(StepPropertyEnum.PRE_TRIAL.getLabel(), preApprovalDTO.getCaseId());
+        if(step.getUserId2()!=null&&userId!=step.getUserId2()){
+            return ResultUtil.error(STEP_USER_NOT_EXPECTED.getCode(), "环节处理人不是预期用户");
+        }
+        if(step.getStatus()==StepEnum.COMPLETED.getMsg()){
+            return ResultUtil.error(STEP_HAS_COMPLETEED.getCode(), "环节已完成,无法重复审批");
+        }
+        ApprovalRecord approvalRecord_origin = approvalService.findByCaseIdAndIsDeleteAndStepName(preApprovalDTO.getCaseId(),StepPropertyEnum.PRE_TRIAL.getLabel(),userId);
+        if (approvalRecord_origin == null) {
+            // 创建审批记录
+            ApprovalRecord approvalRecord = new ApprovalRecord();
+            approvalRecord.setCaseId(preApprovalDTO.getCaseId());
+            approvalRecord.setStepName(StepPropertyEnum.PRE_TRIAL.getLabel());
+            approvalRecord.setApproverId(user.getId());
+            approvalRecord.setDecision(DecisionEnum.PASS.getMsg());
+            approvalRecord.setComments(preApprovalDTO.getComments());
+            approvalRecord.setCreateTime(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
+            approvalRecord.setUpdateTime(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
+            approvalRecord.setIsDelete(false);
+            // 保存到数据库
+            approvalService.save(approvalRecord);
+            stepService.updateUserId2ByCaseIdAndStepName(StepPropertyEnum.PRE_TRIAL.getLabel(), user.getId(), preApprovalDTO.getCaseId());
+        }else {
+            approvalService.updateDecisionByCaseIdAndStepNameAndIsDelete(DecisionEnum.PASS.getMsg(), preApprovalDTO.getCaseId(), StepPropertyEnum.PRE_TRIAL.getLabel(), preApprovalDTO.getComments(), userId);
+        }
+        stepService.updateUserId2ByCaseIdAndStepName(StepPropertyEnum.PRE_TRIAL.getLabel(),userId,preApprovalDTO.getCaseId());
+        //更新步骤状态
+        stepService.updateStatusByCaseId(StepEnum.COMPLETED.getMsg(), StepPropertyEnum.PRE_TRIAL_PARENT.getLabel(), preApprovalDTO.getCaseId());
+        stepService.updateStatusByCaseId(StepEnum.COMPLETED.getMsg(), StepPropertyEnum.PRE_TRIAL.getLabel(), preApprovalDTO.getCaseId());
+        stepService.updateStatusByCaseId(StepEnum.PROCESS.getMsg(), StepPropertyEnum.APPROVAL_PARENT.getLabel(), preApprovalDTO.getCaseId());
+        stepService.updateStatusByCaseId(StepEnum.PROCESS.getMsg(), StepPropertyEnum.APPROVAL.getLabel(), preApprovalDTO.getCaseId());
+        loanCaseService.updateUpdatetimeByIdAndIsDeleted(preApprovalDTO.getCaseId(),false);
+        //TODO:微信推送预审通过消息和通知下一环节
+//        wxService.sendTemplateMessage(loanCase.getCustomer().getMobile(),new TemplateMessage());
+        return ResultUtil.success("success","预审通过");
+    }
+
+//    @PostMapping("/approval-lead/{caseId}/pass")
+//    @PreAuthorize("@pms.hasRole('LEAD_SALES')")
+//    @ApiOperation("主业务员审核")
+//    public Result pre_approval_save_assist(PreApprovalDTO preApprovalDTO, HttpServletRequest request) {
+//        //请求头根据token获取用户信息
+//        //String token = request.getHeader("Authorization").substring(7); // 去掉"Bearer "前缀
+//        String token = request.getHeader("Authorization");
+//        Long userId=Long.parseLong(JwtUtil.parseJWT(jwtProperties.getUserSecretKey(),token).get("userId").toString());
+//        log.info("用户id: {}", userId);
+//        User user = userService.findByIdAndIsDelete(userId);
+//        log.info("用户: {}", user.getMobile());
+//        LoanCase loanCase = loanCaseService.findByIdAndIsDelete(preApprovalDTO.getCaseId());
+//        if(loanCase == null){
+//            return ResultUtil.error(PROJECT_NOT_EXIST.getCode(), PROJECT_NOT_EXIST.getMsg());
+//        }
+//        // TODO: 使用userId进行后续操作
+//        // 创建新的审批记录
+//        ApprovalRecord approvalRecord = new ApprovalRecord();
+//        approvalRecord.setCaseId(preApprovalDTO.getCaseId());
+//        approvalRecord.setStepName(StepPropertyEnum.PRE_TRIAL.getLabel());
+//        approvalRecord.setApproverId(userId);
+//        approvalRecord.setDecision(DecisionEnum.PASS.getMsg());
+//        approvalRecord.setComments(preApprovalDTO.getComments());
+//        approvalRecord.setCreateTime(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
+//        approvalRecord.setUpdateTime(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
+//        approvalRecord.setIsDelete(false);
+//        // 保存到数据库
+//        approvalService.save(approvalRecord);
+//        stepService.updateUserId1ByCaseIdAndStepName(StepPropertyEnum.PRE_TRIAL.getLabel(),userId,preApprovalDTO.getCaseId());
+//        Step step = stepService.findByStepNameAndCaseId(StepPropertyEnum.PRE_TRIAL.getLabel(),preApprovalDTO.getCaseId());
+//        if(step.getUserId1()!=null && step.getUserId2()!=null){
+//            stepService.updateStatusByCaseId(StepEnum.COMPLETED.getMsg(), StepPropertyEnum.PRE_TRIAL_PARENT.getLabel(),preApprovalDTO.getCaseId());
+//            stepService.updateStatusByCaseId(StepEnum.COMPLETED.getMsg(), StepPropertyEnum.PRE_TRIAL.getLabel(),preApprovalDTO.getCaseId());
+//            stepService.updateStatusByCaseId(StepEnum.PROCESS.getMsg(), StepPropertyEnum.APPROVAL_PARENT.getLabel(),preApprovalDTO.getCaseId());
+//            stepService.updateStatusByCaseId(StepEnum.PROCESS.getMsg(), StepPropertyEnum.APPROVAL.getLabel(),preApprovalDTO.getCaseId());
+//            //TODO: 添加业务逻辑 ,通知下一个环节审批人
+//        }
+//        log.info("业务id: {}", preApprovalDTO.getCaseId());
+//        loanCaseService.updateUpdatetimeByIdAndIsDeleted(preApprovalDTO.getCaseId(),false);
+//        return ResultUtil.success("success","审批通过");
+//    }
+
+    @PostMapping("/preapproval-records/{caseId}/reject")
+    @PreAuthorize("@pms.hasAnyRoles('LEAD_SALES','ASSIST_SALES')")
+    @ApiOperation("业务预审拒绝")
+    public Result pre_approval_reject(PreApprovalDTO preApprovalDTO, HttpServletRequest request) {
+        //请求头根据token获取用户信息
+        //String token = request.getHeader("Authorization").substring(7); // 去掉"Bearer "前缀
+        String token = request.getHeader("Authorization");
+        Long userId=Long.parseLong(JwtUtil.parseJWT(jwtProperties.getUserSecretKey(),token).get("userId").toString());
+        log.info("用户id: {}", userId);
+        User user = userService.findByIdAndIsDelete(userId);
+        log.info("用户: {}", user.getMobile());
+        LoanCase loanCase = loanCaseService.findByIdAndIsDelete(preApprovalDTO.getCaseId());
+        Step step = stepService.findByStepNameAndCaseId(StepPropertyEnum.PRE_TRIAL.getLabel(), preApprovalDTO.getCaseId());
+        //判断过去处理人与目前处理人是否一致
+        if(step.getUserId2()!=null&&userId!=step.getUserId2()){
+            return ResultUtil.error(STEP_USER_NOT_EXPECTED.getCode(), "环节处理人不是预期用户");
+        }
+        if(step.getStatus()==StepEnum.COMPLETED.getMsg()){
+            return ResultUtil.error(STEP_HAS_COMPLETEED.getCode(), "环节已完成,无法重复审批");
+        }
+        if(loanCase == null||loanCase.getIsDelete()){
+            return ResultUtil.error(PROJECT_NOT_EXIST.getCode(), PROJECT_NOT_EXIST.getMsg());
+        }
+        ApprovalRecord approvalRecord_origin = approvalService.findByCaseIdAndIsDeleteAndStepName(preApprovalDTO.getCaseId(),StepPropertyEnum.PRE_TRIAL.getLabel(),userId);
+        if(approvalRecord_origin == null) {
+            log.info("没找到对应以前审批记录");
+            // 创建审批记录
+            ApprovalRecord approvalRecord = new ApprovalRecord();
+            approvalRecord.setCaseId(preApprovalDTO.getCaseId());
+            approvalRecord.setStepName(StepPropertyEnum.PRE_TRIAL.getLabel());
+            approvalRecord.setApproverId(userId);
+            approvalRecord.setDecision(DecisionEnum.REJECT.getMsg());
+            approvalRecord.setComments(preApprovalDTO.getComments());
+            approvalRecord.setCreateTime(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
+            approvalRecord.setUpdateTime(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
+            approvalRecord.setIsDelete(false);
+            // 保存到数据库
+            approvalService.save(approvalRecord);
+        }else{
+            log.info("找到对应以前审批记录");
+            approvalService.updateDecisionByCaseIdAndStepNameAndIsDelete(DecisionEnum.REJECT.getMsg(),preApprovalDTO.getCaseId(),StepPropertyEnum.PRE_TRIAL.getLabel(),preApprovalDTO.getComments(),userId);
+        }
+        stepService.updateUserId2ByCaseIdAndStepName(StepPropertyEnum.PRE_TRIAL.getLabel(),userId,preApprovalDTO.getCaseId());
+        loanCaseService.updateUpdatetimeByIdAndIsDeleted(preApprovalDTO.getCaseId(),false);
+        //TODO:微信推送预审拒绝消息和通知下一环节
+//        wxService.sendTemplateMessage(loanCase.getCustomer().getMobile(),new TemplateMessage());
+        return ResultUtil.success("success","预审拒绝");
+    }
+
+    @PostMapping("/approval/{caseId}/pass")
+    @PreAuthorize("@pms.hasRole('APPROVER')")
+    @ApiOperation("业务审批通过")
+    public Result approval_pass(ApprovalDTO approvalDTO, HttpServletRequest request) {
+        String token = request.getHeader("Authorization");
+        Long userId=Long.parseLong(JwtUtil.parseJWT(jwtProperties.getUserSecretKey(),token).get("userId").toString());
+        log.info("用户id: {}", userId);
+        //审批业务逻辑
+        LoanCase loanCase = loanCaseService.findByIdAndIsDelete(approvalDTO.getCaseId());
+        Step step = stepService.findByStepNameAndCaseId(StepPropertyEnum.APPROVAL.getLabel(), approvalDTO.getCaseId());
+        //判断过去处理人与目前处理人是否一致
+        if(step.getUserId1()!=null&&step.getUserId2()!=null&&userId!=step.getUserId2()&&userId!=step.getUserId1()){
+            return ResultUtil.error(STEP_USER_NOT_EXPECTED.getCode(), "环节处理人不是预期用户");
+        }
+        if(step.getStatus()==StepEnum.COMPLETED.getMsg()){
+            return ResultUtil.error(STEP_HAS_COMPLETEED.getCode(), "环节已完成,无法重复审批");
+        }
+        if(loanCase == null||loanCase.getIsDelete()){
+            return ResultUtil.error(PROJECT_NOT_EXIST.getCode(), PROJECT_NOT_EXIST.getMsg());
+        }
+        ApprovalRecord approvalRecord_origin = approvalService.findByCaseIdAndIsDeleteAndStepName(approvalDTO.getCaseId(),StepPropertyEnum.APPROVAL.getLabel(),userId);
+        if(approvalRecord_origin == null) {
+            log.info("没找到对应以前审批记录");
+            // 创建审批记录
+            ApprovalRecord approvalRecord = new ApprovalRecord();
+            approvalRecord.setCaseId(approvalDTO.getCaseId());
+            approvalRecord.setStepName(StepPropertyEnum.APPROVAL.getLabel());
+            approvalRecord.setApproverId(userId);
+            approvalRecord.setDecision(DecisionEnum.PASS.getMsg());
+            approvalRecord.setComments(approvalDTO.getComments());
+            approvalRecord.setCreateTime(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
+            approvalRecord.setUpdateTime(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
+            approvalRecord.setIsDelete(false);
+            // 保存到数据库
+            approvalService.save(approvalRecord);
+        }else{
+            log.info("找到对应以前审批记录");
+            approvalService.updateDecisionByCaseIdAndStepNameAndIsDelete(DecisionEnum.PASS.getMsg(),approvalDTO.getCaseId(),StepPropertyEnum.APPROVAL.getLabel(),approvalDTO.getComments(),userId);
+        }
+        if(step.getUserId1()== null){
+            stepService.updateUserId1ByCaseIdAndStepName(StepPropertyEnum.APPROVAL.getLabel(),userId,approvalDTO.getCaseId());
+        }else if(step.getUserId2()== null){
+            stepService.updateUserId2ByCaseIdAndStepName(StepPropertyEnum.APPROVAL.getLabel(),userId,approvalDTO.getCaseId());
+        }
+        if(step.getUserId1()!=null&&step.getUserId2()!=null){
+            ApprovalRecord approvalRecord_user1 = approvalService.findByCaseIdAndIsDeleteAndStepName(approvalDTO.getCaseId(),StepPropertyEnum.APPROVAL.getLabel(),step.getUserId1());
+            ApprovalRecord approvalRecord_user2 = approvalService.findByCaseIdAndIsDeleteAndStepName(approvalDTO.getCaseId(),StepPropertyEnum.APPROVAL.getLabel(),step.getUserId2());
+            if(approvalRecord_user1.getDecision() == DecisionEnum.PASS.getMsg()&&approvalRecord_user2.getDecision() == DecisionEnum.PASS.getMsg()){
+                stepService.updateStatusByCaseId(StepEnum.COMPLETED.getMsg(),StepPropertyEnum.APPROVAL_PARENT.getLabel(),approvalDTO.getCaseId());
+                stepService.updateStatusByCaseId(StepEnum.COMPLETED.getMsg(),StepPropertyEnum.APPROVAL.getLabel(),approvalDTO.getCaseId());
+                stepService.updateStatusByCaseId(StepEnum.PROCESS.getMsg(),StepPropertyEnum.CONTRACT_SIGN_PARENT.getLabel(),approvalDTO.getCaseId());
+                stepService.updateStatusByCaseId(StepEnum.PROCESS.getMsg(),StepPropertyEnum.CONTRACT_SIGN.getLabel(),approvalDTO.getCaseId());
+                //TODO微信推送审批通过消息和通知下一环节
+            }
+        }else{
+            //TODO微信推送另一个审批人审批
+        }
+
+        return ResultUtil.success("success","审批通过");
+
+    }
+
+    @PostMapping("/approval/{caseId}/reject")
+    @PreAuthorize("@pms.hasRole('APPROVER')")
+    @ApiOperation("业务审批拒绝")
+    public Result approval_reject(ApprovalDTO approvalDTO, HttpServletRequest request) {
+        String token = request.getHeader("Authorization");
+        Long userId=Long.parseLong(JwtUtil.parseJWT(jwtProperties.getUserSecretKey(),token).get("userId").toString());
+        log.info("用户id: {}", userId);
+        //审批业务逻辑
+        LoanCase loanCase = loanCaseService.findByIdAndIsDelete(approvalDTO.getCaseId());
+        if(loanCase == null||loanCase.getIsDelete()){
+            return ResultUtil.error(PROJECT_NOT_EXIST.getCode(), PROJECT_NOT_EXIST.getMsg());
+        }
+        Step step = stepService.findByStepNameAndCaseId(StepPropertyEnum.APPROVAL.getLabel(), approvalDTO.getCaseId());
+        //判断过去处理人与目前处理人是否一致
+        if(step.getUserId1()!=null&&step.getUserId2()!=null&&userId!=step.getUserId2()&&userId!=step.getUserId1()){
+            return ResultUtil.error(STEP_USER_NOT_EXPECTED.getCode(), "环节处理人不是预期用户");
+        }
+        if(step.getStatus()==StepEnum.COMPLETED.getMsg()){
+            return ResultUtil.error(STEP_HAS_COMPLETEED.getCode(), "环节已完成,无法重复审批");
+        }
+        //审批记录处理
+        ApprovalRecord approvalRecord_origin = approvalService.findByCaseIdAndIsDeleteAndStepName(approvalDTO.getCaseId(),StepPropertyEnum.APPROVAL.getLabel(),userId);
+        if(approvalRecord_origin == null) {
+            log.info("没找到对应以前审批记录");
+            // 创建审批记录
+            ApprovalRecord approvalRecord = new ApprovalRecord();
+            approvalRecord.setCaseId(approvalDTO.getCaseId());
+            approvalRecord.setStepName(StepPropertyEnum.APPROVAL.getLabel());
+            approvalRecord.setApproverId(userId);
+            approvalRecord.setDecision(DecisionEnum.REJECT.getMsg());
+            approvalRecord.setComments(approvalDTO.getComments());
+            approvalRecord.setCreateTime(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
+            approvalRecord.setUpdateTime(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
+            approvalRecord.setIsDelete(false);
+            // 保存到数据库
+            approvalService.save(approvalRecord);
+        }else{
+            log.info("找到对应以前审批记录");
+            approvalService.updateDecisionByCaseIdAndStepNameAndIsDelete(DecisionEnum.REJECT.getMsg(),approvalDTO.getCaseId(),StepPropertyEnum.APPROVAL.getLabel(),approvalDTO.getComments(),userId);
+        }
+        if(step.getUserId1()== null){
+            stepService.updateUserId1ByCaseIdAndStepName(StepPropertyEnum.APPROVAL.getLabel(),userId,approvalDTO.getCaseId());
+        }else if(step.getUserId2()== null){
+            stepService.updateUserId2ByCaseIdAndStepName(StepPropertyEnum.APPROVAL.getLabel(),userId,approvalDTO.getCaseId());
+        }
+        //更新环节状态
+        stepService.updateStatusByCaseId(StepEnum.PROCESS.getMsg(),StepPropertyEnum.BUSINESS_ACCEPT_PARENT.getLabel(),approvalDTO.getCaseId());
+        stepService.updateStatusByCaseId(StepEnum.PROCESS.getMsg(),StepPropertyEnum.BUSINESS_ACCEPT.getLabel(),approvalDTO.getCaseId());
+        stepService.updateStatusByCaseId(StepEnum.UNSTART.getMsg(),StepPropertyEnum.PRE_TRIAL_PARENT.getLabel(),approvalDTO.getCaseId());
+        stepService.updateStatusByCaseId(StepEnum.UNSTART.getMsg(),StepPropertyEnum.PRE_TRIAL.getLabel(),approvalDTO.getCaseId());
+        stepService.updateStatusByCaseId(StepEnum.UNSTART.getMsg(),StepPropertyEnum.APPROVAL_PARENT.getLabel(),approvalDTO.getCaseId());
+        stepService.updateStatusByCaseId(StepEnum.UNSTART.getMsg(),StepPropertyEnum.APPROVAL.getLabel(),approvalDTO.getCaseId());
+        //TODO微信推送审批驳回消息和通知重新受理(到业务受理)
+
+        return ResultUtil.success("success","审批驳回");
+    }
+    @PostMapping("/approval/{caseId}/terminate")
+    @PreAuthorize("@pms.hasRole('APPROVER')")
+    @ApiOperation("业务审批终结")
+    public Result approval_end(ApprovalDTO approvalDTO, HttpServletRequest request) {
+        String token = request.getHeader("Authorization");
+        Long userId=Long.parseLong(JwtUtil.parseJWT(jwtProperties.getUserSecretKey(),token).get("userId").toString());
+        log.info("用户id: {}", userId);
+        //审批业务逻辑
+        LoanCase loanCase = loanCaseService.findByIdAndIsDelete(approvalDTO.getCaseId());
+        if(loanCase == null||loanCase.getIsDelete()){
+            return ResultUtil.error(PROJECT_NOT_EXIST.getCode(), PROJECT_NOT_EXIST.getMsg());
+        }
+        Step step = stepService.findByStepNameAndCaseId(StepPropertyEnum.APPROVAL.getLabel(), approvalDTO.getCaseId());
+        //判断过去处理人与目前处理人是否一致
+        if(step.getUserId1()!=null&&step.getUserId2()!=null&&userId!=step.getUserId2()&&userId!=step.getUserId1()){
+            return ResultUtil.error(STEP_USER_NOT_EXPECTED.getCode(), "环节处理人不是预期用户");
+        }
+        if(step.getStatus()==StepEnum.COMPLETED.getMsg()){
+            return ResultUtil.error(STEP_HAS_COMPLETEED.getCode(), "环节已完成,无法重复审批");
+        }
+        //审批记录处理
+        ApprovalRecord approvalRecord_origin = approvalService.findByCaseIdAndIsDeleteAndStepName(approvalDTO.getCaseId(),StepPropertyEnum.APPROVAL.getLabel(),userId);
+        if(approvalRecord_origin == null) {
+            log.info("没找到对应以前审批记录");
+            // 创建审批记录
+            ApprovalRecord approvalRecord = new ApprovalRecord();
+            approvalRecord.setCaseId(approvalDTO.getCaseId());
+            approvalRecord.setStepName(StepPropertyEnum.APPROVAL.getLabel());
+            approvalRecord.setApproverId(userId);
+            approvalRecord.setDecision(DecisionEnum.TERMINATE.getMsg());
+            approvalRecord.setComments(approvalDTO.getComments());
+            approvalRecord.setCreateTime(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
+            approvalRecord.setUpdateTime(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
+            approvalRecord.setIsDelete(false);
+            // 保存到数据库
+            approvalService.save(approvalRecord);
+        }else{
+            log.info("找到对应以前审批记录");
+            approvalService.updateDecisionByCaseIdAndStepNameAndIsDelete(DecisionEnum.TERMINATE.getMsg(),approvalDTO.getCaseId(),StepPropertyEnum.APPROVAL.getLabel(),approvalDTO.getComments(),userId);
+        }
+        if(step.getUserId1()== null){
+            stepService.updateUserId1ByCaseIdAndStepName(StepPropertyEnum.APPROVAL.getLabel(),userId,approvalDTO.getCaseId());
+        }else if(step.getUserId2()== null){
+            stepService.updateUserId2ByCaseIdAndStepName(StepPropertyEnum.APPROVAL.getLabel(),userId,approvalDTO.getCaseId());
+        }
+        //更新项目和环节状态 作逻辑删除
+        loanCaseService.logic_delete(approvalDTO.getCaseId());
+        List<Step> steps = stepService.getAllStepByCaseId(approvalDTO.getCaseId());
+        for (Step step_each : steps){
+            stepService.logic_delete(step_each.getId());
+        }
+        //TODO微信推送审批驳回消息和通知重新受理(到业务受理)
+
+        return ResultUtil.success("success","审批驳回");
+    }
+}
+

+ 123 - 86
src/main/java/com/loan/system/controller/wechat/UploadController.java

@@ -1,99 +1,136 @@
 package com.loan.system.controller.wechat;
 package com.loan.system.controller.wechat;
 
 
+import com.loan.system.config.FileUploadConfig;
+import com.loan.system.domain.entity.Document;
 import com.loan.system.domain.enums.ExceptionEnum;
 import com.loan.system.domain.enums.ExceptionEnum;
 import com.loan.system.domain.pojo.Result;
 import com.loan.system.domain.pojo.Result;
-import com.loan.system.service.Impl.MediaUploadService;
-import com.loan.system.utils.FileUploadUtil;
+import com.loan.system.exception.FileException;
+import com.loan.system.service.DocumentService;
 import com.loan.system.utils.ResultUtil;
 import com.loan.system.utils.ResultUtil;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.apache.commons.io.FilenameUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.RequestParam;
-import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.bind.annotation.*;
 import org.springframework.web.multipart.MultipartFile;
 import org.springframework.web.multipart.MultipartFile;
 
 
-import java.io.IOException;
+import javax.servlet.http.HttpServletResponse;
+import java.io.*;
+import java.net.URLEncoder;
+import java.nio.file.Files;
+import java.nio.file.StandardCopyOption;
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+import java.util.*;
 
 
-/**
- * @author : EdwinXu
- * @date : Created in 2020/12/16 15:34
- */
 @RestController
 @RestController
+@RequestMapping("/wechat/file")
+@Api(tags = "文件处理接口")
 public class UploadController {
 public class UploadController {
+    @Autowired
+    private DocumentService fileService;
+    @Autowired
+    private FileUploadConfig config;
 
 
-//    @Autowired
-//    MediaUploadService uploadService;
-//
-//    @PostMapping("/file/verify")
-//    public Result verifyExist(@RequestParam("fileMd5") String fileMd5,
-//                              @RequestParam("fileName") String fileName,
-//                              @RequestParam("fileSize") Long fileSize,
-//                              @RequestParam("mimetype") String mimetype,
-//                              @RequestParam("fileExt") String fileExt) throws IOException {
-//        System.out.println("=========register==========> ");
-//        System.out.println(fileMd5);
-//        System.out.println(fileName);
-//        System.out.println(fileSize);
-//        System.out.println(mimetype);
-//        System.out.println(fileExt);
-//        boolean register = FileUploadUtil.register(fileMd5, "/project-1/contracts/contract-1", fileExt);
-//        if (register){
-//            return ResultUtil.success();
-//        } else {
-//            return ResultUtil.error(ExceptionEnum.FILE_NOT_EXIST);
-//        }
-////        return uploadService.register(fileMd5,fileName,fileSize,mimetype,fileExt);
-//    }
-//    //校验文件块
-//
-//    @PostMapping("/checkChunk")
-//    public Result checkChunk(@RequestParam("fileMd5") String fileMd5,
-//                             @RequestParam("chunk") Integer chunk,
-//                             @RequestParam("chunkSize") Integer chunkSize) {
-//        System.out.println("=========checkChunk==========> ");
-//        boolean aBoolean = FileUploadUtil.checkChunk("/project-1/contracts/contract-1", chunk);
-//        if (aBoolean){
-//            return ResultUtil.success();
-//        } else {
-//            return ResultUtil.error(ExceptionEnum.FILE_NOT_EXIST);
-//        }
-////        return uploadService.checkChunk(fileMd5,chunk,chunkSize);
-//    }
-//
-//    //上传文件块
-//
-//    @PostMapping("/uploadChunk")
-//    public Result uploadChunk(@RequestParam("file") MultipartFile file,
-//                              @RequestParam("fileMd5") String fileMd5,
-//                              @RequestParam("chunk") Integer chunk) {
-//        System.out.println("=========uploadChunk==========> ");
-//        System.out.println(file);
-//        System.out.println(fileMd5);
-//        System.out.println(chunk);
-//        boolean uploadChunk = FileUploadUtil.uploadChunk(file, "/project-1/contracts/contract-1", chunk);
-//        if (uploadChunk){
-//            return ResultUtil.success();
-//        } else {
-//            return ResultUtil.error(ExceptionEnum.FILE_NOT_EXIST);
-//        }
-//        return uploadService.uploadChunk(file,fileMd5,chunk);
-//    }
-
-    //合并文件块
-/*
-    @PostMapping("/mergeChunks")
-    public Result mergeChunks(@RequestParam("fileMd5") String fileMd5,
-                              @RequestParam("fileName") String fileName,
-                              @RequestParam("fileSize") Long fileSize,
-                              @RequestParam("mimetype") String mimetype,
-                              @RequestParam("fileExt") String fileExt) {
-        System.out.println("=========mergeChunks==========> ");
-        System.out.println(fileMd5);
-        System.out.println(fileName);
-        System.out.println(fileSize);
-        System.out.println(mimetype);
-        System.out.println(fileExt);
-//        return uploadService.mergeChunks(fileMd5,fileMd5,fileSize,mimetype,fileExt);
-//        FileUploadUtil.mergeChunks(fileMd5, fileName, "/project-1/contracts/contract-1", fileSize, mimetype, fileExt);
-
-    }*/
+    /** 上传文件(支持任意类型,只要在白名单内) */
+    @PostMapping("/upload/{caseId}/{type}")
+    @ApiOperation("文件上传")
+    public Result uploadFile(@PathVariable("caseId") Long caseId,@PathVariable("type") String fileType,@RequestParam("file") MultipartFile[] files) throws IOException{
+
+        for (int i=0 ; i < files.length ; i++){
+            MultipartFile file =files[i];
+
+            if (file.isEmpty())
+                return ResultUtil.error(ExceptionEnum.FILE_IS_EMPTY);
+
+            String originalName = file.getOriginalFilename();
+            String ext = FilenameUtils.getExtension(originalName).toLowerCase(Locale.ROOT);
+
+            // 从配置中读取允许的扩展名
+            Set<String> allowed = config.getAllowedExtensions();
+            if (!allowed.contains(ext)) {
+                ResultUtil.error(ExceptionEnum.FILE_UPLOAD_TYPE_NOT_DEFINED);
+            }
+
+            String newFileName = null;
+            // 生成新的文件名
+            if(i == 0)
+                newFileName = String.format("%d-%s-%s.%s", caseId, fileType, originalName, ext);
+            else
+                newFileName = String.format("%d-%s-%s(%d).%s", caseId, fileType, originalName, i, ext);
+
+            // 创建目录
+            File uploadDir = new File(config.getUploadDir(), String.valueOf(caseId) + "/" + fileType);
+            if (!uploadDir.exists() && !uploadDir.mkdirs()) {
+                return ResultUtil.error(ExceptionEnum.DIRECTORY_CREATE_ERROR);
+            }
+
+            // 使用NIO复制流,稳定性更好
+            File destFile = new File(uploadDir, newFileName);
+            try (InputStream in = file.getInputStream()) {
+                Files.copy(in, destFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
+            }
+
+            Document document = new Document();
+            document.setCaseId(caseId);
+            document.setFileName(newFileName);
+            document.setOriginName(originalName);
+            document.setFilePath(destFile.getPath());
+            document.setFileSize(file.getSize());
+            document.setDocType(ext);
+            document.setDictType(fileType);
+            document.setIsDelete( false);
+            document.setCreateTime(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
+            document.setUpdateTime(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
+            fileService.uploadFile(document);
+        }
+
+        return ResultUtil.success("上传成功");
+    }
+
+
+    /** 下载文件 */
+    @GetMapping("/download/{fileName}")
+    @ApiOperation("文件下载")
+    public void downloadFile(@PathVariable String fileName, HttpServletResponse response)throws  IOException{
+        File file = new File(config.getUploadDir(), fileName);
+        if (!file.exists()) {
+            response.sendError(HttpServletResponse.SC_NOT_FOUND, "文件不存在");
+            return;
+        }
+
+        response.setContentType(Files.probeContentType(file.toPath()));
+        response.setHeader("Content-Disposition",
+                "attachment; filename=" + URLEncoder.encode(file.getName(), "UTF-8"));
+
+        try (InputStream in = new FileInputStream(file);
+             OutputStream out = response.getOutputStream()) {
+            byte[] buffer = new byte[8192];
+            int len;
+            while ((len = in.read(buffer)) != -1) {
+                out.write(buffer, 0, len);
+            }
+        }
+    }
+
+    /** 删除文件 */
+    @DeleteMapping("/delete/{fileName}")
+    @ApiOperation("文件删除")
+    public Result deleteFile(@PathVariable String fileName) {
+        File file = new File(config.getUploadDir(), fileName);
+
+        if (!file.exists())
+            return ResultUtil.error(ExceptionEnum.FILE_NOT_EXIST);
+
+        boolean isDelete = file.delete();
+        if (!isDelete)
+            return ResultUtil.error(ExceptionEnum.FILE_DELETE_ERROR);
+
+        return ResultUtil.success("文件删除成功");
+    }
+
+    @PostMapping("save/{caseId}/{type}")
+    public Result saveFile(@PathVariable("caseId") Long caseId,@PathVariable("type") String type,@RequestParam String fileName){
+        return ResultUtil.success();
+    }
 }
 }

+ 140 - 9
src/main/java/com/loan/system/controller/wechat/UserController.java

@@ -1,20 +1,32 @@
 package com.loan.system.controller.wechat;
 package com.loan.system.controller.wechat;
 
 
 import com.loan.system.constant.JwtClaimsConstant;
 import com.loan.system.constant.JwtClaimsConstant;
+
 import com.loan.system.domain.dto.UserLoginDTO;
 import com.loan.system.domain.dto.UserLoginDTO;
+import com.loan.system.domain.dto.WeChatLoginDTO;
+import com.loan.system.domain.entity.Customer;
 import com.loan.system.domain.entity.User;
 import com.loan.system.domain.entity.User;
 import com.loan.system.domain.pojo.Result;
 import com.loan.system.domain.pojo.Result;
+import com.loan.system.domain.vo.CustomerLoginVO;
 import com.loan.system.domain.vo.UserLoginVO;
 import com.loan.system.domain.vo.UserLoginVO;
 import com.loan.system.properties.JwtProperties;
 import com.loan.system.properties.JwtProperties;
+import com.loan.system.service.CustomerService;
+import com.loan.system.service.Impl.UserServiceImpl;
 import com.loan.system.service.UserService;
 import com.loan.system.service.UserService;
+import com.loan.system.service.WxService;
 import com.loan.system.utils.JwtUtil;
 import com.loan.system.utils.JwtUtil;
 import com.loan.system.utils.ResultUtil;
 import com.loan.system.utils.ResultUtil;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
 import io.swagger.annotations.ApiOperation;
 import org.apache.commons.lang3.ObjectUtils;
 import org.apache.commons.lang3.ObjectUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.*;
 import org.springframework.web.bind.annotation.*;
 
 
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+import java.util.Date;
 import java.util.HashMap;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.Map;
 
 
@@ -23,35 +35,154 @@ import java.util.Map;
  * @date 2020/9/2 - 19:11
  * @date 2020/9/2 - 19:11
  */
  */
 @RestController
 @RestController
-@RequestMapping("/wechat")
+@RequestMapping("/WeChat")
 @Api(tags = "微信用户接口")
 @Api(tags = "微信用户接口")
 public class UserController {
 public class UserController {
     @Autowired
     @Autowired
     private UserService userService;
     private UserService userService;
     @Autowired
     @Autowired
     private JwtProperties jwtProperties;
     private JwtProperties jwtProperties;
+    @Autowired
+    private WxService wxService;
+    @Autowired
+    private CustomerService customerService;
+    private static final Logger log = LoggerFactory.getLogger(UserServiceImpl.class);
+    @GetMapping("/get_sessionId")
+    @ApiOperation("获取微信openid")
+    public Result get_sessionId(String code){
+        return userService.get_sessionId(code);
+    }
+    /**
+     * 微信登陆 区分用户还是客户 如果都不是就注册成客户
+     * @param wxAuth
+     * @return
+     */
+//    @PostMapping("/authlogin")
+//    @ApiOperation("微信授权登陆获取openid")
+//    public Result authLogin(@RequestBody WXAuth wxAuth){
+//        try {
+//            String json=wxService.wxDecrypt(wxAuth.getEncryptedData(),wxAuth.getIv(),wxAuth.getSessionKey());
+//            JSONObject jsonObject = JSON.parseObject(json);
+//            String openid=jsonObject.getString("openId");
+//            log.info("获取到的用户openid:{}",openid);
+//            if(openid!=null) {
+//                return ResultUtil.success("success", openid);
+//            }
+////            userLoginDTO.setTel(phoneNumber);
+//        } catch (Exception e) {
+//            e.printStackTrace();
+//            log.error("微信登陆异常:{}",e.getMessage());
+//            return ResultUtil.error(ExceptionEnum.WECHAT_LOGIN_ERROR);
+//        }
+//        return ResultUtil.error(ExceptionEnum.WECHAT_LOGIN_ERROR);
+//    }
 
 
-    @PostMapping("/login")
-    @ApiOperation("微信登陆")
-    public Result login(@RequestBody UserLoginDTO userLoginDTO){
-        //微信登录
-        User user = userService.wxLogin(userLoginDTO);
-        System.out.println(userLoginDTO.getTel());
+    /**
+     * 客户登陆
+     * @param customer
+     * @return
+     */
+    public Result customer_login(Customer customer){
+        customer=customerService.findBymobileAndIsDelete(customer.getMobile());
+       if (ObjectUtils.isEmpty(customer))
+            throw new IllegalArgumentException("Customer object is null");
+        //为微信用户生成jwt令牌
+        Map<String ,Object> claims=new HashMap<>();
+        //用openid还是id?
+        //claims.put(JwtClaimsConstant.CUSTOMER_ID,customer.getOpenid());
+        claims.put(JwtClaimsConstant.USER_ID,customer.getId());
+        String token = JwtUtil.createJWT(jwtProperties.getUserSecretKey(), jwtProperties.getUserTtl(), claims);
+        log.info("手机号码:{}",customer.getMobile());
+        CustomerLoginVO customerLoginVO = CustomerLoginVO.builder()
+                .id(customer.getId())
+                .openid(customer.getOpenid())
+                .token(token)
+                .name(customer.getName())
+                .is_customer(1)
+                .build();
 
 
+        return ResultUtil.success("success", customerLoginVO);
+    }
+
+    /**
+     * 用户登陆
+     * @param userLoginDTO
+     * @return
+     */
+    public Result user_login(UserLoginDTO userLoginDTO){
+        User user= userService.findByPhoneNumberAndIsDelete(userLoginDTO.getTel());
         if (ObjectUtils.isEmpty(user))
         if (ObjectUtils.isEmpty(user))
             throw new IllegalArgumentException("User object is null");
             throw new IllegalArgumentException("User object is null");
-
         //为微信用户生成jwt令牌
         //为微信用户生成jwt令牌
         Map<String ,Object> claims=new HashMap<>();
         Map<String ,Object> claims=new HashMap<>();
         claims.put(JwtClaimsConstant.USER_ID,user.getId());
         claims.put(JwtClaimsConstant.USER_ID,user.getId());
         String token = JwtUtil.createJWT(jwtProperties.getUserSecretKey(), jwtProperties.getUserTtl(), claims);
         String token = JwtUtil.createJWT(jwtProperties.getUserSecretKey(), jwtProperties.getUserTtl(), claims);
-
+        log.info("手机号码:{}",userLoginDTO.getTel());
+        log.info("用户ID:{}",user.getId());
         UserLoginVO userLoginVO = UserLoginVO.builder()
         UserLoginVO userLoginVO = UserLoginVO.builder()
                 .id(user.getId())
                 .id(user.getId())
                 .openid(user.getOpenid())
                 .openid(user.getOpenid())
                 .token(token)
                 .token(token)
+                .is_customer(0)
+                .username(user.getUsername())
                 .build();
                 .build();
 
 
         return ResultUtil.success("success", userLoginVO);
         return ResultUtil.success("success", userLoginVO);
     }
     }
+
+    /**
+     * 注册客户
+     * @param customer
+     * @return
+     */
+    public Result register(Customer customer){
+        customer.setCreateTime(LocalDateTime.now()
+                .format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
+        customer.setUpdateTime(LocalDateTime.now()
+                .format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
+        customerService.createCustomer(customer);
+        return this.customer_login(customer);
+    }
+
+    @PostMapping("/login_wechat")
+    @ApiOperation("微信手机号登陆")
+    public Result login(@RequestBody WeChatLoginDTO weChatLoginDTO){
+        String access_token=wxService.getAccessToken();
+        String phoneNumber=wxService.getUserPhoneNumber(access_token,weChatLoginDTO.getCode());
+        boolean user_is_exist = userService.existsByMobileAndIsDelete(phoneNumber);
+        boolean customer_is_exist=customerService.existsBymobileAndIsDelete(phoneNumber);
+        log.info("code:{}",phoneNumber);
+        log.info("用户是否存在:{}",user_is_exist);
+        if(!customer_is_exist&&!user_is_exist){
+            Customer customer = new Customer();
+            customer.setMobile(phoneNumber);
+            customer.setOpenid(weChatLoginDTO.getOpenid());
+            return this.register(customer);
+        }else if(customer_is_exist){   //存在客户
+            Customer customer=customerService.findBymobileAndIsDelete(phoneNumber);
+            return this.customer_login(customer);
+        }else { //存在用户
+            UserLoginDTO userLoginDTO = new UserLoginDTO();
+            userLoginDTO.setTel(phoneNumber);
+            return this.user_login(userLoginDTO);
+        }
+    }
+    @PostMapping("/login")
+    @ApiOperation("账号登陆")
+    public Result login(@RequestBody UserLoginDTO userLoginDTO){
+        String phoneNumber=userLoginDTO.getTel();
+        boolean user_is_exist = userService.existsByMobileAndIsDelete(phoneNumber);
+        boolean customer_is_exist=customerService.existsBymobileAndIsDelete(phoneNumber);
+        if(!customer_is_exist&&!user_is_exist){
+            Customer customer = new Customer();
+            customer.setMobile(phoneNumber);
+            customer.setOpenid(userLoginDTO.getOpenid());
+            return this.register(customer);
+        }else if(customer_is_exist){
+            Customer customer=customerService.findBymobileAndIsDelete(phoneNumber);
+            return this.customer_login(customer);
+        }else{
+            return this.user_login(userLoginDTO);
+        }
+    }
 }
 }

+ 14 - 0
src/main/java/com/loan/system/domain/WXAuth.java

@@ -0,0 +1,14 @@
+package com.loan.system.domain;
+
+import lombok.Data;
+
+@Data
+public class WXAuth {
+    private String encryptedData;
+    private String iv;
+    private String sessionKey;
+    private String signature;
+    private String rawData;
+
+
+}

+ 14 - 0
src/main/java/com/loan/system/domain/dto/ApprovalDTO.java

@@ -0,0 +1,14 @@
+package com.loan.system.domain.dto;
+
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+public class ApprovalDTO {
+    private Long CaseId;
+    private String comments;
+}

+ 16 - 0
src/main/java/com/loan/system/domain/dto/CustomerLoginDTO.java

@@ -0,0 +1,16 @@
+package com.loan.system.domain.dto;
+
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+public class CustomerLoginDTO implements Serializable {
+    private String mobile;
+    private String openid;
+}

+ 20 - 0
src/main/java/com/loan/system/domain/dto/DocumentDTO.java

@@ -0,0 +1,20 @@
+package com.loan.system.domain.dto;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+public class DocumentDTO implements Serializable {
+    private Long caseId;//业务ID
+    private Long ownerId;//客户id
+    private String dictType;//资料类型
+    private String docType;//文档类型
+    private String filePath;//文件路径
+    private String fileName;//文件名
+    private Long fileSize;//文件大小
+}

+ 15 - 0
src/main/java/com/loan/system/domain/dto/PreApprovalDTO.java

@@ -0,0 +1,15 @@
+package com.loan.system.domain.dto;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+public class PreApprovalDTO implements Serializable {
+    private Long caseId;//业务ID
+    private String comments;
+}

+ 2 - 1
src/main/java/com/loan/system/domain/dto/UserLoginDTO.java

@@ -6,5 +6,6 @@ import java.io.Serializable;
 
 
 @Data
 @Data
 public class UserLoginDTO implements Serializable {
 public class UserLoginDTO implements Serializable {
-    String tel;
+    private String tel;
+    private String openid;
 }
 }

+ 11 - 0
src/main/java/com/loan/system/domain/dto/WeChatLoginDTO.java

@@ -0,0 +1,11 @@
+package com.loan.system.domain.dto;
+
+import lombok.Data;
+
+import java.io.Serializable;
+
+@Data
+public class WeChatLoginDTO implements Serializable {
+    private String code;
+    private String openid;
+}

+ 2 - 2
src/main/java/com/loan/system/domain/entity/ApprovalRecord.java

@@ -33,10 +33,10 @@ public class ApprovalRecord extends BaseEntity{
     private String comments;
     private String comments;
 
 
     @Column(name = "create_time")
     @Column(name = "create_time")
-    private Instant createTime;
+    private String createTime;
 
 
     @Column(name = "update_time")
     @Column(name = "update_time")
-    private Instant updateTime;
+    private String updateTime;
 
 
     @Column(name = "is_delete")
     @Column(name = "is_delete")
     private Boolean isDelete;
     private Boolean isDelete;

+ 5 - 2
src/main/java/com/loan/system/domain/entity/BizRecommender.java

@@ -31,6 +31,9 @@ public class BizRecommender extends BaseEntity{
     @Column(name = "channel", length = 50)
     @Column(name = "channel", length = 50)
     private String channel;
     private String channel;
 
 
+    @Column(name = "group" ,length = 50)
+    private String group;
+
     @Column(name = "id_card", length = 20)
     @Column(name = "id_card", length = 20)
     private String idCard;
     private String idCard;
 
 
@@ -48,10 +51,10 @@ public class BizRecommender extends BaseEntity{
     private String remark;
     private String remark;
 
 
     @Column(name = "create_time")
     @Column(name = "create_time")
-    private Instant createTime;
+    private String createTime;
 
 
     @Column(name = "update_time")
     @Column(name = "update_time")
-    private Instant updateTime;
+    private String updateTime;
 
 
     @Column(name = "create_user_id")
     @Column(name = "create_user_id")
     private Long createUserId;
     private Long createUserId;

+ 11 - 2
src/main/java/com/loan/system/domain/entity/Collateral.java

@@ -19,6 +19,12 @@ public class Collateral extends BaseEntity{
     @Column(name = "case_id")
     @Column(name = "case_id")
     private Long caseId;
     private Long caseId;
 
 
+    @Column(name = "contract_id")
+    private Long contractId;
+
+    @Column(name = "collateral_name", length = 50)
+    private String collateralName;
+
     @Column(name = "collateral_type", length = 30)
     @Column(name = "collateral_type", length = 30)
     private String collateralType;
     private String collateralType;
 
 
@@ -31,6 +37,9 @@ public class Collateral extends BaseEntity{
     @Column(name = "address", length = 500)
     @Column(name = "address", length = 500)
     private String address;
     private String address;
 
 
+    @Column(name = "current_address", length = 255)
+    private String currentAddress;
+
     @Column(name = "eval_price", precision = 18, scale = 2)
     @Column(name = "eval_price", precision = 18, scale = 2)
     private BigDecimal evalPrice;
     private BigDecimal evalPrice;
 
 
@@ -41,10 +50,10 @@ public class Collateral extends BaseEntity{
     private String staus;
     private String staus;
 
 
     @Column(name = "create_time")
     @Column(name = "create_time")
-    private Instant createTime;
+    private String createTime;
 
 
     @Column(name = "update_time")
     @Column(name = "update_time")
-    private Instant updateTime;
+    private String updateTime;
 
 
     @Column(name = "is_delete")
     @Column(name = "is_delete")
     private Boolean isDelete;
     private Boolean isDelete;

+ 12 - 3
src/main/java/com/loan/system/domain/entity/Contract.java

@@ -24,6 +24,9 @@ public class Contract extends BaseEntity{
     @Column(name = "case_id")
     @Column(name = "case_id")
     private Long caseId;
     private Long caseId;
 
 
+    @Column(name = "customer_id")
+    private Long customerId;
+
     @Column(name = "contract_no", length = 50)
     @Column(name = "contract_no", length = 50)
     private String contractNo;
     private String contractNo;
 
 
@@ -49,17 +52,23 @@ public class Contract extends BaseEntity{
     @Column(name = "signed_by_customer")
     @Column(name = "signed_by_customer")
     private Boolean signedByCustomer;
     private Boolean signedByCustomer;
 
 
+    @Column(name = "commited_id")
+    private Long commitedId;
+
     @Column(name = "sifned_id")
     @Column(name = "sifned_id")
     private Long sifnedId;
     private Long sifnedId;
 
 
     @Column(name = "signed_time")
     @Column(name = "signed_time")
-    private Instant signedTime;
+    private String signedTime;
+
+    @Column(name = "is_push")
+    private Boolean isPush;
 
 
     @Column(name = "create_time")
     @Column(name = "create_time")
-    private Instant createTime;
+    private String createTime;
 
 
     @Column(name = "update_time")
     @Column(name = "update_time")
-    private Instant updateTime;
+    private String updateTime;
 
 
     @Column(name = "is_delete")
     @Column(name = "is_delete")
     private Boolean isDelete;
     private Boolean isDelete;

+ 5 - 2
src/main/java/com/loan/system/domain/entity/Customer.java

@@ -31,6 +31,9 @@ public class Customer extends BaseEntity{
     @Column(name = "mobile", length = 11)
     @Column(name = "mobile", length = 11)
     private String mobile;
     private String mobile;
 
 
+    @Column(name = "married_status", length = 50)
+    private String marriedStatus;
+
     @Column(name = "register_source", length = 50)
     @Column(name = "register_source", length = 50)
     private String registerSource;
     private String registerSource;
 
 
@@ -41,10 +44,10 @@ public class Customer extends BaseEntity{
     private Boolean faceAuth;
     private Boolean faceAuth;
 
 
     @Column(name = "create_time")
     @Column(name = "create_time")
-    private Instant createTime;
+    private String createTime;
 
 
     @Column(name = "update_time")
     @Column(name = "update_time")
-    private Instant updateTime;
+    private String updateTime;
 
 
     @Column(name = "is_delete")
     @Column(name = "is_delete")
     private Boolean isDelete;
     private Boolean isDelete;

+ 2 - 2
src/main/java/com/loan/system/domain/entity/CustomersOther.java

@@ -26,10 +26,10 @@ public class CustomersOther extends BaseEntity{
     private String mobile;
     private String mobile;
 
 
     @Column(name = "create_time")
     @Column(name = "create_time")
-    private Instant createTime;
+    private String createTime;
 
 
     @Column(name = "update_time")
     @Column(name = "update_time")
-    private Instant updateTime;
+    private String updateTime;
 
 
     @Column(name = "is_delete")
     @Column(name = "is_delete")
     private Boolean isDelete;
     private Boolean isDelete;

+ 1 - 1
src/main/java/com/loan/system/domain/entity/DictAttribute.java

@@ -30,7 +30,7 @@ public class DictAttribute extends BaseEntity{
     private Integer sortOrder;
     private Integer sortOrder;
 
 
     @Column(name = "created_at")
     @Column(name = "created_at")
-    private Instant createdAt;
+    private String createdAt;
 
 
     @Column(name = "is_delete")
     @Column(name = "is_delete")
     private Boolean isDelete;
     private Boolean isDelete;

+ 1 - 1
src/main/java/com/loan/system/domain/entity/DictBusinessType.java

@@ -30,7 +30,7 @@ public class DictBusinessType extends BaseEntity{
     private Integer sortOrder;
     private Integer sortOrder;
 
 
     @Column(name = "created_at")
     @Column(name = "created_at")
-    private Instant createdAt;
+    private String createdAt;
 
 
     @Column(name = "is_delete")
     @Column(name = "is_delete")
     private Boolean isDelete;
     private Boolean isDelete;

+ 1 - 1
src/main/java/com/loan/system/domain/entity/DictChannel.java

@@ -31,7 +31,7 @@ public class DictChannel extends BaseEntity{
     private Integer sortOrder;
     private Integer sortOrder;
 
 
     @Column(name = "created_at")
     @Column(name = "created_at")
-    private Instant createdAt;
+    private String createdAt;
 
 
     @Column(name = "is_delete")
     @Column(name = "is_delete")
     private Boolean isDelete;
     private Boolean isDelete;

+ 1 - 1
src/main/java/com/loan/system/domain/entity/DictLocation.java

@@ -30,7 +30,7 @@ public class DictLocation extends BaseEntity{
     private Integer sortOrder;
     private Integer sortOrder;
 
 
     @Column(name = "created_at")
     @Column(name = "created_at")
-    private Instant createdAt;
+    private String createdAt;
 
 
     @Column(name = "is_delete")
     @Column(name = "is_delete")
     private Boolean isDelete;
     private Boolean isDelete;

+ 1 - 1
src/main/java/com/loan/system/domain/entity/DictMessage.java

@@ -30,7 +30,7 @@ public class DictMessage extends BaseEntity{
     private Integer sortOrder;
     private Integer sortOrder;
 
 
     @Column(name = "created_at")
     @Column(name = "created_at")
-    private Instant createdAt;
+    private String createdAt;
 
 
     @Column(name = "is_delete")
     @Column(name = "is_delete")
     private Boolean isDelete;
     private Boolean isDelete;

+ 1 - 1
src/main/java/com/loan/system/domain/entity/DictStep.java

@@ -33,7 +33,7 @@ public class DictStep extends BaseEntity{
     private Integer sortOrder;
     private Integer sortOrder;
 
 
     @Column(name = "created_at")
     @Column(name = "created_at")
-    private Instant createdAt;
+    private String createdAt;
 
 
     @Column(name = "is_delete")
     @Column(name = "is_delete")
     private Boolean isDelete;
     private Boolean isDelete;

+ 1 - 1
src/main/java/com/loan/system/domain/entity/DictType.java

@@ -30,7 +30,7 @@ public class DictType extends BaseEntity{
     private Integer sortOrder;
     private Integer sortOrder;
 
 
     @Column(name = "created_at")
     @Column(name = "created_at")
-    private Instant createdAt;
+    private String createdAt;
 
 
     @Column(name = "is_delete")
     @Column(name = "is_delete")
     private Boolean isDelete;
     private Boolean isDelete;

+ 2 - 2
src/main/java/com/loan/system/domain/entity/Disbursement.java

@@ -53,10 +53,10 @@ public class Disbursement extends BaseEntity{
     private Instant payoutTime;
     private Instant payoutTime;
 
 
     @Column(name = "create_time")
     @Column(name = "create_time")
-    private Instant createTime;
+    private String createTime;
 
 
     @Column(name = "update_time")
     @Column(name = "update_time")
-    private Instant updateTime;
+    private String updateTime;
 
 
     @Column(name = "is_delete")
     @Column(name = "is_delete")
     private Boolean isDelete;
     private Boolean isDelete;

+ 1 - 1
src/main/java/com/loan/system/domain/entity/DisbursementRecord.java

@@ -24,7 +24,7 @@ public class DisbursementRecord extends BaseEntity{
     private BigDecimal amount;
     private BigDecimal amount;
 
 
     @Column(name = "create_time")
     @Column(name = "create_time")
-    private Instant createTime;
+    private String createTime;
 
 
     @Column(name = "is_delete")
     @Column(name = "is_delete")
     private Boolean isDelete;
     private Boolean isDelete;

+ 13 - 4
src/main/java/com/loan/system/domain/entity/Document.java

@@ -21,8 +21,8 @@ public class Document extends BaseEntity{
     @Column(name = "owner_id")
     @Column(name = "owner_id")
     private Long ownerId;
     private Long ownerId;
 
 
-    @Column(name = "type_id")
-    private Long typeId;
+    @Column(name = "dict_type" , length = 20)
+    private String dictType;
 
 
     @Column(name = "doc_type", length = 50)
     @Column(name = "doc_type", length = 50)
     private String docType;
     private String docType;
@@ -33,14 +33,23 @@ public class Document extends BaseEntity{
     @Column(name = "file_name")
     @Column(name = "file_name")
     private String fileName;
     private String fileName;
 
 
+    @Column(name = "origin_name", length = 255)
+    private String originName;
+
+    @Column(name = "file_size")
+    private Long fileSize;
+
+    @Column(name = "thumbnails", length = 255)
+    private String thumbnails;
+
     @Column(name = "is_current")
     @Column(name = "is_current")
     private Boolean isCurrent;
     private Boolean isCurrent;
 
 
     @Column(name = "create_time")
     @Column(name = "create_time")
-    private Instant createTime;
+    private String createTime;
 
 
     @Column(name = "update_time")
     @Column(name = "update_time")
-    private Instant updateTime;
+    private String updateTime;
 
 
     @Column(name = "is_delete")
     @Column(name = "is_delete")
     private Boolean isDelete;
     private Boolean isDelete;

+ 11 - 8
src/main/java/com/loan/system/domain/entity/LoanCase.java

@@ -22,17 +22,17 @@ public class LoanCase extends BaseEntity{
     @Column(name = "customer_id")
     @Column(name = "customer_id")
     private Long customerId;
     private Long customerId;
 
 
-    @Column(name = "business_type_id")
-    private Long businessTypeId;
+    @Column(name = "business_type" , length = 20)
+    private String businessType;
 
 
     @Column(name = "business_attrs", length = 200)
     @Column(name = "business_attrs", length = 200)
     private String businessAttrs;
     private String businessAttrs;
 
 
-    @Column(name = "channel_id")
-    private Long channelId;
+    @Column(name = "channel_name" , length = 20)
+    private String channelName;
 
 
-    @Column(name = "remark_id")
-    private Long remarkId;
+    @Column(name = "recommender_id")
+    private Long recommenderId;
 
 
     @Column(name = "custom1_id")
     @Column(name = "custom1_id")
     private Long custom1Id;
     private Long custom1Id;
@@ -46,11 +46,14 @@ public class LoanCase extends BaseEntity{
     @Column(name = "total_loan_amount", precision = 18, scale = 2)
     @Column(name = "total_loan_amount", precision = 18, scale = 2)
     private BigDecimal totalLoanAmount;
     private BigDecimal totalLoanAmount;
 
 
+    @Column(name = "is_complete", length = 1)
+    private Boolean isComplete;
+
     @Column(name = "create_time")
     @Column(name = "create_time")
-    private Instant createTime;
+    private String createTime;
 
 
     @Column(name = "update_time")
     @Column(name = "update_time")
-    private Instant updateTime;
+    private String updateTime;
 
 
     @Column(name = "is_delete")
     @Column(name = "is_delete")
     private Boolean isDelete;
     private Boolean isDelete;

+ 2 - 2
src/main/java/com/loan/system/domain/entity/Repayment.java

@@ -61,10 +61,10 @@ public class Repayment extends BaseEntity{
     private Boolean isCleared;
     private Boolean isCleared;
 
 
     @Column(name = "create_time")
     @Column(name = "create_time")
-    private Instant createTime;
+    private String createTime;
 
 
     @Column(name = "update_time")
     @Column(name = "update_time")
-    private Instant updateTime;
+    private String updateTime;
 
 
     @Column(name = "is_delete")
     @Column(name = "is_delete")
     private Boolean isDelete;
     private Boolean isDelete;

+ 1 - 1
src/main/java/com/loan/system/domain/entity/RepaymentRecord.java

@@ -23,7 +23,7 @@ public class RepaymentRecord extends BaseEntity{
     private BigDecimal amount;
     private BigDecimal amount;
 
 
     @Column(name = "create_time")
     @Column(name = "create_time")
-    private Instant createTime;
+    private String createTime;
 
 
     @Column(name = "is_delete")
     @Column(name = "is_delete")
     private Boolean isDelete;
     private Boolean isDelete;

+ 9 - 0
src/main/java/com/loan/system/domain/entity/Role.java

@@ -4,6 +4,8 @@ import lombok.Getter;
 import lombok.Setter;
 import lombok.Setter;
 
 
 import javax.persistence.*;
 import javax.persistence.*;
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
 
 
 @Getter
 @Getter
 @Setter
 @Setter
@@ -25,4 +27,11 @@ public class Role {
     @Column(name = "is_delete")
     @Column(name = "is_delete")
     private Boolean isDelete;
     private Boolean isDelete;
 
 
+    @Column(name = "update_time")
+    private String updateTime;
+
+    @Column(name = "create_time")
+    private String createTime;
+
+
 }
 }

+ 1 - 1
src/main/java/com/loan/system/domain/entity/StatBusinessSnapshot.java

@@ -37,7 +37,7 @@ public class StatBusinessSnapshot extends BaseEntity{
     private Long userId;
     private Long userId;
 
 
     @Column(name = "create_time")
     @Column(name = "create_time")
-    private Instant createTime;
+    private String createTime;
 
 
     @Column(name = "is_delete")
     @Column(name = "is_delete")
     private Boolean isDelete;
     private Boolean isDelete;

+ 1 - 1
src/main/java/com/loan/system/domain/entity/StatFundEfficiency.java

@@ -30,7 +30,7 @@ public class StatFundEfficiency extends BaseEntity{
     private BigDecimal interestIncome;
     private BigDecimal interestIncome;
 
 
     @Column(name = "create_time")
     @Column(name = "create_time")
-    private Instant createTime;
+    private String createTime;
 
 
     @Column(name = "is_delete")
     @Column(name = "is_delete")
     private Boolean isDelete;
     private Boolean isDelete;

+ 4 - 7
src/main/java/com/loan/system/domain/entity/Step.java

@@ -32,7 +32,10 @@ public class Step extends BaseEntity{
     private Long userId2;
     private Long userId2;
 
 
     @Column(name = "begin_time")
     @Column(name = "begin_time")
-    private Instant beginTime;
+    private String beginTime;
+
+    @Column(name = "update_time")
+    private String updateTime;
 
 
     @Column(name = "parent_id")
     @Column(name = "parent_id")
     private Long parentId;
     private Long parentId;
@@ -43,12 +46,6 @@ public class Step extends BaseEntity{
     @Column(name = "next_id")
     @Column(name = "next_id")
     private Long nextId;
     private Long nextId;
 
 
-    @Column(name = "create_time")
-    private Instant createTime;
-
-    @Column(name = "update_time")
-    private Instant updateTime;
-
     @Column(name = "is_delete")
     @Column(name = "is_delete")
     private Boolean isDelete;
     private Boolean isDelete;
 
 

+ 16 - 0
src/main/java/com/loan/system/domain/entity/TemplateMessage.java

@@ -0,0 +1,16 @@
+package com.loan.system.domain.entity;
+
+import lombok.Data;
+
+import java.util.Map;
+
+@Data
+public class TemplateMessage {
+    private String touser;              // 接收者 openid
+    private String template_id;         // 模板 ID
+    private String page;                // 小程序内部页面路径(如 pages/review/detail?id=1)
+    private String url;                 // 可选,H5 外部链接
+    private Map<String, Object> miniprogram; // 可选,跳转其他小程序
+    private Map<String, Map<String, String>> data; // 模板数据
+    private String client_msg_id;
+}

+ 2 - 5
src/main/java/com/loan/system/domain/entity/User.java

@@ -38,9 +38,6 @@ public class User extends BaseEntity{
     @Column(name = "role")
     @Column(name = "role")
     private String role;
     private String role;
 
 
-    @Column(name = "ext_role_type", length = 50)
-    private String extRoleType;
-
     @Column(name = "dept", length = 100)
     @Column(name = "dept", length = 100)
     private String dept;
     private String dept;
 
 
@@ -48,10 +45,10 @@ public class User extends BaseEntity{
     private Byte status;
     private Byte status;
 
 
     @Column(name = "created_time")
     @Column(name = "created_time")
-    private Instant createdTime;
+    private String createTime;
 
 
     @Column(name = "updated_time")
     @Column(name = "updated_time")
-    private Instant updatedTime;
+    private String updateTime;
 
 
     @Column(name = "is_delete")
     @Column(name = "is_delete")
     private Boolean isDelete;
     private Boolean isDelete;

+ 26 - 0
src/main/java/com/loan/system/domain/enums/DecisionEnum.java

@@ -0,0 +1,26 @@
+package com.loan.system.domain.enums;
+
+/**
+ * 决定结果枚举类
+ */
+public enum DecisionEnum {
+    PASS("PASS", "通过"),
+    REJECT("REJECT", "驳回"),
+    TERMINATE("TERMINATE", "终结");
+
+    private final String status;
+    private final String msg;
+
+    public String getStatus() {
+        return status;
+    }
+
+    public String getMsg() {
+        return msg;
+    }
+
+    DecisionEnum(String status, String msg) {
+        this.status = status;
+        this.msg = msg;
+    }
+}

+ 3 - 0
src/main/java/com/loan/system/domain/enums/ExceptionEnum.java

@@ -55,6 +55,7 @@ public enum ExceptionEnum {
     TOKEN_EXPIRED(-101,"Token Expired"),
     TOKEN_EXPIRED(-101,"Token Expired"),
     WITHOUT_TOKEN(-102,"WITHOUT TOKEN"),
     WITHOUT_TOKEN(-102,"WITHOUT TOKEN"),
     LOGIN_EXPIRED(-103,"登录过期"),
     LOGIN_EXPIRED(-103,"登录过期"),
+    WECHAT_LOGIN_ERROR(-104, "微信登录错误"),
 
 
     USER_NOT_EXIST(-110, "账户不存在"),
     USER_NOT_EXIST(-110, "账户不存在"),
     USER_EXIST(-111, "账户已存在"),
     USER_EXIST(-111, "账户已存在"),
@@ -104,6 +105,8 @@ public enum ExceptionEnum {
     STEP_TEMPLATE_READ_ERROR(-355,"环节模板读取失败"),
     STEP_TEMPLATE_READ_ERROR(-355,"环节模板读取失败"),
     STEP_TEMPLATE_LIST_NOT_EXIST(-356,"环节模板边不存在"),
     STEP_TEMPLATE_LIST_NOT_EXIST(-356,"环节模板边不存在"),
     STEP_TEMPLATE_NODE_NOT_EXIST(-357,"环节模板节点读取失败"),
     STEP_TEMPLATE_NODE_NOT_EXIST(-357,"环节模板节点读取失败"),
+    STEP_USER_NOT_EXPECTED(-358,"环节处理人不是预期用户"),
+    STEP_HAS_COMPLETEED(-359,"环节已完成,不能重复操作"),
 
 
     FUND_EXIST(-400,"经费已存在"),
     FUND_EXIST(-400,"经费已存在"),
     FUND_NOT_EXIST(-401,"经费不存在"),
     FUND_NOT_EXIST(-401,"经费不存在"),

+ 1 - 1
src/main/java/com/loan/system/domain/enums/StepEnum.java

@@ -5,7 +5,7 @@ package com.loan.system.domain.enums;
  * @date 2020/9/30 - 19:40
  * @date 2020/9/30 - 19:40
  */
  */
 public enum StepEnum {
 public enum StepEnum {
-    UNSTART("UNSTART","未开始"),
+    UNSTART("UNSTART","未开始"),
     PROCESS("PROCESS","进行中"),
     PROCESS("PROCESS","进行中"),
     COMPLETED("COMPLETED","已完成");
     COMPLETED("COMPLETED","已完成");
 
 

+ 55 - 23
src/main/java/com/loan/system/domain/enums/StepPropertyEnum.java

@@ -1,36 +1,68 @@
 package com.loan.system.domain.enums;
 package com.loan.system.domain.enums;
 
 
+import java.util.Arrays;
+import java.util.List;
+
 /**
 /**
  * 针对特殊环节的标识设置
  * 针对特殊环节的标识设置
  * @author : EdwinXu
  * @author : EdwinXu
  * @date : Created in 2021/1/25 16:57
  * @date : Created in 2021/1/25 16:57
  */
  */
 public enum StepPropertyEnum {
 public enum StepPropertyEnum {
-    BLANK("BLANK","空白"),
-    UNIVERSAL("UNIVERSAL","通用"),
-    SKIP("SKIP","跳过"),
-    APPROVE("APPROVE","审批"),
-    PERMITION("PERMITION","许可"),
-    CONSTRUCTIONLOD("CONSTRUCTIONLOD","施工日志"),
-    PAYMENT("PAYMENT","支付"),
-
-    APPROVE_SUB("APPROVE_SUB","审批子环节"),
-    PERMITION_SUB("PERMITION_SUB","许可子环节"),
-    CONSTRUCTIONLOD_SUB("CONSTRUCTIONLOD_SUB","施工日志子环节"),
-    PAYMENT_SUB("PAYMENT_SUB","支付子环节");
-    private final String property;
-    private final String desc;
-
-    public String getProperty() {
-        return property;
-    }
+    /* ========== 环节定义 ========== */
+    BUSINESS_ACCEPT_PARENT(501, "业务受理环节", true),
+    BUSINESS_ACCEPT(502, "业务受理", false),
+
+    PRE_TRIAL_PARENT(503, "预审环节", true),
+    PRE_TRIAL(504, "预审", false),
+
+    APPROVAL_PARENT(505, "审批环节", true),
+    APPROVAL(506, "审批", false),
+
+    CONTRACT_SIGN_PARENT(507, "合同签约环节", true),
+    CONTRACT_SIGN(508, "合同签约", false),
+
+    DISBURSE_PARENT(509, "出款环节", true),
+    PLAN_REPORT(510, "计划上报", false),
+    PLAN_AUDIT(511, "计划审核", false),
+    DISBURSE_START(512, "出账启动", false),
+    DISBURSE_AUDIT(513, "出账审核", false),
+    FINANCE_DISBURSE(514, "财务出账", false),
+    DISBURSE_CONFIRM(515, "出账确认", false),
 
 
-    public String getDesc() {
-        return desc;
+    REPAY_PARENT(516, "回款环节", true),
+    REPAY_START(517, "回款启动", false),
+    REPAY_APPROVAL(518, "回款审批", false),
+    FINANCE_CHECK(519, "财务核算", false),
+
+    COLLATERAL_RECEIVE(520, "押品取证环节", true),
+    PLAN_SUBMISSION(521, "计划上报", false),
+    APPROVAL_ASSIGNMENT(522, "审批分派", false),
+    EVIDENCE_CONFIRMATION(523, "确认取证", false),
+
+    COLLATERAL_DELIVERY(524, "押品送证环节", false),
+    PLAN_SUBMISSION_2(525, "计划上报", false),
+    APPROVAL_ASSIGNMENT_2(526, "审批分派", false),
+    DELIVERY_CONFIRMATION(527, "送证确认", false);
+
+    /* ========== 字段 & 构造 ========== */
+    private final int code;
+    private final String label;
+    private final boolean parent;
+
+    StepPropertyEnum(int code, String label, boolean parent) {
+        this.code = code;
+        this.label = label;
+        this.parent = parent;
     }
     }
 
 
-    StepPropertyEnum(String property, String desc) {
-        this.property = property;
-        this.desc = desc;
+    /* ========== getter ========== */
+    public int getCode() { return code; }
+    public String getLabel() { return label; }
+    public boolean isParent() { return parent; }
+
+    public static List<StepPropertyEnum> listAll() {
+        return Arrays.asList(values()); // 顺序与源码声明一致
     }
     }
+
 }
 }

+ 20 - 0
src/main/java/com/loan/system/domain/vo/CustomerLoginVO.java

@@ -0,0 +1,20 @@
+package com.loan.system.domain.vo;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class CustomerLoginVO implements Serializable {
+    private Long id;
+    private String openid;
+    private String token;
+    private String name;
+    private int is_customer;
+}

+ 23 - 0
src/main/java/com/loan/system/domain/vo/DocumentVO.java

@@ -0,0 +1,23 @@
+package com.loan.system.domain.vo;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class DocumentVO implements Serializable {
+    private Long id;//文档ID
+    private Long caseId;//业务ID
+    private Long ownerId;//客户id
+    private String dictType;//资料类型
+    private String docType;//文档类型
+    private String filePath;//文件路径
+    private String fileName;//文件名
+    private Long fileSize;//文件大小
+}

+ 18 - 0
src/main/java/com/loan/system/domain/vo/LoanCasePreApprovalVo.java

@@ -0,0 +1,18 @@
+package com.loan.system.domain.vo;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class LoanCasePreApprovalVo implements Serializable
+{
+    private String Lead_Sales;
+    private String Assist_Sales;
+}

+ 25 - 0
src/main/java/com/loan/system/domain/vo/StepVO.java

@@ -0,0 +1,25 @@
+package com.loan.system.domain.vo;
+
+import com.loan.system.domain.entity.BaseEntity;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import javax.persistence.Entity;
+import java.io.Serializable;
+
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+public class StepVO implements Serializable {
+
+    private Long id;
+    private String stepName;
+    private Long caseId;
+    private String status;
+    private Long userId1;
+    private Long userId2;
+    private String beginTime;
+    private Long parentId;
+
+}

+ 3 - 0
src/main/java/com/loan/system/domain/vo/UserLoginVO.java

@@ -15,6 +15,9 @@ public class UserLoginVO implements Serializable {
 
 
     private Long id;
     private Long id;
     private String openid;
     private String openid;
+    private String username;
     private String token;
     private String token;
+    private int is_customer;
+
 
 
 }
 }

+ 72 - 1
src/main/java/com/loan/system/interceptor/JwtTokenUserInterceptor.java

@@ -2,17 +2,26 @@ package com.loan.system.interceptor;
 
 
 import com.loan.system.constant.JwtClaimsConstant;
 import com.loan.system.constant.JwtClaimsConstant;
 import com.loan.system.context.BaseContext;
 import com.loan.system.context.BaseContext;
+import com.loan.system.domain.entity.User;
 import com.loan.system.properties.JwtProperties;
 import com.loan.system.properties.JwtProperties;
+import com.loan.system.service.UserService;
 import com.loan.system.utils.JwtUtil;
 import com.loan.system.utils.JwtUtil;
 import io.jsonwebtoken.Claims;
 import io.jsonwebtoken.Claims;
 import lombok.extern.slf4j.Slf4j;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
+import org.springframework.security.core.GrantedAuthority;
+import org.springframework.security.core.authority.SimpleGrantedAuthority;
+import org.springframework.security.core.context.SecurityContextHolder;
 import org.springframework.stereotype.Component;
 import org.springframework.stereotype.Component;
 import org.springframework.web.method.HandlerMethod;
 import org.springframework.web.method.HandlerMethod;
 import org.springframework.web.servlet.HandlerInterceptor;
 import org.springframework.web.servlet.HandlerInterceptor;
 
 
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 import javax.servlet.http.HttpServletResponse;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Collectors;
 
 
 /**
 /**
  * jwt令牌校验的拦截器
  * jwt令牌校验的拦截器
@@ -23,7 +32,8 @@ public class JwtTokenUserInterceptor implements HandlerInterceptor {
 
 
     @Autowired
     @Autowired
     private JwtProperties jwtProperties;
     private JwtProperties jwtProperties;
-
+    @Autowired
+    private UserService userService;
     /**
     /**
      * 在拦截的请求前校验jwt
      * 在拦截的请求前校验jwt
      */
      */
@@ -33,6 +43,9 @@ public class JwtTokenUserInterceptor implements HandlerInterceptor {
             //当前拦截到的不是动态方法,直接放行
             //当前拦截到的不是动态方法,直接放行
             return true;
             return true;
         }
         }
+        log.info("请求头中所有字段: {}", request.getHeaderNames());
+        log.info("Authorization 头: {}", request.getHeader("Authorization"));
+        log.info("用户自定义 token 头: {}", request.getHeader(jwtProperties.getUserTokenName()));
 
 
         //1、从请求头中获取令牌
         //1、从请求头中获取令牌
         String token = request.getHeader(jwtProperties.getUserTokenName());
         String token = request.getHeader(jwtProperties.getUserTokenName());
@@ -43,6 +56,8 @@ public class JwtTokenUserInterceptor implements HandlerInterceptor {
             Claims claims = JwtUtil.parseJWT(jwtProperties.getUserSecretKey(), token);
             Claims claims = JwtUtil.parseJWT(jwtProperties.getUserSecretKey(), token);
             Long userId = Long.valueOf(claims.get(JwtClaimsConstant.USER_ID).toString());
             Long userId = Long.valueOf(claims.get(JwtClaimsConstant.USER_ID).toString());
             BaseContext.setCurrentId(userId);
             BaseContext.setCurrentId(userId);
+            // 设置Spring Security认证信息
+            setSpringSecurityAuthentication(userId);
             //3、通过,放行
             //3、通过,放行
             return true;
             return true;
         } catch (Exception ex) {
         } catch (Exception ex) {
@@ -51,4 +66,60 @@ public class JwtTokenUserInterceptor implements HandlerInterceptor {
             return false;
             return false;
         }
         }
     }
     }
+    /**
+     * 设置Spring Security认证信息
+     */
+    private void setSpringSecurityAuthentication(Long userId) {
+        try {
+            // 查询用户信息和权限
+            User user = userService.findByIdAndIsDelete(userId);
+            if (user == null) {
+                log.info("用户不存在: {}", userId);
+                return;
+            }else{
+                log.info("用户信息: {}", user.getId());
+            }
+
+            // 获取用户角色并转换为Spring Security权限
+            List<GrantedAuthority> authorities = getUserAuthorities(user);
+
+            // 创建认证信息
+            UsernamePasswordAuthenticationToken authentication =
+                    new UsernamePasswordAuthenticationToken(user, null, authorities);
+            SecurityContextHolder.getContext().setAuthentication(authentication);
+
+            log.info("Spring Security认证设置完成 - 用户: {}, 角色: {}",
+                    user.getUsername(), authorities);
+        } catch (Exception e) {
+            log.info("设置Spring Security认证信息失败: {}", e.getMessage());
+        }
+    }
+
+    /**
+     * 根据用户信息获取权限列表
+     * role字段是逗号分隔的字符串,如 "ADMIN,USER,MANAGER"
+     */
+    private List<GrantedAuthority> getUserAuthorities(User user) {
+        List<GrantedAuthority> authorities = new ArrayList<>();
+        log.info("用户角色字符串: {}", user.getRole());
+        if (user.getRole() != null && !user.getRole().trim().isEmpty()) {
+            // 分割逗号分隔的角色字符串
+            String[] roleArray = user.getRole().split(",");
+            // 为每个角色添加ROLE_前缀并创建权限对象
+            for (String role : roleArray) {
+                log.info("角色: {}", role);
+                String trimmedRole = role.trim();
+                if (!trimmedRole.isEmpty()) {
+                    authorities.add(new SimpleGrantedAuthority(trimmedRole));
+                }
+            }
+        }
+        log.info("用户角色解析: {} -> {}", user.getRole(),
+                authorities.stream()
+                        .map(GrantedAuthority::getAuthority)
+                        .collect(Collectors.toList()));
+
+        return authorities;
+    }
+
 }
 }

+ 22 - 0
src/main/java/com/loan/system/repository/ApprovalRepository.java

@@ -0,0 +1,22 @@
+package com.loan.system.repository;
+
+import com.loan.system.domain.entity.ApprovalRecord;
+import org.springframework.data.domain.Sort;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.Modifying;
+import org.springframework.data.jpa.repository.Query;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.List;
+
+public interface ApprovalRepository extends JpaRepository<ApprovalRecord,Long> {
+    List<ApprovalRecord> findByCaseIdAndIsDelete(Long id, Boolean isDelete);
+
+    ApprovalRecord findByCaseIdAndIsDeleteAndStepNameAndApproverId(Long caseId, Boolean isDelete, String stepName,Long approverId);
+
+    @Modifying
+    @Transactional
+    @Query(value = "UPDATE approval_record SET decision = ?1, update_time = ?5, comments = ?6 WHERE case_id = ?2 AND step_name = ?3 AND is_delete = ?4 AND approver_id = ?7", nativeQuery = true)
+    void updateDecisionByCaseIdAndStepNameAndIsDeleteAndApproverId(String decision, Long caseId, String stepName, Boolean isDelete,String updateTime,String  comments, Long approverId);
+
+}

+ 25 - 0
src/main/java/com/loan/system/repository/CustomerRepository.java

@@ -0,0 +1,25 @@
+package com.loan.system.repository;
+
+import com.loan.system.domain.entity.Customer;
+import com.loan.system.domain.entity.User;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.Modifying;
+import org.springframework.data.jpa.repository.Query;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.time.Instant;
+import java.util.Date;
+
+public interface CustomerRepository extends JpaRepository<Customer,Long> {
+    boolean existsBymobileAndIsDelete(String mobile,Boolean isDelete);
+    @Transactional
+    @Modifying
+    @Query(value = "INSERT INTO customers (openid, name, sex, id_number, mobile, register_source, bank_account, face_auth, create_time, update_time, is_delete) " +
+            "VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?9, 0)", nativeQuery = true)
+    void createCustomer(String openid, String name, String sex, String idNumber, String mobile,
+                        String registerSource, String bankAccount, Boolean faceAuth, String createTime,String updateTime);
+
+    Customer findByMobileAndIsDelete(String phoneNumber,Boolean isDelete);
+
+    Customer findByIdAndIsDelete(Long id,Boolean isDelete);
+}

+ 14 - 0
src/main/java/com/loan/system/repository/DocumentRepository.java

@@ -0,0 +1,14 @@
+package com.loan.system.repository;
+
+import com.loan.system.domain.entity.Document;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.Query;
+
+import java.util.List;
+
+public interface DocumentRepository extends JpaRepository<Document,Long> {
+    List<Document> findDocumentByCaseIdAndIsDelete(Long CaseId, Boolean IsDelete);
+
+    @Query("select d from Document d where d.id = ?1")
+    Document findByDocumentIdAndIsDelete(Long signId);
+}

+ 24 - 0
src/main/java/com/loan/system/repository/LoanCaseRepository.java

@@ -0,0 +1,24 @@
+package com.loan.system.repository;
+
+
+import com.loan.system.domain.entity.LoanCase;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.Modifying;
+import org.springframework.data.jpa.repository.Query;
+import org.springframework.transaction.annotation.Transactional;
+
+public interface LoanCaseRepository extends JpaRepository<LoanCase,Long> {
+    LoanCase findByIdAndIsDelete(Long customerId,boolean isDelete);
+
+    @Modifying
+    @Transactional
+    @Query("update LoanCase set updateTime = ?3 where id = ?1 and isDelete = ?2")
+    void updateUpdatetimeByIdAndIsDeleted(Long id,boolean isDelete,String updateTime);
+
+    @Modifying
+    @Transactional
+    @Query("UPDATE LoanCase SET updateTime = ?3, isDelete = ?2 WHERE id = ?1 AND isDelete = ?2")
+    void logic_delete(Long id, boolean isDelete, String updateTime);
+
+
+}

+ 52 - 0
src/main/java/com/loan/system/repository/StepRepository.java

@@ -0,0 +1,52 @@
+package com.loan.system.repository;
+
+import com.loan.system.domain.entity.Customer;
+import com.loan.system.domain.entity.Step;
+import com.loan.system.domain.vo.StepVO;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.Modifying;
+import org.springframework.data.jpa.repository.Query;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.List;
+
+/**
+ * @author EdwinXu
+ * @date 2020/9/2 - 15:35
+ * @Description
+ */
+public interface StepRepository extends JpaRepository<Step,Long> {
+
+    @Modifying
+    @Transactional
+    @Query("update Step set status = ?1, " +
+            "beginTime = CASE WHEN ?1 = '进行中' THEN ?4 ELSE beginTime END ," +
+            "updateTime = CASE WHEN ?1 = '已完成' THEN ?4 ELSE updateTime END " +
+            "where caseId = ?3 and stepName = ?2")
+
+    void updateStatusByCaseIdAndStepName(String msg, String stepName, Long caseId,String currentTime);
+
+    Step findByStepNameAndCaseId(String stepName, Long caseId);
+
+    @Modifying
+    @Transactional
+    @Query("update Step set userId1 = ?2 where caseId = ?3 and  stepName = ?1")
+    void updateUser1ByCaseIdAndStepName(String stepName, Long approverId, Long caseId,String currentTime);
+
+    @Modifying
+    @Transactional
+    @Query("update Step set userId2 = ?2 where caseId = ?3 and  stepName = ?1")
+    void updateUser2ByCaseIdAndStepName(String stepName, Long approverId, Long caseId,String currentTime);
+
+    List<StepVO> findByCaseId(Long caseId);
+
+    @Query("select userId1 from Step where caseId = ?1 and stepName = ?2 and isDelete = ?3")
+    Long getLeadSalesIdAndIsDelete(Long caseId, String stepName,boolean isDelete);
+
+    List<Step> findAllByCaseId(Long caseId);
+
+    @Modifying
+    @Transactional
+    @Query("UPDATE Step SET updateTime = ?3, isDelete = ?2 WHERE id = ?1 AND isDelete = ?2")
+    void logic_delete(Long id, boolean isDelete, String updateTime);
+}

+ 7 - 6
src/main/java/com/loan/system/repository/UserRepository.java

@@ -9,11 +9,12 @@ import org.springframework.data.jpa.repository.Query;
 
 
 import java.util.Set;
 import java.util.Set;
 
 
-/**
- * @author EdwinXu
- * @date 2020/9/2 - 15:35
- * @Description
- */
+
 public interface UserRepository extends JpaRepository<User,Long> {
 public interface UserRepository extends JpaRepository<User,Long> {
-    User findByMobile(String mobile);
+
+    boolean existsByMobileAndIsDelete(String mobile,Boolean isDelete);
+
+    User findByMobileAndIsDelete(String phoneNumber,Boolean isDelete);
+
+    User findByIdAndIsDelete(Long mobile, Boolean isDelete);
 }
 }

+ 16 - 0
src/main/java/com/loan/system/service/ApprovalService.java

@@ -0,0 +1,16 @@
+package com.loan.system.service;
+
+import com.loan.system.domain.entity.ApprovalRecord;
+
+import java.util.List;
+
+public interface ApprovalService {
+
+    List<ApprovalRecord> findByCaseIdAndIsDelete(Long caseId);
+
+    void save(ApprovalRecord approvalRecord);
+
+    void updateDecisionByCaseIdAndStepNameAndIsDelete(String decision, Long caseId, String stepName,String  comments,Long approverId);
+
+    ApprovalRecord findByCaseIdAndIsDeleteAndStepName(Long caseId, String stepName,Long approverId);
+}

+ 10 - 0
src/main/java/com/loan/system/service/CustomerService.java

@@ -0,0 +1,10 @@
+package com.loan.system.service;
+
+import com.loan.system.domain.entity.Customer;
+
+public interface CustomerService {
+    Customer findBymobileAndIsDelete(String phoneNumber);
+    boolean existsBymobileAndIsDelete(String phoneNumber);
+    void createCustomer(Customer customer);
+    Customer findByIdAndIsDelete(Long id);
+}

+ 13 - 0
src/main/java/com/loan/system/service/DocumentService.java

@@ -0,0 +1,13 @@
+package com.loan.system.service;
+
+import com.loan.system.domain.entity.Document;
+import com.loan.system.domain.vo.DocumentVO;
+
+import java.util.List;
+
+public interface DocumentService {
+    List<Document> findDocumentByCaseIdAndIsDelete(Long caseId);
+    DocumentVO uploadFile(Document document);
+
+    Document findById(Long signId);
+}

+ 34 - 0
src/main/java/com/loan/system/service/Impl/ApprovalServiceImpl.java

@@ -0,0 +1,34 @@
+package com.loan.system.service.Impl;
+
+import com.loan.system.domain.entity.ApprovalRecord;
+import com.loan.system.repository.ApprovalRepository;
+import com.loan.system.service.ApprovalService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+@Service
+public class ApprovalServiceImpl implements ApprovalService {
+    @Autowired
+    ApprovalRepository approvalRepository;
+
+    @Override
+
+    public List<ApprovalRecord> findByCaseIdAndIsDelete(Long id){
+        return approvalRepository.findByCaseIdAndIsDelete(id, false);
+    }
+
+    public void save(ApprovalRecord approvalRecord){
+        approvalRepository.save(approvalRecord);
+    }
+
+    public void updateDecisionByCaseIdAndStepNameAndIsDelete(String decision, Long caseId, String stepName,String  comments,Long approverId){
+        approvalRepository.updateDecisionByCaseIdAndStepNameAndIsDeleteAndApproverId(decision, caseId, stepName, false, java.time.LocalDateTime.now().format(java.time.format.DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")),comments,approverId);
+    }
+
+    public ApprovalRecord findByCaseIdAndIsDeleteAndStepName(Long caseId,  String stepName,Long approverId){
+        return approvalRepository.findByCaseIdAndIsDeleteAndStepNameAndApproverId(caseId, false, stepName, approverId);
+    }
+
+}

+ 30 - 0
src/main/java/com/loan/system/service/Impl/CustomerServiceImpl.java

@@ -0,0 +1,30 @@
+package com.loan.system.service.Impl;
+
+import com.loan.system.domain.entity.Customer;
+import com.loan.system.repository.CustomerRepository;
+import com.loan.system.service.CustomerService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+@Service
+public class CustomerServiceImpl implements CustomerService {
+    @Autowired
+    private CustomerRepository customerRepository;
+    @Override
+
+    public boolean existsBymobileAndIsDelete(String phoneNumber){
+        return customerRepository.existsBymobileAndIsDelete(phoneNumber,false);
+    }
+    @Override
+    public Customer findBymobileAndIsDelete(String phoneNumber){
+        return customerRepository.findByMobileAndIsDelete(phoneNumber,false);
+    }
+    @Override
+    public void createCustomer(Customer customer){
+        customerRepository.createCustomer(customer.getOpenid(),customer.getName(),customer.getSex(),customer.getIdNumber(),customer.getMobile(),customer.getRegisterSource(),customer.getBankAccount(),customer.getFaceAuth(),customer.getCreateTime(),customer.getUpdateTime());
+    }
+    @Override
+    public Customer findByIdAndIsDelete(Long id){
+        return customerRepository.findByIdAndIsDelete(id,false);
+    }
+}

+ 31 - 0
src/main/java/com/loan/system/service/Impl/DocumentServiceImpl.java

@@ -0,0 +1,31 @@
+package com.loan.system.service.Impl;
+
+import cn.hutool.core.bean.BeanUtil;
+import com.loan.system.domain.entity.Document;
+import com.loan.system.domain.vo.DocumentVO;
+import com.loan.system.repository.DocumentRepository;
+import com.loan.system.service.DocumentService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+@Service
+public class DocumentServiceImpl implements DocumentService {
+
+    @Autowired
+    DocumentRepository documentRepository;
+    @Override
+    public List<Document> findDocumentByCaseIdAndIsDelete(Long caseId){
+        return documentRepository.findDocumentByCaseIdAndIsDelete(caseId,false);
+    }
+    @Override
+    public DocumentVO uploadFile(Document document) {
+        return BeanUtil.copyProperties(documentRepository.save(document), DocumentVO.class);
+    }
+
+    @Override
+    public Document findById(Long signId) {
+        return documentRepository.findByDocumentIdAndIsDelete(signId);
+    }
+}

+ 30 - 0
src/main/java/com/loan/system/service/Impl/LoanCaseServiceImpl.java

@@ -0,0 +1,30 @@
+package com.loan.system.service.Impl;
+
+import com.loan.system.domain.entity.LoanCase;
+import com.loan.system.repository.LoanCaseRepository;
+import com.loan.system.service.LoanCaseService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+
+@Service
+public class LoanCaseServiceImpl implements LoanCaseService {
+    @Autowired
+    private LoanCaseRepository LoanCaseRepository;
+
+    @Override
+
+    public LoanCase findByIdAndIsDelete(Long id){
+        return LoanCaseRepository.findByIdAndIsDelete(id,false);
+    };
+    @Override
+    public void updateUpdatetimeByIdAndIsDeleted(Long id,boolean isDelete){
+        LoanCaseRepository.updateUpdatetimeByIdAndIsDeleted(id,false, LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
+    }
+    @Override
+    public void logic_delete(Long id){
+           LoanCaseRepository.logic_delete(id, true, LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
+    }
+}

+ 52 - 17
src/main/java/com/loan/system/service/Impl/PermissionService.java

@@ -9,26 +9,41 @@ import org.springframework.security.core.GrantedAuthority;
 import org.springframework.security.core.context.SecurityContextHolder;
 import org.springframework.security.core.context.SecurityContextHolder;
 import org.springframework.stereotype.Component;
 import org.springframework.stereotype.Component;
 
 
+import java.util.Arrays;
+import java.util.HashSet;
 import java.util.List;
 import java.util.List;
+import java.util.Set;
 import java.util.stream.Collectors;
 import java.util.stream.Collectors;
 
 
 @Component("pms")
 @Component("pms")
 public class PermissionService {
 public class PermissionService {
     private static final Logger logger = LoggerFactory.getLogger(PermissionService.class);
     private static final Logger logger = LoggerFactory.getLogger(PermissionService.class);
 
 
-    public boolean hasRole(String role, String auth){
+
+
+    public boolean hasRole(String role){
         Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
         Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
         if (authentication == null) {
         if (authentication == null) {
             logger.error("PermissionService | method = hasRole() | 登录过期");
             logger.error("PermissionService | method = hasRole() | 登录过期");
             throw new DescribeException(ExceptionEnum.LOGIN_EXPIRED);
             throw new DescribeException(ExceptionEnum.LOGIN_EXPIRED);
         }
         }
-        List<String> authorities = authentication.getAuthorities().stream().map(GrantedAuthority::getAuthority).collect(Collectors.toList());
-        String roles = authorities.get(0);
-        boolean contains = roles.contains(role) || roles.contains(auth);
-        if (contains){
+//        List<String> authorities = authentication.getAuthorities().stream().map(GrantedAuthority::getAuthority).collect(Collectors.toList());
+//        String roles = authorities.get(0);
+//        boolean contains = roles.contains(role) || roles.contains(auth);
+//        if (contains){
+//            return true;
+//        } else {
+//            logger.error("PermissionService | method = hasRole() | 没有操作权限");
+//            throw new DescribeException(ExceptionEnum.PERMISSION_DENIED);
+//        }
+        Set<String> userRoles = getUserRoles(authentication);
+        // 检查角色
+        boolean hasRole = userRoles.contains(role);
+        if (hasRole){
             return true;
             return true;
         } else {
         } else {
-            logger.error("PermissionService | method = hasRole() | 没有操作权限");
+            logger.error("PermissionService | method = hasRole() | 没有操作权限,所需角色: {}, 用户角色: {}",
+                    role, userRoles);
             throw new DescribeException(ExceptionEnum.PERMISSION_DENIED);
             throw new DescribeException(ExceptionEnum.PERMISSION_DENIED);
         }
         }
     }
     }
@@ -39,19 +54,39 @@ public class PermissionService {
             logger.error("PermissionService | method = hasRole() | 登录过期");
             logger.error("PermissionService | method = hasRole() | 登录过期");
             throw new DescribeException(ExceptionEnum.LOGIN_EXPIRED);
             throw new DescribeException(ExceptionEnum.LOGIN_EXPIRED);
         }
         }
-        boolean contains = false;
-        List<String> strings = authentication.getAuthorities().stream().map(GrantedAuthority::getAuthority).collect(Collectors.toList());
-        for(String role:roles){
-            if(strings.contains(role)){
-                contains = true;
-                break;
+//        boolean contains = false;
+//        List<String> strings = authentication.getAuthorities().stream().map(GrantedAuthority::getAuthority).collect(Collectors.toList());
+//        for(String role:roles){
+//            if(strings.contains(role)){
+//                contains = true;
+//                break;
+//            }
+//        }
+//        if (contains){
+//            return true;
+//        } else {
+//            logger.error("PermissionService | method = hasRole() | 没有操作权限");
+//            throw new DescribeException(ExceptionEnum.PERMISSION_DENIED);
+//        }
+        // 获取用户所有角色
+        Set<String> userRoles = getUserRoles(authentication);
+
+        // 检查是否有任意一个角色
+        for(String role : roles){
+            if(userRoles.contains(role)){
+                return true;
             }
             }
         }
         }
-        if (contains){
-            return true;
-        } else {
-            logger.error("PermissionService | method = hasRole() | 没有操作权限");
-            throw new DescribeException(ExceptionEnum.PERMISSION_DENIED);
+
+        logger.error("PermissionService | method = hasAnyRoles() | 没有操作权限,所需角色: {}, 用户角色: {}",
+                Arrays.toString(roles), userRoles);
+        throw new DescribeException(ExceptionEnum.PERMISSION_DENIED);
+    }
+    private Set<String> getUserRoles(Authentication authentication) {
+        Set<String> roles = new HashSet<>();
+        for (GrantedAuthority authority : authentication.getAuthorities()) {
+            roles.add(authority.getAuthority());
         }
         }
+        return roles;
     }
     }
 }
 }

+ 139 - 0
src/main/java/com/loan/system/service/Impl/StepServiceImpl.java

@@ -0,0 +1,139 @@
+package com.loan.system.service.Impl;
+
+import cn.hutool.core.bean.BeanUtil;
+import com.loan.system.domain.entity.Step;
+import com.loan.system.domain.enums.StepEnum;
+import com.loan.system.domain.enums.StepPropertyEnum;
+import com.loan.system.domain.vo.StepVO;
+import com.loan.system.repository.StepRepository;
+import com.loan.system.service.StepService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+import java.util.ArrayList;
+import java.util.List;
+
+@Service
+public class StepServiceImpl implements StepService {
+    private final StepRepository stepRepository;
+
+    @Autowired
+    public StepServiceImpl(StepRepository stepRepository) {
+        this.stepRepository = stepRepository;
+    }
+
+    @Override
+    public List<StepVO> addStepByCaseId(Long caseId) {
+        List<StepVO> list = new  ArrayList<>();//存放当前业务的流程
+        List<StepPropertyEnum> stepPropertyEnums = StepPropertyEnum.listAll();//获取所有环节
+
+        //创建初始环节
+        Step step = new Step();
+        step.setCaseId(caseId);
+        step.setStepName(stepPropertyEnums.get(0).getLabel());
+        step.setStatus(StepEnum.PROCESS.getMsg());
+        step.setBeginTime(LocalDateTime.now()
+                .format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
+        step.setParentId(0L);
+        step.setIsDelete( false);
+
+        Step step1=stepRepository.save(step);
+
+        StepVO stepVO = BeanUtil.copyProperties(step1, StepVO.class);
+        list.add(stepVO);
+
+        Long currentParentId = step1.getId();
+        for(int i = 1; i < stepPropertyEnums.size(); i++){
+            StepPropertyEnum stepPropertyEnum = stepPropertyEnums.get(i);//获取当前环节
+
+            Step s = new Step();
+            s.setCaseId(caseId);
+            s.setStepName(stepPropertyEnum.getLabel());
+            if(i == 1){
+                s.setStatus(StepEnum.PROCESS.getMsg());
+                s.setBeginTime(LocalDateTime.now()
+                        .format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
+            }
+            else
+                s.setStatus(StepEnum.UNSTART.getMsg());
+
+            if(stepPropertyEnum.isParent())
+                s.setParentId(0L);
+            else
+                s.setParentId(currentParentId);
+            s.setIsDelete( false);
+
+            Step step2 = stepRepository.save(s);
+            if (stepPropertyEnum.isParent())
+                currentParentId = step2.getId();
+
+            stepVO = BeanUtil.copyProperties(step2, StepVO.class);
+
+            list.add(stepVO);
+        }
+
+        return list;
+    }
+
+    @Override
+    public void updateStatusByCaseId(String msg, String stepName, Long caseId) {
+        stepRepository.updateStatusByCaseIdAndStepName(msg,stepName,caseId,LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
+    }
+    
+    @Override
+    public void cancelPreApprove(Long caseId) {
+        //设置预审核阶段已完成,审批阶段开始
+        updateStatusByCaseId(StepEnum.COMPLETED.getMsg(),StepPropertyEnum.PRE_TRIAL_PARENT.getLabel(),caseId);
+        updateStatusByCaseId(StepEnum.COMPLETED.getMsg(),StepPropertyEnum.PRE_TRIAL.getLabel(),caseId);
+
+        updateStatusByCaseId(StepEnum.PROCESS.getMsg(),StepPropertyEnum.APPROVAL_PARENT.getLabel(),caseId);
+        updateStatusByCaseId(StepEnum.PROCESS.getMsg(),StepPropertyEnum.APPROVAL.getLabel(),caseId);
+    }
+
+    @Override
+    public StepVO updateUserByCaseId(String stepName, Long approverId, Long caseId) {
+        Step step = stepRepository.findByStepNameAndCaseId(stepName, caseId);
+        if(step.getUserId1() == null)
+            stepRepository.updateUser1ByCaseIdAndStepName(stepName,approverId,caseId,LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
+        else
+            stepRepository.updateUser2ByCaseIdAndStepName(stepName,approverId,caseId,LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
+
+        step = stepRepository.findByStepNameAndCaseId(stepName, caseId);
+
+        return BeanUtil.copyProperties(step, StepVO.class);
+
+    }
+
+    @Override
+    public List<StepVO> getStepByCaseId(Long caseId) {
+        return stepRepository.findByCaseId(caseId);
+    }
+    @Override
+    public List<Step> getAllStepByCaseId(Long caseId){
+        return stepRepository.findAllByCaseId(caseId);
+    }
+    @Override
+    public Long getLeadSalesIdAndIsDelete(Long caseId, String stepName) {
+        return stepRepository.getLeadSalesIdAndIsDelete(caseId,stepName,false);
+    }
+    @Override
+    public Step findByStepNameAndCaseId(String stepName, Long caseId){
+        return stepRepository.findByStepNameAndCaseId(stepName,caseId);
+    }
+    @Override
+    public void updateUserId1ByCaseIdAndStepName(String stepName, Long approverId, Long caseId){
+
+        stepRepository.updateUser1ByCaseIdAndStepName(stepName,approverId,caseId,LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
+    };
+
+    @Override
+    public void updateUserId2ByCaseIdAndStepName(String stepName, Long approverId, Long caseId){
+        stepRepository.updateUser2ByCaseIdAndStepName(stepName,approverId,caseId,LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
+    };
+
+    public void logic_delete(Long id){
+        stepRepository.logic_delete(id,true,LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
+    }
+}

+ 106 - 3
src/main/java/com/loan/system/service/Impl/UserServiceImpl.java

@@ -1,23 +1,126 @@
 package com.loan.system.service.Impl;
 package com.loan.system.service.Impl;
 
 
+import com.alibaba.fastjson.JSON;
 import com.loan.system.domain.dto.UserLoginDTO;
 import com.loan.system.domain.dto.UserLoginDTO;
+import com.loan.system.domain.pojo.Result;
 import com.loan.system.domain.entity.User;
 import com.loan.system.domain.entity.User;
 import com.loan.system.repository.UserRepository;
 import com.loan.system.repository.UserRepository;
 import com.loan.system.service.UserService;
 import com.loan.system.service.UserService;
+import com.loan.system.utils.RedisUtil;
+import com.loan.system.utils.ResultUtil;
+import org.json.JSONObject;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.security.authentication.AuthenticationManager;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.data.redis.core.StringRedisTemplate;
 import org.springframework.stereotype.Service;
 import org.springframework.stereotype.Service;
+import okhttp3.OkHttpClient;
+import okhttp3.Request;
+import okhttp3.Response;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+import java.io.IOException;
+import java.net.URI;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.UUID;
+import java.util.concurrent.TimeUnit;
 
 
 @Service
 @Service
 public class UserServiceImpl implements UserService {
 public class UserServiceImpl implements UserService {
     UserRepository userRepository;
     UserRepository userRepository;
+    /**
+     * 微信公众号appid
+     */
+    @Value("${wechat.appid}")
+    private String appId;
+    /**
+     * 微信公众号secret
+     */
+    @Value("${wechat.secret}")
+    private String appSecret;
+
+    private static final Logger log = LoggerFactory.getLogger(UserServiceImpl.class);
 
 
     @Autowired
     @Autowired
     public UserServiceImpl(UserRepository userRepository) {
     public UserServiceImpl(UserRepository userRepository) {
         this.userRepository = userRepository;
         this.userRepository = userRepository;
     }
     }
+    @Autowired
+    private StringRedisTemplate redisTemplate;
+
+    /**
+     * 获取微信openid
+     * @param code
+     * @return
+     */
+    @Override
+    public Result get_sessionId(String code) {
+        String url = "https://api.weixin.qq.com/sns/jscode2session"
+                + "?appid=" + appId
+                + "&secret=" + appSecret
+                + "&js_code=" + code
+                + "&grant_type=authorization_code";
+
+        OkHttpClient client = new OkHttpClient();
+        Request request = new Request.Builder().url(url).build();
+        String res = "";
+        try (Response response = client.newCall(request).execute()) {
+            if (response.isSuccessful()) {
+                res = response.body().string();
+                log.info("成功获取数据: {}", res);
+
+                // 解析返回的JSON数据
+                JSONObject obj = new JSONObject(res);
+                String openid = obj.getString("openid");
+                String sessionKey = obj.getString("session_key");
+
+                // 存储到Redis
+                String uuid = UUID.randomUUID().toString();
+                Map<String, String> sessionData = new HashMap<>();
+                sessionData.put("openid", openid);
+                sessionData.put("session_key", sessionKey);
+                redisTemplate.opsForValue().set("wx_session_id_" + uuid,
+                        JSON.toJSONString(sessionData), 30, TimeUnit.MINUTES);
+
+                Map<String, String> result = new HashMap<>();
+                result.put("session_id", uuid);
+                result.put("openid", openid);
+                return ResultUtil.success("success", result);
+
+            } else {
+                String body = response.body().string();
+                try {
+                    JSONObject obj = new JSONObject(body);
+                    int errCode = obj.getInt("errcode");
+                    String errMsg = obj.getString("errmsg");
+                    return ResultUtil.error(errCode, errMsg);
+                } catch (Exception e) {
+                    return ResultUtil.error(response.code(), "服务器返回格式异常");
+                }
+            }
+        } catch (Exception e) {
+            log.error("获取 session_id 失败,code: {}, error: {}", code, e.getMessage());
+            return ResultUtil.error(500, "网络异常");
+        }
+    }
+
+    /**
+     * 根据手机号查询用户
+     * @param phoneNumber
+     * @return
+     */
+    @Override
+    public boolean existsByMobileAndIsDelete(String phoneNumber){
+        return userRepository.existsByMobileAndIsDelete(phoneNumber,false);
+    }
+    @Override
+    public User findByPhoneNumberAndIsDelete(String phoneNumber){
+        return userRepository.findByMobileAndIsDelete(phoneNumber,false);
+    }
     @Override
     @Override
-    public User wxLogin(UserLoginDTO userLoginDTO) {
-        return userRepository.findByMobile(userLoginDTO.getTel());
+    public User findByIdAndIsDelete(Long id){
+        return userRepository.findByIdAndIsDelete(id,false);
     }
     }
 }
 }

+ 107 - 0
src/main/java/com/loan/system/service/Impl/WxServiceImpl.java

@@ -0,0 +1,107 @@
+package com.loan.system.service.Impl;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
+import com.loan.system.domain.entity.TemplateMessage;
+import com.loan.system.service.WxService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.data.redis.core.StringRedisTemplate;
+import org.springframework.stereotype.Service;
+import org.springframework.web.client.RestTemplate;
+
+import javax.crypto.Cipher;
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.SecretKeySpec;
+import java.security.spec.AlgorithmParameterSpec;
+import java.util.Base64;
+import java.util.HashMap;
+import java.util.Map;
+
+@Service
+public class WxServiceImpl implements WxService {
+
+    /**
+     * 微信公众号appid
+     */
+    @Value("${wechat.appid}")
+    private String appId;
+    /**
+     * 微信公众号secret
+     */
+    @Value("${wechat.secret}")
+    private String appSecret;
+    @Autowired
+    private StringRedisTemplate redisTemplate;
+    @Override
+
+    public String wxDecrypt(String encryptedData, String sessionId, String vi) throws Exception {
+        // 开始解密
+        String json = redisTemplate.opsForValue().get("wx_session_id_" + sessionId);
+        JSONObject jsonObject = JSON.parseObject(json);
+        String sessionKey = (String) jsonObject.get("session_key");
+
+        byte[] encData = Base64.getDecoder().decode(encryptedData); // 使用 Java 标准库
+        byte[] iv = Base64.getDecoder().decode(vi); // 使用 Java 标准库
+        byte[] key = Base64.getDecoder().decode(sessionKey); // 使用 Java 标准库
+
+        AlgorithmParameterSpec ivSpec = new IvParameterSpec(iv);
+        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
+        SecretKeySpec keySpec = new SecretKeySpec(key, "AES");
+        cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec);
+
+        return new String(cipher.doFinal(encData), "UTF-8");
+    }
+    @Override
+
+    public String getAccessToken() {
+        String url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid="+appId+"&secret="+appSecret;
+
+        RestTemplate restTemplate = new RestTemplate();
+        Map<String, Object> response = restTemplate.getForObject(url, Map.class, appId, appSecret);
+
+        if (response != null && response.containsKey("access_token")) {
+            return (String) response.get("access_token");
+        } else {
+            throw new RuntimeException("获取access_token失败: " + response);
+        }
+    }
+    @Override
+    public String getUserPhoneNumber(String accessToken, String code) {
+        String url = "https://api.weixin.qq.com/wxa/business/getuserphonenumber?access_token=" + accessToken;
+
+        RestTemplate restTemplate = new RestTemplate();
+
+        // 设置 POST body
+        Map<String, String> requestBody = new HashMap<>();
+        requestBody.put("code", code);
+
+        // 发送 POST 请求
+        Map<String, Object> response = restTemplate.postForObject(url, requestBody, Map.class);
+        if (response != null && response.containsKey("phone_info")) {
+            @SuppressWarnings("unchecked")
+            Map<String, Object> phoneInfo = (Map<String, Object>) response.get("phone_info");
+            return (String) phoneInfo.get("phoneNumber");
+        } else {
+            throw new RuntimeException("获取手机号失败: " + response);
+        }
+    }
+
+    @Override
+    public boolean sendTemplateMessage(String openid, TemplateMessage message) {
+        String token = getAccessToken();
+        String url = "https://api.weixin.qq.com/cgi-bin/message/subscribe/send?access_token=" + token;
+
+        // 确保 message 中的 openid 一致
+        message.setTouser(openid);
+        RestTemplate restTemplate = new RestTemplate();
+        Map<String, Object> result = restTemplate.postForObject(url, message, Map.class);
+
+        if (result == null) return false;
+
+        Integer errcode = (Integer) result.get("errcode");
+        return errcode != null && errcode == 0;
+    }
+
+
+}

+ 11 - 0
src/main/java/com/loan/system/service/LoanCaseService.java

@@ -0,0 +1,11 @@
+package com.loan.system.service;
+
+import com.loan.system.domain.entity.LoanCase;
+
+public interface LoanCaseService {
+    LoanCase findByIdAndIsDelete(Long id);
+
+    void updateUpdatetimeByIdAndIsDeleted(Long id,boolean isDelete);
+
+    void logic_delete(Long id);
+}

+ 30 - 0
src/main/java/com/loan/system/service/StepService.java

@@ -0,0 +1,30 @@
+package com.loan.system.service;
+
+import com.loan.system.domain.entity.Step;
+import com.loan.system.domain.vo.StepVO;
+
+import java.util.List;
+
+public interface StepService {
+    List<StepVO> addStepByCaseId(Long caseId);
+
+    void updateStatusByCaseId(String msg,String stepName, Long caseId);
+    
+    void cancelPreApprove(Long caseId);
+
+    StepVO updateUserByCaseId(String stepName, Long approverId, Long caseId);
+
+    List<StepVO> getStepByCaseId(Long caseId);
+
+    List<Step> getAllStepByCaseId(Long caseId);
+
+    Long getLeadSalesIdAndIsDelete(Long caseId, String stepName);
+
+    Step findByStepNameAndCaseId(String stepName, Long caseId);
+
+    void updateUserId1ByCaseIdAndStepName(String stepName, Long approverId, Long caseId);
+
+    void updateUserId2ByCaseIdAndStepName(String stepName, Long approverId, Long caseId);
+
+    void logic_delete(Long id);
+}

+ 6 - 1
src/main/java/com/loan/system/service/UserService.java

@@ -2,7 +2,12 @@ package com.loan.system.service;
 
 
 import com.loan.system.domain.dto.UserLoginDTO;
 import com.loan.system.domain.dto.UserLoginDTO;
 import com.loan.system.domain.entity.User;
 import com.loan.system.domain.entity.User;
+import com.loan.system.domain.pojo.Result;
 
 
 public interface UserService {
 public interface UserService {
-    User wxLogin(UserLoginDTO userLoginDTO);
+    Result get_sessionId(String code);
+    User findByPhoneNumberAndIsDelete(String phoneNumber);
+    User findByIdAndIsDelete(Long id);
+    boolean existsByMobileAndIsDelete(String phoneNumber);
+
 }
 }

+ 10 - 0
src/main/java/com/loan/system/service/WxService.java

@@ -0,0 +1,10 @@
+package com.loan.system.service;
+
+import com.loan.system.domain.entity.TemplateMessage;
+
+public interface WxService {
+    String wxDecrypt(String encryptedData, String sessionId, String vi) throws Exception;
+    String getAccessToken();
+    String getUserPhoneNumber(String accessToken, String code);
+    boolean sendTemplateMessage(String openid, TemplateMessage message);
+}

+ 4 - 1
src/main/java/com/loan/system/utils/JwtTokenUtil.java

@@ -1,5 +1,6 @@
 package com.loan.system.utils;
 package com.loan.system.utils;
 
 
+import com.loan.system.constant.JwtClaimsConstant;
 import io.jsonwebtoken.Claims;
 import io.jsonwebtoken.Claims;
 import io.jsonwebtoken.ExpiredJwtException;
 import io.jsonwebtoken.ExpiredJwtException;
 import io.jsonwebtoken.Jwts;
 import io.jsonwebtoken.Jwts;
@@ -86,7 +87,9 @@ public class JwtTokenUtil implements Serializable {
     public static String getUsernameFromToken(String token) {
     public static String getUsernameFromToken(String token) {
         return getClaimsFromToken(token).getSubject();
         return getClaimsFromToken(token).getSubject();
     }
     }
-
+    public static Long getUserIdFromToken(String token){
+        return (Long) getClaimsFromToken(token).get(JwtClaimsConstant.USER_ID);
+    }
     public static String getNumberFromToken(String token){
     public static String getNumberFromToken(String token){
         return (String) getClaimsFromToken(token).get("number");
         return (String) getClaimsFromToken(token).get("number");
     }
     }

+ 0 - 122
src/main/java/com/loan/system/utils/WeChatUtil.java

@@ -1,122 +0,0 @@
-package com.loan.system.utils;
-
-
-import com.fasterxml.jackson.databind.ObjectMapper;
-import org.apache.commons.codec.binary.Base64;
-import org.codehaus.xfire.client.Client;
-import org.springframework.context.ApplicationContext;
-import org.springframework.context.support.ClassPathXmlApplicationContext;
-
-import java.security.MessageDigest;
-import java.security.NoSuchAlgorithmException;
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * @author raptor
- * @description WeChatUtil
- * @date 2021/4/1 13:21
- */
-public class WeChatUtil {
-    private static ObjectMapper mapper = new ObjectMapper();
-    private static ApplicationContext appContext;
-
-    /**
-     *
-     * @param person_info
-     * 接收人信息,每个人员信息格式为:名字|学工号|部门ID|部门名称|对应微信账号,
-     * 人与人之间用“^@^”隔开(如果数据无法提供,可以写空,但是“|”不可省略),必须
-     *                      "raptor|202050235|11644008804352|杭州电子科技大学|18758159060"
-     * @param priority  发送优先级(1:紧急通知;2:验证码;3:立即发送;4:发送),必须
-     * @param wechat_info   内容,必须
-     * @return  {"result":true,"msg_id":"22961055561793536","msg":"发布成功"}
-     */
-    public static Object sendWeChatMessage(String person_info, String priority, String wechat_info){
-        Map<String, Object> map = new HashMap<String, Object>(16);
-        try {
-            appContext = new ClassPathXmlApplicationContext(new String[] {});
-            // webservice 地址由生产环境决定
-            org.springframework.core.io.Resource resource = appContext
-                    .getResource("http://i.hdu.edu.cn/tp_mp/service/WechatService?wsdl");
-
-            /** start 协议参数 start **/
-            // 调用接口的第三方系统协议名称。由双方协议确定。(*必填项)
-            map.put("tp_name", "Document");
-            // 提供接口服务的系统名称(sys/up/mp…)。由统一门户系统提供。(*必填项)
-            map.put("sys_id", "mp");
-            // 接口方法所属模块。由统一门户系统提供。(*必填项)
-            map.put("module_id", "wechat");
-            // SHA 加密后第三方系统的权限密钥值。权限密钥由统一门户系统提供。(*必填项)
-            map.put("secret_key", getSHA("xWpDa+fGlqkXGUZLNjawGT+9MHw="));
-            // 对应的接口方法名称,由统一门户系统提供。(*必填项)
-            map.put("interface_method", "saveWechatInfo");
-            /** end 协议参数 end **/
-
-            map.put("person_info", person_info);
-
-            map.put("send_priority", priority);
-
-            /** start 业务参数 start **/
-            //发送微信发布类型(text:⽂本;news:图⽂;image:图⽚;file:⽂件;video:视频;voice:⾳频),不可为空,参数不可省略
-            map.put("wechat_type", "text");
-            //内容,必须
-            map.put("wechat_info", wechat_info);
-            //发送⼈ID_NUMBER,需要发送回执的时候不可为空,参数不可省略
-            map.put("operator_id_number", "09901");
-            //发送微信附件(包括图⽚,⽂件,视频和⾳频的附件路径),为空,参数不可	省略
-            map.put("wechat_attachment", "");
-            //发送附件名称,为空,参数不可省略
-            map.put("attachment_name", "");
-            //发送附件标题,为空,参数不可省略
-            map.put("attachment_title", "");
-            //发送附件描述,为空,参数不可省略
-            map.put("attachment_des", "");
-            //发送附件时⻓(视频和⾳频),为空,参数不可省略
-            map.put("attachment_time", "");
-            //发送模板选择,不发送模板值为”0”,参数不可省略
-            map.put("templet_id", "0");
-            //发送回执选择,不发送回执值为”0”,参数不可省略
-            map.put("receipt_id", "0");
-            //发送⼈签名,根据模板⽽定,选择的模板有“发送⼈签名”标签的需要写值,其他为空,参数不可省略
-            map.put("person_send", "公管处");
-            /** end 业务参数 end **/
-
-
-
-            String json = mapper.writeValueAsString(map);
-            // 请求参数
-            System.out.println("json:" + json);
-
-            Client client = new Client(resource.getInputStream(), null);
-            Object[] result = client.invoke("saveWechatInfo", new Object[] { json });
-
-            // 返回结果
-            System.out.println(result[0]);
-
-            client.close();
-            return result[0];
-        } catch (Exception e) {
-            e.printStackTrace();
-            return null;
-        }
-    }
-    /**
-     * 获取 SHA 值  
-     *
-     * @author neusoft
-     * @since V7.0
-     * @param password
-     * @return SHA(password)
-     */
-    private static String getSHA(String password) {
-        try {
-            MessageDigest sha = MessageDigest.getInstance("SHA");
-            sha.update(password.getBytes());
-            byte[] hash = sha.digest();
-            return new String(Base64.encodeBase64(hash));
-        } catch (NoSuchAlgorithmException e1) {
-            e1.printStackTrace();
-        }
-        return "";
-    }
-}

+ 5 - 6
src/main/resources/application-dev.yaml

@@ -58,18 +58,17 @@ spring:
     driver-class-name: com.mysql.cj.jdbc.Driver
     driver-class-name: com.mysql.cj.jdbc.Driver
     url: jdbc:mysql://localhost:3306/loan_system?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai #改
     url: jdbc:mysql://localhost:3306/loan_system?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai #改
     username: root
     username: root
-    password: wgw20030620 #改
+    password: xjj010430 #改
 mybatis:
 mybatis:
   mapper-locations: classpath*:/mapping/*Mapper.xml
   mapper-locations: classpath*:/mapping/*Mapper.xml
  # type-aliases-package: com.he.common.entity.domain
  # type-aliases-package: com.he.common.entity.domain
 
 
 upload:
 upload:
   host: "http://tczbus.natappfree.cc/uploads"
   host: "http://tczbus.natappfree.cc/uploads"
-  location: "C:\\Users\\45528\\project\\java\\maintenance\\maintenance\\test" #改
+  location: "C:\\Users\\Xu\\Documents\\loan_project" #改
   extensions: "pdf,doc,docx,xlsx,JPG,jpg,bmp,BMP,gif,GIF,BMP,png,PNG,bmp,jpeg,JPEG,svg,txt"
   extensions: "pdf,doc,docx,xlsx,JPG,jpg,bmp,BMP,gif,GIF,BMP,png,PNG,bmp,jpeg,JPEG,svg,txt"
   #改
   #改
 
 
-system:
-  wechat:
-    appid: wx9c0acf979455549f
-    secret: 37452088548ea9cc6e244dc7817d938d
+wechat:
+  appid: wx9c0acf979455549f
+  secret: 37452088548ea9cc6e244dc7817d938d

+ 9 - 9
src/main/resources/application.yaml

@@ -35,12 +35,12 @@ logging:
 
 
 system:
 system:
   jwt:
   jwt:
-    user-secret-key: HDU-JUAasSDSAds*87ASud/A?D(G+KbPeShVmYq3s6v9y$B&E)H@McQfTjWnZr4u7w
-    user-ttl: 604800000
-    user-token-name: Authorization
-    admin-secret-key: HDU-JUAasSDSAds*87ASud/A?D(G+KbPeShVmYq3s6v9y$B&E)H@McQfTjWnZr4u7w
-    admin-ttl: 604800000
-    admin-token-name: Authorization
-  wechat:
-    appid: ${system.wechat.appid}
-    secret: ${system.wechat.secret}
+    user-secret-key: "HDU-JUAasSDSAds*87ASud/A?D(G+KbPeShVmYq3s6v9y$B&E)H@McQfTjWnZr4u7w"
+    user-ttl: 60480000
+    userTokenName: Authorization
+    admin-secret-key: "HDU-JUAasSDSAds*87ASud/A?D(G+KbPeShVmYq3s6v9y$B&E)H@McQfTjWnZr4u7w"
+    admin-ttl: 60480000
+    adminTokenName: Authorization
+wechat:
+  appid: wx9c0acf979455549f
+  secret: 37452088548ea9cc6e244dc7817d938d