书籍列表接口新增参数

This commit is contained in:
2025-08-13 15:19:42 +08:00
parent 6ccc87f2bf
commit 8afe651c64
201 changed files with 6987 additions and 1066 deletions

View File

@ -2,6 +2,7 @@ package cmd
import (
"context"
"server/internal/controller/activity"
"server/internal/controller/admin"
"server/internal/controller/auth"
"server/internal/controller/author"
@ -9,6 +10,9 @@ import (
"server/internal/controller/category"
"server/internal/controller/chapter"
"server/internal/controller/feedback"
"server/internal/controller/recommend"
"server/internal/controller/system"
"server/internal/controller/task"
"server/internal/controller/user"
"server/internal/middleware"
@ -42,6 +46,10 @@ var (
chapter.NewV1(),
feedback.NewV1(),
user.NewV1(),
recommend.NewV1(),
activity.NewV1(),
task.NewV1(),
system.NewV1(),
)
})
})

38
internal/consts/ads.go Normal file
View File

@ -0,0 +1,38 @@
package consts
// AdState 广告状态枚举
type AdState int
const (
StateFetchFailed AdState = iota + 1 // 拉取失败
StateFetchSuccess // 拉取成功
StateDisplayFailed // 显示失败
StateDisplaySuccess // 显示成功
StateNotWatched // 未观看完成
StateWatched // 观看完成
StateNotClicked // 未点击
StateClicked // 已点击
StateNotDownloaded // 未下载
StateDownloaded // 已下载
)
// GetStateDescription 获取状态描述
func GetStateDescription(state AdState) string {
descriptions := map[AdState]string{
StateFetchFailed: "拉取失败",
StateFetchSuccess: "拉取成功",
StateDisplayFailed: "显示失败",
StateDisplaySuccess: "显示成功",
StateNotWatched: "未观看完成",
StateWatched: "观看完成",
StateNotClicked: "未点击",
StateClicked: "已点击",
StateNotDownloaded: "未下载",
StateDownloaded: "已下载",
}
if desc, exists := descriptions[state]; exists {
return desc
}
return "未知状态"
}

View File

@ -0,0 +1,5 @@
// =================================================================================
// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish.
// =================================================================================
package activity

View File

@ -0,0 +1,15 @@
// =================================================================================
// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish.
// =================================================================================
package activity
import (
"server/api/activity"
)
type ControllerV1 struct{}
func NewV1() activity.IActivityV1 {
return &ControllerV1{}
}

View File

@ -0,0 +1,23 @@
package activity
import (
"context"
v1 "server/api/activity/v1"
"server/internal/model"
"server/internal/service"
)
func (c *ControllerV1) ItemAdd(ctx context.Context, req *v1.ItemAddReq) (res *v1.ItemAddRes, err error) {
id, err := service.SignInRewardDetails().Create(ctx, &model.SignInRewardDetail{
RuleId: req.RuleId,
DayNumber: req.DayNumber,
RewardType: req.RewardType,
Quantity: req.Quantity,
Status: req.Status,
})
if err != nil {
return nil, err
}
return &v1.ItemAddRes{Id: id, Success: true}, nil
}

View File

@ -0,0 +1,17 @@
package activity
import (
"context"
v1 "server/api/activity/v1"
"server/internal/model"
"server/internal/service"
)
func (c *ControllerV1) ItemDel(ctx context.Context, req *v1.ItemDelReq) (res *v1.ItemDelRes, err error) {
out, err := service.SignInRewardDetails().Delete(ctx, &model.SignInRewardDetailDeleteIn{Id: req.Id})
if err != nil {
return nil, err
}
return &v1.ItemDelRes{Success: out.Success}, nil
}

View File

@ -0,0 +1,24 @@
package activity
import (
"context"
v1 "server/api/activity/v1"
"server/internal/model"
"server/internal/service"
)
func (c *ControllerV1) ItemEdit(ctx context.Context, req *v1.ItemEditReq) (res *v1.ItemEditRes, err error) {
err = service.SignInRewardDetails().Update(ctx, &model.SignInRewardDetail{
Id: req.Id,
RuleId: req.RuleId,
DayNumber: req.DayNumber,
RewardType: req.RewardType,
Quantity: req.Quantity,
Status: req.Status,
})
if err != nil {
return nil, err
}
return &v1.ItemEditRes{Success: true}, nil
}

View File

@ -0,0 +1,17 @@
package activity
import (
"context"
v1 "server/api/activity/v1"
"server/internal/model"
"server/internal/service"
)
func (c *ControllerV1) ItemGet(ctx context.Context, req *v1.ItemGetReq) (res *v1.ItemGetRes, err error) {
out, err := service.SignInRewardDetails().Get(ctx, &model.SignInRewardDetailGetIn{Id: req.Id})
if err != nil {
return nil, err
}
return &v1.ItemGetRes{SignInRewardDetail: out.SignInRewardDetail}, nil
}

View File

@ -0,0 +1,20 @@
package activity
import (
"context"
v1 "server/api/activity/v1"
"server/internal/model"
"server/internal/service"
)
func (c *ControllerV1) ItemList(ctx context.Context, req *v1.ItemListReq) (res *v1.ItemListRes, err error) {
out, err := service.SignInRewardDetails().List(ctx, &model.SignInRewardDetailListIn{
RuleId: req.RuleId,
})
if err != nil {
return nil, err
}
return &v1.ItemListRes{
List: out.List,
}, nil
}

View File

@ -0,0 +1,19 @@
package activity
import (
"context"
v1 "server/api/activity/v1"
"server/internal/model"
"server/internal/service"
)
func (c *ControllerV1) ItemSetStatus(ctx context.Context, req *v1.ItemSetStatusReq) (res *v1.ItemSetStatusRes, err error) {
out, err := service.SignInRewardDetails().SetStatus(ctx, &model.SignInRewardDetailSetStatusIn{
Id: req.Id,
Status: req.Status,
})
if err != nil {
return nil, err
}
return &v1.ItemSetStatusRes{Success: out.Success}, nil
}

View File

@ -0,0 +1,23 @@
package activity
import (
"context"
"server/internal/model"
"server/internal/service"
v1 "server/api/activity/v1"
)
func (c *ControllerV1) RuleAdd(ctx context.Context, req *v1.RuleAddReq) (res *v1.RuleAddRes, err error) {
out, err := service.SignInRewardRules().Create(ctx, &model.SignInRewardRulesCreateIn{
RuleName: req.RuleName,
StartDate: req.StartDate,
EndDate: req.EndDate,
CycleDays: req.CycleDays,
Status: req.Status,
})
if err != nil {
return nil, err
}
return &v1.RuleAddRes{Success: out.Success}, nil
}

View File

@ -0,0 +1,19 @@
package activity
import (
"context"
"server/internal/model"
"server/internal/service"
"server/api/activity/v1"
)
func (c *ControllerV1) RuleDel(ctx context.Context, req *v1.RuleDelReq) (res *v1.RuleDelRes, err error) {
out, err := service.SignInRewardRules().Delete(ctx, &model.SignInRewardRulesDeleteIn{
Id: req.Id,
})
if err != nil {
return nil, err
}
return &v1.RuleDelRes{Success: out.Success}, nil
}

View File

@ -0,0 +1,24 @@
package activity
import (
"context"
"server/internal/model"
"server/internal/service"
"server/api/activity/v1"
)
func (c *ControllerV1) RuleEdit(ctx context.Context, req *v1.RuleEditReq) (res *v1.RuleEditRes, err error) {
out, err := service.SignInRewardRules().Update(ctx, &model.SignInRewardRulesUpdateIn{
Id: req.Id,
RuleName: req.RuleName,
CycleDays: req.CycleDays,
StartDate: req.StartDate,
EndDate: req.EndDate,
Status: req.Status,
})
if err != nil {
return nil, err
}
return &v1.RuleEditRes{Success: out.Success}, nil
}

View File

@ -0,0 +1,25 @@
package activity
import (
"context"
"server/internal/model"
"server/internal/service"
"server/api/activity/v1"
)
func (c *ControllerV1) RuleList(ctx context.Context, req *v1.RuleListReq) (res *v1.RuleListRes, err error) {
out, err := service.SignInRewardRules().List(ctx, &model.SignInRewardRulesListIn{
Page: req.Page,
RuleName: req.RuleName,
Size: req.Size,
Status: req.Status,
})
if err != nil {
return nil, err
}
return &v1.RuleListRes{
Total: out.Total,
List: out.List,
}, nil
}

View File

@ -0,0 +1,20 @@
package activity
import (
"context"
"server/internal/model"
"server/internal/service"
"server/api/activity/v1"
)
func (c *ControllerV1) RuleSetStatus(ctx context.Context, req *v1.RuleSetStatusReq) (res *v1.RuleSetStatusRes, err error) {
out, err := service.SignInRewardRules().SetStatus(ctx, &model.SignInRewardRulesSetStatusIn{
Id: req.Id,
Status: req.Status,
})
if err != nil {
return nil, err
}
return &v1.RuleSetStatusRes{Success: out.Success}, nil
}

View File

@ -0,0 +1,26 @@
package activity
import (
"context"
v1 "server/api/activity/v1"
"server/internal/model"
"server/internal/service"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/gtime"
)
func (c *ControllerV1) SignIn(ctx context.Context, req *v1.SignInReq) (res *v1.SignInRes, err error) {
userId := g.RequestFromCtx(ctx).GetCtxVar("id").Int64()
in := &model.UserSignInLogSignIn{
UserId: userId,
RuleId: req.RuleId,
RewardDetailId: req.RewardDetailId,
SignInDate: gtime.Now(), // 或根据 req.SignInDate 解析
}
out, err := service.UserSignInLogs().Sign(ctx, in)
if err != nil {
return nil, err
}
return &v1.SignInRes{Success: out.Success}, nil
}

View File

@ -0,0 +1,24 @@
package activity
import (
"context"
"github.com/gogf/gf/v2/frame/g"
"server/internal/model"
"server/internal/service"
"server/api/activity/v1"
)
func (c *ControllerV1) SignInList(ctx context.Context, req *v1.SignInListReq) (res *v1.SignInListRes, err error) {
userId := g.RequestFromCtx(ctx).GetCtxVar("id").Int64()
out, err := service.SignInRewardRules().SignInList(ctx, &model.SignInListIn{
UserId: userId,
})
if err != nil {
return nil, err
}
res = &v1.SignInListRes{
List: out.List,
}
return &v1.SignInListRes{List: out.List}, nil
}

View File

@ -2,11 +2,12 @@ package admin
import (
"context"
"github.com/gogf/gf/v2/frame/g"
"server/internal/model"
"server/internal/service"
"server/api/admin/v1"
"github.com/gogf/gf/v2/frame/g"
v1 "server/api/admin/v1"
)
func (c *ControllerV1) Info(ctx context.Context, req *v1.InfoReq) (res *v1.InfoRes, err error) {
@ -17,7 +18,8 @@ func (c *ControllerV1) Info(ctx context.Context, req *v1.InfoReq) (res *v1.InfoR
return nil, err
}
return &v1.InfoRes{
AdminId: out.AdminId,
Id: out.Id,
Username: out.Username,
Role: out.Role,
}, nil
}

View File

@ -0,0 +1,5 @@
// =================================================================================
// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish.
// =================================================================================
package ads

View File

@ -0,0 +1,15 @@
// =================================================================================
// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish.
// =================================================================================
package ads
import (
"server/api/ads"
)
type ControllerV1 struct{}
func NewV1() ads.IAdsV1 {
return &ControllerV1{}
}

View File

@ -0,0 +1,27 @@
package ads
import (
"context"
"github.com/gogf/gf/v2/frame/g"
v1 "server/api/ads/v1"
"server/internal/model"
"server/internal/service"
)
func (c *ControllerV1) Upload(ctx context.Context, req *v1.UploadReq) (res *v1.UploadRes, err error) {
userId := g.RequestFromCtx(ctx).GetCtxVar("id").Int64()
out, err := service.Ads().Upload(ctx, &model.AdsUploadIn{
UserId: userId,
NodeUid: req.NodeUid,
DeviceCode: req.DeviceCode,
Data: req.Data,
})
if err != nil {
return nil, err
}
return &v1.UploadRes{
Success: out.Success,
}, nil
}

View File

@ -0,0 +1,17 @@
package auth
import (
"context"
v1 "server/api/auth/v1"
"server/internal/model"
"server/internal/service"
)
func (c *ControllerV1) AuthorLogin(ctx context.Context, req *v1.AuthorLoginReq) (res *v1.AuthorLoginRes, err error) {
out, err := service.User().AuthorLogin(ctx, &model.UserLoginIn{Email: req.Email, Password: req.Password})
if err != nil {
return nil, err
}
return &v1.AuthorLoginRes{Token: out.Token}, nil
}

View File

@ -5,7 +5,7 @@ import (
"server/internal/model"
"server/internal/service"
"server/api/auth/v1"
v1 "server/api/auth/v1"
)
func (c *ControllerV1) UserLogin(ctx context.Context, req *v1.UserLoginReq) (res *v1.UserLoginRes, err error) {

View File

@ -0,0 +1,23 @@
package author
import (
"context"
"github.com/gogf/gf/v2/frame/g"
"server/internal/model"
"server/internal/service"
"server/api/author/v1"
)
func (c *ControllerV1) Apply(ctx context.Context, req *v1.ApplyReq) (res *v1.ApplyRes, err error) {
userId := g.RequestFromCtx(ctx).GetCtxVar("id").Int64()
out, err := service.Author().Apply(ctx, &model.AuthorApplyIn{
UserId: userId,
PenName: req.PenName,
Bio: req.Bio,
})
if err != nil {
return nil, err
}
return &v1.ApplyRes{Success: out.Success, Msg: "Please wait patiently for the management review"}, nil
}

View File

@ -0,0 +1,23 @@
package author
import (
"context"
"github.com/gogf/gf/v2/frame/g"
"server/internal/model"
"server/internal/service"
"server/api/author/v1"
)
func (c *ControllerV1) AuthorInfo(ctx context.Context, req *v1.AuthorInfoReq) (res *v1.AuthorInfoRes, err error) {
userId := g.RequestFromCtx(ctx).GetCtxVar("id").Int64()
out, err := service.Author().AuthorInfo(ctx, &model.AuthorInfoIn{UserId: userId})
if err != nil {
return nil, err
}
return &v1.AuthorInfoRes{
Id: out.Id,
PenName: out.PenName,
Role: out.Role,
}, nil
}

View File

@ -13,5 +13,5 @@ func (c *ControllerV1) Detail(ctx context.Context, req *v1.DetailReq) (res *v1.D
if err != nil {
return nil, err
}
return &v1.DetailRes{Author: out}, nil
return &v1.DetailRes{out}, nil
}

View File

@ -0,0 +1,21 @@
package author
import (
"context"
"server/internal/model"
"server/internal/service"
v1 "server/api/author/v1"
)
func (c *ControllerV1) Review(ctx context.Context, req *v1.ReviewReq) (res *v1.ReviewRes, err error) {
out, err := service.Author().Review(ctx, &model.AuthorReviewIn{
AuthorId: req.AuthorId,
Status: req.Status,
})
if err != nil {
return nil, err
}
return &v1.ReviewRes{Success: out.Success}, nil
}

View File

@ -23,22 +23,29 @@ func (c *ControllerV1) AppDetail(ctx context.Context, req *v1.AppDetailReq) (res
return &v1.AppDetailRes{
Id: out.Id,
AuthorId: out.AuthorId,
CategoryId: out.CategoryId,
Title: out.Title,
CoverUrl: out.CoverUrl,
Rating: out.Rating,
Title: out.Title,
Description: out.Description,
AuthorId: out.AuthorId,
Author: out.Author,
CategoryId: out.CategoryId,
Category: out.Category,
Status: out.Status,
WordsCount: out.WordsCount,
ChaptersCount: out.ChaptersCount,
ReadCount: out.ReadCount,
CurrentReaders: out.CurrentReaders,
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,
HasRated: out.HasRated,
MyRating: out.MyRating,
HasRead: out.HasRead,
ReadProgress: out.ReadProgress,
LastChapterId: out.LastChapterId,
LastReadAt: out.LastReadAt,
IsInBookshelf: out.IsInBookshelf,
}, nil
}

View File

@ -17,6 +17,7 @@ func (c *ControllerV1) AppList(ctx context.Context, req *v1.AppListReq) (res *v1
IsRecommended: req.IsRecommended,
IsFeatured: req.IsFeatured,
IsLatest: req.IsLatest,
IsHot: req.IsHot,
CategoryId: req.CategoryId,
Title: req.Title,
AuthorId: req.AuthorId,

View File

@ -0,0 +1,24 @@
package book
import (
"context"
"server/internal/model"
"server/internal/service"
v1 "server/api/book/v1"
"server/utility/ecode"
"github.com/gogf/gf/v2/errors/gerror"
)
func (c *ControllerV1) BookCoverImage(ctx context.Context, req *v1.BookCoverImageReq) (res *v1.BookCoverImageRes, err error) {
if req.File == nil {
return nil, gerror.NewCode(ecode.Fail.Sub("image_file_required").Code())
}
image, err := service.Upload().UploadImage(ctx, &model.UploadImageIn{File: req.File, Type: "book"})
if err != nil {
return nil, err
}
return &v1.BookCoverImageRes{ImageUrl: image.ImageUrl}, nil
}

View File

@ -3,12 +3,15 @@ package book
import (
"context"
"github.com/gogf/gf/v2/errors/gcode"
"github.com/gogf/gf/v2/errors/gerror"
"server/api/book/v1"
"server/internal/model"
"server/internal/service"
)
func (c *ControllerV1) BookSetFeatured(ctx context.Context, req *v1.BookSetFeaturedReq) (res *v1.BookSetFeaturedRes, err error) {
return nil, gerror.NewCode(gcode.CodeNotImplemented)
out, err := service.Book().SetFeatured(ctx, &model.BookSetFeaturedIn{Id: req.Id, IsFeatured: req.IsFeatured})
if err != nil {
return nil, err
}
return &v1.BookSetFeaturedRes{Success: out.Success}, nil
}

View File

@ -0,0 +1,22 @@
package book
import (
"context"
v1 "server/api/book/v1"
"server/internal/model"
"server/internal/service"
)
func (c *ControllerV1) BookSetHot(ctx context.Context, req *v1.BookSetHotReq) (res *v1.BookSetHotRes, err error) {
out, err := service.Book().SetHot(ctx, &model.BookSetHotIn{
Id: req.Id,
IsHot: req.IsHot,
})
if err != nil {
return nil, err
}
return &v1.BookSetHotRes{
Success: out.Success,
}, nil
}

View File

@ -2,13 +2,16 @@ package book
import (
"context"
"github.com/gogf/gf/v2/errors/gcode"
"github.com/gogf/gf/v2/errors/gerror"
"server/internal/model"
"server/internal/service"
"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)
out, err := service.Book().SetRecommended(ctx, &model.BookSetRecommendedIn{Id: req.Id, IsRecommended: req.IsRecommended})
if err != nil {
return nil, err
}
return &v1.BookSetRecommendedRes{Success: out.Success}, nil
}

View File

@ -0,0 +1,21 @@
package book
import (
"context"
"github.com/gogf/gf/v2/frame/g"
"server/internal/model"
"server/internal/service"
"server/api/book/v1"
)
func (c *ControllerV1) HistoryRemove(ctx context.Context, req *v1.HistoryRemoveReq) (res *v1.HistoryRemoveRes, err error) {
userId := g.RequestFromCtx(ctx).GetCtxVar("id").Int64()
out, err := service.UserReadHistory().Remove(ctx, &model.UserReadHistoryDelIn{BookIds: req.BookIds, UserId: userId})
if err != nil {
return nil, err
}
return &v1.HistoryRemoveRes{
Success: out.Success,
}, nil
}

View File

@ -11,11 +11,10 @@ import (
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,
out, err := service.Chapter().AppBatchProgress(ctx, &model.ChapterAppBatchProgressIn{
BookId: req.BookId,
Chapters: req.Chapters,
UserId: userId,
})
if err != nil {
return nil, err

View File

@ -0,0 +1,5 @@
// =================================================================================
// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish.
// =================================================================================
package recommend

View File

@ -0,0 +1,15 @@
// =================================================================================
// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish.
// =================================================================================
package recommend
import (
"server/api/recommend"
)
type ControllerV1 struct{}
func NewV1() recommend.IRecommendV1 {
return &ControllerV1{}
}

View File

@ -0,0 +1,23 @@
package recommend
import (
"context"
"server/internal/model"
"server/internal/service"
v1 "server/api/recommend/v1"
)
func (c *ControllerV1) Add(ctx context.Context, req *v1.AddReq) (res *v1.AddRes, err error) {
out, err := service.BookRecommendations().Create(ctx, &model.BookRecommendationsCreateIn{
BookId: req.BookId,
Type: req.Type,
CoverUrl: req.CoverUrl,
SortOrder: req.SortOrder,
Status: req.Status,
})
if err != nil {
return nil, err
}
return &v1.AddRes{Success: out.Success}, nil
}

View File

@ -0,0 +1,35 @@
package recommend
import (
"context"
"server/internal/model"
"server/internal/service"
v1 "server/api/recommend/v1"
)
func (c *ControllerV1) AppList(ctx context.Context, req *v1.AppListReq) (res *v1.AppListRes, err error) {
out, err := service.BookRecommendations().AppList(ctx, &model.BookRecommendationsListIn{
Page: req.Page,
Size: req.Size,
Type: req.Type,
Status: req.Status,
})
if err != nil {
return nil, err
}
// 转换为 RecommendAppItem
list := make([]model.RecommendAppItem, 0, len(out.List))
for _, item := range out.List {
list = append(list, model.RecommendAppItem{
Id: item.Id,
BookId: item.BookId,
CoverUrl: item.CoverUrl,
SortOrder: item.SortOrder,
})
}
return &v1.AppListRes{
Total: out.Total,
List: list,
}, nil
}

View File

@ -0,0 +1,19 @@
package recommend
import (
"context"
"server/internal/model"
"server/internal/service"
v1 "server/api/recommend/v1"
)
func (c *ControllerV1) Del(ctx context.Context, req *v1.DelReq) (res *v1.DelRes, err error) {
out, err := service.BookRecommendations().Delete(ctx, &model.BookRecommendationsDeleteIn{
Id: req.Id,
})
if err != nil {
return nil, err
}
return &v1.DelRes{Success: out.Success}, nil
}

View File

@ -0,0 +1,24 @@
package recommend
import (
"context"
"server/internal/model"
"server/internal/service"
v1 "server/api/recommend/v1"
)
func (c *ControllerV1) Edit(ctx context.Context, req *v1.EditReq) (res *v1.EditRes, err error) {
out, err := service.BookRecommendations().Update(ctx, &model.BookRecommendationsUpdateIn{
Id: req.Id,
BookId: req.BookId,
Type: req.Type,
CoverUrl: req.CoverUrl,
SortOrder: req.SortOrder,
Status: req.Status,
})
if err != nil {
return nil, err
}
return &v1.EditRes{Success: out.Success}, nil
}

View File

@ -0,0 +1,26 @@
package recommend
import (
"context"
"server/internal/model"
"server/internal/service"
v1 "server/api/recommend/v1"
)
func (c *ControllerV1) List(ctx context.Context, req *v1.ListReq) (res *v1.ListRes, err error) {
out, err := service.BookRecommendations().List(ctx, &model.BookRecommendationsListIn{
Page: req.Page,
Size: req.Size,
Type: req.Type,
Status: req.Status,
BookId: req.BookId,
})
if err != nil {
return nil, err
}
return &v1.ListRes{
Total: out.Total,
List: out.List,
}, nil
}

View File

@ -0,0 +1,20 @@
package recommend
import (
"context"
"server/internal/model"
"server/internal/service"
v1 "server/api/recommend/v1"
)
func (c *ControllerV1) SetStatus(ctx context.Context, req *v1.SetStatusReq) (res *v1.SetStatusRes, err error) {
out, err := service.BookRecommendations().SetStatus(ctx, &model.BookRecommendationsSetStatusIn{
Id: req.Id,
Status: req.Status,
})
if err != nil {
return nil, err
}
return &v1.SetStatusRes{Success: out.Success}, nil
}

View File

@ -0,0 +1,20 @@
package recommend
import (
"context"
"server/internal/model"
"server/internal/service"
v1 "server/api/recommend/v1"
)
func (c *ControllerV1) SortOrder(ctx context.Context, req *v1.SortOrderReq) (res *v1.SortOrderRes, err error) {
out, err := service.BookRecommendations().SortOrder(ctx, &model.BookRecommendationsSortOrderIn{
Id: req.Id,
SortOrder: req.SortOrder,
})
if err != nil {
return nil, err
}
return &v1.SortOrderRes{Success: out.Success}, nil
}

View File

@ -0,0 +1,16 @@
package recommend
import (
"context"
"server/internal/service"
v1 "server/api/recommend/v1"
)
func (c *ControllerV1) UploadCover(ctx context.Context, req *v1.UploadCoverReq) (res *v1.UploadCoverRes, err error) {
url, err := service.BookRecommendations().UploadCover(ctx, req.File)
if err != nil {
return nil, err
}
return &v1.UploadCoverRes{Url: url}, nil
}

View File

@ -0,0 +1,5 @@
// =================================================================================
// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish.
// =================================================================================
package system

View File

@ -0,0 +1,15 @@
// =================================================================================
// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish.
// =================================================================================
package system
import (
"server/api/system"
)
type ControllerV1 struct{}
func NewV1() system.ISystemV1 {
return &ControllerV1{}
}

View File

@ -0,0 +1,16 @@
package system
import (
"context"
"server/internal/model"
"server/internal/service"
"server/api/system/v1"
)
func (c *ControllerV1) SystemSave(ctx context.Context, req *v1.SystemSaveReq) (res *v1.SystemSaveRes, err error) {
return nil, service.System().Save(ctx, &model.SystemSaveInput{
Key: req.Key,
Value: req.Value,
})
}

View File

@ -0,0 +1,16 @@
package system
import (
"context"
"server/internal/service"
"server/api/system/v1"
)
func (c *ControllerV1) SystemVersion(ctx context.Context, req *v1.SystemVersionReq) (res *v1.SystemVersionRes, err error) {
version, err := service.System().Version(ctx)
if err != nil {
return nil, err
}
return &v1.SystemVersionRes{Ios: version.Ios, Android: version.Android}, nil
}

View File

@ -0,0 +1,5 @@
// =================================================================================
// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish.
// =================================================================================
package task

View File

@ -0,0 +1,15 @@
// =================================================================================
// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish.
// =================================================================================
package task
import (
"server/api/task"
)
type ControllerV1 struct{}
func NewV1() task.ITaskV1 {
return &ControllerV1{}
}

View File

@ -0,0 +1,23 @@
package task
import (
"context"
v1 "server/api/task/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.Task().Add(ctx, &model.TaskAddIn{
TaskType: req.TaskType,
Title: req.Title,
Description: req.Description,
RewardPoints: req.RewardPoints,
Status: req.Status,
})
if err != nil {
return nil, err
}
return &v1.AddRes{Success: out.Success}, nil
}

View File

@ -0,0 +1,19 @@
package task
import (
"context"
v1 "server/api/task/v1"
"server/internal/model"
"server/internal/service"
)
func (c *ControllerV1) AppList(ctx context.Context, req *v1.AppListReq) (res *v1.AppListRes, err error) {
out, err := service.Task().AppList(ctx, &model.TaskAppListIn{})
if err != nil {
return nil, err
}
return &v1.AppListRes{
List: out.List,
}, nil
}

View File

@ -0,0 +1,17 @@
package task
import (
"context"
v1 "server/api/task/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.Task().Delete(ctx, &model.TaskDelIn{Id: req.Id})
if err != nil {
return nil, err
}
return &v1.DelRes{Success: out.Success}, nil
}

View File

@ -0,0 +1,24 @@
package task
import (
"context"
v1 "server/api/task/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.Task().Edit(ctx, &model.TaskEditIn{
Id: req.Id,
TaskType: req.TaskType,
Title: req.Title,
Description: req.Description,
RewardPoints: req.RewardPoints,
Status: req.Status,
})
if err != nil {
return nil, err
}
return &v1.EditRes{Success: out.Success}, nil
}

View File

@ -0,0 +1,25 @@
package task
import (
"context"
v1 "server/api/task/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.Task().List(ctx, &model.TaskListIn{
Page: req.Page,
Size: req.Size,
Title: req.Title,
Status: req.Status,
})
if err != nil {
return nil, err
}
return &v1.ListRes{
Total: out.Total,
List: out.List,
}, nil
}

View File

@ -23,10 +23,14 @@ func (c *ControllerV1) Info(ctx context.Context, req *v1.InfoReq) (res *v1.InfoR
}
return &v1.InfoRes{
UserId: out.UserId,
Username: out.Username,
Avatar: out.Avatar,
Email: out.Email,
Points: out.Points,
Id: out.Id,
Username: out.Username,
Avatar: out.Avatar,
Email: out.Email,
Points: out.Points,
BackgroundUrl: out.BackgroundUrl,
AttentionCount: out.AttentionCount,
IsAuthor: out.IsAuthor,
AuthorStatus: out.AuthorStatus,
}, nil
}

View File

@ -2,13 +2,15 @@ package user
import (
"context"
"github.com/gogf/gf/v2/errors/gcode"
"github.com/gogf/gf/v2/errors/gerror"
"fmt"
"github.com/gogf/gf/v2/frame/g"
"server/api/user/v1"
)
func (c *ControllerV1) Logout(ctx context.Context, req *v1.LogoutReq) (res *v1.LogoutRes, err error) {
return nil, gerror.NewCode(gcode.CodeNotImplemented)
g.Redis().Do(ctx, "SETEX", fmt.Sprintf("blacklist:%s", g.RequestFromCtx(ctx).GetCtxVar("jti").String()), "1")
return &v1.LogoutRes{
Success: true,
}, nil
}

View 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"
)
// internalAdEventLogsDao is an internal type for wrapping the internal DAO implementation.
type internalAdEventLogsDao = *internal.AdEventLogsDao
// adEventLogsDao is the data access object for the table ad_event_logs.
// You can define custom methods on it to extend its functionality as needed.
type adEventLogsDao struct {
internalAdEventLogsDao
}
var (
// AdEventLogs is a globally accessible object for table ad_event_logs operations.
AdEventLogs = adEventLogsDao{
internal.NewAdEventLogsDao(),
}
)
// Add your custom methods and functionality below.

View 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"
)
// internalAdEventTransitionsDao is an internal type for wrapping the internal DAO implementation.
type internalAdEventTransitionsDao = *internal.AdEventTransitionsDao
// adEventTransitionsDao is the data access object for the table ad_event_transitions.
// You can define custom methods on it to extend its functionality as needed.
type adEventTransitionsDao struct {
internalAdEventTransitionsDao
}
var (
// AdEventTransitions is a globally accessible object for table ad_event_transitions operations.
AdEventTransitions = adEventTransitionsDao{
internal.NewAdEventTransitionsDao(),
}
)
// Add your custom methods and functionality below.

View 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"
)
// internalBookRecommendationsDao is an internal type for wrapping the internal DAO implementation.
type internalBookRecommendationsDao = *internal.BookRecommendationsDao
// bookRecommendationsDao is the data access object for the table book_recommendations.
// You can define custom methods on it to extend its functionality as needed.
type bookRecommendationsDao struct {
internalBookRecommendationsDao
}
var (
// BookRecommendations is a globally accessible object for table book_recommendations operations.
BookRecommendations = bookRecommendationsDao{
internal.NewBookRecommendationsDao(),
}
)
// Add your custom methods and functionality below.

View File

@ -0,0 +1,97 @@
// ==========================================================================
// 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"
)
// AdEventLogsDao is the data access object for the table ad_event_logs.
type AdEventLogsDao 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 AdEventLogsColumns // columns contains all the column names of Table for convenient usage.
handlers []gdb.ModelHandler // handlers for customized model modification.
}
// AdEventLogsColumns defines and stores column names for the table ad_event_logs.
type AdEventLogsColumns struct {
Id string // 广告事件ID
UserId string // 用户ID
AdsPlatId string // 平台ID1-META2-ADMOB
AdsCategoryId string // 广告类型1-横幅2-插页3-激励插页4-激励5-原生6-开屏
AppPackage string // App包名
Status string // 广告状态1-拉取失败2-拉取成功3-显示失败4-显示成功5-未观看完成6-观看完成7-未点击8-已点击9-未下载10-已下载
StatusDesc string // 状态描述
CreatedAt string // 创建时间
UpdatedAt string // 更新时间
DeletedAt string // 软删除时间戳
}
// adEventLogsColumns holds the columns for the table ad_event_logs.
var adEventLogsColumns = AdEventLogsColumns{
Id: "id",
UserId: "user_id",
AdsPlatId: "ads_plat_id",
AdsCategoryId: "ads_category_id",
AppPackage: "app_package",
Status: "status",
StatusDesc: "status_desc",
CreatedAt: "created_at",
UpdatedAt: "updated_at",
DeletedAt: "deleted_at",
}
// NewAdEventLogsDao creates and returns a new DAO object for table data access.
func NewAdEventLogsDao(handlers ...gdb.ModelHandler) *AdEventLogsDao {
return &AdEventLogsDao{
group: "default",
table: "ad_event_logs",
columns: adEventLogsColumns,
handlers: handlers,
}
}
// DB retrieves and returns the underlying raw database management object of the current DAO.
func (dao *AdEventLogsDao) DB() gdb.DB {
return g.DB(dao.group)
}
// Table returns the table name of the current DAO.
func (dao *AdEventLogsDao) Table() string {
return dao.table
}
// Columns returns all column names of the current DAO.
func (dao *AdEventLogsDao) Columns() AdEventLogsColumns {
return dao.columns
}
// Group returns the database configuration group name of the current DAO.
func (dao *AdEventLogsDao) 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 *AdEventLogsDao) Ctx(ctx context.Context) *gdb.Model {
model := dao.DB().Model(dao.table)
for _, handler := range dao.handlers {
model = handler(model)
}
return model.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 *AdEventLogsDao) Transaction(ctx context.Context, f func(ctx context.Context, tx gdb.TX) error) (err error) {
return dao.Ctx(ctx).Transaction(ctx, f)
}

View File

@ -0,0 +1,89 @@
// ==========================================================================
// 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"
)
// AdEventTransitionsDao is the data access object for the table ad_event_transitions.
type AdEventTransitionsDao 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 AdEventTransitionsColumns // columns contains all the column names of Table for convenient usage.
handlers []gdb.ModelHandler // handlers for customized model modification.
}
// AdEventTransitionsColumns defines and stores column names for the table ad_event_transitions.
type AdEventTransitionsColumns struct {
Id string // 状态流转记录ID
EventId string // 所属广告事件ID关联ad_event_logs.id
FromStatus string // 原状态(首次记录为空)
ToStatus string // 目标状态
CreatedAt string // 状态变更时间
DeletedAt string // 软删除时间戳
}
// adEventTransitionsColumns holds the columns for the table ad_event_transitions.
var adEventTransitionsColumns = AdEventTransitionsColumns{
Id: "id",
EventId: "event_id",
FromStatus: "from_status",
ToStatus: "to_status",
CreatedAt: "created_at",
DeletedAt: "deleted_at",
}
// NewAdEventTransitionsDao creates and returns a new DAO object for table data access.
func NewAdEventTransitionsDao(handlers ...gdb.ModelHandler) *AdEventTransitionsDao {
return &AdEventTransitionsDao{
group: "default",
table: "ad_event_transitions",
columns: adEventTransitionsColumns,
handlers: handlers,
}
}
// DB retrieves and returns the underlying raw database management object of the current DAO.
func (dao *AdEventTransitionsDao) DB() gdb.DB {
return g.DB(dao.group)
}
// Table returns the table name of the current DAO.
func (dao *AdEventTransitionsDao) Table() string {
return dao.table
}
// Columns returns all column names of the current DAO.
func (dao *AdEventTransitionsDao) Columns() AdEventTransitionsColumns {
return dao.columns
}
// Group returns the database configuration group name of the current DAO.
func (dao *AdEventTransitionsDao) 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 *AdEventTransitionsDao) Ctx(ctx context.Context) *gdb.Model {
model := dao.DB().Model(dao.table)
for _, handler := range dao.handlers {
model = handler(model)
}
return model.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 *AdEventTransitionsDao) Transaction(ctx context.Context, f func(ctx context.Context, tx gdb.TX) error) (err error) {
return dao.Ctx(ctx).Transaction(ctx, f)
}

View File

@ -13,9 +13,10 @@ import (
// AdminsDao is the data access object for the table admins.
type AdminsDao 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 AdminsColumns // columns contains all the column names of Table for convenient usage.
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 AdminsColumns // columns contains all the column names of Table for convenient usage.
handlers []gdb.ModelHandler // handlers for customized model modification.
}
// AdminsColumns defines and stores column names for the table admins.
@ -39,11 +40,12 @@ var adminsColumns = AdminsColumns{
}
// NewAdminsDao creates and returns a new DAO object for table data access.
func NewAdminsDao() *AdminsDao {
func NewAdminsDao(handlers ...gdb.ModelHandler) *AdminsDao {
return &AdminsDao{
group: "default",
table: "admins",
columns: adminsColumns,
group: "default",
table: "admins",
columns: adminsColumns,
handlers: handlers,
}
}
@ -69,7 +71,11 @@ func (dao *AdminsDao) Group() string {
// Ctx creates and returns a Model for the current DAO. It automatically sets the context for the current operation.
func (dao *AdminsDao) Ctx(ctx context.Context) *gdb.Model {
return dao.DB().Model(dao.table).Safe().Ctx(ctx)
model := dao.DB().Model(dao.table)
for _, handler := range dao.handlers {
model = handler(model)
}
return model.Safe().Ctx(ctx)
}
// Transaction wraps the transaction logic using function f.

View File

@ -13,41 +13,45 @@ import (
// AuthorsDao is the data access object for the table authors.
type AuthorsDao 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 AuthorsColumns // columns contains all the column names of Table for convenient usage.
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 AuthorsColumns // columns contains all the column names of Table for convenient usage.
handlers []gdb.ModelHandler // handlers for customized model modification.
}
// AuthorsColumns defines and stores column names for the table authors.
type AuthorsColumns struct {
Id string // 作者ID
UserId string // 用户ID
PenName string // 笔名
Bio string // 作者简介
Status string // 状态1=正常2=禁用
CreatedAt string // 创建时间
UpdatedAt string // 更新时间
DeletedAt string // 软删除时间
Id string // 作者ID
UserId string // 用户ID
PenName string // 笔名
Bio string // 作者简介
FollowerCount string // 粉丝数量
Status string // 状态1=正常2=待审核, 3=未通过
CreatedAt string // 创建时间
UpdatedAt string // 更新时间
DeletedAt string // 软删除时间戳
}
// authorsColumns holds the columns for the table authors.
var authorsColumns = AuthorsColumns{
Id: "id",
UserId: "user_id",
PenName: "pen_name",
Bio: "bio",
Status: "status",
CreatedAt: "created_at",
UpdatedAt: "updated_at",
DeletedAt: "deleted_at",
Id: "id",
UserId: "user_id",
PenName: "pen_name",
Bio: "bio",
FollowerCount: "follower_count",
Status: "status",
CreatedAt: "created_at",
UpdatedAt: "updated_at",
DeletedAt: "deleted_at",
}
// NewAuthorsDao creates and returns a new DAO object for table data access.
func NewAuthorsDao() *AuthorsDao {
func NewAuthorsDao(handlers ...gdb.ModelHandler) *AuthorsDao {
return &AuthorsDao{
group: "default",
table: "authors",
columns: authorsColumns,
group: "default",
table: "authors",
columns: authorsColumns,
handlers: handlers,
}
}
@ -73,7 +77,11 @@ func (dao *AuthorsDao) Group() string {
// Ctx creates and returns a Model for the current DAO. It automatically sets the context for the current operation.
func (dao *AuthorsDao) Ctx(ctx context.Context) *gdb.Model {
return dao.DB().Model(dao.table).Safe().Ctx(ctx)
model := dao.DB().Model(dao.table)
for _, handler := range dao.handlers {
model = handler(model)
}
return model.Safe().Ctx(ctx)
}
// Transaction wraps the transaction logic using function f.

View File

@ -13,9 +13,10 @@ import (
// BookRatingsDao is the data access object for the table book_ratings.
type BookRatingsDao 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 BookRatingsColumns // columns contains all the column names of Table for convenient usage.
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 BookRatingsColumns // columns contains all the column names of Table for convenient usage.
handlers []gdb.ModelHandler // handlers for customized model modification.
}
// BookRatingsColumns defines and stores column names for the table book_ratings.
@ -39,11 +40,12 @@ var bookRatingsColumns = BookRatingsColumns{
}
// NewBookRatingsDao creates and returns a new DAO object for table data access.
func NewBookRatingsDao() *BookRatingsDao {
func NewBookRatingsDao(handlers ...gdb.ModelHandler) *BookRatingsDao {
return &BookRatingsDao{
group: "default",
table: "book_ratings",
columns: bookRatingsColumns,
group: "default",
table: "book_ratings",
columns: bookRatingsColumns,
handlers: handlers,
}
}
@ -69,7 +71,11 @@ func (dao *BookRatingsDao) Group() string {
// Ctx creates and returns a Model for the current DAO. It automatically sets the context for the current operation.
func (dao *BookRatingsDao) Ctx(ctx context.Context) *gdb.Model {
return dao.DB().Model(dao.table).Safe().Ctx(ctx)
model := dao.DB().Model(dao.table)
for _, handler := range dao.handlers {
model = handler(model)
}
return model.Safe().Ctx(ctx)
}
// Transaction wraps the transaction logic using function f.

View File

@ -0,0 +1,95 @@
// ==========================================================================
// 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"
)
// BookRecommendationsDao is the data access object for the table book_recommendations.
type BookRecommendationsDao 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 BookRecommendationsColumns // columns contains all the column names of Table for convenient usage.
handlers []gdb.ModelHandler // handlers for customized model modification.
}
// BookRecommendationsColumns defines and stores column names for the table book_recommendations.
type BookRecommendationsColumns struct {
Id string // 主键
BookId string // 书籍ID关联 books 表
Type string // 推荐类型1=首页Banner2=编辑推荐3=分类推荐等
CoverUrl string // 推荐封面图(横图)
SortOrder string // 展示排序,越小越靠前
Status string // 是否启用1=启用0=禁用
CreatedAt string // 创建时间
UpdatedAt string // 更新时间
DeletedAt string // 软删除时间戳
}
// bookRecommendationsColumns holds the columns for the table book_recommendations.
var bookRecommendationsColumns = BookRecommendationsColumns{
Id: "id",
BookId: "book_id",
Type: "type",
CoverUrl: "cover_url",
SortOrder: "sort_order",
Status: "status",
CreatedAt: "created_at",
UpdatedAt: "updated_at",
DeletedAt: "deleted_at",
}
// NewBookRecommendationsDao creates and returns a new DAO object for table data access.
func NewBookRecommendationsDao(handlers ...gdb.ModelHandler) *BookRecommendationsDao {
return &BookRecommendationsDao{
group: "default",
table: "book_recommendations",
columns: bookRecommendationsColumns,
handlers: handlers,
}
}
// DB retrieves and returns the underlying raw database management object of the current DAO.
func (dao *BookRecommendationsDao) DB() gdb.DB {
return g.DB(dao.group)
}
// Table returns the table name of the current DAO.
func (dao *BookRecommendationsDao) Table() string {
return dao.table
}
// Columns returns all column names of the current DAO.
func (dao *BookRecommendationsDao) Columns() BookRecommendationsColumns {
return dao.columns
}
// Group returns the database configuration group name of the current DAO.
func (dao *BookRecommendationsDao) 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 *BookRecommendationsDao) Ctx(ctx context.Context) *gdb.Model {
model := dao.DB().Model(dao.table)
for _, handler := range dao.handlers {
model = handler(model)
}
return model.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 *BookRecommendationsDao) Transaction(ctx context.Context, f func(ctx context.Context, tx gdb.TX) error) (err error) {
return dao.Ctx(ctx).Transaction(ctx, f)
}

View File

@ -13,9 +13,10 @@ import (
// BooksDao is the data access object for the table books.
type BooksDao 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 BooksColumns // columns contains all the column names of Table for convenient usage.
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 BooksColumns // columns contains all the column names of Table for convenient usage.
handlers []gdb.ModelHandler // handlers for customized model modification.
}
// BooksColumns defines and stores column names for the table books.
@ -38,6 +39,7 @@ type BooksColumns struct {
DeletedAt string // 软删除时间戳
IsRecommended string // 是否推荐0=否1=是
IsFeatured string // 是否精选0=否1=是
IsHot string // 是否热门0=否1=是
Language string // 语言,如 zh=中文en=英文jp=日文
}
@ -61,15 +63,17 @@ var booksColumns = BooksColumns{
DeletedAt: "deleted_at",
IsRecommended: "is_recommended",
IsFeatured: "is_featured",
IsHot: "is_hot",
Language: "language",
}
// NewBooksDao creates and returns a new DAO object for table data access.
func NewBooksDao() *BooksDao {
func NewBooksDao(handlers ...gdb.ModelHandler) *BooksDao {
return &BooksDao{
group: "default",
table: "books",
columns: booksColumns,
group: "default",
table: "books",
columns: booksColumns,
handlers: handlers,
}
}
@ -95,7 +99,11 @@ func (dao *BooksDao) Group() string {
// Ctx creates and returns a Model for the current DAO. It automatically sets the context for the current operation.
func (dao *BooksDao) Ctx(ctx context.Context) *gdb.Model {
return dao.DB().Model(dao.table).Safe().Ctx(ctx)
model := dao.DB().Model(dao.table)
for _, handler := range dao.handlers {
model = handler(model)
}
return model.Safe().Ctx(ctx)
}
// Transaction wraps the transaction logic using function f.

View File

@ -13,9 +13,10 @@ import (
// BookshelvesDao is the data access object for the table bookshelves.
type BookshelvesDao 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 BookshelvesColumns // columns contains all the column names of Table for convenient usage.
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 BookshelvesColumns // columns contains all the column names of Table for convenient usage.
handlers []gdb.ModelHandler // handlers for customized model modification.
}
// BookshelvesColumns defines and stores column names for the table bookshelves.
@ -43,11 +44,12 @@ var bookshelvesColumns = BookshelvesColumns{
}
// NewBookshelvesDao creates and returns a new DAO object for table data access.
func NewBookshelvesDao() *BookshelvesDao {
func NewBookshelvesDao(handlers ...gdb.ModelHandler) *BookshelvesDao {
return &BookshelvesDao{
group: "default",
table: "bookshelves",
columns: bookshelvesColumns,
group: "default",
table: "bookshelves",
columns: bookshelvesColumns,
handlers: handlers,
}
}
@ -73,7 +75,11 @@ func (dao *BookshelvesDao) Group() string {
// Ctx creates and returns a Model for the current DAO. It automatically sets the context for the current operation.
func (dao *BookshelvesDao) Ctx(ctx context.Context) *gdb.Model {
return dao.DB().Model(dao.table).Safe().Ctx(ctx)
model := dao.DB().Model(dao.table)
for _, handler := range dao.handlers {
model = handler(model)
}
return model.Safe().Ctx(ctx)
}
// Transaction wraps the transaction logic using function f.

View File

@ -13,9 +13,10 @@ import (
// CategoriesDao is the data access object for the table categories.
type CategoriesDao 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 CategoriesColumns // columns contains all the column names of Table for convenient usage.
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 CategoriesColumns // columns contains all the column names of Table for convenient usage.
handlers []gdb.ModelHandler // handlers for customized model modification.
}
// CategoriesColumns defines and stores column names for the table categories.
@ -39,11 +40,12 @@ var categoriesColumns = CategoriesColumns{
}
// NewCategoriesDao creates and returns a new DAO object for table data access.
func NewCategoriesDao() *CategoriesDao {
func NewCategoriesDao(handlers ...gdb.ModelHandler) *CategoriesDao {
return &CategoriesDao{
group: "default",
table: "categories",
columns: categoriesColumns,
group: "default",
table: "categories",
columns: categoriesColumns,
handlers: handlers,
}
}
@ -69,7 +71,11 @@ func (dao *CategoriesDao) Group() string {
// Ctx creates and returns a Model for the current DAO. It automatically sets the context for the current operation.
func (dao *CategoriesDao) Ctx(ctx context.Context) *gdb.Model {
return dao.DB().Model(dao.table).Safe().Ctx(ctx)
model := dao.DB().Model(dao.table)
for _, handler := range dao.handlers {
model = handler(model)
}
return model.Safe().Ctx(ctx)
}
// Transaction wraps the transaction logic using function f.

View File

@ -13,9 +13,10 @@ import (
// ChaptersDao is the data access object for the table chapters.
type ChaptersDao 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 ChaptersColumns // columns contains all the column names of Table for convenient usage.
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 ChaptersColumns // columns contains all the column names of Table for convenient usage.
handlers []gdb.ModelHandler // handlers for customized model modification.
}
// ChaptersColumns defines and stores column names for the table chapters.
@ -49,11 +50,12 @@ var chaptersColumns = ChaptersColumns{
}
// NewChaptersDao creates and returns a new DAO object for table data access.
func NewChaptersDao() *ChaptersDao {
func NewChaptersDao(handlers ...gdb.ModelHandler) *ChaptersDao {
return &ChaptersDao{
group: "default",
table: "chapters",
columns: chaptersColumns,
group: "default",
table: "chapters",
columns: chaptersColumns,
handlers: handlers,
}
}
@ -79,7 +81,11 @@ func (dao *ChaptersDao) Group() string {
// Ctx creates and returns a Model for the current DAO. It automatically sets the context for the current operation.
func (dao *ChaptersDao) Ctx(ctx context.Context) *gdb.Model {
return dao.DB().Model(dao.table).Safe().Ctx(ctx)
model := dao.DB().Model(dao.table)
for _, handler := range dao.handlers {
model = handler(model)
}
return model.Safe().Ctx(ctx)
}
// Transaction wraps the transaction logic using function f.

View File

@ -13,9 +13,10 @@ import (
// FeedbacksDao is the data access object for the table feedbacks.
type FeedbacksDao 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 FeedbacksColumns // columns contains all the column names of Table for convenient usage.
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 FeedbacksColumns // columns contains all the column names of Table for convenient usage.
handlers []gdb.ModelHandler // handlers for customized model modification.
}
// FeedbacksColumns defines and stores column names for the table feedbacks.
@ -39,11 +40,12 @@ var feedbacksColumns = FeedbacksColumns{
}
// NewFeedbacksDao creates and returns a new DAO object for table data access.
func NewFeedbacksDao() *FeedbacksDao {
func NewFeedbacksDao(handlers ...gdb.ModelHandler) *FeedbacksDao {
return &FeedbacksDao{
group: "default",
table: "feedbacks",
columns: feedbacksColumns,
group: "default",
table: "feedbacks",
columns: feedbacksColumns,
handlers: handlers,
}
}
@ -69,7 +71,11 @@ func (dao *FeedbacksDao) Group() string {
// Ctx creates and returns a Model for the current DAO. It automatically sets the context for the current operation.
func (dao *FeedbacksDao) Ctx(ctx context.Context) *gdb.Model {
return dao.DB().Model(dao.table).Safe().Ctx(ctx)
model := dao.DB().Model(dao.table)
for _, handler := range dao.handlers {
model = handler(model)
}
return model.Safe().Ctx(ctx)
}
// Transaction wraps the transaction logic using function f.

View File

@ -0,0 +1,95 @@
// ==========================================================================
// 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"
)
// SignInRewardDetailsDao is the data access object for the table sign_in_reward_details.
type SignInRewardDetailsDao 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 SignInRewardDetailsColumns // columns contains all the column names of Table for convenient usage.
handlers []gdb.ModelHandler // handlers for customized model modification.
}
// SignInRewardDetailsColumns defines and stores column names for the table sign_in_reward_details.
type SignInRewardDetailsColumns struct {
Id string // 主键
RuleId string // 规则ID关联 sign_in_reward_rules 表
DayNumber string // 签到天数1到cycle_days
RewardType string // 奖励类型1=积分
Quantity string // 奖励数量,如积分数量或礼包数量
Status string // 记录状态1=启用0=禁用
CreatedAt string // 创建时间
UpdatedAt string // 更新时间
DeletedAt string // 软删除时间戳
}
// signInRewardDetailsColumns holds the columns for the table sign_in_reward_details.
var signInRewardDetailsColumns = SignInRewardDetailsColumns{
Id: "id",
RuleId: "rule_id",
DayNumber: "day_number",
RewardType: "reward_type",
Quantity: "quantity",
Status: "status",
CreatedAt: "created_at",
UpdatedAt: "updated_at",
DeletedAt: "deleted_at",
}
// NewSignInRewardDetailsDao creates and returns a new DAO object for table data access.
func NewSignInRewardDetailsDao(handlers ...gdb.ModelHandler) *SignInRewardDetailsDao {
return &SignInRewardDetailsDao{
group: "default",
table: "sign_in_reward_details",
columns: signInRewardDetailsColumns,
handlers: handlers,
}
}
// DB retrieves and returns the underlying raw database management object of the current DAO.
func (dao *SignInRewardDetailsDao) DB() gdb.DB {
return g.DB(dao.group)
}
// Table returns the table name of the current DAO.
func (dao *SignInRewardDetailsDao) Table() string {
return dao.table
}
// Columns returns all column names of the current DAO.
func (dao *SignInRewardDetailsDao) Columns() SignInRewardDetailsColumns {
return dao.columns
}
// Group returns the database configuration group name of the current DAO.
func (dao *SignInRewardDetailsDao) 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 *SignInRewardDetailsDao) Ctx(ctx context.Context) *gdb.Model {
model := dao.DB().Model(dao.table)
for _, handler := range dao.handlers {
model = handler(model)
}
return model.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 *SignInRewardDetailsDao) Transaction(ctx context.Context, f func(ctx context.Context, tx gdb.TX) error) (err error) {
return dao.Ctx(ctx).Transaction(ctx, f)
}

View File

@ -0,0 +1,95 @@
// ==========================================================================
// 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"
)
// SignInRewardRulesDao is the data access object for the table sign_in_reward_rules.
type SignInRewardRulesDao 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 SignInRewardRulesColumns // columns contains all the column names of Table for convenient usage.
handlers []gdb.ModelHandler // handlers for customized model modification.
}
// SignInRewardRulesColumns defines and stores column names for the table sign_in_reward_rules.
type SignInRewardRulesColumns struct {
Id string // 主键
RuleName string // 规则名称如“7天签到活动”
CycleDays string // 奖励周期天数如7天
StartDate string // 活动开始日期
EndDate string // 活动结束日期
Status string // 规则状态1=启用0=禁用
CreatedAt string // 创建时间
UpdatedAt string // 更新时间
DeletedAt string // 软删除时间戳
}
// signInRewardRulesColumns holds the columns for the table sign_in_reward_rules.
var signInRewardRulesColumns = SignInRewardRulesColumns{
Id: "id",
RuleName: "rule_name",
CycleDays: "cycle_days",
StartDate: "start_date",
EndDate: "end_date",
Status: "status",
CreatedAt: "created_at",
UpdatedAt: "updated_at",
DeletedAt: "deleted_at",
}
// NewSignInRewardRulesDao creates and returns a new DAO object for table data access.
func NewSignInRewardRulesDao(handlers ...gdb.ModelHandler) *SignInRewardRulesDao {
return &SignInRewardRulesDao{
group: "default",
table: "sign_in_reward_rules",
columns: signInRewardRulesColumns,
handlers: handlers,
}
}
// DB retrieves and returns the underlying raw database management object of the current DAO.
func (dao *SignInRewardRulesDao) DB() gdb.DB {
return g.DB(dao.group)
}
// Table returns the table name of the current DAO.
func (dao *SignInRewardRulesDao) Table() string {
return dao.table
}
// Columns returns all column names of the current DAO.
func (dao *SignInRewardRulesDao) Columns() SignInRewardRulesColumns {
return dao.columns
}
// Group returns the database configuration group name of the current DAO.
func (dao *SignInRewardRulesDao) 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 *SignInRewardRulesDao) Ctx(ctx context.Context) *gdb.Model {
model := dao.DB().Model(dao.table)
for _, handler := range dao.handlers {
model = handler(model)
}
return model.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 *SignInRewardRulesDao) Transaction(ctx context.Context, f func(ctx context.Context, tx gdb.TX) error) (err error) {
return dao.Ctx(ctx).Transaction(ctx, f)
}

View 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"
)
// SystemDao is the data access object for the table system.
type SystemDao 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 SystemColumns // columns contains all the column names of Table for convenient usage.
handlers []gdb.ModelHandler // handlers for customized model modification.
}
// SystemColumns defines and stores column names for the table system.
type SystemColumns struct {
Key string //
Value string //
}
// systemColumns holds the columns for the table system.
var systemColumns = SystemColumns{
Key: "key",
Value: "value",
}
// NewSystemDao creates and returns a new DAO object for table data access.
func NewSystemDao(handlers ...gdb.ModelHandler) *SystemDao {
return &SystemDao{
group: "default",
table: "system",
columns: systemColumns,
handlers: handlers,
}
}
// DB retrieves and returns the underlying raw database management object of the current DAO.
func (dao *SystemDao) DB() gdb.DB {
return g.DB(dao.group)
}
// Table returns the table name of the current DAO.
func (dao *SystemDao) Table() string {
return dao.table
}
// Columns returns all column names of the current DAO.
func (dao *SystemDao) Columns() SystemColumns {
return dao.columns
}
// Group returns the database configuration group name of the current DAO.
func (dao *SystemDao) 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 *SystemDao) Ctx(ctx context.Context) *gdb.Model {
model := dao.DB().Model(dao.table)
for _, handler := range dao.handlers {
model = handler(model)
}
return model.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 *SystemDao) Transaction(ctx context.Context, f func(ctx context.Context, tx gdb.TX) error) (err error) {
return dao.Ctx(ctx).Transaction(ctx, f)
}

View File

@ -0,0 +1,93 @@
// ==========================================================================
// 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"
)
// TaskLogsDao is the data access object for the table task_logs.
type TaskLogsDao 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 TaskLogsColumns // columns contains all the column names of Table for convenient usage.
handlers []gdb.ModelHandler // handlers for customized model modification.
}
// TaskLogsColumns defines and stores column names for the table task_logs.
type TaskLogsColumns struct {
Id string // 任务日志ID
TaskId string // 任务ID关联 tasks.id
UserId string // 用户ID关联 users.id
RewardPoints string // 本次任务获得的积分
ActionTime string // 操作时间(如完成时间)
Status string // 日志状态1=有效2=无效
Extra string // 扩展信息例如来源、IP 等
CreatedAt string // 创建时间
}
// taskLogsColumns holds the columns for the table task_logs.
var taskLogsColumns = TaskLogsColumns{
Id: "id",
TaskId: "task_id",
UserId: "user_id",
RewardPoints: "reward_points",
ActionTime: "action_time",
Status: "status",
Extra: "extra",
CreatedAt: "created_at",
}
// NewTaskLogsDao creates and returns a new DAO object for table data access.
func NewTaskLogsDao(handlers ...gdb.ModelHandler) *TaskLogsDao {
return &TaskLogsDao{
group: "default",
table: "task_logs",
columns: taskLogsColumns,
handlers: handlers,
}
}
// DB retrieves and returns the underlying raw database management object of the current DAO.
func (dao *TaskLogsDao) DB() gdb.DB {
return g.DB(dao.group)
}
// Table returns the table name of the current DAO.
func (dao *TaskLogsDao) Table() string {
return dao.table
}
// Columns returns all column names of the current DAO.
func (dao *TaskLogsDao) Columns() TaskLogsColumns {
return dao.columns
}
// Group returns the database configuration group name of the current DAO.
func (dao *TaskLogsDao) 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 *TaskLogsDao) Ctx(ctx context.Context) *gdb.Model {
model := dao.DB().Model(dao.table)
for _, handler := range dao.handlers {
model = handler(model)
}
return model.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 *TaskLogsDao) Transaction(ctx context.Context, f func(ctx context.Context, tx gdb.TX) error) (err error) {
return dao.Ctx(ctx).Transaction(ctx, f)
}

View File

@ -0,0 +1,83 @@
// ==========================================================================
// 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"
)
// TaskTypesDao is the data access object for the table task_types.
type TaskTypesDao 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 TaskTypesColumns // columns contains all the column names of Table for convenient usage.
}
// TaskTypesColumns defines and stores column names for the table task_types.
type TaskTypesColumns struct {
Id string // 任务类型ID
Name string // 任务类型名称,例如:广告、写一本书、首次登录
Description string // 任务类型描述
Status string // 状态1=启用2=禁用
CreatedAt string // 创建时间
UpdatedAt string // 更新时间
}
// taskTypesColumns holds the columns for the table task_types.
var taskTypesColumns = TaskTypesColumns{
Id: "id",
Name: "name",
Description: "description",
Status: "status",
CreatedAt: "created_at",
UpdatedAt: "updated_at",
}
// NewTaskTypesDao creates and returns a new DAO object for table data access.
func NewTaskTypesDao() *TaskTypesDao {
return &TaskTypesDao{
group: "default",
table: "task_types",
columns: taskTypesColumns,
}
}
// DB retrieves and returns the underlying raw database management object of the current DAO.
func (dao *TaskTypesDao) DB() gdb.DB {
return g.DB(dao.group)
}
// Table returns the table name of the current DAO.
func (dao *TaskTypesDao) Table() string {
return dao.table
}
// Columns returns all column names of the current DAO.
func (dao *TaskTypesDao) Columns() TaskTypesColumns {
return dao.columns
}
// Group returns the database configuration group name of the current DAO.
func (dao *TaskTypesDao) 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 *TaskTypesDao) 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 *TaskTypesDao) Transaction(ctx context.Context, f func(ctx context.Context, tx gdb.TX) error) (err error) {
return dao.Ctx(ctx).Transaction(ctx, f)
}

View File

@ -0,0 +1,95 @@
// ==========================================================================
// 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"
)
// TasksDao is the data access object for the table tasks.
type TasksDao 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 TasksColumns // columns contains all the column names of Table for convenient usage.
handlers []gdb.ModelHandler // handlers for customized model modification.
}
// TasksColumns defines and stores column names for the table tasks.
type TasksColumns struct {
Id string // 任务ID
TaskType string // 任务类型1=首次登录2=广告3=发布书籍
Title string // 任务标题
Description string // 任务描述
RewardPoints string // 完成任务奖励的积分数
Status string // 状态1=启用2=禁用
CreatedAt string // 创建时间
UpdatedAt string // 更新时间
DeletedAt string // 软删除时间戳
}
// tasksColumns holds the columns for the table tasks.
var tasksColumns = TasksColumns{
Id: "id",
TaskType: "task_type",
Title: "title",
Description: "description",
RewardPoints: "reward_points",
Status: "status",
CreatedAt: "created_at",
UpdatedAt: "updated_at",
DeletedAt: "deleted_at",
}
// NewTasksDao creates and returns a new DAO object for table data access.
func NewTasksDao(handlers ...gdb.ModelHandler) *TasksDao {
return &TasksDao{
group: "default",
table: "tasks",
columns: tasksColumns,
handlers: handlers,
}
}
// DB retrieves and returns the underlying raw database management object of the current DAO.
func (dao *TasksDao) DB() gdb.DB {
return g.DB(dao.group)
}
// Table returns the table name of the current DAO.
func (dao *TasksDao) Table() string {
return dao.table
}
// Columns returns all column names of the current DAO.
func (dao *TasksDao) Columns() TasksColumns {
return dao.columns
}
// Group returns the database configuration group name of the current DAO.
func (dao *TasksDao) 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 *TasksDao) Ctx(ctx context.Context) *gdb.Model {
model := dao.DB().Model(dao.table)
for _, handler := range dao.handlers {
model = handler(model)
}
return model.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 *TasksDao) Transaction(ctx context.Context, f func(ctx context.Context, tx gdb.TX) error) (err error) {
return dao.Ctx(ctx).Transaction(ctx, f)
}

View File

@ -13,9 +13,10 @@ import (
// UserChapterPurchasesDao is the data access object for the table user_chapter_purchases.
type UserChapterPurchasesDao 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 UserChapterPurchasesColumns // columns contains all the column names of Table for convenient usage.
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 UserChapterPurchasesColumns // columns contains all the column names of Table for convenient usage.
handlers []gdb.ModelHandler // handlers for customized model modification.
}
// UserChapterPurchasesColumns defines and stores column names for the table user_chapter_purchases.
@ -39,11 +40,12 @@ var userChapterPurchasesColumns = UserChapterPurchasesColumns{
}
// NewUserChapterPurchasesDao creates and returns a new DAO object for table data access.
func NewUserChapterPurchasesDao() *UserChapterPurchasesDao {
func NewUserChapterPurchasesDao(handlers ...gdb.ModelHandler) *UserChapterPurchasesDao {
return &UserChapterPurchasesDao{
group: "default",
table: "user_chapter_purchases",
columns: userChapterPurchasesColumns,
group: "default",
table: "user_chapter_purchases",
columns: userChapterPurchasesColumns,
handlers: handlers,
}
}
@ -69,7 +71,11 @@ func (dao *UserChapterPurchasesDao) Group() string {
// Ctx creates and returns a Model for the current DAO. It automatically sets the context for the current operation.
func (dao *UserChapterPurchasesDao) Ctx(ctx context.Context) *gdb.Model {
return dao.DB().Model(dao.table).Safe().Ctx(ctx)
model := dao.DB().Model(dao.table)
for _, handler := range dao.handlers {
model = handler(model)
}
return model.Safe().Ctx(ctx)
}
// Transaction wraps the transaction logic using function f.

View File

@ -13,9 +13,10 @@ import (
// UserFollowAuthorsDao is the data access object for the table user_follow_authors.
type UserFollowAuthorsDao 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 UserFollowAuthorsColumns // columns contains all the column names of Table for convenient usage.
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 UserFollowAuthorsColumns // columns contains all the column names of Table for convenient usage.
handlers []gdb.ModelHandler // handlers for customized model modification.
}
// UserFollowAuthorsColumns defines and stores column names for the table user_follow_authors.
@ -35,11 +36,12 @@ var userFollowAuthorsColumns = UserFollowAuthorsColumns{
}
// NewUserFollowAuthorsDao creates and returns a new DAO object for table data access.
func NewUserFollowAuthorsDao() *UserFollowAuthorsDao {
func NewUserFollowAuthorsDao(handlers ...gdb.ModelHandler) *UserFollowAuthorsDao {
return &UserFollowAuthorsDao{
group: "default",
table: "user_follow_authors",
columns: userFollowAuthorsColumns,
group: "default",
table: "user_follow_authors",
columns: userFollowAuthorsColumns,
handlers: handlers,
}
}
@ -65,7 +67,11 @@ func (dao *UserFollowAuthorsDao) Group() string {
// Ctx creates and returns a Model for the current DAO. It automatically sets the context for the current operation.
func (dao *UserFollowAuthorsDao) Ctx(ctx context.Context) *gdb.Model {
return dao.DB().Model(dao.table).Safe().Ctx(ctx)
model := dao.DB().Model(dao.table)
for _, handler := range dao.handlers {
model = handler(model)
}
return model.Safe().Ctx(ctx)
}
// Transaction wraps the transaction logic using function f.

View File

@ -13,9 +13,10 @@ import (
// UserPointsLogsDao is the data access object for the table user_points_logs.
type UserPointsLogsDao 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 UserPointsLogsColumns // columns contains all the column names of Table for convenient usage.
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 UserPointsLogsColumns // columns contains all the column names of Table for convenient usage.
handlers []gdb.ModelHandler // handlers for customized model modification.
}
// UserPointsLogsColumns defines and stores column names for the table user_points_logs.
@ -41,11 +42,12 @@ var userPointsLogsColumns = UserPointsLogsColumns{
}
// NewUserPointsLogsDao creates and returns a new DAO object for table data access.
func NewUserPointsLogsDao() *UserPointsLogsDao {
func NewUserPointsLogsDao(handlers ...gdb.ModelHandler) *UserPointsLogsDao {
return &UserPointsLogsDao{
group: "default",
table: "user_points_logs",
columns: userPointsLogsColumns,
group: "default",
table: "user_points_logs",
columns: userPointsLogsColumns,
handlers: handlers,
}
}
@ -71,7 +73,11 @@ func (dao *UserPointsLogsDao) Group() string {
// Ctx creates and returns a Model for the current DAO. It automatically sets the context for the current operation.
func (dao *UserPointsLogsDao) Ctx(ctx context.Context) *gdb.Model {
return dao.DB().Model(dao.table).Safe().Ctx(ctx)
model := dao.DB().Model(dao.table)
for _, handler := range dao.handlers {
model = handler(model)
}
return model.Safe().Ctx(ctx)
}
// Transaction wraps the transaction logic using function f.

View File

@ -13,9 +13,10 @@ import (
// 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.
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.
handlers []gdb.ModelHandler // handlers for customized model modification.
}
// UserReadHistoryColumns defines and stores column names for the table user_read_history.
@ -37,11 +38,12 @@ var userReadHistoryColumns = UserReadHistoryColumns{
}
// NewUserReadHistoryDao creates and returns a new DAO object for table data access.
func NewUserReadHistoryDao() *UserReadHistoryDao {
func NewUserReadHistoryDao(handlers ...gdb.ModelHandler) *UserReadHistoryDao {
return &UserReadHistoryDao{
group: "default",
table: "user_read_history",
columns: userReadHistoryColumns,
group: "default",
table: "user_read_history",
columns: userReadHistoryColumns,
handlers: handlers,
}
}
@ -67,7 +69,11 @@ func (dao *UserReadHistoryDao) Group() string {
// 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)
model := dao.DB().Model(dao.table)
for _, handler := range dao.handlers {
model = handler(model)
}
return model.Safe().Ctx(ctx)
}
// Transaction wraps the transaction logic using function f.

View File

@ -13,9 +13,10 @@ import (
// UserReadRecordsDao is the data access object for the table user_read_records.
type UserReadRecordsDao struct {
table string // table is the underlying table name of the DAO.
group string // group is the database configuration group name of the current DAO.
columns UserReadRecordsColumns // columns contains all the column names of Table for convenient usage.
table string // table is the underlying table name of the DAO.
group string // group is the database configuration group name of the current DAO.
columns UserReadRecordsColumns // columns contains all the column names of Table for convenient usage.
handlers []gdb.ModelHandler // handlers for customized model modification.
}
// UserReadRecordsColumns defines and stores column names for the table user_read_records.
@ -43,11 +44,12 @@ var userReadRecordsColumns = UserReadRecordsColumns{
}
// NewUserReadRecordsDao creates and returns a new DAO object for table data access.
func NewUserReadRecordsDao() *UserReadRecordsDao {
func NewUserReadRecordsDao(handlers ...gdb.ModelHandler) *UserReadRecordsDao {
return &UserReadRecordsDao{
group: "default",
table: "user_read_records",
columns: userReadRecordsColumns,
group: "default",
table: "user_read_records",
columns: userReadRecordsColumns,
handlers: handlers,
}
}
@ -73,7 +75,11 @@ func (dao *UserReadRecordsDao) Group() string {
// Ctx creates and returns a Model for the current DAO. It automatically sets the context for the current operation.
func (dao *UserReadRecordsDao) Ctx(ctx context.Context) *gdb.Model {
return dao.DB().Model(dao.table).Safe().Ctx(ctx)
model := dao.DB().Model(dao.table)
for _, handler := range dao.handlers {
model = handler(model)
}
return model.Safe().Ctx(ctx)
}
// Transaction wraps the transaction logic using function f.

View File

@ -0,0 +1,97 @@
// ==========================================================================
// 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"
)
// UserSignInLogsDao is the data access object for the table user_sign_in_logs.
type UserSignInLogsDao 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 UserSignInLogsColumns // columns contains all the column names of Table for convenient usage.
handlers []gdb.ModelHandler // handlers for customized model modification.
}
// UserSignInLogsColumns defines and stores column names for the table user_sign_in_logs.
type UserSignInLogsColumns struct {
Id string // 主键
UserId string // 用户ID关联 users 表
RuleId string // 规则ID关联 sign_in_reward_rules 表
RewardDetailId string // 奖励详情ID关联 sign_in_reward_details 表
SignInDate string // 签到日期
Quantity string // 奖励数量,如积分数量或礼包数量
Status string // 记录状态1=有效0=无效
CreatedAt string // 创建时间
UpdatedAt string // 更新时间
DeletedAt string // 软删除时间戳
}
// userSignInLogsColumns holds the columns for the table user_sign_in_logs.
var userSignInLogsColumns = UserSignInLogsColumns{
Id: "id",
UserId: "user_id",
RuleId: "rule_id",
RewardDetailId: "reward_detail_id",
SignInDate: "sign_in_date",
Quantity: "quantity",
Status: "status",
CreatedAt: "created_at",
UpdatedAt: "updated_at",
DeletedAt: "deleted_at",
}
// NewUserSignInLogsDao creates and returns a new DAO object for table data access.
func NewUserSignInLogsDao(handlers ...gdb.ModelHandler) *UserSignInLogsDao {
return &UserSignInLogsDao{
group: "default",
table: "user_sign_in_logs",
columns: userSignInLogsColumns,
handlers: handlers,
}
}
// DB retrieves and returns the underlying raw database management object of the current DAO.
func (dao *UserSignInLogsDao) DB() gdb.DB {
return g.DB(dao.group)
}
// Table returns the table name of the current DAO.
func (dao *UserSignInLogsDao) Table() string {
return dao.table
}
// Columns returns all column names of the current DAO.
func (dao *UserSignInLogsDao) Columns() UserSignInLogsColumns {
return dao.columns
}
// Group returns the database configuration group name of the current DAO.
func (dao *UserSignInLogsDao) 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 *UserSignInLogsDao) Ctx(ctx context.Context) *gdb.Model {
model := dao.DB().Model(dao.table)
for _, handler := range dao.handlers {
model = handler(model)
}
return model.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 *UserSignInLogsDao) Transaction(ctx context.Context, f func(ctx context.Context, tx gdb.TX) error) (err error) {
return dao.Ctx(ctx).Transaction(ctx, f)
}

View File

@ -13,43 +13,49 @@ import (
// UsersDao is the data access object for the table users.
type UsersDao 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 UsersColumns // columns contains all the column names of Table for convenient usage.
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 UsersColumns // columns contains all the column names of Table for convenient usage.
handlers []gdb.ModelHandler // handlers for customized model modification.
}
// UsersColumns defines and stores column names for the table users.
type UsersColumns struct {
Id string // 用户ID
Username string // 用户名
PasswordHash string // 密码哈希
Avatar string // 头像URL
Email string // 邮箱
Points string // 积分
CreatedAt string // 注册时间
UpdatedAt string // 更新时间
DeletedAt string // 软删除时间戳
Id string // 用户ID
Username string // 用户名
PasswordHash string // 密码哈希
Avatar string // 头像URL
Email string // 邮箱
Points string // 积分
CreatedAt string // 注册时间
UpdatedAt string // 更新时间
DeletedAt string // 软删除时间戳
BackgroundUrl string // 作者背景图
AttentionCount string // 关注他人的数量 attention count
}
// usersColumns holds the columns for the table users.
var usersColumns = UsersColumns{
Id: "id",
Username: "username",
PasswordHash: "password_hash",
Avatar: "avatar",
Email: "email",
Points: "points",
CreatedAt: "created_at",
UpdatedAt: "updated_at",
DeletedAt: "deleted_at",
Id: "id",
Username: "username",
PasswordHash: "password_hash",
Avatar: "avatar",
Email: "email",
Points: "points",
CreatedAt: "created_at",
UpdatedAt: "updated_at",
DeletedAt: "deleted_at",
BackgroundUrl: "background_url",
AttentionCount: "attention_count",
}
// NewUsersDao creates and returns a new DAO object for table data access.
func NewUsersDao() *UsersDao {
func NewUsersDao(handlers ...gdb.ModelHandler) *UsersDao {
return &UsersDao{
group: "default",
table: "users",
columns: usersColumns,
group: "default",
table: "users",
columns: usersColumns,
handlers: handlers,
}
}
@ -75,7 +81,11 @@ func (dao *UsersDao) Group() string {
// Ctx creates and returns a Model for the current DAO. It automatically sets the context for the current operation.
func (dao *UsersDao) Ctx(ctx context.Context) *gdb.Model {
return dao.DB().Model(dao.table).Safe().Ctx(ctx)
model := dao.DB().Model(dao.table)
for _, handler := range dao.handlers {
model = handler(model)
}
return model.Safe().Ctx(ctx)
}
// Transaction wraps the transaction logic using function f.

View 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"
)
// internalSignInRewardDetailsDao is an internal type for wrapping the internal DAO implementation.
type internalSignInRewardDetailsDao = *internal.SignInRewardDetailsDao
// signInRewardDetailsDao is the data access object for the table sign_in_reward_details.
// You can define custom methods on it to extend its functionality as needed.
type signInRewardDetailsDao struct {
internalSignInRewardDetailsDao
}
var (
// SignInRewardDetails is a globally accessible object for table sign_in_reward_details operations.
SignInRewardDetails = signInRewardDetailsDao{
internal.NewSignInRewardDetailsDao(),
}
)
// Add your custom methods and functionality below.

View 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"
)
// internalSignInRewardRulesDao is an internal type for wrapping the internal DAO implementation.
type internalSignInRewardRulesDao = *internal.SignInRewardRulesDao
// signInRewardRulesDao is the data access object for the table sign_in_reward_rules.
// You can define custom methods on it to extend its functionality as needed.
type signInRewardRulesDao struct {
internalSignInRewardRulesDao
}
var (
// SignInRewardRules is a globally accessible object for table sign_in_reward_rules operations.
SignInRewardRules = signInRewardRulesDao{
internal.NewSignInRewardRulesDao(),
}
)
// Add your custom methods and functionality below.

27
internal/dao/system.go Normal file
View 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"
)
// internalSystemDao is an internal type for wrapping the internal DAO implementation.
type internalSystemDao = *internal.SystemDao
// systemDao is the data access object for the table system.
// You can define custom methods on it to extend its functionality as needed.
type systemDao struct {
internalSystemDao
}
var (
// System is a globally accessible object for table system operations.
System = systemDao{
internal.NewSystemDao(),
}
)
// Add your custom methods and functionality below.

27
internal/dao/task_logs.go Normal file
View 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"
)
// internalTaskLogsDao is an internal type for wrapping the internal DAO implementation.
type internalTaskLogsDao = *internal.TaskLogsDao
// taskLogsDao is the data access object for the table task_logs.
// You can define custom methods on it to extend its functionality as needed.
type taskLogsDao struct {
internalTaskLogsDao
}
var (
// TaskLogs is a globally accessible object for table task_logs operations.
TaskLogs = taskLogsDao{
internal.NewTaskLogsDao(),
}
)
// Add your custom methods and functionality below.

View 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"
)
// internalTaskTypesDao is an internal type for wrapping the internal DAO implementation.
type internalTaskTypesDao = *internal.TaskTypesDao
// taskTypesDao is the data access object for the table task_types.
// You can define custom methods on it to extend its functionality as needed.
type taskTypesDao struct {
internalTaskTypesDao
}
var (
// TaskTypes is a globally accessible object for table task_types operations.
TaskTypes = taskTypesDao{
internal.NewTaskTypesDao(),
}
)
// Add your custom methods and functionality below.

27
internal/dao/tasks.go Normal file
View 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"
)
// internalTasksDao is an internal type for wrapping the internal DAO implementation.
type internalTasksDao = *internal.TasksDao
// tasksDao is the data access object for the table tasks.
// You can define custom methods on it to extend its functionality as needed.
type tasksDao struct {
internalTasksDao
}
var (
// Tasks is a globally accessible object for table tasks operations.
Tasks = tasksDao{
internal.NewTasksDao(),
}
)
// Add your custom methods and functionality below.

View 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"
)
// internalUserSignInLogsDao is an internal type for wrapping the internal DAO implementation.
type internalUserSignInLogsDao = *internal.UserSignInLogsDao
// userSignInLogsDao is the data access object for the table user_sign_in_logs.
// You can define custom methods on it to extend its functionality as needed.
type userSignInLogsDao struct {
internalUserSignInLogsDao
}
var (
// UserSignInLogs is a globally accessible object for table user_sign_in_logs operations.
UserSignInLogs = userSignInLogsDao{
internal.NewUserSignInLogsDao(),
}
)
// Add your custom methods and functionality below.

View File

@ -0,0 +1,273 @@
package ads
import (
"context"
"fmt"
"server/internal/consts"
"server/internal/dao"
"server/internal/model"
"server/internal/model/do"
"server/internal/service"
"server/utility/ecode"
"server/utility/encrypt"
"server/utility/mqtt"
"server/utility/state_machine"
"time"
"github.com/gogf/gf/v2/os/glog"
"github.com/gogf/gf/v2/database/gdb"
"github.com/gogf/gf/v2/frame/g"
)
type sAds struct {
stateMachine *state_machine.AdStateMachine
}
func New() service.IAds {
return &sAds{
stateMachine: state_machine.NewAdStateMachine(),
}
}
func init() {
service.RegisterAds(New())
}
// Upload 广告数据上传 - 处理用户广告状态流转
func (s *sAds) Upload(ctx context.Context, in *model.AdsUploadIn) (out *model.AdsUploadOut, err error) {
// 解密广告数据
adsData, err := encrypt.DecryptAdsData(in.Data)
if err != nil {
return nil, ecode.Fail.Sub("data_decrypt_failed")
}
// 验证数据
if adsData.AdsPlatId <= 0 || adsData.AdsCategoryId <= 0 || adsData.AppPackage == "" {
return nil, ecode.Params.Sub("invalid_ads_data")
}
// 使用事务同时操作多个表
err = dao.AdEventLogs.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {
// 1. 查找用户该广告的最新记录,确保状态流转是在同一条广告记录上进行的
var fromState consts.AdState
var adEventId int64 // 广告事件ID用于关联状态流转记录
var isNewLifecycle bool // 是否是新的生命周期
// 当前状态
toState := consts.AdState(adsData.Status)
// 拉取成功和拉取失败总是新的广告生命周期的开始
if toState == consts.StateFetchSuccess || toState == consts.StateFetchFailed {
isNewLifecycle = true
fromState = 0
glog.Infof(ctx, "Starting new ad lifecycle with fetch state for user %d, app %s, state: %s",
in.UserId, adsData.AppPackage, consts.GetStateDescription(toState))
} else {
// 查询条件同一用户、同一平台、同一广告类型、同一APP包名
latestLog, err := dao.AdEventLogs.Ctx(ctx).TX(tx).
Where(do.AdEventLogs{
UserId: in.UserId,
AdsPlatId: adsData.AdsPlatId,
AdsCategoryId: adsData.AdsCategoryId,
AppPackage: adsData.AppPackage,
}).
Order("created_at DESC").
One()
if err == nil && !latestLog.IsEmpty() {
fromState = consts.AdState(latestLog["status"].Int())
adEventId = latestLog["id"].Int64()
// 检查是否是终止状态,如果是终止状态,则需要创建新的广告记录
if s.stateMachine.IsTerminalState(fromState) {
// 如果是终止状态,则表示这是一个新的广告生命周期
isNewLifecycle = true
fromState = 0 // 重置状态,表示新的生命周期开始
glog.Infof(ctx, "Starting new ad lifecycle after terminal state for user %d, app %s",
in.UserId, adsData.AppPackage)
} else {
glog.Infof(ctx, "Continuing ad lifecycle for user %d, app %s, from state %d to %d",
in.UserId, adsData.AppPackage, fromState, adsData.Status)
}
} else {
// 没有找到记录,这是第一次上传该广告数据
isNewLifecycle = true
glog.Infof(ctx, "First ad upload for user %d, app %s", in.UserId, adsData.AppPackage)
}
}
// 2. 使用状态机验证状态转换
flowID := generateFlowID(in.UserId, adsData.AppPackage)
// 如果不是新的生命周期,则验证状态转换
if !isNewLifecycle {
err = s.stateMachine.Transition(ctx, flowID, in.UserId, fromState, toState, "用户操作")
if err != nil {
glog.Warningf(ctx, "Invalid state transition: %s -> %s for user %d, app %s",
consts.GetStateDescription(fromState), consts.GetStateDescription(toState),
in.UserId, adsData.AppPackage)
return err
}
}
// 3. 插入或更新广告事件日志
var eventId int64
if isNewLifecycle {
// 新的生命周期,创建新记录
eventId, err = dao.AdEventLogs.Ctx(ctx).TX(tx).Data(do.AdEventLogs{
UserId: in.UserId,
AdsPlatId: adsData.AdsPlatId,
AdsCategoryId: adsData.AdsCategoryId,
AppPackage: adsData.AppPackage,
Status: adsData.Status,
StatusDesc: consts.GetStateDescription(toState),
}).InsertAndGetId()
if err != nil {
return ecode.Fail.Sub("database_save_failed")
}
} else {
// 继续现有生命周期,更新状态
_, err = dao.AdEventLogs.Ctx(ctx).TX(tx).
Where("id", adEventId).
Data(do.AdEventLogs{
Status: adsData.Status,
StatusDesc: consts.GetStateDescription(toState),
}).
Update()
if err != nil {
return ecode.Fail.Sub("database_update_failed")
}
eventId = adEventId
}
// 4. 插入状态流转记录
var fromStatus interface{}
if fromState != 0 {
fromStatus = int(fromState)
}
_, err = dao.AdEventTransitions.Ctx(ctx).TX(tx).Data(do.AdEventTransitions{
EventId: eventId,
FromStatus: fromStatus,
ToStatus: adsData.Status,
}).Insert()
if err != nil {
return ecode.Fail.Sub("transition_save_failed")
}
// 5. 如果状态是观看完成(StateWatched),则给用户增加积分
if toState == consts.StateWatched {
// 查询任务表中状态为1(启用)且任务类型为2(广告)的任务
taskInfo, err := dao.Tasks.Ctx(ctx).TX(tx).
Fields("id, reward_points").
Where("task_type", 2).
Where("status", 1).
One()
if err != nil {
glog.Errorf(ctx, "Failed to query ad task: %v", err)
return ecode.Fail.Sub("task_query_failed")
}
if !taskInfo.IsEmpty() {
taskId := taskInfo["id"].Int64()
rewardPoints := taskInfo["reward_points"].Uint()
if rewardPoints > 0 {
// 更新用户积分
_, err = dao.Users.Ctx(ctx).TX(tx).
Where("id", in.UserId).
Increment("points", rewardPoints)
if err != nil {
glog.Errorf(ctx, "Failed to update user points: %v", err)
return ecode.Fail.Sub("user_points_update_failed")
}
// 记录积分日志
_, err = dao.UserPointsLogs.Ctx(ctx).TX(tx).Data(do.UserPointsLogs{
UserId: in.UserId,
ChangeType: 2, // 2=收入(earn)
PointsChange: int(rewardPoints),
RelatedOrderId: eventId,
Description: "观看广告奖励",
}).Insert()
if err != nil {
glog.Errorf(ctx, "Failed to create user points log: %v", err)
return ecode.Fail.Sub("user_points_log_create_failed")
}
// 记录任务日志
_, err = dao.TaskLogs.Ctx(ctx).TX(tx).Data(do.TaskLogs{
TaskId: taskId,
UserId: in.UserId,
RewardPoints: rewardPoints,
}).Insert()
if err != nil {
glog.Errorf(ctx, "Failed to create task log: %v", err)
return ecode.Fail.Sub("task_log_create_failed")
}
glog.Infof(ctx, "User %d earned %d points for watching ad", in.UserId, rewardPoints)
}
} else {
glog.Warningf(ctx, "No active ad task found")
}
}
return nil
})
if err != nil {
return nil, err
}
// 构建MQTT消息
mqttMessage := map[string]interface{}{
"type": "ads",
"node_uid": in.NodeUid,
"device_code": in.DeviceCode,
"data": map[string]interface{}{
"ads_plat_id": adsData.AdsPlatId,
"ads_category_id": adsData.AdsCategoryId,
"app_package": adsData.AppPackage,
"status": adsData.Status,
"timestamp": time.Now().Unix(),
},
}
// 发送到MQTT
s.publishToMQTT(ctx, mqttMessage)
return &model.AdsUploadOut{Success: true}, nil
}
// generateFlowID 生成流转ID
func generateFlowID(userID int64, appPackage string) string {
return fmt.Sprintf("flow_%d_%s_%d", userID, appPackage, time.Now().Unix())
}
// publishToMQTT 发送消息到MQTT
func (s *sAds) publishToMQTT(ctx context.Context, message map[string]interface{}) {
mqttClient := mqtt.GetMQTTClient("amazon_sqs")
if mqttClient == nil {
glog.Errorf(ctx, "MQTT client not initialized")
return
}
queueName := g.Cfg().MustGet(ctx, "sqs.ads").String()
if queueName == "" {
glog.Errorf(ctx, "MQTT queue name not configured")
return
}
err := mqttClient.Publish(ctx, queueName, message)
if err != nil {
glog.Errorf(ctx, "Failed to publish message to MQTT: %v", err)
} else {
glog.Infof(ctx, "Message published to MQTT: %v", message)
}
}

View File

@ -62,8 +62,9 @@ func (s *sAdmin) Info(ctx context.Context, in *model.AdminInfoIn) (out *model.Ad
return nil, ecode.Fail.Sub("admin_query_failed")
}
return &model.AdminInfoOut{
AdminId: admin.Id,
Id: admin.Id,
Username: admin.Username,
Role: consts.AdminRoleCode,
}, nil
}

View File

@ -31,7 +31,7 @@ func (s *sAuthor) List(ctx context.Context, in *model.AuthorListIn) (out *model.
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 {
if err = m.Page(in.Page, in.Size).WithAll().ScanAndCount(&out.List, &out.Total, false); err != nil {
return
}
return
@ -226,13 +226,8 @@ func (s *sAuthor) Delete(ctx context.Context, in *model.AuthorDelIn) (out *model
// 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).
Where(dao.Authors.Columns().UserId, in.UserId).
Exist()
if err != nil {
return nil, ecode.Fail.Sub("author_query_failed")
@ -241,10 +236,10 @@ func (s *sAuthor) Apply(ctx context.Context, in *model.AuthorApplyIn) (out *mode
return nil, ecode.Params.Sub("author_user_exists")
}
if _, err := dao.Authors.Ctx(ctx).Data(do.Authors{
UserId: userId,
UserId: in.UserId,
PenName: in.PenName,
Bio: in.Bio,
Status: 1, // 默认正常
Status: 2, // 默认禁用
}).Insert(); err != nil {
return nil, ecode.Fail.Sub("author_create_failed")
}
@ -252,17 +247,74 @@ func (s *sAuthor) Apply(ctx context.Context, in *model.AuthorApplyIn) (out *mode
}
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()
err = dao.Authors.Ctx(ctx).WherePri(in.AuthorId).WithAll().Scan(&out)
if err != nil {
return nil, ecode.Fail.Sub("author_query_failed")
}
if out == nil {
return nil, ecode.NotFound.Sub("author_not_found")
}
userId := ctx.Value("id")
if userId != nil {
exist, err := dao.UserFollowAuthors.Ctx(ctx).
Where(dao.UserFollowAuthors.Columns().UserId, userId).
Where(dao.UserFollowAuthors.Columns().AuthorId, in.AuthorId).
Exist()
if err != nil {
return nil, ecode.Fail.Sub("user_follow_author_query_failed")
}
out.IsFollowed = exist
}
// 查询作者作品数量
out.WorksCount, err = dao.Books.Ctx(ctx).
Where(dao.Books.Columns().AuthorId, in.AuthorId).
Count()
if err != nil {
return nil, ecode.Fail.Sub("author_book_count_failed")
}
return out, nil
}
// AuthorInfo 获取作者信息
func (s *sAuthor) AuthorInfo(ctx context.Context, in *model.AuthorInfoIn) (out *model.AuthorInfoOut, err error) {
exist, err := dao.Authors.Ctx(ctx).Where(dao.Authors.Columns().UserId, in.UserId).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 {
var author struct {
Id int64 `json:"id"`
PenName string `json:"penName"`
}
err = dao.Authors.Ctx(ctx).Where(dao.Authors.Columns().UserId, in.UserId).Fields("id, pen_name").Scan(&author)
if err != nil {
return nil, ecode.Fail.Sub("author_query_failed")
}
return out, nil
return &model.AuthorInfoOut{
Id: author.Id,
PenName: author.PenName,
Role: "author",
}, nil
}
// 审核作者申请(通过/拒绝)
func (s *sAuthor) Review(ctx context.Context, in *model.AuthorReviewIn) (out *model.AuthorReviewOut, err error) {
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")
}
_, err = dao.Authors.Ctx(ctx).WherePri(in.AuthorId).Data(do.Authors{
Status: in.Status,
}).Update()
if err != nil {
return nil, ecode.Fail.Sub("author_review_failed")
}
return &model.AuthorReviewOut{Success: true}, nil
}

View File

@ -232,6 +232,9 @@ func (s *sBook) AppList(ctx context.Context, in *model.BookAppListIn) (out *mode
if in.IsFeatured {
m = m.Where(dao.Books.Columns().IsFeatured, 1)
}
if in.IsHot {
m = m.Where(dao.Books.Columns().IsHot, 1)
}
if in.Sort != "" {
m = m.Order(in.Sort)
}
@ -278,6 +281,30 @@ func (s *sBook) AppList(ctx context.Context, in *model.BookAppListIn) (out *mode
out.List[i].MyRating = 0
}
}
// 查询用户书架
type shelfRow struct {
BookId int64 `json:"bookId"`
}
shelves := make([]shelfRow, 0)
err = dao.Bookshelves.Ctx(ctx).
Fields("book_id").
Where(dao.Bookshelves.Columns().UserId, in.UserId).
WhereIn(dao.Bookshelves.Columns().BookId, bookIds).
Scan(&shelves)
if err == nil && len(shelves) > 0 {
shelfMap := make(map[int64]bool, len(shelves))
for _, s := range shelves {
shelfMap[s.BookId] = true
}
for i := range out.List {
out.List[i].IsInBookshelf = shelfMap[out.List[i].Id]
}
} else {
for i := range out.List {
out.List[i].IsInBookshelf = false
}
}
}
return out, nil
@ -323,7 +350,7 @@ func (s *sBook) AppRate(ctx context.Context, in *model.BookAppRateIn) (out *mode
// 开启事务处理评分
if err := dao.BookRatings.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {
// 检查是否已经评分过
exist, err := dao.BookRatings.Ctx(ctx).TX(tx).
exist, err := dao.BookRatings.Ctx(ctx).
Where(dao.BookRatings.Columns().UserId, in.UserId).
Where(dao.BookRatings.Columns().BookId, in.BookId).
Exist()
@ -333,7 +360,7 @@ func (s *sBook) AppRate(ctx context.Context, in *model.BookAppRateIn) (out *mode
if exist {
// 更新现有评分
_, err = dao.BookRatings.Ctx(ctx).TX(tx).
_, err = dao.BookRatings.Ctx(ctx).
Where(dao.BookRatings.Columns().UserId, in.UserId).
Where(dao.BookRatings.Columns().BookId, in.BookId).
Data(do.BookRatings{
@ -344,7 +371,7 @@ func (s *sBook) AppRate(ctx context.Context, in *model.BookAppRateIn) (out *mode
}
} else {
// 创建新评分记录
_, err = dao.BookRatings.Ctx(ctx).TX(tx).Data(do.BookRatings{
_, err = dao.BookRatings.Ctx(ctx).Data(do.BookRatings{
UserId: in.UserId,
BookId: in.BookId,
Score: in.Rating,
@ -355,20 +382,22 @@ func (s *sBook) AppRate(ctx context.Context, in *model.BookAppRateIn) (out *mode
}
// 重新计算书籍平均评分
var avgRating float64
err = dao.BookRatings.Ctx(ctx).TX(tx).
var result struct {
AvgRating float64 `json:"avg_rating"`
}
err = dao.BookRatings.Ctx(ctx).
Where(dao.BookRatings.Columns().BookId, in.BookId).
Fields("AVG(score) as avg_rating").
Scan(&avgRating)
Fields("COALESCE(AVG(" + dao.BookRatings.Columns().Score + "), 0) as avg_rating").
Scan(&result)
if err != nil {
return ecode.Fail.Sub("rating_calculation_failed")
}
// 更新书籍的平均评分
_, err = dao.Books.Ctx(ctx).TX(tx).
_, err = dao.Books.Ctx(ctx).
Where(dao.Books.Columns().Id, in.BookId).
Data(do.Books{
Rating: avgRating,
Rating: result.AvgRating,
}).Update()
if err != nil {
return ecode.Fail.Sub("book_rating_update_failed")
@ -397,7 +426,7 @@ func (s *sBook) AppDetail(ctx context.Context, in *model.BookAppDetailIn) (out *
m = m.Where(dao.Books.Columns().Id, in.Id)
// 执行查询
if err = m.Scan(out); err != nil {
if err = m.WithAll().Scan(out); err != nil {
return nil, ecode.Fail.Sub("book_query_failed")
}
@ -408,6 +437,29 @@ func (s *sBook) AppDetail(ctx context.Context, in *model.BookAppDetailIn) (out *
// 如果用户已登录,查询阅读进度
if in.UserId > 0 {
// 查询用户是否已将本书加入书架
count, err := dao.Bookshelves.Ctx(ctx).
Where(dao.Bookshelves.Columns().UserId, in.UserId).
Where(dao.Bookshelves.Columns().BookId, in.Id).
Count()
if err == nil {
out.IsInBookshelf = count > 0
}
// 查询用户是否已评分
var ratingRecord struct {
Score float64 `json:"score"`
}
err = dao.BookRatings.Ctx(ctx).
Fields("score").
Where(dao.BookRatings.Columns().UserId, in.UserId).
Where(dao.BookRatings.Columns().BookId, in.Id).
Scan(&ratingRecord)
if err == nil && ratingRecord.Score > 0 {
out.HasRated = true
out.MyRating = ratingRecord.Score
}
// 查询用户对该书籍的历史记录
var historyRecord struct {
ChapterId int64 `json:"chapterId"`
@ -435,7 +487,7 @@ func (s *sBook) AppDetail(ctx context.Context, in *model.BookAppDetailIn) (out *
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的记录
WhereGT(dao.UserReadRecords.Columns().ChapterId, 0). // 只统计有章节ID的记录
Count()
if err == nil {
@ -454,274 +506,174 @@ func (s *sBook) AppDetail(ctx context.Context, in *model.BookAppDetailIn) (out *
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
var (
ids []int64
extraMap map[int64]struct {
Progress int
LastReadAt string
}
total int
)
switch in.Type {
case 1: // 正在读
// 查询书架表中read_status=1的记录
case 1, 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, 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)
readStatus := 1
if in.Type == 2 {
readStatus = 2
}
q := 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, readStatus)
if in.Sort != "" {
q = q.Order(in.Sort)
} else {
q = q
}
err = q.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,
})
ids = make([]int64, 0, len(bookshelves))
extraMap = make(map[int64]struct {
Progress int
LastReadAt string
}, len(bookshelves))
for _, bs := range bookshelves {
ids = append(ids, bs.BookId)
extraMap[bs.BookId] = struct {
Progress int
LastReadAt string
}{
Progress: int(bs.LastReadPercent),
LastReadAt: bs.LastReadAt,
}
}
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表
case 3:
var histories []struct {
BookId int64 `json:"bookId"`
ChapterId int64 `json:"chapterId"`
ReadAt string `json:"readAt"`
}
q := dao.UserReadHistory.Ctx(ctx).
Fields("book_id, chapter_id, read_at").
Where(dao.UserReadHistory.Columns().UserId, in.UserId)
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)
q = q.Order(in.Sort)
} 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)
q = q.OrderDesc(dao.UserReadHistory.Columns().ReadAt)
}
err = q.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,
})
ids = make([]int64, 0, len(histories))
extraMap = make(map[int64]struct {
Progress int
LastReadAt string
}, len(histories))
for _, h := range histories {
ids = append(ids, h.BookId)
extraMap[h.BookId] = struct {
Progress int
LastReadAt string
}{
Progress: 0,
LastReadAt: h.ReadAt,
}
}
default:
// 返回空列表
}
out = &model.MyBookListOut{
Total: total,
List: list,
var books []model.MyBookItem
if len(ids) > 0 {
err = dao.Books.Ctx(ctx).WhereIn(dao.Books.Columns().Id, ids).Scan(&books)
if err != nil {
return nil, ecode.Fail.Sub("book_query_failed")
}
}
// type3 需要查书架
shelfBookIds := map[int64]bool{}
if in.Type == 3 && len(ids) > 0 {
var bookshelves []struct{ BookId int64 }
err = dao.Bookshelves.Ctx(ctx).
Fields("book_id").
Where(dao.Bookshelves.Columns().UserId, in.UserId).
WhereIn(dao.Bookshelves.Columns().BookId, ids).
Scan(&bookshelves)
if err != nil {
return nil, ecode.Fail.Sub("bookshelf_query_failed")
}
for _, bs := range bookshelves {
shelfBookIds[bs.BookId] = true
}
}
for i := range books {
if info, ok := extraMap[books[i].Id]; ok {
books[i].Progress = info.Progress
books[i].LastReadAt = info.LastReadAt
}
if in.Type == 1 || in.Type == 2 {
books[i].IsInShelf = true
} else if in.Type == 3 {
books[i].IsInShelf = shelfBookIds[books[i].Id]
}
}
// 查询用户评分信息
if len(books) > 0 {
bookIds := make([]int64, 0, len(books))
for _, book := range books {
bookIds = append(bookIds, book.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 books {
if score, ok := ratingMap[books[i].Id]; ok {
books[i].HasRated = true
books[i].MyRating = score
} else {
books[i].HasRated = false
books[i].MyRating = 0
}
}
} else {
for i := range books {
books[i].HasRated = false
books[i].MyRating = 0
}
}
}
out.Total = total
out.List = books
return
}
@ -762,3 +714,22 @@ func (s *sBook) SetRecommended(ctx context.Context, in *model.BookSetRecommended
}
return &model.BookCRUDOut{Success: true}, nil
}
// SetHot: 单独修改书籍的热门状态
func (s *sBook) SetHot(ctx context.Context, in *model.BookSetHotIn) (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{
IsHot: in.IsHot,
}).Update()
if err != nil {
return nil, ecode.Fail.Sub("book_update_failed")
}
return &model.BookCRUDOut{Success: true}, nil
}

View File

@ -0,0 +1,226 @@
package book_recommendations
import (
"context"
"server/internal/dao"
"server/internal/model"
"server/internal/model/do"
"server/internal/service"
"server/utility/ecode"
"server/utility/oss"
"github.com/gogf/gf/v2/net/ghttp"
)
type sBookRecommendations struct{}
func New() service.IBookRecommendations {
return &sBookRecommendations{}
}
func init() {
service.RegisterBookRecommendations(New())
}
// List 获取推荐列表
func (s *sBookRecommendations) List(ctx context.Context, in *model.BookRecommendationsListIn) (out *model.BookRecommendationsListOut, err error) {
out = &model.BookRecommendationsListOut{}
m := dao.BookRecommendations.Ctx(ctx)
if in.Type != 0 {
m = m.Where(dao.BookRecommendations.Columns().Type, in.Type)
}
if in.Status != 0 {
m = m.Where(dao.BookRecommendations.Columns().Status, in.Status)
}
if in.BookId != 0 {
m = m.Where(dao.BookRecommendations.Columns().BookId, in.BookId)
}
m = m.Order(dao.BookRecommendations.Columns().SortOrder)
if err = m.Page(in.Page, in.Size).WithAll().ScanAndCount(&out.List, &out.Total, false); err != nil {
return nil, ecode.Fail.Sub("book_recommendation_query_failed")
}
return out, nil
}
// AppList 获取APP端推荐列表
func (s *sBookRecommendations) AppList(ctx context.Context, in *model.BookRecommendationsListIn) (out *model.BookRecommendationsAppListOut, err error) {
out = &model.BookRecommendationsAppListOut{}
m := dao.BookRecommendations.Ctx(ctx)
// 直接筛选状态为1的记录
m = m.Where(dao.BookRecommendations.Columns().Status, 1)
// 根据排序字段排序
m = m.Order(dao.BookRecommendations.Columns().SortOrder)
var list []model.RecommendAppItem
if err = m.Page(in.Page, in.Size).ScanAndCount(&list, &out.Total, false); err != nil {
return nil, ecode.Fail.Sub("book_recommendation_query_failed")
}
out.List = list
return out, nil
}
// Create 新增推荐
func (s *sBookRecommendations) Create(ctx context.Context, in *model.BookRecommendationsCreateIn) (out *model.BookRecommendationsCRUDOut, err error) {
// 检查同类型同书籍是否已存在(未软删除)
exist, err := dao.BookRecommendations.Ctx(ctx).
Where(dao.BookRecommendations.Columns().BookId, in.BookId).
Where(dao.BookRecommendations.Columns().Type, in.Type).
Exist()
if err != nil {
return nil, ecode.Fail.Sub("book_recommendation_query_failed")
}
if exist {
return nil, ecode.Params.Sub("book_recommendation_exists")
}
// 插入数据
_, err = dao.BookRecommendations.Ctx(ctx).Data(do.BookRecommendations{
BookId: in.BookId,
Type: in.Type,
CoverUrl: in.CoverUrl,
SortOrder: in.SortOrder,
Status: in.Status,
}).Insert()
if err != nil {
return nil, ecode.Fail.Sub("book_recommendation_create_failed")
}
return &model.BookRecommendationsCRUDOut{Success: true}, nil
}
// Update 编辑推荐
func (s *sBookRecommendations) Update(ctx context.Context, in *model.BookRecommendationsUpdateIn) (out *model.BookRecommendationsCRUDOut, err error) {
// 检查是否存在
exist, err := dao.BookRecommendations.Ctx(ctx).
Where(dao.BookRecommendations.Columns().Id, in.Id).
Exist()
if err != nil {
return nil, ecode.Fail.Sub("book_recommendation_query_failed")
}
if !exist {
return nil, ecode.NotFound.Sub("book_recommendation_not_found")
}
// 检查同类型同书籍是否有重复(排除自己)
repeat, err := dao.BookRecommendations.Ctx(ctx).
Where(dao.BookRecommendations.Columns().BookId, in.BookId).
Where(dao.BookRecommendations.Columns().Type, in.Type).
WhereNot(dao.BookRecommendations.Columns().Id, in.Id).
Exist()
if err != nil {
return nil, ecode.Fail.Sub("book_recommendation_query_failed")
}
if repeat {
return nil, ecode.Params.Sub("book_recommendation_exists")
}
_, err = dao.BookRecommendations.Ctx(ctx).
Where(dao.BookRecommendations.Columns().Id, in.Id).
Data(do.BookRecommendations{
BookId: in.BookId,
Type: in.Type,
CoverUrl: in.CoverUrl,
SortOrder: in.SortOrder,
Status: in.Status,
}).Update()
if err != nil {
return nil, ecode.Fail.Sub("book_recommendation_update_failed")
}
return &model.BookRecommendationsCRUDOut{Success: true}, nil
}
// Delete 删除推荐
func (s *sBookRecommendations) Delete(ctx context.Context, in *model.BookRecommendationsDeleteIn) (out *model.BookRecommendationsCRUDOut, err error) {
// 检查是否存在
exist, err := dao.BookRecommendations.Ctx(ctx).
Where(dao.BookRecommendations.Columns().Id, in.Id).
Exist()
if err != nil {
return nil, ecode.Fail.Sub("book_recommendation_query_failed")
}
if !exist {
return nil, ecode.NotFound.Sub("book_recommendation_not_found")
}
// 直接调用 Delete
_, err = dao.BookRecommendations.Ctx(ctx).
Where(dao.BookRecommendations.Columns().Id, in.Id).
Delete()
if err != nil {
return nil, ecode.Fail.Sub("book_recommendation_delete_failed")
}
return &model.BookRecommendationsCRUDOut{Success: true}, nil
}
// SetStatus 启用/禁用推荐
func (s *sBookRecommendations) SetStatus(ctx context.Context, in *model.BookRecommendationsSetStatusIn) (out *model.BookRecommendationsCRUDOut, err error) {
// 检查是否存在
exist, err := dao.BookRecommendations.Ctx(ctx).
Where(dao.BookRecommendations.Columns().Id, in.Id).
Exist()
if err != nil {
return nil, ecode.Fail.Sub("book_recommendation_query_failed")
}
if !exist {
return nil, ecode.NotFound.Sub("book_recommendation_not_found")
}
_, err = dao.BookRecommendations.Ctx(ctx).
Where(dao.BookRecommendations.Columns().Id, in.Id).
Data(do.BookRecommendations{
Status: in.Status,
}).Update()
if err != nil {
return nil, ecode.Fail.Sub("book_recommendation_update_failed")
}
return &model.BookRecommendationsCRUDOut{Success: true}, nil
}
// SortOrder 设置排序
func (s *sBookRecommendations) SortOrder(ctx context.Context, in *model.BookRecommendationsSortOrderIn) (out *model.BookRecommendationsCRUDOut, err error) {
// 检查是否存在
exist, err := dao.BookRecommendations.Ctx(ctx).
Where(dao.BookRecommendations.Columns().Id, in.Id).
Exist()
if err != nil {
return nil, ecode.Fail.Sub("book_recommendation_query_failed")
}
if !exist {
return nil, ecode.NotFound.Sub("book_recommendation_not_found")
}
_, err = dao.BookRecommendations.Ctx(ctx).
Where(dao.BookRecommendations.Columns().Id, in.Id).
Data(do.BookRecommendations{
SortOrder: in.SortOrder,
}).Update()
if err != nil {
return nil, ecode.Fail.Sub("book_recommendation_update_failed")
}
return &model.BookRecommendationsCRUDOut{Success: true}, nil
}
// UploadCover 上传推荐封面图
func (s *sBookRecommendations) UploadCover(ctx context.Context, file *ghttp.UploadFile) (url string, err error) {
if file == nil {
return "", ecode.Params.Sub("image_file_required")
}
// 校验文件类型(只允许图片)
contentType := file.Header.Get("Content-Type")
if contentType == "" || contentType[:6] != "image/" {
return "", ecode.Params.Sub("image_type_invalid")
}
allowedTypes := map[string]bool{
"image/jpeg": true,
"image/png": true,
"image/gif": true,
"image/webp": true,
}
if !allowedTypes[contentType] {
return "", ecode.Params.Sub("image_format_invalid")
}
if file.Size > 1*1024*1024 {
return "", ecode.Params.Sub("image_size_exceeded")
}
client := oss.GetOSSClient("amazon_s3")
if client == nil {
return "", ecode.Fail.Sub("server_error")
}
url, err = client.Upload(file, "recommend")
if err != nil {
return "", ecode.Fail.Sub("image_upload_failed")
}
return url, nil
}

View File

@ -55,3 +55,4 @@ func (s *sBookshelve) Delete(ctx context.Context, in *model.BookshelveDelIn) (ou
}
return &model.BookshelveCRUDOut{Success: true}, nil
}

View File

@ -180,13 +180,34 @@ func (s *sChapter) AppList(ctx context.Context, in *model.ChapterAppListIn) (out
return nil, ecode.Fail.Sub("read_record_query_failed")
}
// 查询购买记录
purchaseRecords := make([]struct {
ChapterId int64 `json:"chapterId"`
}, 0)
err = dao.UserChapterPurchases.Ctx(ctx).
Fields("chapter_id").
Where(dao.UserChapterPurchases.Columns().UserId, in.UserId).
Where(dao.UserChapterPurchases.Columns().BookId, in.BookId).
WhereIn(dao.UserChapterPurchases.Columns().ChapterId, chapterIds).
Scan(&purchaseRecords)
if err != nil {
return nil, ecode.Fail.Sub("purchase_record_query_failed")
}
// 构建阅读记录映射
readMap := make(map[int64]*gtime.Time)
for _, record := range readRecords {
readMap[record.ChapterId] = record.ReadAt
}
// 为每个章节设置阅读进度
// 构建购买记录映射
purchaseMap := make(map[int64]bool)
for _, record := range purchaseRecords {
purchaseMap[record.ChapterId] = true
}
// 为每个章节设置阅读进度和购买状态
for i := range out.List {
if readAt, exists := readMap[out.List[i].Id]; exists {
out.List[i].ReadAt = readAt
@ -195,6 +216,19 @@ func (s *sChapter) AppList(ctx context.Context, in *model.ChapterAppListIn) (out
out.List[i].ReadProgress = 0 // 未读
out.List[i].ReadAt = nil
}
// 设置购买状态
if out.List[i].IsLocked == 0 {
// 免费章节,直接设置为已购买
out.List[i].IsPurchased = true
} else {
// 付费章节,根据购买记录设置
if purchaseMap[out.List[i].Id] {
out.List[i].IsPurchased = true
} else {
out.List[i].IsPurchased = false
}
}
}
}
}
@ -473,7 +507,7 @@ func (s *sChapter) AppProgress(ctx context.Context, in *model.ChapterAppProgress
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).
WhereGT(dao.UserReadRecords.Columns().ChapterId, 0).
Count()
if err != nil {
return ecode.Fail.Sub("read_chapter_count_failed")
@ -525,3 +559,211 @@ func (s *sChapter) AppProgress(ctx context.Context, in *model.ChapterAppProgress
out.Success = true
return out, nil
}
// AppBatchProgress uploads batch reading progress for app
func (s *sChapter) AppBatchProgress(ctx context.Context, in *model.ChapterAppBatchProgressIn) (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")
}
// 必须指定章节列表
if len(in.Chapters) == 0 {
return nil, ecode.Fail.Sub("chapters_required")
}
// 检查用户是否存在
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")
}
// 验证所有章节进度
for _, chapter := range in.Chapters {
if chapter.ChapterId == 0 {
return nil, ecode.Fail.Sub("chapter_id_required")
}
if chapter.Progress < 0 || chapter.Progress > 100 {
return nil, ecode.Fail.Sub("progress_invalid")
}
}
// 检查所有章节是否存在
chapterIds := make([]int64, 0)
for _, chapter := range in.Chapters {
chapterIds = append(chapterIds, chapter.ChapterId)
}
exist, err = dao.Chapters.Ctx(ctx).
WhereIn(dao.Chapters.Columns().Id, chapterIds).
Where(dao.Chapters.Columns().BookId, in.BookId).
Exist()
if err != nil {
return nil, ecode.Fail.Sub("chapter_query_failed")
}
if !exist {
return nil, ecode.NotFound.Sub("chapter_not_found")
}
// 开启事务处理
if err := dao.UserReadRecords.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {
// 批量处理每个章节的进度
for _, chapter := range in.Chapters {
// 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, chapter.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, chapter.ChapterId).
Data(do.UserReadRecords{
Progress: chapter.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: chapter.ChapterId,
Progress: chapter.Progress,
ReadAt: gtime.Now(),
}).Insert()
if err != nil {
return ecode.Fail.Sub("read_record_create_failed")
}
}
}
// 2. 更新或创建历史记录(使用最后一个章节作为当前阅读章节)
lastChapter := in.Chapters[len(in.Chapters)-1]
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: lastChapter.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: lastChapter.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).
WhereGT(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
}
}
// 判断是否为最后一章
lastChapterInfo, 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 lastChapterInfo != nil && lastChapterInfo["id"].Int64() == lastChapter.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: lastChapter.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
}

View File

@ -5,14 +5,22 @@
package logic
import (
_ "server/internal/logic/ad_event_logs"
_ "server/internal/logic/admin"
_ "server/internal/logic/author"
_ "server/internal/logic/book"
_ "server/internal/logic/book_recommendations"
_ "server/internal/logic/bookshelve"
_ "server/internal/logic/category"
_ "server/internal/logic/chapter"
_ "server/internal/logic/feedback"
_ "server/internal/logic/sign_in_reward_details"
_ "server/internal/logic/sign_in_reward_rules"
_ "server/internal/logic/system"
_ "server/internal/logic/task"
_ "server/internal/logic/upload"
_ "server/internal/logic/user"
_ "server/internal/logic/user_follow_author"
_ "server/internal/logic/user_read_record"
_ "server/internal/logic/user_read_history"
_ "server/internal/logic/user_sign_in_logs"
)

Some files were not shown because too many files have changed in this diff Show More