feat(publish): require cover image for WeChat Official Account

WeChat 公众号在管理员/运营者授权发布场景下需要 2.35:1 封面,
新增共享 publishPlatformRequiresCover 校验并同步前端封面要求与文案,
避免在调度与即时发布两条路径上重复维护平台名单。

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-01 10:21:46 +08:00
parent 052299e54f
commit 3436d9536d
7 changed files with 54 additions and 6 deletions
+1 -1
View File
@@ -1101,7 +1101,7 @@ const enUS = {
previewHintLocked: "A selected platform requires a fixed cover ratio, so the cover will be exported using the current platform requirement.",
previewHintFree: "There is no forced cover ratio right now. You can upload the original image directly or adjust framing before confirming.",
requirementsTitle: "Platform requirements",
requirementsHint: "Requirements switch automatically based on the selected publish platforms. Baijiahao and Dongchedi require a cover image.",
requirementsHint: "Requirements switch automatically based on the selected publish platforms. WeChat Official Account, Baijiahao, and Dongchedi require a cover image.",
recommendedRatio: "Recommended ratio",
recommendedSize: "Recommended size",
required: "Required",
+1 -1
View File
@@ -1110,7 +1110,7 @@ const zhCN = {
previewHintLocked: "已选择需要固定封面比例的平台,确认时会按当前平台要求输出封面。",
previewHintFree: "当前不限制封面比例,可直接上传原图;如需调整也可拖拽缩放后再确认。",
requirementsTitle: "平台封面要求",
requirementsHint: "会根据当前选中的发布平台自动切换要求,百家号和懂车帝为强制上传。",
requirementsHint: "会根据当前选中的发布平台自动切换要求,微信公众号、百家号和懂车帝为强制上传。",
recommendedRatio: "推荐比例",
recommendedSize: "推荐尺寸",
required: "必传",
@@ -24,6 +24,15 @@ const defaultRequirement = {
};
const requirementCatalog: Record<string, Partial<PlatformCoverRequirement>> = {
weixin_gzh: {
required: true,
supportMode: "native",
aspectRatio: 2.35,
aspectLabel: "2.35:1",
outputWidth: 1200,
outputHeight: 511,
priority: 110,
},
baijiahao: {
required: true,
supportMode: "native",
+11 -1
View File
@@ -4,6 +4,7 @@ import (
"context"
"crypto/rand"
"encoding/hex"
"strings"
"time"
"github.com/jackc/pgx/v5/pgxpool"
@@ -136,13 +137,22 @@ func (s *MediaService) listArticlePublishRecords(ctx context.Context, tenantID,
func publishBatchRequiresCover(accounts []platformAccountSeed) bool {
for _, account := range accounts {
if account.PlatformID == "baijiahao" || account.PlatformID == "dongchedi" {
if publishPlatformRequiresCover(account.PlatformID) {
return true
}
}
return false
}
func publishPlatformRequiresCover(platformID string) bool {
switch strings.TrimSpace(platformID) {
case "weixin_gzh", "baijiahao", "dongchedi":
return true
default:
return false
}
}
func pointerStringValue(value *string) string {
if value == nil {
return ""
@@ -162,7 +162,7 @@ func (s *PublishJobService) Create(ctx context.Context, actor auth.Actor, req Cr
accountSeeds = append(accountSeeds, *target.accountSeed)
}
if publishBatchRequiresCover(accountSeeds) && strings.TrimSpace(pointerStringValue(articleMeta.CoverAssetURL)) == "" {
return nil, response.ErrBadRequest(40044, "publish_cover_required", "baijiahao publishing requires a cover image")
return nil, response.ErrBadRequest(40044, "publish_cover_required", "selected publishing platform requires a cover image")
}
publishBatchID, publishRecordIDs, err := createPublishBatchRecords(
@@ -0,0 +1,30 @@
package app
import "testing"
func TestPublishPlatformRequiresCover(t *testing.T) {
t.Parallel()
for _, platformID := range []string{"weixin_gzh", "baijiahao", "dongchedi"} {
if !publishPlatformRequiresCover(platformID) {
t.Fatalf("publishPlatformRequiresCover(%q) = false, want true", platformID)
}
}
if publishPlatformRequiresCover("zhihu") {
t.Fatal("publishPlatformRequiresCover(\"zhihu\") = true, want false")
}
}
func TestPublishCoverRequirementCallersIncludeWeixinGzh(t *testing.T) {
t.Parallel()
accounts := []platformAccountSeed{{PlatformID: "weixin_gzh"}}
if !publishBatchRequiresCover(accounts) {
t.Fatal("publishBatchRequiresCover() = false for weixin_gzh, want true")
}
if !schedulePublishPlatformsRequireCover([]string{"weixin_gzh"}) {
t.Fatal("schedulePublishPlatformsRequireCover() = false for weixin_gzh, want true")
}
}
@@ -564,8 +564,7 @@ func (s *ScheduleTaskService) loadPublishAccountPlatformIDs(ctx context.Context,
func schedulePublishPlatformsRequireCover(platformIDs []string) bool {
for _, platformID := range platformIDs {
switch strings.TrimSpace(platformID) {
case "baijiahao", "dongchedi":
if publishPlatformRequiresCover(platformID) {
return true
}
}