diff --git a/web-admin/nutrition/din-order-pickup.html b/web-admin/nutrition/din-order-pickup.html
index 09d6f49..94df2cf 100644
--- a/web-admin/nutrition/din-order-pickup.html
+++ b/web-admin/nutrition/din-order-pickup.html
@@ -859,15 +859,14 @@ function buildRawDataModal(data) {
const statusTag = recStatus === '已识别' ? '已识别' : '未识别';
const samples = [
- { t: minusSeconds(data.time, 5), w: (data.weight - 38).toFixed(1), d: '+' + (data.weight - 38).toFixed(1), stable: '否' },
- { t: minusSeconds(data.time, 2), w: (data.weight - 9).toFixed(1), d: '+29.0', stable: '否' },
- { t: data.time, w: data.weight.toFixed(1), d: '+9.0', stable: '是' }
+ { t: minusSeconds(data.time, 5), w: (data.weight - 38).toFixed(1), stable: '否' },
+ { t: minusSeconds(data.time, 2), w: (data.weight - 9).toFixed(1), stable: '否' },
+ { t: data.time, w: data.weight.toFixed(1), stable: '是' }
];
const rowsHtml = samples.map(s => `
| ${s.t} |
${s.w} |
- ${s.d} |
${statusTag} |
${recUser} |
${s.stable === '是' ? '是' : '否'} |
@@ -878,7 +877,7 @@ function buildRawDataModal(data) {
设备名称:${data.device}
- | 采样时间 | 当前重量(g) | 较上次变化重量(g) | 识别状态 | 用户 | 是否稳定 |
+ | 采样时间 | 当前重量(g) | 识别状态 | 用户 | 是否稳定 |
${rowsHtml}
`;
diff --git a/web-admin/nutrition/doc/CHANGELOG.md b/web-admin/nutrition/doc/CHANGELOG.md
index 26342e0..c19d189 100644
--- a/web-admin/nutrition/doc/CHANGELOG.md
+++ b/web-admin/nutrition/doc/CHANGELOG.md
@@ -1,5 +1,13 @@
# 营养用餐管理端 CHANGELOG
+## [2026-09-23] feat: 净菜订单明细新增摆放顺序与理由,三页列表字段精简
+
+- `prod-clean-order-history.html` 净菜订单生成历史「数据明细」弹窗:
+ - 餐品维度新增「摆放顺序」「摆放理由」两列:按餐线取餐动线(先取菜后取主食)对荤菜/素菜/主食/汤/饮品分类赋序,餐次分组内排序编号并给出摆放理由
+ - 删除各环节数值下方的差异率趋势徽标(↑ 超 X% / ↓ 省 X% / — 持平),单元格仅保留数值;餐品展开的食材子表同步删除「差异率」列
+- `din-order-pickup.html` 取餐管理「秤原始数据」弹窗:删除「较上次变化重量(g)」列
+- `prod-proc-surplus.html` 余量处置列表:删除「交叉核对状态」字段(表头与各行「正常/异常(损耗超标)」标签),详情抽屉按表头动态渲染自动同步移除
+
## [2026-09-21] feat: 净菜订单生成历史双维度全链路对账 + 食物成分价格变更历史弹窗
- `prod-clean-order-history.html` 净菜订单生成历史「数据明细」弹窗重构为餐品/食材双维度对账视图:
diff --git a/web-admin/nutrition/prod-clean-order-history.html b/web-admin/nutrition/prod-clean-order-history.html
index b1851da..7db5fb0 100644
--- a/web-admin/nutrition/prod-clean-order-history.html
+++ b/web-admin/nutrition/prod-clean-order-history.html
@@ -124,8 +124,6 @@ tbody tr:hover{background:#F8FBFF;}
.val{font-weight:600;}
.val--base{color:var(--primary);}
.val-empty{color:var(--text-placeholder);font-weight:400;}
-.val-diff{margin-top:3px;line-height:1;}
-.tag--mini{font-size:10px;padding:1px 6px;border-radius:8px;}
/* 空态 */
.empty-state{text-align:center;color:var(--text-placeholder);padding:60px 0;font-size:var(--font-sm);}
.empty-state .icon{font-size:40px;display:block;margin-bottom:12px;}
@@ -221,6 +219,8 @@ tbody tr:hover{background:#F8FBFF;}
|
餐次 |
餐品名称 |
+ 摆放顺序 |
+ 摆放理由 |
熟重环节 |
取餐环节 |
@@ -297,6 +297,23 @@ var ING_TYPE_CLS={'主材':'ing-type--main','辅材':'ing-type--aux','调料':'i
var ING_YIELD={'鸡胸肉':0.88,'花生米':0.98,'黄瓜':0.85,'干辣椒':1,'葱姜蒜':0.9,'鲈鱼':0.82,'姜片':0.9,'葱丝':0.9,'五花肉':0.88,'酱油':1,'冰糖':1,'八角':1,'嫩豆腐':0.95,'肉末':0.9,'豆瓣酱':1,'花椒':1,'番茄':0.92,'鸡蛋':0.98,'葱花':0.9,'西兰花':0.82,'胡萝卜':0.88,'大蒜':0.88,'小米':1,'清水':1,'大米':1,'黄豆':1,'面粉':1,'酵母':1,'猪里脊':0.9,'木耳':1,'青椒':0.88,'猪排骨':0.85,'白糖':1,'香醋':1,'紫菜':1,'冬瓜':0.85,'酸奶':1,'茶叶':1};
/* AI 预测熟成率(生重→熟重) */
var COOK_YIELD=0.85;
+/* 餐线摆放规则:分类 → 摆放顺序权重 + 摆放理由(取餐动线:先取菜后取主食) */
+var DISH_PLACE_CAT={
+ '荤菜':{order:1,reason:'主菜优先摆放,突出餐品重心'},
+ '素菜':{order:2,reason:'素菜紧随主菜,均衡营养搭配'},
+ '主食':{order:3,reason:'主食随后摆放,便于按需取量'},
+ '汤':{order:4,reason:'汤品靠后摆放,避免取餐洒漏'},
+ '饮品':{order:5,reason:'饮品置于末端,便于即取即走'}
+};
+/* 菜品 → 摆放分类 */
+var DISH_CAT={
+ '宫保鸡丁':'荤菜','清蒸鲈鱼':'荤菜','红烧肉':'荤菜','番茄炒蛋':'荤菜','糖醋排骨':'荤菜',
+ '鱼香肉丝':'荤菜','麻婆豆腐':'荤菜','糖醋里脊':'荤菜','煮鸡蛋':'荤菜','茶叶蛋':'荤菜',
+ '炒时蔬':'素菜','清炒西兰花':'素菜',
+ '米饭':'主食','馒头':'主食','白粥':'主食','小米粥':'主食',
+ '冬瓜排骨汤':'汤','紫菜蛋花汤':'汤',
+ '豆浆':'饮品','酸奶':'饮品'
+};
function round2(n){return parseFloat(n.toFixed(2));}
/* ========== 净菜订单生成历史数据(订单维度,一个订单可含多个餐次) ========== */
@@ -403,7 +420,7 @@ function nameHash(s){
/* 餐品维度:AI 预测双值(生重/熟重)+ 下单/组配/烹制/取餐各环节实际值 */
function deriveDetail(order){
var generating=order.genStatus==='generating';
- return order.details.map(function(d){
+ var list=order.details.map(function(d){
var bom=recipeBom[d.foodName]||[];
var baseRatio=d.actualRatio!=null?d.actualRatio:(order.actualRatio||1);
var perDishGram=bom.reduce(function(s,i){return s+i.perServing;},0);
@@ -426,13 +443,23 @@ function deriveDetail(order){
var ingAct=parseFloat((ingRec*ingRatio).toFixed(3));
return {name:ing.name,type:ing.type,perServing:ing.perServing,rec:ingRec,act:ingAct};
});
+ var cat=DISH_CAT[d.foodName]||'主食';
+ var place=DISH_PLACE_CAT[cat]||DISH_PLACE_CAT['主食'];
return {
meal:d.meal,foodName:d.foodName,spec:d.spec,dinerCount:d.dinerCount,servings:d.servings,needSeasoning:d.needSeasoning,
recRaw:recRaw,recCooked:recCooked,
orderWeight:orderWeight,comboRaw:comboRaw,cookCooked:cookCooked,actualDiner:actualDiner,pickupWeight:pickupWeight,
- ingredients:ingredients
+ ingredients:ingredients,
+ placeWeight:place.order,placeReason:place.reason
};
});
+ /* 按餐次分组,组内按餐线动线排序赋摆放序号 */
+ var byMeal={};
+ list.forEach(function(d){if(!byMeal[d.meal])byMeal[d.meal]=[];byMeal[d.meal].push(d);});
+ Object.keys(byMeal).forEach(function(meal){
+ byMeal[meal].slice().sort(function(a,b){return a.placeWeight-b.placeWeight;}).forEach(function(d,i){d.placeOrder=i+1;});
+ });
+ return list;
}
/* 食材维度:同一食材跨餐品合并一行,链路覆盖 AI 用量→采购/实收(毛)→净菜产出(净)→组配实际(净) */
@@ -464,15 +491,6 @@ function deriveIngredients(order){
});
}
-/* ========== 差异率 ========== */
-function diffInfo(act,rec){
- if(!rec)return {cls:'flat',text:'— 持平'};
- var pct=(act-rec)/rec*100;
- if(pct>1)return {cls:'tag-red',text:'↑ 超 '+pct.toFixed(1)+'%'};
- if(pct<-1)return {cls:'tag-green',text:'↓ 省 '+Math.abs(pct).toFixed(1)+'%'};
- return {cls:'tag-gray',text:'— 持平'};
-}
-
/* ========== 菜品种类(去重) ========== */
function distinctDishCount(o){
var set={};
@@ -616,21 +634,18 @@ function switchDim(dim){
document.getElementById('dimIngWrap').style.display=dim==='ing'?'':'none';
}
-/* ========== 数值 + 差异徽标单元格(生成中环节未发生时占位 —) ========== */
-function stageCell(val,rec){
+/* ========== 数值单元格(生成中环节未发生时占位 —) ========== */
+function stageCell(val){
if(val==null)return '— | ';
- var diff=diffInfo(val,rec);
- return ''+val.toFixed(2)+' '+diff.text+' | ';
+ return ''+val.toFixed(2)+' | ';
}
-function dinerCell(actual,plan){
+function dinerCell(actual){
if(actual==null)return '— | ';
- var diff=diffInfo(actual,plan);
- return ''+actual+' '+diff.text+' | ';
+ return ''+actual+' | ';
}
-function ingStageCell(val,rec){
- if(val==null||rec==null)return '— | ';
- var diff=diffInfo(val,rec);
- return ''+val.toFixed(3)+' '+diff.text+' | ';
+function ingStageCell(val){
+ if(val==null)return '— | ';
+ return ''+val.toFixed(3)+' | ';
}
function plainCell(val){
if(val==null)return '— | ';
@@ -645,16 +660,18 @@ function renderDishRows(details){
html+='▶ | ';
html+=''+d.meal+' | ';
html+=''+d.foodName+' | ';
+ html+=''+d.placeOrder+' | ';
+ html+=''+d.placeReason+' | ';
/* 熟重环节 */
html+=''+d.recCooked.toFixed(2)+' | ';
- html+=stageCell(d.cookCooked,d.recCooked);
+ html+=stageCell(d.cookCooked);
/* 取餐环节 */
html+=''+d.dinerCount+' | ';
- html+=dinerCell(d.actualDiner,d.dinerCount);
- html+=stageCell(d.pickupWeight,d.recCooked);
+ html+=dinerCell(d.actualDiner);
+ html+=stageCell(d.pickupWeight);
html+='';
html+='';
- html+='| '+buildIngredientsDetail(d)+' | ';
+ html+=''+buildIngredientsDetail(d)+' | ';
html+='
';
});
document.getElementById('detailDishBody').innerHTML=html;
@@ -672,12 +689,12 @@ function renderIngRows(ings){
html+=''+m.aiUsed.toFixed(3)+' | ';
/* 采供环节:采购(链路起点)+ 实收 vs 采购(收货损耗) */
html+=plainCell(m.purchase);
- html+=ingStageCell(m.received,m.purchase);
+ html+=ingStageCell(m.received);
/* 加工环节:出净率 + 净菜产出 */
html+=''+(m.received!=null?(m.yieldRate*100).toFixed(0)+'%':'—')+' | ';
html+=plainCell(m.netOut);
/* 组配环节:实际用量 vs AI 生成用量(核心对账) */
- html+=ingStageCell(m.comboUsed,m.aiUsed);
+ html+=ingStageCell(m.comboUsed);
html+='';
html+='';
html+='| '+buildUsedByDetail(m)+' | ';
@@ -688,16 +705,14 @@ function renderIngRows(ings){
document.querySelector('.modal-mask').addEventListener('click',function(e){if(e.target===this)closeDetail();});
function buildIngredientsDetail(d){
- var html='| 食材名称 | 类别 | 推荐总量(kg) | 组配实际用量(kg) | 差异率 |
';
+ var html='| 食材名称 | 类别 | 推荐总量(kg) | 组配实际用量(kg) |
';
d.ingredients.forEach(function(ing){
var cls=ING_TYPE_CLS[ing.type]||'';
- var diff=diffInfo(ing.act,ing.rec);
html+='';
html+='| '+ing.name+' | ';
html+=''+ing.type+' | ';
html+=''+ing.rec.toFixed(3)+' | ';
html+=''+ing.act.toFixed(3)+' | ';
- html+=''+diff.text+' | ';
html+='
';
});
html+='
';
diff --git a/web-admin/nutrition/prod-proc-surplus.html b/web-admin/nutrition/prod-proc-surplus.html
index 731ffd1..59dc86c 100644
--- a/web-admin/nutrition/prod-proc-surplus.html
+++ b/web-admin/nutrition/prod-proc-surplus.html
@@ -190,16 +190,16 @@ tbody tr:hover td.td-actions{background:#F8FBFF;}
- | 处置单号 | 菜品名称 | 餐线 | 餐次 | 实际制作(kg) | 销售/取餐(kg) | 余量(kg) | 余量率(%) | 处置方式 | 备注 | 处置数量(kg) | 交叉核对状态 | 处置时间 | 处置人员 | 操作 |
+ | 处置单号 | 菜品名称 | 餐线 | 餐次 | 实际制作(kg) | 销售/取餐(kg) | 余量(kg) | 余量率(%) | 处置方式 | 备注 | 处置数量(kg) | 处置时间 | 处置人员 | 操作 |
- | SUR-002 | 白米饭 | A区中餐线 | 午餐 | 62.0 | 54.0 | 8.0 | 12.9% | 捐赠 | 捐赠予未央环卫 | 5.0 | 正常 | 2026-04-22 14:00 | 张主管 | 食材溯源链路 查看视频 更多 ▾ |
- | SUR-002 | 白米饭 | A区中餐线 | 午餐 | 62.0 | 54.0 | 8.0 | 12.9% | 员工福利 | 加班餐 | 3.0 | 正常 | 2026-04-22 14:00 | 张主管 | 食材溯源链路 查看视频 更多 ▾ |
- | SUR-004 | 蒜蓉菠菜 | B区中餐线 | 午餐 | 14.8 | 10.0 | 4.8 | 32.4% | 废弃 | 叶片发黄 | 3.0 | 异常(损耗超标) | 2026-04-22 15:00 | 李主管 | 食材溯源链路 查看视频 更多 ▾ |
- | SUR-004 | 蒜蓉菠菜 | B区中餐线 | 午餐 | 14.8 | 10.0 | 4.8 | 32.4% | 加工再利用 | 制作蔬菜饼 | 1.8 | 异常(损耗超标) | 2026-04-22 15:00 | 李主管 | 食材溯源链路 查看视频 更多 ▾ |
- | SUR-001 | 宫保鸡丁 | A区中餐线 | 午餐 | 43.0 | 39.5 | 3.5 | 8.1% | 员工福利 | 加班餐 | 2.0 | 正常 | 2026-04-22 14:00 | 张主管 | 食材溯源链路 查看视频 更多 ▾ |
- | SUR-001 | 宫保鸡丁 | A区中餐线 | 午餐 | 43.0 | 39.5 | 3.5 | 8.1% | 捐赠 | 捐赠予安保部 | 1.5 | 正常 | 2026-04-22 14:00 | 张主管 | 食材溯源链路 查看视频 更多 ▾ |
- | SUR-005 | 红烧肉 | B区中餐线 | 午餐 | 48.5 | 45.3 | 3.2 | 6.6% | 员工福利 | 加班餐 | 3.2 | 正常 | 2026-04-22 14:45 | 张主管 | 食材溯源链路 查看视频 更多 ▾ |
- | SUR-003 | 香辣大虾 | C区快餐线 | 午餐 | 20.5 | 18.3 | 2.2 | 10.7% | 废弃 | 只剩辣椒和虾头 | 2.2 | 正常 | 2026-04-22 14:30 | 张主管 | 食材溯源链路 查看视频 更多 ▾ |
+ | SUR-002 | 白米饭 | A区中餐线 | 午餐 | 62.0 | 54.0 | 8.0 | 12.9% | 捐赠 | 捐赠予未央环卫 | 5.0 | 2026-04-22 14:00 | 张主管 | 食材溯源链路 查看视频 更多 ▾ |
+ | SUR-002 | 白米饭 | A区中餐线 | 午餐 | 62.0 | 54.0 | 8.0 | 12.9% | 员工福利 | 加班餐 | 3.0 | 2026-04-22 14:00 | 张主管 | 食材溯源链路 查看视频 更多 ▾ |
+ | SUR-004 | 蒜蓉菠菜 | B区中餐线 | 午餐 | 14.8 | 10.0 | 4.8 | 32.4% | 废弃 | 叶片发黄 | 3.0 | 2026-04-22 15:00 | 李主管 | 食材溯源链路 查看视频 更多 ▾ |
+ | SUR-004 | 蒜蓉菠菜 | B区中餐线 | 午餐 | 14.8 | 10.0 | 4.8 | 32.4% | 加工再利用 | 制作蔬菜饼 | 1.8 | 2026-04-22 15:00 | 李主管 | 食材溯源链路 查看视频 更多 ▾ |
+ | SUR-001 | 宫保鸡丁 | A区中餐线 | 午餐 | 43.0 | 39.5 | 3.5 | 8.1% | 员工福利 | 加班餐 | 2.0 | 2026-04-22 14:00 | 张主管 | 食材溯源链路 查看视频 更多 ▾ |
+ | SUR-001 | 宫保鸡丁 | A区中餐线 | 午餐 | 43.0 | 39.5 | 3.5 | 8.1% | 捐赠 | 捐赠予安保部 | 1.5 | 2026-04-22 14:00 | 张主管 | 食材溯源链路 查看视频 更多 ▾ |
+ | SUR-005 | 红烧肉 | B区中餐线 | 午餐 | 48.5 | 45.3 | 3.2 | 6.6% | 员工福利 | 加班餐 | 3.2 | 2026-04-22 14:45 | 张主管 | 食材溯源链路 查看视频 更多 ▾ |
+ | SUR-003 | 香辣大虾 | C区快餐线 | 午餐 | 20.5 | 18.3 | 2.2 | 10.7% | 废弃 | 只剩辣椒和虾头 | 2.2 | 2026-04-22 14:30 | 张主管 | 食材溯源链路 查看视频 更多 ▾ |