xingqq 4 months ago
commit 535d9f9079

@ -144,6 +144,26 @@
<artifactId>spring-boot-starter-test</artifactId> <artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency>
<groupId>com.google.zxing</groupId>
<artifactId>core</artifactId>
<version>3.4.1</version>
</dependency>
<dependency>
<groupId>com.google.zxing</groupId>
<artifactId>javase</artifactId>
<version>3.4.1</version>
</dependency>
</dependencies> </dependencies>
</project> </project>

@ -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;
}
}
}

@ -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<EncodeHintType, String> hints = new HashMap<EncodeHintType, String>();
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<DecodeHintType, String> hints = new HashMap<DecodeHintType, String>();
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;
}
}

@ -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;*/
}

@ -19,6 +19,7 @@ public class LoginUser {
public static final String INFO_KEY_NICKNAME = "nickname"; public static final String INFO_KEY_NICKNAME = "nickname";
public static final String INFO_KEY_DEPT_ID = "deptId"; public static final String INFO_KEY_DEPT_ID = "deptId";
public static final String INFO_KEY_MOBILE = "mobile";
/** /**
* *

@ -112,6 +112,17 @@ public class SecurityFrameworkUtils {
return loginUser != null ? MapUtil.getLong(loginUser.getInfo(), LoginUser.INFO_KEY_DEPT_ID) : null; 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;
}
/** /**
* *
* *

@ -124,6 +124,12 @@
<groupId>org.apache.tika</groupId> <groupId>org.apache.tika</groupId>
<artifactId>tika-core</artifactId> <!-- 文件客户端:文件类型的识别 --> <artifactId>tika-core</artifactId> <!-- 文件客户端:文件类型的识别 -->
</dependency> </dependency>
<dependency>
<groupId>cn.iocoder.boot</groupId>
<artifactId>yudao-module-system-biz</artifactId>
<version>2.1.0-jdk8-snapshot</version>
<scope>compile</scope>
</dependency>
</dependencies> </dependencies>

@ -1,21 +1,36 @@
package cn.iocoder.yudao.module.infra.controller.app.file; 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.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.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.controller.app.file.vo.AppFileUploadReqVO;
import cn.iocoder.yudao.module.infra.service.file.FileService; 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.Operation;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.annotation.Validated; 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.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource; 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.common.pojo.CommonResult.success;
import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
@Tag(name = "用户 App - 文件存储") @Tag(name = "用户 App - 文件存储")
@RestController @RestController
@ -27,6 +42,9 @@ public class AppFileController {
@Resource @Resource
private FileService fileService; private FileService fileService;
@Resource
private DictDataService dictDataService;
@PostMapping("/upload") @PostMapping("/upload")
@Operation(summary = "上传文件") @Operation(summary = "上传文件")
public CommonResult<String> uploadFile(AppFileUploadReqVO uploadReqVO) throws Exception { public CommonResult<String> uploadFile(AppFileUploadReqVO uploadReqVO) throws Exception {
@ -35,4 +53,75 @@ public class AppFileController {
return success(fileService.createFile(file.getOriginalFilename(), path, IoUtil.readBytes(file.getInputStream()))); return success(fileService.createFile(file.getOriginalFilename(), path, IoUtil.readBytes(file.getInputStream())));
} }
@RequestMapping("/qrCode")
@Operation(summary = "生成二维码")
public CommonResult<String> 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<String> 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<String> qrCode64Url(@Valid String type) {
// 创建文件使用PNG扩展名因为QR码是以PNG格式生成的
return success( getString(type));
}
private String getString(String type) {
String replace=null;
List<DictDataDO> 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;
}
} }

@ -124,5 +124,11 @@ public interface ErrorCodeConstants {
// ========== 装修页面 1-013-018-000 ========== // ========== 装修页面 1-013-018-000 ==========
ErrorCode DIY_PAGE_NOT_EXISTS = new ErrorCode(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 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, "分销等级不在权限范围");
} }

@ -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<Long> createPrizeDraw(@Valid @RequestBody PrizeDrawSaveReqVO createReqVO) {
return success(prizeDrawService.createPrizeDraw(createReqVO));
}
@PutMapping("/update")
@Operation(summary = "更新抽奖活动")
@PreAuthorize("@ss.hasPermission('promotion:prize-draw:update')")
public CommonResult<Boolean> 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<Boolean> 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<PrizeDrawRespVO> 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<PageResult<PrizeDrawRespVO>> getPrizeDrawPage(@Valid PrizeDrawPageReqVO pageReqVO) {
PageResult<PrizeDrawDO> pageResult = prizeDrawService.getPrizeDrawPage(pageReqVO);
// 处理用户级别返显
List<MemberLevelRespDTO> 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<PrizeDrawDO> 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<List<ActivityPrizeDO>> getActivityPrizeListByActivityId(@RequestParam("activityId") Long activityId) {
return success(prizeDrawService.getActivityPrizeListByActivityId(activityId));
}
}

@ -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;
}

@ -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;
}

@ -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<ActivityPrizeDO> activityPrizes;
}

@ -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<Long> createPrizeLog(@Valid @RequestBody PrizeLogSaveReqVO createReqVO) {
return success(prizeLogService.createPrizeLog(createReqVO));
}
@PutMapping("/update")
@Operation(summary = "更新抽奖记录")
@PreAuthorize("@ss.hasPermission('promotion:prize-log:update')")
public CommonResult<Boolean> 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<Boolean> 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<PrizeLogRespVO> 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<PageResult<PrizeLogRespVO>> getPrizeLogPage(@Valid PrizeLogPageReqVO pageReqVO) {
PageResult<PrizeLogDO> pageResult = prizeLogService.getPrizeLogPage(pageReqVO);
// 拼接用户数据
Map<Long, MemberUserRespDTO> userMap = memberUserApi.getUserMap(
convertSet(pageResult.getList(), PrizeLogDO::getMebId));
// 拼接活动数据
Map<Long, PrizeDrawDO> 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<PrizeLogDO> list = prizeLogService.getPrizeLogPage(pageReqVO).getList();
// 导出 Excel
ExcelUtils.write(response, "抽奖记录.xls", "数据", PrizeLogRespVO.class,
BeanUtils.toBean(list, PrizeLogRespVO.class));
}
}

@ -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;
}

@ -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;
}

@ -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;
}

@ -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<AppPrizeDrawRespVO> 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<List<ActivityPrizeDO>> getActivityPrizeListByActivityId(@RequestParam("activityId") Long activityId) {
return success(prizeDrawService.getActivityPrizeListByActivityId(activityId));
}
@GetMapping("/lottery")
@Operation(summary = "用户APP--抽奖")
@Parameter(name = "activityId", description = "关联抽奖活动id")
public CommonResult<ActivityPrizeDO> 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()<activityLevel.getLevel()){
throw exception(PRIZE_LOG_NOT_LEVEL);
}
//判断参与次数
Long drawNum = prizeLogService.getPrizeLogByMebIdList(loginUserId, prizeDraw);
if(drawNum>=prizeDraw.getDrawNum()){
throw exception(PRIZE_LOG_NOT_DRAWNUM);
}
//抽奖
ActivityPrizeDO activityPrizeDO = recursionLottery(prizeDraw);
return success(activityPrizeDO);
}
private ActivityPrizeDO recursionLottery(PrizeDrawDO prizeDraw){
//获取奖品信息
List<ActivityPrizeDO> list = prizeDrawService.getActivityPrizeListByActivityId(prizeDraw.getId());
//获取随机数
int sortNum = (int) (Math.random() * ((8-list.size()) + 1));
// TODO: 2023/8/16 0016 后台限制
List<WeightRandom.WeightObj<String>> weightObjList = new ArrayList<WeightRandom.WeightObj<String>>();
list.forEach(s -> {
weightObjList.add(new WeightRandom.WeightObj<>(s.getId().toString(), Double.valueOf(s.getPrizeChance())));
});
WeightRandom<String> 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<List<PrizeLogRespVO>> getPrizeLogPage(@RequestParam("activityId") Long activityId) {
//获取活动信息
PrizeDrawDO prizeDraw = prizeDrawService.getPrizeDraw(activityId);
List<PrizeLogDO> list = prizeLogService.getPrizeLogListByMebId(getLoginUserId(), prizeDraw);
return success(BeanUtils.toBean(list, PrizeLogRespVO.class));
}
}

@ -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;
}

@ -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;
}

@ -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<ActivityPrizeDO> activityPrizes;
}

@ -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<PrizeDrawRespVO> convertPage(PageResult<PrizeDrawDO> page,
List<MemberLevelRespDTO> levels) {
PageResult<PrizeDrawRespVO> pageResult = convertPage(page);
Map<Long, String> 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<PrizeDrawRespVO> convertPage(PageResult<PrizeDrawDO> page);
}

@ -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<PrizeLogRespVO> convertPage(PageResult<PrizeLogDO> page,
Map<Long, MemberUserRespDTO> userMap,
Map<Long, PrizeDrawDO> prizeMap) {
PageResult<PrizeLogRespVO> 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<PrizeLogRespVO> convertPage(PageResult<PrizeLogDO> page);
}

@ -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;
}

@ -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;
/**
* 01
*/
private String status;
/**
*
*/
private LocalDateTime startTime;
/**
*
*/
private LocalDateTime endTime;
/**
*
*/
private Long mebLevel;
/**
*
*/
private Integer drawNum;
}

@ -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;
/**
* 01
*/
private String status;
}

@ -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<ActivityPrizeDO> {
default List<ActivityPrizeDO> selectListByActivityId(Long activityId) {
return selectList(ActivityPrizeDO::getActivityId, activityId);
}
default int deleteByActivityId(Long activityId) {
return delete(ActivityPrizeDO::getActivityId, activityId);
}
}

@ -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<PrizeDrawDO> {
default PageResult<PrizeDrawDO> selectPage(PrizeDrawPageReqVO reqVO) {
return selectPage(reqVO, new LambdaQueryWrapperX<PrizeDrawDO>()
.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));
}
}

@ -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<PrizeLogDO> {
default PageResult<PrizeLogDO> selectPage(PrizeLogPageReqVO reqVO) {
return selectPage(reqVO, new LambdaQueryWrapperX<PrizeLogDO>()
.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));
}
}

@ -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<PrizeDrawDO> getPrizeDrawPage(PrizeDrawPageReqVO pageReqVO);
// ==================== 子表(抽奖活动奖品) ====================
/**
*
*
* @param activityId id
* @return
*/
List<ActivityPrizeDO> getActivityPrizeListByActivityId(Long activityId);
/**
*
*
* @param id id
* @return
*/
ActivityPrizeDO getActivityPrize(Long id);
/**
*
*
* @return
*/
PrizeDrawDO getOnePrizeDraw();
/**
* Map
*
* @param ids id
* @return Map
*/
default Map<Long, PrizeDrawDO> getPrizeDrawMap(Collection<Long> ids) {
List<PrizeDrawDO> list = getPrizeDrawDOList(ids);
return convertMap(list, PrizeDrawDO::getId);
}
/**
*
*
* @param ids
* @return
*/
List<PrizeDrawDO> getPrizeDrawDOList(Collection<Long> ids);
}

@ -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<PrizeDrawDO> getPrizeDrawPage(PrizeDrawPageReqVO pageReqVO) {
return prizeDrawMapper.selectPage(pageReqVO);
}
// ==================== 子表(抽奖活动奖品) ====================
@Override
public List<ActivityPrizeDO> getActivityPrizeListByActivityId(Long activityId) {
return activityPrizeMapper.selectListByActivityId(activityId);
}
private void createActivityPrizeList(Long activityId, List<ActivityPrizeDO> list) {
list.forEach(o -> o.setActivityId(activityId));
activityPrizeMapper.insertBatch(list);
}
private void updateActivityPrizeList(Long activityId, List<ActivityPrizeDO> list) {
deleteActivityPrizeByActivityId(activityId);
list.forEach(o -> o.setId(null).setUpdater(null).setUpdateTime(null)); // 解决更新情况下1id 冲突2updateTime 不更新
createActivityPrizeList(activityId, list);
}
private void deleteActivityPrizeByActivityId(Long activityId) {
activityPrizeMapper.deleteByActivityId(activityId);
}
@Override
public PrizeDrawDO getOnePrizeDraw() {
return prizeDrawMapper.selectOne(new LambdaQueryWrapperX<PrizeDrawDO>()
.eq(PrizeDrawDO::getStatus, 0)
);
}
@Override
public List<PrizeDrawDO> getPrizeDrawDOList(Collection<Long> ids) {
if (CollUtil.isEmpty(ids)) {
return ListUtil.empty();
}
return prizeDrawMapper.selectBatchIds(ids);
}
@Override
public ActivityPrizeDO getActivityPrize(Long id) {
return activityPrizeMapper.selectById(id);
}
}

@ -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<PrizeLogDO> 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<PrizeLogDO> getPrizeLogListByMebId(Long mebId,PrizeDrawDO prizeDraw);
}

@ -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<PrizeLogDO> getPrizeLogPage(PrizeLogPageReqVO pageReqVO) {
return prizeLogMapper.selectPage(pageReqVO);
}
@Override
public Long getPrizeLogByMebIdList(Long mebId,PrizeDrawDO prizeDraw) {
return prizeLogMapper.selectCount(new LambdaQueryWrapperX<PrizeLogDO>()
.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<PrizeLogDO>()
.eq(PrizeLogDO::getPrizeId,prizeId)
.ge(PrizeLogDO::getCreateTime, prizeDraw.getStartTime())
.le(PrizeLogDO::getCreateTime, prizeDraw.getEndTime())
);
}
@Override
public List<PrizeLogDO> getPrizeLogListByMebId(Long mebId,PrizeDrawDO prizeDraw) {
return prizeLogMapper.selectList(new LambdaQueryWrapperX<PrizeLogDO>()
.eq(PrizeLogDO::getMebId, mebId)
.ge(PrizeLogDO::getCreateTime, prizeDraw.getStartTime())
.le(PrizeLogDO::getCreateTime, prizeDraw.getEndTime())
);
}
}

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.iocoder.yudao.module.promotion.dal.mysql.prizedraw.PrizeDrawMapper">
<!--
一般情况下,尽可能使用 Mapper 进行 CRUD 增删改查即可。
无法满足的场景,例如说多表关联查询,才使用 XML 编写 SQL。
代码生成器暂时只生成 Mapper XML 文件本身,更多推荐 MybatisX 快速开发插件来生成查询。
文档可见https://www.iocoder.cn/MyBatis/x-plugins/
-->
</mapper>

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.iocoder.yudao.module.promotion.dal.mysql.prizelog.PrizeLogMapper">
<!--
一般情况下,尽可能使用 Mapper 进行 CRUD 增删改查即可。
无法满足的场景,例如说多表关联查询,才使用 XML 编写 SQL。
代码生成器暂时只生成 Mapper XML 文件本身,更多推荐 MybatisX 快速开发插件来生成查询。
文档可见https://www.iocoder.cn/MyBatis/x-plugins/
-->
</mapper>

@ -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<PrizeDrawDO> pageResult = prizeDrawService.getPrizeDrawPage(reqVO);
// 断言
assertEquals(1, pageResult.getTotal());
assertEquals(1, pageResult.getList().size());
assertPojoEquals(dbPrizeDraw, pageResult.getList().get(0));
}
}

@ -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<PrizeLogDO> pageResult = prizeLogService.getPrizeLogPage(reqVO);
// 断言
assertEquals(1, pageResult.getTotal());
assertEquals(1, pageResult.getList().size());
assertPojoEquals(dbPrizeLog, pageResult.getList().get(0));
}
}

@ -10,3 +10,5 @@ DELETE FROM "promotion_article_category";
DELETE FROM "promotion_article"; DELETE FROM "promotion_article";
DELETE FROM "promotion_diy_template"; DELETE FROM "promotion_diy_template";
DELETE FROM "promotion_diy_page"; DELETE FROM "promotion_diy_page";
DELETE FROM "promotion_prize_draw";
DELETE FROM "promotion_prize_log";

@ -254,3 +254,38 @@ CREATE TABLE IF NOT EXISTS "promotion_diy_page"
"tenant_id" bigint NOT NULL, "tenant_id" bigint NOT NULL,
PRIMARY KEY ("id") PRIMARY KEY ("id")
) COMMENT '装修页面'; ) 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 '抽奖记录表';

@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.trade.controller.admin.order;
import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.CollUtil;
import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageResult; 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.MemberUserApi;
import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO; import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO;
import cn.iocoder.yudao.module.trade.controller.admin.order.vo.*; 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.pojo.CommonResult.success;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; 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.common.util.collection.CollectionUtils.convertSet;
import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.*;
@Tag(name = "管理后台 - 交易订单") @Tag(name = "管理后台 - 交易订单")
@RestController @RestController
@ -153,7 +155,10 @@ public class TradeOrderController {
@Parameter(name = "pickUpVerifyCode", description = "自提核销码") @Parameter(name = "pickUpVerifyCode", description = "自提核销码")
@PreAuthorize("@ss.hasPermission('trade:order:pick-up')") @PreAuthorize("@ss.hasPermission('trade:order:pick-up')")
public CommonResult<Boolean> pickUpOrderByVerifyCode(@RequestParam("pickUpVerifyCode") String pickUpVerifyCode) { public CommonResult<Boolean> 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); return success(true);
} }

@ -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.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageResult; 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.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.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.*;
import cn.iocoder.yudao.module.trade.controller.app.order.vo.item.AppTradeOrderItemCommentCreateReqVO; 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.delivery.DeliveryExpressService;
import cn.iocoder.yudao.module.trade.service.order.TradeOrderQueryService; import cn.iocoder.yudao.module.trade.service.order.TradeOrderQueryService;
import cn.iocoder.yudao.module.trade.service.order.TradeOrderUpdateService; import cn.iocoder.yudao.module.trade.service.order.TradeOrderUpdateService;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.google.common.collect.Maps; import com.google.common.collect.Maps;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter; 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.pojo.CommonResult.success;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; 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; import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
@Tag(name = "用户 App - 交易订单") @Tag(name = "用户 App - 交易订单")
@ -54,6 +58,9 @@ public class AppTradeOrderController {
@Resource @Resource
private TradeOrderProperties tradeOrderProperties; private TradeOrderProperties tradeOrderProperties;
@Resource
private MemberUserApi memberUserApi;
@GetMapping("/settlement") @GetMapping("/settlement")
@Operation(summary = "获得订单结算信息") @Operation(summary = "获得订单结算信息")
@PreAuthenticated @PreAuthenticated
@ -65,6 +72,9 @@ public class AppTradeOrderController {
@Operation(summary = "创建订单") @Operation(summary = "创建订单")
@PreAuthenticated @PreAuthenticated
public CommonResult<AppTradeOrderCreateRespVO> createOrder(@Valid @RequestBody AppTradeOrderCreateReqVO createReqVO) { public CommonResult<AppTradeOrderCreateRespVO> 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); TradeOrderDO order = tradeOrderUpdateService.createOrder(getLoginUserId(), createReqVO);
return success(new AppTradeOrderCreateRespVO().setId(order.getId()).setPayOrderId(order.getPayOrderId())); return success(new AppTradeOrderCreateRespVO().setId(order.getId()).setPayOrderId(order.getPayOrderId()));
} }
@ -74,6 +84,8 @@ public class AppTradeOrderController {
public CommonResult<Boolean> updateOrderPaid(@RequestBody PayOrderNotifyReqDTO notifyReqDTO) { public CommonResult<Boolean> updateOrderPaid(@RequestBody PayOrderNotifyReqDTO notifyReqDTO) {
tradeOrderUpdateService.updateOrderPaid(Long.valueOf(notifyReqDTO.getMerchantOrderId()), tradeOrderUpdateService.updateOrderPaid(Long.valueOf(notifyReqDTO.getMerchantOrderId()),
notifyReqDTO.getPayOrderId()); notifyReqDTO.getPayOrderId());
// memberUserApi.updateUserUpgradesLevel();
return success(true); return success(true);
} }
@ -116,6 +128,13 @@ public class AppTradeOrderController {
return success(TradeOrderConvert.INSTANCE.convertPage02(pageResult, orderItems)); return success(TradeOrderConvert.INSTANCE.convertPage02(pageResult, orderItems));
} }
@GetMapping("/getPickUpVerifyCode")
@Operation(summary = "根据订单id获取自提核销码")
public CommonResult<String> getPickUpVerifyCode(String id) {
String pickUpVerifyCode = tradeOrderQueryService.getPickUpVerifyCode(id);
return success(pickUpVerifyCode);
}
@GetMapping("/get-count") @GetMapping("/get-count")
@Operation(summary = "获得交易订单数量") @Operation(summary = "获得交易订单数量")
public CommonResult<Map<String, Long>> getOrderCount() { public CommonResult<Map<String, Long>> getOrderCount() {

@ -1,6 +1,7 @@
package cn.iocoder.yudao.module.trade.controller.app.order.vo; package cn.iocoder.yudao.module.trade.controller.app.order.vo;
import cn.iocoder.yudao.module.trade.controller.app.order.vo.item.AppTradeOrderItemRespVO; import cn.iocoder.yudao.module.trade.controller.app.order.vo.item.AppTradeOrderItemRespVO;
import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryPickUpStoreDO;
import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data; import lombok.Data;
@ -45,6 +46,19 @@ public class AppTradeOrderPageItemRespVO {
@Schema(description = "配送方式", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") @Schema(description = "配送方式", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
private Integer deliveryType; private Integer deliveryType;
/**
*
*
* {@link DeliveryPickUpStoreDO#getId()}
*/
@Schema(description = "核销单位id", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
private Long pickUpStoreId;
/**
*
*/
@Schema(description = "核销码", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
private String pickUpVerifyCode;
/** /**
* *
*/ */

@ -59,4 +59,8 @@ public class BrokerageUserDO extends BaseDO {
* *
*/ */
private Integer frozenPrice; private Integer frozenPrice;
/**
*
*/
private Integer level;
} }

@ -130,6 +130,7 @@ public class TradeOrderItemDO extends BaseDO {
*/ */
private Integer payPrice; private Integer payPrice;
// ========== 营销基本信息 ========== // ========== 营销基本信息 ==========
/** /**

@ -53,6 +53,20 @@ public interface BrokerageUserMapper extends BaseMapperX<BrokerageUserDO> {
update(null, lambdaUpdateWrapper); update(null, lambdaUpdateWrapper);
} }
/**
*
*
* @param id
* @param incrCount
*/
default void updateUserPriceByBindUserIdIncr(Long id, Integer incrCount) {
Assert.isTrue(incrCount > 0);
LambdaUpdateWrapper<BrokerageUserDO> lambdaUpdateWrapper = new LambdaUpdateWrapper<BrokerageUserDO>()
.setSql(" brokerage_price = brokerage_price + " + incrCount)
.eq(BrokerageUserDO::getBindUserId, id);
update(null, lambdaUpdateWrapper);
}
/** /**
* *
* *
@ -69,6 +83,22 @@ public interface BrokerageUserMapper extends BaseMapperX<BrokerageUserDO> {
return update(null, lambdaUpdateWrapper); return update(null, lambdaUpdateWrapper);
} }
/**
*
*
*
* @param id
* @param incrCount
* @return
*/
default int updateUserPriceByBindUserIdDecr(Long id, Integer incrCount) {
Assert.isTrue(incrCount < 0);
LambdaUpdateWrapper<BrokerageUserDO> lambdaUpdateWrapper = new LambdaUpdateWrapper<BrokerageUserDO>()
.setSql(" brokerage_price = brokerage_price + " + incrCount) // 负数,所以使用 + 号
.eq(BrokerageUserDO::getBindUserId, id);
return update(null, lambdaUpdateWrapper);
}
/** /**
* *
* *

@ -124,4 +124,7 @@ public interface TradeOrderMapper extends BaseMapperX<TradeOrderDO> {
); );
} }
default String getPickUpVerifyCode(String id){
return selectOne(TradeOrderDO::getId, id).getPickUpVerifyCode();
};
} }

@ -76,6 +76,16 @@ public interface BrokerageUserService {
*/ */
boolean updateUserPrice(Long id, Integer price); boolean updateUserPrice(Long id, Integer price);
/**
*
*
* @param id
* @param price
* @return
*/
boolean updateUserPriceByBindUserId(Long id, Integer price);
/** /**
* *
* *

@ -4,6 +4,7 @@ import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.Assert; import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.ArrayUtil; import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.BooleanUtil; import cn.hutool.core.util.BooleanUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils; import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils;
@ -137,6 +138,16 @@ public class BrokerageUserServiceImpl implements BrokerageUserService {
return true; return true;
} }
@Override
public boolean updateUserPriceByBindUserId(Long id, Integer price) {
if (price > 0) {
brokerageUserMapper.updateUserPriceByBindUserIdIncr(id, price);
} else if (price < 0) {
return brokerageUserMapper.updateUserPriceByBindUserIdDecr(id, price) > 0;
}
return true;
}
@Override @Override
public void updateUserFrozenPrice(Long id, Integer frozenPrice) { public void updateUserFrozenPrice(Long id, Integer frozenPrice) {
if (frozenPrice > 0) { if (frozenPrice > 0) {
@ -296,27 +307,29 @@ public class BrokerageUserServiceImpl implements BrokerageUserService {
private void validateCanBindUser(BrokerageUserDO user, Long bindUserId) { private void validateCanBindUser(BrokerageUserDO user, Long bindUserId) {
// 校验要绑定的用户有无推广资格 // 校验要绑定的用户有无推广资格
BrokerageUserDO bindUser = brokerageUserMapper.selectById(bindUserId); BrokerageUserDO bindUser = brokerageUserMapper.selectById(bindUserId);
if (bindUser == null || BooleanUtil.isFalse(bindUser.getBrokerageEnabled())) { /*if (bindUser == null || BooleanUtil.isFalse(bindUser.getBrokerageEnabled())) {
throw exception(BROKERAGE_BIND_USER_NOT_ENABLED); throw exception(BROKERAGE_BIND_USER_NOT_ENABLED);
} }*/
// 校验绑定自己 // 校验绑定自己
if (Objects.equals(user.getId(), bindUserId)) { /* if (Objects.equals(user.getId(), bindUserId)) {
throw exception(BROKERAGE_BIND_SELF); throw exception(BROKERAGE_BIND_SELF);
}*/
if(ObjectUtil.isNotEmpty(bindUser)){
// 下级不能绑定自己的上级
for (int i = 0; i <= Short.MAX_VALUE; i++) {
if (Objects.equals(bindUser.getBindUserId(), user.getId())) {
throw exception(BROKERAGE_BIND_LOOP);
} }
bindUser = getBrokerageUser(bindUser.getBindUserId());
// 下级不能绑定自己的上级 // 找到根节点,结束循环
for (int i = 0; i <= Short.MAX_VALUE; i++) { if (bindUser == null || bindUser.getBindUserId() == null) {
if (Objects.equals(bindUser.getBindUserId(), user.getId())) { break;
throw exception(BROKERAGE_BIND_LOOP);
}
bindUser = getBrokerageUser(bindUser.getBindUserId());
// 找到根节点,结束循环
if (bindUser == null || bindUser.getBindUserId() == null) {
break;
}
} }
} }
}
}
/** /**
* *

@ -155,4 +155,5 @@ public interface TradeOrderQueryService {
*/ */
List<TradeOrderItemDO> getOrderItemListByOrderId(Collection<Long> orderIds); List<TradeOrderItemDO> getOrderItemListByOrderId(Collection<Long> orderIds);
String getPickUpVerifyCode(String id);
} }

@ -248,6 +248,11 @@ public class TradeOrderQueryServiceImpl implements TradeOrderQueryService {
return tradeOrderItemMapper.selectListByOrderId(orderIds); return tradeOrderItemMapper.selectListByOrderId(orderIds);
} }
@Override
public String getPickUpVerifyCode(String id) {
return tradeOrderMapper.getPickUpVerifyCode(id);
}
/** /**
* AOP * AOP
* *

@ -126,8 +126,9 @@ public interface TradeOrderUpdateService {
* *
* *
* @param pickUpVerifyCode * @param pickUpVerifyCode
* @param id id
*/ */
void pickUpOrderByAdmin(String pickUpVerifyCode); void pickUpOrderByAdmin(Long id, String pickUpVerifyCode);
/** /**
* *

@ -40,6 +40,7 @@ import cn.iocoder.yudao.module.trade.enums.order.*;
import cn.iocoder.yudao.module.trade.framework.order.config.TradeOrderProperties; import cn.iocoder.yudao.module.trade.framework.order.config.TradeOrderProperties;
import cn.iocoder.yudao.module.trade.framework.order.core.annotations.TradeOrderLog; import cn.iocoder.yudao.module.trade.framework.order.core.annotations.TradeOrderLog;
import cn.iocoder.yudao.module.trade.framework.order.core.utils.TradeOrderLogUtils; import cn.iocoder.yudao.module.trade.framework.order.core.utils.TradeOrderLogUtils;
import cn.iocoder.yudao.module.trade.service.brokerage.BrokerageUserService;
import cn.iocoder.yudao.module.trade.service.cart.CartService; import cn.iocoder.yudao.module.trade.service.cart.CartService;
import cn.iocoder.yudao.module.trade.service.delivery.DeliveryExpressService; import cn.iocoder.yudao.module.trade.service.delivery.DeliveryExpressService;
import cn.iocoder.yudao.module.trade.service.message.TradeMessageService; import cn.iocoder.yudao.module.trade.service.message.TradeMessageService;
@ -107,6 +108,10 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
@Resource @Resource
private TradeOrderProperties tradeOrderProperties; private TradeOrderProperties tradeOrderProperties;
@Resource
private BrokerageUserService brokerageUserService;
// =================== Order =================== // =================== Order ===================
@Override @Override
@ -679,7 +684,8 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
@Override @Override
@TradeOrderLog(operateType = TradeOrderOperateTypeEnum.ADMIN_PICK_UP_RECEIVE) @TradeOrderLog(operateType = TradeOrderOperateTypeEnum.ADMIN_PICK_UP_RECEIVE)
public void pickUpOrderByAdmin(String pickUpVerifyCode) { public void pickUpOrderByAdmin(Long id, String pickUpVerifyCode) {
boolean b = brokerageUserService.updateUserPriceByBindUserId(id, 30);
getSelf().pickUpOrder(tradeOrderMapper.selectOneByPickUpVerifyCode(pickUpVerifyCode)); getSelf().pickUpOrder(tradeOrderMapper.selectOneByPickUpVerifyCode(pickUpVerifyCode));
} }

@ -3,6 +3,9 @@ package cn.iocoder.yudao.module.member.api.level;
import cn.iocoder.yudao.module.member.api.level.dto.MemberLevelRespDTO; import cn.iocoder.yudao.module.member.api.level.dto.MemberLevelRespDTO;
import cn.iocoder.yudao.module.member.enums.MemberExperienceBizTypeEnum; import cn.iocoder.yudao.module.member.enums.MemberExperienceBizTypeEnum;
import java.util.Collection;
import java.util.List;
/** /**
* API * API
* *
@ -38,4 +41,11 @@ public interface MemberLevelApi {
*/ */
void reduceExperience(Long userId, Integer experience, Integer bizType, String bizId); void reduceExperience(Long userId, Integer experience, Integer bizType, String bizId);
/**
*
*
* @param ids
* @return
*/
List<MemberLevelRespDTO> getLevelList(Collection<Long> ids);
} }

@ -57,4 +57,19 @@ public interface MemberUserApi {
* @return * @return
*/ */
MemberUserRespDTO getUserByMobile(String mobile); MemberUserRespDTO getUserByMobile(String mobile);
/**
*
*
* @param userId
* @return
*/
boolean updateUserLevelId(Long userId);
/**
* 1188
*
* @param userId
* @return
*/
void updateUserUpgradesLevel(Long userId);
} }

@ -85,6 +85,12 @@
<groupId>cn.iocoder.boot</groupId> <groupId>cn.iocoder.boot</groupId>
<artifactId>yudao-spring-boot-starter-biz-ip</artifactId> <artifactId>yudao-spring-boot-starter-biz-ip</artifactId>
</dependency> </dependency>
<dependency>
<groupId>cn.iocoder.boot</groupId>
<artifactId>yudao-module-trade-biz</artifactId>
<version>2.1.0-jdk8-snapshot</version>
<scope>compile</scope>
</dependency>
</dependencies> </dependencies>

@ -1,5 +1,6 @@
package cn.iocoder.yudao.module.member.api.level; package cn.iocoder.yudao.module.member.api.level;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.module.member.api.level.dto.MemberLevelRespDTO; import cn.iocoder.yudao.module.member.api.level.dto.MemberLevelRespDTO;
import cn.iocoder.yudao.module.member.convert.level.MemberLevelConvert; import cn.iocoder.yudao.module.member.convert.level.MemberLevelConvert;
import cn.iocoder.yudao.module.member.enums.MemberExperienceBizTypeEnum; import cn.iocoder.yudao.module.member.enums.MemberExperienceBizTypeEnum;
@ -9,6 +10,9 @@ import org.springframework.validation.annotation.Validated;
import javax.annotation.Resource; import javax.annotation.Resource;
import java.util.Collection;
import java.util.List;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.member.enums.ErrorCodeConstants.EXPERIENCE_BIZ_NOT_SUPPORT; import static cn.iocoder.yudao.module.member.enums.ErrorCodeConstants.EXPERIENCE_BIZ_NOT_SUPPORT;
@ -43,4 +47,9 @@ public class MemberLevelApiImpl implements MemberLevelApi {
addExperience(userId, -experience, bizType, bizId); addExperience(userId, -experience, bizType, bizId);
} }
@Override
public List<MemberLevelRespDTO> getLevelList(Collection<Long> ids) {
return BeanUtils.toBean(memberLevelService.getLevelList(ids),MemberLevelRespDTO.class);
}
} }

@ -44,4 +44,15 @@ public class MemberUserApiImpl implements MemberUserApi {
return MemberUserConvert.INSTANCE.convert2(userService.getUserByMobile(mobile)); return MemberUserConvert.INSTANCE.convert2(userService.getUserByMobile(mobile));
} }
@Override
public boolean updateUserLevelId(Long userId) {
return userService.updateUserLevelId(userId);
}
@Override
public void updateUserUpgradesLevel(Long userId) {
userService.updateUserUpgradesLevel(userId);
}
} }

@ -27,4 +27,9 @@ public class AppAuthWeixinMiniAppLoginReqVO {
@NotEmpty(message = "state 不能为空") @NotEmpty(message = "state 不能为空")
private String state; private String state;
@Schema(description = "bindUserId")
private Long bindUserId;
} }

@ -38,7 +38,9 @@ public class AppMemberUserController {
public CommonResult<AppMemberUserInfoRespVO> getUserInfo() { public CommonResult<AppMemberUserInfoRespVO> getUserInfo() {
MemberUserDO user = userService.getUser(getLoginUserId()); MemberUserDO user = userService.getUser(getLoginUserId());
MemberLevelDO level = levelService.getLevel(user.getLevelId()); MemberLevelDO level = levelService.getLevel(user.getLevelId());
return success(MemberUserConvert.INSTANCE.convert(user, level)); AppMemberUserInfoRespVO convert = MemberUserConvert.INSTANCE.convert(user, level);
convert.setId(getLoginUserId()+"");
return success(convert);
} }
@PutMapping("/update") @PutMapping("/update")

@ -10,6 +10,8 @@ import lombok.NoArgsConstructor;
@NoArgsConstructor @NoArgsConstructor
@AllArgsConstructor @AllArgsConstructor
public class AppMemberUserInfoRespVO { public class AppMemberUserInfoRespVO {
@Schema(description = "id")
private String id;
@Schema(description = "用户昵称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋艿") @Schema(description = "用户昵称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋艿")
private String nickname; private String nickname;

@ -29,6 +29,7 @@ public interface MemberUserConvert {
@Mapping(source = "level", target = "level") @Mapping(source = "level", target = "level")
@Mapping(source = "bean.experience", target = "experience") @Mapping(source = "bean.experience", target = "experience")
@Mapping(source = "bean.id",target = "id")
AppMemberUserInfoRespVO convert(MemberUserDO bean, MemberLevelDO level); AppMemberUserInfoRespVO convert(MemberUserDO bean, MemberLevelDO level);
MemberUserRespDTO convert2(MemberUserDO bean); MemberUserRespDTO convert2(MemberUserDO bean);

@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.member.service.auth;
import cn.hutool.core.lang.Assert; import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.common.enums.TerminalEnum; import cn.iocoder.yudao.framework.common.enums.TerminalEnum;
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
@ -27,6 +28,9 @@ import cn.iocoder.yudao.module.system.enums.logger.LoginResultEnum;
import cn.iocoder.yudao.module.system.enums.oauth2.OAuth2ClientConstants; import cn.iocoder.yudao.module.system.enums.oauth2.OAuth2ClientConstants;
import cn.iocoder.yudao.module.system.enums.sms.SmsSceneEnum; import cn.iocoder.yudao.module.system.enums.sms.SmsSceneEnum;
import cn.iocoder.yudao.module.system.enums.social.SocialTypeEnum; import cn.iocoder.yudao.module.system.enums.social.SocialTypeEnum;
import cn.iocoder.yudao.module.trade.dal.dataobject.brokerage.BrokerageUserDO;
import cn.iocoder.yudao.module.trade.dal.mysql.brokerage.BrokerageUserMapper;
import cn.iocoder.yudao.module.trade.service.brokerage.BrokerageUserService;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
@ -61,6 +65,13 @@ public class MemberAuthServiceImpl implements MemberAuthService {
@Resource @Resource
private OAuth2TokenApi oauth2TokenApi; private OAuth2TokenApi oauth2TokenApi;
@Resource
private BrokerageUserService brokerageUserService;
@Resource
private BrokerageUserMapper brokerageUserMapper;
@Override @Override
public AppAuthLoginRespVO login(AppAuthLoginReqVO reqVO) { public AppAuthLoginRespVO login(AppAuthLoginReqVO reqVO) {
// 使用手机 + 密码,进行登录。 // 使用手机 + 密码,进行登录。
@ -69,8 +80,7 @@ public class MemberAuthServiceImpl implements MemberAuthService {
// 如果 socialType 非空,说明需要绑定社交用户 // 如果 socialType 非空,说明需要绑定社交用户
String openid = null; String openid = null;
if (reqVO.getSocialType() != null) { if (reqVO.getSocialType() != null) {
openid = socialUserApi.bindSocialUser(new SocialUserBindReqDTO(user.getId(), getUserType().getValue(), openid = socialUserApi.bindSocialUser(new SocialUserBindReqDTO(user.getId(), getUserType().getValue(), reqVO.getSocialType(), reqVO.getSocialCode(), reqVO.getSocialState()));
reqVO.getSocialType(), reqVO.getSocialCode(), reqVO.getSocialState()));
} }
// 创建 Token 令牌,记录登录日志 // 创建 Token 令牌,记录登录日志
@ -97,8 +107,7 @@ public class MemberAuthServiceImpl implements MemberAuthService {
// 如果 socialType 非空,说明需要绑定社交用户 // 如果 socialType 非空,说明需要绑定社交用户
String openid = null; String openid = null;
if (reqVO.getSocialType() != null) { if (reqVO.getSocialType() != null) {
openid = socialUserApi.bindSocialUser(new SocialUserBindReqDTO(user.getId(), getUserType().getValue(), openid = socialUserApi.bindSocialUser(new SocialUserBindReqDTO(user.getId(), getUserType().getValue(), reqVO.getSocialType(), reqVO.getSocialCode(), reqVO.getSocialState()));
reqVO.getSocialType(), reqVO.getSocialCode(), reqVO.getSocialState()));
} }
// 创建 Token 令牌,记录登录日志 // 创建 Token 令牌,记录登录日志
@ -109,8 +118,7 @@ public class MemberAuthServiceImpl implements MemberAuthService {
@Transactional @Transactional
public AppAuthLoginRespVO socialLogin(AppAuthSocialLoginReqVO reqVO) { public AppAuthLoginRespVO socialLogin(AppAuthSocialLoginReqVO reqVO) {
// 使用 code 授权码,进行登录。然后,获得到绑定的用户编号 // 使用 code 授权码,进行登录。然后,获得到绑定的用户编号
SocialUserRespDTO socialUser = socialUserApi.getSocialUserByCode(UserTypeEnum.MEMBER.getValue(), reqVO.getType(), SocialUserRespDTO socialUser = socialUserApi.getSocialUserByCode(UserTypeEnum.MEMBER.getValue(), reqVO.getType(), reqVO.getCode(), reqVO.getState());
reqVO.getCode(), reqVO.getState());
if (socialUser == null) { if (socialUser == null) {
throw exception(AUTH_SOCIAL_USER_NOT_FOUND); throw exception(AUTH_SOCIAL_USER_NOT_FOUND);
} }
@ -119,11 +127,10 @@ public class MemberAuthServiceImpl implements MemberAuthService {
MemberUserDO user; MemberUserDO user;
if (socialUser.getUserId() != null) { if (socialUser.getUserId() != null) {
user = userService.getUser(socialUser.getUserId()); user = userService.getUser(socialUser.getUserId());
// 情况二:未绑定,注册用户 + 绑定用户 // 情况二:未绑定,注册用户 + 绑定用户
} else { } else {
user = userService.createUser(socialUser.getNickname(), socialUser.getAvatar(), getClientIP(), getTerminal()); user = userService.createUser(socialUser.getNickname(), socialUser.getAvatar(), getClientIP(), getTerminal());
socialUserApi.bindSocialUser(new SocialUserBindReqDTO(user.getId(), getUserType().getValue(), socialUserApi.bindSocialUser(new SocialUserBindReqDTO(user.getId(), getUserType().getValue(), reqVO.getType(), reqVO.getCode(), reqVO.getState()));
reqVO.getType(), reqVO.getCode(), reqVO.getState()));
} }
if (user == null) { if (user == null) {
throw exception(USER_NOT_EXISTS); throw exception(USER_NOT_EXISTS);
@ -136,31 +143,35 @@ public class MemberAuthServiceImpl implements MemberAuthService {
@Override @Override
public AppAuthLoginRespVO weixinMiniAppLogin(AppAuthWeixinMiniAppLoginReqVO reqVO) { public AppAuthLoginRespVO weixinMiniAppLogin(AppAuthWeixinMiniAppLoginReqVO reqVO) {
// 获得对应的手机号信息 // 获得对应的手机号信息
SocialWxPhoneNumberInfoRespDTO phoneNumberInfo = socialClientApi.getWxMaPhoneNumberInfo( SocialWxPhoneNumberInfoRespDTO phoneNumberInfo = socialClientApi.getWxMaPhoneNumberInfo(UserTypeEnum.MEMBER.getValue(), reqVO.getPhoneCode());
UserTypeEnum.MEMBER.getValue(), reqVO.getPhoneCode());
Assert.notNull(phoneNumberInfo, "获得手机信息失败,结果为空"); Assert.notNull(phoneNumberInfo, "获得手机信息失败,结果为空");
// 获得获得注册用户 // 获得获得注册用户
MemberUserDO user = userService.createUserIfAbsent(phoneNumberInfo.getPurePhoneNumber(), MemberUserDO user = userService.createUserIfAbsent(phoneNumberInfo.getPurePhoneNumber(), getClientIP(), TerminalEnum.WECHAT_MINI_PROGRAM.getTerminal());
getClientIP(), TerminalEnum.WECHAT_MINI_PROGRAM.getTerminal());
Assert.notNull(user, "获取用户失败,结果为空"); Assert.notNull(user, "获取用户失败,结果为空");
// 绑定社交用户 // 绑定社交用户
String openid = socialUserApi.bindSocialUser(new SocialUserBindReqDTO(user.getId(), getUserType().getValue(), String openid = socialUserApi.bindSocialUser(new SocialUserBindReqDTO(user.getId(), getUserType().getValue(), SocialTypeEnum.WECHAT_MINI_APP.getType(), reqVO.getLoginCode(), reqVO.getState()));
SocialTypeEnum.WECHAT_MINI_APP.getType(), reqVO.getLoginCode(), reqVO.getState()));
BrokerageUserDO brokerageUserDO = brokerageUserMapper.selectById(user.getId());
if (ObjectUtil.isEmpty(brokerageUserDO) && ObjectUtil.isNotEmpty(reqVO.getBindUserId())) {
brokerageUserService.bindBrokerageUser(user.getId(), reqVO.getBindUserId());
} else {
if (ObjectUtil.isEmpty(brokerageUserDO)) {
brokerageUserService.bindBrokerageUser(user.getId(), 0L);
}
}
//绑定分销用户
// 创建 Token 令牌,记录登录日志 // 创建 Token 令牌,记录登录日志
return createTokenAfterLoginSuccess(user, user.getMobile(), LoginLogTypeEnum.LOGIN_SOCIAL, openid); return createTokenAfterLoginSuccess(user, user.getMobile(), LoginLogTypeEnum.LOGIN_SOCIAL, openid);
} }
private AppAuthLoginRespVO createTokenAfterLoginSuccess(MemberUserDO user, String mobile, private AppAuthLoginRespVO createTokenAfterLoginSuccess(MemberUserDO user, String mobile, LoginLogTypeEnum logType, String openid) {
LoginLogTypeEnum logType, String openid) {
// 插入登陆日志 // 插入登陆日志
createLoginLog(user.getId(), mobile, logType, LoginResultEnum.SUCCESS); createLoginLog(user.getId(), mobile, logType, LoginResultEnum.SUCCESS);
// 创建 Token 令牌 // 创建 Token 令牌
OAuth2AccessTokenRespDTO accessTokenRespDTO = oauth2TokenApi.createAccessToken(new OAuth2AccessTokenCreateReqDTO() OAuth2AccessTokenRespDTO accessTokenRespDTO = oauth2TokenApi.createAccessToken(new OAuth2AccessTokenCreateReqDTO().setUserId(user.getId()).setUserType(getUserType().getValue()).setClientId(OAuth2ClientConstants.CLIENT_ID_DEFAULT));
.setUserId(user.getId()).setUserType(getUserType().getValue())
.setClientId(OAuth2ClientConstants.CLIENT_ID_DEFAULT));
// 构建返回结果 // 构建返回结果
return AuthConvert.INSTANCE.convert(accessTokenRespDTO, openid); return AuthConvert.INSTANCE.convert(accessTokenRespDTO, openid);
} }
@ -253,8 +264,7 @@ public class MemberAuthServiceImpl implements MemberAuthService {
@Override @Override
public AppAuthLoginRespVO refreshToken(String refreshToken) { public AppAuthLoginRespVO refreshToken(String refreshToken) {
OAuth2AccessTokenRespDTO accessTokenDO = oauth2TokenApi.refreshAccessToken(refreshToken, OAuth2AccessTokenRespDTO accessTokenDO = oauth2TokenApi.refreshAccessToken(refreshToken, OAuth2ClientConstants.CLIENT_ID_DEFAULT);
OAuth2ClientConstants.CLIENT_ID_DEFAULT);
return AuthConvert.INSTANCE.convert(accessTokenDO, null); return AuthConvert.INSTANCE.convert(accessTokenDO, null);
} }

@ -186,5 +186,19 @@ public interface MemberUserService {
* @return * @return
*/ */
boolean updateUserPoint(Long userId, Integer point); boolean updateUserPoint(Long userId, Integer point);
/**
*
*
* @param userId
* @return
*/
boolean updateUserLevelId(Long userId);
/**
* 1188
*
* @param userId
* @return
*/
void updateUserUpgradesLevel(Long userId);
} }

@ -8,12 +8,16 @@ import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.module.member.controller.admin.user.vo.MemberUserPageReqVO; import cn.iocoder.yudao.module.member.controller.admin.user.vo.MemberUserPageReqVO;
import cn.iocoder.yudao.module.member.controller.admin.user.vo.MemberUserUpdateReqVO; import cn.iocoder.yudao.module.member.controller.admin.user.vo.MemberUserUpdateReqVO;
import cn.iocoder.yudao.module.member.controller.app.user.vo.*; import cn.iocoder.yudao.module.member.controller.app.user.vo.*;
import cn.iocoder.yudao.module.member.convert.auth.AuthConvert; import cn.iocoder.yudao.module.member.convert.auth.AuthConvert;
import cn.iocoder.yudao.module.member.convert.user.MemberUserConvert; import cn.iocoder.yudao.module.member.convert.user.MemberUserConvert;
import cn.iocoder.yudao.module.member.dal.dataobject.level.MemberLevelDO;
import cn.iocoder.yudao.module.member.dal.dataobject.user.MemberUserDO; import cn.iocoder.yudao.module.member.dal.dataobject.user.MemberUserDO;
import cn.iocoder.yudao.module.member.dal.mysql.level.MemberLevelMapper;
import cn.iocoder.yudao.module.member.dal.mysql.level.MemberLevelRecordMapper;
import cn.iocoder.yudao.module.member.dal.mysql.user.MemberUserMapper; import cn.iocoder.yudao.module.member.dal.mysql.user.MemberUserMapper;
import cn.iocoder.yudao.module.member.mq.producer.user.MemberUserProducer; import cn.iocoder.yudao.module.member.mq.producer.user.MemberUserProducer;
import cn.iocoder.yudao.module.system.api.sms.SmsCodeApi; import cn.iocoder.yudao.module.system.api.sms.SmsCodeApi;
@ -21,6 +25,9 @@ import cn.iocoder.yudao.module.system.api.sms.dto.code.SmsCodeUseReqDTO;
import cn.iocoder.yudao.module.system.api.social.SocialClientApi; import cn.iocoder.yudao.module.system.api.social.SocialClientApi;
import cn.iocoder.yudao.module.system.api.social.dto.SocialWxPhoneNumberInfoRespDTO; import cn.iocoder.yudao.module.system.api.social.dto.SocialWxPhoneNumberInfoRespDTO;
import cn.iocoder.yudao.module.system.enums.sms.SmsSceneEnum; import cn.iocoder.yudao.module.system.enums.sms.SmsSceneEnum;
import cn.iocoder.yudao.module.trade.dal.dataobject.brokerage.BrokerageUserDO;
import cn.iocoder.yudao.module.trade.dal.mysql.brokerage.BrokerageUserMapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.google.common.annotations.VisibleForTesting; import com.google.common.annotations.VisibleForTesting;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder;
@ -64,6 +71,15 @@ public class MemberUserServiceImpl implements MemberUserService {
@Resource @Resource
private MemberUserProducer memberUserProducer; private MemberUserProducer memberUserProducer;
@Resource
private MemberLevelRecordMapper levelLogMapper;
@Resource
private MemberLevelMapper memberLevelMapper;
@Resource
private BrokerageUserMapper brokerageUserMapper;
@Override @Override
public MemberUserDO getUserByMobile(String mobile) { public MemberUserDO getUserByMobile(String mobile) {
return memberUserMapper.selectByMobile(mobile); return memberUserMapper.selectByMobile(mobile);
@ -314,4 +330,141 @@ public class MemberUserServiceImpl implements MemberUserService {
return true; return true;
} }
@Override
public boolean updateUserLevelId(Long userId) {
//查询帮扶人等级id
MemberLevelDO memberLevelDO = memberLevelMapper.selectOne(new LambdaQueryWrapperX<MemberLevelDO>()
.eq(MemberLevelDO::getStatus, 0)
.eq(MemberLevelDO::getDeleted, 0)
.eq(MemberLevelDO::getLevel, 1)
.orderByAsc(MemberLevelDO::getLevel));
int i = memberUserMapper.updateById(new MemberUserDO()
.setId(userId)
.setLevelId(memberLevelDO.getId())
);
brokerageUserMapper.updateById(new BrokerageUserDO()
.setId(userId)
.setLevel(1)
);
if(i>0){
return true;
}
return false;
}
@Override
public void updateUserUpgradesLevel(Long userId) {
recursionMemberLevel(userId);
// if(i>0){
// return true;
// }
}
private void recursionMemberLevel(Long userId){
//查询会员信息
MemberUserDO memberUserDO = memberUserMapper.selectById(userId);
//查询会员当前等级
MemberLevelDO memberLevelDO = memberLevelMapper.selectById(memberUserDO.getLevelId());
if(ObjectUtil.isNotEmpty(memberLevelDO)){
//查询上一级会员等级
MemberLevelDO upLevelDO = memberLevelMapper.selectOne(new LambdaQueryWrapperX<MemberLevelDO>()
.eq(MemberLevelDO::getStatus, 0)
.eq(MemberLevelDO::getDeleted, 0)
.eq(MemberLevelDO::getLevel, (memberLevelDO.getLevel()+1))
.orderByAsc(MemberLevelDO::getLevel));
if(ObjectUtil.isNotEmpty(upLevelDO)){
if(ObjectUtil.equal(memberLevelDO.getLevel(),1)){//帮扶人升级帮扶员
//添加分润
//升级会员
//修改会员等级
memberUserMapper.updateById(new MemberUserDO()
.setId(userId)
.setLevelId(upLevelDO.getId())
);
//修改邀请记录等级
brokerageUserMapper.updateById(new BrokerageUserDO()
.setId(userId)
.setLevel(upLevelDO.getLevel())
);
//判断上级会员是否升级
BrokerageUserDO brokerageUserDO = brokerageUserMapper.selectById(userId);
recursionMemberLevel(brokerageUserDO.getBindUserId());
}
if(ObjectUtil.equal(memberLevelDO.getLevel(),2)){//帮扶员升级帮扶大使
//查询会员邀请记录下级会员
List<BrokerageUserDO> brokerageUserDOS = brokerageUserMapper.selectList(new LambdaQueryWrapperX<BrokerageUserDO>()
.eq(BrokerageUserDO::getBindUserId, userId)
.eq(BrokerageUserDO::getLevel, memberLevelDO.getLevel())
.eq(BrokerageUserDO::getDeleted, 0)
);
if(ObjectUtil.isNotEmpty(brokerageUserDOS)){
if(brokerageUserDOS.size()>=3){
//升级会员
memberUserMapper.updateById(new MemberUserDO()
.setId(userId)
.setLevelId(upLevelDO.getId())
);
brokerageUserMapper.updateById(new BrokerageUserDO()
.setId(userId)
.setLevel(upLevelDO.getLevel())
);
}
}
//判断上级会员是否升级
BrokerageUserDO brokerageUserDO = brokerageUserMapper.selectById(userId);
recursionMemberLevel(brokerageUserDO.getBindUserId());
}
if(ObjectUtil.equal(memberLevelDO.getLevel(),3)){//帮扶大使升级帮扶中心
//查询会员邀请记录下级会员
List<BrokerageUserDO> brokerageUserDOS = brokerageUserMapper.selectList(new LambdaQueryWrapperX<BrokerageUserDO>()
.eq(BrokerageUserDO::getBindUserId, userId)
.eq(BrokerageUserDO::getLevel, memberLevelDO.getLevel())
.eq(BrokerageUserDO::getDeleted, 0)
);
if(ObjectUtil.isNotEmpty(brokerageUserDOS)){
if(brokerageUserDOS.size()>=5){
//升级会员
memberUserMapper.updateById(new MemberUserDO()
.setId(userId)
.setLevelId(upLevelDO.getId())
);
brokerageUserMapper.updateById(new BrokerageUserDO()
.setId(userId)
.setLevel(upLevelDO.getLevel())
);
}
}
//判断上级会员是否升级
BrokerageUserDO brokerageUserDO = brokerageUserMapper.selectById(userId);
recursionMemberLevel(brokerageUserDO.getBindUserId());
}
if(ObjectUtil.equal(memberLevelDO.getLevel(),4)){//帮扶中心升级帮扶驿站
//查询会员邀请记录下级会员
List<BrokerageUserDO> brokerageUserDOS = brokerageUserMapper.selectList(new LambdaQueryWrapperX<BrokerageUserDO>()
.eq(BrokerageUserDO::getBindUserId, userId)
.eq(BrokerageUserDO::getLevel, memberLevelDO.getLevel())
.eq(BrokerageUserDO::getDeleted, 0)
);
if(ObjectUtil.isNotEmpty(brokerageUserDOS)){
if(brokerageUserDOS.size()>=10){
//升级会员
memberUserMapper.updateById(new MemberUserDO()
.setId(userId)
.setLevelId(upLevelDO.getId())
);
brokerageUserMapper.updateById(new BrokerageUserDO()
.setId(userId)
.setLevel(upLevelDO.getLevel())
);
}
}
//判断上级会员是否升级
BrokerageUserDO brokerageUserDO = brokerageUserMapper.selectById(userId);
recursionMemberLevel(brokerageUserDO.getBindUserId());
}
if(ObjectUtil.equal(memberLevelDO.getLevel(),5)){//帮扶驿站---最终级别
}
}
}
}
} }

@ -33,6 +33,7 @@ public class PayDemoOrderController {
@Resource @Resource
private PayDemoOrderService payDemoOrderService; private PayDemoOrderService payDemoOrderService;
@PostMapping("/create") @PostMapping("/create")
@Operation(summary = "创建示例订单") @Operation(summary = "创建示例订单")
public CommonResult<Long> createDemoOrder(@Valid @RequestBody PayDemoOrderCreateReqVO createReqVO) { public CommonResult<Long> createDemoOrder(@Valid @RequestBody PayDemoOrderCreateReqVO createReqVO) {
@ -52,6 +53,8 @@ public class PayDemoOrderController {
public CommonResult<Boolean> updateDemoOrderPaid(@RequestBody PayOrderNotifyReqDTO notifyReqDTO) { public CommonResult<Boolean> updateDemoOrderPaid(@RequestBody PayOrderNotifyReqDTO notifyReqDTO) {
payDemoOrderService.updateDemoOrderPaid(Long.valueOf(notifyReqDTO.getMerchantOrderId()), payDemoOrderService.updateDemoOrderPaid(Long.valueOf(notifyReqDTO.getMerchantOrderId()),
notifyReqDTO.getPayOrderId()); notifyReqDTO.getPayOrderId());
return success(true); return success(true);
} }

@ -127,6 +127,12 @@
<groupId>com.xingyuv</groupId> <groupId>com.xingyuv</groupId>
<artifactId>spring-boot-starter-captcha-plus</artifactId> <!-- 验证码,一般用于登录使用 --> <artifactId>spring-boot-starter-captcha-plus</artifactId> <!-- 验证码,一般用于登录使用 -->
</dependency> </dependency>
<dependency>
<groupId>cn.iocoder.boot</groupId>
<artifactId>yudao-module-trade-biz</artifactId>
<version>2.1.0-jdk8-snapshot</version>
<scope>compile</scope>
</dependency>
</dependencies> </dependencies>
</project> </project>

@ -178,7 +178,8 @@ public class OAuth2TokenServiceImpl implements OAuth2TokenService {
if (userType.equals(UserTypeEnum.ADMIN.getValue())) { if (userType.equals(UserTypeEnum.ADMIN.getValue())) {
AdminUserDO user = adminUserService.getUser(userId); AdminUserDO user = adminUserService.getUser(userId);
return MapUtil.builder(LoginUser.INFO_KEY_NICKNAME, user.getNickname()) return MapUtil.builder(LoginUser.INFO_KEY_NICKNAME, user.getNickname())
.put(LoginUser.INFO_KEY_DEPT_ID, StrUtil.toStringOrNull(user.getDeptId())).build(); .put(LoginUser.INFO_KEY_DEPT_ID, StrUtil.toStringOrNull(user.getDeptId()))
.put(LoginUser.INFO_KEY_MOBILE,StrUtil.toStringOrNull(user.getMobile())).build();
} else if (userType.equals(UserTypeEnum.MEMBER.getValue())) { } else if (userType.equals(UserTypeEnum.MEMBER.getValue())) {
// 注意:目前 Member 暂时不读取,可以按需实现 // 注意:目前 Member 暂时不读取,可以按需实现
return Collections.emptyMap(); return Collections.emptyMap();

@ -12,6 +12,7 @@ import cn.iocoder.yudao.module.system.dal.dataobject.social.SocialUserDO;
import cn.iocoder.yudao.module.system.dal.mysql.social.SocialUserBindMapper; import cn.iocoder.yudao.module.system.dal.mysql.social.SocialUserBindMapper;
import cn.iocoder.yudao.module.system.dal.mysql.social.SocialUserMapper; import cn.iocoder.yudao.module.system.dal.mysql.social.SocialUserMapper;
import cn.iocoder.yudao.module.system.enums.social.SocialTypeEnum; import cn.iocoder.yudao.module.system.enums.social.SocialTypeEnum;
import cn.iocoder.yudao.module.trade.service.brokerage.BrokerageUserService;
import com.xingyuv.jushauth.model.AuthUser; import com.xingyuv.jushauth.model.AuthUser;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@ -46,6 +47,8 @@ public class SocialUserServiceImpl implements SocialUserService {
@Resource @Resource
private SocialClientService socialClientService; private SocialClientService socialClientService;
@Override @Override
public List<SocialUserDO> getSocialUserList(Long userId, Integer userType) { public List<SocialUserDO> getSocialUserList(Long userId, Integer userType) {
// 获得绑定 // 获得绑定
@ -77,6 +80,8 @@ public class SocialUserServiceImpl implements SocialUserService {
.userId(reqDTO.getUserId()).userType(reqDTO.getUserType()) .userId(reqDTO.getUserId()).userType(reqDTO.getUserType())
.socialUserId(socialUser.getId()).socialType(socialUser.getType()).build(); .socialUserId(socialUser.getId()).socialType(socialUser.getType()).build();
socialUserBindMapper.insert(socialUserBind); socialUserBindMapper.insert(socialUserBind);
//创建绑定用户
return socialUser.getOpenid(); return socialUser.getOpenid();
} }

@ -1 +1,2 @@
SHOPRO_DEV_BASE_URL = http://192.168.0.135:48080 # SHOPRO_DEV_BASE_URL = https://yanghaodong.51vip.biz
SHOPRO_DEV_BASE_URL = http://192.168.1.129:48080

@ -261,6 +261,42 @@
"group": "用户中心" "group": "用户中心"
} }
}, },
{
"path": "prize",
"style": {
"navigationBarTitleText": "抽奖"
},
"meta": {
"auth": true,
"sync": true,
"title": "抽奖活动",
"group": "用户中心"
}
},
{
"path": "PrizesWon",
"style": {
"navigationBarTitleText": "已获奖品"
},
"meta": {
"auth": true,
"sync": true,
"title": "抽奖活动",
"group": "用户中心"
}
},
{
"path": "ActivityRules",
"style": {
"navigationBarTitleText": "活动规则"
},
"meta": {
"auth": true,
"sync": true,
"title": "活动规则",
"group": "用户中心"
}
},
{ {
"path": "goods-collect", "path": "goods-collect",
"style": { "style": {

@ -51,10 +51,15 @@
onLoad((options) => { onLoad((options) => {
// #ifdef MP // #ifdef MP
// //
if (options.scene) { if (options.q) {
const sceneParams = decodeURIComponent(options.scene).split('='); const sceneParams = decodeURIComponent(options.q).split('=');
console.log("sceneParams=>",sceneParams); console.log("sceneParams=>",sceneParams);
options[sceneParams[0]] = sceneParams[1]; options[sceneParams[0]] = sceneParams[1];
console.log(options,'1123456');
uni.setStorageSync('bindUserId', sceneParams[1]);
}
if (options.r) {
uni.setStorageSync('bindUserId', options.r);
} }
// #endif // #endif

@ -0,0 +1,39 @@
<template>
<view>
<s-layout class="set-wrap" title="抽奖规则" :bgStyle="{ color: '#FFF' }">
<!-- <view class="ss-p-30">
<mp-html class="richtext" :content="state.content" />
</view> -->
<rich-text :nodes="data"></rich-text>
</s-layout>
</view>
</template>
<script setup>
import { ref } from 'vue'
import MineApi from '@/sheep/api/prize/index'
import { onLoad, onReachBottom, onShow, onUnload, onHide } from '@dcloudio/uni-app';
const data = ref()
const getActivityRules = async () => {
const res = await MineApi.ActivityRules()
data.value = res.data.name
// data.value = res.data.value = res.result.content.replace(
// /<img(.*?)\s*width=".*?"\s*height=".*?"\s*\/?>/g,
// '<img$1 style="max-width: 100%;" />'
// )
// data.value = data.value.replace(/style="display: block; margin-left: auto; margin-right: auto;"/g, '')
}
onShow(() => {
getActivityRules()
})
</script>
<style lang="scss" scoped>
</style>

@ -0,0 +1,186 @@
<template>
<s-layout class="set-wrap" title="已获奖品" :bgStyle="{ color: '#FFF' }">
<view>
<view class="_thWrap" v-for="(item, index) in list" :key="item.id">
<view class="_cont">
<view class="_left">
<image class="_img" :src="item.imgUrl"></image>
</view>
<view class="_right">
<view class="_h4">
<text>奖品名称{{ item.name }}</text>
</view>
<view class="_h4">
<text>获得时间{{ formattedDateTime(item.createTime) }}</text>
</view>
</view>
</view>
</view>
</view>
</s-layout>
</template>
<script setup>
import { ref, } from 'vue'
import MineApi from '@/sheep/api/prize/index'
// import layOut from '@/components/layout.vue'
import { onLoad, onReachBottom, onShow, onUnload, onHide } from '@dcloudio/uni-app';
const list = ref()
//
const getPrizesWon = async () => {
const r = await MineApi.ActivityRules()
let HDid = r.data?.id
const res = await MineApi.PrizesWon(HDid)
list.value = res.data
}
const formattedDateTime = (timestampInMilliseconds) => {
const date = new Date(timestampInMilliseconds);
const year = date.getFullYear();
const month = ('0' + (date.getMonth() + 1)).slice(-2);
const day = ('0' + date.getDate()).slice(-2);
const hours = ('0' + date.getHours()).slice(-2);
const minutes = ('0' + date.getMinutes()).slice(-2);
const seconds = ('0' + date.getSeconds()).slice(-2);
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
};
onShow(async () => {
await getPrizesWon()
})
</script>
<style lang="scss" scoped>
page {
background-color: white;
}
.tabs {
display: flex;
justify-content: space-evenly;
height: 100rpx;
line-height: 90rpx;
font-size: 28rpx;
border-radius: 10rpx;
box-shadow: 0 4rpx 5rpx rgba(200, 200, 200, 0.3);
color: #333;
background-color: #fff;
z-index: 9;
.text {
margin: 0 20rpx;
position: relative;
font-size: 32rpx;
}
.active {
&::after {
content: '';
width: 70rpx;
height: 5rpx;
transform: translate(-50%);
background-color: #4376f5;
position: absolute;
left: 50%;
bottom: 24rpx;
}
}
}
._thWrap {
width: 100%;
border-bottom: 2rpx solid rgba(242, 242, 242, 1);
padding: 20rpx 0;
}
._cont {
display: flex;
justify-content: space-between;
background: #ffffff;
border-radius: 10px;
box-shadow: 0 0 10rpx 5rpx rgba(200, 200, 200, 0.3);
padding: 10px;
flex: 1;
._left {
width: 266rpx;
height: 260rpx;
border: 2rpx solid rgba(242, 242, 242, 1);
text-align: center;
._img {
width: 265rpx;
height: 250rpx;
}
}
._right {
margin-left: 30rpx;
padding-top: 10rpx;
._h4 {
padding-top: 50rpx;
._h5 {
margin-bottom: 10rpx;
}
._h5Two {
font-size: 35rpx;
margin-bottom: 10rpx;
}
._tips {
color: #aaaaaa;
font-size: 22rpx;
}
._tipsTwo {
color: #565353;
font-size: 30rpx;
}
}
.danjia {
display: block;
color: red;
font-size: 25rpx;
// font-weight: bolder;
margin-top: 60rpx;
text {
font-size: 15rpx;
}
}
}
// ._bo {
// margin-top: 20rpx;
// display: flex;
// justify-content: space-between;
// align-items: center;
// ._money {
// color: red($color: #a9a8a8);
// // font-weight: bold;
// font-size: 20rpx;
// margin-right: 16rpx;
// text {
// font-size: 28rpx;
// }
// }
// ._btn {
// width: 192rpx;
// height: 62rpx;
// line-height: 62rpx;
// text-align: center;
// border-radius: 100rpx;
// color: white;
// font-weight: bold;
// background-color: $color-gray-Main;
// }
// }
}
</style>

@ -0,0 +1,421 @@
<template>
<s-layout class="set-wrap" title="活动" :bgStyle="{ color: '#FFF' }">
<view class="_bgc">
<view class="_bg1">
<!-- <text class="_jf">5积分抽奖一次</text>
<view class="_cont">
<view class="_left">
<image src="https://obs-sdwh.cucloud.cn/cdz/jinbi.png" class="_jinbi"></image>
<text>开心贷</text>
</view>
<view class="_mid">抽到99元优惠券</view>
<view class="_right">4秒前</view>
</view> -->
</view>
<view class="container">
<!-- <view class="container_circle" v-for="(v, i) in circleList" :key="i"
:style="{ 'top': v.topCircle + 'rpx', 'left': v.leftCircle + 'rpx', 'background-color': (i % 2 == 0) ? oneCircleColor : twoCircleColor }">
</view> -->
<view class="container_content">
<view class="content_out" v-for="(v, i) in prizeList" :key="i" :style="{
top: v.topAward + 'rpx',
left: v.leftAward + 'rpx',
background: i == indexSelect ? prizeCheckColor : '',
animation: 'animatebox 4s linear infinite'
}">
<image class="award_image" :src="v.Img"></image>
<!-- {{ v.name }} -->
</view>
<view class="content_btn" @tap="handleStart"
:style="{ 'background-color': isRunning ? '#55ffff' : '' }">
<view class="_diji">点击</view>
<view>抽奖</view>
</view>
</view>
<!-- <view class="container_num">剩余抽奖次数{{ luckDrawNum }}</view> -->
</view>
<view class="_btnWrap">
<view class="_btn" @tap="sheep.$router.go('/pages/user/PrizesWon')"></view>
<view class="_btn" @tap="sheep.$router.go('/pages/user/ActivityRules')"></view>
</view>
</view>
</s-layout>
</template>
<script setup>
import { ref } from 'vue'
import { onLoad, onReachBottom, onShow, onUnload, onHide } from '@dcloudio/uni-app';
import MineApi from '@/sheep/api/prize/index'
import sheep from '@/sheep';
const prizeList = ref([]) //
const prizeCheckColor = ref('linear-gradient(72.5deg, #aa0000, #ff0000, #ff00ff, #550000, #ffaaff, #aa0000, #ff0000)') //
const indexSelect = ref(0) //index
const isRunning = ref(false) //
const imgList = ref([
'https://cdn.cnbj1.fds.api.mi-img.com/nr-pub/202209261921_a1b840c267bd26bcf4dc654d52f259e5.png?w=800&h=800',
'https://cdn.cnbj1.fds.api.mi-img.com/mi-mall/0bcd64f412dfb5e15695fa96d21ecb23.png?w=800&h=800',
'https://cdn.cnbj1.fds.api.mi-img.com/nr-pub/202208111030_e3554c41e0484da99b16bb9e02142e68.png?w=800&h=800',
'https://cdn.cnbj0.fds.api.mi-img.com/b2c-shopapi-pms/pms_1653393310.29013051.png',
'https://cdn.cnbj1.fds.api.mi-img.com/nr-pub/202209261921_a1b840c267bd26bcf4dc654d52f259e5.png?w=800&h=800',
'https://cdn.cnbj0.fds.api.mi-img.com/b2c-shopapi-pms/9E253411E26FD16C7215D7E74321FA45.png',
'https://cdn.cnbj1.fds.api.mi-img.com/mi-mall/cc0be95d45d0063b0aa8bb541be22c77.png?w=800&h=800',
'https://cdn.cnbj1.fds.api.mi-img.com/mi-mall/0c4b5e30d14ca8b51dc6fa6917295ff5.png?w=800&h=800'
]) //
const prizelist = ref([]) //
let showFloag = ref(true)
let HDid = ref()
onLoad(async () => {
const r = await MineApi.ActivityRules()
HDid.value = r.data?.id
const res = await MineApi.prizeImg(HDid.value)
prizelist.value = res.data
imgList.value = []
res.data.forEach((value, index) => {
imgList.value.push(value.imgUrl)
})
for (let i = 0; i < 24; i++) {
let prizeList_on = []
//,.
let topAward = 10
let leftAward = 10
for (let j = 0; j < 8; j++) {
if (j == 0) {
topAward = 5
leftAward = 10
} else if (j < 3) {
topAward = topAward
//166.6666.15.
leftAward = leftAward + 176.6666 + 15
} else if (j < 5) {
leftAward = leftAward
//150,15,
topAward = topAward + 160 + 15
} else if (j < 7) {
leftAward = leftAward - 176.6666 - 15
topAward = topAward
} else if (j < 8) {
leftAward = leftAward
topAward = topAward - 160 - 15
}
// let imgList = this.imgList[j];
let Img = imgList.value[j]
prizeList_on.push({ topAward, leftAward, Img, id: res.data[j].id, name: res.data[j].name })
}
prizeList.value = prizeList_on
}
})
//
const handleStart = async () => {
console.log('抽奖开始,');
if (isRunning.value) return
const res = await MineApi.lottery(HDid.value)
isRunning.value = true
let floag = ref()
for (let i = 0; i < prizelist.value.length; i++) {
if (prizelist.value[i]?.id == res.data?.id) {
floag.value = res.data.id
break
}
}
indexSelect.value = 0
let indexSelect_med = 0
let i = 0
let timer = setInterval(() => {
console.log('floag', floag.value);
//
if (!showFloag.value) {
clearInterval(timer)
isRunning.value = false
}
indexSelect_med++
//
indexSelect_med = indexSelect_med % 8
indexSelect.value = indexSelect_med
i += 30
let randomNum = 1000 + Math.ceil(Math.random() * 1000) //
if (i > randomNum && prizeList.value[indexSelect.value].id === floag.value) {
//
clearInterval(timer)
//
// if (showFloag.value) {
// if (!res.data?.id) {
// uni.showModal({
// title: '',
// content: '',
// showCancel: false,
// success: (res) => {
// if (res.confirm) {
// isRunning.value = false
// }
// }
// })
// return
// }
uni.showModal({
// title: '',
// content: '' + (indexSelect.value) + '',
content: '抽中' + (res.data.name) + '',
showCancel: false,
success: (res) => {
if (res.confirm) {
isRunning.value = false
}
}
})
// }
isRunning.value = false
}
}, 200 + i)
}
onHide(() => {
showFloag.value = false
})
onUnload(() => {
showFloag.value = false
})
onShow(() => {
showFloag.value = true
})
</script>
<style lang="scss" scoped>
._bg1 {
background-image: url('https://obs-sdwh.cucloud.cn/cdz/beijing1.png');
width: 80%;
height: 150rpx;
background-repeat: no-repeat;
background-size: 100% 100%;
overflow: hidden;
margin: 370rpx auto 0;
font-size: 22rpx;
position: relative;
._jf {
position: absolute;
left: 240rpx;
top: 40rpx;
color: white;
}
._cont {
display: flex;
justify-content: space-around;
align-items: center;
color: white;
letter-spacing: 2rpx;
height: 100%;
margin-top: 35rpx;
._left {
display: flex;
align-items: center;
._jinbi {
width: 40rpx;
height: 40rpx;
margin-right: 10rpx;
}
}
}
}
._bgc {
background-image: url('https://obs-sdwh.cucloud.cn/cdz/cjBg.png');
width: 100%;
height: 100vh;
background-repeat: no-repeat;
background-size: 100% 100%;
overflow: hidden;
}
.container {
position: relative;
height: 600rpx;
width: 650rpx;
margin: 0 auto;
border-radius: 40rpx;
// background: linear-gradient(72.5deg, #e9f78c, #ffffb9, #cc55e5, #ef9bcb, #e5b8d8, #ffb140, #f7ed54);
// background-color: #FFB62F;
background-image: url('https://obs-sdwh.cucloud.cn/cdz/beijing2.png');
background-repeat: no-repeat;
background-size: 100% 100%;
// background-size: 400%;
animation: animatebox 4s linear infinite;
@keyframes animatebox {
0% {
background-position: 0%;
}
50% {
background-position: 100%;
}
100% {
background-position: 0%;
}
}
.container_circle {
position: absolute;
display: block;
border-radius: 50%;
height: 20rpx;
width: 20rpx;
}
.container_content {
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
width: 580rpx;
height: 530rpx;
background-color: #ca2c01;
border-radius: 40rpx;
margin: auto;
// background: linear-gradient(72.5deg, #ef499c, #cc55e5, #ffb140, #f7ed54, #ffb140, #cc55e5, #ef499c);
background-size: 400%;
animation: animate1 4s linear infinite;
@keyframes animate1 {
0% {
background-position: 0%;
}
50% {
background-position: 100%;
}
100% {
background-position: 0%;
}
}
.content_out {
position: absolute;
height: 160rpx;
width: 176.6666rpx;
// background-color: #f5f0fc;
background-image: url('https://obs-sdwh.cucloud.cn/cdz/g1.png');
background-repeat: no-repeat;
background-size: 100% 100%;
border-radius: 15rpx;
box-shadow: 0 5px 0 #ff8327;
.award_image {
position: absolute;
margin: auto;
top: 0;
left: 0;
bottom: 0;
right: 0;
height: 140rpx;
width: 130rpx;
background-repeat: no-repeat;
background-size: 100% 100%;
background-image: url('https://obs-sdwh.cucloud.cn/cdz/xxcy.png');
}
}
.content_btn {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
border-radius: 15rpx;
height: 160rpx;
width: 176.6666rpx;
background-color: #ffe400;
box-shadow: 0 5rpx 0 #e7930a;
color: white;
text-align: center;
font-size: 44rpx;
font-weight: bolder;
background-color: #ff8859;
// line-height: 150rpx;
// background: linear-gradient(72.5deg, #f7a0ec, #ffb140, #e58da0, #ef7ecb, #ab9ae5, #ffec8a, #f6f7a6);
// background-size: 400%;
background-image: url('https://obs-sdwh.cucloud.cn/cdz/g5.png');
background-size: 100% 100%;
background-repeat: no-repeat;
animation: animate 4s linear infinite;
._diji {
margin-top: 14rpx;
}
@keyframes animate {
0% {
background-position: 0%;
}
50% {
background-position: 100%;
}
100% {
background-position: 0%;
}
}
}
}
.container_num {
position: absolute;
top: -130rpx;
left: 50%;
transform: translateX(-50%);
color: white;
// background-image: -webkit-linear-gradient(left, #083a96, #e63609 25%, #083a96 50%, #e63609 75%, #083a96);
// -webkit-text-fill-color: transparent;
background-clip: text;
background-size: 200% 100%;
animation: masked-animation 4s infinite linear;
@keyframes masked-animation {
0% {
background-position: 0 0;
}
100% {
background-position: -100% 0;
}
}
}
}
._btnWrap {
display: flex;
align-items: center;
justify-content: space-around;
margin-top: 40rpx;
._btn {
background-image: url('https://obs-sdwh.cucloud.cn/cdz/anniu.png');
background-repeat: no-repeat;
background-size: 100% 100%;
width: 40%;
height: 100rpx;
text-align: center;
line-height: 90rpx;
color: white;
font-weight: bold;
font-size: 32rpx;
}
}
</style>

@ -103,7 +103,8 @@ const AuthUtil = {
data: { data: {
phoneCode, phoneCode,
loginCode, loginCode,
state state,
bindUserId: uni.getStorageSync('bindUserId') || '',
}, },
custom: { custom: {
showSuccess: true, showSuccess: true,

@ -20,12 +20,17 @@ export default {
// 获取微信小程序码 // 获取微信小程序码
getWxacode: async (path, query) => { getWxacode: async (path, query) => {
return await request({ return await request({
url: '/member/social-user/wxa-qrcode', url: '/infra/file/qrCode64',
method: 'POST', method: 'GET',
data: { data: {
scene: query, // scene: query,
path, // path,
checkPath: false, // TODO 开发环境暂不检查 path 是否存在 // checkPath: false, // TODO 开发环境暂不检查 path 是否存在
// content: 'http://cdz.huamar.com/zdfs?bindUserId=12345',
type: '1',
// width: 800,
// height: 800,
// imageFormat: 'png',
}, },
}); });
}, },

@ -0,0 +1,43 @@
import request from '@/sheep/request';
const PayOrderApi = {
// 开始抽奖
lottery: (id) => {
return request({
url: '/promotion/prize-draw/lottery',
method: 'GET',
params: { activityId: id },
});
},
// 已获奖品
PrizesWon: (id) => {
return request({
url: '/promotion/prize-draw/getMyPrizeLogDO',
method: 'GET',
params: { activityId: id },
});
},
// 获得抽奖照片
prizeImg: (id) => {
return request({
url: '/promotion/prize-draw/activity-prize/list-by-activity-id',
method: 'GET',
params: { activityId:id },
});
},
// 规则
ActivityRules: (params) => {
return request({
url: '/promotion/prize-draw/getOne',
method: 'GET',
params,
});
},
};
export default PayOrderApi;

@ -650,8 +650,13 @@ export function getRootUrl() {
/** /**
* copyText 多端复制文本 * copyText 多端复制文本
*/ */
export function copyText(text) { export function copyText(temp) {
let text = temp;
if (text.startsWith('?')) {
text = text.substring(1);
}
// #ifndef H5 // #ifndef H5
console.log(text, 'text1');
uni.setClipboardData({ uni.setClipboardData({
data: text, data: text,
success: function () { success: function () {

@ -88,7 +88,11 @@ const buildSpmQuery = (params) => {
from = platformMap.indexOf(params.from) + 1; from = platformMap.indexOf(params.from) + 1;
} }
//spmParams = ... 可按需扩展 //spmParams = ... 可按需扩展
return `spm=${shareId}.${page}.${query}.${platform}.${from}`; if (user.userInfo.urlLink) {
return `${user.userInfo.urlLink}`;
} else {
return `spm=${shareId}.${page}.${query}.${platform}.${from}`;
}
}; };
// 构造页面分享参数: 所有的分享都先到首页进行 spm 参数解析 // 构造页面分享参数: 所有的分享都先到首页进行 spm 参数解析
@ -173,7 +177,7 @@ const decryptSpm = (spm) => {
}; };
// 绑定推广员 // 绑定推广员
const bindBrokerageUser = async (val= undefined) => { const bindBrokerageUser = async (val = undefined) => {
try { try {
const shareId = val || uni.getStorageSync('shareId'); const shareId = val || uni.getStorageSync('shareId');
if (!shareId) { if (!shareId) {
@ -181,8 +185,7 @@ const bindBrokerageUser = async (val= undefined) => {
} }
await BrokerageApi.bindBrokerageUser({ bindUserId: shareId }); await BrokerageApi.bindBrokerageUser({ bindUserId: shareId });
uni.removeStorageSync('shareId'); uni.removeStorageSync('shareId');
} catch { } catch {}
}
}; };
// 更新公众号分享sdk // 更新公众号分享sdk

@ -72,15 +72,16 @@ const app = defineStore({
}; };
this.platform = { this.platform = {
share: { share: {
methods: ["poster", "link"], methods: ['poster', 'link'],
linkAddress: "https://shopro.sheepjs.com/#/", // linkAddress: 'http://cdz.huamar.com/zdfs',
linkAddress: '',
posterInfo: { posterInfo: {
"user_bg": "/static/img/shop/config/user-poster-bg.png", user_bg: '/static/img/shop/config/user-poster-bg.png',
"goods_bg": "/static/img/shop/config/goods-poster-bg.png", goods_bg: '/static/img/shop/config/goods-poster-bg.png',
"groupon_bg": "/static/img/shop/config/groupon-poster-bg.png" groupon_bg: '/static/img/shop/config/groupon-poster-bg.png',
} },
}, },
bind_mobile: 0 bind_mobile: 0,
}; };
this.chat = { this.chat = {
chat_domain: "https://api.shopro.sheepjs.com/chat", chat_domain: "https://api.shopro.sheepjs.com/chat",

Loading…
Cancel
Save