广告修改

This commit is contained in:
谢宇宁
2026-10-28 17:27:22 +07:00
parent 4e98b85fd8
commit 3879f5a71c
23 changed files with 393 additions and 254 deletions
+5
View File
@@ -87,6 +87,11 @@ type AdvitiseData struct {
TitleList []Advertisement `json:"titleList"`
PlayList []Advertisement `json:"playList"`
PauseyList []Advertisement `json:"pauseyList"`
// 本站后台(webhgdjapi)的字段名:横幅 / 播放页小图标 / 首页小图标
VideoTopList []Advertisement `json:"videoTopList"`
VideoDownList []Advertisement `json:"videoDownList"`
AppInfoAList []Advertisement `json:"appInfoAList"`
AppInfoBList []Advertisement `json:"appInfoBList"`
}
// Advertisement 对应 swagger proxy.AdvitiseInfo。
+37 -40
View File
@@ -7,29 +7,31 @@ import (
// AppConfigVM 注入全站页面的公共配置(字段名与接口 newAddressInfo / seoInfo 对齐)。
type AppConfigVM struct {
ForeverURLAddr string `json:"foreverUrlAddr"`
NewURLAddr string `json:"newUrlAddr"`
NewURLAddr1 string `json:"newUrlAddr1"`
NewURLAddr2 string `json:"newUrlAddr2"`
GmailAddr string `json:"gmailAddr"`
QQ string `json:"qq"`
TGGroup string `json:"tgGroup"`
Telegram string `json:"telegram"`
PotaoGroup string `json:"potaoGroup"`
CustomerServiceHost string `json:"customerServiceHost"`
AppAddr string `json:"appAddr"`
OfficialAppAddr string `json:"officialAppAddr"`
PDFAddr string `json:"pdfAddr"`
TwitterAddr string `json:"twitterAddr"`
SeoInfo SeoInfo `json:"seoInfo,omitempty"`
SeoNavInfo SeoNavInfo `json:"seoNavInfo,omitempty"`
NavPageList []NavPageItem `json:"navPageList,omitempty"`
Advitise AdvitiseData `json:"advitise"`
DetailTopList []Advertisement `json:"detailTopList,omitempty"`
NineGridList []Advertisement `json:"nineGridList,omitempty"`
DetailBannerList []Advertisement `json:"detailbannerList,omitempty"`
BottomBanner []Advertisement `json:"bottomBanner,omitempty"`
DialogList []Advertisement `json:"dialogList,omitempty"`
ForeverURLAddr string `json:"foreverUrlAddr"`
NewURLAddr string `json:"newUrlAddr"`
NewURLAddr1 string `json:"newUrlAddr1"`
NewURLAddr2 string `json:"newUrlAddr2"`
GmailAddr string `json:"gmailAddr"`
QQ string `json:"qq"`
TGGroup string `json:"tgGroup"`
Telegram string `json:"telegram"`
PotaoGroup string `json:"potaoGroup"`
CustomerServiceHost string `json:"customerServiceHost"`
AppAddr string `json:"appAddr"`
OfficialAppAddr string `json:"officialAppAddr"`
PDFAddr string `json:"pdfAddr"`
TwitterAddr string `json:"twitterAddr"`
SeoInfo SeoInfo `json:"seoInfo,omitempty"`
SeoNavInfo SeoNavInfo `json:"seoNavInfo,omitempty"`
NavPageList []NavPageItem `json:"navPageList,omitempty"`
Advitise AdvitiseData `json:"advitise"`
// 网页只用后台「站点」的 5 个广告位:
// 弹窗 / 9宫格(弹窗广告后弹出)/ 详情横幅 / 播放页小图标 / 首页小图标
DialogList []Advertisement `json:"dialogList,omitempty"`
NineGridList []Advertisement `json:"nineGridList,omitempty"`
DetailBannerList []Advertisement `json:"detailbannerList,omitempty"`
AList []Advertisement `json:"AList,omitempty"`
BList []Advertisement `json:"BList,omitempty"`
}
// BuildAppConfigVM 从上游配置组装前端可用字段。
@@ -55,11 +57,12 @@ func BuildAppConfigVM(info *ConfigInfoResp) AppConfigVM {
TwitterAddr: sanitizeURL(addr.TwitterAddr),
NavPageList: buildNavPageList(info.NavPageList),
Advitise: info.Advitise,
DetailTopList: buildAdvertisementList(info.Advitise.DetailTopList),
NineGridList: buildAdvertisementList(info.Advitise.NineGridList),
DetailBannerList: buildAdvertisementList(info.Advitise.DetailBannerList),
BottomBanner: buildAdvertisementList(info.Advitise.BottomBanner),
DialogList: buildAdvertisementList(info.Advitise.DialogList),
NineGridList: buildAdvertisementList(info.Advitise.NineGridList),
// 本站后台用 videoTopList / appInfoAList / appInfoBList;兼容 detailbannerList / AList / BList 命名
DetailBannerList: firstAdvertisementList(info.Advitise.VideoTopList, info.Advitise.DetailBannerList),
AList: firstAdvertisementList(info.Advitise.AppInfoAList, info.Advitise.AList),
BList: firstAdvertisementList(info.Advitise.AppInfoBList, info.Advitise.BList),
SeoInfo: SeoInfo{
Title: strings.TrimSpace(info.SeoInfo.Title),
Description: strings.TrimSpace(info.SeoInfo.Description),
@@ -94,20 +97,14 @@ func buildAdvertisementList(list []Advertisement) []Advertisement {
return out
}
// NineGridRow 按首页设计每行返回两个 banner,超出当前行时返回空切片。
func (c AppConfigVM) NineGridRow(row int) []Advertisement {
if row < 0 {
return nil
// firstAdvertisementList 返回第一个有可用广告的列表(按字段优先级)。
func firstAdvertisementList(lists ...[]Advertisement) []Advertisement {
for _, list := range lists {
if built := buildAdvertisementList(list); len(built) > 0 {
return built
}
}
start := row * 2
if start >= len(c.NineGridList) {
return nil
}
end := start + 2
if end > len(c.NineGridList) {
end = len(c.NineGridList)
}
return c.NineGridList[start:end]
return nil
}
// QRText 下载弹窗二维码、跳转及复制链接内容:仅使用应用下载地址 appAddr。
+15 -24
View File
@@ -18,8 +18,7 @@ func TestBuildAppConfigVMIncludesValidAdvertisements(t *testing.T) {
NewAddressInfo: NewAddressInfo{Telegram: " https://t.me/business ", QQ: " 2168045324 ", OfficialAppAddr: " https://app.example.com/download\\ "},
Config: ConfigInfo{PotaoGroup: " https://potato.example.com/group\\ "},
Advitise: AdvitiseData{
HomeList: []Advertisement{{ID: "home", Images: "https://cdn.example.com/home.gif"}},
DetailTopList: []Advertisement{{ID: "top", Images: " https://cdn.example.com/top.gif "}},
HomeList: []Advertisement{{ID: "home", Images: "https://cdn.example.com/home.gif"}},
NineGridList: []Advertisement{
{ID: "banner-1", Images: "https://cdn.example.com/banner-1.gif"},
{ID: "banner-empty", Images: " "},
@@ -27,10 +26,13 @@ func TestBuildAppConfigVMIncludesValidAdvertisements(t *testing.T) {
{ID: "banner-3", Images: "https://cdn.example.com/banner-3.gif"},
},
DetailBannerList: []Advertisement{{ID: "detail", Images: "https://cdn.example.com/detail.gif"}},
BottomBanner: []Advertisement{
{ID: " bottom ", Images: " https://cdn.example.com/bottom.gif ", Link: " https://example.com/bottom "},
{ID: "bottom-empty", Images: " "},
VideoTopList: []Advertisement{
{ID: " video-top ", Images: " https://cdn.example.com/video-top.gif ", Link: " https://example.com/top "},
{ID: "video-top-empty", Images: " "},
},
AList: []Advertisement{{ID: "a-legacy", Images: "https://cdn.example.com/a.gif"}},
AppInfoAList: []Advertisement{{ID: "a", Images: "https://cdn.example.com/app-a.gif"}},
BList: []Advertisement{{ID: "b", Images: "https://cdn.example.com/b.gif"}},
DialogList: []Advertisement{
{ID: " 1 ", Images: " https://cdn.example.com/ad.webp\\ ", Link: " https://example.com ", Title: " 广告一 "},
{ID: "2", Images: " ", Title: "无图广告"},
@@ -56,17 +58,19 @@ func TestBuildAppConfigVMIncludesValidAdvertisements(t *testing.T) {
if len(vm.Advitise.NineGridList) != 4 {
t.Fatalf("Advitise.NineGridList length = %d, want raw length 4", len(vm.Advitise.NineGridList))
}
if len(vm.DetailTopList) != 1 || vm.DetailTopList[0].ID != "top" {
t.Fatalf("DetailTopList = %#v", vm.DetailTopList)
}
if len(vm.NineGridList) != 3 {
t.Fatalf("NineGridList length = %d, want 3", len(vm.NineGridList))
}
if len(vm.DetailBannerList) != 1 || vm.DetailBannerList[0].ID != "detail" {
// 详情横幅优先 videoTopList(本站后台字段),无效图片被过滤
if len(vm.DetailBannerList) != 1 || vm.DetailBannerList[0].ID != "video-top" || vm.DetailBannerList[0].Images != "https://cdn.example.com/video-top.gif" {
t.Fatalf("DetailBannerList = %#v", vm.DetailBannerList)
}
if len(vm.BottomBanner) != 1 || vm.BottomBanner[0].ID != "bottom" || vm.BottomBanner[0].Images != "https://cdn.example.com/bottom.gif" {
t.Fatalf("BottomBanner = %#v", vm.BottomBanner)
// 播放页小图标优先 appInfoAList;首页小图标无 appInfoBList 时回退 BList
if len(vm.AList) != 1 || vm.AList[0].ID != "a" {
t.Fatalf("AList = %#v", vm.AList)
}
if len(vm.BList) != 1 || vm.BList[0].ID != "b" {
t.Fatalf("BList = %#v", vm.BList)
}
if len(vm.DialogList) != 1 {
t.Fatalf("DialogList length = %d, want 1", len(vm.DialogList))
@@ -76,16 +80,3 @@ func TestBuildAppConfigVMIncludesValidAdvertisements(t *testing.T) {
t.Fatalf("DialogList[0] = %#v", got)
}
}
func TestNineGridRowReturnsTwoItemsPerRow(t *testing.T) {
cfg := AppConfigVM{NineGridList: []Advertisement{{ID: "1"}, {ID: "2"}, {ID: "3"}}}
if got := cfg.NineGridRow(0); len(got) != 2 || got[0].ID != "1" || got[1].ID != "2" {
t.Fatalf("NineGridRow(0) = %#v", got)
}
if got := cfg.NineGridRow(1); len(got) != 1 || got[0].ID != "3" {
t.Fatalf("NineGridRow(1) = %#v", got)
}
if got := cfg.NineGridRow(2); len(got) != 0 {
t.Fatalf("NineGridRow(2) = %#v, want empty", got)
}
}