375 lines
11 KiB
Go
375 lines
11 KiB
Go
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) {
|
||
// 使用用户服务获取公众号实例
|
||
mpUserService := &MpUserService{}
|
||
return mpUserService.GetOfficialAccount()
|
||
}
|
||
|
||
// 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
|
||
}
|