You've already forked FrameTour-BE
feat(pricing): 添加优惠券管理功能
- 新增 CouponManagementController 控制器,实现优惠券配置和领取记录的管理 - 新增 ICouponManagementService 接口和 CouponManagementServiceImpl 实现类,提供优惠券管理服务 - 在 PricingConfigController 中添加获取所有优惠券配置和领取记录的接口 - 新增 BundleProductListTypeHandler 类,用于处理一口价商品列表的序列化和反序列化 - 更新 PriceCouponClaimRecordMapper 和 PriceCouponConfigMapper,添加管理端所需的查询接口
This commit is contained in:
@@ -0,0 +1,220 @@
|
|||||||
|
package com.ycwl.basic.pricing.controller;
|
||||||
|
|
||||||
|
import com.github.pagehelper.PageInfo;
|
||||||
|
import com.ycwl.basic.pricing.entity.PriceCouponClaimRecord;
|
||||||
|
import com.ycwl.basic.pricing.entity.PriceCouponConfig;
|
||||||
|
import com.ycwl.basic.pricing.enums.CouponStatus;
|
||||||
|
import com.ycwl.basic.pricing.service.ICouponManagementService;
|
||||||
|
import com.ycwl.basic.utils.ApiResponse;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 优惠券管理控制器(管理端)
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/api/pricing/admin/coupons")
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class CouponManagementController {
|
||||||
|
|
||||||
|
private final ICouponManagementService couponManagementService;
|
||||||
|
|
||||||
|
// ==================== 优惠券配置管理 ====================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建优惠券配置
|
||||||
|
*/
|
||||||
|
@PostMapping("/configs")
|
||||||
|
public ApiResponse<Long> createCouponConfig(@RequestBody PriceCouponConfig config) {
|
||||||
|
log.info("创建优惠券配置: {}", config.getCouponName());
|
||||||
|
Long id = couponManagementService.createCouponConfig(config);
|
||||||
|
return ApiResponse.success(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新优惠券配置
|
||||||
|
*/
|
||||||
|
@PutMapping("/configs/{id}")
|
||||||
|
public ApiResponse<Boolean> updateCouponConfig(@PathVariable Long id, @RequestBody PriceCouponConfig config) {
|
||||||
|
log.info("更新优惠券配置: id={}, name={}", id, config.getCouponName());
|
||||||
|
config.setId(id);
|
||||||
|
boolean success = couponManagementService.updateCouponConfig(config);
|
||||||
|
return ApiResponse.success(success);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除优惠券配置
|
||||||
|
*/
|
||||||
|
@DeleteMapping("/configs/{id}")
|
||||||
|
public ApiResponse<Boolean> deleteCouponConfig(@PathVariable Long id) {
|
||||||
|
log.info("删除优惠券配置: id={}", id);
|
||||||
|
boolean success = couponManagementService.deleteCouponConfig(id);
|
||||||
|
return ApiResponse.success(success);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 启用/禁用优惠券配置
|
||||||
|
*/
|
||||||
|
@PutMapping("/configs/{id}/status")
|
||||||
|
public ApiResponse<Boolean> updateCouponConfigStatus(@PathVariable Long id, @RequestParam Boolean isActive) {
|
||||||
|
log.info("修改优惠券配置状态: id={}, isActive={}", id, isActive);
|
||||||
|
boolean success = couponManagementService.updateCouponConfigStatus(id, isActive);
|
||||||
|
return ApiResponse.success(success);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询所有优惠券配置(包含禁用的)
|
||||||
|
*/
|
||||||
|
@GetMapping("/configs")
|
||||||
|
public ApiResponse<List<PriceCouponConfig>> getAllCouponConfigs() {
|
||||||
|
log.info("管理端获取所有优惠券配置");
|
||||||
|
List<PriceCouponConfig> configs = couponManagementService.getAllCouponConfigs();
|
||||||
|
return ApiResponse.success(configs);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分页查询优惠券配置
|
||||||
|
*/
|
||||||
|
@GetMapping("/configs/page")
|
||||||
|
public ApiResponse<PageInfo<PriceCouponConfig>> getCouponConfigsPage(
|
||||||
|
@RequestParam(defaultValue = "1") Integer pageNum,
|
||||||
|
@RequestParam(defaultValue = "10") Integer pageSize,
|
||||||
|
@RequestParam(required = false) Boolean isActive,
|
||||||
|
@RequestParam(required = false) String couponName) {
|
||||||
|
log.info("分页查询优惠券配置: pageNum={}, pageSize={}, isActive={}, couponName={}",
|
||||||
|
pageNum, pageSize, isActive, couponName);
|
||||||
|
PageInfo<PriceCouponConfig> pageInfo = couponManagementService.getCouponConfigsPage(
|
||||||
|
pageNum, pageSize, isActive, couponName);
|
||||||
|
return ApiResponse.success(pageInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据状态查询优惠券配置
|
||||||
|
*/
|
||||||
|
@GetMapping("/configs/status/{isActive}")
|
||||||
|
public ApiResponse<List<PriceCouponConfig>> getCouponConfigsByStatus(@PathVariable Boolean isActive) {
|
||||||
|
log.info("根据状态查询优惠券配置: {}", isActive);
|
||||||
|
List<PriceCouponConfig> configs = couponManagementService.getCouponConfigsByStatus(isActive);
|
||||||
|
return ApiResponse.success(configs);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据ID查询优惠券配置
|
||||||
|
*/
|
||||||
|
@GetMapping("/configs/{id}")
|
||||||
|
public ApiResponse<PriceCouponConfig> getCouponConfigById(@PathVariable Long id) {
|
||||||
|
log.info("根据ID查询优惠券配置: {}", id);
|
||||||
|
PriceCouponConfig config = couponManagementService.getCouponConfigById(id);
|
||||||
|
return ApiResponse.success(config);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==================== 优惠券领取记录查询 ====================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询所有优惠券领取记录
|
||||||
|
*/
|
||||||
|
@GetMapping("/claim-records")
|
||||||
|
public ApiResponse<List<PriceCouponClaimRecord>> getAllClaimRecords() {
|
||||||
|
log.info("查询所有优惠券领取记录");
|
||||||
|
List<PriceCouponClaimRecord> records = couponManagementService.getAllClaimRecords();
|
||||||
|
return ApiResponse.success(records);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分页查询优惠券领取记录
|
||||||
|
*/
|
||||||
|
@GetMapping("/claim-records/page")
|
||||||
|
public ApiResponse<PageInfo<PriceCouponClaimRecord>> getClaimRecordsPage(
|
||||||
|
@RequestParam(defaultValue = "1") Integer pageNum,
|
||||||
|
@RequestParam(defaultValue = "10") Integer pageSize,
|
||||||
|
@RequestParam(required = false) Long userId,
|
||||||
|
@RequestParam(required = false) Long couponId,
|
||||||
|
@RequestParam(required = false) CouponStatus status,
|
||||||
|
@RequestParam(required = false) String startTime,
|
||||||
|
@RequestParam(required = false) String endTime) {
|
||||||
|
log.info("分页查询优惠券领取记录: pageNum={}, pageSize={}, userId={}, couponId={}, status={}, startTime={}, endTime={}",
|
||||||
|
pageNum, pageSize, userId, couponId, status, startTime, endTime);
|
||||||
|
PageInfo<PriceCouponClaimRecord> pageInfo = couponManagementService.getClaimRecordsPage(
|
||||||
|
pageNum, pageSize, userId, couponId, status, startTime, endTime);
|
||||||
|
return ApiResponse.success(pageInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据用户ID查询优惠券领取记录
|
||||||
|
*/
|
||||||
|
@GetMapping("/claim-records/user/{userId}")
|
||||||
|
public ApiResponse<List<PriceCouponClaimRecord>> getClaimRecordsByUserId(@PathVariable Long userId) {
|
||||||
|
log.info("根据用户ID查询优惠券领取记录: {}", userId);
|
||||||
|
List<PriceCouponClaimRecord> records = couponManagementService.getClaimRecordsByUserId(userId);
|
||||||
|
return ApiResponse.success(records);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据优惠券ID查询领取记录
|
||||||
|
*/
|
||||||
|
@GetMapping("/claim-records/coupon/{couponId}")
|
||||||
|
public ApiResponse<List<PriceCouponClaimRecord>> getClaimRecordsByCouponId(@PathVariable Long couponId) {
|
||||||
|
log.info("根据优惠券ID查询领取记录: {}", couponId);
|
||||||
|
List<PriceCouponClaimRecord> records = couponManagementService.getClaimRecordsByCouponId(couponId);
|
||||||
|
return ApiResponse.success(records);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据状态查询领取记录
|
||||||
|
*/
|
||||||
|
@GetMapping("/claim-records/status/{status}")
|
||||||
|
public ApiResponse<List<PriceCouponClaimRecord>> getClaimRecordsByStatus(@PathVariable CouponStatus status) {
|
||||||
|
log.info("根据状态查询领取记录: {}", status);
|
||||||
|
List<PriceCouponClaimRecord> records = couponManagementService.getClaimRecordsByStatus(status);
|
||||||
|
return ApiResponse.success(records);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==================== 统计功能 ====================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询优惠券使用统计
|
||||||
|
*/
|
||||||
|
@GetMapping("/stats/{couponId}")
|
||||||
|
public ApiResponse<Map<String, Object>> getCouponUsageStats(@PathVariable Long couponId) {
|
||||||
|
log.info("查询优惠券使用统计: {}", couponId);
|
||||||
|
Map<String, Object> stats = couponManagementService.getCouponUsageStats(couponId);
|
||||||
|
return ApiResponse.success(stats);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询优惠券详细统计
|
||||||
|
*/
|
||||||
|
@GetMapping("/stats/{couponId}/detail")
|
||||||
|
public ApiResponse<Map<String, Object>> getCouponDetailStats(@PathVariable Long couponId) {
|
||||||
|
log.info("查询优惠券详细统计: {}", couponId);
|
||||||
|
Map<String, Object> stats = couponManagementService.getCouponDetailStats(couponId);
|
||||||
|
return ApiResponse.success(stats);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询时间范围内的统计数据
|
||||||
|
*/
|
||||||
|
@GetMapping("/stats/period")
|
||||||
|
public ApiResponse<Map<String, Object>> getPeriodStats(
|
||||||
|
@RequestParam String startDate,
|
||||||
|
@RequestParam String endDate) {
|
||||||
|
log.info("查询时间范围统计: startDate={}, endDate={}", startDate, endDate);
|
||||||
|
Map<String, Object> stats = couponManagementService.getPeriodStats(startDate, endDate);
|
||||||
|
return ApiResponse.success(stats);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询所有优惠券的使用统计概览
|
||||||
|
*/
|
||||||
|
@GetMapping("/stats/overview")
|
||||||
|
public ApiResponse<List<Map<String, Object>>> getAllCouponUsageOverview() {
|
||||||
|
log.info("查询所有优惠券使用统计概览");
|
||||||
|
List<Map<String, Object>> overview = couponManagementService.getAllCouponUsageOverview();
|
||||||
|
return ApiResponse.success(overview);
|
||||||
|
}
|
||||||
|
}
|
@@ -4,9 +4,12 @@ import com.ycwl.basic.utils.ApiResponse;
|
|||||||
import com.ycwl.basic.pricing.entity.PriceProductConfig;
|
import com.ycwl.basic.pricing.entity.PriceProductConfig;
|
||||||
import com.ycwl.basic.pricing.entity.PriceTierConfig;
|
import com.ycwl.basic.pricing.entity.PriceTierConfig;
|
||||||
import com.ycwl.basic.pricing.entity.PriceBundleConfig;
|
import com.ycwl.basic.pricing.entity.PriceBundleConfig;
|
||||||
|
import com.ycwl.basic.pricing.entity.PriceCouponConfig;
|
||||||
|
import com.ycwl.basic.pricing.entity.PriceCouponClaimRecord;
|
||||||
import com.ycwl.basic.pricing.service.IProductConfigService;
|
import com.ycwl.basic.pricing.service.IProductConfigService;
|
||||||
import com.ycwl.basic.pricing.service.IPriceBundleService;
|
import com.ycwl.basic.pricing.service.IPriceBundleService;
|
||||||
import com.ycwl.basic.pricing.service.IPricingManagementService;
|
import com.ycwl.basic.pricing.service.IPricingManagementService;
|
||||||
|
import com.ycwl.basic.pricing.service.ICouponManagementService;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
@@ -25,6 +28,7 @@ public class PricingConfigController {
|
|||||||
private final IProductConfigService productConfigService;
|
private final IProductConfigService productConfigService;
|
||||||
private final IPriceBundleService bundleService;
|
private final IPriceBundleService bundleService;
|
||||||
private final IPricingManagementService managementService;
|
private final IPricingManagementService managementService;
|
||||||
|
private final ICouponManagementService couponManagementService;
|
||||||
|
|
||||||
|
|
||||||
// ==================== 查询API ====================
|
// ==================== 查询API ====================
|
||||||
@@ -273,4 +277,24 @@ public class PricingConfigController {
|
|||||||
List<PriceBundleConfig> configs = bundleService.getAllBundlesForAdmin();
|
List<PriceBundleConfig> configs = bundleService.getAllBundlesForAdmin();
|
||||||
return ApiResponse.success(configs);
|
return ApiResponse.success(configs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 管理端:获取所有优惠券配置(包含禁用的)
|
||||||
|
*/
|
||||||
|
@GetMapping("/admin/coupons")
|
||||||
|
public ApiResponse<List<PriceCouponConfig>> getAllCouponConfigsForAdmin() {
|
||||||
|
log.info("管理端获取所有优惠券配置");
|
||||||
|
List<PriceCouponConfig> configs = couponManagementService.getAllCouponConfigs();
|
||||||
|
return ApiResponse.success(configs);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 管理端:获取所有优惠券领取记录
|
||||||
|
*/
|
||||||
|
@GetMapping("/admin/coupon-records")
|
||||||
|
public ApiResponse<List<PriceCouponClaimRecord>> getAllCouponClaimRecordsForAdmin() {
|
||||||
|
log.info("管理端获取所有优惠券领取记录");
|
||||||
|
List<PriceCouponClaimRecord> records = couponManagementService.getAllClaimRecords();
|
||||||
|
return ApiResponse.success(records);
|
||||||
|
}
|
||||||
}
|
}
|
@@ -0,0 +1,72 @@
|
|||||||
|
package com.ycwl.basic.pricing.handler;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||||
|
import com.fasterxml.jackson.core.type.TypeReference;
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import com.ycwl.basic.pricing.dto.BundleProductItem;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.apache.ibatis.type.BaseTypeHandler;
|
||||||
|
import org.apache.ibatis.type.JdbcType;
|
||||||
|
|
||||||
|
import java.sql.CallableStatement;
|
||||||
|
import java.sql.PreparedStatement;
|
||||||
|
import java.sql.ResultSet;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 一口价商品列表类型处理器
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
public class BundleProductListTypeHandler extends BaseTypeHandler<List<BundleProductItem>> {
|
||||||
|
|
||||||
|
private final ObjectMapper objectMapper = new ObjectMapper();
|
||||||
|
private final TypeReference<List<BundleProductItem>> typeReference = new TypeReference<List<BundleProductItem>>() {};
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setNonNullParameter(PreparedStatement ps, int i, List<BundleProductItem> parameter, JdbcType jdbcType) throws SQLException {
|
||||||
|
try {
|
||||||
|
String json = objectMapper.writeValueAsString(parameter);
|
||||||
|
ps.setString(i, json);
|
||||||
|
log.debug("序列化商品列表: {}", json);
|
||||||
|
} catch (JsonProcessingException e) {
|
||||||
|
log.error("序列化商品列表失败", e);
|
||||||
|
throw new SQLException("序列化商品列表失败", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<BundleProductItem> getNullableResult(ResultSet rs, String columnName) throws SQLException {
|
||||||
|
String json = rs.getString(columnName);
|
||||||
|
return parseJson(json, columnName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<BundleProductItem> getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
|
||||||
|
String json = rs.getString(columnIndex);
|
||||||
|
return parseJson(json, "columnIndex:" + columnIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<BundleProductItem> getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
|
||||||
|
String json = cs.getString(columnIndex);
|
||||||
|
return parseJson(json, "columnIndex:" + columnIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<BundleProductItem> parseJson(String json, String source) {
|
||||||
|
if (json == null || json.trim().isEmpty()) {
|
||||||
|
log.debug("从{}获取的JSON为空,返回空列表", source);
|
||||||
|
return new ArrayList<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
List<BundleProductItem> result = objectMapper.readValue(json, typeReference);
|
||||||
|
log.debug("从{}反序列化商品列表成功,数量: {}", source, result != null ? result.size() : 0);
|
||||||
|
return result != null ? result : new ArrayList<>();
|
||||||
|
} catch (JsonProcessingException e) {
|
||||||
|
log.error("从{}反序列化商品列表失败,JSON: {}", source, json, e);
|
||||||
|
return new ArrayList<>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -60,4 +60,116 @@ public interface PriceCouponClaimRecordMapper extends BaseMapper<PriceCouponClai
|
|||||||
@Update("UPDATE price_coupon_claim_record SET status = #{status}, use_time = #{useTime}, " +
|
@Update("UPDATE price_coupon_claim_record SET status = #{status}, use_time = #{useTime}, " +
|
||||||
"order_id = #{orderId}, updated_time = NOW() WHERE id = #{id}")
|
"order_id = #{orderId}, updated_time = NOW() WHERE id = #{id}")
|
||||||
int updateClaimRecord(PriceCouponClaimRecord record);
|
int updateClaimRecord(PriceCouponClaimRecord record);
|
||||||
|
|
||||||
|
// ==================== 管理端接口 ====================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 管理端:查询所有优惠券领取记录(支持分页)
|
||||||
|
*/
|
||||||
|
@Select("SELECT r.*, c.coupon_name, c.coupon_type, c.discount_value " +
|
||||||
|
"FROM price_coupon_claim_record r " +
|
||||||
|
"LEFT JOIN price_coupon_config c ON r.coupon_id = c.id " +
|
||||||
|
"ORDER BY r.created_time DESC")
|
||||||
|
List<PriceCouponClaimRecord> selectAllForAdmin();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 管理端:根据条件查询优惠券领取记录(支持分页)
|
||||||
|
*/
|
||||||
|
@Select("<script>" +
|
||||||
|
"SELECT r.*, c.coupon_name, c.coupon_type, c.discount_value " +
|
||||||
|
"FROM price_coupon_claim_record r " +
|
||||||
|
"LEFT JOIN price_coupon_config c ON r.coupon_id = c.id " +
|
||||||
|
"<where>" +
|
||||||
|
"<if test='userId != null'>" +
|
||||||
|
"AND r.user_id = #{userId}" +
|
||||||
|
"</if>" +
|
||||||
|
"<if test='couponId != null'>" +
|
||||||
|
"AND r.coupon_id = #{couponId}" +
|
||||||
|
"</if>" +
|
||||||
|
"<if test='status != null'>" +
|
||||||
|
"AND r.status = #{status}" +
|
||||||
|
"</if>" +
|
||||||
|
"<if test='startTime != null and startTime != \"\"'>" +
|
||||||
|
"AND r.claim_time >= #{startTime}" +
|
||||||
|
"</if>" +
|
||||||
|
"<if test='endTime != null and endTime != \"\"'>" +
|
||||||
|
"AND r.claim_time <= #{endTime}" +
|
||||||
|
"</if>" +
|
||||||
|
"</where>" +
|
||||||
|
"ORDER BY r.created_time DESC" +
|
||||||
|
"</script>")
|
||||||
|
List<PriceCouponClaimRecord> selectByConditionsForAdmin(@Param("userId") Long userId,
|
||||||
|
@Param("couponId") Long couponId,
|
||||||
|
@Param("status") CouponStatus status,
|
||||||
|
@Param("startTime") String startTime,
|
||||||
|
@Param("endTime") String endTime);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 管理端:根据用户ID查询优惠券领取记录
|
||||||
|
*/
|
||||||
|
@Select("SELECT r.*, c.coupon_name, c.coupon_type, c.discount_value " +
|
||||||
|
"FROM price_coupon_claim_record r " +
|
||||||
|
"LEFT JOIN price_coupon_config c ON r.coupon_id = c.id " +
|
||||||
|
"WHERE r.user_id = #{userId} " +
|
||||||
|
"ORDER BY r.created_time DESC")
|
||||||
|
List<PriceCouponClaimRecord> selectByUserIdForAdmin(@Param("userId") Long userId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 管理端:根据优惠券ID查询领取记录
|
||||||
|
*/
|
||||||
|
@Select("SELECT r.*, c.coupon_name, c.coupon_type, c.discount_value " +
|
||||||
|
"FROM price_coupon_claim_record r " +
|
||||||
|
"LEFT JOIN price_coupon_config c ON r.coupon_id = c.id " +
|
||||||
|
"WHERE r.coupon_id = #{couponId} " +
|
||||||
|
"ORDER BY r.created_time DESC")
|
||||||
|
List<PriceCouponClaimRecord> selectByCouponIdForAdmin(@Param("couponId") Long couponId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 管理端:根据状态查询领取记录
|
||||||
|
*/
|
||||||
|
@Select("SELECT r.*, c.coupon_name, c.coupon_type, c.discount_value " +
|
||||||
|
"FROM price_coupon_claim_record r " +
|
||||||
|
"LEFT JOIN price_coupon_config c ON r.coupon_id = c.id " +
|
||||||
|
"WHERE r.status = #{status} " +
|
||||||
|
"ORDER BY r.created_time DESC")
|
||||||
|
List<PriceCouponClaimRecord> selectByStatusForAdmin(@Param("status") CouponStatus status);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 管理端:统计优惠券使用情况
|
||||||
|
*/
|
||||||
|
@Select("SELECT " +
|
||||||
|
"COUNT(*) as total_claimed, " +
|
||||||
|
"COUNT(CASE WHEN status = 'USED' THEN 1 END) as total_used, " +
|
||||||
|
"COUNT(CASE WHEN status = 'CLAIMED' THEN 1 END) as total_available " +
|
||||||
|
"FROM price_coupon_claim_record WHERE coupon_id = #{couponId}")
|
||||||
|
java.util.Map<String, Object> selectCouponUsageStats(@Param("couponId") Long couponId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 管理端:统计优惠券详细使用情况
|
||||||
|
*/
|
||||||
|
@Select("SELECT " +
|
||||||
|
"COUNT(*) as total_claimed, " +
|
||||||
|
"COUNT(CASE WHEN status = 'USED' THEN 1 END) as total_used, " +
|
||||||
|
"COUNT(CASE WHEN status = 'CLAIMED' THEN 1 END) as total_available, " +
|
||||||
|
"CASE WHEN COUNT(*) > 0 THEN COUNT(CASE WHEN status = 'USED' THEN 1 END) / COUNT(*) ELSE 0 END as usage_rate, " +
|
||||||
|
"CASE WHEN COUNT(CASE WHEN status = 'USED' THEN 1 END) > 0 THEN " +
|
||||||
|
"AVG(CASE WHEN status = 'USED' AND use_time IS NOT NULL AND claim_time IS NOT NULL THEN " +
|
||||||
|
"DATEDIFF(use_time, claim_time) END) ELSE 0 END as avg_days_to_use " +
|
||||||
|
"FROM price_coupon_claim_record WHERE coupon_id = #{couponId}")
|
||||||
|
java.util.Map<String, Object> selectCouponDetailStats(@Param("couponId") Long couponId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 管理端:统计时间范围内的数据
|
||||||
|
*/
|
||||||
|
@Select("SELECT " +
|
||||||
|
"COUNT(*) as total_claimed, " +
|
||||||
|
"COUNT(CASE WHEN status = 'USED' THEN 1 END) as total_used, " +
|
||||||
|
"COUNT(CASE WHEN status = 'CLAIMED' THEN 1 END) as total_available, " +
|
||||||
|
"COUNT(CASE WHEN status = 'EXPIRED' THEN 1 END) as total_expired, " +
|
||||||
|
"COUNT(DISTINCT coupon_id) as total_coupon_types, " +
|
||||||
|
"COUNT(DISTINCT user_id) as total_users " +
|
||||||
|
"FROM price_coupon_claim_record " +
|
||||||
|
"WHERE claim_time >= #{startDate} AND claim_time <= #{endDate}")
|
||||||
|
java.util.Map<String, Object> selectPeriodStats(@Param("startDate") String startDate,
|
||||||
|
@Param("endDate") String endDate);
|
||||||
}
|
}
|
@@ -59,4 +59,48 @@ public interface PriceCouponConfigMapper extends BaseMapper<PriceCouponConfig> {
|
|||||||
"valid_from = #{validFrom}, valid_until = #{validUntil}, is_active = #{isActive}, " +
|
"valid_from = #{validFrom}, valid_until = #{validUntil}, is_active = #{isActive}, " +
|
||||||
"updated_time = NOW() WHERE id = #{id}")
|
"updated_time = NOW() WHERE id = #{id}")
|
||||||
int updateCoupon(PriceCouponConfig coupon);
|
int updateCoupon(PriceCouponConfig coupon);
|
||||||
|
|
||||||
|
// ==================== 管理端接口 ====================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 管理端:查询所有优惠券配置(包含禁用的)
|
||||||
|
*/
|
||||||
|
@Select("SELECT * FROM price_coupon_config ORDER BY created_time DESC")
|
||||||
|
List<PriceCouponConfig> selectAllForAdmin();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 管理端:根据条件查询优惠券配置(支持分页)
|
||||||
|
*/
|
||||||
|
@Select("<script>" +
|
||||||
|
"SELECT * FROM price_coupon_config " +
|
||||||
|
"<where>" +
|
||||||
|
"<if test='isActive != null'>" +
|
||||||
|
"AND is_active = #{isActive}" +
|
||||||
|
"</if>" +
|
||||||
|
"<if test='couponName != null and couponName != \"\"'>" +
|
||||||
|
"AND coupon_name LIKE CONCAT('%', #{couponName}, '%')" +
|
||||||
|
"</if>" +
|
||||||
|
"</where>" +
|
||||||
|
"ORDER BY created_time DESC" +
|
||||||
|
"</script>")
|
||||||
|
List<PriceCouponConfig> selectByConditionsForAdmin(@Param("isActive") Boolean isActive,
|
||||||
|
@Param("couponName") String couponName);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 管理端:根据状态查询优惠券配置
|
||||||
|
*/
|
||||||
|
@Select("SELECT * FROM price_coupon_config WHERE is_active = #{isActive} ORDER BY created_time DESC")
|
||||||
|
List<PriceCouponConfig> selectByStatusForAdmin(@Param("isActive") Boolean isActive);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 管理端:更新优惠券状态
|
||||||
|
*/
|
||||||
|
@Update("UPDATE price_coupon_config SET is_active = #{isActive}, updated_time = NOW() WHERE id = #{id}")
|
||||||
|
int updateCouponStatus(@Param("id") Long id, @Param("isActive") Boolean isActive);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 管理端:删除优惠券配置
|
||||||
|
*/
|
||||||
|
@Update("UPDATE price_coupon_config SET deleted = 1, updated_time = NOW() WHERE id = #{id}")
|
||||||
|
int deleteCoupon(Long id);
|
||||||
}
|
}
|
@@ -0,0 +1,107 @@
|
|||||||
|
package com.ycwl.basic.pricing.service;
|
||||||
|
|
||||||
|
import com.github.pagehelper.PageInfo;
|
||||||
|
import com.ycwl.basic.pricing.entity.PriceCouponClaimRecord;
|
||||||
|
import com.ycwl.basic.pricing.entity.PriceCouponConfig;
|
||||||
|
import com.ycwl.basic.pricing.enums.CouponStatus;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 优惠券管理服务接口(管理端)
|
||||||
|
*/
|
||||||
|
public interface ICouponManagementService {
|
||||||
|
|
||||||
|
// ==================== 优惠券配置管理 ====================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建优惠券配置
|
||||||
|
*/
|
||||||
|
Long createCouponConfig(PriceCouponConfig config);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新优惠券配置
|
||||||
|
*/
|
||||||
|
boolean updateCouponConfig(PriceCouponConfig config);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除优惠券配置
|
||||||
|
*/
|
||||||
|
boolean deleteCouponConfig(Long id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 启用/禁用优惠券配置
|
||||||
|
*/
|
||||||
|
boolean updateCouponConfigStatus(Long id, Boolean isActive);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询所有优惠券配置(包含禁用的)
|
||||||
|
*/
|
||||||
|
List<PriceCouponConfig> getAllCouponConfigs();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分页查询优惠券配置
|
||||||
|
*/
|
||||||
|
PageInfo<PriceCouponConfig> getCouponConfigsPage(Integer pageNum, Integer pageSize,
|
||||||
|
Boolean isActive, String couponName);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据状态查询优惠券配置
|
||||||
|
*/
|
||||||
|
List<PriceCouponConfig> getCouponConfigsByStatus(Boolean isActive);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据ID查询优惠券配置
|
||||||
|
*/
|
||||||
|
PriceCouponConfig getCouponConfigById(Long id);
|
||||||
|
|
||||||
|
// ==================== 优惠券领取记录查询 ====================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询所有优惠券领取记录
|
||||||
|
*/
|
||||||
|
List<PriceCouponClaimRecord> getAllClaimRecords();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分页查询优惠券领取记录
|
||||||
|
*/
|
||||||
|
PageInfo<PriceCouponClaimRecord> getClaimRecordsPage(Integer pageNum, Integer pageSize,
|
||||||
|
Long userId, Long couponId, CouponStatus status,
|
||||||
|
String startTime, String endTime);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据用户ID查询优惠券领取记录
|
||||||
|
*/
|
||||||
|
List<PriceCouponClaimRecord> getClaimRecordsByUserId(Long userId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据优惠券ID查询领取记录
|
||||||
|
*/
|
||||||
|
List<PriceCouponClaimRecord> getClaimRecordsByCouponId(Long couponId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据状态查询领取记录
|
||||||
|
*/
|
||||||
|
List<PriceCouponClaimRecord> getClaimRecordsByStatus(CouponStatus status);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询优惠券使用统计
|
||||||
|
*/
|
||||||
|
Map<String, Object> getCouponUsageStats(Long couponId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询优惠券配置详细统计
|
||||||
|
*/
|
||||||
|
Map<String, Object> getCouponDetailStats(Long couponId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询时间范围内的统计数据
|
||||||
|
*/
|
||||||
|
Map<String, Object> getPeriodStats(String startDate, String endDate);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询所有优惠券的使用统计概览
|
||||||
|
*/
|
||||||
|
List<Map<String, Object>> getAllCouponUsageOverview();
|
||||||
|
}
|
@@ -0,0 +1,234 @@
|
|||||||
|
package com.ycwl.basic.pricing.service.impl;
|
||||||
|
|
||||||
|
import com.github.pagehelper.PageHelper;
|
||||||
|
import com.github.pagehelper.PageInfo;
|
||||||
|
import com.ycwl.basic.pricing.entity.PriceCouponClaimRecord;
|
||||||
|
import com.ycwl.basic.pricing.entity.PriceCouponConfig;
|
||||||
|
import com.ycwl.basic.pricing.enums.CouponStatus;
|
||||||
|
import com.ycwl.basic.pricing.mapper.PriceCouponClaimRecordMapper;
|
||||||
|
import com.ycwl.basic.pricing.mapper.PriceCouponConfigMapper;
|
||||||
|
import com.ycwl.basic.pricing.service.ICouponManagementService;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 优惠券管理服务实现(管理端)
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Service
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class CouponManagementServiceImpl implements ICouponManagementService {
|
||||||
|
|
||||||
|
private final PriceCouponConfigMapper couponConfigMapper;
|
||||||
|
private final PriceCouponClaimRecordMapper claimRecordMapper;
|
||||||
|
|
||||||
|
// ==================== 优惠券配置管理 ====================
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional
|
||||||
|
public Long createCouponConfig(PriceCouponConfig config) {
|
||||||
|
log.info("创建优惠券配置: {}", config.getCouponName());
|
||||||
|
|
||||||
|
// 设置默认值
|
||||||
|
if (config.getUsedQuantity() == null) {
|
||||||
|
config.setUsedQuantity(0);
|
||||||
|
}
|
||||||
|
if (config.getIsActive() == null) {
|
||||||
|
config.setIsActive(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
int result = couponConfigMapper.insertCoupon(config);
|
||||||
|
if (result > 0) {
|
||||||
|
log.info("优惠券配置创建成功,ID: {}", config.getId());
|
||||||
|
return config.getId();
|
||||||
|
} else {
|
||||||
|
log.error("优惠券配置创建失败");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional
|
||||||
|
public boolean updateCouponConfig(PriceCouponConfig config) {
|
||||||
|
log.info("更新优惠券配置,ID: {}", config.getId());
|
||||||
|
|
||||||
|
PriceCouponConfig existing = couponConfigMapper.selectById(config.getId());
|
||||||
|
if (existing == null) {
|
||||||
|
log.error("优惠券配置不存在,ID: {}", config.getId());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int result = couponConfigMapper.updateCoupon(config);
|
||||||
|
if (result > 0) {
|
||||||
|
log.info("优惠券配置更新成功,ID: {}", config.getId());
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
log.error("优惠券配置更新失败,ID: {}", config.getId());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional
|
||||||
|
public boolean deleteCouponConfig(Long id) {
|
||||||
|
log.info("删除优惠券配置,ID: {}", id);
|
||||||
|
|
||||||
|
PriceCouponConfig existing = couponConfigMapper.selectById(id);
|
||||||
|
if (existing == null) {
|
||||||
|
log.error("优惠券配置不存在,ID: {}", id);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int result = couponConfigMapper.deleteCoupon(id);
|
||||||
|
if (result > 0) {
|
||||||
|
log.info("优惠券配置删除成功,ID: {}", id);
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
log.error("优惠券配置删除失败,ID: {}", id);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional
|
||||||
|
public boolean updateCouponConfigStatus(Long id, Boolean isActive) {
|
||||||
|
log.info("更新优惠券配置状态,ID: {}, 状态: {}", id, isActive);
|
||||||
|
|
||||||
|
PriceCouponConfig existing = couponConfigMapper.selectById(id);
|
||||||
|
if (existing == null) {
|
||||||
|
log.error("优惠券配置不存在,ID: {}", id);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int result = couponConfigMapper.updateCouponStatus(id, isActive);
|
||||||
|
if (result > 0) {
|
||||||
|
log.info("优惠券配置状态更新成功,ID: {}", id);
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
log.error("优惠券配置状态更新失败,ID: {}", id);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<PriceCouponConfig> getAllCouponConfigs() {
|
||||||
|
log.info("查询所有优惠券配置");
|
||||||
|
return couponConfigMapper.selectAllForAdmin();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PageInfo<PriceCouponConfig> getCouponConfigsPage(Integer pageNum, Integer pageSize,
|
||||||
|
Boolean isActive, String couponName) {
|
||||||
|
log.info("分页查询优惠券配置,页码: {}, 页大小: {}, 状态: {}, 名称: {}",
|
||||||
|
pageNum, pageSize, isActive, couponName);
|
||||||
|
|
||||||
|
PageHelper.startPage(pageNum, pageSize);
|
||||||
|
List<PriceCouponConfig> configs = couponConfigMapper.selectByConditionsForAdmin(isActive, couponName);
|
||||||
|
return new PageInfo<>(configs);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<PriceCouponConfig> getCouponConfigsByStatus(Boolean isActive) {
|
||||||
|
log.info("根据状态查询优惠券配置,状态: {}", isActive);
|
||||||
|
return couponConfigMapper.selectByStatusForAdmin(isActive);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PriceCouponConfig getCouponConfigById(Long id) {
|
||||||
|
log.info("根据ID查询优惠券配置,ID: {}", id);
|
||||||
|
return couponConfigMapper.selectById(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==================== 优惠券领取记录查询 ====================
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<PriceCouponClaimRecord> getAllClaimRecords() {
|
||||||
|
log.info("查询所有优惠券领取记录");
|
||||||
|
return claimRecordMapper.selectAllForAdmin();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PageInfo<PriceCouponClaimRecord> getClaimRecordsPage(Integer pageNum, Integer pageSize,
|
||||||
|
Long userId, Long couponId, CouponStatus status,
|
||||||
|
String startTime, String endTime) {
|
||||||
|
log.info("分页查询优惠券领取记录,页码: {}, 页大小: {}, 用户ID: {}, 优惠券ID: {}, 状态: {}, 开始时间: {}, 结束时间: {}",
|
||||||
|
pageNum, pageSize, userId, couponId, status, startTime, endTime);
|
||||||
|
|
||||||
|
PageHelper.startPage(pageNum, pageSize);
|
||||||
|
List<PriceCouponClaimRecord> records = claimRecordMapper.selectByConditionsForAdmin(userId, couponId, status, startTime, endTime);
|
||||||
|
return new PageInfo<>(records);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<PriceCouponClaimRecord> getClaimRecordsByUserId(Long userId) {
|
||||||
|
log.info("根据用户ID查询优惠券领取记录,用户ID: {}", userId);
|
||||||
|
return claimRecordMapper.selectByUserIdForAdmin(userId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<PriceCouponClaimRecord> getClaimRecordsByCouponId(Long couponId) {
|
||||||
|
log.info("根据优惠券ID查询领取记录,优惠券ID: {}", couponId);
|
||||||
|
return claimRecordMapper.selectByCouponIdForAdmin(couponId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<PriceCouponClaimRecord> getClaimRecordsByStatus(CouponStatus status) {
|
||||||
|
log.info("根据状态查询领取记录,状态: {}", status);
|
||||||
|
return claimRecordMapper.selectByStatusForAdmin(status);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<String, Object> getCouponUsageStats(Long couponId) {
|
||||||
|
log.info("查询优惠券使用统计,优惠券ID: {}", couponId);
|
||||||
|
return claimRecordMapper.selectCouponUsageStats(couponId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<String, Object> getCouponDetailStats(Long couponId) {
|
||||||
|
log.info("查询优惠券详细统计,优惠券ID: {}", couponId);
|
||||||
|
return claimRecordMapper.selectCouponDetailStats(couponId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<String, Object> getPeriodStats(String startDate, String endDate) {
|
||||||
|
log.info("查询时间范围统计,开始日期: {}, 结束日期: {}", startDate, endDate);
|
||||||
|
return claimRecordMapper.selectPeriodStats(startDate, endDate);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<Map<String, Object>> getAllCouponUsageOverview() {
|
||||||
|
log.info("查询所有优惠券使用统计概览");
|
||||||
|
|
||||||
|
List<PriceCouponConfig> allCoupons = couponConfigMapper.selectAllForAdmin();
|
||||||
|
List<Map<String, Object>> overview = new ArrayList<>();
|
||||||
|
|
||||||
|
for (PriceCouponConfig coupon : allCoupons) {
|
||||||
|
Map<String, Object> stats = new HashMap<>();
|
||||||
|
stats.put("couponId", coupon.getId());
|
||||||
|
stats.put("couponName", coupon.getCouponName());
|
||||||
|
stats.put("couponType", coupon.getCouponType());
|
||||||
|
stats.put("totalQuantity", coupon.getTotalQuantity());
|
||||||
|
stats.put("usedQuantity", coupon.getUsedQuantity());
|
||||||
|
stats.put("remainingQuantity", coupon.getTotalQuantity() - coupon.getUsedQuantity());
|
||||||
|
stats.put("isActive", coupon.getIsActive());
|
||||||
|
stats.put("validFrom", coupon.getValidFrom());
|
||||||
|
stats.put("validUntil", coupon.getValidUntil());
|
||||||
|
|
||||||
|
// 获取详细统计
|
||||||
|
Map<String, Object> usageStats = claimRecordMapper.selectCouponUsageStats(coupon.getId());
|
||||||
|
stats.putAll(usageStats);
|
||||||
|
|
||||||
|
overview.add(stats);
|
||||||
|
}
|
||||||
|
|
||||||
|
return overview;
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user