feat: 体重管理原型更新(三测口径调整、设备厂商统一为蚁熊、历史方案详情改版等)

This commit is contained in:
liuyunqin
2026-08-25 13:32:12 +08:00
parent e663982b77
commit da410f71b0
13 changed files with 400 additions and 604 deletions
+14 -10
View File
@@ -1046,7 +1046,7 @@ tbody tr:hover td:nth-child(4){background:#F8FBFF;}
</div>
<table class="record-table">
<thead id="unitDetailThead">
<tr><th>序号</th><th>活动名称</th><th>姓名</th><th>员工编号</th><th>单位</th><th>部门</th><th>体重记录</th><th>饮食记录</th><th>运动记录</th><th>三测完成</th></tr>
<tr><th>序号</th><th>活动名称</th><th>姓名</th><th>员工编号</th><th>单位</th><th>部门</th><th>体重记录</th><th>体脂记录</th><th>腰围记录</th><th>三测完成</th></tr>
</thead>
<tbody id="unitDetailTbody"></tbody>
</table>
@@ -2967,10 +2967,9 @@ function openUnitDetailDialog(org, type){
measureData.weight.forEach(function(w,i){
if(w.org !== org) return;
if(selectedPlanId && w.planId !== selectedPlanId) return;
var dRec = measureData.diet[i], exRec = measureData.exercise[i];
var key = w.empId;
if(!empMap[key]){
empMap[key] = {planName:w.planName,name:w.name,empId:w.empId,org:w.org,dept:w.dept,hasWeight:false,hasDiet:false,hasExercise:false};
empMap[key] = {planName:w.planName,name:w.name,empId:w.empId,org:w.org,dept:w.dept,hasWeight:false,hasFat:false,hasWaist:false};
}
function inRange(rec){
if(!rec.hasRecord) return false;
@@ -2978,12 +2977,17 @@ function openUnitDetailDialog(org, type){
if(dateTo && rec.firstDate > dateTo) return false;
return true;
}
if(inRange(w)) empMap[key].hasWeight = true;
if(inRange(dRec)) empMap[key].hasDiet = true;
if(inRange(exRec)) empMap[key].hasExercise = true;
// 三测 = 体重/体脂/腰围,均来自体重测量记录;是否含体脂/腰围取决于记录来源
if(inRange(w)){
empMap[key].hasWeight = true;
// 蓝牙称只有体重;身高称缺体脂;体脂仪/体重秤/自记数据完整
if(w.source !== '蓝牙称' && w.source !== '身高称') empMap[key].hasFat = true;
if(w.source === '体脂仪' || w.source === '自记') empMap[key].hasWaist = true;
}
});
var empList = [];
for(var k in empMap){ empMap[k].allDone = empMap[k].hasWeight && empMap[k].hasDiet && empMap[k].hasExercise; empList.push(empMap[k]); }
// 体重/体脂/腰围中有任一项记录即视为三测完成
for(var k in empMap){ empMap[k].allDone = empMap[k].hasWeight || empMap[k].hasFat || empMap[k].hasWaist; empList.push(empMap[k]); }
// 三测人数弹窗只显示三测完成的员工
if(type === 'measured'){ empList = empList.filter(function(e){ return e.allDone; }); }
var tbody = document.getElementById('unitDetailTbody');
@@ -3000,9 +3004,9 @@ function openUnitDetailDialog(org, type){
html += '<td>'+esc(e.org)+'</td>';
html += '<td>'+esc(e.dept)+'</td>';
html += '<td>'+(e.hasWeight?'<span style="color:var(--success);">●</span>':'<span style="color:var(--danger);">○</span>')+'</td>';
html += '<td>'+(e.hasDiet?'<span style="color:var(--success);">●</span>':'<span style="color:var(--danger);">○</span>')+'</td>';
html += '<td>'+(e.hasExercise?'<span style="color:var(--success);">●</span>':'<span style="color:var(--danger);">○</span>')+'</td>';
html += '<td>'+(e.allDone?'<span class="tag tag-green">是</span>':'<span class="tag tag-default">否</span>')+'</td>';
html += '<td>'+(e.hasFat?'<span style="color:var(--success);">●</span>':'<span style="color:var(--danger);">○</span>')+'</td>';
html += '<td>'+(e.hasWaist?'<span style="color:var(--success);">●</span>':'<span style="color:var(--danger);">○</span>')+'</td>';
html += '<td>'+(e.allDone?'<span class="tag tag-green">是</span>':'<span class="tag tag-red">否</span>')+'</td>';
html += '</tr>';
});
tbody.innerHTML = html;
@@ -137,7 +137,7 @@
<div class="form-item"><label>设备名称<span class="required">*</span></label><input class="form-input" placeholder="请输入设备名称"></div>
<div class="form-item"><label>设备编码<span class="required">*</span></label><input class="form-input" placeholder="请输入设备编码"></div>
<div class="form-item"><label>所属单位<span class="required">*</span></label><select class="form-select"><option value="">请选择</option><option>采油一厂</option><option>采油二厂</option><option>采气厂</option></select></div>
<div class="form-item"><label>设备厂商<span class="required">*</span></label><select class="form-select"><option value="">请选择</option><option>华为</option><option>小米</option><option>乐心</option></select></div>
<div class="form-item"><label>设备厂商<span class="required">*</span></label><select class="form-select"><option value="">请选择</option><option>蚁熊</option></select></div>
<div class="form-item"><label>设备型号<span class="required">*</span></label><select class="form-select"><option value="">请选择</option><option>HW-S100</option><option>MI-Scale2</option><option>LX-Pro</option></select></div>
<div class="form-item"><label>入库日期<span class="required">*</span></label><input class="form-input" type="date"></div>
<div class="form-item full">
@@ -183,7 +183,7 @@
<div class="filter-bar">
<div class="filter-item"><label>所属单位</label><select class="filter-select"><option value="">全部</option><option>采油一厂</option><option>采油二厂</option><option>采气厂</option></select></div>
<div class="filter-item"><label>设备编码</label><input class="filter-input" placeholder="请输入设备编码"></div>
<div class="filter-item"><label>设备厂商</label><select class="filter-select"><option value="">全部</option><option>华为</option><option>小米</option><option>乐心</option></select></div>
<div class="filter-item"><label>设备厂商</label><select class="filter-select"><option value="">全部</option><option>蚁熊</option></select></div>
<div class="filter-item"><label>设备型号</label><select class="filter-select"><option value="">全部</option><option>HW-S100</option><option>MI-Scale2</option><option>LX-Pro</option></select></div>
<button class="btn btn-primary">查询</button>
<button class="btn btn-default">重置</button>
@@ -204,11 +204,11 @@
<table>
<thead><tr><th>序号</th><th>设备编码</th><th>设备名称</th><th>设备厂商</th><th>设备型号</th><th>所属单位</th><th>布放位置</th><th>入库日期</th><th>设备状态</th><th>操作</th></tr></thead>
<tbody>
<tr><td>1</td><td>BT-2024-001</td><td>蓝牙称A1</td><td>华为</td><td>HW-S100</td><td>采油一厂</td><td>职工活动中心1F</td><td>2024-03-15</td><td><span class="tag tag-green">正常</span></td><td><a class="link">详情</a> <a class="link" onclick="openMemberModal(0)">成员管理</a> <a class="link">编辑</a> <a class="link-danger">删除</a></td></tr>
<tr><td>2</td><td>BT-2024-002</td><td>蓝牙称A2</td><td>小米</td><td>MI-Scale2</td><td>采油一厂</td><td>办公楼2F健身房</td><td>2024-03-18</td><td><span class="tag tag-green">正常</span></td><td><a class="link">详情</a> <a class="link" onclick="openMemberModal(1)">成员管理</a> <a class="link">编辑</a> <a class="link-danger">删除</a></td></tr>
<tr><td>3</td><td>BT-2024-003</td><td>蓝牙称B1</td><td>乐心</td><td>LX-Pro</td><td>采油二厂</td><td>员工食堂入口</td><td>2024-04-02</td><td><span class="tag tag-orange">维护中</span></td><td><a class="link">详情</a> <a class="link" onclick="openMemberModal(2)">成员管理</a> <a class="link">编辑</a> <a class="link-danger">删除</a></td></tr>
<tr><td>4</td><td>BT-2024-004</td><td>蓝牙称B2</td><td>华为</td><td>HW-S100</td><td>采油二厂</td><td>宿舍楼大厅</td><td>2024-04-10</td><td><span class="tag tag-green">正常</span></td><td><a class="link">详情</a> <a class="link" onclick="openMemberModal(3)">成员管理</a> <a class="link">编辑</a> <a class="link-danger">删除</a></td></tr>
<tr><td>5</td><td>BT-2024-005</td><td>蓝牙称C1</td><td>小米</td><td>MI-Scale2</td><td>采气厂</td><td>综合办公楼1F</td><td>2024-05-08</td><td><span class="tag tag-red">已停用</span></td><td><a class="link">详情</a> <a class="link" onclick="openMemberModal(4)">成员管理</a> <a class="link">编辑</a> <a class="link-danger">删除</a></td></tr>
<tr><td>1</td><td>BT-2024-001</td><td>蓝牙称A1</td><td>蚁熊</td><td>HW-S100</td><td>采油一厂</td><td>职工活动中心1F</td><td>2024-03-15</td><td><span class="tag tag-green">正常</span></td><td><a class="link">详情</a> <a class="link" onclick="openMemberModal(0)">成员管理</a> <a class="link">编辑</a> <a class="link-danger">删除</a></td></tr>
<tr><td>2</td><td>BT-2024-002</td><td>蓝牙称A2</td><td>蚁熊</td><td>MI-Scale2</td><td>采油一厂</td><td>办公楼2F健身房</td><td>2024-03-18</td><td><span class="tag tag-green">正常</span></td><td><a class="link">详情</a> <a class="link" onclick="openMemberModal(1)">成员管理</a> <a class="link">编辑</a> <a class="link-danger">删除</a></td></tr>
<tr><td>3</td><td>BT-2024-003</td><td>蓝牙称B1</td><td>蚁熊</td><td>LX-Pro</td><td>采油二厂</td><td>员工食堂入口</td><td>2024-04-02</td><td><span class="tag tag-orange">维护中</span></td><td><a class="link">详情</a> <a class="link" onclick="openMemberModal(2)">成员管理</a> <a class="link">编辑</a> <a class="link-danger">删除</a></td></tr>
<tr><td>4</td><td>BT-2024-004</td><td>蓝牙称B2</td><td>蚁熊</td><td>HW-S100</td><td>采油二厂</td><td>宿舍楼大厅</td><td>2024-04-10</td><td><span class="tag tag-green">正常</span></td><td><a class="link">详情</a> <a class="link" onclick="openMemberModal(3)">成员管理</a> <a class="link">编辑</a> <a class="link-danger">删除</a></td></tr>
<tr><td>5</td><td>BT-2024-005</td><td>蓝牙称C1</td><td>蚁熊</td><td>MI-Scale2</td><td>采气厂</td><td>综合办公楼1F</td><td>2024-05-08</td><td><span class="tag tag-red">已停用</span></td><td><a class="link">详情</a> <a class="link" onclick="openMemberModal(4)">成员管理</a> <a class="link">编辑</a> <a class="link-danger">删除</a></td></tr>
</tbody>
</table>
</div>
@@ -137,7 +137,7 @@
<div class="form-item"><label>设备名称<span class="required">*</span></label><input class="form-input" placeholder="请输入设备名称"></div>
<div class="form-item"><label>设备编码<span class="required">*</span></label><input class="form-input" placeholder="请输入设备编码"></div>
<div class="form-item"><label>所属单位<span class="required">*</span></label><select class="form-select"><option value="">请选择</option><option>采油一厂</option><option>采油二厂</option><option>采气厂</option></select></div>
<div class="form-item"><label>设备厂商<span class="required">*</span></label><select class="form-select"><option value="">请选择</option><option>华为</option><option>小米</option><option>乐心</option></select></div>
<div class="form-item"><label>设备厂商<span class="required">*</span></label><select class="form-select"><option value="">请选择</option><option>InBody</option></select></div>
<div class="form-item"><label>设备型号<span class="required">*</span></label><select class="form-select"><option value="">请选择</option><option>HW-S100</option><option>MI-Scale2</option><option>LX-Pro</option></select></div>
<div class="form-item"><label>入库日期<span class="required">*</span></label><input class="form-input" type="date"></div>
<div class="form-item full">
+6 -6
View File
@@ -133,7 +133,7 @@
<div class="filter-bar">
<div class="filter-item"><label>所属单位</label><select class="filter-select"><option value="">全部</option><option>采油一厂</option><option>采油二厂</option><option>采气厂</option></select></div>
<div class="filter-item"><label>设备编码</label><input class="filter-input" placeholder="请输入设备编码"></div>
<div class="filter-item"><label>设备厂商</label><select class="filter-select"><option value="">全部</option><option>华为</option><option>小米</option><option>乐心</option></select></div>
<div class="filter-item"><label>设备厂商</label><select class="filter-select"><option value="">全部</option><option>InBody</option></select></div>
<div class="filter-item"><label>设备型号</label><select class="filter-select"><option value="">全部</option><option>HW-S100</option><option>MI-Scale2</option><option>LX-Pro</option></select></div>
<button class="btn btn-primary">查询</button>
<button class="btn btn-default">重置</button>
@@ -153,11 +153,11 @@
<table>
<thead><tr><th>序号</th><th>设备编码</th><th>设备名称</th><th>设备厂商</th><th>设备型号</th><th>所属单位</th><th>布放位置</th><th>入库日期</th><th>设备状态</th><th>操作</th></tr></thead>
<tbody>
<tr><td>1</td><td>FT-2024-001</td><td>体脂仪A1</td><td>华为</td><td>HW-S100</td><td>采油一厂</td><td>职工活动中心1F</td><td>2024-03-15</td><td><span class="tag tag-green">正常</span></td><td><a class="link">详情</a> <a class="link">编辑</a> <a class="link-danger">删除</a></td></tr>
<tr><td>2</td><td>FT-2024-002</td><td>体脂仪A2</td><td>小米</td><td>MI-Scale2</td><td>采油一厂</td><td>办公楼2F健身房</td><td>2024-03-18</td><td><span class="tag tag-green">正常</span></td><td><a class="link">详情</a> <a class="link">编辑</a> <a class="link-danger">删除</a></td></tr>
<tr><td>3</td><td>FT-2024-003</td><td>体脂仪B1</td><td>乐心</td><td>LX-Pro</td><td>采油二厂</td><td>员工食堂入口</td><td>2024-04-02</td><td><span class="tag tag-orange">维护中</span></td><td><a class="link">详情</a> <a class="link">编辑</a> <a class="link-danger">删除</a></td></tr>
<tr><td>4</td><td>FT-2024-004</td><td>体脂仪B2</td><td>华为</td><td>HW-S100</td><td>采油二厂</td><td>宿舍楼大厅</td><td>2024-04-10</td><td><span class="tag tag-green">正常</span></td><td><a class="link">详情</a> <a class="link">编辑</a> <a class="link-danger">删除</a></td></tr>
<tr><td>5</td><td>FT-2024-005</td><td>体脂仪C1</td><td>小米</td><td>MI-Scale2</td><td>采气厂</td><td>综合办公楼1F</td><td>2024-05-08</td><td><span class="tag tag-red">已停用</span></td><td><a class="link">详情</a> <a class="link">编辑</a> <a class="link-danger">删除</a></td></tr>
<tr><td>1</td><td>FT-2024-001</td><td>体脂仪A1</td><td>InBody</td><td>HW-S100</td><td>采油一厂</td><td>职工活动中心1F</td><td>2024-03-15</td><td><span class="tag tag-green">正常</span></td><td><a class="link">详情</a> <a class="link">编辑</a> <a class="link-danger">删除</a></td></tr>
<tr><td>2</td><td>FT-2024-002</td><td>体脂仪A2</td><td>InBody</td><td>MI-Scale2</td><td>采油一厂</td><td>办公楼2F健身房</td><td>2024-03-18</td><td><span class="tag tag-green">正常</span></td><td><a class="link">详情</a> <a class="link">编辑</a> <a class="link-danger">删除</a></td></tr>
<tr><td>3</td><td>FT-2024-003</td><td>体脂仪B1</td><td>InBody</td><td>LX-Pro</td><td>采油二厂</td><td>员工食堂入口</td><td>2024-04-02</td><td><span class="tag tag-orange">维护中</span></td><td><a class="link">详情</a> <a class="link">编辑</a> <a class="link-danger">删除</a></td></tr>
<tr><td>4</td><td>FT-2024-004</td><td>体脂仪B2</td><td>InBody</td><td>HW-S100</td><td>采油二厂</td><td>宿舍楼大厅</td><td>2024-04-10</td><td><span class="tag tag-green">正常</span></td><td><a class="link">详情</a> <a class="link">编辑</a> <a class="link-danger">删除</a></td></tr>
<tr><td>5</td><td>FT-2024-005</td><td>体脂仪C1</td><td>InBody</td><td>MI-Scale2</td><td>采气厂</td><td>综合办公楼1F</td><td>2024-05-08</td><td><span class="tag tag-red">已停用</span></td><td><a class="link">详情</a> <a class="link">编辑</a> <a class="link-danger">删除</a></td></tr>
</tbody>
</table>
</div>
@@ -118,8 +118,8 @@ tbody tr:hover{background:#F8FBFF;}
<a href="plan-list.html">活动管理</a>
<a href="registration-tracking.html">报名管理</a>
<a href="action-record.html">过程管理</a>
<a href="history-plan-list.html" class="active">历史活动</a>
<a href="personnel-measure-record.html">人员数据</a>
<a href="history-plan-list.html">历史活动</a>
<a href="personnel-measure-record.html" class="active">人员数据</a>
<a href="personal-target-data.html">个人体重管理</a>
<a href="scale-device.html">设备管理</a>
<a href="exception-system-dirty.html">异常事件</a>
@@ -133,9 +133,9 @@ tbody tr:hover{background:#F8FBFF;}
<!-- 侧边栏 -->
<aside class="sidebar">
<div class="sidebar-menu__title">历史活动</div>
<a href="history-plan-list.html" class="sidebar-item">活动列表</a>
<a href="history-personnel-list.html" class="sidebar-item active">人员列表</a>
<div class="sidebar-menu__title">人员数据</div>
<a href="personnel-measure-record.html" class="sidebar-item">三测记录</a>
<a href="personnel-overview-record.html" class="sidebar-item active">总览记录</a>
</aside>
<!-- 主内容 -->
@@ -255,8 +255,14 @@ tbody tr:hover{background:#F8FBFF;}
<script>
/* ===== 侧边栏高亮 ===== */
/* 本页是人员数据-总览记录的二级页面,URL 不在侧边栏菜单中时保持"总览记录"高亮 */
(function(){
var current = location.pathname.split('/').pop();
var matched = false;
document.querySelectorAll('.sidebar-item').forEach(function(item){
if(item.getAttribute('href') === current) matched = true;
});
if(!matched) return;
document.querySelectorAll('.sidebar-item').forEach(function(item){
var href = item.getAttribute('href');
item.classList.toggle('active', href === current);
@@ -74,6 +74,12 @@ body{font-family:-apple-system,BlinkMacSystemFont,'PingFang SC','Microsoft YaHei
.sub-tab-status .sub-tab-item:hover{color:var(--primary);border-color:var(--primary);}
.sub-tab-status .sub-tab-item.active{color:var(--primary);border-color:var(--primary);background:var(--primary-light);}
.sub-tab-item__badge{margin-left:4px;}
/* 行动记录子分类Tab(体重/饮食/运动) */
.sub-tab-bar{display:flex;align-items:center;padding:0 24px;background:#fff;box-shadow:var(--shadow-sm);}
.sub-tab-group{display:flex;gap:0;}
.sub-tab-bar .sub-tab-item{padding:10px 20px;font-size:var(--font-sm);cursor:pointer;color:var(--text-secondary);border-bottom:2px solid transparent;margin-bottom:-1px;transition:all .2s;font-weight:500;}
.sub-tab-bar .sub-tab-item:hover{color:var(--primary);}
.sub-tab-bar .sub-tab-item.active{color:var(--primary);border-bottom-color:var(--primary);font-weight:600;}
/* 筛选栏 */
.filter-bar{background:#fff;padding:16px 24px;display:flex;align-items:center;gap:16px;flex-wrap:wrap;}
@@ -335,7 +341,7 @@ tbody tr:hover{background:#F8FBFF;}
<!-- [交互] 五大Tab切换 — 下划线样式 -->
<div class="tab-bar" style="background:#fff;border-radius:var(--radius-md) var(--radius-md) 0 0;box-shadow:var(--shadow-sm);margin-bottom:0;" id="mainTabs">
<div class="tab-item active" onclick="switchMainTab(0)">报名管理</div>
<div class="tab-item" onclick="switchMainTab(1)">每日行动</div>
<div class="tab-item" onclick="switchMainTab(1)">行动记录</div>
<div class="tab-item" onclick="switchMainTab(2)">总览数据</div>
<div class="tab-item" onclick="switchMainTab(3)">活动排名</div>
<div class="tab-item" onclick="switchMainTab(4)">活动信息</div>
@@ -408,127 +414,72 @@ tbody tr:hover{background:#F8FBFF;}
</div>
</div>
<!-- ==================== Tab 1: 每日行动 ==================== -->
<!-- ==================== Tab 1: 行动记录 ==================== -->
<div class="tab-panel" id="tab-panel-1">
<!-- [交互] 每日行动子Tab — 分段选择 -->
<div style="background:#fff;border-radius:var(--radius-md) var(--radius-md) 0 0;box-shadow:var(--shadow-sm);padding:12px 24px;display:flex;align-items:center;">
<div class="segmented-tab" id="actionSegTabs">
<div class="segmented-tab__item active" onclick="switchActionTab(0)">每日记录</div>
<div class="segmented-tab__item" onclick="switchActionTab(1)">三测记录</div>
<!-- 筛选栏 -->
<div class="filter-bar" style="border-radius:var(--radius-md) var(--radius-md) 0 0;box-shadow:var(--shadow-sm);">
<div class="filter-item">
<label>单位部门</label>
<div class="org-select-wrap" id="actOrgWrap">
<div class="org-trigger" id="actOrgTrigger" onclick="toggleActOrg()">全部单位/部门</div>
<div class="org-panel" id="actOrgPanel">
<div class="org-col" id="actUnitCol">
<div class="org-col__title">单位</div>
<div class="org-item active" data-unit="" onclick="selectActUnit(this,'全部单位/部门','')">全部单位/部门</div>
<div class="org-item" data-unit="第四采油厂" onclick="selectActUnit(this,'第四采油厂','第四采油厂')">第四采油厂</div>
<div class="org-item" data-unit="采油一厂" onclick="selectActUnit(this,'采油一厂','采油一厂')">采油一厂</div>
<div class="org-item" data-unit="采油二厂" onclick="selectActUnit(this,'采油二厂','采油二厂')">采油二厂</div>
<div class="org-item" data-unit="采气一厂" onclick="selectActUnit(this,'采气一厂','采气一厂')">采气一厂</div>
</div>
<div class="org-col" id="actDeptCol">
<div class="org-col__title">部门</div>
<div class="org-item active" data-dept="" onclick="selectActDept(this,'全部部门','')">全部部门</div>
</div>
</div>
</div>
</div>
</div>
<!-- 每日记录 筛选栏 -->
<div class="filter-bar" id="actionFilterBar0" style="border-radius:0;">
<div class="filter-item">
<label>单位部门</label>
<div class="org-select-wrap" id="actOrgWrap">
<div class="org-trigger" id="actOrgTrigger" onclick="toggleActOrg()">全部单位/部门</div>
<div class="org-panel" id="actOrgPanel">
<div class="org-col" id="actUnitCol">
<div class="org-col__title">单位</div>
<div class="org-item active" data-unit="" onclick="selectActUnit(this,'全部单位/部门','')">全部单位/部门</div>
<div class="org-item" data-unit="第四采油厂" onclick="selectActUnit(this,'第四采油厂','第四采油厂')">第四采油厂</div>
<div class="org-item" data-unit="采油一厂" onclick="selectActUnit(this,'采油一厂','采油一厂')">采油一厂</div>
<div class="org-item" data-unit="采油二厂" onclick="selectActUnit(this,'采油二厂','采油二厂')">采油二厂</div>
<div class="org-item" data-unit="采气一厂" onclick="selectActUnit(this,'采气一厂','采气一厂')">采气一厂</div>
</div>
<div class="org-col" id="actDeptCol">
<div class="org-col__title">部门</div>
<div class="org-item active" data-dept="" onclick="selectActDept(this,'全部部门','')">全部部门</div>
</div>
</div>
</div>
</div>
<div class="filter-item"><label>日期范围</label><input class="filter-date" type="date" id="actDateFrom"><span style="font-size:var(--font-xs);color:var(--text-placeholder);"></span><input class="filter-date" type="date" id="actDateTo"></div>
<div class="filter-item"><label>日期范围</label><input class="filter-date" type="date" id="actDateFrom"><span style="font-size:var(--font-xs);color:var(--text-placeholder);"></span><input class="filter-date" type="date" id="actDateTo"></div>
<div class="filter-item"><label>姓名</label><input class="filter-input" id="actFilterName" placeholder="请输入姓名" style="width:100px;"></div>
<div class="filter-item"><label>员工编号</label><input class="filter-input" id="actFilterEmpId" placeholder="请输入编号" style="width:110px;"></div>
<button class="btn btn-primary" onclick="applyActFilter()"><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="resetActFilter()">重置</button>
</div>
<!-- 三测记录 筛选栏 -->
<div class="filter-bar" id="actionFilterBar1" style="display:none;border-radius:0;">
<div class="filter-item"><label>日期范围</label><input class="filter-date" type="date" id="actDateFrom1"><span style="font-size:var(--font-xs);color:var(--text-placeholder);"></span><input class="filter-date" type="date" id="actDateTo1"></div>
<div class="filter-item"><label>姓名</label><input class="filter-input" id="actFilterName1" placeholder="请输入姓名" style="width:100px;"></div>
<button class="btn btn-primary" onclick="applyActFilter1()"><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="resetActFilter1()">重置</button>
</div>
<!-- 操作栏 — 每日记录 -->
<div class="action-bar" id="actActionBar0">
<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="tab-panel active" id="act-panel-0">
<div class="table-card__content">
<table style="min-width:2600px;">
<thead><tr>
<th>序号</th><th>姓名</th><th>员工编号</th><th>性别</th><th>年龄</th><th>单位</th><th>部门</th>
<th>身高(cm)</th><th>初始体重(kg)</th><th>初始BMI</th><th>初始体脂(%)</th><th>初始腰围(cm)</th>
<th>目标体重(kg)</th><th>目标BMI</th><th>目标体脂(%)</th><th>目标腰围(cm)</th>
<th>现体重(kg)</th><th>现BMI</th><th>现体脂(%)</th><th>现腰围(cm)</th>
<th>体重变化(kg)</th><th>BMI变化</th><th>体脂变化(%)</th><th>腰围变化(cm)</th>
<th>日期</th><th>饮食记录</th><th>运动记录</th><th>体重记录</th>
</tr></thead>
<tbody id="actBody0"></tbody>
</table>
</div>
<div class="pagination">
<span id="actPageInfo0">显示 0 条记录</span>
<button class="page-btn" onclick="actGoPage(0,-1)"></button>
<span id="actPageNum0" style="font-size:var(--font-sm);color:var(--text-secondary);">第 1 页</span>
<button class="page-btn" onclick="actGoPage(0,1)"></button>
<!-- [交互] 子分类切换:体重/饮食/运动 -->
<div class="sub-tab-bar">
<div class="sub-tab-group">
<div class="sub-tab-item active" data-sub="weight" onclick="switchSubTab('weight')">体重</div>
<div class="sub-tab-item" data-sub="diet" onclick="switchSubTab('diet')">饮食</div>
<div class="sub-tab-item" data-sub="exercise" onclick="switchSubTab('exercise')">运动</div>
</div>
</div>
<!-- 三测记录 表格 -->
<div class="tab-panel" id="act-panel-1">
<!-- [交互] 子分类方框选择:体重/饮食/运动 -->
<div class="sub-tab-status" style="padding:12px 24px;">
<div class="sub-tab-item active" onclick="switchMeasureTab('weight')">体重</div>
<div class="sub-tab-item" onclick="switchMeasureTab('diet')">饮食</div>
<div class="sub-tab-item" onclick="switchMeasureTab('exercise')">运动</div>
<!-- [交互] 记录状态(左)+ 操作按钮(右)同行 -->
<div class="status-action-row">
<div class="sub-tab-status">
<span>记录状态</span>
<div class="sub-tab-item active" data-status="all" onclick="switchRecordStatus('all')">全部</div>
<div class="sub-tab-item" data-status="yes" onclick="switchRecordStatus('yes')">已记录</div>
<div class="sub-tab-item" data-status="no" onclick="switchRecordStatus('no')">未记录</div>
</div>
<!-- 记录状态 + 操作按钮 -->
<div class="status-action-row">
<div class="radio-group">
<span style="font-size:var(--font-xs);color:var(--text-secondary);">记录状态</span>
<label class="radio-item" onclick="switchRecordStatus('all')">
<span class="radio-item__dot" id="radioDotAll"></span>全部
</label>
<label class="radio-item" onclick="switchRecordStatus('yes')">
<span class="radio-item__dot" id="radioDotYes"></span>已记录
</label>
<label class="radio-item" onclick="switchRecordStatus('no')">
<span class="radio-item__dot" id="radioDotNo"></span>未记录
</label>
</div>
<div style="display:flex;gap:8px;">
<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>
<div class="table-card__content">
<table>
<thead><tr>
<th>序号</th><th>姓名</th><th>员工编号</th><th>性别</th><th>年龄</th><th>单位</th><th>部门</th>
<th class="th-sortable" id="sortCount" onclick="toggleActSort()">打卡次数 <span class="sort-arrow"></span></th>
<th>首次记录日期</th><th>末次记录日期</th>
</tr></thead>
<tbody id="actBody1"></tbody>
</table>
</div>
<div class="pagination">
<span id="actPageInfo1">显示 0 条记录</span>
<button class="page-btn" onclick="actGoPage(1,-1)"></button>
<span id="actPageNum1" style="font-size:var(--font-sm);color:var(--text-secondary);">第 1 页</span>
<button class="page-btn" onclick="actGoPage(1,1)"></button>
<div style="display:flex;gap:8px;">
<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>
<div class="table-card__content">
<table>
<thead id="actThead"></thead>
<tbody id="actBody"></tbody>
</table>
</div>
<div class="pagination">
<span id="actPageInfo">显示 0 条记录</span>
<button class="page-btn" onclick="actGoPage(-1)"></button>
<span id="actPageNum" style="font-size:var(--font-sm);color:var(--text-secondary);">第 1 页</span>
<button class="page-btn" onclick="actGoPage(1)"></button>
</div>
</div>
</div>
@@ -744,52 +695,18 @@ tbody tr:hover{background:#F8FBFF;}
</main>
<!-- [弹窗] 饮食记录查看 -->
<div class="record-overlay" id="dietOverlay">
<div class="record-dialog">
<!-- [弹窗] 打卡记录查看(体重/饮食/运动,按当前子分类动态渲染) -->
<div class="record-overlay" id="checkinOverlay">
<div class="record-dialog" id="checkinDialog" style="width:860px;">
<div class="record-dialog__header">
<span class="record-dialog__title">饮食记录</span>
<button class="record-dialog__close" onclick="closeDietDialog()"></button>
<span class="record-dialog__title" id="checkinTitle">打卡记录</span>
<button class="record-dialog__close" onclick="closeCheckinDialog()"></button>
</div>
<div class="record-dialog__body">
<div class="record-info" id="dietInfo"></div>
<div class="record-info" id="checkinInfo"></div>
<table class="record-table">
<thead><tr><th>序号</th><th>餐次</th><th>摄入时间</th><th>总摄入(千卡)</th><th>数据来源</th></tr></thead>
<tbody id="dietTbody"></tbody>
</table>
</div>
</div>
</div>
<!-- [弹窗] 运动记录查看 -->
<div class="record-overlay" id="exerciseOverlay">
<div class="record-dialog" style="width:820px;">
<div class="record-dialog__header">
<span class="record-dialog__title">运动记录</span>
<button class="record-dialog__close" onclick="closeExerciseDialog()"></button>
</div>
<div class="record-dialog__body">
<div class="record-info" id="exerciseInfo"></div>
<table class="record-table">
<thead><tr><th>序号</th><th>运动类型</th><th>运动数据</th><th>消耗(千卡)</th><th>来源</th></tr></thead>
<tbody id="exerciseTbody"></tbody>
</table>
</div>
</div>
</div>
<!-- [弹窗] 体重记录查看 -->
<div class="record-overlay" id="weightOverlay">
<div class="record-dialog" style="width:860px;">
<div class="record-dialog__header">
<span class="record-dialog__title">体重记录</span>
<button class="record-dialog__close" onclick="closeWeightDialog()"></button>
</div>
<div class="record-dialog__body">
<div class="record-info" id="weightInfo"></div>
<table class="record-table">
<thead><tr><th>序号</th><th>记录时间</th><th>体重(kg)</th><th>BMI</th><th>体脂率(%)</th><th>腰围(cm)</th><th>来源</th></tr></thead>
<tbody id="weightTbody"></tbody>
<thead id="checkinThead"></thead>
<tbody id="checkinTbody"></tbody>
</table>
</div>
</div>
@@ -950,7 +867,7 @@ function switchMainTab(idx){
el.classList.toggle('active', i === idx);
});
if(idx === 0) renderRegTable();
if(idx === 1){ renderActTable0(); renderActTable1(); }
if(idx === 1) applyActFilter();
if(idx === 2) renderOvTable();
}
@@ -1131,108 +1048,63 @@ function regGoPage(delta){
renderRegTable();
}
/* ===== 每日行动 ===== */
var actionTab = 0; // 0=每日记录, 1=三测记录
var measureSub = 'weight'; // 体重/饮食/运动
var recordStatus = 'all'; // 全部/已记录/未记录
var actSortAsc = true;
/* ===== 行动记录(参考 action-record 员工数据交互) ===== */
var actSub = 'weight'; // 子分类:体重/饮食/运动
var actStatus = 'all'; // 记录状态:全部/已记录/未记录
var actSortField = 'count'; // 排序字段:count打卡次数 / days打卡天数
var actSortAsc = false;
var actPageSize = 10;
var actPage = [0,0];
var actFiltered0 = [], actFiltered1 = [];
var actPage = 0;
var actFiltered = [];
/* 每日行动Mock人员数据 */
/* 行动记录Mock人员数据 */
var actEmployees = [
{name:'何婷',empId:'CQ001253',gender:'女',age:34,unit:'采气一厂',dept:'生产技术部',height:160,initWeight:70,initBmi:27.3,initFat:35.3,initWaist:84},
{name:'马超',empId:'CQ001254',gender:'男',age:36,unit:'采气一厂',dept:'生产技术部',height:179,initWeight:95,initBmi:29.6,initFat:32.0,initWaist:107},
{name:'赵鑫',empId:'CQ002101',gender:'男',age:29,unit:'采气一厂',dept:'信息中心',height:173,initWeight:82,initBmi:27.4,initFat:28.2,initWaist:95},
{name:'陈娟',empId:'CQ002102',gender:'女',age:31,unit:'采气一厂',dept:'生产技术部',height:158,initWeight:65,initBmi:26.0,initFat:32.5,initWaist:78},
{name:'刘明',empId:'CQ002103',gender:'男',age:38,unit:'采气一厂',dept:'生产技术部',height:176,initWeight:88,initBmi:28.4,initFat:29.8,initWaist:99},
{name:'王芳',empId:'CQ002104',gender:'女',age:27,unit:'采气一厂',dept:'信息中心',height:162,initWeight:58,initBmi:22.1,initFat:28.0,initWaist:73},
{name:'孙勇',empId:'CQ002105',gender:'男',age:44,unit:'采气一厂',dept:'生产技术部',height:170,initWeight:84,initBmi:29.1,initFat:31.5,initWaist:101},
{name:'周丽',empId:'CQ002106',gender:'女',age:32,unit:'采气一厂',dept:'信息中心',height:165,initWeight:68,initBmi:25.0,initFat:33.1,initWaist:80}
{name:'何婷',empId:'CQ001253',gender:'女',age:34,org:'采气一厂',unit:'采气一厂',dept:'生产技术部',height:160,weight:70,bmi:27.3,fat:35.3,waist:84,initWeight:70,initBmi:27.3,initFat:35.3,initWaist:84},
{name:'马超',empId:'CQ001254',gender:'男',age:36,org:'采气一厂',unit:'采气一厂',dept:'生产技术部',height:179,weight:95,bmi:29.6,fat:32.0,waist:107,initWeight:95,initBmi:29.6,initFat:32.0,initWaist:107},
{name:'赵鑫',empId:'CQ002101',gender:'男',age:29,org:'采气一厂',unit:'采气一厂',dept:'信息中心',height:173,weight:82,bmi:27.4,fat:28.2,waist:95,initWeight:82,initBmi:27.4,initFat:28.2,initWaist:95},
{name:'陈娟',empId:'CQ002102',gender:'女',age:31,org:'采气一厂',unit:'采气一厂',dept:'生产技术部',height:158,weight:65,bmi:26.0,fat:32.5,waist:78,initWeight:65,initBmi:26.0,initFat:32.5,initWaist:78},
{name:'刘明',empId:'CQ002103',gender:'男',age:38,org:'采气一厂',unit:'采气一厂',dept:'生产技术部',height:176,weight:88,bmi:28.4,fat:29.8,waist:99,initWeight:88,initBmi:28.4,initFat:29.8,initWaist:99},
{name:'王芳',empId:'CQ002104',gender:'女',age:27,org:'采气一厂',unit:'采气一厂',dept:'信息中心',height:162,weight:58,bmi:22.1,fat:28.0,waist:73,initWeight:58,initBmi:22.1,initFat:28.0,initWaist:73},
{name:'孙勇',empId:'CQ002105',gender:'男',age:44,org:'采气一厂',unit:'采气一厂',dept:'生产技术部',height:170,weight:84,bmi:29.1,fat:31.5,waist:101,initWeight:84,initBmi:29.1,initFat:31.5,initWaist:101},
{name:'周丽',empId:'CQ002106',gender:'女',age:32,org:'采气一厂',unit:'采气一厂',dept:'信息中心',height:165,weight:68,bmi:25.0,fat:33.1,waist:80,initWeight:68,initBmi:25.0,initFat:33.1,initWaist:80}
];
/* 生成每日记录数据 */
function buildDailyData(){
return actEmployees.map(function(e,i){
var targetWeight = Math.round(e.initWeight * 0.85);
var targetBmi = +(e.initBmi * 0.85).toFixed(1);
var targetFat = +(e.initFat * 0.80).toFixed(1);
var targetWaist = Math.round(e.initWaist * 0.88);
var curWeight = +(e.initWeight + (plan.avgWeightLoss || 0) + (Math.random()-0.5)*0.4).toFixed(1);
var curBmi = +(curWeight / ((e.height/100)*(e.height/100))).toFixed(1);
var curFat = +(e.initFat + (plan.avgFatDrop === '--' ? 0 : plan.avgFatDrop || 0)).toFixed(1);
var curWaist = Math.round(e.initWaist + (plan.avgWaistLoss === '--' ? 0 : plan.avgWaistLoss || 0));
var wc = +(curWeight - e.initWeight).toFixed(1);
var bc = +(curBmi - e.initBmi).toFixed(1);
var fc = +(curFat - e.initFat).toFixed(1);
var wac = curWaist - e.initWaist;
var hasDiet = i < 3;
var hasExercise = i < 4;
var hasWeight = i < 2;
return {
name:e.name, empId:e.empId, gender:e.gender, age:e.age, unit:e.unit, dept:e.dept,
height:e.height, initWeight:e.initWeight, initBmi:e.initBmi, initFat:e.initFat, initWaist:e.initWaist,
targetWeight:targetWeight, targetBmi:targetBmi, targetFat:targetFat, targetWaist:targetWaist,
curWeight:curWeight, curBmi:curBmi, curFat:curFat, curWaist:curWaist,
weightChange:wc, bmiChange:bc, fatChange:fc, waistChange:wac,
date:'2026-09-20',
hasDiet:hasDiet, hasExercise:hasExercise, hasWeight:hasWeight
};
});
function fmtActDate(d){
return d.getFullYear()+'-'+('0'+(d.getMonth()+1)).slice(-2)+'-'+('0'+d.getDate()).slice(-2);
}
/* 生成三测记录数据 */
/* 生成三测记录Mock数据(体重/饮食/运动三类) */
function buildMeasureData(){
return actEmployees.map(function(e,i){
var count = i < 2 ? 15 : (i < 5 ? 8 : (i < 7 ? 3 : 0));
var firstDate = count > 0 ? '2026-09-0' + (1 + Math.floor(i/2)) : '-';
var lastDate = count > 0 ? '2026-09-2' + (i % 5) : '-';
return {
name:e.name, empId:e.empId, gender:e.gender, age:e.age, unit:e.unit, dept:e.dept,
count:count, firstDate:firstDate, lastDate:lastDate, hasRecord: count > 0
};
var data = {weight:[], diet:[], exercise:[]};
var types = ['weight','diet','exercise'];
var today = new Date();
actEmployees.forEach(function(e,i){
var hasRecord = i % 5 !== 4;
types.forEach(function(t){
var count = hasRecord ? (t === 'weight' ? Math.floor(Math.random()*12)+2 : Math.floor(Math.random()*50)+10) : 0;
var days = hasRecord ? Math.min(count, Math.floor(Math.random()*60)+5) : 0;
var firstDay = new Date(today); firstDay.setDate(firstDay.getDate() - (60 + i*3));
var source = '';
if(t === 'weight' && hasRecord){
var sources = ['体重秤','蓝牙称','体脂仪','自记'];
source = sources[i % sources.length];
}
data[t].push({
planName: plan.planName, org: e.org, dept: e.dept,
name: e.name, empId: e.empId, gender: e.gender, age: e.age,
checkinCount: count, checkinDays: days,
firstDate: hasRecord ? fmtActDate(firstDay) : '-',
lastDate: hasRecord ? fmtActDate(today) : '-',
hasRecord: hasRecord, source: source
});
});
});
return data;
}
var dailyAllData = buildDailyData();
var measureAllData = buildMeasureData();
actFiltered0 = dailyAllData.slice();
actFiltered1 = measureAllData.slice();
var actMeasureData = buildMeasureData();
/* 每日行动子Tab切换 */
function switchActionTab(idx){
actionTab = idx;
document.querySelectorAll('#actionSegTabs .segmented-tab__item').forEach(function(el,i){
el.classList.toggle('active', i === idx);
});
document.getElementById('act-panel-0').classList.toggle('active', idx === 0);
document.getElementById('act-panel-1').classList.toggle('active', idx === 1);
document.getElementById('actionFilterBar0').style.display = idx === 0 ? '' : 'none';
document.getElementById('actionFilterBar1').style.display = idx === 0 ? 'none' : '';
document.getElementById('actActionBar0').style.display = idx === 0 ? '' : 'none';
}
/* 三测记录子分类切换 */
function switchMeasureTab(sub){
measureSub = sub;
var idx = sub === 'weight' ? 0 : (sub === 'diet' ? 1 : 2);
document.querySelectorAll('#act-panel-1 .sub-tab-status:first-child .sub-tab-item').forEach(function(el,i){
el.classList.toggle('active', i === idx);
});
applyActFilter1();
}
/* 记录状态切换 */
function switchRecordStatus(st){
recordStatus = st;
document.querySelectorAll('#act-panel-1 .status-action-row .radio-item').forEach(function(el){
el.classList.toggle('active', el.getAttribute('onclick').indexOf("'"+st+"'") > -1);
});
applyActFilter1();
}
/* 每日记录 单位部门 */
/* 单位部门双列面板 */
var actSelUnit = '', actSelDept = '';
function toggleActOrg(){
@@ -1260,20 +1132,32 @@ function selectActDept(elem, name, code){
document.getElementById('actOrgTrigger').textContent = label;
}
/* 每日记录筛选 */
/* 筛选 */
function applyActFilter(){
var unit = actSelUnit, dept = actSelDept;
var name = document.getElementById('actFilterName').value.trim().toLowerCase();
var empId = document.getElementById('actFilterEmpId').value.trim().toLowerCase();
actFiltered0 = dailyAllData.filter(function(d){
if(unit && d.unit !== unit) return false;
var dateFrom = document.getElementById('actDateFrom').value;
var dateTo = document.getElementById('actDateTo').value;
var recStatus = document.querySelector('#tab-panel-1 .sub-tab-status .sub-tab-item.active').dataset.status;
actStatus = recStatus;
var data = actMeasureData[actSub].slice();
actFiltered = data.filter(function(d){
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;
if(recStatus === 'yes' && !d.hasRecord) return false;
if(recStatus === 'no' && d.hasRecord) return false;
if(dateFrom && d.lastDate !== '-' && d.lastDate < dateFrom) return false;
if(dateTo && d.firstDate > dateTo) return false;
return true;
});
actPage[0] = 0;
renderActTable0();
var fieldKey = actSortField === 'days' ? 'checkinDays' : 'checkinCount';
actFiltered.sort(function(a,b){ return actSortAsc ? a[fieldKey] - b[fieldKey] : b[fieldKey] - a[fieldKey]; });
actPage = 0;
renderActHeader();
renderActTable();
}
function resetActFilter(){
@@ -1283,208 +1167,233 @@ function resetActFilter(){
document.getElementById('actDeptCol').innerHTML = '<div class="org-col__title">部门</div><div class="org-item active" data-dept="" onclick="selectActDept(this,\'全部部门\',\'\')">全部部门</div>';
document.getElementById('actFilterName').value = '';
document.getElementById('actFilterEmpId').value = '';
// 日期重置为本周(周一到周日)
var now = new Date();
var day = now.getDay(); day = day === 0 ? 7 : day;
var mon = new Date(now); mon.setDate(now.getDate() - day + 1);
var sun = new Date(now); sun.setDate(now.getDate() - day + 7);
document.getElementById('actDateFrom').value = fmtActDate(mon);
document.getElementById('actDateTo').value = fmtActDate(sun);
document.querySelectorAll('#tab-panel-1 .sub-tab-status .sub-tab-item').forEach(function(el){el.classList.toggle('active', el.dataset.status === 'all');});
actSortAsc = false; actSortField = 'count';
actStatus = 'all';
applyActFilter();
}
/* 三测记录筛选 */
function applyActFilter1(){
var name = document.getElementById('actFilterName1').value.trim().toLowerCase();
actFiltered1 = measureAllData.filter(function(d){
if(recordStatus === 'yes' && !d.hasRecord) return false;
if(recordStatus === 'no' && d.hasRecord) return false;
if(name && d.name.toLowerCase().indexOf(name) === -1) return false;
return true;
/* 子分类切换:体重/饮食/运动 */
function switchSubTab(type){
actSub = type;
document.querySelectorAll('#tab-panel-1 .sub-tab-group .sub-tab-item').forEach(function(el){
el.classList.toggle('active', el.dataset.sub === type);
});
actPage[1] = 0;
renderActTable1();
actSortAsc = false; actSortField = 'count';
// 重置记录状态为全部
document.querySelectorAll('#tab-panel-1 .sub-tab-status .sub-tab-item').forEach(function(el){el.classList.toggle('active', el.dataset.status === 'all');});
actStatus = 'all';
applyActFilter();
}
function resetActFilter1(){
document.getElementById('actFilterName1').value = '';
recordStatus = 'all';
document.querySelectorAll('#act-panel-1 .status-action-row .radio-item').forEach(function(el,i){el.classList.toggle('active', i === 0);});
document.querySelectorAll('#act-panel-1 .sub-tab-status:first-child .sub-tab-item').forEach(function(el,i){el.classList.toggle('active', i === 0);});
measureSub = 'weight';
applyActFilter1();
/* 记录状态切换 */
function switchRecordStatus(status){
document.querySelectorAll('#tab-panel-1 .sub-tab-status .sub-tab-item').forEach(function(el){
el.classList.toggle('active', el.dataset.status === status);
});
actStatus = status;
applyActFilter();
}
/* 更新统计卡片 */
/* 排序切换 */
function toggleActSort(){
actSortAsc = !actSortAsc;
document.getElementById('sortCount').classList.toggle('asc', actSortAsc);
document.getElementById('sortCount').classList.toggle('desc', !actSortAsc);
actFiltered1.sort(function(a,b){return actSortAsc ? a.count - b.count : b.count - a.count;});
actPage[1] = 0;
renderActTable1();
/* 打卡次数/天数排序切换 */
function toggleActSort(field){
if(actSortField !== field){ actSortField = field; actSortAsc = false; }
else { actSortAsc = !actSortAsc; }
applyActFilter();
}
/* 渲染每日记录表格 */
function renderActTable0(){
var tbody = document.getElementById('actBody0');
var start = actPage[0] * actPageSize;
var pd = actFiltered0.slice(start, start + actPageSize);
var tp = Math.ceil(actFiltered0.length / actPageSize) || 1;
document.getElementById('actPageInfo0').textContent = '显示 '+pd.length+' 条,共 '+actFiltered0.length+' 条记录';
document.getElementById('actPageNum0').textContent = '第 '+(actPage[0]+1)+'/'+tp+' 页';
if(actFiltered0.length === 0){ tbody.innerHTML = '<tr><td colspan="29" class="td-empty">暂无数据</td></tr>'; return; }
/* 渲染表头(体重tab为分组两行表头) */
function renderActHeader(){
var thead = document.getElementById('actThead');
var sortCountTh = '<th class="th-sortable" id="sortCount" '+(actSub==='weight'?'rowspan="2" ':'')+'onclick="toggleActSort(\'count\')">打卡次数 <span class="sort-arrow">'+(actSortField==='count'?(actSortAsc?'↑':'↓'):'↕')+'</span></th>';
var sortDaysTh = '<th class="th-sortable" id="sortDays" '+(actSub==='weight'?'rowspan="2" ':'')+'onclick="toggleActSort(\'days\')">打卡天数 <span class="sort-arrow">'+(actSortField==='days'?(actSortAsc?'↑':'↓'):'↕')+'</span></th>';
var html = '';
if(actSub === 'weight'){
html += '<tr>';
html += '<th rowspan="2">序号</th>';
html += '<th rowspan="2">姓名</th>';
html += '<th rowspan="2">员工编号</th>';
html += '<th rowspan="2">性别</th>';
html += '<th rowspan="2">年龄</th>';
html += '<th rowspan="2">单位</th>';
html += '<th rowspan="2">部门</th>';
html += sortCountTh;
html += sortDaysTh;
html += '<th rowspan="2">首次记录日期</th>';
html += '<th rowspan="2">末次记录日期</th>';
html += '<th colspan="6">末次记录数据</th>';
html += '</tr>';
html += '<tr>';
html += '<th>身高</th>';
html += '<th>体重</th>';
html += '<th>BMI</th>';
html += '<th>体脂</th>';
html += '<th>腰围</th>';
html += '<th>记录来源</th>';
html += '</tr>';
} else {
html += '<tr>';
html += '<th>序号</th>';
html += '<th>姓名</th>';
html += '<th>员工编号</th>';
html += '<th>性别</th>';
html += '<th>年龄</th>';
html += '<th>单位</th>';
html += '<th>部门</th>';
html += sortCountTh;
html += sortDaysTh;
html += '<th>首次记录日期</th>';
html += '<th>末次记录日期</th>';
html += '</tr>';
}
thead.innerHTML = html;
}
/* 渲染表格 */
function renderActTable(){
var tbody = document.getElementById('actBody');
var start = actPage * actPageSize;
var pd = actFiltered.slice(start, start + actPageSize);
var tp = Math.ceil(actFiltered.length / actPageSize) || 1;
document.getElementById('actPageInfo').textContent = '显示 ' + pd.length + ' 条,共 ' + actFiltered.length + ' 条记录';
document.getElementById('actPageNum').textContent = '第 ' + (actPage + 1) + '/' + tp + ' 页';
var isWeight = actSub === 'weight';
var colCount = isWeight ? 18 : 12;
if(actFiltered.length === 0){
tbody.innerHTML = '<tr><td colspan="'+colCount+'" class="td-empty">暂无匹配数据</td></tr>';
return;
}
var html = '';
pd.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');
html += '<tr>';
html += '<td>'+(i+1)+'</td><td>'+esc(d.name)+'</td><td>'+esc(d.empId)+'</td><td>'+d.gender+'</td><td>'+d.age+'</td><td>'+esc(d.unit)+'</td><td>'+esc(d.dept)+'</td>';
html += '<td>'+d.height+'</td><td>'+d.initWeight+'</td><td>'+d.initBmi+'</td><td>'+d.initFat+'</td><td>'+d.initWaist+'</td>';
html += '<td>'+d.targetWeight+'</td><td>'+d.targetBmi+'</td><td>'+d.targetFat+'</td><td>'+d.targetWaist+'</td>';
html += '<td>'+d.curWeight+'</td><td>'+d.curBmi+'</td><td>'+d.curFat+'</td><td>'+d.curWaist+'</td>';
html += '<td class="'+wcCls+'">'+d.weightChange+'</td><td class="'+bcCls+'">'+d.bmiChange+'</td><td class="'+fcCls+'">'+d.fatChange+'</td><td class="'+wacCls+'">'+d.waistChange+'</td>';
html += '<td>'+d.date+'</td>';
html += '<td>'+statusTag(d.hasDiet, d.empId, d.name, d.date,'diet')+'</td>';
html += '<td>'+statusTag(d.hasExercise, d.empId, d.name, d.date,'exercise')+'</td>';
html += '<td>'+statusTag(d.hasWeight, d.empId, d.name, d.date,'weight')+'</td>';
html += '<td>'+(i+1)+'</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><a class="link" href="javascript:void(0)" onclick="openCheckinDialog(\''+esc(d.empId)+'\',\''+esc(d.name)+'\',\''+esc(d.org)+'\',\''+esc(d.dept)+'\')">'+d.checkinCount+'</a></td>';
html += '<td>'+d.checkinDays+'</td>';
html += '<td>'+esc(d.firstDate)+'</td>';
html += '<td>'+esc(d.lastDate)+'</td>';
if(isWeight){
var emp = actEmployees.find(function(e){return e.empId === d.empId;}) || {};
html += '<td>'+(emp.height||'-')+'</td>';
html += '<td>'+(emp.weight||'-')+'</td>';
html += '<td>'+(emp.bmi?emp.bmi.toFixed(1):'-')+'</td>';
html += '<td>'+(emp.fat?emp.fat.toFixed(1):'-')+'</td>';
html += '<td>'+(emp.waist||'-')+'</td>';
html += '<td>'+esc(d.source||'-')+'</td>';
}
html += '</tr>';
});
tbody.innerHTML = html;
}
/* 渲染三测记录表格 */
function renderActTable1(){
var tbody = document.getElementById('actBody1');
var start = actPage[1] * actPageSize;
var pd = actFiltered1.slice(start, start + actPageSize);
var tp = Math.ceil(actFiltered1.length / actPageSize) || 1;
document.getElementById('actPageInfo1').textContent = '显示 '+pd.length+' 条,共 '+actFiltered1.length+' 条记录';
document.getElementById('actPageNum1').textContent = '第 '+(actPage[1]+1)+'/'+tp+' 页';
if(actFiltered1.length === 0){ tbody.innerHTML = '<tr><td colspan="11" class="td-empty">暂无数据</td></tr>'; return; }
var html = '';
pd.forEach(function(d,i){
html += '<tr>';
html += '<td>'+(i+1)+'</td><td>'+esc(d.name)+'</td><td>'+esc(d.empId)+'</td><td>'+d.gender+'</td><td>'+d.age+'</td><td>'+esc(d.unit)+'</td><td>'+esc(d.dept)+'</td>';
html += '<td>'+d.count+'</td><td>'+d.firstDate+'</td><td>'+d.lastDate+'</td>';
html += '</tr>';
});
tbody.innerHTML = html;
}
function actGoPage(panel, delta){
var data = panel === 0 ? actFiltered0 : actFiltered1;
var tp = Math.ceil(data.length / actPageSize) || 1;
var np = actPage[panel] + delta;
/* 翻页 */
function actGoPage(delta){
var tp = Math.ceil(actFiltered.length / actPageSize) || 1;
var np = actPage + delta;
if(np < 0 || np >= tp) return;
actPage[panel] = np;
panel === 0 ? renderActTable0() : renderActTable1();
actPage = np;
renderActTable();
}
/* ===== 工具函数 ===== */
function statusTag(flag, empId, name, date, type){
return flag
? '<a class="link" href="javascript:void(0)" onclick="open'+type.charAt(0).toUpperCase()+type.slice(1)+'Dialog(\''+esc(empId)+'\',\''+esc(name)+'\',\''+date+'\')">是</a>'
: '<span style="color:var(--text-primary);">否</span>';
}
/* ===== 饮食记录弹窗 ===== */
function openDietDialog(empId, name, date){
/* ===== 打卡记录弹窗(按当前子分类动态渲染) ===== */
function openCheckinDialog(empId, name, org, dept){
var emp = actEmployees.find(function(e){return e.empId === empId;}) || {};
var infoHtml = '';
infoHtml += '<div class="record-info__item"><span class="record-info__label">姓名:</span><span class="record-info__value">'+esc(name)+'</span></div>';
infoHtml += '<div class="record-info__item"><span class="record-info__label">员工编号:</span><span class="record-info__value">'+esc(empId)+'</span></div>';
infoHtml += '<div class="record-info__item"><span class="record-info__label">日期</span><span class="record-info__value">'+esc(date)+'</span></div>';
infoHtml += '<div class="record-info__item"><span class="record-info__label">单位</span><span class="record-info__value">'+esc(emp.unit)+'</span></div>';
infoHtml += '<div class="record-info__item"><span class="record-info__label">部门:</span><span class="record-info__value">'+esc(emp.dept)+'</span></div>';
document.getElementById('dietInfo').innerHTML = infoHtml;
var meals = ['早餐','午餐','晚餐','加餐'];
var times = ['07:30','08:15','12:00','12:30','18:00','18:45','15:30','10:00'];
var sources = ['智记','自记'];
var rows = Math.floor(Math.random()*4)+2;
var html = '';
for(var i=0;i<rows;i++){
var kcal = (Math.floor(Math.random()*6)+3)*100 + Math.floor(Math.random()*50);
html += '<tr><td>'+(i+1)+'</td><td>'+meals[i%4]+'</td><td>'+date+' '+times[i%8]+'</td><td>'+kcal+'</td><td>'+sources[i%2]+'</td></tr>';
infoHtml += '<div class="record-info__item"><span class="record-info__label">单位</span><span class="record-info__value">'+esc(org)+'</span></div>';
infoHtml += '<div class="record-info__item"><span class="record-info__label">部门</span><span class="record-info__value">'+esc(dept)+'</span></div>';
document.getElementById('checkinInfo').innerHTML = infoHtml;
var type = actSub;
var titleMap = {weight:'体重打卡记录', diet:'饮食打卡记录', exercise:'运动打卡记录'};
document.getElementById('checkinTitle').textContent = titleMap[type] || '打卡记录';
var dialog = document.getElementById('checkinDialog');
var thead = document.getElementById('checkinThead');
var tbody = document.getElementById('checkinTbody');
if(type === 'weight'){
dialog.style.width = '860px';
thead.innerHTML = '<tr><th>序号</th><th>记录时间</th><th>体重(kg)</th><th>BMI</th><th>体脂率(%)</th><th>腰围(cm)</th><th>数据来源</th></tr>';
var sources = ['自记','身高称','蓝牙称','体脂仪'];
var baseW = emp.weight || 80;
var baseFat = emp.fat || 30.0;
var baseWaist = emp.waist || 95;
var rows = Math.floor(Math.random()*4)+3;
var html = '';
for(var i=0;i<rows;i++){
var source = sources[i % sources.length];
var d = new Date(); d.setDate(d.getDate() - i);
var timeStr = fmtActDate(d)+' '+(('0'+(7+Math.floor(Math.random()*15))).slice(-2))+':'+('0'+Math.floor(Math.random()*60)).slice(-2);
var w = (baseW - (i*0.3) + (Math.random()-0.5)*1.0).toFixed(1);
var bmi = (w / ((emp.height||170)/100 * (emp.height||170)/100)).toFixed(1);
var fat = source==='身高称'||source==='蓝牙称' ? '-' : (baseFat - i*0.5 + (Math.random()-0.5)*0.8).toFixed(1);
var waist = source==='蓝牙称'||source==='自记' ? '-' : Math.round(baseWaist - i*1.5 + (Math.random()-0.5)*2);
html += '<tr><td>'+(i+1)+'</td><td>'+timeStr+'</td><td>'+w+'</td><td>'+bmi+'</td><td>'+fat+'</td><td>'+(waist==='-'?'-':waist)+'</td><td>'+source+'</td></tr>';
}
tbody.innerHTML = html;
} else if(type === 'diet'){
dialog.style.width = '760px';
thead.innerHTML = '<tr><th>序号</th><th>记录时间</th><th>餐次</th><th>总摄入(千卡)</th><th>数据来源</th></tr>';
var meals = ['早餐','午餐','晚餐','加餐'];
var times = ['07:30','08:15','12:00','12:30','18:00','18:45','15:30','10:00'];
var srcs = ['智记','自记'];
var rows = Math.floor(Math.random()*5)+3;
var html = '';
for(var i=0;i<rows;i++){
var d = new Date(); d.setDate(d.getDate() - Math.floor(i/2));
var kcal = (Math.floor(Math.random()*6)+3)*100 + Math.floor(Math.random()*50);
html += '<tr><td>'+(i+1)+'</td><td>'+fmtActDate(d)+' '+times[i%8]+'</td><td>'+meals[i%4]+'</td><td>'+kcal+'</td><td>'+srcs[i%2]+'</td></tr>';
}
tbody.innerHTML = html;
} else {
dialog.style.width = '900px';
thead.innerHTML = '<tr><th>序号</th><th>记录时间</th><th>运动类型</th><th>运动数据</th><th>消耗(千卡)</th><th>来源</th></tr>';
var sportTypes = ['跑步','健走','骑行','游泳','健身','瑜伽','跳绳','羽毛球','篮球','爬山'];
var sources = ['微信','自记','穿戴','器械'];
var rows = Math.floor(Math.random()*4)+3;
var html = '';
for(var i=0;i<rows;i++){
var st = sportTypes[i % sportTypes.length];
var source = sources[i % sources.length];
var d = new Date(); d.setDate(d.getDate() - i);
var timeStr = fmtActDate(d)+' '+(('0'+(6+Math.floor(Math.random()*16))).slice(-2))+':'+('0'+Math.floor(Math.random()*60)).slice(-2);
var kcal = (Math.floor(Math.random()*8)+2)*100 + Math.floor(Math.random()*50);
var sportData;
if(st === '健走' || st === '步行'){
var steps = [8523,12100,6850,15200,10030,9450,7800,11600];
sportData = steps[Math.floor(Math.random()*steps.length)].toLocaleString()+'步';
} else {
var mins = [30,35,45,50,60,75,90];
sportData = mins[Math.floor(Math.random()*mins.length)]+'分钟';
}
html += '<tr><td>'+(i+1)+'</td><td>'+timeStr+'</td><td>'+st+'</td><td>'+sportData+'</td><td>'+kcal+'</td><td>'+source+'</td></tr>';
}
tbody.innerHTML = html;
}
document.getElementById('dietTbody').innerHTML = html;
document.getElementById('dietOverlay').classList.add('show');
document.getElementById('checkinOverlay').classList.add('show');
}
function closeDietDialog(){
document.getElementById('dietOverlay').classList.remove('show');
function closeCheckinDialog(){
document.getElementById('checkinOverlay').classList.remove('show');
}
/* ===== 运动记录弹窗 ===== */
function openExerciseDialog(empId, name, date){
var emp = actEmployees.find(function(e){return e.empId === empId;}) || {};
var infoHtml = '';
infoHtml += '<div class="record-info__item"><span class="record-info__label">姓名:</span><span class="record-info__value">'+esc(name)+'</span></div>';
infoHtml += '<div class="record-info__item"><span class="record-info__label">员工编号:</span><span class="record-info__value">'+esc(empId)+'</span></div>';
infoHtml += '<div class="record-info__item"><span class="record-info__label">日期:</span><span class="record-info__value">'+esc(date)+'</span></div>';
infoHtml += '<div class="record-info__item"><span class="record-info__label">单位:</span><span class="record-info__value">'+esc(emp.unit)+'</span></div>';
infoHtml += '<div class="record-info__item"><span class="record-info__label">部门:</span><span class="record-info__value">'+esc(emp.dept)+'</span></div>';
document.getElementById('exerciseInfo').innerHTML = infoHtml;
var sportTypes = ['跑步','健走','骑行','游泳','健身','瑜伽','跳绳','羽毛球','篮球','爬山'];
var dataBySource = {
'微信': ['8,523步','12,100步','6,850步','15,200步','10,030步','9,450步'],
'自记': ['45分钟','60分钟','30分钟','50分钟'],
'穿戴': ['心率132 5km','心率145 8km','心率128 3km'],
'器械': ['3组×12次','4组×10次','5组×15次','60分钟']
};
var sources = ['微信','自记','穿戴','器械'];
var rows = Math.floor(Math.random()*4)+2;
var html = '';
for(var i=0;i<rows;i++){
var source = sources[i%4];
var dataArr = dataBySource[source];
var sportData = dataArr[Math.floor(Math.random()*dataArr.length)];
var kcal = (Math.floor(Math.random()*8)+2)*100 + Math.floor(Math.random()*50);
html += '<tr><td>'+(i+1)+'</td><td>'+sportTypes[i%10]+'</td><td>'+sportData+'</td><td>'+kcal+'</td><td>'+source+'</td></tr>';
}
document.getElementById('exerciseTbody').innerHTML = html;
document.getElementById('exerciseOverlay').classList.add('show');
}
function closeExerciseDialog(){
document.getElementById('exerciseOverlay').classList.remove('show');
}
/* ===== 体重记录弹窗 ===== */
function openWeightDialog(empId, name, date){
var emp = actEmployees.find(function(e){return e.empId === empId;}) || {};
var infoHtml = '';
infoHtml += '<div class="record-info__item"><span class="record-info__label">姓名:</span><span class="record-info__value">'+esc(name)+'</span></div>';
infoHtml += '<div class="record-info__item"><span class="record-info__label">员工编号:</span><span class="record-info__value">'+esc(empId)+'</span></div>';
infoHtml += '<div class="record-info__item"><span class="record-info__label">日期:</span><span class="record-info__value">'+esc(date)+'</span></div>';
infoHtml += '<div class="record-info__item"><span class="record-info__label">单位:</span><span class="record-info__value">'+esc(emp.unit)+'</span></div>';
infoHtml += '<div class="record-info__item"><span class="record-info__label">部门:</span><span class="record-info__value">'+esc(emp.dept)+'</span></div>';
document.getElementById('weightInfo').innerHTML = infoHtml;
var sources = ['自记','身高称','蓝牙称','体脂仪'];
var baseW = emp.initWeight || 80;
var baseBmi = emp.initBmi || 28;
var baseFat = emp.initFat || 30;
var baseWaist = emp.initWaist || 95;
var rows = Math.floor(Math.random()*3)+2;
var html = '';
for(var i=0;i<rows;i++){
var source = sources[i%4];
var timeStr = date+' '+(7+Math.floor(Math.random()*15))+':'+('0'+Math.floor(Math.random()*60)).slice(-2);
var w = (baseW - (i*0.3) + (Math.random()-0.5)*1.0).toFixed(1);
var bmi = (w / ((emp.height||170)/100 * (emp.height||170)/100)).toFixed(1);
var fat = source==='身高称'||source==='蓝牙称' ? '-' : (baseFat - i*0.5 + (Math.random()-0.5)*0.8).toFixed(1);
var waist = source==='蓝牙称'||source==='自记' ? '-' : Math.round(baseWaist - i*1.5 + (Math.random()-0.5)*2);
html += '<tr><td>'+(i+1)+'</td><td>'+timeStr+'</td><td>'+w+'</td><td>'+bmi+'</td><td>'+fat+'</td><td>'+waist+'</td><td>'+source+'</td></tr>';
}
document.getElementById('weightTbody').innerHTML = html;
document.getElementById('weightOverlay').classList.add('show');
}
function closeWeightDialog(){
document.getElementById('weightOverlay').classList.remove('show');
}
/* 点击遮罩关闭记录弹窗 */
['diet','exercise','weight'].forEach(function(type){
document.getElementById(type+'Overlay').addEventListener('click', function(e){
if(e.target === this){ document.getElementById(type+'Overlay').classList.remove('show'); }
});
/* 点击遮罩关闭打卡记录弹窗 */
document.getElementById('checkinOverlay').addEventListener('click', function(e){
if(e.target === this) closeCheckinDialog();
});
function esc(s){return String(s||'').replace(/&/g,'&amp;').replace(/"/g,'&quot;').replace(/</g,'&lt;').replace(/>/g,'&gt;');}
@@ -2026,8 +1935,15 @@ function ovGoPage(delta){
(function init(){
renderRegTable();
renderOvTable();
renderActTable0();
renderActTable1();
// 行动记录:日期默认本周,渲染表格
var now = new Date();
var day = now.getDay(); day = day === 0 ? 7 : day;
var mon = new Date(now); mon.setDate(now.getDate() - day + 1);
var sun = new Date(now); sun.setDate(now.getDate() - day + 7);
document.getElementById('actDateFrom').value = fmtActDate(mon);
document.getElementById('actDateTo').value = fmtActDate(sun);
renderActHeader();
applyActFilter();
renderPersonRankTable();
renderRankUnitTable2();
renderRankUnitTable3();
@@ -242,7 +242,7 @@
<td>-</td><td>-</td><td>-</td><td class="th-divider">-</td>
<td>77.5</td><td>26.2</td><td>24.0</td><td class="th-divider">91</td>
<td>-</td><td>-</td><td>-</td><td>-</td>
<td class="col-fixed-r"><a class="btn-link" href="personal-target-detail.html?empId=EMP-10101">查看</a></td>
<td class="col-fixed-r">-</td>
</tr>
<tr>
<td>7</td>
@@ -252,7 +252,7 @@
<td>-</td><td>-</td><td>-</td><td class="th-divider">-</td>
<td>64.5</td><td>25.8</td><td>30.2</td><td class="th-divider">78</td>
<td>-</td><td>-</td><td>-</td><td>-</td>
<td class="col-fixed-r"><a class="btn-link" href="personal-target-detail.html?empId=EMP-10102">查看</a></td>
<td class="col-fixed-r">-</td>
</tr>
<tr>
<td>8</td>
@@ -262,7 +262,7 @@
<td>-</td><td>-</td><td>-</td><td class="th-divider">-</td>
<td>91.2</td><td>32.3</td><td>34.2</td><td class="th-divider">110</td>
<td>-</td><td>-</td><td>-</td><td>-</td>
<td class="col-fixed-r"><a class="btn-link" href="personal-target-detail.html?empId=EMP-10103">查看</a></td>
<td class="col-fixed-r">-</td>
</tr>
<tr>
<td>9</td>
@@ -272,7 +272,7 @@
<td>-</td><td>-</td><td>-</td><td class="th-divider">-</td>
<td>57.3</td><td>21.0</td><td>24.2</td><td class="th-divider">71</td>
<td>-</td><td>-</td><td>-</td><td>-</td>
<td class="col-fixed-r"><a class="btn-link" href="personal-target-detail.html?empId=EMP-10104">查看</a></td>
<td class="col-fixed-r">-</td>
</tr>
<tr>
<td>10</td>
@@ -282,7 +282,7 @@
<td>-</td><td>-</td><td>-</td><td class="th-divider">-</td>
<td>85.5</td><td>27.9</td><td>28.0</td><td class="th-divider">96</td>
<td>-</td><td>-</td><td>-</td><td>-</td>
<td class="col-fixed-r"><a class="btn-link" href="personal-target-detail.html?empId=EMP-10105">查看</a></td>
<td class="col-fixed-r">-</td>
</tr>
</tbody>
</table>
@@ -995,7 +995,7 @@ tbody tr:hover td:nth-child(4){background:#F8FBFF;}
</div>
<table class="record-table">
<thead>
<tr><th>序号</th><th>活动名称</th><th>姓名</th><th>员工编号</th><th>单位</th><th>部门</th><th>体重记录</th><th>饮食记录</th><th>运动记录</th><th>三测完成</th></tr>
<tr><th>序号</th><th>活动名称</th><th>姓名</th><th>员工编号</th><th>单位</th><th>部门</th><th>体重记录</th><th>体脂记录</th><th>腰围记录</th><th>三测完成</th></tr>
</thead>
<tbody id="unitDetailTbody"></tbody>
</table>
@@ -2891,10 +2891,9 @@ function openUnitDetailDialog(org, type){
measureData.weight.forEach(function(w,i){
if(w.org !== org) return;
if(selectedPlanId && w.planId !== selectedPlanId) return;
var dRec = measureData.diet[i], exRec = measureData.exercise[i];
var key = w.empId;
if(!empMap[key]){
empMap[key] = {planName:w.planName,name:w.name,empId:w.empId,org:w.org,dept:w.dept,hasWeight:false,hasDiet:false,hasExercise:false};
empMap[key] = {planName:w.planName,name:w.name,empId:w.empId,org:w.org,dept:w.dept,hasWeight:false,hasFat:false,hasWaist:false};
}
function inRange(rec){
if(!rec.hasRecord) return false;
@@ -2902,12 +2901,17 @@ function openUnitDetailDialog(org, type){
if(dateTo && rec.firstDate > dateTo) return false;
return true;
}
if(inRange(w)) empMap[key].hasWeight = true;
if(inRange(dRec)) empMap[key].hasDiet = true;
if(inRange(exRec)) empMap[key].hasExercise = true;
// 三测 = 体重/体脂/腰围,均来自体重测量记录;是否含体脂/腰围取决于记录来源
if(inRange(w)){
empMap[key].hasWeight = true;
// 蓝牙称只有体重;身高称缺体脂;体脂仪/体重秤/自记数据完整
if(w.source !== '蓝牙称' && w.source !== '身高称') empMap[key].hasFat = true;
if(w.source === '体脂仪' || w.source === '自记') empMap[key].hasWaist = true;
}
});
var empList = [];
for(var k in empMap){ empMap[k].allDone = empMap[k].hasWeight && empMap[k].hasDiet && empMap[k].hasExercise; empList.push(empMap[k]); }
// 体重/体脂/腰围中有任一项记录即视为三测完成
for(var k in empMap){ empMap[k].allDone = empMap[k].hasWeight || empMap[k].hasFat || empMap[k].hasWaist; empList.push(empMap[k]); }
// 三测人数弹窗只显示三测完成的员工
if(type === 'measured'){ empList = empList.filter(function(e){ return e.allDone; }); }
var tbody = document.getElementById('unitDetailTbody');
@@ -2924,9 +2928,9 @@ function openUnitDetailDialog(org, type){
html += '<td>'+esc(e.org)+'</td>';
html += '<td>'+esc(e.dept)+'</td>';
html += '<td>'+(e.hasWeight?'<span style="color:var(--success);">●</span>':'<span style="color:var(--danger);">○</span>')+'</td>';
html += '<td>'+(e.hasDiet?'<span style="color:var(--success);">●</span>':'<span style="color:var(--danger);">○</span>')+'</td>';
html += '<td>'+(e.hasExercise?'<span style="color:var(--success);">●</span>':'<span style="color:var(--danger);">○</span>')+'</td>';
html += '<td>'+(e.allDone?'<span class="tag tag-green">是</span>':'<span class="tag tag-default">否</span>')+'</td>';
html += '<td>'+(e.hasFat?'<span style="color:var(--success);">●</span>':'<span style="color:var(--danger);">○</span>')+'</td>';
html += '<td>'+(e.hasWaist?'<span style="color:var(--success);">●</span>':'<span style="color:var(--danger);">○</span>')+'</td>';
html += '<td>'+(e.allDone?'<span class="tag tag-green">是</span>':'<span class="tag tag-red">否</span>')+'</td>';
html += '</tr>';
});
tbody.innerHTML = html;
@@ -288,42 +288,6 @@ tbody tr:hover{background:#F8FBFF;}
<label>员工编号</label>
<input class="filter-input" id="filterEmpId" placeholder="请输入编号" style="width:110px;">
</div>
<!-- [交互] 体重支持自定义运算符查询 -->
<div class="filter-item">
<label>体重(kg)</label>
<div class="filter-operator-row">
<select class="filter-select-sm" id="filterWeightOp" onchange="toggleFilterOp('Weight')">
<option value="">请选择</option>
<option value="eq">等于</option>
<option value="gt">大于</option>
<option value="lt">小于</option>
<option value="gte">大于等于</option>
<option value="lte">小于等于</option>
<option value="range">范围</option>
</select>
<input class="filter-input-sm" id="filterWeightVal1" placeholder="kg">
<span class="filter-sep" id="filterWeightSep" style="display:none;"></span>
<input class="filter-input-sm" id="filterWeightVal2" placeholder="kg" style="display:none;">
</div>
</div>
<!-- [交互] BMI支持自定义运算符查询 -->
<div class="filter-item">
<label>BMI</label>
<div class="filter-operator-row">
<select class="filter-select-sm" id="filterBmiOp" onchange="toggleFilterOp('Bmi')">
<option value="">请选择</option>
<option value="eq">等于</option>
<option value="gt">大于</option>
<option value="lt">小于</option>
<option value="gte">大于等于</option>
<option value="lte">小于等于</option>
<option value="range">范围</option>
</select>
<input class="filter-input-sm" id="filterBmiVal1" placeholder="值">
<span class="filter-sep" id="filterBmiSep" style="display:none;"></span>
<input class="filter-input-sm" id="filterBmiVal2" placeholder="值" style="display:none;">
</div>
</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>查询
@@ -762,44 +726,6 @@ function switchTab(idx){
applyFilter();
}
/* ===== 运算符切换 — 范围时显示第二个输入框和分隔符 ===== */
function toggleFilterOp(key){
var op = document.getElementById('filter'+key+'Op').value;
var v1 = document.getElementById('filter'+key+'Val1');
var v2 = document.getElementById('filter'+key+'Val2');
var sep = document.getElementById('filter'+key+'Sep');
if(op === 'range'){
v2.style.display = '';
sep.style.display = '';
} else if(op === ''){
v1.style.display = '';
v2.style.display = 'none';
sep.style.display = 'none';
} else {
v1.style.display = '';
v2.style.display = 'none';
sep.style.display = 'none';
}
}
/* 数值运算符筛选 */
function applyOpFilter(value, op, v1, v2){
if(!op) return true;
var n1 = parseFloat(v1);
if(isNaN(n1)) return true;
if(op === 'eq') return value === n1;
if(op === 'gt') return value > n1;
if(op === 'lt') return value < n1;
if(op === 'gte') return value >= n1;
if(op === 'lte') return value <= n1;
if(op === 'range'){
var n2 = parseFloat(v2);
if(isNaN(n2)) return true;
return value >= n1 && value <= n2;
}
return true;
}
/* ===== 单位部门双列面板 ===== */
var deptMap = {
'第四采油厂':['健康管理部','安全环保科','工会办公室','生产技术部','财务部','信息中心'],
@@ -864,14 +790,6 @@ function applyFilter(){
var name = document.getElementById('filterName').value.trim().toLowerCase();
var empId = document.getElementById('filterEmpId').value.trim().toLowerCase();
var weightOp = document.getElementById('filterWeightOp').value;
var weightV1 = document.getElementById('filterWeightVal1').value;
var weightV2 = document.getElementById('filterWeightVal2').value;
var bmiOp = document.getElementById('filterBmiOp').value;
var bmiV1 = document.getElementById('filterBmiVal1').value;
var bmiV2 = document.getElementById('filterBmiVal2').value;
var data = tabData[currentTab];
// 如果选择了活动,按活动过滤
@@ -884,8 +802,6 @@ function applyFilter(){
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;
if(!applyOpFilter(d.weight, weightOp, weightV1, weightV2)) return false;
if(!applyOpFilter(d.bmi, bmiOp, bmiV1, bmiV2)) return false;
return true;
});
@@ -907,14 +823,6 @@ function resetFilter(){
document.getElementById('filterName').value = '';
document.getElementById('filterEmpId').value = '';
['Weight','Bmi'].forEach(function(k){
document.getElementById('filter'+k+'Op').value = '';
document.getElementById('filter'+k+'Val1').value = '';
document.getElementById('filter'+k+'Val1').style.display = '';
document.getElementById('filter'+k+'Val2').value = '';
document.getElementById('filter'+k+'Val2').style.display = 'none';
document.getElementById('filter'+k+'Sep').style.display = 'none';
});
applyFilter();
}
@@ -137,7 +137,7 @@
<div class="form-item"><label>设备名称<span class="required">*</span></label><input class="form-input" placeholder="请输入设备名称"></div>
<div class="form-item"><label>设备编码<span class="required">*</span></label><input class="form-input" placeholder="请输入设备编码"></div>
<div class="form-item"><label>所属单位<span class="required">*</span></label><select class="form-select"><option value="">请选择</option><option>采油一厂</option><option>采油二厂</option><option>采气厂</option></select></div>
<div class="form-item"><label>设备厂商<span class="required">*</span></label><select class="form-select"><option value="">请选择</option><option>华为</option><option>小米</option><option>乐心</option></select></div>
<div class="form-item"><label>设备厂商<span class="required">*</span></label><select class="form-select"><option value="">请选择</option><option>数字味道</option><option>图讯</option><option>上禾电子</option></select></div>
<div class="form-item"><label>设备型号<span class="required">*</span></label><select class="form-select"><option value="">请选择</option><option>HW-S100</option><option>MI-Scale2</option><option>LX-Pro</option></select></div>
<div class="form-item"><label>入库日期<span class="required">*</span></label><input class="form-input" type="date"></div>
<div class="form-item full">
@@ -133,7 +133,7 @@
<div class="filter-bar">
<div class="filter-item"><label>所属单位</label><select class="filter-select"><option value="">全部</option><option>采油一厂</option><option>采油二厂</option><option>采气厂</option></select></div>
<div class="filter-item"><label>设备编码</label><input class="filter-input" placeholder="请输入设备编码"></div>
<div class="filter-item"><label>设备厂商</label><select class="filter-select"><option value="">全部</option><option>华为</option><option>小米</option><option>乐心</option></select></div>
<div class="filter-item"><label>设备厂商</label><select class="filter-select"><option value="">全部</option><option>数字味道</option><option>图讯</option><option>上禾电子</option></select></div>
<div class="filter-item"><label>设备型号</label><select class="filter-select"><option value="">全部</option><option>HW-S100</option><option>MI-Scale2</option><option>LX-Pro</option></select></div>
<button class="btn btn-primary">查询</button>
<button class="btn btn-default">重置</button>
@@ -153,11 +153,11 @@
<table>
<thead><tr><th>序号</th><th>设备编码</th><th>设备名称</th><th>设备厂商</th><th>设备型号</th><th>所属单位</th><th>布放位置</th><th>入库日期</th><th>设备状态</th><th>操作</th></tr></thead>
<tbody>
<tr><td>1</td><td>SC-2024-001</td><td>体重秤A1</td><td>华为</td><td>HW-S100</td><td>采油一厂</td><td>职工活动中心1F</td><td>2024-03-15</td><td><span class="tag tag-green">正常</span></td><td><a class="link">详情</a> <a class="link">编辑</a> <a class="link-danger">删除</a></td></tr>
<tr><td>2</td><td>SC-2024-002</td><td>体重秤A2</td><td>小米</td><td>MI-Scale2</td><td>采油一厂</td><td>办公楼2F健身房</td><td>2024-03-18</td><td><span class="tag tag-green">正常</span></td><td><a class="link">详情</a> <a class="link">编辑</a> <a class="link-danger">删除</a></td></tr>
<tr><td>3</td><td>SC-2024-003</td><td>体重秤B1</td><td>乐心</td><td>LX-Pro</td><td>采油二厂</td><td>员工食堂入口</td><td>2024-04-02</td><td><span class="tag tag-orange">维护中</span></td><td><a class="link">详情</a> <a class="link">编辑</a> <a class="link-danger">删除</a></td></tr>
<tr><td>4</td><td>SC-2024-004</td><td>体重秤B2</td><td>华为</td><td>HW-S100</td><td>采油二厂</td><td>宿舍楼大厅</td><td>2024-04-10</td><td><span class="tag tag-green">正常</span></td><td><a class="link">详情</a> <a class="link">编辑</a> <a class="link-danger">删除</a></td></tr>
<tr><td>5</td><td>SC-2024-005</td><td>体重秤C1</td><td>小米</td><td>MI-Scale2</td><td>采气厂</td><td>综合办公楼1F</td><td>2024-05-08</td><td><span class="tag tag-red">已停用</span></td><td><a class="link">详情</a> <a class="link">编辑</a> <a class="link-danger">删除</a></td></tr>
<tr><td>1</td><td>SC-2024-001</td><td>体重秤A1</td><td>数字味道</td><td>HW-S100</td><td>采油一厂</td><td>职工活动中心1F</td><td>2024-03-15</td><td><span class="tag tag-green">正常</span></td><td><a class="link">详情</a> <a class="link">编辑</a> <a class="link-danger">删除</a></td></tr>
<tr><td>2</td><td>SC-2024-002</td><td>体重秤A2</td><td>图讯</td><td>MI-Scale2</td><td>采油一厂</td><td>办公楼2F健身房</td><td>2024-03-18</td><td><span class="tag tag-green">正常</span></td><td><a class="link">详情</a> <a class="link">编辑</a> <a class="link-danger">删除</a></td></tr>
<tr><td>3</td><td>SC-2024-003</td><td>体重秤B1</td><td>上禾电子</td><td>LX-Pro</td><td>采油二厂</td><td>员工食堂入口</td><td>2024-04-02</td><td><span class="tag tag-orange">维护中</span></td><td><a class="link">详情</a> <a class="link">编辑</a> <a class="link-danger">删除</a></td></tr>
<tr><td>4</td><td>SC-2024-004</td><td>体重秤B2</td><td>数字味道</td><td>HW-S100</td><td>采油二厂</td><td>宿舍楼大厅</td><td>2024-04-10</td><td><span class="tag tag-green">正常</span></td><td><a class="link">详情</a> <a class="link">编辑</a> <a class="link-danger">删除</a></td></tr>
<tr><td>5</td><td>SC-2024-005</td><td>体重秤C1</td><td>图讯</td><td>MI-Scale2</td><td>采气厂</td><td>综合办公楼1F</td><td>2024-05-08</td><td><span class="tag tag-red">已停用</span></td><td><a class="link">详情</a> <a class="link">编辑</a> <a class="link-danger">删除</a></td></tr>
</tbody>
</table>
</div>
@@ -305,24 +305,6 @@ tbody tr:hover .td-actions{background:#F8FBFF;}
</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>
<div class="filter-item">
<label>体重(kg)</label>
<div class="filter-operator-row">
<select class="filter-select-sm" id="filterWeightOp" onchange="toggleFilterOp('Weight')">
<option value="">请选择</option><option value="eq">等于</option><option value="gt">大于</option><option value="lt">小于</option><option value="gte">大于等于</option><option value="lte">小于等于</option><option value="range">范围</option>
</select>
<input class="filter-input-sm" id="filterWeightVal1" placeholder="kg"><span class="filter-sep" id="filterWeightSep" style="display:none;"></span><input class="filter-input-sm" id="filterWeightVal2" placeholder="kg" style="display:none;">
</div>
</div>
<div class="filter-item">
<label>BMI</label>
<div class="filter-operator-row">
<select class="filter-select-sm" id="filterBmiOp" onchange="toggleFilterOp('Bmi')">
<option value="">请选择</option><option value="eq">等于</option><option value="gt">大于</option><option value="lt">小于</option><option value="gte">大于等于</option><option value="lte">小于等于</option><option value="range">范围</option>
</select>
<input class="filter-input-sm" id="filterBmiVal1" placeholder="值"><span class="filter-sep" id="filterBmiSep" style="display:none;"></span><input class="filter-input-sm" id="filterBmiVal2" placeholder="值" style="display:none;">
</div>
</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>
@@ -574,23 +556,6 @@ function switchTab(idx){
applyFilter();
}
/* 运算符 */
function toggleFilterOp(key){
var op=document.getElementById('filter'+key+'Op').value;
var v1=document.getElementById('filter'+key+'Val1'), v2=document.getElementById('filter'+key+'Val2'), sep=document.getElementById('filter'+key+'Sep');
if(op==='range'){v2.style.display='';sep.style.display='';}
else if(op===''){v1.style.display='';v2.style.display='none';sep.style.display='none';}
else {v1.style.display='';v2.style.display='none';sep.style.display='none';}
}
function applyOpFilter(value,op,v1,v2){
if(!op) return true;
var n1=parseFloat(v1); if(isNaN(n1)) return true;
if(op==='eq')return value===n1; if(op==='gt')return value>n1; if(op==='lt')return value<n1;
if(op==='gte')return value>=n1; if(op==='lte')return value<=n1;
if(op==='range'){var n2=parseFloat(v2); if(isNaN(n2))return true; return value>=n1&&value<=n2;}
return true;
}
/* 单位部门 */
var deptMap={'第四采油厂':['健康管理部','安全环保科','工会办公室','生产技术部','财务部','信息中心'],'采油一厂':['健康管理部','安全环保科','工会办公室','生产技术部'],'采油二厂':['健康管理部','安全环保科','财务部'],'采气一厂':['生产技术部','信息中心']};
var selectedUnitName='',selectedUnitCode='',selectedDeptName='',selectedDeptCode='';
@@ -612,14 +577,11 @@ function selectDept(elem,deptName,deptCode){
/* 筛选 */
function applyFilter(){
var unit=selectedUnitCode, dept=selectedDeptCode, name=document.getElementById('filterName').value.trim().toLowerCase(), empId=document.getElementById('filterEmpId').value.trim().toLowerCase();
var wOp=document.getElementById('filterWeightOp').value, wV1=document.getElementById('filterWeightVal1').value, wV2=document.getElementById('filterWeightVal2').value;
var bOp=document.getElementById('filterBmiOp').value, bV1=document.getElementById('filterBmiVal1').value, bV2=document.getElementById('filterBmiVal2').value;
var data = tabData[currentTab];
if(selectedPlanId) data = data.filter(function(d){return d.planId===selectedPlanId;});
filteredData = data.filter(function(d){
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;
if(!applyOpFilter(d.weight,wOp,wV1,wV2))return false; if(!applyOpFilter(d.bmi,bOp,bV1,bV2))return false;
return true;
});
renderTable(); updateTabBadges();
@@ -631,10 +593,6 @@ function resetFilter(){
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='';
['Weight','Bmi'].forEach(function(k){
document.getElementById('filter'+k+'Op').value=''; document.getElementById('filter'+k+'Val1').value=''; document.getElementById('filter'+k+'Val1').style.display='';
document.getElementById('filter'+k+'Val2').value=''; document.getElementById('filter'+k+'Val2').style.display='none'; document.getElementById('filter'+k+'Sep').style.display='none';
});
applyFilter();
}
function updateTabBadges(){for(var i=0;i<5;i++){var d=tabData[i];if(selectedPlanId)d=d.filter(function(x){return x.planId===selectedPlanId;});document.getElementById('tabBadge'+i).textContent=d.length;}}