feat(article): expose auto_publish_platforms derived from publish accounts

Replace the freeform `platforms` field on articles/tasks (parsed out of
wizard_state/input_params JSON) with `auto_publish_platforms`, resolved
by joining schedule publish accounts to platform_accounts. The migration
strips the legacy keys from existing rows so the new field is the single
source of truth.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-01 11:02:21 +08:00
parent 0f4310c345
commit 490c6c759d
15 changed files with 172 additions and 137 deletions
@@ -21,9 +21,6 @@ import {
publishStateLabel,
type PublishAccountCard,
} from "@/lib/publish-account-cards";
import {
normalizePublishPlatformIds,
} from "@/lib/publish-platforms";
const props = defineProps<{
open: boolean;
@@ -93,10 +90,8 @@ watch(
const platformMap = computed(() => buildPublishPlatformMap(platformsQuery.data.value ?? []));
const articlePlatformIds = computed(() => normalizePublishPlatformIds(detailQuery.data.value?.platforms ?? []));
const accountCards = computed<PublishAccountCard[]>(() =>
buildPublishAccountCards(accountsQuery.data.value ?? [], platformMap.value, articlePlatformIds.value),
buildPublishAccountCards(accountsQuery.data.value ?? [], platformMap.value),
);
watch(
@@ -137,10 +132,7 @@ watchEffect(() => {
return;
}
const preferredPlatforms = new Set(articlePlatformIds.value);
selectedAccountIds.value = accountCards.value
.filter((card) => card.selectable && preferredPlatforms.has(card.platformId))
.map((card) => card.id);
selectedAccountIds.value = [];
selectionHydrated.value = true;
});
@@ -237,7 +229,6 @@ async function persistCoverIfNeeded(detail: ArticleDetail): Promise<ArticleDetai
return articlesApi.update(detail.id, {
title: detail.title?.trim() || t("article.untitled"),
markdown_content: detail.markdown_content ?? "",
platforms: normalizePublishPlatformIds(detail.platforms ?? []),
cover_asset_url: nextUrl || null,
cover_image_asset_id: coverImageAssetId.value,
});