You've already forked FrameTour-BE
feat(printer):优化人脸样本使用逻辑并增强景区列表查询
- 修改 useSample 接口返回类型为 FaceRecognizeResp - 增加根据样本ID和类型查询来源实体的逻辑 - 在景区列表查询中添加参数校验和异常处理 - 完善景区信息处理流程,增加设备数量统计 -优化景区距离计算与筛选逻辑 - 增加人脸匹配后自动添加照片到用户相册的功能 - 添加 XML 映射文件中新的查询语句实现
This commit is contained in:
@@ -2,6 +2,7 @@ package com.ycwl.basic.controller.mobile;
|
||||
|
||||
import com.ycwl.basic.annotation.IgnoreToken;
|
||||
import com.ycwl.basic.model.jwt.JwtInfo;
|
||||
import com.ycwl.basic.model.mobile.face.FaceRecognizeResp;
|
||||
import com.ycwl.basic.model.pc.printer.resp.MemberPrintResp;
|
||||
import com.ycwl.basic.model.pc.printer.resp.PrinterResp;
|
||||
import com.ycwl.basic.model.printer.req.FromSourceReq;
|
||||
@@ -37,7 +38,7 @@ public class AppPrinterController {
|
||||
}
|
||||
|
||||
@PostMapping("/useSample/{sampleId}")
|
||||
public ApiResponse<?> useSample(@PathVariable("sampleId") Long sampleId) throws IOException {
|
||||
public ApiResponse<FaceRecognizeResp> useSample(@PathVariable("sampleId") Long sampleId) throws IOException {
|
||||
JwtInfo worker = JwtTokenUtil.getWorker();
|
||||
return ApiResponse.success(printerService.useSample(worker.getUserId(), sampleId));
|
||||
}
|
||||
|
||||
@@ -105,4 +105,6 @@ public interface SourceMapper {
|
||||
* @return 影响行数
|
||||
*/
|
||||
int addFromZTSource(SourceEntity source);
|
||||
|
||||
SourceEntity getBySampleIdAndType(Long faceSampleId, Integer type);
|
||||
}
|
||||
|
||||
@@ -220,58 +220,98 @@ public class AppScenicServiceImpl implements AppScenicService {
|
||||
|
||||
@Override
|
||||
public List<ScenicAppVO> scenicListByLnLa(ScenicIndexVO scenicIndexVO) {
|
||||
// 参数校验
|
||||
if (scenicIndexVO == null) {
|
||||
log.warn("scenicListByLnLa 接收到空参数");
|
||||
return Collections.emptyList();
|
||||
}
|
||||
if (scenicIndexVO.getLatitude() == null || scenicIndexVO.getLongitude() == null) {
|
||||
log.warn("scenicListByLnLa 缺少必要的经纬度参数, latitude={}, longitude={}",
|
||||
scenicIndexVO.getLatitude(), scenicIndexVO.getLongitude());
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
// 从 scenicRepository 获取所有景区(1000个)
|
||||
ScenicReqQuery query = new ScenicReqQuery();
|
||||
query.setPageNum(1);
|
||||
query.setPageSize(1000);
|
||||
List<ScenicV2DTO> scenicList = scenicRepository.list(query);
|
||||
|
||||
|
||||
if (scenicList == null || scenicList.isEmpty()) {
|
||||
log.info("未查询到任何景区数据");
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
List<ScenicAppVO> list = new ArrayList<>();
|
||||
|
||||
|
||||
// 为每个景区获取详细信息(包含经纬度)
|
||||
for (ScenicV2DTO scenicDTO : scenicList) {
|
||||
try {
|
||||
// ID 格式校验
|
||||
if (StringUtils.isBlank(scenicDTO.getId())) {
|
||||
log.warn("景区 ID 为空,跳过该景区");
|
||||
continue;
|
||||
}
|
||||
|
||||
// 获取景区详细信息(包含经纬度)
|
||||
ScenicEntity scenicEntity = scenicRepository.getScenic(Long.parseLong(scenicDTO.getId()));
|
||||
if (scenicEntity != null && scenicEntity.getLatitude() != null && scenicEntity.getLongitude() != null) {
|
||||
// 计算距离
|
||||
BigDecimal distance = calculateDistance(
|
||||
scenicIndexVO.getLatitude(),
|
||||
scenicIndexVO.getLongitude(),
|
||||
scenicEntity.getLatitude(),
|
||||
scenicEntity.getLongitude()
|
||||
);
|
||||
|
||||
// 根据距离和范围筛选景区
|
||||
if (scenicEntity.getRadius() != null &&
|
||||
distance.compareTo(scenicEntity.getRadius().multiply(BigDecimal.valueOf(1_000L))) < 0) {
|
||||
|
||||
// 转换为 ScenicAppVO
|
||||
ScenicAppVO scenicAppVO = new ScenicAppVO();
|
||||
scenicAppVO.setId(scenicEntity.getId());
|
||||
scenicAppVO.setName(scenicEntity.getName());
|
||||
scenicAppVO.setPhone(scenicEntity.getPhone());
|
||||
scenicAppVO.setIntroduction(scenicEntity.getIntroduction());
|
||||
scenicAppVO.setCoverUrl(scenicEntity.getCoverUrl());
|
||||
scenicAppVO.setLongitude(scenicEntity.getLongitude());
|
||||
scenicAppVO.setLatitude(scenicEntity.getLatitude());
|
||||
scenicAppVO.setRadius(scenicEntity.getRadius());
|
||||
scenicAppVO.setProvince(scenicEntity.getProvince());
|
||||
scenicAppVO.setCity(scenicEntity.getCity());
|
||||
scenicAppVO.setArea(scenicEntity.getArea());
|
||||
scenicAppVO.setAddress(scenicEntity.getAddress());
|
||||
scenicAppVO.setDistance(distance);
|
||||
scenicAppVO.setDeviceNum(deviceRepository.getAllDeviceByScenicId(scenicEntity.getId()).size());
|
||||
|
||||
list.add(scenicAppVO);
|
||||
}
|
||||
if (scenicEntity == null) {
|
||||
log.warn("景区详情查询失败, scenicId={}", scenicDTO.getId());
|
||||
continue;
|
||||
}
|
||||
|
||||
if (scenicEntity.getLatitude() == null || scenicEntity.getLongitude() == null) {
|
||||
log.warn("景区缺少经纬度信息, scenicId={}, scenicName={}",
|
||||
scenicEntity.getId(), scenicEntity.getName());
|
||||
continue;
|
||||
}
|
||||
|
||||
// 计算距离
|
||||
BigDecimal distance = calculateDistance(
|
||||
scenicIndexVO.getLatitude(),
|
||||
scenicIndexVO.getLongitude(),
|
||||
scenicEntity.getLatitude(),
|
||||
scenicEntity.getLongitude()
|
||||
);
|
||||
|
||||
// 根据距离和范围筛选景区
|
||||
if (scenicEntity.getRadius() != null &&
|
||||
distance.compareTo(scenicEntity.getRadius().multiply(BigDecimal.valueOf(1_000L))) < 0) {
|
||||
|
||||
// 转换为 ScenicAppVO
|
||||
ScenicAppVO scenicAppVO = new ScenicAppVO();
|
||||
scenicAppVO.setId(scenicEntity.getId());
|
||||
scenicAppVO.setName(scenicEntity.getName());
|
||||
scenicAppVO.setPhone(scenicEntity.getPhone());
|
||||
scenicAppVO.setIntroduction(scenicEntity.getIntroduction());
|
||||
scenicAppVO.setCoverUrl(scenicEntity.getCoverUrl());
|
||||
scenicAppVO.setLongitude(scenicEntity.getLongitude());
|
||||
scenicAppVO.setLatitude(scenicEntity.getLatitude());
|
||||
scenicAppVO.setRadius(scenicEntity.getRadius());
|
||||
scenicAppVO.setProvince(scenicEntity.getProvince());
|
||||
scenicAppVO.setCity(scenicEntity.getCity());
|
||||
scenicAppVO.setArea(scenicEntity.getArea());
|
||||
scenicAppVO.setAddress(scenicEntity.getAddress());
|
||||
scenicAppVO.setDistance(distance);
|
||||
|
||||
// 获取设备数量
|
||||
List<DeviceV2DTO> devices = deviceRepository.getAllDeviceByScenicId(scenicEntity.getId());
|
||||
scenicAppVO.setDeviceNum(devices != null ? devices.size() : 0);
|
||||
|
||||
list.add(scenicAppVO);
|
||||
}
|
||||
} catch (NumberFormatException e) {
|
||||
log.error("景区 ID 格式错误,无法转换为 Long 类型, scenicId={}, error={}",
|
||||
scenicDTO.getId(), e.getMessage());
|
||||
} catch (Exception e) {
|
||||
// 单个景区获取失败,继续处理下一个
|
||||
continue;
|
||||
log.error("处理景区信息时发生异常, scenicId={}, error={}",
|
||||
scenicDTO != null ? scenicDTO.getId() : "unknown", e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
log.info("根据经纬度筛选景区完成, 输入坐标=({}, {}), 符合条件的景区数量={}",
|
||||
scenicIndexVO.getLatitude(), scenicIndexVO.getLongitude(), list.size());
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.ycwl.basic.service.printer;
|
||||
|
||||
import com.ycwl.basic.model.mobile.face.FaceRecognizeResp;
|
||||
import com.ycwl.basic.model.mobile.order.PriceObj;
|
||||
import com.ycwl.basic.model.pc.printer.entity.PrinterEntity;
|
||||
import com.ycwl.basic.model.pc.printer.resp.MemberPrintResp;
|
||||
@@ -56,7 +57,7 @@ public interface PrinterService {
|
||||
|
||||
void setUserIsBuyItem(Long memberId, Long id, Long orderId);
|
||||
|
||||
Object useSample(Long userId, Long sampleId);
|
||||
FaceRecognizeResp useSample(Long userId, Long sampleId);
|
||||
|
||||
void autoAddPhotosToPreferPrint(Long faceId);
|
||||
}
|
||||
@@ -752,9 +752,10 @@ public class PrinterServiceImpl implements PrinterService {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object useSample(Long userId, Long sampleId) {
|
||||
public FaceRecognizeResp useSample(Long userId, Long sampleId) {
|
||||
// 1. 查询 faceSample 获取其 URL
|
||||
FaceSampleEntity faceSample = faceSampleMapper.getEntity(sampleId);
|
||||
SourceEntity sourceEntity = sourceMapper.getBySampleIdAndType(sampleId, 2);
|
||||
if (faceSample == null) {
|
||||
throw new BaseException("人脸样本不存在");
|
||||
}
|
||||
@@ -807,6 +808,12 @@ public class PrinterServiceImpl implements PrinterService {
|
||||
resp.setScenicId(scenicId);
|
||||
faceService.matchFaceId(faceId);
|
||||
autoAddPhotosToPreferPrint(faceId);
|
||||
List<MemberPrintResp> userPhotoList = getUserPhotoList(userId, scenicId, faceId);
|
||||
boolean noneMatch = userPhotoList.stream()
|
||||
.noneMatch(item -> Strings.CI.equals(item.getOrigUrl(), sourceEntity.getUrl()));
|
||||
if (noneMatch) {
|
||||
addUserPhoto(userId, scenicId, sourceEntity.getUrl(), faceId);
|
||||
}
|
||||
return resp;
|
||||
}
|
||||
|
||||
|
||||
@@ -354,4 +354,9 @@
|
||||
inner join member_source ms on s.id = ms.source_id
|
||||
where ms.face_id = #{faceId} and s.type = 2
|
||||
</select>
|
||||
<select id="getBySampleIdAndType" resultType="com.ycwl.basic.model.pc.source.entity.SourceEntity">
|
||||
select *
|
||||
from source
|
||||
where face_sample_id = #{faceSampleId} and type = #{type}
|
||||
</select>
|
||||
</mapper>
|
||||
|
||||
Reference in New Issue
Block a user