<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>青少年赛艇连队 · 体测数据及发育评估(2026.02.07)</title>
    <!-- Chart.js 轻量图表库 -->
    <script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.0/dist/chart.umd.min.js"></script>
    <style>
        * {
            box-sizing: border-box;
            font-family: 'Segoe UI', Roboto, system-ui, -apple-system, sans-serif;
        }
        body {
            background: #f0f4f8;
            margin: 0;
            padding: 24px 16px;
            display: flex;
            flex-direction: column;
            align-items: center;
        }
        .container {
            max-width: 1600px;
            width: 100%;
            background: white;
            border-radius: 28px;
            box-shadow: 0 20px 40px -12px rgba(0,20,40,0.25);
            padding: 24px 20px 32px 20px;
        }
        h1 {
            font-size: 2rem;
            font-weight: 600;
            margin: 0 0 8px 0;
            color: #0b2b44;
            display: flex;
            align-items: center;
            gap: 8px;
            flex-wrap: wrap;
        }
        .subtitle {
            font-size: 1rem;
            color: #2c5779;
            margin-top: 4px;
            margin-bottom: 24px;
            border-left: 5px solid #1d7ab3;
            padding-left: 18px;
            background: #e9f0f9;
            border-radius: 0 20px 20px 0;
            line-height: 1.5;
        }
        .meta-badge {
            background: #dde9f5;
            border-radius: 40px;
            padding: 6px 18px;
            font-size: 0.9rem;
            font-weight: 500;
            color: #0b3b5c;
            display: inline-block;
            margin-right: 16px;
        }
        .legend {
            display: flex;
            flex-wrap: wrap;
            gap: 20px;
            background: #f8fbfe;
            padding: 14px 20px;
            border-radius: 24px;
            margin: 22px 0 18px 0;
            border: 1px solid #cbd6e4;
            font-size: 0.9rem;
        }
        .legend-item {
            display: flex;
            align-items: center;
            gap: 8px;
        }
        .color-dot {
            width: 18px;
            height: 18px;
            border-radius: 6px;
        }
        .dot-low { background: #b22234; }          /* 下等 */
        .dot-midlow { background: #f4a261; }       /* 中下等 */
        .dot-mid { background: #2a9d8f; }           /* 中等 */
        .dot-midhigh { background: #8ecae6; }       /* 中上等 */
        .dot-high { background: #ffb703; }          /* 上等 */
        .dot-normal { background: #60a847; }
        .dot-overweight { background: #f48c06; }
        .dot-obese { background: #d00000; }
        .table-wrapper {
            overflow-x: auto;
            border-radius: 20px;
            border: 1px solid #cfdeed;
            background: white;
            margin-top: 12px;
        }
        table {
            width: 100%;
            border-collapse: collapse;
            font-size: 0.85rem;
            min-width: 1800px;
            white-space: nowrap;
        }
        th {
            background: #1d3b5c;
            color: white;
            font-weight: 600;
            padding: 14px 8px;
            text-align: center;
            border-right: 1px solid #34658b;
        }
        th:last-child {
            border-right: none;
        }
        td {
            padding: 12px 6px;
            border-bottom: 1px solid #d8e2ee;
            text-align: center;
            background-color: white;
        }
        tr:hover td {
            background-color: #f5faff;
        }
        .section-divider {
            background-color: #e1ecf9;
            font-weight: 600;
            color: #0a3147;
        }
        .badge {
            display: inline-block;
            padding: 4px 10px;
            border-radius: 30px;
            font-weight: 600;
            font-size: 0.75rem;
            letter-spacing: 0.3px;
        }
        .height-low { background: #b22234; color: white; }        /* <-2SD */
        .height-midlow { background: #f4a261; color: #1e2f3d; }   /* -2SD ~ -1SD */
        .height-mid { background: #2a9d8f; color: white; }        /* -1SD ~ +1SD */
        .height-midhigh { background: #8ecae6; color: #0a2f44; }  /* +1SD ~ +2SD */
        .height-high { background: #ffb703; color: #1e2f3d; }     /* >+2SD */
        .weight-normal { background: #60a847; color: white; }
        .weight-overweight { background: #f48c06; color: white; }
        .weight-obese { background: #d00000; color: white; }
        .injury-tag {
            background: #ffe4d6;
            color: #a13e0b;
            border-radius: 16px;
            padding: 2px 8px;
            font-size: 0.7rem;
            font-weight: 600;
            display: inline-block;
            margin: 2px;
            white-space: nowrap;
        }
        .footer-note {
            margin-top: 24px;
            font-size: 0.8rem;
            color: #3d5f82;
            background: #e2edf9;
            padding: 12px 20px;
            border-radius: 18px;
        }
        .date-badge {
            background: #1d7ab3;
            color: white;
            border-radius: 30px;
            padding: 4px 16px;
            font-weight: 500;
            font-size: 0.9rem;
            margin-left: auto;
        }
        .mono {
            font-family: 'JetBrains Mono', monospace;
            font-weight: 500;
        }
        /* 相关性说明卡片 */
        .rowing-correlation {
            background: linear-gradient(145deg, #e2efff, #d2e5fc);
            border-radius: 24px;
            padding: 18px 24px;
            margin: 16px 0 22px 0;
            border: 1px solid #acc9e5;
            display: flex;
            flex-wrap: wrap;
            align-items: center;
            gap: 20px;
        }
        .correlation-icon {
            font-size: 2.8rem;
            background: white;
            width: 70px;
            height: 70px;
            border-radius: 50%;
            display: flex;
            align-items: center;
            justify-content: center;
            box-shadow: 0 6px 12px rgba(0,40,70,0.1);
        }
        .correlation-text {
            flex: 1;
            color: #013a63;
        }
        .correlation-text strong {
            font-size: 1.1rem;
            display: block;
            margin-bottom: 6px;
            color: #012a4a;
        }
        .correlation-text p {
            margin: 6px 0;
            line-height: 1.5;
        }
        /* 卡片布局:饼图 + 伤病统计 */
        .stats-grid {
            display: flex;
            flex-wrap: wrap;
            gap: 24px;
            margin: 24px 0;
            align-items: stretch;
        }
        .chart-card {
            flex: 1 1 260px;
            background: #ffffff;
            border-radius: 20px;
            border: 1px solid #c9ddec;
            padding: 18px 16px 20px 16px;
            box-shadow: 0 4px 10px rgba(0, 30, 50, 0.05);
        }
        .chart-card h3 {
            margin: 0 0 16px 0;
            font-weight: 600;
            font-size: 1.1rem;
            color: #154b70;
            display: flex;
            align-items: center;
            gap: 8px;
            border-bottom: 1px dashed #b3cee8;
            padding-bottom: 10px;
        }
        .canvas-wrapper {
            position: relative;
            height: 200px;
            width: 100%;
            margin-top: 10px;
        }
        .injury-rank-card {
            flex: 2 1 360px;
            background: #ffffff;
            border-radius: 20px;
            border: 1px solid #c9ddec;
            padding: 18px 20px 20px 20px;
            box-shadow: 0 4px 10px rgba(0, 30, 50, 0.05);
        }
        .injury-rank-card h3 {
            margin: 0 0 16px 0;
            font-weight: 600;
            font-size: 1.1rem;
            color: #154b70;
            display: flex;
            align-items: center;
            gap: 8px;
            border-bottom: 1px dashed #b3cee8;
            padding-bottom: 10px;
        }
        .injury-rank-table {
            width: 100%;
            border-collapse: collapse;
            font-size: 0.95rem;
        }
        .injury-rank-table th {
            background: #e2effb;
            color: #034b7c;
            font-weight: 600;
            padding: 10px 8px;
            text-align: center;
        }
        .injury-rank-table td {
            padding: 8px 8px;
            border-bottom: 1px solid #d2e3f0;
            text-align: center;
        }
        .injury-rank-table tr:last-child td {
            border-bottom: none;
        }
        .rank-number {
            display: inline-block;
            background: #245e8f;
            color: white;
            font-weight: 600;
            width: 26px;
            height: 26px;
            line-height: 26px;
            text-align: center;
            border-radius: 30px;
            font-size: 0.8rem;
        }
        .injury-count-badge {
            background: #15607e;
            color: white;
            border-radius: 30px;
            padding: 4px 14px;
            font-weight: 600;
            font-size: 0.85rem;
        }
    </style>
</head>
<body>
<div class="container">
    <div style="display: flex; flex-wrap: wrap; justify-content: space-between; align-items: center;">
        <h1>
            🚣 青少年赛艇连队 · 体测综合评估
            <span class="date-badge">测试日期 2026.02.07</span>
        </h1>
    </div>
    <div class="subtitle">
        ⚡ 依据 WS/T 612—2018 身高发育等级 &nbsp;&nbsp;|&nbsp;&nbsp; WS/T 586—2018 超重/肥胖筛查 &nbsp;&nbsp;|&nbsp;&nbsp; 原始数据来自 <em>青少年赛艇连队2026体测数据表</em>
    </div>

    <!-- 臂展/身高比与赛艇运动相关性说明 -->
    <div class="rowing-correlation">
        <div class="correlation-icon">🏅</div>
        <div class="correlation-text">
            <strong>🚣 臂展/身高比 —— 赛艇选材的关键指标</strong>
            <p>赛艇运动中,更长的臂展意味着更长的划桨力臂,可直接增加单桨做功距离,提升推进效率。通常臂展/身高比 > 1.02 被视为优秀天赋指标。本队多数队员比值在 0.98~1.05 之间,其中 <span style="font-weight:700; color:#003d66;">陈迦杰(1.003)、卢紫铭(1.032)、许芮瑜(1.006)</span> 等表现突出,具备较好的力学优势。该比值与坐高/身高结合可进一步评估身体比例协调性,为专项选材提供科学参考。</p>
        </div>
    </div>

    <!-- 图例/色标 -->
    <div class="legend">
        <span style="font-weight:600; color:#134b73;">📊 身高等级:</span>
        <div class="legend-item"><span class="color-dot dot-low"></span>下等 (<-2SD)</div>
        <div class="legend-item"><span class="color-dot dot-midlow"></span>中下等 [-2SD , -1SD)</div>
        <div class="legend-item"><span class="color-dot dot-mid"></span>中等 [-1SD , +1SD]</div>
        <div class="legend-item"><span class="color-dot dot-midhigh"></span>中上等 (+1SD , +2SD]</div>
        <div class="legend-item"><span class="color-dot dot-high"></span>上等 (>+2SD)</div>
        <span style="font-weight:600; margin-left:20px; color:#134b73;">⚖️ 体重状态:</span>
        <div class="legend-item"><span class="color-dot dot-normal"></span>正常</div>
        <div class="legend-item"><span class="color-dot dot-overweight"></span>超重</div>
        <div class="legend-item"><span class="color-dot dot-obese"></span>肥胖</div>
        <span style="margin-left:auto; color:#3e6a97;">💡 半岁年龄精确查表 · 伤病部位合并展示</span>
    </div>

    <!-- 饼图 + 伤病排名卡片区域 (动态填充) -->
    <div class="stats-grid" id="statsGrid">
        <!-- 身高等级饼图占位 -->
        <div class="chart-card">
            <h3>📈 身高等级分布</h3>
            <div class="canvas-wrapper">
                <canvas id="heightChart" width="300" height="200"></canvas>
            </div>
            <div style="font-size:0.8rem; color:#3f688b; text-align:center; margin-top:8px;">点击图例可隐藏</div>
        </div>
        <!-- 超重/肥胖饼图占位 -->
        <div class="chart-card">
            <h3>⚖️ 超重/肥胖分布</h3>
            <div class="canvas-wrapper">
                <canvas id="bmiChart" width="300" height="200"></canvas>
            </div>
            <div style="font-size:0.8rem; color:#3f688b; text-align:center; margin-top:8px;">点击图例可隐藏</div>
        </div>
        <!-- 伤病频次排名卡片 (将用JS填充) -->
        <div class="injury-rank-card" id="injuryRankContainer">
            <!-- 动态生成内容 -->
        </div>
    </div>

    <!-- 表格容器 可横向滚动 -->
    <div class="table-wrapper">
        <table>
            <thead>
                <tr>
                    <th>姓名</th><th>性别</th><th>年龄(岁)</th><th>身高(cm)</th><th>体重(kg)</th><th>BMI</th>
                    <th>身高等级</th><th>超重/肥胖</th><th>坐高(cm)</th><th>坐高/身高</th><th>臂展(cm)</th><th>臂展/身高</th>
                    <th>左握力</th><th>右握力</th><th>左大腿长</th><th>右大腿长</th><th>ADAM</th><th>PAPQ+</th><th>伤病部位</th>
                </tr>
            </thead>
            <tbody id="data-table-body">
                <!-- 由JavaScript动态填充,基于2026-02-07重新计算 -->
            </tbody>
        </table>
    </div>

    <div class="footer-note">
        ⭐ 身高发育等级基于实足年龄取整查表 (WS/T 612) · 超重/肥胖依据半岁年龄精确匹配界值 (WS/T 586) · 臂展/身高、坐高/身高均为实测比值 · “—”表示无伤病或测试阴性。
    </div>
</div>

<script>
(function() {
    // ---------- 固定基准日期:2026年2月7日 ----------
    const BASE_DATE = new Date(2026, 1, 7);  // 月份0-index, 1表示2月

    // ---------- 原始数据 ----------
    const rawData = [
        { name:"丁时安", sex:"男", birth:"2016.05.06", height:134, sittingH:70, weight:33.1, gripL:6.1, gripR:6.7, armSpan:133, thighL:64, thighR:65, adam:"-", papq:"-", inj1:"膝", inj2:"", inj3:"", inj4:"", inj5:"" },
        { name:"金宜晨", sex:"男", birth:"2013.11.27", height:156.5, sittingH:83, weight:50.3, gripL:23, gripR:24, armSpan:160, thighL:81, thighR:81.5, adam:"-", papq:"-", inj1:"", inj2:"", inj3:"", inj4:"", inj5:"" },
        { name:"金宇晨", sex:"男", birth:"2013.11.27", height:154.5, sittingH:83, weight:45.6, gripL:22.2, gripR:20.7, armSpan:166, thighL:74, thighR:74, adam:"-", papq:"-", inj1:"膝", inj2:"", inj3:"", inj4:"", inj5:"" },
        { name:"张云皓", sex:"男", birth:"2013.05.09", height:152.5, sittingH:83, weight:48.7, gripL:17.9, gripR:18.8, armSpan:157, thighL:78, thighR:77, adam:"-", papq:"-", inj1:"脚踝", inj2:"", inj3:"", inj4:"", inj5:"" },
        { name:"郭景曦", sex:"男", birth:"2013.02.25", height:181, sittingH:98, weight:64.6, gripL:24.6, gripR:23.5, armSpan:180, thighL:91, thighR:91, adam:"-", papq:"-", inj1:"", inj2:"", inj3:"", inj4:"", inj5:"" },
        { name:"张祺又", sex:"男", birth:"2015.06.29", height:148, sittingH:78, weight:39.2, gripL:9.5, gripR:10.2, armSpan:147, thighL:77, thighR:77, adam:"-", papq:"-", inj1:"", inj2:"", inj3:"", inj4:"", inj5:"" },
        { name:"张之予", sex:"女", birth:"2013.05.24", height:165.5, sittingH:83, weight:56.9, gripL:16.6, gripR:15.2, armSpan:165, thighL:88, thighR:88, adam:"-", papq:"-", inj1:"膝", inj2:"", inj3:"", inj4:"", inj5:"" },
        { name:"许恩骁", sex:"男", birth:"2012.02.03", height:178.5, sittingH:98, weight:82, gripL:28.8, gripR:34, armSpan:176, thighL:93, thighR:93, adam:"-", papq:"-", inj1:"腕", inj2:"", inj3:"", inj4:"", inj5:"" },
        { name:"邵丛锐", sex:"男", birth:"2013.05.07", height:155.5, sittingH:81.5, weight:42.6, gripL:21.7, gripR:20.4, armSpan:157, thighL:79, thighR:79, adam:"-", papq:"-", inj1:"腕", inj2:"", inj3:"", inj4:"", inj5:"" },
        { name:"许芮铭", sex:"男", birth:"2013.02.20", height:159, sittingH:83, weight:60.8, gripL:18.4, gripR:22, armSpan:165, thighL:84.5, thighR:84.5, adam:"-", papq:"-", inj1:"肘", inj2:"", inj3:"", inj4:"", inj5:"" },
        { name:"梁书源", sex:"男", birth:"2012.03.08", height:164.5, sittingH:86.5, weight:49.3, gripL:27.5, gripR:28.4, armSpan:163, thighL:83, thighR:82, adam:"-", papq:"-", inj1:"腰", inj2:"肘", inj3:"腕", inj4:"髋", inj5:"踝" },
        { name:"卢紫铭", sex:"男", birth:"2012.09.30", height:172.5, sittingH:91, weight:80.3, gripL:31.3, gripR:32.2, armSpan:178, thighL:88, thighR:88, adam:"-", papq:"+", inj1:"", inj2:"", inj3:"", inj4:"", inj5:"" },
        { name:"陈迦杰", sex:"男", birth:"2012.11.12", height:177.5, sittingH:91.5, weight:68.5, gripL:26.3, gripR:32.8, armSpan:178, thighL:96, thighR:96, adam:"-", papq:"-", inj1:"", inj2:"", inj3:"", inj4:"", inj5:"" },
        { name:"王亦菲", sex:"女", birth:"2011.11.02", height:160.5, sittingH:83.5, weight:43.3, gripL:19.3, gripR:22.2, armSpan:159, thighL:85, thighR:85, adam:"-", papq:"-", inj1:"", inj2:"", inj3:"", inj4:"", inj5:"" },
        { name:"张苏然", sex:"女", birth:"2015.03.21", height:140.5, sittingH:80, weight:37.4, gripL:11.5, gripR:12, armSpan:136, thighL:73, thighR:73, adam:"-", papq:"-", inj1:"", inj2:"", inj3:"", inj4:"", inj5:"" },
        { name:"许芮瑜", sex:"女", birth:"2010.01.12", height:167, sittingH:88, weight:56.5, gripL:17.4, gripR:20, armSpan:168, thighL:88, thighR:88, adam:"-", papq:"-", inj1:"肘", inj2:"腕", inj3:"膝", inj4:"踝", inj5:"" },
        { name:"田思远", sex:"女", birth:"2014.11.19", height:158, sittingH:83, weight:42.7, gripL:15.9, gripR:24.2, armSpan:162, thighL:86, thighR:86, adam:"-", papq:"-", inj1:"肩", inj2:"", inj3:"", inj4:"", inj5:"" }
    ];

    // ---------- 身高发育等级界值 ----------
    const heightTables = {
        male: {
            7:  [113.5, 119.49, 125.48, 131.47, 137.46],
            8:  [118.35, 124.53, 130.72, 136.90, 143.08],
            9:  [122.74, 129.27, 135.81, 142.35, 148.88],
            10: [126.79, 133.77, 140.76, 147.75, 154.74],
            11: [130.39, 138.20, 146.01, 153.82, 161.64],
            12: [134.48, 143.33, 152.18, 161.03, 169.89],
            13: [143.01, 151.60, 160.19, 168.78, 177.38],
            14: [150.22, 157.93, 165.63, 173.34, 181.05],
            15: [155.25, 162.14, 169.02, 175.91, 182.79],
            16: [157.72, 164.15, 170.58, 177.01, 183.44],
            17: [158.76, 165.07, 171.39, 177.70, 184.01],
            18: [158.81, 165.12, 171.42, 177.73, 184.03]
        },
        female: {
            7:  [112.29, 118.21, 124.13, 130.05, 135.97],
            8:  [116.83, 123.09, 129.34, 135.59, 141.84],
            9:  [121.31, 128.11, 134.91, 141.71, 148.51],
            10: [126.38, 133.78, 141.18, 148.57, 155.97],
            11: [132.09, 139.72, 147.36, 154.99, 162.63],
            12: [138.11, 145.26, 152.41, 159.56, 166.71],
            13: [143.75, 149.91, 156.07, 162.23, 168.39],
            14: [146.18, 151.98, 157.78, 163.58, 169.38],
            15: [147.02, 152.74, 158.47, 164.19, 169.91],
            16: [147.59, 153.26, 158.93, 164.60, 170.27],
            17: [147.82, 153.50, 159.18, 164.86, 170.54],
            18: [148.54, 154.28, 160.01, 165.74, 171.48]
        }
    };

    // ---------- BMI超重/肥胖界值 ----------
    const bmiTable = {
        male: {
            6.0: [16.4, 17.7], 6.5: [16.7, 18.1], 7.0: [17.0, 18.7], 7.5: [17.4, 19.2],
            8.0: [17.8, 19.7], 8.5: [18.1, 20.3], 9.0: [18.5, 20.8], 9.5: [18.9, 21.4],
            10.0: [19.2, 21.9], 10.5: [19.6, 22.5], 11.0: [19.9, 23.0], 11.5: [20.3, 23.6],
            12.0: [20.7, 24.1], 12.5: [21.0, 24.7], 13.0: [21.4, 25.2], 13.5: [21.9, 25.7],
            14.0: [22.3, 26.1], 14.5: [22.6, 26.4], 15.0: [22.9, 26.6], 15.5: [23.1, 26.9],
            16.0: [23.3, 27.1], 16.5: [23.5, 27.4], 17.0: [23.7, 27.6], 17.5: [23.8, 27.8],
            18.0: [24.0, 28.0]
        },
        female: {
            6.0: [16.2, 17.5], 6.5: [16.5, 18.0], 7.0: [16.8, 18.5], 7.5: [17.2, 19.0],
            8.0: [17.6, 19.4], 8.5: [18.1, 19.9], 9.0: [18.5, 20.4], 9.5: [19.0, 21.0],
            10.0: [19.5, 21.5], 10.5: [20.0, 22.1], 11.0: [20.5, 22.7], 11.5: [21.1, 23.3],
            12.0: [21.5, 23.9], 12.5: [21.9, 24.5], 13.0: [22.2, 25.0], 13.5: [22.6, 25.6],
            14.0: [22.8, 25.9], 14.5: [23.0, 26.3], 15.0: [23.2, 26.6], 15.5: [23.4, 26.9],
            16.0: [23.6, 27.1], 16.5: [23.7, 27.4], 17.0: [23.8, 27.6], 17.5: [23.9, 27.8],
            18.0: [24.0, 28.0]
        }
    };

    // ---------- 辅助函数 ----------
    function parseBirth(birthStr) {
        let parts = birthStr.split('.').map(Number);
        return new Date(parts[0], parts[1]-1, parts[2]);
    }
    function computeExactAge(birthDate, baseDate) {
        return (baseDate - birthDate) / (1000 * 60 * 60 * 24 * 365.25);
    }
    function getHeightLevel(sex, ageYears, height) {
        let intAge = Math.floor(ageYears);
        if (intAge < 7) intAge = 7;
        if (intAge > 18) intAge = 18;
        let table = sex === '男' ? heightTables.male : heightTables.female;
        let row = table[intAge];
        if (!row) return '数据缺失';
        let [m2sd, m1sd, median, p1sd, p2sd] = row;
        if (height < m2sd) return '下等';
        if (height >= m2sd && height < m1sd) return '中下等';
        if (height >= m1sd && height <= p1sd) return '中等';
        if (height > p1sd && height <= p2sd) return '中上等';
        if (height > p2sd) return '上等';
        return '中等';
    }
    function getWeightStatus(sex, exactAge, bmi) {
        let halfFloor = Math.floor(exactAge * 2) / 2;
        if (halfFloor < 6.0) halfFloor = 6.0;
        if (halfFloor > 18.0) halfFloor = 18.0;
        let table = sex === '男' ? bmiTable.male : bmiTable.female;
        let thresholds = table[halfFloor];
        if (!thresholds) return '参考缺失';
        let [overThresh, obeseThresh] = thresholds;
        if (bmi >= obeseThresh) return '肥胖';
        if (bmi >= overThresh) return '超重';
        return '正常';
    }
    function mergeInjuries(item) {
        let parts = [item.inj1, item.inj2, item.inj3, item.inj4, item.inj5];
        return parts.filter(p => p && p.trim() !== '').join(', ') || '—';
    }

    // 计算所有行
    const rows = [];
    rawData.forEach(p => {
        let birth = parseBirth(p.birth);
        let exactAge = computeExactAge(birth, BASE_DATE);
        let heightM = p.height / 100;
        let bmi = p.weight / (heightM * heightM);
        bmi = Math.round(bmi * 10) / 10;
        let heightLevel = getHeightLevel(p.sex, exactAge, p.height);
        let weightStatus = getWeightStatus(p.sex, exactAge, bmi);
        let sittingRatio = p.sittingH / p.height;
        let armRatio = p.armSpan / p.height;
        let ageDisplay = exactAge.toFixed(1);
        let injuries = mergeInjuries(p);
        rows.push({
            ...p,
            ageDisplay,
            bmi,
            heightLevel,
            weightStatus,
            sittingRatio: sittingRatio.toFixed(3),
            armRatio: armRatio.toFixed(3),
            injuries
        });
    });

    // 渲染表格
    const tbody = document.getElementById('data-table-body');
    rows.forEach(r => {
        let tr = document.createElement('tr');
        let heightClass = '';
        if (r.heightLevel === '下等') heightClass = 'height-low';
        else if (r.heightLevel === '中下等') heightClass = 'height-midlow';
        else if (r.heightLevel === '中等') heightClass = 'height-mid';
        else if (r.heightLevel === '中上等') heightClass = 'height-midhigh';
        else if (r.heightLevel === '上等') heightClass = 'height-high';

        let weightClass = '';
        if (r.weightStatus === '正常') weightClass = 'weight-normal';
        else if (r.weightStatus === '超重') weightClass = 'weight-overweight';
        else if (r.weightStatus === '肥胖') weightClass = 'weight-obese';

        tr.innerHTML = `
            <td style="font-weight:600;">${r.name}</td>
            <td>${r.sex}</td>
            <td>${r.ageDisplay}</td>
            <td>${r.height}</td>
            <td>${r.weight}</td>
            <td class="mono">${r.bmi}</td>
            <td><span class="badge ${heightClass}">${r.heightLevel}</span></td>
            <td><span class="badge ${weightClass}">${r.weightStatus}</span></td>
            <td>${r.sittingH}</td>
            <td>${r.sittingRatio}</td>
            <td>${r.armSpan}</td>
            <td>${r.armRatio}</td>
            <td>${r.gripL}</td>
            <td>${r.gripR}</td>
            <td>${r.thighL}</td>
            <td>${r.thighR}</td>
            <td>${r.adam}</td>
            <td>${r.papq}</td>
            <td style="max-width:200px; white-space:normal; word-break:break-word;">${r.injuries.split(',').map(i => `<span class="injury-tag">${i.trim()}</span>`).join(' ')}</td>
        `;
        tbody.appendChild(tr);
    });

    // ---------- 统计身高等级分布 ----------
    const heightCount = {
        '下等': 0, '中下等': 0, '中等': 0, '中上等': 0, '上等': 0
    };
    rows.forEach(r => { if (heightCount.hasOwnProperty(r.heightLevel)) heightCount[r.heightLevel]++; });

    // ---------- 统计超重/肥胖分布 ----------
    const weightCount = {
        '正常': 0, '超重': 0, '肥胖': 0
    };
    rows.forEach(r => { if (weightCount.hasOwnProperty(r.weightStatus)) weightCount[r.weightStatus]++; });

    // ---------- 伤病部位频次统计并排名 ----------
    const injuryMap = new Map();
    rows.forEach(r => {
        if (r.injuries && r.injuries !== '—') {
            r.injuries.split(',').map(s => s.trim()).filter(s => s).forEach(part => {
                injuryMap.set(part, (injuryMap.get(part) || 0) + 1);
            });
        }
    });
    const sortedInjuries = Array.from(injuryMap.entries()).sort((a, b) => b[1] - a[1]);

    // 填充伤病排名卡片
    const injuryContainer = document.getElementById('injuryRankContainer');
    if (sortedInjuries.length === 0) {
        injuryContainer.innerHTML = `
            <h3>📋 伤病部位频次排名</h3>
            <div style="padding:20px; text-align:center; color:#5d7f9f;">暂无伤病记录</div>
        `;
    } else {
        let rankHtml = `
            <h3>📋 伤病部位频次排名</h3>
            <table class="injury-rank-table">
                <thead><tr><th>排名</th><th>部位</th><th>出现次数</th></tr></thead>
                <tbody>
        `;
        sortedInjuries.forEach(([part, count], index) => {
            rankHtml += `
                <tr>
                    <td><span class="rank-number">${index+1}</span></td>
                    <td style="font-weight:500;">${part}</td>
                    <td><span class="injury-count-badge">${count}</span></td>
                </tr>
            `;
        });
        rankHtml += `</tbody></table>`;
        injuryContainer.innerHTML = rankHtml;
    }

    // ---------- 绘制饼图 ----------
    // 身高等级饼图
    const ctxHeight = document.getElementById('heightChart').getContext('2d');
    new Chart(ctxHeight, {
        type: 'pie',
        data: {
            labels: ['下等', '中下等', '中等', '中上等', '上等'],
            datasets: [{
                data: [
                    heightCount['下等'],
                    heightCount['中下等'],
                    heightCount['中等'],
                    heightCount['中上等'],
                    heightCount['上等']
                ],
                backgroundColor: ['#b22234', '#f4a261', '#2a9d8f', '#8ecae6', '#ffb703'],
                borderColor: 'white',
                borderWidth: 2,
            }]
        },
        options: {
            responsive: true,
            maintainAspectRatio: false,
            plugins: {
                legend: { position: 'bottom', labels: { boxWidth: 12, font: { size: 11 } } },
                tooltip: { callbacks: { label: (ctx) => `${ctx.label}: ${ctx.raw}人 (${((ctx.raw/rows.length)*100).toFixed(1)}%)` } }
            }
        }
    });

    // 超重/肥胖饼图
    const ctxBmi = document.getElementById('bmiChart').getContext('2d');
    new Chart(ctxBmi, {
        type: 'pie',
        data: {
            labels: ['正常', '超重', '肥胖'],
            datasets: [{
                data: [weightCount['正常'], weightCount['超重'], weightCount['肥胖']],
                backgroundColor: ['#60a847', '#f48c06', '#d00000'],
                borderColor: 'white',
                borderWidth: 2,
            }]
        },
        options: {
            responsive: true,
            maintainAspectRatio: false,
            plugins: {
                legend: { position: 'bottom', labels: { boxWidth: 12, font: { size: 11 } } },
                tooltip: { callbacks: { label: (ctx) => `${ctx.label}: ${ctx.raw}人 (${((ctx.raw/rows.length)*100).toFixed(1)}%)` } }
            }
        }
    });
})();
</script>
</body>
</html>
跳至内容