Commit 5ff2c5252d6b641ed1a15d7a19da8e5f197ca991
1 parent
d833d181
feature(*): 并列排名计算
并列排名计算
Showing
12 changed files
with
573 additions
and
63 deletions
fw-morax-dao/src/main/java/cn/fw/morax/dao/eval/EvalGroupRewardRankLogDao.java
0 → 100644
1 | +package cn.fw.morax.dao.eval; | |
2 | + | |
3 | + | |
4 | +import cn.fw.morax.domain.db.eval.EvalGroupRewardRankLog; | |
5 | +import com.baomidou.mybatisplus.core.mapper.BaseMapper; | |
6 | + | |
7 | +/** | |
8 | + * <p> | |
9 | + * 考评指标达成目标记录 Mapper 接口 | |
10 | + * </p> | |
11 | + * | |
12 | + * @author jiangchao | |
13 | + * @since 2022-12-09 | |
14 | + */ | |
15 | +public interface EvalGroupRewardRankLogDao extends BaseMapper<EvalGroupRewardRankLog> { | |
16 | + | |
17 | + | |
18 | +} | ... | ... |
fw-morax-domain/src/main/java/cn/fw/morax/domain/db/eval/EvalGroupRewardRankLog.java
0 → 100644
1 | +package cn.fw.morax.domain.db.eval; | |
2 | + | |
3 | +import cn.fw.common.data.entity.BaseAuditableTimeEntity; | |
4 | +import cn.fw.morax.domain.dto.eval.EvalGroupIndicatorPreconditionLaddersDTO; | |
5 | +import cn.fw.morax.domain.enums.EvalScopeEnum; | |
6 | +import cn.fw.morax.domain.enums.IndicatorTypeEnum; | |
7 | +import cn.fw.morax.domain.enums.RankIndicatorTypeEnum; | |
8 | +import com.baomidou.mybatisplus.annotation.TableName; | |
9 | +import lombok.*; | |
10 | + | |
11 | +import java.math.BigDecimal; | |
12 | +import java.time.LocalDate; | |
13 | + | |
14 | +/** | |
15 | + * <p> | |
16 | + * 奖惩排名日志 | |
17 | + * </p> | |
18 | + * | |
19 | + * @author jiangchao | |
20 | + * @since 2022-12-13 | |
21 | + */ | |
22 | +@Data | |
23 | +@EqualsAndHashCode(callSuper = false) | |
24 | +@TableName(autoResultMap = true) | |
25 | +@AllArgsConstructor | |
26 | +@NoArgsConstructor | |
27 | +@Builder | |
28 | +public class EvalGroupRewardRankLog extends BaseAuditableTimeEntity<EvalGroupRewardRankLog, Long> | |
29 | + implements Comparable<EvalGroupRewardRankLog>{ | |
30 | + | |
31 | + private static final long serialVersionUID = 1L; | |
32 | + | |
33 | + /** | |
34 | + * 员工id | |
35 | + */ | |
36 | + private Long poolId; | |
37 | + | |
38 | + /** | |
39 | + * 考评范围; 1:门店考评 2:人员考评 | |
40 | + */ | |
41 | + private EvalScopeEnum scopeType; | |
42 | + | |
43 | + /** | |
44 | + * 考评奖惩 前置条件 配置id | |
45 | + */ | |
46 | + private Long referId; | |
47 | + /** | |
48 | + * 指标类型 1.奖惩提成 2.前置条件指标 | |
49 | + */ | |
50 | + private RankIndicatorTypeEnum targetType; | |
51 | + /** | |
52 | + * 原始值 | |
53 | + */ | |
54 | + private BigDecimal value; | |
55 | + /** | |
56 | + * 达成目标 | |
57 | + */ | |
58 | + private BigDecimal reachValue; | |
59 | + /** | |
60 | + * 排名 | |
61 | + */ | |
62 | + private Integer rank; | |
63 | + | |
64 | + /** | |
65 | + * 数据日期 | |
66 | + */ | |
67 | + private LocalDate dataDate; | |
68 | + | |
69 | + /** | |
70 | + * 集团 | |
71 | + */ | |
72 | + private Long groupId; | |
73 | + | |
74 | + private Boolean yn; | |
75 | + | |
76 | + @Override | |
77 | + public int compareTo(EvalGroupRewardRankLog other) { | |
78 | + return other.reachValue.compareTo(this.reachValue); | |
79 | + } | |
80 | +} | ... | ... |
fw-morax-domain/src/main/java/cn/fw/morax/domain/enums/RankIndicatorTypeEnum.java
0 → 100644
1 | +package cn.fw.morax.domain.enums; | |
2 | + | |
3 | +import com.baomidou.mybatisplus.core.enums.IEnum; | |
4 | +import com.fasterxml.jackson.annotation.JsonCreator; | |
5 | +import com.fasterxml.jackson.annotation.JsonValue; | |
6 | +import lombok.Getter; | |
7 | + | |
8 | +/** | |
9 | + * 指标类型 | |
10 | + * | |
11 | + * @author kurisu | |
12 | + */ | |
13 | +public enum RankIndicatorTypeEnum implements IEnum<Integer> { | |
14 | + /** | |
15 | + * 指标类型 1.奖惩提成 2.前置条件指标 | |
16 | + */ | |
17 | + REWARD_COMMISSION(1, "奖惩提成"), | |
18 | + PRE(2, "前置条件指标"), | |
19 | + ; | |
20 | + | |
21 | + /** | |
22 | + * 值 | |
23 | + */ | |
24 | + private final Integer value; | |
25 | + /** | |
26 | + * 名称 | |
27 | + */ | |
28 | + @Getter | |
29 | + private final String name; | |
30 | + | |
31 | + RankIndicatorTypeEnum(final Integer value, final String name) { | |
32 | + this.value = value; | |
33 | + this.name = name; | |
34 | + } | |
35 | + | |
36 | + /** | |
37 | + * 根据枚举值获取枚举对象 | |
38 | + */ | |
39 | + @JsonCreator | |
40 | + public static RankIndicatorTypeEnum ofValue(final Integer value) { | |
41 | + for (final RankIndicatorTypeEnum _enum : RankIndicatorTypeEnum.values()) { | |
42 | + if (_enum.value.equals(value)) { | |
43 | + return _enum; | |
44 | + } | |
45 | + } | |
46 | + return null; | |
47 | + } | |
48 | + | |
49 | + /** | |
50 | + * 获取值 | |
51 | + * | |
52 | + * @return 值 | |
53 | + */ | |
54 | + @JsonValue | |
55 | + @Override | |
56 | + public Integer getValue() { | |
57 | + return value; | |
58 | + } | |
59 | + | |
60 | + /** | |
61 | + * 获取描述 | |
62 | + * | |
63 | + * @return 值 | |
64 | + */ | |
65 | + @JsonCreator | |
66 | + public static String getNameByVale(final Integer value) { | |
67 | + for (final RankIndicatorTypeEnum _enum : RankIndicatorTypeEnum.values()) { | |
68 | + if (_enum.value.equals(value)) { | |
69 | + return _enum.getName(); | |
70 | + } | |
71 | + } | |
72 | + return ""; | |
73 | + } | |
74 | +} | ... | ... |
fw-morax-domain/src/main/java/cn/fw/morax/domain/vo/eval/EvalGroupRewardRankLogVO.java
0 → 100644
1 | +package cn.fw.morax.domain.vo.eval; | |
2 | + | |
3 | +import cn.fw.morax.common.constant.Constant; | |
4 | +import cn.fw.morax.common.utils.PublicUtil; | |
5 | +import cn.fw.morax.domain.enums.DataTypeEnum; | |
6 | +import cn.fw.morax.domain.enums.EvalScopeEnum; | |
7 | +import cn.fw.morax.domain.enums.RankIndicatorTypeEnum; | |
8 | +import cn.fw.morax.domain.enums.TargetTypeEnum; | |
9 | +import lombok.Data; | |
10 | +import lombok.EqualsAndHashCode; | |
11 | + | |
12 | +import java.math.BigDecimal; | |
13 | +import java.time.LocalDate; | |
14 | + | |
15 | +/** | |
16 | + * <p> | |
17 | + * 奖惩排名日志 | |
18 | + * </p> | |
19 | + * | |
20 | + * @author jiangchao | |
21 | + * @since 2022-12-13 | |
22 | + */ | |
23 | +@Data | |
24 | +@EqualsAndHashCode(callSuper = false) | |
25 | +public class EvalGroupRewardRankLogVO { | |
26 | + | |
27 | + private static final long serialVersionUID = 1L; | |
28 | + /** | |
29 | + * id | |
30 | + */ | |
31 | + private Long id; | |
32 | + | |
33 | + /** | |
34 | + * 员工id | |
35 | + */ | |
36 | + private Long poolId; | |
37 | + | |
38 | + /** | |
39 | + * 考评范围; 1:门店考评 2:人员考评 | |
40 | + */ | |
41 | + private EvalScopeEnum scopeType; | |
42 | + | |
43 | + /** | |
44 | + * 考评奖惩 前置条件 配置id | |
45 | + */ | |
46 | + private Long referId; | |
47 | + /** | |
48 | + * 指标类型 1.奖惩提成 2.前置条件指标 | |
49 | + */ | |
50 | + private RankIndicatorTypeEnum targetType; | |
51 | + /** | |
52 | + * 原始值 | |
53 | + */ | |
54 | + private BigDecimal value; | |
55 | + /** | |
56 | + * 达成目标 | |
57 | + */ | |
58 | + private BigDecimal reachValue; | |
59 | + /** | |
60 | + * 排名 | |
61 | + */ | |
62 | + private Integer rank; | |
63 | + | |
64 | + /** | |
65 | + * 数据日期 | |
66 | + */ | |
67 | + private LocalDate dataDate; | |
68 | + | |
69 | + /** | |
70 | + * 集团 | |
71 | + */ | |
72 | + private Long groupId; | |
73 | + | |
74 | + /** | |
75 | + * 转换为百分数展示 | |
76 | + */ | |
77 | + public void convertValueToPercent(DataTypeEnum dataType, TargetTypeEnum targetType){ | |
78 | + if (DataTypeEnum.RATIO.equals(dataType)) { | |
79 | + this.setValue(this.getValue().multiply(Constant.ONE_HUNDRED)); | |
80 | + } | |
81 | + //有目标 | |
82 | + if (! TargetTypeEnum.NO.equals(targetType)) { | |
83 | + this.setReachValue(this.getReachValue().multiply(Constant.ONE_HUNDRED)); | |
84 | + } | |
85 | + } | |
86 | + | |
87 | +} | ... | ... |
fw-morax-server/src/main/java/cn/fw/morax/server/controller/app/EvalPoolController.java
... | ... | @@ -31,9 +31,11 @@ import java.time.YearMonth; |
31 | 31 | import java.time.temporal.ChronoField; |
32 | 32 | import java.time.temporal.TemporalAdjuster; |
33 | 33 | import java.time.temporal.TemporalAdjusters; |
34 | +import java.util.List; | |
34 | 35 | import java.util.Objects; |
35 | 36 | import java.util.Set; |
36 | 37 | |
38 | +import static cn.fw.common.businessvalidator.Validator.BV; | |
37 | 39 | import static cn.fw.common.web.util.ResultBuilder.success; |
38 | 40 | |
39 | 41 | /** |
... | ... | @@ -195,6 +197,36 @@ public class EvalPoolController { |
195 | 197 | return success(evalGroupPoolService.queryIndicatorRank(dto, EvalScopeEnum.SHOP)); |
196 | 198 | } |
197 | 199 | |
200 | + /** | |
201 | + * 门店、人员考评条件指标排名 | |
202 | + * | |
203 | + * @param preconditionId | |
204 | + * @param dataDate | |
205 | + * @return | |
206 | + */ | |
207 | + @GetMapping("/reward-cond-rank") | |
208 | + @ControllerMethod("门店、人员考评条件指标排名") | |
209 | + public Message<List<EvalGroupRewardRankLogVO>> queryRewardCondRank(Long preconditionId, | |
210 | + @NotNull(message = "日期不能为空") @RequestParam("dataDate") LocalDate dataDate) { | |
211 | + return success(evalGroupPoolService.getRewardCondRankLogs(preconditionId, dataDate)); | |
212 | + } | |
213 | + | |
214 | + /** | |
215 | + * 门店、人员考评提成指标排名 | |
216 | + * | |
217 | + * @param commissionId | |
218 | + * @param dataDate | |
219 | + * @return | |
220 | + */ | |
221 | + @GetMapping("/reward-commission-rank") | |
222 | + @ControllerMethod("门店、人员考评提成指标排名") | |
223 | + public Message<List<EvalGroupRewardRankLogVO>> queryRewardCommissionRank(Long commissionId, | |
224 | + @NotNull(message = "日期不能为空") @RequestParam("dataDate") LocalDate dataDate) { | |
225 | + return success(evalGroupPoolService.getRewardCondRankLogs(commissionId, dataDate)); | |
226 | + } | |
227 | + | |
228 | + | |
229 | + | |
198 | 230 | |
199 | 231 | /** |
200 | 232 | * 门店考评池列表 | ... | ... |
fw-morax-service/src/main/java/cn/fw/morax/service/biz/CommonService.java
... | ... | @@ -6,6 +6,7 @@ import cn.fw.morax.common.constant.Constant; |
6 | 6 | import cn.fw.morax.common.utils.ExcelDataUtil; |
7 | 7 | import cn.fw.morax.common.utils.PublicUtil; |
8 | 8 | import cn.fw.morax.domain.db.SettingDraft; |
9 | +import cn.fw.morax.domain.db.eval.EvalGroupRewardRankLog; | |
9 | 10 | import cn.fw.morax.domain.db.eval.EvalIndicatorValue; |
10 | 11 | import cn.fw.morax.domain.db.kpi.IndicatorUserValue; |
11 | 12 | import cn.fw.morax.domain.db.kpi.KpiGroup; |
... | ... | @@ -15,6 +16,7 @@ import cn.fw.morax.domain.enums.IndicatorValueTypeEnum; |
15 | 16 | import cn.fw.morax.domain.enums.SettingDraftStatusEnum; |
16 | 17 | import cn.fw.morax.domain.enums.SettingDraftTypeEnum; |
17 | 18 | import cn.fw.morax.domain.vo.kpi.IndicatorUserValueVO; |
19 | +import cn.fw.morax.domain.vo.kpi.KpiIndicatorRankStaffVO; | |
18 | 20 | import cn.fw.morax.rpc.ehr.EhrRpcService; |
19 | 21 | import cn.fw.morax.rpc.ehr.dto.StaffBaseInfoDTO; |
20 | 22 | import cn.fw.morax.service.data.SettingDraftService; |
... | ... | @@ -368,4 +370,27 @@ public class CommonService { |
368 | 370 | return settingDrafts; |
369 | 371 | } |
370 | 372 | |
373 | + /** | |
374 | + * 设置排名序号 | |
375 | + * | |
376 | + * @return | |
377 | + */ | |
378 | + public void calcRank(List<EvalGroupRewardRankLog> rankLogs) { | |
379 | + int rank = 1; | |
380 | + BigDecimal lastIndicatorValue = null; | |
381 | + for (EvalGroupRewardRankLog rankLog : rankLogs) { | |
382 | + //初始化 | |
383 | + if (PublicUtil.isEmpty(lastIndicatorValue)) { | |
384 | + rankLog.setRank(rank); | |
385 | + lastIndicatorValue = rankLog.getReachValue(); | |
386 | + continue; | |
387 | + } | |
388 | + if (lastIndicatorValue.compareTo(rankLog.getReachValue()) != 0) { | |
389 | + rank++; | |
390 | + } | |
391 | + rankLog.setRank(rank); | |
392 | + lastIndicatorValue = rankLog.getReachValue(); | |
393 | + } | |
394 | + } | |
395 | + | |
371 | 396 | } | ... | ... |
fw-morax-service/src/main/java/cn/fw/morax/service/biz/calculator/eval/reward/EvalRewardBaseCalculator.java
... | ... | @@ -6,12 +6,15 @@ import cn.fw.morax.domain.bo.eval.EvalGroupUserShop; |
6 | 6 | import cn.fw.morax.domain.db.eval.*; |
7 | 7 | import cn.fw.morax.domain.db.kpi.IndicatorUserValue; |
8 | 8 | import cn.fw.morax.domain.enums.*; |
9 | +import cn.fw.morax.service.biz.CommonService; | |
9 | 10 | import cn.fw.morax.service.biz.calculator.Calculator; |
10 | 11 | import cn.fw.morax.service.data.eval.*; |
11 | 12 | import cn.fw.morax.service.data.kpi.IndicatorUserValueService; |
13 | +import com.alibaba.fastjson.JSON; | |
12 | 14 | import com.alibaba.fastjson.JSONObject; |
13 | 15 | import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; |
14 | 16 | import com.baomidou.mybatisplus.core.toolkit.Wrappers; |
17 | +import com.google.common.collect.Lists; | |
15 | 18 | import lombok.Getter; |
16 | 19 | import lombok.extern.slf4j.Slf4j; |
17 | 20 | import org.springframework.beans.factory.annotation.Autowired; |
... | ... | @@ -29,7 +32,6 @@ import java.time.LocalDateTime; |
29 | 32 | import java.time.temporal.ChronoUnit; |
30 | 33 | import java.util.*; |
31 | 34 | import java.util.concurrent.atomic.AtomicInteger; |
32 | -import java.util.concurrent.atomic.AtomicReference; | |
33 | 35 | import java.util.function.Consumer; |
34 | 36 | import java.util.function.Function; |
35 | 37 | import java.util.stream.Collectors; |
... | ... | @@ -47,6 +49,8 @@ import java.util.stream.Collectors; |
47 | 49 | public abstract class EvalRewardBaseCalculator implements Calculator<EvalGroupUserShop, EvalGroupReward, BigDecimal> { |
48 | 50 | |
49 | 51 | @Autowired |
52 | + protected EvalGroupRewardRankLogService evalGroupRewardRankLogService; | |
53 | + @Autowired | |
50 | 54 | protected EvalGroupRewardHitLogService evalGroupRewardHitLogService; |
51 | 55 | @Autowired |
52 | 56 | protected EvalGroupRewardPreconditionHitLogService evalGroupRewardPreconditionHitLogService; |
... | ... | @@ -68,6 +72,8 @@ public abstract class EvalRewardBaseCalculator implements Calculator<EvalGroupUs |
68 | 72 | protected EvalGroupRewardService evalGroupRewardService; |
69 | 73 | @Autowired |
70 | 74 | private StringRedisTemplate stringRedisTemplate; |
75 | + @Autowired | |
76 | + private CommonService commonService; | |
71 | 77 | @Value("${spring.cache.custom.global-prefix}:eval:reward:cond:rank") |
72 | 78 | @Getter |
73 | 79 | private String preconditionRank; |
... | ... | @@ -173,49 +179,43 @@ public abstract class EvalRewardBaseCalculator implements Calculator<EvalGroupUs |
173 | 179 | return; |
174 | 180 | } |
175 | 181 | for (EvalGroupRewardPrecondition precondition : preconditions) { |
176 | - final String indicatorCode = precondition.getCode(); | |
177 | 182 | final Long preconditionId = precondition.getId(); |
178 | - final TargetTypeEnum targetType = precondition.getTargetType(); | |
179 | - final BigDecimal targetValue = precondition.getTargetValue(); | |
180 | - final TargetCalcTypeEnum targetCalcType = precondition.getTargetCalcType(); | |
181 | 183 | final BigDecimal personCount = BigDecimal.valueOf(userShops.size()); |
182 | - final Integer startIndex = 0; | |
183 | 184 | final BigDecimal condValue = precondition.getCondValue(); |
185 | + final Integer startIndex = 0; | |
184 | 186 | final Integer endIndex = condValue.multiply(personCount).divide(BigDecimal.ONE, 0, RoundingMode.FLOOR).intValue() - 1; |
185 | 187 | |
186 | - String key = getPreconditionRank() + ":" + precondition.getId(); | |
187 | - BoundZSetOperations<String, String> zSetOps = stringRedisTemplate.boundZSetOps(key); | |
188 | - stringRedisTemplate.expireAt(key, DateUtil.localDateTime2Date(LocalDateTime.now().plus(2L, ChronoUnit.HOURS))); | |
189 | - for (EvalGroupUserShop userShop : userShops) { | |
190 | - final BigDecimal indicatorValue = queryValue(userShop, precondition.getCodeType(), indicatorCode).orElse(BigDecimal.ZERO); | |
191 | - BigDecimal reachValue = indicatorValue; | |
192 | - if (!TargetTypeEnum.NO.equals(targetType)) { | |
193 | - reachValue = calculateTargetValue(targetCalcType, targetValue, indicatorValue); | |
194 | - } | |
195 | - saveTargetHitLog(userShop, preconditionId, IndicatorTypeEnum.PRE, indicatorValue, reachValue); | |
196 | - zSetOps.add(userShop.getPoolId().toString(), reachValue.doubleValue()); | |
197 | - } | |
188 | + //计算排名 | |
189 | + List<EvalGroupRewardRankLog> rankLogs = calculateRankPreconditionValue(userShops, precondition); | |
190 | + Collections.sort(rankLogs); | |
191 | + commonService.calcRank(rankLogs); | |
192 | + saveRankLogs(preconditionId, rankLogs, RankIndicatorTypeEnum.PRE); | |
193 | + Map<Long, EvalGroupUserShop> poolUserShopMap = userShops.stream().collect(Collectors.toMap(EvalGroupUserShop::getPoolId, | |
194 | + Function.identity(), (v1, v2) -> v1)); | |
198 | 195 | |
199 | 196 | if (startIndex > endIndex) { |
200 | 197 | continue; |
201 | 198 | } |
202 | 199 | |
203 | - Map<Long, EvalGroupUserShop> userShopMap = userShops.stream().collect(Collectors.toMap(EvalGroupUserShop::getPoolId, Function.identity(), (v1, v2) -> v1)); | |
204 | - Set<ZSetOperations.TypedTuple<String>> referIdStrs = zSetOps.reverseRangeWithScores(startIndex, endIndex); | |
200 | + Integer _startIndex = startIndex, _endIndex = endIndex;; | |
201 | + List<EvalGroupRewardRankLog> matchRankLogs = rankLogs.stream().filter(rankLog -> { | |
202 | + return rankLog.getRank() > _startIndex && rankLog.getRank() <= _endIndex; | |
203 | + }).collect(Collectors.toList()); | |
204 | + | |
205 | 205 | AtomicInteger rank = new AtomicInteger(0); |
206 | - referIdStrs.stream().forEach(stringTypedTuple -> { | |
207 | - EvalGroupUserShop userShop = userShopMap.get(Long.parseLong(stringTypedTuple.getValue())); | |
206 | + for (EvalGroupRewardRankLog rankLog : matchRankLogs) { | |
207 | + EvalGroupUserShop userShop = poolUserShopMap.get(rankLog.getPoolId()); | |
208 | 208 | if (PublicUtil.isNotEmpty(userShop)) { |
209 | 209 | List<Long> meetRankCondIds = Optional.ofNullable(userShop.getMeetRankCondIds()).orElse(new ArrayList<>()); |
210 | 210 | meetRankCondIds.add(preconditionId); |
211 | 211 | userShop.setMeetRankCondIds(meetRankCondIds); |
212 | 212 | savePreHitLog(userShop, precondition, log -> { |
213 | - log.setReachValue(new BigDecimal(stringTypedTuple.getScore().toString())); | |
213 | + log.setReachValue(rankLog.getReachValue()); | |
214 | 214 | log.setCondValue(new BigDecimal(endIndex + 1)); |
215 | 215 | log.setRank(rank.incrementAndGet()); |
216 | 216 | }); |
217 | 217 | } |
218 | - }); | |
218 | + } | |
219 | 219 | } |
220 | 220 | } |
221 | 221 | |
... | ... | @@ -435,6 +435,100 @@ public abstract class EvalRewardBaseCalculator implements Calculator<EvalGroupUs |
435 | 435 | } |
436 | 436 | |
437 | 437 | /** |
438 | + * 计算排名提成参数最终值 | |
439 | + * | |
440 | + * @param userShops | |
441 | + * @param evalGroupRewardId | |
442 | + * @param params | |
443 | + * @return | |
444 | + */ | |
445 | + protected List<EvalGroupRewardRankLog> calculateRankParamValue(List<EvalGroupUserShop> userShops, Long evalGroupRewardId, List<EvalGroupRewardParam> params) { | |
446 | + List<EvalGroupRewardRankLog> rankLogs = Lists.newArrayListWithCapacity(userShops.size()); | |
447 | + for (EvalGroupUserShop userShop : userShops) { | |
448 | + BigDecimal commissionValue = BigDecimal.ZERO; | |
449 | + for (EvalGroupRewardParam param: params) { | |
450 | + String indicatorCode = param.getCode(); | |
451 | + boolean isCap = Boolean.TRUE.equals(param.getCap()); | |
452 | + BigDecimal proportion = param.getProportion(); | |
453 | + TargetTypeEnum targetType = param.getTargetType(); | |
454 | + final BigDecimal userOriginValue = queryValue(userShop, param.getCodeType(), indicatorCode).orElse(BigDecimal.ZERO); | |
455 | + BigDecimal _calcValue = userOriginValue; | |
456 | + if (!TargetTypeEnum.NO.equals(targetType)) { | |
457 | + _calcValue = calculateTargetValue(param.getTargetCalcType(), param.getTargetValue(), _calcValue); | |
458 | + saveTargetHitLog(userShop, param.getId(), IndicatorTypeEnum.EXAMINE, userOriginValue, _calcValue); | |
459 | + } | |
460 | + if (isCap) { | |
461 | + _calcValue = _calcValue.compareTo(BigDecimal.ONE) > 0 ? BigDecimal.ONE : _calcValue; | |
462 | + } | |
463 | + commissionValue = commissionValue.add(proportion.multiply(_calcValue)); | |
464 | + } | |
465 | + EvalGroupRewardRankLog rankLog = EvalGroupRewardRankLog.builder() | |
466 | + .poolId(userShop.getPoolId()) | |
467 | + .scopeType(userShop.getScopeType()) | |
468 | + .referId(evalGroupRewardId) | |
469 | + .targetType(RankIndicatorTypeEnum.REWARD_COMMISSION) | |
470 | + .value(commissionValue) | |
471 | + .reachValue(commissionValue) | |
472 | + .dataDate(userShop.getDataDate()) | |
473 | + .groupId(userShop.getGroupId()) | |
474 | + .build(); | |
475 | + rankLogs.add(rankLog); | |
476 | + } | |
477 | + return rankLogs; | |
478 | + } | |
479 | + | |
480 | + /** | |
481 | + * 计算排名条件最终值 | |
482 | + * | |
483 | + * @param userShops | |
484 | + * @param precondition | |
485 | + * @return | |
486 | + */ | |
487 | + protected List<EvalGroupRewardRankLog> calculateRankPreconditionValue(List<EvalGroupUserShop> userShops, EvalGroupRewardPrecondition precondition) { | |
488 | + final String indicatorCode = precondition.getCode(); | |
489 | + final Long preconditionId = precondition.getId(); | |
490 | + final TargetTypeEnum targetType = precondition.getTargetType(); | |
491 | + final BigDecimal targetValue = precondition.getTargetValue(); | |
492 | + final TargetCalcTypeEnum targetCalcType = precondition.getTargetCalcType(); | |
493 | + | |
494 | + List<EvalGroupRewardRankLog> rankLogs = Lists.newArrayListWithCapacity(userShops.size()); | |
495 | + for (EvalGroupUserShop userShop : userShops) { | |
496 | + final BigDecimal indicatorValue = queryValue(userShop, precondition.getCodeType(), indicatorCode).orElse(BigDecimal.ZERO); | |
497 | + BigDecimal reachValue = indicatorValue; | |
498 | + if (!TargetTypeEnum.NO.equals(targetType)) { | |
499 | + reachValue = calculateTargetValue(targetCalcType, targetValue, indicatorValue); | |
500 | + } | |
501 | + | |
502 | + EvalGroupRewardRankLog rankLog = EvalGroupRewardRankLog.builder() | |
503 | + .poolId(userShop.getPoolId()) | |
504 | + .scopeType(userShop.getScopeType()) | |
505 | + .referId(preconditionId) | |
506 | + .targetType(RankIndicatorTypeEnum.PRE) | |
507 | + .value(indicatorValue) | |
508 | + .reachValue(reachValue) | |
509 | + .dataDate(userShop.getDataDate()) | |
510 | + .groupId(userShop.getGroupId()) | |
511 | + .build(); | |
512 | + rankLogs.add(rankLog); | |
513 | + } | |
514 | + return rankLogs; | |
515 | + } | |
516 | + | |
517 | + public void saveRankLogs(Long evalGroupRewardId, List<EvalGroupRewardRankLog> rankLogs, RankIndicatorTypeEnum targetType) { | |
518 | + Set<Long> poolIds = rankLogs.stream().map(EvalGroupRewardRankLog::getPoolId).collect(Collectors.toSet()); | |
519 | + EvalGroupRewardRankLog rankLog = rankLogs.stream().findFirst().get(); | |
520 | + evalGroupRewardRankLogService.remove(Wrappers.<EvalGroupRewardRankLog>lambdaQuery() | |
521 | + .in(EvalGroupRewardRankLog::getPoolId, poolIds) | |
522 | + .eq(EvalGroupRewardRankLog::getScopeType, rankLog.getScopeType()) | |
523 | + .eq(EvalGroupRewardRankLog::getReferId, evalGroupRewardId) | |
524 | + .eq(EvalGroupRewardRankLog::getTargetType, targetType) | |
525 | + .eq(EvalGroupRewardRankLog::getGroupId, rankLog.getGroupId()) | |
526 | + ); | |
527 | + | |
528 | + evalGroupRewardRankLogService.saveBatch(rankLogs); | |
529 | + } | |
530 | + | |
531 | + /** | |
438 | 532 | * 初始化奖惩值 |
439 | 533 | * |
440 | 534 | * @param userShops | ... | ... |
fw-morax-service/src/main/java/cn/fw/morax/service/biz/calculator/eval/reward/EvalRewardRankCalculator.java
1 | 1 | package cn.fw.morax.service.biz.calculator.eval.reward; |
2 | 2 | |
3 | -import cn.fw.morax.common.utils.DateUtil; | |
4 | 3 | import cn.fw.morax.common.utils.PublicUtil; |
5 | 4 | import cn.fw.morax.domain.bo.eval.EvalGroupUserShop; |
6 | -import cn.fw.morax.domain.db.eval.EvalGroupReward; | |
7 | -import cn.fw.morax.domain.db.eval.EvalGroupRewardLadders; | |
8 | -import cn.fw.morax.domain.db.eval.EvalGroupRewardParam; | |
9 | -import cn.fw.morax.domain.db.eval.EvalGroupRewardPrecondition; | |
5 | +import cn.fw.morax.domain.db.eval.*; | |
10 | 6 | import cn.fw.morax.domain.enums.EvalRewardCalMethodEnum; |
11 | 7 | import cn.fw.morax.domain.enums.ParamTypeEnum; |
8 | +import cn.fw.morax.domain.enums.RankIndicatorTypeEnum; | |
12 | 9 | import cn.fw.morax.domain.enums.RankTypeEnum; |
10 | +import cn.fw.morax.service.biz.CommonService; | |
13 | 11 | import lombok.Getter; |
14 | 12 | import lombok.RequiredArgsConstructor; |
15 | 13 | import lombok.extern.slf4j.Slf4j; |
16 | 14 | import org.springframework.beans.factory.annotation.Value; |
17 | -import org.springframework.data.redis.core.BoundZSetOperations; | |
18 | 15 | import org.springframework.data.redis.core.StringRedisTemplate; |
19 | 16 | import org.springframework.stereotype.Component; |
20 | 17 | import org.springframework.util.CollectionUtils; |
21 | 18 | |
22 | 19 | import java.math.BigDecimal; |
23 | 20 | import java.math.RoundingMode; |
24 | -import java.time.LocalDate; | |
25 | -import java.time.LocalDateTime; | |
26 | -import java.time.temporal.ChronoUnit; | |
27 | -import java.util.HashMap; | |
28 | -import java.util.List; | |
29 | -import java.util.Map; | |
30 | -import java.util.Set; | |
21 | +import java.util.*; | |
22 | +import java.util.function.Function; | |
23 | +import java.util.stream.Collectors; | |
31 | 24 | |
32 | 25 | /** |
33 | 26 | * @author jiangchao |
... | ... | @@ -40,6 +33,7 @@ import java.util.Set; |
40 | 33 | public class EvalRewardRankCalculator extends EvalRewardBaseCalculator { |
41 | 34 | |
42 | 35 | private final StringRedisTemplate stringRedisTemplate; |
36 | + private final CommonService commonService; | |
43 | 37 | |
44 | 38 | @Value("${spring.cache.custom.global-prefix}:eval:reward:rank") |
45 | 39 | @Getter |
... | ... | @@ -70,48 +64,45 @@ public class EvalRewardRankCalculator extends EvalRewardBaseCalculator { |
70 | 64 | return; |
71 | 65 | } |
72 | 66 | |
73 | - BoundZSetOperations<String, String> zSetOps = stringRedisTemplate.boundZSetOps(key); | |
74 | - stringRedisTemplate.expireAt(key, DateUtil.localDateTime2Date(LocalDateTime.now().plus(2L, ChronoUnit.HOURS))); | |
75 | - | |
76 | - Map<String, EvalGroupUserShop> rewardObjectBOMap = new HashMap<>(); | |
77 | - Map<String, BigDecimal> referCommonMap = new HashMap<>(); | |
78 | - for (EvalGroupUserShop rewardObject : userShops) { | |
79 | - BigDecimal commissionValue = calculateParamValue(rewardObject, params); | |
80 | - zSetOps.add(rewardObject.getReferId().toString(), commissionValue.doubleValue()); | |
81 | - | |
82 | - referCommonMap.put(rewardObject.getReferId().toString(), commissionValue); | |
83 | - rewardObjectBOMap.put(rewardObject.getReferId().toString(), rewardObject); | |
84 | - } | |
67 | + //计算排名 | |
68 | + List<EvalGroupRewardRankLog> rankLogs = calculateRankParamValue(userShops, evalGroupRewardId, params); | |
69 | + Collections.sort(rankLogs); | |
70 | + commonService.calcRank(rankLogs); | |
71 | + saveRankLogs(evalGroupRewardId, rankLogs, RankIndicatorTypeEnum.REWARD_COMMISSION); | |
72 | + Map<Long, EvalGroupUserShop> poolUserShopMap = userShops.stream().collect(Collectors.toMap(EvalGroupUserShop::getPoolId, | |
73 | + Function.identity(), (v1, v2) -> v1)); | |
85 | 74 | |
75 | + //计算金额 | |
86 | 76 | final BigDecimal personCount = BigDecimal.valueOf(userShops.size()); |
87 | 77 | List<EvalGroupRewardLadders> ladders = queryRewardLadders(evalGroupRewardId); |
88 | 78 | for (EvalGroupRewardLadders ladder : ladders) { |
89 | 79 | final BigDecimal money = ladder.getMoney(); |
90 | - Integer startIndex = null; | |
91 | - Integer endIndex = null; | |
80 | + Integer startIndex = ladder.getLower().intValue() - 1; | |
81 | + Integer endIndex = ladder.getUpper().intValue(); | |
92 | 82 | |
93 | 83 | if (RankTypeEnum.PERCENT.equals(rankType)) { |
94 | 84 | startIndex = ladder.getLower().multiply(personCount).divide(BigDecimal.ONE, 0, RoundingMode.FLOOR).intValue(); |
95 | - endIndex = ladder.getUpper().multiply(personCount).divide(BigDecimal.ONE, 0, RoundingMode.FLOOR).intValue() - 1; | |
96 | - } else { | |
97 | - startIndex = ladder.getLower().intValue() - 1; | |
98 | - endIndex = ladder.getUpper().intValue()- 1; | |
85 | + endIndex = ladder.getUpper().multiply(personCount).divide(BigDecimal.ONE, 0, RoundingMode.FLOOR).intValue(); | |
99 | 86 | } |
100 | 87 | |
101 | 88 | if (startIndex > endIndex) { |
102 | 89 | continue; |
103 | 90 | } |
104 | 91 | |
105 | - Set<String> referIdStrs = zSetOps.reverseRange(startIndex, endIndex); | |
106 | - for (String referIdStr : referIdStrs) { | |
107 | - EvalGroupUserShop userShop = rewardObjectBOMap.get(referIdStr); | |
92 | + Integer _startIndex = startIndex, _endIndex = endIndex;; | |
93 | + List<EvalGroupRewardRankLog> matchRankLogs = rankLogs.stream().filter(rankLog -> { | |
94 | + return rankLog.getRank() > _startIndex && rankLog.getRank() <= _endIndex; | |
95 | + }).collect(Collectors.toList()); | |
96 | + | |
97 | + for (EvalGroupRewardRankLog rankLog : matchRankLogs) { | |
98 | + EvalGroupUserShop userShop = poolUserShopMap.get(rankLog.getPoolId()); | |
108 | 99 | boolean examined = examinePrecondition(userShop, preconditions); |
109 | 100 | if (!examined) { |
110 | 101 | userShop.setEvalGroupRewardAmount(BigDecimal.ZERO); |
111 | 102 | continue; |
112 | 103 | } |
113 | 104 | userShop.setEvalGroupRewardAmount(money); |
114 | - BigDecimal hitCommissionValue = referCommonMap.get(referIdStr); | |
105 | + BigDecimal hitCommissionValue = rankLog.getReachValue(); | |
115 | 106 | clearProjectHitLog(evalGroupRewardId, userShop); |
116 | 107 | saveProjectHitLog(evalGroupRewardId, userShop, log -> { |
117 | 108 | log.setRewardValue(money); | ... | ... |
fw-morax-service/src/main/java/cn/fw/morax/service/biz/calculator/kpi/KpiAbsBaseCalculator.java
... | ... | @@ -8,19 +8,19 @@ import cn.fw.morax.domain.enums.TargetCalcTypeEnum; |
8 | 8 | import cn.fw.morax.domain.enums.TargetTypeEnum; |
9 | 9 | import cn.fw.morax.service.biz.calculator.Calculator; |
10 | 10 | import cn.fw.morax.service.data.kpi.*; |
11 | +import com.alibaba.fastjson.JSON; | |
11 | 12 | import com.alibaba.fastjson.JSONObject; |
12 | 13 | import com.baomidou.mybatisplus.core.toolkit.CollectionUtils; |
13 | 14 | import com.baomidou.mybatisplus.core.toolkit.Wrappers; |
15 | +import com.google.common.base.Strings; | |
14 | 16 | import lombok.extern.slf4j.Slf4j; |
17 | +import org.apache.commons.lang3.StringUtils; | |
15 | 18 | import org.springframework.beans.factory.annotation.Autowired; |
16 | 19 | |
17 | 20 | import java.math.BigDecimal; |
18 | 21 | import java.math.RoundingMode; |
19 | 22 | import java.time.LocalDate; |
20 | -import java.util.ArrayList; | |
21 | -import java.util.List; | |
22 | -import java.util.Objects; | |
23 | -import java.util.Optional; | |
23 | +import java.util.*; | |
24 | 24 | import java.util.function.Consumer; |
25 | 25 | |
26 | 26 | /** |
... | ... | @@ -47,6 +47,20 @@ public abstract class KpiAbsBaseCalculator implements Calculator<KpiGroupUser, K |
47 | 47 | @Autowired |
48 | 48 | protected KpiGroupIndicatorTargetHitLogService kpiGroupIndicatorTargetHitLogService; |
49 | 49 | |
50 | + public static void main(String[] args) { | |
51 | + Set<Long> set = new HashSet<>(); | |
52 | + set.add(1L); | |
53 | + set.add(2L); | |
54 | + set.add(3L); | |
55 | + String json = JSON.toJSONString(set); | |
56 | + System.out.println(json); | |
57 | + List<Long> set2 = JSON.parseArray(json, Long.class); | |
58 | + System.out.println(set2.toString()); | |
59 | + System.out.println(Arrays.toString(set2.toArray())); | |
60 | + String join = StringUtils.join(",", set); | |
61 | + System.out.println(join); | |
62 | + } | |
63 | + | |
50 | 64 | /** |
51 | 65 | * 获取设置类型 |
52 | 66 | * | ... | ... |
fw-morax-service/src/main/java/cn/fw/morax/service/biz/eval/EvalGroupPoolService.java
... | ... | @@ -60,6 +60,7 @@ public class EvalGroupPoolService { |
60 | 60 | private final EvalGroupRewardLaddersService evalGroupRewardLaddersService; |
61 | 61 | private final EvalPoolRewardDetailService evalPoolRewardDetailService; |
62 | 62 | private final EvalGroupRewardParamService evalGroupRewardParamService; |
63 | + private final EvalGroupRewardRankLogService evalGroupRewardRankLogService; | |
63 | 64 | private final EvalGroupRewardHitLogService evalGroupRewardHitLogService; |
64 | 65 | private final IndicatorUserValueService indicatorUserValueService; |
65 | 66 | private final EvalIndicatorValueService evalIndicatorValueService; |
... | ... | @@ -1226,4 +1227,39 @@ public class EvalGroupPoolService { |
1226 | 1227 | } |
1227 | 1228 | } |
1228 | 1229 | |
1230 | + public List<EvalGroupRewardRankLogVO> getRewardCondRankLogs(Long preconditionId, LocalDate dataDate) { | |
1231 | + EvalGroupRewardPrecondition precondition = evalGroupRewardPreconditionService.getById(preconditionId); | |
1232 | + BV.notNull(precondition, "奖惩条件不存在"); | |
1233 | + final DataTypeEnum dataType = precondition.getDataType(); | |
1234 | + final TargetTypeEnum targetType = precondition.getTargetType(); | |
1235 | + List<EvalGroupRewardRankLog> rankLogs = evalGroupRewardRankLogService.list(Wrappers.<EvalGroupRewardRankLog>lambdaQuery() | |
1236 | + .eq(EvalGroupRewardRankLog::getDataDate, dataDate) | |
1237 | + .eq(EvalGroupRewardRankLog::getReferId, preconditionId) | |
1238 | + .eq(EvalGroupRewardRankLog::getTargetType, RankIndicatorTypeEnum.PRE) | |
1239 | + .eq(EvalGroupRewardRankLog::getYn, Boolean.TRUE) | |
1240 | + ); | |
1241 | + Collections.sort(rankLogs); | |
1242 | + | |
1243 | + List<EvalGroupRewardRankLogVO> rankLogVOs = PublicUtil.copyList(rankLogs, EvalGroupRewardRankLogVO.class); | |
1244 | + rankLogVOs.stream().forEach(rankLog -> rankLog.convertValueToPercent(dataType, targetType)); | |
1245 | + return rankLogVOs; | |
1246 | + } | |
1247 | + | |
1248 | + public List<EvalGroupRewardRankLogVO> queryRewardCommissionRank(Long commissionId, LocalDate dataDate) { | |
1249 | +// EvalGroupRewardPrecondition precondition = evalGroupRewardPreconditionService.getById(preconditionId); | |
1250 | +// BV.notNull(precondition, "奖惩条件不存在"); | |
1251 | +// final DataTypeEnum dataType = precondition.getDataType(); | |
1252 | +// final TargetTypeEnum targetType = precondition.getTargetType(); | |
1253 | + List<EvalGroupRewardRankLog> rankLogs = evalGroupRewardRankLogService.list(Wrappers.<EvalGroupRewardRankLog>lambdaQuery() | |
1254 | + .eq(EvalGroupRewardRankLog::getDataDate, dataDate) | |
1255 | + .eq(EvalGroupRewardRankLog::getReferId, commissionId) | |
1256 | + .eq(EvalGroupRewardRankLog::getTargetType, RankIndicatorTypeEnum.REWARD_COMMISSION) | |
1257 | + .eq(EvalGroupRewardRankLog::getYn, Boolean.TRUE) | |
1258 | + ); | |
1259 | + Collections.sort(rankLogs); | |
1260 | + | |
1261 | + List<EvalGroupRewardRankLogVO> rankLogVOs = PublicUtil.copyList(rankLogs, EvalGroupRewardRankLogVO.class); | |
1262 | +// rankLogVOs.stream().forEach(rankLog -> rankLog.convertValueToPercent(dataType, targetType)); | |
1263 | + return rankLogVOs; | |
1264 | + } | |
1229 | 1265 | } | ... | ... |
fw-morax-service/src/main/java/cn/fw/morax/service/data/eval/EvalGroupRewardRankLogService.java
0 → 100644
1 | +package cn.fw.morax.service.data.eval; | |
2 | + | |
3 | + | |
4 | +import cn.fw.morax.domain.db.eval.EvalGroupRewardRankLog; | |
5 | +import cn.fw.morax.domain.db.eval.EvalGroupRewardTargetHitLog; | |
6 | +import cn.fw.morax.domain.enums.EvalScopeEnum; | |
7 | +import cn.fw.morax.domain.enums.IndicatorTypeEnum; | |
8 | +import cn.fw.morax.domain.vo.eval.EvalGroupRewardTargetHitLogVO; | |
9 | +import com.baomidou.mybatisplus.extension.service.IService; | |
10 | + | |
11 | +import java.time.YearMonth; | |
12 | +import java.util.List; | |
13 | +import java.util.Set; | |
14 | + | |
15 | +/** | |
16 | + * <p> | |
17 | + * 考评奖惩 服务类 | |
18 | + * </p> | |
19 | + * | |
20 | + * @author jiangchao | |
21 | + * @since 2022-12-09 | |
22 | + */ | |
23 | +public interface EvalGroupRewardRankLogService extends IService<EvalGroupRewardRankLog> { | |
24 | + | |
25 | + | |
26 | +} | ... | ... |
fw-morax-service/src/main/java/cn/fw/morax/service/data/eval/impl/EvalGroupRewardRankLogServiceImpl.java
0 → 100644
1 | +package cn.fw.morax.service.data.eval.impl; | |
2 | + | |
3 | + | |
4 | +import cn.fw.morax.dao.eval.EvalGroupRewardRankLogDao; | |
5 | +import cn.fw.morax.dao.eval.EvalGroupRewardTargetHitLogDao; | |
6 | +import cn.fw.morax.domain.db.eval.EvalGroupRewardRankLog; | |
7 | +import cn.fw.morax.domain.db.eval.EvalGroupRewardTargetHitLog; | |
8 | +import cn.fw.morax.domain.enums.EvalScopeEnum; | |
9 | +import cn.fw.morax.domain.enums.IndicatorTypeEnum; | |
10 | +import cn.fw.morax.domain.vo.eval.EvalGroupRewardTargetHitLogVO; | |
11 | +import cn.fw.morax.service.data.eval.EvalGroupRewardRankLogService; | |
12 | +import cn.fw.morax.service.data.eval.EvalGroupRewardTargetHitLogService; | |
13 | +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; | |
14 | +import org.springframework.stereotype.Service; | |
15 | + | |
16 | +import java.time.YearMonth; | |
17 | +import java.util.List; | |
18 | +import java.util.Set; | |
19 | + | |
20 | +/** | |
21 | + * <p> | |
22 | + * 考评指标达成目标记录 服务实现类 | |
23 | + * </p> | |
24 | + * | |
25 | + * @author jiangchao | |
26 | + * @since 2022-12-09 | |
27 | + */ | |
28 | +@Service | |
29 | +public class EvalGroupRewardRankLogServiceImpl | |
30 | + extends ServiceImpl<EvalGroupRewardRankLogDao, EvalGroupRewardRankLog> | |
31 | + implements EvalGroupRewardRankLogService { | |
32 | + | |
33 | +} | ... | ... |