完善功能
This commit is contained in:
@ -11,6 +11,6 @@ import (
|
||||
)
|
||||
|
||||
type IAdminV1 interface {
|
||||
AdminInfo(ctx context.Context, req *v1.AdminInfoReq) (res *v1.AdminInfoRes, err error)
|
||||
AdminEditPass(ctx context.Context, req *v1.AdminEditPassReq) (res *v1.AdminEditPassRes, err error)
|
||||
Info(ctx context.Context, req *v1.InfoReq) (res *v1.InfoRes, err error)
|
||||
EditPass(ctx context.Context, req *v1.EditPassReq) (res *v1.EditPassRes, err error)
|
||||
}
|
||||
|
||||
@ -4,21 +4,21 @@ import (
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
)
|
||||
|
||||
type AdminInfoReq struct {
|
||||
g.Meta `path:"/admin/info" tags:"Admin" method:"get" summary:"管理员信息"`
|
||||
type InfoReq struct {
|
||||
g.Meta `path:"/admin/info" tags:"Backend/Admin" method:"get" summary:"管理员信息"`
|
||||
}
|
||||
type AdminInfoRes struct {
|
||||
type InfoRes struct {
|
||||
g.Meta `mime:"application/json"`
|
||||
AdminId int64 `json:"adminId"`
|
||||
Username string `json:"username"`
|
||||
}
|
||||
|
||||
type AdminEditPassReq struct {
|
||||
g.Meta `path:"/admin/editPass" tags:"Admin" method:"post" summary:"修改密码"`
|
||||
type EditPassReq struct {
|
||||
g.Meta `path:"/admin/editPass" tags:"Backend/Admin" method:"post" summary:"修改密码"`
|
||||
OldPass string `json:"oldPass" v:"required" dc:"旧密码"`
|
||||
NewPass string `json:"newPass" v:"required" dc:"新密码"`
|
||||
}
|
||||
type AdminEditPassRes struct {
|
||||
type EditPassRes struct {
|
||||
g.Meta `mime:"application/json"`
|
||||
Success bool
|
||||
}
|
||||
|
||||
21
api/author/author.go
Normal file
21
api/author/author.go
Normal file
@ -0,0 +1,21 @@
|
||||
// =================================================================================
|
||||
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
|
||||
// =================================================================================
|
||||
|
||||
package author
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"server/api/author/v1"
|
||||
)
|
||||
|
||||
type IAuthorV1 interface {
|
||||
List(ctx context.Context, req *v1.ListReq) (res *v1.ListRes, err error)
|
||||
Add(ctx context.Context, req *v1.AddReq) (res *v1.AddRes, err error)
|
||||
Edit(ctx context.Context, req *v1.EditReq) (res *v1.EditRes, err error)
|
||||
Del(ctx context.Context, req *v1.DelReq) (res *v1.DelRes, err error)
|
||||
Follow(ctx context.Context, req *v1.FollowReq) (res *v1.FollowRes, err error)
|
||||
Unfollow(ctx context.Context, req *v1.UnfollowReq) (res *v1.UnfollowRes, err error)
|
||||
Detail(ctx context.Context, req *v1.DetailReq) (res *v1.DetailRes, err error)
|
||||
}
|
||||
75
api/author/v1/author.go
Normal file
75
api/author/v1/author.go
Normal file
@ -0,0 +1,75 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"server/internal/model"
|
||||
)
|
||||
|
||||
type ListReq struct {
|
||||
g.Meta `path:"/author" tags:"Backend/Admin" method:"get" summary:"获取作者列表"`
|
||||
Page int `json:"page" dc:"页码"`
|
||||
Size int `json:"size" dc:"每页数量"`
|
||||
PenName string `json:"penName" dc:"笔名(模糊搜索)"`
|
||||
Status int `json:"status" dc:"状态:1正常,2禁用"`
|
||||
}
|
||||
type ListRes struct {
|
||||
Total int `json:"total" dc:"总数"`
|
||||
List interface{} `json:"list" dc:"作者列表"`
|
||||
}
|
||||
|
||||
type AddReq struct {
|
||||
g.Meta `path:"/author" tags:"Backend/Admin" method:"post" summary:"新增作者"`
|
||||
UserId int64 `json:"userId" dc:"用户ID" v:"required"`
|
||||
PenName string `json:"penName" dc:"笔名" v:"required"`
|
||||
Bio string `json:"bio" dc:"作者简介"`
|
||||
Status int `json:"status" dc:"状态:1正常,2禁用"`
|
||||
}
|
||||
type AddRes struct {
|
||||
Success bool `json:"success" dc:"是否成功"`
|
||||
}
|
||||
|
||||
type EditReq struct {
|
||||
g.Meta `path:"/author" tags:"Backend/Admin" method:"put" summary:"编辑作者"`
|
||||
Id int64 `json:"id" dc:"作者ID" v:"required"`
|
||||
PenName string `json:"penName" dc:"笔名" v:"required"`
|
||||
Bio string `json:"bio" dc:"作者简介"`
|
||||
Status int `json:"status" dc:"状态:1正常,2禁用"`
|
||||
}
|
||||
type EditRes struct {
|
||||
Success bool `json:"success" dc:"是否成功"`
|
||||
}
|
||||
|
||||
type DelReq struct {
|
||||
g.Meta `path:"/author" tags:"Backend/Admin" method:"delete" summary:"删除作者"`
|
||||
Id int64 `json:"id" dc:"作者ID" v:"required"`
|
||||
}
|
||||
type DelRes struct {
|
||||
Success bool `json:"success" dc:"是否成功"`
|
||||
}
|
||||
|
||||
// 关注作者
|
||||
// =============================
|
||||
type FollowReq struct {
|
||||
g.Meta `path:"/author/follow" tags:"APP" method:"post" summary:"关注作者"`
|
||||
AuthorId int64 `json:"authorId" dc:"作者ID" v:"required"`
|
||||
}
|
||||
type FollowRes struct {
|
||||
Success bool `json:"success" dc:"是否成功"`
|
||||
}
|
||||
|
||||
// 取消关注作者
|
||||
// =============================
|
||||
type UnfollowReq struct {
|
||||
g.Meta `path:"/author/unfollow" tags:"APP" method:"post" summary:"取消关注作者"`
|
||||
AuthorId int64 `json:"authorId" dc:"作者ID" v:"required"`
|
||||
}
|
||||
type UnfollowRes struct {
|
||||
Success bool `json:"success" dc:"是否成功"`
|
||||
}
|
||||
type DetailReq struct {
|
||||
g.Meta `path:"/author/detail" tags:"APP" method:"get" summary:"作者详情"`
|
||||
AuthorId int64 `json:"authorId" dc:"作者ID" v:"required"`
|
||||
}
|
||||
type DetailRes struct {
|
||||
Author *model.AuthorDetailOut `json:"author" dc:"作者信息"`
|
||||
}
|
||||
@ -11,8 +11,16 @@ import (
|
||||
)
|
||||
|
||||
type IBookV1 interface {
|
||||
BookList(ctx context.Context, req *v1.BookListReq) (res *v1.BookListRes, err error)
|
||||
BookAdd(ctx context.Context, req *v1.BookAddReq) (res *v1.BookAddRes, err error)
|
||||
BookEdit(ctx context.Context, req *v1.BookEditReq) (res *v1.BookEditRes, err error)
|
||||
BookDel(ctx context.Context, req *v1.BookDelReq) (res *v1.BookDelRes, err error)
|
||||
List(ctx context.Context, req *v1.ListReq) (res *v1.ListRes, err error)
|
||||
Add(ctx context.Context, req *v1.AddReq) (res *v1.AddRes, err error)
|
||||
Edit(ctx context.Context, req *v1.EditReq) (res *v1.EditRes, err error)
|
||||
Del(ctx context.Context, req *v1.DelReq) (res *v1.DelRes, err error)
|
||||
ShelfAdd(ctx context.Context, req *v1.ShelfAddReq) (res *v1.ShelfAddRes, err error)
|
||||
ShelfRemove(ctx context.Context, req *v1.ShelfRemoveReq) (res *v1.ShelfRemoveRes, err error)
|
||||
AppList(ctx context.Context, req *v1.AppListReq) (res *v1.AppListRes, err error)
|
||||
AppDetail(ctx context.Context, req *v1.AppDetailReq) (res *v1.AppDetailRes, err error)
|
||||
AppRate(ctx context.Context, req *v1.AppRateReq) (res *v1.AppRateRes, err error)
|
||||
MyList(ctx context.Context, req *v1.MyListReq) (res *v1.MyListRes, err error)
|
||||
BookSetFeatured(ctx context.Context, req *v1.BookSetFeaturedReq) (res *v1.BookSetFeaturedRes, err error)
|
||||
BookSetRecommended(ctx context.Context, req *v1.BookSetRecommendedReq) (res *v1.BookSetRecommendedRes, err error)
|
||||
}
|
||||
|
||||
@ -6,56 +6,180 @@ import (
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
)
|
||||
|
||||
type BookListReq struct {
|
||||
g.Meta `path:"/book" tags:"Book" method:"get" summary:"获取小说列表"`
|
||||
Page int `json:"page"`
|
||||
Size int `json:"size"`
|
||||
Title string `json:"title"`
|
||||
CategoryId int64 `json:"categoryId"`
|
||||
AuthorId int64 `json:"authorId"`
|
||||
Status int `json:"status"`
|
||||
IsRecommended int `json:"isRecommended"`
|
||||
type ListReq struct {
|
||||
g.Meta `path:"/book" tags:"Backend/Author" method:"get" summary:"获取小说列表"`
|
||||
Page int `json:"page" dc:"页码"`
|
||||
Size int `json:"size" dc:"每页数量"`
|
||||
Title string `json:"title" dc:"书名模糊搜索"`
|
||||
CategoryId int64 `json:"categoryId" dc:"分类ID"`
|
||||
AuthorId int64 `json:"authorId" dc:"作者ID"`
|
||||
Status int `json:"status" dc:"状态"`
|
||||
IsRecommended int `json:"isRecommended" dc:"是否推荐"`
|
||||
Sort string `json:"sort" dc:"排序字段"`
|
||||
}
|
||||
type BookListRes struct {
|
||||
Total int `json:"total"`
|
||||
List []model.Book `json:"list"`
|
||||
type ListRes struct {
|
||||
Total int `json:"total" dc:"总数"`
|
||||
List []model.Book `json:"list" dc:"书籍列表"`
|
||||
}
|
||||
|
||||
type BookAddReq struct {
|
||||
g.Meta `path:"/book" tags:"Book" method:"post" summary:"新增小说"`
|
||||
AuthorId int64 `json:"authorId"`
|
||||
CategoryId int64 `json:"categoryId"`
|
||||
Title string `json:"title"`
|
||||
CoverUrl string `json:"coverUrl"`
|
||||
Description string `json:"description"`
|
||||
Status int `json:"status"`
|
||||
Tags string `json:"tags"`
|
||||
IsRecommended int `json:"isRecommended"`
|
||||
type AddReq struct {
|
||||
g.Meta `path:"/book" tags:"Backend/Author" method:"post" summary:"新增小说"`
|
||||
AuthorId int64 `json:"authorId" dc:"作者ID" v:"required"`
|
||||
CategoryId int64 `json:"categoryId" dc:"分类ID" v:"required"`
|
||||
Title string `json:"title" dc:"书名" v:"required"`
|
||||
CoverUrl string `json:"coverUrl" dc:"封面图"`
|
||||
Description string `json:"description" dc:"简介"`
|
||||
Status int `json:"status" dc:"状态"`
|
||||
Tags string `json:"tags" dc:"标签"`
|
||||
IsRecommended int `json:"isRecommended" dc:"是否推荐"`
|
||||
IsFeatured int `json:"isFeatured" dc:"是否精选"`
|
||||
Language string `json:"language" dc:"语言"`
|
||||
}
|
||||
type BookAddRes struct {
|
||||
Success bool `json:"success"`
|
||||
type AddRes struct {
|
||||
Success bool `json:"success" dc:"是否成功"`
|
||||
}
|
||||
|
||||
type BookEditReq struct {
|
||||
g.Meta `path:"/book" tags:"Book" method:"put" summary:"编辑小说"`
|
||||
Id int64 `json:"id"`
|
||||
AuthorId int64 `json:"authorId"`
|
||||
CategoryId int64 `json:"categoryId"`
|
||||
Title string `json:"title"`
|
||||
CoverUrl string `json:"coverUrl"`
|
||||
Description string `json:"description"`
|
||||
Status int `json:"status"`
|
||||
Tags string `json:"tags"`
|
||||
IsRecommended int `json:"isRecommended"`
|
||||
type EditReq struct {
|
||||
g.Meta `path:"/book" tags:"Backend/Author" method:"put" summary:"编辑小说"`
|
||||
Id int64 `json:"id" dc:"书籍ID" v:"required"`
|
||||
AuthorId int64 `json:"authorId" dc:"作者ID" v:"required"`
|
||||
CategoryId int64 `json:"categoryId" dc:"分类ID" v:"required"`
|
||||
Title string `json:"title" dc:"书名" v:"required"`
|
||||
CoverUrl string `json:"coverUrl" dc:"封面图"`
|
||||
Description string `json:"description" dc:"简介"`
|
||||
Status int `json:"status" dc:"状态"`
|
||||
Tags string `json:"tags" dc:"标签"`
|
||||
IsRecommended int `json:"isRecommended" dc:"是否推荐"`
|
||||
IsFeatured int `json:"isFeatured" dc:"是否精选"`
|
||||
Language string `json:"language" dc:"语言"`
|
||||
}
|
||||
type BookEditRes struct {
|
||||
Success bool `json:"success"`
|
||||
type EditRes struct {
|
||||
Success bool `json:"success" dc:"是否成功"`
|
||||
}
|
||||
|
||||
type BookDelReq struct {
|
||||
g.Meta `path:"/book" tags:"Book" method:"delete" summary:"删除小说"`
|
||||
Id int64 `json:"id"`
|
||||
type DelReq struct {
|
||||
g.Meta `path:"/book" tags:"Backend/Author" method:"delete" summary:"删除小说"`
|
||||
Id int64 `json:"id" dc:"书籍ID" v:"required"`
|
||||
}
|
||||
type BookDelRes struct {
|
||||
Success bool `json:"success"`
|
||||
type DelRes struct {
|
||||
Success bool `json:"success" dc:"是否成功"`
|
||||
}
|
||||
|
||||
// 加入书架
|
||||
type ShelfAddReq struct {
|
||||
g.Meta `path:"/book/shelf/add" tags:"APP" method:"post" summary:"加入书架"`
|
||||
BookId int64 `json:"bookId" dc:"小说ID" v:"required"`
|
||||
}
|
||||
type ShelfAddRes struct {
|
||||
Success bool `json:"success" dc:"是否成功"`
|
||||
}
|
||||
|
||||
// 移除书架
|
||||
type ShelfRemoveReq struct {
|
||||
g.Meta `path:"/book/shelf/remove" tags:"APP" method:"post" summary:"移除书架(支持批量)"`
|
||||
BookIds []int64 `json:"bookIds" dc:"小说ID列表" v:"required"`
|
||||
}
|
||||
type ShelfRemoveRes struct {
|
||||
Success bool `json:"success" dc:"是否成功"`
|
||||
}
|
||||
|
||||
// App 获取书籍列表
|
||||
type AppListReq struct {
|
||||
g.Meta `path:"/book/app/list" tags:"APP" method:"get" summary:"App获取书籍列表"`
|
||||
Page int `json:"page" dc:"页码"`
|
||||
Size int `json:"size" dc:"每页数量"`
|
||||
IsRecommended bool `json:"isRecommended" dc:"是否推荐"`
|
||||
IsFeatured bool `json:"isFeatured" dc:"是否精选"`
|
||||
IsLatest int `json:"isLatest" dc:"是否最新"`
|
||||
CategoryId int64 `json:"categoryId" dc:"分类ID"`
|
||||
Title string `json:"title" dc:"书名模糊搜索"`
|
||||
AuthorId int `json:"authorId" dc:"作者ID"`
|
||||
Language string `json:"language" dc:"语言"`
|
||||
Sort string `json:"sort" dc:"排序字段"`
|
||||
}
|
||||
type AppListRes struct {
|
||||
Total int `json:"total" dc:"总数"`
|
||||
List []model.BookAppItem `json:"list" dc:"书籍列表"`
|
||||
}
|
||||
|
||||
// App 获取书籍详情
|
||||
type AppDetailReq struct {
|
||||
g.Meta `path:"/book/app/detail" tags:"APP" method:"get" summary:"App获取书籍详情"`
|
||||
Id int64 `json:"id" dc:"书籍ID" v:"required"`
|
||||
}
|
||||
type AppDetailRes struct {
|
||||
Id int64 `json:"id" dc:"书籍ID"`
|
||||
AuthorId int64 `json:"authorId" dc:"作者ID"`
|
||||
CategoryId int64 `json:"categoryId" dc:"分类ID"`
|
||||
Title string `json:"title" dc:"书名"`
|
||||
CoverUrl string `json:"coverUrl" dc:"封面图"`
|
||||
Description string `json:"description" dc:"简介"`
|
||||
Status int `json:"status" dc:"状态"`
|
||||
Tags string `json:"tags" dc:"标签"`
|
||||
IsRecommended int `json:"isRecommended" dc:"是否推荐"`
|
||||
IsFeatured int `json:"isFeatured" dc:"是否精选"`
|
||||
Language string `json:"language" dc:"语言"`
|
||||
Rating float64 `json:"rating" dc:"评分"`
|
||||
CurrentReaders int64 `json:"currentReaders" dc:"在读人数"`
|
||||
CreatedAt string `json:"createdAt" dc:"创建时间"`
|
||||
UpdatedAt string `json:"updatedAt" dc:"更新时间"`
|
||||
HasRead bool `json:"hasRead" dc:"是否读过"`
|
||||
ReadProgress int `json:"readProgress" dc:"阅读进度百分比"`
|
||||
LastChapterId int64 `json:"lastChapterId" dc:"最近阅读章节ID"`
|
||||
LastReadAt string `json:"lastReadAt" dc:"最近阅读时间"`
|
||||
}
|
||||
|
||||
// App 用户评分
|
||||
type AppRateReq struct {
|
||||
g.Meta `path:"/book/app/rate" tags:"APP" method:"post" summary:"App用户评分"`
|
||||
BookId int64 `json:"bookId" dc:"书籍ID" v:"required"`
|
||||
Rating float64 `json:"rating" dc:"评分(1-10分)" v:"required"`
|
||||
}
|
||||
type AppRateRes struct {
|
||||
Success bool `json:"success" dc:"是否成功"`
|
||||
}
|
||||
|
||||
type BookAppItem struct {
|
||||
Id int64 `json:"id" dc:"书籍ID"`
|
||||
CoverUrl string `json:"coverUrl" dc:"封面图"`
|
||||
Rating float64 `json:"rating" dc:"评分"`
|
||||
Title string `json:"title" dc:"标题"`
|
||||
Description string `json:"description" dc:"简介"`
|
||||
HasRated bool `json:"hasRated" dc:"当前用户是否已评分"`
|
||||
MyRating float64 `json:"myRating" dc:"当前用户评分(未评分为0)"`
|
||||
}
|
||||
|
||||
// 我的书籍列表
|
||||
// =============================
|
||||
type MyListReq struct {
|
||||
g.Meta `path:"/book/app/my-books" tags:"APP" method:"get" summary:"获取我的书籍列表"`
|
||||
Type int `json:"type" dc:"类型:1-正在读 2-已读完 3-历史记录" v:"required"`
|
||||
Page int `json:"page" dc:"页码"`
|
||||
Size int `json:"size" dc:"每页数量"`
|
||||
Sort string `json:"sort" dc:"排序字段"`
|
||||
}
|
||||
type MyListRes struct {
|
||||
Total int `json:"total" dc:"总数"`
|
||||
List []model.MyBookItem `json:"list" dc:"书籍列表"`
|
||||
}
|
||||
|
||||
// =============================
|
||||
// 新增:单独修改精选状态和推荐状态
|
||||
// =============================
|
||||
type BookSetFeaturedReq struct {
|
||||
g.Meta `path:"/book/set-featured" tags:"Backend/Book" method:"post" summary:"设置书籍精选状态"`
|
||||
Id int64 `json:"id" dc:"书籍ID" v:"required"`
|
||||
IsFeatured int `json:"isFeatured" dc:"是否精选" v:"required"`
|
||||
}
|
||||
type BookSetFeaturedRes struct {
|
||||
Success bool `json:"success" dc:"是否成功"`
|
||||
}
|
||||
|
||||
type BookSetRecommendedReq struct {
|
||||
g.Meta `path:"/book/set-recommended" tags:"Backend/Book" method:"post" summary:"设置书籍推荐状态"`
|
||||
Id int64 `json:"id" dc:"书籍ID" v:"required"`
|
||||
IsRecommended int `json:"isRecommended" dc:"是否推荐" v:"required"`
|
||||
}
|
||||
type BookSetRecommendedRes struct {
|
||||
Success bool `json:"success" dc:"是否成功"`
|
||||
}
|
||||
|
||||
@ -11,8 +11,8 @@ import (
|
||||
)
|
||||
|
||||
type ICategoryV1 interface {
|
||||
CategoryList(ctx context.Context, req *v1.CategoryListReq) (res *v1.CategoryListRes, err error)
|
||||
CategoryAdd(ctx context.Context, req *v1.CategoryAddReq) (res *v1.CategoryAddRes, err error)
|
||||
CategoryEdit(ctx context.Context, req *v1.CategoryEditReq) (res *v1.CategoryEditRes, err error)
|
||||
CategoryDel(ctx context.Context, req *v1.CategoryDelReq) (res *v1.CategoryDelRes, err error)
|
||||
List(ctx context.Context, req *v1.ListReq) (res *v1.ListRes, err error)
|
||||
Add(ctx context.Context, req *v1.AddReq) (res *v1.AddRes, err error)
|
||||
Edit(ctx context.Context, req *v1.EditReq) (res *v1.EditRes, err error)
|
||||
Del(ctx context.Context, req *v1.DelReq) (res *v1.DelRes, err error)
|
||||
}
|
||||
|
||||
@ -6,41 +6,41 @@ import (
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
)
|
||||
|
||||
type CategoryListReq struct {
|
||||
g.Meta `path:"/category" tags:"Category" method:"get" summary:"获取分类列表"`
|
||||
Page int `json:"page" dc:"页码"`
|
||||
Size int `json:"size" dc:"每页数量"`
|
||||
Name string `json:"name" dc:"分类名称(模糊搜索)"`
|
||||
Type int `json:"type" dc:"类型,1男频,2女频"`
|
||||
type ListReq struct {
|
||||
g.Meta `path:"/category" tags:"APP" method:"get" summary:"获取分类列表"`
|
||||
Page int `json:"page" dc:"页码"`
|
||||
Size int `json:"size" dc:"每页数量"`
|
||||
Name string `json:"name" dc:"分类名称(模糊搜索)"`
|
||||
Channel int `json:"channel" dc:"频道类型:1=男频,2=女频"`
|
||||
}
|
||||
type CategoryListRes struct {
|
||||
type ListRes struct {
|
||||
Total int `json:"total" dc:"总数"`
|
||||
List []model.Category `json:"list" dc:"分类列表"`
|
||||
}
|
||||
|
||||
type CategoryAddReq struct {
|
||||
g.Meta `path:"/category" tags:"Category" method:"post" summary:"新增分类"`
|
||||
Name string `json:"name" dc:"分类名称"`
|
||||
Type int `json:"type" dc:"类型,1男频,2女频"`
|
||||
type AddReq struct {
|
||||
g.Meta `path:"/category" tags:"Backend/Admin" method:"post" summary:"新增分类"`
|
||||
Name string `json:"name" dc:"分类名称" v:"required"`
|
||||
Channel int `json:"channel" dc:"频道类型:1=男频,2=女频" v:"required"`
|
||||
}
|
||||
type CategoryAddRes struct {
|
||||
type AddRes struct {
|
||||
Success bool `json:"success" dc:"是否成功"`
|
||||
}
|
||||
|
||||
type CategoryEditReq struct {
|
||||
g.Meta `path:"/category" tags:"Category" method:"put" summary:"编辑分类"`
|
||||
Id int `json:"id" dc:"分类ID"`
|
||||
Name string `json:"name" dc:"分类名称"`
|
||||
Type int `json:"type" dc:"类型,1男频,2女频"`
|
||||
type EditReq struct {
|
||||
g.Meta `path:"/category" tags:"Backend/Admin" method:"put" summary:"编辑分类"`
|
||||
Id int64 `json:"id" dc:"分类ID" v:"required"`
|
||||
Name string `json:"name" dc:"分类名称" v:"required"`
|
||||
Channel int `json:"channel" dc:"频道类型:1=男频,2=女频" v:"required"`
|
||||
}
|
||||
type CategoryEditRes struct {
|
||||
type EditRes struct {
|
||||
Success bool `json:"success" dc:"是否成功"`
|
||||
}
|
||||
|
||||
type CategoryDelReq struct {
|
||||
g.Meta `path:"/category" tags:"Category" method:"delete" summary:"删除分类"`
|
||||
Id int `json:"id" dc:"分类ID"`
|
||||
type DelReq struct {
|
||||
g.Meta `path:"/category" tags:"Backend/Admin" method:"delete" summary:"删除分类"`
|
||||
Id int64 `json:"id" dc:"分类ID" v:"required"`
|
||||
}
|
||||
type CategoryDelRes struct {
|
||||
type DelRes struct {
|
||||
Success bool `json:"success" dc:"是否成功"`
|
||||
}
|
||||
|
||||
@ -11,8 +11,12 @@ import (
|
||||
)
|
||||
|
||||
type IChapterV1 interface {
|
||||
ChapterList(ctx context.Context, req *v1.ChapterListReq) (res *v1.ChapterListRes, err error)
|
||||
ChapterAdd(ctx context.Context, req *v1.ChapterAddReq) (res *v1.ChapterAddRes, err error)
|
||||
ChapterEdit(ctx context.Context, req *v1.ChapterEditReq) (res *v1.ChapterEditRes, err error)
|
||||
ChapterDel(ctx context.Context, req *v1.ChapterDelReq) (res *v1.ChapterDelRes, err error)
|
||||
List(ctx context.Context, req *v1.ListReq) (res *v1.ListRes, err error)
|
||||
Add(ctx context.Context, req *v1.AddReq) (res *v1.AddRes, err error)
|
||||
Edit(ctx context.Context, req *v1.EditReq) (res *v1.EditRes, err error)
|
||||
Del(ctx context.Context, req *v1.DelReq) (res *v1.DelRes, err error)
|
||||
AppList(ctx context.Context, req *v1.AppListReq) (res *v1.AppListRes, err error)
|
||||
AppDetail(ctx context.Context, req *v1.AppDetailReq) (res *v1.AppDetailRes, err error)
|
||||
AppPurchase(ctx context.Context, req *v1.AppPurchaseReq) (res *v1.AppPurchaseRes, err error)
|
||||
AppProgress(ctx context.Context, req *v1.AppProgressReq) (res *v1.AppProgressRes, err error)
|
||||
}
|
||||
|
||||
@ -6,52 +6,98 @@ import (
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
)
|
||||
|
||||
type ChapterListReq struct {
|
||||
g.Meta `path:"/chapter" tags:"Chapter" method:"get" summary:"获取章节列表"`
|
||||
type ListReq struct {
|
||||
g.Meta `path:"/chapter" tags:"Backend/Author" method:"get" summary:"获取章节列表"`
|
||||
Page int `json:"page" dc:"页码"`
|
||||
Size int `json:"size" dc:"每页数量"`
|
||||
BookId int64 `json:"bookId" dc:"小说ID"`
|
||||
Title string `json:"title" dc:"章节标题(模糊搜索)"`
|
||||
IsLocked int `json:"isLocked" dc:"是否锁定:0免费,1需积分解锁"`
|
||||
}
|
||||
type ChapterListRes struct {
|
||||
type ListRes struct {
|
||||
Total int `json:"total" dc:"总数"`
|
||||
List []model.Chapter `json:"list" dc:"章节列表"`
|
||||
}
|
||||
|
||||
type ChapterAddReq struct {
|
||||
g.Meta `path:"/chapter" tags:"Chapter" method:"post" summary:"新增章节"`
|
||||
BookId int64 `json:"bookId" dc:"小说ID"`
|
||||
Title string `json:"title" dc:"章节标题"`
|
||||
Content string `json:"content" dc:"章节内容"`
|
||||
type AddReq struct {
|
||||
g.Meta `path:"/chapter" tags:"Backend/Author" method:"post" summary:"新增章节"`
|
||||
BookId int64 `json:"bookId" dc:"小说ID" v:"required"`
|
||||
Title string `json:"title" dc:"章节标题" v:"required"`
|
||||
Content string `json:"content" dc:"章节内容" v:"required"`
|
||||
WordCount int `json:"wordCount" dc:"章节字数"`
|
||||
Sort int `json:"sort" dc:"排序序号"`
|
||||
IsLocked int `json:"isLocked" dc:"是否锁定:0免费,1需积分解锁"`
|
||||
RequiredScore int `json:"requiredScore" dc:"解锁所需积分"`
|
||||
}
|
||||
type ChapterAddRes struct {
|
||||
type AddRes struct {
|
||||
Success bool `json:"success" dc:"是否成功"`
|
||||
}
|
||||
|
||||
type ChapterEditReq struct {
|
||||
g.Meta `path:"/chapter" tags:"Chapter" method:"put" summary:"编辑章节"`
|
||||
type EditReq struct {
|
||||
g.Meta `path:"/chapter" tags:"Backend/Author" method:"put" summary:"编辑章节"`
|
||||
Id int64 `json:"id" dc:"章节ID" v:"required"`
|
||||
BookId int64 `json:"bookId" dc:"小说ID" v:"required"`
|
||||
Title string `json:"title" dc:"章节标题" v:"required"`
|
||||
Content string `json:"content" dc:"章节内容" v:"required"`
|
||||
WordCount int `json:"wordCount" dc:"章节字数"`
|
||||
Sort int `json:"sort" dc:"排序序号"`
|
||||
IsLocked int `json:"isLocked" dc:"是否锁定:0免费,1需积分解锁"`
|
||||
RequiredScore int `json:"requiredScore" dc:"解锁所需积分"`
|
||||
}
|
||||
type EditRes struct {
|
||||
Success bool `json:"success" dc:"是否成功"`
|
||||
}
|
||||
|
||||
type DelReq struct {
|
||||
g.Meta `path:"/chapter" tags:"Backend/Author" method:"delete" summary:"删除章节"`
|
||||
Id int64 `json:"id" dc:"章节ID" v:"required"`
|
||||
}
|
||||
type DelRes struct {
|
||||
Success bool `json:"success" dc:"是否成功"`
|
||||
}
|
||||
|
||||
type AppListReq struct {
|
||||
g.Meta `path:"/chapter/app/list" tags:"APP" method:"get" summary:"App获取章节列表"`
|
||||
BookId int64 `json:"bookId" dc:"书籍ID" v:"required"`
|
||||
IsDesc bool `json:"isDesc" dc:"是否逆序排列"`
|
||||
Page int `json:"page" dc:"页码"`
|
||||
Size int `json:"size" dc:"每页数量"`
|
||||
}
|
||||
type AppListRes struct {
|
||||
Total int `json:"total" dc:"总数"`
|
||||
List []model.ChapterAppItem `json:"list" dc:"章节列表"`
|
||||
}
|
||||
|
||||
type AppDetailReq struct {
|
||||
g.Meta `path:"/chapter/app/detail" tags:"APP" method:"get" summary:"App获取章节详情"`
|
||||
Id int64 `json:"id" dc:"章节ID" v:"required"`
|
||||
}
|
||||
type AppDetailRes struct {
|
||||
Id int64 `json:"id" dc:"章节ID"`
|
||||
BookId int64 `json:"bookId" dc:"小说ID"`
|
||||
BookId int64 `json:"bookId" dc:"书籍ID"`
|
||||
Title string `json:"title" dc:"章节标题"`
|
||||
Content string `json:"content" dc:"章节内容"`
|
||||
WordCount int `json:"wordCount" dc:"章节字数"`
|
||||
Sort int `json:"sort" dc:"排序序号"`
|
||||
IsLocked int `json:"isLocked" dc:"是否锁定:0免费,1需积分解锁"`
|
||||
RequiredScore int `json:"requiredScore" dc:"解锁所需积分"`
|
||||
WordCount int `json:"wordCount" dc:"字数"`
|
||||
Sort int `json:"sort" dc:"排序"`
|
||||
IsLocked int `json:"isLocked" dc:"是否锁定"`
|
||||
RequiredScore int `json:"requiredScore" dc:"所需积分"`
|
||||
UpdatedAt string `json:"updatedAt" dc:"更新时间"`
|
||||
}
|
||||
type ChapterEditRes struct {
|
||||
|
||||
type AppPurchaseReq struct {
|
||||
g.Meta `path:"/chapter/app/purchase" tags:"APP" method:"post" summary:"App购买章节"`
|
||||
Id int64 `json:"id" dc:"章节ID" v:"required"`
|
||||
}
|
||||
type AppPurchaseRes struct {
|
||||
Success bool `json:"success" dc:"是否成功"`
|
||||
}
|
||||
|
||||
type ChapterDelReq struct {
|
||||
g.Meta `path:"/chapter" tags:"Chapter" method:"delete" summary:"删除章节"`
|
||||
Id int64 `json:"id" dc:"章节ID"`
|
||||
type AppProgressReq struct {
|
||||
g.Meta `path:"/chapter/app/progress" tags:"APP" method:"post" summary:"App上传阅读进度"`
|
||||
BookId int64 `json:"bookId" dc:"书籍ID" v:"required"`
|
||||
ChapterId int64 `json:"chapterId" dc:"章节ID" v:"required"`
|
||||
Progress int `json:"progress" dc:"阅读进度百分比(0-100)"`
|
||||
}
|
||||
type ChapterDelRes struct {
|
||||
type AppProgressRes struct {
|
||||
Success bool `json:"success" dc:"是否成功"`
|
||||
}
|
||||
|
||||
@ -11,6 +11,6 @@ import (
|
||||
)
|
||||
|
||||
type IFeedbackV1 interface {
|
||||
FeedbackList(ctx context.Context, req *v1.FeedbackListReq) (res *v1.FeedbackListRes, err error)
|
||||
FeedbackAdd(ctx context.Context, req *v1.FeedbackAddReq) (res *v1.FeedbackAddRes, err error)
|
||||
List(ctx context.Context, req *v1.ListReq) (res *v1.ListRes, err error)
|
||||
Add(ctx context.Context, req *v1.AddReq) (res *v1.AddRes, err error)
|
||||
}
|
||||
|
||||
@ -6,22 +6,22 @@ import (
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
)
|
||||
|
||||
type FeedbackListReq struct {
|
||||
g.Meta `path:"/feedback" tags:"Feedback" method:"get" summary:"获取反馈列表"`
|
||||
Page int `json:"page" dc:"页码"`
|
||||
Size int `json:"size" dc:"每页数量"`
|
||||
UserId int64 `json:"userId" dc:"用户ID"`
|
||||
Status int `json:"status" dc:"处理状态:1未处理,2处理中,3已处理"`
|
||||
type ListReq struct {
|
||||
g.Meta `path:"/feedback" tags:"Backend/Admin" method:"get" summary:"获取反馈列表"`
|
||||
Page int `json:"page" dc:"页码"`
|
||||
Size int `json:"size" dc:"每页数量"`
|
||||
UserId int64 `json:"userId" dc:"用户ID"`
|
||||
Status int `json:"status" dc:"处理状态:1未处理,2处理中,3已处理"`
|
||||
}
|
||||
type FeedbackListRes struct {
|
||||
type ListRes struct {
|
||||
Total int `json:"total" dc:"总数"`
|
||||
List []model.Feedback `json:"list" dc:"反馈列表"`
|
||||
}
|
||||
|
||||
type FeedbackAddReq struct {
|
||||
g.Meta `path:"/feedback" tags:"APP/Feedback" method:"post" summary:"新增反馈"`
|
||||
Content string `json:"content" dc:"反馈内容"`
|
||||
type AddReq struct {
|
||||
g.Meta `path:"/feedback" tags:"APP" method:"post" summary:"新增反馈"`
|
||||
Content string `json:"content" dc:"反馈内容" v:"required"`
|
||||
}
|
||||
type FeedbackAddRes struct {
|
||||
type AddRes struct {
|
||||
Success bool `json:"success" dc:"是否成功"`
|
||||
}
|
||||
|
||||
@ -11,7 +11,7 @@ import (
|
||||
)
|
||||
|
||||
type IUserV1 interface {
|
||||
UserInfo(ctx context.Context, req *v1.UserInfoReq) (res *v1.UserInfoRes, err error)
|
||||
Info(ctx context.Context, req *v1.InfoReq) (res *v1.InfoRes, err error)
|
||||
Delete(ctx context.Context, req *v1.DeleteReq) (res *v1.DeleteRes, err error)
|
||||
Logout(ctx context.Context, req *v1.LogoutReq) (res *v1.LogoutRes, err error)
|
||||
}
|
||||
|
||||
@ -4,10 +4,10 @@ import (
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
)
|
||||
|
||||
type UserInfoReq struct {
|
||||
g.Meta `path:"/user/info" tags:"APP/User" method:"get" summary:"获取用户信息"`
|
||||
type InfoReq struct {
|
||||
g.Meta `path:"/user/info" tags:"APP" method:"get" summary:"获取用户信息"`
|
||||
}
|
||||
type UserInfoRes struct {
|
||||
type InfoRes struct {
|
||||
g.Meta `mime:"application/json"`
|
||||
UserId int64 `json:"userId"`
|
||||
Username string `json:"username"` // 用户名
|
||||
@ -17,7 +17,7 @@ type UserInfoRes struct {
|
||||
}
|
||||
|
||||
type DeleteReq struct {
|
||||
g.Meta `path:"/user/delete" tags:"APP/User" method:"post" summary:"删除用户"`
|
||||
g.Meta `path:"/user/delete" tags:"APP" method:"post" summary:"删除用户"`
|
||||
Password string `json:"password" v:"required" dc:"密码"`
|
||||
}
|
||||
|
||||
@ -26,7 +26,7 @@ type DeleteRes struct {
|
||||
}
|
||||
|
||||
type LogoutReq struct {
|
||||
g.Meta `path:"/user/logout" tags:"APP/User" method:"post" summary:"登出"`
|
||||
g.Meta `path:"/user/logout" tags:"APP" method:"post" summary:"登出"`
|
||||
}
|
||||
type LogoutRes struct {
|
||||
Success bool `json:"success" dc:"是否成功"`
|
||||
|
||||
1
build_x86_64.sh
Executable file
1
build_x86_64.sh
Executable file
@ -0,0 +1 @@
|
||||
GOARCH=amd64 GOOS=linux CGO_ENABLED=0 go build -o ./noveltest ./main.go
|
||||
18
go.mod
18
go.mod
@ -5,7 +5,10 @@ go 1.23.0
|
||||
toolchain go1.24.3
|
||||
|
||||
require (
|
||||
github.com/aliyun/aliyun-oss-go-sdk v3.0.2+incompatible
|
||||
github.com/aws/aws-sdk-go v1.55.7
|
||||
github.com/aws/aws-sdk-go-v2 v1.36.5
|
||||
github.com/aws/aws-sdk-go-v2/config v1.29.17
|
||||
github.com/aws/aws-sdk-go-v2/service/sqs v1.38.8
|
||||
github.com/casbin/casbin/v2 v2.108.0
|
||||
github.com/gogf/gf v1.16.9
|
||||
github.com/gogf/gf/contrib/drivers/mysql/v2 v2.9.0
|
||||
@ -19,6 +22,17 @@ require (
|
||||
|
||||
require (
|
||||
github.com/BurntSushi/toml v1.4.0 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.17.70 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.32 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.36 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.36 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.4 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.17 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.25.5 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.30.3 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.34.0 // indirect
|
||||
github.com/aws/smithy-go v1.22.4 // indirect
|
||||
github.com/bmatcuk/doublestar/v4 v4.6.1 // indirect
|
||||
github.com/casbin/govaluate v1.3.0 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||
@ -34,6 +48,7 @@ require (
|
||||
github.com/gomodule/redigo v1.8.5 // indirect
|
||||
github.com/gorilla/websocket v1.5.3 // indirect
|
||||
github.com/grokify/html-strip-tags-go v0.1.0 // indirect
|
||||
github.com/jmespath/go-jmespath v0.4.0 // indirect
|
||||
github.com/magiconair/properties v1.8.9 // indirect
|
||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
@ -48,6 +63,5 @@ require (
|
||||
golang.org/x/net v0.32.0 // indirect
|
||||
golang.org/x/sys v0.28.0 // indirect
|
||||
golang.org/x/text v0.21.0 // indirect
|
||||
golang.org/x/time v0.12.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
)
|
||||
|
||||
40
go.sum
40
go.sum
@ -1,8 +1,36 @@
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/BurntSushi/toml v1.4.0 h1:kuoIxZQy2WRRk1pttg9asf+WVv6tWQuBNVmK8+nqPr0=
|
||||
github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
|
||||
github.com/aliyun/aliyun-oss-go-sdk v3.0.2+incompatible h1:8psS8a+wKfiLt1iVDX79F7Y6wUM49Lcha2FMXt4UM8g=
|
||||
github.com/aliyun/aliyun-oss-go-sdk v3.0.2+incompatible/go.mod h1:T/Aws4fEfogEE9v+HPhhw+CntffsBHJ8nXQCwKr0/g8=
|
||||
github.com/aws/aws-sdk-go v1.55.7 h1:UJrkFq7es5CShfBwlWAC8DA077vp8PyVbQd3lqLiztE=
|
||||
github.com/aws/aws-sdk-go v1.55.7/go.mod h1:eRwEWoyTWFMVYVQzKMNHWP5/RV4xIUGMQfXQHfHkpNU=
|
||||
github.com/aws/aws-sdk-go-v2 v1.36.5 h1:0OF9RiEMEdDdZEMqF9MRjevyxAQcf6gY+E7vwBILFj0=
|
||||
github.com/aws/aws-sdk-go-v2 v1.36.5/go.mod h1:EYrzvCCN9CMUTa5+6lf6MM4tq3Zjp8UhSGR/cBsjai0=
|
||||
github.com/aws/aws-sdk-go-v2/config v1.29.17 h1:jSuiQ5jEe4SAMH6lLRMY9OVC+TqJLP5655pBGjmnjr0=
|
||||
github.com/aws/aws-sdk-go-v2/config v1.29.17/go.mod h1:9P4wwACpbeXs9Pm9w1QTh6BwWwJjwYvJ1iCt5QbCXh8=
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.17.70 h1:ONnH5CM16RTXRkS8Z1qg7/s2eDOhHhaXVd72mmyv4/0=
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.17.70/go.mod h1:M+lWhhmomVGgtuPOhO85u4pEa3SmssPTdcYpP/5J/xc=
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.32 h1:KAXP9JSHO1vKGCr5f4O6WmlVKLFFXgWYAGoJosorxzU=
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.32/go.mod h1:h4Sg6FQdexC1yYG9RDnOvLbW1a/P986++/Y/a+GyEM8=
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.36 h1:SsytQyTMHMDPspp+spo7XwXTP44aJZZAC7fBV2C5+5s=
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.36/go.mod h1:Q1lnJArKRXkenyog6+Y+zr7WDpk4e6XlR6gs20bbeNo=
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.36 h1:i2vNHQiXUvKhs3quBR6aqlgJaiaexz/aNvdCktW/kAM=
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.36/go.mod h1:UdyGa7Q91id/sdyHPwth+043HhmP6yP9MBHgbZM0xo8=
|
||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3 h1:bIqFDwgGXXN1Kpp99pDOdKMTTb5d2KyU5X/BZxjOkRo=
|
||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3/go.mod h1:H5O/EsxDWyU+LP/V8i5sm8cxoZgc2fdNR9bxlOFrQTo=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.4 h1:CXV68E2dNqhuynZJPB80bhPQwAKqBWVer887figW6Jc=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.4/go.mod h1:/xFi9KtvBXP97ppCz1TAEvU1Uf66qvid89rbem3wCzQ=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.17 h1:t0E6FzREdtCsiLIoLCWsYliNsRBgyGD/MCK571qk4MI=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.17/go.mod h1:ygpklyoaypuyDvOM5ujWGrYWpAK3h7ugnmKCU/76Ys4=
|
||||
github.com/aws/aws-sdk-go-v2/service/sqs v1.38.8 h1:80dpSqWMwx2dAm30Ib7J6ucz1ZHfiv5OCRwN/EnCOXQ=
|
||||
github.com/aws/aws-sdk-go-v2/service/sqs v1.38.8/go.mod h1:IzNt/udsXlETCdvBOL0nmyMe2t9cGmXmZgsdoZGYYhI=
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.25.5 h1:AIRJ3lfb2w/1/8wOOSqYb9fUKGwQbtysJ2H1MofRUPg=
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.25.5/go.mod h1:b7SiVprpU+iGazDUqvRSLf5XmCdn+JtT1on7uNL6Ipc=
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.30.3 h1:BpOxT3yhLwSJ77qIY3DoHAQjZsc4HEGfMCE4NGy3uFg=
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.30.3/go.mod h1:vq/GQR1gOFLquZMSrxUK/cpvKCNVYibNyJ1m7JrU88E=
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.34.0 h1:NFOJ/NXEGV4Rq//71Hs1jC/NvPs1ezajK+yQmkwnPV0=
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.34.0/go.mod h1:7ph2tGpfQvwzgistp2+zga9f+bCjlQJPkPUmMgDSD7w=
|
||||
github.com/aws/smithy-go v1.22.4 h1:uqXzVZNuNexwc/xrh6Tb56u89WDlJY6HS+KC0S4QSjw=
|
||||
github.com/aws/smithy-go v1.22.4/go.mod h1:t1ufH5HMublsJYulve2RKmHDC15xu1f26kHCp/HgceI=
|
||||
github.com/bmatcuk/doublestar/v4 v4.6.1 h1:FH9SifrbvJhnlQpztAx++wlkk70QBf0iBWDwNy7PA4I=
|
||||
github.com/bmatcuk/doublestar/v4 v4.6.1/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc=
|
||||
github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs=
|
||||
@ -67,6 +95,10 @@ github.com/grokify/html-strip-tags-go v0.1.0 h1:03UrQLjAny8xci+R+qjCce/MYnpNXCtg
|
||||
github.com/grokify/html-strip-tags-go v0.1.0/go.mod h1:ZdzgfHEzAfz9X6Xe5eBLVblWIxXfYSQ40S/VKrAOGpc=
|
||||
github.com/hailaz/gf-casbin-adapter/v2 v2.8.1 h1:ZFIlfQAYmrL2Fe6/dZz6vCA5hYK0NxhnoKMQpbklgqc=
|
||||
github.com/hailaz/gf-casbin-adapter/v2 v2.8.1/go.mod h1:Jk91dRBZuMVjBMu2oQmqMRc6xuL5V+rzgHeFWvI+wlg=
|
||||
github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg=
|
||||
github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
|
||||
github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8=
|
||||
github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
|
||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
@ -132,8 +164,6 @@ golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
|
||||
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
|
||||
golang.org/x/time v0.12.0 h1:ScB/8o8olJvc+CQPWrK3fPZNfh7qgwCrY0zJmoEQLSE=
|
||||
golang.org/x/time v0.12.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
@ -141,6 +171,8 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
|
||||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
|
||||
@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"server/internal/controller/admin"
|
||||
"server/internal/controller/auth"
|
||||
"server/internal/controller/author"
|
||||
"server/internal/controller/book"
|
||||
"server/internal/controller/category"
|
||||
"server/internal/controller/chapter"
|
||||
@ -35,6 +36,7 @@ var (
|
||||
group.Middleware(middleware.Casbin)
|
||||
group.Bind(
|
||||
admin.NewV1(),
|
||||
author.NewV1(),
|
||||
book.NewV1(),
|
||||
category.NewV1(),
|
||||
chapter.NewV1(),
|
||||
|
||||
@ -1,17 +0,0 @@
|
||||
package admin
|
||||
|
||||
import (
|
||||
"context"
|
||||
"server/internal/model"
|
||||
"server/internal/service"
|
||||
|
||||
"server/api/admin/v1"
|
||||
)
|
||||
|
||||
func (c *ControllerV1) AdminEditPass(ctx context.Context, req *v1.AdminEditPassReq) (res *v1.AdminEditPassRes, err error) {
|
||||
out, err := service.Admin().EditPass(ctx, &model.AdminEditPassIn{NewPass: req.NewPass, OldPass: req.OldPass})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &v1.AdminEditPassRes{Success: out.Success}, nil
|
||||
}
|
||||
14
internal/controller/admin/admin_v1_edit_pass.go
Normal file
14
internal/controller/admin/admin_v1_edit_pass.go
Normal file
@ -0,0 +1,14 @@
|
||||
package admin
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/gogf/gf/v2/errors/gcode"
|
||||
"github.com/gogf/gf/v2/errors/gerror"
|
||||
|
||||
"server/api/admin/v1"
|
||||
)
|
||||
|
||||
func (c *ControllerV1) EditPass(ctx context.Context, req *v1.EditPassReq) (res *v1.EditPassRes, err error) {
|
||||
return nil, gerror.NewCode(gcode.CodeNotImplemented)
|
||||
}
|
||||
@ -9,13 +9,14 @@ import (
|
||||
"server/api/admin/v1"
|
||||
)
|
||||
|
||||
func (c *ControllerV1) AdminInfo(ctx context.Context, req *v1.AdminInfoReq) (res *v1.AdminInfoRes, err error) {
|
||||
func (c *ControllerV1) Info(ctx context.Context, req *v1.InfoReq) (res *v1.InfoRes, err error) {
|
||||
adminId := g.RequestFromCtx(ctx).GetCtxVar("id").Int64()
|
||||
out, err := service.Admin().Info(ctx, &model.AdminInfoIn{AdminId: adminId})
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &v1.AdminInfoRes{
|
||||
return &v1.InfoRes{
|
||||
AdminId: out.AdminId,
|
||||
Username: out.Username,
|
||||
}, nil
|
||||
5
internal/controller/author/author.go
Normal file
5
internal/controller/author/author.go
Normal file
@ -0,0 +1,5 @@
|
||||
// =================================================================================
|
||||
// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish.
|
||||
// =================================================================================
|
||||
|
||||
package author
|
||||
15
internal/controller/author/author_new.go
Normal file
15
internal/controller/author/author_new.go
Normal file
@ -0,0 +1,15 @@
|
||||
// =================================================================================
|
||||
// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish.
|
||||
// =================================================================================
|
||||
|
||||
package author
|
||||
|
||||
import (
|
||||
"server/api/author"
|
||||
)
|
||||
|
||||
type ControllerV1 struct{}
|
||||
|
||||
func NewV1() author.IAuthorV1 {
|
||||
return &ControllerV1{}
|
||||
}
|
||||
24
internal/controller/author/author_v1_add.go
Normal file
24
internal/controller/author/author_v1_add.go
Normal file
@ -0,0 +1,24 @@
|
||||
package author
|
||||
|
||||
import (
|
||||
"context"
|
||||
v1 "server/api/author/v1"
|
||||
"server/internal/model"
|
||||
"server/internal/service"
|
||||
)
|
||||
|
||||
func (c *ControllerV1) Add(ctx context.Context, req *v1.AddReq) (res *v1.AddRes, err error) {
|
||||
out, err := service.Author().Create(ctx, &model.AuthorAddIn{
|
||||
UserId: req.UserId,
|
||||
PenName: req.PenName,
|
||||
Bio: req.Bio,
|
||||
Status: req.Status,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &v1.AddRes{
|
||||
Success: out.Success,
|
||||
}, nil
|
||||
}
|
||||
21
internal/controller/author/author_v1_del.go
Normal file
21
internal/controller/author/author_v1_del.go
Normal file
@ -0,0 +1,21 @@
|
||||
package author
|
||||
|
||||
import (
|
||||
"context"
|
||||
v1 "server/api/author/v1"
|
||||
"server/internal/model"
|
||||
"server/internal/service"
|
||||
)
|
||||
|
||||
func (c *ControllerV1) Del(ctx context.Context, req *v1.DelReq) (res *v1.DelRes, err error) {
|
||||
out, err := service.Author().Delete(ctx, &model.AuthorDelIn{
|
||||
Id: req.Id,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &v1.DelRes{
|
||||
Success: out.Success,
|
||||
}, nil
|
||||
}
|
||||
17
internal/controller/author/author_v1_detail.go
Normal file
17
internal/controller/author/author_v1_detail.go
Normal file
@ -0,0 +1,17 @@
|
||||
package author
|
||||
|
||||
import (
|
||||
"context"
|
||||
"server/internal/model"
|
||||
"server/internal/service"
|
||||
|
||||
"server/api/author/v1"
|
||||
)
|
||||
|
||||
func (c *ControllerV1) Detail(ctx context.Context, req *v1.DetailReq) (res *v1.DetailRes, err error) {
|
||||
out, err := service.Author().Detail(ctx, &model.AuthorDetailIn{AuthorId: req.AuthorId})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &v1.DetailRes{Author: out}, nil
|
||||
}
|
||||
24
internal/controller/author/author_v1_edit.go
Normal file
24
internal/controller/author/author_v1_edit.go
Normal file
@ -0,0 +1,24 @@
|
||||
package author
|
||||
|
||||
import (
|
||||
"context"
|
||||
v1 "server/api/author/v1"
|
||||
"server/internal/model"
|
||||
"server/internal/service"
|
||||
)
|
||||
|
||||
func (c *ControllerV1) Edit(ctx context.Context, req *v1.EditReq) (res *v1.EditRes, err error) {
|
||||
out, err := service.Author().Update(ctx, &model.AuthorEditIn{
|
||||
Id: req.Id,
|
||||
PenName: req.PenName,
|
||||
Bio: req.Bio,
|
||||
Status: req.Status,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &v1.EditRes{
|
||||
Success: out.Success,
|
||||
}, nil
|
||||
}
|
||||
31
internal/controller/author/author_v1_follow.go
Normal file
31
internal/controller/author/author_v1_follow.go
Normal file
@ -0,0 +1,31 @@
|
||||
package author
|
||||
|
||||
import (
|
||||
"context"
|
||||
v1 "server/api/author/v1"
|
||||
"server/internal/model"
|
||||
"server/internal/service"
|
||||
"server/utility/ecode"
|
||||
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
)
|
||||
|
||||
func (c *ControllerV1) Follow(ctx context.Context, req *v1.FollowReq) (res *v1.FollowRes, err error) {
|
||||
// 从 ctx 获取用户ID
|
||||
userId := g.RequestFromCtx(ctx).GetCtxVar("id").Int64()
|
||||
if userId == 0 {
|
||||
return nil, ecode.Logout
|
||||
}
|
||||
|
||||
out, err := service.UserFollowAuthor().Create(ctx, &model.UserFollowAuthorAddIn{
|
||||
UserId: userId,
|
||||
AuthorId: req.AuthorId,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &v1.FollowRes{
|
||||
Success: out.Success,
|
||||
}, nil
|
||||
}
|
||||
25
internal/controller/author/author_v1_list.go
Normal file
25
internal/controller/author/author_v1_list.go
Normal file
@ -0,0 +1,25 @@
|
||||
package author
|
||||
|
||||
import (
|
||||
"context"
|
||||
v1 "server/api/author/v1"
|
||||
"server/internal/model"
|
||||
"server/internal/service"
|
||||
)
|
||||
|
||||
func (c *ControllerV1) List(ctx context.Context, req *v1.ListReq) (res *v1.ListRes, err error) {
|
||||
out, err := service.Author().List(ctx, &model.AuthorListIn{
|
||||
Page: req.Page,
|
||||
Size: req.Size,
|
||||
PenName: req.PenName,
|
||||
Status: req.Status,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &v1.ListRes{
|
||||
Total: out.Total,
|
||||
List: out.List,
|
||||
}, nil
|
||||
}
|
||||
27
internal/controller/author/author_v1_unfollow.go
Normal file
27
internal/controller/author/author_v1_unfollow.go
Normal file
@ -0,0 +1,27 @@
|
||||
package author
|
||||
|
||||
import (
|
||||
"context"
|
||||
v1 "server/api/author/v1"
|
||||
"server/internal/service"
|
||||
"server/utility/ecode"
|
||||
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
)
|
||||
|
||||
func (c *ControllerV1) Unfollow(ctx context.Context, req *v1.UnfollowReq) (res *v1.UnfollowRes, err error) {
|
||||
// 从 ctx 获取用户ID
|
||||
userId := g.RequestFromCtx(ctx).GetCtxVar("id").Int64()
|
||||
if userId == 0 {
|
||||
return nil, ecode.Logout
|
||||
}
|
||||
|
||||
out, err := service.UserFollowAuthor().Unfollow(ctx, userId, req.AuthorId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &v1.UnfollowRes{
|
||||
Success: out.Success,
|
||||
}, nil
|
||||
}
|
||||
@ -2,25 +2,27 @@ package book
|
||||
|
||||
import (
|
||||
"context"
|
||||
v1 "server/api/book/v1"
|
||||
"server/internal/model"
|
||||
"server/internal/service"
|
||||
|
||||
"server/api/book/v1"
|
||||
)
|
||||
|
||||
func (c *ControllerV1) BookAdd(ctx context.Context, req *v1.BookAddReq) (res *v1.BookAddRes, err error) {
|
||||
func (c *ControllerV1) Add(ctx context.Context, req *v1.AddReq) (res *v1.AddRes, err error) {
|
||||
out, err := service.Book().Create(ctx, &model.BookAddIn{
|
||||
AuthorId: req.AuthorId,
|
||||
CategoryId: req.CategoryId,
|
||||
Title: req.Title,
|
||||
CoverUrl: req.CoverUrl,
|
||||
Description: req.Description,
|
||||
IsRecommended: req.IsRecommended,
|
||||
Status: req.Status,
|
||||
Tags: req.Tags,
|
||||
Title: req.Title,
|
||||
IsRecommended: req.IsRecommended,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &v1.BookAddRes{Success: out.Success}, nil
|
||||
|
||||
return &v1.AddRes{
|
||||
Success: out.Success,
|
||||
}, nil
|
||||
}
|
||||
44
internal/controller/book/book_v1_app_detail.go
Normal file
44
internal/controller/book/book_v1_app_detail.go
Normal file
@ -0,0 +1,44 @@
|
||||
package book
|
||||
|
||||
import (
|
||||
"context"
|
||||
v1 "server/api/book/v1"
|
||||
"server/internal/model"
|
||||
"server/internal/service"
|
||||
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
)
|
||||
|
||||
func (c *ControllerV1) AppDetail(ctx context.Context, req *v1.AppDetailReq) (res *v1.AppDetailRes, err error) {
|
||||
// 从 ctx 获取用户ID
|
||||
userId := g.RequestFromCtx(ctx).GetCtxVar("id").Int64()
|
||||
|
||||
out, err := service.Book().AppDetail(ctx, &model.BookAppDetailIn{
|
||||
Id: req.Id,
|
||||
UserId: userId,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &v1.AppDetailRes{
|
||||
Id: out.Id,
|
||||
AuthorId: out.AuthorId,
|
||||
CategoryId: out.CategoryId,
|
||||
Title: out.Title,
|
||||
CoverUrl: out.CoverUrl,
|
||||
Description: out.Description,
|
||||
Status: out.Status,
|
||||
Tags: out.Tags,
|
||||
IsRecommended: out.IsRecommended,
|
||||
Rating: out.Rating,
|
||||
CurrentReaders: out.CurrentReaders,
|
||||
CreatedAt: out.CreatedAt.String(),
|
||||
UpdatedAt: out.UpdatedAt.String(),
|
||||
// 添加阅读进度信息
|
||||
HasRead: out.HasRead,
|
||||
ReadProgress: out.ReadProgress,
|
||||
LastChapterId: out.LastChapterId,
|
||||
LastReadAt: out.LastReadAt,
|
||||
}, nil
|
||||
}
|
||||
35
internal/controller/book/book_v1_app_list.go
Normal file
35
internal/controller/book/book_v1_app_list.go
Normal file
@ -0,0 +1,35 @@
|
||||
package book
|
||||
|
||||
import (
|
||||
"context"
|
||||
v1 "server/api/book/v1"
|
||||
"server/internal/model"
|
||||
"server/internal/service"
|
||||
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
)
|
||||
|
||||
func (c *ControllerV1) AppList(ctx context.Context, req *v1.AppListReq) (res *v1.AppListRes, err error) {
|
||||
userId := g.RequestFromCtx(ctx).GetCtxVar("id").Int64()
|
||||
out, err := service.Book().AppList(ctx, &model.BookAppListIn{
|
||||
Page: req.Page,
|
||||
Size: req.Size,
|
||||
IsRecommended: req.IsRecommended,
|
||||
IsFeatured: req.IsFeatured,
|
||||
IsLatest: req.IsLatest,
|
||||
CategoryId: req.CategoryId,
|
||||
Title: req.Title,
|
||||
AuthorId: req.AuthorId,
|
||||
UserId: userId,
|
||||
Language: req.Language,
|
||||
Sort: req.Sort,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &v1.AppListRes{
|
||||
Total: out.Total,
|
||||
List: out.List,
|
||||
}, nil
|
||||
}
|
||||
26
internal/controller/book/book_v1_app_rate.go
Normal file
26
internal/controller/book/book_v1_app_rate.go
Normal file
@ -0,0 +1,26 @@
|
||||
package book
|
||||
|
||||
import (
|
||||
"context"
|
||||
v1 "server/api/book/v1"
|
||||
"server/internal/model"
|
||||
"server/internal/service"
|
||||
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
)
|
||||
|
||||
func (c *ControllerV1) AppRate(ctx context.Context, req *v1.AppRateReq) (res *v1.AppRateRes, err error) {
|
||||
userId := g.RequestFromCtx(ctx).GetCtxVar("id").Int64()
|
||||
out, err := service.Book().AppRate(ctx, &model.BookAppRateIn{
|
||||
BookId: req.BookId,
|
||||
Rating: req.Rating,
|
||||
UserId: userId,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &v1.AppRateRes{
|
||||
Success: out.Success,
|
||||
}, nil
|
||||
}
|
||||
14
internal/controller/book/book_v1_book_set_featured.go
Normal file
14
internal/controller/book/book_v1_book_set_featured.go
Normal file
@ -0,0 +1,14 @@
|
||||
package book
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/gogf/gf/v2/errors/gcode"
|
||||
"github.com/gogf/gf/v2/errors/gerror"
|
||||
|
||||
"server/api/book/v1"
|
||||
)
|
||||
|
||||
func (c *ControllerV1) BookSetFeatured(ctx context.Context, req *v1.BookSetFeaturedReq) (res *v1.BookSetFeaturedRes, err error) {
|
||||
return nil, gerror.NewCode(gcode.CodeNotImplemented)
|
||||
}
|
||||
14
internal/controller/book/book_v1_book_set_recommended.go
Normal file
14
internal/controller/book/book_v1_book_set_recommended.go
Normal file
@ -0,0 +1,14 @@
|
||||
package book
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/gogf/gf/v2/errors/gcode"
|
||||
"github.com/gogf/gf/v2/errors/gerror"
|
||||
|
||||
"server/api/book/v1"
|
||||
)
|
||||
|
||||
func (c *ControllerV1) BookSetRecommended(ctx context.Context, req *v1.BookSetRecommendedReq) (res *v1.BookSetRecommendedRes, err error) {
|
||||
return nil, gerror.NewCode(gcode.CodeNotImplemented)
|
||||
}
|
||||
@ -2,18 +2,20 @@ package book
|
||||
|
||||
import (
|
||||
"context"
|
||||
v1 "server/api/book/v1"
|
||||
"server/internal/model"
|
||||
"server/internal/service"
|
||||
|
||||
"server/api/book/v1"
|
||||
)
|
||||
|
||||
func (c *ControllerV1) BookDel(ctx context.Context, req *v1.BookDelReq) (res *v1.BookDelRes, err error) {
|
||||
func (c *ControllerV1) Del(ctx context.Context, req *v1.DelReq) (res *v1.DelRes, err error) {
|
||||
out, err := service.Book().Delete(ctx, &model.BookDelIn{
|
||||
Id: req.Id,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &v1.BookDelRes{Success: out.Success}, nil
|
||||
|
||||
return &v1.DelRes{
|
||||
Success: out.Success,
|
||||
}, nil
|
||||
}
|
||||
@ -2,26 +2,28 @@ package book
|
||||
|
||||
import (
|
||||
"context"
|
||||
v1 "server/api/book/v1"
|
||||
"server/internal/model"
|
||||
"server/internal/service"
|
||||
|
||||
"server/api/book/v1"
|
||||
)
|
||||
|
||||
func (c *ControllerV1) BookEdit(ctx context.Context, req *v1.BookEditReq) (res *v1.BookEditRes, err error) {
|
||||
func (c *ControllerV1) Edit(ctx context.Context, req *v1.EditReq) (res *v1.EditRes, err error) {
|
||||
out, err := service.Book().Update(ctx, &model.BookEditIn{
|
||||
Id: req.Id,
|
||||
AuthorId: req.AuthorId,
|
||||
CategoryId: req.CategoryId,
|
||||
Title: req.Title,
|
||||
CoverUrl: req.CoverUrl,
|
||||
Description: req.Description,
|
||||
Id: req.Id,
|
||||
IsRecommended: req.IsRecommended,
|
||||
Status: req.Status,
|
||||
Tags: req.Tags,
|
||||
Title: req.Title,
|
||||
IsRecommended: req.IsRecommended,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &v1.BookEditRes{Success: out.Success}, nil
|
||||
|
||||
return &v1.EditRes{
|
||||
Success: out.Success,
|
||||
}, nil
|
||||
}
|
||||
@ -2,27 +2,28 @@ package book
|
||||
|
||||
import (
|
||||
"context"
|
||||
v1 "server/api/book/v1"
|
||||
"server/internal/model"
|
||||
"server/internal/service"
|
||||
|
||||
"server/api/book/v1"
|
||||
)
|
||||
|
||||
func (c *ControllerV1) BookList(ctx context.Context, req *v1.BookListReq) (res *v1.BookListRes, err error) {
|
||||
func (c *ControllerV1) List(ctx context.Context, req *v1.ListReq) (res *v1.ListRes, err error) {
|
||||
out, err := service.Book().List(ctx, &model.BookListIn{
|
||||
AuthorId: req.AuthorId,
|
||||
CategoryId: req.CategoryId,
|
||||
IsRecommended: req.IsRecommended,
|
||||
Page: req.Page,
|
||||
Size: req.Size,
|
||||
Status: req.Status,
|
||||
Title: req.Title,
|
||||
CategoryId: req.CategoryId,
|
||||
AuthorId: req.AuthorId,
|
||||
Status: req.Status,
|
||||
IsRecommended: req.IsRecommended,
|
||||
Sort: req.Sort,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &v1.BookListRes{
|
||||
List: out.List,
|
||||
|
||||
return &v1.ListRes{
|
||||
Total: out.Total,
|
||||
List: out.List,
|
||||
}, nil
|
||||
}
|
||||
32
internal/controller/book/book_v1_my_list.go
Normal file
32
internal/controller/book/book_v1_my_list.go
Normal file
@ -0,0 +1,32 @@
|
||||
package book
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
v1 "server/api/book/v1"
|
||||
"server/internal/model"
|
||||
"server/internal/service"
|
||||
|
||||
"github.com/gogf/gf/v2/net/ghttp"
|
||||
)
|
||||
|
||||
func (c *ControllerV1) MyList(ctx context.Context, req *v1.MyListReq) (res *v1.MyListRes, err error) {
|
||||
// 从ctx获取userId
|
||||
userId := ghttp.RequestFromCtx(ctx).GetCtxVar("id").Int64()
|
||||
in := &model.MyBookListIn{
|
||||
Type: req.Type,
|
||||
Page: req.Page,
|
||||
Size: req.Size,
|
||||
UserId: userId,
|
||||
Sort: req.Sort,
|
||||
}
|
||||
result, err := service.Book().MyList(ctx, in)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res = &v1.MyListRes{
|
||||
Total: result.Total,
|
||||
List: result.List,
|
||||
}
|
||||
return
|
||||
}
|
||||
31
internal/controller/book/book_v1_shelf_add.go
Normal file
31
internal/controller/book/book_v1_shelf_add.go
Normal file
@ -0,0 +1,31 @@
|
||||
package book
|
||||
|
||||
import (
|
||||
"context"
|
||||
v1 "server/api/book/v1"
|
||||
"server/internal/model"
|
||||
"server/internal/service"
|
||||
"server/utility/ecode"
|
||||
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
)
|
||||
|
||||
func (c *ControllerV1) ShelfAdd(ctx context.Context, req *v1.ShelfAddReq) (res *v1.ShelfAddRes, err error) {
|
||||
// 从 ctx 获取用户ID
|
||||
userId := g.RequestFromCtx(ctx).GetCtxVar("id").Int64()
|
||||
if userId == 0 {
|
||||
return nil, ecode.Logout
|
||||
}
|
||||
|
||||
out, err := service.Bookshelve().Add(ctx, &model.BookshelveAddIn{
|
||||
UserId: userId,
|
||||
BookId: req.BookId,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &v1.ShelfAddRes{
|
||||
Success: out.Success,
|
||||
}, nil
|
||||
}
|
||||
31
internal/controller/book/book_v1_shelf_remove.go
Normal file
31
internal/controller/book/book_v1_shelf_remove.go
Normal file
@ -0,0 +1,31 @@
|
||||
package book
|
||||
|
||||
import (
|
||||
"context"
|
||||
v1 "server/api/book/v1"
|
||||
"server/internal/model"
|
||||
"server/internal/service"
|
||||
"server/utility/ecode"
|
||||
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
)
|
||||
|
||||
func (c *ControllerV1) ShelfRemove(ctx context.Context, req *v1.ShelfRemoveReq) (res *v1.ShelfRemoveRes, err error) {
|
||||
// 从 ctx 获取用户ID
|
||||
userId := g.RequestFromCtx(ctx).GetCtxVar("id").Int64()
|
||||
if userId == 0 {
|
||||
return nil, ecode.Logout
|
||||
}
|
||||
|
||||
out, err := service.Bookshelve().Delete(ctx, &model.BookshelveDelIn{
|
||||
UserId: userId,
|
||||
BookIds: req.BookIds,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &v1.ShelfRemoveRes{
|
||||
Success: out.Success,
|
||||
}, nil
|
||||
}
|
||||
@ -5,18 +5,18 @@ import (
|
||||
"server/internal/model"
|
||||
"server/internal/service"
|
||||
|
||||
"server/api/category/v1"
|
||||
v1 "server/api/category/v1"
|
||||
)
|
||||
|
||||
func (c *ControllerV1) CategoryAdd(ctx context.Context, req *v1.CategoryAddReq) (res *v1.CategoryAddRes, err error) {
|
||||
func (c *ControllerV1) Add(ctx context.Context, req *v1.AddReq) (res *v1.AddRes, err error) {
|
||||
out, err := service.Category().Create(ctx, &model.CategoryAddIn{
|
||||
Name: req.Name,
|
||||
Type: req.Type,
|
||||
Name: req.Name,
|
||||
Channel: req.Channel,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &v1.CategoryAddRes{
|
||||
return &v1.AddRes{
|
||||
Success: out.Success,
|
||||
}, nil
|
||||
}
|
||||
@ -1,25 +0,0 @@
|
||||
package category
|
||||
|
||||
import (
|
||||
"context"
|
||||
"server/internal/model"
|
||||
"server/internal/service"
|
||||
|
||||
"server/api/category/v1"
|
||||
)
|
||||
|
||||
func (c *ControllerV1) CategoryList(ctx context.Context, req *v1.CategoryListReq) (res *v1.CategoryListRes, err error) {
|
||||
out, err := service.Category().List(ctx, &model.CategoryListIn{
|
||||
Name: req.Name,
|
||||
Page: req.Page,
|
||||
Size: req.Size,
|
||||
Type: req.Type,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &v1.CategoryListRes{
|
||||
List: out.List,
|
||||
Total: out.Total,
|
||||
}, nil
|
||||
}
|
||||
@ -8,14 +8,14 @@ import (
|
||||
"server/api/category/v1"
|
||||
)
|
||||
|
||||
func (c *ControllerV1) CategoryDel(ctx context.Context, req *v1.CategoryDelReq) (res *v1.CategoryDelRes, err error) {
|
||||
func (c *ControllerV1) Del(ctx context.Context, req *v1.DelReq) (res *v1.DelRes, err error) {
|
||||
out, err := service.Category().Delete(ctx, &model.CategoryDelIn{
|
||||
Id: req.Id,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &v1.CategoryDelRes{
|
||||
return &v1.DelRes{
|
||||
Success: out.Success,
|
||||
}, nil
|
||||
}
|
||||
@ -5,19 +5,19 @@ import (
|
||||
"server/internal/model"
|
||||
"server/internal/service"
|
||||
|
||||
"server/api/category/v1"
|
||||
v1 "server/api/category/v1"
|
||||
)
|
||||
|
||||
func (c *ControllerV1) CategoryEdit(ctx context.Context, req *v1.CategoryEditReq) (res *v1.CategoryEditRes, err error) {
|
||||
func (c *ControllerV1) Edit(ctx context.Context, req *v1.EditReq) (res *v1.EditRes, err error) {
|
||||
out, err := service.Category().Update(ctx, &model.CategoryEditIn{
|
||||
Id: req.Id,
|
||||
Name: req.Name,
|
||||
Type: req.Type,
|
||||
Id: req.Id,
|
||||
Name: req.Name,
|
||||
Channel: req.Channel,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &v1.CategoryEditRes{
|
||||
return &v1.EditRes{
|
||||
Success: out.Success,
|
||||
}, nil
|
||||
}
|
||||
30
internal/controller/category/category_v1_list.go
Normal file
30
internal/controller/category/category_v1_list.go
Normal file
@ -0,0 +1,30 @@
|
||||
package category
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
v1 "server/api/category/v1"
|
||||
"server/internal/model"
|
||||
"server/internal/service"
|
||||
)
|
||||
|
||||
func (c *ControllerV1) List(ctx context.Context, req *v1.ListReq) (res *v1.ListRes, err error) {
|
||||
// 调用service层获取分类列表
|
||||
result, err := service.Category().List(ctx, &model.CategoryListIn{
|
||||
Page: req.Page,
|
||||
Size: req.Size,
|
||||
Name: req.Name,
|
||||
Channel: req.Channel,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 构造响应
|
||||
res = &v1.ListRes{
|
||||
Total: result.Total,
|
||||
List: result.List,
|
||||
}
|
||||
|
||||
return res, nil
|
||||
}
|
||||
@ -8,7 +8,7 @@ import (
|
||||
"server/api/chapter/v1"
|
||||
)
|
||||
|
||||
func (c *ControllerV1) ChapterAdd(ctx context.Context, req *v1.ChapterAddReq) (res *v1.ChapterAddRes, err error) {
|
||||
func (c *ControllerV1) Add(ctx context.Context, req *v1.AddReq) (res *v1.AddRes, err error) {
|
||||
out, err := service.Chapter().Create(ctx, &model.ChapterAddIn{
|
||||
BookId: req.BookId,
|
||||
Content: req.Content,
|
||||
@ -21,7 +21,7 @@ func (c *ControllerV1) ChapterAdd(ctx context.Context, req *v1.ChapterAddReq) (r
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &v1.ChapterAddRes{
|
||||
return &v1.AddRes{
|
||||
Success: out.Success,
|
||||
}, nil
|
||||
}
|
||||
29
internal/controller/chapter/chapter_v1_app_detail.go
Normal file
29
internal/controller/chapter/chapter_v1_app_detail.go
Normal file
@ -0,0 +1,29 @@
|
||||
package chapter
|
||||
|
||||
import (
|
||||
"context"
|
||||
v1 "server/api/chapter/v1"
|
||||
"server/internal/model"
|
||||
"server/internal/service"
|
||||
)
|
||||
|
||||
func (c *ControllerV1) AppDetail(ctx context.Context, req *v1.AppDetailReq) (res *v1.AppDetailRes, err error) {
|
||||
out, err := service.Chapter().AppDetail(ctx, &model.ChapterAppDetailIn{
|
||||
Id: req.Id,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &v1.AppDetailRes{
|
||||
Id: out.Id,
|
||||
BookId: out.BookId,
|
||||
Title: out.Title,
|
||||
Content: out.Content,
|
||||
WordCount: out.WordCount,
|
||||
Sort: out.Sort,
|
||||
IsLocked: out.IsLocked,
|
||||
RequiredScore: out.RequiredScore,
|
||||
UpdatedAt: out.UpdatedAt.String(),
|
||||
}, nil
|
||||
}
|
||||
29
internal/controller/chapter/chapter_v1_app_list.go
Normal file
29
internal/controller/chapter/chapter_v1_app_list.go
Normal file
@ -0,0 +1,29 @@
|
||||
package chapter
|
||||
|
||||
import (
|
||||
"context"
|
||||
v1 "server/api/chapter/v1"
|
||||
"server/internal/model"
|
||||
"server/internal/service"
|
||||
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
)
|
||||
|
||||
func (c *ControllerV1) AppList(ctx context.Context, req *v1.AppListReq) (res *v1.AppListRes, err error) {
|
||||
userId := g.RequestFromCtx(ctx).GetCtxVar("id").Int64()
|
||||
out, err := service.Chapter().AppList(ctx, &model.ChapterAppListIn{
|
||||
BookId: req.BookId,
|
||||
IsDesc: req.IsDesc,
|
||||
Page: req.Page,
|
||||
Size: req.Size,
|
||||
UserId: userId,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &v1.AppListRes{
|
||||
Total: out.Total,
|
||||
List: out.List,
|
||||
}, nil
|
||||
}
|
||||
27
internal/controller/chapter/chapter_v1_app_progress.go
Normal file
27
internal/controller/chapter/chapter_v1_app_progress.go
Normal file
@ -0,0 +1,27 @@
|
||||
package chapter
|
||||
|
||||
import (
|
||||
"context"
|
||||
v1 "server/api/chapter/v1"
|
||||
"server/internal/model"
|
||||
"server/internal/service"
|
||||
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
)
|
||||
|
||||
func (c *ControllerV1) AppProgress(ctx context.Context, req *v1.AppProgressReq) (res *v1.AppProgressRes, err error) {
|
||||
userId := g.RequestFromCtx(ctx).GetCtxVar("id").Int64()
|
||||
out, err := service.Chapter().AppProgress(ctx, &model.ChapterAppProgressIn{
|
||||
BookId: req.BookId,
|
||||
ChapterId: req.ChapterId,
|
||||
Progress: req.Progress,
|
||||
UserId: userId,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &v1.AppProgressRes{
|
||||
Success: out.Success,
|
||||
}, nil
|
||||
}
|
||||
25
internal/controller/chapter/chapter_v1_app_purchase.go
Normal file
25
internal/controller/chapter/chapter_v1_app_purchase.go
Normal file
@ -0,0 +1,25 @@
|
||||
package chapter
|
||||
|
||||
import (
|
||||
"context"
|
||||
v1 "server/api/chapter/v1"
|
||||
"server/internal/model"
|
||||
"server/internal/service"
|
||||
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
)
|
||||
|
||||
func (c *ControllerV1) AppPurchase(ctx context.Context, req *v1.AppPurchaseReq) (res *v1.AppPurchaseRes, err error) {
|
||||
userId := g.RequestFromCtx(ctx).GetCtxVar("id").Int64()
|
||||
out, err := service.Chapter().AppPurchase(ctx, &model.ChapterAppPurchaseIn{
|
||||
Id: req.Id,
|
||||
UserId: userId,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &v1.AppPurchaseRes{
|
||||
Success: out.Success,
|
||||
}, nil
|
||||
}
|
||||
@ -8,12 +8,12 @@ import (
|
||||
"server/api/chapter/v1"
|
||||
)
|
||||
|
||||
func (c *ControllerV1) ChapterDel(ctx context.Context, req *v1.ChapterDelReq) (res *v1.ChapterDelRes, err error) {
|
||||
func (c *ControllerV1) Del(ctx context.Context, req *v1.DelReq) (res *v1.DelRes, err error) {
|
||||
out, err := service.Chapter().Delete(ctx, &model.ChapterDelIn{
|
||||
Id: req.Id,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &v1.ChapterDelRes{Success: out.Success}, nil
|
||||
return &v1.DelRes{Success: out.Success}, nil
|
||||
}
|
||||
@ -8,21 +8,21 @@ import (
|
||||
"server/api/chapter/v1"
|
||||
)
|
||||
|
||||
func (c *ControllerV1) ChapterEdit(ctx context.Context, req *v1.ChapterEditReq) (res *v1.ChapterEditRes, err error) {
|
||||
func (c *ControllerV1) Edit(ctx context.Context, req *v1.EditReq) (res *v1.EditRes, err error) {
|
||||
out, err := service.Chapter().Update(ctx, &model.ChapterEditIn{
|
||||
BookId: req.BookId,
|
||||
Content: req.Content,
|
||||
Id: req.Id,
|
||||
IsLocked: req.IsLocked,
|
||||
RequiredScore: req.RequiredScore,
|
||||
Sort: req.Sort,
|
||||
BookId: req.BookId,
|
||||
Title: req.Title,
|
||||
Sort: req.Sort,
|
||||
IsLocked: req.IsLocked,
|
||||
Content: req.Content,
|
||||
WordCount: req.WordCount,
|
||||
RequiredScore: req.RequiredScore,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &v1.ChapterEditRes{
|
||||
return &v1.EditRes{
|
||||
Success: out.Success,
|
||||
}, nil
|
||||
}
|
||||
@ -8,7 +8,7 @@ import (
|
||||
"server/api/chapter/v1"
|
||||
)
|
||||
|
||||
func (c *ControllerV1) ChapterList(ctx context.Context, req *v1.ChapterListReq) (res *v1.ChapterListRes, err error) {
|
||||
func (c *ControllerV1) List(ctx context.Context, req *v1.ListReq) (res *v1.ListRes, err error) {
|
||||
out, err := service.Chapter().List(ctx, &model.ChapterListIn{
|
||||
BookId: req.BookId,
|
||||
IsLocked: req.IsLocked,
|
||||
@ -19,7 +19,7 @@ func (c *ControllerV1) ChapterList(ctx context.Context, req *v1.ChapterListReq)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &v1.ChapterListRes{
|
||||
return &v1.ListRes{
|
||||
List: out.List,
|
||||
Total: out.Total,
|
||||
}, nil
|
||||
@ -9,7 +9,7 @@ import (
|
||||
"server/api/feedback/v1"
|
||||
)
|
||||
|
||||
func (c *ControllerV1) FeedbackAdd(ctx context.Context, req *v1.FeedbackAddReq) (res *v1.FeedbackAddRes, err error) {
|
||||
func (c *ControllerV1) Add(ctx context.Context, req *v1.AddReq) (res *v1.AddRes, err error) {
|
||||
userId := g.RequestFromCtx(ctx).GetCtxVar("id").Int64()
|
||||
out, err := service.Feedback().Create(ctx, &model.FeedbackAddIn{
|
||||
Content: req.Content,
|
||||
@ -18,7 +18,5 @@ func (c *ControllerV1) FeedbackAdd(ctx context.Context, req *v1.FeedbackAddReq)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &v1.FeedbackAddRes{
|
||||
Success: out.Success,
|
||||
}, nil
|
||||
return &v1.AddRes{Success: out.Success}, nil
|
||||
}
|
||||
@ -8,7 +8,7 @@ import (
|
||||
"server/api/feedback/v1"
|
||||
)
|
||||
|
||||
func (c *ControllerV1) FeedbackList(ctx context.Context, req *v1.FeedbackListReq) (res *v1.FeedbackListRes, err error) {
|
||||
func (c *ControllerV1) List(ctx context.Context, req *v1.ListReq) (res *v1.ListRes, err error) {
|
||||
out, err := service.Feedback().List(ctx, &model.FeedbackListIn{
|
||||
Page: req.Page,
|
||||
Size: req.Size,
|
||||
@ -18,8 +18,8 @@ func (c *ControllerV1) FeedbackList(ctx context.Context, req *v1.FeedbackListReq
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &v1.FeedbackListRes{
|
||||
List: out.List,
|
||||
return &v1.ListRes{
|
||||
Total: out.Total,
|
||||
List: out.List,
|
||||
}, nil
|
||||
}
|
||||
32
internal/controller/user/user_v1_info.go
Normal file
32
internal/controller/user/user_v1_info.go
Normal file
@ -0,0 +1,32 @@
|
||||
package user
|
||||
|
||||
import (
|
||||
"context"
|
||||
v1 "server/api/user/v1"
|
||||
"server/internal/model"
|
||||
"server/internal/service"
|
||||
"server/utility/ecode"
|
||||
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
)
|
||||
|
||||
func (c *ControllerV1) Info(ctx context.Context, req *v1.InfoReq) (res *v1.InfoRes, err error) {
|
||||
// 从ctx获取userId
|
||||
userId := g.RequestFromCtx(ctx).GetCtxVar("id").Int64()
|
||||
if userId == 0 {
|
||||
return nil, ecode.Logout
|
||||
}
|
||||
|
||||
out, err := service.User().Info(ctx, &model.UserInfoIn{UserId: userId})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &v1.InfoRes{
|
||||
UserId: out.UserId,
|
||||
Username: out.Username,
|
||||
Avatar: out.Avatar,
|
||||
Email: out.Email,
|
||||
Points: out.Points,
|
||||
}, nil
|
||||
}
|
||||
@ -1,24 +0,0 @@
|
||||
package user
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"server/internal/model"
|
||||
"server/internal/service"
|
||||
|
||||
"server/api/user/v1"
|
||||
)
|
||||
|
||||
func (c *ControllerV1) UserInfo(ctx context.Context, req *v1.UserInfoReq) (res *v1.UserInfoRes, err error) {
|
||||
userId := g.RequestFromCtx(ctx).GetCtxVar("id").Int64()
|
||||
info, err := service.User().Info(ctx, &model.UserInfoIn{UserId: userId})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &v1.UserInfoRes{
|
||||
Username: info.Username,
|
||||
Avatar: info.Avatar,
|
||||
Email: info.Email,
|
||||
Points: info.Points,
|
||||
}, nil
|
||||
}
|
||||
@ -20,44 +20,48 @@ type BooksDao struct {
|
||||
|
||||
// BooksColumns defines and stores column names for the table books.
|
||||
type BooksColumns struct {
|
||||
Id string // 小说ID
|
||||
AuthorId string // 作者ID
|
||||
CategoryId string // 分类ID
|
||||
Title string // 小说标题
|
||||
CoverUrl string // 封面图片URL
|
||||
Description string // 小说简介
|
||||
Status string // 状态:1=连载中,2=完结,3=下架
|
||||
WordsCount string // 字数
|
||||
ChaptersCount string // 章节数
|
||||
LatestChapterId string // 最新章节ID
|
||||
Rating string // 评分(0.00~10.00)
|
||||
ReadCount string // 阅读人数
|
||||
Tags string // 标签(逗号分隔)
|
||||
CreatedAt string // 创建时间
|
||||
UpdatedAt string // 更新时间
|
||||
DeletedAt string // 软删除时间戳
|
||||
IsRecommended string // 是否推荐:0=否,1=是
|
||||
Id string // 小说ID
|
||||
AuthorId string // 作者ID
|
||||
CategoryId string // 分类ID
|
||||
Title string // 小说标题
|
||||
CoverUrl string // 封面图片URL
|
||||
Description string // 小说简介
|
||||
Status string // 状态:1=连载中,2=完结,3=下架
|
||||
WordsCount string // 字数
|
||||
ChaptersCount string // 章节数
|
||||
Rating string // 评分(0.00~10.00)
|
||||
ReadCount string // 阅读人数
|
||||
CurrentReaders string // 在读人数
|
||||
Tags string // 标签(逗号分隔)
|
||||
CreatedAt string // 创建时间
|
||||
UpdatedAt string // 更新时间
|
||||
DeletedAt string // 软删除时间戳
|
||||
IsRecommended string // 是否推荐:0=否,1=是
|
||||
IsFeatured string // 是否精选:0=否,1=是
|
||||
Language string // 语言,如 zh=中文,en=英文,jp=日文
|
||||
}
|
||||
|
||||
// booksColumns holds the columns for the table books.
|
||||
var booksColumns = BooksColumns{
|
||||
Id: "id",
|
||||
AuthorId: "author_id",
|
||||
CategoryId: "category_id",
|
||||
Title: "title",
|
||||
CoverUrl: "cover_url",
|
||||
Description: "description",
|
||||
Status: "status",
|
||||
WordsCount: "words_count",
|
||||
ChaptersCount: "chapters_count",
|
||||
LatestChapterId: "latest_chapter_id",
|
||||
Rating: "rating",
|
||||
ReadCount: "read_count",
|
||||
Tags: "tags",
|
||||
CreatedAt: "created_at",
|
||||
UpdatedAt: "updated_at",
|
||||
DeletedAt: "deleted_at",
|
||||
IsRecommended: "is_recommended",
|
||||
Id: "id",
|
||||
AuthorId: "author_id",
|
||||
CategoryId: "category_id",
|
||||
Title: "title",
|
||||
CoverUrl: "cover_url",
|
||||
Description: "description",
|
||||
Status: "status",
|
||||
WordsCount: "words_count",
|
||||
ChaptersCount: "chapters_count",
|
||||
Rating: "rating",
|
||||
ReadCount: "read_count",
|
||||
CurrentReaders: "current_readers",
|
||||
Tags: "tags",
|
||||
CreatedAt: "created_at",
|
||||
UpdatedAt: "updated_at",
|
||||
DeletedAt: "deleted_at",
|
||||
IsRecommended: "is_recommended",
|
||||
IsFeatured: "is_featured",
|
||||
Language: "language",
|
||||
}
|
||||
|
||||
// NewBooksDao creates and returns a new DAO object for table data access.
|
||||
|
||||
@ -27,6 +27,7 @@ type BookshelvesColumns struct {
|
||||
LastReadChapterId string // 最后阅读章节ID
|
||||
LastReadPercent string // 阅读进度百分比(0.00~100.00)
|
||||
LastReadAt string // 最后阅读时间
|
||||
ReadStatus string // 阅读状态:1=正在读,2=已读完,3=已收藏
|
||||
}
|
||||
|
||||
// bookshelvesColumns holds the columns for the table bookshelves.
|
||||
@ -38,6 +39,7 @@ var bookshelvesColumns = BookshelvesColumns{
|
||||
LastReadChapterId: "last_read_chapter_id",
|
||||
LastReadPercent: "last_read_percent",
|
||||
LastReadAt: "last_read_at",
|
||||
ReadStatus: "read_status",
|
||||
}
|
||||
|
||||
// NewBookshelvesDao creates and returns a new DAO object for table data access.
|
||||
|
||||
@ -22,20 +22,20 @@ type CategoriesDao struct {
|
||||
type CategoriesColumns struct {
|
||||
Id string // 分类ID
|
||||
Name string // 分类名称
|
||||
Type string // 分类类型:1=男频, 2=女频
|
||||
CreatedAt string // 创建时间
|
||||
UpdatedAt string // 更新时间
|
||||
DeletedAt string // 软删除时间戳
|
||||
Channel string // 频道类型:1=男频,2=女频
|
||||
}
|
||||
|
||||
// categoriesColumns holds the columns for the table categories.
|
||||
var categoriesColumns = CategoriesColumns{
|
||||
Id: "id",
|
||||
Name: "name",
|
||||
Type: "type",
|
||||
CreatedAt: "created_at",
|
||||
UpdatedAt: "updated_at",
|
||||
DeletedAt: "deleted_at",
|
||||
Channel: "channel",
|
||||
}
|
||||
|
||||
// NewCategoriesDao creates and returns a new DAO object for table data access.
|
||||
|
||||
@ -22,9 +22,9 @@ type UserPointsLogsDao struct {
|
||||
type UserPointsLogsColumns struct {
|
||||
Id string // 积分流水ID
|
||||
UserId string // 用户ID
|
||||
ChangeType string // 变动类型,例如 earn、spend、refund 等
|
||||
ChangeType string // 变动类型,1=消费(spend), 2=收入(earn)
|
||||
PointsChange string // 积分变化数,正数增加,负数减少
|
||||
RelatedOrderId string // 关联订单ID
|
||||
RelatedOrderId string // 关联ID:当change_type=1时,为chapter_purchases.id;当change_type=2时,为advertisement_records.id
|
||||
Description string // 变动说明
|
||||
CreatedAt string // 变动时间
|
||||
}
|
||||
|
||||
81
internal/dao/internal/user_read_history.go
Normal file
81
internal/dao/internal/user_read_history.go
Normal file
@ -0,0 +1,81 @@
|
||||
// ==========================================================================
|
||||
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
|
||||
// ==========================================================================
|
||||
|
||||
package internal
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/gogf/gf/v2/database/gdb"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
)
|
||||
|
||||
// UserReadHistoryDao is the data access object for the table user_read_history.
|
||||
type UserReadHistoryDao struct {
|
||||
table string // table is the underlying table name of the DAO.
|
||||
group string // group is the database configuration group name of the current DAO.
|
||||
columns UserReadHistoryColumns // columns contains all the column names of Table for convenient usage.
|
||||
}
|
||||
|
||||
// UserReadHistoryColumns defines and stores column names for the table user_read_history.
|
||||
type UserReadHistoryColumns struct {
|
||||
Id string // 历史记录ID
|
||||
UserId string // 用户ID
|
||||
BookId string // 小说ID
|
||||
ChapterId string // 最后阅读章节ID
|
||||
ReadAt string // 最后阅读时间
|
||||
}
|
||||
|
||||
// userReadHistoryColumns holds the columns for the table user_read_history.
|
||||
var userReadHistoryColumns = UserReadHistoryColumns{
|
||||
Id: "id",
|
||||
UserId: "user_id",
|
||||
BookId: "book_id",
|
||||
ChapterId: "chapter_id",
|
||||
ReadAt: "read_at",
|
||||
}
|
||||
|
||||
// NewUserReadHistoryDao creates and returns a new DAO object for table data access.
|
||||
func NewUserReadHistoryDao() *UserReadHistoryDao {
|
||||
return &UserReadHistoryDao{
|
||||
group: "default",
|
||||
table: "user_read_history",
|
||||
columns: userReadHistoryColumns,
|
||||
}
|
||||
}
|
||||
|
||||
// DB retrieves and returns the underlying raw database management object of the current DAO.
|
||||
func (dao *UserReadHistoryDao) DB() gdb.DB {
|
||||
return g.DB(dao.group)
|
||||
}
|
||||
|
||||
// Table returns the table name of the current DAO.
|
||||
func (dao *UserReadHistoryDao) Table() string {
|
||||
return dao.table
|
||||
}
|
||||
|
||||
// Columns returns all column names of the current DAO.
|
||||
func (dao *UserReadHistoryDao) Columns() UserReadHistoryColumns {
|
||||
return dao.columns
|
||||
}
|
||||
|
||||
// Group returns the database configuration group name of the current DAO.
|
||||
func (dao *UserReadHistoryDao) Group() string {
|
||||
return dao.group
|
||||
}
|
||||
|
||||
// Ctx creates and returns a Model for the current DAO. It automatically sets the context for the current operation.
|
||||
func (dao *UserReadHistoryDao) Ctx(ctx context.Context) *gdb.Model {
|
||||
return dao.DB().Model(dao.table).Safe().Ctx(ctx)
|
||||
}
|
||||
|
||||
// Transaction wraps the transaction logic using function f.
|
||||
// It rolls back the transaction and returns the error if function f returns a non-nil error.
|
||||
// It commits the transaction and returns nil if function f returns nil.
|
||||
//
|
||||
// Note: Do not commit or roll back the transaction in function f,
|
||||
// as it is automatically handled by this function.
|
||||
func (dao *UserReadHistoryDao) Transaction(ctx context.Context, f func(ctx context.Context, tx gdb.TX) error) (err error) {
|
||||
return dao.Ctx(ctx).Transaction(ctx, f)
|
||||
}
|
||||
@ -11,62 +11,68 @@ import (
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
)
|
||||
|
||||
// ReadRecordsDao is the data access object for the table read_records.
|
||||
type ReadRecordsDao struct {
|
||||
table string // table is the underlying table name of the DAO.
|
||||
group string // group is the database configuration group name of the current DAO.
|
||||
columns ReadRecordsColumns // columns contains all the column names of Table for convenient usage.
|
||||
// UserReadRecordsDao is the data access object for the table user_read_records.
|
||||
type UserReadRecordsDao struct {
|
||||
table string // table is the underlying table name of the DAO.
|
||||
group string // group is the database configuration group name of the current DAO.
|
||||
columns UserReadRecordsColumns // columns contains all the column names of Table for convenient usage.
|
||||
}
|
||||
|
||||
// ReadRecordsColumns defines and stores column names for the table read_records.
|
||||
type ReadRecordsColumns struct {
|
||||
// UserReadRecordsColumns defines and stores column names for the table user_read_records.
|
||||
type UserReadRecordsColumns struct {
|
||||
Id string // 记录ID
|
||||
UserId string // 用户ID
|
||||
BookId string // 小说ID
|
||||
ChapterId string // 章节ID
|
||||
Progress string // 阅读进度百分比(0-100)
|
||||
ReadAt string // 阅读时间
|
||||
CreatedAt string // 创建时间
|
||||
UpdatedAt string // 更新时间
|
||||
}
|
||||
|
||||
// readRecordsColumns holds the columns for the table read_records.
|
||||
var readRecordsColumns = ReadRecordsColumns{
|
||||
// userReadRecordsColumns holds the columns for the table user_read_records.
|
||||
var userReadRecordsColumns = UserReadRecordsColumns{
|
||||
Id: "id",
|
||||
UserId: "user_id",
|
||||
BookId: "book_id",
|
||||
ChapterId: "chapter_id",
|
||||
Progress: "progress",
|
||||
ReadAt: "read_at",
|
||||
CreatedAt: "created_at",
|
||||
UpdatedAt: "updated_at",
|
||||
}
|
||||
|
||||
// NewReadRecordsDao creates and returns a new DAO object for table data access.
|
||||
func NewReadRecordsDao() *ReadRecordsDao {
|
||||
return &ReadRecordsDao{
|
||||
// NewUserReadRecordsDao creates and returns a new DAO object for table data access.
|
||||
func NewUserReadRecordsDao() *UserReadRecordsDao {
|
||||
return &UserReadRecordsDao{
|
||||
group: "default",
|
||||
table: "read_records",
|
||||
columns: readRecordsColumns,
|
||||
table: "user_read_records",
|
||||
columns: userReadRecordsColumns,
|
||||
}
|
||||
}
|
||||
|
||||
// DB retrieves and returns the underlying raw database management object of the current DAO.
|
||||
func (dao *ReadRecordsDao) DB() gdb.DB {
|
||||
func (dao *UserReadRecordsDao) DB() gdb.DB {
|
||||
return g.DB(dao.group)
|
||||
}
|
||||
|
||||
// Table returns the table name of the current DAO.
|
||||
func (dao *ReadRecordsDao) Table() string {
|
||||
func (dao *UserReadRecordsDao) Table() string {
|
||||
return dao.table
|
||||
}
|
||||
|
||||
// Columns returns all column names of the current DAO.
|
||||
func (dao *ReadRecordsDao) Columns() ReadRecordsColumns {
|
||||
func (dao *UserReadRecordsDao) Columns() UserReadRecordsColumns {
|
||||
return dao.columns
|
||||
}
|
||||
|
||||
// Group returns the database configuration group name of the current DAO.
|
||||
func (dao *ReadRecordsDao) Group() string {
|
||||
func (dao *UserReadRecordsDao) Group() string {
|
||||
return dao.group
|
||||
}
|
||||
|
||||
// Ctx creates and returns a Model for the current DAO. It automatically sets the context for the current operation.
|
||||
func (dao *ReadRecordsDao) Ctx(ctx context.Context) *gdb.Model {
|
||||
func (dao *UserReadRecordsDao) Ctx(ctx context.Context) *gdb.Model {
|
||||
return dao.DB().Model(dao.table).Safe().Ctx(ctx)
|
||||
}
|
||||
|
||||
@ -76,6 +82,6 @@ func (dao *ReadRecordsDao) Ctx(ctx context.Context) *gdb.Model {
|
||||
//
|
||||
// Note: Do not commit or roll back the transaction in function f,
|
||||
// as it is automatically handled by this function.
|
||||
func (dao *ReadRecordsDao) Transaction(ctx context.Context, f func(ctx context.Context, tx gdb.TX) error) (err error) {
|
||||
func (dao *UserReadRecordsDao) Transaction(ctx context.Context, f func(ctx context.Context, tx gdb.TX) error) (err error) {
|
||||
return dao.Ctx(ctx).Transaction(ctx, f)
|
||||
}
|
||||
@ -1,27 +0,0 @@
|
||||
// =================================================================================
|
||||
// This file is auto-generated by the GoFrame CLI tool. You may modify it as needed.
|
||||
// =================================================================================
|
||||
|
||||
package dao
|
||||
|
||||
import (
|
||||
"server/internal/dao/internal"
|
||||
)
|
||||
|
||||
// internalReadRecordsDao is an internal type for wrapping the internal DAO implementation.
|
||||
type internalReadRecordsDao = *internal.ReadRecordsDao
|
||||
|
||||
// readRecordsDao is the data access object for the table read_records.
|
||||
// You can define custom methods on it to extend its functionality as needed.
|
||||
type readRecordsDao struct {
|
||||
internalReadRecordsDao
|
||||
}
|
||||
|
||||
var (
|
||||
// ReadRecords is a globally accessible object for table read_records operations.
|
||||
ReadRecords = readRecordsDao{
|
||||
internal.NewReadRecordsDao(),
|
||||
}
|
||||
)
|
||||
|
||||
// Add your custom methods and functionality below.
|
||||
27
internal/dao/user_read_history.go
Normal file
27
internal/dao/user_read_history.go
Normal file
@ -0,0 +1,27 @@
|
||||
// =================================================================================
|
||||
// This file is auto-generated by the GoFrame CLI tool. You may modify it as needed.
|
||||
// =================================================================================
|
||||
|
||||
package dao
|
||||
|
||||
import (
|
||||
"server/internal/dao/internal"
|
||||
)
|
||||
|
||||
// internalUserReadHistoryDao is an internal type for wrapping the internal DAO implementation.
|
||||
type internalUserReadHistoryDao = *internal.UserReadHistoryDao
|
||||
|
||||
// userReadHistoryDao is the data access object for the table user_read_history.
|
||||
// You can define custom methods on it to extend its functionality as needed.
|
||||
type userReadHistoryDao struct {
|
||||
internalUserReadHistoryDao
|
||||
}
|
||||
|
||||
var (
|
||||
// UserReadHistory is a globally accessible object for table user_read_history operations.
|
||||
UserReadHistory = userReadHistoryDao{
|
||||
internal.NewUserReadHistoryDao(),
|
||||
}
|
||||
)
|
||||
|
||||
// Add your custom methods and functionality below.
|
||||
27
internal/dao/user_read_records.go
Normal file
27
internal/dao/user_read_records.go
Normal file
@ -0,0 +1,27 @@
|
||||
// =================================================================================
|
||||
// This file is auto-generated by the GoFrame CLI tool. You may modify it as needed.
|
||||
// =================================================================================
|
||||
|
||||
package dao
|
||||
|
||||
import (
|
||||
"server/internal/dao/internal"
|
||||
)
|
||||
|
||||
// internalUserReadRecordsDao is an internal type for wrapping the internal DAO implementation.
|
||||
type internalUserReadRecordsDao = *internal.UserReadRecordsDao
|
||||
|
||||
// userReadRecordsDao is the data access object for the table user_read_records.
|
||||
// You can define custom methods on it to extend its functionality as needed.
|
||||
type userReadRecordsDao struct {
|
||||
internalUserReadRecordsDao
|
||||
}
|
||||
|
||||
var (
|
||||
// UserReadRecords is a globally accessible object for table user_read_records operations.
|
||||
UserReadRecords = userReadRecordsDao{
|
||||
internal.NewUserReadRecordsDao(),
|
||||
}
|
||||
)
|
||||
|
||||
// Add your custom methods and functionality below.
|
||||
268
internal/logic/author/author.go
Normal file
268
internal/logic/author/author.go
Normal file
@ -0,0 +1,268 @@
|
||||
package author
|
||||
|
||||
import (
|
||||
"context"
|
||||
"server/internal/dao"
|
||||
"server/internal/model"
|
||||
"server/internal/model/do"
|
||||
"server/internal/service"
|
||||
"server/utility/ecode"
|
||||
"server/utility/encrypt"
|
||||
|
||||
"github.com/gogf/gf/v2/database/gdb"
|
||||
)
|
||||
|
||||
type sAuthor struct{}
|
||||
|
||||
func New() service.IAuthor {
|
||||
return &sAuthor{}
|
||||
}
|
||||
func init() {
|
||||
service.RegisterAuthor(New())
|
||||
}
|
||||
|
||||
// List retrieves a paginated list of authors
|
||||
func (s *sAuthor) List(ctx context.Context, in *model.AuthorListIn) (out *model.AuthorListOut, err error) {
|
||||
out = &model.AuthorListOut{}
|
||||
m := dao.Authors.Ctx(ctx)
|
||||
if in.PenName != "" {
|
||||
m = m.Where(dao.Authors.Columns().PenName+" like ?", "%"+in.PenName+"%")
|
||||
}
|
||||
if in.Status != 0 {
|
||||
m = m.Where(dao.Authors.Columns().Status, in.Status)
|
||||
}
|
||||
if err = m.Page(in.Page, in.Size).ScanAndCount(&out.List, &out.Total, false); err != nil {
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Create adds a new author
|
||||
func (s *sAuthor) Create(ctx context.Context, in *model.AuthorAddIn) (out *model.AuthorCRUDOut, err error) {
|
||||
// 开启事务,确保用户和作者同时写入
|
||||
err = dao.Authors.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {
|
||||
// 检查该 userId 是否已存在作者
|
||||
exist, err := dao.Authors.Ctx(ctx).TX(tx).
|
||||
Where(dao.Authors.Columns().UserId, in.UserId).
|
||||
Exist()
|
||||
if err != nil {
|
||||
return ecode.Fail.Sub("author_query_failed")
|
||||
}
|
||||
if exist {
|
||||
return ecode.Params.Sub("author_user_exists")
|
||||
}
|
||||
|
||||
// 检查用户是否存在
|
||||
userExist, err := dao.Users.Ctx(ctx).TX(tx).
|
||||
Where(dao.Users.Columns().Id, in.UserId).
|
||||
Exist()
|
||||
if err != nil {
|
||||
return ecode.Fail.Sub("author_query_failed")
|
||||
}
|
||||
if !userExist {
|
||||
// 不存在则创建用户,用户名用笔名,密码默认 Aa123456
|
||||
hash, err := encrypt.EncryptPassword("Aa123456")
|
||||
if err != nil {
|
||||
return ecode.Fail.Sub("password_encryption_failed")
|
||||
}
|
||||
result, err := dao.Users.Ctx(ctx).TX(tx).Data(do.Users{
|
||||
Username: in.PenName,
|
||||
PasswordHash: hash,
|
||||
}).InsertAndGetId()
|
||||
if err != nil {
|
||||
return ecode.Fail.Sub("author_create_failed")
|
||||
}
|
||||
in.UserId = result
|
||||
}
|
||||
|
||||
// 创建作者
|
||||
_, err = dao.Authors.Ctx(ctx).TX(tx).Data(do.Authors{
|
||||
UserId: in.UserId,
|
||||
PenName: in.PenName,
|
||||
Bio: in.Bio,
|
||||
Status: in.Status,
|
||||
}).Insert()
|
||||
if err != nil {
|
||||
return ecode.Fail.Sub("author_create_failed")
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &model.AuthorCRUDOut{Success: true}, nil
|
||||
}
|
||||
|
||||
// Update edits an author
|
||||
func (s *sAuthor) Update(ctx context.Context, in *model.AuthorEditIn) (out *model.AuthorCRUDOut, err error) {
|
||||
exist, err := dao.Authors.Ctx(ctx).
|
||||
WherePri(in.Id).
|
||||
Exist()
|
||||
if err != nil {
|
||||
return nil, ecode.Fail.Sub("author_query_failed")
|
||||
}
|
||||
if !exist {
|
||||
return nil, ecode.NotFound.Sub("author_not_found")
|
||||
}
|
||||
_, err = dao.Authors.Ctx(ctx).
|
||||
WherePri(in.Id).
|
||||
Data(do.Authors{
|
||||
PenName: in.PenName,
|
||||
Bio: in.Bio,
|
||||
Status: in.Status,
|
||||
}).Update()
|
||||
if err != nil {
|
||||
return nil, ecode.Fail.Sub("author_update_failed")
|
||||
}
|
||||
return &model.AuthorCRUDOut{Success: true}, nil
|
||||
}
|
||||
|
||||
// Delete removes an author by id
|
||||
func (s *sAuthor) Delete(ctx context.Context, in *model.AuthorDelIn) (out *model.AuthorCRUDOut, err error) {
|
||||
exist, err := dao.Authors.Ctx(ctx).
|
||||
WherePri(in.Id).
|
||||
Exist()
|
||||
if err != nil {
|
||||
return nil, ecode.Fail.Sub("author_query_failed")
|
||||
}
|
||||
if !exist {
|
||||
return nil, ecode.NotFound.Sub("author_not_found")
|
||||
}
|
||||
|
||||
// 开启事务,删除作者及相关数据
|
||||
err = dao.Authors.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {
|
||||
// 1. 删除作者相关的用户关注记录
|
||||
_, err := dao.UserFollowAuthors.Ctx(ctx).TX(tx).
|
||||
Where(dao.UserFollowAuthors.Columns().AuthorId, in.Id).
|
||||
Delete()
|
||||
if err != nil {
|
||||
return ecode.Fail.Sub("follow_author_delete_failed")
|
||||
}
|
||||
|
||||
// 2. 删除作者相关的书籍(这里需要递归删除书籍相关的所有数据)
|
||||
// 先查询该作者的所有书籍ID
|
||||
var bookIds []int64
|
||||
err = dao.Books.Ctx(ctx).TX(tx).
|
||||
Where(dao.Books.Columns().AuthorId, in.Id).
|
||||
Fields("id").
|
||||
Scan(&bookIds)
|
||||
if err != nil {
|
||||
return ecode.Fail.Sub("book_query_failed")
|
||||
}
|
||||
|
||||
if len(bookIds) > 0 {
|
||||
// 删除书籍相关的章节
|
||||
_, err = dao.Chapters.Ctx(ctx).TX(tx).
|
||||
WhereIn(dao.Chapters.Columns().BookId, bookIds).
|
||||
Delete()
|
||||
if err != nil {
|
||||
return ecode.Fail.Sub("chapter_delete_failed")
|
||||
}
|
||||
|
||||
// 删除书籍相关的用户阅读记录
|
||||
_, err = dao.UserReadRecords.Ctx(ctx).TX(tx).
|
||||
WhereIn(dao.UserReadRecords.Columns().BookId, bookIds).
|
||||
Delete()
|
||||
if err != nil {
|
||||
return ecode.Fail.Sub("read_record_delete_failed")
|
||||
}
|
||||
|
||||
// 删除书籍相关的用户阅读历史
|
||||
_, err = dao.UserReadHistory.Ctx(ctx).TX(tx).
|
||||
WhereIn(dao.UserReadHistory.Columns().BookId, bookIds).
|
||||
Delete()
|
||||
if err != nil {
|
||||
return ecode.Fail.Sub("history_delete_failed")
|
||||
}
|
||||
|
||||
// 删除书籍相关的用户书架
|
||||
_, err = dao.Bookshelves.Ctx(ctx).TX(tx).
|
||||
WhereIn(dao.Bookshelves.Columns().BookId, bookIds).
|
||||
Delete()
|
||||
if err != nil {
|
||||
return ecode.Fail.Sub("bookshelf_delete_failed")
|
||||
}
|
||||
|
||||
// 删除书籍相关的用户评分
|
||||
_, err = dao.BookRatings.Ctx(ctx).TX(tx).
|
||||
WhereIn(dao.BookRatings.Columns().BookId, bookIds).
|
||||
Delete()
|
||||
if err != nil {
|
||||
return ecode.Fail.Sub("rating_delete_failed")
|
||||
}
|
||||
|
||||
// 删除书籍相关的章节购买记录
|
||||
_, err = dao.UserChapterPurchases.Ctx(ctx).TX(tx).
|
||||
WhereIn(dao.UserChapterPurchases.Columns().BookId, bookIds).
|
||||
Delete()
|
||||
if err != nil {
|
||||
return ecode.Fail.Sub("purchase_delete_failed")
|
||||
}
|
||||
|
||||
// 最后删除书籍
|
||||
_, err = dao.Books.Ctx(ctx).TX(tx).
|
||||
Where(dao.Books.Columns().AuthorId, in.Id).
|
||||
Delete()
|
||||
if err != nil {
|
||||
return ecode.Fail.Sub("book_delete_failed")
|
||||
}
|
||||
}
|
||||
|
||||
// 3. 最后删除作者
|
||||
_, err = dao.Authors.Ctx(ctx).TX(tx).WherePri(in.Id).Delete()
|
||||
if err != nil {
|
||||
return ecode.Fail.Sub("author_delete_failed")
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &model.AuthorCRUDOut{Success: true}, nil
|
||||
}
|
||||
|
||||
// Apply 允许用户申请成为作者
|
||||
func (s *sAuthor) Apply(ctx context.Context, in *model.AuthorApplyIn) (out *model.AuthorApplyOut, err error) {
|
||||
userIdVal := ctx.Value("id")
|
||||
userId, ok := userIdVal.(int64)
|
||||
if !ok || userId == 0 {
|
||||
return nil, ecode.Fail.Sub("user_id_invalid")
|
||||
}
|
||||
exist, err := dao.Authors.Ctx(ctx).
|
||||
Where(dao.Authors.Columns().UserId, userId).
|
||||
Exist()
|
||||
if err != nil {
|
||||
return nil, ecode.Fail.Sub("author_query_failed")
|
||||
}
|
||||
if exist {
|
||||
return nil, ecode.Params.Sub("author_user_exists")
|
||||
}
|
||||
if _, err := dao.Authors.Ctx(ctx).Data(do.Authors{
|
||||
UserId: userId,
|
||||
PenName: in.PenName,
|
||||
Bio: in.Bio,
|
||||
Status: 1, // 默认正常
|
||||
}).Insert(); err != nil {
|
||||
return nil, ecode.Fail.Sub("author_create_failed")
|
||||
}
|
||||
return &model.AuthorApplyOut{Success: true}, nil
|
||||
}
|
||||
func (s *sAuthor) Detail(ctx context.Context, in *model.AuthorDetailIn) (out *model.AuthorDetailOut, err error) {
|
||||
out = &model.AuthorDetailOut{}
|
||||
exist, err := dao.Authors.Ctx(ctx).
|
||||
WherePri(in.AuthorId).
|
||||
Exist()
|
||||
if err != nil {
|
||||
return nil, ecode.Fail.Sub("author_query_failed")
|
||||
}
|
||||
if !exist {
|
||||
return nil, ecode.NotFound.Sub("author_not_found")
|
||||
}
|
||||
if err = dao.Authors.Ctx(ctx).WherePri(in.AuthorId).WithAll().Scan(&out); err != nil {
|
||||
return nil, ecode.Fail.Sub("author_query_failed")
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
@ -7,6 +7,8 @@ import (
|
||||
"server/internal/model/do"
|
||||
"server/internal/service"
|
||||
"server/utility/ecode"
|
||||
|
||||
"github.com/gogf/gf/v2/database/gdb"
|
||||
)
|
||||
|
||||
type sBook struct{}
|
||||
@ -38,7 +40,10 @@ func (s *sBook) List(ctx context.Context, in *model.BookListIn) (out *model.Book
|
||||
if in.IsRecommended != 0 {
|
||||
m = m.Where(dao.Books.Columns().IsRecommended, in.IsRecommended)
|
||||
}
|
||||
if err = m.Page(in.Page, in.Size).ScanAndCount(&out.List, &out.Total, false); err != nil {
|
||||
if in.Sort != "" {
|
||||
m = m.Order(in.Sort)
|
||||
}
|
||||
if err = m.Page(in.Page, in.Size).WithAll().ScanAndCount(&out.List, &out.Total, false); err != nil {
|
||||
return
|
||||
}
|
||||
return
|
||||
@ -127,12 +132,633 @@ func (s *sBook) Delete(ctx context.Context, in *model.BookDelIn) (out *model.Boo
|
||||
return nil, ecode.NotFound.Sub("book_not_found")
|
||||
}
|
||||
|
||||
_, err = dao.Books.Ctx(ctx).WherePri(in.Id).Delete()
|
||||
// 开启事务,删除书籍及相关数据
|
||||
err = dao.Books.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {
|
||||
// 1. 删除书籍相关的章节
|
||||
_, err := dao.Chapters.Ctx(ctx).TX(tx).
|
||||
Where(dao.Chapters.Columns().BookId, in.Id).
|
||||
Delete()
|
||||
if err != nil {
|
||||
return ecode.Fail.Sub("chapter_delete_failed")
|
||||
}
|
||||
|
||||
// 2. 删除书籍相关的用户阅读记录
|
||||
_, err = dao.UserReadRecords.Ctx(ctx).TX(tx).
|
||||
Where(dao.UserReadRecords.Columns().BookId, in.Id).
|
||||
Delete()
|
||||
if err != nil {
|
||||
return ecode.Fail.Sub("read_record_delete_failed")
|
||||
}
|
||||
|
||||
// 3. 删除书籍相关的用户阅读历史
|
||||
_, err = dao.UserReadHistory.Ctx(ctx).TX(tx).
|
||||
Where(dao.UserReadHistory.Columns().BookId, in.Id).
|
||||
Delete()
|
||||
if err != nil {
|
||||
return ecode.Fail.Sub("history_delete_failed")
|
||||
}
|
||||
|
||||
// 4. 删除书籍相关的用户书架
|
||||
_, err = dao.Bookshelves.Ctx(ctx).TX(tx).
|
||||
Where(dao.Bookshelves.Columns().BookId, in.Id).
|
||||
Delete()
|
||||
if err != nil {
|
||||
return ecode.Fail.Sub("bookshelf_delete_failed")
|
||||
}
|
||||
|
||||
// 5. 删除书籍相关的用户评分
|
||||
_, err = dao.BookRatings.Ctx(ctx).TX(tx).
|
||||
Where(dao.BookRatings.Columns().BookId, in.Id).
|
||||
Delete()
|
||||
if err != nil {
|
||||
return ecode.Fail.Sub("rating_delete_failed")
|
||||
}
|
||||
|
||||
// 6. 删除书籍相关的章节购买记录
|
||||
_, err = dao.UserChapterPurchases.Ctx(ctx).TX(tx).
|
||||
Where(dao.UserChapterPurchases.Columns().BookId, in.Id).
|
||||
Delete()
|
||||
if err != nil {
|
||||
return ecode.Fail.Sub("purchase_delete_failed")
|
||||
}
|
||||
|
||||
// 7. 最后删除书籍
|
||||
_, err = dao.Books.Ctx(ctx).TX(tx).WherePri(in.Id).Delete()
|
||||
if err != nil {
|
||||
return ecode.Fail.Sub("book_delete_failed")
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return nil, ecode.Fail.Sub("book_delete_failed")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &model.BookCRUDOut{
|
||||
Success: true,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// AppList retrieves book list for app
|
||||
func (s *sBook) AppList(ctx context.Context, in *model.BookAppListIn) (out *model.BookAppListOut, err error) {
|
||||
out = &model.BookAppListOut{}
|
||||
|
||||
// 构建查询条件,使用WithAll查询关联的作者信息
|
||||
m := dao.Books.Ctx(ctx).WithAll()
|
||||
|
||||
// 书名模糊搜索
|
||||
if in.Title != "" {
|
||||
m = m.Where(dao.Books.Columns().Title+" like ?", "%"+in.Title+"%")
|
||||
}
|
||||
|
||||
// 分类筛选
|
||||
if in.CategoryId != 0 {
|
||||
m = m.Where(dao.Books.Columns().CategoryId, in.CategoryId)
|
||||
}
|
||||
|
||||
// 推荐筛选
|
||||
if in.IsRecommended {
|
||||
m = m.Where(dao.Books.Columns().IsRecommended, 1)
|
||||
}
|
||||
|
||||
// 最新筛选(按创建时间倒序)
|
||||
if in.IsLatest == 1 {
|
||||
m = m.OrderDesc(dao.Books.Columns().CreatedAt)
|
||||
}
|
||||
if in.AuthorId != 0 {
|
||||
m = m.Where(dao.Books.Columns().AuthorId, in.AuthorId)
|
||||
}
|
||||
if in.IsFeatured {
|
||||
m = m.Where(dao.Books.Columns().IsFeatured, 1)
|
||||
}
|
||||
if in.Sort != "" {
|
||||
m = m.Order(in.Sort)
|
||||
}
|
||||
|
||||
// 执行分页查询
|
||||
if err = m.Page(in.Page, in.Size).ScanAndCount(&out.List, &out.Total, false); err != nil {
|
||||
return nil, ecode.Fail.Sub("book_query_failed")
|
||||
}
|
||||
|
||||
// 用户评分批量查询
|
||||
if in.UserId > 0 && len(out.List) > 0 {
|
||||
bookIds := make([]int64, 0, len(out.List))
|
||||
for _, item := range out.List {
|
||||
bookIds = append(bookIds, item.Id)
|
||||
}
|
||||
// 查询用户对这些书的评分
|
||||
type ratingRow struct {
|
||||
BookId int64 `json:"bookId"`
|
||||
Score float64 `json:"score"`
|
||||
}
|
||||
ratings := make([]ratingRow, 0)
|
||||
err = dao.BookRatings.Ctx(ctx).
|
||||
Fields("book_id, score").
|
||||
Where(dao.BookRatings.Columns().UserId, in.UserId).
|
||||
WhereIn(dao.BookRatings.Columns().BookId, bookIds).
|
||||
Scan(&ratings)
|
||||
if err == nil && len(ratings) > 0 {
|
||||
ratingMap := make(map[int64]float64, len(ratings))
|
||||
for _, r := range ratings {
|
||||
ratingMap[r.BookId] = r.Score
|
||||
}
|
||||
for i := range out.List {
|
||||
if score, ok := ratingMap[out.List[i].Id]; ok {
|
||||
out.List[i].HasRated = true
|
||||
out.List[i].MyRating = score
|
||||
} else {
|
||||
out.List[i].HasRated = false
|
||||
out.List[i].MyRating = 0
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for i := range out.List {
|
||||
out.List[i].HasRated = false
|
||||
out.List[i].MyRating = 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// AppRate rates a book for app
|
||||
func (s *sBook) AppRate(ctx context.Context, in *model.BookAppRateIn) (out *model.BookAppRateOut, err error) {
|
||||
out = &model.BookAppRateOut{}
|
||||
|
||||
// 必须指定用户ID
|
||||
if in.UserId == 0 {
|
||||
return nil, ecode.Fail.Sub("user_id_required")
|
||||
}
|
||||
|
||||
// 必须指定书籍ID
|
||||
if in.BookId == 0 {
|
||||
return nil, ecode.Fail.Sub("book_id_required")
|
||||
}
|
||||
|
||||
// 验证评分范围(1-10分)
|
||||
if in.Rating < 1 || in.Rating > 10 {
|
||||
return nil, ecode.Fail.Sub("rating_invalid")
|
||||
}
|
||||
|
||||
// 检查书籍是否存在
|
||||
exist, err := dao.Books.Ctx(ctx).Where(dao.Books.Columns().Id, in.BookId).Exist()
|
||||
if err != nil {
|
||||
return nil, ecode.Fail.Sub("book_query_failed")
|
||||
}
|
||||
if !exist {
|
||||
return nil, ecode.NotFound.Sub("book_not_found")
|
||||
}
|
||||
|
||||
// 检查用户是否存在
|
||||
exist, err = dao.Users.Ctx(ctx).Where(dao.Users.Columns().Id, in.UserId).Exist()
|
||||
if err != nil {
|
||||
return nil, ecode.Fail.Sub("user_query_failed")
|
||||
}
|
||||
if !exist {
|
||||
return nil, ecode.NotFound.Sub("user_not_found")
|
||||
}
|
||||
|
||||
// 开启事务处理评分
|
||||
if err := dao.BookRatings.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {
|
||||
// 检查是否已经评分过
|
||||
exist, err := dao.BookRatings.Ctx(ctx).TX(tx).
|
||||
Where(dao.BookRatings.Columns().UserId, in.UserId).
|
||||
Where(dao.BookRatings.Columns().BookId, in.BookId).
|
||||
Exist()
|
||||
if err != nil {
|
||||
return ecode.Fail.Sub("rating_query_failed")
|
||||
}
|
||||
|
||||
if exist {
|
||||
// 更新现有评分
|
||||
_, err = dao.BookRatings.Ctx(ctx).TX(tx).
|
||||
Where(dao.BookRatings.Columns().UserId, in.UserId).
|
||||
Where(dao.BookRatings.Columns().BookId, in.BookId).
|
||||
Data(do.BookRatings{
|
||||
Score: in.Rating,
|
||||
}).Update()
|
||||
if err != nil {
|
||||
return ecode.Fail.Sub("rating_update_failed")
|
||||
}
|
||||
} else {
|
||||
// 创建新评分记录
|
||||
_, err = dao.BookRatings.Ctx(ctx).TX(tx).Data(do.BookRatings{
|
||||
UserId: in.UserId,
|
||||
BookId: in.BookId,
|
||||
Score: in.Rating,
|
||||
}).Insert()
|
||||
if err != nil {
|
||||
return ecode.Fail.Sub("rating_create_failed")
|
||||
}
|
||||
}
|
||||
|
||||
// 重新计算书籍平均评分
|
||||
var avgRating float64
|
||||
err = dao.BookRatings.Ctx(ctx).TX(tx).
|
||||
Where(dao.BookRatings.Columns().BookId, in.BookId).
|
||||
Fields("AVG(score) as avg_rating").
|
||||
Scan(&avgRating)
|
||||
if err != nil {
|
||||
return ecode.Fail.Sub("rating_calculation_failed")
|
||||
}
|
||||
|
||||
// 更新书籍的平均评分
|
||||
_, err = dao.Books.Ctx(ctx).TX(tx).
|
||||
Where(dao.Books.Columns().Id, in.BookId).
|
||||
Data(do.Books{
|
||||
Rating: avgRating,
|
||||
}).Update()
|
||||
if err != nil {
|
||||
return ecode.Fail.Sub("book_rating_update_failed")
|
||||
}
|
||||
|
||||
return nil
|
||||
}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
out.Success = true
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// AppDetail retrieves book detail for app
|
||||
func (s *sBook) AppDetail(ctx context.Context, in *model.BookAppDetailIn) (out *model.BookAppDetailOut, err error) {
|
||||
out = &model.BookAppDetailOut{}
|
||||
|
||||
// 必须指定书籍ID
|
||||
if in.Id == 0 {
|
||||
return nil, ecode.Fail.Sub("book_id_required")
|
||||
}
|
||||
|
||||
// 构建查询条件
|
||||
m := dao.Books.Ctx(ctx)
|
||||
m = m.Where(dao.Books.Columns().Id, in.Id)
|
||||
|
||||
// 执行查询
|
||||
if err = m.Scan(out); err != nil {
|
||||
return nil, ecode.Fail.Sub("book_query_failed")
|
||||
}
|
||||
|
||||
// 检查书籍是否存在
|
||||
if out.Id == 0 {
|
||||
return nil, ecode.NotFound.Sub("book_not_found")
|
||||
}
|
||||
|
||||
// 如果用户已登录,查询阅读进度
|
||||
if in.UserId > 0 {
|
||||
// 查询用户对该书籍的历史记录
|
||||
var historyRecord struct {
|
||||
ChapterId int64 `json:"chapterId"`
|
||||
ReadAt string `json:"readAt"`
|
||||
}
|
||||
err = dao.UserReadHistory.Ctx(ctx).
|
||||
Fields("chapter_id, read_at").
|
||||
Where(dao.UserReadHistory.Columns().UserId, in.UserId).
|
||||
Where(dao.UserReadHistory.Columns().BookId, in.Id).
|
||||
OrderDesc(dao.UserReadHistory.Columns().ReadAt).
|
||||
Scan(&historyRecord)
|
||||
|
||||
if err == nil && historyRecord.ChapterId > 0 {
|
||||
// 用户读过这本书
|
||||
out.HasRead = true
|
||||
out.LastChapterId = historyRecord.ChapterId
|
||||
out.LastReadAt = historyRecord.ReadAt
|
||||
|
||||
// 计算阅读进度:总章节数 vs 已读章节数
|
||||
totalChapters, err := dao.Chapters.Ctx(ctx).
|
||||
Where(dao.Chapters.Columns().BookId, in.Id).
|
||||
Count()
|
||||
|
||||
if err == nil && totalChapters > 0 {
|
||||
readChapters, err := dao.UserReadRecords.Ctx(ctx).
|
||||
Where(dao.UserReadRecords.Columns().UserId, in.UserId).
|
||||
Where(dao.UserReadRecords.Columns().BookId, in.Id).
|
||||
Where(dao.UserReadRecords.Columns().ChapterId, ">", 0). // 只统计有章节ID的记录
|
||||
Count()
|
||||
|
||||
if err == nil {
|
||||
out.ReadProgress = int(float64(readChapters) / float64(totalChapters) * 100)
|
||||
if out.ReadProgress > 100 {
|
||||
out.ReadProgress = 100
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (s *sBook) MyList(ctx context.Context, in *model.MyBookListIn) (out *model.MyBookListOut, err error) {
|
||||
out = &model.MyBookListOut{}
|
||||
|
||||
// 验证用户ID
|
||||
if in.UserId == 0 {
|
||||
return nil, ecode.Fail.Sub("user_id_required")
|
||||
}
|
||||
|
||||
// 验证类型参数
|
||||
if in.Type < 1 || in.Type > 3 {
|
||||
return nil, ecode.Fail.Sub("type_invalid")
|
||||
}
|
||||
|
||||
var list []model.MyBookItem
|
||||
var total int
|
||||
|
||||
switch in.Type {
|
||||
case 1: // 正在读
|
||||
// 查询书架表中read_status=1的记录
|
||||
var bookshelves []struct {
|
||||
BookId int64 `json:"bookId"`
|
||||
LastReadPercent float64 `json:"lastReadPercent"`
|
||||
LastReadAt string `json:"lastReadAt"`
|
||||
}
|
||||
|
||||
if in.Sort != "" {
|
||||
err = dao.Bookshelves.Ctx(ctx).
|
||||
Fields("book_id, last_read_percent, last_read_at").
|
||||
Where(dao.Bookshelves.Columns().UserId, in.UserId).
|
||||
Where(dao.Bookshelves.Columns().ReadStatus, 1).
|
||||
Order(in.Sort).
|
||||
Page(in.Page, in.Size).
|
||||
ScanAndCount(&bookshelves, &total, false)
|
||||
} else {
|
||||
err = dao.Bookshelves.Ctx(ctx).
|
||||
Fields("book_id, last_read_percent, last_read_at").
|
||||
Where(dao.Bookshelves.Columns().UserId, in.UserId).
|
||||
Where(dao.Bookshelves.Columns().ReadStatus, 1).
|
||||
Page(in.Page, in.Size).
|
||||
ScanAndCount(&bookshelves, &total, false)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, ecode.Fail.Sub("bookshelf_query_failed")
|
||||
}
|
||||
|
||||
// 获取书籍详细信息
|
||||
if len(bookshelves) > 0 {
|
||||
bookIds := make([]int64, 0, len(bookshelves))
|
||||
for _, bs := range bookshelves {
|
||||
bookIds = append(bookIds, bs.BookId)
|
||||
}
|
||||
|
||||
var books []model.Book
|
||||
err = dao.Books.Ctx(ctx).
|
||||
WhereIn(dao.Books.Columns().Id, bookIds).
|
||||
Scan(&books)
|
||||
if err != nil {
|
||||
return nil, ecode.Fail.Sub("book_query_failed")
|
||||
}
|
||||
|
||||
// 构建书籍ID到书架信息的映射
|
||||
bookshelfMap := make(map[int64]struct {
|
||||
LastReadPercent float64
|
||||
LastReadAt string
|
||||
})
|
||||
for _, bs := range bookshelves {
|
||||
bookshelfMap[bs.BookId] = struct {
|
||||
LastReadPercent float64
|
||||
LastReadAt string
|
||||
}{
|
||||
LastReadPercent: bs.LastReadPercent,
|
||||
LastReadAt: bs.LastReadAt,
|
||||
}
|
||||
}
|
||||
|
||||
// 构建返回列表
|
||||
for _, book := range books {
|
||||
bsInfo := bookshelfMap[book.Id]
|
||||
list = append(list, model.MyBookItem{
|
||||
Id: book.Id,
|
||||
Title: book.Title,
|
||||
CoverUrl: book.CoverUrl,
|
||||
Description: book.Description,
|
||||
Progress: int(bsInfo.LastReadPercent),
|
||||
IsInShelf: true,
|
||||
LastReadAt: bsInfo.LastReadAt,
|
||||
Status: book.Status,
|
||||
AuthorId: book.AuthorId,
|
||||
CategoryId: book.CategoryId,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
case 2: // 已读完
|
||||
// 查询书架表中read_status=2的记录
|
||||
var bookshelves []struct {
|
||||
BookId int64 `json:"bookId"`
|
||||
LastReadPercent float64 `json:"lastReadPercent"`
|
||||
LastReadAt string `json:"lastReadAt"`
|
||||
}
|
||||
|
||||
if in.Sort != "" {
|
||||
err = dao.Bookshelves.Ctx(ctx).
|
||||
Fields("book_id, last_read_percent, last_read_at").
|
||||
Where(dao.Bookshelves.Columns().UserId, in.UserId).
|
||||
Where(dao.Bookshelves.Columns().ReadStatus, 2).
|
||||
Order(in.Sort).
|
||||
Page(in.Page, in.Size).
|
||||
ScanAndCount(&bookshelves, &total, false)
|
||||
} else {
|
||||
err = dao.Bookshelves.Ctx(ctx).
|
||||
Fields("book_id, last_read_percent, last_read_at").
|
||||
Where(dao.Bookshelves.Columns().UserId, in.UserId).
|
||||
Where(dao.Bookshelves.Columns().ReadStatus, 2).
|
||||
Page(in.Page, in.Size).
|
||||
ScanAndCount(&bookshelves, &total, false)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, ecode.Fail.Sub("bookshelf_query_failed")
|
||||
}
|
||||
|
||||
// 获取书籍详细信息
|
||||
if len(bookshelves) > 0 {
|
||||
bookIds := make([]int64, 0, len(bookshelves))
|
||||
for _, bs := range bookshelves {
|
||||
bookIds = append(bookIds, bs.BookId)
|
||||
}
|
||||
|
||||
var books []model.Book
|
||||
err = dao.Books.Ctx(ctx).
|
||||
WhereIn(dao.Books.Columns().Id, bookIds).
|
||||
Scan(&books)
|
||||
if err != nil {
|
||||
return nil, ecode.Fail.Sub("book_query_failed")
|
||||
}
|
||||
|
||||
// 构建书籍ID到书架信息的映射
|
||||
bookshelfMap := make(map[int64]struct {
|
||||
LastReadPercent float64
|
||||
LastReadAt string
|
||||
})
|
||||
for _, bs := range bookshelves {
|
||||
bookshelfMap[bs.BookId] = struct {
|
||||
LastReadPercent float64
|
||||
LastReadAt string
|
||||
}{
|
||||
LastReadPercent: bs.LastReadPercent,
|
||||
LastReadAt: bs.LastReadAt,
|
||||
}
|
||||
}
|
||||
|
||||
// 构建返回列表
|
||||
for _, book := range books {
|
||||
bsInfo := bookshelfMap[book.Id]
|
||||
list = append(list, model.MyBookItem{
|
||||
Id: book.Id,
|
||||
Title: book.Title,
|
||||
CoverUrl: book.CoverUrl,
|
||||
Description: book.Description,
|
||||
Progress: int(bsInfo.LastReadPercent),
|
||||
IsInShelf: true,
|
||||
LastReadAt: bsInfo.LastReadAt,
|
||||
Status: book.Status,
|
||||
AuthorId: book.AuthorId,
|
||||
CategoryId: book.CategoryId,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
case 3: // 历史记录
|
||||
// 查询user_read_history表
|
||||
var histories []struct {
|
||||
BookId int64 `json:"bookId"`
|
||||
ChapterId int64 `json:"chapterId"`
|
||||
ReadAt string `json:"readAt"`
|
||||
}
|
||||
|
||||
if in.Sort != "" {
|
||||
err = dao.UserReadHistory.Ctx(ctx).
|
||||
Fields("book_id, chapter_id, read_at").
|
||||
Where(dao.UserReadHistory.Columns().UserId, in.UserId).
|
||||
Order(in.Sort).
|
||||
Page(in.Page, in.Size).
|
||||
ScanAndCount(&histories, &total, false)
|
||||
} else {
|
||||
err = dao.UserReadHistory.Ctx(ctx).
|
||||
Fields("book_id, chapter_id, read_at").
|
||||
Where(dao.UserReadHistory.Columns().UserId, in.UserId).
|
||||
OrderDesc(dao.UserReadHistory.Columns().ReadAt).
|
||||
Page(in.Page, in.Size).
|
||||
ScanAndCount(&histories, &total, false)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, ecode.Fail.Sub("history_query_failed")
|
||||
}
|
||||
|
||||
// 获取书籍详细信息
|
||||
if len(histories) > 0 {
|
||||
bookIds := make([]int64, 0, len(histories))
|
||||
for _, history := range histories {
|
||||
bookIds = append(bookIds, history.BookId)
|
||||
}
|
||||
|
||||
var books []model.Book
|
||||
err = dao.Books.Ctx(ctx).
|
||||
WhereIn(dao.Books.Columns().Id, bookIds).
|
||||
Scan(&books)
|
||||
if err != nil {
|
||||
return nil, ecode.Fail.Sub("book_query_failed")
|
||||
}
|
||||
|
||||
// 构建书籍ID到历史信息的映射
|
||||
historyMap := make(map[int64]struct {
|
||||
ChapterId int64
|
||||
ReadAt string
|
||||
})
|
||||
for _, history := range histories {
|
||||
historyMap[history.BookId] = struct {
|
||||
ChapterId int64
|
||||
ReadAt string
|
||||
}{
|
||||
ChapterId: history.ChapterId,
|
||||
ReadAt: history.ReadAt,
|
||||
}
|
||||
}
|
||||
|
||||
// 检查是否在书架中
|
||||
var bookshelves []struct {
|
||||
BookId int64 `json:"bookId"`
|
||||
}
|
||||
err = dao.Bookshelves.Ctx(ctx).
|
||||
Fields("book_id").
|
||||
Where(dao.Bookshelves.Columns().UserId, in.UserId).
|
||||
WhereIn(dao.Bookshelves.Columns().BookId, bookIds).
|
||||
Scan(&bookshelves)
|
||||
if err != nil {
|
||||
return nil, ecode.Fail.Sub("bookshelf_query_failed")
|
||||
}
|
||||
|
||||
// 构建书架ID集合
|
||||
shelfBookIds := make(map[int64]bool)
|
||||
for _, bs := range bookshelves {
|
||||
shelfBookIds[bs.BookId] = true
|
||||
}
|
||||
|
||||
// 构建返回列表
|
||||
for _, book := range books {
|
||||
historyInfo := historyMap[book.Id]
|
||||
list = append(list, model.MyBookItem{
|
||||
Id: book.Id,
|
||||
Title: book.Title,
|
||||
CoverUrl: book.CoverUrl,
|
||||
Description: book.Description,
|
||||
Progress: 0, // 历史记录不显示进度
|
||||
IsInShelf: shelfBookIds[book.Id],
|
||||
LastReadAt: historyInfo.ReadAt,
|
||||
Status: book.Status,
|
||||
AuthorId: book.AuthorId,
|
||||
CategoryId: book.CategoryId,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
default:
|
||||
// 返回空列表
|
||||
}
|
||||
|
||||
out = &model.MyBookListOut{
|
||||
Total: total,
|
||||
List: list,
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// SetFeatured: 单独修改书籍的精选状态
|
||||
func (s *sBook) SetFeatured(ctx context.Context, in *model.BookSetFeaturedIn) (out *model.BookCRUDOut, err error) {
|
||||
// 检查书籍是否存在
|
||||
exist, err := dao.Books.Ctx(ctx).WherePri(in.Id).Exist()
|
||||
if err != nil {
|
||||
return nil, ecode.Fail.Sub("book_query_failed")
|
||||
}
|
||||
if !exist {
|
||||
return nil, ecode.NotFound.Sub("book_not_found")
|
||||
}
|
||||
_, err = dao.Books.Ctx(ctx).WherePri(in.Id).Data(do.Books{
|
||||
IsFeatured: in.IsFeatured,
|
||||
}).Update()
|
||||
if err != nil {
|
||||
return nil, ecode.Fail.Sub("book_update_failed")
|
||||
}
|
||||
return &model.BookCRUDOut{Success: true}, nil
|
||||
}
|
||||
|
||||
// SetRecommended: 单独修改书籍的推荐状态
|
||||
func (s *sBook) SetRecommended(ctx context.Context, in *model.BookSetRecommendedIn) (out *model.BookCRUDOut, err error) {
|
||||
// 检查书籍是否存在
|
||||
exist, err := dao.Books.Ctx(ctx).WherePri(in.Id).Exist()
|
||||
if err != nil {
|
||||
return nil, ecode.Fail.Sub("book_query_failed")
|
||||
}
|
||||
if !exist {
|
||||
return nil, ecode.NotFound.Sub("book_not_found")
|
||||
}
|
||||
_, err = dao.Books.Ctx(ctx).WherePri(in.Id).Data(do.Books{
|
||||
IsRecommended: in.IsRecommended,
|
||||
}).Update()
|
||||
if err != nil {
|
||||
return nil, ecode.Fail.Sub("book_update_failed")
|
||||
}
|
||||
return &model.BookCRUDOut{Success: true}, nil
|
||||
}
|
||||
|
||||
57
internal/logic/bookshelve/bookshelve.go
Normal file
57
internal/logic/bookshelve/bookshelve.go
Normal file
@ -0,0 +1,57 @@
|
||||
package bookshelve
|
||||
|
||||
import (
|
||||
"context"
|
||||
"server/internal/dao"
|
||||
"server/internal/model"
|
||||
"server/internal/model/do"
|
||||
"server/internal/service"
|
||||
"server/utility/ecode"
|
||||
)
|
||||
|
||||
type sBookshelve struct{}
|
||||
|
||||
func New() service.IBookshelve {
|
||||
return &sBookshelve{}
|
||||
}
|
||||
|
||||
func init() {
|
||||
service.RegisterBookshelve(New())
|
||||
}
|
||||
|
||||
// Add 添加书架
|
||||
func (s *sBookshelve) Add(ctx context.Context, in *model.BookshelveAddIn) (out *model.BookshelveCRUDOut, err error) {
|
||||
exist, err := dao.Bookshelves.Ctx(ctx).
|
||||
Where(dao.Bookshelves.Columns().UserId, in.UserId).
|
||||
Where(dao.Bookshelves.Columns().BookId, in.BookId).
|
||||
Exist()
|
||||
if err != nil {
|
||||
return nil, ecode.Fail.Sub("bookshelve_query_failed")
|
||||
}
|
||||
if exist {
|
||||
return nil, ecode.Params.Sub("bookshelve_exists")
|
||||
}
|
||||
if _, err := dao.Bookshelves.Ctx(ctx).Data(do.Bookshelves{
|
||||
UserId: in.UserId,
|
||||
BookId: in.BookId,
|
||||
ReadStatus: 1, // 默认为正在读
|
||||
}).Insert(); err != nil {
|
||||
return nil, ecode.Fail.Sub("bookshelve_create_failed")
|
||||
}
|
||||
return &model.BookshelveCRUDOut{Success: true}, nil
|
||||
}
|
||||
|
||||
// Delete 批量删除书架
|
||||
func (s *sBookshelve) Delete(ctx context.Context, in *model.BookshelveDelIn) (out *model.BookshelveCRUDOut, err error) {
|
||||
if len(in.BookIds) == 0 {
|
||||
return nil, ecode.Params.Sub("bookshelve_bookids_empty")
|
||||
}
|
||||
_, err = dao.Bookshelves.Ctx(ctx).
|
||||
Where(dao.Bookshelves.Columns().UserId, in.UserId).
|
||||
WhereIn(dao.Bookshelves.Columns().BookId, in.BookIds).
|
||||
Delete()
|
||||
if err != nil {
|
||||
return nil, ecode.Fail.Sub("bookshelve_delete_failed")
|
||||
}
|
||||
return &model.BookshelveCRUDOut{Success: true}, nil
|
||||
}
|
||||
@ -7,6 +7,8 @@ import (
|
||||
"server/internal/model/do"
|
||||
"server/internal/service"
|
||||
"server/utility/ecode"
|
||||
|
||||
"github.com/gogf/gf/v2/database/gdb"
|
||||
)
|
||||
|
||||
type sCategory struct {
|
||||
@ -24,8 +26,8 @@ func init() {
|
||||
func (s *sCategory) List(ctx context.Context, in *model.CategoryListIn) (out *model.CategoryListOut, err error) {
|
||||
out = &model.CategoryListOut{}
|
||||
m := dao.Categories.Ctx(ctx)
|
||||
if in.Type != 0 {
|
||||
m = m.Where(dao.Categories.Columns().Type, in.Type)
|
||||
if in.Channel != 0 {
|
||||
m = m.Where(dao.Categories.Columns().Channel, in.Channel)
|
||||
}
|
||||
if err = m.Page(in.Page, in.Size).ScanAndCount(&out.List, &out.Total, false); err != nil {
|
||||
return
|
||||
@ -34,9 +36,6 @@ func (s *sCategory) List(ctx context.Context, in *model.CategoryListIn) (out *mo
|
||||
}
|
||||
|
||||
func (s *sCategory) Create(ctx context.Context, in *model.CategoryAddIn) (out *model.CategoryCRUDOut, err error) {
|
||||
if in.Type != 1 && in.Type != 2 {
|
||||
return nil, ecode.Params.Sub("category_type_invalid")
|
||||
}
|
||||
exist, err := dao.Categories.Ctx(ctx).
|
||||
Where(dao.Categories.Columns().Name, in.Name).
|
||||
Exist()
|
||||
@ -48,8 +47,8 @@ func (s *sCategory) Create(ctx context.Context, in *model.CategoryAddIn) (out *m
|
||||
}
|
||||
|
||||
if _, err := dao.Categories.Ctx(ctx).Data(do.Categories{
|
||||
Name: in.Name,
|
||||
Type: in.Type,
|
||||
Name: in.Name,
|
||||
Channel: in.Channel,
|
||||
}).Insert(); err != nil {
|
||||
return nil, ecode.Fail.Sub("category_create_failed")
|
||||
}
|
||||
@ -60,9 +59,6 @@ func (s *sCategory) Create(ctx context.Context, in *model.CategoryAddIn) (out *m
|
||||
}
|
||||
|
||||
func (s *sCategory) Update(ctx context.Context, in *model.CategoryEditIn) (out *model.CategoryCRUDOut, err error) {
|
||||
if in.Type != 1 && in.Type != 2 {
|
||||
return nil, ecode.Params.Sub("category_type_invalid")
|
||||
}
|
||||
exist, err := dao.Categories.Ctx(ctx).
|
||||
WherePri(in.Id).
|
||||
Exist()
|
||||
@ -88,8 +84,8 @@ func (s *sCategory) Update(ctx context.Context, in *model.CategoryEditIn) (out *
|
||||
_, err = dao.Categories.Ctx(ctx).
|
||||
WherePri(in.Id).
|
||||
Data(do.Categories{
|
||||
Name: in.Name,
|
||||
Type: in.Type,
|
||||
Name: in.Name,
|
||||
Channel: in.Channel,
|
||||
}).Update()
|
||||
if err != nil {
|
||||
return nil, ecode.Fail.Sub("category_update_failed")
|
||||
@ -111,10 +107,31 @@ func (s *sCategory) Delete(ctx context.Context, in *model.CategoryDelIn) (out *m
|
||||
return nil, ecode.NotFound.Sub("category_not_found")
|
||||
}
|
||||
|
||||
// Soft delete category
|
||||
_, err = dao.Categories.Ctx(ctx).WherePri(in.Id).Delete()
|
||||
// 开启事务,检查是否有书籍使用了这个分类
|
||||
err = dao.Categories.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {
|
||||
// 检查是否有书籍使用了这个分类
|
||||
bookCount, err := dao.Books.Ctx(ctx).TX(tx).
|
||||
Where(dao.Books.Columns().CategoryId, in.Id).
|
||||
Count()
|
||||
if err != nil {
|
||||
return ecode.Fail.Sub("book_query_failed")
|
||||
}
|
||||
|
||||
if bookCount > 0 {
|
||||
return ecode.Fail.Sub("category_in_use")
|
||||
}
|
||||
|
||||
// 删除分类
|
||||
_, err = dao.Categories.Ctx(ctx).TX(tx).WherePri(in.Id).Delete()
|
||||
if err != nil {
|
||||
return ecode.Fail.Sub("category_delete_failed")
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return nil, ecode.Fail.Sub("category_delete_failed")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &model.CategoryCRUDOut{
|
||||
|
||||
@ -5,8 +5,12 @@ import (
|
||||
"server/internal/dao"
|
||||
"server/internal/model"
|
||||
"server/internal/model/do"
|
||||
"server/internal/model/entity"
|
||||
"server/internal/service"
|
||||
"server/utility/ecode"
|
||||
|
||||
"github.com/gogf/gf/v2/database/gdb"
|
||||
"github.com/gogf/gf/v2/os/gtime"
|
||||
)
|
||||
|
||||
type sChapter struct{}
|
||||
@ -38,6 +42,7 @@ func (s *sChapter) List(ctx context.Context, in *model.ChapterListIn) (out *mode
|
||||
return
|
||||
}
|
||||
|
||||
// Create creates a new chapter
|
||||
func (s *sChapter) Create(ctx context.Context, in *model.ChapterAddIn) (out *model.ChapterCRUDOut, err error) {
|
||||
if _, err := dao.Chapters.Ctx(ctx).Data(do.Chapters{
|
||||
BookId: in.BookId,
|
||||
@ -53,6 +58,7 @@ func (s *sChapter) Create(ctx context.Context, in *model.ChapterAddIn) (out *mod
|
||||
return &model.ChapterCRUDOut{Success: true}, nil
|
||||
}
|
||||
|
||||
// Update updates an existing chapter
|
||||
func (s *sChapter) Update(ctx context.Context, in *model.ChapterEditIn) (out *model.ChapterCRUDOut, err error) {
|
||||
exist, err := dao.Chapters.Ctx(ctx).
|
||||
WherePri(in.Id).
|
||||
@ -80,6 +86,7 @@ func (s *sChapter) Update(ctx context.Context, in *model.ChapterEditIn) (out *mo
|
||||
return &model.ChapterCRUDOut{Success: true}, nil
|
||||
}
|
||||
|
||||
// Delete deletes a chapter by ID
|
||||
func (s *sChapter) Delete(ctx context.Context, in *model.ChapterDelIn) (out *model.ChapterCRUDOut, err error) {
|
||||
exist, err := dao.Chapters.Ctx(ctx).
|
||||
WherePri(in.Id).
|
||||
@ -90,9 +97,431 @@ func (s *sChapter) Delete(ctx context.Context, in *model.ChapterDelIn) (out *mod
|
||||
if !exist {
|
||||
return nil, ecode.NotFound.Sub("chapter_not_found")
|
||||
}
|
||||
_, err = dao.Chapters.Ctx(ctx).WherePri(in.Id).Delete()
|
||||
|
||||
// 开启事务,删除章节及相关数据
|
||||
err = dao.Chapters.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {
|
||||
// 1. 删除章节相关的用户阅读记录
|
||||
_, err := dao.UserReadRecords.Ctx(ctx).TX(tx).
|
||||
Where(dao.UserReadRecords.Columns().ChapterId, in.Id).
|
||||
Delete()
|
||||
if err != nil {
|
||||
return ecode.Fail.Sub("read_record_delete_failed")
|
||||
}
|
||||
|
||||
// 2. 删除章节相关的购买记录
|
||||
_, err = dao.UserChapterPurchases.Ctx(ctx).TX(tx).
|
||||
Where(dao.UserChapterPurchases.Columns().ChapterId, in.Id).
|
||||
Delete()
|
||||
if err != nil {
|
||||
return ecode.Fail.Sub("purchase_delete_failed")
|
||||
}
|
||||
|
||||
// 3. 最后删除章节
|
||||
_, err = dao.Chapters.Ctx(ctx).TX(tx).WherePri(in.Id).Delete()
|
||||
if err != nil {
|
||||
return ecode.Fail.Sub("chapter_delete_failed")
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return nil, ecode.Fail.Sub("chapter_delete_failed")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &model.ChapterCRUDOut{Success: true}, nil
|
||||
}
|
||||
|
||||
// AppList retrieves chapter list for app without content
|
||||
func (s *sChapter) AppList(ctx context.Context, in *model.ChapterAppListIn) (out *model.ChapterAppListOut, err error) {
|
||||
out = &model.ChapterAppListOut{}
|
||||
|
||||
// 构建查询条件
|
||||
m := dao.Chapters.Ctx(ctx)
|
||||
|
||||
// 必须指定 bookId
|
||||
if in.BookId == 0 {
|
||||
return nil, ecode.Fail.Sub("chapter_book_id_required")
|
||||
}
|
||||
m = m.Where(dao.Chapters.Columns().BookId, in.BookId)
|
||||
|
||||
// 根据 isDesc 字段排序
|
||||
if in.IsDesc {
|
||||
m = m.OrderDesc(dao.Chapters.Columns().Sort)
|
||||
}
|
||||
|
||||
// 执行分页查询,获取列表和总数
|
||||
if err = m.Page(in.Page, in.Size).ScanAndCount(&out.List, &out.Total, false); err != nil {
|
||||
return nil, ecode.Fail.Sub("chapter_query_failed")
|
||||
}
|
||||
|
||||
// 如果指定了用户ID,查询阅读进度
|
||||
if in.UserId > 0 {
|
||||
// 获取所有章节ID
|
||||
chapterIds := make([]int64, 0, len(out.List))
|
||||
for _, item := range out.List {
|
||||
chapterIds = append(chapterIds, item.Id)
|
||||
}
|
||||
|
||||
if len(chapterIds) > 0 {
|
||||
// 查询阅读记录
|
||||
readRecords := make([]struct {
|
||||
ChapterId int64 `json:"chapterId"`
|
||||
ReadAt *gtime.Time `json:"readAt"`
|
||||
}, 0)
|
||||
|
||||
err = dao.UserReadRecords.Ctx(ctx).
|
||||
Fields("chapter_id, read_at").
|
||||
Where(dao.UserReadRecords.Columns().UserId, in.UserId).
|
||||
Where(dao.UserReadRecords.Columns().BookId, in.BookId).
|
||||
WhereIn(dao.UserReadRecords.Columns().ChapterId, chapterIds).
|
||||
Scan(&readRecords)
|
||||
if err != nil {
|
||||
return nil, ecode.Fail.Sub("read_record_query_failed")
|
||||
}
|
||||
|
||||
// 构建阅读记录映射
|
||||
readMap := make(map[int64]*gtime.Time)
|
||||
for _, record := range readRecords {
|
||||
readMap[record.ChapterId] = record.ReadAt
|
||||
}
|
||||
|
||||
// 为每个章节设置阅读进度
|
||||
for i := range out.List {
|
||||
if readAt, exists := readMap[out.List[i].Id]; exists {
|
||||
out.List[i].ReadAt = readAt
|
||||
out.List[i].ReadProgress = 100 // 有阅读记录表示已读
|
||||
} else {
|
||||
out.List[i].ReadProgress = 0 // 未读
|
||||
out.List[i].ReadAt = nil
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// AppDetail retrieves chapter detail for app
|
||||
func (s *sChapter) AppDetail(ctx context.Context, in *model.ChapterAppDetailIn) (out *model.ChapterAppDetailOut, err error) {
|
||||
out = &model.ChapterAppDetailOut{}
|
||||
|
||||
// 构建查询条件
|
||||
m := dao.Chapters.Ctx(ctx)
|
||||
|
||||
// 必须指定章节ID
|
||||
if in.Id == 0 {
|
||||
return nil, ecode.Fail.Sub("chapter_id_required")
|
||||
}
|
||||
m = m.Where(dao.Chapters.Columns().Id, in.Id)
|
||||
|
||||
// 执行查询
|
||||
if err = m.Scan(out); err != nil {
|
||||
return nil, ecode.Fail.Sub("chapter_query_failed")
|
||||
}
|
||||
|
||||
// 检查章节是否存在
|
||||
if out.Id == 0 {
|
||||
return nil, ecode.NotFound.Sub("chapter_not_found")
|
||||
}
|
||||
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// AppPurchase purchases chapter for app
|
||||
func (s *sChapter) AppPurchase(ctx context.Context, in *model.ChapterAppPurchaseIn) (out *model.ChapterAppPurchaseOut, err error) {
|
||||
out = &model.ChapterAppPurchaseOut{}
|
||||
|
||||
// 必须指定章节ID
|
||||
if in.Id == 0 {
|
||||
return nil, ecode.Fail.Sub("chapter_id_required")
|
||||
}
|
||||
|
||||
// 必须指定用户ID
|
||||
if in.UserId == 0 {
|
||||
return nil, ecode.Fail.Sub("user_id_required")
|
||||
}
|
||||
|
||||
// 查询章节信息
|
||||
chapter := &entity.Chapters{}
|
||||
err = dao.Chapters.Ctx(ctx).Where(dao.Chapters.Columns().Id, in.Id).Scan(chapter)
|
||||
if err != nil {
|
||||
return nil, ecode.Fail.Sub("chapter_query_failed")
|
||||
}
|
||||
|
||||
// 检查章节是否存在
|
||||
if chapter.Id == 0 {
|
||||
return nil, ecode.NotFound.Sub("chapter_not_found")
|
||||
}
|
||||
|
||||
// 检查章节是否锁定
|
||||
if chapter.IsLocked == 0 {
|
||||
// 章节免费,直接返回成功
|
||||
out.Success = true
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// 查询用户信息
|
||||
user := &entity.Users{}
|
||||
err = dao.Users.Ctx(ctx).Where(dao.Users.Columns().Id, in.UserId).Scan(user)
|
||||
if err != nil {
|
||||
return nil, ecode.Fail.Sub("user_query_failed")
|
||||
}
|
||||
|
||||
// 检查用户是否存在
|
||||
if user.Id == 0 {
|
||||
return nil, ecode.NotFound.Sub("user_not_found")
|
||||
}
|
||||
|
||||
// 检查用户积分是否足够
|
||||
if user.Points < uint64(chapter.RequiredScore) {
|
||||
return nil, ecode.Fail.Sub("insufficient_points")
|
||||
}
|
||||
|
||||
// 检查是否已经购买过该章节
|
||||
exist, err := dao.UserChapterPurchases.Ctx(ctx).
|
||||
Where(dao.UserChapterPurchases.Columns().UserId, in.UserId).
|
||||
Where(dao.UserChapterPurchases.Columns().ChapterId, in.Id).
|
||||
Exist()
|
||||
if err != nil {
|
||||
return nil, ecode.Fail.Sub("purchase_query_failed")
|
||||
}
|
||||
|
||||
if exist {
|
||||
// 已经购买过,直接返回成功
|
||||
out.Success = true
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// 开启事务处理
|
||||
if err := dao.UserChapterPurchases.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {
|
||||
// 扣除用户积分
|
||||
_, err := dao.Users.Ctx(ctx).TX(tx).Where(dao.Users.Columns().Id, in.UserId).Decrement(dao.Users.Columns().Points, chapter.RequiredScore)
|
||||
if err != nil {
|
||||
return ecode.Fail.Sub("score_deduction_failed")
|
||||
}
|
||||
|
||||
// 记录购买记录
|
||||
purchaseId, err := dao.UserChapterPurchases.Ctx(ctx).TX(tx).Data(do.UserChapterPurchases{
|
||||
UserId: in.UserId,
|
||||
ChapterId: in.Id,
|
||||
BookId: chapter.BookId,
|
||||
PointsUsed: chapter.RequiredScore,
|
||||
PurchaseTime: gtime.Now(),
|
||||
}).InsertAndGetId()
|
||||
if err != nil {
|
||||
return ecode.Fail.Sub("purchase_record_failed")
|
||||
}
|
||||
|
||||
// 记录用户积分日志
|
||||
_, err = dao.UserPointsLogs.Ctx(ctx).TX(tx).Data(do.UserPointsLogs{
|
||||
UserId: in.UserId,
|
||||
ChangeType: 1, // 消费
|
||||
PointsChange: -chapter.RequiredScore,
|
||||
RelatedOrderId: purchaseId,
|
||||
Description: "购买章节:" + chapter.Title,
|
||||
CreatedAt: gtime.Now(),
|
||||
}).Insert()
|
||||
if err != nil {
|
||||
return ecode.Fail.Sub("point_log_failed")
|
||||
}
|
||||
|
||||
return nil
|
||||
}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
out.Success = true
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// AppProgress uploads reading progress for app
|
||||
func (s *sChapter) AppProgress(ctx context.Context, in *model.ChapterAppProgressIn) (out *model.ChapterAppProgressOut, err error) {
|
||||
out = &model.ChapterAppProgressOut{}
|
||||
|
||||
// 必须指定用户ID
|
||||
if in.UserId == 0 {
|
||||
return nil, ecode.Fail.Sub("user_id_required")
|
||||
}
|
||||
|
||||
// 必须指定书籍ID
|
||||
if in.BookId == 0 {
|
||||
return nil, ecode.Fail.Sub("book_id_required")
|
||||
}
|
||||
|
||||
// 必须指定章节ID
|
||||
if in.ChapterId == 0 {
|
||||
return nil, ecode.Fail.Sub("chapter_id_required")
|
||||
}
|
||||
|
||||
// 验证进度范围
|
||||
if in.Progress < 0 || in.Progress > 100 {
|
||||
return nil, ecode.Fail.Sub("progress_invalid")
|
||||
}
|
||||
|
||||
// 检查章节是否存在
|
||||
exist, err := dao.Chapters.Ctx(ctx).Where(dao.Chapters.Columns().Id, in.ChapterId).Exist()
|
||||
if err != nil {
|
||||
return nil, ecode.Fail.Sub("chapter_query_failed")
|
||||
}
|
||||
if !exist {
|
||||
return nil, ecode.NotFound.Sub("chapter_not_found")
|
||||
}
|
||||
|
||||
// 检查用户是否存在
|
||||
exist, err = dao.Users.Ctx(ctx).Where(dao.Users.Columns().Id, in.UserId).Exist()
|
||||
if err != nil {
|
||||
return nil, ecode.Fail.Sub("user_query_failed")
|
||||
}
|
||||
if !exist {
|
||||
return nil, ecode.NotFound.Sub("user_not_found")
|
||||
}
|
||||
|
||||
// 开启事务处理
|
||||
if err := dao.UserReadRecords.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {
|
||||
// 1. 更新或创建阅读记录
|
||||
exist, err := dao.UserReadRecords.Ctx(ctx).TX(tx).
|
||||
Where(dao.UserReadRecords.Columns().UserId, in.UserId).
|
||||
Where(dao.UserReadRecords.Columns().BookId, in.BookId).
|
||||
Where(dao.UserReadRecords.Columns().ChapterId, in.ChapterId).
|
||||
Exist()
|
||||
if err != nil {
|
||||
return ecode.Fail.Sub("read_record_query_failed")
|
||||
}
|
||||
|
||||
if exist {
|
||||
// 更新现有记录
|
||||
_, err = dao.UserReadRecords.Ctx(ctx).TX(tx).
|
||||
Where(dao.UserReadRecords.Columns().UserId, in.UserId).
|
||||
Where(dao.UserReadRecords.Columns().BookId, in.BookId).
|
||||
Where(dao.UserReadRecords.Columns().ChapterId, in.ChapterId).
|
||||
Data(do.UserReadRecords{
|
||||
Progress: in.Progress,
|
||||
ReadAt: gtime.Now(),
|
||||
}).Update()
|
||||
if err != nil {
|
||||
return ecode.Fail.Sub("read_record_update_failed")
|
||||
}
|
||||
} else {
|
||||
// 创建新记录
|
||||
_, err = dao.UserReadRecords.Ctx(ctx).TX(tx).Data(do.UserReadRecords{
|
||||
UserId: in.UserId,
|
||||
BookId: in.BookId,
|
||||
ChapterId: in.ChapterId,
|
||||
Progress: in.Progress,
|
||||
ReadAt: gtime.Now(),
|
||||
}).Insert()
|
||||
if err != nil {
|
||||
return ecode.Fail.Sub("read_record_create_failed")
|
||||
}
|
||||
}
|
||||
|
||||
// 2. 更新或创建历史记录
|
||||
exist, err = dao.UserReadHistory.Ctx(ctx).TX(tx).
|
||||
Where(dao.UserReadHistory.Columns().UserId, in.UserId).
|
||||
Where(dao.UserReadHistory.Columns().BookId, in.BookId).
|
||||
Exist()
|
||||
if err != nil {
|
||||
return ecode.Fail.Sub("history_query_failed")
|
||||
}
|
||||
|
||||
if exist {
|
||||
// 更新现有历史记录
|
||||
_, err = dao.UserReadHistory.Ctx(ctx).TX(tx).
|
||||
Where(dao.UserReadHistory.Columns().UserId, in.UserId).
|
||||
Where(dao.UserReadHistory.Columns().BookId, in.BookId).
|
||||
Data(do.UserReadHistory{
|
||||
ChapterId: in.ChapterId,
|
||||
ReadAt: gtime.Now(),
|
||||
}).Update()
|
||||
if err != nil {
|
||||
return ecode.Fail.Sub("history_update_failed")
|
||||
}
|
||||
} else {
|
||||
// 创建新历史记录
|
||||
_, err = dao.UserReadHistory.Ctx(ctx).TX(tx).Data(do.UserReadHistory{
|
||||
UserId: in.UserId,
|
||||
BookId: in.BookId,
|
||||
ChapterId: in.ChapterId,
|
||||
ReadAt: gtime.Now(),
|
||||
}).Insert()
|
||||
if err != nil {
|
||||
return ecode.Fail.Sub("history_create_failed")
|
||||
}
|
||||
}
|
||||
|
||||
// 3. 更新书架记录(如果存在)
|
||||
exist, err = dao.Bookshelves.Ctx(ctx).TX(tx).
|
||||
Where(dao.Bookshelves.Columns().UserId, in.UserId).
|
||||
Where(dao.Bookshelves.Columns().BookId, in.BookId).
|
||||
Exist()
|
||||
if err != nil {
|
||||
return ecode.Fail.Sub("bookshelf_query_failed")
|
||||
}
|
||||
|
||||
if exist {
|
||||
// 计算阅读进度百分比
|
||||
totalChapters, err := dao.Chapters.Ctx(ctx).TX(tx).
|
||||
Where(dao.Chapters.Columns().BookId, in.BookId).
|
||||
Count()
|
||||
if err != nil {
|
||||
return ecode.Fail.Sub("chapter_count_failed")
|
||||
}
|
||||
|
||||
var readChapters int
|
||||
if totalChapters > 0 {
|
||||
readChapters, err = dao.UserReadRecords.Ctx(ctx).TX(tx).
|
||||
Where(dao.UserReadRecords.Columns().UserId, in.UserId).
|
||||
Where(dao.UserReadRecords.Columns().BookId, in.BookId).
|
||||
Where(dao.UserReadRecords.Columns().ChapterId, ">", 0).
|
||||
Count()
|
||||
if err != nil {
|
||||
return ecode.Fail.Sub("read_chapter_count_failed")
|
||||
}
|
||||
}
|
||||
|
||||
readPercent := 0.0
|
||||
if totalChapters > 0 {
|
||||
readPercent = float64(readChapters) / float64(totalChapters) * 100
|
||||
if readPercent > 100 {
|
||||
readPercent = 100
|
||||
}
|
||||
}
|
||||
|
||||
// 判断是否为最后一章
|
||||
lastChapter, err := dao.Chapters.Ctx(ctx).TX(tx).
|
||||
Where(dao.Chapters.Columns().BookId, in.BookId).
|
||||
OrderDesc(dao.Chapters.Columns().Sort).
|
||||
One()
|
||||
if err != nil {
|
||||
return ecode.Fail.Sub("chapter_query_failed")
|
||||
}
|
||||
|
||||
readStatus := 1 // 默认为正在读
|
||||
if lastChapter != nil && lastChapter["id"].Int64() == in.ChapterId {
|
||||
readStatus = 2 // 如果是最后一章,标记为已读完
|
||||
}
|
||||
|
||||
// 更新书架记录
|
||||
_, err = dao.Bookshelves.Ctx(ctx).TX(tx).
|
||||
Where(dao.Bookshelves.Columns().UserId, in.UserId).
|
||||
Where(dao.Bookshelves.Columns().BookId, in.BookId).
|
||||
Data(do.Bookshelves{
|
||||
LastReadChapterId: in.ChapterId,
|
||||
LastReadPercent: readPercent,
|
||||
LastReadAt: gtime.Now(),
|
||||
ReadStatus: readStatus,
|
||||
}).Update()
|
||||
if err != nil {
|
||||
return ecode.Fail.Sub("bookshelf_update_failed")
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
out.Success = true
|
||||
return out, nil
|
||||
}
|
||||
|
||||
@ -28,7 +28,7 @@ func (s *sFeedback) List(ctx context.Context, in *model.FeedbackListIn) (out *mo
|
||||
if in.Status != 0 {
|
||||
m = m.Where(dao.Feedbacks.Columns().Status, in.Status)
|
||||
}
|
||||
if err = m.Page(in.Page, in.Size).ScanAndCount(&out.List, &out.Total, false); err != nil {
|
||||
if err = m.Page(in.Page, in.Size).WithAll().ScanAndCount(&out.List, &out.Total, false); err != nil {
|
||||
return
|
||||
}
|
||||
return
|
||||
|
||||
@ -6,11 +6,13 @@ package logic
|
||||
|
||||
import (
|
||||
_ "server/internal/logic/admin"
|
||||
_ "server/internal/logic/author"
|
||||
_ "server/internal/logic/book"
|
||||
_ "server/internal/logic/bookshelve"
|
||||
_ "server/internal/logic/category"
|
||||
_ "server/internal/logic/chapter"
|
||||
_ "server/internal/logic/feedback"
|
||||
_ "server/internal/logic/read_record"
|
||||
_ "server/internal/logic/tag"
|
||||
_ "server/internal/logic/user"
|
||||
_ "server/internal/logic/user_follow_author"
|
||||
_ "server/internal/logic/user_read_record"
|
||||
)
|
||||
|
||||
@ -1,68 +0,0 @@
|
||||
package read_record
|
||||
|
||||
import (
|
||||
"context"
|
||||
"server/internal/dao"
|
||||
"server/internal/model"
|
||||
"server/internal/model/do"
|
||||
"server/internal/service"
|
||||
"server/utility/ecode"
|
||||
)
|
||||
|
||||
type sReadRecord struct{}
|
||||
|
||||
func New() service.IReadRecord {
|
||||
return &sReadRecord{}
|
||||
}
|
||||
func init() {
|
||||
service.RegisterReadRecord(New())
|
||||
}
|
||||
|
||||
// List retrieves a paginated list of read records
|
||||
func (s *sReadRecord) List(ctx context.Context, in *model.ReadRecordListIn) (out *model.ReadRecordListOut, err error) {
|
||||
out = &model.ReadRecordListOut{}
|
||||
m := dao.ReadRecords.Ctx(ctx)
|
||||
if in.UserId != 0 {
|
||||
m = m.Where(dao.ReadRecords.Columns().UserId, in.UserId)
|
||||
}
|
||||
if in.BookId != 0 {
|
||||
m = m.Where(dao.ReadRecords.Columns().BookId, in.BookId)
|
||||
}
|
||||
if in.ChapterId != 0 {
|
||||
m = m.Where(dao.ReadRecords.Columns().ChapterId, in.ChapterId)
|
||||
}
|
||||
if err = m.Page(in.Page, in.Size).ScanAndCount(&out.List, &out.Total, false); err != nil {
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Create adds a new read record
|
||||
func (s *sReadRecord) Create(ctx context.Context, in *model.ReadRecordAddIn) (out *model.ReadRecordCRUDOut, err error) {
|
||||
if _, err := dao.ReadRecords.Ctx(ctx).Data(do.ReadRecords{
|
||||
UserId: in.UserId,
|
||||
BookId: in.BookId,
|
||||
ChapterId: in.ChapterId,
|
||||
}).Insert(); err != nil {
|
||||
return nil, ecode.Fail.Sub("read_record_create_failed")
|
||||
}
|
||||
return &model.ReadRecordCRUDOut{Success: true}, nil
|
||||
}
|
||||
|
||||
// Delete removes a read record by id
|
||||
func (s *sReadRecord) Delete(ctx context.Context, in *model.ReadRecordDelIn) (out *model.ReadRecordCRUDOut, err error) {
|
||||
exist, err := dao.ReadRecords.Ctx(ctx).
|
||||
WherePri(in.Id).
|
||||
Exist()
|
||||
if err != nil {
|
||||
return nil, ecode.Fail.Sub("read_record_query_failed")
|
||||
}
|
||||
if !exist {
|
||||
return nil, ecode.NotFound.Sub("read_record_not_found")
|
||||
}
|
||||
_, err = dao.ReadRecords.Ctx(ctx).WherePri(in.Id).Delete()
|
||||
if err != nil {
|
||||
return nil, ecode.Fail.Sub("read_record_delete_failed")
|
||||
}
|
||||
return &model.ReadRecordCRUDOut{Success: true}, nil
|
||||
}
|
||||
@ -1,119 +0,0 @@
|
||||
package tag
|
||||
|
||||
import (
|
||||
"context"
|
||||
"server/internal/dao"
|
||||
"server/internal/model"
|
||||
"server/internal/model/do"
|
||||
"server/internal/service"
|
||||
"server/utility/ecode"
|
||||
)
|
||||
|
||||
type sTag struct{}
|
||||
|
||||
func New() service.ITag {
|
||||
return &sTag{}
|
||||
}
|
||||
|
||||
func init() {
|
||||
service.RegisterTag(New())
|
||||
}
|
||||
|
||||
// List retrieves a paginated list of tags
|
||||
func (s *sTag) List(ctx context.Context, in *model.TagListIn) (out *model.TagListOut, err error) {
|
||||
out = &model.TagListOut{}
|
||||
m := dao.Tags.Ctx(ctx)
|
||||
if in.Name != "" {
|
||||
m = m.Where(dao.Tags.Columns().Name+" like ?", "%"+in.Name+"%")
|
||||
}
|
||||
if in.Type != 0 {
|
||||
m = m.Where(dao.Tags.Columns().Type, in.Type)
|
||||
}
|
||||
if err = m.Page(in.Page, in.Size).ScanAndCount(&out.List, &out.Total, false); err != nil {
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (s *sTag) Create(ctx context.Context, in *model.TagAddIn) (out *model.TagCRUDOut, err error) {
|
||||
exist, err := dao.Tags.Ctx(ctx).
|
||||
Where(dao.Tags.Columns().Name, in.Name).
|
||||
Where(dao.Tags.Columns().Type, in.Type).
|
||||
Exist()
|
||||
if err != nil {
|
||||
return nil, ecode.Fail.Sub("tag_query_failed")
|
||||
}
|
||||
if exist {
|
||||
return nil, ecode.Params.Sub("tag_exists")
|
||||
}
|
||||
|
||||
if _, err := dao.Tags.Ctx(ctx).Data(do.Tags{
|
||||
Name: in.Name,
|
||||
Type: in.Type,
|
||||
}).Insert(); err != nil {
|
||||
return nil, ecode.Fail.Sub("tag_create_failed")
|
||||
}
|
||||
|
||||
return &model.TagCRUDOut{
|
||||
Success: true,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *sTag) Update(ctx context.Context, in *model.TagEditIn) (out *model.TagCRUDOut, err error) {
|
||||
exist, err := dao.Tags.Ctx(ctx).
|
||||
WherePri(in.Id).
|
||||
Exist()
|
||||
if err != nil {
|
||||
return nil, ecode.Fail.Sub("tag_query_failed")
|
||||
}
|
||||
if !exist {
|
||||
return nil, ecode.NotFound.Sub("tag_not_found")
|
||||
}
|
||||
|
||||
exist, err = dao.Tags.Ctx(ctx).
|
||||
Where(dao.Tags.Columns().Name, in.Name).
|
||||
Where(dao.Tags.Columns().Type, in.Type).
|
||||
Where("id != ?", in.Id).
|
||||
Exist()
|
||||
if err != nil {
|
||||
return nil, ecode.Fail.Sub("tag_query_failed")
|
||||
}
|
||||
if exist {
|
||||
return nil, ecode.Params.Sub("tag_exists")
|
||||
}
|
||||
|
||||
_, err = dao.Tags.Ctx(ctx).
|
||||
WherePri(in.Id).
|
||||
Data(do.Tags{
|
||||
Name: in.Name,
|
||||
Type: in.Type,
|
||||
}).Update()
|
||||
if err != nil {
|
||||
return nil, ecode.Fail.Sub("tag_update_failed")
|
||||
}
|
||||
|
||||
return &model.TagCRUDOut{
|
||||
Success: true,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *sTag) Delete(ctx context.Context, in *model.TagDelIn) (out *model.TagCRUDOut, err error) {
|
||||
exist, err := dao.Tags.Ctx(ctx).
|
||||
WherePri(in.Id).
|
||||
Exist()
|
||||
if err != nil {
|
||||
return nil, ecode.Fail.Sub("tag_query_failed")
|
||||
}
|
||||
if !exist {
|
||||
return nil, ecode.NotFound.Sub("tag_not_found")
|
||||
}
|
||||
|
||||
_, err = dao.Tags.Ctx(ctx).WherePri(in.Id).Delete()
|
||||
if err != nil {
|
||||
return nil, ecode.Fail.Sub("tag_delete_failed")
|
||||
}
|
||||
|
||||
return &model.TagCRUDOut{
|
||||
Success: true,
|
||||
}, nil
|
||||
}
|
||||
@ -11,6 +11,8 @@ import (
|
||||
"server/utility/encrypt"
|
||||
"server/utility/jwt"
|
||||
"strings"
|
||||
|
||||
"github.com/gogf/gf/v2/database/gdb"
|
||||
)
|
||||
|
||||
type sUser struct{}
|
||||
@ -37,7 +39,13 @@ func (s *sUser) Login(ctx context.Context, in *model.UserLoginIn) (out *model.Us
|
||||
if !encrypt.ComparePassword(entityUser.PasswordHash, in.Password) {
|
||||
return nil, ecode.Password // 密码不正确
|
||||
}
|
||||
token, err := jwt.GenerateToken(&jwt.TokenIn{UserId: entityUser.Id, Role: "user"})
|
||||
// 判断是否为作者
|
||||
author, _ := dao.Authors.Ctx(ctx).Where(do.Authors{UserId: entityUser.Id, Status: 1}).One()
|
||||
role := "user"
|
||||
if author != nil && !author.IsEmpty() {
|
||||
role = "author"
|
||||
}
|
||||
token, err := jwt.GenerateToken(&jwt.TokenIn{UserId: entityUser.Id, Role: role})
|
||||
if err != nil {
|
||||
return nil, ecode.Fail.Sub("token_generation_failed")
|
||||
}
|
||||
@ -92,7 +100,111 @@ func (s *sUser) Info(ctx context.Context, in *model.UserInfoIn) (out *model.User
|
||||
}
|
||||
|
||||
func (s *sUser) Delete(ctx context.Context, in *model.UserDeleteIn) (out *model.UserDeleteOut, err error) {
|
||||
// FIXME
|
||||
// 查询用户信息
|
||||
user, err := dao.Users.Ctx(ctx).Where(do.Users{Id: in.UserId}).One()
|
||||
if err != nil {
|
||||
return nil, ecode.Fail.Sub("database_query_failed")
|
||||
}
|
||||
if user == nil {
|
||||
return nil, ecode.Auth.Sub("user_not_found")
|
||||
}
|
||||
|
||||
var entityUser entity.Users
|
||||
if err = user.Struct(&entityUser); err != nil {
|
||||
return nil, ecode.Fail.Sub("data_conversion_failed")
|
||||
}
|
||||
|
||||
// 验证密码
|
||||
if !encrypt.ComparePassword(entityUser.PasswordHash, in.Password) {
|
||||
return nil, ecode.Password.Sub("password_incorrect")
|
||||
}
|
||||
|
||||
// 开启事务,删除用户及相关数据
|
||||
err = dao.Users.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {
|
||||
// 1. 删除用户阅读记录
|
||||
_, err := dao.UserReadRecords.Ctx(ctx).TX(tx).
|
||||
Where(dao.UserReadRecords.Columns().UserId, in.UserId).
|
||||
Delete()
|
||||
if err != nil {
|
||||
return ecode.Fail.Sub("read_record_delete_failed")
|
||||
}
|
||||
|
||||
// 2. 删除用户阅读历史
|
||||
_, err = dao.UserReadHistory.Ctx(ctx).TX(tx).
|
||||
Where(dao.UserReadHistory.Columns().UserId, in.UserId).
|
||||
Delete()
|
||||
if err != nil {
|
||||
return ecode.Fail.Sub("history_delete_failed")
|
||||
}
|
||||
|
||||
// 3. 删除用户书架
|
||||
_, err = dao.Bookshelves.Ctx(ctx).TX(tx).
|
||||
Where(dao.Bookshelves.Columns().UserId, in.UserId).
|
||||
Delete()
|
||||
if err != nil {
|
||||
return ecode.Fail.Sub("bookshelf_delete_failed")
|
||||
}
|
||||
|
||||
// 4. 删除用户关注作者记录
|
||||
_, err = dao.UserFollowAuthors.Ctx(ctx).TX(tx).
|
||||
Where(dao.UserFollowAuthors.Columns().UserId, in.UserId).
|
||||
Delete()
|
||||
if err != nil {
|
||||
return ecode.Fail.Sub("follow_author_delete_failed")
|
||||
}
|
||||
|
||||
// 5. 删除用户评分记录
|
||||
_, err = dao.BookRatings.Ctx(ctx).TX(tx).
|
||||
Where(dao.BookRatings.Columns().UserId, in.UserId).
|
||||
Delete()
|
||||
if err != nil {
|
||||
return ecode.Fail.Sub("rating_delete_failed")
|
||||
}
|
||||
|
||||
// 6. 删除用户章节购买记录
|
||||
_, err = dao.UserChapterPurchases.Ctx(ctx).TX(tx).
|
||||
Where(dao.UserChapterPurchases.Columns().UserId, in.UserId).
|
||||
Delete()
|
||||
if err != nil {
|
||||
return ecode.Fail.Sub("purchase_delete_failed")
|
||||
}
|
||||
|
||||
// 7. 删除用户积分日志
|
||||
_, err = dao.UserPointsLogs.Ctx(ctx).TX(tx).
|
||||
Where(dao.UserPointsLogs.Columns().UserId, in.UserId).
|
||||
Delete()
|
||||
if err != nil {
|
||||
return ecode.Fail.Sub("points_log_delete_failed")
|
||||
}
|
||||
|
||||
// 8. 删除用户反馈
|
||||
_, err = dao.Feedbacks.Ctx(ctx).TX(tx).
|
||||
Where(dao.Feedbacks.Columns().UserId, in.UserId).
|
||||
Delete()
|
||||
if err != nil {
|
||||
return ecode.Fail.Sub("feedback_delete_failed")
|
||||
}
|
||||
|
||||
// 9. 删除作者信息(如果用户是作者)
|
||||
_, err = dao.Authors.Ctx(ctx).TX(tx).
|
||||
Where(dao.Authors.Columns().UserId, in.UserId).
|
||||
Delete()
|
||||
if err != nil {
|
||||
return ecode.Fail.Sub("author_delete_failed")
|
||||
}
|
||||
|
||||
// 10. 最后删除用户(软删除)
|
||||
_, err = dao.Users.Ctx(ctx).TX(tx).Where(do.Users{Id: in.UserId}).Delete()
|
||||
if err != nil {
|
||||
return ecode.Fail.Sub("user_delete_failed")
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &model.UserDeleteOut{Success: true}, nil
|
||||
}
|
||||
|
||||
@ -5,11 +5,19 @@ import (
|
||||
"server/internal/dao"
|
||||
"server/internal/model"
|
||||
"server/internal/model/do"
|
||||
"server/internal/service"
|
||||
"server/utility/ecode"
|
||||
)
|
||||
|
||||
type sUserFollowAuthor struct{}
|
||||
|
||||
func New() service.IUserFollowAuthor {
|
||||
return &sUserFollowAuthor{}
|
||||
}
|
||||
func init() {
|
||||
service.RegisterUserFollowAuthor(New())
|
||||
}
|
||||
|
||||
// List retrieves a paginated list of user follow authors
|
||||
func (s *sUserFollowAuthor) List(ctx context.Context, in *model.UserFollowAuthorListIn) (out *model.UserFollowAuthorListOut, err error) {
|
||||
out = &model.UserFollowAuthorListOut{}
|
||||
@ -64,3 +72,27 @@ func (s *sUserFollowAuthor) Delete(ctx context.Context, in *model.UserFollowAuth
|
||||
}
|
||||
return &model.UserFollowAuthorCRUDOut{Success: true}, nil
|
||||
}
|
||||
|
||||
// Unfollow removes a user follow author by userId and authorId
|
||||
func (s *sUserFollowAuthor) Unfollow(ctx context.Context, userId int64, authorId int64) (out *model.UserFollowAuthorCRUDOut, err error) {
|
||||
if userId == 0 || authorId == 0 {
|
||||
return nil, ecode.Params.Sub("user_id_or_author_id_invalid")
|
||||
}
|
||||
// 查找关注记录
|
||||
var record struct{ Id int64 }
|
||||
err = dao.UserFollowAuthors.Ctx(ctx).
|
||||
Where(dao.UserFollowAuthors.Columns().UserId, userId).
|
||||
Where(dao.UserFollowAuthors.Columns().AuthorId, authorId).
|
||||
Fields("id").Scan(&record)
|
||||
if err != nil {
|
||||
return nil, ecode.Fail.Sub("user_follow_author_query_failed")
|
||||
}
|
||||
if record.Id == 0 {
|
||||
return nil, ecode.NotFound.Sub("user_follow_author_not_found")
|
||||
}
|
||||
_, err = dao.UserFollowAuthors.Ctx(ctx).WherePri(record.Id).Delete()
|
||||
if err != nil {
|
||||
return nil, ecode.Fail.Sub("user_follow_author_delete_failed")
|
||||
}
|
||||
return &model.UserFollowAuthorCRUDOut{Success: true}, nil
|
||||
}
|
||||
|
||||
97
internal/logic/user_read_record/user_read_record.go
Normal file
97
internal/logic/user_read_record/user_read_record.go
Normal file
@ -0,0 +1,97 @@
|
||||
package user_read_record
|
||||
|
||||
import (
|
||||
"context"
|
||||
"server/internal/dao"
|
||||
"server/internal/model"
|
||||
"server/internal/model/do"
|
||||
"server/internal/service"
|
||||
"server/utility/ecode"
|
||||
|
||||
"github.com/gogf/gf/v2/os/gtime"
|
||||
)
|
||||
|
||||
type sUserReadRecord struct{}
|
||||
|
||||
func New() service.IUserReadRecord {
|
||||
return &sUserReadRecord{}
|
||||
}
|
||||
func init() {
|
||||
service.RegisterUserReadRecord(New())
|
||||
}
|
||||
|
||||
// List retrieves a paginated list of user read records
|
||||
func (s *sUserReadRecord) List(ctx context.Context, in *model.UserReadRecordListIn) (out *model.UserReadRecordListOut, err error) {
|
||||
out = &model.UserReadRecordListOut{}
|
||||
m := dao.UserReadRecords.Ctx(ctx)
|
||||
if in.UserId != 0 {
|
||||
m = m.Where(dao.UserReadRecords.Columns().UserId, in.UserId)
|
||||
}
|
||||
if in.BookId != 0 {
|
||||
m = m.Where(dao.UserReadRecords.Columns().BookId, in.BookId)
|
||||
}
|
||||
if in.ChapterId != 0 {
|
||||
m = m.Where(dao.UserReadRecords.Columns().ChapterId, in.ChapterId)
|
||||
}
|
||||
if err = m.Page(in.Page, in.Size).ScanAndCount(&out.List, &out.Total, false); err != nil {
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Create adds a new user read record
|
||||
func (s *sUserReadRecord) Create(ctx context.Context, in *model.UserReadRecordAddIn) (out *model.UserReadRecordCRUDOut, err error) {
|
||||
// 检查是否已存在相同的阅读记录
|
||||
exist, err := dao.UserReadRecords.Ctx(ctx).
|
||||
Where(dao.UserReadRecords.Columns().UserId, in.UserId).
|
||||
Where(dao.UserReadRecords.Columns().BookId, in.BookId).
|
||||
Where(dao.UserReadRecords.Columns().ChapterId, in.ChapterId).
|
||||
Exist()
|
||||
|
||||
if err != nil {
|
||||
return nil, ecode.Fail.Sub("read_record_query_failed")
|
||||
}
|
||||
|
||||
if exist {
|
||||
// 如果记录已存在,更新进度和时间
|
||||
_, err = dao.UserReadRecords.Ctx(ctx).
|
||||
Where(dao.UserReadRecords.Columns().UserId, in.UserId).
|
||||
Where(dao.UserReadRecords.Columns().BookId, in.BookId).
|
||||
Where(dao.UserReadRecords.Columns().ChapterId, in.ChapterId).
|
||||
Data(do.UserReadRecords{
|
||||
Progress: in.Progress,
|
||||
ReadAt: gtime.Now(),
|
||||
}).Update()
|
||||
} else {
|
||||
// 创建新记录
|
||||
_, err = dao.UserReadRecords.Ctx(ctx).Data(do.UserReadRecords{
|
||||
UserId: in.UserId,
|
||||
BookId: in.BookId,
|
||||
ChapterId: in.ChapterId,
|
||||
Progress: in.Progress,
|
||||
ReadAt: gtime.Now(),
|
||||
}).Insert()
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, ecode.Fail.Sub("read_record_create_failed")
|
||||
}
|
||||
return &model.UserReadRecordCRUDOut{Success: true}, nil
|
||||
}
|
||||
|
||||
// Delete removes user read records by userId and bookIds
|
||||
func (s *sUserReadRecord) Delete(ctx context.Context, in *model.UserReadRecordDelIn) (out *model.UserReadRecordCRUDOut, err error) {
|
||||
if len(in.BookIds) == 0 {
|
||||
return nil, ecode.Params.Sub("bookshelve_bookids_empty")
|
||||
}
|
||||
|
||||
// 批量删除指定用户的指定书籍历史记录
|
||||
_, err = dao.UserReadRecords.Ctx(ctx).
|
||||
Where(dao.UserReadRecords.Columns().UserId, in.UserId).
|
||||
WhereIn(dao.UserReadRecords.Columns().BookId, in.BookIds).
|
||||
Delete()
|
||||
if err != nil {
|
||||
return nil, ecode.Fail.Sub("read_record_delete_failed")
|
||||
}
|
||||
return &model.UserReadRecordCRUDOut{Success: true}, nil
|
||||
}
|
||||
60
internal/model/author.go
Normal file
60
internal/model/author.go
Normal file
@ -0,0 +1,60 @@
|
||||
package model
|
||||
|
||||
import "github.com/gogf/gf/v2/frame/g"
|
||||
|
||||
type Author struct {
|
||||
g.Meta `orm:"table:authors"`
|
||||
Id int64 `json:"id" orm:"id"`
|
||||
UserId int64 `json:"userId" orm:"user_id"`
|
||||
PenName string `json:"penName" orm:"pen_name"`
|
||||
Bio string `json:"bio" orm:"bio"`
|
||||
}
|
||||
|
||||
type AuthorListIn struct {
|
||||
Page int
|
||||
Size int
|
||||
PenName string
|
||||
Status int
|
||||
}
|
||||
type AuthorListOut struct {
|
||||
Total int
|
||||
List []Author
|
||||
}
|
||||
|
||||
type AuthorAddIn struct {
|
||||
UserId int64
|
||||
PenName string
|
||||
Bio string
|
||||
Status int
|
||||
}
|
||||
type AuthorEditIn struct {
|
||||
Id int64
|
||||
PenName string
|
||||
Bio string
|
||||
Status int
|
||||
}
|
||||
type AuthorDelIn struct {
|
||||
Id int64
|
||||
}
|
||||
type AuthorCRUDOut struct {
|
||||
Success bool
|
||||
}
|
||||
|
||||
type AuthorApplyIn struct {
|
||||
PenName string // 笔名
|
||||
Bio string // 作者简介
|
||||
}
|
||||
type AuthorApplyOut struct {
|
||||
Success bool
|
||||
}
|
||||
type AuthorDetailIn struct {
|
||||
AuthorId int64
|
||||
}
|
||||
type AuthorDetailOut struct {
|
||||
g.Meta `orm:"table:authors"`
|
||||
Id int64 `json:"id" orm:"id"`
|
||||
UserId int64 `json:"userId" orm:"user_id"`
|
||||
PenName string `json:"penName" orm:"pen_name"`
|
||||
Bio string `json:"bio" orm:"bio"`
|
||||
User User `json:"user" orm:"with:id = user_id"`
|
||||
}
|
||||
@ -1,23 +1,41 @@
|
||||
package model
|
||||
|
||||
import "github.com/gogf/gf/v2/frame/g"
|
||||
import (
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/os/gtime"
|
||||
)
|
||||
|
||||
type Book struct {
|
||||
g.Meta `orm:"table:books"`
|
||||
Id int64 `json:"id"`
|
||||
AuthorId int64 `json:"authorId"`
|
||||
CategoryId int64 `json:"categoryId"`
|
||||
Title string `json:"title"`
|
||||
CoverUrl string `json:"coverUrl"`
|
||||
Description string `json:"description"`
|
||||
Status int `json:"status"`
|
||||
WordsCount int `json:"wordsCount"`
|
||||
ChaptersCount int `json:"chaptersCount"`
|
||||
LatestChapterId int64 `json:"latestChapterId"`
|
||||
Rating float64 `json:"rating"`
|
||||
ReadCount int64 `json:"readCount"`
|
||||
Tags string `json:"tags"`
|
||||
IsRecommended int `json:"isRecommended"`
|
||||
Id int64 `json:"id" orm:"id"`
|
||||
AuthorId int64 `json:"authorId" orm:"author_id"`
|
||||
Author Author `json:"author" orm:"with:id = author_id"`
|
||||
CategoryId int64 `json:"categoryId" orm:"category_id"`
|
||||
Category Category `json:"category" orm:"with:id = category_id"`
|
||||
Title string `json:"title" orm:"title"`
|
||||
CoverUrl string `json:"coverUrl" orm:"cover_url"`
|
||||
Description string `json:"description" orm:"description"`
|
||||
Status int `json:"status" orm:"status"`
|
||||
WordsCount int `json:"wordsCount" orm:"words_count"`
|
||||
ChaptersCount int `json:"chaptersCount" orm:"chapters_count"`
|
||||
LatestChapterId int64 `json:"latestChapterId" orm:"latest_chapter_id"`
|
||||
Rating float64 `json:"rating" orm:"rating"`
|
||||
ReadCount int64 `json:"readCount" orm:"read_count"`
|
||||
CurrentReaders int64 `json:"currentReaders" orm:"current_readers"`
|
||||
Tags string `json:"tags" orm:"tags"`
|
||||
IsRecommended int `json:"isRecommended" orm:"is_recommended"`
|
||||
IsFeatured int `json:"isFeatured" orm:"is_featured"`
|
||||
Language string `json:"language" orm:"language"`
|
||||
}
|
||||
|
||||
// App作者信息结构体
|
||||
type AppAuthor struct {
|
||||
g.Meta `orm:"table:authors"`
|
||||
Id int64 `json:"id" orm:"id"`
|
||||
UserId int64 `json:"-" orm:"user_id"`
|
||||
PenName string `json:"penName" orm:"pen_name"`
|
||||
Bio string `json:"bio" orm:"bio"`
|
||||
Status int `json:"status" orm:"status"`
|
||||
}
|
||||
|
||||
type BookListIn struct {
|
||||
@ -28,6 +46,7 @@ type BookListIn struct {
|
||||
AuthorId int64
|
||||
Status int
|
||||
IsRecommended int
|
||||
Sort string
|
||||
}
|
||||
type BookListOut struct {
|
||||
Total int
|
||||
@ -43,6 +62,8 @@ type BookAddIn struct {
|
||||
Status int
|
||||
Tags string
|
||||
IsRecommended int
|
||||
IsFeatured int
|
||||
Language string
|
||||
}
|
||||
type BookEditIn struct {
|
||||
Id int64
|
||||
@ -54,6 +75,8 @@ type BookEditIn struct {
|
||||
Status int
|
||||
Tags string
|
||||
IsRecommended int
|
||||
IsFeatured int
|
||||
Language string
|
||||
}
|
||||
type BookDelIn struct {
|
||||
Id int64
|
||||
@ -62,3 +85,166 @@ type BookDelIn struct {
|
||||
type BookCRUDOut struct {
|
||||
Success bool
|
||||
}
|
||||
|
||||
type BookHistoryRemoveOut struct {
|
||||
Success bool `json:"success" dc:"是否成功"`
|
||||
}
|
||||
|
||||
// App 书籍列表项结构体
|
||||
type BookAppItem struct {
|
||||
g.Meta `orm:"table:books"`
|
||||
Id int64 `json:"id" dc:"书籍ID" orm:"id"`
|
||||
CoverUrl string `json:"coverUrl" dc:"封面图" orm:"cover_url"`
|
||||
Rating float64 `json:"rating" dc:"评分" orm:"rating"`
|
||||
Title string `json:"title" dc:"标题" orm:"title"`
|
||||
Description string `json:"description" dc:"简介" orm:"description"`
|
||||
AuthorId int64 `json:"authorId" dc:"作者ID" orm:"author_id"`
|
||||
Author AppAuthor `json:"author" dc:"作者信息" orm:"with:id = author_id"`
|
||||
IsFeatured int `json:"isFeatured" dc:"是否精选" orm:"is_featured"`
|
||||
Language string `json:"language" dc:"语言" orm:"language"`
|
||||
CategoryId int64 `json:"categoryId" dc:"分类ID" orm:"category_id"`
|
||||
Category Category `json:"category" dc:"分类信息" orm:"with:id = category_id"`
|
||||
Status int `json:"status" dc:"状态" orm:"status"`
|
||||
WordsCount int `json:"wordsCount" dc:"字数" orm:"words_count"`
|
||||
ChaptersCount int `json:"chaptersCount" dc:"章节数" orm:"chapters_count"`
|
||||
LatestChapterId int64 `json:"latestChapterId" dc:"最新章节ID" orm:"latest_chapter_id"`
|
||||
ReadCount int64 `json:"readCount" dc:"阅读人数" orm:"read_count"`
|
||||
CurrentReaders int64 `json:"currentReaders" dc:"在读人数" orm:"current_readers"`
|
||||
Tags string `json:"tags" dc:"标签" orm:"tags"`
|
||||
IsRecommended int `json:"isRecommended" dc:"是否推荐" orm:"is_recommended"`
|
||||
CreatedAt *gtime.Time `json:"createdAt" dc:"创建时间" orm:"created_at"`
|
||||
UpdatedAt *gtime.Time `json:"updatedAt" dc:"更新时间" orm:"updated_at"`
|
||||
HasRated bool `json:"hasRated" dc:"当前用户是否已评分"`
|
||||
MyRating float64 `json:"myRating" dc:"当前用户评分(未评分为0)"`
|
||||
}
|
||||
|
||||
// App 书籍列表查询输入参数
|
||||
type BookAppListIn struct {
|
||||
Page int `json:"page" dc:"页码"`
|
||||
Size int `json:"size" dc:"每页数量"`
|
||||
IsRecommended bool `json:"isRecommended" dc:"是否推荐"`
|
||||
IsLatest int `json:"isLatest" dc:"是否最新"`
|
||||
CategoryId int64 `json:"categoryId" dc:"分类ID"`
|
||||
Title string `json:"title" dc:"书名模糊搜索"`
|
||||
UserId int64 `json:"userId" dc:"用户ID"`
|
||||
AuthorId int `json:"authorId" dc:"作者ID"`
|
||||
IsFeatured bool `json:"isFeatured" dc:"是否精选"`
|
||||
Language string `json:"language" dc:"语言"`
|
||||
Sort string `json:"sort" dc:"排序字段"`
|
||||
}
|
||||
|
||||
// App 书籍列表输出结构体
|
||||
type BookAppListOut struct {
|
||||
Total int `json:"total" dc:"总数"`
|
||||
List []BookAppItem `json:"list" dc:"书籍列表"`
|
||||
}
|
||||
|
||||
// App 书籍详情查询输入参数
|
||||
type BookAppDetailIn struct {
|
||||
Id int64 `json:"id" dc:"书籍ID"`
|
||||
UserId int64 `json:"userId" dc:"用户ID"`
|
||||
}
|
||||
|
||||
// App 书籍详情输出结构体
|
||||
type BookAppDetailOut struct {
|
||||
Id int64 `json:"id" dc:"书籍ID"`
|
||||
AuthorId int64 `json:"authorId" dc:"作者ID"`
|
||||
CategoryId int64 `json:"categoryId" dc:"分类ID"`
|
||||
Title string `json:"title" dc:"书名"`
|
||||
CoverUrl string `json:"coverUrl" dc:"封面图"`
|
||||
Description string `json:"description" dc:"简介"`
|
||||
Status int `json:"status" dc:"状态"`
|
||||
Tags string `json:"tags" dc:"标签"`
|
||||
IsRecommended int `json:"isRecommended" dc:"是否推荐"`
|
||||
IsFeatured int `json:"isFeatured" dc:"是否精选"`
|
||||
Language string `json:"language" dc:"语言"`
|
||||
Rating float64 `json:"rating" dc:"评分"`
|
||||
CurrentReaders int64 `json:"currentReaders" dc:"在读人数"`
|
||||
CreatedAt *gtime.Time `json:"createdAt" dc:"创建时间"`
|
||||
UpdatedAt *gtime.Time `json:"updatedAt" dc:"更新时间"`
|
||||
HasRead bool `json:"hasRead" dc:"是否读过"`
|
||||
ReadProgress int `json:"readProgress" dc:"阅读进度百分比"`
|
||||
LastChapterId int64 `json:"lastChapterId" dc:"最近阅读章节ID"`
|
||||
LastReadAt string `json:"lastReadAt" dc:"最近阅读时间"`
|
||||
}
|
||||
|
||||
// App 用户评分输入参数
|
||||
type BookAppRateIn struct {
|
||||
BookId int64 `json:"bookId" dc:"书籍ID"`
|
||||
UserId int64 `json:"userId" dc:"用户ID"`
|
||||
Rating float64 `json:"rating" dc:"评分(1-10分)"`
|
||||
}
|
||||
|
||||
// App 用户评分输出结构体
|
||||
type BookAppRateOut struct {
|
||||
Success bool `json:"success" dc:"是否成功"`
|
||||
}
|
||||
|
||||
// 书籍评分模型
|
||||
type BookRating struct {
|
||||
g.Meta `orm:"table:book_ratings"`
|
||||
Id int64 `json:"id" orm:"id"`
|
||||
UserId int64 `json:"userId" orm:"user_id"`
|
||||
BookId int64 `json:"bookId" orm:"book_id"`
|
||||
Score float64 `json:"score" orm:"score"`
|
||||
Comment string `json:"comment" orm:"comment"`
|
||||
CreatedAt *gtime.Time `json:"createdAt" orm:"created_at"`
|
||||
}
|
||||
|
||||
// 书籍评分输入参数
|
||||
type BookRatingAddIn struct {
|
||||
UserId int64 `json:"userId" dc:"用户ID"`
|
||||
BookId int64 `json:"bookId" dc:"书籍ID"`
|
||||
Score float64 `json:"score" dc:"评分(1-10分)"`
|
||||
Comment string `json:"comment" dc:"用户评论"`
|
||||
}
|
||||
|
||||
// 书籍评分输出结构体
|
||||
type BookRatingCRUDOut struct {
|
||||
Success bool `json:"success" dc:"是否成功"`
|
||||
}
|
||||
|
||||
// 我的书籍列表项
|
||||
// =============================
|
||||
type MyBookItem struct {
|
||||
Id int64 `json:"id"`
|
||||
Title string `json:"title"`
|
||||
CoverUrl string `json:"coverUrl"`
|
||||
Description string `json:"description"`
|
||||
Progress int `json:"progress" dc:"阅读进度百分比"`
|
||||
IsInShelf bool `json:"isInShelf" dc:"是否在书架"`
|
||||
LastReadAt string `json:"lastReadAt" dc:"最近阅读时间"`
|
||||
Status int `json:"status" dc:"书籍状态"`
|
||||
AuthorId int64 `json:"authorId"`
|
||||
CategoryId int64 `json:"categoryId"`
|
||||
}
|
||||
|
||||
// 我的书籍列表查询参数
|
||||
// =============================
|
||||
type MyBookListIn struct {
|
||||
Type int // 1-正在读 2-已读完 3-历史记录
|
||||
Page int
|
||||
Size int
|
||||
UserId int64
|
||||
Sort string
|
||||
}
|
||||
|
||||
// 我的书籍列表返回
|
||||
// =============================
|
||||
type MyBookListOut struct {
|
||||
Total int
|
||||
List []MyBookItem
|
||||
}
|
||||
|
||||
// =============================
|
||||
// 新增:单独修改精选状态和推荐状态
|
||||
// =============================
|
||||
type BookSetFeaturedIn struct {
|
||||
Id int64 `json:"id" dc:"书籍ID"`
|
||||
IsFeatured int `json:"isFeatured" dc:"是否精选"`
|
||||
}
|
||||
|
||||
type BookSetRecommendedIn struct {
|
||||
Id int64 `json:"id" dc:"书籍ID"`
|
||||
IsRecommended int `json:"isRecommended" dc:"是否推荐"`
|
||||
}
|
||||
|
||||
24
internal/model/bookshelve.go
Normal file
24
internal/model/bookshelve.go
Normal file
@ -0,0 +1,24 @@
|
||||
package model
|
||||
|
||||
import "github.com/gogf/gf/v2/frame/g"
|
||||
|
||||
type Bookshelve struct {
|
||||
g.Meta `orm:"table:bookshelves"`
|
||||
Id int64 `json:"id" orm:"id"`
|
||||
UserId int64 `json:"userId" orm:"user_id"`
|
||||
BookId int64 `json:"bookId" orm:"book_id"`
|
||||
AddedAt int64 `json:"addedAt" orm:"added_at"`
|
||||
ReadStatus int `json:"readStatus" orm:"read_status"`
|
||||
}
|
||||
|
||||
type BookshelveAddIn struct {
|
||||
UserId int64
|
||||
BookId int64
|
||||
}
|
||||
type BookshelveDelIn struct {
|
||||
UserId int64
|
||||
BookIds []int64
|
||||
}
|
||||
type BookshelveCRUDOut struct {
|
||||
Success bool
|
||||
}
|
||||
@ -3,17 +3,17 @@ package model
|
||||
import "github.com/gogf/gf/v2/frame/g"
|
||||
|
||||
type Category struct {
|
||||
g.Meta `orm:"table:categories"`
|
||||
Id int64 `json:"id" orm:"id"` // 分类ID
|
||||
Name string `json:"name" orm:"name"` // 分类名称
|
||||
Type int `json:type orm:"type"` // 类型,1 男频,2 女频
|
||||
g.Meta `orm:"table:categories"`
|
||||
Id int64 `json:"id" orm:"id"`
|
||||
Name string `json:"name" orm:"name"`
|
||||
Channel int `json:"channel" orm:"channel"`
|
||||
}
|
||||
|
||||
type CategoryListIn struct {
|
||||
Page int
|
||||
Size int
|
||||
Name string
|
||||
Type int
|
||||
Page int
|
||||
Size int
|
||||
Name string
|
||||
Channel int
|
||||
}
|
||||
type CategoryListOut struct {
|
||||
Total int
|
||||
@ -21,16 +21,16 @@ type CategoryListOut struct {
|
||||
}
|
||||
|
||||
type CategoryAddIn struct {
|
||||
Name string
|
||||
Type int // 类型,1 男频,2 女频
|
||||
Name string
|
||||
Channel int
|
||||
}
|
||||
type CategoryEditIn struct {
|
||||
Id int
|
||||
Name string
|
||||
Type int // 类型,1 男频,2 女频
|
||||
Id int64
|
||||
Name string
|
||||
Channel int
|
||||
}
|
||||
type CategoryDelIn struct {
|
||||
Id int
|
||||
Id int64
|
||||
}
|
||||
|
||||
type CategoryCRUDOut struct {
|
||||
|
||||
@ -1,17 +1,20 @@
|
||||
package model
|
||||
|
||||
import "github.com/gogf/gf/v2/frame/g"
|
||||
import (
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/os/gtime"
|
||||
)
|
||||
|
||||
type Chapter struct {
|
||||
g.Meta `orm:"table:chapters"`
|
||||
Id int64 `json:"id"`
|
||||
BookId int64 `json:"bookId"`
|
||||
Title string `json:"title"`
|
||||
Content string `json:"content"`
|
||||
WordCount int `json:"wordCount"`
|
||||
Sort int `json:"sort"`
|
||||
IsLocked int `json:"isLocked"`
|
||||
RequiredScore int `json:"requiredScore"`
|
||||
Id int64 `json:"id" orm:"id"`
|
||||
BookId int64 `json:"bookId" orm:"book_id"`
|
||||
Title string `json:"title" orm:"title"`
|
||||
Content string `json:"content" orm:"content"`
|
||||
WordCount int `json:"wordCount" orm:"word_count"`
|
||||
Sort int `json:"sort" orm:"sort"`
|
||||
IsLocked int `json:"isLocked" orm:"is_locked"`
|
||||
RequiredScore int `json:"requiredScore" orm:"required_score"`
|
||||
}
|
||||
|
||||
type ChapterListIn struct {
|
||||
@ -52,3 +55,73 @@ type ChapterDelIn struct {
|
||||
type ChapterCRUDOut struct {
|
||||
Success bool
|
||||
}
|
||||
|
||||
// App 章节列表查询输入参数
|
||||
type ChapterAppListIn struct {
|
||||
BookId int64 `json:"bookId" dc:"书籍ID"`
|
||||
IsDesc bool `json:"isDesc" dc:"是否逆序排列"`
|
||||
Page int `json:"page" dc:"页码"`
|
||||
Size int `json:"size" dc:"每页数量"`
|
||||
UserId int64 `json:"userId" dc:"用户ID"`
|
||||
}
|
||||
|
||||
// App 章节列表输出结构体(不包含 content)
|
||||
type ChapterAppItem struct {
|
||||
g.Meta `orm:"table:chapters"`
|
||||
Id int64 `json:"id" orm:"id" dc:"章节ID"`
|
||||
Title string `json:"title" orm:"title" dc:"章节标题"`
|
||||
WordCount int `json:"wordCount" orm:"word_count" dc:"字数"`
|
||||
Sort int `json:"sort" orm:"sort" dc:"排序"`
|
||||
IsLocked int `json:"isLocked" orm:"is_locked" dc:"是否锁定"`
|
||||
RequiredScore int `json:"requiredScore" orm:"required_score" dc:"所需积分"`
|
||||
UpdatedAt *gtime.Time `json:"updatedAt" orm:"updated_at" dc:"更新时间"`
|
||||
ReadProgress int `json:"readProgress" dc:"阅读进度百分比"`
|
||||
ReadAt *gtime.Time `json:"readAt" dc:"最后阅读时间"`
|
||||
}
|
||||
|
||||
type ChapterAppListOut struct {
|
||||
List []ChapterAppItem
|
||||
Total int
|
||||
}
|
||||
|
||||
// App 章节详情查询输入参数
|
||||
type ChapterAppDetailIn struct {
|
||||
Id int64 `json:"id" dc:"章节ID"`
|
||||
}
|
||||
|
||||
// App 章节详情输出结构体
|
||||
type ChapterAppDetailOut struct {
|
||||
Id int64 `json:"id" dc:"章节ID"`
|
||||
BookId int64 `json:"bookId" dc:"书籍ID"`
|
||||
Title string `json:"title" dc:"章节标题"`
|
||||
Content string `json:"content" dc:"章节内容"`
|
||||
WordCount int `json:"wordCount" dc:"字数"`
|
||||
Sort int `json:"sort" dc:"排序"`
|
||||
IsLocked int `json:"isLocked" dc:"是否锁定"`
|
||||
RequiredScore int `json:"requiredScore" dc:"所需积分"`
|
||||
UpdatedAt *gtime.Time `json:"updatedAt" dc:"更新时间"`
|
||||
}
|
||||
|
||||
// App 购买章节输入参数
|
||||
type ChapterAppPurchaseIn struct {
|
||||
Id int64 `json:"id" dc:"章节ID"`
|
||||
UserId int64 `json:"userId" dc:"用户ID"`
|
||||
}
|
||||
|
||||
// App 购买章节输出结构体
|
||||
type ChapterAppPurchaseOut struct {
|
||||
Success bool `json:"success" dc:"是否成功"`
|
||||
}
|
||||
|
||||
// App 上传阅读进度输入参数
|
||||
type ChapterAppProgressIn struct {
|
||||
BookId int64 `json:"bookId" dc:"书籍ID"`
|
||||
ChapterId int64 `json:"chapterId" dc:"章节ID"`
|
||||
Progress int `json:"progress" dc:"阅读进度百分比"`
|
||||
UserId int64 `json:"userId" dc:"用户ID"`
|
||||
}
|
||||
|
||||
// App 上传阅读进度输出结构体
|
||||
type ChapterAppProgressOut struct {
|
||||
Success bool `json:"success" dc:"是否成功"`
|
||||
}
|
||||
|
||||
@ -11,22 +11,24 @@ import (
|
||||
|
||||
// Books is the golang structure of table books for DAO operations like Where/Data.
|
||||
type Books struct {
|
||||
g.Meta `orm:"table:books, do:true"`
|
||||
Id interface{} // 小说ID
|
||||
AuthorId interface{} // 作者ID
|
||||
CategoryId interface{} // 分类ID
|
||||
Title interface{} // 小说标题
|
||||
CoverUrl interface{} // 封面图片URL
|
||||
Description interface{} // 小说简介
|
||||
Status interface{} // 状态:1=连载中,2=完结,3=下架
|
||||
WordsCount interface{} // 字数
|
||||
ChaptersCount interface{} // 章节数
|
||||
LatestChapterId interface{} // 最新章节ID
|
||||
Rating interface{} // 评分(0.00~10.00)
|
||||
ReadCount interface{} // 阅读人数
|
||||
Tags interface{} // 标签(逗号分隔)
|
||||
CreatedAt *gtime.Time // 创建时间
|
||||
UpdatedAt *gtime.Time // 更新时间
|
||||
DeletedAt *gtime.Time // 软删除时间戳
|
||||
IsRecommended interface{} // 是否推荐:0=否,1=是
|
||||
g.Meta `orm:"table:books, do:true"`
|
||||
Id interface{} // 小说ID
|
||||
AuthorId interface{} // 作者ID
|
||||
CategoryId interface{} // 分类ID
|
||||
Title interface{} // 小说标题
|
||||
CoverUrl interface{} // 封面图片URL
|
||||
Description interface{} // 小说简介
|
||||
Status interface{} // 状态:1=连载中,2=完结,3=下架
|
||||
WordsCount interface{} // 字数
|
||||
ChaptersCount interface{} // 章节数
|
||||
Rating interface{} // 评分(0.00~10.00)
|
||||
ReadCount interface{} // 阅读人数
|
||||
CurrentReaders interface{} // 在读人数
|
||||
Tags interface{} // 标签(逗号分隔)
|
||||
CreatedAt *gtime.Time // 创建时间
|
||||
UpdatedAt *gtime.Time // 更新时间
|
||||
DeletedAt *gtime.Time // 软删除时间戳
|
||||
IsRecommended interface{} // 是否推荐:0=否,1=是
|
||||
IsFeatured interface{} // 是否精选:0=否,1=是
|
||||
Language interface{} // 语言,如 zh=中文,en=英文,jp=日文
|
||||
}
|
||||
|
||||
@ -19,4 +19,5 @@ type Bookshelves struct {
|
||||
LastReadChapterId interface{} // 最后阅读章节ID
|
||||
LastReadPercent interface{} // 阅读进度百分比(0.00~100.00)
|
||||
LastReadAt *gtime.Time // 最后阅读时间
|
||||
ReadStatus interface{} // 阅读状态:1=正在读,2=已读完,3=已收藏
|
||||
}
|
||||
|
||||
@ -14,8 +14,8 @@ type Categories struct {
|
||||
g.Meta `orm:"table:categories, do:true"`
|
||||
Id interface{} // 分类ID
|
||||
Name interface{} // 分类名称
|
||||
Type interface{} // 分类类型:1=男频, 2=女频
|
||||
CreatedAt *gtime.Time // 创建时间
|
||||
UpdatedAt *gtime.Time // 更新时间
|
||||
DeletedAt *gtime.Time // 软删除时间戳
|
||||
Channel interface{} // 频道类型:1=男频,2=女频
|
||||
}
|
||||
|
||||
@ -14,9 +14,9 @@ type UserPointsLogs struct {
|
||||
g.Meta `orm:"table:user_points_logs, do:true"`
|
||||
Id interface{} // 积分流水ID
|
||||
UserId interface{} // 用户ID
|
||||
ChangeType interface{} // 变动类型,例如 earn、spend、refund 等
|
||||
ChangeType interface{} // 变动类型,1=消费(spend), 2=收入(earn)
|
||||
PointsChange interface{} // 积分变化数,正数增加,负数减少
|
||||
RelatedOrderId interface{} // 关联订单ID
|
||||
RelatedOrderId interface{} // 关联ID:当change_type=1时,为chapter_purchases.id;当change_type=2时,为advertisement_records.id
|
||||
Description interface{} // 变动说明
|
||||
CreatedAt *gtime.Time // 变动时间
|
||||
}
|
||||
|
||||
20
internal/model/do/user_read_history.go
Normal file
20
internal/model/do/user_read_history.go
Normal file
@ -0,0 +1,20 @@
|
||||
// =================================================================================
|
||||
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
|
||||
// =================================================================================
|
||||
|
||||
package do
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/os/gtime"
|
||||
)
|
||||
|
||||
// UserReadHistory is the golang structure of table user_read_history for DAO operations like Where/Data.
|
||||
type UserReadHistory struct {
|
||||
g.Meta `orm:"table:user_read_history, do:true"`
|
||||
Id interface{} // 历史记录ID
|
||||
UserId interface{} // 用户ID
|
||||
BookId interface{} // 小说ID
|
||||
ChapterId interface{} // 最后阅读章节ID
|
||||
ReadAt *gtime.Time // 最后阅读时间
|
||||
}
|
||||
@ -9,12 +9,15 @@ import (
|
||||
"github.com/gogf/gf/v2/os/gtime"
|
||||
)
|
||||
|
||||
// ReadRecords is the golang structure of table read_records for DAO operations like Where/Data.
|
||||
type ReadRecords struct {
|
||||
g.Meta `orm:"table:read_records, do:true"`
|
||||
// UserReadRecords is the golang structure of table user_read_records for DAO operations like Where/Data.
|
||||
type UserReadRecords struct {
|
||||
g.Meta `orm:"table:user_read_records, do:true"`
|
||||
Id interface{} // 记录ID
|
||||
UserId interface{} // 用户ID
|
||||
BookId interface{} // 小说ID
|
||||
ChapterId interface{} // 章节ID
|
||||
Progress interface{} // 阅读进度百分比(0-100)
|
||||
ReadAt *gtime.Time // 阅读时间
|
||||
CreatedAt *gtime.Time // 创建时间
|
||||
UpdatedAt *gtime.Time // 更新时间
|
||||
}
|
||||
@ -10,21 +10,23 @@ import (
|
||||
|
||||
// Books is the golang structure for table books.
|
||||
type Books struct {
|
||||
Id int64 `json:"id" orm:"id" description:"小说ID"` // 小说ID
|
||||
AuthorId int64 `json:"authorId" orm:"author_id" description:"作者ID"` // 作者ID
|
||||
CategoryId int64 `json:"categoryId" orm:"category_id" description:"分类ID"` // 分类ID
|
||||
Title string `json:"title" orm:"title" description:"小说标题"` // 小说标题
|
||||
CoverUrl string `json:"coverUrl" orm:"cover_url" description:"封面图片URL"` // 封面图片URL
|
||||
Description string `json:"description" orm:"description" description:"小说简介"` // 小说简介
|
||||
Status int `json:"status" orm:"status" description:"状态:1=连载中,2=完结,3=下架"` // 状态:1=连载中,2=完结,3=下架
|
||||
WordsCount int `json:"wordsCount" orm:"words_count" description:"字数"` // 字数
|
||||
ChaptersCount int `json:"chaptersCount" orm:"chapters_count" description:"章节数"` // 章节数
|
||||
LatestChapterId int64 `json:"latestChapterId" orm:"latest_chapter_id" description:"最新章节ID"` // 最新章节ID
|
||||
Rating float64 `json:"rating" orm:"rating" description:"评分(0.00~10.00)"` // 评分(0.00~10.00)
|
||||
ReadCount int64 `json:"readCount" orm:"read_count" description:"阅读人数"` // 阅读人数
|
||||
Tags string `json:"tags" orm:"tags" description:"标签(逗号分隔)"` // 标签(逗号分隔)
|
||||
CreatedAt *gtime.Time `json:"createdAt" orm:"created_at" description:"创建时间"` // 创建时间
|
||||
UpdatedAt *gtime.Time `json:"updatedAt" orm:"updated_at" description:"更新时间"` // 更新时间
|
||||
DeletedAt *gtime.Time `json:"deletedAt" orm:"deleted_at" description:"软删除时间戳"` // 软删除时间戳
|
||||
IsRecommended int `json:"isRecommended" orm:"is_recommended" description:"是否推荐:0=否,1=是"` // 是否推荐:0=否,1=是
|
||||
Id int64 `json:"id" orm:"id" description:"小说ID"` // 小说ID
|
||||
AuthorId int64 `json:"authorId" orm:"author_id" description:"作者ID"` // 作者ID
|
||||
CategoryId int64 `json:"categoryId" orm:"category_id" description:"分类ID"` // 分类ID
|
||||
Title string `json:"title" orm:"title" description:"小说标题"` // 小说标题
|
||||
CoverUrl string `json:"coverUrl" orm:"cover_url" description:"封面图片URL"` // 封面图片URL
|
||||
Description string `json:"description" orm:"description" description:"小说简介"` // 小说简介
|
||||
Status int `json:"status" orm:"status" description:"状态:1=连载中,2=完结,3=下架"` // 状态:1=连载中,2=完结,3=下架
|
||||
WordsCount int `json:"wordsCount" orm:"words_count" description:"字数"` // 字数
|
||||
ChaptersCount int `json:"chaptersCount" orm:"chapters_count" description:"章节数"` // 章节数
|
||||
Rating float64 `json:"rating" orm:"rating" description:"评分(0.00~10.00)"` // 评分(0.00~10.00)
|
||||
ReadCount int64 `json:"readCount" orm:"read_count" description:"阅读人数"` // 阅读人数
|
||||
CurrentReaders int64 `json:"currentReaders" orm:"current_readers" description:"在读人数"` // 在读人数
|
||||
Tags string `json:"tags" orm:"tags" description:"标签(逗号分隔)"` // 标签(逗号分隔)
|
||||
CreatedAt *gtime.Time `json:"createdAt" orm:"created_at" description:"创建时间"` // 创建时间
|
||||
UpdatedAt *gtime.Time `json:"updatedAt" orm:"updated_at" description:"更新时间"` // 更新时间
|
||||
DeletedAt *gtime.Time `json:"deletedAt" orm:"deleted_at" description:"软删除时间戳"` // 软删除时间戳
|
||||
IsRecommended int `json:"isRecommended" orm:"is_recommended" description:"是否推荐:0=否,1=是"` // 是否推荐:0=否,1=是
|
||||
IsFeatured int `json:"isFeatured" orm:"is_featured" description:"是否精选:0=否,1=是"` // 是否精选:0=否,1=是
|
||||
Language string `json:"language" orm:"language" description:"语言,如 zh=中文,en=英文,jp=日文"` // 语言,如 zh=中文,en=英文,jp=日文
|
||||
}
|
||||
|
||||
@ -10,11 +10,12 @@ import (
|
||||
|
||||
// Bookshelves is the golang structure for table bookshelves.
|
||||
type Bookshelves struct {
|
||||
Id int64 `json:"id" orm:"id" description:"记录ID"` // 记录ID
|
||||
UserId int64 `json:"userId" orm:"user_id" description:"用户ID"` // 用户ID
|
||||
BookId int64 `json:"bookId" orm:"book_id" description:"小说ID"` // 小说ID
|
||||
AddedAt *gtime.Time `json:"addedAt" orm:"added_at" description:"加入书架时间"` // 加入书架时间
|
||||
LastReadChapterId int64 `json:"lastReadChapterId" orm:"last_read_chapter_id" description:"最后阅读章节ID"` // 最后阅读章节ID
|
||||
LastReadPercent float64 `json:"lastReadPercent" orm:"last_read_percent" description:"阅读进度百分比(0.00~100.00)"` // 阅读进度百分比(0.00~100.00)
|
||||
LastReadAt *gtime.Time `json:"lastReadAt" orm:"last_read_at" description:"最后阅读时间"` // 最后阅读时间
|
||||
Id int64 `json:"id" orm:"id" description:"记录ID"` // 记录ID
|
||||
UserId int64 `json:"userId" orm:"user_id" description:"用户ID"` // 用户ID
|
||||
BookId int64 `json:"bookId" orm:"book_id" description:"小说ID"` // 小说ID
|
||||
AddedAt *gtime.Time `json:"addedAt" orm:"added_at" description:"加入书架时间"` // 加入书架时间
|
||||
LastReadChapterId int64 `json:"lastReadChapterId" orm:"last_read_chapter_id" description:"最后阅读章节ID"` // 最后阅读章节ID
|
||||
LastReadPercent float64 `json:"lastReadPercent" orm:"last_read_percent" description:"阅读进度百分比(0.00~100.00)"` // 阅读进度百分比(0.00~100.00)
|
||||
LastReadAt *gtime.Time `json:"lastReadAt" orm:"last_read_at" description:"最后阅读时间"` // 最后阅读时间
|
||||
ReadStatus int `json:"readStatus" orm:"read_status" description:"阅读状态:1=正在读,2=已读完,3=已收藏"` // 阅读状态:1=正在读,2=已读完,3=已收藏
|
||||
}
|
||||
|
||||
@ -10,10 +10,10 @@ import (
|
||||
|
||||
// Categories is the golang structure for table categories.
|
||||
type Categories struct {
|
||||
Id int64 `json:"id" orm:"id" description:"分类ID"` // 分类ID
|
||||
Name string `json:"name" orm:"name" description:"分类名称"` // 分类名称
|
||||
Type int `json:"type" orm:"type" description:"分类类型:1=男频, 2=女频"` // 分类类型:1=男频, 2=女频
|
||||
CreatedAt *gtime.Time `json:"createdAt" orm:"created_at" description:"创建时间"` // 创建时间
|
||||
UpdatedAt *gtime.Time `json:"updatedAt" orm:"updated_at" description:"更新时间"` // 更新时间
|
||||
DeletedAt *gtime.Time `json:"deletedAt" orm:"deleted_at" description:"软删除时间戳"` // 软删除时间戳
|
||||
Id int64 `json:"id" orm:"id" description:"分类ID"` // 分类ID
|
||||
Name string `json:"name" orm:"name" description:"分类名称"` // 分类名称
|
||||
CreatedAt *gtime.Time `json:"createdAt" orm:"created_at" description:"创建时间"` // 创建时间
|
||||
UpdatedAt *gtime.Time `json:"updatedAt" orm:"updated_at" description:"更新时间"` // 更新时间
|
||||
DeletedAt *gtime.Time `json:"deletedAt" orm:"deleted_at" description:"软删除时间戳"` // 软删除时间戳
|
||||
Channel int `json:"channel" orm:"channel" description:"频道类型:1=男频,2=女频"` // 频道类型:1=男频,2=女频
|
||||
}
|
||||
|
||||
@ -10,11 +10,11 @@ import (
|
||||
|
||||
// UserPointsLogs is the golang structure for table user_points_logs.
|
||||
type UserPointsLogs struct {
|
||||
Id int64 `json:"id" orm:"id" description:"积分流水ID"` // 积分流水ID
|
||||
UserId int64 `json:"userId" orm:"user_id" description:"用户ID"` // 用户ID
|
||||
ChangeType string `json:"changeType" orm:"change_type" description:"变动类型,例如 earn、spend、refund 等"` // 变动类型,例如 earn、spend、refund 等
|
||||
PointsChange int `json:"pointsChange" orm:"points_change" description:"积分变化数,正数增加,负数减少"` // 积分变化数,正数增加,负数减少
|
||||
RelatedOrderId int64 `json:"relatedOrderId" orm:"related_order_id" description:"关联订单ID"` // 关联订单ID
|
||||
Description string `json:"description" orm:"description" description:"变动说明"` // 变动说明
|
||||
CreatedAt *gtime.Time `json:"createdAt" orm:"created_at" description:"变动时间"` // 变动时间
|
||||
Id int64 `json:"id" orm:"id" description:"积分流水ID"` // 积分流水ID
|
||||
UserId int64 `json:"userId" orm:"user_id" description:"用户ID"` // 用户ID
|
||||
ChangeType int `json:"changeType" orm:"change_type" description:"变动类型,1=消费(spend), 2=收入(earn)"` // 变动类型,1=消费(spend), 2=收入(earn)
|
||||
PointsChange int `json:"pointsChange" orm:"points_change" description:"积分变化数,正数增加,负数减少"` // 积分变化数,正数增加,负数减少
|
||||
RelatedOrderId int64 `json:"relatedOrderId" orm:"related_order_id" description:"关联ID:当change_type=1时,为chapter_purchases.id;当change_type=2时,为advertisement_records.id"` // 关联ID:当change_type=1时,为chapter_purchases.id;当change_type=2时,为advertisement_records.id
|
||||
Description string `json:"description" orm:"description" description:"变动说明"` // 变动说明
|
||||
CreatedAt *gtime.Time `json:"createdAt" orm:"created_at" description:"变动时间"` // 变动时间
|
||||
}
|
||||
|
||||
@ -8,11 +8,11 @@ import (
|
||||
"github.com/gogf/gf/v2/os/gtime"
|
||||
)
|
||||
|
||||
// ReadRecords is the golang structure for table read_records.
|
||||
type ReadRecords struct {
|
||||
Id int64 `json:"id" orm:"id" description:"记录ID"` // 记录ID
|
||||
UserId int64 `json:"userId" orm:"user_id" description:"用户ID"` // 用户ID
|
||||
BookId int64 `json:"bookId" orm:"book_id" description:"小说ID"` // 小说ID
|
||||
ChapterId int64 `json:"chapterId" orm:"chapter_id" description:"章节ID"` // 章节ID
|
||||
ReadAt *gtime.Time `json:"readAt" orm:"read_at" description:"阅读时间"` // 阅读时间
|
||||
// UserReadHistory is the golang structure for table user_read_history.
|
||||
type UserReadHistory struct {
|
||||
Id int64 `json:"id" orm:"id" description:"历史记录ID"` // 历史记录ID
|
||||
UserId int64 `json:"userId" orm:"user_id" description:"用户ID"` // 用户ID
|
||||
BookId int64 `json:"bookId" orm:"book_id" description:"小说ID"` // 小说ID
|
||||
ChapterId int64 `json:"chapterId" orm:"chapter_id" description:"最后阅读章节ID"` // 最后阅读章节ID
|
||||
ReadAt *gtime.Time `json:"readAt" orm:"read_at" description:"最后阅读时间"` // 最后阅读时间
|
||||
}
|
||||
21
internal/model/entity/user_read_records.go
Normal file
21
internal/model/entity/user_read_records.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"
|
||||
)
|
||||
|
||||
// UserReadRecords is the golang structure for table user_read_records.
|
||||
type UserReadRecords struct {
|
||||
Id int64 `json:"id" orm:"id" description:"记录ID"` // 记录ID
|
||||
UserId int64 `json:"userId" orm:"user_id" description:"用户ID"` // 用户ID
|
||||
BookId int64 `json:"bookId" orm:"book_id" description:"小说ID"` // 小说ID
|
||||
ChapterId int64 `json:"chapterId" orm:"chapter_id" description:"章节ID"` // 章节ID
|
||||
Progress int `json:"progress" orm:"progress" description:"阅读进度百分比(0-100)"` // 阅读进度百分比(0-100)
|
||||
ReadAt *gtime.Time `json:"readAt" orm:"read_at" description:"阅读时间"` // 阅读时间
|
||||
CreatedAt *gtime.Time `json:"createdAt" orm:"created_at" description:"创建时间"` // 创建时间
|
||||
UpdatedAt *gtime.Time `json:"updatedAt" orm:"updated_at" description:"更新时间"` // 更新时间
|
||||
}
|
||||
@ -1,13 +1,18 @@
|
||||
package model
|
||||
|
||||
import "github.com/gogf/gf/v2/frame/g"
|
||||
import (
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/os/gtime"
|
||||
)
|
||||
|
||||
type Feedback struct {
|
||||
g.Meta `orm:"table:feedbacks"`
|
||||
Id int64 `json:"id"`
|
||||
UserId int64 `json:"userId"`
|
||||
Content string `json:"content"`
|
||||
Status int `json:"status"`
|
||||
g.Meta `orm:"table:feedbacks"`
|
||||
Id int64 `json:"id" orm:"id"`
|
||||
UserId int64 `json:"userId" orm:"user_id"`
|
||||
Content string `json:"content" orm:"content"`
|
||||
Status int `json:"status" orm:"status"`
|
||||
CreatedAt *gtime.Time `json:"createdAt" orm:"created_at"`
|
||||
User User `json:"user" orm:"with:id=user_id"`
|
||||
}
|
||||
|
||||
type FeedbackListIn struct {
|
||||
|
||||
@ -1,36 +0,0 @@
|
||||
package model
|
||||
|
||||
import "github.com/gogf/gf/v2/frame/g"
|
||||
|
||||
type ReadRecord struct {
|
||||
g.Meta `orm:"table:read_records"`
|
||||
Id int64 `json:"id"`
|
||||
UserId int64 `json:"userId"`
|
||||
BookId int64 `json:"bookId"`
|
||||
ChapterId int64 `json:"chapterId"`
|
||||
ReadAt int64 `json:"readAt"`
|
||||
}
|
||||
|
||||
type ReadRecordListIn struct {
|
||||
Page int
|
||||
Size int
|
||||
UserId int64
|
||||
BookId int64
|
||||
ChapterId int64
|
||||
}
|
||||
type ReadRecordListOut struct {
|
||||
Total int
|
||||
List []ReadRecord
|
||||
}
|
||||
|
||||
type ReadRecordAddIn struct {
|
||||
UserId int64
|
||||
BookId int64
|
||||
ChapterId int64
|
||||
}
|
||||
type ReadRecordDelIn struct {
|
||||
Id int64
|
||||
}
|
||||
type ReadRecordCRUDOut struct {
|
||||
Success bool
|
||||
}
|
||||
@ -4,9 +4,9 @@ import "github.com/gogf/gf/v2/frame/g"
|
||||
|
||||
type Tag struct {
|
||||
g.Meta `orm:"table:tags"`
|
||||
Id int64 `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Type int `json:"type"` // 1=主题, 2=角色, 3=情节
|
||||
Id int64 `json:"id" orm:"id"`
|
||||
Name string `json:"name" orm:"name"`
|
||||
Type int `json:"type" orm:"type"` // 1=主题, 2=角色, 3=情节
|
||||
}
|
||||
|
||||
type TagListIn struct {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user