@@ -2,6 +2,7 @@ package com.hz.pm.api.common.helper; | |||
import cn.hutool.core.util.NumberUtil; | |||
import com.hz.pm.api.user.model.entity.UserInfo; | |||
import com.hz.pm.api.user.model.enumeration.RoleEnum; | |||
import com.hz.pm.api.user.security.model.UserFullInfoDTO; | |||
import com.ningdatech.basic.util.CollUtils; | |||
@@ -42,9 +43,11 @@ public interface UserInfoHelper { | |||
List<UserFullInfoDTO> listUserFullInfoByUserIds(Collection<Long> userIds); | |||
default List<UserFullInfoDTO> listUserFullInfoByUserIds(List<String> userIds){ | |||
default List<UserFullInfoDTO> listUserFullInfoByUserIds(List<String> userIds) { | |||
List<Long> userIdsLong = CollUtils.convert(userIds, Long::parseLong); | |||
return listUserFullInfoByUserIds(userIdsLong); | |||
} | |||
List<UserFullInfoDTO> listUserFullInfoByUnitIdsAndRole(Collection<Long> unitIds, RoleEnum role); | |||
} |
@@ -5,6 +5,8 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; | |||
import com.baomidou.mybatisplus.core.toolkit.StringUtils; | |||
import com.baomidou.mybatisplus.core.toolkit.Wrappers; | |||
import com.hz.pm.api.common.helper.UserInfoHelper; | |||
import com.hz.pm.api.common.model.constant.BizConst; | |||
import com.hz.pm.api.common.util.BizUtils; | |||
import com.hz.pm.api.common.util.StrUtils; | |||
import com.hz.pm.api.sys.mapper.RoleMapper; | |||
import com.hz.pm.api.sys.model.entity.Role; | |||
@@ -15,6 +17,7 @@ import com.hz.pm.api.user.model.enumeration.RoleEnum; | |||
import com.hz.pm.api.user.model.enumeration.UserAvailableEnum; | |||
import com.hz.pm.api.user.security.model.UserFullInfoDTO; | |||
import com.hz.pm.api.user.service.IUserInfoService; | |||
import com.ningdatech.basic.util.CollUtils; | |||
import lombok.RequiredArgsConstructor; | |||
import org.springframework.stereotype.Component; | |||
@@ -100,23 +103,25 @@ public class UserInfoHelperImpl implements UserInfoHelper { | |||
if (CollUtil.isEmpty(userInfos)) { | |||
return Collections.emptyList(); | |||
} | |||
return userInfos.stream().map(userInfo -> { | |||
UserFullInfoDTO userFullInfo = new UserFullInfoDTO(); | |||
// 装配返回 | |||
userFullInfo.setMhUnitName(userInfo.getMhUnitName()); | |||
userFullInfo.setMhUnitId(userInfo.getMhUnitId()); | |||
userFullInfo.setUserId(userInfo.getId()); | |||
userFullInfo.setIdentifier(userInfo.getRealName()); | |||
userFullInfo.setRealName(userInfo.getRealName()); | |||
userFullInfo.setUsername(userInfo.getRealName()); | |||
userFullInfo.setMobile(userInfo.getMobile()); | |||
userFullInfo.setAccountId(userInfo.getAccountId()); | |||
String available = userInfo.getAvailable(); | |||
if (StrUtils.isNotBlank(available)) { | |||
userFullInfo.setAvailable(UserAvailableEnum.valueOf(available)); | |||
} | |||
return userFullInfo; | |||
}).collect(Collectors.toList()); | |||
return userInfos.stream().map(this::convert).collect(Collectors.toList()); | |||
} | |||
private UserFullInfoDTO convert(UserInfo userInfo){ | |||
UserFullInfoDTO userFullInfo = new UserFullInfoDTO(); | |||
// 装配返回 | |||
userFullInfo.setMhUnitName(userInfo.getMhUnitName()); | |||
userFullInfo.setMhUnitId(userInfo.getMhUnitId()); | |||
userFullInfo.setUserId(userInfo.getId()); | |||
userFullInfo.setIdentifier(userInfo.getRealName()); | |||
userFullInfo.setRealName(userInfo.getRealName()); | |||
userFullInfo.setUsername(userInfo.getRealName()); | |||
userFullInfo.setMobile(userInfo.getMobile()); | |||
userFullInfo.setAccountId(userInfo.getAccountId()); | |||
String available = userInfo.getAvailable(); | |||
if (StrUtils.isNotBlank(available)) { | |||
userFullInfo.setAvailable(UserAvailableEnum.valueOf(available)); | |||
} | |||
return userFullInfo; | |||
} | |||
@Override | |||
@@ -145,4 +150,21 @@ public class UserInfoHelperImpl implements UserInfoHelper { | |||
return getUserFullInfos(userInfos); | |||
} | |||
@Override | |||
public List<UserFullInfoDTO> listUserFullInfoByUnitIdsAndRole(Collection<Long> unitIds, RoleEnum roleEnum) { | |||
LambdaQueryWrapper<Role> rQuery = Wrappers.lambdaQuery(Role.class) | |||
.eq(Role::getCode, roleEnum.name()) | |||
.last(BizConst.LIMIT_1); | |||
Role role = roleMapper.selectOne(rQuery); | |||
if (role == null) { | |||
return Collections.emptyList(); | |||
} | |||
LambdaQueryWrapper<UserInfo> query = Wrappers.lambdaQuery(UserInfo.class) | |||
.in(UserInfo::getMhUnitId, unitIds) | |||
.exists("select 1 from nd_user_role nur where nur.user_id = nd_user_info.id" + | |||
" and nur.role_id = {0}", role.getId()); | |||
List<UserInfo> userInfos = userInfoService.list(query); | |||
return CollUtils.convert(userInfos,this::convert); | |||
} | |||
} |
@@ -0,0 +1,34 @@ | |||
package com.hz.pm.api.common.util; | |||
import org.springframework.lang.NonNull; | |||
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; | |||
import java.util.concurrent.Callable; | |||
import java.util.concurrent.Future; | |||
/** | |||
* <p> | |||
* MDCThreadPoolTaskExecutor | |||
* </p> | |||
* | |||
* @author WendyYang | |||
* @since 2023/10/27 | |||
**/ | |||
public class MDCThreadPoolTaskScheduler extends ThreadPoolTaskScheduler { | |||
@Override | |||
public @NonNull Future<?> submit(@NonNull Runnable task) { | |||
return super.submit(MDCThreadUtil.wrap(task)); | |||
} | |||
@Override | |||
public void execute(@NonNull Runnable task) { | |||
super.execute(MDCThreadUtil.wrap(task)); | |||
} | |||
@Override | |||
public <T> @NonNull Future<T> submit(@NonNull Callable<T> task) { | |||
return super.submit(MDCThreadUtil.wrap(task)); | |||
} | |||
} |
@@ -1,6 +1,7 @@ | |||
package com.hz.pm.api.common.util; | |||
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; | |||
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; | |||
import java.util.concurrent.ThreadPoolExecutor; | |||
@@ -18,16 +19,28 @@ public class ThreadPoolUtil { | |||
} | |||
public static final ThreadPoolTaskExecutor REQUEST; | |||
public static final ThreadPoolTaskScheduler SCHEDULER; | |||
static { | |||
REQUEST = new MDCThreadPoolTaskExecutor(); | |||
REQUEST.setCorePoolSize(5); | |||
REQUEST.setMaxPoolSize(15); | |||
REQUEST.setQueueCapacity(300); | |||
REQUEST.setThreadPriority(Thread.NORM_PRIORITY); | |||
REQUEST.setKeepAliveSeconds(120); | |||
REQUEST.setThreadNamePrefix("requestAsyncExecutor-"); | |||
REQUEST.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); | |||
REQUEST.initialize(); | |||
} | |||
static { | |||
SCHEDULER = new MDCThreadPoolTaskScheduler(); | |||
SCHEDULER.setPoolSize(5); | |||
SCHEDULER.setThreadPriority(Thread.NORM_PRIORITY - 1); | |||
SCHEDULER.setWaitForTasksToCompleteOnShutdown(true); | |||
SCHEDULER.setThreadNamePrefix("scheduler-"); | |||
SCHEDULER.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); | |||
SCHEDULER.initialize(); | |||
} | |||
} |
@@ -77,7 +77,7 @@ public class MHTodoClient { | |||
log.info("添加新创待办:{}", todoReq); | |||
String responseResult = HttpUtil.post(url, JSON.toJSONString(todoReq)); | |||
MhTodoRetDTO retData = JSON.parseObject(responseResult, TYPE_REF); | |||
if (retData.getCode() != 0 || StrUtil.isBlank(retData.getData())) { | |||
if (retData.getCode() != 200 || StrUtil.isBlank(retData.getData())) { | |||
log.warn("发送待办失败:{} {}", todoReq, retData); | |||
throw BizException.wrap("发送待办失败"); | |||
} | |||
@@ -21,6 +21,8 @@ public class MhTodoExtraParamDTO { | |||
private String instanceId; | |||
private String projectCode; | |||
private Long projectId; | |||
private String taskId; | |||
@@ -16,10 +16,12 @@ import lombok.Getter; | |||
public enum MHTodoTypeEnum { | |||
FINAL_INSPECT_AUDIT("终验审批"), | |||
XCFHX_INSPECT_AUDIT("信创符合性审查审批"), | |||
DECLARED_RECORD_AUDIT("立项备案审批"); | |||
FINAL_INSPECT_AUDIT("终验审批", "instanceId=${instanceId}&projectId=${projectId}&nodeId=${nodeId}&taskId=${taskId}&bidId=${bizId}&userId=${userId}&userName=${userName}&path=${path}"), | |||
XCFHX_INSPECT_AUDIT("信创符合性审查审批", "instanceId=${instanceId}&projectId=${projectId}&nodeId=${nodeId}&taskId=${taskId}&bidId=${bizId}&userId=${userId}&userName=${userName}&path=${path}"), | |||
DECLARED_RECORD_APPLY("立项备案申请", "userId=${userId}&userName=${userName}&path=${path}"), | |||
DECLARED_RECORD_AUDIT("立项备案审批", "instanceId=${instanceId}&projectId=${projectId}&nodeId=${nodeId}&taskId=${taskId}&bidId=${bizId}&userId=${userId}&userName=${userName}&path=${path}"); | |||
private final String val; | |||
private final String referLinkParam; | |||
} |
@@ -21,6 +21,8 @@ import com.hz.pm.api.datascope.model.DataScopeDTO; | |||
import com.hz.pm.api.datascope.utils.DataScopeUtil; | |||
import com.hz.pm.api.external.model.enumeration.MhUnitStripEnum; | |||
import com.hz.pm.api.external.model.enumeration.MhUnitTypeEnum; | |||
import com.hz.pm.api.external.todo.MHTodoClient; | |||
import com.hz.pm.api.external.todo.enumerization.MHTodoTypeEnum; | |||
import com.hz.pm.api.projectdeclared.manage.DefaultDeclaredProjectManage; | |||
import com.hz.pm.api.projectdeclared.model.dto.DefaultDeclaredDTO; | |||
import com.hz.pm.api.projectdeclared.model.dto.ProjectConditionDTO; | |||
@@ -101,6 +103,7 @@ public class DeclaredRecordManage { | |||
private final ProjectLibManage projectLibManage; | |||
private final IProjectStatusChangeService projectStatusChangeService; | |||
private final IProjectGovSystemReplaceInfosService systemReplaceInfosService; | |||
private final MHTodoClient mhTodoClient; | |||
private LambdaQueryWrapper<MhProject> buildQuery(DeclaredProjectListReq req) { | |||
LambdaQueryWrapper<MhProject> query = Wrappers.lambdaQuery(MhProject.class) | |||
@@ -335,6 +338,8 @@ public class DeclaredRecordManage { | |||
//发送给第一个审批人消息 | |||
noticeManage.sendFirstUser(newProj, model.getFormName(), instanceId, | |||
WorkNoticeConst.PASS_MSG_TEMPLATE, MsgTypeEnum.PROJECT_REVIEW); | |||
// 完成立项备案待办 | |||
mhTodoClient.completeTodo(MHTodoTypeEnum.DECLARED_RECORD_APPLY, newProj.getProjectCode()); | |||
} | |||
@Transactional(rollbackFor = Exception.class) | |||
@@ -0,0 +1,154 @@ | |||
package com.hz.pm.api.scheduler.task; | |||
import cn.hutool.core.util.NumberUtil; | |||
import cn.hutool.core.util.StrUtil; | |||
import com.baomidou.mybatisplus.core.conditions.Wrapper; | |||
import com.baomidou.mybatisplus.core.toolkit.Wrappers; | |||
import com.hz.pm.api.common.helper.UserInfoHelper; | |||
import com.hz.pm.api.common.util.ThreadPoolUtil; | |||
import com.hz.pm.api.external.MhApiClient; | |||
import com.hz.pm.api.external.model.dto.MhZwddWorkNoticeDTO; | |||
import com.hz.pm.api.external.todo.MHTodoClient; | |||
import com.hz.pm.api.external.todo.dto.MhTodoExtraParamDTO; | |||
import com.hz.pm.api.projectlib.model.entity.Project; | |||
import com.hz.pm.api.projectlib.model.enumeration.ProjectStatusEnum; | |||
import com.hz.pm.api.projectlib.service.IProjectService; | |||
import com.hz.pm.api.sys.entity.MhTodoRecord; | |||
import com.hz.pm.api.sys.service.IMhTodoRecordService; | |||
import com.hz.pm.api.user.helper.MhUnitCache; | |||
import com.hz.pm.api.user.model.dto.UnitDTO; | |||
import com.hz.pm.api.user.model.enumeration.RoleEnum; | |||
import com.hz.pm.api.user.security.model.UserFullInfoDTO; | |||
import com.ningdatech.basic.util.CollUtils; | |||
import lombok.extern.slf4j.Slf4j; | |||
import org.springframework.core.env.Environment; | |||
import org.springframework.scheduling.support.CronTrigger; | |||
import org.springframework.stereotype.Component; | |||
import javax.annotation.PostConstruct; | |||
import java.util.List; | |||
import java.util.Map; | |||
import java.util.stream.Collectors; | |||
import static com.hz.pm.api.external.todo.enumerization.MHTodoTypeEnum.DECLARED_RECORD_APPLY; | |||
/** | |||
* <p> | |||
* DeclaredRecordReminderTask | |||
* </p> | |||
* | |||
* @author WendyYang | |||
* @since 10:40 2024/3/14 | |||
*/ | |||
@Slf4j | |||
@Component | |||
public class DeclaredRecordReminderTask extends ReminderTask { | |||
private final IProjectService projectService; | |||
private final IMhTodoRecordService todoRecordService; | |||
private final MhApiClient mhApiClient; | |||
private final MHTodoClient mhTodoClient; | |||
private final MhUnitCache mhUnitCache; | |||
private final UserInfoHelper userInfoHelper; | |||
public DeclaredRecordReminderTask(Environment environment, | |||
IProjectService projectService, | |||
IMhTodoRecordService todoRecordService, | |||
MhApiClient mhApiClient, | |||
MHTodoClient mhTodoClient, | |||
MhUnitCache mhUnitCache, | |||
UserInfoHelper userInfoHelper) { | |||
super(environment); | |||
this.projectService = projectService; | |||
this.todoRecordService = todoRecordService; | |||
this.mhApiClient = mhApiClient; | |||
this.mhTodoClient = mhTodoClient; | |||
this.mhUnitCache = mhUnitCache; | |||
this.userInfoHelper = userInfoHelper; | |||
} | |||
@Override | |||
public String getTaskPropertyName() { | |||
return "declared-record"; | |||
} | |||
private static final String MSG_FMT = "【%s】需要发起立项备案申请,请及时处理。"; | |||
private void declaredRecordReminder() { | |||
Wrapper<Project> query = Wrappers.lambdaQuery(Project.class) | |||
.eq(Project::getNewest, Boolean.TRUE) | |||
.eq(Project::getStatus, ProjectStatusEnum.DECLARED_APPROVED_TO_BE_RECORD); | |||
List<Project> projects = projectService.list(query); | |||
if (projects.isEmpty()) { | |||
return; | |||
} | |||
List<String> projectCodes = CollUtils.fieldList(projects, Project::getProjectCode); | |||
List<Long> buildOrgCodes = projects.stream() | |||
.map(Project::getBuildOrgCode) | |||
.filter(w -> StrUtil.isNotBlank(w) && NumberUtil.isNumber(w)) | |||
.map(NumberUtil::parseLong) | |||
.collect(Collectors.toList()); | |||
if (buildOrgCodes.isEmpty()) { | |||
return; | |||
} | |||
List<UnitDTO> units = mhUnitCache.listByIds(buildOrgCodes); | |||
Map<String, UnitDTO> unitMap = CollUtils.listToMap(units, w -> String.valueOf(w.getId())); | |||
List<MhTodoRecord> todoRecords = todoRecordService.list(DECLARED_RECORD_APPLY, projectCodes); | |||
Map<String, MhTodoRecord> todoRecordMap = CollUtils.listToMap(todoRecords, MhTodoRecord::getBizId); | |||
List<UserFullInfoDTO> userFullInfos = userInfoHelper.listUserFullInfoByUnitIdsAndRole(buildOrgCodes, RoleEnum.COMPANY_MANAGER); | |||
if (userFullInfos.isEmpty()) { | |||
return; | |||
} | |||
Map<String, List<UserFullInfoDTO>> userMap = CollUtils.group(userFullInfos, UserFullInfoDTO::getMhUnitIdStr); | |||
for (Project project : projects) { | |||
try { | |||
String projectCode = project.getProjectCode(); | |||
String buildOrgCode = project.getBuildOrgCode(); | |||
UnitDTO unit = unitMap.get(buildOrgCode); | |||
if (unit == null) { | |||
continue; | |||
} | |||
List<UserFullInfoDTO> currUnitUsers = userMap.get(buildOrgCode); | |||
if (currUnitUsers == null) { | |||
continue; | |||
} | |||
String content = String.format(MSG_FMT, project.getProjectName()); | |||
for (UserFullInfoDTO user : currUnitUsers) { | |||
if (todoRecordMap.containsKey(project.getProjectCode())) { | |||
MhZwddWorkNoticeDTO notice = MhZwddWorkNoticeDTO.builder() | |||
.title(DECLARED_RECORD_APPLY.getVal()) | |||
.content(content) | |||
.targetUser(user.getMhUserId()) | |||
.build(); | |||
mhApiClient.sendZwddWorkNotice(notice); | |||
} else { | |||
MhTodoExtraParamDTO paramObj = MhTodoExtraParamDTO.builder() | |||
.projectId(project.getId()) | |||
.projectCode(projectCode) | |||
.path("/declareManage/projectFiling") | |||
.userId(user.getUserId()) | |||
.userName(user.getRealName()) | |||
.build(); | |||
mhTodoClient.addTodo(paramObj, user, DECLARED_RECORD_APPLY, projectCode, content); | |||
} | |||
} | |||
} catch (Exception e) { | |||
log.error("通知失败", e); | |||
} | |||
} | |||
} | |||
@PostConstruct | |||
public void initTask() { | |||
// 初始化立项备案提醒任务 | |||
if (this.open()) { | |||
String cron = this.cron(); | |||
ThreadPoolUtil.SCHEDULER.schedule(this::declaredRecordReminder, triggerContext -> { | |||
CronTrigger cronTrigger = new CronTrigger(cron); | |||
return cronTrigger.nextExecutionTime(triggerContext); | |||
}); | |||
} | |||
} | |||
} |
@@ -0,0 +1,39 @@ | |||
package com.hz.pm.api.scheduler.task; | |||
import lombok.AllArgsConstructor; | |||
import lombok.NoArgsConstructor; | |||
import lombok.RequiredArgsConstructor; | |||
import org.springframework.core.env.Environment; | |||
/** | |||
* <p> | |||
* ReminderTask | |||
* </p> | |||
* | |||
* @author WendyYang | |||
* @since 13:20 2024/3/14 | |||
*/ | |||
@RequiredArgsConstructor | |||
public abstract class ReminderTask { | |||
public static final String PREFIX = "reminder-task"; | |||
public static final String CRON = "cron"; | |||
public static final String OPEN = "open"; | |||
public final Environment environment; | |||
public abstract String getTaskPropertyName(); | |||
public boolean open() { | |||
String property = PREFIX + "." + getTaskPropertyName() + "." + OPEN; | |||
Boolean value = environment.getProperty(property, Boolean.class); | |||
return value != null && value; | |||
} | |||
public String cron() { | |||
String property = PREFIX + "." + getTaskPropertyName() + "." + CRON; | |||
return environment.getProperty(property, String.class); | |||
} | |||
} |
@@ -1,8 +1,15 @@ | |||
package com.hz.pm.api.sys.service; | |||
import com.baomidou.mybatisplus.core.conditions.Wrapper; | |||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; | |||
import com.baomidou.mybatisplus.core.toolkit.Wrappers; | |||
import com.hz.pm.api.external.todo.enumerization.MHTodoTypeEnum; | |||
import com.hz.pm.api.sys.entity.MhTodoRecord; | |||
import com.baomidou.mybatisplus.extension.service.IService; | |||
import java.util.Collection; | |||
import java.util.List; | |||
/** | |||
* <p> | |||
* 信产待办发送记录 服务类 | |||
@@ -13,4 +20,18 @@ import com.baomidou.mybatisplus.extension.service.IService; | |||
*/ | |||
public interface IMhTodoRecordService extends IService<MhTodoRecord> { | |||
default MhTodoRecord getOne(MHTodoTypeEnum type, String bizId) { | |||
Wrapper<MhTodoRecord> query = Wrappers.lambdaQuery(MhTodoRecord.class) | |||
.eq(MhTodoRecord::getType, type.name()) | |||
.eq(MhTodoRecord::getBizId, bizId); | |||
return getOne(query); | |||
} | |||
default List<MhTodoRecord> list(MHTodoTypeEnum type, Collection<String> bizIds) { | |||
Wrapper<MhTodoRecord> query = Wrappers.lambdaQuery(MhTodoRecord.class) | |||
.eq(MhTodoRecord::getType, type.name()) | |||
.in(MhTodoRecord::getBizId, bizIds); | |||
return list(query); | |||
} | |||
} |
@@ -263,4 +263,11 @@ agent-login: | |||
proxy: | |||
secret-key: nqkwiqojg7g4eiypr3rb8s7nb4noa8b2 | |||
sms: | |||
client-url: http://10.54.38.13:8081/mh-gateway/auth-single | |||
client-url: http://10.54.38.13:8081/mh-gateway/auth-single | |||
# 提醒任务 | |||
reminder-task: | |||
declared-record: | |||
open: false | |||
cron: 0 30 8 * * ? |
@@ -268,4 +268,10 @@ auth-code: | |||
secret-key: uqrvd2bani4fercnisua1cqxjwk1neym | |||
agent-login: | |||
proxy: | |||
secret-key: tqkwiqojg5j4eiypr3rb8w7nb4noa8b2 | |||
secret-key: tqkwiqojg5j4eiypr3rb8w7nb4noa8b2 | |||
# 提醒任务 | |||
reminder-task: | |||
declared-record: | |||
open: false | |||
cron: 0 30 8 * * ? |
@@ -26,7 +26,9 @@ public class MhApiClientTest extends AppTests { | |||
@Test | |||
public void sendTodo() { | |||
UserFullInfoDTO assignee = userInfoHelper.getUserFullInfo("347873"); | |||
UserFullInfoDTO assignee = new UserFullInfoDTO(); | |||
assignee.setUserId(347873L); | |||
assignee.setMhUserId("62697f4ed80d823fa1f26c5a082d989e"); | |||
JSONObject paramObj = new JSONObject(); | |||
paramObj.set("projectId", 1213); | |||
paramObj.set("instId", 1213); | |||