feat(REQ-3714) 工人退场流程优化 - 工人自动打离场标签以及取消标签的XXL-JOB

This commit is contained in:
luofu 2025-03-12 11:50:23 +08:00
parent 04a13c9741
commit 90ff9f1f70
4 changed files with 74 additions and 161 deletions

View File

@ -22,6 +22,10 @@ import java.util.List;
@AllArgsConstructor
public class AttendanceClockRecordListReq {
public static final int USER_TYPE_WORKER = 1;
public static final int USER_TYPE_PRACTITIONER = 2;
public static final int USER_TYPE_WORKER_LEADER = 4;
/**
* 项目部id - 必传
*/

View File

@ -2,37 +2,23 @@ package cn.axzo.orgmanax.server.orguser.xxl;
import cn.axzo.foundation.page.PageResp;
import cn.axzo.orgmanax.dto.common.IdentityType;
import cn.axzo.orgmanax.dto.cooperateship.enums.CooperateShipStatusEnum;
import cn.axzo.orgmanax.dto.cooperateship.enums.CooperateShipTypeEnum;
import cn.axzo.orgmanax.dto.nodeuser.enums.TagOperateEnum;
import cn.axzo.orgmanax.dto.nodeuser.req.TagOperateReq;
import cn.axzo.orgmanax.infra.client.workspace.dto.Workspace;
import cn.axzo.orgmanax.infra.dao.cooperateship.entity.SaasCooperateShip;
import cn.axzo.orgmanax.infra.dao.cooperateship.repository.CooperateShipQueryRepository;
import cn.axzo.orgmanax.infra.dao.nodeuser.repository.NodeUserQueryRepository.ListReq;
import cn.axzo.orgmanax.infra.dao.nodeuser.repository.NodeUserQueryRepository.NodeUserResp;
import cn.axzo.orgmanax.server.cooperateship.foundation.CooperateShipFoundationService;
import cn.axzo.orgmanax.server.nodeuser.foundation.NodeUserFoundationService;
import cn.hutool.core.collection.CollUtil;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.xxl.job.core.biz.model.ReturnT;
import com.xxl.job.core.handler.annotation.XxlJob;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
/**
@ -47,29 +33,12 @@ public class AutoAddWorkerLeavedTagJob extends BaseAutoOperatePersonLeavedTagJob
private static final String LOG_PREFIX = "[ADD_WORKER_LEAVED_TAG ] ";
private static final ImmutableList<Integer> INCLUDE_WORKSPACE_TYPES = ImmutableList.of(Workspace.WorkspaceTypeEnum.GENERAL_PROJECT.getValue());
private static final ImmutableList<Integer> INCLUDE_COOPERATE_TYPES = ImmutableList.of(CooperateShipTypeEnum.PROJ_TEAM.getCode(),
CooperateShipTypeEnum.PROJ_GROUP.getCode());
private static final ImmutableList<Integer> INCLUDE_STATUS = ImmutableList.of(CooperateShipStatusEnum.PRESENT.getCode());
@Resource
private NodeUserFoundationService nodeUserFoundationService;
@Resource
private CooperateShipFoundationService cooperateShipFoundationService;
private Context context;
@Override
@XxlJob("autoAddWorkerLeavedTagJob")
public ReturnT<String> execute(String param) {
// init context of job
initContext();
if (context.invalid()) {
// failed to init context.
error("failed to init context.");
return ReturnT.FAIL;
}
// start to execute
doExecute(param);
return ReturnT.SUCCESS;
}
@ -79,17 +48,15 @@ public class AutoAddWorkerLeavedTagJob extends BaseAutoOperatePersonLeavedTagJob
return LOG_PREFIX;
}
@Override
LocalDateTime startDateTimeOfJobExecution() {
return context.getStartDateTime();
}
@Override
List<NodeUserResp> scrollList(long scrollIndex) {
ListReq page = new ListReq();
page.setIdLt(scrollIndex);
page.setIdentityType(IdentityType.WORKER.getCode());
page.setWorkspaceIdGt(0L);
page.setPageSize(MAX_CNT_ONCE);
page.setWorkspaceIds(context.getWorkspaceIds());
page.setSort(Collections.singletonList(sortDesc("id")));
PageResp<NodeUserResp> pageResult = nodeUserFoundationService.page(page);
return Optional.ofNullable(pageResult.getData()).orElseGet(Collections::emptyList);
}
@ -129,44 +96,6 @@ public class AutoAddWorkerLeavedTagJob extends BaseAutoOperatePersonLeavedTagJob
addLeavedTag(workspaceId, withoutClockedPersonIds);
}
@Override
Integer listAutoLeaveDaysConfig(Long workspaceId) {
return context.getWorkspaceDaysConfig().get(workspaceId);
}
private void initContext() {
context = new Context();
assembleDataScope(context);
assembleWorkspaceConfig(context);
}
private void assembleDataScope(Context context) {
CooperateShipQueryRepository.ListReq listReq = new CooperateShipQueryRepository.ListReq();
listReq.setWorkspaceTypes(INCLUDE_WORKSPACE_TYPES);
listReq.setIncludeCooperateTypes(INCLUDE_COOPERATE_TYPES);
listReq.setStatuses(INCLUDE_STATUS);
Map<Long, List<SaasCooperateShip>> dataScope = cooperateShipFoundationService.list(listReq).stream()
.collect(Collectors.groupingBy(SaasCooperateShip::getWorkspaceId));
context.setActiveProjectTeamAndGroups(dataScope);
}
private void assembleWorkspaceConfig(Context context) {
if (context.invalid()) {
return;
}
Map<Long, Integer> workspaceDaysConfig = Maps.newHashMap();
context.setWorkspaceDaysConfig(workspaceDaysConfig);
Set<Long> workspaceIds = context.getWorkspaceDaysConfig().keySet();
List<List<Long>> partition = Lists.partition(Lists.newArrayList(workspaceIds), 20);
for (List<Long> sub : partition) {
Map<Long, Integer> autoLeaveDaysConfigMap = workspaceGateway.listAutoLeaveDaysConfig(sub);
if (CollUtil.isEmpty(autoLeaveDaysConfigMap)) {
continue;
}
workspaceDaysConfig.putAll(autoLeaveDaysConfigMap);
}
}
private void addLeavedTag(Long workspaceId, List<Long> personIds) {
TagOperateReq param = new TagOperateReq();
param.setPersonIds(personIds);
@ -176,37 +105,4 @@ public class AutoAddWorkerLeavedTagJob extends BaseAutoOperatePersonLeavedTagJob
param.setOperateType(TagOperateEnum.ADD);
orgUserService.operateTag(param);
}
@Data
private static class Context {
private LocalDateTime startDateTime = LocalDateTime.now();
/**
* 在场的项目内班组和小组节点
* key: workspaceId
* value: 在场的项目内班组和小组节点列表
*/
private Map<Long, List<SaasCooperateShip>> activeProjectTeamAndGroups;
/**
* 开关开启的项目id集合
* key: workspaceId
* value: days
*/
private Map<Long, Integer> workspaceDaysConfig;
boolean invalid() {
return CollUtil.isEmpty(activeProjectTeamAndGroups);
}
Date getJoinedAtLe(Long workspaceId) {
Integer days = workspaceDaysConfig.get(workspaceId);
if (Objects.isNull(days)) {
return null;
}
LocalDateTime le = startDateTime.minusDays(days);
return Date.from(le.atZone(ZoneId.systemDefault()).toInstant());
}
}
}

View File

@ -7,19 +7,14 @@ import cn.axzo.orgmanax.infra.dao.nodeuser.repository.NodeUserExtraQueryReposito
import cn.axzo.orgmanax.infra.dao.nodeuser.repository.NodeUserExtraQueryRepository.NodeUserExtraResp;
import cn.axzo.orgmanax.server.nodeuser.foundation.NodeUserExtraFoundationService;
import cn.hutool.core.collection.CollUtil;
import com.google.common.collect.Maps;
import com.xxl.job.core.biz.model.ReturnT;
import com.xxl.job.core.handler.annotation.XxlJob;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
/**
@ -37,13 +32,9 @@ public class AutoClearPersonLeavedTagJob extends BaseAutoOperatePersonLeavedTagJ
@Resource
private NodeUserExtraFoundationService nodeUserExtraFoundationService;
private Context context;
@Override
@XxlJob("autoClearPersonLeavedTagJob")
public ReturnT<String> execute(String param) {
// init context
context = new Context();
doExecute(param);
return ReturnT.SUCCESS;
}
@ -53,17 +44,13 @@ public class AutoClearPersonLeavedTagJob extends BaseAutoOperatePersonLeavedTagJ
return LOG_PREFIX;
}
@Override
LocalDateTime startDateTimeOfJobExecution() {
return context.getStartDateTime();
}
@Override
List<NodeUserExtraResp> scrollList(long scrollIndex) {
String tag = personTagConfig.getLeaveTagNode().format(":");
NodeUserExtraQueryRepository.ListReq page = new NodeUserExtraQueryRepository.ListReq();
page.setIdLt(scrollIndex);
page.setTag(tag);
page.setWorkspaceIds(context.getWorkspaceIds());
page.setPageSize(MAX_CNT_ONCE);
page.setSort(Collections.singletonList(sortDesc("id")));
PageResp<NodeUserExtraQueryRepository.NodeUserExtraResp> pageResult = nodeUserExtraFoundationService.page(page);
@ -99,38 +86,4 @@ public class AutoClearPersonLeavedTagJob extends BaseAutoOperatePersonLeavedTagJ
param.setOperateType(TagOperateEnum.REMOVE);
orgUserService.operateTag(param);
}
@Override
Integer listAutoLeaveDaysConfig(Long workspaceId) {
// fetch from local cache first.
Integer days = context.getWorkspaceDaysConfig().get(workspaceId);
if (Objects.nonNull(days)) {
return days;
}
// fetch from attendance service.
Map<Long, Integer> map = workspaceGateway.listAutoLeaveDaysConfig(Collections.singletonList(workspaceId));
if (CollUtil.isEmpty(map)) {
return null;
}
// cache the config of this workspace
context.getWorkspaceDaysConfig().putAll(map);
// return days config
return context.getWorkspaceDaysConfig().get(workspaceId);
}
@Data
private static class Context {
/**
* start time of job execute
*/
private LocalDateTime startDateTime = LocalDateTime.now();
/**
* days configuration for add person tag of workspace.
* key: workspaceId
* value: days
*/
private Map<Long, Integer> workspaceDaysConfig = Maps.newHashMap();
}
}

View File

@ -11,18 +11,23 @@ import cn.hutool.core.collection.CollUtil;
import com.alibaba.fastjson.JSON;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.xxl.job.core.handler.IJobHandler;
import com.xxl.job.core.log.XxlJobLogger;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
/**
@ -33,7 +38,7 @@ import java.util.stream.Collectors;
@Slf4j
public abstract class BaseAutoOperatePersonLeavedTagJob<T> extends IJobHandler {
static final int MAX_CNT_ONCE = 4;
static final int MAX_CNT_ONCE = 200;
@Resource
PersonTagConfig personTagConfig;
@ -45,7 +50,11 @@ public abstract class BaseAutoOperatePersonLeavedTagJob<T> extends IJobHandler {
@Resource
WorkspaceGateway workspaceGateway;
Context context;
void doExecute(String param) {
// init context
context = Context.instance(param);
long scrollIndex = Long.MAX_VALUE;
info("start to scan org_user.");
// key: workspaceId value: records
@ -66,8 +75,6 @@ public abstract class BaseAutoOperatePersonLeavedTagJob<T> extends IJobHandler {
abstract String logPrefix();
abstract LocalDateTime startDateTimeOfJobExecution();
abstract List<T> scrollList(long scrollIndex);
abstract Long extractId(T record);
@ -78,8 +85,6 @@ public abstract class BaseAutoOperatePersonLeavedTagJob<T> extends IJobHandler {
abstract void handle(Long workspaceId, List<T> records, List<Long> clockedPersonIds);
abstract Integer listAutoLeaveDaysConfig(Long workspaceId);
private void cacheAndTrigger(Map<Long, List<T>> localCache, List<T> records) {
// grouping by workspaceId
Map<Long, List<T>> groupingByWorkspaceId = records.stream().collect(Collectors.groupingBy(this::extractWorkspaceId));
@ -134,6 +139,23 @@ public abstract class BaseAutoOperatePersonLeavedTagJob<T> extends IJobHandler {
}
}
private Integer listAutoLeaveDaysConfig(Long workspaceId) {
// fetch from local cache first.
Integer days = context.getWorkspaceDaysConfig().get(workspaceId);
if (Objects.nonNull(days)) {
return days;
}
// fetch from attendance service.
Map<Long, Integer> map = workspaceGateway.listAutoLeaveDaysConfig(Collections.singletonList(workspaceId));
if (CollUtil.isEmpty(map)) {
return null;
}
// cache the config of this workspace
context.getWorkspaceDaysConfig().putAll(map);
// return days config
return context.getWorkspaceDaysConfig().get(workspaceId);
}
private List<Long> findClockedPersons(Long workspaceId, Integer days, List<T> records) {
List<Long> personIds = CollUtil.map(records, this::extractPersonId, true);
if (CollUtil.isEmpty(personIds)) {
@ -148,10 +170,12 @@ public abstract class BaseAutoOperatePersonLeavedTagJob<T> extends IJobHandler {
}
private List<AttendanceClockRecordResp> listClockRecords(Long workspaceId, Integer days, List<Long> personIds) {
LocalDateTime to = startDateTimeOfJobExecution();
LocalDateTime to = context.getStartDateTime();
LocalDateTime from = to.minusDays(days);
AttendanceClockRecordListReq request = new AttendanceClockRecordListReq();
request.setPersonIds(personIds);
// only list worker clocked records
request.setUserType(AttendanceClockRecordListReq.USER_TYPE_WORKER);
request.setWorkspaceId(workspaceId);
request.setClockAtFrom(Date.from(from.atZone(ZoneOffset.systemDefault()).toInstant()));
request.setClockAtTo(Date.from(to.atZone(ZoneOffset.systemDefault()).toInstant()));
@ -169,4 +193,40 @@ public abstract class BaseAutoOperatePersonLeavedTagJob<T> extends IJobHandler {
log.error(msgFormat, args);
XxlJobLogger.log(msgFormat, args);
}
@Data
static class Context {
/**
* param of job
*/
private Set<Long> workspaceIds = Sets.newHashSet();
private LocalDateTime startDateTime = LocalDateTime.now();
/**
* days configuration for add person tag of workspace.
* key: workspaceId
* value: days
*/
private Map<Long, Integer> workspaceDaysConfig = Maps.newHashMap();
static Context instance(String param) {
Context context = new Context();
if (StringUtils.isNotBlank(param)) {
Context contextParam = JSON.parseObject(param, Context.class);
context.setWorkspaceIds(contextParam.getWorkspaceIds());
}
return context;
}
Date getJoinedAtLe(Long workspaceId) {
Integer days = workspaceDaysConfig.get(workspaceId);
if (Objects.isNull(days)) {
return null;
}
LocalDateTime le = startDateTime.minusDays(days);
return Date.from(le.atZone(ZoneId.systemDefault()).toInstant());
}
}
}