|
@@ -11,11 +11,13 @@ import com.fs.common.core.domain.R;
|
|
|
import com.fs.common.core.page.PageRequest;
|
|
import com.fs.common.core.page.PageRequest;
|
|
|
import com.fs.common.core.page.TableDataInfo;
|
|
import com.fs.common.core.page.TableDataInfo;
|
|
|
import com.fs.common.core.redis.RedisCache;
|
|
import com.fs.common.core.redis.RedisCache;
|
|
|
|
|
+import com.fs.common.utils.StringUtils;
|
|
|
import com.fs.live.domain.*;
|
|
import com.fs.live.domain.*;
|
|
|
import com.fs.framework.aspectj.lock.DistributeLock;
|
|
import com.fs.framework.aspectj.lock.DistributeLock;
|
|
|
import com.fs.live.param.CouponPO;
|
|
import com.fs.live.param.CouponPO;
|
|
|
import com.fs.live.param.LotteryPO;
|
|
import com.fs.live.param.LotteryPO;
|
|
|
import com.fs.live.param.RedPO;
|
|
import com.fs.live.param.RedPO;
|
|
|
|
|
+import com.fs.live.param.SignPO;
|
|
|
import com.fs.live.service.*;
|
|
import com.fs.live.service.*;
|
|
|
import com.fs.live.vo.*;
|
|
import com.fs.live.vo.*;
|
|
|
import com.github.pagehelper.PageInfo;
|
|
import com.github.pagehelper.PageInfo;
|
|
@@ -62,6 +64,24 @@ public class LiveFacadeServiceImpl extends BaseController implements LiveFacadeS
|
|
|
@Autowired
|
|
@Autowired
|
|
|
private ILiveConsoleOpLogService liveConsoleOpLogService;
|
|
private ILiveConsoleOpLogService liveConsoleOpLogService;
|
|
|
|
|
|
|
|
|
|
+ @Autowired
|
|
|
|
|
+ private ILiveSignRecordService liveSignRecordService;
|
|
|
|
|
+
|
|
|
|
|
+ @Autowired
|
|
|
|
|
+ private ILiveAutoTaskService liveAutoTaskService;
|
|
|
|
|
+
|
|
|
|
|
+ @Autowired
|
|
|
|
|
+ private ILiveCouponIssueService liveCouponIssueService;
|
|
|
|
|
+
|
|
|
|
|
+ @Autowired
|
|
|
|
|
+ private com.fs.his.service.IFsUserService fsUserService;
|
|
|
|
|
+
|
|
|
|
|
+ @Autowired
|
|
|
|
|
+ private com.fs.his.service.IFsStorePaymentService paymentService;
|
|
|
|
|
+
|
|
|
|
|
+ @Autowired
|
|
|
|
|
+ private ILiveRewardRecordService liveRewardRecordService;
|
|
|
|
|
+
|
|
|
@Override
|
|
@Override
|
|
|
public R liveList(PageRequest pageRequest) {
|
|
public R liveList(PageRequest pageRequest) {
|
|
|
int start = (pageRequest.getCurrentPage() - 1) * pageRequest.getPageSize();
|
|
int start = (pageRequest.getCurrentPage() - 1) * pageRequest.getPageSize();
|
|
@@ -286,6 +306,258 @@ public class LiveFacadeServiceImpl extends BaseController implements LiveFacadeS
|
|
|
return vo;
|
|
return vo;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 直播签到领取:写 live_sign_record 防重,再按 rewards 发奖并绑定留存。
|
|
|
|
|
+ * 金额红包成功时返回 package 等字段,供 App 跳转微信确认收款。
|
|
|
|
|
+ */
|
|
|
|
|
+ @Override
|
|
|
|
|
+ @DistributeLock(keyExpression = "#sign.liveId +'_'+#userId +'_'+#sign.signNo", scene = "live_sign_claim", waitTime = 1000, errorMsg = "签到处理中,请稍后")
|
|
|
|
|
+ public R signClaim(SignPO sign, Long userId) {
|
|
|
|
|
+ if (sign == null || sign.getLiveId() == null || StringUtils.isEmpty(sign.getSignNo())) {
|
|
|
|
|
+ return R.error("签到参数不完整");
|
|
|
|
|
+ }
|
|
|
|
|
+ Long liveId = sign.getLiveId();
|
|
|
|
|
+ String signNo = String.valueOf(sign.getSignNo());
|
|
|
|
|
+
|
|
|
|
|
+ // 防重复签到
|
|
|
|
|
+ LiveSignRecord existQuery = new LiveSignRecord();
|
|
|
|
|
+ existQuery.setLiveId(liveId);
|
|
|
|
|
+ existQuery.setUserId(userId);
|
|
|
|
|
+ existQuery.setSignNo(signNo);
|
|
|
|
|
+ List<LiveSignRecord> exists = liveSignRecordService.selectLiveSignRecordList(existQuery);
|
|
|
|
|
+ if (CollUtil.isNotEmpty(exists)) {
|
|
|
|
|
+ return R.error("您已完成该次签到");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 从触发缓存取奖励留存;没有则从已执行签到任务解析
|
|
|
|
|
+ List<com.alibaba.fastjson.JSONObject> rewards = resolveSignRewards(liveId, signNo, sign.getTaskId());
|
|
|
|
|
+ if (CollUtil.isEmpty(rewards)) {
|
|
|
|
|
+ return R.error("签到任务尚未开启或奖励配置不存在");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 写入签到记录
|
|
|
|
|
+ LiveSignRecord record = new LiveSignRecord();
|
|
|
|
|
+ record.setLiveId(liveId);
|
|
|
|
|
+ record.setUserId(userId);
|
|
|
|
|
+ record.setSignNo(signNo);
|
|
|
|
|
+ record.setCreateTime(new Date());
|
|
|
|
|
+ liveSignRecordService.save(record);
|
|
|
|
|
+
|
|
|
|
|
+ List<Map<String, Object>> claimResults = new ArrayList<>();
|
|
|
|
|
+ for (com.alibaba.fastjson.JSONObject item : rewards) {
|
|
|
|
|
+ Long rewardType = item.getLong("rewardType");
|
|
|
|
|
+ Long opLogId = item.getLong("opLogId");
|
|
|
|
|
+ Map<String, Object> one = new HashMap<>();
|
|
|
|
|
+ one.put("rewardType", rewardType);
|
|
|
|
|
+ one.put("opLogId", opLogId);
|
|
|
|
|
+ try {
|
|
|
|
|
+ if (rewardType != null && rewardType == 2L) {
|
|
|
|
|
+ // 积分红包:走直播积分红包领取
|
|
|
|
|
+ RedPO red = new RedPO();
|
|
|
|
|
+ red.setLiveId(liveId);
|
|
|
|
|
+ red.setUserId(userId);
|
|
|
|
|
+ red.setRedId(item.getLong("rewardId"));
|
|
|
|
|
+ red.setOpLogId(opLogId);
|
|
|
|
|
+ R r = iLiveRedConfService.claimRedPacket(red);
|
|
|
|
|
+ one.put("success", Integer.valueOf(200).equals(r.get("code")));
|
|
|
|
|
+ one.put("msg", r.get("msg"));
|
|
|
|
|
+ } else if (rewardType != null && rewardType == 5L) {
|
|
|
|
|
+ // 优惠券:按配置张数发放
|
|
|
|
|
+ CouponPO coupon = new CouponPO();
|
|
|
|
|
+ coupon.setLiveId(liveId);
|
|
|
|
|
+ coupon.setUserId(userId);
|
|
|
|
|
+ Long couponIssueId = item.getLong("couponIssueId");
|
|
|
|
|
+ if (couponIssueId == null) {
|
|
|
|
|
+ Long couponId = item.getLong("rewardId");
|
|
|
|
|
+ LiveCouponIssue issue = liveCouponIssueService.selectIssueByLiveIdAndCouponId(liveId, couponId);
|
|
|
|
|
+ couponIssueId = issue != null ? issue.getId() : null;
|
|
|
|
|
+ }
|
|
|
|
|
+ coupon.setCouponIssueId(couponIssueId);
|
|
|
|
|
+ coupon.setGoodsId(item.getLong("goodsId"));
|
|
|
|
|
+ coupon.setOpLogId(opLogId);
|
|
|
|
|
+ Integer couponCount = item.getInteger("couponCount");
|
|
|
|
|
+ coupon.setCouponCount(couponCount != null && couponCount > 0 ? couponCount : 1);
|
|
|
|
|
+ R r = iLiveCouponService.claimCoupon(coupon);
|
|
|
|
|
+ one.put("success", Integer.valueOf(200).equals(r.get("code")));
|
|
|
|
|
+ one.put("msg", r.get("msg"));
|
|
|
|
|
+ one.put("couponCount", coupon.getCouponCount());
|
|
|
|
|
+ if (r.get("opLogId") != null) {
|
|
|
|
|
+ one.put("opLogId", r.get("opLogId"));
|
|
|
|
|
+ }
|
|
|
|
|
+ } else if (rewardType != null && rewardType == 6L) {
|
|
|
|
|
+ // 金额红包:微信商家转账,App 用返回参数确认收款
|
|
|
|
|
+ R r = claimSignCashRed(liveId, userId, item, sign);
|
|
|
|
|
+ one.put("success", Integer.valueOf(200).equals(r.get("code")));
|
|
|
|
|
+ one.put("msg", r.get("msg"));
|
|
|
|
|
+ // App 调起微信确认收款所需字段
|
|
|
|
|
+ if (Integer.valueOf(200).equals(r.get("code"))) {
|
|
|
|
|
+ one.put("needWxConfirm", true);
|
|
|
|
|
+ one.put("package", r.get("package"));
|
|
|
|
|
+ one.put("mchId", r.get("mchId"));
|
|
|
|
|
+ one.put("appId", r.get("appId"));
|
|
|
|
|
+ one.put("orderCode", r.get("orderCode"));
|
|
|
|
|
+ one.put("amount", item.getBigDecimal("amount"));
|
|
|
|
|
+ if (opLogId != null) {
|
|
|
|
|
+ liveConsoleOpLogService.bindOpLogUser(opLogId, liveId, userId);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ } else {
|
|
|
|
|
+ one.put("success", false);
|
|
|
|
|
+ one.put("msg", "不支持的奖励类型");
|
|
|
|
|
+ }
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ log.error("签到领取奖励失败, liveId={}, userId={}, rewardType={}", liveId, userId, rewardType, e);
|
|
|
|
|
+ one.put("success", false);
|
|
|
|
|
+ one.put("msg", "领取失败");
|
|
|
|
|
+ }
|
|
|
|
|
+ claimResults.add(one);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ boolean anySuccess = claimResults.stream().anyMatch(m -> Boolean.TRUE.equals(m.get("success")));
|
|
|
|
|
+ return R.ok(anySuccess ? "签到成功" : "签到成功,但奖励领取失败")
|
|
|
|
|
+ .put("signNo", signNo)
|
|
|
|
|
+ .put("rewards", claimResults);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 签到金额红包:发起微信商家转账(金额精确到 0.1 元)。
|
|
|
|
|
+ * 成功时返回 package/mchId/appId/orderCode,供 App 跳转微信确认收款。
|
|
|
|
|
+ */
|
|
|
|
|
+ private R claimSignCashRed(Long liveId, Long userId, com.alibaba.fastjson.JSONObject item, SignPO sign) {
|
|
|
|
|
+ java.math.BigDecimal amount = item.getBigDecimal("amount");
|
|
|
|
|
+ if (amount == null || amount.compareTo(java.math.BigDecimal.ZERO) <= 0) {
|
|
|
|
|
+ return R.error("金额红包配置无效");
|
|
|
|
|
+ }
|
|
|
|
|
+ Live live = liveService.selectLiveByLiveId(liveId);
|
|
|
|
|
+ if (live == null) {
|
|
|
|
|
+ return R.error("直播间不存在");
|
|
|
|
|
+ }
|
|
|
|
|
+ com.fs.his.domain.FsUser user = fsUserService.selectFsUserById(userId);
|
|
|
|
|
+ if (user == null) {
|
|
|
|
|
+ return R.error("用户不存在");
|
|
|
|
|
+ }
|
|
|
|
|
+ if (live.getCompanyId() == null) {
|
|
|
|
|
+ return R.error("直播间未绑定公司,无法发放金额红包");
|
|
|
|
|
+ }
|
|
|
|
|
+ String openId = null;
|
|
|
|
|
+ if (sign != null && sign.getSource() != null && sign.getSource() == 2
|
|
|
|
|
+ && StringUtils.isNotEmpty(user.getCourseMaOpenId())) {
|
|
|
|
|
+ openId = user.getCourseMaOpenId();
|
|
|
|
|
+ } else if (StringUtils.isNotEmpty(user.getMpOpenId())) {
|
|
|
|
|
+ openId = user.getMpOpenId();
|
|
|
|
|
+ } else if (StringUtils.isNotEmpty(user.getCourseMaOpenId())) {
|
|
|
|
|
+ openId = user.getCourseMaOpenId();
|
|
|
|
|
+ }
|
|
|
|
|
+ if (StringUtils.isEmpty(openId)) {
|
|
|
|
|
+ return R.error("请使用微信登录后再领取金额红包");
|
|
|
|
|
+ }
|
|
|
|
|
+ com.fs.his.param.WxSendRedPacketParam packetParam = new com.fs.his.param.WxSendRedPacketParam();
|
|
|
|
|
+ packetParam.setOpenId(openId);
|
|
|
|
|
+ packetParam.setAmount(amount.setScale(1, java.math.RoundingMode.HALF_UP));
|
|
|
|
|
+ packetParam.setCompanyId(live.getCompanyId());
|
|
|
|
|
+ packetParam.setSource(sign != null && sign.getSource() != null ? sign.getSource() : 1);
|
|
|
|
|
+ packetParam.setAppId(sign != null ? sign.getAppId() : null);
|
|
|
|
|
+ packetParam.setRedPacketMode(1);
|
|
|
|
|
+ packetParam.setUser(user);
|
|
|
|
|
+ try {
|
|
|
|
|
+ R sendResult = paymentService.sendRedPacket(packetParam);
|
|
|
|
|
+ if (!Integer.valueOf(200).equals(sendResult.get("code"))) {
|
|
|
|
|
+ return sendResult;
|
|
|
|
|
+ }
|
|
|
|
|
+ // 写入直播奖励流水(现金,来源类型 7=签到)
|
|
|
|
|
+ try {
|
|
|
|
|
+ LiveRewardRecord rewardRecord = new LiveRewardRecord();
|
|
|
|
|
+ rewardRecord.setLiveId(liveId);
|
|
|
|
|
+ rewardRecord.setUserId(userId);
|
|
|
|
|
+ rewardRecord.setRewardType(1L);
|
|
|
|
|
+ rewardRecord.setNum(amount);
|
|
|
|
|
+ rewardRecord.setIncomeType(1L);
|
|
|
|
|
+ rewardRecord.setSourceType(7L);
|
|
|
|
|
+ rewardRecord.setSourceId(live.getCompanyId() != null ? live.getCompanyId() : 0L);
|
|
|
|
|
+ rewardRecord.setCreateBy(String.valueOf(userId));
|
|
|
|
|
+ liveRewardRecordService.insertLiveRewardRecord(rewardRecord);
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ log.warn("签到金额红包流水写入失败, liveId={}, userId={}", liveId, userId, e);
|
|
|
|
|
+ }
|
|
|
|
|
+ return sendResult;
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ log.error("签到金额红包发放失败, liveId={}, userId={}, amount={}", liveId, userId, amount, e);
|
|
|
|
|
+ return R.error("金额红包发放失败:" + e.getMessage());
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 解析本次签到可领取奖励:优先读触发后 Redis 缓存(含 opLogId),否则回落已执行签到任务 content.rewards。
|
|
|
|
|
+ */
|
|
|
|
|
+ private List<com.alibaba.fastjson.JSONObject> resolveSignRewards(Long liveId, String signNo, Long taskId) {
|
|
|
|
|
+ List<com.alibaba.fastjson.JSONObject> rewards = new ArrayList<>();
|
|
|
|
|
+ try {
|
|
|
|
|
+ Object cache = redisCache.getCacheObject(String.format(LiveKeysConstant.LIVE_SIGN_OP_LOGS, liveId, signNo));
|
|
|
|
|
+ if (cache != null) {
|
|
|
|
|
+ com.alibaba.fastjson.JSONObject data = JSON.parseObject(String.valueOf(cache));
|
|
|
|
|
+ if (data != null && data.getJSONArray("rewards") != null) {
|
|
|
|
|
+ com.alibaba.fastjson.JSONArray arr = data.getJSONArray("rewards");
|
|
|
|
|
+ for (int i = 0; i < arr.size(); i++) {
|
|
|
|
|
+ rewards.add(arr.getJSONObject(i));
|
|
|
|
|
+ }
|
|
|
|
|
+ if (!rewards.isEmpty()) {
|
|
|
|
|
+ return rewards;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ log.warn("读取签到奖励缓存失败, liveId={}, signNo={}", liveId, signNo, e);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ LiveAutoTask task = null;
|
|
|
|
|
+ if (taskId != null) {
|
|
|
|
|
+ task = liveAutoTaskService.selectLiveAutoTaskById(taskId);
|
|
|
|
|
+ }
|
|
|
|
|
+ if (task == null) {
|
|
|
|
|
+ LiveAutoTask query = new LiveAutoTask();
|
|
|
|
|
+ query.setLiveId(liveId);
|
|
|
|
|
+ query.setTaskType(7L);
|
|
|
|
|
+ query.setFinishStatus(1L);
|
|
|
|
|
+ List<LiveAutoTask> tasks = liveAutoTaskService.selectLiveAutoTaskList(query);
|
|
|
|
|
+ if (CollUtil.isNotEmpty(tasks)) {
|
|
|
|
|
+ for (LiveAutoTask t : tasks) {
|
|
|
|
|
+ if (t.getContent() == null) {
|
|
|
|
|
+ continue;
|
|
|
|
|
+ }
|
|
|
|
|
+ try {
|
|
|
|
|
+ com.alibaba.fastjson.JSONObject c = JSON.parseObject(t.getContent());
|
|
|
|
|
+ if (c != null && signNo.equals(String.valueOf(c.get("signNo")))) {
|
|
|
|
|
+ task = t;
|
|
|
|
|
+ break;
|
|
|
|
|
+ }
|
|
|
|
|
+ } catch (Exception ignored) {
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ if (task == null || task.getContent() == null) {
|
|
|
|
|
+ return rewards;
|
|
|
|
|
+ }
|
|
|
|
|
+ try {
|
|
|
|
|
+ com.alibaba.fastjson.JSONObject content = JSON.parseObject(task.getContent());
|
|
|
|
|
+ com.alibaba.fastjson.JSONArray arr = content.getJSONArray("rewards");
|
|
|
|
|
+ if (arr != null) {
|
|
|
|
|
+ for (int i = 0; i < arr.size(); i++) {
|
|
|
|
|
+ rewards.add(arr.getJSONObject(i));
|
|
|
|
|
+ }
|
|
|
|
|
+ } else if (content.getLong("rewardType") != null) {
|
|
|
|
|
+ com.alibaba.fastjson.JSONObject single = new com.alibaba.fastjson.JSONObject();
|
|
|
|
|
+ single.put("rewardType", content.getLong("rewardType"));
|
|
|
|
|
+ single.put("rewardId", content.getLong("rewardId"));
|
|
|
|
|
+ single.put("reward", content.get("reward"));
|
|
|
|
|
+ rewards.add(single);
|
|
|
|
|
+ }
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ log.error("解析签到任务奖励失败, taskId={}", task.getId(), e);
|
|
|
|
|
+ }
|
|
|
|
|
+ return rewards;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
private Long resolveLiveDuration(Long liveId) {
|
|
private Long resolveLiveDuration(Long liveId) {
|
|
|
if (liveId == null) {
|
|
if (liveId == null) {
|
|
|
return 0L;
|
|
return 0L;
|