Files
AIclinicalresearch/docs/03-业务模块/ASL-AI智能文献/03-UI设计/数据综合分析与报告.html
HaHafeng 8eef9e0544 feat(asl): Complete Week 4 - Results display and Excel export with hybrid solution
Features:
- Backend statistics API (cloud-native Prisma aggregation)
- Results page with hybrid solution (AI consensus + human final decision)
- Excel export (frontend generation, zero disk write, cloud-native)
- PRISMA-style exclusion reason analysis with bar chart
- Batch selection and export (3 export methods)
- Fixed logic contradiction (inclusion does not show exclusion reason)
- Optimized table width (870px, no horizontal scroll)

Components:
- Backend: screeningController.ts - add getProjectStatistics API
- Frontend: ScreeningResults.tsx - complete results page (hybrid solution)
- Frontend: excelExport.ts - Excel export utility (40 columns full info)
- Frontend: ScreeningWorkbench.tsx - add navigation button
- Utils: get-test-projects.mjs - quick test tool

Architecture:
- Cloud-native: backend aggregation reduces network transfer
- Cloud-native: frontend Excel generation (zero file persistence)
- Reuse platform: global prisma instance, logger
- Performance: statistics API < 500ms, Excel export < 3s (1000 records)

Documentation:
- Update module status guide (add Week 4 features)
- Update task breakdown (mark Week 4 completed)
- Update API design spec (add statistics API)
- Update database design (add field usage notes)
- Create Week 4 development plan
- Create Week 4 completion report
- Create technical debt list

Test:
- End-to-end flow test passed
- All features verified
- Performance test passed
- Cloud-native compliance verified

Ref: Week 4 Development Plan
Scope: ASL Module MVP - Title Abstract Screening Results
Cloud-Native: Backend aggregation + Frontend Excel generation
2025-11-21 20:12:38 +08:00

304 lines
19 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>数据综合分析模块原型 V1</title>
<script src="https://cdn.tailwindcss.com"></script>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
<link href="https://cdnjs.cloudflare.com/ajax/libs/heroicons/2.1.3/24/outline/css/heroicons.min.css" rel="stylesheet">
<style>
body { font-family: 'Inter', sans-serif; }
.sidebar { background-color: #f8fafc; transition: width 0.3s ease; }
.sidebar-link.active { background-color: #e0f2fe; color: #0c4a6e; font-weight: 600; }
.main-content { transition: margin-left 0.3s ease; margin-left: 16rem; }
.modal-backdrop { background-color: rgba(0, 0, 0, 0.5); }
.wizard-step { display: none; }
.wizard-step.active { display: block; }
.droppable { background-color: #f9fafb; border: 2px dashed #d1d5db; }
.draggable { cursor: grab; }
.bubble { transition: all 0.3s ease; }
.bubble-chart-cell:hover .bubble { transform: scale(1.2); }
.tooltip { visibility: hidden; opacity: 0; transition: opacity 0.2s; }
.has-tooltip:hover .tooltip { visibility: visible; opacity: 1; }
</style>
</head>
<body class="bg-gray-100 text-gray-800">
<div class="h-screen flex">
<!-- 模拟的左侧主导航 -->
<aside id="sidebar" class="sidebar w-64 border-r border-gray-200 p-4 flex-shrink-0 flex flex-col fixed h-full">
<div class="text-xl font-bold text-gray-800 mb-8 flex items-center space-x-2">
<svg class="h-8 w-8 text-sky-600" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M12 6.042A8.967 8.967 0 0 0 6 3.75c-1.052 0-2.062.18-3 .512v14.25A8.987 8.987 0 0 1 6 18c2.305 0 4.408.867 6 2.292m0-14.25a8.966 8.966 0 0 1 6-2.292c1.052 0-2.062.18-3 .512v14.25A8.987 8.987 0 0 0 18 18a8.967 8.967 0 0 0-6 2.292m0-14.25v14.25" /></svg>
<span class="logo-text">AI文献平台</span>
</div>
<nav class="flex-grow space-y-2">
<a href="#" class="sidebar-link group flex items-center px-3 py-2 text-sm font-medium rounded-md text-gray-700 space-x-3"><i class="h-5 w-5 hi-outline hi-home"></i><span class="sidebar-text">项目概览</span></a>
<a href="#" class="sidebar-link group flex items-center px-3 py-2 text-sm font-medium rounded-md text-gray-700 space-x-3"><i class="h-5 w-5 hi-outline hi-magnifying-glass"></i><span class="sidebar-text">1. 智能文献检索</span></a>
<a href="#" class="sidebar-link group flex items-center px-3 py-2 text-sm font-medium rounded-md text-gray-700 space-x-3"><i class="h-5 w-5 hi-outline hi-beaker"></i><span class="sidebar-text">2. AI辅助初筛</span></a>
<a href="#" class="sidebar-link group flex items-center px-3 py-2 text-sm font-medium rounded-md text-gray-700 space-x-3"><i class="h-5 w-5 hi-outline hi-document-text"></i><span class="sidebar-text">3. 全文解析与数据提取</span></a>
<a href="#" id="nav-analysis-main" class="sidebar-link active group flex items-center px-3 py-2 text-sm font-medium rounded-md text-gray-700 space-x-3"><i class="h-5 w-5 hi-outline hi-chart-pie"></i><span class="sidebar-text">4. 数据综合分析与报告</span></a>
</nav>
</aside>
<!-- 主内容区 -->
<div class="main-content flex-grow flex flex-col w-full">
<header class="bg-white shadow-sm flex-shrink-0 z-10 p-4 border-b"><h1 id="header-title" class="text-xl font-bold">数据综合分析与报告生成</h1></header>
<div id="view-container" class="flex-grow p-6 overflow-auto">
<!-- 视图1: 应用选择中心 -->
<div id="hub-view">
<h2 class="text-3xl font-bold mb-6">应用选择中心</h2>
<p class="text-gray-600 mb-8">请选择您希望进行的分析应用。数据将自动从“全文解析与数据提取”模块导入。</p>
<div class="grid grid-cols-1 md:grid-cols-3 gap-8">
<div class="bg-white p-8 rounded-lg shadow hover:shadow-xl transition-shadow cursor-pointer" onclick="startWizard()">
<h3 class="font-bold text-xl mb-3 text-sky-700">证据图谱生成</h3>
<p class="text-sm text-gray-600 mb-4">通过可视化矩阵,直观展示研究领域的证据分布,快速识别研究热点与证据空白。</p>
<span class="font-semibold text-sky-600">开始分析 →</span>
</div>
<div class="bg-white p-8 rounded-lg shadow hover:shadow-xl transition-shadow cursor-pointer opacity-50">
<h3 class="font-bold text-xl mb-3">Meta分析数据准备</h3>
<p class="text-sm text-gray-600 mb-4">为RevMan, Stata等专业统计软件准备和导出格式化、可直接使用的数据文件。</p>
<span class="font-semibold text-gray-500">即将推出</span>
</div>
<div class="bg-white p-8 rounded-lg shadow hover:shadow-xl transition-shadow cursor-pointer opacity-50">
<h3 class="font-bold text-xl mb-3">药物综合评价报告</h3>
<p class="text-sm text-gray-600 mb-4">基于模板,一键生成包含有效性、安全性等多维度的综合评价报告初稿。</p>
<span class="font-semibold text-gray-500">即将推出</span>
</div>
</div>
</div>
<!-- 视图2: 配置向导 -->
<div id="wizard-view" class="hidden">
<div class="max-w-4xl mx-auto bg-white p-8 rounded-lg shadow">
<h2 class="text-2xl font-bold mb-2">证据图谱框架配置向导</h2>
<p class="text-gray-500 mb-6">请按照步骤定义图谱的框架,以便系统为您生成可视化结果。</p>
<!-- Steps -->
<div id="wizard-step-1" class="wizard-step active">
<h3 class="text-lg font-semibold mb-4">步骤 1/3: 定义Y轴 (干预措施)</h3>
<p class="text-sm text-gray-600 mb-4">请将左侧提取的干预措施拖拽或分配到右侧的分组中。</p>
<div class="grid grid-cols-2 gap-4 h-96">
<div class="border rounded p-4">
<h4 class="font-semibold mb-2">可用的干预措施</h4>
<div id="available-interventions" class="space-y-2 text-sm">
<div class="draggable bg-gray-100 p-2 rounded">Drug-X</div><div class="draggable bg-gray-100 p-2 rounded">Drug-Y</div><div class="draggable bg-gray-100 p-2 rounded">安慰剂</div>
</div>
</div>
<div class="droppable rounded p-4">
<h4 class="font-semibold mb-2">干预措施分组</h4>
<div class="p-2 bg-white border rounded mb-2"><strong>分组1:</strong> Drug-X, Drug-Y <button class="text-xs text-sky-600 ml-2">重命名</button></div>
<div class="p-2 bg-white border rounded"><strong>分组2:</strong> 安慰剂 <button class="text-xs text-sky-600 ml-2">重命名</button></div>
</div>
</div>
</div>
<div id="wizard-step-2" class="wizard-step">
<h3 class="text-lg font-semibold mb-4">步骤 2/3: 定义X轴 (结局指标)</h3>
<p class="text-sm text-gray-600 mb-4">请将左侧提取的结局指标拖拽或分配到右侧的分组中。</p>
<!-- Simplified for demo -->
<p class="p-4 bg-gray-50 rounded">此步骤与上一步类似,用户可对“糖化血红蛋白”、“不良事件”等结局指标进行分组。</p>
</div>
<div id="wizard-step-3" class="wizard-step">
<h3 class="text-lg font-semibold mb-4">步骤 3/3: 配置气泡含义</h3>
<p class="text-sm text-gray-600 mb-4">请选择气泡颜色所代表的维度。气泡大小固定代表研究数量。</p>
<div class="space-y-3">
<label class="flex items-center p-4 border rounded-lg cursor-pointer"><input type="radio" name="bubble-color" class="mr-3" checked>研究质量/偏倚风险</label>
<label class="flex items-center p-4 border rounded-lg cursor-pointer"><input type="radio" name="bubble-color" class="mr-3">研究设计</label>
</div>
</div>
<!-- Navigation -->
<div class="mt-8 flex justify-between">
<button id="wizard-prev" onclick="navigateWizard(-1)" class="bg-gray-300 hover:bg-gray-400 text-gray-800 font-bold py-2 px-4 rounded">上一步</button>
<button id="wizard-next" onclick="navigateWizard(1)" class="bg-sky-600 hover:bg-sky-700 text-white font-bold py-2 px-4 rounded">下一步</button>
<button id="wizard-finish" onclick="finishWizard()" class="hidden bg-green-600 hover:bg-green-700 text-white font-bold py-2 px-4 rounded">生成证据图谱</button>
</div>
</div>
</div>
<!-- 视图3: 分析仪表盘 -->
<div id="dashboard-view" class="hidden h-full flex flex-col">
<div class="flex-shrink-0 flex justify-between items-center mb-4">
<h2 class="text-2xl font-bold">交互式分析仪表盘</h2>
<button onclick="showView('report')" class="bg-green-600 hover:bg-green-700 text-white font-bold py-2 px-6 rounded-lg shadow">生成完整报告</button>
</div>
<div class="flex-grow flex space-x-6 overflow-hidden">
<!-- Left Panel -->
<aside class="w-1/4 bg-white rounded-lg shadow p-6 overflow-y-auto">
<h3 class="text-lg font-bold mb-4">动态筛选器</h3>
<!-- Filters -->
<div class="space-y-4 text-sm">
<div><label class="font-semibold">发表年份:</label><input type="range" class="w-full mt-1"></div>
<div><label class="font-semibold">研究设计:</label><div class="mt-1 space-y-1"><label class="flex items-center"><input type="checkbox" checked class="mr-2">RCT</label><label class="flex items-center"><input type="checkbox" checked class="mr-2">队列研究</label></div></div>
</div>
<hr class="my-6">
<h3 class="text-lg font-bold mb-4">AI洞察摘要</h3>
<div class="text-sm text-gray-700 space-y-3 bg-gray-50 p-4 rounded-lg">
<p><strong>证据热点:</strong> 研究证据主要集中在Drug-X糖化血红蛋白的影响上。</p>
<p><strong>证据空白:</strong>Drug-Y不良事件交叉领域缺少高质量研究。</p>
</div>
</aside>
<!-- Main Panel -->
<main class="w-3/4 flex flex-col space-y-6 overflow-y-auto">
<div class="bg-white rounded-lg shadow p-6">
<h3 class="text-xl font-bold mb-4">证据图谱</h3>
<div id="bubble-chart-container" class="border rounded-lg p-4"></div>
</div>
<div class="bg-white rounded-lg shadow p-6">
<h3 class="text-xl font-bold mb-4">描述性统计</h3>
<p class="text-sm text-gray-600">本次分析共纳入50项研究其中60% (30项) 为随机对照试验 (RCT)...</p>
</div>
</main>
</div>
</div>
<!-- 视图4: 报告编辑器 -->
<div id="report-view" class="hidden">
<div class="flex justify-between items-center mb-4">
<h2 class="text-2xl font-bold">智能报告编辑器</h2>
<div>
<button onclick="showView('dashboard')" class="bg-gray-300 hover:bg-gray-400 text-gray-800 font-bold py-2 px-4 rounded mr-2">返回仪表盘</button>
<button class="bg-sky-600 hover:bg-sky-700 text-white font-bold py-2 px-4 rounded">导出为 Word</button>
</div>
</div>
<div class="bg-white p-12 rounded-lg shadow prose max-w-none">
<h1>XX药物治疗XX疾病的证据图谱分析报告</h1>
<p class="text-gray-500">生成日期: 2025-10-22</p>
<h2>摘要</h2>
<p>本报告旨在通过证据图谱方法系统性梳理XX药物治疗XX疾病的现有研究证据。分析共纳入50项研究结果表明研究热点主要集中于... 同时,我们发现...领域存在显著的证据空白,提示这是未来需要重点投入的研究方向。</p>
<h2>方法</h2>
<p>我们遵循系统评价流程... 最终纳入50篇文献进行分析。证据图谱的干预措施维度包括... 结局指标维度包括...</p>
<h2>结果</h2>
<h3>纳入研究的描述性统计</h3>
<p>如图1所示本次分析共纳入50项研究。其中随机对照试验RCT是主要的研究类型占总数的60%30项其次是队列研究25%12项...</p>
<h3>证据图谱可视化与解读</h3>
<p>证据图谱图2显示研究证据主要集中在抗血小板药物主要心血管不良事件(MACE)’的影响上...</p>
<figure>
<div class="border rounded-lg p-4 bg-gray-50 text-center text-gray-500">[此处为证据图谱图片]</div>
<figcaption>图2: 证据图谱可视化</figcaption>
</figure>
<h4>证据空白分析</h4>
<p>图谱也揭示了显著的证据空白。特别是在‘新一代抗凝药’与‘出血风险’这一关键领域的直接对比研究非常稀少...</p>
<h2>结论</h2>
<p>...</p>
<h2>附录</h2>
<p>...</p>
</div>
</div>
</div>
</div>
</div>
<script>
// --- STATE MANAGEMENT ---
let currentView = 'hub';
let wizardStep = 1;
// --- DOM ELEMENTS ---
const views = {
hub: document.getElementById('hub-view'),
wizard: document.getElementById('wizard-view'),
dashboard: document.getElementById('dashboard-view'),
report: document.getElementById('report-view')
};
const headerTitle = document.getElementById('header-title');
// --- NAVIGATION ---
function showView(view) {
currentView = view;
Object.values(views).forEach(v => v.classList.add('hidden'));
views[view].classList.remove('hidden');
const titles = {
hub: '数据综合分析与报告生成',
wizard: '证据图谱配置向导',
dashboard: '交互式分析仪表盘',
report: '智能报告编辑器'
};
headerTitle.textContent = titles[view];
}
function startWizard() {
wizardStep = 1;
updateWizardView();
showView('wizard');
}
function navigateWizard(direction) {
wizardStep += direction;
updateWizardView();
}
function updateWizardView() {
document.querySelectorAll('.wizard-step').forEach(step => step.classList.remove('active'));
document.getElementById(`wizard-step-${wizardStep}`).classList.add('active');
document.getElementById('wizard-prev').style.visibility = wizardStep === 1 ? 'hidden' : 'visible';
document.getElementById('wizard-next').style.display = wizardStep === 3 ? 'none' : 'block';
document.getElementById('wizard-finish').style.display = wizardStep === 3 ? 'block' : 'none';
}
function finishWizard() {
renderBubbleChart();
showView('dashboard');
}
// --- DASHBOARD: BUBBLE CHART ---
function renderBubbleChart() {
const container = document.getElementById('bubble-chart-container');
const interventions = ['Drug-X', 'Drug-Y', '安慰剂'];
const outcomes = ['糖化血红蛋白', '不良事件', 'MACE'];
// Simulated data
const data = [
[15, 2, 8],
[5, 1, 3],
[12, 10, 11]
];
const quality = [
['green', 'red', 'yellow'],
['yellow', 'red', 'green'],
['green', 'green', 'yellow']
];
let tableHTML = `<table class="w-full border-collapse"><thead><tr><th class="border p-2"></th>`;
outcomes.forEach(o => tableHTML += `<th class="border p-2 text-sm font-semibold">${o}</th>`);
tableHTML += `</tr></thead><tbody>`;
interventions.forEach((inter, i) => {
tableHTML += `<tr><td class="border p-2 text-sm font-semibold text-right">${inter}</td>`;
outcomes.forEach((outc, j) => {
const count = data[i][j];
const size = count * 3 + 10; // Simple size mapping
const color = quality[i][j];
const colorClass = {green: 'bg-green-500', yellow: 'bg-yellow-400', red: 'bg-red-500'}[color];
tableHTML += `
<td class="border p-2 h-24 w-24 text-center bubble-chart-cell has-tooltip relative">
${count > 0 ? `
<div class="bubble w-12 h-12 rounded-full mx-auto flex items-center justify-center text-white font-bold ${colorClass}" style="width:${size}px; height:${size}px;">
${count}
</div>
<div class="tooltip absolute z-10 -mt-24 w-48 bg-gray-800 text-white text-xs rounded py-1 px-2 text-left">
<strong>${inter} vs ${outc}</strong><br>
研究数量: ${count}<br>
质量: ${color === 'green' ? '高' : '中'}
</div>` : ''}
</td>`;
});
tableHTML += `</tr>`;
});
tableHTML += `</tbody></table>`;
container.innerHTML = tableHTML;
}
// Initial view
showView('hub');
</script>
</body>
</html>