|
|
@@ -3,31 +3,69 @@ package com.usky.sas.service.impl;
|
|
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
|
|
import com.baomidou.mybatisplus.core.metadata.IPage;
|
|
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
|
|
+import com.fasterxml.jackson.databind.ObjectMapper;
|
|
|
import com.usky.common.core.bean.CommonPage;
|
|
|
import com.usky.sas.domain.SasFollowPerson;
|
|
|
import com.usky.sas.domain.SasPerson;
|
|
|
+import com.usky.sas.domain.SasCredentialTypeCode;
|
|
|
+import com.usky.sas.domain.SasPeopleTypeCode;
|
|
|
import com.usky.sas.mapper.SasFollowPersonMapper;
|
|
|
import com.usky.sas.mapper.SasPersonMapper;
|
|
|
+import com.usky.sas.mapper.SasCredentialTypeCodeMapper;
|
|
|
+import com.usky.sas.mapper.SasPeopleTypeCodeMapper;
|
|
|
+import com.usky.sas.mapper.SasVillageMapper;
|
|
|
+import com.usky.sas.domain.SasVillage;
|
|
|
import com.usky.sas.service.SasPersonnelService;
|
|
|
+import com.usky.sas.service.SasConfigService;
|
|
|
+import com.usky.sas.service.dto.agbox.JsonRpcRequest;
|
|
|
+import com.usky.sas.service.dto.agbox.PersonVo;
|
|
|
+import com.usky.sas.service.dto.agbox.PersonBlackListVO;
|
|
|
import com.usky.sas.service.vo.PersonnelDetailResponse;
|
|
|
import com.usky.sas.service.vo.PersonnelListItem;
|
|
|
import com.usky.sas.service.vo.PersonnelPageRequest;
|
|
|
+import cn.hutool.http.HttpRequest;
|
|
|
+import cn.hutool.json.JSONUtil;
|
|
|
+import lombok.extern.slf4j.Slf4j;
|
|
|
import org.springframework.beans.factory.annotation.Autowired;
|
|
|
import org.springframework.stereotype.Service;
|
|
|
|
|
|
-import java.util.Collections;
|
|
|
-import java.util.List;
|
|
|
+import java.time.LocalDateTime;
|
|
|
+import java.time.format.DateTimeFormatter;
|
|
|
+import java.util.*;
|
|
|
import java.util.stream.Collectors;
|
|
|
|
|
|
+@Slf4j
|
|
|
@Service
|
|
|
public class SasPersonnelServiceImpl implements SasPersonnelService {
|
|
|
|
|
|
+ /** 关注人员/黑名单 AG 路径 */
|
|
|
+ private static final String AGBOX_PERSON_PATH = "/agbox/person";
|
|
|
+ private static final String AGBOX_VILLAGE_PATH = "/agbox/village";
|
|
|
+ /** getBlackList 请求中写死的 eventCode(关注类型) */
|
|
|
+ private static final int FOLLOW_EVENT_CODE = 904;
|
|
|
+ private static final int PERSON_PAGE_SIZE = 100;
|
|
|
+ private static final int HTTP_TIMEOUT_MS = 90000;
|
|
|
+ private static final int MAX_RETRIES = 5;
|
|
|
+ private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
|
|
|
+
|
|
|
@Autowired
|
|
|
private SasPersonMapper sasPersonMapper;
|
|
|
|
|
|
+ @Autowired
|
|
|
+ private SasConfigService sasConfigService;
|
|
|
+
|
|
|
@Autowired
|
|
|
private SasFollowPersonMapper sasFollowPersonMapper;
|
|
|
|
|
|
+ @Autowired
|
|
|
+ private SasCredentialTypeCodeMapper sasCredentialTypeCodeMapper;
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private SasPeopleTypeCodeMapper sasPeopleTypeCodeMapper;
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private SasVillageMapper sasVillageMapper;
|
|
|
+
|
|
|
@Override
|
|
|
public CommonPage<PersonnelListItem> whitelistPage(PersonnelPageRequest request) {
|
|
|
// 目前按人员表简单分页,后续可根据白名单标识补充筛选条件
|
|
|
@@ -70,8 +108,169 @@ public class SasPersonnelServiceImpl implements SasPersonnelService {
|
|
|
|
|
|
@Override
|
|
|
public int syncRegistered() {
|
|
|
- // 预留与 agbox 同步实现
|
|
|
- return 0;
|
|
|
+ com.usky.sas.domain.SasConfig config = sasConfigService.getConfig();
|
|
|
+ if (config == null || config.getKeyds() == null || config.getHost() == null) {
|
|
|
+ log.warn("同步在册人员失败:未配置 AG 接口(key/host)");
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+ String villageCode = getVillageCodeForSync();
|
|
|
+ if (villageCode == null || villageCode.isEmpty()) {
|
|
|
+ log.warn("同步在册人员失败:地块信息表中无可用地块(请先同步地块或设置默认地块)");
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+ String baseUrl = buildAgboxBaseUrl(config.getHost(), config.getPort());
|
|
|
+ String villageUrl = baseUrl + AGBOX_VILLAGE_PATH;
|
|
|
+ String key = config.getKeyds();
|
|
|
+ ObjectMapper mapper = new ObjectMapper();
|
|
|
+ int totalSynced = 0;
|
|
|
+ int page = 1;
|
|
|
+
|
|
|
+ try {
|
|
|
+ while (true) {
|
|
|
+ Map<String, Object> params = new HashMap<>();
|
|
|
+ params.put("page", page);
|
|
|
+ params.put("pageSize", PERSON_PAGE_SIZE);
|
|
|
+ params.put("villageCode", villageCode);
|
|
|
+ JsonRpcRequest getPersonJson = new JsonRpcRequest("getPerson", params, null);
|
|
|
+ Map<String, Object> requestBody = new HashMap<>();
|
|
|
+ requestBody.put("key", key);
|
|
|
+ requestBody.put("json", JSONUtil.toJsonStr(getPersonJson));
|
|
|
+ log.info("请求AG在册人员,page={}:{}", page, JSONUtil.toJsonStr(getPersonJson));
|
|
|
+
|
|
|
+ String resultStr = postWithRetry(villageUrl, requestBody);
|
|
|
+ log.info("AG在册人员响应 page={}:{}", page, resultStr);
|
|
|
+
|
|
|
+ PersonVo personVo = mapper.readValue(resultStr, PersonVo.class);
|
|
|
+ PersonVo.PersonResult result = personVo != null ? personVo.getResult() : null;
|
|
|
+ List<PersonVo.PersonMsg> personList = (result != null && result.getPerson() != null) ? result.getPerson() : Collections.emptyList();
|
|
|
+
|
|
|
+ if (personList.isEmpty()) {
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ for (PersonVo.PersonMsg msg : personList) {
|
|
|
+ if (msg.getPersonCode() == null || msg.getPersonCode().isEmpty()) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ try {
|
|
|
+ SasPerson entity = personMsgToSasPerson(msg);
|
|
|
+ SasPerson exist = sasPersonMapper.selectById(msg.getPersonCode());
|
|
|
+ LocalDateTime now = LocalDateTime.now();
|
|
|
+ if (exist != null) {
|
|
|
+ entity.setCreateTime(exist.getCreateTime());
|
|
|
+ entity.setUpdateTime(now);
|
|
|
+ sasPersonMapper.updateById(entity);
|
|
|
+ } else {
|
|
|
+ entity.setCreateTime(now);
|
|
|
+ entity.setUpdateTime(now);
|
|
|
+ sasPersonMapper.insert(entity);
|
|
|
+ }
|
|
|
+ totalSynced++;
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("同步在册人员 {} 失败:{}", msg.getPersonCode(), e.getMessage(), e);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (personList.size() < PERSON_PAGE_SIZE) {
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ page++;
|
|
|
+ }
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("同步在册人员失败:{}", e.getMessage(), e);
|
|
|
+ }
|
|
|
+ log.info("在册人员同步完成,共同步 {} 条", totalSynced);
|
|
|
+ return totalSynced;
|
|
|
+ }
|
|
|
+
|
|
|
+ private SasPerson personMsgToSasPerson(PersonVo.PersonMsg msg) {
|
|
|
+ SasPerson entity = new SasPerson();
|
|
|
+ entity.setPersonCode(msg.getPersonCode());
|
|
|
+ entity.setName(msg.getName());
|
|
|
+ entity.setCredentialType(msg.getCredentialType());
|
|
|
+ entity.setCredentialNo(msg.getCredentialNo());
|
|
|
+ entity.setPhone1(msg.getPhone1());
|
|
|
+ entity.setPhone2(msg.getPhone2());
|
|
|
+ entity.setPhone3(msg.getPhone3());
|
|
|
+ entity.setPeopleTypeCode(msg.getPersonTypeCode());
|
|
|
+ entity.setPersonEntranceTypeCode(msg.getPersonEntranceTypeCode());
|
|
|
+ entity.setEntranceTypeCode(msg.getEntranceTypeCode());
|
|
|
+ entity.setCompanyCode(msg.getCompanyCode());
|
|
|
+ entity.setOrigin(msg.getOrigin());
|
|
|
+ entity.setPlaceOfBirth(msg.getPlaceOfBirth());
|
|
|
+ entity.setEducationCode(msg.getEducationCode());
|
|
|
+ entity.setMaritalStatusCode(msg.getMaritalStatusCode());
|
|
|
+ entity.setNationalityCode(msg.getNationalityCode());
|
|
|
+ if (msg.getPicId() != null && !msg.getPicId().isEmpty()) {
|
|
|
+ entity.setPicId(msg.getPicId());
|
|
|
+ } else if (msg.getFacePicUrl() != null) {
|
|
|
+ String url = msg.getFacePicUrl().getUrl();
|
|
|
+ String path = msg.getFacePicUrl().getPath();
|
|
|
+ if (url != null && path != null) {
|
|
|
+ entity.setPicId(url + path);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (msg.getUpdateTime() != null && !msg.getUpdateTime().isEmpty()) {
|
|
|
+ try {
|
|
|
+ entity.setUpdateTime(LocalDateTime.parse(msg.getUpdateTime(), DATE_TIME_FORMATTER));
|
|
|
+ } catch (Exception ignored) {
|
|
|
+ entity.setUpdateTime(LocalDateTime.now());
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return entity;
|
|
|
+ }
|
|
|
+
|
|
|
+ private String buildAgboxBaseUrl(String host, String port) {
|
|
|
+ if (host == null || host.isEmpty()) {
|
|
|
+ return "";
|
|
|
+ }
|
|
|
+ if (host.startsWith("http://") || host.startsWith("https://")) {
|
|
|
+ return host;
|
|
|
+ }
|
|
|
+ return "http://" + host;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 从地块信息表动态获取用于同步的 villageCode:优先取默认地块(is_default=true),若无则取第一条。
|
|
|
+ */
|
|
|
+ private String getVillageCodeForSync() {
|
|
|
+ LambdaQueryWrapper<SasVillage> wrapper = new LambdaQueryWrapper<>();
|
|
|
+ wrapper.eq(SasVillage::getIsDefault, true).last("limit 1");
|
|
|
+ List<SasVillage> list = sasVillageMapper.selectList(wrapper);
|
|
|
+ if (list != null && !list.isEmpty()) {
|
|
|
+ return list.get(0).getVillageCode();
|
|
|
+ }
|
|
|
+ wrapper = new LambdaQueryWrapper<>();
|
|
|
+ wrapper.last("limit 1");
|
|
|
+ list = sasVillageMapper.selectList(wrapper);
|
|
|
+ return (list != null && !list.isEmpty()) ? list.get(0).getVillageCode() : null;
|
|
|
+ }
|
|
|
+
|
|
|
+ private String postWithRetry(String url, Map<String, Object> requestBody) {
|
|
|
+ Exception lastEx = null;
|
|
|
+ for (int i = 0; i < MAX_RETRIES; i++) {
|
|
|
+ try {
|
|
|
+ return HttpRequest.post(url)
|
|
|
+ .form(requestBody)
|
|
|
+ .timeout(HTTP_TIMEOUT_MS)
|
|
|
+ .execute()
|
|
|
+ .body();
|
|
|
+ } catch (Exception e) {
|
|
|
+ lastEx = e;
|
|
|
+ if (i < MAX_RETRIES - 1) {
|
|
|
+ long delayMs = 2000L * (i + 1);
|
|
|
+ log.warn("AG 接口请求失败,第 {} 次重试({}ms 后):{}", i + 1, delayMs, e.getMessage());
|
|
|
+ try {
|
|
|
+ Thread.sleep(delayMs);
|
|
|
+ } catch (InterruptedException ie) {
|
|
|
+ Thread.currentThread().interrupt();
|
|
|
+ throw new RuntimeException("重试被中断", ie);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ String causeMsg = lastEx != null ? lastEx.getMessage() : "";
|
|
|
+ throw new RuntimeException("AG 接口请求失败,重试 " + MAX_RETRIES + " 次后仍失败:" + causeMsg, lastEx);
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
@@ -81,7 +280,7 @@ public class SasPersonnelServiceImpl implements SasPersonnelService {
|
|
|
|
|
|
@Override
|
|
|
public CommonPage<PersonnelListItem> followPage(PersonnelPageRequest request) {
|
|
|
- IPage<SasFollowPerson> page = new Page<>(request.getPage(), request.getPageSize());
|
|
|
+ IPage<SasFollowPerson> page = new Page<>(request.getCurrent(), request.getSize());
|
|
|
LambdaQueryWrapper<SasFollowPerson> wrapper = new LambdaQueryWrapper<>();
|
|
|
if (request.getName() != null && !request.getName().isEmpty()) {
|
|
|
wrapper.like(SasFollowPerson::getName, request.getName());
|
|
|
@@ -98,8 +297,96 @@ public class SasPersonnelServiceImpl implements SasPersonnelService {
|
|
|
|
|
|
@Override
|
|
|
public int syncFollow() {
|
|
|
- // 预留与 agbox 同步实现
|
|
|
- return 0;
|
|
|
+ com.usky.sas.domain.SasConfig config = sasConfigService.getConfig();
|
|
|
+ if (config == null || config.getKeyds() == null || config.getHost() == null) {
|
|
|
+ log.warn("同步关注人员失败:未配置 AG 接口(key/host)");
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+ String baseUrl = buildAgboxBaseUrl(config.getHost(), config.getPort());
|
|
|
+ String personUrl = baseUrl + AGBOX_PERSON_PATH;
|
|
|
+ String key = config.getKeyds();
|
|
|
+ ObjectMapper mapper = new ObjectMapper();
|
|
|
+ int totalSynced = 0;
|
|
|
+ int page = 1;
|
|
|
+
|
|
|
+ try {
|
|
|
+ while (true) {
|
|
|
+ Map<String, Object> params = new HashMap<>();
|
|
|
+ params.put("page", page);
|
|
|
+ params.put("pageSize", PERSON_PAGE_SIZE);
|
|
|
+ params.put("eventCode", FOLLOW_EVENT_CODE);
|
|
|
+ JsonRpcRequest getBlackListJson = new JsonRpcRequest("getBlackList", params, null);
|
|
|
+ Map<String, Object> requestBody = new HashMap<>();
|
|
|
+ requestBody.put("key", key);
|
|
|
+ requestBody.put("json", JSONUtil.toJsonStr(getBlackListJson));
|
|
|
+ log.info("请求AG关注人员(getBlackList),page={}:{}", page, JSONUtil.toJsonStr(getBlackListJson));
|
|
|
+
|
|
|
+ String resultStr = postWithRetry(personUrl, requestBody);
|
|
|
+ log.info("AG关注人员响应 page={}:{}", page, resultStr);
|
|
|
+
|
|
|
+ PersonBlackListVO vo = mapper.readValue(resultStr, PersonBlackListVO.class);
|
|
|
+ PersonBlackListVO.PersonBlackResult result = vo != null ? vo.getResult() : null;
|
|
|
+ List<PersonBlackListVO.PersonBlackList> blackList = (result != null && result.getBlackList() != null) ? result.getBlackList() : Collections.emptyList();
|
|
|
+
|
|
|
+ if (blackList.isEmpty()) {
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ int indexInPage = 0;
|
|
|
+ for (PersonBlackListVO.PersonBlackList item : blackList) {
|
|
|
+ String personCode = item.getPersonCode();
|
|
|
+ if (personCode == null || personCode.isEmpty()) {
|
|
|
+ personCode = "follow_" + FOLLOW_EVENT_CODE + "_" + page + "_" + indexInPage;
|
|
|
+ }
|
|
|
+ indexInPage++;
|
|
|
+ try {
|
|
|
+ SasFollowPerson entity = blackListItemToFollowPerson(personCode, item);
|
|
|
+ SasFollowPerson exist = sasFollowPersonMapper.selectById(entity.getPersonCode());
|
|
|
+ LocalDateTime now = LocalDateTime.now();
|
|
|
+ if (exist != null) {
|
|
|
+ entity.setCreateTime(exist.getCreateTime());
|
|
|
+ entity.setUpdateTime(now);
|
|
|
+ sasFollowPersonMapper.updateById(entity);
|
|
|
+ } else {
|
|
|
+ entity.setCreateTime(now);
|
|
|
+ entity.setUpdateTime(now);
|
|
|
+ sasFollowPersonMapper.insert(entity);
|
|
|
+ }
|
|
|
+ totalSynced++;
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("同步关注人员 {} 失败:{}", personCode, e.getMessage(), e);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (blackList.size() < PERSON_PAGE_SIZE) {
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ page++;
|
|
|
+ }
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("同步关注人员失败:{}", e.getMessage(), e);
|
|
|
+ }
|
|
|
+ log.info("关注人员同步完成,共同步 {} 条", totalSynced);
|
|
|
+ return totalSynced;
|
|
|
+ }
|
|
|
+
|
|
|
+ private SasFollowPerson blackListItemToFollowPerson(String personCode, PersonBlackListVO.PersonBlackList item) {
|
|
|
+ SasFollowPerson entity = new SasFollowPerson();
|
|
|
+ entity.setPersonCode(personCode);
|
|
|
+ entity.setName(item.getNote() != null ? item.getNote() : item.getPersonCode());
|
|
|
+ entity.setFollowPeopleType(item.getEventCode());
|
|
|
+ if (item.getPicUrl() != null) {
|
|
|
+ String url = item.getPicUrl().getUrl();
|
|
|
+ String path = item.getPicUrl().getPath();
|
|
|
+ if (url != null && path != null) {
|
|
|
+ entity.setPicId(url + path);
|
|
|
+ } else if (path != null) {
|
|
|
+ entity.setPicId(path);
|
|
|
+ } else if (url != null) {
|
|
|
+ entity.setPicId(url);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return entity;
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
@@ -117,7 +404,7 @@ public class SasPersonnelServiceImpl implements SasPersonnelService {
|
|
|
}
|
|
|
|
|
|
private CommonPage<PersonnelListItem> buildPersonPage(PersonnelPageRequest request) {
|
|
|
- IPage<SasPerson> page = new Page<>(request.getPage(), request.getPageSize());
|
|
|
+ IPage<SasPerson> page = new Page<>(request.getCurrent(), request.getSize());
|
|
|
LambdaQueryWrapper<SasPerson> wrapper = new LambdaQueryWrapper<>();
|
|
|
if (request.getName() != null && !request.getName().isEmpty()) {
|
|
|
wrapper.like(SasPerson::getName, request.getName());
|
|
|
@@ -147,10 +434,24 @@ public class SasPersonnelServiceImpl implements SasPersonnelService {
|
|
|
detail.setName(person.getName());
|
|
|
detail.setCredentialType(person.getCredentialType());
|
|
|
detail.setCredentialNo(person.getCredentialNo());
|
|
|
+ // 证件类型名称:从 sas_credential_type_code 查询
|
|
|
+ if (person.getCredentialType() != null) {
|
|
|
+ SasCredentialTypeCode ct = sasCredentialTypeCodeMapper.selectById(person.getCredentialType());
|
|
|
+ detail.setCredentialTypeName(ct != null ? ct.getName() : null);
|
|
|
+ }
|
|
|
detail.setPicId(person.getPicId());
|
|
|
detail.setPhone1(person.getPhone1());
|
|
|
detail.setPhone2(person.getPhone2());
|
|
|
+ detail.setPhone3(person.getPhone3());
|
|
|
+ detail.setRemark(null); // sas_person 表无备注字段,可后续扩展
|
|
|
detail.setPeopleTypeCode(person.getPeopleTypeCode());
|
|
|
+ // 人员类型名称:从 sas_people_type_code 查询(code 为字符串)
|
|
|
+ if (person.getPeopleTypeCode() != null) {
|
|
|
+ SasPeopleTypeCode pt = sasPeopleTypeCodeMapper.selectById(String.valueOf(person.getPeopleTypeCode()));
|
|
|
+ detail.setPeopleTypeName(pt != null ? pt.getName() : null);
|
|
|
+ }
|
|
|
+ detail.setEntranceTypeCode(person.getEntranceTypeCode());
|
|
|
+ detail.setEntranceTypeName(null); // 暂无出入类型编码表,可后续扩展
|
|
|
detail.setEducationCode(person.getEducationCode());
|
|
|
detail.setMaritalStatusCode(person.getMaritalStatusCode());
|
|
|
detail.setNationalityCode(person.getNationalityCode());
|