feat(article): support regenerating failed articles

This commit is contained in:
2026-05-07 10:55:44 +08:00
parent ff2bb77cdd
commit 7d82c5c193
21 changed files with 659 additions and 23 deletions
@@ -4,6 +4,7 @@ import {
DeleteOutlined,
EditOutlined,
EyeOutlined,
ReloadOutlined,
SendOutlined,
} from '@ant-design/icons-vue'
import { useI18n } from 'vue-i18n'
@@ -22,6 +23,11 @@ withDefaults(
showCopy?: boolean
canCopy?: boolean
copyDisabledTitle?: string
showRegenerate?: boolean
canRegenerate?: boolean
regenerateDisabledTitle?: string
regenerateConfirmTitle?: string
regenerateLoading?: boolean
showDelete?: boolean
canDelete?: boolean
deleteDisabledTitle?: string
@@ -41,6 +47,11 @@ withDefaults(
showCopy: false,
canCopy: true,
copyDisabledTitle: '',
showRegenerate: false,
canRegenerate: true,
regenerateDisabledTitle: '',
regenerateConfirmTitle: '',
regenerateLoading: false,
showDelete: true,
canDelete: true,
deleteDisabledTitle: '',
@@ -54,6 +65,7 @@ const emit = defineEmits<{
edit: []
preview: []
copy: []
regenerate: []
delete: []
}>()
@@ -135,6 +147,43 @@ function resolveTitle(enabled: boolean, enabledTitle: string, disabledTitle?: st
</span>
</a-tooltip>
<a-tooltip
v-if="showRegenerate && !regenerateConfirmTitle"
:title="resolveTitle(canRegenerate, t('common.regenerate'), regenerateDisabledTitle)"
>
<span>
<a-button
type="text"
shape="circle"
size="small"
class="action-btn action-regenerate"
:disabled="!canRegenerate"
:loading="regenerateLoading"
@click="emit('regenerate')"
>
<ReloadOutlined />
</a-button>
</span>
</a-tooltip>
<a-popconfirm
v-else-if="showRegenerate"
:title="regenerateConfirmTitle"
:disabled="!canRegenerate"
@confirm="emit('regenerate')"
>
<a-button
type="text"
shape="circle"
size="small"
class="action-btn action-regenerate"
:disabled="!canRegenerate"
:loading="regenerateLoading"
>
<ReloadOutlined />
</a-button>
</a-popconfirm>
<a-tooltip
v-if="showDelete && !deleteConfirmTitle"
:title="resolveTitle(canDelete, t('common.delete'), deleteDisabledTitle)"
@@ -195,6 +244,11 @@ function resolveTitle(enabled: boolean, enabledTitle: string, disabledTitle?: st
background: #e6f4ff;
}
.action-regenerate.ant-btn:hover:not(:disabled) {
color: #fa8c16;
background: #fff7e6;
}
.action-delete.ant-btn:hover:not(:disabled) {
color: #ff4d4f;
background: #fff2f0;
@@ -15,6 +15,7 @@ import ArticleSourceMeta from '@/components/ArticleSourceMeta.vue'
import PublishArticleModal from '@/components/PublishArticleModal.vue'
import { articlesApi, promptRulesApi } from '@/lib/api'
import { buildArticleClipboardContent, resolveArticleActionState } from '@/lib/article-list-actions'
import { useArticleRegenerateAction } from '@/lib/article-regenerate-action'
import { getGenerateStatusMeta, getPublishStatusMeta } from '@/lib/display'
import { formatError } from '@/lib/errors'
import { formatPublishPlatformList } from '@/lib/publish-platforms'
@@ -110,6 +111,8 @@ const deleteMutation = useMutation({
onError: (error) => message.error(formatError(error)),
})
const { regeneratingArticleId, handleRegenerate } = useArticleRegenerateAction()
const columns = computed<TableColumnsType<ArticleListItem>>(() => [
{ title: t('custom.article.titleColumn'), dataIndex: 'title', key: 'title', width: 340 },
{
@@ -353,13 +356,16 @@ onBeforeUnmount(() => {
</template>
<template v-else-if="column.key === 'actions'">
<ArticleActionGroup
v-bind="resolveArticleActionState(record.generate_status)"
v-bind="resolveArticleActionState(record)"
:delete-confirm-title="t('templates.list.deleteConfirm')"
:delete-loading="deleteMutation.isPending.value"
:regenerate-confirm-title="t('common.regenerateConfirm')"
:regenerate-loading="regeneratingArticleId === record.id"
@publish="openPublish(record)"
@edit="openEditor(record)"
@preview="openDetail(record)"
@copy="copyArticle(record.id)"
@regenerate="handleRegenerate(record)"
@delete="deleteMutation.mutate(record.id)"
/>
</template>