feat: enhance platform management and synchronization in ArticleEditor and PublishArticle components

This commit is contained in:
2026-04-06 15:41:49 +08:00
parent fe124b0ba4
commit 08ace0a9e0
7 changed files with 209 additions and 88 deletions
@@ -8,10 +8,11 @@ import { useI18n } from "vue-i18n";
import PromptRuleModal from "@/components/PromptRuleModal.vue";
import PublishPlatformSelector from "@/components/PublishPlatformSelector.vue";
import { generateApi, promptRulesApi, schedulesApi } from "@/lib/api";
import { generateApi, mediaApi, promptRulesApi, schedulesApi } from "@/lib/api";
import { formatError } from "@/lib/errors";
import {
getAllPublishPlatforms,
buildPublishPlatformOptions,
normalizePublishPlatformIds,
parseTargetPlatforms,
serializeTargetPlatforms,
} from "@/lib/publish-platforms";
@@ -44,7 +45,26 @@ const form = reactive({
});
const isSchedule = computed(() => props.mode === "schedule");
const allPlatforms = computed(() => getAllPublishPlatforms());
const platformsQuery = useQuery({
queryKey: ["media", "platforms", "task-drawer"],
enabled: computed(() => props.open),
queryFn: () => mediaApi.platforms(),
});
const accountsQuery = useQuery({
queryKey: ["media", "platform-accounts", "task-drawer"],
enabled: computed(() => props.open),
queryFn: () => mediaApi.accounts(),
});
const allPlatforms = computed(() =>
buildPublishPlatformOptions(platformsQuery.data.value ?? [], accountsQuery.data.value),
);
const platformsLoading = computed(
() => platformsQuery.isPending.value || accountsQuery.isPending.value,
);
const rulesQuery = useQuery({
queryKey: ["promptRules", "simple"],
@@ -89,12 +109,7 @@ onBeforeUnmount(() => {
const createScheduleMutation = useMutation({
mutationFn: () =>
schedulesApi.create({
name: form.name.trim(),
prompt_rule_id: form.promptRuleId!,
cron_expr: buildDailyCron(form.scheduleTime),
target_platform: serializeTargetPlatforms(form.platformIds),
}),
schedulesApi.create(buildSchedulePayload()),
onSuccess: async () => {
message.success(t("custom.messages.scheduleCreated"));
emit("update:open", false);
@@ -105,12 +120,7 @@ const createScheduleMutation = useMutation({
const updateScheduleMutation = useMutation({
mutationFn: () =>
schedulesApi.update(props.task!.id, {
name: form.name.trim(),
prompt_rule_id: form.promptRuleId!,
cron_expr: buildDailyCron(form.scheduleTime),
target_platform: serializeTargetPlatforms(form.platformIds),
}),
schedulesApi.update(props.task!.id, buildSchedulePayload()),
onSuccess: async () => {
message.success(t("custom.messages.scheduleUpdated"));
emit("update:open", false);
@@ -121,18 +131,7 @@ const updateScheduleMutation = useMutation({
const instantGenerateMutation = useMutation({
mutationFn: () =>
generateApi.fromRule({
prompt_rule_id: form.promptRuleId!,
target_platform: serializeTargetPlatforms(form.platformIds),
extra_params: {
task_name: form.name.trim(),
generation_mode: "instant",
enable_web_search: form.enableWebSearch,
generate_count: form.generateCount,
target_platforms: form.platformIds,
cover_file_name: coverFileName.value || null,
},
}),
generateApi.fromRule(buildInstantPayload()),
onSuccess: async () => {
message.success(t("custom.messages.generateSubmitted"));
emit("update:open", false);
@@ -162,6 +161,36 @@ function hydrateForm(): void {
resetCoverState();
}
function getSelectedPlatformIds(): string[] {
return normalizePublishPlatformIds(form.platformIds);
}
function buildSchedulePayload() {
return {
name: form.name.trim(),
prompt_rule_id: form.promptRuleId!,
cron_expr: buildDailyCron(form.scheduleTime),
target_platform: serializeTargetPlatforms(getSelectedPlatformIds()),
};
}
function buildInstantPayload() {
const platformIds = getSelectedPlatformIds();
return {
prompt_rule_id: form.promptRuleId!,
target_platform: serializeTargetPlatforms(platformIds),
extra_params: {
task_name: form.name.trim(),
generation_mode: "instant",
enable_web_search: form.enableWebSearch,
generate_count: form.generateCount,
target_platforms: platformIds,
cover_file_name: coverFileName.value || null,
},
};
}
function resetCoverState(): void {
if (coverPreviewUrl.value) {
URL.revokeObjectURL(coverPreviewUrl.value);
@@ -323,7 +352,17 @@ function padTime(value: string): string {
<div class="generate-task-drawer__field">
<label class="generate-task-drawer__label">{{ t("custom.task.platforms") }}</label>
<p class="generate-task-drawer__hint">{{ t("custom.task.platformsHint") }}</p>
<PublishPlatformSelector v-model="form.platformIds" :platforms="allPlatforms" />
<a-skeleton
v-if="platformsLoading"
active
:title="false"
:paragraph="{ rows: 4 }"
/>
<PublishPlatformSelector
v-else
v-model="form.platformIds"
:platforms="allPlatforms"
/>
</div>
<div class="generate-task-drawer__field">