Sfoglia il codice sorgente

Merge remote-tracking branch 'origin/master'

master
PoffyZhang 1 anno fa
parent
commit
ca34b550a9
56 ha cambiato i file con 1368 aggiunte e 629 eliminazioni
  1. +1
    -1
      ningda-generator/src/main/java/com/ningdatech/generator/config/GeneratorCodeKingbaseConfig.java
  2. +0
    -45
      pmapi/src/main/java/com/ningdatech/pmapi/common/config/BeanConfig.java
  3. +0
    -65
      pmapi/src/main/java/com/ningdatech/pmapi/common/config/GovDingProperties.java
  4. +0
    -1
      pmapi/src/main/java/com/ningdatech/pmapi/common/constant/CommonConstant.java
  5. +2
    -1
      pmapi/src/main/java/com/ningdatech/pmapi/common/constant/StateMachineConstants.java
  6. +1
    -2
      pmapi/src/main/java/com/ningdatech/pmapi/common/handler/GlobalResponseHandler.java
  7. +2
    -2
      pmapi/src/main/java/com/ningdatech/pmapi/common/statemachine/action/ProjectDeclareAction.java
  8. +2
    -2
      pmapi/src/main/java/com/ningdatech/pmapi/common/statemachine/action/ProjectDeclareChoiceAction.java
  9. +2
    -2
      pmapi/src/main/java/com/ningdatech/pmapi/common/statemachine/factory/ProjectDeclareGuardFactory.java
  10. +5
    -5
      pmapi/src/main/java/com/ningdatech/pmapi/common/statemachine/util/StateMachineUtils.java
  11. +144
    -77
      pmapi/src/main/java/com/ningdatech/pmapi/ding/task/EmployeeBatchGetTask.java
  12. +23
    -0
      pmapi/src/main/java/com/ningdatech/pmapi/expert/controller/ReviewTemplateSettingsController.java
  13. +16
    -0
      pmapi/src/main/java/com/ningdatech/pmapi/expert/mapper/ReviewTemplateSettingsMapper.java
  14. +5
    -0
      pmapi/src/main/java/com/ningdatech/pmapi/expert/mapper/ReviewTemplateSettingsMapper.xml
  15. +56
    -0
      pmapi/src/main/java/com/ningdatech/pmapi/expert/model/dto/ReviewTemplateSettingsDTO.java
  16. +113
    -0
      pmapi/src/main/java/com/ningdatech/pmapi/expert/model/entity/ReviewTemplateSettings.java
  17. +16
    -0
      pmapi/src/main/java/com/ningdatech/pmapi/expert/service/IReviewTemplateSettingsService.java
  18. +20
    -0
      pmapi/src/main/java/com/ningdatech/pmapi/expert/service/impl/ReviewTemplateSettingsServiceImpl.java
  19. +2
    -1
      pmapi/src/main/java/com/ningdatech/pmapi/projectdeclared/manage/ConstructionPlanManage.java
  20. +2
    -2
      pmapi/src/main/java/com/ningdatech/pmapi/projectlib/manage/AnnualPlanLibManage.java
  21. +4
    -6
      pmapi/src/main/java/com/ningdatech/pmapi/sys/manage/MenuManage.java
  22. +22
    -1
      pmapi/src/main/java/com/ningdatech/pmapi/sys/model/enumeration/DataScopeEnum.java
  23. +1
    -0
      pmapi/src/main/java/com/ningdatech/pmapi/todocenter/constant/WorkNotice.java
  24. +5
    -5
      pmapi/src/main/java/com/ningdatech/pmapi/todocenter/controller/TodoCenterController.java
  25. +21
    -20
      pmapi/src/main/java/com/ningdatech/pmapi/todocenter/extension/cmd/BackToHisApprovalNodeCmd.java
  26. +267
    -134
      pmapi/src/main/java/com/ningdatech/pmapi/todocenter/manage/TodoCenterManage.java
  27. +1
    -5
      pmapi/src/main/java/com/ningdatech/pmapi/todocenter/model/dto/req/ReqToBeProcessedDTO.java
  28. +52
    -0
      pmapi/src/main/java/com/ningdatech/pmapi/todocenter/model/dto/req/ReqToBeProcessedExportDTO.java
  29. +30
    -0
      pmapi/src/main/java/com/ningdatech/pmapi/user/constant/LoginTypeEnum.java
  30. +0
    -20
      pmapi/src/main/java/com/ningdatech/pmapi/user/controller/NdUserAuthController.java
  31. +0
    -20
      pmapi/src/main/java/com/ningdatech/pmapi/user/controller/NdUserInfoController.java
  32. +9
    -6
      pmapi/src/main/java/com/ningdatech/pmapi/user/controller/UserAuthController.java
  33. +16
    -1
      pmapi/src/main/java/com/ningdatech/pmapi/user/controller/UserInfoController.java
  34. +38
    -0
      pmapi/src/main/java/com/ningdatech/pmapi/user/manage/UserAuthLoginManage.java
  35. +10
    -0
      pmapi/src/main/java/com/ningdatech/pmapi/user/manage/UserInfoManage.java
  36. +33
    -0
      pmapi/src/main/java/com/ningdatech/pmapi/user/model/base/UserRoleInfo.java
  37. +29
    -0
      pmapi/src/main/java/com/ningdatech/pmapi/user/model/po/ReqUserDetailEditPO.java
  38. +20
    -0
      pmapi/src/main/java/com/ningdatech/pmapi/user/model/po/ReqUserDetailPO.java
  39. +29
    -0
      pmapi/src/main/java/com/ningdatech/pmapi/user/model/vo/ResUserDetailVO.java
  40. +5
    -8
      pmapi/src/main/java/com/ningdatech/pmapi/user/security/auth/WebSecurityConfig.java
  41. +11
    -0
      pmapi/src/main/java/com/ningdatech/pmapi/user/security/auth/constants/UserDeatilsServiceConstant.java
  42. +6
    -6
      pmapi/src/main/java/com/ningdatech/pmapi/user/security/auth/credential/AccountIdLoginUserDetailService.java
  43. +108
    -0
      pmapi/src/main/java/com/ningdatech/pmapi/user/security/auth/credential/CredentialAuthFilter.java
  44. +103
    -0
      pmapi/src/main/java/com/ningdatech/pmapi/user/security/auth/credential/CredentialAuthProvider.java
  45. +19
    -12
      pmapi/src/main/java/com/ningdatech/pmapi/user/security/auth/credential/CredentialAuthSecurityConfig.java
  46. +13
    -5
      pmapi/src/main/java/com/ningdatech/pmapi/user/security/auth/credential/CredentialAuthToken.java
  47. +67
    -0
      pmapi/src/main/java/com/ningdatech/pmapi/user/security/auth/credential/CredentialLoginUserDetailService.java
  48. +0
    -71
      pmapi/src/main/java/com/ningdatech/pmapi/user/security/auth/password/UsernamePasswordAuthFilter.java
  49. +0
    -65
      pmapi/src/main/java/com/ningdatech/pmapi/user/security/auth/password/UsernamePasswordAuthProvider.java
  50. +9
    -0
      pmapi/src/main/java/com/ningdatech/pmapi/user/util/LoginUserUtil.java
  51. +1
    -13
      pmapi/src/main/resources/application-dev.yml
  52. +5
    -13
      pmapi/src/main/resources/integration/zwdd-dev.yml
  53. +11
    -10
      pmapi/src/main/resources/integration/zwdd-prod.yml
  54. +1
    -1
      pmapi/src/main/resources/security/auth-dev.yml
  55. +1
    -1
      pmapi/src/main/resources/security/auth-prod.yml
  56. +9
    -0
      pmapi/src/test/java/com/ningdatech/pmapi/organization/OrganizationTest.java

+ 1
- 1
ningda-generator/src/main/java/com/ningdatech/generator/config/GeneratorCodeKingbaseConfig.java Vedi File

@@ -56,7 +56,7 @@ public class GeneratorCodeKingbaseConfig {
}

public static void main(String[] args) {
generate("Poffy", "projectlib", PATH_YYD, "nd_project_inst");
generate("WendyYang", "expert", PATH_YYD, "nd_review_template_settings");
}

}

+ 0
- 45
pmapi/src/main/java/com/ningdatech/pmapi/common/config/BeanConfig.java Vedi File

@@ -1,45 +0,0 @@
package com.ningdatech.pmapi.common.config;

import com.alibaba.xxpt.gateway.shared.client.http.ExecutableClient;
import com.ningdatech.pmapi.common.util.SpringContextHolder;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;

/**
* @author CMM
* @since 2023/02/03 09:24
*/
@Configuration
@Slf4j
public class BeanConfig {
@Bean
public SpringContextHolder springContextHolder() {
return new SpringContextHolder();
}

@Bean("authExecutableClient")
@DependsOn(value = "govDingProperties")
public ExecutableClient executableAuthClientInit() {
ExecutableClient executableClient = ExecutableClient.getInstance();
executableClient.setAccessKey(GovDingProperties.appAuthkey);
executableClient.setSecretKey(GovDingProperties.appAuthsecret);
executableClient.setDomainName(GovDingProperties.domain);
executableClient.setProtocal("https");
executableClient.init();
return executableClient;
}

@Bean("executableClient")
@DependsOn(value = "govDingProperties")
public ExecutableClient executableClientInit() {
ExecutableClient executableClient = new ExecutableClient();
executableClient.setAccessKey(GovDingProperties.appkey);
executableClient.setSecretKey(GovDingProperties.appsecret);
executableClient.setDomainName(GovDingProperties.domain);
executableClient.setProtocal("https");
executableClient.init();
return executableClient;
}
}

+ 0
- 65
pmapi/src/main/java/com/ningdatech/pmapi/common/config/GovDingProperties.java Vedi File

@@ -1,65 +0,0 @@
package com.ningdatech.pmapi.common.config;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import lombok.Data;

/**
* @description: 浙政钉配置
* @author: liushuai
* @date: 2022/5/5 15:10
*/
@Data
@Component
public class GovDingProperties {
public static String appkey;
public static String appsecret;
public static String appAuthkey;
public static String appAuthsecret;

public static String appSsoAuthkey;
public static String appSsoAuthsecret;
public static Long tenantId;

public static String domain;

@Value("${ding.app-key}")
public void setPrivateKey(String appkey) {
GovDingProperties.appkey = appkey;
}

@Value("${ding.app-secret}")
public void setAppsecret(String appsecret) {
GovDingProperties.appsecret = appsecret;
}

@Value("${ding.app-auth-key}")
public void setAppAuthKey(String appAuthkey) {
GovDingProperties.appAuthkey = appAuthkey;
}

@Value("${ding.app-auth-secret}")
public void setAppAuthsecret(String appAuthsecret) {
GovDingProperties.appAuthsecret = appAuthsecret;
}

// @Value("${ding.app-sso-auth-key}")
// public void setAppSsoAuthKey(String appSsoAuthkey) {
// GovDingProperties.appSsoAuthkey = appSsoAuthkey;
// }
//
// @Value("${ding.app-sso-auth-secret}")
// public void setAppSsoAuthsecret(String appSsoAuthsecret) {
// GovDingProperties.appSsoAuthsecret = appSsoAuthsecret;
// }

@Value("${ding.tenantId}")
public void setTenantId(Long tenantId) {
GovDingProperties.tenantId = tenantId;
}
@Value("${ding.domain}")
public void setDomain(String domain) {
GovDingProperties.domain = domain;
}
}

+ 0
- 1
pmapi/src/main/java/com/ningdatech/pmapi/common/constant/CommonConstant.java Vedi File

@@ -10,7 +10,6 @@ public class CommonConstant {
public static final String COOKIE_KEY = "ND_JSESSION";

public static final Integer EXPORT_PAGE_NUMBER = 1;

public static final Integer EXPORT_PAGE_SIZE = 100000;
public static final String CALL_STATUS = "status";
public static final String CALL_STATUS_OK_VALUE = "ok";


pmapi/src/main/java/com/ningdatech/pmapi/common/constant/StateMachineHeaderNameConstants.java → pmapi/src/main/java/com/ningdatech/pmapi/common/constant/StateMachineConstants.java Vedi File

@@ -5,8 +5,9 @@ package com.ningdatech.pmapi.common.constant;
* @since 2023/02/07 16:24
*/

public class StateMachineHeaderNameConstants {
public class StateMachineConstants {

public static final String PROJECT_DECLARE = "projectDeclare";
public static final String LI_SHUI_CITY_AREA_CODE = "331100";

}

+ 1
- 2
pmapi/src/main/java/com/ningdatech/pmapi/common/handler/GlobalResponseHandler.java Vedi File

@@ -2,7 +2,6 @@ package com.ningdatech.pmapi.common.handler;

import cn.hutool.json.JSONUtil;
import com.ningdatech.basic.model.ApiResponse;
import com.ningdatech.pmapi.common.util.BizUtils;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
@@ -24,7 +23,7 @@ import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
"com.ningdatech.pmapi.projectlib.controller",
"com.ningdatech.pmapi.sys.controller",
"com.ningdatech.pmapi.todocenter.controller",
"com.ningdatech.pmapi.user.controller"
"com.ningdatech.pmapi.user.controller",
})
public class GlobalResponseHandler implements ResponseBodyAdvice<Object> {



+ 2
- 2
pmapi/src/main/java/com/ningdatech/pmapi/common/statemachine/action/ProjectDeclareAction.java Vedi File

@@ -1,6 +1,6 @@
package com.ningdatech.pmapi.common.statemachine.action;

import com.ningdatech.pmapi.common.constant.StateMachineHeaderNameConstants;
import com.ningdatech.pmapi.common.constant.StateMachineConstants;
import com.ningdatech.pmapi.common.statemachine.builder.ProjectDeclareStateMachineBuilder;
import com.ningdatech.pmapi.common.statemachine.util.StateMachineUtils;
import com.ningdatech.pmapi.common.statemachine.event.ProjectStatusChangeEvent;
@@ -23,7 +23,7 @@ import org.springframework.statemachine.annotation.WithStateMachine;
@WithStateMachine(id = ProjectDeclareStateMachineBuilder.MACHINEID_TO)
public class ProjectDeclareAction {

private static final String PROJECT_DECLARE = StateMachineHeaderNameConstants.PROJECT_DECLARE;
private static final String PROJECT_DECLARE = StateMachineConstants.PROJECT_DECLARE;

@OnTransition(source = "UNDER_INTERNAL_AUDIT", target = "PENDING_PREQUALIFICATION")
public void UNDER_INTERNAL_PASS(Message<ProjectStatusChangeEvent> message) {


+ 2
- 2
pmapi/src/main/java/com/ningdatech/pmapi/common/statemachine/action/ProjectDeclareChoiceAction.java Vedi File

@@ -1,6 +1,6 @@
package com.ningdatech.pmapi.common.statemachine.action;

import com.ningdatech.pmapi.common.constant.StateMachineHeaderNameConstants;
import com.ningdatech.pmapi.common.constant.StateMachineConstants;
import com.ningdatech.pmapi.common.statemachine.util.StateMachineUtils;
import com.ningdatech.pmapi.common.statemachine.event.ProjectStatusChangeEvent;
import com.ningdatech.pmapi.projectlib.enumeration.ProjectStatusEnum;
@@ -18,7 +18,7 @@ import org.springframework.statemachine.action.Action;
@Slf4j
public class ProjectDeclareChoiceAction implements Action<ProjectStatusEnum, ProjectStatusChangeEvent> {

private static final String PROJECT_DECLARE = StateMachineHeaderNameConstants.PROJECT_DECLARE;
private static final String PROJECT_DECLARE = StateMachineConstants.PROJECT_DECLARE;

@Override
public void execute(StateContext<ProjectStatusEnum, ProjectStatusChangeEvent> stateContext) {


+ 2
- 2
pmapi/src/main/java/com/ningdatech/pmapi/common/statemachine/factory/ProjectDeclareGuardFactory.java Vedi File

@@ -1,6 +1,6 @@
package com.ningdatech.pmapi.common.statemachine.factory;

import com.ningdatech.pmapi.common.constant.StateMachineHeaderNameConstants;
import com.ningdatech.pmapi.common.constant.StateMachineConstants;
import com.ningdatech.pmapi.common.statemachine.util.StateMachineUtils;
import com.ningdatech.pmapi.common.statemachine.event.ProjectStatusChangeEvent;
import com.ningdatech.pmapi.projectlib.enumeration.ProjectStatusEnum;
@@ -16,7 +16,7 @@ import org.springframework.statemachine.guard.Guard;
*/

public class ProjectDeclareGuardFactory {
private static final String PROJECT_DECLARE = StateMachineHeaderNameConstants.PROJECT_DECLARE;
private static final String PROJECT_DECLARE = StateMachineConstants.PROJECT_DECLARE;

public class PendingPreQualificationChoiceGuard implements Guard<ProjectStatusEnum, ProjectStatusChangeEvent> {
@Override


+ 5
- 5
pmapi/src/main/java/com/ningdatech/pmapi/common/statemachine/util/StateMachineUtils.java Vedi File

@@ -2,7 +2,7 @@ package com.ningdatech.pmapi.common.statemachine.util;

import com.ningdatech.basic.exception.BizException;
import com.ningdatech.pmapi.common.constant.ProjectDeclareConstants;
import com.ningdatech.pmapi.common.constant.StateMachineHeaderNameConstants;
import com.ningdatech.pmapi.common.constant.StateMachineConstants;
import com.ningdatech.pmapi.common.statemachine.builder.ProjectDeclareStateMachineBuilder;
import com.ningdatech.pmapi.common.statemachine.event.ProjectStatusChangeEvent;
import com.ningdatech.pmapi.projectlib.enumeration.ProjectStatusEnum;
@@ -29,7 +29,7 @@ import java.util.Objects;
@RequiredArgsConstructor
public class StateMachineUtils {

private static final String PROJECT_DECLARE = StateMachineHeaderNameConstants.PROJECT_DECLARE;
private static final String PROJECT_DECLARE = StateMachineConstants.PROJECT_DECLARE;

private final ProjectDeclareStateMachineBuilder projectDeclareStateMachineBuilder;

@@ -64,7 +64,7 @@ public class StateMachineUtils {
}

/**
* 判断项目建设层级是否为市级项目
* 判断申报项目是否为市级项目
*
* @param project
* @return boolean
@@ -72,8 +72,8 @@ public class StateMachineUtils {
* @since 2023/02/07 17:05
*/
public static boolean isCityProject(Project project) {
if (ProjectDeclareConstants.Number.CITY_BUILD_LEVEL.equals(project.getBuildLevel()) ||
ProjectDeclareConstants.Number.CITY_SELF_BUILD_LEVEL.equals(project.getBuildLevel())) {
String areaCode = project.getAreaCode();
if (areaCode.equals(StateMachineConstants.LI_SHUI_CITY_AREA_CODE)) {
return true;
}
return false;


+ 144
- 77
pmapi/src/main/java/com/ningdatech/pmapi/ding/task/EmployeeBatchGetTask.java Vedi File

@@ -1,77 +1,144 @@
package com.ningdatech.pmapi.ding.task;

import cn.hutool.core.collection.CollUtil;
import com.ningdatech.basic.model.GenericResult;
import com.ningdatech.pmapi.common.config.GovDingProperties;
import com.ningdatech.pmapi.organization.entity.DingOrganization;
import com.ningdatech.pmapi.organization.service.IDingOrganizationService;
import com.ningdatech.zwdd.client.ZwddClient;
import com.ningdatech.zwdd.model.Page;
import com.ningdatech.zwdd.model.query.PageOrganizationEmployeePositionsQuery;
import com.ningdatech.zwdd.model.response.OrganizationEmployeePosition;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;

/**
* @author liuxinxin
* @date 2023/2/10 上午9:52
*/

@Component
public class EmployeeBatchGetTask {

private final static Integer PAGE_SIZE = 20;

@Autowired
private ZwddClient zwddClient;
private IDingOrganizationService iDingOrganizationService;

@Transactional(rollbackFor = Exception.class)
public void batchGetEmployeeTask() {
List<DingOrganization> dingOrganizationList = iDingOrganizationService.list();
if (CollUtil.isNotEmpty(dingOrganizationList)) {
List<OrganizationEmployeePosition> allOrganizationEmployeePositionList = new ArrayList<>();

for (DingOrganization dingOrganization : dingOrganizationList) {
String organizationCode = dingOrganization.getOrganizationCode();
PageOrganizationEmployeePositionsQuery query = new PageOrganizationEmployeePositionsQuery();
query.setEmployeeStatus("A");
query.setOrganizationCode(organizationCode);
query.setReturnTotalSize(true);
query.setTenantId(GovDingProperties.tenantId);

int pageNo = 1;
query.setPageNo(pageNo);
query.setPageSize(PAGE_SIZE);

GenericResult<Page<OrganizationEmployeePosition>> firstPageGenericResult = zwddClient.pageOrganizationEmployeePositions(query);
Page<OrganizationEmployeePosition> data = firstPageGenericResult.getData();
if (CollUtil.isNotEmpty(data.getData())) {
allOrganizationEmployeePositionList.addAll(data.getData());
}
Long totalSize = data.getTotalSize();
if (totalSize > PAGE_SIZE) {
int maxPageNo = (int) Math.ceil(totalSize / PAGE_SIZE);
for (pageNo = 2; pageNo <= maxPageNo; pageNo++) {
query.setPageNo(maxPageNo);
GenericResult<Page<OrganizationEmployeePosition>> pageGenericResult = zwddClient.pageOrganizationEmployeePositions(query);
if (CollUtil.isNotEmpty(pageGenericResult.getData().getData())) {
allOrganizationEmployeePositionList.addAll(pageGenericResult.getData().getData());
}
}
}


}

// zwddClient.pageOrganizationEmployeePositions(query);

}


}
}
//package com.ningdatech.pmapi.ding.task;
//
//import cn.hutool.core.collection.CollUtil;
//import com.ningdatech.basic.model.GenericResult;
//import com.ningdatech.pmapi.organization.entity.DingEmployeeInfo;
//import com.ningdatech.pmapi.organization.entity.DingOrganization;
//import com.ningdatech.pmapi.organization.service.IDingEmployeeInfoService;
//import com.ningdatech.pmapi.organization.service.IDingOrganizationService;
//import com.ningdatech.zwdd.client.ZwddClient;
//import com.ningdatech.zwdd.model.Page;
//import com.ningdatech.zwdd.model.dto.EmployeeAccountIdDTO;
//import com.ningdatech.zwdd.model.query.PageOrganizationEmployeePositionsQuery;
//import com.ningdatech.zwdd.model.response.OrganizationEmployeePosition;
//import com.ningdatech.zwdd.model.response.OrganizationEmployeePosition.GovEmployeePosition;
//import org.springframework.beans.BeanUtils;
//import org.springframework.beans.factory.annotation.Autowired;
//import org.springframework.stereotype.Component;
//import org.springframework.transaction.annotation.Transactional;
//
//import java.util.ArrayList;
//import java.util.List;
//import java.util.stream.Collectors;
//
///**
// * @author liuxinxin
// * @date 2023/2/10 上午9:52
// */
//
//@Component
//public class EmployeeBatchGetTask {
//
// private final static Integer PAGE_SIZE = 20;
//
// private final static Integer GROUP_SIZE = 100;
//
// @Autowired
// private ZwddClient zwddClient;
//
// @Autowired
// private IDingOrganizationService iDingOrganizationService;
//
// @Autowired
// private IDingEmployeeInfoService iDingEmployeeInfoService;
//
// @Transactional(rollbackFor = Exception.class)
// public void batchGetEmployeeTask() {
//
// // 获取所有的组织列表用户获取组织下的 用户信息
// List<DingOrganization> dingOrganizationList = iDingOrganizationService.list();
// if (CollUtil.isNotEmpty(dingOrganizationList)) {
// for (DingOrganization dingOrganization : dingOrganizationList) {
// List<OrganizationEmployeePosition> allOrganizationEmployeePositionList = new ArrayList<>();
// String organizationCode = dingOrganization.getOrganizationCode();
// PageOrganizationEmployeePositionsQuery query = new PageOrganizationEmployeePositionsQuery();
// query.setEmployeeStatus("A");
// query.setOrganizationCode(organizationCode);
// query.setReturnTotalSize(true);
//// query.setTenantId(GovDingProperties.tenantId);
// int pageNo = 1;
// query.setPageNo(pageNo);
// query.setPageSize(PAGE_SIZE);
//
// // 查询组织下 用户信息
// GenericResult<Page<OrganizationEmployeePosition>> firstPageGenericResult = zwddClient.pageOrganizationEmployeePositions(query);
// Page<OrganizationEmployeePosition> data = firstPageGenericResult.getData();
// if (CollUtil.isNotEmpty(data.getData())) {
//
// allOrganizationEmployeePositionList.addAll(data.getData());
// }
// Long totalSize = data.getTotalSize();
// if (totalSize > PAGE_SIZE) {
// int maxPageNo = (int) Math.ceil(totalSize / PAGE_SIZE);
// for (pageNo = 2; pageNo <= maxPageNo; pageNo++) {
// query.setPageNo(maxPageNo);
// GenericResult<Page<OrganizationEmployeePosition>> pageGenericResult = zwddClient.pageOrganizationEmployeePositions(query);
// if (CollUtil.isNotEmpty(pageGenericResult.getData().getData())) {
// allOrganizationEmployeePositionList.addAll(pageGenericResult.getData().getData());
// }
// }
// }
//
// List<DingEmployeeInfo> dingEmployeeInfoList = new ArrayList<>();
// if (allOrganizationEmployeePositionList.size() <= GROUP_SIZE) {
// List<String> employeeCodes = allOrganizationEmployeePositionList.stream().map(OrganizationEmployeePosition::getEmployeeCode).collect(Collectors.toList());
// GenericResult<List<EmployeeAccountIdDTO>> listGenericResult = zwddClient.listEmployeeAccountIds(employeeCodes);
//// List<EmployeeAccountIdDTO> employeeAccountIdDTOList = listGenericResult.getData();
// } else {
//// iDingEmployeeInfoService.saveBatch();
// }
// // 批量保存用户信息
// saveBatch(allOrganizationEmployeePositionList);
// }
//
// }
//
//
// }
//
// private List<DingEmployeeInfo> buildDingEmployeeInfoRecord(List<OrganizationEmployeePosition> allOrganizationEmployeePositionList) {
// List<DingEmployeeInfo> saveRecordList = new ArrayList<>();
// for (OrganizationEmployeePosition organizationEmployeePosition : allOrganizationEmployeePositionList) {
// List<GovEmployeePosition> govEmployeePositions = organizationEmployeePosition.getGovEmployeePositions();
// if (CollUtil.isNotEmpty(govEmployeePositions)) {
// List<DingEmployeeInfo> segmentSaveRecordList = new ArrayList<>();
// for (GovEmployeePosition govEmployeePosition : govEmployeePositions) {
// DingEmployeeInfo dingEmployeeInfo = new DingEmployeeInfo();
// BeanUtils.copyProperties(organizationEmployeePosition, dingEmployeeInfo);
// dingEmployeeInfo.setMainJob(govEmployeePosition.getMainJob());
// dingEmployeeInfo.setEmpPosUnitCode(govEmployeePosition.getEmpPosUnitCode());
// dingEmployeeInfo.setEmpPosEmployeeRoleCode(govEmployeePosition.getEmpPosEmployeeRoleCode());
// dingEmployeeInfo.setEmpPosInnerInstitutionCode(govEmployeePosition.getEmpPosInnerInstitutionCode());
// dingEmployeeInfo.setEmployeeCode(govEmployeePosition.getEmployeeCode());
// dingEmployeeInfo.setJobAttributesCode(govEmployeePosition.getJobAttributesCode());
// dingEmployeeInfo.setOrganizationCode(govEmployeePosition.getOrganizationCode());
// dingEmployeeInfo.setEmpPosVirtualOrganizationCode(govEmployeePosition.getEmpPosVirtualOrganizationCode());
// dingEmployeeInfo.setEmpStatus(govEmployeePosition.getStatus());
// segmentSaveRecordList.add(dingEmployeeInfo);
// }
// saveRecordList.addAll(segmentSaveRecordList);
// } else {
// DingEmployeeInfo dingEmployeeInfo = new DingEmployeeInfo();
// BeanUtils.copyProperties(organizationEmployeePosition, dingEmployeeInfo);
// saveRecordList.add(dingEmployeeInfo);
// }
//
//
// }
// return null;
// }
//
// private void saveBatch(List<OrganizationEmployeePosition> allOrganizationEmployeePositionList) {
//
//// // 批量保存
//// if (saveRecordList.size() <= GROUP_SIZE) {
//// iDingOrganizationService.saveBatch(saveRecordList);
//// } else {
//// List<List<DingOrganization>> split = Lists.partition(saveRecordList, GROUP_SIZE);
//// for (List<DingOrganization> segment : split) {
//// iDingOrganizationService.saveBatch(segment);
//// }
//// }
//
// }
//}

+ 23
- 0
pmapi/src/main/java/com/ningdatech/pmapi/expert/controller/ReviewTemplateSettingsController.java Vedi File

@@ -0,0 +1,23 @@
package com.ningdatech.pmapi.expert.controller;


import io.swagger.annotations.Api;
import lombok.AllArgsConstructor;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
* <p>
* 评审模版配置表 前端控制器
* </p>
*
* @author WendyYang
* @since 2023-02-14
*/
@RestController
@AllArgsConstructor
@Api(tags = "评审模版配置")
@RequestMapping("/api/v1/reviewTemplateSettings")
public class ReviewTemplateSettingsController {

}

+ 16
- 0
pmapi/src/main/java/com/ningdatech/pmapi/expert/mapper/ReviewTemplateSettingsMapper.java Vedi File

@@ -0,0 +1,16 @@
package com.ningdatech.pmapi.expert.mapper;

import com.ningdatech.pmapi.expert.model.entity.ReviewTemplateSettings;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;

/**
* <p>
* 评审模版配置表 Mapper 接口
* </p>
*
* @author WendyYang
* @since 2023-02-14
*/
public interface ReviewTemplateSettingsMapper extends BaseMapper<ReviewTemplateSettings> {

}

+ 5
- 0
pmapi/src/main/java/com/ningdatech/pmapi/expert/mapper/ReviewTemplateSettingsMapper.xml Vedi File

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

</mapper>

+ 56
- 0
pmapi/src/main/java/com/ningdatech/pmapi/expert/model/dto/ReviewTemplateSettingsDTO.java Vedi File

@@ -0,0 +1,56 @@
package com.ningdatech.pmapi.expert.model.dto;

import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;

import javax.validation.Valid;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import java.util.List;

/**
* <p>
* ReviewTemplateSettingsDTO
* </p>
*
* @author WendyYang
* @since 17:06 2023/2/14
*/
@Data
public class ReviewTemplateSettingsDTO {

@ApiModelProperty("序号")
@NotNull(message = "序号不能为空")
private Integer serialNo;

@ApiModelProperty("标题")
@NotBlank(message = "标题不能为空")
private String title;

@Valid
@ApiModelProperty("选项")
@NotEmpty(message = "选项不能为空")
private List<OptionDTO> options;

@ApiModelProperty("选择类型:1 单选、2 多选")
@NotNull(message = "选择类型不能为空")
private Integer optionType;

@Data
@ApiModel("选项实体")
public static class OptionDTO {

@ApiModelProperty("序号")
@NotNull(message = "序号不能为空")
private Integer serialNo;

@ApiModelProperty("选项内容")
@NotBlank(message = "选项内容不能为空")
private String option;

}


}

+ 113
- 0
pmapi/src/main/java/com/ningdatech/pmapi/expert/model/entity/ReviewTemplateSettings.java Vedi File

@@ -0,0 +1,113 @@
package com.ningdatech.pmapi.expert.model.entity;

import com.baomidou.mybatisplus.annotation.TableName;
import java.io.Serializable;
import java.time.LocalDateTime;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;

/**
* <p>
* 评审模版配置表
* </p>
*
* @author WendyYang
* @since 2023-02-14
*/
@TableName("nd_review_template_settings")
@ApiModel(value = "NdReviewTemplateSettings对象", description = "评审模版配置表")
public class ReviewTemplateSettings implements Serializable {

private static final long serialVersionUID = 1L;

@ApiModelProperty("主键")
private Long id;

@ApiModelProperty("模版类型:1 初步方案评审模版、2 建设方案评审模版、3 验收方案评审模版")
private Integer templateType;

@ApiModelProperty("模版内容")
private String content;

private Long createBy;

private Long updateBy;

private LocalDateTime createOn;

private LocalDateTime updateOn;

@ApiModelProperty("是否是最新")
private Boolean isLast;

public Long getId() {
return id;
}

public void setId(Long id) {
this.id = id;
}
public Integer getTemplateType() {
return templateType;
}

public void setTemplateType(Integer templateType) {
this.templateType = templateType;
}
public String getContent() {
return content;
}

public void setContent(String content) {
this.content = content;
}
public Long getCreateBy() {
return createBy;
}

public void setCreateBy(Long createBy) {
this.createBy = createBy;
}
public Long getUpdateBy() {
return updateBy;
}

public void setUpdateBy(Long updateBy) {
this.updateBy = updateBy;
}
public LocalDateTime getCreateOn() {
return createOn;
}

public void setCreateOn(LocalDateTime createOn) {
this.createOn = createOn;
}
public LocalDateTime getUpdateOn() {
return updateOn;
}

public void setUpdateOn(LocalDateTime updateOn) {
this.updateOn = updateOn;
}
public Boolean getIsLast() {
return isLast;
}

public void setIsLast(Boolean isLast) {
this.isLast = isLast;
}

@Override
public String toString() {
return "NdReviewTemplateSettings{" +
"id=" + id +
", templateType=" + templateType +
", content=" + content +
", createBy=" + createBy +
", updateBy=" + updateBy +
", createOn=" + createOn +
", updateOn=" + updateOn +
", isLast=" + isLast +
"}";
}
}

+ 16
- 0
pmapi/src/main/java/com/ningdatech/pmapi/expert/service/IReviewTemplateSettingsService.java Vedi File

@@ -0,0 +1,16 @@
package com.ningdatech.pmapi.expert.service;

import com.ningdatech.pmapi.expert.model.entity.ReviewTemplateSettings;
import com.baomidou.mybatisplus.extension.service.IService;

/**
* <p>
* 评审模版配置表 服务类
* </p>
*
* @author WendyYang
* @since 2023-02-14
*/
public interface IReviewTemplateSettingsService extends IService<ReviewTemplateSettings> {

}

+ 20
- 0
pmapi/src/main/java/com/ningdatech/pmapi/expert/service/impl/ReviewTemplateSettingsServiceImpl.java Vedi File

@@ -0,0 +1,20 @@
package com.ningdatech.pmapi.expert.service.impl;

import com.ningdatech.pmapi.expert.model.entity.ReviewTemplateSettings;
import com.ningdatech.pmapi.expert.mapper.ReviewTemplateSettingsMapper;
import com.ningdatech.pmapi.expert.service.IReviewTemplateSettingsService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;

/**
* <p>
* 评审模版配置表 服务实现类
* </p>
*
* @author WendyYang
* @since 2023-02-14
*/
@Service
public class ReviewTemplateSettingsServiceImpl extends ServiceImpl<ReviewTemplateSettingsMapper, ReviewTemplateSettings> implements IReviewTemplateSettingsService {

}

+ 2
- 1
pmapi/src/main/java/com/ningdatech/pmapi/projectdeclared/manage/ConstructionPlanManage.java Vedi File

@@ -24,6 +24,7 @@ import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.util.Collections;
import java.util.Map;
@@ -77,7 +78,7 @@ public class ConstructionPlanManage {

//首先要判断 项目当前状态 是不是 方案待申报
VUtils.isTrue(!ProjectStatusEnum.PLAN_TO_BE_DECLARED.getCode().equals(projectInfo.getStatus()) ||
!ProjectStatusEnum.NOT_APPROVED.getCode().equals(projectInfo.getStage()))
!ProjectStatusEnum.NOT_APPROVED.getCode().equals(projectInfo.getStage()))
.throwMessage("提交失败 该项目不是 待预审状态或者未立项阶段");
// TODO 再判断 该项目是否 真实走完 预审审批



+ 2
- 2
pmapi/src/main/java/com/ningdatech/pmapi/projectlib/manage/AnnualPlanLibManage.java Vedi File

@@ -145,7 +145,7 @@ public class AnnualPlanLibManage {
try (InputStream inputStream = file.getInputStream()) {
EasyExcel.read(inputStream, new AnalysisEventListener<AnnualLibImportDTO>() {

private List<Project> records = new ArrayList<>();
private final List<Project> records = new ArrayList<>();

@Override
public void onException(Exception exception, AnalysisContext context) throws Exception {
@@ -179,7 +179,7 @@ public class AnnualPlanLibManage {
project.setBeginTime(dataArr[0].trim());
project.setEndTime(dataArr[1].trim());
project.setProjectIntroduction(data.getProjectIntroduction());
project.setIsFirst(data.getIsFirst().equals("新建") ? 1 : 0);
project.setIsFirst("新建".equals(data.getIsFirst()) ? 1 : 0);
records.add(project);
}



+ 4
- 6
pmapi/src/main/java/com/ningdatech/pmapi/sys/manage/MenuManage.java Vedi File

@@ -1,7 +1,6 @@
package com.ningdatech.pmapi.sys.manage;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.ningdatech.basic.util.CollUtils;
import com.ningdatech.pmapi.common.util.TreeUtil;
@@ -10,12 +9,11 @@ import com.ningdatech.pmapi.sys.model.entity.RoleMenu;
import com.ningdatech.pmapi.sys.model.vo.MenuRoleVO;
import com.ningdatech.pmapi.sys.service.IRoleMenuService;
import com.ningdatech.pmapi.user.security.auth.model.UserInfoDetails;
import com.ningdatech.pmapi.user.util.LoginUserUtil;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;

import java.util.Collections;
import java.util.List;
import java.util.Objects;

/**
* <p>
@@ -32,11 +30,11 @@ public class MenuManage {
private final IRoleMenuService roleMenuService;

public List<MenuRoleVO> buildUserMenu(List<Menu> list, UserInfoDetails loginUser) {
if (Objects.isNull(loginUser) || CollUtil.isEmpty(loginUser.getRoleIdList())) {
/*if (Objects.isNull(loginUser) || CollUtil.isEmpty(loginUser.getRoleIdList())) {
return Collections.emptyList();
}
}*/
List<RoleMenu> roleMenus = roleMenuService.list(Wrappers.lambdaQuery(RoleMenu.class)
.in(RoleMenu::getRoleId, loginUser.getRoleIdList()));
.in(RoleMenu::getRoleId, LoginUserUtil.getRoleIdList()));
List<MenuRoleVO> menuRoles = CollUtils.convert(list, w -> BeanUtil.copyProperties(w, MenuRoleVO.class));
return TreeUtil.buildUserTree(menuRoles, roleMenus);
}


+ 22
- 1
pmapi/src/main/java/com/ningdatech/pmapi/sys/model/enumeration/DataScopeEnum.java Vedi File

@@ -2,9 +2,11 @@ package com.ningdatech.pmapi.sys.model.enumeration;

import lombok.Getter;

import java.util.Arrays;

/**
* <p>
* DataScopeEnum
* 数据权限可见范围枚举
* </p>
*
* @author WendyYang
@@ -28,4 +30,23 @@ public enum DataScopeEnum {
this.code = code;
this.desc = desc;
}

public boolean eq(Integer code) {
return this.code.equals(code);
}

/**
* 根据code获取枚举实例
*
* @param code 编码
* @return {@link DataScopeEnum}
* @author WendyYang
**/
public static DataScopeEnum getByCode(Integer code) {
return Arrays.stream(values())
.filter(w -> w.eq(code))
.findFirst()
.orElseThrow(() -> new IllegalArgumentException("无效的数据权限可见范围编码"));
}

}

+ 1
- 0
pmapi/src/main/java/com/ningdatech/pmapi/todocenter/constant/WorkNotice.java Vedi File

@@ -7,6 +7,7 @@ package com.ningdatech.pmapi.todocenter.constant;
public interface WorkNotice {
public final String PASS_MSG_TEMPLATE = "标题:审核任务 内容:【%s】的【%s】需要您审核。";
public final String PASS_MSG_TEMPLATE2 = "【%s】已通过【%s】,请及时开始下一步操作。";
public final String PASS_MSG_TEMPLATE3 = "【%s】的【%s】被退回,请及时处理。";


}

+ 5
- 5
pmapi/src/main/java/com/ningdatech/pmapi/todocenter/controller/TodoCenterController.java Vedi File

@@ -7,6 +7,7 @@ import javax.validation.Valid;
import com.ningdatech.pmapi.common.util.ExcelDownUtil;
import com.ningdatech.pmapi.todocenter.bean.vo.ProcessProgressDetailVo;
import com.ningdatech.pmapi.todocenter.model.dto.req.ReqProcessHandlerDTO;
import com.ningdatech.pmapi.todocenter.model.dto.req.ReqToBeProcessedExportDTO;
import org.springframework.web.bind.annotation.*;

import com.ningdatech.basic.model.ApiResponse;
@@ -53,7 +54,7 @@ public class TodoCenterController {
* @return void
*/
@PostMapping("/exportPending")
public void exportPendingProjectList(@Valid @RequestBody ReqToBeProcessedDTO param, HttpServletResponse response){
public void exportPendingProjectList(@Valid @RequestBody ReqToBeProcessedExportDTO param, HttpServletResponse response){
todoCenterManage.exportPendingProjectList(response,param);
}

@@ -66,7 +67,6 @@ public class TodoCenterController {
@GetMapping("/progress/{instanceId}/{nodeId}")
public ApiResponse<ProcessProgressDetailVo> getProcessDetail(@PathVariable String instanceId,
@PathVariable(required = false) String nodeId) {

return ApiResponse.ofSuccess(todoCenterManage.getProcessDetail(nodeId, instanceId));
}

@@ -99,7 +99,7 @@ public class TodoCenterController {
* @return void
*/
@PostMapping("/exportHandled")
public void exportHandledProjectList(@Valid @RequestBody ReqToBeProcessedDTO param, HttpServletResponse response){
public void exportHandledProjectList(@Valid @RequestBody ReqToBeProcessedExportDTO param, HttpServletResponse response){
todoCenterManage.exportHandledProjectList(response,param);
}

@@ -122,7 +122,7 @@ public class TodoCenterController {
* @return void
*/
@PostMapping("/exportMySubmitted")
public void exportMySubmittedProjectList(@Valid @RequestBody ReqToBeProcessedDTO param, HttpServletResponse response){
public void exportMySubmittedProjectList(@Valid @RequestBody ReqToBeProcessedExportDTO param, HttpServletResponse response){
todoCenterManage.exportMySubmittedProjectList(response,param);
}

@@ -145,7 +145,7 @@ public class TodoCenterController {
* @return void
*/
@PostMapping("/exportCcMe")
public void exportCcMeProjectList(@Valid @RequestBody ReqToBeProcessedDTO param, HttpServletResponse response){
public void exportCcMeProjectList(@Valid @RequestBody ReqToBeProcessedExportDTO param, HttpServletResponse response){
todoCenterManage.exportCcMeProjectList(response,param);
}
}

+ 21
- 20
pmapi/src/main/java/com/ningdatech/pmapi/todocenter/extension/cmd/BackToHisApprovalNodeCmd.java Vedi File

@@ -4,9 +4,17 @@ import java.io.Serializable;
import java.util.*;
import java.util.stream.Collectors;

import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.ningdatech.pmapi.projectlib.enumeration.ProjectStatusEnum;
import com.ningdatech.pmapi.projectlib.model.entity.Project;
import com.ningdatech.pmapi.projectlib.service.IProjectService;
import com.ningdatech.pmapi.todocenter.enumeration.ProcessStatusEnum;
import com.wflow.workflow.enums.ProcessHandlerEnum;
import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor;
import lombok.RequiredArgsConstructor;
import org.assertj.core.util.Sets;
import org.flowable.bpmn.model.BpmnModel;
import org.flowable.bpmn.model.FlowNode;
import org.flowable.bpmn.model.Process;
import org.flowable.bpmn.model.UserTask;
@@ -14,6 +22,7 @@ import org.flowable.common.engine.api.FlowableException;
import org.flowable.common.engine.api.FlowableObjectNotFoundException;
import org.flowable.common.engine.impl.interceptor.Command;
import org.flowable.common.engine.impl.interceptor.CommandContext;
import org.flowable.engine.RepositoryService;
import org.flowable.engine.RuntimeService;
import org.flowable.engine.TaskService;
import org.flowable.engine.impl.delegate.ActivityBehavior;
@@ -32,21 +41,15 @@ import com.wflow.workflow.utils.FlowableUtils;
* @date : 2022/10/14
*/
@RequiredArgsConstructor
@AllArgsConstructor
public class BackToHisApprovalNodeCmd implements Command<String>, Serializable {

private static final long serialVersionUID = -80075781855060928L;
protected TaskService taskService;

protected RuntimeService runtimeService;
protected BpmnModel bpmnModel;
protected String taskId;
protected String targetNodeId;

public BackToHisApprovalNodeCmd(RuntimeService runtimeService, String taskId, String targetNodeId) {
this.runtimeService = runtimeService;
this.taskId = taskId;
this.targetNodeId = targetNodeId;
}

@Override
public String execute(CommandContext commandContext) {

@@ -60,28 +63,30 @@ public class BackToHisApprovalNodeCmd implements Command<String>, Serializable {
String sourceNodeId = task.getTaskDefinitionKey();
String processInstanceId = task.getProcessInstanceId();
String processDefinitionId = task.getProcessDefinitionId();

//获取流程定义
Process process = ProcessDefinitionUtil.getProcess(processDefinitionId);
FlowNode sourceFlowElement = (FlowNode) process.getFlowElement(sourceNodeId, true);

// 传节点定义key 获取当前节点
FlowNode sourceFlowElement = (FlowNode) bpmnModel.getFlowElement(sourceNodeId);

// 只支持从用户任务退回
if (!(sourceFlowElement instanceof UserTask)) {
throw new FlowableException("只能从审批节点进行回退");
}
FlowNode targetFlowElement = (FlowNode) process.getFlowElement(targetNodeId, true);
FlowNode targetFlowElement = (FlowNode) bpmnModel.getFlowElement(targetNodeId);
// 退回节点到当前节点不可达到,不允许退回
if (!ExecutionGraphUtil.isReachable(processDefinitionId, targetNodeId, sourceNodeId)) {
throw new FlowableException("无法回退到目标节点");
}
//目标节点如果相对当前节点是在子流程内部,则无法直接退回,目前处理是只能退回到子流程开始节点

// 目标节点如果相对当前节点是在子流程内部,则无法直接退回,目前处理是只能退回到子流程开始节点
String[] sourceAndTargetRealActivityId = FlowableUtils.getSourceAndTargetRealActivityId(sourceFlowElement, targetFlowElement);
// 实际应操作的当前节点ID
String sourceRealActivityId = sourceAndTargetRealActivityId[0];

//// 实际应操作的目标节点ID
//String targetRealActivityId = sourceAndTargetRealActivityId[1];

// 实际应操作的目标节点的发起人ID
String targetRealActivityId = sourceAndTargetRealActivityId[0];
// 实际应操作的目标节点ID
String targetRealActivityId = sourceAndTargetRealActivityId[1];

Map<String, Set<String>> specialGatewayNodes = FlowableUtils.getSpecialGatewayElements(process);
// 当前节点处在的并行网关list
@@ -146,10 +151,6 @@ public class BackToHisApprovalNodeCmd implements Command<String>, Serializable {
if (targetRealSpecialGateway != null) {
createTargetInSpecialGatewayEndExecutions(commandContext, realExecutions, process, targetInSpecialGatewayList, targetRealSpecialGateway);
}
// TODO 调用原生的execute方法 在流程实例表中END_ACT_ID添加对应的字段标识
Map<String, Object> var = new HashMap<>(16);
var.put("approve_" + task.getId(), ProcessHandlerEnum.BACK);
taskService.complete(task.getId(), var);
return targetRealActivityId;
}



+ 267
- 134
pmapi/src/main/java/com/ningdatech/pmapi/todocenter/manage/TodoCenterManage.java Vedi File

@@ -1,19 +1,13 @@
package com.ningdatech.pmapi.todocenter.manage;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.xxpt.gateway.shared.api.request.OapiMessageWorkNotificationRequest;
import com.alibaba.xxpt.gateway.shared.api.response.OapiMessageWorkNotificationResponse;
import com.alibaba.xxpt.gateway.shared.client.http.ExecutableClient;
import com.alibaba.xxpt.gateway.shared.client.http.IntelligentGetClient;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ningdatech.basic.enumeration.Status;
import com.ningdatech.basic.exception.BizException;
import com.ningdatech.basic.model.PageVo;
@@ -38,6 +32,7 @@ import com.ningdatech.pmapi.todocenter.extension.cmd.BackToHisApprovalNodeCmd;
import com.ningdatech.pmapi.todocenter.extension.cmd.SaveCommentCmd;
import com.ningdatech.pmapi.todocenter.model.dto.req.ReqProcessHandlerDTO;
import com.ningdatech.pmapi.todocenter.model.dto.req.ReqToBeProcessedDTO;
import com.ningdatech.pmapi.todocenter.model.dto.req.ReqToBeProcessedExportDTO;
import com.ningdatech.pmapi.todocenter.model.dto.res.ResToBeProcessedDTO;
import com.ningdatech.pmapi.todocenter.zwdd.model.MessageContent;
import com.ningdatech.pmapi.todocenter.zwdd.model.MessageText;
@@ -64,18 +59,18 @@ import com.wflow.workflow.bean.vo.ProcessTaskVo;
import com.wflow.workflow.config.WflowGlobalVarDef;
import com.wflow.workflow.enums.ProcessHandlerEnum;
import com.wflow.workflow.service.FormService;
import com.wflow.workflow.service.*;
import com.wflow.workflow.service.ProcessModelService;
import com.wflow.workflow.service.ProcessNodeCatchService;
import com.wflow.workflow.service.UserDeptOrLeaderService;
import com.wflow.workflow.utils.Executor;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.assertj.core.util.Maps;
import org.flowable.bpmn.model.Process;
import org.flowable.bpmn.model.*;
import org.flowable.engine.*;
import org.flowable.engine.history.HistoricActivityInstance;
import org.flowable.engine.history.HistoricProcessInstance;
import org.flowable.engine.history.HistoricProcessInstanceQuery;
import org.flowable.engine.impl.util.ProcessDefinitionUtil;
import org.flowable.engine.runtime.ActivityInstance;
import org.flowable.engine.runtime.Execution;
import org.flowable.engine.task.Comment;
@@ -95,8 +90,9 @@ import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

import static com.ningdatech.pmapi.todocenter.constant.WorkNotice.PASS_MSG_TEMPLATE;
import static com.ningdatech.pmapi.todocenter.constant.WorkNotice.PASS_MSG_TEMPLATE2;
import static cn.hutool.core.collection.CollUtil.isEmpty;
import static cn.hutool.core.collection.CollUtil.isNotEmpty;
import static com.ningdatech.pmapi.todocenter.constant.WorkNotice.*;

/**
* @author CMM
@@ -122,8 +118,8 @@ public class TodoCenterManage {
private final IUserInfoService userInfoService;
private final IProjectService projectService;
private final StateMachineUtils stateMachineUtils;
@Resource(name = "executableClient")
private ExecutableClient client;
// @Resource(name = "executableClient")
// private ExecutableClient client;

/**
* 待办中心待我处理项目列表查询
@@ -144,6 +140,15 @@ public class TodoCenterManage {
taskQuery.active().taskCandidateOrAssigned(String.valueOf(userId)).orderByTaskCreateTime().desc();
List<Task> taskList = taskQuery.list();
List<Project> results = getToBeProcessedProjects(param, taskList);
// 总数
int total = results.size();
// 获取传入的分页参数
Integer pageNumber = param.getPageNumber();
Integer pageSize = param.getPageSize();
List<Project> records = results.stream()
.skip((long) (pageNumber - 1) * pageSize)
.limit(pageSize)
.collect(Collectors.toList());

Map<String, Task> taskMap = taskList.stream()
.collect(Collectors.toMap(Task::getProcessInstanceId, t -> t));
@@ -153,13 +158,13 @@ public class TodoCenterManage {

Set<String> staterUsers = new HashSet<>();
// 将申报项目待登录用户处理的流程实例一次性取出来,减少查询次数
Map<String, HistoricProcessInstance> instanceMap = CollectionUtil.isNotEmpty(taskList)
Map<String, HistoricProcessInstance> instanceMap = isNotEmpty(taskList)
? historyService.createHistoricProcessInstanceQuery()
.processInstanceIds(processInsIds).list().stream()
.collect(Collectors.toMap(HistoricProcessInstance::getId, v -> v))
: new HashMap<>();

List<ResToBeProcessedDTO> resVos = results.stream().map(d -> {
List<ResToBeProcessedDTO> resVos = records.stream().map(d -> {
ResToBeProcessedDTO res = new ResToBeProcessedDTO();
BeanUtils.copyProperties(d, res);
res.setProjectId(d.getId());
@@ -185,17 +190,19 @@ public class TodoCenterManage {
return res;
}).collect(Collectors.toList());
// 取用户信息,减少数据库查询,一次构建
List<ResToBeProcessedDTO> result = null;
if (CollectionUtil.isNotEmpty(staterUsers)) {
if (isNotEmpty(staterUsers)) {
Map<String, OrgUser> userMap = userDeptOrLeaderService.getUserMapByIds(staterUsers);
result = resVos.stream()
resVos.stream()
.peek(v -> v.getProcessTaskInfo().setOwner(userMap.get(v.getProcessTaskInfo().getOwnerId())))
.collect(Collectors.toList());
// Map<Long,UserInfo> userMap = userInfoService.getUserMapByIds(staterUsers);
// result = resVos.stream().peek(v -> v.setOwner(userMap.get(userId)))
// .collect(Collectors.toList());
}
return PageVo.of(result, result.size());
if (isEmpty(resVos)) {
return PageVo.empty();
}
return PageVo.of(resVos, total);
}

/**
@@ -207,7 +214,7 @@ public class TodoCenterManage {
* @author CMM
* @since 2023/02/01
*/
public void exportPendingProjectList(HttpServletResponse response, ReqToBeProcessedDTO param) {
public void exportPendingProjectList(HttpServletResponse response, ReqToBeProcessedExportDTO param) {
param.setPageNumber(1);
param.setPageSize(10000);
// 获取登录用户ID
@@ -218,8 +225,9 @@ public class TodoCenterManage {
TaskQuery taskQuery = taskService.createTaskQuery();
taskQuery.active().taskCandidateOrAssigned(String.valueOf(userId)).orderByTaskCreateTime().desc();
List<Task> taskList = taskQuery.list();
List<Project> records = getToBeProcessedProjects(param, taskList);

ReqToBeProcessedDTO reqToBeProcessedDTO = new ReqToBeProcessedDTO();
BeanUtils.copyProperties(param, reqToBeProcessedDTO);
List<Project> records = getToBeProcessedProjects(reqToBeProcessedDTO, taskList);
ExcelExportWriter excelExportWriter = new ExcelExportWriter();

String fileName = null;
@@ -269,7 +277,6 @@ public class TodoCenterManage {
* @since 2023/02/11
*/
private List<Project> getToBeProcessedProjects(ReqToBeProcessedDTO param, List<Task> taskList) {
Page<Project> page = param.page();
LambdaQueryWrapper<Project> wrapper = Wrappers.lambdaQuery(Project.class);
wrapper.like(StrUtil.isNotBlank(param.getProjectName()), Project::getProjectName, param.getProjectName())
.like(StrUtil.isNotBlank(param.getBuildUnitName()), Project::getBuildOrgName, param.getBuildUnitName())
@@ -278,12 +285,13 @@ public class TodoCenterManage {
.ge(Objects.nonNull(param.getProcessLaunchStartTime()), Project::getBeginTime,
param.getProcessLaunchStartTime())
.le(Objects.nonNull(param.getProcessLaunchEndTime()), Project::getEndTime, param.getProcessLaunchEndTime());
projectService.page(page, wrapper);
List<Project> results = projectService.list(wrapper);

List<String> taskProcessInsIds = taskList.stream().map(Task::getProcessInstanceId).collect(Collectors.toList());


// 过滤申报项目中待登录用户审核的项目
return page.getRecords().stream().filter(w -> taskProcessInsIds.contains(w.getInstCode()))
return results.stream().filter(w -> taskProcessInsIds.contains(w.getInstCode()))
.collect(Collectors.toList());
}

@@ -301,12 +309,12 @@ public class TodoCenterManage {

// Long userId = LoginUserUtil.getUserId();

Long userId = 381496L;

// Long userId = 381496L;
// Long userId = 6418616L;
Long userId = 61769799L;

// 若进行的是撤回操作(流程发起人和当前流程审核人的前一个审核人操作)
if (param.getAction().equals(ProcessHandlerEnum.WITHDRAW)){
if (param.getAction().equals(ProcessHandlerEnum.WITHDRAW)) {
HistoricTaskInstance handledTaskInstance = historyService.createHistoricTaskInstanceQuery().taskId(param.getTaskId()).singleResult();
doWithDrawProcess(handledTaskInstance, userId);
return;
@@ -375,13 +383,14 @@ public class TodoCenterManage {
// TODO 中止流程并使项目进入对应状态,给项目创建人、流程发起人发送浙政钉工作通知:【项目名称】的【流程名称】被驳回,请及时处理。
// sendWorkNoticeToStartUser(task, projectName, rootNode);

// 更新项目状态
updateRejectProjectStatus(userId,declaredProject);
// 更新项目状态和流程状态
updateRejectProjectStatus(userId, declaredProject);
taskService.complete(param.getTaskId(), var);
}

/**
* 当为驳回操作时,更新项目表中的项目状态
*
* @param userId
* @param declaredProject
* @return void
@@ -400,7 +409,10 @@ public class TodoCenterManage {
} catch (Exception e) {
throw new BizException("状态机执行失败!");
}
// 更新项目状态到下一个状态
// 更新流程状态、项目状态到下一个状态
declaredProject.setProcessStatus(ProcessStatusEnum.BE_REJECTED.getCode());
declaredProject.setUpdateOn(LocalDateTime.now());
declaredProject.setUpdateBy(userId);
projectService.updateById(declaredProject);
}

@@ -466,23 +478,39 @@ public class TodoCenterManage {
managementService.executeCommand(new SaveCommentCmd(param.getTaskId(), param.getInstanceId(),
String.valueOf(userId), JSONObject.toJSONString(param.getAuditInfo())));
}
// 如果流程状态是被退回状态,流程通过后,当前审核人一定不是最后一个审核人(至多是最后一个),更新流程状态为审核中
if (ProcessStatusEnum.BE_BACKED.getCode().equals(declaredProject.getProcessStatus())) {
// 通过该任务,流程到下一审核人处
taskService.complete(param.getTaskId(), var);
// 更新流程状态为审核中
declaredProject.setProcessStatus(ProcessStatusEnum.UNDER_REVIEW.getCode());
declaredProject.setUpdateOn(LocalDateTime.now());
declaredProject.setUpdateBy(userId);
projectService.updateById(declaredProject);
// 获取此时待审核任务
Task currentTask = taskService.createTaskQuery().processInstanceId(processInstanceId).singleResult();
// 获取审核人信息,向审核人发送工作通知
String currentUserId = currentTask.getAssignee();
// UserInfo auditUserInfo = userInfoService.getById(Long.valueOf(currentUserId));
// TODO 获取浙政钉用户dingKey,向其发送浙政钉工作通知
String msg = String.format(PASS_MSG_TEMPLATE, null, projectName);
// sendWorkNotice(auditUserInfo,msg);
return;
}
// 获取bpm对象
BpmnModel bpmnModel = repositoryService.getBpmnModel(task.getProcessDefinitionId());
// 传节点定义key 获取当前节点
// 若不是被退回项目,传节点定义key 获取当前节点
FlowNode currentNode = (FlowNode) bpmnModel.getFlowElement(task.getTaskDefinitionKey());


// TODO 若当前流程是预审流程,需要在提交预审申报的时候,调用状态机判断申报后的项目状态,
// 若是省级部门联审中,要对接外部接口,获取省级部门联审的结果,更新项目状态(预审申报提交的时候处理)

// 需要先通过后才能有下一个节点的信息
taskService.complete(param.getTaskId(), var);

// 获取流程下一个节点的审核用户ID
String nextUserId = getNextUserId(currentNode, processInstanceId);
// 获取当前流程状态
// 获取当前项目状态
Integer status = declaredProject.getStatus();
// 若当前登录用户是最后一个审批人
// 若当前登录用户是最后一个审批人,需更新流程状态为审核完成,项目状态到下个状态
HistoricProcessInstance instance = historyService
.createHistoricProcessInstanceQuery()
.processInstanceId(processInstanceId)
@@ -491,13 +519,13 @@ public class TodoCenterManage {
switch (Objects.requireNonNull(ProjectStatusEnum.getValue(status))) {
// 当前项目状态是单位内部审核中
case UNDER_INTERNAL_AUDIT:
// 当前项目状态是预审中
// 当前项目状态是预审中
case PRE_APPLYING:
// 当前项目状态是部门联审中
// 当前项目状态是部门联审中
case DEPARTMENT_JOINT_REVIEW:
// 当前项目状态是方案评审中
// 当前项目状态是方案评审中
case SCHEME_UNDER_REVIEW:
// 当前项目状态是终验审核中
// 当前项目状态是终验审核中
case FINAL_ACCEPTANCE_IS_UNDER_REVIEW:
updatePassProjectStatus(userId, declaredProject);
break;
@@ -516,12 +544,13 @@ public class TodoCenterManage {
// TODO 向其发送浙政钉工作通知 获取根节点的孩子节点(即发起人节点),向其发送浙政钉工作通知
// 获取根节点即流程发起节点
// FlowNode rootNode = (FlowNode) bpmnModel.getFlowElement("root");
// sendWorkNoticeToStartUser(task, projectName, rootNode);
// sendPassWorkNoticeToStartUser(task, projectName, rootNode);
}
}

/**
* 当为通过操作时,更新项目表中项目状态
*
* @param userId
* @param declaredProject
* @return void
@@ -540,7 +569,10 @@ public class TodoCenterManage {
} catch (Exception e) {
throw new BizException("状态机执行失败!");
}
// 更新项目状态到下一个状态
// 更新流程状态、项目状态到下一个状态
declaredProject.setProcessStatus(ProcessStatusEnum.APPROVED.getCode());
declaredProject.setUpdateOn(LocalDateTime.now());
declaredProject.setUpdateBy(userId);
projectService.updateById(declaredProject);
}

@@ -554,7 +586,7 @@ public class TodoCenterManage {
* @author CMM
* @since 2023/02/03
*/
private void sendWorkNoticeToStartUser(Task task, String projectName, FlowNode rootNode) {
private void sendPassWorkNoticeToStartUser(Task task, String projectName, FlowNode rootNode) {
String startUserId = getRootUserId(rootNode, task.getProcessInstanceId());
UserInfo startUserInfo = userInfoService.getById(Long.valueOf(startUserId));
// 从历史表获取最新版本的流程
@@ -567,7 +599,7 @@ public class TodoCenterManage {
/**
* 获取流程发起节点的用户ID
*
* @param rootNode 根节点
* @param rootNode 根节点
* @param processInstanceId
* @return java.lang.String
* @author CMM
@@ -599,9 +631,9 @@ public class TodoCenterManage {
/**
* 获取当前节点的下一个节点的审核用户ID
*
* @param currentNode 当前节点
* @param currentNode 当前节点
* @param processInstanceId
* @return java.lang.String 下一个节点的浙政钉用户ID
* @return java.lang.String 下一个节点的审核用户ID
* @author CMM
* @since 2023/02/02
*/
@@ -641,7 +673,7 @@ public class TodoCenterManage {
*/
private boolean hasComment(ProcessComment comment) {
return Objects.nonNull(comment)
&& (StrUtil.isNotBlank(comment.getText()) || CollectionUtil.isNotEmpty(comment.getAttachments()));
&& (StrUtil.isNotBlank(comment.getText()) || isNotEmpty(comment.getAttachments()));
}

/**
@@ -655,38 +687,38 @@ public class TodoCenterManage {
*/
private void sendWorkNotice(UserInfo auditUserInfo, String msg) {
// TODO 获取浙政钉唯一标识
String dingKey = null;
IntelligentGetClient intelligentGetClient = client.newIntelligentGetClient(DingConstant.WORKING_NOTICE);
OapiMessageWorkNotificationRequest request = new OapiMessageWorkNotificationRequest();
// 消息体(参考下文示例消息格式)
MessageText messageText = new MessageText();
messageText.setMsgType("text");
MessageContent messageContent = new MessageContent();
messageContent.setContent(msg);
messageText.setText(messageContent);
request.setMsg(JSONUtil.toJsonStr(messageText));
// 构建唯一的消息ID
// String bizMsgId = "ZB_URGE_NOTICE_" + "_" + auditUserInfo.getDeptId() + "_" + auditUserInfo.getUserId();
// request.setBizMsgId(bizMsgId);
request.setBizMsgId(null);
// 租户id
// request.setTenantId(GovDingProperties.tenantId.toString());
request.setReceiverIds(dingKey);
// 获取结果
OapiMessageWorkNotificationResponse apiResult = intelligentGetClient.get(request);
if (!apiResult.getSuccess() || !JSONUtil.parseObj(apiResult.getContent()).getBool("success")) {
log.warn("发送工作通知失败: {}", apiResult.getContent());
throw new BizException(Status.BAD_REQUEST.toString());
}
// String dingKey = null;
// IntelligentGetClient intelligentGetClient = client.newIntelligentGetClient(DingConstant.WORKING_NOTICE);
// OapiMessageWorkNotificationRequest request = new OapiMessageWorkNotificationRequest();
// // 消息体(参考下文示例消息格式)
// MessageText messageText = new MessageText();
// messageText.setMsgType("text");
// MessageContent messageContent = new MessageContent();
//
// messageContent.setContent(msg);
// messageText.setText(messageContent);
// request.setMsg(JSONUtil.toJsonStr(messageText));
// // 构建唯一的消息ID
// // String bizMsgId = "ZB_URGE_NOTICE_" + "_" + auditUserInfo.getDeptId() + "_" + auditUserInfo.getUserId();
// // request.setBizMsgId(bizMsgId);
// request.setBizMsgId(null);
// // 租户id
// // request.setTenantId(GovDingProperties.tenantId.toString());
// request.setReceiverIds(dingKey);
// // 获取结果
// OapiMessageWorkNotificationResponse apiResult = intelligentGetClient.get(request);
// if (!apiResult.getSuccess() || !JSONUtil.parseObj(apiResult.getContent()).getBool("success")) {
// log.warn("发送工作通知失败: {}", apiResult.getContent());
// throw new BizException(Status.BAD_REQUEST.toString());
// }

}

/**
* 撤销流程处理
*
* @param handledTaskInstance 已处理的历史任务实例
* @param userId 当前登录用户ID
* @param handledTaskInstance 已处理的历史任务实例
* @param userId 当前登录用户ID
*/
private void doWithDrawProcess(HistoricTaskInstance handledTaskInstance, Long userId) {
String processInstanceId = handledTaskInstance.getProcessInstanceId();
@@ -715,17 +747,17 @@ public class TodoCenterManage {
// 判断当前登录用户是否是流程发起人
if (startUserId.equals(String.valueOf(userId))) {
// TODO 若是流程发起人点击撤回,项目回到上一个状态,并删除当前审核人对应的待办记录
// 若是流程发起人点击撤回,项目回到上一个状态,需调用状态机更新项目状态
// 若是流程发起人点击撤回,项目回到上一个状态,需调用状态机更新项目状态,流程状态更新为审核通过
switch (Objects.requireNonNull(ProjectStatusEnum.getValue(status))) {
// 当前项目状态是单位内部审核中
case UNDER_INTERNAL_AUDIT:
// 当前项目状态是预审中
// 当前项目状态是预审中
case PRE_APPLYING:
// 当前项目状态是部门联审中
// 当前项目状态是部门联审中
case DEPARTMENT_JOINT_REVIEW:
// 当前项目状态是方案评审中
// 当前项目状态是方案评审中
case SCHEME_UNDER_REVIEW:
// 当前项目状态是终验审核中
// 当前项目状态是终验审核中
case FINAL_ACCEPTANCE_IS_UNDER_REVIEW:
updateWithdrawProjectStatus(userId, declaredProject);
break;
@@ -743,12 +775,25 @@ public class TodoCenterManage {
.collect(Collectors.toList()), HisProInsEndActId.WITHDRAW)
.changeState();
} else {
// TODO 获取前一个审核节点审核人信息
// 获取当前流程待审核节点
FlowNode currentNode = (FlowNode) bpmnModel.getFlowElement(task.getTaskDefinitionKey());
SequenceFlow sequenceFlow = currentNode.getIncomingFlows().get(0);
// 获取上一个节点的activityId
String sourceRef = sequenceFlow.getSourceRef();

HistoricActivityInstance lastInstance = historyService.createHistoricActivityInstanceQuery()
.processInstanceId(task.getProcessInstanceId())
.activityId(sourceRef)
.activityType("userTask")
.finished()
.singleResult();
// 获取前一个审核节点审核人信息
String beforeUserId = lastInstance.getAssignee();

// TODO 判断前一个审核人的部门和当前登录用户的部门是否是同一个,如果是同一个才可以撤回,否则抛出异常
Boolean orgFlag = true;
if (orgFlag){
// 注意:是前一个审核人,说明此时仍在一个审核流程中,项目状态不需要改变
if (orgFlag) {
// 注意:是前一个审核人,说明此时仍在一个审核流程中,项目状态不需要改变,流程状态也不要改变,仍为审核中
// 在审核记录中移除前一个审核人提交过的审核意见
Comment comment = taskService.getProcessInstanceComments(processInstanceId).stream()
.filter(c -> c.getTaskId().equals(handledTaskInstance.getId()))
@@ -768,7 +813,7 @@ public class TodoCenterManage {
.map(Execution::getActivityId)
.collect(Collectors.toList()), handledNode.getId())
.changeState();
}else {
} else {
throw new BizException("下一个审核人和您不是同一个部门,无法撤回!");
}

@@ -778,6 +823,7 @@ public class TodoCenterManage {

/**
* 当为撤回操作时,更新项目表中的项目状态为前一个状态
*
* @param userId
* @param declaredProject
* @return void
@@ -797,6 +843,9 @@ public class TodoCenterManage {
throw new BizException("状态机执行失败!");
}
// 更新项目状态
declaredProject.setProcessStatus(ProcessStatusEnum.APPROVED.getCode());
declaredProject.setUpdateOn(LocalDateTime.now());
declaredProject.setUpdateBy(userId);
projectService.updateById(declaredProject);
}

@@ -812,19 +861,56 @@ public class TodoCenterManage {
Project declaredProject = projectService
.getOne(Wrappers.lambdaQuery(Project.class).eq(Project::getInstCode, task.getProcessInstanceId()));
String projectName = declaredProject.getProjectName();
// 获取流程定义
Process process = ProcessDefinitionUtil.getProcess(task.getProcessDefinitionId());
// 获取根节点即流程发起节点
FlowNode rootNode = (FlowNode) process.getFlowElement("root", true);
// TODO 流程变成【被退回】状态,待我处理中,为流程发起人增加一条待办记录,给项目创建人、流程发起人发送浙政钉工作通知:【项目名称】的【流程名称】被退回,请及时处理。
sendWorkNoticeToStartUser(task, projectName, rootNode);

// 保存审核意见
if (hasComment(param.getAuditInfo())) {
// 执行自定义的保存评论的功能
managementService.executeCommand(new SaveCommentCmd(param.getTaskId(), param.getInstanceId(),
String.valueOf(userId), JSONObject.toJSONString(param.getAuditInfo())));
}

// 获取bpm对象
BpmnModel bpmnModel = repositoryService.getBpmnModel(task.getProcessDefinitionId());
// 传节点定义key 获取根节点即流程发起节点
FlowNode rootNode = (FlowNode) bpmnModel.getFlowElement("root");

// TODO 流程变成【被退回】状态,待我处理中,为流程发起人增加一条待办记录,
// 执行自定义回退逻辑,回退到流程发起人
managementService
.executeCommand(new BackToHisApprovalNodeCmd(runtimeService, param.getTaskId(), rootNode.getId()));
// 注意:因为审核人有执行退回的权限,且是退回到流程发起人,说明是在同一个流程实例中,所以项目状态不需要更新
managementService.executeCommand(new BackToHisApprovalNodeCmd(runtimeService, bpmnModel, param.getTaskId(), rootNode.getId()));
runtimeService.setVariables(param.getInstanceId(),
Maps.newHashMap("approve_" + param.getTaskId(), param.getAction()));
log.info("用户[{}] 退回流程[{}] [{} -> {}]", userId, param.getInstanceId(), task.getTaskDefinitionKey(),
log.info("用户[{}] 退回流程[{}] [{} -> {}]", userId, param.getInstanceId(),
task.getTaskDefinitionKey(),
param.getTargetNode());
// 更新申报项目表中的流程状态为被退回
declaredProject.setProcessStatus(ProcessStatusEnum.BE_BACKED.getCode());
declaredProject.setUpdateOn(LocalDateTime.now());
declaredProject.setUpdateBy(userId);
projectService.updateById(declaredProject);
// TODO 给项目创建人、流程发起人发送浙政钉工作通知:【项目名称】的【流程名称】被退回,请及时处理。
// sendBackWorkNoticeToStartUser(task, projectName, rootNode);

}

/**
* 给流程发起人发送流程退回工作通知
*
* @param task
* @param projectName
* @param rootNode
* @return void
* @author CMM
* @since 2023/02/14 15:32
*/
private void sendBackWorkNoticeToStartUser(Task task, String projectName, FlowNode rootNode) {
String startUserId = getRootUserId(rootNode, task.getProcessInstanceId());
UserInfo startUserInfo = userInfoService.getById(Long.valueOf(startUserId));
// 从历史表获取最新版本的流程
WflowModels wflowModels = getLastWflowModels(task);
String formName = wflowModels.getFormName();
String msg = String.format(PASS_MSG_TEMPLATE3, projectName, formName);
sendWorkNotice(startUserInfo, msg);
}

/**
@@ -835,13 +921,27 @@ public class TodoCenterManage {
* @return 流程进度及表单详情
*/
public ProcessProgressDetailVo getProcessDetail(String nodeId, String instanceId) {
HistoricProcessInstance instance =
historyService.createHistoricProcessInstanceQuery().processInstanceId(instanceId).singleResult();
HistoricProcessInstance instance = historyService.createHistoricProcessInstanceQuery()
.processInstanceId(instanceId).singleResult();
// 取表单及表单数据
HistoricVariableInstance forms = historyService.createHistoricVariableInstanceQuery()
.processInstanceId(instanceId).variableName(WflowGlobalVarDef.WFLOW_FORMS).singleResult();
List<HistoricVariableInstance> formDatas =
historyService.createHistoricVariableInstanceQuery().processInstanceId(instanceId).list();
.processInstanceId(instanceId)
.variableName(WflowGlobalVarDef.WFLOW_FORMS)
.singleResult();
List<HistoricVariableInstance> formDatas = null;
if (nodeId.equals("undefined")) {
List<HistoricTaskInstance> historicTaskInstances = historyService.createHistoricTaskInstanceQuery().processInstanceId(instanceId).list();
formDatas = historyService
.createHistoricVariableInstanceQuery()
.executionIds(historicTaskInstances.stream().map(HistoricTaskInstance::getExecutionId).collect(Collectors.toSet()))
.processInstanceId(instanceId)
.list();
} else {
formDatas = historyService
.createHistoricVariableInstanceQuery()
.processInstanceId(instanceId)
.list();
}
// 取节点设置
HistoricVariableInstance nodeProps = historyService.createHistoricVariableInstanceQuery()
.processInstanceId(instanceId).variableName(WflowGlobalVarDef.WFLOW_NODE_PROPS).singleResult();
@@ -914,7 +1014,7 @@ public class TodoCenterManage {
.name(task.getNodeName()).user(OrgUser.builder().id(task.getUserId()).build())
.startTime(task.getCreateTime()).finishTime(task.getCreateTime()).build();
}).collect(Collectors.toList());
if (CollectionUtil.isNotEmpty(ccUsers)) {
if (isNotEmpty(ccUsers)) {
Map<String, OrgUser> userMap = userDeptOrLeaderService.getUserMapByIds(ccUsers);
ccList.stream().peek(v -> v.setUser(userMap.get(v.getUser().getId()))).collect(Collectors.toList());
}
@@ -975,7 +1075,7 @@ public class TodoCenterManage {
.approvalMode(approvalMode).auditInfo(commentsMap.get(his.getTaskId()))
.result(varMap.get("approve_" + his.getTaskId())).build();
}).collect(Collectors.toList());
if (CollectionUtil.isNotEmpty(userSet)) {
if (isNotEmpty(userSet)) {
Map<String, OrgUser> map = userDeptOrLeaderService.getUserMapByIds(userSet);
progressNodes.forEach(n -> n.setUser(map.get(n.getUser().getId())));
}
@@ -1016,18 +1116,29 @@ public class TodoCenterManage {
.collect(Collectors.toSet());
List<Project> results = getHandledProjects(param, taskProcessInsIds);

// 总数
int total = results.size();
// 获取传入的分页参数
Integer pageNumber = param.getPageNumber();
Integer pageSize = param.getPageSize();
List<Project> records = results.stream()
.skip((long) (pageNumber - 1) * pageSize)
.limit(pageSize)
.collect(Collectors.toList());


// 把已办任务实例一次性取出来,减少查询次数
Map<String, HistoricTaskInstance> taskInstanceMap = taskInstances.stream()
.collect(Collectors.toMap(HistoricTaskInstance::getProcessInstanceId, v -> v));

Map<String, HistoricProcessInstance> instanceMap = CollectionUtil.isNotEmpty(taskInstances)
Map<String, HistoricProcessInstance> instanceMap = isNotEmpty(taskInstances)
? historyService.createHistoricProcessInstanceQuery()
.processInstanceIds(taskProcessInsIds)
.list().stream().collect(Collectors.toMap(HistoricProcessInstance::getId, v -> v))
: new HashMap<>();
Set<String> staterUsers = new HashSet<>();

List<ResToBeProcessedDTO> resVos = results.stream().map(d -> {
List<ResToBeProcessedDTO> resVos = records.stream().map(d -> {

ResToBeProcessedDTO res = new ResToBeProcessedDTO();
BeanUtils.copyProperties(d, res);
@@ -1060,18 +1171,19 @@ public class TodoCenterManage {
return res;
}).collect(Collectors.toList());
// 取用户信息,减少数据库查询,一次构建
List<ResToBeProcessedDTO> result = null;
if (CollectionUtil.isNotEmpty(staterUsers)) {
if (isNotEmpty(staterUsers)) {
Map<String, OrgUser> userMap = userDeptOrLeaderService.getUserMapByIds(staterUsers);
result = resVos.stream()
resVos.stream()
.peek(v -> v.getProcessTaskInfo().setOwner(userMap.get(v.getProcessTaskInfo().getOwnerId())))
.collect(Collectors.toList());
// Map<Long,UserInfo> userMap = userInfoService.getUserMapByIds(staterUsers);
// result = resVos.stream().peek(v -> v.setOwner(userMap.get(userId)))
// .collect(Collectors.toList());

}
return PageVo.of(result, result.size());
if (isEmpty(resVos)) {
return PageVo.empty();
}
return PageVo.of(resVos, total);
}

/**
@@ -1084,8 +1196,6 @@ public class TodoCenterManage {
* @since 2023/02/11
*/
private List<Project> getHandledProjects(ReqToBeProcessedDTO param, Set<String> taskProcessInsIds) {
// 获取入参分页信息
Page<Project> page = param.page();
LambdaQueryWrapper<Project> wrapper = Wrappers.lambdaQuery(Project.class);
wrapper.like(StrUtil.isNotBlank(param.getProjectName()), Project::getProjectName, param.getProjectName())
.like(StrUtil.isNotBlank(param.getBuildUnitName()), Project::getBuildOrgName, param.getBuildUnitName())
@@ -1094,10 +1204,10 @@ public class TodoCenterManage {
.ge(Objects.nonNull(param.getProcessLaunchStartTime()), Project::getBeginTime,
param.getProcessLaunchStartTime())
.le(Objects.nonNull(param.getProcessLaunchEndTime()), Project::getEndTime, param.getProcessLaunchEndTime());
projectService.page(page, wrapper);
List<Project> results = projectService.list(wrapper);

// 过滤申报项目中登录用户已审核的项目
return page.getRecords().stream()
return results.stream()
.filter(w -> taskProcessInsIds.contains(w.getInstCode()))
.collect(Collectors.toList());
}
@@ -1111,7 +1221,7 @@ public class TodoCenterManage {
* @author CMM
* @since 2023/02/06
*/
public void exportHandledProjectList(HttpServletResponse response, ReqToBeProcessedDTO param) {
public void exportHandledProjectList(HttpServletResponse response, ReqToBeProcessedExportDTO param) {
param.setPageNumber(1);
param.setPageSize(10000);
// 获取登录用户ID
@@ -1129,7 +1239,9 @@ public class TodoCenterManage {
Set<String> taskProcessInsIds = taskInstances.stream()
.map(HistoricTaskInstance::getProcessInstanceId)
.collect(Collectors.toSet());
List<Project> records = getHandledProjects(param, taskProcessInsIds);
ReqToBeProcessedDTO reqToBeProcessedDTO = new ReqToBeProcessedDTO();
BeanUtils.copyProperties(param, reqToBeProcessedDTO);
List<Project> records = getHandledProjects(reqToBeProcessedDTO, taskProcessInsIds);

ExcelExportWriter excelExportWriter = new ExcelExportWriter();

@@ -1188,20 +1300,30 @@ public class TodoCenterManage {
List<HistoricProcessInstance> historicProcessInstances =
instanceQuery.orderByProcessInstanceStartTime().desc().orderByProcessInstanceEndTime().desc().list();
Set<String> historicProcessInstanceIds =
historicProcessInstances.stream().map(h -> h.getId()).collect(Collectors.toSet());
historicProcessInstances.stream().map(HistoricProcessInstance::getId).collect(Collectors.toSet());

List<Project> results = getMySubmittedProjects(param, historicProcessInstanceIds);

// 总数
int total = results.size();
// 获取传入的分页参数
Integer pageNumber = param.getPageNumber();
Integer pageSize = param.getPageSize();
List<Project> records = results.stream()
.skip((long) (pageNumber - 1) * pageSize)
.limit(pageSize)
.collect(Collectors.toList());

// 把已办任务流程实例一次性取出来,减少查询次数
Map<String, HistoricProcessInstance> instanceMap = CollectionUtil.isNotEmpty(historicProcessInstances) ? historyService
Map<String, HistoricProcessInstance> instanceMap = isNotEmpty(historicProcessInstances) ? historyService
.createHistoricProcessInstanceQuery()
.processInstanceIds(historicProcessInstances.stream().map(h -> h.getId()).collect(Collectors.toSet()))
.processInstanceIds(historicProcessInstances.stream().map(HistoricProcessInstance::getId).collect(Collectors.toSet()))
.list().stream().collect(Collectors.toMap(HistoricProcessInstance::getId, v -> v)) : new HashMap<>();

Set<String> staterUsers = new HashSet<>();

List<ResToBeProcessedDTO> resVos =
results.stream().map(d -> {
records.stream().map(d -> {
ResToBeProcessedDTO res = new ResToBeProcessedDTO();
BeanUtils.copyProperties(d, res);
res.setProjectId(d.getId());
@@ -1218,7 +1340,7 @@ public class TodoCenterManage {
return res;
}).collect(Collectors.toList());

if (CollectionUtil.isNotEmpty(staterUsers)) {
if (isNotEmpty(staterUsers)) {
Map<String, OrgUser> userMap = userDeptOrLeaderService.getUserMapByIds(staterUsers);
resVos.stream().map(v -> {
v.getProcessInstanceInfo().setStaterUser(userMap.get(v.getProcessInstanceInfo().getStaterUserId()));
@@ -1231,7 +1353,7 @@ public class TodoCenterManage {
// resVos.stream().peek(v -> v.setOwner(userMap.get(startUserId)))
// .collect(Collectors.toList());
// }
return PageVo.of(resVos, resVos.size());
return PageVo.of(resVos, total);
}

/**
@@ -1244,7 +1366,6 @@ public class TodoCenterManage {
* @since 2023/02/11
*/
private List<Project> getMySubmittedProjects(ReqToBeProcessedDTO param, Set<String> historicProcessInstanceIds) {
Page<Project> page = param.page();
LambdaQueryWrapper<Project> wrapper = Wrappers.lambdaQuery(Project.class);
wrapper.like(StrUtil.isNotBlank(param.getProjectName()), Project::getProjectName, param.getProjectName())
.like(StrUtil.isNotBlank(param.getBuildUnitName()), Project::getBuildOrgName, param.getBuildUnitName())
@@ -1253,13 +1374,12 @@ public class TodoCenterManage {
.ge(Objects.nonNull(param.getProcessLaunchStartTime()), Project::getBeginTime,
param.getProcessLaunchStartTime())
.le(Objects.nonNull(param.getProcessLaunchEndTime()), Project::getEndTime, param.getProcessLaunchEndTime());
projectService.page(page, wrapper);
List<Project> results = projectService.list(wrapper);

// 筛选出申报项目中我发起的项目
List<Project> results = page.getRecords().stream()
return results.stream()
.filter(d -> historicProcessInstanceIds.contains(d.getInstCode()))
.collect(Collectors.toList());
return results;
}

/**
@@ -1294,7 +1414,7 @@ public class TodoCenterManage {
List<Task> list =
taskService.createTaskQuery().processInstanceId(ist.getId()).includeIdentityLinks().active().list();
instanceVo.setNodeId(Optional.ofNullable(instanceVo.getNodeId()).orElseGet(() -> {
if (CollectionUtil.isNotEmpty(list)) {
if (isNotEmpty(list)) {
return list.get(0).getTaskDefinitionKey();
}
return null;
@@ -1322,7 +1442,7 @@ public class TodoCenterManage {
* @author CMM
* @since 2023/02/11
*/
public void exportMySubmittedProjectList(HttpServletResponse response, ReqToBeProcessedDTO param) {
public void exportMySubmittedProjectList(HttpServletResponse response, ReqToBeProcessedExportDTO param) {

param.setPageNumber(1);
param.setPageSize(10000);
@@ -1337,7 +1457,9 @@ public class TodoCenterManage {
Set<String> historicProcessInstanceIds = historicProcessInstances.stream()
.map(h -> h.getId())
.collect(Collectors.toSet());
List<Project> records = getMySubmittedProjects(param, historicProcessInstanceIds);
ReqToBeProcessedDTO reqToBeProcessedDTO = new ReqToBeProcessedDTO();
BeanUtils.copyProperties(param, reqToBeProcessedDTO);
List<Project> records = getMySubmittedProjects(reqToBeProcessedDTO, historicProcessInstanceIds);

ExcelExportWriter excelExportWriter = new ExcelExportWriter();

@@ -1400,15 +1522,25 @@ public class TodoCenterManage {

List<Project> results = getCcMeProjects(param, processInsIds);

// 总数
int total = results.size();
// 获取传入的分页参数
Integer pageNumber = param.getPageNumber();
Integer pageSize = param.getPageSize();
List<Project> records = results.stream()
.skip((long) (pageNumber - 1) * pageSize)
.limit(pageSize)
.collect(Collectors.toList());

Set<String> staterUsers = new HashSet<>();
// 将抄送我的流程实例一次性取出来,减少查询次数
Map<String, HistoricProcessInstance> instanceMap = CollectionUtil.isNotEmpty(ccTasks)
Map<String, HistoricProcessInstance> instanceMap = isNotEmpty(ccTasks)
? historyService.createHistoricProcessInstanceQuery()
.processInstanceIds(ccTasks.stream().map(WflowCcTasks::getInstanceId).collect(Collectors.toSet()))
.list().stream().collect(Collectors.toMap(HistoricProcessInstance::getId, v -> v))
: new HashMap<>();
List<ResToBeProcessedDTO> resVos =
results.stream().map(d -> {
records.stream().map(d -> {
ResToBeProcessedDTO res = new ResToBeProcessedDTO();
BeanUtils.copyProperties(d, res);
res.setProjectId(d.getId());
@@ -1425,7 +1557,7 @@ public class TodoCenterManage {
return res;
}).collect(Collectors.toList());

if (CollectionUtil.isNotEmpty(staterUsers)) {
if (isNotEmpty(staterUsers)) {
Map<String, OrgUser> userMap = userDeptOrLeaderService.getUserMapByIds(staterUsers);
resVos.stream().map(v -> {
v.getProcessInstanceInfo().setStaterUser(userMap.get(v.getProcessInstanceInfo().getStaterUserId()));
@@ -1438,7 +1570,7 @@ public class TodoCenterManage {
// resVos.stream().peek(v -> v.setOwner(userMap.get(startUserId)))
// .collect(Collectors.toList());
// }
return PageVo.of(resVos, resVos.size());
return PageVo.of(resVos, total);
}

/**
@@ -1451,7 +1583,6 @@ public class TodoCenterManage {
* @since 2023/02/11
*/
private List<Project> getCcMeProjects(ReqToBeProcessedDTO param, List<String> processInsIds) {
Page<Project> page = param.page();
LambdaQueryWrapper<Project> wrapper = Wrappers.lambdaQuery(Project.class);
wrapper.like(StrUtil.isNotBlank(param.getProjectName()), Project::getProjectName, param.getProjectName())
.like(StrUtil.isNotBlank(param.getBuildUnitName()), Project::getBuildOrgName, param.getBuildUnitName())
@@ -1460,9 +1591,9 @@ public class TodoCenterManage {
.ge(Objects.nonNull(param.getProcessLaunchStartTime()), Project::getBeginTime,
param.getProcessLaunchStartTime())
.le(Objects.nonNull(param.getProcessLaunchEndTime()), Project::getEndTime, param.getProcessLaunchEndTime());
projectService.page(page, wrapper);
List<Project> results = projectService.list(wrapper);

return page.getRecords().stream()
return results.stream()
.filter(d -> processInsIds.contains(d.getInstCode()))
.collect(Collectors.toList());
}
@@ -1476,7 +1607,7 @@ public class TodoCenterManage {
* @author CMM
* @since 2023/02/11
*/
public void exportCcMeProjectList(HttpServletResponse response, ReqToBeProcessedDTO param) {
public void exportCcMeProjectList(HttpServletResponse response, ReqToBeProcessedExportDTO param) {

param.setPageNumber(1);
param.setPageSize(10000);
@@ -1490,7 +1621,9 @@ public class TodoCenterManage {
.map(WflowCcTasks::getInstanceId)
.collect(Collectors.toList());

List<Project> records = getCcMeProjects(param, processInsIds);
ReqToBeProcessedDTO reqToBeProcessedDTO = new ReqToBeProcessedDTO();
BeanUtils.copyProperties(param, reqToBeProcessedDTO);
List<Project> records = getCcMeProjects(reqToBeProcessedDTO, processInsIds);

ExcelExportWriter excelExportWriter = new ExcelExportWriter();



+ 1
- 5
pmapi/src/main/java/com/ningdatech/pmapi/todocenter/model/dto/req/ReqToBeProcessedDTO.java Vedi File

@@ -15,7 +15,7 @@ import lombok.NoArgsConstructor;
import javax.validation.constraints.NotNull;

/**
* 待办中心-待我处理查询实体信息
* 待办中心-列表查询实体信息
*
* @author CMM
* @since 2023/01/12 16:01
@@ -44,8 +44,4 @@ public class ReqToBeProcessedDTO extends PagePo implements Serializable {
@ApiModelProperty(value = "是否增补项目",allowableValues = "非增补项目 0,增补项目 1")
@NotNull(message = "是否增补字段不能为空!")
private Integer isSupplement;

@ApiModelProperty("导出选项")
private List<ExportOptionEnum> exportOptionList;

}

+ 52
- 0
pmapi/src/main/java/com/ningdatech/pmapi/todocenter/model/dto/req/ReqToBeProcessedExportDTO.java Vedi File

@@ -0,0 +1,52 @@
package com.ningdatech.pmapi.todocenter.model.dto.req;

import java.io.Serializable;
import java.time.LocalDateTime;
import java.util.List;

import javax.validation.constraints.NotNull;

import com.ningdatech.basic.model.PagePo;
import com.ningdatech.pmapi.common.enumeration.ExportOptionEnum;

import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
* 待办中心-导出查询实体信息
*
* @author CMM
* @since 2023/01/12 16:01
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class ReqToBeProcessedExportDTO extends PagePo implements Serializable {
private static final long serialVersionUID = 1L;

@ApiModelProperty("项目名称")
private String projectName;

@ApiModelProperty("申报单位名称")
private String buildUnitName;

@ApiModelProperty("预算年度")
private Integer projectYear;

@ApiModelProperty("流程发起开始时间")
private LocalDateTime processLaunchStartTime;

@ApiModelProperty("流程发起结束时间")
private LocalDateTime processLaunchEndTime;

@ApiModelProperty(value = "是否增补项目",allowableValues = "非增补项目 0,增补项目 1")
@NotNull(message = "是否增补字段不能为空!")
private Integer isSupplement;

@ApiModelProperty("导出选项")
@NotNull(message = "导出选项不能为空")
private List<ExportOptionEnum> exportOptionList;

}

+ 30
- 0
pmapi/src/main/java/com/ningdatech/pmapi/user/constant/LoginTypeEnum.java Vedi File

@@ -0,0 +1,30 @@
package com.ningdatech.pmapi.user.constant;

import io.swagger.annotations.ApiModel;
import lombok.AllArgsConstructor;
import lombok.Getter;

/**
* @author liuxinxin
* @date 2022/8/17 下午5:55
*/
@AllArgsConstructor
@Getter
@ApiModel("登陆类型")
public enum LoginTypeEnum {
/**
* 浙政钉扫码登陆
*/
DING_QR_LOGIN,

/**
* 手机号验证码登陆
*/
PHONE_VERIFICATION_CODE_LOGIN,

/**
* 账号密码登陆
*/
USERNAME_PASSWORD_LOGIN;

}

+ 0
- 20
pmapi/src/main/java/com/ningdatech/pmapi/user/controller/NdUserAuthController.java Vedi File

@@ -1,20 +0,0 @@
package com.ningdatech.pmapi.user.controller;


import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.stereotype.Controller;

/**
* <p>
* 前端控制器
* </p>
*
* @author Lierbao
* @since 2023-02-01
*/
@Controller
@RequestMapping("/pmapi.user/nd-user-auth")
public class NdUserAuthController {

}

+ 0
- 20
pmapi/src/main/java/com/ningdatech/pmapi/user/controller/NdUserInfoController.java Vedi File

@@ -1,20 +0,0 @@
package com.ningdatech.pmapi.user.controller;


import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

/**
* <p>
* 前端控制器
* </p>
*
* @author Lierbao
* @since 2023-02-01
*/
@Controller
@RequestMapping("/pmapi.user/nd-user-info")
public class NdUserInfoController {


}

+ 9
- 6
pmapi/src/main/java/com/ningdatech/pmapi/user/controller/UserAuthController.java Vedi File

@@ -36,13 +36,16 @@ public class UserAuthController {

private final ObjectMapper objectMapper;

@PostMapping(value = "/login/password", consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
@ApiOperation(value = "账号密码的登陆方式")
@PostMapping(value = "/login", consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
@ApiOperation(value = "登陆")
@ApiImplicitParams({
@ApiImplicitParam(name = "username", value = "用户名", required = true, paramType = "form", dataType = "String"),
@ApiImplicitParam(name = "password", value = "密码", required = true, paramType = "form", dataType = "String")})
public void loginByUsernameAndPassword(@RequestParam("username") String username,
@RequestParam("password") String password) {
@ApiImplicitParam(name = "identifier", value = "账号", required = true, paramType = "form", dataType = "String"),
@ApiImplicitParam(name = "credential", value = "凭证", required = true, paramType = "form", dataType = "String"),
@ApiImplicitParam(name = "loginType", value = "DING_QR_LOGIN 浙政钉扫码登陆,PHONE_VERIFICATION_CODE_LOGIN 手机号验证码登陆"
, required = true, paramType = "form", dataType = "String")})
public void loginByUsernameAndPassword(@RequestParam(value = "identifier",required = false) String identifier,
@RequestParam(value = "credential",required = false) String credential,
@RequestParam("loginType") String loginType) {
// 不实现任何内容,只是为了出api文档
}



+ 16
- 1
pmapi/src/main/java/com/ningdatech/pmapi/user/controller/UserInfoController.java Vedi File

@@ -3,8 +3,10 @@ package com.ningdatech.pmapi.user.controller;

import com.ningdatech.basic.model.PageVo;
import com.ningdatech.pmapi.user.manage.UserInfoManage;
import com.ningdatech.pmapi.user.model.po.ReqUserDetailEditPO;
import com.ningdatech.pmapi.user.model.po.ReqUserDisablePO;
import com.ningdatech.pmapi.user.model.po.ReqUserInfoListPO;
import com.ningdatech.pmapi.user.model.vo.ResUserDetailVO;
import com.ningdatech.pmapi.user.model.vo.ResUserInfoListVO;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
@@ -40,8 +42,21 @@ public class UserInfoController {

@ApiOperation(value = "用户禁用", notes = "用户禁用")
@PostMapping("/disable")
public void disable(@Valid @RequestBody ReqUserDisablePO reqUserDisablePO){
public void disable(@Valid @RequestBody ReqUserDisablePO reqUserDisablePO) {
userInfoManage.disable(reqUserDisablePO);
}

@ApiOperation(value = "用户详情", notes = "用户详情")
@PostMapping("/detail")
public ResUserDetailVO userInfoDetail(@Valid @RequestBody ReqUserInfoListPO reqUserInfoListPO) {
return userInfoManage.userInfoDetail(reqUserInfoListPO);
}

@ApiOperation(value = "用户详情编辑", notes = "用户详情编辑")
@PostMapping("/detail/edit")
public void userInfoDetailEdit(@Valid @RequestBody ReqUserDetailEditPO reqUserDetailEditPO) {
userInfoManage.userInfoDetailEdit(reqUserDetailEditPO);
}


}

+ 38
- 0
pmapi/src/main/java/com/ningdatech/pmapi/user/manage/UserAuthLoginManage.java Vedi File

@@ -18,6 +18,12 @@ public class UserAuthLoginManage {
private final IUserAuthService iUserAuthService;
private final IUserInfoService iUserInfoService;

/**
* 根据用户名获取
*
* @param username
* @return
*/
public UserFullInfoDTO queryUserInfoInPasswordAuth(String username) {
UserFullInfoDTO userFullInfoDTO = new UserFullInfoDTO();
userFullInfoDTO.setCompanyId(1L);
@@ -27,4 +33,36 @@ public class UserAuthLoginManage {
userFullInfoDTO.setUsername("测试账号");
return userFullInfoDTO;
}

/**
* 根据手机号获取
*
* @param phoneNo
* @return
*/
public UserFullInfoDTO queryUserInfoInPhoneNoAuth(String phoneNo) {
UserFullInfoDTO userFullInfoDTO = new UserFullInfoDTO();
userFullInfoDTO.setCompanyId(1L);
userFullInfoDTO.setUserId(1L);
userFullInfoDTO.setIdentifier("123456");
userFullInfoDTO.setRealName("测试账号");
userFullInfoDTO.setUsername("测试账号");
return userFullInfoDTO;
}

/**
* 根据accountId
*
* @param accountId
* @return
*/
public UserFullInfoDTO queryUserInfoInAccountIdAuth(String accountId) {
UserFullInfoDTO userFullInfoDTO = new UserFullInfoDTO();
userFullInfoDTO.setCompanyId(1L);
userFullInfoDTO.setUserId(1L);
userFullInfoDTO.setIdentifier("123456");
userFullInfoDTO.setRealName("测试账号");
userFullInfoDTO.setUsername("测试账号");
return userFullInfoDTO;
}
}

+ 10
- 0
pmapi/src/main/java/com/ningdatech/pmapi/user/manage/UserInfoManage.java Vedi File

@@ -2,8 +2,10 @@ package com.ningdatech.pmapi.user.manage;

import com.ningdatech.basic.model.PageVo;
import com.ningdatech.pmapi.user.mapper.UserInfoMapper;
import com.ningdatech.pmapi.user.model.po.ReqUserDetailEditPO;
import com.ningdatech.pmapi.user.model.po.ReqUserDisablePO;
import com.ningdatech.pmapi.user.model.po.ReqUserInfoListPO;
import com.ningdatech.pmapi.user.model.vo.ResUserDetailVO;
import com.ningdatech.pmapi.user.model.vo.ResUserInfoListVO;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;
@@ -26,4 +28,12 @@ public class UserInfoManage {
public void disable(ReqUserDisablePO reqUserDisablePO) {

}

public ResUserDetailVO userInfoDetail(ReqUserInfoListPO reqUserInfoListPO) {
return null;
}

public void userInfoDetailEdit(ReqUserDetailEditPO reqUserDetailEditPO) {

}
}

+ 33
- 0
pmapi/src/main/java/com/ningdatech/pmapi/user/model/base/UserRoleInfo.java Vedi File

@@ -0,0 +1,33 @@
package com.ningdatech.pmapi.user.model.base;

import com.baomidou.mybatisplus.annotation.TableField;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;

import javax.validation.constraints.Size;

import static com.baomidou.mybatisplus.annotation.SqlCondition.LIKE;

/**
* @author liuxinxin
* @date 2022/8/22 下午4:12
*/
@Data
@ApiModel("用户角色信息")
public class UserRoleInfo {

@ApiModelProperty(value = "名称")
private String name;

@ApiModelProperty(value = "枚举code")
private String code;

@ApiModelProperty(value = "描述")
@Size(max = 100, message = "描述长度不能超过100")
@TableField(value = "describe", condition = LIKE)
private String describe;

@ApiModelProperty(value = "排序")
private Integer roleSort;
}

+ 29
- 0
pmapi/src/main/java/com/ningdatech/pmapi/user/model/po/ReqUserDetailEditPO.java Vedi File

@@ -0,0 +1,29 @@
package com.ningdatech.pmapi.user.model.po;

import com.ningdatech.pmapi.user.model.base.UserRoleInfo;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;

import java.util.List;

/**
* @author liuxinxin
* @date 2023/2/15 上午8:43
*/
@Data
@ApiModel("获取用户详情编辑请求")
public class ReqUserDetailEditPO {

@ApiModelProperty("userId")
private Long userId;

@ApiModelProperty("手机号")
private String phoneNo;

@ApiModelProperty("状态 启用/禁用")
private Boolean status;

@ApiModelProperty("用户角色信息列表")
private List<UserRoleInfo> userRoleInfoList;
}

+ 20
- 0
pmapi/src/main/java/com/ningdatech/pmapi/user/model/po/ReqUserDetailPO.java Vedi File

@@ -0,0 +1,20 @@
package com.ningdatech.pmapi.user.model.po;

import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;

import javax.validation.constraints.NotNull;

/**
* @author liuxinxin
* @date 2023/2/15 上午8:43
*/
@Data
@ApiModel("获取用户详情请求")
public class ReqUserDetailPO {

@NotNull(message = "用户id 不能为空")
@ApiModelProperty("用户id")
private Long userId;
}

+ 29
- 0
pmapi/src/main/java/com/ningdatech/pmapi/user/model/vo/ResUserDetailVO.java Vedi File

@@ -0,0 +1,29 @@
package com.ningdatech.pmapi.user.model.vo;

import com.ningdatech.pmapi.user.model.base.UserRoleInfo;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;

import java.util.List;

/**
* @author liuxinxin
* @date 2023/2/15 上午8:43
*/
@Data
@ApiModel("获取用户详情请求")
public class ResUserDetailVO {

@ApiModelProperty("userId")
private Long userId;

@ApiModelProperty("手机号")
private String phoneNo;

@ApiModelProperty("状态 启用/禁用")
private Boolean status;

@ApiModelProperty("用户角色信息列表")
private List<UserRoleInfo> userRoleInfoList;
}

+ 5
- 8
pmapi/src/main/java/com/ningdatech/pmapi/user/security/auth/WebSecurityConfig.java Vedi File

@@ -1,13 +1,11 @@
package com.ningdatech.pmapi.user.security.auth;

import com.google.common.collect.Lists;
import com.ningdatech.basic.util.CollUtils;
import com.ningdatech.basic.util.NdJsonUtil;
import com.ningdatech.basic.util.StrPool;
import com.ningdatech.pmapi.common.constant.BizConst;
import com.ningdatech.pmapi.common.constant.CommonConstant;
import com.ningdatech.pmapi.user.security.auth.handler.DefaultExpiredSessionStrategy;
import com.ningdatech.pmapi.user.security.auth.password.UsernamePasswordAuthSecurityConfig;
import com.ningdatech.pmapi.user.security.auth.credential.CredentialAuthSecurityConfig;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpStatus;
@@ -18,7 +16,6 @@ import org.springframework.security.web.authentication.logout.LogoutSuccessHandl
import org.springframework.security.web.csrf.CookieCsrfTokenRepository;

import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Map;
import java.util.Set;

@@ -31,16 +28,16 @@ import java.util.Set;
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

private final AuthProperties authProperties;
private final UsernamePasswordAuthSecurityConfig usernamePasswordAuthSecurityConfig;
private final CredentialAuthSecurityConfig credentialAuthSecurityConfig;
private final LogoutSuccessHandler logoutSuccessHandler;
private final DefaultExpiredSessionStrategy defaultExpiredSessionStrategy;

public WebSecurityConfig(AuthProperties authProperties,
UsernamePasswordAuthSecurityConfig usernamePasswordAuthSecurityConfig,
CredentialAuthSecurityConfig credentialAuthSecurityConfig,
@Qualifier(value = "defaultLogoutSuccessHandler") LogoutSuccessHandler logoutSuccessHandler,
DefaultExpiredSessionStrategy defaultExpiredSessionStrategy) {
this.authProperties = authProperties;
this.usernamePasswordAuthSecurityConfig = usernamePasswordAuthSecurityConfig;
this.credentialAuthSecurityConfig = credentialAuthSecurityConfig;
this.logoutSuccessHandler = logoutSuccessHandler;
this.defaultExpiredSessionStrategy = defaultExpiredSessionStrategy;
}
@@ -50,7 +47,7 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
assemblerPreAuthUrls(http);
http.formLogin()
.loginPage(authProperties.getAuthRequireUrl())
.and().apply(usernamePasswordAuthSecurityConfig)
.and().apply(credentialAuthSecurityConfig)
.and()
.authorizeRequests().antMatchers(authProperties.getIgnoreAuthUrlsArray()).permitAll().anyRequest()
.authenticated().and()


+ 11
- 0
pmapi/src/main/java/com/ningdatech/pmapi/user/security/auth/constants/UserDeatilsServiceConstant.java Vedi File

@@ -0,0 +1,11 @@
package com.ningdatech.pmapi.user.security.auth.constants;

/**
* @author liuxinxin
* @date 2023/2/14 上午11:29
*/

public class UserDeatilsServiceConstant {

public static final String USER_DETAILS_SERVICE_SEPARATOR = "@###@";
}

pmapi/src/main/java/com/ningdatech/pmapi/user/security/auth/password/PasswordLoginUserDetailService.java → pmapi/src/main/java/com/ningdatech/pmapi/user/security/auth/credential/AccountIdLoginUserDetailService.java Vedi File

@@ -1,4 +1,4 @@
package com.ningdatech.pmapi.user.security.auth.password;
package com.ningdatech.pmapi.user.security.auth.credential;


import com.ningdatech.pmapi.user.manage.UserAuthLoginManage;
@@ -16,17 +16,17 @@ import java.util.Objects;
* @date 2022/9/30 上午9:49
*/

@Service("passwordLoginUserDetailService")
@Service("accountIdLoginUserDetailService")
@RequiredArgsConstructor
public class PasswordLoginUserDetailService implements UserDetailsService {
public class AccountIdLoginUserDetailService implements UserDetailsService {

private final UserAuthLoginManage userAuthLoginManage;

@Override
public UserInfoDetails loadUserByUsername(String username) throws UsernameNotFoundException {
UserFullInfoDTO userFullInfoDTO = userAuthLoginManage.queryUserInfoInPasswordAuth(username);
public UserInfoDetails loadUserByUsername(String accountId) throws UsernameNotFoundException {
UserFullInfoDTO userFullInfoDTO = userAuthLoginManage.queryUserInfoInAccountIdAuth(accountId);
if (Objects.isNull(userFullInfoDTO)) {
throw new UsernameNotFoundException(String.format("%s user not exist", username));
throw new UsernameNotFoundException(String.format("%s user not exist", accountId));
}
UserInfoDetails userInfoDetails = new UserInfoDetails();
userInfoDetails.setUserId(userFullInfoDTO.getUserId());

+ 108
- 0
pmapi/src/main/java/com/ningdatech/pmapi/user/security/auth/credential/CredentialAuthFilter.java Vedi File

@@ -0,0 +1,108 @@
package com.ningdatech.pmapi.user.security.auth.credential;

import com.ningdatech.basic.exception.BizException;
import com.ningdatech.pmapi.user.constant.LoginTypeEnum;
import org.apache.commons.lang3.StringUtils;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.InternalAuthenticationServiceException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
* @Author LiuXinXin
* @Date 2020/8/3 8:46 下午
* @Version 1.0
**/
public class CredentialAuthFilter extends AbstractAuthenticationProcessingFilter {

private boolean postOnly = true;

private static final String IDENTIFIER_PARAMETER = "identifier";
private static final String CREDENTIAL_PARAMETER = "credential";
private static final String LOGIN_TYPE_PARAMETER = "loginType";


// ~ Constructors
// ===================================================================================================

public CredentialAuthFilter(String processingUrl) {
super(new AntPathRequestMatcher(processingUrl, HttpMethod.POST.name()));
}

// ~ Methods
// ========================================================================================================

@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
throws AuthenticationException {
if (postOnly && !request.getMethod().equals(HttpMethod.POST.name())) {
throw new AuthenticationServiceException("请求方法错误");
}
String identifier = request.getParameter(IDENTIFIER_PARAMETER);
String credential = request.getParameter(CREDENTIAL_PARAMETER);
String loginType = request.getParameter(LOGIN_TYPE_PARAMETER);
if (StringUtils.isBlank(loginType)) {
throw new BadCredentialsException("登陆类型不能为空");
}
paramValid(identifier, credential, loginType);


identifier = trim(identifier);
credential = trim(credential);
loginType = trim(loginType);
try {
CredentialAuthToken authRequest = new CredentialAuthToken(identifier, credential, loginType);
// Allow subclasses to set the "details" property
setDetails(request, authRequest);
return this.getAuthenticationManager().authenticate(authRequest);
} catch (AuthenticationException e) {
throw new BadCredentialsException("账号或密码错误");
} catch (BizException e) {
throw new BadCredentialsException(e.getMessage());
} catch (Exception e) {
throw new InternalAuthenticationServiceException("授权失败:", e);
}
}

protected void setDetails(HttpServletRequest request, CredentialAuthToken authRequest) {
authRequest.setDetails(authenticationDetailsSource.buildDetails(request));
}

private void paramValid(String identifier, String credential, String loginType) {
LoginTypeEnum loginTypeEnum = LoginTypeEnum.valueOf(loginType);
switch (loginTypeEnum) {
case DING_QR_LOGIN: {
if (StringUtils.isBlank(credential)) {
throw new BadCredentialsException("浙政钉扫码登陆 授权码 不能为空 credential");
}
}
break;
case USERNAME_PASSWORD_LOGIN: {
if (StringUtils.isBlank(identifier) || StringUtils.isBlank(credential)) {
throw new BadCredentialsException("账号密码登陆 账号密码不能为空 identifier credential");
}
}
break;
case PHONE_VERIFICATION_CODE_LOGIN: {
if (StringUtils.isBlank(identifier) || StringUtils.isBlank(credential)) {
throw new BadCredentialsException("手机号验证码登陆 手机号或验证码不能为空 identifier credential");
}
}
break;
}
}

private String trim(String trimStr) {
if (StringUtils.isNotBlank(trimStr)) {
return trimStr.trim();
}
return null;
}
}

+ 103
- 0
pmapi/src/main/java/com/ningdatech/pmapi/user/security/auth/credential/CredentialAuthProvider.java Vedi File

@@ -0,0 +1,103 @@
package com.ningdatech.pmapi.user.security.auth.credential;

import com.ningdatech.basic.model.GenericResult;
import com.ningdatech.pmapi.user.constant.LoginTypeEnum;
import com.ningdatech.pmapi.user.security.auth.constants.UserDeatilsServiceConstant;
import com.ningdatech.zwdd.client.ZwddAuthClient;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.InternalAuthenticationServiceException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.PasswordEncoder;

import java.util.Objects;

/**
* @Author LiuXinXin
* @Date 2020/8/3 8:55 下午
* @Version 1.0
**/
public class CredentialAuthProvider implements AuthenticationProvider {

private UserDetailsService userDetailsService;

private PasswordEncoder passwordEncoder;

private ZwddAuthClient zwddAuthClient;

@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
if (!(authentication instanceof CredentialAuthToken)) {
throw new RuntimeException("CustomAuthProvider 只支持 CustomAuthToken");
}
CredentialAuthToken authenticationToken = (CredentialAuthToken) authentication;
String principal = (String) authenticationToken.getPrincipal();

UserDetails user = null;
LoginTypeEnum loginTypeEnum = authenticationToken.getLoginTypeEnum();
switch (loginTypeEnum) {
case DING_QR_LOGIN: {
String code = (String) authenticationToken.getCredentials();
GenericResult<String> accountResult = zwddAuthClient.getAccountId(code);
if (!accountResult.isSuccess()) {
throw new BadCredentialsException("login fail! 浙政钉校验失败");
}
String accountId = accountResult.getData();
if (Objects.isNull(accountId)) {
throw new BadCredentialsException("login fail! 浙政钉校验失败");
}
user = userDetailsService.loadUserByUsername(accountId + UserDeatilsServiceConstant.USER_DETAILS_SERVICE_SEPARATOR + loginTypeEnum.name());
}
break;
case PHONE_VERIFICATION_CODE_LOGIN: {
// TODO 校验短信验证码
user = userDetailsService.loadUserByUsername(principal + UserDeatilsServiceConstant.USER_DETAILS_SERVICE_SEPARATOR + loginTypeEnum.name());
}
break;
case USERNAME_PASSWORD_LOGIN: {
user = userDetailsService.loadUserByUsername((String) authenticationToken.getPrincipal());
if (user == null) {
throw new InternalAuthenticationServiceException("can not get user info!");
}
// 账号密码登陆 更改
additionalAuthenticationChecks(user, authenticationToken);
}
break;
}
// 将用户定义的user放入token中,这样可以在session中查询到所有自定义的用户信息
return new CredentialAuthToken(user, user.getPassword(), user.getAuthorities());
}

protected void additionalAuthenticationChecks(UserDetails userDetails, CredentialAuthToken authentication)
throws AuthenticationException {
if (authentication.getCredentials() == null) {
throw new BadCredentialsException("login fail! password is null");
}
String presentedPassword = authentication.getCredentials().toString();
if (!passwordEncoder.matches(presentedPassword, userDetails.getPassword())) {
throw new BadCredentialsException("login fail! password is error");
}
}


@Override
public boolean supports(Class<?> authentication) {
return CredentialAuthToken.class.isAssignableFrom(authentication);
}

public void setUserDetailsService(UserDetailsService userDetailsService) {
this.userDetailsService = userDetailsService;
}

public void setPasswordEncoder(PasswordEncoder passwordEncoder) {
this.passwordEncoder = passwordEncoder;
}

public void setZwddAuthClient(ZwddAuthClient zwddAuthClient) {
this.zwddAuthClient = zwddAuthClient;
}

}

pmapi/src/main/java/com/ningdatech/pmapi/user/security/auth/password/UsernamePasswordAuthSecurityConfig.java → pmapi/src/main/java/com/ningdatech/pmapi/user/security/auth/credential/CredentialAuthSecurityConfig.java Vedi File

@@ -1,6 +1,7 @@
package com.ningdatech.pmapi.user.security.auth.password;
package com.ningdatech.pmapi.user.security.auth.credential;

import com.ningdatech.pmapi.user.security.auth.AuthProperties;
import com.ningdatech.zwdd.client.ZwddAuthClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.security.authentication.AuthenticationManager;
@@ -18,7 +19,7 @@ import org.springframework.stereotype.Component;
* 账号密码登陆的认证配置
*/
@Component
public class UsernamePasswordAuthSecurityConfig
public class CredentialAuthSecurityConfig
extends SecurityConfigurerAdapter<DefaultSecurityFilterChain, HttpSecurity> {

@Autowired
@@ -30,8 +31,8 @@ public class UsernamePasswordAuthSecurityConfig
protected AuthenticationFailureHandler defaultLoginFailureHandler;

@Autowired
@Qualifier(value = "passwordLoginUserDetailService")
private UserDetailsService passwordLoginUserDetailService;
@Qualifier(value = "credentialLoginUserDetailService")
private UserDetailsService credentialLoginUserDetailService;

@Autowired
private PasswordEncoder passwordEncoder;
@@ -41,20 +42,26 @@ public class UsernamePasswordAuthSecurityConfig

private AuthenticationManager authenticationManager;

@Autowired
private ZwddAuthClient zwddAuthClient;

@Override
public void configure(HttpSecurity http) throws Exception {
UsernamePasswordAuthFilter usernamePasswordAuthFilter =
new UsernamePasswordAuthFilter(authProperties.getPasswordLoginUrl());
CredentialAuthFilter credentialAuthFilter =
new CredentialAuthFilter(authProperties.getPasswordLoginUrl());
authenticationManager = http.getSharedObject(AuthenticationManager.class);
usernamePasswordAuthFilter.setAuthenticationManager(authenticationManager);
usernamePasswordAuthFilter.setAuthenticationSuccessHandler(defaultLoginSuccessHandler);
usernamePasswordAuthFilter.setAuthenticationFailureHandler(defaultLoginFailureHandler);
credentialAuthFilter.setAuthenticationManager(authenticationManager);
credentialAuthFilter.setAuthenticationSuccessHandler(defaultLoginSuccessHandler);
credentialAuthFilter.setAuthenticationFailureHandler(defaultLoginFailureHandler);

UsernamePasswordAuthProvider authenticationProvider = new UsernamePasswordAuthProvider();
authenticationProvider.setUserDetailsService(passwordLoginUserDetailService);
CredentialAuthProvider authenticationProvider = new CredentialAuthProvider();
authenticationProvider.setUserDetailsService(credentialLoginUserDetailService);
// 确保对密码进行加密的encoder和解密的encoder相同
authenticationProvider.setPasswordEncoder(passwordEncoder);
http.authenticationProvider(authenticationProvider).addFilterAfter(usernamePasswordAuthFilter,
// 传入浙政钉client
authenticationProvider.setZwddAuthClient(zwddAuthClient);

http.authenticationProvider(authenticationProvider).addFilterAfter(credentialAuthFilter,
UsernamePasswordAuthenticationFilter.class);
}


pmapi/src/main/java/com/ningdatech/pmapi/user/security/auth/password/UsernamePasswordAuthToken.java → pmapi/src/main/java/com/ningdatech/pmapi/user/security/auth/credential/CredentialAuthToken.java Vedi File

@@ -1,5 +1,6 @@
package com.ningdatech.pmapi.user.security.auth.password;
package com.ningdatech.pmapi.user.security.auth.credential;

import com.ningdatech.pmapi.user.constant.LoginTypeEnum;
import org.springframework.security.authentication.AbstractAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.SpringSecurityCoreVersion;
@@ -11,7 +12,7 @@ import java.util.Collection;
* @Date 2020/8/3 8:52 下午
* @Version 1.0
**/
public class UsernamePasswordAuthToken extends AbstractAuthenticationToken {
public class CredentialAuthToken extends AbstractAuthenticationToken {

private static final long serialVersionUID = SpringSecurityCoreVersion.SERIAL_VERSION_UID;

@@ -19,16 +20,18 @@ public class UsernamePasswordAuthToken extends AbstractAuthenticationToken {

private final Object credentials;

private final LoginTypeEnum loginTypeEnum;

/**
* This constructor can be safely used by any code that wishes to create a
* <code>UsernamePasswordAuthenticationToken</code>, as the {@link #isAuthenticated()} will return
* <code>false</code>.
*/
public UsernamePasswordAuthToken(String principal, String credentials) {
public CredentialAuthToken(String principal, String credentials, String loginTypeEnum) {
super(null);
this.principal = principal;
this.credentials = credentials;
this.loginTypeEnum = LoginTypeEnum.valueOf(loginTypeEnum);
setAuthenticated(false);
}

@@ -40,15 +43,20 @@ public class UsernamePasswordAuthToken extends AbstractAuthenticationToken {
* @param principal
* @param authorities
*/
public UsernamePasswordAuthToken(Object principal, Object credentials,
Collection<? extends GrantedAuthority> authorities) {
public CredentialAuthToken(Object principal, Object credentials,
Collection<? extends GrantedAuthority> authorities) {
super(authorities);
this.principal = principal;
this.credentials = credentials;
this.loginTypeEnum = null;
// must use super, as we override
super.setAuthenticated(true);
}

public LoginTypeEnum getLoginTypeEnum() {
return this.loginTypeEnum;
}

@Override
public Object getCredentials() {
return this.credentials;

+ 67
- 0
pmapi/src/main/java/com/ningdatech/pmapi/user/security/auth/credential/CredentialLoginUserDetailService.java Vedi File

@@ -0,0 +1,67 @@
package com.ningdatech.pmapi.user.security.auth.credential;


import com.ningdatech.pmapi.user.constant.LoginTypeEnum;
import com.ningdatech.pmapi.user.manage.UserAuthLoginManage;
import com.ningdatech.pmapi.user.security.auth.constants.UserDeatilsServiceConstant;
import com.ningdatech.pmapi.user.security.auth.model.UserFullInfoDTO;
import com.ningdatech.pmapi.user.security.auth.model.UserInfoDetails;
import lombok.RequiredArgsConstructor;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;

import java.util.Objects;

/**
* @author LiuXinXin
* @date 2022/9/30 上午9:49
*/

@Service("credentialLoginUserDetailService")
@RequiredArgsConstructor
public class CredentialLoginUserDetailService implements UserDetailsService {

private final UserAuthLoginManage userAuthLoginManage;

@Override
public UserInfoDetails loadUserByUsername(String username) throws UsernameNotFoundException {
String[] split = username.split(UserDeatilsServiceConstant.USER_DETAILS_SERVICE_SEPARATOR);
username = split[0];
String loginTypeStr = split[1];
LoginTypeEnum loginTypeEnum = LoginTypeEnum.valueOf(loginTypeStr);

UserFullInfoDTO userFullInfoDTO = null;
switch (loginTypeEnum) {
case PHONE_VERIFICATION_CODE_LOGIN: {
userFullInfoDTO = userAuthLoginManage.queryUserInfoInPhoneNoAuth(username);
}
break;
case USERNAME_PASSWORD_LOGIN: {
userFullInfoDTO = userAuthLoginManage.queryUserInfoInPasswordAuth(username);
}
break;
case DING_QR_LOGIN: {
userFullInfoDTO = userAuthLoginManage.queryUserInfoInAccountIdAuth(username);
}
break;
default: {
throw new UsernameNotFoundException(String.format("%s user not exist", username));
}
}

if (Objects.isNull(userFullInfoDTO)) {
throw new UsernameNotFoundException(String.format("%s user not exist", username));
}
UserInfoDetails userInfoDetails = new UserInfoDetails();
userInfoDetails.setUserId(userFullInfoDTO.getUserId());
userInfoDetails.setUsername(userFullInfoDTO.getUsername());
userInfoDetails.setRealName(userFullInfoDTO.getRealName());
userInfoDetails.setRole(userFullInfoDTO.getRole());
userInfoDetails.setRegionCode(userFullInfoDTO.getRegionCode());
userInfoDetails.setCompanyId(userFullInfoDTO.getCompanyId());
userInfoDetails.setIdentifier(userFullInfoDTO.getIdentifier());
userInfoDetails.setPassword(userFullInfoDTO.getCredential());
return userInfoDetails;
}
}

+ 0
- 71
pmapi/src/main/java/com/ningdatech/pmapi/user/security/auth/password/UsernamePasswordAuthFilter.java Vedi File

@@ -1,71 +0,0 @@
package com.ningdatech.pmapi.user.security.auth.password;

import com.ningdatech.basic.exception.BizException;
import org.apache.commons.lang3.StringUtils;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.InternalAuthenticationServiceException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
* @Author LiuXinXin
* @Date 2020/8/3 8:46 下午
* @Version 1.0
**/
public class UsernamePasswordAuthFilter extends AbstractAuthenticationProcessingFilter {

private boolean postOnly = true;

private static final String USERNAME_PARAMETER = "username";
private static final String PASSWORD_PARAMETER = "password";


// ~ Constructors
// ===================================================================================================

public UsernamePasswordAuthFilter(String processingUrl) {
super(new AntPathRequestMatcher(processingUrl, HttpMethod.POST.name()));
}

// ~ Methods
// ========================================================================================================

@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
throws AuthenticationException {
if (postOnly && !request.getMethod().equals(HttpMethod.POST.name())) {
throw new AuthenticationServiceException("请求方法错误");
}
String username = request.getParameter(USERNAME_PARAMETER);
String password = request.getParameter(PASSWORD_PARAMETER);
if (StringUtils.isBlank(username) || StringUtils.isBlank(password)) {
throw new UsernameNotFoundException("用户名或密码不能为空");
}
username = username.trim();
password = password.trim();
try {
UsernamePasswordAuthToken authRequest = new UsernamePasswordAuthToken(username, password);
// Allow subclasses to set the "details" property
setDetails(request, authRequest);
return this.getAuthenticationManager().authenticate(authRequest);
} catch (AuthenticationException e) {
throw new BadCredentialsException("账号或密码错误");
} catch (BizException e) {
throw new BadCredentialsException(e.getMessage());
} catch (Exception e) {
throw new InternalAuthenticationServiceException("授权失败:", e);
}
}

protected void setDetails(HttpServletRequest request, UsernamePasswordAuthToken authRequest) {
authRequest.setDetails(authenticationDetailsSource.buildDetails(request));
}
}

+ 0
- 65
pmapi/src/main/java/com/ningdatech/pmapi/user/security/auth/password/UsernamePasswordAuthProvider.java Vedi File

@@ -1,65 +0,0 @@
package com.ningdatech.pmapi.user.security.auth.password;

import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.InternalAuthenticationServiceException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.PasswordEncoder;

/**
* @Author LiuXinXin
* @Date 2020/8/3 8:55 下午
* @Version 1.0
**/
public class UsernamePasswordAuthProvider implements AuthenticationProvider {

private UserDetailsService userDetailsService;

private PasswordEncoder passwordEncoder;

@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
if (!(authentication instanceof UsernamePasswordAuthToken)) {
throw new RuntimeException("CustomAuthProvider 只支持 CustomAuthToken");
}
UsernamePasswordAuthToken authenticationToken = (UsernamePasswordAuthToken) authentication;

UserDetails user = userDetailsService.loadUserByUsername((String) authenticationToken.getPrincipal());
if (user == null) {
throw new InternalAuthenticationServiceException("can not get user info!");
}
// TODO 开发使用暂时关闭账号密码验证
// additionalAuthenticationChecks(user, authenticationToken);
// 校验用户是否有当前端的登陆权限
// 将用户定义的user放入token中,这样可以在session中查询到所有自定义的用户信息
return new UsernamePasswordAuthToken(user, user.getPassword(), user.getAuthorities());
}

protected void additionalAuthenticationChecks(UserDetails userDetails, UsernamePasswordAuthToken authentication)
throws AuthenticationException {
if (authentication.getCredentials() == null) {
throw new BadCredentialsException("login fail! password is null");
}
String presentedPassword = authentication.getCredentials().toString();
if (!passwordEncoder.matches(presentedPassword, userDetails.getPassword())) {
throw new BadCredentialsException("login fail! password is error");
}
}

@Override
public boolean supports(Class<?> authentication) {
return UsernamePasswordAuthToken.class.isAssignableFrom(authentication);
}

public void setUserDetailsService(UserDetailsService userDetailsService) {
this.userDetailsService = userDetailsService;
}

public void setPasswordEncoder(PasswordEncoder passwordEncoder) {
this.passwordEncoder = passwordEncoder;
}

}

+ 9
- 0
pmapi/src/main/java/com/ningdatech/pmapi/user/util/LoginUserUtil.java Vedi File

@@ -3,6 +3,9 @@ package com.ningdatech.pmapi.user.util;
import com.ningdatech.basic.auth.AbstractLoginUserUtil;
import com.ningdatech.pmapi.user.security.auth.model.UserInfoDetails;

import java.util.ArrayList;
import java.util.List;


/**
* @Author liuxinxin
@@ -15,4 +18,10 @@ public class LoginUserUtil extends AbstractLoginUserUtil {
return getLoginUserPrincipal();
}

public static List<Long> getRoleIdList() {
List<Long> roleIdList = new ArrayList<>();
roleIdList.add(1L);
return roleIdList;
}

}

+ 1
- 13
pmapi/src/main/resources/application-dev.yml Vedi File

@@ -153,16 +153,4 @@ sa-token:
# token风格
token-style: uuid
# 是否输出操作日志
is-log: false

#专有钉钉
ding:
#扫码
app-auth-key: expert-base_dingoa-c5nnefYVnie
app-auth-secret: nm8qtST8uK431HYrjr7srcE23sT4889QgMcYFM3L
# #免登/获取信息
app-key: file-manage-4Mjx9358wuxjyYFjY3
app-secret: hE41938wqyQ5LOpc1QDRA9e7gb5YugoClWD3nY4O
#专有钉钉在开发管理工作台,右键查看网页源码realmId: '31141',浙政钉固定196729
tenantId: 31141
domain: openplatform.dg-work.cn
is-log: false

+ 5
- 13
pmapi/src/main/resources/integration/zwdd-dev.yml Vedi File

@@ -1,20 +1,12 @@
#专有钉钉
integration:
zzd:
zwdd:
#扫码
app-auth-key: expert-base_dingoa-c5nnefYVnie
app-auth-secret: nm8qtST8uK431HYrjr7srcE23sT4889QgMcYFM3L
# #免登/获取信息
# app-key: file-manage-4Mjx9358wuxjyYFjY3
# app-secret: hE41938wqyQ5LOpc1QDRA9e7gb5YugoClWD3nY4O
app-auth-key: ls-rebuild_dingoa-rgeWs3YVr26z
app-auth-secret: 37qCe6ylNMW0N8K2741z0c2b9vJP2gtuMRQQtZ9P
#免登/获取信息
app-key: ls_rebuild-10c8n5X0707yFV7jURr
app-secret: gN8J3WazyXLMWKDuFmx6C4yaH5lFUY41x8rYLLo6
#专有钉钉在开发管理工作台,右键查看网页源码realmId: '31141',浙政钉固定196729
tenantId: 31141
domain: openplatform.dg-work.cn

# integration.zzd.enabled=true
# #扫码
# integration.zzd.app-auth-key=file-manage_dingoa-zte2LbiAfIj
# integration.zzd.app-auth-secret=H794aFZf271QbfUr50pbBpBTlXSrWIP71q9RTR34
# integration.zzd.domain=openplatform.dg-work.cn
domain: openplatform.dg-work.cn

+ 11
- 10
pmapi/src/main/resources/integration/zwdd-prod.yml Vedi File

@@ -1,11 +1,12 @@
#专有钉钉
ding:
#扫码
app-auth-key: expert-base_dingoa-c5nnefYVnie
app-auth-secret: nm8qtST8uK431HYrjr7srcE23sT4889QgMcYFM3L
# #免登/获取信息
app-key: file-manage-4Mjx9358wuxjyYFjY3
app-secret: hE41938wqyQ5LOpc1QDRA9e7gb5YugoClWD3nY4O
#专有钉钉在开发管理工作台,右键查看网页源码realmId: '31141',浙政钉固定196729
tenantId: 31141
domain: openplatform.dg-work.cn
integration:
zwdd:
#扫码
app-auth-key: ls-rebuild_dingoa-rgeWs3YVr26z
app-auth-secret: 37qCe6ylNMW0N8K2741z0c2b9vJP2gtuMRQQtZ9P
#免登/获取信息
app-key: ls_rebuild-10c8n5X0707yFV7jURr
app-secret: gN8J3WazyXLMWKDuFmx6C4yaH5lFUY41x8rYLLo6
#专有钉钉在开发管理工作台,右键查看网页源码realmId: '31141',浙政钉固定196729
tenantId: 31141
domain: openplatform.dg-work.cn

+ 1
- 1
pmapi/src/main/resources/security/auth-dev.yml Vedi File

@@ -2,7 +2,7 @@ security:
auth:
auth-require-url: /api/v1/user/auth/auth-require
invalid-session-url: /api/v1/user/auth/invalid-session
password-login-url: /api/v1/user/auth/login/password
password-login-url: /api/v1/user/auth/login
logout-url: /api/v1/user/auth/logout
ignore-auth-urls:
- /v2/api-docs


+ 1
- 1
pmapi/src/main/resources/security/auth-prod.yml Vedi File

@@ -2,7 +2,7 @@ security:
auth:
auth-require-url: /api/v1/user/auth/auth-require
invalid-session-url: /api/v1/user/auth/invalid-session
password-login-url: /api/v1/user/auth/login/password
password-login-url: /api/v1/user/auth/login
logout-url: /api/v1/user/auth/logout
ignore-auth-urls:
- /v2/api-docs


+ 9
- 0
pmapi/src/test/java/com/ningdatech/pmapi/organization/OrganizationTest.java Vedi File

@@ -1,6 +1,7 @@
package com.ningdatech.pmapi.organization;

import com.ningdatech.pmapi.AppTests;
//import com.ningdatech.pmapi.ding.task.EmployeeBatchGetTask;
import com.ningdatech.pmapi.ding.task.OrganizationBatchGetTask;
import com.ningdatech.zwdd.client.ZwddAuthClient;
import com.ningdatech.zwdd.client.ZwddClient;
@@ -23,9 +24,17 @@ class OrganizationTest extends AppTests {
@Autowired
private OrganizationBatchGetTask organizationBatchGetTask;

// @Autowired
// private EmployeeBatchGetTask employeeBatchGetTask;

@Test
public void testBatchGetOrganization() {
organizationBatchGetTask.batchGetOrganizationTask();
}

// @Test
// public void testEmployeeBatchGetTask(){
// employeeBatchGetTask.batchGetEmployeeTask();
// }

}

Loading…
Annulla
Salva