You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

145 lines
5.4 KiB

package console
import (
"strings"
"time"
"yunyan/comm"
"yunyan/lego/sys/postgres"
"yunyan/pb"
"github.com/gin-gonic/gin"
)
// ============================ 渠道分发 (channelapp) ============================
//
// 「SaaS 管理 → 渠道分发」的后端:管理各应用在各分发渠道(华为/小米/OPPO/VIVO/荣耀/官方/苹果/谷歌)
// 上**因渠道而异**的东西——本渠道下载地址、上架状态、支付渠道、是否允许跳过设备绑定。
// 模型见 comm/channelapp.go,存 console 主库(postgres.GetSys()),按 app_name 作用域,
// 业务服务(home 的 user 模块)运行时按 (app_name=? OR app_name='') 直读下发。
//
// ⚠️ 版本号/最低支持版本/强制更新/更新日志/送审版本/游客登录开关**不在这里**:它们是
// 「整个应用一套」的,已搬到「服务配置 → 版本控制 / 游客显隐控制」(api_apprelease.go)。
// 别再往本页加这些字段——按渠道各存一份的直接后果是同一个开关有 8 处能改、客户端只读一处。
//
// 旧实现(deep_server modules/api/api_*channelapp.go + 各应用业务库 mysql 的 channelapp 表)已下线:
// 数据统一收到 console 主库,后台一个库即可总览全部应用的渠道版本。
//
// 支付:本页只管「这个渠道开放哪几种支付」(PayChannels);各支付方式的商户凭据仍在
// 「应用中心 → 业务功能配置」的支付分组(app_module_config)里配,不在此重复。
// getChannelPayStatus 负责把两边对上——告诉前端哪些已开的支付渠道其实还没配凭据。
// getChannelApps 列出某作用域下的渠道配置(app_name=”为全局默认)。
func (this *serverComp) getChannelApps(c *gin.Context) {
var req struct {
AppName string `json:"app_name"`
}
_ = c.ShouldBindJSON(&req)
items := make([]*comm.ChannelApp, 0)
if err := postgres.Find(comm.TableChannelAppCfg, &items, "app_name=?", req.AppName); err != nil {
writeErr(c, pb.ErrorCode_DBError, err.Error())
return
}
writeOK(c, gin.H{"items": items})
}
// saveChannelApp 新增或更新一个渠道配置(按 app_name+channel upsert)。
func (this *serverComp) saveChannelApp(c *gin.Context) {
var m comm.ChannelApp
if err := c.ShouldBindJSON(&m); err != nil {
writeErr(c, pb.ErrorCode_ReqParameterError, err.Error())
return
}
if m.Channel == 0 {
writeErr(c, pb.ErrorCode_ReqParameterError, "渠道 必选")
return
}
// 版本/强更/游客登录的校验已随字段搬到 api_apprelease.go(按应用配,不分渠道)。
now := time.Now().UnixMilli()
m.Updatetime = now
old := &comm.ChannelApp{}
err := postgres.FindOne(comm.TableChannelAppCfg, old, "app_name=? AND channel=?", m.AppName, m.Channel)
if err != nil {
m.RowId = 0
m.Createtime = now
err = postgres.Insert(comm.TableChannelAppCfg, &m)
} else {
m.RowId = old.RowId
m.Createtime = old.Createtime
err = postgres.Save(comm.TableChannelAppCfg, &m)
}
if err != nil {
writeErr(c, pb.ErrorCode_DBError, err.Error())
return
}
broadcastConfigChanged(comm.ConfigKindChannelApp, "update", 0)
writeOK(c, &m)
}
// delChannelApp 删除某作用域下某渠道的配置。
func (this *serverComp) delChannelApp(c *gin.Context) {
var req struct {
AppName string `json:"app_name"`
Channel int32 `json:"channel"`
}
_ = c.ShouldBindJSON(&req)
if req.Channel == 0 {
writeErr(c, pb.ErrorCode_ReqParameterError, "channel 必填")
return
}
if err := postgres.Delete(comm.TableChannelAppCfg, "app_name=? AND channel=?", req.AppName, req.Channel); err != nil {
writeErr(c, pb.ErrorCode_DBError, err.Error())
return
}
broadcastConfigChanged(comm.ConfigKindChannelApp, "delete", 0)
writeOK(c, gin.H{"channel": req.Channel})
}
// getChannelPayStatus 查这个应用的支付凭据配了哪几种。
//
// 渠道配置里的 PayChannels 只是「开放哪几种支付入口」,真正的商户凭据在**应用业务库**的
// app_module_config 里。两者分处不同库,运营很容易开了入口却忘了配凭据,故后台直接把结论算好:
// 遍历该 app_name 下的部署,连上任意一个业务库,读出已配置的支付模块键。
// 全局作用域(app_name=”)没有对应业务库,返回空表示「无法判定」,前端据此不告警。
func (this *serverComp) getChannelPayStatus(c *gin.Context) {
var req struct {
AppName string `json:"app_name"`
}
_ = c.ShouldBindJSON(&req)
resp := gin.H{"configured": []string{}, "checked": false}
if strings.TrimSpace(req.AppName) == "" {
writeOK(c, resp)
return
}
regs := make([]*AppRegistry, 0)
if err := postgres.Find(comm.TableAppRegistry, &regs, "app_name=?", req.AppName); err != nil || len(regs) == 0 {
writeOK(c, resp)
return
}
payModules := map[string]bool{}
for _, m := range comm.PayChannelModule {
payModules[m] = true
}
for _, r := range regs {
db, err := this.module.registry.getServiceDB(r.Id)
if err != nil {
continue // 这个部署连不上,试下一个
}
rows, err := listModuleConfig(db, "")
if err != nil {
continue
}
configured := make([]string, 0, len(payModules))
seen := map[string]bool{}
for _, row := range rows {
if !payModules[row.Module] || seen[row.Module] || strings.TrimSpace(row.Value) == "" {
continue
}
seen[row.Module] = true
configured = append(configured, row.Module)
}
writeOK(c, gin.H{"configured": configured, "checked": true, "app_id": r.Id})
return
}
writeOK(c, resp)
}