后端优化修复问题

This commit is contained in:
super
2026-06-18 18:53:16 +08:00
parent 021b0c618b
commit 0ecf5cd45a
44 changed files with 4275 additions and 81 deletions
@@ -20,6 +20,7 @@ import com.nanri.aiimage.modules.pricetrack.model.vo.PriceTrackLoopRunVo;
import com.nanri.aiimage.modules.pricetrack.model.vo.PriceTrackMatchShopsVo;
import com.nanri.aiimage.modules.pricetrack.model.vo.PriceTrackPendingDeleteVo;
import com.nanri.aiimage.modules.pricetrack.model.vo.PriceTrackTaskBatchVo;
import com.nanri.aiimage.modules.pricetrack.model.vo.SkipPriceAsinCheckVo;
import com.nanri.aiimage.modules.pricetrack.model.vo.SkipPriceAsinPageVo;
import com.nanri.aiimage.modules.pricetrack.service.PriceTrackLoopRunService;
import com.nanri.aiimage.modules.pricetrack.service.PriceTrackService;
@@ -125,6 +126,21 @@ public class PriceTrackController {
return ApiResponse.success(priceTrackTaskService.getTaskSkipAsinsPaginated(taskId, page, pageSize));
}
@GetMapping("/tasks/{taskId}/skip-asin/check")
@Operation(
summary = "检查单个跳过跟价 ASIN",
description = "Python 按国家和单个 ASIN 查询是否命中跳过跟价库,避免分页加载全量跳过 ASIN。"
)
public ApiResponse<SkipPriceAsinCheckVo> checkTaskSkipAsin(
@Parameter(description = "任务 ID", required = true, example = "200")
@PathVariable Long taskId,
@Parameter(description = "国家代码", required = true, example = "DE")
@RequestParam("country") String country,
@Parameter(description = "ASIN", required = true, example = "B0XXXX")
@RequestParam("asin") String asin) {
return ApiResponse.success(priceTrackTaskService.checkTaskSkipAsin(taskId, country, asin));
}
@GetMapping("/dashboard")
@Operation(summary = "统计看板", description = "返回备选店铺数、已结束任务数、成功任务数和失败任务数。")
public ApiResponse<PriceTrackDashboardVo> dashboard(
@@ -0,0 +1,21 @@
package com.nanri.aiimage.modules.pricetrack.model.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
@Data
@Schema(description = "single skip price asin lookup response")
public class SkipPriceAsinCheckVo {
@Schema(description = "country code", example = "DE")
private String country;
@Schema(description = "normalized asin", example = "B0XXXX")
private String asin;
@Schema(description = "whether the asin exists in skip price asin table")
private boolean exists;
@Schema(description = "configured minimum price, empty when not configured or not found")
private String minimumPrice;
}
@@ -21,6 +21,8 @@ import com.nanri.aiimage.modules.pricetrack.model.vo.PriceTrackResultItemVo;
import com.nanri.aiimage.modules.pricetrack.model.vo.PriceTrackTaskBatchVo;
import com.nanri.aiimage.modules.pricetrack.model.vo.PriceTrackTaskDetailVo;
import com.nanri.aiimage.modules.pricetrack.model.vo.PriceTrackTaskItemVo;
import com.nanri.aiimage.modules.pricetrack.model.vo.SkipPriceAsinCheckVo;
import com.nanri.aiimage.modules.shopkey.model.dto.SkipPriceAsinDetailDto;
import com.nanri.aiimage.modules.shopkey.service.SkipPriceAsinService;
import com.nanri.aiimage.modules.task.mapper.FileResultMapper;
import com.nanri.aiimage.modules.task.mapper.FileTaskMapper;
@@ -367,18 +369,10 @@ public class PriceTrackTaskService {
}
}
// 汇总店铺名并查询需要跳过的 ASIN
Map<String, List<String>> skipAsinsByCountry = request.isAsinMode()
? new LinkedHashMap<>()
: skipPriceAsinService.listAllSkipAsinsByCountry();
Map<String, List<Map<String, String>>> skipAsinDetailsByCountry = request.isAsinMode()
? new LinkedHashMap<>()
: skipPriceAsinService.listAllSkipAsinDetailsByCountry();
Map<String, List<Map<String, String>>> asinRowsByCountry = request.isAsinMode()
? parseAsinRowsByCountry(request.getAsinFiles(), request.getCountryCodes())
: new LinkedHashMap<>();
Map<String, Map<String, String>> minimumPriceByCountryAndAsin =
buildMinimumPriceByCountryAndAsin(asinRowsByCountry);
Map<String, List<String>> skipAsinsByCountry = new LinkedHashMap<>();
Map<String, List<Map<String, String>>> skipAsinDetailsByCountry = new LinkedHashMap<>();
Map<String, List<Map<String, String>>> asinRowsByCountry = new LinkedHashMap<>();
Map<String, Map<String, String>> minimumPriceByCountryAndAsin = new LinkedHashMap<>();
log.info("[price-track] createTask skipAsins countries={} asinMode={}",
skipAsinsByCountry.keySet(), request.isAsinMode());
@@ -788,16 +782,7 @@ public class PriceTrackTaskService {
throw new BusinessException("任务不存在");
}
// 解析任务请求参数
PriceTrackCreateTaskRequest request;
try {
if (task.getRequestJson() == null || task.getRequestJson().isBlank()) {
throw new BusinessException("任务请求参数为空");
}
request = objectMapper.readValue(task.getRequestJson(), PriceTrackCreateTaskRequest.class);
} catch (Exception e) {
throw new BusinessException("任务请求参数解析失败: " + e.getMessage());
}
PriceTrackCreateTaskRequest request = parseTaskRequest(task);
// 从任务中获取国家代码
List<String> countryCodes = request.getCountryCodes();
@@ -814,6 +799,78 @@ public class PriceTrackTaskService {
}
}
public SkipPriceAsinCheckVo checkTaskSkipAsin(Long taskId, String country, String asin) {
if (taskId == null || taskId <= 0) {
throw new BusinessException("taskId 不合法");
}
String normalizedCountry = normalizeLookupCountry(country);
String normalizedAsin = normalizeLookupAsin(asin);
FileTaskEntity task = loadTaskForExecution(taskId);
if (task == null || !MODULE_TYPE.equals(task.getModuleType())) {
throw new BusinessException("任务不存在");
}
PriceTrackCreateTaskRequest request = parseTaskRequest(task);
SkipPriceAsinCheckVo vo = new SkipPriceAsinCheckVo();
vo.setCountry(normalizedCountry);
vo.setAsin(normalizedAsin);
vo.setExists(false);
vo.setMinimumPrice("");
if (request.isAsinMode() || !isTaskCountryEnabled(request.getCountryCodes(), normalizedCountry)) {
return vo;
}
SkipPriceAsinDetailDto detail = skipPriceAsinService.findSkipAsinByCountryAndAsin(normalizedCountry, normalizedAsin);
if (detail != null) {
vo.setExists(true);
vo.setMinimumPrice(detail.getMinimumPrice() == null ? "" : detail.getMinimumPrice());
}
return vo;
}
private PriceTrackCreateTaskRequest parseTaskRequest(FileTaskEntity task) {
try {
if (task.getRequestJson() == null || task.getRequestJson().isBlank()) {
throw new BusinessException("任务请求参数为空");
}
return objectMapper.readValue(task.getRequestJson(), PriceTrackCreateTaskRequest.class);
} catch (BusinessException ex) {
throw ex;
} catch (Exception ex) {
throw new BusinessException("任务请求参数解析失败: " + ex.getMessage());
}
}
private boolean isTaskCountryEnabled(List<String> countryCodes, String country) {
if (countryCodes == null || countryCodes.isEmpty()) {
return true;
}
return countryCodes.stream()
.filter(Objects::nonNull)
.map(code -> code.trim().toUpperCase(Locale.ROOT))
.anyMatch(country::equals);
}
private String normalizeLookupCountry(String country) {
String normalized = country == null ? "" : country.trim().toUpperCase(Locale.ROOT);
if (!List.of("DE", "UK", "FR", "IT", "ES").contains(normalized)) {
throw new BusinessException("国家参数不支持: " + country);
}
return normalized;
}
private String normalizeLookupAsin(String asin) {
String normalized = asin == null ? "" : asin.trim().toUpperCase(Locale.ROOT);
if (normalized.isEmpty()) {
throw new BusinessException("ASIN 不能为空");
}
if (normalized.length() > 64) {
throw new BusinessException("ASIN 长度不能超过 64");
}
return normalized;
}
/**
* 文件模式:从任务上传的文件中分页返回 ASIN 数据
*/