package web import ( "encoding/json" "fmt" "net/url" "strings" "videoweb/app/service/authser" "videoweb/app/service/playletser" "videoweb/app/service/usercenterser" "videoweb/pub/common/log" "videoweb/pub/common/useragent" "github.com/gin-gonic/gin" ) type profileWork struct { Title, Meta, Episodes, Badge, Image, Progress, Remaining, URL string } // Profile 从当前会话拉取用户信息、观看历史和收藏,不展示演示账号数据。 func Profile(c *gin.Context) { data := gin.H{ "title": "个人中心 - 黄果短剧", "navActive": "profile", "accountTab": "profile", } responses := gin.H{} loadAccountSummary(c, data, responses) if useragent.TokenFromRequest(c.Request) != "" { fetchProfileLists(c, data, responses) } if pretty, err := json.MarshalIndent(responses, "", " "); err == nil { data["responseJSON"] = string(pretty) } HTMLOK(c, "profile.html", data) } func loadAccountSummary(c *gin.Context, data, responses gin.H) { data["userName"] = "未登录" data["balance"] = "—" data["historyCount"] = "—" data["favoriteCount"] = "—" data["chasingCount"] = "—" data["boughtChapterCount"] = "—" user := authser.SyncUserOnEnter(c) if user == nil { if useragent.TokenFromRequest(c.Request) != "" { responses["auth/getInfo"] = gin.H{"error": "加载失败"} fetchProfileStats(c, data, responses) return } responses["auth/getInfo"] = gin.H{"error": "暂无登录会话"} return } applyProfileInfo(data, responses, user) if useragent.TokenFromRequest(c.Request) != "" { fetchProfileStats(c, data, responses) } } func fetchProfileStats(c *gin.Context, data, responses gin.H) { stats, code, err := usercenterser.Fetch(c) if retry, _ := authser.OnSessionExpired(c, code); retry { stats, code, err = usercenterser.Fetch(c) } if err != nil || stats == nil { responses["user/center/data"] = gin.H{"error": "加载失败"} if err != nil { log.Error("fetch user center data failed", log.E(err)) } return } responses["user/center/data"] = gin.H{"code": code, "data": stats} data["historyCount"] = fmt.Sprint(stats.WatchCount) data["favoriteCount"] = fmt.Sprint(stats.CollectCount) data["chasingCount"] = fmt.Sprint(stats.ChasingCount) data["boughtChapterCount"] = fmt.Sprint(stats.BoughtChapterCount) } func fetchProfileLists(c *gin.Context, data, responses gin.H) { query := playletser.HistoryListQuery{PageNum: 1, PageSize: 6} history, code, err := playletser.FetchHistoryList(c, query) if retry, _ := authser.OnSessionExpired(c, code); retry { history, _, err = playletser.FetchHistoryList(c, query) } if err == nil && history != nil { responses["playlet/history/list"] = gin.H{"code": 200, "data": history} data["history"] = profileHistoryWorks(history.List) } else if err != nil { responses["playlet/history/list"] = gin.H{"error": "加载失败"} log.Error("fetch profile history failed", log.E(err)) data["historyUnavailable"] = true } collectQuery := playletser.CollectListQuery{PageNum: 1, PageSize: 6, WatchStatus: 0} favorites, code, err := playletser.FetchCollectList(c, collectQuery) if retry, _ := authser.OnSessionExpired(c, code); retry { favorites, _, err = playletser.FetchCollectList(c, collectQuery) } if err == nil && favorites != nil { responses["playlet/collect/list"] = gin.H{"code": 200, "data": favorites} data["favorites"] = profileFavoriteWorks(favorites.List) } else if err != nil { responses["playlet/collect/list"] = gin.H{"error": "加载失败"} log.Error("fetch profile favorites failed", log.E(err)) data["favoritesUnavailable"] = true } } func applyProfileInfo(data, responses gin.H, user *authser.LoginResp) { if user == nil { return } // 登录响应可能包含 token;调试区域只展示非凭证字段。 rawUser, _ := json.Marshal(user) var safeUser map[string]any _ = json.Unmarshal(rawUser, &safeUser) delete(safeUser, "token") responses["auth/getInfo"] = gin.H{"code": 200, "data": safeUser} name := strings.TrimSpace(user.NickName) if name == "" { name = strings.TrimSpace(user.AccountNo) } if name == "" { name = "用户" } data["userName"] = name data["setting"] = authser.BuildSettingVM(user) data["userID"] = user.UserID data["userId"] = fmt.Sprint(user.UserID) data["balance"] = fmt.Sprint(user.Recharge) data["recharge"] = user.Recharge data["rechargeText"] = authser.FormatRecharge(user.Recharge) if avatar := safeProfileImage(user.Avatar); avatar != "" { data["avatar"] = avatar } } func safeProfileImage(raw string) string { raw = strings.TrimSpace(raw) if strings.HasPrefix(raw, "/static/") { return raw } u, err := url.Parse(raw) if err == nil && (u.Scheme == "https" || u.Scheme == "http") && u.Host != "" { return raw } return "" } func profileHistoryWorks(items []playletser.PlayletHistoryData) []profileWork { works := make([]profileWork, 0, len(items)) for _, item := range items { if len(works) == 6 { break } name := strings.TrimSpace(item.Title) if name == "" { name = strings.TrimSpace(item.PlayName) } if name == "" { continue } progress := 0 if item.TotalEpisode > 0 { progress = item.WatchedCount * 100 / item.TotalEpisode } if progress < 0 { progress = 0 } if progress > 100 { progress = 100 } meta := "观看记录" if item.LastEpisode > 0 { meta = fmt.Sprintf("看至第 %d 集", item.LastEpisode) } remaining := "" if item.UnwatchedCount > 0 { remaining = fmt.Sprintf("剩 %d 集", item.UnwatchedCount) } works = append(works, profileWork{Title: name, Meta: meta, Image: profileCover(item.Cover), Progress: fmt.Sprintf("%d%%", progress), Remaining: remaining, URL: profilePlayURL(item.Slug, item.ID, item.LastEpisode)}) } return works } func profileFavoriteWorks(items []playletser.PlayletCollectData) []profileWork { works := make([]profileWork, 0, len(items)) for _, item := range items { if len(works) == 6 { break } name := strings.TrimSpace(item.Title) if name == "" { name = strings.TrimSpace(item.PlayName) } if name == "" { continue } work := profileWork{Title: name, Meta: strings.Join(item.ThemeNames, " "), Image: profileCover(item.Cover), URL: profilePlayURL(item.Slug, item.ID, 1)} if item.TotalEpisode > 0 { work.Episodes = fmt.Sprintf("全 %d 集", item.TotalEpisode) } if item.IsFeatured { work.Badge = "爆剧" } works = append(works, work) } return works } func profileCover(raw string) string { if safe := safeProfileImage(raw); safe != "" { return safe } return "/static/images/placeholder.png?v=2" } func profilePlayURL(slug string, id int64, episode int) string { if slug == "" { if id <= 0 { return "" } slug = fmt.Sprint(id) } if episode < 1 { episode = 1 } return "/play/" + url.PathEscape(slug) + "/" + fmt.Sprint(episode) }