@@ -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"); | |||
} | |||
} |
@@ -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; | |||
} | |||
} |
@@ -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; | |||
} | |||
} |
@@ -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"; | |||
@@ -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"; | |||
} |
@@ -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> { | |||
@@ -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) { | |||
@@ -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) { | |||
@@ -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 | |||
@@ -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; | |||
@@ -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); | |||
//// } | |||
//// } | |||
// | |||
// } | |||
//} |
@@ -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 { | |||
} |
@@ -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> { | |||
} |
@@ -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> |
@@ -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; | |||
} | |||
} |
@@ -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 + | |||
"}"; | |||
} | |||
} |
@@ -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> { | |||
} |
@@ -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 { | |||
} |
@@ -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 再判断 该项目是否 真实走完 预审审批 | |||
@@ -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); | |||
} | |||
@@ -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); | |||
} | |||
@@ -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("无效的数据权限可见范围编码")); | |||
} | |||
} |
@@ -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】被退回,请及时处理。"; | |||
} |
@@ -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); | |||
} | |||
} |
@@ -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; | |||
} | |||
@@ -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(); | |||
@@ -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; | |||
} |
@@ -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; | |||
} |
@@ -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; | |||
} |
@@ -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 { | |||
} |
@@ -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 { | |||
} |
@@ -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文档 | |||
} | |||
@@ -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); | |||
} | |||
} |
@@ -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; | |||
} | |||
} |
@@ -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) { | |||
} | |||
} |
@@ -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; | |||
} |
@@ -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; | |||
} |
@@ -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; | |||
} |
@@ -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; | |||
} |
@@ -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() | |||
@@ -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 = "@###@"; | |||
} |
@@ -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()); |
@@ -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; | |||
} | |||
} |
@@ -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; | |||
} | |||
} |
@@ -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); | |||
} | |||
@@ -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; |
@@ -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; | |||
} | |||
} |
@@ -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)); | |||
} | |||
} |
@@ -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; | |||
} | |||
} |
@@ -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; | |||
} | |||
} |
@@ -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 |
@@ -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 |
@@ -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 |
@@ -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 | |||
@@ -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,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(); | |||
// } | |||
} |