初始化天卡开放平台后端项目

包含完整功能模块:
- 设备激活(直销激活码模式 + 代销免激活码模式)
- 微信支付 + 天卡订单
- 天卡池管理 + 异步橘视厅SDK激活
- 第三方合作伙伴接口(代销模式)
  - 签名鉴权(appKey/appSecret + nonce防重放)
  - 天卡消耗(事务 + 幂等 + 并发控制)
  - 媒资接口(三级授权过滤)
  - 审计日志
- 定价策略(3层:门店 > 渠道 > 平台)
- 分账(微信分账 + 分润规则)
- Docker部署(含Redis容器)
This commit is contained in:
zhaogd
2026-07-26 12:34:13 +08:00
commit 30198c7191
349 changed files with 28837 additions and 0 deletions
@@ -0,0 +1,100 @@
package io.as.modules.openapi.controller;
import io.as.common.utils.IPUtils;
import io.as.common.utils.R;
import io.as.modules.openapi.filter.PartnerSignFilter;
import io.as.modules.openapi.service.OpenApiCallLogService;
import io.as.modules.openapi.service.PartnerCardPoolService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.Map;
/**
* 开放API - 合作伙伴天卡接口(代销模式,appKey/appSecret 签名鉴权)
* <p>第三方EPG调消耗接口:从partner池子分配天卡绑定设备,APK后续用同一设备标识调init/checkBenefits播放</p>
*/
@Api(tags = "开放API-天卡(代销)")
@RestController
@RequestMapping("/openapi/partner/card")
public class OpenApiPartnerCardController {
private static final Logger logger = LoggerFactory.getLogger(OpenApiPartnerCardController.class);
@Autowired
private PartnerCardPoolService partnerCardPoolService;
@Autowired
private OpenApiCallLogService openApiCallLogService;
/**
* 消耗天卡(代销模式)
* <p>第三方EPG客人付费后调用,从partner池子分配1张天卡绑定到设备,异步激活。</p>
* <p>APK后续用同一设备标识调 /api/jst/init(免activationCode)+ checkBenefits 拿天卡播放。</p>
*
* @param body {mac, deviceUid, deviceSn, channelOrgId}
*/
@ApiOperation("消耗天卡(代销)")
@PostMapping("/consume")
public R consume(@RequestBody Map<String, Object> body, HttpServletRequest req) {
long start = System.currentTimeMillis();
String partnerId = (String) req.getAttribute(PartnerSignFilter.REQUEST_ATTR_PARTNER_ID);
String mac = body.get("mac") != null ? String.valueOf(body.get("mac")) : null;
String wifiMac = body.get("wifiMac") != null ? String.valueOf(body.get("wifiMac")) : null;
String deviceUid = body.get("deviceUid") != null ? String.valueOf(body.get("deviceUid")) : null;
String deviceSn = body.get("deviceSn") != null ? String.valueOf(body.get("deviceSn")) : null;
Long channelOrgId = body.get("channelOrgId") != null ? Long.valueOf(String.valueOf(body.get("channelOrgId"))) : null;
// 构建审计参数(记录设备标识,用于溯源)
String auditParams = "mac=" + mac + ",wifiMac=" + wifiMac + ",deviceSn=" + deviceSn + ",deviceUid=" + deviceUid;
int resultCode = 0;
try {
Map<String, Object> result = partnerCardPoolService.consume(partnerId, mac, wifiMac, deviceUid, deviceSn, channelOrgId);
return R.dataSuccess(result);
} catch (Exception e) {
resultCode = e instanceof io.as.common.exception.ASException ? ((io.as.common.exception.ASException) e).getCode() : 500;
throw e;
} finally {
logCall(req, "/card/consume", "POST", auditParams, resultCode, start);
}
}
/**
* 查询我的天卡库存
*/
@ApiOperation("我的天卡库存")
@GetMapping("/stock")
public R stock(HttpServletRequest req) {
long start = System.currentTimeMillis();
int resultCode = 0;
try {
String partnerId = (String) req.getAttribute(PartnerSignFilter.REQUEST_ATTR_PARTNER_ID);
int available = partnerCardPoolService.getAvailableCount(partnerId);
Map<String, Object> data = new HashMap<>();
data.put("available", available);
return R.dataSuccess(data);
} catch (Exception e) {
resultCode = 500;
throw e;
} finally {
logCall(req, "/card/stock", "GET", null, resultCode, start);
}
}
private void logCall(HttpServletRequest req, String api, String method, String params, int resultCode, long startMs) {
try {
String partnerId = (String) req.getAttribute(PartnerSignFilter.REQUEST_ATTR_PARTNER_ID);
String appKey = (String) req.getAttribute(PartnerSignFilter.REQUEST_ATTR_APP_KEY);
String ip = IPUtils.getIpAddr(req);
int costMs = (int) (System.currentTimeMillis() - startMs);
openApiCallLogService.saveLog(partnerId, appKey, "/openapi/partner" + api, method, params, resultCode, ip, costMs);
} catch (Exception e) {
logger.warn("调用日志记录失败: {}", e.getMessage());
}
}
}