feat(publish-dedup): disable already-published accounts and rework retry UX
In the admin publish modal, fetch the article's publish records, disable accounts that already succeeded for the same article/platform, label queued/publishing accounts inline, and route the success notification by created vs existing task counts (with a dedicated warning for the `desktop_publish_duplicate` server error). Replace the "再次发送" mutation/popconfirm on both admin and desktop publish management views with a "重新创建发布任务" action that calls the same Create endpoint, only enables on failed/aborted/unknown rows, and reports created vs existing task counts (with a tailored warning for `unknown` results that may have already succeeded). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -11,7 +11,9 @@ import type {
|
||||
ArticleDetail,
|
||||
ComplianceCheckResult,
|
||||
ComplianceRuntimeStatus,
|
||||
CreatePublishJobResponse,
|
||||
GateDecisionLiteral,
|
||||
PublishRecord,
|
||||
} from '@geo/shared-types'
|
||||
import { useMutation, useQuery, useQueryClient } from '@tanstack/vue-query'
|
||||
import { message, notification } from 'ant-design-vue'
|
||||
@@ -41,6 +43,7 @@ import {
|
||||
publishStateLabel,
|
||||
type PublishAccountCard,
|
||||
} from '@/lib/publish-account-cards'
|
||||
import { normalizePublishPlatformId } from '@/lib/publish-platforms'
|
||||
import { useCompanyStore } from '@/stores/company'
|
||||
|
||||
const props = defineProps<{
|
||||
@@ -92,6 +95,20 @@ const accountsQuery = useQuery({
|
||||
queryFn: () => tenantAccountsApi.list(),
|
||||
})
|
||||
|
||||
const publishRecordsQuery = useQuery({
|
||||
queryKey: computed(() => [
|
||||
'articles',
|
||||
'publish-records',
|
||||
companyStore.currentBrandId,
|
||||
props.articleId,
|
||||
'publish-modal',
|
||||
]),
|
||||
enabled: computed(
|
||||
() => props.open && Boolean(props.articleId) && Boolean(companyStore.currentBrandId),
|
||||
),
|
||||
queryFn: () => articlesApi.publishRecords(props.articleId as number),
|
||||
})
|
||||
|
||||
const platformsQuery = useQuery({
|
||||
queryKey: ['media', 'platforms', 'publish-modal'],
|
||||
enabled: computed(() => props.open),
|
||||
@@ -127,6 +144,7 @@ watch(
|
||||
|
||||
await Promise.allSettled([
|
||||
props.articleId ? detailQuery.refetch() : Promise.resolve(),
|
||||
props.articleId ? publishRecordsQuery.refetch() : Promise.resolve(),
|
||||
accountsQuery.refetch(),
|
||||
platformsQuery.refetch(),
|
||||
complianceStatusQuery.refetch(),
|
||||
@@ -136,9 +154,52 @@ watch(
|
||||
)
|
||||
|
||||
const platformMap = computed(() => buildPublishPlatformMap(platformsQuery.data.value ?? []))
|
||||
const successfulPublishRecordKeys = computed(() =>
|
||||
new Set(
|
||||
(publishRecordsQuery.data.value ?? [])
|
||||
.filter((record) => isSuccessfulPublishRecord(record))
|
||||
.map((record) => successfulPublishRecordKey(record.desktop_account_id, record.platform_id))
|
||||
.filter((key): key is string => Boolean(key)),
|
||||
),
|
||||
)
|
||||
const activePublishRecordStatusByKey = computed(() => {
|
||||
const statusByKey = new Map<string, string>()
|
||||
for (const record of publishRecordsQuery.data.value ?? []) {
|
||||
if (!isActivePublishRecord(record)) {
|
||||
continue
|
||||
}
|
||||
const key = successfulPublishRecordKey(record.desktop_account_id, record.platform_id)
|
||||
if (!key || statusByKey.has(key)) {
|
||||
continue
|
||||
}
|
||||
statusByKey.set(key, record.status)
|
||||
}
|
||||
return statusByKey
|
||||
})
|
||||
const publishedAccountIds = computed(() =>
|
||||
new Set(
|
||||
(publishRecordsQuery.data.value ?? [])
|
||||
.filter((record) => isSuccessfulPublishRecord(record))
|
||||
.map((record) => record.desktop_account_id?.trim())
|
||||
.filter((id): id is string => Boolean(id)),
|
||||
),
|
||||
)
|
||||
const publishedAccountCount = computed(() => publishedAccountIds.value.size)
|
||||
|
||||
const accountCards = computed<PublishAccountCard[]>(() =>
|
||||
buildPublishAccountCards(accountsQuery.data.value ?? [], platformMap.value),
|
||||
buildPublishAccountCards(accountsQuery.data.value ?? [], platformMap.value).map((card) => {
|
||||
const alreadyPublished = successfulPublishRecordKeys.value.has(
|
||||
successfulPublishRecordKey(card.id, card.platformId) ?? '',
|
||||
)
|
||||
if (!alreadyPublished) {
|
||||
return card
|
||||
}
|
||||
return {
|
||||
...card,
|
||||
selectable: false,
|
||||
statusText: '这篇文章已用该账号在该平台发布成功,不能重复发布;如需重新发布,请复制或新建一篇文章。',
|
||||
}
|
||||
}),
|
||||
)
|
||||
|
||||
watch(
|
||||
@@ -173,6 +234,8 @@ watchEffect(() => {
|
||||
detailQuery.isFetching.value ||
|
||||
accountsQuery.isPending.value ||
|
||||
accountsQuery.isFetching.value ||
|
||||
publishRecordsQuery.isPending.value ||
|
||||
publishRecordsQuery.isFetching.value ||
|
||||
platformsQuery.isPending.value ||
|
||||
platformsQuery.isFetching.value
|
||||
) {
|
||||
@@ -287,6 +350,9 @@ const okText = computed(() => {
|
||||
return '提交发布'
|
||||
})
|
||||
const okDisabled = computed(() => {
|
||||
if (coverRequired.value && !normalizedCoverValue.value) {
|
||||
return true
|
||||
}
|
||||
if (mandatoryAdmissionBlocking.value) {
|
||||
return true
|
||||
}
|
||||
@@ -481,13 +547,19 @@ async function runPublishFlow(ackRecordId?: number) {
|
||||
})
|
||||
}
|
||||
|
||||
async function handlePublishSuccess() {
|
||||
notification.success({
|
||||
message: '已提交发布任务',
|
||||
description: successDescription(),
|
||||
async function handlePublishSuccess(result: CreatePublishJobResponse) {
|
||||
const description = successDescription(result)
|
||||
const options = {
|
||||
message: result.created_task_ids.length === 0 ? '发布任务已存在' : '已提交发布任务',
|
||||
description,
|
||||
placement: 'topRight',
|
||||
duration: 5,
|
||||
})
|
||||
} as const
|
||||
if (result.created_task_ids.length === 0 && result.existing_task_ids.length > 0) {
|
||||
notification.info(options)
|
||||
} else {
|
||||
notification.success(options)
|
||||
}
|
||||
|
||||
await Promise.all([
|
||||
queryClient.invalidateQueries({ queryKey: ['articles'] }),
|
||||
@@ -522,6 +594,10 @@ function handlePublishError(error: unknown) {
|
||||
if (normalized === 'compliance_needs_ack' || normalized === 'compliance_block') {
|
||||
return
|
||||
}
|
||||
if (error instanceof ApiClientError && error.message === 'desktop_publish_duplicate') {
|
||||
message.warning('内容已在发布队列中,未重复提交')
|
||||
return
|
||||
}
|
||||
message.error(formatError(error))
|
||||
}
|
||||
|
||||
@@ -542,18 +618,30 @@ async function persistCoverIfNeeded(detail: ArticleDetail): Promise<ArticleDetai
|
||||
})
|
||||
}
|
||||
|
||||
function successDescription(): string {
|
||||
const total = selectedCards.value.length
|
||||
if (total === 0) {
|
||||
function successDescription(result: CreatePublishJobResponse): string {
|
||||
const created = result.created_task_ids.length
|
||||
const existing = result.existing_task_ids.length
|
||||
const total = created + existing
|
||||
if (total > 0) {
|
||||
if (created === 0) {
|
||||
return `共 ${existing} 个账号已有发布记录或任务,未重复提交;如结果未知,请先核实平台侧结果。`
|
||||
}
|
||||
if (existing > 0) {
|
||||
return `新建 ${created} 个发布任务;${existing} 个账号已有发布记录或任务,未重复提交。`
|
||||
}
|
||||
}
|
||||
|
||||
const selectedTotal = selectedCards.value.length
|
||||
if (selectedTotal === 0) {
|
||||
return '任务已进入发布队列。'
|
||||
}
|
||||
if (selectedQueuedCount.value === 0) {
|
||||
return `共 ${total} 个账号,在线客户端会立即开始消费。`
|
||||
return `共 ${selectedTotal} 个账号,在线客户端会立即开始消费。`
|
||||
}
|
||||
if (selectedImmediateCount.value === 0) {
|
||||
return `共 ${total} 个账号已进入离线队列,客户端上线后会自动继续发布。`
|
||||
return `共 ${selectedTotal} 个账号已进入离线队列,客户端上线后会自动继续发布。`
|
||||
}
|
||||
return `共 ${total} 个账号:${selectedImmediateCount.value} 个立即发布,${selectedQueuedCount.value} 个离线排队。`
|
||||
return `共 ${selectedTotal} 个账号:${selectedImmediateCount.value} 个立即发布,${selectedQueuedCount.value} 个离线排队。`
|
||||
}
|
||||
|
||||
function toggleAccount(accountId: string, selectable: boolean): void {
|
||||
@@ -573,6 +661,64 @@ function isSelected(accountId: string): boolean {
|
||||
return selectedAccountIds.value.includes(accountId)
|
||||
}
|
||||
|
||||
function isAlreadyPublished(account: PublishAccountCard): boolean {
|
||||
return successfulPublishRecordKeys.value.has(
|
||||
successfulPublishRecordKey(account.id, account.platformId) ?? '',
|
||||
)
|
||||
}
|
||||
|
||||
function activePublishRecordStatus(account: PublishAccountCard): string | null {
|
||||
return activePublishRecordStatusByKey.value.get(
|
||||
successfulPublishRecordKey(account.id, account.platformId) ?? '',
|
||||
) ?? null
|
||||
}
|
||||
|
||||
function activePublishRecordLabel(account: PublishAccountCard): string | null {
|
||||
switch (activePublishRecordStatus(account)) {
|
||||
case 'publishing':
|
||||
case 'running':
|
||||
return '发布中'
|
||||
case 'queued':
|
||||
case 'pending':
|
||||
return '已排队'
|
||||
default:
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
function successfulPublishRecordKey(
|
||||
desktopAccountId?: string | null,
|
||||
platformId?: string | null,
|
||||
): string | null {
|
||||
const accountID = String(desktopAccountId ?? '').trim()
|
||||
const platform = normalizePublishPlatformId(platformId)
|
||||
if (!accountID || !platform) {
|
||||
return null
|
||||
}
|
||||
return `${accountID}:${platform}`
|
||||
}
|
||||
|
||||
function isSuccessfulPublishRecord(record: PublishRecord): boolean {
|
||||
switch (String(record.status ?? '').trim()) {
|
||||
case 'success':
|
||||
return Boolean(record.desktop_account_id)
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
function isActivePublishRecord(record: PublishRecord): boolean {
|
||||
switch (String(record.status ?? '').trim()) {
|
||||
case 'queued':
|
||||
case 'pending':
|
||||
case 'publishing':
|
||||
case 'running':
|
||||
return Boolean(record.desktop_account_id)
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
function handleCoverToggle(checked: boolean): void {
|
||||
if (coverRequired.value) {
|
||||
coverEnabled.value = true
|
||||
@@ -667,8 +813,8 @@ async function publishWithAck(): Promise<void> {
|
||||
const ack = await complianceApi.createAck(result.record_id, {
|
||||
acknowledged_violation_ids: complianceAcknowledgedViolationIds.value,
|
||||
})
|
||||
await runPublishFlow(ack.id)
|
||||
await handlePublishSuccess()
|
||||
const publishResult = await runPublishFlow(ack.id)
|
||||
await handlePublishSuccess(publishResult)
|
||||
} catch (error) {
|
||||
handlePublishError(error)
|
||||
} finally {
|
||||
@@ -784,12 +930,19 @@ function decisionAlertType(result: ComplianceCheckResult | null | undefined) {
|
||||
</div>
|
||||
</div>
|
||||
<p class="muted">
|
||||
优先预选文章里已经勾选的平台账号。支持同平台多账号;授权异常或未绑定桌面客户端的账号不可选。
|
||||
优先预选文章里已经勾选的平台账号。支持同平台多账号;授权异常、未绑定桌面客户端或已成功发布过该文章的账号不可选;如需重新发布,请复制或新建一篇文章。
|
||||
<span v-if="publishedAccountCount > 0" class="publish-modal__published-note">
|
||||
其中 {{ publishedAccountCount }} 个因已成功发布禁用。
|
||||
</span>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-if="accountsQuery.isPending.value || platformsQuery.isPending.value"
|
||||
v-if="
|
||||
accountsQuery.isPending.value ||
|
||||
platformsQuery.isPending.value ||
|
||||
publishRecordsQuery.isPending.value
|
||||
"
|
||||
class="publish-modal__loading"
|
||||
>
|
||||
<a-skeleton active :paragraph="{ rows: 5 }" />
|
||||
@@ -826,9 +979,13 @@ function decisionAlertType(result: ComplianceCheckResult | null | undefined) {
|
||||
<a-tooltip :title="account.statusText" placement="top">
|
||||
<span
|
||||
class="publish-modal__state-pill publish-modal__state-pill--compact"
|
||||
:class="`publish-modal__state-pill--${account.publishState}`"
|
||||
:class="
|
||||
isAlreadyPublished(account)
|
||||
? 'publish-modal__state-pill--published'
|
||||
: `publish-modal__state-pill--${account.publishState}`
|
||||
"
|
||||
>
|
||||
{{ publishStateLabel(account.publishState) }}
|
||||
{{ isAlreadyPublished(account) ? '已发布' : publishStateLabel(account.publishState) }}
|
||||
</span>
|
||||
</a-tooltip>
|
||||
</div>
|
||||
@@ -874,6 +1031,12 @@ function decisionAlertType(result: ComplianceCheckResult | null | undefined) {
|
||||
{{ clientStatusLabel(account) }}
|
||||
</a-tag>
|
||||
</a-tooltip>
|
||||
<a-tag v-if="isAlreadyPublished(account)" color="blue">
|
||||
已发布
|
||||
</a-tag>
|
||||
<a-tag v-else-if="activePublishRecordLabel(account)" color="gold">
|
||||
{{ activePublishRecordLabel(account) }}
|
||||
</a-tag>
|
||||
</div>
|
||||
</div>
|
||||
</button>
|
||||
@@ -1457,6 +1620,12 @@ function decisionAlertType(result: ComplianceCheckResult | null | undefined) {
|
||||
border: 1px solid #fecaca;
|
||||
}
|
||||
|
||||
.publish-modal__state-pill--published {
|
||||
background: #dbeafe;
|
||||
color: #1d4ed8;
|
||||
border: 1px solid #bfdbfe;
|
||||
}
|
||||
|
||||
.publish-modal__tags {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
|
||||
@@ -219,7 +219,7 @@ const zhCN = {
|
||||
},
|
||||
publishManagement: {
|
||||
title: "发文管理",
|
||||
description: "查看桌面端发布任务、外链、账号工作台入口和重发状态。",
|
||||
description: "查看桌面端发布任务、外链、账号工作台入口和发布结果。",
|
||||
},
|
||||
brands: {
|
||||
title: "品牌和词库",
|
||||
|
||||
@@ -83,6 +83,7 @@ const errorMessageMap: Record<string, string> = {
|
||||
desktop_account_client_missing: '所选账号还没有绑定桌面客户端,暂时无法发布',
|
||||
desktop_account_not_found: '所选桌面账号不存在,请刷新后重试',
|
||||
desktop_client_offline: '当前登录账号的桌面客户端未在线,请先打开 desktop-client',
|
||||
desktop_publish_duplicate: '内容已在发布队列中,未重复提交',
|
||||
desktop_publish_job_store_unavailable: '发布队列暂时不可用,请稍后重试',
|
||||
compliance_blocked: '内容合规检测已阻断本次发布',
|
||||
compliance_needs_ack: '内容合规检测需要确认风险后才能发布',
|
||||
|
||||
@@ -5,11 +5,11 @@ import {
|
||||
DesktopOutlined,
|
||||
ExportOutlined,
|
||||
ReloadOutlined,
|
||||
RetweetOutlined,
|
||||
SearchOutlined,
|
||||
SendOutlined,
|
||||
} from '@ant-design/icons-vue'
|
||||
import type { DesktopTaskInfo, JsonValue } from '@geo/shared-types'
|
||||
import { useMutation, useQuery, useQueryClient } from '@tanstack/vue-query'
|
||||
import type { DesktopTaskInfo, JsonValue, TenantPublishTaskListResponse } from '@geo/shared-types'
|
||||
import { useQuery } from '@tanstack/vue-query'
|
||||
import type { TableColumnsType } from 'ant-design-vue'
|
||||
import { message } from 'ant-design-vue'
|
||||
import { computed, ref, watch } from 'vue'
|
||||
@@ -26,6 +26,7 @@ import { useCompanyStore } from '@/stores/company'
|
||||
const PAGE_SIZE = 10
|
||||
const INLINE_ERROR_HEAD_CHARS = 52
|
||||
const INLINE_ERROR_TAIL_CHARS = 10
|
||||
const ACTIVE_PUBLISH_TASK_POLL_INTERVAL_MS = 5_000
|
||||
const DONGCHEDI_PLATFORM_EXCEPTION_MESSAGE =
|
||||
'懂车帝平台返回异常,请打开懂车帝后台查看并处理平台提示,确认账号状态后再重试。'
|
||||
|
||||
@@ -97,6 +98,10 @@ function isPendingStatus(status: PublishTaskStatus): boolean {
|
||||
return status === 'queued' || status === 'in_progress'
|
||||
}
|
||||
|
||||
function hasActivePublishingTask(page: TenantPublishTaskListResponse | undefined): boolean {
|
||||
return Boolean(page?.items.some((task) => normalizePublishTaskStatus(task.status) === 'in_progress'))
|
||||
}
|
||||
|
||||
function normalizeTaskErrorMessage(messageText: string | null, platform?: string | null): string | null {
|
||||
const normalized = extractString(messageText)
|
||||
if (!normalized) {
|
||||
@@ -209,12 +214,12 @@ function summaryForTask(
|
||||
? '文章已保存到草稿箱,需在平台后台完成发表。'
|
||||
: '文章已成功发送到目标平台。'
|
||||
case 'failed':
|
||||
return '本次发送失败,可以手动再次发送。'
|
||||
return '本次发送失败,请检查账号状态或平台提示后重新创建发布。'
|
||||
case 'aborted':
|
||||
return '任务已被取消,如需继续可再次发送。'
|
||||
return '任务已被取消,请检查原因后重新创建发布。'
|
||||
case 'unknown':
|
||||
default:
|
||||
return '发送结果异常,已按失败处理,可检查平台侧结果后再次发送。'
|
||||
return '发送结果异常,已按失败处理,请检查平台侧结果后重新创建发布。'
|
||||
}
|
||||
}
|
||||
|
||||
@@ -233,7 +238,7 @@ function statusMetaForTask(
|
||||
case 'queued':
|
||||
return { label: '等待发布', color: 'processing' }
|
||||
case 'in_progress':
|
||||
return { label: '正在发送', color: 'processing' }
|
||||
return { label: '正在发布', color: 'processing' }
|
||||
case 'succeeded':
|
||||
return { label: '发送成功', color: 'success' }
|
||||
case 'failed':
|
||||
@@ -308,12 +313,13 @@ function buildDesktopWorkbenchUrl(record: {
|
||||
}
|
||||
|
||||
const { t } = useI18n()
|
||||
const queryClient = useQueryClient()
|
||||
const companyStore = useCompanyStore()
|
||||
const page = ref(1)
|
||||
const searchTitle = ref('')
|
||||
const appliedTitle = ref('')
|
||||
const copiedErrorTaskId = ref<string | null>(null)
|
||||
const retryingTaskId = ref<string | null>(null)
|
||||
const manualRefreshing = ref(false)
|
||||
|
||||
const accountsQuery = useQuery({
|
||||
queryKey: ['tenant', 'desktop-accounts', 'publish-management'],
|
||||
@@ -334,23 +340,15 @@ const tasksQuery = useQuery({
|
||||
page_size: PAGE_SIZE,
|
||||
title: appliedTitle.value || undefined,
|
||||
}),
|
||||
})
|
||||
|
||||
const retryMutation = useMutation({
|
||||
mutationFn: (taskId: string) => publishTasksApi.retry(taskId),
|
||||
onSuccess: async () => {
|
||||
message.success('已重新加入发布队列')
|
||||
await Promise.all([
|
||||
queryClient.invalidateQueries({ queryKey: ['tenant', 'publish-tasks'] }),
|
||||
queryClient.invalidateQueries({ queryKey: ['articles'] }),
|
||||
queryClient.invalidateQueries({ queryKey: ['workspace'] }),
|
||||
])
|
||||
refetchInterval: (query) => {
|
||||
const data = query.state.data as TenantPublishTaskListResponse | undefined
|
||||
return hasActivePublishingTask(data) ? ACTIVE_PUBLISH_TASK_POLL_INTERVAL_MS : false
|
||||
},
|
||||
onError: (error) => message.error(formatError(error)),
|
||||
refetchIntervalInBackground: false,
|
||||
})
|
||||
|
||||
const loading = computed(() => tasksQuery.isPending.value || accountsQuery.isPending.value)
|
||||
const refreshing = computed(() => tasksQuery.isFetching.value || accountsQuery.isFetching.value)
|
||||
const refreshing = computed(() => manualRefreshing.value)
|
||||
const taskPage = computed(() => tasksQuery.data.value)
|
||||
const pendingCount = computed(() => taskPage.value?.pending_count ?? 0)
|
||||
const historyTotal = computed(() => taskPage.value?.history_total ?? 0)
|
||||
@@ -456,9 +454,17 @@ watch(searchTitle, (value) => {
|
||||
}
|
||||
})
|
||||
|
||||
function refresh(): void {
|
||||
void tasksQuery.refetch()
|
||||
void accountsQuery.refetch()
|
||||
async function refresh(): Promise<void> {
|
||||
if (manualRefreshing.value) {
|
||||
return
|
||||
}
|
||||
|
||||
manualRefreshing.value = true
|
||||
try {
|
||||
await Promise.all([tasksQuery.refetch(), accountsQuery.refetch()])
|
||||
} finally {
|
||||
manualRefreshing.value = false
|
||||
}
|
||||
}
|
||||
|
||||
function applySearch(): void {
|
||||
@@ -474,6 +480,35 @@ function rowClassName(record: PublishTaskItem): string {
|
||||
return isPendingStatus(record.status) ? 'publish-management-row--pending' : ''
|
||||
}
|
||||
|
||||
function canRetryTask(record: PublishTaskItem): boolean {
|
||||
return record.status === 'failed' || record.status === 'aborted' || record.status === 'unknown'
|
||||
}
|
||||
|
||||
async function retryTask(record: PublishTaskItem): Promise<void> {
|
||||
retryingTaskId.value = record.id
|
||||
try {
|
||||
const result = await publishTasksApi.retry(record.id)
|
||||
const created = result.created_task_ids.length
|
||||
const existing = result.existing_task_ids.length
|
||||
if (created > 0) {
|
||||
message.success(created === 1 ? '已重新创建发布任务' : `已重新创建 ${created} 个发布任务`)
|
||||
} else if (existing > 0) {
|
||||
if (record.status === 'unknown') {
|
||||
message.warning('原任务结果未知且已有发布记录,可能已成功,请先核实平台侧结果。')
|
||||
} else {
|
||||
message.info('发布任务已存在,无需重复创建')
|
||||
}
|
||||
} else {
|
||||
message.success('已提交重试请求')
|
||||
}
|
||||
await tasksQuery.refetch()
|
||||
} catch (error) {
|
||||
message.error(formatError(error))
|
||||
} finally {
|
||||
retryingTaskId.value = null
|
||||
}
|
||||
}
|
||||
|
||||
async function copyErrorMessage(record: PublishTaskItem): Promise<void> {
|
||||
if (!record.errorMessage) {
|
||||
return
|
||||
@@ -690,28 +725,18 @@ async function copyErrorMessage(record: PublishTaskItem): Promise<void> {
|
||||
<template #icon><DesktopOutlined /></template>
|
||||
</a-button>
|
||||
</a-tooltip>
|
||||
<a-popconfirm
|
||||
v-if="!isPendingStatus(record.status)"
|
||||
title="确定要重试本次发布吗?"
|
||||
placement="topRight"
|
||||
ok-text="确定"
|
||||
cancel-text="取消"
|
||||
@confirm="retryMutation.mutate(record.id)"
|
||||
>
|
||||
<a-tooltip title="重新发送" placement="top">
|
||||
<a-button
|
||||
type="text"
|
||||
class="publish-action-btn"
|
||||
:loading="
|
||||
retryMutation.isPending.value && retryMutation.variables.value === record.id
|
||||
"
|
||||
:aria-label="`重新发送:${record.title}`"
|
||||
>
|
||||
<template #icon><SendOutlined /></template>
|
||||
</a-button>
|
||||
</a-tooltip>
|
||||
</a-popconfirm>
|
||||
<a-tooltip v-else title="发布任务进行中">
|
||||
<a-tooltip v-if="canRetryTask(record)" title="重新创建发布任务" placement="top">
|
||||
<a-button
|
||||
type="text"
|
||||
class="publish-action-btn"
|
||||
:loading="retryingTaskId === record.id"
|
||||
:aria-label="`重新创建发布任务:${record.title}`"
|
||||
@click.stop="retryTask(record)"
|
||||
>
|
||||
<template #icon><RetweetOutlined /></template>
|
||||
</a-button>
|
||||
</a-tooltip>
|
||||
<a-tooltip v-if="isPendingStatus(record.status)" title="发布任务进行中">
|
||||
<span class="publish-action-placeholder">
|
||||
<ClockCircleOutlined />
|
||||
</span>
|
||||
|
||||
Reference in New Issue
Block a user