Commit 4ab00f6c by zhangxingmin

push

parent 48abef2d
...@@ -25,6 +25,7 @@ import org.springframework.beans.factory.annotation.Autowired; ...@@ -25,6 +25,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils; import org.springframework.util.CollectionUtils;
import java.time.LocalDateTime;
import java.util.*; import java.util.*;
import java.util.stream.Collectors; import java.util.stream.Collectors;
...@@ -88,7 +89,7 @@ public class ApiAnnouncementCommissionRatioServiceImpl implements ApiAnnouncemen ...@@ -88,7 +89,7 @@ public class ApiAnnouncementCommissionRatioServiceImpl implements ApiAnnouncemen
.stream() .stream()
.map(dto -> { .map(dto -> {
AnnouncementCommissionRatio ratio = new AnnouncementCommissionRatio(); AnnouncementCommissionRatio ratio = new AnnouncementCommissionRatio();
BeanUtils.copyProperties(dto,ratio); BeanUtils.copyProperties(dto, ratio);
ratio.setAnnouncementSpeciesBizId(request.getAnnouncementSpeciesBizId()); ratio.setAnnouncementSpeciesBizId(request.getAnnouncementSpeciesBizId());
ratio.setAnnouncementCommissionRatioBizId(RandomStringGenerator.generateBizId16(CommonEnum.UID_TYPE_ANNOUNCEMENT_COMMISSION_RATIO.getCode())); ratio.setAnnouncementCommissionRatioBizId(RandomStringGenerator.generateBizId16(CommonEnum.UID_TYPE_ANNOUNCEMENT_COMMISSION_RATIO.getCode()));
return ratio; return ratio;
...@@ -110,7 +111,7 @@ public class ApiAnnouncementCommissionRatioServiceImpl implements ApiAnnouncemen ...@@ -110,7 +111,7 @@ public class ApiAnnouncementCommissionRatioServiceImpl implements ApiAnnouncemen
//入参校验,佣金年限校验不同条件下的唯一性 TODO //入参校验,佣金年限校验不同条件下的唯一性 TODO
//新增 //新增
AnnouncementCommissionRatio ratio = new AnnouncementCommissionRatio(); AnnouncementCommissionRatio ratio = new AnnouncementCommissionRatio();
BeanUtils.copyProperties(request,ratio); BeanUtils.copyProperties(request, ratio);
ratio.setAnnouncementCommissionRatioBizId(RandomStringGenerator.generateBizId16(CommonEnum.UID_TYPE_ANNOUNCEMENT_COMMISSION_RATIO.getCode())); ratio.setAnnouncementCommissionRatioBizId(RandomStringGenerator.generateBizId16(CommonEnum.UID_TYPE_ANNOUNCEMENT_COMMISSION_RATIO.getCode()));
iAnnouncementCommissionRatioService.saveOrUpdate(ratio); iAnnouncementCommissionRatioService.saveOrUpdate(ratio);
return Result.success(); return Result.success();
...@@ -130,7 +131,7 @@ public class ApiAnnouncementCommissionRatioServiceImpl implements ApiAnnouncemen ...@@ -130,7 +131,7 @@ public class ApiAnnouncementCommissionRatioServiceImpl implements ApiAnnouncemen
apiAnnouncementSpeciesService.checkAnnouncementSpeciesIsExist(request.getAnnouncementSpeciesBizId()); apiAnnouncementSpeciesService.checkAnnouncementSpeciesIsExist(request.getAnnouncementSpeciesBizId());
//入参校验,佣金年限校验不同条件下的唯一性 TODO //入参校验,佣金年限校验不同条件下的唯一性 TODO
//新增 //新增
BeanUtils.copyProperties(request,ratio); BeanUtils.copyProperties(request, ratio);
iAnnouncementCommissionRatioService.saveOrUpdate(ratio); iAnnouncementCommissionRatioService.saveOrUpdate(ratio);
return Result.success(); return Result.success();
} }
...@@ -162,7 +163,7 @@ public class ApiAnnouncementCommissionRatioServiceImpl implements ApiAnnouncemen ...@@ -162,7 +163,7 @@ public class ApiAnnouncementCommissionRatioServiceImpl implements ApiAnnouncemen
Result<AnnouncementCommissionRatio> result = checkAnnouncementCommissionRatioIsExist(announcementCommissionRatioBizId); Result<AnnouncementCommissionRatio> result = checkAnnouncementCommissionRatioIsExist(announcementCommissionRatioBizId);
AnnouncementCommissionRatio announcementCommissionRatio = result.getData(); AnnouncementCommissionRatio announcementCommissionRatio = result.getData();
ApiAnnouncementCommissionRatioDetailResponse response = new ApiAnnouncementCommissionRatioDetailResponse(); ApiAnnouncementCommissionRatioDetailResponse response = new ApiAnnouncementCommissionRatioDetailResponse();
BeanUtils.copyProperties(announcementCommissionRatio,response); BeanUtils.copyProperties(announcementCommissionRatio, response);
return Result.success(response); return Result.success(response);
} }
...@@ -204,7 +205,7 @@ public class ApiAnnouncementCommissionRatioServiceImpl implements ApiAnnouncemen ...@@ -204,7 +205,7 @@ public class ApiAnnouncementCommissionRatioServiceImpl implements ApiAnnouncemen
@Override @Override
public Result<Boolean> isData(String productLaunchBizId) { public Result<Boolean> isData(String productLaunchBizId) {
List<AnnouncementSpecies> speciesList = iAnnouncementSpeciesService.queryList(productLaunchBizId); List<AnnouncementSpecies> speciesList = iAnnouncementSpeciesService.queryList(productLaunchBizId);
if (CollectionUtils.isEmpty(speciesList)){ if (CollectionUtils.isEmpty(speciesList)) {
return Result.success(false); return Result.success(false);
} }
List<String> announcementSpeciesBizIdList = speciesList.stream().map(AnnouncementSpecies::getAnnouncementSpeciesBizId).collect(Collectors.toList()); List<String> announcementSpeciesBizIdList = speciesList.stream().map(AnnouncementSpecies::getAnnouncementSpeciesBizId).collect(Collectors.toList());
...@@ -231,28 +232,35 @@ public class ApiAnnouncementCommissionRatioServiceImpl implements ApiAnnouncemen ...@@ -231,28 +232,35 @@ public class ApiAnnouncementCommissionRatioServiceImpl implements ApiAnnouncemen
} }
/** /**
* 校验入参-公告佣比率规格明细列表 * 校验入参-公告佣比率规格明细列表(年限区间和有效时间区间均不能重叠)
* @param ratioBatchSaveDtoList * @param ratioBatchSaveDtoList
* @return * @return
*/ */
public Result checkBatchSaveRequestPram(List<ApiAnnouncementCommissionRatioBatchSaveDto> ratioBatchSaveDtoList) { public Result checkBatchSaveRequestPram(List<ApiAnnouncementCommissionRatioBatchSaveDto> ratioBatchSaveDtoList) {
// 1. 验证并准备数据(增加有效时间字段)
// 1. 验证并准备数据
List<DtoWithParsedData> preparedDataList = prepareData(ratioBatchSaveDtoList); List<DtoWithParsedData> preparedDataList = prepareData(ratioBatchSaveDtoList);
// 2. 检查所有数据对的年限重叠情况(考虑scope交集) // 2. 检查年限重叠(原有逻辑,保持不变)
List<OverlapError> errors = checkAllDataPairs(preparedDataList); List<OverlapError> yearErrors = checkYearOverlap(preparedDataList);
// 3. 检查有效时间重叠(新增逻辑,使用排除 effectiveStart/end 的分组,但仍考虑 scope 交集)
List<OverlapError> effectiveErrors = checkEffectiveTimeOverlap(preparedDataList);
// 3. 如果有错误,返回错误信息 // 4. 合并错误
if (!errors.isEmpty()) { List<OverlapError> allErrors = new ArrayList<>();
String errorMsg = buildErrorMessage(errors, ratioBatchSaveDtoList); allErrors.addAll(yearErrors);
throw new BusinessException(1004,errorMsg); allErrors.addAll(effectiveErrors);
// 5. 如果有错误,返回错误信息
if (!allErrors.isEmpty()) {
String errorMsg = buildErrorMessage(allErrors, ratioBatchSaveDtoList);
throw new BusinessException(1004, errorMsg);
} }
return Result.success(); return Result.success();
} }
/** /**
* 准备数据:解析年限并将scope转换为集合 * 准备数据:解析年限、存储有效时间、解析scope,并校验基本合法性
* @param dtoList * @param dtoList
* @return * @return
*/ */
...@@ -267,63 +275,96 @@ public class ApiAnnouncementCommissionRatioServiceImpl implements ApiAnnouncemen ...@@ -267,63 +275,96 @@ public class ApiAnnouncementCommissionRatioServiceImpl implements ApiAnnouncemen
Integer endYear = ProductCommonUtils.parseYearToInt(dto.getEndPeriod()); Integer endYear = ProductCommonUtils.parseYearToInt(dto.getEndPeriod());
if (startYear > endYear) { if (startYear > endYear) {
throw new BusinessException("第" + (i+1) + "条数据的起始年限[" + startYear + "]不能大于结束年限[" + endYear + "]"); throw new BusinessException("第" + (i + 1) + "条数据的起始年限[" + startYear + "]不能大于结束年限[" + endYear + "]");
}
// 校验有效时间起止顺序(新增)
if (dto.getEffectiveStart().isAfter(dto.getEffectiveEnd())) {
throw new BusinessException("第" + (i + 1) + "条数据的有效开始时间不能晚于有效结束时间");
} }
// 解析scope为集合,去重 // 解析scope为集合,去重
Set<String> scopeSet = ProductCommonUtils.parseScopeToSet(dto.getScope()); Set<String> scopeSet = ProductCommonUtils.parseScopeToSet(dto.getScope());
preparedList.add(new DtoWithParsedData(i, dto, startYear, endYear, scopeSet)); preparedList.add(new DtoWithParsedData(i, dto, startYear, endYear, scopeSet,
dto.getEffectiveStart(), dto.getEffectiveEnd()));
} }
return preparedList; return preparedList;
} }
/** /**
* 检查所有数据对的年限重叠情况 * 检查年限重叠(原有逻辑,完全不变)
*/ */
private List<OverlapError> checkAllDataPairs(List<DtoWithParsedData> preparedDataList) { private List<OverlapError> checkYearOverlap(List<DtoWithParsedData> preparedDataList) {
List<OverlapError> errors = new ArrayList<>(); List<OverlapError> errors = new ArrayList<>();
int n = preparedDataList.size(); int n = preparedDataList.size();
// 使用双重循环检查所有数据对
for (int i = 0; i < n - 1; i++) { for (int i = 0; i < n - 1; i++) {
DtoWithParsedData data1 = preparedDataList.get(i); DtoWithParsedData data1 = preparedDataList.get(i);
for (int j = i + 1; j < n; j++) { for (int j = i + 1; j < n; j++) {
DtoWithParsedData data2 = preparedDataList.get(j); DtoWithParsedData data2 = preparedDataList.get(j);
// 使用原有的分组条件(包含 effectiveStart/end 和 scope 交集)
// 检查是否属于同一分组条件(考虑scope交集) if (isSameGroupForYear(data1, data2)) {
if (isSameGroup(data1, data2)) { if (ProductCommonUtils.isYearRangeOverlap(data1.startYear, data1.endYear,
// 检查年限是否重叠 data2.startYear, data2.endYear)) {
if (ProductCommonUtils.isYearRangeOverlap(data1.startYear, data1.endYear, data2.startYear, data2.endYear)) { if (!isErrorAlreadyExists(errors, data1.originalIndex, data2.originalIndex, "YEAR")) {
// 避免重复添加相同的错误 errors.add(new OverlapError(data1.originalIndex, data2.originalIndex, "YEAR"));
if (!isErrorAlreadyExists(errors, data1.originalIndex, data2.originalIndex)) {
errors.add(new OverlapError(data1.originalIndex, data2.originalIndex));
} }
} }
} }
} }
} }
return errors;
}
/**
* 检查有效时间重叠(新增逻辑,使用排除 effectiveStart/end 的分组,但仍考虑 scope 交集)
*/
private List<OverlapError> checkEffectiveTimeOverlap(List<DtoWithParsedData> preparedDataList) {
List<OverlapError> errors = new ArrayList<>();
int n = preparedDataList.size();
for (int i = 0; i < n - 1; i++) {
DtoWithParsedData data1 = preparedDataList.get(i);
for (int j = i + 1; j < n; j++) {
DtoWithParsedData data2 = preparedDataList.get(j);
// 使用排除 effectiveStart/end 的分组条件,但仍然检查 scope 交集
if (isSameGroupForEffectiveTime(data1, data2)) {
if (isTimeRangeOverlap(data1.effectiveStart, data1.effectiveEnd,
data2.effectiveStart, data2.effectiveEnd)) {
if (!isErrorAlreadyExists(errors, data1.originalIndex, data2.originalIndex, "EFFECTIVE")) {
errors.add(new OverlapError(data1.originalIndex, data2.originalIndex, "EFFECTIVE"));
}
}
}
}
}
return errors; return errors;
} }
/** /**
* 判断两个数据是否属于同一分组条件 * 判断两个有效时间区间是否重叠
*/ */
private boolean isSameGroup(DtoWithParsedData data1, DtoWithParsedData data2) { private boolean isTimeRangeOverlap(LocalDateTime start1, LocalDateTime end1,
// 1. 检查除scope外的其他条件是否相同 LocalDateTime start2, LocalDateTime end2) {
return !(end1.isBefore(start2) || end2.isBefore(start1));
}
/**
* 原有的分组条件(包含 effectiveStart/end 和 scope 交集),用于年限重叠校验,保持不变
*/
private boolean isSameGroupForYear(DtoWithParsedData data1, DtoWithParsedData data2) {
// 1. 检查除scope外的其他条件是否相同(包含 effectiveStart/end)
if (!isSameGroupExceptScope(data1.dto, data2.dto)) { if (!isSameGroupExceptScope(data1.dto, data2.dto)) {
return false; return false;
} }
// 2. 检查scope是否有交集 // 2. 检查scope是否有交集
return ProductCommonUtils.hasScopeIntersection(data1.scopeSet, data2.scopeSet); return ProductCommonUtils.hasScopeIntersection(data1.scopeSet, data2.scopeSet);
} }
/** /**
* 检查除scope外的其他条件是否相同 * 原有的 isSameGroupExceptScope 方法,完全不变
*/ */
private boolean isSameGroupExceptScope(ApiAnnouncementCommissionRatioBatchSaveDto dto1, private boolean isSameGroupExceptScope(ApiAnnouncementCommissionRatioBatchSaveDto dto1,
ApiAnnouncementCommissionRatioBatchSaveDto dto2) { ApiAnnouncementCommissionRatioBatchSaveDto dto2) {
...@@ -335,7 +376,29 @@ public class ApiAnnouncementCommissionRatioServiceImpl implements ApiAnnouncemen ...@@ -335,7 +376,29 @@ public class ApiAnnouncementCommissionRatioServiceImpl implements ApiAnnouncemen
} }
/** /**
* 校验基础字段 * 新增:用于有效时间重叠校验的分组条件(排除 effectiveStart/end,但仍检查 scope 交集)
*/
private boolean isSameGroupForEffectiveTime(DtoWithParsedData data1, DtoWithParsedData data2) {
// 1. 检查排除 effectiveStart/end 后的其他条件是否相同
if (!isSameGroupExceptTimeAndScope(data1.dto, data2.dto)) {
return false;
}
// 2. 检查scope是否有交集
return ProductCommonUtils.hasScopeIntersection(data1.scopeSet, data2.scopeSet);
}
/**
* 检查排除 effectiveStart/end 和 scope 后的条件是否相同(仅业务分组字段)
*/
private boolean isSameGroupExceptTimeAndScope(ApiAnnouncementCommissionRatioBatchSaveDto dto1,
ApiAnnouncementCommissionRatioBatchSaveDto dto2) {
return Objects.equals(dto1.getExpenseName(), dto2.getExpenseName())
&& Objects.equals(dto1.getIsExchangeRate(), dto2.getIsExchangeRate())
&& Objects.equals(dto1.getCurrency(), dto2.getCurrency());
}
/**
* 校验基础字段(保留,未使用)
*/ */
private boolean validateBasicFields(ApiAnnouncementCommissionRatioBatchSaveDto dto) { private boolean validateBasicFields(ApiAnnouncementCommissionRatioBatchSaveDto dto) {
return dto.getExpenseName() != null && !dto.getExpenseName().trim().isEmpty() return dto.getExpenseName() != null && !dto.getExpenseName().trim().isEmpty()
...@@ -348,52 +411,21 @@ public class ApiAnnouncementCommissionRatioServiceImpl implements ApiAnnouncemen ...@@ -348,52 +411,21 @@ public class ApiAnnouncementCommissionRatioServiceImpl implements ApiAnnouncemen
} }
/** /**
* 检查错误是否已存在 * 检查错误是否已存在(区分类型)
*/ */
private boolean isErrorAlreadyExists(List<OverlapError> errors, int index1, int index2) { private boolean isErrorAlreadyExists(List<OverlapError> errors, int index1, int index2, String type) {
for (OverlapError error : errors) { for (OverlapError error : errors) {
if ((error.index1 == index1 && error.index2 == index2) || if (((error.index1 == index1 && error.index2 == index2) ||
(error.index1 == index2 && error.index2 == index1)) { (error.index1 == index2 && error.index2 == index1)) &&
error.type.equals(type)) {
return true; return true;
} }
} }
return false; return false;
} }
// /**
// * 构建错误消息
// */
// private String buildErrorMessage(List<OverlapError> errors,
// List<ApiAnnouncementCommissionRatioBatchSaveDto> originalList) {
// if (errors.isEmpty()) {
// return "未发现重叠数据";
// }
//
// StringBuilder sb = new StringBuilder();
//
// Set<Integer> set = new HashSet<>();
// if (!CollectionUtils.isEmpty(errors)) {
// errors.stream().forEach(dto -> {
// set.add(dto.getIndex1());
// set.add(dto.getIndex2());
// });
// }
//
// sb.append("发现佣金年限区间重叠的数据,请检查以下行数:\n\n");
//
// // 将行数(索引+1,因为用户从1开始计数)排序并格式化为"第X行"
// String rowNumbers = set.stream()
// .sorted()
// .map(index -> "第" + (index + 1) + "行")
// .collect(Collectors.joining(",")); // 用中文逗号分隔
//
// sb.append(rowNumbers);
//
// return sb.toString();
// }
/** /**
* 构建错误消息 * 构建错误消息(区分年限重叠和有效时间重叠)
*/ */
private String buildErrorMessage(List<OverlapError> errors, private String buildErrorMessage(List<OverlapError> errors,
List<ApiAnnouncementCommissionRatioBatchSaveDto> originalList) { List<ApiAnnouncementCommissionRatioBatchSaveDto> originalList) {
...@@ -401,72 +433,45 @@ public class ApiAnnouncementCommissionRatioServiceImpl implements ApiAnnouncemen ...@@ -401,72 +433,45 @@ public class ApiAnnouncementCommissionRatioServiceImpl implements ApiAnnouncemen
return "未发现重叠数据"; return "未发现重叠数据";
} }
StringBuilder sb = new StringBuilder(); // 按重叠类型分组
Map<String, Map<Integer, List<Integer>>> typeGroupMap = new LinkedHashMap<>();
// Set<Integer> set = new HashSet<>();
// if (!CollectionUtils.isEmpty(errors)) {
// errors.stream().forEach(dto -> {
// set.add(dto.getIndex1());
// set.add(dto.getIndex2());
// });
// }
sb.append("发现佣金年限区间重叠的数据,请检查以下数据:\n\n");
// sb.append("发现佣金年限区间重叠的数据,请检查以下行数:\n\n");
// sb.append(String.join("",set))
// // 按数据索引分组,方便查看每条数据的所有重叠关系
Map<Integer, List<Integer>> overlapMap = new TreeMap<>();
for (OverlapError error : errors) { for (OverlapError error : errors) {
overlapMap.computeIfAbsent(error.index1, k -> new ArrayList<>()).add(error.index2); typeGroupMap.computeIfAbsent(error.type, k -> new TreeMap<>())
overlapMap.computeIfAbsent(error.index2, k -> new ArrayList<>()).add(error.index1); .computeIfAbsent(error.index1, k -> new ArrayList<>()).add(error.index2);
typeGroupMap.get(error.type)
.computeIfAbsent(error.index2, k -> new ArrayList<>()).add(error.index1);
} }
// 构建错误信息 StringBuilder sb = new StringBuilder();
for (Map.Entry<String, Map<Integer, List<Integer>>> typeEntry : typeGroupMap.entrySet()) {
String overlapType = "YEAR".equals(typeEntry.getKey()) ? "佣金年限区间" : "有效时间区间";
sb.append("发现").append(overlapType).append("重叠的数据:\n");
Map<Integer, List<Integer>> overlapMap = typeEntry.getValue();
for (Map.Entry<Integer, List<Integer>> entry : overlapMap.entrySet()) { for (Map.Entry<Integer, List<Integer>> entry : overlapMap.entrySet()) {
int dataIndex = entry.getKey(); int dataIndex = entry.getKey();
List<Integer> overlapIndices = entry.getValue(); List<Integer> overlapIndices = entry.getValue();
ApiAnnouncementCommissionRatioBatchSaveDto dto = originalList.get(dataIndex); ApiAnnouncementCommissionRatioBatchSaveDto dto = originalList.get(dataIndex);
if ("YEAR".equals(typeEntry.getKey())) {
sb.append("第").append(dataIndex + 1).append("行数据年限区间") sb.append("第").append(dataIndex + 1).append("行数据年限区间 ")
// .append(" - 费用名称: ").append(dto.getExpenseName()).append("\n") .append(dto.getStartPeriod()).append("~").append(dto.getEndPeriod())
// .append(" - 年限区间: ").append(dto.getStartPeriod()).append(" 至 ").append(dto.getEndPeriod()).append("\n") .append(" 与以下数据年限区间重叠:");
// .append(" - 适用范围: ").append(dto.getScope()).append("\n") } else {
// .append(" - 有效时间: ").append(dto.getEffectiveStart()).append(" 至 ").append(dto.getEffectiveEnd()).append("\n") sb.append("第").append(dataIndex + 1).append("行数据有效时间 ")
// .append(" - 汇率影响: ").append(dto.getIsExchangeRate()).append("\n") .append(dto.getEffectiveStart()).append("~").append(dto.getEffectiveEnd())
// .append(" - 结算币种: ").append(dto.getCurrency()).append("\n") .append(" 与以下数据有效时间重叠:");
.append("与以下数据年限区间有重叠:"); }
for (int overlapIndex : overlapIndices) { for (int overlapIndex : overlapIndices) {
ApiAnnouncementCommissionRatioBatchSaveDto overlapDto = originalList.get(overlapIndex);
sb.append(" 第").append(overlapIndex + 1).append("行"); sb.append(" 第").append(overlapIndex + 1).append("行");
// .append(overlapDto.getExpenseName())
// .append(" [").append(overlapDto.getStartPeriod())
// .append("-").append(overlapDto.getEndPeriod()).append("]")
// .append(" 适用范围:").append(overlapDto.getScope()).append("\n");
} }
sb.append("\n"); sb.append("\n");
} }
sb.append("\n");
// 添加通用分组条件说明 }
// sb.append("重叠判断规则说明:\n");
// sb.append("1. 以下条件完全相同的数据才会被比较:\n");
// sb.append(" - 费用名称\n");
// sb.append(" - 有效开始时间\n");
// sb.append(" - 有效结束时间\n");
// sb.append(" - 是否受汇率影响\n");
// sb.append(" - 结算币种\n");
// sb.append("2. 适用范围只要有一个相同的值(交集)就视为相同分组条件\n");
// sb.append("3. 年限区间重叠判断规则:\n");
// sb.append(" - 1-3 和 3-5: 算重叠(因为有共同的3)\n");
// sb.append(" - 1-3 和 4-7: 不算重叠\n");
// sb.append(" - 1-5 和 2-4: 算重叠\n");
return sb.toString(); return sb.toString();
} }
/** /**
* 内部类:包含解析后数据的DTO * 内部类:包含解析后数据的DTO(增加有效时间字段)
*/ */
private static class DtoWithParsedData { private static class DtoWithParsedData {
final int originalIndex; // 在原始列表中的索引 final int originalIndex; // 在原始列表中的索引
...@@ -474,31 +479,34 @@ public class ApiAnnouncementCommissionRatioServiceImpl implements ApiAnnouncemen ...@@ -474,31 +479,34 @@ public class ApiAnnouncementCommissionRatioServiceImpl implements ApiAnnouncemen
final int startYear; // 解析后的起始年份 final int startYear; // 解析后的起始年份
final int endYear; // 解析后的结束年份 final int endYear; // 解析后的结束年份
final Set<String> scopeSet; // 解析后的scope集合 final Set<String> scopeSet; // 解析后的scope集合
final LocalDateTime effectiveStart; // 有效开始时间
final LocalDateTime effectiveEnd; // 有效结束时间
public DtoWithParsedData(int originalIndex, ApiAnnouncementCommissionRatioBatchSaveDto dto, public DtoWithParsedData(int originalIndex, ApiAnnouncementCommissionRatioBatchSaveDto dto,
int startYear, int endYear, Set<String> scopeSet) { int startYear, int endYear, Set<String> scopeSet,
LocalDateTime effectiveStart, LocalDateTime effectiveEnd) {
this.originalIndex = originalIndex; this.originalIndex = originalIndex;
this.dto = dto; this.dto = dto;
this.startYear = startYear; this.startYear = startYear;
this.endYear = endYear; this.endYear = endYear;
this.scopeSet = scopeSet; this.scopeSet = scopeSet;
this.effectiveStart = effectiveStart;
this.effectiveEnd = effectiveEnd;
} }
} }
/** /**
* 内部类:重叠错误 * 内部类:重叠错误(增加类型字段)
*/ */
private static class OverlapError { private static class OverlapError {
private final int index1; private final int index1;
private final int index2; private final int index2;
private final String type; // "YEAR" 或 "EFFECTIVE"
public OverlapError(int index1, int index2) { public OverlapError(int index1, int index2, String type) {
this.index1 = index1; this.index1 = index1;
this.index2 = index2; this.index2 = index2;
this.type = type;
} }
public int getIndex1() { return index1; }
public int getIndex2() { return index2; }
} }
} }
\ No newline at end of file
...@@ -10,14 +10,12 @@ import com.yd.product.api.service.ApiExpectedCommissionRatioService; ...@@ -10,14 +10,12 @@ import com.yd.product.api.service.ApiExpectedCommissionRatioService;
import com.yd.product.api.service.ApiExpectedSpeciesService; import com.yd.product.api.service.ApiExpectedSpeciesService;
import com.yd.product.api.utils.ProductCommonUtils; import com.yd.product.api.utils.ProductCommonUtils;
import com.yd.product.feign.dto.ApiExpectedCommissionRatioBatchSaveDto; import com.yd.product.feign.dto.ApiExpectedCommissionRatioBatchSaveDto;
import com.yd.product.feign.dto.ApiExpectedCommissionRatioBatchSaveDto;
import com.yd.product.feign.request.expectedcommissionratio.ApiExpectedCommissionRatioAddRequest; import com.yd.product.feign.request.expectedcommissionratio.ApiExpectedCommissionRatioAddRequest;
import com.yd.product.feign.request.expectedcommissionratio.ApiExpectedCommissionRatioBatchSaveRequest; import com.yd.product.feign.request.expectedcommissionratio.ApiExpectedCommissionRatioBatchSaveRequest;
import com.yd.product.feign.request.expectedcommissionratio.ApiExpectedCommissionRatioEditRequest; import com.yd.product.feign.request.expectedcommissionratio.ApiExpectedCommissionRatioEditRequest;
import com.yd.product.feign.request.expectedcommissionratio.ApiExpectedCommissionRatioPageRequest; import com.yd.product.feign.request.expectedcommissionratio.ApiExpectedCommissionRatioPageRequest;
import com.yd.product.feign.response.expectedcommissionratio.ApiExpectedCommissionRatioDetailResponse; import com.yd.product.feign.response.expectedcommissionratio.ApiExpectedCommissionRatioDetailResponse;
import com.yd.product.feign.response.expectedcommissionratio.ApiExpectedCommissionRatioPageResponse; import com.yd.product.feign.response.expectedcommissionratio.ApiExpectedCommissionRatioPageResponse;
import com.yd.product.service.model.AnnouncementCommissionRatio;
import com.yd.product.service.model.ExpectedCommissionRatio; import com.yd.product.service.model.ExpectedCommissionRatio;
import com.yd.product.service.service.IExpectedCommissionRatioService; import com.yd.product.service.service.IExpectedCommissionRatioService;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
...@@ -26,6 +24,7 @@ import org.springframework.beans.factory.annotation.Autowired; ...@@ -26,6 +24,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils; import org.springframework.util.CollectionUtils;
import java.time.LocalDateTime;
import java.util.*; import java.util.*;
import java.util.stream.Collectors; import java.util.stream.Collectors;
...@@ -70,7 +69,7 @@ public class ApiExpectedCommissionRatioServiceImpl implements ApiExpectedCommiss ...@@ -70,7 +69,7 @@ public class ApiExpectedCommissionRatioServiceImpl implements ApiExpectedCommiss
.stream() .stream()
.map(dto -> { .map(dto -> {
ExpectedCommissionRatio ratio = new ExpectedCommissionRatio(); ExpectedCommissionRatio ratio = new ExpectedCommissionRatio();
BeanUtils.copyProperties(dto,ratio); BeanUtils.copyProperties(dto, ratio);
ratio.setExpectedSpeciesBizId(request.getExpectedSpeciesBizId()); ratio.setExpectedSpeciesBizId(request.getExpectedSpeciesBizId());
ratio.setExpectedCommissionRatioBizId(RandomStringGenerator.generateBizId16(CommonEnum.UID_TYPE_EXPECTED_COMMISSION_RATIO.getCode())); ratio.setExpectedCommissionRatioBizId(RandomStringGenerator.generateBizId16(CommonEnum.UID_TYPE_EXPECTED_COMMISSION_RATIO.getCode()));
return ratio; return ratio;
...@@ -92,7 +91,7 @@ public class ApiExpectedCommissionRatioServiceImpl implements ApiExpectedCommiss ...@@ -92,7 +91,7 @@ public class ApiExpectedCommissionRatioServiceImpl implements ApiExpectedCommiss
//入参校验,佣金年限校验不同条件下的唯一性 TODO //入参校验,佣金年限校验不同条件下的唯一性 TODO
//新增 //新增
ExpectedCommissionRatio ratio = new ExpectedCommissionRatio(); ExpectedCommissionRatio ratio = new ExpectedCommissionRatio();
BeanUtils.copyProperties(request,ratio); BeanUtils.copyProperties(request, ratio);
ratio.setExpectedCommissionRatioBizId(RandomStringGenerator.generateBizId16(CommonEnum.UID_TYPE_EXPECTED_COMMISSION_RATIO.getCode())); ratio.setExpectedCommissionRatioBizId(RandomStringGenerator.generateBizId16(CommonEnum.UID_TYPE_EXPECTED_COMMISSION_RATIO.getCode()));
iExpectedCommissionRatioService.saveOrUpdate(ratio); iExpectedCommissionRatioService.saveOrUpdate(ratio);
return Result.success(); return Result.success();
...@@ -112,7 +111,7 @@ public class ApiExpectedCommissionRatioServiceImpl implements ApiExpectedCommiss ...@@ -112,7 +111,7 @@ public class ApiExpectedCommissionRatioServiceImpl implements ApiExpectedCommiss
apiExpectedSpeciesService.checkExpectedSpeciesIsExist(request.getExpectedSpeciesBizId()); apiExpectedSpeciesService.checkExpectedSpeciesIsExist(request.getExpectedSpeciesBizId());
//入参校验,佣金年限校验不同条件下的唯一性 TODO //入参校验,佣金年限校验不同条件下的唯一性 TODO
//编辑 //编辑
BeanUtils.copyProperties(request,ratio); BeanUtils.copyProperties(request, ratio);
iExpectedCommissionRatioService.saveOrUpdate(ratio); iExpectedCommissionRatioService.saveOrUpdate(ratio);
return Result.success(); return Result.success();
} }
...@@ -144,7 +143,7 @@ public class ApiExpectedCommissionRatioServiceImpl implements ApiExpectedCommiss ...@@ -144,7 +143,7 @@ public class ApiExpectedCommissionRatioServiceImpl implements ApiExpectedCommiss
Result<ExpectedCommissionRatio> result = checkExpectedCommissionRatioIsExist(expectedSpeciesBizId); Result<ExpectedCommissionRatio> result = checkExpectedCommissionRatioIsExist(expectedSpeciesBizId);
ExpectedCommissionRatio ratio = result.getData(); ExpectedCommissionRatio ratio = result.getData();
ApiExpectedCommissionRatioDetailResponse response = new ApiExpectedCommissionRatioDetailResponse(); ApiExpectedCommissionRatioDetailResponse response = new ApiExpectedCommissionRatioDetailResponse();
BeanUtils.copyProperties(ratio,response); BeanUtils.copyProperties(ratio, response);
return Result.success(response); return Result.success(response);
} }
...@@ -179,33 +178,40 @@ public class ApiExpectedCommissionRatioServiceImpl implements ApiExpectedCommiss ...@@ -179,33 +178,40 @@ public class ApiExpectedCommissionRatioServiceImpl implements ApiExpectedCommiss
} }
/** /**
* 校验入参-来佣比率规格明细列表 * 校验入参-来佣比率规格明细列表(年限区间和有效时间区间均不能重叠)
* @param ratioBatchSaveDtoList * @param ratioBatchSaveDtoList
* @return * @return
*/ */
public Result checkBatchSaveRequestPram(List<ApiExpectedCommissionRatioBatchSaveDto> ratioBatchSaveDtoList) { public Result checkBatchSaveRequestPram(List<ApiExpectedCommissionRatioBatchSaveDto> ratioBatchSaveDtoList) {
// 1. 验证并准备数据(增加有效时间字段)
List<DtoWithParsedData> preparedDataList = prepareData(ratioBatchSaveDtoList);
// 2. 检查所有数据对的年限重叠情况(原有逻辑,保持不变)
List<OverlapError> yearErrors = checkYearOverlap(preparedDataList);
// 1. 验证并准备数据 // 3. 检查所有数据对的有效时间重叠情况(新增逻辑,使用排除时间字段的业务分组)
List<ApiExpectedCommissionRatioServiceImpl.DtoWithParsedData> preparedDataList = prepareData(ratioBatchSaveDtoList); List<OverlapError> effectiveErrors = checkEffectiveTimeOverlap(preparedDataList);
// 2. 检查所有数据对的年限重叠情况 // 4. 合并错误
List<ApiExpectedCommissionRatioServiceImpl.OverlapError> errors = checkAllDataPairs(preparedDataList); List<OverlapError> allErrors = new ArrayList<>();
allErrors.addAll(yearErrors);
allErrors.addAll(effectiveErrors);
// 3. 如果有错误,返回错误信息 // 5. 如果有错误,返回错误信息
if (!errors.isEmpty()) { if (!allErrors.isEmpty()) {
String errorMsg = buildErrorMessage(errors, ratioBatchSaveDtoList); String errorMsg = buildErrorMessage(allErrors, ratioBatchSaveDtoList);
throw new BusinessException(1004,errorMsg); throw new BusinessException(1004, errorMsg);
} }
return Result.success(); return Result.success();
} }
/** /**
* 准备数据:解析年限并转换为集合 * 准备数据:解析年限、存储有效时间,并校验基本合法性
* @param dtoList * @param dtoList
* @return * @return
*/ */
private List<ApiExpectedCommissionRatioServiceImpl.DtoWithParsedData> prepareData(List<ApiExpectedCommissionRatioBatchSaveDto> dtoList) { private List<DtoWithParsedData> prepareData(List<ApiExpectedCommissionRatioBatchSaveDto> dtoList) {
List<ApiExpectedCommissionRatioServiceImpl.DtoWithParsedData> preparedList = new ArrayList<>(); List<DtoWithParsedData> preparedList = new ArrayList<>();
for (int i = 0; i < dtoList.size(); i++) { for (int i = 0; i < dtoList.size(); i++) {
ApiExpectedCommissionRatioBatchSaveDto dto = dtoList.get(i); ApiExpectedCommissionRatioBatchSaveDto dto = dtoList.get(i);
...@@ -218,56 +224,85 @@ public class ApiExpectedCommissionRatioServiceImpl implements ApiExpectedCommiss ...@@ -218,56 +224,85 @@ public class ApiExpectedCommissionRatioServiceImpl implements ApiExpectedCommiss
throw new BusinessException("第" + (i+1) + "条数据的起始年限[" + startYear + "]不能大于结束年限[" + endYear + "]"); throw new BusinessException("第" + (i+1) + "条数据的起始年限[" + startYear + "]不能大于结束年限[" + endYear + "]");
} }
preparedList.add(new ApiExpectedCommissionRatioServiceImpl.DtoWithParsedData(i, dto, startYear, endYear)); // 校验有效时间起止顺序(新增)
if (dto.getEffectiveStart().isAfter(dto.getEffectiveEnd())) {
throw new BusinessException("第" + (i+1) + "条数据的有效开始时间不能晚于有效结束时间");
}
preparedList.add(new DtoWithParsedData(i, dto, startYear, endYear,
dto.getEffectiveStart(), dto.getEffectiveEnd()));
} }
return preparedList; return preparedList;
} }
/** /**
* 检查所有数据对的年限重叠情况 * 检查年限重叠(原有逻辑,完全不变)
*/ */
private List<ApiExpectedCommissionRatioServiceImpl.OverlapError> checkAllDataPairs(List<ApiExpectedCommissionRatioServiceImpl.DtoWithParsedData> preparedDataList) { private List<OverlapError> checkYearOverlap(List<DtoWithParsedData> preparedDataList) {
List<ApiExpectedCommissionRatioServiceImpl.OverlapError> errors = new ArrayList<>(); List<OverlapError> errors = new ArrayList<>();
int n = preparedDataList.size(); int n = preparedDataList.size();
// 使用双重循环检查所有数据对
for (int i = 0; i < n - 1; i++) { for (int i = 0; i < n - 1; i++) {
ApiExpectedCommissionRatioServiceImpl.DtoWithParsedData data1 = preparedDataList.get(i); DtoWithParsedData data1 = preparedDataList.get(i);
for (int j = i + 1; j < n; j++) { for (int j = i + 1; j < n; j++) {
ApiExpectedCommissionRatioServiceImpl.DtoWithParsedData data2 = preparedDataList.get(j); DtoWithParsedData data2 = preparedDataList.get(j);
// 使用原有的分组条件(包含 effectiveStart/end)
// 检查是否属于同一分组条件 if (isSameGroupForYear(data1, data2)) {
if (isSameGroup(data1, data2)) { if (ProductCommonUtils.isYearRangeOverlap(data1.startYear, data1.endYear,
// 检查年限是否重叠 data2.startYear, data2.endYear)) {
if (ProductCommonUtils.isYearRangeOverlap(data1.startYear, data1.endYear, data2.startYear, data2.endYear)) { if (!isErrorAlreadyExists(errors, data1.originalIndex, data2.originalIndex, "YEAR")) {
// 避免重复添加相同的错误 errors.add(new OverlapError(data1.originalIndex, data2.originalIndex, "YEAR"));
if (!isErrorAlreadyExists(errors, data1.originalIndex, data2.originalIndex)) {
errors.add(new ApiExpectedCommissionRatioServiceImpl.OverlapError(data1.originalIndex, data2.originalIndex));
} }
} }
} }
} }
} }
return errors;
}
/**
* 检查有效时间重叠(新增逻辑,使用排除时间字段的业务分组)
*/
private List<OverlapError> checkEffectiveTimeOverlap(List<DtoWithParsedData> preparedDataList) {
List<OverlapError> errors = new ArrayList<>();
int n = preparedDataList.size();
for (int i = 0; i < n - 1; i++) {
DtoWithParsedData data1 = preparedDataList.get(i);
for (int j = i + 1; j < n; j++) {
DtoWithParsedData data2 = preparedDataList.get(j);
// 使用排除时间字段的分组条件(expenseName, isExchangeRate, currency, reconciliationCompany)
if (isSameGroupForEffectiveTime(data1.dto, data2.dto)) {
if (isTimeRangeOverlap(data1.effectiveStart, data1.effectiveEnd,
data2.effectiveStart, data2.effectiveEnd)) {
if (!isErrorAlreadyExists(errors, data1.originalIndex, data2.originalIndex, "EFFECTIVE")) {
errors.add(new OverlapError(data1.originalIndex, data2.originalIndex, "EFFECTIVE"));
}
}
}
}
}
return errors; return errors;
} }
/** /**
* 判断两个数据是否属于同一分组条件 * 判断两个有效时间区间是否重叠
*/ */
private boolean isSameGroup(ApiExpectedCommissionRatioServiceImpl.DtoWithParsedData data1, ApiExpectedCommissionRatioServiceImpl.DtoWithParsedData data2) { private boolean isTimeRangeOverlap(LocalDateTime start1, LocalDateTime end1,
// 1. 检查条件是否相同 LocalDateTime start2, LocalDateTime end2) {
if (!isSameGroupExcept(data1.dto, data2.dto)) { return !(end1.isBefore(start2) || end2.isBefore(start1));
return false;
} }
return true; /**
* 原有的分组条件(包含有效开始/结束时间),用于年限重叠校验,保持不变
*/
private boolean isSameGroupForYear(DtoWithParsedData data1, DtoWithParsedData data2) {
return isSameGroupExcept(data1.dto, data2.dto);
} }
/** /**
* 检查条件是否相同 * 原有的 isSameGroupExcept 方法,完全不变
*/ */
private boolean isSameGroupExcept(ApiExpectedCommissionRatioBatchSaveDto dto1, private boolean isSameGroupExcept(ApiExpectedCommissionRatioBatchSaveDto dto1,
ApiExpectedCommissionRatioBatchSaveDto dto2) { ApiExpectedCommissionRatioBatchSaveDto dto2) {
...@@ -280,12 +315,24 @@ public class ApiExpectedCommissionRatioServiceImpl implements ApiExpectedCommiss ...@@ -280,12 +315,24 @@ public class ApiExpectedCommissionRatioServiceImpl implements ApiExpectedCommiss
} }
/** /**
* 检查错误是否已存在 * 新增:用于有效时间重叠校验的分组条件(排除 effectiveStart/end)
*/ */
private boolean isErrorAlreadyExists(List<ApiExpectedCommissionRatioServiceImpl.OverlapError> errors, int index1, int index2) { private boolean isSameGroupForEffectiveTime(ApiExpectedCommissionRatioBatchSaveDto dto1,
for (ApiExpectedCommissionRatioServiceImpl.OverlapError error : errors) { ApiExpectedCommissionRatioBatchSaveDto dto2) {
if ((error.index1 == index1 && error.index2 == index2) || return Objects.equals(dto1.getExpenseName(), dto2.getExpenseName())
(error.index1 == index2 && error.index2 == index1)) { && Objects.equals(dto1.getIsExchangeRate(), dto2.getIsExchangeRate())
&& Objects.equals(dto1.getCurrency(), dto2.getCurrency())
&& Objects.equals(dto1.getReconciliationCompany(), dto2.getReconciliationCompany());
}
/**
* 检查错误是否已存在(区分类型)
*/
private boolean isErrorAlreadyExists(List<OverlapError> errors, int index1, int index2, String type) {
for (OverlapError error : errors) {
if (((error.index1 == index1 && error.index2 == index2) ||
(error.index1 == index2 && error.index2 == index1)) &&
error.type.equals(type)) {
return true; return true;
} }
} }
...@@ -293,76 +340,87 @@ public class ApiExpectedCommissionRatioServiceImpl implements ApiExpectedCommiss ...@@ -293,76 +340,87 @@ public class ApiExpectedCommissionRatioServiceImpl implements ApiExpectedCommiss
} }
/** /**
* 构建错误消息 * 构建错误消息(区分年限重叠和有效时间重叠)
*/ */
private String buildErrorMessage(List<ApiExpectedCommissionRatioServiceImpl.OverlapError> errors, private String buildErrorMessage(List<OverlapError> errors,
List<ApiExpectedCommissionRatioBatchSaveDto> originalList) { List<ApiExpectedCommissionRatioBatchSaveDto> originalList) {
if (errors.isEmpty()) { if (errors.isEmpty()) {
return "未发现重叠数据"; return "未发现重叠数据";
} }
StringBuilder sb = new StringBuilder(); // 按重叠类型分组
Map<String, Map<Integer, List<Integer>>> typeGroupMap = new LinkedHashMap<>();
sb.append("发现佣金年限区间重叠的数据,请检查以下数据:\n\n"); for (OverlapError error : errors) {
Map<Integer, List<Integer>> overlapMap = new TreeMap<>(); typeGroupMap.computeIfAbsent(error.type, k -> new TreeMap<>())
.computeIfAbsent(error.index1, k -> new ArrayList<>()).add(error.index2);
for (ApiExpectedCommissionRatioServiceImpl.OverlapError error : errors) { typeGroupMap.get(error.type)
overlapMap.computeIfAbsent(error.index1, k -> new ArrayList<>()).add(error.index2); .computeIfAbsent(error.index2, k -> new ArrayList<>()).add(error.index1);
overlapMap.computeIfAbsent(error.index2, k -> new ArrayList<>()).add(error.index1);
} }
// 构建错误信息 StringBuilder sb = new StringBuilder();
for (Map.Entry<String, Map<Integer, List<Integer>>> typeEntry : typeGroupMap.entrySet()) {
String overlapType = "YEAR".equals(typeEntry.getKey()) ? "佣金年限区间" : "有效时间区间";
sb.append("发现").append(overlapType).append("重叠的数据:\n");
Map<Integer, List<Integer>> overlapMap = typeEntry.getValue();
for (Map.Entry<Integer, List<Integer>> entry : overlapMap.entrySet()) { for (Map.Entry<Integer, List<Integer>> entry : overlapMap.entrySet()) {
int dataIndex = entry.getKey(); int dataIndex = entry.getKey();
List<Integer> overlapIndices = entry.getValue(); List<Integer> overlapIndices = entry.getValue();
ApiExpectedCommissionRatioBatchSaveDto dto = originalList.get(dataIndex); ApiExpectedCommissionRatioBatchSaveDto dto = originalList.get(dataIndex);
if ("YEAR".equals(typeEntry.getKey())) {
sb.append("第").append(dataIndex + 1).append("行数据年限区间") sb.append("第").append(dataIndex + 1).append("行数据年限区间 ")
.append("与以下数据年限区间有重叠:"); .append(dto.getStartPeriod()).append("~").append(dto.getEndPeriod())
.append(" 与以下数据年限区间重叠:");
} else {
sb.append("第").append(dataIndex + 1).append("行数据有效时间 ")
.append(dto.getEffectiveStart()).append("~").append(dto.getEffectiveEnd())
.append(" 与以下数据有效时间重叠:");
}
for (int overlapIndex : overlapIndices) { for (int overlapIndex : overlapIndices) {
ApiExpectedCommissionRatioBatchSaveDto overlapDto = originalList.get(overlapIndex);
sb.append(" 第").append(overlapIndex + 1).append("行"); sb.append(" 第").append(overlapIndex + 1).append("行");
} }
sb.append("\n"); sb.append("\n");
} }
sb.append("\n");
}
return sb.toString(); return sb.toString();
} }
/** /**
* 内部类:包含解析后数据的DTO * 内部类:包含解析后数据的DTO(增加有效时间字段)
*/ */
private static class DtoWithParsedData { private static class DtoWithParsedData {
final int originalIndex; // 在原始列表中的索引 final int originalIndex; // 在原始列表中的索引
final ApiExpectedCommissionRatioBatchSaveDto dto; // 原始DTO final ApiExpectedCommissionRatioBatchSaveDto dto; // 原始DTO
final int startYear; // 解析后的起始年份 final int startYear; // 解析后的起始年份
final int endYear; // 解析后的结束年份 final int endYear; // 解析后的结束年份
final LocalDateTime effectiveStart; // 有效开始时间
final LocalDateTime effectiveEnd; // 有效结束时间
public DtoWithParsedData(int originalIndex, ApiExpectedCommissionRatioBatchSaveDto dto, public DtoWithParsedData(int originalIndex, ApiExpectedCommissionRatioBatchSaveDto dto,
int startYear, int endYear) { int startYear, int endYear,
LocalDateTime effectiveStart, LocalDateTime effectiveEnd) {
this.originalIndex = originalIndex; this.originalIndex = originalIndex;
this.dto = dto; this.dto = dto;
this.startYear = startYear; this.startYear = startYear;
this.endYear = endYear; this.endYear = endYear;
this.effectiveStart = effectiveStart;
this.effectiveEnd = effectiveEnd;
} }
} }
/** /**
* 内部类:重叠错误 * 内部类:重叠错误(增加类型字段)
*/ */
private static class OverlapError { private static class OverlapError {
private final int index1; private final int index1;
private final int index2; private final int index2;
private final String type; // "YEAR" 或 "EFFECTIVE"
public OverlapError(int index1, int index2) { public OverlapError(int index1, int index2, String type) {
this.index1 = index1; this.index1 = index1;
this.index2 = index2; this.index2 = index2;
this.type = type;
} }
public int getIndex1() { return index1; }
public int getIndex2() { return index2; }
} }
/** /**
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment