zoukankan      html  css  js  c++  java
  • 抽奖功能实现

    1. 需求分析

    抽奖可以获得积分,礼券,小样,正品等

    若库存为0,则用户不能在抽中此奖

    每个奖项的中奖概率

    每天抽奖次数的限制

    每次抽奖是否需要消耗积分的限制

    有没有批量抽奖功能

    2.表结构设计

    会员表,积分表,是以前就有的,本次新增抽奖功能,需要新增一下的表:

    首先要有库存表,暂且定义为BPRIZE

    其次要记录用户抽中的奖项,暂且定义为HPRIZE

          

    3. 后台代码实现

    Controller 

    @RestController
    @RequestMapping(value = "draw")
    public class DrawController extends BaseController {
    
        @Autowired
        DrawService drawService;
    
        @Autowired
        CouponService couponService;
    
        @Autowired
        SocialProviderService socialProviderService;
    
        @ApiOperation(value = "抽奖历史记录", notes = "抽奖历史记录")
        @GetMapping(value = "history", produces = {MediaType.APPLICATION_JSON_UTF8_VALUE})
        private ResponseBean prizeHistory(@RequestParam("userId") String userId,
                                          @RequestParam("social") String social, @RequestParam("page") int page, @RequestParam("size") int size) {
    
            ResponseBean responseBean = new ResponseBean();
            List<HPrizerecord> hPrizerecords = drawService.getPrizeHistory(userId, social, page, size);
            responseBean.setData(hPrizerecords);
            return responseBean;
        }
    
        @ApiOperation(value = "抽奖榜单", notes = "抽奖榜单")
        @GetMapping(value = "billboard", produces = {MediaType.APPLICATION_JSON_UTF8_VALUE})
        private ResponseBean billboard(@RequestParam("topN") int topN, @RequestParam("levelList") String levelList, @RequestParam("social") String social) {
            ResponseBean responseBean = new ResponseBean();
    
            // 查找SopId
            SSocialProvider socialProvider = socialProviderService.findSocialProvider(social);
    
            // 格式化等级 (str-> list(int))
            List<Integer> level = Arrays.stream(levelList.split(",")).map(a -> {
                return Integer.parseInt(a);
            }).collect(Collectors.toList());
    
            // 查询
            JSONArray billboard = drawService.getBillboard(topN, level, socialProvider.getSopId());
            responseBean.setData(billboard);
            return responseBean;
        }
    
    
        @ApiOperation(value = "抽奖", notes = "抽奖")
        @PostMapping(produces = {MediaType.APPLICATION_JSON_UTF8_VALUE})
        private ResponseBean<BPrize> draw(@RequestParam("userId") String userId,
                                          @RequestParam("social") String social) throws Exception {
    
            ResponseBean responseBean = new ResponseBean();
            BPrize bPrize = drawService.draw(userId, social, super.getSid());
            responseBean.setData(bPrize);
    
            return responseBean;
        }
    }
    

     

    具体实现

    @Service
    public class DrawServiceImpl implements DrawService {
    
    
        @Autowired
        HPrizerecordMapper hPrizerecordMapper;
    
        @Autowired
        SaveDrawRecord saveDrawRecord;
    
    
        @Autowired
        SocialService socialService;
    
        @Autowired
        SocialProviderService socialProviderService;
    
        @Autowired
        BCustomerService bCustomerService;
    
        @Autowired
        BPrizeService bPrizeService;
    
        @Autowired
        PEService peService;
    
    
        @Autowired
        CustomerService customerService;
    
        @Autowired
        SendMemberInfoToEcrmMqTask sendMemberInfoToEcrmMqTask;
    
        @Value("${sys.name}")
        private String sysName;
    
        int freeCount=2;
    
        int dalyMaxDrawCount=5;
    
    
        @Value("${cc.draw.pe.code}")
        String luckyDrawPeEventCode;
    
        @Value("${cc.draw.max.probability}")
        int maxProbability;
        static  Random rand = new Random();
    
        @Value("#{'${cc.draw.actual.prizeLevel}'.split(',')}")
        private  List<Integer>  actualPrizeLevel;
    
    
        @Override
        public List<HPrizerecord> getPrizeHistory(String userId, String social, int page, int size) {
            int cstId = socialService.findCstIdBySocialAndSocialId(userId, social);
    
            if (size == 0 ){
                size = 10;
            }
            if (page<=0){
                page = 1;
            }
    
            return  hPrizerecordMapper.getPrizeHistory(cstId, page, size);
        }
    
    
        @Override
        public BPrize draw(String userId, String social, String sid) throws Exception {
            int cstId = socialService.findCstIdBySocialAndSocialId(userId, social);
    
    
            // 今天一共抽了几次奖
            int todayCount = getDrawCountToday(cstId);
    
            // 如果超过最大次数,直接返回, 不进行抽奖
            if (todayCount >= dalyMaxDrawCount){
                throw new DrawCountLimitException();
            }
    
            // 超过规定的一个次数就要开始扣积分
            if (todayCount >= freeCount) {
                // 扣减积分, 如果扣减失败, 会抛出异常,这边不用管
                peService.sendEvent(cstId, sysName, luckyDrawPeEventCode);
                sendMemberInfoToEcrmMqTask.syncMemberInfoToECRM(cstId, luckyDrawPeEventCode);
            }
    
            boolean drawEnd = false;
            BPrize bPrize = null;
    
            while (!drawEnd) {
                int x = rand.nextInt(maxProbability);
                bPrize = bPrizeService.getPrize(x);
    
                // 如果抽中的是实物奖品
                if (bPrize!=null && actualPrizeLevel.indexOf(bPrize.getPrizeLevel())>=0){
                    // 判断当日是否有中过实物奖品
                    boolean isWinningTheActualPrizeFlag =  isWinningTheActualPrize(cstId);
                    // 如果isWinningTheActualPrizeFlag 为false , 抽奖成功
                    if (!isWinningTheActualPrizeFlag) {
                        drawEnd = true;
                    }
                }
    
                if (bPrize != null) {
                    drawEnd = true;
                }
            }
    
            // 如果礼品里面配置了PEcode 调用PE积分调整
            String peCode = bPrize.getPointCode();
            if (StringUtils.isNotBlank(peCode)) {
                peService.sendEvent(cstId, sysName, peCode);
                sendMemberInfoToEcrmMqTask.syncMemberInfoToECRM(cstId, luckyDrawPeEventCode);
            }
    
            // 记录到抽奖历史
            saveDrawRecord.savePrizerecordHistory(cstId, bPrize, sid);
            return bPrize;
        }
    
        private boolean isWinningTheActualPrize(int cstId) {
    
            // 查询今天是否中过实物奖项
            List<HPrizerecord> hPrizerecords = hPrizerecordMapper.getWinningTheActualPrizeToday(cstId,actualPrizeLevel);
            if (null != hPrizerecords ||!hPrizerecords.isEmpty() || hPrizerecords.size()>0) {
                return true;
            }
    
            return false;
        }
    
        @Override
        public JSONArray getBillboard(int topN, List<Integer> levelList, Integer sopId) {
    
    
            List<Map> records = hPrizerecordMapper.selectBillboard(topN, levelList, sopId);
    
            return (JSONArray) JSONArray.toJSON(records);
        }
    
        private int getDrawCountToday(int cstId) {
            return hPrizerecordMapper.getDrawCountToday(cstId);
        }
    
    
    }
    

      

     

    4. 前端UI实现

  • 相关阅读:
    PAT顶级 1015 Letter-moving Game (35分)
    PAT顶级 1008 Airline Routes (35分)(有向图的强连通分量)
    PAT顶级 1025 Keep at Most 100 Characters (35分)
    PAT顶级 1027 Larry and Inversions (35分)(树状数组)
    PAT 顶级 1026 String of Colorful Beads (35分)(尺取法)
    PAT顶级 1009 Triple Inversions (35分)(树状数组)
    Codeforces 1283F DIY Garland
    Codeforces Round #438 A. Bark to Unlock
    Codeforces Round #437 E. Buy Low Sell High
    Codeforces Round #437 C. Ordering Pizza
  • 原文地址:https://www.cnblogs.com/qianjinyan/p/11384470.html
Copyright © 2011-2022 走看看