提交昨晚更新改动
This commit is contained in:
+17
-8
@@ -111,19 +111,28 @@ public class PriceTrackController {
|
||||
@GetMapping("/tasks/{taskId}/skip-asins/paginated")
|
||||
@Operation(
|
||||
summary = "分页查询任务的跳过 ASIN 数据",
|
||||
description = "根据任务 ID 分页拉取该任务关联的 ASIN 数据。"
|
||||
+ "全量模式:从 biz_skip_price_asin 表查询;"
|
||||
+ "文件模式:从任务 requestJson 中存储的上传文件数据查询。"
|
||||
+ "国家代码从任务的 requestJson.countryCodes 中获取。"
|
||||
description = "根据任务编号分页拉取该任务关联的 ASIN 数据。"
|
||||
+ "全量模式:按任务店铺和国家从跳过跟价库查询;"
|
||||
+ "文件模式:从任务保存的上传文件解析数据查询。"
|
||||
+ "未传国家过滤条件时,默认使用任务创建时选择的国家。"
|
||||
)
|
||||
public ApiResponse<SkipPriceAsinPageVo> getTaskSkipAsinsPaginated(
|
||||
@Parameter(description = "任务 ID", required = true, example = "200")
|
||||
@Parameter(description = "任务编号", required = true, example = "200")
|
||||
@PathVariable Long taskId,
|
||||
@Parameter(description = "页码,从 1 开始", example = "1")
|
||||
@RequestParam(value = "page", defaultValue = "1") Integer page,
|
||||
@Parameter(description = "每页条数,默认 1000,最大 2000", example = "1000")
|
||||
@RequestParam(value = "page_size", defaultValue = "1000") Integer pageSize) {
|
||||
return ApiResponse.success(priceTrackTaskService.getTaskSkipAsinsPaginated(taskId, page, pageSize));
|
||||
@RequestParam(value = "page_size", defaultValue = "1000") Integer pageSize,
|
||||
@Parameter(description = "店铺名称过滤条件,可重复传入,也可用英文逗号分隔;仅在任务关联店铺范围内生效", example = "测试店铺A")
|
||||
@RequestParam(value = "shop_name", required = false) List<String> shopNames,
|
||||
@Parameter(description = "国家代码过滤条件,可重复传入,也可用英文逗号分隔;仅在任务国家范围内生效", example = "DE")
|
||||
@RequestParam(value = "country_code", required = false) List<String> countryCodes) {
|
||||
return ApiResponse.success(priceTrackTaskService.getTaskSkipAsinsPaginated(
|
||||
taskId,
|
||||
page,
|
||||
pageSize,
|
||||
shopNames,
|
||||
countryCodes));
|
||||
}
|
||||
|
||||
@GetMapping("/tasks/{taskId}/skip-asin/check")
|
||||
@@ -251,7 +260,7 @@ public class PriceTrackController {
|
||||
+ "未完成/处理中:本次只传增量行数据,shop.success 不传或传 null,后端仅合并缓存继续等待。"
|
||||
+ "已完成:传最后一批数据并设置 shop.success=true,后端会使用该店铺累计后的完整数据出结果。"
|
||||
+ "失败:传 shop.success=false 或传非空 shop.error。"
|
||||
+ "行级数据只保留表头字段:shopMallName、asin、price、recommendedPrice、shippingFee、minimumPrice、firstPlace、secondPlace、cartShopName、priceChangeStatus、modifyCount、status。"
|
||||
+ "行级数据只保留表头字段:shopMallName、asin、price、recommendedPrice、shippingFee、minimumPrice、firstPlace、firstShop、secondPlace、secondShop、cartShopName、priceChangeStatus、modifyCount、status。"
|
||||
)
|
||||
public ApiResponse<Void> submitResult(
|
||||
@Parameter(
|
||||
|
||||
+8
@@ -83,9 +83,17 @@ public class PriceTrackSubmitResultRequest {
|
||||
@Schema(description = "第一名", example = "竞对A")
|
||||
private String firstPlace;
|
||||
|
||||
@JsonAlias({"first_shop", "firstPlaceShop", "first_place_shop", "第一名店铺名"})
|
||||
@Schema(description = "第一名店铺名", example = "店铺A")
|
||||
private String firstShop;
|
||||
|
||||
@Schema(description = "第二名", example = "竞对B")
|
||||
private String secondPlace;
|
||||
|
||||
@JsonAlias({"second_shop", "secondPlaceShop", "second_place_shop", "第二名店铺名"})
|
||||
@Schema(description = "第二名店铺名", example = "店铺B")
|
||||
private String secondShop;
|
||||
|
||||
@Schema(description = "购物车店铺名", example = "店铺A")
|
||||
private String cartShopName;
|
||||
|
||||
|
||||
+13
-13
@@ -9,47 +9,47 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Price-track skipped ASIN page response.
|
||||
* 跟价任务跳过 ASIN 分页响应。
|
||||
*/
|
||||
@Data
|
||||
@Schema(description = "Price-track skipped ASIN page response")
|
||||
@Schema(description = "跟价任务跳过 ASIN 分页响应")
|
||||
public class SkipPriceAsinPageVo {
|
||||
|
||||
@Schema(description = "Current page, starting from 1")
|
||||
@Schema(description = "当前页码,从 1 开始")
|
||||
private Integer page;
|
||||
|
||||
@Schema(description = "Page size")
|
||||
@Schema(description = "每页条数")
|
||||
private Integer pageSize;
|
||||
|
||||
@Schema(description = "Total records")
|
||||
@Schema(description = "总记录数")
|
||||
private Long total;
|
||||
|
||||
@Schema(description = "Total pages")
|
||||
@Schema(description = "总页数")
|
||||
private Integer totalPages;
|
||||
|
||||
@Schema(description = "ASIN list grouped by country")
|
||||
@Schema(description = "按国家分组的 ASIN 列表")
|
||||
private Map<String, List<String>> skipAsinsByCountry = new LinkedHashMap<>();
|
||||
|
||||
@Schema(description = "ASIN detail list grouped by country, including asin and minimumPrice")
|
||||
@Schema(description = "按国家分组的 ASIN 明细列表,包含 ASIN 和最低价")
|
||||
private Map<String, List<Map<String, String>>> skipAsinDetailsByCountry = new LinkedHashMap<>();
|
||||
|
||||
@JsonProperty("skip_asins")
|
||||
@Schema(description = "Legacy Python queue field: ASIN list grouped by country")
|
||||
@Schema(description = "兼容旧版队列字段:按国家分组的 ASIN 列表")
|
||||
private Map<String, List<String>> skipAsins = new LinkedHashMap<>();
|
||||
|
||||
@JsonProperty("skip_asins_by_country")
|
||||
@Schema(description = "Legacy Python queue field: ASIN list grouped by country")
|
||||
@Schema(description = "兼容旧版队列字段:按国家分组的 ASIN 列表")
|
||||
private Map<String, List<String>> skipAsinsByCountryLegacy = new LinkedHashMap<>();
|
||||
|
||||
@JsonProperty("skip_asin_details_by_country")
|
||||
@Schema(description = "Legacy Python queue field: ASIN detail list grouped by country")
|
||||
@Schema(description = "兼容旧版队列字段:按国家分组的 ASIN 明细列表")
|
||||
private Map<String, List<Map<String, String>>> skipAsinDetailsByCountryLegacy = new LinkedHashMap<>();
|
||||
|
||||
@JsonProperty("asin_rows_by_country")
|
||||
@Schema(description = "Legacy Python queue field: appointed ASIN rows grouped by country")
|
||||
@Schema(description = "兼容旧版队列字段:按国家分组的指定 ASIN 文件行数据")
|
||||
private Map<String, List<Map<String, String>>> asinRowsByCountry = new LinkedHashMap<>();
|
||||
|
||||
@JsonProperty("minimum_price_by_country_and_asin")
|
||||
@Schema(description = "Legacy Python queue field: minimum price map grouped by country and ASIN")
|
||||
@Schema(description = "兼容旧版队列字段:按国家和 ASIN 分组的最低价映射")
|
||||
private Map<String, Map<String, String>> minimumPriceByCountryAndAsin = new LinkedHashMap<>();
|
||||
}
|
||||
|
||||
+11
-7
@@ -27,7 +27,9 @@ public class PriceTrackExcelAssemblyService {
|
||||
"运费",
|
||||
"最低价",
|
||||
"第一名",
|
||||
"第一名店铺名",
|
||||
"第二名",
|
||||
"第二名店铺名",
|
||||
"购物车店铺名",
|
||||
"改价价格",
|
||||
"改价情况",
|
||||
@@ -62,12 +64,14 @@ public class PriceTrackExcelAssemblyService {
|
||||
row.createCell(4).setCellValue(valueOf(item.getShippingFee()));
|
||||
row.createCell(5).setCellValue(valueOf(item.getMinimumPrice()));
|
||||
row.createCell(6).setCellValue(valueOf(item.getFirstPlace()));
|
||||
row.createCell(7).setCellValue(valueOf(item.getSecondPlace()));
|
||||
row.createCell(8).setCellValue(valueOf(item.getCartShopName()));
|
||||
row.createCell(9).setCellValue(valueOf(item.getPriceChangePrice()));
|
||||
row.createCell(10).setCellValue(valueOf(item.getPriceChangeStatus()));
|
||||
row.createCell(11).setCellValue(valueOf(item.getModifyCount()));
|
||||
row.createCell(12).setCellValue(valueOf(item.getStatus()));
|
||||
row.createCell(7).setCellValue(valueOf(item.getFirstShop()));
|
||||
row.createCell(8).setCellValue(valueOf(item.getSecondPlace()));
|
||||
row.createCell(9).setCellValue(valueOf(item.getSecondShop()));
|
||||
row.createCell(10).setCellValue(valueOf(item.getCartShopName()));
|
||||
row.createCell(11).setCellValue(valueOf(item.getPriceChangePrice()));
|
||||
row.createCell(12).setCellValue(valueOf(item.getPriceChangeStatus()));
|
||||
row.createCell(13).setCellValue(valueOf(item.getModifyCount()));
|
||||
row.createCell(14).setCellValue(valueOf(item.getStatus()));
|
||||
}
|
||||
applyDefaultColumnWidths(sheet);
|
||||
}
|
||||
@@ -127,7 +131,7 @@ public class PriceTrackExcelAssemblyService {
|
||||
}
|
||||
|
||||
private void applyDefaultColumnWidths(Sheet sheet) {
|
||||
int[] widths = {22, 18, 12, 12, 12, 12, 20, 20, 22, 14, 18, 12, 12};
|
||||
int[] widths = {22, 18, 12, 12, 12, 12, 20, 22, 20, 22, 22, 14, 18, 12, 12};
|
||||
for (int i = 0; i < widths.length; i++) {
|
||||
sheet.setColumnWidth(i, widths[i] * 256);
|
||||
}
|
||||
|
||||
+123
-4
@@ -48,6 +48,7 @@ import java.time.LocalDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
@@ -816,6 +817,11 @@ public class PriceTrackTaskService {
|
||||
*/
|
||||
public com.nanri.aiimage.modules.pricetrack.model.vo.SkipPriceAsinPageVo getTaskSkipAsinsPaginated(
|
||||
Long taskId, int page, int pageSize) {
|
||||
return getTaskSkipAsinsPaginated(taskId, page, pageSize, List.of(), List.of());
|
||||
}
|
||||
|
||||
public com.nanri.aiimage.modules.pricetrack.model.vo.SkipPriceAsinPageVo getTaskSkipAsinsPaginated(
|
||||
Long taskId, int page, int pageSize, List<String> requestedShopNames, List<String> requestedCountryCodes) {
|
||||
if (taskId == null || taskId <= 0) {
|
||||
throw new BusinessException("taskId 不合法");
|
||||
}
|
||||
@@ -827,8 +833,10 @@ public class PriceTrackTaskService {
|
||||
|
||||
PriceTrackCreateTaskRequest request = parseTaskRequest(task);
|
||||
|
||||
// Resolve country codes from task request.
|
||||
List<String> countryCodes = request.getCountryCodes();
|
||||
List<String> countryCodes = resolveSkipAsinCountryCodes(request, requestedCountryCodes);
|
||||
if (countryCodes.isEmpty()) {
|
||||
return emptySkipAsinPage(List.of(), page, pageSize);
|
||||
}
|
||||
|
||||
// Choose full mode or uploaded-ASIN file mode.
|
||||
boolean isAsinMode = request.isAsinMode();
|
||||
@@ -841,11 +849,116 @@ public class PriceTrackTaskService {
|
||||
// File mode reads parsed uploaded ASIN rows.
|
||||
return getTaskAsinFilePaginated(request, countryCodes, page, pageSize);
|
||||
} else {
|
||||
// Full mode uses all ASINs and minimum prices from biz_skip_price_asin.
|
||||
return skipPriceAsinService.listSkipAsinsPaginated(List.of(), countryCodes, page, pageSize);
|
||||
List<String> shopNames = resolveSkipAsinShopNames(request, requestedShopNames);
|
||||
if (shopNames.isEmpty()) {
|
||||
return emptySkipAsinPage(countryCodes, page, pageSize);
|
||||
}
|
||||
return skipPriceAsinService.listSkipAsinsPaginated(shopNames, countryCodes, page, pageSize);
|
||||
}
|
||||
}
|
||||
|
||||
private List<String> resolveSkipAsinCountryCodes(PriceTrackCreateTaskRequest request, List<String> requestedCountryCodes) {
|
||||
List<String> taskCountryCodes = normalizeTaskCountryCodes(request == null ? null : request.getCountryCodes());
|
||||
LinkedHashSet<String> requested = new LinkedHashSet<>();
|
||||
for (String country : splitQueryValues(requestedCountryCodes)) {
|
||||
requested.add(normalizeLookupCountry(country));
|
||||
}
|
||||
if (requested.isEmpty()) {
|
||||
return taskCountryCodes;
|
||||
}
|
||||
List<String> result = new ArrayList<>();
|
||||
for (String country : requested) {
|
||||
if (isTaskCountryEnabled(taskCountryCodes, country)) {
|
||||
result.add(country);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private List<String> normalizeTaskCountryCodes(List<String> countryCodes) {
|
||||
LinkedHashSet<String> normalized = new LinkedHashSet<>();
|
||||
if (countryCodes != null) {
|
||||
for (String country : countryCodes) {
|
||||
String value = country == null ? "" : country.trim().toUpperCase(Locale.ROOT);
|
||||
if (!value.isEmpty()) {
|
||||
normalized.add(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
return new ArrayList<>(normalized);
|
||||
}
|
||||
|
||||
private List<String> resolveSkipAsinShopNames(PriceTrackCreateTaskRequest request, List<String> requestedShopNames) {
|
||||
List<String> taskShopNames = resolveTaskShopNames(request);
|
||||
List<String> requested = splitQueryValues(requestedShopNames);
|
||||
LinkedHashSet<String> normalized = new LinkedHashSet<>();
|
||||
for (String shopName : requested) {
|
||||
String value = ziniaoShopSwitchService.normalizeShopName(shopName);
|
||||
if (!value.isBlank() && (taskShopNames.isEmpty() || taskShopNames.contains(value))) {
|
||||
normalized.add(value);
|
||||
}
|
||||
}
|
||||
if (!normalized.isEmpty()) {
|
||||
return new ArrayList<>(normalized);
|
||||
}
|
||||
if (!requested.isEmpty()) {
|
||||
return List.of();
|
||||
}
|
||||
return taskShopNames;
|
||||
}
|
||||
|
||||
private List<String> splitQueryValues(List<String> values) {
|
||||
List<String> result = new ArrayList<>();
|
||||
if (values == null) {
|
||||
return result;
|
||||
}
|
||||
for (String value : values) {
|
||||
if (value == null) {
|
||||
continue;
|
||||
}
|
||||
for (String part : value.split(",")) {
|
||||
String trimmed = part.trim();
|
||||
if (!trimmed.isEmpty()) {
|
||||
result.add(trimmed);
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private com.nanri.aiimage.modules.pricetrack.model.vo.SkipPriceAsinPageVo emptySkipAsinPage(
|
||||
List<String> countryCodes, int page, int pageSize) {
|
||||
if (page < 1) {
|
||||
page = 1;
|
||||
}
|
||||
if (pageSize < 1 || pageSize > 2000) {
|
||||
pageSize = 1000;
|
||||
}
|
||||
List<String> targetCountries = (countryCodes == null || countryCodes.isEmpty())
|
||||
? List.of("DE", "UK", "FR", "IT", "ES")
|
||||
: countryCodes;
|
||||
Map<String, List<String>> skipAsinsByCountry = new LinkedHashMap<>();
|
||||
Map<String, List<Map<String, String>>> skipDetailsByCountry = new LinkedHashMap<>();
|
||||
for (String country : targetCountries) {
|
||||
skipAsinsByCountry.put(country, new ArrayList<>());
|
||||
skipDetailsByCountry.put(country, new ArrayList<>());
|
||||
}
|
||||
com.nanri.aiimage.modules.pricetrack.model.vo.SkipPriceAsinPageVo vo =
|
||||
new com.nanri.aiimage.modules.pricetrack.model.vo.SkipPriceAsinPageVo();
|
||||
vo.setPage(page);
|
||||
vo.setPageSize(pageSize);
|
||||
vo.setTotal(0L);
|
||||
vo.setTotalPages(0);
|
||||
vo.setSkipAsinsByCountry(skipAsinsByCountry);
|
||||
vo.setSkipAsinDetailsByCountry(skipDetailsByCountry);
|
||||
vo.setSkipAsins(skipAsinsByCountry);
|
||||
vo.setSkipAsinsByCountryLegacy(skipAsinsByCountry);
|
||||
vo.setSkipAsinDetailsByCountryLegacy(skipDetailsByCountry);
|
||||
vo.setAsinRowsByCountry(new LinkedHashMap<>());
|
||||
vo.setMinimumPriceByCountryAndAsin(new LinkedHashMap<>());
|
||||
return vo;
|
||||
}
|
||||
|
||||
private List<String> resolveTaskShopNames(PriceTrackCreateTaskRequest request) {
|
||||
List<String> shopNames = new ArrayList<>();
|
||||
if (request == null || request.getItems() == null) {
|
||||
@@ -1391,7 +1504,9 @@ public class PriceTrackTaskService {
|
||||
case "推荐价", "recommendedprice" -> "recommendedPrice";
|
||||
case "最低价", "minimumprice" -> "minimumPrice";
|
||||
case "第一名", "firstplace" -> "firstPlace";
|
||||
case "第一名店铺名", "firstshop", "firstplaceshop" -> "firstShop";
|
||||
case "第二名", "secondplace" -> "secondPlace";
|
||||
case "第二名店铺名", "secondshop", "secondplaceshop" -> "secondShop";
|
||||
case "购物车店铺名", "cartshopname" -> "cartShopName";
|
||||
case "改价情况", "pricechangestatus" -> "priceChangeStatus";
|
||||
case "修改次数", "modifycount" -> "modifyCount";
|
||||
@@ -1661,7 +1776,9 @@ public class PriceTrackTaskService {
|
||||
merged.setShippingFee(firstNonBlank(incoming.getShippingFee(), merged.getShippingFee()));
|
||||
merged.setMinimumPrice(firstNonBlank(incoming.getMinimumPrice(), merged.getMinimumPrice()));
|
||||
merged.setFirstPlace(firstNonBlank(incoming.getFirstPlace(), merged.getFirstPlace()));
|
||||
merged.setFirstShop(firstNonBlank(incoming.getFirstShop(), merged.getFirstShop()));
|
||||
merged.setSecondPlace(firstNonBlank(incoming.getSecondPlace(), merged.getSecondPlace()));
|
||||
merged.setSecondShop(firstNonBlank(incoming.getSecondShop(), merged.getSecondShop()));
|
||||
merged.setCartShopName(firstNonBlank(incoming.getCartShopName(), merged.getCartShopName()));
|
||||
merged.setPriceChangePrice(firstNonBlank(incoming.getPriceChangePrice(), merged.getPriceChangePrice()));
|
||||
merged.setPriceChangeStatus(firstNonBlank(incoming.getPriceChangeStatus(), merged.getPriceChangeStatus()));
|
||||
@@ -1686,7 +1803,9 @@ public class PriceTrackTaskService {
|
||||
out.setShippingFee(row.getShippingFee());
|
||||
out.setMinimumPrice(row.getMinimumPrice());
|
||||
out.setFirstPlace(row.getFirstPlace());
|
||||
out.setFirstShop(row.getFirstShop());
|
||||
out.setSecondPlace(row.getSecondPlace());
|
||||
out.setSecondShop(row.getSecondShop());
|
||||
out.setCartShopName(row.getCartShopName());
|
||||
out.setPriceChangePrice(row.getPriceChangePrice());
|
||||
out.setPriceChangeStatus(row.getPriceChangeStatus());
|
||||
|
||||
Reference in New Issue
Block a user