完善功能
This commit is contained in:
@ -11,6 +11,6 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type IAdminV1 interface {
|
type IAdminV1 interface {
|
||||||
AdminInfo(ctx context.Context, req *v1.AdminInfoReq) (res *v1.AdminInfoRes, err error)
|
Info(ctx context.Context, req *v1.InfoReq) (res *v1.InfoRes, err error)
|
||||||
AdminEditPass(ctx context.Context, req *v1.AdminEditPassReq) (res *v1.AdminEditPassRes, 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"
|
"github.com/gogf/gf/v2/frame/g"
|
||||||
)
|
)
|
||||||
|
|
||||||
type AdminInfoReq struct {
|
type InfoReq struct {
|
||||||
g.Meta `path:"/admin/info" tags:"Admin" method:"get" summary:"管理员信息"`
|
g.Meta `path:"/admin/info" tags:"Backend/Admin" method:"get" summary:"管理员信息"`
|
||||||
}
|
}
|
||||||
type AdminInfoRes struct {
|
type InfoRes struct {
|
||||||
g.Meta `mime:"application/json"`
|
g.Meta `mime:"application/json"`
|
||||||
AdminId int64 `json:"adminId"`
|
AdminId int64 `json:"adminId"`
|
||||||
Username string `json:"username"`
|
Username string `json:"username"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type AdminEditPassReq struct {
|
type EditPassReq struct {
|
||||||
g.Meta `path:"/admin/editPass" tags:"Admin" method:"post" summary:"修改密码"`
|
g.Meta `path:"/admin/editPass" tags:"Backend/Admin" method:"post" summary:"修改密码"`
|
||||||
OldPass string `json:"oldPass" v:"required" dc:"旧密码"`
|
OldPass string `json:"oldPass" v:"required" dc:"旧密码"`
|
||||||
NewPass string `json:"newPass" v:"required" dc:"新密码"`
|
NewPass string `json:"newPass" v:"required" dc:"新密码"`
|
||||||
}
|
}
|
||||||
type AdminEditPassRes struct {
|
type EditPassRes struct {
|
||||||
g.Meta `mime:"application/json"`
|
g.Meta `mime:"application/json"`
|
||||||
Success bool
|
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 {
|
type IBookV1 interface {
|
||||||
BookList(ctx context.Context, req *v1.BookListReq) (res *v1.BookListRes, err error)
|
List(ctx context.Context, req *v1.ListReq) (res *v1.ListRes, err error)
|
||||||
BookAdd(ctx context.Context, req *v1.BookAddReq) (res *v1.BookAddRes, err error)
|
Add(ctx context.Context, req *v1.AddReq) (res *v1.AddRes, err error)
|
||||||
BookEdit(ctx context.Context, req *v1.BookEditReq) (res *v1.BookEditRes, err error)
|
Edit(ctx context.Context, req *v1.EditReq) (res *v1.EditRes, err error)
|
||||||
BookDel(ctx context.Context, req *v1.BookDelReq) (res *v1.BookDelRes, 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"
|
"github.com/gogf/gf/v2/frame/g"
|
||||||
)
|
)
|
||||||
|
|
||||||
type BookListReq struct {
|
type ListReq struct {
|
||||||
g.Meta `path:"/book" tags:"Book" method:"get" summary:"获取小说列表"`
|
g.Meta `path:"/book" tags:"Backend/Author" method:"get" summary:"获取小说列表"`
|
||||||
Page int `json:"page"`
|
Page int `json:"page" dc:"页码"`
|
||||||
Size int `json:"size"`
|
Size int `json:"size" dc:"每页数量"`
|
||||||
Title string `json:"title"`
|
Title string `json:"title" dc:"书名模糊搜索"`
|
||||||
CategoryId int64 `json:"categoryId"`
|
CategoryId int64 `json:"categoryId" dc:"分类ID"`
|
||||||
AuthorId int64 `json:"authorId"`
|
AuthorId int64 `json:"authorId" dc:"作者ID"`
|
||||||
Status int `json:"status"`
|
Status int `json:"status" dc:"状态"`
|
||||||
IsRecommended int `json:"isRecommended"`
|
IsRecommended int `json:"isRecommended" dc:"是否推荐"`
|
||||||
|
Sort string `json:"sort" dc:"排序字段"`
|
||||||
}
|
}
|
||||||
type BookListRes struct {
|
type ListRes struct {
|
||||||
Total int `json:"total"`
|
Total int `json:"total" dc:"总数"`
|
||||||
List []model.Book `json:"list"`
|
List []model.Book `json:"list" dc:"书籍列表"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type BookAddReq struct {
|
type AddReq struct {
|
||||||
g.Meta `path:"/book" tags:"Book" method:"post" summary:"新增小说"`
|
g.Meta `path:"/book" tags:"Backend/Author" method:"post" summary:"新增小说"`
|
||||||
AuthorId int64 `json:"authorId"`
|
AuthorId int64 `json:"authorId" dc:"作者ID" v:"required"`
|
||||||
CategoryId int64 `json:"categoryId"`
|
CategoryId int64 `json:"categoryId" dc:"分类ID" v:"required"`
|
||||||
Title string `json:"title"`
|
Title string `json:"title" dc:"书名" v:"required"`
|
||||||
CoverUrl string `json:"coverUrl"`
|
CoverUrl string `json:"coverUrl" dc:"封面图"`
|
||||||
Description string `json:"description"`
|
Description string `json:"description" dc:"简介"`
|
||||||
Status int `json:"status"`
|
Status int `json:"status" dc:"状态"`
|
||||||
Tags string `json:"tags"`
|
Tags string `json:"tags" dc:"标签"`
|
||||||
IsRecommended int `json:"isRecommended"`
|
IsRecommended int `json:"isRecommended" dc:"是否推荐"`
|
||||||
|
IsFeatured int `json:"isFeatured" dc:"是否精选"`
|
||||||
|
Language string `json:"language" dc:"语言"`
|
||||||
}
|
}
|
||||||
type BookAddRes struct {
|
type AddRes struct {
|
||||||
Success bool `json:"success"`
|
Success bool `json:"success" dc:"是否成功"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type BookEditReq struct {
|
type EditReq struct {
|
||||||
g.Meta `path:"/book" tags:"Book" method:"put" summary:"编辑小说"`
|
g.Meta `path:"/book" tags:"Backend/Author" method:"put" summary:"编辑小说"`
|
||||||
Id int64 `json:"id"`
|
Id int64 `json:"id" dc:"书籍ID" v:"required"`
|
||||||
AuthorId int64 `json:"authorId"`
|
AuthorId int64 `json:"authorId" dc:"作者ID" v:"required"`
|
||||||
CategoryId int64 `json:"categoryId"`
|
CategoryId int64 `json:"categoryId" dc:"分类ID" v:"required"`
|
||||||
Title string `json:"title"`
|
Title string `json:"title" dc:"书名" v:"required"`
|
||||||
CoverUrl string `json:"coverUrl"`
|
CoverUrl string `json:"coverUrl" dc:"封面图"`
|
||||||
Description string `json:"description"`
|
Description string `json:"description" dc:"简介"`
|
||||||
Status int `json:"status"`
|
Status int `json:"status" dc:"状态"`
|
||||||
Tags string `json:"tags"`
|
Tags string `json:"tags" dc:"标签"`
|
||||||
IsRecommended int `json:"isRecommended"`
|
IsRecommended int `json:"isRecommended" dc:"是否推荐"`
|
||||||
|
IsFeatured int `json:"isFeatured" dc:"是否精选"`
|
||||||
|
Language string `json:"language" dc:"语言"`
|
||||||
}
|
}
|
||||||
type BookEditRes struct {
|
type EditRes struct {
|
||||||
Success bool `json:"success"`
|
Success bool `json:"success" dc:"是否成功"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type BookDelReq struct {
|
type DelReq struct {
|
||||||
g.Meta `path:"/book" tags:"Book" method:"delete" summary:"删除小说"`
|
g.Meta `path:"/book" tags:"Backend/Author" method:"delete" summary:"删除小说"`
|
||||||
Id int64 `json:"id"`
|
Id int64 `json:"id" dc:"书籍ID" v:"required"`
|
||||||
}
|
}
|
||||||
type BookDelRes struct {
|
type DelRes struct {
|
||||||
Success bool `json:"success"`
|
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 {
|
type ICategoryV1 interface {
|
||||||
CategoryList(ctx context.Context, req *v1.CategoryListReq) (res *v1.CategoryListRes, err error)
|
List(ctx context.Context, req *v1.ListReq) (res *v1.ListRes, err error)
|
||||||
CategoryAdd(ctx context.Context, req *v1.CategoryAddReq) (res *v1.CategoryAddRes, err error)
|
Add(ctx context.Context, req *v1.AddReq) (res *v1.AddRes, err error)
|
||||||
CategoryEdit(ctx context.Context, req *v1.CategoryEditReq) (res *v1.CategoryEditRes, err error)
|
Edit(ctx context.Context, req *v1.EditReq) (res *v1.EditRes, err error)
|
||||||
CategoryDel(ctx context.Context, req *v1.CategoryDelReq) (res *v1.CategoryDelRes, 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"
|
"github.com/gogf/gf/v2/frame/g"
|
||||||
)
|
)
|
||||||
|
|
||||||
type CategoryListReq struct {
|
type ListReq struct {
|
||||||
g.Meta `path:"/category" tags:"Category" method:"get" summary:"获取分类列表"`
|
g.Meta `path:"/category" tags:"APP" method:"get" summary:"获取分类列表"`
|
||||||
Page int `json:"page" dc:"页码"`
|
Page int `json:"page" dc:"页码"`
|
||||||
Size int `json:"size" dc:"每页数量"`
|
Size int `json:"size" dc:"每页数量"`
|
||||||
Name string `json:"name" dc:"分类名称(模糊搜索)"`
|
Name string `json:"name" dc:"分类名称(模糊搜索)"`
|
||||||
Type int `json:"type" dc:"类型,1男频,2女频"`
|
Channel int `json:"channel" dc:"频道类型:1=男频,2=女频"`
|
||||||
}
|
}
|
||||||
type CategoryListRes struct {
|
type ListRes struct {
|
||||||
Total int `json:"total" dc:"总数"`
|
Total int `json:"total" dc:"总数"`
|
||||||
List []model.Category `json:"list" dc:"分类列表"`
|
List []model.Category `json:"list" dc:"分类列表"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type CategoryAddReq struct {
|
type AddReq struct {
|
||||||
g.Meta `path:"/category" tags:"Category" method:"post" summary:"新增分类"`
|
g.Meta `path:"/category" tags:"Backend/Admin" method:"post" summary:"新增分类"`
|
||||||
Name string `json:"name" dc:"分类名称"`
|
Name string `json:"name" dc:"分类名称" v:"required"`
|
||||||
Type int `json:"type" dc:"类型,1男频,2女频"`
|
Channel int `json:"channel" dc:"频道类型:1=男频,2=女频" v:"required"`
|
||||||
}
|
}
|
||||||
type CategoryAddRes struct {
|
type AddRes struct {
|
||||||
Success bool `json:"success" dc:"是否成功"`
|
Success bool `json:"success" dc:"是否成功"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type CategoryEditReq struct {
|
type EditReq struct {
|
||||||
g.Meta `path:"/category" tags:"Category" method:"put" summary:"编辑分类"`
|
g.Meta `path:"/category" tags:"Backend/Admin" method:"put" summary:"编辑分类"`
|
||||||
Id int `json:"id" dc:"分类ID"`
|
Id int64 `json:"id" dc:"分类ID" v:"required"`
|
||||||
Name string `json:"name" dc:"分类名称"`
|
Name string `json:"name" dc:"分类名称" v:"required"`
|
||||||
Type int `json:"type" dc:"类型,1男频,2女频"`
|
Channel int `json:"channel" dc:"频道类型:1=男频,2=女频" v:"required"`
|
||||||
}
|
}
|
||||||
type CategoryEditRes struct {
|
type EditRes struct {
|
||||||
Success bool `json:"success" dc:"是否成功"`
|
Success bool `json:"success" dc:"是否成功"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type CategoryDelReq struct {
|
type DelReq struct {
|
||||||
g.Meta `path:"/category" tags:"Category" method:"delete" summary:"删除分类"`
|
g.Meta `path:"/category" tags:"Backend/Admin" method:"delete" summary:"删除分类"`
|
||||||
Id int `json:"id" dc:"分类ID"`
|
Id int64 `json:"id" dc:"分类ID" v:"required"`
|
||||||
}
|
}
|
||||||
type CategoryDelRes struct {
|
type DelRes struct {
|
||||||
Success bool `json:"success" dc:"是否成功"`
|
Success bool `json:"success" dc:"是否成功"`
|
||||||
}
|
}
|
||||||
|
|||||||
@ -11,8 +11,12 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type IChapterV1 interface {
|
type IChapterV1 interface {
|
||||||
ChapterList(ctx context.Context, req *v1.ChapterListReq) (res *v1.ChapterListRes, err error)
|
List(ctx context.Context, req *v1.ListReq) (res *v1.ListRes, err error)
|
||||||
ChapterAdd(ctx context.Context, req *v1.ChapterAddReq) (res *v1.ChapterAddRes, err error)
|
Add(ctx context.Context, req *v1.AddReq) (res *v1.AddRes, err error)
|
||||||
ChapterEdit(ctx context.Context, req *v1.ChapterEditReq) (res *v1.ChapterEditRes, err error)
|
Edit(ctx context.Context, req *v1.EditReq) (res *v1.EditRes, err error)
|
||||||
ChapterDel(ctx context.Context, req *v1.ChapterDelReq) (res *v1.ChapterDelRes, 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"
|
"github.com/gogf/gf/v2/frame/g"
|
||||||
)
|
)
|
||||||
|
|
||||||
type ChapterListReq struct {
|
type ListReq struct {
|
||||||
g.Meta `path:"/chapter" tags:"Chapter" method:"get" summary:"获取章节列表"`
|
g.Meta `path:"/chapter" tags:"Backend/Author" method:"get" summary:"获取章节列表"`
|
||||||
Page int `json:"page" dc:"页码"`
|
Page int `json:"page" dc:"页码"`
|
||||||
Size int `json:"size" dc:"每页数量"`
|
Size int `json:"size" dc:"每页数量"`
|
||||||
BookId int64 `json:"bookId" dc:"小说ID"`
|
BookId int64 `json:"bookId" dc:"小说ID"`
|
||||||
Title string `json:"title" dc:"章节标题(模糊搜索)"`
|
Title string `json:"title" dc:"章节标题(模糊搜索)"`
|
||||||
IsLocked int `json:"isLocked" dc:"是否锁定:0免费,1需积分解锁"`
|
IsLocked int `json:"isLocked" dc:"是否锁定:0免费,1需积分解锁"`
|
||||||
}
|
}
|
||||||
type ChapterListRes struct {
|
type ListRes struct {
|
||||||
Total int `json:"total" dc:"总数"`
|
Total int `json:"total" dc:"总数"`
|
||||||
List []model.Chapter `json:"list" dc:"章节列表"`
|
List []model.Chapter `json:"list" dc:"章节列表"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ChapterAddReq struct {
|
type AddReq struct {
|
||||||
g.Meta `path:"/chapter" tags:"Chapter" method:"post" summary:"新增章节"`
|
g.Meta `path:"/chapter" tags:"Backend/Author" method:"post" summary:"新增章节"`
|
||||||
BookId int64 `json:"bookId" dc:"小说ID"`
|
BookId int64 `json:"bookId" dc:"小说ID" v:"required"`
|
||||||
Title string `json:"title" dc:"章节标题"`
|
Title string `json:"title" dc:"章节标题" v:"required"`
|
||||||
Content string `json:"content" dc:"章节内容"`
|
Content string `json:"content" dc:"章节内容" v:"required"`
|
||||||
WordCount int `json:"wordCount" dc:"章节字数"`
|
WordCount int `json:"wordCount" dc:"章节字数"`
|
||||||
Sort int `json:"sort" dc:"排序序号"`
|
Sort int `json:"sort" dc:"排序序号"`
|
||||||
IsLocked int `json:"isLocked" dc:"是否锁定:0免费,1需积分解锁"`
|
IsLocked int `json:"isLocked" dc:"是否锁定:0免费,1需积分解锁"`
|
||||||
RequiredScore int `json:"requiredScore" dc:"解锁所需积分"`
|
RequiredScore int `json:"requiredScore" dc:"解锁所需积分"`
|
||||||
}
|
}
|
||||||
type ChapterAddRes struct {
|
type AddRes struct {
|
||||||
Success bool `json:"success" dc:"是否成功"`
|
Success bool `json:"success" dc:"是否成功"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ChapterEditReq struct {
|
type EditReq struct {
|
||||||
g.Meta `path:"/chapter" tags:"Chapter" method:"put" summary:"编辑章节"`
|
g.Meta `path:"/chapter" tags:"Backend/Author" method:"put" summary:"编辑章节"`
|
||||||
Id int64 `json:"id" dc:"章节ID"`
|
Id int64 `json:"id" dc:"章节ID" v:"required"`
|
||||||
BookId int64 `json:"bookId" dc:"小说ID"`
|
BookId int64 `json:"bookId" dc:"小说ID" v:"required"`
|
||||||
Title string `json:"title" dc:"章节标题"`
|
Title string `json:"title" dc:"章节标题" v:"required"`
|
||||||
Content string `json:"content" dc:"章节内容"`
|
Content string `json:"content" dc:"章节内容" v:"required"`
|
||||||
WordCount int `json:"wordCount" dc:"章节字数"`
|
WordCount int `json:"wordCount" dc:"章节字数"`
|
||||||
Sort int `json:"sort" dc:"排序序号"`
|
Sort int `json:"sort" dc:"排序序号"`
|
||||||
IsLocked int `json:"isLocked" dc:"是否锁定:0免费,1需积分解锁"`
|
IsLocked int `json:"isLocked" dc:"是否锁定:0免费,1需积分解锁"`
|
||||||
RequiredScore int `json:"requiredScore" dc:"解锁所需积分"`
|
RequiredScore int `json:"requiredScore" dc:"解锁所需积分"`
|
||||||
}
|
}
|
||||||
type ChapterEditRes struct {
|
type EditRes struct {
|
||||||
Success bool `json:"success" dc:"是否成功"`
|
Success bool `json:"success" dc:"是否成功"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ChapterDelReq struct {
|
type DelReq struct {
|
||||||
g.Meta `path:"/chapter" tags:"Chapter" method:"delete" summary:"删除章节"`
|
g.Meta `path:"/chapter" tags:"Backend/Author" method:"delete" summary:"删除章节"`
|
||||||
Id int64 `json:"id" dc:"章节ID"`
|
Id int64 `json:"id" dc:"章节ID" v:"required"`
|
||||||
}
|
}
|
||||||
type ChapterDelRes struct {
|
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"`
|
||||||
|
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 string `json:"updatedAt" dc:"更新时间"`
|
||||||
|
}
|
||||||
|
|
||||||
|
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 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 AppProgressRes struct {
|
||||||
Success bool `json:"success" dc:"是否成功"`
|
Success bool `json:"success" dc:"是否成功"`
|
||||||
}
|
}
|
||||||
|
|||||||
@ -11,6 +11,6 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type IFeedbackV1 interface {
|
type IFeedbackV1 interface {
|
||||||
FeedbackList(ctx context.Context, req *v1.FeedbackListReq) (res *v1.FeedbackListRes, err error)
|
List(ctx context.Context, req *v1.ListReq) (res *v1.ListRes, err error)
|
||||||
FeedbackAdd(ctx context.Context, req *v1.FeedbackAddReq) (res *v1.FeedbackAddRes, 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"
|
"github.com/gogf/gf/v2/frame/g"
|
||||||
)
|
)
|
||||||
|
|
||||||
type FeedbackListReq struct {
|
type ListReq struct {
|
||||||
g.Meta `path:"/feedback" tags:"Feedback" method:"get" summary:"获取反馈列表"`
|
g.Meta `path:"/feedback" tags:"Backend/Admin" method:"get" summary:"获取反馈列表"`
|
||||||
Page int `json:"page" dc:"页码"`
|
Page int `json:"page" dc:"页码"`
|
||||||
Size int `json:"size" dc:"每页数量"`
|
Size int `json:"size" dc:"每页数量"`
|
||||||
UserId int64 `json:"userId" dc:"用户ID"`
|
UserId int64 `json:"userId" dc:"用户ID"`
|
||||||
Status int `json:"status" dc:"处理状态:1未处理,2处理中,3已处理"`
|
Status int `json:"status" dc:"处理状态:1未处理,2处理中,3已处理"`
|
||||||
}
|
}
|
||||||
type FeedbackListRes struct {
|
type ListRes struct {
|
||||||
Total int `json:"total" dc:"总数"`
|
Total int `json:"total" dc:"总数"`
|
||||||
List []model.Feedback `json:"list" dc:"反馈列表"`
|
List []model.Feedback `json:"list" dc:"反馈列表"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type FeedbackAddReq struct {
|
type AddReq struct {
|
||||||
g.Meta `path:"/feedback" tags:"APP/Feedback" method:"post" summary:"新增反馈"`
|
g.Meta `path:"/feedback" tags:"APP" method:"post" summary:"新增反馈"`
|
||||||
Content string `json:"content" dc:"反馈内容"`
|
Content string `json:"content" dc:"反馈内容" v:"required"`
|
||||||
}
|
}
|
||||||
type FeedbackAddRes struct {
|
type AddRes struct {
|
||||||
Success bool `json:"success" dc:"是否成功"`
|
Success bool `json:"success" dc:"是否成功"`
|
||||||
}
|
}
|
||||||
|
|||||||
@ -11,7 +11,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type IUserV1 interface {
|
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)
|
Delete(ctx context.Context, req *v1.DeleteReq) (res *v1.DeleteRes, err error)
|
||||||
Logout(ctx context.Context, req *v1.LogoutReq) (res *v1.LogoutRes, 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"
|
"github.com/gogf/gf/v2/frame/g"
|
||||||
)
|
)
|
||||||
|
|
||||||
type UserInfoReq struct {
|
type InfoReq struct {
|
||||||
g.Meta `path:"/user/info" tags:"APP/User" method:"get" summary:"获取用户信息"`
|
g.Meta `path:"/user/info" tags:"APP" method:"get" summary:"获取用户信息"`
|
||||||
}
|
}
|
||||||
type UserInfoRes struct {
|
type InfoRes struct {
|
||||||
g.Meta `mime:"application/json"`
|
g.Meta `mime:"application/json"`
|
||||||
UserId int64 `json:"userId"`
|
UserId int64 `json:"userId"`
|
||||||
Username string `json:"username"` // 用户名
|
Username string `json:"username"` // 用户名
|
||||||
@ -17,7 +17,7 @@ type UserInfoRes struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type DeleteReq 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:"密码"`
|
Password string `json:"password" v:"required" dc:"密码"`
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -26,7 +26,7 @@ type DeleteRes struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type LogoutReq 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 {
|
type LogoutRes struct {
|
||||||
Success bool `json:"success" dc:"是否成功"`
|
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
|
toolchain go1.24.3
|
||||||
|
|
||||||
require (
|
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/casbin/casbin/v2 v2.108.0
|
||||||
github.com/gogf/gf v1.16.9
|
github.com/gogf/gf v1.16.9
|
||||||
github.com/gogf/gf/contrib/drivers/mysql/v2 v2.9.0
|
github.com/gogf/gf/contrib/drivers/mysql/v2 v2.9.0
|
||||||
@ -19,6 +22,17 @@ require (
|
|||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/BurntSushi/toml v1.4.0 // indirect
|
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/bmatcuk/doublestar/v4 v4.6.1 // indirect
|
||||||
github.com/casbin/govaluate v1.3.0 // indirect
|
github.com/casbin/govaluate v1.3.0 // indirect
|
||||||
github.com/cespare/xxhash/v2 v2.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/gomodule/redigo v1.8.5 // indirect
|
||||||
github.com/gorilla/websocket v1.5.3 // indirect
|
github.com/gorilla/websocket v1.5.3 // indirect
|
||||||
github.com/grokify/html-strip-tags-go v0.1.0 // 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/magiconair/properties v1.8.9 // indirect
|
||||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||||
github.com/mattn/go-isatty v0.0.20 // 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/net v0.32.0 // indirect
|
||||||
golang.org/x/sys v0.28.0 // indirect
|
golang.org/x/sys v0.28.0 // indirect
|
||||||
golang.org/x/text v0.21.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
|
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 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 h1:kuoIxZQy2WRRk1pttg9asf+WVv6tWQuBNVmK8+nqPr0=
|
||||||
github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
|
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/aws/aws-sdk-go v1.55.7 h1:UJrkFq7es5CShfBwlWAC8DA077vp8PyVbQd3lqLiztE=
|
||||||
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/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 h1:FH9SifrbvJhnlQpztAx++wlkk70QBf0iBWDwNy7PA4I=
|
||||||
github.com/bmatcuk/doublestar/v4 v4.6.1/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc=
|
github.com/bmatcuk/doublestar/v4 v4.6.1/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc=
|
||||||
github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs=
|
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/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 h1:ZFIlfQAYmrL2Fe6/dZz6vCA5hYK0NxhnoKMQpbklgqc=
|
||||||
github.com/hailaz/gf-casbin-adapter/v2 v2.8.1/go.mod h1:Jk91dRBZuMVjBMu2oQmqMRc6xuL5V+rzgHeFWvI+wlg=
|
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 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||||
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
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.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 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
|
||||||
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
|
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-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
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=
|
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 h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
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.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-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.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
|
|||||||
@ -4,6 +4,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"server/internal/controller/admin"
|
"server/internal/controller/admin"
|
||||||
"server/internal/controller/auth"
|
"server/internal/controller/auth"
|
||||||
|
"server/internal/controller/author"
|
||||||
"server/internal/controller/book"
|
"server/internal/controller/book"
|
||||||
"server/internal/controller/category"
|
"server/internal/controller/category"
|
||||||
"server/internal/controller/chapter"
|
"server/internal/controller/chapter"
|
||||||
@ -35,6 +36,7 @@ var (
|
|||||||
group.Middleware(middleware.Casbin)
|
group.Middleware(middleware.Casbin)
|
||||||
group.Bind(
|
group.Bind(
|
||||||
admin.NewV1(),
|
admin.NewV1(),
|
||||||
|
author.NewV1(),
|
||||||
book.NewV1(),
|
book.NewV1(),
|
||||||
category.NewV1(),
|
category.NewV1(),
|
||||||
chapter.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"
|
"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()
|
adminId := g.RequestFromCtx(ctx).GetCtxVar("id").Int64()
|
||||||
out, err := service.Admin().Info(ctx, &model.AdminInfoIn{AdminId: adminId})
|
out, err := service.Admin().Info(ctx, &model.AdminInfoIn{AdminId: adminId})
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return &v1.AdminInfoRes{
|
return &v1.InfoRes{
|
||||||
AdminId: out.AdminId,
|
AdminId: out.AdminId,
|
||||||
Username: out.Username,
|
Username: out.Username,
|
||||||
}, nil
|
}, 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 (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
v1 "server/api/book/v1"
|
||||||
"server/internal/model"
|
"server/internal/model"
|
||||||
"server/internal/service"
|
"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{
|
out, err := service.Book().Create(ctx, &model.BookAddIn{
|
||||||
AuthorId: req.AuthorId,
|
AuthorId: req.AuthorId,
|
||||||
CategoryId: req.CategoryId,
|
CategoryId: req.CategoryId,
|
||||||
|
Title: req.Title,
|
||||||
CoverUrl: req.CoverUrl,
|
CoverUrl: req.CoverUrl,
|
||||||
Description: req.Description,
|
Description: req.Description,
|
||||||
IsRecommended: req.IsRecommended,
|
|
||||||
Status: req.Status,
|
Status: req.Status,
|
||||||
Tags: req.Tags,
|
Tags: req.Tags,
|
||||||
Title: req.Title,
|
IsRecommended: req.IsRecommended,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
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 (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
v1 "server/api/book/v1"
|
||||||
"server/internal/model"
|
"server/internal/model"
|
||||||
"server/internal/service"
|
"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{
|
out, err := service.Book().Delete(ctx, &model.BookDelIn{
|
||||||
Id: req.Id,
|
Id: req.Id,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return &v1.BookDelRes{Success: out.Success}, nil
|
|
||||||
|
return &v1.DelRes{
|
||||||
|
Success: out.Success,
|
||||||
|
}, nil
|
||||||
}
|
}
|
||||||
@ -2,26 +2,28 @@ package book
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
v1 "server/api/book/v1"
|
||||||
"server/internal/model"
|
"server/internal/model"
|
||||||
"server/internal/service"
|
"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{
|
out, err := service.Book().Update(ctx, &model.BookEditIn{
|
||||||
|
Id: req.Id,
|
||||||
AuthorId: req.AuthorId,
|
AuthorId: req.AuthorId,
|
||||||
CategoryId: req.CategoryId,
|
CategoryId: req.CategoryId,
|
||||||
|
Title: req.Title,
|
||||||
CoverUrl: req.CoverUrl,
|
CoverUrl: req.CoverUrl,
|
||||||
Description: req.Description,
|
Description: req.Description,
|
||||||
Id: req.Id,
|
|
||||||
IsRecommended: req.IsRecommended,
|
|
||||||
Status: req.Status,
|
Status: req.Status,
|
||||||
Tags: req.Tags,
|
Tags: req.Tags,
|
||||||
Title: req.Title,
|
IsRecommended: req.IsRecommended,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return &v1.BookEditRes{Success: out.Success}, nil
|
|
||||||
|
return &v1.EditRes{
|
||||||
|
Success: out.Success,
|
||||||
|
}, nil
|
||||||
}
|
}
|
||||||
@ -2,27 +2,28 @@ package book
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
v1 "server/api/book/v1"
|
||||||
"server/internal/model"
|
"server/internal/model"
|
||||||
"server/internal/service"
|
"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{
|
out, err := service.Book().List(ctx, &model.BookListIn{
|
||||||
AuthorId: req.AuthorId,
|
|
||||||
CategoryId: req.CategoryId,
|
|
||||||
IsRecommended: req.IsRecommended,
|
|
||||||
Page: req.Page,
|
Page: req.Page,
|
||||||
Size: req.Size,
|
Size: req.Size,
|
||||||
Status: req.Status,
|
|
||||||
Title: req.Title,
|
Title: req.Title,
|
||||||
|
CategoryId: req.CategoryId,
|
||||||
|
AuthorId: req.AuthorId,
|
||||||
|
Status: req.Status,
|
||||||
|
IsRecommended: req.IsRecommended,
|
||||||
|
Sort: req.Sort,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return &v1.BookListRes{
|
|
||||||
List: out.List,
|
return &v1.ListRes{
|
||||||
Total: out.Total,
|
Total: out.Total,
|
||||||
|
List: out.List,
|
||||||
}, nil
|
}, 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/model"
|
||||||
"server/internal/service"
|
"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{
|
out, err := service.Category().Create(ctx, &model.CategoryAddIn{
|
||||||
Name: req.Name,
|
Name: req.Name,
|
||||||
Type: req.Type,
|
Channel: req.Channel,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return &v1.CategoryAddRes{
|
return &v1.AddRes{
|
||||||
Success: out.Success,
|
Success: out.Success,
|
||||||
}, nil
|
}, 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"
|
"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{
|
out, err := service.Category().Delete(ctx, &model.CategoryDelIn{
|
||||||
Id: req.Id,
|
Id: req.Id,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return &v1.CategoryDelRes{
|
return &v1.DelRes{
|
||||||
Success: out.Success,
|
Success: out.Success,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
@ -5,19 +5,19 @@ import (
|
|||||||
"server/internal/model"
|
"server/internal/model"
|
||||||
"server/internal/service"
|
"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{
|
out, err := service.Category().Update(ctx, &model.CategoryEditIn{
|
||||||
Id: req.Id,
|
Id: req.Id,
|
||||||
Name: req.Name,
|
Name: req.Name,
|
||||||
Type: req.Type,
|
Channel: req.Channel,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return &v1.CategoryEditRes{
|
return &v1.EditRes{
|
||||||
Success: out.Success,
|
Success: out.Success,
|
||||||
}, nil
|
}, 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"
|
"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{
|
out, err := service.Chapter().Create(ctx, &model.ChapterAddIn{
|
||||||
BookId: req.BookId,
|
BookId: req.BookId,
|
||||||
Content: req.Content,
|
Content: req.Content,
|
||||||
@ -21,7 +21,7 @@ func (c *ControllerV1) ChapterAdd(ctx context.Context, req *v1.ChapterAddReq) (r
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return &v1.ChapterAddRes{
|
return &v1.AddRes{
|
||||||
Success: out.Success,
|
Success: out.Success,
|
||||||
}, nil
|
}, 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"
|
"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{
|
out, err := service.Chapter().Delete(ctx, &model.ChapterDelIn{
|
||||||
Id: req.Id,
|
Id: req.Id,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
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"
|
"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{
|
out, err := service.Chapter().Update(ctx, &model.ChapterEditIn{
|
||||||
BookId: req.BookId,
|
|
||||||
Content: req.Content,
|
|
||||||
Id: req.Id,
|
Id: req.Id,
|
||||||
IsLocked: req.IsLocked,
|
BookId: req.BookId,
|
||||||
RequiredScore: req.RequiredScore,
|
|
||||||
Sort: req.Sort,
|
|
||||||
Title: req.Title,
|
Title: req.Title,
|
||||||
|
Sort: req.Sort,
|
||||||
|
IsLocked: req.IsLocked,
|
||||||
|
Content: req.Content,
|
||||||
WordCount: req.WordCount,
|
WordCount: req.WordCount,
|
||||||
|
RequiredScore: req.RequiredScore,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return &v1.ChapterEditRes{
|
return &v1.EditRes{
|
||||||
Success: out.Success,
|
Success: out.Success,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
@ -8,7 +8,7 @@ import (
|
|||||||
"server/api/chapter/v1"
|
"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{
|
out, err := service.Chapter().List(ctx, &model.ChapterListIn{
|
||||||
BookId: req.BookId,
|
BookId: req.BookId,
|
||||||
IsLocked: req.IsLocked,
|
IsLocked: req.IsLocked,
|
||||||
@ -19,7 +19,7 @@ func (c *ControllerV1) ChapterList(ctx context.Context, req *v1.ChapterListReq)
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return &v1.ChapterListRes{
|
return &v1.ListRes{
|
||||||
List: out.List,
|
List: out.List,
|
||||||
Total: out.Total,
|
Total: out.Total,
|
||||||
}, nil
|
}, nil
|
||||||
@ -9,7 +9,7 @@ import (
|
|||||||
"server/api/feedback/v1"
|
"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()
|
userId := g.RequestFromCtx(ctx).GetCtxVar("id").Int64()
|
||||||
out, err := service.Feedback().Create(ctx, &model.FeedbackAddIn{
|
out, err := service.Feedback().Create(ctx, &model.FeedbackAddIn{
|
||||||
Content: req.Content,
|
Content: req.Content,
|
||||||
@ -18,7 +18,5 @@ func (c *ControllerV1) FeedbackAdd(ctx context.Context, req *v1.FeedbackAddReq)
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return &v1.FeedbackAddRes{
|
return &v1.AddRes{Success: out.Success}, nil
|
||||||
Success: out.Success,
|
|
||||||
}, nil
|
|
||||||
}
|
}
|
||||||
@ -8,7 +8,7 @@ import (
|
|||||||
"server/api/feedback/v1"
|
"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{
|
out, err := service.Feedback().List(ctx, &model.FeedbackListIn{
|
||||||
Page: req.Page,
|
Page: req.Page,
|
||||||
Size: req.Size,
|
Size: req.Size,
|
||||||
@ -18,8 +18,8 @@ func (c *ControllerV1) FeedbackList(ctx context.Context, req *v1.FeedbackListReq
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return &v1.FeedbackListRes{
|
return &v1.ListRes{
|
||||||
List: out.List,
|
|
||||||
Total: out.Total,
|
Total: out.Total,
|
||||||
|
List: out.List,
|
||||||
}, nil
|
}, 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
|
|
||||||
}
|
|
||||||
@ -29,14 +29,16 @@ type BooksColumns struct {
|
|||||||
Status string // 状态:1=连载中,2=完结,3=下架
|
Status string // 状态:1=连载中,2=完结,3=下架
|
||||||
WordsCount string // 字数
|
WordsCount string // 字数
|
||||||
ChaptersCount string // 章节数
|
ChaptersCount string // 章节数
|
||||||
LatestChapterId string // 最新章节ID
|
|
||||||
Rating string // 评分(0.00~10.00)
|
Rating string // 评分(0.00~10.00)
|
||||||
ReadCount string // 阅读人数
|
ReadCount string // 阅读人数
|
||||||
|
CurrentReaders string // 在读人数
|
||||||
Tags string // 标签(逗号分隔)
|
Tags string // 标签(逗号分隔)
|
||||||
CreatedAt string // 创建时间
|
CreatedAt string // 创建时间
|
||||||
UpdatedAt string // 更新时间
|
UpdatedAt string // 更新时间
|
||||||
DeletedAt string // 软删除时间戳
|
DeletedAt string // 软删除时间戳
|
||||||
IsRecommended string // 是否推荐:0=否,1=是
|
IsRecommended string // 是否推荐:0=否,1=是
|
||||||
|
IsFeatured string // 是否精选:0=否,1=是
|
||||||
|
Language string // 语言,如 zh=中文,en=英文,jp=日文
|
||||||
}
|
}
|
||||||
|
|
||||||
// booksColumns holds the columns for the table books.
|
// booksColumns holds the columns for the table books.
|
||||||
@ -50,14 +52,16 @@ var booksColumns = BooksColumns{
|
|||||||
Status: "status",
|
Status: "status",
|
||||||
WordsCount: "words_count",
|
WordsCount: "words_count",
|
||||||
ChaptersCount: "chapters_count",
|
ChaptersCount: "chapters_count",
|
||||||
LatestChapterId: "latest_chapter_id",
|
|
||||||
Rating: "rating",
|
Rating: "rating",
|
||||||
ReadCount: "read_count",
|
ReadCount: "read_count",
|
||||||
|
CurrentReaders: "current_readers",
|
||||||
Tags: "tags",
|
Tags: "tags",
|
||||||
CreatedAt: "created_at",
|
CreatedAt: "created_at",
|
||||||
UpdatedAt: "updated_at",
|
UpdatedAt: "updated_at",
|
||||||
DeletedAt: "deleted_at",
|
DeletedAt: "deleted_at",
|
||||||
IsRecommended: "is_recommended",
|
IsRecommended: "is_recommended",
|
||||||
|
IsFeatured: "is_featured",
|
||||||
|
Language: "language",
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewBooksDao creates and returns a new DAO object for table data access.
|
// NewBooksDao creates and returns a new DAO object for table data access.
|
||||||
|
|||||||
@ -27,6 +27,7 @@ type BookshelvesColumns struct {
|
|||||||
LastReadChapterId string // 最后阅读章节ID
|
LastReadChapterId string // 最后阅读章节ID
|
||||||
LastReadPercent string // 阅读进度百分比(0.00~100.00)
|
LastReadPercent string // 阅读进度百分比(0.00~100.00)
|
||||||
LastReadAt string // 最后阅读时间
|
LastReadAt string // 最后阅读时间
|
||||||
|
ReadStatus string // 阅读状态:1=正在读,2=已读完,3=已收藏
|
||||||
}
|
}
|
||||||
|
|
||||||
// bookshelvesColumns holds the columns for the table bookshelves.
|
// bookshelvesColumns holds the columns for the table bookshelves.
|
||||||
@ -38,6 +39,7 @@ var bookshelvesColumns = BookshelvesColumns{
|
|||||||
LastReadChapterId: "last_read_chapter_id",
|
LastReadChapterId: "last_read_chapter_id",
|
||||||
LastReadPercent: "last_read_percent",
|
LastReadPercent: "last_read_percent",
|
||||||
LastReadAt: "last_read_at",
|
LastReadAt: "last_read_at",
|
||||||
|
ReadStatus: "read_status",
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewBookshelvesDao creates and returns a new DAO object for table data access.
|
// NewBookshelvesDao creates and returns a new DAO object for table data access.
|
||||||
|
|||||||
@ -22,20 +22,20 @@ type CategoriesDao struct {
|
|||||||
type CategoriesColumns struct {
|
type CategoriesColumns struct {
|
||||||
Id string // 分类ID
|
Id string // 分类ID
|
||||||
Name string // 分类名称
|
Name string // 分类名称
|
||||||
Type string // 分类类型:1=男频, 2=女频
|
|
||||||
CreatedAt string // 创建时间
|
CreatedAt string // 创建时间
|
||||||
UpdatedAt string // 更新时间
|
UpdatedAt string // 更新时间
|
||||||
DeletedAt string // 软删除时间戳
|
DeletedAt string // 软删除时间戳
|
||||||
|
Channel string // 频道类型:1=男频,2=女频
|
||||||
}
|
}
|
||||||
|
|
||||||
// categoriesColumns holds the columns for the table categories.
|
// categoriesColumns holds the columns for the table categories.
|
||||||
var categoriesColumns = CategoriesColumns{
|
var categoriesColumns = CategoriesColumns{
|
||||||
Id: "id",
|
Id: "id",
|
||||||
Name: "name",
|
Name: "name",
|
||||||
Type: "type",
|
|
||||||
CreatedAt: "created_at",
|
CreatedAt: "created_at",
|
||||||
UpdatedAt: "updated_at",
|
UpdatedAt: "updated_at",
|
||||||
DeletedAt: "deleted_at",
|
DeletedAt: "deleted_at",
|
||||||
|
Channel: "channel",
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewCategoriesDao creates and returns a new DAO object for table data access.
|
// NewCategoriesDao creates and returns a new DAO object for table data access.
|
||||||
|
|||||||
@ -22,9 +22,9 @@ type UserPointsLogsDao struct {
|
|||||||
type UserPointsLogsColumns struct {
|
type UserPointsLogsColumns struct {
|
||||||
Id string // 积分流水ID
|
Id string // 积分流水ID
|
||||||
UserId string // 用户ID
|
UserId string // 用户ID
|
||||||
ChangeType string // 变动类型,例如 earn、spend、refund 等
|
ChangeType string // 变动类型,1=消费(spend), 2=收入(earn)
|
||||||
PointsChange string // 积分变化数,正数增加,负数减少
|
PointsChange string // 积分变化数,正数增加,负数减少
|
||||||
RelatedOrderId string // 关联订单ID
|
RelatedOrderId string // 关联ID:当change_type=1时,为chapter_purchases.id;当change_type=2时,为advertisement_records.id
|
||||||
Description string // 变动说明
|
Description string // 变动说明
|
||||||
CreatedAt 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"
|
"github.com/gogf/gf/v2/frame/g"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ReadRecordsDao is the data access object for the table read_records.
|
// UserReadRecordsDao is the data access object for the table user_read_records.
|
||||||
type ReadRecordsDao struct {
|
type UserReadRecordsDao struct {
|
||||||
table string // table is the underlying table name of the DAO.
|
table string // table is the underlying table name of the DAO.
|
||||||
group string // group is the database configuration group name of the current 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.
|
columns UserReadRecordsColumns // columns contains all the column names of Table for convenient usage.
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReadRecordsColumns defines and stores column names for the table read_records.
|
// UserReadRecordsColumns defines and stores column names for the table user_read_records.
|
||||||
type ReadRecordsColumns struct {
|
type UserReadRecordsColumns struct {
|
||||||
Id string // 记录ID
|
Id string // 记录ID
|
||||||
UserId string // 用户ID
|
UserId string // 用户ID
|
||||||
BookId string // 小说ID
|
BookId string // 小说ID
|
||||||
ChapterId string // 章节ID
|
ChapterId string // 章节ID
|
||||||
|
Progress string // 阅读进度百分比(0-100)
|
||||||
ReadAt string // 阅读时间
|
ReadAt string // 阅读时间
|
||||||
|
CreatedAt string // 创建时间
|
||||||
|
UpdatedAt string // 更新时间
|
||||||
}
|
}
|
||||||
|
|
||||||
// readRecordsColumns holds the columns for the table read_records.
|
// userReadRecordsColumns holds the columns for the table user_read_records.
|
||||||
var readRecordsColumns = ReadRecordsColumns{
|
var userReadRecordsColumns = UserReadRecordsColumns{
|
||||||
Id: "id",
|
Id: "id",
|
||||||
UserId: "user_id",
|
UserId: "user_id",
|
||||||
BookId: "book_id",
|
BookId: "book_id",
|
||||||
ChapterId: "chapter_id",
|
ChapterId: "chapter_id",
|
||||||
|
Progress: "progress",
|
||||||
ReadAt: "read_at",
|
ReadAt: "read_at",
|
||||||
|
CreatedAt: "created_at",
|
||||||
|
UpdatedAt: "updated_at",
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewReadRecordsDao creates and returns a new DAO object for table data access.
|
// NewUserReadRecordsDao creates and returns a new DAO object for table data access.
|
||||||
func NewReadRecordsDao() *ReadRecordsDao {
|
func NewUserReadRecordsDao() *UserReadRecordsDao {
|
||||||
return &ReadRecordsDao{
|
return &UserReadRecordsDao{
|
||||||
group: "default",
|
group: "default",
|
||||||
table: "read_records",
|
table: "user_read_records",
|
||||||
columns: readRecordsColumns,
|
columns: userReadRecordsColumns,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// DB retrieves and returns the underlying raw database management object of the current DAO.
|
// 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)
|
return g.DB(dao.group)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Table returns the table name of the current DAO.
|
// Table returns the table name of the current DAO.
|
||||||
func (dao *ReadRecordsDao) Table() string {
|
func (dao *UserReadRecordsDao) Table() string {
|
||||||
return dao.table
|
return dao.table
|
||||||
}
|
}
|
||||||
|
|
||||||
// Columns returns all column names of the current DAO.
|
// Columns returns all column names of the current DAO.
|
||||||
func (dao *ReadRecordsDao) Columns() ReadRecordsColumns {
|
func (dao *UserReadRecordsDao) Columns() UserReadRecordsColumns {
|
||||||
return dao.columns
|
return dao.columns
|
||||||
}
|
}
|
||||||
|
|
||||||
// Group returns the database configuration group name of the current DAO.
|
// Group returns the database configuration group name of the current DAO.
|
||||||
func (dao *ReadRecordsDao) Group() string {
|
func (dao *UserReadRecordsDao) Group() string {
|
||||||
return dao.group
|
return dao.group
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ctx creates and returns a Model for the current DAO. It automatically sets the context for the current operation.
|
// 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)
|
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,
|
// Note: Do not commit or roll back the transaction in function f,
|
||||||
// as it is automatically handled by this function.
|
// 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)
|
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/model/do"
|
||||||
"server/internal/service"
|
"server/internal/service"
|
||||||
"server/utility/ecode"
|
"server/utility/ecode"
|
||||||
|
|
||||||
|
"github.com/gogf/gf/v2/database/gdb"
|
||||||
)
|
)
|
||||||
|
|
||||||
type sBook struct{}
|
type sBook struct{}
|
||||||
@ -38,7 +40,10 @@ func (s *sBook) List(ctx context.Context, in *model.BookListIn) (out *model.Book
|
|||||||
if in.IsRecommended != 0 {
|
if in.IsRecommended != 0 {
|
||||||
m = m.Where(dao.Books.Columns().IsRecommended, in.IsRecommended)
|
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
|
||||||
}
|
}
|
||||||
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")
|
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 {
|
if err != nil {
|
||||||
return nil, ecode.Fail.Sub("book_delete_failed")
|
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, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return &model.BookCRUDOut{
|
return &model.BookCRUDOut{
|
||||||
Success: true,
|
Success: true,
|
||||||
}, nil
|
}, 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/model/do"
|
||||||
"server/internal/service"
|
"server/internal/service"
|
||||||
"server/utility/ecode"
|
"server/utility/ecode"
|
||||||
|
|
||||||
|
"github.com/gogf/gf/v2/database/gdb"
|
||||||
)
|
)
|
||||||
|
|
||||||
type sCategory struct {
|
type sCategory struct {
|
||||||
@ -24,8 +26,8 @@ func init() {
|
|||||||
func (s *sCategory) List(ctx context.Context, in *model.CategoryListIn) (out *model.CategoryListOut, err error) {
|
func (s *sCategory) List(ctx context.Context, in *model.CategoryListIn) (out *model.CategoryListOut, err error) {
|
||||||
out = &model.CategoryListOut{}
|
out = &model.CategoryListOut{}
|
||||||
m := dao.Categories.Ctx(ctx)
|
m := dao.Categories.Ctx(ctx)
|
||||||
if in.Type != 0 {
|
if in.Channel != 0 {
|
||||||
m = m.Where(dao.Categories.Columns().Type, in.Type)
|
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 {
|
if err = m.Page(in.Page, in.Size).ScanAndCount(&out.List, &out.Total, false); err != nil {
|
||||||
return
|
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) {
|
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).
|
exist, err := dao.Categories.Ctx(ctx).
|
||||||
Where(dao.Categories.Columns().Name, in.Name).
|
Where(dao.Categories.Columns().Name, in.Name).
|
||||||
Exist()
|
Exist()
|
||||||
@ -49,7 +48,7 @@ func (s *sCategory) Create(ctx context.Context, in *model.CategoryAddIn) (out *m
|
|||||||
|
|
||||||
if _, err := dao.Categories.Ctx(ctx).Data(do.Categories{
|
if _, err := dao.Categories.Ctx(ctx).Data(do.Categories{
|
||||||
Name: in.Name,
|
Name: in.Name,
|
||||||
Type: in.Type,
|
Channel: in.Channel,
|
||||||
}).Insert(); err != nil {
|
}).Insert(); err != nil {
|
||||||
return nil, ecode.Fail.Sub("category_create_failed")
|
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) {
|
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).
|
exist, err := dao.Categories.Ctx(ctx).
|
||||||
WherePri(in.Id).
|
WherePri(in.Id).
|
||||||
Exist()
|
Exist()
|
||||||
@ -89,7 +85,7 @@ func (s *sCategory) Update(ctx context.Context, in *model.CategoryEditIn) (out *
|
|||||||
WherePri(in.Id).
|
WherePri(in.Id).
|
||||||
Data(do.Categories{
|
Data(do.Categories{
|
||||||
Name: in.Name,
|
Name: in.Name,
|
||||||
Type: in.Type,
|
Channel: in.Channel,
|
||||||
}).Update()
|
}).Update()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, ecode.Fail.Sub("category_update_failed")
|
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")
|
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 {
|
if err != nil {
|
||||||
return nil, ecode.Fail.Sub("category_delete_failed")
|
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, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return &model.CategoryCRUDOut{
|
return &model.CategoryCRUDOut{
|
||||||
|
|||||||
@ -5,8 +5,12 @@ import (
|
|||||||
"server/internal/dao"
|
"server/internal/dao"
|
||||||
"server/internal/model"
|
"server/internal/model"
|
||||||
"server/internal/model/do"
|
"server/internal/model/do"
|
||||||
|
"server/internal/model/entity"
|
||||||
"server/internal/service"
|
"server/internal/service"
|
||||||
"server/utility/ecode"
|
"server/utility/ecode"
|
||||||
|
|
||||||
|
"github.com/gogf/gf/v2/database/gdb"
|
||||||
|
"github.com/gogf/gf/v2/os/gtime"
|
||||||
)
|
)
|
||||||
|
|
||||||
type sChapter struct{}
|
type sChapter struct{}
|
||||||
@ -38,6 +42,7 @@ func (s *sChapter) List(ctx context.Context, in *model.ChapterListIn) (out *mode
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Create creates a new chapter
|
||||||
func (s *sChapter) Create(ctx context.Context, in *model.ChapterAddIn) (out *model.ChapterCRUDOut, err error) {
|
func (s *sChapter) Create(ctx context.Context, in *model.ChapterAddIn) (out *model.ChapterCRUDOut, err error) {
|
||||||
if _, err := dao.Chapters.Ctx(ctx).Data(do.Chapters{
|
if _, err := dao.Chapters.Ctx(ctx).Data(do.Chapters{
|
||||||
BookId: in.BookId,
|
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
|
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) {
|
func (s *sChapter) Update(ctx context.Context, in *model.ChapterEditIn) (out *model.ChapterCRUDOut, err error) {
|
||||||
exist, err := dao.Chapters.Ctx(ctx).
|
exist, err := dao.Chapters.Ctx(ctx).
|
||||||
WherePri(in.Id).
|
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
|
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) {
|
func (s *sChapter) Delete(ctx context.Context, in *model.ChapterDelIn) (out *model.ChapterCRUDOut, err error) {
|
||||||
exist, err := dao.Chapters.Ctx(ctx).
|
exist, err := dao.Chapters.Ctx(ctx).
|
||||||
WherePri(in.Id).
|
WherePri(in.Id).
|
||||||
@ -90,9 +97,431 @@ func (s *sChapter) Delete(ctx context.Context, in *model.ChapterDelIn) (out *mod
|
|||||||
if !exist {
|
if !exist {
|
||||||
return nil, ecode.NotFound.Sub("chapter_not_found")
|
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 {
|
if err != nil {
|
||||||
return nil, ecode.Fail.Sub("chapter_delete_failed")
|
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, err
|
||||||
|
}
|
||||||
|
|
||||||
return &model.ChapterCRUDOut{Success: true}, nil
|
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 {
|
if in.Status != 0 {
|
||||||
m = m.Where(dao.Feedbacks.Columns().Status, in.Status)
|
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
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
|
|||||||
@ -6,11 +6,13 @@ package logic
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
_ "server/internal/logic/admin"
|
_ "server/internal/logic/admin"
|
||||||
|
_ "server/internal/logic/author"
|
||||||
_ "server/internal/logic/book"
|
_ "server/internal/logic/book"
|
||||||
|
_ "server/internal/logic/bookshelve"
|
||||||
_ "server/internal/logic/category"
|
_ "server/internal/logic/category"
|
||||||
_ "server/internal/logic/chapter"
|
_ "server/internal/logic/chapter"
|
||||||
_ "server/internal/logic/feedback"
|
_ "server/internal/logic/feedback"
|
||||||
_ "server/internal/logic/read_record"
|
|
||||||
_ "server/internal/logic/tag"
|
|
||||||
_ "server/internal/logic/user"
|
_ "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/encrypt"
|
||||||
"server/utility/jwt"
|
"server/utility/jwt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/gogf/gf/v2/database/gdb"
|
||||||
)
|
)
|
||||||
|
|
||||||
type sUser struct{}
|
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) {
|
if !encrypt.ComparePassword(entityUser.PasswordHash, in.Password) {
|
||||||
return nil, ecode.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 {
|
if err != nil {
|
||||||
return nil, ecode.Fail.Sub("token_generation_failed")
|
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) {
|
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
|
return &model.UserDeleteOut{Success: true}, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,11 +5,19 @@ import (
|
|||||||
"server/internal/dao"
|
"server/internal/dao"
|
||||||
"server/internal/model"
|
"server/internal/model"
|
||||||
"server/internal/model/do"
|
"server/internal/model/do"
|
||||||
|
"server/internal/service"
|
||||||
"server/utility/ecode"
|
"server/utility/ecode"
|
||||||
)
|
)
|
||||||
|
|
||||||
type sUserFollowAuthor struct{}
|
type sUserFollowAuthor struct{}
|
||||||
|
|
||||||
|
func New() service.IUserFollowAuthor {
|
||||||
|
return &sUserFollowAuthor{}
|
||||||
|
}
|
||||||
|
func init() {
|
||||||
|
service.RegisterUserFollowAuthor(New())
|
||||||
|
}
|
||||||
|
|
||||||
// List retrieves a paginated list of user follow authors
|
// List retrieves a paginated list of user follow authors
|
||||||
func (s *sUserFollowAuthor) List(ctx context.Context, in *model.UserFollowAuthorListIn) (out *model.UserFollowAuthorListOut, err error) {
|
func (s *sUserFollowAuthor) List(ctx context.Context, in *model.UserFollowAuthorListIn) (out *model.UserFollowAuthorListOut, err error) {
|
||||||
out = &model.UserFollowAuthorListOut{}
|
out = &model.UserFollowAuthorListOut{}
|
||||||
@ -64,3 +72,27 @@ func (s *sUserFollowAuthor) Delete(ctx context.Context, in *model.UserFollowAuth
|
|||||||
}
|
}
|
||||||
return &model.UserFollowAuthorCRUDOut{Success: true}, nil
|
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
|
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 {
|
type Book struct {
|
||||||
g.Meta `orm:"table:books"`
|
g.Meta `orm:"table:books"`
|
||||||
Id int64 `json:"id"`
|
Id int64 `json:"id" orm:"id"`
|
||||||
AuthorId int64 `json:"authorId"`
|
AuthorId int64 `json:"authorId" orm:"author_id"`
|
||||||
CategoryId int64 `json:"categoryId"`
|
Author Author `json:"author" orm:"with:id = author_id"`
|
||||||
Title string `json:"title"`
|
CategoryId int64 `json:"categoryId" orm:"category_id"`
|
||||||
CoverUrl string `json:"coverUrl"`
|
Category Category `json:"category" orm:"with:id = category_id"`
|
||||||
Description string `json:"description"`
|
Title string `json:"title" orm:"title"`
|
||||||
Status int `json:"status"`
|
CoverUrl string `json:"coverUrl" orm:"cover_url"`
|
||||||
WordsCount int `json:"wordsCount"`
|
Description string `json:"description" orm:"description"`
|
||||||
ChaptersCount int `json:"chaptersCount"`
|
Status int `json:"status" orm:"status"`
|
||||||
LatestChapterId int64 `json:"latestChapterId"`
|
WordsCount int `json:"wordsCount" orm:"words_count"`
|
||||||
Rating float64 `json:"rating"`
|
ChaptersCount int `json:"chaptersCount" orm:"chapters_count"`
|
||||||
ReadCount int64 `json:"readCount"`
|
LatestChapterId int64 `json:"latestChapterId" orm:"latest_chapter_id"`
|
||||||
Tags string `json:"tags"`
|
Rating float64 `json:"rating" orm:"rating"`
|
||||||
IsRecommended int `json:"isRecommended"`
|
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 {
|
type BookListIn struct {
|
||||||
@ -28,6 +46,7 @@ type BookListIn struct {
|
|||||||
AuthorId int64
|
AuthorId int64
|
||||||
Status int
|
Status int
|
||||||
IsRecommended int
|
IsRecommended int
|
||||||
|
Sort string
|
||||||
}
|
}
|
||||||
type BookListOut struct {
|
type BookListOut struct {
|
||||||
Total int
|
Total int
|
||||||
@ -43,6 +62,8 @@ type BookAddIn struct {
|
|||||||
Status int
|
Status int
|
||||||
Tags string
|
Tags string
|
||||||
IsRecommended int
|
IsRecommended int
|
||||||
|
IsFeatured int
|
||||||
|
Language string
|
||||||
}
|
}
|
||||||
type BookEditIn struct {
|
type BookEditIn struct {
|
||||||
Id int64
|
Id int64
|
||||||
@ -54,6 +75,8 @@ type BookEditIn struct {
|
|||||||
Status int
|
Status int
|
||||||
Tags string
|
Tags string
|
||||||
IsRecommended int
|
IsRecommended int
|
||||||
|
IsFeatured int
|
||||||
|
Language string
|
||||||
}
|
}
|
||||||
type BookDelIn struct {
|
type BookDelIn struct {
|
||||||
Id int64
|
Id int64
|
||||||
@ -62,3 +85,166 @@ type BookDelIn struct {
|
|||||||
type BookCRUDOut struct {
|
type BookCRUDOut struct {
|
||||||
Success bool
|
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
|
||||||
|
}
|
||||||
@ -4,16 +4,16 @@ import "github.com/gogf/gf/v2/frame/g"
|
|||||||
|
|
||||||
type Category struct {
|
type Category struct {
|
||||||
g.Meta `orm:"table:categories"`
|
g.Meta `orm:"table:categories"`
|
||||||
Id int64 `json:"id" orm:"id"` // 分类ID
|
Id int64 `json:"id" orm:"id"`
|
||||||
Name string `json:"name" orm:"name"` // 分类名称
|
Name string `json:"name" orm:"name"`
|
||||||
Type int `json:type orm:"type"` // 类型,1 男频,2 女频
|
Channel int `json:"channel" orm:"channel"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type CategoryListIn struct {
|
type CategoryListIn struct {
|
||||||
Page int
|
Page int
|
||||||
Size int
|
Size int
|
||||||
Name string
|
Name string
|
||||||
Type int
|
Channel int
|
||||||
}
|
}
|
||||||
type CategoryListOut struct {
|
type CategoryListOut struct {
|
||||||
Total int
|
Total int
|
||||||
@ -22,15 +22,15 @@ type CategoryListOut struct {
|
|||||||
|
|
||||||
type CategoryAddIn struct {
|
type CategoryAddIn struct {
|
||||||
Name string
|
Name string
|
||||||
Type int // 类型,1 男频,2 女频
|
Channel int
|
||||||
}
|
}
|
||||||
type CategoryEditIn struct {
|
type CategoryEditIn struct {
|
||||||
Id int
|
Id int64
|
||||||
Name string
|
Name string
|
||||||
Type int // 类型,1 男频,2 女频
|
Channel int
|
||||||
}
|
}
|
||||||
type CategoryDelIn struct {
|
type CategoryDelIn struct {
|
||||||
Id int
|
Id int64
|
||||||
}
|
}
|
||||||
|
|
||||||
type CategoryCRUDOut struct {
|
type CategoryCRUDOut struct {
|
||||||
|
|||||||
@ -1,17 +1,20 @@
|
|||||||
package model
|
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 {
|
type Chapter struct {
|
||||||
g.Meta `orm:"table:chapters"`
|
g.Meta `orm:"table:chapters"`
|
||||||
Id int64 `json:"id"`
|
Id int64 `json:"id" orm:"id"`
|
||||||
BookId int64 `json:"bookId"`
|
BookId int64 `json:"bookId" orm:"book_id"`
|
||||||
Title string `json:"title"`
|
Title string `json:"title" orm:"title"`
|
||||||
Content string `json:"content"`
|
Content string `json:"content" orm:"content"`
|
||||||
WordCount int `json:"wordCount"`
|
WordCount int `json:"wordCount" orm:"word_count"`
|
||||||
Sort int `json:"sort"`
|
Sort int `json:"sort" orm:"sort"`
|
||||||
IsLocked int `json:"isLocked"`
|
IsLocked int `json:"isLocked" orm:"is_locked"`
|
||||||
RequiredScore int `json:"requiredScore"`
|
RequiredScore int `json:"requiredScore" orm:"required_score"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ChapterListIn struct {
|
type ChapterListIn struct {
|
||||||
@ -52,3 +55,73 @@ type ChapterDelIn struct {
|
|||||||
type ChapterCRUDOut struct {
|
type ChapterCRUDOut struct {
|
||||||
Success bool
|
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:"是否成功"`
|
||||||
|
}
|
||||||
|
|||||||
@ -21,12 +21,14 @@ type Books struct {
|
|||||||
Status interface{} // 状态:1=连载中,2=完结,3=下架
|
Status interface{} // 状态:1=连载中,2=完结,3=下架
|
||||||
WordsCount interface{} // 字数
|
WordsCount interface{} // 字数
|
||||||
ChaptersCount interface{} // 章节数
|
ChaptersCount interface{} // 章节数
|
||||||
LatestChapterId interface{} // 最新章节ID
|
|
||||||
Rating interface{} // 评分(0.00~10.00)
|
Rating interface{} // 评分(0.00~10.00)
|
||||||
ReadCount interface{} // 阅读人数
|
ReadCount interface{} // 阅读人数
|
||||||
|
CurrentReaders interface{} // 在读人数
|
||||||
Tags interface{} // 标签(逗号分隔)
|
Tags interface{} // 标签(逗号分隔)
|
||||||
CreatedAt *gtime.Time // 创建时间
|
CreatedAt *gtime.Time // 创建时间
|
||||||
UpdatedAt *gtime.Time // 更新时间
|
UpdatedAt *gtime.Time // 更新时间
|
||||||
DeletedAt *gtime.Time // 软删除时间戳
|
DeletedAt *gtime.Time // 软删除时间戳
|
||||||
IsRecommended interface{} // 是否推荐:0=否,1=是
|
IsRecommended interface{} // 是否推荐:0=否,1=是
|
||||||
|
IsFeatured interface{} // 是否精选:0=否,1=是
|
||||||
|
Language interface{} // 语言,如 zh=中文,en=英文,jp=日文
|
||||||
}
|
}
|
||||||
|
|||||||
@ -19,4 +19,5 @@ type Bookshelves struct {
|
|||||||
LastReadChapterId interface{} // 最后阅读章节ID
|
LastReadChapterId interface{} // 最后阅读章节ID
|
||||||
LastReadPercent interface{} // 阅读进度百分比(0.00~100.00)
|
LastReadPercent interface{} // 阅读进度百分比(0.00~100.00)
|
||||||
LastReadAt *gtime.Time // 最后阅读时间
|
LastReadAt *gtime.Time // 最后阅读时间
|
||||||
|
ReadStatus interface{} // 阅读状态:1=正在读,2=已读完,3=已收藏
|
||||||
}
|
}
|
||||||
|
|||||||
@ -14,8 +14,8 @@ type Categories struct {
|
|||||||
g.Meta `orm:"table:categories, do:true"`
|
g.Meta `orm:"table:categories, do:true"`
|
||||||
Id interface{} // 分类ID
|
Id interface{} // 分类ID
|
||||||
Name interface{} // 分类名称
|
Name interface{} // 分类名称
|
||||||
Type interface{} // 分类类型:1=男频, 2=女频
|
|
||||||
CreatedAt *gtime.Time // 创建时间
|
CreatedAt *gtime.Time // 创建时间
|
||||||
UpdatedAt *gtime.Time // 更新时间
|
UpdatedAt *gtime.Time // 更新时间
|
||||||
DeletedAt *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"`
|
g.Meta `orm:"table:user_points_logs, do:true"`
|
||||||
Id interface{} // 积分流水ID
|
Id interface{} // 积分流水ID
|
||||||
UserId interface{} // 用户ID
|
UserId interface{} // 用户ID
|
||||||
ChangeType interface{} // 变动类型,例如 earn、spend、refund 等
|
ChangeType interface{} // 变动类型,1=消费(spend), 2=收入(earn)
|
||||||
PointsChange interface{} // 积分变化数,正数增加,负数减少
|
PointsChange interface{} // 积分变化数,正数增加,负数减少
|
||||||
RelatedOrderId interface{} // 关联订单ID
|
RelatedOrderId interface{} // 关联ID:当change_type=1时,为chapter_purchases.id;当change_type=2时,为advertisement_records.id
|
||||||
Description interface{} // 变动说明
|
Description interface{} // 变动说明
|
||||||
CreatedAt *gtime.Time // 变动时间
|
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"
|
"github.com/gogf/gf/v2/os/gtime"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ReadRecords is the golang structure of table read_records for DAO operations like Where/Data.
|
// UserReadRecords is the golang structure of table user_read_records for DAO operations like Where/Data.
|
||||||
type ReadRecords struct {
|
type UserReadRecords struct {
|
||||||
g.Meta `orm:"table:read_records, do:true"`
|
g.Meta `orm:"table:user_read_records, do:true"`
|
||||||
Id interface{} // 记录ID
|
Id interface{} // 记录ID
|
||||||
UserId interface{} // 用户ID
|
UserId interface{} // 用户ID
|
||||||
BookId interface{} // 小说ID
|
BookId interface{} // 小说ID
|
||||||
ChapterId interface{} // 章节ID
|
ChapterId interface{} // 章节ID
|
||||||
|
Progress interface{} // 阅读进度百分比(0-100)
|
||||||
ReadAt *gtime.Time // 阅读时间
|
ReadAt *gtime.Time // 阅读时间
|
||||||
|
CreatedAt *gtime.Time // 创建时间
|
||||||
|
UpdatedAt *gtime.Time // 更新时间
|
||||||
}
|
}
|
||||||
@ -19,12 +19,14 @@ type Books struct {
|
|||||||
Status int `json:"status" orm:"status" description:"状态:1=连载中,2=完结,3=下架"` // 状态:1=连载中,2=完结,3=下架
|
Status int `json:"status" orm:"status" description:"状态:1=连载中,2=完结,3=下架"` // 状态:1=连载中,2=完结,3=下架
|
||||||
WordsCount int `json:"wordsCount" orm:"words_count" description:"字数"` // 字数
|
WordsCount int `json:"wordsCount" orm:"words_count" description:"字数"` // 字数
|
||||||
ChaptersCount int `json:"chaptersCount" orm:"chapters_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)
|
Rating float64 `json:"rating" orm:"rating" description:"评分(0.00~10.00)"` // 评分(0.00~10.00)
|
||||||
ReadCount int64 `json:"readCount" orm:"read_count" description:"阅读人数"` // 阅读人数
|
ReadCount int64 `json:"readCount" orm:"read_count" description:"阅读人数"` // 阅读人数
|
||||||
|
CurrentReaders int64 `json:"currentReaders" orm:"current_readers" description:"在读人数"` // 在读人数
|
||||||
Tags string `json:"tags" orm:"tags" description:"标签(逗号分隔)"` // 标签(逗号分隔)
|
Tags string `json:"tags" orm:"tags" description:"标签(逗号分隔)"` // 标签(逗号分隔)
|
||||||
CreatedAt *gtime.Time `json:"createdAt" orm:"created_at" description:"创建时间"` // 创建时间
|
CreatedAt *gtime.Time `json:"createdAt" orm:"created_at" description:"创建时间"` // 创建时间
|
||||||
UpdatedAt *gtime.Time `json:"updatedAt" orm:"updated_at" description:"更新时间"` // 更新时间
|
UpdatedAt *gtime.Time `json:"updatedAt" orm:"updated_at" description:"更新时间"` // 更新时间
|
||||||
DeletedAt *gtime.Time `json:"deletedAt" orm:"deleted_at" description:"软删除时间戳"` // 软删除时间戳
|
DeletedAt *gtime.Time `json:"deletedAt" orm:"deleted_at" description:"软删除时间戳"` // 软删除时间戳
|
||||||
IsRecommended int `json:"isRecommended" orm:"is_recommended" description:"是否推荐:0=否,1=是"` // 是否推荐:0=否,1=是
|
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=日文
|
||||||
}
|
}
|
||||||
|
|||||||
@ -17,4 +17,5 @@ type Bookshelves struct {
|
|||||||
LastReadChapterId int64 `json:"lastReadChapterId" orm:"last_read_chapter_id" description:"最后阅读章节ID"` // 最后阅读章节ID
|
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)
|
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:"最后阅读时间"` // 最后阅读时间
|
LastReadAt *gtime.Time `json:"lastReadAt" orm:"last_read_at" description:"最后阅读时间"` // 最后阅读时间
|
||||||
|
ReadStatus int `json:"readStatus" orm:"read_status" description:"阅读状态:1=正在读,2=已读完,3=已收藏"` // 阅读状态:1=正在读,2=已读完,3=已收藏
|
||||||
}
|
}
|
||||||
|
|||||||
@ -12,8 +12,8 @@ import (
|
|||||||
type Categories struct {
|
type Categories struct {
|
||||||
Id int64 `json:"id" orm:"id" description:"分类ID"` // 分类ID
|
Id int64 `json:"id" orm:"id" description:"分类ID"` // 分类ID
|
||||||
Name string `json:"name" orm:"name" description:"分类名称"` // 分类名称
|
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:"创建时间"` // 创建时间
|
CreatedAt *gtime.Time `json:"createdAt" orm:"created_at" description:"创建时间"` // 创建时间
|
||||||
UpdatedAt *gtime.Time `json:"updatedAt" orm:"updated_at" description:"更新时间"` // 更新时间
|
UpdatedAt *gtime.Time `json:"updatedAt" orm:"updated_at" description:"更新时间"` // 更新时间
|
||||||
DeletedAt *gtime.Time `json:"deletedAt" orm:"deleted_at" description:"软删除时间戳"` // 软删除时间戳
|
DeletedAt *gtime.Time `json:"deletedAt" orm:"deleted_at" description:"软删除时间戳"` // 软删除时间戳
|
||||||
|
Channel int `json:"channel" orm:"channel" description:"频道类型:1=男频,2=女频"` // 频道类型:1=男频,2=女频
|
||||||
}
|
}
|
||||||
|
|||||||
@ -12,9 +12,9 @@ import (
|
|||||||
type UserPointsLogs struct {
|
type UserPointsLogs struct {
|
||||||
Id int64 `json:"id" orm:"id" description:"积分流水ID"` // 积分流水ID
|
Id int64 `json:"id" orm:"id" description:"积分流水ID"` // 积分流水ID
|
||||||
UserId int64 `json:"userId" orm:"user_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 等
|
ChangeType int `json:"changeType" orm:"change_type" description:"变动类型,1=消费(spend), 2=收入(earn)"` // 变动类型,1=消费(spend), 2=收入(earn)
|
||||||
PointsChange int `json:"pointsChange" orm:"points_change" description:"积分变化数,正数增加,负数减少"` // 积分变化数,正数增加,负数减少
|
PointsChange int `json:"pointsChange" orm:"points_change" description:"积分变化数,正数增加,负数减少"` // 积分变化数,正数增加,负数减少
|
||||||
RelatedOrderId int64 `json:"relatedOrderId" orm:"related_order_id" description:"关联订单ID"` // 关联订单ID
|
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:"变动说明"` // 变动说明
|
Description string `json:"description" orm:"description" description:"变动说明"` // 变动说明
|
||||||
CreatedAt *gtime.Time `json:"createdAt" orm:"created_at" description:"变动时间"` // 变动时间
|
CreatedAt *gtime.Time `json:"createdAt" orm:"created_at" description:"变动时间"` // 变动时间
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,11 +8,11 @@ import (
|
|||||||
"github.com/gogf/gf/v2/os/gtime"
|
"github.com/gogf/gf/v2/os/gtime"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ReadRecords is the golang structure for table read_records.
|
// UserReadHistory is the golang structure for table user_read_history.
|
||||||
type ReadRecords struct {
|
type UserReadHistory struct {
|
||||||
Id int64 `json:"id" orm:"id" description:"记录ID"` // 记录ID
|
Id int64 `json:"id" orm:"id" description:"历史记录ID"` // 历史记录ID
|
||||||
UserId int64 `json:"userId" orm:"user_id" description:"用户ID"` // 用户ID
|
UserId int64 `json:"userId" orm:"user_id" description:"用户ID"` // 用户ID
|
||||||
BookId int64 `json:"bookId" orm:"book_id" description:"小说ID"` // 小说ID
|
BookId int64 `json:"bookId" orm:"book_id" description:"小说ID"` // 小说ID
|
||||||
ChapterId int64 `json:"chapterId" orm:"chapter_id" description:"章节ID"` // 章节ID
|
ChapterId int64 `json:"chapterId" orm:"chapter_id" description:"最后阅读章节ID"` // 最后阅读章节ID
|
||||||
ReadAt *gtime.Time `json:"readAt" orm:"read_at" description:"阅读时间"` // 阅读时间
|
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
|
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 {
|
type Feedback struct {
|
||||||
g.Meta `orm:"table:feedbacks"`
|
g.Meta `orm:"table:feedbacks"`
|
||||||
Id int64 `json:"id"`
|
Id int64 `json:"id" orm:"id"`
|
||||||
UserId int64 `json:"userId"`
|
UserId int64 `json:"userId" orm:"user_id"`
|
||||||
Content string `json:"content"`
|
Content string `json:"content" orm:"content"`
|
||||||
Status int `json:"status"`
|
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 {
|
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 {
|
type Tag struct {
|
||||||
g.Meta `orm:"table:tags"`
|
g.Meta `orm:"table:tags"`
|
||||||
Id int64 `json:"id"`
|
Id int64 `json:"id" orm:"id"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name" orm:"name"`
|
||||||
Type int `json:"type"` // 1=主题, 2=角色, 3=情节
|
Type int `json:"type" orm:"type"` // 1=主题, 2=角色, 3=情节
|
||||||
}
|
}
|
||||||
|
|
||||||
type TagListIn struct {
|
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