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;}
-
-
-
-
+
-
+
-
-
-
+
+
共 156 条脏数据
+
+
-
- | 记录ID |
- 来源模块 |
- 数据类型 |
- 问题描述 |
- 影响范围 |
- 发现时间 |
- 处理状态 |
- 操作 |
+ 业务模块 |
+ 异常类型 |
+ 异常描述 |
+ 异常检测时间 |
+ 表名 |
+ 字段名 |
+ 编号 |
+ 异常值 |
+ 数据产生时间 |
- | DIRTY-001 |
- 营养用餐 |
- 格式错误 |
- 员工EMP0234营养摄入值为负数 |
- 1条记录 |
- 2026-04-15 08:30 |
- 待处理 |
- 查看 修正 |
+ 食谱管理 |
+ 数据缺失 |
+ 热量值字段为空,无法参与营养计算 |
+ 2026-05-14 09:23 |
+ t_recipe_nutrition |
+ calorie |
+ RCP-20260514-0087 |
+ NULL |
+ 2026-05-14 08:10 |
+
+
+ | 订餐管理 |
+ 格式错误 |
+ 订餐日期格式非法,无法解析 |
+ 2026-05-14 09:15 |
+ t_order_meal |
+ order_date |
+ ORD-20260514-0342 |
+ 2026/13/45 |
+ 2026-05-14 07:55 |
+
+
+ | 用户档案 |
+ 逻辑矛盾 |
+ 员工年龄为负数,BMI值超出合理范围 |
+ 2026-05-14 08:50 |
+ t_employee_health |
+ age / bmi |
+ EMP-00156 |
+ age=-5, bmi=999 |
+ 2026-05-13 18:30 |
+
+
+ | 营养分析 |
+ 重复数据 |
+ 同一用户同日存在3条重复营养分析记录 |
+ 2026-05-13 17:30 |
+ t_nutri_analysis |
+ user_id |
+ NA-20260513-0218 |
+ 3条重复 |
+ 2026-05-13 12:00 |
+
+
+ | 食材库存 |
+ 范围越界 |
+ 库存数量为负值,疑似出库数据异常 |
+ 2026-05-13 16:45 |
+ t_material_stock |
+ stock_qty |
+ MAT-00523 |
+ -500 kg |
+ 2026-05-13 15:20 |
+
+
+ | 健康生产 |
+ 格式错误 |
+ 生产批次号含非法字符,无法关联溯源 |
+ 2026-05-13 15:10 |
+ t_prod_batch |
+ batch_no |
+ PRD-20260513-0091 |
+ B@TCH#001! |
+ 2026-05-13 14:00 |
- | DIRTY-002 |
卫生供应 |
- 缺失值 |
- 采购单食材重量字段为空 |
- 1条记录 |
- 2026-04-14 16:20 |
- 已修正 |
- 查看 修正 |
+ 数据缺失 |
+ 供应商资质证书编号为空 |
+ 2026-05-13 14:20 |
+ t_supplier_cert |
+ cert_no |
+ SUP-00078 |
+ NULL |
+ 2026-05-13 10:30 |
- | DIRTY-003 |
- 人员健康 |
- 重复数据 |
- 员工EMP0156今日就餐记录重复录入 |
- 2条记录 |
- 2026-04-15 12:05 |
- 已忽略 |
- 查看 修正 |
+ 订餐管理 |
+ 范围越界 |
+ 单次订餐份数超出系统上限 |
+ 2026-05-13 11:05 |
+ t_order_meal |
+ quantity |
+ ORD-20260513-0198 |
+ 99999 |
+ 2026-05-13 10:45 |
+
+
+ | 食谱管理 |
+ 关联缺失 |
+ 食谱引用的食材ID在食材库中不存在 |
+ 2026-05-12 17:30 |
+ t_recipe_item |
+ material_id |
+ RCP-20260512-0045 |
+ MAT-99999 |
+ 2026-05-12 16:00 |
+
+
+ | 用户档案 |
+ 重复数据 |
+ 员工健康档案存在重复建档记录 |
+ 2026-05-12 15:40 |
+ t_employee_health |
+ emp_id |
+ EMP-00234 |
+ 2条重复 |
+ 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;}
-
-
-
+
+
+
+
+
+
+
+
@@ -146,38 +144,29 @@ tbody tr:hover td.td-actions{background:#F8FBFF;}
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+ 至
+
-
+
+
共 89 条异常记录
+
+
-
@@ -194,46 +183,129 @@ tbody tr:hover td.td-actions{background:#F8FBFF;}
- | ERR-001 |
- 营养值异常 |
+ ERR-2026-001 |
+ 营养值异常 |
营养计算 |
员工EMP0234午餐热量计算结果为0kcal |
高 |
v2.3.1 |
- 2026-04-15 12:30 |
- 查看 溯源 |
+ 2026-05-14 12:30 |
+ 详情 |
- | ERR-002 |
- 推荐结果为空 |
+ ERR-2026-002 |
+ 推荐结果为空 |
菜品推荐 |
员工EMP0456个性化推荐返回空列表 |
中 |
v1.8.0 |
- 2026-04-15 11:45 |
- 查看 溯源 |
+ 2026-05-14 11:45 |
+ 详情 |
- | ERR-003 |
- 营养值超范围 |
+ ERR-2026-003 |
+ 营养值超范围 |
营养计算 |
某菜品钠含量计算结果为99999mg |
高 |
v2.3.1 |
- 2026-04-15 10:20 |
- 查看 溯源 |
+ 2026-05-14 10:20 |
+ 详情 |
+
+
+ | ERR-2026-004 |
+ 算法超时 |
+ 营养计算 |
+ 批量营养分析任务执行超时(>30s) |
+ 中 |
+ v2.3.1 |
+ 2026-05-13 16:40 |
+ 详情 |
+
+
+ | ERR-2026-005 |
+ 推荐结果为空 |
+ 菜品推荐 |
+ 糖尿病患者推荐食谱未返回低GI菜品 |
+ 高 |
+ v1.8.0 |
+ 2026-05-13 14:15 |
+ 详情 |
+
+
+ | ERR-2026-006 |
+ 模型输出异常 |
+ 智能推荐 |
+ LLM返回JSON格式解析失败 |
+ 中 |
+ v3.0.2 |
+ 2026-05-13 11:30 |
+ 详情 |
+
+
+ | ERR-2026-007 |
+ 营养值异常 |
+ 营养计算 |
+ 维生素A摄入量计算结果为负值 |
+ 高 |
+ v2.3.1 |
+ 2026-05-12 15:50 |
+ 详情 |
+
+
+ | ERR-2026-008 |
+ 营养值超范围 |
+ 营养计算 |
+ 单餐蛋白质含量超出日推荐量300% |
+ 中 |
+ v2.3.1 |
+ 2026-05-12 12:10 |
+ 详情 |
+
+
+ | ERR-2026-009 |
+ 模型输出异常 |
+ 智能推荐 |
+ 小模型推理服务返回500错误 |
+ 高 |
+ v3.0.2 |
+ 2026-05-11 09:25 |
+ 详情 |
+
+
+ | ERR-2026-010 |
+ 推荐结果为空 |
+ 菜品推荐 |
+ 过敏源过滤后可推荐菜品为零 |
+ 中 |
+ v1.8.0 |
+ 2026-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;}
-
-
-
| 人群类型 | 热量范围(kcal) | 蛋白质比例(%) | 脂肪比例(%) | 碳水比例(%) | 钙(mg) | 铁(mg) | 维生素C(mg) | 膳食纤维(g) | 每日饮水量(mL) | 操作 |
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;}
-
-
-
- | 用户编号/姓名 | 定制目标类型 | 每日热量(kcal) | 蛋白质目标(g) | 脂肪目标(g) | 碳水目标(g) | 特殊限制项 | 制定营养师 | 生效日期 | 复评日期 | 操作 |
+ | 姓名 | 用户编号 | 所属单位 | 所属部门 | 定制目标类型 | 每日热量(kcal) | 蛋白质目标(g) | 脂肪目标(g) | 碳水目标(g) | 特殊限制项 | 制定营养师 | 生效日期 | 复评日期 | 操作 |
- | VIP001/张明 | 减重 | 1650 | 95 | 45 | 170 | 禁高糖饮料 | 营养师李明 | 2026-04-01 | 2026-05-01 | 编辑 |
- | VIP002/刘芳 | 控糖(糖尿病) | 1750 | 88 | 50 | 160 | 低GI优先 | 营养师王芳 | 2026-03-20 | 2026-04-25 | 编辑 |
- | VIP003/陈伟 | 增肌 | 2450 | 140 | 68 | 280 | 增加优质蛋白 | 营养师李明 | 2026-04-10 | 2026-05-10 | 编辑 |
+ | 张明 | VIP001 | 长庆油田 | 采油一厂 | 减重 | 1650 | 95 | 45 | 170 | 禁高糖饮料 | 营养师李明 | 2026-04-01 | 2026-05-01 | 详情 编辑 删除 |
+ | 刘芳 | VIP002 | 长庆油田 | 采气二厂 | 控糖(糖尿病) | 1750 | 88 | 50 | 160 | 低GI优先 | 营养师王芳 | 2026-03-20 | 2026-04-25 | 详情 编辑 删除 |
+ | 陈伟 | VIP003 | 长庆油田 | 机械制造公司 | 增肌 | 2450 | 140 | 68 | 280 | 增加优质蛋白 | 营养师李明 | 2026-04-10 | 2026-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}
+
+
+
+
损耗分析
+
+
采购总额${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=`
+
+
+ | 食材名称 | 用量/份 | 采购单价 | 成本(元/份) |
+ ${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));
+ }
+ });
+ });
+});