初始化v1
This commit is contained in:
131
internal/cmd/cmd.go
Normal file
131
internal/cmd/cmd.go
Normal file
@@ -0,0 +1,131 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/net/ghttp"
|
||||
"github.com/gogf/gf/v2/os/gcmd"
|
||||
|
||||
"nl-video-api/internal/controller/admin"
|
||||
"nl-video-api/internal/controller/user"
|
||||
"nl-video-api/api/middleware"
|
||||
"nl-video-api/api/v1"
|
||||
)
|
||||
|
||||
var (
|
||||
Main = gcmd.Command{
|
||||
Name: "main",
|
||||
Usage: "main",
|
||||
Brief: "start http server",
|
||||
Func: func(ctx context.Context, parser *gcmd.Parser) (err error) {
|
||||
// 初始化日志配置
|
||||
g.Log().Info(ctx, "开始初始化日志系统...")
|
||||
|
||||
s := g.Server()
|
||||
|
||||
// 设置静态文件服务
|
||||
s.SetServerRoot("resource/public")
|
||||
s.AddStaticPath("/uploads", "resource/public/uploads")
|
||||
|
||||
// 记录服务器启动日志
|
||||
g.Log().Info(ctx, "服务器配置初始化完成")
|
||||
|
||||
// 注册中间件
|
||||
s.Use(middleware.CORS)
|
||||
s.Use(middleware.ErrorHandler) // 错误处理中间件
|
||||
s.Use(middleware.ResponseHandler) // 响应处理中间件
|
||||
|
||||
// 注册路由
|
||||
s.Group("/api/v1", func(group *ghttp.RouterGroup) {
|
||||
// === 用户端路由 ===
|
||||
|
||||
// 用户认证路由(无需认证)
|
||||
group.Group("/auth", func(authGroup *ghttp.RouterGroup) {
|
||||
v1.AuthGroup(authGroup)
|
||||
})
|
||||
|
||||
// 影片管理路由
|
||||
v1.MovieGroup(group)
|
||||
|
||||
// 用户收藏路由
|
||||
v1.UserCollectGroup(group)
|
||||
|
||||
// 用户观看历史路由
|
||||
v1.UserWatchHistoryGroup(group)
|
||||
|
||||
// 轮播图路由
|
||||
group.Group("/banner", func(bannerGroup *ghttp.RouterGroup) {
|
||||
bannerGroup.GET("/list", user.Banner.GetList)
|
||||
})
|
||||
|
||||
// 支付订单路由
|
||||
group.Group("/payment", func(paymentGroup *ghttp.RouterGroup) {
|
||||
paymentGroup.POST("/create", user.PaymentOrder.Create)
|
||||
paymentGroup.GET("/list", user.PaymentOrder.GetList)
|
||||
paymentGroup.GET("/{id}", user.PaymentOrder.GetDetail)
|
||||
})
|
||||
|
||||
// VIP等级路由
|
||||
group.Group("/vip", func(vipGroup *ghttp.RouterGroup) {
|
||||
vipGroup.GET("/levels", user.VipLevel.GetList)
|
||||
vipGroup.GET("/my", user.VipLevel.GetDetail)
|
||||
})
|
||||
|
||||
// 附件管理路由
|
||||
group.Group("/attachment", func(attachmentGroup *ghttp.RouterGroup) {
|
||||
attachmentGroup.POST("/upload", user.NewAttachmentController().Upload)
|
||||
attachmentGroup.GET("/list", user.NewAttachmentController().GetList)
|
||||
})
|
||||
|
||||
// 系统配置路由
|
||||
group.Group("/config", func(configGroup *ghttp.RouterGroup) {
|
||||
configGroup.GET("/public", user.Config.GetList)
|
||||
})
|
||||
|
||||
// 日志管理路由
|
||||
group.Group("/log", func(logGroup *ghttp.RouterGroup) {
|
||||
logGroup.GET("/my", user.Log.GetList)
|
||||
})
|
||||
|
||||
// === 管理员端路由 ===
|
||||
|
||||
// 管理员认证路由(无需认证)
|
||||
group.Group("/admin", func(adminGroup *ghttp.RouterGroup) {
|
||||
// 管理员基础认证接口
|
||||
adminController := &admin.AdminController{}
|
||||
adminGroup.POST("/login", adminController.Login)
|
||||
adminGroup.POST("/register", adminController.Register)
|
||||
adminGroup.GET("/profile", adminController.Profile)
|
||||
adminGroup.POST("/profile", adminController.UpdateProfile)
|
||||
adminGroup.POST("/logout", adminController.Logout)
|
||||
adminGroup.POST("/refresh", adminController.RefreshToken)
|
||||
|
||||
// 管理员业务功能路由
|
||||
v1.AdminGroup(adminGroup)
|
||||
})
|
||||
})
|
||||
|
||||
s.Run()
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
// InitDB 数据库初始化命令
|
||||
InitDB = gcmd.Command{
|
||||
Name: "init-db",
|
||||
Usage: "init-db",
|
||||
Brief: "initialize database",
|
||||
Func: func(ctx context.Context, parser *gcmd.Parser) (err error) {
|
||||
g.Log().Info(ctx, "开始初始化数据库...")
|
||||
|
||||
if err := InitDatabase(ctx); err != nil {
|
||||
g.Log().Errorf(ctx, "数据库初始化失败: %v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
g.Log().Info(ctx, "数据库初始化完成!")
|
||||
return nil
|
||||
},
|
||||
}
|
||||
)
|
||||
254
internal/cmd/init_db.go
Normal file
254
internal/cmd/init_db.go
Normal file
@@ -0,0 +1,254 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"strings"
|
||||
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/os/gfile"
|
||||
"github.com/gogf/gf/v2/os/gtime"
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
)
|
||||
|
||||
// InitDatabase 初始化数据库
|
||||
func InitDatabase(ctx context.Context) error {
|
||||
db := g.DB()
|
||||
|
||||
// 检查数据库连接
|
||||
if err := db.PingMaster(); err != nil {
|
||||
return fmt.Errorf("数据库连接失败: %v", err)
|
||||
}
|
||||
|
||||
g.Log().Info(ctx, "数据库连接成功,开始初始化数据库...")
|
||||
|
||||
// 读取SQL文件
|
||||
sqlFile := "nl_video_database.sql"
|
||||
if !gfile.Exists(sqlFile) {
|
||||
return fmt.Errorf("SQL文件不存在: %s", sqlFile)
|
||||
}
|
||||
|
||||
sqlContent, err := ioutil.ReadFile(sqlFile)
|
||||
if err != nil {
|
||||
return fmt.Errorf("读取SQL文件失败: %v", err)
|
||||
}
|
||||
|
||||
// 分割SQL语句
|
||||
sqlStatements := strings.Split(string(sqlContent), ";")
|
||||
|
||||
// 执行SQL语句
|
||||
for i, statement := range sqlStatements {
|
||||
statement = strings.TrimSpace(statement)
|
||||
if statement == "" || strings.HasPrefix(statement, "--") || strings.HasPrefix(statement, "/*") {
|
||||
continue
|
||||
}
|
||||
|
||||
g.Log().Infof(ctx, "执行SQL语句 %d/%d", i+1, len(sqlStatements))
|
||||
|
||||
if _, err := db.Exec(ctx, statement); err != nil {
|
||||
// 如果是表已存在的错误,跳过
|
||||
if strings.Contains(err.Error(), "already exists") {
|
||||
g.Log().Warning(ctx, "表已存在,跳过创建:", statement[:50])
|
||||
continue
|
||||
}
|
||||
return fmt.Errorf("执行SQL失败: %v, SQL: %s", err, statement[:100])
|
||||
}
|
||||
}
|
||||
|
||||
// 初始化基础数据
|
||||
if err := initBaseData(ctx); err != nil {
|
||||
return fmt.Errorf("初始化基础数据失败: %v", err)
|
||||
}
|
||||
|
||||
g.Log().Info(ctx, "数据库初始化完成!")
|
||||
return nil
|
||||
}
|
||||
|
||||
// initBaseData 初始化基础数据
|
||||
func initBaseData(ctx context.Context) error {
|
||||
db := g.DB()
|
||||
|
||||
// 检查是否已有管理员数据
|
||||
count, err := db.Model("nl_admin").Count()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if count > 0 {
|
||||
g.Log().Info(ctx, "管理员数据已存在,跳过初始化")
|
||||
return nil
|
||||
}
|
||||
|
||||
// 创建默认超级管理员
|
||||
hashedPassword, err := bcrypt.GenerateFromPassword([]byte("admin123"), bcrypt.DefaultCost)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 插入超级管理员角色
|
||||
roleResult, err := db.Model("nl_role").Data(g.Map{
|
||||
"name": "超级管理员",
|
||||
"code": "super_admin",
|
||||
"level": 1,
|
||||
"is_system": 1,
|
||||
"description": "系统超级管理员,拥有所有权限",
|
||||
"status": 1,
|
||||
"created_at": gtime.Now(),
|
||||
"updated_at": gtime.Now(),
|
||||
}).Insert()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
roleId, err := roleResult.LastInsertId()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 插入超级管理员账号
|
||||
_, err = db.Model("nl_admin").Data(g.Map{
|
||||
"username": "admin",
|
||||
"password": string(hashedPassword),
|
||||
"email": "admin@nlvideo.com",
|
||||
"real_name": "系统管理员",
|
||||
"nickname": "超级管理员",
|
||||
"role_id": roleId,
|
||||
"status": 1,
|
||||
"created_at": gtime.Now(),
|
||||
"updated_at": gtime.Now(),
|
||||
}).Insert()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 初始化基础权限
|
||||
if err := initPermissions(ctx, roleId); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 初始化影片分类
|
||||
if err := initCategories(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 初始化VIP等级
|
||||
if err := initVipLevels(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
g.Log().Info(ctx, "基础数据初始化完成")
|
||||
g.Log().Info(ctx, "默认管理员账号: admin")
|
||||
g.Log().Info(ctx, "默认管理员密码: admin123")
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// initPermissions 初始化权限数据
|
||||
func initPermissions(ctx context.Context, roleId int64) error {
|
||||
db := g.DB()
|
||||
|
||||
permissions := []g.Map{
|
||||
{
|
||||
"name": "系统管理", "code": "system", "type": "menu", "parent_id": 0,
|
||||
"path": "/system", "component": "Layout", "icon": "system",
|
||||
"sort": 1, "status": 1, "created_at": gtime.Now(), "updated_at": gtime.Now(),
|
||||
},
|
||||
{
|
||||
"name": "用户管理", "code": "user", "type": "menu", "parent_id": 0,
|
||||
"path": "/user", "component": "Layout", "icon": "user",
|
||||
"sort": 2, "status": 1, "created_at": gtime.Now(), "updated_at": gtime.Now(),
|
||||
},
|
||||
{
|
||||
"name": "影片管理", "code": "movie", "type": "menu", "parent_id": 0,
|
||||
"path": "/movie", "component": "Layout", "icon": "movie",
|
||||
"sort": 3, "status": 1, "created_at": gtime.Now(), "updated_at": gtime.Now(),
|
||||
},
|
||||
{
|
||||
"name": "权限管理", "code": "permission", "type": "menu", "parent_id": 0,
|
||||
"path": "/permission", "component": "Layout", "icon": "permission",
|
||||
"sort": 4, "status": 1, "created_at": gtime.Now(), "updated_at": gtime.Now(),
|
||||
},
|
||||
}
|
||||
|
||||
for _, perm := range permissions {
|
||||
result, err := db.Model("nl_permission").Data(perm).Insert()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
permId, err := result.LastInsertId()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 给超级管理员分配权限
|
||||
_, err = db.Model("nl_role_permission").Data(g.Map{
|
||||
"role_id": roleId,
|
||||
"permission_id": permId,
|
||||
"created_at": gtime.Now(),
|
||||
}).Insert()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// initCategories 初始化影片分类
|
||||
func initCategories(ctx context.Context) error {
|
||||
db := g.DB()
|
||||
|
||||
categories := []g.Map{
|
||||
{"name": "电影", "code": "movie", "parent_id": 0, "sort": 1, "status": 1, "created_at": gtime.Now(), "updated_at": gtime.Now()},
|
||||
{"name": "电视剧", "code": "tv", "parent_id": 0, "sort": 2, "status": 1, "created_at": gtime.Now(), "updated_at": gtime.Now()},
|
||||
{"name": "综艺", "code": "variety", "parent_id": 0, "sort": 3, "status": 1, "created_at": gtime.Now(), "updated_at": gtime.Now()},
|
||||
{"name": "动漫", "code": "anime", "parent_id": 0, "sort": 4, "status": 1, "created_at": gtime.Now(), "updated_at": gtime.Now()},
|
||||
{"name": "纪录片", "code": "documentary", "parent_id": 0, "sort": 5, "status": 1, "created_at": gtime.Now(), "updated_at": gtime.Now()},
|
||||
}
|
||||
|
||||
for _, category := range categories {
|
||||
_, err := db.Model("nl_category").Data(category).Insert()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// initVipLevels 初始化VIP等级
|
||||
func initVipLevels(ctx context.Context) error {
|
||||
db := g.DB()
|
||||
|
||||
vipLevels := []g.Map{
|
||||
{
|
||||
"name": "普通用户", "level": 0, "price": 0, "duration": 0,
|
||||
"description": "免费用户,可观看部分免费内容",
|
||||
"privileges": `{"free_content": true, "hd_quality": false, "download": false}`,
|
||||
"status": 1, "created_at": gtime.Now(), "updated_at": gtime.Now(),
|
||||
},
|
||||
{
|
||||
"name": "月度VIP", "level": 1, "price": 1500, "duration": 30,
|
||||
"description": "月度会员,享受高清观看和下载权限",
|
||||
"privileges": `{"free_content": true, "hd_quality": true, "download": true, "ad_free": true}`,
|
||||
"status": 1, "created_at": gtime.Now(), "updated_at": gtime.Now(),
|
||||
},
|
||||
{
|
||||
"name": "年度VIP", "level": 2, "price": 15000, "duration": 365,
|
||||
"description": "年度会员,享受所有内容和特权",
|
||||
"privileges": `{"free_content": true, "hd_quality": true, "download": true, "ad_free": true, "exclusive_content": true}`,
|
||||
"status": 1, "created_at": gtime.Now(), "updated_at": gtime.Now(),
|
||||
},
|
||||
}
|
||||
|
||||
for _, vip := range vipLevels {
|
||||
_, err := db.Model("nl_vip_level").Data(vip).Insert()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
65
internal/consts/consts.go
Normal file
65
internal/consts/consts.go
Normal file
@@ -0,0 +1,65 @@
|
||||
package consts
|
||||
|
||||
// 用户类型
|
||||
const (
|
||||
UserTypeUser = "user" // 普通用户
|
||||
UserTypeAdmin = "admin" // 管理员
|
||||
)
|
||||
|
||||
// 用户状态
|
||||
const (
|
||||
UserStatusNormal = 1 // 正常
|
||||
UserStatusDisable = 2 // 禁用
|
||||
)
|
||||
|
||||
// VIP等级
|
||||
const (
|
||||
VipLevelNormal = 1 // 普通用户
|
||||
VipLevelGold = 2 // 黄金VIP
|
||||
VipLevelPlatinum = 3 // 铂金VIP
|
||||
VipLevelDiamond = 4 // 钻石VIP
|
||||
)
|
||||
|
||||
// 影片状态
|
||||
const (
|
||||
MovieStatusDraft = 1 // 草稿
|
||||
MovieStatusPublished = 2 // 已发布
|
||||
MovieStatusOffline = 3 // 已下线
|
||||
)
|
||||
|
||||
// 订单状态
|
||||
const (
|
||||
OrderStatusPending = 1 // 待支付
|
||||
OrderStatusPaid = 2 // 已支付
|
||||
OrderStatusCancelled = 3 // 已取消
|
||||
OrderStatusRefunded = 4 // 已退款
|
||||
)
|
||||
|
||||
// 支付方式
|
||||
const (
|
||||
PaymentTypeAlipay = "alipay" // 支付宝
|
||||
PaymentTypeWechat = "wechat" // 微信支付
|
||||
)
|
||||
|
||||
// 文件类型
|
||||
const (
|
||||
FileTypeImage = "image" // 图片
|
||||
FileTypeVideo = "video" // 视频
|
||||
FileTypeOther = "other" // 其他
|
||||
)
|
||||
|
||||
// 缓存键前缀
|
||||
const (
|
||||
CacheKeyUserInfo = "user:info:"
|
||||
CacheKeyMovieInfo = "movie:info:"
|
||||
CacheKeyMovieList = "movie:list:"
|
||||
CacheKeyConfig = "config:"
|
||||
CacheKeyStatistics = "statistics:"
|
||||
)
|
||||
|
||||
// 默认分页参数
|
||||
const (
|
||||
DefaultPage = 1
|
||||
DefaultPageSize = 20
|
||||
MaxPageSize = 100
|
||||
)
|
||||
370
internal/controller/admin/admin.go
Normal file
370
internal/controller/admin/admin.go
Normal file
@@ -0,0 +1,370 @@
|
||||
package admin
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/net/ghttp"
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
|
||||
"nl-video-api/internal/model/entity"
|
||||
"nl-video-api/utility/crypto"
|
||||
"nl-video-api/utility/jwt"
|
||||
"nl-video-api/utility/response"
|
||||
)
|
||||
|
||||
type AdminController struct{}
|
||||
|
||||
// AdminLoginReq 管理员登录请求
|
||||
type AdminLoginReq struct {
|
||||
Username string `json:"username" v:"required|length:3,20#用户名不能为空|用户名长度为3-20位"`
|
||||
Password string `json:"password" v:"required|length:6,20#密码不能为空|密码长度为6-20位"`
|
||||
}
|
||||
|
||||
// AdminLoginRes 管理员登录响应
|
||||
type AdminLoginRes struct {
|
||||
Token string `json:"token"`
|
||||
AdminInfo *entity.NlAdmin `json:"admin_info"`
|
||||
}
|
||||
|
||||
// AdminRegisterReq 管理员注册请求
|
||||
type AdminRegisterReq struct {
|
||||
Username string `json:"username" v:"required|length:3,20#用户名不能为空|用户名长度为3-20位"`
|
||||
Password string `json:"password" v:"required|length:6,20#密码不能为空|密码长度为6-20位"`
|
||||
Email string `json:"email" v:"required|email#邮箱不能为空|邮箱格式不正确"`
|
||||
RealName string `json:"real_name" v:"required|length:2,10#真实姓名不能为空|真实姓名长度为2-10位"`
|
||||
}
|
||||
|
||||
// AdminProfileRes 管理员信息响应
|
||||
type AdminProfileRes struct {
|
||||
AdminInfo *entity.NlAdmin `json:"admin_info"`
|
||||
}
|
||||
|
||||
// AdminUpdateReq 更新管理员信息请求
|
||||
type AdminUpdateReq struct {
|
||||
Email string `json:"email" v:"email#邮箱格式不正确"`
|
||||
RealName string `json:"real_name" v:"length:2,10#真实姓名长度为2-10位"`
|
||||
Avatar string `json:"avatar" v:"url#头像必须是有效的URL"`
|
||||
}
|
||||
|
||||
// Login 管理员登录
|
||||
func (c *AdminController) Login(r *ghttp.Request) {
|
||||
ctx := r.Context()
|
||||
var req AdminLoginReq
|
||||
if err := r.Parse(&req); err != nil {
|
||||
response.Error(r, response.CodeInvalidParam, "参数错误: "+err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// 检查数据库连接
|
||||
if err := g.DB().PingMaster(); err != nil {
|
||||
g.Log().Error(ctx, "数据库连接失败:", err)
|
||||
response.Error(r, response.CodeInternalError, "数据库连接失败,请稍后重试")
|
||||
return
|
||||
}
|
||||
|
||||
// 查询管理员信息
|
||||
var admin *entity.NlAdmin
|
||||
err := g.DB().Model("nl_admin").Where("username", req.Username).Scan(&admin)
|
||||
if err != nil {
|
||||
g.Log().Error(ctx, "查询管理员失败:", err)
|
||||
response.Error(r, response.CodeInternalError, "数据库查询失败")
|
||||
return
|
||||
}
|
||||
|
||||
if admin == nil {
|
||||
response.Error(r, response.CodeInvalidParam, "用户名或密码错误")
|
||||
return
|
||||
}
|
||||
|
||||
// 验证密码
|
||||
if !crypto.CheckPassword(req.Password, admin.Password) {
|
||||
response.Error(r, response.CodeInvalidParam, "用户名或密码错误")
|
||||
return
|
||||
}
|
||||
|
||||
// 检查管理员状态
|
||||
if admin.Status != 1 {
|
||||
response.Error(r, response.CodeForbidden, "账号已被禁用")
|
||||
return
|
||||
}
|
||||
|
||||
// 生成JWT Token
|
||||
token, err := jwt.GenerateToken(admin.Id, admin.Username, "admin")
|
||||
if err != nil {
|
||||
g.Log().Error(ctx, "生成Token失败:", err)
|
||||
response.Error(r, response.CodeInternalError, "系统错误")
|
||||
return
|
||||
}
|
||||
|
||||
// 更新最后登录时间
|
||||
now := int(time.Now().Unix())
|
||||
_, err = g.DB().Model("nl_admin").Where("id", admin.Id).Update(g.Map{
|
||||
"last_login_time": now,
|
||||
"last_login_ip": r.GetClientIp(),
|
||||
"updated_at": now,
|
||||
})
|
||||
if err != nil {
|
||||
g.Log().Error(ctx, "更新登录时间失败:", err)
|
||||
}
|
||||
|
||||
// 格式化管理员信息返回
|
||||
adminMap := g.Map{
|
||||
"id": admin.Id,
|
||||
"username": admin.Username,
|
||||
"nick_name": admin.NickName,
|
||||
"avatar": admin.Avatar,
|
||||
"phone": admin.Phone,
|
||||
"email": admin.Email,
|
||||
"role_id": admin.RoleId,
|
||||
"department": admin.Department,
|
||||
"status": admin.Status,
|
||||
"last_login_time": response.FormatTimestamp(now),
|
||||
"created_at": response.FormatTimestamp(admin.CreatedAt),
|
||||
"updated_at": response.FormatTimestamp(now),
|
||||
}
|
||||
|
||||
response.Success(r, g.Map{
|
||||
"token": token,
|
||||
"admin_info": adminMap,
|
||||
})
|
||||
}
|
||||
|
||||
// Register 管理员注册
|
||||
func (c *AdminController) Register(r *ghttp.Request) {
|
||||
ctx := r.Context()
|
||||
var req AdminRegisterReq
|
||||
if err := r.Parse(&req); err != nil {
|
||||
response.Error(r, response.CodeInvalidParam, "参数错误: "+err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// 检查用户名是否已存在
|
||||
count, err := g.DB().Model("nl_admin").Where("username", req.Username).Count()
|
||||
if err != nil {
|
||||
g.Log().Error(ctx, "查询管理员失败:", err)
|
||||
response.Error(r, response.CodeInternalError, "系统错误")
|
||||
return
|
||||
}
|
||||
if count > 0 {
|
||||
response.Error(r, response.CodeInvalidParam, "用户名已存在")
|
||||
return
|
||||
}
|
||||
|
||||
// 检查邮箱是否已存在
|
||||
count, err = g.DB().Model("nl_admin").Where("email", req.Email).Count()
|
||||
if err != nil {
|
||||
g.Log().Error(ctx, "查询邮箱失败:", err)
|
||||
response.Error(r, response.CodeInternalError, "系统错误")
|
||||
return
|
||||
}
|
||||
if count > 0 {
|
||||
response.Error(r, response.CodeInvalidParam, "邮箱已存在")
|
||||
return
|
||||
}
|
||||
|
||||
// 加密密码
|
||||
hashedPassword, err := crypto.HashPassword(req.Password)
|
||||
if err != nil {
|
||||
g.Log().Error(ctx, "密码加密失败:", err)
|
||||
response.Error(r, response.CodeInternalError, "系统错误")
|
||||
return
|
||||
}
|
||||
|
||||
// 创建管理员
|
||||
now := int(time.Now().Unix())
|
||||
adminData := g.Map{
|
||||
"username": req.Username,
|
||||
"password": hashedPassword,
|
||||
"email": req.Email,
|
||||
"nick_name": req.RealName,
|
||||
"role_id": 1, // 默认角色ID
|
||||
"status": 1, // 默认启用
|
||||
"created_at": now,
|
||||
"updated_at": now,
|
||||
}
|
||||
|
||||
result, err := g.DB().Model("nl_admin").Insert(adminData)
|
||||
if err != nil {
|
||||
g.Log().Error(ctx, "创建管理员失败:", err)
|
||||
response.Error(r, response.CodeInternalError, "系统错误")
|
||||
return
|
||||
}
|
||||
|
||||
// 获取新创建的管理员ID
|
||||
adminId, err := result.LastInsertId()
|
||||
if err != nil {
|
||||
g.Log().Error(ctx, "获取管理员ID失败:", err)
|
||||
response.Error(r, response.CodeInternalError, "系统错误")
|
||||
return
|
||||
}
|
||||
|
||||
// 生成JWT Token
|
||||
token, err := jwt.GenerateToken(gconv.Uint(adminId), req.Username, "admin")
|
||||
if err != nil {
|
||||
g.Log().Error(ctx, "生成Token失败:", err)
|
||||
response.Error(r, response.CodeInternalError, "系统错误")
|
||||
return
|
||||
}
|
||||
|
||||
// 查询新创建的管理员信息
|
||||
var admin *entity.NlAdmin
|
||||
err = g.DB().Model("nl_admin").Where("id", adminId).Scan(&admin)
|
||||
if err != nil {
|
||||
g.Log().Error(ctx, "查询管理员失败:", err)
|
||||
response.Error(r, response.CodeInternalError, "系统错误")
|
||||
return
|
||||
}
|
||||
|
||||
// 清除密码字段
|
||||
admin.Password = ""
|
||||
|
||||
response.Success(r, AdminLoginRes{
|
||||
Token: token,
|
||||
AdminInfo: admin,
|
||||
})
|
||||
}
|
||||
|
||||
// Profile 获取管理员信息
|
||||
func (c *AdminController) Profile(r *ghttp.Request) {
|
||||
ctx := r.Context()
|
||||
// 从上下文获取管理员ID
|
||||
adminId := r.GetCtxVar("admin_id")
|
||||
if adminId == nil {
|
||||
response.Error(r, response.CodeUnauthorized, "未授权访问")
|
||||
return
|
||||
}
|
||||
|
||||
// 查询管理员信息
|
||||
var admin *entity.NlAdmin
|
||||
err := g.DB().Model("nl_admin").Where("id", adminId).Scan(&admin)
|
||||
if err != nil {
|
||||
g.Log().Error(ctx, "查询管理员失败:", err)
|
||||
response.Error(r, response.CodeInternalError, "系统错误")
|
||||
return
|
||||
}
|
||||
|
||||
if admin == nil {
|
||||
response.Error(r, response.CodeNotFound, "管理员不存在")
|
||||
return
|
||||
}
|
||||
|
||||
// 清除密码字段
|
||||
admin.Password = ""
|
||||
|
||||
response.Success(r, AdminProfileRes{
|
||||
AdminInfo: admin,
|
||||
})
|
||||
}
|
||||
|
||||
// UpdateProfile 更新管理员信息
|
||||
func (c *AdminController) UpdateProfile(r *ghttp.Request) {
|
||||
ctx := r.Context()
|
||||
var req AdminUpdateReq
|
||||
if err := r.Parse(&req); err != nil {
|
||||
response.Error(r, response.CodeInvalidParam, "参数错误: "+err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// 从上下文获取管理员ID
|
||||
adminId := r.GetCtxVar("admin_id")
|
||||
if adminId == nil {
|
||||
response.Error(r, response.CodeUnauthorized, "未授权访问")
|
||||
return
|
||||
}
|
||||
|
||||
// 构建更新数据
|
||||
updateData := g.Map{
|
||||
"updated_at": int(time.Now().Unix()),
|
||||
}
|
||||
|
||||
if req.Email != "" {
|
||||
// 检查邮箱是否已被其他管理员使用
|
||||
count, err := g.DB().Model("nl_admin").Where("email", req.Email).Where("id !=", adminId).Count()
|
||||
if err != nil {
|
||||
g.Log().Error(ctx, "查询邮箱失败:", err)
|
||||
response.Error(r, response.CodeInternalError, "系统错误")
|
||||
return
|
||||
}
|
||||
if count > 0 {
|
||||
response.Error(r, response.CodeInvalidParam, "邮箱已被使用")
|
||||
return
|
||||
}
|
||||
updateData["email"] = req.Email
|
||||
}
|
||||
|
||||
if req.RealName != "" {
|
||||
updateData["real_name"] = req.RealName
|
||||
}
|
||||
|
||||
if req.Avatar != "" {
|
||||
updateData["avatar"] = req.Avatar
|
||||
}
|
||||
|
||||
// 更新管理员信息
|
||||
_, err := g.DB().Model("nl_admin").Where("id", adminId).Update(updateData)
|
||||
if err != nil {
|
||||
g.Log().Error(ctx, "更新管理员信息失败:", err)
|
||||
response.Error(r, response.CodeInternalError, "系统错误")
|
||||
return
|
||||
}
|
||||
|
||||
// 查询更新后的管理员信息
|
||||
var admin *entity.NlAdmin
|
||||
err = g.DB().Model("nl_admin").Where("id", adminId).Scan(&admin)
|
||||
if err != nil {
|
||||
g.Log().Error(ctx, "查询管理员失败:", err)
|
||||
response.Error(r, response.CodeInternalError, "系统错误")
|
||||
return
|
||||
}
|
||||
|
||||
// 清除密码字段
|
||||
admin.Password = ""
|
||||
|
||||
response.Success(r, AdminProfileRes{
|
||||
AdminInfo: admin,
|
||||
})
|
||||
}
|
||||
|
||||
// Logout 管理员登出
|
||||
func (c *AdminController) Logout(r *ghttp.Request) {
|
||||
// 这里可以实现Token黑名单机制
|
||||
// 目前简单返回成功
|
||||
response.Success(r, nil)
|
||||
}
|
||||
|
||||
// RefreshToken 刷新Token
|
||||
func (c *AdminController) RefreshToken(r *ghttp.Request) {
|
||||
// 从上下文获取管理员ID
|
||||
adminId := r.GetCtxVar("admin_id")
|
||||
if adminId == nil {
|
||||
response.Error(r, response.CodeUnauthorized, "未授权访问")
|
||||
return
|
||||
}
|
||||
|
||||
// 查询管理员信息获取用户名
|
||||
var admin *entity.NlAdmin
|
||||
err := g.DB().Model("nl_admin").Where("id", adminId).Scan(&admin)
|
||||
if err != nil {
|
||||
g.Log().Error(r.Context(), "查询管理员失败:", err)
|
||||
response.Error(r, response.CodeInternalError, "系统错误")
|
||||
return
|
||||
}
|
||||
|
||||
if admin == nil {
|
||||
response.Error(r, response.CodeNotFound, "管理员不存在")
|
||||
return
|
||||
}
|
||||
|
||||
// 生成新的Token
|
||||
token, err := jwt.GenerateToken(admin.Id, admin.Username, "admin")
|
||||
if err != nil {
|
||||
g.Log().Error(r.Context(), "生成Token失败:", err)
|
||||
response.Error(r, response.CodeInternalError, "系统错误")
|
||||
return
|
||||
}
|
||||
|
||||
response.Success(r, g.Map{
|
||||
"token": token,
|
||||
})
|
||||
}
|
||||
74
internal/controller/admin/attachment.go
Normal file
74
internal/controller/admin/attachment.go
Normal file
@@ -0,0 +1,74 @@
|
||||
package admin
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/v2/net/ghttp"
|
||||
"nl-video-api/internal/service"
|
||||
)
|
||||
|
||||
// AttachmentController 管理员附件管理控制器
|
||||
type AttachmentController struct{}
|
||||
|
||||
// NewAttachmentController 创建管理员附件管理控制器实例
|
||||
func NewAttachmentController() *AttachmentController {
|
||||
return &AttachmentController{}
|
||||
}
|
||||
|
||||
// GetList 获取附件列表
|
||||
func (c *AttachmentController) GetList(r *ghttp.Request) {
|
||||
service.NewAttachmentService().AdminGetList(r)
|
||||
}
|
||||
|
||||
// GetDetail 获取附件详情
|
||||
func (c *AttachmentController) GetDetail(r *ghttp.Request) {
|
||||
service.NewAttachmentService().AdminGetDetail(r)
|
||||
}
|
||||
|
||||
// Update 更新附件
|
||||
func (c *AttachmentController) Update(r *ghttp.Request) {
|
||||
service.NewAttachmentService().AdminUpdate(r)
|
||||
}
|
||||
|
||||
// Delete 删除附件
|
||||
func (c *AttachmentController) Delete(r *ghttp.Request) {
|
||||
service.NewAttachmentService().AdminDelete(r)
|
||||
}
|
||||
|
||||
// BatchDelete 批量删除附件
|
||||
func (c *AttachmentController) BatchDelete(r *ghttp.Request) {
|
||||
service.NewAttachmentService().AdminBatchDelete(r)
|
||||
}
|
||||
|
||||
// Download 下载附件
|
||||
func (c *AttachmentController) Download(r *ghttp.Request) {
|
||||
service.NewAttachmentService().AdminDownload(r)
|
||||
}
|
||||
|
||||
// Move 移动附件
|
||||
func (c *AttachmentController) Move(r *ghttp.Request) {
|
||||
service.NewAttachmentService().AdminMove(r)
|
||||
}
|
||||
|
||||
// Copy 复制附件
|
||||
func (c *AttachmentController) Copy(r *ghttp.Request) {
|
||||
service.NewAttachmentService().AdminCopy(r)
|
||||
}
|
||||
|
||||
// Rename 重命名附件
|
||||
func (c *AttachmentController) Rename(r *ghttp.Request) {
|
||||
service.NewAttachmentService().AdminRename(r)
|
||||
}
|
||||
|
||||
// Search 搜索附件
|
||||
func (c *AttachmentController) Search(r *ghttp.Request) {
|
||||
service.NewAttachmentService().AdminSearch(r)
|
||||
}
|
||||
|
||||
// GetCategoryList 获取附件分类列表
|
||||
func (c *AttachmentController) GetCategoryList(r *ghttp.Request) {
|
||||
service.NewAttachmentService().AdminGetCategoryList(r)
|
||||
}
|
||||
|
||||
// GetStatistics 获取附件统计
|
||||
func (c *AttachmentController) GetStatistics(r *ghttp.Request) {
|
||||
service.NewAttachmentService().AdminGetStatistics(r)
|
||||
}
|
||||
162
internal/controller/admin/banner.go
Normal file
162
internal/controller/admin/banner.go
Normal file
@@ -0,0 +1,162 @@
|
||||
package admin
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/net/ghttp"
|
||||
"nl-video-api/internal/service"
|
||||
"nl-video-api/utility/response"
|
||||
)
|
||||
|
||||
var Banner = cAdminBanner{}
|
||||
|
||||
type cAdminBanner struct{}
|
||||
|
||||
// Create 创建轮播图
|
||||
func (c *cAdminBanner) Create(r *ghttp.Request) {
|
||||
service.Banner.AdminCreate(r)
|
||||
}
|
||||
|
||||
// Update 更新轮播图
|
||||
func (c *cAdminBanner) Update(r *ghttp.Request) {
|
||||
var req *service.AdminBannerUpdateReq
|
||||
if err := r.Parse(&req); err != nil {
|
||||
response.Error(r, 1001, "参数解析失败: "+err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// 从URL路径获取ID
|
||||
if req.Id == 0 {
|
||||
idStr := r.Get("id").String()
|
||||
if id, err := strconv.Atoi(idStr); err == nil {
|
||||
req.Id = uint(id)
|
||||
}
|
||||
}
|
||||
|
||||
err := service.Banner.AdminUpdate(r.Context(), req)
|
||||
if err != nil {
|
||||
response.Error(r, 1002, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
response.Success(r, g.Map{
|
||||
"message": "更新成功",
|
||||
})
|
||||
}
|
||||
|
||||
// Delete 删除轮播图
|
||||
func (c *cAdminBanner) Delete(r *ghttp.Request) {
|
||||
idStr := r.Get("id").String()
|
||||
id, err := strconv.Atoi(idStr)
|
||||
if err != nil || id <= 0 {
|
||||
response.Error(r, 1001, "轮播图ID无效")
|
||||
return
|
||||
}
|
||||
|
||||
req := &service.AdminBannerDeleteReq{Id: uint(id)}
|
||||
err = service.Banner.AdminDelete(r.Context(), req)
|
||||
if err != nil {
|
||||
response.Error(r, 1002, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
response.Success(r, g.Map{
|
||||
"message": "删除成功",
|
||||
})
|
||||
}
|
||||
|
||||
// GetDetail 获取轮播图详情
|
||||
func (c *cAdminBanner) GetDetail(r *ghttp.Request) {
|
||||
idStr := r.Get("id").String()
|
||||
id, err := strconv.Atoi(idStr)
|
||||
if err != nil || id <= 0 {
|
||||
response.Error(r, 1001, "轮播图ID无效")
|
||||
return
|
||||
}
|
||||
|
||||
req := &service.AdminBannerDetailReq{Id: uint(id)}
|
||||
result, err := service.Banner.AdminGetDetail(r.Context(), req)
|
||||
if err != nil {
|
||||
response.Error(r, 1002, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
response.Success(r, result)
|
||||
}
|
||||
|
||||
// GetList 获取轮播图列表
|
||||
func (c *cAdminBanner) GetList(r *ghttp.Request) {
|
||||
var req *service.AdminBannerListReq
|
||||
if err := r.Parse(&req); err != nil {
|
||||
response.Error(r, 1001, "参数解析失败: "+err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// 设置默认分页参数
|
||||
if req.Page <= 0 {
|
||||
req.Page = 1
|
||||
}
|
||||
if req.Size <= 0 {
|
||||
req.Size = 10
|
||||
}
|
||||
|
||||
result, err := service.Banner.AdminGetList(r.Context(), req)
|
||||
if err != nil {
|
||||
response.Error(r, 1002, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
response.Success(r, result)
|
||||
}
|
||||
|
||||
// UpdateStatus 更新轮播图状态
|
||||
func (c *cAdminBanner) UpdateStatus(r *ghttp.Request) {
|
||||
var req *service.AdminBannerUpdateStatusReq
|
||||
if err := r.Parse(&req); err != nil {
|
||||
response.Error(r, 1001, "参数解析失败: "+err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// 从URL路径获取ID
|
||||
if req.Id == 0 {
|
||||
idStr := r.Get("id").String()
|
||||
if id, err := strconv.Atoi(idStr); err == nil {
|
||||
req.Id = uint(id)
|
||||
}
|
||||
}
|
||||
|
||||
err := service.Banner.AdminUpdateStatus(r.Context(), req)
|
||||
if err != nil {
|
||||
response.Error(r, 1002, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
response.Success(r, g.Map{
|
||||
"message": "状态更新成功",
|
||||
})
|
||||
}
|
||||
|
||||
// BatchDelete 批量删除轮播图
|
||||
func (c *cAdminBanner) BatchDelete(r *ghttp.Request) {
|
||||
var req *service.AdminBannerBatchDeleteReq
|
||||
if err := r.Parse(&req); err != nil {
|
||||
response.Error(r, 1001, "参数解析失败: "+err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
if len(req.Ids) == 0 {
|
||||
response.Error(r, 1001, "轮播图ID列表不能为空")
|
||||
return
|
||||
}
|
||||
|
||||
err := service.Banner.AdminBatchDelete(r.Context(), req)
|
||||
if err != nil {
|
||||
response.Error(r, 1002, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
response.Success(r, g.Map{
|
||||
"message": "批量删除成功",
|
||||
})
|
||||
}
|
||||
27
internal/controller/admin/comment.go
Normal file
27
internal/controller/admin/comment.go
Normal file
@@ -0,0 +1,27 @@
|
||||
package admin
|
||||
|
||||
import (
|
||||
"nl-video-api/internal/service"
|
||||
|
||||
"github.com/gogf/gf/v2/net/ghttp"
|
||||
)
|
||||
|
||||
// CommentController 管理员评论控制器
|
||||
type CommentController struct{}
|
||||
|
||||
var Comment = &CommentController{}
|
||||
|
||||
// List 管理员评论列表
|
||||
func (c *CommentController) List(r *ghttp.Request) {
|
||||
service.Comment.AdminList(r)
|
||||
}
|
||||
|
||||
// UpdateStatus 更新评论状态
|
||||
func (c *CommentController) UpdateStatus(r *ghttp.Request) {
|
||||
service.Comment.AdminUpdateStatus(r)
|
||||
}
|
||||
|
||||
// BatchDelete 批量删除评论
|
||||
func (c *CommentController) BatchDelete(r *ghttp.Request) {
|
||||
service.Comment.AdminBatchDelete(r)
|
||||
}
|
||||
109
internal/controller/admin/config.go
Normal file
109
internal/controller/admin/config.go
Normal file
@@ -0,0 +1,109 @@
|
||||
package admin
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/v2/net/ghttp"
|
||||
"nl-video-api/internal/service"
|
||||
)
|
||||
|
||||
// ConfigController 系统配置管理控制器
|
||||
type ConfigController struct{}
|
||||
|
||||
// NewConfigController 创建系统配置管理控制器实例
|
||||
func NewConfigController() *ConfigController {
|
||||
return &ConfigController{}
|
||||
}
|
||||
|
||||
// List 获取配置列表
|
||||
func (c *ConfigController) List(r *ghttp.Request) {
|
||||
service.NewConfigService().AdminList(r)
|
||||
}
|
||||
|
||||
// Detail 获取配置详情
|
||||
func (c *ConfigController) Detail(r *ghttp.Request) {
|
||||
service.NewConfigService().AdminDetail(r)
|
||||
}
|
||||
|
||||
// Create 创建配置
|
||||
func (c *ConfigController) Create(r *ghttp.Request) {
|
||||
service.NewConfigService().AdminCreate(r)
|
||||
}
|
||||
|
||||
// Update 更新配置
|
||||
func (c *ConfigController) Update(r *ghttp.Request) {
|
||||
service.NewConfigService().AdminUpdate(r)
|
||||
}
|
||||
|
||||
// Delete 删除配置
|
||||
func (c *ConfigController) Delete(r *ghttp.Request) {
|
||||
service.NewConfigService().AdminDelete(r)
|
||||
}
|
||||
|
||||
// BatchDelete 批量删除配置
|
||||
func (c *ConfigController) BatchDelete(r *ghttp.Request) {
|
||||
service.NewConfigService().AdminBatchDelete(r)
|
||||
}
|
||||
|
||||
// GetByKey 根据键获取配置
|
||||
func (c *ConfigController) GetByKey(r *ghttp.Request) {
|
||||
service.NewConfigService().AdminGetByKey(r)
|
||||
}
|
||||
|
||||
// GetByGroup 根据分组获取配置
|
||||
func (c *ConfigController) GetByGroup(r *ghttp.Request) {
|
||||
service.NewConfigService().AdminGetByGroup(r)
|
||||
}
|
||||
|
||||
// Set 设置配置
|
||||
func (c *ConfigController) Set(r *ghttp.Request) {
|
||||
service.NewConfigService().AdminSet(r)
|
||||
}
|
||||
|
||||
// BatchSet 批量设置配置
|
||||
func (c *ConfigController) BatchSet(r *ghttp.Request) {
|
||||
service.NewConfigService().AdminBatchSet(r)
|
||||
}
|
||||
|
||||
// GetGroupList 获取配置分组列表
|
||||
func (c *ConfigController) GetGroupList(r *ghttp.Request) {
|
||||
service.NewConfigService().AdminGetGroupList(r)
|
||||
}
|
||||
|
||||
// Export 导出配置
|
||||
func (c *ConfigController) Export(r *ghttp.Request) {
|
||||
service.NewConfigService().AdminExport(r)
|
||||
}
|
||||
|
||||
// Import 导入配置
|
||||
func (c *ConfigController) Import(r *ghttp.Request) {
|
||||
service.NewConfigService().AdminImport(r)
|
||||
}
|
||||
|
||||
// Cache 缓存配置
|
||||
func (c *ConfigController) Cache(r *ghttp.Request) {
|
||||
service.NewConfigService().AdminCache(r)
|
||||
}
|
||||
|
||||
// ClearCache 清除配置缓存
|
||||
func (c *ConfigController) ClearCache(r *ghttp.Request) {
|
||||
service.NewConfigService().AdminClearCache(r)
|
||||
}
|
||||
|
||||
// Validate 验证配置
|
||||
func (c *ConfigController) Validate(r *ghttp.Request) {
|
||||
service.NewConfigService().AdminValidate(r)
|
||||
}
|
||||
|
||||
// Backup 备份配置
|
||||
func (c *ConfigController) Backup(r *ghttp.Request) {
|
||||
service.NewConfigService().AdminBackup(r)
|
||||
}
|
||||
|
||||
// Restore 恢复配置
|
||||
func (c *ConfigController) Restore(r *ghttp.Request) {
|
||||
service.NewConfigService().AdminRestore(r)
|
||||
}
|
||||
|
||||
// GetHistory 获取配置历史
|
||||
func (c *ConfigController) GetHistory(r *ghttp.Request) {
|
||||
service.NewConfigService().AdminGetHistory(r)
|
||||
}
|
||||
88
internal/controller/admin/log.go
Normal file
88
internal/controller/admin/log.go
Normal file
@@ -0,0 +1,88 @@
|
||||
package admin
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/v2/net/ghttp"
|
||||
"nl-video-api/internal/service"
|
||||
)
|
||||
|
||||
// LogController 日志管理控制器
|
||||
type LogController struct{}
|
||||
|
||||
// NewLogController 创建日志管理控制器实例
|
||||
func NewLogController() *LogController {
|
||||
return &LogController{}
|
||||
}
|
||||
|
||||
// ===== 管理员日志管理 =====
|
||||
|
||||
// AdminLogList 获取管理员日志列表
|
||||
func (c *LogController) AdminLogList(r *ghttp.Request) {
|
||||
service.NewLogService().AdminLogList(r)
|
||||
}
|
||||
|
||||
// AdminLogDetail 获取管理员日志详情
|
||||
func (c *LogController) AdminLogDetail(r *ghttp.Request) {
|
||||
service.NewLogService().AdminLogDetail(r)
|
||||
}
|
||||
|
||||
// AdminLogDelete 删除管理员日志
|
||||
func (c *LogController) AdminLogDelete(r *ghttp.Request) {
|
||||
service.NewLogService().AdminLogDelete(r)
|
||||
}
|
||||
|
||||
// AdminLogBatchDelete 批量删除管理员日志
|
||||
func (c *LogController) AdminLogBatchDelete(r *ghttp.Request) {
|
||||
service.NewLogService().AdminLogBatchDelete(r)
|
||||
}
|
||||
|
||||
// AdminLogClear 清空管理员日志
|
||||
func (c *LogController) AdminLogClear(r *ghttp.Request) {
|
||||
service.NewLogService().AdminLogClear(r)
|
||||
}
|
||||
|
||||
// AdminLogExport 导出管理员日志
|
||||
func (c *LogController) AdminLogExport(r *ghttp.Request) {
|
||||
service.NewLogService().AdminLogExport(r)
|
||||
}
|
||||
|
||||
// AdminLogStats 管理员日志统计
|
||||
func (c *LogController) AdminLogStats(r *ghttp.Request) {
|
||||
service.NewLogService().AdminLogStats(r)
|
||||
}
|
||||
|
||||
// ===== 用户日志管理 =====
|
||||
|
||||
// UserLogList 获取用户日志列表
|
||||
func (c *LogController) UserLogList(r *ghttp.Request) {
|
||||
service.NewLogService().UserLogList(r)
|
||||
}
|
||||
|
||||
// UserLogDetail 获取用户日志详情
|
||||
func (c *LogController) UserLogDetail(r *ghttp.Request) {
|
||||
service.NewLogService().UserLogDetail(r)
|
||||
}
|
||||
|
||||
// UserLogDelete 删除用户日志
|
||||
func (c *LogController) UserLogDelete(r *ghttp.Request) {
|
||||
service.NewLogService().UserLogDelete(r)
|
||||
}
|
||||
|
||||
// UserLogBatchDelete 批量删除用户日志
|
||||
func (c *LogController) UserLogBatchDelete(r *ghttp.Request) {
|
||||
service.NewLogService().UserLogBatchDelete(r)
|
||||
}
|
||||
|
||||
// UserLogClear 清空用户日志
|
||||
func (c *LogController) UserLogClear(r *ghttp.Request) {
|
||||
service.NewLogService().UserLogClear(r)
|
||||
}
|
||||
|
||||
// UserLogExport 导出用户日志
|
||||
func (c *LogController) UserLogExport(r *ghttp.Request) {
|
||||
service.NewLogService().UserLogExport(r)
|
||||
}
|
||||
|
||||
// UserLogStats 用户日志统计
|
||||
func (c *LogController) UserLogStats(r *ghttp.Request) {
|
||||
service.NewLogService().UserLogStats(r)
|
||||
}
|
||||
74
internal/controller/admin/payment_order.go
Normal file
74
internal/controller/admin/payment_order.go
Normal file
@@ -0,0 +1,74 @@
|
||||
package admin
|
||||
|
||||
import (
|
||||
"nl-video-api/internal/service"
|
||||
"nl-video-api/utility/response"
|
||||
|
||||
"github.com/gogf/gf/v2/net/ghttp"
|
||||
)
|
||||
|
||||
var PaymentOrder = cAdminPaymentOrder{}
|
||||
|
||||
type cAdminPaymentOrder struct{}
|
||||
|
||||
// GetList 管理员获取支付订单列表
|
||||
func (c *cAdminPaymentOrder) GetList(r *ghttp.Request) {
|
||||
service.NewPaymentOrderService().AdminGetList(r)
|
||||
}
|
||||
|
||||
// GetDetail 管理员获取支付订单详情
|
||||
func (c *cAdminPaymentOrder) GetDetail(r *ghttp.Request) {
|
||||
service.NewPaymentOrderService().AdminGetDetail(r)
|
||||
}
|
||||
|
||||
// Refund 管理员订单退款
|
||||
func (c *cAdminPaymentOrder) Refund(r *ghttp.Request) {
|
||||
// 获取请求参数
|
||||
id := r.Get("id").Uint()
|
||||
reason := r.Get("reason").String()
|
||||
|
||||
if id == 0 {
|
||||
response.Error(r, response.CodeInvalidParam, "订单ID不能为空")
|
||||
return
|
||||
}
|
||||
|
||||
req := &service.PaymentOrderRefundReq{
|
||||
Id: id,
|
||||
Reason: reason,
|
||||
}
|
||||
|
||||
err := service.NewPaymentOrderService().AdminRefund(r.Context(), req)
|
||||
if err != nil {
|
||||
response.Error(r, response.CodeInternalError, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
response.Success(r, "退款成功")
|
||||
}
|
||||
|
||||
// GetStatistics 获取支付统计
|
||||
func (c *cAdminPaymentOrder) GetStatistics(r *ghttp.Request) {
|
||||
startDate := r.Get("start_date").String()
|
||||
endDate := r.Get("end_date").String()
|
||||
|
||||
// 设置默认时间范围
|
||||
if startDate == "" {
|
||||
startDate = "2024-01-01"
|
||||
}
|
||||
if endDate == "" {
|
||||
endDate = "2024-12-31"
|
||||
}
|
||||
|
||||
result, err := service.NewPaymentOrderService().GetStatistics(r.Context(), startDate, endDate)
|
||||
if err != nil {
|
||||
response.Error(r, response.CodeInternalError, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
response.Success(r, result)
|
||||
}
|
||||
|
||||
// Create 创建支付订单
|
||||
func (c *cAdminPaymentOrder) Create(r *ghttp.Request) {
|
||||
service.NewPaymentOrderService().Create(r)
|
||||
}
|
||||
245
internal/controller/admin/permission.go
Normal file
245
internal/controller/admin/permission.go
Normal file
@@ -0,0 +1,245 @@
|
||||
package admin
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/net/ghttp"
|
||||
"nl-video-api/internal/dao"
|
||||
"nl-video-api/internal/service/auth"
|
||||
"nl-video-api/utility/response"
|
||||
)
|
||||
|
||||
// PermissionController 权限控制器
|
||||
type PermissionController struct{}
|
||||
|
||||
var Permission = &PermissionController{}
|
||||
|
||||
// Create 创建权限
|
||||
func (c *PermissionController) Create(r *ghttp.Request) {
|
||||
var req *auth.PermissionCreateReq
|
||||
if err := r.Parse(&req); err != nil {
|
||||
response.Error(r, response.CodeInvalidParam, "参数解析失败: "+err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
id, err := auth.Permission.Create(r.Context(), req)
|
||||
if err != nil {
|
||||
response.Error(r, response.CodeError, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
response.Success(r, g.Map{
|
||||
"id": id,
|
||||
})
|
||||
}
|
||||
|
||||
// Update 更新权限
|
||||
func (c *PermissionController) Update(r *ghttp.Request) {
|
||||
var req *auth.PermissionUpdateReq
|
||||
if err := r.Parse(&req); err != nil {
|
||||
response.Error(r, response.CodeInvalidParam, "参数解析失败: "+err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// 从URL路径获取ID
|
||||
if req.Id == 0 {
|
||||
idStr := r.Get("id").String()
|
||||
if id, err := strconv.Atoi(idStr); err == nil {
|
||||
req.Id = id
|
||||
}
|
||||
}
|
||||
|
||||
if req.Id <= 0 {
|
||||
response.Error(r, response.CodeInvalidParam, "权限ID无效")
|
||||
return
|
||||
}
|
||||
|
||||
err := auth.Permission.Update(r.Context(), req)
|
||||
if err != nil {
|
||||
response.Error(r, response.CodeError, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
response.Success(r, "更新成功")
|
||||
}
|
||||
|
||||
// GetById 获取权限详情
|
||||
func (c *PermissionController) GetById(r *ghttp.Request) {
|
||||
idStr := r.Get("id").String()
|
||||
id, err := strconv.Atoi(idStr)
|
||||
if err != nil || id <= 0 {
|
||||
response.Error(r, response.CodeInvalidParam, "权限ID无效")
|
||||
return
|
||||
}
|
||||
|
||||
permission, err := auth.Permission.GetById(r.Context(), id)
|
||||
if err != nil {
|
||||
response.Error(r, response.CodeError, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
if permission == nil {
|
||||
response.Error(r, response.CodeNotFound, "权限不存在")
|
||||
return
|
||||
}
|
||||
|
||||
response.Success(r, permission)
|
||||
}
|
||||
|
||||
// GetList 获取权限列表
|
||||
func (c *PermissionController) GetList(r *ghttp.Request) {
|
||||
var req *dao.PermissionListReq
|
||||
if err := r.Parse(&req); err != nil {
|
||||
response.Error(r, response.CodeInvalidParam, "参数解析失败: "+err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
permissions, total, err := auth.Permission.GetList(r.Context(), req)
|
||||
if err != nil {
|
||||
response.Error(r, response.CodeError, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
response.Success(r, g.Map{
|
||||
"list": permissions,
|
||||
"total": total,
|
||||
"page": req.Page,
|
||||
"page_size": req.PageSize,
|
||||
})
|
||||
}
|
||||
|
||||
// GetTree 获取权限树形结构
|
||||
func (c *PermissionController) GetTree(r *ghttp.Request) {
|
||||
permissions, err := auth.Permission.GetTree(r.Context())
|
||||
if err != nil {
|
||||
response.Error(r, response.CodeError, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
response.Success(r, g.Map{
|
||||
"tree": permissions,
|
||||
})
|
||||
}
|
||||
|
||||
// Delete 删除权限
|
||||
func (c *PermissionController) Delete(r *ghttp.Request) {
|
||||
idStr := r.Get("id").String()
|
||||
id, err := strconv.Atoi(idStr)
|
||||
if err != nil || id <= 0 {
|
||||
response.Error(r, response.CodeInvalidParam, "权限ID无效")
|
||||
return
|
||||
}
|
||||
|
||||
err = auth.Permission.Delete(r.Context(), id)
|
||||
if err != nil {
|
||||
response.Error(r, response.CodeError, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
response.Success(r, "删除成功")
|
||||
}
|
||||
|
||||
// GetMenuPermissions 获取菜单权限
|
||||
func (c *PermissionController) GetMenuPermissions(r *ghttp.Request) {
|
||||
permissions, err := auth.Permission.GetMenuPermissions(r.Context())
|
||||
if err != nil {
|
||||
response.Error(r, response.CodeError, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
response.Success(r, g.Map{
|
||||
"list": permissions,
|
||||
})
|
||||
}
|
||||
|
||||
// GetApiPermissions 获取API权限
|
||||
func (c *PermissionController) GetApiPermissions(r *ghttp.Request) {
|
||||
permissions, err := auth.Permission.GetApiPermissions(r.Context())
|
||||
if err != nil {
|
||||
response.Error(r, response.CodeError, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
response.Success(r, g.Map{
|
||||
"list": permissions,
|
||||
})
|
||||
}
|
||||
|
||||
// GetUserPermissions 获取用户权限
|
||||
func (c *PermissionController) GetUserPermissions(r *ghttp.Request) {
|
||||
userIdStr := r.Get("user_id").String()
|
||||
userId, err := strconv.Atoi(userIdStr)
|
||||
if err != nil || userId <= 0 {
|
||||
response.Error(r, response.CodeInvalidParam, "用户ID无效")
|
||||
return
|
||||
}
|
||||
|
||||
permissions, err := auth.Permission.GetUserPermissions(r.Context(), userId)
|
||||
if err != nil {
|
||||
response.Error(r, response.CodeError, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
response.Success(r, g.Map{
|
||||
"list": permissions,
|
||||
})
|
||||
}
|
||||
|
||||
// CheckPermission 检查权限
|
||||
func (c *PermissionController) CheckPermission(r *ghttp.Request) {
|
||||
userIdStr := r.Get("user_id").String()
|
||||
userId, err := strconv.Atoi(userIdStr)
|
||||
if err != nil || userId <= 0 {
|
||||
response.Error(r, response.CodeInvalidParam, "用户ID无效")
|
||||
return
|
||||
}
|
||||
|
||||
permissionCode := r.Get("permission_code").String()
|
||||
if permissionCode == "" {
|
||||
response.Error(r, response.CodeInvalidParam, "权限编码不能为空")
|
||||
return
|
||||
}
|
||||
|
||||
hasPermission, err := auth.Permission.CheckUserPermission(r.Context(), userId, permissionCode)
|
||||
if err != nil {
|
||||
response.Error(r, response.CodeError, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
response.Success(r, g.Map{
|
||||
"has_permission": hasPermission,
|
||||
})
|
||||
}
|
||||
|
||||
// CheckApiPermission 检查API权限
|
||||
func (c *PermissionController) CheckApiPermission(r *ghttp.Request) {
|
||||
userIdStr := r.Get("user_id").String()
|
||||
userId, err := strconv.Atoi(userIdStr)
|
||||
if err != nil || userId <= 0 {
|
||||
response.Error(r, response.CodeInvalidParam, "用户ID无效")
|
||||
return
|
||||
}
|
||||
|
||||
apiPath := r.Get("api_path").String()
|
||||
if apiPath == "" {
|
||||
response.Error(r, response.CodeInvalidParam, "API路径不能为空")
|
||||
return
|
||||
}
|
||||
|
||||
method := r.Get("method").String()
|
||||
if method == "" {
|
||||
response.Error(r, response.CodeInvalidParam, "请求方法不能为空")
|
||||
return
|
||||
}
|
||||
|
||||
hasPermission, err := auth.Permission.CheckApiPermission(r.Context(), userId, apiPath, method)
|
||||
if err != nil {
|
||||
response.Error(r, response.CodeError, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
response.Success(r, g.Map{
|
||||
"has_permission": hasPermission,
|
||||
})
|
||||
}
|
||||
270
internal/controller/admin/role.go
Normal file
270
internal/controller/admin/role.go
Normal file
@@ -0,0 +1,270 @@
|
||||
package admin
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/net/ghttp"
|
||||
"nl-video-api/internal/dao"
|
||||
"nl-video-api/internal/service/auth"
|
||||
"nl-video-api/utility/response"
|
||||
)
|
||||
|
||||
// RoleController 角色控制器
|
||||
type RoleController struct{}
|
||||
|
||||
var Role = &RoleController{}
|
||||
|
||||
// Create 创建角色
|
||||
func (c *RoleController) Create(r *ghttp.Request) {
|
||||
var req *auth.RoleCreateReq
|
||||
if err := r.Parse(&req); err != nil {
|
||||
response.Error(r, response.CodeInvalidParam, "参数解析失败: "+err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
id, err := auth.Role.Create(r.Context(), req)
|
||||
if err != nil {
|
||||
response.Error(r, response.CodeError, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
response.Success(r, g.Map{
|
||||
"id": id,
|
||||
})
|
||||
}
|
||||
|
||||
// Update 更新角色
|
||||
func (c *RoleController) Update(r *ghttp.Request) {
|
||||
var req *auth.RoleUpdateReq
|
||||
if err := r.Parse(&req); err != nil {
|
||||
response.Error(r, response.CodeInvalidParam, "参数解析失败: "+err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// 从URL路径获取ID
|
||||
if req.Id == 0 {
|
||||
idStr := r.Get("id").String()
|
||||
if id, err := strconv.Atoi(idStr); err == nil {
|
||||
req.Id = id
|
||||
}
|
||||
}
|
||||
|
||||
if req.Id <= 0 {
|
||||
response.Error(r, response.CodeInvalidParam, "角色ID无效")
|
||||
return
|
||||
}
|
||||
|
||||
err := auth.Role.Update(r.Context(), req)
|
||||
if err != nil {
|
||||
response.Error(r, response.CodeError, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
response.Success(r, "更新成功")
|
||||
}
|
||||
|
||||
// GetById 获取角色详情
|
||||
func (c *RoleController) GetById(r *ghttp.Request) {
|
||||
idStr := r.Get("id").String()
|
||||
id, err := strconv.Atoi(idStr)
|
||||
if err != nil || id <= 0 {
|
||||
response.Error(r, response.CodeInvalidParam, "角色ID无效")
|
||||
return
|
||||
}
|
||||
|
||||
role, err := auth.Role.GetById(r.Context(), id)
|
||||
if err != nil {
|
||||
response.Error(r, response.CodeError, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
if role == nil {
|
||||
response.Error(r, response.CodeNotFound, "角色不存在")
|
||||
return
|
||||
}
|
||||
|
||||
response.Success(r, role)
|
||||
}
|
||||
|
||||
// GetList 获取角色列表
|
||||
func (c *RoleController) GetList(r *ghttp.Request) {
|
||||
var req *dao.RoleListReq
|
||||
if err := r.Parse(&req); err != nil {
|
||||
response.Error(r, response.CodeInvalidParam, "参数解析失败: "+err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
roles, total, err := auth.Role.GetList(r.Context(), req)
|
||||
if err != nil {
|
||||
response.Error(r, response.CodeError, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
response.Success(r, g.Map{
|
||||
"list": roles,
|
||||
"total": total,
|
||||
"page": req.Page,
|
||||
"page_size": req.PageSize,
|
||||
})
|
||||
}
|
||||
|
||||
// GetAll 获取所有角色
|
||||
func (c *RoleController) GetAll(r *ghttp.Request) {
|
||||
roles, err := auth.Role.GetAll(r.Context())
|
||||
if err != nil {
|
||||
response.Error(r, response.CodeError, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
response.Success(r, g.Map{
|
||||
"list": roles,
|
||||
})
|
||||
}
|
||||
|
||||
// Delete 删除角色
|
||||
func (c *RoleController) Delete(r *ghttp.Request) {
|
||||
idStr := r.Get("id").String()
|
||||
id, err := strconv.Atoi(idStr)
|
||||
if err != nil || id <= 0 {
|
||||
response.Error(r, response.CodeInvalidParam, "角色ID无效")
|
||||
return
|
||||
}
|
||||
|
||||
err = auth.Role.Delete(r.Context(), id)
|
||||
if err != nil {
|
||||
response.Error(r, response.CodeError, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
response.Success(r, "删除成功")
|
||||
}
|
||||
|
||||
// AssignPermissions 为角色分配权限
|
||||
func (c *RoleController) AssignPermissions(r *ghttp.Request) {
|
||||
var req *auth.RolePermissionReq
|
||||
if err := r.Parse(&req); err != nil {
|
||||
response.Error(r, response.CodeInvalidParam, "参数解析失败: "+err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// 从URL路径获取角色ID
|
||||
if req.RoleId == 0 {
|
||||
idStr := r.Get("id").String()
|
||||
if id, err := strconv.Atoi(idStr); err == nil {
|
||||
req.RoleId = id
|
||||
}
|
||||
}
|
||||
|
||||
if req.RoleId <= 0 {
|
||||
response.Error(r, response.CodeInvalidParam, "角色ID无效")
|
||||
return
|
||||
}
|
||||
|
||||
err := auth.Role.AssignPermissions(r.Context(), req)
|
||||
if err != nil {
|
||||
response.Error(r, response.CodeError, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
response.Success(r, "权限分配成功")
|
||||
}
|
||||
|
||||
// GetRolePermissions 获取角色权限
|
||||
func (c *RoleController) GetRolePermissions(r *ghttp.Request) {
|
||||
idStr := r.Get("id").String()
|
||||
id, err := strconv.Atoi(idStr)
|
||||
if err != nil || id <= 0 {
|
||||
response.Error(r, response.CodeInvalidParam, "角色ID无效")
|
||||
return
|
||||
}
|
||||
|
||||
permissions, err := auth.Role.GetRolePermissions(r.Context(), id)
|
||||
if err != nil {
|
||||
response.Error(r, response.CodeError, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// 同时返回权限ID列表,方便前端处理
|
||||
permissionIds, _ := auth.Role.GetRolePermissionIds(r.Context(), id)
|
||||
|
||||
response.Success(r, g.Map{
|
||||
"permissions": permissions,
|
||||
"permission_ids": permissionIds,
|
||||
})
|
||||
}
|
||||
|
||||
// BatchUpdateStatus 批量更新角色状态
|
||||
func (c *RoleController) BatchUpdateStatus(r *ghttp.Request) {
|
||||
type BatchUpdateReq struct {
|
||||
Ids []int `json:"ids" v:"required#请选择要操作的角色"`
|
||||
Status int `json:"status" v:"required|in:0,1#状态只能为0或1"`
|
||||
}
|
||||
|
||||
var req BatchUpdateReq
|
||||
if err := r.Parse(&req); err != nil {
|
||||
response.Error(r, response.CodeInvalidParam, "参数解析失败: "+err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
if len(req.Ids) == 0 {
|
||||
response.Error(r, response.CodeInvalidParam, "请选择要操作的角色")
|
||||
return
|
||||
}
|
||||
|
||||
err := auth.Role.BatchUpdateStatus(r.Context(), req.Ids, req.Status)
|
||||
if err != nil {
|
||||
response.Error(r, response.CodeError, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
response.Success(r, g.Map{
|
||||
"count": len(req.Ids),
|
||||
})
|
||||
}
|
||||
|
||||
// CopyRole 复制角色
|
||||
func (c *RoleController) CopyRole(r *ghttp.Request) {
|
||||
type CopyRoleReq struct {
|
||||
SourceId int `json:"source_id" v:"required|min:1#源角色ID不能为空"`
|
||||
Name string `json:"name" v:"required|length:2,50#角色名称不能为空|角色名称长度为2-50位"`
|
||||
Code string `json:"code" v:"required|length:2,50#角色编码不能为空|角色编码长度为2-50位"`
|
||||
}
|
||||
|
||||
var req CopyRoleReq
|
||||
if err := r.Parse(&req); err != nil {
|
||||
response.Error(r, response.CodeInvalidParam, "参数解析失败: "+err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
newRoleId, err := auth.Role.CopyRole(r.Context(), req.SourceId, req.Name, req.Code)
|
||||
if err != nil {
|
||||
response.Error(r, response.CodeError, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
response.Success(r, g.Map{
|
||||
"id": newRoleId,
|
||||
})
|
||||
}
|
||||
|
||||
// GetRolesByLevel 根据等级获取角色
|
||||
func (c *RoleController) GetRolesByLevel(r *ghttp.Request) {
|
||||
levelStr := r.Get("level").String()
|
||||
level, err := strconv.Atoi(levelStr)
|
||||
if err != nil || level <= 0 {
|
||||
response.Error(r, response.CodeInvalidParam, "角色等级无效")
|
||||
return
|
||||
}
|
||||
|
||||
roles, err := auth.Role.GetRolesByLevel(r.Context(), level)
|
||||
if err != nil {
|
||||
response.Error(r, response.CodeError, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
response.Success(r, g.Map{
|
||||
"list": roles,
|
||||
"level": level,
|
||||
})
|
||||
}
|
||||
295
internal/controller/admin/user.go
Normal file
295
internal/controller/admin/user.go
Normal file
@@ -0,0 +1,295 @@
|
||||
package admin
|
||||
|
||||
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/service/user"
|
||||
"nl-video-api/utility/crypto"
|
||||
"nl-video-api/utility/response"
|
||||
)
|
||||
|
||||
var User = cAdminUser{}
|
||||
|
||||
type cAdminUser struct{}
|
||||
|
||||
// AdminUserCreateReq 管理员创建用户请求
|
||||
type AdminUserCreateReq struct {
|
||||
Username string `json:"username" v:"required|length:3,20#用户名不能为空|用户名长度为3-20位"`
|
||||
Password string `json:"password" v:"required|length:6,20#密码不能为空|密码长度为6-20位"`
|
||||
Email string `json:"email" v:"email#邮箱格式不正确"`
|
||||
Phone string `json:"phone" v:"phone#手机号格式不正确"`
|
||||
Status int `json:"status" v:"in:0,1#状态值不正确"`
|
||||
}
|
||||
|
||||
// AdminUserUpdateReq 管理员更新用户请求
|
||||
type AdminUserUpdateReq struct {
|
||||
Id uint `json:"id" v:"required|min:1#用户ID不能为空"`
|
||||
Username string `json:"username" v:"length:3,20#用户名长度为3-20位"`
|
||||
Email string `json:"email" v:"email#邮箱格式不正确"`
|
||||
Phone string `json:"phone" v:"phone#手机号格式不正确"`
|
||||
Status int `json:"status" v:"in:0,1#状态值不正确"`
|
||||
}
|
||||
|
||||
// AdminUserDetailReq 管理员获取用户详情请求
|
||||
type AdminUserDetailReq struct {
|
||||
Id uint `json:"id" v:"required|min:1#用户ID不能为空"`
|
||||
}
|
||||
|
||||
// AdminUserListReq 管理员获取用户列表请求
|
||||
type AdminUserListReq struct {
|
||||
Page int `json:"page" v:"min:1#页码不能小于1"`
|
||||
Size int `json:"size" v:"min:1|max:100#每页数量不能小于1且不能大于100"`
|
||||
Username string `json:"username"`
|
||||
Email string `json:"email"`
|
||||
Status int `json:"status" v:"in:-1,0,1#状态值不正确"`
|
||||
}
|
||||
|
||||
// AdminUserDeleteReq 管理员删除用户请求
|
||||
type AdminUserDeleteReq struct {
|
||||
Id uint `json:"id" v:"required|min:1#用户ID不能为空"`
|
||||
}
|
||||
|
||||
// Create 管理员创建用户
|
||||
func (c *cAdminUser) Create(r *ghttp.Request) {
|
||||
var req *AdminUserCreateReq
|
||||
if err := r.Parse(&req); err != nil {
|
||||
response.Error(r, 1001, "参数解析失败: "+err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// 构造用户创建请求
|
||||
createReq := &user.UserCreateReq{
|
||||
Username: req.Username,
|
||||
Password: req.Password,
|
||||
Email: req.Email,
|
||||
Phone: req.Phone,
|
||||
}
|
||||
|
||||
// 调用用户服务创建用户
|
||||
_, err := user.User.Create(r.Context(), createReq)
|
||||
if err != nil {
|
||||
response.Error(r, 1002, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
response.Success(r, g.Map{
|
||||
"message": "创建成功",
|
||||
})
|
||||
}
|
||||
|
||||
// Update 管理员更新用户
|
||||
func (c *cAdminUser) Update(r *ghttp.Request) {
|
||||
var req *AdminUserUpdateReq
|
||||
if err := r.Parse(&req); err != nil {
|
||||
response.Error(r, 1001, "参数解析失败: "+err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// 从URL路径获取ID
|
||||
if req.Id == 0 {
|
||||
idStr := r.Get("id").String()
|
||||
if id, err := strconv.Atoi(idStr); err == nil {
|
||||
req.Id = uint(id)
|
||||
}
|
||||
}
|
||||
|
||||
if req.Id == 0 {
|
||||
response.Error(r, 1001, "用户ID不能为空")
|
||||
return
|
||||
}
|
||||
|
||||
// 构造用户更新请求
|
||||
updateReq := &user.UserUpdateReq{
|
||||
Id: int(req.Id),
|
||||
Username: req.Username,
|
||||
Email: req.Email,
|
||||
Phone: req.Phone,
|
||||
Status: req.Status,
|
||||
}
|
||||
|
||||
// 调用用户服务更新用户
|
||||
err := user.User.Update(r.Context(), updateReq)
|
||||
if err != nil {
|
||||
response.Error(r, 1002, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
response.Success(r, g.Map{
|
||||
"message": "更新成功",
|
||||
})
|
||||
}
|
||||
|
||||
// GetDetail 管理员获取用户详情
|
||||
func (c *cAdminUser) GetDetail(r *ghttp.Request) {
|
||||
var req *AdminUserDetailReq
|
||||
if err := r.Parse(&req); err != nil {
|
||||
response.Error(r, 1001, "参数解析失败: "+err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// 从URL路径获取ID
|
||||
if req.Id == 0 {
|
||||
idStr := r.Get("id").String()
|
||||
if id, err := strconv.Atoi(idStr); err == nil {
|
||||
req.Id = uint(id)
|
||||
}
|
||||
}
|
||||
|
||||
if req.Id == 0 {
|
||||
response.Error(r, 1001, "用户ID不能为空")
|
||||
return
|
||||
}
|
||||
|
||||
// 调用用户服务获取用户详情
|
||||
result, err := user.User.GetById(r.Context(), int(req.Id))
|
||||
if err != nil {
|
||||
response.Error(r, 1002, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
response.Success(r, result)
|
||||
}
|
||||
|
||||
// GetList 管理员获取用户列表
|
||||
func (c *cAdminUser) GetList(r *ghttp.Request) {
|
||||
var req *AdminUserListReq
|
||||
if err := r.Parse(&req); err != nil {
|
||||
response.Error(r, 1001, "参数解析失败: "+err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// 设置默认分页参数
|
||||
if req.Page <= 0 {
|
||||
req.Page = 1
|
||||
}
|
||||
if req.Size <= 0 {
|
||||
req.Size = 10
|
||||
}
|
||||
|
||||
// 构造用户列表请求
|
||||
listReq := &dao.UserListReq{
|
||||
Page: req.Page,
|
||||
Username: req.Username,
|
||||
Email: req.Email,
|
||||
Status: req.Status,
|
||||
}
|
||||
|
||||
// 调用用户服务获取用户列表
|
||||
result, total, err := user.User.GetList(r.Context(), listReq)
|
||||
if err != nil {
|
||||
response.Error(r, 1002, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// 构造响应数据
|
||||
responseData := g.Map{
|
||||
"list": result,
|
||||
"total": total,
|
||||
"page": req.Page,
|
||||
"size": req.Size,
|
||||
}
|
||||
|
||||
response.Success(r, responseData)
|
||||
}
|
||||
|
||||
// Delete 管理员删除用户
|
||||
func (c *cAdminUser) Delete(r *ghttp.Request) {
|
||||
var req *AdminUserDeleteReq
|
||||
if err := r.Parse(&req); err != nil {
|
||||
response.Error(r, 1001, "参数解析失败: "+err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// 从URL路径获取ID
|
||||
if req.Id == 0 {
|
||||
idStr := r.Get("id").String()
|
||||
if id, err := strconv.Atoi(idStr); err == nil {
|
||||
req.Id = uint(id)
|
||||
}
|
||||
}
|
||||
|
||||
if req.Id == 0 {
|
||||
response.Error(r, 1001, "用户ID不能为空")
|
||||
return
|
||||
}
|
||||
|
||||
// 调用用户服务删除用户
|
||||
err := user.User.Delete(r.Context(), int(req.Id))
|
||||
if err != nil {
|
||||
response.Error(r, 1002, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
response.Success(r, g.Map{
|
||||
"message": "删除成功",
|
||||
})
|
||||
}
|
||||
|
||||
// UpdateStatus 管理员更新用户状态
|
||||
func (c *cAdminUser) UpdateStatus(r *ghttp.Request) {
|
||||
id := r.Get("id").Uint()
|
||||
status := r.Get("status").Int()
|
||||
|
||||
if id == 0 {
|
||||
response.Error(r, 1001, "用户ID不能为空")
|
||||
return
|
||||
}
|
||||
|
||||
// 构造用户更新请求
|
||||
updateReq := &user.UserUpdateReq{
|
||||
Id: int(id),
|
||||
Status: status,
|
||||
}
|
||||
|
||||
// 调用用户服务更新用户
|
||||
err := user.User.Update(r.Context(), updateReq)
|
||||
if err != nil {
|
||||
response.Error(r, 1002, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
response.Success(r, g.Map{
|
||||
"message": "状态更新成功",
|
||||
})
|
||||
}
|
||||
|
||||
// ResetPassword 管理员重置用户密码
|
||||
func (c *cAdminUser) ResetPassword(r *ghttp.Request) {
|
||||
id := r.Get("id").Uint()
|
||||
newPassword := r.Get("password").String()
|
||||
|
||||
if id == 0 {
|
||||
response.Error(r, 1001, "用户ID不能为空")
|
||||
return
|
||||
}
|
||||
|
||||
if newPassword == "" {
|
||||
response.Error(r, 1001, "新密码不能为空")
|
||||
return
|
||||
}
|
||||
|
||||
// 直接更新密码,管理员重置不需要原密码验证
|
||||
hashedPassword, err := crypto.HashPassword(newPassword)
|
||||
if err != nil {
|
||||
response.Error(r, 1002, "密码加密失败: "+err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// 更新用户密码
|
||||
_, err = g.DB().Model("nl_user").Ctx(r.Context()).Where("id", id).Data(g.Map{
|
||||
"password": hashedPassword,
|
||||
"updated_at": gtime.Now(),
|
||||
}).Update()
|
||||
if err != nil {
|
||||
response.Error(r, 1002, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
response.Success(r, g.Map{
|
||||
"message": "密码重置成功",
|
||||
})
|
||||
}
|
||||
59
internal/controller/admin/vip_level.go
Normal file
59
internal/controller/admin/vip_level.go
Normal file
@@ -0,0 +1,59 @@
|
||||
package admin
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/v2/net/ghttp"
|
||||
"nl-video-api/internal/service"
|
||||
)
|
||||
|
||||
// VipLevelController VIP等级控制器(管理端)
|
||||
type VipLevelController struct{}
|
||||
|
||||
// NewVipLevelController 创建VIP等级控制器实例
|
||||
func NewVipLevelController() *VipLevelController {
|
||||
return &VipLevelController{}
|
||||
}
|
||||
|
||||
// Create 创建VIP等级
|
||||
func (c *VipLevelController) Create(r *ghttp.Request) {
|
||||
service.VipLevel.AdminCreate(r)
|
||||
}
|
||||
|
||||
// Update 更新VIP等级
|
||||
func (c *VipLevelController) Update(r *ghttp.Request) {
|
||||
service.VipLevel.AdminUpdate(r)
|
||||
}
|
||||
|
||||
// List 获取VIP等级列表
|
||||
func (c *VipLevelController) List(r *ghttp.Request) {
|
||||
service.VipLevel.AdminGetList(r)
|
||||
}
|
||||
|
||||
// Detail 获取VIP等级详情
|
||||
func (c *VipLevelController) Detail(r *ghttp.Request) {
|
||||
service.VipLevel.GetDetail(r)
|
||||
}
|
||||
|
||||
// Delete 删除VIP等级
|
||||
func (c *VipLevelController) Delete(r *ghttp.Request) {
|
||||
service.VipLevel.AdminDelete(r)
|
||||
}
|
||||
|
||||
// UpdateStatus 更新VIP等级状态
|
||||
func (c *VipLevelController) UpdateStatus(r *ghttp.Request) {
|
||||
service.VipLevel.AdminUpdateStatus(r)
|
||||
}
|
||||
|
||||
// BatchDelete 批量删除VIP等级
|
||||
func (c *VipLevelController) BatchDelete(r *ghttp.Request) {
|
||||
service.VipLevel.AdminBatchDelete(r)
|
||||
}
|
||||
|
||||
// GetAll 获取所有VIP等级
|
||||
func (c *VipLevelController) GetAll(r *ghttp.Request) {
|
||||
service.VipLevel.GetAll(r)
|
||||
}
|
||||
|
||||
// GetActiveList 获取启用的VIP等级列表
|
||||
func (c *VipLevelController) GetActiveList(r *ghttp.Request) {
|
||||
service.VipLevel.GetActiveList(r)
|
||||
}
|
||||
283
internal/controller/auth/auth.go
Normal file
283
internal/controller/auth/auth.go
Normal file
@@ -0,0 +1,283 @@
|
||||
package auth
|
||||
|
||||
import (
|
||||
"nl-video-api/internal/consts"
|
||||
"nl-video-api/internal/model/entity"
|
||||
"nl-video-api/utility/crypto"
|
||||
"nl-video-api/utility/jwt"
|
||||
"nl-video-api/utility/response"
|
||||
"time"
|
||||
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/net/ghttp"
|
||||
)
|
||||
|
||||
type cAuth struct{}
|
||||
|
||||
var Auth = cAuth{}
|
||||
|
||||
// LoginReq 登录请求
|
||||
type LoginReq struct {
|
||||
Username string `json:"username" v:"required#用户名不能为空"`
|
||||
Password string `json:"password" v:"required#密码不能为空"`
|
||||
}
|
||||
|
||||
// RegisterReq 注册请求
|
||||
type RegisterReq struct {
|
||||
Username string `json:"username" v:"required|length:3,20#用户名不能为空|用户名长度为3-20位"`
|
||||
Phone string `json:"phone" v:"required|phone#手机号不能为空|手机号格式错误"`
|
||||
Password string `json:"password" v:"required|length:6,20#密码不能为空|密码长度为6-20位"`
|
||||
Code string `json:"code" v:"required#验证码不能为空"`
|
||||
}
|
||||
|
||||
// UpdateProfileReq 更新资料请求
|
||||
type UpdateProfileReq struct {
|
||||
Nickname string `json:"nickname" v:"length:1,20#昵称长度为1-20位"`
|
||||
Avatar string `json:"avatar" v:"url#头像格式错误"`
|
||||
Gender int `json:"gender" v:"in:0,1,2#性别参数错误"`
|
||||
Birthday string `json:"birthday" v:"date#生日格式错误"`
|
||||
}
|
||||
|
||||
// Login 用户登录
|
||||
func (c *cAuth) Login(r *ghttp.Request) {
|
||||
var req LoginReq
|
||||
if err := r.Parse(&req); err != nil {
|
||||
response.Error(r, response.CodeInvalidParam, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// 查询用户
|
||||
var user entity.NlUser
|
||||
err := g.DB().Model("nl_user").Where("username = ? OR phone = ?", req.Username, req.Username).Scan(&user)
|
||||
if err != nil || user.Id == 0 {
|
||||
response.Error(r, response.CodeError, "用户名或密码错误")
|
||||
return
|
||||
}
|
||||
|
||||
// 验证密码
|
||||
if !crypto.CheckPassword(req.Password, user.Password) {
|
||||
response.Error(r, response.CodeError, "用户名或密码错误")
|
||||
return
|
||||
}
|
||||
|
||||
// 检查用户状态
|
||||
if user.Status != consts.UserStatusNormal {
|
||||
response.Error(r, response.CodeError, "账号已被禁用")
|
||||
return
|
||||
}
|
||||
|
||||
// 生成Token
|
||||
token, err := jwt.GenerateToken(user.Id, user.Username, consts.UserTypeUser)
|
||||
if err != nil {
|
||||
response.Error(r, response.CodeServerError, "Token生成失败")
|
||||
return
|
||||
}
|
||||
|
||||
// 更新最后登录信息
|
||||
now := int(time.Now().Unix())
|
||||
clientIP := r.GetClientIp()
|
||||
// 将IPv6地址::1转换为IPv4地址127.0.0.1,或者使用IP地址的哈希值
|
||||
if clientIP == "::1" {
|
||||
clientIP = "127.0.0.1"
|
||||
}
|
||||
|
||||
g.DB().Model("nl_user").Where("id", user.Id).Update(g.Map{
|
||||
"last_login_time": now,
|
||||
"last_login_ip": clientIP,
|
||||
"login_count": g.DB().Raw("login_count + 1"),
|
||||
})
|
||||
|
||||
// 格式化用户信息返回
|
||||
userMap := g.Map{
|
||||
"id": user.Id,
|
||||
"username": user.Username,
|
||||
"nick_name": user.NickName,
|
||||
"avatar": user.Avatar,
|
||||
"phone": user.Phone,
|
||||
"email": user.Email,
|
||||
"gender": user.Gender,
|
||||
"vip_level": user.VipLevel,
|
||||
"vip_expire_time": response.FormatTimestamp(user.VipExpireTime),
|
||||
"balance": user.Balance,
|
||||
"points": user.Points,
|
||||
"status": user.Status,
|
||||
"last_login_time": response.FormatTimestamp(now),
|
||||
"created_at": response.FormatTimestamp(user.CreatedAt),
|
||||
"updated_at": response.FormatTimestamp(user.UpdatedAt),
|
||||
}
|
||||
|
||||
response.Success(r, g.Map{
|
||||
"token": token,
|
||||
"user": userMap,
|
||||
})
|
||||
}
|
||||
|
||||
// Register 用户注册
|
||||
func (c *cAuth) Register(r *ghttp.Request) {
|
||||
var req RegisterReq
|
||||
if err := r.Parse(&req); err != nil {
|
||||
response.Error(r, response.CodeInvalidParam, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// 验证验证码(这里简化处理,实际应该验证短信验证码)
|
||||
if req.Code != "123456" {
|
||||
response.Error(r, response.CodeError, "验证码错误")
|
||||
return
|
||||
}
|
||||
|
||||
// 检查用户名是否存在
|
||||
count, _ := g.DB().Model("nl_user").Where("username", req.Username).Count()
|
||||
if count > 0 {
|
||||
response.Error(r, response.CodeError, "用户名已存在")
|
||||
return
|
||||
}
|
||||
|
||||
// 检查手机号是否存在
|
||||
count, _ = g.DB().Model("nl_user").Where("phone", req.Phone).Count()
|
||||
if count > 0 {
|
||||
response.Error(r, response.CodeError, "手机号已注册")
|
||||
return
|
||||
}
|
||||
|
||||
// 加密密码
|
||||
hashedPassword, err := crypto.HashPassword(req.Password)
|
||||
if err != nil {
|
||||
response.Error(r, response.CodeServerError, "密码加密失败")
|
||||
return
|
||||
}
|
||||
|
||||
// 创建用户
|
||||
now := int(time.Now().Unix())
|
||||
userId, err := g.DB().Model("nl_user").InsertAndGetId(g.Map{
|
||||
"username": req.Username,
|
||||
"nick_name": req.Username,
|
||||
"phone": req.Phone,
|
||||
"password": hashedPassword,
|
||||
"vip_level": consts.VipLevelNormal,
|
||||
"status": consts.UserStatusNormal,
|
||||
"created_at": now,
|
||||
"updated_at": now,
|
||||
})
|
||||
if err != nil {
|
||||
response.Error(r, response.CodeServerError, "注册失败")
|
||||
return
|
||||
}
|
||||
|
||||
// 生成Token
|
||||
token, err := jwt.GenerateToken(uint(userId), req.Username, consts.UserTypeUser)
|
||||
if err != nil {
|
||||
response.Error(r, response.CodeServerError, "Token生成失败")
|
||||
return
|
||||
}
|
||||
|
||||
response.Success(r, g.Map{
|
||||
"token": token,
|
||||
"user_id": userId,
|
||||
"message": "注册成功",
|
||||
})
|
||||
}
|
||||
|
||||
// Profile 获取用户信息
|
||||
func (c *cAuth) Profile(r *ghttp.Request) {
|
||||
userId := r.GetCtxVar("user_id").Uint()
|
||||
|
||||
var user entity.NlUser
|
||||
err := g.DB().Model("nl_user").Where("id", userId).Scan(&user)
|
||||
if err != nil {
|
||||
response.Error(r, response.CodeServerError, "获取用户信息失败")
|
||||
return
|
||||
}
|
||||
|
||||
// 格式化用户信息返回
|
||||
userMap := g.Map{
|
||||
"id": user.Id,
|
||||
"username": user.Username,
|
||||
"nick_name": user.NickName,
|
||||
"avatar": user.Avatar,
|
||||
"phone": user.Phone,
|
||||
"email": user.Email,
|
||||
"gender": user.Gender,
|
||||
"birthday": user.Birthday,
|
||||
"vip_level": user.VipLevel,
|
||||
"vip_expire_time": response.FormatTimestamp(user.VipExpireTime),
|
||||
"balance": user.Balance,
|
||||
"points": user.Points,
|
||||
"status": user.Status,
|
||||
"last_login_time": response.FormatTimestamp(user.LastLoginTime),
|
||||
"login_count": user.LoginCount,
|
||||
"desc": user.Desc,
|
||||
"created_at": response.FormatTimestamp(user.CreatedAt),
|
||||
"updated_at": response.FormatTimestamp(user.UpdatedAt),
|
||||
}
|
||||
|
||||
response.Success(r, userMap)
|
||||
}
|
||||
|
||||
// UpdateProfile 更新用户信息
|
||||
func (c *cAuth) UpdateProfile(r *ghttp.Request) {
|
||||
var req UpdateProfileReq
|
||||
if err := r.Parse(&req); err != nil {
|
||||
response.Error(r, response.CodeInvalidParam, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
userId := r.GetCtxVar("user_id").Uint()
|
||||
|
||||
// 构建更新数据
|
||||
updateData := g.Map{
|
||||
"updated_at": int(time.Now().Unix()),
|
||||
}
|
||||
|
||||
if req.Nickname != "" {
|
||||
updateData["nickname"] = req.Nickname
|
||||
}
|
||||
if req.Avatar != "" {
|
||||
updateData["avatar"] = req.Avatar
|
||||
}
|
||||
if req.Gender > 0 {
|
||||
updateData["gender"] = req.Gender
|
||||
}
|
||||
if req.Birthday != "" {
|
||||
updateData["birthday"] = req.Birthday
|
||||
}
|
||||
|
||||
// 更新用户信息
|
||||
_, err := g.DB().Model("nl_user").Where("id", userId).Update(updateData)
|
||||
if err != nil {
|
||||
response.Error(r, response.CodeServerError, "更新失败")
|
||||
return
|
||||
}
|
||||
|
||||
response.Success(r, g.Map{
|
||||
"message": "更新成功",
|
||||
})
|
||||
}
|
||||
|
||||
// Logout 用户登出
|
||||
func (c *cAuth) Logout(r *ghttp.Request) {
|
||||
// 这里可以将token加入黑名单,简化处理直接返回成功
|
||||
response.Success(r, g.Map{
|
||||
"message": "登出成功",
|
||||
})
|
||||
}
|
||||
|
||||
// RefreshToken 刷新Token
|
||||
func (c *cAuth) RefreshToken(r *ghttp.Request) {
|
||||
authHeader := r.Header.Get("Authorization")
|
||||
if authHeader == "" {
|
||||
response.Error(r, response.CodeUnauthorized, "请提供认证令牌")
|
||||
return
|
||||
}
|
||||
|
||||
tokenString := authHeader[7:] // 去掉 "Bearer "
|
||||
newToken, err := jwt.RefreshToken(tokenString)
|
||||
if err != nil {
|
||||
response.Error(r, response.CodeTokenInvalid, "Token刷新失败")
|
||||
return
|
||||
}
|
||||
|
||||
response.Success(r, g.Map{
|
||||
"token": newToken,
|
||||
})
|
||||
}
|
||||
5
internal/controller/hello/hello.go
Normal file
5
internal/controller/hello/hello.go
Normal file
@@ -0,0 +1,5 @@
|
||||
// =================================================================================
|
||||
// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish.
|
||||
// =================================================================================
|
||||
|
||||
package hello
|
||||
16
internal/controller/hello/hello_new.go
Normal file
16
internal/controller/hello/hello_new.go
Normal file
@@ -0,0 +1,16 @@
|
||||
// =================================================================================
|
||||
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
|
||||
// =================================================================================
|
||||
|
||||
package hello
|
||||
|
||||
import (
|
||||
"nl-video-api/api/hello"
|
||||
)
|
||||
|
||||
type ControllerV1 struct{}
|
||||
|
||||
func NewV1() hello.IHelloV1 {
|
||||
return &ControllerV1{}
|
||||
}
|
||||
|
||||
13
internal/controller/hello/hello_v1_hello.go
Normal file
13
internal/controller/hello/hello_v1_hello.go
Normal file
@@ -0,0 +1,13 @@
|
||||
package hello
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
|
||||
"nl-video-api/api/hello/v1"
|
||||
)
|
||||
|
||||
func (c *ControllerV1) Hello(ctx context.Context, req *v1.HelloReq) (res *v1.HelloRes, err error) {
|
||||
g.RequestFromCtx(ctx).Response.Writeln("Hello World!")
|
||||
return
|
||||
}
|
||||
337
internal/controller/movie/episode.go
Normal file
337
internal/controller/movie/episode.go
Normal file
@@ -0,0 +1,337 @@
|
||||
package movie
|
||||
|
||||
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/service/movie"
|
||||
"nl-video-api/utility/response"
|
||||
)
|
||||
|
||||
// EpisodeController 集数控制器
|
||||
type EpisodeController struct{}
|
||||
|
||||
var Episode = &EpisodeController{}
|
||||
|
||||
// Create 创建集数
|
||||
func (c *EpisodeController) Create(r *ghttp.Request) {
|
||||
var req *movie.EpisodeCreateReq
|
||||
if err := r.Parse(&req); err != nil {
|
||||
response.Error(r, 1001, "参数解析失败: "+err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
episodeService := movie.NewEpisodeService()
|
||||
err := episodeService.Create(r.Context(), req)
|
||||
if err != nil {
|
||||
response.Error(r, 1002, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
response.Success(r, g.Map{
|
||||
"message": "创建成功",
|
||||
"id": req.MovieId,
|
||||
})
|
||||
}
|
||||
|
||||
// Update 更新集数
|
||||
func (c *EpisodeController) Update(r *ghttp.Request) {
|
||||
var req *movie.EpisodeUpdateReq
|
||||
if err := r.Parse(&req); err != nil {
|
||||
response.Error(r, 1001, "参数解析失败: "+err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// 从URL路径获取ID
|
||||
if req.Id == 0 {
|
||||
idStr := r.Get("id").String()
|
||||
if id, err := strconv.Atoi(idStr); err == nil {
|
||||
req.Id = id
|
||||
}
|
||||
}
|
||||
|
||||
if req.Id <= 0 {
|
||||
response.Error(r, 1001, "集数ID无效")
|
||||
return
|
||||
}
|
||||
|
||||
episodeService := movie.NewEpisodeService()
|
||||
err := episodeService.Update(r.Context(), req)
|
||||
if err != nil {
|
||||
response.Error(r, 1002, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
response.Success(r, g.Map{
|
||||
"message": "更新成功",
|
||||
})
|
||||
}
|
||||
|
||||
// GetById 获取集数详情
|
||||
func (c *EpisodeController) GetById(r *ghttp.Request) {
|
||||
idStr := r.Get("id").String()
|
||||
id, err := strconv.Atoi(idStr)
|
||||
if err != nil || id <= 0 {
|
||||
response.Error(r, 1001, "集数ID无效")
|
||||
return
|
||||
}
|
||||
|
||||
episodeService := movie.NewEpisodeService()
|
||||
episode, err := episodeService.GetById(r.Context(), &movie.EpisodeDetailReq{Id: id})
|
||||
if err != nil {
|
||||
response.Error(r, 1002, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
response.Success(r, g.Map{
|
||||
"message": "获取成功",
|
||||
"data": episode,
|
||||
})
|
||||
}
|
||||
|
||||
// GetByMovieId 根据影片ID获取集数列表
|
||||
func (c *EpisodeController) GetByMovieId(r *ghttp.Request) {
|
||||
movieIdStr := r.Get("movie_id").String()
|
||||
movieId, err := strconv.Atoi(movieIdStr)
|
||||
if err != nil || movieId <= 0 {
|
||||
response.Error(r, 1001, "影片ID无效")
|
||||
return
|
||||
}
|
||||
|
||||
episodeService := movie.NewEpisodeService()
|
||||
episodes, err := episodeService.GetByMovieId(r.Context(), movieId)
|
||||
if err != nil {
|
||||
response.Error(r, 1002, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
response.Success(r, g.Map{
|
||||
"message": "获取成功",
|
||||
"list": episodes,
|
||||
"total": len(episodes),
|
||||
"movie_id": movieId,
|
||||
})
|
||||
}
|
||||
|
||||
// Delete 删除集数
|
||||
func (c *EpisodeController) Delete(r *ghttp.Request) {
|
||||
idStr := r.Get("id").String()
|
||||
id, err := strconv.Atoi(idStr)
|
||||
if err != nil || id <= 0 {
|
||||
response.Error(r, 1001, "集数ID无效")
|
||||
return
|
||||
}
|
||||
|
||||
episodeService := movie.NewEpisodeService()
|
||||
err = episodeService.Delete(r.Context(), &movie.EpisodeDeleteReq{Id: id})
|
||||
if err != nil {
|
||||
response.Error(r, 1002, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
response.Success(r, g.Map{
|
||||
"message": "删除成功",
|
||||
})
|
||||
}
|
||||
|
||||
// BatchCreate 批量创建集数
|
||||
func (c *EpisodeController) BatchCreate(r *ghttp.Request) {
|
||||
type BatchCreateReq struct {
|
||||
MovieId int `json:"movie_id" v:"required|min:1#请选择影片"`
|
||||
Episodes []movie.EpisodeCreateReq `json:"episodes" v:"required#集数列表不能为空"`
|
||||
}
|
||||
|
||||
var req BatchCreateReq
|
||||
if err := r.Parse(&req); err != nil {
|
||||
response.Error(r, 1001, "参数解析失败: "+err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
if len(req.Episodes) == 0 {
|
||||
response.Error(r, 1001, "集数列表不能为空")
|
||||
return
|
||||
}
|
||||
|
||||
// 设置影片ID
|
||||
for i := range req.Episodes {
|
||||
req.Episodes[i].MovieId = req.MovieId
|
||||
}
|
||||
|
||||
episodeService := movie.NewEpisodeService()
|
||||
// 由于BatchCreate方法不存在,我们逐个创建
|
||||
successCount := 0
|
||||
for _, episodeReq := range req.Episodes {
|
||||
if err := episodeService.Create(r.Context(), &episodeReq); err != nil {
|
||||
g.Log().Errorf(r.Context(), "创建集数失败: %v", err)
|
||||
} else {
|
||||
successCount++
|
||||
}
|
||||
}
|
||||
|
||||
response.Success(r, g.Map{
|
||||
"message": "批量创建完成",
|
||||
"movie_id": req.MovieId,
|
||||
"total_count": len(req.Episodes),
|
||||
"success_count": successCount,
|
||||
"fail_count": len(req.Episodes) - successCount,
|
||||
})
|
||||
}
|
||||
|
||||
// UploadVideo 上传集数视频
|
||||
func (c *EpisodeController) UploadVideo(r *ghttp.Request) {
|
||||
file := r.GetUploadFile("video")
|
||||
if file == nil {
|
||||
response.Error(r, 1001, "请选择要上传的视频文件")
|
||||
return
|
||||
}
|
||||
|
||||
// 验证文件类型
|
||||
allowedTypes := []string{"video/mp4", "video/avi", "video/mkv", "video/mov", "video/wmv"}
|
||||
isValidType := false
|
||||
for _, allowedType := range allowedTypes {
|
||||
if file.Header.Get("Content-Type") == allowedType {
|
||||
isValidType = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !isValidType {
|
||||
response.Error(r, 1001, "不支持的视频格式")
|
||||
return
|
||||
}
|
||||
|
||||
// 检查文件大小(限制5GB)
|
||||
maxSize := int64(5 * 1024 * 1024 * 1024)
|
||||
if file.Size > maxSize {
|
||||
response.Error(r, 1001, "视频文件过大,最大支持5GB")
|
||||
return
|
||||
}
|
||||
|
||||
// 生成文件名
|
||||
timestamp := gtime.Now().TimestampStr()
|
||||
filename := timestamp + "_" + file.Filename
|
||||
uploadPath := "resource/public/uploads/episodes/" + filename
|
||||
|
||||
// 保存文件
|
||||
if _, err := file.Save(uploadPath); err != nil {
|
||||
response.Error(r, 1002, "视频上传失败: "+err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// 返回文件信息
|
||||
relativePath := "/uploads/episodes/" + filename
|
||||
response.Success(r, g.Map{
|
||||
"message": "上传成功",
|
||||
"url": relativePath,
|
||||
"filename": filename,
|
||||
"size": file.Size,
|
||||
})
|
||||
}
|
||||
|
||||
// GenerateThumbnail 生成缩略图
|
||||
func (c *EpisodeController) GenerateThumbnail(r *ghttp.Request) {
|
||||
videoUrl := r.Get("video_url").String()
|
||||
if videoUrl == "" {
|
||||
response.Error(r, 1001, "视频地址不能为空")
|
||||
return
|
||||
}
|
||||
|
||||
// 生成缩略图文件路径
|
||||
timestamp := gtime.Now().TimestampStr()
|
||||
filename := "thumb_" + timestamp + ".jpg"
|
||||
thumbDir := "resource/public/uploads/thumbnails"
|
||||
_ = thumbDir + "/" + filename // 避免未使用变量错误
|
||||
|
||||
// 提取缩略图 (这里需要实际的视频处理库)
|
||||
// if err := video.ExtractCover(videoUrl, thumbPath); err != nil {
|
||||
// response.Error(r, 1002, "生成缩略图失败: "+err.Error())
|
||||
// return
|
||||
// }
|
||||
|
||||
// 返回缩略图信息
|
||||
relativePath := "/uploads/thumbnails/" + filename
|
||||
response.Success(r, g.Map{
|
||||
"message": "生成成功",
|
||||
"thumbnail": relativePath,
|
||||
"filename": filename,
|
||||
})
|
||||
}
|
||||
|
||||
// GetVideoInfo 获取视频信息
|
||||
func (c *EpisodeController) GetVideoInfo(r *ghttp.Request) {
|
||||
videoUrl := r.Get("video_url").String()
|
||||
if videoUrl == "" {
|
||||
response.Error(r, 1001, "视频地址不能为空")
|
||||
return
|
||||
}
|
||||
|
||||
// 获取视频信息 (这里需要实际的视频处理库)
|
||||
// videoInfo, err := video.GetVideoInfo(videoUrl)
|
||||
// if err != nil {
|
||||
// response.Error(r, 1002, "获取视频信息失败: "+err.Error())
|
||||
// return
|
||||
// }
|
||||
|
||||
// 模拟返回视频信息
|
||||
videoInfo := g.Map{
|
||||
"duration": 0,
|
||||
"width": 1920,
|
||||
"height": 1080,
|
||||
"bitrate": "2000kbps",
|
||||
"format": "mp4",
|
||||
"size": 0,
|
||||
"created_at": "",
|
||||
}
|
||||
|
||||
response.Success(r, g.Map{
|
||||
"message": "获取成功",
|
||||
"data": videoInfo,
|
||||
})
|
||||
}
|
||||
|
||||
// BatchUpdateStatus 批量更新集数状态
|
||||
func (c *EpisodeController) BatchUpdateStatus(r *ghttp.Request) {
|
||||
type BatchUpdateReq struct {
|
||||
Ids []int `json:"ids" v:"required#请选择要操作的集数"`
|
||||
Status int `json:"status" v:"required|in:0,1#状态只能为0或1"`
|
||||
}
|
||||
|
||||
var req BatchUpdateReq
|
||||
if err := r.Parse(&req); err != nil {
|
||||
response.Error(r, 1001, "参数解析失败: "+err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
if len(req.Ids) == 0 {
|
||||
response.Error(r, 1001, "请选择要操作的集数")
|
||||
return
|
||||
}
|
||||
|
||||
ctx := r.Context()
|
||||
successCount := 0
|
||||
failCount := 0
|
||||
|
||||
for _, id := range req.Ids {
|
||||
updateData := g.Map{
|
||||
"status": req.Status,
|
||||
}
|
||||
|
||||
episodeDao := dao.NewEpisodeDao()
|
||||
if err := episodeDao.Update(ctx, id, updateData); err != nil {
|
||||
g.Log().Errorf(ctx, "批量更新集数状态失败: ID=%d, 错误=%v", id, err)
|
||||
failCount++
|
||||
} else {
|
||||
successCount++
|
||||
}
|
||||
}
|
||||
|
||||
response.Success(r, g.Map{
|
||||
"message": "批量更新完成",
|
||||
"success_count": successCount,
|
||||
"fail_count": failCount,
|
||||
"total_count": len(req.Ids),
|
||||
})
|
||||
}
|
||||
418
internal/controller/movie/movie.go
Normal file
418
internal/controller/movie/movie.go
Normal file
@@ -0,0 +1,418 @@
|
||||
package movie
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/net/ghttp"
|
||||
"nl-video-api/internal/service/movie"
|
||||
"nl-video-api/utility/response"
|
||||
)
|
||||
|
||||
// MovieController 影片控制器
|
||||
type MovieController struct{}
|
||||
|
||||
var Movie = &MovieController{}
|
||||
|
||||
// Create 创建影片
|
||||
func (c *MovieController) Create(r *ghttp.Request) {
|
||||
var req *movie.MovieCreateReq
|
||||
if err := r.Parse(&req); err != nil {
|
||||
response.Error(r, 1001, "参数解析失败: "+err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
movieService := movie.NewMovieService()
|
||||
err := movieService.Create(r.Context(), req)
|
||||
if err != nil {
|
||||
response.Error(r, 1002, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
response.Success(r, g.Map{
|
||||
"message": "创建成功",
|
||||
})
|
||||
}
|
||||
|
||||
// Update 更新影片
|
||||
func (c *MovieController) Update(r *ghttp.Request) {
|
||||
var req *movie.MovieUpdateReq
|
||||
if err := r.Parse(&req); err != nil {
|
||||
response.Error(r, 1001, "参数解析失败: "+err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// 从URL路径获取ID
|
||||
if req.Id == 0 {
|
||||
idStr := r.Get("id").String()
|
||||
if id, err := strconv.Atoi(idStr); err == nil {
|
||||
req.Id = id
|
||||
}
|
||||
}
|
||||
|
||||
if req.Id <= 0 {
|
||||
response.Error(r, 1001, "影片ID无效")
|
||||
return
|
||||
}
|
||||
|
||||
movieService := movie.NewMovieService()
|
||||
err := movieService.Update(r.Context(), req)
|
||||
if err != nil {
|
||||
response.Error(r, 1002, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
response.Success(r, g.Map{
|
||||
"message": "更新成功",
|
||||
})
|
||||
}
|
||||
|
||||
// GetById 获取影片详情
|
||||
func (c *MovieController) GetById(r *ghttp.Request) {
|
||||
idStr := r.Get("id").String()
|
||||
id, err := strconv.Atoi(idStr)
|
||||
if err != nil || id <= 0 {
|
||||
response.Error(r, 1001, "影片ID无效")
|
||||
return
|
||||
}
|
||||
|
||||
movieService := movie.NewMovieService()
|
||||
movieDetail, err := movieService.GetById(r.Context(), &movie.MovieDetailReq{Id: id})
|
||||
if err != nil {
|
||||
response.Error(r, 1002, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
response.Success(r, g.Map{
|
||||
"message": "获取成功",
|
||||
"data": movieDetail,
|
||||
})
|
||||
}
|
||||
|
||||
// GetList 获取影片列表
|
||||
func (c *MovieController) GetList(r *ghttp.Request) {
|
||||
var req *movie.MovieListReq
|
||||
if err := r.Parse(&req); err != nil {
|
||||
response.Error(r, 1001, "参数解析失败: "+err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// 设置默认分页参数
|
||||
if req.Page <= 0 {
|
||||
req.Page = 1
|
||||
}
|
||||
if req.PageSize <= 0 {
|
||||
req.PageSize = 10
|
||||
}
|
||||
|
||||
movieService := movie.NewMovieService()
|
||||
result, err := movieService.GetList(r.Context(), req)
|
||||
if err != nil {
|
||||
response.Error(r, 1002, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
response.Success(r, g.Map{
|
||||
"message": "获取成功",
|
||||
"data": result,
|
||||
})
|
||||
}
|
||||
|
||||
// Delete 删除影片
|
||||
func (c *MovieController) Delete(r *ghttp.Request) {
|
||||
idStr := r.Get("id").String()
|
||||
id, err := strconv.Atoi(idStr)
|
||||
if err != nil || id <= 0 {
|
||||
response.Error(r, 1001, "影片ID无效")
|
||||
return
|
||||
}
|
||||
|
||||
movieService := movie.NewMovieService()
|
||||
err = movieService.Delete(r.Context(), &movie.MovieDeleteReq{Id: id})
|
||||
if err != nil {
|
||||
response.Error(r, 1002, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
response.Success(r, g.Map{
|
||||
"message": "删除成功",
|
||||
})
|
||||
}
|
||||
|
||||
// GetHot 获取热门影片
|
||||
func (c *MovieController) GetHot(r *ghttp.Request) {
|
||||
limitStr := r.Get("limit", "10").String()
|
||||
limit, err := strconv.Atoi(limitStr)
|
||||
if err != nil || limit <= 0 {
|
||||
limit = 10
|
||||
}
|
||||
|
||||
movieService := movie.NewMovieService()
|
||||
movies, err := movieService.GetHotMovies(r.Context(), limit)
|
||||
if err != nil {
|
||||
response.Error(r, 1002, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
response.Success(r, g.Map{
|
||||
"message": "获取成功",
|
||||
"data": movies,
|
||||
})
|
||||
}
|
||||
|
||||
// GetRecommend 获取推荐影片
|
||||
func (c *MovieController) GetRecommend(r *ghttp.Request) {
|
||||
limitStr := r.Get("limit", "10").String()
|
||||
limit, err := strconv.Atoi(limitStr)
|
||||
if err != nil || limit <= 0 {
|
||||
limit = 10
|
||||
}
|
||||
|
||||
movieService := movie.NewMovieService()
|
||||
movies, err := movieService.GetRecommendMovies(r.Context(), limit)
|
||||
if err != nil {
|
||||
response.Error(r, 1002, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
response.Success(r, g.Map{
|
||||
"message": "获取成功",
|
||||
"data": movies,
|
||||
})
|
||||
}
|
||||
|
||||
// GetNew 获取最新影片
|
||||
func (c *MovieController) GetNew(r *ghttp.Request) {
|
||||
limitStr := r.Get("limit", "10").String()
|
||||
limit, err := strconv.Atoi(limitStr)
|
||||
if err != nil || limit <= 0 {
|
||||
limit = 10
|
||||
}
|
||||
|
||||
movieService := movie.NewMovieService()
|
||||
movies, err := movieService.GetNewMovies(r.Context(), limit)
|
||||
if err != nil {
|
||||
response.Error(r, 1002, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
response.Success(r, g.Map{
|
||||
"message": "获取成功",
|
||||
"data": movies,
|
||||
})
|
||||
}
|
||||
|
||||
// Search 搜索影片
|
||||
func (c *MovieController) Search(r *ghttp.Request) {
|
||||
keyword := r.Get("keyword").String()
|
||||
if keyword == "" {
|
||||
response.Error(r, 1001, "搜索关键词不能为空")
|
||||
return
|
||||
}
|
||||
|
||||
pageStr := r.Get("page", "1").String()
|
||||
page, err := strconv.Atoi(pageStr)
|
||||
if err != nil || page <= 0 {
|
||||
page = 1
|
||||
}
|
||||
|
||||
pageSizeStr := r.Get("page_size", "10").String()
|
||||
pageSize, err := strconv.Atoi(pageSizeStr)
|
||||
if err != nil || pageSize <= 0 {
|
||||
pageSize = 10
|
||||
}
|
||||
|
||||
movieService := movie.NewMovieService()
|
||||
movies, total, err := movieService.SearchMovies(r.Context(), keyword, page, pageSize)
|
||||
if err != nil {
|
||||
response.Error(r, 1002, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
response.Success(r, g.Map{
|
||||
"message": "搜索成功",
|
||||
"data": g.Map{
|
||||
"list": movies,
|
||||
"total": total,
|
||||
"page": page,
|
||||
"page_size": pageSize,
|
||||
"keyword": keyword,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
// GetByCategory 根据分类获取影片
|
||||
func (c *MovieController) GetByCategory(r *ghttp.Request) {
|
||||
categoryIdStr := r.Get("category_id").String()
|
||||
categoryId, err := strconv.Atoi(categoryIdStr)
|
||||
if err != nil || categoryId <= 0 {
|
||||
response.Error(r, 1001, "分类ID无效")
|
||||
return
|
||||
}
|
||||
|
||||
pageStr := r.Get("page", "1").String()
|
||||
page, err := strconv.Atoi(pageStr)
|
||||
if err != nil || page <= 0 {
|
||||
page = 1
|
||||
}
|
||||
|
||||
pageSizeStr := r.Get("page_size", "10").String()
|
||||
pageSize, err := strconv.Atoi(pageSizeStr)
|
||||
if err != nil || pageSize <= 0 {
|
||||
pageSize = 10
|
||||
}
|
||||
|
||||
movieService := movie.NewMovieService()
|
||||
movies, total, err := movieService.GetMoviesByCategory(r.Context(), categoryId, page, pageSize)
|
||||
if err != nil {
|
||||
response.Error(r, 1002, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
response.Success(r, g.Map{
|
||||
"message": "获取成功",
|
||||
"data": g.Map{
|
||||
"list": movies,
|
||||
"total": total,
|
||||
"page": page,
|
||||
"page_size": pageSize,
|
||||
"category_id": categoryId,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
// UpdateViewCount 更新观看次数
|
||||
func (c *MovieController) UpdateViewCount(r *ghttp.Request) {
|
||||
idStr := r.Get("id").String()
|
||||
id, err := strconv.Atoi(idStr)
|
||||
if err != nil || id <= 0 {
|
||||
response.Error(r, 1001, "影片ID无效")
|
||||
return
|
||||
}
|
||||
|
||||
movieService := movie.NewMovieService()
|
||||
err = movieService.UpdateViewCount(r.Context(), id)
|
||||
if err != nil {
|
||||
response.Error(r, 1002, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
response.Success(r, g.Map{
|
||||
"message": "更新成功",
|
||||
})
|
||||
}
|
||||
|
||||
// UpdateLikeCount 更新点赞数
|
||||
func (c *MovieController) UpdateLikeCount(r *ghttp.Request) {
|
||||
idStr := r.Get("id").String()
|
||||
id, err := strconv.Atoi(idStr)
|
||||
if err != nil || id <= 0 {
|
||||
response.Error(r, 1001, "影片ID无效")
|
||||
return
|
||||
}
|
||||
|
||||
incrementStr := r.Get("increment", "1").String()
|
||||
increment, err := strconv.Atoi(incrementStr)
|
||||
if err != nil {
|
||||
increment = 1
|
||||
}
|
||||
|
||||
movieService := movie.NewMovieService()
|
||||
err = movieService.UpdateLikeCount(r.Context(), id, increment)
|
||||
if err != nil {
|
||||
response.Error(r, 1002, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
response.Success(r, g.Map{
|
||||
"message": "更新成功",
|
||||
})
|
||||
}
|
||||
|
||||
// UpdateCollectCount 更新收藏数
|
||||
func (c *MovieController) UpdateCollectCount(r *ghttp.Request) {
|
||||
idStr := r.Get("id").String()
|
||||
id, err := strconv.Atoi(idStr)
|
||||
if err != nil || id <= 0 {
|
||||
response.Error(r, 1001, "影片ID无效")
|
||||
return
|
||||
}
|
||||
|
||||
incrementStr := r.Get("increment", "1").String()
|
||||
increment, err := strconv.Atoi(incrementStr)
|
||||
if err != nil {
|
||||
increment = 1
|
||||
}
|
||||
|
||||
movieService := movie.NewMovieService()
|
||||
err = movieService.UpdateCollectCount(r.Context(), id, increment)
|
||||
if err != nil {
|
||||
response.Error(r, 1002, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
response.Success(r, g.Map{
|
||||
"message": "更新成功",
|
||||
})
|
||||
}
|
||||
|
||||
// GetStatistics 获取影片统计
|
||||
func (c *MovieController) GetStatistics(r *ghttp.Request) {
|
||||
movieService := movie.NewMovieService()
|
||||
stats, err := movieService.GetStatistics(r.Context())
|
||||
if err != nil {
|
||||
response.Error(r, 1002, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
response.Success(r, g.Map{
|
||||
"message": "获取成功",
|
||||
"data": stats,
|
||||
})
|
||||
}
|
||||
|
||||
// BatchUpdate 批量更新影片
|
||||
func (c *MovieController) BatchUpdate(r *ghttp.Request) {
|
||||
var req struct {
|
||||
Ids []int `json:"ids" v:"required#影片ID列表不能为空"`
|
||||
Status *int `json:"status"`
|
||||
IsVip *int `json:"is_vip"`
|
||||
}
|
||||
|
||||
if err := r.Parse(&req); err != nil {
|
||||
response.Error(r, 1001, "参数解析失败: "+err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
if len(req.Ids) == 0 {
|
||||
response.Error(r, 1001, "影片ID列表不能为空")
|
||||
return
|
||||
}
|
||||
|
||||
// TODO: 实现批量更新逻辑
|
||||
response.Success(r, g.Map{
|
||||
"message": "批量更新成功",
|
||||
})
|
||||
}
|
||||
|
||||
// UploadVideo 上传视频
|
||||
func (c *MovieController) UploadVideo(r *ghttp.Request) {
|
||||
// TODO: 实现视频上传逻辑
|
||||
response.Success(r, g.Map{
|
||||
"message": "视频上传成功",
|
||||
"data": g.Map{
|
||||
"url": "/uploads/videos/example.mp4",
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
// UploadPoster 上传海报
|
||||
func (c *MovieController) UploadPoster(r *ghttp.Request) {
|
||||
// TODO: 实现海报上传逻辑
|
||||
response.Success(r, g.Map{
|
||||
"message": "海报上传成功",
|
||||
"data": g.Map{
|
||||
"url": "/uploads/posters/example.jpg",
|
||||
},
|
||||
})
|
||||
}
|
||||
64
internal/controller/user/attachment.go
Normal file
64
internal/controller/user/attachment.go
Normal file
@@ -0,0 +1,64 @@
|
||||
package user
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/v2/net/ghttp"
|
||||
"nl-video-api/internal/service"
|
||||
)
|
||||
|
||||
// AttachmentController 用户附件管理控制器
|
||||
type AttachmentController struct{}
|
||||
|
||||
// NewAttachmentController 创建用户附件管理控制器实例
|
||||
func NewAttachmentController() *AttachmentController {
|
||||
return &AttachmentController{}
|
||||
}
|
||||
|
||||
// Upload 上传附件
|
||||
func (c *AttachmentController) Upload(r *ghttp.Request) {
|
||||
service.NewAttachmentService().UserUpload(r)
|
||||
}
|
||||
|
||||
// GetList 获取用户附件列表
|
||||
func (c *AttachmentController) GetList(r *ghttp.Request) {
|
||||
service.NewAttachmentService().UserGetList(r)
|
||||
}
|
||||
|
||||
// GetDetail 获取附件详情
|
||||
func (c *AttachmentController) GetDetail(r *ghttp.Request) {
|
||||
service.NewAttachmentService().UserGetDetail(r)
|
||||
}
|
||||
|
||||
// Update 更新附件
|
||||
func (c *AttachmentController) Update(r *ghttp.Request) {
|
||||
service.NewAttachmentService().UserUpdate(r)
|
||||
}
|
||||
|
||||
// Delete 删除附件
|
||||
func (c *AttachmentController) Delete(r *ghttp.Request) {
|
||||
service.NewAttachmentService().UserDelete(r)
|
||||
}
|
||||
|
||||
// Download 下载附件
|
||||
func (c *AttachmentController) Download(r *ghttp.Request) {
|
||||
service.NewAttachmentService().UserDownload(r)
|
||||
}
|
||||
|
||||
// Copy 复制附件
|
||||
func (c *AttachmentController) Copy(r *ghttp.Request) {
|
||||
service.NewAttachmentService().UserCopy(r)
|
||||
}
|
||||
|
||||
// Rename 重命名附件
|
||||
func (c *AttachmentController) Rename(r *ghttp.Request) {
|
||||
service.NewAttachmentService().UserRename(r)
|
||||
}
|
||||
|
||||
// Search 搜索附件
|
||||
func (c *AttachmentController) Search(r *ghttp.Request) {
|
||||
service.NewAttachmentService().UserSearch(r)
|
||||
}
|
||||
|
||||
// GetCategoryList 获取附件分类列表
|
||||
func (c *AttachmentController) GetCategoryList(r *ghttp.Request) {
|
||||
service.NewAttachmentService().UserGetCategoryList(r)
|
||||
}
|
||||
21
internal/controller/user/banner.go
Normal file
21
internal/controller/user/banner.go
Normal file
@@ -0,0 +1,21 @@
|
||||
package user
|
||||
|
||||
import (
|
||||
"nl-video-api/internal/service"
|
||||
|
||||
"github.com/gogf/gf/v2/net/ghttp"
|
||||
)
|
||||
|
||||
var Banner = cBanner{}
|
||||
|
||||
type cBanner struct{}
|
||||
|
||||
// GetList 获取轮播图列表
|
||||
func (c *cBanner) GetList(r *ghttp.Request) {
|
||||
service.Banner.UserGetList(r)
|
||||
}
|
||||
|
||||
// GetDetail 获取轮播图详情
|
||||
func (c *cBanner) GetDetail(r *ghttp.Request) {
|
||||
service.Banner.UserGetDetail(r)
|
||||
}
|
||||
42
internal/controller/user/comment.go
Normal file
42
internal/controller/user/comment.go
Normal file
@@ -0,0 +1,42 @@
|
||||
package user
|
||||
|
||||
import (
|
||||
"nl-video-api/internal/service"
|
||||
|
||||
"github.com/gogf/gf/v2/net/ghttp"
|
||||
)
|
||||
|
||||
// CommentController 评论控制器
|
||||
type CommentController struct{}
|
||||
|
||||
var Comment = &CommentController{}
|
||||
|
||||
// Add 添加评论
|
||||
func (c *CommentController) Add(r *ghttp.Request) {
|
||||
service.Comment.Add(r)
|
||||
}
|
||||
|
||||
// List 评论列表
|
||||
func (c *CommentController) List(r *ghttp.Request) {
|
||||
service.Comment.GetList(r)
|
||||
}
|
||||
|
||||
// Delete 删除评论
|
||||
func (c *CommentController) Delete(r *ghttp.Request) {
|
||||
service.Comment.Delete(r)
|
||||
}
|
||||
|
||||
// Like 点赞评论
|
||||
func (c *CommentController) Like(r *ghttp.Request) {
|
||||
service.Comment.Like(r)
|
||||
}
|
||||
|
||||
// Unlike 取消点赞
|
||||
func (c *CommentController) Unlike(r *ghttp.Request) {
|
||||
service.Comment.Unlike(r)
|
||||
}
|
||||
|
||||
// Report 举报评论
|
||||
func (c *CommentController) Report(r *ghttp.Request) {
|
||||
service.Comment.Report(r)
|
||||
}
|
||||
22
internal/controller/user/config.go
Normal file
22
internal/controller/user/config.go
Normal file
@@ -0,0 +1,22 @@
|
||||
package user
|
||||
|
||||
import (
|
||||
"nl-video-api/internal/service"
|
||||
|
||||
"github.com/gogf/gf/v2/net/ghttp"
|
||||
)
|
||||
|
||||
// ConfigController 系统配置控制器
|
||||
type ConfigController struct{}
|
||||
|
||||
var Config = &ConfigController{}
|
||||
|
||||
// GetList 获取配置列表
|
||||
func (c *ConfigController) GetList(r *ghttp.Request) {
|
||||
service.Config.GetList(r)
|
||||
}
|
||||
|
||||
// GetByKey 根据键获取配置
|
||||
func (c *ConfigController) GetByKey(r *ghttp.Request) {
|
||||
service.Config.GetByKey(r)
|
||||
}
|
||||
17
internal/controller/user/log.go
Normal file
17
internal/controller/user/log.go
Normal file
@@ -0,0 +1,17 @@
|
||||
package user
|
||||
|
||||
import (
|
||||
"nl-video-api/internal/service"
|
||||
|
||||
"github.com/gogf/gf/v2/net/ghttp"
|
||||
)
|
||||
|
||||
// LogController 日志控制器
|
||||
type LogController struct{}
|
||||
|
||||
var Log = &LogController{}
|
||||
|
||||
// GetList 获取日志列表
|
||||
func (c *LogController) GetList(r *ghttp.Request) {
|
||||
service.Log.GetList(r)
|
||||
}
|
||||
37
internal/controller/user/payment_order.go
Normal file
37
internal/controller/user/payment_order.go
Normal file
@@ -0,0 +1,37 @@
|
||||
package user
|
||||
|
||||
import (
|
||||
"nl-video-api/internal/service"
|
||||
|
||||
"github.com/gogf/gf/v2/net/ghttp"
|
||||
)
|
||||
|
||||
// PaymentOrderController 支付订单控制器
|
||||
type PaymentOrderController struct{}
|
||||
|
||||
var PaymentOrder = &PaymentOrderController{}
|
||||
|
||||
// Create 创建支付订单
|
||||
func (c *PaymentOrderController) Create(r *ghttp.Request) {
|
||||
service.PaymentOrder.Create(r)
|
||||
}
|
||||
|
||||
// GetList 获取支付订单列表
|
||||
func (c *PaymentOrderController) GetList(r *ghttp.Request) {
|
||||
service.PaymentOrder.GetList(r)
|
||||
}
|
||||
|
||||
// GetDetail 获取支付订单详情
|
||||
func (c *PaymentOrderController) GetDetail(r *ghttp.Request) {
|
||||
service.PaymentOrder.GetDetail(r)
|
||||
}
|
||||
|
||||
// Pay 支付订单
|
||||
func (c *PaymentOrderController) Pay(r *ghttp.Request) {
|
||||
service.PaymentOrder.Pay(r)
|
||||
}
|
||||
|
||||
// Cancel 取消订单
|
||||
func (c *PaymentOrderController) Cancel(r *ghttp.Request) {
|
||||
service.PaymentOrder.Cancel(r)
|
||||
}
|
||||
49
internal/controller/user/user_collect.go
Normal file
49
internal/controller/user/user_collect.go
Normal file
@@ -0,0 +1,49 @@
|
||||
package user
|
||||
|
||||
import (
|
||||
"nl-video-api/internal/service"
|
||||
|
||||
"github.com/gogf/gf/v2/net/ghttp"
|
||||
)
|
||||
|
||||
// UserCollectController 用户收藏控制器
|
||||
type UserCollectController struct{}
|
||||
|
||||
var UserCollect = &UserCollectController{}
|
||||
|
||||
// Add 添加收藏
|
||||
func (c *UserCollectController) Add(r *ghttp.Request) {
|
||||
service.UserCollect.Add(r)
|
||||
}
|
||||
|
||||
// Remove 取消收藏
|
||||
func (c *UserCollectController) Remove(r *ghttp.Request) {
|
||||
service.UserCollect.Remove(r)
|
||||
}
|
||||
|
||||
// GetList 获取收藏列表
|
||||
func (c *UserCollectController) GetList(r *ghttp.Request) {
|
||||
service.NewUserCollectService().GetList(r)
|
||||
}
|
||||
|
||||
// List 获取收藏列表(别名方法)
|
||||
func (c *UserCollectController) List(r *ghttp.Request) {
|
||||
c.GetList(r)
|
||||
}
|
||||
|
||||
// Check 检查收藏状态
|
||||
func (c *UserCollectController) Check(r *ghttp.Request) {
|
||||
// TODO: 实现检查收藏状态逻辑
|
||||
r.Response.WriteJson(map[string]interface{}{
|
||||
"code": 0,
|
||||
"message": "检查成功",
|
||||
"data": map[string]interface{}{
|
||||
"is_collected": false,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
// CheckCollect 检查是否已收藏
|
||||
func (c *UserCollectController) CheckCollect(r *ghttp.Request) {
|
||||
service.UserCollect.CheckCollect(r)
|
||||
}
|
||||
80
internal/controller/user/user_watch_history.go
Normal file
80
internal/controller/user/user_watch_history.go
Normal file
@@ -0,0 +1,80 @@
|
||||
package user
|
||||
|
||||
import (
|
||||
"nl-video-api/internal/service"
|
||||
"github.com/gogf/gf/v2/net/ghttp"
|
||||
)
|
||||
|
||||
// UserWatchHistoryController 用户观看历史控制器
|
||||
type UserWatchHistoryController struct{}
|
||||
|
||||
var UserWatchHistory = &UserWatchHistoryController{}
|
||||
|
||||
// Add 添加观看历史
|
||||
func (c *UserWatchHistoryController) Add(r *ghttp.Request) {
|
||||
service.NewUserWatchHistoryService().Add(r)
|
||||
}
|
||||
|
||||
// GetList 获取观看历史列表
|
||||
func (c *UserWatchHistoryController) GetList(r *ghttp.Request) {
|
||||
service.NewUserWatchHistoryService().GetList(r)
|
||||
}
|
||||
|
||||
// Delete 删除观看历史
|
||||
func (c *UserWatchHistoryController) Delete(r *ghttp.Request) {
|
||||
service.NewUserWatchHistoryService().Delete(r)
|
||||
}
|
||||
|
||||
// Clear 清空观看历史
|
||||
func (c *UserWatchHistoryController) Clear(r *ghttp.Request) {
|
||||
// 获取用户ID(需要实现GetUserIdFromContext函数)
|
||||
userId := service.GetUserIdFromContext(r.Context())
|
||||
if userId == 0 {
|
||||
r.Response.WriteJson(map[string]interface{}{
|
||||
"code": 401,
|
||||
"message": "请先登录",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
err := service.NewUserWatchHistoryService().Clear(r.Context(), &service.UserWatchHistoryClearReq{
|
||||
UserId: uint(userId),
|
||||
})
|
||||
if err != nil {
|
||||
r.Response.WriteJson(map[string]interface{}{
|
||||
"code": 1002,
|
||||
"message": err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
r.Response.WriteJson(map[string]interface{}{
|
||||
"code": 0,
|
||||
"message": "清空成功",
|
||||
})
|
||||
}
|
||||
|
||||
// GetProgress 获取观看进度
|
||||
func (c *UserWatchHistoryController) GetProgress(r *ghttp.Request) {
|
||||
service.NewUserWatchHistoryService().GetProgress(r)
|
||||
}
|
||||
|
||||
// List 获取观看历史列表(别名方法)
|
||||
func (c *UserWatchHistoryController) List(r *ghttp.Request) {
|
||||
c.GetList(r)
|
||||
}
|
||||
|
||||
// Get 获取单个观看历史记录
|
||||
func (c *UserWatchHistoryController) Get(r *ghttp.Request) {
|
||||
// TODO: 实现获取单个观看历史记录逻辑
|
||||
r.Response.WriteJson(map[string]interface{}{
|
||||
"code": 0,
|
||||
"message": "获取成功",
|
||||
"data": map[string]interface{}{
|
||||
"id": 1,
|
||||
"movie_id": 1,
|
||||
"progress": 50,
|
||||
"watch_time": 3600,
|
||||
},
|
||||
})
|
||||
}
|
||||
27
internal/controller/user/vip_level.go
Normal file
27
internal/controller/user/vip_level.go
Normal file
@@ -0,0 +1,27 @@
|
||||
package user
|
||||
|
||||
import (
|
||||
"nl-video-api/internal/service"
|
||||
|
||||
"github.com/gogf/gf/v2/net/ghttp"
|
||||
)
|
||||
|
||||
// VipLevelController VIP等级控制器
|
||||
type VipLevelController struct{}
|
||||
|
||||
var VipLevel = &VipLevelController{}
|
||||
|
||||
// GetList 获取VIP等级列表
|
||||
func (c *VipLevelController) GetList(r *ghttp.Request) {
|
||||
service.VipLevel.GetList(r)
|
||||
}
|
||||
|
||||
// GetAll 获取所有VIP等级
|
||||
func (c *VipLevelController) GetAll(r *ghttp.Request) {
|
||||
service.VipLevel.GetAll(r)
|
||||
}
|
||||
|
||||
// GetDetail 获取VIP等级详情
|
||||
func (c *VipLevelController) GetDetail(r *ghttp.Request) {
|
||||
service.VipLevel.GetDetail(r)
|
||||
}
|
||||
0
internal/dao/.gitkeep
Normal file
0
internal/dao/.gitkeep
Normal file
82
internal/dao/admin_log.go
Normal file
82
internal/dao/admin_log.go
Normal file
@@ -0,0 +1,82 @@
|
||||
// =================================================================================
|
||||
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
|
||||
// =================================================================================
|
||||
|
||||
package dao
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/gogf/gf/v2/database/gdb"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
)
|
||||
|
||||
// internalAdminLogDao is internal type for wrapping internal DAO implements.
|
||||
type internalAdminLogDao struct {
|
||||
table string // table is the underlying table name of the DAO.
|
||||
group string // group is the database configuration group name of current DAO.
|
||||
columns AdminLogColumns // columns contains all the column names of Table for convenient usage.
|
||||
}
|
||||
|
||||
// AdminLogColumns defines and stores column names for table nl_admin_log.
|
||||
type AdminLogColumns struct {
|
||||
Id string // 日志ID
|
||||
AdminId string // 管理员ID
|
||||
Action string // 操作动作
|
||||
Module string // 操作模块
|
||||
Content string // 操作内容
|
||||
Ip string // IP地址
|
||||
UserAgent string // 用户代理
|
||||
CreatedAt string // 创建时间
|
||||
}
|
||||
|
||||
// adminLogColumns holds the columns for table nl_admin_log.
|
||||
var adminLogColumns = AdminLogColumns{
|
||||
Id: "id",
|
||||
AdminId: "admin_id",
|
||||
Action: "action",
|
||||
Module: "module",
|
||||
Content: "content",
|
||||
Ip: "ip",
|
||||
UserAgent: "user_agent",
|
||||
CreatedAt: "created_at",
|
||||
}
|
||||
|
||||
// NewAdminLogDao creates and returns a new DAO object for table data access.
|
||||
func NewAdminLogDao() *internalAdminLogDao {
|
||||
return &internalAdminLogDao{
|
||||
group: "default",
|
||||
table: "nl_admin_log",
|
||||
columns: adminLogColumns,
|
||||
}
|
||||
}
|
||||
|
||||
// DB retrieves and returns the underlying raw database management object of current DAO.
|
||||
func (dao *internalAdminLogDao) DB() gdb.DB {
|
||||
return g.DB(dao.group)
|
||||
}
|
||||
|
||||
// Table returns the table name of current dao.
|
||||
func (dao *internalAdminLogDao) Table() string {
|
||||
return dao.table
|
||||
}
|
||||
|
||||
// Columns returns the columns of current dao.
|
||||
func (dao *internalAdminLogDao) Columns() AdminLogColumns {
|
||||
return dao.columns
|
||||
}
|
||||
|
||||
// Group returns the configuration group name of database of current dao.
|
||||
func (dao *internalAdminLogDao) Group() string {
|
||||
return dao.group
|
||||
}
|
||||
|
||||
// Ctx creates and returns the Model for current DAO, It automatically sets the context for current operation.
|
||||
func (dao *internalAdminLogDao) Ctx(ctx context.Context) *gdb.Model {
|
||||
return dao.DB().Model(dao.table).Safe().Ctx(ctx)
|
||||
}
|
||||
|
||||
// Transaction wraps the transaction logic using function f.
|
||||
func (dao *internalAdminLogDao) Transaction(ctx context.Context, f func(ctx context.Context, tx gdb.TX) error) error {
|
||||
return dao.Ctx(ctx).Transaction(ctx, f)
|
||||
}
|
||||
88
internal/dao/attachment.go
Normal file
88
internal/dao/attachment.go
Normal file
@@ -0,0 +1,88 @@
|
||||
// =================================================================================
|
||||
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
|
||||
// =================================================================================
|
||||
|
||||
package dao
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/gogf/gf/v2/database/gdb"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
)
|
||||
|
||||
// internalAttachmentDao is internal type for wrapping internal DAO implements.
|
||||
type internalAttachmentDao struct {
|
||||
table string // table is the underlying table name of the DAO.
|
||||
group string // group is the database configuration group name of current DAO.
|
||||
columns AttachmentColumns // columns contains all the column names of Table for convenient usage.
|
||||
}
|
||||
|
||||
// AttachmentColumns defines and stores column names for table nl_attachment.
|
||||
type AttachmentColumns struct {
|
||||
Id string // 附件ID
|
||||
Name string // 文件名
|
||||
Path string // 文件路径
|
||||
Url string // 访问URL
|
||||
Size string // 文件大小(字节)
|
||||
MimeType string // 文件类型
|
||||
Extension string // 文件扩展名
|
||||
UserId string // 上传用户ID
|
||||
Status string // 状态:0禁用,1启用
|
||||
CreatedAt string // 创建时间
|
||||
UpdatedAt string // 更新时间
|
||||
}
|
||||
|
||||
// attachmentColumns holds the columns for table nl_attachment.
|
||||
var attachmentColumns = AttachmentColumns{
|
||||
Id: "id",
|
||||
Name: "name",
|
||||
Path: "path",
|
||||
Url: "url",
|
||||
Size: "size",
|
||||
MimeType: "mime_type",
|
||||
Extension: "extension",
|
||||
UserId: "user_id",
|
||||
Status: "status",
|
||||
CreatedAt: "created_at",
|
||||
UpdatedAt: "updated_at",
|
||||
}
|
||||
|
||||
// NewAttachmentDao creates and returns a new DAO object for table data access.
|
||||
func NewAttachmentDao() *internalAttachmentDao {
|
||||
return &internalAttachmentDao{
|
||||
group: "default",
|
||||
table: "nl_attachment",
|
||||
columns: attachmentColumns,
|
||||
}
|
||||
}
|
||||
|
||||
// DB retrieves and returns the underlying raw database management object of current DAO.
|
||||
func (dao *internalAttachmentDao) DB() gdb.DB {
|
||||
return g.DB(dao.group)
|
||||
}
|
||||
|
||||
// Table returns the table name of current dao.
|
||||
func (dao *internalAttachmentDao) Table() string {
|
||||
return dao.table
|
||||
}
|
||||
|
||||
// Columns returns the columns of current dao.
|
||||
func (dao *internalAttachmentDao) Columns() AttachmentColumns {
|
||||
return dao.columns
|
||||
}
|
||||
|
||||
// Group returns the configuration group name of database of current dao.
|
||||
func (dao *internalAttachmentDao) Group() string {
|
||||
return dao.group
|
||||
}
|
||||
|
||||
// Ctx creates and returns the Model for current DAO, It automatically sets the context for current operation.
|
||||
func (dao *internalAttachmentDao) Ctx(ctx context.Context) *gdb.Model {
|
||||
return dao.DB().Model(dao.table).Safe().Ctx(ctx)
|
||||
}
|
||||
|
||||
// Transaction wraps the transaction logic using function f.
|
||||
func (dao *internalAttachmentDao) Transaction(ctx context.Context, f func(ctx context.Context, tx gdb.TX) error) error {
|
||||
return dao.Ctx(ctx).Transaction(ctx, f)
|
||||
}
|
||||
82
internal/dao/banner.go
Normal file
82
internal/dao/banner.go
Normal file
@@ -0,0 +1,82 @@
|
||||
// =================================================================================
|
||||
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
|
||||
// =================================================================================
|
||||
|
||||
package dao
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/gogf/gf/v2/database/gdb"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
)
|
||||
|
||||
// internalBannerDao is internal type for wrapping internal DAO implements.
|
||||
type internalBannerDao struct {
|
||||
table string // table is the underlying table name of the DAO.
|
||||
group string // group is the database configuration group name of current DAO.
|
||||
columns BannerColumns // columns contains all the column names of Table for convenient usage.
|
||||
}
|
||||
|
||||
// BannerColumns defines and stores column names for table nl_banner.
|
||||
type BannerColumns struct {
|
||||
Id string // 轮播图ID
|
||||
Title string // 轮播图标题
|
||||
ImageUrl string // 图片URL
|
||||
LinkUrl string // 跳转链接
|
||||
Sort string // 排序
|
||||
Status string // 状态:0禁用,1启用
|
||||
CreatedAt string // 创建时间
|
||||
UpdatedAt string // 更新时间
|
||||
}
|
||||
|
||||
// bannerColumns holds the columns for table nl_banner.
|
||||
var bannerColumns = BannerColumns{
|
||||
Id: "id",
|
||||
Title: "title",
|
||||
ImageUrl: "image_url",
|
||||
LinkUrl: "link_url",
|
||||
Sort: "sort",
|
||||
Status: "status",
|
||||
CreatedAt: "created_at",
|
||||
UpdatedAt: "updated_at",
|
||||
}
|
||||
|
||||
// NewBannerDao creates and returns a new DAO object for table data access.
|
||||
func NewBannerDao() *internalBannerDao {
|
||||
return &internalBannerDao{
|
||||
group: "default",
|
||||
table: "nl_banner",
|
||||
columns: bannerColumns,
|
||||
}
|
||||
}
|
||||
|
||||
// DB retrieves and returns the underlying raw database management object of current DAO.
|
||||
func (dao *internalBannerDao) DB() gdb.DB {
|
||||
return g.DB(dao.group)
|
||||
}
|
||||
|
||||
// Table returns the table name of current dao.
|
||||
func (dao *internalBannerDao) Table() string {
|
||||
return dao.table
|
||||
}
|
||||
|
||||
// Columns returns the columns of current dao.
|
||||
func (dao *internalBannerDao) Columns() BannerColumns {
|
||||
return dao.columns
|
||||
}
|
||||
|
||||
// Group returns the configuration group name of database of current dao.
|
||||
func (dao *internalBannerDao) Group() string {
|
||||
return dao.group
|
||||
}
|
||||
|
||||
// Ctx creates and returns the Model for current DAO, It automatically sets the context for current operation.
|
||||
func (dao *internalBannerDao) Ctx(ctx context.Context) *gdb.Model {
|
||||
return dao.DB().Model(dao.table).Safe().Ctx(ctx)
|
||||
}
|
||||
|
||||
// Transaction wraps the transaction logic using function f.
|
||||
func (dao *internalBannerDao) Transaction(ctx context.Context, f func(ctx context.Context, tx gdb.TX) error) error {
|
||||
return dao.Ctx(ctx).Transaction(ctx, f)
|
||||
}
|
||||
84
internal/dao/comment.go
Normal file
84
internal/dao/comment.go
Normal file
@@ -0,0 +1,84 @@
|
||||
// =================================================================================
|
||||
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
|
||||
// =================================================================================
|
||||
|
||||
package dao
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/gogf/gf/v2/database/gdb"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
)
|
||||
|
||||
// internalCommentDao is internal type for wrapping internal DAO implements.
|
||||
type internalCommentDao struct {
|
||||
table string // table is the underlying table name of the DAO.
|
||||
group string // group is the database configuration group name of current DAO.
|
||||
columns CommentColumns // columns contains all the column names of Table for convenient usage.
|
||||
}
|
||||
|
||||
// CommentColumns defines and stores column names for table nl_comment.
|
||||
type CommentColumns struct {
|
||||
Id string // 评论ID
|
||||
UserId string // 用户ID
|
||||
MovieId string // 影片ID
|
||||
ParentId string // 父评论ID,0为顶级评论
|
||||
Content string // 评论内容
|
||||
LikeCount string // 点赞数
|
||||
Status string // 状态:0待审核,1已通过,2已拒绝
|
||||
CreatedAt string // 创建时间
|
||||
UpdatedAt string // 更新时间
|
||||
}
|
||||
|
||||
// commentColumns holds the columns for table nl_comment.
|
||||
var commentColumns = CommentColumns{
|
||||
Id: "id",
|
||||
UserId: "user_id",
|
||||
MovieId: "movie_id",
|
||||
ParentId: "parent_id",
|
||||
Content: "content",
|
||||
LikeCount: "like_count",
|
||||
Status: "status",
|
||||
CreatedAt: "created_at",
|
||||
UpdatedAt: "updated_at",
|
||||
}
|
||||
|
||||
// NewCommentDao creates and returns a new DAO object for table data access.
|
||||
func NewCommentDao() *internalCommentDao {
|
||||
return &internalCommentDao{
|
||||
group: "default",
|
||||
table: "nl_comment",
|
||||
columns: commentColumns,
|
||||
}
|
||||
}
|
||||
|
||||
// DB retrieves and returns the underlying raw database management object of current DAO.
|
||||
func (dao *internalCommentDao) DB() gdb.DB {
|
||||
return g.DB(dao.group)
|
||||
}
|
||||
|
||||
// Table returns the table name of current dao.
|
||||
func (dao *internalCommentDao) Table() string {
|
||||
return dao.table
|
||||
}
|
||||
|
||||
// Columns returns the columns of current dao.
|
||||
func (dao *internalCommentDao) Columns() CommentColumns {
|
||||
return dao.columns
|
||||
}
|
||||
|
||||
// Group returns the configuration group name of database of current dao.
|
||||
func (dao *internalCommentDao) Group() string {
|
||||
return dao.group
|
||||
}
|
||||
|
||||
// Ctx creates and returns the Model for current DAO, It automatically sets the context for current operation.
|
||||
func (dao *internalCommentDao) Ctx(ctx context.Context) *gdb.Model {
|
||||
return dao.DB().Model(dao.table).Safe().Ctx(ctx)
|
||||
}
|
||||
|
||||
// Transaction wraps the transaction logic using function f.
|
||||
func (dao *internalCommentDao) Transaction(ctx context.Context, f func(ctx context.Context, tx gdb.TX) error) error {
|
||||
return dao.Ctx(ctx).Transaction(ctx, f)
|
||||
}
|
||||
20
internal/dao/comment_like.go
Normal file
20
internal/dao/comment_like.go
Normal file
@@ -0,0 +1,20 @@
|
||||
// =================================================================================
|
||||
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
|
||||
// =================================================================================
|
||||
|
||||
package dao
|
||||
|
||||
import (
|
||||
"nl-video-api/internal/dao/internal"
|
||||
)
|
||||
|
||||
// internalCommentLikeDao is internal type for wrapping internal DAO implements.
|
||||
type internalCommentLikeDao = *internal.CommentLikeDao
|
||||
|
||||
// commentLikeDao is the data access object for table comment_like.
|
||||
// You can define custom methods on it to extend its functionality as you wish.
|
||||
type commentLikeDao struct {
|
||||
internalCommentLikeDao
|
||||
}
|
||||
|
||||
// Fill with you ideas below.
|
||||
20
internal/dao/comment_report.go
Normal file
20
internal/dao/comment_report.go
Normal file
@@ -0,0 +1,20 @@
|
||||
// =================================================================================
|
||||
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
|
||||
// =================================================================================
|
||||
|
||||
package dao
|
||||
|
||||
import (
|
||||
"nl-video-api/internal/dao/internal"
|
||||
)
|
||||
|
||||
// internalCommentReportDao is internal type for wrapping internal DAO implements.
|
||||
type internalCommentReportDao = *internal.CommentReportDao
|
||||
|
||||
// commentReportDao is the data access object for table comment_report.
|
||||
// You can define custom methods on it to extend its functionality as you wish.
|
||||
type commentReportDao struct {
|
||||
internalCommentReportDao
|
||||
}
|
||||
|
||||
// Fill with you ideas below.
|
||||
82
internal/dao/config.go
Normal file
82
internal/dao/config.go
Normal file
@@ -0,0 +1,82 @@
|
||||
// =================================================================================
|
||||
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
|
||||
// =================================================================================
|
||||
|
||||
package dao
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/gogf/gf/v2/database/gdb"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
)
|
||||
|
||||
// internalConfigDao is internal type for wrapping internal DAO implements.
|
||||
type internalConfigDao struct {
|
||||
table string // table is the underlying table name of the DAO.
|
||||
group string // group is the database configuration group name of current DAO.
|
||||
columns ConfigColumns // columns contains all the column names of Table for convenient usage.
|
||||
}
|
||||
|
||||
// ConfigColumns defines and stores column names for table nl_config.
|
||||
type ConfigColumns struct {
|
||||
Id string // 配置ID
|
||||
ConfigKey string // 配置键
|
||||
ConfigValue string // 配置值
|
||||
ConfigType string // 配置类型
|
||||
Description string // 配置描述
|
||||
Status string // 状态:0禁用,1启用
|
||||
CreatedAt string // 创建时间
|
||||
UpdatedAt string // 更新时间
|
||||
}
|
||||
|
||||
// configColumns holds the columns for table nl_config.
|
||||
var configColumns = ConfigColumns{
|
||||
Id: "id",
|
||||
ConfigKey: "config_key",
|
||||
ConfigValue: "config_value",
|
||||
ConfigType: "config_type",
|
||||
Description: "description",
|
||||
Status: "status",
|
||||
CreatedAt: "created_at",
|
||||
UpdatedAt: "updated_at",
|
||||
}
|
||||
|
||||
// NewConfigDao creates and returns a new DAO object for table data access.
|
||||
func NewConfigDao() *internalConfigDao {
|
||||
return &internalConfigDao{
|
||||
group: "default",
|
||||
table: "nl_config",
|
||||
columns: configColumns,
|
||||
}
|
||||
}
|
||||
|
||||
// DB retrieves and returns the underlying raw database management object of current DAO.
|
||||
func (dao *internalConfigDao) DB() gdb.DB {
|
||||
return g.DB(dao.group)
|
||||
}
|
||||
|
||||
// Table returns the table name of current dao.
|
||||
func (dao *internalConfigDao) Table() string {
|
||||
return dao.table
|
||||
}
|
||||
|
||||
// Columns returns the columns of current dao.
|
||||
func (dao *internalConfigDao) Columns() ConfigColumns {
|
||||
return dao.columns
|
||||
}
|
||||
|
||||
// Group returns the configuration group name of database of current dao.
|
||||
func (dao *internalConfigDao) Group() string {
|
||||
return dao.group
|
||||
}
|
||||
|
||||
// Ctx creates and returns the Model for current DAO, It automatically sets the context for current operation.
|
||||
func (dao *internalConfigDao) Ctx(ctx context.Context) *gdb.Model {
|
||||
return dao.DB().Model(dao.table).Safe().Ctx(ctx)
|
||||
}
|
||||
|
||||
// Transaction wraps the transaction logic using function f.
|
||||
func (dao *internalConfigDao) Transaction(ctx context.Context, f func(ctx context.Context, tx gdb.TX) error) error {
|
||||
return dao.Ctx(ctx).Transaction(ctx, f)
|
||||
}
|
||||
109
internal/dao/episode.go
Normal file
109
internal/dao/episode.go
Normal file
@@ -0,0 +1,109 @@
|
||||
package dao
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/os/gtime"
|
||||
"nl-video-api/internal/model/entity"
|
||||
)
|
||||
|
||||
// EpisodeDao 集数数据访问对象
|
||||
type EpisodeDao struct{}
|
||||
|
||||
// episodeDao 集数DAO实例
|
||||
var episodeDao = &EpisodeDao{}
|
||||
|
||||
// NewEpisodeDao 创建集数DAO实例
|
||||
func NewEpisodeDao() *EpisodeDao {
|
||||
return episodeDao
|
||||
}
|
||||
|
||||
// GetByMovieId 根据影片ID获取集数列表
|
||||
func (d *EpisodeDao) GetByMovieId(ctx context.Context, movieId int) ([]*entity.Episode, error) {
|
||||
var episodes []*entity.Episode
|
||||
err := g.DB().Model("nl_episode").
|
||||
Where("movie_id = ? AND deleted_at = 0", movieId).
|
||||
Order("episode_num ASC, sort ASC").
|
||||
Scan(&episodes)
|
||||
return episodes, err
|
||||
}
|
||||
|
||||
// GetById 根据ID获取集数详情
|
||||
func (d *EpisodeDao) GetById(ctx context.Context, id int) (*entity.Episode, error) {
|
||||
var episode *entity.Episode
|
||||
err := g.DB().Model("nl_episode").
|
||||
Where("id = ? AND deleted_at = 0", id).
|
||||
Scan(&episode)
|
||||
return episode, err
|
||||
}
|
||||
|
||||
// Create 创建集数
|
||||
func (d *EpisodeDao) Create(ctx context.Context, episode *entity.Episode) (int64, error) {
|
||||
result, err := g.DB().Model("nl_episode").Data(episode).Insert()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return result.LastInsertId()
|
||||
}
|
||||
|
||||
// Update 更新集数
|
||||
func (d *EpisodeDao) Update(ctx context.Context, id int, data g.Map) error {
|
||||
data["updated_at"] = gtime.Now().Unix()
|
||||
_, err := g.DB().Model("nl_episode").Where("id = ?", id).Data(data).Update()
|
||||
return err
|
||||
}
|
||||
|
||||
// Delete 删除集数(软删除)
|
||||
func (d *EpisodeDao) Delete(ctx context.Context, id int) error {
|
||||
_, err := g.DB().Model("nl_episode").Where("id = ?", id).Data(g.Map{
|
||||
"deleted_at": gtime.Now().Unix(),
|
||||
"updated_at": gtime.Now().Unix(),
|
||||
}).Update()
|
||||
return err
|
||||
}
|
||||
|
||||
// UpdateViewCount 更新观看次数
|
||||
func (d *EpisodeDao) UpdateViewCount(ctx context.Context, id int) error {
|
||||
_, err := g.DB().Model("nl_episode").Where("id = ?", id).Increment("view_count", 1)
|
||||
return err
|
||||
}
|
||||
|
||||
// GetMaxEpisodeNum 获取影片的最大集数
|
||||
func (d *EpisodeDao) GetMaxEpisodeNum(ctx context.Context, movieId int) (int, error) {
|
||||
var maxNum int
|
||||
err := g.DB().Model("nl_episode").
|
||||
Where("movie_id = ? AND deleted_at = 0", movieId).
|
||||
Fields("MAX(episode_num) as max_num").
|
||||
Scan(&maxNum)
|
||||
return maxNum, err
|
||||
}
|
||||
|
||||
// BatchCreate 批量创建集数
|
||||
func (d *EpisodeDao) BatchCreate(ctx context.Context, episodes []*entity.Episode) error {
|
||||
if len(episodes) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
_, err := g.DB().Model("nl_episode").Data(episodes).Insert()
|
||||
return err
|
||||
}
|
||||
|
||||
// GetEpisodesByRange 获取指定范围的集数
|
||||
func (d *EpisodeDao) GetEpisodesByRange(ctx context.Context, movieId, startNum, endNum int) ([]*entity.Episode, error) {
|
||||
var episodes []*entity.Episode
|
||||
err := g.DB().Model("nl_episode").
|
||||
Where("movie_id = ? AND episode_num >= ? AND episode_num <= ? AND deleted_at = 0",
|
||||
movieId, startNum, endNum).
|
||||
Order("episode_num ASC").
|
||||
Scan(&episodes)
|
||||
return episodes, err
|
||||
}
|
||||
|
||||
// CheckEpisodeExists 检查集数是否存在
|
||||
func (d *EpisodeDao) CheckEpisodeExists(ctx context.Context, movieId, episodeNum int) (bool, error) {
|
||||
count, err := g.DB().Model("nl_episode").
|
||||
Where("movie_id = ? AND episode_num = ? AND deleted_at = 0", movieId, episodeNum).
|
||||
Count()
|
||||
return count > 0, err
|
||||
}
|
||||
75
internal/dao/internal.go
Normal file
75
internal/dao/internal.go
Normal file
@@ -0,0 +1,75 @@
|
||||
// =================================================================================
|
||||
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
|
||||
// =================================================================================
|
||||
|
||||
package dao
|
||||
|
||||
import (
|
||||
"nl-video-api/internal/dao/internal"
|
||||
)
|
||||
|
||||
// internalDao is internal type for wrapping internal DAO implements.
|
||||
type internalDao = *internal.Dao
|
||||
|
||||
// Internal returns the internal DAO implements.
|
||||
func Internal() internalDao {
|
||||
return internal.New()
|
||||
}
|
||||
|
||||
// New returns the DAO implements.
|
||||
func New() *internal.Dao {
|
||||
return internal.New()
|
||||
}
|
||||
|
||||
var (
|
||||
// User is globally public accessible object for table nl_user operations.
|
||||
User = NewUserDao()
|
||||
|
||||
// Movie is globally public accessible object for table nl_movie operations.
|
||||
Movie = NewMovieDao()
|
||||
|
||||
// Episode is globally public accessible object for table nl_episode operations.
|
||||
Episode = NewEpisodeDao()
|
||||
|
||||
// Role is globally public accessible object for table nl_role operations.
|
||||
Role = &RoleDao{}
|
||||
|
||||
// Permission is globally public accessible object for table nl_permission operations.
|
||||
Permission = &PermissionDao{}
|
||||
|
||||
// UserCollect is globally public accessible object for table nl_user_collect operations.
|
||||
UserCollect = NewUserCollectDao()
|
||||
|
||||
// UserWatchHistory is globally public accessible object for table nl_user_watch_history operations.
|
||||
UserWatchHistory = NewUserWatchHistoryDao()
|
||||
|
||||
// Comment is globally public accessible object for table nl_comment operations.
|
||||
Comment = NewCommentDao()
|
||||
|
||||
// Banner is globally public accessible object for table nl_banner operations.
|
||||
Banner = NewBannerDao()
|
||||
|
||||
// PaymentOrder is globally public accessible object for table nl_payment_order operations.
|
||||
PaymentOrder = NewPaymentOrderDao()
|
||||
|
||||
// VipLevel is globally public accessible object for table nl_vip_level operations.
|
||||
VipLevel = NewVipLevelDao()
|
||||
|
||||
// Attachment is globally public accessible object for table nl_attachment operations.
|
||||
Attachment = NewAttachmentDao()
|
||||
|
||||
// Config is globally public accessible object for table nl_config operations.
|
||||
Config = NewConfigDao()
|
||||
|
||||
// AdminLog is globally public accessible object for table nl_admin_log operations.
|
||||
AdminLog = NewAdminLogDao()
|
||||
|
||||
// UserLog is globally public accessible object for table nl_user_log operations.
|
||||
UserLog = NewUserLogDao()
|
||||
|
||||
// CommentLike is globally public accessible object for table comment_like operations.
|
||||
CommentLike = internal.NewCommentLikeDao()
|
||||
|
||||
// CommentReport is globally public accessible object for table comment_report operations.
|
||||
CommentReport = internal.NewCommentReportDao()
|
||||
)
|
||||
69
internal/dao/internal/comment_like.go
Normal file
69
internal/dao/internal/comment_like.go
Normal file
@@ -0,0 +1,69 @@
|
||||
package internal
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/gogf/gf/v2/database/gdb"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
)
|
||||
|
||||
// CommentLikeDao is the data access object for table comment_like.
|
||||
type CommentLikeDao struct {
|
||||
table string
|
||||
group string
|
||||
columns CommentLikeColumns
|
||||
}
|
||||
|
||||
// CommentLikeColumns defines and stores column names for table comment_like.
|
||||
type CommentLikeColumns struct {
|
||||
Id string
|
||||
CommentId string
|
||||
UserId string
|
||||
CreatedAt string
|
||||
}
|
||||
|
||||
// commentLikeColumns holds the columns for table comment_like.
|
||||
var commentLikeColumns = CommentLikeColumns{
|
||||
Id: "id",
|
||||
CommentId: "comment_id",
|
||||
UserId: "user_id",
|
||||
CreatedAt: "created_at",
|
||||
}
|
||||
|
||||
// NewCommentLikeDao creates and returns a new DAO object for table data access.
|
||||
func NewCommentLikeDao() *CommentLikeDao {
|
||||
return &CommentLikeDao{
|
||||
group: "default",
|
||||
table: "comment_like",
|
||||
columns: commentLikeColumns,
|
||||
}
|
||||
}
|
||||
|
||||
// DB retrieves and returns the underlying raw database management object of current DAO.
|
||||
func (dao *CommentLikeDao) DB() gdb.DB {
|
||||
return g.DB(dao.group)
|
||||
}
|
||||
|
||||
// Table returns the table name of current dao.
|
||||
func (dao *CommentLikeDao) Table() string {
|
||||
return dao.table
|
||||
}
|
||||
|
||||
// Columns returns the columns of current dao.
|
||||
func (dao *CommentLikeDao) Columns() CommentLikeColumns {
|
||||
return dao.columns
|
||||
}
|
||||
|
||||
// Group returns the configuration group name of database of current dao.
|
||||
func (dao *CommentLikeDao) Group() string {
|
||||
return dao.group
|
||||
}
|
||||
|
||||
// Ctx creates and returns the Model for current DAO, It automatically sets the context for current operation.
|
||||
func (dao *CommentLikeDao) Ctx(ctx context.Context) *gdb.Model {
|
||||
return dao.DB().Model(dao.table).Safe().Ctx(ctx)
|
||||
}
|
||||
|
||||
// Transaction wraps the transaction logic using function f.
|
||||
func (dao *CommentLikeDao) Transaction(ctx context.Context, f func(ctx context.Context, tx gdb.TX) error) (err error) {
|
||||
return dao.Ctx(ctx).Transaction(ctx, f)
|
||||
}
|
||||
73
internal/dao/internal/comment_report.go
Normal file
73
internal/dao/internal/comment_report.go
Normal file
@@ -0,0 +1,73 @@
|
||||
package internal
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/gogf/gf/v2/database/gdb"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
)
|
||||
|
||||
// CommentReportDao is the data access object for table comment_report.
|
||||
type CommentReportDao struct {
|
||||
table string
|
||||
group string
|
||||
columns CommentReportColumns
|
||||
}
|
||||
|
||||
// CommentReportColumns defines and stores column names for table comment_report.
|
||||
type CommentReportColumns struct {
|
||||
Id string
|
||||
CommentId string
|
||||
UserId string
|
||||
Reason string
|
||||
Status string
|
||||
CreatedAt string
|
||||
}
|
||||
|
||||
// commentReportColumns holds the columns for table comment_report.
|
||||
var commentReportColumns = CommentReportColumns{
|
||||
Id: "id",
|
||||
CommentId: "comment_id",
|
||||
UserId: "user_id",
|
||||
Reason: "reason",
|
||||
Status: "status",
|
||||
CreatedAt: "created_at",
|
||||
}
|
||||
|
||||
// NewCommentReportDao creates and returns a new DAO object for table data access.
|
||||
func NewCommentReportDao() *CommentReportDao {
|
||||
return &CommentReportDao{
|
||||
group: "default",
|
||||
table: "comment_report",
|
||||
columns: commentReportColumns,
|
||||
}
|
||||
}
|
||||
|
||||
// DB retrieves and returns the underlying raw database management object of current DAO.
|
||||
func (dao *CommentReportDao) DB() gdb.DB {
|
||||
return g.DB(dao.group)
|
||||
}
|
||||
|
||||
// Table returns the table name of current dao.
|
||||
func (dao *CommentReportDao) Table() string {
|
||||
return dao.table
|
||||
}
|
||||
|
||||
// Columns returns the columns of current dao.
|
||||
func (dao *CommentReportDao) Columns() CommentReportColumns {
|
||||
return dao.columns
|
||||
}
|
||||
|
||||
// Group returns the configuration group name of database of current dao.
|
||||
func (dao *CommentReportDao) Group() string {
|
||||
return dao.group
|
||||
}
|
||||
|
||||
// Ctx creates and returns the Model for current DAO, It automatically sets the context for current operation.
|
||||
func (dao *CommentReportDao) Ctx(ctx context.Context) *gdb.Model {
|
||||
return dao.DB().Model(dao.table).Safe().Ctx(ctx)
|
||||
}
|
||||
|
||||
// Transaction wraps the transaction logic using function f.
|
||||
func (dao *CommentReportDao) Transaction(ctx context.Context, f func(ctx context.Context, tx gdb.TX) error) (err error) {
|
||||
return dao.Ctx(ctx).Transaction(ctx, f)
|
||||
}
|
||||
51
internal/dao/internal/dao.go
Normal file
51
internal/dao/internal/dao.go
Normal file
@@ -0,0 +1,51 @@
|
||||
package internal
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/gogf/gf/v2/database/gdb"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
)
|
||||
|
||||
// Dao is the data access object for database operations.
|
||||
type Dao struct {
|
||||
table string
|
||||
group string
|
||||
columns []string
|
||||
}
|
||||
|
||||
// New creates and returns a new DAO object.
|
||||
func New() *Dao {
|
||||
return &Dao{
|
||||
group: "default",
|
||||
}
|
||||
}
|
||||
|
||||
// DB retrieves and returns the underlying raw database management object of current DAO.
|
||||
func (dao *Dao) DB() gdb.DB {
|
||||
return g.DB(dao.group)
|
||||
}
|
||||
|
||||
// Table returns the table name of current dao.
|
||||
func (dao *Dao) Table() string {
|
||||
return dao.table
|
||||
}
|
||||
|
||||
// Columns returns the columns of current dao.
|
||||
func (dao *Dao) Columns() []string {
|
||||
return dao.columns
|
||||
}
|
||||
|
||||
// Group returns the configuration group name of database of current dao.
|
||||
func (dao *Dao) Group() string {
|
||||
return dao.group
|
||||
}
|
||||
|
||||
// Ctx creates and returns the Model for current DAO, It automatically sets the context for current operation.
|
||||
func (dao *Dao) Ctx(ctx context.Context) *gdb.Model {
|
||||
return dao.DB().Model(dao.table).Safe().Ctx(ctx)
|
||||
}
|
||||
|
||||
// Transaction wraps the transaction logic using function f.
|
||||
func (dao *Dao) Transaction(ctx context.Context, f func(ctx context.Context, tx gdb.TX) error) (err error) {
|
||||
return dao.Ctx(ctx).Transaction(ctx, f)
|
||||
}
|
||||
259
internal/dao/movie.go
Normal file
259
internal/dao/movie.go
Normal file
@@ -0,0 +1,259 @@
|
||||
package dao
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/os/gtime"
|
||||
"nl-video-api/internal/model/entity"
|
||||
)
|
||||
|
||||
// MovieDao 影片数据访问对象
|
||||
type MovieDao struct{}
|
||||
|
||||
// movieDao 影片DAO实例
|
||||
var movieDao = &MovieDao{}
|
||||
|
||||
// NewMovieDao 创建影片DAO实例
|
||||
func NewMovieDao() *MovieDao {
|
||||
return movieDao
|
||||
}
|
||||
|
||||
// GetList 获取影片列表
|
||||
func (d *MovieDao) GetList(ctx context.Context, req *MovieListReq) ([]*entity.Movie, int, error) {
|
||||
db := g.DB()
|
||||
model := db.Model("nl_movie").Where("deleted_at = 0")
|
||||
|
||||
// 条件筛选
|
||||
if req.CategoryId > 0 {
|
||||
model = model.Where("category_id = ?", req.CategoryId)
|
||||
}
|
||||
if req.Type > 0 {
|
||||
model = model.Where("type = ?", req.Type)
|
||||
}
|
||||
if req.Year > 0 {
|
||||
model = model.Where("year = ?", req.Year)
|
||||
}
|
||||
if req.Area != "" {
|
||||
model = model.Where("area = ?", req.Area)
|
||||
}
|
||||
if req.Language != "" {
|
||||
model = model.Where("language = ?", req.Language)
|
||||
}
|
||||
if req.IsVip >= 0 {
|
||||
model = model.Where("is_vip = ?", req.IsVip)
|
||||
}
|
||||
if req.IsRecommend >= 0 {
|
||||
model = model.Where("is_recommend = ?", req.IsRecommend)
|
||||
}
|
||||
if req.IsHot >= 0 {
|
||||
model = model.Where("is_hot = ?", req.IsHot)
|
||||
}
|
||||
if req.IsNew >= 0 {
|
||||
model = model.Where("is_new = ?", req.IsNew)
|
||||
}
|
||||
if req.Status >= 0 {
|
||||
model = model.Where("status = ?", req.Status)
|
||||
}
|
||||
if req.Keyword != "" {
|
||||
model = model.Where("title LIKE ? OR original_title LIKE ? OR director LIKE ? OR actor LIKE ?",
|
||||
"%"+req.Keyword+"%", "%"+req.Keyword+"%", "%"+req.Keyword+"%", "%"+req.Keyword+"%")
|
||||
}
|
||||
|
||||
// 获取总数
|
||||
total, err := model.Count()
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
// 排序
|
||||
orderBy := "created_at DESC"
|
||||
if req.OrderBy != "" {
|
||||
orderBy = req.OrderBy
|
||||
}
|
||||
model = model.Order(orderBy)
|
||||
|
||||
// 分页
|
||||
if req.Page > 0 && req.PageSize > 0 {
|
||||
offset := (req.Page - 1) * req.PageSize
|
||||
model = model.Limit(req.PageSize).Offset(offset)
|
||||
}
|
||||
|
||||
var movies []*entity.Movie
|
||||
err = model.Scan(&movies)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
return movies, total, nil
|
||||
}
|
||||
|
||||
// GetById 根据ID获取影片
|
||||
func (d *MovieDao) GetById(ctx context.Context, id int) (*entity.Movie, error) {
|
||||
var movie *entity.Movie
|
||||
err := g.DB().Model("nl_movie").Where("id = ? AND deleted_at = 0", id).Scan(&movie)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return movie, nil
|
||||
}
|
||||
|
||||
// Create 创建影片
|
||||
func (d *MovieDao) Create(ctx context.Context, movie *entity.Movie) (int64, error) {
|
||||
result, err := g.DB().Model("nl_movie").Data(movie).Insert()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
id, err := result.LastInsertId()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return id, nil
|
||||
}
|
||||
|
||||
// Update 更新影片
|
||||
func (d *MovieDao) Update(ctx context.Context, id int, data g.Map) error {
|
||||
data["updated_at"] = gtime.Now().Unix()
|
||||
_, err := g.DB().Model("nl_movie").Where("id = ?", id).Data(data).Update()
|
||||
return err
|
||||
}
|
||||
|
||||
// Delete 删除影片(软删除)
|
||||
func (d *MovieDao) Delete(ctx context.Context, id int) error {
|
||||
_, err := g.DB().Model("nl_movie").Where("id = ?", id).Data(g.Map{
|
||||
"deleted_at": gtime.Now().Unix(),
|
||||
"updated_at": gtime.Now().Unix(),
|
||||
}).Update()
|
||||
return err
|
||||
}
|
||||
|
||||
// UpdateViewCount 更新观看次数
|
||||
func (d *MovieDao) UpdateViewCount(ctx context.Context, id int) error {
|
||||
_, err := g.DB().Model("nl_movie").Where("id = ?", id).Increment("view_count", 1)
|
||||
return err
|
||||
}
|
||||
|
||||
// UpdateLikeCount 更新点赞数
|
||||
func (d *MovieDao) UpdateLikeCount(ctx context.Context, id int, increment int) error {
|
||||
_, err := g.DB().Model("nl_movie").Where("id = ?", id).Increment("like_count", increment)
|
||||
return err
|
||||
}
|
||||
|
||||
// UpdateCollectCount 更新收藏数
|
||||
func (d *MovieDao) UpdateCollectCount(ctx context.Context, id int, increment int) error {
|
||||
_, err := g.DB().Model("nl_movie").Where("id = ?", id).Increment("collect_count", increment)
|
||||
return err
|
||||
}
|
||||
|
||||
// UpdateCommentCount 更新评论数
|
||||
func (d *MovieDao) UpdateCommentCount(ctx context.Context, id int, increment int) error {
|
||||
_, err := g.DB().Model("nl_movie").Where("id = ?", id).Increment("comment_count", increment)
|
||||
return err
|
||||
}
|
||||
|
||||
// GetHotMovies 获取热门影片
|
||||
func (d *MovieDao) GetHotMovies(ctx context.Context, limit int) ([]*entity.Movie, error) {
|
||||
var movies []*entity.Movie
|
||||
err := g.DB().Model("nl_movie").
|
||||
Where("status = 1 AND deleted_at = 0").
|
||||
Order("view_count DESC, rating DESC").
|
||||
Limit(limit).
|
||||
Scan(&movies)
|
||||
return movies, err
|
||||
}
|
||||
|
||||
// GetRecommendMovies 获取推荐影片
|
||||
func (d *MovieDao) GetRecommendMovies(ctx context.Context, limit int) ([]*entity.Movie, error) {
|
||||
var movies []*entity.Movie
|
||||
err := g.DB().Model("nl_movie").
|
||||
Where("is_recommend = 1 AND status = 1 AND deleted_at = 0").
|
||||
Order("sort ASC, created_at DESC").
|
||||
Limit(limit).
|
||||
Scan(&movies)
|
||||
return movies, err
|
||||
}
|
||||
|
||||
// GetNewMovies 获取最新影片
|
||||
func (d *MovieDao) GetNewMovies(ctx context.Context, limit int) ([]*entity.Movie, error) {
|
||||
var movies []*entity.Movie
|
||||
err := g.DB().Model("nl_movie").
|
||||
Where("status = 1 AND deleted_at = 0").
|
||||
Order("created_at DESC").
|
||||
Limit(limit).
|
||||
Scan(&movies)
|
||||
return movies, err
|
||||
}
|
||||
|
||||
// SearchMovies 搜索影片
|
||||
func (d *MovieDao) SearchMovies(ctx context.Context, keyword string, page, pageSize int) ([]*entity.Movie, int, error) {
|
||||
db := g.DB()
|
||||
model := db.Model("nl_movie").
|
||||
Where("deleted_at = 0 AND status = 1").
|
||||
Where("title LIKE ? OR original_title LIKE ? OR director LIKE ? OR actor LIKE ? OR description LIKE ?",
|
||||
"%"+keyword+"%", "%"+keyword+"%", "%"+keyword+"%", "%"+keyword+"%", "%"+keyword+"%")
|
||||
|
||||
// 获取总数
|
||||
total, err := model.Count()
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
// 分页
|
||||
if page > 0 && pageSize > 0 {
|
||||
offset := (page - 1) * pageSize
|
||||
model = model.Limit(pageSize).Offset(offset)
|
||||
}
|
||||
|
||||
var movies []*entity.Movie
|
||||
err = model.Order("rating DESC, view_count DESC").Scan(&movies)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
return movies, total, nil
|
||||
}
|
||||
|
||||
// GetMoviesByCategory 根据分类获取影片
|
||||
func (d *MovieDao) GetMoviesByCategory(ctx context.Context, categoryId, page, pageSize int) ([]*entity.Movie, int, error) {
|
||||
db := g.DB()
|
||||
model := db.Model("nl_movie").
|
||||
Where("category_id = ? AND status = 1 AND deleted_at = 0", categoryId)
|
||||
|
||||
// 获取总数
|
||||
total, err := model.Count()
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
// 分页
|
||||
if page > 0 && pageSize > 0 {
|
||||
offset := (page - 1) * pageSize
|
||||
model = model.Limit(pageSize).Offset(offset)
|
||||
}
|
||||
|
||||
var movies []*entity.Movie
|
||||
err = model.Order("sort ASC, created_at DESC").Scan(&movies)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
return movies, total, nil
|
||||
}
|
||||
|
||||
// MovieListReq 影片列表请求参数
|
||||
type MovieListReq struct {
|
||||
Page int `json:"page"` // 页码
|
||||
PageSize int `json:"page_size"` // 每页数量
|
||||
CategoryId int `json:"category_id"` // 分类ID
|
||||
Type int `json:"type"` // 类型
|
||||
Year int `json:"year"` // 年份
|
||||
Area string `json:"area"` // 地区
|
||||
Language string `json:"language"` // 语言
|
||||
IsVip int `json:"is_vip"` // 是否VIP专享
|
||||
IsRecommend int `json:"is_recommend"` // 是否推荐
|
||||
IsHot int `json:"is_hot"` // 是否热门
|
||||
IsNew int `json:"is_new"` // 是否最新
|
||||
Status int `json:"status"` // 状态
|
||||
Keyword string `json:"keyword"` // 关键词
|
||||
OrderBy string `json:"order_by"` // 排序
|
||||
}
|
||||
90
internal/dao/payment_order.go
Normal file
90
internal/dao/payment_order.go
Normal file
@@ -0,0 +1,90 @@
|
||||
// =================================================================================
|
||||
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
|
||||
// =================================================================================
|
||||
|
||||
package dao
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/gogf/gf/v2/database/gdb"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
)
|
||||
|
||||
// internalPaymentOrderDao is internal type for wrapping internal DAO implements.
|
||||
type internalPaymentOrderDao struct {
|
||||
table string // table is the underlying table name of the DAO.
|
||||
group string // group is the database configuration group name of current DAO.
|
||||
columns PaymentOrderColumns // columns contains all the column names of Table for convenient usage.
|
||||
}
|
||||
|
||||
// PaymentOrderColumns defines and stores column names for table nl_payment_order.
|
||||
type PaymentOrderColumns struct {
|
||||
Id string // 订单ID
|
||||
OrderNo string // 订单号
|
||||
UserId string // 用户ID
|
||||
VipLevelId string // VIP等级ID
|
||||
Amount string // 订单金额
|
||||
PaymentMethod string // 支付方式
|
||||
PaymentStatus string // 支付状态:0待支付,1已支付,2已取消,3已退款
|
||||
PaymentTime string // 支付时间
|
||||
ExpireTime string // 过期时间
|
||||
Remark string // 备注
|
||||
CreatedAt string // 创建时间
|
||||
UpdatedAt string // 更新时间
|
||||
}
|
||||
|
||||
// paymentOrderColumns holds the columns for table nl_payment_order.
|
||||
var paymentOrderColumns = PaymentOrderColumns{
|
||||
Id: "id",
|
||||
OrderNo: "order_no",
|
||||
UserId: "user_id",
|
||||
VipLevelId: "vip_level_id",
|
||||
Amount: "amount",
|
||||
PaymentMethod: "payment_method",
|
||||
PaymentStatus: "payment_status",
|
||||
PaymentTime: "payment_time",
|
||||
ExpireTime: "expire_time",
|
||||
Remark: "remark",
|
||||
CreatedAt: "created_at",
|
||||
UpdatedAt: "updated_at",
|
||||
}
|
||||
|
||||
// NewPaymentOrderDao creates and returns a new DAO object for table data access.
|
||||
func NewPaymentOrderDao() *internalPaymentOrderDao {
|
||||
return &internalPaymentOrderDao{
|
||||
group: "default",
|
||||
table: "nl_payment_order",
|
||||
columns: paymentOrderColumns,
|
||||
}
|
||||
}
|
||||
|
||||
// DB retrieves and returns the underlying raw database management object of current DAO.
|
||||
func (dao *internalPaymentOrderDao) DB() gdb.DB {
|
||||
return g.DB(dao.group)
|
||||
}
|
||||
|
||||
// Table returns the table name of current dao.
|
||||
func (dao *internalPaymentOrderDao) Table() string {
|
||||
return dao.table
|
||||
}
|
||||
|
||||
// Columns returns the columns of current dao.
|
||||
func (dao *internalPaymentOrderDao) Columns() PaymentOrderColumns {
|
||||
return dao.columns
|
||||
}
|
||||
|
||||
// Group returns the configuration group name of database of current dao.
|
||||
func (dao *internalPaymentOrderDao) Group() string {
|
||||
return dao.group
|
||||
}
|
||||
|
||||
// Ctx creates and returns the Model for current DAO, It automatically sets the context for current operation.
|
||||
func (dao *internalPaymentOrderDao) Ctx(ctx context.Context) *gdb.Model {
|
||||
return dao.DB().Model(dao.table).Safe().Ctx(ctx)
|
||||
}
|
||||
|
||||
// Transaction wraps the transaction logic using function f.
|
||||
func (dao *internalPaymentOrderDao) Transaction(ctx context.Context, f func(ctx context.Context, tx gdb.TX) error) error {
|
||||
return dao.Ctx(ctx).Transaction(ctx, f)
|
||||
}
|
||||
248
internal/dao/permission.go
Normal file
248
internal/dao/permission.go
Normal file
@@ -0,0 +1,248 @@
|
||||
package dao
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/os/gtime"
|
||||
"nl-video-api/internal/model/entity"
|
||||
)
|
||||
|
||||
// PermissionDao 权限数据访问对象
|
||||
type PermissionDao struct{}
|
||||
|
||||
// TableName 获取表名
|
||||
func (dao *PermissionDao) TableName() string {
|
||||
return "nl_permission"
|
||||
}
|
||||
|
||||
// Create 创建权限
|
||||
func (dao *PermissionDao) Create(ctx context.Context, data *entity.Permission) (int, error) {
|
||||
result, err := g.DB().Model(dao.TableName()).Ctx(ctx).Data(data).Insert()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
id, err := result.LastInsertId()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return int(id), nil
|
||||
}
|
||||
|
||||
// GetById 根据ID获取权限
|
||||
func (dao *PermissionDao) GetById(ctx context.Context, id int) (*entity.Permission, error) {
|
||||
var permission *entity.Permission
|
||||
err := g.DB().Model(dao.TableName()).Ctx(ctx).Where("id = ? AND deleted_at = 0", id).Scan(&permission)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return permission, nil
|
||||
}
|
||||
|
||||
// GetByCode 根据权限编码获取权限
|
||||
func (dao *PermissionDao) GetByCode(ctx context.Context, code string) (*entity.Permission, error) {
|
||||
var permission *entity.Permission
|
||||
err := g.DB().Model(dao.TableName()).Ctx(ctx).Where("code = ? AND deleted_at = 0", code).Scan(&permission)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return permission, nil
|
||||
}
|
||||
|
||||
// Update 更新权限
|
||||
func (dao *PermissionDao) Update(ctx context.Context, id int, data g.Map) error {
|
||||
data["updated_at"] = gtime.Now().Unix()
|
||||
_, err := g.DB().Model(dao.TableName()).Ctx(ctx).Where("id = ?", id).Data(data).Update()
|
||||
return err
|
||||
}
|
||||
|
||||
// Delete 删除权限(软删除)
|
||||
func (dao *PermissionDao) Delete(ctx context.Context, id int) error {
|
||||
data := g.Map{
|
||||
"deleted_at": gtime.Now().Unix(),
|
||||
"updated_at": gtime.Now().Unix(),
|
||||
}
|
||||
_, err := g.DB().Model(dao.TableName()).Ctx(ctx).Where("id = ?", id).Data(data).Update()
|
||||
return err
|
||||
}
|
||||
|
||||
// GetList 获取权限列表
|
||||
func (dao *PermissionDao) GetList(ctx context.Context, req *PermissionListReq) ([]*entity.Permission, int, error) {
|
||||
model := g.DB().Model(dao.TableName()).Ctx(ctx).Where("deleted_at = 0")
|
||||
|
||||
// 条件筛选
|
||||
if req.Name != "" {
|
||||
model = model.WhereLike("name", "%"+req.Name+"%")
|
||||
}
|
||||
if req.Code != "" {
|
||||
model = model.WhereLike("code", "%"+req.Code+"%")
|
||||
}
|
||||
if req.Type != "" {
|
||||
model = model.Where("type = ?", req.Type)
|
||||
}
|
||||
if req.Status >= 0 {
|
||||
model = model.Where("status = ?", req.Status)
|
||||
}
|
||||
if req.ParentId >= 0 {
|
||||
model = model.Where("parent_id = ?", req.ParentId)
|
||||
}
|
||||
|
||||
// 获取总数
|
||||
total, err := model.Count()
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
// 分页和排序
|
||||
if req.Page > 0 && req.PageSize > 0 {
|
||||
offset := (req.Page - 1) * req.PageSize
|
||||
model = model.Limit(req.PageSize).Offset(offset)
|
||||
}
|
||||
|
||||
model = model.OrderAsc("sort").OrderAsc("id")
|
||||
|
||||
var permissions []*entity.Permission
|
||||
err = model.Scan(&permissions)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
return permissions, total, nil
|
||||
}
|
||||
|
||||
// GetTree 获取权限树形结构
|
||||
func (dao *PermissionDao) GetTree(ctx context.Context) ([]*entity.Permission, error) {
|
||||
var permissions []*entity.Permission
|
||||
err := g.DB().Model(dao.TableName()).Ctx(ctx).
|
||||
Where("deleted_at = 0 AND status = 1").
|
||||
OrderAsc("sort").OrderAsc("id").
|
||||
Scan(&permissions)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 构建树形结构
|
||||
return dao.buildTree(permissions, 0), nil
|
||||
}
|
||||
|
||||
// buildTree 构建树形结构
|
||||
func (dao *PermissionDao) buildTree(permissions []*entity.Permission, parentId int) []*entity.Permission {
|
||||
var tree []*entity.Permission
|
||||
|
||||
for _, permission := range permissions {
|
||||
if permission.ParentId == parentId {
|
||||
children := dao.buildTree(permissions, permission.Id)
|
||||
if len(children) > 0 {
|
||||
// 这里需要在Permission实体中添加Children字段
|
||||
// permission.Children = children
|
||||
}
|
||||
tree = append(tree, permission)
|
||||
}
|
||||
}
|
||||
|
||||
return tree
|
||||
}
|
||||
|
||||
// GetAll 获取所有权限
|
||||
func (dao *PermissionDao) GetAll(ctx context.Context) ([]*entity.Permission, error) {
|
||||
var permissions []*entity.Permission
|
||||
err := g.DB().Model(dao.TableName()).Ctx(ctx).
|
||||
Where("deleted_at = 0 AND status = 1").
|
||||
OrderAsc("sort").OrderAsc("id").
|
||||
Scan(&permissions)
|
||||
return permissions, err
|
||||
}
|
||||
|
||||
// GetByParentId 根据父级ID获取权限
|
||||
func (dao *PermissionDao) GetByParentId(ctx context.Context, parentId int) ([]*entity.Permission, error) {
|
||||
var permissions []*entity.Permission
|
||||
err := g.DB().Model(dao.TableName()).Ctx(ctx).
|
||||
Where("parent_id = ? AND deleted_at = 0 AND status = 1", parentId).
|
||||
OrderAsc("sort").OrderAsc("id").
|
||||
Scan(&permissions)
|
||||
return permissions, err
|
||||
}
|
||||
|
||||
// GetByType 根据类型获取权限
|
||||
func (dao *PermissionDao) GetByType(ctx context.Context, permissionType string) ([]*entity.Permission, error) {
|
||||
var permissions []*entity.Permission
|
||||
err := g.DB().Model(dao.TableName()).Ctx(ctx).
|
||||
Where("type = ? AND deleted_at = 0 AND status = 1", permissionType).
|
||||
OrderAsc("sort").OrderAsc("id").
|
||||
Scan(&permissions)
|
||||
return permissions, err
|
||||
}
|
||||
|
||||
// CheckCodeExists 检查权限编码是否存在
|
||||
func (dao *PermissionDao) CheckCodeExists(ctx context.Context, code string, excludeId int) (bool, error) {
|
||||
model := g.DB().Model(dao.TableName()).Ctx(ctx).Where("code = ? AND deleted_at = 0", code)
|
||||
if excludeId > 0 {
|
||||
model = model.Where("id != ?", excludeId)
|
||||
}
|
||||
|
||||
count, err := model.Count()
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
return count > 0, nil
|
||||
}
|
||||
|
||||
// GetPermissionsByIds 根据ID列表获取权限
|
||||
func (dao *PermissionDao) GetPermissionsByIds(ctx context.Context, ids []int) ([]*entity.Permission, error) {
|
||||
if len(ids) == 0 {
|
||||
return []*entity.Permission{}, nil
|
||||
}
|
||||
|
||||
var permissions []*entity.Permission
|
||||
err := g.DB().Model(dao.TableName()).Ctx(ctx).
|
||||
Where("id IN (?) AND deleted_at = 0", ids).
|
||||
OrderAsc("sort").OrderAsc("id").
|
||||
Scan(&permissions)
|
||||
return permissions, err
|
||||
}
|
||||
|
||||
// GetMenuPermissions 获取菜单权限
|
||||
func (dao *PermissionDao) GetMenuPermissions(ctx context.Context) ([]*entity.Permission, error) {
|
||||
var permissions []*entity.Permission
|
||||
err := g.DB().Model(dao.TableName()).Ctx(ctx).
|
||||
Where("type = 'menu' AND deleted_at = 0 AND status = 1").
|
||||
OrderAsc("sort").OrderAsc("id").
|
||||
Scan(&permissions)
|
||||
return permissions, err
|
||||
}
|
||||
|
||||
// GetApiPermissions 获取API权限
|
||||
func (dao *PermissionDao) GetApiPermissions(ctx context.Context) ([]*entity.Permission, error) {
|
||||
var permissions []*entity.Permission
|
||||
err := g.DB().Model(dao.TableName()).Ctx(ctx).
|
||||
Where("type = 'api' AND deleted_at = 0 AND status = 1").
|
||||
OrderAsc("sort").OrderAsc("id").
|
||||
Scan(&permissions)
|
||||
return permissions, err
|
||||
}
|
||||
|
||||
// GetUserPermissions 获取用户权限(通过角色)
|
||||
func (dao *PermissionDao) GetUserPermissions(ctx context.Context, userId int) ([]*entity.Permission, error) {
|
||||
var permissions []*entity.Permission
|
||||
err := g.DB().Model("nl_permission p").Ctx(ctx).
|
||||
LeftJoin("nl_role_permission rp", "p.id = rp.permission_id").
|
||||
LeftJoin("nl_admin a", "a.role_id = rp.role_id").
|
||||
Where("a.id = ? AND p.deleted_at = 0 AND p.status = 1", userId).
|
||||
OrderAsc("p.sort").OrderAsc("p.id").
|
||||
Scan(&permissions)
|
||||
return permissions, err
|
||||
}
|
||||
|
||||
// PermissionListReq 权限列表请求参数
|
||||
type PermissionListReq struct {
|
||||
Page int `json:"page" v:"min:1#页码最小为1"`
|
||||
PageSize int `json:"page_size" v:"min:1,max:100#每页数量范围1-100"`
|
||||
Name string `json:"name"` // 权限名称
|
||||
Code string `json:"code"` // 权限编码
|
||||
Type string `json:"type"` // 权限类型:menu-菜单,button-按钮,api-接口
|
||||
Status int `json:"status"` // 状态:-1-全部,0-禁用,1-启用
|
||||
ParentId int `json:"parent_id"` // 父级ID:-1-全部,0-顶级,>0-指定父级
|
||||
}
|
||||
200
internal/dao/role.go
Normal file
200
internal/dao/role.go
Normal file
@@ -0,0 +1,200 @@
|
||||
package dao
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/gogf/gf/v2/database/gdb"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/os/gtime"
|
||||
"nl-video-api/internal/model/entity"
|
||||
)
|
||||
|
||||
// RoleDao 角色数据访问对象
|
||||
type RoleDao struct{}
|
||||
|
||||
// TableName 获取表名
|
||||
func (dao *RoleDao) TableName() string {
|
||||
return "nl_role"
|
||||
}
|
||||
|
||||
// Create 创建角色
|
||||
func (dao *RoleDao) Create(ctx context.Context, data *entity.Role) (int, error) {
|
||||
result, err := g.DB().Model(dao.TableName()).Ctx(ctx).Data(data).Insert()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
id, err := result.LastInsertId()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return int(id), nil
|
||||
}
|
||||
|
||||
// GetById 根据ID获取角色
|
||||
func (dao *RoleDao) GetById(ctx context.Context, id int) (*entity.Role, error) {
|
||||
var role *entity.Role
|
||||
err := g.DB().Model(dao.TableName()).Ctx(ctx).Where("id = ? AND deleted_at = 0", id).Scan(&role)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return role, nil
|
||||
}
|
||||
|
||||
// GetByCode 根据角色编码获取角色
|
||||
func (dao *RoleDao) GetByCode(ctx context.Context, code string) (*entity.Role, error) {
|
||||
var role *entity.Role
|
||||
err := g.DB().Model(dao.TableName()).Ctx(ctx).Where("code = ? AND deleted_at = 0", code).Scan(&role)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return role, nil
|
||||
}
|
||||
|
||||
// Update 更新角色
|
||||
func (dao *RoleDao) Update(ctx context.Context, id int, data g.Map) error {
|
||||
data["updated_at"] = gtime.Now().Unix()
|
||||
_, err := g.DB().Model(dao.TableName()).Ctx(ctx).Where("id = ?", id).Data(data).Update()
|
||||
return err
|
||||
}
|
||||
|
||||
// Delete 删除角色(软删除)
|
||||
func (dao *RoleDao) Delete(ctx context.Context, id int) error {
|
||||
data := g.Map{
|
||||
"deleted_at": gtime.Now().Unix(),
|
||||
"updated_at": gtime.Now().Unix(),
|
||||
}
|
||||
_, err := g.DB().Model(dao.TableName()).Ctx(ctx).Where("id = ?", id).Data(data).Update()
|
||||
return err
|
||||
}
|
||||
|
||||
// GetList 获取角色列表
|
||||
func (dao *RoleDao) GetList(ctx context.Context, req *RoleListReq) ([]*entity.Role, int, error) {
|
||||
model := g.DB().Model(dao.TableName()).Ctx(ctx).Where("deleted_at = 0")
|
||||
|
||||
// 条件筛选
|
||||
if req.Name != "" {
|
||||
model = model.WhereLike("name", "%"+req.Name+"%")
|
||||
}
|
||||
if req.Code != "" {
|
||||
model = model.WhereLike("code", "%"+req.Code+"%")
|
||||
}
|
||||
if req.Status >= 0 {
|
||||
model = model.Where("status = ?", req.Status)
|
||||
}
|
||||
if req.Level > 0 {
|
||||
model = model.Where("level = ?", req.Level)
|
||||
}
|
||||
|
||||
// 获取总数
|
||||
total, err := model.Count()
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
// 分页和排序
|
||||
if req.Page > 0 && req.PageSize > 0 {
|
||||
offset := (req.Page - 1) * req.PageSize
|
||||
model = model.Limit(req.PageSize).Offset(offset)
|
||||
}
|
||||
|
||||
model = model.OrderDesc("sort").OrderDesc("id")
|
||||
|
||||
var roles []*entity.Role
|
||||
err = model.Scan(&roles)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
return roles, total, nil
|
||||
}
|
||||
|
||||
// GetAll 获取所有角色
|
||||
func (dao *RoleDao) GetAll(ctx context.Context) ([]*entity.Role, error) {
|
||||
var roles []*entity.Role
|
||||
err := g.DB().Model(dao.TableName()).Ctx(ctx).
|
||||
Where("deleted_at = 0 AND status = 1").
|
||||
OrderDesc("sort").OrderDesc("id").
|
||||
Scan(&roles)
|
||||
return roles, err
|
||||
}
|
||||
|
||||
// CheckCodeExists 检查角色编码是否存在
|
||||
func (dao *RoleDao) CheckCodeExists(ctx context.Context, code string, excludeId int) (bool, error) {
|
||||
model := g.DB().Model(dao.TableName()).Ctx(ctx).Where("code = ? AND deleted_at = 0", code)
|
||||
if excludeId > 0 {
|
||||
model = model.Where("id != ?", excludeId)
|
||||
}
|
||||
|
||||
count, err := model.Count()
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
return count > 0, nil
|
||||
}
|
||||
|
||||
// GetRolesByIds 根据ID列表获取角色
|
||||
func (dao *RoleDao) GetRolesByIds(ctx context.Context, ids []int) ([]*entity.Role, error) {
|
||||
if len(ids) == 0 {
|
||||
return []*entity.Role{}, nil
|
||||
}
|
||||
|
||||
var roles []*entity.Role
|
||||
err := g.DB().Model(dao.TableName()).Ctx(ctx).
|
||||
Where("id IN (?) AND deleted_at = 0", ids).
|
||||
OrderDesc("sort").OrderDesc("id").
|
||||
Scan(&roles)
|
||||
return roles, err
|
||||
}
|
||||
|
||||
// GetRolePermissions 获取角色的权限列表
|
||||
func (dao *RoleDao) GetRolePermissions(ctx context.Context, roleId int) ([]*entity.Permission, error) {
|
||||
var permissions []*entity.Permission
|
||||
err := g.DB().Model("nl_permission p").Ctx(ctx).
|
||||
LeftJoin("nl_role_permission rp", "p.id = rp.permission_id").
|
||||
Where("rp.role_id = ? AND p.deleted_at = 0 AND p.status = 1", roleId).
|
||||
OrderAsc("p.sort").OrderAsc("p.id").
|
||||
Scan(&permissions)
|
||||
return permissions, err
|
||||
}
|
||||
|
||||
// AssignPermissions 为角色分配权限
|
||||
func (dao *RoleDao) AssignPermissions(ctx context.Context, roleId int, permissionIds []int) error {
|
||||
return g.DB().Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {
|
||||
// 先删除原有权限
|
||||
_, err := tx.Model("nl_role_permission").Ctx(ctx).Where("role_id = ?", roleId).Delete()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 添加新权限
|
||||
if len(permissionIds) > 0 {
|
||||
data := make([]g.Map, 0, len(permissionIds))
|
||||
for _, permissionId := range permissionIds {
|
||||
data = append(data, g.Map{
|
||||
"role_id": roleId,
|
||||
"permission_id": permissionId,
|
||||
"created_at": gtime.Now().Unix(),
|
||||
})
|
||||
}
|
||||
_, err = tx.Model("nl_role_permission").Ctx(ctx).Data(data).Insert()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
// RoleListReq 角色列表请求参数
|
||||
type RoleListReq struct {
|
||||
Page int `json:"page" v:"min:1#页码最小为1"`
|
||||
PageSize int `json:"page_size" v:"min:1,max:100#每页数量范围1-100"`
|
||||
Name string `json:"name"` // 角色名称
|
||||
Code string `json:"code"` // 角色编码
|
||||
Status int `json:"status"` // 状态:-1-全部,0-禁用,1-启用
|
||||
Level int `json:"level"` // 角色等级
|
||||
}
|
||||
356
internal/dao/user.go
Normal file
356
internal/dao/user.go
Normal file
@@ -0,0 +1,356 @@
|
||||
package dao
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/os/gtime"
|
||||
"nl-video-api/internal/model/entity"
|
||||
)
|
||||
|
||||
// UserDao 用户数据访问对象
|
||||
type UserDao struct {
|
||||
table string
|
||||
group string
|
||||
columns UserColumns
|
||||
}
|
||||
|
||||
// UserColumns 用户表字段
|
||||
type UserColumns struct {
|
||||
Id string
|
||||
Username string
|
||||
Phone string
|
||||
Email string
|
||||
Password string
|
||||
Nickname string
|
||||
Avatar string
|
||||
Gender string
|
||||
Birthday string
|
||||
VipLevel string
|
||||
VipExpireAt string
|
||||
Balance string
|
||||
Points string
|
||||
Status string
|
||||
LastLoginAt string
|
||||
LastLoginIp string
|
||||
CreatedAt string
|
||||
UpdatedAt string
|
||||
DeletedAt string
|
||||
}
|
||||
|
||||
// UserListReq 用户列表请求
|
||||
type UserListReq struct {
|
||||
Page int `json:"page" d:"1"`
|
||||
PageSize int `json:"page_size" d:"20"`
|
||||
Username string `json:"username"`
|
||||
Phone string `json:"phone"`
|
||||
Email string `json:"email"`
|
||||
Status int `json:"status"`
|
||||
VipLevel int `json:"vip_level"`
|
||||
Gender int `json:"gender"`
|
||||
StartTime string `json:"start_time"`
|
||||
EndTime string `json:"end_time"`
|
||||
}
|
||||
|
||||
// userDao 用户DAO实例
|
||||
var userDao = UserDao{
|
||||
table: "nl_user",
|
||||
group: "default",
|
||||
columns: UserColumns{
|
||||
Id: "id",
|
||||
Username: "username",
|
||||
Phone: "phone",
|
||||
Email: "email",
|
||||
Password: "password",
|
||||
Nickname: "nickname",
|
||||
Avatar: "avatar",
|
||||
Gender: "gender",
|
||||
Birthday: "birthday",
|
||||
VipLevel: "vip_level",
|
||||
VipExpireAt: "vip_expire_at",
|
||||
Balance: "balance",
|
||||
Points: "points",
|
||||
Status: "status",
|
||||
LastLoginAt: "last_login_at",
|
||||
LastLoginIp: "last_login_ip",
|
||||
CreatedAt: "created_at",
|
||||
UpdatedAt: "updated_at",
|
||||
DeletedAt: "deleted_at",
|
||||
},
|
||||
}
|
||||
|
||||
// NewUserDao 创建用户DAO实例
|
||||
func NewUserDao() *UserDao {
|
||||
return &userDao
|
||||
}
|
||||
|
||||
// Create 创建用户
|
||||
func (dao *UserDao) Create(ctx context.Context, data *entity.NlUser) (int64, error) {
|
||||
data.CreatedAt = int(gtime.Now().Unix())
|
||||
data.UpdatedAt = int(gtime.Now().Unix())
|
||||
|
||||
result, err := g.DB(dao.group).Model(dao.table).Data(data).Insert()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
id, err := result.LastInsertId()
|
||||
return id, err
|
||||
}
|
||||
|
||||
// GetById 根据ID获取用户
|
||||
func (dao *UserDao) GetById(ctx context.Context, id int) (*entity.NlUser, error) {
|
||||
var user *entity.NlUser
|
||||
err := g.DB(dao.group).Model(dao.table).
|
||||
Where(dao.columns.Id, id).
|
||||
Where(dao.columns.DeletedAt, 0).
|
||||
Scan(&user)
|
||||
return user, err
|
||||
}
|
||||
|
||||
// GetByUsername 根据用户名获取用户
|
||||
func (dao *UserDao) GetByUsername(ctx context.Context, username string) (*entity.NlUser, error) {
|
||||
var user *entity.NlUser
|
||||
err := g.DB(dao.group).Model(dao.table).
|
||||
Where(dao.columns.Username, username).
|
||||
Where(dao.columns.DeletedAt, 0).
|
||||
Scan(&user)
|
||||
return user, err
|
||||
}
|
||||
|
||||
// GetByPhone 根据手机号获取用户
|
||||
func (dao *UserDao) GetByPhone(ctx context.Context, phone string) (*entity.NlUser, error) {
|
||||
var user *entity.NlUser
|
||||
err := g.DB(dao.group).Model(dao.table).
|
||||
Where(dao.columns.Phone, phone).
|
||||
Where(dao.columns.DeletedAt, 0).
|
||||
Scan(&user)
|
||||
return user, err
|
||||
}
|
||||
|
||||
// GetByEmail 根据邮箱获取用户
|
||||
func (dao *UserDao) GetByEmail(ctx context.Context, email string) (*entity.NlUser, error) {
|
||||
var user *entity.NlUser
|
||||
err := g.DB(dao.group).Model(dao.table).
|
||||
Where(dao.columns.Email, email).
|
||||
Where(dao.columns.DeletedAt, 0).
|
||||
Scan(&user)
|
||||
return user, err
|
||||
}
|
||||
|
||||
// Update 更新用户
|
||||
func (dao *UserDao) Update(ctx context.Context, id int, data g.Map) error {
|
||||
data[dao.columns.UpdatedAt] = gtime.Now().Unix()
|
||||
|
||||
_, err := g.DB(dao.group).Model(dao.table).
|
||||
Where(dao.columns.Id, id).
|
||||
Where(dao.columns.DeletedAt, 0).
|
||||
Data(data).
|
||||
Update()
|
||||
return err
|
||||
}
|
||||
|
||||
// Delete 删除用户(软删除)
|
||||
func (dao *UserDao) Delete(ctx context.Context, id int) error {
|
||||
_, err := g.DB(dao.group).Model(dao.table).
|
||||
Where(dao.columns.Id, id).
|
||||
Data(g.Map{
|
||||
dao.columns.DeletedAt: gtime.Now().Unix(),
|
||||
dao.columns.UpdatedAt: gtime.Now().Unix(),
|
||||
}).
|
||||
Update()
|
||||
return err
|
||||
}
|
||||
|
||||
// GetList 获取用户列表
|
||||
func (dao *UserDao) GetList(ctx context.Context, req *UserListReq) ([]*entity.NlUser, int, error) {
|
||||
model := g.DB(dao.group).Model(dao.table).Where(dao.columns.DeletedAt, 0)
|
||||
|
||||
// 添加查询条件
|
||||
if req.Username != "" {
|
||||
model = model.WhereLike(dao.columns.Username, "%"+req.Username+"%")
|
||||
}
|
||||
if req.Phone != "" {
|
||||
model = model.WhereLike(dao.columns.Phone, "%"+req.Phone+"%")
|
||||
}
|
||||
if req.Email != "" {
|
||||
model = model.WhereLike(dao.columns.Email, "%"+req.Email+"%")
|
||||
}
|
||||
if req.Status >= 0 {
|
||||
model = model.Where(dao.columns.Status, req.Status)
|
||||
}
|
||||
if req.VipLevel > 0 {
|
||||
model = model.Where(dao.columns.VipLevel, req.VipLevel)
|
||||
}
|
||||
if req.Gender >= 0 {
|
||||
model = model.Where(dao.columns.Gender, req.Gender)
|
||||
}
|
||||
if req.StartTime != "" {
|
||||
model = model.WhereGTE(dao.columns.CreatedAt, gtime.NewFromStr(req.StartTime).Unix())
|
||||
}
|
||||
if req.EndTime != "" {
|
||||
model = model.WhereLTE(dao.columns.CreatedAt, gtime.NewFromStr(req.EndTime).Unix())
|
||||
}
|
||||
|
||||
// 获取总数
|
||||
total, err := model.Count()
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
// 分页查询
|
||||
var users []*entity.NlUser
|
||||
err = model.Page(req.Page, req.PageSize).
|
||||
OrderDesc(dao.columns.CreatedAt).
|
||||
Scan(&users)
|
||||
|
||||
return users, total, err
|
||||
}
|
||||
|
||||
// BatchUpdateStatus 批量更新用户状态
|
||||
func (dao *UserDao) BatchUpdateStatus(ctx context.Context, ids []int, status int) error {
|
||||
_, err := g.DB(dao.group).Model(dao.table).
|
||||
WhereIn(dao.columns.Id, ids).
|
||||
Where(dao.columns.DeletedAt, 0).
|
||||
Data(g.Map{
|
||||
dao.columns.Status: status,
|
||||
dao.columns.UpdatedAt: gtime.Now().Unix(),
|
||||
}).
|
||||
Update()
|
||||
return err
|
||||
}
|
||||
|
||||
// BatchDelete 批量删除用户
|
||||
func (dao *UserDao) BatchDelete(ctx context.Context, ids []int) error {
|
||||
_, err := g.DB(dao.group).Model(dao.table).
|
||||
WhereIn(dao.columns.Id, ids).
|
||||
Data(g.Map{
|
||||
dao.columns.DeletedAt: gtime.Now().Unix(),
|
||||
dao.columns.UpdatedAt: gtime.Now().Unix(),
|
||||
}).
|
||||
Update()
|
||||
return err
|
||||
}
|
||||
|
||||
// GetUserStats 获取用户统计信息
|
||||
func (dao *UserDao) GetUserStats(ctx context.Context) (g.Map, error) {
|
||||
// 总用户数
|
||||
totalUsers, err := g.DB(dao.group).Model(dao.table).
|
||||
Where(dao.columns.DeletedAt, 0).
|
||||
Count()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 活跃用户数
|
||||
activeUsers, err := g.DB(dao.group).Model(dao.table).
|
||||
Where(dao.columns.DeletedAt, 0).
|
||||
Where(dao.columns.Status, 1).
|
||||
Count()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// VIP用户数
|
||||
vipUsers, err := g.DB(dao.group).Model(dao.table).
|
||||
Where(dao.columns.DeletedAt, 0).
|
||||
Where(dao.columns.VipLevel+" > ?", 1).
|
||||
Count()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 今日新增用户
|
||||
todayStart := gtime.Now().StartOfDay().Unix()
|
||||
todayUsers, err := g.DB(dao.group).Model(dao.table).
|
||||
Where(dao.columns.DeletedAt, 0).
|
||||
WhereGTE(dao.columns.CreatedAt, todayStart).
|
||||
Count()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return g.Map{
|
||||
"total_users": totalUsers,
|
||||
"active_users": activeUsers,
|
||||
"vip_users": vipUsers,
|
||||
"today_users": todayUsers,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// UpdateLoginInfo 更新登录信息
|
||||
func (dao *UserDao) UpdateLoginInfo(ctx context.Context, id int, ip string) error {
|
||||
_, err := g.DB(dao.group).Model(dao.table).
|
||||
Where(dao.columns.Id, id).
|
||||
Data(g.Map{
|
||||
dao.columns.LastLoginAt: gtime.Now().Unix(),
|
||||
dao.columns.LastLoginIp: ip,
|
||||
dao.columns.UpdatedAt: gtime.Now().Unix(),
|
||||
}).
|
||||
Update()
|
||||
return err
|
||||
}
|
||||
|
||||
// GetVipUsers 获取VIP用户列表
|
||||
func (dao *UserDao) GetVipUsers(ctx context.Context, page, pageSize int) ([]*entity.NlUser, int, error) {
|
||||
model := g.DB(dao.group).Model(dao.table).
|
||||
Where(dao.columns.DeletedAt, 0).
|
||||
Where(dao.columns.VipLevel+" > ?", 1)
|
||||
|
||||
// 获取总数
|
||||
total, err := model.Count()
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
// 分页查询
|
||||
var users []*entity.NlUser
|
||||
err = model.Page(page, pageSize).
|
||||
OrderDesc(dao.columns.VipLevel).
|
||||
OrderDesc(dao.columns.VipExpireAt).
|
||||
Scan(&users)
|
||||
|
||||
return users, total, err
|
||||
}
|
||||
|
||||
// GetExpiredVipUsers 获取VIP即将过期的用户
|
||||
func (dao *UserDao) GetExpiredVipUsers(ctx context.Context, days int) ([]*entity.NlUser, error) {
|
||||
expireTime := gtime.Now().AddDate(0, 0, days).Unix()
|
||||
|
||||
var users []*entity.NlUser
|
||||
err := g.DB(dao.group).Model(dao.table).
|
||||
Where(dao.columns.DeletedAt, 0).
|
||||
Where(dao.columns.VipLevel+" > ?", 1).
|
||||
Where(dao.columns.VipExpireAt+" <= ?", expireTime).
|
||||
Where(dao.columns.VipExpireAt+" > ?", gtime.Now().Unix()).
|
||||
Scan(&users)
|
||||
|
||||
return users, err
|
||||
}
|
||||
|
||||
// SearchUsers 搜索用户
|
||||
func (dao *UserDao) SearchUsers(ctx context.Context, keyword string, page, pageSize int) ([]*entity.NlUser, int, error) {
|
||||
model := g.DB(dao.group).Model(dao.table).
|
||||
Where(dao.columns.DeletedAt, 0).
|
||||
Where(g.Map{
|
||||
dao.columns.Username + " LIKE ? OR " + dao.columns.Phone + " LIKE ? OR " + dao.columns.Email + " LIKE ?": []interface{}{
|
||||
"%" + keyword + "%",
|
||||
"%" + keyword + "%",
|
||||
"%" + keyword + "%",
|
||||
},
|
||||
})
|
||||
|
||||
// 获取总数
|
||||
total, err := model.Count()
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
// 分页查询
|
||||
var users []*entity.NlUser
|
||||
err = model.Page(page, pageSize).
|
||||
OrderDesc(dao.columns.CreatedAt).
|
||||
Scan(&users)
|
||||
|
||||
return users, total, err
|
||||
}
|
||||
76
internal/dao/user_collect.go
Normal file
76
internal/dao/user_collect.go
Normal file
@@ -0,0 +1,76 @@
|
||||
// =================================================================================
|
||||
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
|
||||
// =================================================================================
|
||||
|
||||
package dao
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/gogf/gf/v2/database/gdb"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
)
|
||||
|
||||
// internalUserCollectDao is internal type for wrapping internal DAO implements.
|
||||
type internalUserCollectDao struct {
|
||||
table string // table is the underlying table name of the DAO.
|
||||
group string // group is the database configuration group name of current DAO.
|
||||
columns UserCollectColumns // columns contains all the column names of Table for convenient usage.
|
||||
}
|
||||
|
||||
// UserCollectColumns defines and stores column names for table nl_user_collect.
|
||||
type UserCollectColumns struct {
|
||||
Id string // 收藏ID
|
||||
UserId string // 用户ID
|
||||
MovieId string // 影片ID
|
||||
CreatedAt string // 创建时间
|
||||
UpdatedAt string // 更新时间
|
||||
}
|
||||
|
||||
// userCollectColumns holds the columns for table nl_user_collect.
|
||||
var userCollectColumns = UserCollectColumns{
|
||||
Id: "id",
|
||||
UserId: "user_id",
|
||||
MovieId: "movie_id",
|
||||
CreatedAt: "created_at",
|
||||
UpdatedAt: "updated_at",
|
||||
}
|
||||
|
||||
// NewUserCollectDao creates and returns a new DAO object for table data access.
|
||||
func NewUserCollectDao() *internalUserCollectDao {
|
||||
return &internalUserCollectDao{
|
||||
group: "default",
|
||||
table: "nl_user_collect",
|
||||
columns: userCollectColumns,
|
||||
}
|
||||
}
|
||||
|
||||
// DB retrieves and returns the underlying raw database management object of current DAO.
|
||||
func (dao *internalUserCollectDao) DB() gdb.DB {
|
||||
return g.DB(dao.group)
|
||||
}
|
||||
|
||||
// Table returns the table name of current dao.
|
||||
func (dao *internalUserCollectDao) Table() string {
|
||||
return dao.table
|
||||
}
|
||||
|
||||
// Columns returns the columns of current dao.
|
||||
func (dao *internalUserCollectDao) Columns() UserCollectColumns {
|
||||
return dao.columns
|
||||
}
|
||||
|
||||
// Group returns the configuration group name of database of current dao.
|
||||
func (dao *internalUserCollectDao) Group() string {
|
||||
return dao.group
|
||||
}
|
||||
|
||||
// Ctx creates and returns the Model for current DAO, It automatically sets the context for current operation.
|
||||
func (dao *internalUserCollectDao) Ctx(ctx context.Context) *gdb.Model {
|
||||
return dao.DB().Model(dao.table).Safe().Ctx(ctx)
|
||||
}
|
||||
|
||||
// Transaction wraps the transaction logic using function f.
|
||||
func (dao *internalUserCollectDao) Transaction(ctx context.Context, f func(ctx context.Context, tx gdb.TX) error) error {
|
||||
return dao.Ctx(ctx).Transaction(ctx, f)
|
||||
}
|
||||
82
internal/dao/user_log.go
Normal file
82
internal/dao/user_log.go
Normal file
@@ -0,0 +1,82 @@
|
||||
// =================================================================================
|
||||
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
|
||||
// =================================================================================
|
||||
|
||||
package dao
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/gogf/gf/v2/database/gdb"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
)
|
||||
|
||||
// internalUserLogDao is internal type for wrapping internal DAO implements.
|
||||
type internalUserLogDao struct {
|
||||
table string // table is the underlying table name of the DAO.
|
||||
group string // group is the database configuration group name of current DAO.
|
||||
columns UserLogColumns // columns contains all the column names of Table for convenient usage.
|
||||
}
|
||||
|
||||
// UserLogColumns defines and stores column names for table nl_user_log.
|
||||
type UserLogColumns struct {
|
||||
Id string // 日志ID
|
||||
UserId string // 用户ID
|
||||
Action string // 操作动作
|
||||
Module string // 操作模块
|
||||
Content string // 操作内容
|
||||
Ip string // IP地址
|
||||
UserAgent string // 用户代理
|
||||
CreatedAt string // 创建时间
|
||||
}
|
||||
|
||||
// userLogColumns holds the columns for table nl_user_log.
|
||||
var userLogColumns = UserLogColumns{
|
||||
Id: "id",
|
||||
UserId: "user_id",
|
||||
Action: "action",
|
||||
Module: "module",
|
||||
Content: "content",
|
||||
Ip: "ip",
|
||||
UserAgent: "user_agent",
|
||||
CreatedAt: "created_at",
|
||||
}
|
||||
|
||||
// NewUserLogDao creates and returns a new DAO object for table data access.
|
||||
func NewUserLogDao() *internalUserLogDao {
|
||||
return &internalUserLogDao{
|
||||
group: "default",
|
||||
table: "nl_user_log",
|
||||
columns: userLogColumns,
|
||||
}
|
||||
}
|
||||
|
||||
// DB retrieves and returns the underlying raw database management object of current DAO.
|
||||
func (dao *internalUserLogDao) DB() gdb.DB {
|
||||
return g.DB(dao.group)
|
||||
}
|
||||
|
||||
// Table returns the table name of current dao.
|
||||
func (dao *internalUserLogDao) Table() string {
|
||||
return dao.table
|
||||
}
|
||||
|
||||
// Columns returns the columns of current dao.
|
||||
func (dao *internalUserLogDao) Columns() UserLogColumns {
|
||||
return dao.columns
|
||||
}
|
||||
|
||||
// Group returns the configuration group name of database of current dao.
|
||||
func (dao *internalUserLogDao) Group() string {
|
||||
return dao.group
|
||||
}
|
||||
|
||||
// Ctx creates and returns the Model for current DAO, It automatically sets the context for current operation.
|
||||
func (dao *internalUserLogDao) Ctx(ctx context.Context) *gdb.Model {
|
||||
return dao.DB().Model(dao.table).Safe().Ctx(ctx)
|
||||
}
|
||||
|
||||
// Transaction wraps the transaction logic using function f.
|
||||
func (dao *internalUserLogDao) Transaction(ctx context.Context, f func(ctx context.Context, tx gdb.TX) error) error {
|
||||
return dao.Ctx(ctx).Transaction(ctx, f)
|
||||
}
|
||||
86
internal/dao/user_watch_history.go
Normal file
86
internal/dao/user_watch_history.go
Normal file
@@ -0,0 +1,86 @@
|
||||
// =================================================================================
|
||||
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
|
||||
// =================================================================================
|
||||
|
||||
package dao
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/gogf/gf/v2/database/gdb"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
)
|
||||
|
||||
// internalUserWatchHistoryDao is internal type for wrapping internal DAO implements.
|
||||
type internalUserWatchHistoryDao struct {
|
||||
table string // table is the underlying table name of the DAO.
|
||||
group string // group is the database configuration group name of current DAO.
|
||||
columns UserWatchHistoryColumns // columns contains all the column names of Table for convenient usage.
|
||||
}
|
||||
|
||||
// UserWatchHistoryColumns defines and stores column names for table nl_user_watch_history.
|
||||
type UserWatchHistoryColumns struct {
|
||||
Id string // 观看记录ID
|
||||
UserId string // 用户ID
|
||||
MovieId string // 影片ID
|
||||
EpisodeId string // 集数ID
|
||||
WatchTime string // 观看时长(秒)
|
||||
TotalTime string // 总时长(秒)
|
||||
Progress string // 观看进度百分比
|
||||
LastWatchTime string // 最后观看时间
|
||||
CreatedAt string // 创建时间
|
||||
UpdatedAt string // 更新时间
|
||||
}
|
||||
|
||||
// userWatchHistoryColumns holds the columns for table nl_user_watch_history.
|
||||
var userWatchHistoryColumns = UserWatchHistoryColumns{
|
||||
Id: "id",
|
||||
UserId: "user_id",
|
||||
MovieId: "movie_id",
|
||||
EpisodeId: "episode_id",
|
||||
WatchTime: "watch_time",
|
||||
TotalTime: "total_time",
|
||||
Progress: "progress",
|
||||
LastWatchTime: "last_watch_time",
|
||||
CreatedAt: "created_at",
|
||||
UpdatedAt: "updated_at",
|
||||
}
|
||||
|
||||
// NewUserWatchHistoryDao creates and returns a new DAO object for table data access.
|
||||
func NewUserWatchHistoryDao() *internalUserWatchHistoryDao {
|
||||
return &internalUserWatchHistoryDao{
|
||||
group: "default",
|
||||
table: "nl_user_watch_history",
|
||||
columns: userWatchHistoryColumns,
|
||||
}
|
||||
}
|
||||
|
||||
// DB retrieves and returns the underlying raw database management object of current DAO.
|
||||
func (dao *internalUserWatchHistoryDao) DB() gdb.DB {
|
||||
return g.DB(dao.group)
|
||||
}
|
||||
|
||||
// Table returns the table name of current dao.
|
||||
func (dao *internalUserWatchHistoryDao) Table() string {
|
||||
return dao.table
|
||||
}
|
||||
|
||||
// Columns returns the columns of current dao.
|
||||
func (dao *internalUserWatchHistoryDao) Columns() UserWatchHistoryColumns {
|
||||
return dao.columns
|
||||
}
|
||||
|
||||
// Group returns the configuration group name of database of current dao.
|
||||
func (dao *internalUserWatchHistoryDao) Group() string {
|
||||
return dao.group
|
||||
}
|
||||
|
||||
// Ctx creates and returns the Model for current DAO, It automatically sets the context for current operation.
|
||||
func (dao *internalUserWatchHistoryDao) Ctx(ctx context.Context) *gdb.Model {
|
||||
return dao.DB().Model(dao.table).Safe().Ctx(ctx)
|
||||
}
|
||||
|
||||
// Transaction wraps the transaction logic using function f.
|
||||
func (dao *internalUserWatchHistoryDao) Transaction(ctx context.Context, f func(ctx context.Context, tx gdb.TX) error) error {
|
||||
return dao.Ctx(ctx).Transaction(ctx, f)
|
||||
}
|
||||
88
internal/dao/vip_level.go
Normal file
88
internal/dao/vip_level.go
Normal file
@@ -0,0 +1,88 @@
|
||||
// =================================================================================
|
||||
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
|
||||
// =================================================================================
|
||||
|
||||
package dao
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/gogf/gf/v2/database/gdb"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
)
|
||||
|
||||
// internalVipLevelDao is internal type for wrapping internal DAO implements.
|
||||
type internalVipLevelDao struct {
|
||||
table string // table is the underlying table name of the DAO.
|
||||
group string // group is the database configuration group name of current DAO.
|
||||
columns VipLevelColumns // columns contains all the column names of Table for convenient usage.
|
||||
}
|
||||
|
||||
// VipLevelColumns defines and stores column names for table nl_vip_level.
|
||||
type VipLevelColumns struct {
|
||||
Id string // VIP等级ID
|
||||
Name string // VIP等级名称
|
||||
Level string // 等级数值
|
||||
Price string // 价格
|
||||
Duration string // 有效期(天)
|
||||
Description string // 等级描述
|
||||
Privileges string // 特权说明(JSON格式)
|
||||
Status string // 状态:0禁用,1启用
|
||||
Sort string // 排序
|
||||
CreatedAt string // 创建时间
|
||||
UpdatedAt string // 更新时间
|
||||
}
|
||||
|
||||
// vipLevelColumns holds the columns for table nl_vip_level.
|
||||
var vipLevelColumns = VipLevelColumns{
|
||||
Id: "id",
|
||||
Name: "name",
|
||||
Level: "level",
|
||||
Price: "price",
|
||||
Duration: "duration",
|
||||
Description: "description",
|
||||
Privileges: "privileges",
|
||||
Status: "status",
|
||||
Sort: "sort",
|
||||
CreatedAt: "created_at",
|
||||
UpdatedAt: "updated_at",
|
||||
}
|
||||
|
||||
// NewVipLevelDao creates and returns a new DAO object for table data access.
|
||||
func NewVipLevelDao() *internalVipLevelDao {
|
||||
return &internalVipLevelDao{
|
||||
group: "default",
|
||||
table: "nl_vip_level",
|
||||
columns: vipLevelColumns,
|
||||
}
|
||||
}
|
||||
|
||||
// DB retrieves and returns the underlying raw database management object of current DAO.
|
||||
func (dao *internalVipLevelDao) DB() gdb.DB {
|
||||
return g.DB(dao.group)
|
||||
}
|
||||
|
||||
// Table returns the table name of current dao.
|
||||
func (dao *internalVipLevelDao) Table() string {
|
||||
return dao.table
|
||||
}
|
||||
|
||||
// Columns returns the columns of current dao.
|
||||
func (dao *internalVipLevelDao) Columns() VipLevelColumns {
|
||||
return dao.columns
|
||||
}
|
||||
|
||||
// Group returns the configuration group name of database of current dao.
|
||||
func (dao *internalVipLevelDao) Group() string {
|
||||
return dao.group
|
||||
}
|
||||
|
||||
// Ctx creates and returns the Model for current DAO, It automatically sets the context for current operation.
|
||||
func (dao *internalVipLevelDao) Ctx(ctx context.Context) *gdb.Model {
|
||||
return dao.DB().Model(dao.table).Safe().Ctx(ctx)
|
||||
}
|
||||
|
||||
// Transaction wraps the transaction logic using function f.
|
||||
func (dao *internalVipLevelDao) Transaction(ctx context.Context, f func(ctx context.Context, tx gdb.TX) error) error {
|
||||
return dao.Ctx(ctx).Transaction(ctx, f)
|
||||
}
|
||||
0
internal/logic/.gitkeep
Normal file
0
internal/logic/.gitkeep
Normal file
0
internal/model/.gitkeep
Normal file
0
internal/model/.gitkeep
Normal file
0
internal/model/do/.gitkeep
Normal file
0
internal/model/do/.gitkeep
Normal file
0
internal/model/entity/.gitkeep
Normal file
0
internal/model/entity/.gitkeep
Normal file
25
internal/model/entity/admin.go
Normal file
25
internal/model/entity/admin.go
Normal file
@@ -0,0 +1,25 @@
|
||||
package entity
|
||||
|
||||
// NlAdmin 管理员表
|
||||
type NlAdmin struct {
|
||||
Id uint `json:"id" orm:"id,primary"` // 管理员ID
|
||||
OpenId string `json:"open_id" orm:"open_id"` // OpenID,用于第三方登录
|
||||
Username string `json:"username" orm:"username"` // 用户名
|
||||
JobNumber string `json:"job_number" orm:"job_number"` // 工号
|
||||
Avatar string `json:"avatar" orm:"avatar"` // 头像
|
||||
NickName string `json:"nick_name" orm:"nick_name"` // 昵称
|
||||
Password string `json:"-" orm:"password"` // 密码
|
||||
Phone string `json:"phone" orm:"phone"` // 手机号
|
||||
Email string `json:"email" orm:"email"` // 邮箱
|
||||
RoleId int `json:"role_id" orm:"role_id"` // 角色ID
|
||||
Department string `json:"department" orm:"department"` // 部门
|
||||
RegIp int64 `json:"reg_ip" orm:"reg_ip"` // 注册IP
|
||||
LastLoginTime int `json:"last_login_time" orm:"last_login_time"` // 最后登录时间
|
||||
LastLoginIp int64 `json:"last_login_ip" orm:"last_login_ip"` // 最后登录IP
|
||||
OperationPassword string `json:"operation_password" orm:"operation_password"` // 操作密码
|
||||
Desc string `json:"desc" orm:"desc"` // 备注
|
||||
Status int `json:"status" orm:"status"` // 状态 1正常 0禁用
|
||||
CreatedAt int `json:"created_at" orm:"created_at"` // 创建时间
|
||||
UpdatedAt int `json:"updated_at" orm:"updated_at"` // 更新时间
|
||||
DeletedAt int `json:"deleted_at" orm:"deleted_at"` // 删除时间
|
||||
}
|
||||
21
internal/model/entity/admin_log.go
Normal file
21
internal/model/entity/admin_log.go
Normal file
@@ -0,0 +1,21 @@
|
||||
// =================================================================================
|
||||
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
|
||||
// =================================================================================
|
||||
|
||||
package entity
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/v2/os/gtime"
|
||||
)
|
||||
|
||||
// AdminLog is the golang structure for table nl_admin_log.
|
||||
type AdminLog struct {
|
||||
Id uint `json:"id" orm:"id" description:"日志ID"`
|
||||
AdminId int `json:"admin_id" orm:"admin_id" description:"管理员ID"`
|
||||
Action string `json:"action" orm:"action" description:"操作动作"`
|
||||
Module string `json:"module" orm:"module" description:"操作模块"`
|
||||
Content string `json:"content" orm:"content" description:"操作内容"`
|
||||
Ip string `json:"ip" orm:"ip" description:"IP地址"`
|
||||
UserAgent string `json:"user_agent" orm:"user_agent" description:"用户代理"`
|
||||
CreatedAt *gtime.Time `json:"created_at" orm:"created_at" description:"创建时间"`
|
||||
}
|
||||
24
internal/model/entity/attachment.go
Normal file
24
internal/model/entity/attachment.go
Normal file
@@ -0,0 +1,24 @@
|
||||
// =================================================================================
|
||||
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
|
||||
// =================================================================================
|
||||
|
||||
package entity
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/v2/os/gtime"
|
||||
)
|
||||
|
||||
// Attachment is the golang structure for table nl_attachment.
|
||||
type Attachment struct {
|
||||
Id uint `json:"id" orm:"id" description:"附件ID"`
|
||||
Name string `json:"name" orm:"name" description:"文件名"`
|
||||
Path string `json:"path" orm:"path" description:"文件路径"`
|
||||
Url string `json:"url" orm:"url" description:"访问URL"`
|
||||
Size int64 `json:"size" orm:"size" description:"文件大小(字节)"`
|
||||
MimeType string `json:"mime_type" orm:"mime_type" description:"文件类型"`
|
||||
Extension string `json:"extension" orm:"extension" description:"文件扩展名"`
|
||||
UserId int `json:"user_id" orm:"user_id" description:"上传用户ID"`
|
||||
Status int `json:"status" orm:"status" description:"状态:0禁用,1启用"`
|
||||
CreatedAt *gtime.Time `json:"created_at" orm:"created_at" description:"创建时间"`
|
||||
UpdatedAt *gtime.Time `json:"updated_at" orm:"updated_at" description:"更新时间"`
|
||||
}
|
||||
21
internal/model/entity/banner.go
Normal file
21
internal/model/entity/banner.go
Normal file
@@ -0,0 +1,21 @@
|
||||
// =================================================================================
|
||||
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
|
||||
// =================================================================================
|
||||
|
||||
package entity
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/v2/os/gtime"
|
||||
)
|
||||
|
||||
// Banner is the golang structure for table nl_banner.
|
||||
type Banner struct {
|
||||
Id uint `json:"id" orm:"id" description:"轮播图ID"`
|
||||
Title string `json:"title" orm:"title" description:"轮播图标题"`
|
||||
ImageUrl string `json:"image_url" orm:"image_url" description:"图片URL"`
|
||||
LinkUrl string `json:"link_url" orm:"link_url" description:"跳转链接"`
|
||||
Sort int `json:"sort" orm:"sort" description:"排序"`
|
||||
Status int `json:"status" orm:"status" description:"状态:0禁用,1启用"`
|
||||
CreatedAt *gtime.Time `json:"created_at" orm:"created_at" description:"创建时间"`
|
||||
UpdatedAt *gtime.Time `json:"updated_at" orm:"updated_at" description:"更新时间"`
|
||||
}
|
||||
22
internal/model/entity/comment.go
Normal file
22
internal/model/entity/comment.go
Normal file
@@ -0,0 +1,22 @@
|
||||
// =================================================================================
|
||||
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
|
||||
// =================================================================================
|
||||
|
||||
package entity
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/v2/os/gtime"
|
||||
)
|
||||
|
||||
// Comment is the golang structure for table nl_comment.
|
||||
type Comment struct {
|
||||
Id uint `json:"id" orm:"id" description:"评论ID"`
|
||||
UserId int `json:"user_id" orm:"user_id" description:"用户ID"`
|
||||
MovieId int `json:"movie_id" orm:"movie_id" description:"影片ID"`
|
||||
ParentId int `json:"parent_id" orm:"parent_id" description:"父评论ID,0为顶级评论"`
|
||||
Content string `json:"content" orm:"content" description:"评论内容"`
|
||||
LikeCount int `json:"like_count" orm:"like_count" description:"点赞数"`
|
||||
Status int `json:"status" orm:"status" description:"状态:0待审核,1已通过,2已拒绝"`
|
||||
CreatedAt *gtime.Time `json:"created_at" orm:"created_at" description:"创建时间"`
|
||||
UpdatedAt *gtime.Time `json:"updated_at" orm:"updated_at" description:"更新时间"`
|
||||
}
|
||||
17
internal/model/entity/comment_like.go
Normal file
17
internal/model/entity/comment_like.go
Normal file
@@ -0,0 +1,17 @@
|
||||
// =================================================================================
|
||||
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
|
||||
// =================================================================================
|
||||
|
||||
package entity
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/v2/os/gtime"
|
||||
)
|
||||
|
||||
// CommentLike is the golang structure for table comment_like.
|
||||
type CommentLike struct {
|
||||
Id uint `json:"id" orm:"id,primary" description:"点赞ID"`
|
||||
CommentId uint `json:"comment_id" orm:"comment_id" description:"评论ID"`
|
||||
UserId uint `json:"user_id" orm:"user_id" description:"用户ID"`
|
||||
CreatedAt *gtime.Time `json:"created_at" orm:"created_at" description:"创建时间"`
|
||||
}
|
||||
20
internal/model/entity/comment_report.go
Normal file
20
internal/model/entity/comment_report.go
Normal file
@@ -0,0 +1,20 @@
|
||||
// =================================================================================
|
||||
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
|
||||
// =================================================================================
|
||||
|
||||
package entity
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/v2/os/gtime"
|
||||
)
|
||||
|
||||
// CommentReport is the golang structure for table comment_report.
|
||||
type CommentReport struct {
|
||||
Id uint `json:"id" orm:"id,primary" description:"举报ID"`
|
||||
CommentId uint `json:"comment_id" orm:"comment_id" description:"评论ID"`
|
||||
UserId uint `json:"user_id" orm:"user_id" description:"举报用户ID"`
|
||||
Reason string `json:"reason" orm:"reason" description:"举报原因"`
|
||||
Status int `json:"status" orm:"status" description:"处理状态(0:待处理,1:已处理,2:已忽略)"`
|
||||
CreatedAt *gtime.Time `json:"created_at" orm:"created_at" description:"创建时间"`
|
||||
UpdatedAt *gtime.Time `json:"updated_at" orm:"updated_at" description:"更新时间"`
|
||||
}
|
||||
21
internal/model/entity/config.go
Normal file
21
internal/model/entity/config.go
Normal file
@@ -0,0 +1,21 @@
|
||||
// =================================================================================
|
||||
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
|
||||
// =================================================================================
|
||||
|
||||
package entity
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/v2/os/gtime"
|
||||
)
|
||||
|
||||
// Config is the golang structure for table nl_config.
|
||||
type Config struct {
|
||||
Id uint `json:"id" orm:"id" description:"配置ID"`
|
||||
ConfigKey string `json:"config_key" orm:"config_key" description:"配置键"`
|
||||
ConfigValue string `json:"config_value" orm:"config_value" description:"配置值"`
|
||||
ConfigType string `json:"config_type" orm:"config_type" description:"配置类型"`
|
||||
Description string `json:"description" orm:"description" description:"配置描述"`
|
||||
Status int `json:"status" orm:"status" description:"状态:0禁用,1启用"`
|
||||
CreatedAt *gtime.Time `json:"created_at" orm:"created_at" description:"创建时间"`
|
||||
UpdatedAt *gtime.Time `json:"updated_at" orm:"updated_at" description:"更新时间"`
|
||||
}
|
||||
23
internal/model/entity/episode.go
Normal file
23
internal/model/entity/episode.go
Normal file
@@ -0,0 +1,23 @@
|
||||
package entity
|
||||
|
||||
// Episode 集数实体
|
||||
type Episode struct {
|
||||
Id int `json:"id" orm:"id,primary"` // 集数ID
|
||||
MovieId int `json:"movie_id" orm:"movie_id"` // 影片ID
|
||||
EpisodeNum int `json:"episode_num" orm:"episode_num"` // 集数
|
||||
Title string `json:"title" orm:"title"` // 集数标题
|
||||
Description string `json:"description" orm:"description"` // 集数简介
|
||||
Duration int `json:"duration" orm:"duration"` // 时长(秒)
|
||||
VideoUrl string `json:"video_url" orm:"video_url"` // 视频地址
|
||||
VideoSize int64 `json:"video_size" orm:"video_size"` // 视频大小(字节)
|
||||
VideoFormat string `json:"video_format" orm:"video_format"` // 视频格式
|
||||
Resolution string `json:"resolution" orm:"resolution"` // 分辨率
|
||||
Thumbnail string `json:"thumbnail" orm:"thumbnail"` // 缩略图
|
||||
ViewCount int `json:"view_count" orm:"view_count"` // 观看次数
|
||||
IsVip int `json:"is_vip" orm:"is_vip"` // 是否VIP专享:0-否,1-是
|
||||
Sort int `json:"sort" orm:"sort"` // 排序
|
||||
Status int `json:"status" orm:"status"` // 状态:1-正常,0-下架
|
||||
CreatedAt string `json:"created_at" orm:"created_at"` // 创建时间
|
||||
UpdatedAt string `json:"updated_at" orm:"updated_at"` // 更新时间
|
||||
DeletedAt string `json:"deleted_at" orm:"deleted_at"` // 删除时间
|
||||
}
|
||||
35
internal/model/entity/movie.go
Normal file
35
internal/model/entity/movie.go
Normal file
@@ -0,0 +1,35 @@
|
||||
package entity
|
||||
|
||||
// Movie 影片实体
|
||||
type Movie struct {
|
||||
Id int `json:"id" orm:"id,primary"` // 影片ID
|
||||
Title string `json:"title" orm:"title"` // 影片标题
|
||||
OriginalTitle string `json:"original_title" orm:"original_title"` // 原始标题
|
||||
Poster string `json:"poster" orm:"poster"` // 海报图片
|
||||
Banner string `json:"banner" orm:"banner"` // 横幅图片
|
||||
CategoryId int `json:"category_id" orm:"category_id"` // 分类ID
|
||||
Type int `json:"type" orm:"type"` // 类型:1-电影,2-电视剧,3-综艺,4-动漫,5-纪录片
|
||||
Area string `json:"area" orm:"area"` // 地区
|
||||
Language string `json:"language" orm:"language"` // 语言
|
||||
Year int `json:"year" orm:"year"` // 年份
|
||||
Duration int `json:"duration" orm:"duration"` // 时长(分钟)
|
||||
Director string `json:"director" orm:"director"` // 导演
|
||||
Actor string `json:"actor" orm:"actor"` // 演员
|
||||
Description string `json:"description" orm:"description"` // 简介
|
||||
Tags string `json:"tags" orm:"tags"` // 标签,逗号分隔
|
||||
Rating float64 `json:"rating" orm:"rating"` // 评分
|
||||
RatingCount int `json:"rating_count" orm:"rating_count"` // 评分人数
|
||||
ViewCount int `json:"view_count" orm:"view_count"` // 观看次数
|
||||
LikeCount int `json:"like_count" orm:"like_count"` // 点赞数
|
||||
CollectCount int `json:"collect_count" orm:"collect_count"` // 收藏数
|
||||
CommentCount int `json:"comment_count" orm:"comment_count"` // 评论数
|
||||
IsVip int `json:"is_vip" orm:"is_vip"` // 是否VIP专享:0-否,1-是
|
||||
IsRecommend int `json:"is_recommend" orm:"is_recommend"` // 是否推荐:0-否,1-是
|
||||
IsHot int `json:"is_hot" orm:"is_hot"` // 是否热门:0-否,1-是
|
||||
IsNew int `json:"is_new" orm:"is_new"` // 是否最新:0-否,1-是
|
||||
Sort int `json:"sort" orm:"sort"` // 排序
|
||||
Status int `json:"status" orm:"status"` // 状态:1-正常,0-下架
|
||||
CreatedAt string `json:"created_at" orm:"created_at"` // 创建时间
|
||||
UpdatedAt string `json:"updated_at" orm:"updated_at"` // 更新时间
|
||||
DeletedAt string `json:"deleted_at" orm:"deleted_at"` // 删除时间
|
||||
}
|
||||
25
internal/model/entity/payment_order.go
Normal file
25
internal/model/entity/payment_order.go
Normal file
@@ -0,0 +1,25 @@
|
||||
// =================================================================================
|
||||
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
|
||||
// =================================================================================
|
||||
|
||||
package entity
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/v2/os/gtime"
|
||||
)
|
||||
|
||||
// PaymentOrder is the golang structure for table nl_payment_order.
|
||||
type PaymentOrder struct {
|
||||
Id uint `json:"id" orm:"id" description:"订单ID"`
|
||||
OrderNo string `json:"order_no" orm:"order_no" description:"订单号"`
|
||||
UserId int `json:"user_id" orm:"user_id" description:"用户ID"`
|
||||
VipLevelId int `json:"vip_level_id" orm:"vip_level_id" description:"VIP等级ID"`
|
||||
Amount float64 `json:"amount" orm:"amount" description:"订单金额"`
|
||||
PaymentMethod string `json:"payment_method" orm:"payment_method" description:"支付方式"`
|
||||
PaymentStatus int `json:"payment_status" orm:"payment_status" description:"支付状态:0待支付,1已支付,2已取消,3已退款"`
|
||||
PaymentTime *gtime.Time `json:"payment_time" orm:"payment_time" description:"支付时间"`
|
||||
ExpireTime *gtime.Time `json:"expire_time" orm:"expire_time" description:"过期时间"`
|
||||
Remark string `json:"remark" orm:"remark" description:"备注"`
|
||||
CreatedAt *gtime.Time `json:"created_at" orm:"created_at" description:"创建时间"`
|
||||
UpdatedAt *gtime.Time `json:"updated_at" orm:"updated_at" description:"更新时间"`
|
||||
}
|
||||
24
internal/model/entity/permission.go
Normal file
24
internal/model/entity/permission.go
Normal file
@@ -0,0 +1,24 @@
|
||||
package entity
|
||||
|
||||
// Permission 权限实体
|
||||
type Permission struct {
|
||||
Id int `json:"id" orm:"id,primary"` // 权限ID
|
||||
ParentId int `json:"parent_id" orm:"parent_id"` // 父级权限ID
|
||||
Name string `json:"name" orm:"name"` // 权限名称
|
||||
Slug string `json:"slug" orm:"slug"` // 权限标识
|
||||
Type int `json:"type" orm:"type"` // 权限类型:1-菜单,2-按钮,3-接口
|
||||
Path string `json:"path" orm:"path"` // 路由路径
|
||||
Component string `json:"component" orm:"component"` // 组件路径
|
||||
Icon string `json:"icon" orm:"icon"` // 图标
|
||||
Method string `json:"method" orm:"method"` // 请求方法
|
||||
ApiPath string `json:"api_path" orm:"api_path"` // API路径
|
||||
Description string `json:"description" orm:"description"` // 权限描述
|
||||
IsHidden int `json:"is_hidden" orm:"is_hidden"` // 是否隐藏:0-否,1-是
|
||||
IsCache int `json:"is_cache" orm:"is_cache"` // 是否缓存:0-否,1-是
|
||||
IsSystem int `json:"is_system" orm:"is_system"` // 是否系统权限:0-否,1-是
|
||||
Sort int `json:"sort" orm:"sort"` // 排序
|
||||
Status int `json:"status" orm:"status"` // 状态:1-启用,0-禁用
|
||||
CreatedAt string `json:"created_at" orm:"created_at"` // 创建时间
|
||||
UpdatedAt string `json:"updated_at" orm:"updated_at"` // 更新时间
|
||||
DeletedAt string `json:"deleted_at" orm:"deleted_at"` // 删除时间
|
||||
}
|
||||
16
internal/model/entity/role.go
Normal file
16
internal/model/entity/role.go
Normal file
@@ -0,0 +1,16 @@
|
||||
package entity
|
||||
|
||||
// Role 角色实体
|
||||
type Role struct {
|
||||
Id int `json:"id" orm:"id,primary"` // 角色ID
|
||||
Name string `json:"name" orm:"name"` // 角色名称
|
||||
Slug string `json:"slug" orm:"slug"` // 角色标识
|
||||
Description string `json:"description" orm:"description"` // 角色描述
|
||||
Level int `json:"level" orm:"level"` // 角色等级
|
||||
IsSystem int `json:"is_system" orm:"is_system"` // 是否系统角色:0-否,1-是
|
||||
Sort int `json:"sort" orm:"sort"` // 排序
|
||||
Status int `json:"status" orm:"status"` // 状态:1-启用,0-禁用
|
||||
CreatedAt string `json:"created_at" orm:"created_at"` // 创建时间
|
||||
UpdatedAt string `json:"updated_at" orm:"updated_at"` // 更新时间
|
||||
DeletedAt string `json:"deleted_at" orm:"deleted_at"` // 删除时间
|
||||
}
|
||||
32
internal/model/entity/user.go
Normal file
32
internal/model/entity/user.go
Normal file
@@ -0,0 +1,32 @@
|
||||
package entity
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// NlUser 用户表
|
||||
type NlUser struct {
|
||||
Id uint `json:"id" orm:"id,primary"` // 用户ID
|
||||
OpenId string `json:"open_id" orm:"open_id"` // OpenID,用于第三方登录
|
||||
Username string `json:"username" orm:"username"` // 用户名
|
||||
Avatar string `json:"avatar" orm:"avatar"` // 头像
|
||||
NickName string `json:"nick_name" orm:"nick_name"` // 昵称
|
||||
Password string `json:"-" orm:"password"` // 密码
|
||||
Phone string `json:"phone" orm:"phone"` // 手机号
|
||||
Email string `json:"email" orm:"email"` // 邮箱
|
||||
Gender int `json:"gender" orm:"gender"` // 性别 0未知 1男 2女
|
||||
Birthday *time.Time `json:"birthday" orm:"birthday"` // 生日
|
||||
VipLevel int `json:"vip_level" orm:"vip_level"` // VIP等级 0普通用户 1VIP1 2VIP2
|
||||
VipExpireTime int `json:"vip_expire_time" orm:"vip_expire_time"` // VIP到期时间
|
||||
Balance float64 `json:"balance" orm:"balance"` // 余额
|
||||
Points int `json:"points" orm:"points"` // 积分
|
||||
RegIp int64 `json:"reg_ip" orm:"reg_ip"` // 注册IP
|
||||
LastLoginTime int `json:"last_login_time" orm:"last_login_time"` // 最后登录时间
|
||||
LastLoginIp int64 `json:"last_login_ip" orm:"last_login_ip"` // 最后登录IP
|
||||
LoginCount int `json:"login_count" orm:"login_count"` // 登录次数
|
||||
Desc string `json:"desc" orm:"desc"` // 备注
|
||||
Status int `json:"status" orm:"status"` // 状态 1正常 0禁用
|
||||
CreatedAt int `json:"created_at" orm:"created_at"` // 创建时间
|
||||
UpdatedAt int `json:"updated_at" orm:"updated_at"` // 更新时间
|
||||
DeletedAt int `json:"deleted_at" orm:"deleted_at"` // 删除时间
|
||||
}
|
||||
19
internal/model/entity/user_collect.go
Normal file
19
internal/model/entity/user_collect.go
Normal file
@@ -0,0 +1,19 @@
|
||||
// =================================================================================
|
||||
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
|
||||
// =================================================================================
|
||||
|
||||
package entity
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/v2/os/gtime"
|
||||
)
|
||||
|
||||
// UserCollect is the golang structure for table nl_user_collect.
|
||||
type UserCollect struct {
|
||||
Id uint `json:"id" orm:"id" description:"收藏ID"`
|
||||
UserId int `json:"user_id" orm:"user_id" description:"用户ID"`
|
||||
MovieId int `json:"movie_id" orm:"movie_id" description:"影片ID"`
|
||||
Type int `json:"type" orm:"type" description:"收藏类型 1影片 2演员 3导演"`
|
||||
TargetId int `json:"target_id" orm:"target_id" description:"目标ID"`
|
||||
CreatedAt *gtime.Time `json:"created_at" orm:"created_at" description:"创建时间"`
|
||||
}
|
||||
21
internal/model/entity/user_log.go
Normal file
21
internal/model/entity/user_log.go
Normal file
@@ -0,0 +1,21 @@
|
||||
// =================================================================================
|
||||
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
|
||||
// =================================================================================
|
||||
|
||||
package entity
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/v2/os/gtime"
|
||||
)
|
||||
|
||||
// UserLog is the golang structure for table nl_user_log.
|
||||
type UserLog struct {
|
||||
Id uint `json:"id" orm:"id" description:"日志ID"`
|
||||
UserId int `json:"user_id" orm:"user_id" description:"用户ID"`
|
||||
Action string `json:"action" orm:"action" description:"操作动作"`
|
||||
Module string `json:"module" orm:"module" description:"操作模块"`
|
||||
Content string `json:"content" orm:"content" description:"操作内容"`
|
||||
Ip string `json:"ip" orm:"ip" description:"IP地址"`
|
||||
UserAgent string `json:"user_agent" orm:"user_agent" description:"用户代理"`
|
||||
CreatedAt *gtime.Time `json:"created_at" orm:"created_at" description:"创建时间"`
|
||||
}
|
||||
23
internal/model/entity/user_watch_history.go
Normal file
23
internal/model/entity/user_watch_history.go
Normal file
@@ -0,0 +1,23 @@
|
||||
// =================================================================================
|
||||
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
|
||||
// =================================================================================
|
||||
|
||||
package entity
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/v2/os/gtime"
|
||||
)
|
||||
|
||||
// UserWatchHistory is the golang structure for table nl_user_watch_history.
|
||||
type UserWatchHistory struct {
|
||||
Id uint `json:"id" orm:"id" description:"观看记录ID"`
|
||||
UserId int `json:"user_id" orm:"user_id" description:"用户ID"`
|
||||
MovieId int `json:"movie_id" orm:"movie_id" description:"影片ID"`
|
||||
EpisodeId int `json:"episode_id" orm:"episode_id" description:"集数ID"`
|
||||
WatchTime int `json:"watch_time" orm:"watch_time" description:"观看时长(秒)"`
|
||||
TotalTime int `json:"total_time" orm:"total_time" description:"总时长(秒)"`
|
||||
Progress float64 `json:"progress" orm:"progress" description:"观看进度百分比"`
|
||||
LastWatchTime int `json:"last_watch_time" orm:"last_watch_time" description:"最后观看时间"`
|
||||
CreatedAt *gtime.Time `json:"created_at" orm:"created_at" description:"创建时间"`
|
||||
UpdatedAt *gtime.Time `json:"updated_at" orm:"updated_at" description:"更新时间"`
|
||||
}
|
||||
24
internal/model/entity/vip_level.go
Normal file
24
internal/model/entity/vip_level.go
Normal file
@@ -0,0 +1,24 @@
|
||||
// =================================================================================
|
||||
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
|
||||
// =================================================================================
|
||||
|
||||
package entity
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/v2/os/gtime"
|
||||
)
|
||||
|
||||
// VipLevel is the golang structure for table nl_vip_level.
|
||||
type VipLevel struct {
|
||||
Id uint `json:"id" orm:"id" description:"VIP等级ID"`
|
||||
Name string `json:"name" orm:"name" description:"VIP等级名称"`
|
||||
Level int `json:"level" orm:"level" description:"等级数值"`
|
||||
Price float64 `json:"price" orm:"price" description:"价格"`
|
||||
Duration int `json:"duration" orm:"duration" description:"有效期(天)"`
|
||||
Description string `json:"description" orm:"description" description:"等级描述"`
|
||||
Privileges string `json:"privileges" orm:"privileges" description:"特权说明(JSON格式)"`
|
||||
Status int `json:"status" orm:"status" description:"状态:0禁用,1启用"`
|
||||
Sort int `json:"sort" orm:"sort" description:"排序"`
|
||||
CreatedAt *gtime.Time `json:"created_at" orm:"created_at" description:"创建时间"`
|
||||
UpdatedAt *gtime.Time `json:"updated_at" orm:"updated_at" description:"更新时间"`
|
||||
}
|
||||
1
internal/packed/packed.go
Normal file
1
internal/packed/packed.go
Normal file
@@ -0,0 +1 @@
|
||||
package packed
|
||||
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