优惠卷计算逻辑

This commit is contained in:
2026-07-28 11:56:31 +08:00
parent 42fa82ce07
commit 4d6b3dfe2f
10 changed files with 638 additions and 49 deletions

View File

@@ -121,6 +121,23 @@ public class LbUserCouponController {
return ResponseEntity.badRequest().body(result);
}
@GetMapping("/calculateMonthlyAmount")
@Operation(summary = "计算用户本月从开始日期到月末的优惠券金额")
public ResponseEntity<Map<String, Object>> calculateMonthlyAmount(
@Parameter(description = "用户ID", required = true)
@RequestParam String userId,
@Parameter(description = "用户昵称")
@RequestParam(required = false) String userNickname,
@Parameter(description = "开始日期,格式 yyyy-MM-dd")
@RequestParam(required = false) String startDate) {
Map<String, Object> result = lbUserCouponService.calculateUserMonthlyAmount(userId, userNickname, startDate);
Boolean success = (Boolean) result.get("success");
if (success != null && success) {
return ResponseEntity.ok(result);
}
return ResponseEntity.badRequest().body(result);
}
@GetMapping("/export")
@Operation(summary = "导出用户优惠券Excel", description = "按照分页查询的相同条件导出用户优惠券数据")
public void export(

View File

@@ -47,6 +47,16 @@ public interface ILbUserCouponService extends IService<LbUserCoupon> {
*/
Map<String, Object> monthlyStatistic(String tenantId, String couponDateStart, String couponDateEnd);
/**
* 计算用户本月从开始日期到月末的优惠券金额
*
* @param userId 用户ID
* @param userNickname 用户昵称
* @param startDate 开始日期,格式 yyyy-MM-dd
* @return 计算结果
*/
Map<String, Object> calculateUserMonthlyAmount(String userId, String userNickname, String startDate);
/**
* 导出用户优惠券Excel
*

View File

@@ -668,7 +668,7 @@ public class LbGoodsServiceImpl extends ServiceImpl<LbGoodsMapper, LbGoods> impl
if (buyResult.success()) {
successCount++;
successTotalAmount += goods.getTotalMoney().intValue();
Thread.sleep(1000);
Thread.sleep(3000);
} else {
failCount++;
if (buyResult.orderAlreadyGrabbed()) {

View File

@@ -32,12 +32,14 @@ import java.net.http.HttpResponse;
import java.nio.charset.StandardCharsets;
import java.security.SecureRandom;
import java.time.Duration;
import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
@@ -444,6 +446,72 @@ public class LbUserCouponServiceImpl
}
}
private List<LbUserCoupon> fillMissingWeekdayRecords(List<LbUserCoupon> records, LocalDate start, LocalDate end) {
if (records == null || records.isEmpty()) {
return records;
}
Map<String, LbUserCoupon> userInfoMap = new LinkedHashMap<>();
Map<String, Set<LocalDate>> userDateMap = new HashMap<>();
for (LbUserCoupon record : records) {
String userId = record.getUserId();
if (userId == null) {
continue;
}
if (!userInfoMap.containsKey(userId)) {
userInfoMap.put(userId, record);
}
userDateMap.computeIfAbsent(userId, k -> new LinkedHashSet<>());
if (record.getCouponDate() != null) {
userDateMap.get(userId).add(record.getCouponDate());
}
}
List<LbUserCoupon> result = new ArrayList<>(records);
LocalDateTime now = LocalDateTime.now();
for (Map.Entry<String, LbUserCoupon> entry : userInfoMap.entrySet()) {
String userId = entry.getKey();
LbUserCoupon template = entry.getValue();
Set<LocalDate> existingDates = userDateMap.getOrDefault(userId, new LinkedHashSet<>());
LocalDate current = start;
while (!current.isAfter(end)) {
DayOfWeek dayOfWeek = current.getDayOfWeek();
if (dayOfWeek != DayOfWeek.SATURDAY && dayOfWeek != DayOfWeek.SUNDAY) {
if (!existingDates.contains(current)) {
LbUserCoupon missingRecord = new LbUserCoupon();
missingRecord.setId(UUID.randomUUID().toString());
missingRecord.setTenantId(template.getTenantId());
missingRecord.setUserId(userId);
missingRecord.setUserPhone(template.getUserPhone());
missingRecord.setUserNickname(template.getUserNickname());
missingRecord.setParentPhone(template.getParentPhone());
missingRecord.setParentNickname(template.getParentNickname());
missingRecord.setCouponAmount(BigDecimal.ZERO);
missingRecord.setCouponDate(current);
missingRecord.setDataType(template.getDataType());
missingRecord.setCreateTime(now);
missingRecord.setUpdateTime(now);
result.add(missingRecord);
}
}
current = current.plusDays(1);
}
}
result.sort((a, b) -> {
BigDecimal amountA = a.getCouponAmount() != null ? a.getCouponAmount() : BigDecimal.ZERO;
BigDecimal amountB = b.getCouponAmount() != null ? b.getCouponAmount() : BigDecimal.ZERO;
return amountB.compareTo(amountA);
});
return result;
}
@Override
public Map<String, Object> add(LbUserCoupon entity) {
Map<String, Object> result = new HashMap<>();
@@ -627,14 +695,34 @@ public class LbUserCouponServiceImpl
queryWrapper.orderByDesc(LbUserCoupon::getCouponAmount);
Page<LbUserCoupon> page = this.page(new Page<>(current, size), queryWrapper);
result.put("success", true);
result.put("message", "查询成功");
result.put("data", page.getRecords());
result.put("total", page.getTotal());
result.put("current", page.getCurrent());
result.put("size", page.getSize());
result.put("pages", page.getPages());
if (start != null && end != null) {
List<LbUserCoupon> allRecords = this.list(queryWrapper);
List<LbUserCoupon> filledRecords = fillMissingWeekdayRecords(allRecords, start, end);
int total = filledRecords.size();
int pages = (total + size - 1) / size;
int fromIndex = (current - 1) * size;
int toIndex = Math.min(fromIndex + size, total);
List<LbUserCoupon> pageRecords = fromIndex < total ? filledRecords.subList(fromIndex, toIndex) : new ArrayList<>();
result.put("success", true);
result.put("message", "查询成功");
result.put("data", pageRecords);
result.put("total", (long) total);
result.put("current", (long) current);
result.put("size", (long) size);
result.put("pages", (long) pages);
} else {
Page<LbUserCoupon> page = this.page(new Page<>(current, size), queryWrapper);
result.put("success", true);
result.put("message", "查询成功");
result.put("data", page.getRecords());
result.put("total", page.getTotal());
result.put("current", page.getCurrent());
result.put("size", page.getSize());
result.put("pages", page.getPages());
}
return result;
} catch (Exception e) {
log.error("用户优惠券分页查询异常", e);
@@ -726,6 +814,63 @@ public class LbUserCouponServiceImpl
}
}
@Override
public Map<String, Object> calculateUserMonthlyAmount(String userId, String userNickname, String startDate) {
Map<String, Object> result = new HashMap<>();
try {
if (userId == null || userId.trim().isEmpty()) {
result.put("success", false);
result.put("message", "userId不能为空");
return result;
}
LocalDate start = parseDate(startDate);
if (startDate != null && !startDate.trim().isEmpty() && start == null) {
result.put("success", false);
result.put("message", "startDate 格式错误,请使用 yyyy-MM-dd");
return result;
}
if (start == null) {
start = LocalDate.now();
}
LocalDate end = start.withDayOfMonth(start.lengthOfMonth());
LambdaQueryWrapper<LbUserCoupon> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(LbUserCoupon::getUserId, userId.trim());
if (userNickname != null && !userNickname.trim().isEmpty()) {
queryWrapper.like(LbUserCoupon::getUserNickname, userNickname.trim());
}
queryWrapper.eq(LbUserCoupon::getDataType, "data_detail");
queryWrapper.ge(LbUserCoupon::getCouponDate, start);
queryWrapper.le(LbUserCoupon::getCouponDate, end);
List<LbUserCoupon> records = this.list(queryWrapper);
BigDecimal totalAmount = records.stream()
.map(r -> r.getCouponAmount() != null ? r.getCouponAmount() : BigDecimal.ZERO)
.reduce(BigDecimal.ZERO, BigDecimal::add);
List<LbUserCoupon> filledRecords = fillMissingWeekdayRecords(records, start, end);
result.put("success", true);
result.put("message", "计算成功");
result.put("userId", userId);
result.put("userNickname", userNickname);
result.put("startDate", start.format(DATE_FORMATTER));
result.put("endDate", end.format(DATE_FORMATTER));
result.put("totalAmount", totalAmount);
result.put("recordCount", records.size());
result.put("dailyDetail", filledRecords);
return result;
} catch (Exception e) {
log.error("计算用户本月优惠券金额异常", e);
result.put("success", false);
result.put("message", "计算异常:" + e.getMessage());
return result;
}
}
@Override
public void exportExcel(String tenantId,
String userId,