基础项目
Some checks failed
CI / init (pull_request) Has been cancelled
CI / Frontend node 18.16.0 (pull_request) Has been cancelled
CI / Backend go (1.22) (pull_request) Has been cancelled
CI / release-pr (pull_request) Has been cancelled
CI / devops-test (1.22, 18.16.0) (pull_request) Has been cancelled
CI / release-please (pull_request) Has been cancelled
CI / devops-prod (1.22, 18.x) (pull_request) Has been cancelled
CI / docker (pull_request) Has been cancelled
Some checks failed
CI / init (pull_request) Has been cancelled
CI / Frontend node 18.16.0 (pull_request) Has been cancelled
CI / Backend go (1.22) (pull_request) Has been cancelled
CI / release-pr (pull_request) Has been cancelled
CI / devops-test (1.22, 18.16.0) (pull_request) Has been cancelled
CI / release-please (pull_request) Has been cancelled
CI / devops-prod (1.22, 18.x) (pull_request) Has been cancelled
CI / docker (pull_request) Has been cancelled
This commit is contained in:
9
server/model/book/base.go
Normal file
9
server/model/book/base.go
Normal file
@@ -0,0 +1,9 @@
|
||||
package book
|
||||
|
||||
import "time"
|
||||
|
||||
type HardDeleteModel struct {
|
||||
ID uint `json:"id" form:"id" gorm:"primarykey;comment:主键"`
|
||||
CreatedAt time.Time `json:"createdAt" form:"createdAt" gorm:"comment:创建时间"`
|
||||
UpdatedAt time.Time `json:"updatedAt" form:"updatedAt" gorm:"comment:更新时间"`
|
||||
}
|
||||
50
server/model/book/book.go
Normal file
50
server/model/book/book.go
Normal file
@@ -0,0 +1,50 @@
|
||||
package book
|
||||
|
||||
import "time"
|
||||
|
||||
const (
|
||||
BookEraTagUnknown = "unknown"
|
||||
BookEraTagAncient = "ancient"
|
||||
BookEraTagHan = "han"
|
||||
BookEraTagTang = "tang"
|
||||
BookEraTagSong = "song"
|
||||
BookEraTagYuan = "yuan"
|
||||
BookEraTagMing = "ming"
|
||||
BookEraTagQing = "qing"
|
||||
BookEraTagModern = "modern"
|
||||
BookEraTagContemporary = "contemporary"
|
||||
BookCompletionStatusCompleted = "completed"
|
||||
BookCompletionStatusSerializing = "serializing"
|
||||
BookPublishStatusDraft = "draft"
|
||||
BookPublishStatusOffShelf = "off_shelf"
|
||||
BookPublishStatusOnShelf = "on_shelf"
|
||||
BookAuthorStatusEnabled = "enabled"
|
||||
BookAuthorStatusDisabled = "disabled"
|
||||
BookCommentStatusNormal = "normal"
|
||||
BookCommentStatusHidden = "hidden"
|
||||
)
|
||||
|
||||
type Book struct {
|
||||
HardDeleteModel
|
||||
Title string `json:"title" form:"title" gorm:"type:varchar(255);not null;comment:书名主标题"`
|
||||
Subtitle string `json:"subtitle" form:"subtitle" gorm:"type:varchar(255);comment:书籍副标题"`
|
||||
BookType string `json:"bookType" form:"bookType" gorm:"type:varchar(64);not null;index;comment:书籍类型字典值,对应 book_type"`
|
||||
EraTag string `json:"eraTag" form:"eraTag" gorm:"type:varchar(32);not null;default:unknown;index;comment:时代标签字典值,对应 book_era_tag"`
|
||||
CoverUrl string `json:"coverUrl" form:"coverUrl" gorm:"type:varchar(500);comment:封面图片 URL"`
|
||||
Publisher string `json:"publisher" form:"publisher" gorm:"type:varchar(128);comment:出版社名称"`
|
||||
PublishedAt *time.Time `json:"publishedAt" form:"publishedAt" gorm:"type:date;comment:出版日期"`
|
||||
Intro string `json:"intro" form:"intro" gorm:"type:text;comment:书籍简介"`
|
||||
HotScore int64 `json:"hotScore" form:"hotScore" gorm:"not null;default:0;comment:热度聚合值"`
|
||||
Rating float64 `json:"rating" form:"rating" gorm:"type:numeric(3,1);not null;default:0.0;comment:书籍评分,范围 0-10"`
|
||||
CommentCount int64 `json:"commentCount" form:"commentCount" gorm:"not null;default:0;comment:点评数聚合值"`
|
||||
WordCount int64 `json:"wordCount" form:"wordCount" gorm:"not null;default:0;comment:书籍总字数"`
|
||||
CompletionStatus string `json:"completionStatus" form:"completionStatus" gorm:"type:varchar(32);not null;default:serializing;index;comment:书籍完结状态字典值,对应 book_completion_status"`
|
||||
PublishStatus string `json:"publishStatus" form:"publishStatus" gorm:"type:varchar(32);not null;default:draft;index;comment:书籍上下架状态字典值,对应 book_publish_status"`
|
||||
SeriesID *uint `json:"seriesId" form:"seriesId" gorm:"index:idx_book_series_id_series_sort;comment:所属系列 ID,可为空"`
|
||||
SeriesSort int `json:"seriesSort" form:"seriesSort" gorm:"not null;default:0;index:idx_book_series_id_series_sort;comment:同系列内展示排序"`
|
||||
RawTxtUrl string `json:"rawTxtUrl" form:"rawTxtUrl" gorm:"type:varchar(500);comment:原始 txt 文件 URL"`
|
||||
}
|
||||
|
||||
func (Book) TableName() string {
|
||||
return "book"
|
||||
}
|
||||
13
server/model/book/book_author.go
Normal file
13
server/model/book/book_author.go
Normal file
@@ -0,0 +1,13 @@
|
||||
package book
|
||||
|
||||
type BookAuthor struct {
|
||||
HardDeleteModel
|
||||
Name string `json:"name" form:"name" gorm:"type:varchar(128);not null;uniqueIndex:uk_book_author_name;comment:作者名称"`
|
||||
AuthorStatus string `json:"authorStatus" form:"authorStatus" gorm:"type:varchar(32);not null;default:enabled;index;comment:作者状态字典值,对应 book_author_status"`
|
||||
Intro string `json:"intro" form:"intro" gorm:"type:text;comment:作者简介"`
|
||||
CoverUrl string `json:"coverUrl" form:"coverUrl" gorm:"type:varchar(500);comment:作者头像或封面 URL"`
|
||||
}
|
||||
|
||||
func (BookAuthor) TableName() string {
|
||||
return "book_author"
|
||||
}
|
||||
12
server/model/book/book_author_relation.go
Normal file
12
server/model/book/book_author_relation.go
Normal file
@@ -0,0 +1,12 @@
|
||||
package book
|
||||
|
||||
type BookAuthorRelation struct {
|
||||
HardDeleteModel
|
||||
BookID uint `json:"bookId" form:"bookId" gorm:"not null;uniqueIndex:uk_book_author_relation_book_id_author_id;index:idx_book_author_relation_book_id_author_sort;comment:书籍 ID"`
|
||||
AuthorID uint `json:"authorId" form:"authorId" gorm:"not null;uniqueIndex:uk_book_author_relation_book_id_author_id;index;comment:作者 ID"`
|
||||
AuthorSort int `json:"authorSort" form:"authorSort" gorm:"not null;default:1;index:idx_book_author_relation_book_id_author_sort;comment:作者展示排序"`
|
||||
}
|
||||
|
||||
func (BookAuthorRelation) TableName() string {
|
||||
return "book_author_relation"
|
||||
}
|
||||
16
server/model/book/book_chapter.go
Normal file
16
server/model/book/book_chapter.go
Normal file
@@ -0,0 +1,16 @@
|
||||
package book
|
||||
|
||||
type BookChapter struct {
|
||||
HardDeleteModel
|
||||
BookID uint `json:"bookId" form:"bookId" gorm:"not null;uniqueIndex:uk_book_chapter_book_id_chapter_no;index:idx_book_chapter_book_id_is_enabled_is_readable;comment:书籍 ID"`
|
||||
Title string `json:"title" form:"title" gorm:"type:varchar(255);not null;comment:章节标题"`
|
||||
ChapterNo int `json:"chapterNo" form:"chapterNo" gorm:"not null;uniqueIndex:uk_book_chapter_book_id_chapter_no;comment:章节序号"`
|
||||
IsReadable bool `json:"isReadable" form:"isReadable" gorm:"not null;default:false;index:idx_book_chapter_book_id_is_enabled_is_readable;comment:是否开放阅读"`
|
||||
ContentFileUrl string `json:"contentFileUrl" form:"contentFileUrl" gorm:"type:varchar(500);not null;comment:章节正文文件 URL"`
|
||||
TotalLines int `json:"totalLines" form:"totalLines" gorm:"not null;default:0;comment:正文总行数"`
|
||||
IsEnabled bool `json:"isEnabled" form:"isEnabled" gorm:"not null;default:true;index:idx_book_chapter_book_id_is_enabled_is_readable;comment:章节是否启用"`
|
||||
}
|
||||
|
||||
func (BookChapter) TableName() string {
|
||||
return "book_chapter"
|
||||
}
|
||||
16
server/model/book/book_comment.go
Normal file
16
server/model/book/book_comment.go
Normal file
@@ -0,0 +1,16 @@
|
||||
package book
|
||||
|
||||
type BookComment struct {
|
||||
HardDeleteModel
|
||||
MemberUserID uint `json:"memberUserId" form:"memberUserId" gorm:"not null;index;comment:会员用户 ID"`
|
||||
BookID uint `json:"bookId" form:"bookId" gorm:"not null;index;index:idx_book_comment_book_id_chapter_id_line_index;comment:书籍 ID"`
|
||||
ChapterID uint `json:"chapterId" form:"chapterId" gorm:"not null;default:0;index:idx_book_comment_book_id_chapter_id_line_index;comment:章节 ID,0 表示整书评论"`
|
||||
LineIndex int `json:"lineIndex" form:"lineIndex" gorm:"not null;default:0;index:idx_book_comment_book_id_chapter_id_line_index;comment:文本行序号,0 表示整书或整章"`
|
||||
Content string `json:"content" form:"content" gorm:"type:text;not null;comment:评论内容"`
|
||||
LikeCount int64 `json:"likeCount" form:"likeCount" gorm:"not null;default:0;comment:点赞聚合数"`
|
||||
CommentStatus string `json:"commentStatus" form:"commentStatus" gorm:"type:varchar(32);not null;default:normal;index;comment:评论状态字典值,对应 book_comment_status"`
|
||||
}
|
||||
|
||||
func (BookComment) TableName() string {
|
||||
return "book_comment"
|
||||
}
|
||||
14
server/model/book/book_comment_like_record.go
Normal file
14
server/model/book/book_comment_like_record.go
Normal file
@@ -0,0 +1,14 @@
|
||||
package book
|
||||
|
||||
import "time"
|
||||
|
||||
type BookCommentLikeRecord struct {
|
||||
HardDeleteModel
|
||||
CommentID uint `json:"commentId" form:"commentId" gorm:"not null;uniqueIndex:uk_book_comment_like_record_comment_id_member_user_id;comment:评论 ID"`
|
||||
MemberUserID uint `json:"memberUserId" form:"memberUserId" gorm:"not null;uniqueIndex:uk_book_comment_like_record_comment_id_member_user_id;index;comment:会员用户 ID"`
|
||||
LikedAt time.Time `json:"likedAt" form:"likedAt" gorm:"not null;default:CURRENT_TIMESTAMP;index;comment:点赞时间"`
|
||||
}
|
||||
|
||||
func (BookCommentLikeRecord) TableName() string {
|
||||
return "book_comment_like_record"
|
||||
}
|
||||
14
server/model/book/book_favorite_record.go
Normal file
14
server/model/book/book_favorite_record.go
Normal file
@@ -0,0 +1,14 @@
|
||||
package book
|
||||
|
||||
import "time"
|
||||
|
||||
type BookFavoriteRecord struct {
|
||||
HardDeleteModel
|
||||
MemberUserID uint `json:"memberUserId" form:"memberUserId" gorm:"not null;uniqueIndex:uk_book_favorite_record_member_user_id_book_id;index:idx_book_favorite_record_member_user_id_favorited_at;comment:会员用户 ID"`
|
||||
BookID uint `json:"bookId" form:"bookId" gorm:"not null;uniqueIndex:uk_book_favorite_record_member_user_id_book_id;index;comment:书籍 ID"`
|
||||
FavoritedAt time.Time `json:"favoritedAt" form:"favoritedAt" gorm:"not null;default:CURRENT_TIMESTAMP;index:idx_book_favorite_record_member_user_id_favorited_at;comment:收藏时间"`
|
||||
}
|
||||
|
||||
func (BookFavoriteRecord) TableName() string {
|
||||
return "book_favorite_record"
|
||||
}
|
||||
29
server/model/book/book_models_test.go
Normal file
29
server/model/book/book_models_test.go
Normal file
@@ -0,0 +1,29 @@
|
||||
package book
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestBookModelTableNames(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
got string
|
||||
want string
|
||||
}{
|
||||
{name: "book", got: Book{}.TableName(), want: "book"},
|
||||
{name: "book_author", got: BookAuthor{}.TableName(), want: "book_author"},
|
||||
{name: "book_author_relation", got: BookAuthorRelation{}.TableName(), want: "book_author_relation"},
|
||||
{name: "book_chapter", got: BookChapter{}.TableName(), want: "book_chapter"},
|
||||
{name: "book_comment", got: BookComment{}.TableName(), want: "book_comment"},
|
||||
{name: "book_comment_like_record", got: BookCommentLikeRecord{}.TableName(), want: "book_comment_like_record"},
|
||||
{name: "book_favorite_record", got: BookFavoriteRecord{}.TableName(), want: "book_favorite_record"},
|
||||
{name: "book_read_record", got: BookReadRecord{}.TableName(), want: "book_read_record"},
|
||||
{name: "book_series", got: BookSeries{}.TableName(), want: "book_series"},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if tt.got != tt.want {
|
||||
t.Fatalf("TableName() = %q, want %q", tt.got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
18
server/model/book/book_read_record.go
Normal file
18
server/model/book/book_read_record.go
Normal file
@@ -0,0 +1,18 @@
|
||||
package book
|
||||
|
||||
import "time"
|
||||
|
||||
type BookReadRecord struct {
|
||||
HardDeleteModel
|
||||
MemberUserID uint `json:"memberUserId" form:"memberUserId" gorm:"not null;uniqueIndex:uk_book_read_record_member_user_id_book_id;index:idx_book_read_record_member_user_id_last_read_at;comment:会员用户 ID"`
|
||||
BookID uint `json:"bookId" form:"bookId" gorm:"not null;uniqueIndex:uk_book_read_record_member_user_id_book_id;index;comment:书籍 ID"`
|
||||
BookTitleSnapshot string `json:"bookTitleSnapshot" form:"bookTitleSnapshot" gorm:"type:varchar(255);not null;comment:书名快照"`
|
||||
ReadProgress float64 `json:"readProgress" form:"readProgress" gorm:"type:numeric(5,2);not null;default:0.00;comment:阅读进度百分比"`
|
||||
ChapterID uint `json:"chapterId" form:"chapterId" gorm:"not null;comment:续读章节 ID"`
|
||||
LineIndex int `json:"lineIndex" form:"lineIndex" gorm:"not null;comment:续读文本行序号"`
|
||||
LastReadAt time.Time `json:"lastReadAt" form:"lastReadAt" gorm:"not null;default:CURRENT_TIMESTAMP;index:idx_book_read_record_member_user_id_last_read_at;comment:最后阅读时间"`
|
||||
}
|
||||
|
||||
func (BookReadRecord) TableName() string {
|
||||
return "book_read_record"
|
||||
}
|
||||
13
server/model/book/book_series.go
Normal file
13
server/model/book/book_series.go
Normal file
@@ -0,0 +1,13 @@
|
||||
package book
|
||||
|
||||
type BookSeries struct {
|
||||
HardDeleteModel
|
||||
Name string `json:"name" form:"name" gorm:"type:varchar(128);not null;index;comment:系列名称"`
|
||||
CoverUrl string `json:"coverUrl" form:"coverUrl" gorm:"type:varchar(500);comment:系列封面图片 URL"`
|
||||
Intro string `json:"intro" form:"intro" gorm:"type:text;comment:系列简介"`
|
||||
IsEnabled bool `json:"isEnabled" form:"isEnabled" gorm:"not null;default:true;index;comment:系列是否启用"`
|
||||
}
|
||||
|
||||
func (BookSeries) TableName() string {
|
||||
return "book_series"
|
||||
}
|
||||
64
server/model/book/request/book.go
Normal file
64
server/model/book/request/book.go
Normal file
@@ -0,0 +1,64 @@
|
||||
package request
|
||||
|
||||
import commonReq "github.com/flipped-aurora/gin-vue-admin/server/model/common/request"
|
||||
|
||||
type BookSearch struct {
|
||||
commonReq.PageInfo
|
||||
Title string `json:"title" form:"title"`
|
||||
BookType string `json:"bookType" form:"bookType"`
|
||||
EraTag string `json:"eraTag" form:"eraTag"`
|
||||
CompletionStatus string `json:"completionStatus" form:"completionStatus"`
|
||||
PublishStatus string `json:"publishStatus" form:"publishStatus"`
|
||||
SeriesID *uint `json:"seriesId" form:"seriesId"`
|
||||
}
|
||||
|
||||
type BookAuthorSearch struct {
|
||||
commonReq.PageInfo
|
||||
Name string `json:"name" form:"name"`
|
||||
AuthorStatus string `json:"authorStatus" form:"authorStatus"`
|
||||
}
|
||||
|
||||
type BookAuthorRelationSearch struct {
|
||||
commonReq.PageInfo
|
||||
BookID *uint `json:"bookId" form:"bookId"`
|
||||
AuthorID *uint `json:"authorId" form:"authorId"`
|
||||
}
|
||||
|
||||
type BookChapterSearch struct {
|
||||
commonReq.PageInfo
|
||||
BookID *uint `json:"bookId" form:"bookId"`
|
||||
IsReadable *bool `json:"isReadable" form:"isReadable"`
|
||||
IsEnabled *bool `json:"isEnabled" form:"isEnabled"`
|
||||
}
|
||||
|
||||
type BookCommentSearch struct {
|
||||
commonReq.PageInfo
|
||||
MemberUserID *uint `json:"memberUserId" form:"memberUserId"`
|
||||
BookID *uint `json:"bookId" form:"bookId"`
|
||||
ChapterID *uint `json:"chapterId" form:"chapterId"`
|
||||
CommentStatus string `json:"commentStatus" form:"commentStatus"`
|
||||
}
|
||||
|
||||
type BookCommentLikeRecordSearch struct {
|
||||
commonReq.PageInfo
|
||||
CommentID *uint `json:"commentId" form:"commentId"`
|
||||
MemberUserID *uint `json:"memberUserId" form:"memberUserId"`
|
||||
}
|
||||
|
||||
type BookFavoriteRecordSearch struct {
|
||||
commonReq.PageInfo
|
||||
MemberUserID *uint `json:"memberUserId" form:"memberUserId"`
|
||||
BookID *uint `json:"bookId" form:"bookId"`
|
||||
}
|
||||
|
||||
type BookReadRecordSearch struct {
|
||||
commonReq.PageInfo
|
||||
MemberUserID *uint `json:"memberUserId" form:"memberUserId"`
|
||||
BookID *uint `json:"bookId" form:"bookId"`
|
||||
}
|
||||
|
||||
type BookSeriesSearch struct {
|
||||
commonReq.PageInfo
|
||||
Name string `json:"name" form:"name"`
|
||||
IsEnabled *bool `json:"isEnabled" form:"isEnabled"`
|
||||
}
|
||||
31
server/model/book/response/book.go
Normal file
31
server/model/book/response/book.go
Normal file
@@ -0,0 +1,31 @@
|
||||
package response
|
||||
|
||||
import "github.com/flipped-aurora/gin-vue-admin/server/model/book"
|
||||
|
||||
type BookResponse struct {
|
||||
Book book.Book `json:"book"`
|
||||
}
|
||||
type BookAuthorResponse struct {
|
||||
BookAuthor book.BookAuthor `json:"bookAuthor"`
|
||||
}
|
||||
type BookAuthorRelationResponse struct {
|
||||
BookAuthorRelation book.BookAuthorRelation `json:"bookAuthorRelation"`
|
||||
}
|
||||
type BookChapterResponse struct {
|
||||
BookChapter book.BookChapter `json:"bookChapter"`
|
||||
}
|
||||
type BookCommentResponse struct {
|
||||
BookComment book.BookComment `json:"bookComment"`
|
||||
}
|
||||
type BookCommentLikeRecordResponse struct {
|
||||
BookCommentLikeRecord book.BookCommentLikeRecord `json:"bookCommentLikeRecord"`
|
||||
}
|
||||
type BookFavoriteRecordResponse struct {
|
||||
BookFavoriteRecord book.BookFavoriteRecord `json:"bookFavoriteRecord"`
|
||||
}
|
||||
type BookReadRecordResponse struct {
|
||||
BookReadRecord book.BookReadRecord `json:"bookReadRecord"`
|
||||
}
|
||||
type BookSeriesResponse struct {
|
||||
BookSeries book.BookSeries `json:"bookSeries"`
|
||||
}
|
||||
Reference in New Issue
Block a user