package com.panzhihua.service_community.service.impl; import static java.util.Objects.isNull; import static java.util.Objects.nonNull; import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.Random; import javax.annotation.Resource; import org.springframework.beans.BeanUtils; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.panzhihua.common.model.dtos.community.microCommercialStreet.McsGameDTO; import com.panzhihua.common.model.dtos.community.microCommercialStreet.PageMcsGameDTO; import com.panzhihua.common.model.dtos.community.microCommercialStreet.SetPopularForGameDTO; import com.panzhihua.common.model.dtos.community.microCommercialStreet.SetShelfForGameDTO; import com.panzhihua.common.model.vos.R; import com.panzhihua.common.model.vos.community.microCommercialStreet.McsCouponVO; import com.panzhihua.common.model.vos.community.microCommercialStreet.McsGameVO; import com.panzhihua.common.model.vos.community.microCommercialStreet.TopStatisticsVO; import com.panzhihua.common.utlis.DateUtils; import com.panzhihua.common.utlis.Snowflake; import com.panzhihua.service_community.dao.McsCouponDAO; import com.panzhihua.service_community.dao.McsEvaluateDAO; import com.panzhihua.service_community.dao.McsGameDAO; import com.panzhihua.service_community.dao.McsMerchantDAO; import com.panzhihua.service_community.entity.McsCoupon; import com.panzhihua.service_community.entity.McsGame; import com.panzhihua.service_community.entity.McsMerchant; import com.panzhihua.service_community.service.McsGameService; import com.panzhihua.service_community.util.QRCodeUtil; /** * (McsGame)表服务实现类 * * @author makejava * @since 2021-12-28 14:37:09 */ @Service("mcsGameService") public class McsGameServiceImpl extends ServiceImpl implements McsGameService { @Resource private McsMerchantDAO mcsMerchantDAO; @Resource private McsCouponDAO mcsCouponDAO; @Resource private McsEvaluateDAO mcsEvaluateDAO; /** * 分页查询戳戳游戏 * @param pageMcsGameDTO * @return */ @Override public R pageMcsGame(PageMcsGameDTO pageMcsGameDTO) { Page page = new Page<>(); page.setSize(pageMcsGameDTO.getPageSize()); page.setCurrent(pageMcsGameDTO.getPageNum()); IPage mcsGames = this.baseMapper.pageMcsGame(page, pageMcsGameDTO); return R.ok(mcsGames); } /** * 设为/取消游戏热门 * @param setPopularForGameDTO * @return */ @Override @Transactional(rollbackFor = Exception.class) public R setPopularForGame(SetPopularForGameDTO setPopularForGameDTO) { McsGame mcsGame = this.baseMapper.selectById(setPopularForGameDTO.getGameId()); if (isNull(mcsGame)) { return R.fail("修改数据不存在"); } Integer type = setPopularForGameDTO.getType(); if (type.equals(1)) { //设为热门 List popularGames = this.baseMapper.selectList(new QueryWrapper().lambda().eq(McsGame::getIsPopular, true)); if (nonNull(popularGames) && !popularGames.isEmpty()) { popularGames.forEach(e -> e.setIsPopular(false)); this.updateBatchById(popularGames); } mcsGame.setIsPopular(true); } else if (type.equals(2)) { //取消热门 mcsGame.setIsPopular(false); } else { return R.fail("未知错误"); } int num = this.baseMapper.updateById(mcsGame); if (num > 0) { return R.ok(); } return R.fail("修改失败,请重新尝试"); } /** * 上架/下架戳戳游戏 * @param setShelfForGameDTO * @return */ @Override public R setShelfForGame(SetShelfForGameDTO setShelfForGameDTO) { McsGame mcsGame = this.baseMapper.selectById(setShelfForGameDTO.getGameId()); if (isNull(mcsGame)) { return R.fail("修改数据不存在"); } Integer type = setShelfForGameDTO.getType(); if (type.equals(1)) { //上架 McsMerchant mcsMerchant = mcsMerchantDAO.selectById(mcsGame.getMerchantId()); Integer publishLimit = mcsMerchant.getPublishLimit(); Integer publishCount = this.baseMapper.selectPublishCount(mcsGame.getMerchantId()); if (publishCount >= publishLimit) { return R.fail("空闲戳戳点不足"); } mcsGame.setStatus(2); } else if (type.equals(2)) { //下架 mcsGame.setStatus(3); } else { return R.fail("未知错误"); } int num = this.baseMapper.updateById(mcsGame); if (num > 0) { return R.ok(); } return R.fail("修改失败,请重新尝试"); } /** * 删除戳戳游戏 * @param gameId * @param userId * @return */ @Override public R deleteMcsGame(Long gameId, Long userId) { McsGame mcsGame = this.baseMapper.selectById(gameId); if (isNull(mcsGame)) { return R.fail("修改数据不存在"); } mcsGame.setIsDel(true); mcsGame.setStatus(McsGame.Status.yxj); mcsGame.setUpdatedBy(userId); int num = this.baseMapper.updateById(mcsGame); if (num > 0) { return R.ok(); } return R.fail("删除失败,请重新尝试"); } /** * 新增戳戳游戏 * @param mcsGameDTO * @return */ @Override public R addMcsGame(McsGameDTO mcsGameDTO) { Long userId = mcsGameDTO.getCreatedBy(); McsMerchant mcsMerchant = mcsMerchantDAO.selectOne(new QueryWrapper().lambda().eq(McsMerchant::getUserId, userId)); if (isNull(mcsMerchant)) { return R.fail("未查询到商家信息"); } Integer type = mcsGameDTO.getType(); McsGame mcsGame = new McsGame(); if (type.equals(1)) { //1.戳戳币游戏 Integer allocation = mcsGameDTO.getAllocation(); Integer coins = mcsGameDTO.getCoins(); if (isNull(allocation)) { return R.fail("缺少分配方式"); } if (isNull(coins)) { return R.fail("未设置戳戳币额度"); } if (allocation.equals(1)) { mcsGame.setSurplusCoins(mcsGameDTO.getCoins()); } } else if (type.equals(2)) { //2.体验游戏 Integer awardType = mcsGameDTO.getAwardType(); if (isNull(awardType)) { return R.fail("缺少奖励类型"); } } else { return R.fail("未知错误"); } BeanUtils.copyProperties(mcsGameDTO, mcsGame); mcsGame.setSurplusCoupons(mcsGameDTO.getCoupons()); mcsGame.setStatus(McsGame.Status.wfb); mcsGame.setMerchantId(mcsMerchant.getId()); int num = this.baseMapper.insert(mcsGame); if (num > 0) { return R.ok(); } return R.fail("新增失败,请重新尝试"); } /** * 编辑戳戳游戏 * @param mcsGameDTO * @return */ @Override public R putMcsGame(McsGameDTO mcsGameDTO) { McsGame mcsGame = this.baseMapper.selectById(mcsGameDTO.getId()); if (isNull(mcsGame)) { return R.fail("资源不存在"); } Integer type = mcsGameDTO.getType(); if (type.equals(1)) { //1.戳戳币游戏 Integer allocation = mcsGameDTO.getAllocation(); Integer coins = mcsGameDTO.getCoins(); if (isNull(allocation)) { return R.fail("缺少分配方式"); } if (isNull(coins)) { return R.fail("未设置戳戳币额度"); } Integer beforeCoins = mcsGame.getCoins(); Integer beforeSurplusCoins = mcsGame.getSurplusCoins(); if (isNull(beforeSurplusCoins)) { beforeSurplusCoins = beforeCoins; } Integer beforeUsedCoins = beforeCoins - beforeSurplusCoins; Integer surplusCoins = coins - beforeUsedCoins; if (surplusCoins < 0) { return R.fail("戳戳币总额少于已发出的数量"); } mcsGame.setSurplusCoins(surplusCoins); } else if (type.equals(2)) { //2.体验游戏 Integer awardType = mcsGameDTO.getAwardType(); if (isNull(awardType)) { return R.fail("缺少奖励类型"); } } else { return R.fail("未知错误"); } Integer beforeCoupons = mcsGame.getCoupons(); Integer beforeSurplusCoupons = mcsGame.getSurplusCoupons(); Integer beforeUsedCoupons = beforeCoupons - beforeSurplusCoupons; BeanUtils.copyProperties(mcsGameDTO, mcsGame); Integer coupons = mcsGame.getCoupons(); Integer surplusCoupons = coupons - beforeUsedCoupons; if (surplusCoupons < 0) { return R.fail("卷总数少于已发出的数量"); } mcsGame.setSurplusCoupons(surplusCoupons); int num = this.baseMapper.updateById(mcsGame); if (num > 0) { return R.ok(); } return R.fail("编辑失败,请重新尝试"); } /** * 发布戳戳游戏 * @param gameId * @param userId * @return */ @Override public R publishMcsGame(Long gameId, Long userId) { McsGame mcsGame = this.baseMapper.selectById(gameId); if (isNull(mcsGame)) { return R.fail("资源不存在"); } McsMerchant mcsMerchant = mcsMerchantDAO.selectById(mcsGame.getMerchantId()); Integer publishLimit = mcsMerchant.getPublishLimit(); Integer publishCount = this.baseMapper.selectPublishCount(mcsGame.getMerchantId()); if (publishCount >= publishLimit) { return R.fail("空闲戳戳点不足"); } mcsGame.setStatus(McsGame.Status.jxz); mcsGame.setPublishAt(new Date()); mcsGame.setUpdatedBy(userId); int num = this.baseMapper.updateById(mcsGame); if (num > 0) { return R.ok(); } return R.fail("发布失败,请重新尝试"); } /** * 结束戳戳游戏 * @param gameId * @param userId * @return */ @Override public R finishMcsGame(Long gameId, Long userId) { McsGame mcsGame = this.baseMapper.selectById(gameId); if (isNull(mcsGame)) { return R.fail("资源不存在"); } mcsGame.setStatus(McsGame.Status.yjs); mcsGame.setUpdatedBy(userId); int num = this.baseMapper.updateById(mcsGame); if (num > 0) { return R.ok(); } return R.fail("结束失败,请重新尝试"); } /** * 戳戳游戏顶部统计数据 * @param userId * @param type * @return */ @Override public R getTopStatistics(Long userId, Integer type) { McsMerchant mcsMerchant = mcsMerchantDAO.selectOne(new QueryWrapper().lambda().eq(McsMerchant::getUserId, userId)); if (isNull(mcsMerchant)) { return R.fail("未查询到商家信息"); } TopStatisticsVO topStatisticsVO = new TopStatisticsVO(); topStatisticsVO.setExpireAt(mcsMerchant.getExpireAt()); if (nonNull(mcsMerchant.getExpireAt())) { int surplusLitDays = DateUtils.retrieveRemainingDays(mcsMerchant.getExpireAt()); topStatisticsVO.setSurplusLitDays(surplusLitDays > 0 ? surplusLitDays : 0); } Integer appliedCount = this.baseMapper.selectAppliedCount(mcsMerchant.getId(), type); topStatisticsVO.setAppliedTotal(appliedCount); Integer verifiedCount = this.baseMapper.selectVerifiedCount(mcsMerchant.getId(), type); topStatisticsVO.setVerifiedTotal(verifiedCount); Integer publishLimit = mcsMerchant.getPublishLimit(); Integer publishCount = this.baseMapper.selectPublishCount(mcsMerchant.getId()); Integer idleTotal = publishLimit - publishCount; topStatisticsVO.setIdleTotal(idleTotal > 0 ? idleTotal : 0); return R.ok(topStatisticsVO); } /** * 戳戳卷领取 * @param gameId * @param userId * @return */ @Override @Transactional(rollbackFor = Exception.class) public R applyMcsCoupon(Long gameId, Long userId) { McsGame mcsGame = this.baseMapper.selectById(gameId); if (isNull(mcsGame) || mcsGame.getIsDel()) { return R.fail("游戏已下架"); } Integer userAppliedCount = mcsCouponDAO.selectCount(new QueryWrapper().lambda().eq(McsCoupon::getGameId, gameId).eq(McsCoupon::getUserId, userId)); if (userAppliedCount > 0) { return R.fail("请勿重复领取"); } Integer surplusCoupons = mcsGame.getSurplusCoupons(); if (surplusCoupons <= 0) { return R.fail("抢光了"); } McsCoupon mcsCoupon = new McsCoupon(); Long snowflakeId = Snowflake.getId(); mcsCoupon.setId(snowflakeId); mcsCoupon.setGameId(gameId); mcsCoupon.setUserId(userId); mcsCoupon.setQrCode(QRCodeUtil.getBase64QRCode(snowflakeId.toString())); Integer type = mcsGame.getType(); if (type.equals(1)) { //戳戳币游戏 Integer allocation = mcsGame.getAllocation(); if (allocation.equals(1)) { //随机分配 Integer surplusCoins = mcsGame.getSurplusCoins(); Integer coin = getRandomCoins(surplusCoins, mcsGame.getSurplusCoupons()); mcsCoupon.setCoin(coin); mcsCoupon.setAward("戳戳币:" + coin); mcsGame.setSurplusCoins(surplusCoins - coin); } else { //固定值 mcsCoupon.setCoin(mcsGame.getCoins()); mcsCoupon.setAward("戳戳币:" + mcsGame.getCoins()); } } else { //体验游戏 Integer awardType = mcsGame.getAwardType(); if (awardType.equals(1)) { mcsCoupon.setAward("免费领"); } else if (awardType.equals(2)) { mcsCoupon.setAward("产品试用"); } else if (awardType.equals(3)) { mcsCoupon.setAward("消费赠礼"); } else { mcsCoupon.setAward("优惠券"); } } int num = mcsCouponDAO.insert(mcsCoupon); if (num > 0) { mcsGame.setSurplusCoupons(surplusCoupons - 1); this.baseMapper.updateById(mcsGame); McsCouponVO mcsCouponVO = new McsCouponVO(); mcsCouponVO.setId(snowflakeId); mcsCouponVO.setIsVerified(false); mcsCouponVO.setQrCode(mcsCoupon.getQrCode()); mcsCouponVO.setAward(mcsCoupon.getAward()); return R.ok(mcsCouponVO); } return R.fail("领取失败,请重试"); } /** * h5分页查询戳戳游戏 * @param pageMcsGameDTO * @return */ @Override public R pageH5McsGame(PageMcsGameDTO pageMcsGameDTO) { Page page = new Page<>(); page.setSize(pageMcsGameDTO.getPageSize()); page.setCurrent(pageMcsGameDTO.getPageNum()); IPage mcsGames = this.baseMapper.pageH5McsGame(page, pageMcsGameDTO); return R.ok(mcsGames); } /** * 游戏详情 * @param gameId * @return */ @Override public R getMcsGame(Long gameId) { McsGameVO mcsGameVO = this.baseMapper.selectDetailById(gameId); Integer gameCount = this.baseMapper.selectCount(new QueryWrapper().lambda() .eq(McsGame::getMerchantId, mcsGameVO.getMerchantId()).eq(McsGame::getStatus, McsGame.Status.jxz) .eq(McsGame::getType, mcsGameVO.getType()).eq(McsGame::getIsDel, false)); mcsGameVO.setGameCount(gameCount); return R.ok(mcsGameVO); } /** * 定时任务-每隔5分钟执行一次,将已到期的微商业街游戏结束 * @return */ @Override public R endStatusForMcsGame() { List games = this.baseMapper.selectNeedDealExpire(); if (nonNull(games) && !games.isEmpty()) { games.forEach(e -> e.setStatus(McsGame.Status.yjs)); this.updateBatchById(games); } return R.ok(); } public static void main(String[] args) { int total = 500; int people = 10; for (int i = 1;i <= 10; i++) { Integer decrease = getRandomCoins(total, people); total -= decrease; people --; System.out.println("第:" + i + "个人领取到:" + decrease + "戳戳币,总数还剩下:" + total); } } public static Integer getRandomCoins(int totalCoins, int peopleTotal) { List list = new ArrayList<>(peopleTotal); if (peopleTotal == 1) { return totalCoins; } Random random = new Random(); // 平均分配 int average = totalCoins / peopleTotal; int max = (int) Math.floor(totalCoins * 0.6); int min = (int) Math.floor(average * 0.5); float thresh = 0.95F; int rest = totalCoins - average * peopleTotal; for (int i = 0; i < peopleTotal; i++) { if (i < rest) { list.add(average + 1); } else { list.add(average); } } // 根据阀值进行数据随机处理 int randOfRange = 0; int randRom = 0; int nextIndex = 0; int nextValue = 0; //多余 int surplus = 0; //缺少 int lack = 0; for (int i = 0; i < peopleTotal - 1; i++) { nextIndex = i + 1; int itemThis = list.get(i); int itemNext = list.get(nextIndex); boolean isLt = itemThis < itemNext; int rangeThis = isLt ? max - itemThis : itemThis - min; int rangeNext = isLt ? itemNext - min : max - itemNext; int rangeFinal = (int) Math.ceil(thresh * (Math.min(rangeThis, rangeNext) + 1)); randOfRange = random.nextInt(rangeFinal); randRom = isLt ? 1 : -1; int iValue = list.get(i) + randRom * randOfRange; nextValue = list.get(nextIndex) + randRom * randOfRange * -1; if (iValue > max) { surplus += (iValue - max); list.set(i, max); } else if (iValue < min) { list.set(i, min); lack += (min - iValue); } else { list.set(i, iValue); } list.set(nextIndex, nextValue); } if (nextValue > max) { surplus += (nextValue - max); list.set(nextIndex, max); } if (nextValue < min) { lack += (min - nextValue); list.set(nextIndex, min); } if (surplus - lack > 0) { //分少了 给低于max的凑到max for (int i = 0; i < list.size(); i++) { int value = list.get(i); if (value < max) { int tmp = max - value; if (surplus >= tmp) { surplus -= tmp; list.set(i, max); } else { list.set(i, value + surplus); return list.get(random.nextInt(list.size() - 1)); } } } } else if (lack - surplus > 0) { //分多了 给超过高于min的人凑到min for (int i = 0; i < list.size(); i++) { int value = list.get(i); if (value > min) { int tmp = value - min; if (lack >= tmp) { lack -= tmp; list.set(i, min); } else { list.set(i, min + tmp - lack); return list.get(random.nextInt(list.size() - 1)); } } } } return list.get(random.nextInt(list.size() - 1)); } }