Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
Y
yd-product
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
xingmin
yd-product
Commits
7f382e6e
Commit
7f382e6e
authored
Dec 12, 2025
by
zhangxingmin
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
push
parent
29d6a4cd
Show whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
345 additions
and
4 deletions
+345
-4
yd-product-api/src/main/java/com/yd/product/api/service/impl/ApiAnnouncementCommissionRatioServiceImpl.java
+254
-3
yd-product-api/src/main/java/com/yd/product/api/utils/ProductCommonUtils.java
+87
-0
yd-product-feign/src/main/java/com/yd/product/feign/dto/ApiAnnouncementCommissionRatioBatchSaveDto.java
+4
-1
No files found.
yd-product-api/src/main/java/com/yd/product/api/service/impl/ApiAnnouncementCommissionRatioServiceImpl.java
View file @
7f382e6e
...
...
@@ -8,6 +8,8 @@ import com.yd.common.result.Result;
import
com.yd.common.utils.RandomStringGenerator
;
import
com.yd.product.api.service.ApiAnnouncementCommissionRatioService
;
import
com.yd.product.api.service.ApiAnnouncementSpeciesService
;
import
com.yd.product.api.utils.ProductCommonUtils
;
import
com.yd.product.feign.dto.ApiAnnouncementCommissionRatioBatchSaveDto
;
import
com.yd.product.feign.request.announcementcommissionratio.ApiAnnouncementCommissionRatioBatchSaveRequest
;
import
com.yd.product.feign.request.announcementcommissionratio.ApiAnnouncementCommissionRatioEditRequest
;
import
com.yd.product.feign.request.announcementcommissionratio.ApiAnnouncementCommissionRatioPageRequest
;
...
...
@@ -22,9 +24,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import
org.springframework.stereotype.Service
;
import
org.springframework.util.CollectionUtils
;
import
java.util.ArrayList
;
import
java.util.List
;
import
java.util.Objects
;
import
java.util.*
;
import
java.util.stream.Collectors
;
@Slf4j
...
...
@@ -173,4 +173,255 @@ public class ApiAnnouncementCommissionRatioServiceImpl implements ApiAnnouncemen
return
Result
.
success
(
announcementCommissionRatio
);
}
// /**
// * 校验入参-公告佣比率规格明细列表
// * @param ratioBatchSaveDtoList
// * @return
// */
// public Result checkBatchSaveRequestPram(List<ApiAnnouncementCommissionRatioBatchSaveDto> ratioBatchSaveDtoList) {
// //校验ratioBatchSaveDtoList入参对象里面费用名称、有效开始时间、有效结束时间、适用范围、是否受汇率影响、结算币种都一样的数据情况下,判断佣金年限(起)- 佣金年限(止)区间是否有重叠情况,然后抛出异常提示哪几条数据有重叠情况。比如都一样的数据情况下,两条数据的判断佣金年限(起)- 佣金年限(止)区间一个是1-3、3-5年也算重叠,只有1-3、4-7不算重叠)
// return null;
// }
/**
* 校验入参-公告佣比率规格明细列表
* @param ratioBatchSaveDtoList
* @return
*/
public
Result
checkBatchSaveRequestPram
(
List
<
ApiAnnouncementCommissionRatioBatchSaveDto
>
ratioBatchSaveDtoList
)
{
if
(
ratioBatchSaveDtoList
==
null
||
ratioBatchSaveDtoList
.
isEmpty
())
{
return
Result
.
success
(
"数据为空,无需校验"
);
}
try
{
// 1. 验证并准备数据
List
<
DtoWithParsedData
>
preparedDataList
=
prepareData
(
ratioBatchSaveDtoList
);
if
(
preparedDataList
==
null
)
{
return
Result
.
fail
(
"数据准备失败,请检查输入数据"
);
}
// 2. 检查所有数据对的年限重叠情况(考虑scope交集)
List
<
OverlapError
>
errors
=
checkAllDataPairs
(
preparedDataList
);
// 3. 如果有错误,返回错误信息
if
(!
errors
.
isEmpty
())
{
String
errorMsg
=
buildErrorMessage
(
errors
,
ratioBatchSaveDtoList
);
return
Result
.
fail
(
errorMsg
);
}
return
Result
.
success
(
"校验通过,无重叠数据"
);
}
catch
(
Exception
e
)
{
return
Result
.
fail
(
"数据校验异常:"
+
e
.
getMessage
());
}
}
/**
* 准备数据:解析年限并将scope转换为集合
* @param dtoList
* @return
*/
private
List
<
DtoWithParsedData
>
prepareData
(
List
<
ApiAnnouncementCommissionRatioBatchSaveDto
>
dtoList
)
{
List
<
DtoWithParsedData
>
preparedList
=
new
ArrayList
<>();
for
(
int
i
=
0
;
i
<
dtoList
.
size
();
i
++)
{
ApiAnnouncementCommissionRatioBatchSaveDto
dto
=
dtoList
.
get
(
i
);
// 解析年限
Integer
startYear
=
ProductCommonUtils
.
parseYearToInt
(
dto
.
getStartPeriod
());
Integer
endYear
=
ProductCommonUtils
.
parseYearToInt
(
dto
.
getEndPeriod
());
if
(
startYear
>
endYear
)
{
throw
new
BusinessException
(
"第"
+
(
i
+
1
)
+
"条数据的起始年限["
+
startYear
+
"]不能大于结束年限["
+
endYear
+
"]"
);
}
// 解析scope为集合,去重
Set
<
String
>
scopeSet
=
ProductCommonUtils
.
parseScopeToSet
(
dto
.
getScope
());
preparedList
.
add
(
new
DtoWithParsedData
(
i
,
dto
,
startYear
,
endYear
,
scopeSet
));
}
return
preparedList
;
}
/**
* 检查所有数据对的年限重叠情况
*/
private
List
<
OverlapError
>
checkAllDataPairs
(
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
);
// 检查是否属于同一分组条件(考虑scope交集)
if
(
isSameGroup
(
data1
,
data2
))
{
// 检查年限是否重叠
if
(
ProductCommonUtils
.
isYearRangeOverlap
(
data1
.
startYear
,
data1
.
endYear
,
data2
.
startYear
,
data2
.
endYear
))
{
// 避免重复添加相同的错误
if
(!
isErrorAlreadyExists
(
errors
,
data1
.
originalIndex
,
data2
.
originalIndex
))
{
errors
.
add
(
new
OverlapError
(
data1
.
originalIndex
,
data2
.
originalIndex
));
}
}
}
}
}
return
errors
;
}
/**
* 判断两个数据是否属于同一分组条件
*/
private
boolean
isSameGroup
(
DtoWithParsedData
data1
,
DtoWithParsedData
data2
)
{
// 1. 检查除scope外的其他条件是否相同
if
(!
isSameGroupExceptScope
(
data1
.
dto
,
data2
.
dto
))
{
return
false
;
}
// 2. 检查scope是否有交集
return
ProductCommonUtils
.
hasScopeIntersection
(
data1
.
scopeSet
,
data2
.
scopeSet
);
}
/**
* 检查除scope外的其他条件是否相同
*/
private
boolean
isSameGroupExceptScope
(
ApiAnnouncementCommissionRatioBatchSaveDto
dto1
,
ApiAnnouncementCommissionRatioBatchSaveDto
dto2
)
{
return
Objects
.
equals
(
dto1
.
getExpenseName
(),
dto2
.
getExpenseName
())
&&
Objects
.
equals
(
dto1
.
getEffectiveStart
(),
dto2
.
getEffectiveStart
())
&&
Objects
.
equals
(
dto1
.
getEffectiveEnd
(),
dto2
.
getEffectiveEnd
())
&&
Objects
.
equals
(
dto1
.
getIsExchangeRate
(),
dto2
.
getIsExchangeRate
())
&&
Objects
.
equals
(
dto1
.
getCurrency
(),
dto2
.
getCurrency
());
}
/**
* 校验基础字段
*/
private
boolean
validateBasicFields
(
ApiAnnouncementCommissionRatioBatchSaveDto
dto
)
{
return
dto
.
getExpenseName
()
!=
null
&&
!
dto
.
getExpenseName
().
trim
().
isEmpty
()
&&
dto
.
getEffectiveStart
()
!=
null
&&
dto
.
getEffectiveEnd
()
!=
null
&&
dto
.
getEffectiveStart
().
isBefore
(
dto
.
getEffectiveEnd
())
&&
dto
.
getScope
()
!=
null
&&
!
dto
.
getScope
().
trim
().
isEmpty
()
&&
dto
.
getIsExchangeRate
()
!=
null
&&
!
dto
.
getIsExchangeRate
().
trim
().
isEmpty
()
&&
dto
.
getCurrency
()
!=
null
&&
!
dto
.
getCurrency
().
trim
().
isEmpty
();
}
/**
* 检查错误是否已存在
*/
private
boolean
isErrorAlreadyExists
(
List
<
OverlapError
>
errors
,
int
index1
,
int
index2
)
{
for
(
OverlapError
error
:
errors
)
{
if
((
error
.
index1
==
index1
&&
error
.
index2
==
index2
)
||
(
error
.
index1
==
index2
&&
error
.
index2
==
index1
))
{
return
true
;
}
}
return
false
;
}
/**
* 构建错误消息
*/
private
String
buildErrorMessage
(
List
<
OverlapError
>
errors
,
List
<
ApiAnnouncementCommissionRatioBatchSaveDto
>
originalList
)
{
if
(
errors
.
isEmpty
())
{
return
"未发现重叠数据"
;
}
StringBuilder
sb
=
new
StringBuilder
();
sb
.
append
(
"发现佣金年限区间重叠的数据,请检查以下数据(只要适用范围有交集就视为相同分组条件):\n\n"
);
// 按数据索引分组,方便查看每条数据的所有重叠关系
Map
<
Integer
,
List
<
Integer
>>
overlapMap
=
new
TreeMap
<>();
for
(
OverlapError
error
:
errors
)
{
overlapMap
.
computeIfAbsent
(
error
.
index1
,
k
->
new
ArrayList
<>()).
add
(
error
.
index2
);
overlapMap
.
computeIfAbsent
(
error
.
index2
,
k
->
new
ArrayList
<>()).
add
(
error
.
index1
);
}
// 构建错误信息
for
(
Map
.
Entry
<
Integer
,
List
<
Integer
>>
entry
:
overlapMap
.
entrySet
())
{
int
dataIndex
=
entry
.
getKey
();
List
<
Integer
>
overlapIndices
=
entry
.
getValue
();
ApiAnnouncementCommissionRatioBatchSaveDto
dto
=
originalList
.
get
(
dataIndex
);
sb
.
append
(
"第"
).
append
(
dataIndex
+
1
).
append
(
"条数据:\n"
)
.
append
(
" - 费用名称: "
).
append
(
dto
.
getExpenseName
()).
append
(
"\n"
)
.
append
(
" - 年限区间: "
).
append
(
dto
.
getStartPeriod
()).
append
(
" 至 "
).
append
(
dto
.
getEndPeriod
()).
append
(
"\n"
)
.
append
(
" - 适用范围: "
).
append
(
dto
.
getScope
()).
append
(
"\n"
)
.
append
(
" - 有效时间: "
).
append
(
dto
.
getEffectiveStart
()).
append
(
" 至 "
).
append
(
dto
.
getEffectiveEnd
()).
append
(
"\n"
)
.
append
(
" - 汇率影响: "
).
append
(
dto
.
getIsExchangeRate
()).
append
(
"\n"
)
.
append
(
" - 结算币种: "
).
append
(
dto
.
getCurrency
()).
append
(
"\n"
)
.
append
(
" 与以下数据重叠:\n"
);
for
(
int
overlapIndex
:
overlapIndices
)
{
ApiAnnouncementCommissionRatioBatchSaveDto
overlapDto
=
originalList
.
get
(
overlapIndex
);
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
(
"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
();
}
/**
* 内部类:包含解析后数据的DTO
*/
private
static
class
DtoWithParsedData
{
final
int
originalIndex
;
// 在原始列表中的索引
final
ApiAnnouncementCommissionRatioBatchSaveDto
dto
;
// 原始DTO
final
int
startYear
;
// 解析后的起始年份
final
int
endYear
;
// 解析后的结束年份
final
Set
<
String
>
scopeSet
;
// 解析后的scope集合
public
DtoWithParsedData
(
int
originalIndex
,
ApiAnnouncementCommissionRatioBatchSaveDto
dto
,
int
startYear
,
int
endYear
,
Set
<
String
>
scopeSet
)
{
this
.
originalIndex
=
originalIndex
;
this
.
dto
=
dto
;
this
.
startYear
=
startYear
;
this
.
endYear
=
endYear
;
this
.
scopeSet
=
scopeSet
;
}
}
/**
* 内部类:重叠错误
*/
private
static
class
OverlapError
{
private
final
int
index1
;
private
final
int
index2
;
public
OverlapError
(
int
index1
,
int
index2
)
{
this
.
index1
=
index1
;
this
.
index2
=
index2
;
}
public
int
getIndex1
()
{
return
index1
;
}
public
int
getIndex2
()
{
return
index2
;
}
}
}
yd-product-api/src/main/java/com/yd/product/api/utils/ProductCommonUtils.java
0 → 100644
View file @
7f382e6e
package
com
.
yd
.
product
.
api
.
utils
;
import
java.util.Arrays
;
import
java.util.HashSet
;
import
java.util.Set
;
import
java.util.stream.Collectors
;
public
class
ProductCommonUtils
{
/**
* 解析年限字符串为整数
* @param yearStr
* @return
*/
public
static
Integer
parseYearToInt
(
String
yearStr
)
{
if
(
yearStr
==
null
||
yearStr
.
trim
().
isEmpty
())
{
return
null
;
}
try
{
// 提取数字部分,支持"1"、"1年"、"第1年"等格式
String
numericPart
=
yearStr
.
replaceAll
(
"[^0-9]"
,
""
).
trim
();
if
(
numericPart
.
isEmpty
())
{
return
null
;
}
return
Integer
.
parseInt
(
numericPart
);
}
catch
(
NumberFormatException
e
)
{
return
null
;
}
}
/**
* 检查年限区间是否重叠
* 根据需求:1-3和3-5算重叠,1-3和4-7不算重叠
* @param start1
* @param end1
* @param start2
* @param end2
* @return
*/
public
static
boolean
isYearRangeOverlap
(
int
start1
,
int
end1
,
int
start2
,
int
end2
)
{
// 两个区间重叠的条件:区间1的结束年份 >= 区间2的开始年份
// 例如:1-3和3-5重叠(3>=3),1-3和4-7不重叠(3<4)
return
Math
.
max
(
start1
,
start2
)
<=
Math
.
min
(
end1
,
end2
);
}
/**
* 将scope字符串解析为集合
* @param scope
* @return
*/
public
static
Set
<
String
>
parseScopeToSet
(
String
scope
)
{
if
(
scope
==
null
||
scope
.
trim
().
isEmpty
())
{
return
new
HashSet
<>();
}
return
Arrays
.
stream
(
scope
.
split
(
";"
))
.
map
(
String:
:
trim
)
.
filter
(
s
->
!
s
.
isEmpty
())
.
collect
(
Collectors
.
toSet
());
}
/**
* 检查两个scope集合是否有交集
*/
public
static
boolean
hasScopeIntersection
(
Set
<
String
>
scopeSet1
,
Set
<
String
>
scopeSet2
)
{
// 特殊情况处理
if
(
scopeSet1
.
isEmpty
()
||
scopeSet2
.
isEmpty
())
{
return
false
;
}
// 如果任一集合包含"全部",则视为有交集
if
(
scopeSet1
.
contains
(
"全部"
)
||
scopeSet2
.
contains
(
"全部"
))
{
return
true
;
}
// 检查是否有共同元素
for
(
String
item
:
scopeSet1
)
{
if
(
scopeSet2
.
contains
(
item
))
{
return
true
;
}
}
return
false
;
}
}
yd-product-feign/src/main/java/com/yd/product/feign/dto/ApiAnnouncementCommissionRatioBatchSaveDto.java
View file @
7f382e6e
package
com
.
yd
.
product
.
feign
.
dto
;
import
com.fasterxml.jackson.annotation.JsonFormat
;
import
lombok.Data
;
import
javax.validation.constraints.NotBlank
;
...
...
@@ -43,17 +44,19 @@ public class ApiAnnouncementCommissionRatioBatchSaveDto {
/**
* 有效开始时间
*/
@JsonFormat
(
pattern
=
"yyyy-MM-dd"
)
@NotNull
(
message
=
"有效开始时间不能为空"
)
private
LocalDateTime
effectiveStart
;
/**
* 有效结束时间
*/
@JsonFormat
(
pattern
=
"yyyy-MM-dd"
)
@NotNull
(
message
=
"有效结束时间不能为空"
)
private
LocalDateTime
effectiveEnd
;
/**
* 适用范围(经纪人/分销员/加盟商/签单员/转介人/全部,字典)
* 适用范围(经纪人/分销员/加盟商/签单员/转介人/全部,字典
,多选多个用分号分隔
)
*/
@NotBlank
(
message
=
"适用范围不能为空"
)
private
String
scope
;
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment