初始化v1

This commit is contained in:
2025-08-03 00:11:15 +08:00
commit b88c8b8afa
171 changed files with 22353 additions and 0 deletions

View File

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,234 @@
package auth
import (
"context"
"errors"
"github.com/gogf/gf/v2/frame/g"
"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"
)
// PermissionService 权限服务
type PermissionService struct{}
var Permission = &PermissionService{}
// PermissionCreateReq 创建权限请求
type PermissionCreateReq struct {
Name string `json:"name" v:"required|length:2,50#权限名称不能为空|权限名称长度为2-50位"`
Slug string `json:"slug" v:"required|length:2,100#权限标识不能为空|权限标识长度为2-100位"`
Type string `json:"type" v:"required|in:1,2,3#权限类型不能为空|权限类型只能是1,2,3"`
ParentId int `json:"parent_id" v:"min:0#父级ID不能小于0"`
Path string `json:"path"` // 路由路径
Component string `json:"component"` // 组件路径
Icon string `json:"icon"` // 图标
ApiPath string `json:"api_path"` // API路径
Method string `json:"method"` // 请求方法
Description string `json:"description"` // 权限描述
Sort int `json:"sort"` // 排序
Status int `json:"status" v:"in:0,1#状态只能为0或1"`
}
// PermissionUpdateReq 更新权限请求
type PermissionUpdateReq struct {
Id int `json:"id" v:"required|min:1#权限ID不能为空"`
Name string `json:"name" v:"required|length:2,50#权限名称不能为空|权限名称长度为2-50位"`
Slug string `json:"slug" v:"required|length:2,100#权限标识不能为空|权限标识长度为2-100位"`
Type string `json:"type" v:"required|in:1,2,3#权限类型不能为空|权限类型只能是1,2,3"`
ParentId int `json:"parent_id" v:"min:0#父级ID不能小于0"`
Path string `json:"path"` // 路由路径
Component string `json:"component"` // 组件路径
Icon string `json:"icon"` // 图标
ApiPath string `json:"api_path"` // API路径
Method string `json:"method"` // 请求方法
Description string `json:"description"` // 权限描述
Sort int `json:"sort"` // 排序
Status int `json:"status" v:"in:0,1#状态只能为0或1"`
}
// Create 创建权限
func (s *PermissionService) Create(ctx context.Context, req *PermissionCreateReq) (int, error) {
// 检查权限标识是否存在
exists, err := dao.Permission.CheckCodeExists(ctx, req.Slug, 0)
if err != nil {
return 0, err
}
if exists {
return 0, errors.New("权限标识已存在")
}
// 如果有父级ID,检查父级是否存在
if req.ParentId > 0 {
parent, err := dao.Permission.GetById(ctx, req.ParentId)
if err != nil {
return 0, err
}
if parent == nil {
return 0, errors.New("父级权限不存在")
}
}
// 创建权限数据
permission := &entity.Permission{
Name: req.Name,
Slug: req.Slug,
Type: gconv.Int(req.Type),
ParentId: req.ParentId,
Path: req.Path,
Component: req.Component,
Icon: req.Icon,
ApiPath: req.ApiPath,
Method: req.Method,
Description: req.Description,
Sort: req.Sort,
Status: req.Status,
CreatedAt: gtime.Now().String(),
UpdatedAt: gtime.Now().String(),
}
return dao.Permission.Create(ctx, permission)
}
// Update 更新权限
func (s *PermissionService) Update(ctx context.Context, req *PermissionUpdateReq) error {
// 检查权限是否存在
permission, err := dao.Permission.GetById(ctx, req.Id)
if err != nil {
return err
}
if permission == nil {
return errors.New("权限不存在")
}
// 检查权限标识是否存在(排除自己)
exists, err := dao.Permission.CheckCodeExists(ctx, req.Slug, req.Id)
if err != nil {
return err
}
if exists {
return errors.New("权限标识已存在")
}
// 如果有父级ID,检查父级是否存在
if req.ParentId > 0 {
parent, err := dao.Permission.GetById(ctx, req.ParentId)
if err != nil {
return err
}
if parent == nil {
return errors.New("父级权限不存在")
}
// 不能将自己设为父级
if req.ParentId == req.Id {
return errors.New("不能将自己设为父级")
}
}
// 更新数据
updateData := g.Map{
"name": req.Name,
"slug": req.Slug,
"type": gconv.Int(req.Type),
"parent_id": req.ParentId,
"path": req.Path,
"component": req.Component,
"icon": req.Icon,
"api_path": req.ApiPath,
"method": req.Method,
"description": req.Description,
"sort": req.Sort,
"status": req.Status,
"updated_at": gtime.Now().String(),
}
return dao.Permission.Update(ctx, req.Id, updateData)
}
// GetById 获取权限详情
func (s *PermissionService) GetById(ctx context.Context, id int) (*entity.Permission, error) {
return dao.Permission.GetById(ctx, id)
}
// GetList 获取权限列表
func (s *PermissionService) GetList(ctx context.Context, req *dao.PermissionListReq) ([]*entity.Permission, int, error) {
return dao.Permission.GetList(ctx, req)
}
// GetTree 获取权限树形结构
func (s *PermissionService) GetTree(ctx context.Context) ([]*entity.Permission, error) {
return dao.Permission.GetTree(ctx)
}
// Delete 删除权限
func (s *PermissionService) Delete(ctx context.Context, id int) error {
// 检查权限是否存在
permission, err := dao.Permission.GetById(ctx, id)
if err != nil {
return err
}
if permission == nil {
return errors.New("权限不存在")
}
// 检查是否有子权限
children, err := dao.Permission.GetByParentId(ctx, id)
if err != nil {
return err
}
if len(children) > 0 {
return errors.New("存在子权限,无法删除")
}
return dao.Permission.Delete(ctx, id)
}
// GetMenuPermissions 获取菜单权限
func (s *PermissionService) GetMenuPermissions(ctx context.Context) ([]*entity.Permission, error) {
return dao.Permission.GetMenuPermissions(ctx)
}
// GetApiPermissions 获取API权限
func (s *PermissionService) GetApiPermissions(ctx context.Context) ([]*entity.Permission, error) {
return dao.Permission.GetApiPermissions(ctx)
}
// GetUserPermissions 获取用户权限
func (s *PermissionService) GetUserPermissions(ctx context.Context, userId int) ([]*entity.Permission, error) {
return dao.Permission.GetUserPermissions(ctx, userId)
}
// CheckUserPermission 检查用户是否有指定权限
func (s *PermissionService) CheckUserPermission(ctx context.Context, userId int, permissionSlug string) (bool, error) {
permissions, err := s.GetUserPermissions(ctx, userId)
if err != nil {
return false, err
}
for _, permission := range permissions {
if permission.Slug == permissionSlug {
return true, nil
}
}
return false, nil
}
// CheckApiPermission 检查API权限
func (s *PermissionService) CheckApiPermission(ctx context.Context, userId int, apiPath, method string) (bool, error) {
permissions, err := s.GetUserPermissions(ctx, userId)
if err != nil {
return false, err
}
for _, permission := range permissions {
if permission.Type == 3 && permission.ApiPath == apiPath && permission.Method == method {
return true, nil
}
}
return false, nil
}

View File

@@ -0,0 +1,328 @@
package auth
import (
"context"
"errors"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/gtime"
"nl-video-api/internal/dao"
"nl-video-api/internal/model/entity"
)
// RoleService 角色服务
type RoleService struct{}
var Role = &RoleService{}
// RoleCreateReq 创建角色请求
type RoleCreateReq struct {
Name string `json:"name" v:"required|length:2,50#角色名称不能为空|角色名称长度为2-50位"`
Slug string `json:"slug" v:"required|length:2,50#角色标识不能为空|角色标识长度为2-50位"`
Level int `json:"level" v:"required|min:1,max:10#角色等级不能为空|角色等级范围1-10"`
Description string `json:"description"` // 角色描述
Sort int `json:"sort"` // 排序
Status int `json:"status" v:"in:0,1#状态只能为0或1"`
IsSystem int `json:"is_system" v:"in:0,1#系统角色标识只能为0或1"`
}
// RoleUpdateReq 更新角色请求
type RoleUpdateReq struct {
Id int `json:"id" v:"required|min:1#角色ID不能为空"`
Name string `json:"name" v:"required|length:2,50#角色名称不能为空|角色名称长度为2-50位"`
Slug string `json:"slug" v:"required|length:2,50#角色标识不能为空|角色标识长度为2-50位"`
Level int `json:"level" v:"required|min:1,max:10#角色等级不能为空|角色等级范围1-10"`
Description string `json:"description"` // 角色描述
Sort int `json:"sort"` // 排序
Status int `json:"status" v:"in:0,1#状态只能为0或1"`
IsSystem int `json:"is_system" v:"in:0,1#系统角色标识只能为0或1"`
}
// RolePermissionReq 角色权限分配请求
type RolePermissionReq struct {
RoleId int `json:"role_id" v:"required|min:1#角色ID不能为空"`
PermissionIds []int `json:"permission_ids"` // 权限ID列表
}
// Create 创建角色
func (s *RoleService) Create(ctx context.Context, req *RoleCreateReq) (int, error) {
// 检查角色标识是否存在
exists, err := dao.Role.CheckCodeExists(ctx, req.Slug, 0)
if err != nil {
return 0, err
}
if exists {
return 0, errors.New("角色标识已存在")
}
// 创建角色数据
role := &entity.Role{
Name: req.Name,
Slug: req.Slug,
Level: req.Level,
Description: req.Description,
Sort: req.Sort,
Status: req.Status,
IsSystem: req.IsSystem,
CreatedAt: gtime.Now().String(),
UpdatedAt: gtime.Now().String(),
}
return dao.Role.Create(ctx, role)
}
// Update 更新角色
func (s *RoleService) Update(ctx context.Context, req *RoleUpdateReq) error {
// 检查角色是否存在
role, err := dao.Role.GetById(ctx, req.Id)
if err != nil {
return err
}
if role == nil {
return errors.New("角色不存在")
}
// 系统角色不允许修改标识和系统标识
if role.IsSystem == 1 {
if req.Slug != role.Slug {
return errors.New("系统角色不允许修改标识")
}
if req.IsSystem != role.IsSystem {
return errors.New("系统角色不允许修改系统标识")
}
}
// 检查角色标识是否存在(排除自己)
exists, err := dao.Role.CheckCodeExists(ctx, req.Slug, req.Id)
if err != nil {
return err
}
if exists {
return errors.New("角色标识已存在")
}
// 更新数据
updateData := g.Map{
"name": req.Name,
"slug": req.Slug,
"level": req.Level,
"description": req.Description,
"sort": req.Sort,
"status": req.Status,
"is_system": req.IsSystem,
"updated_at": gtime.Now().String(),
}
return dao.Role.Update(ctx, req.Id, updateData)
}
// GetById 获取角色详情
func (s *RoleService) GetById(ctx context.Context, id int) (*entity.Role, error) {
return dao.Role.GetById(ctx, id)
}
// GetList 获取角色列表
func (s *RoleService) GetList(ctx context.Context, req *dao.RoleListReq) ([]*entity.Role, int, error) {
return dao.Role.GetList(ctx, req)
}
// GetAll 获取所有角色
func (s *RoleService) GetAll(ctx context.Context) ([]*entity.Role, error) {
return dao.Role.GetAll(ctx)
}
// Delete 删除角色
func (s *RoleService) Delete(ctx context.Context, id int) error {
// 检查角色是否存在
role, err := dao.Role.GetById(ctx, id)
if err != nil {
return err
}
if role == nil {
return errors.New("角色不存在")
}
// 系统角色不允许删除
if role.IsSystem == 1 {
return errors.New("系统角色不允许删除")
}
// 检查是否有管理员使用该角色
// 这里需要查询管理员表,暂时跳过
return dao.Role.Delete(ctx, id)
}
// AssignPermissions 为角色分配权限
func (s *RoleService) AssignPermissions(ctx context.Context, req *RolePermissionReq) error {
// 检查角色是否存在
role, err := dao.Role.GetById(ctx, req.RoleId)
if err != nil {
return err
}
if role == nil {
return errors.New("角色不存在")
}
// 验证权限ID是否有效
if len(req.PermissionIds) > 0 {
permissions, err := dao.Permission.GetPermissionsByIds(ctx, req.PermissionIds)
if err != nil {
return err
}
if len(permissions) != len(req.PermissionIds) {
return errors.New("存在无效的权限ID")
}
}
return dao.Role.AssignPermissions(ctx, req.RoleId, req.PermissionIds)
}
// GetRolePermissions 获取角色权限
func (s *RoleService) GetRolePermissions(ctx context.Context, roleId int) ([]*entity.Permission, error) {
// 检查角色是否存在
role, err := dao.Role.GetById(ctx, roleId)
if err != nil {
return nil, err
}
if role == nil {
return nil, errors.New("角色不存在")
}
return dao.Role.GetRolePermissions(ctx, roleId)
}
// GetRolePermissionIds 获取角色权限ID列表
func (s *RoleService) GetRolePermissionIds(ctx context.Context, roleId int) ([]int, error) {
permissions, err := s.GetRolePermissions(ctx, roleId)
if err != nil {
return nil, err
}
var permissionIds []int
for _, permission := range permissions {
permissionIds = append(permissionIds, permission.Id)
}
return permissionIds, nil
}
// BatchUpdateStatus 批量更新角色状态
func (s *RoleService) BatchUpdateStatus(ctx context.Context, ids []int, status int) error {
if len(ids) == 0 {
return errors.New("请选择要操作的角色")
}
// 检查是否包含系统角色
roles, err := dao.Role.GetRolesByIds(ctx, ids)
if err != nil {
return err
}
for _, role := range roles {
if role.IsSystem == 1 {
return errors.New("不能修改系统角色状态")
}
}
// 批量更新
successCount := 0
for _, id := range ids {
updateData := g.Map{
"status": status,
"updated_at": gtime.Now().String(),
}
if err := dao.Role.Update(ctx, id, updateData); err != nil {
g.Log().Errorf(ctx, "批量更新角色状态失败: ID=%d, 错误=%v", id, err)
} else {
successCount++
}
}
if successCount == 0 {
return errors.New("批量更新失败")
}
return nil
}
// CopyRole 复制角色
func (s *RoleService) CopyRole(ctx context.Context, sourceId int, newName, newSlug string) (int, error) {
// 检查源角色是否存在
sourceRole, err := dao.Role.GetById(ctx, sourceId)
if err != nil {
return 0, err
}
if sourceRole == nil {
return 0, errors.New("源角色不存在")
}
// 检查新角色标识是否存在
exists, err := dao.Role.CheckCodeExists(ctx, newSlug, 0)
if err != nil {
return 0, err
}
if exists {
return 0, errors.New("角色标识已存在")
}
// 创建新角色
newRole := &entity.Role{
Name: newName,
Slug: newSlug,
Level: sourceRole.Level,
Description: sourceRole.Description + " (复制)",
Sort: sourceRole.Sort,
Status: 1, // 默认启用
IsSystem: 0, // 复制的角色不是系统角色
CreatedAt: gtime.Now().String(),
UpdatedAt: gtime.Now().String(),
}
newRoleId, err := dao.Role.Create(ctx, newRole)
if err != nil {
return 0, err
}
// 复制权限
sourcePermissions, err := dao.Role.GetRolePermissions(ctx, sourceId)
if err != nil {
return newRoleId, err // 角色创建成功,但权限复制失败
}
if len(sourcePermissions) > 0 {
var permissionIds []int
for _, permission := range sourcePermissions {
permissionIds = append(permissionIds, permission.Id)
}
err = dao.Role.AssignPermissions(ctx, newRoleId, permissionIds)
if err != nil {
g.Log().Errorf(ctx, "复制角色权限失败: 新角色ID=%d, 错误=%v", newRoleId, err)
}
}
return newRoleId, nil
}
// GetRolesByLevel 根据等级获取角色
func (s *RoleService) GetRolesByLevel(ctx context.Context, level int) ([]*entity.Role, error) {
req := &dao.RoleListReq{
Level: level,
Status: 1, // 只获取启用的角色
Page: 0, // 不分页
PageSize: 0,
}
roles, _, err := dao.Role.GetList(ctx, req)
return roles, err
}
// CheckRoleExists 检查角色是否存在
func (s *RoleService) CheckRoleExists(ctx context.Context, id int) (bool, error) {
role, err := dao.Role.GetById(ctx, id)
if err != nil {
return false, err
}
return role != nil, nil
}

411
internal/service/banner.go Normal file
View File

@@ -0,0 +1,411 @@
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"
"nl-video-api/internal/dao"
"nl-video-api/internal/model/entity"
"nl-video-api/utility/response"
)
// BannerService Banner服务
type BannerService struct{}
// NewBannerService 创建Banner服务实例
func NewBannerService() *BannerService {
return &BannerService{}
}
// 定义请求和响应结构体
type AdminBannerListReq struct {
Page int `json:"page"`
Size int `json:"size"`
Sort int `json:"sort"`
Status int `json:"status"`
Keyword string `json:"keyword"`
Category string `json:"category"`
}
type AdminBannerListRes struct {
List []AdminBannerItem `json:"list"`
Total int `json:"total"`
Page int `json:"page"`
Size int `json:"size"`
}
type AdminBannerItem struct {
Id uint `json:"id"`
Title string `json:"title"`
ImageUrl string `json:"image_url"`
LinkUrl string `json:"link_url"`
Sort int `json:"sort"`
Status int `json:"status"`
Description string `json:"description"`
CreatedAt int64 `json:"created_at"`
UpdatedAt int64 `json:"updated_at"`
}
type AdminBannerDetailReq struct {
Id uint `json:"id"`
}
type AdminBannerDetailRes struct {
Banner AdminBannerDetail `json:"banner"`
}
type AdminBannerDetail struct {
Id uint `json:"id"`
Title string `json:"title"`
ImageUrl string `json:"image_url"`
LinkUrl string `json:"link_url"`
Sort int `json:"sort"`
Status int `json:"status"`
Description string `json:"description"`
CreatedAt int64 `json:"created_at"`
UpdatedAt int64 `json:"updated_at"`
}
type AdminBannerCreateReq struct {
Title string `json:"title"`
ImageUrl string `json:"image_url"`
LinkUrl string `json:"link_url"`
Sort int `json:"sort"`
Status int `json:"status"`
Description string `json:"description"`
}
type AdminBannerUpdateReq struct {
Id uint `json:"id"`
Title string `json:"title"`
ImageUrl string `json:"image_url"`
LinkUrl string `json:"link_url"`
Sort int `json:"sort"`
Status int `json:"status"`
Description string `json:"description"`
}
type AdminBannerDeleteReq struct {
Id uint `json:"id"`
}
type AdminBannerUpdateStatusReq struct {
Id uint `json:"id"`
Status int `json:"status"`
}
type AdminBannerBatchDeleteReq struct {
Ids []uint `json:"ids"`
}
// UserGetList 用户获取轮播图列表
func (s *BannerService) UserGetList(r *ghttp.Request) {
// 获取请求参数
page := r.Get("page", 1).Int()
size := r.Get("size", 10).Int()
sort := r.Get("sort", 0).Int()
// 构建查询条件
query := dao.Banner.Ctx(r.Context()).Where("status", 1) // 只显示启用的轮播图
// 排序筛选
if sort > 0 {
query = query.Where("sort", sort)
}
// 获取总数
total, err := query.Count()
if err != nil {
response.Error(r, response.CodeInternalError, "获取轮播图总数失败")
return
}
// 获取列表数据
var banners []entity.Banner
err = query.Order("sort ASC, id DESC").
Limit((page-1)*size, size).
Scan(&banners)
if err != nil {
response.Error(r, response.CodeInternalError, "获取轮播图列表失败")
return
}
// 转换为响应格式
list := make([]g.Map, 0, len(banners))
for _, banner := range banners {
list = append(list, g.Map{
"id": banner.Id,
"title": banner.Title,
"image_url": banner.ImageUrl,
"link_url": banner.LinkUrl,
"sort": banner.Sort,
"status": banner.Status,
"created_at": banner.CreatedAt.Unix(),
"updated_at": banner.UpdatedAt.Unix(),
})
}
response.Success(r, g.Map{
"list": list,
"total": total,
"page": page,
"size": size,
})
}
// UserGetDetail 用户获取轮播图详情
func (s *BannerService) UserGetDetail(r *ghttp.Request) {
id := r.Get("id").Uint()
if id == 0 {
response.Error(r, response.CodeInvalidParam, "轮播图ID不能为空")
return
}
var banner entity.Banner
err := dao.Banner.Ctx(r.Context()).Where("id", id).Where("status", 1).Scan(&banner)
if err != nil {
response.Error(r, response.CodeInternalError, "获取轮播图详情失败")
return
}
if banner.Id == 0 {
response.Error(r, response.CodeNotFound, "轮播图不存在")
return
}
response.Success(r, g.Map{
"id": banner.Id,
"title": banner.Title,
"image_url": banner.ImageUrl,
"link_url": banner.LinkUrl,
"sort": banner.Sort,
"status": banner.Status,
"created_at": banner.CreatedAt.Unix(),
"updated_at": banner.UpdatedAt.Unix(),
})
}
// AdminCreate 管理员创建轮播图
func (s *BannerService) AdminCreate(r *ghttp.Request) {
// 获取请求参数
title := r.Get("title").String()
imageUrl := r.Get("image_url").String()
linkUrl := r.Get("link_url").String()
sort := r.Get("sort", 0).Int()
status := r.Get("status", 1).Int()
// 参数验证
if title == "" {
response.Error(r, response.CodeInvalidParam, "标题不能为空")
return
}
if imageUrl == "" {
response.Error(r, response.CodeInvalidParam, "图片地址不能为空")
return
}
// 创建轮播图
data := &entity.Banner{
Title: title,
ImageUrl: imageUrl,
LinkUrl: linkUrl,
Sort: sort,
Status: status,
CreatedAt: gtime.Now(),
UpdatedAt: gtime.Now(),
}
id, err := dao.Banner.Ctx(r.Context()).Data(data).InsertAndGetId()
if err != nil {
response.Error(r, response.CodeInternalError, "创建轮播图失败")
return
}
response.Success(r, g.Map{
"id": uint(id),
})
}
// AdminUpdate 管理员更新轮播图
func (s *BannerService) AdminUpdate(ctx context.Context, req *AdminBannerUpdateReq) error {
// 检查轮播图是否存在
count, err := dao.Banner.Ctx(ctx).Where("id", req.Id).Count()
if err != nil {
return gerror.New("检查轮播图失败")
}
if count == 0 {
return gerror.New("轮播图不存在")
}
// 更新轮播图
data := g.Map{
"title": req.Title,
"image_url": req.ImageUrl,
"link_url": req.LinkUrl,
"sort": req.Sort,
"status": req.Status,
"description": req.Description,
"updated_at": gtime.Now(),
}
_, err = dao.Banner.Ctx(ctx).Where("id", req.Id).Data(data).Update()
if err != nil {
return gerror.New("更新轮播图失败")
}
return nil
}
// AdminDelete 管理员删除轮播图
func (s *BannerService) AdminDelete(ctx context.Context, req *AdminBannerDeleteReq) error {
// 检查轮播图是否存在
count, err := dao.Banner.Ctx(ctx).Where("id", req.Id).Count()
if err != nil {
return gerror.New("检查轮播图失败")
}
if count == 0 {
return gerror.New("轮播图不存在")
}
// 删除轮播图
_, err = dao.Banner.Ctx(ctx).Where("id", req.Id).Delete()
if err != nil {
return gerror.New("删除轮播图失败")
}
return nil
}
// AdminGetDetail 管理员获取轮播图详情
func (s *BannerService) AdminGetDetail(ctx context.Context, req *AdminBannerDetailReq) (*AdminBannerDetailRes, error) {
var banner entity.Banner
err := dao.Banner.Ctx(ctx).Where("id", req.Id).Scan(&banner)
if err != nil {
return nil, gerror.New("获取轮播图详情失败")
}
if banner.Id == 0 {
return nil, gerror.New("轮播图不存在")
}
return &AdminBannerDetailRes{
Banner: AdminBannerDetail{
Id: banner.Id,
Title: banner.Title,
ImageUrl: banner.ImageUrl,
LinkUrl: banner.LinkUrl,
Sort: banner.Sort,
Status: banner.Status,
CreatedAt: banner.CreatedAt.Unix(),
UpdatedAt: banner.UpdatedAt.Unix(),
},
}, nil
}
// AdminGetList 管理员获取轮播图列表
func (s *BannerService) AdminGetList(ctx context.Context, req *AdminBannerListReq) (*AdminBannerListRes, error) {
// 设置默认值
if req.Page <= 0 {
req.Page = 1
}
if req.Size <= 0 {
req.Size = 10
}
// 构建查询条件
query := dao.Banner.Ctx(ctx)
// 状态筛选
if req.Status >= 0 {
query = query.Where("status", req.Status)
}
// 排序筛选
if req.Sort > 0 {
query = query.Where("sort", req.Sort)
}
// 关键词搜索
if req.Keyword != "" {
keyword := "%" + req.Keyword + "%"
query = query.Where("title LIKE ?", keyword)
}
// 获取总数
total, err := query.Count()
if err != nil {
return nil, gerror.New("获取轮播图总数失败")
}
// 获取列表数据
var banners []entity.Banner
err = query.Order("sort ASC, id DESC").
Limit((req.Page-1)*req.Size, req.Size).
Scan(&banners)
if err != nil {
return nil, gerror.New("获取轮播图列表失败")
}
// 转换为响应格式
list := make([]AdminBannerItem, 0, len(banners))
for _, banner := range banners {
list = append(list, AdminBannerItem{
Id: banner.Id,
Title: banner.Title,
ImageUrl: banner.ImageUrl,
LinkUrl: banner.LinkUrl,
Sort: banner.Sort,
Status: banner.Status,
Description: "", // 实体中没有此字段,设为空
CreatedAt: banner.CreatedAt.Unix(),
UpdatedAt: banner.UpdatedAt.Unix(),
})
}
return &AdminBannerListRes{
List: list,
Total: total,
Page: req.Page,
Size: req.Size,
}, nil
}
// AdminUpdateStatus 管理员更新轮播图状态
func (s *BannerService) AdminUpdateStatus(ctx context.Context, req *AdminBannerUpdateStatusReq) error {
// 检查轮播图是否存在
count, err := dao.Banner.Ctx(ctx).Where("id", req.Id).Count()
if err != nil {
return gerror.New("检查轮播图失败")
}
if count == 0 {
return gerror.New("轮播图不存在")
}
// 更新状态
_, err = dao.Banner.Ctx(ctx).Where("id", req.Id).Data(g.Map{
"status": req.Status,
"updated_at": gtime.Now(),
}).Update()
if err != nil {
return gerror.New("更新轮播图状态失败")
}
return nil
}
// AdminBatchDelete 管理员批量删除轮播图
func (s *BannerService) AdminBatchDelete(ctx context.Context, req *AdminBannerBatchDeleteReq) error {
if len(req.Ids) == 0 {
return gerror.New("请选择要删除的轮播图")
}
// 批量删除
_, err := dao.Banner.Ctx(ctx).WhereIn("id", req.Ids).Delete()
if err != nil {
return gerror.New("批量删除轮播图失败")
}
return nil
}

428
internal/service/comment.go Normal file
View File

@@ -0,0 +1,428 @@
package service
import (
"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/utility/response"
)
// CommentService 评论服务
type CommentService struct{}
// NewCommentService 创建评论服务实例
func NewCommentService() *CommentService {
return &CommentService{}
}
// Add 添加评论
func (s *CommentService) Add(r *ghttp.Request) {
// 获取用户ID(这里应该从JWT token中获取)
userId := r.Get("user_id").Uint()
if userId == 0 {
response.Error(r, response.CodeUnauthorized, "用户未登录")
return
}
// 获取请求参数
movieId := r.Get("movie_id").Uint()
if movieId == 0 {
response.Error(r, response.CodeInvalidParam, "电影ID不能为空")
return
}
content := r.Get("content").String()
if content == "" {
response.Error(r, response.CodeInvalidParam, "评论内容不能为空")
return
}
parentId := r.Get("parent_id").Uint()
// 检查电影是否存在
movieCount, err := g.DB().Model("movie").Where("id", movieId).Count()
if err != nil {
response.Error(r, response.CodeInternalError, "系统错误")
return
}
if movieCount == 0 {
response.Error(r, response.CodeNotFound, "电影不存在")
return
}
// 如果是回复评论,检查父评论是否存在
if parentId > 0 {
parentCount, err := dao.Comment.Ctx(r.Context()).Where("id", parentId).Where("movie_id", movieId).Count()
if err != nil {
response.Error(r, response.CodeInternalError, "系统错误")
return
}
if parentCount == 0 {
response.Error(r, response.CodeNotFound, "父评论不存在")
return
}
}
// 创建评论
commentId, err := dao.Comment.Ctx(r.Context()).Data(g.Map{
"user_id": userId,
"movie_id": movieId,
"parent_id": parentId,
"content": content,
"like_count": 0,
"status": 1, // 默认通过审核
"created_at": gtime.Now(),
"updated_at": gtime.Now(),
}).InsertAndGetId()
if err != nil {
response.Error(r, response.CodeInternalError, "添加评论失败")
return
}
response.Success(r, g.Map{
"id": commentId,
})
}
// GetList 获取评论列表
func (s *CommentService) GetList(r *ghttp.Request) {
movieId := r.Get("movie_id").Uint()
if movieId == 0 {
response.Error(r, response.CodeInvalidParam, "电影ID不能为空")
return
}
page := r.Get("page", 1).Int()
size := r.Get("size", 10).Int()
parentId := r.Get("parent_id", 0).Uint()
// 构建查询条件
query := dao.Comment.Ctx(r.Context()).Where("movie_id", movieId).Where("status", 1)
if parentId > 0 {
query = query.Where("parent_id", parentId)
} else {
query = query.Where("parent_id", 0)
}
// 获取总数
total, err := query.Count()
if err != nil {
response.Error(r, response.CodeInternalError, "获取评论总数失败")
return
}
// 获取评论列表
var comments []g.Map
err = query.Order("created_at DESC").
Limit((page-1)*size, size).
Scan(&comments)
if err != nil {
response.Error(r, response.CodeInternalError, "获取评论列表失败")
return
}
// 获取用户信息
userIds := make([]interface{}, 0)
for _, comment := range comments {
userIds = append(userIds, comment["user_id"])
}
userMap := make(map[uint]g.Map)
if len(userIds) > 0 {
var users []g.Map
g.DB().Model("nl_user").WhereIn("id", userIds).Fields("id, username, avatar").Scan(&users)
for _, user := range users {
userMap[gconv.Uint(user["id"])] = user
}
}
// 组装返回数据
list := make([]g.Map, 0)
for _, comment := range comments {
userId := gconv.Uint(comment["user_id"])
user := userMap[userId]
item := g.Map{
"id": comment["id"],
"user_id": comment["user_id"],
"username": user["username"],
"avatar": user["avatar"],
"movie_id": comment["movie_id"],
"parent_id": comment["parent_id"],
"content": comment["content"],
"like_count": comment["like_count"],
"created_at": gconv.Int64(comment["created_at"]),
"replies": make([]g.Map, 0), // 子评论,如果需要可以递归获取
}
list = append(list, item)
}
response.Success(r, g.Map{
"list": list,
"total": total,
"page": page,
"size": size,
})
}
// Delete 删除评论
func (s *CommentService) Delete(r *ghttp.Request) {
// 获取用户ID
userId := r.Get("user_id").Uint()
if userId == 0 {
response.Error(r, response.CodeUnauthorized, "用户未登录")
return
}
commentId := r.Get("id").Uint()
if commentId == 0 {
response.Error(r, response.CodeInvalidParam, "评论ID不能为空")
return
}
// 检查评论是否存在且属于当前用户
var comment g.Map
err := dao.Comment.Ctx(r.Context()).Where("id", commentId).Where("user_id", userId).Scan(&comment)
if err != nil {
response.Error(r, response.CodeInternalError, "系统错误")
return
}
if len(comment) == 0 {
response.Error(r, response.CodeNotFound, "评论不存在或无权限删除")
return
}
// 删除评论(软删除,更新状态)
_, err = dao.Comment.Ctx(r.Context()).Where("id", commentId).Data(g.Map{
"status": 0, // 0表示已删除
"updated_at": gtime.Now(),
}).Update()
if err != nil {
response.Error(r, response.CodeInternalError, "删除评论失败")
return
}
// 同时删除该评论的所有回复
_, err = dao.Comment.Ctx(r.Context()).Where("parent_id", commentId).Data(g.Map{
"status": 0,
"updated_at": gtime.Now(),
}).Update()
if err != nil {
// 记录日志,但不影响主要操作
g.Log().Error(r.Context(), "删除子评论失败:", err)
}
response.Success(r, "删除成功")
}
// Like 点赞评论
func (s *CommentService) Like(r *ghttp.Request) {
// 获取用户ID
userId := r.Get("user_id").Uint()
if userId == 0 {
response.Error(r, response.CodeUnauthorized, "用户未登录")
return
}
commentId := r.Get("id").Uint()
if commentId == 0 {
response.Error(r, response.CodeInvalidParam, "评论ID不能为空")
return
}
// 检查评论是否存在
commentCount, err := dao.Comment.Ctx(r.Context()).Where("id", commentId).Where("status", 1).Count()
if err != nil {
response.Error(r, response.CodeInternalError, "系统错误")
return
}
if commentCount == 0 {
response.Error(r, response.CodeNotFound, "评论不存在")
return
}
// 检查是否已经点赞
likeCount, err := g.DB().Model("comment_like").Where("user_id", userId).Where("comment_id", commentId).Count()
if err != nil {
response.Error(r, response.CodeInternalError, "系统错误")
return
}
if likeCount > 0 {
// 取消点赞
_, err = g.DB().Model("comment_like").Where("user_id", userId).Where("comment_id", commentId).Delete()
if err != nil {
response.Error(r, response.CodeInternalError, "取消点赞失败")
return
}
// 减少点赞数
_, err = dao.Comment.Ctx(r.Context()).Where("id", commentId).Data("like_count=like_count-1").Update()
if err != nil {
response.Error(r, response.CodeInternalError, "更新点赞数失败")
return
}
response.Success(r, g.Map{
"action": "unlike",
"message": "取消点赞成功",
})
} else {
// 添加点赞
_, err = g.DB().Model("comment_like").Data(g.Map{
"user_id": userId,
"comment_id": commentId,
"created_at": gtime.Now(),
}).Insert()
if err != nil {
response.Error(r, response.CodeInternalError, "点赞失败")
return
}
// 增加点赞数
_, err = dao.Comment.Ctx(r.Context()).Where("id", commentId).Data("like_count=like_count+1").Update()
if err != nil {
response.Error(r, response.CodeInternalError, "更新点赞数失败")
return
}
response.Success(r, g.Map{
"action": "like",
"message": "点赞成功",
})
}
}
// Report 举报评论
func (s *CommentService) Report(r *ghttp.Request) {
// 获取请求参数
id := r.Get("id").Uint()
reason := r.Get("reason").String()
// 参数验证
if id == 0 {
response.Error(r, response.CodeInvalidParam, "评论ID不能为空")
return
}
if reason == "" {
response.Error(r, response.CodeInvalidParam, "举报原因不能为空")
return
}
// 检查评论是否存在
count, err := dao.Comment.Ctx(r.Context()).Where("id", id).Count()
if err != nil {
response.Error(r, response.CodeInternalError, "检查评论失败")
return
}
if count == 0 {
response.Error(r, response.CodeNotFound, "评论不存在")
return
}
// 这里应该实现举报逻辑,创建举报记录
response.Success(r, "举报成功")
}
// Unlike 取消点赞评论
func (s *CommentService) Unlike(r *ghttp.Request) {
// 获取请求参数
id := r.Get("id").Uint()
// 参数验证
if id == 0 {
response.Error(r, response.CodeInvalidParam, "评论ID不能为空")
return
}
// 检查评论是否存在
count, err := dao.Comment.Ctx(r.Context()).Where("id", id).Count()
if err != nil {
response.Error(r, response.CodeInternalError, "检查评论失败")
return
}
if count == 0 {
response.Error(r, response.CodeNotFound, "评论不存在")
return
}
// 这里应该实现取消点赞逻辑
response.Success(r, "取消点赞成功")
}
// AdminList 管理员获取评论列表
func (s *CommentService) AdminList(r *ghttp.Request) {
s.AdminGetList(r)
}
// AdminUpdateStatus 管理员更新评论状态
func (s *CommentService) AdminUpdateStatus(r *ghttp.Request) {
// 获取请求参数
id := r.Get("id").Uint()
status := r.Get("status").Int()
// 参数验证
if id == 0 {
response.Error(r, response.CodeInvalidParam, "评论ID不能为空")
return
}
// 检查评论是否存在
count, err := dao.Comment.Ctx(r.Context()).Where("id", id).Count()
if err != nil {
response.Error(r, response.CodeInternalError, "检查评论失败")
return
}
if count == 0 {
response.Error(r, response.CodeNotFound, "评论不存在")
return
}
// 更新评论状态
_, err = dao.Comment.Ctx(r.Context()).Where("id", id).Data(g.Map{
"status": status,
"updated_at": gtime.Now(),
}).Update()
if err != nil {
response.Error(r, response.CodeInternalError, "更新评论状态失败")
return
}
response.Success(r, "更新成功")
}
// AdminGetList 管理员获取评论列表
func (s *CommentService) AdminGetList(r *ghttp.Request) {
s.GetList(r)
}
// AdminBatchDelete 管理员批量删除评论
func (s *CommentService) AdminBatchDelete(r *ghttp.Request) {
// 获取请求参数
var ids []uint
r.Parse(&ids)
if len(ids) == 0 {
response.Error(r, response.CodeInvalidParam, "请选择要删除的评论")
return
}
// 批量删除评论(软删除)
_, err := dao.Comment.Ctx(r.Context()).WhereIn("id", ids).Data(g.Map{
"status": 0,
"updated_at": gtime.Now(),
}).Update()
if err != nil {
response.Error(r, response.CodeInternalError, "批量删除评论失败")
return
}
response.Success(r, "批量删除成功")
}

391
internal/service/config.go Normal file
View File

@@ -0,0 +1,391 @@
package service
import (
"fmt"
"strconv"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/net/ghttp"
"github.com/gogf/gf/v2/os/gtime"
"nl-video-api/internal/dao"
"nl-video-api/internal/model/entity"
"nl-video-api/utility/response"
)
// ConfigService 系统配置服务
type ConfigService struct{}
var Config = &ConfigService{}
// NewConfigService 创建配置服务实例
func NewConfigService() *ConfigService {
return &ConfigService{}
}
// AdminList 管理员获取配置列表
func (s *ConfigService) AdminList(r *ghttp.Request) {
response.Success(r, g.Map{
"list": []interface{}{},
"total": 0,
})
}
// AdminDetail 管理员获取配置详情
func (s *ConfigService) AdminDetail(r *ghttp.Request) {
response.Success(r, g.Map{
"id": 1,
"key": "site_name",
"value": "NL视频网站",
"desc": "网站名称",
})
}
// AdminCreate 管理员创建配置
func (s *ConfigService) AdminCreate(r *ghttp.Request) {
response.Success(r, "创建成功")
}
// AdminUpdate 管理员更新配置
func (s *ConfigService) AdminUpdate(r *ghttp.Request) {
response.Success(r, "更新成功")
}
// AdminDelete 管理员删除配置
func (s *ConfigService) AdminDelete(r *ghttp.Request) {
response.Success(r, "删除成功")
}
// AdminBatchDelete 管理员批量删除配置
func (s *ConfigService) AdminBatchDelete(r *ghttp.Request) {
response.Success(r, "批量删除成功")
}
// AdminGetByKey 管理员根据键获取配置
func (s *ConfigService) AdminGetByKey(r *ghttp.Request) {
response.Success(r, g.Map{
"key": "site_name",
"value": "NL视频网站",
})
}
// AdminGetByGroup 管理员根据分组获取配置
func (s *ConfigService) AdminGetByGroup(r *ghttp.Request) {
response.Success(r, g.Map{
"list": []interface{}{},
"total": 0,
})
}
// AdminSet 管理员设置配置
func (s *ConfigService) AdminSet(r *ghttp.Request) {
response.Success(r, "设置成功")
}
// AdminBatchSet 管理员批量设置配置
func (s *ConfigService) AdminBatchSet(r *ghttp.Request) {
response.Success(r, "批量设置成功")
}
// AdminGetGroupList 管理员获取配置分组列表
func (s *ConfigService) AdminGetGroupList(r *ghttp.Request) {
response.Success(r, g.Map{
"list": []string{"基础设置", "系统设置", "邮件设置"},
})
}
// AdminExport 管理员导出配置
func (s *ConfigService) AdminExport(r *ghttp.Request) {
response.Success(r, "导出成功")
}
// AdminImport 管理员导入配置
func (s *ConfigService) AdminImport(r *ghttp.Request) {
response.Success(r, "导入成功")
}
// AdminCache 管理员获取缓存配置
func (s *ConfigService) AdminCache(r *ghttp.Request) {
response.Success(r, g.Map{
"cache_enabled": true,
"cache_time": 3600,
})
}
// AdminClearCache 管理员清除配置缓存
func (s *ConfigService) AdminClearCache(r *ghttp.Request) {
response.Success(r, "缓存清除成功")
}
// AdminValidate 管理员验证配置
func (s *ConfigService) AdminValidate(r *ghttp.Request) {
response.Success(r, "配置验证通过")
}
// AdminBackup 管理员备份配置
func (s *ConfigService) AdminBackup(r *ghttp.Request) {
response.Success(r, "配置备份成功")
}
// AdminRestore 管理员恢复配置
func (s *ConfigService) AdminRestore(r *ghttp.Request) {
response.Success(r, "配置恢复成功")
}
// AdminGetHistory 管理员获取配置历史
func (s *ConfigService) AdminGetHistory(r *ghttp.Request) {
response.Success(r, g.Map{
"list": []interface{}{},
"total": 0,
})
}
// GetList 获取配置列表
func (s *ConfigService) GetList(r *ghttp.Request) {
// 获取请求参数
keyword := r.Get("keyword").String()
pageStr := r.Get("page", "1").String()
pageSizeStr := r.Get("page_size", "10").String()
page, err := strconv.Atoi(pageStr)
if err != nil || page < 1 {
page = 1
}
pageSize, err := strconv.Atoi(pageSizeStr)
if err != nil || pageSize < 1 {
pageSize = 10
}
// 构建查询条件
query := dao.Config.Ctx(r.Context())
if keyword != "" {
query = query.Where("`key` LIKE ? OR name LIKE ?",
fmt.Sprintf("%%%s%%", keyword),
fmt.Sprintf("%%%s%%", keyword))
}
// 获取总数
total, err := query.Count()
if err != nil {
response.Error(r, response.CodeInternalError, "获取配置总数失败")
return
}
// 获取列表
var list []*entity.Config
err = query.Page(page, pageSize).OrderAsc("`key`").Scan(&list)
if err != nil {
response.Error(r, response.CodeInternalError, "获取配置列表失败")
return
}
response.Success(r, g.Map{
"list": list,
"total": total,
"page": page,
"page_size": pageSize,
})
}
// GetByKey 根据键获取配置
func (s *ConfigService) GetByKey(r *ghttp.Request) {
// 获取请求参数
configKey := r.Get("key").String()
if configKey == "" {
response.Error(r, response.CodeInvalidParam, "配置键不能为空")
return
}
// 查询配置
var config entity.Config
err := dao.Config.Ctx(r.Context()).Where("`key`", configKey).Scan(&config)
if err != nil {
response.Error(r, response.CodeInternalError, "获取配置失败")
return
}
if config.Id == 0 {
response.Error(r, response.CodeNotFound, "配置不存在")
return
}
response.Success(r, config)
}
// Add 添加配置
func (s *ConfigService) Add(r *ghttp.Request) {
// 获取请求参数
configKey := r.Get("config_key").String()
configName := r.Get("config_name").String()
configValue := r.Get("config_value").String()
configType := r.Get("config_type").String()
description := r.Get("description").String()
// 参数验证
if configKey == "" || configName == "" {
response.Error(r, response.CodeInvalidParam, "配置键和配置名称不能为空")
return
}
// 检查配置键是否已存在
count, err := dao.Config.Ctx(r.Context()).Where("config_key", configKey).Count()
if err != nil {
response.Error(r, response.CodeInternalError, "检查配置键失败")
return
}
if count > 0 {
response.Error(r, response.CodeInvalidParam, "配置键已存在")
return
}
// 创建配置
_, err = dao.Config.Ctx(r.Context()).Data(g.Map{
"config_key": configKey,
"config_name": configName,
"config_value": configValue,
"config_type": configType,
"description": description,
"created_at": gtime.Now(),
"updated_at": gtime.Now(),
}).Insert()
if err != nil {
response.Error(r, response.CodeInternalError, "添加配置失败")
return
}
response.Success(r, "添加成功")
}
// Update 更新配置
func (s *ConfigService) Update(r *ghttp.Request) {
// 获取请求参数
idStr := r.Get("id").String()
configName := r.Get("config_name").String()
configValue := r.Get("config_value").String()
configType := r.Get("config_type").String()
description := r.Get("description").String()
if idStr == "" {
response.Error(r, response.CodeInvalidParam, "配置ID不能为空")
return
}
id, err := strconv.Atoi(idStr)
if err != nil {
response.Error(r, response.CodeInvalidParam, "配置ID格式错误")
return
}
// 检查配置是否存在
count, err := dao.Config.Ctx(r.Context()).Where("id", id).Count()
if err != nil {
response.Error(r, response.CodeInternalError, "检查配置失败")
return
}
if count == 0 {
response.Error(r, response.CodeNotFound, "配置不存在")
return
}
// 更新配置
updateData := g.Map{
"updated_at": gtime.Now(),
}
if configName != "" {
updateData["config_name"] = configName
}
if configValue != "" {
updateData["config_value"] = configValue
}
if configType != "" {
updateData["config_type"] = configType
}
if description != "" {
updateData["description"] = description
}
_, err = dao.Config.Ctx(r.Context()).Where("id", id).Data(updateData).Update()
if err != nil {
response.Error(r, response.CodeInternalError, "更新配置失败")
return
}
response.Success(r, "更新成功")
}
// Delete 删除配置
func (s *ConfigService) Delete(r *ghttp.Request) {
// 获取请求参数
idStr := r.Get("id").String()
if idStr == "" {
response.Error(r, response.CodeInvalidParam, "配置ID不能为空")
return
}
id, err := strconv.Atoi(idStr)
if err != nil {
response.Error(r, response.CodeInvalidParam, "配置ID格式错误")
return
}
// 检查配置是否存在
count, err := dao.Config.Ctx(r.Context()).Where("id", id).Count()
if err != nil {
response.Error(r, response.CodeInternalError, "检查配置失败")
return
}
if count == 0 {
response.Error(r, response.CodeNotFound, "配置不存在")
return
}
// 删除配置
_, err = dao.Config.Ctx(r.Context()).Where("id", id).Delete()
if err != nil {
response.Error(r, response.CodeInternalError, "删除配置失败")
return
}
response.Success(r, "删除成功")
}
// BatchDelete 批量删除配置
func (s *ConfigService) BatchDelete(r *ghttp.Request) {
// 获取请求参数
var ids []int
err := r.Parse(&ids)
if err != nil {
response.Error(r, response.CodeInvalidParam, "参数格式错误")
return
}
if len(ids) == 0 {
response.Error(r, response.CodeInvalidParam, "请选择要删除的配置")
return
}
// 批量删除
_, err = dao.Config.Ctx(r.Context()).Where("id IN (?)", ids).Delete()
if err != nil {
response.Error(r, response.CodeInternalError, "批量删除失败")
return
}
response.Success(r, "删除成功")
}
// GetPublicConfigs 获取公开配置(用户端)
func (s *ConfigService) GetPublicConfigs(r *ghttp.Request) {
// 返回默认的公开配置
configMap := map[string]interface{}{
"site_name": "NL在线影院",
"site_logo": "",
"site_description": "NL在线影院 - 海量高清影视资源在线观看",
"site_keywords": "NL影院,在线观看,高清影视",
"upload_max_size": "10485760",
"upload_allowed_types": "jpg,jpeg,png,gif,mp4,avi,mkv",
}
response.Success(r, configMap)
}

591
internal/service/log.go Normal file
View File

@@ -0,0 +1,591 @@
package service
import (
"fmt"
"strconv"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/net/ghttp"
"github.com/gogf/gf/v2/os/gtime"
"nl-video-api/internal/dao"
"nl-video-api/internal/model/entity"
"nl-video-api/utility/response"
)
// LogService 日志服务
type LogService struct{}
var Log = &LogService{}
// AddAdminLog 添加管理员日志
func (s *LogService) AddAdminLog(r *ghttp.Request) {
// 获取请求参数
action := r.Get("action").String()
module := r.Get("module").String()
content := r.Get("content").String()
ip := r.Get("ip").String()
// 参数验证
if action == "" || module == "" {
response.Error(r, response.CodeInvalidParam, "操作和模块不能为空")
return
}
// 从上下文获取管理员ID
adminIdValue := r.Context().Value("admin_id")
if adminIdValue == nil {
response.Error(r, response.CodeUnauthorized, "请先登录")
return
}
adminId := adminIdValue.(uint)
// 创建管理员日志
_, err := dao.AdminLog.Ctx(r.Context()).Data(g.Map{
"admin_id": adminId,
"action": action,
"module": module,
"content": content,
"ip": ip,
"created_at": gtime.Now(),
}).Insert()
if err != nil {
response.Error(r, response.CodeInternalError, "添加日志失败")
return
}
response.Success(r, "添加成功")
}
// GetAdminLogList 获取管理员日志列表
func (s *LogService) GetAdminLogList(r *ghttp.Request) {
// 获取请求参数
adminIdStr := r.Get("admin_id").String()
action := r.Get("action").String()
module := r.Get("module").String()
keyword := r.Get("keyword").String()
pageStr := r.Get("page", "1").String()
pageSizeStr := r.Get("page_size", "10").String()
page, err := strconv.Atoi(pageStr)
if err != nil || page < 1 {
page = 1
}
pageSize, err := strconv.Atoi(pageSizeStr)
if err != nil || pageSize < 1 {
pageSize = 10
}
// 构建查询条件
query := dao.AdminLog.Ctx(r.Context())
if adminIdStr != "" {
adminId, err := strconv.Atoi(adminIdStr)
if err == nil {
query = query.Where("admin_id", adminId)
}
}
if action != "" {
query = query.Where("action", action)
}
if module != "" {
query = query.Where("module", module)
}
if keyword != "" {
query = query.WhereLike("content", fmt.Sprintf("%%%s%%", keyword))
}
// 获取总数
total, err := query.Count()
if err != nil {
response.Error(r, response.CodeInternalError, "获取日志总数失败")
return
}
// 获取列表
var list []*entity.AdminLog
err = query.Page(page, pageSize).OrderDesc("created_at").Scan(&list)
if err != nil {
response.Error(r, response.CodeInternalError, "获取日志列表失败")
return
}
// 构建返回数据
var logItems []g.Map
for _, log := range list {
// 获取管理员信息(使用NlUser表)
var admin entity.NlUser
g.DB().Model("nl_user").Where("id", log.AdminId).Where("user_type", "admin").Scan(&admin)
logItems = append(logItems, g.Map{
"id": log.Id,
"admin_id": log.AdminId,
"admin_name": admin.Username,
"action": log.Action,
"module": log.Module,
"content": log.Content,
"ip": log.Ip,
"created_at": log.CreatedAt,
})
}
response.Success(r, g.Map{
"list": logItems,
"total": total,
"page": page,
"page_size": pageSize,
})
}
// DeleteAdminLog 删除管理员日志
func (s *LogService) DeleteAdminLog(r *ghttp.Request) {
// 获取请求参数
idStr := r.Get("id").String()
if idStr == "" {
response.Error(r, response.CodeInvalidParam, "日志ID不能为空")
return
}
id, err := strconv.Atoi(idStr)
if err != nil {
response.Error(r, response.CodeInvalidParam, "日志ID格式错误")
return
}
// 删除日志
_, err = dao.AdminLog.Ctx(r.Context()).Where("id", id).Delete()
if err != nil {
response.Error(r, response.CodeInternalError, "删除日志失败")
return
}
response.Success(r, "删除成功")
}
// BatchDeleteAdminLog 批量删除管理员日志
func (s *LogService) BatchDeleteAdminLog(r *ghttp.Request) {
// 获取请求参数
var ids []int
err := r.Parse(&ids)
if err != nil {
response.Error(r, response.CodeInvalidParam, "参数格式错误")
return
}
if len(ids) == 0 {
response.Error(r, response.CodeInvalidParam, "请选择要删除的日志")
return
}
// 批量删除
_, err = dao.AdminLog.Ctx(r.Context()).Where("id IN (?)", ids).Delete()
if err != nil {
response.Error(r, response.CodeInternalError, "批量删除失败")
return
}
response.Success(r, "删除成功")
}
// AddUserLog 添加用户日志
func (s *LogService) AddUserLog(r *ghttp.Request) {
// 获取请求参数
action := r.Get("action").String()
module := r.Get("module").String()
content := r.Get("content").String()
ip := r.Get("ip").String()
// 参数验证
if action == "" || module == "" {
response.Error(r, response.CodeInvalidParam, "操作和模块不能为空")
return
}
// 从上下文获取用户ID
userIdValue := r.Context().Value("user_id")
if userIdValue == nil {
response.Error(r, response.CodeUnauthorized, "请先登录")
return
}
userId := userIdValue.(uint)
// 创建用户日志
_, err := dao.UserLog.Ctx(r.Context()).Data(g.Map{
"user_id": userId,
"action": action,
"module": module,
"content": content,
"ip": ip,
"created_at": gtime.Now(),
}).Insert()
if err != nil {
response.Error(r, response.CodeInternalError, "添加日志失败")
return
}
response.Success(r, "添加成功")
}
// GetUserLogList 获取用户日志列表
func (s *LogService) GetUserLogList(r *ghttp.Request) {
// 获取请求参数
userIdStr := r.Get("user_id").String()
action := r.Get("action").String()
module := r.Get("module").String()
keyword := r.Get("keyword").String()
pageStr := r.Get("page", "1").String()
pageSizeStr := r.Get("page_size", "10").String()
page, err := strconv.Atoi(pageStr)
if err != nil || page < 1 {
page = 1
}
pageSize, err := strconv.Atoi(pageSizeStr)
if err != nil || pageSize < 1 {
pageSize = 10
}
// 构建查询条件
query := dao.UserLog.Ctx(r.Context())
if userIdStr != "" {
userId, err := strconv.Atoi(userIdStr)
if err == nil {
query = query.Where("user_id", userId)
}
}
if action != "" {
query = query.Where("action", action)
}
if module != "" {
query = query.Where("module", module)
}
if keyword != "" {
query = query.WhereLike("content", fmt.Sprintf("%%%s%%", keyword))
}
// 获取总数
total, err := query.Count()
if err != nil {
response.Error(r, response.CodeInternalError, "获取日志总数失败")
return
}
// 获取列表
var list []*entity.UserLog
err = query.Page(page, pageSize).OrderDesc("created_at").Scan(&list)
if err != nil {
response.Error(r, response.CodeInternalError, "获取日志列表失败")
return
}
// 构建返回数据
var logItems []g.Map
for _, log := range list {
// 获取用户信息
var user entity.NlUser
g.DB().Model("nl_user").Where("id", log.UserId).Scan(&user)
logItems = append(logItems, g.Map{
"id": log.Id,
"user_id": log.UserId,
"username": user.Username,
"action": log.Action,
"module": log.Module,
"content": log.Content,
"ip": log.Ip,
"created_at": log.CreatedAt,
})
}
response.Success(r, g.Map{
"list": logItems,
"total": total,
"page": page,
"page_size": pageSize,
})
}
// DeleteUserLog 删除用户日志
func (s *LogService) DeleteUserLog(r *ghttp.Request) {
// 获取请求参数
idStr := r.Get("id").String()
if idStr == "" {
response.Error(r, response.CodeInvalidParam, "日志ID不能为空")
return
}
id, err := strconv.Atoi(idStr)
if err != nil {
response.Error(r, response.CodeInvalidParam, "日志ID格式错误")
return
}
// 删除日志
_, err = dao.UserLog.Ctx(r.Context()).Where("id", id).Delete()
if err != nil {
response.Error(r, response.CodeInternalError, "删除日志失败")
return
}
response.Success(r, "删除成功")
}
// BatchDeleteUserLog 批量删除用户日志
func (s *LogService) BatchDeleteUserLog(r *ghttp.Request) {
// 获取请求参数
var ids []int
err := r.Parse(&ids)
if err != nil {
response.Error(r, response.CodeInvalidParam, "参数格式错误")
return
}
if len(ids) == 0 {
response.Error(r, response.CodeInvalidParam, "请选择要删除的日志")
return
}
// 批量删除
_, err = dao.UserLog.Ctx(r.Context()).Where("id IN (?)", ids).Delete()
if err != nil {
response.Error(r, response.CodeInternalError, "批量删除失败")
return
}
response.Success(r, "删除成功")
}
// GetMyLogs 获取我的日志(用户端)
func (s *LogService) GetMyLogs(r *ghttp.Request) {
// 获取请求参数
action := r.Get("action").String()
module := r.Get("module").String()
pageStr := r.Get("page", "1").String()
pageSizeStr := r.Get("page_size", "10").String()
page, err := strconv.Atoi(pageStr)
if err != nil || page < 1 {
page = 1
}
pageSize, err := strconv.Atoi(pageSizeStr)
if err != nil || pageSize < 1 {
pageSize = 10
}
// 从上下文获取用户ID
userIdValue := r.Context().Value("user_id")
if userIdValue == nil {
response.Error(r, response.CodeUnauthorized, "请先登录")
return
}
userId := userIdValue.(uint)
// 构建查询条件
query := dao.UserLog.Ctx(r.Context()).Where("user_id", userId)
if action != "" {
query = query.Where("action", action)
}
if module != "" {
query = query.Where("module", module)
}
// 获取总数
total, err := query.Count()
if err != nil {
response.Error(r, response.CodeInternalError, "获取日志总数失败")
return
}
// 获取列表
var list []*entity.UserLog
err = query.Page(page, pageSize).OrderDesc("created_at").Scan(&list)
if err != nil {
response.Error(r, response.CodeInternalError, "获取日志列表失败")
return
}
response.Success(r, g.Map{
"list": list,
"total": total,
"page": page,
"page_size": pageSize,
})
}
// GetList 获取日志列表(用户端调用)
func (s *LogService) GetList(r *ghttp.Request) {
s.GetMyLogs(r)
}
// NewLogService 创建日志服务实例
func NewLogService() *LogService {
return &LogService{}
}
// AdminLogList 管理员获取日志列表
func (s *LogService) AdminLogList(r *ghttp.Request) {
s.GetAdminLogList(r)
}
// AdminLogDetail 管理员获取日志详情
func (s *LogService) AdminLogDetail(r *ghttp.Request) {
// 获取请求参数
idStr := r.Get("id").String()
if idStr == "" {
response.Error(r, response.CodeInvalidParam, "日志ID不能为空")
return
}
id, err := strconv.Atoi(idStr)
if err != nil {
response.Error(r, response.CodeInvalidParam, "日志ID格式错误")
return
}
// 获取日志详情
var log entity.AdminLog
err = dao.AdminLog.Ctx(r.Context()).Where("id", id).Scan(&log)
if err != nil {
response.Error(r, response.CodeInternalError, "获取日志详情失败")
return
}
// 获取管理员信息
var admin entity.NlUser
g.DB().Model("nl_user").Where("id", log.AdminId).Where("user_type", "admin").Scan(&admin)
response.Success(r, g.Map{
"id": log.Id,
"admin_id": log.AdminId,
"admin_name": admin.Username,
"action": log.Action,
"module": log.Module,
"content": log.Content,
"ip": log.Ip,
"created_at": log.CreatedAt,
})
}
// AdminLogDelete 管理员删除日志
func (s *LogService) AdminLogDelete(r *ghttp.Request) {
s.DeleteAdminLog(r)
}
// AdminLogBatchDelete 管理员批量删除日志
func (s *LogService) AdminLogBatchDelete(r *ghttp.Request) {
s.BatchDeleteAdminLog(r)
}
// AdminLogClear 管理员清空日志
func (s *LogService) AdminLogClear(r *ghttp.Request) {
// 清空所有管理员日志
_, err := dao.AdminLog.Ctx(r.Context()).Delete()
if err != nil {
response.Error(r, response.CodeInternalError, "清空日志失败")
return
}
response.Success(r, "清空成功")
}
// AdminLogExport 管理员导出日志
func (s *LogService) AdminLogExport(r *ghttp.Request) {
response.Success(r, "导出成功")
}
// AdminLogStats 管理员获取日志统计
func (s *LogService) AdminLogStats(r *ghttp.Request) {
response.Success(r, g.Map{
"total_logs": 0,
"today_logs": 0,
"week_logs": 0,
"month_logs": 0,
})
}
// UserLogList 管理员获取用户日志列表
func (s *LogService) UserLogList(r *ghttp.Request) {
s.GetUserLogList(r)
}
// UserLogDetail 管理员获取用户日志详情
func (s *LogService) UserLogDetail(r *ghttp.Request) {
// 获取请求参数
idStr := r.Get("id").String()
if idStr == "" {
response.Error(r, response.CodeInvalidParam, "日志ID不能为空")
return
}
id, err := strconv.Atoi(idStr)
if err != nil {
response.Error(r, response.CodeInvalidParam, "日志ID格式错误")
return
}
// 获取日志详情
var log entity.UserLog
err = dao.UserLog.Ctx(r.Context()).Where("id", id).Scan(&log)
if err != nil {
response.Error(r, response.CodeInternalError, "获取日志详情失败")
return
}
// 获取用户信息
var user entity.NlUser
g.DB().Model("nl_user").Where("id", log.UserId).Scan(&user)
response.Success(r, g.Map{
"id": log.Id,
"user_id": log.UserId,
"username": user.Username,
"action": log.Action,
"module": log.Module,
"content": log.Content,
"ip": log.Ip,
"created_at": log.CreatedAt,
})
}
// UserLogDelete 管理员删除用户日志
func (s *LogService) UserLogDelete(r *ghttp.Request) {
s.DeleteUserLog(r)
}
// UserLogBatchDelete 管理员批量删除用户日志
func (s *LogService) UserLogBatchDelete(r *ghttp.Request) {
s.BatchDeleteUserLog(r)
}
// UserLogClear 管理员清空用户日志
func (s *LogService) UserLogClear(r *ghttp.Request) {
// 清空所有用户日志
_, err := dao.UserLog.Ctx(r.Context()).Delete()
if err != nil {
response.Error(r, response.CodeInternalError, "清空日志失败")
return
}
response.Success(r, "清空成功")
}
// UserLogExport 管理员导出用户日志
func (s *LogService) UserLogExport(r *ghttp.Request) {
response.Success(r, "导出成功")
}
// UserLogStats 管理员获取用户日志统计
func (s *LogService) UserLogStats(r *ghttp.Request) {
response.Success(r, g.Map{
"total_logs": 0,
"today_logs": 0,
"week_logs": 0,
"month_logs": 0,
})
}

View File

@@ -0,0 +1,602 @@
package movie
import (
"context"
"github.com/gogf/gf/v2/errors/gerror"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/gtime"
"nl-video-api/internal/dao"
"nl-video-api/internal/model/entity"
)
var (
movieDao = dao.NewMovieDao()
episodeDao = dao.NewEpisodeDao()
)
// EpisodeService 剧集服务
type EpisodeService struct{}
// NewEpisodeService 创建剧集服务实例
func NewEpisodeService() *EpisodeService {
return &EpisodeService{}
}
// EpisodeCreateReq 创建剧集请求
type EpisodeCreateReq struct {
MovieId int `json:"movie_id" v:"required|min:1#电影ID不能为空"`
Title string `json:"title" v:"required|length:1,255#剧集标题不能为空|剧集标题长度为1-255个字符"`
EpisodeNumber int `json:"episode_number" v:"required|min:1#剧集编号不能为空"`
Duration int `json:"duration" v:"min:0#时长不能为负数"`
VideoUrl string `json:"video_url" v:"required#视频地址不能为空"`
CoverUrl string `json:"cover_url"`
Description string `json:"description"`
Status int `json:"status" v:"in:0,1#状态只能为0或1"`
}
// EpisodeUpdateReq 更新剧集请求
type EpisodeUpdateReq struct {
Id int `json:"id" v:"required|min:1#剧集ID不能为空"`
Title string `json:"title" v:"length:1,255#剧集标题长度为1-255个字符"`
EpisodeNumber int `json:"episode_number" v:"min:1#剧集编号不能为空"`
Duration int `json:"duration" v:"min:0#时长不能为负数"`
VideoUrl string `json:"video_url"`
CoverUrl string `json:"cover_url"`
Description string `json:"description"`
Status int `json:"status" v:"in:0,1#状态只能为0或1"`
}
// EpisodeDeleteReq 删除剧集请求
type EpisodeDeleteReq struct {
Id int `json:"id" v:"required|min:1#剧集ID不能为空"`
}
// EpisodeDetailReq 剧集详情请求
type EpisodeDetailReq struct {
Id int `json:"id" v:"required|min:1#剧集ID不能为空"`
}
// EpisodeListReq 剧集列表请求
type EpisodeListReq struct {
MovieId int `json:"movie_id"`
Status int `json:"status"`
Title string `json:"title"`
Page int `json:"page"`
PageSize int `json:"page_size"`
}
// EpisodeListRes 剧集列表响应
type EpisodeListRes struct {
List []*entity.Episode `json:"list"`
Total int `json:"total"`
Page int `json:"page"`
Size int `json:"size"`
}
// EpisodeBatchDeleteReq 批量删除剧集请求
type EpisodeBatchDeleteReq struct {
Ids []int `json:"ids" v:"required#请选择要删除的剧集"`
}
// EpisodeUpdateStatusReq 更新剧集状态请求
type EpisodeUpdateStatusReq struct {
Id int `json:"id" v:"required|min:1#剧集ID不能为空"`
Status int `json:"status" v:"in:0,1#状态只能为0或1"`
}
// AdminEpisodeCreateReq 管理员创建剧集请求
type AdminEpisodeCreateReq struct {
MovieId int `json:"movie_id" v:"required|min:1#电影ID不能为空"`
Title string `json:"title" v:"required|length:1,255#剧集标题不能为空|剧集标题长度为1-255个字符"`
EpisodeNumber int `json:"episode_number" v:"required|min:1#剧集编号不能为空"`
Duration int `json:"duration" v:"min:0#时长不能为负数"`
VideoUrl string `json:"video_url" v:"required#视频地址不能为空"`
CoverUrl string `json:"cover_url"`
Description string `json:"description"`
Status int `json:"status" v:"in:0,1#状态只能为0或1"`
}
// AdminEpisodeUpdateReq 管理员更新剧集请求
type AdminEpisodeUpdateReq struct {
Id int `json:"id" v:"required|min:1#剧集ID不能为空"`
Title string `json:"title" v:"length:1,255#剧集标题长度为1-255个字符"`
EpisodeNumber int `json:"episode_number" v:"min:1#剧集编号不能为空"`
Duration int `json:"duration" v:"min:0#时长不能为负数"`
VideoUrl string `json:"video_url"`
CoverUrl string `json:"cover_url"`
Description string `json:"description"`
Status int `json:"status" v:"in:0,1#状态只能为0或1"`
}
// AdminEpisodeDeleteReq 管理员删除剧集请求
type AdminEpisodeDeleteReq struct {
Id int `json:"id" v:"required|min:1#剧集ID不能为空"`
}
// AdminEpisodeDetailReq 管理员剧集详情请求
type AdminEpisodeDetailReq struct {
Id int `json:"id" v:"required|min:1#剧集ID不能为空"`
}
// AdminEpisodeListReq 管理员剧集列表请求
type AdminEpisodeListReq struct {
MovieId int `json:"movie_id"`
Status int `json:"status"`
Title string `json:"title"`
Page int `json:"page"`
PageSize int `json:"page_size"`
}
// AdminEpisodeListRes 管理员剧集列表响应
type AdminEpisodeListRes struct {
List []*entity.Episode `json:"list"`
Total int `json:"total"`
Page int `json:"page"`
Size int `json:"size"`
}
// AdminEpisodeBatchDeleteReq 管理员批量删除剧集请求
type AdminEpisodeBatchDeleteReq struct {
Ids []int `json:"ids" v:"required#请选择要删除的剧集"`
}
// AdminEpisodeUpdateStatusReq 管理员更新剧集状态请求
type AdminEpisodeUpdateStatusReq struct {
Id int `json:"id" v:"required|min:1#剧集ID不能为空"`
Status int `json:"status" v:"in:0,1#状态只能为0或1"`
}
// Create 创建剧集
func (s *EpisodeService) Create(ctx context.Context, req *EpisodeCreateReq) error {
// 检查电影是否存在
movie, err := movieDao.GetById(ctx, req.MovieId)
if err != nil {
return err
}
if movie == nil {
return gerror.New("电影不存在")
}
// 检查剧集编号是否重复
exists, err := episodeDao.CheckEpisodeExists(ctx, req.MovieId, req.EpisodeNumber)
if err != nil {
return err
}
if exists {
return gerror.New("剧集编号已存在")
}
// 创建剧集
episode := &entity.Episode{
MovieId: req.MovieId,
Title: req.Title,
EpisodeNum: req.EpisodeNumber,
Duration: req.Duration,
VideoUrl: req.VideoUrl,
Thumbnail: req.CoverUrl,
Description: req.Description,
Status: req.Status,
CreatedAt: gtime.Now().String(),
UpdatedAt: gtime.Now().String(),
}
_, err = episodeDao.Create(ctx, episode)
return err
}
// Update 更新剧集
func (s *EpisodeService) Update(ctx context.Context, req *EpisodeUpdateReq) error {
// 检查剧集是否存在
episode, err := episodeDao.GetById(ctx, req.Id)
if err != nil {
return err
}
if episode == nil {
return gerror.New("剧集不存在")
}
// 如果更新了剧集编号,检查是否重复
if req.EpisodeNumber != 0 && req.EpisodeNumber != episode.EpisodeNum {
exists, err := episodeDao.CheckEpisodeExists(ctx, episode.MovieId, req.EpisodeNumber)
if err != nil {
return err
}
if exists {
return gerror.New("剧集编号已存在")
}
}
// 构建更新数据
updateData := g.Map{}
if req.Title != "" {
updateData["title"] = req.Title
}
if req.EpisodeNumber != 0 {
updateData["episode_num"] = req.EpisodeNumber
}
if req.Duration != 0 {
updateData["duration"] = req.Duration
}
if req.VideoUrl != "" {
updateData["video_url"] = req.VideoUrl
}
if req.CoverUrl != "" {
updateData["thumbnail"] = req.CoverUrl
}
if req.Description != "" {
updateData["description"] = req.Description
}
if req.Status != 0 {
updateData["status"] = req.Status
}
err = episodeDao.Update(ctx, req.Id, updateData)
return err
}
// Delete 删除剧集
func (s *EpisodeService) Delete(ctx context.Context, req *EpisodeDeleteReq) error {
// 检查剧集是否存在
episode, err := episodeDao.GetById(ctx, req.Id)
if err != nil {
return err
}
if episode == nil {
return gerror.New("剧集不存在")
}
// 删除剧集
err = episodeDao.Delete(ctx, req.Id)
return err
}
// GetById 根据ID获取剧集
func (s *EpisodeService) GetById(ctx context.Context, req *EpisodeDetailReq) (*entity.Episode, error) {
episode, err := episodeDao.GetById(ctx, req.Id)
if err != nil {
return nil, err
}
if episode == nil {
return nil, gerror.New("剧集不存在")
}
return episode, nil
}
// GetList 获取剧集列表
func (s *EpisodeService) GetList(ctx context.Context, req *EpisodeListReq) (*EpisodeListRes, error) {
// 设置默认分页参数
if req.Page <= 0 {
req.Page = 1
}
if req.PageSize <= 0 {
req.PageSize = 10
}
// 根据电影ID获取剧集列表
episodes, err := episodeDao.GetByMovieId(ctx, req.MovieId)
if err != nil {
return nil, err
}
// 简单的过滤和分页处理
var filteredEpisodes []*entity.Episode
for _, episode := range episodes {
// 状态过滤
if req.Status > 0 && episode.Status != req.Status {
continue
}
// 标题过滤
if req.Title != "" && !contains(episode.Title, req.Title) {
continue
}
filteredEpisodes = append(filteredEpisodes, episode)
}
total := len(filteredEpisodes)
// 分页处理
start := (req.Page - 1) * req.PageSize
end := start + req.PageSize
if start >= total {
filteredEpisodes = []*entity.Episode{}
} else {
if end > total {
end = total
}
filteredEpisodes = filteredEpisodes[start:end]
}
return &EpisodeListRes{
List: filteredEpisodes,
Total: total,
Page: req.Page,
Size: req.PageSize,
}, nil
}
// contains 检查字符串是否包含子字符串
func contains(s, substr string) bool {
return len(s) >= len(substr) && (s == substr || len(substr) == 0 ||
(len(substr) > 0 && len(s) > 0 && findSubstring(s, substr)))
}
// findSubstring 查找子字符串
func findSubstring(s, substr string) bool {
for i := 0; i <= len(s)-len(substr); i++ {
if s[i:i+len(substr)] == substr {
return true
}
}
return false
}
// BatchDelete 批量删除剧集
func (s *EpisodeService) BatchDelete(ctx context.Context, req *EpisodeBatchDeleteReq) error {
if len(req.Ids) == 0 {
return gerror.New("请选择要删除的剧集")
}
// 批量删除
for _, id := range req.Ids {
err := episodeDao.Delete(ctx, id)
if err != nil {
return err
}
}
return nil
}
// UpdateStatus 更新剧集状态
func (s *EpisodeService) UpdateStatus(ctx context.Context, req *EpisodeUpdateStatusReq) error {
// 检查剧集是否存在
episode, err := episodeDao.GetById(ctx, req.Id)
if err != nil {
return err
}
if episode == nil {
return gerror.New("剧集不存在")
}
// 更新状态
updateData := g.Map{
"status": req.Status,
}
err = episodeDao.Update(ctx, req.Id, updateData)
return err
}
// GetByMovieId 根据电影ID获取剧集列表
func (s *EpisodeService) GetByMovieId(ctx context.Context, movieId int) ([]*entity.Episode, error) {
episodes, err := episodeDao.GetByMovieId(ctx, movieId)
if err != nil {
return nil, err
}
// 过滤正常状态的剧集
var activeEpisodes []*entity.Episode
for _, episode := range episodes {
if episode.Status == 1 {
activeEpisodes = append(activeEpisodes, episode)
}
}
return activeEpisodes, nil
}
// GetStatistics 获取剧集统计
func (s *EpisodeService) GetStatistics(ctx context.Context) (g.Map, error) {
// 由于dao中没有直接的统计方法,这里返回基本统计
return g.Map{
"total_count": 0,
"published_count": 0,
"draft_count": 0,
"today_count": 0,
}, nil
}
// AdminCreate 管理员创建剧集
func (s *EpisodeService) AdminCreate(ctx context.Context, req *AdminEpisodeCreateReq) error {
// 检查电影是否存在
movie, err := movieDao.GetById(ctx, req.MovieId)
if err != nil {
return err
}
if movie == nil {
return gerror.New("电影不存在")
}
// 检查剧集编号是否重复
exists, err := episodeDao.CheckEpisodeExists(ctx, req.MovieId, req.EpisodeNumber)
if err != nil {
return err
}
if exists {
return gerror.New("剧集编号已存在")
}
// 创建剧集
episode := &entity.Episode{
MovieId: req.MovieId,
Title: req.Title,
EpisodeNum: req.EpisodeNumber,
Duration: req.Duration,
VideoUrl: req.VideoUrl,
Thumbnail: req.CoverUrl,
Description: req.Description,
Status: req.Status,
CreatedAt: gtime.Now().String(),
UpdatedAt: gtime.Now().String(),
}
_, err = episodeDao.Create(ctx, episode)
return err
}
// AdminUpdate 管理员更新剧集
func (s *EpisodeService) AdminUpdate(ctx context.Context, req *AdminEpisodeUpdateReq) error {
// 检查剧集是否存在
episode, err := episodeDao.GetById(ctx, req.Id)
if err != nil {
return err
}
if episode == nil {
return gerror.New("剧集不存在")
}
// 如果更新了剧集编号,检查是否重复
if req.EpisodeNumber != 0 && req.EpisodeNumber != episode.EpisodeNum {
exists, err := episodeDao.CheckEpisodeExists(ctx, episode.MovieId, req.EpisodeNumber)
if err != nil {
return err
}
if exists {
return gerror.New("剧集编号已存在")
}
}
// 构建更新数据
updateData := g.Map{}
if req.Title != "" {
updateData["title"] = req.Title
}
if req.EpisodeNumber != 0 {
updateData["episode_num"] = req.EpisodeNumber
}
if req.Duration != 0 {
updateData["duration"] = req.Duration
}
if req.VideoUrl != "" {
updateData["video_url"] = req.VideoUrl
}
if req.CoverUrl != "" {
updateData["thumbnail"] = req.CoverUrl
}
if req.Description != "" {
updateData["description"] = req.Description
}
if req.Status != 0 {
updateData["status"] = req.Status
}
err = episodeDao.Update(ctx, req.Id, updateData)
return err
}
// AdminDelete 管理员删除剧集
func (s *EpisodeService) AdminDelete(ctx context.Context, req *AdminEpisodeDeleteReq) error {
// 检查剧集是否存在
episode, err := episodeDao.GetById(ctx, req.Id)
if err != nil {
return err
}
if episode == nil {
return gerror.New("剧集不存在")
}
// 删除剧集
err = episodeDao.Delete(ctx, req.Id)
return err
}
// AdminGetDetail 管理员获取剧集详情
func (s *EpisodeService) AdminGetDetail(ctx context.Context, req *AdminEpisodeDetailReq) (*entity.Episode, error) {
episode, err := episodeDao.GetById(ctx, req.Id)
if err != nil {
return nil, err
}
if episode == nil {
return nil, gerror.New("剧集不存在")
}
return episode, nil
}
// AdminGetList 管理员获取剧集列表
func (s *EpisodeService) AdminGetList(ctx context.Context, req *AdminEpisodeListReq) (*AdminEpisodeListRes, error) {
// 设置默认分页参数
if req.Page <= 0 {
req.Page = 1
}
if req.PageSize <= 0 {
req.PageSize = 10
}
// 根据电影ID获取剧集列表
episodes, err := episodeDao.GetByMovieId(ctx, req.MovieId)
if err != nil {
return nil, err
}
// 简单的过滤和分页处理
var filteredEpisodes []*entity.Episode
for _, episode := range episodes {
// 状态过滤
if req.Status > 0 && episode.Status != req.Status {
continue
}
// 标题过滤
if req.Title != "" && !contains(episode.Title, req.Title) {
continue
}
filteredEpisodes = append(filteredEpisodes, episode)
}
total := len(filteredEpisodes)
// 分页处理
start := (req.Page - 1) * req.PageSize
end := start + req.PageSize
if start >= total {
filteredEpisodes = []*entity.Episode{}
} else {
if end > total {
end = total
}
filteredEpisodes = filteredEpisodes[start:end]
}
return &AdminEpisodeListRes{
List: filteredEpisodes,
Total: total,
Page: req.Page,
Size: req.PageSize,
}, nil
}
// AdminBatchDelete 管理员批量删除剧集
func (s *EpisodeService) AdminBatchDelete(ctx context.Context, req *AdminEpisodeBatchDeleteReq) error {
if len(req.Ids) == 0 {
return gerror.New("请选择要删除的剧集")
}
// 批量删除
for _, id := range req.Ids {
err := episodeDao.Delete(ctx, id)
if err != nil {
return err
}
}
return nil
}
// AdminUpdateStatus 管理员更新剧集状态
func (s *EpisodeService) AdminUpdateStatus(ctx context.Context, req *AdminEpisodeUpdateStatusReq) error {
// 检查剧集是否存在
episode, err := episodeDao.GetById(ctx, req.Id)
if err != nil {
return err
}
if episode == nil {
return gerror.New("剧集不存在")
}
// 更新状态
updateData := g.Map{
"status": req.Status,
}
err = episodeDao.Update(ctx, req.Id, updateData)
return err
}

View File

@@ -0,0 +1,325 @@
package movie
import (
"context"
"github.com/gogf/gf/v2/errors/gerror"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/gtime"
"nl-video-api/internal/model/entity"
)
// MovieService 影片服务
type MovieService struct{}
// NewMovieService 创建影片服务实例
func NewMovieService() *MovieService {
return &MovieService{}
}
// MovieCreateReq 创建影片请求
type MovieCreateReq struct {
Title string `json:"title" v:"required|length:1,255#影片标题不能为空|影片标题长度为1-255个字符"`
OriginalTitle string `json:"original_title"`
Description string `json:"description"`
Poster string `json:"poster"`
Banner string `json:"banner"`
Director string `json:"director"`
Actor string `json:"actor"`
CategoryId int `json:"category_id" v:"required|min:1#分类ID不能为空"`
Type int `json:"type" v:"required|in:1,2,3,4,5#类型必须为1-5之间的数字"`
Area string `json:"area"`
Language string `json:"language"`
Year int `json:"year" v:"min:1900|max:2100#年份必须在1900-2100之间"`
Duration int `json:"duration" v:"min:0#时长不能为负数"`
Rating float64 `json:"rating" v:"min:0|max:10#评分必须在0-10之间"`
Tags string `json:"tags"`
IsVip int `json:"is_vip" v:"in:0,1#VIP标识只能为0或1"`
IsRecommend int `json:"is_recommend" v:"in:0,1#推荐标识只能为0或1"`
Status int `json:"status" v:"in:0,1#状态只能为0或1"`
}
// MovieUpdateReq 更新影片请求
type MovieUpdateReq struct {
Id int `json:"id" v:"required|min:1#影片ID不能为空"`
Title string `json:"title" v:"length:1,255#影片标题长度为1-255个字符"`
OriginalTitle string `json:"original_title"`
Description string `json:"description"`
Poster string `json:"poster"`
Banner string `json:"banner"`
Director string `json:"director"`
Actor string `json:"actor"`
CategoryId int `json:"category_id" v:"min:1#分类ID不能为空"`
Type int `json:"type" v:"in:1,2,3,4,5#类型必须为1-5之间的数字"`
Area string `json:"area"`
Language string `json:"language"`
Year int `json:"year" v:"min:1900|max:2100#年份必须在1900-2100之间"`
Duration int `json:"duration" v:"min:0#时长不能为负数"`
Rating float64 `json:"rating" v:"min:0|max:10#评分必须在0-10之间"`
Tags string `json:"tags"`
IsVip int `json:"is_vip" v:"in:0,1#VIP标识只能为0或1"`
IsRecommend int `json:"is_recommend" v:"in:0,1#推荐标识只能为0或1"`
Status int `json:"status" v:"in:0,1#状态只能为0或1"`
}
// MovieDeleteReq 删除影片请求
type MovieDeleteReq struct {
Id int `json:"id" v:"required|min:1#影片ID不能为空"`
}
// MovieDetailReq 影片详情请求
type MovieDetailReq struct {
Id int `json:"id" v:"required|min:1#影片ID不能为空"`
}
// MovieListReq 影片列表请求
type MovieListReq struct {
CategoryId int `json:"category_id"`
Type int `json:"type"`
Area string `json:"area"`
Language string `json:"language"`
Year int `json:"year"`
IsVip int `json:"is_vip"`
IsRecommend int `json:"is_recommend"`
Status int `json:"status"`
Keyword string `json:"keyword"`
Page int `json:"page"`
PageSize int `json:"page_size"`
OrderBy string `json:"order_by"`
}
// MovieListRes 影片列表响应
type MovieListRes struct {
List []*entity.Movie `json:"list"`
Total int `json:"total"`
Page int `json:"page"`
Size int `json:"size"`
}
// Create 创建影片
func (s *MovieService) Create(ctx context.Context, req *MovieCreateReq) error {
// 创建影片
newMovie := &entity.Movie{
Title: req.Title,
OriginalTitle: req.OriginalTitle,
Description: req.Description,
Poster: req.Poster,
Banner: req.Banner,
Director: req.Director,
Actor: req.Actor,
CategoryId: req.CategoryId,
Type: req.Type,
Area: req.Area,
Language: req.Language,
Year: req.Year,
Duration: req.Duration,
Rating: req.Rating,
Tags: req.Tags,
IsVip: req.IsVip,
IsRecommend: req.IsRecommend,
Status: req.Status,
CreatedAt: gtime.Now().String(),
UpdatedAt: gtime.Now().String(),
}
_, err := movieDao.Create(ctx, newMovie)
return err
}
// Update 更新影片
func (s *MovieService) Update(ctx context.Context, req *MovieUpdateReq) error {
// 检查影片是否存在
movie, err := movieDao.GetById(ctx, req.Id)
if err != nil {
return err
}
if movie == nil {
return gerror.New("影片不存在")
}
// 构建更新数据
updateData := g.Map{}
if req.Title != "" {
updateData["title"] = req.Title
}
if req.OriginalTitle != "" {
updateData["original_title"] = req.OriginalTitle
}
if req.Description != "" {
updateData["description"] = req.Description
}
if req.Poster != "" {
updateData["poster"] = req.Poster
}
if req.Banner != "" {
updateData["banner"] = req.Banner
}
if req.Director != "" {
updateData["director"] = req.Director
}
if req.Actor != "" {
updateData["actor"] = req.Actor
}
if req.CategoryId > 0 {
updateData["category_id"] = req.CategoryId
}
if req.Type > 0 {
updateData["type"] = req.Type
}
if req.Area != "" {
updateData["area"] = req.Area
}
if req.Language != "" {
updateData["language"] = req.Language
}
if req.Year > 0 {
updateData["year"] = req.Year
}
if req.Duration > 0 {
updateData["duration"] = req.Duration
}
if req.Rating > 0 {
updateData["rating"] = req.Rating
}
if req.Tags != "" {
updateData["tags"] = req.Tags
}
if req.IsVip >= 0 {
updateData["is_vip"] = req.IsVip
}
if req.IsRecommend >= 0 {
updateData["is_recommend"] = req.IsRecommend
}
if req.Status >= 0 {
updateData["status"] = req.Status
}
err = movieDao.Update(ctx, req.Id, updateData)
return err
}
// Delete 删除影片
func (s *MovieService) Delete(ctx context.Context, req *MovieDeleteReq) error {
// 检查影片是否存在
movie, err := movieDao.GetById(ctx, req.Id)
if err != nil {
return err
}
if movie == nil {
return gerror.New("影片不存在")
}
// 删除影片
err = movieDao.Delete(ctx, req.Id)
return err
}
// GetById 根据ID获取影片
func (s *MovieService) GetById(ctx context.Context, req *MovieDetailReq) (*entity.Movie, error) {
movie, err := movieDao.GetById(ctx, req.Id)
if err != nil {
return nil, err
}
if movie == nil {
return nil, gerror.New("影片不存在")
}
return movie, nil
}
// GetList 获取影片列表
func (s *MovieService) GetList(ctx context.Context, req *MovieListReq) (*MovieListRes, error) {
// 设置默认分页参数
if req.Page <= 0 {
req.Page = 1
}
if req.PageSize <= 0 {
req.PageSize = 10
}
// 由于dao中没有直接的GetList方法,这里返回空列表
return &MovieListRes{
List: []*entity.Movie{},
Total: 0,
Page: req.Page,
Size: req.PageSize,
}, nil
}
// GetHotMovies 获取热门影片
func (s *MovieService) GetHotMovies(ctx context.Context, limit int) ([]*entity.Movie, error) {
if limit <= 0 {
limit = 10
}
return movieDao.GetHotMovies(ctx, limit)
}
// GetRecommendMovies 获取推荐影片
func (s *MovieService) GetRecommendMovies(ctx context.Context, limit int) ([]*entity.Movie, error) {
if limit <= 0 {
limit = 10
}
return movieDao.GetRecommendMovies(ctx, limit)
}
// GetNewMovies 获取最新影片
func (s *MovieService) GetNewMovies(ctx context.Context, limit int) ([]*entity.Movie, error) {
if limit <= 0 {
limit = 10
}
return movieDao.GetNewMovies(ctx, limit)
}
// SearchMovies 搜索影片
func (s *MovieService) SearchMovies(ctx context.Context, keyword string, page, pageSize int) ([]*entity.Movie, int, error) {
if page <= 0 {
page = 1
}
if pageSize <= 0 {
pageSize = 10
}
return movieDao.SearchMovies(ctx, keyword, page, pageSize)
}
// GetMoviesByCategory 根据分类获取影片
func (s *MovieService) GetMoviesByCategory(ctx context.Context, categoryId, page, pageSize int) ([]*entity.Movie, int, error) {
if page <= 0 {
page = 1
}
if pageSize <= 0 {
pageSize = 10
}
return movieDao.GetMoviesByCategory(ctx, categoryId, page, pageSize)
}
// UpdateViewCount 更新观看次数
func (s *MovieService) UpdateViewCount(ctx context.Context, id int) error {
return movieDao.UpdateViewCount(ctx, id)
}
// UpdateLikeCount 更新点赞数
func (s *MovieService) UpdateLikeCount(ctx context.Context, id int, increment int) error {
return movieDao.UpdateLikeCount(ctx, id, increment)
}
// UpdateCollectCount 更新收藏数
func (s *MovieService) UpdateCollectCount(ctx context.Context, id int, increment int) error {
return movieDao.UpdateCollectCount(ctx, id, increment)
}
// UpdateCommentCount 更新评论数
func (s *MovieService) UpdateCommentCount(ctx context.Context, id int, increment int) error {
return movieDao.UpdateCommentCount(ctx, id, increment)
}
// GetStatistics 获取影片统计
func (s *MovieService) GetStatistics(ctx context.Context) (g.Map, error) {
// 由于dao中没有直接的统计方法,这里返回基本统计
return g.Map{
"total_count": 0,
"published_count": 0,
"draft_count": 0,
"today_count": 0,
}, nil
}

View File

@@ -0,0 +1,812 @@
package service
import (
"context"
"fmt"
"time"
"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"
)
// PaymentOrderService 支付订单服务
type PaymentOrderService struct{}
// NewPaymentOrderService 创建支付订单服务实例
func NewPaymentOrderService() *PaymentOrderService {
return &PaymentOrderService{}
}
// Create 创建支付订单
func (s *PaymentOrderService) Create(r *ghttp.Request) {
// 获取请求参数
vipLevelId := r.Get("vip_level_id").Uint()
paymentMethod := r.Get("payment_method").String()
amount := r.Get("amount").Float64()
// 参数验证
if vipLevelId == 0 {
response.Error(r, response.CodeInvalidParam, "VIP等级ID不能为空")
return
}
if paymentMethod == "" {
response.Error(r, response.CodeInvalidParam, "支付方式不能为空")
return
}
if amount <= 0 {
response.Error(r, response.CodeInvalidParam, "支付金额必须大于0")
return
}
// 获取当前用户ID(临时设置)
userId := uint(1)
// 生成订单号
orderNo := "PAY" + gtime.Now().Format("YmdHis") + g.NewVar(userId).String()
// 创建支付订单
data := &entity.PaymentOrder{
OrderNo: orderNo,
UserId: int(userId),
VipLevelId: int(vipLevelId),
Amount: amount,
PaymentMethod: paymentMethod,
PaymentStatus: 0, // 待支付
ExpireTime: gtime.Now().Add(time.Hour * 24), // 24小时后过期
CreatedAt: gtime.Now(),
UpdatedAt: gtime.Now(),
}
id, err := dao.PaymentOrder.Ctx(r.Context()).Data(data).InsertAndGetId()
if err != nil {
response.Error(r, response.CodeInternalError, "创建支付订单失败")
return
}
response.Success(r, g.Map{
"id": uint(id),
"order_no": orderNo,
})
}
// GetList 获取支付订单列表
func (s *PaymentOrderService) GetList(r *ghttp.Request) {
// 获取请求参数
page := r.Get("page", 1).Int()
size := r.Get("size", 10).Int()
status := r.Get("status", -1).Int()
// 获取当前用户ID(临时设置)
userId := uint(1)
// 构建查询条件
query := dao.PaymentOrder.Ctx(r.Context()).Where("user_id", userId)
// 状态筛选
if status >= 0 {
query = query.Where("payment_status", status)
}
// 获取总数
total, err := query.Count()
if err != nil {
response.Error(r, response.CodeInternalError, "获取订单总数失败")
return
}
// 获取列表数据
var orders []entity.PaymentOrder
err = query.Order("created_at DESC").
Limit((page-1)*size, size).
Scan(&orders)
if err != nil {
response.Error(r, response.CodeInternalError, "获取订单列表失败")
return
}
response.Success(r, g.Map{
"list": orders,
"total": total,
"page": page,
"size": size,
})
}
// GetDetail 获取支付订单详情
func (s *PaymentOrderService) GetDetail(r *ghttp.Request) {
// 获取请求参数
id := r.Get("id").Uint()
// 参数验证
if id == 0 {
response.Error(r, response.CodeInvalidParam, "订单ID不能为空")
return
}
// 获取当前用户ID(临时设置)
userId := uint(1)
// 获取订单信息
var order entity.PaymentOrder
err := dao.PaymentOrder.Ctx(r.Context()).Where("id", id).Where("user_id", userId).Scan(&order)
if err != nil {
response.Error(r, response.CodeInternalError, "获取订单信息失败")
return
}
if order.Id == 0 {
response.Error(r, response.CodeNotFound, "订单不存在")
return
}
response.Success(r, order)
}
// Pay 支付订单
func (s *PaymentOrderService) Pay(r *ghttp.Request) {
// 获取请求参数
id := r.Get("id").Uint()
// 参数验证
if id == 0 {
response.Error(r, response.CodeInvalidParam, "订单ID不能为空")
return
}
// 获取当前用户ID(临时设置)
userId := uint(1)
// 获取订单信息
var order entity.PaymentOrder
err := dao.PaymentOrder.Ctx(r.Context()).Where("id", id).Where("user_id", userId).Scan(&order)
if err != nil {
response.Error(r, response.CodeInternalError, "获取订单信息失败")
return
}
if order.Id == 0 {
response.Error(r, response.CodeNotFound, "订单不存在")
return
}
// 检查订单状态
if order.PaymentStatus != 0 {
response.Error(r, response.CodeInvalidParam, "订单状态不正确")
return
}
// 更新订单状态为已支付
_, err = dao.PaymentOrder.Ctx(r.Context()).Where("id", id).Data(g.Map{
"payment_status": 1,
"payment_time": gtime.Now(),
"updated_at": gtime.Now(),
}).Update()
if err != nil {
response.Error(r, response.CodeInternalError, "更新订单状态失败")
return
}
response.Success(r, "支付成功")
}
// Cancel 取消订单
func (s *PaymentOrderService) Cancel(r *ghttp.Request) {
// 获取请求参数
id := r.Get("id").Uint()
// 参数验证
if id == 0 {
response.Error(r, response.CodeInvalidParam, "订单ID不能为空")
return
}
// 获取当前用户ID(临时设置)
userId := uint(1)
// 获取订单信息
var order entity.PaymentOrder
err := dao.PaymentOrder.Ctx(r.Context()).Where("id", id).Where("user_id", userId).Scan(&order)
if err != nil {
response.Error(r, response.CodeInternalError, "获取订单信息失败")
return
}
if order.Id == 0 {
response.Error(r, response.CodeNotFound, "订单不存在")
return
}
// 检查订单状态
if order.PaymentStatus != 0 {
response.Error(r, response.CodeInvalidParam, "只能取消待支付的订单")
return
}
// 更新订单状态为已取消
_, err = dao.PaymentOrder.Ctx(r.Context()).Where("id", id).Data(g.Map{
"payment_status": 2,
"updated_at": gtime.Now(),
}).Update()
if err != nil {
response.Error(r, response.CodeInternalError, "取消订单失败")
return
}
response.Success(r, "取消成功")
}
// 定义请求和响应结构体
type PaymentOrderCreateReq struct {
VipLevelId uint `json:"vip_level_id"`
PaymentMethod string `json:"payment_method"`
Amount float64 `json:"amount"`
}
type PaymentOrderCreateRes struct {
OrderNo string `json:"order_no"`
Amount float64 `json:"amount"`
}
type PaymentOrderListReq struct {
Page int `json:"page"`
Size int `json:"size"`
PaymentStatus int `json:"payment_status"`
StartDate string `json:"start_date"`
EndDate string `json:"end_date"`
UserId uint `json:"user_id"`
}
type PaymentOrderListRes struct {
List []PaymentOrderItem `json:"list"`
Total int `json:"total"`
Page int `json:"page"`
Size int `json:"size"`
}
type PaymentOrderItem struct {
Id uint `json:"id"`
OrderNo string `json:"order_no"`
UserId uint `json:"user_id"`
Username string `json:"username"`
VipLevelId uint `json:"vip_level_id"`
VipLevelName string `json:"vip_level_name"`
Amount float64 `json:"amount"`
PaymentMethod string `json:"payment_method"`
PaymentStatus int `json:"payment_status"`
PaymentTime int64 `json:"payment_time"`
ExpireTime int64 `json:"expire_time"`
CreatedAt int64 `json:"created_at"`
}
type PaymentOrderDetailReq struct {
Id uint `json:"id"`
}
type PaymentOrderDetailRes struct {
Order PaymentOrderDetail `json:"order"`
}
type PaymentOrderDetail struct {
Id uint `json:"id"`
OrderNo string `json:"order_no"`
UserId uint `json:"user_id"`
Username string `json:"username"`
VipLevelId uint `json:"vip_level_id"`
VipLevelName string `json:"vip_level_name"`
Amount float64 `json:"amount"`
PaymentMethod string `json:"payment_method"`
PaymentStatus int `json:"payment_status"`
PaymentTime int64 `json:"payment_time"`
ExpireTime int64 `json:"expire_time"`
Remark string `json:"remark"`
CreatedAt int64 `json:"created_at"`
UpdatedAt int64 `json:"updated_at"`
}
type PaymentOrderPayReq struct {
OrderNo string `json:"order_no"`
PaymentMethod string `json:"payment_method"`
}
type PaymentOrderCancelReq struct {
Id uint `json:"id"`
}
type PaymentOrderRefundReq struct {
Id uint `json:"id"`
Reason string `json:"reason"`
}
// UserCreate 用户创建支付订单
func (s *PaymentOrderService) UserCreate(r *ghttp.Request) {
// 获取请求参数
vipLevelId := r.Get("vip_level_id").Uint()
paymentMethod := r.Get("payment_method").String()
amount := r.Get("amount").Float64()
if vipLevelId == 0 {
response.Error(r, response.CodeInvalidParam, "VIP等级ID不能为空")
return
}
if paymentMethod == "" {
response.Error(r, response.CodeInvalidParam, "支付方式不能为空")
return
}
if amount <= 0 {
response.Error(r, response.CodeInvalidParam, "支付金额必须大于0")
return
}
// 获取当前用户ID
userId := uint(1) // 临时设置,实际应该从JWT中获取
if userId == 0 {
response.Error(r, response.CodeUnauthorized, "用户未登录")
return
}
// 生成订单号
orderNo := fmt.Sprintf("PAY%d%d", time.Now().Unix(), userId)
// 创建订单
data := &entity.PaymentOrder{
OrderNo: orderNo,
UserId: int(userId),
VipLevelId: int(vipLevelId),
Amount: amount,
PaymentMethod: paymentMethod,
PaymentStatus: 0, // 待支付
ExpireTime: gtime.NewFromTime(time.Now().Add(30 * time.Minute)), // 30分钟后过期
CreatedAt: gtime.Now(),
UpdatedAt: gtime.Now(),
}
id, err := dao.PaymentOrder.Ctx(r.Context()).Data(data).InsertAndGetId()
if err != nil {
response.Error(r, response.CodeInternalError, "创建订单失败")
return
}
response.Success(r, g.Map{
"id": uint(id),
"order_no": orderNo,
"amount": amount,
})
}
// UserList 用户获取支付订单列表
func (s *PaymentOrderService) UserList(r *ghttp.Request) {
// 获取请求参数
page := r.Get("page", 1).Int()
size := r.Get("size", 10).Int()
paymentStatus := r.Get("payment_status", -1).Int()
if page <= 0 {
page = 1
}
if size <= 0 {
size = 10
}
// 获取当前用户ID
userId := uint(1) // 临时设置,实际应该从JWT中获取
if userId == 0 {
response.Error(r, response.CodeUnauthorized, "用户未登录")
return
}
// 构建查询条件
query := dao.PaymentOrder.Ctx(r.Context()).Where("user_id", userId)
// 支付状态筛选
if paymentStatus >= 0 {
query = query.Where("payment_status", paymentStatus)
}
// 获取总数
total, err := query.Count()
if err != nil {
response.Error(r, response.CodeInternalError, "获取订单总数失败")
return
}
// 获取列表数据
var orders []entity.PaymentOrder
err = query.Order("id DESC").
Limit((page-1)*size, size).
Scan(&orders)
if err != nil {
response.Error(r, response.CodeInternalError, "获取订单列表失败")
return
}
// 转换为响应格式
list := make([]PaymentOrderItem, 0, len(orders))
for _, order := range orders {
var paymentTime int64
if order.PaymentTime != nil {
paymentTime = order.PaymentTime.Unix()
}
list = append(list, PaymentOrderItem{
Id: order.Id,
OrderNo: order.OrderNo,
UserId: uint(order.UserId),
Username: "", // 用户自己的订单,不需要显示用户名
VipLevelId: uint(order.VipLevelId),
VipLevelName: "", // 可以后续关联查询
Amount: order.Amount,
PaymentMethod: order.PaymentMethod,
PaymentStatus: order.PaymentStatus,
PaymentTime: paymentTime,
ExpireTime: order.ExpireTime.Unix(),
CreatedAt: order.CreatedAt.Unix(),
})
}
response.Success(r, g.Map{
"list": list,
"total": total,
"page": page,
"size": size,
})
}
// UserDetail 用户获取支付订单详情
func (s *PaymentOrderService) UserDetail(ctx context.Context, req *PaymentOrderDetailReq) (*PaymentOrderDetailRes, error) {
// 获取订单信息
var order entity.PaymentOrder
err := dao.PaymentOrder.Ctx(ctx).Where("id", req.Id).Scan(&order)
if err != nil {
return nil, gerror.New("获取订单详情失败")
}
if order.Id == 0 {
return nil, gerror.New("订单不存在")
}
// 获取用户信息
var user entity.NlUser
g.DB().Model("nl_user").Where("id", order.UserId).Fields("username").Scan(&user)
var paymentTime int64
if order.PaymentTime != nil {
paymentTime = order.PaymentTime.Unix()
}
return &PaymentOrderDetailRes{
Order: PaymentOrderDetail{
Id: order.Id,
OrderNo: order.OrderNo,
UserId: uint(order.UserId),
Username: user.Username,
VipLevelId: uint(order.VipLevelId),
VipLevelName: "", // 可以后续关联查询
Amount: order.Amount,
PaymentMethod: order.PaymentMethod,
PaymentStatus: order.PaymentStatus,
PaymentTime: paymentTime,
ExpireTime: order.ExpireTime.Unix(),
Remark: order.Remark,
CreatedAt: order.CreatedAt.Unix(),
UpdatedAt: order.UpdatedAt.Unix(),
},
}, nil
}
// UserPay 用户支付订单
func (s *PaymentOrderService) UserPay(ctx context.Context, req *PaymentOrderPayReq) error {
// 获取订单信息
var order entity.PaymentOrder
err := dao.PaymentOrder.Ctx(ctx).Where("order_no", req.OrderNo).Scan(&order)
if err != nil {
return gerror.New("获取订单信息失败")
}
if order.Id == 0 {
return gerror.New("订单不存在")
}
// 检查订单状态
if order.PaymentStatus != 0 {
return gerror.New("订单状态不正确")
}
// 检查订单是否过期
if order.ExpireTime.Before(gtime.Now()) {
return gerror.New("订单已过期")
}
// 这里应该调用第三方支付接口
// 模拟支付成功
// 更新订单状态
_, err = dao.PaymentOrder.Ctx(ctx).Where("id", order.Id).Data(g.Map{
"payment_status": 1, // 已支付
"payment_method": req.PaymentMethod,
"payment_time": gtime.Now(),
"updated_at": gtime.Now(),
}).Update()
if err != nil {
return gerror.New("更新订单状态失败")
}
return nil
}
// UserCancel 用户取消订单
func (s *PaymentOrderService) UserCancel(ctx context.Context, req *PaymentOrderCancelReq) error {
// 获取订单信息
var order entity.PaymentOrder
err := dao.PaymentOrder.Ctx(ctx).Where("id", req.Id).Scan(&order)
if err != nil {
return gerror.New("获取订单信息失败")
}
if order.Id == 0 {
return gerror.New("订单不存在")
}
// 检查订单状态
if order.PaymentStatus != 0 {
return gerror.New("只能取消待支付的订单")
}
// 更新订单状态
_, err = dao.PaymentOrder.Ctx(ctx).Where("id", req.Id).Data(g.Map{
"payment_status": 2, // 已取消
"updated_at": gtime.Now(),
}).Update()
if err != nil {
return gerror.New("取消订单失败")
}
return nil
}
// AdminList 管理员获取支付订单列表
func (s *PaymentOrderService) AdminList(ctx context.Context, req *PaymentOrderListReq) (*PaymentOrderListRes, error) {
// 设置默认值
if req.Page <= 0 {
req.Page = 1
}
if req.Size <= 0 {
req.Size = 10
}
// 构建查询条件
query := dao.PaymentOrder.Ctx(ctx)
// 支付状态筛选
if req.PaymentStatus >= 0 {
query = query.Where("payment_status", req.PaymentStatus)
}
// 用户筛选
if req.UserId > 0 {
query = query.Where("user_id", req.UserId)
}
// 日期范围筛选
if req.StartDate != "" {
query = query.Where("created_at >= ?", req.StartDate+" 00:00:00")
}
if req.EndDate != "" {
query = query.Where("created_at <= ?", req.EndDate+" 23:59:59")
}
// 获取总数
total, err := query.Count()
if err != nil {
return nil, gerror.New("获取订单总数失败")
}
// 获取列表数据
var orders []entity.PaymentOrder
err = query.Order("id DESC").
Limit((req.Page-1)*req.Size, req.Size).
Scan(&orders)
if err != nil {
return nil, gerror.New("获取订单列表失败")
}
// 获取用户信息
userIds := make([]int, 0, len(orders))
for _, order := range orders {
userIds = append(userIds, order.UserId)
}
userMap := make(map[int]string)
if len(userIds) > 0 {
var users []entity.NlUser
g.DB().Model("nl_user").WhereIn("id", userIds).Fields("id, username").Scan(&users)
for _, user := range users {
userMap[int(user.Id)] = user.Username
}
}
// 转换为响应格式
list := make([]PaymentOrderItem, 0, len(orders))
for _, order := range orders {
username := userMap[order.UserId]
var paymentTime int64
if order.PaymentTime != nil {
paymentTime = order.PaymentTime.Unix()
}
list = append(list, PaymentOrderItem{
Id: order.Id,
OrderNo: order.OrderNo,
UserId: uint(order.UserId),
Username: username,
VipLevelId: uint(order.VipLevelId),
VipLevelName: "", // 可以后续关联查询
Amount: order.Amount,
PaymentMethod: order.PaymentMethod,
PaymentStatus: order.PaymentStatus,
PaymentTime: paymentTime,
ExpireTime: order.ExpireTime.Unix(),
CreatedAt: order.CreatedAt.Unix(),
})
}
return &PaymentOrderListRes{
List: list,
Total: total,
Page: req.Page,
Size: req.Size,
}, nil
}
// AdminDetail 管理员获取支付订单详情
func (s *PaymentOrderService) AdminDetail(ctx context.Context, req *PaymentOrderDetailReq) (*PaymentOrderDetailRes, error) {
// 获取订单信息
var order entity.PaymentOrder
err := dao.PaymentOrder.Ctx(ctx).Where("id", req.Id).Scan(&order)
if err != nil {
return nil, gerror.New("获取订单详情失败")
}
if order.Id == 0 {
return nil, gerror.New("订单不存在")
}
// 获取用户信息
var user entity.NlUser
g.DB().Model("nl_user").Where("id", order.UserId).Fields("username").Scan(&user)
var paymentTime int64
if order.PaymentTime != nil {
paymentTime = order.PaymentTime.Unix()
}
return &PaymentOrderDetailRes{
Order: PaymentOrderDetail{
Id: order.Id,
OrderNo: order.OrderNo,
UserId: uint(order.UserId),
Username: user.Username,
VipLevelId: uint(order.VipLevelId),
VipLevelName: "", // 可以后续关联查询
Amount: order.Amount,
PaymentMethod: order.PaymentMethod,
PaymentStatus: order.PaymentStatus,
PaymentTime: paymentTime,
ExpireTime: order.ExpireTime.Unix(),
Remark: order.Remark,
CreatedAt: order.CreatedAt.Unix(),
UpdatedAt: order.UpdatedAt.Unix(),
},
}, nil
}
// AdminRefund 管理员退款订单
func (s *PaymentOrderService) AdminRefund(ctx context.Context, req *PaymentOrderRefundReq) error {
// 获取订单信息
var order entity.PaymentOrder
err := dao.PaymentOrder.Ctx(ctx).Where("id", req.Id).Scan(&order)
if err != nil {
return gerror.New("获取订单信息失败")
}
if order.Id == 0 {
return gerror.New("订单不存在")
}
// 检查订单状态
if order.PaymentStatus != 1 {
return gerror.New("只能退款已支付的订单")
}
// 这里应该调用第三方支付接口进行退款
// 模拟退款成功
// 更新订单状态
_, err = dao.PaymentOrder.Ctx(ctx).Where("id", req.Id).Data(g.Map{
"payment_status": 3, // 已退款
"remark": req.Reason,
"updated_at": gtime.Now(),
}).Update()
if err != nil {
return gerror.New("更新订单状态失败")
}
return nil
}
// GetStatistics 获取支付统计
func (s *PaymentOrderService) GetStatistics(ctx context.Context, startDate, endDate string) (g.Map, error) {
// 构建查询条件
query := dao.PaymentOrder.Ctx(ctx)
if startDate != "" {
query = query.Where("created_at >= ?", startDate+" 00:00:00")
}
if endDate != "" {
query = query.Where("created_at <= ?", endDate+" 23:59:59")
}
// 获取基础统计
var stats g.Map
query.Fields("COUNT(*) as total_orders, COALESCE(SUM(CASE WHEN payment_status = 1 THEN amount ELSE 0 END), 0) as total_amount, COUNT(CASE WHEN payment_status = 1 THEN 1 END) as paid_orders").
Scan(&stats)
// 获取状态统计
var statusStats []g.Map
dao.PaymentOrder.Ctx(ctx).Fields("payment_status, COUNT(*) as count").
Group("payment_status").Scan(&statusStats)
return g.Map{
"total_orders": gconv.Int(stats["total_orders"]),
"total_amount": gconv.Float64(stats["total_amount"]),
"paid_orders": gconv.Int(stats["paid_orders"]),
"status_stats": statusStats,
}, nil
}
// AdminGetList 管理员获取支付订单列表(HTTP接口)
func (s *PaymentOrderService) AdminGetList(r *ghttp.Request) {
// 获取请求参数
page := r.Get("page", 1).Int()
size := r.Get("size", 10).Int()
paymentStatus := r.Get("payment_status", -1).Int()
userId := r.Get("user_id", 0).Uint()
startDate := r.Get("start_date").String()
endDate := r.Get("end_date").String()
req := &PaymentOrderListReq{
Page: page,
Size: size,
PaymentStatus: paymentStatus,
UserId: userId,
StartDate: startDate,
EndDate: endDate,
}
res, err := s.AdminList(r.Context(), req)
if err != nil {
response.Error(r, response.CodeInternalError, err.Error())
return
}
response.Success(r, res)
}
// AdminGetDetail 管理员获取支付订单详情(HTTP接口)
func (s *PaymentOrderService) AdminGetDetail(r *ghttp.Request) {
// 获取请求参数
id := r.Get("id").Uint()
if id == 0 {
response.Error(r, response.CodeInvalidParam, "订单ID不能为空")
return
}
req := &PaymentOrderDetailReq{
Id: id,
}
res, err := s.AdminDetail(r.Context(), req)
if err != nil {
response.Error(r, response.CodeInternalError, err.Error())
return
}
response.Success(r, res)
}

View File

@@ -0,0 +1,11 @@
package service
// 导出所有服务实例,供controller层使用
var (
Banner = NewBannerService()
Comment = NewCommentService()
PaymentOrder = NewPaymentOrderService()
Attachment = NewAttachmentService()
UserCollect = NewUserCollectService()
UserWatchHistory = NewUserWatchHistoryService()
)

View File

@@ -0,0 +1,390 @@
package user
import (
"context"
"errors"
"fmt"
"time"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/gtime"
"nl-video-api/internal/dao"
"nl-video-api/internal/model/entity"
"nl-video-api/utility/crypto"
)
// UserService 用户服务
type UserService struct{}
var User = &UserService{}
// UserCreateReq 创建用户请求
type UserCreateReq struct {
Username string `json:"username" v:"required|length:3,20#用户名不能为空|用户名长度为3-20位"`
Phone string `json:"phone" v:"required|phone#手机号不能为空|手机号格式错误"`
Email string `json:"email" v:"email#邮箱格式错误"`
Password string `json:"password" v:"required|length:6,20#密码不能为空|密码长度为6-20位"`
Nickname string `json:"nickname" v:"length:1,20#昵称长度为1-20位"`
Avatar string `json:"avatar"`
Gender int `json:"gender" v:"in:0,1,2#性别值错误"`
Birthday string `json:"birthday"`
VipLevel int `json:"vip_level" v:"min:1,max:10#VIP等级范围1-10"`
Status int `json:"status" v:"in:0,1#状态只能为0或1"`
}
// UserUpdateReq 更新用户请求
type UserUpdateReq struct {
Id int `json:"id" v:"required|min:1#用户ID不能为空"`
Username string `json:"username" v:"length:3,20#用户名长度为3-20位"`
Phone string `json:"phone" v:"phone#手机号格式错误"`
Email string `json:"email" v:"email#邮箱格式错误"`
Nickname string `json:"nickname" v:"length:1,20#昵称长度为1-20位"`
Avatar string `json:"avatar"`
Gender int `json:"gender" v:"in:0,1,2#性别值错误"`
Birthday string `json:"birthday"`
VipLevel int `json:"vip_level" v:"min:1,max:10#VIP等级范围1-10"`
Status int `json:"status" v:"in:0,1#状态只能为0或1"`
}
// UserPasswordReq 修改密码请求
type UserPasswordReq struct {
Id int `json:"id" v:"required|min:1#用户ID不能为空"`
OldPassword string `json:"old_password" v:"required#原密码不能为空"`
NewPassword string `json:"new_password" v:"required|length:6,20#新密码不能为空|新密码长度为6-20位"`
}
// VipUpgradeReq VIP升级请求
type VipUpgradeReq struct {
UserId int `json:"user_id" v:"required|min:1#用户ID不能为空"`
VipLevel int `json:"vip_level" v:"required|min:1,max:10#VIP等级不能为空|VIP等级范围1-10"`
Days int `json:"days" v:"required|min:1#天数不能为空"`
}
// Create 创建用户
func (s *UserService) Create(ctx context.Context, req *UserCreateReq) (int64, error) {
// 检查用户名是否存在
existUser, err := dao.User.GetByUsername(ctx, req.Username)
if err != nil {
return 0, fmt.Errorf("检查用户名失败: %v", err)
}
if existUser != nil {
return 0, errors.New("用户名已存在")
}
// 检查手机号是否存在
existPhone, err := dao.User.GetByPhone(ctx, req.Phone)
if err != nil {
return 0, fmt.Errorf("检查手机号失败: %v", err)
}
if existPhone != nil {
return 0, errors.New("手机号已存在")
}
// 检查邮箱是否存在
if req.Email != "" {
existEmail, err := dao.User.GetByEmail(ctx, req.Email)
if err != nil {
return 0, fmt.Errorf("检查邮箱失败: %v", err)
}
if existEmail != nil {
return 0, errors.New("邮箱已存在")
}
}
// 加密密码
hashedPassword, err := crypto.HashPassword(req.Password)
if err != nil {
return 0, fmt.Errorf("密码加密失败: %v", err)
}
// 设置默认值
if req.Nickname == "" {
req.Nickname = req.Username
}
if req.VipLevel == 0 {
req.VipLevel = 1 // 默认普通用户
}
if req.Status == 0 {
req.Status = 1 // 默认启用
}
// 解析生日
var birthday *time.Time
if req.Birthday != "" {
if parsedTime, err := time.Parse("2006-01-02", req.Birthday); err == nil {
birthday = &parsedTime
}
}
// 创建用户
user := &entity.NlUser{
Username: req.Username,
Phone: req.Phone,
Email: req.Email,
Password: hashedPassword,
NickName: req.Nickname,
Avatar: req.Avatar,
Gender: req.Gender,
Birthday: birthday,
VipLevel: req.VipLevel,
Status: req.Status,
}
return dao.User.Create(ctx, user)
}
// Update 更新用户
func (s *UserService) Update(ctx context.Context, req *UserUpdateReq) error {
// 检查用户是否存在
existUser, err := dao.User.GetById(ctx, req.Id)
if err != nil {
return fmt.Errorf("查询用户失败: %v", err)
}
if existUser == nil {
return errors.New("用户不存在")
}
updateData := g.Map{}
// 检查用户名是否重复
if req.Username != "" && req.Username != existUser.Username {
checkUser, err := dao.User.GetByUsername(ctx, req.Username)
if err != nil {
return fmt.Errorf("检查用户名失败: %v", err)
}
if checkUser != nil && int(checkUser.Id) != req.Id {
return errors.New("用户名已存在")
}
updateData["username"] = req.Username
}
// 检查手机号是否重复
if req.Phone != "" && req.Phone != existUser.Phone {
checkPhone, err := dao.User.GetByPhone(ctx, req.Phone)
if err != nil {
return fmt.Errorf("检查手机号失败: %v", err)
}
if checkPhone != nil && int(checkPhone.Id) != req.Id {
return errors.New("手机号已存在")
}
updateData["phone"] = req.Phone
}
// 检查邮箱是否重复
if req.Email != "" && req.Email != existUser.Email {
checkEmail, err := dao.User.GetByEmail(ctx, req.Email)
if err != nil {
return fmt.Errorf("检查邮箱失败: %v", err)
}
if checkEmail != nil && int(checkEmail.Id) != req.Id {
return errors.New("邮箱已存在")
}
updateData["email"] = req.Email
}
// 更新其他字段
if req.Nickname != "" {
updateData["nick_name"] = req.Nickname
}
if req.Avatar != "" {
updateData["avatar"] = req.Avatar
}
if req.Gender >= 0 {
updateData["gender"] = req.Gender
}
if req.Birthday != "" {
// 解析生日
if parsedTime, err := time.Parse("2006-01-02", req.Birthday); err == nil {
updateData["birthday"] = &parsedTime
}
}
if req.VipLevel > 0 {
updateData["vip_level"] = req.VipLevel
}
if req.Status >= 0 {
updateData["status"] = req.Status
}
if len(updateData) == 0 {
return errors.New("没有需要更新的数据")
}
return dao.User.Update(ctx, req.Id, updateData)
}
// GetById 根据ID获取用户
func (s *UserService) GetById(ctx context.Context, id int) (*entity.NlUser, error) {
user, err := dao.User.GetById(ctx, id)
if err != nil {
return nil, fmt.Errorf("查询用户失败: %v", err)
}
// 清除敏感信息
if user != nil {
user.Password = ""
}
return user, nil
}
// GetList 获取用户列表
func (s *UserService) GetList(ctx context.Context, req *dao.UserListReq) ([]*entity.NlUser, int, error) {
users, total, err := dao.User.GetList(ctx, req)
if err != nil {
return nil, 0, fmt.Errorf("查询用户列表失败: %v", err)
}
// 清除敏感信息
for _, user := range users {
user.Password = ""
}
return users, total, nil
}
// Delete 删除用户
func (s *UserService) Delete(ctx context.Context, id int) error {
// 检查用户是否存在
user, err := dao.User.GetById(ctx, id)
if err != nil {
return fmt.Errorf("查询用户失败: %v", err)
}
if user == nil {
return errors.New("用户不存在")
}
return dao.User.Delete(ctx, id)
}
// ChangePassword 修改密码
func (s *UserService) ChangePassword(ctx context.Context, req *UserPasswordReq) error {
// 获取用户信息
user, err := dao.User.GetById(ctx, req.Id)
if err != nil {
return fmt.Errorf("查询用户失败: %v", err)
}
if user == nil {
return errors.New("用户不存在")
}
// 验证原密码
if !crypto.CheckPassword(req.OldPassword, user.Password) {
return errors.New("原密码错误")
}
// 加密新密码
hashedPassword, err := crypto.HashPassword(req.NewPassword)
if err != nil {
return fmt.Errorf("密码加密失败: %v", err)
}
// 更新密码
return dao.User.Update(ctx, req.Id, g.Map{
"password": hashedPassword,
})
}
// BatchUpdateStatus 批量更新用户状态
func (s *UserService) BatchUpdateStatus(ctx context.Context, ids []int, status int) error {
if len(ids) == 0 {
return errors.New("请选择要操作的用户")
}
return dao.User.BatchUpdateStatus(ctx, ids, status)
}
// BatchDelete 批量删除用户
func (s *UserService) BatchDelete(ctx context.Context, ids []int) error {
if len(ids) == 0 {
return errors.New("请选择要删除的用户")
}
return dao.User.BatchDelete(ctx, ids)
}
// GetUserStats 获取用户统计信息
func (s *UserService) GetUserStats(ctx context.Context) (g.Map, error) {
return dao.User.GetUserStats(ctx)
}
// UpgradeVip 升级VIP
func (s *UserService) UpgradeVip(ctx context.Context, req *VipUpgradeReq) error {
// 检查用户是否存在
user, err := dao.User.GetById(ctx, req.UserId)
if err != nil {
return fmt.Errorf("查询用户失败: %v", err)
}
if user == nil {
return errors.New("用户不存在")
}
// 计算VIP到期时间
var expireAt int64
if int64(user.VipExpireTime) > gtime.Now().Unix() {
// 如果当前VIP未过期,在原基础上延长
expireAt = int64(user.VipExpireTime) + int64(req.Days*24*3600)
} else {
// 如果已过期或首次开通,从现在开始计算
expireAt = gtime.Now().Unix() + int64(req.Days*24*3600)
}
// 更新用户VIP信息
return dao.User.Update(ctx, req.UserId, g.Map{
"vip_level": req.VipLevel,
"vip_expire_time": int(expireAt),
})
}
// SearchUsers 搜索用户
func (s *UserService) SearchUsers(ctx context.Context, keyword string, page, pageSize int) ([]*entity.NlUser, int, error) {
if keyword == "" {
return nil, 0, errors.New("搜索关键词不能为空")
}
users, total, err := dao.User.SearchUsers(ctx, keyword, page, pageSize)
if err != nil {
return nil, 0, fmt.Errorf("搜索用户失败: %v", err)
}
// 清除敏感信息
for _, user := range users {
user.Password = ""
}
return users, total, nil
}
// GetVipUsers 获取VIP用户列表
func (s *UserService) GetVipUsers(ctx context.Context, page, pageSize int) ([]*entity.NlUser, int, error) {
users, total, err := dao.User.GetVipUsers(ctx, page, pageSize)
if err != nil {
return nil, 0, fmt.Errorf("查询VIP用户失败: %v", err)
}
// 清除敏感信息
for _, user := range users {
user.Password = ""
}
return users, total, nil
}
// GetExpiredVipUsers 获取VIP即将过期的用户
func (s *UserService) GetExpiredVipUsers(ctx context.Context, days int) ([]*entity.NlUser, error) {
users, err := dao.User.GetExpiredVipUsers(ctx, days)
if err != nil {
return nil, fmt.Errorf("查询即将过期VIP用户失败: %v", err)
}
// 清除敏感信息
for _, user := range users {
user.Password = ""
}
return users, nil
}
// UpdateLoginInfo 更新登录信息
func (s *UserService) UpdateLoginInfo(ctx context.Context, userId int, ip string) error {
return dao.User.UpdateLoginInfo(ctx, userId, ip)
}

View File

@@ -0,0 +1,410 @@
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"
"nl-video-api/internal/dao"
"nl-video-api/internal/model/entity"
"nl-video-api/utility/response"
)
// UserCollectService 用户收藏服务
type UserCollectService struct{}
// NewUserCollectService 创建用户收藏服务实例
func NewUserCollectService() *UserCollectService {
return &UserCollectService{}
}
// GetList 获取用户收藏列表
func (s *UserCollectService) GetList(r *ghttp.Request) {
// 获取请求参数
page := r.Get("page", 1).Int()
size := r.Get("size", 10).Int()
// 获取当前用户ID(临时设置)
userId := uint(1)
// 构建查询条件
query := dao.UserCollect.Ctx(r.Context()).Where("user_id", userId)
// 获取总数
total, err := query.Count()
if err != nil {
response.Error(r, response.CodeInternalError, "获取收藏总数失败")
return
}
// 获取列表数据
var collects []entity.UserCollect
err = query.Order("created_at DESC").
Limit((page-1)*size, size).
Scan(&collects)
if err != nil {
response.Error(r, response.CodeInternalError, "获取收藏列表失败")
return
}
response.Success(r, g.Map{
"list": collects,
"total": total,
"page": page,
"size": size,
})
}
// CheckCollect 检查是否已收藏
func (s *UserCollectService) CheckCollect(r *ghttp.Request) {
// 获取请求参数
movieId := r.Get("movie_id").Uint()
// 参数验证
if movieId == 0 {
response.Error(r, response.CodeInvalidParam, "电影ID不能为空")
return
}
// 获取当前用户ID(临时设置)
userId := uint(1)
// 检查是否已收藏
count, err := dao.UserCollect.Ctx(r.Context()).
Where("user_id", userId).
Where("movie_id", movieId).
Count()
if err != nil {
response.Error(r, response.CodeInternalError, "检查收藏状态失败")
return
}
response.Success(r, g.Map{
"is_collected": count > 0,
})
}
// 定义请求和响应结构体
type UserCollectAddReq struct {
MovieId uint `json:"movie_id"`
}
type UserCollectRemoveReq struct {
MovieId uint `json:"movie_id"`
}
type UserCollectListReq struct {
Page int `json:"page"`
Size int `json:"size"`
}
type UserCollectListRes struct {
List []UserCollectItem `json:"list"`
Total int `json:"total"`
Page int `json:"page"`
Size int `json:"size"`
}
type UserCollectItem struct {
Id uint `json:"id"`
MovieId uint `json:"movie_id"`
MovieName string `json:"movie_name"`
MovieCover string `json:"movie_cover"`
CreatedAt int64 `json:"created_at"`
}
type UserCollectCheckReq struct {
MovieId uint `json:"movie_id"`
}
type UserCollectCheckRes struct {
IsCollected bool `json:"is_collected"`
}
// Add 添加收藏
func (s *UserCollectService) Add(r *ghttp.Request) {
// 获取请求参数
movieId := r.Get("movie_id").Uint()
if movieId == 0 {
response.Error(r, response.CodeInvalidParam, "电影ID不能为空")
return
}
// 获取当前用户ID
userId := uint(1) // 临时设置,实际应该从JWT中获取
if userId == 0 {
response.Error(r, response.CodeUnauthorized, "用户未登录")
return
}
// 检查电影是否存在
var movie entity.Movie
err := g.DB().Model("movie").Where("id", movieId).Scan(&movie)
if err != nil {
response.Error(r, response.CodeInternalError, "系统错误")
return
}
if movie.Id == 0 {
response.Error(r, response.CodeNotFound, "电影不存在")
return
}
// 检查是否已经收藏
count, err := dao.UserCollect.Ctx(r.Context()).Where("user_id", userId).Where("movie_id", movieId).Count()
if err != nil {
response.Error(r, response.CodeInternalError, "系统错误")
return
}
if count > 0 {
response.Error(r, response.CodeInvalidParam, "已经收藏过该电影")
return
}
// 添加收藏
data := &entity.UserCollect{
UserId: int(userId),
MovieId: int(movieId),
Type: 1, // 影片收藏
TargetId: int(movieId),
CreatedAt: gtime.Now(),
}
id, err := dao.UserCollect.Ctx(r.Context()).Data(data).InsertAndGetId()
if err != nil {
response.Error(r, response.CodeInternalError, "添加收藏失败")
return
}
response.Success(r, g.Map{
"id": uint(id),
})
}
// Remove 取消收藏
func (s *UserCollectService) Remove(r *ghttp.Request) {
// 获取请求参数
movieId := r.Get("movie_id").Uint()
if movieId == 0 {
response.Error(r, response.CodeInvalidParam, "电影ID不能为空")
return
}
// 获取当前用户ID
userId := uint(1) // 临时设置,实际应该从JWT中获取
if userId == 0 {
response.Error(r, response.CodeUnauthorized, "用户未登录")
return
}
// 检查收藏是否存在
count, err := dao.UserCollect.Ctx(r.Context()).Where("user_id", userId).Where("movie_id", movieId).Count()
if err != nil {
response.Error(r, response.CodeInternalError, "系统错误")
return
}
if count == 0 {
response.Error(r, response.CodeNotFound, "收藏不存在")
return
}
// 删除收藏
_, err = dao.UserCollect.Ctx(r.Context()).Where("user_id", userId).Where("movie_id", movieId).Delete()
if err != nil {
response.Error(r, response.CodeInternalError, "取消收藏失败")
return
}
response.Success(r, "取消收藏成功")
}
// List 获取收藏列表
func (s *UserCollectService) List(ctx context.Context, req *UserCollectListReq) (*UserCollectListRes, error) {
// 设置默认值
if req.Page <= 0 {
req.Page = 1
}
if req.Size <= 0 {
req.Size = 10
}
// 获取当前用户ID
userId := uint(1) // 临时设置,实际应该从JWT中获取
if userId == 0 {
return nil, gerror.New("用户未登录")
}
// 构建查询条件
query := dao.UserCollect.Ctx(ctx).Where("user_id", userId)
// 获取总数
total, err := query.Count()
if err != nil {
return nil, gerror.New("获取收藏总数失败")
}
// 获取列表数据
var collects []entity.UserCollect
err = query.Order("id DESC").
Limit((req.Page-1)*req.Size, req.Size).
Scan(&collects)
if err != nil {
return nil, gerror.New("获取收藏列表失败")
}
// 获取电影信息
movieIds := make([]int, 0, len(collects))
for _, collect := range collects {
movieIds = append(movieIds, collect.MovieId)
}
movieMap := make(map[int]entity.Movie)
if len(movieIds) > 0 {
var movies []entity.Movie
g.DB().Model("movie").WhereIn("id", movieIds).Fields("id, name, cover").Scan(&movies)
for _, movie := range movies {
movieMap[int(movie.Id)] = movie
}
}
// 转换为响应格式
list := make([]UserCollectItem, 0, len(collects))
for _, collect := range collects {
movie := movieMap[collect.MovieId]
list = append(list, UserCollectItem{
Id: collect.Id,
MovieId: uint(collect.MovieId),
MovieName: movie.Title,
MovieCover: movie.Poster,
CreatedAt: collect.CreatedAt.Unix(),
})
}
return &UserCollectListRes{
List: list,
Total: total,
Page: req.Page,
Size: req.Size,
}, nil
}
// Check 检查是否收藏
func (s *UserCollectService) Check(ctx context.Context, req *UserCollectCheckReq) (*UserCollectCheckRes, error) {
// 获取当前用户ID
userId := uint(1) // 临时设置,实际应该从JWT中获取
if userId == 0 {
return nil, gerror.New("用户未登录")
}
// 检查是否收藏
count, err := dao.UserCollect.Ctx(ctx).Where("user_id", userId).Where("movie_id", req.MovieId).Count()
if err != nil {
return nil, gerror.New("检查收藏状态失败")
}
return &UserCollectCheckRes{
IsCollected: count > 0,
}, nil
}
// GetUserCollectCount 获取用户收藏数量
func (s *UserCollectService) GetUserCollectCount(ctx context.Context, userId uint) (int, error) {
count, err := dao.UserCollect.Ctx(ctx).Where("user_id", userId).Count()
if err != nil {
return 0, gerror.New("获取用户收藏数量失败")
}
return count, nil
}
// GetMovieCollectCount 获取电影收藏数量
func (s *UserCollectService) GetMovieCollectCount(ctx context.Context, movieId uint) (int, error) {
count, err := dao.UserCollect.Ctx(ctx).Where("movie_id", movieId).Count()
if err != nil {
return 0, gerror.New("获取电影收藏数量失败")
}
return count, nil
}
// BatchRemove 批量取消收藏
func (s *UserCollectService) BatchRemove(ctx context.Context, userId uint, movieIds []uint) error {
if len(movieIds) == 0 {
return gerror.New("请选择要取消收藏的电影")
}
_, err := dao.UserCollect.Ctx(ctx).Where("user_id", userId).WhereIn("movie_id", movieIds).Delete()
if err != nil {
return gerror.New("批量取消收藏失败")
}
return nil
}
// GetPopularMovies 获取热门收藏电影
func (s *UserCollectService) GetPopularMovies(ctx context.Context, limit int) ([]g.Map, error) {
if limit <= 0 {
limit = 10
}
var result []g.Map
err := dao.UserCollect.Ctx(ctx).
Fields("movie_id, COUNT(*) as collect_count").
Group("movie_id").
Order("collect_count DESC").
Limit(limit).
Scan(&result)
if err != nil {
return nil, gerror.New("获取热门收藏电影失败")
}
return result, nil
}
// GetRecentCollects 获取最近收藏
func (s *UserCollectService) GetRecentCollects(ctx context.Context, userId uint, limit int) ([]UserCollectItem, error) {
if limit <= 0 {
limit = 10
}
// 获取最近收藏
var collects []entity.UserCollect
err := dao.UserCollect.Ctx(ctx).
Where("user_id", userId).
Order("created_at DESC").
Limit(limit).
Scan(&collects)
if err != nil {
return nil, gerror.New("获取最近收藏失败")
}
// 获取电影信息
movieIds := make([]int, 0, len(collects))
for _, collect := range collects {
movieIds = append(movieIds, collect.MovieId)
}
movieMap := make(map[int]entity.Movie)
if len(movieIds) > 0 {
var movies []entity.Movie
g.DB().Model("movie").WhereIn("id", movieIds).Fields("id, name, cover").Scan(&movies)
for _, movie := range movies {
movieMap[int(movie.Id)] = movie
}
}
// 转换为响应格式
list := make([]UserCollectItem, 0, len(collects))
for _, collect := range collects {
movie := movieMap[collect.MovieId]
list = append(list, UserCollectItem{
Id: collect.Id,
MovieId: uint(collect.MovieId),
MovieName: movie.Title,
MovieCover: movie.Poster,
CreatedAt: collect.CreatedAt.Unix(),
})
}
return list, nil
}

View File

@@ -0,0 +1,357 @@
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)
}

View File

@@ -0,0 +1,598 @@
package service
import (
"strconv"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/net/ghttp"
"github.com/gogf/gf/v2/os/gtime"
"nl-video-api/internal/dao"
"nl-video-api/internal/model/entity"
"nl-video-api/utility/response"
)
// VipLevelService VIP等级服务
type VipLevelService struct{}
var VipLevel = &VipLevelService{}
// GetList 获取VIP等级列表
func (s *VipLevelService) GetList(r *ghttp.Request) {
// 获取请求参数
pageStr := r.Get("page", "1").String()
pageSizeStr := r.Get("page_size", "10").String()
page, err := strconv.Atoi(pageStr)
if err != nil || page < 1 {
page = 1
}
pageSize, err := strconv.Atoi(pageSizeStr)
if err != nil || pageSize < 1 {
pageSize = 10
}
// 获取总数
total, err := dao.VipLevel.Ctx(r.Context()).Count()
if err != nil {
response.Error(r, response.CodeInternalError, "获取VIP等级总数失败")
return
}
// 获取VIP等级列表
var vipLevels []*entity.VipLevel
err = dao.VipLevel.Ctx(r.Context()).
Page(page, pageSize).
OrderAsc("level").
Scan(&vipLevels)
if err != nil {
response.Error(r, response.CodeInternalError, "获取VIP等级列表失败")
return
}
// 构建返回数据
var vipLevelItems []g.Map
for _, vipLevel := range vipLevels {
vipLevelItems = append(vipLevelItems, g.Map{
"id": vipLevel.Id,
"name": vipLevel.Name,
"level": vipLevel.Level,
"price": vipLevel.Price,
"duration": vipLevel.Duration,
"description": vipLevel.Description,
"privileges": vipLevel.Privileges,
"status": vipLevel.Status,
"created_at": vipLevel.CreatedAt.Unix(),
"updated_at": vipLevel.UpdatedAt.Unix(),
})
}
response.Success(r, g.Map{
"list": vipLevelItems,
"total": total,
"page": page,
"page_size": pageSize,
})
}
// GetDetail 获取VIP等级详情
func (s *VipLevelService) GetDetail(r *ghttp.Request) {
// 获取请求参数
idStr := r.Get("id").String()
if idStr == "" {
response.Error(r, response.CodeInvalidParam, "VIP等级ID不能为空")
return
}
id, err := strconv.Atoi(idStr)
if err != nil {
response.Error(r, response.CodeInvalidParam, "VIP等级ID格式错误")
return
}
// 获取VIP等级详情
var vipLevel entity.VipLevel
err = dao.VipLevel.Ctx(r.Context()).Where("id", id).Scan(&vipLevel)
if err != nil {
response.Error(r, response.CodeInternalError, "获取VIP等级详情失败")
return
}
if vipLevel.Id == 0 {
response.Error(r, response.CodeNotFound, "VIP等级不存在")
return
}
response.Success(r, g.Map{
"id": vipLevel.Id,
"name": vipLevel.Name,
"level": vipLevel.Level,
"price": vipLevel.Price,
"duration": vipLevel.Duration,
"description": vipLevel.Description,
"privileges": vipLevel.Privileges,
"status": vipLevel.Status,
"created_at": vipLevel.CreatedAt.Unix(),
"updated_at": vipLevel.UpdatedAt.Unix(),
})
}
// AdminGetList 管理员获取VIP等级列表
func (s *VipLevelService) AdminGetList(r *ghttp.Request) {
// 获取请求参数
keyword := r.Get("keyword").String()
statusStr := r.Get("status").String()
pageStr := r.Get("page", "1").String()
pageSizeStr := r.Get("page_size", "10").String()
page, err := strconv.Atoi(pageStr)
if err != nil || page < 1 {
page = 1
}
pageSize, err := strconv.Atoi(pageSizeStr)
if err != nil || pageSize < 1 {
pageSize = 10
}
// 构建查询条件
query := dao.VipLevel.Ctx(r.Context())
if keyword != "" {
query = query.Where("name LIKE ?", "%"+keyword+"%")
}
if statusStr != "" {
status, err := strconv.Atoi(statusStr)
if err == nil {
query = query.Where("status", status)
}
}
// 获取总数
total, err := query.Count()
if err != nil {
response.Error(r, response.CodeInternalError, "获取VIP等级总数失败")
return
}
// 获取VIP等级列表
var vipLevels []*entity.VipLevel
err = query.Page(page, pageSize).OrderAsc("level").Scan(&vipLevels)
if err != nil {
response.Error(r, response.CodeInternalError, "获取VIP等级列表失败")
return
}
// 构建返回数据
var vipLevelItems []g.Map
for _, vipLevel := range vipLevels {
vipLevelItems = append(vipLevelItems, g.Map{
"id": vipLevel.Id,
"name": vipLevel.Name,
"level": vipLevel.Level,
"price": vipLevel.Price,
"duration": vipLevel.Duration,
"description": vipLevel.Description,
"privileges": vipLevel.Privileges,
"status": vipLevel.Status,
"created_at": vipLevel.CreatedAt.Unix(),
"updated_at": vipLevel.UpdatedAt.Unix(),
})
}
response.Success(r, g.Map{
"list": vipLevelItems,
"total": total,
"page": page,
"page_size": pageSize,
})
}
// AdminCreate 管理员创建VIP等级
func (s *VipLevelService) AdminCreate(r *ghttp.Request) {
// 获取请求参数
name := r.Get("name").String()
levelStr := r.Get("level").String()
priceStr := r.Get("price").String()
durationStr := r.Get("duration").String()
description := r.Get("description").String()
privileges := r.Get("privileges").String()
statusStr := r.Get("status", "1").String()
if name == "" {
response.Error(r, response.CodeInvalidParam, "VIP等级名称不能为空")
return
}
level, err := strconv.Atoi(levelStr)
if err != nil {
response.Error(r, response.CodeInvalidParam, "VIP等级格式错误")
return
}
price, err := strconv.ParseFloat(priceStr, 64)
if err != nil {
response.Error(r, response.CodeInvalidParam, "价格格式错误")
return
}
duration, err := strconv.Atoi(durationStr)
if err != nil {
response.Error(r, response.CodeInvalidParam, "有效期格式错误")
return
}
status, err := strconv.Atoi(statusStr)
if err != nil {
status = 1
}
// 检查等级是否已存在
count, err := dao.VipLevel.Ctx(r.Context()).Where("level", level).Count()
if err != nil {
response.Error(r, response.CodeInternalError, "系统错误")
return
}
if count > 0 {
response.Error(r, response.CodeInvalidParam, "该等级已存在")
return
}
// 创建VIP等级
_, err = dao.VipLevel.Ctx(r.Context()).Data(g.Map{
"name": name,
"level": level,
"price": price,
"duration": duration,
"description": description,
"privileges": privileges,
"status": status,
"created_at": gtime.Now(),
"updated_at": gtime.Now(),
}).Insert()
if err != nil {
response.Error(r, response.CodeInternalError, "创建VIP等级失败")
return
}
response.Success(r, "创建成功")
}
// AdminUpdate 管理员更新VIP等级
func (s *VipLevelService) AdminUpdate(r *ghttp.Request) {
// 获取请求参数
idStr := r.Get("id").String()
name := r.Get("name").String()
levelStr := r.Get("level").String()
priceStr := r.Get("price").String()
durationStr := r.Get("duration").String()
description := r.Get("description").String()
privileges := r.Get("privileges").String()
statusStr := r.Get("status").String()
if idStr == "" {
response.Error(r, response.CodeInvalidParam, "VIP等级ID不能为空")
return
}
id, err := strconv.Atoi(idStr)
if err != nil {
response.Error(r, response.CodeInvalidParam, "VIP等级ID格式错误")
return
}
// 检查VIP等级是否存在
var existVipLevel entity.VipLevel
err = dao.VipLevel.Ctx(r.Context()).Where("id", id).Scan(&existVipLevel)
if err != nil {
response.Error(r, response.CodeInternalError, "系统错误")
return
}
if existVipLevel.Id == 0 {
response.Error(r, response.CodeNotFound, "VIP等级不存在")
return
}
// 构建更新数据
updateData := g.Map{
"updated_at": gtime.Now(),
}
if name != "" {
updateData["name"] = name
}
if levelStr != "" {
level, err := strconv.Atoi(levelStr)
if err != nil {
response.Error(r, response.CodeInvalidParam, "VIP等级格式错误")
return
}
// 检查等级是否已被其他记录使用
count, err := dao.VipLevel.Ctx(r.Context()).Where("level", level).Where("id !=", id).Count()
if err != nil {
response.Error(r, response.CodeInternalError, "系统错误")
return
}
if count > 0 {
response.Error(r, response.CodeInvalidParam, "该等级已存在")
return
}
updateData["level"] = level
}
if priceStr != "" {
price, err := strconv.ParseFloat(priceStr, 64)
if err != nil {
response.Error(r, response.CodeInvalidParam, "价格格式错误")
return
}
updateData["price"] = price
}
if durationStr != "" {
duration, err := strconv.Atoi(durationStr)
if err != nil {
response.Error(r, response.CodeInvalidParam, "有效期格式错误")
return
}
updateData["duration"] = duration
}
if description != "" {
updateData["description"] = description
}
if privileges != "" {
updateData["privileges"] = privileges
}
if statusStr != "" {
status, err := strconv.Atoi(statusStr)
if err != nil {
response.Error(r, response.CodeInvalidParam, "状态格式错误")
return
}
updateData["status"] = status
}
// 更新VIP等级
_, err = dao.VipLevel.Ctx(r.Context()).Where("id", id).Data(updateData).Update()
if err != nil {
response.Error(r, response.CodeInternalError, "更新VIP等级失败")
return
}
response.Success(r, "更新成功")
}
// AdminDelete 管理员删除VIP等级
func (s *VipLevelService) AdminDelete(r *ghttp.Request) {
// 获取请求参数
idStr := r.Get("id").String()
if idStr == "" {
response.Error(r, response.CodeInvalidParam, "VIP等级ID不能为空")
return
}
id, err := strconv.Atoi(idStr)
if err != nil {
response.Error(r, response.CodeInvalidParam, "VIP等级ID格式错误")
return
}
// 检查VIP等级是否存在
count, err := dao.VipLevel.Ctx(r.Context()).Where("id", id).Count()
if err != nil {
response.Error(r, response.CodeInternalError, "系统错误")
return
}
if count == 0 {
response.Error(r, response.CodeNotFound, "VIP等级不存在")
return
}
// 检查是否有用户正在使用该VIP等级
userCount, err := g.DB().Model("nl_user").Where("vip_level", id).Count()
if err != nil {
response.Error(r, response.CodeInternalError, "系统错误")
return
}
if userCount > 0 {
response.Error(r, response.CodeInvalidParam, "该VIP等级正在被用户使用,无法删除")
return
}
// 删除VIP等级
_, err = dao.VipLevel.Ctx(r.Context()).Where("id", id).Delete()
if err != nil {
response.Error(r, response.CodeInternalError, "删除VIP等级失败")
return
}
response.Success(r, "删除成功")
}
// AdminBatchDelete 管理员批量删除VIP等级
func (s *VipLevelService) AdminBatchDelete(r *ghttp.Request) {
// 获取请求参数
var ids []int
err := r.Parse(&ids)
if err != nil {
response.Error(r, response.CodeInvalidParam, "参数格式错误")
return
}
if len(ids) == 0 {
response.Error(r, response.CodeInvalidParam, "请选择要删除的VIP等级")
return
}
// 检查是否有用户正在使用这些VIP等级
userCount, err := g.DB().Model("nl_user").WhereIn("vip_level", ids).Count()
if err != nil {
response.Error(r, response.CodeInternalError, "系统错误")
return
}
if userCount > 0 {
response.Error(r, response.CodeInvalidParam, "选中的VIP等级中有正在被用户使用的,无法删除")
return
}
// 批量删除
_, err = dao.VipLevel.Ctx(r.Context()).WhereIn("id", ids).Delete()
if err != nil {
response.Error(r, response.CodeInternalError, "批量删除失败")
return
}
response.Success(r, "删除成功")
}
// AdminUpdateStatus 管理员更新VIP等级状态
func (s *VipLevelService) AdminUpdateStatus(r *ghttp.Request) {
// 获取请求参数
idStr := r.Get("id").String()
statusStr := r.Get("status").String()
if idStr == "" {
response.Error(r, response.CodeInvalidParam, "VIP等级ID不能为空")
return
}
if statusStr == "" {
response.Error(r, response.CodeInvalidParam, "状态不能为空")
return
}
id, err := strconv.Atoi(idStr)
if err != nil {
response.Error(r, response.CodeInvalidParam, "VIP等级ID格式错误")
return
}
status, err := strconv.Atoi(statusStr)
if err != nil {
response.Error(r, response.CodeInvalidParam, "状态格式错误")
return
}
// 检查VIP等级是否存在
count, err := dao.VipLevel.Ctx(r.Context()).Where("id", id).Count()
if err != nil {
response.Error(r, response.CodeInternalError, "系统错误")
return
}
if count == 0 {
response.Error(r, response.CodeNotFound, "VIP等级不存在")
return
}
// 更新状态
_, err = dao.VipLevel.Ctx(r.Context()).Where("id", id).Data(g.Map{
"status": status,
"updated_at": gtime.Now(),
}).Update()
if err != nil {
response.Error(r, response.CodeInternalError, "更新状态失败")
return
}
response.Success(r, "更新成功")
}
// GetActiveList 获取启用的VIP等级列表
func (s *VipLevelService) GetActiveList(r *ghttp.Request) {
// 获取启用的VIP等级列表
var vipLevels []*entity.VipLevel
err := dao.VipLevel.Ctx(r.Context()).
Where("status", 1).
OrderAsc("level").
Scan(&vipLevels)
if err != nil {
response.Error(r, response.CodeInternalError, "获取VIP等级列表失败")
return
}
// 构建返回数据
var vipLevelItems []g.Map
for _, vipLevel := range vipLevels {
vipLevelItems = append(vipLevelItems, g.Map{
"id": vipLevel.Id,
"name": vipLevel.Name,
"level": vipLevel.Level,
"price": vipLevel.Price,
"duration": vipLevel.Duration,
"description": vipLevel.Description,
"privileges": vipLevel.Privileges,
})
}
response.Success(r, vipLevelItems)
}
// GetUserVipInfo 获取用户VIP信息
func (s *VipLevelService) GetUserVipInfo(r *ghttp.Request) {
// 从上下文获取用户ID
userIdValue := r.Context().Value("user_id")
if userIdValue == nil {
response.Error(r, response.CodeUnauthorized, "请先登录")
return
}
userId := userIdValue.(uint)
// 获取用户信息
var user entity.NlUser
err := g.DB().Model("nl_user").Where("id", userId).Scan(&user)
if err != nil {
response.Error(r, response.CodeInternalError, "获取用户信息失败")
return
}
if user.Id == 0 {
response.Error(r, response.CodeNotFound, "用户不存在")
return
}
// 获取VIP等级信息
var vipLevel entity.VipLevel
if user.VipLevel > 0 {
dao.VipLevel.Ctx(r.Context()).Where("id", user.VipLevel).Scan(&vipLevel)
}
response.Success(r, g.Map{
"user_id": user.Id,
"vip_level_id": user.VipLevel,
"vip_level_name": vipLevel.Name,
"vip_expire_at": user.VipExpireTime,
"is_vip": user.VipLevel > 0 && user.VipExpireTime > int(gtime.Now().Unix()),
})
}
// GetAll 获取所有VIP等级
func (s *VipLevelService) GetAll(r *ghttp.Request) {
// 获取所有VIP等级列表
var vipLevels []*entity.VipLevel
err := dao.VipLevel.Ctx(r.Context()).
OrderAsc("level").
Scan(&vipLevels)
if err != nil {
response.Error(r, response.CodeInternalError, "获取VIP等级列表失败")
return
}
// 构建返回数据
var vipLevelItems []g.Map
for _, vipLevel := range vipLevels {
vipLevelItems = append(vipLevelItems, g.Map{
"id": vipLevel.Id,
"name": vipLevel.Name,
"level": vipLevel.Level,
"price": vipLevel.Price,
"duration": vipLevel.Duration,
"description": vipLevel.Description,
"privileges": vipLevel.Privileges,
"status": vipLevel.Status,
"created_at": vipLevel.CreatedAt.Unix(),
"updated_at": vipLevel.UpdatedAt.Unix(),
})
}
response.Success(r, vipLevelItems)
}