feat(monitoring): match citations by canonical link and scope summary by brand/keyword/platform/date

Replace the domain+title fuzzy alias scoring with a canonical
candidate-key index built from published-link aliases — only exact
matches now resolve to a SaaS source, eliminating false positives
across articles sharing a host (e.g. m.163.com vs www.163.com).

Surface the summary scoping that already existed on loadCitationRanking
/ loadCitedArticles by accepting brand_id, keyword_id, ai_platform_id
and business_date on CitationSummary, plumbing them through the handler
and admin tracking view.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-01 11:46:17 +08:00
parent 2436f50c1f
commit b345ee26e4
10 changed files with 592 additions and 307 deletions
+1 -1
View File
@@ -432,7 +432,7 @@ const enUS = {
backToQuestions: "Back to questions",
citationRanking: "Citation Ranking",
citationRankingTitle: "Citation Ranking",
citationRankingHint: "Attribute SaaS-published content by registrable domain across model citation sources.",
citationRankingHint: "Attribute SaaS-published content by published-link identity across model citation sources.",
citationWindow7: "Last 7 days",
citationWindow30: "Last 30 days",
citationWindowLabel: "Last {days} days",
+1 -1
View File
@@ -433,7 +433,7 @@ const zhCN = {
backToQuestions: "返回问题列表",
citationRanking: "Citation Ranking",
citationRankingTitle: "引用排行",
citationRankingHint: "按主体域名归因 SaaS 发文在模型引用来源中的出现次数与占比。",
citationRankingHint: "按发布外链主体归因 SaaS 发文在模型引用来源中的出现次数与占比。",
citationWindow7: "近 7 天",
citationWindow30: "近 30 天",
citationWindowLabel: "近 {days} 天",
+4
View File
@@ -1078,6 +1078,10 @@ export const monitoringApi = {
},
citationSummary(params: {
days?: number;
brand_id?: number;
keyword_id?: number | null;
business_date?: string;
ai_platform_id?: string;
}) {
return apiClient.get<MonitoringCitationSummaryResponse>("/api/tenant/monitoring/citation-summary", {
params,
@@ -251,10 +251,19 @@ const citationSummaryQuery = useQuery({
queryKey: computed(() => [
"tracking",
"citation-summary",
selectedBrandId.value,
selectedKeywordId.value,
selectedPlatformId.value,
selectedBusinessDate.value,
selectedCitationWindowDays.value,
]),
enabled: computed(() => Boolean(selectedBrandId.value)),
queryFn: () =>
monitoringApi.citationSummary({
brand_id: selectedBrandId.value ?? undefined,
keyword_id: selectedKeywordId.value,
business_date: selectedBusinessDate.value,
ai_platform_id: selectedPlatformId.value !== "all" ? selectedPlatformId.value : undefined,
days: selectedCitationWindowDays.value,
}),
});