1、人员定位大屏区域匹配

master
shenzhidan 2026-08-12 15:06:05 +08:00
parent 4d24075d22
commit 44fb60dd2c
12 changed files with 183 additions and 100 deletions

View File

@ -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;
}

View File

@ -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;

View File

@ -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;
}

View File

@ -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)) {

View File

@ -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;

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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);

View File

@ -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);

View File

@ -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);
}

View File

@ -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';

View File

@ -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 &lt;=&gt; VALUES(finds_terminal_no), location_area_id, NULL),
location_area_name = IF(finds_terminal_no &lt;=&gt; VALUES(finds_terminal_no), location_area_name, NULL),
location_area_time = IF(finds_terminal_no &lt;=&gt; 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 &lt;&gt; '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 &lt; #{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