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