diff --git a/employee-app/weight-management/diet-advice-v2.html b/employee-app/weight-management/diet-advice-v2.html index 8e8c81b..abff4d1 100644 --- a/employee-app/weight-management/diet-advice-v2.html +++ b/employee-app/weight-management/diet-advice-v2.html @@ -17,7 +17,6 @@ body { background: #f0f2f5; display: flex; justify-content: center; align-items: .nav-back { width: 28px; height: 28px; display: flex; align-items: center; justify-content: center; cursor: pointer; color: #1a1a1a; } .nav-title { flex: 1; text-align: center; font-size: 17px; font-weight: 600; color: #1a1a1a; } .nav-placeholder { width: 28px; height: 28px; } - .nav-action { font-size: 13px; color: #36cfc9; font-weight: 600; cursor: pointer; white-space: nowrap; flex-shrink: 0; } /* ===== 周日历(页面顶部) ===== */ .calendar-card { background: #fff; border-radius: 16px; margin: 10px 12px 0; padding: 12px 12px 8px; box-shadow: 0 4px 14px rgba(0,0,0,0.04); position: relative; } @@ -343,7 +342,7 @@ body { background: #f0f2f5; display: flex; justify-content: center; align-items: - 修改偏好 + diff --git a/employee-app/weight-management/doc/PRD.md b/employee-app/weight-management/doc/PRD.md index d036244..6df6c49 100644 --- a/employee-app/weight-management/doc/PRD.md +++ b/employee-app/weight-management/doc/PRD.md @@ -10,7 +10,7 @@ 体重管理(员工端) ├── 体重管理主页(入口) │ ├── 目标管理 → 目标详情 -│ ├── 历史计划 +│ ├── 历史目标 │ ├── 活动详情 │ ├── 基本信息 │ ├── 签订承诺 / 我的承诺 @@ -45,6 +45,8 @@ stateDiagram-v2 每日打卡 --> 饮食记录: 查看饮食 每日打卡 --> 运动记录: 查看运动 每日打卡 --> 体重记录: 查看体重 + 体重管理主页 --> 目标详情: 查看目标卡片 + 体重管理主页 --> 健康科普: 查看科普食谱/推荐视频 体重管理主页 --> 吃动平衡: 查看吃动平衡 体重管理主页 --> 排行榜: 查看排名 体重管理主页 --> 体重报告: 查看报告 @@ -61,7 +63,7 @@ stateDiagram-v2 | 1 | 体重管理主页 | weight-main-v2.html | 页面 | | 2 | 目标管理 | goal-management-v2.html | 页面 | | 3 | 目标详情 | goal-detail-v2.html | 页面 | -| 4 | 历史计划 | goal-history-v2.html | 页面 | +| 4 | 历史目标 | goal-history-v2.html | 页面 | | 5 | 活动详情 | activity-detail.html | 页面 | | 6 | 基本信息 | basic-info.html | 页面 | | 7 | 签订承诺 | promise-signing.html | 页面 | @@ -117,18 +119,18 @@ stateDiagram-v2 **功能说明:** 体重管理模块的核心中枢页面,聚合展示体重管理目标、每日吃/动/体重打卡概览、吃动平衡、排行榜、体重报告与推荐视频。 页面存在六种状态:6 种演示状态:已设置-参加活动·已签署、已设置-参加活动·审核中、已设置-参加活动·已通过待签署、已设置-参加活动·已驳回、已设置-个人目标、未设置目标。 -| UI 区域 | 已签署 | 审核中 | 已通过待签署 | 已驳回 | 个人目标 | 未设置 | -|---------|:--:|:--:|:--:|:--:|:--:|:--:| -| 目标卡片-标尺(人物+波浪球) | ✅ | ❌ | ❌ | ❌ | ✅ | ❌ | -| 目标状态横幅 | ❌ | 🟡 审核中 | 🟢 去签署 | 🔴 重新提交 | ❌ | ❌ | -| 目标空状态 | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ | -| 排名徽章(第N名) | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | -| 排行榜-我的排名行 | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | -| 体重报告-目标相关行 | ✅ | ❌ | ❌ | ❌ | ✅ | ❌ | +| UI 区域 | 已签署 | 审核中 | 已通过待签署 | 已驳回 | 个人目标 | 未设置/未参加 | +|---------|:--:|:--:|:--:|:--:|:--:|:-------:| +| 目标卡片-标尺(人物+波浪球) | ✅ | ❌ | ❌ | ❌ | ✅ | ❌ | +| 目标状态横幅 | ❌ | 🟡 审核中 | 🟢 去签署 | 🔴 重新提交 | ❌ | ❌ | +| 目标空状态 | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ | +| 排名徽章(第N名) | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | +| 排行榜-我的排名行 | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | +| 体重报告-目标相关行 | ✅ | ❌ | ❌ | ❌ | ✅ | ❌ | **主要UI元素:** -- **导航栏:** 标题"体重管理",右侧"历史计划"链接(跳转到历史计划页) +- **导航栏:** 标题"体重管理",右侧"历史目标"链接(跳转到历史目标页) - **体重管理目标卡片:** - 标题"体重管理目标"+ 右侧"当前第N天/共N天"(点击跳转到目标详情/目标管理页) - 活动名称 + 排名徽章(🏆 第N名) @@ -142,26 +144,29 @@ stateDiagram-v2 - **记录体重弹窗(底部弹层):** 记录体重(必填,滑动尺子调整)+ 记录体脂率(开关)+ 记录腰围(开关)+ "保存"按钮,构成同体重记录页的记录体重弹窗(见第 18 节) ![记录体重弹窗](screenshots/weight-main-record.jpg) +- **记录成功弹窗(保存后弹出):** 居中弹窗——今日日期 + "记录成功" + 今日体重(kg,青绿高亮)+ 体脂率/腰围摘要行(对应开关开启时显示)+ "确定"按钮(仅关闭弹窗,留在当前页) + + ![记录成功弹窗](screenshots/weight-main-record-success.jpg) - **排行榜卡片:** "我的排名"行(排名/积分)+ 前三名金银铜牌列表,点击跳转到排行榜页 - **体重报告卡片:** 初始体重 → 当前体重 → 目标体重,统计行(已减体重/距目标/目标进度)+ 进度条 - **推荐视频卡片:** 2列网格展示健康科普视频(缩略图 + 播放次数 + 作者 + 标题 + 机构) **交互说明:** -- 点击"历史计划"跳转到历史计划页(goal-history-v2.html) -- 点击目标卡片天数链接跳转到目标详情页(goal-detail-v2.html),未设置目标时跳转到目标管理页(goal-management-v2.html) +- 点击"历史目标"跳转到历史目标页(goal-history-v2.html) +- 点击目标卡片跳转到目标详情页(goal-detail-v2.html),未设置目标时跳转到目标管理页(goal-management-v2.html) - 点击状态横幅"去签署"跳转到签订承诺页(promise-signing.html);"重新提交"跳转到目标管理页(goal-management-v2.html,携带活动回填参数) - 点击吃/动/体重卡片:已记录时跳转到对应记录页(饮食记录 eat-detail-v2.html / 运动记录 exercise-detail-v2.html / 体重记录 weight-detail-v2.html),未记录时直接跳转到自记打卡页(饮食录入 eat-checkin-v2.html / 运动录入 exercise-checkin-v2.html,体重为打开记录体重弹窗) - 点击吃卡片"+"跳转到饮食录入页(eat-checkin-v2.html);动卡片"+"跳转到运动录入页(exercise-checkin-v2.html);体重卡片"+"打开记录体重弹窗 +- 记录体重弹窗点击"保存"后关闭弹窗并弹出记录成功弹窗(展示本次记录的体重等数据),主页体重卡片同步更新为最新记录 - 点击"今日饮食建议",先判断是否设置饮食偏好,如未设置,跳转到diet-questionnaire.html,设置了则跳转到今日饮食建议页(diet-advice-v2.html);"智能运动计划"跳转到智能运动计划页(exercise-advice-v2.html);"蓝牙称"跳转到蓝牙称页(bluetooth-scale-v2.html) - 点击吃动平衡卡片跳转到吃动平衡页(eat-exercise-detail-v2.html);点击周日历中的日期切换当日吃动统计(不触发跳转) - 点击排行榜卡片跳转到排行榜页(weight-ranking.html);体重报告卡片跳转到体重报告页(weight-report.html) - 点击返回按钮跳转到应用主页(home/index.html) **业务规则:** -- 非"已签署"状态下,排行榜隐藏"我的排名"行、体重报告隐藏目标相关行、标尺隐藏并展示状态横幅 -- 个人目标模式下隐藏排名徽章与"我的排名"行,体重报告完整展示 -- 如员工有参加过活动(签署过承诺书),则后续被纳入参与人员范围的活动自动参加,自动变成已签署状态 - +- 未参加活动时,判断当前单位是否存在活动,已存在,显示排行榜;未存在活动,显示排行榜示意图,无法点击 +- 如员工有参加过活动(签署过承诺书),则后续被纳入参与人员范围的活动自动参加,自动变成已签署状态(已参加) +- --- ### 2. 目标管理(goal-management-v2.html) @@ -188,9 +193,13 @@ stateDiagram-v2 - **活动选择弹窗:** 活动列表(活动名称、起止时间、组织机构)+ 确定按钮 ![活动选择弹窗](screenshots/goal-management-activity.jpg) -- **确认提交弹窗:** 活动信息 / 初始数据 / 目标数据三段式确认,取消 / 确认提交(个人目标模式下活动信息段为空占位"--") +- **确认提交弹窗:** 按目标类型展示信息段 + 初始数据 / 目标数据三段式确认,取消 / 确认提交 + - 活动目标模式:信息段标题为"活动信息",含活动名称 / 起止日期 / 组织机构 - ![确认提交弹窗](screenshots/goal-management-confirm.jpg) + ![确认提交弹窗-活动目标](screenshots/goal-management-confirm.jpg) + - 个人目标模式:信息段标题为"个人目标信息",含目标名称 / 起止日期(回填所填名称与开始~结束日期),不展示组织机构 + + ![确认提交弹窗-个人目标](screenshots/goal-management-confirm-personal.jpg) **交互说明:** - 点击"活动目标/个人目标"切换类型 @@ -198,13 +207,12 @@ stateDiagram-v2 - 点击"查看全部"跳转到基本信息页(basic-info.html) - 点击底部"提交"校验(活动模式需先选活动,个人模式需填写名称与合法日期),通过后打开确认弹窗 - 点击"确认提交"跳转到目标详情页(goal-detail-v2.html) -- 页面支持通过 URL 参数回填(个人目标:name/startDate/endDate;活动目标:actId/actName/actPeriod/actOrg) **业务规则:** - 活动天数由活动起止日期自动计算,不可修改 - 个人目标天数由开始/结束日期自动计算 -- 目标数据各项分别给出推荐范围与换算说明:体重按身高与健康 BMI 标准(18.5~23.9)换算;体脂率按性别健康标准;腰围按身高比例与性别中心性肥胖线取较严值(原型中为静态示例文案) -- 结束日期必须晚于开始日期 +- 目标数据各项分别给出推荐范围与换算说明(推荐范围按原系统公式走,换算说明可暂时等待AI处理) +- 开始日期只能今日及以后,结束日期必须晚于开始日期 --- @@ -212,24 +220,28 @@ stateDiagram-v2 ![页面截图](screenshots/goal-detail-signed.jpg) + ![修改目标弹窗](screenshots/goal-detail-edit.jpg) + + ![修改目标审核中](screenshots/goal-detail-review.jpg) + **功能说明:** 展示单个活动目标或个人目标的完整信息,含审核状态、目标数据、变化趋势、排行榜与体重报告。 -**页面状态:** 导航栏标题旁下拉菜单切换"活动目标 / 个人目标";活动目标模式下通过顶部状态标签切换 5 种状态演示:审核中、已通过待签署、已驳回、已签署、已结束。 +**页面状态:** 导航栏标题"目标详情",标题旁下拉菜单切换"活动目标 / 个人目标";活动目标模式下通过顶部状态标签切换 5 种状态演示:审核中、已通过待签署、已驳回、已签署、已结束。 -| 状态 | 状态横幅 | 目标信息列 | 变化趋势 | 排行榜/报告 | -|------|------|------|:--:|:--:| -| 审核中 | 🟡 目标审核中,请耐心等待(提交时间) | 初始 → 目标 | ❌ | ❌ | -| 已通过待签署 | 🟢 审核已通过,请签署目标承诺书(审核人)+ 签署按钮 | 初始 → 目标 | ❌ | ❌ | -| 已驳回 | 🔴 目标已被驳回(驳回原因 + 重新提交按钮) | 初始 → 目标(体重标红) | ❌ | ❌ | -| 已签署 | 🎉 承诺书已签署,活动进行中(签署时间)+ 承诺书按钮 | 初始 → 当前 → 目标 | ❌ | ❌ | -| 已结束 | 🏁 活动已结束,恭喜完成目标 + 承诺书按钮 | 初始 → 最终 → 目标 | ✅ | ✅ | +| 状态 | 状态横幅 | 目标信息列 | 变化趋势 | 排行榜/报告/摄入消耗 | +|------|------|------|:--:|:-----------:| +| 审核中 | 🟡 目标审核中,请耐心等待(提交时间) | 初始 → 目标 | ❌ | ❌ | +| 已通过待签署 | 🟢 审核已通过,请签署目标承诺书(审核人)+ 签署按钮 | 初始 → 目标 | ❌ | ❌ | +| 已驳回 | 🔴 目标已被驳回(驳回原因 + 重新提交按钮) | 初始 → 目标 | ❌ | ❌ | +| 已签署 | 🎉 承诺书已签署,活动进行中(签署时间)+ 承诺书按钮;目标信息卡片标题右侧"修改目标"按钮 | 初始 → 当前 → 目标 | ❌ | ❌ | +| 已结束 | 🏁 活动已结束 + 承诺书按钮 | 初始 → 最终 → 目标 | ✅ | ✅ | **主要UI元素:** -- **导航栏:** 标题"活动目标详情/个人目标详情" + 标题旁下拉菜单(活动目标/个人目标) +- **导航栏:** 标题"目标详情" + 标题旁下拉菜单(活动目标/个人目标) - **状态横幅:** 按状态显示不同颜色与文案,含提交/审核/签署时间、审核人、驳回原因及操作按钮 - **活动信息卡片:** 活动名称 + "活动详情"链接 + 起止时间 · 组织机构 -- **目标信息卡片:** 三列数据(初始 / 当前·最终 / 目标),含体重、体脂率、腰围 +- **目标信息卡片:** 三列数据(初始 / 当前·最终 / 目标),含体重、体脂率、腰围;已签署状态下卡片标题右侧显示"修改目标"按钮,提交修改后按钮隐藏、卡片底部显示黄色审核提示条("修改目标已提交,正在审核中" + 修改后的目标体重/体脂/腰围数据) - **变化趋势卡片:** 体重变化 / 体脂变化 / 腰围变化三 Tab,各含统计行(平均/最大/最小/变化)+ 折线图(初始参考线、目标参考线、实际趋势) - **排行榜卡片:** 我的排名 + 前三名(跳转排行榜页) - **体重报告卡片:** 截止日期/天数 + 初始→当前→目标体重 + 已减/距目标/目标进度 + 进度条 @@ -241,33 +253,38 @@ stateDiagram-v2 - 点击状态标签切换活动目标状态演示 - 点击"活动详情"跳转到活动详情页(activity-detail.html) - 点击"签署"跳转到签订承诺页(promise-signing.html),"承诺书"跳转到我的承诺页(my-promise.html) -- 点击"重新提交/修改目标"跳转到目标管理页(goal-management-v2.html,携带回填参数) +- 点击"重新提交"跳转到目标管理页(goal-management-v2.html,携带回填参数) +- 已签署状态下点击"修改目标"弹出修改目标弹窗:提示"当前已参加活动,仅限修改一次目标数据",下方为目标体重、目标体脂、目标腰围三个输入项并回填当前目标值;点击"提交"关闭弹窗、隐藏"修改目标"按钮,并在目标信息卡片下方显示"修改目标已提交,正在审核中"提示及修改后的目标数据;点击"取消"直接关闭弹窗 +- 个人目标模式下点击底部"修改目标"跳转到目标管理页(goal-management-v2.html,携带回填参数) - 点击排行榜卡片跳转到排行榜页(weight-ranking.html),体重报告卡片跳转到体重报告页(weight-report.html) **业务规则:** - 活动目标状态流转:审核中 → 已通过待签署 → 已签署 → 已结束;审核驳回后可重新提交 -- 已驳回状态下目标信息中的体重值红色高亮提示 +- 目标值超过推荐范围则红色警示 - 个人目标模式无审核流程,提交后即为"进行中",可修改目标 +- 活动目标已签署状态下修改目标仅限一次,提交后进入审核中状态,审核通过前目标数据不变 --- -### 4. 历史计划(goal-history-v2.html) +### 4. 历史目标(goal-history-v2.html) ![页面截图](screenshots/goal-history.jpg) -**功能说明:** 展示员工参与过的全部活动计划与个人计划历史列表。 +**功能说明:** 展示员工参与过的全部活动目标与个人目标历史列表。 **主要UI元素:** -- Tab 栏:活动计划 / 个人计划 -- 计划卡片:计划名称、状态标签(进行中/已结束/已完成)、起止日期、机构(活动计划)、数据行(初始体重 → 目标体重 → 当前/最终体重)、底部(签署时间 / 剩余天数 / 减重结果)+ "详情"链接 +- Tab 栏:活动目标 / 个人目标 +- 目标卡片:目标名称、状态标签(进行中/已结束/已完成)、起止日期、机构(活动目标)、数据行(初始体重 → 目标体重 → 当前/最终体重)、底部(参加时间 / 剩余天数 / 减重结果)+ "详情"链接 +- 底部"新建目标"按钮:固定于手机壳底部,带渐变背景过渡 **交互说明:** -- 点击 Tab 切换活动计划/个人计划列表 -- 点击计划卡片或"详情"跳转到目标详情页(goal-detail-v2.html,携带类型与状态参数) +- 点击 Tab 切换活动目标/个人目标列表 +- 点击目标卡片或"详情"跳转到目标详情页(goal-detail-v2.html,携带类型与状态参数) +- 点击底部"新建目标"跳转到目标管理页(goal-management-v2.html) **业务规则:** -- 已结束计划展示最终体重与减重结果 -- 个人计划已达标时展示"达成目标 ✅" +- 进行中的活动目标底部展示参加时间,已结束目标展示最终体重与减重结果 +- 个人目标已达标时展示"达成目标 ✅" --- @@ -373,26 +390,32 @@ stateDiagram-v2 **功能说明:** 员工记录每日饮食摄入,按早餐/午餐/晚餐/加餐分类,支持搜索餐品、手动录入克数和拍照识别。 **主要UI元素:** -- 导航栏标题:当前日期 +- 导航栏:标题为当前日期,右上角"拍照识别"按钮(取景框图标 + 文字,跳转拍照识别页) - 餐次选择 + 搜索行:餐次下拉(点击展开下拉浮层选择:早餐/午餐/晚餐/加餐,当前餐次高亮)+ 餐品搜索框 ![餐次下拉浮层](screenshots/eat-checkin-meal.jpg) -- 双列布局:左侧餐品分类(常用/主食/肉蛋奶/蔬菜/水果/饮品/零食)、右侧菜品列表(emoji + 名称 + 千卡/参考份量 + "+"按钮) -- 底部固定栏:购物袋图标(显示已选数量徽章)、"完成打卡"按钮、拍照识别图标按钮(取景框图标,无文字) +- 双列布局:左侧餐品分类("已记录"置顶,下接常用/主食/肉蛋奶/蔬菜/水果/饮品/零食)、右侧菜品列表(emoji + 名称 + 千卡/参考份量 + "+"按钮) +- "已记录"分类列表:汇总展示各餐次已记录餐品(emoji + 名称 + 餐次标签 + 智记/自记标签 + 千卡/克数,自记条目可删除),支持搜索过滤 + + ![已记录分类](screenshots/eat-checkin-recorded.jpg) +- 底部固定栏:购物袋图标(显示当前餐次已选数量徽章)+ 已选统计两行("已选 X 样" / "摄入 XXX 千卡",跟随当前餐次刷新)+ "提交记录"按钮(固定宽度,靠右) - 克数录入弹窗:菜品信息 + 克数(+/- 步进)+ 预估热量 + 确认添加 ![克数录入弹窗](screenshots/eat-checkin-gram.jpg) -- 已选餐品弹窗:四个餐次 Tab(含数量角标)+ 已选列表(智记/自记标签 + 克数 + 热量 + 移除按钮)+ 完成打卡 +- 已选餐品弹窗(仅当前餐次):标题"XX · 已选餐品"(XX 为当前餐次名)+ 汇总行(共 X 样,XXX 千卡)+ 已选列表(智记/自记标签 + 克数 + 热量 + 移除按钮)+ 提交记录 ![已选餐品弹窗](screenshots/eat-checkin-bag.jpg) +- 提交成功弹窗:今日日期 + "记录成功" + "XX摄入 XXX 千卡"(XX 为当前餐次名,数值为该餐次汇总)+ "确定"按钮 + + ![提交成功弹窗](screenshots/eat-checkin-success.jpg) **交互说明:** -- 点击餐次下拉展开选项浮层,选择后切换餐次并收起浮层 -- 点击分类切换菜品列表,支持搜索过滤 +- 点击餐次下拉展开选项浮层,选择后切换餐次(底部栏统计与购物袋徽章同步刷新)并收起浮层 +- 点击分类切换菜品列表,支持搜索过滤;点击"已记录"分类查看各餐次已记录餐品,可删除自记条目 - 点击菜品"+"打开克数录入弹窗 -- 点击购物袋打开已选餐品汇总面板,可切换餐次、移除菜品(智记不可移除) -- 点击"完成打卡"提交当日饮食记录 -- 点击拍照识别图标按钮跳转到拍照识别页(scan-checkin.html) +- 点击购物袋打开当前餐次的已选餐品面板,可移除菜品(智记不可移除),当前餐次删空后自动关闭面板 +- 点击"提交记录"提交记录并弹出提交成功弹窗,点击"确定"返回上一页 +- 点击右上角"拍照识别"跳转到拍照识别页(scan-checkin.html) - 点击返回按钮返回上一页 **业务规则:** @@ -464,20 +487,26 @@ stateDiagram-v2 **主要UI元素:** - 导航栏标题:"添加YYYY/MM/DD运动" - 搜索行:运动搜索框 -- 双列布局:左侧运动分类(常用/有氧运动/力量训练/球类运动/日常活动/柔韧平衡)、右侧运动列表(emoji + 名称 + 千卡/30分钟 + "+"按钮) -- 底部固定栏:购物袋图标(显示已选数量徽章)、"完成记录"按钮 +- 双列布局:左侧运动分类("已记录"置顶,下接常用/有氧运动/力量训练/球类运动/日常活动/柔韧平衡)、右侧运动列表(emoji + 名称 + 千卡/30分钟 + "+"按钮) +- "已记录"分类列表:展示已记录运动(emoji + 名称 + 来源标签(穿戴/器械/微信/自记)+ 千卡/时长,自记条目可删除),支持搜索过滤 + + ![已记录分类](screenshots/exercise-checkin-recorded.jpg) +- 底部固定栏:购物袋图标(显示已选数量徽章)+ 已选统计两行("已选 X 项" / "消耗 XXX 千卡")+ "提交记录"按钮(固定宽度,靠右) - 时长录入弹窗:运动信息 + 时长(+/- 步进)+ 预估消耗 + 确认添加 ![时长录入弹窗](screenshots/exercise-checkin-duration.jpg) -- 已选运动弹窗:已选列表(穿戴/器械/微信/自记标签 + 时长 + 消耗 + 移除按钮)+ 完成记录 +- 已选运动弹窗:标题"已选运动" + 汇总行(共 X 项,XXX 分钟 XXX 千卡)+ 已选列表(穿戴/器械/微信/自记标签 + 时长 + 消耗 + 移除按钮)+ 提交记录 ![已选运动弹窗](screenshots/exercise-checkin-bag.jpg) +- 提交成功弹窗:今日日期 + "记录成功" + "今日运动消耗 XXX 千卡"(全部已选运动汇总)+ "确定"按钮 + + ![提交成功弹窗](screenshots/exercise-checkin-success.jpg) **交互说明:** -- 点击分类切换运动列表,支持搜索过滤 +- 点击分类切换运动列表,支持搜索过滤;点击"已记录"分类查看已记录运动,可删除自记条目 - 点击运动"+"打开时长录入弹窗 - 点击购物袋打开已选运动汇总面板,可移除自记运动 -- 点击"完成记录"提交当日运动记录 +- 点击"提交记录"提交当日运动记录并弹出提交成功弹窗,点击"确定"返回上一页 - 点击返回按钮返回上一页 **业务规则:** @@ -497,7 +526,7 @@ stateDiagram-v2 - 总消耗标尺:半圆进度弧,左端基础消耗、右端活动消耗、中心总消耗(实际/推荐),右上"智能运动计划"按钮 - 运动统计三列:今日步数 / 运动次数 / 运动时长 - 数据来源卡片:四张来源小卡(穿戴·步数 / 器械·千卡 / 微信·步数(右上角"同步"按钮)/ 自记·步数),未记录时显示“尚未记录”,点击自记卡片跳转运动录入页(exercise-checkin-v2.html) -- 变化趋势卡片:时间范围(周/月/季/年/活动期间)+ 三 Tab(步数趋势/消耗趋势/时长趋势)+ 折线图(数据点悬浮提示) +- 变化趋势卡片:时间范围(周/月/季/年/活动期间)+ 三 Tab(步数变化/消耗变化/时长变化)+ 折线图(数据点悬浮提示) - 运动明细列表:按日期分组,每条含运动名、消耗、运动详情、来源徽章 **交互说明:** @@ -521,7 +550,7 @@ stateDiagram-v2 **功能说明:** 为员工提供个性化膳食指导方案,含"食谱建议"与"营养分析"两个 Tab。 **主要UI元素:** -- 导航栏:标题"今日饮食建议",右侧"修改偏好"按钮(跳转到膳食偏好设置页) +- 导航栏:标题"今日饮食建议" - 周历(含月历弹窗):日期用圆环标记有无饮食数据 - Tab 栏:食谱建议 / 营养分析 @@ -549,7 +578,6 @@ stateDiagram-v2 - 点击注意事项标题折叠/展开 - 点击菜品打开餐品详情弹窗,查看推荐理由;点击弹窗内"不喜欢"关闭详情弹窗并打开"不再推荐"弹窗 - 在"不再推荐"弹窗中选填不喜欢的原因(可多选、可跳过),点击"确定"提交并弹出"已记录"提示;点击"取消"或遮罩关闭 -- 点击"修改偏好"跳转到膳食偏好设置页(diet-questionnaire.html) - 点击返回按钮返回来源页 **业务规则:** diff --git a/employee-app/weight-management/doc/screenshots/diet-advice.jpg b/employee-app/weight-management/doc/screenshots/diet-advice.jpg index db77fa4..c9a24b2 100644 Binary files a/employee-app/weight-management/doc/screenshots/diet-advice.jpg and b/employee-app/weight-management/doc/screenshots/diet-advice.jpg differ diff --git a/employee-app/weight-management/doc/screenshots/eat-checkin-bag.jpg b/employee-app/weight-management/doc/screenshots/eat-checkin-bag.jpg index 6b28276..d0e427b 100644 Binary files a/employee-app/weight-management/doc/screenshots/eat-checkin-bag.jpg and b/employee-app/weight-management/doc/screenshots/eat-checkin-bag.jpg differ diff --git a/employee-app/weight-management/doc/screenshots/eat-checkin-recorded.jpg b/employee-app/weight-management/doc/screenshots/eat-checkin-recorded.jpg new file mode 100644 index 0000000..3786cdc Binary files /dev/null and b/employee-app/weight-management/doc/screenshots/eat-checkin-recorded.jpg differ diff --git a/employee-app/weight-management/doc/screenshots/eat-checkin-success.jpg b/employee-app/weight-management/doc/screenshots/eat-checkin-success.jpg new file mode 100644 index 0000000..e6cab48 Binary files /dev/null and b/employee-app/weight-management/doc/screenshots/eat-checkin-success.jpg differ diff --git a/employee-app/weight-management/doc/screenshots/eat-checkin.jpg b/employee-app/weight-management/doc/screenshots/eat-checkin.jpg index 28e989b..5468812 100644 Binary files a/employee-app/weight-management/doc/screenshots/eat-checkin.jpg and b/employee-app/weight-management/doc/screenshots/eat-checkin.jpg differ diff --git a/employee-app/weight-management/doc/screenshots/exercise-checkin-bag.jpg b/employee-app/weight-management/doc/screenshots/exercise-checkin-bag.jpg index b03eae2..f3c9db7 100644 Binary files a/employee-app/weight-management/doc/screenshots/exercise-checkin-bag.jpg and b/employee-app/weight-management/doc/screenshots/exercise-checkin-bag.jpg differ diff --git a/employee-app/weight-management/doc/screenshots/exercise-checkin-recorded.jpg b/employee-app/weight-management/doc/screenshots/exercise-checkin-recorded.jpg new file mode 100644 index 0000000..28fd41b Binary files /dev/null and b/employee-app/weight-management/doc/screenshots/exercise-checkin-recorded.jpg differ diff --git a/employee-app/weight-management/doc/screenshots/exercise-checkin-success.jpg b/employee-app/weight-management/doc/screenshots/exercise-checkin-success.jpg new file mode 100644 index 0000000..a939c64 Binary files /dev/null and b/employee-app/weight-management/doc/screenshots/exercise-checkin-success.jpg differ diff --git a/employee-app/weight-management/doc/screenshots/exercise-checkin.jpg b/employee-app/weight-management/doc/screenshots/exercise-checkin.jpg index bf6f97c..43bda42 100644 Binary files a/employee-app/weight-management/doc/screenshots/exercise-checkin.jpg and b/employee-app/weight-management/doc/screenshots/exercise-checkin.jpg differ diff --git a/employee-app/weight-management/doc/screenshots/exercise-detail.jpg b/employee-app/weight-management/doc/screenshots/exercise-detail.jpg index 32cf8cd..8ab2010 100644 Binary files a/employee-app/weight-management/doc/screenshots/exercise-detail.jpg and b/employee-app/weight-management/doc/screenshots/exercise-detail.jpg differ diff --git a/employee-app/weight-management/doc/screenshots/goal-detail-edit.jpg b/employee-app/weight-management/doc/screenshots/goal-detail-edit.jpg new file mode 100644 index 0000000..9d72e5e Binary files /dev/null and b/employee-app/weight-management/doc/screenshots/goal-detail-edit.jpg differ diff --git a/employee-app/weight-management/doc/screenshots/goal-detail-ended.jpg b/employee-app/weight-management/doc/screenshots/goal-detail-ended.jpg index d63d2cf..25323c2 100644 Binary files a/employee-app/weight-management/doc/screenshots/goal-detail-ended.jpg and b/employee-app/weight-management/doc/screenshots/goal-detail-ended.jpg differ diff --git a/employee-app/weight-management/doc/screenshots/goal-detail-rejected.jpg b/employee-app/weight-management/doc/screenshots/goal-detail-rejected.jpg index 0d98aab..eb25410 100644 Binary files a/employee-app/weight-management/doc/screenshots/goal-detail-rejected.jpg and b/employee-app/weight-management/doc/screenshots/goal-detail-rejected.jpg differ diff --git a/employee-app/weight-management/doc/screenshots/goal-detail-review.jpg b/employee-app/weight-management/doc/screenshots/goal-detail-review.jpg index 4d0ec8e..158aef3 100644 Binary files a/employee-app/weight-management/doc/screenshots/goal-detail-review.jpg and b/employee-app/weight-management/doc/screenshots/goal-detail-review.jpg differ diff --git a/employee-app/weight-management/doc/screenshots/goal-detail-signed.jpg b/employee-app/weight-management/doc/screenshots/goal-detail-signed.jpg index f241984..0a1c343 100644 Binary files a/employee-app/weight-management/doc/screenshots/goal-detail-signed.jpg and b/employee-app/weight-management/doc/screenshots/goal-detail-signed.jpg differ diff --git a/employee-app/weight-management/doc/screenshots/goal-history-personal.jpg b/employee-app/weight-management/doc/screenshots/goal-history-personal.jpg index 3b2692d..dd0def4 100644 Binary files a/employee-app/weight-management/doc/screenshots/goal-history-personal.jpg and b/employee-app/weight-management/doc/screenshots/goal-history-personal.jpg differ diff --git a/employee-app/weight-management/doc/screenshots/goal-history.jpg b/employee-app/weight-management/doc/screenshots/goal-history.jpg index 0e345eb..30d2dfb 100644 Binary files a/employee-app/weight-management/doc/screenshots/goal-history.jpg and b/employee-app/weight-management/doc/screenshots/goal-history.jpg differ diff --git a/employee-app/weight-management/doc/screenshots/goal-management-confirm-personal.jpg b/employee-app/weight-management/doc/screenshots/goal-management-confirm-personal.jpg new file mode 100644 index 0000000..1c39374 Binary files /dev/null and b/employee-app/weight-management/doc/screenshots/goal-management-confirm-personal.jpg differ diff --git a/employee-app/weight-management/doc/screenshots/weight-main-record-success.jpg b/employee-app/weight-management/doc/screenshots/weight-main-record-success.jpg new file mode 100644 index 0000000..7245fe7 Binary files /dev/null and b/employee-app/weight-management/doc/screenshots/weight-main-record-success.jpg differ diff --git a/employee-app/weight-management/doc/screenshots/weight-main.jpg b/employee-app/weight-management/doc/screenshots/weight-main.jpg index 4bed5c8..6cfd05d 100644 Binary files a/employee-app/weight-management/doc/screenshots/weight-main.jpg and b/employee-app/weight-management/doc/screenshots/weight-main.jpg differ diff --git a/employee-app/weight-management/doc/screenshots/weight-report.jpg b/employee-app/weight-management/doc/screenshots/weight-report.jpg index caaccd1..55ff642 100644 Binary files a/employee-app/weight-management/doc/screenshots/weight-report.jpg and b/employee-app/weight-management/doc/screenshots/weight-report.jpg differ diff --git a/employee-app/weight-management/eat-checkin-v2.html b/employee-app/weight-management/eat-checkin-v2.html index f22d055..8b5984a 100644 --- a/employee-app/weight-management/eat-checkin-v2.html +++ b/employee-app/weight-management/eat-checkin-v2.html @@ -17,6 +17,9 @@ body { background: #f0f2f5; display: flex; justify-content: center; align-items: .nav-back { width: 28px; height: 28px; display: flex; align-items: center; justify-content: center; cursor: pointer; color: #1a1a1a; } .nav-title { flex: 1; text-align: center; font-size: 17px; font-weight: 600; color: #1a1a1a; } .nav-placeholder { width: 28px; height: 28px; } +.nav-camera { display: flex; align-items: center; gap: 4px; height: 28px; padding: 0 10px; border-radius: 14px; background: #e8fbfa; color: #36cfc9; font-size: 12px; font-weight: 700; cursor: pointer; flex-shrink: 0; } +.nav-camera svg { width: 14px; height: 14px; } +.nav-camera:active { opacity: 0.8; } /* ===== 餐次选择 + 搜索行 ===== */ .filter-row { background: #fff; padding: 10px 12px; display: flex; align-items: center; gap: 8px; border-bottom: 1px solid #f0f0f0; } @@ -52,7 +55,6 @@ body { background: #f0f2f5; display: flex; justify-content: center; align-items: /* ===== 分类列表 ===== */ .category-list { background: #fff; border-radius: 12px; overflow: hidden; height: 100%; display: flex; flex-direction: column; } -.category-list__title { font-size: 12px; font-weight: 700; color: #999; padding: 10px 10px 6px; letter-spacing: 1px; flex-shrink: 0; } .category-list__items { flex: 1; overflow-y: auto; } .category-list__items::-webkit-scrollbar { display: none; } .category-item { padding: 12px 10px; font-size: 13px; color: #666; text-align: center; cursor: pointer; border-left: 3px solid transparent; transition: all .2s; } @@ -79,6 +81,7 @@ body { background: #f0f2f5; display: flex; justify-content: center; align-items: .dish-item__btn:active { background: #f5f5f5; } .dish-item__btn--minus { color: #ff4d4f; border-color: #ffccc7; } .dish-item__btn--plus { color: #3ec46a; border-color: #b7ebc4; background: #f6fff6; } +.dish-item__btn--remove { color: #ff4d4f; border-color: #ffccc7; background: #fff1f0; } /* ===== 底部固定栏 ===== */ .bottom-bar { height: 68px; background: #fff; border-top: 1px solid #f0f0f0; display: flex; align-items: center; padding: 0 16px; flex-shrink: 0; gap: 12px; } @@ -86,12 +89,14 @@ body { background: #f0f2f5; display: flex; justify-content: center; align-items: .bottom-bar__bag svg { width: 22px; height: 22px; color: #1890ff; } .bottom-bar__bag-badge { position: absolute; top: -4px; right: -4px; min-width: 18px; height: 18px; border-radius: 9px; background: #ff4d4f; color: #fff; font-size: 10px; font-weight: 700; display: none; align-items: center; justify-content: center; padding: 0 4px; line-height: 1; } .bottom-bar__bag-badge.show { display: flex; } -.bottom-bar__submit { flex: 1; height: 40px; border-radius: 20px; border: none; background: linear-gradient(160deg, #6ee16e, #3ec46a); color: #fff; font-size: 15px; font-weight: 700; cursor: pointer; box-shadow: 0 2px 8px rgba(62,196,106,0.3); transition: opacity .2s, transform .15s; } +.bottom-bar__stats { flex: 1; min-width: 0; display: flex; flex-direction: column; justify-content: center; gap: 2px; } +.bottom-bar__stats-item { font-size: 12px; color: #666; line-height: 1.3; white-space: nowrap; } +.bottom-bar__stats-item em { font-style: normal; font-weight: 800; font-size: 14px; } +.bottom-bar__stats-item--count em { color: #36cfc9; } +.bottom-bar__stats-item--kcal em { color: #fa8c16; } +.bottom-bar__submit { width: 116px; flex-shrink: 0; height: 40px; border-radius: 20px; border: none; background: linear-gradient(160deg, #6ee16e, #3ec46a); color: #fff; font-size: 15px; font-weight: 700; cursor: pointer; box-shadow: 0 2px 8px rgba(62,196,106,0.3); transition: opacity .2s, transform .15s; margin-left: auto; } .bottom-bar__submit:active { transform: scale(0.97); } .bottom-bar__submit:disabled { opacity: 0.4; cursor: not-allowed; box-shadow: none; } -.bottom-bar__scan { width: 40px; height: 40px; border-radius: 10px; background: #f7f8fa; display: flex; align-items: center; justify-content: center; cursor: pointer; flex-shrink: 0; } -.bottom-bar__scan svg { width: 22px; height: 22px; color: #666; } -.bottom-bar__scan:active { background: #e8e8e8; } /* ===== 克数录入弹窗 ===== */ .gram-mask { display: none; position: absolute; inset: 0; background: rgba(0,0,0,0.45); z-index: 50; } @@ -127,14 +132,7 @@ body { background: #f0f2f5; display: flex; justify-content: center; align-items: .bag-panel__head { padding: 16px 16px 8px; flex-shrink: 0; } .bag-panel__handle { width: 36px; height: 4px; background: #ddd; border-radius: 2px; margin: 0 auto 12px; } .bag-panel__title { font-size: 15px; font-weight: 700; color: #1a1a1a; text-align: center; margin-bottom: 8px; } -.bag-panel__body { flex: 1; overflow: hidden; display: flex; gap: 8px; padding: 0 16px; } -/* 左侧:餐次标签 */ -.bag-panel__meals { width: 68px; flex-shrink: 0; display: flex; flex-direction: column; gap: 4px; padding-bottom: 4px; } -.bag-meal-tab { padding: 10px 6px; font-size: 13px; color: #666; text-align: center; cursor: pointer; border-radius: 8px; transition: all .2s; position: relative; font-weight: 500; } -.bag-meal-tab.active { color: #36cfc9; font-weight: 700; background: #e8fbfa; } -.bag-meal-tab__count { display: none; position: absolute; top: 2px; right: 2px; min-width: 16px; height: 16px; border-radius: 8px; background: #ff4d4f; color: #fff; font-size: 10px; font-weight: 700; align-items: center; justify-content: center; padding: 0 4px; line-height: 1; } -.bag-meal-tab__count.show { display: flex; } -/* 右侧:已选列表 */ +.bag-panel__body { flex: 1; overflow: hidden; display: flex; padding: 0 16px; } .bag-panel__list-wrap { flex: 1; min-width: 0; display: flex; flex-direction: column; overflow: hidden; } .bag-panel__summary { font-size: 13px; color: #666; padding-bottom: 8px; flex-shrink: 0; } .bag-panel__summary em { font-style: normal; font-weight: 800; color: #fa8c16; } @@ -152,12 +150,27 @@ body { background: #f0f2f5; display: flex; justify-content: center; align-items: .bag-item__src { font-size: 9px; font-weight: 600; padding: 1px 6px; border-radius: 6px; white-space: nowrap; line-height: 1.5; } .bag-item__src--auto { color: #1890ff; background: #e6f7ff; } .bag-item__src--manual { color: #fa8c16; background: #fff7e6; } +.bag-item__src--meal { color: #36cfc9; background: #e8fbfa; } .bag-item__remove { width: 24px; height: 24px; border-radius: 50%; border: none; background: #fff1f0; color: #ff4d4f; cursor: pointer; display: flex; align-items: center; justify-content: center; flex-shrink: 0; font-size: 12px; line-height: 1; } .bag-item__remove:active { background: #ffccc7; } .bag-panel__footer { padding: 12px 16px 24px; flex-shrink: 0; } .bag-panel__submit { width: 100%; height: 46px; border: none; border-radius: 23px; background: linear-gradient(160deg, #6ee16e, #3ec46a); color: #fff; font-size: 16px; font-weight: 700; cursor: pointer; } .bag-panel__submit:active { opacity: 0.85; } +/* ===== 提交成功弹窗 ===== */ +.success-mask { position: absolute; inset: 0; background: rgba(0,0,0,0.45); z-index: 60; opacity: 0; visibility: hidden; transition: opacity .25s ease, visibility .25s ease; } +.success-mask.show { opacity: 1; visibility: visible; } +.success-dialog { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%) scale(0.9); width: 296px; background: #fff; border-radius: 16px; padding: 28px 20px 20px; z-index: 61; text-align: center; transition: transform .25s ease; } +.success-mask.show .success-dialog { transform: translate(-50%, -50%) scale(1); } +.success-dialog__icon { width: 56px; height: 56px; border-radius: 50%; background: linear-gradient(160deg, #6ee16e, #3ec46a); display: flex; align-items: center; justify-content: center; margin: 0 auto; box-shadow: 0 4px 12px rgba(62,196,106,0.35); } +.success-dialog__icon svg { width: 28px; height: 28px; color: #fff; } +.success-dialog__date { font-size: 13px; color: #999; margin-top: 12px; } +.success-dialog__title { font-size: 18px; font-weight: 700; color: #1a1a1a; margin-top: 4px; } +.success-dialog__kcal { font-size: 13px; color: #666; margin-top: 12px; padding: 10px; background: #fff7e6; border-radius: 10px; } +.success-dialog__kcal em { font-style: normal; font-weight: 800; color: #fa8c16; font-size: 18px; } +.success-dialog__btn { width: 100%; height: 44px; border: none; border-radius: 22px; background: linear-gradient(160deg, #6ee16e, #3ec46a); color: #fff; font-size: 16px; font-weight: 700; cursor: pointer; margin-top: 16px; box-shadow: 0 2px 8px rgba(62,196,106,0.3); } +.success-dialog__btn:active { opacity: 0.85; } + /* Toast */ .toast { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%) scale(0.9); background: rgba(0,0,0,0.78); color: #fff; font-size: 14px; padding: 10px 22px; border-radius: 20px; z-index: 100; pointer-events: none; opacity: 0; transition: all .25s ease; white-space: nowrap; } .toast.show { opacity: 1; transform: translate(-50%, -50%) scale(1); } @@ -182,7 +195,10 @@ body { background: #f0f2f5; display: flex; justify-content: center; align-items: - + @@ -216,7 +232,6 @@ body { background: #f0f2f5; display: flex; justify-content: center; align-items:
-
餐品分类
@@ -237,10 +252,11 @@ body { background: #f0f2f5; display: flex; justify-content: center; align-items:
- -
- +
+
已选 0
+
摄入 0 千卡
+
@@ -273,36 +289,33 @@ body { background: #f0f2f5; display: flex; justify-content: center; align-items:
-
已记录餐品
+
已选餐品
- -
-
- 早餐 -
-
- 午餐 -
-
- 晚餐 -
-
- 加餐 -
-
-
+ +
+
+
+ +
+
+
记录成功
+
本餐摄入 0 千卡
+ +
+
+
@@ -416,7 +429,6 @@ var currentCategory = 'common'; var cart = { breakfast: {}, lunch: {}, dinner: {}, snack: {} }; var searchText = ''; var currentDishId = null; -var bagActiveMeal = 'breakfast'; function getMealFromURL() { var m = (location.search || '').match(/meal=(\w+)/); @@ -498,6 +510,7 @@ function loadCart() { function renderCategories() { var container = document.getElementById('categoryList'); var html = ''; + html += '
已记录
'; var keys = ['common', 'staple', 'meat', 'vegetable', 'fruit', 'drink', 'snack']; keys.forEach(function(key) { var cat = foodData[key]; @@ -532,6 +545,13 @@ function findDish(dishId) { function renderDishes() { var container = document.getElementById('dishList'); var empty = document.getElementById('dishEmpty'); + + // "已记录"分类:展示各餐次已记录的餐品 + if (currentCategory === 'recorded') { + renderRecordedDishes(); + return; + } + var cat = foodData[currentCategory]; var dishes = cat.items; @@ -543,6 +563,7 @@ function renderDishes() { if (dishes.length === 0) { container.innerHTML = ''; + empty.textContent = '暂无匹配餐品'; empty.classList.add('show'); return; } @@ -570,6 +591,67 @@ function filterDishes() { renderDishes(); } +/* ===== 已记录分类列表(汇总各餐次已记录餐品) ===== */ +function renderRecordedDishes() { + var container = document.getElementById('dishList'); + var empty = document.getElementById('dishEmpty'); + var mealNames = { breakfast: '早餐', lunch: '午餐', dinner: '晚餐', snack: '加餐' }; + var rows = []; + ['breakfast', 'lunch', 'dinner', 'snack'].forEach(function(meal) { + var mealCart = cart[meal] || {}; + Object.keys(mealCart).forEach(function(id) { + mealCart[id].forEach(function(e, idx) { + rows.push({ meal: meal, id: id, entry: e, idx: idx }); + }); + }); + }); + var kw = searchText.trim(); + if (kw) { + rows = rows.filter(function(r) { + var dish = findDish(r.id); + return dish && dish.name.indexOf(kw) !== -1; + }); + } + if (rows.length === 0) { + container.innerHTML = ''; + empty.textContent = '暂无已记录餐品'; + empty.classList.add('show'); + return; + } + empty.classList.remove('show'); + var html = ''; + rows.forEach(function(r) { + var dish = findDish(r.id); + var isAuto = r.entry.source === 'auto'; + var srcLabel = isAuto ? '智记' : '自记'; + html += '
' + + '
' + + '
' + (dish ? dish.emoji : '🍽') + '
' + + '
' + + '
' + + '
' + (dish ? dish.name : r.id) + + '' + mealNames[r.meal] + '' + + '' + srcLabel + '' + + '
' + + '
' + r.entry.kcal + ' 千卡 / ' + r.entry.grams + 'g
' + + '
' + + (isAuto ? '' : '') + + '
'; + }); + container.innerHTML = html; +} + +function removeRecordedItem(meal, dishId, idx) { + var mealCart = cart[meal]; + if (!mealCart || !mealCart[dishId]) return; + mealCart[dishId].splice(idx, 1); + if (mealCart[dishId].length === 0) delete mealCart[dishId]; + saveCart(); + updateBottomBar(); + renderDishes(); + if (document.getElementById('bagMask').classList.contains('show')) renderBagItems(); +} + /* ===== 克数录入弹窗 ===== */ function openGramPanel(dishId) { currentDishId = dishId; @@ -639,16 +721,21 @@ function removeCartItem(dishId) { } } -/* ===== 更新底部栏(汇总所有餐次) ===== */ +/* ===== 更新底部栏(当前餐次) ===== */ function updateBottomBar() { + var mealCart = cart[currentMeal] || {}; var totalItems = 0; - ['breakfast', 'lunch', 'dinner', 'snack'].forEach(function(meal) { - var mealCart = cart[meal] || {}; - Object.keys(mealCart).forEach(function(id) { - mealCart[id].forEach(function(e) { totalItems++; }); + var totalKcal = 0; + Object.keys(mealCart).forEach(function(id) { + mealCart[id].forEach(function(e) { + totalItems++; + totalKcal += e.kcal; }); }); + document.getElementById('statCount').textContent = totalItems; + document.getElementById('statKcal').textContent = totalKcal; + var badge = document.getElementById('bagBadge'); if (totalItems > 0) { badge.textContent = totalItems; @@ -662,13 +749,10 @@ function updateBottomBar() { submitBtn.disabled = totalItems === 0; } -/* ===== 已选餐品弹窗 ===== */ +/* ===== 已选餐品弹窗(当前餐次) ===== */ function toggleBagPanel() { - var hasAny = false; - ['breakfast', 'lunch', 'dinner', 'snack'].forEach(function(meal) { - if (Object.keys(cart[meal] || {}).length > 0) hasAny = true; - }); - if (!hasAny) { + var mealCart = cart[currentMeal] || {}; + if (Object.keys(mealCart).length === 0) { showToast('请先选择餐品'); return; } @@ -683,9 +767,6 @@ function toggleBagPanel() { function openBagPanel() { var mask = document.getElementById('bagMask'); mask.classList.add('show'); - // 默认选中当前顶部选择的餐次 - bagActiveMeal = currentMeal; - renderBagMealTabs(); renderBagItems(); } @@ -693,35 +774,12 @@ function closeBagPanel() { document.getElementById('bagMask').classList.remove('show'); } -function switchBagMeal(meal) { - bagActiveMeal = meal; - renderBagMealTabs(); - renderBagItems(); -} - -function renderBagMealTabs() { - var tabs = document.querySelectorAll('.bag-meal-tab'); - tabs.forEach(function(tab) { - var meal = tab.dataset.meal; - tab.classList.toggle('active', meal === bagActiveMeal); - var mealCart = cart[meal] || {}; - var count = 0; - Object.keys(mealCart).forEach(function(id) { count += mealCart[id].length; }); - var countEl = document.getElementById('bagCount_' + meal); - if (count > 0) { - countEl.textContent = count; - countEl.classList.add('show'); - } else { - countEl.classList.remove('show'); - countEl.textContent = ''; - } - }); -} - function renderBagItems() { - var mealCart = cart[bagActiveMeal] || {}; + var mealNames = { breakfast: '早餐', lunch: '午餐', dinner: '晚餐', snack: '加餐' }; + var mealCart = cart[currentMeal] || {}; var container = document.getElementById('bagItemList'); var summaryEl = document.getElementById('bagSummary'); + document.getElementById('bagTitle').textContent = (mealNames[currentMeal] || '') + ' · 已选餐品'; var allIds = Object.keys(mealCart); var totalItems = 0; @@ -758,7 +816,7 @@ function renderBagItems() { '' + e.kcal + ' 千卡' + '' + '' + - (isAuto ? '' : '') + + (isAuto ? '' : '') + ''; }); }); @@ -770,17 +828,12 @@ function removeBagItem(meal, dishId, idx) { if (!mealCart || !mealCart[dishId]) return; mealCart[dishId].splice(idx, 1); if (mealCart[dishId].length === 0) delete mealCart[dishId]; + saveCart(); renderDishes(); updateBottomBar(); - saveCart(); - renderBagMealTabs(); renderBagItems(); - // 如果所有餐次都为空则关闭弹窗 - var hasAny = false; - ['breakfast', 'lunch', 'dinner', 'snack'].forEach(function(m) { - if (Object.keys(cart[m] || {}).length > 0) hasAny = true; - }); - if (!hasAny) closeBagPanel(); + // 当前餐次删空后关闭弹窗 + if (Object.keys(cart[meal] || {}).length === 0) closeBagPanel(); } /* ===== 餐次下拉 ===== */ @@ -807,43 +860,51 @@ function selectMeal(mealKey, mealName, e) { }); closeMealDropdown(); renderDishes(); + updateBottomBar(); } document.addEventListener('click', function(e) { if (!e.target.closest('#mealSelector')) closeMealDropdown(); }); -/* ===== 完成打卡(汇总所有餐次) ===== */ +/* ===== 提交记录(汇总所有餐次) ===== */ +function formatToday() { + var now = new Date(); + var y = now.getFullYear(); + var m = ('0' + (now.getMonth() + 1)).slice(-2); + var d = ('0' + now.getDate()).slice(-2); + return y + '/' + m + '/' + d; +} + function submitCheckin() { var mealNames = { breakfast: '早餐', lunch: '午餐', dinner: '晚餐', snack: '加餐' }; - var totalKcal = 0; + var mealCart = cart[currentMeal] || {}; var totalItems = 0; - var mealSummary = []; - ['breakfast', 'lunch', 'dinner', 'snack'].forEach(function(meal) { - var mealCart = cart[meal] || {}; - var mealKcal = 0; - var mealItems = 0; - Object.keys(mealCart).forEach(function(id) { - mealCart[id].forEach(function(e) { - totalKcal += e.kcal; - mealKcal += e.kcal; - mealItems++; - totalItems++; - }); + var mealKcal = 0; + Object.keys(mealCart).forEach(function(id) { + mealCart[id].forEach(function(e) { + totalItems++; + mealKcal += e.kcal; }); - if (mealItems > 0) mealSummary.push(mealNames[meal] + ' ' + mealItems + '样'); }); if (totalItems === 0) { showToast('请先选择餐品'); return; } - showToast('已记录 ' + mealSummary.join('、') + ',共 ' + totalKcal + ' 千卡'); + closeBagPanel(); + document.getElementById('successDate').textContent = formatToday(); + document.getElementById('successMealName').textContent = mealNames[currentMeal] || '本餐'; + document.getElementById('successKcal').textContent = mealKcal; + document.getElementById('successMask').classList.add('show'); // 提交后重置为默认数据,保证下次打开仍有"上次记录" cart = getDefaultCart(); saveCart(); - setTimeout(function() { - history.back(); - }, 1200); + updateBottomBar(); +} + +function closeSuccessDialog() { + document.getElementById('successMask').classList.remove('show'); + history.back(); } /* ===== 拍照识别 ===== */ diff --git a/employee-app/weight-management/exercise-checkin-v2.html b/employee-app/weight-management/exercise-checkin-v2.html index 4d764e0..f8cb2ff 100644 --- a/employee-app/weight-management/exercise-checkin-v2.html +++ b/employee-app/weight-management/exercise-checkin-v2.html @@ -52,7 +52,6 @@ body { background: #f0f2f5; display: flex; justify-content: center; align-items: /* ===== 分类列表 ===== */ .category-list { background: #fff; border-radius: 12px; overflow: hidden; height: 100%; display: flex; flex-direction: column; } -.category-list__title { font-size: 12px; font-weight: 700; color: #999; padding: 10px 10px 6px; letter-spacing: 1px; flex-shrink: 0; } .category-list__items { flex: 1; overflow-y: auto; } .category-list__items::-webkit-scrollbar { display: none; } .category-item { padding: 12px 10px; font-size: 13px; color: #666; text-align: center; cursor: pointer; border-left: 3px solid transparent; transition: all .2s; } @@ -76,6 +75,7 @@ body { background: #f0f2f5; display: flex; justify-content: center; align-items: .exe-item__btn { width: 28px; height: 28px; border-radius: 50%; border: 1.5px solid #e8e8e8; background: #fff; display: flex; align-items: center; justify-content: center; cursor: pointer; font-size: 16px; color: #666; line-height: 1; transition: all .15s; } .exe-item__btn:active { background: #f5f5f5; } .exe-item__btn--plus { color: #52c41a; border-color: #b7ebc4; background: #f6fff6; } +.exe-item__btn--remove { color: #ff4d4f; border-color: #ffccc7; background: #fff1f0; } /* ===== 底部固定栏 ===== */ .bottom-bar { height: 68px; background: #fff; border-top: 1px solid #f0f0f0; display: flex; align-items: center; padding: 0 16px; flex-shrink: 0; gap: 12px; } @@ -83,7 +83,12 @@ body { background: #f0f2f5; display: flex; justify-content: center; align-items: .bottom-bar__bag svg { width: 22px; height: 22px; color: #52c41a; } .bottom-bar__bag-badge { position: absolute; top: -4px; right: -4px; min-width: 18px; height: 18px; border-radius: 9px; background: #ff4d4f; color: #fff; font-size: 10px; font-weight: 700; display: none; align-items: center; justify-content: center; padding: 0 4px; line-height: 1; } .bottom-bar__bag-badge.show { display: flex; } -.bottom-bar__submit { flex: 1; height: 40px; border-radius: 20px; border: none; background: linear-gradient(160deg, #73d13d, #389e0d); color: #fff; font-size: 15px; font-weight: 700; cursor: pointer; box-shadow: 0 2px 8px rgba(82,196,26,0.3); transition: opacity .2s, transform .15s; } +.bottom-bar__stats { flex: 1; min-width: 0; display: flex; flex-direction: column; justify-content: center; gap: 2px; } +.bottom-bar__stats-item { font-size: 12px; color: #666; line-height: 1.3; white-space: nowrap; } +.bottom-bar__stats-item em { font-style: normal; font-weight: 800; font-size: 14px; } +.bottom-bar__stats-item--count em { color: #52c41a; } +.bottom-bar__stats-item--kcal em { color: #fa8c16; } +.bottom-bar__submit { width: 116px; flex-shrink: 0; height: 40px; border-radius: 20px; border: none; background: linear-gradient(160deg, #73d13d, #389e0d); color: #fff; font-size: 15px; font-weight: 700; cursor: pointer; box-shadow: 0 2px 8px rgba(82,196,26,0.3); transition: opacity .2s, transform .15s; margin-left: auto; } .bottom-bar__submit:active { transform: scale(0.97); } .bottom-bar__submit:disabled { opacity: 0.4; cursor: not-allowed; box-shadow: none; } .bottom-bar__scan { width: 40px; height: 40px; border-radius: 10px; background: #f7f8fa; display: flex; align-items: center; justify-content: center; cursor: pointer; flex-shrink: 0; } @@ -155,6 +160,20 @@ body { background: #f0f2f5; display: flex; justify-content: center; align-items: .bag-panel__submit { width: 100%; height: 46px; border: none; border-radius: 23px; background: linear-gradient(160deg, #73d13d, #389e0d); color: #fff; font-size: 16px; font-weight: 700; cursor: pointer; } .bag-panel__submit:active { opacity: 0.85; } +/* ===== 提交成功弹窗 ===== */ +.success-mask { position: absolute; inset: 0; background: rgba(0,0,0,0.45); z-index: 60; opacity: 0; visibility: hidden; transition: opacity .25s ease, visibility .25s ease; } +.success-mask.show { opacity: 1; visibility: visible; } +.success-dialog { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%) scale(0.9); width: 296px; background: #fff; border-radius: 16px; padding: 28px 20px 20px; z-index: 61; text-align: center; transition: transform .25s ease; } +.success-mask.show .success-dialog { transform: translate(-50%, -50%) scale(1); } +.success-dialog__icon { width: 56px; height: 56px; border-radius: 50%; background: linear-gradient(160deg, #73d13d, #389e0d); display: flex; align-items: center; justify-content: center; margin: 0 auto; box-shadow: 0 4px 12px rgba(82,196,26,0.35); } +.success-dialog__icon svg { width: 28px; height: 28px; color: #fff; } +.success-dialog__date { font-size: 13px; color: #999; margin-top: 12px; } +.success-dialog__title { font-size: 18px; font-weight: 700; color: #1a1a1a; margin-top: 4px; } +.success-dialog__kcal { font-size: 13px; color: #666; margin-top: 12px; padding: 10px; background: #fff7e6; border-radius: 10px; } +.success-dialog__kcal em { font-style: normal; font-weight: 800; color: #fa8c16; font-size: 18px; } +.success-dialog__btn { width: 100%; height: 44px; border: none; border-radius: 22px; background: linear-gradient(160deg, #73d13d, #389e0d); color: #fff; font-size: 16px; font-weight: 700; cursor: pointer; margin-top: 16px; box-shadow: 0 2px 8px rgba(82,196,26,0.3); } +.success-dialog__btn:active { opacity: 0.85; } + /* Toast */ .toast { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%) scale(0.9); background: rgba(0,0,0,0.78); color: #fff; font-size: 14px; padding: 10px 22px; border-radius: 20px; z-index: 100; pointer-events: none; opacity: 0; transition: all .25s ease; white-space: nowrap; } .toast.show { opacity: 1; transform: translate(-50%, -50%) scale(1); } @@ -198,7 +217,6 @@ body { background: #f0f2f5; display: flex; justify-content: center; align-items:
-
运动分类
@@ -219,7 +237,11 @@ body { background: #f0f2f5; display: flex; justify-content: center; align-items:
- +
+
已选 0
+
消耗 0 千卡
+
+ @@ -252,7 +274,7 @@ body { background: #f0f2f5; display: flex; justify-content: center; align-items:
-
已记录运动
+
已选运动
@@ -261,11 +283,24 @@ body { background: #f0f2f5; display: flex; justify-content: center; align-items:
+ +
+
+
+ +
+
+
记录成功
+
今日运动消耗 0 千卡
+ +
+
+
@@ -373,12 +408,16 @@ renderCategories(); selectCategory('common'); updateBottomBar(); -function setPageTitle() { +function formatToday() { var now = new Date(); var y = now.getFullYear(); var m = ('0' + (now.getMonth() + 1)).slice(-2); var d = ('0' + now.getDate()).slice(-2); - document.getElementById('pageTitle').textContent = '添加' + y + '/' + m + '/' + d + '运动'; + return y + '/' + m + '/' + d; +} + +function setPageTitle() { + document.getElementById('pageTitle').textContent = '添加' + formatToday() + '运动'; } /* ===== 持久化:localStorage ===== */ @@ -417,6 +456,7 @@ function loadCart() { function renderCategories() { var container = document.getElementById('categoryList'); var html = ''; + html += '
已记录
'; var keys = ['common', 'cardio', 'strength', 'ball', 'daily', 'flexibility']; keys.forEach(function(key) { var cat = exerciseData[key]; @@ -451,6 +491,13 @@ function findExercise(exeId) { function renderExercises() { var container = document.getElementById('exeList'); var empty = document.getElementById('exeEmpty'); + + // "已记录"分类:展示已记录的运动 + if (currentCategory === 'recorded') { + renderRecordedExercises(); + return; + } + var cat = exerciseData[currentCategory]; var exercises = cat.items; @@ -462,6 +509,7 @@ function renderExercises() { if (exercises.length === 0) { container.innerHTML = ''; + empty.textContent = '暂无匹配运动'; empty.classList.add('show'); return; } @@ -489,6 +537,62 @@ function filterExercises() { renderExercises(); } +/* ===== 已记录分类列表 ===== */ +function renderRecordedExercises() { + var container = document.getElementById('exeList'); + var empty = document.getElementById('exeEmpty'); + var srcLabels = { wearable: '穿戴', equip: '器械', wechat: '微信', manual: '自记' }; + var rows = []; + Object.keys(cart).forEach(function(id) { + cart[id].forEach(function(e, idx) { + rows.push({ id: id, entry: e, idx: idx }); + }); + }); + var kw = searchText.trim(); + if (kw) { + rows = rows.filter(function(r) { + var exe = findExercise(r.id); + return exe && exe.name.indexOf(kw) !== -1; + }); + } + if (rows.length === 0) { + container.innerHTML = ''; + empty.textContent = '暂无已记录运动'; + empty.classList.add('show'); + return; + } + empty.classList.remove('show'); + var html = ''; + rows.forEach(function(r) { + var exe = findExercise(r.id); + var src = r.entry.source || 'manual'; + var isManual = src === 'manual'; + html += '
' + + '
' + + '
' + (exe ? exe.emoji : '🏃') + '
' + + '
' + + '
' + + '
' + (exe ? exe.name : r.id) + + '' + (srcLabels[src] || '自记') + '' + + '
' + + '
' + r.entry.kcal + ' 千卡 / ' + r.entry.duration + '分钟
' + + '
' + + (isManual ? '' : '') + + '
'; + }); + container.innerHTML = html; +} + +function removeRecordedItem(exeId, idx) { + if (!cart[exeId]) return; + cart[exeId].splice(idx, 1); + if (cart[exeId].length === 0) delete cart[exeId]; + saveCart(); + renderExercises(); + updateBottomBar(); + if (document.getElementById('bagMask').classList.contains('show')) renderBagItems(); +} + /* ===== 时长录入弹窗 ===== */ function openDurPanel(exeId) { currentExeId = exeId; @@ -561,10 +665,17 @@ function removeCartItem(exeId) { /* ===== 更新底部栏 ===== */ function updateBottomBar() { var totalItems = 0; + var totalKcal = 0; Object.keys(cart).forEach(function(id) { - cart[id].forEach(function(e) { totalItems++; }); + cart[id].forEach(function(e) { + totalItems++; + totalKcal += e.kcal; + }); }); + document.getElementById('statCount').textContent = totalItems; + document.getElementById('statKcal').textContent = totalKcal; + var badge = document.getElementById('bagBadge'); if (totalItems > 0) { badge.textContent = totalItems; @@ -661,15 +772,13 @@ function removeBagItem(exeId, idx) { if (Object.keys(cart).length === 0) closeBagPanel(); } -/* ===== 完成记录 ===== */ +/* ===== 提交记录 ===== */ function submitCheckin() { var totalKcal = 0; var totalItems = 0; - var totalDuration = 0; Object.keys(cart).forEach(function(id) { cart[id].forEach(function(e) { totalKcal += e.kcal; - totalDuration += e.duration; totalItems++; }); }); @@ -677,12 +786,18 @@ function submitCheckin() { showToast('请先选择运动'); return; } - showToast('已记录 ' + totalItems + ' 项运动,共 ' + totalDuration + '分钟 ' + totalKcal + ' 千卡'); + closeBagPanel(); + document.getElementById('successDate').textContent = formatToday(); + document.getElementById('successKcal').textContent = totalKcal; + document.getElementById('successMask').classList.add('show'); cart = getDefaultCart(); saveCart(); - setTimeout(function() { - history.back(); - }, 1200); + updateBottomBar(); +} + +function closeSuccessDialog() { + document.getElementById('successMask').classList.remove('show'); + history.back(); } /* ===== 扫码 ===== */ diff --git a/employee-app/weight-management/exercise-detail-v2.html b/employee-app/weight-management/exercise-detail-v2.html index e1a76ee..659b770 100644 --- a/employee-app/weight-management/exercise-detail-v2.html +++ b/employee-app/weight-management/exercise-detail-v2.html @@ -428,9 +428,9 @@ body { background: #f0f2f5; display: flex; justify-content: center; align-items:
-
步数趋势
-
消耗趋势
-
时长趋势
+
步数变化
+
消耗变化
+
时长变化
diff --git a/employee-app/weight-management/goal-detail-v2.html b/employee-app/weight-management/goal-detail-v2.html index 914cfdc..c1f611c 100644 --- a/employee-app/weight-management/goal-detail-v2.html +++ b/employee-app/weight-management/goal-detail-v2.html @@ -162,6 +162,28 @@ body { background: #f0f2f5; display: flex; justify-content: center; align-items: .report-card__progress-label { display: flex; justify-content: space-between; font-size: 10px; color: #999; margin-top: 4px; } .hidden { display: none !important; } + +/* ===== 修改目标弹窗 ===== */ +.modal-mask { position: absolute; inset: 0; background: rgba(0,0,0,0.45); z-index: 100; display: flex; align-items: center; justify-content: center; padding: 24px; } +.modal { width: 100%; background: #fff; border-radius: 16px; padding: 20px 16px 16px; max-height: 80%; overflow-y: auto; } +.modal__title { font-size: 16px; font-weight: 700; color: #1a1a1a; text-align: center; margin-bottom: 8px; } +.modal__tip { font-size: 12px; color: #faad14; background: #fffbe6; border-radius: 8px; padding: 8px 10px; margin-bottom: 14px; text-align: center; } +.modal__field { margin-bottom: 12px; } +.modal__field label { display: block; font-size: 13px; color: #666; margin-bottom: 6px; } +.modal__field input { width: 100%; height: 40px; border: 1px solid #e0e0e0; border-radius: 10px; padding: 0 12px; font-size: 14px; color: #1a1a1a; outline: none; } +.modal__field input:focus { border-color: #36cfc9; } +.modal__btns { display: flex; gap: 10px; margin-top: 16px; } +.modal__btn { flex: 1; height: 40px; border: none; border-radius: 20px; font-size: 14px; font-weight: 600; cursor: pointer; } +.modal__btn--cancel { background: #f0f0f0; color: #666; } +.modal__btn--primary { background: #36cfc9; color: #fff; } +.modal__data-row { display: flex; justify-content: space-between; align-items: center; padding: 12px 0; border-bottom: 1px solid #f5f5f5; } +.modal__data-row:last-child { border-bottom: none; } +.modal__data-label { font-size: 14px; color: #666; } +.modal__data-val { font-size: 15px; font-weight: 700; color: #1a1a1a; } + +.goal-review-note { margin-top: 10px; padding: 10px 12px; background: #fffbe6; border-radius: 10px; } +.goal-review-note__text { font-size: 12px; color: #faad14; font-weight: 600; margin-bottom: 8px; } +.goal-review-note__data { font-size: 12px; color: #666; line-height: 1.8; } .bottom-safe { height: 16px; flex-shrink: 0; } @@ -334,7 +356,7 @@ body { background: #f0f2f5; display: flex; justify-content: center; align-items: 体重 73.5kg - 65.0kg + 65.0kg
体脂率 @@ -371,7 +393,7 @@ body { background: #f0f2f5; display: flex; justify-content: center; align-items:
-
目标信息
+
目标信息
@@ -406,6 +428,10 @@ body { background: #f0f2f5; display: flex; justify-content: center; align-items: 78cm
+
@@ -415,7 +441,7 @@ body { background: #f0f2f5; display: flex; justify-content: center; align-items: 🏁
-
活动已结束,恭喜完成目标!
+
活动已结束
@@ -854,6 +880,30 @@ body { background: #f0f2f5; display: flex; justify-content: center; align-items:
+ + + diff --git a/employee-app/weight-management/goal-history-v2.html b/employee-app/weight-management/goal-history-v2.html index 5f2769d..0821dfc 100644 --- a/employee-app/weight-management/goal-history-v2.html +++ b/employee-app/weight-management/goal-history-v2.html @@ -3,7 +3,7 @@ -历史计划 - 员工端 | 健康CQ原型 v2 +历史目标 - 员工端 | 健康CQ原型 v2 @@ -81,25 +85,25 @@ body { background: #f0f2f5; display: flex; justify-content: center; align-items: - +
-
活动计划
-
个人计划
+
活动目标
+
个人目标
- +
2026年二季度体重管理活动 进行中 -
+
起止:2026-04-01 ~ 2026-09-30 机构:公司机关 @@ -121,7 +125,7 @@ body { background: #f0f2f5; display: flex; justify-content: center; align-items:
@@ -159,7 +163,7 @@ body { background: #f0f2f5; display: flex; justify-content: center; align-items:
- 全员健康体重管理计划 + 全员健康体重管理目标 已结束
@@ -191,7 +195,7 @@ body { background: #f0f2f5; display: flex; justify-content: center; align-items:
- + - -
- -
- - -
-
李健康
第四采油厂 / 第四采油厂卫生所
-
王体检
第四采油厂 / 第四采油厂卫生所
-
张体检
采油一厂 / 采油一厂医务室
-
赵预防
采油一厂 / 采油一厂医务室
-
陈管理
采油二厂 / 采油二厂医疗点
-
杨体检
采油二厂 / 采油二厂医疗点
-
冯审核
采气一厂 / 采气一厂卫生站
+ +
+ +
+ +
+
医疗点医护人员
+
+ 请进行选择 +
+
+ + +
+
李健康
第四采油厂 / 第四采油厂卫生所
+
王体检
第四采油厂 / 第四采油厂卫生所
+
张体检
采油一厂 / 采油一厂医务室
+
赵预防
采油一厂 / 采油一厂医务室
+
陈管理
采油二厂 / 采油二厂医疗点
+
杨体检
采油二厂 / 采油二厂医疗点
+
冯审核
采气一厂 / 采气一厂卫生站
+
+
+
+ +
+
管理员
+
+ 请进行选择 +
+
+ + +
+
赵管理员
第四采油厂 / 健康管理部
+
钱干事
采油一厂 / 工会办公室
+
孙主任
采油二厂 / 安全环保科
+
周专员
采气一厂 / 生产技术部
+
+
-
@@ -1010,33 +1046,77 @@ function selectLeader(el, name, empId){ el.classList.add('selected'); } -/* ===== 审核人搜索选择 ===== */ -var selectedReviewer = null; +/* ===== 审核人选择(医疗点 / 管理员人员,均可添加多个) ===== */ +var selectedMedicalReviewers = []; +var selectedAdminReviewers = []; -function searchReviewer2(){ - var keyword = document.getElementById('reviewerInput').value.trim().toLowerCase(); - var options = document.querySelectorAll('#reviewerPanel .search-select__option'); +function searchReviewer(type){ + var input = document.getElementById(type+'ReviewerInput'); + var keyword = input.value.trim().toLowerCase(); + var options = document.querySelectorAll('#'+type+'ReviewerPanel .search-select__option'); options.forEach(function(opt){ - // 按姓名搜索 - var nameEl = opt.querySelector('div > div:first-child'); - var nameText = nameEl ? nameEl.textContent.toLowerCase() : ''; - opt.style.display = nameText.indexOf(keyword) > -1 ? '' : 'none'; + var name = opt.getAttribute('data-name') || ''; + opt.style.display = name.toLowerCase().indexOf(keyword) > -1 ? '' : 'none'; }); - showReviewerPanel(); + showReviewerPanel(type); } -function showReviewerPanel(){ +function showReviewerPanel(type){ closeAllPanels(); - document.getElementById('reviewerPanel').classList.add('show'); + updateReviewerOptionStates(type); + document.getElementById(type+'ReviewerPanel').classList.add('show'); } -function selectReviewer2(el, name, site, phone){ - selectedReviewer = {name:name, site:site, phone:phone}; - document.getElementById('reviewerInput').value = name; - document.getElementById('reviewerInfo').value = site + ' | ' + phone; - document.getElementById('reviewerPanel').classList.remove('show'); - document.querySelectorAll('#reviewerPanel .search-select__option').forEach(function(o){o.classList.remove('selected');}); - el.classList.add('selected'); +function addReviewer(el){ + var panel = el.closest('.search-select__panel'); + var type = panel.id === 'medicalReviewerPanel' ? 'medical' : 'admin'; + var name = el.getAttribute('data-name'); + var site = el.getAttribute('data-site'); + var phone = el.getAttribute('data-phone'); + var arr = type==='medical' ? selectedMedicalReviewers : selectedAdminReviewers; + if(!arr.some(function(r){return r.name===name;})){ + arr.push({name:name, site:site, phone:phone}); + } + renderReviewerTags(type); + var input = document.getElementById(type+'ReviewerInput'); + if(input) input.value = ''; + document.getElementById(type+'ReviewerPanel').classList.remove('show'); +} + +function removeReviewer(btn){ + var type = btn.getAttribute('data-type'); + var idx = parseInt(btn.getAttribute('data-idx'), 10); + if(type==='medical'){ selectedMedicalReviewers.splice(idx,1); } + else { selectedAdminReviewers.splice(idx,1); } + renderReviewerTags(type); +} + +function renderReviewerTags(type){ + var arr = type==='medical' ? selectedMedicalReviewers : selectedAdminReviewers; + var listId = type==='medical' ? 'medicalReviewerList' : 'adminReviewerList'; + var list = document.getElementById(listId); + if(arr.length===0){ + list.innerHTML = '请进行选择'; + return; + } + var html = ''; + arr.forEach(function(r, i){ + html += ''+esc(r.name)+'×'; + }); + list.innerHTML = html; +} + +function updateReviewerOptionStates(type){ + var arr = type==='medical' ? selectedMedicalReviewers : selectedAdminReviewers; + var options = document.querySelectorAll('#'+type+'ReviewerPanel .search-select__option'); + options.forEach(function(opt){ + var name = opt.getAttribute('data-name'); + if(arr.some(function(r){return r.name===name;})){ + opt.classList.add('added'); + } else { + opt.classList.remove('added'); + } + }); } /* ===== 文件上传 ===== */ @@ -1086,7 +1166,8 @@ function removeFile(idx){ /* ===== 关闭所有面板 ===== */ function closeAllPanels(){ document.getElementById('leaderPanel').classList.remove('show'); - document.getElementById('reviewerPanel').classList.remove('show'); + document.getElementById('medicalReviewerPanel').classList.remove('show'); + document.getElementById('adminReviewerPanel').classList.remove('show'); document.getElementById('deptPanel').classList.remove('show'); document.getElementById('orgTreePanel').classList.remove('show'); } @@ -1107,6 +1188,7 @@ function savePlan(){ var dept = document.getElementById('planDept').value.trim(); if(!dept){showToast('请选择组织部门');return;} if(!selectedLeader){showToast('请选择负责人');return;} + if(selectedMedicalReviewers.length===0 && selectedAdminReviewers.length===0){showToast('请选择审核人');return;} if(uploadedFiles.length === 0){showToast('请上传通知文件');return;} showToast('保存成功!'); @@ -1123,7 +1205,8 @@ function showToast(msg){ /* 点击外部关闭面板 */ document.addEventListener('click',function(e){ if(!e.target.closest('#leaderSelect')) document.getElementById('leaderPanel').classList.remove('show'); - if(!e.target.closest('#reviewerSelect2')) document.getElementById('reviewerPanel').classList.remove('show'); + if(!e.target.closest('#medicalReviewerSelect')) document.getElementById('medicalReviewerPanel').classList.remove('show'); + if(!e.target.closest('#adminReviewerSelect')) document.getElementById('adminReviewerPanel').classList.remove('show'); if(!e.target.closest('#deptSelect')) document.getElementById('deptPanel').classList.remove('show'); if(!e.target.closest('#orgTreeSelect')) document.getElementById('orgTreePanel').classList.remove('show'); }); @@ -1177,16 +1260,17 @@ document.getElementById('empModal').addEventListener('click',function(e){ selectedLeader = {name:data.leader, empId:leaderOpt.getAttribute('onclick').match(/'(CQ\d+)'/)[1]}; } - // 回显审核人 - document.getElementById('reviewerInput').value = data.reviewer; - var reviewerOpts = document.querySelectorAll('#reviewerPanel .search-select__option'); - reviewerOpts.forEach(function(opt){ - if(opt.textContent.indexOf(data.reviewer) > -1){ - opt.classList.add('selected'); - var m = opt.getAttribute('onclick').match(/selectReviewer2\(this,'([^']+)','([^']+)','([^']+)'\)/); - if(m) selectedReviewer = {name:m[1], site:m[2], phone:m[3]}; - } - }); + // 回显审核人(医疗点) + var medOpt = document.querySelector('#medicalReviewerPanel .search-select__option[data-name="'+data.reviewer+'"]'); + if(medOpt){ + selectedMedicalReviewers.push({ + name: medOpt.getAttribute('data-name'), + site: medOpt.getAttribute('data-site'), + phone: medOpt.getAttribute('data-phone') + }); + } + renderReviewerTags('medical'); + renderReviewerTags('admin'); // 激活部门/员工选择器 updateOrgDependent(); diff --git a/web-admin/weight-management/plan-list.html b/web-admin/weight-management/plan-list.html index a405d0d..c668c8e 100644 --- a/web-admin/weight-management/plan-list.html +++ b/web-admin/weight-management/plan-list.html @@ -163,7 +163,7 @@ tbody tr:hover td.td-actions{background:#F8FBFF;} .emp-card__header{font-size:var(--font-sm);font-weight:600;color:var(--primary);margin-bottom:12px;padding-bottom:8px;border-bottom:1px dashed var(--border);} .emp-card__grid{display:grid;grid-template-columns:1fr 1fr;gap:8px 24px;} .emp-card__item{display:flex;font-size:var(--font-sm);} -.emp-card__item .ec-label{color:var(--text-secondary);width:70px;flex-shrink:0;} +.emp-card__item .ec-label{color:var(--text-secondary);width:92px;flex-shrink:0;} .emp-card__item .ec-value{color:var(--text-primary);} @@ -232,15 +232,6 @@ tbody tr:hover td.td-actions{background:#F8FBFF;}
-
- - -
@@ -639,9 +630,9 @@ tbody tr:hover td.td-actions{background:#F8FBFF;} 序号 单位 姓名 - 所属医疗点 + 类型 + 所属医疗点/部门 联系电话 - 职称 岗位 操作 @@ -718,8 +709,9 @@ tbody tr:hover td.td-actions{background:#F8FBFF;}
员工基本信息
单位-
-
所属医疗点-
姓名-
+
类型-
+
所属医疗点/部门-
联系电话-
岗位-
职称-
@@ -1097,13 +1089,17 @@ renderPersonTable(allPersons); /* 审核人员模拟数据 */ var allReviewers = [ - {org:'第四采油厂',name:'李健康',site:'第四采油厂卫生所',phone:'138-9210-1111',title:'主任医师',post:'医生'}, - {org:'第四采油厂',name:'王体检',site:'第四采油厂卫生所',phone:'138-9210-2222',title:'健康管理师',post:'护士'}, - {org:'采油一厂',name:'张体检',site:'采油一厂医务室',phone:'139-8521-3333',title:'副主任医师',post:'医生'}, - {org:'采油一厂',name:'赵预防',site:'采油一厂医务室',phone:'139-8521-4444',title:'健康管理师',post:'护士'}, - {org:'采油二厂',name:'陈管理',site:'采油二厂医疗点',phone:'137-6523-5555',title:'主治医师',post:'医生'}, - {org:'采油二厂',name:'杨体检',site:'采油二厂医疗点',phone:'137-6523-6666',title:'健康管理师',post:'护士'}, - {org:'采气一厂',name:'冯审核',site:'采气一厂卫生站',phone:'136-8901-7777',title:'执业医师',post:'医生'} + {org:'第四采油厂',name:'李健康',site:'第四采油厂卫生所',phone:'138-9210-1111',title:'主任医师',post:'医生',type:'医疗点医护人员'}, + {org:'第四采油厂',name:'王体检',site:'第四采油厂卫生所',phone:'138-9210-2222',title:'健康管理师',post:'护士',type:'医疗点医护人员'}, + {org:'采油一厂',name:'张体检',site:'采油一厂医务室',phone:'139-8521-3333',title:'副主任医师',post:'医生',type:'医疗点医护人员'}, + {org:'采油一厂',name:'赵预防',site:'采油一厂医务室',phone:'139-8521-4444',title:'健康管理师',post:'护士',type:'医疗点医护人员'}, + {org:'采油二厂',name:'陈管理',site:'采油二厂医疗点',phone:'137-6523-5555',title:'主治医师',post:'医生',type:'医疗点医护人员'}, + {org:'采油二厂',name:'杨体检',site:'采油二厂医疗点',phone:'137-6523-6666',title:'健康管理师',post:'护士',type:'医疗点医护人员'}, + {org:'采气一厂',name:'冯审核',site:'采气一厂卫生站',phone:'136-8901-7777',title:'执业医师',post:'医生',type:'医疗点医护人员'}, + {org:'第四采油厂',name:'赵管理员',site:'健康管理部',phone:'138-9210-8888',title:'—',post:'管理员',type:'管理员'}, + {org:'采油一厂',name:'钱干事',site:'工会办公室',phone:'139-8521-9999',title:'—',post:'管理员',type:'管理员'}, + {org:'采油二厂',name:'孙主任',site:'安全环保科',phone:'137-6523-8888',title:'—',post:'管理员',type:'管理员'}, + {org:'采气一厂',name:'周专员',site:'生产技术部',phone:'136-8901-5555',title:'—',post:'管理员',type:'管理员'} ]; /* 打开审核人员弹窗 */ @@ -1136,9 +1132,9 @@ function renderReviewerTable(data) { html += ''+(i+1)+''; html += '' + esc(r.org) + ''; html += '' + esc(r.name) + ''; + html += '' + esc(r.type) + ''; html += '' + esc(r.site) + ''; html += '' + r.phone + ''; - html += '' + esc(r.title) + ''; html += '' + esc(r.post) + ''; html += '移除'; html += ''; @@ -1290,12 +1286,14 @@ document.addEventListener('click', function(e) { /* ===== 新增审核人员弹窗 ===== */ var candidateReviewers = [ - {org:'第四采油厂',name:'孙健',site:'第四采油厂卫生所',phone:'138-9210-8801',post:'医生',title:'主治医师'}, - {org:'第四采油厂',name:'周芳',site:'第四采油厂卫生所',phone:'138-9210-8802',post:'护士',title:'主管护师'}, - {org:'采油一厂',name:'吴刚',site:'采油一厂医务室',phone:'139-8521-8803',post:'医生',title:'执业医师'}, - {org:'采油一厂',name:'郑洁',site:'采油一厂医务室',phone:'139-8521-8804',post:'护士',title:'护师'}, - {org:'采油二厂',name:'钱辉',site:'采油二厂医疗点',phone:'137-6523-8805',post:'医生',title:'副主任医师'}, - {org:'采气一厂',name:'沈敏',site:'采气一厂卫生站',phone:'136-8901-8806',post:'护士',title:'健康管理师'} + {org:'第四采油厂',name:'孙健',site:'第四采油厂卫生所',phone:'138-9210-8801',post:'医生',title:'主治医师',type:'医疗点医护人员'}, + {org:'第四采油厂',name:'周芳',site:'第四采油厂卫生所',phone:'138-9210-8802',post:'护士',title:'主管护师',type:'医疗点医护人员'}, + {org:'采油一厂',name:'吴刚',site:'采油一厂医务室',phone:'139-8521-8803',post:'医生',title:'执业医师',type:'医疗点医护人员'}, + {org:'采油一厂',name:'郑洁',site:'采油一厂医务室',phone:'139-8521-8804',post:'护士',title:'护师',type:'医疗点医护人员'}, + {org:'采油二厂',name:'钱辉',site:'采油二厂医疗点',phone:'137-6523-8805',post:'医生',title:'副主任医师',type:'医疗点医护人员'}, + {org:'采气一厂',name:'沈敏',site:'采气一厂卫生站',phone:'136-8901-8806',post:'护士',title:'健康管理师',type:'医疗点医护人员'}, + {org:'第四采油厂',name:'吴主任',site:'财务部',phone:'138-9210-8807',post:'管理员',title:'—',type:'管理员'}, + {org:'采油二厂',name:'郑干事',site:'信息中心',phone:'137-6523-8808',post:'管理员',title:'—',type:'管理员'} ]; var selectedReviewer = null; @@ -1335,7 +1333,7 @@ function renderReviewerDropdown(data) { data.forEach(function(p) { html += '
'; html += '' + esc(p.name) + ''; - html += '' + esc(p.org) + ' / ' + esc(p.site) + ''; + html += '' + esc(p.type) + ' · ' + esc(p.org) + ' / ' + esc(p.site) + ''; html += '
'; }); dropdown.innerHTML = html; @@ -1352,6 +1350,7 @@ function selectReviewerCandidate(phone) { document.getElementById('arUnit').textContent = selectedReviewer.org; document.getElementById('arSite').textContent = selectedReviewer.site; document.getElementById('arName').textContent = selectedReviewer.name; + document.getElementById('arType').textContent = selectedReviewer.type; document.getElementById('arPhone').textContent = selectedReviewer.phone; document.getElementById('arPost').textContent = selectedReviewer.post; document.getElementById('arTitle').textContent = selectedReviewer.title; @@ -1368,7 +1367,8 @@ function confirmAddReviewer() { site: selectedReviewer.site, phone: selectedReviewer.phone, title: selectedReviewer.title, - post: selectedReviewer.post + post: selectedReviewer.post, + type: selectedReviewer.type }); candidateReviewers = candidateReviewers.filter(function(p) { return p.phone !== selectedReviewer.phone; }); closeAddReviewerDialog(); diff --git a/web-admin/weight-management/registration-tracking.html b/web-admin/weight-management/registration-tracking.html index 4135bf9..e907f4b 100644 --- a/web-admin/weight-management/registration-tracking.html +++ b/web-admin/weight-management/registration-tracking.html @@ -236,7 +236,7 @@ tbody tr:hover{background:#F8FBFF;} 全部0
- 未提交任务书0 + 未提交目标0
已提交待审核0 diff --git a/web-admin/weight-management/scale-device-add.html b/web-admin/weight-management/scale-device-add.html index 3c3aa77..3a3d7d6 100644 --- a/web-admin/weight-management/scale-device-add.html +++ b/web-admin/weight-management/scale-device-add.html @@ -12,7 +12,7 @@ --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-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;} @@ -68,6 +68,26 @@ .btn{height:36px;padding:0 20px;border-radius:var(--radius-sm);font-size:var(--font-sm);cursor:pointer;border:none;transition:all .2s;display:inline-flex;align-items:center;gap:6px;text-decoration:none;} .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);} +/* 树形选择器(所属单位二级联动) */ +.tree-select{position:relative;width:100%;} +.tree-select__trigger{width:100%;height:36px;border:1px solid var(--border);border-radius:var(--radius-sm);padding:0 32px 0 12px;font-size:var(--font-sm);background:#fff;cursor:pointer;display:flex;align-items:center;user-select:none;transition:border-color .2s;box-sizing:border-box;position:relative;} +.tree-select__trigger:hover{border-color:var(--primary);} +.tree-select__trigger::after{content:'';position:absolute;right:12px;top:50%;transform:translateY(-50%);border:4px solid transparent;border-top:5px solid #999;pointer-events:none;} +.tree-select__text{color:var(--text-placeholder);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;} +.tree-select__text.has-value{color:var(--text-primary);} +.tree-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:320px;overflow-y:auto;} +.tree-select__panel.show{display:block;} +.tree-select__group{border-bottom:1px solid #F5F5F5;} +.tree-select__group:last-child{border-bottom:none;} +.tree-select__group-header{display:flex;align-items:center;gap:6px;padding:9px 16px;font-size:var(--font-sm);font-weight:500;color:var(--text-primary);cursor:pointer;transition:background .1s;user-select:none;} +.tree-select__group-header:hover{background:#F5F7FA;} +.tree-select__group-arrow{width:16px;height:16px;display:flex;align-items:center;justify-content:center;transition:transform .2s;flex-shrink:0;color:var(--text-placeholder);} +.tree-select__group-arrow.expanded{transform:rotate(90deg);} +.tree-select__group-label{flex:1;} +.tree-select__option{padding:8px 16px 8px 38px;font-size:var(--font-sm);cursor:pointer;transition:background .1s;display:none;color:var(--text-secondary);} +.tree-select__option.show{display:block;} +.tree-select__option:hover{background:#F5F7FA;} +.tree-select__option.selected{color:var(--primary);background:var(--primary-light);} @@ -136,7 +156,65 @@
-
+
+ +
+ +
+ 请选择所属单位 +
+
+
+
+ + 第四采油厂 +
+
健康管理部
+
安全环保科
+
工会办公室
+
生产技术部
+
财务部
+
信息中心
+
+
+
+ + 采油一厂 +
+
健康管理部
+
安全环保科
+
工会办公室
+
生产技术部
+
财务部
+
信息中心
+
+
+
+ + 采油二厂 +
+
健康管理部
+
安全环保科
+
工会办公室
+
生产技术部
+
财务部
+
信息中心
+
+
+
+ + 采气一厂 +
+
健康管理部
+
安全环保科
+
工会办公室
+
生产技术部
+
财务部
+
信息中心
+
+
+
+
@@ -160,5 +238,61 @@
+ \ No newline at end of file diff --git a/web-admin/weight-management/scale-monitor.html b/web-admin/weight-management/scale-monitor.html index e7e50e4..11e50be 100644 --- a/web-admin/weight-management/scale-monitor.html +++ b/web-admin/weight-management/scale-monitor.html @@ -139,14 +139,14 @@ - + - - - - - + + + + +
序号设备名称设备编码设备所属单位布放位置本周使用次数本月使用次数本年使用次数累计使用次数操作最近一次使用时间本周使用次数本月使用次数本年使用次数累计使用次数操作
1智能体重秤A01SC-2024-001采油一厂办公楼1层大厅562381,4203,856数据明细
2智能体重秤A02SC-2024-002采油一厂健身房893562,1055,230数据明细
3智能体重秤B01SC-2024-003采油二厂职工活动中心421789802,145数据明细
4智能体重秤B02SC-2024-004采油二厂办公楼2层311458761,920数据明细
5智能体重秤C01SC-2024-005采气厂综合楼1层672891,6804,102数据明细
1智能体重秤A01SC-2024-001采油一厂办公楼1层大厅2026-08-26 09:15562381,4203,856数据明细
2智能体重秤A02SC-2024-002采油一厂健身房2026-08-26 08:42893562,1055,230数据明细
3智能体重秤B01SC-2024-003采油二厂职工活动中心2026-08-25 18:20421789802,145数据明细
4智能体重秤B02SC-2024-004采油二厂办公楼2层2026-08-25 16:05311458761,920数据明细
5智能体重秤C01SC-2024-005采气厂综合楼1层2026-08-24 11:30672891,6804,102数据明细
diff --git a/web-admin/weight-management/sport-device-add.html b/web-admin/weight-management/sport-device-add.html index 127bfb5..8d5eda2 100644 --- a/web-admin/weight-management/sport-device-add.html +++ b/web-admin/weight-management/sport-device-add.html @@ -12,7 +12,7 @@ --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-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;} @@ -68,6 +68,26 @@ .btn{height:36px;padding:0 20px;border-radius:var(--radius-sm);font-size:var(--font-sm);cursor:pointer;border:none;transition:all .2s;display:inline-flex;align-items:center;gap:6px;text-decoration:none;} .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);} +/* 树形选择器(所属单位二级联动) */ +.tree-select{position:relative;width:100%;} +.tree-select__trigger{width:100%;height:36px;border:1px solid var(--border);border-radius:var(--radius-sm);padding:0 32px 0 12px;font-size:var(--font-sm);background:#fff;cursor:pointer;display:flex;align-items:center;user-select:none;transition:border-color .2s;box-sizing:border-box;position:relative;} +.tree-select__trigger:hover{border-color:var(--primary);} +.tree-select__trigger::after{content:'';position:absolute;right:12px;top:50%;transform:translateY(-50%);border:4px solid transparent;border-top:5px solid #999;pointer-events:none;} +.tree-select__text{color:var(--text-placeholder);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;} +.tree-select__text.has-value{color:var(--text-primary);} +.tree-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:320px;overflow-y:auto;} +.tree-select__panel.show{display:block;} +.tree-select__group{border-bottom:1px solid #F5F5F5;} +.tree-select__group:last-child{border-bottom:none;} +.tree-select__group-header{display:flex;align-items:center;gap:6px;padding:9px 16px;font-size:var(--font-sm);font-weight:500;color:var(--text-primary);cursor:pointer;transition:background .1s;user-select:none;} +.tree-select__group-header:hover{background:#F5F7FA;} +.tree-select__group-arrow{width:16px;height:16px;display:flex;align-items:center;justify-content:center;transition:transform .2s;flex-shrink:0;color:var(--text-placeholder);} +.tree-select__group-arrow.expanded{transform:rotate(90deg);} +.tree-select__group-label{flex:1;} +.tree-select__option{padding:8px 16px 8px 38px;font-size:var(--font-sm);cursor:pointer;transition:background .1s;display:none;color:var(--text-secondary);} +.tree-select__option.show{display:block;} +.tree-select__option:hover{background:#F5F7FA;} +.tree-select__option.selected{color:var(--primary);background:var(--primary-light);} @@ -136,7 +156,65 @@
-
+
+ +
+ +
+ 请选择所属单位 +
+
+
+
+ + 第四采油厂 +
+
健康管理部
+
安全环保科
+
工会办公室
+
生产技术部
+
财务部
+
信息中心
+
+
+
+ + 采油一厂 +
+
健康管理部
+
安全环保科
+
工会办公室
+
生产技术部
+
财务部
+
信息中心
+
+
+
+ + 采油二厂 +
+
健康管理部
+
安全环保科
+
工会办公室
+
生产技术部
+
财务部
+
信息中心
+
+
+
+ + 采气一厂 +
+
健康管理部
+
安全环保科
+
工会办公室
+
生产技术部
+
财务部
+
信息中心
+
+
+
+
@@ -161,5 +239,61 @@
+ \ No newline at end of file diff --git a/web-admin/weight-management/sport-monitor.html b/web-admin/weight-management/sport-monitor.html index 39b56f5..782fbf7 100644 --- a/web-admin/weight-management/sport-monitor.html +++ b/web-admin/weight-management/sport-monitor.html @@ -139,14 +139,14 @@ - + - - - - - + + + + +
序号设备名称设备编码设备所属单位布放位置本周使用次数本月使用次数本年使用次数累计使用次数操作最近一次使用时间本周使用次数本月使用次数本年使用次数累计使用次数操作
1智能跑步机A01SP-2024-001采油一厂健身房1204852,8606,320数据明细
2智能跑步机A02SP-2024-002采油一厂职工活动中心984122,3505,180数据明细
3智能椭圆机B01SP-2024-003采油二厂健身房652781,5603,420数据明细
4智能动感单车B02SP-2024-004采油二厂职工活动中心783201,8904,150数据明细
5智能划船机C01SP-2024-005采气厂综合楼健身房451981,1202,560数据明细
1智能跑步机A01SP-2024-001采油一厂健身房2026-08-26 09:151204852,8606,320数据明细
2智能跑步机A02SP-2024-002采油一厂职工活动中心2026-08-26 08:42984122,3505,180数据明细
3智能椭圆机B01SP-2024-003采油二厂健身房2026-08-25 18:20652781,5603,420数据明细
4智能动感单车B02SP-2024-004采油二厂职工活动中心2026-08-25 16:05783201,8904,150数据明细
5智能划船机C01SP-2024-005采气厂综合楼健身房2026-08-24 11:30451981,1202,560数据明细
diff --git a/web-admin/weight-management/weight-ranking.html b/web-admin/weight-management/weight-ranking.html index d9c76d1..14d6953 100644 --- a/web-admin/weight-management/weight-ranking.html +++ b/web-admin/weight-management/weight-ranking.html @@ -407,6 +407,13 @@ tbody tr:hover{background:#F8FBFF;}
+
+ +
+ +
+
+
@@ -725,6 +732,7 @@ function selectPlan(planId){ var plan = plans.find(function(p){return p.id === planId;}); if(!plan) return; document.getElementById('planSearchInput').value = plan.name; + document.getElementById('unitPlanSearchInput').value = plan.name; document.getElementById('planPanel').classList.remove('show'); if(mainTab === 'person'){ applyPersonFilter(); } else { applyUnitFilter(); } @@ -734,6 +742,46 @@ function clearPlan(){ // 活动筛选为必选,不允许清空 } +/* ===== 单位排名 - 活动搜索选择 ===== */ +function showUnitPlanPanel(){ + searchUnitPlan(); + document.getElementById('unitPlanPanel').classList.add('show'); +} + +function searchUnitPlan(){ + var keyword = document.getElementById('unitPlanSearchInput').value.trim().toLowerCase(); + var panel = document.getElementById('unitPlanPanel'); + 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 = '
无匹配活动
'; + } else { + var html = ''; + filtered.forEach(function(p){ + var sel = selectedPlanId === p.id ? ' selected' : ''; + html += '
'; + html += '
'+esc(p.name)+'
'; + html += '
'+esc(p.org)+' | '+p.dateFrom+' ~ '+p.dateTo+'
'; + html += '
'; + }); + panel.innerHTML = html; + } +} + +function selectUnitPlan(planId){ + selectedPlanId = planId; + var plan = plans.find(function(p){return p.id === planId;}); + if(!plan) return; + document.getElementById('unitPlanSearchInput').value = plan.name; + document.getElementById('planSearchInput').value = plan.name; + document.getElementById('unitPlanPanel').classList.remove('show'); + applyUnitFilter(); +} + /* ===== 单位部门双列面板 ===== */ var deptMap = { '第四采油厂':['健康管理部','安全环保科','工会办公室','生产技术部','财务部','信息中心'], @@ -1153,6 +1201,9 @@ document.addEventListener('click',function(e){ if(!e.target.closest('#planSelect')){ document.getElementById('planPanel').classList.remove('show'); } + if(!e.target.closest('#unitPlanSelect')){ + document.getElementById('unitPlanPanel').classList.remove('show'); + } var orgWrap = document.getElementById('orgWrap'); if(orgWrap && !orgWrap.contains(e.target)){ document.getElementById('orgPanel').classList.remove('open'); @@ -1176,6 +1227,14 @@ document.addEventListener('click',function(e){ html += ''; }); document.getElementById('planPanel').innerHTML = html; + var unitHtml = ''; + plans.forEach(function(p){ + unitHtml += '
'; + unitHtml += '
'+esc(p.name)+'
'; + unitHtml += '
'+esc(p.org)+' | '+p.dateFrom+' ~ '+p.dateTo+'
'; + unitHtml += '
'; + }); + document.getElementById('unitPlanPanel').innerHTML = unitHtml; selectPlan(1); renderPersonTable(); renderUnitTable();