package service import ( "Blog/internal/client" "Blog/internal/consts" "Blog/internal/model" "Blog/internal/repository" "context" "errors" "strconv" "time" "github.com/google/uuid" "github.com/redis/go-redis/v9" "github.com/sirupsen/logrus" "gorm.io/gorm" ) var ArticleService *articleService = newArticleService() type articleService struct { } func initArticleData() { var slices []model.BlogArticle = repository.ArticleRepository.FindList(nil, "state = ?", consts.ARTICLE_STATE_PUBLISH) logrus.Info("文章初始化数据加载量:", len(slices)) ctx := context.Background() for _, article := range slices { // logrus.Info(article) publishTime := article.PublishTime err := client.RedisClient.ZAdd(ctx, consts.REDIS_BLOG_ARTICLE_LATEST, redis.Z{Score: float64(publishTime), Member: &article}).Err() if err != nil { logrus.Info(err) } } } func newArticleService() *articleService { go initArticleData() return &articleService{} } // 根据ID获取文章 func (*articleService) GetArticle(id string) *model.BlogArticle { var ret *model.BlogArticle = &model.BlogArticle{} key := consts.REDIS_BLOG_ARTICLE + id err := client.RedisClient.Get(context.Background(), key).Scan(ret) if err != nil { logrus.Infoln(id, "文章的缓存不存在,读取数据库") ret = repository.ArticleRepository.GetById(id) client.RedisClient.Set(context.Background(), key, ret, time.Duration(0)) } return ret } func (*articleService) GetLatest() []model.BlogArticle { ctx := context.Background() var slices []model.BlogArticle err := client.RedisClient.ZRevRange(ctx, consts.REDIS_BLOG_ARTICLE_LATEST, 0, 10).ScanSlice(&slices) // if err != nil || len(slices) == 0 { // result := repository.ArticleRepository.Where("state = ?", consts.ARTICLE_STATE_PUBLISH).Order("publish_time DESC").Find(&slices) // logrus.Info("文章初始化数据加载量:", result.RowsAffected) // ctx := context.Background() // client.RedisClient.Del(ctx, consts.REDIS_BLOG_ARTICLE_LATEST) // for _, article := range slices { // // logrus.Info(article) // publishTime := article.PublishTime // err := client.RedisClient.ZAdd(ctx, consts.REDIS_BLOG_ARTICLE_LATEST, redis.Z{Score: float64(publishTime), Member: &article}).Err() // if err != nil { // logrus.Info(err) // } // } // } if err != nil { logrus.Error("获取文章失败:", err) return nil } return slices } // 文章分页 func (*articleService) PageArticle(page int, itemsPerPage int) model.Page[any] { var slice []model.BlogArticle var totalElements int64 ctx := context.Background() repository.ArticleRepository.Table(consts.TABLE_BLOG_ARTICLE).Count(&totalElements) repository.ArticleRepository.Table(consts.TABLE_BLOG_ARTICLE). Where("del != ?", 1). Offset((page - 1) * itemsPerPage). Limit(itemsPerPage). Order("create_time DESC"). Find(&slice) ret := []any{} for _, v := range slice { id := v.Id view, _ := client.RedisClient.HGet(ctx, consts.REDIS_BLOG_VIEW_RECORD, id).Int64() // content[i].View = view var vo = struct { model.BlogArticle View int64 `json:"view"` }{v, view} ret = append(ret, vo) } pre := int(totalElements) % itemsPerPage if pre > 0 { pre = 1 } var totalPages int = int(totalElements)/itemsPerPage + pre return model.Page[any]{TotalElements: totalElements, TotalPages: totalPages, Number: page, Content: ret} } // 创建文章 func (*articleService) CreateArticle(articel *model.BlogArticle) (string, error) { time := time.Now().UnixMilli() articleId := uuid.NewString() articel.Id = articleId articel.CreateTime = time articel.UpdateTime = time articel.Del = 0 articel.State = consts.ARTICLE_STATE_DRAFT err := repository.ArticleRepository.WGorm(func(tx *gorm.DB) error { contentId := uuid.NewString() content := articel.Content commonContent := model.BlogTextContent{Id: contentId, RelId: articleId, Content: content, State: consts.CONTENT_STATE_DOWN} err := tx.Table(consts.TABLE_BLOG_TEXT_CONTENT).Create(commonContent).Error if err != nil { return err } articel.Content = "" err = tx.Table(consts.TABLE_BLOG_ARTICLE).Create(*articel).Error return err }) return articleId, err } // 修改文章 func (*articleService) UpdateArticle(articel *model.BlogArticle) (string, error) { time := time.Now().UnixMilli() articleId := articel.Id articel.UpdateTime = time err := repository.ArticleRepository.WGorm(func(tx *gorm.DB) error { //更新Article tx.Table(consts.TABLE_BLOG_ARTICLE).Updates(articel) //更新Content err := tx.Table(consts.TABLE_BLOG_TEXT_CONTENT).Where("rel_id", articleId).UpdateColumn("content", articel.Content).Error return err }) return articleId, err } // 发布文章 func (*articleService) PublishArticle(id string) error { now := time.Now().UnixMilli() // var article model.BlogArticle // err := repository.ArticleRepository.Table(consts.TABLE_BLOG_ARTICLE).Where("id = ?", id).First(&article).Error article := repository.ArticleRepository.GetById(id) if article == nil { return errors.New("不存在该文章") } if article.State != consts.ARTICLE_STATE_DRAFT { return errors.New("发布失败,文章状态不是起草状态,无法发布") } if article.PublishTime == 0 { article.PublishTime = now } article.State = consts.ARTICLE_STATE_PUBLISH err := repository.ArticleRepository.WGorm(func(tx *gorm.DB) error { var txErr error = tx.Table(consts.TABLE_BLOG_ARTICLE).Updates(&article).Error if txErr != nil { return errors.New("文章更新错误") } // txErr = ContentService.UpdataState(id, consts.CONTENT_STATE_PUBLISH) txErr = tx.Table(consts.TABLE_BLOG_TEXT_CONTENT).Where("rel_id = ?", id).UpdateColumn("state", consts.CONTENT_STATE_PUBLISH).Error if txErr != nil { return errors.New("文本状态更新错误") } content := TextContentService.GetContent(id) if txErr != nil { return errors.New("文本查询错误") } ctx := context.Background() txErr = client.RedisClient.ZAdd(ctx, consts.REDIS_BLOG_ARTICLE_LATEST, redis.Z{Score: float64(article.PublishTime), Member: &article}).Err() if txErr != nil { return errors.New("缓存错误") } txErr = client.RedisClient.Set(ctx, consts.REDIS_BLOG_CONTENT+id, content.Content, time.Duration(0)).Err() return txErr }) return err } // 撤回发布文章 func (*articleService) UnPublishArticle(id string) error { // var article model.BlogArticle // err := repository.ArticleRepository.Table(consts.TABLE_BLOG_ARTICLE).Where("id = ?", id).First(&article).Error article := repository.ArticleRepository.GetById(id) if article == nil { return errors.New("不存在该文章") } if article.State != consts.CONTENT_STATE_PUBLISH { return errors.New("撤下失败,文章状态不是已发布状态,无法撤下") } err := repository.ArticleRepository.WGorm(func(tx *gorm.DB) error { var txErr error ctx := context.Background() txErr = client.RedisClient.ZRemRangeByScore(ctx, consts.REDIS_BLOG_ARTICLE_LATEST, strconv.FormatFloat(float64(article.PublishTime), 'E', -1, 64), strconv.FormatFloat(float64(article.PublishTime), 'E', -1, 64), ).Err() // txErr = client.RedisClient.ZAdd(ctx, "blog:article:latest", redis.Z{Score: float64(article.PublishTime), Member: &article}).Err() if txErr != nil { return errors.New("缓存错误") } txErr = client.RedisClient.Del(ctx, consts.REDIS_BLOG_CONTENT+id).Err() if txErr != nil { return errors.New("缓存错误") } article.State = consts.ARTICLE_STATE_DRAFT // article.PublishTime = -1 txErr = tx.Table(consts.TABLE_BLOG_ARTICLE).Updates(&article).Error if txErr != nil { return errors.New("文章状态更新错误") } // txErr = ContentService.UpdataState(id, consts.CONTENT_STATE_DOWN) txErr = tx.Table(consts.TABLE_BLOG_TEXT_CONTENT).Where("rel_id = ?", id).UpdateColumn("state", consts.CONTENT_STATE_DOWN).Error return txErr }) return err } // 删除文章 func (*articleService) DelArticle(id string) error { // articel := ArticleService.GetAdminArticle(id) // err := repository.ArticleRepository.Table(consts.TABLE_BLOG_ARTICLE).Where("id = ?", id).First(&article).Error err := repository.ArticleRepository.WGorm(func(tx *gorm.DB) error { txErr := tx.Table(consts.TABLE_BLOG_ARTICLE).Where("id = ?", id).UpdateColumn("del", 1).Error return txErr }) return err }