冲突合并

This commit is contained in:
fengpu
2026-06-17 08:43:26 +08:00
15 changed files with 8329 additions and 145 deletions
+8
View File
@@ -24,6 +24,14 @@
- **决策**:每个模块维护 `doc/CHANGELOG.md` + `doc/PRD.md` + `doc/screenshots/`
- **原因**:规范化模块文档管理,便于团队协作和评审
## 单位部门筛选控件
- **决策**:所有筛选条件中的"单位部门"必须使用双列面板样式(左单位→右部门联动)
- **原因**:用户明确要求统一该交互模式
- **参考实现**`web-admin/health-consult/history-expert.html``web-admin/weight-management/registration-tracking.html`
- **结构**`org-select-wrap` 容器包裹 `org-trigger`(触发器) + `org-panel`(双列面板),左侧 `orgUnitCol` 列单位,右侧 `orgDeptCol` 列部门
- **交互**:点击触发器展开面板;选择左侧单位后右侧部门动态加载;选中部门后触发器文本更新为"单位 / 部门"
- **日期**2026-06-16
## 导航页设计状态标识
- **决策**SITE_MAP 中通过 `done: true` 字段标记模块设计完成状态
- **三态**:待设计(无页面)/ 设计中(有页面无done)/ 已完成(有页面+done:true
+3 -1
View File
@@ -5,6 +5,8 @@ type: lint
last_updated: 2026-06-15
commit: 2668114
---
last_updated: 2026-06-12
commit: 2373704
# 记忆健康检查报告
@@ -26,7 +28,7 @@ commit: 2668114
---
## AUTO-FIX 已执行清单
## 摘要
(无)
+14 -2
View File
@@ -24,7 +24,9 @@ commit: 2668114
- `emergency-medical/` — 应急就医(25+ 页)✅
- `health-checkup/` — 健康体检(20+ 页)✅
- `weight-management/` — 体重管理(23 页)✅
- `weight-main.html` — 体重管理主页(英雄区/三态卡片/吃动平衡/体重记录/排行榜/推荐视频)
- `weight-main.html` — 体重管理主页(英雄区/三态卡片/吃动平衡/体重记录/排行榜/推荐视频)
- `weight-management/` — 体重管理(20 页)✅
- `weight-main.html` — 体重管理主页(三态切换/英雄区/三态卡片/吃动平衡/体重记录/排行榜/推荐视频)
- `goal-commitment.html` — 目标承诺签订(活动/个人双类型+URL参数状态同步)
- `goal-management.html` — 目标管理(7种状态多卡片显隐+自我/活动目标切换)
- `basic-info.html` — 基本信息
@@ -35,6 +37,16 @@ commit: 2668114
- `my-promise.html` — 我的承诺书(证书风格)
- `balance-history.html` — 吃动平衡历史(月视图日历+柱状图)
- 新增 13 页:`diet-advice.html``eat-checkin.html``eat-history.html``exercise-advice.html``exercise-checkin.html``exercise-history.html``history.html``index.html``report-detail.html``weight-checkin.html``weight-history.html``weight-ranking.html``weight-report.html`
- `diet-advice.html` — 膳食建议(今日推荐摄入)
- `eat-checkin.html` — 饮食打卡
- `eat-history.html` — 摄入记录历史
- `exercise-advice.html` — 运动建议(今日推荐运动量)
- `exercise-checkin.html` — 运动打卡
- `exercise-history.html` — 消耗记录历史
- `weight-checkin.html` — 体重打卡
- `weight-history.html` — 体重记录历史
- `weight-ranking.html` — 排行榜
- `weight-report.html` — 体重报告
- `health-monitor/` — 健康监测(20+ 页)🔨 设计中
- `wearable/` — 穿戴设备监测(16 页:血氧/心率/压力/体温/步数/运动/睡眠/血压/心电+告警)
- `weight/` — 体重监测(3 页,已独立为 `weight-management/` 模块)
@@ -72,7 +84,7 @@ commit: 2668114
Web 管理端和员工端 APP 的其余模块(系统管理、运动管理、健康评估、知识普及、健康数据、心脑血管/糖尿病/癌症预防等)均为待开发状态。
## 总计
- 已完成/设计中:550+ 个 HTML 原型页面
- 已完成/设计中:560+ 个 HTML 原型页面
- 覆盖模块:18 个(含三端+其他终端)
## 近期里程碑
+3 -1
View File
@@ -231,10 +231,12 @@ const SITE_MAP = [
{ file:'archive-unit-report.html', label:'单位报表数据' },
{ file:'archive-algorithm-model.html', label:'算法模型' },
{ file:'plan-list.html', label:'计划列表' },
{ file:'plan-edit.html', label:'新增/编辑计划' },
{ file:'registration-tracking.html', label:'报名跟踪' },
{ file:'target-weight-review.html', label:'目标体重审核' },
{ file:'action-record.html', label:'行动记录' },
{ file:'action-overview.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:'活动统计' },
@@ -0,0 +1,716 @@
<!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 a{color:var(--text-placeholder);text-decoration:none;}
.page-header__breadcrumb a:hover{color:var(--primary);}
.page-header__breadcrumb span{color:var(--text-primary);}
/* 信息卡片区 */
.info-cards{display:flex;gap:16px;margin-bottom:16px;}
.info-card{background:#fff;border-radius:var(--radius-md);padding:16px 24px;box-shadow:var(--shadow-sm);flex:1;}
.info-card__title{font-size:var(--font-sm);color:var(--text-secondary);margin-bottom:12px;font-weight:500;display:flex;align-items:center;gap:6px;}
.info-card__title::before{content:'';width:3px;height:14px;background:var(--primary);border-radius:2px;display:inline-block;}
.info-card__body{display:flex;flex-wrap:wrap;gap:12px 24px;}
.info-item{display:flex;align-items:center;gap:6px;}
.info-item__label{font-size:var(--font-xs);color:var(--text-secondary);}
.info-item__value{font-size:var(--font-sm);color:var(--text-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;margin-bottom:16px;}
/* 日期筛选 */
.date-filter-bar{display:flex;align-items:center;justify-content:space-between;padding:12px 24px;background:#fff;border-radius:var(--radius-md) var(--radius-md) 0 0;box-shadow:var(--shadow-sm);margin-bottom:0;}
.date-filter-tabs{display:flex;align-items:center;gap:2px;}
.date-filter-tab{padding:5px 14px;font-size:var(--font-xs);color:var(--text-secondary);cursor:pointer;border:1px solid var(--border);border-radius:var(--radius-sm);transition:all .15s;user-select:none;background:#fff;}
.date-filter-tab:hover{color:var(--primary);border-color:var(--primary);}
.date-filter-tab.active{color:#fff;background:var(--primary);border-color:var(--primary);}
.date-filter-controls{display:flex;align-items:center;gap:8px;}
.filter-select{height:32px;border:1px solid var(--border);border-radius:var(--radius-sm);padding:0 24px 0 10px;font-size:var(--font-xs);outline:none;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;appearance:none;cursor:pointer;}
.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);}
/* 表格卡片 */
.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{width:100%;border-collapse:collapse;}
/* 表头 - 两行结构 */
thead th{background:#FAFAFA;padding:8px 6px;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 6px;text-align:center;font-size:var(--font-sm);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(1),tbody td:nth-child(1){position:sticky;left:0;z-index:6;background:#fff;width:100px;min-width:100px;max-width:100px;}
thead th:nth-child(1){z-index:9;background:#FAFAFA;}
tbody tr:hover td:nth-child(1){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);}
/* 变化值颜色 */
.change-up{color:var(--danger);}
.change-down{color:var(--success);}
.change-zero{color:var(--text-placeholder);}
/* 排名 */
.rank-num{display:inline-flex;align-items:center;justify-content:center;width:22px;height:22px;border-radius:50%;font-size:var(--font-xs);font-weight:700;}
.rank-1{background:#FFF7E6;color:#FA8C10;}
.rank-2{background:#F5F5F5;color:#8C8C8C;}
.rank-3{background:#FFF1F0;color:#D46B08;}
.rank-other{color:var(--text-secondary);}
/* 分页 */
.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);}
/* 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;}
</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="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="action-overview.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="activity-statistics.html" class="sidebar-item">活动统计</a>
</aside>
<!-- 主内容 -->
<main class="main">
<!-- 页面标题 -->
<div class="page-header">
<div class="page-header__breadcrumb">体重管理 / 过程管理 / <a href="action-overview.html">活动总览</a> / <span>赛况明细</span></div>
</div>
<!-- [交互] 干预计划 + 员工基本信息卡片 -->
<div class="info-cards">
<div class="info-card">
<div class="info-card__title">干预计划</div>
<div class="info-card__body" id="planCard">
<div class="info-item"><span class="info-item__label">计划名称:</span><span class="info-item__value" id="ciPlanName">-</span></div>
<div class="info-item"><span class="info-item__label">组织单位:</span><span class="info-item__value" id="ciOrg">-</span></div>
<div class="info-item"><span class="info-item__label">起止日期:</span><span class="info-item__value" id="ciDate">-</span></div>
<div class="info-item"><span class="info-item__label">进行天数:</span><span class="info-item__value" id="ciDays">-</span></div>
</div>
</div>
<div class="info-card">
<div class="info-card__title">员工信息</div>
<div class="info-card__body" id="empCard">
<div class="info-item"><span class="info-item__label">姓名:</span><span class="info-item__value" id="eiName">-</span></div>
<div class="info-item"><span class="info-item__label">员工编号:</span><span class="info-item__value" id="eiEmpId">-</span></div>
<div class="info-item"><span class="info-item__label">性别:</span><span class="info-item__value" id="eiGender">-</span></div>
<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 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="date-filter-bar">
<div class="date-filter-tabs" id="dateFilterTabs">
<span class="date-filter-tab active" data-type="all" onclick="switchDateType('all')">全部</span>
<span class="date-filter-tab" data-type="range" onclick="switchDateType('range')">选时</span>
<span class="date-filter-tab" data-type="day" onclick="switchDateType('day')"></span>
<span class="date-filter-tab" data-type="week" onclick="switchDateType('week')"></span>
<span class="date-filter-tab" data-type="month" onclick="switchDateType('month')"></span>
<span class="date-filter-tab" data-type="quarter" onclick="switchDateType('quarter')"></span>
<span class="date-filter-tab" data-type="year" onclick="switchDateType('year')"></span>
</div>
<div class="date-filter-controls" id="dateFilterControls"></div>
</div>
<!-- 数据表格 -->
<div class="table-card" style="border-radius:0 0 var(--radius-md) var(--radius-md);">
<div class="table-card__content">
<table>
<thead>
<!-- [交互] 表头第一行:父级分类 -->
<tr>
<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>
<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>
<!-- 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 || (href === 'action-overview.html' && current === 'action-overview-detail.html'));
});
})();
/* ===== 数据 ===== */
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}
];
var pageSize = 15;
var currentPage = 0;
var detailData = [];
var employee = null;
var plan = null;
/* ===== 日期筛选状态 ===== */
var dateFilterType = 'all'; // all | range | day | week | month | quarter | year
var dateFilterRange = { from: '', to: '' };
var dateFilterDay = '';
var dateFilterWeek = ''; // 存储选中的日期,据此计算周一~周日
var dateFilterMonth = { year: '', month: '' };
var dateFilterQuarter = { year: '', quarter: '' };
var dateFilterYear = '';
/* ===== 解析URL参数 ===== */
function getParam(name){
var params = new URLSearchParams(location.search);
return params.get(name);
}
/* ===== 生成每日明细Mock数据 ===== */
function buildDetailData(emp){
var data = [];
// 使用计划起止日期生成每日数据
var dateFrom = new Date(plan.dateFrom);
var dateTo = new Date(plan.dateTo);
var today = new Date();
var end = dateTo < today ? dateTo : today;
var totalDays = Math.ceil((end - dateFrom) / (1000*60*60*24)) + 1;
// 目标值
var targetWeight = Math.round(emp.weight * 0.85);
var targetBmi = +(emp.bmi * 0.85).toFixed(1);
var targetWaist = Math.round(emp.waist * 0.88);
var targetFat = +(emp.fat * 0.80).toFixed(1);
// 初始值与目标值差异
var weightDiff = emp.weight - targetWeight;
var bmiDiff = +(emp.bmi - targetBmi).toFixed(1);
var waistDiff = emp.waist - targetWaist;
var fatDiff = +(emp.fat - targetFat).toFixed(1);
for(var d = 0; d < totalDays; d++){
var curDate = new Date(dateFrom);
curDate.setDate(curDate.getDate() + d);
var dateStr = curDate.getFullYear()+'-'+('0'+(curDate.getMonth()+1)).slice(-2)+'-'+('0'+curDate.getDate()).slice(-2);
// 线性插值 + 随机波动模拟每日变化
var progress = d / Math.max(totalDays - 1, 1);
var curWeight = +(emp.weight - weightDiff * progress + (Math.random() - 0.5) * 0.6).toFixed(1);
var curBmi = +(curWeight / ((emp.height/100) * (emp.height/100))).toFixed(1);
var curWaist = Math.round(emp.waist - waistDiff * progress + (Math.random() - 0.5) * 1.5);
var curFat = +(emp.fat - fatDiff * progress + (Math.random() - 0.5) * 0.5).toFixed(1);
var wChange = +(curWeight - emp.weight).toFixed(1);
var bChange = +(curBmi - emp.bmi).toFixed(1);
var waChange = +(curWaist - emp.waist).toFixed(1);
var fChange = +(curFat - emp.fat).toFixed(1);
// 摄入数据(千卡):早餐 200-500, 午餐 400-800, 晚餐 300-700, 加餐 0-300
var breakfast = Math.floor(Math.random() * 301) + 200;
var lunch = Math.floor(Math.random() * 401) + 400;
var dinner = Math.floor(Math.random() * 401) + 300;
var snack = Math.floor(Math.random() * 301);
var totalIntake = breakfast + lunch + dinner + snack;
// 消耗数据(千卡):基础消耗 1200-1800, 步数消耗 50-250, 其他消耗 0-200
var basalMetab = Math.floor(Math.random() * 601) + 1200;
var stepBurn = Math.floor(Math.random() * 201) + 50;
var otherBurn = Math.floor(Math.random() * 201);
var totalBurn = basalMetab + stepBurn + otherBurn;
// 吃动热量差 = 摄入 - 消耗
var balance = totalIntake - totalBurn;
// 当日减重排名(1-20之间随机)
var rank = Math.floor(Math.random() * 20) + 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
});
}
return data;
}
/* ===== 渲染信息卡片 ===== */
function renderInfoCards(){
if(!employee || !plan) return;
// 计划信息
document.getElementById('ciPlanName').textContent = plan.name;
document.getElementById('ciOrg').textContent = plan.org;
document.getElementById('ciDate').textContent = plan.dateFrom + ' ~ ' + plan.dateTo;
var planDays = Math.ceil((new Date(plan.dateTo) - new Date(plan.dateFrom)) / (1000*60*60*24)) + 1;
document.getElementById('ciDays').textContent = planDays + ' 天';
// 员工信息
document.getElementById('eiName').textContent = employee.name;
document.getElementById('eiEmpId').textContent = employee.empId;
document.getElementById('eiGender').textContent = employee.gender;
document.getElementById('eiAge').textContent = employee.age + ' 岁';
document.getElementById('eiDept').textContent = employee.org + ' / ' + employee.dept;
document.getElementById('eiHeight').textContent = employee.height + ' cm';
}
/* ===== 日期筛选 ===== */
/* [交互] 切换日期筛选类型 */
function switchDateType(type){
dateFilterType = type;
// 更新tab激活态
document.querySelectorAll('#dateFilterTabs .date-filter-tab').forEach(function(el){
el.classList.toggle('active', el.dataset.type === type);
});
// 重置筛选状态
dateFilterRange = { from: '', to: '' };
dateFilterDay = '';
dateFilterWeek = '';
dateFilterMonth = { year: '', month: '' };
dateFilterQuarter = { year: '', quarter: '' };
dateFilterYear = '';
updateDateControls();
currentPage = 0;
renderTable();
}
/* [交互] 根据筛选类型渲染日期控件 */
function updateDateControls(){
var container = document.getElementById('dateFilterControls');
var today = new Date();
var thisYear = today.getFullYear();
if(dateFilterType === 'all'){
container.innerHTML = '';
return;
}
var html = '';
if(dateFilterType === 'range'){
// 日期范围选择
html += '<input class="filter-date" type="date" id="dfRangeFrom" value="'+esc(dateFilterRange.from)+'" onchange="onRangeChange()">';
html += '<span style="font-size:var(--font-xs);color:var(--text-secondary);">至</span>';
html += '<input class="filter-date" type="date" id="dfRangeTo" value="'+esc(dateFilterRange.to)+'" onchange="onRangeChange()">';
} else if(dateFilterType === 'day'){
// 单日选择
html += '<input class="filter-date" type="date" id="dfDay" value="'+esc(dateFilterDay)+'" onchange="onDayChange()">';
} else if(dateFilterType === 'week'){
// 周选择 — 选一个日期,自动定位到其所在周(周一~周日)
html += '<span style="font-size:var(--font-xs);color:var(--text-secondary);">选择日期</span>';
html += '<input class="filter-date" type="date" id="dfWeek" value="'+esc(dateFilterWeek)+'" onchange="onWeekChange()">';
if(dateFilterWeek){
var weekRange = calcWeekRange(dateFilterWeek);
html += '<span style="font-size:var(--font-xs);color:#888;margin-left:4px;">'+weekRange.monday+' ~ '+weekRange.sunday+'</span>';
}
} else if(dateFilterType === 'month'){
// 月选择 — 年 + 月
html += '<select class="filter-select" id="dfMonthYear" onchange="onMonthChange()">';
for(var y = thisYear - 3; y <= thisYear; y++){
html += '<option value="'+y+'"'+(dateFilterMonth.year === String(y) ? ' selected' : '')+'>'+y+' 年</option>';
}
html += '</select>';
html += '<select class="filter-select" id="dfMonthMon" onchange="onMonthChange()">';
for(var m = 1; m <= 12; m++){
html += '<option value="'+m+'"'+(dateFilterMonth.month === String(m) ? ' selected' : '')+'>'+m+' 月</option>';
}
html += '</select>';
} else if(dateFilterType === 'quarter'){
// 季选择 — 年 + 季度
html += '<select class="filter-select" id="dfQuarterYear" onchange="onQuarterChange()">';
for(var y2 = thisYear - 3; y2 <= thisYear; y2++){
html += '<option value="'+y2+'"'+(dateFilterQuarter.year === String(y2) ? ' selected' : '')+'>'+y2+' 年</option>';
}
html += '</select>';
html += '<select class="filter-select" id="dfQuarterQ" onchange="onQuarterChange()">';
var quarters = ['Q1 (1-3月)','Q2 (4-6月)','Q3 (7-9月)','Q4 (10-12月)'];
for(var q = 0; q < 4; q++){
html += '<option value="'+(q+1)+'"'+(dateFilterQuarter.quarter === String(q+1) ? ' selected' : '')+'>'+quarters[q]+'</option>';
}
html += '</select>';
} else if(dateFilterType === 'year'){
// 年选择
html += '<select class="filter-select" id="dfYear" onchange="onYearChange()">';
for(var y3 = thisYear - 3; y3 <= thisYear; y3++){
html += '<option value="'+y3+'"'+(dateFilterYear === String(y3) ? ' selected' : '')+'>'+y3+' 年</option>';
}
html += '</select>';
}
container.innerHTML = html;
// 初始触发默认值填充
if(dateFilterType === 'month' && !dateFilterMonth.year){
onMonthChange();
} else if(dateFilterType === 'quarter' && !dateFilterQuarter.year){
onQuarterChange();
} else if(dateFilterType === 'year' && !dateFilterYear){
onYearChange();
}
}
function onRangeChange(){
dateFilterRange.from = document.getElementById('dfRangeFrom').value || '';
dateFilterRange.to = document.getElementById('dfRangeTo').value || '';
currentPage = 0; renderTable();
}
function onDayChange(){
dateFilterDay = document.getElementById('dfDay').value || '';
currentPage = 0; renderTable();
}
function onWeekChange(){
dateFilterWeek = document.getElementById('dfWeek').value || '';
updateDateControls(); // 刷新显示周范围
currentPage = 0; renderTable();
}
function onMonthChange(){
var yEl = document.getElementById('dfMonthYear');
var mEl = document.getElementById('dfMonthMon');
dateFilterMonth.year = yEl ? yEl.value : '';
dateFilterMonth.month = mEl ? mEl.value : '';
currentPage = 0; renderTable();
}
function onQuarterChange(){
var yEl = document.getElementById('dfQuarterYear');
var qEl = document.getElementById('dfQuarterQ');
dateFilterQuarter.year = yEl ? yEl.value : '';
dateFilterQuarter.quarter = qEl ? qEl.value : '';
currentPage = 0; renderTable();
}
function onYearChange(){
var yEl = document.getElementById('dfYear');
dateFilterYear = yEl ? yEl.value : '';
currentPage = 0; renderTable();
}
/* 根据一个日期计算其所在周的周一和周日 */
function calcWeekRange(dateStr){
var d = new Date(dateStr);
var dayOfWeek = d.getDay(); // 0=周日
var monday = new Date(d);
monday.setDate(d.getDate() - (dayOfWeek === 0 ? 6 : dayOfWeek - 1));
var sunday = new Date(monday);
sunday.setDate(monday.getDate() + 6);
var fmt = function(dd){ return dd.getFullYear()+'-'+('0'+(dd.getMonth()+1)).slice(-2)+'-'+('0'+dd.getDate()).slice(-2); };
return { monday: fmt(monday), sunday: fmt(sunday) };
}
/* 根据筛选条件过滤数据 */
function getFilteredData(){
if(dateFilterType === 'all') return detailData;
return detailData.filter(function(d){
if(dateFilterType === 'range'){
if(dateFilterRange.from && d.date < dateFilterRange.from) return false;
if(dateFilterRange.to && d.date > dateFilterRange.to) return false;
} else if(dateFilterType === 'day'){
if(dateFilterDay && d.date !== dateFilterDay) return false;
} else if(dateFilterType === 'week'){
if(dateFilterWeek){
var wr = calcWeekRange(dateFilterWeek);
if(d.date < wr.monday || d.date > wr.sunday) return false;
}
} else if(dateFilterType === 'month'){
if(dateFilterMonth.year && dateFilterMonth.month){
var prefix = dateFilterMonth.year + '-' + ('0'+dateFilterMonth.month).slice(-2);
if(d.date.indexOf(prefix) !== 0) return false;
}
} else if(dateFilterType === 'quarter'){
if(dateFilterQuarter.year && dateFilterQuarter.quarter){
var q = parseInt(dateFilterQuarter.quarter);
var qStart = (q - 1) * 3 + 1;
var qEnd = q * 3;
var m = parseInt(d.date.substring(5, 7));
var y = parseInt(d.date.substring(0, 4));
if(y !== parseInt(dateFilterQuarter.year)) return false;
if(m < qStart || m > qEnd) return false;
}
} else if(dateFilterType === 'year'){
if(dateFilterYear && d.date.indexOf(dateFilterYear) !== 0) return false;
}
return true;
});
}
/* ===== 渲染表格 ===== */
function renderTable(){
var tbody = document.getElementById('tableBody');
var filtered = getFilteredData();
var start = currentPage * pageSize;
var pageData = filtered.slice(start, start + pageSize);
var totalPages = Math.ceil(filtered.length / pageSize) || 1;
document.getElementById('pageInfo').textContent = '显示 ' + pageData.length + ' 条,共 ' + filtered.length + ' 条记录';
document.getElementById('pageNum').textContent = '第 ' + (currentPage + 1) + '/' + totalPages + ' 页';
if(filtered.length === 0){
tbody.innerHTML = '<tr><td colspan="27" class="td-empty">暂无匹配的每日明细数据</td></tr>';
return;
}
var html = '';
pageData.forEach(function(d){
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 ? '+' : '';
// 吃动热量差 颜色:正数(盈余)红色,负数(赤字)绿色
var balCls = d.balance > 0 ? 'change-up' : (d.balance < 0 ? 'change-down' : 'change-zero');
var balSign = d.balance > 0 ? '+' : '';
// 排名样式
var rankHtml = '';
if(d.rank === 1) rankHtml = '<span class="rank-num rank-1">1</span>';
else if(d.rank === 2) rankHtml = '<span class="rank-num rank-2">2</span>';
else if(d.rank === 3) rankHtml = '<span class="rank-num rank-3">3</span>';
else rankHtml = '<span class="rank-other">'+d.rank+'</span>';
html += '<tr>';
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 class="'+balCls+'">'+balSign+d.balance+'</td>';
// 当日减重排名
html += '<td>'+rankHtml+'</td>';
html += '</tr>';
});
tbody.innerHTML = html;
}
/* ===== 翻页 ===== */
function goPage(delta){
var totalPages = Math.ceil(getFilteredData().length / pageSize);
var newPage = currentPage + delta;
if(newPage < 0 || newPage >= totalPages) return;
currentPage = newPage;
renderTable();
}
/* ===== 工具函数 ===== */
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);
}
/* ===== 初始化 ===== */
(function init(){
var planId = getParam('planId');
var empId = getParam('empId');
// 查找计划和员工
plan = plans.find(function(p){return p.id === parseInt(planId);}) || plans[0];
employee = baseEmployees.find(function(e){return e.empId === empId;}) || baseEmployees[0];
// 更新页面标题
document.querySelector('.page-header__breadcrumb span').textContent = '赛况明细 - ' + employee.name;
// 渲染
renderInfoCards();
detailData = buildDetailData(employee);
// 默认展示最新数据(第一页显示最后的数据)
currentPage = Math.max(0, Math.ceil(detailData.length / pageSize) - 1);
renderTable();
})();
</script>
</body>
</html>
+686 -29
View File
@@ -3,37 +3,164 @@
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>动总览 | 体重管理</title>
<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);
}
.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);}
*{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);}
/* 计划选择区 */
.plan-selector{background:#fff;border-radius:var(--radius-md);padding:20px 24px;margin-bottom:16px;box-shadow:var(--shadow-sm);display:flex;align-items:flex-start;gap:24px;}
.plan-selector__left{flex:1;min-width:0;max-width:400px;}
.plan-selector__label{font-size:var(--font-sm);color:var(--text-secondary);margin-bottom:8px;font-weight:500;}
.plan-selector__right{flex:1;display:flex;gap:28px;padding:18px 20px;background:#FAFAFA;border-radius:var(--radius-md);border:1px solid var(--border);min-height:78px;align-items:center;}
.plan-selector__right--empty{justify-content:center;color:var(--text-placeholder);font-size:var(--font-sm);}
.plan-info-item{display:flex;flex-direction:column;gap:6px;}
.plan-info-item__label{font-size:var(--font-xs);color:var(--text-secondary);}
.plan-info-item__value{font-size:var(--font-base);color:var(--text-primary);font-weight:600;}
.plan-info-item__value strong{color:var(--primary);font-size:var(--font-lg);}
/* 搜索下拉 */
.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:20px 24px;display:flex;align-items:center;gap:16px;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);}
/* 单位部门双列面板 */
.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:3200px;white-space:nowrap;}
table{width:100%;border-collapse:collapse;}
/* 表头 - 两行结构 */
thead th{background:#FAFAFA;padding:8px 6px;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 6px;text-align:center;font-size:var(--font-sm);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(1),tbody td:nth-child(1){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(1){z-index:9;background:#FAFAFA;}
thead th:nth-child(2),tbody td:nth-child(2){position:sticky;left:200px;z-index:5;background:#fff;width:56px;min-width:56px;max-width:56px;}
thead th:nth-child(2){z-index:8;background:#FAFAFA;}
thead th:nth-child(3),tbody td:nth-child(3){position:sticky;left:256px;z-index:4;background:#fff;width:88px;min-width:88px;max-width:88px;}
thead th:nth-child(3){z-index:7;background:#FAFAFA;}
tbody tr:hover td:nth-child(1),
tbody tr:hover td:nth-child(2),
tbody tr:hover td:nth-child(3){background:#F8FBFF;}
/* 赛况明细列固定右侧 — 仅第一行表头(rowspan=2的th)和tbody最后一列 */
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);}
thead tr:first-child th:last-child{z-index:4;background:#FAFAFA;}
/* 第二行表头最后一个th(累计消耗)需要保持与父级表头相同的背景 */
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;}
.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-sm);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;}
</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">
@@ -51,16 +178,546 @@
<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="action-overview.html" class="sidebar-item active">动总览</a>
<a href="action-overview.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="activity-statistics.html" class="sidebar-item">活动统计</a>
</aside>
<!-- 主内容 -->
<main class="main">
<!-- 主内容区域 -->
<!-- 页面标题 -->
<div class="page-header">
<div class="page-header__breadcrumb">体重管理 / 过程管理 / <span>活动总览</span></div>
</div>
<!-- [交互] 干预计划选择区 — 搜索下拉选择计划,选中后右侧展示基本信息 -->
<div class="plan-selector">
<div class="plan-selector__left">
<div class="plan-selector__label">干预计划</div>
<div class="search-select" id="planSelect">
<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="plan-selector__right plan-selector__right--empty" id="planInfoEmpty">
<svg width="18" height="18" viewBox="0 0 18 18" fill="none" style="margin-right:6px;flex-shrink:0;"><circle cx="9" cy="9" r="8" stroke="#999" stroke-width="1.2" stroke-dasharray="3 2"/><path d="M9 5v4M9 11v.5" stroke="#999" stroke-width="1.2" stroke-linecap="round"/></svg>
可选择干预计划进行查看
</div>
<div class="plan-selector__right" id="planInfo" style="display:none;">
<div class="plan-info-item">
<span class="plan-info-item__label">组织单位</span>
<span class="plan-info-item__value" id="piOrg">-</span>
</div>
<div class="plan-info-item">
<span class="plan-info-item__label">起止日期</span>
<span class="plan-info-item__value" id="piDate">-</span>
</div>
<div class="plan-info-item">
<span class="plan-info-item__label">进行天数</span>
<span class="plan-info-item__value" id="piDays">-</span>
</div>
<div class="plan-info-item">
<span class="plan-info-item__label">应参加人数</span>
<span class="plan-info-item__value"><strong id="piCount">-</strong></span>
</div>
<div class="plan-info-item">
<span class="plan-info-item__label">实际参加人数</span>
<span class="plan-info-item__value"><strong id="piActual">-</strong></span>
</div>
</div>
</div>
<!-- [交互] 筛选栏 — 单位部门、姓名、员工编号 -->
<div class="filter-bar">
<!-- [交互] 双列面板:左选单位→右选部门 -->
<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">身高<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="4">运动总览</th>
<th rowspan="2">赛况明细</th>
</tr>
<!-- [交互] 表头第二行:饮食总览和运动总览的子列 -->
<tr>
<th>缺天</th>
<th>缺餐</th>
<th>日均摄入<br>(千卡)</th>
<th class="col-diet-last">累计摄入<br>(千卡)</th>
<th>缺天</th>
<th>日均步数</th>
<th>日均消耗<br>(千卡)</th>
<th class="col-exercise-last">累计消耗<br>(千卡)</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>
<!-- 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 buildOverviewData(){
var data = [];
baseEmployees.forEach(function(e, i){
var planIdx = i % 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 progress = (i % 5) / 4;
var curWeight = +(e.weight - (e.weight - targetWeight) * progress).toFixed(1);
var curBmi = +(curWeight / ((e.height/100) * (e.height/100))).toFixed(1);
var curWaist = +(e.waist - (e.waist - targetWaist) * progress).toFixed(1);
var curFat = +(e.fat - (e.fat - targetFat) * progress).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 planDays = Math.floor(Math.random() * 120) + 30;
// 饮食总览 - 缺天:随机0-5天
var dietMissDays = Math.floor(Math.random() * 6);
// 饮食总览 - 缺餐:随机0-8餐
var dietMissMeals = dietMissDays > 0 ? Math.floor(Math.random() * 8) + 1 : 0;
// 日均摄入:1200-2200千卡
var dietAvgDaily = Math.floor(Math.random() * 1000) + 1200;
// 累计摄入 = 日均 * (计划天数 - 缺天)
var dietTotal = dietAvgDaily * (planDays - dietMissDays);
// 运动总览 - 缺天:随机0-5天
var exMissDays = Math.floor(Math.random() * 6);
// 日均步数:5000-15000
var exAvgSteps = Math.floor(Math.random() * 10000) + 5000;
// 日均消耗:200-600千卡
var exAvgDaily = Math.floor(Math.random() * 400) + 200;
// 累计消耗 = 日均 * (计划天数 - 缺天)
var exTotal = exAvgDaily * (planDays - exMissDays);
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, 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,
dietMissDays: dietMissDays, dietMissMeals: dietMissMeals,
dietAvgDaily: dietAvgDaily, dietTotal: dietTotal,
exMissDays: exMissDays, exAvgSteps: exAvgSteps,
exAvgDaily: exAvgDaily, exTotal: exTotal
});
});
return data;
}
var overviewData = buildOverviewData();
var selectedPlanId = null;
var pageSize = 10;
var currentPage = 0;
var filteredData = overviewData.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+' | 应参加 '+p.totalCount+' 人</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');
document.getElementById('planInfoEmpty').style.display = 'none';
document.getElementById('planInfo').style.display = 'flex';
document.getElementById('piOrg').textContent = plan.org;
document.getElementById('piDate').textContent = plan.dateFrom + ' ~ ' + plan.dateTo;
document.getElementById('piDays').textContent = calcPlanDays(plan.dateFrom, plan.dateTo) + ' 天';
document.getElementById('piCount').textContent = plan.totalCount + ' 人';
document.getElementById('piActual').textContent = (plan.actualCount || 0) + ' 人';
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');
document.getElementById('planInfoEmpty').style.display = '';
document.getElementById('planInfo').style.display = 'none';
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 unit = selectedUnitCode;
var dept = selectedDeptCode;
var name = document.getElementById('filterName').value.trim().toLowerCase();
var empId = document.getElementById('filterEmpId').value.trim().toLowerCase();
var data = overviewData.slice();
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;
return true;
});
currentPage = 0;
renderTable();
}
function resetFilter(){
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="33" class="td-empty">暂无匹配数据,请选择干预计划后查看</td></tr>';
return;
}
var html = '';
pageData.forEach(function(d){
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>';
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.dietMissDays+'</td>';
html += '<td>'+d.dietMissMeals+'</td>';
html += '<td>'+d.dietAvgDaily+'</td>';
html += '<td class="col-diet-last">'+d.dietTotal+'</td>';
// 运动总览
html += '<td>'+d.exMissDays+'</td>';
html += '<td>'+d.exAvgSteps.toLocaleString()+'</td>';
html += '<td>'+d.exAvgDaily+'</td>';
html += '<td class="col-exercise-last">'+d.exTotal+'</td>';
// 赛况明细
html += '<td><a class="link" href="javascript:void(0)" onclick="openMatchDetail(\''+esc(d.empId)+'\',\''+esc(d.name)+'\')">查看</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();
}
/* ===== 赛况明细 ===== */
function openMatchDetail(empId, name){
var planId = selectedPlanId || '';
window.location.href = 'action-overview-detail.html?planId=' + encodeURIComponent(planId) + '&empId=' + encodeURIComponent(empId);
}
/* ===== 工具函数 ===== */
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 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+' | 应参加 '+p.totalCount+' 人</div>';
html += '</div>';
});
document.getElementById('planPanel').innerHTML = html;
renderTable();
})();
</script>
</body>
</html>
File diff suppressed because it is too large Load Diff
@@ -54,7 +54,7 @@
<aside class="sidebar">
<div class="sidebar-menu__title">过程管理</div>
<a href="action-record.html" class="sidebar-item">行动记录</a>
<a href="action-overview.html" class="sidebar-item">动总览</a>
<a href="action-overview.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="activity-statistics.html" class="sidebar-item active">活动统计</a>
+1 -1
View File
@@ -54,7 +54,7 @@
<aside class="sidebar">
<div class="sidebar-menu__title">过程管理</div>
<a href="action-record.html" class="sidebar-item">行动记录</a>
<a href="action-overview.html" class="sidebar-item">动总览</a>
<a href="action-overview.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="activity-statistics.html" class="sidebar-item">活动统计</a>
@@ -0,0 +1,52 @@
# CHANGELOG | 体重管理 Web 管理端
## 2026-06-16 | 体重管理活动计划管理页面全面重构
### 新增页面
- **`action-overview-detail.html`**:赛况明细页(716 行),含计划选择区(搜索下拉)、双维度 Tab(减重百分比/减脂百分比)、筛选栏(含数值运算符)、多行表头大数据表格
- **`plan-edit.html`**:新增/编辑计划页(1092 行),含计划基本信息表单、多 Tab 切换等完整交互
### 页面全面重构
- **`action-overview.html`**+715 行):
- CSS 整体重构:按组件分段注释(顶部导航/侧边栏/主内容/页面标题/计划选择区/搜索下拉/筛选栏/单位部门双列面板/按钮/操作栏/表格)
- 新增设计令牌 `--shadow-md`
- 新增页面标题面包屑、计划选择区(搜索下拉选择计划 + 右侧信息展示)
- 新增筛选栏(活动名称/活动类型/单位部门双列面板级联/日期范围)
- 新增操作栏(批量操作按钮+导出)
- 表格重构:两行多列合并表头、前三列固定左侧、横向滚动大数据表格(min-width: 3200px
- 标题与侧边栏标签从"行动总览"更新为"活动总览"
- **`action-record.html`**+2756 行):
- CSS 重构为分组件分段注释结构
- 新增计划选择区(搜索下拉选择计划)
- 新增 4 列统计卡片(打卡人数/饮食打卡/运动打卡/体重打卡,含可点击数字与未打卡红色标注)
- 新增 Tab 切换(全部/饮食打卡/运动打卡/体重打卡,含数字徽标)
- 新增筛选栏(日期范围/单位部门级联/数值运算符筛选)
- 表格重构:多行合并表头、横向滚动、分页组件
- **`plan-list.html`**+1307 行):
- CSS 重构为分组件分段注释结构
- 新增页面标题面包屑、筛选栏(计划名称/活动类型/年份/月份)
- 新增操作栏(新增计划/批量操作按钮)
- 表格重构:操作列固定右侧、状态标签(蓝/绿/橙/灰)、分页
- 新增计划新增/编辑弹窗(含表单:计划名称/活动类型/目标/时间/状态)
- 新增人员筛选弹窗(modal-xl,含筛选栏+人员列表表格)
- **`registration-tracking.html`**+1026 行):
- CSS 重构为分组件分段注释结构
- 新增计划选择区(搜索下拉)
- 新增 Tab 切换(待审核/已通过/已驳回/全部,含数字徽标)
- 新增筛选栏(姓名/排名范围数值运算符/单位部门双列面板级联/日期)
- 新增单位部门双列面板控件
- 表格重构:多行合并表头、横向滚动、分页
- **`target-weight-review.html`**+772 行):
- CSS 重构为分组件分段注释结构
- 新增计划选择区(搜索下拉)
- 新增 Tab 切换(待审核/已通过/已驳回/全部,含数字徽标)
- 新增筛选栏(姓名/初始体重范围数值运算符/目标体重范围数值运算符/单位部门双列面板/日期)
- 新增单位部门双列面板控件
- 表格新增通过/驳回操作按钮(btn-success / btn-danger
- 新增批量审核按钮
### 微调
- **`activity-statistics.html`**、**`detail-data.html`**、**`weight-ranking.html`**:侧边栏菜单"行动总览" → "活动总览"
### 导航页同步
- **`index.html`**SITE_MAP 新增 `plan-edit.html`(新增/编辑计划)、`action-overview-detail.html`(赛况明细),`action-overview.html` 标签由"行动总览"更新为"活动总览"
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -5,35 +5,234 @@
<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);
}
.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);}
*{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);}
/* 计划选择区 */
.plan-selector{background:#fff;border-radius:var(--radius-md);padding:20px 24px;margin-bottom:16px;box-shadow:var(--shadow-sm);display:flex;align-items:flex-start;gap:24px;}
.plan-selector__left{flex:1;min-width:0;max-width:400px;}
.plan-selector__label{font-size:var(--font-sm);color:var(--text-secondary);margin-bottom:8px;font-weight:500;}
.plan-selector__right{flex:1;display:flex;gap:28px;padding:18px 20px;background:#FAFAFA;border-radius:var(--radius-md);border:1px solid var(--border);min-height:78px;align-items:center;}
.plan-selector__right--empty{justify-content:center;color:var(--text-placeholder);font-size:var(--font-sm);}
.plan-info-item{display:flex;flex-direction:column;gap:6px;}
.plan-info-item__label{font-size:var(--font-xs);color:var(--text-secondary);}
.plan-info-item__value{font-size:var(--font-base);color:var(--text-primary);font-weight:600;}
.plan-info-item__value strong{color:var(--primary);font-size:var(--font-lg);}
/* 搜索下拉 */
.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;}
/* Tab 切换 */
.tab-bar{display:flex;gap:0;padding:0 24px;border-bottom:1px solid var(--border);}
.tab-item{padding:12px 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;}
.tab-item:hover{color:var(--primary);}
.tab-item.active{color:var(--primary);border-bottom-color:var(--primary);font-weight:600;}
.tab-item__badge{display:inline-block;margin-left:6px;padding:0 8px;border-radius:10px;font-size:var(--font-xs);background:#F0F0F0;color:var(--text-secondary);line-height:1.8;}
.tab-item.active .tab-item__badge{background:var(--primary-light);color:var(--primary);}
.tab-panel{display:none;}
.tab-panel.active{display:block;}
/* 筛选栏 */
.filter-bar{background:#fff;padding:20px 24px;display:flex;align-items:center;gap:16px;flex-wrap:wrap;}
.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-select{height:32px;border:1px solid var(--border);border-radius:var(--radius-sm);padding:0 24px 0 10px;font-size:var(--font-xs);outline:none;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;appearance:none;cursor:pointer;min-width:80px;}
/* 数值运算符筛选 */
.filter-operator-row{display:flex;align-items:center;gap:6px;}
.filter-operator-row .filter-select-sm{min-width:72px;}
.filter-operator-row .filter-input-sm{width:70px;}
.filter-operator-row .filter-sep{font-size:var(--font-xs);color:var(--text-placeholder);}
.filter-select-sm{height:32px;border:1px solid var(--border);border-radius:var(--radius-sm);padding:0 24px 0 10px;font-size:var(--font-xs);outline:none;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;appearance:none;cursor:pointer;min-width:80px;}
.filter-input-sm{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;}
.filter-input-sm:focus{border-color:var(--primary);}
/* 单位部门双列面板 */
.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-success{background:var(--success);color:#fff;}.btn-success:hover{background:#73d13d;}
.btn-danger{background:#fff;color:var(--danger);border:1px solid var(--danger);}.btn-danger:hover{background:var(--danger);color:#fff;}
.btn-export{background:#fff;color:var(--text-primary);border:1px solid var(--border);}.btn-export:hover{color:var(--primary);border-color:var(--primary);}
.btn-sm{height:28px;padding:0 12px;font-size:var(--font-xs);}
/* 表格卡片 */
.table-card{background:#fff;border-radius:0 0 var(--radius-md) var(--radius-md);box-shadow:var(--shadow-sm);overflow:hidden;}
.table-card__header{display:flex;align-items:center;justify-content:space-between;padding:16px 24px;border-bottom:1px solid var(--border);}
.table-card__title{font-size:var(--font-base);font-weight:600;}
.table-card__count{font-size:var(--font-sm);color:var(--text-secondary);}
.table-card__content{overflow-x:auto;-webkit-overflow-scrolling:touch;}
.table-card__content table{min-width:1300px;white-space:nowrap;}
table{width:100%;border-collapse:collapse;}
thead th{background:#FAFAFA;padding:10px 12px;text-align:center;font-size:var(--font-sm);color:var(--text-secondary);font-weight:500;border-bottom:1px solid var(--border);white-space:nowrap;}
tbody td{padding:12px 12px;text-align:center;font-size:var(--font-sm);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(1),tbody td:nth-child(1){position:sticky;left:0;z-index:6;background:#fff;width:220px;min-width:220px;max-width:220px;overflow:hidden;text-overflow:ellipsis;}
thead th:nth-child(1){z-index:8;background:#FAFAFA;}
thead th:nth-child(2),tbody td:nth-child(2){position:sticky;left:220px;z-index:5;background:#fff;width:64px;min-width:64px;max-width:64px;}
thead th:nth-child(2){z-index:7;background:#FAFAFA;}
thead th:nth-child(3),tbody td:nth-child(3){position:sticky;left:284px;z-index:4;background:#fff;width:100px;min-width:100px;max-width:100px;}
thead th:nth-child(3){z-index:6;background:#FAFAFA;}
tbody tr:hover td:nth-child(1),
tbody tr:hover td:nth-child(2),
tbody tr:hover td:nth-child(3){background:#F8FBFF;}
.td-empty{text-align:center;padding:48px 0;color:var(--text-placeholder);font-size:var(--font-sm);}
/* 操作列固定 */
.td-actions{position:sticky;right:0;background:#fff;box-shadow:-4px 0 8px rgba(0,0,0,0.04);}
thead .th-actions{position:sticky;right:0;background:#FAFAFA;box-shadow:-4px 0 8px rgba(0,0,0,0.04);}
tbody tr:hover .td-actions{background:#F8FBFF;}
/* 标签 */
.tag{display:inline-flex;align-items:center;padding:2px 8px;border-radius:10px;font-size:var(--font-xs);}
.tag-green{background:#F6FFED;color:var(--success);}
.tag-red{background:#FFF1F0;color:var(--danger);}
.tag-orange{background:#FFF7E6;color:#FA8C10;}
/* 分页 */
.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-sm);text-decoration:none;}.link:hover{color:#40a9ff;}
/* 操作栏 */
.action-bar{display:flex;align-items:center;gap:8px;margin:16px 0;}
/* 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;}
/* 审核弹窗 */
.audit-overlay{display:none;position:fixed;top:0;left:0;right:0;bottom:0;background:rgba(0,0,0,0.45);z-index:1000;align-items:center;justify-content:center;}
.audit-overlay.show{display:flex;}
.audit-dialog{background:#fff;border-radius:var(--radius-lg);box-shadow:0 8px 40px rgba(0,0,0,0.18);width:640px;overflow:hidden;max-height:90vh;display:flex;flex-direction:column;}
.audit-dialog__header{display:flex;align-items:center;justify-content:space-between;padding:16px 24px;border-bottom:1px solid var(--border);flex-shrink:0;}
.audit-dialog__title{font-size:var(--font-lg);font-weight:600;}
.audit-dialog__close{width:32px;height:32px;border:none;background:none;cursor:pointer;border-radius:var(--radius-sm);display:flex;align-items:center;justify-content:center;color:var(--text-secondary);font-size:20px;transition:all .15s;}
.audit-dialog__close:hover{background:#F5F7FA;color:var(--text-primary);}
.audit-dialog__body{padding:24px;overflow-y:auto;flex:1;}
.audit-dialog__footer{display:flex;justify-content:flex-end;gap:8px;padding:0 24px 24px;flex-shrink:0;}
/* 审核弹窗 - 基本信息卡片 */
.audit-info-card{background:#FAFAFA;border:1px solid var(--border);border-radius:var(--radius-md);padding:16px 20px;margin-bottom:16px;}
.audit-info-card__title{font-size:var(--font-sm);font-weight:600;color:var(--text-primary);margin-bottom:10px;padding-bottom:8px;border-bottom:1px dashed var(--border);}
.audit-info-card__grid{display:grid;grid-template-columns:1fr 1fr 1fr 1fr;gap:8px 16px;}
.audit-info-card__item{display:flex;flex-direction:column;gap:2px;min-width:0;}
.audit-info-card__label{font-size:var(--font-xs);color:var(--text-secondary);}
.audit-info-card__value{font-size:var(--font-sm);color:var(--text-primary);font-weight:500;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
/* 审核弹窗 - 指标对比表 */
.audit-cmp-card{border:1px solid var(--border);border-radius:var(--radius-md);overflow:hidden;margin-bottom:20px;}
.audit-cmp-card__header{display:flex;align-items:center;padding:12px 20px;background:#FAFAFA;border-bottom:1px solid var(--border);}
.audit-cmp-card__title{font-size:var(--font-sm);font-weight:600;color:var(--text-primary);}
.audit-cmp-table{width:100%;border-collapse:collapse;}
.audit-cmp-table th{padding:10px 16px;text-align:center;font-size:var(--font-xs);color:var(--text-secondary);font-weight:500;border-bottom:1px solid var(--border);}
.audit-cmp-table th:first-child{text-align:left;padding-left:20px;}
.audit-cmp-table th.audit-cmp-table__col-before{background:#FFF7E6;}
.audit-cmp-table th.audit-cmp-table__col-arrow{width:40px;color:var(--text-placeholder);font-size:var(--font-base);}
.audit-cmp-table th.audit-cmp-table__col-after{background:#F6FFED;}
.audit-cmp-table th.audit-cmp-table__col-delta{width:80px;color:var(--text-placeholder);}
.audit-cmp-table td{padding:10px 16px;text-align:center;font-size:var(--font-sm);border-bottom:1px solid #F0F0F0;}
.audit-cmp-table td:first-child{text-align:left;font-weight:500;color:var(--text-primary);padding-left:20px;}
.audit-cmp-table tr:last-child td{border-bottom:none;}
.audit-cmp-table__before{color:var(--text-secondary);}
.audit-cmp-table__after{color:var(--success);font-weight:600;}
.audit-cmp-table__delta{font-size:var(--font-xs);font-weight:500;}
.audit-cmp-table__delta--good{color:var(--success);}
.audit-cmp-table__delta--neutral{color:var(--text-placeholder);}
/* 审核弹窗 - 通过/驳回决策按钮组 */
.audit-decision{display:flex;gap:12px;margin-bottom:0;align-items:center;}
.audit-decision__label{font-size:var(--font-sm);color:var(--text-primary);font-weight:500;margin-right:4px;}
.audit-decision__btn{flex:1;height:44px;border:2px solid var(--border);border-radius:var(--radius-md);background:#fff;cursor:pointer;font-size:var(--font-base);font-weight:500;color:var(--text-secondary);transition:all .2s;display:flex;align-items:center;justify-content:center;gap:6px;}
.audit-decision__btn:hover{border-color:#91d5ff;color:var(--primary);}
.audit-decision__btn--approve.selected{border-color:var(--success);background:#F6FFED;color:var(--success);font-weight:600;}
.audit-decision__btn--reject.selected{border-color:var(--danger);background:#FFF1F0;color:var(--danger);font-weight:600;}
/* 审核弹窗 - 驳回原因区域(默认隐藏) */
.audit-reject-section{display:none;margin-top:16px;padding-top:16px;border-top:1px dashed var(--border);}
.audit-reject-section.show{display:block;}
.audit-dialog__body .form-label{display:block;font-size:var(--font-sm);color:var(--text-primary);margin-bottom:8px;font-weight:500;}
.audit-dialog__body .form-label span{color:var(--danger);margin-left:2px;}
.audit-dialog__body textarea{width:100%;height:100px;border:1px solid var(--border);border-radius:var(--radius-sm);padding:10px 12px;font-size:var(--font-sm);outline:none;resize:none;font-family:inherit;box-sizing:border-box;transition:border-color .2s;}
.audit-dialog__body textarea:focus{border-color:var(--primary);}
.audit-dialog__body textarea::placeholder{color:var(--text-placeholder);}
/* 驳回原因tooltip样式 */
.reject-reason{max-width:200px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;display:inline-block;cursor:default;}
</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">
@@ -51,13 +250,532 @@
<span style="color:rgba(255,255,255,0.65);">系统管理员 ▾</span>
</div>
</div>
<!-- 侧边栏 -->
<aside class="sidebar">
<div class="sidebar-menu__title">报名管理</div>
<a href="registration-tracking.html" class="sidebar-item">报名跟踪</a>
<a href="target-weight-review.html" class="sidebar-item active">目标体重审核</a>
</aside>
<!-- 主内容 -->
<main class="main">
<!-- 主内容区域 -->
<div class="page-header">
<div class="page-header__breadcrumb">体重管理 / 报名管理 / <span>目标体重审核</span></div>
</div>
<!-- [交互] 干预计划选择区 -->
<div class="plan-selector">
<div class="plan-selector__left">
<div class="plan-selector__label">干预计划</div>
<div class="search-select" id="planSelect">
<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="plan-selector__right plan-selector__right--empty" id="planInfoEmpty">
<svg width="18" height="18" viewBox="0 0 18 18" fill="none" style="margin-right:6px;flex-shrink:0;"><circle cx="9" cy="9" r="8" stroke="#999" stroke-width="1.2" stroke-dasharray="3 2"/><path d="M9 5v4M9 11v.5" stroke="#999" stroke-width="1.2" stroke-linecap="round"/></svg>
可选择干预计划进行查看
</div>
<div class="plan-selector__right" id="planInfo" style="display:none;">
<div class="plan-info-item"><span class="plan-info-item__label">组织单位</span><span class="plan-info-item__value" id="piOrg">-</span></div>
<div class="plan-info-item"><span class="plan-info-item__label">起止日期</span><span class="plan-info-item__value" id="piDate">-</span></div>
<div class="plan-info-item"><span class="plan-info-item__label">进行天数</span><span class="plan-info-item__value" id="piDays">-</span></div>
<div class="plan-info-item"><span class="plan-info-item__label">应参加人数</span><span class="plan-info-item__value"><strong id="piCount">-</strong></span></div>
<div class="plan-info-item"><span class="plan-info-item__label">实际参加人数</span><span class="plan-info-item__value"><strong id="piActual">-</strong></span></div>
</div>
</div>
<!-- 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;">
<div class="tab-item active" data-tab="0" onclick="switchTab(0)">待审核<span class="tab-item__badge" id="tabBadge0">0</span></div>
<div class="tab-item" data-tab="1" onclick="switchTab(1)">已通过<span class="tab-item__badge" id="tabBadge1">0</span></div>
<div class="tab-item" data-tab="2" onclick="switchTab(2)">已通过待签署<span class="tab-item__badge" id="tabBadge2">0</span></div>
<div class="tab-item" data-tab="3" onclick="switchTab(3)">已驳回<span class="tab-item__badge" id="tabBadge3">0</span></div>
</div>
<!-- 筛选栏 -->
<div class="filter-bar" style="border-radius:0 0 var(--radius-md) var(--radius-md);margin-top:0;">
<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>
<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>
<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>
</div>
<!-- 数据表格 -->
<div class="table-card">
<div class="tab-panel active" id="tab-panel-0">
<div class="table-card__content">
<table>
<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>初始腰围(cm)</th><th>初始体脂(%)</th><th>目标体重(kg)</th><th>目标BMI</th><th>目标腰围(cm)</th><th>目标体脂(%)</th><th>提交时间</th><th class="th-actions">操作</th></tr></thead>
<tbody id="tableBody0"></tbody>
</table>
</div>
<div class="pagination"><span id="pageInfo0">显示 0 条记录</span><button class="page-btn"></button><button class="page-btn active">1</button><button class="page-btn"></button></div>
</div>
<div class="tab-panel" id="tab-panel-1">
<div class="table-card__content">
<table>
<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>初始腰围(cm)</th><th>初始体脂(%)</th><th>目标体重(kg)</th><th>目标BMI</th><th>目标腰围(cm)</th><th>目标体脂(%)</th><th>提交时间</th><th>审核时间</th><th>审核人</th></tr></thead>
<tbody id="tableBody1"></tbody>
</table>
</div>
<div class="pagination"><span id="pageInfo1">显示 0 条记录</span><button class="page-btn"></button><button class="page-btn active">1</button><button class="page-btn"></button></div>
</div>
<div class="tab-panel" id="tab-panel-2">
<div class="table-card__content">
<table>
<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>初始腰围(cm)</th><th>初始体脂(%)</th><th>目标体重(kg)</th><th>目标BMI</th><th>目标腰围(cm)</th><th>目标体脂(%)</th><th>提交时间</th><th>审核时间</th><th>审核人</th></tr></thead>
<tbody id="tableBody2"></tbody>
</table>
</div>
<div class="pagination"><span id="pageInfo2">显示 0 条记录</span><button class="page-btn"></button><button class="page-btn active">1</button><button class="page-btn"></button></div>
</div>
<div class="tab-panel" id="tab-panel-3">
<div class="table-card__content">
<table>
<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>初始腰围(cm)</th><th>初始体脂(%)</th><th>目标体重(kg)</th><th>目标BMI</th><th>目标腰围(cm)</th><th>目标体脂(%)</th><th>提交时间</th><th>驳回时间</th><th>审核人</th><th>驳回原因</th></tr></thead>
<tbody id="tableBody3"></tbody>
</table>
</div>
<div class="pagination"><span id="pageInfo3">显示 0 条记录</span><button class="page-btn"></button><button class="page-btn active">1</button><button class="page-btn"></button></div>
</div>
</div>
</main>
<!-- [弹窗] 审核 -->
<div class="audit-overlay" id="auditOverlay">
<div class="audit-dialog">
<div class="audit-dialog__header">
<span class="audit-dialog__title">目标体重审核</span>
<button class="audit-dialog__close" onclick="closeAudit()"></button>
</div>
<div class="audit-dialog__body">
<!-- 基本信息卡片 -->
<div class="audit-info-card">
<div class="audit-info-card__title">基本信息</div>
<div class="audit-info-card__grid" id="auditInfoGrid"></div>
</div>
<!-- 指标对比表:初始 vs 目标 -->
<div class="audit-cmp-card" id="auditCmpCard">
<div class="audit-cmp-card__header"><span class="audit-cmp-card__title">指标对比</span></div>
<table class="audit-cmp-table">
<thead>
<tr>
<th>指标</th>
<th class="audit-cmp-table__col-before">初始</th>
<th class="audit-cmp-table__col-arrow"></th>
<th class="audit-cmp-table__col-after">目标</th>
<th class="audit-cmp-table__col-delta">变化</th>
</tr>
</thead>
<tbody id="auditCmpBody"></tbody>
</table>
</div>
<!-- 通过/驳回决策 -->
<div class="audit-decision">
<span class="audit-decision__label">审核决定</span>
<button class="audit-decision__btn audit-decision__btn--approve" id="auditBtnApprove" onclick="selectDecision('approve')"><svg width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M3 8l3.5 3.5L13 5" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg>通过</button>
<button class="audit-decision__btn audit-decision__btn--reject" id="auditBtnReject" onclick="selectDecision('reject')"><svg width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M4 4l8 8M12 4l-8 8" stroke="currentColor" stroke-width="2" stroke-linecap="round"/></svg>驳回</button>
</div>
<div class="audit-reject-section" id="auditRejectSection">
<label class="form-label">驳回原因<span>*</span></label>
<textarea id="auditRejectReason" placeholder="请输入驳回原因,该原因将展示给员工…"></textarea>
</div>
</div>
<div class="audit-dialog__footer">
<button class="btn btn-default" onclick="closeAudit()">取消</button>
<button class="btn btn-primary" id="auditConfirmBtn" onclick="confirmAudit()" disabled>确定</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}
];
function buildMockData(){
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}
];
var rejectReasons = [
'目标体重设置过低,不符合健康减重标准,请重新设定合理目标',
'目标BMI与实际身体状况不符,建议调整至合理区间22-24',
'缺少必要的体检数据支撑,请补充近期体检报告后再提交',
'目标体脂率与目标体重存在矛盾,请核对后重新提交',
'目标腰围降幅过大,建议分阶段设定目标以保证健康安全'
];
var data = [[],[],[],[]];
baseEmployees.forEach(function(e,i){
var status = i % 4;
var p = plans[i % plans.length];
var row = {
planName: p.name, org: e.org, dept: e.dept, name: e.name, empId: e.empId,
gender: e.gender, age: e.age, height: e.height,
weight: e.weight, bmi: e.bmi, waist: e.waist, fat: e.fat, planId: p.id,
targetWeight: Math.round(e.weight * 0.85),
targetBmi: +(e.bmi * 0.85).toFixed(1),
targetWaist: Math.round(e.waist * 0.88),
targetFat: +(e.fat * 0.80).toFixed(1),
submitTime: '2026-0'+((i%9)+1)+'-'+('0'+(10+i%28)).slice(-2)+' '+(8+i%12)+':'+('0'+(i%60)).slice(-2)
};
if(status === 1){
row.auditTime = '2026-0'+((i%9)+1)+'-'+('0'+(12+i%28)).slice(-2)+' '+(9+i%10)+':'+('0'+(30+i%30)).slice(-2);
row.auditor = ['张健康','李管理','王营养'][i%3];
}
if(status === 2){
row.auditTime = '2026-0'+((i%9)+1)+'-'+('0'+(12+i%28)).slice(-2)+' '+(9+i%10)+':'+('0'+(30+i%30)).slice(-2);
row.auditor = ['张健康','李管理','王营养'][i%3];
}
if(status === 3){
row.rejectTime = '2026-0'+((i%9)+1)+'-'+('0'+(12+i%28)).slice(-2)+' '+(9+i%10)+':'+('0'+(30+i%30)).slice(-2);
row.rejectReason = rejectReasons[i % rejectReasons.length];
row.rejectAuditor = ['张健康','李管理','王营养'][i%3];
}
data[status].push(row);
});
return data;
}
var tabData = buildMockData();
var currentTab = 0;
var filteredData = [];
var selectedPlanId = null;
var pendingAuditRow = null;
var auditDecision = '';
/* 计划搜索 */
function searchPlan(){
var keyword = document.getElementById('planSearchInput').value.trim().toLowerCase();
var panel = document.getElementById('planPanel');
var filtered = keyword ? plans.filter(function(p){ return p.name.toLowerCase().indexOf(keyword)>-1 || p.org.toLowerCase().indexOf(keyword)>-1; }) : plans;
if(!filtered.length){ panel.innerHTML = '<div class="search-select__empty">无匹配计划</div>'; return; }
var html = '';
filtered.forEach(function(p){
html += '<div class="search-select__option'+(selectedPlanId===p.id?' selected':'')+'" onclick="selectPlan('+p.id+')"><div style="font-weight:500;">'+esc(p.name)+'</div><div class="ss-org">'+esc(p.org)+' | '+p.dateFrom+' ~ '+p.dateTo+' | 应参加 '+p.totalCount+' 人</div></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('planClearBtn').classList.add('show');
document.getElementById('planSelect').classList.add('search-select--selected');
document.getElementById('planPanel').classList.remove('show');
document.getElementById('planInfoEmpty').style.display='none';
document.getElementById('planInfo').style.display='flex';
document.getElementById('piOrg').textContent=plan.org;
document.getElementById('piDate').textContent=plan.dateFrom+' ~ '+plan.dateTo;
document.getElementById('piDays').textContent=calcPlanDays(plan.dateFrom, plan.dateTo)+' 天';
document.getElementById('piCount').textContent=plan.totalCount+' 人';
document.getElementById('piActual').textContent=(plan.actualCount||0)+' 人';
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');
document.getElementById('planInfoEmpty').style.display='';
document.getElementById('planInfo').style.display='none';
applyFilter();
}
/* Tab */
function switchTab(idx){
currentTab=idx;
document.querySelectorAll('.tab-item').forEach(function(el,i){el.classList.toggle('active',i===idx);});
document.querySelectorAll('.tab-panel').forEach(function(el,i){el.classList.toggle('active',i===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='';
function toggleOrg(){var p=document.getElementById('orgPanel'),t=document.getElementById('orgTrigger');p.classList.toggle('open');t.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]||[],html='<div class="org-col__title">部门</div><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 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();
}
function resetFilter(){
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='';
['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<4;i++){var d=tabData[i];if(selectedPlanId)d=d.filter(function(x){return x.planId===selectedPlanId;});document.getElementById('tabBadge'+i).textContent=d.length;}}
/* 渲染表格 */
function renderTable(){
var tbody=document.getElementById('tableBody'+currentTab);
document.getElementById('pageInfo'+currentTab).textContent='显示 '+filteredData.length+' 条记录';
if(!filteredData.length){tbody.innerHTML='<tr><td colspan="19" class="td-empty">暂无匹配数据</td></tr>';return;}
var html='';
filteredData.forEach(function(d){
html+='<tr>';
html+='<td>'+esc(d.planName)+'</td><td>'+esc(d.name)+'</td><td>'+esc(d.empId)+'</td>';
html+='<td>'+d.gender+'</td><td>'+d.age+'</td><td>'+esc(d.org)+'</td><td>'+esc(d.dept)+'</td>';
html+='<td>'+d.height+'</td><td>'+d.weight+'</td><td>'+d.bmi.toFixed(1)+'</td><td>'+d.waist+'</td><td>'+d.fat.toFixed(1)+'</td>';
html+='<td>'+d.targetWeight+'</td><td>'+d.targetBmi+'</td><td>'+d.targetWaist+'</td><td>'+d.targetFat+'</td>';
html+='<td>'+esc(d.submitTime)+'</td>';
if(currentTab===0) html+='<td class="td-actions"><a class="link" href="javascript:void(0)" onclick="openAudit(\''+esc(d.empId)+'\')">审核</a></td>';
if(currentTab===1){html+='<td>'+esc(d.auditTime)+'</td><td>'+esc(d.auditor)+'</td>';}
if(currentTab===2){html+='<td>'+esc(d.auditTime)+'</td><td>'+esc(d.auditor)+'</td>';}
if(currentTab===3){html+='<td>'+esc(d.rejectTime)+'</td><td>'+esc(d.rejectAuditor)+'</td><td><span class="reject-reason" title="'+escAttr(d.rejectReason)+'">'+esc(d.rejectReason)+'</span></td>';}
html+='</tr>';
});
tbody.innerHTML=html;
}
function calcPlanDays(dF,dT){var t=new Date(),f=new Date(dF),e=new Date(dT),end=e<t?e:t;if(end<f)return'未开始';return Math.ceil((end-f)/(864e5))+1;}
function esc(s){return String(s||'').replace(/&/g,'&amp;').replace(/"/g,'&quot;').replace(/</g,'&lt;').replace(/>/g,'&gt;');}
function escAttr(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);}
/* ===== 审核操作 ===== */
/* 渲染基本信息卡片 */
function renderBasicInfoCard(row){
var items = [
{label:'计划名称',value:row.planName,span:4},
{label:'姓名',value:row.name},
{label:'员工编号',value:row.empId},
{label:'性别',value:row.gender},
{label:'年龄',value:row.age+' 岁'},
{label:'身高',value:row.height+' cm'},
{label:'所属单位',value:row.org},
{label:'所属部门',value:row.dept},
{label:'提交时间',value:row.submitTime}
];
var html='';
items.forEach(function(item){
var s = item.span ? ' style="grid-column:span '+item.span+'"' : '';
html+='<div class="audit-info-card__item"'+s+'><span class="audit-info-card__label">'+item.label+'</span><span class="audit-info-card__value">'+esc(item.value)+'</span></div>';
});
document.getElementById('auditInfoGrid').innerHTML=html;
}
/* 渲染指标对比表 */
function renderCmpTable(row){
var metrics = [
{label:'体重 (kg)', before:row.weight, after:row.targetWeight},
{label:'BMI', before:row.bmi.toFixed(1), after:row.targetBmi},
{label:'腰围 (cm)', before:row.waist, after:row.targetWaist},
{label:'体脂 (%)', before:row.fat.toFixed(1), after:row.targetFat}
];
var html='';
metrics.forEach(function(m){
var delta = (parseFloat(m.after) - parseFloat(m.before)).toFixed(1);
var deltaStr = delta > 0 ? '+' + delta : String(delta);
var deltaCls = delta < 0 ? 'audit-cmp-table__delta--good' : 'audit-cmp-table__delta--neutral';
html+='<tr>';
html+='<td>'+m.label+'</td>';
html+='<td><span class="audit-cmp-table__before">'+m.before+'</span></td>';
html+='<td><span class="audit-cmp-table__arrow" style="display:inline-block;margin:0 6px;color:var(--text-placeholder)">→</span></td>';
html+='<td><span class="audit-cmp-table__after">'+m.after+'</span></td>';
html+='<td><span class="audit-cmp-table__delta '+deltaCls+'">'+deltaStr+'</span></td>';
html+='</tr>';
});
document.getElementById('auditCmpBody').innerHTML=html;
}
function openAudit(empId){
var idx=-1;
for(var i=0;i<tabData[0].length;i++){if(tabData[0][i].empId===empId){idx=i;break;}}
if(idx===-1)return;
pendingAuditRow={data:tabData[0][idx],index:idx};
auditDecision='';
renderBasicInfoCard(tabData[0][idx]);
renderCmpTable(tabData[0][idx]);
document.getElementById('auditBtnApprove').classList.remove('selected');
document.getElementById('auditBtnReject').classList.remove('selected');
document.getElementById('auditRejectSection').classList.remove('show');
document.getElementById('auditRejectReason').value='';
document.getElementById('auditConfirmBtn').disabled=true;
document.getElementById('auditConfirmBtn').className='btn btn-primary';
document.getElementById('auditConfirmBtn').textContent='确定';
document.getElementById('auditOverlay').classList.add('show');
}
function selectDecision(type){
auditDecision=type;
var btnApprove=document.getElementById('auditBtnApprove'), btnReject=document.getElementById('auditBtnReject');
var rejectSection=document.getElementById('auditRejectSection'), confirmBtn=document.getElementById('auditConfirmBtn');
if(type==='approve'){btnApprove.classList.add('selected');btnReject.classList.remove('selected');rejectSection.classList.remove('show');}
else {btnApprove.classList.remove('selected');btnReject.classList.add('selected');rejectSection.classList.add('show');}
confirmBtn.disabled=false;
confirmBtn.className=type==='approve'?'btn btn-success':'btn btn-danger';
confirmBtn.textContent=type==='approve'?'确认通过':'确认驳回';
}
function closeAudit(){document.getElementById('auditOverlay').classList.remove('show');pendingAuditRow=null;auditDecision='';}
function confirmAudit(){
if(!pendingAuditRow||!auditDecision)return;
if(auditDecision==='approve'){
var row=tabData[0].splice(pendingAuditRow.index,1)[0];
var now=new Date(); row.auditTime=now.getFullYear()+'-'+('0'+(now.getMonth()+1)).slice(-2)+'-'+('0'+now.getDate()).slice(-2)+' '+('0'+now.getHours()).slice(-2)+':'+('0'+now.getMinutes()).slice(-2);
row.auditor='张健康'; tabData[1].unshift(row);
closeAudit(); showToast('已通过「'+row.name+'」的目标体重审核'); applyFilter();
} else {
var reason=document.getElementById('auditRejectReason').value.trim();
if(!reason){showToast('请输入驳回原因');return;}
var row=tabData[0].splice(pendingAuditRow.index,1)[0];
var now=new Date(); row.rejectTime=now.getFullYear()+'-'+('0'+(now.getMonth()+1)).slice(-2)+'-'+('0'+now.getDate()).slice(-2)+' '+('0'+now.getHours()).slice(-2)+':'+('0'+now.getMinutes()).slice(-2);
row.rejectReason=reason; row.rejectAuditor='张健康'; tabData[3].unshift(row);
closeAudit(); showToast('已驳回「'+row.name+'」的目标体重申请'); applyFilter();
}
}
document.getElementById('auditOverlay').addEventListener('click',function(e){if(e.target===this)closeAudit();});
document.addEventListener('click',function(e){
if(!e.target.closest('#planSelect'))document.getElementById('planPanel').classList.remove('show');
var ow=document.getElementById('orgWrap'); if(ow&&!ow.contains(e.target)){document.getElementById('orgPanel').classList.remove('open');document.getElementById('orgTrigger').classList.remove('open');}
});
(function init(){
var html='';
plans.forEach(function(p){html+='<div class="search-select__option" onclick="selectPlan('+p.id+')"><div style="font-weight:500;">'+esc(p.name)+'</div><div class="ss-org">'+esc(p.org)+' | '+p.dateFrom+' ~ '+p.dateTo+' | 应参加 '+p.totalCount+' 人</div></div>';});
document.getElementById('planPanel').innerHTML=html; applyFilter();
})();
</script>
</body>
</html>
@@ -54,7 +54,7 @@
<aside class="sidebar">
<div class="sidebar-menu__title">过程管理</div>
<a href="action-record.html" class="sidebar-item">行动记录</a>
<a href="action-overview.html" class="sidebar-item">动总览</a>
<a href="action-overview.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="activity-statistics.html" class="sidebar-item">活动统计</a>