package com.xiaopeng.account.service.impl;
|
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
import com.alibaba.fastjson2.JSON;
|
import com.xiaopeng.account.mapper.XpAppUserCollectAddrMapper;
|
import com.xiaopeng.account.model.dto.CollectAddrDTO;
|
import com.xiaopeng.account.model.query.XpUserCollectAddrListQuery;
|
import com.xiaopeng.account.model.vo.CollectAddrTargetVO;
|
import com.xiaopeng.account.model.vo.XpAppUserCollectAddrVO;
|
import com.xiaopeng.account.service.IXpAppUserCollectAddrService;
|
import com.xiaopeng.api.dto.map.XpPointExportExcelQuery;
|
import com.xiaopeng.api.feignClient.map.XpStationClient;
|
import com.xiaopeng.api.feignClient.operation.XpPointClient;
|
import com.xiaopeng.api.model.account.XpAppUserCollectAddr;
|
import com.xiaopeng.api.model.operation.XpPoint;
|
import com.xiaopeng.api.model.operation.XpStation;
|
import com.xiaopeng.api.vo.order.XpPointsListVo;
|
import com.xiaopeng.common.core.domain.R;
|
import com.xiaopeng.common.core.exception.ServiceException;
|
import com.xiaopeng.common.core.web.page.PageInfo;
|
import org.springframework.stereotype.Service;
|
|
import javax.annotation.Resource;
|
import java.math.BigDecimal;
|
import java.math.RoundingMode;
|
import java.util.*;
|
import java.util.stream.Collectors;
|
|
/**
|
* <p>
|
* 用户收藏地址 服务实现类
|
* </p>
|
*
|
* @author ck
|
* @since 2026-04-10
|
*/
|
@Service
|
public class XpAppUserCollectAddrServiceImpl extends ServiceImpl<XpAppUserCollectAddrMapper, XpAppUserCollectAddr> implements IXpAppUserCollectAddrService {
|
|
private static final int COLLECT_TYPE_ADD = 1;
|
private static final int COLLECT_TYPE_CANCEL = 2;
|
private static final int ITEM_TYPE_POINT = 1;
|
private static final int ITEM_TYPE_STATION = 2;
|
private static final int COLLECT_LIMIT = 50;
|
|
|
@Resource
|
private XpPointClient xpPointClient;
|
|
@Resource
|
private XpStationClient xpStationClient;
|
|
|
|
|
/**
|
* 收藏地址。
|
* 收藏表显式保存 item_type / station_id:
|
* 1. 站点收藏:item_type=1,point_id 保存站点自身。
|
* 2. 场站收藏:item_type=2,station_id 保存场站id,point_id 保存代表点位id。
|
* 这样取消收藏、列表回显和后续扩展都不需要再做隐式推断。
|
*/
|
@Override
|
public Boolean collectAddr(CollectAddrDTO dto, String uid) {
|
Long userId = Long.parseLong(uid);
|
if(dto.getItemType() == 1){//收藏对象类型 1=站点 2=场站,不传时默认按站点处理
|
if(dto.getLatitude() == null || dto.getLongitude() == null){
|
throw new ServiceException("经度、纬度不能为空");
|
}
|
XpPointExportExcelQuery xpPointExportExcelQuery = new XpPointExportExcelQuery();
|
xpPointExportExcelQuery.setPointIds(Arrays.asList(dto.getPointId()));
|
List<XpPoint> data = xpPointClient.getByIds(xpPointExportExcelQuery).getData();
|
if(null == data || data.size() == 0){
|
throw new ServiceException("站点不存在");
|
}
|
}
|
if(dto.getItemType() == 2){
|
XpStation data = xpStationClient.getXpStationById(dto.getStationId()).getData();
|
if(null == data){
|
throw new ServiceException("场站不存在");
|
}
|
}
|
|
if(1 == dto.getType()){
|
XpAppUserCollectAddr collectAddr = new XpAppUserCollectAddr();
|
collectAddr.setAppUserId(userId);
|
collectAddr.setItemType(dto.getItemType());
|
collectAddr.setPointId(dto.getPointId());
|
collectAddr.setStationId(dto.getStationId());
|
collectAddr.setLongitude(dto.getLongitude());
|
collectAddr.setLatitude(dto.getLatitude());
|
return this.save(collectAddr);
|
}else{
|
if(dto.getItemType() == 1){
|
return this.remove(new LambdaQueryWrapper<XpAppUserCollectAddr>().eq(XpAppUserCollectAddr::getAppUserId, userId)
|
.eq(XpAppUserCollectAddr::getPointId, dto.getPointId()));
|
}
|
if(dto.getItemType() == 2){
|
return this.remove(new LambdaQueryWrapper<XpAppUserCollectAddr>().eq(XpAppUserCollectAddr::getAppUserId, userId)
|
.eq(XpAppUserCollectAddr::getStationId, dto.getStationId()));
|
}
|
|
}
|
return false;
|
}
|
|
/**
|
* 收藏地址列表。
|
* 列表查询直接联表回显,场站/站点通过 item_type 直接区分。
|
*/
|
@Override
|
public Page<XpAppUserCollectAddrVO> userCollectAddrList(XpUserCollectAddrListQuery query, String uid) {
|
Page<XpAppUserCollectAddrVO> page = new Page<>(query.getPageNum(), query.getPageSize());
|
Page<XpAppUserCollectAddrVO> pageData = this.baseMapper.userCollectAddrPageList(page, query, Long.parseLong(uid));
|
Set<Long> collectedPointIds = new HashSet<>(getPointIdsByUserId(Long.parseLong(uid)));
|
List<XpAppUserCollectAddrVO> list = new ArrayList<>();
|
for (XpAppUserCollectAddrVO record : pageData.getRecords()) {
|
if(record.getItemType() == 1){
|
XpPoint point = xpPointClient.queryById(record.getPointId()).getData();
|
if(null == point){
|
continue;
|
}
|
fillPointInfo(record, point, query);
|
}
|
if(record.getItemType() == 2){
|
fillCollectPointInfo(record, query);
|
XpStation data = xpStationClient.getXpStationById(record.getStationId()).getData();
|
if(null == data){
|
continue;
|
}
|
record.setPointName(data.getStationName());
|
record.setChildren(buildStationChildren(record.getStationId(), query, collectedPointIds));
|
}
|
|
list.add(record);
|
}
|
page.setTotal(list.size());
|
page.setRecords(list);
|
return page;
|
}
|
|
private List<XpPointsListVo> buildStationChildren(Long stationId, XpUserCollectAddrListQuery query, Set<Long> collectedPointIds) {
|
if (stationId == null) {
|
return Collections.emptyList();
|
}
|
R<List<XpPointsListVo>> result = xpPointClient.getStationChildren(stationId);
|
List<XpPointsListVo> children = result == null ? Collections.emptyList() : result.getData();
|
if (children == null || children.isEmpty()) {
|
return Collections.emptyList();
|
}
|
return children.stream()
|
.peek(child -> fillChildInfo(child, query, collectedPointIds))
|
.collect(Collectors.toList());
|
}
|
|
private void fillChildInfo(XpPointsListVo child, XpUserCollectAddrListQuery query, Set<Long> collectedPointIds) {
|
fillChildDistance(child, query);
|
if (collectedPointIds.contains(child.getId())) {
|
child.setIsCollect(1);
|
}
|
}
|
|
private void fillChildDistance(XpPointsListVo child, XpUserCollectAddrListQuery query) {
|
if (query.getLatitude() == null || query.getLongitude() == null || child.getLatitude() == null || child.getLongitude() == null) {
|
return;
|
}
|
double distance = distanceFast(query.getLatitude(), query.getLongitude(), child.getLatitude(), child.getLongitude());
|
child.setDistance(BigDecimal.valueOf(distance).setScale(2, RoundingMode.HALF_UP).doubleValue());
|
}
|
|
private void fillCollectPointInfo(XpAppUserCollectAddrVO collectAddrVO, XpUserCollectAddrListQuery query) {
|
XpPointExportExcelQuery xpPointExportExcelQuery = new XpPointExportExcelQuery();
|
xpPointExportExcelQuery.setPointIds(Arrays.asList(collectAddrVO.getPointId()));
|
List<XpPoint> data = xpPointClient.getByIds(xpPointExportExcelQuery).getData();
|
if (data == null || data.isEmpty()) {
|
return;
|
}
|
fillPointInfo(collectAddrVO, data.get(0), query);
|
}
|
|
private void fillPointInfo(XpAppUserCollectAddrVO collectAddrVO, XpPoint point, XpUserCollectAddrListQuery query) {
|
Integer parkingTimeLimit = point.getParkingTimeLimit();
|
//如果点位位于场站内,则使用场站的限停时间
|
if(null != point.getStationId()){
|
XpStation xpStation = xpStationClient.getXpStationById(point.getStationId()).getData();
|
parkingTimeLimit = xpStation.getParkingTimeLimit();
|
}
|
collectAddrVO.setPointName(point.getPointName());
|
collectAddrVO.setPointAddress(point.getPointAddress());
|
collectAddrVO.setElectronicAreaId(point.getElectronicAreaId());
|
collectAddrVO.setTime(parkingTimeLimit);
|
fillEffectiveTime(collectAddrVO, point.getEffectiveTimePeriod());
|
fillDistance(collectAddrVO, point, query);
|
}
|
|
private void fillEffectiveTime(XpAppUserCollectAddrVO collectAddrVO, String effectiveTimePeriod) {
|
if (effectiveTimePeriod == null || effectiveTimePeriod.isEmpty()) {
|
return;
|
}
|
List<String> timeRanges;
|
try {
|
timeRanges = JSON.parseArray(effectiveTimePeriod, String.class);
|
} catch (Exception e) {
|
return;
|
}
|
if (timeRanges == null || timeRanges.isEmpty()) {
|
return;
|
}
|
String[] timeRange = timeRanges.get(0).split("-");
|
if (timeRange.length != 2) {
|
return;
|
}
|
collectAddrVO.setStartTime(timeRange[0].trim());
|
collectAddrVO.setEndTime(timeRange[1].trim());
|
}
|
|
private void fillDistance(XpAppUserCollectAddrVO collectAddrVO, XpPoint point, XpUserCollectAddrListQuery query) {
|
if (query.getLatitude() == null || query.getLongitude() == null || point.getPointLat() == null || point.getPointLon() == null) {
|
return;
|
}
|
double distance = distanceFast(query.getLatitude(), query.getLongitude(), point.getPointLat(), point.getPointLon());
|
collectAddrVO.setDistance(BigDecimal.valueOf(distance).setScale(2, RoundingMode.HALF_UP).doubleValue());
|
}
|
|
private double distanceFast(double lat1, double lon1, double lat2, double lon2) {
|
double latDistance = Math.toRadians(lat2 - lat1);
|
double lonDistance = Math.toRadians(lon2 - lon1);
|
double value = Math.sin(latDistance / 2) * Math.sin(latDistance / 2)
|
+ Math.cos(Math.toRadians(lat1)) * Math.cos(Math.toRadians(lat2))
|
* Math.sin(lonDistance / 2) * Math.sin(lonDistance / 2);
|
return 6371000 * 2 * Math.atan2(Math.sqrt(value), Math.sqrt(1 - value));
|
}
|
|
@Override
|
public List<Long> getPointIdsByUserId(Long uid) {
|
return this.list(buildUserCollectQuery(uid)
|
.eq(XpAppUserCollectAddr::getItemType, ITEM_TYPE_POINT))
|
.stream()
|
.map(XpAppUserCollectAddr::getPointId)
|
.filter(Objects::nonNull)
|
.distinct()
|
.collect(Collectors.toList());
|
}
|
|
@Override
|
public List<Long> getStationIdsByUserId(Long uid) {
|
return this.list(buildUserCollectQuery(uid)
|
.eq(XpAppUserCollectAddr::getItemType, ITEM_TYPE_STATION))
|
.stream()
|
.map(XpAppUserCollectAddr::getStationId)
|
.filter(Objects::nonNull)
|
.distinct()
|
.collect(Collectors.toList());
|
}
|
|
|
|
private LambdaQueryWrapper<XpAppUserCollectAddr> buildUserCollectQuery(Long uid) {
|
return new LambdaQueryWrapper<XpAppUserCollectAddr>()
|
.eq(XpAppUserCollectAddr::getAppUserId, uid)
|
.eq(XpAppUserCollectAddr::getDeleted, 0);
|
}
|
|
|
}
|