/**
* 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} 字
`
: '';
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;
},
};