修复优惠券模块导致的bug运行不起来
This commit is contained in:
@@ -14,52 +14,57 @@ import org.springframework.stereotype.Component;
|
||||
@Component
|
||||
@ConfigurationProperties(prefix = "mqtt")
|
||||
public class MqttProperties {
|
||||
|
||||
|
||||
/**
|
||||
* 是否启用MQTT服务
|
||||
*/
|
||||
private boolean enabled = false;
|
||||
|
||||
/**
|
||||
* MQTT服务器地址
|
||||
*/
|
||||
private String host = "tcp://127.0.0.1:1883";
|
||||
|
||||
|
||||
/**
|
||||
* 用户名
|
||||
*/
|
||||
private String username = "";
|
||||
|
||||
|
||||
/**
|
||||
* 密码
|
||||
*/
|
||||
private String password = "";
|
||||
|
||||
|
||||
/**
|
||||
* 客户端ID前缀
|
||||
*/
|
||||
private String clientIdPrefix = "mqtt_client_";
|
||||
|
||||
|
||||
/**
|
||||
* 订阅主题
|
||||
*/
|
||||
private String topic = "/SW_GPS/#";
|
||||
|
||||
|
||||
/**
|
||||
* QoS等级
|
||||
*/
|
||||
private int qos = 2;
|
||||
|
||||
|
||||
/**
|
||||
* 连接超时时间(秒)
|
||||
*/
|
||||
private int connectionTimeout = 10;
|
||||
|
||||
|
||||
/**
|
||||
* 心跳间隔(秒)
|
||||
*/
|
||||
private int keepAliveInterval = 20;
|
||||
|
||||
|
||||
/**
|
||||
* 是否自动重连
|
||||
*/
|
||||
private boolean autoReconnect = true;
|
||||
|
||||
|
||||
/**
|
||||
* 是否清除会话
|
||||
*/
|
||||
|
||||
@@ -19,6 +19,8 @@ import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import javax.annotation.Resource;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.util.Arrays;
|
||||
import org.springframework.web.context.request.RequestContextHolder;
|
||||
import org.springframework.web.context.request.ServletRequestAttributes;
|
||||
|
||||
/**
|
||||
* MybatisPlus配置
|
||||
@@ -32,28 +34,36 @@ public class MybatisPlusConfig {
|
||||
private RedisUtil redisUtil;
|
||||
|
||||
@Bean
|
||||
public MybatisPlusInterceptor mybatisPlusInterceptor(HttpServletRequest request) {
|
||||
public MybatisPlusInterceptor mybatisPlusInterceptor() {
|
||||
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
|
||||
|
||||
// 多租户插件配置
|
||||
TenantLineHandler tenantLineHandler = new TenantLineHandler() {
|
||||
@Override
|
||||
public Expression getTenantId() {
|
||||
String tenantId;
|
||||
// 从请求头拿ID
|
||||
tenantId = request.getHeader("tenantId");
|
||||
if(tenantId != null){
|
||||
return new LongValue(tenantId);
|
||||
}
|
||||
// 从域名拿ID
|
||||
String Domain = request.getHeader("Domain");
|
||||
if (StrUtil.isNotBlank(Domain)) {
|
||||
String key = "Domain:" + Domain;
|
||||
tenantId = redisUtil.get(key);
|
||||
if(tenantId != null){
|
||||
System.out.println("从域名拿TID = " + tenantId);
|
||||
return new LongValue(tenantId);
|
||||
String tenantId = null;
|
||||
try {
|
||||
// 从Spring上下文获取当前请求
|
||||
HttpServletRequest request = getCurrentRequest();
|
||||
if (request != null) {
|
||||
// 从请求头拿ID
|
||||
tenantId = request.getHeader("tenantId");
|
||||
if(tenantId != null){
|
||||
return new LongValue(tenantId);
|
||||
}
|
||||
// 从域名拿ID
|
||||
String Domain = request.getHeader("Domain");
|
||||
if (StrUtil.isNotBlank(Domain)) {
|
||||
String key = "Domain:" + Domain;
|
||||
tenantId = redisUtil.get(key);
|
||||
if(tenantId != null){
|
||||
System.out.println("从域名拿TID = " + tenantId);
|
||||
return new LongValue(tenantId);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// 忽略异常,使用默认逻辑
|
||||
}
|
||||
return getLoginUserTenantId();
|
||||
}
|
||||
@@ -111,4 +121,16 @@ public class MybatisPlusConfig {
|
||||
return new NullValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前HTTP请求
|
||||
*/
|
||||
private HttpServletRequest getCurrentRequest() {
|
||||
try {
|
||||
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
|
||||
return attributes != null ? attributes.getRequest() : null;
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -6,9 +6,9 @@ import org.springframework.http.HttpMethod;
|
||||
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||
import org.springframework.security.config.http.SessionCreationPolicy;
|
||||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
||||
import org.springframework.security.web.SecurityFilterChain;
|
||||
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
@@ -22,7 +22,7 @@ import javax.annotation.Resource;
|
||||
@Configuration
|
||||
@EnableWebSecurity
|
||||
@EnableGlobalMethodSecurity(prePostEnabled = true)
|
||||
public class SecurityConfig extends WebSecurityConfigurerAdapter {
|
||||
public class SecurityConfig {
|
||||
@Resource
|
||||
private JwtAccessDeniedHandler jwtAccessDeniedHandler;
|
||||
@Resource
|
||||
@@ -30,9 +30,9 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter {
|
||||
@Resource
|
||||
private JwtAuthenticationFilter jwtAuthenticationFilter;
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http.authorizeRequests()
|
||||
@Bean
|
||||
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
|
||||
return http.authorizeRequests()
|
||||
.antMatchers(HttpMethod.OPTIONS, "/**")
|
||||
.permitAll()
|
||||
.antMatchers(HttpMethod.GET, "/api/file/**","/**", "/api/captcha", "/")
|
||||
@@ -48,6 +48,7 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter {
|
||||
"/v2/api-docs",
|
||||
"/v3/api-docs",
|
||||
"/swagger-ui/**",
|
||||
"/doc.html",
|
||||
"/api/open/**",
|
||||
"/hxz/v1/**",
|
||||
"/api/sendSmsCaptcha",
|
||||
@@ -95,7 +96,8 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter {
|
||||
.accessDeniedHandler(jwtAccessDeniedHandler)
|
||||
.authenticationEntryPoint(jwtAuthenticationEntryPoint)
|
||||
.and()
|
||||
.addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);
|
||||
.addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class)
|
||||
.build();
|
||||
}
|
||||
|
||||
@Bean
|
||||
|
||||
@@ -40,6 +40,12 @@ public class MqttService {
|
||||
try {
|
||||
logger.info("开始初始化MQTT服务...");
|
||||
|
||||
// 检查是否启用MQTT服务
|
||||
if (!mqttProperties.isEnabled()) {
|
||||
logger.info("MQTT服务已禁用,跳过初始化");
|
||||
return;
|
||||
}
|
||||
|
||||
// 验证配置属性
|
||||
validateMqttProperties();
|
||||
|
||||
|
||||
@@ -1,178 +0,0 @@
|
||||
package com.gxwebsoft.shop.controller;
|
||||
|
||||
import com.gxwebsoft.common.core.annotation.OperationLog;
|
||||
import com.gxwebsoft.common.core.web.ApiResult;
|
||||
import com.gxwebsoft.common.core.web.BaseController;
|
||||
import com.gxwebsoft.common.system.entity.User;
|
||||
import com.gxwebsoft.shop.entity.ShopUserCoupon;
|
||||
import com.gxwebsoft.shop.service.CouponBusinessService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 优惠券业务控制器
|
||||
*
|
||||
* @author 科技小王子
|
||||
* @since 2025-08-08 22:30:00
|
||||
*/
|
||||
@Tag(name = "优惠券业务管理")
|
||||
@RestController
|
||||
@RequestMapping("/api/shop/coupon-business")
|
||||
public class CouponBusinessController extends BaseController {
|
||||
|
||||
@Resource
|
||||
private CouponBusinessService couponBusinessService;
|
||||
|
||||
@Operation(summary = "获取订单可用优惠券")
|
||||
@PostMapping("/available-for-order")
|
||||
public ApiResult<List<ShopUserCoupon>> getAvailableCouponsForOrder(
|
||||
@RequestBody Map<String, Object> orderData) {
|
||||
User loginUser = getLoginUser();
|
||||
if (loginUser == null) {
|
||||
return fail("请先登录", null);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
List<Map<String, Object>> goodsItems = (List<Map<String, Object>>) orderData.get("goodsItems");
|
||||
BigDecimal totalAmount = new BigDecimal(orderData.get("totalAmount").toString());
|
||||
|
||||
List<ShopUserCoupon> coupons = couponBusinessService.getAvailableCouponsForOrder(
|
||||
loginUser.getUserId(), goodsItems, totalAmount);
|
||||
|
||||
return success(coupons);
|
||||
}
|
||||
|
||||
@Operation(summary = "计算使用优惠券后的订单金额")
|
||||
@PostMapping("/calculate-order-amount")
|
||||
public ApiResult<Map<String, Object>> calculateOrderAmountWithCoupon(
|
||||
@RequestParam Long userCouponId,
|
||||
@RequestBody Map<String, Object> orderData) {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
List<Map<String, Object>> goodsItems = (List<Map<String, Object>>) orderData.get("goodsItems");
|
||||
BigDecimal totalAmount = new BigDecimal(orderData.get("totalAmount").toString());
|
||||
|
||||
Map<String, Object> result = couponBusinessService.calculateOrderAmountWithCoupon(
|
||||
userCouponId, goodsItems, totalAmount);
|
||||
|
||||
return success(result);
|
||||
}
|
||||
|
||||
@Operation(summary = "验证优惠券是否可用于订单")
|
||||
@PostMapping("/validate-for-order")
|
||||
public ApiResult<Map<String, Object>> validateCouponForOrder(
|
||||
@RequestParam Long userCouponId,
|
||||
@RequestBody Map<String, Object> orderData) {
|
||||
User loginUser = getLoginUser();
|
||||
if (loginUser == null) {
|
||||
return fail("请先登录", null);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
List<Map<String, Object>> goodsItems = (List<Map<String, Object>>) orderData.get("goodsItems");
|
||||
BigDecimal totalAmount = new BigDecimal(orderData.get("totalAmount").toString());
|
||||
|
||||
Map<String, Object> result = couponBusinessService.validateCouponForOrder(
|
||||
userCouponId, loginUser.getUserId(), goodsItems, totalAmount);
|
||||
|
||||
return success(result);
|
||||
}
|
||||
|
||||
@Operation(summary = "推荐最优优惠券组合")
|
||||
@PostMapping("/recommend-best-combination")
|
||||
public ApiResult<Map<String, Object>> recommendBestCouponCombination(
|
||||
@RequestBody Map<String, Object> orderData) {
|
||||
User loginUser = getLoginUser();
|
||||
if (loginUser == null) {
|
||||
return fail("请先登录", null);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
List<Map<String, Object>> goodsItems = (List<Map<String, Object>>) orderData.get("goodsItems");
|
||||
BigDecimal totalAmount = new BigDecimal(orderData.get("totalAmount").toString());
|
||||
|
||||
Map<String, Object> result = couponBusinessService.recommendBestCouponCombination(
|
||||
loginUser.getUserId(), goodsItems, totalAmount);
|
||||
|
||||
return success(result);
|
||||
}
|
||||
|
||||
@PreAuthorize("hasAuthority('shop:coupon:manage')")
|
||||
@OperationLog
|
||||
@Operation(summary = "为新用户发放欢迎优惠券")
|
||||
@PostMapping("/issue-welcome/{userId}")
|
||||
public ApiResult<?> issueWelcomeCoupons(@PathVariable Integer userId) {
|
||||
int count = couponBusinessService.issueWelcomeCoupons(userId);
|
||||
return success("成功发放" + count + "张欢迎优惠券");
|
||||
}
|
||||
|
||||
@PreAuthorize("hasAuthority('shop:coupon:manage')")
|
||||
@OperationLog
|
||||
@Operation(summary = "为用户发放生日优惠券")
|
||||
@PostMapping("/issue-birthday/{userId}")
|
||||
public ApiResult<?> issueBirthdayCoupons(@PathVariable Integer userId) {
|
||||
int count = couponBusinessService.issueBirthdayCoupons(userId);
|
||||
return success("成功发放" + count + "张生日优惠券");
|
||||
}
|
||||
|
||||
@PreAuthorize("hasAuthority('shop:coupon:manage')")
|
||||
@OperationLog
|
||||
@Operation(summary = "根据消费金额发放优惠券")
|
||||
@PostMapping("/issue-consume/{userId}")
|
||||
public ApiResult<?> issueConsumeCoupons(@PathVariable Integer userId,
|
||||
@RequestParam BigDecimal consumeAmount) {
|
||||
int count = couponBusinessService.issueConsumeCoupons(userId, consumeAmount);
|
||||
return success("成功发放" + count + "张消费返券");
|
||||
}
|
||||
|
||||
@PreAuthorize("hasAuthority('shop:coupon:manage')")
|
||||
@OperationLog
|
||||
@Operation(summary = "批量发放活动优惠券")
|
||||
@PostMapping("/batch-issue-activity")
|
||||
public ApiResult<Map<String, Object>> batchIssueActivityCoupons(
|
||||
@RequestParam String activityName,
|
||||
@RequestParam List<Integer> couponIds,
|
||||
@RequestParam(required = false) List<Integer> userIds) {
|
||||
|
||||
Map<String, Object> result = couponBusinessService.batchIssueActivityCoupons(
|
||||
activityName, couponIds, userIds);
|
||||
|
||||
return success(result);
|
||||
}
|
||||
|
||||
@PreAuthorize("hasAuthority('shop:coupon:statistics')")
|
||||
@Operation(summary = "获取优惠券使用统计")
|
||||
@GetMapping("/usage-statistics")
|
||||
public ApiResult<Map<String, Object>> getCouponUsageStatistics(
|
||||
@RequestParam(required = false) String startDate,
|
||||
@RequestParam(required = false) String endDate) {
|
||||
|
||||
Map<String, Object> statistics = couponBusinessService.getCouponUsageStatistics(startDate, endDate);
|
||||
return success(statistics);
|
||||
}
|
||||
|
||||
@PreAuthorize("hasAuthority('shop:coupon:manage')")
|
||||
@OperationLog
|
||||
@Operation(summary = "手动处理过期优惠券")
|
||||
@PostMapping("/process-expired")
|
||||
public ApiResult<?> processExpiredCoupons() {
|
||||
int count = couponBusinessService.autoProcessExpiredCoupons();
|
||||
return success("处理了" + count + "张过期优惠券");
|
||||
}
|
||||
|
||||
@PreAuthorize("hasAuthority('shop:coupon:manage')")
|
||||
@OperationLog
|
||||
@Operation(summary = "发送优惠券到期提醒")
|
||||
@PostMapping("/send-expiry-reminder")
|
||||
public ApiResult<?> sendExpiryReminder(@RequestParam(defaultValue = "3") Integer days) {
|
||||
int count = couponBusinessService.sendCouponExpiryReminder(days);
|
||||
return success("向" + count + "个用户发送了到期提醒");
|
||||
}
|
||||
}
|
||||
@@ -1,129 +0,0 @@
|
||||
package com.gxwebsoft.shop.controller;
|
||||
|
||||
import com.gxwebsoft.common.core.web.BaseController;
|
||||
import com.gxwebsoft.shop.service.ShopUserCouponService;
|
||||
import com.gxwebsoft.shop.entity.ShopUserCoupon;
|
||||
import com.gxwebsoft.shop.param.ShopUserCouponParam;
|
||||
import com.gxwebsoft.common.core.web.ApiResult;
|
||||
import com.gxwebsoft.common.core.web.PageResult;
|
||||
import com.gxwebsoft.common.core.web.PageParam;
|
||||
import com.gxwebsoft.common.core.web.BatchParam;
|
||||
import com.gxwebsoft.common.core.annotation.OperationLog;
|
||||
import com.gxwebsoft.common.system.entity.User;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 用户优惠券控制器
|
||||
*
|
||||
* @author 科技小王子
|
||||
* @since 2025-08-09 15:48:01
|
||||
*/
|
||||
@Tag(name = "用户优惠券管理")
|
||||
@RestController
|
||||
@RequestMapping("/api/shop/shop-user-coupon")
|
||||
public class ShopUserCouponController extends BaseController {
|
||||
@Resource
|
||||
private ShopUserCouponService shopUserCouponService;
|
||||
|
||||
@PreAuthorize("hasAuthority('shop:shopUserCoupon:list')")
|
||||
@Operation(summary = "分页查询用户优惠券")
|
||||
@GetMapping("/page")
|
||||
public ApiResult<PageResult<ShopUserCoupon>> page(ShopUserCouponParam param) {
|
||||
// 使用关联查询
|
||||
return success(shopUserCouponService.pageRel(param));
|
||||
}
|
||||
|
||||
@PreAuthorize("hasAuthority('shop:shopUserCoupon:list')")
|
||||
@Operation(summary = "查询全部用户优惠券")
|
||||
@GetMapping()
|
||||
public ApiResult<List<ShopUserCoupon>> list(ShopUserCouponParam param) {
|
||||
// 使用关联查询
|
||||
return success(shopUserCouponService.listRel(param));
|
||||
}
|
||||
|
||||
@PreAuthorize("hasAuthority('shop:shopUserCoupon:list')")
|
||||
@Operation(summary = "根据id查询用户优惠券")
|
||||
@GetMapping("/{id}")
|
||||
public ApiResult<ShopUserCoupon> get(@PathVariable("id") Integer id) {
|
||||
// 使用关联查询
|
||||
return success(shopUserCouponService.getByIdRel(id));
|
||||
}
|
||||
|
||||
@PreAuthorize("hasAuthority('shop:shopUserCoupon:save')")
|
||||
@OperationLog
|
||||
@Operation(summary = "添加用户优惠券")
|
||||
@PostMapping()
|
||||
public ApiResult<?> save(@RequestBody ShopUserCoupon shopUserCoupon) {
|
||||
// 记录当前登录用户id
|
||||
User loginUser = getLoginUser();
|
||||
if (loginUser != null) {
|
||||
shopUserCoupon.setUserId(loginUser.getUserId());
|
||||
}
|
||||
if (shopUserCouponService.save(shopUserCoupon)) {
|
||||
return success("添加成功");
|
||||
}
|
||||
return fail("添加失败");
|
||||
}
|
||||
|
||||
@PreAuthorize("hasAuthority('shop:shopUserCoupon:update')")
|
||||
@OperationLog
|
||||
@Operation(summary = "修改用户优惠券")
|
||||
@PutMapping()
|
||||
public ApiResult<?> update(@RequestBody ShopUserCoupon shopUserCoupon) {
|
||||
if (shopUserCouponService.updateById(shopUserCoupon)) {
|
||||
return success("修改成功");
|
||||
}
|
||||
return fail("修改失败");
|
||||
}
|
||||
|
||||
@PreAuthorize("hasAuthority('shop:shopUserCoupon:remove')")
|
||||
@OperationLog
|
||||
@Operation(summary = "删除用户优惠券")
|
||||
@DeleteMapping("/{id}")
|
||||
public ApiResult<?> remove(@PathVariable("id") Integer id) {
|
||||
if (shopUserCouponService.removeById(id)) {
|
||||
return success("删除成功");
|
||||
}
|
||||
return fail("删除失败");
|
||||
}
|
||||
|
||||
@PreAuthorize("hasAuthority('shop:shopUserCoupon:save')")
|
||||
@OperationLog
|
||||
@Operation(summary = "批量添加用户优惠券")
|
||||
@PostMapping("/batch")
|
||||
public ApiResult<?> saveBatch(@RequestBody List<ShopUserCoupon> list) {
|
||||
if (shopUserCouponService.saveBatch(list)) {
|
||||
return success("添加成功");
|
||||
}
|
||||
return fail("添加失败");
|
||||
}
|
||||
|
||||
@PreAuthorize("hasAuthority('shop:shopUserCoupon:update')")
|
||||
@OperationLog
|
||||
@Operation(summary = "批量修改用户优惠券")
|
||||
@PutMapping("/batch")
|
||||
public ApiResult<?> removeBatch(@RequestBody BatchParam<ShopUserCoupon> batchParam) {
|
||||
if (batchParam.update(shopUserCouponService, "id")) {
|
||||
return success("修改成功");
|
||||
}
|
||||
return fail("修改失败");
|
||||
}
|
||||
|
||||
@PreAuthorize("hasAuthority('shop:shopUserCoupon:remove')")
|
||||
@OperationLog
|
||||
@Operation(summary = "批量删除用户优惠券")
|
||||
@DeleteMapping("/batch")
|
||||
public ApiResult<?> removeBatch(@RequestBody List<Integer> ids) {
|
||||
if (shopUserCouponService.removeByIds(ids)) {
|
||||
return success("删除成功");
|
||||
}
|
||||
return fail("删除失败");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
package com.gxwebsoft.shop.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.gxwebsoft.shop.entity.ShopUserCoupon;
|
||||
import com.gxwebsoft.shop.param.ShopUserCouponParam;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 用户优惠券Mapper
|
||||
*
|
||||
* @author 科技小王子
|
||||
* @since 2025-08-09 15:48:01
|
||||
*/
|
||||
public interface ShopUserCouponMapper extends BaseMapper<ShopUserCoupon> {
|
||||
|
||||
/**
|
||||
* 分页查询
|
||||
*
|
||||
* @param page 分页对象
|
||||
* @param param 查询参数
|
||||
* @return List<ShopUserCoupon>
|
||||
*/
|
||||
List<ShopUserCoupon> selectPageRel(@Param("page") IPage<ShopUserCoupon> page,
|
||||
@Param("param") ShopUserCouponParam param);
|
||||
|
||||
/**
|
||||
* 查询全部
|
||||
*
|
||||
* @param param 查询参数
|
||||
* @return List<User>
|
||||
*/
|
||||
List<ShopUserCoupon> selectListRel(@Param("param") ShopUserCouponParam param);
|
||||
|
||||
}
|
||||
@@ -1,57 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.gxwebsoft.shop.mapper.ShopGoodsCouponMapper">
|
||||
|
||||
<!-- 关联查询sql -->
|
||||
<sql id="selectSql">
|
||||
SELECT a.*
|
||||
FROM shop_goods_coupon a
|
||||
<where>
|
||||
<if test="param.id != null">
|
||||
AND a.id = #{param.id}
|
||||
</if>
|
||||
<if test="param.goodsId != null">
|
||||
AND a.goods_id = #{param.goodsId}
|
||||
</if>
|
||||
<if test="param.issueCouponId != null">
|
||||
AND a.issue_coupon_id = #{param.issueCouponId}
|
||||
</if>
|
||||
<if test="param.sortNumber != null">
|
||||
AND a.sort_number = #{param.sortNumber}
|
||||
</if>
|
||||
<if test="param.status != null">
|
||||
AND a.status = #{param.status}
|
||||
</if>
|
||||
<if test="param.deleted != null">
|
||||
AND a.deleted = #{param.deleted}
|
||||
</if>
|
||||
<if test="param.deleted == null">
|
||||
AND a.deleted = 0
|
||||
</if>
|
||||
<if test="param.userId != null">
|
||||
AND a.user_id = #{param.userId}
|
||||
</if>
|
||||
<if test="param.createTimeStart != null">
|
||||
AND a.create_time >= #{param.createTimeStart}
|
||||
</if>
|
||||
<if test="param.createTimeEnd != null">
|
||||
AND a.create_time <= #{param.createTimeEnd}
|
||||
</if>
|
||||
<if test="param.keywords != null">
|
||||
AND (a.comments LIKE CONCAT('%', #{param.keywords}, '%')
|
||||
)
|
||||
</if>
|
||||
</where>
|
||||
</sql>
|
||||
|
||||
<!-- 分页查询 -->
|
||||
<select id="selectPageRel" resultType="com.gxwebsoft.shop.entity.ShopGoodsCoupon">
|
||||
<include refid="selectSql"></include>
|
||||
</select>
|
||||
|
||||
<!-- 查询全部 -->
|
||||
<select id="selectListRel" resultType="com.gxwebsoft.shop.entity.ShopGoodsCoupon">
|
||||
<include refid="selectSql"></include>
|
||||
</select>
|
||||
|
||||
</mapper>
|
||||
@@ -1,96 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.gxwebsoft.shop.mapper.ShopUserCouponMapper">
|
||||
|
||||
<!-- 关联查询sql -->
|
||||
<sql id="selectSql">
|
||||
SELECT a.*
|
||||
FROM shop_user_coupon a
|
||||
<where>
|
||||
<if test="param.id != null">
|
||||
AND a.id = #{param.id}
|
||||
</if>
|
||||
<if test="param.couponId != null">
|
||||
AND a.coupon_id = #{param.couponId}
|
||||
</if>
|
||||
<if test="param.userId != null">
|
||||
AND a.user_id = #{param.userId}
|
||||
</if>
|
||||
<if test="param.name != null">
|
||||
AND a.name LIKE CONCAT('%', #{param.name}, '%')
|
||||
</if>
|
||||
<if test="param.description != null">
|
||||
AND a.description LIKE CONCAT('%', #{param.description}, '%')
|
||||
</if>
|
||||
<if test="param.type != null">
|
||||
AND a.type = #{param.type}
|
||||
</if>
|
||||
<if test="param.reducePrice != null">
|
||||
AND a.reduce_price = #{param.reducePrice}
|
||||
</if>
|
||||
<if test="param.discount != null">
|
||||
AND a.discount = #{param.discount}
|
||||
</if>
|
||||
<if test="param.minPrice != null">
|
||||
AND a.min_price = #{param.minPrice}
|
||||
</if>
|
||||
<if test="param.applyRange != null">
|
||||
AND a.apply_range = #{param.applyRange}
|
||||
</if>
|
||||
<if test="param.applyRangeConfig != null">
|
||||
AND a.apply_range_config LIKE CONCAT('%', #{param.applyRangeConfig}, '%')
|
||||
</if>
|
||||
<if test="param.startTime != null">
|
||||
AND a.start_time LIKE CONCAT('%', #{param.startTime}, '%')
|
||||
</if>
|
||||
<if test="param.endTime != null">
|
||||
AND a.end_time LIKE CONCAT('%', #{param.endTime}, '%')
|
||||
</if>
|
||||
<if test="param.status != null">
|
||||
AND a.status = #{param.status}
|
||||
</if>
|
||||
<if test="param.useTime != null">
|
||||
AND a.use_time LIKE CONCAT('%', #{param.useTime}, '%')
|
||||
</if>
|
||||
<if test="param.orderId != null">
|
||||
AND a.order_id LIKE CONCAT('%', #{param.orderId}, '%')
|
||||
</if>
|
||||
<if test="param.orderNo != null">
|
||||
AND a.order_no LIKE CONCAT('%', #{param.orderNo}, '%')
|
||||
</if>
|
||||
<if test="param.obtainType != null">
|
||||
AND a.obtain_type = #{param.obtainType}
|
||||
</if>
|
||||
<if test="param.obtainSource != null">
|
||||
AND a.obtain_source LIKE CONCAT('%', #{param.obtainSource}, '%')
|
||||
</if>
|
||||
<if test="param.deleted != null">
|
||||
AND a.deleted = #{param.deleted}
|
||||
</if>
|
||||
<if test="param.deleted == null">
|
||||
AND a.deleted = 0
|
||||
</if>
|
||||
<if test="param.createTimeStart != null">
|
||||
AND a.create_time >= #{param.createTimeStart}
|
||||
</if>
|
||||
<if test="param.createTimeEnd != null">
|
||||
AND a.create_time <= #{param.createTimeEnd}
|
||||
</if>
|
||||
<if test="param.keywords != null">
|
||||
AND (a.comments LIKE CONCAT('%', #{param.keywords}, '%')
|
||||
)
|
||||
</if>
|
||||
</where>
|
||||
</sql>
|
||||
|
||||
<!-- 分页查询 -->
|
||||
<select id="selectPageRel" resultType="com.gxwebsoft.shop.entity.ShopUserCoupon">
|
||||
<include refid="selectSql"></include>
|
||||
</select>
|
||||
|
||||
<!-- 查询全部 -->
|
||||
<select id="selectListRel" resultType="com.gxwebsoft.shop.entity.ShopUserCoupon">
|
||||
<include refid="selectSql"></include>
|
||||
</select>
|
||||
|
||||
</mapper>
|
||||
@@ -1,96 +0,0 @@
|
||||
package com.gxwebsoft.shop.param;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import com.gxwebsoft.common.core.annotation.QueryField;
|
||||
import com.gxwebsoft.common.core.annotation.QueryType;
|
||||
import com.gxwebsoft.common.core.web.BaseParam;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
/**
|
||||
* 用户优惠券查询参数
|
||||
*
|
||||
* @author 科技小王子
|
||||
* @since 2025-08-09 15:48:01
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
@Schema(name = "ShopUserCouponParam对象", description = "用户优惠券查询参数")
|
||||
public class ShopUserCouponParam extends BaseParam {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Schema(description = "id")
|
||||
@QueryField(type = QueryType.EQ)
|
||||
private Integer id;
|
||||
|
||||
@Schema(description = "优惠券模板ID")
|
||||
@QueryField(type = QueryType.EQ)
|
||||
private Integer couponId;
|
||||
|
||||
@Schema(description = "用户ID")
|
||||
@QueryField(type = QueryType.EQ)
|
||||
private Integer userId;
|
||||
|
||||
@Schema(description = "优惠券名称")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "优惠券描述")
|
||||
private String description;
|
||||
|
||||
@Schema(description = "优惠券类型(10满减券 20折扣券 30免费劵)")
|
||||
@QueryField(type = QueryType.EQ)
|
||||
private Integer type;
|
||||
|
||||
@Schema(description = "满减券-减免金额")
|
||||
@QueryField(type = QueryType.EQ)
|
||||
private BigDecimal reducePrice;
|
||||
|
||||
@Schema(description = "折扣券-折扣率(0-100)")
|
||||
@QueryField(type = QueryType.EQ)
|
||||
private Integer discount;
|
||||
|
||||
@Schema(description = "最低消费金额")
|
||||
@QueryField(type = QueryType.EQ)
|
||||
private BigDecimal minPrice;
|
||||
|
||||
@Schema(description = "适用范围(10全部商品 20指定商品 30指定分类)")
|
||||
@QueryField(type = QueryType.EQ)
|
||||
private Integer applyRange;
|
||||
|
||||
@Schema(description = "适用范围配置(json格式)")
|
||||
private String applyRangeConfig;
|
||||
|
||||
@Schema(description = "有效期开始时间")
|
||||
private String startTime;
|
||||
|
||||
@Schema(description = "有效期结束时间")
|
||||
private String endTime;
|
||||
|
||||
@Schema(description = "使用状态(0未使用 1已使用 2已过期)")
|
||||
@QueryField(type = QueryType.EQ)
|
||||
private Integer status;
|
||||
|
||||
@Schema(description = "使用时间")
|
||||
private String useTime;
|
||||
|
||||
@Schema(description = "使用订单ID")
|
||||
private Long orderId;
|
||||
|
||||
@Schema(description = "使用订单号")
|
||||
private String orderNo;
|
||||
|
||||
@Schema(description = "获取方式(10主动领取 20系统发放 30活动赠送)")
|
||||
@QueryField(type = QueryType.EQ)
|
||||
private Integer obtainType;
|
||||
|
||||
@Schema(description = "获取来源描述")
|
||||
private String obtainSource;
|
||||
|
||||
@Schema(description = "是否删除, 0否, 1是")
|
||||
@QueryField(type = QueryType.EQ)
|
||||
private Boolean deleted;
|
||||
|
||||
}
|
||||
@@ -1,130 +0,0 @@
|
||||
package com.gxwebsoft.shop.service;
|
||||
|
||||
import com.gxwebsoft.shop.entity.ShopUserCoupon;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 优惠券业务服务
|
||||
* 处理订单中的优惠券相关业务逻辑
|
||||
*
|
||||
* @author 科技小王子
|
||||
* @since 2025-08-08 22:00:00
|
||||
*/
|
||||
public interface CouponBusinessService {
|
||||
|
||||
/**
|
||||
* 获取用户在指定订单中可用的优惠券
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @param goodsItems 商品列表 [{goodsId, categoryId, price, quantity}]
|
||||
* @param totalAmount 订单总金额
|
||||
* @return 可用优惠券列表
|
||||
*/
|
||||
List<ShopUserCoupon> getAvailableCouponsForOrder(Integer userId,
|
||||
List<Map<String, Object>> goodsItems,
|
||||
BigDecimal totalAmount);
|
||||
|
||||
/**
|
||||
* 计算使用优惠券后的订单金额
|
||||
*
|
||||
* @param userCouponId 用户优惠券ID
|
||||
* @param goodsItems 商品列表
|
||||
* @param totalAmount 订单总金额
|
||||
* @return 计算结果 {discountAmount: 优惠金额, finalAmount: 最终金额, valid: 是否有效}
|
||||
*/
|
||||
Map<String, Object> calculateOrderAmountWithCoupon(Long userCouponId,
|
||||
List<Map<String, Object>> goodsItems,
|
||||
BigDecimal totalAmount);
|
||||
|
||||
/**
|
||||
* 验证优惠券是否可用于订单
|
||||
*
|
||||
* @param userCouponId 用户优惠券ID
|
||||
* @param userId 用户ID
|
||||
* @param goodsItems 商品列表
|
||||
* @param totalAmount 订单总金额
|
||||
* @return 验证结果 {valid: boolean, reason: String}
|
||||
*/
|
||||
Map<String, Object> validateCouponForOrder(Long userCouponId,
|
||||
Integer userId,
|
||||
List<Map<String, Object>> goodsItems,
|
||||
BigDecimal totalAmount);
|
||||
|
||||
/**
|
||||
* 为新用户发放欢迎优惠券
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @return 发放成功的优惠券数量
|
||||
*/
|
||||
int issueWelcomeCoupons(Integer userId);
|
||||
|
||||
/**
|
||||
* 为用户生日发放生日优惠券
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @return 发放成功的优惠券数量
|
||||
*/
|
||||
int issueBirthdayCoupons(Integer userId);
|
||||
|
||||
/**
|
||||
* 根据用户消费金额发放优惠券
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @param consumeAmount 消费金额
|
||||
* @return 发放成功的优惠券数量
|
||||
*/
|
||||
int issueConsumeCoupons(Integer userId, BigDecimal consumeAmount);
|
||||
|
||||
/**
|
||||
* 活动期间批量发放优惠券
|
||||
*
|
||||
* @param activityName 活动名称
|
||||
* @param couponIds 优惠券模板ID列表
|
||||
* @param userIds 用户ID列表(为空则发放给所有用户)
|
||||
* @return 发放统计 {totalUsers: 总用户数, totalCoupons: 总优惠券数, successCount: 成功数量}
|
||||
*/
|
||||
Map<String, Object> batchIssueActivityCoupons(String activityName,
|
||||
List<Integer> couponIds,
|
||||
List<Integer> userIds);
|
||||
|
||||
/**
|
||||
* 获取优惠券使用统计
|
||||
*
|
||||
* @param startDate 开始日期
|
||||
* @param endDate 结束日期
|
||||
* @return 统计结果
|
||||
*/
|
||||
Map<String, Object> getCouponUsageStatistics(String startDate, String endDate);
|
||||
|
||||
/**
|
||||
* 自动处理过期优惠券
|
||||
* 定时任务调用
|
||||
*
|
||||
* @return 处理数量
|
||||
*/
|
||||
int autoProcessExpiredCoupons();
|
||||
|
||||
/**
|
||||
* 发送优惠券到期提醒
|
||||
* 定时任务调用
|
||||
*
|
||||
* @param days 提前天数
|
||||
* @return 提醒用户数量
|
||||
*/
|
||||
int sendCouponExpiryReminder(Integer days);
|
||||
|
||||
/**
|
||||
* 推荐最优优惠券组合
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @param goodsItems 商品列表
|
||||
* @param totalAmount 订单总金额
|
||||
* @return 推荐结果 {coupons: 优惠券列表, totalDiscount: 总优惠金额, finalAmount: 最终金额}
|
||||
*/
|
||||
Map<String, Object> recommendBestCouponCombination(Integer userId,
|
||||
List<Map<String, Object>> goodsItems,
|
||||
BigDecimal totalAmount);
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
package com.gxwebsoft.shop.service;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import com.gxwebsoft.common.core.web.PageResult;
|
||||
import com.gxwebsoft.shop.entity.ShopUserCoupon;
|
||||
import com.gxwebsoft.shop.param.ShopUserCouponParam;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 用户优惠券Service
|
||||
*
|
||||
* @author 科技小王子
|
||||
* @since 2025-08-09 15:48:01
|
||||
*/
|
||||
public interface ShopUserCouponService extends IService<ShopUserCoupon> {
|
||||
|
||||
/**
|
||||
* 分页关联查询
|
||||
*
|
||||
* @param param 查询参数
|
||||
* @return PageResult<ShopUserCoupon>
|
||||
*/
|
||||
PageResult<ShopUserCoupon> pageRel(ShopUserCouponParam param);
|
||||
|
||||
/**
|
||||
* 关联查询全部
|
||||
*
|
||||
* @param param 查询参数
|
||||
* @return List<ShopUserCoupon>
|
||||
*/
|
||||
List<ShopUserCoupon> listRel(ShopUserCouponParam param);
|
||||
|
||||
/**
|
||||
* 根据id查询
|
||||
*
|
||||
* @param id id
|
||||
* @return ShopUserCoupon
|
||||
*/
|
||||
ShopUserCoupon getByIdRel(Integer id);
|
||||
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
package com.gxwebsoft.shop.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.gxwebsoft.shop.mapper.ShopUserCouponMapper;
|
||||
import com.gxwebsoft.shop.service.ShopUserCouponService;
|
||||
import com.gxwebsoft.shop.entity.ShopUserCoupon;
|
||||
import com.gxwebsoft.shop.param.ShopUserCouponParam;
|
||||
import com.gxwebsoft.common.core.web.PageParam;
|
||||
import com.gxwebsoft.common.core.web.PageResult;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 用户优惠券Service实现
|
||||
*
|
||||
* @author 科技小王子
|
||||
* @since 2025-08-09 15:48:01
|
||||
*/
|
||||
@Service
|
||||
public class ShopUserCouponServiceImpl extends ServiceImpl<ShopUserCouponMapper, ShopUserCoupon> implements ShopUserCouponService {
|
||||
|
||||
@Override
|
||||
public PageResult<ShopUserCoupon> pageRel(ShopUserCouponParam param) {
|
||||
PageParam<ShopUserCoupon, ShopUserCouponParam> page = new PageParam<>(param);
|
||||
page.setDefaultOrder("sort_number asc, create_time desc");
|
||||
List<ShopUserCoupon> list = baseMapper.selectPageRel(page, param);
|
||||
return new PageResult<>(list, page.getTotal());
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ShopUserCoupon> listRel(ShopUserCouponParam param) {
|
||||
List<ShopUserCoupon> list = baseMapper.selectListRel(param);
|
||||
// 排序
|
||||
PageParam<ShopUserCoupon, ShopUserCouponParam> page = new PageParam<>();
|
||||
page.setDefaultOrder("sort_number asc, create_time desc");
|
||||
return page.sortRecords(list);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ShopUserCoupon getByIdRel(Integer id) {
|
||||
ShopUserCouponParam param = new ShopUserCouponParam();
|
||||
param.setId(id);
|
||||
return param.getOne(baseMapper.selectListRel(param));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,65 +0,0 @@
|
||||
package com.gxwebsoft.shop.task;
|
||||
|
||||
import com.gxwebsoft.shop.service.CouponBusinessService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
/**
|
||||
* 优惠券定时任务
|
||||
*
|
||||
* @author 科技小王子
|
||||
* @since 2025-08-08 22:30:00
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
public class CouponScheduledTask {
|
||||
|
||||
@Resource
|
||||
private CouponBusinessService couponBusinessService;
|
||||
|
||||
/**
|
||||
* 每天凌晨2点处理过期优惠券
|
||||
*/
|
||||
@Scheduled(cron = "0 0 2 * * ?")
|
||||
public void processExpiredCoupons() {
|
||||
try {
|
||||
log.info("开始执行过期优惠券处理任务");
|
||||
int count = couponBusinessService.autoProcessExpiredCoupons();
|
||||
log.info("过期优惠券处理任务完成,处理{}张优惠券", count);
|
||||
} catch (Exception e) {
|
||||
log.error("过期优惠券处理任务执行失败", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 每天上午10点发送优惠券到期提醒
|
||||
*/
|
||||
@Scheduled(cron = "0 0 10 * * ?")
|
||||
public void sendExpiryReminder() {
|
||||
try {
|
||||
log.info("开始执行优惠券到期提醒任务");
|
||||
int count = couponBusinessService.sendCouponExpiryReminder(3);
|
||||
log.info("优惠券到期提醒任务完成,提醒{}个用户", count);
|
||||
} catch (Exception e) {
|
||||
log.error("优惠券到期提醒任务执行失败", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 每天凌晨1点发送生日优惠券
|
||||
*/
|
||||
@Scheduled(cron = "0 0 1 * * ?")
|
||||
public void issueBirthdayCoupons() {
|
||||
try {
|
||||
log.info("开始执行生日优惠券发放任务");
|
||||
// 这里需要获取今天生日的用户列表
|
||||
// 由于没有具体的用户生日查询方法,这里只是示例
|
||||
log.info("生日优惠券发放任务完成");
|
||||
} catch (Exception e) {
|
||||
log.error("生日优惠券发放任务执行失败", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user