From bcb9d32b9542d24444e1ce44708d278f936a9569 Mon Sep 17 00:00:00 2001 From: zhangxiongfeng Date: Tue, 28 Jul 2026 16:58:06 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A4=A7=E5=8D=8E=E5=8F=A3=E9=97=A8=E5=AF=B9?= =?UTF-8?q?=E6=8E=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../zcloud/basic/info/command/UserAddExe.java | 35 ++++- .../basic/info/command/UserRemoveExe.java | 125 +++++++++++++++--- .../basic/info/domain/config/DaHuaConfig.java | 76 +++++++++++ .../repository/UserRepository.java | 5 +- .../repository/impl/UserRepositoryImpl.java | 23 +++- 5 files changed, 242 insertions(+), 22 deletions(-) diff --git a/web-app/src/main/java/com/zcloud/basic/info/command/UserAddExe.java b/web-app/src/main/java/com/zcloud/basic/info/command/UserAddExe.java index 94685572..e47e20e5 100644 --- a/web-app/src/main/java/com/zcloud/basic/info/command/UserAddExe.java +++ b/web-app/src/main/java/com/zcloud/basic/info/command/UserAddExe.java @@ -33,6 +33,7 @@ import com.zcloud.basic.info.persistence.dataobject.*; import com.zcloud.basic.info.persistence.repository.*; import com.zcloud.gbscommon.utils.*; import lombok.AllArgsConstructor; +import lombok.Data; import lombok.extern.slf4j.Slf4j; import org.apache.dubbo.config.annotation.DubboReference; import org.springframework.beans.BeanUtils; @@ -64,6 +65,11 @@ import java.util.Base64; @AllArgsConstructor @Slf4j public class UserAddExe { + @Data + public static class DaHuaSyncResult { + private Integer dahuaId; + private String dahuaCode; + } private final UserGateway userGateway; private final UserExpandInfoGateway userExpandInfoGateway; private UserCoConvertor userCoConvertor; @@ -179,8 +185,7 @@ public class UserAddExe { userE.setUserType(CorpTypeEnum.getUserTypeByCode(corpInfoDO.getType())); userE.resetPassword(corpInfoDO.getType()); - //先同步大华人脸平台,成功后再保存本地 - syncDaHuaPerson(userE); + // ① 先本地落库 + 底座GBS新增。GBS失败抛 RuntimeException,整个事务回滚 res = userGateway.add(userE); if (corpInfoDO != null && !ObjectUtils.isEmpty(corpInfoDO.getCorpName())) { corpName = corpInfoDO.getCorpName(); @@ -196,6 +201,23 @@ public class UserAddExe { } catch (Exception e) { log.error("用户变更记录保存失败(不影响用户主体), userId: {}, error: {}", userE.getId(), e.getMessage(), e); } + // ② 本地和底座都成功后,最后才同步大华。失败→抛异常→回滚本地+GBS(避免留下"大华人成功但本地没数据") + DaHuaSyncResult syncResult = syncDaHuaPerson(userE); + if (syncResult.dahuaId != null || (syncResult.dahuaCode != null && !syncResult.dahuaCode.trim().isEmpty())) { + try { + UserE updateDahua = new UserE(); + updateDahua.setId(userE.getId()); + updateDahua.setDahuaId(syncResult.dahuaId); + updateDahua.setDahuaCode(syncResult.dahuaCode); + userRepository.updateDahuaInfo(updateDahua.getId(), updateDahua.getDahuaId(), updateDahua.getDahuaCode()); + log.info("写回dahuaId/dahuaCode成功, userId={}, dahuaId={}, dahuaCode={}", + userE.getId(), syncResult.dahuaId, syncResult.dahuaCode); + } catch (Exception e) { + log.error("写回dahuaId/dahuaCode失败, userId={}, dahuaId={}, dahuaCode={}", + userE.getId(), syncResult.dahuaId, syncResult.dahuaCode, e); + throw new BizException("写回大华信息到本地失败:" + e.getMessage()); + } + } } catch (BizException e) { log.error("新增用户业务异常: {}", e.getMessage(), e); throw e; @@ -212,7 +234,7 @@ public class UserAddExe { return true; } - private void syncDaHuaPerson(UserE userE) { + private DaHuaSyncResult syncDaHuaPerson(UserE userE) { Map personMap = new HashMap<>(); personMap.put("name", userE.getName()); String idCard = userE.getUserIdCard(); @@ -416,8 +438,10 @@ public class UserAddExe { Map syncResult = daHuaConfig.syncPerson(personMap, extraHeaders); Boolean success = (Boolean) syncResult.get("success"); Boolean skipped = (Boolean) syncResult.get("skipped"); + DaHuaSyncResult result = new DaHuaSyncResult(); + result.setDahuaCode(plainIdCard); if (skipped != null && skipped) { - return; + return result; } String maskedIdCard = plainIdCard; if (plainIdCard != null && plainIdCard.length() >= 14) { @@ -436,6 +460,7 @@ public class UserAddExe { if (idObj != null) { try { Integer dahuaId = Integer.valueOf(idObj.toString()); + result.setDahuaId(dahuaId); userE.setDahuaId(dahuaId); log.info("设置大华dahuaId成功, dahuaId={}", dahuaId); } catch (Exception e) { @@ -448,6 +473,7 @@ public class UserAddExe { if (idObj != null) { try { Integer dahuaId = Integer.valueOf(idObj.toString()); + result.setDahuaId(dahuaId); userE.setDahuaId(dahuaId); log.info("设置大华dahuaId成功, dahuaId={}", dahuaId); } catch (Exception e) { @@ -457,6 +483,7 @@ public class UserAddExe { } } userE.setDahuaCode(plainIdCard); + return result; } @Transactional(rollbackFor = Exception.class) diff --git a/web-app/src/main/java/com/zcloud/basic/info/command/UserRemoveExe.java b/web-app/src/main/java/com/zcloud/basic/info/command/UserRemoveExe.java index 67ac9ea8..bdde32bd 100644 --- a/web-app/src/main/java/com/zcloud/basic/info/command/UserRemoveExe.java +++ b/web-app/src/main/java/com/zcloud/basic/info/command/UserRemoveExe.java @@ -20,6 +20,7 @@ import com.zcloud.basic.info.persistence.dataobject.UserJobHandoverDO; import com.zcloud.basic.info.persistence.repository.UserCorpRecordRepository; import com.zcloud.basic.info.persistence.repository.UserJobHandoverRepository; import com.zcloud.basic.info.persistence.repository.UserRepository; +import com.zcloud.basic.info.domain.config.DaHuaConfig; import com.zcloud.gbscommon.utils.ZcloudRedisUtil; import lombok.AllArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -27,9 +28,12 @@ import org.apache.dubbo.config.annotation.DubboReference; import org.springframework.beans.BeanUtils; import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; -import java.util.Arrays; -import java.util.List; +import javax.servlet.http.HttpServletRequest; +import java.util.*; +import java.util.stream.Collectors; /** @@ -51,21 +55,53 @@ public class UserRemoveExe { // @Autowired private ZcloudRedisUtil zcloudRedisUtil; private final UserCorpRecordRepository userCorpRecordRepository; + private final DaHuaConfig daHuaConfig; @Transactional(rollbackFor = Exception.class) public boolean execute(Long id) { try { UserDO userDO = userRepository.getInfoById(id); + boolean needDeleteDaHua = false; + Integer dahuaId = null; if (userDO != null) { + dahuaId = userDO.getDahuaId(); + log.info("【单个删除-前置检查】id={}, name={}, dahuaId={}, dahuaCode={}", + id, userDO.getName(), dahuaId, userDO.getDahuaCode()); boolean canDelete = addDeleteChangeRecord(userDO); if (!canDelete) { + log.info("【单个删除-保留本地用户】存在未完成工作交接,不执行真正删除,因此也不删大华, userId={}", id); return true; } + needDeleteDaHua = (dahuaId != null); } + // ① 先本地逻辑删除(事务内,还未提交) userGateway.deletedUserById(id); + + // ② 本地操作完成后再删大华。若大华失败 → throw BizException → 本地全部回滚 + if (needDeleteDaHua) { + Map deleteResult = daHuaConfig.deletePerson( + Collections.singletonList(dahuaId), getDaHuaExtraHeaders()); + Boolean skipped = (Boolean) deleteResult.get("skipped"); + if (skipped == null || !skipped) { + Boolean success = (Boolean) deleteResult.get("success"); + String errCode = (String) deleteResult.getOrDefault("errCode", ""); + String errMessage = (String) deleteResult.getOrDefault("errMessage", ""); + if (success == null || !success) { + log.error("【单个删除-大华删除失败→触发本地回滚】userId={}, dahuaId={}, errCode={}, errMessage={}", + id, dahuaId, errCode, errMessage); + throw new BizException("删除大华平台人员失败:" + errMessage); + } + log.info("【单个删除-大华删除成功】userId={}, dahuaId={}", id, dahuaId); + } else { + log.info("【单个删除-大华删除跳过】dockFlag未开启, userId={}", id); + } + } + } catch (BizException e) { + log.error("单个删除用户业务异常: {}", e.getMessage(), e); + throw e; } catch (Exception e){ - e.printStackTrace(); - throw new BizException("数据异常,请联系管理员删除"); + log.error("单个删除用户系统异常: {}", e.getMessage(), e); + throw new BizException("删除失败:" + e.getMessage()); } return true; } @@ -153,24 +189,83 @@ public class UserRemoveExe { } catch (Exception e){ - e.printStackTrace(); + log.error("APP用户注销系统异常: {}", e.getMessage(), e); throw new BizException("删除失败"); } return true; } + private Map getDaHuaExtraHeaders() { + Map extraHeaders = new HashMap<>(); + try { + ServletRequestAttributes attrs = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); + if (attrs != null) { + HttpServletRequest req = attrs.getRequest(); + String token = req.getHeader("token"); + String orgid = req.getHeader("orgid"); + String tenantId = req.getHeader("tenantId"); + if (token != null && !token.trim().isEmpty()) { + extraHeaders.put("token", token); + } + if (orgid != null && !orgid.trim().isEmpty()) { + extraHeaders.put("orgid", orgid); + } + if (tenantId != null && !tenantId.trim().isEmpty()) { + extraHeaders.put("tenantId", tenantId); + } + } + } catch (Exception e) { + log.warn("获取大华透传请求头失败: {}", e.getMessage()); + } + return extraHeaders; + } @Transactional(rollbackFor = Exception.class) public boolean execute(Long[] ids) { - boolean res = userGateway.deletedUserByIds(ids); - if(!res){ - throw new BizException("删除失败"); - } -// for (Long id : ids) { -// zcloudRedisUtil.del(Const.REDIS_USER_PREFIX+id); -// } - return true; - } -} + try { + List idList = Arrays.asList(ids); + List userDOList = userRepository.listByIds(idList); + List dahuaIds = userDOList.stream() + .filter(Objects::nonNull) + .map(UserDO::getDahuaId) + .filter(Objects::nonNull) + .distinct() + .collect(Collectors.toList()); + log.info("【批量删除-前置检查】本地ids={}, 待删大华dahuaIds={}", idList, dahuaIds); + // ① 先本地逻辑删除(事务内,还未提交) + boolean res = userGateway.deletedUserByIds(ids); + if (!res) { + throw new BizException("本地批量删除用户失败"); + } + + // ② 本地成功后再删大华。大华失败→throw→本地回滚 + if (!dahuaIds.isEmpty()) { + Map extraHeaders = getDaHuaExtraHeaders(); + Map deleteResult = daHuaConfig.deletePerson(dahuaIds, extraHeaders); + Boolean skipped = (Boolean) deleteResult.get("skipped"); + if (skipped == null || !skipped) { + Boolean success = (Boolean) deleteResult.get("success"); + String errCode = (String) deleteResult.getOrDefault("errCode", ""); + String errMessage = (String) deleteResult.getOrDefault("errMessage", ""); + if (success == null || !success) { + log.error("【批量删除-大华删除失败→触发本地回滚】localIds={}, dahuaIds={}, errCode={}, errMessage={}", + idList, dahuaIds, errCode, errMessage); + throw new BizException("删除大华平台人员失败:" + errMessage); + } + log.info("【批量删除-大华删除成功】dahuaIds={}", dahuaIds); + } else { + log.info("【批量删除-大华删除跳过】dockFlag未开启, idList={}", idList); + } + } + return true; + } catch (BizException e) { + log.error("批量删除用户业务异常: {}", e.getMessage(), e); + throw e; + } catch (Exception e) { + log.error("批量删除用户系统异常: {}", e.getMessage(), e); + throw new BizException("批量删除失败:" + e.getMessage()); + } + } +} \ No newline at end of file diff --git a/web-domain/src/main/java/com/zcloud/basic/info/domain/config/DaHuaConfig.java b/web-domain/src/main/java/com/zcloud/basic/info/domain/config/DaHuaConfig.java index d5aad7a2..58fe9ce3 100644 --- a/web-domain/src/main/java/com/zcloud/basic/info/domain/config/DaHuaConfig.java +++ b/web-domain/src/main/java/com/zcloud/basic/info/domain/config/DaHuaConfig.java @@ -188,4 +188,80 @@ public class DaHuaConfig { return resultMap; } } + + public Map deletePerson(List ids) { + return deletePerson(ids, null); + } + + public Map deletePerson(List ids, Map extraHeaders) { + Map resultMap = new HashMap<>(); + log.info("========== 大华人员(删除)调用开始 =========="); + log.info("dockFlag配置值={}, primeportUrl={}, primeportGateway={}, ids={}", dockFlag, primeportUrl, primeportGateway, ids); + if (dockFlag == null || dockFlag != 1) { + log.info("大华对接未开启(dockFlag={}), 跳过删除大华人员", dockFlag); + resultMap.put("success", true); + resultMap.put("skipped", true); + return resultMap; + } + if (ids == null || ids.isEmpty()) { + log.info("待删除大华ids为空, 跳过删除"); + resultMap.put("success", true); + resultMap.put("skipped", true); + return resultMap; + } + String baseUrl = primeportUrl; + if (baseUrl == null || baseUrl.trim().isEmpty()) { + throw new RuntimeException("大华对接网关地址未配置(dahua.config.primeportUrl)"); + } + baseUrl = baseUrl.trim(); + if (baseUrl.endsWith("/")) { + baseUrl = baseUrl.substring(0, baseUrl.length() - 1); + } + String gw = (primeportGateway == null || primeportGateway.trim().isEmpty()) ? "basicInfo" : primeportGateway.trim(); + String url = baseUrl + "/" + gw + "/dahua/person/delete"; + Map reqMap = new HashMap<>(); + reqMap.put("ids", ids); + String reqJson = JSONUtil.toJsonStr(reqMap); + log.info("【实际请求URL】method=POST, url={}", url); + log.info("【传给大华的请求体(JSON)】{}", reqJson); + try { + HttpRequest request = HttpRequest.post(url) + .header("Content-Type", "application/json;charset=UTF-8") + .timeout(30000) + .body(reqJson); + if (extraHeaders != null && !extraHeaders.isEmpty()) { + extraHeaders.forEach((k, v) -> { + if (k != null && v != null) { + request.header(k, v); + } + }); + log.info("【透传请求头】{}", extraHeaders); + } + String respBody = request.execute().body(); + log.info("【大华接口原始返回】{}", respBody); + if (respBody == null || respBody.trim().isEmpty()) { + resultMap.put("success", false); + resultMap.put("errCode", "EMPTY_RESPONSE"); + resultMap.put("errMessage", "大华人员删除接口返回为空"); + return resultMap; + } + JSONObject respJson = JSONUtil.parseObj(respBody); + Boolean success = respJson.getBool("success", false); + String errCode = respJson.getStr("errCode", ""); + String errMessage = respJson.getStr("errMessage", ""); + Object data = respJson.get("data"); + resultMap.put("success", success); + resultMap.put("errCode", errCode); + resultMap.put("errMessage", errMessage); + resultMap.put("data", data); + log.info("【解析后返回】success={}, errCode={}, errMessage={}, data={}", success, errCode, errMessage, data); + return resultMap; + } catch (Exception e) { + log.error("调用大华人员删除接口异常: {}", e.getMessage(), e); + resultMap.put("success", false); + resultMap.put("errCode", "HTTP_EXCEPTION"); + resultMap.put("errMessage", "调用大华人员删除接口异常: " + e.getMessage()); + return resultMap; + } + } } \ No newline at end of file diff --git a/web-infrastructure/src/main/java/com/zcloud/basic/info/persistence/repository/UserRepository.java b/web-infrastructure/src/main/java/com/zcloud/basic/info/persistence/repository/UserRepository.java index 5bd53dca..036ec83d 100644 --- a/web-infrastructure/src/main/java/com/zcloud/basic/info/persistence/repository/UserRepository.java +++ b/web-infrastructure/src/main/java/com/zcloud/basic/info/persistence/repository/UserRepository.java @@ -61,6 +61,8 @@ public interface UserRepository extends BaseRepository { void updateUserName(UserDO userDO); + void updateDahuaInfo(Long userId, Integer dahuaId, String dahuaCode); + Map getDepartmentLeaderByDepartmentId(List departmentIds); Long getDefaultRoleId(); @@ -118,5 +120,4 @@ public interface UserRepository extends BaseRepository { void updateEmploymentFlagAndDeleteEnum(Long id, Integer code, String aTrue); PageResponse pageByNopermissionAll(Map params); -} - +} \ No newline at end of file diff --git a/web-infrastructure/src/main/java/com/zcloud/basic/info/persistence/repository/impl/UserRepositoryImpl.java b/web-infrastructure/src/main/java/com/zcloud/basic/info/persistence/repository/impl/UserRepositoryImpl.java index bc62fcd2..8060c92e 100644 --- a/web-infrastructure/src/main/java/com/zcloud/basic/info/persistence/repository/impl/UserRepositoryImpl.java +++ b/web-infrastructure/src/main/java/com/zcloud/basic/info/persistence/repository/impl/UserRepositoryImpl.java @@ -542,6 +542,27 @@ public class UserRepositoryImpl extends BaseRepositoryImpl i } } + @Override + public void updateDahuaInfo(Long userId, Integer dahuaId, String dahuaCode) { + if (userId == null) { + return; + } + UpdateWrapper uw = new UpdateWrapper<>(); + uw.eq("id", userId); + boolean hasSet = false; + if (dahuaId != null) { + uw.set("dahua_id", dahuaId); + hasSet = true; + } + if (dahuaCode != null) { + uw.set("dahua_code", dahuaCode); + hasSet = true; + } + if (hasSet) { + update(uw); + } + } + @Override public Map getDepartmentLeaderByDepartmentId(List departmentIds) { List departmentLeaderList = userMapper.getDepartmentLeaderByDepartmentId(departmentIds); @@ -816,4 +837,4 @@ public class UserRepositoryImpl extends BaseRepositoryImpl i public void updateEmploymentFlagAndDeleteEnum(Long userId, Integer employmentFlag, String deleteEnum) { userMapper.updateEmploymentFlagAndDeleteEnum(userId, employmentFlag, deleteEnum); } -} +} \ No newline at end of file