feat(ui/publish-records): surface 已存草稿 status and client-only manage hint
Render publish_type=draft tasks with the warn tone and 已存草稿 label, swap the management link copy to 打开草稿箱 for weixin_gzh, and expand the task summary to mention the publish_authorization_required reason. In the admin drawer, stop falling back to external_manage_url for missing public links and instead show a hint pointing operators back to the desktop client for weixin_gzh / zol records. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -229,7 +229,13 @@ async function refreshArticleData(): Promise<void> {
|
||||
}
|
||||
|
||||
function resolvePublishLink(record: PublishRecord): string {
|
||||
return record.external_article_url || record.external_manage_url || "";
|
||||
return record.external_article_url?.trim() || "";
|
||||
}
|
||||
|
||||
function shouldShowClientManageHint(record: PublishRecord): boolean {
|
||||
return !resolvePublishLink(record)
|
||||
&& Boolean(record.external_manage_url?.trim())
|
||||
&& ["weixin_gzh", "zol"].includes(record.platform_id);
|
||||
}
|
||||
|
||||
async function copyPublishLink(record: PublishRecord): Promise<void> {
|
||||
@@ -395,6 +401,9 @@ async function copyPublishLink(record: PublishRecord): Promise<void> {
|
||||
</a-button>
|
||||
</a-tooltip>
|
||||
</div>
|
||||
<span v-else-if="shouldShowClientManageHint(record)" class="article-drawer__record-hint">
|
||||
{{ t("media.records.clientManageHint") }}
|
||||
</span>
|
||||
<span v-else class="article-drawer__record-empty">--</span>
|
||||
</template>
|
||||
</template>
|
||||
@@ -521,6 +530,11 @@ async function copyPublishLink(record: PublishRecord): Promise<void> {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.article-drawer__record-hint {
|
||||
color: var(--muted);
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.article-drawer__record-link {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
|
||||
@@ -1086,6 +1086,7 @@ const zhCN = {
|
||||
copy: "复制",
|
||||
empty: "暂无发布记录",
|
||||
linkEmpty: "当前记录还没有可用链接",
|
||||
clientManageHint: "仅有管理页面,请在客户端打开管理页面查看",
|
||||
copySuccess: "链接已复制",
|
||||
},
|
||||
},
|
||||
|
||||
@@ -41,6 +41,8 @@ interface PublishTaskItem {
|
||||
updatedAt: number;
|
||||
externalArticleUrl: string | null;
|
||||
externalManageUrl: string | null;
|
||||
publishType: string | null;
|
||||
fallbackReason: string | null;
|
||||
errorMessage: string | null;
|
||||
}
|
||||
|
||||
@@ -79,6 +81,13 @@ function statusLabel(status: DesktopTaskInfo["status"]): string {
|
||||
return map[status];
|
||||
}
|
||||
|
||||
function statusLabelForTask(task: PublishTaskItem): string {
|
||||
if (task.status === "succeeded" && task.publishType === "draft") {
|
||||
return "已存草稿";
|
||||
}
|
||||
return statusLabel(task.status);
|
||||
}
|
||||
|
||||
function isPendingStatus(status: DesktopTaskInfo["status"]): boolean {
|
||||
return status === "queued" || status === "in_progress";
|
||||
}
|
||||
@@ -98,6 +107,13 @@ function statusTone(status: DesktopTaskInfo["status"]): "info" | "warn" | "succe
|
||||
}
|
||||
}
|
||||
|
||||
function statusToneForTask(task: PublishTaskItem): "info" | "warn" | "success" | "danger" {
|
||||
if (task.status === "succeeded" && task.publishType === "draft") {
|
||||
return "warn";
|
||||
}
|
||||
return statusTone(task.status);
|
||||
}
|
||||
|
||||
function extractNumber(value: JsonValue | null | undefined): number | null {
|
||||
if (typeof value === "number" && Number.isFinite(value)) {
|
||||
return value;
|
||||
@@ -164,13 +180,23 @@ function inlineErrorPreview(message: string): string {
|
||||
return `${compact.slice(0, INLINE_ERROR_HEAD_CHARS)}...${compact.slice(-INLINE_ERROR_TAIL_CHARS)}`;
|
||||
}
|
||||
|
||||
function summaryForTask(status: DesktopTaskInfo["status"]): string {
|
||||
function summaryForTask(
|
||||
status: DesktopTaskInfo["status"],
|
||||
publishType: string | null = null,
|
||||
fallbackReason: string | null = null,
|
||||
): string {
|
||||
switch (status) {
|
||||
case "queued":
|
||||
return "任务已进入队列,等前面的 PublishTasks 翻完后再继续展示历史记录。";
|
||||
case "in_progress":
|
||||
return "当前正在由桌面端执行发送,请避免重复触发。";
|
||||
case "succeeded":
|
||||
if (publishType === "draft") {
|
||||
if (fallbackReason === "publish_authorization_required") {
|
||||
return "草稿已保存,需在公众号后台完成微信验证/授权发布。";
|
||||
}
|
||||
return "文章已保存到草稿箱,需在平台后台完成发表。";
|
||||
}
|
||||
return "文章已成功发送到目标平台。";
|
||||
case "failed":
|
||||
return "本次发送失败,可以手动再次发送。";
|
||||
@@ -182,6 +208,13 @@ function summaryForTask(status: DesktopTaskInfo["status"]): string {
|
||||
}
|
||||
}
|
||||
|
||||
function manageLinkLabel(task: PublishTaskItem): string {
|
||||
if (task.publishType === "draft" && task.platform === "weixin_gzh") {
|
||||
return "打开草稿箱";
|
||||
}
|
||||
return "打开管理页";
|
||||
}
|
||||
|
||||
function parseTimestamp(value: string | null): number {
|
||||
if (!value) {
|
||||
return Date.now();
|
||||
@@ -376,6 +409,8 @@ const publishTasks = computed<PublishTaskItem[]>(() =>
|
||||
const payload = task.payload ?? {};
|
||||
const result = task.result ?? {};
|
||||
const taskError = task.error ?? {};
|
||||
const publishType = extractString(result.publish_type);
|
||||
const fallbackReason = extractString(result.fallback_reason);
|
||||
const nestedContentRef =
|
||||
payload.content_ref && typeof payload.content_ref === "object" && !Array.isArray(payload.content_ref)
|
||||
? (payload.content_ref as Record<string, JsonValue>)
|
||||
@@ -390,13 +425,17 @@ const publishTasks = computed<PublishTaskItem[]>(() =>
|
||||
accountId: task.target_account_id,
|
||||
accountName: accountNameMap.value.get(task.target_account_id) ?? "待同步账号",
|
||||
status: normalizedStatus,
|
||||
summary: summaryForTask(normalizedStatus),
|
||||
summary: summaryForTask(normalizedStatus, publishType, fallbackReason),
|
||||
attempts: task.attempts,
|
||||
leaseExpiresAt: task.lease_expires_at ? parseTimestamp(task.lease_expires_at) : null,
|
||||
createdAt: parseTimestamp(task.created_at),
|
||||
updatedAt: parseTimestamp(task.updated_at),
|
||||
externalArticleUrl: extractString(result.external_article_url) ?? buildSohuArticleUrl(task, result),
|
||||
externalArticleUrl: publishType === "draft"
|
||||
? null
|
||||
: extractString(result.external_article_url) ?? buildSohuArticleUrl(task, result),
|
||||
externalManageUrl: extractString(result.external_manage_url),
|
||||
publishType,
|
||||
fallbackReason,
|
||||
errorMessage: normalizeTaskErrorMessage(
|
||||
extractString(taskError.message)
|
||||
?? extractString(taskError.detail)
|
||||
@@ -533,7 +572,7 @@ const tableScroll = { x: 1000 } as const;
|
||||
</template>
|
||||
|
||||
<template v-else-if="column.key === 'status'">
|
||||
<StatusBadge :tone="statusTone(record.status)" :label="statusLabel(record.status)" />
|
||||
<StatusBadge :tone="statusToneForTask(record)" :label="statusLabelForTask(record)" />
|
||||
</template>
|
||||
|
||||
<template v-else-if="column.key === 'meta'">
|
||||
@@ -592,7 +631,7 @@ const tableScroll = { x: 1000 } as const;
|
||||
@click.prevent.stop="openAccountWorkbench(record)"
|
||||
>
|
||||
<LinkOutlined />
|
||||
打开管理页
|
||||
{{ manageLinkLabel(record) }}
|
||||
</a>
|
||||
</a-tooltip>
|
||||
</template>
|
||||
|
||||
Reference in New Issue
Block a user