feat(publish): add baijiahao and jianshu desktop adapters

Wires up Baijiahao (百家号) and Jianshu (简书) as first-class desktop
publish targets, with risk-control prompts surfaced in the runtime
controller and a normalized error message in publish records. Adds
external-link buttons in the publish management table, an asset
format conversion endpoint for cover image compatibility, and
reorders publish-status display priority so failures take precedence
over partial successes.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-26 19:47:35 +08:00
parent ae63f60def
commit 87e329207c
27 changed files with 2056 additions and 54 deletions
+1
View File
@@ -28,6 +28,7 @@ declare global {
unbindPublishAccount(accountId: string, syncVersion: number): Promise<null>;
listPublishTasks(params?: ListDesktopPublishTasksParams): Promise<DesktopPublishTaskListResponse>;
retryPublishTask(taskId: string): Promise<CreatePublishJobResponse>;
openExternalUrl(url: string): Promise<null>;
syncRuntimeSession(session: DesktopRuntimeSessionSyncRequest | null): Promise<null>;
releaseRuntimeSession(revoke?: boolean): Promise<null>;
setWindowMode(mode: "login" | "main"): Promise<null>;
@@ -1,5 +1,11 @@
<script setup lang="ts">
import { ClockCircleOutlined, ReloadOutlined, SearchOutlined, SendOutlined } from "@ant-design/icons-vue";
import {
ClockCircleOutlined,
ExportOutlined,
ReloadOutlined,
SearchOutlined,
SendOutlined,
} from "@ant-design/icons-vue";
import type { DesktopPublishTaskListResponse, DesktopTaskInfo, JsonValue } from "@geo/shared-types";
import { computed, onMounted, onUnmounted, ref, watch } from "vue";
@@ -190,6 +196,19 @@ async function retryTask(taskId: string) {
}
}
async function openExternalUrl(url: string | null) {
if (!url) {
return;
}
actionError.value = null;
try {
await window.desktopBridge.app.openExternalUrl(url);
} catch (err) {
actionError.value = err instanceof Error ? err.message : "打开外链失败";
}
}
function applySearch() {
currentPage.value = 1;
appliedTitle.value = searchTitle.value.trim();
@@ -396,8 +415,36 @@ const tableColumns = [
<span class="subtitle mono-detail">
尝试 {{ record.attempts }}
<template v-if="record.leaseExpiresAt"> · 租约 {{ formatRelativeTime(record.leaseExpiresAt) }} 到期</template>
<template v-else-if="record.externalArticleUrl"> · 已生成外链</template>
<template v-else-if="record.externalManageUrl"> · 已生成管理链接</template>
<template v-else-if="record.externalArticleUrl">
·
<a-tooltip :title="record.externalArticleUrl" overlay-class-name="external-url-tooltip">
<a
class="external-task-link"
:href="record.externalArticleUrl"
target="_blank"
rel="noopener noreferrer"
@click.prevent.stop="openExternalUrl(record.externalArticleUrl)"
>
<ExportOutlined />
打开外链
</a>
</a-tooltip>
</template>
<template v-else-if="record.externalManageUrl">
·
<a-tooltip :title="record.externalManageUrl" overlay-class-name="external-url-tooltip">
<a
class="external-task-link"
:href="record.externalManageUrl"
target="_blank"
rel="noopener noreferrer"
@click.prevent.stop="openExternalUrl(record.externalManageUrl)"
>
<ExportOutlined />
打开管理页
</a>
</a-tooltip>
</template>
</span>
</div>
</div>
@@ -628,6 +675,23 @@ const tableColumns = [
color: #94a3b8;
}
.external-task-link {
display: inline-flex;
align-items: center;
gap: 4px;
color: #2563eb;
font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
font-size: 12px;
font-weight: 600;
line-height: 1.5;
text-decoration: none;
}
.external-task-link:hover {
color: #1d4ed8;
text-decoration: underline;
}
.info-stack .strong-text {
color: #1e293b;
font-weight: 500;
@@ -709,6 +773,11 @@ const tableColumns = [
background: #ecfdf5;
}
:global(.external-url-tooltip .ant-tooltip-inner) {
max-width: min(520px, 80vw);
overflow-wrap: anywhere;
}
/* Responsiveness */
@media (max-width: 1024px) {
.hero-header {