Files
HaHafeng 31b0433195 docs(iit): Add CRA Agent V3.0 development plan and update module status guide
V3.0 Plan:
- Finalize CRA Agent V3.0 development plan (replace CRA positioning)
- Add unified CRA QC platform PRD
- Add HTML UI prototype (dashboard, AI stream, eQuery, reports)
- Architecture: report-driven + LLM Tool Use + 4 semantic tools

Module Status Update:
- Update architecture from dual-brain V2.9.1 to V3.0 Tool Use
- Update DB schema inventory (5 tables -> 18 tables)
- Update code stats (577 lines -> 15,000+ lines / 61 files)
- Update next steps to V3.0 P0 roadmap
- Archive old phase plans (ReAct engine, IntentService)
- Add V3.0 document references (plan, PRD, prototype)

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-25 22:04:00 +08:00

743 lines
50 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>统一数字 CRA 质控平台 - 终极版</title>
<script src="https://cdn.tailwindcss.com"></script>
<script src="https://unpkg.com/@phosphor-icons/web"></script>
<style>
.no-scrollbar::-webkit-scrollbar { display: none; }
.no-scrollbar { -ms-overflow-style: none; scrollbar-width: none; }
.dash-border { background-image: url("data:image/svg+xml,%3csvg width='100%25' height='100%25' xmlns='http://www.w3.org/2000/svg'%3e%3crect width='100%25' height='100%25' fill='none' rx='8' ry='8' stroke='%2394A3B8FF' stroke-width='2' stroke-dasharray='8%2c 8' stroke-dashoffset='0' stroke-linecap='square'/%3e%3c/svg%3e"); border-radius: 8px; }
.dash-border:hover { background-image: url("data:image/svg+xml,%3csvg width='100%25' height='100%25' xmlns='http://www.w3.org/2000/svg'%3e%3crect width='100%25' height='100%25' fill='none' rx='8' ry='8' stroke='%233B82F6FF' stroke-width='2' stroke-dasharray='8%2c 8' stroke-dashoffset='0' stroke-linecap='square'/%3e%3c/svg%3e"); }
/* Timeline line styling */
.timeline-line::before {
content: ''; position: absolute; top: 24px; bottom: -24px; left: 15px; width: 2px; background-color: #e2e8f0; z-index: 0;
}
.timeline-item:last-child .timeline-line::before { display: none; }
</style>
</head>
<body class="flex h-screen w-full bg-slate-50 text-slate-800 font-sans overflow-hidden">
<!-- 1. 统一左侧导航栏 -->
<aside class="w-64 bg-slate-900 text-slate-300 flex flex-col transition-all duration-300 shrink-0">
<div class="h-16 flex items-center px-6 border-b border-slate-800 bg-slate-950">
<i class="ph-fill ph-robot text-2xl text-blue-500 mr-2"></i>
<span class="font-bold text-lg text-white tracking-wide">AI 监查系统</span>
</div>
<div class="p-4">
<p class="text-[10px] font-bold text-slate-500 uppercase tracking-widest mb-2">当前监控项目</p>
<div class="bg-slate-800 rounded-lg p-3 border border-slate-700 shadow-inner">
<h3 class="text-sm font-bold text-white mb-1 leading-tight">IIT-2026-001</h3>
<p class="text-xs text-slate-400 leading-tight">非小细胞肺癌真实世界研究</p>
</div>
</div>
<!-- 统一视角的导航菜单 -->
<nav class="flex-1 px-3 py-4 space-y-1 overflow-y-auto">
<p class="text-[10px] font-bold text-slate-500 uppercase tracking-widest px-3 mb-2">全局与宏观概览</p>
<a href="#" onclick="switchView('dashboard')" id="nav-dashboard" class="flex items-center px-3 py-2.5 rounded-md group transition-colors bg-blue-600/20 text-blue-400">
<i class="ph ph-presentation-chart text-xl mr-3 opacity-70 group-hover:opacity-100"></i>
<span class="font-medium text-sm">项目健康度大盘</span>
</a>
<a href="#" onclick="switchView('reports')" id="nav-reports" class="flex items-center px-3 py-2.5 rounded-md text-slate-400 group hover:bg-slate-800 hover:text-white transition-colors">
<i class="ph ph-files text-xl mr-3 opacity-70 group-hover:opacity-100"></i>
<span class="font-medium text-sm">定期报告与关键事件</span>
</a>
<p class="text-[10px] font-bold text-slate-500 uppercase tracking-widest px-3 mb-2 mt-6">AI 监查过程与细节</p>
<a href="#" onclick="switchView('ai-stream')" id="nav-ai-stream" class="flex items-center px-3 py-2.5 rounded-md text-slate-400 group hover:bg-slate-800 hover:text-white transition-colors">
<i class="ph ph-activity text-xl mr-3 opacity-70 group-hover:opacity-100"></i>
<span class="font-medium text-sm">AI 实时工作流水</span>
<span class="ml-auto flex h-2 w-2 relative">
<span class="animate-ping absolute inline-flex h-full w-full rounded-full bg-emerald-400 opacity-75"></span>
<span class="relative inline-flex rounded-full h-2 w-2 bg-emerald-500"></span>
</span>
</a>
<p class="text-[10px] font-bold text-slate-500 uppercase tracking-widest px-3 mb-2 mt-6">人工介入与协作</p>
<a href="#" onclick="switchView('equery')" id="nav-equery" class="flex items-center px-3 py-2.5 rounded-md text-slate-400 group hover:bg-slate-800 hover:text-white transition-colors">
<i class="ph ph-list-checks text-xl mr-3 opacity-70 group-hover:opacity-100"></i>
<span class="font-medium text-sm">待处理电子质疑 (eQuery)</span>
<span class="ml-auto bg-red-500 text-white py-0.5 px-2 rounded-full text-[10px] font-bold shadow-sm">3</span>
</a>
</nav>
<div class="p-4 border-t border-slate-800 text-xs text-slate-500 flex items-center">
<i class="ph-fill ph-check-circle text-emerald-500 mr-2"></i> 系统统一视图,全员可见
</div>
</aside>
<!-- 2. 主内容区域 -->
<main class="flex-1 flex flex-col min-w-0 overflow-hidden relative">
<!-- 顶部 Header -->
<header class="h-16 bg-white border-b border-slate-200 flex items-center justify-between px-6 shrink-0 z-10">
<div class="flex items-center">
<button id="btn-back" onclick="switchView('equery')" class="hidden mr-4 p-1.5 rounded-md hover:bg-slate-100 text-slate-500 transition-colors">
<i class="ph ph-arrow-left text-xl"></i>
</button>
<h1 id="header-title" class="text-xl font-bold text-slate-800">项目健康度大盘</h1>
</div>
<div class="flex items-center space-x-4">
<div class="flex items-center px-3 py-1.5 bg-slate-50 border border-slate-200 rounded-full">
<i class="ph-fill ph-plugs-connected text-emerald-500 mr-2"></i>
<span class="text-xs font-medium text-slate-600">EDC 实时直连中</span>
</div>
<button onclick="toggleCopilot()" id="btn-copilot-toggle" class="p-2 rounded-md transition-colors bg-blue-50 text-blue-600 hover:bg-blue-100" title="呼叫 AI 助理">
<i class="ph-fill ph-sparkle text-xl"></i>
</button>
</div>
</header>
<!-- ================= 视图 A全局大盘 (Dashboard) ================= -->
<div id="view-dashboard" class="flex-1 overflow-y-auto p-6 bg-slate-50/50 block">
<div class="mb-6 flex justify-between items-end">
<div>
<h2 class="text-2xl font-bold text-slate-800">全局监查态势</h2>
<p class="text-sm text-slate-500 mt-1">从宏观趋势到底层患者明细,掌握项目全维度数据质量</p>
</div>
</div>
<!-- 1. 宏观数据卡片 -->
<div class="grid grid-cols-4 gap-4 mb-8">
<div class="bg-white rounded-xl border border-slate-200 p-5 shadow-sm relative overflow-hidden">
<div class="absolute top-0 right-0 w-24 h-24 bg-emerald-100 rounded-full -mr-8 -mt-8 opacity-50"></div>
<div class="flex items-center text-slate-500 mb-2 relative z-10">
<span class="text-sm font-bold">整体数据合规率</span>
</div>
<div class="text-3xl font-black text-emerald-600 relative z-10">96.8%</div>
<div class="text-xs text-emerald-600 mt-2 font-medium">↑ 较上周提升 1.2%</div>
</div>
<div class="bg-white rounded-xl border border-slate-200 p-5 shadow-sm cursor-pointer hover:border-blue-400 transition-colors" onclick="switchView('equery')">
<div class="flex items-center text-slate-500 mb-2">
<span class="text-sm font-bold">待处理违规 (eQuery)</span>
<i class="ph-bold ph-arrow-up-right ml-auto text-blue-500"></i>
</div>
<div class="text-3xl font-black text-red-600">3</div>
<div class="text-xs text-red-500 mt-2 font-medium">包含 1 项重大时序冲突</div>
</div>
<div class="bg-white rounded-xl border border-slate-200 p-5 shadow-sm cursor-pointer hover:border-blue-400 transition-colors" onclick="switchView('ai-stream')">
<div class="flex items-center text-slate-500 mb-2">
<span class="text-sm font-bold">AI 今日审查表单数</span>
<i class="ph-bold ph-arrow-up-right ml-auto text-blue-500"></i>
</div>
<div class="text-3xl font-black text-slate-800">142</div>
<div class="text-xs text-slate-500 mt-2">100% 自动化,无需人工参与</div>
</div>
<div class="bg-gradient-to-br from-slate-800 to-slate-900 rounded-xl border border-slate-700 p-5 shadow-sm text-white cursor-pointer hover:from-slate-700 hover:to-slate-800 transition-colors" onclick="switchView('reports')">
<div class="flex items-center text-slate-300 mb-2">
<span class="text-sm font-bold">累计关键事件 (AE/PD)</span>
<i class="ph-bold ph-arrow-up-right ml-auto text-blue-300"></i>
</div>
<div class="text-3xl font-black text-white">12 <span class="text-sm text-slate-400 font-normal"></span></div>
<div class="text-xs text-blue-300 mt-2">已沉淀至定期质控报告</div>
</div>
</div>
<!-- 2. 微观状态底座:项目风险热力图 (引入患者维度真实质控情况) -->
<div class="bg-white rounded-xl border border-slate-200 shadow-sm mb-8 relative overflow-hidden">
<div class="px-6 py-4 border-b border-slate-200 flex justify-between items-center bg-slate-50/50">
<h2 class="text-base font-bold text-slate-800 flex items-center">
<i class="ph-fill ph-squares-four text-blue-500 mr-2 text-lg"></i>
当前入组患者最新质控状态 (受试者 × 表单矩阵)
</h2>
<div class="flex items-center text-xs text-slate-500 space-x-4">
<span class="flex items-center"><div class="w-3 h-3 rounded-sm bg-red-500 border border-red-600 mr-1"></div>异常/质疑中</span>
<span class="flex items-center"><div class="w-3 h-3 rounded-sm bg-yellow-400 border border-yellow-500 mr-1"></div>逻辑存疑</span>
<span class="flex items-center"><div class="w-3 h-3 rounded-sm bg-emerald-50 border border-emerald-200 mr-1"></div>AI 质控通过</span>
</div>
</div>
<div class="p-6 overflow-x-auto">
<table class="w-full text-sm text-left">
<thead>
<tr>
<th class="pb-3 pr-4 font-bold text-slate-500 w-32 border-b border-slate-200">受试者编号</th>
<th class="pb-3 px-2 font-bold text-slate-500 text-center border-b border-slate-200">知情同意</th>
<th class="pb-3 px-2 font-bold text-slate-500 text-center border-b border-slate-200">入选标准</th>
<th class="pb-3 px-2 font-bold text-slate-500 text-center border-b border-slate-200">实验室检查</th>
<th class="pb-3 px-2 font-bold text-slate-500 text-center border-b border-slate-200">不良事件 (AE)</th>
<th class="pb-3 px-2 font-bold text-slate-500 text-center border-b border-slate-200">随访记录</th>
</tr>
</thead>
<tbody id="heatmap-body">
<!-- JS 动态渲染热力图 -->
</tbody>
</table>
</div>
<div class="px-6 py-3 border-t border-slate-100 bg-slate-50 text-xs text-slate-500 flex justify-between items-center">
<span>* 矩阵实时反映 REDCap 最新录入与 AI 验证结果。点击红色高亮色块可直接进入 eQuery 处理中心。</span>
<button class="text-blue-600 font-bold hover:underline">查看全部 45 名患者</button>
</div>
</div>
<!-- 3. 近期概览 (事件预警 & 质量评级) -->
<div class="grid grid-cols-2 gap-6">
<!-- 近期高亮事件 -->
<div class="bg-white rounded-xl border border-slate-200 shadow-sm">
<div class="px-6 py-4 border-b border-slate-200 flex justify-between items-center">
<h2 class="text-base font-bold text-slate-800 flex items-center">
<i class="ph-fill ph-warning-circle text-yellow-500 mr-2 text-lg"></i>
近期关键事件预警 (AE/PD)
</h2>
</div>
<div class="p-0">
<div class="divide-y divide-slate-100">
<div class="p-4 px-6 hover:bg-slate-50">
<div class="flex items-center justify-between mb-1">
<span class="text-xs font-bold px-2 py-0.5 rounded bg-red-100 text-red-700">严重不良事件 (SAE)</span>
<span class="text-xs text-slate-400">昨天 14:30</span>
</div>
<p class="text-sm font-bold text-slate-800">P005 - 谷丙转氨酶(ALT)达到 150U/L</p>
<p class="text-xs text-slate-500 mt-1">由 AI 从实验室检查表抓取,已触发强制 SDV。</p>
</div>
<div class="p-4 px-6 hover:bg-slate-50">
<div class="flex items-center justify-between mb-1">
<span class="text-xs font-bold px-2 py-0.5 rounded bg-orange-100 text-orange-700">方案偏离 (PD)</span>
<span class="text-xs text-slate-400">3天前</span>
</div>
<p class="text-sm font-bold text-slate-800">P002 - 随访 2 严重超窗</p>
<p class="text-xs text-slate-500 mt-1">实际随访日期偏离方案要求窗口期超过 7 天。</p>
</div>
</div>
</div>
</div>
<!-- 质量评级 -->
<div class="bg-white rounded-xl border border-slate-200 shadow-sm">
<div class="px-6 py-4 border-b border-slate-200">
<h2 class="text-base font-bold text-slate-800 flex items-center">
<i class="ph-fill ph-users-three text-slate-400 mr-2 text-lg"></i>
数据响应质量一览
</h2>
</div>
<div class="p-6">
<p class="text-sm text-slate-600 mb-4">通过 AI 发起质疑的响应速度,评估各中心的数据录入质量与配合度。</p>
<div class="space-y-4">
<div>
<div class="flex justify-between text-sm mb-1">
<span class="font-medium text-slate-800">北京协和中心 (李明)</span>
<span class="text-emerald-600 font-bold">平均响应 4.5h</span>
</div>
<div class="w-full bg-slate-100 h-2 rounded-full overflow-hidden">
<div class="bg-emerald-500 h-full w-[90%] rounded-full"></div>
</div>
</div>
<div>
<div class="flex justify-between text-sm mb-1">
<span class="font-medium text-slate-800">上海中山中心 (赵小丽)</span>
<span class="text-yellow-600 font-bold">平均响应 12.2h</span>
</div>
<div class="w-full bg-slate-100 h-2 rounded-full overflow-hidden">
<div class="bg-yellow-400 h-full w-[60%] rounded-full"></div>
</div>
</div>
<div>
<div class="flex justify-between text-sm mb-1">
<span class="font-medium text-slate-800">广州南方中心 (王强)</span>
<span class="text-red-500 font-bold">平均响应 48.2h</span>
</div>
<div class="w-full bg-slate-100 h-2 rounded-full overflow-hidden">
<div class="bg-red-500 h-full w-[25%] rounded-full"></div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- ================= 视图 BAI 工作流水 (AI Stream) ================= -->
<div id="view-ai-stream" class="flex-1 overflow-y-auto p-6 bg-slate-50/50 hidden">
<div class="max-w-4xl mx-auto">
<div class="mb-8">
<h2 class="text-2xl font-bold text-slate-800 flex items-center">
AI 实时工作流水
<span class="ml-4 flex items-center text-xs font-normal px-2.5 py-1 rounded-full bg-emerald-100 text-emerald-700">
<i class="ph-fill ph-radio mr-1"></i> Webhook 实时监听中
</span>
</h2>
<p class="text-sm text-slate-500 mt-1">完全透明展示 AI 的每一次审查、推理和结果,建立 100% 的信任。</p>
</div>
<div class="bg-white rounded-xl border border-slate-200 shadow-sm p-6 relative">
<div class="absolute top-6 left-12 bottom-6 w-px bg-slate-200"></div> <!-- 贯穿的垂直线 -->
<div class="space-y-6">
<!-- 流水记录 1 -->
<div class="relative flex items-start gap-4">
<div class="w-16 shrink-0 text-right pt-1">
<span class="text-xs font-bold text-blue-600">刚才</span>
</div>
<div class="w-8 h-8 rounded-full bg-blue-100 border-2 border-white flex items-center justify-center relative z-10 shrink-0 shadow-sm">
<i class="ph-bold ph-eye text-blue-600"></i>
</div>
<div class="flex-1 bg-slate-50 rounded-lg p-4 border border-slate-100">
<p class="text-sm font-bold text-slate-800">监听 EDC 保存事件,扫描 <span class="text-blue-600">P008 随访记录表</span></p>
<p class="text-xs text-slate-500 mt-1">调用 12 条硬逻辑规则,比对完成。耗时 0.2 秒。</p>
<div class="mt-2 inline-flex items-center text-xs font-bold text-emerald-600 bg-emerald-50 px-2 py-1 rounded">
<i class="ph-fill ph-check-circle mr-1"></i> 未发现异常,放行。
</div>
</div>
</div>
<!-- 流水记录 2 (发现问题并派发) -->
<div class="relative flex items-start gap-4">
<div class="w-16 shrink-0 text-right pt-1">
<span class="text-xs font-medium text-slate-400">10:24</span>
</div>
<div class="w-8 h-8 rounded-full bg-red-100 border-2 border-white flex items-center justify-center relative z-10 shrink-0 shadow-sm">
<i class="ph-bold ph-warning text-red-600"></i>
</div>
<div class="flex-1 bg-red-50/50 rounded-lg p-4 border border-red-100">
<p class="text-sm font-bold text-slate-800">扫描 <span class="text-blue-600">P005 实验室检查表</span> 时拦截异常</p>
<p class="text-xs text-slate-600 mt-1 leading-relaxed">
<strong class="text-slate-800">AI 推理链路:</strong>提取到 ALT=150U/L -> 检索方案知识库发现超 SAE 阈值 -> 交叉查询患者不良事件表 -> <span class="text-red-600 font-bold">发现记录缺失。</span>
</p>
<div class="mt-3 bg-white border border-red-200 rounded p-3 text-sm flex justify-between items-center">
<div>
<span class="font-mono text-xs text-red-500 font-bold block mb-1">执行动作:</span>
已自动生成电子质疑 <strong>eQuery-1029</strong>,并推送到 CRC 任务列表。
</div>
<button onclick="switchView('equery')" class="px-3 py-1.5 bg-red-100 text-red-700 text-xs font-bold rounded hover:bg-red-200 transition-colors">
查看该质疑
</button>
</div>
</div>
</div>
<!-- 流水记录 3 (自动复核闭环) -->
<div class="relative flex items-start gap-4">
<div class="w-16 shrink-0 text-right pt-1">
<span class="text-xs font-medium text-slate-400">09:15</span>
</div>
<div class="w-8 h-8 rounded-full bg-purple-100 border-2 border-white flex items-center justify-center relative z-10 shrink-0 shadow-sm">
<i class="ph-bold ph-arrows-clockwise text-purple-600"></i>
</div>
<div class="flex-1 bg-slate-50 rounded-lg p-4 border border-slate-100">
<p class="text-sm font-bold text-slate-800">执行二次自动复核 (P003 体格检查表)</p>
<p class="text-xs text-slate-500 mt-1">接收到 CRC 数据修正信号。重新验证身高体重计算的 BMI 逻辑关系。</p>
<div class="mt-2 inline-flex items-center text-xs font-bold text-purple-600 bg-purple-50 px-2 py-1 rounded">
<i class="ph-fill ph-check-circle mr-1"></i> 数据一致性验证通过,已自动关闭 eQuery-1015。
</div>
</div>
</div>
<!-- 凌晨跑批 -->
<div class="relative flex items-start gap-4">
<div class="w-16 shrink-0 text-right pt-1">
<span class="text-xs font-medium text-slate-400">02:00</span>
</div>
<div class="w-8 h-8 rounded-full bg-slate-200 border-2 border-white flex items-center justify-center relative z-10 shrink-0 shadow-sm">
<i class="ph-bold ph-moon-stars text-slate-600"></i>
</div>
<div class="flex-1 bg-slate-50 rounded-lg p-4 border border-slate-100">
<p class="text-sm font-bold text-slate-800">执行每日凌晨全量交叉核对跑批 (Cron Job)</p>
<p class="text-xs text-slate-500 mt-1">扫描全库 1204 份表单,进行跨表单逻辑验证。耗时 4.2 秒。未发现全局性新问题。</p>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- ================= 视图 C待处理质疑 (eQuery) ================= -->
<div id="view-equery" class="flex-1 overflow-y-auto p-6 bg-slate-50/50 hidden">
<div class="max-w-5xl mx-auto">
<div class="mb-6 flex justify-between items-end">
<div>
<h2 class="text-2xl font-bold text-slate-800">待处理质疑 (eQuery) 列表</h2>
<p class="text-sm text-slate-500 mt-1">AI 发现的数据缺陷,需人工 (CRC) 响应修复或上传 SDV 凭证。</p>
</div>
</div>
<div class="bg-white rounded-xl border border-slate-200 shadow-sm overflow-hidden mb-6">
<div class="divide-y divide-slate-100">
<!-- 质疑项 1 -->
<div class="p-6 hover:bg-slate-50 transition-colors flex gap-6">
<div class="mt-1">
<i class="ph-fill ph-warning text-3xl text-red-500"></i>
</div>
<div class="flex-1">
<div class="flex justify-between items-start mb-2">
<div class="flex items-center gap-3">
<span class="px-2.5 py-1 rounded bg-slate-100 text-sm font-bold text-slate-700">P005</span>
<span class="text-base font-bold text-slate-800">实验室检查异常:漏报 AE</span>
<span class="text-xs font-bold px-2 py-0.5 bg-red-100 text-red-700 rounded border border-red-200">强制 SDV</span>
</div>
<span class="text-xs font-bold text-slate-500 font-mono bg-slate-100 px-2 py-1 rounded">eQuery-1029</span>
</div>
<p class="text-sm text-slate-700 leading-relaxed mb-4 p-3 bg-red-50/50 rounded border border-red-100">
<strong>AI 监查意见:</strong>检测到 ALT 异常升高 (150U/L),已达到方案规定的 SAE 标准。但该患者无对应的 AE 记录。为了排除数据录入错误,此项已触发强制 SDV。请上传该次访视的原始化验单照片供 AI 核对。
</p>
<div class="flex items-center justify-between mt-2 pt-4 border-t border-slate-100">
<div class="text-xs text-slate-500">
<i class="ph-fill ph-clock mr-1"></i> AI 派发时间: 今天 10:24
</div>
<button onclick="switchView('sdv-response')" class="px-6 py-2 text-sm font-bold text-white bg-blue-600 rounded-lg shadow-sm hover:bg-blue-700 transition-colors flex items-center">
去响应并上传凭证 <i class="ph-bold ph-arrow-right ml-2"></i>
</button>
</div>
</div>
</div>
<!-- 质疑项 2 -->
<div class="p-6 hover:bg-slate-50 transition-colors flex gap-6">
<div class="mt-1">
<i class="ph-fill ph-info text-3xl text-yellow-500"></i>
</div>
<div class="flex-1">
<div class="flex justify-between items-start mb-2">
<div class="flex items-center gap-3">
<span class="px-2.5 py-1 rounded bg-slate-100 text-sm font-bold text-slate-700">P002</span>
<span class="text-base font-bold text-slate-800">知情同意书:逻辑时序冲突</span>
</div>
<span class="text-xs font-bold text-slate-500 font-mono bg-slate-100 px-2 py-1 rounded">eQuery-1028</span>
</div>
<p class="text-sm text-slate-700 leading-relaxed mb-4 p-3 bg-yellow-50/50 rounded border border-yellow-100">
<strong>AI 监查意见:</strong>签署知情同意书的日期 (2026-02-25) 晚于心电图检查日期 (2026-02-24),涉嫌违规操作。请核实 REDCap 录入日期是否错误。
</p>
<div class="flex items-center justify-end gap-3 mt-2 pt-4 border-t border-slate-100">
<button class="px-4 py-2 bg-white border border-slate-300 hover:bg-slate-50 text-slate-700 text-sm font-medium rounded-lg transition-colors">
声明此为真实数据 (填写理由)
</button>
<button class="px-4 py-2 bg-slate-800 hover:bg-slate-900 text-white text-sm font-medium rounded-lg transition-colors flex items-center">
<i class="ph-bold ph-arrows-clockwise mr-2"></i> 我已在 EDC 修正,通知 AI 重查
</button>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- ================= 视图 D定期报告与事件沉淀 (Reports) ================= -->
<div id="view-reports" class="flex-1 overflow-y-auto p-6 bg-slate-50/50 hidden">
<div class="max-w-5xl mx-auto">
<div class="mb-8">
<h2 class="text-2xl font-bold text-slate-800">定期报告与关键事件库</h2>
<p class="text-sm text-slate-500 mt-1">临床研究的长期资产。AI 自动生成的阶段性报告与全生命周期重大事件追踪。</p>
</div>
<div class="grid grid-cols-3 gap-6">
<!-- 左侧:定期质控报告 -->
<div class="col-span-2">
<h3 class="text-base font-bold text-slate-800 mb-4 flex items-center">
<i class="ph-fill ph-files text-blue-500 mr-2"></i> AI 自动生成定期报告
</h3>
<div class="grid grid-cols-2 gap-4">
<!-- Report Card -->
<div class="bg-white rounded-xl border border-slate-200 p-5 shadow-sm hover:border-blue-400 cursor-pointer transition-colors group">
<div class="flex justify-between items-start mb-3">
<div class="w-10 h-10 rounded bg-blue-50 flex items-center justify-center text-blue-600">
<i class="ph-bold ph-file-pdf text-xl"></i>
</div>
<span class="text-xs font-bold text-slate-400">本周</span>
</div>
<h4 class="font-bold text-slate-800 group-hover:text-blue-600 transition-colors">2026年2月第3周 质控周报</h4>
<p class="text-xs text-slate-500 mt-2 mb-4 leading-relaxed">共审查 842 份表单,拦截并闭环 12 项逻辑错误,项目合规率提升 0.5%。</p>
<div class="text-xs font-medium text-blue-600 flex items-center border-t border-slate-100 pt-3">
点击预览详细报告 <i class="ph-bold ph-arrow-right ml-1"></i>
</div>
</div>
<!-- Report Card -->
<div class="bg-white rounded-xl border border-slate-200 p-5 shadow-sm hover:border-blue-400 cursor-pointer transition-colors group">
<div class="flex justify-between items-start mb-3">
<div class="w-10 h-10 rounded bg-slate-100 flex items-center justify-center text-slate-500">
<i class="ph-bold ph-file-pdf text-xl"></i>
</div>
<span class="text-xs font-bold text-slate-400">上周</span>
</div>
<h4 class="font-bold text-slate-800 group-hover:text-blue-600 transition-colors">2026年2月第2周 质控周报</h4>
<p class="text-xs text-slate-500 mt-2 mb-4 leading-relaxed">共审查 750 份表单,包含 1 项 PD (方案偏离) 专题汇总分析。</p>
<div class="text-xs font-medium text-slate-500 flex items-center border-t border-slate-100 pt-3">
点击预览详细报告 <i class="ph-bold ph-arrow-right ml-1"></i>
</div>
</div>
</div>
</div>
<!-- 右侧:重大事件记录库 -->
<div class="col-span-1">
<h3 class="text-base font-bold text-slate-800 mb-4 flex items-center">
<i class="ph-fill ph-archive text-slate-500 mr-2"></i> 重大事件沉淀库
</h3>
<div class="bg-white rounded-xl border border-slate-200 shadow-sm overflow-hidden">
<div class="divide-y divide-slate-100">
<div class="p-4 hover:bg-slate-50 cursor-pointer">
<div class="flex items-center justify-between mb-1">
<span class="text-xs font-bold text-red-600">严重不良事件 (SAE) 归档</span>
</div>
<p class="text-sm font-bold text-slate-800">P012 肺炎住院</p>
<p class="text-xs text-slate-500 mt-1">2026-01-15 发生,已完成与申办方的上报流程并闭环。</p>
</div>
<div class="p-4 hover:bg-slate-50 cursor-pointer">
<div class="flex items-center justify-between mb-1">
<span class="text-xs font-bold text-orange-600">方案偏离 (PD) 归档</span>
</div>
<p class="text-sm font-bold text-slate-800">P003 服药依从性极低</p>
<p class="text-xs text-slate-500 mt-1">记录于 2026-01-10AI 评估为重大偏离,剔除分析集。</p>
</div>
<div class="p-3 text-center bg-slate-50 border-t border-slate-100">
<button class="text-xs font-bold text-blue-600 hover:underline">查看全部 12 项历史事件</button>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- ================= 视图 ESDV 响应界面 ================= -->
<div id="view-sdv" class="flex-1 flex flex-col h-full bg-slate-100 p-6 overflow-hidden hidden">
<div class="flex flex-col h-full bg-white rounded-xl border border-slate-200 shadow-sm overflow-hidden">
<div class="px-6 py-4 border-b border-slate-200 bg-slate-50 flex justify-between items-center shrink-0">
<div>
<h2 class="text-lg font-bold text-slate-800">响应 eQuery-1029上传 SDV 原始凭证</h2>
<p class="text-xs text-slate-500 mt-1">受试者 P005 / 实验室检查 / ALT 异常漏报</p>
</div>
<span class="px-3 py-1 bg-red-100 text-red-700 font-bold text-xs rounded-full flex items-center">
<i class="ph-bold ph-warning-circle mr-1"></i> AI 强制核查项
</span>
</div>
<div class="flex-1 flex overflow-hidden">
<div class="w-1/3 bg-slate-50 border-r border-slate-200 p-6 overflow-y-auto">
<div class="flex items-center text-blue-600 font-bold mb-4">
<i class="ph-fill ph-robot text-xl mr-2"></i> AI 监查员判定依据
</div>
<div class="space-y-6">
<div>
<h4 class="text-xs font-bold text-slate-400 uppercase mb-2">当前 REDCap 数据</h4>
<div class="bg-white border border-slate-200 rounded p-3 text-sm">
<span class="text-slate-500">lab_alt:</span> <span class="font-bold text-slate-800 ml-2">150 U/L</span>
</div>
</div>
<div>
<h4 class="text-xs font-bold text-slate-400 uppercase mb-2">AI 要求指令</h4>
<div class="bg-red-50 border border-red-100 rounded p-3 text-sm text-red-800">
在 REDCap 的《不良事件表》中未查找到对应记录。请在右侧上传该检验报告的原件照片AI 将重新提取化验单数值以确认是否为您的键盘录入错误。
</div>
</div>
</div>
</div>
<div class="flex-1 p-8 flex flex-col justify-center items-center bg-white relative">
<div id="drop-zone" class="w-full max-w-lg p-10 dash-border bg-slate-50 text-center hover:bg-blue-50 transition-colors cursor-pointer group">
<div class="w-16 h-16 rounded-full bg-blue-100 text-blue-600 flex items-center justify-center mx-auto mb-4 group-hover:scale-110 transition-transform">
<i class="ph-fill ph-cloud-arrow-up text-3xl"></i>
</div>
<h3 class="text-lg font-bold text-slate-800 mb-2">点击或将凭证照片拖拽至此处</h3>
<p class="text-sm text-slate-500 mb-6">支持 JPG, PNG, PDF 格式。请确保图片清晰,包含患者脱敏 ID。</p>
<button class="px-6 py-2.5 bg-white border border-slate-300 shadow-sm text-slate-700 font-medium rounded-lg hover:bg-slate-50 transition-colors">
浏览本地文件
</button>
</div>
</div>
</div>
</div>
</div>
</main>
<!-- 3. 全局统一 AI Copilot -->
<aside id="sidebar-copilot" class="w-80 bg-white border-l border-slate-200 flex flex-col transition-all duration-300 ease-in-out shrink-0 z-20 shadow-xl">
<div class="h-16 border-b border-slate-100 flex items-center justify-between px-4 shrink-0 bg-blue-50/50">
<div class="flex items-center">
<div class="w-6 h-6 rounded bg-gradient-to-br from-blue-500 to-indigo-600 flex items-center justify-center mr-2 shadow-sm">
<i class="ph-fill ph-sparkle text-white text-xs"></i>
</div>
<span class="font-bold text-slate-800 text-sm">项目大模型助理</span>
</div>
<button onclick="toggleCopilot()" class="text-slate-400 hover:text-slate-600">
<i class="ph-fill ph-x-circle text-xl"></i>
</button>
</div>
<div id="chat-container" class="flex-1 overflow-y-auto p-4 space-y-4">
<div class="flex justify-start">
<div class="max-w-[85%] rounded-2xl px-4 py-3 text-sm leading-relaxed bg-slate-100 text-slate-800 rounded-bl-sm border border-slate-200">
<span class="font-bold block mb-1">您好!</span>
我是本项目的统一数字监查大脑。无论您是研究者还是协调员,都可以随时向我提问关于项目进度、数据质量或具体违规记录的细节。
</div>
</div>
</div>
<div class="p-3 border-t border-slate-100 bg-white shrink-0">
<form id="chat-form" class="relative">
<input
type="text"
id="chat-input"
placeholder="例如: 总结本周重大事件..."
class="w-full bg-slate-50 border border-slate-200 rounded-full pl-4 pr-10 py-2.5 text-sm focus:outline-none focus:border-blue-500 focus:ring-1 focus:ring-blue-500"
autocomplete="off"
/>
<button type="submit" class="absolute right-2 top-1/2 -translate-y-1/2 p-1.5 bg-blue-600 text-white rounded-full hover:bg-blue-700 transition-colors flex items-center justify-center">
<i class="ph-bold ph-paper-plane-right text-sm"></i>
</button>
</form>
<div class="mt-2 flex gap-2 overflow-x-auto pb-1 no-scrollbar">
<span onclick="sendPrompt('总结本周最容易犯的错误')" class="whitespace-nowrap bg-slate-50 border border-slate-200 text-slate-500 text-[10px] px-2 py-1 rounded-full cursor-pointer hover:bg-slate-100">总结本周错误趋势</span>
<span onclick="sendPrompt('解释为什么 P005 需要SDV')" class="whitespace-nowrap bg-slate-50 border border-slate-200 text-slate-500 text-[10px] px-2 py-1 rounded-full cursor-pointer hover:bg-slate-100">解释 P005 问题</span>
</div>
</div>
</aside>
<script>
// === Heatmap 渲染逻辑整合 ===
const MOCK_HEATMAP = [
{ id: 'P001', forms: ['green', 'green', 'green', 'green', 'yellow'] },
{ id: 'P002', forms: ['green', 'red', 'green', 'green', 'green'] },
{ id: 'P003', forms: ['green', 'green', 'yellow', 'green', 'green'] },
{ id: 'P004', forms: ['green', 'green', 'green', 'green', 'green'] },
{ id: 'P005', forms: ['green', 'green', 'red', 'red', 'yellow'] },
];
function renderHeatmap() {
const tbody = document.getElementById('heatmap-body');
if(!tbody) return;
let html = '';
MOCK_HEATMAP.forEach(row => {
let rowHtml = `<tr class="border-t border-slate-100 hover:bg-slate-50 transition-colors"><td class="py-3 pr-4 font-bold text-slate-700">${row.id}</td>`;
row.forms.forEach(status => {
let colorClass = status === 'red' ? 'bg-red-500 border-red-600 text-white shadow-sm hover:opacity-80' :
status === 'yellow' ? 'bg-yellow-400 border-yellow-500 text-yellow-900 shadow-sm hover:opacity-80' :
'bg-emerald-50 border-emerald-100 opacity-60 hover:opacity-100';
let iconHtml = status === 'red' ? `<i class="ph-bold ph-warning"></i>` : '';
let action = (status === 'red' || status === 'yellow') ? `onclick="switchView('equery')"` : '';
rowHtml += `<td class="p-1">
<div ${action} class="h-10 rounded flex items-center justify-center border transition-all cursor-pointer ${colorClass}">
${iconHtml}
</div>
</td>`;
});
rowHtml += '</tr>';
html += rowHtml;
});
tbody.innerHTML = html;
}
// === 视图路由映射表 ===
const views = {
'dashboard': { el: 'view-dashboard', title: '项目健康度大盘', nav: 'nav-dashboard', showBack: false },
'reports': { el: 'view-reports', title: '定期报告与关键事件', nav: 'nav-reports', showBack: false },
'ai-stream': { el: 'view-ai-stream', title: 'AI 工作流水', nav: 'nav-ai-stream', showBack: false },
'equery': { el: 'view-equery', title: '待处理质疑 (eQuery)', nav: 'nav-equery', showBack: false },
'sdv-response': { el: 'view-sdv', title: 'SDV 凭证上传与验证', nav: 'nav-equery', showBack: true }
};
function switchView(targetViewId) {
// 隐藏所有视图
Object.values(views).forEach(v => {
document.getElementById(v.el).classList.add('hidden');
document.getElementById(v.el).classList.remove('block', 'flex');
});
// 重置所有导航高亮
['nav-dashboard', 'nav-reports', 'nav-ai-stream', 'nav-equery'].forEach(id => {
const el = document.getElementById(id);
el.classList.remove('bg-blue-600/20', 'text-blue-400');
el.classList.add('text-slate-400');
});
// 显示目标视图
const target = views[targetViewId];
const el = document.getElementById(target.el);
// 某些视图需要 flex (如 sdv),其他用 block
if(targetViewId === 'sdv-response') {
el.classList.remove('hidden'); el.classList.add('flex');
} else {
el.classList.remove('hidden'); el.classList.add('block');
}
// 更新 Header 与返回按钮
document.getElementById('header-title').innerText = target.title;
const btnBack = document.getElementById('btn-back');
if(target.showBack) {
btnBack.classList.remove('hidden');
} else {
btnBack.classList.add('hidden');
}
// 更新导航高亮
const navEl = document.getElementById(target.nav);
navEl.classList.add('bg-blue-600/20', 'text-blue-400');
navEl.classList.remove('text-slate-400');
}
// Copilot 逻辑
let copilotOpen = true;
function toggleCopilot() {
const sidebar = document.getElementById('sidebar-copilot');
const btnToggle = document.getElementById('btn-copilot-toggle');
copilotOpen = !copilotOpen;
if (copilotOpen) {
sidebar.classList.remove('w-0', 'border-none');
sidebar.classList.add('w-80');
btnToggle.classList.replace('text-slate-400', 'text-blue-600');
btnToggle.classList.replace('hover:bg-slate-100', 'bg-blue-50');
} else {
sidebar.classList.remove('w-80');
sidebar.classList.add('w-0', 'border-none');
btnToggle.classList.replace('text-blue-600', 'text-slate-400');
btnToggle.classList.replace('bg-blue-50', 'hover:bg-slate-100');
}
}
let chatMessages = [
{ role: 'system', content: '您好!我是本项目的统一数字监查大脑。无论您是研究者还是协调员,都可以随时向我提问关于项目进度、数据质量或具体违规记录的细节。' }
];
function renderChat() {
const container = document.getElementById('chat-container');
let html = '';
chatMessages.forEach(msg => {
let alignment = msg.role === 'user' ? 'justify-end' : 'justify-start';
let styling = msg.role === 'user' ? 'bg-blue-600 text-white rounded-br-sm' :
msg.role === 'system' ? 'bg-slate-100 text-slate-500 text-xs text-center w-full rounded-lg' :
'bg-slate-100 text-slate-800 rounded-bl-sm border border-slate-200';
html += `
<div class="flex ${alignment}">
<div class="max-w-[85%] rounded-2xl px-4 py-2.5 text-sm leading-relaxed ${styling}">
${msg.content}
</div>
</div>`;
});
container.innerHTML = html;
container.scrollTop = container.scrollHeight;
}
function sendPrompt(text) {
document.getElementById('chat-input').value = text;
document.getElementById('chat-form').dispatchEvent(new Event('submit'));
}
document.getElementById('chat-form').addEventListener('submit', function(e) {
e.preventDefault();
const input = document.getElementById('chat-input');
const text = input.value.trim();
if (!text) return;
chatMessages.push({ role: 'user', content: text });
input.value = '';
renderChat();
setTimeout(() => {
chatMessages.push({ role: 'ai', content: '收到您的指令。我已将底层数据检索报告推送到您的界面,请查看左侧的模块视图。' });
renderChat();
}, 800);
});
// 初始化
window.onload = function() {
renderHeatmap(); // 渲染热力图
switchView('dashboard'); // 默认进入大盘视图
};
</script>
</body>
</html>