新增广告V2模块,双端下载落地页调整

- 新增 advitise v2: info/location/bind/click-stat/day-click-stat 模型与
  对应的 service、api、router、proto 定义
- models/index.go 注册 5 个新模型的索引初始化
- 鉴权白名单: /rsdownload/ 改为 /download/,放行 advitise v2 的
  get/click 接口
- statg/config: proxyUrl 增加 fileRes1
- common/genId: lid 生成逻辑补充
- 新增 91fans / huangguo 的 mobileconfig 描述文件
- 新增 deploy/nginx/cpcdownload.mfcg.me.conf 网关配置

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-09-22 16:53:23 +08:00
co-authored by Claude Opus 5
parent bc605f303d
commit 01d9f7bc86
40 changed files with 2561 additions and 30 deletions
+106
View File
@@ -0,0 +1,106 @@
package advitiseV2Api
import (
"stat/api/proto"
"stat/common/stdLog"
"stat/common/utils"
"stat/service/advitiseV2Ser"
"stat/service/opLogSer"
"github.com/gin-gonic/gin"
)
// @Tags 广告管理V2/绑定
// @Summary 绑定关系列表
// @Router /api/stat/advitise/v2/bind/list [POST]
// @Param param body proto.AdvitiseBindListReq true "参数"
// @Success 200 {object} proto.AdvitiseBindListResp "成功"
// @Security ApiKeyAuth
func BindList(ctx *gin.Context) {
req := &proto.AdvitiseBindListReq{}
if err := ctx.ShouldBindJSON(req); err != nil {
stdLog.ServerJSON(ctx, stdLog.ParamError, err.Error())
return
}
resp, err := advitiseV2Ser.BindList(ctx, req)
if err != nil {
stdLog.ServerJSON(ctx, stdLog.Failure, err.Error())
return
}
stdLog.ServerJSON(ctx, stdLog.Success, resp)
}
// @Tags 广告管理V2/绑定
// @Summary 新增绑定
// @Router /api/stat/advitise/v2/bind/add [POST]
// @Param param body proto.AddAdvitiseBindReq true "参数"
// @Success 200 {string} string "成功"
// @Security ApiKeyAuth
func BindAdd(ctx *gin.Context) {
account, err := utils.GetAdmin(ctx)
if err != nil {
stdLog.ServerJSON(ctx, stdLog.NoToken, err.Error())
return
}
req := &proto.AddAdvitiseBindReq{}
if err := ctx.ShouldBindJSON(req); err != nil {
stdLog.ServerJSON(ctx, stdLog.ParamError, err.Error())
return
}
if err := advitiseV2Ser.BindAdd(ctx, req); err != nil {
stdLog.ServerJSON(ctx, stdLog.Failure, err.Error())
return
}
opLogSer.AddOpLog(ctx, account, true, req)
stdLog.ServerJSON(ctx, stdLog.Success, "")
}
// @Tags 广告管理V2/绑定
// @Summary 更新绑定
// @Router /api/stat/advitise/v2/bind/update [POST]
// @Param param body proto.UpdateAdvitiseBindReq true "参数"
// @Success 200 {string} string "成功"
// @Security ApiKeyAuth
func BindUpdate(ctx *gin.Context) {
account, err := utils.GetAdmin(ctx)
if err != nil {
stdLog.ServerJSON(ctx, stdLog.NoToken, err.Error())
return
}
req := &proto.UpdateAdvitiseBindReq{}
if err := ctx.ShouldBindJSON(req); err != nil {
stdLog.ServerJSON(ctx, stdLog.ParamError, err.Error())
return
}
if err := advitiseV2Ser.BindUpdate(ctx, req); err != nil {
stdLog.ServerJSON(ctx, stdLog.Failure, err.Error())
return
}
opLogSer.AddOpLog(ctx, account, true, req)
stdLog.ServerJSON(ctx, stdLog.Success, "")
}
// @Tags 广告管理V2/绑定
// @Summary 删除绑定
// @Router /api/stat/advitise/v2/bind/del [POST]
// @Param param body proto.DelAdvitiseBindReq true "参数"
// @Success 200 {string} string "成功"
// @Security ApiKeyAuth
func BindDel(ctx *gin.Context) {
account, err := utils.GetAdmin(ctx)
if err != nil {
stdLog.ServerJSON(ctx, stdLog.NoToken, err.Error())
return
}
req := &proto.DelAdvitiseBindReq{}
if err := ctx.ShouldBindJSON(req); err != nil {
stdLog.ServerJSON(ctx, stdLog.ParamError, err.Error())
return
}
if err := advitiseV2Ser.BindDel(ctx, req.Id); err != nil {
stdLog.ServerJSON(ctx, stdLog.Failure, err.Error())
return
}
opLogSer.AddOpLog(ctx, account, true, req)
stdLog.ServerJSON(ctx, stdLog.Success, "")
}
+49
View File
@@ -0,0 +1,49 @@
package advitiseV2Api
import (
"stat/api/proto"
"stat/common/stdLog"
"stat/service/advitiseV2Ser"
"github.com/gin-gonic/gin"
)
// @Tags 广告管理V2/外部
// @Summary 拉广告列表(客户端)
// @Description 按 (appId, locationId?) 返回可展示广告;结构对齐老 /ads/get(advertiseList);每条 item 多带 bindId 供点击回传
// @Router /api/stat/advitise/v2/get [POST]
// @Param param body proto.GetAdvitiseV2Req true "参数"
// @Success 200 {object} proto.AdvertiseRes "成功"
func GetAdvitises(ctx *gin.Context) {
req := &proto.GetAdvitiseV2Req{}
if err := ctx.ShouldBindJSON(req); err != nil {
stdLog.ServerJSON(ctx, stdLog.ParamError, err.Error())
return
}
resp, err := advitiseV2Ser.GetAdvitises(ctx, req)
if err != nil {
stdLog.ServerJSON(ctx, stdLog.Failure, err.Error())
return
}
// 对齐老 GetAds 直接 ctx.JSON(200, data) 的行为
ctx.JSON(200, resp)
}
// @Tags 广告管理V2/外部
// @Summary 广告点击(客户端)
// @Description 根据 GetAds 返回的 bindId 上报点击,服务端反查 (广告, 位置) 并沿用老统计逻辑(redis 时段 hash + doc 累计)
// @Router /api/stat/advitise/v2/click [POST]
// @Param param body proto.ClickAdvitiseV2Req true "参数"
// @Success 200 {string} string "成功"
func ClickAdvitise(ctx *gin.Context) {
req := &proto.ClickAdvitiseV2Req{}
if err := ctx.ShouldBindJSON(req); err != nil {
stdLog.ServerJSON(ctx, stdLog.ParamError, err.Error())
return
}
if err := advitiseV2Ser.ClickAdvitise(ctx, req); err != nil {
stdLog.ServerJSON(ctx, stdLog.Failure, err.Error())
return
}
stdLog.ServerJSON(ctx, stdLog.Success, "")
}
+106
View File
@@ -0,0 +1,106 @@
package advitiseV2Api
import (
"stat/api/proto"
"stat/common/stdLog"
"stat/common/utils"
"stat/service/advitiseV2Ser"
"stat/service/opLogSer"
"github.com/gin-gonic/gin"
)
// @Tags 广告管理V2/素材
// @Summary 素材列表
// @Router /api/stat/advitise/v2/info/list [POST]
// @Param param body proto.AdvitiseInfoListReq true "参数"
// @Success 200 {object} proto.AdvitiseInfoListResp "成功"
// @Security ApiKeyAuth
func InfoList(ctx *gin.Context) {
req := &proto.AdvitiseInfoListReq{}
if err := ctx.ShouldBindJSON(req); err != nil {
stdLog.ServerJSON(ctx, stdLog.ParamError, err.Error())
return
}
resp, err := advitiseV2Ser.InfoList(ctx, req)
if err != nil {
stdLog.ServerJSON(ctx, stdLog.Failure, err.Error())
return
}
stdLog.ServerJSON(ctx, stdLog.Success, resp)
}
// @Tags 广告管理V2/素材
// @Summary 新增素材
// @Router /api/stat/advitise/v2/info/add [POST]
// @Param param body proto.AddAdvitiseInfoReq true "参数"
// @Success 200 {string} string "成功"
// @Security ApiKeyAuth
func InfoAdd(ctx *gin.Context) {
account, err := utils.GetAdmin(ctx)
if err != nil {
stdLog.ServerJSON(ctx, stdLog.NoToken, err.Error())
return
}
req := &proto.AddAdvitiseInfoReq{}
if err := ctx.ShouldBindJSON(req); err != nil {
stdLog.ServerJSON(ctx, stdLog.ParamError, err.Error())
return
}
if err := advitiseV2Ser.InfoAdd(ctx, req); err != nil {
stdLog.ServerJSON(ctx, stdLog.Failure, err.Error())
return
}
opLogSer.AddOpLog(ctx, account, true, req)
stdLog.ServerJSON(ctx, stdLog.Success, "")
}
// @Tags 广告管理V2/素材
// @Summary 更新素材
// @Router /api/stat/advitise/v2/info/update [POST]
// @Param param body proto.UpdateAdvitiseInfoReq true "参数"
// @Success 200 {string} string "成功"
// @Security ApiKeyAuth
func InfoUpdate(ctx *gin.Context) {
account, err := utils.GetAdmin(ctx)
if err != nil {
stdLog.ServerJSON(ctx, stdLog.NoToken, err.Error())
return
}
req := &proto.UpdateAdvitiseInfoReq{}
if err := ctx.ShouldBindJSON(req); err != nil {
stdLog.ServerJSON(ctx, stdLog.ParamError, err.Error())
return
}
if err := advitiseV2Ser.InfoUpdate(ctx, req); err != nil {
stdLog.ServerJSON(ctx, stdLog.Failure, err.Error())
return
}
opLogSer.AddOpLog(ctx, account, true, req)
stdLog.ServerJSON(ctx, stdLog.Success, "")
}
// @Tags 广告管理V2/素材
// @Summary 删除素材
// @Router /api/stat/advitise/v2/info/del [POST]
// @Param param body proto.DelAdvitiseInfoReq true "参数"
// @Success 200 {string} string "成功"
// @Security ApiKeyAuth
func InfoDel(ctx *gin.Context) {
account, err := utils.GetAdmin(ctx)
if err != nil {
stdLog.ServerJSON(ctx, stdLog.NoToken, err.Error())
return
}
req := &proto.DelAdvitiseInfoReq{}
if err := ctx.ShouldBindJSON(req); err != nil {
stdLog.ServerJSON(ctx, stdLog.ParamError, err.Error())
return
}
if err := advitiseV2Ser.InfoDel(ctx, req.Id); err != nil {
stdLog.ServerJSON(ctx, stdLog.Failure, err.Error())
return
}
opLogSer.AddOpLog(ctx, account, true, req)
stdLog.ServerJSON(ctx, stdLog.Success, "")
}
+106
View File
@@ -0,0 +1,106 @@
package advitiseV2Api
import (
"stat/api/proto"
"stat/common/stdLog"
"stat/common/utils"
"stat/service/advitiseV2Ser"
"stat/service/opLogSer"
"github.com/gin-gonic/gin"
)
// @Tags 广告管理V2/位置
// @Summary 广告位列表
// @Router /api/stat/advitise/v2/location/list [POST]
// @Param param body proto.AdvitiseLocationListReq true "参数"
// @Success 200 {object} proto.AdvitiseLocationListResp "成功"
// @Security ApiKeyAuth
func LocationList(ctx *gin.Context) {
req := &proto.AdvitiseLocationListReq{}
if err := ctx.ShouldBindJSON(req); err != nil {
stdLog.ServerJSON(ctx, stdLog.ParamError, err.Error())
return
}
resp, err := advitiseV2Ser.LocationList(ctx, req)
if err != nil {
stdLog.ServerJSON(ctx, stdLog.Failure, err.Error())
return
}
stdLog.ServerJSON(ctx, stdLog.Success, resp)
}
// @Tags 广告管理V2/位置
// @Summary 新增广告位
// @Router /api/stat/advitise/v2/location/add [POST]
// @Param param body proto.AddAdvitiseLocationReq true "参数"
// @Success 200 {string} string "成功"
// @Security ApiKeyAuth
func LocationAdd(ctx *gin.Context) {
account, err := utils.GetAdmin(ctx)
if err != nil {
stdLog.ServerJSON(ctx, stdLog.NoToken, err.Error())
return
}
req := &proto.AddAdvitiseLocationReq{}
if err := ctx.ShouldBindJSON(req); err != nil {
stdLog.ServerJSON(ctx, stdLog.ParamError, err.Error())
return
}
if err := advitiseV2Ser.LocationAdd(ctx, req); err != nil {
stdLog.ServerJSON(ctx, stdLog.Failure, err.Error())
return
}
opLogSer.AddOpLog(ctx, account, true, req)
stdLog.ServerJSON(ctx, stdLog.Success, "")
}
// @Tags 广告管理V2/位置
// @Summary 更新广告位
// @Router /api/stat/advitise/v2/location/update [POST]
// @Param param body proto.UpdateAdvitiseLocationReq true "参数"
// @Success 200 {string} string "成功"
// @Security ApiKeyAuth
func LocationUpdate(ctx *gin.Context) {
account, err := utils.GetAdmin(ctx)
if err != nil {
stdLog.ServerJSON(ctx, stdLog.NoToken, err.Error())
return
}
req := &proto.UpdateAdvitiseLocationReq{}
if err := ctx.ShouldBindJSON(req); err != nil {
stdLog.ServerJSON(ctx, stdLog.ParamError, err.Error())
return
}
if err := advitiseV2Ser.LocationUpdate(ctx, req); err != nil {
stdLog.ServerJSON(ctx, stdLog.Failure, err.Error())
return
}
opLogSer.AddOpLog(ctx, account, true, req)
stdLog.ServerJSON(ctx, stdLog.Success, "")
}
// @Tags 广告管理V2/位置
// @Summary 删除广告位
// @Router /api/stat/advitise/v2/location/del [POST]
// @Param param body proto.DelAdvitiseLocationReq true "参数"
// @Success 200 {string} string "成功"
// @Security ApiKeyAuth
func LocationDel(ctx *gin.Context) {
account, err := utils.GetAdmin(ctx)
if err != nil {
stdLog.ServerJSON(ctx, stdLog.NoToken, err.Error())
return
}
req := &proto.DelAdvitiseLocationReq{}
if err := ctx.ShouldBindJSON(req); err != nil {
stdLog.ServerJSON(ctx, stdLog.ParamError, err.Error())
return
}
if err := advitiseV2Ser.LocationDel(ctx, req.Id); err != nil {
stdLog.ServerJSON(ctx, stdLog.Failure, err.Error())
return
}
opLogSer.AddOpLog(ctx, account, true, req)
stdLog.ServerJSON(ctx, stdLog.Success, "")
}
+80
View File
@@ -0,0 +1,80 @@
package advitiseV2Api
import (
"stat/api/proto"
"stat/common/stdLog"
"stat/service/advitiseV2Ser"
"github.com/gin-gonic/gin"
)
// @Tags 广告管理V2/统计
// @Summary 广告每日点击列表(汇总)
// @Router /api/stat/advitise/v2/day/click/list [POST]
// @Param param body proto.AdvitiseDayClickListReq true "参数"
// @Success 200 {object} proto.AdvitiseDayClickListResp "成功"
// @Security ApiKeyAuth
func DayClickList(ctx *gin.Context) {
req := &proto.AdvitiseDayClickListReq{}
if err := ctx.ShouldBindJSON(req); err != nil {
stdLog.ServerJSON(ctx, stdLog.ParamError, err.Error())
return
}
resp, err := advitiseV2Ser.DayClickList(ctx, req)
if err != nil {
stdLog.ServerJSON(ctx, stdLog.Failure, err.Error())
return
}
stdLog.ServerJSON(ctx, stdLog.Success, resp)
}
// @Tags 广告管理V2/统计
// @Summary 广告点击详情(细维度)
// @Router /api/stat/advitise/v2/day/click/info [POST]
// @Param param body proto.AdvitiseClickListReq true "参数"
// @Success 200 {object} proto.AdvitiseClickListResp "成功"
// @Security ApiKeyAuth
func DayClickInfo(ctx *gin.Context) {
req := &proto.AdvitiseClickListReq{}
if err := ctx.ShouldBindJSON(req); err != nil {
stdLog.ServerJSON(ctx, stdLog.ParamError, err.Error())
return
}
resp, err := advitiseV2Ser.ClickList(ctx, req)
if err != nil {
stdLog.ServerJSON(ctx, stdLog.Failure, err.Error())
return
}
stdLog.ServerJSON(ctx, stdLog.Success, resp)
}
// @Tags 广告管理V2/统计
// @Summary 广告细维度点击列表(广告位查看统计入口)
// @Router /api/stat/advitise/v2/click/list [POST]
// @Param param body proto.AdvitiseClickListReq true "参数"
// @Success 200 {object} proto.AdvitiseClickListResp "成功"
// @Security ApiKeyAuth
func ClickList(ctx *gin.Context) {
// 与 DayClickInfo 语义一致,复用同一入口
DayClickInfo(ctx)
}
// @Tags 广告管理V2/统计
// @Summary 按时间范围汇总广告点击量(每广告一行)
// @Router /api/stat/advitise/v2/day/click/summary [POST]
// @Param param body proto.AdvitiseClickSummaryReq true "参数"
// @Success 200 {object} proto.AdvitiseClickSummaryResp "成功"
// @Security ApiKeyAuth
func ClickSummary(ctx *gin.Context) {
req := &proto.AdvitiseClickSummaryReq{}
if err := ctx.ShouldBindJSON(req); err != nil {
stdLog.ServerJSON(ctx, stdLog.ParamError, err.Error())
return
}
resp, err := advitiseV2Ser.ClickSummary(ctx, req)
if err != nil {
stdLog.ServerJSON(ctx, stdLog.Failure, err.Error())
return
}
stdLog.ServerJSON(ctx, stdLog.Success, resp)
}