Files
fish03andClaude Opus 5.5 bef9f8b4ed Initial commit
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-23 14:43:16 +07:00

146 lines
3.3 KiB
Go

package commentser
import (
"fmt"
"net/url"
"strconv"
"strings"
"time"
"videoweb/app/service/authser"
"videoweb/app/service/upstream"
"videoweb/pub/common/log"
"github.com/gin-gonic/gin"
)
const (
listPath = "/api/app/comment/list"
defaultCommentSize = 10
)
// ListQuery 评论列表查询参数。
type ListQuery struct {
ObjectID int64
ObjectType int
PageNum int
PageSize int
SortOrder int
}
// Normalize 校正分页与排序默认值。
func (q *ListQuery) Normalize() {
if q.PageNum <= 0 {
q.PageNum = 1
}
if q.PageSize <= 0 {
q.PageSize = defaultCommentSize
}
if q.PageSize > 50 {
q.PageSize = 50
}
if q.ObjectType != ObjectTypeChapter {
q.ObjectType = ObjectTypePlaylet
}
if q.SortOrder != SortLatest {
q.SortOrder = SortHot
}
}
// FetchList 分页查询评论。
func FetchList(c *gin.Context, q ListQuery) (*GetCommentListResp, error) {
q.Normalize()
if q.ObjectID <= 0 {
return nil, fmt.Errorf("comment list invalid objectId")
}
params := url.Values{}
params.Set("objectId", strconv.FormatInt(q.ObjectID, 10))
params.Set("objectType", strconv.Itoa(q.ObjectType))
params.Set("pageNum", strconv.Itoa(q.PageNum))
params.Set("pageSize", strconv.Itoa(q.PageSize))
params.Set("sortOrder", strconv.Itoa(q.SortOrder))
authser.EnsureGuestOnEnter(c)
requestPath := listPath + "?" + params.Encode()
env, err := fetchListOnce(c, requestPath)
if err != nil {
return nil, err
}
if env.Code != 200 && authser.IsSessionExpiredCode(env.Code) && authser.RecoverContentSession(c, env.Code) {
env, err = fetchListOnce(c, requestPath)
if err != nil {
return nil, err
}
}
if env.Code != 200 {
return nil, fmt.Errorf("comment list code=%d msg=%s", env.Code, env.Msg)
}
return &env.Data, nil
}
func fetchListOnce(c *gin.Context, path string) (*APIEnvelope[GetCommentListResp], error) {
var env APIEnvelope[GetCommentListResp]
if err := upstream.GetJSON(c, path, &env); err != nil {
return nil, err
}
return &env, nil
}
// FetchListOrEmpty 失败时返回空列表。
func FetchListOrEmpty(c *gin.Context, q ListQuery) *GetCommentListResp {
data, err := FetchList(c, q)
if err != nil {
log.Error("fetch comment list failed", log.E(err))
return &GetCommentListResp{
ObjectID: q.ObjectID,
PageNum: q.PageNum,
PageSize: q.PageSize,
}
}
if data == nil {
return &GetCommentListResp{
ObjectID: q.ObjectID,
PageNum: q.PageNum,
PageSize: q.PageSize,
}
}
return data
}
// ParseSortOrder 解析站点评论排序(1 热门 / 2 最新)。
func ParseSortOrder(s string) int {
n, err := strconv.Atoi(strings.TrimSpace(s))
if err != nil || n != SortLatest {
return SortHot
}
return SortLatest
}
// FormatCreatedAt 展示用时间格式化(非字段映射)。
func FormatCreatedAt(raw string) string {
raw = strings.TrimSpace(raw)
if raw == "" {
return ""
}
layouts := []string{
time.RFC3339Nano,
time.RFC3339,
"2006-01-02T15:04:05Z07:00",
"2006-01-02 15:04:05",
}
for _, layout := range layouts {
if t, err := time.Parse(layout, raw); err == nil {
return t.Local().Format("2006/1/2 15:04")
}
}
return raw
}
// AvatarOrDefault 头像空时回退默认图。
func AvatarOrDefault(avatar string) string {
avatar = strings.TrimSpace(avatar)
if avatar == "" {
return "/static/images/avatar.png"
}
return avatar
}