卷轴模式系统包含的主要功能:
系统客户端:
客户端:
APP端
设计上开发2个APP。一个是商城购物APP,一个是任务包APP,这样方便业务流程更清晰,产品体验使用上简单易操作。
H5客户端
功能用于分享邀请码推广、注册账户、链接APP下载地址
卷轴模式任务模型命名定义
入门赠送任务,不同等级的任务设置。一般默认设置为5到7个等级任务类型。在不同的电商平台和O2O项目里有不同名称类型。例如做通信类产品的,以流量包任务来呈现。做健康领域产业的以健康包来表示,做农业种植业行业的的以农作物,经济类作物命名,做旅游产业的以为旅行线路套餐来命名。下面我举一些例子让任务包名称更具形象化。
电商购物:初级购物包,中级购物包,进阶购物包,高级购物包,精英购物包
消费积分:初级积分包,中级积分包,进阶积分包,高级积分包,精英积分包,超级积分包,王者积分包
景区任务:新人任务,旅游任务,门票任务,景区任务,酒店任务,渠道任务
消费包:初级,低级,中级,高级,达人,富人。农场系列:苹果树,香蕉树,柿子树,石榴树,荔枝树,芒果树,山竹,车厘子,榴莲树。
卷轴任务包的实例设计
我们以农场系列的香蕉树来举例:香蕉树,兑换所需数量(果粒值)10个,初始任务每日可得果粒值为0.4个,起始周期30天,总收益12颗,有效期90天,最多持有任务数量12天,活跃度1个,兑换任务完成后复做任务产出周期增加数量为1天,获得奖励单位是果粒值。其中每日可得果粒值是12个除以30天计算出来的。
卷轴任务包核心源码
@RestController public class VideoController { @Autowired private StringRedisTemplate redisTemplate; @PostMapping("/watchVideo") public Map<String, Object> watchVideo(@RequestParam Long uid) { Map<String, Object> result = new HashMap<>(); // 1. 检查缓存锁 String cacheKey = "cache_purchase_" + uid; Boolean lock = redisTemplate.opsForValue() .setIfAbsent(cacheKey, "1", 2, TimeUnit.SECONDS); if (Boolean.FALSE.equals(lock)) { result.put("code", 500054); result.put("msg", "操作过于频繁"); return result; } try { // 2. 获取用户信息(这里简化,实际需要从数据库查询) User user = getUserFromDatabase(uid); // 3. 检查任务次数 if (user.getTask() >= 5) { result.put("code", 200); result.put("msg", "任务已完成"); return result; } // 4. 更新任务次数 int newTaskCount = user.getTask() + 1; updateUserTask(uid, newTaskCount); // 5. 如果达到5次,发放奖励 if (newTaskCount == 5) { sendReward(uid); } result.put("code", 200); result.put("msg", "成功"); return result; } catch (Exception e) { result.put("code", 500); result.put("msg", "系统错误"); return result; } } private User getUserFromDatabase(Long uid) { // 从数据库查询用户 // 实现数据库查询逻辑 return new User(); // 示例 } private void updateUserTask(Long uid, int newTaskCount) { // 更新数据库中的任务次数 // 实现数据库更新逻辑 } private void sendReward(Long uid) { // 发放奖励逻辑 } }任务领取代码
@Service @Transactional(rollbackFor = Exception.class) public class TaskService { @Autowired private UserTaskNotesMapper userTaskNotesMapper; @Autowired private FudouService fudouService; @Autowired private UserService userService; @Autowired private UserMapper userMapper; /** * 获取累积笔记(积分释放) * @param uid 用户ID * @return 操作结果 */ public boolean getLjNotes(Long uid) { return TransactionSynchronizationManager.isActualTransactionActive() ? executeInTransaction(uid) : executeWithNewTransaction(uid); } /** * 在现有事务中执行 */ private boolean executeInTransaction(Long uid) { try { return processLjNotes(uid); } catch (Exception e) { throw new BusinessException("领取失败", e); } } /** * 开启新事务执行 */ @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW) public boolean executeWithNewTransaction(Long uid) { try { return processLjNotes(uid); } catch (Exception e) { throw new BusinessException("领取失败", e); } } /** * 处理累积笔记的核心逻辑 */ private boolean processLjNotes(Long uid) { // 1. 获取该释放的所有积分 BigDecimal allJifen = userTaskNotesMapper.sumNumByCondition(uid, 1, 1); if (allJifen == null || allJifen.compareTo(BigDecimal.ZERO) <= 0) { return false; } // 2. 增加用户fudou余额 boolean res1 = userService.bcInc(uid, "fudou", allJifen, 4); // 3. 创建fudou记录 Fudou fudou = new Fudou(); fudou.setUid(uid); fudou.setType(5); fudou.setNum(allJifen); fudou.setPm(1); fudou.setLinkId(0L); fudou.setAddTime(LocalDateTime.now()); fudou.setLevel(66); boolean res2 = fudouService.save(fudou); // 4. 更新记录为释放状态 boolean res3 = userTaskNotesMapper.updateStatusByCondition(uid, 1, 1, 2) > 0; // 5. 重置用户lj_num boolean res4 = userService.update(uid, Map.of("lj_num", BigDecimal.ZERO)); if (res1 && res2 && res3 && res4) { return true; } else { throw new BusinessException("领取失败"); } } }