package repository import ( "strings" "hyapp-admin-server/internal/model" ) type AppPopupListOptions struct { AppCode string Keyword string Status string } func (s *Store) ListAppPopups(options AppPopupListOptions) ([]model.AppPopup, error) { var items []model.AppPopup // 管理后台列表先用 app_code 做租户隔离,再叠加状态和关键字;时间窗口只改变展示资格,不影响后台可见性。 query := s.db.Where("app_code = ?", strings.TrimSpace(options.AppCode)) if options.Status != "" { query = query.Where("status = ?", strings.TrimSpace(options.Status)) } if options.Keyword != "" { like := "%" + strings.TrimSpace(options.Keyword) + "%" query = query.Where("(code LIKE ? OR name LIKE ? OR jump_url LIKE ? OR image_url LIKE ?)", like, like, like, like) } err := query.Order("sort_order ASC, id DESC").Find(&items).Error return items, err } func (s *Store) HasAppPopupCode(appCode string, code string, excludeID uint) (bool, error) { var count int64 // code 是客户端频控和埋点使用的稳定标识,同一个 App 下必须唯一;更新时排除当前记录。 query := s.db.Model(&model.AppPopup{}). Where("app_code = ? AND code = ?", strings.TrimSpace(appCode), strings.TrimSpace(code)) if excludeID > 0 { query = query.Where("id <> ?", excludeID) } if err := query.Count(&count).Error; err != nil { return false, err } return count > 0, nil } func (s *Store) ExpireAppPopups(appCode string, nowMs int64) error { appCode = strings.TrimSpace(appCode) if appCode == "" || nowMs <= 0 { return nil } // 只把已经结束的 active 弹窗转成 expired,手动关闭的配置不自动覆盖,避免运营状态被时间任务误改。 return s.db.Model(&model.AppPopup{}). Where("app_code = ? AND status = ? AND ends_at_ms > 0 AND ends_at_ms <= ?", appCode, "active", nowMs). Updates(map[string]any{ "status": "expired", "updated_at_ms": nowMs, }).Error } func (s *Store) GetAppPopup(appCode string, id uint) (model.AppPopup, error) { var item model.AppPopup // app_code 和 id 同时限定,防止多 App 后台误编辑其他应用的弹窗。 err := s.db.Where("app_code = ? AND id = ?", strings.TrimSpace(appCode), id).First(&item).Error return item, err } func (s *Store) CreateAppPopup(item *model.AppPopup) error { return s.db.Create(item).Error } func (s *Store) UpdateAppPopup(item *model.AppPopup) error { return s.db.Save(item).Error } func (s *Store) DeleteAppPopup(appCode string, id uint) error { // 弹窗配置和 Banner/开屏保持一致,后台删除使用硬删除;审计在 handler 层写操作日志。 return s.db.Where("app_code = ? AND id = ?", strings.TrimSpace(appCode), id).Delete(&model.AppPopup{}).Error }