优化后台业务
This commit is contained in:
@@ -25,8 +25,19 @@
|
||||
<hutool.version>5.8.36</hutool.version>
|
||||
<rocketmq-spring.version>2.3.5</rocketmq-spring.version>
|
||||
<minio.version>8.5.17</minio.version>
|
||||
<javassist.version>3.28.0-GA</javassist.version>
|
||||
</properties>
|
||||
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.javassist</groupId>
|
||||
<artifactId>javassist</artifactId>
|
||||
<version>${javassist.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
|
||||
@@ -649,7 +649,7 @@ public class AppearancePatentCozeClient {
|
||||
}
|
||||
|
||||
private String normalize(String value) {
|
||||
return value == null ? "" : value.replace("\ufeff", "").replace("\u3000", " ").trim();
|
||||
return value == null ? "" : value.replace(String.valueOf((char) 0xFEFF), "").replace((char) 0x3000, ' ').trim();
|
||||
}
|
||||
|
||||
private String rowKey(AppearancePatentResultRowDto row) {
|
||||
|
||||
@@ -83,7 +83,10 @@ public class AppearancePatentController {
|
||||
public ApiResponse<Void> result(
|
||||
@Parameter(description = "外观专利检测任务 ID。任务必须处于 RUNNING 状态。", required = true, example = "3938")
|
||||
@PathVariable Long taskId,
|
||||
@Valid @RequestBody AppearancePatentSubmitResultRequest request) {
|
||||
@Valid @RequestBody AppearancePatentSubmitResultRequest request,
|
||||
jakarta.servlet.http.HttpServletResponse response) {
|
||||
response.setCharacterEncoding(StandardCharsets.UTF_8.name());
|
||||
response.setContentType("application/json;charset=UTF-8");
|
||||
service.submitResult(taskId, request);
|
||||
return ApiResponse.success(null);
|
||||
}
|
||||
|
||||
@@ -121,7 +121,7 @@ public class AppearancePatentTaskService {
|
||||
.filter(Objects::nonNull)
|
||||
.toList();
|
||||
if (sourceFiles.isEmpty()) {
|
||||
throw new BusinessException("璇峰厛涓婁紶 Excel 鏂囦欢");
|
||||
throw new BusinessException("请先上传 Excel 文件");
|
||||
}
|
||||
List<AppearancePatentParsedRowVo> allRows = new ArrayList<>();
|
||||
List<String> mergedHeaders = new ArrayList<>();
|
||||
@@ -461,10 +461,10 @@ public class AppearancePatentTaskService {
|
||||
private SubmitContext persistSubmittedChunk(Long taskId, AppearancePatentSubmitResultRequest request) {
|
||||
FileTaskEntity task = fileTaskMapper.selectById(taskId);
|
||||
if (task == null || !MODULE_TYPE.equals(task.getModuleType())) {
|
||||
throw new BusinessException("浠诲姟涓嶅瓨鍦?");
|
||||
throw new BusinessException("任务不存在");
|
||||
}
|
||||
if (!STATUS_RUNNING.equals(task.getStatus())) {
|
||||
throw new BusinessException("浠诲姟涓嶆槸杩愯涓姸鎬?");
|
||||
throw new BusinessException("任务不是运行中状态");
|
||||
}
|
||||
|
||||
int chunkIndex = request.getChunkIndex() == null ? 0 : request.getChunkIndex();
|
||||
@@ -482,7 +482,7 @@ public class AppearancePatentTaskService {
|
||||
.last("limit 1"));
|
||||
if (existing == null) {
|
||||
List<AppearancePatentResultRowDto> rawRows = flattenSubmittedRows(request);
|
||||
String payloadJson = writeJson(rawRows, "缁撴灉搴忓垪鍖栧け璐?");
|
||||
String payloadJson = writeJson(rawRows, "结果序列化失败");
|
||||
|
||||
TaskChunkEntity chunk = new TaskChunkEntity();
|
||||
chunk.setTaskId(taskId);
|
||||
@@ -514,7 +514,7 @@ public class AppearancePatentTaskService {
|
||||
private void completeSubmittedChunk(SubmitContext context) {
|
||||
FileTaskEntity task = fileTaskMapper.selectById(context.task().getId());
|
||||
if (task == null || !MODULE_TYPE.equals(task.getModuleType())) {
|
||||
throw new BusinessException("浠诲姟涓嶅瓨鍦?");
|
||||
throw new BusinessException("任务不存在");
|
||||
}
|
||||
if (!STATUS_RUNNING.equals(task.getStatus())) {
|
||||
log.info("[appearance-patent] skip completion because task already finalized taskId={} status={}",
|
||||
@@ -1379,7 +1379,7 @@ public class AppearancePatentTaskService {
|
||||
}
|
||||
|
||||
private String normalize(String val) {
|
||||
return val == null ? "" : val.replace("\ufeff", "").replace("\u3000", " ").trim().replaceAll("\\s+", " ");
|
||||
return val == null ? "" : val.replace(String.valueOf((char) 0xFEFF), "").replace((char) 0x3000, ' ').trim().replaceAll("\\s+", " ");
|
||||
}
|
||||
|
||||
private String buildParsedPayloadJson(String aiPrompt, List<AppearancePatentSourceFileDto> sourceFiles, List<String> headers, List<AppearancePatentParsedGroupVo> groups, List<AppearancePatentParsedRowVo> allRows) {
|
||||
|
||||
@@ -881,8 +881,8 @@ public class BrandTaskService {
|
||||
if (value == null) {
|
||||
return "";
|
||||
}
|
||||
return value.replace("\ufeff", "")
|
||||
.replace("\u3000", " ")
|
||||
return value.replace(String.valueOf((char) 0xFEFF), "")
|
||||
.replace((char) 0x3000, ' ')
|
||||
.replace("\r\n", " ")
|
||||
.replace("\r", " ")
|
||||
.replace("\n", " ")
|
||||
|
||||
@@ -475,8 +475,8 @@ public class ConvertRunService {
|
||||
if (value == null) {
|
||||
return "";
|
||||
}
|
||||
return value.replace("\ufeff", "")
|
||||
.replace("\u3000", " ")
|
||||
return value.replace(String.valueOf((char) 0xFEFF), "")
|
||||
.replace((char) 0x3000, ' ')
|
||||
.replace("\r\n", " ")
|
||||
.replace("\r", " ")
|
||||
.replace("\n", " ")
|
||||
|
||||
@@ -47,8 +47,8 @@ import java.util.zip.ZipOutputStream;
|
||||
@Slf4j
|
||||
public class DedupeRunService {
|
||||
|
||||
private static final String HEADER_SPLIT_MARKER = "idASIN\u56fd\u5bb6\u72b6\u6001\u4ef7\u683c\u53d8\u4f53\u6570\u91cf";
|
||||
private static final String HEADER_STOP_COLUMN = "\u7f29\u7565\u56fe\u5730\u57408";
|
||||
private static final String HEADER_SPLIT_MARKER = "idASIN国家状态价格变体数量";
|
||||
private static final String HEADER_STOP_COLUMN = "缩略图地址8";
|
||||
|
||||
private final FileTaskMapper fileTaskMapper;
|
||||
private final FileResultMapper fileResultMapper;
|
||||
@@ -59,7 +59,7 @@ public class DedupeRunService {
|
||||
public DedupeRunVo run(DedupeRunRequest request) {
|
||||
long runStartNs = System.nanoTime();
|
||||
if (!request.isKeepIntegerIds() && !request.isKeepUnderscoreIds() && !request.isKeepIntegerMainIdsWhenNoSubIds()) {
|
||||
throw new BusinessException("\u8bf7\u81f3\u5c11\u9009\u62e9\u4e00\u79cd ID \u4fdd\u7559\u89c4\u5219");
|
||||
throw new BusinessException("请至少选择一种 ID 保留规则");
|
||||
}
|
||||
|
||||
FileTaskEntity task = new FileTaskEntity();
|
||||
@@ -90,7 +90,7 @@ public class DedupeRunService {
|
||||
File inputFile = findLocalSourceFile(sourceFile.getFileKey());
|
||||
long findFileNs = elapsedNs(fileStartNs);
|
||||
if (inputFile == null || !inputFile.exists()) {
|
||||
throw new BusinessException("\u4e0a\u4f20\u6587\u4ef6\u4e0d\u5b58\u5728\uff0c\u8bf7\u91cd\u65b0\u4e0a\u4f20");
|
||||
throw new BusinessException("上传文件不存在,请重新上传");
|
||||
}
|
||||
|
||||
String inputName = sourceFile.getOriginalFilename() == null ? inputFile.getName() : sourceFile.getOriginalFilename();
|
||||
@@ -240,7 +240,7 @@ public class DedupeRunService {
|
||||
public void deleteHistory(Long resultId, Long userId) {
|
||||
FileResultEntity entity = fileResultMapper.selectById(resultId);
|
||||
if (entity == null || !"DEDUPE".equals(entity.getModuleType()) || !userId.equals(entity.getUserId())) {
|
||||
throw new BusinessException("\u8bb0\u5f55\u4e0d\u5b58\u5728");
|
||||
throw new BusinessException("记录不存在");
|
||||
}
|
||||
fileResultMapper.deleteById(resultId);
|
||||
}
|
||||
@@ -248,11 +248,11 @@ public class DedupeRunService {
|
||||
public Resource getResultFile(Long resultId, Long userId) {
|
||||
FileResultEntity entity = fileResultMapper.selectById(resultId);
|
||||
if (entity == null || entity.getResultFileUrl() == null || !"DEDUPE".equals(entity.getModuleType()) || !userId.equals(entity.getUserId())) {
|
||||
throw new BusinessException("\u7ed3\u679c\u6587\u4ef6\u4e0d\u5b58\u5728");
|
||||
throw new BusinessException("结果文件不存在");
|
||||
}
|
||||
File file = new File(entity.getResultFileUrl());
|
||||
if (!file.exists()) {
|
||||
throw new BusinessException("\u7ed3\u679c\u6587\u4ef6\u4e0d\u5b58\u5728");
|
||||
throw new BusinessException("结果文件不存在");
|
||||
}
|
||||
return new FileSystemResource(file);
|
||||
}
|
||||
@@ -342,18 +342,18 @@ public class DedupeRunService {
|
||||
Sheet sheet = workbook.getSheetAt(0);
|
||||
Row headerRow = sheet.getRow(0);
|
||||
if (headerRow == null) {
|
||||
throw new BusinessException("Excel \u8868\u5934\u4e3a\u7a7a");
|
||||
throw new BusinessException("Excel 表头为空");
|
||||
}
|
||||
|
||||
Map<String, Integer> headerMap = buildHeaderMap(headerRow, formatter);
|
||||
if (headerMap.isEmpty()) {
|
||||
throw new BusinessException("Excel \u8868\u5934\u4e3a\u7a7a");
|
||||
throw new BusinessException("Excel 表头为空");
|
||||
}
|
||||
List<String> missing = selectedColumns.stream()
|
||||
.filter(column -> !headerMap.containsKey(column))
|
||||
.toList();
|
||||
if (!missing.isEmpty()) {
|
||||
throw new BusinessException("\u7f3a\u5c11\u5217\uff1a" + String.join("\u3001", missing));
|
||||
throw new BusinessException("缺少列:" + String.join("、", missing));
|
||||
}
|
||||
|
||||
List<Integer> selectedIndexes = new ArrayList<>(selectedColumns.size());
|
||||
@@ -478,7 +478,7 @@ public class DedupeRunService {
|
||||
zos.closeEntry();
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
throw new BusinessException("\u53bb\u91cd\u7ed3\u679c\u6253\u5305\u5931\u8d25\uff1a" + ex.getMessage());
|
||||
throw new BusinessException("去重结果打包失败:" + ex.getMessage());
|
||||
}
|
||||
return zipFile;
|
||||
}
|
||||
@@ -602,7 +602,7 @@ public class DedupeRunService {
|
||||
boolean previousWhitespace = false;
|
||||
for (int i = start; i < end; i++) {
|
||||
char ch = value.charAt(i);
|
||||
if (ch == '\uFEFF') {
|
||||
if (ch == 0xFEFF) {
|
||||
if (builder == null) {
|
||||
builder = new StringBuilder(value.length());
|
||||
builder.append(value, start, i);
|
||||
@@ -629,11 +629,11 @@ public class DedupeRunService {
|
||||
}
|
||||
|
||||
private boolean isTrimmedWhitespace(char ch) {
|
||||
return ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n' || ch == '\u3000' || Character.isWhitespace(ch);
|
||||
return ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n' || ch == 0x3000 || Character.isWhitespace(ch);
|
||||
}
|
||||
|
||||
private boolean isNormalizedWhitespace(char ch) {
|
||||
return ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n' || ch == '\u3000' || Character.isWhitespace(ch);
|
||||
return ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n' || ch == 0x3000 || Character.isWhitespace(ch);
|
||||
}
|
||||
|
||||
private record DedupeArchiveEntry(String relativePath, String inputName, File outputFile) {
|
||||
|
||||
@@ -109,8 +109,8 @@ public class LocalFileStorageService {
|
||||
if (value == null) {
|
||||
return "";
|
||||
}
|
||||
return value.replace("\ufeff", "")
|
||||
.replace("\u3000", " ")
|
||||
return value.replace(String.valueOf((char) 0xFEFF), "")
|
||||
.replace((char) 0x3000, ' ')
|
||||
.replace("\r\n", " ")
|
||||
.replace("\r", " ")
|
||||
.replace("\n", " ")
|
||||
|
||||
@@ -281,7 +281,6 @@ public class PatrolDeleteTaskService {
|
||||
return vo;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public void submitResult(Long taskId, PatrolDeleteSubmitResultRequest request) {
|
||||
if (taskId == null || taskId <= 0) {
|
||||
throw new BusinessException("taskId 不合法");
|
||||
@@ -334,7 +333,6 @@ public class PatrolDeleteTaskService {
|
||||
tryFinalizeTask(taskId, false);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public boolean tryFinalizeTask(Long taskId, boolean fromCompensation) {
|
||||
if (taskId == null || taskId <= 0) {
|
||||
return false;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.nanri.aiimage.modules.pricetrack.model.dto;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonAlias;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
@@ -88,6 +89,10 @@ public class PriceTrackSubmitResultRequest {
|
||||
@Schema(description = "购物车店铺名", example = "店铺A")
|
||||
private String cartShopName;
|
||||
|
||||
@JsonAlias({"changedPrice", "changePrice", "modifiedPrice", "newPrice", "targetPrice", "updatedPrice", "改价价格"})
|
||||
@Schema(description = "改价价格", example = "18.99")
|
||||
private String priceChangePrice;
|
||||
|
||||
@Schema(description = "改价情况", example = "UPDATED")
|
||||
private String priceChangeStatus;
|
||||
|
||||
|
||||
@@ -29,6 +29,7 @@ public class PriceTrackExcelAssemblyService {
|
||||
"第一名",
|
||||
"第二名",
|
||||
"购物车店铺名",
|
||||
"改价价格",
|
||||
"改价情况",
|
||||
"修改次数",
|
||||
"状态"
|
||||
@@ -40,13 +41,14 @@ public class PriceTrackExcelAssemblyService {
|
||||
workbook.setCompressTempFiles(true);
|
||||
try (FileOutputStream fos = new FileOutputStream(outputXlsx)) {
|
||||
for (ProductRiskCountryCode code : ProductRiskCountryCode.values()) {
|
||||
String sheetName = code.name();
|
||||
String countryCode = code.name();
|
||||
String sheetName = sheetNameOf(code);
|
||||
Sheet sheet = workbook.createSheet(sheetName);
|
||||
Row headerRow = sheet.createRow(0);
|
||||
for (int i = 0; i < RESULT_HEADER.length; i++) {
|
||||
headerRow.createCell(i).setCellValue(RESULT_HEADER[i]);
|
||||
}
|
||||
List<PriceTrackSubmitResultRequest.AsinResult> rows = safe.getOrDefault(sheetName, List.of());
|
||||
List<PriceTrackSubmitResultRequest.AsinResult> rows = safe.getOrDefault(countryCode, List.of());
|
||||
int rowIdx = 1;
|
||||
for (PriceTrackSubmitResultRequest.AsinResult item : rows) {
|
||||
if (item == null) {
|
||||
@@ -62,9 +64,10 @@ public class PriceTrackExcelAssemblyService {
|
||||
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.getPriceChangeStatus()));
|
||||
row.createCell(10).setCellValue(valueOf(item.getModifyCount()));
|
||||
row.createCell(11).setCellValue(valueOf(item.getStatus()));
|
||||
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()));
|
||||
}
|
||||
applyDefaultColumnWidths(sheet);
|
||||
}
|
||||
@@ -113,8 +116,18 @@ public class PriceTrackExcelAssemblyService {
|
||||
return value == null ? "" : value;
|
||||
}
|
||||
|
||||
private static String sheetNameOf(ProductRiskCountryCode code) {
|
||||
return switch (code) {
|
||||
case DE -> "德国";
|
||||
case FR -> "法国";
|
||||
case ES -> "西班牙";
|
||||
case IT -> "意大利";
|
||||
case UK -> "英国";
|
||||
};
|
||||
}
|
||||
|
||||
private void applyDefaultColumnWidths(Sheet sheet) {
|
||||
int[] widths = {22, 18, 12, 12, 12, 12, 20, 20, 22, 18, 12, 12};
|
||||
int[] widths = {22, 18, 12, 12, 12, 12, 20, 20, 22, 14, 18, 12, 12};
|
||||
for (int i = 0; i < widths.length; i++) {
|
||||
sheet.setColumnWidth(i, widths[i] * 256);
|
||||
}
|
||||
|
||||
@@ -127,6 +127,21 @@ public class PriceTrackTaskService {
|
||||
return tasks;
|
||||
}
|
||||
|
||||
private List<FileTaskEntity> selectTaskStatusesByIdsInBatches(List<Long> taskIds) {
|
||||
List<FileTaskEntity> tasks = new ArrayList<>();
|
||||
if (taskIds == null || taskIds.isEmpty()) {
|
||||
return tasks;
|
||||
}
|
||||
int batchSize = Math.max(1, taskPressureProperties.getDbSelectBatchSize());
|
||||
for (int start = 0; start < taskIds.size(); start += batchSize) {
|
||||
int end = Math.min(start + batchSize, taskIds.size());
|
||||
tasks.addAll(fileTaskMapper.selectList(new LambdaQueryWrapper<FileTaskEntity>()
|
||||
.select(FileTaskEntity::getId, FileTaskEntity::getStatus)
|
||||
.in(FileTaskEntity::getId, taskIds.subList(start, end))));
|
||||
}
|
||||
return tasks;
|
||||
}
|
||||
|
||||
public PriceTrackDashboardVo dashboard(Long userId) {
|
||||
if (userId == null || userId <= 0) throw new BusinessException("user_id 不合法");
|
||||
PriceTrackDashboardVo vo = new PriceTrackDashboardVo();
|
||||
@@ -166,7 +181,7 @@ public class PriceTrackTaskService {
|
||||
.distinct()
|
||||
.toList();
|
||||
if (!taskIds.isEmpty()) {
|
||||
List<FileTaskEntity> tasks = selectTasksByIdsInBatches(taskIds);
|
||||
List<FileTaskEntity> tasks = selectTaskStatusesByIdsInBatches(taskIds);
|
||||
for (FileTaskEntity t : tasks) {
|
||||
if (t != null) statusByTaskId.put(t.getId(), t.getStatus());
|
||||
}
|
||||
@@ -383,7 +398,6 @@ public class PriceTrackTaskService {
|
||||
return vo;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public void submitResult(Long taskId, PriceTrackSubmitResultRequest request) {
|
||||
if (taskId == null || taskId <= 0) throw new BusinessException("taskId 不合法");
|
||||
if (request == null || request.getShops() == null || request.getShops().isEmpty()) {
|
||||
@@ -458,7 +472,6 @@ public class PriceTrackTaskService {
|
||||
updateTaskStatusFromLatestRows(task, latest);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public boolean tryFinalizeTask(Long taskId, boolean fromCompensation) {
|
||||
if (taskId == null || taskId <= 0) return false;
|
||||
FileTaskEntity task = loadTaskForExecution(taskId);
|
||||
@@ -1139,6 +1152,7 @@ public class PriceTrackTaskService {
|
||||
merged.setFirstPlace(firstNonBlank(incoming.getFirstPlace(), merged.getFirstPlace()));
|
||||
merged.setSecondPlace(firstNonBlank(incoming.getSecondPlace(), merged.getSecondPlace()));
|
||||
merged.setCartShopName(firstNonBlank(incoming.getCartShopName(), merged.getCartShopName()));
|
||||
merged.setPriceChangePrice(firstNonBlank(incoming.getPriceChangePrice(), merged.getPriceChangePrice()));
|
||||
merged.setPriceChangeStatus(firstNonBlank(incoming.getPriceChangeStatus(), merged.getPriceChangeStatus()));
|
||||
merged.setModifyCount(firstNonBlank(incoming.getModifyCount(), merged.getModifyCount()));
|
||||
merged.setStatus(firstNonBlank(incoming.getStatus(), merged.getStatus()));
|
||||
@@ -1163,6 +1177,7 @@ public class PriceTrackTaskService {
|
||||
out.setFirstPlace(row.getFirstPlace());
|
||||
out.setSecondPlace(row.getSecondPlace());
|
||||
out.setCartShopName(row.getCartShopName());
|
||||
out.setPriceChangePrice(row.getPriceChangePrice());
|
||||
out.setPriceChangeStatus(row.getPriceChangeStatus());
|
||||
out.setModifyCount(row.getModifyCount());
|
||||
out.setStatus(row.getStatus());
|
||||
|
||||
@@ -124,6 +124,21 @@ public class ProductRiskTaskService {
|
||||
return tasks;
|
||||
}
|
||||
|
||||
private List<FileTaskEntity> selectTaskStatusesByIdsInBatches(List<Long> taskIds) {
|
||||
List<FileTaskEntity> tasks = new ArrayList<>();
|
||||
if (taskIds == null || taskIds.isEmpty()) {
|
||||
return tasks;
|
||||
}
|
||||
int batchSize = Math.max(1, taskPressureProperties.getDbSelectBatchSize());
|
||||
for (int start = 0; start < taskIds.size(); start += batchSize) {
|
||||
int end = Math.min(start + batchSize, taskIds.size());
|
||||
tasks.addAll(fileTaskMapper.selectList(new LambdaQueryWrapper<FileTaskEntity>()
|
||||
.select(FileTaskEntity::getId, FileTaskEntity::getStatus)
|
||||
.in(FileTaskEntity::getId, taskIds.subList(start, end))));
|
||||
}
|
||||
return tasks;
|
||||
}
|
||||
|
||||
public ProductRiskDashboardVo dashboard(Long userId) {
|
||||
if (userId == null || userId <= 0) {
|
||||
throw new BusinessException("user_id 不合法");
|
||||
@@ -166,7 +181,7 @@ public class ProductRiskTaskService {
|
||||
.distinct()
|
||||
.toList();
|
||||
if (!taskIds.isEmpty()) {
|
||||
List<FileTaskEntity> tasks = selectTasksByIdsInBatches(taskIds);
|
||||
List<FileTaskEntity> tasks = selectTaskStatusesByIdsInBatches(taskIds);
|
||||
for (FileTaskEntity t : tasks) {
|
||||
if (t != null) {
|
||||
statusByTaskId.put(t.getId(), t.getStatus());
|
||||
@@ -465,7 +480,6 @@ public class ProductRiskTaskService {
|
||||
return vo;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public void submitResult(Long taskId, ProductRiskSubmitResultRequest request) {
|
||||
if (taskId == null || taskId <= 0) {
|
||||
throw new BusinessException("taskId 不合法");
|
||||
@@ -630,7 +644,6 @@ public class ProductRiskTaskService {
|
||||
cleanupTaskCacheIfTerminal(taskId, task.getStatus());
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public boolean tryFinalizeTask(Long taskId, boolean fromCompensation) {
|
||||
if (taskId == null || taskId <= 0) {
|
||||
return false;
|
||||
|
||||
@@ -287,7 +287,6 @@ public class QueryAsinTaskService {
|
||||
return vo;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public void submitResult(Long taskId, QueryAsinSubmitResultRequest request) {
|
||||
if (taskId == null || taskId <= 0) {
|
||||
throw new BusinessException("taskId 不合法");
|
||||
@@ -340,7 +339,6 @@ public class QueryAsinTaskService {
|
||||
tryFinalizeTask(taskId, false);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public boolean tryFinalizeTask(Long taskId, boolean fromCompensation) {
|
||||
if (taskId == null || taskId <= 0) {
|
||||
return false;
|
||||
|
||||
@@ -3,7 +3,68 @@ package com.nanri.aiimage.modules.shopkey.mapper;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.nanri.aiimage.modules.shopkey.model.entity.ShopManageGroupEntity;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import org.apache.ibatis.annotations.Select;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Mapper
|
||||
public interface ShopManageGroupMapper extends BaseMapper<ShopManageGroupEntity> {
|
||||
|
||||
@Select("""
|
||||
SELECT DISTINCT accessible_group_id
|
||||
FROM (
|
||||
SELECT g.id AS accessible_group_id
|
||||
FROM biz_shop_manage_group g
|
||||
WHERE g.created_by_id = #{operatorId}
|
||||
OR g.user_id = #{operatorId}
|
||||
UNION
|
||||
SELECT gm.group_id AS accessible_group_id
|
||||
FROM biz_shop_manage_group_member gm
|
||||
WHERE gm.user_id = #{operatorId}
|
||||
UNION
|
||||
SELECT g2.id AS accessible_group_id
|
||||
FROM biz_shop_manage_group_member gm
|
||||
INNER JOIN biz_shop_manage_group g1 ON g1.id = gm.group_id
|
||||
INNER JOIN biz_shop_manage_group g2
|
||||
ON g2.created_by_id = COALESCE(g1.created_by_id, g1.user_id)
|
||||
OR g2.user_id = COALESCE(g1.created_by_id, g1.user_id)
|
||||
WHERE gm.user_id = #{operatorId}
|
||||
AND COALESCE(g1.created_by_id, g1.user_id) IS NOT NULL
|
||||
UNION
|
||||
SELECT member_groups.id AS accessible_group_id
|
||||
FROM biz_shop_manage_group leader_group
|
||||
INNER JOIN biz_shop_manage_group_member direct_member ON direct_member.group_id = leader_group.id
|
||||
INNER JOIN biz_shop_manage_group member_groups
|
||||
ON member_groups.created_by_id = direct_member.user_id
|
||||
OR member_groups.user_id = direct_member.user_id
|
||||
WHERE leader_group.created_by_id = #{operatorId}
|
||||
OR leader_group.user_id = #{operatorId}
|
||||
) accessible_groups
|
||||
WHERE accessible_group_id IS NOT NULL
|
||||
ORDER BY accessible_group_id ASC
|
||||
""")
|
||||
List<Long> selectAccessibleGroupIds(@Param("operatorId") Long operatorId);
|
||||
|
||||
@Select("""
|
||||
SELECT DISTINCT visible_user_id
|
||||
FROM (
|
||||
SELECT #{operatorId} AS visible_user_id
|
||||
UNION
|
||||
SELECT direct_member.user_id AS visible_user_id
|
||||
FROM biz_shop_manage_group leader_group
|
||||
INNER JOIN biz_shop_manage_group_member direct_member ON direct_member.group_id = leader_group.id
|
||||
WHERE leader_group.created_by_id = #{operatorId}
|
||||
OR leader_group.user_id = #{operatorId}
|
||||
UNION
|
||||
SELECT COALESCE(direct_group.created_by_id, direct_group.user_id) AS visible_user_id
|
||||
FROM biz_shop_manage_group_member membership
|
||||
INNER JOIN biz_shop_manage_group direct_group ON direct_group.id = membership.group_id
|
||||
WHERE membership.user_id = #{operatorId}
|
||||
AND COALESCE(direct_group.created_by_id, direct_group.user_id) IS NOT NULL
|
||||
) visible_users
|
||||
WHERE visible_user_id IS NOT NULL
|
||||
ORDER BY visible_user_id ASC
|
||||
""")
|
||||
List<Long> selectAccessibleCreatorUserIds(@Param("operatorId") Long operatorId);
|
||||
}
|
||||
|
||||
@@ -40,7 +40,7 @@ public class QueryAsinService {
|
||||
|
||||
private static final List<String> SUPPORTED_COUNTRIES = List.of("DE", "UK", "FR", "IT", "ES");
|
||||
private static final String KEY_SEPARATOR = Character.toString((char) 1);
|
||||
private static final String UTF8_BOM = Character.toString(0xFEFF);
|
||||
private static final String UTF8_BOM = String.valueOf((char) 0xFEFF);
|
||||
|
||||
private final QueryAsinMapper queryAsinMapper;
|
||||
private final ShopManageGroupService shopManageGroupService;
|
||||
@@ -79,7 +79,7 @@ public class QueryAsinService {
|
||||
List<QueryAsinEntity> rows = queryAsinMapper
|
||||
.selectList(query.last("LIMIT " + ((safePage - 1) * safePageSize) + ", " + safePageSize));
|
||||
|
||||
Map<Long, String> groupNameById = buildGroupNameMap(rows.stream()
|
||||
Map<Long, String> groupNameById = shopManageGroupService.buildGroupNameMap(rows.stream()
|
||||
.map(QueryAsinEntity::getGroupId)
|
||||
.filter(id -> id != null && id > 0)
|
||||
.distinct()
|
||||
@@ -316,22 +316,6 @@ public class QueryAsinService {
|
||||
return vo;
|
||||
}
|
||||
|
||||
private Map<Long, String> buildGroupNameMap(List<Long> groupIds) {
|
||||
if (groupIds == null || groupIds.isEmpty()) {
|
||||
return Map.of();
|
||||
}
|
||||
LinkedHashMap<Long, String> map = new LinkedHashMap<>();
|
||||
for (Long groupId : groupIds) {
|
||||
try {
|
||||
ShopManageGroupEntity group = shopManageGroupService.getById(groupId);
|
||||
map.put(groupId, group.getGroupName());
|
||||
} catch (Exception ignored) {
|
||||
map.put(groupId, "");
|
||||
}
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
private Set<String> normalizeCountries(List<String> countries) {
|
||||
LinkedHashSet<String> normalized = new LinkedHashSet<>();
|
||||
if (countries != null) {
|
||||
@@ -384,11 +368,11 @@ public class QueryAsinService {
|
||||
return upper;
|
||||
}
|
||||
return switch (normalizeHeaderKey(normalized)) {
|
||||
case "\u5fb7\u56fd", "\u5fb7", "de", "germany", "german", "deutschland" -> "DE";
|
||||
case "\u82f1\u56fd", "\u82f1", "uk", "gb", "greatbritain", "britain", "unitedkingdom" -> "UK";
|
||||
case "\u6cd5\u56fd", "\u6cd5", "fr", "france", "french" -> "FR";
|
||||
case "\u610f\u5927\u5229", "\u610f", "it", "italy", "italian" -> "IT";
|
||||
case "\u897f\u73ed\u7259", "\u897f", "es", "spain", "spanish", "espana" -> "ES";
|
||||
case "德国", "德", "de", "germany", "german", "deutschland" -> "DE";
|
||||
case "英国", "英", "uk", "gb", "greatbritain", "britain", "unitedkingdom" -> "UK";
|
||||
case "法国", "法", "fr", "france", "french" -> "FR";
|
||||
case "意大利", "意", "it", "italy", "italian" -> "IT";
|
||||
case "西班牙", "西", "es", "spain", "spanish", "espana" -> "ES";
|
||||
default -> "";
|
||||
};
|
||||
}
|
||||
@@ -860,11 +844,11 @@ public class QueryAsinService {
|
||||
if (index != null) {
|
||||
return index;
|
||||
}
|
||||
index = firstHeader("groupname", "\u5206\u7ec4id", "\u5206\u7ec4");
|
||||
index = firstHeader("groupname", "分组id", "分组");
|
||||
if (index != null) {
|
||||
return index;
|
||||
}
|
||||
return findHeaderByPredicate(key -> key.contains("\u5206\u7ec4") || key.contains("group"));
|
||||
return findHeaderByPredicate(key -> key.contains("分组") || key.contains("group"));
|
||||
}
|
||||
|
||||
private Integer resolveShopHeaderIndex() {
|
||||
@@ -873,13 +857,13 @@ public class QueryAsinService {
|
||||
return index;
|
||||
}
|
||||
index = firstHeader(
|
||||
"\u5e97\u94fa\u540d", "\u5e97\u94fa\u540d\u79f0", "\u5e97\u94fa\u8d26\u53f7", "\u8d26\u53f7",
|
||||
"店铺名", "店铺名称", "店铺账号", "账号",
|
||||
"account", "selleraccount", "storeaccount", "storename");
|
||||
if (index != null) {
|
||||
return index;
|
||||
}
|
||||
return findHeaderByPredicate(key ->
|
||||
(key.contains("\u5e97\u94fa") && (key.contains("\u540d") || key.contains("\u8d26\u53f7")))
|
||||
(key.contains("店铺") && (key.contains("名") || key.contains("账号")))
|
||||
|| (key.contains("shop") && (key.contains("name") || key.contains("account")))
|
||||
|| key.contains("selleraccount")
|
||||
|| key.contains("storeaccount"));
|
||||
@@ -891,32 +875,32 @@ public class QueryAsinService {
|
||||
return index;
|
||||
}
|
||||
return switch (country) {
|
||||
case "DE" -> firstHeader("\u5fb7\u56fd", "\u5fb7", "\u5fb7\u56fdasin");
|
||||
case "UK" -> firstHeader("\u82f1\u56fd", "\u82f1", "\u82f1\u56fdasin");
|
||||
case "FR" -> firstHeader("\u6cd5\u56fd", "\u6cd5", "\u6cd5\u56fdasin");
|
||||
case "IT" -> firstHeader("\u610f\u5927\u5229", "\u610f", "\u610f\u5927\u5229asin");
|
||||
case "ES" -> firstHeader("\u897f\u73ed\u7259", "\u897f", "\u897f\u73ed\u7259asin");
|
||||
case "DE" -> firstHeader("德国", "德", "德国asin");
|
||||
case "UK" -> firstHeader("英国", "英", "英国asin");
|
||||
case "FR" -> firstHeader("法国", "法", "法国asin");
|
||||
case "IT" -> firstHeader("意大利", "意", "意大利asin");
|
||||
case "ES" -> firstHeader("西班牙", "西", "西班牙asin");
|
||||
default -> null;
|
||||
};
|
||||
}
|
||||
|
||||
private Integer findSingleCountryIndex() {
|
||||
Integer index = firstHeader(
|
||||
"\u4e2d\u6587\u56fd\u5bb6\u540d", "\u56fd\u5bb6", "\u56fd\u5bb6\u540d", "\u56fd\u5bb6\u7ad9\u70b9",
|
||||
"\u7ad9\u70b9", "country", "countryname", "marketplace", "site");
|
||||
"中文国家名", "国家", "国家名", "国家站点",
|
||||
"站点", "country", "countryname", "marketplace", "site");
|
||||
if (index != null) {
|
||||
return index;
|
||||
}
|
||||
return findHeaderByPredicate(key ->
|
||||
key.contains("\u56fd\u5bb6")
|
||||
|| key.contains("\u7ad9\u70b9")
|
||||
key.contains("国家")
|
||||
|| key.contains("站点")
|
||||
|| key.contains("country")
|
||||
|| key.contains("marketplace")
|
||||
|| key.equals("site"));
|
||||
}
|
||||
|
||||
private Integer findSingleAsinIndex() {
|
||||
return firstHeader("asin", "\u67e5\u8be2asin", "\u4ea7\u54c1asin", "\u94fe\u63a5asin");
|
||||
return firstHeader("asin", "查询asin", "产品asin", "链接asin");
|
||||
}
|
||||
|
||||
private boolean hasWideCountryColumns() {
|
||||
|
||||
@@ -48,6 +48,7 @@ public class ShopManageGroupService {
|
||||
public List<ShopManageGroupItemVo> list(Long createdById) {
|
||||
return toVoList(groupMapper.selectList(new LambdaQueryWrapper<ShopManageGroupEntity>()
|
||||
.eq(createdById != null && createdById > 0, ShopManageGroupEntity::getCreatedById, createdById)
|
||||
.or(createdById != null && createdById > 0, wrapper -> wrapper.eq(ShopManageGroupEntity::getUserId, createdById))
|
||||
.orderByAsc(ShopManageGroupEntity::getId)));
|
||||
}
|
||||
|
||||
@@ -74,40 +75,44 @@ public class ShopManageGroupService {
|
||||
.collect(Collectors.toCollection(LinkedHashSet::new));
|
||||
}
|
||||
Long normalizedOperatorId = normalizePositiveId(operatorId, "操作人不能为空");
|
||||
LinkedHashSet<Long> groupIds = groupMapper.selectList(new LambdaQueryWrapper<ShopManageGroupEntity>()
|
||||
.select(ShopManageGroupEntity::getId)
|
||||
.eq(ShopManageGroupEntity::getCreatedById, normalizedOperatorId))
|
||||
return groupMapper.selectAccessibleGroupIds(normalizedOperatorId)
|
||||
.stream()
|
||||
.map(ShopManageGroupEntity::getId)
|
||||
.filter(id -> id != null && id > 0)
|
||||
.collect(Collectors.toCollection(LinkedHashSet::new));
|
||||
List<Long> memberGroupIds = groupMemberMapper.selectList(new LambdaQueryWrapper<ShopManageGroupMemberEntity>()
|
||||
.select(ShopManageGroupMemberEntity::getGroupId)
|
||||
.eq(ShopManageGroupMemberEntity::getUserId, normalizedOperatorId))
|
||||
.stream()
|
||||
.map(ShopManageGroupMemberEntity::getGroupId)
|
||||
.filter(id -> id != null && id > 0)
|
||||
.toList();
|
||||
groupIds.addAll(memberGroupIds);
|
||||
if (!memberGroupIds.isEmpty()) {
|
||||
LinkedHashSet<Long> leaderIds = groupMapper.selectList(new LambdaQueryWrapper<ShopManageGroupEntity>()
|
||||
.select(ShopManageGroupEntity::getCreatedById)
|
||||
.in(ShopManageGroupEntity::getId, memberGroupIds))
|
||||
.stream()
|
||||
.map(ShopManageGroupEntity::getCreatedById)
|
||||
.filter(id -> id != null && id > 0)
|
||||
.collect(Collectors.toCollection(LinkedHashSet::new));
|
||||
if (!leaderIds.isEmpty()) {
|
||||
groupIds.addAll(groupMapper.selectList(new LambdaQueryWrapper<ShopManageGroupEntity>()
|
||||
.select(ShopManageGroupEntity::getId)
|
||||
.in(ShopManageGroupEntity::getCreatedById, leaderIds))
|
||||
.stream()
|
||||
.map(ShopManageGroupEntity::getId)
|
||||
.filter(id -> id != null && id > 0)
|
||||
.toList());
|
||||
}
|
||||
}
|
||||
|
||||
public Set<Long> listAccessibleCreatorUserIds(Long operatorId, boolean superAdmin) {
|
||||
if (superAdmin) {
|
||||
return Set.of();
|
||||
}
|
||||
return groupIds;
|
||||
Long normalizedOperatorId = normalizePositiveId(operatorId, "操作人不能为空");
|
||||
return groupMapper.selectAccessibleCreatorUserIds(normalizedOperatorId)
|
||||
.stream()
|
||||
.filter(id -> id != null && id > 0)
|
||||
.collect(Collectors.toCollection(LinkedHashSet::new));
|
||||
}
|
||||
|
||||
public Map<Long, String> buildGroupNameMap(List<Long> groupIds) {
|
||||
if (groupIds == null || groupIds.isEmpty()) {
|
||||
return Map.of();
|
||||
}
|
||||
List<Long> normalizedGroupIds = groupIds.stream()
|
||||
.filter(id -> id != null && id > 0)
|
||||
.distinct()
|
||||
.toList();
|
||||
if (normalizedGroupIds.isEmpty()) {
|
||||
return Map.of();
|
||||
}
|
||||
return groupMapper.selectList(new LambdaQueryWrapper<ShopManageGroupEntity>()
|
||||
.select(ShopManageGroupEntity::getId, ShopManageGroupEntity::getGroupName)
|
||||
.in(ShopManageGroupEntity::getId, normalizedGroupIds))
|
||||
.stream()
|
||||
.filter(group -> group.getId() != null)
|
||||
.collect(Collectors.toMap(
|
||||
ShopManageGroupEntity::getId,
|
||||
group -> normalizeBlank(group.getGroupName()),
|
||||
(left, right) -> left,
|
||||
LinkedHashMap::new));
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@@ -207,8 +212,9 @@ public class ShopManageGroupService {
|
||||
return;
|
||||
}
|
||||
Long normalizedOperatorId = normalizePositiveId(operatorId, "操作人不能为空");
|
||||
boolean createdBySelf = entity.getCreatedById() != null && entity.getCreatedById().equals(normalizedOperatorId);
|
||||
if (!createdBySelf) {
|
||||
boolean leaderBySelf = entity.getCreatedById() != null && entity.getCreatedById().equals(normalizedOperatorId);
|
||||
boolean legacyLeaderBySelf = entity.getUserId() != null && entity.getUserId().equals(normalizedOperatorId);
|
||||
if (!leaderBySelf && !legacyLeaderBySelf) {
|
||||
throw new BusinessException("只有组长才能维护分组");
|
||||
}
|
||||
}
|
||||
@@ -332,8 +338,9 @@ public class ShopManageGroupService {
|
||||
|
||||
LinkedHashSet<Long> userIds = new LinkedHashSet<>();
|
||||
for (ShopManageGroupEntity group : groups) {
|
||||
if (group.getCreatedById() != null && group.getCreatedById() > 0) {
|
||||
userIds.add(group.getCreatedById());
|
||||
Long leaderUserId = resolveGroupLeaderUserId(group);
|
||||
if (leaderUserId != null && leaderUserId > 0) {
|
||||
userIds.add(leaderUserId);
|
||||
}
|
||||
}
|
||||
for (List<ShopManageGroupMemberEntity> members : membersByGroupId.values()) {
|
||||
@@ -355,8 +362,9 @@ public class ShopManageGroupService {
|
||||
ShopManageGroupItemVo vo = new ShopManageGroupItemVo();
|
||||
vo.setId(entity.getId());
|
||||
vo.setGroupName(entity.getGroupName());
|
||||
vo.setLeaderUserId(entity.getCreatedById());
|
||||
AdminUserEntity leaderUser = entity.getCreatedById() == null ? null : userById.get(entity.getCreatedById());
|
||||
Long leaderUserId = resolveGroupLeaderUserId(entity);
|
||||
vo.setLeaderUserId(leaderUserId);
|
||||
AdminUserEntity leaderUser = leaderUserId == null ? null : userById.get(leaderUserId);
|
||||
vo.setLeaderUsername(leaderUser == null ? "" : normalizeBlank(leaderUser.getUsername()));
|
||||
|
||||
List<ShopManageGroupMemberEntity> memberEntities = membersByGroupId.getOrDefault(entity.getId(), Collections.emptyList());
|
||||
@@ -380,4 +388,14 @@ public class ShopManageGroupService {
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private Long resolveGroupLeaderUserId(ShopManageGroupEntity entity) {
|
||||
if (entity == null) {
|
||||
return null;
|
||||
}
|
||||
if (entity.getCreatedById() != null && entity.getCreatedById() > 0) {
|
||||
return entity.getCreatedById();
|
||||
}
|
||||
return entity.getUserId();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,7 +15,6 @@ import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
@@ -33,6 +32,7 @@ public class ShopManageService {
|
||||
long safePageSize = Math.min(Math.max(pageSize, 1), 100);
|
||||
String safeShopName = shopName == null ? "" : shopName.trim();
|
||||
Set<Long> accessibleGroupIds = superAdmin ? Set.of() : shopManageGroupService.listAccessibleGroupIds(operatorId, false);
|
||||
Set<Long> accessibleCreatorUserIds = superAdmin ? Set.of() : shopManageGroupService.listAccessibleCreatorUserIds(operatorId, false);
|
||||
|
||||
LambdaQueryWrapper<ShopManageEntity> query = new LambdaQueryWrapper<ShopManageEntity>()
|
||||
.eq(groupId != null && groupId > 0, ShopManageEntity::getGroupId, groupId)
|
||||
@@ -40,20 +40,30 @@ public class ShopManageService {
|
||||
.orderByDesc(ShopManageEntity::getId);
|
||||
|
||||
if (!superAdmin) {
|
||||
Long normalizedOperatorId = normalizePositiveId(operatorId, "操作人不能为空");
|
||||
query.and(wrapper -> {
|
||||
wrapper.eq(ShopManageEntity::getCreatedById, normalizedOperatorId);
|
||||
if (!accessibleGroupIds.isEmpty()) {
|
||||
wrapper.or().in(ShopManageEntity::getGroupId, accessibleGroupIds);
|
||||
}
|
||||
});
|
||||
normalizePositiveId(operatorId, "操作人不能为空");
|
||||
if (accessibleGroupIds.isEmpty() && accessibleCreatorUserIds.isEmpty()) {
|
||||
query.eq(ShopManageEntity::getId, -1L);
|
||||
} else {
|
||||
query.and(wrapper -> {
|
||||
boolean hasCreatorFilter = !accessibleCreatorUserIds.isEmpty();
|
||||
if (hasCreatorFilter) {
|
||||
wrapper.in(ShopManageEntity::getCreatedById, accessibleCreatorUserIds);
|
||||
}
|
||||
if (!accessibleGroupIds.isEmpty()) {
|
||||
if (hasCreatorFilter) {
|
||||
wrapper.or();
|
||||
}
|
||||
wrapper.in(ShopManageEntity::getGroupId, accessibleGroupIds);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Long total = shopManageMapper.selectCount(query);
|
||||
List<ShopManageEntity> rows = shopManageMapper
|
||||
.selectList(query.last("LIMIT " + ((safePage - 1) * safePageSize) + ", " + safePageSize));
|
||||
|
||||
Map<Long, String> groupNameById = buildGroupNameMap(rows.stream()
|
||||
Map<Long, String> groupNameById = shopManageGroupService.buildGroupNameMap(rows.stream()
|
||||
.map(ShopManageEntity::getGroupId)
|
||||
.filter(id -> id != null && id > 0)
|
||||
.distinct()
|
||||
@@ -190,22 +200,6 @@ public class ShopManageService {
|
||||
}
|
||||
}
|
||||
|
||||
private Map<Long, String> buildGroupNameMap(List<Long> groupIds) {
|
||||
if (groupIds == null || groupIds.isEmpty()) {
|
||||
return Map.of();
|
||||
}
|
||||
LinkedHashMap<Long, String> map = new LinkedHashMap<>();
|
||||
for (Long groupId : groupIds) {
|
||||
try {
|
||||
ShopManageGroupEntity group = shopManageGroupService.getById(groupId);
|
||||
map.put(groupId, group.getGroupName());
|
||||
} catch (Exception ignored) {
|
||||
map.put(groupId, "");
|
||||
}
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
private ShopManageItemVo toItemVo(ShopManageEntity entity, String groupName) {
|
||||
ShopManageItemVo vo = new ShopManageItemVo();
|
||||
vo.setId(entity.getId());
|
||||
|
||||
@@ -62,7 +62,7 @@ public class SkipPriceAsinService {
|
||||
List<SkipPriceAsinEntity> rows = skipPriceAsinMapper
|
||||
.selectList(query.last("LIMIT " + ((safePage - 1) * safePageSize) + ", " + safePageSize));
|
||||
|
||||
Map<Long, String> groupNameById = buildGroupNameMap(rows.stream()
|
||||
Map<Long, String> groupNameById = shopManageGroupService.buildGroupNameMap(rows.stream()
|
||||
.map(SkipPriceAsinEntity::getGroupId)
|
||||
.filter(id -> id != null && id > 0)
|
||||
.distinct()
|
||||
@@ -174,22 +174,6 @@ public class SkipPriceAsinService {
|
||||
return vo;
|
||||
}
|
||||
|
||||
private Map<Long, String> buildGroupNameMap(List<Long> groupIds) {
|
||||
if (groupIds == null || groupIds.isEmpty()) {
|
||||
return Map.of();
|
||||
}
|
||||
LinkedHashMap<Long, String> map = new LinkedHashMap<>();
|
||||
for (Long groupId : groupIds) {
|
||||
try {
|
||||
ShopManageGroupEntity group = shopManageGroupService.getById(groupId);
|
||||
map.put(groupId, group.getGroupName());
|
||||
} catch (Exception ignored) {
|
||||
map.put(groupId, "");
|
||||
}
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
private Set<String> normalizeCountries(List<String> countries) {
|
||||
LinkedHashSet<String> normalized = new LinkedHashSet<>();
|
||||
if (countries != null) {
|
||||
|
||||
@@ -132,6 +132,21 @@ public class ShopMatchTaskService {
|
||||
return tasks;
|
||||
}
|
||||
|
||||
private List<FileTaskEntity> selectTaskStatusesByIdsInBatches(List<Long> taskIds) {
|
||||
List<FileTaskEntity> tasks = new ArrayList<>();
|
||||
if (taskIds == null || taskIds.isEmpty()) {
|
||||
return tasks;
|
||||
}
|
||||
int batchSize = Math.max(1, taskPressureProperties.getDbSelectBatchSize());
|
||||
for (int start = 0; start < taskIds.size(); start += batchSize) {
|
||||
int end = Math.min(start + batchSize, taskIds.size());
|
||||
tasks.addAll(fileTaskMapper.selectList(new LambdaQueryWrapper<FileTaskEntity>()
|
||||
.select(FileTaskEntity::getId, FileTaskEntity::getStatus)
|
||||
.in(FileTaskEntity::getId, taskIds.subList(start, end))));
|
||||
}
|
||||
return tasks;
|
||||
}
|
||||
|
||||
public ProductRiskDashboardVo dashboard(Long userId) {
|
||||
if (userId == null || userId <= 0) {
|
||||
throw new BusinessException("user_id 不合法");
|
||||
@@ -174,7 +189,7 @@ public class ShopMatchTaskService {
|
||||
.distinct()
|
||||
.toList();
|
||||
if (!taskIds.isEmpty()) {
|
||||
for (FileTaskEntity task : selectTasksByIdsInBatches(taskIds)) {
|
||||
for (FileTaskEntity task : selectTaskStatusesByIdsInBatches(taskIds)) {
|
||||
if (task != null) {
|
||||
statusByTaskId.put(task.getId(), task.getStatus());
|
||||
}
|
||||
@@ -465,7 +480,6 @@ public class ShopMatchTaskService {
|
||||
}
|
||||
|
||||
|
||||
@Transactional
|
||||
public void submitResult(Long taskId, ShopMatchSubmitResultRequest request) {
|
||||
if (taskId == null || taskId <= 0) {
|
||||
throw new BusinessException("taskId 不合法");
|
||||
@@ -540,7 +554,6 @@ public class ShopMatchTaskService {
|
||||
updateTaskStatusFromLatestRows(task, latest);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public boolean tryFinalizeTask(Long taskId, boolean fromCompensation) {
|
||||
if (taskId == null || taskId <= 0) {
|
||||
return false;
|
||||
|
||||
@@ -456,8 +456,8 @@ public class SplitRunService {
|
||||
if (value == null) {
|
||||
return "";
|
||||
}
|
||||
return value.replace("\ufeff", "")
|
||||
.replace("\u3000", " ")
|
||||
return value.replace(String.valueOf((char) 0xFEFF), "")
|
||||
.replace((char) 0x3000, ' ')
|
||||
.replace("\r\n", " ")
|
||||
.replace("\r", " ")
|
||||
.replace("\n", " ")
|
||||
|
||||
@@ -23,7 +23,6 @@ public class TaskFileJobService {
|
||||
private final TaskFileJobMapper taskFileJobMapper;
|
||||
private final ApplicationEventPublisher applicationEventPublisher;
|
||||
|
||||
@Transactional
|
||||
public TaskFileJobEntity enqueueAssembleResult(Long taskId, String moduleType, Long resultId, String scopeKey) {
|
||||
if (taskId == null || taskId <= 0 || moduleType == null || moduleType.isBlank() || resultId == null || resultId <= 0) {
|
||||
return null;
|
||||
@@ -146,7 +145,6 @@ public class TaskFileJobService {
|
||||
return reset;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public boolean markRunning(Long jobId) {
|
||||
if (jobId == null || jobId <= 0) {
|
||||
return false;
|
||||
@@ -158,7 +156,6 @@ public class TaskFileJobService {
|
||||
.set(TaskFileJobEntity::getUpdatedAt, LocalDateTime.now())) > 0;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public void touchRunning(Long jobId) {
|
||||
if (jobId == null || jobId <= 0) {
|
||||
return;
|
||||
@@ -169,7 +166,6 @@ public class TaskFileJobService {
|
||||
.set(TaskFileJobEntity::getUpdatedAt, LocalDateTime.now()));
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public void markSuccess(TaskFileJobEntity job, String resultFileUrl) {
|
||||
taskFileJobMapper.update(null, new LambdaUpdateWrapper<TaskFileJobEntity>()
|
||||
.eq(TaskFileJobEntity::getId, job.getId())
|
||||
@@ -180,7 +176,6 @@ public class TaskFileJobService {
|
||||
.set(TaskFileJobEntity::getFinishedAt, LocalDateTime.now()));
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public void markFailed(TaskFileJobEntity job, String message) {
|
||||
int retryCount = job.getRetryCount() == null ? 0 : job.getRetryCount() + 1;
|
||||
taskFileJobMapper.update(null, new LambdaUpdateWrapper<TaskFileJobEntity>()
|
||||
|
||||
@@ -25,7 +25,6 @@ public class TaskResultItemService {
|
||||
private final ObjectMapper objectMapper;
|
||||
private final TransientPayloadStorageService transientPayloadStorageService;
|
||||
|
||||
@Transactional
|
||||
public void replaceResultSnapshot(Long taskId, String moduleType, Long resultId, String scopeKey, Object snapshot) {
|
||||
if (taskId == null || taskId <= 0 || isBlank(moduleType) || resultId == null || resultId <= 0 || snapshot == null) {
|
||||
return;
|
||||
@@ -35,7 +34,6 @@ public class TaskResultItemService {
|
||||
upsert(taskId, moduleType, resultId, normalizedScopeKey, itemKey, null, null, null, snapshot);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public void replaceTaskSnapshots(Long taskId, String moduleType, List<? extends Object> snapshots, SnapshotKeyResolver resolver) {
|
||||
if (taskId == null || taskId <= 0 || isBlank(moduleType) || snapshots == null) {
|
||||
return;
|
||||
|
||||
@@ -25,7 +25,6 @@ public class TaskResultPayloadService {
|
||||
private final ObjectMapper objectMapper;
|
||||
private final TransientPayloadStorageService transientPayloadStorageService;
|
||||
|
||||
@Transactional
|
||||
public void saveLatest(Long taskId, String moduleType, String scopeKey, Object payload) {
|
||||
if (taskId == null || taskId <= 0 || isBlank(moduleType) || isBlank(scopeKey) || payload == null) {
|
||||
return;
|
||||
|
||||
@@ -212,7 +212,7 @@ public boolean isIpWhitelistError(BusinessException ex) {
|
||||
if (value == null) {
|
||||
return "";
|
||||
}
|
||||
return value.replace("\u3000", " ")
|
||||
return value.replace((char) 0x3000, ' ')
|
||||
.trim();
|
||||
}
|
||||
|
||||
|
||||
@@ -357,7 +357,7 @@ public class ZiniaoShopIndexService {
|
||||
if (value == null) {
|
||||
return "";
|
||||
}
|
||||
return value.replace("\u3000", " ").trim();
|
||||
return value.replace((char) 0x3000, ' ').trim();
|
||||
}
|
||||
|
||||
private ZiniaoShopMatchResultVo pendingResult(String message) {
|
||||
|
||||
@@ -19,6 +19,10 @@ spring:
|
||||
maximum-pool-size: ${AIIMAGE_DB_POOL_MAX_SIZE:30}
|
||||
minimum-idle: ${AIIMAGE_DB_POOL_MIN_IDLE:5}
|
||||
connection-timeout: ${AIIMAGE_DB_POOL_CONNECTION_TIMEOUT_MS:30000}
|
||||
validation-timeout: ${AIIMAGE_DB_POOL_VALIDATION_TIMEOUT_MS:5000}
|
||||
idle-timeout: ${AIIMAGE_DB_POOL_IDLE_TIMEOUT_MS:600000}
|
||||
max-lifetime: ${AIIMAGE_DB_POOL_MAX_LIFETIME_MS:1500000}
|
||||
keepalive-time: ${AIIMAGE_DB_POOL_KEEPALIVE_TIME_MS:120000}
|
||||
leak-detection-threshold: ${AIIMAGE_DB_POOL_LEAK_DETECT_MS:0}
|
||||
data:
|
||||
redis:
|
||||
@@ -54,7 +58,7 @@ mybatis-plus:
|
||||
mapper-locations: classpath*:mapper/**/*.xml
|
||||
configuration:
|
||||
map-underscore-to-camel-case: true
|
||||
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
|
||||
log-impl: org.apache.ibatis.logging.slf4j.Slf4jImpl
|
||||
|
||||
springdoc:
|
||||
api-docs:
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
SET @db_name = DATABASE();
|
||||
|
||||
SET @idx_exists := (
|
||||
SELECT COUNT(*)
|
||||
FROM information_schema.STATISTICS
|
||||
WHERE TABLE_SCHEMA = @db_name
|
||||
AND TABLE_NAME = 'biz_shop_manage'
|
||||
AND INDEX_NAME = 'idx_group_id_id'
|
||||
);
|
||||
SET @sql := IF(@idx_exists = 0,
|
||||
'ALTER TABLE biz_shop_manage ADD INDEX idx_group_id_id (group_id, id)',
|
||||
'SELECT 1'
|
||||
);
|
||||
PREPARE stmt FROM @sql;
|
||||
EXECUTE stmt;
|
||||
DEALLOCATE PREPARE stmt;
|
||||
|
||||
SET @idx_exists := (
|
||||
SELECT COUNT(*)
|
||||
FROM information_schema.STATISTICS
|
||||
WHERE TABLE_SCHEMA = @db_name
|
||||
AND TABLE_NAME = 'biz_shop_manage'
|
||||
AND INDEX_NAME = 'idx_created_by_id_id'
|
||||
);
|
||||
SET @sql := IF(@idx_exists = 0,
|
||||
'ALTER TABLE biz_shop_manage ADD INDEX idx_created_by_id_id (created_by_id, id)',
|
||||
'SELECT 1'
|
||||
);
|
||||
PREPARE stmt FROM @sql;
|
||||
EXECUTE stmt;
|
||||
DEALLOCATE PREPARE stmt;
|
||||
|
||||
SET @idx_exists := (
|
||||
SELECT COUNT(*)
|
||||
FROM information_schema.STATISTICS
|
||||
WHERE TABLE_SCHEMA = @db_name
|
||||
AND TABLE_NAME = 'biz_skip_price_asin'
|
||||
AND INDEX_NAME = 'idx_group_id_id'
|
||||
);
|
||||
SET @sql := IF(@idx_exists = 0,
|
||||
'ALTER TABLE biz_skip_price_asin ADD INDEX idx_group_id_id (group_id, id)',
|
||||
'SELECT 1'
|
||||
);
|
||||
PREPARE stmt FROM @sql;
|
||||
EXECUTE stmt;
|
||||
DEALLOCATE PREPARE stmt;
|
||||
|
||||
SET @idx_exists := (
|
||||
SELECT COUNT(*)
|
||||
FROM information_schema.STATISTICS
|
||||
WHERE TABLE_SCHEMA = @db_name
|
||||
AND TABLE_NAME = 'biz_query_asin'
|
||||
AND INDEX_NAME = 'idx_group_id_id'
|
||||
);
|
||||
SET @sql := IF(@idx_exists = 0,
|
||||
'ALTER TABLE biz_query_asin ADD INDEX idx_group_id_id (group_id, id)',
|
||||
'SELECT 1'
|
||||
);
|
||||
PREPARE stmt FROM @sql;
|
||||
EXECUTE stmt;
|
||||
DEALLOCATE PREPARE stmt;
|
||||
@@ -0,0 +1,31 @@
|
||||
SET @db_name = DATABASE();
|
||||
|
||||
SET @idx_exists := (
|
||||
SELECT COUNT(*)
|
||||
FROM information_schema.STATISTICS
|
||||
WHERE TABLE_SCHEMA = @db_name
|
||||
AND TABLE_NAME = 'columns'
|
||||
AND INDEX_NAME = 'idx_menu_type_sort_id'
|
||||
);
|
||||
SET @sql := IF(@idx_exists = 0,
|
||||
'ALTER TABLE columns ADD INDEX idx_menu_type_sort_id (menu_type, sort_order, id)',
|
||||
'SELECT 1'
|
||||
);
|
||||
PREPARE stmt FROM @sql;
|
||||
EXECUTE stmt;
|
||||
DEALLOCATE PREPARE stmt;
|
||||
|
||||
SET @idx_exists := (
|
||||
SELECT COUNT(*)
|
||||
FROM information_schema.STATISTICS
|
||||
WHERE TABLE_SCHEMA = @db_name
|
||||
AND TABLE_NAME = 'user_column_permission'
|
||||
AND INDEX_NAME = 'idx_user_column'
|
||||
);
|
||||
SET @sql := IF(@idx_exists = 0,
|
||||
'ALTER TABLE user_column_permission ADD INDEX idx_user_column (user_id, column_id)',
|
||||
'SELECT 1'
|
||||
);
|
||||
PREPARE stmt FROM @sql;
|
||||
EXECUTE stmt;
|
||||
DEALLOCATE PREPARE stmt;
|
||||
@@ -0,0 +1,31 @@
|
||||
SET @db_name = DATABASE();
|
||||
|
||||
SET @idx_exists := (
|
||||
SELECT COUNT(*)
|
||||
FROM information_schema.STATISTICS
|
||||
WHERE TABLE_SCHEMA = @db_name
|
||||
AND TABLE_NAME = 'biz_file_result'
|
||||
AND INDEX_NAME = 'idx_file_result_task_module_id'
|
||||
);
|
||||
SET @sql := IF(@idx_exists = 0,
|
||||
'ALTER TABLE biz_file_result ADD INDEX idx_file_result_task_module_id (task_id, module_type, id)',
|
||||
'SELECT 1'
|
||||
);
|
||||
PREPARE stmt FROM @sql;
|
||||
EXECUTE stmt;
|
||||
DEALLOCATE PREPARE stmt;
|
||||
|
||||
SET @idx_exists := (
|
||||
SELECT COUNT(*)
|
||||
FROM information_schema.STATISTICS
|
||||
WHERE TABLE_SCHEMA = @db_name
|
||||
AND TABLE_NAME = 'biz_task_file_job'
|
||||
AND INDEX_NAME = 'idx_file_job_status_retry_updated'
|
||||
);
|
||||
SET @sql := IF(@idx_exists = 0,
|
||||
'ALTER TABLE biz_task_file_job ADD INDEX idx_file_job_status_retry_updated (status, retry_count, updated_at)',
|
||||
'SELECT 1'
|
||||
);
|
||||
PREPARE stmt FROM @sql;
|
||||
EXECUTE stmt;
|
||||
DEALLOCATE PREPARE stmt;
|
||||
Reference in New Issue
Block a user