feat: 每日热点问题共享库(定时生成+管理员手动更新+点击埋点)
CI / 后端测试 (push) Has been cancelled
CI / 前端构建 (push) Has been cancelled

数据库:
- daily_topics表:每天每场景一条热点问题记录
- sample_clicks表:记录用户点击示例问题行为

后端:
- DailyTopicStore: CRUD + 埋点 + 点击统计
- generate_daily_topics: AI生成4场景各25-30个问题
- 定时任务:每天凌晨3点自动生成(后台线程轮询)
- GET /topics/daily: 获取当天热点(公开)
- POST /topics/click: 点击埋点
- GET /admin/daily-topics: 管理端查看
- POST /admin/daily-topics: 管理员手动更新
- POST /admin/daily-topics/generate: 手动触发AI生成
- GET /admin/sample-clicks: 点击统计

前端:
- ChatPanel挂载时取当天热点,无则用硬编码兜底
- 点击示例问题时记录埋点
- AdminDailyTopics管理页面:查看/编辑/手动生成
- 路由 /admin/daily-topics + 导航配置

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
selfrelease
2026-08-31 17:04:33 +08:00
co-authored by Devin
parent 35cc6e54ea
commit a7ef530841
9 changed files with 638 additions and 3 deletions
+26
View File
@@ -240,6 +240,32 @@ export const api = {
method: 'POST', body: JSON.stringify({ scene, topic, existing }),
}),
// ===== 每日热点问题 =====
getDailyTopics: (scene: Scene) =>
request<{ scene: string; questions: string[] }>(`/topics/daily?scene=${scene}`),
recordSampleClick: (scene: Scene, question: string) =>
request<{ recorded: boolean }>('/topics/click', {
method: 'POST', body: JSON.stringify({ scene, question }),
}),
// ===== 管理端:热点问题 =====
adminGetDailyTopics: (date?: string) =>
request<{ results: Array<{ id: number; date: string; scene: string; questions: string[]; source: string; created_at: string }> }>(
`/admin/daily-topics${date ? `?date=${date}` : ''}`,
),
adminUpdateDailyTopics: (data: { scene: string; questions: string[]; date?: string }) =>
request<{ updated: boolean; topic: { id: number; date: string; scene: string; questions: string[]; source: string } }>(
'/admin/daily-topics', { method: 'POST', body: JSON.stringify(data) },
),
adminGenerateDailyTopics: () =>
request<{ generated: boolean; results: Record<string, { count: number; source: string; error?: string }> }>(
'/admin/daily-topics/generate', { method: 'POST' },
),
adminSampleClickStats: (days = 14) =>
request<{ results: Array<{ scene: string; question: string; clicks: number }> }>(
`/admin/sample-clicks?days=${days}`,
),
// ===== 知识库 =====
addKnowledge: (data: { title: string; content: string; source?: string; doc_type?: string; region?: string | null; effective_date?: string | null; keywords?: string | null }) =>
request<KnowledgeDoc>('/knowledge', { method: 'POST', body: JSON.stringify(data) }),