feat(phase2): 数据回传聚合与可信分账(F09/F18)
- internal/playback: 播放事件存储/MA码维度聚合/分账结算(CP60/平台34/服务费6) - service: ReportPlayback(链上状态门禁)/PlaybackSummary/ComputeSettlement - api: /data/playback, /data/playback-summary, /settlement/compute - 分账取余兜底无丢分; 未知/已下架MA码回传被拒 - 13项新测试通过; 端到端验证: 回传3条→聚合40元→分账24/13.6/2.4
This commit is contained in:
@@ -4,6 +4,7 @@ package api
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/tcs-iptv/tcs/internal/chain"
|
||||
@@ -42,6 +43,9 @@ func (h *Handler) Register(rg *gin.RouterGroup) {
|
||||
rg.GET("/content/episodes", h.listEpisodes) // 列出集级哈希
|
||||
rg.GET("/content/reviews", h.listReviews) // 送审待办队列(待审/待发码)
|
||||
rg.GET("/content/list", h.listContents) // 内容队列(待入库/待发布/待注入)
|
||||
rg.POST("/data/playback", h.reportPlayback) // 播放数据回传(需求9)
|
||||
rg.GET("/data/playback-summary", h.playbackSummary) // 按MA码聚合可信播放数据(需求9/21)
|
||||
rg.POST("/settlement/compute", h.computeSettlement) // 基于可信播放数据分账(需求21)
|
||||
}
|
||||
|
||||
func roleOf(c *gin.Context) chain.Role {
|
||||
@@ -386,3 +390,63 @@ func (h *Handler) listContents(c *gin.Context) {
|
||||
}
|
||||
httpx.OK(c, gin.H{"contents": list, "count": len(list)})
|
||||
}
|
||||
|
||||
// ---- 二期:播放数据回传与分账(需求9/21) ----
|
||||
|
||||
type playbackReq struct {
|
||||
PlatformID string `json:"platform_id"`
|
||||
Batch []struct {
|
||||
MACode string `json:"ma_code"`
|
||||
Episode int `json:"episode"`
|
||||
UserHash string `json:"user_hash"`
|
||||
EventType string `json:"event_type"`
|
||||
DurationSec int `json:"duration_sec"`
|
||||
RevenueCent int64 `json:"revenue_cent"`
|
||||
} `json:"batch"`
|
||||
}
|
||||
|
||||
func (h *Handler) reportPlayback(c *gin.Context) {
|
||||
var req playbackReq
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
httpx.Error(c, http.StatusBadRequest, "INVALID_REQUEST", err.Error())
|
||||
return
|
||||
}
|
||||
events := make([]model.PlaybackEvent, 0, len(req.Batch))
|
||||
for _, b := range req.Batch {
|
||||
events = append(events, model.PlaybackEvent{
|
||||
MACode: b.MACode, Episode: b.Episode, PlatformID: req.PlatformID,
|
||||
UserHash: b.UserHash, EventType: model.PlaybackEventType(b.EventType),
|
||||
DurationSec: b.DurationSec, RevenueCent: b.RevenueCent, EventTime: time.Now(),
|
||||
})
|
||||
}
|
||||
accepted, rejected := h.svc.ReportPlayback(events)
|
||||
httpx.OK(c, gin.H{"accepted": accepted, "rejected": rejected})
|
||||
}
|
||||
|
||||
func (h *Handler) playbackSummary(c *gin.Context) {
|
||||
maCode := c.Query("ma_code")
|
||||
if maCode == "" {
|
||||
httpx.Error(c, http.StatusBadRequest, "INVALID_REQUEST", "缺少 ma_code")
|
||||
return
|
||||
}
|
||||
httpx.OK(c, h.svc.PlaybackSummary(maCode))
|
||||
}
|
||||
|
||||
type settlementReq struct {
|
||||
MACode string `json:"ma_code"`
|
||||
Period string `json:"period"`
|
||||
}
|
||||
|
||||
func (h *Handler) computeSettlement(c *gin.Context) {
|
||||
var req settlementReq
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
httpx.Error(c, http.StatusBadRequest, "INVALID_REQUEST", err.Error())
|
||||
return
|
||||
}
|
||||
st, err := h.svc.ComputeSettlement(req.MACode, req.Period)
|
||||
if err != nil {
|
||||
httpx.Error(c, http.StatusBadRequest, "SETTLEMENT_FAILED", err.Error())
|
||||
return
|
||||
}
|
||||
httpx.OK(c, st)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user