Compare commits
11 Commits
d9e4371735
...
8a22ad771a
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8a22ad771a | ||
|
|
68d2a99b77 | ||
|
|
359c080023 | ||
|
|
70b299eda6 | ||
|
|
9eeb0c5682 | ||
|
|
818be01c7c | ||
|
|
1ae7a76901 | ||
|
|
95964219a5 | ||
|
|
9344f3750c | ||
| 1575bf504c | |||
| 47ae81ca9f |
18
.workbuddy/memory/2026-04-21.md
Normal file
18
.workbuddy/memory/2026-04-21.md
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
# 2026-04-21 日志
|
||||||
|
|
||||||
|
## WxLoginController.getOrderQRCodeUnlimited 修复(完整)
|
||||||
|
|
||||||
|
### 根因
|
||||||
|
1. `extractTenantIdFromScene` 通过 `selectByIdIgnoreTenant` 反查用户获取 tenantId,userId=35280 在多租户下有2条记录 → `TooManyResultsException`
|
||||||
|
2. 异常被 catch 后 fallback 到默认租户 10550,Redis 中无 `mp-weixin:10550` 缓存 → 最终失败
|
||||||
|
3. 第 452 行 `website.getRunning().equals(2)` 存在 NPE 风险
|
||||||
|
|
||||||
|
### 修复内容
|
||||||
|
- **后端 WxLoginController**: scene 格式改为 `uid_userId_tenantId`,优先从 scene 直接解析 tenantId;兼容旧 `uid_userId` 格式时改用 `selectList` 避免多条记录异常
|
||||||
|
- **后端 UserMapper/UserService**: `selectByIdIgnoreTenant` 返回类型从 `User` 改为 `List<User>`;新增 `listByIdIgnoreTenant` 方法
|
||||||
|
- **后端 NPE 修复**: `website.getRunning().equals(2)` → `website != null && Integer.valueOf(2).equals(website.getRunning())`
|
||||||
|
- **前端 3 个 vue**: scene 从 `uid_${userId}` 改为 `uid_${userId}_${tenantId}`(从 tenantStore.company.tenantId 获取)
|
||||||
|
- shopDealerUser/index.vue
|
||||||
|
- shopDealerUserShop/index.vue
|
||||||
|
- shopDealerUserDelivery/index.vue
|
||||||
|
|
||||||
@@ -2,4 +2,7 @@ package com.gxwebsoft.common.core.constants;
|
|||||||
|
|
||||||
public class BaseConstants {
|
public class BaseConstants {
|
||||||
public static final String[] STATUS = {"未定义","显示","隐藏"};
|
public static final String[] STATUS = {"未定义","显示","隐藏"};
|
||||||
|
|
||||||
|
public static final String FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND = "yyyy-MM-dd HH:mm:ss";
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,43 @@
|
|||||||
|
package com.gxwebsoft.common.core.enums;
|
||||||
|
|
||||||
|
import cn.hutool.core.util.ArrayUtil;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 全局用户类型枚举
|
||||||
|
*/
|
||||||
|
@AllArgsConstructor
|
||||||
|
@Getter
|
||||||
|
public enum UserTypeEnum {
|
||||||
|
|
||||||
|
// 面向 a 端,管理后台
|
||||||
|
RIDER(0, "骑手"),
|
||||||
|
// 面向 c 端,普通用户
|
||||||
|
MEMBER(1, "会员"),
|
||||||
|
|
||||||
|
STORE(3, "门店"),
|
||||||
|
// 面向 b 端,管理后台
|
||||||
|
ADMIN(2, "管理员"),
|
||||||
|
|
||||||
|
CHAT(4, "群聊");
|
||||||
|
|
||||||
|
public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(UserTypeEnum::getValue).toArray();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 类型
|
||||||
|
*/
|
||||||
|
private final Integer value;
|
||||||
|
/**
|
||||||
|
* 类型名
|
||||||
|
*/
|
||||||
|
private final String name;
|
||||||
|
|
||||||
|
public static UserTypeEnum valueOf(Integer value) {
|
||||||
|
return ArrayUtil.firstMatch(userType -> userType.getValue().equals(value), UserTypeEnum.values());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
package com.gxwebsoft.common.core.exception;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 错误码对象
|
||||||
|
*
|
||||||
|
* 全局错误码,占用 [0, 999], 参见 {@link com.gxwebsoft.common.core.exception.enums.GlobalErrorCodeConstants}
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class ErrorCode {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 错误码
|
||||||
|
*/
|
||||||
|
private final Integer code;
|
||||||
|
/**
|
||||||
|
* 错误提示
|
||||||
|
*/
|
||||||
|
private final String msg;
|
||||||
|
|
||||||
|
public ErrorCode(Integer code, String message) {
|
||||||
|
this.code = code;
|
||||||
|
this.msg = message;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
package com.gxwebsoft.common.core.exception.enums;
|
||||||
|
|
||||||
|
import com.gxwebsoft.common.core.exception.ErrorCode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 全局错误码枚举
|
||||||
|
* 0-999 系统异常编码保留
|
||||||
|
*
|
||||||
|
* 一般情况下,使用 HTTP 响应状态码 https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Status
|
||||||
|
* 虽然说,HTTP 响应状态码作为业务使用表达能力偏弱,但是使用在系统层面还是非常不错的
|
||||||
|
* 比较特殊的是,因为之前一直使用 0 作为成功,就不使用 200 啦。
|
||||||
|
*
|
||||||
|
* @author xm
|
||||||
|
*/
|
||||||
|
public interface GlobalErrorCodeConstants {
|
||||||
|
|
||||||
|
ErrorCode SUCCESS = new ErrorCode(0, "成功");
|
||||||
|
|
||||||
|
// ========== 客户端错误段 ==========
|
||||||
|
|
||||||
|
ErrorCode BAD_REQUEST = new ErrorCode(400, "请求参数不正确");
|
||||||
|
ErrorCode UNAUTHORIZED = new ErrorCode(401, "账号未登录");
|
||||||
|
ErrorCode FORBIDDEN = new ErrorCode(403, "没有该操作权限");
|
||||||
|
ErrorCode NOT_FOUND = new ErrorCode(404, "查询无此数据");
|
||||||
|
ErrorCode METHOD_NOT_ALLOWED = new ErrorCode(405, "请求方法不正确");
|
||||||
|
ErrorCode LOCKED = new ErrorCode(423, "请求失败,请稍后重试"); // 并发请求,不允许
|
||||||
|
ErrorCode TOO_MANY_REQUESTS = new ErrorCode(429, "请求过于频繁,请稍后重试");
|
||||||
|
|
||||||
|
// ========== 服务端错误段 ==========
|
||||||
|
|
||||||
|
ErrorCode INTERNAL_SERVER_ERROR = new ErrorCode(500, "系统异常");
|
||||||
|
ErrorCode NOT_IMPLEMENTED = new ErrorCode(501, "功能未实现/未开启");
|
||||||
|
|
||||||
|
// ========== 自定义错误段 ==========
|
||||||
|
ErrorCode REPEATED_REQUESTS = new ErrorCode(900, "重复请求,请稍后重试"); // 重复请求
|
||||||
|
ErrorCode DEMO_DENY = new ErrorCode(901, "演示模式,禁止写操作");
|
||||||
|
|
||||||
|
ErrorCode UNKNOWN = new ErrorCode(999, "未知错误");
|
||||||
|
ErrorCode FINANCE_BILL_NOT_EXISTS = new ErrorCode(600, "门店财务账单不存在");
|
||||||
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
package com.gxwebsoft.common.core.service;
|
package com.gxwebsoft.common.core.service;
|
||||||
|
|
||||||
|
import cn.hutool.core.util.StrUtil;
|
||||||
import com.gxwebsoft.common.system.entity.Payment;
|
import com.gxwebsoft.common.system.entity.Payment;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
@@ -26,6 +27,9 @@ public class EnvironmentAwarePaymentService {
|
|||||||
@Value("${config.server-url:}")
|
@Value("${config.server-url:}")
|
||||||
private String serverUrl;
|
private String serverUrl;
|
||||||
|
|
||||||
|
@Value("${config.api-url:}")
|
||||||
|
private String apiUrl;
|
||||||
|
|
||||||
// 开发环境回调地址配置
|
// 开发环境回调地址配置
|
||||||
@Value("${payment.dev.notify-url:http://frps-10550.s209.websoft.top/api/shop/shop-order/notify}")
|
@Value("${payment.dev.notify-url:http://frps-10550.s209.websoft.top/api/shop/shop-order/notify}")
|
||||||
private String devNotifyUrl;
|
private String devNotifyUrl;
|
||||||
@@ -73,8 +77,8 @@ public class EnvironmentAwarePaymentService {
|
|||||||
// 生产环境使用生产回调地址
|
// 生产环境使用生产回调地址
|
||||||
return prodNotifyUrl;
|
return prodNotifyUrl;
|
||||||
} else {
|
} else {
|
||||||
// 默认使用配置的服务器地址
|
// 默认使用 API 网关地址(支付回调需要公网可访问的 API 地址)
|
||||||
return serverUrl + "/shop/shop-order/notify";
|
return (StrUtil.isNotBlank(apiUrl) ? apiUrl : serverUrl) + "/shop/shop-order/notify";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,29 @@
|
|||||||
|
package com.gxwebsoft.common.core.utils;
|
||||||
|
|
||||||
|
import com.gxwebsoft.common.system.entity.User;
|
||||||
|
import org.springframework.security.core.Authentication;
|
||||||
|
import org.springframework.security.core.context.SecurityContextHolder;
|
||||||
|
|
||||||
|
public class LoginUserUtil {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取当前登录的user
|
||||||
|
*
|
||||||
|
* @return User
|
||||||
|
*/
|
||||||
|
public static User getLoginUser() {
|
||||||
|
try {
|
||||||
|
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
|
||||||
|
if (authentication != null) {
|
||||||
|
Object object = authentication.getPrincipal();
|
||||||
|
if (object instanceof User) {
|
||||||
|
return (User) object;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
System.out.println(e.getMessage());
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -40,6 +40,7 @@ import java.io.File;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
@@ -449,7 +450,7 @@ public class WxLoginController extends BaseController {
|
|||||||
|
|
||||||
// 判断应用运行状态
|
// 判断应用运行状态
|
||||||
final CmsWebsite website = cmsWebsiteService.getByTenantId(tenantId);
|
final CmsWebsite website = cmsWebsiteService.getByTenantId(tenantId);
|
||||||
if(website.getRunning().equals(2)){
|
if(website != null && Integer.valueOf(2).equals(website.getRunning())){
|
||||||
map.put("check_path",false);
|
map.put("check_path",false);
|
||||||
map.put("env_version","trial");
|
map.put("env_version","trial");
|
||||||
}
|
}
|
||||||
@@ -725,27 +726,44 @@ public class WxLoginController extends BaseController {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 从scene参数中提取租户ID
|
* 从scene参数中提取租户ID
|
||||||
* scene格式可能是: uid_33103 或其他包含用户ID的格式
|
* scene格式: uid_userId_tenantId(优先)或 uid_userId(兼容旧格式)
|
||||||
*/
|
*/
|
||||||
private Integer extractTenantIdFromScene(String scene) {
|
private Integer extractTenantIdFromScene(String scene) {
|
||||||
try {
|
try {
|
||||||
System.out.println("解析scene参数: " + scene);
|
System.out.println("解析scene参数: " + scene);
|
||||||
|
|
||||||
// 如果scene包含uid_前缀,提取用户ID
|
|
||||||
if (scene != null && scene.startsWith("uid_")) {
|
if (scene != null && scene.startsWith("uid_")) {
|
||||||
String userIdStr = scene.substring(4); // 去掉"uid_"前缀
|
String content = scene.substring(4); // 去掉"uid_"前缀
|
||||||
Integer userId = Integer.parseInt(userIdStr);
|
|
||||||
System.out.println("userId = " + userId);
|
|
||||||
|
|
||||||
// 根据用户ID查询用户信息,获取租户ID
|
// 优先解析 uid_userId_tenantId 格式
|
||||||
User user = userService.getByIdIgnoreTenant(userId);
|
String[] parts = content.split("_");
|
||||||
System.out.println("user = " + user);
|
if (parts.length >= 2) {
|
||||||
if (user != null) {
|
try {
|
||||||
System.out.println("从用户ID " + userId + " 获取到租户ID: " + user.getTenantId());
|
Integer tenantId = Integer.parseInt(parts[1]);
|
||||||
return user.getTenantId();
|
System.out.println("从scene直接解析到tenantId = " + tenantId);
|
||||||
|
return tenantId;
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
System.err.println("scene中tenantId格式异常: " + parts[1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 兼容旧格式 uid_userId:根据用户ID查询租户ID
|
||||||
|
if (parts.length == 1) {
|
||||||
|
Integer userId = Integer.parseInt(parts[0]);
|
||||||
|
System.out.println("userId = " + userId);
|
||||||
|
try {
|
||||||
|
List<User> users = userService.listByIdIgnoreTenant(userId);
|
||||||
|
System.out.println("查询到用户数量 = " + (users != null ? users.size() : 0));
|
||||||
|
if (users != null && !users.isEmpty()) {
|
||||||
|
System.out.println("从用户ID " + userId + " 获取到租户ID: " + users.get(0).getTenantId());
|
||||||
|
return users.get(0).getTenantId();
|
||||||
} else {
|
} else {
|
||||||
System.err.println("未找到用户ID: " + userId);
|
System.err.println("未找到用户ID: " + userId);
|
||||||
}
|
}
|
||||||
|
} catch (Exception ex) {
|
||||||
|
System.err.println("查询用户异常: " + ex.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 如果无法解析,默认使用租户10550
|
// 如果无法解析,默认使用租户10550
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ public interface UserMapper extends BaseMapper<User> {
|
|||||||
* @return User
|
* @return User
|
||||||
*/
|
*/
|
||||||
@InterceptorIgnore(tenantLine = "true")
|
@InterceptorIgnore(tenantLine = "true")
|
||||||
User selectByIdIgnoreTenant(@Param("userId") Integer userId);
|
List<User> selectByIdIgnoreTenant(@Param("userId") Integer userId);
|
||||||
|
|
||||||
@InterceptorIgnore(tenantLine = "true")
|
@InterceptorIgnore(tenantLine = "true")
|
||||||
List<User> pageAdminByPhone(@Param("param") UserParam param);
|
List<User> pageAdminByPhone(@Param("param") UserParam param);
|
||||||
|
|||||||
@@ -117,6 +117,11 @@ public interface UserService extends IService<User>, UserDetailsService {
|
|||||||
*/
|
*/
|
||||||
User getByIdIgnoreTenant(Integer userId);
|
User getByIdIgnoreTenant(Integer userId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据用户ID查询用户列表(忽略租户隔离)
|
||||||
|
*/
|
||||||
|
List<User> listByIdIgnoreTenant(Integer userId);
|
||||||
|
|
||||||
List<User> pageAdminByPhone(UserParam param);
|
List<User> pageAdminByPhone(UserParam param);
|
||||||
|
|
||||||
List<User> listByAlert();
|
List<User> listByAlert();
|
||||||
|
|||||||
@@ -2,6 +2,9 @@ package com.gxwebsoft.common.system.service.impl;
|
|||||||
|
|
||||||
import cn.hutool.core.util.ObjectUtil;
|
import cn.hutool.core.util.ObjectUtil;
|
||||||
import cn.hutool.core.util.StrUtil;
|
import cn.hutool.core.util.StrUtil;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||||
@@ -224,6 +227,15 @@ public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements Us
|
|||||||
if (userId == null) {
|
if (userId == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
List<User> users = baseMapper.selectByIdIgnoreTenant(userId);
|
||||||
|
return users != null && !users.isEmpty() ? users.get(0) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<User> listByIdIgnoreTenant(Integer userId) {
|
||||||
|
if (userId == null) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
return baseMapper.selectByIdIgnoreTenant(userId);
|
return baseMapper.selectByIdIgnoreTenant(userId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package com.gxwebsoft.glt.service;
|
|||||||
|
|
||||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||||
|
import com.gxwebsoft.common.core.annotation.IgnoreTenant;
|
||||||
import com.gxwebsoft.glt.entity.GltTicketTemplate;
|
import com.gxwebsoft.glt.entity.GltTicketTemplate;
|
||||||
import com.gxwebsoft.glt.entity.GltUserTicket;
|
import com.gxwebsoft.glt.entity.GltUserTicket;
|
||||||
import com.gxwebsoft.glt.entity.GltUserTicketLog;
|
import com.gxwebsoft.glt.entity.GltUserTicketLog;
|
||||||
@@ -12,17 +13,18 @@ import com.gxwebsoft.shop.service.ShopOrderGoodsService;
|
|||||||
import com.gxwebsoft.shop.service.ShopOrderService;
|
import com.gxwebsoft.shop.service.ShopOrderService;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.apache.commons.collections4.CollectionUtils;
|
||||||
|
import org.springframework.scheduling.annotation.Async;
|
||||||
|
import org.springframework.scheduling.annotation.Scheduled;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
import org.springframework.transaction.support.TransactionTemplate;
|
import org.springframework.transaction.support.TransactionTemplate;
|
||||||
|
|
||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.time.LocalTime;
|
import java.time.LocalTime;
|
||||||
import java.util.ArrayList;
|
import java.util.*;
|
||||||
import java.util.HashSet;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 套票发放(从订单生成用户套票 + 释放计划)的业务逻辑。
|
* 套票发放(从订单生成用户套票 + 释放计划)的业务逻辑。
|
||||||
@@ -128,6 +130,57 @@ public class GltTicketIssueService {
|
|||||||
tenantId, uniqueGoodsIds, orders.size(), success, skipped, failed);
|
tenantId, uniqueGoodsIds, orders.size(), success, skipped, failed);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Async
|
||||||
|
// @Scheduled(cron = "0/1 * 4-22 * * ?") 没秒钟执行一次
|
||||||
|
public void paySuccessExecute(String orderNo, Integer tenantId){
|
||||||
|
suerTicketRelease(orderNo, tenantId);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 订单支付成功,直接发送水票【后期优化订单类型,为水票的订单才需要执行此业务】
|
||||||
|
* @param orderNo 订单号
|
||||||
|
* @param tenantId 租户ID
|
||||||
|
*/
|
||||||
|
public void suerTicketRelease(String orderNo, Integer tenantId){
|
||||||
|
//1.订单为空跳过执行
|
||||||
|
ShopOrder shopOrder = shopOrderService.getByOrderNo(orderNo, tenantId);
|
||||||
|
if(shopOrder == null){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//2.跳过已完成发放套票订单
|
||||||
|
if(shopOrder.getOrderStatus() == 1){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//3.订单商品为空跳过执行
|
||||||
|
List<ShopOrderGoods> goodsList = shopOrderGoodsService.getListByOrderIdIgnoreTenant(shopOrder.getOrderId());
|
||||||
|
if (CollectionUtils.isEmpty(goodsList)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//4.执行水票发放业务【】
|
||||||
|
AtomicBoolean release = new AtomicBoolean(false);
|
||||||
|
goodsList.forEach(orderGood ->{
|
||||||
|
IssueOutcome outcome = transactionTemplate.execute(status -> doIssueOne(tenantId, shopOrder, orderGood));
|
||||||
|
if(Arrays.asList(IssueOutcome.ISSUED, IssueOutcome.ALREADY_ISSUED).contains(outcome)){
|
||||||
|
release.set(true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
//5.更新商品订单为已完成、已收到赠品状态
|
||||||
|
if (release.get()) {
|
||||||
|
shopOrderService.update(new LambdaUpdateWrapper<ShopOrder>()
|
||||||
|
.eq(ShopOrder::getOrderId, shopOrder.getOrderId())
|
||||||
|
.eq(ShopOrder::getTenantId, tenantId)
|
||||||
|
.eq(ShopOrder::getOrderStatus, 0)
|
||||||
|
.set(ShopOrder::getOrderStatus, 1)
|
||||||
|
.set(ShopOrder::getHasTakeGift, true)
|
||||||
|
.set(ShopOrder::getUpdateTime, LocalDateTime.now())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private int issueForOrder(Integer tenantId, Set<Integer> goodsIds, ShopOrder order) {
|
private int issueForOrder(Integer tenantId, Set<Integer> goodsIds, ShopOrder order) {
|
||||||
List<ShopOrderGoods> goodsList = shopOrderGoodsService.getListByOrderIdIgnoreTenant(order.getOrderId());
|
List<ShopOrderGoods> goodsList = shopOrderGoodsService.getListByOrderIdIgnoreTenant(order.getOrderId());
|
||||||
if (goodsList == null || goodsList.isEmpty()) {
|
if (goodsList == null || goodsList.isEmpty()) {
|
||||||
@@ -304,12 +357,14 @@ public class GltTicketIssueService {
|
|||||||
|
|
||||||
// 若启用了 releasePeriods 且首期释放时机为“支付成功当刻”,则将首期释放量直接计入可用,
|
// 若启用了 releasePeriods 且首期释放时机为“支付成功当刻”,则将首期释放量直接计入可用,
|
||||||
// 避免用户刚购买后短时间内无可用水票;后续期数仍由自动释放任务按 release_time 释放。
|
// 避免用户刚购买后短时间内无可用水票;后续期数仍由自动释放任务按 release_time 释放。
|
||||||
if (useReleasePeriods && !releases.isEmpty() && !Objects.equals(template.getFirstReleaseMode(), 1)) {
|
// if (useReleasePeriods && !releases.isEmpty() && !Objects.equals(template.getFirstReleaseMode(), 1)) {
|
||||||
|
if (!releases.isEmpty() && !Objects.equals(template.getFirstReleaseMode(), 1)) {
|
||||||
GltUserTicketRelease first = releases.get(0);
|
GltUserTicketRelease first = releases.get(0);
|
||||||
Integer firstQtyObj = first.getReleaseQty();
|
Integer firstQtyObj = first.getReleaseQty();
|
||||||
LocalDateTime firstTime = first.getReleaseTime();
|
LocalDateTime firstTime = first.getReleaseTime();
|
||||||
int firstQty = firstQtyObj != null ? firstQtyObj : 0;
|
int firstQty = firstQtyObj != null ? firstQtyObj : 0;
|
||||||
if (firstQty > 0 && (firstTime == null || !firstTime.isAfter(now))) {
|
// if (firstQty > 0 && (firstTime == null || !firstTime.isAfter(now))) {
|
||||||
|
if (firstQty > 0) {
|
||||||
first.setStatus(1);
|
first.setStatus(1);
|
||||||
first.setUpdateTime(now);
|
first.setUpdateTime(now);
|
||||||
|
|
||||||
@@ -376,10 +431,13 @@ public class GltTicketIssueService {
|
|||||||
|
|
||||||
// 首期释放时间
|
// 首期释放时间
|
||||||
LocalDateTime firstReleaseTime;
|
LocalDateTime firstReleaseTime;
|
||||||
|
LocalDateTime referenceTime;
|
||||||
if (Objects.equals(template.getFirstReleaseMode(), 1)) {
|
if (Objects.equals(template.getFirstReleaseMode(), 1)) {
|
||||||
firstReleaseTime = nextMonthSameDay(baseTime);
|
firstReleaseTime = nextMonthSameDay(baseTime);
|
||||||
|
referenceTime = firstReleaseTime.withDayOfMonth(1).toLocalDate().atStartOfDay();
|
||||||
} else {
|
} else {
|
||||||
firstReleaseTime = baseTime;
|
firstReleaseTime = baseTime;
|
||||||
|
referenceTime = firstReleaseTime.withDayOfMonth(1).toLocalDate().atStartOfDay();
|
||||||
}
|
}
|
||||||
|
|
||||||
// 每期释放数量计算
|
// 每期释放数量计算
|
||||||
@@ -393,7 +451,11 @@ public class GltTicketIssueService {
|
|||||||
if (qty <= 0) {
|
if (qty <= 0) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
list.add(buildRelease(userTicket, i, qty, firstReleaseTime.plusMonths(i), now));
|
if(i == 0){
|
||||||
|
list.add(buildRelease(userTicket, i, qty, firstReleaseTime, now));
|
||||||
|
}else {
|
||||||
|
list.add(buildRelease(userTicket, i, qty, referenceTime.plusMonths(i), now));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
@@ -410,7 +472,11 @@ public class GltTicketIssueService {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
remaining -= qty;
|
remaining -= qty;
|
||||||
list.add(buildRelease(userTicket, i, qty, firstReleaseTime.plusMonths(i), now));
|
if(i == 0){
|
||||||
|
list.add(buildRelease(userTicket, i, qty, firstReleaseTime, now));
|
||||||
|
}else {
|
||||||
|
list.add(buildRelease(userTicket, i, qty, referenceTime.plusMonths(i), now));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return list;
|
return list;
|
||||||
|
|||||||
@@ -878,7 +878,8 @@ public class GltTicketOrderServiceImpl extends ServiceImpl<GltTicketOrderMapper,
|
|||||||
newDealerUser.setFreezeMoney(BigDecimal.ZERO);
|
newDealerUser.setFreezeMoney(BigDecimal.ZERO);
|
||||||
newDealerUser.setTotalMoney(BigDecimal.ZERO);
|
newDealerUser.setTotalMoney(BigDecimal.ZERO);
|
||||||
try {
|
try {
|
||||||
User sysUser = userMapper.selectByIdIgnoreTenant(riderId);
|
List<User> sysUsers = userMapper.selectByIdIgnoreTenant(riderId);
|
||||||
|
User sysUser = (sysUsers != null && !sysUsers.isEmpty()) ? sysUsers.get(0) : null;
|
||||||
if (sysUser != null) {
|
if (sysUser != null) {
|
||||||
newDealerUser.setRealName(sysUser.getRealName() != null ? sysUser.getRealName() : sysUser.getNickname());
|
newDealerUser.setRealName(sysUser.getRealName() != null ? sysUser.getRealName() : sysUser.getNickname());
|
||||||
newDealerUser.setMobile(sysUser.getPhone());
|
newDealerUser.setMobile(sysUser.getPhone());
|
||||||
|
|||||||
@@ -620,7 +620,8 @@ public class DealerOrderSettlement10584Task {
|
|||||||
newDealerUser.setTotalMoney(BigDecimal.ZERO);
|
newDealerUser.setTotalMoney(BigDecimal.ZERO);
|
||||||
// 尽量补齐基础信息,避免表字段 NOT NULL 导致插入失败(插入失败会让门店分佣“找到了人但入不了账”)。
|
// 尽量补齐基础信息,避免表字段 NOT NULL 导致插入失败(插入失败会让门店分佣“找到了人但入不了账”)。
|
||||||
try {
|
try {
|
||||||
User sysUser = userMapper.selectByIdIgnoreTenant(dealerUserId);
|
List<User> sysUsers = userMapper.selectByIdIgnoreTenant(dealerUserId);
|
||||||
|
User sysUser = (sysUsers != null && !sysUsers.isEmpty()) ? sysUsers.get(0) : null;
|
||||||
if (sysUser != null) {
|
if (sysUser != null) {
|
||||||
newDealerUser.setRealName(sysUser.getRealName() != null ? sysUser.getRealName() : sysUser.getNickname());
|
newDealerUser.setRealName(sysUser.getRealName() != null ? sysUser.getRealName() : sysUser.getNickname());
|
||||||
newDealerUser.setMobile(sysUser.getPhone());
|
newDealerUser.setMobile(sysUser.getPhone());
|
||||||
|
|||||||
@@ -0,0 +1,127 @@
|
|||||||
|
package com.gxwebsoft.shop.controller;
|
||||||
|
|
||||||
|
import com.gxwebsoft.common.core.web.BaseController;
|
||||||
|
import com.gxwebsoft.shop.service.ShopActiveImageService;
|
||||||
|
import com.gxwebsoft.shop.entity.ShopActiveImage;
|
||||||
|
import com.gxwebsoft.shop.param.ShopActiveImageParam;
|
||||||
|
import com.gxwebsoft.common.core.web.ApiResult;
|
||||||
|
import com.gxwebsoft.common.core.web.PageResult;
|
||||||
|
import com.gxwebsoft.common.core.web.BatchParam;
|
||||||
|
import com.gxwebsoft.common.core.annotation.OperationLog;
|
||||||
|
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.time.LocalDateTime;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 推广码底图控制器
|
||||||
|
*
|
||||||
|
* @author xm
|
||||||
|
* @since 2026-04-27 18:02:18
|
||||||
|
*/
|
||||||
|
@Tag(name = "推广码底图管理")
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/api/shop/shop-active-image")
|
||||||
|
public class ShopActiveImageController extends BaseController {
|
||||||
|
@Resource
|
||||||
|
private ShopActiveImageService shopActiveImageService;
|
||||||
|
|
||||||
|
// @PreAuthorize("hasAuthority('shop:shopActiveImage:list')")
|
||||||
|
@Operation(summary = "分页查询推广码底图")
|
||||||
|
@GetMapping("/page")
|
||||||
|
public ApiResult<PageResult<ShopActiveImage>> page(ShopActiveImageParam param) {
|
||||||
|
// 使用关联查询
|
||||||
|
return success(shopActiveImageService.pageRel(param));
|
||||||
|
}
|
||||||
|
|
||||||
|
// @PreAuthorize("hasAuthority('shop:shopActiveImage:list')")
|
||||||
|
@Operation(summary = "查询全部推广码底图")
|
||||||
|
@GetMapping()
|
||||||
|
public ApiResult<List<ShopActiveImage>> list(ShopActiveImageParam param) {
|
||||||
|
// 使用关联查询
|
||||||
|
return success(shopActiveImageService.listRel(param));
|
||||||
|
}
|
||||||
|
|
||||||
|
// @PreAuthorize("hasAuthority('shop:shopActiveImage:list')")
|
||||||
|
@Operation(summary = "根据id查询推广码底图")
|
||||||
|
@GetMapping("/{id}")
|
||||||
|
public ApiResult<ShopActiveImage> get(@PathVariable("id") Integer id) {
|
||||||
|
// 使用关联查询
|
||||||
|
return success(shopActiveImageService.getByIdRel(id));
|
||||||
|
}
|
||||||
|
|
||||||
|
// @PreAuthorize("hasAuthority('shop:shopActiveImage:save')")
|
||||||
|
@OperationLog
|
||||||
|
@Operation(summary = "添加推广码底图")
|
||||||
|
@PostMapping()
|
||||||
|
public ApiResult<?> save(@RequestBody ShopActiveImage shopActiveImage) {
|
||||||
|
shopActiveImage.setCreator(String.valueOf(getLoginUserId()));
|
||||||
|
shopActiveImage.setCreateTime(LocalDateTime.now());
|
||||||
|
if (shopActiveImageService.save(shopActiveImage)) {
|
||||||
|
return success("添加成功");
|
||||||
|
}
|
||||||
|
return fail("添加失败");
|
||||||
|
}
|
||||||
|
|
||||||
|
// @PreAuthorize("hasAuthority('shop:shopActiveImage:update')")
|
||||||
|
@OperationLog
|
||||||
|
@Operation(summary = "修改推广码底图")
|
||||||
|
@PutMapping()
|
||||||
|
public ApiResult<?> update(@RequestBody ShopActiveImage shopActiveImage) {
|
||||||
|
shopActiveImage.setUpdater(String.valueOf(getLoginUserId()));
|
||||||
|
shopActiveImage.setUpdateTime(LocalDateTime.now());
|
||||||
|
if (shopActiveImageService.updateById(shopActiveImage)) {
|
||||||
|
return success("修改成功");
|
||||||
|
}
|
||||||
|
return fail("修改失败");
|
||||||
|
}
|
||||||
|
|
||||||
|
// @PreAuthorize("hasAuthority('shop:shopActiveImage:remove')")
|
||||||
|
@OperationLog
|
||||||
|
@Operation(summary = "删除推广码底图")
|
||||||
|
@DeleteMapping("/{id}")
|
||||||
|
public ApiResult<?> remove(@PathVariable("id") Integer id) {
|
||||||
|
if (shopActiveImageService.removeById(id)) {
|
||||||
|
return success("删除成功");
|
||||||
|
}
|
||||||
|
return fail("删除失败");
|
||||||
|
}
|
||||||
|
|
||||||
|
@PreAuthorize("hasAuthority('shop:shopActiveImage:save')")
|
||||||
|
@OperationLog
|
||||||
|
@Operation(summary = "批量添加推广码底图")
|
||||||
|
@PostMapping("/batch")
|
||||||
|
public ApiResult<?> saveBatch(@RequestBody List<ShopActiveImage> list) {
|
||||||
|
if (shopActiveImageService.saveBatch(list)) {
|
||||||
|
return success("添加成功");
|
||||||
|
}
|
||||||
|
return fail("添加失败");
|
||||||
|
}
|
||||||
|
|
||||||
|
@PreAuthorize("hasAuthority('shop:shopActiveImage:update')")
|
||||||
|
@OperationLog
|
||||||
|
@Operation(summary = "批量修改推广码底图")
|
||||||
|
@PutMapping("/batch")
|
||||||
|
public ApiResult<?> removeBatch(@RequestBody BatchParam<ShopActiveImage> batchParam) {
|
||||||
|
if (batchParam.update(shopActiveImageService, "id")) {
|
||||||
|
return success("修改成功");
|
||||||
|
}
|
||||||
|
return fail("修改失败");
|
||||||
|
}
|
||||||
|
|
||||||
|
// @PreAuthorize("hasAuthority('shop:shopActiveImage:remove')")
|
||||||
|
@OperationLog
|
||||||
|
@Operation(summary = "批量删除推广码底图")
|
||||||
|
@DeleteMapping("/batch")
|
||||||
|
public ApiResult<?> removeBatch(@RequestBody List<Integer> ids) {
|
||||||
|
if (shopActiveImageService.removeByIds(ids)) {
|
||||||
|
return success("删除成功");
|
||||||
|
}
|
||||||
|
return fail("删除失败");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,156 @@
|
|||||||
|
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.core.web.BatchParam;
|
||||||
|
import com.gxwebsoft.common.core.web.PageResult;
|
||||||
|
import com.gxwebsoft.common.system.entity.User;
|
||||||
|
import com.gxwebsoft.shop.entity.ShopFlashSaleActivity;
|
||||||
|
import com.gxwebsoft.shop.param.ShopFlashSaleActivityParam;
|
||||||
|
import com.gxwebsoft.shop.service.ShopFlashSaleActivityService;
|
||||||
|
import com.gxwebsoft.shop.vo.ShopFlashSaleActivityVO;
|
||||||
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
|
import io.swagger.v3.oas.annotations.Parameter;
|
||||||
|
import io.swagger.v3.oas.annotations.Parameters;
|
||||||
|
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 xm
|
||||||
|
* @since 2026-04-22 17:18:18
|
||||||
|
*/
|
||||||
|
@Tag(name = "秒杀活动管理")
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/api/shop/shop-flash-sale-activity")
|
||||||
|
public class ShopFlashSaleActivityController extends BaseController {
|
||||||
|
@Resource
|
||||||
|
private ShopFlashSaleActivityService shopFlashSaleActivityService;
|
||||||
|
|
||||||
|
// @PreAuthorize("hasAuthority('shop:shopFlashSaleActivity:list')")
|
||||||
|
@Operation(summary = "后台分页查询秒杀活动")
|
||||||
|
@GetMapping("/page")
|
||||||
|
public ApiResult<PageResult<ShopFlashSaleActivityVO>> page(ShopFlashSaleActivityParam param) {
|
||||||
|
// 使用关联查询
|
||||||
|
return success(shopFlashSaleActivityService.pageRel(param));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Operation(summary = "个人获取秒杀活动数据")
|
||||||
|
@GetMapping("/getMyActive")
|
||||||
|
public ApiResult<List<ShopFlashSaleActivityVO>> getMyActive(@RequestParam("tenantId") Integer tenantId) {
|
||||||
|
// 使用关联查询
|
||||||
|
return success(shopFlashSaleActivityService.getMyActive(tenantId));
|
||||||
|
}
|
||||||
|
|
||||||
|
// @PreAuthorize("hasAuthority('shop:shopFlashSaleActivity:list')")
|
||||||
|
@Operation(summary = "查询全部秒杀活动")
|
||||||
|
@GetMapping()
|
||||||
|
public ApiResult<List<ShopFlashSaleActivity>> list(ShopFlashSaleActivityParam param) {
|
||||||
|
// 使用关联查询
|
||||||
|
return success(shopFlashSaleActivityService.listRel(param));
|
||||||
|
}
|
||||||
|
|
||||||
|
// @PreAuthorize("hasAuthority('shop:shopFlashSaleActivity:list')")
|
||||||
|
@Operation(summary = "根据id查询秒杀活动")
|
||||||
|
@GetMapping("/{id}")
|
||||||
|
public ApiResult<ShopFlashSaleActivity> get(@PathVariable("id") Integer id) {
|
||||||
|
// 使用关联查询
|
||||||
|
return success(shopFlashSaleActivityService.getByIdRel(id));
|
||||||
|
}
|
||||||
|
|
||||||
|
// @PreAuthorize("hasAuthority('shop:shopFlashSaleActivity:save')")
|
||||||
|
@OperationLog
|
||||||
|
@Operation(summary = "添加秒杀活动")
|
||||||
|
@PostMapping()
|
||||||
|
public ApiResult<?> save(@RequestBody ShopFlashSaleActivity shopFlashSaleActivity) {
|
||||||
|
// 记录当前登录用户id
|
||||||
|
User loginUser = getLoginUser();
|
||||||
|
if (loginUser != null) {
|
||||||
|
shopFlashSaleActivity.setCreator(loginUser.getUserId().toString());
|
||||||
|
}
|
||||||
|
if (shopFlashSaleActivityService.save(shopFlashSaleActivity)) {
|
||||||
|
return success("添加成功");
|
||||||
|
}
|
||||||
|
return fail("添加失败");
|
||||||
|
}
|
||||||
|
|
||||||
|
// @PreAuthorize("hasAuthority('shop:shopFlashSaleActivity:update')")
|
||||||
|
@OperationLog
|
||||||
|
@Operation(summary = "修改秒杀活动")
|
||||||
|
@PutMapping()
|
||||||
|
public ApiResult<?> update(@RequestBody ShopFlashSaleActivity shopFlashSaleActivity) {
|
||||||
|
shopFlashSaleActivity.setUpdater(String.valueOf(getLoginUserId()));
|
||||||
|
if (shopFlashSaleActivityService.updateById(shopFlashSaleActivity)) {
|
||||||
|
return success("修改成功");
|
||||||
|
}
|
||||||
|
return fail("修改失败");
|
||||||
|
}
|
||||||
|
|
||||||
|
@OperationLog
|
||||||
|
@Operation(summary = "开启/关闭秒杀活动状态")
|
||||||
|
@PutMapping("/updateStatus")
|
||||||
|
public ApiResult<?> updateStatus(@RequestParam("id") Integer id) {
|
||||||
|
return success(shopFlashSaleActivityService.updateStatus(id));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Operation(summary = "修改秒杀活动排序")
|
||||||
|
@PutMapping("/updateSortNumber")
|
||||||
|
@Parameters({
|
||||||
|
@Parameter(name = "id", description = "活动ID", required = true, example = "1"),
|
||||||
|
@Parameter(name = "sortNumber", description = "排序", required = true, example = "2")
|
||||||
|
})
|
||||||
|
public ApiResult<?> updateSortNumber(@RequestParam("id") Integer id, @RequestParam("sortNumber") Integer sortNumber) {
|
||||||
|
return success(shopFlashSaleActivityService.updateSortNumber(id, sortNumber));
|
||||||
|
}
|
||||||
|
|
||||||
|
// @PreAuthorize("hasAuthority('shop:shopFlashSaleActivity:remove')")
|
||||||
|
@OperationLog
|
||||||
|
@Operation(summary = "删除秒杀活动")
|
||||||
|
@DeleteMapping("/{id}")
|
||||||
|
public ApiResult<?> remove(@PathVariable("id") Integer id) {
|
||||||
|
if (shopFlashSaleActivityService.removeById(id)) {
|
||||||
|
return success("删除成功");
|
||||||
|
}
|
||||||
|
return fail("删除失败");
|
||||||
|
}
|
||||||
|
|
||||||
|
@PreAuthorize("hasAuthority('shop:shopFlashSaleActivity:save')")
|
||||||
|
@OperationLog
|
||||||
|
@Operation(summary = "批量添加秒杀活动")
|
||||||
|
@PostMapping("/batch")
|
||||||
|
public ApiResult<?> saveBatch(@RequestBody List<ShopFlashSaleActivity> list) {
|
||||||
|
if (shopFlashSaleActivityService.saveBatch(list)) {
|
||||||
|
return success("添加成功");
|
||||||
|
}
|
||||||
|
return fail("添加失败");
|
||||||
|
}
|
||||||
|
|
||||||
|
@PreAuthorize("hasAuthority('shop:shopFlashSaleActivity:update')")
|
||||||
|
@OperationLog
|
||||||
|
@Operation(summary = "批量修改秒杀活动")
|
||||||
|
@PutMapping("/batch")
|
||||||
|
public ApiResult<?> removeBatch(@RequestBody BatchParam<ShopFlashSaleActivity> batchParam) {
|
||||||
|
if (batchParam.update(shopFlashSaleActivityService, "id")) {
|
||||||
|
return success("修改成功");
|
||||||
|
}
|
||||||
|
return fail("修改失败");
|
||||||
|
}
|
||||||
|
|
||||||
|
@PreAuthorize("hasAuthority('shop:shopFlashSaleActivity:remove')")
|
||||||
|
@OperationLog
|
||||||
|
@Operation(summary = "批量删除秒杀活动")
|
||||||
|
@DeleteMapping("/batch")
|
||||||
|
public ApiResult<?> removeBatch(@RequestBody List<Integer> ids) {
|
||||||
|
if (shopFlashSaleActivityService.removeByIds(ids)) {
|
||||||
|
return success("删除成功");
|
||||||
|
}
|
||||||
|
return fail("删除失败");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -13,6 +13,7 @@ import com.gxwebsoft.common.core.utils.WechatCertAutoConfig;
|
|||||||
import com.gxwebsoft.common.core.utils.WechatPayConfigValidator;
|
import com.gxwebsoft.common.core.utils.WechatPayConfigValidator;
|
||||||
import com.gxwebsoft.common.core.web.BaseController;
|
import com.gxwebsoft.common.core.web.BaseController;
|
||||||
import com.gxwebsoft.common.system.entity.Payment;
|
import com.gxwebsoft.common.system.entity.Payment;
|
||||||
|
import com.gxwebsoft.glt.service.GltTicketIssueService;
|
||||||
import com.gxwebsoft.shop.entity.ShopOrderDelivery;
|
import com.gxwebsoft.shop.entity.ShopOrderDelivery;
|
||||||
import com.gxwebsoft.shop.entity.ShopUserAddress;
|
import com.gxwebsoft.shop.entity.ShopUserAddress;
|
||||||
import com.gxwebsoft.shop.service.*;
|
import com.gxwebsoft.shop.service.*;
|
||||||
@@ -110,6 +111,8 @@ public class ShopOrderController extends BaseController {
|
|||||||
private GltTicketRevokeService gltTicketRevokeService;
|
private GltTicketRevokeService gltTicketRevokeService;
|
||||||
@Resource
|
@Resource
|
||||||
private ShopDealerCommissionRollbackService shopDealerCommissionRollbackService;
|
private ShopDealerCommissionRollbackService shopDealerCommissionRollbackService;
|
||||||
|
@Resource
|
||||||
|
private GltTicketIssueService gltTicketIssueService;
|
||||||
|
|
||||||
@Operation(summary = "分页查询订单")
|
@Operation(summary = "分页查询订单")
|
||||||
@GetMapping("/page")
|
@GetMapping("/page")
|
||||||
@@ -763,7 +766,7 @@ public class ShopOrderController extends BaseController {
|
|||||||
@Schema(description = "异步通知11")
|
@Schema(description = "异步通知11")
|
||||||
@PostMapping("/notify/{tenantId}")
|
@PostMapping("/notify/{tenantId}")
|
||||||
public String wxNotify(@RequestHeader Map<String, String> header, @RequestBody String body, @PathVariable("tenantId") Integer tenantId) {
|
public String wxNotify(@RequestHeader Map<String, String> header, @RequestBody String body, @PathVariable("tenantId") Integer tenantId) {
|
||||||
logger.info("异步通知*************** = " + tenantId);
|
logger.info("异步通知*************** = " + body + ",租户:" +tenantId);
|
||||||
|
|
||||||
// 获取支付配置信息用于解密
|
// 获取支付配置信息用于解密
|
||||||
String key = "Payment:1:".concat(tenantId.toString());
|
String key = "Payment:1:".concat(tenantId.toString());
|
||||||
@@ -899,7 +902,7 @@ public class ShopOrderController extends BaseController {
|
|||||||
logger.info("开始解析微信支付异步通知...");
|
logger.info("开始解析微信支付异步通知...");
|
||||||
Transaction transaction = parser.parse(requestParam, Transaction.class);
|
Transaction transaction = parser.parse(requestParam, Transaction.class);
|
||||||
logger.info("✅ 异步通知解析成功 - 交易状态: {}, 商户订单号: {}",
|
logger.info("✅ 异步通知解析成功 - 交易状态: {}, 商户订单号: {}",
|
||||||
transaction.getTradeStateDesc(), transaction.getOutTradeNo());
|
transaction.getTradeState(), transaction.getOutTradeNo());
|
||||||
|
|
||||||
// 使用枚举值判断支付状态,避免依赖状态描述字符串
|
// 使用枚举值判断支付状态,避免依赖状态描述字符串
|
||||||
if (Transaction.TradeStateEnum.SUCCESS.equals(transaction.getTradeState())) {
|
if (Transaction.TradeStateEnum.SUCCESS.equals(transaction.getTradeState())) {
|
||||||
@@ -934,6 +937,10 @@ public class ShopOrderController extends BaseController {
|
|||||||
System.out.println("实际付款金额 = " + order.getPayPrice());
|
System.out.println("实际付款金额 = " + order.getPayPrice());
|
||||||
// 更新订单状态并处理支付成功后的业务逻辑(包括累加商品销量)
|
// 更新订单状态并处理支付成功后的业务逻辑(包括累加商品销量)
|
||||||
shopOrderService.updateByOutTradeNo(order);
|
shopOrderService.updateByOutTradeNo(order);
|
||||||
|
|
||||||
|
// //支付成功执行一步任务
|
||||||
|
// gltTicketIssueService.paySuccessExecute(order.getOrderNo(), tenantId);
|
||||||
|
|
||||||
return "SUCCESS";
|
return "SUCCESS";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -147,6 +147,9 @@ public class OrderCreateRequest {
|
|||||||
@NotNull(message = "租户ID不能为空")
|
@NotNull(message = "租户ID不能为空")
|
||||||
private Integer tenantId;
|
private Integer tenantId;
|
||||||
|
|
||||||
|
@Schema(description = "秒杀活动ID")
|
||||||
|
private Integer activityId;
|
||||||
|
|
||||||
@Schema(description = "订单商品列表")
|
@Schema(description = "订单商品列表")
|
||||||
@Valid
|
@Valid
|
||||||
@NotEmpty(message = "订单商品列表不能为空")
|
@NotEmpty(message = "订单商品列表不能为空")
|
||||||
@@ -158,6 +161,9 @@ public class OrderCreateRequest {
|
|||||||
@Data
|
@Data
|
||||||
@Schema(name = "OrderGoodsItem", description = "订单商品项")
|
@Schema(name = "OrderGoodsItem", description = "订单商品项")
|
||||||
public static class OrderGoodsItem {
|
public static class OrderGoodsItem {
|
||||||
|
@Schema(description = "秒杀活动ID")
|
||||||
|
private Integer activityId;
|
||||||
|
|
||||||
@Schema(description = "商品ID", required = true)
|
@Schema(description = "商品ID", required = true)
|
||||||
@NotNull(message = "商品ID不能为空")
|
@NotNull(message = "商品ID不能为空")
|
||||||
private Integer goodsId;
|
private Integer goodsId;
|
||||||
|
|||||||
71
src/main/java/com/gxwebsoft/shop/entity/ShopActiveImage.java
Normal file
71
src/main/java/com/gxwebsoft/shop/entity/ShopActiveImage.java
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
package com.gxwebsoft.shop.entity;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.*;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
|
||||||
|
import javax.validation.constraints.NotNull;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 推广码底图
|
||||||
|
*
|
||||||
|
* @author xm
|
||||||
|
* @since 2026-04-27 18:02:17
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = false)
|
||||||
|
@Schema(name = "ShopActiveImage对象", description = "推广码底图")
|
||||||
|
@TableName("shop_active_image")
|
||||||
|
public class ShopActiveImage implements Serializable {
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
@Schema(description = "主键ID")
|
||||||
|
@TableId(value = "id", type = IdType.AUTO)
|
||||||
|
private Integer id;
|
||||||
|
|
||||||
|
@Schema(description = "名称")
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
@Schema(description = "类型 0-推广底图 1-其他")
|
||||||
|
private Integer type;
|
||||||
|
|
||||||
|
@Schema(description = "图片地址,多个以‘,’隔开")
|
||||||
|
private String imgUrl;
|
||||||
|
|
||||||
|
@Schema(description = "图片地址集合")
|
||||||
|
@TableField(exist = false)
|
||||||
|
private List<String> imgUrlList;
|
||||||
|
|
||||||
|
@Schema(description = "启用状态 0-启用 1-禁用")
|
||||||
|
private Integer status;
|
||||||
|
|
||||||
|
@Schema(description = "排序")
|
||||||
|
private Integer sortNumber;
|
||||||
|
|
||||||
|
@Schema(description = "租户ID")
|
||||||
|
@NotNull(message = "租户ID不能为空!")
|
||||||
|
private Integer tenantId;
|
||||||
|
|
||||||
|
@Schema(description = "创建人")
|
||||||
|
private String creator;
|
||||||
|
|
||||||
|
@Schema(description = "创建时间")
|
||||||
|
private LocalDateTime createTime;
|
||||||
|
|
||||||
|
@Schema(description = "更新人")
|
||||||
|
private String updater;
|
||||||
|
|
||||||
|
@Schema(description = "修改时间")
|
||||||
|
private LocalDateTime updateTime;
|
||||||
|
|
||||||
|
@Schema(description = "是否删除 0-未删 1-已删")
|
||||||
|
@TableLogic
|
||||||
|
private Integer deleted;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,101 @@
|
|||||||
|
package com.gxwebsoft.shop.entity;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.*;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
import com.gxwebsoft.common.core.constants.BaseConstants;
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import org.springframework.format.annotation.DateTimeFormat;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 秒杀活动
|
||||||
|
*
|
||||||
|
* @author xm
|
||||||
|
* @since 2026-04-22 17:18:17
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = false)
|
||||||
|
@Schema(name = "ShopFlashSaleActivity对象", description = "秒杀活动")
|
||||||
|
@TableName("shop_flash_sale_activity")
|
||||||
|
public class ShopFlashSaleActivity implements Serializable {
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
@Schema(description = "秒杀活动编号")
|
||||||
|
@TableId(value = "id", type = IdType.AUTO)
|
||||||
|
private Integer id;
|
||||||
|
|
||||||
|
@Schema(description = "秒杀活动名称")
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
@Schema(description = "秒杀活动商品")
|
||||||
|
private Integer goodsId;
|
||||||
|
|
||||||
|
@Schema(description = "商品skuId")
|
||||||
|
private Integer skuId;
|
||||||
|
|
||||||
|
@Schema(description = "商品数量")
|
||||||
|
private Integer num;
|
||||||
|
|
||||||
|
@Schema(description = "秒杀活动商品价格")
|
||||||
|
private BigDecimal price;
|
||||||
|
|
||||||
|
@Schema(description = "活动状态 0-开启 1-关闭")
|
||||||
|
private Integer status;
|
||||||
|
|
||||||
|
@Schema(
|
||||||
|
description = "活动开始时间",
|
||||||
|
type = "string",
|
||||||
|
pattern = BaseConstants.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND,
|
||||||
|
example = "2026-04-01 12:00:00"
|
||||||
|
)
|
||||||
|
private LocalDateTime startTime;
|
||||||
|
|
||||||
|
@Schema(
|
||||||
|
description = "活动结束时间",
|
||||||
|
type = "string",
|
||||||
|
pattern = BaseConstants.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND,
|
||||||
|
example = "2027-01-01 12:00:00"
|
||||||
|
)
|
||||||
|
private LocalDateTime endTime;
|
||||||
|
|
||||||
|
@Schema(description = "活动限购数量")
|
||||||
|
private Integer saleLimit;
|
||||||
|
|
||||||
|
@Schema(description = "库存")
|
||||||
|
private Integer stock;
|
||||||
|
|
||||||
|
@Schema(description = "展示类型,0:普通用户,1:新用户")
|
||||||
|
private Integer displayType;
|
||||||
|
|
||||||
|
@Schema(description = "备注")
|
||||||
|
private String remark;
|
||||||
|
|
||||||
|
@Schema(description = "排序")
|
||||||
|
private Integer sortNumber;
|
||||||
|
|
||||||
|
@Schema(description = "租户id")
|
||||||
|
private Integer tenantId;
|
||||||
|
|
||||||
|
@Schema(description = "创建者")
|
||||||
|
private String creator;
|
||||||
|
|
||||||
|
@Schema(description = "创建时间", pattern = BaseConstants.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
|
||||||
|
private LocalDateTime createTime;
|
||||||
|
|
||||||
|
@Schema(description = "更新者")
|
||||||
|
private String updater;
|
||||||
|
|
||||||
|
@Schema(description = "更新时间")
|
||||||
|
@DateTimeFormat(pattern = BaseConstants.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
|
||||||
|
private LocalDateTime updateTime;
|
||||||
|
|
||||||
|
@Schema(description = "是否删除")
|
||||||
|
@TableLogic
|
||||||
|
private Integer deleted;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -306,6 +306,9 @@ public class ShopOrder implements Serializable {
|
|||||||
@NotNull(message = "租户ID不能为空")
|
@NotNull(message = "租户ID不能为空")
|
||||||
private Integer tenantId;
|
private Integer tenantId;
|
||||||
|
|
||||||
|
@Schema(description = "秒杀活动ID")
|
||||||
|
private Integer activityId;
|
||||||
|
|
||||||
@Schema(description = "修改时间")
|
@Schema(description = "修改时间")
|
||||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||||
private LocalDateTime updateTime;
|
private LocalDateTime updateTime;
|
||||||
|
|||||||
@@ -0,0 +1,37 @@
|
|||||||
|
package com.gxwebsoft.shop.mapper;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
|
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||||
|
import com.gxwebsoft.shop.entity.ShopActiveImage;
|
||||||
|
import com.gxwebsoft.shop.param.ShopActiveImageParam;
|
||||||
|
import org.apache.ibatis.annotations.Param;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 推广码底图Mapper
|
||||||
|
*
|
||||||
|
* @author xm
|
||||||
|
* @since 2026-04-27 18:02:17
|
||||||
|
*/
|
||||||
|
public interface ShopActiveImageMapper extends BaseMapper<ShopActiveImage> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分页查询
|
||||||
|
*
|
||||||
|
* @param page 分页对象
|
||||||
|
* @param param 查询参数
|
||||||
|
* @return List<ShopActiveImage>
|
||||||
|
*/
|
||||||
|
List<ShopActiveImage> selectPageRel(@Param("page") IPage<ShopActiveImage> page,
|
||||||
|
@Param("param") ShopActiveImageParam param);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询全部
|
||||||
|
*
|
||||||
|
* @param param 查询参数
|
||||||
|
* @return List<User>
|
||||||
|
*/
|
||||||
|
List<ShopActiveImage> selectListRel(@Param("param") ShopActiveImageParam param);
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
package com.gxwebsoft.shop.mapper;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
|
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||||
|
import com.gxwebsoft.shop.entity.ShopFlashSaleActivity;
|
||||||
|
import com.gxwebsoft.shop.param.ShopFlashSaleActivityParam;
|
||||||
|
import com.gxwebsoft.shop.vo.ShopFlashSaleActivityVO;
|
||||||
|
import org.apache.ibatis.annotations.Param;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 秒杀活动Mapper
|
||||||
|
*
|
||||||
|
* @author xm
|
||||||
|
* @since 2026-04-22 17:18:17
|
||||||
|
*/
|
||||||
|
public interface ShopFlashSaleActivityMapper extends BaseMapper<ShopFlashSaleActivity> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分页查询
|
||||||
|
*
|
||||||
|
* @param page 分页对象
|
||||||
|
* @param param 查询参数
|
||||||
|
* @return List<ShopFlashSaleActivity>
|
||||||
|
*/
|
||||||
|
List<ShopFlashSaleActivityVO> selectPageRel(@Param("page") IPage<ShopFlashSaleActivity> page,
|
||||||
|
@Param("param") ShopFlashSaleActivityParam param);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询全部
|
||||||
|
*
|
||||||
|
* @param param 查询参数
|
||||||
|
* @return List<User>
|
||||||
|
*/
|
||||||
|
List<ShopFlashSaleActivity> selectListRel(@Param("param") ShopFlashSaleActivityParam param);
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
<?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.ShopActiveImageMapper">
|
||||||
|
|
||||||
|
<!-- 关联查询sql -->
|
||||||
|
<sql id="selectSql">
|
||||||
|
SELECT a.*
|
||||||
|
FROM shop_active_image a
|
||||||
|
<where>
|
||||||
|
<if test="param.id != null">
|
||||||
|
AND a.id = #{param.id}
|
||||||
|
</if>
|
||||||
|
<if test="param.name != null">
|
||||||
|
AND a.name LIKE CONCAT('%', #{param.name}, '%')
|
||||||
|
</if>
|
||||||
|
<if test="param.type != null">
|
||||||
|
AND a.type = #{param.type}
|
||||||
|
</if>
|
||||||
|
<if test="param.imgUrl != null">
|
||||||
|
AND a.img_url LIKE CONCAT('%', #{param.imgUrl}, '%')
|
||||||
|
</if>
|
||||||
|
<if test="param.status != null">
|
||||||
|
AND a.status = #{param.status}
|
||||||
|
</if>
|
||||||
|
<if test="param.sortNumber != null">
|
||||||
|
AND a.sort_number = #{param.sortNumber}
|
||||||
|
</if>
|
||||||
|
<if test="param.creator != null">
|
||||||
|
AND a.creator LIKE CONCAT('%', #{param.creator}, '%')
|
||||||
|
</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.updater != null">
|
||||||
|
AND a.updater LIKE CONCAT('%', #{param.updater}, '%')
|
||||||
|
</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.keywords != null">
|
||||||
|
AND (a.comments LIKE CONCAT('%', #{param.keywords}, '%')
|
||||||
|
)
|
||||||
|
</if>
|
||||||
|
</where>
|
||||||
|
</sql>
|
||||||
|
|
||||||
|
<!-- 分页查询 -->
|
||||||
|
<select id="selectPageRel" resultType="com.gxwebsoft.shop.entity.ShopActiveImage">
|
||||||
|
<include refid="selectSql"></include>
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<!-- 查询全部 -->
|
||||||
|
<select id="selectListRel" resultType="com.gxwebsoft.shop.entity.ShopActiveImage">
|
||||||
|
<include refid="selectSql"></include>
|
||||||
|
</select>
|
||||||
|
|
||||||
|
</mapper>
|
||||||
@@ -0,0 +1,75 @@
|
|||||||
|
<?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.ShopFlashSaleActivityMapper">
|
||||||
|
|
||||||
|
<!-- 关联查询sql -->
|
||||||
|
<sql id="selectSql">
|
||||||
|
SELECT a.*
|
||||||
|
FROM shop_flash_sale_activity a
|
||||||
|
<where>
|
||||||
|
<if test="param.id != null">
|
||||||
|
AND a.id = #{param.id}
|
||||||
|
</if>
|
||||||
|
<if test="param.name != null">
|
||||||
|
AND a.name LIKE CONCAT('%', #{param.name}, '%')
|
||||||
|
</if>
|
||||||
|
<if test="param.goodsId != null">
|
||||||
|
AND a.goods_id LIKE CONCAT('%', #{param.goodsId}, '%')
|
||||||
|
</if>
|
||||||
|
<if test="param.status != null">
|
||||||
|
AND a.status = #{param.status}
|
||||||
|
</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.stock != null">
|
||||||
|
AND a.stock = #{param.stock}
|
||||||
|
</if>
|
||||||
|
<if test="param.displayType != null">
|
||||||
|
AND a.display_type = #{param.displayType}
|
||||||
|
</if>
|
||||||
|
<if test="param.remark != null">
|
||||||
|
AND a.remark LIKE CONCAT('%', #{param.remark}, '%')
|
||||||
|
</if>
|
||||||
|
<if test="param.sortNumber != null">
|
||||||
|
AND a.sort_number = #{param.sortNumber}
|
||||||
|
</if>
|
||||||
|
<if test="param.creator != null">
|
||||||
|
AND a.creator LIKE CONCAT('%', #{param.creator}, '%')
|
||||||
|
</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.updater != null">
|
||||||
|
AND a.updater LIKE CONCAT('%', #{param.updater}, '%')
|
||||||
|
</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.keywords != null">
|
||||||
|
AND (a.comments LIKE CONCAT('%', #{param.keywords}, '%')
|
||||||
|
)
|
||||||
|
</if>
|
||||||
|
</where>
|
||||||
|
</sql>
|
||||||
|
|
||||||
|
<!-- 分页查询 -->
|
||||||
|
<select id="selectPageRel" resultType="com.gxwebsoft.shop.vo.ShopFlashSaleActivityVO">
|
||||||
|
<include refid="selectSql"></include>
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<!-- 查询全部 -->
|
||||||
|
<select id="selectListRel" resultType="com.gxwebsoft.shop.entity.ShopFlashSaleActivity">
|
||||||
|
<include refid="selectSql"></include>
|
||||||
|
</select>
|
||||||
|
|
||||||
|
</mapper>
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
package com.gxwebsoft.shop.param;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||||
|
import com.gxwebsoft.common.core.annotation.QueryField;
|
||||||
|
import com.gxwebsoft.common.core.annotation.QueryType;
|
||||||
|
import com.gxwebsoft.common.core.web.BaseParam;
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 推广码底图查询参数
|
||||||
|
*
|
||||||
|
* @author xm
|
||||||
|
* @since 2026-04-27 18:02:17
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = false)
|
||||||
|
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||||
|
@Schema(name = "ShopActiveImageParam对象", description = "推广码底图查询参数")
|
||||||
|
public class ShopActiveImageParam extends BaseParam {
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
@Schema(description = "主键ID")
|
||||||
|
@QueryField(type = QueryType.EQ)
|
||||||
|
private Integer id;
|
||||||
|
|
||||||
|
@Schema(description = "名称")
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
@Schema(description = "类型 0-推广底图 1-其他")
|
||||||
|
@QueryField(type = QueryType.EQ)
|
||||||
|
private Integer type;
|
||||||
|
|
||||||
|
@Schema(description = "图片地址")
|
||||||
|
private String imgUrl;
|
||||||
|
|
||||||
|
@Schema(description = "启用状态 0-启用 1-禁用")
|
||||||
|
@QueryField(type = QueryType.EQ)
|
||||||
|
private Integer status;
|
||||||
|
|
||||||
|
@Schema(description = "排序")
|
||||||
|
@QueryField(type = QueryType.EQ)
|
||||||
|
private Integer sortNumber;
|
||||||
|
|
||||||
|
@Schema(description = "创建人")
|
||||||
|
private String creator;
|
||||||
|
|
||||||
|
@Schema(description = "更新人")
|
||||||
|
private String updater;
|
||||||
|
|
||||||
|
@Schema(description = "是否删除 0-未删 1-已删")
|
||||||
|
@QueryField(type = QueryType.EQ)
|
||||||
|
private Integer deleted;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,82 @@
|
|||||||
|
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 xm
|
||||||
|
* @since 2026-04-22 17:18:17
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = false)
|
||||||
|
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||||
|
@Schema(name = "ShopFlashSaleActivityParam对象", description = "秒杀活动查询参数")
|
||||||
|
public class ShopFlashSaleActivityParam extends BaseParam {
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
@Schema(description = "秒杀活动编号")
|
||||||
|
@QueryField(type = QueryType.EQ)
|
||||||
|
private Integer id;
|
||||||
|
|
||||||
|
@Schema(description = "秒杀活动名称")
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
@Schema(description = "秒杀活动商品")
|
||||||
|
private Integer goodsId;
|
||||||
|
|
||||||
|
@Schema(description = "商品skuId")
|
||||||
|
private Integer skuId;
|
||||||
|
|
||||||
|
@Schema(description = "商品数量")
|
||||||
|
private Integer num;
|
||||||
|
|
||||||
|
@Schema(description = "秒杀活动商品价格")
|
||||||
|
private BigDecimal price;
|
||||||
|
|
||||||
|
@Schema(description = "活动状态 0-开启 1-关闭")
|
||||||
|
@QueryField(type = QueryType.EQ)
|
||||||
|
private Integer status;
|
||||||
|
|
||||||
|
@Schema(description = "活动开始时间")
|
||||||
|
private String startTime;
|
||||||
|
|
||||||
|
@Schema(description = "活动结束时间")
|
||||||
|
private String endTime;
|
||||||
|
|
||||||
|
@Schema(description = "活动限购数量")
|
||||||
|
private Integer saleLimit;
|
||||||
|
|
||||||
|
@Schema(description = "库存")
|
||||||
|
@QueryField(type = QueryType.EQ)
|
||||||
|
private Integer stock;
|
||||||
|
|
||||||
|
@Schema(description = "展示类型,0:普通用户,1:新用户")
|
||||||
|
@QueryField(type = QueryType.EQ)
|
||||||
|
private Integer displayType;
|
||||||
|
|
||||||
|
@Schema(description = "备注")
|
||||||
|
private String remark;
|
||||||
|
|
||||||
|
@Schema(description = "排序")
|
||||||
|
@QueryField(type = QueryType.EQ)
|
||||||
|
private Integer sortNumber;
|
||||||
|
|
||||||
|
@Schema(description = "创建者")
|
||||||
|
private String creator;
|
||||||
|
|
||||||
|
@Schema(description = "更新者")
|
||||||
|
private String updater;
|
||||||
|
|
||||||
|
@Schema(description = "是否删除")
|
||||||
|
@QueryField(type = QueryType.EQ)
|
||||||
|
private Integer deleted;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -3,10 +3,12 @@ package com.gxwebsoft.shop.service;
|
|||||||
import cn.hutool.core.util.IdUtil;
|
import cn.hutool.core.util.IdUtil;
|
||||||
import cn.hutool.core.util.ObjectUtil;
|
import cn.hutool.core.util.ObjectUtil;
|
||||||
import com.gxwebsoft.common.core.exception.BusinessException;
|
import com.gxwebsoft.common.core.exception.BusinessException;
|
||||||
|
import com.gxwebsoft.common.core.exception.enums.GlobalErrorCodeConstants;
|
||||||
import com.gxwebsoft.common.system.entity.User;
|
import com.gxwebsoft.common.system.entity.User;
|
||||||
import com.gxwebsoft.shop.config.OrderConfigProperties;
|
import com.gxwebsoft.shop.config.OrderConfigProperties;
|
||||||
import com.gxwebsoft.shop.dto.OrderCreateRequest;
|
import com.gxwebsoft.shop.dto.OrderCreateRequest;
|
||||||
import com.gxwebsoft.shop.entity.*;
|
import com.gxwebsoft.shop.entity.*;
|
||||||
|
import com.gxwebsoft.shop.mapper.ShopFlashSaleActivityMapper;
|
||||||
import com.gxwebsoft.shop.service.ShopStoreFenceService;
|
import com.gxwebsoft.shop.service.ShopStoreFenceService;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.beans.BeanUtils;
|
import org.springframework.beans.BeanUtils;
|
||||||
@@ -52,11 +54,16 @@ public class OrderBusinessService {
|
|||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
private ShopUserAddressService shopUserAddressService;
|
private ShopUserAddressService shopUserAddressService;
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
private ShopUserCouponService shopUserCouponService;
|
private ShopUserCouponService shopUserCouponService;
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
private ShopStoreFenceService shopStoreFenceService;
|
private ShopStoreFenceService shopStoreFenceService;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private ShopFlashSaleActivityMapper shopFlashSaleActivityMapper;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 创建订单
|
* 创建订单
|
||||||
*
|
*
|
||||||
@@ -167,6 +174,8 @@ public class OrderBusinessService {
|
|||||||
BigDecimal total = BigDecimal.ZERO;
|
BigDecimal total = BigDecimal.ZERO;
|
||||||
|
|
||||||
for (OrderCreateRequest.OrderGoodsItem item : request.getGoodsItems()) {
|
for (OrderCreateRequest.OrderGoodsItem item : request.getGoodsItems()) {
|
||||||
|
Integer activityId = item.getActivityId();
|
||||||
|
|
||||||
// 验证商品ID
|
// 验证商品ID
|
||||||
if (item.getGoodsId() == null) {
|
if (item.getGoodsId() == null) {
|
||||||
throw new BusinessException("商品ID不能为空");
|
throw new BusinessException("商品ID不能为空");
|
||||||
@@ -216,6 +225,25 @@ public class OrderBusinessService {
|
|||||||
productName = goods.getName() + "(" + (item.getSpecInfo() != null ? item.getSpecInfo() : sku.getSku()) + ")";
|
productName = goods.getName() + "(" + (item.getSpecInfo() != null ? item.getSpecInfo() : sku.getSku()) + ")";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//秒杀商品价格以秒杀价为准
|
||||||
|
if(activityId != null){
|
||||||
|
request.setActivityId(activityId);
|
||||||
|
ShopFlashSaleActivity saleActivity = shopFlashSaleActivityMapper.selectById(activityId);
|
||||||
|
if(saleActivity == null){
|
||||||
|
throw new BusinessException("秒杀活动数据查询失败!");
|
||||||
|
}
|
||||||
|
if(saleActivity.getStatus() != 0){
|
||||||
|
throw new BusinessException("当前秒杀活动已失效!");
|
||||||
|
}
|
||||||
|
if(saleActivity.getStock() <= 0){
|
||||||
|
throw new BusinessException("当前秒杀活动商品已售罄!");
|
||||||
|
}
|
||||||
|
if(item.getQuantity() > saleActivity.getSaleLimit()){
|
||||||
|
throw new BusinessException("选购数量已超秒杀活动限购数量!");
|
||||||
|
}
|
||||||
|
actualPrice = saleActivity.getPrice();
|
||||||
|
}
|
||||||
|
|
||||||
// 验证实际价格
|
// 验证实际价格
|
||||||
if (actualPrice == null || actualPrice.compareTo(BigDecimal.ZERO) <= 0) {
|
if (actualPrice == null || actualPrice.compareTo(BigDecimal.ZERO) <= 0) {
|
||||||
throw new BusinessException("商品价格异常:" + productName);
|
throw new BusinessException("商品价格异常:" + productName);
|
||||||
@@ -651,6 +679,13 @@ public class OrderBusinessService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//秒杀商品价格以秒杀价为准
|
||||||
|
Integer activityId = item.getActivityId();
|
||||||
|
if(activityId != null){
|
||||||
|
ShopFlashSaleActivity saleActivity = shopFlashSaleActivityMapper.selectById(activityId);
|
||||||
|
actualPrice = saleActivity.getPrice();
|
||||||
|
}
|
||||||
|
|
||||||
// 验证库存
|
// 验证库存
|
||||||
if (actualStock == null || actualStock < item.getQuantity()) {
|
if (actualStock == null || actualStock < item.getQuantity()) {
|
||||||
String stockMsg = sku != null ? "商品规格库存不足" : "商品库存不足";
|
String stockMsg = sku != null ? "商品规格库存不足" : "商品库存不足";
|
||||||
|
|||||||
@@ -0,0 +1,42 @@
|
|||||||
|
package com.gxwebsoft.shop.service;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.extension.service.IService;
|
||||||
|
import com.gxwebsoft.common.core.web.PageResult;
|
||||||
|
import com.gxwebsoft.shop.entity.ShopActiveImage;
|
||||||
|
import com.gxwebsoft.shop.param.ShopActiveImageParam;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 推广码底图Service
|
||||||
|
*
|
||||||
|
* @author xm
|
||||||
|
* @since 2026-04-27 18:02:17
|
||||||
|
*/
|
||||||
|
public interface ShopActiveImageService extends IService<ShopActiveImage> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分页关联查询
|
||||||
|
*
|
||||||
|
* @param param 查询参数
|
||||||
|
* @return PageResult<ShopActiveImage>
|
||||||
|
*/
|
||||||
|
PageResult<ShopActiveImage> pageRel(ShopActiveImageParam param);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 关联查询全部
|
||||||
|
*
|
||||||
|
* @param param 查询参数
|
||||||
|
* @return List<ShopActiveImage>
|
||||||
|
*/
|
||||||
|
List<ShopActiveImage> listRel(ShopActiveImageParam param);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据id查询
|
||||||
|
*
|
||||||
|
* @param id 主键ID
|
||||||
|
* @return ShopActiveImage
|
||||||
|
*/
|
||||||
|
ShopActiveImage getByIdRel(Integer id);
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
package com.gxwebsoft.shop.service;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.extension.service.IService;
|
||||||
|
import com.gxwebsoft.common.core.web.PageResult;
|
||||||
|
import com.gxwebsoft.shop.entity.ShopFlashSaleActivity;
|
||||||
|
import com.gxwebsoft.shop.param.ShopFlashSaleActivityParam;
|
||||||
|
import com.gxwebsoft.shop.vo.ShopFlashSaleActivityVO;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 秒杀活动Service
|
||||||
|
*
|
||||||
|
* @author xm
|
||||||
|
* @since 2026-04-22 17:18:17
|
||||||
|
*/
|
||||||
|
public interface ShopFlashSaleActivityService extends IService<ShopFlashSaleActivity> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分页关联查询
|
||||||
|
*
|
||||||
|
* @param param 查询参数
|
||||||
|
* @return PageResult<ShopFlashSaleActivity>
|
||||||
|
*/
|
||||||
|
PageResult<ShopFlashSaleActivityVO> pageRel(ShopFlashSaleActivityParam param);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 关联查询全部
|
||||||
|
*
|
||||||
|
* @param param 查询参数
|
||||||
|
* @return List<ShopFlashSaleActivity>
|
||||||
|
*/
|
||||||
|
List<ShopFlashSaleActivity> listRel(ShopFlashSaleActivityParam param);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据id查询
|
||||||
|
*
|
||||||
|
* @param id 秒杀活动编号
|
||||||
|
* @return ShopFlashSaleActivity
|
||||||
|
*/
|
||||||
|
ShopFlashSaleActivity getByIdRel(Integer id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询个人可参与的活动数据
|
||||||
|
* @param tenantId 租户ID
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
List<ShopFlashSaleActivityVO> getMyActive(Integer tenantId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改秒杀活动状态
|
||||||
|
* @param id
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
Boolean updateStatus(Integer id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改秒杀活动排序
|
||||||
|
* @param id
|
||||||
|
* @param sortNumber
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
Boolean updateSortNumber(Integer id, Integer sortNumber);
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
package com.gxwebsoft.shop.service.impl;
|
||||||
|
|
||||||
|
import com.aliyuncs.utils.StringUtils;
|
||||||
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||||
|
import com.gxwebsoft.common.core.web.PageParam;
|
||||||
|
import com.gxwebsoft.common.core.web.PageResult;
|
||||||
|
import com.gxwebsoft.shop.entity.ShopActiveImage;
|
||||||
|
import com.gxwebsoft.shop.mapper.ShopActiveImageMapper;
|
||||||
|
import com.gxwebsoft.shop.param.ShopActiveImageParam;
|
||||||
|
import com.gxwebsoft.shop.service.ShopActiveImageService;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import org.apache.commons.collections4.CollectionUtils;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 推广码底图Service实现
|
||||||
|
*
|
||||||
|
* @author xm
|
||||||
|
* @since 2026-04-27 17:53:00
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class ShopActiveImageServiceImpl extends ServiceImpl<ShopActiveImageMapper, ShopActiveImage> implements ShopActiveImageService {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PageResult<ShopActiveImage> pageRel(ShopActiveImageParam param) {
|
||||||
|
PageParam<ShopActiveImage, ShopActiveImageParam> page = new PageParam<>(param);
|
||||||
|
page.setDefaultOrder("sort_number asc, create_time desc");
|
||||||
|
List<ShopActiveImage> list = baseMapper.selectPageRel(page, param);
|
||||||
|
if(CollectionUtils.isNotEmpty(list)){
|
||||||
|
list.forEach(shopActiveImage -> {
|
||||||
|
if(!StringUtils.isEmpty(shopActiveImage.getImgUrl())){
|
||||||
|
shopActiveImage.setImgUrlList(Arrays.asList(shopActiveImage.getImgUrl().split(",")));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return new PageResult<>(list, page.getTotal());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<ShopActiveImage> listRel(ShopActiveImageParam param) {
|
||||||
|
List<ShopActiveImage> list = baseMapper.selectListRel(param);
|
||||||
|
if(CollectionUtils.isNotEmpty(list)){
|
||||||
|
list.forEach(shopActiveImage -> {
|
||||||
|
if(!StringUtils.isEmpty(shopActiveImage.getImgUrl())){
|
||||||
|
shopActiveImage.setImgUrlList(Arrays.asList(shopActiveImage.getImgUrl().split(",")));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// 排序
|
||||||
|
PageParam<ShopActiveImage, ShopActiveImageParam> page = new PageParam<>();
|
||||||
|
page.setDefaultOrder("sort_number asc, create_time desc");
|
||||||
|
return page.sortRecords(list);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ShopActiveImage getByIdRel(Integer id) {
|
||||||
|
ShopActiveImageParam param = new ShopActiveImageParam();
|
||||||
|
param.setId(id);
|
||||||
|
ShopActiveImage activeImage = param.getOne(baseMapper.selectListRel(param));
|
||||||
|
if(activeImage != null && !StringUtils.isEmpty(activeImage.getImgUrl())){
|
||||||
|
activeImage.setImgUrlList(Arrays.asList(activeImage.getImgUrl().split(",")));
|
||||||
|
}
|
||||||
|
return activeImage;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,183 @@
|
|||||||
|
package com.gxwebsoft.shop.service.impl;
|
||||||
|
|
||||||
|
import cn.hutool.core.bean.BeanUtil;
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
|
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
|
||||||
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||||
|
import com.gxwebsoft.common.core.exception.BusinessException;
|
||||||
|
import com.gxwebsoft.common.core.exception.enums.GlobalErrorCodeConstants;
|
||||||
|
import com.gxwebsoft.common.core.utils.LoginUserUtil;
|
||||||
|
import com.gxwebsoft.common.core.web.PageParam;
|
||||||
|
import com.gxwebsoft.common.core.web.PageResult;
|
||||||
|
import com.gxwebsoft.common.system.entity.User;
|
||||||
|
import com.gxwebsoft.shop.entity.ShopFlashSaleActivity;
|
||||||
|
import com.gxwebsoft.shop.entity.ShopGoods;
|
||||||
|
import com.gxwebsoft.shop.entity.ShopOrder;
|
||||||
|
import com.gxwebsoft.shop.mapper.ShopFlashSaleActivityMapper;
|
||||||
|
import com.gxwebsoft.shop.mapper.ShopGoodsMapper;
|
||||||
|
import com.gxwebsoft.shop.mapper.ShopOrderMapper;
|
||||||
|
import com.gxwebsoft.shop.param.ShopFlashSaleActivityParam;
|
||||||
|
import com.gxwebsoft.shop.service.ShopFlashSaleActivityService;
|
||||||
|
import com.gxwebsoft.shop.vo.ShopFlashSaleActivityVO;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import org.apache.commons.collections4.CollectionUtils;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 秒杀活动Service实现
|
||||||
|
*
|
||||||
|
* @author xm
|
||||||
|
* @since 2026-04-22 17:18:17
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class ShopFlashSaleActivityServiceImpl extends ServiceImpl<ShopFlashSaleActivityMapper, ShopFlashSaleActivity> implements ShopFlashSaleActivityService {
|
||||||
|
|
||||||
|
private ShopGoodsMapper shopGoodsMapper;
|
||||||
|
|
||||||
|
private ShopOrderMapper shopOrderMapper;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PageResult<ShopFlashSaleActivityVO> pageRel(ShopFlashSaleActivityParam param) {
|
||||||
|
PageParam<ShopFlashSaleActivity, ShopFlashSaleActivityParam> page = new PageParam<>(param);
|
||||||
|
page.setDefaultOrder("sort_number asc, create_time desc");
|
||||||
|
List<ShopFlashSaleActivityVO> list = baseMapper.selectPageRel(page, param);
|
||||||
|
if(CollectionUtils.isNotEmpty(list)){
|
||||||
|
List<Integer> goodsIdList = list.stream().map(ShopFlashSaleActivityVO::getGoodsId).distinct().collect(Collectors.toList());
|
||||||
|
List<ShopGoods> shopGoods = shopGoodsMapper.selectBatchIds(goodsIdList);
|
||||||
|
list.forEach(shopFlashSaleActivityVO -> {
|
||||||
|
ShopGoods shopGood = shopGoods.stream().filter(goods -> shopFlashSaleActivityVO.getGoodsId().equals(goods.getGoodsId())).findFirst().orElse(null);
|
||||||
|
if(shopGood != null){
|
||||||
|
shopFlashSaleActivityVO.setGoodsPrice(shopGood.getPrice());
|
||||||
|
shopFlashSaleActivityVO.setGoodsTotalPrice(shopGood.getPrice().multiply(new BigDecimal(shopFlashSaleActivityVO.getNum())));
|
||||||
|
shopFlashSaleActivityVO.setGoodsName(shopGood.getName());
|
||||||
|
shopFlashSaleActivityVO.setImage(shopGood.getImage());
|
||||||
|
shopFlashSaleActivityVO.setUnitName(shopGood.getUnitName());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return new PageResult<>(list, page.getTotal());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<ShopFlashSaleActivity> listRel(ShopFlashSaleActivityParam param) {
|
||||||
|
List<ShopFlashSaleActivity> list = baseMapper.selectListRel(param);
|
||||||
|
// 排序
|
||||||
|
PageParam<ShopFlashSaleActivity, ShopFlashSaleActivityParam> page = new PageParam<>();
|
||||||
|
page.setDefaultOrder("sort_number asc, create_time desc");
|
||||||
|
return page.sortRecords(list);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ShopFlashSaleActivity getByIdRel(Integer id) {
|
||||||
|
ShopFlashSaleActivityParam param = new ShopFlashSaleActivityParam();
|
||||||
|
param.setId(id);
|
||||||
|
return param.getOne(baseMapper.selectListRel(param));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<ShopFlashSaleActivityVO> getMyActive(Integer tenantId) {
|
||||||
|
List<ShopFlashSaleActivityVO> resultVOList = new ArrayList<>();
|
||||||
|
User loginUser = LoginUserUtil.getLoginUser();
|
||||||
|
if(loginUser == null){
|
||||||
|
throw new BusinessException(GlobalErrorCodeConstants.UNAUTHORIZED.getMsg());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Boolean newUser = true;
|
||||||
|
//判断是否为新用户【只要未成功下单都判定为新用户】
|
||||||
|
LambdaQueryWrapper<ShopOrder> shopOrderLambdaQueryWrapper = new LambdaQueryWrapper<ShopOrder>().eq(ShopOrder::getUserId, loginUser.getUserId()).eq(ShopOrder::getPayStatus, 1)
|
||||||
|
.in(ShopOrder::getOrderStatus, Arrays.asList(0, 1));
|
||||||
|
List<ShopOrder> shopOrderList = shopOrderMapper.selectList(shopOrderLambdaQueryWrapper);
|
||||||
|
if(CollectionUtils.isNotEmpty(shopOrderList)){
|
||||||
|
newUser = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//查询满足条件的活动数据
|
||||||
|
LambdaQueryChainWrapper<ShopFlashSaleActivity> activityWrapper = lambdaQuery().eq(ShopFlashSaleActivity::getStatus, 0).gt(ShopFlashSaleActivity::getStock, 0).eq(ShopFlashSaleActivity::getTenantId, tenantId)
|
||||||
|
.apply("NOW() BETWEEN start_time AND end_time");
|
||||||
|
|
||||||
|
Map<Integer, Integer> activityMap = new HashMap<>();
|
||||||
|
if(!newUser){
|
||||||
|
//查询当前用户是否有下过秒杀活动订单数据【判断下单数量是否超过限制】
|
||||||
|
List<Integer> activityIdList = activityWrapper.list().stream().map(ShopFlashSaleActivity::getId).collect(Collectors.toList());
|
||||||
|
LambdaQueryWrapper<ShopOrder> shopOrderWrapper = new LambdaQueryWrapper<ShopOrder>().select(ShopOrder::getOrderId, ShopOrder::getActivityId, ShopOrder::getTotalNum)
|
||||||
|
.eq(ShopOrder::getUserId, loginUser.getUserId()).in(ShopOrder::getActivityId, activityIdList).in(ShopOrder::getOrderStatus, Arrays.asList(0, 1));
|
||||||
|
activityMap = shopOrderMapper.selectList(shopOrderWrapper).stream().collect(Collectors.groupingBy(ShopOrder::getActivityId, Collectors.summingInt(ShopOrder::getTotalNum)));
|
||||||
|
|
||||||
|
activityWrapper.eq(ShopFlashSaleActivity::getDisplayType, 0);
|
||||||
|
}
|
||||||
|
activityWrapper.orderByAsc(ShopFlashSaleActivity::getSortNumber);
|
||||||
|
List<ShopFlashSaleActivity> activityList = activityWrapper.list();
|
||||||
|
|
||||||
|
if(CollectionUtils.isNotEmpty(activityList)){
|
||||||
|
resultVOList = BeanUtil.copyToList(activityList, ShopFlashSaleActivityVO.class);
|
||||||
|
List<Integer> goodsIdList = resultVOList.stream().map(ShopFlashSaleActivityVO::getGoodsId).distinct().collect(Collectors.toList());
|
||||||
|
List<ShopGoods> shopGoods = shopGoodsMapper.selectBatchIds(goodsIdList);
|
||||||
|
resultVOList.forEach(activity -> {
|
||||||
|
ShopGoods shopGood = shopGoods.stream().filter(goods -> activity.getGoodsId().equals(goods.getGoodsId())).findFirst().orElse(null);
|
||||||
|
if(shopGood != null){
|
||||||
|
activity.setGoodsPrice(shopGood.getPrice());
|
||||||
|
activity.setGoodsTotalPrice(shopGood.getPrice().multiply(new BigDecimal(activity.getNum())));
|
||||||
|
activity.setGoodsName(shopGood.getName());
|
||||||
|
activity.setImage(shopGood.getImage());
|
||||||
|
activity.setUnitName(shopGood.getUnitName());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
//过滤超下单数量活动
|
||||||
|
if(!activityMap.isEmpty()){
|
||||||
|
Iterator<ShopFlashSaleActivityVO> iterator = resultVOList.iterator();
|
||||||
|
while (iterator.hasNext()){
|
||||||
|
ShopFlashSaleActivityVO vo = iterator.next();
|
||||||
|
Integer orderTotalNum = activityMap.get(vo.getId());
|
||||||
|
if(orderTotalNum != null && orderTotalNum >= vo.getSaleLimit()){
|
||||||
|
iterator.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return resultVOList;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Boolean updateStatus(Integer id) {
|
||||||
|
ShopFlashSaleActivity saleActivity = baseMapper.selectById(id);
|
||||||
|
if(saleActivity != null){
|
||||||
|
if (saleActivity.getStatus() == 0){
|
||||||
|
saleActivity.setStatus(1);
|
||||||
|
}else {
|
||||||
|
saleActivity.setStatus(0);
|
||||||
|
}
|
||||||
|
User loginUser = LoginUserUtil.getLoginUser();
|
||||||
|
if(loginUser != null){
|
||||||
|
saleActivity.setUpdater(loginUser.getUserId().toString());
|
||||||
|
}
|
||||||
|
saleActivity.setUpdateTime(LocalDateTime.now());
|
||||||
|
baseMapper.updateById(saleActivity);
|
||||||
|
return Boolean.TRUE;
|
||||||
|
}else {
|
||||||
|
throw new BusinessException(GlobalErrorCodeConstants.NOT_FOUND.getMsg());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Boolean updateSortNumber(Integer id, Integer sortNumber) {
|
||||||
|
ShopFlashSaleActivity saleActivity = baseMapper.selectById(id);
|
||||||
|
if(saleActivity != null){
|
||||||
|
saleActivity.setSortNumber(sortNumber);
|
||||||
|
saleActivity.setUpdateTime(LocalDateTime.now());
|
||||||
|
baseMapper.updateById(saleActivity);
|
||||||
|
return Boolean.TRUE;
|
||||||
|
}else {
|
||||||
|
throw new BusinessException(GlobalErrorCodeConstants.NOT_FOUND.getMsg());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,96 @@
|
|||||||
|
package com.gxwebsoft.shop.vo;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableLogic;
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 秒杀活动
|
||||||
|
*
|
||||||
|
* @author xm
|
||||||
|
* @since 2026-04-22 17:18:17
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class ShopFlashSaleActivityVO implements Serializable {
|
||||||
|
|
||||||
|
@Schema(description = "秒杀活动编号")
|
||||||
|
private Integer id;
|
||||||
|
|
||||||
|
@Schema(description = "秒杀活动名称")
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
@Schema(description = "秒杀活动商品")
|
||||||
|
private Integer goodsId;
|
||||||
|
|
||||||
|
@Schema(description = "秒杀活动商品名称")
|
||||||
|
private String goodsName;
|
||||||
|
|
||||||
|
@Schema(description = "商品skuId")
|
||||||
|
private Integer skuId;
|
||||||
|
|
||||||
|
@Schema(description = "商品图片地址")
|
||||||
|
private String image;
|
||||||
|
|
||||||
|
@Schema(description = "单位")
|
||||||
|
private String unitName;
|
||||||
|
|
||||||
|
@Schema(description = "商品数量")
|
||||||
|
private Integer num;
|
||||||
|
|
||||||
|
@Schema(description = "秒杀价")
|
||||||
|
private BigDecimal price;
|
||||||
|
|
||||||
|
@Schema(description = "商品单价")
|
||||||
|
private BigDecimal goodsPrice;
|
||||||
|
|
||||||
|
@Schema(description = "商品总价")
|
||||||
|
private BigDecimal goodsTotalPrice;
|
||||||
|
|
||||||
|
@Schema(description = "活动状态 0-开启 1-关闭")
|
||||||
|
private Integer status;
|
||||||
|
|
||||||
|
@Schema(description = "活动开始时间")
|
||||||
|
private LocalDateTime startTime;
|
||||||
|
|
||||||
|
@Schema(description = "活动结束时间")
|
||||||
|
private LocalDateTime endTime;
|
||||||
|
|
||||||
|
@Schema(description = "活动限购数量")
|
||||||
|
private Integer saleLimit;
|
||||||
|
|
||||||
|
@Schema(description = "库存")
|
||||||
|
private Integer stock;
|
||||||
|
|
||||||
|
@Schema(description = "展示类型,0:普通用户,1:新用户")
|
||||||
|
private Integer displayType;
|
||||||
|
|
||||||
|
@Schema(description = "备注")
|
||||||
|
private String remark;
|
||||||
|
|
||||||
|
@Schema(description = "排序")
|
||||||
|
private Integer sortNumber;
|
||||||
|
|
||||||
|
@Schema(description = "租户id")
|
||||||
|
private Integer tenantId;
|
||||||
|
|
||||||
|
@Schema(description = "创建者")
|
||||||
|
private String creator;
|
||||||
|
|
||||||
|
@Schema(description = "创建时间")
|
||||||
|
private LocalDateTime createTime;
|
||||||
|
|
||||||
|
@Schema(description = "更新者")
|
||||||
|
private String updater;
|
||||||
|
|
||||||
|
@Schema(description = "更新时间")
|
||||||
|
private LocalDateTime updateTime;
|
||||||
|
|
||||||
|
@Schema(description = "是否删除")
|
||||||
|
@TableLogic
|
||||||
|
private Integer deleted;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -7,7 +7,7 @@ server:
|
|||||||
# 数据源配置
|
# 数据源配置
|
||||||
spring:
|
spring:
|
||||||
datasource:
|
datasource:
|
||||||
url: jdbc:mysql://8.134.55.105:13306/modules?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=GMT%2B8
|
url: jdbc:mysql://47.107.249.41:13306/modules?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=GMT%2B8
|
||||||
username: modules
|
username: modules
|
||||||
password: tYmmMGh5wpwXR3ae
|
password: tYmmMGh5wpwXR3ae
|
||||||
driver-class-name: com.mysql.cj.jdbc.Driver
|
driver-class-name: com.mysql.cj.jdbc.Driver
|
||||||
|
|||||||
@@ -38,14 +38,14 @@ public class ShopGenerator {
|
|||||||
// Vue文件输出目录
|
// Vue文件输出目录
|
||||||
private static final String OUTPUT_DIR_VUE = "/src";
|
private static final String OUTPUT_DIR_VUE = "/src";
|
||||||
// 作者名称
|
// 作者名称
|
||||||
private static final String AUTHOR = "科技小王子";
|
private static final String AUTHOR = "xm";
|
||||||
// 是否在xml中添加二级缓存配置
|
// 是否在xml中添加二级缓存配置
|
||||||
private static final boolean ENABLE_CACHE = false;
|
private static final boolean ENABLE_CACHE = false;
|
||||||
// 数据库连接配置
|
// 数据库连接配置
|
||||||
private static final String DB_URL = "jdbc:mysql://8.134.169.209:13306/modules?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=GMT%2B8";
|
private static final String DB_URL = "jdbc:mysql://47.107.249.41:13306/modules?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=GMT%2B8";
|
||||||
private static final String DB_DRIVER = "com.mysql.cj.jdbc.Driver";
|
private static final String DB_DRIVER = "com.mysql.cj.jdbc.Driver";
|
||||||
private static final String DB_USERNAME = "modules";
|
private static final String DB_USERNAME = "modules";
|
||||||
private static final String DB_PASSWORD = "8YdLnk7KsPAyDXGA";
|
private static final String DB_PASSWORD = "tYmmMGh5wpwXR3ae";
|
||||||
// 包名
|
// 包名
|
||||||
private static final String PACKAGE_NAME = "com.gxwebsoft";
|
private static final String PACKAGE_NAME = "com.gxwebsoft";
|
||||||
// 模块名
|
// 模块名
|
||||||
@@ -105,7 +105,8 @@ public class ShopGenerator {
|
|||||||
// "shop_express_template",
|
// "shop_express_template",
|
||||||
// "shop_express_template_detail",
|
// "shop_express_template_detail",
|
||||||
// "shop_gift"
|
// "shop_gift"
|
||||||
"shop_article"
|
// "shop_flash_sale_activity"
|
||||||
|
// "shop_active_image"
|
||||||
};
|
};
|
||||||
// 需要去除的表前缀
|
// 需要去除的表前缀
|
||||||
private static final String[] TABLE_PREFIX = new String[]{
|
private static final String[] TABLE_PREFIX = new String[]{
|
||||||
|
|||||||
@@ -19,10 +19,8 @@ import ${cfg.packageName!}.${package.ModuleName}.entity.${entity};
|
|||||||
import ${cfg.packageName!}.${package.ModuleName}.param.${entity}Param;
|
import ${cfg.packageName!}.${package.ModuleName}.param.${entity}Param;
|
||||||
import ${cfg.packageName!}.common.core.web.ApiResult;
|
import ${cfg.packageName!}.common.core.web.ApiResult;
|
||||||
import ${cfg.packageName!}.common.core.web.PageResult;
|
import ${cfg.packageName!}.common.core.web.PageResult;
|
||||||
import ${cfg.packageName!}.common.core.web.PageParam;
|
|
||||||
import ${cfg.packageName!}.common.core.web.BatchParam;
|
import ${cfg.packageName!}.common.core.web.BatchParam;
|
||||||
import ${cfg.packageName!}.common.core.annotation.OperationLog;
|
import ${cfg.packageName!}.common.core.annotation.OperationLog;
|
||||||
import ${cfg.packageName!}.common.system.entity.User;
|
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
import org.springframework.security.access.prepost.PreAuthorize;
|
import org.springframework.security.access.prepost.PreAuthorize;
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package ${package.Entity};
|
|||||||
<% for(pkg in table.importPackages) { %>
|
<% for(pkg in table.importPackages) { %>
|
||||||
import ${pkg};
|
import ${pkg};
|
||||||
<% } %>
|
<% } %>
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
<% if(swagger2) { %>
|
<% if(swagger2) { %>
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
<% } %>
|
<% } %>
|
||||||
@@ -34,6 +35,7 @@ import lombok.experimental.Accessors;
|
|||||||
<% if(swagger2) { %>
|
<% if(swagger2) { %>
|
||||||
@Schema(name = "${entity}对象", description = "${table.comment!''}")
|
@Schema(name = "${entity}对象", description = "${table.comment!''}")
|
||||||
<% } %>
|
<% } %>
|
||||||
|
@TableName("${table.name}")
|
||||||
<% if(table.convert) { %>
|
<% if(table.convert) { %>
|
||||||
@TableName("${table.name}")
|
@TableName("${table.name}")
|
||||||
<% } %>
|
<% } %>
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import ${package.Entity}.${entity};
|
|||||||
import ${cfg.packageName!}.${package.ModuleName}.param.${entity}Param;
|
import ${cfg.packageName!}.${package.ModuleName}.param.${entity}Param;
|
||||||
import ${cfg.packageName!}.common.core.web.PageParam;
|
import ${cfg.packageName!}.common.core.web.PageParam;
|
||||||
import ${cfg.packageName!}.common.core.web.PageResult;
|
import ${cfg.packageName!}.common.core.web.PageResult;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -27,6 +28,7 @@ import java.util.List;
|
|||||||
* @since ${date(), 'yyyy-MM-dd HH:mm:ss'}
|
* @since ${date(), 'yyyy-MM-dd HH:mm:ss'}
|
||||||
*/
|
*/
|
||||||
@Service
|
@Service
|
||||||
|
@AllArgsConstructor
|
||||||
<% if(kotlin){ %>
|
<% if(kotlin){ %>
|
||||||
open class ${table.serviceImplName} : ${superServiceImplClass}<${table.mapperName}, ${entity}>(), ${table.serviceName} {
|
open class ${table.serviceImplName} : ${superServiceImplClass}<${table.mapperName}, ${entity}>(), ${table.serviceName} {
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user