// app/static/js/research-tree.js
function renderTree(session, outline) {
const container = document.getElementById('treeContainer');
if (!container) {
console.error('Tree container not found!');
return;
}
container.innerHTML = '';
// 根节点 - 始终显示
const rootNode = document.createElement('div');
rootNode.className = 'root-node';
rootNode.innerHTML = `
${session.question || '研究问题'}
状态:${getStatusText(session.status)} |
开始时间:${new Date(session.created_at).toLocaleString()}
${session.error_message ? `错误: ${session.error_message}
` : ''}
`;
container.appendChild(rootNode);
// 如果出错,显示错误信息
if (session.status === 'error') {
const errorNode = createTreeNode('研究出现错误', 'error');
container.appendChild(wrapInTreeNode(errorNode));
return;
}
// 研究准备节点
const prepNode = createTreeNode('研究准备', session.refined_questions ? 'completed' : session.status);
prepNode.onclick = () => showDetail('preparation', session);
if (session.refined_questions) {
const content = document.createElement('div');
content.className = 'node-content expanded';
content.innerHTML = `
🎯 问题细化
${session.refined_questions.map(q => `- • ${q}
`).join('')}
`;
prepNode.querySelector('.node-card').appendChild(content);
}
container.appendChild(wrapInTreeNode(prepNode));
// 大纲节点
if (outline) {
const outlineNode = createTreeNode('研究大纲', 'completed');
const outlineContent = document.createElement('div');
outlineContent.className = 'node-content expanded';
outlineContent.innerHTML = `
📋 主要研究问题
${outline.research_questions.map(q => `- • ${q}
`).join('')}
`;
outlineNode.querySelector('.node-card').appendChild(outlineContent);
const outlineWrapper = wrapInTreeNode(outlineNode);
container.appendChild(outlineWrapper);
// 子主题节点
outline.sub_topics.forEach((subtopic, idx) => {
const subtopicNode = createSubtopicNode(subtopic, idx + 1);
outlineWrapper.appendChild(wrapInTreeNode(subtopicNode, true));
});
} else {
// 显示大纲创建中或失败
const outlineStatus = session.status === 'outlining' ? 'processing' :
session.status === 'error' ? 'error' : 'pending';
const outlineNode = createTreeNode('研究大纲', outlineStatus);
container.appendChild(wrapInTreeNode(outlineNode));
}
// 最终报告节点
const reportNode = createTreeNode('研究报告生成', session.final_report ? 'completed' : 'pending');
container.appendChild(wrapInTreeNode(reportNode));
}
function createTreeNode(title, status) {
const node = document.createElement('div');
const statusInfo = getStatusInfo(status);
node.innerHTML = `
`;
return node;
}
function createSubtopicNode(subtopic, index) {
const node = document.createElement('div');
const statusInfo = getStatusInfo(subtopic.status);
node.innerHTML = `
`;
return node;
}
function wrapInTreeNode(node, isSubtopic = false) {
const wrapper = document.createElement('div');
wrapper.className = 'tree-node' + (isSubtopic ? ' subtopic-node' : '');
wrapper.appendChild(node);
return wrapper;
}
function getStatusInfo(status) {
const statusMap = {
'pending': { icon: '○', className: 'pending' },
'analyzing': { icon: '●', className: 'processing' },
'outlining': { icon: '●', className: 'processing' },
'researching': { icon: '●', className: 'processing' },
'writing': { icon: '●', className: 'processing' },
'reviewing': { icon: '●', className: 'processing' },
'completed': { icon: '✓', className: 'completed' },
'error': { icon: '✗', className: 'error' },
'cancelled': { icon: '⊘', className: 'cancelled' }
};
return statusMap[status] || statusMap['pending'];
}