This commit is contained in:
@@ -0,0 +1,373 @@
|
||||
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
|
||||
}
|
||||
Reference in New Issue
Block a user