Merge remote-tracking branch 'origin/master'

dev
shenzhidan 2026-07-27 18:03:47 +08:00
commit 79de8c607e
36 changed files with 1194 additions and 31 deletions

View File

@ -8,9 +8,12 @@ import com.jjb.saas.framework.auth.model.SSOUser;
import com.jjb.saas.framework.auth.utils.AuthContext;
import com.zcloud.personnel.positioning.api.AlarmRecordServiceI;
import com.zcloud.personnel.positioning.dto.AlarmRecordAddCmd;
import com.zcloud.personnel.positioning.dto.AlarmRecordBiAlarmTypeQry;
import com.zcloud.personnel.positioning.dto.AlarmRecordBiQry;
import com.zcloud.personnel.positioning.dto.AlarmRecordPageQry;
import com.zcloud.personnel.positioning.dto.AlarmRecordUpdateCmd;
import com.zcloud.personnel.positioning.dto.clientobject.AlarmRecordCO;
import com.zcloud.personnel.positioning.dto.clientobject.AlarmTypeStatCO;
import com.zcloud.personnel.positioning.dto.clientobject.OptionCO;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
@ -58,6 +61,7 @@ public class AlarmRecordController {
return MultiResponse.of(alarmRecordService.listAll());
}
@ApiOperation("公司选项")
@GetMapping("/companyOptions")
public MultiResponse<OptionCO> companyOptions() {
@ -111,4 +115,17 @@ public class AlarmRecordController {
cmd.setCorpinfoId(String.valueOf(ssoUser.getCompanyId()));
}
}
@ApiOperation("可视化大屏-报警列表")
@PostMapping("/bi/list")
public MultiResponse<AlarmRecordCO> listBiAlarm(@RequestBody AlarmRecordBiQry qry) {
return MultiResponse.of(alarmRecordService.listBiAlarm(qry));
}
@ApiOperation("可视化大屏-报警类型")
@PostMapping("/bi/alarmType")
public MultiResponse<AlarmTypeStatCO> listBiAlarmType(@RequestBody AlarmRecordBiAlarmTypeQry qry) {
return MultiResponse.of(alarmRecordService.listBiAlarmType(qry));
}
}

View File

@ -4,7 +4,9 @@ import com.zcloud.personnel.positioning.api.AreaServiceI;
import com.zcloud.personnel.positioning.dto.AreaAddCmd;
import com.zcloud.personnel.positioning.dto.AreaPageQry;
import com.zcloud.personnel.positioning.dto.AreaUpdateCmd;
import com.zcloud.personnel.positioning.dto.BiPersonPositionQry;
import com.zcloud.personnel.positioning.dto.clientobject.AreaCO;
import com.zcloud.personnel.positioning.dto.clientobject.AreaPersonStatCO;
import com.zcloud.personnel.positioning.dto.clientobject.OptionCO;
import com.alibaba.cola.dto.MultiResponse;
import com.alibaba.cola.dto.PageResponse;
@ -65,6 +67,7 @@ public class AreaController {
return MultiResponse.of(areaService.listOptions(corpinfoId, keyword));
}
@ApiOperation("详情")
@GetMapping("/{id}")
public SingleResponse<AreaCO> getInfoById(@PathVariable("id") Long id) {
@ -106,4 +109,11 @@ public class AreaController {
cmd.setCorpinfoId(String.valueOf(ssoUser.getCompanyId()));
}
}
@ApiOperation("可视化大屏-封闭区域人员统计情况")
@PostMapping("/personStat")
public MultiResponse<AreaPersonStatCO> listPersonStat(@RequestBody BiPersonPositionQry qry) {
return MultiResponse.of(areaService.listPersonStat(qry.getCorpinfoId()));
}
}

View File

@ -6,12 +6,16 @@ import com.alibaba.cola.dto.SingleResponse;
import com.zcloud.personnel.positioning.api.PersonnelPositioningBiServiceI;
import com.zcloud.personnel.positioning.dto.BiAreaFenceQry;
import com.zcloud.personnel.positioning.dto.BiCompanyFenceQry;
import com.zcloud.personnel.positioning.dto.BiCompanyOnlinePersonQry;
import com.zcloud.personnel.positioning.dto.BiPersonLocationQry;
import com.zcloud.personnel.positioning.dto.BiPersonPositionQry;
import com.zcloud.personnel.positioning.dto.BiPersonTraceQry;
import com.zcloud.personnel.positioning.dto.clientobject.BiAreaFenceCO;
import com.zcloud.personnel.positioning.dto.clientobject.BiCompanyLocationCO;
import com.zcloud.personnel.positioning.dto.clientobject.BiCompanyOnlinePersonStatCO;
import com.zcloud.personnel.positioning.dto.clientobject.BiOverviewCO;
import com.zcloud.personnel.positioning.dto.clientobject.BiPersonLocationCO;
import com.zcloud.personnel.positioning.dto.clientobject.BiPersonPositionCO;
import com.zcloud.personnel.positioning.dto.clientobject.BiPersonTraceCO;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
@ -25,7 +29,7 @@ import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
/**
* BI
* BI
*
* @Author fangjiakai
* @Date 2026-07-07
@ -62,6 +66,9 @@ public class PersonnelPositioningBiController {
return personnelPositioningBiService.listPersonLocation(qry);
}
@ApiOperation("人员轨迹")
@PostMapping("/personTrace")
public SingleResponse<BiPersonTraceCO> queryPersonTrace(@RequestBody BiPersonTraceQry qry) {
@ -85,4 +92,16 @@ public class PersonnelPositioningBiController {
public SingleResponse<BiAreaFenceCO> queryAreaFenceById(@PathVariable("id") Long id) {
return SingleResponse.of(personnelPositioningBiService.queryAreaFenceById(id));
}
@ApiOperation("可视化大屏-企业在线人员统计")
@PostMapping("/personLocation/companyOnlineStat")
public SingleResponse<BiCompanyOnlinePersonStatCO> queryCompanyOnlinePersonStat(
@RequestBody BiCompanyOnlinePersonQry qry) {
return SingleResponse.of(personnelPositioningBiService.queryCompanyOnlinePersonStat(qry));
}
@ApiOperation("可视化大屏-人员定位列表")
@PostMapping("/personLocation/positioning")
public MultiResponse<BiPersonPositionCO> listPersonPosition(@RequestBody BiPersonPositionQry qry) {
return MultiResponse.of(personnelPositioningBiService.listPersonPosition(qry));
}
}

View File

@ -1,15 +1,20 @@
package com.zcloud.personnel.positioning.command.query;
import com.alibaba.cola.dto.PageResponse;
import com.alibaba.cola.exception.BizException;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.jjb.saas.framework.auth.model.SSOUser;
import com.jjb.saas.framework.auth.utils.AuthContext;
import com.zcloud.personnel.positioning.command.convertor.AlarmRecordCoConvertor;
import com.zcloud.personnel.positioning.command.convertor.AlarmRecordTargetCoConvertor;
import com.zcloud.personnel.positioning.dto.AlarmRecordBiAlarmTypeQry;
import com.zcloud.personnel.positioning.dto.AlarmRecordBiQry;
import com.zcloud.personnel.positioning.dto.AlarmRecordPageQry;
import com.zcloud.personnel.positioning.dto.clientobject.AlarmRecordCO;
import com.zcloud.personnel.positioning.dto.clientobject.AlarmTypeStatCO;
import com.zcloud.personnel.positioning.dto.clientobject.AlarmRecordTargetCO;
import com.zcloud.personnel.positioning.dto.clientobject.OptionCO;
import com.zcloud.personnel.positioning.persistence.dataobject.AlarmTypeStatDO;
import com.zcloud.personnel.positioning.persistence.dataobject.AlarmRecordDO;
import com.zcloud.personnel.positioning.persistence.dataobject.AlarmRecordTargetDO;
import com.zcloud.personnel.positioning.persistence.dataobject.CompanyOptionDO;
@ -55,6 +60,35 @@ public class AlarmRecordQueryExe {
return PageResponse.of(data, pageResponse.getTotalCount(), pageResponse.getPageSize(), pageResponse.getPageIndex());
}
public List<AlarmRecordCO> listBiAlarm(AlarmRecordBiQry qry) {
AlarmRecordBiQry query = qry == null ? new AlarmRecordBiQry() : qry;
String corpinfoId = query.getCorpinfoId() == null ? null : String.valueOf(query.getCorpinfoId());
List<AlarmRecordCO> rows = alarmRecordCoConvertor.converDOsToCOs(
alarmRecordRepository.listBiAlarm(corpinfoId, query.getPortArea()));
return rows;
}
public List<AlarmTypeStatCO> listBiAlarmType(AlarmRecordBiAlarmTypeQry qry) {
AlarmRecordBiAlarmTypeQry query = qry == null ? new AlarmRecordBiAlarmTypeQry() : qry;
String corpinfoId = query.getCorpinfoId() == null ? null : String.valueOf(query.getCorpinfoId());
List<AlarmTypeStatDO> rows = alarmRecordRepository.listBiAlarmType(corpinfoId);
if (rows == null || rows.isEmpty()) {
return Collections.emptyList();
}
List<AlarmTypeStatCO> result = new ArrayList<>();
for (AlarmTypeStatDO row : rows) {
if (row == null) {
continue;
}
AlarmTypeStatCO co = new AlarmTypeStatCO();
co.setAlarmCode(row.getAlarmCode());
co.setAlarmName(alarmTypeNameOf(row.getAlarmCode(), row.getAlarmName()));
co.setAlarmCount(row.getAlarmCount());
result.add(co);
}
return result;
}
public List<AlarmRecordCO> listAll() {
QueryWrapper<AlarmRecordDO> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("delete_enum", "FALSE");
@ -190,6 +224,7 @@ public class AlarmRecordQueryExe {
}
}
private String normalizeAlarmCode(String value) {
if (!StringUtils.hasText(value)) {
return null;
@ -274,7 +309,16 @@ public class AlarmRecordQueryExe {
return alarmCode;
}
private String alarmTypeNameOf(String alarmCode, String alarmName) {
String name = defaultIfBlank(alarmName, alarmNameOf(alarmCode));
if (name != null && name.contains("-")) {
return name.substring(name.lastIndexOf('-') + 1);
}
return name;
}
private String defaultIfBlank(String value, String defaultValue) {
return StringUtils.hasText(value) ? value : defaultValue;
}
}

View File

@ -4,17 +4,24 @@ import com.zcloud.gbscommon.utils.PageQueryHelper;
import com.zcloud.personnel.positioning.command.convertor.AreaCoConvertor;
import com.zcloud.personnel.positioning.dto.AreaPageQry;
import com.zcloud.personnel.positioning.dto.clientobject.AreaCO;
import com.zcloud.personnel.positioning.dto.clientobject.AreaPersonStatCO;
import com.zcloud.personnel.positioning.dto.clientobject.BiCompanyOnlinePersonCO;
import com.zcloud.personnel.positioning.dto.clientobject.OptionCO;
import com.zcloud.personnel.positioning.persistence.dataobject.AreaDO;
import com.zcloud.personnel.positioning.persistence.repository.AreaRepository;
import com.alibaba.cola.dto.PageResponse;
import com.alibaba.cola.exception.BizException;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.jjb.saas.framework.auth.model.SSOUser;
import com.jjb.saas.framework.auth.utils.AuthContext;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@ -30,6 +37,8 @@ import java.util.Map;
public class AreaQueryExe {
private final AreaRepository areaRepository;
private final AreaCoConvertor areaCoConvertor;
private final BiPersonLocationProvider biPersonLocationProvider;
private final ObjectMapper objectMapper;
public PageResponse<AreaCO> execute(AreaPageQry qry) {
AreaPageQry query = qry == null ? new AreaPageQry() : qry;
@ -66,6 +75,24 @@ public class AreaQueryExe {
return options;
}
public List<AreaPersonStatCO> listPersonStat(Long corpinfoId) {
if (corpinfoId == null) {
throw new BizException("企业id不能为空");
}
String companyId = String.valueOf(corpinfoId);
List<AreaStatAccumulator> areas = listCompanyAreas(companyId);
List<BiCompanyOnlinePersonCO> personList =
biPersonLocationProvider.listCompanyOnlinePersons(companyId, null, null);
for (BiCompanyOnlinePersonCO person : personList) {
countPerson(areas, person);
}
List<AreaPersonStatCO> result = new ArrayList<>(areas.size());
for (AreaStatAccumulator area : areas) {
result.add(area.toCO());
}
return result;
}
public AreaCO queryById(Long id) {
QueryWrapper<AreaDO> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("id", id);
@ -74,6 +101,85 @@ public class AreaQueryExe {
return areaCoConvertor.converDOToCO(dataObject);
}
private List<AreaStatAccumulator> listCompanyAreas(String corpinfoId) {
QueryWrapper<AreaDO> queryWrapper = new QueryWrapper<>();
queryWrapper.and(wrapper -> wrapper.isNull("delete_enum").or().eq("delete_enum", "FALSE"));
queryWrapper.and(wrapper -> wrapper.isNull("status").or().eq("status", "ENABLED"));
queryWrapper.eq("corpinfo_id", corpinfoId);
queryWrapper.orderByAsc("sort_no").orderByAsc("area_name").orderByDesc("create_time");
List<AreaDO> rows = areaRepository.list(queryWrapper);
List<AreaStatAccumulator> result = new ArrayList<>(rows.size());
for (AreaDO row : rows) {
result.add(new AreaStatAccumulator(row, parsePolygon(row.getPolygonJson())));
}
return result;
}
private void countPerson(List<AreaStatAccumulator> areas, BiCompanyOnlinePersonCO person) {
if (person == null || person.getLon() == null || person.getLat() == null) {
return;
}
for (AreaStatAccumulator area : areas) {
if (pointInPolygon(person.getLon(), person.getLat(), area.points)) {
area.add(person);
return;
}
}
}
private List<BigDecimal[]> parsePolygon(String polygonJson) {
List<BigDecimal[]> points = new ArrayList<>();
if (!StringUtils.hasText(polygonJson)) {
return points;
}
try {
collectPoints(objectMapper.readTree(polygonJson), points);
} catch (IOException e) {
throw new BizException("区域边界坐标JSON格式错误");
}
return points;
}
private void collectPoints(JsonNode node, List<BigDecimal[]> points) {
if (node == null || node.isNull() || node.isMissingNode()) {
return;
}
if (node.isObject()) {
node.elements().forEachRemaining(child -> collectPoints(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) {
collectPoints(child, points);
}
}
private boolean pointInPolygon(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;
}
private void fillCorpinfo(Map<String, Object> params) {
if (params.get("eqCorpinfoId") != null || StringUtils.hasText((String) params.get("likeCorpinfoName"))) {
return;
@ -94,4 +200,41 @@ public class AreaQueryExe {
queryWrapper.eq("corpinfo_id", String.valueOf(ssoUser.getCompanyId()));
}
}
private static class AreaStatAccumulator {
private final AreaDO area;
private final List<BigDecimal[]> points;
private int unitCount;
private int relatedCount;
private AreaStatAccumulator(AreaDO area, List<BigDecimal[]> points) {
this.area = area;
this.points = points;
}
private void add(BiCompanyOnlinePersonCO person) {
if (Boolean.TRUE.equals(person.getInternalEmployee())) {
unitCount++;
} else {
relatedCount++;
}
}
private AreaPersonStatCO toCO() {
AreaPersonStatCO co = new AreaPersonStatCO();
co.setAreaId(area.getId());
co.setAreaCode(area.getAreaCode());
co.setAreaName(area.getAreaName());
co.setAreaType(area.getAreaType());
co.setCorpinfoId(area.getCorpinfoId());
co.setCorpinfoName(area.getCorpinfoName());
co.setCenterLon(area.getCenterLon());
co.setCenterLat(area.getCenterLat());
co.setPolygonJson(area.getPolygonJson());
co.setUnitCount(unitCount);
co.setRelatedCount(relatedCount);
co.setTotalCount(unitCount + relatedCount);
return co;
}
}
}

View File

@ -0,0 +1,151 @@
package com.zcloud.personnel.positioning.command.query;
import com.zcloud.personnel.positioning.dto.clientobject.BiCompanyOnlinePersonCO;
import com.zcloud.personnel.positioning.persistence.dataobject.BiPersonPositionUserDO;
import com.zcloud.personnel.positioning.persistence.repository.UserRepository;
import lombok.Data;
import lombok.RequiredArgsConstructor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
/**
*
*
* @Author Codex
* @Date 2026-07-27
*/
@Component
@RequiredArgsConstructor
public class BiPersonLocationProvider {
private static final Logger LOGGER = LoggerFactory.getLogger(BiPersonLocationProvider.class);
private final UserRepository userRepository;
public List<BiCompanyOnlinePersonCO> listCompanyOnlinePersons(String corpinfoId,
String corpinfoName,
String corpCode) {
if (!StringUtils.hasText(corpinfoId)) {
return Collections.emptyList();
}
LOGGER.info("开始查询可视化大屏第三方人员定位corpinfoId={}", corpinfoId);
List<ThirdPartyPersonLocation> locations = loadThirdPartyPersonLocations(corpinfoId, corpinfoName, corpCode);
if (locations.isEmpty()) {
LOGGER.info("可视化大屏第三方人员定位为空corpinfoId={}", corpinfoId);
return Collections.emptyList();
}
Map<String, BiPersonPositionUserDO> userMap = buildUserMap(corpinfoId);
List<BiCompanyOnlinePersonCO> result = new ArrayList<>(locations.size());
for (ThirdPartyPersonLocation location : locations) {
result.add(toOnlinePerson(corpinfoId, corpinfoName, location, userMap));
}
LOGGER.info("可视化大屏第三方人员定位转换完成corpinfoId={},定位人数={}", corpinfoId, result.size());
return result;
}
private List<ThirdPartyPersonLocation> loadThirdPartyPersonLocations(String corpinfoId,
String corpinfoName,
String corpCode) {
LOGGER.info("TODO 待接入第三方人员定位接口corpinfoId={}corpinfoName={}corpCode={}",
corpinfoId, corpinfoName, corpCode);
// TODO 后续只在这里接入第三方接口根据企业id获取在线人员、经纬度、定位时间、人员唯一标识。
return Collections.emptyList();
}
private Map<String, BiPersonPositionUserDO> buildUserMap(String corpinfoId) {
List<BiPersonPositionUserDO> users = userRepository.listBiPersonPositionUsers(corpinfoId);
Map<String, BiPersonPositionUserDO> result = new LinkedHashMap<>();
for (BiPersonPositionUserDO user : users) {
putUser(result, user.getUserId() == null ? null : String.valueOf(user.getUserId()), user);
putUser(result, user.getUsername(), user);
putUser(result, user.getMobileNo(), user);
putUser(result, user.getIdCardNo(), user);
}
return result;
}
private void putUser(Map<String, BiPersonPositionUserDO> userMap,
String key,
BiPersonPositionUserDO user) {
if (StringUtils.hasText(key)) {
userMap.putIfAbsent(key.trim(), user);
}
}
private BiCompanyOnlinePersonCO toOnlinePerson(String corpinfoId,
String corpinfoName,
ThirdPartyPersonLocation location,
Map<String, BiPersonPositionUserDO> userMap) {
BiPersonPositionUserDO user = findUser(location, userMap);
BiCompanyOnlinePersonCO co = new BiCompanyOnlinePersonCO();
co.setUserId(user == null ? null : user.getUserId());
co.setStaffName(firstText(user == null ? null : user.getPersonName(), location.getPersonName()));
co.setStaffNo(firstText(location.getStaffNo(), location.getUsername()));
co.setMobileNo(firstText(user == null ? null : user.getMobileNo(), location.getMobileNo()));
co.setCorpinfoId(corpinfoId);
co.setCorpinfoName(firstText(corpinfoName, user == null ? null : user.getCorpinfoName()));
co.setInternalEmployee(user != null);
co.setPersonType(user == null ? "TEMP" : "INTERNAL");
co.setTerminalNo(location.getTerminalNo());
co.setCurrentLocation(location.getLocationName());
co.setLastLocationTime(location.getLastLocationTime());
co.setLon(location.getLon());
co.setLat(location.getLat());
co.setStaffRawJson(location.getPersonRawJson());
co.setLocationRawJson(location.getLocationRawJson());
return co;
}
private BiPersonPositionUserDO findUser(ThirdPartyPersonLocation location,
Map<String, BiPersonPositionUserDO> userMap) {
BiPersonPositionUserDO user = userMap.get(location.getUserId() == null
? null : String.valueOf(location.getUserId()));
if (user == null) {
user = userMap.get(location.getUsername());
}
if (user == null) {
user = userMap.get(location.getMobileNo());
}
if (user == null) {
user = userMap.get(location.getIdCardNo());
}
return user;
}
private String firstText(String... values) {
if (values == null) {
return null;
}
for (String value : values) {
if (StringUtils.hasText(value)) {
return value;
}
}
return null;
}
@Data
private static class ThirdPartyPersonLocation {
private Long userId;
private String username;
private String personName;
private String staffNo;
private String mobileNo;
private String idCardNo;
private String terminalNo;
private String locationName;
private Long lastLocationTime;
private BigDecimal lon;
private BigDecimal lat;
private String personRawJson;
private String locationRawJson;
}
}

View File

@ -9,21 +9,26 @@ import com.jjb.saas.framework.auth.model.SSOUser;
import com.jjb.saas.framework.auth.utils.AuthContext;
import com.zcloud.personnel.positioning.dto.BiAreaFenceQry;
import com.zcloud.personnel.positioning.dto.BiCompanyFenceQry;
import com.zcloud.personnel.positioning.dto.BiCompanyOnlinePersonQry;
import com.zcloud.personnel.positioning.dto.BiPersonLocationQry;
import com.zcloud.personnel.positioning.dto.BiPersonPositionQry;
import com.zcloud.personnel.positioning.dto.BiPersonTraceQry;
import com.zcloud.personnel.positioning.dto.clientobject.BiAreaFenceCO;
import com.zcloud.personnel.positioning.dto.clientobject.BiCompanyLocationCO;
import com.zcloud.personnel.positioning.dto.clientobject.BiCompanyOnlinePersonCO;
import com.zcloud.personnel.positioning.dto.clientobject.BiCompanyOnlinePersonStatCO;
import com.zcloud.personnel.positioning.dto.clientobject.BiOverviewCO;
import com.zcloud.personnel.positioning.dto.clientobject.BiPersonLocationCO;
import com.zcloud.personnel.positioning.dto.clientobject.BiPersonPositionCO;
import com.zcloud.personnel.positioning.dto.clientobject.BiPersonTraceCO;
import com.zcloud.personnel.positioning.dto.clientobject.BiPortStatCO;
import com.zcloud.personnel.positioning.integration.finds.FindsOpenApiClient;
import com.zcloud.personnel.positioning.persistence.dataobject.AreaDO;
import com.zcloud.personnel.positioning.persistence.dataobject.BiPersonPositionUserDO;
import com.zcloud.personnel.positioning.persistence.dataobject.FenceDO;
import com.zcloud.personnel.positioning.persistence.dataobject.BiAreaSnapshotDO;
import com.zcloud.personnel.positioning.persistence.dataobject.BiCompanyAlarmCountDO;
import com.zcloud.personnel.positioning.persistence.dataobject.BiCorpInfoDO;
import com.zcloud.personnel.positioning.persistence.repository.AreaRepository;
import com.zcloud.personnel.positioning.persistence.repository.FenceRepository;
import com.zcloud.personnel.positioning.persistence.repository.PersonnelPositioningBiRepository;
import com.zcloud.personnel.positioning.persistence.repository.UserRepository;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
@ -64,8 +69,11 @@ public class PersonnelPositioningBiQueryExe {
private final FindsOpenApiClient findsOpenApiClient;
private final ObjectMapper objectMapper;
private final PersonnelPositioningBiRepository biRepository;
private final JdbcTemplate jdbcTemplate;
private final AreaRepository areaRepository;
private final FenceRepository fenceRepository;
private final UserRepository userRepository;
private final BiPersonLocationProvider biPersonLocationProvider;
private final BiOverviewCache biOverviewCache;
private final PositionPersonLocalLookupService localLookupService;
@ -230,6 +238,200 @@ public class PersonnelPositioningBiQueryExe {
return PageResponse.of(rows.subList(fromIndex, toIndex), rows.size(), pageSize, pageNo);
}
public List<BiPersonPositionCO> listPersonPosition(BiPersonPositionQry qry) {
if (qry == null || qry.getCorpinfoId() == null) {
throw new BizException("企业id不能为空");
}
String corpinfoId = String.valueOf(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));
}
return result;
}
private List<BiPersonPositionArea> loadBiPersonPositionAreas(String 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(String corpinfoId) {
List<BiCompanyOnlinePersonCO> locations =
biPersonLocationProvider.listCompanyOnlinePersons(corpinfoId, null, null);
Map<String, BiCompanyOnlinePersonCO> result = new LinkedHashMap<>();
for (BiCompanyOnlinePersonCO location : locations) {
putBiPersonPositionLocation(result, location.getUserId() == null ? null : String.valueOf(location.getUserId()), location);
putBiPersonPositionLocation(result, location.getStaffNo(), location);
putBiPersonPositionLocation(result, location.getMobileNo(), location);
}
return result;
}
private void putBiPersonPositionLocation(Map<String, BiCompanyOnlinePersonCO> locationMap,
String key,
BiCompanyOnlinePersonCO location) {
if (StringUtils.hasText(key)) {
locationMap.putIfAbsent(key.trim(), location);
}
}
private BiCompanyOnlinePersonCO findBiPersonPositionLocation(BiPersonPositionUserDO user,
Map<String, BiCompanyOnlinePersonCO> locationMap) {
if (user == null || locationMap == null || locationMap.isEmpty()) {
return null;
}
BiCompanyOnlinePersonCO location = locationMap.get(String.valueOf(user.getUserId()));
if (location == null) {
location = locationMap.get(user.getUsername());
}
if (location == null) {
location = locationMap.get(user.getMobileNo());
}
if (location == null) {
location = locationMap.get(user.getIdCardNo());
}
return location;
}
private BiPersonPositionCO buildBiPersonPositionRow(BiPersonPositionUserDO user,
BiCompanyOnlinePersonCO location,
List<BiPersonPositionArea> areas) {
BiPersonPositionCO co = new BiPersonPositionCO();
co.setUserId(user.getUserId());
co.setPersonName(user.getPersonName());
co.setCorpinfoId(user.getCorpinfoId());
co.setCorpinfoName(user.getCorpinfoName());
if (location == null) {
co.setOnlineStatus("OFFLINE");
co.setOnlineStatusName("离线");
return co;
}
co.setOnlineStatus("ONLINE");
co.setOnlineStatusName("在线");
co.setLon(location.getLon());
co.setLat(location.getLat());
co.setLastLocationTime(location.getLastLocationTime());
fillBiPersonPositionArea(co, location, areas);
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(BiCompanyOnlinePersonQry qry) {
BiCompanyOnlinePersonQry query = qry == null ? new BiCompanyOnlinePersonQry() : qry;
validatePortArea(query.getPortArea());
List<CorpInfoView> corpInfos = queryCompanyOnlineCorpInfos(query);
List<BiCompanyOnlinePersonCO> personList = new ArrayList<>();
for (CorpInfoView corpInfo : corpInfos) {
personList.addAll(biPersonLocationProvider.listCompanyOnlinePersons(
corpInfo.corpinfoId, corpInfo.corpName, corpInfo.code));
}
personList.sort((left, right) -> {
long leftTime = left.getLastLocationTime() == null ? 0L : left.getLastLocationTime();
long rightTime = right.getLastLocationTime() == null ? 0L : right.getLastLocationTime();
return Long.compare(rightTime, leftTime);
});
BiCompanyOnlinePersonStatCO co = new BiCompanyOnlinePersonStatCO();
co.setPersonList(personList);
co.setOnlineCount(personList.size());
int internalCount = 0;
for (BiCompanyOnlinePersonCO person : personList) {
if (Boolean.TRUE.equals(person.getInternalEmployee())) {
internalCount++;
}
}
co.setInternalCount(internalCount);
co.setTemporaryCount(personList.size() - internalCount);
return co;
}
private List<CorpInfoView> queryCompanyOnlineCorpInfos(BiCompanyOnlinePersonQry qry) {
if (qry.getCorpinfoId() != null) {
CorpInfoView corpInfo = queryCorpInfoById(String.valueOf(qry.getCorpinfoId()));
if (corpInfo == null) {
throw new BizException("未找到对应企业信息");
}
if (qry.getPortArea() != null && !qry.getPortArea().equals(corpInfo.portArea)) {
return Collections.emptyList();
}
return Collections.singletonList(corpInfo);
}
return listCorpInfos(qry.getPortArea());
}
private List<BiPersonLocationCO> loadMatchedPersonLocations(BiPersonLocationQry query) {
List<StaffSnapshot> staffRows = loadAllStaffSnapshots();
Set<String> phones = new LinkedHashSet<>();
@ -1204,7 +1406,8 @@ public class PersonnelPositioningBiQueryExe {
if (corpinfoId == null) {
return null;
}
return mapCorpInfo(biRepository.findCorpById(corpinfoId));
return queryFirstCorpInfo(CORP_INFO_SELECT
+ " AND CAST(id AS CHAR) = CAST(? AS CHAR) LIMIT 1", corpinfoId);
}
private CorpInfoView mapCorpInfo(BiCorpInfoDO row) {
@ -1381,6 +1584,16 @@ 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

@ -6,9 +6,12 @@ import com.zcloud.personnel.positioning.command.AlarmRecordRemoveExe;
import com.zcloud.personnel.positioning.command.AlarmRecordUpdateExe;
import com.zcloud.personnel.positioning.command.query.AlarmRecordQueryExe;
import com.zcloud.personnel.positioning.dto.AlarmRecordAddCmd;
import com.zcloud.personnel.positioning.dto.AlarmRecordBiAlarmTypeQry;
import com.zcloud.personnel.positioning.dto.AlarmRecordBiQry;
import com.zcloud.personnel.positioning.dto.AlarmRecordPageQry;
import com.zcloud.personnel.positioning.dto.AlarmRecordUpdateCmd;
import com.zcloud.personnel.positioning.dto.clientobject.AlarmRecordCO;
import com.zcloud.personnel.positioning.dto.clientobject.AlarmTypeStatCO;
import com.zcloud.personnel.positioning.dto.clientobject.OptionCO;
import com.alibaba.cola.dto.PageResponse;
import com.alibaba.cola.dto.SingleResponse;
@ -36,6 +39,16 @@ public class AlarmRecordServiceImpl implements AlarmRecordServiceI {
return alarmRecordQueryExe.execute(qry);
}
@Override
public List<AlarmRecordCO> listBiAlarm(AlarmRecordBiQry qry) {
return alarmRecordQueryExe.listBiAlarm(qry);
}
@Override
public List<AlarmTypeStatCO> listBiAlarmType(AlarmRecordBiAlarmTypeQry qry) {
return alarmRecordQueryExe.listBiAlarmType(qry);
}
@Override
public List<AlarmRecordCO> listAll() {
return alarmRecordQueryExe.listAll();

View File

@ -9,6 +9,7 @@ import com.zcloud.personnel.positioning.dto.AreaAddCmd;
import com.zcloud.personnel.positioning.dto.AreaPageQry;
import com.zcloud.personnel.positioning.dto.AreaUpdateCmd;
import com.zcloud.personnel.positioning.dto.clientobject.AreaCO;
import com.zcloud.personnel.positioning.dto.clientobject.AreaPersonStatCO;
import com.zcloud.personnel.positioning.dto.clientobject.OptionCO;
import com.alibaba.cola.dto.PageResponse;
import com.alibaba.cola.dto.SingleResponse;
@ -46,6 +47,11 @@ public class AreaServiceImpl implements AreaServiceI {
return areaQueryExe.listOptions(corpinfoId, keyword);
}
@Override
public List<AreaPersonStatCO> listPersonStat(Long corpinfoId) {
return areaQueryExe.listPersonStat(corpinfoId);
}
@Override
public AreaCO queryById(Long id) {
return areaQueryExe.queryById(id);

View File

@ -4,13 +4,17 @@ import com.alibaba.cola.dto.PageResponse;
import com.zcloud.personnel.positioning.api.PersonnelPositioningBiServiceI;
import com.zcloud.personnel.positioning.command.query.PersonnelPositioningBiQueryExe;
import com.zcloud.personnel.positioning.dto.BiAreaFenceQry;
import com.zcloud.personnel.positioning.dto.BiCompanyOnlinePersonQry;
import com.zcloud.personnel.positioning.dto.BiCompanyFenceQry;
import com.zcloud.personnel.positioning.dto.BiPersonLocationQry;
import com.zcloud.personnel.positioning.dto.BiPersonPositionQry;
import com.zcloud.personnel.positioning.dto.BiPersonTraceQry;
import com.zcloud.personnel.positioning.dto.clientobject.BiAreaFenceCO;
import com.zcloud.personnel.positioning.dto.clientobject.BiCompanyLocationCO;
import com.zcloud.personnel.positioning.dto.clientobject.BiCompanyOnlinePersonStatCO;
import com.zcloud.personnel.positioning.dto.clientobject.BiOverviewCO;
import com.zcloud.personnel.positioning.dto.clientobject.BiPersonLocationCO;
import com.zcloud.personnel.positioning.dto.clientobject.BiPersonPositionCO;
import com.zcloud.personnel.positioning.dto.clientobject.BiPersonTraceCO;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Service;
@ -48,6 +52,16 @@ public class PersonnelPositioningBiServiceImpl implements PersonnelPositioningBi
return personnelPositioningBiQueryExe.listPersonLocation(qry);
}
@Override
public List<BiPersonPositionCO> listPersonPosition(BiPersonPositionQry qry) {
return personnelPositioningBiQueryExe.listPersonPosition(qry);
}
@Override
public BiCompanyOnlinePersonStatCO queryCompanyOnlinePersonStat(BiCompanyOnlinePersonQry qry) {
return personnelPositioningBiQueryExe.queryCompanyOnlinePersonStat(qry);
}
@Override
public BiPersonTraceCO queryPersonTrace(BiPersonTraceQry qry) {
return personnelPositioningBiQueryExe.queryPersonTrace(qry);

View File

@ -1,9 +1,12 @@
package com.zcloud.personnel.positioning.api;
import com.zcloud.personnel.positioning.dto.AlarmRecordAddCmd;
import com.zcloud.personnel.positioning.dto.AlarmRecordBiAlarmTypeQry;
import com.zcloud.personnel.positioning.dto.AlarmRecordBiQry;
import com.zcloud.personnel.positioning.dto.AlarmRecordPageQry;
import com.zcloud.personnel.positioning.dto.AlarmRecordUpdateCmd;
import com.zcloud.personnel.positioning.dto.clientobject.AlarmRecordCO;
import com.zcloud.personnel.positioning.dto.clientobject.AlarmTypeStatCO;
import com.zcloud.personnel.positioning.dto.clientobject.OptionCO;
import com.alibaba.cola.dto.PageResponse;
import com.alibaba.cola.dto.SingleResponse;
@ -19,6 +22,10 @@ import java.util.List;
public interface AlarmRecordServiceI {
PageResponse<AlarmRecordCO> listPage(AlarmRecordPageQry qry);
List<AlarmRecordCO> listBiAlarm(AlarmRecordBiQry qry);
List<AlarmTypeStatCO> listBiAlarmType(AlarmRecordBiAlarmTypeQry qry);
List<AlarmRecordCO> listAll();
AlarmRecordCO queryById(Long id);

View File

@ -4,6 +4,7 @@ import com.zcloud.personnel.positioning.dto.AreaAddCmd;
import com.zcloud.personnel.positioning.dto.AreaPageQry;
import com.zcloud.personnel.positioning.dto.AreaUpdateCmd;
import com.zcloud.personnel.positioning.dto.clientobject.AreaCO;
import com.zcloud.personnel.positioning.dto.clientobject.AreaPersonStatCO;
import com.zcloud.personnel.positioning.dto.clientobject.OptionCO;
import com.alibaba.cola.dto.PageResponse;
import com.alibaba.cola.dto.SingleResponse;
@ -23,6 +24,8 @@ public interface AreaServiceI {
List<OptionCO> listOptions(String corpinfoId, String keyword);
List<AreaPersonStatCO> listPersonStat(Long corpinfoId);
AreaCO queryById(Long id);
SingleResponse<AreaCO> add(AreaAddCmd cmd);

View File

@ -2,13 +2,17 @@ package com.zcloud.personnel.positioning.api;
import com.alibaba.cola.dto.PageResponse;
import com.zcloud.personnel.positioning.dto.BiAreaFenceQry;
import com.zcloud.personnel.positioning.dto.BiCompanyOnlinePersonQry;
import com.zcloud.personnel.positioning.dto.BiCompanyFenceQry;
import com.zcloud.personnel.positioning.dto.BiPersonLocationQry;
import com.zcloud.personnel.positioning.dto.BiPersonPositionQry;
import com.zcloud.personnel.positioning.dto.BiPersonTraceQry;
import com.zcloud.personnel.positioning.dto.clientobject.BiAreaFenceCO;
import com.zcloud.personnel.positioning.dto.clientobject.BiCompanyLocationCO;
import com.zcloud.personnel.positioning.dto.clientobject.BiCompanyOnlinePersonStatCO;
import com.zcloud.personnel.positioning.dto.clientobject.BiOverviewCO;
import com.zcloud.personnel.positioning.dto.clientobject.BiPersonLocationCO;
import com.zcloud.personnel.positioning.dto.clientobject.BiPersonPositionCO;
import com.zcloud.personnel.positioning.dto.clientobject.BiPersonTraceCO;
import java.util.List;
@ -28,6 +32,10 @@ public interface PersonnelPositioningBiServiceI {
PageResponse<BiPersonLocationCO> listPersonLocation(BiPersonLocationQry qry);
List<BiPersonPositionCO> listPersonPosition(BiPersonPositionQry qry);
BiCompanyOnlinePersonStatCO queryCompanyOnlinePersonStat(BiCompanyOnlinePersonQry qry);
BiPersonTraceCO queryPersonTrace(BiPersonTraceQry qry);
PageResponse<BiAreaFenceCO> listAreaFence(BiAreaFenceQry qry);

View File

@ -0,0 +1,16 @@
package com.zcloud.personnel.positioning.dto;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/**
*
*
* @Author Codex
* @Date 2026-07-27
*/
@Data
public class AlarmRecordBiAlarmTypeQry {
@ApiModelProperty(value = "企业id", name = "corpinfoId")
private Long corpinfoId;
}

View File

@ -0,0 +1,19 @@
package com.zcloud.personnel.positioning.dto;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/**
*
*
* @Author Codex
* @Date 2026-07-27
*/
@Data
public class AlarmRecordBiQry {
@ApiModelProperty(value = "企业id", name = "corpinfoId")
private Long corpinfoId;
@ApiModelProperty(value = "港区1:秦皇岛港区,2:秦皇岛东,3:秦皇岛西", name = "portArea")
private Integer portArea;
}

View File

@ -0,0 +1,19 @@
package com.zcloud.personnel.positioning.dto;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/**
* BI线
*
* @Author Codex
* @Date 2026-07-27
*/
@Data
public class BiCompanyOnlinePersonQry {
@ApiModelProperty(value = "企业id", name = "corpinfoId")
private Long corpinfoId;
@ApiModelProperty(value = "港区1:秦皇岛港区,2:秦皇岛东,3:秦皇岛西", name = "portArea")
private Integer portArea;
}

View File

@ -0,0 +1,16 @@
package com.zcloud.personnel.positioning.dto;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/**
*
*
* @Author Codex
* @Date 2026-07-27
*/
@Data
public class BiPersonPositionQry {
@ApiModelProperty(value = "企业id", name = "corpinfoId")
private Long corpinfoId;
}

View File

@ -0,0 +1,23 @@
package com.zcloud.personnel.positioning.dto.clientobject;
import com.alibaba.cola.dto.ClientObject;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/**
*
*
* @Author Codex
* @Date 2026-07-27
*/
@Data
public class AlarmTypeStatCO extends ClientObject {
@ApiModelProperty(value = "报警类型编码", name = "alarmCode")
private String alarmCode;
@ApiModelProperty(value = "报警类型名称", name = "alarmName")
private String alarmName;
@ApiModelProperty(value = "报警数量", name = "alarmCount")
private Long alarmCount;
}

View File

@ -0,0 +1,52 @@
package com.zcloud.personnel.positioning.dto.clientobject;
import com.alibaba.cola.dto.ClientObject;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.math.BigDecimal;
/**
*
*
* @Author Codex
* @Date 2026-07-27
*/
@Data
public class AreaPersonStatCO extends ClientObject {
@ApiModelProperty(value = "区域ID", name = "areaId")
private Long areaId;
@ApiModelProperty(value = "区域编码", name = "areaCode")
private String areaCode;
@ApiModelProperty(value = "区域名称", name = "areaName")
private String areaName;
@ApiModelProperty(value = "区域类型", name = "areaType")
private String areaType;
@ApiModelProperty(value = "企业id", name = "corpinfoId")
private String corpinfoId;
@ApiModelProperty(value = "企业名称", name = "corpinfoName")
private String corpinfoName;
@ApiModelProperty(value = "中心点经度", name = "centerLon")
private BigDecimal centerLon;
@ApiModelProperty(value = "中心点纬度", name = "centerLat")
private BigDecimal centerLat;
@ApiModelProperty(value = "区域边界坐标JSON", name = "polygonJson")
private String polygonJson;
@ApiModelProperty(value = "单位人数", name = "unitCount")
private Integer unitCount;
@ApiModelProperty(value = "相关方人员数量", name = "relatedCount")
private Integer relatedCount;
@ApiModelProperty(value = "区域内总人数", name = "totalCount")
private Integer totalCount;
}

View File

@ -0,0 +1,61 @@
package com.zcloud.personnel.positioning.dto.clientobject;
import com.alibaba.cola.dto.ClientObject;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.math.BigDecimal;
/**
* BI线
*
* @Author
* @Date 2026-07-27
*/
@Data
public class BiCompanyOnlinePersonCO extends ClientObject {
@ApiModelProperty(value = "本平台用户ID内部员工时返回", name = "userId")
private Long userId;
@ApiModelProperty(value = "人员姓名", name = "staffName")
private String staffName;
@ApiModelProperty(value = "三方人员编号", name = "staffNo")
private String staffNo;
@ApiModelProperty(value = "手机号", name = "mobileNo")
private String mobileNo;
@ApiModelProperty(value = "企业id", name = "corpinfoId")
private String corpinfoId;
@ApiModelProperty(value = "企业名称", name = "corpinfoName")
private String corpinfoName;
@ApiModelProperty(value = "是否内部员工", name = "internalEmployee")
private Boolean internalEmployee;
@ApiModelProperty(value = "人员类型 INTERNAL内部 TEMP临时", name = "personType")
private String personType;
@ApiModelProperty(value = "终端号", name = "terminalNo")
private String terminalNo;
@ApiModelProperty(value = "当前位置", name = "currentLocation")
private String currentLocation;
@ApiModelProperty(value = "最后定位时间", name = "lastLocationTime")
private Long lastLocationTime;
@ApiModelProperty(value = "经度", name = "lon")
private BigDecimal lon;
@ApiModelProperty(value = "纬度", name = "lat")
private BigDecimal lat;
@ApiModelProperty(value = "人员原始JSON", name = "staffRawJson")
private String staffRawJson;
@ApiModelProperty(value = "定位原始JSON", name = "locationRawJson")
private String locationRawJson;
}

View File

@ -0,0 +1,28 @@
package com.zcloud.personnel.positioning.dto.clientobject;
import com.alibaba.cola.dto.ClientObject;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.util.List;
/**
* BI线
*
* @Author Codex
* @Date 2026-07-27
*/
@Data
public class BiCompanyOnlinePersonStatCO extends ClientObject {
@ApiModelProperty(value = "在线员工数量", name = "onlineCount")
private Integer onlineCount;
@ApiModelProperty(value = "内部人员数量", name = "internalCount")
private Integer internalCount;
@ApiModelProperty(value = "临时人员数量", name = "temporaryCount")
private Integer temporaryCount;
@ApiModelProperty(value = "在线人员列表", name = "personList")
private List<BiCompanyOnlinePersonCO> personList;
}

View File

@ -0,0 +1,49 @@
package com.zcloud.personnel.positioning.dto.clientobject;
import com.alibaba.cola.dto.ClientObject;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.math.BigDecimal;
/**
*
*
* @Author Codex
* @Date 2026-07-27
*/
@Data
public class BiPersonPositionCO extends ClientObject {
@ApiModelProperty(value = "用户ID", name = "userId")
private Long userId;
@ApiModelProperty(value = "人员姓名", name = "personName")
private String personName;
@ApiModelProperty(value = "所属区域", name = "areaName")
private String areaName;
@ApiModelProperty(value = "在线状态 ONLINE在线 OFFLINE离线", name = "onlineStatus")
private String onlineStatus;
@ApiModelProperty(value = "在线状态名称", name = "onlineStatusName")
private String onlineStatusName;
@ApiModelProperty(value = "企业id", name = "corpinfoId")
private String corpinfoId;
@ApiModelProperty(value = "企业名称", name = "corpinfoName")
private String corpinfoName;
@ApiModelProperty(value = "区域ID", name = "areaId")
private Long areaId;
@ApiModelProperty(value = "经度", name = "lon")
private BigDecimal lon;
@ApiModelProperty(value = "纬度", name = "lat")
private BigDecimal lat;
@ApiModelProperty(value = "最后定位时间", name = "lastLocationTime")
private Long lastLocationTime;
}

View File

@ -0,0 +1,18 @@
package com.zcloud.personnel.positioning.persistence.dataobject;
import lombok.Data;
/**
*
*
* @Author Codex
* @Date 2026-07-27
*/
@Data
public class AlarmTypeStatDO {
private String alarmCode;
private String alarmName;
private Long alarmCount;
}

View File

@ -0,0 +1,20 @@
package com.zcloud.personnel.positioning.persistence.dataobject;
import lombok.Data;
/**
*
*
* @Author Codex
* @Date 2026-07-27
*/
@Data
public class BiPersonPositionUserDO {
private Long userId;
private String username;
private String personName;
private String mobileNo;
private String idCardNo;
private String corpinfoId;
private String corpinfoName;
}

View File

@ -1,5 +1,6 @@
package com.zcloud.personnel.positioning.persistence.mapper;
import com.zcloud.personnel.positioning.persistence.dataobject.AlarmTypeStatDO;
import com.zcloud.personnel.positioning.persistence.dataobject.AlarmRecordDO;
import com.zcloud.personnel.positioning.persistence.dataobject.CompanyOptionDO;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
@ -7,7 +8,6 @@ import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.List;
import java.util.Map;
/**
* web-infrastructure
@ -17,7 +17,8 @@ import java.util.Map;
*/
@Mapper
public interface AlarmRecordMapper extends BaseMapper<AlarmRecordDO> {
List<CompanyOptionDO> listCompanyOptions(@Param("params") Map<String, Object> params);
List<AlarmRecordDO> selectBiAlarmList(@Param("corpinfoId") String corpinfoId,
@Param("portArea") Integer portArea);
String findCorpinfoName(@Param("corpinfoId") String corpinfoId);
List<AlarmTypeStatDO> selectBiAlarmTypeList(@Param("corpinfoId") String corpinfoId);
}

View File

@ -3,6 +3,9 @@ package com.zcloud.personnel.positioning.persistence.mapper;
import com.zcloud.personnel.positioning.persistence.dataobject.AreaDO;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.List;
/**
* web-infrastructure
@ -12,4 +15,5 @@ import org.apache.ibatis.annotations.Mapper;
*/
@Mapper
public interface AreaMapper extends BaseMapper<AreaDO> {
List<AreaDO> selectBiPersonPositionAreas(@Param("corpinfoId") String corpinfoId);
}

View File

@ -0,0 +1,18 @@
package com.zcloud.personnel.positioning.persistence.mapper;
import com.zcloud.personnel.positioning.persistence.dataobject.BiPersonPositionUserDO;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.List;
/**
*
*
* @Author Codex
* @Date 2026-07-27
*/
@Mapper
public interface UserMapper {
List<BiPersonPositionUserDO> selectBiPersonPositionUsers(@Param("corpinfoId") String corpinfoId);
}

View File

@ -1,5 +1,6 @@
package com.zcloud.personnel.positioning.persistence.repository;
import com.zcloud.personnel.positioning.persistence.dataobject.AlarmTypeStatDO;
import com.zcloud.personnel.positioning.persistence.dataobject.AlarmRecordDO;
import com.zcloud.personnel.positioning.persistence.dataobject.CompanyOptionDO;
import com.alibaba.cola.dto.PageResponse;
@ -17,7 +18,7 @@ import java.util.Map;
public interface AlarmRecordRepository extends BaseRepository<AlarmRecordDO> {
PageResponse<AlarmRecordDO> listPage(Map<String, Object> params);
List<CompanyOptionDO> listCompanyOptions(Map<String, Object> params);
List<AlarmRecordDO> listBiAlarm(String corpinfoId, Integer portArea);
String findCorpinfoName(String corpinfoId);
List<AlarmTypeStatDO> listBiAlarmType(String corpinfoId);
}

View File

@ -4,6 +4,7 @@ import com.zcloud.personnel.positioning.persistence.dataobject.AreaDO;
import com.alibaba.cola.dto.PageResponse;
import com.jjb.saas.framework.repository.repo.BaseRepository;
import java.util.List;
import java.util.Map;
/**
@ -14,4 +15,6 @@ import java.util.Map;
*/
public interface AreaRepository extends BaseRepository<AreaDO> {
PageResponse<AreaDO> listPage(Map<String, Object> params);
List<AreaDO> listBiPersonPositionAreas(String corpinfoId);
}

View File

@ -0,0 +1,15 @@
package com.zcloud.personnel.positioning.persistence.repository;
import com.zcloud.personnel.positioning.persistence.dataobject.BiPersonPositionUserDO;
import java.util.List;
/**
*
*
* @Author Codex
* @Date 2026-07-27
*/
public interface UserRepository {
List<BiPersonPositionUserDO> listBiPersonPositionUsers(String corpinfoId);
}

View File

@ -1,5 +1,6 @@
package com.zcloud.personnel.positioning.persistence.repository.impl;
import com.zcloud.personnel.positioning.persistence.dataobject.AlarmTypeStatDO;
import com.zcloud.personnel.positioning.persistence.dataobject.AlarmRecordDO;
import com.zcloud.personnel.positioning.persistence.dataobject.CompanyOptionDO;
import com.zcloud.personnel.positioning.persistence.mapper.AlarmRecordMapper;
@ -39,12 +40,12 @@ public class AlarmRecordRepositoryImpl extends BaseRepositoryImpl<AlarmRecordMap
}
@Override
public List<CompanyOptionDO> listCompanyOptions(Map<String, Object> params) {
return alarmRecordMapper.listCompanyOptions(params);
public List<AlarmRecordDO> listBiAlarm(String corpinfoId, Integer portArea) {
return alarmRecordMapper.selectBiAlarmList(corpinfoId, portArea);
}
@Override
public String findCorpinfoName(String corpinfoId) {
return alarmRecordMapper.findCorpinfoName(corpinfoId);
public List<AlarmTypeStatDO> listBiAlarmType(String corpinfoId) {
return alarmRecordMapper.selectBiAlarmTypeList(corpinfoId);
}
}

View File

@ -14,6 +14,7 @@ import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import java.util.Map;
import java.util.List;
/**
* web-infrastructure
@ -35,4 +36,9 @@ public class AreaRepositoryImpl extends BaseRepositoryImpl<AreaMapper, AreaDO> i
IPage<AreaDO> result = areaMapper.selectPage(iPage, queryWrapper);
return PageHelper.pageToResponse(result, result.getRecords());
}
@Override
public List<AreaDO> listBiPersonPositionAreas(String corpinfoId) {
return areaMapper.selectBiPersonPositionAreas(corpinfoId);
}
}

View File

@ -0,0 +1,26 @@
package com.zcloud.personnel.positioning.persistence.repository.impl;
import com.zcloud.personnel.positioning.persistence.dataobject.BiPersonPositionUserDO;
import com.zcloud.personnel.positioning.persistence.mapper.UserMapper;
import com.zcloud.personnel.positioning.persistence.repository.UserRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import java.util.List;
/**
*
*
* @Author Codex
* @Date 2026-07-27
*/
@Service
@RequiredArgsConstructor
public class UserRepositoryImpl implements UserRepository {
private final UserMapper userMapper;
@Override
public List<BiPersonPositionUserDO> listBiPersonPositionUsers(String corpinfoId) {
return userMapper.selectBiPersonPositionUsers(corpinfoId);
}
}

View File

@ -3,23 +3,78 @@
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.zcloud.personnel.positioning.persistence.mapper.AlarmRecordMapper">
<select id="listCompanyOptions"
resultType="com.zcloud.personnel.positioning.persistence.dataobject.CompanyOptionDO">
SELECT corp_name AS label, CAST(corpinfo_id AS CHAR) AS value
FROM corp_info
WHERE (delete_enum IS NULL OR delete_enum = 'FALSE')
AND corpinfo_id IS NOT NULL AND corp_name IS NOT NULL
<if test="params.eqCorpinfoId != null and params.eqCorpinfoId != ''">
AND corpinfo_id = #{params.eqCorpinfoId}
<select id="selectBiAlarmList"
resultType="com.zcloud.personnel.positioning.persistence.dataobject.AlarmRecordDO">
SELECT
ar.id,
ar.alarm_no,
ar.finds_alarm_id,
ar.alarm_code,
ar.alarm_name,
ar.level,
ar.description,
ar.dispose_status,
ar.dispose_description,
ar.duration,
ar.start_time,
ar.end_time,
ar.start_fences_json,
ar.end_fences_json,
ar.lon,
ar.lat,
ar.alt,
ar.speed,
ar.direction,
ar.gt,
CAST(ci.id AS CHAR) AS corpinfo_id,
ci.corp_name AS corpinfo_name,
ar.first_id_card_no,
ar.first_staff_no_snapshot,
ar.first_staff_name_snapshot,
ar.terminal_no_list_json,
ar.sync_time,
ar.raw_json,
ar.delete_enum,
ar.remarks,
ar.create_name,
ar.update_name,
ar.tenant_id,
ar.org_id,
ar.env,
ar.version,
ar.create_time,
ar.update_time,
ar.create_id,
ar.update_id
FROM alarm_record ar
INNER JOIN corp_info ci
ON CAST(ci.id AS CHAR) = CAST(ar.corpinfo_id AS CHAR)
WHERE (ar.delete_enum IS NULL OR ar.delete_enum = 'FALSE')
AND (ci.delete_enum IS NULL OR ci.delete_enum = 'FALSE')
<if test="corpinfoId != null and corpinfoId != ''">
AND CAST(ci.id AS CHAR) = CAST(#{corpinfoId} AS CHAR)
</if>
ORDER BY corp_name ASC
LIMIT 200
<if test="portArea != null">
AND ci.port_area = #{portArea}
</if>
ORDER BY COALESCE(ar.start_time, ar.create_time) DESC, ar.id DESC
</select>
<select id="findCorpinfoName" resultType="string">
SELECT corp_name FROM corp_info
WHERE CAST(corpinfo_id AS CHAR) = #{corpinfoId}
AND (delete_enum IS NULL OR delete_enum = 'FALSE')
LIMIT 1
<select id="selectBiAlarmTypeList"
resultType="com.zcloud.personnel.positioning.persistence.dataobject.AlarmTypeStatDO">
SELECT
ar.alarm_code AS alarmCode,
MAX(ar.alarm_name) AS alarmName,
COUNT(1) AS alarmCount
FROM alarm_record ar
INNER JOIN corp_info ci
ON CAST(ci.id AS CHAR) = CAST(ar.corpinfo_id AS CHAR)
WHERE (ar.delete_enum IS NULL OR ar.delete_enum = 'FALSE')
AND (ci.delete_enum IS NULL OR ci.delete_enum = 'FALSE')
<if test="corpinfoId != null and corpinfoId != ''">
AND CAST(ci.id AS CHAR) = CAST(#{corpinfoId} AS CHAR)
</if>
GROUP BY ar.alarm_code
ORDER BY alarmCount DESC, ar.alarm_code ASC
</select>
</mapper>

View File

@ -3,4 +3,45 @@
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.zcloud.personnel.positioning.persistence.mapper.AreaMapper">
<select id="selectBiPersonPositionAreas"
resultType="com.zcloud.personnel.positioning.persistence.dataobject.AreaDO">
SELECT
id,
area_code,
area_name,
area_type,
parent_id,
parent_code,
org_code,
org_name,
CAST(corpinfo_id AS CHAR) AS corpinfo_id,
corpinfo_name,
area_level,
sort_no,
center_lon,
center_lat,
polygon_json,
status,
bind_fence_id,
finds_fence_id,
delete_enum,
remarks,
create_name,
update_name,
tenant_id,
org_id,
env,
version,
create_time,
update_time,
create_id,
update_id
FROM area
WHERE (delete_enum IS NULL OR delete_enum = 'FALSE')
AND (status IS NULL OR status = 'ENABLED')
AND polygon_json IS NOT NULL
AND TRIM(polygon_json) != ''
AND CAST(corpinfo_id AS CHAR) = CAST(#{corpinfoId} AS CHAR)
ORDER BY sort_no ASC, area_name ASC, create_time DESC
</select>
</mapper>

View File

@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.zcloud.personnel.positioning.persistence.mapper.UserMapper">
<select id="selectBiPersonPositionUsers"
resultType="com.zcloud.personnel.positioning.persistence.dataobject.BiPersonPositionUserDO">
SELECT
u.id AS userId,
u.username AS username,
u.name AS personName,
TRIM(u.phone) AS mobileNo,
u.user_id_card AS idCardNo,
CAST(u.corpinfo_id AS CHAR) AS corpinfoId,
ci.corp_name AS corpinfoName
FROM `user` u
LEFT JOIN corp_info ci
ON CAST(ci.corpinfo_id AS CHAR) = CAST(u.corpinfo_id AS CHAR)
WHERE (u.delete_enum IS NULL OR u.delete_enum = 'FALSE')
AND CAST(u.corpinfo_id AS CHAR) = CAST(#{corpinfoId} AS CHAR)
ORDER BY u.id DESC
</select>
</mapper>