126 lines
3.7 KiB
Go
126 lines
3.7 KiB
Go
package opscenter
|
||
|
||
import (
|
||
"context"
|
||
"sort"
|
||
"strings"
|
||
"time"
|
||
|
||
"hyapp-admin-server/internal/modules/appregistry"
|
||
"hyapp-admin-server/internal/modules/luckygift"
|
||
"hyapp-admin-server/internal/response"
|
||
|
||
"github.com/gin-gonic/gin"
|
||
)
|
||
|
||
type Handler struct {
|
||
apps *appregistry.Service
|
||
luckyGift *luckygift.Handler
|
||
}
|
||
|
||
type appDTO struct {
|
||
AppID int64 `json:"app_id"`
|
||
AppCode string `json:"app_code"`
|
||
AppName string `json:"app_name"`
|
||
PackageName string `json:"package_name"`
|
||
Platform string `json:"platform"`
|
||
Status string `json:"status"`
|
||
Source string `json:"source"`
|
||
CreatedAtMS int64 `json:"created_at_ms"`
|
||
UpdatedAtMS int64 `json:"updated_at_ms"`
|
||
}
|
||
|
||
func New(apps *appregistry.Service, luckyGift *luckygift.Handler) *Handler {
|
||
return &Handler{apps: apps, luckyGift: luckyGift}
|
||
}
|
||
|
||
func (h *Handler) ListApps(c *gin.Context) {
|
||
ctx, cancel := context.WithTimeout(c.Request.Context(), 3*time.Second)
|
||
defer cancel()
|
||
|
||
items := make([]appDTO, 0, 4)
|
||
if h.apps != nil {
|
||
registryApps, err := h.apps.ListApps(ctx)
|
||
if err != nil {
|
||
response.ServerError(c, "获取应用列表失败")
|
||
return
|
||
}
|
||
for _, item := range registryApps {
|
||
items = append(items, appDTO{
|
||
AppID: item.AppID,
|
||
AppCode: strings.ToLower(strings.TrimSpace(item.AppCode)),
|
||
AppName: strings.TrimSpace(item.AppName),
|
||
PackageName: strings.TrimSpace(item.PackageName),
|
||
Platform: strings.TrimSpace(item.Platform),
|
||
Status: strings.TrimSpace(item.Status),
|
||
Source: "registry",
|
||
CreatedAtMS: item.CreatedAtMs,
|
||
UpdatedAtMS: item.UpdatedAtMs,
|
||
})
|
||
}
|
||
}
|
||
|
||
// ops-center 的外部幸运礼物接入只认 app_code。这里强制补齐 yumi/aslan,使运营首屏能配置外部 App,
|
||
// 但不反向写入 admin app registry,避免把临时接入白名单伪装成完整 App 主数据。
|
||
nowMS := time.Now().UTC().UnixMilli()
|
||
items = append(items,
|
||
appDTO{AppCode: "yumi", AppName: "Yumi", Status: "active", Source: "fixed", CreatedAtMS: nowMS, UpdatedAtMS: nowMS},
|
||
appDTO{AppCode: "aslan", AppName: "Aslan", Status: "active", Source: "fixed", CreatedAtMS: nowMS, UpdatedAtMS: nowMS},
|
||
)
|
||
|
||
items = filterApps(dedupeApps(items), c.Query("app_code"), c.Query("status"))
|
||
response.OK(c, gin.H{"items": items, "total": len(items)})
|
||
}
|
||
|
||
func filterApps(items []appDTO, appCode string, status string) []appDTO {
|
||
appCode = strings.ToLower(strings.TrimSpace(appCode))
|
||
status = strings.ToLower(strings.TrimSpace(status))
|
||
if appCode == "" && status == "" {
|
||
return items
|
||
}
|
||
filtered := make([]appDTO, 0, len(items))
|
||
for _, item := range items {
|
||
if appCode != "" && !strings.Contains(strings.ToLower(item.AppCode), appCode) {
|
||
continue
|
||
}
|
||
if status != "" && strings.ToLower(item.Status) != status {
|
||
continue
|
||
}
|
||
filtered = append(filtered, item)
|
||
}
|
||
return filtered
|
||
}
|
||
|
||
func dedupeApps(items []appDTO) []appDTO {
|
||
seen := make(map[string]appDTO, len(items))
|
||
for _, item := range items {
|
||
code := strings.ToLower(strings.TrimSpace(item.AppCode))
|
||
if code == "" {
|
||
continue
|
||
}
|
||
item.AppCode = code
|
||
if item.AppName == "" {
|
||
item.AppName = code
|
||
}
|
||
if item.Status == "" {
|
||
item.Status = "active"
|
||
}
|
||
// registry 里已存在同 app_code 时以真实主数据为准;固定 app 只补缺口,不覆盖包名、平台和时间戳。
|
||
if existing, ok := seen[code]; ok && existing.Source == "registry" {
|
||
continue
|
||
}
|
||
seen[code] = item
|
||
}
|
||
result := make([]appDTO, 0, len(seen))
|
||
for _, item := range seen {
|
||
result = append(result, item)
|
||
}
|
||
sort.Slice(result, func(i, j int) bool {
|
||
if result[i].Source != result[j].Source {
|
||
return result[i].Source == "registry"
|
||
}
|
||
return result[i].AppCode < result[j].AppCode
|
||
})
|
||
return result
|
||
}
|