Files
nl-video-api/internal/service/user_watch_history.go
2025-08-03 00:11:15 +08:00

358 lines
9.3 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package service
import (
"context"
"github.com/gogf/gf/v2/errors/gerror"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/net/ghttp"
"github.com/gogf/gf/v2/os/gtime"
"github.com/gogf/gf/v2/util/gconv"
"nl-video-api/internal/dao"
"nl-video-api/internal/model/entity"
"nl-video-api/utility/response"
)
// UserWatchHistoryService 用户观看历史服务
type UserWatchHistoryService struct{}
// NewUserWatchHistoryService 创建用户观看历史服务实例
func NewUserWatchHistoryService() *UserWatchHistoryService {
return &UserWatchHistoryService{}
}
// UserWatchHistoryCreateReq 创建观看历史请求
type UserWatchHistoryCreateReq struct {
MovieId uint `json:"movie_id" v:"required#电影ID不能为空"`
EpisodeId uint `json:"episode_id"`
Progress int `json:"progress" v:"required#观看进度不能为空"`
WatchTime int `json:"watch_time" v:"required#观看时长不能为空"`
}
// UserWatchHistoryListReq 获取观看历史列表请求
type UserWatchHistoryListReq struct {
Page int `json:"page" v:"min:1#页码最小为1"`
Size int `json:"size" v:"min:1,max:100#每页数量范围1-100"`
}
// UserWatchHistoryListRes 观看历史列表响应
type UserWatchHistoryListRes struct {
List []UserWatchHistoryItem `json:"list"`
Total int `json:"total"`
Page int `json:"page"`
Size int `json:"size"`
}
// UserWatchHistoryItem 观看历史项
type UserWatchHistoryItem struct {
Id uint `json:"id"`
MovieId uint `json:"movie_id"`
MovieTitle string `json:"movie_title"`
MoviePoster string `json:"movie_poster"`
EpisodeId uint `json:"episode_id"`
EpisodeTitle string `json:"episode_title"`
Progress int `json:"progress"`
WatchTime int `json:"watch_time"`
LastWatchTime int64 `json:"last_watch_time"`
CreatedAt int64 `json:"created_at"`
}
// UserWatchHistoryClearReq 清空观看历史请求
type UserWatchHistoryClearReq struct {
UserId uint `json:"user_id"`
}
// UserWatchHistoryProgressReq 获取观看进度请求
type UserWatchHistoryProgressReq struct {
MovieId uint `json:"movie_id" v:"required#电影ID不能为空"`
EpisodeId uint `json:"episode_id"`
}
// UserWatchHistoryProgressRes 观看进度响应
type UserWatchHistoryProgressRes struct {
Progress int `json:"progress"`
WatchTime int `json:"watch_time"`
LastWatchTime int64 `json:"last_watch_time"`
}
// Create 创建观看历史
func (s *UserWatchHistoryService) Create(r *ghttp.Request) {
var req UserWatchHistoryCreateReq
if err := r.Parse(&req); err != nil {
response.Error(r, response.CodeInvalidParam, err.Error())
return
}
// 获取用户ID(从JWT token或session中获取)
userId := GetUserIdFromContext(r.Context())
// 检查是否已存在观看历史
var existHistory entity.UserWatchHistory
err := dao.UserWatchHistory.Ctx(r.Context()).
Where("user_id", userId).
Where("movie_id", req.MovieId).
Where("episode_id", req.EpisodeId).
Scan(&existHistory)
if err != nil && !g.IsEmpty(existHistory) {
response.Error(r, response.CodeInternalError, "系统错误")
return
}
if existHistory.Id > 0 {
// 更新现有记录
_, err = dao.UserWatchHistory.Ctx(r.Context()).
Where("id", existHistory.Id).
Update(g.Map{
"progress": req.Progress,
"watch_time": req.WatchTime,
"last_watch_time": gtime.Now(),
"updated_at": gtime.Now(),
})
} else {
// 创建新记录
history := &entity.UserWatchHistory{
UserId: gconv.Int(userId),
MovieId: gconv.Int(req.MovieId),
EpisodeId: gconv.Int(req.EpisodeId),
Progress: float64(req.Progress),
WatchTime: req.WatchTime,
LastWatchTime: int(gtime.Now().Unix()),
CreatedAt: gtime.Now(),
}
_, err = dao.UserWatchHistory.Ctx(r.Context()).Insert(history)
}
if err != nil {
response.Error(r, response.CodeInternalError, "保存观看历史失败")
return
}
response.Success(r, "保存成功")
}
// GetList 获取观看历史列表
func (s *UserWatchHistoryService) GetList(r *ghttp.Request) {
var req UserWatchHistoryListReq
if err := r.Parse(&req); err != nil {
response.Error(r, response.CodeInvalidParam, err.Error())
return
}
// 设置默认值
if req.Page <= 0 {
req.Page = 1
}
if req.Size <= 0 {
req.Size = 10
}
// 获取用户ID
userId := GetUserIdFromContext(r.Context())
// 构建查询
query := dao.UserWatchHistory.Ctx(r.Context()).Where("user_id", userId)
// 获取总数
total, err := query.Count()
if err != nil {
response.Error(r, response.CodeInternalError, "获取数据失败")
return
}
// 获取列表数据
var histories []entity.UserWatchHistory
err = query.Order("last_watch_time DESC").
Limit((req.Page-1)*req.Size, req.Size).
Scan(&histories)
if err != nil {
response.Error(r, response.CodeInternalError, "获取数据失败")
return
}
// 构建响应数据
var list []UserWatchHistoryItem
for _, history := range histories {
// 获取电影信息
var movie entity.Movie
err = g.DB().Model("movie").Where("id", history.MovieId).Scan(&movie)
if err != nil {
continue
}
// 获取剧集信息(如果有)
var episode entity.Episode
episodeTitle := ""
if history.EpisodeId > 0 {
err = g.DB().Model("episode").Where("id", history.EpisodeId).Scan(&episode)
if err == nil {
episodeTitle = episode.Title
}
}
list = append(list, UserWatchHistoryItem{
Id: gconv.Uint(history.Id),
MovieId: gconv.Uint(history.MovieId),
MovieTitle: movie.Title,
MoviePoster: movie.Poster,
EpisodeId: gconv.Uint(history.EpisodeId),
EpisodeTitle: episodeTitle,
Progress: int(history.Progress),
WatchTime: history.WatchTime,
LastWatchTime: int64(history.LastWatchTime),
CreatedAt: history.CreatedAt.Unix(),
})
}
res := UserWatchHistoryListRes{
List: list,
Total: total,
Page: req.Page,
Size: req.Size,
}
response.Success(r, res)
}
// Delete 删除观看历史
func (s *UserWatchHistoryService) Delete(r *ghttp.Request) {
id := r.Get("id").Uint()
if id == 0 {
response.Error(r, response.CodeInvalidParam, "ID不能为空")
return
}
// 获取用户ID
userId := GetUserIdFromContext(r.Context())
// 删除记录
_, err := dao.UserWatchHistory.Ctx(r.Context()).
Where("id", id).
Where("user_id", userId).
Delete()
if err != nil {
response.Error(r, response.CodeInternalError, "删除失败")
return
}
response.Success(r, "删除成功")
}
// Clear 清空观看历史
func (s *UserWatchHistoryService) Clear(ctx context.Context, req *UserWatchHistoryClearReq) error {
// 删除用户的所有观看历史
_, err := dao.UserWatchHistory.Ctx(ctx).
Where("user_id", req.UserId).
Delete()
if err != nil {
return gerror.New("清空观看历史失败")
}
return nil
}
// Add 添加观看历史
func (s *UserWatchHistoryService) Add(r *ghttp.Request) {
var req UserWatchHistoryCreateReq
if err := r.Parse(&req); err != nil {
response.Error(r, response.CodeInvalidParam, err.Error())
return
}
// 获取用户ID
userId := GetUserIdFromContext(r.Context())
// 检查是否已存在观看历史
var existHistory entity.UserWatchHistory
err := dao.UserWatchHistory.Ctx(r.Context()).
Where("user_id", userId).
Where("movie_id", req.MovieId).
Where("episode_id", req.EpisodeId).
Scan(&existHistory)
if err != nil && !g.IsEmpty(existHistory) {
response.Error(r, response.CodeInternalError, "系统错误")
return
}
if existHistory.Id > 0 {
// 更新现有记录
_, err = dao.UserWatchHistory.Ctx(r.Context()).
Where("id", existHistory.Id).
Update(g.Map{
"progress": req.Progress,
"watch_time": req.WatchTime,
"last_watch_time": gtime.Now().Unix(),
"updated_at": gtime.Now(),
})
} else {
// 创建新记录
history := &entity.UserWatchHistory{
UserId: gconv.Int(userId),
MovieId: gconv.Int(req.MovieId),
EpisodeId: gconv.Int(req.EpisodeId),
Progress: float64(req.Progress),
WatchTime: req.WatchTime,
LastWatchTime: int(gtime.Now().Unix()),
CreatedAt: gtime.Now(),
}
_, err = dao.UserWatchHistory.Ctx(r.Context()).Insert(history)
}
if err != nil {
response.Error(r, response.CodeInternalError, "保存观看历史失败")
return
}
response.Success(r, "保存成功")
}
// GetProgress 获取观看进度
func (s *UserWatchHistoryService) GetProgress(r *ghttp.Request) {
var req UserWatchHistoryProgressReq
if err := r.Parse(&req); err != nil {
response.Error(r, response.CodeInvalidParam, err.Error())
return
}
// 获取用户ID
userId := GetUserIdFromContext(r.Context())
// 查询观看历史
var history entity.UserWatchHistory
err := dao.UserWatchHistory.Ctx(r.Context()).
Where("user_id", userId).
Where("movie_id", req.MovieId).
Where("episode_id", req.EpisodeId).
Scan(&history)
if err != nil && !g.IsEmpty(history) {
response.Error(r, response.CodeInternalError, "获取观看进度失败")
return
}
var res UserWatchHistoryProgressRes
if history.Id > 0 {
res = UserWatchHistoryProgressRes{
Progress: int(history.Progress),
WatchTime: history.WatchTime,
LastWatchTime: int64(history.LastWatchTime),
}
} else {
res = UserWatchHistoryProgressRes{
Progress: 0,
WatchTime: 0,
LastWatchTime: 0,
}
}
response.Success(r, res)
}