feat: paginate and search brand questions across selects
Make GET /api/tenant/brands/:id/questions return a paginated QuestionListResponse (items/total/page/page_size) with optional `q` full-text filter, validated page/page_size query params, and per-params cache keys. Add a usePaginatedBrandQuestions composable backing the imitation, template-wizard, and tracking question selects with search-as-you-type and infinite scroll, plus ensure-loaded-by-id so a deep-linked or pre-selected question is fetched even when off the first page. Brands view now drives its questions table via server pagination. Also redesign the Tracking hot-questions and cited-articles lists (mention-rate badges/bars, metric groups, refreshed styling) and fall back to citation-fact article_id/title when no high-confidence URL alias matches, so cited articles surface even without an alias row. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -7,8 +7,9 @@ import { useI18n } from 'vue-i18n'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
|
||||
import KnowledgeGroupSelect from '@/components/KnowledgeGroupSelect.vue'
|
||||
import { articlesApi, brandsApi } from '@/lib/api'
|
||||
import { articlesApi } from '@/lib/api'
|
||||
import { formatError } from '@/lib/errors'
|
||||
import { usePaginatedBrandQuestions } from '@/lib/use-paginated-brand-questions'
|
||||
import { useCompanyStore } from '@/stores/company'
|
||||
|
||||
const route = useRoute()
|
||||
@@ -34,14 +35,10 @@ const selectedBrand = computed(() => companyStore.currentBrand)
|
||||
const selectedBrandId = computed(() => selectedBrand.value?.id ?? null)
|
||||
const currentBrandName = computed(() => selectedBrand.value?.name?.trim() || '')
|
||||
|
||||
const questionsQuery = useQuery({
|
||||
queryKey: computed(() => ['brands', selectedBrandId.value, 'questions', 'imitation']),
|
||||
enabled: computed(() => Boolean(selectedBrandId.value)),
|
||||
queryFn: () => brandsApi.listQuestions(selectedBrandId.value as number),
|
||||
})
|
||||
const questionList = usePaginatedBrandQuestions(selectedBrandId)
|
||||
|
||||
const keywordOptions = computed(() =>
|
||||
(questionsQuery.data.value ?? []).map((item) => ({
|
||||
questionList.items.value.map((item) => ({
|
||||
label: item.question_text,
|
||||
value: item.question_text,
|
||||
})),
|
||||
@@ -239,9 +236,14 @@ function submit(): void {
|
||||
<a-select
|
||||
v-model:value="form.keywords"
|
||||
mode="tags"
|
||||
show-search
|
||||
style="width: 100%"
|
||||
:filter-option="false"
|
||||
:loading="questionList.loading.value"
|
||||
:options="keywordOptions"
|
||||
:placeholder="t('imitation.create.keywordsPlaceholder')"
|
||||
@search="questionList.search"
|
||||
@popup-scroll="questionList.handlePopupScroll"
|
||||
/>
|
||||
</div>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user