feat(iit): Complete V3.1 QC engine + GCP business reports + AI timeline + bug fixes
V3.1 QC Engine: - QcExecutor unified entry + D1-D7 dimension engines + three-level aggregation - HealthScoreEngine + CompletenessEngine + ProtocolDeviationEngine + QcAggregator - B4 flexible cron scheduling (project-level cronExpression + pg-boss dispatcher) - Prisma migrations for qc_field_status, event_status, project_stats GCP Business Reports (Phase A - 4 reports): - D1 Eligibility: record_summary full list + qc_field_status D1 overlay - D2 Completeness: data entry rate and missing rate aggregation - D3/D4 Query Tracking: severity distribution from qc_field_status - D6 Protocol Deviation: D6 dimension filtering - 4 frontend table components + ReportsPage 5-tab restructure AI Timeline Enhancement: - SkillRunner outputs totalRules (33 actual rules vs 1 skill) - iitQcCockpitController severity mapping fix (critical->red, warning->yellow) - AiStreamPage expandable issue detail table with Chinese labels - Event label localization (eventLabel from backend) Business-side One-click Batch QC: - DashboardPage batch QC button with SyncOutlined icon - Auto-refresh QcReport cache after batch execution Bug Fixes: - dimension_code -> rule_category in 4 SQL queries - D1 eligibility data source: record_summary full + qc_field_status overlay - Timezone UTC -> Asia/Shanghai (QcReportService toBeijingTime helper) - Pass rate calculation: passed/totalEvents instead of passed/totalRecords Docs: - Update IIT module status with GCP reports and bug fix milestones - Update system status doc v6.6 with IIT progress Tested: Backend compiles, frontend linter clean, batch QC verified Made-with: Cursor
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
/**
|
||||
* 风险热力图组件
|
||||
* 风险热力图组件 (V3.1)
|
||||
*
|
||||
* 展示受试者 × 表单/访视 矩阵
|
||||
* 展示受试者 × 事件 矩阵
|
||||
* - 绿色圆点:通过
|
||||
* - 黄色图标:警告(可点击)
|
||||
* - 红色图标:严重(可点击)
|
||||
@@ -11,7 +11,6 @@
|
||||
import React from 'react';
|
||||
import { Spin, Tag, Tooltip } from 'antd';
|
||||
import {
|
||||
CheckOutlined,
|
||||
ExclamationOutlined,
|
||||
CloseOutlined,
|
||||
} from '@ant-design/icons';
|
||||
@@ -24,6 +23,8 @@ interface RiskHeatmapProps {
|
||||
}
|
||||
|
||||
const RiskHeatmap: React.FC<RiskHeatmapProps> = ({ data, onCellClick, loading }) => {
|
||||
const columnLabels = data.columnLabels || {};
|
||||
|
||||
const getStatusTag = (status: string) => {
|
||||
switch (status) {
|
||||
case 'enrolled':
|
||||
@@ -39,13 +40,16 @@ const RiskHeatmap: React.FC<RiskHeatmapProps> = ({ data, onCellClick, loading })
|
||||
}
|
||||
};
|
||||
|
||||
const getColumnLabel = (col: string): string => {
|
||||
if (columnLabels[col]) return columnLabels[col];
|
||||
if (col.includes('(')) return col.split('(')[0];
|
||||
return col;
|
||||
};
|
||||
|
||||
const renderCell = (cell: HeatmapCell) => {
|
||||
const hasIssues = cell.status === 'warning' || cell.status === 'fail';
|
||||
|
||||
// ✅ 所有单元格都可点击,便于查看详情
|
||||
const handleClick = () => onCellClick(cell);
|
||||
|
||||
// 有问题的单元格:显示可点击图标
|
||||
if (hasIssues) {
|
||||
const iconClass = `qc-heatmap-cell-icon ${cell.status}`;
|
||||
const icon = cell.status === 'fail'
|
||||
@@ -61,7 +65,6 @@ const RiskHeatmap: React.FC<RiskHeatmapProps> = ({ data, onCellClick, loading })
|
||||
);
|
||||
}
|
||||
|
||||
// 通过或待检查:显示小圆点(也可点击)
|
||||
const dotClass = `qc-heatmap-cell-dot ${cell.status === 'pass' ? 'pass' : 'pending'}`;
|
||||
const tooltipText = cell.status === 'pass'
|
||||
? '已通过,点击查看数据'
|
||||
@@ -83,7 +86,6 @@ const RiskHeatmap: React.FC<RiskHeatmapProps> = ({ data, onCellClick, loading })
|
||||
|
||||
return (
|
||||
<div className="qc-heatmap">
|
||||
{/* 头部 */}
|
||||
<div className="qc-heatmap-header">
|
||||
<h3 className="qc-heatmap-title">受试者风险全景图 (Risk Heatmap)</h3>
|
||||
<div className="qc-heatmap-legend">
|
||||
@@ -106,7 +108,6 @@ const RiskHeatmap: React.FC<RiskHeatmapProps> = ({ data, onCellClick, loading })
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 表格内容 */}
|
||||
<div className="qc-heatmap-body">
|
||||
<Spin spinning={loading}>
|
||||
<table className="qc-heatmap-table">
|
||||
@@ -114,14 +115,16 @@ const RiskHeatmap: React.FC<RiskHeatmapProps> = ({ data, onCellClick, loading })
|
||||
<tr>
|
||||
<th className="subject-header">受试者 ID</th>
|
||||
<th>入组状态</th>
|
||||
{data.columns.map((col, idx) => (
|
||||
<th key={idx}>
|
||||
{col.split('(')[0]}<br />
|
||||
<small style={{ fontWeight: 'normal' }}>
|
||||
{col.includes('(') ? `(${col.split('(')[1]}` : ''}
|
||||
</small>
|
||||
</th>
|
||||
))}
|
||||
{data.columns.map((col, idx) => {
|
||||
const label = getColumnLabel(col);
|
||||
return (
|
||||
<th key={idx}>
|
||||
<Tooltip title={col !== label ? col : undefined}>
|
||||
<span>{label}</span>
|
||||
</Tooltip>
|
||||
</th>
|
||||
);
|
||||
})}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
|
||||
Reference in New Issue
Block a user