/** * IIT 项目配置详情页 * * 包含4个Tab:基本配置、质控规则、用户映射、知识库 */ import React, { useState, useEffect, useCallback } from 'react'; import { useParams, useNavigate } from 'react-router-dom'; import { Card, Tabs, Button, Form, Input, Select, Table, Modal, message, Popconfirm, Typography, Space, Tag, Spin, Alert, Descriptions, Empty, Tooltip, Badge, } from 'antd'; import { ArrowLeftOutlined, SaveOutlined, PlusOutlined, DeleteOutlined, EditOutlined, CheckCircleOutlined, CloseCircleOutlined, SyncOutlined, LinkOutlined, DisconnectOutlined, ExclamationCircleOutlined, BookOutlined, ThunderboltOutlined, BarChartOutlined, DashboardOutlined, } from '@ant-design/icons'; import * as iitProjectApi from '../api/iitProjectApi'; import type { IitProject, UpdateProjectRequest, QCRule, CreateRuleRequest, IitUserMapping, CreateUserMappingRequest, RoleOption, KnowledgeBaseOption, } from '../types/iitProject'; const { Title, Text, Paragraph } = Typography; const { TextArea } = Input; // ==================== 常量定义 ==================== const SEVERITY_MAP = { error: { color: 'error', text: '错误' }, warning: { color: 'warning', text: '警告' }, info: { color: 'processing', text: '信息' }, }; const CATEGORY_MAP = { inclusion: { color: '#52c41a', text: '纳入标准' }, exclusion: { color: '#ff4d4f', text: '排除标准' }, lab_values: { color: '#1890ff', text: '变量范围' }, logic_check: { color: '#722ed1', text: '逻辑检查' }, }; // ==================== 主组件 ==================== const IitProjectDetailPage: React.FC = () => { const { id } = useParams<{ id: string }>(); const navigate = useNavigate(); const [project, setProject] = useState(null); const [loading, setLoading] = useState(true); const [activeTab, setActiveTab] = useState('basic'); const [batchQcLoading, setBatchQcLoading] = useState(false); const [batchSummaryLoading, setBatchSummaryLoading] = useState(false); // 加载项目详情 const loadProject = useCallback(async () => { if (!id) return; setLoading(true); try { const data = await iitProjectApi.getProject(id); setProject(data); } catch (error) { message.error('加载项目详情失败'); navigate('/admin/iit-projects'); } finally { setLoading(false); } }, [id, navigate]); useEffect(() => { loadProject(); }, [loadProject]); // ⭐ 一键全量质控 const handleBatchQc = async () => { if (!id) return; setBatchQcLoading(true); try { const result = await iitProjectApi.batchQualityCheck(id); message.success(`质控完成!共 ${result.stats.totalRecords} 条记录,通过率 ${result.stats.passRate}`); } catch (error: any) { message.error(error.message || '质控失败'); } finally { setBatchQcLoading(false); } }; // ⭐ 一键全量数据汇总 const handleBatchSummary = async () => { if (!id) return; setBatchSummaryLoading(true); try { const result = await iitProjectApi.batchSummary(id); message.success(`汇总完成!共 ${result.stats.totalRecords} 条记录,平均完成率 ${result.stats.avgCompletionRate}`); } catch (error: any) { message.error(error.message || '汇总失败'); } finally { setBatchSummaryLoading(false); } }; if (loading) { return (
); } if (!project) { return ; } const tabItems = [ { key: 'basic', label: 'REDCap 配置', children: , }, { key: 'rules', label: '质控规则', children: , }, { key: 'users', label: '通知设置', children: , }, { key: 'kb', label: '知识库', children: , }, ]; return (
{/* 页面标题 */}
{project.name} {/* ⭐ 批量操作按钮 */} {/* ⭐ 质控全览图按钮 - 导航到驾驶舱页面 */}
{project.description && ( {project.description} )}
{/* Tab 页 */}
); }; // ==================== Tab 1: 基本配置 ==================== interface BasicConfigTabProps { project: IitProject; onUpdate: () => void; } const BasicConfigTab: React.FC = ({ project, onUpdate }) => { const [form] = Form.useForm(); const [saving, setSaving] = useState(false); const [testing, setTesting] = useState(false); const [syncing, setSyncing] = useState(false); useEffect(() => { form.setFieldsValue({ name: project.name, description: project.description, redcapUrl: project.redcapUrl, redcapProjectId: project.redcapProjectId, redcapApiToken: project.redcapApiToken, }); }, [form, project]); const handleSave = async (values: UpdateProjectRequest) => { setSaving(true); try { await iitProjectApi.updateProject(project.id, values); message.success('保存成功'); onUpdate(); } catch (error) { message.error('保存失败'); } finally { setSaving(false); } }; const handleTestConnection = async () => { setTesting(true); try { const result = await iitProjectApi.testProjectConnection(project.id); if (result.success) { message.success(`连接成功!REDCap 版本: ${result.version},记录数: ${result.recordCount}`); } else { message.error(`连接失败: ${result.error}`); } } catch (error) { message.error('测试连接失败'); } finally { setTesting(false); } }; const handleSyncMetadata = async () => { setSyncing(true); try { const result = await iitProjectApi.syncMetadata(project.id); message.success(`同步成功!共 ${result.fieldCount} 个字段`); } catch (error) { message.error('同步失败'); } finally { setSyncing(false); } }; return (