Files
web_huangguo2_h5/app/service/configser/view.go
T
2026-10-29 16:41:17 +07:00

250 lines
9.2 KiB
Go

package configser
import (
"strconv"
"strings"
)
// AppConfigVM 注入全站页面的公共配置(字段名与接口 newAddressInfo / seoInfo 对齐)。
type AppConfigVM struct {
// Config 为 data.config 原样字段(页脚社交等优先用此对象)。
Config ConfigInfo `json:"config"`
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"`
TelegramAdd string `json:"telegramAdd"`
PotaoGroup string `json:"potaoGroup"`
CustomerServiceHost string `json:"customerServiceHost"`
AppAddr string `json:"appAddr"`
OfficialAppAddr string `json:"officialAppAddr"`
PDFAddr string `json:"pdfAddr"`
TwitterAddr string `json:"twitterAddr"`
GitAddr string `json:"gitAddr"`
FreeVPN string `json:"freeVPN"`
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 从上游配置组装前端可用字段;社交/地址优先取 data.config。
func BuildAppConfigVM(info *ConfigInfoResp) AppConfigVM {
if info == nil {
return AppConfigVM{}
}
cfg := sanitizeConfigInfo(info.Config)
addr := info.NewAddressInfo
return AppConfigVM{
Config: cfg,
ForeverURLAddr: firstNonEmptyURL(cfg.ForeverURLAddr, addr.ForeverURLAddr),
NewURLAddr: firstNonEmptyURL(cfg.NewURLAddr, addr.NewURLAddr),
NewURLAddr1: firstNonEmptyURL(cfg.NewURLAddr1, addr.NewURLAddr1),
NewURLAddr2: firstNonEmptyURL(cfg.NewURLAddr2, addr.NewURLAddr2),
GmailAddr: firstNonEmpty(normalizeEmailAddress(cfg.GmailAddr), normalizeEmailAddress(addr.GmailAddr)),
QQ: firstNonEmpty(cfg.QQ, strings.TrimSpace(addr.QQ)),
TGGroup: firstNonEmptyURL(cfg.TGGroup, addr.TGGroup),
Telegram: firstNonEmptyURL(cfg.Telegram, addr.Telegram),
TelegramAdd: sanitizeURL(cfg.TelegramAdd),
PotaoGroup: firstNonEmptyURL(cfg.PotaoGroup, addr.PotaoGroup),
CustomerServiceHost: firstNonEmptyURL(cfg.CustomerServiceHost, addr.CustomerServiceHost),
AppAddr: firstNonEmptyURL(cfg.AppAddr, addr.AppAddr),
OfficialAppAddr: firstNonEmptyURL(cfg.OfficialAppAddr, addr.OfficialAppAddr),
PDFAddr: firstNonEmptyURL(cfg.PDFAddr, addr.PDFAddr),
TwitterAddr: firstNonEmptyURL(cfg.TwitterAddr, addr.TwitterAddr),
GitAddr: sanitizeURL(cfg.GitAddr),
FreeVPN: sanitizeURL(cfg.FreeVPN),
NavPageList: buildNavPageList(info.NavPageList),
Advitise: info.Advitise,
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),
Keywords: info.SeoInfo.Keywords,
CanonicalURL: strings.TrimSpace(info.SeoInfo.CanonicalURL),
WebSiteName: strings.TrimSpace(info.SeoInfo.WebSiteName),
},
SeoNavInfo: SeoNavInfo{
DhTitle: strings.TrimSpace(info.SeoNavInfo.DhTitle),
DhDescription: strings.TrimSpace(info.SeoNavInfo.DhDescription),
DhKeyworld: info.SeoNavInfo.DhKeyworld,
DhSiteName: strings.TrimSpace(info.SeoNavInfo.DhSiteName),
},
}
}
func sanitizeConfigInfo(cfg ConfigInfo) ConfigInfo {
return ConfigInfo{
AppAddr: sanitizeURL(cfg.AppAddr),
OfficialAppAddr: sanitizeURL(cfg.OfficialAppAddr),
ForeverURLAddr: sanitizeURL(cfg.ForeverURLAddr),
NewURLAddr: sanitizeURL(cfg.NewURLAddr),
NewURLAddr1: sanitizeURL(cfg.NewURLAddr1),
NewURLAddr2: sanitizeURL(cfg.NewURLAddr2),
GmailAddr: normalizeEmailAddress(cfg.GmailAddr),
QQ: strings.TrimSpace(cfg.QQ),
WeiChart: strings.TrimSpace(cfg.WeiChart),
TGGroup: sanitizeURL(cfg.TGGroup),
Telegram: sanitizeURL(cfg.Telegram),
TelegramAdd: sanitizeURL(cfg.TelegramAdd),
PotaoGroup: sanitizeURL(cfg.PotaoGroup),
CustomerServiceHost: sanitizeURL(cfg.CustomerServiceHost),
PDFAddr: sanitizeURL(cfg.PDFAddr),
TwitterAddr: sanitizeURL(cfg.TwitterAddr),
GitAddr: sanitizeURL(cfg.GitAddr),
FreeVPN: sanitizeURL(cfg.FreeVPN),
}
}
func firstNonEmpty(values ...string) string {
for _, v := range values {
if strings.TrimSpace(v) != "" {
return strings.TrimSpace(v)
}
}
return ""
}
func buildAdvertisementList(list []Advertisement) []Advertisement {
if len(list) == 0 {
return nil
}
out := make([]Advertisement, 0, len(list))
for _, item := range list {
item.ID = strings.TrimSpace(item.ID)
item.AdvertiseCode = strings.TrimSpace(item.AdvertiseCode)
item.AdvertiseLocationCode = strings.TrimSpace(item.AdvertiseLocationCode)
item.AdvertiseLocationName = strings.TrimSpace(item.AdvertiseLocationName)
item.AdsID = parseAdsID(item.ID)
if item.AdvertiseCode != "" {
item.ID = item.AdvertiseCode
}
item.Images = sanitizeURL(item.Images)
item.Link = sanitizeURL(item.Link)
item.Title = strings.TrimSpace(item.Title)
if item.Images == "" {
continue
}
out = append(out, item)
}
return out
}
// parseAdsID 解析上游数字字符串广告 id;非正整数返回 0(不上报)。
func parseAdsID(id string) int64 {
n, err := strconv.ParseInt(strings.TrimSpace(id), 10, 64)
if err != nil || n <= 0 {
return 0
}
return n
}
// firstAdvertisementList 返回第一个有可用广告的列表(按字段优先级)。
func firstAdvertisementList(lists ...[]Advertisement) []Advertisement {
for _, list := range lists {
if built := buildAdvertisementList(list); len(built) > 0 {
return built
}
}
return nil
}
// QRText 应用下载二维码及跳转地址:仅使用应用下载地址 appAddr。
func (c AppConfigVM) QRText() string {
return strings.TrimSpace(c.AppAddr)
}
func buildNavPageList(list []NavPageItem) []NavPageItem {
if len(list) == 0 {
return nil
}
out := make([]NavPageItem, 0, len(list))
for _, item := range list {
u := sanitizeURL(item.URL)
if u == "" {
continue
}
out = append(out, NavPageItem{Line: item.Line, URL: u})
}
return out
}
func (n NavPageItem) Label() string {
digits := []string{"", "一", "二", "三", "四", "五", "六", "七", "八", "九", "十"}
if n.Line >= 1 && n.Line <= 10 {
return "线路" + digits[n.Line]
}
if n.Line > 0 {
return "线路" + strconv.Itoa(n.Line)
}
return "线路"
}
func sanitizeURL(v string) string {
v = strings.TrimSpace(v)
v = strings.TrimRight(v, "\\")
return strings.TrimSpace(v)
}
// normalizeEmailAddress 兼容上游把邮箱误配为 mailto/http(s) 地址的情况。
func normalizeEmailAddress(value string) string {
value = strings.TrimSpace(value)
for {
lower := strings.ToLower(value)
switch {
case strings.HasPrefix(lower, "mailto:"):
value = strings.TrimSpace(value[len("mailto:"):])
case strings.HasPrefix(lower, "https://"):
value = strings.TrimSpace(value[len("https://"):])
case strings.HasPrefix(lower, "http://"):
value = strings.TrimSpace(value[len("http://"):])
default:
return value
}
}
}
func firstNonEmptyURL(values ...string) string {
for _, v := range values {
if u := sanitizeURL(v); u != "" {
return u
}
}
return ""
}
// TelegramURL 客服/商务 TG:优先 telegram,其次 telegramAdd、tgGroup。
func (c ConfigInfo) TelegramURL() string {
return firstNonEmptyURL(c.Telegram, c.TelegramAdd, c.TGGroup)
}
// TelegramHandle 从 TG 链接提取展示用 @用户名;无法解析时返回空。
func (c ConfigInfo) TelegramHandle() string {
raw := c.TelegramURL()
raw = strings.TrimRight(raw, "/")
if i := strings.LastIndex(raw, "/"); i >= 0 && i+1 < len(raw) {
raw = raw[i+1:]
}
raw = strings.TrimPrefix(strings.TrimSpace(raw), "@")
if raw == "" || strings.Contains(raw, ".") || strings.Contains(raw, "?") {
return ""
}
return "@" + raw
}