diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-common/pom.xml b/ruoyi-vue-pro-master/yudao-framework/yudao-common/pom.xml
index f364df7..cb960d5 100644
--- a/ruoyi-vue-pro-master/yudao-framework/yudao-common/pom.xml
+++ b/ruoyi-vue-pro-master/yudao-framework/yudao-common/pom.xml
@@ -144,6 +144,26 @@
spring-boot-starter-test
test
+
+
+
+ com.google.zxing
+
+ core
+
+ 3.4.1
+
+
+
+
+
+ com.google.zxing
+
+ javase
+
+ 3.4.1
+
+
diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/qccode/Base64Util.java b/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/qccode/Base64Util.java
new file mode 100644
index 0000000..f4eaab2
--- /dev/null
+++ b/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/qccode/Base64Util.java
@@ -0,0 +1,107 @@
+package cn.iocoder.yudao.framework.common.util.qccode;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.UnsupportedEncodingException;
+import java.util.Base64;
+
+/**
+ * 编码工具
+ *
+ * Created by FSQ
+ * CopyRight https://www.huamar.com
+ */
+public class Base64Util {
+
+ private static final Logger logger = LoggerFactory.getLogger(Base64Util.class);
+
+ public Base64Util() {
+ // empty
+ }
+
+ public static byte[] baseEncode(byte[] bytes) {
+ return Base64.getEncoder().encode(bytes);
+ }
+
+ public static String baseEncode(String s) {
+ try {
+ byte[] e = s.getBytes("UTF-8");
+ return Base64.getEncoder().encodeToString(e);
+ } catch (UnsupportedEncodingException var2) {
+ logger.error(var2.getMessage(), var2);
+ return null;
+ }
+ }
+
+ public static byte[] baseDecode(byte[] bytes) {
+ return Base64.getDecoder().decode(bytes);
+ }
+
+ public static String baseDecode(String s) {
+ try {
+ byte[] e = Base64.getDecoder().decode(s);
+ return new String(e, "UTF-8");
+ } catch (UnsupportedEncodingException var2) {
+ logger.error(var2.getMessage(), var2);
+ return null;
+ }
+ }
+
+ public static byte[] urlEncode(byte[] bytes) {
+ return Base64.getUrlEncoder().encode(bytes);
+ }
+
+ public static String urlEncode(String s) {
+ try {
+ byte[] e = s.getBytes("UTF-8");
+ return Base64.getUrlEncoder().encodeToString(e);
+ } catch (UnsupportedEncodingException var2) {
+ logger.error(var2.getMessage(), var2);
+ return null;
+ }
+ }
+
+ public static byte[] urlDecode(byte[] bytes) {
+ return Base64.getUrlDecoder().decode(bytes);
+ }
+
+ public static String urlDecode(String s) {
+ byte[] result = Base64.getUrlDecoder().decode(s);
+
+ try {
+ return new String(result, "UTF-8");
+ } catch (UnsupportedEncodingException var3) {
+ logger.error(var3.getMessage(), var3);
+ return null;
+ }
+ }
+
+ public static byte[] mimeEncode(byte[] bytes) {
+ return Base64.getMimeEncoder().encode(bytes);
+ }
+
+ public static String mimeEncode(String s) {
+ try {
+ byte[] e = s.getBytes("UTF-8");
+ return Base64.getMimeEncoder().encodeToString(e);
+ } catch (UnsupportedEncodingException var2) {
+ logger.error(var2.getMessage(), var2);
+ return null;
+ }
+ }
+
+ public static byte[] mimeDecode(byte[] bytes) {
+ return Base64.getMimeDecoder().decode(bytes);
+ }
+
+ public static String mimeDecode(String s) {
+ try {
+ byte[] e = Base64.getMimeDecoder().decode(s);
+ return new String(e, "UTF-8");
+ } catch (UnsupportedEncodingException var2) {
+ logger.error(var2.getMessage(), var2);
+ return null;
+ }
+ }
+}
diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/qccode/QRCodeUtil.java b/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/qccode/QRCodeUtil.java
new file mode 100644
index 0000000..d3d6b0a
--- /dev/null
+++ b/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/qccode/QRCodeUtil.java
@@ -0,0 +1,158 @@
+package cn.iocoder.yudao.framework.common.util.qccode;
+
+import cn.hutool.core.util.StrUtil;
+import cn.hutool.extra.qrcode.BufferedImageLuminanceSource;
+import com.google.zxing.*;
+
+import com.google.zxing.common.BitMatrix;
+import com.google.zxing.common.HybridBinarizer;
+import com.google.zxing.qrcode.QRCodeReader;
+import com.google.zxing.qrcode.QRCodeWriter;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.yaml.snakeyaml.reader.ReaderException;
+
+import javax.imageio.ImageIO;
+import java.awt.*;
+import java.awt.image.BufferedImage;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.HashMap;
+
+/**
+ * 二维码生成工具类
+ *
+ * Created by FSQ
+ * CopyRight https://www.huamar.com
+ */
+public class QRCodeUtil {
+ public static final Logger logger = LoggerFactory.getLogger(QRCodeUtil.class);
+
+ /**
+ * 生成包含字符串信息的二维码图片
+ *
+ * @param outputStream 文件输出流路径
+ * @param content 二维码携带信息
+ * @param width 宽度
+ * @param height 高度
+ * @param imageFormat 二维码的格式
+ * @param resource 原图
+ */
+ public static boolean createQrCode(OutputStream outputStream, String content, int width, int height, String imageFormat, String resource) {
+ //设置二维码纠错级别
+ HashMap hints = new HashMap();
+ hints.put(EncodeHintType.CHARACTER_SET, "utf-8");
+ /* width = width ;
+ height = height ;*/
+ try {
+ //创建比特矩阵(位矩阵)的QR码编码的字符串
+ QRCodeWriter qrCodeWriter = new QRCodeWriter();
+ BitMatrix byteMatrix = qrCodeWriter.encode(content, BarcodeFormat.QR_CODE, width, height, hints);
+
+ // 使BufferedImage勾画QRCode (matrixWidth 是行二维码像素点)
+ int matrixWidth = byteMatrix.getWidth();
+ BufferedImage image = new BufferedImage(matrixWidth - 200, matrixWidth - 200, BufferedImage.TYPE_INT_RGB);
+
+ // 使用比特矩阵画并保存图像
+ image.createGraphics();
+ Graphics2D graphics = (Graphics2D) image.getGraphics();
+ graphics.setColor(Color.WHITE);
+ graphics.fillRect(0, 0, matrixWidth, matrixWidth);
+ graphics.setColor(Color.BLACK);
+ for (int i = 0; i < matrixWidth; i++) {
+ for (int j = 0; j < matrixWidth; j++) {
+ if (byteMatrix.get(i, j)) {
+ graphics.fillRect(i - 100, j - 100, 1, 1);
+ }
+ }
+ }
+
+ if (StrUtil.isNotEmpty(resource)) {
+ BufferedImage big = getRemoteBufferedImage(resource);
+
+ BufferedImage small = image;
+ Graphics2D g = big.createGraphics();
+
+ // 二维码坐标(默认在右上角)
+ int x = big.getWidth() - small.getWidth() - 2;
+ int y = 2;
+
+ g.drawImage(small, x, y, small.getWidth(), small.getHeight(), null);
+ g.dispose();
+
+ return ImageIO.write(big, imageFormat, outputStream);
+ } else {
+ return ImageIO.write(image, imageFormat, outputStream);
+ }
+ } catch (Exception e) {
+ logger.error(e.getMessage(), e);
+ }
+ return false;
+ }
+
+ /**
+ * 读二维码并输出携带的信息
+ */
+ public static void readQrCode(InputStream inputStream) throws IOException {
+ //设置二维码纠错级别
+ HashMap hints = new HashMap();
+ hints.put(DecodeHintType.CHARACTER_SET, "utf-8");
+ //从输入流中获取字符串信息
+ BufferedImage image = ImageIO.read(inputStream);
+ //将图像转换为二进制位图源
+ LuminanceSource source = new BufferedImageLuminanceSource(image);
+ BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));
+ QRCodeReader reader = new QRCodeReader();
+ Result result = null;
+ try {
+ result = reader.decode(bitmap, hints);
+ } catch (ReaderException e) {
+ logger.error(e.getMessage(), e);
+ } catch (ChecksumException e) {
+ throw new RuntimeException(e);
+ } catch (NotFoundException e) {
+ throw new RuntimeException(e);
+ } catch (FormatException e) {
+ throw new RuntimeException(e);
+ }
+ logger.info(result.getText());
+ }
+
+ /**
+ * 获取远程网络图片信息
+ * @param imageURL
+ * @return
+ */
+ public static BufferedImage getRemoteBufferedImage(String imageURL) {
+ URL url;
+ InputStream is = null;
+ BufferedImage bufferedImage = null;
+ try {
+ url = new URL(imageURL);
+ is = url.openStream();
+ bufferedImage = ImageIO.read(is);
+ } catch (MalformedURLException e) {
+ e.printStackTrace();
+ System.out.println("imageURL: " + imageURL + ",无效!");
+ return null;
+ } catch (IOException e) {
+ e.printStackTrace();
+ System.out.println("imageURL: " + imageURL + ",读取失败!");
+ return null;
+ } finally {
+ try {
+ if (is!=null) {
+ is.close();
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ System.out.println("imageURL: " + imageURL + ",流关闭异常!");
+ return null;
+ }
+ }
+ return bufferedImage;
+ }
+}
diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/qccode/vo/QRCodeConfig.java b/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/qccode/vo/QRCodeConfig.java
new file mode 100644
index 0000000..b6d59d7
--- /dev/null
+++ b/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/qccode/vo/QRCodeConfig.java
@@ -0,0 +1,32 @@
+package cn.iocoder.yudao.framework.common.util.qccode.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
+
+
+@Schema(description = "QRCodeConfig 二维码 vo")
+@Data
+@EqualsAndHashCode(callSuper = false)
+@ToString(callSuper = true)
+public class QRCodeConfig {
+ // 二维码内容
+ @Schema(description = "二维码内容",defaultValue = "我是二维码的内容")
+ private String content;
+
+ // 二维码的宽度
+ @Schema(description = "二维码的宽度",defaultValue = "800")
+ private int width=800;
+
+ // 二维码的高度
+ @Schema(description = "二维码的高度",defaultValue = "800")
+ private int height=800;
+
+ // 二维码的图片格式,如"png", "jpg"等
+ @Schema(description = "二维码的高度",defaultValue = "png,jpg")
+ private String imageFormat="jpg";
+
+ // 附加资源或相关信息(具体含义根据项目需求定义)
+ /*private String resource;*/
+}
diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/LoginUser.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/LoginUser.java
index 68d1c56..ae8565b 100644
--- a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/LoginUser.java
+++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/LoginUser.java
@@ -19,6 +19,7 @@ public class LoginUser {
public static final String INFO_KEY_NICKNAME = "nickname";
public static final String INFO_KEY_DEPT_ID = "deptId";
+ public static final String INFO_KEY_MOBILE = "mobile";
/**
* 用户编号
diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/util/SecurityFrameworkUtils.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/util/SecurityFrameworkUtils.java
index f85d77c..88bf6ba 100644
--- a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/util/SecurityFrameworkUtils.java
+++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/util/SecurityFrameworkUtils.java
@@ -112,6 +112,17 @@ public class SecurityFrameworkUtils {
return loginUser != null ? MapUtil.getLong(loginUser.getInfo(), LoginUser.INFO_KEY_DEPT_ID) : null;
}
+ /**
+ * 获得当前用户的电话,从上下文中
+ *
+ * @return 昵称
+ */
+ @Nullable
+ public static String getLoginUserMobile() {
+ LoginUser loginUser = getLoginUser();
+ return loginUser != null ? MapUtil.getStr(loginUser.getInfo(), LoginUser.INFO_KEY_MOBILE) : null;
+ }
+
/**
* 设置当前用户
*
diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/pom.xml b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/pom.xml
index f2840cf..5b15541 100644
--- a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/pom.xml
+++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/pom.xml
@@ -124,6 +124,12 @@
org.apache.tika
tika-core
+
+ cn.iocoder.boot
+ yudao-module-system-biz
+ 2.1.0-jdk8-snapshot
+ compile
+
diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/app/file/AppFileController.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/app/file/AppFileController.java
index 62755fc..c633ccc 100644
--- a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/app/file/AppFileController.java
+++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/app/file/AppFileController.java
@@ -1,21 +1,36 @@
package cn.iocoder.yudao.module.infra.controller.app.file;
+import cn.hutool.core.codec.Base64;
+import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.IoUtil;
+import cn.hutool.core.lang.UUID;
+import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
+import cn.iocoder.yudao.framework.common.util.qccode.Base64Util;
+import cn.iocoder.yudao.framework.common.util.qccode.QRCodeUtil;
+import cn.iocoder.yudao.framework.common.util.qccode.vo.QRCodeConfig;
import cn.iocoder.yudao.module.infra.controller.app.file.vo.AppFileUploadReqVO;
import cn.iocoder.yudao.module.infra.service.file.FileService;
+import cn.iocoder.yudao.module.system.dal.dataobject.dict.DictDataDO;
+import cn.iocoder.yudao.module.system.service.dict.DictDataService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
+import javax.validation.Valid;
+
+import java.io.*;
+import java.util.List;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
+import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
@Tag(name = "用户 App - 文件存储")
@RestController
@@ -27,6 +42,9 @@ public class AppFileController {
@Resource
private FileService fileService;
+ @Resource
+ private DictDataService dictDataService;
+
@PostMapping("/upload")
@Operation(summary = "上传文件")
public CommonResult uploadFile(AppFileUploadReqVO uploadReqVO) throws Exception {
@@ -35,4 +53,75 @@ public class AppFileController {
return success(fileService.createFile(file.getOriginalFilename(), path, IoUtil.readBytes(file.getInputStream())));
}
+ @RequestMapping("/qrCode")
+ @Operation(summary = "生成二维码")
+ public CommonResult qrCode(@Valid QRCodeConfig qrCodeConfig) {
+ try {
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ // 假设QRCodeUtil.createQrCode是一个正确实现的方法,用于生成二维码并写入到ByteArrayOutputStream中
+ QRCodeUtil.createQrCode(out, qrCodeConfig.getContent(), qrCodeConfig.getWidth(), qrCodeConfig.getHeight(), qrCodeConfig.getImageFormat(), ""); // 使用PNG格式,不是JPG
+ // 创建文件,使用PNG扩展名,因为QR码是以PNG格式生成的
+ File file = FileUtil.file(UUID.fastUUID()+"."+qrCodeConfig.getImageFormat()); // 注意文件扩展名应为.png
+ byte[] imageBytes = out.toByteArray();
+ // 使用 FileOutputStream 将字节数组写入本地文件
+ try (FileOutputStream fos = new FileOutputStream(file)) {
+ fos.write(imageBytes);
+ }
+ // 输出文件名和位置
+ //System.out.println("文件名: " + file.getName());
+ //System.out.println("文件位置: " + file.getAbsolutePath());
+ // 假设fileService.createFile是一个正确实现的方法,用于在您的服务中创建文件记录
+ // 读取文件内容并传递给createFile方法
+ byte[] fileContent = IoUtil.readBytes(new FileInputStream(file)); // 使用FileInputStream读取文件内容
+ String url = fileService.createFile(file.getName(), UUID.fastUUID()+"."+qrCodeConfig.getImageFormat(), fileContent);
+ out.close(); // 关闭ByteArrayOutputStream,虽然在这个上下文中它会在方法结束时自动关闭
+ return success(url);
+ } catch (IOException e) {
+ e.printStackTrace(); // 适当的错误处理应该替换这一行,例如记录日志或向用户显示错误消息
+ }
+
+ return success("");
+ }
+
+ @RequestMapping("/qrCode64")
+ @Operation(summary = "生成二维码64")
+ public CommonResult qrCode64(@Valid String type) {
+ try {
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ // 假设QRCodeUtil.createQrCode是一个正确实现的方法,用于生成二维码并写入到ByteArrayOutputStream中
+ QRCodeConfig qrCodeConfig = new QRCodeConfig();
+ QRCodeUtil.createQrCode(out, getString(type), qrCodeConfig.getWidth(), qrCodeConfig.getHeight(), qrCodeConfig.getImageFormat(), ""); // 使用PNG格式,不是JPG
+ // 创建文件,使用PNG扩展名,因为QR码是以PNG格式生成的
+ String h5QrCode = new String(Base64Util.baseEncode(out.toByteArray()), "UTF-8");
+ out.close(); // 关闭ByteArrayOutputStream,虽然在这个上下文中它会在方法结束时自动关闭
+ return success(h5QrCode);
+ } catch (IOException e) {
+ e.printStackTrace(); // 适当的错误处理应该替换这一行,例如记录日志或向用户显示错误消息
+ }
+
+ return success(null);
+ }
+
+ @RequestMapping("/qrCode64Url")
+ @Operation(summary = "生成Url")
+ public CommonResult qrCode64Url(@Valid String type) {
+
+ // 创建文件,使用PNG扩展名,因为QR码是以PNG格式生成的
+ return success( getString(type));
+
+ }
+
+ private String getString(String type) {
+ String replace=null;
+ List list = dictDataService.getDictDataList(
+ CommonStatusEnum.ENABLE.getStatus(), "xcxscewm_type");
+ Long loginUserId = getLoginUserId();
+ for (DictDataDO dictDataDO : list) {
+ if (dictDataDO.getValue().equals(type)) {
+ replace = dictDataDO.getRemark().replace("{bindUserId}", loginUserId.toString());
+ }
+ }
+ return replace;
+ }
+
}
diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/ErrorCodeConstants.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/ErrorCodeConstants.java
index 3b19d61..a0cb259 100644
--- a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/ErrorCodeConstants.java
+++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/ErrorCodeConstants.java
@@ -124,5 +124,11 @@ public interface ErrorCodeConstants {
// ========== 装修页面 1-013-018-000 ==========
ErrorCode DIY_PAGE_NOT_EXISTS = new ErrorCode(1_013_018_000, "装修页面不存在");
ErrorCode DIY_PAGE_NAME_USED = new ErrorCode(1_013_018_001, "装修页面名称({})已经被使用");
+ ErrorCode PRIZE_DRAW_NOT_EXISTS = new ErrorCode(1_013_018_002, "抽奖活动不存在");
+ ErrorCode PRIZE_DRAW_NOT_START = new ErrorCode(1_013_018_003, "抽奖活动暂未开启");
+ ErrorCode PRIZE_DRAW_NOT_TIME = new ErrorCode(1_013_018_004, "抽奖活动未开始或已过期");
+ ErrorCode PRIZE_LOG_NOT_EXISTS = new ErrorCode(1_013_018_005, "抽奖记录不存在");
+ ErrorCode PRIZE_LOG_NOT_DRAWNUM = new ErrorCode(1_013_018_006, "抽奖次数已达上限");
+ ErrorCode PRIZE_LOG_NOT_LEVEL = new ErrorCode(1_013_018_007, "分销等级不在权限范围");
}
diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/prizedraw/PrizeDrawController.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/prizedraw/PrizeDrawController.java
new file mode 100644
index 0000000..79230eb
--- /dev/null
+++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/prizedraw/PrizeDrawController.java
@@ -0,0 +1,121 @@
+package cn.iocoder.yudao.module.promotion.controller.admin.prizedraw;
+
+import cn.iocoder.yudao.module.member.api.level.MemberLevelApi;
+import cn.iocoder.yudao.module.member.api.level.dto.MemberLevelRespDTO;
+import cn.iocoder.yudao.module.member.api.user.MemberUserApi;
+import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO;
+import cn.iocoder.yudao.module.promotion.convert.prizedraw.PrizeDrawConvert;
+import cn.iocoder.yudao.module.promotion.convert.prizelog.PrizeLogConvert;
+import cn.iocoder.yudao.module.promotion.dal.dataobject.bargain.BargainHelpDO;
+import cn.iocoder.yudao.module.promotion.dal.dataobject.prizedraw.ActivityPrizeDO;
+import org.springframework.web.bind.annotation.*;
+import javax.annotation.Resource;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.security.access.prepost.PreAuthorize;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.Operation;
+
+import javax.validation.constraints.*;
+import javax.validation.*;
+import javax.servlet.http.*;
+import java.util.*;
+import java.io.IOException;
+
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.common.pojo.CommonResult;
+import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
+
+import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
+
+import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog;
+import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.*;
+import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;
+import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
+
+import cn.iocoder.yudao.module.promotion.controller.admin.prizedraw.vo.*;
+import cn.iocoder.yudao.module.promotion.dal.dataobject.prizedraw.PrizeDrawDO;
+import cn.iocoder.yudao.module.promotion.service.prizedraw.PrizeDrawService;
+
+@Tag(name = "管理后台 - 抽奖活动")
+@RestController
+@RequestMapping("/promotion/prize-draw")
+@Validated
+public class PrizeDrawController {
+
+ @Resource
+ private PrizeDrawService prizeDrawService;
+
+ @Resource
+ private MemberLevelApi memberLevelApi;
+
+ @PostMapping("/create")
+ @Operation(summary = "创建抽奖活动")
+ @PreAuthorize("@ss.hasPermission('promotion:prize-draw:create')")
+ public CommonResult createPrizeDraw(@Valid @RequestBody PrizeDrawSaveReqVO createReqVO) {
+ return success(prizeDrawService.createPrizeDraw(createReqVO));
+ }
+
+ @PutMapping("/update")
+ @Operation(summary = "更新抽奖活动")
+ @PreAuthorize("@ss.hasPermission('promotion:prize-draw:update')")
+ public CommonResult updatePrizeDraw(@Valid @RequestBody PrizeDrawSaveReqVO updateReqVO) {
+ prizeDrawService.updatePrizeDraw(updateReqVO);
+ return success(true);
+ }
+
+ @DeleteMapping("/delete")
+ @Operation(summary = "删除抽奖活动")
+ @Parameter(name = "id", description = "编号", required = true)
+ @PreAuthorize("@ss.hasPermission('promotion:prize-draw:delete')")
+ public CommonResult deletePrizeDraw(@RequestParam("id") Long id) {
+ prizeDrawService.deletePrizeDraw(id);
+ return success(true);
+ }
+
+ @GetMapping("/get")
+ @Operation(summary = "获得抽奖活动")
+ @Parameter(name = "id", description = "编号", required = true, example = "1024")
+ @PreAuthorize("@ss.hasPermission('promotion:prize-draw:query')")
+ public CommonResult getPrizeDraw(@RequestParam("id") Long id) {
+ PrizeDrawDO prizeDraw = prizeDrawService.getPrizeDraw(id);
+ return success(BeanUtils.toBean(prizeDraw, PrizeDrawRespVO.class));
+ }
+
+ @GetMapping("/page")
+ @Operation(summary = "获得抽奖活动分页")
+ @PreAuthorize("@ss.hasPermission('promotion:prize-draw:query')")
+ public CommonResult> getPrizeDrawPage(@Valid PrizeDrawPageReqVO pageReqVO) {
+ PageResult pageResult = prizeDrawService.getPrizeDrawPage(pageReqVO);
+ // 处理用户级别返显
+ List levels = memberLevelApi.getLevelList(
+ convertSet(pageResult.getList(), PrizeDrawDO::getMebLevel));
+ return success(PrizeDrawConvert.INSTANCE.convertPage(pageResult, levels));
+ }
+
+ @GetMapping("/export-excel")
+ @Operation(summary = "导出抽奖活动 Excel")
+ @PreAuthorize("@ss.hasPermission('promotion:prize-draw:export')")
+ @ApiAccessLog(operateType = EXPORT)
+ public void exportPrizeDrawExcel(@Valid PrizeDrawPageReqVO pageReqVO,
+ HttpServletResponse response) throws IOException {
+ pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
+ List list = prizeDrawService.getPrizeDrawPage(pageReqVO).getList();
+ // 导出 Excel
+ ExcelUtils.write(response, "抽奖活动.xls", "数据", PrizeDrawRespVO.class,
+ BeanUtils.toBean(list, PrizeDrawRespVO.class));
+ }
+
+ // ==================== 子表(抽奖活动奖品) ====================
+
+ @GetMapping("/activity-prize/list-by-activity-id")
+ @Operation(summary = "获得抽奖活动奖品列表")
+ @Parameter(name = "activityId", description = "关联抽奖活动id")
+ @PreAuthorize("@ss.hasPermission('promotion:prize-draw:query')")
+ public CommonResult> getActivityPrizeListByActivityId(@RequestParam("activityId") Long activityId) {
+ return success(prizeDrawService.getActivityPrizeListByActivityId(activityId));
+ }
+
+}
diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/prizedraw/vo/PrizeDrawPageReqVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/prizedraw/vo/PrizeDrawPageReqVO.java
new file mode 100644
index 0000000..3b2a278
--- /dev/null
+++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/prizedraw/vo/PrizeDrawPageReqVO.java
@@ -0,0 +1,49 @@
+package cn.iocoder.yudao.module.promotion.controller.admin.prizedraw.vo;
+
+import com.alibaba.excel.annotation.ExcelProperty;
+import lombok.*;
+import java.util.*;
+import io.swagger.v3.oas.annotations.media.Schema;
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+import org.springframework.format.annotation.DateTimeFormat;
+import java.time.LocalDateTime;
+
+import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
+
+@Schema(description = "管理后台 - 抽奖活动分页 Request VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+public class PrizeDrawPageReqVO extends PageParam {
+
+ @Schema(description = "活动名称", example = "李四")
+ private String name;
+
+ @Schema(description = "活动规则")
+ private String activityRule;
+
+ @Schema(description = "活动状态(0:开启;1关闭)", example = "1")
+ private String status;
+
+ @Schema(description = "开始时间")
+ @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+ private LocalDateTime[] startTime;
+
+ @Schema(description = "截至时间")
+ @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+ private LocalDateTime[] endTime;
+
+ @Schema(description = "会员等级")
+ private Integer mebLevel;
+
+ /**
+ * 单人次抽奖次数
+ */
+ @Schema(description = "单人次抽奖次数")
+ private Integer drawNum;
+
+ @Schema(description = "创建时间")
+ @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+ private LocalDateTime[] createTime;
+
+}
diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/prizedraw/vo/PrizeDrawRespVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/prizedraw/vo/PrizeDrawRespVO.java
new file mode 100644
index 0000000..465d5e0
--- /dev/null
+++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/prizedraw/vo/PrizeDrawRespVO.java
@@ -0,0 +1,61 @@
+package cn.iocoder.yudao.module.promotion.controller.admin.prizedraw.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.*;
+import java.util.*;
+import org.springframework.format.annotation.DateTimeFormat;
+import java.time.LocalDateTime;
+import com.alibaba.excel.annotation.*;
+
+@Schema(description = "管理后台 - 抽奖活动 Response VO")
+@Data
+@ExcelIgnoreUnannotated
+public class PrizeDrawRespVO {
+
+ @Schema(description = "id主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "1166")
+ @ExcelProperty("id主键")
+ private Long id;
+
+ @Schema(description = "活动名称", example = "李四")
+ @ExcelProperty("活动名称")
+ private String name;
+
+ @Schema(description = "活动规则")
+ @ExcelProperty("活动规则")
+ private String activityRule;
+
+ @Schema(description = "活动状态(0:开启;1关闭)", example = "1")
+ @ExcelProperty("活动状态(0:开启;1关闭)")
+ private String status;
+
+ @Schema(description = "开始时间")
+ @ExcelProperty("开始时间")
+ private LocalDateTime startTime;
+
+ @Schema(description = "截至时间")
+ @ExcelProperty("截至时间")
+ private LocalDateTime endTime;
+
+ @Schema(description = "会员等级")
+ @ExcelProperty("会员等级")
+ private Long mebLevel;
+
+ /**
+ * 单人次抽奖次数
+ */
+ @Schema(description = "单人次抽奖次数")
+ @ExcelProperty("单人次抽奖次数")
+ private Integer drawNum;
+
+ @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
+ @ExcelProperty("创建时间")
+ private LocalDateTime createTime;
+
+ /**
+ * 会员等级名称
+ */
+ @Schema(description = "会员等级名称")
+ @ExcelProperty("会员等级名称")
+ private String levelName;
+
+}
diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/prizedraw/vo/PrizeDrawSaveReqVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/prizedraw/vo/PrizeDrawSaveReqVO.java
new file mode 100644
index 0000000..5165284
--- /dev/null
+++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/prizedraw/vo/PrizeDrawSaveReqVO.java
@@ -0,0 +1,46 @@
+package cn.iocoder.yudao.module.promotion.controller.admin.prizedraw.vo;
+
+import cn.iocoder.yudao.module.promotion.dal.dataobject.prizedraw.ActivityPrizeDO;
+import com.alibaba.excel.annotation.ExcelProperty;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.*;
+import java.util.*;
+import javax.validation.constraints.*;
+import org.springframework.format.annotation.DateTimeFormat;
+import java.time.LocalDateTime;
+
+@Schema(description = "管理后台 - 抽奖活动新增/修改 Request VO")
+@Data
+public class PrizeDrawSaveReqVO {
+
+ @Schema(description = "id主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "1166")
+ private Long id;
+
+ @Schema(description = "活动名称", example = "李四")
+ private String name;
+
+ @Schema(description = "活动规则")
+ private String activityRule;
+
+ @Schema(description = "活动状态(0:开启;1关闭)", example = "1")
+ private String status;
+
+ @Schema(description = "开始时间")
+ private LocalDateTime startTime;
+
+ @Schema(description = "截至时间")
+ private LocalDateTime endTime;
+
+ @Schema(description = "会员等级")
+ private Integer mebLevel;
+
+ /**
+ * 单人次抽奖次数
+ */
+ @Schema(description = "单人次抽奖次数")
+ private Integer drawNum;
+
+ @Schema(description = "抽奖活动奖品列表")
+ private List activityPrizes;
+
+}
diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/prizelog/PrizeLogController.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/prizelog/PrizeLogController.java
new file mode 100644
index 0000000..acf265f
--- /dev/null
+++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/prizelog/PrizeLogController.java
@@ -0,0 +1,115 @@
+package cn.iocoder.yudao.module.promotion.controller.admin.prizelog;
+
+import cn.iocoder.yudao.module.member.api.user.MemberUserApi;
+import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO;
+import cn.iocoder.yudao.module.promotion.convert.bargain.BargainHelpConvert;
+import cn.iocoder.yudao.module.promotion.convert.prizelog.PrizeLogConvert;
+import cn.iocoder.yudao.module.promotion.dal.dataobject.bargain.BargainHelpDO;
+import cn.iocoder.yudao.module.promotion.dal.dataobject.prizedraw.PrizeDrawDO;
+import cn.iocoder.yudao.module.promotion.service.prizedraw.PrizeDrawService;
+import org.springframework.web.bind.annotation.*;
+import javax.annotation.Resource;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.security.access.prepost.PreAuthorize;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.Operation;
+
+import javax.validation.constraints.*;
+import javax.validation.*;
+import javax.servlet.http.*;
+import java.util.*;
+import java.io.IOException;
+
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.common.pojo.CommonResult;
+import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
+
+import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
+
+import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog;
+import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.*;
+import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
+
+import cn.iocoder.yudao.module.promotion.controller.admin.prizelog.vo.*;
+import cn.iocoder.yudao.module.promotion.dal.dataobject.prizelog.PrizeLogDO;
+import cn.iocoder.yudao.module.promotion.service.prizelog.PrizeLogService;
+
+@Tag(name = "管理后台 - 抽奖记录")
+@RestController
+@RequestMapping("/promotion/prize-log")
+@Validated
+public class PrizeLogController {
+
+ @Resource
+ private PrizeLogService prizeLogService;
+
+ @Resource
+ private MemberUserApi memberUserApi;
+
+ @Resource
+ private PrizeDrawService prizeDrawService;
+
+ @PostMapping("/create")
+ @Operation(summary = "创建抽奖记录")
+ @PreAuthorize("@ss.hasPermission('promotion:prize-log:create')")
+ public CommonResult createPrizeLog(@Valid @RequestBody PrizeLogSaveReqVO createReqVO) {
+ return success(prizeLogService.createPrizeLog(createReqVO));
+ }
+
+ @PutMapping("/update")
+ @Operation(summary = "更新抽奖记录")
+ @PreAuthorize("@ss.hasPermission('promotion:prize-log:update')")
+ public CommonResult updatePrizeLog(@Valid @RequestBody PrizeLogSaveReqVO updateReqVO) {
+ prizeLogService.updatePrizeLog(updateReqVO);
+ return success(true);
+ }
+
+ @DeleteMapping("/delete")
+ @Operation(summary = "删除抽奖记录")
+ @Parameter(name = "id", description = "编号", required = true)
+ @PreAuthorize("@ss.hasPermission('promotion:prize-log:delete')")
+ public CommonResult deletePrizeLog(@RequestParam("id") Long id) {
+ prizeLogService.deletePrizeLog(id);
+ return success(true);
+ }
+
+ @GetMapping("/get")
+ @Operation(summary = "获得抽奖记录")
+ @Parameter(name = "id", description = "编号", required = true, example = "1024")
+ @PreAuthorize("@ss.hasPermission('promotion:prize-log:query')")
+ public CommonResult getPrizeLog(@RequestParam("id") Long id) {
+ PrizeLogDO prizeLog = prizeLogService.getPrizeLog(id);
+ return success(BeanUtils.toBean(prizeLog, PrizeLogRespVO.class));
+ }
+
+ @GetMapping("/page")
+ @Operation(summary = "获得抽奖记录分页")
+ @PreAuthorize("@ss.hasPermission('promotion:prize-log:query')")
+ public CommonResult> getPrizeLogPage(@Valid PrizeLogPageReqVO pageReqVO) {
+ PageResult pageResult = prizeLogService.getPrizeLogPage(pageReqVO);
+ // 拼接用户数据
+ Map userMap = memberUserApi.getUserMap(
+ convertSet(pageResult.getList(), PrizeLogDO::getMebId));
+ // 拼接活动数据
+ Map prizeMap = prizeDrawService.getPrizeDrawMap(
+ convertSet(pageResult.getList(), PrizeLogDO::getActivityId));
+ return success(PrizeLogConvert.INSTANCE.convertPage(pageResult, userMap,prizeMap));
+ }
+
+ @GetMapping("/export-excel")
+ @Operation(summary = "导出抽奖记录 Excel")
+ @PreAuthorize("@ss.hasPermission('promotion:prize-log:export')")
+ @ApiAccessLog(operateType = EXPORT)
+ public void exportPrizeLogExcel(@Valid PrizeLogPageReqVO pageReqVO,
+ HttpServletResponse response) throws IOException {
+ pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
+ List list = prizeLogService.getPrizeLogPage(pageReqVO).getList();
+ // 导出 Excel
+ ExcelUtils.write(response, "抽奖记录.xls", "数据", PrizeLogRespVO.class,
+ BeanUtils.toBean(list, PrizeLogRespVO.class));
+ }
+
+}
diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/prizelog/vo/PrizeLogPageReqVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/prizelog/vo/PrizeLogPageReqVO.java
new file mode 100644
index 0000000..7db8eca
--- /dev/null
+++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/prizelog/vo/PrizeLogPageReqVO.java
@@ -0,0 +1,49 @@
+package cn.iocoder.yudao.module.promotion.controller.admin.prizelog.vo;
+
+import lombok.*;
+import java.util.*;
+import io.swagger.v3.oas.annotations.media.Schema;
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+import org.springframework.format.annotation.DateTimeFormat;
+import java.time.LocalDateTime;
+
+import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
+
+@Schema(description = "管理后台 - 抽奖记录分页 Request VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+public class PrizeLogPageReqVO extends PageParam {
+
+ @Schema(description = "会员id", example = "26219")
+ private Long mebId;
+
+ @Schema(description = "关联抽奖活动id", example = "17850")
+ private Long activityId;
+
+ @Schema(description = "奖品id", example = "17850")
+ private Long prizeId;
+
+ @Schema(description = "奖品名称", example = "李四")
+ private String name;
+
+ @Schema(description = "奖品图片路径", example = "https://www.iocoder.cn")
+ private String imgUrl;
+
+ @Schema(description = "获奖人数上限")
+ private Integer winNum;
+
+ @Schema(description = "获奖概率")
+ private String prizeChance;
+
+ @Schema(description = "获奖金额")
+ private String prizePoolAmount;
+
+ @Schema(description = "兑奖状态(0:已兑奖;1:未兑奖)", example = "2")
+ private String status;
+
+ @Schema(description = "创建时间")
+ @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+ private LocalDateTime[] createTime;
+
+}
diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/prizelog/vo/PrizeLogRespVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/prizelog/vo/PrizeLogRespVO.java
new file mode 100644
index 0000000..63aee16
--- /dev/null
+++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/prizelog/vo/PrizeLogRespVO.java
@@ -0,0 +1,67 @@
+package cn.iocoder.yudao.module.promotion.controller.admin.prizelog.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.*;
+import java.util.*;
+import org.springframework.format.annotation.DateTimeFormat;
+import java.time.LocalDateTime;
+import com.alibaba.excel.annotation.*;
+
+@Schema(description = "管理后台 - 抽奖记录 Response VO")
+@Data
+@ExcelIgnoreUnannotated
+public class PrizeLogRespVO {
+
+ @Schema(description = "主键id", requiredMode = Schema.RequiredMode.REQUIRED, example = "5655")
+ @ExcelProperty("主键id")
+ private Long id;
+
+ @Schema(description = "会员id", example = "26219")
+ @ExcelProperty("会员id")
+ private Long mebId;
+
+ @Schema(description = "关联抽奖活动id", example = "17850")
+ @ExcelProperty("关联抽奖活动id")
+ private Long activityId;
+
+ @Schema(description = "奖品id", example = "17850")
+ @ExcelProperty("奖品id")
+ private Long prizeId;
+
+ @Schema(description = "奖品名称", example = "李四")
+ @ExcelProperty("奖品名称")
+ private String name;
+
+ @Schema(description = "奖品图片路径", example = "https://www.iocoder.cn")
+ @ExcelProperty("奖品图片路径")
+ private String imgUrl;
+
+ @Schema(description = "获奖人数上限")
+ @ExcelProperty("获奖人数上限")
+ private Integer winNum;
+
+ @Schema(description = "获奖概率")
+ @ExcelProperty("获奖概率")
+ private String prizeChance;
+
+ @Schema(description = "获奖金额")
+ @ExcelProperty("获奖金额")
+ private String prizePoolAmount;
+
+ @Schema(description = "兑奖状态(0:已兑奖;1:未兑奖)", example = "2")
+ @ExcelProperty("兑奖状态(0:已兑奖;1:未兑奖)")
+ private String status;
+
+ @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
+ @ExcelProperty("创建时间")
+ private LocalDateTime createTime;
+
+ // ========== 用户相关 ==========
+
+ @Schema(description = "用户昵称", example = "老芋艿")
+ private String nickname;
+
+ @Schema(description = "活动名称", example = "老芋艿")
+ private String activityName;
+
+}
diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/prizelog/vo/PrizeLogSaveReqVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/prizelog/vo/PrizeLogSaveReqVO.java
new file mode 100644
index 0000000..1fc8442
--- /dev/null
+++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/prizelog/vo/PrizeLogSaveReqVO.java
@@ -0,0 +1,42 @@
+package cn.iocoder.yudao.module.promotion.controller.admin.prizelog.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.*;
+import java.util.*;
+import javax.validation.constraints.*;
+
+@Schema(description = "管理后台 - 抽奖记录新增/修改 Request VO")
+@Data
+public class PrizeLogSaveReqVO {
+
+ @Schema(description = "主键id", requiredMode = Schema.RequiredMode.REQUIRED, example = "5655")
+ private Long id;
+
+ @Schema(description = "会员id", example = "26219")
+ private Long mebId;
+
+ @Schema(description = "关联抽奖活动id", example = "17850")
+ private Long activityId;
+
+ @Schema(description = "奖品id", example = "17850")
+ private Long prizeId;
+
+ @Schema(description = "奖品名称", example = "李四")
+ private String name;
+
+ @Schema(description = "奖品图片路径", example = "https://www.iocoder.cn")
+ private String imgUrl;
+
+ @Schema(description = "获奖人数上限")
+ private Integer winNum;
+
+ @Schema(description = "获奖概率")
+ private String prizeChance;
+
+ @Schema(description = "获奖金额")
+ private String prizePoolAmount;
+
+ @Schema(description = "兑奖状态(0:已兑奖;1:未兑奖)", example = "2")
+ private String status;
+
+}
diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/prizedraw/AppPrizeDrawController.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/prizedraw/AppPrizeDrawController.java
new file mode 100644
index 0000000..d5fa9c4
--- /dev/null
+++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/prizedraw/AppPrizeDrawController.java
@@ -0,0 +1,180 @@
+package cn.iocoder.yudao.module.promotion.controller.app.prizedraw;
+
+import cn.hutool.core.date.DateUtil;
+import cn.hutool.core.lang.WeightRandom;
+import cn.hutool.core.util.ObjectUtil;
+import cn.hutool.core.util.RandomUtil;
+import cn.iocoder.yudao.framework.common.pojo.CommonResult;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.common.util.date.DateUtils;
+import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+import cn.iocoder.yudao.module.member.api.level.MemberLevelApi;
+import cn.iocoder.yudao.module.member.api.level.dto.MemberLevelRespDTO;
+import cn.iocoder.yudao.module.member.api.user.MemberUserApi;
+import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO;
+import cn.iocoder.yudao.module.promotion.controller.admin.prizelog.vo.PrizeLogPageReqVO;
+import cn.iocoder.yudao.module.promotion.controller.admin.prizelog.vo.PrizeLogRespVO;
+import cn.iocoder.yudao.module.promotion.controller.admin.prizelog.vo.PrizeLogSaveReqVO;
+import cn.iocoder.yudao.module.promotion.controller.app.prizedraw.vo.AppPrizeDrawRespVO;
+import cn.iocoder.yudao.module.promotion.dal.dataobject.prizedraw.ActivityPrizeDO;
+import cn.iocoder.yudao.module.promotion.dal.dataobject.prizedraw.PrizeDrawDO;
+import cn.iocoder.yudao.module.promotion.dal.dataobject.prizelog.PrizeLogDO;
+import cn.iocoder.yudao.module.promotion.service.prizedraw.PrizeDrawService;
+import cn.iocoder.yudao.module.promotion.service.prizelog.PrizeLogService;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.redisson.api.RLock;
+import org.redisson.api.RedissonClient;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Lazy;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import javax.annotation.Resource;
+import javax.validation.Valid;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
+import static cn.iocoder.yudao.framework.common.pojo.CommonResult.error;
+import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
+import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.getLoginUserId;
+import static cn.iocoder.yudao.module.member.enums.ErrorCodeConstants.USER_NOT_EXISTS;
+import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.*;
+
+@Tag(name = "用户APP - 抽奖活动")
+@RestController
+@RequestMapping("/promotion/prize-draw")
+@Validated
+public class AppPrizeDrawController {
+
+ @Resource
+ private PrizeDrawService prizeDrawService;
+
+ @Resource
+ private PrizeLogService prizeLogService;
+
+ @Resource
+ private RedissonClient redissonClient;
+
+ @Resource
+ private MemberUserApi memberUserApi;
+
+ @Resource
+ private MemberLevelApi memberLevelApi;
+
+ @GetMapping("/getOne")
+ @Operation(summary = "用户APP--获得抽奖活动规则")
+ public CommonResult getPrizeDraw() {
+ PrizeDrawDO prizeDraw = prizeDrawService.getOnePrizeDraw();
+ if (prizeDraw == null) {//抽奖活动不存在
+ throw exception(PRIZE_DRAW_NOT_EXISTS);
+ }
+ return success(BeanUtils.toBean(prizeDraw, AppPrizeDrawRespVO.class));
+ }
+ @GetMapping("/activity-prize/list-by-activity-id")
+ @Operation(summary = "用户APP--获得抽奖活动奖品列表")
+ @Parameter(name = "activityId", description = "关联抽奖活动id")
+ public CommonResult> getActivityPrizeListByActivityId(@RequestParam("activityId") Long activityId) {
+ return success(prizeDrawService.getActivityPrizeListByActivityId(activityId));
+ }
+ @GetMapping("/lottery")
+ @Operation(summary = "用户APP--抽奖")
+ @Parameter(name = "activityId", description = "关联抽奖活动id")
+ public CommonResult lottery(@RequestParam("activityId") Long activityId) {
+ //获取用户id
+ Long loginUserId = getLoginUserId();
+ //查询用户信息
+ MemberUserRespDTO user = memberUserApi.getUser(loginUserId);
+ //用户不存在
+ if(user == null){
+ throw exception(USER_NOT_EXISTS);
+ }
+ //获取活动信息
+ PrizeDrawDO prizeDraw = prizeDrawService.getPrizeDraw(activityId);
+ if (prizeDraw == null) {//抽奖活动不存在
+ throw exception(PRIZE_DRAW_NOT_EXISTS);
+ }
+ //判断活动状态
+ if(!ObjectUtil.equal(prizeDraw.getStatus(),"0")){
+ throw exception(PRIZE_DRAW_NOT_START);
+ }
+ //判断抽奖活动时间范围
+ if(!DateUtil.isIn(new Date(),DateUtils.of(prizeDraw.getStartTime()),DateUtils.of(prizeDraw.getEndTime()))){
+ throw exception(PRIZE_DRAW_NOT_TIME);
+ }
+ //判断抽奖活动会员等级
+ MemberLevelRespDTO memberLevel = memberLevelApi.getMemberLevel(user.getLevelId());
+ MemberLevelRespDTO activityLevel = memberLevelApi.getMemberLevel(Long.valueOf(prizeDraw.getMebLevel()));
+ if(memberLevel.getLevel()=prizeDraw.getDrawNum()){
+ throw exception(PRIZE_LOG_NOT_DRAWNUM);
+ }
+ //抽奖
+ ActivityPrizeDO activityPrizeDO = recursionLottery(prizeDraw);
+ return success(activityPrizeDO);
+ }
+
+ private ActivityPrizeDO recursionLottery(PrizeDrawDO prizeDraw){
+ //获取奖品信息
+ List list = prizeDrawService.getActivityPrizeListByActivityId(prizeDraw.getId());
+ //获取随机数
+ int sortNum = (int) (Math.random() * ((8-list.size()) + 1));
+ // TODO: 2023/8/16 0016 后台限制
+ List> weightObjList = new ArrayList>();
+ list.forEach(s -> {
+ weightObjList.add(new WeightRandom.WeightObj<>(s.getId().toString(), Double.valueOf(s.getPrizeChance())));
+ });
+ WeightRandom wr = RandomUtil.weightRandom(weightObjList);
+ String str = wr.next();
+ RLock lock = redissonClient.getLock(str);
+ try {
+ if (lock.tryLock(1000, 10000, TimeUnit.MILLISECONDS)) {
+ ActivityPrizeDO activityPrize = prizeDrawService.getActivityPrize(Long.valueOf(str));
+ //判断被抽中次数
+ Long prizeLogNum = prizeLogService.getPrizeLogList(prizeDraw, activityPrize.getId());
+ if (prizeLogNum >= activityPrize.getWinNum()) {
+ recursionLottery(prizeDraw);
+ }
+ //中奖
+ //添加抽奖记录
+ PrizeLogSaveReqVO createReqVO = new PrizeLogSaveReqVO();
+ createReqVO.setMebId(getLoginUserId());
+ createReqVO.setActivityId(prizeDraw.getId());
+ createReqVO.setPrizeId(activityPrize.getId());
+ createReqVO.setName(activityPrize.getName());
+ createReqVO.setImgUrl(activityPrize.getImgUrl());
+ createReqVO.setWinNum(activityPrize.getWinNum());
+ createReqVO.setPrizeChance(activityPrize.getPrizeChance());
+ createReqVO.setPrizePoolAmount(activityPrize.getPrizePoolAmount());
+ createReqVO.setStatus("1");
+ prizeLogService.createPrizeLog(createReqVO);
+ return activityPrize;
+ }
+ } catch (InterruptedException e) {
+ throw new RuntimeException(e);
+ } finally {
+ if (ObjectUtil.isNotEmpty(lock)){
+ lock.unlock();
+ }
+ }
+ return null;
+ }
+
+ @GetMapping("/getMyPrizeLogDO")
+ @Operation(summary = "获得我的抽奖记录")
+ public CommonResult> getPrizeLogPage(@RequestParam("activityId") Long activityId) {
+ //获取活动信息
+ PrizeDrawDO prizeDraw = prizeDrawService.getPrizeDraw(activityId);
+ List list = prizeLogService.getPrizeLogListByMebId(getLoginUserId(), prizeDraw);
+ return success(BeanUtils.toBean(list, PrizeLogRespVO.class));
+ }
+}
diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/prizedraw/vo/AppPrizeDrawPageReqVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/prizedraw/vo/AppPrizeDrawPageReqVO.java
new file mode 100644
index 0000000..9116361
--- /dev/null
+++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/prizedraw/vo/AppPrizeDrawPageReqVO.java
@@ -0,0 +1,52 @@
+package cn.iocoder.yudao.module.promotion.controller.app.prizedraw.vo;
+
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+import com.alibaba.excel.annotation.ExcelProperty;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.time.LocalDateTime;
+
+import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
+
+@Schema(description = "应用 App - 抽奖活动分页 Request VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+public class AppPrizeDrawPageReqVO extends PageParam {
+
+ @Schema(description = "活动名称", example = "李四")
+ private String name;
+
+ @Schema(description = "活动规则")
+ private String activityRule;
+
+ @Schema(description = "活动状态(0:开启;1关闭)", example = "1")
+ private String status;
+
+ @Schema(description = "开始时间")
+ @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+ private LocalDateTime[] startTime;
+
+ @Schema(description = "截至时间")
+ @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+ private LocalDateTime[] endTime;
+
+ @Schema(description = "会员等级")
+ private Integer mebLevel;
+
+ /**
+ * 单人次抽奖次数
+ */
+ @Schema(description = "单人次抽奖次数")
+ @ExcelProperty("单人次抽奖次数")
+ private Integer drawNum;
+
+ @Schema(description = "创建时间")
+ @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+ private LocalDateTime[] createTime;
+
+}
diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/prizedraw/vo/AppPrizeDrawRespVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/prizedraw/vo/AppPrizeDrawRespVO.java
new file mode 100644
index 0000000..b9cfbbf
--- /dev/null
+++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/prizedraw/vo/AppPrizeDrawRespVO.java
@@ -0,0 +1,54 @@
+package cn.iocoder.yudao.module.promotion.controller.app.prizedraw.vo;
+
+import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
+import com.alibaba.excel.annotation.ExcelProperty;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.time.LocalDateTime;
+
+@Schema(description = "应用 App - 抽奖活动 Response VO")
+@Data
+@ExcelIgnoreUnannotated
+public class AppPrizeDrawRespVO {
+
+ @Schema(description = "id主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "1166")
+ @ExcelProperty("id主键")
+ private Long id;
+
+ @Schema(description = "活动名称", example = "李四")
+ @ExcelProperty("活动名称")
+ private String name;
+
+ @Schema(description = "活动规则")
+ @ExcelProperty("活动规则")
+ private String activityRule;
+
+ @Schema(description = "活动状态(0:开启;1关闭)", example = "1")
+ @ExcelProperty("活动状态(0:开启;1关闭)")
+ private String status;
+
+ @Schema(description = "开始时间")
+ @ExcelProperty("开始时间")
+ private LocalDateTime startTime;
+
+ @Schema(description = "截至时间")
+ @ExcelProperty("截至时间")
+ private LocalDateTime endTime;
+
+ @Schema(description = "会员等级")
+ @ExcelProperty("会员等级")
+ private Integer mebLevel;
+
+ /**
+ * 单人次抽奖次数
+ */
+ @Schema(description = "单人次抽奖次数")
+ @ExcelProperty("单人次抽奖次数")
+ private Integer drawNum;
+
+ @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
+ @ExcelProperty("创建时间")
+ private LocalDateTime createTime;
+
+}
diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/prizedraw/vo/AppPrizeDrawSaveReqVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/prizedraw/vo/AppPrizeDrawSaveReqVO.java
new file mode 100644
index 0000000..fab22fa
--- /dev/null
+++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/prizedraw/vo/AppPrizeDrawSaveReqVO.java
@@ -0,0 +1,44 @@
+package cn.iocoder.yudao.module.promotion.controller.app.prizedraw.vo;
+
+import cn.iocoder.yudao.module.promotion.dal.dataobject.prizedraw.ActivityPrizeDO;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.time.LocalDateTime;
+import java.util.List;
+
+@Schema(description = "应用 App - 抽奖活动新增/修改 Request VO")
+@Data
+public class AppPrizeDrawSaveReqVO {
+
+ @Schema(description = "id主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "1166")
+ private Long id;
+
+ @Schema(description = "活动名称", example = "李四")
+ private String name;
+
+ @Schema(description = "活动规则")
+ private String activityRule;
+
+ @Schema(description = "活动状态(0:开启;1关闭)", example = "1")
+ private String status;
+
+ @Schema(description = "开始时间")
+ private LocalDateTime startTime;
+
+ @Schema(description = "截至时间")
+ private LocalDateTime endTime;
+
+ @Schema(description = "会员等级")
+ private Integer mebLevel;
+
+ /**
+ * 单人次抽奖次数
+ */
+ @Schema(description = "单人次抽奖次数")
+ private Integer drawNum;
+
+ @Schema(description = "抽奖活动奖品列表")
+ private List activityPrizes;
+
+}
diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/prizedraw/PrizeDrawConvert.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/prizedraw/PrizeDrawConvert.java
new file mode 100644
index 0000000..952c582
--- /dev/null
+++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/prizedraw/PrizeDrawConvert.java
@@ -0,0 +1,36 @@
+package cn.iocoder.yudao.module.promotion.convert.prizedraw;
+
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
+import cn.iocoder.yudao.module.member.api.level.dto.MemberLevelRespDTO;
+import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO;
+import cn.iocoder.yudao.module.promotion.controller.admin.prizedraw.vo.PrizeDrawRespVO;
+import cn.iocoder.yudao.module.promotion.controller.admin.prizelog.vo.PrizeLogRespVO;
+import cn.iocoder.yudao.module.promotion.convert.prizelog.PrizeLogConvert;
+import cn.iocoder.yudao.module.promotion.dal.dataobject.prizedraw.PrizeDrawDO;
+import cn.iocoder.yudao.module.promotion.dal.dataobject.prizelog.PrizeLogDO;
+import org.mapstruct.Mapper;
+import org.mapstruct.factory.Mappers;
+
+import java.util.List;
+import java.util.Map;
+
+import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;
+
+@Mapper
+public interface PrizeDrawConvert {
+ PrizeDrawConvert INSTANCE = Mappers.getMapper(PrizeDrawConvert.class);
+
+ default PageResult convertPage(PageResult page,
+ List levels) {
+ PageResult pageResult = convertPage(page);
+ Map levelMap = convertMap(levels, MemberLevelRespDTO::getId, MemberLevelRespDTO::getName);
+ // 拼接数据
+ pageResult.getList().forEach(record ->{
+ MapUtils.findAndThen(levelMap, record.getMebLevel(),
+ level -> record.setLevelName(levelMap.get(record.getMebLevel())));
+ });
+ return pageResult;
+ }
+ PageResult convertPage(PageResult page);
+}
diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/prizelog/PrizeLogConvert.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/prizelog/PrizeLogConvert.java
new file mode 100644
index 0000000..58e3819
--- /dev/null
+++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/prizelog/PrizeLogConvert.java
@@ -0,0 +1,42 @@
+package cn.iocoder.yudao.module.promotion.convert.prizelog;
+
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
+import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO;
+import cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.help.BargainHelpRespVO;
+import cn.iocoder.yudao.module.promotion.controller.admin.prizelog.vo.PrizeLogRespVO;
+import cn.iocoder.yudao.module.promotion.controller.app.bargain.vo.help.AppBargainHelpRespVO;
+import cn.iocoder.yudao.module.promotion.dal.dataobject.bargain.BargainHelpDO;
+import cn.iocoder.yudao.module.promotion.dal.dataobject.prizedraw.PrizeDrawDO;
+import cn.iocoder.yudao.module.promotion.dal.dataobject.prizelog.PrizeLogDO;
+import org.mapstruct.Mapper;
+import org.mapstruct.factory.Mappers;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 抽奖记录 Convert
+ *
+ * @author 芋道源码
+ */
+@Mapper
+public interface PrizeLogConvert {
+
+ PrizeLogConvert INSTANCE = Mappers.getMapper(PrizeLogConvert.class);
+
+ default PageResult convertPage(PageResult page,
+ Map userMap,
+ Map prizeMap) {
+ PageResult pageResult = convertPage(page);
+ // 拼接数据
+ pageResult.getList().forEach(record ->{
+ MapUtils.findAndThen(userMap, record.getMebId(),
+ user -> record.setNickname(user.getNickname()));
+ MapUtils.findAndThen(prizeMap, record.getActivityId(),
+ activity -> record.setActivityName(activity.getName()));
+ });
+ return pageResult;
+ }
+ PageResult convertPage(PageResult page);
+}
diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/prizedraw/ActivityPrizeDO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/prizedraw/ActivityPrizeDO.java
new file mode 100644
index 0000000..9fc93f6
--- /dev/null
+++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/prizedraw/ActivityPrizeDO.java
@@ -0,0 +1,55 @@
+package cn.iocoder.yudao.module.promotion.dal.dataobject.prizedraw;
+
+import lombok.*;
+import java.util.*;
+import java.time.LocalDateTime;
+import java.time.LocalDateTime;
+import com.baomidou.mybatisplus.annotation.*;
+import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
+
+/**
+ * 抽奖活动奖品 DO
+ *
+ * @author 芋道源码
+ */
+@TableName("promotion_activity_prize")
+@KeySequence("promotion_activity_prize_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class ActivityPrizeDO extends BaseDO {
+
+ /**
+ * id主键
+ */
+ @TableId
+ private Long id;
+ /**
+ * 关联抽奖活动id
+ */
+ private Long activityId;
+ /**
+ * 奖品名称
+ */
+ private String name;
+ /**
+ * 奖品图片路径
+ */
+ private String imgUrl;
+ /**
+ * 获奖人数上限
+ */
+ private Integer winNum;
+ /**
+ * 获奖概率
+ */
+ private String prizeChance;
+ /**
+ * 获奖金额
+ */
+ private String prizePoolAmount;
+
+}
diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/prizedraw/PrizeDrawDO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/prizedraw/PrizeDrawDO.java
new file mode 100644
index 0000000..5d755e8
--- /dev/null
+++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/prizedraw/PrizeDrawDO.java
@@ -0,0 +1,61 @@
+package cn.iocoder.yudao.module.promotion.dal.dataobject.prizedraw;
+
+import lombok.*;
+import java.util.*;
+import java.time.LocalDateTime;
+import java.time.LocalDateTime;
+import java.time.LocalDateTime;
+import java.time.LocalDateTime;
+import com.baomidou.mybatisplus.annotation.*;
+import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
+
+/**
+ * 抽奖活动 DO
+ *
+ * @author 芋道源码
+ */
+@TableName("promotion_prize_draw")
+@KeySequence("promotion_prize_draw_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class PrizeDrawDO extends BaseDO {
+
+ /**
+ * id主键
+ */
+ @TableId
+ private Long id;
+ /**
+ * 活动名称
+ */
+ private String name;
+ /**
+ * 活动规则
+ */
+ private String activityRule;
+ /**
+ * 活动状态(0:开启;1关闭)
+ */
+ private String status;
+ /**
+ * 开始时间
+ */
+ private LocalDateTime startTime;
+ /**
+ * 截至时间
+ */
+ private LocalDateTime endTime;
+ /**
+ * 会员等级
+ */
+ private Long mebLevel;
+
+ /**
+ * 单人次抽奖次数
+ */
+ private Integer drawNum;
+}
diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/prizelog/PrizeLogDO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/prizelog/PrizeLogDO.java
new file mode 100644
index 0000000..a543db0
--- /dev/null
+++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/prizelog/PrizeLogDO.java
@@ -0,0 +1,67 @@
+package cn.iocoder.yudao.module.promotion.dal.dataobject.prizelog;
+
+import lombok.*;
+import java.util.*;
+import java.time.LocalDateTime;
+import java.time.LocalDateTime;
+import com.baomidou.mybatisplus.annotation.*;
+import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
+
+/**
+ * 抽奖记录 DO
+ *
+ * @author 芋道源码
+ */
+@TableName("promotion_prize_log")
+@KeySequence("promotion_prize_log_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class PrizeLogDO extends BaseDO {
+
+ /**
+ * 主键id
+ */
+ @TableId
+ private Long id;
+ /**
+ * 会员id
+ */
+ private Long mebId;
+ /**
+ * 关联抽奖活动id
+ */
+ private Long activityId;
+ /**
+ * 奖品id
+ */
+ private Long prizeId;
+ /**
+ * 奖品名称
+ */
+ private String name;
+ /**
+ * 奖品图片路径
+ */
+ private String imgUrl;
+ /**
+ * 获奖人数上限
+ */
+ private Integer winNum;
+ /**
+ * 获奖概率
+ */
+ private String prizeChance;
+ /**
+ * 获奖金额
+ */
+ private String prizePoolAmount;
+ /**
+ * 兑奖状态(0:已兑奖;1:未兑奖)
+ */
+ private String status;
+
+}
diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/prizedraw/ActivityPrizeMapper.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/prizedraw/ActivityPrizeMapper.java
new file mode 100644
index 0000000..67830a5
--- /dev/null
+++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/prizedraw/ActivityPrizeMapper.java
@@ -0,0 +1,28 @@
+package cn.iocoder.yudao.module.promotion.dal.mysql.prizedraw;
+
+import java.util.*;
+
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
+import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
+import cn.iocoder.yudao.module.promotion.dal.dataobject.prizedraw.ActivityPrizeDO;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * 抽奖活动奖品 Mapper
+ *
+ * @author 芋道源码
+ */
+@Mapper
+public interface ActivityPrizeMapper extends BaseMapperX {
+
+ default List selectListByActivityId(Long activityId) {
+ return selectList(ActivityPrizeDO::getActivityId, activityId);
+ }
+
+ default int deleteByActivityId(Long activityId) {
+ return delete(ActivityPrizeDO::getActivityId, activityId);
+ }
+
+}
diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/prizedraw/PrizeDrawMapper.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/prizedraw/PrizeDrawMapper.java
new file mode 100644
index 0000000..7b0f8d9
--- /dev/null
+++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/prizedraw/PrizeDrawMapper.java
@@ -0,0 +1,32 @@
+package cn.iocoder.yudao.module.promotion.dal.mysql.prizedraw;
+
+import java.util.*;
+
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
+import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
+import cn.iocoder.yudao.module.promotion.dal.dataobject.prizedraw.PrizeDrawDO;
+import org.apache.ibatis.annotations.Mapper;
+import cn.iocoder.yudao.module.promotion.controller.admin.prizedraw.vo.*;
+
+/**
+ * 抽奖活动 Mapper
+ *
+ * @author 芋道源码
+ */
+@Mapper
+public interface PrizeDrawMapper extends BaseMapperX {
+
+ default PageResult selectPage(PrizeDrawPageReqVO reqVO) {
+ return selectPage(reqVO, new LambdaQueryWrapperX()
+ .likeIfPresent(PrizeDrawDO::getName, reqVO.getName())
+ .eqIfPresent(PrizeDrawDO::getActivityRule, reqVO.getActivityRule())
+ .eqIfPresent(PrizeDrawDO::getStatus, reqVO.getStatus())
+ .betweenIfPresent(PrizeDrawDO::getStartTime, reqVO.getStartTime())
+ .betweenIfPresent(PrizeDrawDO::getEndTime, reqVO.getEndTime())
+ .eqIfPresent(PrizeDrawDO::getMebLevel, reqVO.getMebLevel())
+ .betweenIfPresent(PrizeDrawDO::getCreateTime, reqVO.getCreateTime())
+ .orderByDesc(PrizeDrawDO::getId));
+ }
+
+}
\ No newline at end of file
diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/prizelog/PrizeLogMapper.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/prizelog/PrizeLogMapper.java
new file mode 100644
index 0000000..650d62e
--- /dev/null
+++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/prizelog/PrizeLogMapper.java
@@ -0,0 +1,34 @@
+package cn.iocoder.yudao.module.promotion.dal.mysql.prizelog;
+
+import java.util.*;
+
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
+import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
+import cn.iocoder.yudao.module.promotion.dal.dataobject.prizelog.PrizeLogDO;
+import org.apache.ibatis.annotations.Mapper;
+import cn.iocoder.yudao.module.promotion.controller.admin.prizelog.vo.*;
+
+/**
+ * 抽奖记录 Mapper
+ *
+ * @author 芋道源码
+ */
+@Mapper
+public interface PrizeLogMapper extends BaseMapperX {
+
+ default PageResult selectPage(PrizeLogPageReqVO reqVO) {
+ return selectPage(reqVO, new LambdaQueryWrapperX()
+ .eqIfPresent(PrizeLogDO::getMebId, reqVO.getMebId())
+ .eqIfPresent(PrizeLogDO::getActivityId, reqVO.getActivityId())
+ .likeIfPresent(PrizeLogDO::getName, reqVO.getName())
+ .eqIfPresent(PrizeLogDO::getImgUrl, reqVO.getImgUrl())
+ .eqIfPresent(PrizeLogDO::getWinNum, reqVO.getWinNum())
+ .eqIfPresent(PrizeLogDO::getPrizeChance, reqVO.getPrizeChance())
+ .eqIfPresent(PrizeLogDO::getPrizePoolAmount, reqVO.getPrizePoolAmount())
+ .eqIfPresent(PrizeLogDO::getStatus, reqVO.getStatus())
+ .betweenIfPresent(PrizeLogDO::getCreateTime, reqVO.getCreateTime())
+ .orderByDesc(PrizeLogDO::getId));
+ }
+
+}
\ No newline at end of file
diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/prizedraw/PrizeDrawService.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/prizedraw/PrizeDrawService.java
new file mode 100644
index 0000000..e57e2b8
--- /dev/null
+++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/prizedraw/PrizeDrawService.java
@@ -0,0 +1,104 @@
+package cn.iocoder.yudao.module.promotion.service.prizedraw;
+
+import java.util.*;
+import javax.validation.*;
+
+import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO;
+import cn.iocoder.yudao.module.promotion.controller.admin.prizedraw.vo.*;
+import cn.iocoder.yudao.module.promotion.controller.app.prizedraw.vo.AppPrizeDrawRespVO;
+import cn.iocoder.yudao.module.promotion.dal.dataobject.prizedraw.ActivityPrizeDO;
+import cn.iocoder.yudao.module.promotion.dal.dataobject.prizedraw.PrizeDrawDO;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+
+import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;
+
+/**
+ * 抽奖活动 Service 接口
+ *
+ * @author 芋道源码
+ */
+public interface PrizeDrawService {
+
+ /**
+ * 创建抽奖活动
+ *
+ * @param createReqVO 创建信息
+ * @return 编号
+ */
+ Long createPrizeDraw(@Valid PrizeDrawSaveReqVO createReqVO);
+
+ /**
+ * 更新抽奖活动
+ *
+ * @param updateReqVO 更新信息
+ */
+ void updatePrizeDraw(@Valid PrizeDrawSaveReqVO updateReqVO);
+
+ /**
+ * 删除抽奖活动
+ *
+ * @param id 编号
+ */
+ void deletePrizeDraw(Long id);
+
+ /**
+ * 获得抽奖活动
+ *
+ * @param id 编号
+ * @return 抽奖活动
+ */
+ PrizeDrawDO getPrizeDraw(Long id);
+
+ /**
+ * 获得抽奖活动分页
+ *
+ * @param pageReqVO 分页查询
+ * @return 抽奖活动分页
+ */
+ PageResult getPrizeDrawPage(PrizeDrawPageReqVO pageReqVO);
+
+ // ==================== 子表(抽奖活动奖品) ====================
+
+ /**
+ * 获得抽奖活动奖品列表
+ *
+ * @param activityId 关联抽奖活动id
+ * @return 抽奖活动奖品列表
+ */
+ List getActivityPrizeListByActivityId(Long activityId);
+ /**
+ * 获得抽奖活动奖品
+ *
+ * @param id 奖品id
+ * @return 抽奖活动奖品列表
+ */
+ ActivityPrizeDO getActivityPrize(Long id);
+
+ /**
+ * 获得已开启抽奖活动
+ *
+ * @return 抽奖活动
+ */
+ PrizeDrawDO getOnePrizeDraw();
+
+
+ /**
+ * 获得活动 Map
+ *
+ * @param ids 活动id的数组
+ * @return 活动 Map
+ */
+ default Map getPrizeDrawMap(Collection ids) {
+ List list = getPrizeDrawDOList(ids);
+ return convertMap(list, PrizeDrawDO::getId);
+ }
+
+ /**
+ * 获得活动信息
+ *
+ * @param ids 用户编号的数组
+ * @return 用户信息们
+ */
+ List getPrizeDrawDOList(Collection ids);
+}
diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/prizedraw/PrizeDrawServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/prizedraw/PrizeDrawServiceImpl.java
new file mode 100644
index 0000000..7304758
--- /dev/null
+++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/prizedraw/PrizeDrawServiceImpl.java
@@ -0,0 +1,136 @@
+package cn.iocoder.yudao.module.promotion.service.prizedraw;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.collection.ListUtil;
+import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
+import cn.iocoder.yudao.module.promotion.dal.dataobject.prizedraw.ActivityPrizeDO;
+import cn.iocoder.yudao.module.promotion.dal.mysql.prizedraw.ActivityPrizeMapper;
+import org.springframework.stereotype.Service;
+import javax.annotation.Resource;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.*;
+import cn.iocoder.yudao.module.promotion.controller.admin.prizedraw.vo.*;
+import cn.iocoder.yudao.module.promotion.dal.dataobject.prizedraw.PrizeDrawDO;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+
+import cn.iocoder.yudao.module.promotion.dal.mysql.prizedraw.PrizeDrawMapper;
+
+import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
+import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.*;
+
+/**
+ * 抽奖活动 Service 实现类
+ *
+ * @author 芋道源码
+ */
+@Service
+@Validated
+public class PrizeDrawServiceImpl implements PrizeDrawService {
+
+ @Resource
+ private PrizeDrawMapper prizeDrawMapper;
+ @Resource
+ private ActivityPrizeMapper activityPrizeMapper;
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public Long createPrizeDraw(PrizeDrawSaveReqVO createReqVO) {
+ // 插入
+ PrizeDrawDO prizeDraw = BeanUtils.toBean(createReqVO, PrizeDrawDO.class);
+ prizeDrawMapper.insert(prizeDraw);
+
+ // 插入子表
+ createActivityPrizeList(prizeDraw.getId(), createReqVO.getActivityPrizes());
+ // 返回
+ return prizeDraw.getId();
+ }
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public void updatePrizeDraw(PrizeDrawSaveReqVO updateReqVO) {
+ // 校验存在
+ validatePrizeDrawExists(updateReqVO.getId());
+ // 更新
+ PrizeDrawDO updateObj = BeanUtils.toBean(updateReqVO, PrizeDrawDO.class);
+ prizeDrawMapper.updateById(updateObj);
+
+ // 更新子表
+ updateActivityPrizeList(updateReqVO.getId(), updateReqVO.getActivityPrizes());
+ }
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public void deletePrizeDraw(Long id) {
+ // 校验存在
+ validatePrizeDrawExists(id);
+ // 删除
+ prizeDrawMapper.deleteById(id);
+
+ // 删除子表
+ deleteActivityPrizeByActivityId(id);
+ }
+
+ private void validatePrizeDrawExists(Long id) {
+ if (prizeDrawMapper.selectById(id) == null) {
+ throw exception(PRIZE_DRAW_NOT_EXISTS);
+ }
+ }
+
+ @Override
+ public PrizeDrawDO getPrizeDraw(Long id) {
+ return prizeDrawMapper.selectById(id);
+ }
+
+ @Override
+ public PageResult getPrizeDrawPage(PrizeDrawPageReqVO pageReqVO) {
+ return prizeDrawMapper.selectPage(pageReqVO);
+ }
+
+ // ==================== 子表(抽奖活动奖品) ====================
+
+ @Override
+ public List getActivityPrizeListByActivityId(Long activityId) {
+ return activityPrizeMapper.selectListByActivityId(activityId);
+ }
+
+ private void createActivityPrizeList(Long activityId, List list) {
+ list.forEach(o -> o.setActivityId(activityId));
+ activityPrizeMapper.insertBatch(list);
+ }
+
+ private void updateActivityPrizeList(Long activityId, List list) {
+ deleteActivityPrizeByActivityId(activityId);
+ list.forEach(o -> o.setId(null).setUpdater(null).setUpdateTime(null)); // 解决更新情况下:1)id 冲突;2)updateTime 不更新
+ createActivityPrizeList(activityId, list);
+ }
+
+ private void deleteActivityPrizeByActivityId(Long activityId) {
+ activityPrizeMapper.deleteByActivityId(activityId);
+ }
+
+
+ @Override
+ public PrizeDrawDO getOnePrizeDraw() {
+ return prizeDrawMapper.selectOne(new LambdaQueryWrapperX()
+ .eq(PrizeDrawDO::getStatus, 0)
+ );
+ }
+
+ @Override
+ public List getPrizeDrawDOList(Collection ids) {
+ if (CollUtil.isEmpty(ids)) {
+ return ListUtil.empty();
+ }
+ return prizeDrawMapper.selectBatchIds(ids);
+ }
+
+ @Override
+ public ActivityPrizeDO getActivityPrize(Long id) {
+ return activityPrizeMapper.selectById(id);
+ }
+
+}
diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/prizelog/PrizeLogService.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/prizelog/PrizeLogService.java
new file mode 100644
index 0000000..d29ac07
--- /dev/null
+++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/prizelog/PrizeLogService.java
@@ -0,0 +1,81 @@
+package cn.iocoder.yudao.module.promotion.service.prizelog;
+
+import java.util.*;
+import javax.validation.*;
+
+import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO;
+import cn.iocoder.yudao.module.promotion.controller.admin.prizelog.vo.*;
+import cn.iocoder.yudao.module.promotion.dal.dataobject.prizedraw.PrizeDrawDO;
+import cn.iocoder.yudao.module.promotion.dal.dataobject.prizelog.PrizeLogDO;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+
+import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;
+
+/**
+ * 抽奖记录 Service 接口
+ *
+ * @author 芋道源码
+ */
+public interface PrizeLogService {
+
+ /**
+ * 创建抽奖记录
+ *
+ * @param createReqVO 创建信息
+ * @return 编号
+ */
+ Long createPrizeLog(@Valid PrizeLogSaveReqVO createReqVO);
+
+ /**
+ * 更新抽奖记录
+ *
+ * @param updateReqVO 更新信息
+ */
+ void updatePrizeLog(@Valid PrizeLogSaveReqVO updateReqVO);
+
+ /**
+ * 删除抽奖记录
+ *
+ * @param id 编号
+ */
+ void deletePrizeLog(Long id);
+
+ /**
+ * 获得抽奖记录
+ *
+ * @param id 编号
+ * @return 抽奖记录
+ */
+ PrizeLogDO getPrizeLog(Long id);
+
+ /**
+ * 获得抽奖记录分页
+ *
+ * @param pageReqVO 分页查询
+ * @return 抽奖记录分页
+ */
+ PageResult getPrizeLogPage(PrizeLogPageReqVO pageReqVO);
+ /**
+ * 查询用户抽奖次数
+ *
+ * @param mebId 用户id
+ * @return 抽奖记录分页
+ */
+ Long getPrizeLogByMebIdList(Long mebId,PrizeDrawDO prizeDraw);
+ /**
+ * 查询奖品被抽中次数
+ *
+ * @param prizeDraw 活动
+ * @return 抽奖记录分页
+ */
+ Long getPrizeLogList(PrizeDrawDO prizeDraw,Long prizeId);
+ /**
+ * 获取我的抽奖记录
+ *
+ * @param prizeDraw 活动
+ * @return 抽奖记录分页
+ */
+ List getPrizeLogListByMebId(Long mebId,PrizeDrawDO prizeDraw);
+
+}
diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/prizelog/PrizeLogServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/prizelog/PrizeLogServiceImpl.java
new file mode 100644
index 0000000..410f7e7
--- /dev/null
+++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/prizelog/PrizeLogServiceImpl.java
@@ -0,0 +1,103 @@
+package cn.iocoder.yudao.module.promotion.service.prizelog;
+
+import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
+import cn.iocoder.yudao.module.promotion.dal.dataobject.prizedraw.PrizeDrawDO;
+import org.springframework.stereotype.Service;
+import javax.annotation.Resource;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.*;
+import cn.iocoder.yudao.module.promotion.controller.admin.prizelog.vo.*;
+import cn.iocoder.yudao.module.promotion.dal.dataobject.prizelog.PrizeLogDO;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+
+import cn.iocoder.yudao.module.promotion.dal.mysql.prizelog.PrizeLogMapper;
+
+import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
+import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.*;
+
+/**
+ * 抽奖记录 Service 实现类
+ *
+ * @author 芋道源码
+ */
+@Service
+@Validated
+public class PrizeLogServiceImpl implements PrizeLogService {
+
+ @Resource
+ private PrizeLogMapper prizeLogMapper;
+
+ @Override
+ public Long createPrizeLog(PrizeLogSaveReqVO createReqVO) {
+ // 插入
+ PrizeLogDO prizeLog = BeanUtils.toBean(createReqVO, PrizeLogDO.class);
+ prizeLogMapper.insert(prizeLog);
+ // 返回
+ return prizeLog.getId();
+ }
+
+ @Override
+ public void updatePrizeLog(PrizeLogSaveReqVO updateReqVO) {
+ // 校验存在
+ validatePrizeLogExists(updateReqVO.getId());
+ // 更新
+ PrizeLogDO updateObj = BeanUtils.toBean(updateReqVO, PrizeLogDO.class);
+ prizeLogMapper.updateById(updateObj);
+ }
+
+ @Override
+ public void deletePrizeLog(Long id) {
+ // 校验存在
+ validatePrizeLogExists(id);
+ // 删除
+ prizeLogMapper.deleteById(id);
+ }
+
+ private void validatePrizeLogExists(Long id) {
+ if (prizeLogMapper.selectById(id) == null) {
+ throw exception(PRIZE_LOG_NOT_EXISTS);
+ }
+ }
+
+ @Override
+ public PrizeLogDO getPrizeLog(Long id) {
+ return prizeLogMapper.selectById(id);
+ }
+
+ @Override
+ public PageResult getPrizeLogPage(PrizeLogPageReqVO pageReqVO) {
+ return prizeLogMapper.selectPage(pageReqVO);
+ }
+
+ @Override
+ public Long getPrizeLogByMebIdList(Long mebId,PrizeDrawDO prizeDraw) {
+ return prizeLogMapper.selectCount(new LambdaQueryWrapperX()
+ .eq(PrizeLogDO::getMebId, mebId)
+ .ge(PrizeLogDO::getCreateTime, prizeDraw.getStartTime())
+ .le(PrizeLogDO::getCreateTime, prizeDraw.getEndTime())
+ );
+ }
+
+ @Override
+ public Long getPrizeLogList(PrizeDrawDO prizeDraw,Long prizeId) {
+ return prizeLogMapper.selectCount(new LambdaQueryWrapperX()
+ .eq(PrizeLogDO::getPrizeId,prizeId)
+ .ge(PrizeLogDO::getCreateTime, prizeDraw.getStartTime())
+ .le(PrizeLogDO::getCreateTime, prizeDraw.getEndTime())
+ );
+ }
+
+ @Override
+ public List getPrizeLogListByMebId(Long mebId,PrizeDrawDO prizeDraw) {
+ return prizeLogMapper.selectList(new LambdaQueryWrapperX()
+ .eq(PrizeLogDO::getMebId, mebId)
+ .ge(PrizeLogDO::getCreateTime, prizeDraw.getStartTime())
+ .le(PrizeLogDO::getCreateTime, prizeDraw.getEndTime())
+ );
+ }
+
+}
diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/resources/mapper/prizedraw/PrizeDrawMapper.xml b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/resources/mapper/prizedraw/PrizeDrawMapper.xml
new file mode 100644
index 0000000..3fa77d9
--- /dev/null
+++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/resources/mapper/prizedraw/PrizeDrawMapper.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/resources/mapper/prizelog/PrizeLogMapper.xml b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/resources/mapper/prizelog/PrizeLogMapper.xml
new file mode 100644
index 0000000..a96a198
--- /dev/null
+++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/resources/mapper/prizelog/PrizeLogMapper.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/test/java/cn/iocoder/yudao/module/promotion/service/prizedraw/PrizeDrawServiceImplTest.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/test/java/cn/iocoder/yudao/module/promotion/service/prizedraw/PrizeDrawServiceImplTest.java
new file mode 100644
index 0000000..e9395ce
--- /dev/null
+++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/test/java/cn/iocoder/yudao/module/promotion/service/prizedraw/PrizeDrawServiceImplTest.java
@@ -0,0 +1,154 @@
+package cn.iocoder.yudao.module.promotion.service.prizedraw;
+
+import org.junit.jupiter.api.Disabled;
+import org.junit.jupiter.api.Test;
+import org.springframework.boot.test.mock.mockito.MockBean;
+
+import javax.annotation.Resource;
+
+import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
+
+import cn.iocoder.yudao.module.promotion.controller.admin.prizedraw.vo.*;
+import cn.iocoder.yudao.module.promotion.dal.dataobject.prizedraw.PrizeDrawDO;
+import cn.iocoder.yudao.module.promotion.dal.mysql.prizedraw.PrizeDrawMapper;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+
+import javax.annotation.Resource;
+import org.springframework.context.annotation.Import;
+import java.util.*;
+import java.time.LocalDateTime;
+
+import static cn.hutool.core.util.RandomUtil.*;
+import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.*;
+import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.*;
+import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*;
+import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.*;
+import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.*;
+import static cn.iocoder.yudao.framework.common.util.date.DateUtils.*;
+import static org.junit.jupiter.api.Assertions.*;
+import static org.mockito.Mockito.*;
+
+/**
+ * {@link PrizeDrawServiceImpl} 的单元测试类
+ *
+ * @author 芋道源码
+ */
+@Import(PrizeDrawServiceImpl.class)
+public class PrizeDrawServiceImplTest extends BaseDbUnitTest {
+
+ @Resource
+ private PrizeDrawServiceImpl prizeDrawService;
+
+ @Resource
+ private PrizeDrawMapper prizeDrawMapper;
+
+ @Test
+ public void testCreatePrizeDraw_success() {
+ // 准备参数
+ PrizeDrawSaveReqVO createReqVO = randomPojo(PrizeDrawSaveReqVO.class).setId(null);
+
+ // 调用
+ Long prizeDrawId = prizeDrawService.createPrizeDraw(createReqVO);
+ // 断言
+ assertNotNull(prizeDrawId);
+ // 校验记录的属性是否正确
+ PrizeDrawDO prizeDraw = prizeDrawMapper.selectById(prizeDrawId);
+ assertPojoEquals(createReqVO, prizeDraw, "id");
+ }
+
+ @Test
+ public void testUpdatePrizeDraw_success() {
+ // mock 数据
+ PrizeDrawDO dbPrizeDraw = randomPojo(PrizeDrawDO.class);
+ prizeDrawMapper.insert(dbPrizeDraw);// @Sql: 先插入出一条存在的数据
+ // 准备参数
+ PrizeDrawSaveReqVO updateReqVO = randomPojo(PrizeDrawSaveReqVO.class, o -> {
+ o.setId(dbPrizeDraw.getId()); // 设置更新的 ID
+ });
+
+ // 调用
+ prizeDrawService.updatePrizeDraw(updateReqVO);
+ // 校验是否更新正确
+ PrizeDrawDO prizeDraw = prizeDrawMapper.selectById(updateReqVO.getId()); // 获取最新的
+ assertPojoEquals(updateReqVO, prizeDraw);
+ }
+
+ @Test
+ public void testUpdatePrizeDraw_notExists() {
+ // 准备参数
+ PrizeDrawSaveReqVO updateReqVO = randomPojo(PrizeDrawSaveReqVO.class);
+
+ // 调用, 并断言异常
+ assertServiceException(() -> prizeDrawService.updatePrizeDraw(updateReqVO), PRIZE_DRAW_NOT_EXISTS);
+ }
+
+ @Test
+ public void testDeletePrizeDraw_success() {
+ // mock 数据
+ PrizeDrawDO dbPrizeDraw = randomPojo(PrizeDrawDO.class);
+ prizeDrawMapper.insert(dbPrizeDraw);// @Sql: 先插入出一条存在的数据
+ // 准备参数
+ Long id = dbPrizeDraw.getId();
+
+ // 调用
+ prizeDrawService.deletePrizeDraw(id);
+ // 校验数据不存在了
+ assertNull(prizeDrawMapper.selectById(id));
+ }
+
+ @Test
+ public void testDeletePrizeDraw_notExists() {
+ // 准备参数
+ Long id = randomLongId();
+
+ // 调用, 并断言异常
+ assertServiceException(() -> prizeDrawService.deletePrizeDraw(id), PRIZE_DRAW_NOT_EXISTS);
+ }
+
+ @Test
+ @Disabled // TODO 请修改 null 为需要的值,然后删除 @Disabled 注解
+ public void testGetPrizeDrawPage() {
+ // mock 数据
+ PrizeDrawDO dbPrizeDraw = randomPojo(PrizeDrawDO.class, o -> { // 等会查询到
+ o.setName(null);
+ o.setActivityRule(null);
+ o.setStatus(null);
+ o.setStartTime(null);
+ o.setEndTime(null);
+ o.setMebLevel(null);
+ o.setCreateTime(null);
+ });
+ prizeDrawMapper.insert(dbPrizeDraw);
+ // 测试 name 不匹配
+ prizeDrawMapper.insert(cloneIgnoreId(dbPrizeDraw, o -> o.setName(null)));
+ // 测试 activityRule 不匹配
+ prizeDrawMapper.insert(cloneIgnoreId(dbPrizeDraw, o -> o.setActivityRule(null)));
+ // 测试 status 不匹配
+ prizeDrawMapper.insert(cloneIgnoreId(dbPrizeDraw, o -> o.setStatus(null)));
+ // 测试 startTime 不匹配
+ prizeDrawMapper.insert(cloneIgnoreId(dbPrizeDraw, o -> o.setStartTime(null)));
+ // 测试 endTime 不匹配
+ prizeDrawMapper.insert(cloneIgnoreId(dbPrizeDraw, o -> o.setEndTime(null)));
+ // 测试 mebLevel 不匹配
+ prizeDrawMapper.insert(cloneIgnoreId(dbPrizeDraw, o -> o.setMebLevel(null)));
+ // 测试 createTime 不匹配
+ prizeDrawMapper.insert(cloneIgnoreId(dbPrizeDraw, o -> o.setCreateTime(null)));
+ // 准备参数
+ PrizeDrawPageReqVO reqVO = new PrizeDrawPageReqVO();
+ reqVO.setName(null);
+ reqVO.setActivityRule(null);
+ reqVO.setStatus(null);
+ reqVO.setStartTime(buildBetweenTime(2023, 2, 1, 2023, 2, 28));
+ reqVO.setEndTime(buildBetweenTime(2023, 2, 1, 2023, 2, 28));
+ reqVO.setMebLevel(null);
+ reqVO.setCreateTime(buildBetweenTime(2023, 2, 1, 2023, 2, 28));
+
+ // 调用
+ PageResult pageResult = prizeDrawService.getPrizeDrawPage(reqVO);
+ // 断言
+ assertEquals(1, pageResult.getTotal());
+ assertEquals(1, pageResult.getList().size());
+ assertPojoEquals(dbPrizeDraw, pageResult.getList().get(0));
+ }
+
+}
\ No newline at end of file
diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/test/java/cn/iocoder/yudao/module/promotion/service/prizelog/PrizeLogServiceImplTest.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/test/java/cn/iocoder/yudao/module/promotion/service/prizelog/PrizeLogServiceImplTest.java
new file mode 100644
index 0000000..4f94756
--- /dev/null
+++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/test/java/cn/iocoder/yudao/module/promotion/service/prizelog/PrizeLogServiceImplTest.java
@@ -0,0 +1,162 @@
+package cn.iocoder.yudao.module.promotion.service.prizelog;
+
+import org.junit.jupiter.api.Disabled;
+import org.junit.jupiter.api.Test;
+import org.springframework.boot.test.mock.mockito.MockBean;
+
+import javax.annotation.Resource;
+
+import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
+
+import cn.iocoder.yudao.module.promotion.controller.admin.prizelog.vo.*;
+import cn.iocoder.yudao.module.promotion.dal.dataobject.prizelog.PrizeLogDO;
+import cn.iocoder.yudao.module.promotion.dal.mysql.prizelog.PrizeLogMapper;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+
+import javax.annotation.Resource;
+import org.springframework.context.annotation.Import;
+import java.util.*;
+import java.time.LocalDateTime;
+
+import static cn.hutool.core.util.RandomUtil.*;
+import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.*;
+import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.*;
+import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*;
+import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.*;
+import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.*;
+import static cn.iocoder.yudao.framework.common.util.date.DateUtils.*;
+import static org.junit.jupiter.api.Assertions.*;
+import static org.mockito.Mockito.*;
+
+/**
+ * {@link PrizeLogServiceImpl} 的单元测试类
+ *
+ * @author 芋道源码
+ */
+@Import(PrizeLogServiceImpl.class)
+public class PrizeLogServiceImplTest extends BaseDbUnitTest {
+
+ @Resource
+ private PrizeLogServiceImpl prizeLogService;
+
+ @Resource
+ private PrizeLogMapper prizeLogMapper;
+
+ @Test
+ public void testCreatePrizeLog_success() {
+ // 准备参数
+ PrizeLogSaveReqVO createReqVO = randomPojo(PrizeLogSaveReqVO.class).setId(null);
+
+ // 调用
+ Long prizeLogId = prizeLogService.createPrizeLog(createReqVO);
+ // 断言
+ assertNotNull(prizeLogId);
+ // 校验记录的属性是否正确
+ PrizeLogDO prizeLog = prizeLogMapper.selectById(prizeLogId);
+ assertPojoEquals(createReqVO, prizeLog, "id");
+ }
+
+ @Test
+ public void testUpdatePrizeLog_success() {
+ // mock 数据
+ PrizeLogDO dbPrizeLog = randomPojo(PrizeLogDO.class);
+ prizeLogMapper.insert(dbPrizeLog);// @Sql: 先插入出一条存在的数据
+ // 准备参数
+ PrizeLogSaveReqVO updateReqVO = randomPojo(PrizeLogSaveReqVO.class, o -> {
+ o.setId(dbPrizeLog.getId()); // 设置更新的 ID
+ });
+
+ // 调用
+ prizeLogService.updatePrizeLog(updateReqVO);
+ // 校验是否更新正确
+ PrizeLogDO prizeLog = prizeLogMapper.selectById(updateReqVO.getId()); // 获取最新的
+ assertPojoEquals(updateReqVO, prizeLog);
+ }
+
+ @Test
+ public void testUpdatePrizeLog_notExists() {
+ // 准备参数
+ PrizeLogSaveReqVO updateReqVO = randomPojo(PrizeLogSaveReqVO.class);
+
+ // 调用, 并断言异常
+ assertServiceException(() -> prizeLogService.updatePrizeLog(updateReqVO), PRIZE_LOG_NOT_EXISTS);
+ }
+
+ @Test
+ public void testDeletePrizeLog_success() {
+ // mock 数据
+ PrizeLogDO dbPrizeLog = randomPojo(PrizeLogDO.class);
+ prizeLogMapper.insert(dbPrizeLog);// @Sql: 先插入出一条存在的数据
+ // 准备参数
+ Long id = dbPrizeLog.getId();
+
+ // 调用
+ prizeLogService.deletePrizeLog(id);
+ // 校验数据不存在了
+ assertNull(prizeLogMapper.selectById(id));
+ }
+
+ @Test
+ public void testDeletePrizeLog_notExists() {
+ // 准备参数
+ Long id = randomLongId();
+
+ // 调用, 并断言异常
+ assertServiceException(() -> prizeLogService.deletePrizeLog(id), PRIZE_LOG_NOT_EXISTS);
+ }
+
+ @Test
+ @Disabled // TODO 请修改 null 为需要的值,然后删除 @Disabled 注解
+ public void testGetPrizeLogPage() {
+ // mock 数据
+ PrizeLogDO dbPrizeLog = randomPojo(PrizeLogDO.class, o -> { // 等会查询到
+ o.setMebId(null);
+ o.setActivityId(null);
+ o.setName(null);
+ o.setImgUrl(null);
+ o.setWinNum(null);
+ o.setPrizeChance(null);
+ o.setPrizePoolAmount(null);
+ o.setStatus(null);
+ o.setCreateTime(null);
+ });
+ prizeLogMapper.insert(dbPrizeLog);
+ // 测试 mebId 不匹配
+ prizeLogMapper.insert(cloneIgnoreId(dbPrizeLog, o -> o.setMebId(null)));
+ // 测试 activityId 不匹配
+ prizeLogMapper.insert(cloneIgnoreId(dbPrizeLog, o -> o.setActivityId(null)));
+ // 测试 name 不匹配
+ prizeLogMapper.insert(cloneIgnoreId(dbPrizeLog, o -> o.setName(null)));
+ // 测试 imgUrl 不匹配
+ prizeLogMapper.insert(cloneIgnoreId(dbPrizeLog, o -> o.setImgUrl(null)));
+ // 测试 winNum 不匹配
+ prizeLogMapper.insert(cloneIgnoreId(dbPrizeLog, o -> o.setWinNum(null)));
+ // 测试 prizeChance 不匹配
+ prizeLogMapper.insert(cloneIgnoreId(dbPrizeLog, o -> o.setPrizeChance(null)));
+ // 测试 prizePoolAmount 不匹配
+ prizeLogMapper.insert(cloneIgnoreId(dbPrizeLog, o -> o.setPrizePoolAmount(null)));
+ // 测试 status 不匹配
+ prizeLogMapper.insert(cloneIgnoreId(dbPrizeLog, o -> o.setStatus(null)));
+ // 测试 createTime 不匹配
+ prizeLogMapper.insert(cloneIgnoreId(dbPrizeLog, o -> o.setCreateTime(null)));
+ // 准备参数
+ PrizeLogPageReqVO reqVO = new PrizeLogPageReqVO();
+ reqVO.setMebId(null);
+ reqVO.setActivityId(null);
+ reqVO.setName(null);
+ reqVO.setImgUrl(null);
+ reqVO.setWinNum(null);
+ reqVO.setPrizeChance(null);
+ reqVO.setPrizePoolAmount(null);
+ reqVO.setStatus(null);
+ reqVO.setCreateTime(buildBetweenTime(2023, 2, 1, 2023, 2, 28));
+
+ // 调用
+ PageResult pageResult = prizeLogService.getPrizeLogPage(reqVO);
+ // 断言
+ assertEquals(1, pageResult.getTotal());
+ assertEquals(1, pageResult.getList().size());
+ assertPojoEquals(dbPrizeLog, pageResult.getList().get(0));
+ }
+
+}
\ No newline at end of file
diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/test/resources/sql/clean.sql b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/test/resources/sql/clean.sql
index 6a1a242..993e5d7 100644
--- a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/test/resources/sql/clean.sql
+++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/test/resources/sql/clean.sql
@@ -9,4 +9,6 @@ DELETE FROM "promotion_combination_activity";
DELETE FROM "promotion_article_category";
DELETE FROM "promotion_article";
DELETE FROM "promotion_diy_template";
-DELETE FROM "promotion_diy_page";
\ No newline at end of file
+DELETE FROM "promotion_diy_page";
+DELETE FROM "promotion_prize_draw";
+DELETE FROM "promotion_prize_log";
diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/test/resources/sql/create_tables.sql b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/test/resources/sql/create_tables.sql
index 00ac3f9..6227cb4 100644
--- a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/test/resources/sql/create_tables.sql
+++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/test/resources/sql/create_tables.sql
@@ -253,4 +253,39 @@ CREATE TABLE IF NOT EXISTS "promotion_diy_page"
"deleted" bit NOT NULL DEFAULT FALSE,
"tenant_id" bigint NOT NULL,
PRIMARY KEY ("id")
-) COMMENT '装修页面';
\ No newline at end of file
+) COMMENT '装修页面';
+CREATE TABLE IF NOT EXISTS "promotion_prize_draw" (
+ "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY,
+ "name" varchar,
+ "activity_rule" varchar,
+ "status" varchar,
+ "start_time" varchar,
+ "end_time" varchar,
+ "meb_level" int,
+ "creator" varchar DEFAULT '',
+ "create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "updater" varchar DEFAULT '',
+ "update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+ "deleted" bit NOT NULL DEFAULT FALSE,
+ "tenant_id" bigint NOT NULL,
+ PRIMARY KEY ("id")
+ ) COMMENT '抽奖活动';
+
+CREATE TABLE IF NOT EXISTS "promotion_prize_log" (
+ "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY,
+ "meb_id" bigint,
+ "activity_id" bigint,
+ "name" varchar,
+ "img_url" varchar,
+ "win_num" int,
+ "prize_chance" varchar,
+ "prize_pool_amount" varchar,
+ "status" varchar,
+ "creator" varchar DEFAULT '',
+ "create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "updater" varchar DEFAULT '',
+ "update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+ "deleted" bit NOT NULL DEFAULT FALSE,
+ "tenant_id" bigint NOT NULL,
+ PRIMARY KEY ("id")
+ ) COMMENT '抽奖记录表';
diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/order/TradeOrderController.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/order/TradeOrderController.java
index 58acde4..9c9b973 100644
--- a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/order/TradeOrderController.java
+++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/order/TradeOrderController.java
@@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.trade.controller.admin.order;
import cn.hutool.core.collection.CollUtil;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.security.core.LoginUser;
import cn.iocoder.yudao.module.member.api.user.MemberUserApi;
import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO;
import cn.iocoder.yudao.module.trade.controller.admin.order.vo.*;
@@ -31,6 +32,7 @@ import java.util.Set;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
+import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.*;
@Tag(name = "管理后台 - 交易订单")
@RestController
@@ -153,7 +155,10 @@ public class TradeOrderController {
@Parameter(name = "pickUpVerifyCode", description = "自提核销码")
@PreAuthorize("@ss.hasPermission('trade:order:pick-up')")
public CommonResult pickUpOrderByVerifyCode(@RequestParam("pickUpVerifyCode") String pickUpVerifyCode) {
- tradeOrderUpdateService.pickUpOrderByAdmin(pickUpVerifyCode);
+ // 根据管理系统登录用户信息获取APP系统用户信息
+ String mobile = getLoginUserMobile();
+ MemberUserRespDTO userByMobile = memberUserApi.getUserByMobile(mobile);
+ tradeOrderUpdateService.pickUpOrderByAdmin(userByMobile.getId(),pickUpVerifyCode);
return success(true);
}
diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/AppTradeOrderController.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/AppTradeOrderController.java
index 762b238..6c8b745 100644
--- a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/AppTradeOrderController.java
+++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/AppTradeOrderController.java
@@ -2,7 +2,9 @@ package cn.iocoder.yudao.module.trade.controller.app.order;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.security.core.LoginUser;
import cn.iocoder.yudao.framework.security.core.annotations.PreAuthenticated;
+import cn.iocoder.yudao.module.member.api.user.MemberUserApi;
import cn.iocoder.yudao.module.pay.api.notify.dto.PayOrderNotifyReqDTO;
import cn.iocoder.yudao.module.trade.controller.app.order.vo.*;
import cn.iocoder.yudao.module.trade.controller.app.order.vo.item.AppTradeOrderItemCommentCreateReqVO;
@@ -17,6 +19,7 @@ import cn.iocoder.yudao.module.trade.service.aftersale.AfterSaleService;
import cn.iocoder.yudao.module.trade.service.delivery.DeliveryExpressService;
import cn.iocoder.yudao.module.trade.service.order.TradeOrderQueryService;
import cn.iocoder.yudao.module.trade.service.order.TradeOrderUpdateService;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.google.common.collect.Maps;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
@@ -32,6 +35,7 @@ import java.util.Map;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
+import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUser;
import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
@Tag(name = "用户 App - 交易订单")
@@ -54,6 +58,9 @@ public class AppTradeOrderController {
@Resource
private TradeOrderProperties tradeOrderProperties;
+ @Resource
+ private MemberUserApi memberUserApi;
+
@GetMapping("/settlement")
@Operation(summary = "获得订单结算信息")
@PreAuthenticated
@@ -65,6 +72,9 @@ public class AppTradeOrderController {
@Operation(summary = "创建订单")
@PreAuthenticated
public CommonResult createOrder(@Valid @RequestBody AppTradeOrderCreateReqVO createReqVO) {
+ LoginUser loginUser = getLoginUser();
+ createReqVO.setReceiverName(loginUser.getInfo().getOrDefault("nickname",""));
+ createReqVO.setReceiverMobile(loginUser.getInfo().getOrDefault("mobile",""));
TradeOrderDO order = tradeOrderUpdateService.createOrder(getLoginUserId(), createReqVO);
return success(new AppTradeOrderCreateRespVO().setId(order.getId()).setPayOrderId(order.getPayOrderId()));
}
@@ -74,6 +84,8 @@ public class AppTradeOrderController {
public CommonResult updateOrderPaid(@RequestBody PayOrderNotifyReqDTO notifyReqDTO) {
tradeOrderUpdateService.updateOrderPaid(Long.valueOf(notifyReqDTO.getMerchantOrderId()),
notifyReqDTO.getPayOrderId());
+// memberUserApi.updateUserUpgradesLevel();
+
return success(true);
}
@@ -116,6 +128,13 @@ public class AppTradeOrderController {
return success(TradeOrderConvert.INSTANCE.convertPage02(pageResult, orderItems));
}
+ @GetMapping("/getPickUpVerifyCode")
+ @Operation(summary = "根据订单id获取自提核销码")
+ public CommonResult getPickUpVerifyCode(String id) {
+ String pickUpVerifyCode = tradeOrderQueryService.getPickUpVerifyCode(id);
+ return success(pickUpVerifyCode);
+ }
+
@GetMapping("/get-count")
@Operation(summary = "获得交易订单数量")
public CommonResult