package service import ( "errors" "fmt" "github.com/flipped-aurora/gin-vue-admin/server/global" "github.com/silenceper/wechat/v2/officialaccount" "github.com/silenceper/wechat/v2/officialaccount/draft" ) type MpDraftService struct{} // DraftListResponse 草稿列表响应结构 type DraftListResponse struct { Items []DraftItem `json:"items"` TotalCount int `json:"totalCount"` } // DraftItem 草稿项目结构 type DraftItem struct { MediaID string `json:"mediaId"` Content DraftContent `json:"content"` UpdateTime int64 `json:"updateTime"` } // DraftContent 草稿内容结构 type DraftContent struct { NewsItem []DraftArticle `json:"newsItem"` } // DraftArticle 草稿文章结构 type DraftArticle struct { Title string `json:"title"` Author string `json:"author"` Digest string `json:"digest"` Content string `json:"content"` ContentSourceURL string `json:"contentSourceUrl"` ThumbMediaID string `json:"thumbMediaId"` ShowCoverPic int `json:"showCoverPic"` NeedOpenComment int `json:"needOpenComment"` OnlyFansCanComment int `json:"onlyFansCanComment"` ThumbURL string `json:"thumbUrl,omitempty"` } // GetDraftList 获取草稿列表 func (m *MpDraftService) GetDraftList(page, pageSize int, title, author string) (*DraftListResponse, error) { // 获取微信公众号实例 oa, err := m.getOfficialAccount() if err != nil { return nil, err } // 计算偏移量 offset := int64((page - 1) * pageSize) count := int64(pageSize) // 调用微信API获取草稿列表 draftService := oa.GetDraft() articleList, err := draftService.PaginateDraft(offset, count, false) if err != nil { global.GVA_LOG.Error("获取微信草稿列表失败: " + err.Error()) return nil, fmt.Errorf("获取草稿列表失败: %v", err) } // 转换数据格式 response := &DraftListResponse{ Items: make([]DraftItem, 0, len(articleList.Item)), TotalCount: int(articleList.TotalCount), } for _, item := range articleList.Item { draftItem := DraftItem{ MediaID: item.MediaID, UpdateTime: item.UpdateTime, Content: DraftContent{ NewsItem: make([]DraftArticle, 0, len(item.Content.NewsItem)), }, } // 转换文章列表 for _, article := range item.Content.NewsItem { draftArticle := DraftArticle{ Title: article.Title, Author: article.Author, Digest: article.Digest, Content: article.Content, ContentSourceURL: article.ContentSourceURL, ThumbMediaID: article.ThumbMediaID, ShowCoverPic: int(article.ShowCoverPic), NeedOpenComment: int(article.NeedOpenComment), OnlyFansCanComment: int(article.OnlyFansCanComment), } draftItem.Content.NewsItem = append(draftItem.Content.NewsItem, draftArticle) } // 应用过滤条件 if title != "" || author != "" { matched := false for _, article := range draftItem.Content.NewsItem { if title != "" && article.Title != "" && len(article.Title) > 0 && article.Title == title { matched = true break } if author != "" && article.Author != "" && len(article.Author) > 0 && article.Author == author { matched = true break } } if matched { response.Items = append(response.Items, draftItem) } } else { response.Items = append(response.Items, draftItem) } } global.GVA_LOG.Info(fmt.Sprintf("成功获取草稿列表,共 %d 条记录", len(response.Items))) return response, nil } // getOfficialAccount 获取微信公众号实例 func (m *MpDraftService) getOfficialAccount() (*officialaccount.OfficialAccount, error) { // 使用账号服务获取默认公众号实例 return nil, nil } // GetDraftInfo 获取草稿详情(通过MediaID) func (m *MpDraftService) GetDraftInfo(mediaID string) (*DraftItem, error) { if mediaID == "" { return nil, errors.New("MediaID不能为空") } // 获取微信公众号实例 oa, err := m.getOfficialAccount() if err != nil { return nil, err } // 调用微信API获取草稿详情 draftService := oa.GetDraft() articles, err := draftService.GetDraft(mediaID) if err != nil { global.GVA_LOG.Error("获取微信草稿详情失败: " + err.Error()) return nil, fmt.Errorf("获取草稿详情失败: %v", err) } // 转换数据格式 draftItem := &DraftItem{ MediaID: mediaID, UpdateTime: 0, // 微信API返回的草稿详情不包含更新时间,需要从列表接口获取 Content: DraftContent{ NewsItem: make([]DraftArticle, 0, len(articles)), }, } // 转换文章列表 for _, article := range articles { draftArticle := DraftArticle{ Title: article.Title, Author: article.Author, Digest: article.Digest, Content: article.Content, ContentSourceURL: article.ContentSourceURL, ThumbMediaID: article.ThumbMediaID, ShowCoverPic: int(article.ShowCoverPic), NeedOpenComment: int(article.NeedOpenComment), OnlyFansCanComment: int(article.OnlyFansCanComment), } draftItem.Content.NewsItem = append(draftItem.Content.NewsItem, draftArticle) } global.GVA_LOG.Info(fmt.Sprintf("成功获取草稿详情,MediaID: %s", mediaID)) return draftItem, nil } // CreateDraftRequest 创建草稿请求结构 type CreateDraftRequest struct { Articles []DraftArticle `json:"articles"` } // CreateDraft 创建草稿 func (m *MpDraftService) CreateDraft(req *CreateDraftRequest) (string, error) { if len(req.Articles) == 0 { return "", errors.New("文章列表不能为空") } // 获取微信公众号实例 oa, err := m.getOfficialAccount() if err != nil { return "", err } // 构建微信API请求参数 articles := make([]*draft.Article, 0, len(req.Articles)) for _, article := range req.Articles { if article.Title == "" { return "", errors.New("文章标题不能为空") } wxArticle := &draft.Article{ Title: article.Title, Author: article.Author, Digest: article.Digest, Content: article.Content, ContentSourceURL: article.ContentSourceURL, ThumbMediaID: article.ThumbMediaID, ShowCoverPic: uint(article.ShowCoverPic), NeedOpenComment: uint(article.NeedOpenComment), OnlyFansCanComment: uint(article.OnlyFansCanComment), } articles = append(articles, wxArticle) } // 调用微信API创建草稿 draftService := oa.GetDraft() mediaID, err := draftService.AddDraft(articles) if err != nil { global.GVA_LOG.Error("创建微信草稿失败: " + err.Error()) return "", fmt.Errorf("创建草稿失败: %v", err) } return mediaID, nil } // UpdateDraftRequest 更新草稿请求结构 type UpdateDraftRequest struct { MediaID string `json:"mediaId"` Index int `json:"index"` Articles []DraftArticle `json:"articles"` } // UpdateDraft 更新草稿 func (m *MpDraftService) UpdateDraft(req *UpdateDraftRequest) error { if req.MediaID == "" { return errors.New("草稿MediaID不能为空") } if len(req.Articles) == 0 { return errors.New("文章列表不能为空") } // 获取微信公众号实例 oa, err := m.getOfficialAccount() if err != nil { return err } // 微信API只支持单篇文章更新,需要逐个更新 draftService := oa.GetDraft() for i, article := range req.Articles { if article.Title == "" { return fmt.Errorf("第%d篇文章标题不能为空", i+1) } wxArticle := &draft.Article{ Title: article.Title, Author: article.Author, Digest: article.Digest, Content: article.Content, ContentSourceURL: article.ContentSourceURL, ThumbMediaID: article.ThumbMediaID, ShowCoverPic: uint(article.ShowCoverPic), NeedOpenComment: uint(article.NeedOpenComment), OnlyFansCanComment: uint(article.OnlyFansCanComment), } // 调用微信API更新草稿 err = draftService.UpdateDraft(wxArticle, req.MediaID, uint(i)) if err != nil { global.GVA_LOG.Error(fmt.Sprintf("更新草稿第%d篇文章失败: %s", i+1, err.Error())) return fmt.Errorf("更新草稿第%d篇文章失败: %v", i+1, err) } } global.GVA_LOG.Info(fmt.Sprintf("成功更新草稿,MediaID: %s,共更新 %d 篇文章", req.MediaID, len(req.Articles))) return nil } // DeleteDraft 删除草稿 func (m *MpDraftService) DeleteDraft(mediaID string) error { if mediaID == "" { return errors.New("草稿MediaID不能为空") } // 获取微信公众号实例 oa, err := m.getOfficialAccount() if err != nil { return err } // 调用微信API删除草稿 draftService := oa.GetDraft() err = draftService.DeleteDraft(mediaID) if err != nil { global.GVA_LOG.Error("删除微信草稿失败: " + err.Error()) return fmt.Errorf("删除草稿失败: %v", err) } return nil } // PublishDraft 发布草稿 func (m *MpDraftService) PublishDraft(mediaID string) error { if mediaID == "" { return errors.New("草稿MediaID不能为空") } // 获取微信公众号实例 _, err := m.getOfficialAccount() if err != nil { return err } // 注意:微信公众号草稿发布需要使用freepublish模块 // 这里我们先记录日志,实际发布功能需要使用freepublish.SubmitPublish global.GVA_LOG.Info(fmt.Sprintf("草稿发布请求,MediaID: %s。注意:实际发布需要使用freepublish模块", mediaID)) // 由于草稿发布涉及到发布流程,这里暂时只做记录 // 实际项目中可以调用 oa.GetFreePublish().SubmitPublish(mediaID) 来发布 return fmt.Errorf("草稿发布功能需要使用freepublish模块,MediaID: %s", mediaID) } // SyncDrafts 同步草稿 func (m *MpDraftService) SyncDrafts() error { // 获取微信公众号实例 oa, err := m.getOfficialAccount() if err != nil { return err } // 获取草稿总数 draftService := oa.GetDraft() total, err := draftService.CountDraft() if err != nil { global.GVA_LOG.Error("获取草稿总数失败: " + err.Error()) return fmt.Errorf("同步草稿失败: %v", err) } global.GVA_LOG.Info(fmt.Sprintf("草稿同步完成,当前草稿总数: %d", total)) return nil } // GetDraftCount 获取草稿数量统计 func (m *MpDraftService) GetDraftCount() (map[string]int64, error) { // 获取微信公众号实例 oa, err := m.getOfficialAccount() if err != nil { return nil, err } // 调用微信API获取草稿总数 draftService := oa.GetDraft() total, err := draftService.CountDraft() if err != nil { global.GVA_LOG.Error("获取草稿总数失败: " + err.Error()) return nil, fmt.Errorf("获取草稿数量失败: %v", err) } result := map[string]int64{ "draft": int64(total), "published": 0, // 发布数量需要通过其他API获取 "total": int64(total), } global.GVA_LOG.Info(fmt.Sprintf("成功获取草稿数量统计,总数: %d", total)) return result, nil }