feat(imitation): add article imitation create flow

Introduce 仿写创作: new list and create views, backend imitation service
and prompt templates, worker task routing for imitation jobs, and one-click
rewrite triggers from question citation sources. Surface source article
URL/title on article list/detail, and restrict failed articles to delete-only.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-25 21:36:44 +08:00
parent 46d0a7aea0
commit 40d9a6cc63
29 changed files with 2678 additions and 120 deletions
@@ -1,5 +1,5 @@
<script setup lang="ts">
import { CopyOutlined } from "@ant-design/icons-vue";
import { CopyOutlined, LinkOutlined } from "@ant-design/icons-vue";
import { useQuery, useQueryClient } from "@tanstack/vue-query";
import { message } from "ant-design-vue";
import type { TableColumnsType } from "ant-design-vue";
@@ -122,6 +122,8 @@ const generateMeta = computed(() =>
getGenerateStatusMeta(streamStatus.value || detail.value?.generate_status),
);
const publishMeta = computed(() => getPublishStatusMeta(detail.value?.publish_status));
const sourceArticleTitle = computed(() => detail.value?.source_title?.trim() || "");
const sourceArticleURL = computed(() => detail.value?.source_url?.trim() || "");
function handleClose(): void {
activeTab.value = "content";
@@ -284,6 +286,27 @@ async function copyPublishLink(record: PublishRecord): Promise<void> {
<a-descriptions-item :label="t('article.meta.wordCount')">
{{ detail.word_count || "--" }}
</a-descriptions-item>
<a-descriptions-item
v-if="sourceArticleURL"
:label="t('article.meta.sourceArticle')"
:span="2"
>
<a
class="article-drawer__source-link"
:href="sourceArticleURL"
target="_blank"
rel="noopener noreferrer"
:title="sourceArticleURL"
>
<LinkOutlined />
<span class="article-drawer__source-copy">
<span v-if="sourceArticleTitle" class="article-drawer__source-title">
{{ sourceArticleTitle }}
</span>
<span class="article-drawer__source-url">{{ sourceArticleURL }}</span>
</span>
</a>
</a-descriptions-item>
</a-descriptions>
</section>
@@ -423,6 +446,37 @@ async function copyPublishLink(record: PublishRecord): Promise<void> {
margin-top: 24px;
}
.article-drawer__source-link {
display: inline-flex;
max-width: 100%;
align-items: center;
gap: 6px;
color: #1677ff;
}
.article-drawer__source-copy {
display: flex;
min-width: 0;
flex-direction: column;
gap: 4px;
}
.article-drawer__source-title,
.article-drawer__source-url {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.article-drawer__source-title {
color: #1f2937;
font-weight: 500;
}
.article-drawer__source-url {
color: #1677ff;
}
.article-drawer__alert {
margin-top: 24px;
}