feat: 体重管理页面更新,删除 detail-data.html

This commit is contained in:
liuyunqin
2026-08-04 10:44:53 +08:00
parent d7ca18766e
commit c8606b37f5
10 changed files with 99 additions and 1040 deletions
-1
View File
@@ -238,7 +238,6 @@ const SITE_MAP = [
{ file:'action-record.html', label:'行动记录' },
{ file:'action-overview.html', label:'活动总览' },
{ file:'action-overview-detail.html', label:'赛况明细' },
{ file:'detail-data.html', label:'详细数据' },
{ file:'weight-ranking.html', label:'体重排名' },
{ file:'activity-statistics.html', label:'活动统计' },
{ file:'history-plan-list.html', label:'历史干预-计划列表' },
@@ -78,7 +78,7 @@ body{font-family:-apple-system,BlinkMacSystemFont,'PingFang SC','Microsoft YaHei
/* 表格卡片 */
.table-card{background:#fff;border-radius:var(--radius-md);box-shadow:var(--shadow-sm);overflow:hidden;}
.table-card__content{overflow-x:auto;-webkit-overflow-scrolling:touch;}
.table-card__content table{min-width:2400px;white-space:nowrap;}
.table-card__content table{min-width:1600px;white-space:nowrap;}
table{width:100%;border-collapse:collapse;}
/* 表头 - 两行结构 */
@@ -97,10 +97,7 @@ thead th:nth-child(2){z-index:9;background:#FAFAFA;}
tbody tr:hover td:nth-child(2){background:#F8FBFF;}
/* 吃动热量差列 */
.col-diet-last{border-right:2px solid var(--border) !important;}
.col-exercise-last{border-right:2px solid var(--border) !important;}
.td-empty{text-align:center;padding:48px 0;color:var(--text-placeholder);font-size:var(--font-sm);}
.td-empty{text-align:center;padding:48px 0;color:var(--text-placeholder);font-size:var(--font-sm);}
/* 变化值颜色 */
.change-up{color:var(--danger);}
@@ -150,7 +147,8 @@ tbody tr:hover td:nth-child(2){background:#F8FBFF;}
<aside class="sidebar">
<div class="sidebar-menu__title">过程管理</div>
<a href="action-record.html" class="sidebar-item">行动记录</a>
<a href="detail-data.html" class="sidebar-item">详细数据</a>
<a href="weight-ranking.html" class="sidebar-item">体重排名</a>
<a href="action-overview.html" class="sidebar-item active">活动总览</a>
<a href="activity-statistics.html" class="sidebar-item">活动统计</a>
@@ -185,9 +183,16 @@ tbody tr:hover td:nth-child(2){background:#F8FBFF;}
<div class="info-item"><span class="info-item__label">年龄:</span><span class="info-item__value" id="eiAge">-</span></div>
<div class="info-item"><span class="info-item__label">单位部门:</span><span class="info-item__value" id="eiDept">-</span></div>
<div class="info-item"><span class="info-item__label">身高:</span><span class="info-item__value" id="eiHeight">- cm</span></div>
</div>
</div>
</div>
</div>
</div>
<div class="info-card">
<div class="info-card__title">体重指标</div>
<div class="info-card__body" id="metricCard">
<div class="info-item"><span class="info-item__label">初始:</span><span class="info-item__value">体重 <b id="miInitWeight">-</b> kg | BMI <b id="miInitBmi">-</b> | 体脂 <b id="miInitFat">-</b>% | 腰围 <b id="miInitWaist">-</b> cm</span></div>
<div class="info-item"><span class="info-item__label">目标:</span><span class="info-item__value">体重 <b id="miTargetWeight">-</b> kg | BMI <b id="miTargetBmi">-</b> | 体脂 <b id="miTargetFat">-</b>% | 腰围 <b id="miTargetWaist">-</b> cm</span></div>
</div>
</div>
</div>
<!-- [交互] 操作按钮区 -->
<div class="action-bar">
@@ -217,44 +222,25 @@ tbody tr:hover td:nth-child(2){background:#F8FBFF;}
<div class="table-card" style="border-radius:0 0 var(--radius-md) var(--radius-md);">
<div class="table-card__content">
<table>
<thead>
<!-- [交互] 表头第一行:父级分类 -->
<thead>
<tr>
<th rowspan="2">序号</th>
<th rowspan="2">日期</th>
<th rowspan="2">身高<br>(cm)</th>
<th rowspan="2">初始<br>体重(kg)</th>
<th rowspan="2">初始<br>BMI</th>
<th rowspan="2">初始<br>体脂(%)</th>
<th rowspan="2">初始<br>腰围(cm)</th>
<th rowspan="2">目标<br>体重(kg)</th>
<th rowspan="2">目标<br>BMI</th>
<th rowspan="2">目标<br>体脂(%)</th>
<th rowspan="2">目标<br>腰围(cm)</th>
<th rowspan="2">现体重<br>(kg)</th>
<th rowspan="2">现BMI</th>
<th rowspan="2">现体脂<br>(%)</th>
<th rowspan="2">现腰围<br>(cm)</th>
<th rowspan="2">体重变化<br>(kg)</th>
<th rowspan="2">BMI变化</th>
<th rowspan="2">体脂变化<br>(%)</th>
<th rowspan="2">腰围变化<br>(cm)</th>
<th class="th-parent" colspan="4">摄入数据(千卡)</th>
<th class="th-parent" colspan="3">消耗数据(千卡)</th>
<th rowspan="2">吃动热量差<br>(千卡)</th>
<th rowspan="2">当日减重<br>排名</th>
</tr>
<!-- [交互] 表头第二行:子列 -->
<tr>
<th>早餐</th>
<th>午餐</th>
<th>晚餐</th>
<th class="col-diet-last">加餐</th>
<th>基础消耗</th>
<th>步数</th>
<th class="col-exercise-last">其他消耗</th>
</tr>
</thead>
<th>序号</th>
<th>日期</th>
<th>身高<br>(cm)</th>
<th>体重<br>(kg)</th>
<th>BMI</th>
<th>体脂<br>(%)</th>
<th>腰围<br>(cm)</th>
<th>体重变化<br>(kg)</th>
<th>BMI变化</th>
<th>体脂变化<br>(%)</th>
<th>腰围变化<br>(cm)</th>
<th>摄入<br>(千卡)</th>
<th>消耗<br>(千卡)</th>
<th>吃动热量差<br>(千卡)</th>
<th>当日减重<br>排名</th>
</tr>
</thead>
<tbody id="tableBody"></tbody>
</table>
</div>
@@ -393,19 +379,26 @@ function buildDetailData(emp){
// 吃动热量差 = 摄入 - 消耗
var balance = totalIntake - totalBurn;
// 当日减重排名(1-20之间随机)
var rank = Math.floor(Math.random() * 20) + 1;
// 当日减重排名(1-20之间随机)
var rank = Math.floor(Math.random() * 20) + 1;
data.push({
// 体重记录(最新测量值,带轻微波动)
var latestWeight = +(curWeight + (Math.random() - 0.3) * 0.5).toFixed(1);
var latestFat = +(curFat + (Math.random() - 0.5) * 0.4).toFixed(1);
var latestWaist = Math.round(curWaist + (Math.random() - 0.5) * 1);
data.push({
date: dateStr,
height: emp.height,
initWeight: emp.weight, initBmi: emp.bmi, initFat: emp.fat, initWaist: emp.waist,
targetWeight: targetWeight, targetBmi: targetBmi, targetFat: targetFat, targetWaist: targetWaist,
curWeight: curWeight, curBmi: curBmi, curFat: curFat, curWaist: curWaist,
weightChange: wChange, bmiChange: bChange, fatChange: fChange, waistChange: waChange,
breakfast: breakfast, lunch: lunch, dinner: dinner, snack: snack,
basalMetab: basalMetab, stepBurn: stepBurn, otherBurn: otherBurn,
balance: balance, rank: rank
breakfast: breakfast, lunch: lunch, dinner: dinner, snack: snack,
basalMetab: basalMetab, stepBurn: stepBurn, otherBurn: otherBurn,
totalIntake: totalIntake, totalBurn: totalBurn,
balance: balance, rank: rank,
latestWeight: latestWeight, latestFat: latestFat, latestWaist: latestWaist
});
}
return data;
@@ -427,6 +420,19 @@ function renderInfoCards(){
document.getElementById('eiAge').textContent = employee.age + ' 岁';
document.getElementById('eiDept').textContent = employee.org + ' / ' + employee.dept;
document.getElementById('eiHeight').textContent = employee.height + ' cm';
// 体重指标(初始 + 目标)
var targetWeight = Math.round(employee.weight * 0.85);
var targetBmi = +(employee.bmi * 0.85).toFixed(1);
var targetWaist = Math.round(employee.waist * 0.88);
var targetFat = +(employee.fat * 0.80).toFixed(1);
document.getElementById('miInitWeight').textContent = employee.weight;
document.getElementById('miInitBmi').textContent = employee.bmi;
document.getElementById('miInitFat').textContent = employee.fat;
document.getElementById('miInitWaist').textContent = employee.waist;
document.getElementById('miTargetWeight').textContent = targetWeight;
document.getElementById('miTargetBmi').textContent = targetBmi;
document.getElementById('miTargetFat').textContent = targetFat;
document.getElementById('miTargetWaist').textContent = targetWaist;
}
/* ===== 日期筛选 ===== */
@@ -616,7 +622,7 @@ function renderTable(){
document.getElementById('pageNum').textContent = '第 ' + (currentPage + 1) + '/' + totalPages + ' 页';
if(filtered.length === 0){
tbody.innerHTML = '<tr><td colspan="28" class="td-empty">暂无匹配的每日明细数据</td></tr>';
tbody.innerHTML = '<tr><td colspan="15" class="td-empty">暂无匹配的每日明细数据</td></tr>';
return;
}
@@ -645,32 +651,19 @@ function renderTable(){
html += '<tr>';
html += '<td>'+(i+1)+'</td>';
html += '<td>'+esc(d.date)+'</td>';
html += '<td>'+d.height+'</td>';
html += '<td>'+d.initWeight+'</td>';
html += '<td>'+d.initBmi.toFixed(1)+'</td>';
html += '<td>'+d.initFat.toFixed(1)+'</td>';
html += '<td>'+d.initWaist+'</td>';
html += '<td>'+d.targetWeight+'</td>';
html += '<td>'+d.targetBmi+'</td>';
html += '<td>'+d.targetFat+'</td>';
html += '<td>'+d.targetWaist+'</td>';
html += '<td>'+d.curWeight+'</td>';
html += '<td>'+d.curBmi.toFixed(1)+'</td>';
html += '<td>'+d.curFat.toFixed(1)+'</td>';
html += '<td>'+d.curWaist+'</td>';
html += '<td class="'+wcCls+'">'+wcSign+d.weightChange+'</td>';
html += '<td class="'+bcCls+'">'+bcSign+d.bmiChange+'</td>';
html += '<td class="'+fcCls+'">'+fcSign+d.fatChange+'</td>';
html += '<td class="'+wacCls+'">'+wacSign+d.waistChange+'</td>';
// 摄入数据
html += '<td>'+d.breakfast+'</td>';
html += '<td>'+d.lunch+'</td>';
html += '<td>'+d.dinner+'</td>';
html += '<td class="col-diet-last">'+d.snack+'</td>';
// 消耗数据
html += '<td>'+d.basalMetab+'</td>';
html += '<td>'+d.stepBurn+'</td>';
html += '<td class="col-exercise-last">'+d.otherBurn+'</td>';
html += '<td>'+d.height+'</td>';
html += '<td>'+d.curWeight+'</td>';
html += '<td>'+d.curBmi.toFixed(1)+'</td>';
html += '<td>'+d.curFat.toFixed(1)+'</td>';
html += '<td>'+d.curWaist+'</td>';
html += '<td class="'+wcCls+'">'+wcSign+d.weightChange+'</td>';
html += '<td class="'+bcCls+'">'+bcSign+d.bmiChange+'</td>';
html += '<td class="'+fcCls+'">'+fcSign+d.fatChange+'</td>';
html += '<td class="'+wacCls+'">'+wacSign+d.waistChange+'</td>';
// 摄入
html += '<td>'+d.totalIntake+'</td>';
// 消耗
html += '<td>'+d.totalBurn+'</td>';
// 吃动热量差
html += '<td class="'+balCls+'">'+balSign+d.balance+'</td>';
// 当日减重排名
@@ -175,9 +175,8 @@ tbody tr:hover td:last-child{background:#F8FBFF;}
<!-- 侧边栏 -->
<aside class="sidebar">
<div class="sidebar-menu__title">过程管理</div>
<a href="action-record.html" class="sidebar-item">行动记录</a>
<a href="detail-data.html" class="sidebar-item">详细数据</a>
<a href="weight-ranking.html" class="sidebar-item">体重排名</a>
<a href="action-record.html" class="sidebar-item">行动记录</a>
<a href="weight-ranking.html" class="sidebar-item">体重排名</a>
<a href="action-overview.html" class="sidebar-item active">活动总览</a>
<a href="activity-statistics.html" class="sidebar-item">活动统计</a>
<a href="recipe-record.html" class="sidebar-item">食堂食谱</a>
@@ -269,9 +269,8 @@ tbody tr:hover td:nth-child(4){background:#F8FBFF;}
<!-- 侧边栏 -->
<aside class="sidebar">
<div class="sidebar-menu__title">过程管理</div>
<a href="action-record.html" class="sidebar-item active">行动记录</a>
<a href="detail-data.html" class="sidebar-item">详细数据</a>
<a href="weight-ranking.html" class="sidebar-item">体重排名</a>
<a href="action-record.html" class="sidebar-item active">行动记录</a>
<a href="weight-ranking.html" class="sidebar-item">体重排名</a>
<a href="action-overview.html" class="sidebar-item">活动总览</a>
<a href="activity-statistics.html" class="sidebar-item">活动统计</a>
<a href="recipe-record.html" class="sidebar-item">食堂食谱</a>
@@ -160,9 +160,8 @@ tbody tr:hover{background:#F8FBFF;}
<!-- 侧边栏 -->
<aside class="sidebar">
<div class="sidebar-menu__title">过程管理</div>
<a href="action-record.html" class="sidebar-item">行动记录</a>
<a href="detail-data.html" class="sidebar-item">详细数据</a>
<a href="weight-ranking.html" class="sidebar-item">体重排名</a>
<a href="action-record.html" class="sidebar-item">行动记录</a>
<a href="weight-ranking.html" class="sidebar-item">体重排名</a>
<a href="action-overview.html" class="sidebar-item">活动总览</a>
<a href="activity-statistics.html" class="sidebar-item active">活动统计</a>
<a href="recipe-record.html" class="sidebar-item">食堂食谱</a>
@@ -1,889 +0,0 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>详细数据 | 体重管理</title>
<style>
*{box-sizing:border-box;margin:0;padding:0;}
body{font-family:-apple-system,BlinkMacSystemFont,'PingFang SC','Microsoft YaHei',sans-serif;background:#F5F7FA;color:#333;min-width:1280px;}
:root{
--primary:#1890FF;--primary-light:#E6F7FF;--success:#52C41A;--warning:#FAAD14;--danger:#FF4D4F;
--text-primary:#333;--text-secondary:#666;--text-placeholder:#999;--border:#E8E8E8;--background:#F5F7FA;
--font-xs:11px;--font-sm:13px;--font-base:15px;--font-lg:17px;
--radius-sm:4px;--radius-md:8px;--radius-lg:12px;
--shadow-sm:0 1px 4px rgba(0,0,0,0.08);--shadow-md:0 4px 12px rgba(0,0,0,0.10);
}
/* 顶部导航栏 */
.top-bar{display:flex;align-items:center;height:56px;background:#001529;padding:0 24px;position:fixed;top:0;left:0;right:0;z-index:100;}
.top-bar__logo{display:flex;align-items:center;gap:8px;color:#fff;font-size:var(--font-lg);font-weight:600;white-space:nowrap;width:240px;flex-shrink:0;}
.top-bar__logo svg{width:28px;height:28px;}
.top-bar__nav{display:flex;align-items:center;gap:4px;flex:1;}
.top-bar__nav a{color:rgba(255,255,255,0.65);text-decoration:none;padding:6px 16px;border-radius:var(--radius-sm);font-size:var(--font-sm);transition:all .2s;}
.top-bar__nav a:hover{color:#fff;background:rgba(255,255,255,0.08);}
.top-bar__nav a.active{color:#fff;background:var(--primary);}
.top-bar__right{display:flex;align-items:center;gap:16px;color:rgba(255,255,255,0.65);font-size:var(--font-sm);}
.btn-back{color:rgba(255,255,255,0.65);cursor:pointer;display:flex;align-items:center;gap:4px;text-decoration:none;}
.btn-back:hover{color:#fff;}
.avatar{width:32px;height:32px;border-radius:50%;background:#1890FF;display:flex;align-items:center;justify-content:center;color:#fff;font-size:var(--font-sm);cursor:pointer;}
/* 侧边栏 */
.sidebar{position:fixed;top:56px;left:0;bottom:0;width:240px;background:#001529;overflow-y:auto;z-index:90;padding-top:8px;}
.sidebar-menu__title{color:rgba(255,255,255,0.35);font-size:var(--font-xs);padding:16px 24px 8px;letter-spacing:.5px;}
.sidebar-item{display:flex;align-items:center;gap:8px;padding:10px 24px;color:rgba(255,255,255,0.65);font-size:var(--font-sm);cursor:pointer;transition:all .15s;text-decoration:none;}
.sidebar-item:hover{color:#fff;background:rgba(255,255,255,0.06);}
.sidebar-item.active{color:#fff;background:var(--primary);}
/* 主内容区 */
.main{margin-left:240px;margin-top:56px;padding:24px;min-height:calc(100vh - 56px);}
/* 页面标题 */
.page-header{margin-bottom:16px;}
.page-header__breadcrumb{font-size:var(--font-sm);color:var(--text-placeholder);}
.page-header__breadcrumb span{color:var(--text-primary);}
/* 搜索下拉 */
.search-select{position:relative;width:100%;}
.search-select__input{width:100%;height:40px;border:1px solid var(--border);border-radius:var(--radius-sm);padding:0 36px 0 12px;font-size:var(--font-sm);outline:none;transition:border-color .2s;box-sizing:border-box;background:#fff url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='7'%3E%3Cpath d='M0 0l6 7 6-7z' fill='%23999'/%3E%3C/svg%3E") no-repeat right 12px center;}
.search-select__input:focus{border-color:var(--primary);}
.search-select__input::placeholder{color:var(--text-placeholder);}
.search-select__panel{position:absolute;top:100%;left:0;right:0;margin-top:4px;background:#fff;border:1px solid var(--border);border-radius:var(--radius-md);box-shadow:var(--shadow-md);z-index:500;display:none;max-height:280px;overflow-y:auto;}
.search-select__panel.show{display:block;}
.search-select__option{padding:12px 16px;font-size:var(--font-sm);cursor:pointer;transition:background .1s;border-bottom:1px solid #F5F5F5;}
.search-select__option:last-child{border-bottom:none;}
.search-select__option:hover{background:#F5F7FA;}
.search-select__option.selected{color:var(--primary);background:var(--primary-light);}
.search-select__option .ss-org{font-size:var(--font-xs);color:var(--text-placeholder);margin-top:2px;}
.search-select__empty{padding:20px;text-align:center;color:var(--text-placeholder);font-size:var(--font-sm);}
.search-select__clear{position:absolute;right:8px;top:50%;transform:translateY(-50%);width:22px;height:22px;border:none;background:none;cursor:pointer;color:var(--text-placeholder);font-size:16px;display:none;align-items:center;justify-content:center;border-radius:50%;line-height:1;padding:0;z-index:1;}
.search-select__clear:hover{color:var(--text-primary);background:#F0F0F0;}
.search-select__clear.show{display:flex;}
.search-select--selected .search-select__input{background-image:none;padding-right:32px;}
/* 筛选栏 */
.filter-bar{background:#fff;padding:16px 24px;display:flex;align-items:center;gap:12px;flex-wrap:wrap;border-radius:var(--radius-md) var(--radius-md) 0 0;box-shadow:var(--shadow-sm);}
.filter-item{display:flex;align-items:center;gap:8px;}
.filter-item label{font-size:var(--font-xs);color:var(--text-secondary);white-space:nowrap;}
.filter-input{height:32px;border:1px solid var(--border);border-radius:var(--radius-sm);padding:0 10px;font-size:var(--font-xs);outline:none;transition:border-color .2s;box-sizing:border-box;}
.filter-input:focus{border-color:var(--primary);}
.filter-date{height:32px;border:1px solid var(--border);border-radius:var(--radius-sm);padding:0 10px;font-size:var(--font-xs);outline:none;transition:border-color .2s;box-sizing:border-box;color:var(--text-primary);}
.filter-date:focus{border-color:var(--primary);}
.filter-divider{color:var(--text-placeholder);font-size:var(--font-xs);margin:0 2px;}
/* 单位部门双列面板 */
.org-select-wrap{position:relative;display:inline-block;}
.org-trigger{height:32px;min-width:160px;border:1px solid var(--border);border-radius:var(--radius-sm);padding:0 28px 0 10px;font-size:var(--font-xs);color:var(--text-primary);background:#fff url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6'%3E%3Cpath d='M0 0l5 6 5-6z' fill='%23999'/%3E%3C/svg%3E") no-repeat right 8px center;cursor:pointer;display:flex;align-items:center;user-select:none;white-space:nowrap;}
.org-trigger.open,.org-trigger:hover{border-color:var(--primary);}
.org-panel{display:none;position:absolute;top:36px;left:0;z-index:300;background:#fff;border:1px solid var(--border);border-radius:var(--radius-sm);box-shadow:var(--shadow-md);width:420px;}
.org-panel.open{display:flex;}
.org-col{flex:1;overflow-y:auto;max-height:240px;border-right:1px solid var(--border);}
.org-col:last-child{border-right:none;}
.org-col__title{padding:8px 14px;font-size:var(--font-xs);color:var(--text-placeholder);background:#FAFAFA;border-bottom:1px solid var(--border);font-weight:500;}
.org-item{padding:9px 14px;font-size:var(--font-sm);color:var(--text-primary);cursor:pointer;display:flex;align-items:center;justify-content:space-between;gap:4px;}
.org-item:hover{background:#F0F8FF;color:var(--primary);}
.org-item.active{background:var(--primary-light);color:var(--primary);font-weight:500;}
/* 按钮 */
.btn{height:32px;padding:0 16px;border-radius:var(--radius-sm);font-size:var(--font-xs);cursor:pointer;border:none;transition:all .2s;display:inline-flex;align-items:center;gap:6px;white-space:nowrap;}
.btn-primary{background:var(--primary);color:#fff;}.btn-primary:hover{background:#40a9ff;}
.btn-default{background:#fff;color:var(--text-primary);border:1px solid var(--border);}.btn-default:hover{color:var(--primary);border-color:var(--primary);}
.btn-export{background:#fff;color:var(--text-primary);border:1px solid var(--border);}.btn-export:hover{color:var(--primary);border-color:var(--primary);}
/* 操作栏 */
.action-bar{display:flex;align-items:center;gap:8px;padding:16px 24px;background:#fff;border-top:1px solid var(--border);}
/* 表格卡片 */
.table-card{background:#fff;border-radius:0 0 var(--radius-md) var(--radius-md);box-shadow:var(--shadow-sm);overflow:hidden;}
.table-card__content{overflow-x:auto;-webkit-overflow-scrolling:touch;}
.table-card__content table{min-width:1600px;white-space:nowrap;}
table{width:100%;border-collapse:collapse;}
/* 表头 - 两行结构 */
thead th{background:#FAFAFA;padding:8px 4px;text-align:center;font-size:var(--font-xs);color:var(--text-secondary);font-weight:500;border-bottom:1px solid var(--border);white-space:nowrap;}
thead th.th-parent{background:#F0F2F5;font-weight:600;color:var(--text-primary);border-bottom:1px solid var(--border);}
thead th.th-divider{border-right:2px solid var(--border);}
tbody td{padding:10px 4px;text-align:center;font-size:var(--font-xs);color:var(--text-primary);border-bottom:1px solid #F0F0F0;white-space:nowrap;}
tbody tr:last-child td{border-bottom:none;}
tbody tr:hover{background:#F8FBFF;}
/* 左侧固定列:干预计划、姓名(序号列不固定) */
thead th:nth-child(2),tbody td:nth-child(2){position:sticky;left:0;z-index:6;background:#fff;width:200px;min-width:200px;max-width:200px;overflow:hidden;text-overflow:ellipsis;}
thead th:nth-child(2){z-index:9;background:#FAFAFA;}
thead th:nth-child(3),tbody td:nth-child(3){position:sticky;left:200px;z-index:5;background:#fff;width:60px;min-width:60px;max-width:60px;}
thead th:nth-child(3){z-index:8;background:#FAFAFA;}
thead th:nth-child(4),tbody td:nth-child(4){position:sticky;left:260px;z-index:4;background:#fff;width:88px;min-width:88px;max-width:88px;}
thead th:nth-child(4){z-index:7;background:#FAFAFA;}
tbody tr:hover td:nth-child(2),
tbody tr:hover td:nth-child(3),
tbody tr:hover td:nth-child(4){background:#F8FBFF;}
/* 右侧固定列:体重报告(操作列) */
thead tr:first-child th:last-child,tbody td:last-child{position:sticky;right:0;z-index:2;background:#fff;box-shadow:-2px 0 4px rgba(0,0,0,0.04);width:72px;min-width:72px;max-width:72px;}
thead tr:first-child th:last-child{z-index:4;background:#FAFAFA;}
thead tr:nth-child(2) th:last-child{background:#FAFAFA;}
tbody tr:hover td:last-child{background:#F8FBFF;}
/* 饮食、运动、体重子列分隔线 */
.col-diet-last{border-right:2px solid var(--border) !important;}
.col-exercise-last{border-right:2px solid var(--border) !important;}
.col-weight-last{border-right:2px solid var(--border) !important;}
.td-empty{text-align:center;padding:48px 0;color:var(--text-placeholder);font-size:var(--font-sm);}
/* 变化值颜色 */
.change-up{color:var(--danger);}
.change-down{color:var(--success);}
.change-zero{color:var(--text-placeholder);}
/* 分页 */
.pagination{display:flex;align-items:center;justify-content:flex-end;padding:16px 24px;gap:8px;border-top:1px solid var(--border);}
.pagination span{font-size:var(--font-sm);color:var(--text-secondary);}
.page-btn{width:32px;height:32px;border:1px solid var(--border);border-radius:var(--radius-sm);background:#fff;cursor:pointer;font-size:var(--font-sm);display:inline-flex;align-items:center;justify-content:center;transition:all .2s;}
.page-btn:hover,.page-btn.active{background:var(--primary);color:#fff;border-color:var(--primary);}
/* 链接 */
.link{color:var(--primary);cursor:pointer;font-size:var(--font-xs);text-decoration:none;}.link:hover{color:#40a9ff;}
/* Toast */
.toast{position:fixed;top:80px;left:50%;transform:translateX(-50%);background:#333;color:#fff;padding:10px 24px;border-radius:var(--radius-sm);font-size:var(--font-sm);z-index:9999;opacity:0;transition:opacity .2s;pointer-events:none;}
.toast.show{opacity:1;}
/* ===== 体重报告弹窗 ===== */
.report-overlay{display:none;position:fixed;inset:0;z-index:1000;background:rgba(0,0,0,0.45);justify-content:center;align-items:flex-start;padding-top:40px;}
.report-overlay.show{display:flex;}
.report-modal{background:#fff;border-radius:var(--radius-lg);width:720px;max-height:calc(100vh - 80px);display:flex;flex-direction:column;overflow:hidden;box-shadow:0 8px 40px rgba(0,0,0,0.18);}
.report-modal__header{display:flex;align-items:center;justify-content:space-between;padding:16px 24px;border-bottom:1px solid var(--border);flex-shrink:0;}
.report-modal__title{font-size:var(--font-lg);font-weight:700;color:var(--text-primary);}
.report-modal__close{width:32px;height:32px;border:none;background:none;cursor:pointer;display:flex;align-items:center;justify-content:center;border-radius:var(--radius-sm);color:var(--text-placeholder);font-size:20px;transition:all .15s;}
.report-modal__close:hover{background:#F0F0F0;color:var(--text-primary);}
.report-modal__body{flex:1;overflow-y:auto;padding:0 24px 24px;display:flex;flex-direction:column;}
.report-modal__body::-webkit-scrollbar{width:6px;}
.report-modal__body::-webkit-scrollbar-thumb{background:#D9D9D9;border-radius:3px;}
/* 总览卡片(固定在弹窗顶部,不随列表滚动) */
.report-overview{background:linear-gradient(135deg, #36cfc9 0%, #2ec4b6 100%);border-radius:var(--radius-md);padding:20px 24px;color:#fff;position:relative;overflow:hidden;flex-shrink:0;margin:16px 24px 0;}
.report-overview::before{content:'';position:absolute;top:-40px;right:-40px;width:120px;height:120px;border-radius:50%;background:rgba(255,255,255,0.08);pointer-events:none;}
.report-overview::after{content:'';position:absolute;bottom:-50px;left:-30px;width:140px;height:140px;border-radius:50%;background:rgba(255,255,255,0.05);pointer-events:none;}
.report-overview__title{font-size:18px;font-weight:800;margin-bottom:12px;position:relative;z-index:1;letter-spacing:1px;}
.report-overview__row{display:flex;align-items:center;gap:32px;position:relative;z-index:1;font-size:13px;opacity:0.9;margin-bottom:8px;}
.report-overview__rank{position:relative;z-index:1;font-size:13px;opacity:0.9;margin-bottom:14px;line-height:1.8;}
.report-overview__metrics{display:flex;gap:16px;position:relative;z-index:1;}
.report-overview__metric{flex:1;background:rgba(255,255,255,0.15);border-radius:10px;padding:14px 18px;backdrop-filter:blur(4px);}
.report-overview__metric-label{font-size:12px;opacity:0.8;margin-bottom:6px;}
.report-overview__metric-val{font-size:28px;font-weight:800;}
.report-overview__metric-unit{font-size:13px;font-weight:500;opacity:0.8;margin-left:2px;}
/* 记录表格 */
.report-table-wrap{overflow-x:auto;-webkit-overflow-scrolling:touch;}
.report-table{width:100%;border-collapse:collapse;}
.report-table thead{position:sticky;top:0;z-index:5;}
.report-table thead th{background:#FAFAFA;padding:8px 10px;text-align:center;font-size:var(--font-xs);color:var(--text-secondary);font-weight:500;border-bottom:1px solid var(--border);white-space:nowrap;}
.report-table tbody td{padding:9px 10px;text-align:center;font-size:var(--font-xs);color:var(--text-primary);border-bottom:1px solid #F0F0F0;white-space:nowrap;}
.report-table tbody tr:hover{background:#F8FBFF;}
.report-table tbody tr:last-child td{border-bottom:none;}
.report-table-empty{text-align:center;padding:40px 20px;color:var(--text-placeholder);font-size:var(--font-sm);}
/* 弹窗底部 */
.report-modal__footer{display:flex;align-items:center;justify-content:flex-end;padding:12px 24px;border-top:1px solid var(--border);flex-shrink:0;gap:8px;}
</style>
</head>
<body>
<!-- 顶部导航栏 -->
<div class="top-bar">
<div class="top-bar__logo"><svg viewBox="0 0 28 28" fill="none"><rect width="28" height="28" rx="6" fill="#1890FF"/><path d="M7 14h14M14 7v14" stroke="#fff" stroke-width="2.5" stroke-linecap="round"/></svg> 体重管理</div>
<nav class="top-bar__nav">
<a href="archive-personal-weight-data.html">档案</a>
<a href="plan-list.html">计划管理</a>
<a href="registration-tracking.html">报名管理</a>
<a href="action-record.html" class="active">过程管理</a>
<a href="history-plan-list.html">历史干预</a>
<a href="personal-target-data.html">个人体重管理</a>
<a href="scale-device.html">设备管理</a>
<a href="exception-system-dirty.html">异常事件</a>
</nav>
<div class="top-bar__right">
<a class="btn-back" href="../../index.html"><svg width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M10 3L5 8l5 5" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg> 返回首页</a>
<div class="avatar"></div>
<span style="color:rgba(255,255,255,0.65);">系统管理员 ▾</span>
</div>
</div>
<!-- 侧边栏 -->
<aside class="sidebar">
<div class="sidebar-menu__title">过程管理</div>
<a href="action-record.html" class="sidebar-item">行动记录</a>
<a href="detail-data.html" class="sidebar-item active">详细数据</a>
<a href="weight-ranking.html" class="sidebar-item">体重排名</a>
<a href="action-overview.html" class="sidebar-item">活动总览</a>
<a href="activity-statistics.html" class="sidebar-item">活动统计</a>
<a href="recipe-record.html" class="sidebar-item">食堂食谱</a>
</aside>
<!-- 主内容 -->
<main class="main">
<!-- 页面标题 -->
<div class="page-header">
<div class="page-header__breadcrumb">体重管理 / 过程管理 / <span>详细数据</span></div>
</div>
<!-- [交互] 筛选栏 — 日期范围(默认当日)、单位部门、姓名、员工编号 -->
<div class="filter-bar">
<!-- [交互] 干预计划下拉搜索 -->
<div class="filter-item">
<label>干预计划</label>
<div class="search-select" id="planSelect" style="width:280px;">
<input class="search-select__input" id="planSearchInput" placeholder="搜索计划名称或组织机构" oninput="searchPlan()" onfocus="showPlanPanel()" autocomplete="off">
<button class="search-select__clear" id="planClearBtn" onclick="clearPlan()" title="清空计划">×</button>
<div class="search-select__panel" id="planPanel"></div>
</div>
</div>
<!-- [交互] 日期范围选择,默认当日 -->
<div class="filter-item">
<label>日期范围</label>
<input class="filter-date" type="date" id="filterDateFrom" onchange="applyFilter()">
<span class="filter-divider">~</span>
<input class="filter-date" type="date" id="filterDateTo" onchange="applyFilter()">
</div>
<!-- [交互] 双列面板:左选单位→右选部门 -->
<div class="filter-item">
<label>单位部门</label>
<div class="org-select-wrap" id="orgWrap">
<div class="org-trigger" id="orgTrigger" onclick="toggleOrg()">全部单位/部门</div>
<div class="org-panel" id="orgPanel">
<div class="org-col" id="orgUnitCol">
<div class="org-col__title">单位</div>
<div class="org-item active" data-unit="" onclick="selectUnit(this,'全部单位/部门','')">全部单位/部门</div>
<div class="org-item" data-unit="第四采油厂" onclick="selectUnit(this,'第四采油厂','第四采油厂')">第四采油厂</div>
<div class="org-item" data-unit="采油一厂" onclick="selectUnit(this,'采油一厂','采油一厂')">采油一厂</div>
<div class="org-item" data-unit="采油二厂" onclick="selectUnit(this,'采油二厂','采油二厂')">采油二厂</div>
<div class="org-item" data-unit="采气一厂" onclick="selectUnit(this,'采气一厂','采气一厂')">采气一厂</div>
</div>
<div class="org-col" id="orgDeptCol">
<div class="org-col__title">部门</div>
<div class="org-item active" data-dept="" onclick="selectDept(this,'全部部门','')">全部部门</div>
</div>
</div>
</div>
</div>
<div class="filter-item">
<label>姓名</label>
<input class="filter-input" id="filterName" placeholder="请输入姓名" style="width:100px;">
</div>
<div class="filter-item">
<label>员工编号</label>
<input class="filter-input" id="filterEmpId" placeholder="请输入编号" style="width:110px;">
</div>
<!-- [交互] 点击查询按钮筛选列表 -->
<button class="btn btn-primary" onclick="applyFilter()">
<svg width="14" height="14" viewBox="0 0 14 14" fill="none"><circle cx="6" cy="6" r="4.5" stroke="#fff" stroke-width="1.3"/><path d="M9.5 9.5L13 13" stroke="#fff" stroke-width="1.3" stroke-linecap="round"/></svg>查询
</button>
<button class="btn btn-default" onclick="resetFilter()">重置</button>
</div>
<!-- [交互] 操作按钮区 -->
<div class="action-bar">
<button class="btn btn-export" onclick="showToast('导出列表数据功能开发中')">
<svg width="14" height="14" viewBox="0 0 14 14" fill="none"><path d="M2 10v2h10v-2M7 2v7M4.5 6.5L7 9l2.5-2.5" stroke="currentColor" stroke-width="1.4" stroke-linecap="round" stroke-linejoin="round"/></svg>导出列表数据
</button>
<!-- [交互] 点击打开导出任务列表弹窗 -->
<button class="btn btn-default" onclick="showToast('导出任务列表开发中')">
<svg width="14" height="14" viewBox="0 0 14 14" fill="none"><rect x="2" y="2" width="10" height="10" rx="1.5" stroke="currentColor" stroke-width="1.4"/><path d="M4 5h6M4 7.5h4" stroke="currentColor" stroke-width="1.2" stroke-linecap="round"/></svg>查看导出任务
</button>
</div>
<!-- 数据表格 -->
<div class="table-card">
<div class="table-card__content">
<table>
<thead>
<!-- [交互] 表头第一行:父级分类(饮食摄入、运动消耗、体重为合并单元格) -->
<tr>
<th rowspan="2">序号</th>
<th rowspan="2">干预计划</th>
<th rowspan="2">姓名</th>
<th rowspan="2">员工编号</th>
<th rowspan="2">性别</th>
<th rowspan="2">年龄</th>
<th rowspan="2">单位</th>
<th rowspan="2">部门</th>
<th rowspan="2">日期</th>
<th rowspan="2">身高<br>(cm)</th>
<th class="th-parent" colspan="4">饮食摄入(千卡)</th>
<th class="th-parent" colspan="2">运动消耗(千卡)</th>
<th class="th-parent" colspan="3">体重记录</th>
<th rowspan="2">体重报告</th>
</tr>
<!-- [交互] 表头第二行:饮食摄入、运动消耗、体重的子列 -->
<tr>
<th>早餐</th>
<th>午餐</th>
<th>晚餐</th>
<th class="col-diet-last">加餐</th>
<th>基础消耗</th>
<th class="col-exercise-last">其他消耗</th>
<th>体重</th>
<th>体脂</th>
<th class="col-weight-last">腰围</th>
</tr>
</thead>
<tbody id="tableBody"></tbody>
</table>
</div>
<div class="pagination">
<span id="pageInfo">显示 0 条记录</span>
<button class="page-btn" onclick="goPage(-1)"></button>
<span id="pageNum" style="font-size:var(--font-sm);color:var(--text-secondary);">第 1 页</span>
<button class="page-btn" onclick="goPage(1)"></button>
</div>
</div>
</main>
<!-- [交互] 体重报告弹窗 — 点击列表"查看"按钮打开 -->
<div class="report-overlay" id="reportOverlay" onclick="if(event.target===this)closeReport()">
<div class="report-modal">
<div class="report-modal__header">
<span class="report-modal__title" id="reportModalTitle">体重报告</span>
<!-- [交互] 点击关闭弹窗 -->
<button class="report-modal__close" onclick="closeReport()"></button>
</div>
<!-- 总览卡片(固定不滚动) -->
<div class="report-overview">
<div class="report-overview__title" id="rpOverviewTitle">体重报告</div>
<div class="report-overview__row">
<span>截止至 <strong id="rpCutoff">-</strong></span>
<span><strong id="rpDay">-</strong> 天(共 <strong id="rpTotal">-</strong> 天)</span>
</div>
<div class="report-overview__rank" id="rpRank">
目前的减重量排名 <strong id="rpRankWeight">-</strong>,减重率排名 <strong id="rpRankRate">-</strong>,结合个人打卡情况,综合分排名 <strong id="rpRankScore">-</strong>
</div>
<div class="report-overview__metrics">
<div class="report-overview__metric">
<div class="report-overview__metric-label">已减重</div>
<div class="report-overview__metric-val" id="rpLoss">-<span class="report-overview__metric-unit">kg</span></div>
</div>
<div class="report-overview__metric">
<div class="report-overview__metric-label">减重率</div>
<div class="report-overview__metric-val" id="rpRate">-<span class="report-overview__metric-unit">%</span></div>
</div>
</div>
</div>
<!-- 记录表格(可滚动) -->
<div class="report-modal__body">
<div class="report-table-wrap">
<table class="report-table">
<thead>
<tr>
<th>日期</th>
<th>体重(kg)</th>
<th>BMI</th>
<th>体脂率(%)</th>
<th>腰围(cm)</th>
<th>摄入(kcal)</th>
<th>消耗(kcal)</th>
</tr>
</thead>
<tbody id="reportTableBody"></tbody>
</table>
</div>
</div>
<div class="report-modal__footer">
<button class="btn btn-default" onclick="closeReport()">关闭</button>
</div>
</div>
</div>
<!-- Toast -->
<div class="toast" id="toast"></div>
<script>
/* ===== 侧边栏当前页高亮 ===== */
(function(){
var current = location.pathname.split('/').pop();
document.querySelectorAll('.sidebar-item').forEach(function(item){
var href = item.getAttribute('href');
item.classList.toggle('active', href === current);
});
})();
/* ===== 干预计划数据 ===== */
var plans = [
{id:1,name:'第四采油厂2026年超重健康干预计划',org:'第四采油厂',dateFrom:'2026-03-01',dateTo:'2026-08-31',totalCount:234,actualCount:218},
{id:2,name:'采油一厂2026年体重管理专项行动',org:'采油一厂',dateFrom:'2026-04-01',dateTo:'2026-09-30',totalCount:186,actualCount:180},
{id:3,name:'采油二厂2026年健康减重计划',org:'采油二厂',dateFrom:'2026-05-15',dateTo:'2026-11-15',totalCount:312,actualCount:295},
{id:4,name:'采气一厂2025年度体重管理计划',org:'采气一厂',dateFrom:'2025-06-01',dateTo:'2025-12-01',totalCount:158,actualCount:142},
{id:5,name:'第四采油厂2025年超重健康干预计划',org:'第四采油厂',dateFrom:'2025-03-01',dateTo:'2025-08-31',totalCount:267,actualCount:251},
{id:6,name:'采油一厂2025年员工健康体重计划',org:'采油一厂',dateFrom:'2025-04-15',dateTo:'2025-10-15',totalCount:420,actualCount:398},
{id:7,name:'采气一厂2026下半年体重干预计划',org:'采气一厂',dateFrom:'2026-09-01',dateTo:'2026-12-31',totalCount:89,actualCount:72},
{id:8,name:'采油二厂2024年体重控制专项计划',org:'采油二厂',dateFrom:'2024-07-01',dateTo:'2024-12-31',totalCount:145,actualCount:130}
];
/* ===== 基础员工数据 ===== */
var baseEmployees = [
{org:'第四采油厂',dept:'健康管理部',name:'张伟',empId:'CQ001234',gender:'男',age:42,height:172,weight:85,bmi:28.7,waist:96,fat:28.5},
{org:'第四采油厂',dept:'健康管理部',name:'李娜',empId:'CQ001235',gender:'女',age:35,height:160,weight:72,bmi:28.1,waist:84,fat:35.2},
{org:'第四采油厂',dept:'健康管理部',name:'王磊',empId:'CQ001236',gender:'男',age:28,height:178,weight:90,bmi:28.4,waist:98,fat:26.8},
{org:'第四采油厂',dept:'安全环保科',name:'赵敏',empId:'CQ001237',gender:'女',age:39,height:163,weight:75,bmi:28.2,waist:86,fat:36.5},
{org:'第四采油厂',dept:'安全环保科',name:'刘洋',empId:'CQ001238',gender:'男',age:45,height:175,weight:88,bmi:28.7,waist:100,fat:29.2},
{org:'第四采油厂',dept:'安全环保科',name:'陈晨',empId:'CQ001239',gender:'男',age:31,height:170,weight:82,bmi:28.4,waist:94,fat:27.5},
{org:'第四采油厂',dept:'工会办公室',name:'周杰',empId:'CQ001240',gender:'男',age:50,height:168,weight:78,bmi:27.6,waist:92,fat:28.1},
{org:'第四采油厂',dept:'工会办公室',name:'吴芳',empId:'CQ001241',gender:'女',age:33,height:158,weight:70,bmi:28.0,waist:82,fat:34.8},
{org:'第四采油厂',dept:'生产技术部',name:'孙丽',empId:'CQ001242',gender:'女',age:40,height:165,weight:76,bmi:27.9,waist:88,fat:37.0},
{org:'第四采油厂',dept:'生产技术部',name:'郑浩',empId:'CQ001243',gender:'男',age:36,height:180,weight:95,bmi:29.3,waist:104,fat:30.5},
{org:'第四采油厂',dept:'生产技术部',name:'黄磊',empId:'CQ001244',gender:'男',age:27,height:176,weight:88,bmi:28.4,waist:97,fat:27.0},
{org:'第四采油厂',dept:'生产技术部',name:'林燕',empId:'CQ001245',gender:'女',age:29,height:162,weight:74,bmi:28.2,waist:85,fat:35.8},
{org:'采油一厂',dept:'健康管理部',name:'杨帆',empId:'CQ001246',gender:'男',age:38,height:170,weight:88,bmi:30.4,waist:102,fat:31.2},
{org:'采油一厂',dept:'安全环保科',name:'孙强',empId:'CQ001247',gender:'男',age:44,height:173,weight:86,bmi:28.7,waist:99,fat:28.8},
{org:'采油一厂',dept:'工会办公室',name:'周强',empId:'CQ001248',gender:'男',age:50,height:168,weight:78,bmi:27.6,waist:93,fat:27.6},
{org:'采油一厂',dept:'生产技术部',name:'吴敏',empId:'CQ001249',gender:'女',age:29,height:162,weight:56,bmi:21.3,waist:72,fat:26.5},
{org:'采油二厂',dept:'健康管理部',name:'郑浩',empId:'CQ001250',gender:'男',age:33,height:176,weight:82,bmi:26.5,waist:91,fat:25.8},
{org:'采油二厂',dept:'安全环保科',name:'黄丽',empId:'CQ001251',gender:'女',age:27,height:162,weight:74,bmi:28.2,waist:86,fat:36.0},
{org:'采油二厂',dept:'财务部',name:'林涛',empId:'CQ001252',gender:'男',age:41,height:175,weight:92,bmi:30.0,waist:105,fat:31.5},
{org:'采气一厂',dept:'生产技术部',name:'何婷',empId:'CQ001253',gender:'女',age:34,height:160,weight:70,bmi:27.3,waist:84,fat:35.3},
{org:'采气一厂',dept:'信息中心',name:'马超',empId:'CQ001254',gender:'男',age:36,height:179,weight:95,bmi:29.6,waist:107,fat:32.0}
];
/* ===== 每日明细Mock数据 ===== */
function buildDailyData(){
var data = [];
var today = new Date();
// 生成最近10天日期列表
var dateList = [];
for(var d = 9; d >= 0; d--){
var dt = new Date(today);
dt.setDate(today.getDate() - d);
dateList.push(formatDate(dt));
}
baseEmployees.forEach(function(e, empIdx){
var planIdx = empIdx % plans.length;
var p = plans[planIdx];
// 目标指标(比初始降低约15%
var targetWeight = Math.round(e.weight * 0.85);
var targetBmi = +(e.bmi * 0.85).toFixed(1);
var targetWaist = Math.round(e.waist * 0.88);
var targetFat = +(e.fat * 0.80).toFixed(1);
// 第一个员工的进度基准
var progressBase = (empIdx % 5) / 4;
dateList.forEach(function(dateStr, dateIdx){
// 模拟每日波动 + 整体趋势向目标靠近
var dayProgress = progressBase - (9 - dateIdx) * 0.015;
var curWeight = +(e.weight - (e.weight - targetWeight) * Math.max(0, dayProgress) + (Math.random() - 0.5) * 0.6).toFixed(1);
var curBmi = +(curWeight / ((e.height/100) * (e.height/100))).toFixed(1);
var curWaist = +(e.waist - (e.waist - targetWaist) * Math.max(0, dayProgress) + (Math.random() - 0.5) * 0.4).toFixed(1);
var curFat = +(e.fat - (e.fat - targetFat) * Math.max(0, dayProgress) + (Math.random() - 0.5) * 0.3).toFixed(1);
var weightChange = +(curWeight - e.weight).toFixed(1);
var bmiChange = +(curBmi - e.bmi).toFixed(1);
var fatChange = +(curFat - e.fat).toFixed(1);
var waistChange = +(curWaist - e.waist).toFixed(1);
// 饮食摄入 - 三餐 + 加餐
var breakfast = Math.floor(Math.random() * 200) + 300;
var lunch = Math.floor(Math.random() * 300) + 400;
var dinner = Math.floor(Math.random() * 250) + 350;
var snack = Math.floor(Math.random() * 150);
// 运动消耗
var exercise = Math.floor(Math.random() * 300) + 150;
var baseExercise = Math.floor(exercise * 0.6);
var otherExercise = exercise - baseExercise;
// 最新体重指标
var latestWeight = +(curWeight + (Math.random() - 0.3) * 0.5).toFixed(1);
var latestFat = +(curFat + (Math.random() - 0.5) * 0.4).toFixed(1);
var latestWaist = Math.round(curWaist + (Math.random() - 0.5) * 1);
data.push({
planId: p.id, planName: p.name,
org: e.org, dept: e.dept,
name: e.name, empId: e.empId,
gender: e.gender, age: e.age,
date: dateStr,
height: e.height,
initWeight: e.weight, initBmi: e.bmi, initFat: e.fat, initWaist: e.waist,
targetWeight: targetWeight, targetBmi: targetBmi, targetFat: targetFat, targetWaist: targetWaist,
curWeight: curWeight, curBmi: curBmi, curFat: curFat, curWaist: curWaist,
weightChange: weightChange, bmiChange: bmiChange, fatChange: fatChange, waistChange: waistChange,
breakfast: breakfast, lunch: lunch, dinner: dinner, snack: snack,
exercise: exercise, baseExercise: baseExercise, otherExercise: otherExercise,
latestWeight: latestWeight, latestFat: latestFat, latestWaist: latestWaist
});
});
});
return data;
}
var dailyData = buildDailyData();
var selectedPlanId = null;
var pageSize = 10;
var currentPage = 0;
var filteredData = dailyData.slice();
/* ===== 计划搜索选择 ===== */
function searchPlan(){
var keyword = document.getElementById('planSearchInput').value.trim().toLowerCase();
var panel = document.getElementById('planPanel');
var filtered = plans;
if(keyword){
filtered = plans.filter(function(p){
return p.name.toLowerCase().indexOf(keyword) > -1 || p.org.toLowerCase().indexOf(keyword) > -1;
});
}
if(filtered.length === 0){
panel.innerHTML = '<div class="search-select__empty">无匹配计划</div>';
} else {
var html = '';
filtered.forEach(function(p){
var sel = selectedPlanId === p.id ? ' selected' : '';
html += '<div class="search-select__option'+sel+'" onclick="selectPlan('+p.id+')">';
html += '<div style="font-weight:500;">'+esc(p.name)+'</div>';
html += '<div class="ss-org">'+esc(p.org)+' | '+p.dateFrom+' ~ '+p.dateTo+'</div>';
html += '</div>';
});
panel.innerHTML = html;
}
}
function showPlanPanel(){
searchPlan();
document.getElementById('planPanel').classList.add('show');
}
function selectPlan(planId){
selectedPlanId = planId;
var plan = plans.find(function(p){return p.id === planId;});
if(!plan) return;
document.getElementById('planSearchInput').value = plan.name;
document.getElementById('planPanel').classList.remove('show');
document.getElementById('planClearBtn').classList.add('show');
document.getElementById('planSelect').classList.add('search-select--selected');
applyFilter();
}
/* [交互] 清空已选干预计划,恢复未选择状态 */
function clearPlan(){
selectedPlanId = null;
document.getElementById('planSearchInput').value = '';
document.getElementById('planClearBtn').classList.remove('show');
document.getElementById('planSelect').classList.remove('search-select--selected');
document.getElementById('planPanel').classList.remove('show');
applyFilter();
}
/* ===== 单位部门双列面板 ===== */
var deptMap = {
'第四采油厂':['健康管理部','安全环保科','工会办公室','生产技术部','财务部','信息中心'],
'采油一厂':['健康管理部','安全环保科','工会办公室','生产技术部'],
'采油二厂':['健康管理部','安全环保科','财务部'],
'采气一厂':['生产技术部','信息中心']
};
var selectedUnitName = '';
var selectedUnitCode = '';
var selectedDeptName = '';
var selectedDeptCode = '';
function toggleOrg(){
var panel = document.getElementById('orgPanel');
var trigger = document.getElementById('orgTrigger');
panel.classList.toggle('open');
trigger.classList.toggle('open');
}
function selectUnit(elem, unitName, unitCode){
document.querySelectorAll('#orgUnitCol .org-item').forEach(function(item){item.classList.remove('active');});
elem.classList.add('active');
selectedUnitName = unitName;
selectedUnitCode = unitCode;
var depts = deptMap[unitCode] || [];
var html = '<div class="org-col__title">部门</div>';
html += '<div class="org-item active" data-dept="" onclick="selectDept(this,\'全部部门\',\'\')">全部部门</div>';
depts.forEach(function(d){
html += '<div class="org-item" data-dept="'+d+'" onclick="selectDept(this,\''+d+'\',\''+d+'\')">'+d+'</div>';
});
document.getElementById('orgDeptCol').innerHTML = html;
selectedDeptName = '';
selectedDeptCode = '';
}
function selectDept(elem, deptName, deptCode){
document.querySelectorAll('#orgDeptCol .org-item').forEach(function(item){item.classList.remove('active');});
elem.classList.add('active');
selectedDeptName = deptName;
selectedDeptCode = deptCode;
var label = selectedUnitCode ? selectedUnitName : '全部单位';
label += deptCode ? ' / ' + deptName : ' / 全部部门';
document.getElementById('orgTrigger').textContent = label;
}
/* ===== 筛选 ===== */
function applyFilter(){
var dateFrom = document.getElementById('filterDateFrom').value;
var dateTo = document.getElementById('filterDateTo').value;
var unit = selectedUnitCode;
var dept = selectedDeptCode;
var name = document.getElementById('filterName').value.trim().toLowerCase();
var empId = document.getElementById('filterEmpId').value.trim().toLowerCase();
var data = dailyData.slice();
if(selectedPlanId){ data = data.filter(function(d){return d.planId === selectedPlanId;}); }
filteredData = data.filter(function(d){
if(dateFrom && d.date < dateFrom) return false;
if(dateTo && d.date > dateTo) return false;
if(unit && d.org !== unit) return false;
if(dept && d.dept !== dept) return false;
if(name && d.name.toLowerCase().indexOf(name) === -1) return false;
if(empId && d.empId.toLowerCase().indexOf(empId) === -1) return false;
return true;
});
currentPage = 0;
renderTable();
}
function resetFilter(){
// 恢复日期默认当日
var today = formatDate(new Date());
document.getElementById('filterDateFrom').value = today;
document.getElementById('filterDateTo').value = today;
selectedUnitName = '';
selectedUnitCode = '';
selectedDeptName = '';
selectedDeptCode = '';
document.getElementById('orgTrigger').textContent = '全部单位/部门';
document.querySelectorAll('#orgUnitCol .org-item').forEach(function(item){item.classList.remove('active');});
document.querySelectorAll('#orgUnitCol .org-item').item(0).classList.add('active');
document.getElementById('orgDeptCol').innerHTML = '<div class="org-col__title">部门</div><div class="org-item active" data-dept="" onclick="selectDept(this,\'全部部门\',\'\')">全部部门</div>';
document.getElementById('filterName').value = '';
document.getElementById('filterEmpId').value = '';
applyFilter();
}
/* ===== 渲染表格 ===== */
function renderTable(){
var tbody = document.getElementById('tableBody');
var start = currentPage * pageSize;
var pageData = filteredData.slice(start, start + pageSize);
var totalPages = Math.ceil(filteredData.length / pageSize) || 1;
document.getElementById('pageInfo').textContent = '显示 ' + pageData.length + ' 条,共 ' + filteredData.length + ' 条记录';
document.getElementById('pageNum').textContent = '第 ' + (currentPage + 1) + '/' + totalPages + ' 页';
if(filteredData.length === 0){
tbody.innerHTML = '<tr><td colspan="20" class="td-empty">暂无匹配数据,请选择干预计划后查看</td></tr>';
return;
}
var html = '';
pageData.forEach(function(d,i){
html += '<tr>';
html += '<td>'+(start+i+1)+'</td>';
html += '<td>'+esc(d.planName)+'</td>';
html += '<td>'+esc(d.name)+'</td>';
html += '<td>'+esc(d.empId)+'</td>';
html += '<td>'+d.gender+'</td>';
html += '<td>'+d.age+'</td>';
html += '<td>'+esc(d.org)+'</td>';
html += '<td>'+esc(d.dept)+'</td>';
html += '<td>'+d.date+'</td>';
html += '<td>'+d.height+'</td>';
// 饮食摄入(千卡):早餐、午餐、晚餐、加餐
html += '<td>'+d.breakfast+'</td>';
html += '<td>'+d.lunch+'</td>';
html += '<td>'+d.dinner+'</td>';
html += '<td class="col-diet-last">'+d.snack+'</td>';
// 运动消耗(千卡):基础消耗、其他消耗
html += '<td>'+d.baseExercise+'</td>';
html += '<td class="col-exercise-last">'+d.otherExercise+'</td>';
// 体重记录:体重、体脂、腰围
html += '<td>'+d.latestWeight+'</td>';
html += '<td>'+d.latestFat.toFixed(1)+'</td>';
html += '<td class="col-weight-last">'+d.latestWaist+'</td>';
// 体重报告
html += '<td><a class="link" href="javascript:void(0)" onclick="viewWeightReport(\''+esc(d.empId)+'\',\''+esc(d.name)+'\',\''+d.date+'\')">查看</a></td>';
html += '</tr>';
});
tbody.innerHTML = html;
}
/* ===== 翻页 ===== */
function goPage(delta){
var totalPages = Math.ceil(filteredData.length / pageSize);
var newPage = currentPage + delta;
if(newPage < 0 || newPage >= totalPages) return;
currentPage = newPage;
renderTable();
}
/* ===== 体重报告弹窗 ===== */
var reportEmpId = null;
var reportEmpName = '';
var reportDate = '';
var reportRecords = [];
/* 生成指定员工的体重报告Mock数据 */
function generateReportRecords(empId, empName, targetDate){
var endDate = parseDate(targetDate);
var records = [];
var emp = null;
for(var i = 0; i < baseEmployees.length; i++){
if(baseEmployees[i].empId === empId){ emp = baseEmployees[i]; break; }
}
if(!emp) emp = baseEmployees[0];
var initWeight = emp.weight;
var height = emp.height;
var currentWeight = initWeight - (Math.random() * 8 + 4);
var startWeight = currentWeight + (Math.random() * 6 + 6);
for(var d = 60; d >= 0; d -= (Math.random() > 0.5 ? 2 : 3)){
var dt = new Date(endDate);
dt.setDate(dt.getDate() - d);
if(dt > endDate) continue;
var progress = (60 - d) / 60;
var w = +(startWeight - (startWeight - currentWeight) * progress + (Math.random() - 0.5) * 0.4).toFixed(1);
if(d === 0) w = currentWeight;
var bmi = +(w / ((height/100) * (height/100))).toFixed(1);
var fat = +(22 + (initWeight - w) * 0.3 + (Math.random() - 0.5) * 0.5).toFixed(1);
var waist = +(80 + (initWeight - w) * 1.2 + (Math.random() - 0.5) * 0.3).toFixed(1);
var intake = Math.floor(Math.random() * 600) + 1000;
var consume = Math.floor(Math.random() * 500) + 800;
records.push({
date: formatDate(dt),
weight: w, bmi: bmi, bodyFat: fat, waist: waist,
intake: intake, consume: consume
});
if(d === 0) break;
}
if(records.length === 0 || records[records.length-1].date !== targetDate){
var w = currentWeight;
var bmi = +(w / ((height/100) * (height/100))).toFixed(1);
var fat = +(22 + (initWeight - w) * 0.3).toFixed(1);
var waist = +(80 + (initWeight - w) * 1.2).toFixed(1);
records.push({
date: targetDate,
weight: w, bmi: bmi, bodyFat: fat, waist: waist,
intake: Math.floor(Math.random() * 600) + 1000,
consume: Math.floor(Math.random() * 500) + 800
});
}
return records;
}
function viewWeightReport(empId, name, date){
reportEmpId = empId;
reportEmpName = name;
reportDate = date;
reportRecords = generateReportRecords(empId, name, date);
updateReportOverview();
renderReportRecords();
document.getElementById('reportOverlay').classList.add('show');
document.body.style.overflow = 'hidden';
}
function closeReport(){
document.getElementById('reportOverlay').classList.remove('show');
document.body.style.overflow = '';
}
function updateReportOverview(){
var recs = reportRecords;
if(recs.length === 0) return;
var firstRec = recs[0];
var lastRec = recs[recs.length - 1];
var startW = firstRec.weight;
var curW = lastRec.weight;
var loss = startW - curW;
var rate = startW > 0 ? (loss / startW) * 100 : 0;
var firstDate = parseDate(firstRec.date);
var lastDate = parseDate(lastRec.date);
var days = Math.floor((lastDate - firstDate) / (1000*60*60*24)) + 1;
document.getElementById('reportModalTitle').textContent = reportEmpName + ' - 体重报告';
document.getElementById('rpOverviewTitle').textContent = reportEmpName + ' 的体重报告';
document.getElementById('rpCutoff').textContent = lastRec.date;
document.getElementById('rpDay').textContent = days;
document.getElementById('rpTotal').textContent = days;
document.getElementById('rpLoss').innerHTML = loss.toFixed(1) + '<span class="report-overview__metric-unit">kg</span>';
document.getElementById('rpRate').innerHTML = rate.toFixed(1) + '<span class="report-overview__metric-unit">%</span>';
// 模拟排名(基于empId的hash保证同一员工每次排名一致)
var hash = 0;
for(var i = 0; i < reportEmpId.length; i++){ hash = ((hash << 5) - hash) + reportEmpId.charCodeAt(i); hash |= 0; }
var rankWeight = Math.abs(hash % 80) + 1;
var rankRate = Math.abs((hash * 7 + 13) % 75) + 1;
var rankScore = Math.abs((hash * 3 + 47) % 60) + 1;
document.getElementById('rpRankWeight').textContent = '第 ' + rankWeight + ' 名';
document.getElementById('rpRankRate').textContent = '第 ' + rankRate + ' 名';
document.getElementById('rpRankScore').textContent = '第 ' + rankScore + ' 名';
}
function renderReportRecords(){
var tbody = document.getElementById('reportTableBody');
if(reportRecords.length === 0){
tbody.innerHTML = '<tr><td colspan="7" class="report-table-empty">暂无记录</td></tr>';
return;
}
var html = '';
for(var i = 0; i < reportRecords.length; i++){
var r = reportRecords[i];
html += '<tr>';
html += '<td>'+r.date+'</td>';
html += '<td>'+r.weight.toFixed(1)+'</td>';
html += '<td>'+r.bmi.toFixed(1)+'</td>';
html += '<td>'+r.bodyFat.toFixed(1)+'</td>';
html += '<td>'+r.waist.toFixed(1)+'</td>';
html += '<td>'+r.intake+'</td>';
html += '<td>'+r.consume+'</td>';
html += '</tr>';
}
tbody.innerHTML = html;
}
function parseDate(s){ var p = s.split('-'); return new Date(+p[0], +p[1]-1, +p[2]); }
/* ===== 工具函数 ===== */
function formatDate(d){
var y = d.getFullYear();
var m = (d.getMonth() + 1);
var day = d.getDate();
return y + '-' + (m < 10 ? '0' + m : m) + '-' + (day < 10 ? '0' + day : day);
}
function calcPlanDays(dateFrom, dateTo){
var today = new Date();
var from = new Date(dateFrom);
var to = new Date(dateTo);
var end = to < today ? to : today;
if(end < from) return '未开始';
return Math.ceil((end - from) / (1000*60*60*24)) + 1;
}
function esc(s){return String(s||'').replace(/&/g,'&amp;').replace(/"/g,'&quot;').replace(/</g,'&lt;').replace(/>/g,'&gt;');}
function showToast(msg){
var t=document.getElementById('toast');t.textContent=msg;t.classList.add('show');
setTimeout(function(){t.classList.remove('show');},1500);
}
/* 点击外部关闭下拉 */
document.addEventListener('click',function(e){
if(!e.target.closest('#planSelect')){
document.getElementById('planPanel').classList.remove('show');
}
var orgWrap = document.getElementById('orgWrap');
if(orgWrap && !orgWrap.contains(e.target)){
document.getElementById('orgPanel').classList.remove('open');
document.getElementById('orgTrigger').classList.remove('open');
}
});
/* ===== 初始化 ===== */
(function init(){
// 初始化日期范围为当日
var today = formatDate(new Date());
document.getElementById('filterDateFrom').value = today;
document.getElementById('filterDateTo').value = today;
// 预填充计划下拉数据
var html = '';
plans.forEach(function(p){
html += '<div class="search-select__option" onclick="selectPlan('+p.id+')">';
html += '<div style="font-weight:500;">'+esc(p.name)+'</div>';
html += '<div class="ss-org">'+esc(p.org)+' | '+p.dateFrom+' ~ '+p.dateTo+'</div>';
html += '</div>';
});
document.getElementById('planPanel').innerHTML = html;
renderTable();
})();
</script>
</body>
</html>
@@ -144,8 +144,7 @@
<a href="sport-monitor.html" class="sidebar-item">设备监测</a>
</div>
</div>
<a href="employee-data.html" class="sidebar-item">员工监测数据</a>
<a href="employee-data-record.html" class="sidebar-item active">员工监测数据记录</a>
<a href="employee-data.html" class="sidebar-item active">员工监测数据</a>
<a href="dept-stat.html" class="sidebar-item">单位数据统计</a>
<a href="employee-stat.html" class="sidebar-item">员工数据统计</a>
</aside>
@@ -149,7 +149,7 @@
<th rowspan="2" style="vertical-align:middle;">年龄</th>
<th rowspan="2" style="vertical-align:middle;">所属单位</th>
<th rowspan="2" style="vertical-align:middle;">所属部门</th>
<th colspan="6" style="text-align:center;border-bottom:1px solid var(--border);">最新测量数据</th>
<th colspan="6" style="text-align:center;border-bottom:1px solid var(--border);">末次测量数据</th>
<th rowspan="2" style="vertical-align:middle;">操作</th>
</tr>
<tr>
@@ -146,9 +146,8 @@ tbody tr:hover{background:#F8FBFF;}
<!-- 侧边栏 -->
<aside class="sidebar">
<div class="sidebar-menu__title">过程管理</div>
<a href="action-record.html" class="sidebar-item">行动记录</a>
<a href="detail-data.html" class="sidebar-item">详细数据</a>
<a href="weight-ranking.html" class="sidebar-item">体重排名</a>
<a href="action-record.html" class="sidebar-item">行动记录</a>
<a href="weight-ranking.html" class="sidebar-item">体重排名</a>
<a href="action-overview.html" class="sidebar-item">活动总览</a>
<a href="activity-statistics.html" class="sidebar-item">活动统计</a>
<a href="recipe-record.html" class="sidebar-item active">食堂食谱</a>
+17 -56
View File
@@ -103,7 +103,7 @@ body{font-family:-apple-system,BlinkMacSystemFont,'PingFang SC','Microsoft YaHei
/* 表格卡片 */
.table-card{background:#fff;border-radius:0 0 var(--radius-md) var(--radius-md);box-shadow:var(--shadow-sm);overflow:hidden;}
.table-card__content{overflow-x:auto;-webkit-overflow-scrolling:touch;}
.table-card__content table{min-width:2800px;white-space:nowrap;}
.table-card__content table{min-width:1800px;white-space:nowrap;}
.table-card--unit .table-card__content table{min-width:auto;white-space:nowrap;}
.table-card--unit thead th{padding:6px 4px;font-size:10px;}
.table-card--unit tbody td{padding:8px 4px;font-size:12px;}
@@ -263,9 +263,8 @@ tbody tr:hover{background:#F8FBFF;}
<!-- 侧边栏 -->
<aside class="sidebar">
<div class="sidebar-menu__title">过程管理</div>
<a href="action-record.html" class="sidebar-item">行动记录</a>
<a href="detail-data.html" class="sidebar-item">详细数据</a>
<a href="weight-ranking.html" class="sidebar-item active">体重排名</a>
<a href="action-record.html" class="sidebar-item">行动记录</a>
<a href="weight-ranking.html" class="sidebar-item active">体重排名</a>
<a href="action-overview.html" class="sidebar-item">活动总览</a>
<a href="activity-statistics.html" class="sidebar-item">活动统计</a>
<a href="recipe-record.html" class="sidebar-item">食堂食谱</a>
@@ -356,23 +355,8 @@ tbody tr:hover{background:#F8FBFF;}
<th>年龄</th>
<th>单位</th>
<th>部门</th>
<th>身高<br>(cm)</th>
<th>初始<br>体重(kg)</th>
<th>初始<br>BMI</th>
<th>初始<br>体脂(%)</th>
<th>初始<br>腰围(cm)</th>
<th>目标<br>体重(kg)</th>
<th>目标<br>BMI</th>
<th>目标<br>体脂(%)</th>
<th>目标<br>腰围(cm)</th>
<th>现体重<br>(kg)</th>
<th>现BMI</th>
<th>现体脂<br>(%)</th>
<th>现腰围<br>(cm)</th>
<th>体重变化<br>(kg)</th>
<th>BMI变化</th>
<th>体脂变化<br>(%)</th>
<th>腰围变化<br>(cm)</th>
<th>减重量<br>(kg)</th>
<th>减重率<br>(%)</th>
<th>综合得分</th>
<th>行动得分</th>
<!-- [交互] 排名列支持点击排序切换(升序/降序/默认) -->
@@ -888,46 +872,23 @@ function renderPersonTable(){
document.getElementById('personPageInfo').textContent = '显示 ' + pageData.length + ' 条,共 ' + personFiltered.length + ' 条记录';
document.getElementById('personPageNum').textContent = '第 ' + (personPage + 1) + '/' + totalPages + ' 页';
if(personFiltered.length === 0){
tbody.innerHTML = '<tr><td colspan="31" class="td-empty">暂无匹配数据,请选择干预计划后查看</td></tr>';
tbody.innerHTML = '<tr><td colspan="16" class="td-empty">暂无匹配数据,请选择干预计划后查看</td></tr>';
return;
}
var html = '';
pageData.forEach(function(d,i){
var wcCls = d.weightChange < 0 ? 'change-down' : (d.weightChange > 0 ? 'change-up' : 'change-zero');
var bcCls = d.bmiChange < 0 ? 'change-down' : (d.bmiChange > 0 ? 'change-up' : 'change-zero');
var fcCls = d.fatChange < 0 ? 'change-down' : (d.fatChange > 0 ? 'change-up' : 'change-zero');
var wacCls = d.waistChange < 0 ? 'change-down' : (d.waistChange > 0 ? 'change-up' : 'change-zero');
var wcSign = d.weightChange > 0 ? '+' : '';
var bcSign = d.bmiChange > 0 ? '+' : '';
var fcSign = d.fatChange > 0 ? '+' : '';
var wacSign = d.waistChange > 0 ? '+' : '';
html += '<tr>';
pageData.forEach(function(d,i){
html += '<tr>';
html += '<td>'+(personPage*personPageSize+i+1)+'</td>';
html += '<td>'+esc(d.planName)+'</td>';
html += '<td>'+esc(d.name)+'</td>';
html += '<td>'+esc(d.empId)+'</td>';
html += '<td>'+d.gender+'</td>';
html += '<td>'+d.age+'</td>';
html += '<td>'+esc(d.org)+'</td>';
html += '<td>'+esc(d.dept)+'</td>';
html += '<td>'+d.height+'</td>';
html += '<td>'+d.initWeight+'</td>';
html += '<td>'+d.initBmi.toFixed(1)+'</td>';
html += '<td>'+d.initFat.toFixed(1)+'</td>';
html += '<td>'+d.initWaist+'</td>';
html += '<td>'+d.targetWeight+'</td>';
html += '<td>'+d.targetBmi+'</td>';
html += '<td>'+d.targetFat+'</td>';
html += '<td>'+d.targetWaist+'</td>';
html += '<td>'+d.curWeight+'</td>';
html += '<td>'+d.curBmi.toFixed(1)+'</td>';
html += '<td>'+d.curFat.toFixed(1)+'</td>';
html += '<td>'+d.curWaist+'</td>';
html += '<td class="'+wcCls+'">'+wcSign+d.weightChange+'</td>';
html += '<td class="'+bcCls+'">'+bcSign+d.bmiChange+'</td>';
html += '<td class="'+fcCls+'">'+fcSign+d.fatChange+'</td>';
html += '<td class="'+wacCls+'">'+wacSign+d.waistChange+'</td>';
html += '<td>'+d.compositeScore+'</td>';
html += '<td>'+esc(d.name)+'</td>';
html += '<td>'+esc(d.empId)+'</td>';
html += '<td>'+esc(d.gender)+'</td>';
html += '<td>'+d.age+'</td>';
html += '<td>'+esc(d.org)+'</td>';
html += '<td>'+esc(d.dept)+'</td>';
html += '<td>'+d.weightLoss+'</td>';
html += '<td>'+d.weightLossRate+'%</td>';
html += '<td>'+d.compositeScore+'</td>';
html += '<td>'+d.actionScore+'</td>';
html += '<td>'+d.weightLossRank+'</td>';
html += '<td>'+d.weightRateRank+'</td>';