1、人员定位大屏区域匹配
parent
4d24075d22
commit
44fb60dd2c
|
|
@ -107,6 +107,8 @@ public class BiPersonLocationProvider {
|
|||
location.setLastLocationTime(row.getLastLocationTime());
|
||||
location.setLon(row.getLon());
|
||||
location.setLat(row.getLat());
|
||||
location.setLocationAreaId(row.getLocationAreaId());
|
||||
location.setLocationAreaName(row.getLocationAreaName());
|
||||
return location;
|
||||
}
|
||||
|
||||
|
|
@ -152,6 +154,8 @@ public class BiPersonLocationProvider {
|
|||
co.setLastLocationTime(location.getLastLocationTime());
|
||||
co.setLon(location.getLon());
|
||||
co.setLat(location.getLat());
|
||||
co.setLocationAreaId(location.getLocationAreaId());
|
||||
co.setLocationAreaName(location.getLocationAreaName());
|
||||
co.setStaffRawJson(location.getPersonRawJson());
|
||||
co.setLocationRawJson(location.getLocationRawJson());
|
||||
return co;
|
||||
|
|
@ -204,6 +208,8 @@ public class BiPersonLocationProvider {
|
|||
private Long lastLocationTime;
|
||||
private BigDecimal lon;
|
||||
private BigDecimal lat;
|
||||
private Long locationAreaId;
|
||||
private String locationAreaName;
|
||||
private String personRawJson;
|
||||
private String locationRawJson;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -292,27 +292,17 @@ public class PersonnelPositioningBiQueryExe {
|
|||
int pageNo = Math.max(qry.getPageIndex(), 1);
|
||||
int pageSize = Math.max(qry.getPageSize(), 1);
|
||||
Long corpinfoId = qry.getCorpinfoId();
|
||||
List<BiPersonPositionArea> areas = loadBiPersonPositionAreas(corpinfoId);
|
||||
Map<String, BiCompanyOnlinePersonCO> locationMap = loadBiPersonPositionLocationMap(corpinfoId);
|
||||
List<BiPersonPositionCO> result = new ArrayList<>();
|
||||
for (BiPersonPositionUserDO user : userRepository.listBiPersonPositionUsers(corpinfoId)) {
|
||||
BiCompanyOnlinePersonCO location = findBiPersonPositionLocation(user, locationMap);
|
||||
result.add(buildBiPersonPositionRow(user, location, areas));
|
||||
result.add(buildBiPersonPositionRow(user, location));
|
||||
}
|
||||
int fromIndex = Math.min((pageNo - 1) * pageSize, result.size());
|
||||
int toIndex = Math.min(fromIndex + pageSize, result.size());
|
||||
return PageResponse.of(result.subList(fromIndex, toIndex), result.size(), pageSize, pageNo);
|
||||
}
|
||||
|
||||
private List<BiPersonPositionArea> loadBiPersonPositionAreas(Long corpinfoId) {
|
||||
List<AreaDO> rows = areaRepository.listBiPersonPositionAreas(corpinfoId);
|
||||
List<BiPersonPositionArea> result = new ArrayList<>();
|
||||
for (AreaDO row : rows) {
|
||||
result.add(new BiPersonPositionArea(row, parseBiPersonPositionPolygon(row.getPolygonJson())));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private Map<String, BiCompanyOnlinePersonCO> loadBiPersonPositionLocationMap(Long corpinfoId) {
|
||||
List<BiCompanyOnlinePersonCO> locations =
|
||||
biPersonLocationProvider.listCompanyOnlinePersons(corpinfoId, null, null);
|
||||
|
|
@ -352,8 +342,7 @@ public class PersonnelPositioningBiQueryExe {
|
|||
}
|
||||
|
||||
private BiPersonPositionCO buildBiPersonPositionRow(BiPersonPositionUserDO user,
|
||||
BiCompanyOnlinePersonCO location,
|
||||
List<BiPersonPositionArea> areas) {
|
||||
BiCompanyOnlinePersonCO location) {
|
||||
BiPersonPositionCO co = new BiPersonPositionCO();
|
||||
co.setUserId(user.getUserId());
|
||||
co.setPersonName(user.getPersonName());
|
||||
|
|
@ -369,78 +358,12 @@ public class PersonnelPositioningBiQueryExe {
|
|||
co.setLon(location.getLon());
|
||||
co.setLat(location.getLat());
|
||||
co.setLastLocationTime(location.getLastLocationTime());
|
||||
fillBiPersonPositionArea(co, location, areas);
|
||||
// 区域已在统一人员定位查询中按实时坐标匹配,这里直接透传以避免重复计算。
|
||||
co.setAreaId(location.getLocationAreaId());
|
||||
co.setAreaName(location.getLocationAreaName());
|
||||
return co;
|
||||
}
|
||||
|
||||
private void fillBiPersonPositionArea(BiPersonPositionCO co,
|
||||
BiCompanyOnlinePersonCO location,
|
||||
List<BiPersonPositionArea> areas) {
|
||||
if (location == null || location.getLon() == null || location.getLat() == null) {
|
||||
return;
|
||||
}
|
||||
for (BiPersonPositionArea area : areas) {
|
||||
if (isBiPersonPositionInArea(location.getLon(), location.getLat(), area.points)) {
|
||||
co.setAreaId(area.area.getId());
|
||||
co.setAreaName(area.area.getAreaName());
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private List<BigDecimal[]> parseBiPersonPositionPolygon(String polygonJson) {
|
||||
List<BigDecimal[]> points = new ArrayList<>();
|
||||
if (!StringUtils.hasText(polygonJson)) {
|
||||
return points;
|
||||
}
|
||||
try {
|
||||
collectBiPersonPositionPoints(objectMapper.readTree(polygonJson), points);
|
||||
} catch (IOException e) {
|
||||
throw new BizException("区域边界坐标JSON格式错误");
|
||||
}
|
||||
return points;
|
||||
}
|
||||
|
||||
private void collectBiPersonPositionPoints(JsonNode node, List<BigDecimal[]> points) {
|
||||
if (node == null || node.isNull() || node.isMissingNode()) {
|
||||
return;
|
||||
}
|
||||
if (node.isObject()) {
|
||||
node.elements().forEachRemaining(child -> collectBiPersonPositionPoints(child, points));
|
||||
return;
|
||||
}
|
||||
if (!node.isArray()) {
|
||||
return;
|
||||
}
|
||||
if (node.size() >= 2 && node.get(0).isNumber() && node.get(1).isNumber()) {
|
||||
points.add(new BigDecimal[]{node.get(0).decimalValue(), node.get(1).decimalValue()});
|
||||
return;
|
||||
}
|
||||
for (JsonNode child : node) {
|
||||
collectBiPersonPositionPoints(child, points);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isBiPersonPositionInArea(BigDecimal lon, BigDecimal lat, List<BigDecimal[]> points) {
|
||||
if (lon == null || lat == null || points == null || points.size() < 3) {
|
||||
return false;
|
||||
}
|
||||
boolean inside = false;
|
||||
double x = lon.doubleValue();
|
||||
double y = lat.doubleValue();
|
||||
for (int i = 0, j = points.size() - 1; i < points.size(); j = i++) {
|
||||
double xi = points.get(i)[0].doubleValue();
|
||||
double yi = points.get(i)[1].doubleValue();
|
||||
double xj = points.get(j)[0].doubleValue();
|
||||
double yj = points.get(j)[1].doubleValue();
|
||||
if ((yi > y) != (yj > y)
|
||||
&& x < (xj - xi) * (y - yi) / (yj - yi) + xi) {
|
||||
inside = !inside;
|
||||
}
|
||||
}
|
||||
return inside;
|
||||
}
|
||||
|
||||
public BiCompanyOnlinePersonStatCO queryCompanyOnlinePersonStat(BiCompanyOnlinePersonStatQry qry) {
|
||||
BiCompanyOnlinePersonStatQry query = qry == null ? new BiCompanyOnlinePersonStatQry() : qry;
|
||||
validatePortArea(query.getPortArea());
|
||||
|
|
@ -1721,16 +1644,6 @@ public class PersonnelPositioningBiQueryExe {
|
|||
}
|
||||
}
|
||||
|
||||
private static class BiPersonPositionArea {
|
||||
private final AreaDO area;
|
||||
private final List<BigDecimal[]> points;
|
||||
|
||||
private BiPersonPositionArea(AreaDO area, List<BigDecimal[]> points) {
|
||||
this.area = area;
|
||||
this.points = points;
|
||||
}
|
||||
}
|
||||
|
||||
private static class StaffSnapshot {
|
||||
private JsonNode rawNode;
|
||||
private String staffName;
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ package com.zcloud.personnel.positioning.command.query;
|
|||
|
||||
import com.zcloud.personnel.positioning.dto.PositionPersonPageQry;
|
||||
import com.zcloud.personnel.positioning.persistence.dataobject.PersonnelLocalPersonDO;
|
||||
import com.zcloud.personnel.positioning.persistence.dataobject.PersonnelLocationAreaUpdateDO;
|
||||
import com.zcloud.personnel.positioning.persistence.dataobject.PersonnelMappingSnapshotDO;
|
||||
import com.zcloud.personnel.positioning.persistence.dataobject.TerminalBindingSnapshotDO;
|
||||
import com.zcloud.personnel.positioning.persistence.dataobject.TerminalLocationSnapshotDO;
|
||||
|
|
@ -11,6 +12,7 @@ import lombok.RequiredArgsConstructor;
|
|||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
|
|
@ -22,6 +24,7 @@ import java.util.Set;
|
|||
@RequiredArgsConstructor
|
||||
class PositionPersonLocalLookupService {
|
||||
private static final int BATCH_SIZE = 500;
|
||||
private static final String FINDS_SOURCE_CONFIG_CODE = "FINDS";
|
||||
|
||||
private final PersonnelMatchRepository personnelMatchRepository;
|
||||
|
||||
|
|
@ -57,12 +60,22 @@ class PositionPersonLocalLookupService {
|
|||
mapping.setFindsTerminalNo(normalize(row.getFindsTerminalNo()));
|
||||
mapping.setLocationStatus(normalize(row.getLocationStatus()));
|
||||
mapping.setFindsDeviceStatus(normalize(row.getFindsDeviceStatus()));
|
||||
mapping.setLocationAreaId(row.getLocationAreaId());
|
||||
mapping.setLocationAreaName(row.getLocationAreaName());
|
||||
mapping.setLocationAreaTime(row.getLocationAreaTime());
|
||||
mapping.setLocal(toLocalPerson(row));
|
||||
result.add(mapping);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量保存实时定位点匹配出的当前区域。
|
||||
*/
|
||||
int updateLocationAreas(List<PersonnelLocationAreaUpdateDO> updates, LocalDateTime syncTime) {
|
||||
return personnelMatchRepository.updateLocationAreas(FINDS_SOURCE_CONFIG_CODE, updates, syncTime);
|
||||
}
|
||||
|
||||
Map<String, LocalPerson> findUniquePeopleByPhones(Set<String> phones) {
|
||||
Map<String, List<LocalPerson>> grouped = new LinkedHashMap<>();
|
||||
for (List<String> batch : batches(phones)) {
|
||||
|
|
@ -211,6 +224,9 @@ class PositionPersonLocalLookupService {
|
|||
private String findsTerminalNo;
|
||||
private String locationStatus;
|
||||
private String findsDeviceStatus;
|
||||
private Long locationAreaId;
|
||||
private String locationAreaName;
|
||||
private LocalDateTime locationAreaTime;
|
||||
private LocalPerson local;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -6,6 +6,9 @@ import com.fasterxml.jackson.databind.JsonNode;
|
|||
import com.zcloud.personnel.positioning.dto.PositionPersonPageQry;
|
||||
import com.zcloud.personnel.positioning.dto.clientobject.PositionPersonCO;
|
||||
import com.zcloud.personnel.positioning.integration.finds.FindsOpenApiClient;
|
||||
import com.zcloud.personnel.positioning.persistence.dataobject.AreaDO;
|
||||
import com.zcloud.personnel.positioning.persistence.dataobject.PersonnelLocationAreaUpdateDO;
|
||||
import com.zcloud.personnel.positioning.persistence.repository.AreaRepository;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
|
@ -17,6 +20,7 @@ import java.time.OffsetDateTime;
|
|||
import java.time.ZoneId;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
|
|
@ -38,6 +42,8 @@ public class PositionPersonQueryExe {
|
|||
|
||||
private final FindsOpenApiClient findsOpenApiClient;
|
||||
private final PositionPersonLocalLookupService localLookupService;
|
||||
private final AreaRepository areaRepository;
|
||||
private final PositionAreaMatcher positionAreaMatcher;
|
||||
|
||||
public PageResponse<PositionPersonCO> list(PositionPersonPageQry qry) {
|
||||
PositionPersonPageQry query = qry == null ? new PositionPersonPageQry() : qry;
|
||||
|
|
@ -64,11 +70,21 @@ public class PositionPersonQueryExe {
|
|||
}
|
||||
}
|
||||
|
||||
Map<String, JsonNode> currentLocations = persistedMappings
|
||||
? Collections.emptyMap() : locateTerminals(terminalNos);
|
||||
Map<String, PositionPersonLocalLookupService.TerminalSnapshot> localTerminals =
|
||||
localLookupService.findTerminals(terminalNos);
|
||||
Set<String> terminalNosToLocate;
|
||||
if (persistedMappings) {
|
||||
// 正常运行时在线状态已由定时任务落库,只查询在线且已绑定设备的人员,避免无效定位请求。
|
||||
terminalNosToLocate = collectOnlineTerminalNos(matched, localTerminals);
|
||||
} else {
|
||||
// 首次同步前没有可靠的在线状态缓存,保留原定位探测作为兼容回退。
|
||||
terminalNosToLocate = terminalNos;
|
||||
}
|
||||
Map<String, JsonNode> currentLocations = locateTerminals(terminalNosToLocate);
|
||||
List<PositionPersonCO> rows = new ArrayList<>();
|
||||
Map<Long, List<PositionAreaMatcher.AreaPolygon>> areasByCorpinfoId = new HashMap<>();
|
||||
List<PersonnelLocationAreaUpdateDO> locationAreaUpdates = new ArrayList<>();
|
||||
LocalDateTime locationAreaSyncTime = LocalDateTime.now().withNano(0);
|
||||
for (MatchedPerson person : matched) {
|
||||
JsonNode currentLocation = currentLocations.get(person.finds.terminalNo);
|
||||
PositionPersonLocalLookupService.TerminalSnapshot terminal =
|
||||
|
|
@ -83,11 +99,30 @@ public class PositionPersonQueryExe {
|
|||
}
|
||||
String locationStatus = online ? STATUS_ONLINE : STATUS_OFFLINE;
|
||||
String positionSource = positionSource(terminal);
|
||||
PositionPersonCO row = toClientObject(
|
||||
person, terminal, currentLocation, online, locationStatus, positionSource);
|
||||
boolean locationQueried = StringUtils.hasText(person.finds.terminalNo)
|
||||
&& terminalNosToLocate.contains(person.finds.terminalNo);
|
||||
if (online && locationQueried) {
|
||||
AreaDO area = matchLocationArea(row, areasByCorpinfoId);
|
||||
if (area != null) {
|
||||
row.setLocationAreaId(area.getId());
|
||||
row.setLocationAreaName(area.getAreaName());
|
||||
}
|
||||
if (persistedMappings && StringUtils.hasText(person.finds.staffNo)) {
|
||||
// 只回写本次实际查询过的在线设备;未命中区域时写入空值,避免保留上一次旧区域。
|
||||
locationAreaUpdates.add(new PersonnelLocationAreaUpdateDO(
|
||||
person.finds.staffNo, row.getLocationAreaId(), row.getLocationAreaName()));
|
||||
}
|
||||
}
|
||||
if (!matchesText(query.getLocationStatus(), locationStatus)
|
||||
|| !matchesText(query.getPositionSource(), positionSource)) {
|
||||
continue;
|
||||
}
|
||||
rows.add(toClientObject(person, terminal, currentLocation, online, locationStatus, positionSource));
|
||||
rows.add(row);
|
||||
}
|
||||
if (persistedMappings && !locationAreaUpdates.isEmpty()) {
|
||||
localLookupService.updateLocationAreas(locationAreaUpdates, locationAreaSyncTime);
|
||||
}
|
||||
|
||||
int pageIndex = Math.max(query.getPageIndex(), 1);
|
||||
|
|
@ -97,6 +132,21 @@ public class PositionPersonQueryExe {
|
|||
return PageResponse.of(rows.subList(fromIndex, toIndex), rows.size(), pageSize, pageIndex);
|
||||
}
|
||||
|
||||
/**
|
||||
* 按企业加载并缓存启用区域,再使用人员实时经纬度匹配当前定位区域。
|
||||
*/
|
||||
private AreaDO matchLocationArea(
|
||||
PositionPersonCO person,
|
||||
Map<Long, List<PositionAreaMatcher.AreaPolygon>> areasByCorpinfoId) {
|
||||
if (person.getCorpinfoId() == null || person.getLon() == null || person.getLat() == null) {
|
||||
return null;
|
||||
}
|
||||
List<PositionAreaMatcher.AreaPolygon> areas = areasByCorpinfoId.computeIfAbsent(
|
||||
person.getCorpinfoId(), corpinfoId -> positionAreaMatcher.prepare(
|
||||
areaRepository.listBiPersonPositionAreas(corpinfoId)));
|
||||
return positionAreaMatcher.match(person.getLon(), person.getLat(), areas);
|
||||
}
|
||||
|
||||
private List<MatchedPerson> loadMatchedPeople(PositionPersonPageQry query, boolean persistedMappings) {
|
||||
if (persistedMappings) {
|
||||
return loadPersistedMatches(query);
|
||||
|
|
@ -361,6 +411,23 @@ public class PositionPersonQueryExe {
|
|||
|| "MOVING".equalsIgnoreCase(deviceStatus);
|
||||
}
|
||||
|
||||
/**
|
||||
* 从人员映射和本地终端快照中筛选需要实时定位的在线终端,并通过 Set 去重设备编号。
|
||||
*/
|
||||
private Set<String> collectOnlineTerminalNos(
|
||||
List<MatchedPerson> matched,
|
||||
Map<String, PositionPersonLocalLookupService.TerminalSnapshot> localTerminals) {
|
||||
Set<String> result = new LinkedHashSet<>();
|
||||
for (MatchedPerson person : matched) {
|
||||
String terminalNo = person.finds.terminalNo;
|
||||
if (StringUtils.hasText(terminalNo)
|
||||
&& isStoredOnline(person.finds, localTerminals.get(terminalNo))) {
|
||||
result.add(terminalNo);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private String positionSource(PositionPersonLocalLookupService.TerminalSnapshot terminal) {
|
||||
String type = terminal == null ? null : normalize(terminal.getDeviceType());
|
||||
if ("CARD".equalsIgnoreCase(type)) {
|
||||
|
|
|
|||
|
|
@ -59,6 +59,12 @@ public class BiCompanyOnlinePersonCO extends ClientObject {
|
|||
@ApiModelProperty(value = "纬度", name = "lat")
|
||||
private BigDecimal lat;
|
||||
|
||||
@ApiModelProperty(value = "当前定位区域ID", name = "locationAreaId")
|
||||
private Long locationAreaId;
|
||||
|
||||
@ApiModelProperty(value = "当前定位区域名称", name = "locationAreaName")
|
||||
private String locationAreaName;
|
||||
|
||||
@ApiModelProperty(value = "人员原始JSON", name = "staffRawJson")
|
||||
private String staffRawJson;
|
||||
|
||||
|
|
|
|||
|
|
@ -80,6 +80,12 @@ public class PositionPersonCO extends ClientObject {
|
|||
@ApiModelProperty(value = "当前方向,仅在线时返回", name = "direction")
|
||||
private BigDecimal direction;
|
||||
|
||||
@ApiModelProperty(value = "当前定位区域ID,仅在线且坐标命中区域时返回", name = "locationAreaId")
|
||||
private Long locationAreaId;
|
||||
|
||||
@ApiModelProperty(value = "当前定位区域名称,仅在线且坐标命中区域时返回", name = "locationAreaName")
|
||||
private String locationAreaName;
|
||||
|
||||
@ApiModelProperty(value = "跨平台人员匹配说明", name = "matchDescription")
|
||||
private String matchDescription;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@ package com.zcloud.personnel.positioning.persistence.dataobject;
|
|||
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Data
|
||||
public class PersonnelMappingSnapshotDO extends PersonnelLocalPersonDO {
|
||||
private String findsStaffNo;
|
||||
|
|
@ -14,4 +16,7 @@ public class PersonnelMappingSnapshotDO extends PersonnelLocalPersonDO {
|
|||
private String findsTerminalNo;
|
||||
private String locationStatus;
|
||||
private String findsDeviceStatus;
|
||||
private Long locationAreaId;
|
||||
private String locationAreaName;
|
||||
private LocalDateTime locationAreaTime;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package com.zcloud.personnel.positioning.persistence.mapper;
|
||||
|
||||
import com.zcloud.personnel.positioning.persistence.dataobject.PersonnelLocalPersonDO;
|
||||
import com.zcloud.personnel.positioning.persistence.dataobject.PersonnelLocationAreaUpdateDO;
|
||||
import com.zcloud.personnel.positioning.persistence.dataobject.PersonnelMappingSnapshotDO;
|
||||
import com.zcloud.personnel.positioning.persistence.dataobject.RealtimePersonRoutingDO;
|
||||
import com.zcloud.personnel.positioning.persistence.dataobject.TerminalBindingSnapshotDO;
|
||||
|
|
@ -46,6 +47,10 @@ public interface PersonnelMatchMapper {
|
|||
int markStaleOffline(@Param("sourceConfigCode") String sourceConfigCode,
|
||||
@Param("syncTime") LocalDateTime syncTime);
|
||||
|
||||
int updateLocationAreas(@Param("sourceConfigCode") String sourceConfigCode,
|
||||
@Param("updates") List<PersonnelLocationAreaUpdateDO> updates,
|
||||
@Param("syncTime") LocalDateTime syncTime);
|
||||
|
||||
List<RealtimePersonRoutingDO> listRealtimePersonRoutes(
|
||||
@Param("sourceConfigCode") String sourceConfigCode);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package com.zcloud.personnel.positioning.persistence.repository;
|
||||
|
||||
import com.zcloud.personnel.positioning.persistence.dataobject.PersonnelLocalPersonDO;
|
||||
import com.zcloud.personnel.positioning.persistence.dataobject.PersonnelLocationAreaUpdateDO;
|
||||
import com.zcloud.personnel.positioning.persistence.dataobject.PersonnelMappingSnapshotDO;
|
||||
import com.zcloud.personnel.positioning.persistence.dataobject.RealtimePersonRoutingDO;
|
||||
import com.zcloud.personnel.positioning.persistence.dataobject.TerminalBindingSnapshotDO;
|
||||
|
|
@ -31,6 +32,10 @@ public interface PersonnelMatchRepository {
|
|||
|
||||
void markStaleOffline(String sourceConfigCode, LocalDateTime syncTime);
|
||||
|
||||
int updateLocationAreas(String sourceConfigCode,
|
||||
List<PersonnelLocationAreaUpdateDO> updates,
|
||||
LocalDateTime syncTime);
|
||||
|
||||
List<RealtimePersonRoutingDO> listRealtimePersonRoutes(String sourceConfigCode);
|
||||
|
||||
List<PersonnelMappingSnapshotDO> listMatched(Map<String, Object> params);
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package com.zcloud.personnel.positioning.persistence.repository.impl;
|
||||
|
||||
import com.zcloud.personnel.positioning.persistence.dataobject.PersonnelLocalPersonDO;
|
||||
import com.zcloud.personnel.positioning.persistence.dataobject.PersonnelLocationAreaUpdateDO;
|
||||
import com.zcloud.personnel.positioning.persistence.dataobject.PersonnelMappingSnapshotDO;
|
||||
import com.zcloud.personnel.positioning.persistence.dataobject.RealtimePersonRoutingDO;
|
||||
import com.zcloud.personnel.positioning.persistence.dataobject.TerminalBindingSnapshotDO;
|
||||
|
|
@ -21,6 +22,8 @@ import java.util.Map;
|
|||
@Repository
|
||||
@RequiredArgsConstructor
|
||||
public class PersonnelMatchRepositoryImpl implements PersonnelMatchRepository {
|
||||
private static final int LOCATION_AREA_UPDATE_BATCH_SIZE = 500;
|
||||
|
||||
private final PersonnelMatchMapper personnelMatchMapper;
|
||||
|
||||
@Override public long countActive(String code) { return personnelMatchMapper.countActive(code); }
|
||||
|
|
@ -43,6 +46,23 @@ public class PersonnelMatchRepositoryImpl implements PersonnelMatchRepository {
|
|||
@Override public void markStaleOffline(String code, LocalDateTime time) {
|
||||
personnelMatchMapper.markStaleOffline(code, time);
|
||||
}
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public int updateLocationAreas(String code,
|
||||
List<PersonnelLocationAreaUpdateDO> updates,
|
||||
LocalDateTime time) {
|
||||
if (updates == null || updates.isEmpty()) {
|
||||
return 0;
|
||||
}
|
||||
int affected = 0;
|
||||
// 限制单条 CASE UPDATE 的人员数量,避免在线人员较多时 SQL 过长。
|
||||
for (int from = 0; from < updates.size(); from += LOCATION_AREA_UPDATE_BATCH_SIZE) {
|
||||
List<PersonnelLocationAreaUpdateDO> batch = updates.subList(
|
||||
from, Math.min(from + LOCATION_AREA_UPDATE_BATCH_SIZE, updates.size()));
|
||||
affected += personnelMatchMapper.updateLocationAreas(code, batch, time);
|
||||
}
|
||||
return affected;
|
||||
}
|
||||
@Override public List<RealtimePersonRoutingDO> listRealtimePersonRoutes(String code) {
|
||||
return personnelMatchMapper.listRealtimePersonRoutes(code);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -192,6 +192,9 @@ CREATE TABLE IF NOT EXISTS `personnel_match` (
|
|||
`location_status` varchar(32) NOT NULL DEFAULT 'OFFLINE' COMMENT 'ONLINE/OFFLINE',
|
||||
`finds_device_status` varchar(32) DEFAULT NULL COMMENT 'FindS STATIC/MOVING/OFFLINE/UN_LOCATION/NONE',
|
||||
`location_status_time` datetime DEFAULT NULL COMMENT 'location status sync time',
|
||||
`location_area_id` bigint DEFAULT NULL COMMENT '当前定位区域id',
|
||||
`location_area_name` varchar(255) DEFAULT NULL COMMENT '当前定位区域名称',
|
||||
`location_area_time` datetime DEFAULT NULL COMMENT '定位区域状态更新时间',
|
||||
`last_seen_time` datetime DEFAULT NULL COMMENT 'last time observed from FindS',
|
||||
`last_sync_time` datetime DEFAULT NULL COMMENT 'last mapping synchronization time',
|
||||
`sync_status` varchar(32) NOT NULL DEFAULT 'SUCCESS' COMMENT 'SUCCESS/FAIL',
|
||||
|
|
@ -215,6 +218,7 @@ CREATE TABLE IF NOT EXISTS `personnel_match` (
|
|||
KEY `idx_personnel_match_local_id_card` (`local_id_card_no`),
|
||||
KEY `idx_personnel_match_scope_status` (`finds_corpinfo_id`, `match_status`),
|
||||
KEY `idx_personnel_match_location_status` (`location_status`, `match_status`),
|
||||
KEY `idx_personnel_match_location_area` (`location_area_id`, `location_status`),
|
||||
KEY `idx_personnel_match_last_seen` (`last_seen_time`),
|
||||
KEY `idx_personnel_match_tenant_org` (`tenant_id`, `org_id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='FindS to local personnel mapping';
|
||||
|
|
|
|||
|
|
@ -38,6 +38,9 @@
|
|||
finds_track_id = VALUES(finds_track_id), finds_id_card_no = VALUES(finds_id_card_no),
|
||||
finds_staff_name = VALUES(finds_staff_name), finds_corpinfo_id = VALUES(finds_corpinfo_id),
|
||||
finds_corpinfo_name = VALUES(finds_corpinfo_name), finds_department_name = VALUES(finds_department_name),
|
||||
location_area_id = IF(finds_terminal_no <=> VALUES(finds_terminal_no), location_area_id, NULL),
|
||||
location_area_name = IF(finds_terminal_no <=> VALUES(finds_terminal_no), location_area_name, NULL),
|
||||
location_area_time = IF(finds_terminal_no <=> VALUES(finds_terminal_no), location_area_time, VALUES(last_sync_time)),
|
||||
finds_terminal_no = VALUES(finds_terminal_no), local_user_id = VALUES(local_user_id),
|
||||
local_mobile_no = VALUES(local_mobile_no), local_id_card_no = VALUES(local_id_card_no),
|
||||
match_status = VALUES(match_status), match_type = VALUES(match_type),
|
||||
|
|
@ -46,6 +49,7 @@
|
|||
</insert>
|
||||
<update id="disableMissing">
|
||||
UPDATE personnel_match SET match_status = 'DISABLED', sync_status = 'SUCCESS',
|
||||
location_area_id = NULL, location_area_name = NULL, location_area_time = #{syncTime},
|
||||
last_sync_time = #{syncTime}, version = version + 1
|
||||
WHERE source_config_code = #{sourceConfigCode}
|
||||
AND (delete_enum IS NULL OR delete_enum = 'FALSE')
|
||||
|
|
@ -61,7 +65,8 @@
|
|||
<update id="clearTerminalBinding">
|
||||
UPDATE personnel_match
|
||||
SET finds_terminal_no = NULL, location_status = 'OFFLINE', finds_device_status = 'OFFLINE',
|
||||
location_status_time = #{syncTime}, version = version + 1
|
||||
location_status_time = #{syncTime}, location_area_id = NULL,
|
||||
location_area_name = NULL, location_area_time = #{syncTime}, version = version + 1
|
||||
WHERE source_config_code = #{sourceConfigCode}
|
||||
AND (delete_enum IS NULL OR delete_enum = 'FALSE')
|
||||
AND finds_terminal_no = #{terminalNo}
|
||||
|
|
@ -69,7 +74,8 @@
|
|||
</update>
|
||||
<update id="bindTerminal">
|
||||
UPDATE personnel_match
|
||||
SET finds_terminal_no = #{terminalNo}, version = version + 1
|
||||
SET finds_terminal_no = #{terminalNo}, location_area_id = NULL,
|
||||
location_area_name = NULL, location_area_time = #{syncTime}, version = version + 1
|
||||
WHERE source_config_code = #{sourceConfigCode}
|
||||
AND (delete_enum IS NULL OR delete_enum = 'FALSE')
|
||||
AND match_status <> 'DISABLED'
|
||||
|
|
@ -78,13 +84,36 @@
|
|||
</update>
|
||||
<update id="markStaleOffline">
|
||||
UPDATE personnel_match SET location_status = 'OFFLINE', finds_device_status = 'OFFLINE',
|
||||
location_status_time = #{syncTime}, version = version + 1
|
||||
location_status_time = #{syncTime}, location_area_id = NULL,
|
||||
location_area_name = NULL, location_area_time = #{syncTime}, version = version + 1
|
||||
WHERE source_config_code = #{sourceConfigCode}
|
||||
AND (delete_enum IS NULL OR delete_enum = 'FALSE')
|
||||
AND location_status = 'ONLINE'
|
||||
AND (location_status_time IS NULL OR location_status_time < #{syncTime})
|
||||
</update>
|
||||
|
||||
<update id="updateLocationAreas">
|
||||
UPDATE personnel_match
|
||||
SET location_area_id = CASE finds_staff_no
|
||||
<foreach collection="updates" item="item">
|
||||
WHEN #{item.findsStaffNo} THEN #{item.locationAreaId}
|
||||
</foreach>
|
||||
ELSE location_area_id END,
|
||||
location_area_name = CASE finds_staff_no
|
||||
<foreach collection="updates" item="item">
|
||||
WHEN #{item.findsStaffNo} THEN #{item.locationAreaName}
|
||||
</foreach>
|
||||
ELSE location_area_name END,
|
||||
location_area_time = #{syncTime}, version = version + 1
|
||||
WHERE source_config_code = #{sourceConfigCode}
|
||||
AND match_status = 'MATCHED'
|
||||
AND (delete_enum IS NULL OR delete_enum = 'FALSE')
|
||||
AND finds_staff_no IN
|
||||
<foreach collection="updates" item="item" open="(" separator="," close=")">
|
||||
#{item.findsStaffNo}
|
||||
</foreach>
|
||||
</update>
|
||||
|
||||
<select id="listRealtimePersonRoutes"
|
||||
resultType="com.zcloud.personnel.positioning.persistence.dataobject.RealtimePersonRoutingDO">
|
||||
SELECT pm.finds_staff_no, u.id AS user_id, u.username AS local_staff_no,
|
||||
|
|
@ -120,7 +149,7 @@
|
|||
<sql id="localPersonSelect">
|
||||
SELECT u.id AS user_id, u.username AS local_staff_no, u.name AS staff_name,
|
||||
TRIM(u.phone) AS mobile_no, u.user_id_card AS id_card_no, ci.id AS corpinfo_id,
|
||||
ci.corp_name AS corpinfo_name, ci.code AS credit_code,
|
||||
ci.corp_name AS corpinfo_name, ci.code AS credit_code, ci.port_area AS port_area,
|
||||
u.department_id, d.dept_name AS department_name
|
||||
FROM user_scope_v u
|
||||
LEFT JOIN corp_info ci ON ci.id = u.corpinfo_id
|
||||
|
|
@ -200,7 +229,8 @@
|
|||
SELECT pm.finds_staff_no, pm.finds_staff_no_type, pm.finds_id_card_no,
|
||||
pm.finds_staff_name, pm.finds_corpinfo_id, pm.finds_corpinfo_name,
|
||||
pm.finds_department_name, pm.finds_terminal_no, pm.location_status,
|
||||
pm.finds_device_status, u.id AS user_id, u.username AS local_staff_no,
|
||||
pm.finds_device_status, pm.location_area_id, pm.location_area_name,
|
||||
pm.location_area_time, u.id AS user_id, u.username AS local_staff_no,
|
||||
u.name AS staff_name, TRIM(u.phone) AS mobile_no, u.user_id_card AS id_card_no,
|
||||
ci.id AS corpinfo_id, ci.corp_name AS corpinfo_name, ci.code AS credit_code,
|
||||
u.department_id, d.dept_name AS department_name
|
||||
|
|
|
|||
Loading…
Reference in New Issue