Merge branch 'feature/REQ-3714-zhh' into 'feature/REQ-3714'

Feature/req 3714 zhh

See merge request universal/infrastructure/backend/orgmanax!205
This commit is contained in:
张弘昊 2025-03-07 06:41:56 +00:00
commit 3d1010fa99
44 changed files with 2073 additions and 17 deletions

View File

@ -0,0 +1,41 @@
package cn.axzo.orgmanax.api.nodeuser.feign;
import cn.axzo.foundation.result.ApiResult;
import cn.axzo.orgmanax.dto.nodeuser.req.BatchDeleteNodeUserCheckReq;
import cn.axzo.orgmanax.dto.nodeuser.resp.BatchDeleteNodeUserCheckResp;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import java.util.List;
/**
* 部门相关基础API
*
* @author tanjie@axzo.cn
* @date 2024/12/2 15:40
*/
@FeignClient(
value = "orgmanax",
url = "${axzo.service.orgmanax:http://orgmanax:8080}")
public interface OrgNodeUserCheckApi {
/**
* 根据条件聚合查询节点用户
*
* @param req
* @return
*/
@PostMapping("/api/node-user/batchDelete/check/unit")
ApiResult<List<BatchDeleteNodeUserCheckResp>> checkUnit(@RequestBody @Validated BatchDeleteNodeUserCheckReq req);
/**
* 根据条件聚合查询节点用户
*
* @param req
* @return
*/
@PostMapping("/api/node-user/batchDelete/check/workspace")
ApiResult<List<BatchDeleteNodeUserCheckResp>> checkWorkspace(@RequestBody @Validated BatchDeleteNodeUserCheckReq req);
}

View File

@ -1,6 +1,8 @@
package cn.axzo.orgmanax.dto.node.dto;
import cn.axzo.foundation.result.ResultCode;
import cn.axzo.orgmanax.dto.cooperateship.dto.OrgCooperateShipDTO;
import cn.axzo.orgmanax.dto.node.enums.NodeTypeEnum;
import com.alibaba.fastjson.JSONObject;
import lombok.AllArgsConstructor;
import lombok.Data;
@ -10,6 +12,7 @@ import lombok.experimental.SuperBuilder;
import java.io.Serializable;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
@NoArgsConstructor
@ -154,4 +157,18 @@ public class OrgNodeDTO implements Serializable {
}
return (T) Optional.ofNullable(profile).map(p -> JSONObject.parseObject(p.toString(), clazz)).orElse(null);
}
/**
* 获取项目内小组节点配置信息
* @return 是否合作小组true 独立false 非独立
*/
public Boolean independentGroup() {
if (!Objects.equals(this.nodeType, NodeTypeEnum.PROJECT_GROUP.getValue())) {
throw ResultCode.INVALID_PARAMS.toException("小组节点类型错误");
}
if (Objects.nonNull(this.profile) && !this.profile.isEmpty()) {
return this.profile.getBooleanValue("independentGroup");
}
return null;
}
}

View File

@ -0,0 +1,37 @@
package cn.axzo.orgmanax.dto.nodeuser.enums;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Getter;
import java.util.Arrays;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
@Getter
@AllArgsConstructor(access = AccessLevel.PRIVATE)
public enum CheckInfoTypeEnum {
SUPER_ADMIN(1, "超级管理员", "【%s】是超级管理员无法删除", 0),
IN_PROJECT(2, "在项目中", "【%s】在项目中无法删除", 0),
TEAM_LEADER(3, "班组长", "【%s】是班组长无法删除", 0),
PROJECT_GROUP_LEADER(4, "合作小组小组长", "【%s】是项目组组长无法删除", 0),
NOT_IN_JURISDICTION(5, "不在管辖范围", "【%s】,不在你的管辖范围,无法删除!", 0),
ANY_ADMIN(6, "单位负责人", "【%s】是项目单位负责人无法删除", 0),
TASK_ORDER(7, "任务单", "当前人员有未完成的任务单:%d单。无法删除", 2),
RECTIFY_ORDERS(8, "整改单", "当前人员有未完成的整改单:%d单。无法删除", 6),
ACCEPTANCE_PROCESS(9, "验收流程", "当前人员有未完成的验收单:%d单。无法删除", 7);
private final Integer value;
private final String desc;
private final String msg;
private final Integer thirdType;
private static final Map<Integer, CheckInfoTypeEnum> thirdTypeMap = Arrays.stream(CheckInfoTypeEnum.values())
.collect(Collectors.toMap(CheckInfoTypeEnum::getThirdType, Function.identity(), (key1, key2) -> key2));
public static CheckInfoTypeEnum getByThirdType(Integer type) {
return thirdTypeMap.get(type);
}
}

View File

@ -0,0 +1,36 @@
package cn.axzo.orgmanax.dto.nodeuser.req;
import lombok.Data;
import javax.validation.constraints.NotNull;
import java.util.List;
import java.util.Set;
/**
* @author : zhanghonghao@axzo.cn
* @since : 2025/3/6
*/
@Data
public class BatchDeleteNodeUserCheckReq {
/**
* personIds
*/
@NotNull(message = "personIds不可以为空")
private Set<Long> personIds;
private Long workspaceId;
private Long ouId;
/**
* 删除项目人员的时候传入
* 节点ID
*/
private Long nodeId;
/**
* 操作者ID
*/
private Long operatorId;
}

View File

@ -1,12 +1,7 @@
package cn.axzo.orgmanax.dto.nodeuser.req;
import com.alibaba.fastjson.JSONObject;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.*;
import lombok.experimental.SuperBuilder;
@NoArgsConstructor
@ -24,7 +19,9 @@ public class ProcessNodeUserReq {
@Getter
public enum Action {
CREATE("创建", "createNodeUserProcessor"),
UPDATE("普通更新", "updateNodeUserProcessor");
UPDATE("普通更新", "updateNodeUserProcessor"),
UNIT_DELETE("删除单位人员", "unitDeleteNodeUserProcessor"),
WORKSPACE_DELETE("删除项目人员", "workspaceDeleteNodeUserProcessor");
private final String desc;
private final String processor;

View File

@ -0,0 +1,30 @@
package cn.axzo.orgmanax.dto.nodeuser.resp;
import cn.axzo.orgmanax.dto.nodeuser.enums.CheckInfoTypeEnum;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
/**
* @author : zhanghonghao@axzo.cn
* @since : 2025/3/6
*/
@Data
public class BatchDeleteNodeUserCheckResp {
private Long personId;
private List<CheckFailInfo> failInfos;
@Data
@AllArgsConstructor
@NoArgsConstructor
public static class CheckFailInfo {
private CheckInfoTypeEnum type;
private Integer count;
}
}

View File

@ -0,0 +1,43 @@
package cn.axzo.orgmanax.dto.project.worker.req;
import cn.axzo.foundation.page.PageReqV2;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.experimental.SuperBuilder;
import java.util.List;
/**
* @author : zhanghonghao@axzo.cn
* @since : 2025/3/6
*/
@EqualsAndHashCode(callSuper = true)
@NoArgsConstructor
@AllArgsConstructor
@Data
@SuperBuilder
public class ListOrgProjectWorkerReq extends PageReqV2 {
/**
* 工作台ID
*/
private Long workspaceId;
/**
* 总包ID
*/
private Long entId;
/**
* 所属单位id
*/
private Long organizationalUnitId;
/**
* 工人personId
*/
private List<Long> workerPersonIds;
}

View File

@ -0,0 +1,10 @@
package cn.axzo.orgmanax.infra.client.karma;
import java.util.List;
import java.util.Map;
import java.util.Set;
public interface KarmaThirdApiClient {
Map<Long, List<ThirdCheckFailResp>> getThirdCheckFail(Long workspaceId, Set<Long> personIds);
}

View File

@ -0,0 +1,17 @@
package cn.axzo.orgmanax.infra.client.karma;
import cn.axzo.orgmanax.dto.nodeuser.enums.CheckInfoTypeEnum;
import lombok.Data;
/**
* @author : zhanghonghao@axzo.cn
* @since : 2025/3/7
*/
@Data
public class ThirdCheckFailResp {
private CheckInfoTypeEnum type;
private Integer count;
}

View File

@ -1,5 +1,8 @@
package cn.axzo.orgmanax.infra.client.workspace;
import cn.axzo.apollo.workspace.api.v2.participating.feign.ParticipatingUnitV2Api;
import cn.axzo.apollo.workspace.api.v2.participating.req.ParticipatingUnitListReq;
import cn.axzo.apollo.workspace.api.v2.participating.resp.ParticipatingUnitResp;
import cn.axzo.apollo.workspace.api.v2.workspace.feign.WorkspaceV2Api;
import cn.axzo.apollo.workspace.api.v2.workspace.req.ListWorkspaceReq;
import cn.axzo.apollo.workspace.api.v2.workspace.req.WorkspaceDetailReq;
@ -15,6 +18,7 @@ import org.springframework.stereotype.Component;
import java.util.List;
/**
*
*/
@RequiredArgsConstructor
@Component
@ -23,8 +27,11 @@ public class WorkspaceGateway {
private final WorkspaceV2Api workspaceV2Api;
private final ParticipatingUnitV2Api participatingUnitV2Api;
/**
* 更新和新增
*
* @param request
* @return
*/
@ -34,6 +41,7 @@ public class WorkspaceGateway {
/**
* 获取详情
*
* @param request
* @return
*/
@ -43,10 +51,15 @@ public class WorkspaceGateway {
/**
* 获取详情
*
* @param request
* @return
*/
public List<WorkspaceDTO> list(ListWorkspaceReq request) {
return RpcWrapper.wrapApiResult(() -> workspaceV2Api.listV2(request));
}
public List<ParticipatingUnitResp> listParticipatingUnits(ParticipatingUnitListReq unitListReq) {
return RpcWrapper.wrapApiResult(() -> participatingUnitV2Api.list(unitListReq));
}
}

View File

@ -18,6 +18,8 @@ public interface NodeUserUpsertRepository {
OrganizationalNodeUser update(UpdateReq node);
void batchDelete(Set<Long> ids);
@EqualsAndHashCode(callSuper = true)
@NoArgsConstructor
@AllArgsConstructor

View File

@ -5,11 +5,15 @@ import cn.axzo.orgmanax.infra.dao.nodeuser.dao.NodeUserDao;
import cn.axzo.orgmanax.infra.dao.nodeuser.entity.OrganizationalNodeUser;
import cn.axzo.orgmanax.infra.dao.nodeuser.repository.NodeUserUpsertRepository;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.extension.conditions.update.LambdaUpdateChainWrapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import java.util.Date;
import java.util.Set;
@Service
@RequiredArgsConstructor
@Slf4j
@ -32,4 +36,14 @@ public class NodeUserUpsertRepositoryImpl implements NodeUserUpsertRepository {
wrapper.update(req);
return nodeUserDao.getById(req.getId());
}
}
@Override
public void batchDelete(Set<Long> ids) {
Date date = new Date();
nodeUserDao.lambdaUpdate().in(OrganizationalNodeUser::getId, ids)
.eq(OrganizationalNodeUser::getIsDelete, 0)
.setSql("is_delete = id, leave_at = CASE WHEN leave_at IS NULL THEN '" + DateUtil.formatDateTime(date) + "' ELSE leave_at END")
.update();
}
}

View File

@ -1,4 +1,13 @@
package cn.axzo.orgmanax.infra.dao.orguser.repository;
import cn.axzo.orgmanax.infra.dao.orguser.entity.OrgUser;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
public interface OrgUserUpsertRepository {
}
@Transactional(rollbackFor = Throwable.class)
void batchUpdate(List<OrgUser> orgUsers);
}

View File

@ -1,10 +1,22 @@
package cn.axzo.orgmanax.infra.dao.orguser.repository.impl;
import cn.axzo.orgmanax.infra.dao.orguser.dao.OrgUserDao;
import cn.axzo.orgmanax.infra.dao.orguser.entity.OrgUser;
import cn.axzo.orgmanax.infra.dao.orguser.repository.OrgUserUpsertRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
@RequiredArgsConstructor
public class OrgUserUpsertRepositoryImpl implements OrgUserUpsertRepository {
}
private final OrgUserDao orgUserDao;
@Override
public void batchUpdate(List<OrgUser> orgUsers) {
orgUserDao.updateBatchById(orgUsers);
}
}

View File

@ -0,0 +1,16 @@
package cn.axzo.orgmanax.infra.dao.project.worker.dao;
import cn.axzo.orgmanax.infra.dao.project.worker.entity.OrgProjectWorker;
import cn.axzo.orgmanax.infra.dao.project.worker.mapper.OrgProjectWorkerMapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Repository;
/**
* @author : zhanghonghao@axzo.cn
* @since : 2025/1/8
*/
@Repository
public class OrgProjectWorkerDao extends ServiceImpl<OrgProjectWorkerMapper, OrgProjectWorker> {
}

View File

@ -0,0 +1,148 @@
package cn.axzo.orgmanax.infra.dao.project.worker.entity;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.experimental.SuperBuilder;
import java.io.Serializable;
import java.util.Date;
/**
* 项目内工人表实体类
*
* @author chenliang@axzo.cn
* @since 2022-07-20 15:01:43
*/
@TableName(value = "org_project_worker", autoResultMap = true)
@Data
@SuperBuilder
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode(callSuper = false)
public class OrgProjectWorker implements Serializable {
private static final long serialVersionUID = 260206461965825922L;
@TableField("id")
private Long id;
/**
* 工作台ID
*/
@TableField("workspace_id")
private Long workspaceId;
/**
* 总包ID
*/
@TableField("ent_id")
private Long entId;
/**
* 所属单位id
*/
@TableField("organizational_unit_id")
private Long organizationalUnitId;
/**
* 所属单位类型: 1:总包 4:专业分包 5:劳务分包
*/
@TableField("organizational_unit_type")
private Integer organizationalUnitType;
/**
* 项目内班组ID
*/
@TableField("project_team_id")
private Long projectTeamId;
/**
* 工人personId
*/
@TableField("worker_person_id")
private Long workerPersonId;
/**
* 工人身份ID
*/
@TableField("worker_identity_id")
private Long workerIdentityId;
/**
* 状态0未激活 1已激活 3已退场
*/
@TableField("status")
private Integer status;
/**
* 工种类别
*/
@TableField("profession_category_name")
private String professionCategoryName;
/**
* 入场时间
*/
@TableField("join_at")
private Date joinAt;
/**
* 离场时间
*/
@TableField("resign_at")
private Date resignAt;
/**
* 是否删除 0:未删除 其他:已删除
*/
@TableField("is_delete")
private Long isDelete;
/**
* 创建时间
*/
@TableField("create_at")
private Date createAt;
@TableField("update_at")
private Date updateAt;
/**
* 最后一次进工地的时间进场打卡更新
* 进场打卡更新
*/
@TableField("last_check_in_time")
private Date lastCheckInTime;
/**
* 最后一次出工地的时间出场打卡更新
*/
@TableField("last_check_out_time")
private Date lastCheckOutTime;
/**
* 工人施工开始时间工人所有任务单中最早开始时间
*/
private Date constructionStartTime;
/**
* 工人施工结束时间
*/
private Date constructionEndTime;
/**
* 在岗待岗
*/
private Integer occupyStatus;
/**
* 推送未备案消息次数
*/
@TableField("push_supervision_msg_count")
private Integer pushSupervisionMsgCount;
}

View File

@ -0,0 +1,10 @@
package cn.axzo.orgmanax.infra.dao.project.worker.mapper;
import cn.axzo.orgmanax.infra.dao.project.worker.entity.OrgProjectWorker;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface OrgProjectWorkerMapper extends BaseMapper<OrgProjectWorker> {
}

View File

@ -0,0 +1,100 @@
package cn.axzo.orgmanax.infra.dao.project.worker.repositrory;
import cn.axzo.foundation.dao.support.wrapper.CriteriaField;
import cn.axzo.foundation.dao.support.wrapper.Operator;
import cn.axzo.foundation.page.PageReqV2;
import cn.axzo.foundation.page.PageResp;
import cn.axzo.orgmanax.infra.dao.project.worker.entity.OrgProjectWorker;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import com.google.common.base.Preconditions;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.experimental.SuperBuilder;
import java.util.List;
import java.util.Optional;
import java.util.Set;
public interface OrgProjectWorkerQueryRepository {
PageResp<OrgProjectWorkerResp> page(ListReq req);
default List<OrgProjectWorkerResp> list(ListReq req) {
return page(req).getData();
}
default OrgProjectWorkerResp one(OneReq req) {
return oneOpt(req).orElse(null);
}
default Optional<OrgProjectWorkerResp> oneOpt(OneReq req) {
req.check();
ListReq page = BeanUtil.toBean(req, ListReq.class);
page.setPage(1);
page.setPageSize(1);
return page(page).getData().stream().findFirst();
}
@NoArgsConstructor
@AllArgsConstructor
@Data
@SuperBuilder
class OneReq {
private Long id;
private Set<Long> ids;
public void check() {
Preconditions.checkArgument(id != null || CollUtil.isNotEmpty(ids), "参数异常");
}
}
@EqualsAndHashCode(callSuper = true)
@NoArgsConstructor
@AllArgsConstructor
@Data
@SuperBuilder
class ListReq extends PageReqV2 {
/**
* 工作台ID
*/
@CriteriaField
private Long workspaceId;
/**
* 所属单位id
*/
@CriteriaField
private Long organizationalUnitId;
/**
* 状态
*/
@CriteriaField
private Integer status;
/**
* 工人personId
*/
@CriteriaField(field = "workerPersonId", operator = Operator.IN)
private List<Long> workerPersonIds;
@CriteriaField(ignore = true)
private Boolean includeDeleted;
}
@EqualsAndHashCode(callSuper = true)
@NoArgsConstructor
@AllArgsConstructor
@Data
@SuperBuilder
class OrgProjectWorkerResp extends OrgProjectWorker {
// 按需扩展字段占个位避免报错
private String todo;
}
}

View File

@ -0,0 +1,13 @@
package cn.axzo.orgmanax.infra.dao.project.worker.repositrory;
import cn.axzo.orgmanax.infra.dao.project.worker.entity.OrgProjectWorker;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
public interface OrgProjectWorkerUpsertRepository {
@Transactional(rollbackFor = Throwable.class)
void batchUpdate(List<OrgProjectWorker> orgProjectWorkers);
}

View File

@ -0,0 +1,40 @@
package cn.axzo.orgmanax.infra.dao.project.worker.repositrory.impl;
import cn.axzo.foundation.dao.support.converter.PageConverter;
import cn.axzo.foundation.dao.support.mysql.QueryWrapperHelper;
import cn.axzo.foundation.page.PageResp;
import cn.axzo.orgmanax.infra.dao.project.worker.dao.OrgProjectWorkerDao;
import cn.axzo.orgmanax.infra.dao.project.worker.entity.OrgProjectWorker;
import cn.axzo.orgmanax.infra.dao.project.worker.repositrory.OrgProjectWorkerQueryRepository;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.BooleanUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
/**
* @author : zhanghonghao@axzo.cn
* @since : 2025/3/6
*/
@Service
@RequiredArgsConstructor
@Slf4j
public class OrgProjectWorkerQueryRepositoryImpl implements OrgProjectWorkerQueryRepository {
private final OrgProjectWorkerDao orgProjectWorkerDao;
@Override
public PageResp<OrgProjectWorkerResp> page(ListReq req) {
IPage<OrgProjectWorker> page = PageConverter.toMybatis(req, OrgProjectWorker.class);
QueryWrapper<OrgProjectWorker> wrapper = QueryWrapperHelper.fromBean(req, OrgProjectWorker.class);
if (!BooleanUtil.isTrue(req.getIncludeDeleted())) {
wrapper.eq("is_delete", 0);
}
IPage<OrgProjectWorkerQueryRepository.OrgProjectWorkerResp> results = orgProjectWorkerDao.page(page, wrapper)
.convert(e -> BeanUtil.toBean(e, OrgProjectWorkerQueryRepository.OrgProjectWorkerResp.class));
return (PageResp<OrgProjectWorkerQueryRepository.OrgProjectWorkerResp>) PageConverter.toResp(results);
}
}

View File

@ -0,0 +1,28 @@
package cn.axzo.orgmanax.infra.dao.project.worker.repositrory.impl;
import cn.axzo.orgmanax.infra.dao.project.worker.dao.OrgProjectWorkerDao;
import cn.axzo.orgmanax.infra.dao.project.worker.entity.OrgProjectWorker;
import cn.axzo.orgmanax.infra.dao.project.worker.repositrory.OrgProjectWorkerUpsertRepository;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* @author : zhanghonghao@axzo.cn
* @since : 2025/3/6
*/
@Service
@RequiredArgsConstructor
@Slf4j
public class OrgProjectWorkerUpsertRepositoryImpl implements OrgProjectWorkerUpsertRepository {
private final OrgProjectWorkerDao orgProjectWorkerDao;
@Override
public void batchUpdate(List<OrgProjectWorker> orgProjectWorkers) {
orgProjectWorkerDao.updateBatchById(orgProjectWorkers);
}
}

View File

@ -0,0 +1,50 @@
package cn.axzo.orgmanax.integration.sdk.karma;
import cn.axzo.karma.client.feign.team.ThirdApiCheckServiceApi;
import cn.axzo.karma.client.model.request.ThirdApiPersonNormalCheckReq;
import cn.axzo.karma.client.model.vo.OpFailVO;
import cn.axzo.orgmanax.dto.nodeuser.enums.CheckInfoTypeEnum;
import cn.axzo.orgmanax.infra.client.karma.KarmaThirdApiClient;
import cn.axzo.orgmanax.infra.client.karma.ThirdCheckFailResp;
import cn.axzo.orgmanax.integration.core.RpcWrapper;
import cn.hutool.core.collection.CollUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import java.util.*;
import java.util.stream.Collectors;
/**
* @author : zhanghonghao@axzo.cn
* @since : 2025/3/7
*/
@Slf4j
@Component
@RequiredArgsConstructor
public class KarmaThirdApiClientImpl implements KarmaThirdApiClient {
private final ThirdApiCheckServiceApi thirdApiCheckServiceApi;
@Override
public Map<Long, List<ThirdCheckFailResp>> getThirdCheckFail(Long workspaceId, Set<Long> personIds) {
ThirdApiPersonNormalCheckReq checkReq = new ThirdApiPersonNormalCheckReq();
checkReq.setWorkspaceId(workspaceId);
checkReq.setPersonIdList(new ArrayList<>(personIds));
Map<Long, List<OpFailVO>> checkMap = RpcWrapper.commonRes(() -> thirdApiCheckServiceApi.thirdApiNormalCheckPerson(checkReq));
if (CollUtil.isEmpty(checkMap)) {
return Collections.emptyMap();
}
Map<Long, List<ThirdCheckFailResp>> failInfoMap = new HashMap<>();
checkMap.forEach((key, opFailVOs) -> {
List<ThirdCheckFailResp> personList = opFailVOs.stream().map(opFailVO -> {
ThirdCheckFailResp thirdCheckFailResp = new ThirdCheckFailResp();
thirdCheckFailResp.setType(CheckInfoTypeEnum.getByThirdType(opFailVO.getType()));
thirdCheckFailResp.setCount(opFailVO.getCount());
return thirdCheckFailResp;
}).collect(Collectors.toList());
failInfoMap.put(key, personList);
});
return failInfoMap;
}
}

View File

@ -0,0 +1,62 @@
package cn.axzo.orgmanax.server.mq;
import cn.axzo.foundation.event.support.Event;
import cn.axzo.orgmanax.infra.dao.nodeuser.entity.OrganizationalNodeUser;
import cn.axzo.orgmanax.server.mq.enums.MQEventEnum;
import com.alibaba.fastjson.JSONObject;
import com.google.common.base.Preconditions;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.apache.commons.lang3.ObjectUtils;
import java.io.Serializable;
/**
* OrganizationalNodeUser 变更事件(新增/修改/删除)
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class OrganizationalNodeUserUpsertedPayload implements Serializable {
private OrganizationalNodeUser newValue;
private OrganizationalNodeUser oldValue;
private JSONObject ext;
public Long getTopNodeId() {
return ObjectUtils.firstNonNull(oldValue, newValue).getTopNodeId();
}
public Long getPersonId() {
return ObjectUtils.firstNonNull(oldValue, newValue).getPersonId();
}
public Long getIdentityId() {
return ObjectUtils.firstNonNull(oldValue, newValue).getIdentityId();
}
public Integer getIdentityType() {
return ObjectUtils.firstNonNull(oldValue, newValue).getIdentityType();
}
public static Event from(OrganizationalNodeUser newValue,
OrganizationalNodeUser oldValue,
String operator, JSONObject ext) {
Preconditions.checkArgument(ObjectUtils.anyNotNull(newValue, oldValue));
return Event.builder()
.shardingKey(ObjectUtils.firstNonNull(newValue, oldValue).getId() + "")
.targetId(ObjectUtils.firstNonNull(newValue, oldValue).getId() + "")
.targetType(MQEventEnum.NODE_USER_UPSERTED.getModel())
.eventCode(new Event.EventCode(MQEventEnum.NODE_USER_UPSERTED.getModel(), MQEventEnum.NODE_USER_UPSERTED.getTag()))
.operatorId(operator)
.data(OrganizationalNodeUserUpsertedPayload.builder()
.newValue(newValue)
.oldValue(oldValue)
.ext(ext)
.build())
.build();
}
}

View File

@ -0,0 +1,65 @@
package cn.axzo.orgmanax.server.mq.enums;
import cn.axzo.foundation.event.support.Event;
import lombok.Getter;
@Getter
public enum MQEventEnum {
NODE_CREATE("node", "node-create", "节点创建"),
NODE_UPDATE("node", "node-update", "节点修改"),
NODE_DELETE("node", "node-delete", "节点删除"),
NODE_USER_CREATE("node-user", "node-user-create", "节点用户创建"),
NODE_USER_UPDATE("node-user", "node-user-update", "节点用户修改"),
NODE_USER_DELETE("node-user", "node-user-delete", "节点用户删除"),
NODE_USER_UPSERTED("node-user", "node-user-upserted", "节点用户更新"),
NODE_USER_VERIFY("profile", "verify-success", "节点用户实名认证"),
WORKSPACE_USER_CHANGED("workspace-user", "workspace-user-changed", "项目用户变更"),
UNIT_CREATE("unit", "unit-create", "单位创建"),
UNIT_UPDATE("unit", "unit-update", "单位修改"),
// updated 事件会将 oldnew发出来
UNIT_UPDATED("unit", "unit-updated", "单位修改"),
UNIT_DELETE("unit", "unit-delete", "单位删除"),
INDUSTRY_DICT_CHANGE("industry-dict", "industry-dict-change", "行业字典变更"),
COOPERATE_SHIP_CREATE_OR_UPDATE("cooperate-ship", "cooperate-ship-create-or-update", "创建或更新协作关系"),
COOPERATE_SHIP_RESIGN("cooperate-ship", "cooperate-ship-resign", "退场"),
PERSON_TAG_BATCH_UPDATED("person-tag", "person-tag-batch-upserted", "批量修改用户标签"),
PROJECT_WORKER_RESIGN("project-worker", "project-worker-resign", "工人退场"),
ORG_USER_MOVEMENT("org-user", "org-user-movement", "用户组织异动"),
ORG_NODE_USER_CHANGED("org-user", "org-node-user-change", "用户人岗架异动"),
COOPERATE_SHIP_UPSERT("cooperate-ship", "cooperate-ship-upsert", "创建或更新协作关系"),
SAAS_ROLE_UPSERT("saas-role", "saas-role-upsert", "更新角色信息"),
/**
* 小组
*/
PROJECT_GROUP_CHANGE_LEADER("group","project-group-chang-leader","项目小组更换小组长"),
GROUP_CREATE("group","group-create","项目小组组创建"),
GROUP_DISSOLVE("group","group-dissolve","项目小组组解散")
;
private final String model;
private final String tag;
private final String desc;
private final Event.EventCode eventCode;
MQEventEnum(String model, String tag, String desc) {
this.eventCode = Event.EventCode.builder()
.module(model)
.name(tag)
.build();
this.model = model;
this.tag = tag;
this.desc = desc;
}
}

View File

@ -0,0 +1,71 @@
package cn.axzo.orgmanax.server.mq.producer;
import cn.axzo.foundation.event.support.Event;
import cn.axzo.foundation.event.support.producer.EventProducer;
import cn.axzo.orgmanax.dto.common.util.NumberUtil;
import cn.axzo.orgmanax.dto.orguser.event.OrgUserStatusChangedEvent;
import cn.axzo.orgmanax.server.mq.enums.MQEventEnum;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.extra.spring.SpringUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.stereotype.Component;
import java.util.Collection;
import java.util.Objects;
/**
* @author luofu
* @version 1.0
* @date 2024/10/31
*/
@Slf4j
@Component
public class OrgUserChangedEventProducer implements InitializingBean {
private static final String EVENT_INVALID = "the event is invalid. {}";
private static EventProducer<?> eventProducer;
public static void sendStatusEvent(OrgUserStatusChangedEvent event) {
if (isInvalid(event)) {
log.info(EVENT_INVALID, event);
return;
}
//生产消息
eventProducer.send(map(event));
}
public static void batchSendStatusEvents(Collection<OrgUserStatusChangedEvent> events) {
if (CollUtil.isEmpty(events)) {
log.info("the events is empty.");
return;
}
events.forEach(OrgUserChangedEventProducer::sendStatusEvent);
}
public static boolean isInvalid(OrgUserStatusChangedEvent eventData) {
return Objects.isNull(eventData)
|| NumberUtil.isNotPositiveNumber(eventData.getPersonId())
|| NumberUtil.isNotPositiveNumber(eventData.getOuId())
|| NumberUtil.isNotPositiveNumber(eventData.getWorkspaceId())
|| Objects.isNull(eventData.getStatusCode())
|| NumberUtil.isNotPositiveNumber(eventData.getTransferTimestamp());
}
private static Event map(OrgUserStatusChangedEvent event) {
MQEventEnum mqEvent = MQEventEnum.ORG_USER_MOVEMENT;
return Event.builder()
.shardingKey(String.valueOf(event.getPersonId()))
.targetType(mqEvent.getModel())
.eventCode(mqEvent.getEventCode())
.data(event)
.build();
}
@Override
public void afterPropertiesSet() throws Exception {
eventProducer = SpringUtil.getBean(EventProducer.class);
}
}

View File

@ -0,0 +1,34 @@
package cn.axzo.orgmanax.server.nodeuser.controller;
import cn.axzo.foundation.result.ApiResult;
import cn.axzo.orgmanax.api.nodeuser.feign.OrgNodeUserCheckApi;
import cn.axzo.orgmanax.dto.nodeuser.req.BatchDeleteNodeUserCheckReq;
import cn.axzo.orgmanax.dto.nodeuser.resp.BatchDeleteNodeUserCheckResp;
import cn.axzo.orgmanax.server.nodeuser.service.NodeUserCheckService;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
/**
* @author : zhanghonghao@axzo.cn
* @since : 2025/3/6
*/
@RestController
@RequestMapping
@RequiredArgsConstructor
public class NodeUserCheckController implements OrgNodeUserCheckApi {
private final NodeUserCheckService nodeUserCheckService;
@Override
public ApiResult<List<BatchDeleteNodeUserCheckResp>> checkUnit(BatchDeleteNodeUserCheckReq req) {
return ApiResult.success(nodeUserCheckService.checkUnit(req));
}
@Override
public ApiResult<List<BatchDeleteNodeUserCheckResp>> checkWorkspace(BatchDeleteNodeUserCheckReq req) {
return ApiResult.success(nodeUserCheckService.checkWorkspace(req));
}
}

View File

@ -0,0 +1,30 @@
package cn.axzo.orgmanax.server.nodeuser.dto;
import cn.axzo.foundation.result.ResultCode;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.apache.commons.lang3.ObjectUtils;
import java.util.Set;
/**
* @author : zhanghonghao@axzo.cn
* @since : 2025/3/7
*/
@NoArgsConstructor
@AllArgsConstructor
@Data
@Builder
public class CheckUserOperateParam {
private Long operatorId;
private Set<Long> personIds;
private Long workspaceId;
public void check() {
if (ObjectUtils.anyNull(personIds, workspaceId, operatorId)) {
throw ResultCode.INVALID_PARAMS.toException("参数异常,您暂无权限!");
}
}
}

View File

@ -1,12 +1,10 @@
package cn.axzo.orgmanax.server.nodeuser.foundation;
import cn.axzo.orgmanax.dto.nodeuser.dto.NodeUserDTO;
import cn.axzo.orgmanax.dto.nodeuser.req.SearchEntNodeUserReq;
import cn.axzo.orgmanax.dto.nodeuser.resp.SearchEntNodeUserResp;
import cn.axzo.orgmanax.infra.dao.nodeuser.entity.OrganizationalNodeUser;
import cn.axzo.orgmanax.infra.dao.nodeuser.repository.NodeUserQueryRepository;
import cn.axzo.orgmanax.infra.dao.orgjob.entity.OrgJob;
import cn.axzo.orgmanax.server.nodeuser.foundation.req.NodeUserCreate;
import cn.axzo.orgmanax.server.nodeuser.foundation.req.NodeUserDelete;
import cn.axzo.orgmanax.server.nodeuser.foundation.req.NodeUserUpdate;
import org.springframework.transaction.annotation.Transactional;
@ -32,6 +30,15 @@ public interface NodeUserFoundationService {
@Transactional(rollbackFor = Throwable.class)
OrganizationalNodeUser update(NodeUserUpdate req);
/**
* 该接口为更新的收口接口业务使用的时候需要自行做业务判断
*
* @param req
* @return
*/
@Transactional(rollbackFor = Throwable.class)
List<OrganizationalNodeUser> delete(NodeUserDelete req);
/**
* 根据岗位进行过滤
* @param nodeUsers

View File

@ -1,15 +1,19 @@
package cn.axzo.orgmanax.server.nodeuser.foundation.impl;
import cn.axzo.apollo.workspace.api.v2.workspace.req.WorkspaceDetailReq;
import cn.axzo.apollo.workspace.api.v2.workspace.resp.WorkspaceDetailResp;
import cn.axzo.foundation.event.support.Event;
import cn.axzo.foundation.event.support.producer.EventProducer;
import cn.axzo.foundation.exception.Axssert;
import cn.axzo.orgmanax.common.config.BizResultCode;
import cn.axzo.orgmanax.dto.common.util.NumberUtil;
import cn.axzo.orgmanax.dto.nodeuser.enums.NodeUserTypeEnum;
import cn.axzo.orgmanax.dto.nodeuser.req.SearchEntNodeUserReq;
import cn.axzo.orgmanax.dto.nodeuser.resp.SearchEntNodeUserResp;
import cn.axzo.orgmanax.infra.client.profile.PersonProfileGateway;
import cn.axzo.orgmanax.infra.client.profile.dto.ProfileGetIdentityProfileLiteResp;
import cn.axzo.orgmanax.infra.client.profile.dto.ProfilePersonResp;
import cn.axzo.orgmanax.infra.client.workspace.WorkspaceGateway;
import cn.axzo.orgmanax.infra.dao.cooperateship.entity.SaasCooperateShip;
import cn.axzo.orgmanax.infra.dao.cooperateship.repository.CooperateShipQueryRepository;
import cn.axzo.orgmanax.infra.dao.node.entity.OrganizationalNode;
@ -20,21 +24,30 @@ import cn.axzo.orgmanax.infra.dao.nodeuser.repository.NodeUserQueryRepository;
import cn.axzo.orgmanax.infra.dao.nodeuser.repository.NodeUserUpsertRepository;
import cn.axzo.orgmanax.infra.dao.orgjob.entity.OrgJob;
import cn.axzo.orgmanax.infra.dao.orgjob.repository.OrgJobQueryRepository;
import cn.axzo.orgmanax.infra.dao.unit.repository.UnitQueryRepository;
import cn.axzo.orgmanax.server.mq.OrganizationalNodeUserUpsertedPayload;
import cn.axzo.orgmanax.server.node.event.inner.NodeEventType;
import cn.axzo.orgmanax.server.nodeuser.event.inner.payload.NodeUserUpsertedPayload;
import cn.axzo.orgmanax.server.nodeuser.foundation.NodeUserFoundationService;
import cn.axzo.orgmanax.server.nodeuser.foundation.req.NodeUserCreate;
import cn.axzo.orgmanax.server.nodeuser.foundation.req.NodeUserDelete;
import cn.axzo.orgmanax.server.nodeuser.foundation.req.NodeUserUpdate;
import cn.axzo.orgmanax.server.orguser.foundation.OrgUserFoundationService;
import cn.axzo.orgmanax.server.orguser.foundation.req.OrgUserWithdrawOrQuitReq;
import cn.axzo.orgmanax.server.project.worker.foundation.OrgProjectWorkerFoundationService;
import cn.axzo.orgmanax.server.project.worker.foundation.req.OrgProjectWorkerWithdrawReq;
import cn.axzo.orgmanax.server.service.OperateLogService;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.BooleanUtil;
import com.alibaba.fastjson.JSONObject;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.ObjectUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.Collection;
import java.util.List;
import java.util.Objects;
import java.util.*;
import java.util.stream.Collectors;
/**
* @author tanjie@axzo.cn
@ -52,7 +65,10 @@ public class NodeUserFoundationServiceImpl implements NodeUserFoundationService
private final PersonProfileGateway profileGateway;
private final OrganizationalNodeUserMapper organizationalNodeUserMapper;
private final OrgJobQueryRepository orgJobQueryRepository;
private final UnitQueryRepository unitQueryRepository;
private final WorkspaceGateway workspaceGateway;
private final OrgUserFoundationService orgUserFoundationService;
private final OrgProjectWorkerFoundationService orgProjectWorkerFoundationService;
/**
* 创建部门标准接口
@ -142,6 +158,72 @@ public class NodeUserFoundationServiceImpl implements NodeUserFoundationService
return nodeUserUpsertRepository.update(updateReq);
}
@Override
public List<OrganizationalNodeUser> delete(NodeUserDelete req) {
checkDeleteReq(req);
List<NodeUserQueryRepository.NodeUserResp> list = nodeUserQueryRepository.list(
NodeUserQueryRepository.ListReq.builder().organizationalUnitId(req.getOuId())
.workspaceId(req.getWorkspaceId()).personIds(req.getPersonIds()).identityType(req.getIdentityType()).build());
if (CollUtil.isEmpty(list)) {
return CollUtil.newArrayList();
}
//批量删除node_user
nodeUserUpsertRepository.batchDelete(list.stream().map(NodeUserQueryRepository.NodeUserResp::getId).collect(Collectors.toSet()));
List<OrganizationalNodeUser> nodeUserList = list.stream().map(e -> BeanUtil.toBean(e, OrganizationalNodeUser.class)).collect(Collectors.toList());
nodeUserList.forEach(this::sendNodeUserDeleteMq);
//处理orgUser退场或离职逻辑
Map<Long, Set<Long>> quitMap = nodeUserList.stream().collect(Collectors.groupingBy(OrganizationalNodeUser::getTopNodeId,
Collectors.mapping(OrganizationalNodeUser::getPersonId, Collectors.toSet())));
OrgUserWithdrawOrQuitReq quitReq = new OrgUserWithdrawOrQuitReq();
quitReq.setUnitUpdate(req.isUnitDelete());
quitReq.setWorkspaceId(req.getWorkspaceId());
quitReq.setOuId(req.getOuId());
if (req.isUnitDelete()) {
quitReq.setWorkspaceId(nodeUserList.get(0).getWorkspaceId());
}
quitReq.setTopNodeIdAndPersonIds(quitMap);
orgUserFoundationService.batchWithdrawOrQuit(quitReq);
//项目内工人退场
OrgProjectWorkerWithdrawReq workerReq = new OrgProjectWorkerWithdrawReq();
workerReq.setOuId(req.getOuId());
workerReq.setWorkspaceId(req.getWorkspaceId());
if (req.isUnitDelete()) {
workerReq.setWorkspaceId(nodeUserList.get(0).getWorkspaceId());
}
workerReq.setPersonIds(req.getPersonIds());
orgProjectWorkerFoundationService.batchWithdraw(workerReq);
return nodeUserList;
}
private void sendNodeUserDeleteMq(OrganizationalNodeUser e) {
String summary = "部门人员删除";
// 方便记录操作日志
OperateLogService.OperateType operateType = OperateLogService.OperateType.DELETE;
OperateLogService.SaveParam saveParam = OperateLogService.SaveParam.builder()
.summary(summary)
.resourceType(OperateLogService.ResourceType.ORGANIZATIONAL_NODE_USER)
.resourceId(ObjectUtils.firstNonNull(e, null).getId())
.operateType(operateType)
.apiCaller("orgmanax")
.build();
eventProducer.send(OrganizationalNodeUserUpsertedPayload.from(null, e, "-1",
new JSONObject().fluentPut("operateLogSaveParam", saveParam)));
}
private void checkDeleteReq(NodeUserDelete req) {
if (NumberUtil.isPositiveNumber(req.getOuId())) {
UnitQueryRepository.UnitResp one = unitQueryRepository.oneOpt(UnitQueryRepository.OneReq.builder().id(req.getOuId()).build())
.orElseThrow(() -> BizResultCode.ENTITY_NOT_FOUND.toException("单位不存在{}", req.getOuId()));
}
if (NumberUtil.isPositiveNumber(req.getWorkspaceId())) {
WorkspaceDetailReq workspaceDetailReq = WorkspaceDetailReq.builder().id(req.getWorkspaceId()).build();
WorkspaceDetailResp workspaceDetailResp = workspaceGateway.getDetail(workspaceDetailReq);
Axssert.checkNonNull(workspaceDetailResp, "项目不存在");
}
}
@Override
public <T extends OrganizationalNodeUser> void filterByJobs(Collection<T> nodeUsers, Collection<String> jobCodes) {
List<OrgJobQueryRepository.JobResp> orgJobs = orgJobQueryRepository.list(OrgJobQueryRepository.ListReq.builder()

View File

@ -0,0 +1,40 @@
package cn.axzo.orgmanax.server.nodeuser.foundation.req;
import cn.axzo.orgmanax.infra.dao.nodeuser.entity.OrganizationalNodeUser;
import cn.hutool.core.bean.BeanUtil;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.SuperBuilder;
import java.util.List;
@NoArgsConstructor
@AllArgsConstructor
@Data
@SuperBuilder
public class NodeUserDelete {
private Long ouId;
private Long operatorId;
private Long workspaceId;
private List<Long> personIds;
/**
* 是否企业删除
*/
private boolean isUnitDelete;
/**
* 身份类型 按照项目删除的时候
*/
private Integer identityType;
public OrganizationalNodeUser toEntity() {
return BeanUtil.toBean(this, OrganizationalNodeUser.class);
}
}

View File

@ -0,0 +1,34 @@
package cn.axzo.orgmanax.server.nodeuser.foundation.req;
import cn.axzo.foundation.exception.Axssert;
import cn.axzo.orgmanax.infra.dao.nodeuser.entity.OrganizationalNodeUser;
import cn.hutool.core.bean.BeanUtil;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.SuperBuilder;
import java.util.List;
@NoArgsConstructor
@AllArgsConstructor
@Data
@SuperBuilder
public class NodeUserUnitDelete {
private Long ouId;
private Long operatorId;
private List<Long> personIds;
public void check() {
Axssert.checkNonNull(operatorId, "操作人不能为空");
Axssert.checkNonNull(ouId, "单位不能为空");
Axssert.checkNonNull(personIds, "用户id列表不能都为空");
}
public OrganizationalNodeUser toEntity() {
return BeanUtil.toBean(this, OrganizationalNodeUser.class);
}
}

View File

@ -0,0 +1,34 @@
package cn.axzo.orgmanax.server.nodeuser.foundation.req;
import cn.axzo.foundation.exception.Axssert;
import cn.axzo.orgmanax.infra.dao.nodeuser.entity.OrganizationalNodeUser;
import cn.hutool.core.bean.BeanUtil;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.SuperBuilder;
import java.util.List;
@NoArgsConstructor
@AllArgsConstructor
@Data
@SuperBuilder
public class NodeUserWorkspaceDelete {
private Long workspaceId;
private Long operatorId;
private List<Long> personIds;
public void check() {
Axssert.checkNonNull(operatorId, "操作人不能为空");
Axssert.checkNonNull(workspaceId, "项目不能为空");
Axssert.checkNonNull(personIds, "用户id列表不能都为空");
}
public OrganizationalNodeUser toEntity() {
return BeanUtil.toBean(this, OrganizationalNodeUser.class);
}
}

View File

@ -0,0 +1,13 @@
package cn.axzo.orgmanax.server.nodeuser.service;
import cn.axzo.orgmanax.dto.nodeuser.req.BatchDeleteNodeUserCheckReq;
import cn.axzo.orgmanax.dto.nodeuser.resp.BatchDeleteNodeUserCheckResp;
import java.util.List;
public interface NodeUserCheckService {
List<BatchDeleteNodeUserCheckResp> checkUnit(BatchDeleteNodeUserCheckReq req);
List<BatchDeleteNodeUserCheckResp> checkWorkspace(BatchDeleteNodeUserCheckReq req);
}

View File

@ -0,0 +1,516 @@
package cn.axzo.orgmanax.server.nodeuser.service.impl;
import cn.axzo.apollo.workspace.api.v2.participating.req.ParticipatingUnitListReq;
import cn.axzo.apollo.workspace.api.v2.participating.resp.ParticipatingUnitResp;
import cn.axzo.foundation.exception.Axssert;
import cn.axzo.foundation.result.ResultCode;
import cn.axzo.orgmanax.dto.common.IdentityType;
import cn.axzo.orgmanax.dto.common.util.NumberUtil;
import cn.axzo.orgmanax.dto.cooperateship.dto.OrgCooperateShipDTO;
import cn.axzo.orgmanax.dto.cooperateship.enums.CooperateShipTypeEnum;
import cn.axzo.orgmanax.dto.cooperateship.req.ListOrgCooperateShipReq;
import cn.axzo.orgmanax.dto.node.dto.OrgNodeDTO;
import cn.axzo.orgmanax.dto.node.enums.NodeTypeEnum;
import cn.axzo.orgmanax.dto.node.req.ListNodeReq;
import cn.axzo.orgmanax.dto.nodeuser.dto.NodeUserDTO;
import cn.axzo.orgmanax.dto.nodeuser.enums.CheckInfoTypeEnum;
import cn.axzo.orgmanax.dto.nodeuser.req.BatchDeleteNodeUserCheckReq;
import cn.axzo.orgmanax.dto.nodeuser.req.ListNodeUserReq;
import cn.axzo.orgmanax.dto.nodeuser.resp.BatchDeleteNodeUserCheckResp;
import cn.axzo.orgmanax.infra.client.karma.KarmaThirdApiClient;
import cn.axzo.orgmanax.infra.client.karma.ThirdCheckFailResp;
import cn.axzo.orgmanax.infra.client.tyr.RoleUserGateway;
import cn.axzo.orgmanax.infra.client.workspace.WorkspaceGateway;
import cn.axzo.orgmanax.infra.client.workspace.dto.Workspace;
import cn.axzo.orgmanax.server.cooperateship.service.CooperateShipService;
import cn.axzo.orgmanax.server.node.service.NodeService;
import cn.axzo.orgmanax.server.nodeuser.dto.CheckUserOperateParam;
import cn.axzo.orgmanax.server.nodeuser.service.NodeUserCheckService;
import cn.axzo.orgmanax.server.nodeuser.service.NodeUserService;
import cn.axzo.orgmanax.server.util.constants.JobCodeConstants;
import cn.axzo.tyr.feign.enums.IdentityTypeEnum;
import cn.axzo.tyr.feign.enums.RoleTypeEnum;
import cn.axzo.tyr.feign.req.PageRoleUserReq;
import cn.axzo.tyr.feign.resp.RoleUserResp;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import java.util.*;
import java.util.function.Function;
import java.util.function.ToIntFunction;
import java.util.stream.Collectors;
@Slf4j
@Service
@RequiredArgsConstructor
public class NodeUserCheckServiceImpl implements NodeUserCheckService {
private final WorkspaceGateway workspaceGateway;
private final RoleUserGateway roleUserGateway;
private final CooperateShipService cooperateShipService;
private final NodeUserService nodeUserService;
private final NodeService nodeService;
private final KarmaThirdApiClient karmaThirdApiClient;
// 单位类型默认角色关系,后面可以座位管理员的逻辑进行迭代
@Value("#{${participateUnitDefaultRoleId:{}}}")
public Map<Integer, Long> participateUnitDefaultRoleId;
/**
* 小组长角色分组编码
*/
@Value("${projectTeamGPLeader:projectTeamGPLeader}")
private String projectTeamGPLeader;
// 企业内班组长岗位编码
@Value("${entTeamLeader:entTeamLeader}")
private String entTeamLeader;
// 企业内班组工人岗位编码
@Value("${entWorker:entWorker}")
private String entWorker;
@Override
public List<BatchDeleteNodeUserCheckResp> checkUnit(BatchDeleteNodeUserCheckReq req) {
List<BatchDeleteNodeUserCheckResp> resultList = new ArrayList<>();
Map<Long, List<BatchDeleteNodeUserCheckResp.CheckFailInfo>> failInfoMap = new HashMap<>();
Long ouId = req.getOuId();
Long workspaceId = req.getWorkspaceId();
Set<Long> personIds = req.getPersonIds();
ParticipatingUnitListReq participatingUnitListReq = new ParticipatingUnitListReq();
participatingUnitListReq.setLevels(ListUtil.of(Workspace.WorkspaceTypeEnum.GENERAL_ENT.value, Workspace.WorkspaceTypeEnum.GENERAL_PROJECT.value));
participatingUnitListReq.setWorkspaceId(workspaceId);
participatingUnitListReq.setOrganizationUnitId(ouId);
List<ParticipatingUnitResp> participatingUnitList = workspaceGateway.listParticipatingUnits(participatingUnitListReq);
Axssert.checkNotEmpty(participatingUnitList, "当前单位未参建任何项目,获取详细信息失败");
Long topNodeId = participatingUnitList.get(0).getOrganizationNodeId();
//1 单位联系人(超管)不能删除
PageRoleUserReq param = new PageRoleUserReq();
PageRoleUserReq.WorkspaceOuPair workspaceOuPair = new PageRoleUserReq.WorkspaceOuPair();
workspaceOuPair.setWorkspaceId(workspaceId);
workspaceOuPair.setOuId(ouId);
param.setWorkspaceOuPairs(Collections.singletonList(workspaceOuPair));
param.setRoleTypes(Collections.singleton(RoleTypeEnum.SUPER_ADMIN));
List<RoleUserResp> superAminInfoResult = roleUserGateway.pageAll(param);
superAminInfoResult.forEach(e -> {
if (personIds.contains(e.getPersonId())) {
BatchDeleteNodeUserCheckResp.CheckFailInfo checkFailInfo = new BatchDeleteNodeUserCheckResp.CheckFailInfo();
checkFailInfo.setType(CheckInfoTypeEnum.SUPER_ADMIN);
addFailInfo(failInfoMap, e.getPersonId(), checkFailInfo);
}
});
ListOrgCooperateShipReq listOrgCooperateShipReq = new ListOrgCooperateShipReq();
listOrgCooperateShipReq.setOuIds(Collections.singleton(ouId));
listOrgCooperateShipReq.setStatuses(CollUtil.newHashSet(0, 1));
List<OrgCooperateShipDTO> listPersonJoinedWorkspace = cooperateShipService.list(listOrgCooperateShipReq);
Set<Long> inProjectPersonIds = filterByPerson(listPersonJoinedWorkspace, personIds);
if (CollectionUtil.isNotEmpty(inProjectPersonIds)) {
inProjectPersonIds.forEach(e -> {
BatchDeleteNodeUserCheckResp.CheckFailInfo checkFailInfo = new BatchDeleteNodeUserCheckResp.CheckFailInfo();
checkFailInfo.setType(CheckInfoTypeEnum.IN_PROJECT);
addFailInfo(failInfoMap, e, checkFailInfo);
});
}
ListNodeUserReq nodeUserQueryVO = new ListNodeUserReq();
nodeUserQueryVO.setPersonIds(personIds);
nodeUserQueryVO.setOrganizationalUnitId(ouId);
nodeUserQueryVO.setTopNodeIds(Collections.singletonList(topNodeId));
nodeUserQueryVO.setNeeds(ListNodeUserReq.Needs.builder().job(true).build());
//查询人所在的部门节点列表
List<NodeUserDTO> organizationalNodeUserList = nodeUserService.list(nodeUserQueryVO);
Set<Long> teamLeader = Sets.newHashSet();
organizationalNodeUserList.forEach(organizationalNodeUserVO -> {
if (IdentityTypeEnum.WORKER_LEADER.getCode().equals(organizationalNodeUserVO.getIdentityType()) || entTeamLeader.equals(organizationalNodeUserVO.getJob().getCode())) {
teamLeader.add(organizationalNodeUserVO.getPersonId());
}
});
if (CollUtil.isNotEmpty(teamLeader)) {
teamLeader.forEach(e -> {
BatchDeleteNodeUserCheckResp.CheckFailInfo checkFailInfo = new BatchDeleteNodeUserCheckResp.CheckFailInfo();
checkFailInfo.setType(CheckInfoTypeEnum.TEAM_LEADER);
addFailInfo(failInfoMap, e, checkFailInfo);
});
}
//判断当前人是否有操作权限
if (NumberUtil.isPositiveNumber(req.getOperatorId())) {
}
transformFailMap(failInfoMap, resultList);
return resultList;
}
private Set<Long> filterByPerson(List<OrgCooperateShipDTO> result, Set<Long> personIds) {
if (CollUtil.isEmpty(personIds)) {
return personIds;
}
Set<Long> filterResult = new HashSet<>();
List<Long> topNodeIds = result.stream().map(OrgCooperateShipDTO::getOrganizationalNodeId).distinct().collect(Collectors.toList());
ListNodeUserReq nodeUserReq = new ListNodeUserReq();
nodeUserReq.setTopNodeIds(topNodeIds);
nodeUserReq.setPersonIds(personIds);
List<NodeUserDTO> nodeUserDTOS = nodeUserService.list(nodeUserReq);
Map<Long, Long> personNodeMap = nodeUserDTOS.stream().collect(Collectors.toMap(NodeUserDTO::getPersonId, NodeUserDTO::getTopNodeId));
Set<Long> shipNodeIds = result.stream().map(OrgCooperateShipDTO::getOrganizationalNodeId).collect(Collectors.toSet());
for (Map.Entry<Long, Long> entry : personNodeMap.entrySet()) {
if (shipNodeIds.contains(entry.getValue())) {
filterResult.add(entry.getKey());
}
}
return filterResult;
}
private void addFailInfo(Map<Long, List<BatchDeleteNodeUserCheckResp.CheckFailInfo>> failInfoMap, Long personId, BatchDeleteNodeUserCheckResp.CheckFailInfo checkFailInfo) {
failInfoMap.computeIfAbsent(personId, k -> new ArrayList<>()).add(checkFailInfo);
}
@Override
public List<BatchDeleteNodeUserCheckResp> checkWorkspace(BatchDeleteNodeUserCheckReq req) {
Long personId = req.getOperatorId();
List<BatchDeleteNodeUserCheckResp> resultList = new ArrayList<>();
Map<Long, List<BatchDeleteNodeUserCheckResp.CheckFailInfo>> failInfoMap = new HashMap<>();
ListOrgCooperateShipReq listOrgCooperateShipReq = new ListOrgCooperateShipReq();
listOrgCooperateShipReq.setOuIds(Collections.singleton(req.getOuId()));
listOrgCooperateShipReq.setWorkspaceIds(Collections.singleton(req.getWorkspaceId()));
listOrgCooperateShipReq.setStatuses(CollUtil.newHashSet(0, 1));
List<OrgCooperateShipDTO> cooperateShipRespList = cooperateShipService.list(listOrgCooperateShipReq);
Axssert.checkNotEmpty(cooperateShipRespList, "操作失败,获取协同组织失败");
// 协同节点关联的顶级部门节点列表
List<Long> nodeIds = cooperateShipRespList.stream().map(OrgCooperateShipDTO::getOrganizationalNodeId).distinct().collect(Collectors.toList());
List<Long> nodePersonIds = Lists.newArrayList(req.getPersonIds());
nodePersonIds.add(personId);
ListNodeUserReq query = ListNodeUserReq.builder()
.topNodeIds(nodeIds)
.personIds(nodePersonIds)
.findByAncestorNodeId(true)
.build();
// 查询当前登录及待删除人员在当前项目中的参与记录仅限当前登录单位
List<NodeUserDTO> nodeUsers = nodeUserService.list(query);
// 校验当前入参
checkPermission(nodeUsers, personId);
// 过滤当前操作人员
nodeUsers = nodeUsers.stream()
.filter(e -> req.getPersonIds().contains(e.getPersonId()))
.collect(Collectors.toList());
if (CollectionUtil.isEmpty(nodeUsers)) {
req.getPersonIds().forEach(e -> {
BatchDeleteNodeUserCheckResp.CheckFailInfo checkFailInfo = new BatchDeleteNodeUserCheckResp.CheckFailInfo();
checkFailInfo.setType(CheckInfoTypeEnum.NOT_IN_JURISDICTION);
addFailInfo(failInfoMap, e, checkFailInfo);
});
}
nodeUsers.stream().filter(e -> e.getIdentityType().equals(IdentityType.WORKER_LEADER.getCode())).findAny().ifPresent(e -> {
BatchDeleteNodeUserCheckResp.CheckFailInfo checkFailInfo = new BatchDeleteNodeUserCheckResp.CheckFailInfo();
checkFailInfo.setType(CheckInfoTypeEnum.TEAM_LEADER);
addFailInfo(failInfoMap, e.getPersonId(), checkFailInfo);
});
// 判断是否合作小组小组长合作小组小组长不允许删除
checkIndependentGroupLeader(nodeUsers, failInfoMap);
// 判断是否拥有admin角色 判断是否是分包管理员
List<Long> adminRoleIds = getSpecialRole();
PageRoleUserReq roleUserParam = PageRoleUserReq.builder().build();
PageRoleUserReq.WorkspaceOuPair workspaceOuPair = new PageRoleUserReq.WorkspaceOuPair();
workspaceOuPair.setWorkspaceId(req.getWorkspaceId());
workspaceOuPair.setOuId(req.getOuId());
roleUserParam.setWorkspaceOuPairs(Collections.singletonList(workspaceOuPair));
roleUserParam.setPersonIds(req.getPersonIds());
roleUserParam.setNeedRole(true);
List<RoleUserResp> saasRoleUserInfo = roleUserGateway.pageAll(roleUserParam);
saasRoleUserInfo.forEach(e -> {
Optional<RoleTypeEnum> roleTypeEnumOptional = RoleTypeEnum.fromValue(e.getRole().getRoleType());
RoleTypeEnum roleTypeEnum = RoleTypeEnum.AUTO_OWN;
if (roleTypeEnumOptional.isPresent()) {
roleTypeEnum = roleTypeEnumOptional.get();
}
boolean anyAdminRole = adminRoleIds.contains(e.getRoleId()) || roleTypeEnum.isAdmin();
if (anyAdminRole) {
BatchDeleteNodeUserCheckResp.CheckFailInfo checkFailInfo = new BatchDeleteNodeUserCheckResp.CheckFailInfo();
checkFailInfo.setType(CheckInfoTypeEnum.ANY_ADMIN);
addFailInfo(failInfoMap, e.getPersonId(), checkFailInfo);
}
});
// 检查班组节点权限
checkUserOperate(CheckUserOperateParam.builder()
.operatorId(req.getOperatorId())
.personIds(req.getPersonIds())
.workspaceId(req.getWorkspaceId())
.build(), failInfoMap);
// 三方阻断校验
thirdApiCheckPerson(req.getWorkspaceId(), req.getPersonIds(), failInfoMap);
transformFailMap(failInfoMap, resultList);
return resultList;
}
private static void transformFailMap(Map<Long, List<BatchDeleteNodeUserCheckResp.CheckFailInfo>> failInfoMap, List<BatchDeleteNodeUserCheckResp> resultList) {
if (CollUtil.isNotEmpty(failInfoMap)) {
failInfoMap.forEach((failPerson, checkFailInfos) -> {
// Use a LinkedHashMap to keep track of the last count for each type
Map<CheckInfoTypeEnum, Integer> lastCounts = new LinkedHashMap<>();
for (BatchDeleteNodeUserCheckResp.CheckFailInfo info : checkFailInfos) {
lastCounts.put(info.getType(), info.getCount());
}
// Create a new list of CheckFailInfo objects with unique types and their last counts
List<BatchDeleteNodeUserCheckResp.CheckFailInfo> uniqueFailInfos = new ArrayList<>();
for (Map.Entry<CheckInfoTypeEnum, Integer> entry : lastCounts.entrySet()) {
uniqueFailInfos.add(new BatchDeleteNodeUserCheckResp.CheckFailInfo(entry.getKey(), entry.getValue()));
}
BatchDeleteNodeUserCheckResp batchDeleteNodeUserCheckVO = new BatchDeleteNodeUserCheckResp();
batchDeleteNodeUserCheckVO.setPersonId(failPerson);
batchDeleteNodeUserCheckVO.setFailInfos(uniqueFailInfos);
resultList.add(batchDeleteNodeUserCheckVO);
});
}
}
private void thirdApiCheckPerson(Long workspaceId, Set<Long> personIds, Map<Long, List<BatchDeleteNodeUserCheckResp.CheckFailInfo>> failInfoMap) {
Map<Long, List<ThirdCheckFailResp>> thirdCheckFail = karmaThirdApiClient.getThirdCheckFail(workspaceId, personIds);
if (CollUtil.isEmpty(thirdCheckFail)) {
return;
}
thirdCheckFail.forEach((key, value) -> value.forEach(thirdCheckFailResp -> {
BatchDeleteNodeUserCheckResp.CheckFailInfo checkFailInfo = new BatchDeleteNodeUserCheckResp.CheckFailInfo();
checkFailInfo.setType(thirdCheckFailResp.getType());
checkFailInfo.setCount(thirdCheckFailResp.getCount());
addFailInfo(failInfoMap, key, checkFailInfo);
}));
}
private void checkIndependentGroupLeader(List<NodeUserDTO> nodeUsers, Map<Long, List<BatchDeleteNodeUserCheckResp.CheckFailInfo>> failInfoMap) {
Set<Long> nodeIdList = nodeUsers.stream().map(NodeUserDTO::getOrganizationalNodeId).collect(Collectors.toSet());
ListNodeReq nodeBatchQueryVO = new ListNodeReq();
nodeBatchQueryVO.setIds(nodeIdList);
List<OrgNodeDTO> nodeVOList = nodeService.list(nodeBatchQueryVO);
if (CollectionUtil.isEmpty(nodeVOList)) {
throw ResultCode.INVALID_PARAMS.toException("操作失败:获取部门节点信息失败");
}
Map<Long, OrgNodeDTO> nodeVOMap = nodeVOList.stream().collect(Collectors.toMap(OrgNodeDTO::getId, Function.identity()));
for (NodeUserDTO u : nodeUsers) {
if (projectTeamGPLeader.equals(u.getJob().getCode())) {
OrgNodeDTO nodeVO = nodeVOMap.getOrDefault(u.getOrganizationalNodeId(), null);
if (Objects.nonNull(nodeVO) && NodeTypeEnum.PROJECT_GROUP.getValue().equals(nodeVO.getNodeType())
&& Objects.nonNull(nodeVO.independentGroup()) && nodeVO.independentGroup()) {
BatchDeleteNodeUserCheckResp.CheckFailInfo checkFailInfo = new BatchDeleteNodeUserCheckResp.CheckFailInfo();
checkFailInfo.setType(CheckInfoTypeEnum.PROJECT_GROUP_LEADER);
addFailInfo(failInfoMap, u.getPersonId(), checkFailInfo);
}
}
}
}
private void checkPermission(List<NodeUserDTO> nodeUsers, Long personId) {
if (CollUtil.isEmpty(nodeUsers)
|| nodeUsers.stream().noneMatch(e -> Objects.equals(e.getPersonId(), personId))) {
throw ResultCode.INVALID_PARAMS.toException("你已被移除当前项目");
}
}
private List<Long> getSpecialRole() {
if (participateUnitDefaultRoleId != null && !participateUnitDefaultRoleId.isEmpty()) {
return new ArrayList<>(participateUnitDefaultRoleId.values());
} else {
return new ArrayList<>();
}
}
public void checkUserOperate(CheckUserOperateParam param, Map<Long, List<BatchDeleteNodeUserCheckResp.CheckFailInfo>> failInfoMap) {
if (NumberUtil.isNotPositiveNumber(param.getOperatorId())) {
return;
}
param.check();
List<Long> nodePersonIds = Lists.newArrayList(param.getPersonIds());
nodePersonIds.add(param.getOperatorId());
ListNodeUserReq nodeUserReq = ListNodeUserReq.builder()
.personIds(nodePersonIds)
.workspaceId(param.getWorkspaceId())
.needs(ListNodeUserReq.Needs.builder().job(true).node(true).build())
.build();
List<NodeUserDTO> nodeUsers = nodeUserService.list(nodeUserReq);
NodeUserDTO operator = nodeUsers.stream().filter(nu -> Objects.equals(nu.getPersonId(), param.getOperatorId()))
.filter(nu -> StrUtil.isNotBlank(nu.getJob().getCode()))
.min(Comparator.comparingInt(NODE_USER_PRIORITY_RESOLVER)).orElse(null);
List<NodeUserDTO> targets = param.getPersonIds().stream()
.map(personId -> nodeUsers.stream()
.filter(nu -> Objects.equals(nu.getPersonId(), personId))
.min(Comparator.comparingInt(NODE_USER_PRIORITY_RESOLVER))
.orElse(null))
.collect(Collectors.toList());
log.info("## checkUserOperate, param = {}, operator = {}, targets = {}, nodeUsers = {} "
, JSON.toJSONString(param), JSON.toJSONString(operator), JSON.toJSONString(targets), JSON.toJSONString(nodeUsers));
if (operator == null) {
throw ResultCode.INVALID_PARAMS.toException("你已经被移出该企业/项目,请及时联系管理员;你可以退出登录或切换到其他企业/项目使用");
}
if (CollUtil.isEmpty(targets)) {
throw ResultCode.INVALID_PARAMS.toException("操作对象已经被移出该企业/项目,请刷新页面重新操作");
}
// 如果只有工人身份则直接提示无权限
if (isProjectWorker(operator)) {
throw ResultCode.INVALID_PARAMS.toException("操作失败,您暂无权限!");
}
if (param.getPersonIds().size() == 1 && param.getPersonIds().contains(param.getOperatorId())) {
return;
}
// 如果 操作人是 从业人员 直接返回
if (isPractitioner(operator)) {
return;
}
// 操作人是 班组长或者带班长 则被操作人只能是 自己或者自己班组 小组的工人
if (isProjectTeamLeader(operator) || isProjectTeamManager(operator)) {
targets.forEach(target -> teamManagerCheck(target, operator, failInfoMap));
}
if (isProjectGroupManager(operator)) {
targets.forEach(target -> groupManagerCheck(target, operator, nodeUsers, failInfoMap));
}
}
private void groupManagerCheck(NodeUserDTO target, NodeUserDTO operator, List<NodeUserDTO> nodeUsers, Map<Long, List<BatchDeleteNodeUserCheckResp.CheckFailInfo>> failInfoMap) {
if (isPractitioner(target)) {
BatchDeleteNodeUserCheckResp.CheckFailInfo checkFailInfo = new BatchDeleteNodeUserCheckResp.CheckFailInfo();
checkFailInfo.setType(CheckInfoTypeEnum.ANY_ADMIN);
addFailInfo(failInfoMap, target.getPersonId(), checkFailInfo);
return;
}
// 工人必须仅在自己小组
boolean isSameGroup = nodeUsers.stream()
.filter(nu -> Objects.equals(nu.getPersonId(), target.getPersonId()))
.anyMatch(nu -> Objects.equals(nu.getOrganizationalNodeId(), operator.getOrganizationalNodeId()));
if (!isSameGroup) {
BatchDeleteNodeUserCheckResp.CheckFailInfo checkFailInfo = new BatchDeleteNodeUserCheckResp.CheckFailInfo();
checkFailInfo.setType(CheckInfoTypeEnum.NOT_IN_JURISDICTION);
addFailInfo(failInfoMap, target.getPersonId(), checkFailInfo);
}
}
private void teamManagerCheck(NodeUserDTO target, NodeUserDTO operator, Map<Long, List<BatchDeleteNodeUserCheckResp.CheckFailInfo>> failInfoMap) {
if (isPractitioner(target)) {
BatchDeleteNodeUserCheckResp.CheckFailInfo checkFailInfo = new BatchDeleteNodeUserCheckResp.CheckFailInfo();
checkFailInfo.setType(CheckInfoTypeEnum.ANY_ADMIN);
addFailInfo(failInfoMap, target.getPersonId(), checkFailInfo);
return;
}
boolean isSameTeam = Objects.equals(target.getOrganizationalNodeId(), operator.getOrganizationalNodeId());
if (isSameTeam) {
return;
}
// 否则自己下级小组也可以
boolean isGroup = target.getNode() != null
&& Objects.equals(target.getNode().getNodeType(), NodeTypeEnum.PROJECT_GROUP.getCode());
if (!isGroup) {
BatchDeleteNodeUserCheckResp.CheckFailInfo checkFailInfo = new BatchDeleteNodeUserCheckResp.CheckFailInfo();
checkFailInfo.setType(CheckInfoTypeEnum.NOT_IN_JURISDICTION);
addFailInfo(failInfoMap, target.getPersonId(), checkFailInfo);
return;
}
Long belongProjectTeamNodeId = resolveProjectTeamNodeId(target.getOrganizationalNodeId());
if (Objects.equals(belongProjectTeamNodeId, operator.getOrganizationalNodeId())) {
return;
}
BatchDeleteNodeUserCheckResp.CheckFailInfo checkFailInfo = new BatchDeleteNodeUserCheckResp.CheckFailInfo();
checkFailInfo.setType(CheckInfoTypeEnum.NOT_IN_JURISDICTION);
addFailInfo(failInfoMap, target.getPersonId(), checkFailInfo);
}
private boolean isPractitioner(NodeUserDTO nodeUser) {
if (nodeUser == null) {
return false;
}
return Objects.equals(nodeUser.getIdentityType(), IdentityType.PRACTITIONER.getCode());
}
private boolean isProjectWorker(NodeUserDTO nodeUser) {
if (nodeUser == null) {
return false;
}
return Objects.equals(nodeUser.getJob().getCode(), JobCodeConstants.PROJECT_TEAM_WORKER);
}
private boolean isProjectTeamLeader(NodeUserDTO nodeUser) {
if (nodeUser == null) {
return false;
}
return Objects.equals(nodeUser.getJob().getCode(), JobCodeConstants.PROJ_TEAM_LEADER);
}
private boolean isProjectTeamManager(NodeUserDTO nodeUser) {
if (nodeUser == null) {
return false;
}
return Objects.equals(nodeUser.getJob().getCode(), JobCodeConstants.PROJ_TEAM_MANAGER);
}
private boolean isProjectGroupManager(NodeUserDTO nodeUser) {
if (nodeUser == null) {
return false;
}
return Objects.equals(nodeUser.getJob().getCode(), JobCodeConstants.PROJECT_TEAM_GROUP_LEADER);
}
private static final ToIntFunction<NodeUserDTO> NODE_USER_PRIORITY_RESOLVER = nodeUser -> {
if (nodeUser == null) {
return 9999;
}
if (Objects.equals(nodeUser.getIdentityType(), IdentityType.PRACTITIONER.getCode())) {
return 20;
}
if (StrUtil.isBlank(nodeUser.getJob().getCode())) {
return 9999;
}
switch (nodeUser.getJob().getCode()) {
case JobCodeConstants.PROJECT_TEAM_WORKER:
// 工人
return 100;
case JobCodeConstants.PROJECT_TEAM_GROUP_LEADER:
// 小组长
return 90;
case JobCodeConstants.PROJ_TEAM_MANAGER:
// 带班长
return 80;
case JobCodeConstants.PROJ_TEAM_LEADER:
// 班组长
return 70;
case JobCodeConstants.ENT_TEAM_WORK:
// 平台工人
return 60;
case JobCodeConstants.ENT_TEAM_MANAGER:
// 平台班组管理员
return 50;
case JobCodeConstants.ENT_TEAM_LEADER:
// 平台班组长
return 40;
default:
return 20;
}
};
private Long resolveProjectTeamNodeId(Long nodeId) {
ListOrgCooperateShipReq saasCooperateShipQueryReq = ListOrgCooperateShipReq.builder()
.organizationNodeIds(ImmutableSet.of(nodeId))
.includeAncestors(true)
.build();
List<OrgCooperateShipDTO> nodes = cooperateShipService.list(saasCooperateShipQueryReq);
return nodes.stream().filter(n -> Objects.equals(n.getCooperateType(), CooperateShipTypeEnum.PROJ_TEAM.getCode())).findFirst()
.map(OrgCooperateShipDTO::getOrganizationalNodeId).orElse(0L);
}
}

View File

@ -0,0 +1,34 @@
package cn.axzo.orgmanax.server.nodeuser.service.processor.impl;
import cn.axzo.orgmanax.infra.dao.nodeuser.entity.OrganizationalNodeUser;
import cn.axzo.orgmanax.server.nodeuser.foundation.NodeUserFoundationService;
import cn.axzo.orgmanax.server.nodeuser.foundation.req.NodeUserDelete;
import cn.axzo.orgmanax.server.nodeuser.service.processor.NodeUserProcessor;
import com.alibaba.fastjson.JSONObject;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import java.util.List;
/**
* 删除单位人员
*/
@Component
@Slf4j
@RequiredArgsConstructor
public class UnitDeleteNodeUserProcessor implements NodeUserProcessor {
private final NodeUserFoundationService nodeUserFoundationService;
@Override
public ProcessResult process(ProcessContext context) {
// 转成该处理器关注的参数对象
NodeUserDelete nodeUserDelete = context.getParams().toJavaObject(NodeUserDelete.class);
nodeUserDelete.setUnitDelete(true);
List<OrganizationalNodeUser> nodeUserList = nodeUserFoundationService.delete(nodeUserDelete);
// 返回数据
return ProcessResult.success((JSONObject) JSONObject.toJSON(nodeUserList));
}
}

View File

@ -0,0 +1,32 @@
package cn.axzo.orgmanax.server.nodeuser.service.processor.impl;
import cn.axzo.orgmanax.infra.dao.nodeuser.entity.OrganizationalNodeUser;
import cn.axzo.orgmanax.server.nodeuser.foundation.NodeUserFoundationService;
import cn.axzo.orgmanax.server.nodeuser.foundation.req.NodeUserDelete;
import cn.axzo.orgmanax.server.nodeuser.service.processor.NodeUserProcessor;
import com.alibaba.fastjson.JSONObject;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import java.util.List;
/**
* 删除项目人员
*/
@Component
@Slf4j
@RequiredArgsConstructor
public class WorkspaceDeleteNodeUserProcessor implements NodeUserProcessor {
private final NodeUserFoundationService nodeUserFoundationService;
@Override
public ProcessResult process(ProcessContext context) {
// 转成该处理器关注的参数对象
NodeUserDelete nodeUserDelete = context.getParams().toJavaObject(NodeUserDelete.class);
List<OrganizationalNodeUser> nodeUserList = nodeUserFoundationService.delete(nodeUserDelete);
// 返回数据
return ProcessResult.success((JSONObject) JSONObject.toJSON(nodeUserList));
}
}

View File

@ -0,0 +1,11 @@
package cn.axzo.orgmanax.server.orguser.foundation;
import cn.axzo.orgmanax.server.orguser.foundation.req.OrgUserWithdrawOrQuitReq;
import org.springframework.transaction.annotation.Transactional;
public interface OrgUserFoundationService {
@Transactional(rollbackFor = Throwable.class)
void batchWithdrawOrQuit(OrgUserWithdrawOrQuitReq req);
}

View File

@ -0,0 +1,115 @@
package cn.axzo.orgmanax.server.orguser.foundation.impl;
import cn.axzo.apollo.workspace.api.v2.workspace.req.WorkspaceDetailReq;
import cn.axzo.apollo.workspace.api.v2.workspace.resp.WorkspaceDetailResp;
import cn.axzo.orgmanax.dto.nodeuser.enums.OrgUserStatusEnum;
import cn.axzo.orgmanax.dto.orguser.dto.OrgUserDTO;
import cn.axzo.orgmanax.dto.orguser.event.OrgUserStatusChangedEvent;
import cn.axzo.orgmanax.dto.orguser.req.ListOrgUserReq;
import cn.axzo.orgmanax.infra.client.workspace.WorkspaceGateway;
import cn.axzo.orgmanax.infra.client.workspace.dto.Workspace;
import cn.axzo.orgmanax.infra.dao.orguser.entity.OrgUser;
import cn.axzo.orgmanax.infra.dao.orguser.repository.OrgUserQueryRepository;
import cn.axzo.orgmanax.infra.dao.orguser.repository.OrgUserUpsertRepository;
import cn.axzo.orgmanax.server.mq.producer.OrgUserChangedEventProducer;
import cn.axzo.orgmanax.server.orguser.foundation.OrgUserFoundationService;
import cn.axzo.orgmanax.server.orguser.foundation.req.OrgUserWithdrawOrQuitReq;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.Pair;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
/**
* @author : zhanghonghao@axzo.cn
* @since : 2025/3/6
*/
@Slf4j
@Service
@RequiredArgsConstructor
public class OrgUserFoundationServiceImpl implements OrgUserFoundationService {
private final WorkspaceGateway workspaceGateway;
private final OrgUserQueryRepository orgUserQueryRepository;
private final OrgUserUpsertRepository orgUserUpsertRepository;
@Override
public void batchWithdrawOrQuit(OrgUserWithdrawOrQuitReq req) {
OrgUserStatusEnum status;
if (req.isUnitUpdate()) {
WorkspaceDetailReq workspaceDetailReq = new WorkspaceDetailReq();
workspaceDetailReq.setId(req.getWorkspaceId());
WorkspaceDetailResp detail = workspaceGateway.getDetail(workspaceDetailReq);
status = Integer.valueOf(Workspace.WorkspaceTypeEnum.GENERAL_PROJECT.value).equals(detail.getWorkspaceType()) ?
OrgUserStatusEnum.WITHDRAW : OrgUserStatusEnum.QUIT;
} else {
status = OrgUserStatusEnum.WITHDRAW;
}
ListOrgUserReq listOrgUserReq = new ListOrgUserReq();
listOrgUserReq.setOuId(req.getOuId());
listOrgUserReq.setWorkspaceId(req.getWorkspaceId());
Set<Long> personIds = req.getTopNodeIdAndPersonIds().values().stream().flatMap(Set::stream).collect(Collectors.toSet());
listOrgUserReq.setPersonIds(personIds);
List<OrgUserQueryRepository.OrgUserResp> list = orgUserQueryRepository.list(listOrgUserReq);
if (CollUtil.isEmpty(list)) {
return;
}
Pair<Long, String> operator = Pair.of(-1L, "系统");
Date now = new Date();
List<OrgUser> orgUsers = list.stream().map(orgUserResp -> {
OrgUser orgUser = new OrgUser();
orgUser.setId(orgUserResp.getId());
orgUser.setOperatorId(operator.getKey());
orgUser.setOperatorName(operator.getValue());
orgUser.setTransferTime(now);
orgUser.setStatus(status.getCode());
return orgUser;
}).collect(Collectors.toList());
orgUserUpsertRepository.batchUpdate(orgUsers);
Map<Long, OrgUser> orgUserMap = orgUsers.stream().collect(Collectors.toMap(OrgUser::getPersonId, orgUser -> orgUser));
for (Map.Entry<Long, Set<Long>> setEntry : req.getTopNodeIdAndPersonIds().entrySet()) {
Long topNodeId = setEntry.getKey();
Set<Long> personIdSet = setEntry.getValue();
List<OrgUser> orgUserList = orgUserMap.entrySet().stream()
.filter(personIdOrgUserEntry -> personIdSet.contains(personIdOrgUserEntry.getKey()))
.map(Map.Entry::getValue).collect(Collectors.toList());
List<OrgUserDTO> dtoList = CollUtil.map(orgUsers, this::toOrgUserDTO, true);
// 发送用户状态变更事件
batchSendStatusEvents(dtoList, topNodeId);
}
}
private void batchSendStatusEvents(Collection<OrgUserDTO> orgUsers, Long topNodeId) {
if (CollUtil.isEmpty(orgUsers)) {
return;
}
// 事务提交之后发送MQ
Function<OrgUserDTO, OrgUserStatusChangedEvent> eventMapper = e -> toOrgUserStatusChangedEvent(e, topNodeId);
List<OrgUserStatusChangedEvent> events = CollUtil.map(orgUsers, eventMapper, true);
OrgUserChangedEventProducer.batchSendStatusEvents(events);
}
public static OrgUserStatusChangedEvent toOrgUserStatusChangedEvent(OrgUserDTO orgUser, Long topNodeId) {
return OrgUserStatusChangedEvent.builder()
.personId(orgUser.getPersonId())
.ouId(orgUser.getOuId())
.workspaceId(orgUser.getWorkspaceId())
.topNodeId(topNodeId)
.statusCode(orgUser.getStatus())
.transferTimestamp(orgUser.getTransferTime().getTime())
.operatorId(orgUser.getOperatorId())
.build();
}
private OrgUserDTO toOrgUserDTO(OrgUser orgUser) {
OrgUserDTO dto = OrgUserDTO.builder().build();
BeanUtils.copyProperties(orgUser, dto);
return dto;
}
}

View File

@ -0,0 +1,26 @@
package cn.axzo.orgmanax.server.orguser.foundation.req;
import lombok.Data;
import java.util.Map;
import java.util.Set;
/**
* @author : zhanghonghao@axzo.cn
* @since : 2025/3/6
*/
@Data
public class OrgUserWithdrawOrQuitReq {
private Long ouId;
private Long workspaceId;
private Map<Long, Set<Long>> topNodeIdAndPersonIds;
/**
* 是否单位更新
*/
private boolean isUnitUpdate;
}

View File

@ -0,0 +1,10 @@
package cn.axzo.orgmanax.server.project.worker.foundation;
import cn.axzo.orgmanax.server.project.worker.foundation.req.OrgProjectWorkerWithdrawReq;
import org.springframework.transaction.annotation.Transactional;
public interface OrgProjectWorkerFoundationService {
@Transactional(rollbackFor = Throwable.class)
void batchWithdraw(OrgProjectWorkerWithdrawReq req);
}

View File

@ -0,0 +1,52 @@
package cn.axzo.orgmanax.server.project.worker.foundation.impl;
import cn.axzo.orgmanax.dto.project.worker.enums.ProjectWorkerStatusEnum;
import cn.axzo.orgmanax.infra.dao.project.worker.entity.OrgProjectWorker;
import cn.axzo.orgmanax.infra.dao.project.worker.repositrory.OrgProjectWorkerQueryRepository;
import cn.axzo.orgmanax.infra.dao.project.worker.repositrory.OrgProjectWorkerUpsertRepository;
import cn.axzo.orgmanax.server.project.worker.foundation.OrgProjectWorkerFoundationService;
import cn.axzo.orgmanax.server.project.worker.foundation.req.OrgProjectWorkerWithdrawReq;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;
/**
* @author : zhanghonghao@axzo.cn
* @since : 2025/3/6
*/
@Slf4j
@Service
@RequiredArgsConstructor
public class OrgProjectWorkerFoundationServiceImpl implements OrgProjectWorkerFoundationService {
private final OrgProjectWorkerQueryRepository orgProjectWorkerQueryRepository;
private final OrgProjectWorkerUpsertRepository orgProjectWorkerUpsertRepository;
@Override
public void batchWithdraw(OrgProjectWorkerWithdrawReq req) {
OrgProjectWorkerQueryRepository.ListReq listReq = new OrgProjectWorkerQueryRepository.ListReq();
listReq.setOrganizationalUnitId(req.getOuId());
listReq.setWorkspaceId(req.getWorkspaceId());
listReq.setWorkerPersonIds(req.getPersonIds());
listReq.setStatus(ProjectWorkerStatusEnum.ACTIVE.getValue());
List<OrgProjectWorkerQueryRepository.OrgProjectWorkerResp> projectWorkerResps = orgProjectWorkerQueryRepository.list(listReq);
if (CollUtil.isEmpty(projectWorkerResps)) {
return;
}
Date now = new Date();
List<OrgProjectWorker> orgProjectWorkers = projectWorkerResps.stream().map(e -> {
OrgProjectWorker orgProjectWorker = BeanUtil.toBean(e, OrgProjectWorker.class);
e.setStatus(ProjectWorkerStatusEnum.WITHDRAW.getValue());
e.setResignAt(now);
e.setUpdateAt(now);
return orgProjectWorker;
}).collect(Collectors.toList());
orgProjectWorkerUpsertRepository.batchUpdate(orgProjectWorkers);
}
}

View File

@ -0,0 +1,20 @@
package cn.axzo.orgmanax.server.project.worker.foundation.req;
import lombok.Data;
import java.util.List;
/**
* @author : zhanghonghao@axzo.cn
* @since : 2025/3/6
*/
@Data
public class OrgProjectWorkerWithdrawReq {
private Long ouId;
private Long workspaceId;
private List<Long> personIds;
}

View File

@ -0,0 +1,51 @@
package cn.axzo.orgmanax.server.service;
import com.alibaba.fastjson.JSONObject;
import com.google.common.base.Preconditions;
import lombok.*;
public interface OperateLogService {
/**
* 保存操作日志
*
* @return
*/
void save(SaveParam param);
@NoArgsConstructor
@Data
@Builder
@AllArgsConstructor
class SaveParam {
private static final Long UNKNOWN_OPERATOR_ID = -1L;
private Long operatorId;
private String operatorName;
private String apiCaller;
private Long resourceId;
private ResourceType resourceType;
private OperateType operateType;
private Object oldValue;
private Object newValue;
private String summary;
private JSONObject ext;
public void check() {
Preconditions.checkArgument(resourceType != null && resourceId != null, "操作资源类型和资源id不能为空");
}
}
@Getter
@AllArgsConstructor(access = AccessLevel.PRIVATE)
enum ResourceType {
ORGANIZATIONAL_UNIT("organizational_unit", "单位"),
ORGANIZATIONAL_NODE("organizational_node", "部门"),
ORGANIZATIONAL_NODE_USER("organizational_node_user", "部门人员"),
SAAS_COOPERATE_SHIP("saas_cooperate_ship", "协同关系");
private final String tableName;
private final String desc;
}
enum OperateType {
ADD, UPDATE, DELETE;
}
}

View File

@ -0,0 +1,34 @@
package cn.axzo.orgmanax.server.util.constants;
/**
* 岗位编码常量
*
* @version V1.0
* @author: ZhanSiHu
* @date: 2024/1/25 14:03
*/
public class JobCodeConstants {
/** 企业内班组长 **/
public static final String ENT_TEAM_LEADER = "entTeamLeader";
/** 企业内班组管理员 **/
public static final String ENT_TEAM_MANAGER = "entTeamManager";
/** 企业内工人 **/
public static final String ENT_TEAM_WORK = "entWorker";
/** 项目内班组 班组长 **/
public static final String PROJ_TEAM_LEADER = "projTeamLeader";
/**
* 项目 - 带班长
*/
public static final String PROJ_TEAM_MANAGER = "projectTeamManager";
/**
* 项目 - 小组长
*/
public static final String PROJECT_TEAM_GROUP_LEADER = "projectTeamGPLeader";
public static final String PROJECT_TEAM_WORKER = "projWorker";
}