/** * history.js — 历史记录页(检索历史 + 对话历史) */ const HistoryPage = { state: { tab: 'chat', // 'chat' 或 'search' chatPage: 1, chatPageSize: 20, chatData: null, searchPage: 1, searchPageSize: 20, searchData: null, loading: false, error: null, detailChat: null, // 查看详情的对话 }, render() { const tab = this.state.tab; return `

历史记录

${this._renderLoading()}
`; }, init() { this.loadList(); }, _renderLoading() { return `
${UI.spinner(20)}加载中...
`; }, setTab(tab) { this.state.tab = tab; this.state.error = null; this.state.detailChat = null; const content = document.getElementById('content'); content.innerHTML = this.render(); this.loadList(); }, async loadList() { this.state.loading = true; this.state.error = null; const el = document.getElementById('history-content'); if (el) el.innerHTML = this._renderLoading(); try { if (this.state.tab === 'chat') { const resp = await API.get(`/api/history/chat?page=${this.state.chatPage}&page_size=${this.state.chatPageSize}`); this.state.chatData = resp.data; } else { const resp = await API.get(`/api/history/search?page=${this.state.searchPage}&page_size=${this.state.searchPageSize}`); this.state.searchData = resp.data; } this.state.loading = false; this.renderList(); } catch (e) { this.state.loading = false; this.state.error = e.message; this.renderList(); } }, renderList() { const el = document.getElementById('history-content'); if (!el) return; if (this.state.error) { el.innerHTML = UI.errorState(this.state.error, 'HistoryPage.loadList()'); return; } if (this.state.tab === 'chat') { el.innerHTML = this._renderChatList(); } else { el.innerHTML = this._renderSearchList(); } }, _renderChatList() { const data = this.state.chatData; if (!data || !data.items || data.items.length === 0) { return UI.emptyState('暂无对话历史', '在智能问答页提问后会自动记录'); } const items = data.items.map(item => { const tplLabel = { simple: '通俗解释', professional: '专业分析', compare: '对比条文' }[item.template] || item.template; const statusBadge = item.status === 'error' ? '错误' : item.status === 'streaming' ? '生成中' : ''; const answerPreview = item.answer ? item.answer.substring(0, 120).replace(/\n/g, ' ') + (item.answer.length > 120 ? '...' : '') : '无答案'; const citationCount = item.citations ? item.citations.length : 0; return `
${item.created_at} ${tplLabel} ${item.thinking_enabled ? 'Thinking' : ''} ${statusBadge} ${citationCount ? `引用 ${citationCount} 条` : ''}
${this._escapeHtml(item.question)}
${this._escapeHtml(answerPreview)}
`; }).join(''); const pagination = UI.pagination( data.page, data.page_size, data.total, 'HistoryPage.changeChatPage' ); return items + pagination; }, _renderSearchList() { const data = this.state.searchData; if (!data || !data.items || data.items.length === 0) { return UI.emptyState('暂无检索历史', '在语义检索页查询后会自动记录'); } const items = data.items.map(item => { const filters = []; if (item.category) filters.push(UI.categoryBadge(item.category)); if (item.province) filters.push(`[${item.province}]`); return `
${item.created_at} ${filters.join('')} ${item.result_count} 条结果
${this._escapeHtml(item.query)}
`; }).join(''); const pagination = UI.pagination( data.page, data.page_size, data.total, 'HistoryPage.changeSearchPage' ); return items + pagination; }, changeChatPage(page) { this.state.chatPage = page; this.loadList(); }, changeSearchPage(page) { this.state.searchPage = page; this.loadList(); }, async viewChat(id) { try { const resp = await API.get(`/api/history/chat/${id}`); this.state.detailChat = resp.data; this._renderChatDetail(); } catch (e) { this.state.error = e.message; this.renderList(); } }, _renderChatDetail() { const chat = this.state.detailChat; if (!chat) return; const tplLabel = { simple: '通俗解释', professional: '专业分析', compare: '对比条文' }[chat.template] || chat.template; const thinkingHtml = chat.thinking ? `
Thinking 思考过程 ${chat.thinking.length} 字
${this._escapeHtml(chat.thinking)}
` : ''; const answerHtml = chat.answer ? `
${marked.parse(chat.answer)}
` : '
无答案
'; const citationsHtml = chat.citations && chat.citations.length ? `
引用条文(${chat.citations.length})
${chat.citations.map(c => UI.clauseCard(c)).join('')}
` : ''; const el = document.getElementById('history-content'); el.innerHTML = `
${chat.created_at} ${tplLabel} ${chat.thinking_enabled ? 'Thinking' : ''}
${this._escapeHtml(chat.question)}
AI 回答
${thinkingHtml} ${answerHtml} ${citationsHtml}
`; }, closeDetail() { this.state.detailChat = null; this.renderList(); }, async deleteChat(id) { if (!confirm('确认删除这条对话历史?')) return; try { await fetch(`/api/history/chat/${id}`, { method: 'DELETE' }); this.loadList(); } catch (e) { alert('删除失败: ' + e.message); } }, async deleteSearch(id) { if (!confirm('确认删除这条检索历史?')) return; try { await fetch(`/api/history/search/${id}`, { method: 'DELETE' }); this.loadList(); } catch (e) { alert('删除失败: ' + e.message); } }, async clearAll() { const type = this.state.tab === 'chat' ? '对话' : '检索'; if (!confirm(`确认清空全部${type}历史?此操作不可恢复。`)) return; try { const url = this.state.tab === 'chat' ? '/api/history/chat' : '/api/history/search'; await fetch(url, { method: 'DELETE' }); this.loadList(); } catch (e) { alert('清空失败: ' + e.message); } }, replaySearch(item) { // 跳转到检索页并填充查询条件 navigate('search'); setTimeout(() => { const input = document.getElementById('search-input'); if (input) input.value = item.query; if (SearchPage.state) { SearchPage.state.query = item.query; SearchPage.state.category = item.category || ''; SearchPage.state.province = item.province || ''; if (item.category) { const sel = document.getElementById('search-category'); if (sel) sel.value = item.category; } if (item.province) { const sel = document.getElementById('search-province'); if (sel) sel.value = item.province; } } // 自动触发检索 if (SearchPage.submit) SearchPage.submit(); }, 100); }, _escapeHtml(text) { if (!text) return ''; const div = document.createElement('div'); div.textContent = text; return div.innerHTML; }, };