diff --git a/index.html b/index.html index 49b80be..59044c1 100644 --- a/index.html +++ b/index.html @@ -324,6 +324,7 @@ const SITE_MAP = [ { file:'din-ingredient.html', label:'食材管理' }, { file:'din-ingredient-dialog.html', label:'食材管理弹窗', dialog:true }, { file:'din-ingredient-detail.html', label:'食材详情' }, + { file:'din-clean-veg-mgmt.html', label:'净菜管理' }, { file:'din-recipe-mgmt.html', label:'食谱管理' }, { file:'din-terminal.html', label:'设备管理' }, { file:'din-content-center.html', label:'内容中心' }, diff --git a/web-admin/nutrition/din-clean-veg-mgmt.html b/web-admin/nutrition/din-clean-veg-mgmt.html new file mode 100644 index 0000000..d80bea1 --- /dev/null +++ b/web-admin/nutrition/din-clean-veg-mgmt.html @@ -0,0 +1,911 @@ + + + + +营养管理 - 净菜管理 | 健康CQ原型 + + + + +
+ + +
+ ← 返回首页 +
+ 系统管理员 ▾ +
+
+ + + + + +
+ +
+ 🧪 食物成分/净菜管理 + 原型演示:本页净菜类型数据独立维护,与食物成分页共享同一数据模型 +
+ + +
+
🥬
净菜类型总数
+
🧪
覆盖食材数
+
📐
切配规格总数
+
⚖️
平均出净率
+
+ + +
+ +
+
+ + +
+
+
+
+ +
+ + +
+ +
+
+ + + +
+
0 个净菜类型
+
+ +
+ + + + + + + + + + + + + + + +
序号食材净菜标准名净菜俗名切配形状出净率可食部(%)规格别名切配规格刀工操作
+
+ +
+
+ + +
+
+
+
选择食材
+ +
+
+ +
+
净菜类型需挂在具体食材下维护,请先选定食材;选定后将回显该食材已有的净菜类型,可在其基础上新增或编辑。
+
+ +
+
+ + +
+
+
+
净菜类型维护
+ +
+
+ +
+ 🥬 + 当前食材: + ⇄ 更换食材 +
+
+ +
+ +
+
+ + +
+
+
+
删除净菜类型
+ +
+
+
+
⚠️
+
+
确定要删除该净菜类型吗?其下所有切配规格将一并移除。
+
食材:
+
净菜标准名:
+
+
+
+ +
+
+ + + + diff --git a/web-admin/nutrition/din-ingredient-add.html b/web-admin/nutrition/din-ingredient-add.html index 8cdf230..b6c38fc 100644 --- a/web-admin/nutrition/din-ingredient-add.html +++ b/web-admin/nutrition/din-ingredient-add.html @@ -577,7 +577,7 @@ function renderVegTypes(){ var container = document.getElementById('vegTypeRows'); if(!container) return; if(vegTypes.length===0){ - vegTypes.push({groupId:genGroupId(),alias:'',specAlias:'',yieldRate:'',cutSpec:{}}); + vegTypes.push({groupId:genGroupId(),alias:'',specAlias:'',yieldRate:'',edibleRate:'',cutSpec:{}}); } /* 按 groupId 分组(保持原顺序) */ var groupKeys = []; @@ -597,6 +597,7 @@ function renderVegTypes(){ html += '出净率(%)'; html += '切配形状'; html += '规格别名'; + html += '可食部(%)'; html += '长(mm)'; html += '宽(mm)'; html += '高(mm)'; @@ -605,7 +606,7 @@ function renderVegTypes(){ html += ''; if(groupKeys.length===0){ - html += '暂无净菜类型,点击下方"+ 添加净菜"按钮新增'; + html += '暂无净菜类型,点击下方"+ 添加净菜"按钮新增'; } groupKeys.forEach(function(key){ @@ -637,8 +638,9 @@ function renderVegTypes(){ }); html += ''; } - /* 各规格独立列:规格别名/长宽高/刀工 */ + /* 各规格独立列:规格别名/可食部/长宽高/刀工(可食部随各规格独立维护) */ html += ''; + html += ''; var cs = item.cutSpec||{}; html += ''; html += ''; @@ -667,7 +669,7 @@ function renderVegTypes(){ /* 添加净菜(新组) */ function addVegType(){ saveVegTypes(); - vegTypes.push({groupId:genGroupId(),alias:'',specAlias:'',yieldRate:'',cutSpec:{}}); + vegTypes.push({groupId:genGroupId(),alias:'',specAlias:'',yieldRate:'',edibleRate:'',cutSpec:{}}); renderVegTypes(); } /* 在指定净菜组下追加一行规格(共用 groupId) */ @@ -679,6 +681,7 @@ function addVegSpec(groupId){ alias:'', specAlias:'', yieldRate:'', + edibleRate:'', cutSpec:{} }; /* 紧跟该组最后一项插入 */ @@ -701,7 +704,7 @@ function removeVegRow(idx,groupId){ if(pos<0) return; vegTypes.splice(pos,1); if(vegTypes.length===0){ - vegTypes.push({groupId:genGroupId(),shapeCat:'',alias:'',specAlias:'',yieldRate:'',cutSpec:{}}); + vegTypes.push({groupId:genGroupId(),shapeCat:'',alias:'',specAlias:'',yieldRate:'',edibleRate:'',cutSpec:{}}); } renderVegTypes(); } @@ -733,7 +736,7 @@ function onRowField(idx,groupId,field,val){ var sameGroupItems = vegTypes.filter(function(it){return it.groupId===groupId;}); if(idx>=sameGroupItems.length) return; var item = sameGroupItems[idx]; - if(field==='specAlias'){ + if(field==='specAlias' || field==='edibleRate'){ item[field] = val; } else if(field==='length' || field==='width' || field==='height' || field==='technique'){ if(!item.cutSpec) item.cutSpec = {}; @@ -769,6 +772,8 @@ function saveVegTypes(){ item.cutSpec = {shape:shared.shape}; } item.specAlias = row.querySelector('.veg-spec-alias') ? row.querySelector('.veg-spec-alias').value : ''; + /* 可食部为行级字段,逐行收集 */ + item.edibleRate = row.querySelector('.veg-edible') ? row.querySelector('.veg-edible').value : ''; var dims = row.querySelectorAll('.veg-dim'); var techSel = row.querySelector('.veg-tech'); item.cutSpec.length = dims[0] ? dims[0].value : ''; @@ -777,7 +782,7 @@ function saveVegTypes(){ item.cutSpec.technique = techSel ? techSel.value : ''; newVegs.push(item); }); - vegTypes = newVegs.length>0 ? newVegs : [{groupId:genGroupId(),alias:'',specAlias:'',yieldRate:'',cutSpec:{}}]; + vegTypes = newVegs.length>0 ? newVegs : [{groupId:genGroupId(),alias:'',specAlias:'',yieldRate:'',edibleRate:'',cutSpec:{}}]; } /* 食物名称输入时实时刷新所有净菜标准名 */ @@ -938,8 +943,8 @@ if(initTab >= 0 && initTab < totalSteps) currentStep = initTab; /* 编辑模式 mock 数据(与 din-ingredient.html 的 FOODS 结构一致) */ var EDIT_FOODS = { '0101001':{name:'粳米(生)',code:'0101001',alias:'大米',firstClass:'谷薯类',secondClass:'稻米',edible:'97',waterRate:'13.3',dataSource:'0',basePrice:'3.5',vegTypes:[ - {groupId:'g1',alias:'普洗组',specAlias:'洗净米',yieldRate:'97',cutSpec:{shape:'原材'}}, - {groupId:'g1',alias:'普洗组',specAlias:'免淘米',yieldRate:'95',cutSpec:{shape:'原材'}} + {groupId:'g1',alias:'普洗组',specAlias:'洗净米',yieldRate:'97',edibleRate:'100',cutSpec:{shape:'原材'}}, + {groupId:'g1',alias:'普洗组',specAlias:'免淘米',yieldRate:'95',edibleRate:'100',cutSpec:{shape:'原材'}} ], crowd:[{name:'全人群',level:'推荐'},{name:'糖尿病人群',level:'适量'}], nutri:{calorie:346,protein:7.4,fat:0.6,carbohydrate:77.2,dietary_fiber:0.7, @@ -952,9 +957,9 @@ var EDIT_FOODS = { taste:{main:'淡味',sub:'微涩',intensity:'弱',desc:'生米无明显味道,煮熟后清香'}, texture:{main:'软糯',chew:'易',digest:'中',desc:'米粒饱满,质地坚硬,煮后软糯',cook:'水米比1:1.2,浸泡30分钟口感更佳'}}, '0301001':{name:'猪里脊(生)',code:'0301001',alias:'里脊肉',firstClass:'畜禽肉类',secondClass:'猪肉',edible:'100',waterRate:'73.3',dataSource:'0',basePrice:'18.8',vegTypes:[ - {groupId:'g1',alias:'丝类组',specAlias:'细丝',yieldRate:'92',cutSpec:{shape:'丝',length:10,width:1,height:1,technique:'平刀'}}, - {groupId:'g1',alias:'丝类组',specAlias:'粗丝',yieldRate:'90',cutSpec:{shape:'丝',length:10,width:2,height:2,technique:'直刀'}}, - {groupId:'g2',alias:'块类组',specAlias:'方块',yieldRate:'88',cutSpec:{shape:'块',length:15,width:15,height:15,technique:'直刀'}} + {groupId:'g1',alias:'丝类组',specAlias:'细丝',yieldRate:'92',edibleRate:'100',cutSpec:{shape:'丝',length:10,width:1,height:1,technique:'平刀'}}, + {groupId:'g1',alias:'丝类组',specAlias:'粗丝',yieldRate:'90',edibleRate:'100',cutSpec:{shape:'丝',length:10,width:2,height:2,technique:'直刀'}}, + {groupId:'g2',alias:'块类组',specAlias:'方块',yieldRate:'88',edibleRate:'100',cutSpec:{shape:'块',length:15,width:15,height:15,technique:'直刀'}} ], crowd:[{name:'成人',level:'推荐'},{name:'儿童',level:'推荐'},{name:'高血脂人群',level:'适量'}], nutri:{calorie:143,protein:20.2,fat:7.1,carbohydrate:0.7,dietary_fiber:0, @@ -978,8 +983,8 @@ var EDIT_FOODS = { taste:{main:'鲜味',sub:'蛋香',intensity:'中',desc:'蛋白柔和,蛋黄浓郁'}, texture:{main:'嫩滑',chew:'易',digest:'易',desc:'水煮蛋弹嫩,炒蛋软嫩,蒸蛋细腻',cook:'蒸蛋口感最软,适合各年龄段'}}, '0201001':{name:'菠菜(生)',code:'0201001',alias:'波斯菜',firstClass:'蔬菜类',secondClass:'叶菜类',edible:'89',waterRate:'91.2',dataSource:'0',basePrice:'4.2',vegTypes:[ - {groupId:'g1',alias:'段类组',specAlias:'净菜',yieldRate:'90',cutSpec:{shape:'原材'}}, - {groupId:'g1',alias:'段类组',specAlias:'寸段',yieldRate:'88',cutSpec:{shape:'原材',length:50,width:'',height:'',technique:'直刀'}} + {groupId:'g1',alias:'段类组',specAlias:'净菜',yieldRate:'90',edibleRate:'89',cutSpec:{shape:'原材'}}, + {groupId:'g1',alias:'段类组',specAlias:'寸段',yieldRate:'88',edibleRate:'88',cutSpec:{shape:'原材',length:50,width:'',height:'',technique:'直刀'}} ], crowd:[{name:'全人群',level:'推荐'},{name:'肾结石人群',level:'慎食'}], nutri:{calorie:28,protein:2.6,fat:0.3,carbohydrate:4.5,dietary_fiber:1.7, @@ -992,8 +997,8 @@ var EDIT_FOODS = { taste:{main:'清甜',sub:'微涩',intensity:'弱',desc:'清爽微甜带涩'}, texture:{main:'嫩脆',chew:'易',digest:'易',desc:'叶片嫩滑,茎部脆嫩',cook:'焯水去草酸后口感最佳'}}, '0601001':{name:'豆腐(北)',code:'0601001',alias:'北豆腐',firstClass:'豆及豆制品',secondClass:'豆制品',edible:'100',waterRate:'82.8',dataSource:'1',basePrice:'5.0',vegTypes:[ - {groupId:'g1',alias:'块类组',specAlias:'大方块',yieldRate:'96',cutSpec:{shape:'块',length:30,width:30,height:20,technique:'直刀'}}, - {groupId:'g2',alias:'片类组',specAlias:'薄片',yieldRate:'94',cutSpec:{shape:'片',length:10,width:10,height:3,technique:'平刀'}} + {groupId:'g1',alias:'块类组',specAlias:'大方块',yieldRate:'96',edibleRate:'100',cutSpec:{shape:'块',length:30,width:30,height:20,technique:'直刀'}}, + {groupId:'g2',alias:'片类组',specAlias:'薄片',yieldRate:'94',edibleRate:'100',cutSpec:{shape:'片',length:10,width:10,height:3,technique:'平刀'}} ], crowd:[{name:'全人群',level:'推荐'},{name:'高血压人群',level:'推荐'},{name:'痛风人群',level:'适量'},{name:'老年人',level:'推荐'},{name:'术后恢复',level:'推荐'}], nutri:{calorie:98,protein:12.2,fat:4.8,carbohydrate:1.5,dietary_fiber:0.4, diff --git a/web-admin/nutrition/din-ingredient.html b/web-admin/nutrition/din-ingredient.html index 8d8c482..43eb59f 100644 --- a/web-admin/nutrition/din-ingredient.html +++ b/web-admin/nutrition/din-ingredient.html @@ -342,6 +342,7 @@ body{font-family:-apple-system,BlinkMacSystemFont,'PingFang SC','Microsoft YaHei
➕ 新增食物 + 🥬 净菜管理
@@ -432,8 +433,8 @@ function formatCutSpecNoShape(cut){ // 食物数据(对齐 yx_mater_base_material 表结构) const FOODS = [ {name:'粳米(生)',code:'0101001',alias:'大米',firstClass:'谷薯类',secondClass:'稻米',icon:'🌾',edible:'100',waterRate:'13.3',dataSource:0,basePrice:'3.5',vegTypes:[ - {groupId:'g1',alias:'普洗组',specAlias:'洗净米',yieldRate:'97',cutSpec:{shape:'原状'}}, - {groupId:'g1',alias:'普洗组',specAlias:'免淘米',yieldRate:'95',cutSpec:{shape:'原状'}} + {groupId:'g1',alias:'普洗组',specAlias:'洗净米',yieldRate:'97',edibleRate:'100',cutSpec:{shape:'原状'}}, + {groupId:'g1',alias:'普洗组',specAlias:'免淘米',yieldRate:'95',edibleRate:'100',cutSpec:{shape:'原状'}} ], nutri:{calorie:346,protein:7.4,fat:0.8,carbohydrate:77.2,dietary_fiber:0.6, vitamin_a:0,vitamin_b1:0.16,vitamin_b2:0.08,vitamin_b6:0.16,vitamin_b12:0,vitamin_c:0,vitamin_d:0,vitamin_e:0.46,vitamin_k:0,niacin:1.9,folic_acid:3.8,biotin:0,pantothenic_acid:0.6,total_choline:0, @@ -452,10 +453,10 @@ const FOODS = [ {type:'编辑',title:'修订色泽描述',time:'2026-07-21 11:05',user:'李建国',role:'营养师',dept:'营养管理部',summary:'色泽描述语义化,补充感官评级。',changes:[{field:'色泽描述',old:'乳白色,半透明',new:'乳白色,半透明,颗粒饱满'},{field:'感官评级',old:'—',new:'优'}]} ]}, {name:'猪里脊肉',code:'0201001',alias:'里脊',firstClass:'畜禽肉类',secondClass:'猪肉',icon:'🥩',edible:'100',waterRate:'71.4',dataSource:0,basePrice:'18.8',vegTypes:[ - {groupId:'g1',alias:'里脊肉丝',specAlias:'细丝',yieldRate:'92',cutSpec:{shape:'丝',length:10,width:1,height:1,technique:'平刀'}}, - {groupId:'g1',alias:'里脊肉丝',specAlias:'粗丝',yieldRate:'90',cutSpec:{shape:'丝',length:10,width:2,height:2,technique:'直刀'}}, - {groupId:'g2',alias:'里脊肉片',specAlias:'薄片',yieldRate:'95',cutSpec:{shape:'片',length:3,width:1,height:5,technique:'平刀'}}, - {groupId:'g3',alias:'里脊肉块',specAlias:'方块',yieldRate:'92',cutSpec:{shape:'块',length:20,width:20,height:20,technique:'直刀'}} + {groupId:'g1',alias:'里脊肉丝',specAlias:'细丝',yieldRate:'92',edibleRate:'100',cutSpec:{shape:'丝',length:10,width:1,height:1,technique:'平刀'}}, + {groupId:'g1',alias:'里脊肉丝',specAlias:'粗丝',yieldRate:'90',edibleRate:'100',cutSpec:{shape:'丝',length:10,width:2,height:2,technique:'直刀'}}, + {groupId:'g2',alias:'里脊肉片',specAlias:'薄片',yieldRate:'95',edibleRate:'100',cutSpec:{shape:'片',length:3,width:1,height:5,technique:'平刀'}}, + {groupId:'g3',alias:'里脊肉块',specAlias:'方块',yieldRate:'92',edibleRate:'100',cutSpec:{shape:'块',length:20,width:20,height:20,technique:'直刀'}} ], nutri:{calorie:155,protein:20.2,fat:7.9,carbohydrate:0.7,dietary_fiber:0, vitamin_a:6,vitamin_b1:0.54,vitamin_b2:0.1,vitamin_b6:0.33,vitamin_b12:0.6,vitamin_c:0,vitamin_d:0,vitamin_e:0.34,vitamin_k:0,niacin:5.3,folic_acid:3,biotin:0,pantothenic_acid:0.8,total_choline:0, @@ -507,8 +508,8 @@ const FOODS = [ {type:'编辑',title:'补充碘含量',time:'2026-07-04 14:50',user:'王秀兰',role:'营养师',dept:'营养管理部',summary:'补充碘元素数据,完善矿物质维度。',changes:[{field:'碘',old:'—',new:'27.2 μg'}]} ]}, {name:'豆腐(北)',code:'0601001',alias:'北豆腐',firstClass:'豆及豆制品',secondClass:'豆制品',icon:'🧈',edible:'100',waterRate:'82.8',dataSource:1,basePrice:'5.0',vegTypes:[ - {groupId:'g1',alias:'块类组',specAlias:'大方块',yieldRate:'96',cutSpec:{shape:'块',length:30,width:30,height:20,technique:'直刀'}}, - {groupId:'g1',alias:'块类组',specAlias:'中方块',yieldRate:'98',cutSpec:{shape:'块',length:20,width:20,height:15,technique:'直刀'}} + {groupId:'g1',alias:'块类组',specAlias:'大方块',yieldRate:'96',edibleRate:'100',cutSpec:{shape:'块',length:30,width:30,height:20,technique:'直刀'}}, + {groupId:'g1',alias:'块类组',specAlias:'中方块',yieldRate:'98',edibleRate:'100',cutSpec:{shape:'块',length:20,width:20,height:15,technique:'直刀'}} ], nutri:{calorie:98,protein:12.2,fat:4.8,carbohydrate:1.5,dietary_fiber:0.4, vitamin_a:0,vitamin_b1:0.07,vitamin_b2:0.04,vitamin_b6:0.05,vitamin_b12:0,vitamin_c:0,vitamin_d:0,vitamin_e:2.71,vitamin_k:0,niacin:0.1,folic_acid:37,biotin:0,pantothenic_acid:0.1,total_choline:0, @@ -604,6 +605,8 @@ function renderBasicInfo(f){ var cutShape = cs.shape || '—'; var cutSpecTxt = formatCutSpecNoShape(item.cutSpec); var specAlias = item.specAlias || '—'; + /* 可食部为规格行级字段,随各规格独立维护 */ + var edibleRate = (item.edibleRate!==undefined && item.edibleRate!=='') ? item.edibleRate+'%' : '—'; if(si===0){ rows += ``; rows += `${vegName}`; @@ -612,16 +615,18 @@ function renderBasicInfo(f){ rows += `${cutShape}`; rows += `${cutSpecTxt}`; rows += `${specAlias}`; + rows += `${edibleRate}`; rows += ``; } else { rows += ``; rows += `${cutSpecTxt}`; rows += `${specAlias}`; + rows += `${edibleRate}`; rows += ``; } }); }); - vegTypesValue = `${rows}
净菜标准名净菜俗名出净率切配形状切配规格规格别名
`; + vegTypesValue = `${rows}
净菜标准名净菜俗名出净率切配形状切配规格规格别名可食部(%)
`; } else { vegTypesValue = '—'; } diff --git a/web-admin/nutrition/doc/CHANGELOG.md b/web-admin/nutrition/doc/CHANGELOG.md index 5e626f7..21eb11e 100644 --- a/web-admin/nutrition/doc/CHANGELOG.md +++ b/web-admin/nutrition/doc/CHANGELOG.md @@ -1,5 +1,20 @@ # 营养用餐管理端 CHANGELOG +## [2026-09-07] feat: 净菜类型拆分独立管理(新增净菜管理页 + 规格行级可食部字段) + +- `din-ingredient.html` 食物成分: + - 左侧列表操作区「食材分类管理」后新增「净菜管理」按钮,跳转新二级页 + - 详情净菜类型表「规格别名」后新增「可食部(%)」列:规格行级字段,每个规格独立显示,不随组合并行合并 +- `din-ingredient-add.html` 新增/编辑食物: + - 净菜类型维护表「规格别名」后新增「可食部(%)」列,逐规格独立录入,新增规格行默认空值不继承 +- 新增 `din-clean-veg-mgmt.html` 净菜管理页: + - 统计卡片:净菜类型总数/覆盖食材数/切配规格总数/平均出净率 + - 筛选区:食材名称(下拉搜索框,选中精确/手输模糊)、食材编码、净菜类型(命中净菜俗名/净菜标准名/规格俗名任一)、切配形状(不设食物分类筛选) + - 操作区:新增净菜 + 异步导出按钮组「导出列表数据」「查看导出任务」(样式对齐 farm-purchase 等列表页惯例,空结果不建任务) + - 分页列表:组级列(序号/食材/净菜标准名/净菜俗名/切配形状/出净率/操作)rowspan 合并;可食部(%)/规格别名/切配规格/刀工四列按规格逐行拆分(切配规格仅留尺寸、刀工独立成列),组内规格间虚线分隔、规格列组左侧纵向分隔线,组间实线 + - 新增流程:先弹食材选择器(关键字搜索)→ 选定后回显该食材已有净菜类型 → 在其基础上新增或编辑;维护表结构对齐新增食物页(含行级可食部);支持按组删除(确认弹窗) +- `index.html` SITE_MAP「营养用餐」新增「净菜管理」条目 + ## [2026-09-01] feat: 餐线营养秤四Tab分页 + 日期默认当天 + 人脸识别数据更名视频数据 - `din-terminal.html` 设备概览「餐线营养秤」: