From 772879cd8b6083452fb90f756ef5b74d17b43acd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=86=AF=E6=99=AE?= <18691763612@163.com> Date: Thu, 14 May 2026 14:04:04 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E8=90=A5=E5=85=BB=E7=AE=A1=E7=90=86?= =?UTF-8?q?=E5=BC=82=E5=B8=B8=E4=BA=8B=E4=BB=B6=E9=A1=B5=E9=9D=A2=E9=87=8D?= =?UTF-8?q?=E6=9E=84=E5=8F=8A=E5=A4=9A=E9=A1=B5=E9=9D=A2=E4=BA=A4=E4=BA=92?= =?UTF-8?q?=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 重构系统脏数据页面(ano-dirty):去掉统计卡片,筛选项改为业务模块/异常类型/年份,表格列重新设计 - 重构结果异常页面(ano-result):去掉统计卡片,筛选项改为年份/异常类型/时间范围,操作列仅保留详情 - 营养用餐模块多页面交互优化(数据、模型、终端、订单等) - 删除 din-user-mgmt-dialog.html,用户管理弹窗合并至主页面 - 同步更新 index.html SITE_MAP(移除已删除条目,新增 arc-employee-detail) Co-Authored-By: Claude Opus 4.6 --- index.html | 4 +- web-admin/nutrition/ano-dirty.html | 277 ++++--- web-admin/nutrition/ano-result.html | 226 ++++-- web-admin/nutrition/arc-employee-detail.html | 1 - web-admin/nutrition/din-algo-population.html | 4 - web-admin/nutrition/din-algo-vip.html | 17 +- web-admin/nutrition/din-data-benefit.html | 240 +++++- web-admin/nutrition/din-data-consume.html | 141 +++- web-admin/nutrition/din-data-nutri.html | 695 +++++++++++++++++- web-admin/nutrition/din-innovation.html | 32 +- web-admin/nutrition/din-model-llm.html | 224 +++--- web-admin/nutrition/din-model-small.html | 291 +++++--- web-admin/nutrition/din-order-line.html | 161 +++- web-admin/nutrition/din-order-meal.html | 100 ++- web-admin/nutrition/din-order-pickup.html | 1 - web-admin/nutrition/din-recipe-mgmt.html | 48 +- web-admin/nutrition/din-terminal.html | 179 ++++- web-admin/nutrition/din-user-mgmt-dialog.html | 172 ----- web-admin/nutrition/din-user-mgmt.html | 198 ++++- 19 files changed, 2322 insertions(+), 689 deletions(-) delete mode 100644 web-admin/nutrition/din-user-mgmt-dialog.html diff --git a/index.html b/index.html index bfda823..13c7ec9 100644 --- a/index.html +++ b/index.html @@ -230,6 +230,7 @@ const SITE_MAP = [ { file:'trace-query.html', label:'溯源查询' }, { file:'trace-timeline.html', label:'链路可视化' }, { file:'arc-employee.html', label:'员工营养数据' }, + { file:'arc-employee-detail.html', label:'员工营养详情' }, { file:'arc-unit.html', label:'单位报表数据' }, { file:'arc-algo.html', label:'算法模型' }, { file:'farm-land.html', label:'土地环境' }, @@ -247,11 +248,9 @@ const SITE_MAP = [ { file:'sup-clean-internal.html', label:'净菜内供' }, { file:'sup-clean-external.html', label:'净菜外售' }, { file:'din-user-mgmt.html', label:'用户管理' }, - { file:'din-user-mgmt-dialog.html', label:'用户管理弹窗', dialog:true }, { file:'din-dish-all.html', label:'菜品总库' }, { file:'din-dish-all-dialog.html', label:'菜品总库弹窗', dialog:true }, { file:'din-dish-add.html', label:'新增菜品' }, - { file:'din-dish-composition.html', label:'菜品成分' }, { file:'din-ingredient.html', label:'食材管理' }, { file:'din-ingredient-dialog.html', label:'食材管理弹窗', dialog:true }, { file:'din-ingredient-detail.html', label:'食材详情' }, @@ -271,7 +270,6 @@ const SITE_MAP = [ { file:'din-data-consume.html', label:'消费数据' }, { file:'din-data-benefit.html', label:'效益数据' }, { file:'prod-recipe-plan.html', label:'食谱排期' }, - { file:'prod-recipe-plan-dialog.html', label:'食谱排期弹窗', dialog:true }, { file:'prod-clean-order.html', label:'净菜下单' }, { file:'prod-proc-combo.html', label:'配菜组合' }, { file:'prod-proc-cook.html', label:'烹饪加工' }, diff --git a/web-admin/nutrition/ano-dirty.html b/web-admin/nutrition/ano-dirty.html index f9a1feb..2e158f9 100644 --- a/web-admin/nutrition/ano-dirty.html +++ b/web-admin/nutrition/ano-dirty.html @@ -35,20 +35,27 @@ body{font-family:-apple-system,BlinkMacSystemFont,'PingFang SC','Microsoft YaHei .sidebar-item.active{color:#fff;background:var(--primary);} .mi{display:inline-block;width:20px;text-align:center;filter:grayscale(1);opacity:0.65;margin-right:2px;} .sidebar-item.active .mi{opacity:0.9;} -.action-bar{display:flex;align-items:center;gap:8px;margin-bottom:16px;} .main{margin-left:240px;margin-top:56px;padding:24px;min-height:calc(100vh - 56px);} + +/* 筛选栏 */ .filter-bar{background:#fff;border-radius:var(--radius-md);padding:20px 24px;margin-bottom:16px;box-shadow:var(--shadow-sm);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-sm);color:var(--text-secondary);white-space:nowrap;} .filter-select{height:36px;border:1px solid var(--border);border-radius:var(--radius-sm);padding:0 28px 0 12px;font-size:var(--font-sm);color:var(--text-primary);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 10px center;appearance:none;cursor:pointer;min-width:120px;} + +/* 按钮 */ .btn{height:36px;padding:0 16px;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;} .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);} + +/* 操作栏 */ +.action-bar{display:flex;align-items:center;gap:8px;margin-bottom:16px;} +.action-bar__right{margin-left:auto;font-size:var(--font-sm);color:var(--text-secondary);} +.action-bar__right strong{color:var(--primary);font-weight:600;} + +/* 表格卡片 */ .table-card{background:#fff;border-radius: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__actions{display:flex;gap:8px;align-items:center;} .table-card__content{overflow-x:auto;overflow-y:hidden;-webkit-overflow-scrolling:touch;} .table-card__content table{min-width:100%;white-space:nowrap;} table{width:100%;border-collapse:collapse;} @@ -56,33 +63,26 @@ thead th{background:#FAFAFA;padding:12px 16px;text-align:left;font-size:var(--fo tbody td{padding:14px 16px;font-size:var(--font-sm);color:var(--text-primary);border-bottom:1px solid var(--border);white-space:nowrap;} tbody tr:last-child td{border-bottom:none;} tbody tr:hover{background:#F8FBFF;} + +/* 标签 */ .tag{display:inline-flex;align-items:center;padding:2px 8px;border-radius:10px;font-size:var(--font-xs);} +.tag-red{background:#FFF1F0;color:var(--danger);} +.tag-orange{background:#FFF7E6;color:var(--warning);} .tag-blue{background:var(--primary-light);color:var(--primary);} .tag-green{background:#F6FFED;color:var(--success);} -.tag-orange{background:#FFF7E6;color:var(--warning);} -.tag-red{background:#FFF1F0;color:var(--danger);} .tag-gray{background:#F5F5F5;color:#999;} -.link{color:var(--primary);cursor:pointer;font-size:var(--font-sm);}.link:hover{color:#40a9ff;} -.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);} + +/* 分页 */ +.pagination{display:flex;align-items:center;justify-content:space-between;padding:16px 24px;border-top:1px solid var(--border);} +.pagination__left{display:flex;align-items:center;gap:8px;font-size:var(--font-sm);color:var(--text-secondary);} +.pagination__left .filter-select{min-width:80px;height:32px;} +.pagination__right{display:flex;align-items:center;gap:6px;} .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);} +.page-ellipsis{width:32px;height:32px;display:inline-flex;align-items:center;justify-content:center;font-size:var(--font-sm);color:var(--text-secondary);} -/* 统计卡片 */ -.stats-row{display:grid;grid-template-columns:repeat(3,1fr);gap:16px;margin-bottom:16px;} -.stat-card{background:#fff;border-radius:var(--radius-md);padding:20px 24px;box-shadow:var(--shadow-sm);display:flex;align-items:center;gap:16px;} -.stat-card__icon{width:48px;height:48px;border-radius:var(--radius-md);display:flex;align-items:center;justify-content:center;font-size:24px;} -.stat-card__icon.blue{background:var(--primary-light);} -.stat-card__icon.green{background:#F6FFED;} -.stat-card__icon.orange{background:#FFF7E6;} -.stat-card__icon.red{background:#FFF1F0;} -.stat-card__info{display:flex;flex-direction:column;gap:4px;} -.stat-card__value{font-size:var(--font-xl);font-weight:700;color:var(--text-primary);} -.stat-card__label{font-size:var(--font-sm);color:var(--text-secondary);} -/* 操作列固定右侧 */ -thead th:last-child,tbody td.td-actions{position:sticky;right:0;background:#fff;box-shadow:-4px 0 8px rgba(0,0,0,0.04);z-index:2;white-space:nowrap;} -thead th:last-child{background:#FAFAFA;} -tbody tr:hover td.td-actions{background:#F8FBFF;} +/* 异常值高亮 */ +.val-error{color:var(--danger);font-weight:500;} @@ -119,129 +119,204 @@ tbody tr:hover td.td-actions{background:#F8FBFF;}
- -
-
-
🗑️
-
-
28
-
今日脏数据
-
-
-
-
-
-
20
-
已修正
-
-
-
-
-
-
8
-
待处理
-
-
-
-
- +
- +
- - + + +
- +
+
156 条脏数据
+ +
-
-
系统脏数据
-
- - - - - - - - + + + + + + + + + - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - + + + + + + + + - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
记录ID来源模块数据类型问题描述影响范围发现时间处理状态操作业务模块异常类型异常描述异常检测时间表名字段名编号异常值数据产生时间
DIRTY-001营养用餐格式错误员工EMP0234营养摄入值为负数1条记录2026-04-15 08:30待处理查看 修正食谱管理数据缺失热量值字段为空,无法参与营养计算2026-05-14 09:23t_recipe_nutritioncalorieRCP-20260514-0087NULL2026-05-14 08:10
订餐管理格式错误订餐日期格式非法,无法解析2026-05-14 09:15t_order_mealorder_dateORD-20260514-03422026/13/452026-05-14 07:55
用户档案逻辑矛盾员工年龄为负数,BMI值超出合理范围2026-05-14 08:50t_employee_healthage / bmiEMP-00156age=-5, bmi=9992026-05-13 18:30
营养分析重复数据同一用户同日存在3条重复营养分析记录2026-05-13 17:30t_nutri_analysisuser_idNA-20260513-02183条重复2026-05-13 12:00
食材库存范围越界库存数量为负值,疑似出库数据异常2026-05-13 16:45t_material_stockstock_qtyMAT-00523-500 kg2026-05-13 15:20
健康生产格式错误生产批次号含非法字符,无法关联溯源2026-05-13 15:10t_prod_batchbatch_noPRD-20260513-0091B@TCH#001!2026-05-13 14:00
DIRTY-002 卫生供应缺失值采购单食材重量字段为空1条记录2026-04-14 16:20已修正查看 修正数据缺失供应商资质证书编号为空2026-05-13 14:20t_supplier_certcert_noSUP-00078NULL2026-05-13 10:30
DIRTY-003人员健康重复数据员工EMP0156今日就餐记录重复录入2条记录2026-04-15 12:05已忽略查看 修正订餐管理范围越界单次订餐份数超出系统上限2026-05-13 11:05t_order_mealquantityORD-20260513-0198999992026-05-13 10:45
食谱管理关联缺失食谱引用的食材ID在食材库中不存在2026-05-12 17:30t_recipe_itemmaterial_idRCP-20260512-0045MAT-999992026-05-12 16:00
用户档案重复数据员工健康档案存在重复建档记录2026-05-12 15:40t_employee_healthemp_idEMP-002342条重复2026-05-12 09:15
diff --git a/web-admin/nutrition/ano-result.html b/web-admin/nutrition/ano-result.html index bf1bdf3..f3e2174 100644 --- a/web-admin/nutrition/ano-result.html +++ b/web-admin/nutrition/ano-result.html @@ -35,20 +35,30 @@ body{font-family:-apple-system,BlinkMacSystemFont,'PingFang SC','Microsoft YaHei .sidebar-item.active{color:#fff;background:var(--primary);} .mi{display:inline-block;width:20px;text-align:center;filter:grayscale(1);opacity:0.65;margin-right:2px;} .sidebar-item.active .mi{opacity:0.9;} -.action-bar{display:flex;align-items:center;gap:8px;margin-bottom:16px;} .main{margin-left:240px;margin-top:56px;padding:24px;min-height:calc(100vh - 56px);} + +/* 筛选栏 */ .filter-bar{background:#fff;border-radius:var(--radius-md);padding:20px 24px;margin-bottom:16px;box-shadow:var(--shadow-sm);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-sm);color:var(--text-secondary);white-space:nowrap;} .filter-select{height:36px;border:1px solid var(--border);border-radius:var(--radius-sm);padding:0 28px 0 12px;font-size:var(--font-sm);color:var(--text-primary);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 10px center;appearance:none;cursor:pointer;min-width:120px;} +.filter-input{height:36px;border:1px solid var(--border);border-radius:var(--radius-sm);padding:0 12px;font-size:var(--font-sm);color:var(--text-primary);outline:none;background:#fff;min-width:140px;} +.filter-input:focus{border-color:var(--primary);} +.filter-range-sep{font-size:var(--font-sm);color:var(--text-placeholder);} + +/* 按钮 */ .btn{height:36px;padding:0 16px;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;} .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);} + +/* 操作栏 */ +.action-bar{display:flex;align-items:center;gap:8px;margin-bottom:16px;} +.action-bar__right{margin-left:auto;font-size:var(--font-sm);color:var(--text-secondary);} +.action-bar__right strong{color:var(--primary);font-weight:600;} + +/* 表格卡片 */ .table-card{background:#fff;border-radius: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__actions{display:flex;gap:8px;align-items:center;} .table-card__content{overflow-x:auto;overflow-y:hidden;-webkit-overflow-scrolling:touch;} .table-card__content table{min-width:100%;white-space:nowrap;} table{width:100%;border-collapse:collapse;} @@ -56,33 +66,31 @@ thead th{background:#FAFAFA;padding:12px 16px;text-align:left;font-size:var(--fo tbody td{padding:14px 16px;font-size:var(--font-sm);color:var(--text-primary);border-bottom:1px solid var(--border);white-space:nowrap;} tbody tr:last-child td{border-bottom:none;} tbody tr:hover{background:#F8FBFF;} + +/* 标签 */ .tag{display:inline-flex;align-items:center;padding:2px 8px;border-radius:10px;font-size:var(--font-xs);} +.tag-red{background:#FFF1F0;color:var(--danger);} +.tag-orange{background:#FFF7E6;color:var(--warning);} .tag-blue{background:var(--primary-light);color:var(--primary);} .tag-green{background:#F6FFED;color:var(--success);} -.tag-orange{background:#FFF7E6;color:var(--warning);} -.tag-red{background:#FFF1F0;color:var(--danger);} .tag-gray{background:#F5F5F5;color:#999;} -.link{color:var(--primary);cursor:pointer;font-size:var(--font-sm);}.link:hover{color:#40a9ff;} -.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);} -/* 统计卡片 */ -.stats-row{display:grid;grid-template-columns:repeat(2,1fr);gap:16px;margin-bottom:16px;} -.stat-card{background:#fff;border-radius:var(--radius-md);padding:20px 24px;box-shadow:var(--shadow-sm);display:flex;align-items:center;gap:16px;} -.stat-card__icon{width:48px;height:48px;border-radius:var(--radius-md);display:flex;align-items:center;justify-content:center;font-size:24px;} -.stat-card__icon.blue{background:var(--primary-light);} -.stat-card__icon.green{background:#F6FFED;} -.stat-card__icon.orange{background:#FFF7E6;} -.stat-card__icon.red{background:#FFF1F0;} -.stat-card__info{display:flex;flex-direction:column;gap:4px;} -.stat-card__value{font-size:var(--font-xl);font-weight:700;color:var(--text-primary);} -.stat-card__label{font-size:var(--font-sm);color:var(--text-secondary);} +/* 操作链接 */ +.link{color:var(--primary);cursor:pointer;font-size:var(--font-sm);}.link:hover{color:#40a9ff;} + /* 操作列固定右侧 */ thead th:last-child,tbody td.td-actions{position:sticky;right:0;background:#fff;box-shadow:-4px 0 8px rgba(0,0,0,0.04);z-index:2;white-space:nowrap;} thead th:last-child{background:#FAFAFA;} tbody tr:hover td.td-actions{background:#F8FBFF;} + +/* 分页 */ +.pagination{display:flex;align-items:center;justify-content:space-between;padding:16px 24px;border-top:1px solid var(--border);} +.pagination__left{display:flex;align-items:center;gap:8px;font-size:var(--font-sm);color:var(--text-secondary);} +.pagination__left .filter-select{min-width:70px;height:32px;} +.pagination__right{display:flex;align-items:center;gap:6px;} +.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);} +.page-ellipsis{width:32px;height:32px;display:inline-flex;align-items:center;justify-content:center;font-size:var(--font-sm);color:var(--text-secondary);} @@ -119,26 +127,16 @@ tbody tr:hover td.td-actions{background:#F8FBFF;}
- -
-
-
-
-
12
-
今日结果异常
-
-
-
-
-
-
8
-
已溯源
-
-
-
-
+
+ + +
- - -
-
- - + + + +
- +
+
89 条异常记录
+ +
-
-
结果异常
-
@@ -194,46 +183,129 @@ tbody tr:hover td.td-actions{background:#F8FBFF;} - - + + - - + + - - + + - - + + - - + + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ERR-001营养值异常ERR-2026-001营养值异常 营养计算 员工EMP0234午餐热量计算结果为0kcal v2.3.12026-04-15 12:30查看 溯源2026-05-14 12:30详情
ERR-002推荐结果为空ERR-2026-002推荐结果为空 菜品推荐 员工EMP0456个性化推荐返回空列表 v1.8.02026-04-15 11:45查看 溯源2026-05-14 11:45详情
ERR-003营养值超范围ERR-2026-003营养值超范围 营养计算 某菜品钠含量计算结果为99999mg v2.3.12026-04-15 10:20查看 溯源2026-05-14 10:20详情
ERR-2026-004算法超时营养计算批量营养分析任务执行超时(>30s)v2.3.12026-05-13 16:40详情
ERR-2026-005推荐结果为空菜品推荐糖尿病患者推荐食谱未返回低GI菜品v1.8.02026-05-13 14:15详情
ERR-2026-006模型输出异常智能推荐LLM返回JSON格式解析失败v3.0.22026-05-13 11:30详情
ERR-2026-007营养值异常营养计算维生素A摄入量计算结果为负值v2.3.12026-05-12 15:50详情
ERR-2026-008营养值超范围营养计算单餐蛋白质含量超出日推荐量300%v2.3.12026-05-12 12:10详情
ERR-2026-009模型输出异常智能推荐小模型推理服务返回500错误v3.0.22026-05-11 09:25详情
ERR-2026-010推荐结果为空菜品推荐过敏源过滤后可推荐菜品为零v1.8.02026-05-11 08:40详情
diff --git a/web-admin/nutrition/arc-employee-detail.html b/web-admin/nutrition/arc-employee-detail.html index 29c8ad5..cc999d5 100644 --- a/web-admin/nutrition/arc-employee-detail.html +++ b/web-admin/nutrition/arc-employee-detail.html @@ -80,7 +80,6 @@ tbody tr:hover{background:#F8FBFF;} .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);} -${CSS_RULE} /* 操作列固定右侧 */ thead th:last-child,tbody td.td-actions{position:sticky;right:0;background:#fff;box-shadow:-4px 0 8px rgba(0,0,0,0.04);z-index:2;white-space:nowrap;} thead th:last-child{background:#FAFAFA;} diff --git a/web-admin/nutrition/din-algo-population.html b/web-admin/nutrition/din-algo-population.html index bf00be8..d1bb15a 100644 --- a/web-admin/nutrition/din-algo-population.html +++ b/web-admin/nutrition/din-algo-population.html @@ -31,7 +31,6 @@ body{font-family:-apple-system,BlinkMacSystemFont,'PingFang SC','Microsoft YaHei .sidebar-item.active{color:#fff;background:var(--primary);} .mi{display:inline-block;width:20px;text-align:center;filter:grayscale(1);opacity:0.65;margin-right:2px;} .sidebar-item.active .mi{opacity:0.9;} -${CSS_RULE} .sidebar-subgroup__header{display:flex;align-items:center;gap:6px;padding:10px 24px;color:rgba(255,255,255,0.65);font-size:var(--font-sm);cursor:pointer;transition:all .15s;user-select:none;} .sidebar-subgroup__header:hover{color:rgba(255,255,255,0.85);background:rgba(255,255,255,0.04);} .sidebar-subgroup__header .arrow{width:10px;height:10px;transition:transform .2s;flex-shrink:0;} @@ -183,9 +182,6 @@ tbody tr:hover td.td-actions{background:#F8FBFF;}
-
- -
算法标准
diff --git a/web-admin/nutrition/din-algo-vip.html b/web-admin/nutrition/din-algo-vip.html index c3e5b48..c287d60 100644 --- a/web-admin/nutrition/din-algo-vip.html +++ b/web-admin/nutrition/din-algo-vip.html @@ -31,7 +31,6 @@ body{font-family:-apple-system,BlinkMacSystemFont,'PingFang SC','Microsoft YaHei .sidebar-item.active{color:#fff;background:var(--primary);} .mi{display:inline-block;width:20px;text-align:center;filter:grayscale(1);opacity:0.65;margin-right:2px;} .sidebar-item.active .mi{opacity:0.9;} -${CSS_RULE} .sidebar-subgroup__header{display:flex;align-items:center;gap:6px;padding:10px 24px;color:rgba(255,255,255,0.65);font-size:var(--font-sm);cursor:pointer;transition:all .15s;user-select:none;} .sidebar-subgroup__header:hover{color:rgba(255,255,255,0.85);background:rgba(255,255,255,0.04);} .sidebar-subgroup__header .arrow{width:10px;height:10px;transition:transform .2s;flex-shrink:0;} @@ -154,14 +153,6 @@ tbody tr:hover td.td-actions{background:#F8FBFF;}
- -
-
💎
186
VIP定制人数
-
🎯
82
减重目标
-
💪
54
增肌目标
-
🩺
50
慢病管理目标
-
-
@@ -184,11 +175,11 @@ tbody tr:hover td.td-actions{background:#F8FBFF;}
人群类型热量范围(kcal)蛋白质比例(%)脂肪比例(%)碳水比例(%)钙(mg)铁(mg)维生素C(mg)膳食纤维(g)每日饮水量(mL)操作
- + - - - + + +
用户编号/姓名定制目标类型每日热量(kcal)蛋白质目标(g)脂肪目标(g)碳水目标(g)特殊限制项制定营养师生效日期复评日期操作
姓名用户编号所属单位所属部门定制目标类型每日热量(kcal)蛋白质目标(g)脂肪目标(g)碳水目标(g)特殊限制项制定营养师生效日期复评日期操作
VIP001/张明减重16509545170禁高糖饮料营养师李明2026-04-012026-05-01编辑
VIP002/刘芳控糖(糖尿病)17508850160低GI优先营养师王芳2026-03-202026-04-25编辑
VIP003/陈伟增肌245014068280增加优质蛋白营养师李明2026-04-102026-05-10编辑
张明VIP001长庆油田采油一厂减重16509545170禁高糖饮料营养师李明2026-04-012026-05-01详情 编辑 删除
刘芳VIP002长庆油田采气二厂控糖(糖尿病)17508850160低GI优先营养师王芳2026-03-202026-04-25详情 编辑 删除
陈伟VIP003长庆油田机械制造公司增肌245014068280增加优质蛋白营养师李明2026-04-102026-05-10详情 编辑 删除
diff --git a/web-admin/nutrition/din-data-benefit.html b/web-admin/nutrition/din-data-benefit.html index 644cb44..833935c 100644 --- a/web-admin/nutrition/din-data-benefit.html +++ b/web-admin/nutrition/din-data-benefit.html @@ -31,7 +31,6 @@ body{font-family:-apple-system,BlinkMacSystemFont,'PingFang SC','Microsoft YaHei .sidebar-item.active{color:#fff;background:var(--primary);} .mi{display:inline-block;width:20px;text-align:center;filter:grayscale(1);opacity:0.65;margin-right:2px;} .sidebar-item.active .mi{opacity:0.9;} -${CSS_RULE} .sidebar-subgroup__header{display:flex;align-items:center;gap:6px;padding:10px 24px;color:rgba(255,255,255,0.65);font-size:var(--font-sm);cursor:pointer;transition:all .15s;user-select:none;} .sidebar-subgroup__header:hover{color:rgba(255,255,255,0.85);background:rgba(255,255,255,0.04);} .sidebar-subgroup__header .arrow{width:10px;height:10px;transition:transform .2s;flex-shrink:0;} @@ -42,16 +41,16 @@ ${CSS_RULE} .sidebar-subgroup.open>.sidebar-subgroup__body{display:block;} .sidebar-subgroup__body .sidebar-item{padding-left:36px;font-size:12px;} .main{margin-left:240px;margin-top:56px;padding:24px;min-height:calc(100vh - 56px);} -.stats-row{display:grid;grid-template-columns:repeat(3,1fr);gap:16px;margin-bottom:16px;} -.stat-card{background:#fff;border-radius:var(--radius-md);padding:20px 24px;box-shadow:var(--shadow-sm);display:flex;align-items:center;gap:16px;} -.stat-card__icon{width:48px;height:48px;border-radius:var(--radius-md);display:flex;align-items:center;justify-content:center;font-size:24px;} +.stats-row{display:grid;grid-template-columns:repeat(6,1fr);gap:12px;margin-bottom:16px;} +.stat-card{background:#fff;border-radius:var(--radius-md);padding:12px 14px;box-shadow:var(--shadow-sm);display:flex;align-items:center;gap:10px;} +.stat-card__icon{width:36px;height:36px;border-radius:var(--radius-sm);display:flex;align-items:center;justify-content:center;font-size:18px;flex-shrink:0;} .stat-card__icon.blue{background:var(--primary-light);} .stat-card__icon.green{background:#F6FFED;} .stat-card__icon.orange{background:#FFF7E6;} .stat-card__icon.red{background:#FFF1F0;} -.stat-card__info{display:flex;flex-direction:column;gap:4px;} -.stat-card__value{font-size:var(--font-xl);font-weight:700;color:var(--text-primary);} -.stat-card__label{font-size:var(--font-sm);color:var(--text-secondary);} +.stat-card__info{display:flex;flex-direction:column;gap:2px;min-width:0;} +.stat-card__value{font-size:var(--font-base);font-weight:700;color:var(--text-primary);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;} +.stat-card__label{font-size:var(--font-xs);color:var(--text-secondary);white-space:nowrap;} .page-tabs{display:flex;gap:0;background:#fff;border-radius:var(--radius-md) var(--radius-md) 0 0;padding:0 24px;box-shadow:var(--shadow-sm);border-bottom:2px solid var(--border);} .page-tab{padding:14px 20px;font-size:var(--font-sm);cursor:pointer;color:var(--text-secondary);border-bottom:2px solid transparent;margin-bottom:-2px;transition:all .2s;display:flex;align-items:center;gap:6px;} .page-tab:hover{color:var(--primary);} @@ -94,6 +93,42 @@ tbody tr:hover{background:#F8FBFF;} thead th:last-child,tbody td.td-actions{position:sticky;right:0;background:#fff;box-shadow:-4px 0 8px rgba(0,0,0,0.04);z-index:2;white-space:nowrap;} thead th:last-child{background:#FAFAFA;} tbody tr:hover td.td-actions{background:#F8FBFF;} +/* 弹窗基础样式 */ +.modal-overlay{position:fixed;inset:0;background:rgba(0,0,0,0.45);z-index:1000;display:flex;align-items:center;justify-content:center;opacity:0;transition:opacity .25s;} +.modal-overlay.show{opacity:1;} +.modal{background:#fff;border-radius:var(--radius-lg);width:680px;max-height:80vh;display:flex;flex-direction:column;transform:translateY(30px);transition:transform .25s;box-shadow:0 12px 40px rgba(0,0,0,0.18);} +.modal-overlay.show .modal{transform:translateY(0);} +.modal__header{display:flex;align-items:center;justify-content:space-between;padding:18px 24px;border-bottom:1px solid var(--border);} +.modal__header h3{font-size:var(--font-lg);font-weight:600;margin:0;} +.modal__close{width:32px;height:32px;border:none;background:none;cursor:pointer;font-size:20px;color:#999;display:flex;align-items:center;justify-content:center;border-radius:var(--radius-sm);} +.modal__close:hover{background:#f5f5f5;color:#333;} +.modal__body{padding:20px 24px;overflow-y:auto;flex:1;} +.modal__footer{display:flex;justify-content:flex-end;gap:12px;padding:16px 24px;border-top:1px solid var(--border);} +/* 损耗明细弹窗 */ +.loss-info{display:grid;grid-template-columns:1fr 1fr;gap:12px 24px;margin-bottom:20px;} +.loss-info__item{display:flex;align-items:center;gap:8px;font-size:var(--font-sm);} +.loss-info__label{color:var(--text-secondary);min-width:80px;} +.loss-info__value{color:var(--text-primary);font-weight:500;} +.loss-section{margin-bottom:16px;} +.loss-section__title{font-size:var(--font-sm);font-weight:600;color:var(--text-primary);margin-bottom:10px;padding-bottom:6px;border-bottom:1px solid var(--border);} +.loss-bar{display:flex;align-items:center;gap:10px;margin-bottom:8px;font-size:var(--font-sm);} +.loss-bar__label{width:80px;color:var(--text-secondary);text-align:right;} +.loss-bar__track{flex:1;height:18px;background:#f0f0f0;border-radius:9px;overflow:hidden;position:relative;} +.loss-bar__fill{height:100%;border-radius:9px;transition:width .4s;} +.loss-bar__val{width:60px;font-weight:500;} +.loss-tip{background:#FFF7E6;border:1px solid #FFE58F;border-radius:var(--radius-sm);padding:10px 14px;font-size:var(--font-sm);color:#D48806;margin-top:12px;display:flex;align-items:flex-start;gap:6px;} +/* 食材成本明细弹窗 */ +.cost-header{display:flex;gap:24px;margin-bottom:16px;font-size:var(--font-sm);} +.cost-header span{color:var(--text-secondary);} +.cost-header strong{color:var(--text-primary);margin-left:4px;} +.cost-table{width:100%;border-collapse:collapse;} +.cost-table thead th{background:#FAFAFA;padding:10px 16px;text-align:left;font-size:var(--font-sm);color:var(--text-secondary);font-weight:500;border-bottom:1px solid var(--border);} +.cost-table tbody td{padding:12px 16px;font-size:var(--font-sm);color:var(--text-primary);border-bottom:1px solid var(--border);} +.cost-table tbody tr:last-child td{border-bottom:none;} +.cost-table tbody tr:hover{background:#F8FBFF;} +.cost-summary{display:flex;justify-content:flex-end;gap:24px;padding:12px 16px;background:#FAFAFA;border-radius:0 0 var(--radius-md) var(--radius-md);font-size:var(--font-sm);} +.cost-summary span{color:var(--text-secondary);} +.cost-summary strong{color:var(--primary);margin-left:4px;} @@ -122,40 +157,40 @@ tbody tr:hover td.td-actions{background:#F8FBFF;} @@ -251,6 +286,157 @@ tbody tr:hover td.td-actions{background:#F8FBFF;} function switchTab(idx){document.querySelectorAll('.page-tab').forEach((t,i)=>t.classList.toggle('active',i===idx));document.querySelectorAll('.tab-panel').forEach((p,i)=>p.classList.toggle('active',i===idx));} function toggleSubgroup(header){header.parentElement.classList.toggle('open');} (function(){var active=document.querySelector('.sidebar-item.active');if(!active)return;var sub=active.closest('.sidebar-subgroup');if(sub)sub.classList.add('open');})(); + +/* ===== 弹窗组件 ===== */ +const Modal={ + open(title,bodyHtml,extraClass){ + const overlay=document.createElement('div'); + overlay.className='modal-overlay'; + overlay.innerHTML=``; + document.body.appendChild(overlay); + overlay.addEventListener('click',e=>{if(e.target===overlay)Modal.close();}); + requestAnimationFrame(()=>overlay.classList.add('show')); + }, + close(){ + const o=document.querySelector('.modal-overlay'); + if(!o)return; + o.classList.remove('show'); + setTimeout(()=>o.remove(),250); + } +}; + +/* ===== 损耗明细弹窗 ===== */ +function showLossDetail(row){ + /* 从表格行中读取数据 */ + const cells=row.querySelectorAll('td'); + const date=cells[0].textContent.trim(); + const code=cells[1].textContent.trim(); + const name=cells[2].textContent.trim(); + const category=cells[3].textContent.trim(); + const supplier=cells[4].textContent.trim(); + const buyQty=cells[5].textContent.trim(); + const price=cells[6].textContent.trim(); + const total=cells[7].textContent.trim(); + const usedQty=cells[8].textContent.trim(); + const lossQty=cells[9].textContent.trim(); + const lossAmt=cells[10].textContent.trim(); + const lossRate=cells[11].textContent.trim(); + const level=cells[12].textContent.trim(); + const reason=cells[13].textContent.trim(); + + const html=` +
+
食材编号${code}
+
食材名称${name}
+
所属分类${category}
+
供应商${supplier}
+
统计日期${date}
+
采购单价${price}
+
+
+
用量与损耗
+
采购量
${buyQty}kg
+
实际使用
${usedQty}kg
+
损耗量
${lossQty}kg
+
+
+
损耗分析
+
+
采购总额${total}
+
损耗金额${lossAmt}
+
损耗率${lossRate}
+
预警等级${level}
+
损耗原因${reason}
+
+
+
⚠️ 建议:${reason==='过期未用'?'加强库存先进先出管理,缩短采购周期,减少积压。':reason==='储存变质'?'检查冷链温控设备,优化储存条件,缩短库存周转天数。':'优化加工切配流程,加强厨师技能培训,减少边角料浪费。'}
`; + + Modal.open('损耗明细 — '+name,html); +} + +/* ===== 食材成本明细弹窗 ===== */ +function showCostDetail(row){ + const cells=row.querySelectorAll('td'); + const dishCode=cells[0].textContent.trim(); + const dishName=cells[1].textContent.trim(); + const mealType=cells[2].textContent.trim(); + const costPerServe=cells[8].textContent.trim(); + const sellPrice=cells[9].textContent.trim(); + + /* 模拟食材成本数据 */ + const costData={ + '糖醋里脊':[ + {name:'猪里脊肉',weight:'150g',unitPrice:'28.0',cost:'4.20'}, + {name:'淀粉',weight:'20g',unitPrice:'6.0',cost:'0.12'}, + {name:'番茄酱',weight:'30g',unitPrice:'12.0',cost:'0.36'}, + {name:'白糖',weight:'15g',unitPrice:'8.0',cost:'0.12'}, + {name:'食用油',weight:'40ml',unitPrice:'10.0',cost:'0.40'}, + {name:'醋',weight:'20ml',unitPrice:'5.0',cost:'0.10'} + ], + '蒜蓉西兰花':[ + {name:'西兰花',weight:'200g',unitPrice:'5.0',cost:'1.00'}, + {name:'大蒜',weight:'15g',unitPrice:'12.0',cost:'0.18'}, + {name:'食用油',weight:'15ml',unitPrice:'10.0',cost:'0.15'}, + {name:'蚝油',weight:'10ml',unitPrice:'15.0',cost:'0.15'}, + {name:'盐',weight:'3g',unitPrice:'3.0',cost:'0.01'} + ], + '鱼香肉丝':[ + {name:'猪瘦肉',weight:'120g',unitPrice:'24.0',cost:'2.88'}, + {name:'胡萝卜',weight:'50g',unitPrice:'3.0',cost:'0.15'}, + {name:'黑木耳',weight:'30g',unitPrice:'40.0',cost:'1.20'}, + {name:'笋丝',weight:'40g',unitPrice:'8.0',cost:'0.32'}, + {name:'豆瓣酱',weight:'15g',unitPrice:'10.0',cost:'0.15'}, + {name:'食用油',weight:'30ml',unitPrice:'10.0',cost:'0.30'} + ], + '红烧肉':[ + {name:'五花肉',weight:'180g',unitPrice:'26.0',cost:'4.68'}, + {name:'生姜',weight:'10g',unitPrice:'8.0',cost:'0.08'}, + {name:'八角',weight:'3g',unitPrice:'30.0',cost:'0.09'}, + {name:'冰糖',weight:'15g',unitPrice:'10.0',cost:'0.15'}, + {name:'酱油',weight:'20ml',unitPrice:'8.0',cost:'0.16'}, + {name:'料酒',weight:'15ml',unitPrice:'5.0',cost:'0.08'} + ] + }; + const items=costData[dishName]||costData['糖醋里脊']; + const totalCost=items.reduce((s,i)=>s+parseFloat(i.cost),0).toFixed(2); + + let tableRows=items.map(i=>`${i.name}${i.weight}¥${i.unitPrice}/kg¥${i.cost}`).join(''); + + const html=` +
+ 餐品编号:${dishCode} + 所属餐次:${mealType} + 销售单价:¥${sellPrice} +
+ + + ${tableRows} +
食材名称用量/份采购单价成本(元/份)
+
+ 食材成本合计:¥${totalCost} + 毛利/份:¥${(parseFloat(sellPrice)-parseFloat(totalCost)).toFixed(2)} +
`; + + Modal.open('食材成本明细 — '+dishName,html); +} + +/* ===== 事件绑定 ===== */ +document.querySelectorAll('.tab-panel').forEach((panel,tabIdx)=>{ + panel.querySelectorAll('tbody tr').forEach(row=>{ + row.querySelectorAll('.td-actions .link').forEach(link=>{ + if(tabIdx===0 && link.textContent.includes('损耗明细')){ + link.addEventListener('click',()=>showLossDetail(row)); + } + if(tabIdx===1 && link.textContent.includes('食材成本明细')){ + link.addEventListener('click',()=>showCostDetail(row)); + } + }); + }); +}); \ No newline at end of file diff --git a/web-admin/nutrition/din-data-consume.html b/web-admin/nutrition/din-data-consume.html index 4126d0b..986397c 100644 --- a/web-admin/nutrition/din-data-consume.html +++ b/web-admin/nutrition/din-data-consume.html @@ -35,7 +35,6 @@ body{font-family:-apple-system,BlinkMacSystemFont,'PingFang SC','Microsoft YaHei .sidebar-item.active{color:#fff;background:var(--primary);} .mi{display:inline-block;width:20px;text-align:center;filter:grayscale(1);opacity:0.65;margin-right:2px;} .sidebar-item.active .mi{opacity:0.9;} -${CSS_RULE} .sidebar-subgroup__header{display:flex;align-items:center;gap:6px;padding:10px 24px;color:rgba(255,255,255,0.65);font-size:var(--font-sm);cursor:pointer;transition:all .15s;user-select:none;} .sidebar-subgroup__header:hover{color:rgba(255,255,255,0.85);background:rgba(255,255,255,0.04);} .sidebar-subgroup__header .arrow{width:10px;height:10px;transition:transform .2s;flex-shrink:0;} @@ -93,6 +92,33 @@ tbody tr:hover{background:#F8FBFF;} thead th:last-child,tbody td.td-actions{position:sticky;right:0;background:#fff;box-shadow:-4px 0 8px rgba(0,0,0,0.04);z-index:2;white-space:nowrap;} thead th:last-child{background:#FAFAFA;} tbody tr:hover td.td-actions{background:#F8FBFF;} + +/* 弹窗样式 */ +.modal-overlay{position:fixed;top:0;left:0;right:0;bottom:0;background:rgba(0,0,0,.45);z-index:1000;display:flex;align-items:center;justify-content:center;animation:modalFadeIn .2s ease;} +.modal-overlay.closing{animation:modalFadeOut .2s ease forwards;} +@keyframes modalFadeIn{from{opacity:0}to{opacity:1}} +@keyframes modalFadeOut{from{opacity:1}to{opacity:0}} +@keyframes modalSlideIn{from{transform:translateY(-20px);opacity:0}to{transform:translateY(0);opacity:1}} +@keyframes modalSlideOut{from{transform:translateY(0);opacity:1}to{transform:translateY(-20px);opacity:0}} +.modal{background:#fff;border-radius:8px;width:860px;max-width:90vw;max-height:85vh;display:flex;flex-direction:column;box-shadow:0 12px 48px rgba(0,0,0,.15);animation:modalSlideIn .25s ease;} +.modal-overlay.closing .modal{animation:modalSlideOut .2s ease forwards;} +.modal-header{display:flex;align-items:center;justify-content:space-between;padding:16px 24px;border-bottom:1px solid var(--border);} +.modal-title{font-size:var(--font-lg);font-weight:600;color:var(--text-primary);} +.modal-close{width:32px;height:32px;border:none;background:none;font-size:20px;cursor:pointer;border-radius:var(--radius-sm);color:var(--text-secondary);display:flex;align-items:center;justify-content:center;} +.modal-close:hover{background:#f5f5f5;color:var(--text-primary);} +.modal-body{padding:24px;overflow-y:auto;flex:1;} +.modal-table{width:100%;border-collapse:collapse;font-size:var(--font-sm);} +.modal-table thead th{background:#FAFAFA;padding:10px 12px;text-align:left;color:var(--text-secondary);font-weight:500;border-bottom:1px solid var(--border);} +.modal-table tbody td{padding:10px 12px;border-bottom:1px solid var(--border);color:var(--text-primary);} +.modal-table tbody tr:last-child td{border-bottom:none;} +.modal-table tbody tr:hover{background:#F8FBFF;} +.detail-grid{display:grid;grid-template-columns:1fr 1fr;gap:12px 24px;margin-bottom:20px;padding:16px;background:#FAFAFA;border-radius:var(--radius-md);} +.detail-grid__item{display:flex;align-items:center;gap:8px;font-size:var(--font-sm);} +.detail-grid__label{color:var(--text-secondary);min-width:80px;} +.detail-grid__value{color:var(--text-primary);font-weight:500;} +.detail-info{display:flex;gap:24px;padding:12px 16px;background:#FAFAFA;border-radius:var(--radius-sm);margin-bottom:16px;font-size:var(--font-sm);} +.detail-info span{color:var(--text-secondary);} +.detail-info b{color:var(--text-primary);font-weight:500;} @@ -252,6 +278,119 @@ tbody tr:hover td.td-actions{background:#F8FBFF;} \ No newline at end of file diff --git a/web-admin/nutrition/din-data-nutri.html b/web-admin/nutrition/din-data-nutri.html index 56d7858..d8f45e5 100644 --- a/web-admin/nutrition/din-data-nutri.html +++ b/web-admin/nutrition/din-data-nutri.html @@ -31,7 +31,6 @@ body{font-family:-apple-system,BlinkMacSystemFont,'PingFang SC','Microsoft YaHei .sidebar-item.active{color:#fff;background:var(--primary);} .mi{display:inline-block;width:20px;text-align:center;filter:grayscale(1);opacity:0.65;margin-right:2px;} .sidebar-item.active .mi{opacity:0.9;} -${CSS_RULE} .sidebar-subgroup__header{display:flex;align-items:center;gap:6px;padding:10px 24px;color:rgba(255,255,255,0.65);font-size:var(--font-sm);cursor:pointer;transition:all .15s;user-select:none;} .sidebar-subgroup__header:hover{color:rgba(255,255,255,0.85);background:rgba(255,255,255,0.04);} .sidebar-subgroup__header .arrow{width:10px;height:10px;transition:transform .2s;flex-shrink:0;} @@ -94,6 +93,206 @@ tbody tr:hover{background:#F8FBFF;} thead th:last-child,tbody td.td-actions{position:sticky;right:0;background:#fff;box-shadow:-4px 0 8px rgba(0,0,0,0.04);z-index:2;white-space:nowrap;} thead th:last-child{background:#FAFAFA;} tbody tr:hover td.td-actions{background:#F8FBFF;} + +/* 弹窗样式 */ +.modal-overlay{position:fixed;top:0;left:0;right:0;bottom:0;background:rgba(0,0,0,.45);z-index:1000;display:flex;align-items:center;justify-content:center;animation:modalFadeIn .2s ease;} +.modal-overlay.closing{animation:modalFadeOut .2s ease forwards;} +@keyframes modalFadeIn{from{opacity:0}to{opacity:1}} +@keyframes modalFadeOut{from{opacity:1}to{opacity:0}} +@keyframes modalSlideIn{from{transform:translateY(-20px);opacity:0}to{transform:translateY(0);opacity:1}} +@keyframes modalSlideOut{from{transform:translateY(0);opacity:1}to{transform:translateY(-20px);opacity:0}} +.modal{background:#fff;border-radius:8px;width:900px;max-width:90vw;max-height:85vh;display:flex;flex-direction:column;box-shadow:0 12px 48px rgba(0,0,0,.15);animation:modalSlideIn .25s ease;} +.modal-overlay.closing .modal{animation:modalSlideOut .2s ease forwards;} +.modal-header{display:flex;align-items:center;justify-content:space-between;padding:16px 24px;border-bottom:1px solid var(--border);} +.modal-title{font-size:var(--font-lg);font-weight:600;color:var(--text-primary);} +.modal-close{width:32px;height:32px;border:none;background:none;font-size:20px;cursor:pointer;border-radius:var(--radius-sm);color:var(--text-secondary);display:flex;align-items:center;justify-content:center;} +.modal-close:hover{background:#f5f5f5;color:var(--text-primary);} +.modal-body{padding:24px;overflow-y:auto;flex:1;} +.modal-footer{display:flex;justify-content:flex-end;gap:12px;padding:16px 24px;border-top:1px solid var(--border);} + +/* 十维档案 Tab */ +.profile-tabs{display:flex;gap:0;border-bottom:1px solid var(--border);margin-bottom:20px;overflow-x:auto;} +.profile-tab{padding:10px 16px;font-size:var(--font-sm);color:var(--text-secondary);cursor:pointer;border-bottom:2px solid transparent;white-space:nowrap;transition:all .2s;} +.profile-tab:hover{color:var(--primary);} +.profile-tab.active{color:var(--primary);border-bottom-color:var(--primary);font-weight:500;} +.profile-panel{display:none;} +.profile-panel.active{display:block;} +.profile-grid{display:grid;grid-template-columns:repeat(2,1fr);gap:12px 24px;} +.profile-field{display:flex;align-items:baseline;gap:8px;font-size:var(--font-sm);padding:8px 0;border-bottom:1px dashed #f0f0f0;} +.profile-field__label{color:var(--text-secondary);min-width:80px;flex-shrink:0;} +.profile-field__value{color:var(--text-primary);font-weight:500;} +.profile-summary{display:flex;align-items:center;gap:16px;padding:16px;background:#f8fafc;border-radius:var(--radius-md);margin-bottom:20px;} +.profile-summary__avatar{width:56px;height:56px;border-radius:50%;background:var(--primary);display:flex;align-items:center;justify-content:center;color:#fff;font-size:22px;font-weight:600;} +.profile-summary__info{display:flex;flex-direction:column;gap:4px;} +.profile-summary__name{font-size:var(--font-base);font-weight:600;color:var(--text-primary);} +.profile-summary__meta{font-size:var(--font-sm);color:var(--text-secondary);} + +/* 营养明细弹窗 */ +.nutri-modal{width:960px;} +.nutri-header-info{display:flex;align-items:center;gap:24px;padding:14px 20px;background:#f8fafc;border-radius:var(--radius-md);margin-bottom:20px;font-size:var(--font-sm);flex-wrap:wrap;} +.nutri-header-info__item{display:flex;align-items:center;gap:6px;} +.nutri-header-info__label{color:var(--text-secondary);} +.nutri-header-info__value{color:var(--text-primary);font-weight:500;} +.nutri-tabs{display:flex;gap:0;border-bottom:1px solid var(--border);margin-bottom:20px;} +.nutri-tab{padding:10px 20px;font-size:var(--font-sm);color:var(--text-secondary);cursor:pointer;border-bottom:2px solid transparent;white-space:nowrap;transition:all .2s;} +.nutri-tab:hover{color:var(--primary);} +.nutri-tab.active{color:var(--primary);border-bottom-color:var(--primary);font-weight:500;} +.nutri-panel{display:none;} +.nutri-panel.active{display:block;} +.nutri-section{margin-bottom:24px;} +.nutri-section__title{font-size:var(--font-sm);font-weight:600;color:var(--text-primary);margin-bottom:14px;padding-left:8px;border-left:3px solid var(--primary);} +/* 进度条 */ +.nutri-bar-list{display:flex;flex-direction:column;gap:14px;} +.nutri-bar-item{display:flex;align-items:center;gap:12px;font-size:var(--font-sm);} +.nutri-bar-item__label{min-width:50px;color:var(--text-secondary);text-align:right;flex-shrink:0;} +.nutri-bar-item__track{flex:1;height:20px;background:#f0f0f0;border-radius:10px;position:relative;overflow:hidden;} +.nutri-bar-item__fill{height:100%;border-radius:10px;transition:width .6s ease;} +.nutri-bar-item__fill.green{background:linear-gradient(90deg,#95de64,#52C41A);} +.nutri-bar-item__fill.orange{background:linear-gradient(90deg,#ffd666,#FAAD14);} +.nutri-bar-item__fill.red{background:linear-gradient(90deg,#ff9c9c,#FF4D4F);} +.nutri-bar-item__info{min-width:200px;color:var(--text-secondary);flex-shrink:0;font-size:12px;} +.nutri-bar-item__info strong{color:var(--text-primary);} +/* 群体对比 */ +.nutri-compare{display:flex;gap:32px;justify-content:center;padding:16px 0;} +.nutri-compare__item{display:flex;flex-direction:column;align-items:center;gap:6px;min-width:120px;} +.nutri-compare__score{font-size:40px;font-weight:700;line-height:1;} +.nutri-compare__score.green{color:var(--success);} +.nutri-compare__score.orange{color:var(--warning);} +.nutri-compare__score.gray{color:#999;} +.nutri-compare__label{font-size:var(--font-sm);color:var(--text-secondary);} +/* 趋势图 */ +.nutri-charts{display:grid;grid-template-columns:1fr 1fr;gap:20px;} +.nutri-chart-box{background:#fafafa;border-radius:var(--radius-md);padding:16px;} +.nutri-chart-box__title{font-size:var(--font-sm);font-weight:500;color:var(--text-primary);margin-bottom:12px;} +.nutri-chart-box svg{width:100%;display:block;} +/* 风险评估 */ +.nutri-risk{display:flex;align-items:center;gap:12px;padding:14px 20px;border-radius:var(--radius-md);font-size:var(--font-sm);} +.nutri-risk.low{background:#F6FFED;color:var(--success);border:1px solid #b7eb8f;} +.nutri-risk.mid{background:#FFF7E6;color:var(--warning);border:1px solid #ffe58f;} +.nutri-risk.high{background:#FFF1F0;color:var(--danger);border:1px solid #ffa39e;} +.nutri-risk__icon{font-size:20px;flex-shrink:0;} +.nutri-risk__text{display:flex;flex-direction:column;gap:2px;} +.nutri-risk__title{font-weight:600;} +/* 干预建议 */ +.nutri-advice{background:#f8fafc;border-radius:var(--radius-md);padding:16px 20px;} +.nutri-advice__item{display:flex;align-items:flex-start;gap:8px;font-size:var(--font-sm);color:var(--text-primary);padding:6px 0;} +.nutri-advice__item::before{content:'💡';flex-shrink:0;} +/* 膳食宝塔 */ +.pyramid{display:flex;flex-direction:column;align-items:center;gap:0;padding:20px 0;} +.pyramid__level{display:flex;align-items:center;justify-content:center;text-align:center;font-size:var(--font-sm);color:#fff;font-weight:500;border-radius:4px 4px 0 0;padding:10px 8px;line-height:1.4;} +.pyramid__level:nth-child(1){width:20%;background:#FF4D4F;} +.pyramid__level:nth-child(2){width:35%;background:#FAAD14;} +.pyramid__level:nth-child(3){width:50%;background:#1890FF;} +.pyramid__level:nth-child(4){width:65%;background:#13C2C2;} +.pyramid__level:nth-child(5){width:80%;background:#52C41A;} +.pyramid__legend{margin-top:20px;width:100%;} +.pyramid__legend-row{display:flex;align-items:center;justify-content:space-between;padding:8px 0;border-bottom:1px dashed #f0f0f0;font-size:var(--font-sm);} +.pyramid__legend-name{display:flex;align-items:center;gap:8px;} +.pyramid__legend-dot{width:10px;height:10px;border-radius:2px;flex-shrink:0;} +.pyramid__legend-values{display:flex;gap:24px;color:var(--text-secondary);} +.pyramid__legend-values strong{color:var(--text-primary);} + +/* 餐品明细(溯源关联)弹窗 */ +.dish-modal{width:980px;} +.dish-header-info{display:flex;align-items:center;gap:24px;padding:14px 20px;background:#f8fafc;border-radius:var(--radius-md);margin-bottom:16px;font-size:var(--font-sm);flex-wrap:wrap;} +.dish-header-info__item{display:flex;align-items:center;gap:6px;} +.dish-header-info__label{color:var(--text-secondary);} +.dish-header-info__value{color:var(--text-primary);font-weight:500;} +.dish-tip{display:flex;align-items:center;gap:8px;padding:10px 16px;background:var(--primary-light);border-radius:var(--radius-sm);margin-bottom:16px;font-size:var(--font-sm);color:var(--primary);} +.dish-tip svg{flex-shrink:0;} +.dish-table{width:100%;border-collapse:collapse;font-size:var(--font-sm);margin-bottom:16px;} +.dish-table thead th{background:#FAFAFA;padding:10px 12px;text-align:left;color:var(--text-secondary);font-weight:500;border-bottom:1px solid var(--border);white-space:nowrap;} +.dish-table tbody td{padding:12px 12px;border-bottom:1px solid var(--border);color:var(--text-primary);white-space:nowrap;} +.dish-table tbody tr:last-child td{border-bottom:none;} +.dish-table tbody tr:hover{background:#F8FBFF;} +.dish-table .td-num{font-variant-numeric:tabular-nums;} +.dish-table .td-code{color:var(--text-secondary);font-family:monospace;font-size:12px;} +.dish-trace-link{color:var(--primary);cursor:pointer;font-size:var(--font-sm);display:inline-flex;align-items:center;gap:4px;}.dish-trace-link:hover{color:#40a9ff;} +/* 底部汇总 */ +.dish-summary{display:flex;align-items:center;gap:32px;padding:16px 20px;background:#f8fafc;border-radius:var(--radius-md);font-size:var(--font-sm);} +.dish-summary__item{display:flex;align-items:baseline;gap:6px;} +.dish-summary__label{color:var(--text-secondary);} +.dish-summary__value{font-size:var(--font-lg);font-weight:700;color:var(--text-primary);} +.dish-summary__value.blue{color:var(--primary);} +.dish-summary__value.green{color:var(--success);} +.dish-summary__value.orange{color:var(--warning);} + +/* 营养师工作台弹窗 */ +.wb-modal{width:1060px;} +.wb-layout{display:flex;gap:16px;align-items:flex-start;} +/* 左侧用户摘要 */ +.wb-left{width:240px;flex-shrink:0;background:#f8fafc;border-radius:var(--radius-md);padding:16px;} +.wb-avatar-row{display:flex;align-items:center;gap:10px;margin-bottom:14px;} +.wb-avatar{width:48px;height:48px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:22px;flex-shrink:0;} +.wb-user-name{font-size:14px;font-weight:700;color:var(--text-primary);} +.wb-user-meta{font-size:11px;color:var(--text-secondary);margin-top:2px;} +.wb-score-row{display:grid;grid-template-columns:1fr 1fr;gap:8px;margin-bottom:14px;} +.wb-score-card{background:#fff;border-radius:6px;padding:8px;text-align:center;} +.wb-score-card__val{font-size:18px;font-weight:800;line-height:1.2;} +.wb-score-card__label{font-size:10px;color:var(--text-secondary);margin-top:2px;} +.wb-spark{background:#fff;border-radius:6px;padding:10px;margin-bottom:12px;} +.wb-spark__title{font-size:11px;color:var(--text-secondary);margin-bottom:6px;} +.wb-spark svg{display:block;width:100%;} +.wb-info-list{display:flex;flex-direction:column;gap:8px;} +.wb-info-item__label{font-size:11px;color:var(--text-secondary);} +.wb-info-item__value{font-size:13px;font-weight:600;color:var(--text-primary);} +/* 右侧 Tab */ +.wb-right{flex:1;min-width:0;} +.wb-tabs{display:flex;gap:0;border-bottom:1px solid var(--border);margin-bottom:14px;} +.wb-tab{padding:8px 16px;font-size:13px;color:var(--text-secondary);cursor:pointer;border:none;background:none;border-bottom:2px solid transparent;margin-bottom:-1px;transition:all .2s;white-space:nowrap;} +.wb-tab:hover{color:var(--primary);} +.wb-tab.active{color:var(--primary);border-bottom-color:var(--primary);font-weight:600;} +.wb-tab-body{max-height:520px;overflow-y:auto;padding-right:6px;} +.wb-panel{display:none;} +.wb-panel.active{display:block;} +/* 预警卡片 */ +.wb-warn{border-left:4px solid;border-radius:6px;padding:12px 14px;margin-bottom:10px;background:#fff;} +.wb-warn.high{border-color:var(--danger);border-top:1px solid #ffa39e;border-right:1px solid #ffa39e;border-bottom:1px solid #ffa39e;} +.wb-warn.mid{border-color:var(--warning);border-top:1px solid #ffe58f;border-right:1px solid #ffe58f;border-bottom:1px solid #ffe58f;} +.wb-warn.low{border-color:var(--primary);border-top:1px solid #91d5ff;border-right:1px solid #91d5ff;border-bottom:1px solid #91d5ff;} +.wb-warn__head{display:flex;align-items:center;justify-content:space-between;margin-bottom:6px;} +.wb-warn__title{font-size:14px;font-weight:600;} +.wb-warn__body{font-size:12px;color:var(--text-secondary);line-height:1.7;} +.wb-warn__foot{font-size:11px;color:var(--text-secondary);margin-top:6px;} +/* 规划卡片 */ +.wb-plan{background:#fff;border:1px solid var(--border);border-radius:var(--radius-md);padding:14px;margin-bottom:12px;} +.wb-plan__head{display:flex;align-items:center;justify-content:space-between;margin-bottom:8px;} +.wb-plan__goal{font-size:14px;font-weight:600;color:var(--text-primary);} +.wb-plan__period{font-size:11px;color:var(--text-secondary);margin-bottom:8px;} +.wb-plan__bar{background:#f0f0f0;height:6px;border-radius:3px;margin-bottom:8px;overflow:hidden;} +.wb-plan__bar-fill{height:100%;border-radius:3px;background:linear-gradient(90deg,#1890FF,#36cfc9);} +.wb-plan__pct{font-size:11px;color:var(--text-secondary);margin-bottom:8px;} +.wb-plan__items{font-size:12px;color:var(--text-secondary);line-height:1.9;} +.wb-plan__actions{display:flex;gap:6px;margin-top:10px;} +/* 建议卡片 */ +.wb-adv{border:1px solid var(--border);border-radius:6px;padding:10px 12px;margin-bottom:8px;} +.wb-adv.ai{background:#f0f7ff;} +.wb-adv__head{display:flex;align-items:center;justify-content:space-between;margin-bottom:4px;} +.wb-adv__author{font-size:12px;font-weight:600;display:flex;align-items:center;gap:6px;} +.wb-adv__time{font-size:11px;color:var(--text-secondary);} +.wb-adv__content{font-size:13px;color:var(--text-secondary);line-height:1.7;} +/* 跟进时间轴 */ +.wb-timeline{position:relative;padding-left:18px;} +.wb-timeline::before{content:'';position:absolute;left:5px;top:6px;bottom:6px;width:2px;background:var(--border);} +.wb-tl-item{position:relative;margin-bottom:14px;} +.wb-tl-dot{position:absolute;left:-15px;top:6px;width:10px;height:10px;border-radius:50%;background:var(--primary);border:2px solid #fff;box-shadow:0 0 0 1px var(--primary);} +.wb-tl-card{background:#fff;border:1px solid var(--border);border-radius:6px;padding:10px 12px;} +.wb-tl-card__head{display:flex;align-items:center;justify-content:space-between;margin-bottom:4px;} +.wb-tl-card__topic{font-size:13px;font-weight:600;} +.wb-tl-card__time{font-size:11px;color:var(--text-secondary);} +.wb-tl-card__who{font-size:12px;color:var(--text-secondary);margin-bottom:6px;} +.wb-tl-card__body{font-size:12px;color:var(--text-secondary);line-height:1.7;} +.wb-tl-card__fb{font-size:11px;color:var(--text-secondary);margin-top:6px;} +/* 空状态 */ +.wb-empty{text-align:center;padding:40px 20px;color:var(--text-placeholder);} +.wb-empty__icon{font-size:32px;margin-bottom:8px;} +/* 面板头部工具条 */ +.wb-panel-bar{display:flex;justify-content:space-between;align-items:center;margin-bottom:12px;} +.wb-panel-bar__title{font-size:13px;font-weight:600;} +/* 建议输入区 */ +.wb-adv-input{width:100%;min-height:70px;padding:8px;border:1px solid var(--border);border-radius:var(--radius-sm);font-size:var(--font-sm);resize:vertical;outline:none;font-family:inherit;} +.wb-adv-input:focus{border-color:var(--primary);} +.wb-adv-btns{display:flex;gap:6px;margin-top:8px;margin-bottom:12px;} @@ -122,40 +321,40 @@ tbody tr:hover td.td-actions{background:#F8FBFF;} @@ -192,10 +391,10 @@ tbody tr:hover td.td-actions{background:#F8FBFF;}
- - + +
@@ -233,10 +432,10 @@ tbody tr:hover td.td-actions{background:#F8FBFF;}
- - + +
@@ -272,10 +471,10 @@ tbody tr:hover td.td-actions{background:#F8FBFF;}
- - + +
@@ -310,10 +509,10 @@ tbody tr:hover td.td-actions{background:#F8FBFF;}
- - + +
@@ -344,6 +543,444 @@ tbody tr:hover td.td-actions{background:#F8FBFF;} function switchTab(idx){document.querySelectorAll('.page-tab').forEach((t,i)=>t.classList.toggle('active',i===idx));document.querySelectorAll('.tab-panel').forEach((p,i)=>p.classList.toggle('active',i===idx));} function toggleSubgroup(header){header.parentElement.classList.toggle('open');} (function(){var active=document.querySelector('.sidebar-item.active');if(!active)return;var sub=active.closest('.sidebar-subgroup');if(sub)sub.classList.add('open');})(); + +/* ========== 弹窗基础 ========== */ +const Modal = { + open(title, bodyHtml, extraClass, footerHtml) { + this.close(); + const overlay = document.createElement('div'); + overlay.className = 'modal-overlay'; + overlay.innerHTML = ``; + overlay.addEventListener('click', e => { if (e.target === overlay) Modal.close(); }); + document.body.appendChild(overlay); + }, + close() { + const o = document.querySelector('.modal-overlay'); + if (!o) return; + o.classList.add('closing'); + setTimeout(() => o.remove(), 200); + } +}; + +/* ========== 十维档案 ========== */ +const userProfiles = { + '张伟': { dept:'研发部', age:38, gender:'男', height:'175cm', weight:'72kg', bmi:'22.9', activity:'中度活动', + disease:'无', chronic:'无', medicine:'无', family:'高血压(父)', + examDate:'2026-03-15', bp:'125/80', glucose:'5.2', lipid:'正常', uric:'380', liver:'正常', kidney:'正常', + taste:'偏辣', region:'川菜、湘菜', taboo:'无', allergy:'花生', + exercise:'6000步/日', weightTrend:'稳定', bodyFat:'18%', heartRate:'68', sleep:'7.5h', stress:'低', source:'智能手环', + meals30:'58次', hotDish:'宫保鸡丁、番茄牛腩', avgCal:'680kcal', nutriRate:'88%', + favDish:'宫保鸡丁、清炒西兰花', recDish:'三文鱼沙拉', avoidDish:'油炸花生', topRate:'番茄牛腩(4.8)', repurchase:'宫保鸡丁', + hometown:'四川成都', momTag:'麻辣鲜香', momList:'回锅肉、麻婆豆腐', memory:'妈妈的回锅肉', recTry:'水煮鱼', + modelVer:'v2.3', modelTime:'2026-04-20', recCal:'2100kcal', nutriFocus:'蛋白质+膳食纤维', risk:'无', tags:'运动达人、川菜爱好者', confidence:'92%' }, + '李娜': { dept:'市场部', age:34, gender:'女', height:'163cm', weight:'52kg', bmi:'19.8', activity:'轻度活动', + disease:'无', chronic:'无', medicine:'无', family:'糖尿病(母)', + examDate:'2026-02-20', bp:'110/70', glucose:'4.8', lipid:'正常', uric:'290', liver:'正常', kidney:'正常', + taste:'清淡', region:'粤菜、日料', taboo:'无', allergy:'海鲜(虾蟹)', + exercise:'4000步/日', weightTrend:'稳定', bodyFat:'22%', heartRate:'72', sleep:'7h', stress:'中', source:'手机计步', + meals30:'52次', hotDish:'蒸鱼、蔬菜沙拉', avgCal:'520kcal', nutriRate:'92%', + favDish:'清蒸鲈鱼、藜麦沙拉', recDish:'牛油果吐司', avoidDish:'麻辣火锅', topRate:'藜麦沙拉(4.9)', repurchase:'清蒸鲈鱼', + hometown:'广东广州', momTag:'鲜甜清润', momList:'老火靓汤、白切鸡', memory:'周末的煲汤', recTry:'椰子鸡', + modelVer:'v2.3', modelTime:'2026-04-18', recCal:'1650kcal', nutriFocus:'钙+铁+维生素D', risk:'注意糖摄入', tags:'轻食主义、养生达人', confidence:'95%' } +}; +const defaultProfile = { dept:'—', age:30, gender:'—', height:'170cm', weight:'65kg', bmi:'22.5', activity:'中等', + disease:'无', chronic:'无', medicine:'无', family:'无', + examDate:'2026-01-10', bp:'120/78', glucose:'5.0', lipid:'正常', uric:'350', liver:'正常', kidney:'正常', + taste:'适中', region:'不限', taboo:'无', allergy:'无', + exercise:'5000步/日', weightTrend:'稳定', bodyFat:'20%', heartRate:'70', sleep:'7h', stress:'低', source:'手动录入', + meals30:'45次', hotDish:'家常菜', avgCal:'600kcal', nutriRate:'78%', + favDish:'红烧肉、西红柿炒蛋', recDish:'杂粮饭套餐', avoidDish:'无', topRate:'红烧肉(4.5)', repurchase:'西红柿炒蛋', + hometown:'—', momTag:'家常味', momList:'红烧肉', memory:'—', recTry:'—', + modelVer:'v2.3', modelTime:'2026-04-15', recCal:'1900kcal', nutriFocus:'均衡', risk:'无', tags:'普通用户', confidence:'80%' }; + +const tabDefs = [ + { key:'basic', label:'静态基础' },{ key:'disease', label:'疾病信息' },{ key:'physical', label:'体检信息' }, + { key:'taste', label:'口味偏好' },{ key:'taboo', label:'禁忌关联' },{ key:'dynamic', label:'动态生理' }, + { key:'meal', label:'历史用餐' },{ key:'dish', label:'菜品偏好' },{ key:'mom', label:'妈妈味道' },{ key:'model', label:'个性模型' } +]; + +function buildProfileHTML(name, p) { + const panels = { + basic: `
姓名${name}
部门${p.dept}
年龄${p.age}岁
性别${p.gender}
身高${p.height}
体重${p.weight}
BMI${p.bmi}
活动水平${p.activity}
`, + disease: `
疾病史${p.disease}
慢病分级${p.chronic}
用药情况${p.medicine}
家族病史${p.family}
`, + physical: `
体检日期${p.examDate}
血压${p.bp} mmHg
空腹血糖${p.glucose} mmol/L
血脂${p.lipid}
尿酸${p.uric} μmol/L
肝功能${p.liver}
肾功能${p.kidney}
`, + taste: `
口味偏好${p.taste}
地域菜系${p.region}
`, + taboo: `
饮食禁忌${p.taboo}
过敏原${p.allergy}
`, + dynamic: `
日均运动量${p.exercise}
体重趋势${p.weightTrend}
体脂率${p.bodyFat}
静息心率${p.heartRate} bpm
平均睡眠${p.sleep}
压力指数${p.stress}
数据来源${p.source}
`, + meal: `
近30日就餐${p.meals30}
常点菜品${p.hotDish}
平均热量${p.avgCal}
营养达标率${p.nutriRate}
`, + dish: `
常点菜品${p.favDish}
系统推荐${p.recDish}
忌口菜品${p.avoidDish}
评分最高${p.topRate}
复购冠军${p.repurchase}
`, + mom: `
家乡${p.hometown}
妈妈味道标签${p.momTag}
思乡菜清单${p.momList}
关联记忆${p.memory}
推荐尝试${p.recTry}
`, + model: `
模型版本${p.modelVer}
生成时间${p.modelTime}
推荐热量${p.recCal}
营养侧重${p.nutriFocus}
风险预警${p.risk}
个性标签${p.tags}
模型置信度${p.confidence}
` + }; + const tabs = tabDefs.map((t, i) => `
${t.label}
`).join(''); + const panelsHtml = tabDefs.map((t, i) => `
${panels[t.key]}
`).join(''); + const summary = `
${name[0]}
${name}
${p.dept} · ${p.gender} · ${p.age}岁 · BMI ${p.bmi}
`; + return summary + `
${tabs}
${panelsHtml}`; +} + +function switchProfileTab(el, key) { + el.parentElement.querySelectorAll('.profile-tab').forEach(t => t.classList.remove('active')); + el.classList.add('active'); + el.closest('.modal-body').querySelectorAll('.profile-panel').forEach(p => p.classList.remove('active')); + el.closest('.modal-body').querySelector(`[data-panel="${key}"]`).classList.add('active'); +} + +function showUserProfile(name) { + const p = userProfiles[name] || defaultProfile; + Modal.open('用户十维档案 — ' + name, buildProfileHTML(name, p)); +} + +/* ========== 营养明细弹窗 ========== */ +function buildNutriDetailHTML() { + /* SVG 折线图:热量趋势 */ + const calPoints = [2080,2150,2020,2200,2100,2180,2156]; + const naPoints = [1750,1900,1680,1850,1920,1780,1820]; + const dates = ['4/22','4/23','4/24','4/25','4/26','4/27','4/28']; + function buildSvgLine(data, color, unit, minY, maxY) { + const w = 340, h = 120, px = 36, pr = 10, pt = 10, pb = 24; + const cw = w - px - pr, ch = h - pt - pb; + const step = cw / (data.length - 1); + const range = maxY - minY || 1; + const pts = data.map((v, i) => [px + i * step, pt + ch - (v - minY) / range * ch]); + const line = pts.map(p => p.join(',')).join(' '); + const gridLines = [0, 0.5, 1].map(r => { + const y = pt + ch - r * ch; + const val = Math.round(minY + r * range); + return ` + ${val}`; + }).join(''); + const xLabels = dates.map((d, i) => `${d}`).join(''); + const dots = pts.map((p, i) => ``).join(''); + return ` + ${gridLines}${xLabels} + + ${dots} + `; + } + + const calChart = buildSvgLine(calPoints, '#1890FF', 'kcal', 1900, 2300); + const naChart = buildSvgLine(naPoints, '#FAAD14', 'mg', 1500, 2100); + + /* 营养维度面板 */ + const dimensionPanel = ` +
+
当日营养摄入 vs 日推荐量
+
+
+ 热量 +
+ 2,156 kcal / 推荐 2,250 kcal(96%) +
+
+ 蛋白质 +
+ 78.3 g / 推荐 75 g(104%) +
+
+ 碳水 +
+ 285.4 g / 推荐 300 g(95%) +
+
+ 脂肪 +
+ 72.1 g / 推荐 80 g(90%) +
+
+ +
+ 1,820 mg / 推荐 2,000 mg(91%) +
+
+
+
+
与群体均值对比(综合评分)
+
+
88
本人
+
84
研发部均值
+
81
全公司均值
+
+
+
+
近7日营养素趋势
+
+
热量(kcal)
${calChart}
+
钠(mg)
${naChart}
+
+
+
+
慢病风险评估
+
+ +
低风险暂无慢病风险项,继续保持良好饮食习惯
+
+
+
+
专业干预建议
+
+
本周营养摄入稳定,各项指标均在合理范围
+
脂肪摄入连续偏高,建议减少红肉频次,每周不超过3次
+
建议增加深色蔬菜摄入,补充膳食纤维
+
+
`; + + /* 膳食宝塔面板 */ + const pyramidPanel = ` +
+
油盐
油 25g · 盐 5g
+
奶豆
奶 300g · 大豆 25g
+
鱼肉蛋
鱼虾 75g · 畜禽肉 50g · 蛋 50g
+
蔬果
蔬菜 400g · 水果 250g
+
谷薯
谷薯类 300g
+
+
+
谷薯类
推荐 300g实际 285g达标
+
蔬菜水果
推荐 650g实际 580g偏低
+
鱼肉蛋
推荐 175g实际 190g达标
+
奶豆类
推荐 325g实际 260g偏低
+
油盐
推荐 油25g 盐5g实际 油22g 盐4.6g达标
+
`; + + /* 顶部信息 + Tab 组装 */ + const headerInfo = `
+
用户:张伟(EMP001)
+
统计日期:2026-04-28
+
统计范围:午餐聚合
+
综合评分:88分
+
慢病风险:低风险
+
`; + + const tabs = `
+
📊 营养维度
+
🔺 膳食宝塔
+
`; + + return headerInfo + tabs + + `
${dimensionPanel}
` + + `
${pyramidPanel}
`; +} + +function switchNutriTab(el, idx) { + el.parentElement.querySelectorAll('.nutri-tab').forEach((t, i) => t.classList.toggle('active', i === idx)); + el.closest('.modal-body').querySelectorAll('.nutri-panel').forEach((p, i) => p.classList.toggle('active', i === idx)); +} + +function showNutriDetail() { + Modal.open('营养明细 — 张伟(EMP001) · 2026-04-28 午餐聚合', buildNutriDetailHTML(), 'nutri-modal'); +} + +/* ========== 餐品明细弹窗 ========== */ +function buildDishDetailHTML() { + const headerInfo = `
+
用户:张伟(EMP001)
+
统计范围:2026-04-28 午餐
+
消费合计:¥22.00
+
营养评分:88分
+
`; + + const tip = `
+ + 点击「食材溯源链路」按钮可在链路可视化中查看该餐品对应的食材溯源链路 +
`; + + const table = ` + + + + + + +
餐品编码菜品重量热量(kcal)蛋白质碳水脂肪单价超标状态食材溯源
DM-MIFA米饭180g2324.3g50.8g0.5g2mg¥2.00正常🔗 食材溯源链路
DM-HSRO红烧肉120g39514.2g8.6g28g680mg¥12.00⚠️ 脂肪偏高🔗 食材溯源链路
DM-CSHU炒时蔬80g382.1g5.2g1.2g180mg¥8.00正常🔗 食材溯源链路
`; + + const summary = `
+
总热量:856 kcal
+
热量达成率:43%
+
消费合计:¥22.00
+
营养评分:88分
+
`; + + return headerInfo + tip + table + summary; +} + +function showDishDetail() { + Modal.open('溯源关联 — 张伟(EMP001) · 2026-04-28 午餐', buildDishDetailHTML(), 'dish-modal'); +} + +/* ========== 营养师工作台弹窗 ========== */ +const wbData = { + user:'张伟(EMP001)', dept:'研发部', personType:'会员', age:38, gender:'男', bmi:'22.9', diseaseLabel:'无', + avgScore30:86, riskLevel:'低', interventionStatus:'已稳定', nutritionist:'林营养师', lastFollowUp:'2026-04-26', + scoreTrend:[82,84,85,86,88,87,86], + warnings:[], + plans:[ + { goal:'维持当前营养均衡水平', period:'2026-04-01 ~ 2026-09-30', progress:65, items:['每日蛋白质保持 ≥75g','深色蔬菜每日 ≥250g','红肉每周 ≤3 次'], status:'进行中' } + ], + advices:[ + { time:'2026-04-26', author:'林营养师', content:'本月各项指标稳定,继续保持当前饮食结构。下次复评 2026-05-26。', isAi:false }, + { time:'2026-04-15', author:'AI 助手', content:'检测到脂肪摄入连续 3 日偏高,建议减少红肉频次。', isAi:true } + ], + followUps:[ + { time:'2026-04-26 14:30', who:'林营养师', topic:'月度复评', content:'电话沟通,用户反馈饮食习惯无变化,BMI 维持 22.9。', feedback:'满意' }, + { time:'2026-03-26 10:00', who:'林营养师', topic:'月度复评', content:'首次建立营养档案,目标维持稳定。', feedback:'认可' } + ] +}; + +function buildWorkbenchHTML() { + const a = wbData; + const scoreColor = a.avgScore30 >= 85 ? '#52C41A' : a.avgScore30 >= 75 ? '#1890FF' : a.avgScore30 >= 60 ? '#FAAD14' : '#FF4D4F'; + const riskColor = a.riskLevel === '高' ? '#FF4D4F' : a.riskLevel === '中' ? '#FAAD14' : '#52C41A'; + + /* 迷你折线图 */ + const trend = a.scoreTrend; + const maxS = Math.max(...trend), minS = Math.min(...trend), spkRange = (maxS - minS) || 1; + const spkPts = trend.map((v, i) => { + const x = (i / (trend.length - 1)) * 200; + const y = 40 - ((v - minS) / spkRange) * 34 - 3; + return `${x.toFixed(1)},${y.toFixed(1)}`; + }).join(' '); + const spkDots = trend.map((v, i) => { + const x = (i / (trend.length - 1)) * 200; + const y = 40 - ((v - minS) / spkRange) * 34 - 3; + return ``; + }).join(''); + + /* 左侧面板 */ + const left = `
+
+
👤
+
${a.user}
${a.dept} · ${a.gender} · ${a.age}岁
+
+
+
${a.avgScore30}
近30日均分
+
${a.riskLevel}
风险等级
+
+
+
近7日评分趋势
+ ${spkDots} +
+
+
BMI
${a.bmi}
+
慢病标签
${a.diseaseLabel}
+
人员类别
${a.personType}
+
负责营养师
${a.nutritionist}
+
最近跟进
${a.lastFollowUp}
+
干预状态
${a.interventionStatus}
+
+
`; + + /* ① 疾病预警 */ + const warnList = a.warnings.length + ? a.warnings.map(w => { + const cls = w.severity === '高' ? 'high' : w.severity === '中' ? 'mid' : 'low'; + const sevColor = w.severity === '高' ? 'var(--danger)' : w.severity === '中' ? 'var(--warning)' : 'var(--primary)'; + return `
+
⚠️ ${w.type}${w.severity}风险
+
${w.evidence}
+
触发时间:${w.triggeredAt} · ${w.notified ? '✓ 已通知' : '⏳ 待通知'}
+
`; + }).join('') + : '
当前无疾病预警
'; + const warnHtml = `
预警列表(${a.warnings.length})
${warnList}`; + + /* ② 营养规划 */ + const planList = a.plans.length + ? a.plans.map(p => `
+
🎯 ${p.goal}${p.status}
+
⏱ ${p.period}
+
+
完成进度 ${p.progress}%
+
${p.items.map(i => `
· ${i}
`).join('')}
+
+
`).join('') + : '
📋
暂无营养规划
'; + const planHtml = `
营养规划(${a.plans.length})
${planList}`; + + /* ③ 营养建议 */ + const advList = a.advices.map(ad => { + const tag = ad.isAi ? '🤖 AI' : '👤 营养师'; + return `
+
${ad.author} ${tag}
${ad.time}
+
${ad.content}
+
`; + }).join(''); + const advHtml = ` +
+
历史建议(${a.advices.length})
${advList}`; + + /* ④ 跟进记录 */ + const followList = a.followUps.length + ? `
${a.followUps.map(f => `
+
+
+
${f.topic}${f.time}
+
👤 ${f.who}
+
${f.content}
+
用户反馈:${f.feedback}
+
+
`).join('')}
` + : '
暂无跟进记录
'; + const followHtml = `
跟进时间轴(${a.followUps.length})
${followList}`; + + /* 右侧面板 */ + const right = `
+
+ + + + +
+
+
${warnHtml}
+
${planHtml}
+
${advHtml}
+
${followHtml}
+
+
`; + + return `
${left}${right}
`; +} + +function switchWbTab(el, idx) { + el.parentElement.querySelectorAll('.wb-tab').forEach((t, i) => t.classList.toggle('active', i === idx)); + el.closest('.wb-right').querySelectorAll('.wb-panel').forEach((p, i) => p.classList.toggle('active', i === idx)); +} + +function showWorkbench() { + const footer = ``; + Modal.open('🍽️ 营养师工作台 — ' + wbData.user, buildWorkbenchHTML(), 'wb-modal', footer); +} + +/* ========== 四个 Tab 列表事件绑定 ========== */ +document.querySelectorAll('.tab-panel').forEach((panel, tabIdx) => { + panel.querySelectorAll('tbody tr').forEach(row => { + const links = row.querySelectorAll('.td-actions .link'); + const nameCell = row.querySelector('td:first-child'); + if (!nameCell) return; + const rawName = nameCell.textContent.trim(); + const userName = rawName.replace(/\(.*\)/, '').trim(); + links.forEach(link => { + if (link.textContent.includes('查看用户信息')) { + link.addEventListener('click', () => showUserProfile(userName)); + } + /* 前三个 Tab(餐次/按日/按周)的营养明细按钮 */ + if (tabIdx < 3 && link.textContent.includes('营养明细')) { + link.addEventListener('click', () => showNutriDetail()); + } + /* 前三个 Tab(餐次/按日/按周)的餐品明细按钮 */ + if (tabIdx < 3 && link.textContent.includes('餐品明细')) { + link.addEventListener('click', () => showDishDetail()); + } + /* 第四个 Tab(营养档案)的营养管理按钮 */ + if (tabIdx === 3 && link.textContent.includes('营养管理')) { + link.addEventListener('click', () => showWorkbench()); + } + }); + }); +}); \ No newline at end of file diff --git a/web-admin/nutrition/din-innovation.html b/web-admin/nutrition/din-innovation.html index 6818d73..7a2f0d0 100644 --- a/web-admin/nutrition/din-innovation.html +++ b/web-admin/nutrition/din-innovation.html @@ -115,22 +115,22 @@ tbody tr:hover td.td-actions{background:#F8FBFF;}
diff --git a/web-admin/nutrition/din-model-llm.html b/web-admin/nutrition/din-model-llm.html index 5e6be27..d118cf3 100644 --- a/web-admin/nutrition/din-model-llm.html +++ b/web-admin/nutrition/din-model-llm.html @@ -32,7 +32,6 @@ body{font-family:-apple-system,BlinkMacSystemFont,'PingFang SC','Microsoft YaHei .sidebar-item.active{color:#fff;background:var(--primary);} .mi{display:inline-block;width:20px;text-align:center;filter:grayscale(1);opacity:0.65;margin-right:2px;} .sidebar-item.active .mi{opacity:0.9;} -${CSS_RULE} .sidebar-subgroup__header{display:flex;align-items:center;gap:6px;padding:10px 24px;color:rgba(255,255,255,0.65);font-size:var(--font-sm);cursor:pointer;transition:all .15s;user-select:none;} .sidebar-subgroup__header:hover{color:rgba(255,255,255,0.85);background:rgba(255,255,255,0.04);} .sidebar-subgroup__header .arrow{width:10px;height:10px;transition:transform .2s;flex-shrink:0;} @@ -74,37 +73,31 @@ tbody tr:hover{background:#F8FBFF;} .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);} -.modal-overlay{position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,0.45);z-index:1000;display:flex;align-items:center;justify-content:center;} -.modal{background:#fff;border-radius:8px;width:680px;max-height:80vh;overflow-y:auto;box-shadow:0 4px 12px rgba(0,0,0,0.15);} -.modal-header{display:flex;align-items:center;justify-content:space-between;padding:16px 24px;border-bottom:1px solid #e8e8e8;} -.modal-title{font-size:16px;font-weight:600;color:#262626;} -.modal-close{font-size:22px;cursor:pointer;color:#8c8c8c;line-height:1;} -.modal-close:hover{color:#262626;} -.modal-body{padding:24px;} -.modal-footer{display:flex;justify-content:flex-end;gap:12px;padding:16px 24px;border-top:1px solid #e8e8e8;} -.form-grid{display:grid;grid-template-columns:1fr 1fr;gap:16px;} -.form-item{display:flex;flex-direction:column;gap:4px;} -.form-item.full{grid-column:1/-1;} -.form-item label{font-size:13px;color:#8c8c8c;} -.form-item label .required{color:#ff4d4f;margin-left:2px;} -.form-item input,.form-item select,.form-item textarea{height:36px;padding:0 12px;border:1px solid #e8e8e8;border-radius:4px;font-size:13px;outline:none;} -.form-item input:focus,.form-item select:focus,.form-item textarea:focus{border-color:#1890FF;} -.form-item textarea{height:80px;padding:8px 12px;resize:vertical;} -.stats-row{display:grid;grid-template-columns:repeat(4,1fr);gap:16px;margin-bottom:16px;} -.stat-card{background:#fff;border-radius:var(--radius-md);padding:20px 24px;box-shadow:var(--shadow-sm);display:flex;align-items:center;gap:16px;} -.stat-card__icon{width:48px;height:48px;border-radius:var(--radius-md);display:flex;align-items:center;justify-content:center;font-size:24px;} -.stat-card__icon.blue{background:var(--primary-light);} -.stat-card__icon.green{background:#F6FFED;} -.stat-card__icon.orange{background:#FFF7E6;} -.stat-card__icon.red{background:#FFF1F0;} -.stat-card__info{display:flex;flex-direction:column;gap:4px;} -.stat-card__value{font-size:var(--font-xl);font-weight:700;color:var(--text-primary);} -.stat-card__label{font-size:var(--font-sm);color:var(--text-secondary);} .action-bar{display:flex;align-items:center;gap:8px;margin-bottom:16px;} /* 操作列固定右侧 */ thead th:last-child,tbody td.td-actions{position:sticky;right:0;background:#fff;box-shadow:-4px 0 8px rgba(0,0,0,0.04);z-index:2;white-space:nowrap;} thead th:last-child{background:#FAFAFA;} tbody tr:hover td.td-actions{background:#F8FBFF;} +/* 动态弹窗 */ +.dyn-overlay{position:fixed;inset:0;background:rgba(0,0,0,0.45);z-index:1000;display:flex;align-items:center;justify-content:center;opacity:0;transition:opacity .25s;} +.dyn-overlay.show{opacity:1;} +.dyn-modal{background:#fff;border-radius:var(--radius-lg);max-height:80vh;display:flex;flex-direction:column;transform:translateY(30px);transition:transform .25s;box-shadow:0 12px 40px rgba(0,0,0,0.18);} +.dyn-overlay.show .dyn-modal{transform:translateY(0);} +.dyn-modal__header{display:flex;align-items:center;justify-content:space-between;padding:18px 24px;border-bottom:1px solid var(--border);} +.dyn-modal__header h3{font-size:var(--font-lg);font-weight:600;margin:0;} +.dyn-modal__close{width:32px;height:32px;border:none;background:none;cursor:pointer;font-size:20px;color:#999;display:flex;align-items:center;justify-content:center;border-radius:var(--radius-sm);} +.dyn-modal__close:hover{background:#f5f5f5;color:#333;} +.dyn-modal__body{padding:20px 24px;overflow-y:auto;flex:1;} +.dyn-modal__footer{display:flex;justify-content:flex-end;gap:12px;padding:16px 24px;border-top:1px solid var(--border);} +/* 调试日志弹窗 */ +.log-modal{width:820px;} +.log-dev-info{display:flex;gap:24px;margin-bottom:16px;font-size:var(--font-sm);color:var(--text-secondary);flex-wrap:wrap;} +.log-dev-info strong{color:var(--text-primary);margin-left:4px;} +.log-table{width:100%;border-collapse:collapse;} +.log-table thead th{background:#FAFAFA;padding:10px 16px;text-align:left;font-size:var(--font-sm);color:var(--text-secondary);font-weight:500;border-bottom:1px solid var(--border);} +.log-table tbody td{padding:12px 16px;font-size:var(--font-sm);color:var(--text-primary);border-bottom:1px solid var(--border);} +.log-table tbody tr:last-child td{border-bottom:none;} +.log-table tbody tr:hover{background:#F8FBFF;} @@ -133,52 +126,44 @@ tbody tr:hover td.td-actions{background:#F8FBFF;}
- -
-
🧠
3
接入大模型数
-
2
在用
-
📊
12.4万次
本月调用量
-
💰
¥3,860
本月费用
-
-
@@ -190,7 +175,7 @@ tbody tr:hover td.td-actions{background:#F8FBFF;}
- +
@@ -202,9 +187,9 @@ tbody tr:hover td.td-actions{background:#F8FBFF;} - - - + + +
模型编号模型名称提供商版本接入方式使用场景月调用量(次)月消耗Token月费用平均响应(ms)错误率超时率状态操作
LLM-001豆包字节跳动Doubao-pro-32kAPI调用小程序AI营养顾问68,24042.6万¥2,1403200.12%0.08%在用调用日志
LLM-002DeepSeek-V3深度求索v3-20250324API调用管理端智能助手54,82038.2万¥1,7202800.08%0.05%在用调用日志
LLM-003文心一言百度ERNIE-4.0API调用小程序AI营养顾问00¥0备用调用日志
LLM-001豆包字节跳动Doubao-pro-32kAPI调用小程序AI营养顾问68,24042.6万¥2,1403200.12%0.08%在用调试日志
LLM-002DeepSeek-V3深度求索v3-20250324API调用管理端智能助手54,82038.2万¥1,7202800.08%0.05%在用调试日志
LLM-003文心一言百度ERNIE-4.0API调用小程序AI营养顾问00¥0备用调试日志
@@ -212,36 +197,103 @@ tbody tr:hover td.td-actions{background:#F8FBFF;}
- - - \ No newline at end of file diff --git a/web-admin/nutrition/din-model-small.html b/web-admin/nutrition/din-model-small.html index 4a46c62..e83bd5c 100644 --- a/web-admin/nutrition/din-model-small.html +++ b/web-admin/nutrition/din-model-small.html @@ -32,7 +32,6 @@ body{font-family:-apple-system,BlinkMacSystemFont,'PingFang SC','Microsoft YaHei .sidebar-item.active{color:#fff;background:var(--primary);} .mi{display:inline-block;width:20px;text-align:center;filter:grayscale(1);opacity:0.65;margin-right:2px;} .sidebar-item.active .mi{opacity:0.9;} -${CSS_RULE} .sidebar-subgroup__header{display:flex;align-items:center;gap:6px;padding:10px 24px;color:rgba(255,255,255,0.65);font-size:var(--font-sm);cursor:pointer;transition:all .15s;user-select:none;} .sidebar-subgroup__header:hover{color:rgba(255,255,255,0.85);background:rgba(255,255,255,0.04);} .sidebar-subgroup__header .arrow{width:10px;height:10px;transition:transform .2s;flex-shrink:0;} @@ -74,37 +73,52 @@ tbody tr:hover{background:#F8FBFF;} .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);} -.modal-overlay{position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,0.45);z-index:1000;display:flex;align-items:center;justify-content:center;} -.modal{background:#fff;border-radius:8px;width:680px;max-height:80vh;overflow-y:auto;box-shadow:0 4px 12px rgba(0,0,0,0.15);} -.modal-header{display:flex;align-items:center;justify-content:space-between;padding:16px 24px;border-bottom:1px solid #e8e8e8;} -.modal-title{font-size:16px;font-weight:600;color:#262626;} -.modal-close{font-size:22px;cursor:pointer;color:#8c8c8c;line-height:1;} -.modal-close:hover{color:#262626;} -.modal-body{padding:24px;} -.modal-footer{display:flex;justify-content:flex-end;gap:12px;padding:16px 24px;border-top:1px solid #e8e8e8;} -.form-grid{display:grid;grid-template-columns:1fr 1fr;gap:16px;} -.form-item{display:flex;flex-direction:column;gap:4px;} -.form-item.full{grid-column:1/-1;} -.form-item label{font-size:13px;color:#8c8c8c;} -.form-item label .required{color:#ff4d4f;margin-left:2px;} -.form-item input,.form-item select,.form-item textarea{height:36px;padding:0 12px;border:1px solid #e8e8e8;border-radius:4px;font-size:13px;outline:none;} -.form-item input:focus,.form-item select:focus,.form-item textarea:focus{border-color:#1890FF;} -.form-item textarea{height:80px;padding:8px 12px;resize:vertical;} -.stats-row{display:grid;grid-template-columns:repeat(4,1fr);gap:16px;margin-bottom:16px;} -.stat-card{background:#fff;border-radius:var(--radius-md);padding:20px 24px;box-shadow:var(--shadow-sm);display:flex;align-items:center;gap:16px;} -.stat-card__icon{width:48px;height:48px;border-radius:var(--radius-md);display:flex;align-items:center;justify-content:center;font-size:24px;} -.stat-card__icon.blue{background:var(--primary-light);} -.stat-card__icon.green{background:#F6FFED;} -.stat-card__icon.orange{background:#FFF7E6;} -.stat-card__icon.red{background:#FFF1F0;} -.stat-card__info{display:flex;flex-direction:column;gap:4px;} -.stat-card__value{font-size:var(--font-xl);font-weight:700;color:var(--text-primary);} -.stat-card__label{font-size:var(--font-sm);color:var(--text-secondary);} .action-bar{display:flex;align-items:center;gap:8px;margin-bottom:16px;} /* 操作列固定右侧 */ thead th:last-child,tbody td.td-actions{position:sticky;right:0;background:#fff;box-shadow:-4px 0 8px rgba(0,0,0,0.04);z-index:2;white-space:nowrap;} thead th:last-child{background:#FAFAFA;} tbody tr:hover td.td-actions{background:#F8FBFF;} +/* 动态弹窗 */ +.dyn-overlay{position:fixed;inset:0;background:rgba(0,0,0,0.45);z-index:1000;display:flex;align-items:center;justify-content:center;opacity:0;transition:opacity .25s;} +.dyn-overlay.show{opacity:1;} +.dyn-modal{background:#fff;border-radius:var(--radius-lg);max-height:80vh;display:flex;flex-direction:column;transform:translateY(30px);transition:transform .25s;box-shadow:0 12px 40px rgba(0,0,0,0.18);} +.dyn-overlay.show .dyn-modal{transform:translateY(0);} +.dyn-modal__header{display:flex;align-items:center;justify-content:space-between;padding:18px 24px;border-bottom:1px solid var(--border);} +.dyn-modal__header h3{font-size:var(--font-lg);font-weight:600;margin:0;} +.dyn-modal__close{width:32px;height:32px;border:none;background:none;cursor:pointer;font-size:20px;color:#999;display:flex;align-items:center;justify-content:center;border-radius:var(--radius-sm);} +.dyn-modal__close:hover{background:#f5f5f5;color:#333;} +.dyn-modal__body{padding:20px 24px;overflow-y:auto;flex:1;} +.dyn-modal__footer{display:flex;justify-content:flex-end;gap:12px;padding:16px 24px;border-top:1px solid var(--border);} +/* 上传版本表单 */ +.upload-modal{width:600px;} +.upload-form{display:grid;grid-template-columns:1fr 1fr;gap:16px;} +.upload-form .form-item{display:flex;flex-direction:column;gap:4px;} +.upload-form .form-item.full{grid-column:1/-1;} +.upload-form .form-item label{font-size:var(--font-sm);color:var(--text-secondary);} +.upload-form .form-item label .req{color:var(--danger);margin-left:2px;} +.upload-form .form-item input,.upload-form .form-item select{height:36px;padding:0 12px;border:1px solid var(--border);border-radius:var(--radius-sm);font-size:var(--font-sm);outline:none;} +.upload-form .form-item input:focus,.upload-form .form-item select:focus,.upload-form .form-item textarea:focus{border-color:var(--primary);} +.upload-form .form-item textarea{height:72px;padding:8px 12px;border:1px solid var(--border);border-radius:var(--radius-sm);font-size:var(--font-sm);outline:none;resize:vertical;} +/* 版本历史 */ +.ver-modal{width:780px;} +.ver-info{display:flex;gap:24px;margin-bottom:16px;font-size:var(--font-sm);color:var(--text-secondary);flex-wrap:wrap;} +.ver-info strong{color:var(--text-primary);margin-left:4px;} +.ver-table{width:100%;border-collapse:collapse;} +.ver-table thead th{background:#FAFAFA;padding:10px 16px;text-align:left;font-size:var(--font-sm);color:var(--text-secondary);font-weight:500;border-bottom:1px solid var(--border);} +.ver-table tbody td{padding:12px 16px;font-size:var(--font-sm);color:var(--text-primary);border-bottom:1px solid var(--border);} +.ver-table tbody tr:last-child td{border-bottom:none;} +.ver-table tbody tr:hover{background:#F8FBFF;} +/* 在线测试 */ +.test-modal{width:560px;} +.test-input-area{margin-bottom:16px;} +.test-input-area label{display:block;font-size:var(--font-sm);color:var(--text-secondary);margin-bottom:6px;} +.test-input-area textarea{width:100%;height:80px;padding:10px 12px;border:1px solid var(--border);border-radius:var(--radius-sm);font-size:var(--font-sm);outline:none;resize:vertical;} +.test-input-area textarea:focus{border-color:var(--primary);} +.test-run-bar{display:flex;justify-content:flex-end;margin-bottom:16px;} +.test-result{background:#F6FFED;border:1px solid #B7EB8F;border-radius:var(--radius-md);padding:16px 20px;} +.test-result__title{font-size:var(--font-sm);color:var(--success);font-weight:600;margin-bottom:8px;} +.test-result__content{font-size:var(--font-base);color:var(--text-primary);line-height:1.6;} +.test-result__score{font-size:var(--font-lg);font-weight:700;color:var(--success);} @@ -133,52 +147,44 @@ tbody tr:hover td.td-actions{background:#F8FBFF;}
- -
-
🔬
6
小模型总数
-
5
在线
-
⏸️
1
离线
-
🎯
91.2%
平均准确率
-
-
@@ -190,7 +196,7 @@ tbody tr:hover td.td-actions{background:#F8FBFF;}
- +
@@ -216,36 +222,155 @@ tbody tr:hover td.td-actions{background:#F8FBFF;}
- - - \ No newline at end of file diff --git a/web-admin/nutrition/din-order-line.html b/web-admin/nutrition/din-order-line.html index 28b5be0..78383e9 100644 --- a/web-admin/nutrition/din-order-line.html +++ b/web-admin/nutrition/din-order-line.html @@ -35,7 +35,6 @@ body{font-family:-apple-system,BlinkMacSystemFont,'PingFang SC','Microsoft YaHei .sidebar-item.active{color:#fff;background:var(--primary);} .mi{display:inline-block;width:20px;text-align:center;filter:grayscale(1);opacity:0.65;margin-right:2px;} .sidebar-item.active .mi{opacity:0.9;} -${CSS_RULE} .sidebar-subgroup__header{display:flex;align-items:center;gap:6px;padding:10px 24px;color:rgba(255,255,255,0.65);font-size:var(--font-sm);cursor:pointer;transition:all .15s;user-select:none;} .sidebar-subgroup__header:hover{color:rgba(255,255,255,0.85);background:rgba(255,255,255,0.04);} .sidebar-subgroup__header .arrow{width:10px;height:10px;transition:transform .2s;flex-shrink:0;} @@ -104,6 +103,26 @@ tbody tr:hover{background:#F8FBFF;} thead th:last-child,tbody td.td-actions{position:sticky;right:0;background:#fff;box-shadow:-4px 0 8px rgba(0,0,0,0.04);z-index:2;white-space:nowrap;} thead th:last-child{background:#FAFAFA;} tbody tr:hover td.td-actions{background:#F8FBFF;} + +/* 弹窗样式 */ +.modal-overlay{position:fixed;top:0;left:0;right:0;bottom:0;background:rgba(0,0,0,.45);z-index:1000;display:flex;align-items:center;justify-content:center;animation:modalFadeIn .2s ease;} +.modal-overlay.closing{animation:modalFadeOut .2s ease forwards;} +@keyframes modalFadeIn{from{opacity:0}to{opacity:1}} +@keyframes modalFadeOut{from{opacity:1}to{opacity:0}} +@keyframes modalSlideIn{from{transform:translateY(-20px);opacity:0}to{transform:translateY(0);opacity:1}} +@keyframes modalSlideOut{from{transform:translateY(0);opacity:1}to{transform:translateY(-20px);opacity:0}} +.modal{background:#fff;border-radius:8px;width:860px;max-width:90vw;max-height:85vh;display:flex;flex-direction:column;box-shadow:0 12px 48px rgba(0,0,0,.15);animation:modalSlideIn .25s ease;} +.modal-overlay.closing .modal{animation:modalSlideOut .2s ease forwards;} +.modal-header{display:flex;align-items:center;justify-content:space-between;padding:16px 24px;border-bottom:1px solid var(--border);} +.modal-title{font-size:var(--font-lg);font-weight:600;color:var(--text-primary);} +.modal-close{width:32px;height:32px;border:none;background:none;font-size:20px;cursor:pointer;border-radius:var(--radius-sm);color:var(--text-secondary);display:flex;align-items:center;justify-content:center;} +.modal-close:hover{background:#f5f5f5;color:var(--text-primary);} +.modal-body{padding:24px;overflow-y:auto;flex:1;} +.modal-table{width:100%;border-collapse:collapse;font-size:var(--font-sm);} +.modal-table thead th{background:#FAFAFA;padding:10px 12px;text-align:left;color:var(--text-secondary);font-weight:500;border-bottom:1px solid var(--border);} +.modal-table tbody td{padding:10px 12px;border-bottom:1px solid var(--border);color:var(--text-primary);} +.modal-table tbody tr:last-child td{border-bottom:none;} +.modal-table tbody tr:hover{background:#F8FBFF;} @@ -353,6 +372,146 @@ function switchTab(idx){ document.querySelectorAll('.page-tab').forEach(function(t,i){t.classList.toggle('active',i===idx);}); document.querySelectorAll('.tab-panel').forEach(function(p,i){p.classList.toggle('active',i===idx);}); } + +/* ========== 弹窗基础 ========== */ +const Modal = { + open(title, bodyHtml) { + this.close(); + const overlay = document.createElement('div'); + overlay.className = 'modal-overlay'; + overlay.innerHTML = ``; + overlay.addEventListener('click', e => { if (e.target === overlay) Modal.close(); }); + document.body.appendChild(overlay); + }, + close() { + const o = document.querySelector('.modal-overlay'); + if (!o) return; + o.classList.add('closing'); + setTimeout(() => o.remove(), 200); + } +}; + +/* ========== 取餐明细弹窗 ========== */ +const pickupData = { + '00022号秤': [ + { time:'07:32', person:'张伟', dept:'研发部', dish:'小米粥', weight:'0.35kg', price:'¥5/份', amount:'¥5' }, + { time:'07:35', person:'李娜', dept:'市场部', dish:'小米粥', weight:'0.28kg', price:'¥5/份', amount:'¥5' }, + { time:'07:38', person:'王磊', dept:'运营部', dish:'小米粥', weight:'0.32kg', price:'¥5/份', amount:'¥5' }, + { time:'07:42', person:'赵敏', dept:'财务部', dish:'小米粥', weight:'0.30kg', price:'¥5/份', amount:'¥5' }, + { time:'07:45', person:'陈刚', dept:'人事部', dish:'小米粥', weight:'0.26kg', price:'¥5/份', amount:'¥5' }, + ], + '00023号秤': [ + { time:'07:36', person:'刘芳', dept:'市场部', dish:'燕麦粥', weight:'0.30kg', price:'¥4/份', amount:'¥4' }, + { time:'07:40', person:'孙磊', dept:'行政部', dish:'燕麦粥', weight:'0.28kg', price:'¥4/份', amount:'¥4' }, + { time:'07:44', person:'钱芳', dept:'销售部', dish:'燕麦粥', weight:'0.25kg', price:'¥4/份', amount:'¥4' }, + ], + '00025号秤': [ + { time:'11:35', person:'张伟', dept:'研发部', dish:'宫保鸡丁', weight:'0.18kg', price:'¥14/份', amount:'¥14' }, + { time:'11:38', person:'李娜', dept:'市场部', dish:'宫保鸡丁', weight:'0.15kg', price:'¥14/份', amount:'¥14' }, + { time:'11:42', person:'赵敏', dept:'财务部', dish:'宫保鸡丁', weight:'0.20kg', price:'¥14/份', amount:'¥14' }, + { time:'11:45', person:'陈刚', dept:'人事部', dish:'宫保鸡丁', weight:'0.16kg', price:'¥14/份', amount:'¥14' }, + ], + '00026号秤': [ + { time:'11:36', person:'王磊', dept:'运营部', dish:'红烧肉', weight:'0.22kg', price:'¥16/份', amount:'¥16' }, + { time:'11:40', person:'刘芳', dept:'市场部', dish:'红烧肉', weight:'0.18kg', price:'¥16/份', amount:'¥16' }, + { time:'11:44', person:'孙磊', dept:'行政部', dish:'红烧肉', weight:'0.20kg', price:'¥16/份', amount:'¥16' }, + ], + '00027号秤': [ + { time:'12:15', person:'钱芳', dept:'销售部', dish:'番茄炒蛋', weight:'0.16kg', price:'¥8/份', amount:'¥8' }, + { time:'12:20', person:'张伟', dept:'研发部', dish:'番茄炒蛋', weight:'0.14kg', price:'¥8/份', amount:'¥8' }, + ] +}; + +function showPickupDetail(scaleId) { + const rows = pickupData[scaleId] || []; + const totalWeight = rows.reduce((s, r) => s + parseFloat(r.weight), 0).toFixed(2); + const totalAmount = rows.reduce((s, r) => s + parseFloat(r.amount.replace('¥','')), 0); + const totalCount = rows.length; + const summaryHtml = `
+ 取餐人次:${totalCount}人 + 累计重量:${totalWeight}kg + 累计金额:¥${totalAmount} +
`; + const pageSize = 5; + const totalPages = Math.ceil(rows.length / pageSize) || 1; + const buildPage = (page) => { + const start = (page - 1) * pageSize; + const pageRows = rows.slice(start, start + pageSize); + const tbody = pageRows.map(r => `${r.time}${r.person}${r.dept}${r.dish}${r.weight}${r.price}${r.amount}`).join(''); + let pageBtns = ''; + for (let i = 1; i <= totalPages; i++) { + pageBtns += ``; + } + return `${summaryHtml} + + ${tbody} + +
+ 显示 ${pageRows.length} 条,共 ${rows.length} 条 + ${pageBtns} +
`; + }; + window._pickupScaleId = scaleId; + window.pickupGoPage = function(page) { + const body = document.querySelector('.modal-overlay .modal-body'); + if (body) body.innerHTML = buildPage(page); + }; + Modal.open('取餐明细 — ' + scaleId, buildPage(1)); +} + +/* ========== 上餐明细弹窗 ========== */ +const servingData = { + '00022号秤': [ + { time:'06:55', batch:'SC-0428-001', type:'首次上餐', dish:'小米粥', rawWeight:'8.0kg', servWeight:'7.2kg', chef:'王师傅' }, + { time:'08:10', batch:'SC-0428-002', type:'补餐', dish:'小米粥', rawWeight:'6.2kg', servWeight:'5.4kg', chef:'王师傅' }, + ], + '00023号秤': [ + { time:'07:00', batch:'SC-0428-003', type:'首次上餐', dish:'燕麦粥', rawWeight:'5.8kg', servWeight:'5.2kg', chef:'李师傅' }, + { time:'08:20', batch:'SC-0428-004', type:'补餐', dish:'燕麦粥', rawWeight:'3.8kg', servWeight:'3.2kg', chef:'李师傅' }, + ], + '00025号秤': [ + { time:'11:30', batch:'SC-0428-005', type:'首次上餐', dish:'宫保鸡丁', rawWeight:'26.0kg', servWeight:'22.8kg', chef:'张师傅' }, + { time:'12:15', batch:'SC-0428-006', type:'补餐', dish:'宫保鸡丁', rawWeight:'18.0kg', servWeight:'15.4kg', chef:'张师傅' }, + ], + '00026号秤': [ + { time:'11:38', batch:'SC-0428-007', type:'首次上餐', dish:'红烧肉', rawWeight:'28.5kg', servWeight:'24.6kg', chef:'赵师傅' }, + { time:'12:20', batch:'SC-0428-008', type:'补餐', dish:'红烧肉', rawWeight:'20.0kg', servWeight:'18.0kg', chef:'赵师傅' }, + ], + '00027号秤': [ + { time:'12:12', batch:'SC-0428-009', type:'首次上餐', dish:'番茄炒蛋', rawWeight:'12.6kg', servWeight:'11.2kg', chef:'刘师傅' }, + { time:'12:50', batch:'SC-0428-010', type:'补餐', dish:'番茄炒蛋', rawWeight:'6.0kg', servWeight:'5.6kg', chef:'刘师傅' }, + ] +}; + +function showServingDetail(scaleId) { + const rows = servingData[scaleId] || []; + const tbody = rows.map(r => `${r.time}${r.batch}${r.type}${r.dish}${r.rawWeight}${r.servWeight}${r.chef}`).join(''); + const html = ` + + ${tbody} + `; + Modal.open('上餐明细 — ' + scaleId, html); +} + +/* ========== 事件绑定 ========== */ +(function bindDetailLinks() { + const panel = document.querySelectorAll('.tab-panel')[0]; + if (!panel) return; + panel.querySelectorAll('tbody tr').forEach(row => { + const cells = row.querySelectorAll('td'); + if (cells.length < 15) return; + const scaleId = cells[0].textContent.trim(); + // 累计取餐重量 — 第13列(index 12) + const pickupLink = cells[12] && cells[12].querySelector('.link'); + if (pickupLink) pickupLink.addEventListener('click', () => showPickupDetail(scaleId)); + // 累计上餐重量 — 第15列(index 14) + const servingLink = cells[14] && cells[14].querySelector('.link'); + if (servingLink) servingLink.addEventListener('click', () => showServingDetail(scaleId)); + }); +})(); \ No newline at end of file diff --git a/web-admin/nutrition/din-order-meal.html b/web-admin/nutrition/din-order-meal.html index 1800814..86e4e70 100644 --- a/web-admin/nutrition/din-order-meal.html +++ b/web-admin/nutrition/din-order-meal.html @@ -31,7 +31,6 @@ body{font-family:-apple-system,BlinkMacSystemFont,'PingFang SC','Microsoft YaHei .sidebar-item.active{color:#fff;background:var(--primary);} .mi{display:inline-block;width:20px;text-align:center;filter:grayscale(1);opacity:0.65;margin-right:2px;} .sidebar-item.active .mi{opacity:0.9;} -${CSS_RULE} .sidebar-subgroup__header{display:flex;align-items:center;gap:6px;padding:10px 24px;color:rgba(255,255,255,0.65);font-size:var(--font-sm);cursor:pointer;transition:all .15s;user-select:none;} .sidebar-subgroup__header:hover{color:rgba(255,255,255,0.85);background:rgba(255,255,255,0.04);} .sidebar-subgroup__header .arrow{width:10px;height:10px;transition:transform .2s;flex-shrink:0;} @@ -90,6 +89,22 @@ tbody tr:hover{background:#F8FBFF;} .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);} .action-bar{display:flex;align-items:center;gap:8px;margin-bottom:16px;} +/* 弹窗样式 */ +.modal-overlay{position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,0.45);z-index:1000;display:flex;align-items:center;justify-content:center;} +.modal{background:#fff;border-radius:8px;width:780px;max-height:80vh;overflow-y:auto;box-shadow:0 4px 12px rgba(0,0,0,0.15);} +.modal-header{display:flex;align-items:center;justify-content:space-between;padding:16px 24px;border-bottom:1px solid #e8e8e8;} +.modal-title{font-size:16px;font-weight:600;color:#262626;} +.modal-close{font-size:22px;cursor:pointer;color:#8c8c8c;line-height:1;}.modal-close:hover{color:#262626;} +.modal-body{padding:24px;} +.modal-footer{display:flex;justify-content:flex-end;gap:12px;padding:16px 24px;border-top:1px solid #e8e8e8;} +.detail-info{display:grid;grid-template-columns:1fr 1fr 1fr;gap:12px 24px;margin-bottom:20px;padding:16px;background:#FAFAFA;border-radius:var(--radius-md);} +.detail-info__item{display:flex;align-items:center;gap:6px;font-size:var(--font-sm);} +.detail-info__label{color:var(--text-secondary);} +.detail-info__value{color:var(--text-primary);font-weight:500;} +.modal-table{width:100%;border-collapse:collapse;font-size:var(--font-sm);} +.modal-table thead th{background:#FAFAFA;padding:10px 12px;text-align:left;color:var(--text-secondary);font-weight:500;border-bottom:1px solid var(--border);} +.modal-table tbody td{padding:10px 12px;border-bottom:1px solid var(--border);color:var(--text-primary);} +.modal-table tfoot td{padding:10px 12px;font-weight:600;background:#FAFAFA;border-top:2px solid var(--border);} /* 操作列固定右侧 */ thead th:last-child,tbody td.td-actions{position:sticky;right:0;background:#fff;box-shadow:-4px 0 8px rgba(0,0,0,0.04);z-index:2;white-space:nowrap;} thead th:last-child{background:#FAFAFA;} @@ -184,7 +199,7 @@ tbody tr:hover td.td-actions{background:#F8FBFF;}
-
+
个人点餐
@@ -251,7 +266,7 @@ tbody tr:hover td.td-actions{background:#F8FBFF;} -
+
净菜订单
订单号用户餐次目标热量(kcal)点餐内容营养匹配度禁忌过滤营养评分日期操作
@@ -276,11 +291,90 @@ tbody tr:hover td.td-actions{background:#F8FBFF;} + +
订单号用户净菜清单总规格金额取货方式订单状态下单时间操作
+ + + + + + + + + +
+ +
+
+ + + + diff --git a/web-admin/nutrition/din-order-pickup.html b/web-admin/nutrition/din-order-pickup.html index 63f645e..858aae3 100644 --- a/web-admin/nutrition/din-order-pickup.html +++ b/web-admin/nutrition/din-order-pickup.html @@ -35,7 +35,6 @@ body{font-family:-apple-system,BlinkMacSystemFont,'PingFang SC','Microsoft YaHei .sidebar-item.active{color:#fff;background:var(--primary);} .mi{display:inline-block;width:20px;text-align:center;filter:grayscale(1);opacity:0.65;margin-right:2px;} .sidebar-item.active .mi{opacity:0.9;} -${CSS_RULE} .sidebar-subgroup__header{display:flex;align-items:center;gap:6px;padding:10px 24px;color:rgba(255,255,255,0.65);font-size:var(--font-sm);cursor:pointer;transition:all .15s;user-select:none;} .sidebar-subgroup__header:hover{color:rgba(255,255,255,0.85);background:rgba(255,255,255,0.04);} .sidebar-subgroup__header .arrow{width:10px;height:10px;transition:transform .2s;flex-shrink:0;} diff --git a/web-admin/nutrition/din-recipe-mgmt.html b/web-admin/nutrition/din-recipe-mgmt.html index 94bfb0d..5e16c5b 100644 --- a/web-admin/nutrition/din-recipe-mgmt.html +++ b/web-admin/nutrition/din-recipe-mgmt.html @@ -31,7 +31,6 @@ body{font-family:-apple-system,BlinkMacSystemFont,'PingFang SC','Microsoft YaHei .sidebar-item.active{color:#fff;background:var(--primary);} .mi{display:inline-block;width:20px;text-align:center;filter:grayscale(1);opacity:0.65;margin-right:2px;} .sidebar-item.active .mi{opacity:0.9;} -${CSS_RULE} .sidebar-subgroup__header{display:flex;align-items:center;gap:6px;padding:10px 24px;color:rgba(255,255,255,0.65);font-size:var(--font-sm);cursor:pointer;transition:all .15s;user-select:none;} .sidebar-subgroup__header:hover{color:rgba(255,255,255,0.85);background:rgba(255,255,255,0.04);} .sidebar-subgroup__header .arrow{width:10px;height:10px;transition:transform .2s;flex-shrink:0;} @@ -83,22 +82,6 @@ tbody tr:hover{background:#F8FBFF;} .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);} -.modal-overlay{position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,0.45);z-index:1000;display:flex;align-items:center;justify-content:center;} -.modal{background:#fff;border-radius:8px;width:680px;max-height:80vh;overflow-y:auto;box-shadow:0 4px 12px rgba(0,0,0,0.15);} -.modal-header{display:flex;align-items:center;justify-content:space-between;padding:16px 24px;border-bottom:1px solid #e8e8e8;} -.modal-title{font-size:16px;font-weight:600;color:#262626;} -.modal-close{font-size:22px;cursor:pointer;color:#8c8c8c;line-height:1;} -.modal-close:hover{color:#262626;} -.modal-body{padding:24px;} -.modal-footer{display:flex;justify-content:flex-end;gap:12px;padding:16px 24px;border-top:1px solid #e8e8e8;} -.form-grid{display:grid;grid-template-columns:1fr 1fr;gap:16px;} -.form-item{display:flex;flex-direction:column;gap:4px;} -.form-item.full{grid-column:1/-1;} -.form-item label{font-size:13px;color:#8c8c8c;} -.form-item label .required{color:#ff4d4f;margin-left:2px;} -.form-item input,.form-item select,.form-item textarea{height:36px;padding:0 12px;border:1px solid #e8e8e8;border-radius:4px;font-size:13px;outline:none;} -.form-item input:focus,.form-item select:focus,.form-item textarea:focus{border-color:#1890FF;} -.form-item textarea{height:80px;padding:8px 12px;resize:vertical;} .action-bar{display:flex;align-items:center;gap:8px;margin-bottom:16px;} /* 操作列固定右侧 */ thead th:last-child,tbody td.td-actions{position:sticky;right:0;background:#fff;box-shadow:-4px 0 8px rgba(0,0,0,0.04);z-index:2;white-space:nowrap;} @@ -182,7 +165,7 @@ tbody tr:hover td.td-actions{background:#F8FBFF;}
-
+
食谱管理
@@ -209,36 +192,7 @@ tbody tr:hover td.td-actions{background:#F8FBFF;}
- - - diff --git a/web-admin/nutrition/din-terminal.html b/web-admin/nutrition/din-terminal.html index dcd76fd..bb7bcb8 100644 --- a/web-admin/nutrition/din-terminal.html +++ b/web-admin/nutrition/din-terminal.html @@ -32,7 +32,6 @@ body{font-family:-apple-system,BlinkMacSystemFont,'PingFang SC','Microsoft YaHei .sidebar-item.active{color:#fff;background:var(--primary);} .mi{display:inline-block;width:20px;text-align:center;filter:grayscale(1);opacity:0.65;margin-right:2px;} .sidebar-item.active .mi{opacity:0.9;} -${CSS_RULE} .sidebar-subgroup__header{display:flex;align-items:center;gap:6px;padding:10px 24px;color:rgba(255,255,255,0.65);font-size:var(--font-sm);cursor:pointer;transition:all .15s;user-select:none;} .sidebar-subgroup__header:hover{color:rgba(255,255,255,0.85);background:rgba(255,255,255,0.04);} .sidebar-subgroup__header .arrow{width:10px;height:10px;transition:transform .2s;flex-shrink:0;} @@ -109,6 +108,33 @@ tbody tr:hover{background:#F8FBFF;} .stat-card__value{font-size:var(--font-xl);font-weight:700;color:var(--text-primary);} .stat-card__label{font-size:var(--font-sm);color:var(--text-secondary);} .action-bar{display:flex;align-items:center;gap:8px;margin-bottom:16px;} +/* 动态弹窗基础 */ +.dyn-overlay{position:fixed;inset:0;background:rgba(0,0,0,0.45);z-index:1010;display:flex;align-items:center;justify-content:center;opacity:0;transition:opacity .25s;} +.dyn-overlay.show{opacity:1;} +.dyn-modal{background:#fff;border-radius:var(--radius-lg);max-height:80vh;display:flex;flex-direction:column;transform:translateY(30px);transition:transform .25s;box-shadow:0 12px 40px rgba(0,0,0,0.18);} +.dyn-overlay.show .dyn-modal{transform:translateY(0);} +.dyn-modal__header{display:flex;align-items:center;justify-content:space-between;padding:18px 24px;border-bottom:1px solid var(--border);} +.dyn-modal__header h3{font-size:var(--font-lg);font-weight:600;margin:0;} +.dyn-modal__close{width:32px;height:32px;border:none;background:none;cursor:pointer;font-size:20px;color:#999;display:flex;align-items:center;justify-content:center;border-radius:var(--radius-sm);} +.dyn-modal__close:hover{background:#f5f5f5;color:#333;} +.dyn-modal__body{padding:20px 24px;overflow-y:auto;flex:1;} +.dyn-modal__footer{display:flex;justify-content:flex-end;gap:12px;padding:16px 24px;border-top:1px solid var(--border);} +/* 故障记录弹窗 */ +.fault-modal{width:760px;} +.fault-dev-info{display:flex;gap:24px;margin-bottom:16px;font-size:var(--font-sm);color:var(--text-secondary);flex-wrap:wrap;} +.fault-dev-info strong{color:var(--text-primary);margin-left:4px;} +.fault-table{width:100%;border-collapse:collapse;} +.fault-table thead th{background:#FAFAFA;padding:10px 16px;text-align:left;font-size:var(--font-sm);color:var(--text-secondary);font-weight:500;border-bottom:1px solid var(--border);} +.fault-table tbody td{padding:12px 16px;font-size:var(--font-sm);color:var(--text-primary);border-bottom:1px solid var(--border);} +.fault-table tbody tr:last-child td{border-bottom:none;} +.fault-table tbody tr:hover{background:#F8FBFF;} +.fault-empty{text-align:center;padding:40px 0;color:var(--text-placeholder);font-size:var(--font-sm);} +/* 确认弹窗 */ +.confirm-modal{width:420px;} +.confirm-icon{display:flex;align-items:center;justify-content:center;margin-bottom:16px;} +.confirm-icon svg{width:48px;height:48px;} +.confirm-msg{text-align:center;font-size:var(--font-base);color:var(--text-primary);margin-bottom:8px;font-weight:500;} +.confirm-sub{text-align:center;font-size:var(--font-sm);color:var(--text-secondary);} @@ -137,40 +163,40 @@ tbody tr:hover{background:#F8FBFF;} @@ -258,6 +284,117 @@ function closeModal(){document.getElementById('modalOverlay').style.display='non document.getElementById('modalOverlay').addEventListener('click',function(e){if(e.target===this)closeModal();}); function toggleSubgroup(header){header.parentElement.classList.toggle('open');} (function(){var active=document.querySelector('.sidebar-item.active');if(!active)return;var sub=active.closest('.sidebar-subgroup');if(sub)sub.classList.add('open');})(); + +/* ===== 动态弹窗工具 ===== */ +const DynModal={ + open(title,bodyHtml,footerHtml,extraClass){ + const overlay=document.createElement('div'); + overlay.className='dyn-overlay'; + overlay.innerHTML=`
+

${title}

+
${bodyHtml}
+ +
`; + document.body.appendChild(overlay); + overlay.addEventListener('click',e=>{if(e.target===overlay)DynModal.close();}); + requestAnimationFrame(()=>overlay.classList.add('show')); + }, + close(){ + const o=document.querySelector('.dyn-overlay'); + if(!o)return; + o.classList.remove('show'); + setTimeout(()=>o.remove(),250); + } +}; + +/* ===== 故障记录数据(模拟) ===== */ +const faultData={ + 'DEV-001':[ + {time:'2026-03-18 14:22',type:'触屏无响应',level:'中',status:'已修复',handler:'张运维'}, + {time:'2025-12-05 09:10',type:'网络断连',level:'低',status:'已修复',handler:'李运维'} + ], + 'DEV-002':[], + 'DEV-003':[ + {time:'2026-04-08 16:35',type:'显示花屏',level:'高',status:'已修复',handler:'张运维'} + ], + 'DEV-004':[ + {time:'2026-04-22 09:18',type:'主板故障',level:'高',status:'维修中',handler:'李运维'}, + {time:'2026-02-14 11:00',type:'电源异常',level:'中',status:'已修复',handler:'王运维'}, + {time:'2025-11-20 08:45',type:'网络断连',level:'低',status:'已修复',handler:'李运维'} + ], + 'DEV-005':[], + 'DEV-006':[ + {time:'2026-04-20 10:30',type:'传感器异常',level:'高',status:'维修中',handler:'张运维'} + ] +}; + +/* ===== 故障记录弹窗 ===== */ +function showFaultLog(row){ + const cells=row.querySelectorAll('td'); + const devCode=cells[0].textContent.trim(); + const devName=cells[2].textContent.trim(); + const devType=cells[3].textContent.trim(); + const records=faultData[devCode]||[]; + + let tableHtml=''; + if(records.length===0){ + tableHtml='
暂无故障记录
'; + }else{ + const levelTag=l=>l==='高'?'tag-red':l==='中'?'tag-orange':'tag-green'; + const statusTag=s=>s==='维修中'?'tag-orange':s==='已修复'?'tag-green':'tag-gray'; + const rows=records.map(r=>` + ${r.time} + ${r.type} + ${r.level} + ${r.status} + ${r.handler} + `).join(''); + tableHtml=` + + ${rows} +
时间故障类型等级状态处理人
`; + } + + const html=` +
+ 设备编号:${devCode} + 设备名称:${devName} + 设备类型:${devType} + 故障记录数:${records.length} +
+ ${tableHtml}`; + + DynModal.open('故障记录 — '+devName,html,'','fault-modal'); +} + +/* ===== 远程重启确认弹窗 ===== */ +function showRebootConfirm(row){ + const cells=row.querySelectorAll('td'); + const devName=cells[2].textContent.trim(); + const devCode=cells[0].textContent.trim(); + + const html=` +
+ +
+
是否要强制重启该设备?
+
${devCode} · ${devName}
`; + + const footer=``; + DynModal.open('远程重启确认',html,footer,'confirm-modal'); +} + +/* ===== 事件绑定 ===== */ +document.querySelectorAll('tbody tr').forEach(row=>{ + row.querySelectorAll('.td-actions .link').forEach(link=>{ + if(link.textContent.includes('故障记录')){ + link.addEventListener('click',()=>showFaultLog(row)); + } + if(link.textContent.includes('远程重启')){ + link.addEventListener('click',()=>showRebootConfirm(row)); + } + }); +}); \ No newline at end of file diff --git a/web-admin/nutrition/din-user-mgmt-dialog.html b/web-admin/nutrition/din-user-mgmt-dialog.html deleted file mode 100644 index 01d7f83..0000000 --- a/web-admin/nutrition/din-user-mgmt-dialog.html +++ /dev/null @@ -1,172 +0,0 @@ - - - - - -营养管理 - 用户管理弹窗 | 健康长庆原型 - - - - - -
-
-
用户管理
- -
- - -
-
开通会员
-
新增等级
-
- - -
-
-
-
- - -
-
- - -
-
-
-
- - -
-
- - -
-
-
- - -
-
- -
- - -
-
-
-
- - -
-
- - -
-
-
-
- - -
-
- - -
-
-
-
- - -
-
-
-
- - -
-
- -
-
- - - - \ No newline at end of file diff --git a/web-admin/nutrition/din-user-mgmt.html b/web-admin/nutrition/din-user-mgmt.html index 94c0392..86548eb 100644 --- a/web-admin/nutrition/din-user-mgmt.html +++ b/web-admin/nutrition/din-user-mgmt.html @@ -35,7 +35,6 @@ body{font-family:-apple-system,BlinkMacSystemFont,'PingFang SC','Microsoft YaHei .sidebar-item.active{color:#fff;background:var(--primary);} .mi{display:inline-block;width:20px;text-align:center;filter:grayscale(1);opacity:0.65;margin-right:2px;} .sidebar-item.active .mi{opacity:0.9;} -${CSS_RULE} .sidebar-subgroup__header{display:flex;align-items:center;gap:6px;padding:10px 24px;color:rgba(255,255,255,0.65);font-size:var(--font-sm);cursor:pointer;transition:all .15s;user-select:none;} .sidebar-subgroup__header:hover{color:rgba(255,255,255,0.85);background:rgba(255,255,255,0.04);} .sidebar-subgroup__header .arrow{width:10px;height:10px;transition:transform .2s;flex-shrink:0;} @@ -105,6 +104,55 @@ tbody tr:hover{background:#F8FBFF;} thead th:last-child,tbody td.td-actions{position:sticky;right:0;background:#fff;box-shadow:-4px 0 8px rgba(0,0,0,0.04);z-index:2;white-space:nowrap;} thead th:last-child{background:#FAFAFA;} tbody tr:hover td.td-actions{background:#F8FBFF;} + +/* 弹窗样式 */ +.modal-overlay{position:fixed;top:0;left:0;right:0;bottom:0;background:rgba(0,0,0,.45);z-index:1000;display:flex;align-items:center;justify-content:center;animation:modalFadeIn .2s ease;} +.modal-overlay.closing{animation:modalFadeOut .2s ease forwards;} +@keyframes modalFadeIn{from{opacity:0}to{opacity:1}} +@keyframes modalFadeOut{from{opacity:1}to{opacity:0}} +@keyframes modalSlideIn{from{transform:translateY(-20px);opacity:0}to{transform:translateY(0);opacity:1}} +@keyframes modalSlideOut{from{transform:translateY(0);opacity:1}to{transform:translateY(-20px);opacity:0}} +.modal{background:#fff;border-radius:8px;width:900px;max-width:90vw;max-height:85vh;display:flex;flex-direction:column;box-shadow:0 12px 48px rgba(0,0,0,.15);animation:modalSlideIn .25s ease;} +.modal-overlay.closing .modal{animation:modalSlideOut .2s ease forwards;} +.modal-header{display:flex;align-items:center;justify-content:space-between;padding:16px 24px;border-bottom:1px solid var(--border);} +.modal-title{font-size:var(--font-lg);font-weight:600;color:var(--text-primary);} +.modal-close{width:32px;height:32px;border:none;background:none;font-size:20px;cursor:pointer;border-radius:var(--radius-sm);color:var(--text-secondary);display:flex;align-items:center;justify-content:center;} +.modal-close:hover{background:#f5f5f5;color:var(--text-primary);} +.modal-body{padding:24px;overflow-y:auto;flex:1;} +.modal-footer{display:flex;justify-content:flex-end;gap:12px;padding:16px 24px;border-top:1px solid var(--border);} + +/* 十维档案 Tab */ +.profile-tabs{display:flex;gap:0;border-bottom:1px solid var(--border);margin-bottom:20px;overflow-x:auto;} +.profile-tab{padding:10px 16px;font-size:var(--font-sm);color:var(--text-secondary);cursor:pointer;border-bottom:2px solid transparent;white-space:nowrap;transition:all .2s;} +.profile-tab:hover{color:var(--primary);} +.profile-tab.active{color:var(--primary);border-bottom-color:var(--primary);font-weight:500;} +.profile-panel{display:none;} +.profile-panel.active{display:block;} +.profile-grid{display:grid;grid-template-columns:repeat(2,1fr);gap:12px 24px;} +.profile-field{display:flex;align-items:baseline;gap:8px;font-size:var(--font-sm);padding:8px 0;border-bottom:1px dashed #f0f0f0;} +.profile-field__label{color:var(--text-secondary);min-width:80px;flex-shrink:0;} +.profile-field__value{color:var(--text-primary);font-weight:500;} +.profile-summary{display:flex;align-items:center;gap:16px;padding:16px;background:#f8fafc;border-radius:var(--radius-md);margin-bottom:20px;} +.profile-summary__avatar{width:56px;height:56px;border-radius:50%;background:var(--primary);display:flex;align-items:center;justify-content:center;color:#fff;font-size:22px;font-weight:600;} +.profile-summary__info{display:flex;flex-direction:column;gap:4px;} +.profile-summary__name{font-size:var(--font-base);font-weight:600;color:var(--text-primary);} +.profile-summary__meta{font-size:var(--font-sm);color:var(--text-secondary);} + +/* 推荐食谱弹窗 */ +.recipe-modal{width:720px;} +.recipe-banner{display:flex;align-items:center;gap:8px;padding:10px 16px;background:var(--primary-light);border-radius:var(--radius-sm);margin-bottom:20px;font-size:var(--font-sm);color:var(--primary);} +.recipe-banner svg{flex-shrink:0;} +.recipe-section{margin-bottom:16px;} +.recipe-section__title{font-size:var(--font-sm);font-weight:600;color:var(--text-primary);margin-bottom:8px;padding-left:4px;} +.recipe-section table{width:100%;border-collapse:collapse;font-size:var(--font-sm);} +.recipe-section thead th{background:#FAFAFA;padding:8px 12px;text-align:left;color:var(--text-secondary);font-weight:500;border-bottom:1px solid var(--border);} +.recipe-section tbody td{padding:8px 12px;border-bottom:1px solid var(--border);color:var(--text-primary);} +.recipe-section tbody td.td-cal{color:var(--primary);font-weight:500;} +.recipe-section tbody td.td-safe{color:var(--success);} +.recipe-summary{display:flex;align-items:center;gap:24px;padding:12px 16px;background:#FAFAFA;border-radius:var(--radius-sm);margin-top:16px;font-size:var(--font-sm);} +.recipe-summary__item{display:flex;align-items:center;gap:4px;} +.recipe-summary__label{color:var(--text-secondary);} +.recipe-summary__value{font-weight:600;color:var(--text-primary);} @@ -282,7 +330,7 @@ tbody tr:hover td.td-actions{background:#F8FBFF;}
- ➕ 开通会员 + @@ -326,7 +374,7 @@ tbody tr:hover td.td-actions{background:#F8FBFF;}
- ➕ 新增等级 +
@@ -363,6 +411,150 @@ function switchTab(idx){ document.querySelectorAll('.page-tab').forEach(function(t,i){t.classList.toggle('active',i===idx);}); document.querySelectorAll('.tab-panel').forEach(function(p,i){p.classList.toggle('active',i===idx);}); } + +/* ========== 弹窗基础 ========== */ +const Modal = { + open(title, bodyHtml, extraClass, footerHtml) { + this.close(); + const overlay = document.createElement('div'); + overlay.className = 'modal-overlay'; + overlay.innerHTML = ``; + overlay.addEventListener('click', e => { if (e.target === overlay) Modal.close(); }); + document.body.appendChild(overlay); + }, + close() { + const o = document.querySelector('.modal-overlay'); + if (!o) return; + o.classList.add('closing'); + setTimeout(() => o.remove(), 200); + } +}; + +/* ========== 十维档案 ========== */ +const userProfiles = { + '张伟': { dept:'研发部', age:38, gender:'男', height:'175cm', weight:'72kg', bmi:'22.9', activity:'中度活动', + disease:'无', chronic:'无', medicine:'无', family:'高血压(父)', + examDate:'2026-03-15', bp:'125/80', glucose:'5.2', lipid:'正常', uric:'380', liver:'正常', kidney:'正常', + taste:'偏辣', region:'川菜、湘菜', taboo:'无', allergy:'花生', + exercise:'6000步/日', weightTrend:'稳定', bodyFat:'18%', heartRate:'68', sleep:'7.5h', stress:'低', source:'智能手环', + meals30:'58次', hotDish:'宫保鸡丁、番茄牛腩', avgCal:'680kcal', nutriRate:'88%', + favDish:'宫保鸡丁、清炒西兰花', recDish:'三文鱼沙拉', avoidDish:'油炸花生', topRate:'番茄牛腩(4.8)', repurchase:'宫保鸡丁', + hometown:'四川成都', momTag:'麻辣鲜香', momList:'回锅肉、麻婆豆腐', memory:'妈妈的回锅肉', recTry:'水煮鱼', + modelVer:'v2.3', modelTime:'2026-04-20', recCal:'2100kcal', nutriFocus:'蛋白质+膳食纤维', risk:'无', tags:'运动达人、川菜爱好者', confidence:'92%' }, + '李娜': { dept:'市场部', age:34, gender:'女', height:'163cm', weight:'52kg', bmi:'19.8', activity:'轻度活动', + disease:'无', chronic:'无', medicine:'无', family:'糖尿病(母)', + examDate:'2026-02-20', bp:'110/70', glucose:'4.8', lipid:'正常', uric:'290', liver:'正常', kidney:'正常', + taste:'清淡', region:'粤菜、日料', taboo:'无', allergy:'海鲜(虾蟹)', + exercise:'4000步/日', weightTrend:'稳定', bodyFat:'22%', heartRate:'72', sleep:'7h', stress:'中', source:'手机计步', + meals30:'52次', hotDish:'蒸鱼、蔬菜沙拉', avgCal:'520kcal', nutriRate:'92%', + favDish:'清蒸鲈鱼、藜麦沙拉', recDish:'牛油果吐司', avoidDish:'麻辣火锅', topRate:'藜麦沙拉(4.9)', repurchase:'清蒸鲈鱼', + hometown:'广东广州', momTag:'鲜甜清润', momList:'老火靓汤、白切鸡', memory:'周末的煲汤', recTry:'椰子鸡', + modelVer:'v2.3', modelTime:'2026-04-18', recCal:'1650kcal', nutriFocus:'钙+铁+维生素D', risk:'注意糖摄入', tags:'轻食主义、养生达人', confidence:'95%' } +}; +const defaultProfile = { dept:'—', age:30, gender:'—', height:'170cm', weight:'65kg', bmi:'22.5', activity:'中等', + disease:'无', chronic:'无', medicine:'无', family:'无', + examDate:'2026-01-10', bp:'120/78', glucose:'5.0', lipid:'正常', uric:'350', liver:'正常', kidney:'正常', + taste:'适中', region:'不限', taboo:'无', allergy:'无', + exercise:'5000步/日', weightTrend:'稳定', bodyFat:'20%', heartRate:'70', sleep:'7h', stress:'低', source:'手动录入', + meals30:'45次', hotDish:'家常菜', avgCal:'600kcal', nutriRate:'78%', + favDish:'红烧肉、西红柿炒蛋', recDish:'杂粮饭套餐', avoidDish:'无', topRate:'红烧肉(4.5)', repurchase:'西红柿炒蛋', + hometown:'—', momTag:'家常味', momList:'红烧肉', memory:'—', recTry:'—', + modelVer:'v2.3', modelTime:'2026-04-15', recCal:'1900kcal', nutriFocus:'均衡', risk:'无', tags:'普通用户', confidence:'80%' }; + +const tabDefs = [ + { key:'basic', label:'静态基础' },{ key:'disease', label:'疾病信息' },{ key:'physical', label:'体检信息' }, + { key:'taste', label:'口味偏好' },{ key:'taboo', label:'禁忌关联' },{ key:'dynamic', label:'动态生理' }, + { key:'meal', label:'历史用餐' },{ key:'dish', label:'菜品偏好' },{ key:'mom', label:'妈妈味道' },{ key:'model', label:'个性模型' } +]; + +function buildProfileHTML(name, p) { + const panels = { + basic: `
姓名${name}
部门${p.dept}
年龄${p.age}岁
性别${p.gender}
身高${p.height}
体重${p.weight}
BMI${p.bmi}
活动水平${p.activity}
`, + disease: `
疾病史${p.disease}
慢病分级${p.chronic}
用药情况${p.medicine}
家族病史${p.family}
`, + physical: `
体检日期${p.examDate}
血压${p.bp} mmHg
空腹血糖${p.glucose} mmol/L
血脂${p.lipid}
尿酸${p.uric} μmol/L
肝功能${p.liver}
肾功能${p.kidney}
`, + taste: `
口味偏好${p.taste}
地域菜系${p.region}
`, + taboo: `
饮食禁忌${p.taboo}
过敏原${p.allergy}
`, + dynamic: `
日均运动量${p.exercise}
体重趋势${p.weightTrend}
体脂率${p.bodyFat}
静息心率${p.heartRate} bpm
平均睡眠${p.sleep}
压力指数${p.stress}
数据来源${p.source}
`, + meal: `
近30日就餐${p.meals30}
常点菜品${p.hotDish}
平均热量${p.avgCal}
营养达标率${p.nutriRate}
`, + dish: `
常点菜品${p.favDish}
系统推荐${p.recDish}
忌口菜品${p.avoidDish}
评分最高${p.topRate}
复购冠军${p.repurchase}
`, + mom: `
家乡${p.hometown}
妈妈味道标签${p.momTag}
思乡菜清单${p.momList}
关联记忆${p.memory}
推荐尝试${p.recTry}
`, + model: `
模型版本${p.modelVer}
生成时间${p.modelTime}
推荐热量${p.recCal}
营养侧重${p.nutriFocus}
风险预警${p.risk}
个性标签${p.tags}
模型置信度${p.confidence}
` + }; + const tabs = tabDefs.map((t, i) => `
${t.label}
`).join(''); + const panelsHtml = tabDefs.map((t, i) => `
${panels[t.key]}
`).join(''); + const summary = `
${name[0]}
${name}
${p.dept} · ${p.gender} · ${p.age}岁 · BMI ${p.bmi}
`; + return summary + `
${tabs}
${panelsHtml}`; +} + +function switchProfileTab(el, key) { + el.parentElement.querySelectorAll('.profile-tab').forEach(t => t.classList.remove('active')); + el.classList.add('active'); + el.closest('.modal-body').querySelectorAll('.profile-panel').forEach(p => p.classList.remove('active')); + el.closest('.modal-body').querySelector(`[data-panel="${key}"]`).classList.add('active'); +} + +function showUserProfile(name) { + const p = userProfiles[name] || defaultProfile; + Modal.open('用户十维档案 — ' + name, buildProfileHTML(name, p)); +} + +/* ========== 推荐食谱弹窗 ========== */ +function showRecipeModal(name) { + const p = userProfiles[name] || defaultProfile; + const html = `
+
+ +
+
+ + 基于十维档案数据自动生成:BMI ${p.bmi} / 活动水平 ${p.activity} / 每日目标 ${p.recCal} +
+
+
早餐
+ + + + +
菜品热量(kcal)口味匹配禁忌过滤
小米粥186匹配安全
凉拌黄瓜48匹配安全
+
+
+
午餐
+ + + + + +
菜品热量(kcal)口味匹配禁忌过滤
米饭232匹配安全
清蒸鱼136匹配安全
炒西兰花50匹配安全
+
+
+
晚餐
+ + + + + +
菜品热量(kcal)口味匹配禁忌过滤
杂粮饭162匹配安全
番茄炒蛋142匹配安全
紫菜汤38匹配安全
+
+
+
总热量:994 kcal
+
目标热量:${p.recCal}
+
匹配度:44%
+
`; + const footer = ``; + Modal.open(name + ' — 个人推荐食谱', html, 'recipe-modal', footer); +} + +/* ========== 事件绑定 ========== */ +document.querySelectorAll('.tab-panel')[0].querySelectorAll('tbody tr').forEach(row => { + const links = row.querySelectorAll('.td-actions .link'); + const nameCell = row.querySelector('td:first-child'); + if (links[0] && nameCell) links[0].addEventListener('click', () => showUserProfile(nameCell.textContent)); + if (links[1] && nameCell) links[1].addEventListener('click', () => showRecipeModal(nameCell.textContent)); +}); \ No newline at end of file