提交 2662eae7 authored 作者: 窦馨雨's avatar 窦馨雨

合并分支 'dxy' 到 'qa'

增加重客抽奖小程序接口相关代码 查看合并请求 !106
package com.wangxiaolu.promotion.controller.lottery;
import com.wangxiaolu.promotion.pojo.lottery.dto.LotteryRecordDto;
import com.wangxiaolu.promotion.pojo.lottery.vo.LotteryRecordVo;
import com.wangxiaolu.promotion.result.basedata.R;
import com.wangxiaolu.promotion.service.lottery.impl.LotteryCoreServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/lottery")
@CrossOrigin // 允许前端跨域访问
public class LotteryController {
@Autowired
private LotteryCoreServiceImpl lotteryService;
/**
* 初始化
*/
@PostMapping("/init")
public LotteryRecordDto init(@RequestBody LotteryRecordVo lotteryRecordVo) {
return lotteryService.initLottery(lotteryRecordVo.getLongitude(), lotteryRecordVo.getLatitude(), lotteryRecordVo.getReceiptImageUrl(), lotteryRecordVo.getUserInfo());
}
/**
* 抽奖
*/
@PostMapping("/draw")
public LotteryRecordDto draw(@RequestBody LotteryRecordVo lotteryRecordVo) {
return lotteryService.doDraw(lotteryRecordVo.getId());
}
@PostMapping("/upload-receipt")
public R uploadReceipt(@RequestBody LotteryRecordVo lotteryRecordVo) {
lotteryService.uploadReceipt(lotteryRecordVo.getId(), lotteryRecordVo.getReceiptImageUrl());
return R.success(lotteryRecordVo.getReceiptImageUrl());
}
}
\ No newline at end of file
package com.wangxiaolu.promotion.domain.lottery.dao;
import com.wangxiaolu.promotion.domain.lottery.entity.LotteryUserInfo;
import com.wangxiaolu.promotion.pojo.lottery.dto.LotteryRecordDto;
/**
* @Author: DouXinYu
* @Date: 2026-04-07 17:41
* @Description:
*/
public interface LotteryCoreDao {
LotteryRecordDto doDraw(Long recordId);
LotteryRecordDto initLottery(Double longitude, Double latitude, String receiptImage, LotteryUserInfo userInfo);
}
package com.wangxiaolu.promotion.domain.lottery.dao.impl;
import cn.hutool.core.date.DateTime;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.wangxiaolu.promotion.common.util.BeanUtils;
import com.wangxiaolu.promotion.domain.lottery.dao.LotteryCoreDao;
import com.wangxiaolu.promotion.domain.lottery.entity.LotteryRecord;
import com.wangxiaolu.promotion.domain.lottery.entity.LotteryUserInfo;
import com.wangxiaolu.promotion.domain.lottery.mapper.LotteryMapper;
import com.wangxiaolu.promotion.domain.lottery.mapper.LotteryUserInfoMapper;
import com.wangxiaolu.promotion.exception.ParamException;
import com.wangxiaolu.promotion.pojo.lottery.dto.LotteryRecordDto;
import com.wangxiaolu.promotion.result.basedata.RCode;
import com.wangxiaolu.promotion.utils.TencentMapUtil;
import org.apache.poi.ss.formula.functions.Now;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.Map;
import java.util.Objects;
import java.util.Random;
/**
* @Author: DouXinYu
* @Date: 2026-04-07 17:42
* @Description: 抽奖核心DAO实现(动态概率:当月+同地址 中过一等奖则降低概率)
*/
@Service
public class LotteryCoreDaoImpl implements LotteryCoreDao {
@Autowired
private LotteryMapper lotteryMapper;
@Autowired
private TencentMapUtil tencentMapUtil;
@Autowired
private LotteryUserInfoMapper lotteryUserInfoMapper;
/**
* 初始化抽奖记录
*/
@Override
public LotteryRecordDto initLottery(Double longitude, Double latitude, String receiptImage, LotteryUserInfo userInfo) {
// 腾讯地图逆地址解析
Map<String, String> location = tencentMapUtil.getAddressMapByLngLat(longitude, latitude);
LotteryRecord record = new LotteryRecord();
record.setLongitude(longitude);
record.setLatitude(latitude);
// ====================== 自动拆分省市区 ======================
record.setProvince(location.get("province"));
record.setCity(location.get("city"));
record.setDistrict(location.get("district"));
record.setAddress(location.get("address"));
record.setReceiptImageUrl(receiptImage);
if (Objects.nonNull(userInfo) && userInfo.getOpenId() != null) {
LambdaQueryWrapper<LotteryUserInfo> eq = new LambdaQueryWrapper<LotteryUserInfo>()
.eq(LotteryUserInfo::getOpenId, userInfo.getOpenId());
LotteryUserInfo lotteryUserInfo = lotteryUserInfoMapper.selectOne(eq);
if (lotteryUserInfo == null) {
// 保存用户信息
lotteryUserInfoMapper.insert(userInfo);
record.setWxOpenId(userInfo.getOpenId());
}else {
record.setWxOpenId(userInfo.getOpenId());
}
}
lotteryMapper.insert(record);
LotteryRecordDto result = BeanUtils.transitionDto(record, LotteryRecordDto.class);
ArrayList<String> prizeList = new ArrayList<>();
prizeList.add("三等奖");
prizeList.add("一等奖");
prizeList.add("二等奖");
prizeList.add("三等奖");
prizeList.add("二等奖");
prizeList.add("三等奖");
prizeList.add("二等奖");
prizeList.add("三等奖");
result.setPrizes(prizeList);
return result;
}
/**
* 执行抽奖(动态概率核心)
*/
@Override
public LotteryRecordDto doDraw(Long recordId) {
LotteryRecord record = lotteryMapper.selectById(recordId);
if (record == null) {
throw new ParamException(RCode.LOTTERY_RECORD_NOT_EXIST);
}
if (record.getWxOpenId() != null && record.getPrizeLevel() != null) {
throw new ParamException(RCode.LOTTERY_RECORD_ERROR);
}
// 动态概率
int prizeLevel = simpleDynamicPrize();
record.setPrizeLevel(prizeLevel);
lotteryMapper.updateById(record);
return BeanUtils.transitionDto(record, LotteryRecordDto.class);
}
/**
* 简单动态概率
*/
private int simpleDynamicPrize() {
int r = new Random().nextInt(100);
if (r < 10) {
return 1;
} else if (r < 30) {
return 2;
} else {
return 3;
}
}
}
\ No newline at end of file
package com.wangxiaolu.promotion.domain.lottery.entity;
import cn.hutool.core.date.DateTime;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.time.LocalDateTime;
import java.util.Date;
@Data
@TableName("lottery_record") // 对应数据库表名
public class LotteryRecord {
@TableId(type = IdType.AUTO) // 主键自增
private Long id;
/**
* 经度
*/
private Double longitude;
/**
* 纬度
*/
private Double latitude;
/**
* 省
*/
private String province;
/**
* 市
*/
private String city;
/**
* 区/县
*/
private String district;
/**
* 解析后的地址
*/
private String address;
/**
* 中奖等级 (0:一等奖, 1:二等奖, 2:三等奖)
*/
private Integer prizeLevel;
/**
* 小票图片URL
*/
private String receiptImageUrl;
/**
* 状态 (verified:已审核, pending:待审核)
*/
private String status;
private String wxOpenId;
/**
* 创建时间
*/
private Date createTime;
private Date updateTime;
private Integer isDeleted;
}
\ No newline at end of file
package com.wangxiaolu.promotion.domain.lottery.entity;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.util.Date;
@Data
@TableName("lottery_user_info")
public class LotteryUserInfo {
private Long id;
private String openId;
private String nickName;
private String avatarUrl;
private String gender;
private String language;
private String country;
private String province;
private String city;
private Date createTime;
private Date updateTime;
private Integer isDeleted;
}
\ No newline at end of file
package com.wangxiaolu.promotion.domain.lottery.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.wangxiaolu.promotion.domain.lottery.entity.LotteryRecord;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface LotteryMapper extends BaseMapper<LotteryRecord> {
}
\ No newline at end of file
package com.wangxiaolu.promotion.domain.lottery.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.wangxiaolu.promotion.domain.lottery.entity.LotteryUserInfo;
import org.apache.ibatis.annotations.Mapper;
/**
* @Author: DouXinYu
* @Date: 2026-04-24 11:29
* @Description:
*/
@Mapper
public interface LotteryUserInfoMapper extends BaseMapper<LotteryUserInfo> {
}
package com.wangxiaolu.promotion.pojo.lottery.dto;
import cn.hutool.core.date.DateTime;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.time.LocalDateTime;
import java.util.Date;
import java.util.List;
@Data
public class LotteryRecordDto {
private Long id;
/**
* 经度
*/
private Double longitude;
/**
* 纬度
*/
private Double latitude;
/**
* 省
*/
private String province;
/**
* 市
*/
private String city;
/**
* 区/县
*/
private String district;
/**
* 解析后的地址
*/
private String address;
/**
* 中奖等级 (0:一等奖, 1:二等奖, 2:三等奖, -1:未中奖)
*/
private Integer prizeLevel;
/**
* 创建时间
*/
private Date createTime;
/**
* 奖品列表
*/
private List<String> prizes;
/**
* 抽奖结果
*/
private String drawResult;
/**
* 用户的Open_id
*/
private String wxOpenId;
}
\ No newline at end of file
package com.wangxiaolu.promotion.pojo.lottery.vo;
import cn.hutool.system.UserInfo;
import com.wangxiaolu.promotion.domain.lottery.entity.LotteryUserInfo;
import lombok.Data;
import java.util.List;
@Data
public class LotteryRecordVo {
private Long id;
/**
* 经度
*/
private Double longitude;
/**
* 纬度
*/
private Double latitude;
/**
* 省
*/
private String province;
/**
* 市
*/
private String city;
/**
* 区/县
*/
private String district;
/**
* 解析后的地址
*/
private String address;
/**
* 中奖等级 (0:一等奖, 1:二等奖, 2:三等奖, -1:未中奖)
*/
private Integer prizeLevel;
/**
* 奖品列表
*/
private List<String> prizes;
/**
* 小票图片地址(OSS路径)
*/
private String receiptImageUrl;
/**
* 用户信息
*/
private LotteryUserInfo userInfo;
}
\ No newline at end of file
package com.wangxiaolu.promotion.service.lottery;
import com.wangxiaolu.promotion.domain.lottery.entity.LotteryUserInfo;
import com.wangxiaolu.promotion.pojo.lottery.dto.LotteryRecordDto;
/**
* @Author: DouXinYu
* @Date: 2026-04-07 17:38
* @Description:
*/
public interface LotteryCoreService {
LotteryRecordDto initLottery(Double longitude, Double latitude, String receiptImage, LotteryUserInfo userInfo);
LotteryRecordDto doDraw(Long recordId);
}
package com.wangxiaolu.promotion.service.lottery.impl;
import cn.hutool.system.UserInfo;
import com.wangxiaolu.promotion.domain.lottery.dao.LotteryCoreDao;
import com.wangxiaolu.promotion.domain.lottery.entity.LotteryRecord;
import com.wangxiaolu.promotion.domain.lottery.entity.LotteryUserInfo;
import com.wangxiaolu.promotion.domain.lottery.mapper.LotteryMapper;
import com.wangxiaolu.promotion.exception.ParamException;
import com.wangxiaolu.promotion.pojo.lottery.dto.LotteryRecordDto;
import com.wangxiaolu.promotion.result.basedata.RCode;
import com.wangxiaolu.promotion.service.lottery.LotteryCoreService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.Random;
@Service
public class LotteryCoreServiceImpl implements LotteryCoreService {
@Autowired
private LotteryMapper lotteryMapper;
@Autowired
private LotteryCoreDao lotteryCoreDao;
/**
* 上传小票
*/
public void uploadReceipt(Long recordId, String receiptImage) {
LotteryRecord record = lotteryMapper.selectById(recordId);
if (record == null) {
throw new ParamException(RCode.LOTTERY_RECORD_NOT_EXIST);
}
record.setReceiptImageUrl(receiptImage);
record.setStatus("verified"); // 促销员审核通过
lotteryMapper.updateById(record);
}
/**
* 1. 初始化:保存位置信息
*/
@Override
public LotteryRecordDto initLottery(Double longitude, Double latitude, String receiptImage, LotteryUserInfo userInfo) {
return lotteryCoreDao.initLottery(longitude, latitude, receiptImage, userInfo);
}
/**
* 2. 抽奖:根据地址动态计算概率
*/
@Override
public LotteryRecordDto doDraw(Long recordId) {
return lotteryCoreDao.doDraw(recordId);
}
}
\ No newline at end of file
......@@ -13,6 +13,7 @@ import javax.annotation.PostConstruct;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
/**
......@@ -40,6 +41,19 @@ public class TencentMapUtil {
@Autowired
private StringRedisTemplate stringRedisTemplate;
/**
* 1.1 逆地理编码:经纬度转地址Map(province/city/district/address)
*/
public Map<String, String> getAddressMapByLngLat(double lng, double lat) {
AddressInfo addressInfo = getAddressByLngLat(lng, lat);
Map<String, String> result = new java.util.HashMap<>();
result.put("province", addressInfo.getProvince());
result.put("city", addressInfo.getCity());
result.put("district", addressInfo.getDistrict());
result.put("address", addressInfo.getFullAddress());
return result;
}
// ==================== 1. 逆地理编码实体(保留原有) ====================
public static class AddressInfo {
private String province; // 省份
......
......@@ -65,8 +65,8 @@ tengxunyun:
qince:
open_api: https://openapi.region2.qince.com
open_id: 8546408787259919799
app_key: oV0FHfMt81Tii2_kst
open_id: 5459563908315541679
app_key: MlqoWw9zcmY21htoHI
# mybatis-plus 打印sql日志
#mybatis-plus:
......
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.wangxiaolu.promotion.domain.lottery.mapper.LotteryMapper">
<!-- 通用结果映射 -->
<resultMap id="LotteryRecordMap" type="com.wangxiaolu.promotion.domain.lottery.entity.LotteryRecord">
<id column="id" property="id"/>
<result column="longitude" property="longitude"/>
<result column="latitude" property="latitude"/>
<result column="province" property="province"/>
<result column="city" property="city"/>
<result column="district" property="district"/>
<result column="address" property="address"/>
<result column="prize_level" property="prizeLevel"/>
<result column="create_time" property="createTime"/>
<result column="update_time" property="updateTime"/>
<result column="wx_open_id" property="wxOpenId"/>
<result column="receipt_image_url" property="receiptImageUrl"/>
<result column="status" property="status"/>
<result column="is_deleted" property="isDeleted"/>
</resultMap>
</mapper>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.wangxiaolu.promotion.domain.lottery.mapper.LotteryUserInfoMapper">
<!-- 通用结果映射 -->
<resultMap id="LotteryUserInfoMap" type="com.wangxiaolu.promotion.domain.lottery.entity.LotteryUserInfo">
<id column="id" property="id"/>
<result column="open_id" property="openId"/>
<result column="nick_name" property="nickName"/>
<result column="avatar_url" property="avatarUrl"/>
<result column="gender" property="gender"/>
<result column="language" property="language"/>
<result column="province" property="province"/>
<result column="city" property="city"/>
<result column="country" property="country"/>
<result column="create_time" property="createTime"/>
<result column="update_time" property="updateTime"/>
<result column="is_deleted" property="isDeleted"/>
</resultMap>
</mapper>
\ No newline at end of file
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论