<!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 身高发育等级 | WS/T 586—2018 超重/肥胖筛查 | 原始数据来自 <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>