opo-线索管理V3edit icon

作者:
Fadinghaze
Fork(复制)
下载
嵌入
BUG反馈
index.html
style.css
index.js
现在支持上传本地图片了!
index.html
            
            <!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>江苏省OPO可视化调度指挥平台 - 终版V10</title>
    <script src="https://cdn.tailwindcss.com"></script>
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
    
    <style>
        /* ==================== 1. 全局定义 ==================== */
        :root {
            --primary-blue: #007aff;
            --tech-cyan: #00f0ff;
            --tech-bg: #050b16;
            --card-bg: rgba(16, 36, 68, 0.95);
            --border-color: rgba(64, 116, 180, 0.4);
            --text-main: #ffffff;
            
            --label-color: #6a8bad; 
            --value-color: #ffffff;
            
            --status-pending: #ff9f0a;
            --status-approved: #30d158;
            --status-rejected: #ff453a;
            --panel-width: 480px; 
        }

        body {
            margin: 0; padding: 0;
            background-color: var(--tech-bg);
            font-family: "Microsoft YaHei", sans-serif;
            color: var(--text-main);
            height: 100vh; width: 100vw;
            overflow: hidden;
            display: flex;
            justify-content: space-between;
        }

        ::-webkit-scrollbar { width: 4px; }
        ::-webkit-scrollbar-thumb { background: rgba(0, 240, 255, 0.3); border-radius: 2px; }
        ::-webkit-scrollbar-track { background: rgba(0,0,0,0.2); }

        /* ==================== 2. 地图层 ==================== */
        .map-viewport {
            position: absolute; top: 0; left: 0; width: 100%; height: 100%;
            background-image: radial-gradient(circle at 50% 50%, #112240 0%, #02050a 100%),
                              url('https://api.mapbox.com/styles/v1/mapbox/dark-v10/static/118.78,32.07,7,0/1600x1200?access_token=pk.eyJ1IjoiZGVtb3VzZXIiLCJhIjoiY2x4eH..."');
            background-size: cover; background-position: center;
            overflow: hidden; z-index: 0;
        }
        .map-layer { width: 100%; height: 100%; position: absolute; top: 0; left: 0; transition: transform 1s cubic-bezier(0.19, 1, 0.22, 1); }

        /* 点位交互组件 */
        .map-point {
            position: absolute; transform: translate(-50%, -100%);
            display: flex; flex-direction: column; align-items: center;
            z-index: 10; cursor: pointer; transition: 0.3s;
        }
        .map-point.active { z-index: 20; transform: translate(-50%, -100%) scale(1.1); }
        
        /* HUD 卡片 (V9样式保持) */
        .point-hud { margin-bottom: 12px; transition: 0.3s; }
        .hud-card {
            background: rgba(8, 20, 40, 0.9); border: 1px solid var(--tech-cyan); border-radius: 4px;
            padding: 12px 16px; 
            box-shadow: 0 4px 20px rgba(0,0,0,0.6); backdrop-filter: blur(8px); 
            min-width: 180px; 
        }
        
        .map-point.urgent .hud-card { border-color: var(--status-pending); box-shadow: 0 0 15px rgba(255,159,10,0.4); }
        .map-point.active .hud-card { background: rgba(0, 50, 100, 0.95); border-color: #fff; }
        
        .hud-title { 
            font-size: 15px; font-weight: bold; color: #fff; text-align: center; 
            border-bottom: 1px solid rgba(255,255,255,0.15); 
            padding-bottom: 8px; margin-bottom: 8px; 
            letter-spacing: 1px;
        }
        
        .hud-content { display: flex; justify-content: space-between; align-items: center; }
        .hud-col { display: flex; flex-direction: column; align-items: center; flex: 1; }
        
        .hud-lbl { font-size: 12px; color: var(--text-sub); margin-bottom: 4px; }
        
        .hud-num { font-family: Impact, sans-serif; font-size: 22px; color: var(--tech-cyan); line-height: 1.1; }
        
        .map-point.urgent .hud-num.active { color: var(--status-pending); text-shadow: 0 0 10px rgba(255,159,10,0.5); }
        .map-point.urgent .hud-num.inactive { color: #aaa; } 
        
        .pulse-ring {
            position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%);
            width: 40px; height: 40px; border-radius: 50%;
            border: 1px solid var(--status-pending); opacity: 0; pointer-events: none;
        }
        .map-point.urgent .pulse-ring { animation: ripple 2s infinite; }
        
        .point-icon {
            width: 36px; height: 36px; background: #050b16; border: 2px solid var(--tech-cyan);
            border-radius: 50%; display: flex; justify-content: center; align-items: center;
            color: var(--tech-cyan); font-size: 16px; position: relative; z-index: 2;
            box-shadow: 0 0 10px var(--tech-cyan); transition: 0.3s;
        }
        .map-point.urgent .point-icon { border-color: var(--status-pending); color: var(--status-pending); box-shadow: 0 0 20px var(--status-pending); }
        .map-point.active .point-icon { background: var(--tech-cyan); color: #000; box-shadow: 0 0 25px var(--tech-cyan); }
        .map-point.active.urgent .point-icon { background: var(--status-pending); }

        @keyframes ripple { 0% { transform: translate(-50%, -50%) scale(1); opacity: 0.8; } 100% { transform: translate(-50%, -50%) scale(2.8); opacity: 0; } }

        /* ==================== 3. 面板容器通用 ==================== */
        .panel-container {
            width: var(--panel-width); height: 95vh; 
            background: rgba(8, 26, 54, 0.95);
            border: 1px solid var(--border-color);
            box-shadow: 0 0 40px rgba(0, 0, 0, 0.6);
            display: flex; flex-direction: column;
            backdrop-filter: blur(12px);
            z-index: 50;
            margin-top: 2.5vh;
            transition: transform 0.4s ease, opacity 0.4s ease;
        }
        
        .panel-header { height: 44px; background: linear-gradient(90deg, rgba(0,76,163,0.6) 0%, rgba(0,0,0,0) 100%); display: flex; align-items: center; padding: 0 16px; border-bottom: 1px solid var(--border-color); flex-shrink: 0; }
        .header-icon { width: 4px; height: 18px; background: var(--tech-cyan); margin-right: 10px; box-shadow: 0 0 8px var(--tech-cyan); }
        .panel-title { font-size: 18px; font-weight: bold; letter-spacing: 1px; flex: 1; color: #fff; }
        .list-content { flex: 1; overflow-y: auto; padding: 15px; }

        /* ==================== 4. 左侧详情面板 ==================== */
        .left-panel {
            position: absolute; left: 20px; 
            transform: translateX(-120%); opacity: 0;
        }
        .left-panel.show { transform: translateX(0); opacity: 1; }

        .lp-section-title {
            font-size: 14px; font-weight: bold; color: var(--tech-cyan);
            border-left: 3px solid var(--tech-cyan); padding-left: 8px;
            margin: 15px 0 10px 0; background: linear-gradient(90deg, rgba(0,240,255,0.1) 0%, transparent 100%);
            padding-top: 2px; padding-bottom: 2px;
        }
        .lp-section-title:first-child { margin-top: 0; }

        .lp-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 10px 20px; font-size: 12px; margin-bottom: 10px; }
        .lp-field { display: flex; flex-direction: column; }
        .lp-label { color: var(--label-color); margin-bottom: 3px; font-size: 11px; }
        .lp-val { color: var(--value-color); border-bottom: 1px solid rgba(255,255,255,0.05); padding-bottom: 2px; min-height: 20px; }
        .lp-val.highlight { color: var(--tech-cyan); font-weight: bold; }
        
        .diag-box { grid-column: span 2; background: rgba(0,0,0,0.2); padding: 8px; border-radius: 4px; border: 1px solid rgba(255,255,255,0.05); }
        
        .tag-box { display: flex; flex-wrap: wrap; gap: 6px; }
        .tag-item { padding: 2px 8px; border-radius: 2px; font-size: 11px; border: 1px solid; }
        .tag-green { border-color: rgba(48,209,88,0.3); background: rgba(48,209,88,0.1); color: #30d158; }
        .tag-red { border-color: rgba(255,69,58,0.3); background: rgba(255,69,58,0.1); color: #ff453a; }

        .dispatch-card {
            background: rgba(255,255,255,0.03); border: 1px solid rgba(255,255,255,0.05);
            padding: 8px 12px; margin-bottom: 6px; border-radius: 4px;
            display: flex; justify-content: space-between; align-items: center;
        }
        .dispatch-btn { background: var(--primary-blue); color: #fff; border:none; padding:3px 12px; border-radius:2px; cursor:pointer; font-size:12px; transition:0.2s;}
        .dispatch-btn:hover { background: var(--tech-cyan); color: #000; }
        
        .audit-row { display: flex; flex-direction: column; width: 100%; font-size: 12px; }
        .audit-top { display: flex; justify-content: space-between; margin-bottom: 4px; color: #fff; font-weight: bold; }
        .audit-btm { display: flex; justify-content: space-between; color: #888; font-size: 11px; }

        /* ==================== 5. 右侧列表面板 ==================== */
        .right-panel { position: absolute; right: 20px; }
        
        /* KPI */
        .kpi-section { display: grid; grid-template-columns: repeat(4, 1fr); padding: 10px; gap: 5px; border-bottom: 1px solid rgba(255,255,255,0.05); }
        .kpi-item { background: rgba(255,255,255,0.05); border-radius: 4px; padding: 6px 0; text-align: center; }
        .kpi-item.active { background: rgba(0,122,255,0.2); border: 1px solid var(--primary-blue); }
        .kpi-num { font-size: 18px; font-weight: bold; display: block; }
        .kpi-lbl { font-size: 10px; color: var(--text-sub); }

        /* 筛选区 1:时间 */
        .filter-time-row { 
            padding: 8px 12px; border-bottom: 1px solid rgba(255,255,255,0.05); background: rgba(0,0,0,0.2); 
            display: flex; align-items: center; justify-content: space-between; gap: 10px; flex-shrink: 0; 
        }
        .date-display {
            background: rgba(0,0,0,0.3); border: 1px solid rgba(143, 180, 217, 0.3); border-radius: 3px; 
            padding: 4px 8px; font-size: 12px; color: #fff; flex: 1; display: flex; align-items: center;
        }
        .time-controls { display: flex; background: rgba(255,255,255,0.05); border-radius: 3px; padding: 2px; }
        .time-btn { 
            border: none; background: none; color: var(--text-sub); font-size: 11px; 
            padding: 4px 10px; cursor: pointer; border-radius: 2px; transition: all 0.2s; 
        }
        .time-btn.active { background: var(--primary-blue); color: white; font-weight: bold; }

        /* 筛选区 2:行政区与医院 */
        .filter-area-row {
            padding: 8px 12px; border-bottom: 1px solid var(--border-color); background: rgba(0,0,0,0.1);
            display: flex; align-items: center; gap: 6px; flex-shrink: 0;
        }
        .filter-select {
            background: rgba(0,0,0,0.4); border: 1px solid rgba(64,116,180,0.5); color: #fff;
            padding: 3px 6px; border-radius: 3px; font-size: 12px; flex: 1; outline: none;
            cursor: pointer;
        }
        .filter-select option { background: #050b16; color: #fff; }
        
        .reset-btn {
            background: rgba(255,255,255,0.1); border: 1px solid rgba(255,255,255,0.2); color: #aaa;
            width: 24px; height: 24px; border-radius: 3px; display: flex; align-items: center; justify-content: center;
            cursor: pointer; transition: 0.2s;
        }
        .reset-btn:hover { background: rgba(255,255,255,0.2); color: #fff; }
        .reset-btn.active { color: var(--tech-cyan); border-color: var(--tech-cyan); background: rgba(0,240,255,0.1); }

        /* 列表卡片 */
        .list-card {
            background: var(--card-bg);
            border: 1px solid rgba(0, 240, 255, 0.1);
            border-left: 3px solid #888;
            border-radius: 4px; margin-bottom: 10px; padding: 10px;
            cursor: pointer; transition: 0.2s; position: relative;
        }
        .list-card:hover { background: rgba(20, 45, 85, 0.9); transform: translateX(-4px); }
        .list-card.active-select { border: 1px solid var(--tech-cyan); background: rgba(20, 45, 85, 1); box-shadow: inset 0 0 10px rgba(0,240,255,0.2); }

        .list-card.pending { border-left-color: var(--status-pending); }
        .list-card.approved { border-left-color: var(--status-approved); }
        .list-card.rejected { border-left-color: var(--status-rejected); }

        .lc-top { display: flex; justify-content: space-between; margin-bottom: 6px; align-items: center; }
        .lc-id { font-size: 14px; font-weight: bold; color: var(--tech-cyan); }
        .lc-status { font-size: 10px; padding: 1px 6px; border-radius: 2px; border: 1px solid; }
        .lc-hospital { font-size: 13px; color: #fff; margin-bottom: 8px; font-weight: 500; }
        .lc-meta-row { display: flex; flex-direction: column; font-size: 11px; color: var(--text-sub); border-top: 1px dashed rgba(255,255,255,0.1); padding-top: 6px; gap: 2px; }
        .lc-meta-item { display: flex; }
        .lc-meta-lbl { color: #666; margin-right: 4px; min-width: 55px; }
        .lc-meta-val { color: #ccc; }
        
        .st-pending { color: var(--status-pending); border-color: var(--status-pending); background: rgba(255, 159, 10, 0.1); }
        .st-approved { color: var(--status-approved); border-color: var(--status-approved); background: rgba(48, 209, 88, 0.1); }
        .st-rejected { color: var(--status-rejected); border-color: var(--status-rejected); background: rgba(255, 69, 58, 0.1); }

    </style>
</head>
<body>

<!-- 地图底座 -->
<div class="map-viewport" id="mapContainer">
    <div class="map-layer" id="mapLayer"></div>
</div>

<!-- 左侧详情面板 -->
<div class="panel-container left-panel" id="leftPanel">
    <div class="panel-header">
        <div class="header-icon"></div>
        <div class="panel-title">线索详情</div>
    </div>
    <div class="list-content" id="detailContent">
        <!-- JS 渲染 -->
    </div>
</div>

<!-- 右侧列表面板 -->
<div class="panel-container right-panel">
    <div class="panel-header">
        <div class="header-icon"></div>
        <div class="panel-title">线索管理</div>
    </div>
    
    <!-- KPI -->
    <div class="kpi-section">
        <div class="kpi-item active"><span class="kpi-num text-white">28</span><span class="kpi-lbl">线索总数</span></div>
        <div class="kpi-item"><span class="kpi-num text-green-400">12</span><span class="kpi-lbl">已通过</span></div>
        <div class="kpi-item"><span class="kpi-num text-orange-400">4</span><span class="kpi-lbl">待审核</span></div>
        <div class="kpi-item"><span class="kpi-num text-red-400">12</span><span class="kpi-lbl">未通过</span></div>
    </div>

    <!-- 筛选 1:时间 -->
    <div class="filter-time-row">
        <div class="date-display">
            <i class="far fa-calendar-alt mr-2 text-cyan-400"></i>
            <span>2023-11-20 ~ 2023-11-26</span>
        </div>
        <div class="time-controls">
            <button class="time-btn active">本周</button>
            <button class="time-btn">本月</button>
            <button class="time-btn">本年</button>
        </div>
    </div>

    <!-- 筛选 2:区域与医院 -->
    <div class="filter-area-row">
        <select class="filter-select" id="selCity">
            <option value="">选择地市</option><option>南京市</option><option>苏州市</option><option>无锡市</option>
        </select>
        <select class="filter-select" id="selDistrict">
            <option value="">选择区域</option><option>秦淮区</option><option>鼓楼区</option><option>玄武区</option>
        </select>
        <select class="filter-select" id="selHospital" onchange="filterByHospital(this.value)">
            <option value="">选择医院</option>
            <option value="H001">南京市第一医院</option>
            <option value="H002">南京市鼓楼医院</option>
            <option value="H003">江苏省人民医院</option>
            <option value="H004">无锡市人民医院</option>
        </select>
        <!-- 重置按钮 -->
        <button class="reset-btn" id="btnReset" onclick="resetFilter()" title="重置筛选">
            <i class="fas fa-undo"></i>
        </button>
    </div>

    <!-- 列表 -->
    <div class="list-content" id="rightListContent">
        <!-- JS 渲染列表 -->
    </div>
</div>

<script>
    // ==================== 数据源 ====================
    const database = [
        {
            id: 'JSNJ00043', name: '***', status: 'pending', hospitalId: 'H001', hospitalName: '南京市第一医院', 
            registrant: '凌晓红', time: '2023-11-26 14:20:05',
            details: {
                dept: '急诊抢救室', idCard: '3201**********1234', sex: '男', age: '57', inpatientNo: 'A3', blood: 'A型',
                diag: '脑干出血、脑疝', gcs: '3分', uw: '21分', resp: '无', vent: '是', sedative: '无',
                contraindications: ['无'], intention: '犹豫',
                coordinators: [ {name:'刘伟', dist:'1.2km', status:'avail'}, {name:'陈静', dist:'8.5km', status:'busy'} ]
            },
            hospitalData: { x: 45, y: 40, total: 45, active: 2 }
        },
        {
            id: 'JSNJ00045', name: '孙*', status: 'pending', hospitalId: 'H001', hospitalName: '南京市第一医院', 
            registrant: '凌晓红', time: '2023-11-26 10:15:30',
            details: {
                dept: 'ICU', idCard: '3201**********9988', sex: '女', age: '62', inpatientNo: 'C09', blood: 'O型',
                diag: '自发性蛛网膜下腔出血', gcs: '4分', uw: '20分', resp: '微弱', vent: '是', sedative: '有',
                contraindications: ['无'], intention: '部分亲属同意',
                coordinators: [ {name:'刘伟', dist:'1.2km', status:'avail'} ]
            },
            hospitalData: { x: 45, y: 40, total: 45, active: 2 }
        },
        {
            id: 'JSCZ00039', name: '覃**', status: 'pending', hospitalId: 'H002', hospitalName: '南京市鼓楼医院', 
            registrant: '王大伟', time: '2023-11-25 10:45:12',
            details: {
                dept: 'ICU', idCard: '3203**********0099', sex: '男', age: '45', inpatientNo: 'B12', blood: 'B型',
                diag: '大面积脑出血,自主呼吸消失', gcs: '3分', uw: '19分', resp: '无', vent: '是', sedative: '无',
                contraindications: ['未经过治疗的颅外恶性肿瘤'], intention: '全部亲属同意',
                coordinators: [ {name:'王强', dist:'2.0km', status:'avail'} ]
            },
            hospitalData: { x: 50, y: 60, total: 156, active: 1 }
        },
        {
            id: 'JSCZ00040', name: '李**', status: 'approved', hospitalId: 'H003', hospitalName: '江苏省人民医院', 
            registrant: '陈明明', time: '2023-11-24 09:30:22',
            details: {
                dept: '神经外科', idCard: '3201**********5566', sex: '女', age: '32', inpatientNo: 'N09', blood: 'O型',
                diag: '重度颅脑损伤,脑疝形成', gcs: '3分', uw: '19分', resp: '微弱', vent: '是', sedative: '有',
                contraindications: ['无'], intention: '全部亲属同意',
                auditRecord: { auditor: '张三', result: '审核通过', time: '2023-11-24 10:05:00' }
            },
            hospitalData: { x: 55, y: 55, total: 203, active: 0 }
        },
        {
            id: 'JSCZ00035', name: '王*', status: 'rejected', hospitalId: 'H004', hospitalName: '无锡市人民医院', 
            registrant: '周云', time: '2023-11-20 14:20:18',
            details: {
                dept: '肿瘤科', idCard: '3202**********8877', sex: '男', age: '65', inpatientNo: 'C01', blood: 'AB型',
                diag: '恶性肿瘤全身转移', gcs: '3分', uw: '19分', resp: '有', vent: '否', sedative: '无',
                contraindications: ['恶性肿瘤'], intention: '不同意',
                auditRecord: { auditor: '李四', result: '审核驳回: 医学禁忌', time: '2023-11-20 15:30:12' }
            },
            hospitalData: { x: 65, y: 75, total: 89, active: 0 }
        }
    ];

    // ==================== 初始化 ====================
    const mapLayer = document.getElementById('mapLayer');
    const rightList = document.getElementById('rightListContent');
    const leftPanel = document.getElementById('leftPanel');
    const detailContent = document.getElementById('detailContent');
    const selHospital = document.getElementById('selHospital');
    const btnReset = document.getElementById('btnReset');

    // 1. 渲染地图
    const hospitalMap = {};
    database.forEach(item => {
        if(!hospitalMap[item.hospitalId]) {
            hospitalMap[item.hospitalId] = item.hospitalData;
            hospitalMap[item.hospitalId].name = item.hospitalName;
            hospitalMap[item.hospitalId].id = item.hospitalId;
        }
    });

    function initMap() {
        for (let hId in hospitalMap) {
            const h = hospitalMap[hId];
            const isUrgent = h.active > 0;
            const el = document.createElement('div');
            el.className = `map-point ${isUrgent ? 'urgent' : ''}`;
            el.style.left = h.x + '%';
            el.style.top = h.y + '%';
            el.id = `pt-${hId}`;
            
            el.onclick = (e) => { 
                e.stopPropagation(); 
                selHospital.value = hId; 
                filterByHospital(hId);   
            };

            // HUD 布局:标题在上,数字在下
            const html = `
                <div class="point-hud">
                    <div class="hud-card">
                        <div class="hud-title">${h.name}</div>
                        <div class="hud-content">
                            <div class="hud-col">
                                <div class="hud-lbl">活跃线索</div>
                                <div class="hud-num ${isUrgent?'active':'inactive'}">${h.active}</div>
                            </div>
                            <div class="hud-col">
                                <div class="hud-lbl">线索总数</div>
                                <div class="hud-num" style="color:#aaa">${h.total}</div>
                            </div>
                        </div>
                    </div>
                </div>
                <div class="pulse-ring"></div>
                <div class="point-icon"><i class="fas fa-hospital"></i></div>
            `;
            el.innerHTML = html;
            mapLayer.appendChild(el);
        }
    }

    // 2. 渲染右侧列表
    function renderList(data = database) {
        rightList.innerHTML = data.map(item => {
            let stClass = '', stText = '';
            if(item.status==='pending') { stClass='st-pending'; stText='待审核'; }
            if(item.status==='approved') { stClass='st-approved'; stText='已通过'; }
            if(item.status==='rejected') { stClass='st-rejected'; stText='未通过'; }

            return `
                <div class="list-card ${item.status}" id="card-${item.id}" onclick="selectClueById('${item.id}')">
                    <div class="lc-top">
                        <span class="lc-id">${item.id}</span>
                        <span class="lc-status ${stClass}">${stText}</span>
                    </div>
                    <div class="lc-hospital">${item.hospitalName}</div>
                    <div class="lc-meta-row">
                        <div class="lc-meta-item">
                            <span class="lc-meta-lbl">登记人:</span>
                            <span class="lc-meta-val">${item.registrant}</span>
                        </div>
                        <div class="lc-meta-item">
                            <span class="lc-meta-lbl">登记时间:</span>
                            <span class="lc-meta-val">${item.time}</span>
                        </div>
                    </div>
                </div>
            `;
        }).join('');
    }

    // ==================== 联动逻辑 ====================
    window.filterByHospital = (hId) => {
        if (!hId) {
            resetFilter();
            return;
        }
        const filtered = database.filter(d => d.hospitalId === hId);
        renderList(filtered);
        btnReset.classList.add('active'); 
        if(filtered.length > 0) {
            selectClue(filtered[0]);
        }
    }

    window.resetFilter = () => {
        selHospital.value = "";
        renderList(database); 
        btnReset.classList.remove('active');
        
        mapLayer.style.transform = `translate(0, 0) scale(1)`;
        document.querySelectorAll('.map-point').forEach(p => p.classList.remove('active'));
        document.querySelectorAll('.list-card').forEach(c => c.classList.remove('active-select'));
        leftPanel.classList.remove('show');
    }

    window.selectClueById = (id) => {
        const item = database.find(d => d.id === id);
        if(item) selectClue(item);
    }

    function selectClue(item) {
        // 地图定位
        const h = item.hospitalData;
        mapLayer.style.transform = `translate(${50 - h.x}%, ${50 - h.y}%) scale(1.1)`;
        document.querySelectorAll('.map-point').forEach(p => p.classList.remove('active'));
        document.getElementById(`pt-${item.hospitalId}`).classList.add('active');

        // 列表高亮
        document.querySelectorAll('.list-card').forEach(c => c.classList.remove('active-select'));
        const card = document.getElementById(`card-${item.id}`);
        if(card) {
            card.classList.add('active-select');
            card.scrollIntoView({ behavior: 'smooth', block: 'center' });
        }

        // 详情展示
        renderLeftDetail(item);
        leftPanel.classList.add('show');
    }

    function renderLeftDetail(item) {
        const d = item.details;
        
        // 禁忌症
        let contraHtml = '';
        if(d.contraindications.includes('无')) {
            contraHtml = '<span class="tag-item tag-green">无禁忌症</span>';
        } else {
            contraHtml = d.contraindications.map(c => `<span class="tag-item tag-red">${c}</span>`).join('');
        }

        // 调度/审核
        let dispatchHtml = '';
        if(item.status === 'pending') {
            const list = d.coordinators || [];
            if(list.length > 0) {
                dispatchHtml = list.map(c => `
                    <div class="dispatch-card">
                        <div class="flex items-center">
                            <span style="width:6px;height:6px;border-radius:50%;margin-right:8px;background:${c.status==='avail'?'#30d158':'#ff453a'}"></span>
                            <span class="text-white">${c.name}</span>
                            <span class="text-gray-400 text-xs ml-2">${c.dist}</span>
                        </div>
                        <button class="dispatch-btn">调度</button>
                    </div>
                `).join('');
            } else {
                dispatchHtml = '<div class="text-gray-500 text-xs italic p-2">附近暂无可用协调员</div>';
            }
        } else {
            const rec = d.auditRecord;
            const statusColor = item.status === 'approved' ? '#30d158' : '#ff453a';
            dispatchHtml = `
                <div class="dispatch-card">
                    <div class="audit-row">
                        <div class="audit-top">
                            <span>审核人: ${rec.auditor}</span>
                            <span style="color:${statusColor}">${rec.result}</span>
                        </div>
                        <div class="audit-btm">
                            <span><i class="far fa-clock mr-1"></i>${rec.time}</span>
                        </div>
                    </div>
                </div>
            `;
        }

        const html = `
            <div class="lp-section-title">基本信息</div>
            <div class="lp-grid">
                <div class="lp-field"><span class="lp-label">潜在登记编号</span><span class="lp-val highlight">${item.id}</span></div>
                <div class="lp-field"><span class="lp-label">医院</span><span class="lp-val">${item.hospitalName}</span></div>
                <div class="lp-field"><span class="lp-label">科室</span><span class="lp-val">${d.dept}</span></div>
                <div class="lp-field"><span class="lp-label">登记人</span><span class="lp-val">${item.registrant}</span></div>
                <div class="lp-field"><span class="lp-label">入院时间</span><span class="lp-val">${item.time}</span></div>
            </div>

            <div class="lp-section-title">患者信息</div>
            <div class="lp-grid">
                <div class="lp-field"><span class="lp-label">姓名</span><span class="lp-val">${item.name}</span></div>
                <div class="lp-field"><span class="lp-label">性别</span><span class="lp-val">${d.sex}</span></div>
                <div class="lp-field"><span class="lp-label">年龄</span><span class="lp-val">${d.age}</span></div>
                <div class="lp-field"><span class="lp-label">血型</span><span class="lp-val">${d.blood}</span></div>
                <div class="lp-field"><span class="lp-label">住院号</span><span class="lp-val">${d.inpatientNo}</span></div>
                <div class="lp-field"><span class="lp-label">身份证号</span><span class="lp-val">${d.idCard}</span></div>
            </div>

            <div class="lp-section-title">临床指标</div>
            <div class="lp-grid">
                <div class="lp-field span-col-2 diag-box">
                    <span class="lp-label w-full block">诊断</span>
                    <span class="text-white font-bold">${d.diag}</span>
                </div>
                <div class="lp-field"><span class="lp-label">格拉斯哥评分</span><span class="lp-val highlight">${d.gcs}</span></div>
                <div class="lp-field"><span class="lp-label">UW评分</span><span class="lp-val highlight">${d.uw}</span></div>
                <div class="lp-field"><span class="lp-label">自主呼吸</span><span class="lp-val">${d.resp}</span></div>
                <div class="lp-field"><span class="lp-label">机械通气</span><span class="lp-val">${d.vent}</span></div>
                <div class="lp-field"><span class="lp-label">有无使用镇静药</span><span class="lp-val">${d.sedative}</span></div>
            </div>

            <div class="lp-section-title">禁忌症与意愿</div>
            <div class="lp-grid">
                <div class="lp-field" style="grid-column: span 2">
                    <span class="lp-label">禁忌症</span>
                    <div class="tag-box mt-1">${contraHtml}</div>
                </div>
                <div class="lp-field" style="grid-column: span 2; margin-top:5px">
                    <span class="lp-label">目前捐献意愿</span>
                    <span class="lp-val highlight">${d.intention}</span>
                </div>
            </div>

            <div class="lp-section-title">协调员跟进</div>
            <div>${dispatchHtml}</div>
        `;
        detailContent.innerHTML = html;
    }

    initMap();
    renderList(database);

</script>
</body>
</html>
        
编辑器加载中
预览
控制台