初始化v1
This commit is contained in:
0
internal/service/.gitkeep
Normal file
0
internal/service/.gitkeep
Normal file
1213
internal/service/attachment.go
Normal file
1213
internal/service/attachment.go
Normal file
File diff suppressed because it is too large
Load Diff
234
internal/service/auth/permission.go
Normal file
234
internal/service/auth/permission.go
Normal 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
|
||||
}
|
||||
328
internal/service/auth/role.go
Normal file
328
internal/service/auth/role.go
Normal 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
411
internal/service/banner.go
Normal 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
428
internal/service/comment.go
Normal 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
391
internal/service/config.go
Normal 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
591
internal/service/log.go
Normal 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,
|
||||
})
|
||||
}
|
||||
602
internal/service/movie/episode.go
Normal file
602
internal/service/movie/episode.go
Normal 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
|
||||
}
|
||||
325
internal/service/movie/movie.go
Normal file
325
internal/service/movie/movie.go
Normal 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
|
||||
}
|
||||
812
internal/service/payment_order.go
Normal file
812
internal/service/payment_order.go
Normal 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)
|
||||
}
|
||||
11
internal/service/service.go
Normal file
11
internal/service/service.go
Normal file
@@ -0,0 +1,11 @@
|
||||
package service
|
||||
|
||||
// 导出所有服务实例,供controller层使用
|
||||
var (
|
||||
Banner = NewBannerService()
|
||||
Comment = NewCommentService()
|
||||
PaymentOrder = NewPaymentOrderService()
|
||||
Attachment = NewAttachmentService()
|
||||
UserCollect = NewUserCollectService()
|
||||
UserWatchHistory = NewUserWatchHistoryService()
|
||||
)
|
||||
390
internal/service/user/user.go
Normal file
390
internal/service/user/user.go
Normal 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)
|
||||
}
|
||||
410
internal/service/user_collect.go
Normal file
410
internal/service/user_collect.go
Normal 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
|
||||
}
|
||||
357
internal/service/user_watch_history.go
Normal file
357
internal/service/user_watch_history.go
Normal 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)
|
||||
}
|
||||
|
||||
598
internal/service/vip_level.go
Normal file
598
internal/service/vip_level.go
Normal 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)
|
||||
}
|
||||
Reference in New Issue
Block a user