feat(energy): 添加三步导入接口(预览/确认/进度)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -7,6 +7,7 @@ public interface ErrorCodeConstants {
|
|||||||
ErrorCode HYDROGEN_RECORD_NOT_EXISTS = new ErrorCode(1_050_000_000, "加氢记录不存在");
|
ErrorCode HYDROGEN_RECORD_NOT_EXISTS = new ErrorCode(1_050_000_000, "加氢记录不存在");
|
||||||
ErrorCode HYDROGEN_RECORD_IMPORT_EMPTY = new ErrorCode(1_050_000_001, "导入数据为空");
|
ErrorCode HYDROGEN_RECORD_IMPORT_EMPTY = new ErrorCode(1_050_000_001, "导入数据为空");
|
||||||
ErrorCode HYDROGEN_RECORD_DUPLICATE = new ErrorCode(1_050_000_002, "存在重复导入记录");
|
ErrorCode HYDROGEN_RECORD_DUPLICATE = new ErrorCode(1_050_000_002, "存在重复导入记录");
|
||||||
|
ErrorCode HYDROGEN_RECORD_IMPORT_PREVIEW_EXPIRED = new ErrorCode(1_050_000_003, "导入预览已过期或不存在,请重新上传文件");
|
||||||
|
|
||||||
// ========== 加氢明细 1-050-001-000 ==========
|
// ========== 加氢明细 1-050-001-000 ==========
|
||||||
ErrorCode HYDROGEN_DETAIL_NOT_EXISTS = new ErrorCode(1_050_001_000, "加氢明细不存在");
|
ErrorCode HYDROGEN_DETAIL_NOT_EXISTS = new ErrorCode(1_050_001_000, "加氢明细不存在");
|
||||||
|
|||||||
@@ -102,6 +102,33 @@ public class HydrogenRecordController {
|
|||||||
return success(result);
|
return success(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@PostMapping("/import-preview")
|
||||||
|
@Operation(summary = "导入预览")
|
||||||
|
@PreAuthorize("@ss.hasPermission('energy:hydrogen-record:import')")
|
||||||
|
public CommonResult<HydrogenRecordImportPreviewVO> importPreview(
|
||||||
|
@RequestParam("stationId") Long stationId,
|
||||||
|
@RequestParam("file") MultipartFile file) throws Exception {
|
||||||
|
List<HydrogenRecordImportVO> list = ExcelUtils.read(file, HydrogenRecordImportVO.class);
|
||||||
|
return success(hydrogenRecordService.importPreview(stationId, list));
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/import-confirm")
|
||||||
|
@Operation(summary = "确认导入")
|
||||||
|
@PreAuthorize("@ss.hasPermission('energy:hydrogen-record:import')")
|
||||||
|
public CommonResult<Map<String, Integer>> importConfirm(
|
||||||
|
@RequestParam("batchNo") String batchNo,
|
||||||
|
@RequestParam(value = "duplicateStrategy", defaultValue = "skip") String duplicateStrategy) {
|
||||||
|
return success(hydrogenRecordService.importConfirm(batchNo, duplicateStrategy));
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/import-progress")
|
||||||
|
@Operation(summary = "导入进度")
|
||||||
|
@PreAuthorize("@ss.hasPermission('energy:hydrogen-record:import')")
|
||||||
|
public CommonResult<HydrogenRecordImportProgressVO> getImportProgress(
|
||||||
|
@RequestParam("batchNo") String batchNo) {
|
||||||
|
return success(hydrogenRecordService.getImportProgress(batchNo));
|
||||||
|
}
|
||||||
|
|
||||||
@PutMapping("/match")
|
@PutMapping("/match")
|
||||||
@Operation(summary = "手动匹配车辆")
|
@Operation(summary = "手动匹配车辆")
|
||||||
@PreAuthorize("@ss.hasPermission('energy:hydrogen-record:update')")
|
@PreAuthorize("@ss.hasPermission('energy:hydrogen-record:update')")
|
||||||
|
|||||||
@@ -0,0 +1,47 @@
|
|||||||
|
package cn.iocoder.yudao.module.energy.controller.admin.record.vo;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import lombok.Data;
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.time.LocalDate;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Schema(description = "管理后台 - 加氢记录导入预览 Response VO")
|
||||||
|
@Data
|
||||||
|
public class HydrogenRecordImportPreviewVO {
|
||||||
|
|
||||||
|
@Schema(description = "批次号")
|
||||||
|
private String batchNo;
|
||||||
|
@Schema(description = "总行数")
|
||||||
|
private Integer totalCount;
|
||||||
|
@Schema(description = "有效行数")
|
||||||
|
private Integer validCount;
|
||||||
|
@Schema(description = "重复行数")
|
||||||
|
private Integer duplicateCount;
|
||||||
|
@Schema(description = "错误行数")
|
||||||
|
private Integer errorCount;
|
||||||
|
@Schema(description = "预览记录")
|
||||||
|
private List<RecordPreviewItem> records;
|
||||||
|
@Schema(description = "重复记录")
|
||||||
|
private List<RecordPreviewItem> duplicates;
|
||||||
|
@Schema(description = "错误明细")
|
||||||
|
private List<ImportErrorItem> errors;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public static class RecordPreviewItem {
|
||||||
|
private Integer rowNum;
|
||||||
|
private String plateNumber;
|
||||||
|
private LocalDate hydrogenDate;
|
||||||
|
private BigDecimal hydrogenQuantity;
|
||||||
|
private BigDecimal unitPrice;
|
||||||
|
private BigDecimal amount;
|
||||||
|
private BigDecimal mileage;
|
||||||
|
private Boolean isDuplicate;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public static class ImportErrorItem {
|
||||||
|
private Integer rowNum;
|
||||||
|
private String reason;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
package cn.iocoder.yudao.module.energy.controller.admin.record.vo;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Schema(description = "管理后台 - 加氢记录导入进度 Response VO")
|
||||||
|
@Data
|
||||||
|
public class HydrogenRecordImportProgressVO {
|
||||||
|
@Schema(description = "当前进度")
|
||||||
|
private Integer current;
|
||||||
|
@Schema(description = "总数")
|
||||||
|
private Integer total;
|
||||||
|
@Schema(description = "状态: processing / completed / failed")
|
||||||
|
private String status;
|
||||||
|
}
|
||||||
@@ -1,6 +1,8 @@
|
|||||||
package cn.iocoder.yudao.module.energy.service.record;
|
package cn.iocoder.yudao.module.energy.service.record;
|
||||||
|
|
||||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||||
|
import cn.iocoder.yudao.module.energy.controller.admin.record.vo.HydrogenRecordImportPreviewVO;
|
||||||
|
import cn.iocoder.yudao.module.energy.controller.admin.record.vo.HydrogenRecordImportProgressVO;
|
||||||
import cn.iocoder.yudao.module.energy.controller.admin.record.vo.HydrogenRecordImportVO;
|
import cn.iocoder.yudao.module.energy.controller.admin.record.vo.HydrogenRecordImportVO;
|
||||||
import cn.iocoder.yudao.module.energy.controller.admin.record.vo.HydrogenRecordPageReqVO;
|
import cn.iocoder.yudao.module.energy.controller.admin.record.vo.HydrogenRecordPageReqVO;
|
||||||
import cn.iocoder.yudao.module.energy.controller.admin.record.vo.HydrogenRecordSaveReqVO;
|
import cn.iocoder.yudao.module.energy.controller.admin.record.vo.HydrogenRecordSaveReqVO;
|
||||||
@@ -17,4 +19,7 @@ public interface HydrogenRecordService {
|
|||||||
Map<String, Integer> importRecords(Long stationId, List<HydrogenRecordImportVO> list, String batchNo);
|
Map<String, Integer> importRecords(Long stationId, List<HydrogenRecordImportVO> list, String batchNo);
|
||||||
void matchRecord(Long id, Long vehicleId, Long customerId);
|
void matchRecord(Long id, Long vehicleId, Long customerId);
|
||||||
Map<String, Integer> batchMatch();
|
Map<String, Integer> batchMatch();
|
||||||
|
HydrogenRecordImportPreviewVO importPreview(Long stationId, List<HydrogenRecordImportVO> list);
|
||||||
|
Map<String, Integer> importConfirm(String batchNo, String duplicateStrategy);
|
||||||
|
HydrogenRecordImportProgressVO getImportProgress(String batchNo);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
package cn.iocoder.yudao.module.energy.service.record;
|
package cn.iocoder.yudao.module.energy.service.record;
|
||||||
|
|
||||||
|
import cn.hutool.json.JSONUtil;
|
||||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||||
|
import cn.iocoder.yudao.module.energy.controller.admin.record.vo.HydrogenRecordImportPreviewVO;
|
||||||
|
import cn.iocoder.yudao.module.energy.controller.admin.record.vo.HydrogenRecordImportProgressVO;
|
||||||
import cn.iocoder.yudao.module.energy.controller.admin.record.vo.HydrogenRecordImportVO;
|
import cn.iocoder.yudao.module.energy.controller.admin.record.vo.HydrogenRecordImportVO;
|
||||||
import cn.iocoder.yudao.module.energy.controller.admin.record.vo.HydrogenRecordPageReqVO;
|
import cn.iocoder.yudao.module.energy.controller.admin.record.vo.HydrogenRecordPageReqVO;
|
||||||
import cn.iocoder.yudao.module.energy.controller.admin.record.vo.HydrogenRecordSaveReqVO;
|
import cn.iocoder.yudao.module.energy.controller.admin.record.vo.HydrogenRecordSaveReqVO;
|
||||||
@@ -15,10 +18,17 @@ import cn.iocoder.yudao.module.energy.event.RecordMatchedEvent;
|
|||||||
import jakarta.annotation.Resource;
|
import jakarta.annotation.Resource;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.context.ApplicationEventPublisher;
|
import org.springframework.context.ApplicationEventPublisher;
|
||||||
|
import org.springframework.data.redis.core.StringRedisTemplate;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
import org.springframework.validation.annotation.Validated;
|
import org.springframework.validation.annotation.Validated;
|
||||||
|
|
||||||
|
import java.time.LocalDate;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.time.format.DateTimeFormatter;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||||
import static cn.iocoder.yudao.module.energy.enums.ErrorCodeConstants.*;
|
import static cn.iocoder.yudao.module.energy.enums.ErrorCodeConstants.*;
|
||||||
@@ -28,10 +38,16 @@ import static cn.iocoder.yudao.module.energy.enums.ErrorCodeConstants.*;
|
|||||||
@Slf4j
|
@Slf4j
|
||||||
public class HydrogenRecordServiceImpl implements HydrogenRecordService {
|
public class HydrogenRecordServiceImpl implements HydrogenRecordService {
|
||||||
|
|
||||||
|
private static final String REDIS_KEY_PREVIEW = "energy:import:preview:";
|
||||||
|
private static final String REDIS_KEY_PROGRESS = "energy:import:progress:";
|
||||||
|
private static final long PREVIEW_TTL_MINUTES = 15L;
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
private EnergyHydrogenRecordMapper hydrogenRecordMapper;
|
private EnergyHydrogenRecordMapper hydrogenRecordMapper;
|
||||||
@Resource
|
@Resource
|
||||||
private ApplicationEventPublisher eventPublisher;
|
private ApplicationEventPublisher eventPublisher;
|
||||||
|
@Resource
|
||||||
|
private StringRedisTemplate stringRedisTemplate;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Long createRecord(HydrogenRecordSaveReqVO createReqVO) {
|
public Long createRecord(HydrogenRecordSaveReqVO createReqVO) {
|
||||||
@@ -144,6 +160,229 @@ public class HydrogenRecordServiceImpl implements HydrogenRecordService {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ==================== 三步导入接口 ====================
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public HydrogenRecordImportPreviewVO importPreview(Long stationId, List<HydrogenRecordImportVO> list) {
|
||||||
|
if (list == null || list.isEmpty()) {
|
||||||
|
throw exception(HYDROGEN_RECORD_IMPORT_EMPTY);
|
||||||
|
}
|
||||||
|
|
||||||
|
String batchNo = generateBatchNo();
|
||||||
|
|
||||||
|
List<HydrogenRecordImportPreviewVO.RecordPreviewItem> validRecords = new ArrayList<>();
|
||||||
|
List<HydrogenRecordImportPreviewVO.RecordPreviewItem> duplicateRecords = new ArrayList<>();
|
||||||
|
List<HydrogenRecordImportPreviewVO.ImportErrorItem> errors = new ArrayList<>();
|
||||||
|
|
||||||
|
// Build a set of keys for existing DB records (stationId+plateNumber+hydrogenDate)
|
||||||
|
// We'll check duplicates on-the-fly per record to avoid pulling too much data at once
|
||||||
|
Set<String> seenInBatch = new HashSet<>();
|
||||||
|
|
||||||
|
int rowNum = 1;
|
||||||
|
for (HydrogenRecordImportVO importVO : list) {
|
||||||
|
// Validate required fields
|
||||||
|
if (importVO.getPlateNumber() == null || importVO.getPlateNumber().isBlank()) {
|
||||||
|
HydrogenRecordImportPreviewVO.ImportErrorItem err = new HydrogenRecordImportPreviewVO.ImportErrorItem();
|
||||||
|
err.setRowNum(rowNum);
|
||||||
|
err.setReason("车牌号不能为空");
|
||||||
|
errors.add(err);
|
||||||
|
rowNum++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (importVO.getHydrogenDate() == null) {
|
||||||
|
HydrogenRecordImportPreviewVO.ImportErrorItem err = new HydrogenRecordImportPreviewVO.ImportErrorItem();
|
||||||
|
err.setRowNum(rowNum);
|
||||||
|
err.setReason("加氢日期不能为空");
|
||||||
|
errors.add(err);
|
||||||
|
rowNum++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (importVO.getHydrogenQuantity() == null) {
|
||||||
|
HydrogenRecordImportPreviewVO.ImportErrorItem err = new HydrogenRecordImportPreviewVO.ImportErrorItem();
|
||||||
|
err.setRowNum(rowNum);
|
||||||
|
err.setReason("加氢量不能为空");
|
||||||
|
errors.add(err);
|
||||||
|
rowNum++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check duplicate: stationId + plateNumber + hydrogenDate
|
||||||
|
String dedupKey = stationId + ":" + importVO.getPlateNumber() + ":" + importVO.getHydrogenDate();
|
||||||
|
boolean isDuplicateInBatch = seenInBatch.contains(dedupKey);
|
||||||
|
boolean isDuplicateInDb = false;
|
||||||
|
if (!isDuplicateInBatch) {
|
||||||
|
Long count = hydrogenRecordMapper.selectCount(
|
||||||
|
new LambdaQueryWrapperX<EnergyHydrogenRecordDO>()
|
||||||
|
.eq(EnergyHydrogenRecordDO::getStationId, stationId)
|
||||||
|
.eq(EnergyHydrogenRecordDO::getPlateNumber, importVO.getPlateNumber())
|
||||||
|
.eq(EnergyHydrogenRecordDO::getHydrogenDate, importVO.getHydrogenDate()));
|
||||||
|
isDuplicateInDb = count != null && count > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
HydrogenRecordImportPreviewVO.RecordPreviewItem item = new HydrogenRecordImportPreviewVO.RecordPreviewItem();
|
||||||
|
item.setRowNum(rowNum);
|
||||||
|
item.setPlateNumber(importVO.getPlateNumber());
|
||||||
|
item.setHydrogenDate(importVO.getHydrogenDate());
|
||||||
|
item.setHydrogenQuantity(importVO.getHydrogenQuantity());
|
||||||
|
item.setUnitPrice(importVO.getUnitPrice());
|
||||||
|
item.setAmount(importVO.getAmount());
|
||||||
|
item.setMileage(importVO.getMileage());
|
||||||
|
item.setIsDuplicate(isDuplicateInBatch || isDuplicateInDb);
|
||||||
|
|
||||||
|
if (isDuplicateInBatch || isDuplicateInDb) {
|
||||||
|
duplicateRecords.add(item);
|
||||||
|
} else {
|
||||||
|
validRecords.add(item);
|
||||||
|
seenInBatch.add(dedupKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
rowNum++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build cache payload
|
||||||
|
Map<String, Object> cachePayload = new HashMap<>();
|
||||||
|
cachePayload.put("stationId", stationId);
|
||||||
|
cachePayload.put("validRecords", validRecords);
|
||||||
|
cachePayload.put("duplicateRecords", duplicateRecords);
|
||||||
|
|
||||||
|
// Store in Redis with 15-minute TTL
|
||||||
|
stringRedisTemplate.opsForValue().set(
|
||||||
|
REDIS_KEY_PREVIEW + batchNo,
|
||||||
|
JSONUtil.toJsonStr(cachePayload),
|
||||||
|
PREVIEW_TTL_MINUTES,
|
||||||
|
TimeUnit.MINUTES);
|
||||||
|
|
||||||
|
// Build response
|
||||||
|
HydrogenRecordImportPreviewVO result = new HydrogenRecordImportPreviewVO();
|
||||||
|
result.setBatchNo(batchNo);
|
||||||
|
result.setTotalCount(list.size());
|
||||||
|
result.setValidCount(validRecords.size());
|
||||||
|
result.setDuplicateCount(duplicateRecords.size());
|
||||||
|
result.setErrorCount(errors.size());
|
||||||
|
// Return first 50 preview records
|
||||||
|
result.setRecords(validRecords.stream().limit(50).collect(Collectors.toList()));
|
||||||
|
result.setDuplicates(duplicateRecords.stream().limit(50).collect(Collectors.toList()));
|
||||||
|
result.setErrors(errors);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public Map<String, Integer> importConfirm(String batchNo, String duplicateStrategy) {
|
||||||
|
// Read cached preview data
|
||||||
|
String cacheJson = stringRedisTemplate.opsForValue().get(REDIS_KEY_PREVIEW + batchNo);
|
||||||
|
if (cacheJson == null || cacheJson.isBlank()) {
|
||||||
|
throw exception(HYDROGEN_RECORD_IMPORT_PREVIEW_EXPIRED);
|
||||||
|
}
|
||||||
|
|
||||||
|
cn.hutool.json.JSONObject payload = JSONUtil.parseObj(cacheJson);
|
||||||
|
Long stationId = payload.getLong("stationId");
|
||||||
|
|
||||||
|
List<HydrogenRecordImportPreviewVO.RecordPreviewItem> validRecords =
|
||||||
|
JSONUtil.toList(payload.getJSONArray("validRecords"), HydrogenRecordImportPreviewVO.RecordPreviewItem.class);
|
||||||
|
List<HydrogenRecordImportPreviewVO.RecordPreviewItem> duplicateRecords =
|
||||||
|
JSONUtil.toList(payload.getJSONArray("duplicateRecords"), HydrogenRecordImportPreviewVO.RecordPreviewItem.class);
|
||||||
|
|
||||||
|
// Determine records to insert based on strategy
|
||||||
|
List<HydrogenRecordImportPreviewVO.RecordPreviewItem> toInsert = new ArrayList<>(validRecords);
|
||||||
|
if ("overwrite".equals(duplicateStrategy)) {
|
||||||
|
toInsert.addAll(duplicateRecords);
|
||||||
|
}
|
||||||
|
|
||||||
|
int total = toInsert.size();
|
||||||
|
|
||||||
|
// Set initial progress
|
||||||
|
HydrogenRecordImportProgressVO progress = new HydrogenRecordImportProgressVO();
|
||||||
|
progress.setCurrent(0);
|
||||||
|
progress.setTotal(total);
|
||||||
|
progress.setStatus("processing");
|
||||||
|
stringRedisTemplate.opsForValue().set(
|
||||||
|
REDIS_KEY_PROGRESS + batchNo,
|
||||||
|
JSONUtil.toJsonStr(progress),
|
||||||
|
PREVIEW_TTL_MINUTES,
|
||||||
|
TimeUnit.MINUTES);
|
||||||
|
|
||||||
|
int successCount = 0;
|
||||||
|
int failCount = 0;
|
||||||
|
List<Long> recordIds = new ArrayList<>();
|
||||||
|
|
||||||
|
for (int i = 0; i < toInsert.size(); i++) {
|
||||||
|
HydrogenRecordImportPreviewVO.RecordPreviewItem item = toInsert.get(i);
|
||||||
|
try {
|
||||||
|
if ("overwrite".equals(duplicateStrategy) && Boolean.TRUE.equals(item.getIsDuplicate())) {
|
||||||
|
// Delete existing record(s) with same key before inserting
|
||||||
|
hydrogenRecordMapper.delete(
|
||||||
|
new LambdaQueryWrapperX<EnergyHydrogenRecordDO>()
|
||||||
|
.eq(EnergyHydrogenRecordDO::getStationId, stationId)
|
||||||
|
.eq(EnergyHydrogenRecordDO::getPlateNumber, item.getPlateNumber())
|
||||||
|
.eq(EnergyHydrogenRecordDO::getHydrogenDate, item.getHydrogenDate()));
|
||||||
|
}
|
||||||
|
EnergyHydrogenRecordDO record = EnergyHydrogenRecordDO.builder()
|
||||||
|
.stationId(stationId)
|
||||||
|
.plateNumber(item.getPlateNumber())
|
||||||
|
.hydrogenDate(item.getHydrogenDate())
|
||||||
|
.hydrogenQuantity(item.getHydrogenQuantity())
|
||||||
|
.unitPrice(item.getUnitPrice())
|
||||||
|
.amount(item.getAmount())
|
||||||
|
.mileage(item.getMileage())
|
||||||
|
.sourceType(SourceTypeEnum.EXCEL.getType())
|
||||||
|
.matchStatus(MatchStatusEnum.UNMATCHED.getStatus())
|
||||||
|
.uploadBatchNo(batchNo)
|
||||||
|
.build();
|
||||||
|
hydrogenRecordMapper.insert(record);
|
||||||
|
recordIds.add(record.getId());
|
||||||
|
successCount++;
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.warn("[importConfirm] Failed to import record row {}: {}", item.getRowNum(), e.getMessage());
|
||||||
|
failCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update progress
|
||||||
|
progress.setCurrent(i + 1);
|
||||||
|
stringRedisTemplate.opsForValue().set(
|
||||||
|
REDIS_KEY_PROGRESS + batchNo,
|
||||||
|
JSONUtil.toJsonStr(progress),
|
||||||
|
PREVIEW_TTL_MINUTES,
|
||||||
|
TimeUnit.MINUTES);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mark progress as completed
|
||||||
|
progress.setStatus(failCount == 0 ? "completed" : "failed");
|
||||||
|
stringRedisTemplate.opsForValue().set(
|
||||||
|
REDIS_KEY_PROGRESS + batchNo,
|
||||||
|
JSONUtil.toJsonStr(progress),
|
||||||
|
PREVIEW_TTL_MINUTES,
|
||||||
|
TimeUnit.MINUTES);
|
||||||
|
|
||||||
|
// Publish event
|
||||||
|
if (!recordIds.isEmpty()) {
|
||||||
|
eventPublisher.publishEvent(new RecordImportedEvent(stationId, recordIds, batchNo));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clean up preview cache
|
||||||
|
stringRedisTemplate.delete(REDIS_KEY_PREVIEW + batchNo);
|
||||||
|
|
||||||
|
Map<String, Integer> result = new HashMap<>();
|
||||||
|
result.put("successCount", successCount);
|
||||||
|
result.put("failCount", failCount);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public HydrogenRecordImportProgressVO getImportProgress(String batchNo) {
|
||||||
|
String json = stringRedisTemplate.opsForValue().get(REDIS_KEY_PROGRESS + batchNo);
|
||||||
|
if (json == null || json.isBlank()) {
|
||||||
|
HydrogenRecordImportProgressVO vo = new HydrogenRecordImportProgressVO();
|
||||||
|
vo.setCurrent(0);
|
||||||
|
vo.setTotal(0);
|
||||||
|
vo.setStatus("completed");
|
||||||
|
return vo;
|
||||||
|
}
|
||||||
|
return JSONUtil.toBean(json, HydrogenRecordImportProgressVO.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==================== 私有方法 ====================
|
||||||
|
|
||||||
private EnergyHydrogenRecordDO validateRecordExists(Long id) {
|
private EnergyHydrogenRecordDO validateRecordExists(Long id) {
|
||||||
EnergyHydrogenRecordDO record = hydrogenRecordMapper.selectById(id);
|
EnergyHydrogenRecordDO record = hydrogenRecordMapper.selectById(id);
|
||||||
if (record == null) {
|
if (record == null) {
|
||||||
@@ -151,4 +390,9 @@ public class HydrogenRecordServiceImpl implements HydrogenRecordService {
|
|||||||
}
|
}
|
||||||
return record;
|
return record;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String generateBatchNo() {
|
||||||
|
return "IMP" + LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"))
|
||||||
|
+ UUID.randomUUID().toString().substring(0, 4).toUpperCase();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user