You've already forked FrameTour-BE
Compare commits
8 Commits
becbe5f6ab
...
3c700a42f9
Author | SHA1 | Date | |
---|---|---|---|
3c700a42f9 | |||
47c6b2ca67 | |||
59baf8811b | |||
019b9ffca6 | |||
30805f3e30 | |||
94d6b2f443 | |||
b34f994298 | |||
7728f4424f |
@@ -3,8 +3,10 @@ package com.ycwl.basic.controller.pc;
|
|||||||
import com.ycwl.basic.integration.device.dto.config.*;
|
import com.ycwl.basic.integration.device.dto.config.*;
|
||||||
import com.ycwl.basic.integration.common.response.PageResponse;
|
import com.ycwl.basic.integration.common.response.PageResponse;
|
||||||
import com.ycwl.basic.integration.device.dto.device.*;
|
import com.ycwl.basic.integration.device.dto.device.*;
|
||||||
|
import com.ycwl.basic.integration.device.dto.status.DeviceStatusDTO;
|
||||||
import com.ycwl.basic.integration.device.service.DeviceConfigIntegrationService;
|
import com.ycwl.basic.integration.device.service.DeviceConfigIntegrationService;
|
||||||
import com.ycwl.basic.integration.device.service.DeviceIntegrationService;
|
import com.ycwl.basic.integration.device.service.DeviceIntegrationService;
|
||||||
|
import com.ycwl.basic.integration.device.service.DeviceStatusIntegrationService;
|
||||||
import com.ycwl.basic.utils.ApiResponse;
|
import com.ycwl.basic.utils.ApiResponse;
|
||||||
import jakarta.validation.Valid;
|
import jakarta.validation.Valid;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
@@ -29,6 +31,7 @@ public class DeviceV2Controller {
|
|||||||
|
|
||||||
private final DeviceIntegrationService deviceIntegrationService;
|
private final DeviceIntegrationService deviceIntegrationService;
|
||||||
private final DeviceConfigIntegrationService deviceConfigIntegrationService;
|
private final DeviceConfigIntegrationService deviceConfigIntegrationService;
|
||||||
|
private final DeviceStatusIntegrationService deviceStatusIntegrationService;
|
||||||
|
|
||||||
// ========== 设备基础 CRUD 操作 ==========
|
// ========== 设备基础 CRUD 操作 ==========
|
||||||
|
|
||||||
@@ -144,6 +147,28 @@ public class DeviceV2Controller {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据设备ID获取设备在线状态
|
||||||
|
*/
|
||||||
|
@GetMapping("/{id}/status")
|
||||||
|
public ApiResponse<DeviceStatusDTO> getDeviceOnlineStatus(@PathVariable Long id) {
|
||||||
|
log.info("获取设备在线状态, deviceId: {}", id);
|
||||||
|
try {
|
||||||
|
// 首先获取设备信息以获得设备编号
|
||||||
|
DeviceV2DTO device = deviceIntegrationService.getDevice(id);
|
||||||
|
if (device == null) {
|
||||||
|
return ApiResponse.fail("设备不存在");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 使用设备编号查询在线状态
|
||||||
|
DeviceStatusDTO onlineStatus = deviceStatusIntegrationService.getDeviceStatus(device.getNo());
|
||||||
|
return ApiResponse.success(onlineStatus);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("获取设备在线状态失败, deviceId: {}", id, e);
|
||||||
|
return ApiResponse.fail("获取设备在线状态失败: " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 创建设备
|
* 创建设备
|
||||||
*/
|
*/
|
||||||
|
@@ -0,0 +1,51 @@
|
|||||||
|
package com.ycwl.basic.integration.device.client;
|
||||||
|
|
||||||
|
import com.ycwl.basic.integration.common.response.CommonResponse;
|
||||||
|
import com.ycwl.basic.integration.device.dto.status.DeviceStatusDTO;
|
||||||
|
import com.ycwl.basic.integration.device.dto.status.OnlineStatusResponseDTO;
|
||||||
|
import org.springframework.cloud.openfeign.FeignClient;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.PathVariable;
|
||||||
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@FeignClient(name = "zt-device", contextId = "deviceStatusClient", path = "/api/device/status")
|
||||||
|
public interface DeviceStatusClient {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取设备状态
|
||||||
|
*/
|
||||||
|
@GetMapping("/{deviceNo}")
|
||||||
|
CommonResponse<DeviceStatusDTO> getDeviceStatus(@PathVariable("deviceNo") String deviceNo);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查设备是否在线
|
||||||
|
*/
|
||||||
|
@GetMapping("/{deviceNo}/online")
|
||||||
|
CommonResponse<OnlineStatusResponseDTO> isDeviceOnline(@PathVariable("deviceNo") String deviceNo);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取所有在线设备
|
||||||
|
*/
|
||||||
|
@GetMapping("/online")
|
||||||
|
CommonResponse<List<DeviceStatusDTO>> getAllOnlineDevices();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置设备离线
|
||||||
|
*/
|
||||||
|
@PostMapping("/{deviceNo}/offline")
|
||||||
|
CommonResponse<String> setDeviceOffline(@PathVariable("deviceNo") String deviceNo);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置设备在线
|
||||||
|
*/
|
||||||
|
@PostMapping("/{deviceNo}/online")
|
||||||
|
CommonResponse<String> setDeviceOnline(@PathVariable("deviceNo") String deviceNo);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 清理过期设备状态
|
||||||
|
*/
|
||||||
|
@PostMapping("/clean")
|
||||||
|
CommonResponse<String> cleanExpiredDevices();
|
||||||
|
}
|
@@ -0,0 +1,41 @@
|
|||||||
|
package com.ycwl.basic.integration.device.dto.status;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设备状态动作枚举
|
||||||
|
*/
|
||||||
|
public enum DeviceStatusActionEnum {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设备注册
|
||||||
|
*/
|
||||||
|
REGISTER("register"),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设备保活
|
||||||
|
*/
|
||||||
|
KEEPALIVE("keepalive"),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设备注销
|
||||||
|
*/
|
||||||
|
UNREGISTER("unregister");
|
||||||
|
|
||||||
|
private final String action;
|
||||||
|
|
||||||
|
DeviceStatusActionEnum(String action) {
|
||||||
|
this.action = action;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getAction() {
|
||||||
|
return action;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static DeviceStatusActionEnum fromString(String action) {
|
||||||
|
for (DeviceStatusActionEnum statusAction : values()) {
|
||||||
|
if (statusAction.action.equalsIgnoreCase(action)) {
|
||||||
|
return statusAction;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new IllegalArgumentException("Unknown device status action: " + action);
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,50 @@
|
|||||||
|
package com.ycwl.basic.integration.device.dto.status;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设备状态信息
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class DeviceStatusDTO {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设备编号
|
||||||
|
*/
|
||||||
|
private String deviceNo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否在线
|
||||||
|
*/
|
||||||
|
private Boolean isOnline;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 最后活动时间
|
||||||
|
*/
|
||||||
|
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||||
|
private Date lastActiveTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 最后动作(register/keepalive/unregister)
|
||||||
|
*/
|
||||||
|
private String lastAction;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 客户端IP
|
||||||
|
*/
|
||||||
|
private String clientIP;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 状态更新时间
|
||||||
|
*/
|
||||||
|
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||||
|
private Date updateTime;
|
||||||
|
}
|
@@ -0,0 +1,24 @@
|
|||||||
|
package com.ycwl.basic.integration.device.dto.status;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 在线状态响应
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class OnlineStatusResponseDTO {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设备编号
|
||||||
|
*/
|
||||||
|
private String deviceNo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否在线
|
||||||
|
*/
|
||||||
|
private Boolean isOnline;
|
||||||
|
}
|
@@ -0,0 +1,211 @@
|
|||||||
|
package com.ycwl.basic.integration.device.service;
|
||||||
|
|
||||||
|
import com.ycwl.basic.integration.common.exception.IntegrationException;
|
||||||
|
import com.ycwl.basic.integration.common.response.CommonResponse;
|
||||||
|
import com.ycwl.basic.integration.common.service.IntegrationFallbackService;
|
||||||
|
import com.ycwl.basic.integration.device.client.DeviceStatusClient;
|
||||||
|
import com.ycwl.basic.integration.device.dto.status.DeviceStatusDTO;
|
||||||
|
import com.ycwl.basic.integration.device.dto.status.OnlineStatusResponseDTO;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@Service
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class DeviceStatusIntegrationService {
|
||||||
|
|
||||||
|
private final DeviceStatusClient deviceStatusClient;
|
||||||
|
private final IntegrationFallbackService fallbackService;
|
||||||
|
|
||||||
|
private static final String SERVICE_NAME = "zt-device";
|
||||||
|
|
||||||
|
public DeviceStatusDTO getDeviceStatus(String deviceNo) {
|
||||||
|
log.debug("获取设备状态, deviceNo: {}", deviceNo);
|
||||||
|
return fallbackService.executeWithFallback(
|
||||||
|
SERVICE_NAME,
|
||||||
|
"device:status:" + deviceNo,
|
||||||
|
() -> {
|
||||||
|
CommonResponse<DeviceStatusDTO> response = deviceStatusClient.getDeviceStatus(deviceNo);
|
||||||
|
return handleResponse(response, "获取设备状态失败");
|
||||||
|
},
|
||||||
|
DeviceStatusDTO.class
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public OnlineStatusResponseDTO isDeviceOnline(String deviceNo) {
|
||||||
|
log.debug("检查设备是否在线, deviceNo: {}", deviceNo);
|
||||||
|
return fallbackService.executeWithFallback(
|
||||||
|
SERVICE_NAME,
|
||||||
|
"device:online:" + deviceNo,
|
||||||
|
() -> {
|
||||||
|
CommonResponse<OnlineStatusResponseDTO> response = deviceStatusClient.isDeviceOnline(deviceNo);
|
||||||
|
return handleResponse(response, "检查设备在线状态失败");
|
||||||
|
},
|
||||||
|
OnlineStatusResponseDTO.class
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<DeviceStatusDTO> getAllOnlineDevices() {
|
||||||
|
log.debug("获取所有在线设备");
|
||||||
|
return fallbackService.executeWithFallback(
|
||||||
|
SERVICE_NAME,
|
||||||
|
"devices:online:all",
|
||||||
|
() -> {
|
||||||
|
CommonResponse<List<DeviceStatusDTO>> response = deviceStatusClient.getAllOnlineDevices();
|
||||||
|
return handleResponse(response, "获取所有在线设备失败");
|
||||||
|
},
|
||||||
|
List.class
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDeviceOffline(String deviceNo) {
|
||||||
|
log.debug("设置设备离线, deviceNo: {}", deviceNo);
|
||||||
|
CommonResponse<String> response = deviceStatusClient.setDeviceOffline(deviceNo);
|
||||||
|
handleResponse(response, "设置设备离线失败");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDeviceOnline(String deviceNo) {
|
||||||
|
log.debug("设置设备在线, deviceNo: {}", deviceNo);
|
||||||
|
CommonResponse<String> response = deviceStatusClient.setDeviceOnline(deviceNo);
|
||||||
|
handleResponse(response, "设置设备在线失败");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void cleanExpiredDevices() {
|
||||||
|
log.debug("清理过期设备状态");
|
||||||
|
CommonResponse<String> response = deviceStatusClient.cleanExpiredDevices();
|
||||||
|
handleResponse(response, "清理过期设备状态失败");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 安全地获取设备状态
|
||||||
|
*/
|
||||||
|
public Optional<DeviceStatusDTO> getDeviceStatusSafely(String deviceNo) {
|
||||||
|
try {
|
||||||
|
DeviceStatusDTO status = getDeviceStatus(deviceNo);
|
||||||
|
return Optional.ofNullable(status);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.warn("获取设备状态异常: deviceNo={}, error={}", deviceNo, e.getMessage());
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 安全地检查设备是否在线
|
||||||
|
*/
|
||||||
|
public boolean isDeviceOnlineSafely(String deviceNo) {
|
||||||
|
try {
|
||||||
|
OnlineStatusResponseDTO response = isDeviceOnline(deviceNo);
|
||||||
|
return response != null && Boolean.TRUE.equals(response.getIsOnline());
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.warn("检查设备在线状态异常: deviceNo={}, error={}", deviceNo, e.getMessage());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量检查设备是否在线
|
||||||
|
*/
|
||||||
|
public boolean areAllDevicesOnline(List<String> deviceNos) {
|
||||||
|
if (deviceNos == null || deviceNos.isEmpty()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
log.debug("批量检查设备在线状态, deviceNos: {}", deviceNos);
|
||||||
|
for (String deviceNo : deviceNos) {
|
||||||
|
if (!isDeviceOnlineSafely(deviceNo)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量设置设备离线
|
||||||
|
*/
|
||||||
|
public void setDevicesOffline(List<String> deviceNos) {
|
||||||
|
if (deviceNos == null || deviceNos.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
log.debug("批量设置设备离线, deviceNos: {}", deviceNos);
|
||||||
|
for (String deviceNo : deviceNos) {
|
||||||
|
try {
|
||||||
|
setDeviceOffline(deviceNo);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("设置设备离线失败: deviceNo={}, error={}", deviceNo, e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量设置设备在线
|
||||||
|
*/
|
||||||
|
public void setDevicesOnline(List<String> deviceNos) {
|
||||||
|
if (deviceNos == null || deviceNos.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
log.debug("批量设置设备在线, deviceNos: {}", deviceNos);
|
||||||
|
for (String deviceNo : deviceNos) {
|
||||||
|
try {
|
||||||
|
setDeviceOnline(deviceNo);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("设置设备在线失败: deviceNo={}, error={}", deviceNo, e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取在线设备数量
|
||||||
|
*/
|
||||||
|
public int getOnlineDeviceCount() {
|
||||||
|
try {
|
||||||
|
List<DeviceStatusDTO> onlineDevices = getAllOnlineDevices();
|
||||||
|
return onlineDevices != null ? onlineDevices.size() : 0;
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.warn("获取在线设备数量失败: {}", e.getMessage());
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取指定设备编号列表中的在线设备
|
||||||
|
*/
|
||||||
|
public List<String> getOnlineDeviceNos(List<String> deviceNos) {
|
||||||
|
if (deviceNos == null || deviceNos.isEmpty()) {
|
||||||
|
return List.of();
|
||||||
|
}
|
||||||
|
|
||||||
|
return deviceNos.stream()
|
||||||
|
.filter(this::isDeviceOnlineSafely)
|
||||||
|
.toList();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取指定设备编号列表中的离线设备
|
||||||
|
*/
|
||||||
|
public List<String> getOfflineDeviceNos(List<String> deviceNos) {
|
||||||
|
if (deviceNos == null || deviceNos.isEmpty()) {
|
||||||
|
return List.of();
|
||||||
|
}
|
||||||
|
|
||||||
|
return deviceNos.stream()
|
||||||
|
.filter(deviceNo -> !isDeviceOnlineSafely(deviceNo))
|
||||||
|
.toList();
|
||||||
|
}
|
||||||
|
|
||||||
|
private <T> T handleResponse(CommonResponse<T> response, String errorMessage) {
|
||||||
|
if (response == null || !response.isSuccess()) {
|
||||||
|
String msg = response != null && response.getMessage() != null
|
||||||
|
? response.getMessage()
|
||||||
|
: errorMessage;
|
||||||
|
Integer code = response != null ? response.getCode() : 5000;
|
||||||
|
throw new IntegrationException(code, msg, SERVICE_NAME);
|
||||||
|
}
|
||||||
|
return response.getData();
|
||||||
|
}
|
||||||
|
}
|
@@ -12,6 +12,7 @@ import com.ycwl.basic.service.task.TaskFaceService;
|
|||||||
import com.ycwl.basic.task.DynamicTaskGenerator;
|
import com.ycwl.basic.task.DynamicTaskGenerator;
|
||||||
import com.ycwl.basic.integration.common.manager.DeviceConfigManager;
|
import com.ycwl.basic.integration.common.manager.DeviceConfigManager;
|
||||||
// 不再需要SnowFlakeUtil,使用外部传入的ID
|
// 不再需要SnowFlakeUtil,使用外部传入的ID
|
||||||
|
import com.ycwl.basic.utils.JacksonUtil;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||||
@@ -33,7 +34,6 @@ public class FaceProcessingKafkaService {
|
|||||||
|
|
||||||
private static final String ZT_FACE_TOPIC = "zt-face";
|
private static final String ZT_FACE_TOPIC = "zt-face";
|
||||||
|
|
||||||
private final ObjectMapper objectMapper;
|
|
||||||
private final FaceSampleMapper faceSampleMapper;
|
private final FaceSampleMapper faceSampleMapper;
|
||||||
private final TaskFaceService taskFaceService;
|
private final TaskFaceService taskFaceService;
|
||||||
private final ScenicService scenicService;
|
private final ScenicService scenicService;
|
||||||
@@ -43,10 +43,10 @@ public class FaceProcessingKafkaService {
|
|||||||
* 消费外部系统发送的人脸处理消息
|
* 消费外部系统发送的人脸处理消息
|
||||||
* 先保存人脸样本数据,再进行异步人脸识别处理
|
* 先保存人脸样本数据,再进行异步人脸识别处理
|
||||||
*/
|
*/
|
||||||
@KafkaListener(topics = ZT_FACE_TOPIC, groupId = "face-processing-group")
|
@KafkaListener(topics = ZT_FACE_TOPIC)
|
||||||
public void processFaceMessage(String message) {
|
public void processFaceMessage(String message) {
|
||||||
try {
|
try {
|
||||||
FaceProcessingMessage faceMessage = objectMapper.readValue(message, FaceProcessingMessage.class);
|
FaceProcessingMessage faceMessage = JacksonUtil.parseObject(message, FaceProcessingMessage.class);
|
||||||
log.info("接收到外部人脸处理消息, scenicId: {}, deviceId: {}, faceUrl: {}",
|
log.info("接收到外部人脸处理消息, scenicId: {}, deviceId: {}, faceUrl: {}",
|
||||||
faceMessage.getScenicId(), faceMessage.getDeviceId(), faceMessage.getFaceUrl());
|
faceMessage.getScenicId(), faceMessage.getDeviceId(), faceMessage.getFaceUrl());
|
||||||
|
|
||||||
@@ -145,7 +145,7 @@ public class FaceProcessingKafkaService {
|
|||||||
if (addFaceResp != null) {
|
if (addFaceResp != null) {
|
||||||
// 更新人脸样本得分和状态
|
// 更新人脸样本得分和状态
|
||||||
faceSampleMapper.updateScore(faceSampleId, addFaceResp.getScore());
|
faceSampleMapper.updateScore(faceSampleId, addFaceResp.getScore());
|
||||||
updateFaceSampleStatus(faceSampleId, 2); // 成功状态
|
updateFaceSampleStatus(faceSampleId, 2);
|
||||||
log.info("人脸识别处理完成, faceSampleId: {}, score: {}",
|
log.info("人脸识别处理完成, faceSampleId: {}, score: {}",
|
||||||
faceSampleId, addFaceResp.getScore());
|
faceSampleId, addFaceResp.getScore());
|
||||||
|
|
||||||
@@ -176,8 +176,7 @@ public class FaceProcessingKafkaService {
|
|||||||
*/
|
*/
|
||||||
private void updateFaceSampleStatus(Long faceSampleId, Integer status) {
|
private void updateFaceSampleStatus(Long faceSampleId, Integer status) {
|
||||||
try {
|
try {
|
||||||
// TODO: 需要在FaceSampleMapper中添加updateStatus方法
|
faceSampleMapper.updateStatus(faceSampleId, status);
|
||||||
// faceSampleMapper.updateStatus(faceSampleId, status);
|
|
||||||
log.info("人脸样本状态已更新, faceSampleId: {}, status: {} (0:初始,1:处理中,2:成功,-1:失败)", faceSampleId, status);
|
log.info("人脸样本状态已更新, faceSampleId: {}, status: {} (0:初始,1:处理中,2:成功,-1:失败)", faceSampleId, status);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("更新人脸样本状态失败, faceSampleId: {}", faceSampleId, e);
|
log.error("更新人脸样本状态失败, faceSampleId: {}", faceSampleId, e);
|
||||||
|
@@ -29,4 +29,6 @@ public interface FaceSampleMapper {
|
|||||||
List<FaceSampleEntity> listEntityBeforeDate(Long scenicId, Date endDate);
|
List<FaceSampleEntity> listEntityBeforeDate(Long scenicId, Date endDate);
|
||||||
|
|
||||||
void updateScore(Long id, Float score);
|
void updateScore(Long id, Float score);
|
||||||
|
|
||||||
|
void updateStatus(Long id, Integer status);
|
||||||
}
|
}
|
||||||
|
@@ -56,6 +56,12 @@ public interface SourceMapper {
|
|||||||
|
|
||||||
int addRelations(List<MemberSourceEntity> list);
|
int addRelations(List<MemberSourceEntity> list);
|
||||||
|
|
||||||
|
List<MemberSourceEntity> filterExistingRelations(List<MemberSourceEntity> list);
|
||||||
|
|
||||||
|
boolean sourceExists(Long sourceId);
|
||||||
|
|
||||||
|
List<MemberSourceEntity> filterValidSourceRelations(List<MemberSourceEntity> list);
|
||||||
|
|
||||||
int updateRelation(MemberSourceEntity memberSourceEntity);
|
int updateRelation(MemberSourceEntity memberSourceEntity);
|
||||||
int freeRelations(List<Long> ids, int type);
|
int freeRelations(List<Long> ids, int type);
|
||||||
|
|
||||||
|
@@ -69,6 +69,11 @@ public class PriceProductConfig {
|
|||||||
*/
|
*/
|
||||||
private Boolean canUseVoucher;
|
private Boolean canUseVoucher;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否可使用一口价优惠
|
||||||
|
*/
|
||||||
|
private Boolean canUseOnePrice;
|
||||||
|
|
||||||
@TableField("create_time")
|
@TableField("create_time")
|
||||||
private Date createTime;
|
private Date createTime;
|
||||||
|
|
||||||
|
@@ -57,15 +57,15 @@ public interface PriceProductConfigMapper extends BaseMapper<PriceProductConfig>
|
|||||||
/**
|
/**
|
||||||
* 插入商品价格配置
|
* 插入商品价格配置
|
||||||
*/
|
*/
|
||||||
@Insert("INSERT INTO price_product_config (product_type, product_id, scenic_id, product_name, base_price, original_price, unit, is_active, can_use_coupon, can_use_voucher, create_time, update_time) " +
|
@Insert("INSERT INTO price_product_config (product_type, product_id, scenic_id, product_name, base_price, original_price, unit, is_active, can_use_coupon, can_use_voucher, can_use_one_price, create_time, update_time) " +
|
||||||
"VALUES (#{productType}, #{productId}, #{scenicId}, #{productName}, #{basePrice}, #{originalPrice}, #{unit}, #{isActive}, #{canUseCoupon}, #{canUseVoucher}, NOW(), NOW())")
|
"VALUES (#{productType}, #{productId}, #{scenicId}, #{productName}, #{basePrice}, #{originalPrice}, #{unit}, #{isActive}, #{canUseCoupon}, #{canUseVoucher}, #{canUseOnePrice}, NOW(), NOW())")
|
||||||
int insertProductConfig(PriceProductConfig config);
|
int insertProductConfig(PriceProductConfig config);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 更新商品价格配置
|
* 更新商品价格配置
|
||||||
*/
|
*/
|
||||||
@Update("UPDATE price_product_config SET product_id = #{productId}, scenic_id = #{scenicId}, product_name = #{productName}, base_price = #{basePrice}, " +
|
@Update("UPDATE price_product_config SET product_id = #{productId}, scenic_id = #{scenicId}, product_name = #{productName}, base_price = #{basePrice}, " +
|
||||||
"original_price = #{originalPrice}, unit = #{unit}, is_active = #{isActive}, can_use_coupon = #{canUseCoupon}, can_use_voucher = #{canUseVoucher}, update_time = NOW() WHERE id = #{id}")
|
"original_price = #{originalPrice}, unit = #{unit}, is_active = #{isActive}, can_use_coupon = #{canUseCoupon}, can_use_voucher = #{canUseVoucher}, can_use_one_price = #{canUseOnePrice}, update_time = NOW() WHERE id = #{id}")
|
||||||
int updateProductConfig(PriceProductConfig config);
|
int updateProductConfig(PriceProductConfig config);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -4,8 +4,11 @@ import com.ycwl.basic.pricing.dto.DiscountDetectionContext;
|
|||||||
import com.ycwl.basic.pricing.dto.DiscountInfo;
|
import com.ycwl.basic.pricing.dto.DiscountInfo;
|
||||||
import com.ycwl.basic.pricing.dto.DiscountResult;
|
import com.ycwl.basic.pricing.dto.DiscountResult;
|
||||||
import com.ycwl.basic.pricing.dto.OnePriceInfo;
|
import com.ycwl.basic.pricing.dto.OnePriceInfo;
|
||||||
|
import com.ycwl.basic.pricing.dto.ProductItem;
|
||||||
|
import com.ycwl.basic.pricing.entity.PriceProductConfig;
|
||||||
import com.ycwl.basic.pricing.service.IDiscountProvider;
|
import com.ycwl.basic.pricing.service.IDiscountProvider;
|
||||||
import com.ycwl.basic.pricing.service.IOnePricePurchaseService;
|
import com.ycwl.basic.pricing.service.IOnePricePurchaseService;
|
||||||
|
import com.ycwl.basic.pricing.service.IProductConfigService;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
@@ -23,6 +26,7 @@ import java.util.List;
|
|||||||
public class OnePricePurchaseDiscountProvider implements IDiscountProvider {
|
public class OnePricePurchaseDiscountProvider implements IDiscountProvider {
|
||||||
|
|
||||||
private final IOnePricePurchaseService onePricePurchaseService;
|
private final IOnePricePurchaseService onePricePurchaseService;
|
||||||
|
private final IProductConfigService productConfigService;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getProviderType() {
|
public String getProviderType() {
|
||||||
@@ -50,6 +54,12 @@ public class OnePricePurchaseDiscountProvider implements IDiscountProvider {
|
|||||||
return discounts;
|
return discounts;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 检查商品是否支持一口价优惠
|
||||||
|
if (!areAllProductsSupportOnePrice(context.getProducts())) {
|
||||||
|
log.debug("存在不支持一口价优惠的商品,跳过一口价检测");
|
||||||
|
return discounts;
|
||||||
|
}
|
||||||
|
|
||||||
// 获取一口价信息
|
// 获取一口价信息
|
||||||
OnePriceInfo onePriceInfo = onePricePurchaseService.getOnePriceInfo(
|
OnePriceInfo onePriceInfo = onePricePurchaseService.getOnePriceInfo(
|
||||||
context.getScenicId(), context.getCurrentAmount());
|
context.getScenicId(), context.getCurrentAmount());
|
||||||
@@ -170,6 +180,54 @@ public class OnePricePurchaseDiscountProvider implements IDiscountProvider {
|
|||||||
return BigDecimal.ZERO;
|
return BigDecimal.ZERO;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查购物车中的所有商品是否都支持一口价优惠
|
||||||
|
*/
|
||||||
|
private boolean areAllProductsSupportOnePrice(List<ProductItem> products) {
|
||||||
|
if (products == null || products.isEmpty()) {
|
||||||
|
return true; // 空购物车时默认支持
|
||||||
|
}
|
||||||
|
|
||||||
|
for (ProductItem product : products) {
|
||||||
|
try {
|
||||||
|
// 查询商品配置
|
||||||
|
PriceProductConfig productConfig = productConfigService.getProductConfig(
|
||||||
|
product.getProductType().getCode(), product.getProductId());
|
||||||
|
|
||||||
|
if (productConfig != null) {
|
||||||
|
// 检查商品是否支持一口价优惠
|
||||||
|
if (Boolean.FALSE.equals(productConfig.getCanUseOnePrice())) {
|
||||||
|
log.debug("商品 {}({}) 不支持一口价优惠",
|
||||||
|
product.getProductType().getCode(), product.getProductId());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 如果找不到具体商品配置,尝试查询 default 配置
|
||||||
|
PriceProductConfig defaultConfig = productConfigService.getProductConfig(
|
||||||
|
product.getProductType().getCode(), "default");
|
||||||
|
|
||||||
|
if (defaultConfig != null) {
|
||||||
|
if (Boolean.FALSE.equals(defaultConfig.getCanUseOnePrice())) {
|
||||||
|
log.debug("商品类型 {} 的默认配置不支持一口价优惠",
|
||||||
|
product.getProductType().getCode());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 如果既没有具体配置也没有默认配置,默认支持一口价优惠
|
||||||
|
log.debug("商品 {}({}) 未找到价格配置,默认支持一口价优惠",
|
||||||
|
product.getProductType().getCode(), product.getProductId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.warn("检查商品 {}({}) 一口价优惠支持情况时发生异常,默认支持",
|
||||||
|
product.getProductType().getCode(), product.getProductId(), e);
|
||||||
|
// 异常情况下默认支持,避免影响正常业务流程
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 检查优惠叠加规则
|
* 检查优惠叠加规则
|
||||||
*/
|
*/
|
||||||
|
@@ -7,7 +7,9 @@ import com.ycwl.basic.model.pc.device.entity.DeviceConfigEntity;
|
|||||||
import com.ycwl.basic.model.pc.device.entity.DeviceEntity;
|
import com.ycwl.basic.model.pc.device.entity.DeviceEntity;
|
||||||
import com.ycwl.basic.utils.SnowFlakeUtil;
|
import com.ycwl.basic.utils.SnowFlakeUtil;
|
||||||
import com.ycwl.basic.integration.device.service.DeviceIntegrationService;
|
import com.ycwl.basic.integration.device.service.DeviceIntegrationService;
|
||||||
|
import com.ycwl.basic.integration.device.service.DeviceStatusIntegrationService;
|
||||||
import com.ycwl.basic.integration.device.dto.device.DeviceV2DTO;
|
import com.ycwl.basic.integration.device.dto.device.DeviceV2DTO;
|
||||||
|
import com.ycwl.basic.integration.device.dto.status.DeviceStatusDTO;
|
||||||
import com.ycwl.basic.integration.common.manager.DeviceConfigManager;
|
import com.ycwl.basic.integration.common.manager.DeviceConfigManager;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.data.redis.core.RedisTemplate;
|
import org.springframework.data.redis.core.RedisTemplate;
|
||||||
@@ -33,6 +35,8 @@ public class DeviceRepository {
|
|||||||
public static final String DEVICE_CACHE_KEY = "device:%s";
|
public static final String DEVICE_CACHE_KEY = "device:%s";
|
||||||
@Autowired
|
@Autowired
|
||||||
private DeviceConfigIntegrationService deviceConfigIntegrationService;
|
private DeviceConfigIntegrationService deviceConfigIntegrationService;
|
||||||
|
@Autowired
|
||||||
|
private DeviceStatusIntegrationService deviceStatusIntegrationService;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 将DeviceV2DTO转换为DeviceEntity
|
* 将DeviceV2DTO转换为DeviceEntity
|
||||||
@@ -57,6 +61,30 @@ public class DeviceRepository {
|
|||||||
return entity;
|
return entity;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将DeviceV2DTO和DeviceStatusDTO合并转换为DeviceEntity
|
||||||
|
*/
|
||||||
|
private DeviceEntity convertToEntityWithStatus(DeviceV2DTO deviceDto, DeviceStatusDTO statusDto) {
|
||||||
|
if (deviceDto == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
DeviceEntity entity = convertToEntity(deviceDto);
|
||||||
|
|
||||||
|
// 合并状态信息
|
||||||
|
if (statusDto != null) {
|
||||||
|
// Boolean转Integer: true→1, false→0
|
||||||
|
entity.setOnline(statusDto.getIsOnline() != null && statusDto.getIsOnline() ? 1 : 0);
|
||||||
|
entity.setKeepaliveAt(statusDto.getLastActiveTime());
|
||||||
|
entity.setIpAddr(statusDto.getClientIP());
|
||||||
|
} else {
|
||||||
|
// 默认离线状态
|
||||||
|
entity.setOnline(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return entity;
|
||||||
|
}
|
||||||
|
|
||||||
public DeviceEntity getDevice(Long deviceId) {
|
public DeviceEntity getDevice(Long deviceId) {
|
||||||
log.debug("获取设备信息, deviceId: {}", deviceId);
|
log.debug("获取设备信息, deviceId: {}", deviceId);
|
||||||
DeviceV2DTO deviceDto = deviceIntegrationService.getDevice(deviceId);
|
DeviceV2DTO deviceDto = deviceIntegrationService.getDevice(deviceId);
|
||||||
@@ -144,10 +172,31 @@ public class DeviceRepository {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public DeviceEntity getOnlineStatus(Long deviceId) {
|
public DeviceEntity getOnlineStatus(Long deviceId) {
|
||||||
if (redisTemplate.hasKey(String.format(DEVICE_ONLINE_CACHE_KEY, deviceId))) {
|
log.debug("获取设备在线状态, deviceId: {}", deviceId);
|
||||||
return JacksonUtil.parseObject(redisTemplate.opsForValue().get(String.format(DEVICE_ONLINE_CACHE_KEY, deviceId)), DeviceEntity.class);
|
try {
|
||||||
} else {
|
// 首先获取设备基本信息
|
||||||
return null;
|
DeviceV2DTO deviceDto = deviceIntegrationService.getDevice(deviceId);
|
||||||
|
if (deviceDto == null) {
|
||||||
|
log.warn("设备不存在, deviceId: {}", deviceId);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 通过设备编号获取设备状态
|
||||||
|
DeviceStatusDTO statusDto = deviceStatusIntegrationService.getDeviceStatus(deviceDto.getNo());
|
||||||
|
|
||||||
|
// 合并设备信息和状态信息
|
||||||
|
return convertToEntityWithStatus(deviceDto, statusDto);
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("获取设备在线状态异常, deviceId: {}", deviceId, e);
|
||||||
|
// 降级处理:尝试仅返回设备基本信息
|
||||||
|
try {
|
||||||
|
DeviceV2DTO deviceDto = deviceIntegrationService.getDevice(deviceId);
|
||||||
|
return convertToEntityWithStatus(deviceDto, null);
|
||||||
|
} catch (Exception fallbackException) {
|
||||||
|
log.error("降级获取设备信息也失败, deviceId: {}", deviceId, fallbackException);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -343,8 +343,16 @@ public class FaceServiceImpl implements FaceService {
|
|||||||
handleVideoRecreation(scenicConfig, memberSourceEntityList, faceId,
|
handleVideoRecreation(scenicConfig, memberSourceEntityList, faceId,
|
||||||
face.getMemberId(), sampleListIds, isNew);
|
face.getMemberId(), sampleListIds, isNew);
|
||||||
|
|
||||||
// 保存关联关系并创建任务
|
// 过滤已存在的关联关系和无效的source引用,防止数据不一致
|
||||||
sourceMapper.addRelations(memberSourceEntityList);
|
List<MemberSourceEntity> existingFiltered = sourceMapper.filterExistingRelations(memberSourceEntityList);
|
||||||
|
List<MemberSourceEntity> validFiltered = sourceMapper.filterValidSourceRelations(existingFiltered);
|
||||||
|
if (!validFiltered.isEmpty()) {
|
||||||
|
sourceMapper.addRelations(validFiltered);
|
||||||
|
log.debug("创建关联关系: faceId={}, 原始数量={}, 过滤后数量={}",
|
||||||
|
faceId, memberSourceEntityList.size(), validFiltered.size());
|
||||||
|
} else {
|
||||||
|
log.warn("没有有效的关联关系可创建: faceId={}, 原始数量={}", faceId, memberSourceEntityList.size());
|
||||||
|
}
|
||||||
memberRelationRepository.clearSCacheByFace(faceId);
|
memberRelationRepository.clearSCacheByFace(faceId);
|
||||||
taskTaskService.autoCreateTaskByFaceId(faceId);
|
taskTaskService.autoCreateTaskByFaceId(faceId);
|
||||||
|
|
||||||
@@ -1115,7 +1123,16 @@ public class FaceServiceImpl implements FaceService {
|
|||||||
handleVideoRecreation(scenicConfig, memberSourceEntityList, faceId,
|
handleVideoRecreation(scenicConfig, memberSourceEntityList, faceId,
|
||||||
face.getMemberId(), sampleListIds, false);
|
face.getMemberId(), sampleListIds, false);
|
||||||
|
|
||||||
sourceMapper.addRelations(memberSourceEntityList);
|
// 过滤已存在的关联关系和无效的source引用,防止数据不一致
|
||||||
|
List<MemberSourceEntity> existingFiltered = sourceMapper.filterExistingRelations(memberSourceEntityList);
|
||||||
|
List<MemberSourceEntity> validFiltered = sourceMapper.filterValidSourceRelations(existingFiltered);
|
||||||
|
if (!validFiltered.isEmpty()) {
|
||||||
|
sourceMapper.addRelations(validFiltered);
|
||||||
|
log.debug("创建关联关系: faceId={}, 原始数量={}, 过滤后数量={}",
|
||||||
|
faceId, memberSourceEntityList.size(), validFiltered.size());
|
||||||
|
} else {
|
||||||
|
log.warn("没有有效的关联关系可创建: faceId={}, 原始数量={}", faceId, memberSourceEntityList.size());
|
||||||
|
}
|
||||||
memberRelationRepository.clearSCacheByFace(faceId);
|
memberRelationRepository.clearSCacheByFace(faceId);
|
||||||
taskTaskService.autoCreateTaskByFaceId(faceId);
|
taskTaskService.autoCreateTaskByFaceId(faceId);
|
||||||
|
|
||||||
|
@@ -153,7 +153,16 @@ public class TaskFaceServiceImpl implements TaskFaceService {
|
|||||||
memberSourceEntity.setIsBuy(0);
|
memberSourceEntity.setIsBuy(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
sourceMapper.addRelations(memberSourceEntityList);
|
// 过滤已存在的关联关系和无效的source引用,防止数据不一致
|
||||||
|
List<MemberSourceEntity> existingFiltered = sourceMapper.filterExistingRelations(memberSourceEntityList);
|
||||||
|
List<MemberSourceEntity> validFiltered = sourceMapper.filterValidSourceRelations(existingFiltered);
|
||||||
|
if (!validFiltered.isEmpty()) {
|
||||||
|
sourceMapper.addRelations(validFiltered);
|
||||||
|
log.debug("创建关联关系: faceId={}, 原始数量={}, 过滤后数量={}",
|
||||||
|
faceId, memberSourceEntityList.size(), validFiltered.size());
|
||||||
|
} else {
|
||||||
|
log.warn("没有有效的关联关系可创建: faceId={}, 原始数量={}", faceId, memberSourceEntityList.size());
|
||||||
|
}
|
||||||
memberRelationRepository.clearSCacheByFace(faceId);
|
memberRelationRepository.clearSCacheByFace(faceId);
|
||||||
VideoPieceGetter.Task task = new VideoPieceGetter.Task();
|
VideoPieceGetter.Task task = new VideoPieceGetter.Task();
|
||||||
task.faceId = faceEntity.getId();
|
task.faceId = faceEntity.getId();
|
||||||
|
@@ -333,7 +333,14 @@ public class VideoPieceGetter {
|
|||||||
sourceEntity.setScenicId(deviceV2.getScenicId());
|
sourceEntity.setScenicId(deviceV2.getScenicId());
|
||||||
sourceEntity.setDeviceId(deviceId);
|
sourceEntity.setDeviceId(deviceId);
|
||||||
sourceEntity.setType(1);
|
sourceEntity.setType(1);
|
||||||
|
|
||||||
|
// 先插入source记录
|
||||||
|
sourceMapper.add(sourceEntity);
|
||||||
|
videoReUploader.addTask(sourceEntity.getId());
|
||||||
|
|
||||||
|
// 然后处理关联关系
|
||||||
if (task.memberId != null && task.faceId != null) {
|
if (task.memberId != null && task.faceId != null) {
|
||||||
|
List<MemberSourceEntity> memberSourceEntities = memberRelationRepository.listSourceByFaceRelation(task.faceId, 1);
|
||||||
MemberSourceEntity videoSource = new MemberSourceEntity();
|
MemberSourceEntity videoSource = new MemberSourceEntity();
|
||||||
videoSource.setMemberId(task.getMemberId());
|
videoSource.setMemberId(task.getMemberId());
|
||||||
videoSource.setType(1);
|
videoSource.setType(1);
|
||||||
@@ -348,11 +355,17 @@ public class VideoPieceGetter {
|
|||||||
} else {
|
} else {
|
||||||
videoSource.setIsBuy(0);
|
videoSource.setIsBuy(0);
|
||||||
}
|
}
|
||||||
sourceMapper.addRelation(videoSource);
|
boolean anyMatch = memberSourceEntities.stream().anyMatch(memberSourceEntity -> {
|
||||||
|
return memberSourceEntity.getSourceId().equals(videoSource.getSourceId())
|
||||||
|
&& memberSourceEntity.getType().equals(videoSource.getType())
|
||||||
|
&& memberSourceEntity.getFaceId().equals(videoSource.getFaceId());
|
||||||
|
});
|
||||||
|
if (!anyMatch) {
|
||||||
|
// source已插入,可以直接添加关联关系
|
||||||
|
sourceMapper.addRelation(videoSource);
|
||||||
|
}
|
||||||
memberRelationRepository.clearSCacheByFace(task.faceId);
|
memberRelationRepository.clearSCacheByFace(task.faceId);
|
||||||
}
|
}
|
||||||
sourceMapper.add(sourceEntity);
|
|
||||||
videoReUploader.addTask(sourceEntity.getId());
|
|
||||||
} else {
|
} else {
|
||||||
source.setVideoUrl(url);
|
source.setVideoUrl(url);
|
||||||
if (StringUtils.isNotBlank(config.getString("video_crop"))) {
|
if (StringUtils.isNotBlank(config.getString("video_crop"))) {
|
||||||
@@ -362,29 +375,35 @@ public class VideoPieceGetter {
|
|||||||
videoReUploader.addTask(source.getId());
|
videoReUploader.addTask(source.getId());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// 有原视频
|
// 有原视频,source已存在,可以直接添加关联关系
|
||||||
if (task.memberId != null && task.faceId != null) {
|
if (task.memberId != null && task.faceId != null) {
|
||||||
int count = sourceMapper.hasRelationTo(task.getMemberId(), source.getId(), 1);
|
List<MemberSourceEntity> memberSourceEntities = memberRelationRepository.listSourceByFaceRelation(task.faceId, 1);
|
||||||
if (count <= 0) {
|
IsBuyRespVO isBuy = orderBiz.isBuy(task.getMemberId(), deviceV2.getScenicId(), 1, task.getFaceId());
|
||||||
// 没有关联
|
MemberSourceEntity videoSource = new MemberSourceEntity();
|
||||||
IsBuyRespVO isBuy = orderBiz.isBuy(task.getMemberId(), deviceV2.getScenicId(), 1, task.getFaceId());
|
videoSource.setId(SnowFlakeUtil.getLongId());
|
||||||
MemberSourceEntity videoSource = new MemberSourceEntity();
|
videoSource.setScenicId(deviceV2.getScenicId());
|
||||||
videoSource.setId(SnowFlakeUtil.getLongId());
|
videoSource.setFaceId(task.getFaceId());
|
||||||
videoSource.setScenicId(deviceV2.getScenicId());
|
videoSource.setMemberId(task.getMemberId());
|
||||||
videoSource.setFaceId(task.getFaceId());
|
videoSource.setType(1);
|
||||||
videoSource.setMemberId(task.getMemberId());
|
if (isBuy.isBuy()) { // 如果用户买过
|
||||||
videoSource.setType(1);
|
videoSource.setIsBuy(1);
|
||||||
if (isBuy.isBuy()) { // 如果用户买过
|
} else if (isBuy.isFree()) { // 全免费逻辑
|
||||||
videoSource.setIsBuy(1);
|
videoSource.setIsBuy(1);
|
||||||
} else if (isBuy.isFree()) { // 全免费逻辑
|
} else {
|
||||||
videoSource.setIsBuy(1);
|
videoSource.setIsBuy(0);
|
||||||
} else {
|
|
||||||
videoSource.setIsBuy(0);
|
|
||||||
}
|
|
||||||
videoSource.setSourceId(source.getId());
|
|
||||||
sourceMapper.addRelation(videoSource);
|
|
||||||
memberRelationRepository.clearSCacheByFace(task.faceId);
|
|
||||||
}
|
}
|
||||||
|
videoSource.setSourceId(source.getId());
|
||||||
|
// 没有关联
|
||||||
|
boolean anyMatch = memberSourceEntities.stream().anyMatch(memberSourceEntity -> {
|
||||||
|
return memberSourceEntity.getSourceId().equals(videoSource.getSourceId())
|
||||||
|
&& memberSourceEntity.getType().equals(videoSource.getType())
|
||||||
|
&& memberSourceEntity.getFaceId().equals(videoSource.getFaceId());
|
||||||
|
});
|
||||||
|
if (!anyMatch) {
|
||||||
|
// source已存在,可以直接添加关联关系
|
||||||
|
sourceMapper.addRelation(videoSource);
|
||||||
|
}
|
||||||
|
memberRelationRepository.clearSCacheByFace(task.faceId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
@@ -41,6 +41,11 @@
|
|||||||
set score = #{score}
|
set score = #{score}
|
||||||
where id = #{id}
|
where id = #{id}
|
||||||
</update>
|
</update>
|
||||||
|
<update id="updateStatus">
|
||||||
|
update face_sample
|
||||||
|
set `status` = #{status}
|
||||||
|
where id = #{id}
|
||||||
|
</update>
|
||||||
<delete id="deleteById">
|
<delete id="deleteById">
|
||||||
delete from face_sample where id = #{id}
|
delete from face_sample where id = #{id}
|
||||||
</delete>
|
</delete>
|
||||||
|
@@ -16,6 +16,105 @@
|
|||||||
(#{item.scenicId}, #{item.faceId}, #{item.memberId}, #{item.sourceId}, #{item.isBuy}, #{item.type}, #{item.orderId}, #{item.isFree})
|
(#{item.scenicId}, #{item.faceId}, #{item.memberId}, #{item.sourceId}, #{item.isBuy}, #{item.type}, #{item.orderId}, #{item.isFree})
|
||||||
</foreach>
|
</foreach>
|
||||||
</insert>
|
</insert>
|
||||||
|
<select id="filterExistingRelations" resultType="com.ycwl.basic.model.pc.source.entity.MemberSourceEntity">
|
||||||
|
<choose>
|
||||||
|
<when test="list != null and list.size() > 0">
|
||||||
|
SELECT
|
||||||
|
r.memberId as memberId,
|
||||||
|
r.sourceId as sourceId,
|
||||||
|
r.type as type,
|
||||||
|
r.faceId as faceId,
|
||||||
|
r.scenicId as scenicId,
|
||||||
|
r.isBuy as isBuy,
|
||||||
|
r.orderId as orderId,
|
||||||
|
r.isFree as isFree,
|
||||||
|
r.id as id
|
||||||
|
FROM (
|
||||||
|
<foreach collection="list" item="item" separator=" UNION ALL ">
|
||||||
|
SELECT
|
||||||
|
#{item.memberId} as memberId,
|
||||||
|
#{item.sourceId} as sourceId,
|
||||||
|
#{item.type} as type,
|
||||||
|
#{item.faceId} as faceId,
|
||||||
|
#{item.scenicId} as scenicId,
|
||||||
|
#{item.isBuy} as isBuy,
|
||||||
|
#{item.orderId} as orderId,
|
||||||
|
#{item.isFree} as isFree,
|
||||||
|
#{item.id} as id
|
||||||
|
</foreach>
|
||||||
|
) r
|
||||||
|
WHERE NOT EXISTS (
|
||||||
|
SELECT 1 FROM member_source ms
|
||||||
|
WHERE ms.member_id = r.memberId
|
||||||
|
AND ms.source_id = r.sourceId
|
||||||
|
AND ms.type = r.type
|
||||||
|
AND ms.face_id = r.faceId
|
||||||
|
)
|
||||||
|
</when>
|
||||||
|
<otherwise>
|
||||||
|
SELECT
|
||||||
|
NULL as memberId,
|
||||||
|
NULL as sourceId,
|
||||||
|
NULL as type,
|
||||||
|
NULL as faceId,
|
||||||
|
NULL as scenicId,
|
||||||
|
NULL as isBuy,
|
||||||
|
NULL as orderId,
|
||||||
|
NULL as isFree,
|
||||||
|
NULL as id
|
||||||
|
WHERE 1 = 0
|
||||||
|
</otherwise>
|
||||||
|
</choose>
|
||||||
|
</select>
|
||||||
|
<select id="sourceExists" resultType="boolean">
|
||||||
|
SELECT COUNT(1) > 0 FROM source WHERE id = #{sourceId}
|
||||||
|
</select>
|
||||||
|
<select id="filterValidSourceRelations" resultType="com.ycwl.basic.model.pc.source.entity.MemberSourceEntity">
|
||||||
|
<choose>
|
||||||
|
<when test="list != null and list.size() > 0">
|
||||||
|
SELECT
|
||||||
|
r.memberId as memberId,
|
||||||
|
r.sourceId as sourceId,
|
||||||
|
r.type as type,
|
||||||
|
r.faceId as faceId,
|
||||||
|
r.scenicId as scenicId,
|
||||||
|
r.isBuy as isBuy,
|
||||||
|
r.orderId as orderId,
|
||||||
|
r.isFree as isFree,
|
||||||
|
r.id as id
|
||||||
|
FROM (
|
||||||
|
<foreach collection="list" item="item" separator=" UNION ALL ">
|
||||||
|
SELECT
|
||||||
|
#{item.memberId} as memberId,
|
||||||
|
#{item.sourceId} as sourceId,
|
||||||
|
#{item.type} as type,
|
||||||
|
#{item.faceId} as faceId,
|
||||||
|
#{item.scenicId} as scenicId,
|
||||||
|
#{item.isBuy} as isBuy,
|
||||||
|
#{item.orderId} as orderId,
|
||||||
|
#{item.isFree} as isFree,
|
||||||
|
#{item.id} as id
|
||||||
|
</foreach>
|
||||||
|
) r
|
||||||
|
WHERE EXISTS (
|
||||||
|
SELECT 1 FROM source s WHERE s.id = r.sourceId
|
||||||
|
)
|
||||||
|
</when>
|
||||||
|
<otherwise>
|
||||||
|
SELECT
|
||||||
|
NULL as memberId,
|
||||||
|
NULL as sourceId,
|
||||||
|
NULL as type,
|
||||||
|
NULL as faceId,
|
||||||
|
NULL as scenicId,
|
||||||
|
NULL as isBuy,
|
||||||
|
NULL as orderId,
|
||||||
|
NULL as isFree,
|
||||||
|
NULL as id
|
||||||
|
WHERE 1 = 0
|
||||||
|
</otherwise>
|
||||||
|
</choose>
|
||||||
|
</select>
|
||||||
<insert id="addSourceWatermark">
|
<insert id="addSourceWatermark">
|
||||||
insert source_watermark(source_id, face_id, watermark_type, watermark_url)
|
insert source_watermark(source_id, face_id, watermark_type, watermark_url)
|
||||||
values (#{sourceId}, #{faceId}, #{type}, #{url})
|
values (#{sourceId}, #{faceId}, #{type}, #{url})
|
||||||
|
Reference in New Issue
Block a user