diff --git a/web-app/src/main/java/com/zcloud/personnel/positioning/command/query/BiPersonLocationProvider.java b/web-app/src/main/java/com/zcloud/personnel/positioning/command/query/BiPersonLocationProvider.java index 856211f..c8ea2e5 100644 --- a/web-app/src/main/java/com/zcloud/personnel/positioning/command/query/BiPersonLocationProvider.java +++ b/web-app/src/main/java/com/zcloud/personnel/positioning/command/query/BiPersonLocationProvider.java @@ -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; } diff --git a/web-app/src/main/java/com/zcloud/personnel/positioning/command/query/PersonnelPositioningBiQueryExe.java b/web-app/src/main/java/com/zcloud/personnel/positioning/command/query/PersonnelPositioningBiQueryExe.java index fe57138..7c1239c 100644 --- a/web-app/src/main/java/com/zcloud/personnel/positioning/command/query/PersonnelPositioningBiQueryExe.java +++ b/web-app/src/main/java/com/zcloud/personnel/positioning/command/query/PersonnelPositioningBiQueryExe.java @@ -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 areas = loadBiPersonPositionAreas(corpinfoId); Map locationMap = loadBiPersonPositionLocationMap(corpinfoId); List 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 loadBiPersonPositionAreas(Long corpinfoId) { - List rows = areaRepository.listBiPersonPositionAreas(corpinfoId); - List result = new ArrayList<>(); - for (AreaDO row : rows) { - result.add(new BiPersonPositionArea(row, parseBiPersonPositionPolygon(row.getPolygonJson()))); - } - return result; - } - private Map loadBiPersonPositionLocationMap(Long corpinfoId) { List locations = biPersonLocationProvider.listCompanyOnlinePersons(corpinfoId, null, null); @@ -352,8 +342,7 @@ public class PersonnelPositioningBiQueryExe { } private BiPersonPositionCO buildBiPersonPositionRow(BiPersonPositionUserDO user, - BiCompanyOnlinePersonCO location, - List 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 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 parseBiPersonPositionPolygon(String polygonJson) { - List 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 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 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 points; - - private BiPersonPositionArea(AreaDO area, List points) { - this.area = area; - this.points = points; - } - } - private static class StaffSnapshot { private JsonNode rawNode; private String staffName; diff --git a/web-app/src/main/java/com/zcloud/personnel/positioning/command/query/PositionPersonLocalLookupService.java b/web-app/src/main/java/com/zcloud/personnel/positioning/command/query/PositionPersonLocalLookupService.java index 2f10e33..55ded51 100644 --- a/web-app/src/main/java/com/zcloud/personnel/positioning/command/query/PositionPersonLocalLookupService.java +++ b/web-app/src/main/java/com/zcloud/personnel/positioning/command/query/PositionPersonLocalLookupService.java @@ -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 updates, LocalDateTime syncTime) { + return personnelMatchRepository.updateLocationAreas(FINDS_SOURCE_CONFIG_CODE, updates, syncTime); + } + Map findUniquePeopleByPhones(Set phones) { Map> grouped = new LinkedHashMap<>(); for (List 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; } diff --git a/web-app/src/main/java/com/zcloud/personnel/positioning/command/query/PositionPersonQueryExe.java b/web-app/src/main/java/com/zcloud/personnel/positioning/command/query/PositionPersonQueryExe.java index 25611b0..668a9e8 100644 --- a/web-app/src/main/java/com/zcloud/personnel/positioning/command/query/PositionPersonQueryExe.java +++ b/web-app/src/main/java/com/zcloud/personnel/positioning/command/query/PositionPersonQueryExe.java @@ -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 list(PositionPersonPageQry qry) { PositionPersonPageQry query = qry == null ? new PositionPersonPageQry() : qry; @@ -64,11 +70,21 @@ public class PositionPersonQueryExe { } } - Map currentLocations = persistedMappings - ? Collections.emptyMap() : locateTerminals(terminalNos); Map localTerminals = localLookupService.findTerminals(terminalNos); + Set terminalNosToLocate; + if (persistedMappings) { + // 正常运行时在线状态已由定时任务落库,只查询在线且已绑定设备的人员,避免无效定位请求。 + terminalNosToLocate = collectOnlineTerminalNos(matched, localTerminals); + } else { + // 首次同步前没有可靠的在线状态缓存,保留原定位探测作为兼容回退。 + terminalNosToLocate = terminalNos; + } + Map currentLocations = locateTerminals(terminalNosToLocate); List rows = new ArrayList<>(); + Map> areasByCorpinfoId = new HashMap<>(); + List 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> areasByCorpinfoId) { + if (person.getCorpinfoId() == null || person.getLon() == null || person.getLat() == null) { + return null; + } + List areas = areasByCorpinfoId.computeIfAbsent( + person.getCorpinfoId(), corpinfoId -> positionAreaMatcher.prepare( + areaRepository.listBiPersonPositionAreas(corpinfoId))); + return positionAreaMatcher.match(person.getLon(), person.getLat(), areas); + } + private List loadMatchedPeople(PositionPersonPageQry query, boolean persistedMappings) { if (persistedMappings) { return loadPersistedMatches(query); @@ -361,6 +411,23 @@ public class PositionPersonQueryExe { || "MOVING".equalsIgnoreCase(deviceStatus); } + /** + * 从人员映射和本地终端快照中筛选需要实时定位的在线终端,并通过 Set 去重设备编号。 + */ + private Set collectOnlineTerminalNos( + List matched, + Map localTerminals) { + Set 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)) { diff --git a/web-client/src/main/java/com/zcloud/personnel/positioning/dto/clientobject/BiCompanyOnlinePersonCO.java b/web-client/src/main/java/com/zcloud/personnel/positioning/dto/clientobject/BiCompanyOnlinePersonCO.java index 4805b37..056f82c 100644 --- a/web-client/src/main/java/com/zcloud/personnel/positioning/dto/clientobject/BiCompanyOnlinePersonCO.java +++ b/web-client/src/main/java/com/zcloud/personnel/positioning/dto/clientobject/BiCompanyOnlinePersonCO.java @@ -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; diff --git a/web-client/src/main/java/com/zcloud/personnel/positioning/dto/clientobject/PositionPersonCO.java b/web-client/src/main/java/com/zcloud/personnel/positioning/dto/clientobject/PositionPersonCO.java index 70d165c..8e2fa93 100644 --- a/web-client/src/main/java/com/zcloud/personnel/positioning/dto/clientobject/PositionPersonCO.java +++ b/web-client/src/main/java/com/zcloud/personnel/positioning/dto/clientobject/PositionPersonCO.java @@ -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; } diff --git a/web-infrastructure/src/main/java/com/zcloud/personnel/positioning/persistence/dataobject/PersonnelMappingSnapshotDO.java b/web-infrastructure/src/main/java/com/zcloud/personnel/positioning/persistence/dataobject/PersonnelMappingSnapshotDO.java index 0efcb94..68eed1a 100644 --- a/web-infrastructure/src/main/java/com/zcloud/personnel/positioning/persistence/dataobject/PersonnelMappingSnapshotDO.java +++ b/web-infrastructure/src/main/java/com/zcloud/personnel/positioning/persistence/dataobject/PersonnelMappingSnapshotDO.java @@ -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; } diff --git a/web-infrastructure/src/main/java/com/zcloud/personnel/positioning/persistence/mapper/PersonnelMatchMapper.java b/web-infrastructure/src/main/java/com/zcloud/personnel/positioning/persistence/mapper/PersonnelMatchMapper.java index 0bcace1..cd7c1dc 100644 --- a/web-infrastructure/src/main/java/com/zcloud/personnel/positioning/persistence/mapper/PersonnelMatchMapper.java +++ b/web-infrastructure/src/main/java/com/zcloud/personnel/positioning/persistence/mapper/PersonnelMatchMapper.java @@ -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 updates, + @Param("syncTime") LocalDateTime syncTime); + List listRealtimePersonRoutes( @Param("sourceConfigCode") String sourceConfigCode); diff --git a/web-infrastructure/src/main/java/com/zcloud/personnel/positioning/persistence/repository/PersonnelMatchRepository.java b/web-infrastructure/src/main/java/com/zcloud/personnel/positioning/persistence/repository/PersonnelMatchRepository.java index 52a10e4..4229649 100644 --- a/web-infrastructure/src/main/java/com/zcloud/personnel/positioning/persistence/repository/PersonnelMatchRepository.java +++ b/web-infrastructure/src/main/java/com/zcloud/personnel/positioning/persistence/repository/PersonnelMatchRepository.java @@ -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 updates, + LocalDateTime syncTime); + List listRealtimePersonRoutes(String sourceConfigCode); List listMatched(Map params); diff --git a/web-infrastructure/src/main/java/com/zcloud/personnel/positioning/persistence/repository/impl/PersonnelMatchRepositoryImpl.java b/web-infrastructure/src/main/java/com/zcloud/personnel/positioning/persistence/repository/impl/PersonnelMatchRepositoryImpl.java index 2228cc0..96f027f 100644 --- a/web-infrastructure/src/main/java/com/zcloud/personnel/positioning/persistence/repository/impl/PersonnelMatchRepositoryImpl.java +++ b/web-infrastructure/src/main/java/com/zcloud/personnel/positioning/persistence/repository/impl/PersonnelMatchRepositoryImpl.java @@ -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 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 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 listRealtimePersonRoutes(String code) { return personnelMatchMapper.listRealtimePersonRoutes(code); } diff --git a/web-infrastructure/src/main/resources/TableCreationDDL.sql b/web-infrastructure/src/main/resources/TableCreationDDL.sql index 145c69d..b41a866 100644 --- a/web-infrastructure/src/main/resources/TableCreationDDL.sql +++ b/web-infrastructure/src/main/resources/TableCreationDDL.sql @@ -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'; diff --git a/web-infrastructure/src/main/resources/mapper/PersonnelMatchMapper.xml b/web-infrastructure/src/main/resources/mapper/PersonnelMatchMapper.xml index 7005265..c64f324 100644 --- a/web-infrastructure/src/main/resources/mapper/PersonnelMatchMapper.xml +++ b/web-infrastructure/src/main/resources/mapper/PersonnelMatchMapper.xml @@ -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 @@ 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 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 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 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 personnel_match + SET location_area_id = CASE finds_staff_no + + WHEN #{item.findsStaffNo} THEN #{item.locationAreaId} + + ELSE location_area_id END, + location_area_name = CASE finds_staff_no + + WHEN #{item.findsStaffNo} THEN #{item.locationAreaName} + + 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 + + #{item.findsStaffNo} + + +