feat(imitation): simplify form fields and make brand_name required
Deployment Config CI / Deployment Config (push) Successful in 25s
Frontend CI / Frontend (push) Successful in 2m51s
Backend CI / Backend (push) Successful in 14m47s

Remove industry, target_audience, content_goal, tone, and length_goal from the imitation form; brand_name is now mandatory with autocomplete from brand library, keywords are pre-populated from the selected brand's search keywords, and output length is hardcoded to ~2000 characters in the prompt.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-20 02:16:45 +08:00
parent c44ddc55a6
commit 00eb514efc
8 changed files with 67 additions and 124 deletions
@@ -1,13 +1,13 @@
<script setup lang="ts">
import { LeftOutlined, LinkOutlined } from '@ant-design/icons-vue'
import { useMutation, useQueryClient } from '@tanstack/vue-query'
import { useMutation, useQuery, useQueryClient } from '@tanstack/vue-query'
import { message } from 'ant-design-vue'
import { computed, reactive, watch } from 'vue'
import { useI18n } from 'vue-i18n'
import { useRoute, useRouter } from 'vue-router'
import KnowledgeGroupSelect from '@/components/KnowledgeGroupSelect.vue'
import { articlesApi } from '@/lib/api'
import { articlesApi, brandsApi } from '@/lib/api'
import { formatError } from '@/lib/errors'
const route = useRoute()
@@ -19,13 +19,8 @@ const form = reactive({
source_url: '',
source_title: '',
locale: 'zh-CN',
industry: '',
brand_name: '',
region: '',
target_audience: '',
content_goal: '',
tone: '',
length_goal: '',
keywords: [] as string[],
preserve_points: '',
avoid_points: '',
@@ -34,8 +29,40 @@ const form = reactive({
knowledge_group_ids: [] as number[],
})
const brandsQuery = useQuery({
queryKey: ['brands'],
queryFn: () => brandsApi.list(),
})
const brandNameOptions = computed(() =>
(brandsQuery.data.value ?? []).map((item) => ({
label: item.name,
value: item.name,
})),
)
const selectedBrand = computed(
() => brandsQuery.data.value?.find((item) => item.name === form.brand_name.trim()) ?? null,
)
const questionsQuery = useQuery({
queryKey: computed(() => ['brands', selectedBrand.value?.id, 'questions', 'imitation']),
enabled: computed(() => Boolean(selectedBrand.value?.id)),
queryFn: () => brandsApi.listQuestions(selectedBrand.value?.id as number),
})
const keywordOptions = computed(() =>
(questionsQuery.data.value ?? []).map((item) => ({
label: item.question_text,
value: item.question_text,
})),
)
const canSubmit = computed(
() => form.source_url.trim().length > 0 && !generateMutation.isPending.value,
() =>
form.source_url.trim().length > 0 &&
form.brand_name.trim().length > 0 &&
!generateMutation.isPending.value,
)
const generateMutation = useMutation({
@@ -44,13 +71,8 @@ const generateMutation = useMutation({
source_url: form.source_url.trim(),
source_title: form.source_title.trim(),
locale: form.locale,
industry: form.industry.trim(),
brand_name: form.brand_name.trim(),
region: form.region.trim(),
target_audience: form.target_audience.trim(),
content_goal: form.content_goal.trim(),
tone: form.tone.trim(),
length_goal: form.length_goal.trim(),
keywords: form.keywords.map((item) => item.trim()).filter(Boolean),
preserve_points: form.preserve_points.trim(),
avoid_points: form.avoid_points.trim(),
@@ -95,6 +117,10 @@ function submit(): void {
message.warning(t('imitation.create.sourceURLRequired'))
return
}
if (!form.brand_name.trim()) {
message.warning(t('imitation.create.brandNameRequired'))
return
}
generateMutation.mutate()
}
</script>
@@ -204,17 +230,11 @@ function submit(): void {
<div class="imitation-generate-page__field-grid">
<div class="imitation-generate-page__field">
<label>{{ t('imitation.create.industry') }}</label>
<a-input
v-model:value="form.industry"
:placeholder="t('imitation.create.industryPlaceholder')"
/>
</div>
<div class="imitation-generate-page__field">
<label>{{ t('imitation.create.brandName') }}</label>
<a-input
<label class="required-asterisk">{{ t('imitation.create.brandName') }}</label>
<a-auto-complete
v-model:value="form.brand_name"
allow-clear
:options="brandNameOptions"
:placeholder="t('imitation.create.brandNamePlaceholder')"
/>
</div>
@@ -227,44 +247,13 @@ function submit(): void {
/>
</div>
<div class="imitation-generate-page__field">
<label>{{ t('imitation.create.targetAudience') }}</label>
<a-input
v-model:value="form.target_audience"
:placeholder="t('imitation.create.targetAudiencePlaceholder')"
/>
</div>
<div class="imitation-generate-page__field">
<label>{{ t('imitation.create.contentGoal') }}</label>
<a-input
v-model:value="form.content_goal"
:placeholder="t('imitation.create.contentGoalPlaceholder')"
/>
</div>
<div class="imitation-generate-page__field">
<label>{{ t('imitation.create.tone') }}</label>
<a-input
v-model:value="form.tone"
:placeholder="t('imitation.create.tonePlaceholder')"
/>
</div>
<div class="imitation-generate-page__field">
<label>{{ t('imitation.create.lengthGoal') }}</label>
<a-input
v-model:value="form.length_goal"
:placeholder="t('imitation.create.lengthGoalPlaceholder')"
/>
</div>
<div class="imitation-generate-page__field imitation-generate-page__field--wide">
<label>{{ t('imitation.create.keywords') }}</label>
<a-select
v-model:value="form.keywords"
mode="tags"
style="width: 100%"
:options="keywordOptions"
:placeholder="t('imitation.create.keywordsPlaceholder')"
/>
</div>