@@ -0,0 +1,736 @@
<!DOCTYPE html>
< html lang = "zh-CN" >
< head >
< meta charset = "UTF-8" >
< title > 营养管理 - 自由餐品库 | 健康CQ原型< / title >
< style >
*{box-sizing:border-box;margin:0;padding:0;}
body{font-family:-apple-system,BlinkMacSystemFont,'PingFang SC','Microsoft YaHei',sans-serif;background:#F5F7FA;color:#333;min-width:1280px;}
:root{
--primary:#1890FF;--primary-light:#E6F7FF;--success:#52C41A;--warning:#FAAD14;--danger:#FF4D4F;
--text-primary:#333;--text-secondary:#666;--text-placeholder:#999;--border:#E8E8E8;--background:#F5F7FA;
--font-xs:11px;--font-sm:13px;--font-base:15px;--font-lg:17px;--font-xl:20px;--font-xxl:24px;
--radius-sm:4px;--radius-md:8px;--radius-lg:12px;
--shadow-sm:0 1px 4px rgba(0,0,0,0.08);--shadow-md:0 4px 12px rgba(0,0,0,0.12);
}
.top-bar{display:flex;align-items:center;height:56px;background:#001529;padding:0 24px;position:fixed;top:0;left:0;right:0;z-index:100;}
.top-bar__logo{display:flex;align-items:center;gap:8px;color:#fff;font-size:var(--font-lg);font-weight:600;white-space:nowrap;width:240px;flex-shrink:0;}
.top-bar__logo svg{width:28px;height:28px;}
.top-bar__nav{display:flex;align-items:center;gap:4px;flex:1;}
.top-bar__nav a{color:rgba(255,255,255,0.65);text-decoration:none;padding:6px 16px;border-radius:var(--radius-sm);font-size:var(--font-sm);transition:all .2s;}
.top-bar__nav a:hover{color:#fff;background:rgba(255,255,255,0.08);}
.top-bar__nav a.active{color:#fff;background:var(--primary);}
.top-bar__right{display:flex;align-items:center;gap:16px;color:rgba(255,255,255,0.65);font-size:var(--font-sm);}
.top-bar__right .btn-back{color:rgba(255,255,255,0.65);cursor:pointer;display:flex;align-items:center;gap:4px;text-decoration:none;}
.top-bar__right .btn-back:hover{color:#fff;}
.avatar{width:32px;height:32px;border-radius:50%;background:#1890FF;display:flex;align-items:center;justify-content:center;color:#fff;font-size:var(--font-sm);cursor:pointer;}
.sidebar{position:fixed;top:56px;left:0;bottom:0;width:240px;background:#001529;overflow-y:auto;z-index:90;padding-top:8px;}
.sidebar-menu__title{color:rgba(255,255,255,0.35);font-size:var(--font-xs);padding:16px 24px 8px;text-transform:uppercase;letter-spacing:.5px;}
.sidebar-item{display:flex;align-items:center;gap:8px;padding:10px 24px;color:rgba(255,255,255,0.65);font-size:var(--font-sm);cursor:pointer;transition:all .15s;text-decoration:none;}
.sidebar-item:hover{color:#fff;background:rgba(255,255,255,0.06);}
.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;}
.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;}
.sidebar-subgroup__header .arrow path{stroke:rgba(255,255,255,0.45);}
.sidebar-subgroup.open>.sidebar-subgroup__header{color:rgba(255,255,255,0.85);}
.sidebar-subgroup.open>.sidebar-subgroup__header .arrow{transform:rotate(90deg);}
.sidebar-subgroup__body{display:none;padding-left:16px;}
.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(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);}
.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;text-decoration:none;}
.btn-primary{background:var(--primary);color:#fff;}.btn-primary:hover{background:#40a9ff;}
.btn-default{background:#fff;color:var(--text-primary);border:1px solid var(--border);}.btn-default:hover{color:var(--primary);border-color:var(--primary);}
.tag{display:inline-flex;align-items:center;padding:2px 8px;border-radius:10px;font-size:var(--font-xs);margin-right:4px;}
.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);text-decoration:none;}.link:hover{color:#40a9ff;}
/* 左右分栏布局 */
.master-detail{display:flex;gap:16px;height:calc(100vh - 56px - 24px - 24px - 100px);}
.panel-left{width:380px;flex-shrink:0;background:#fff;border-radius:var(--radius-md);box-shadow:var(--shadow-sm);display:flex;flex-direction:column;overflow:hidden;}
.panel-right{flex:1;background:#fff;border-radius:var(--radius-md);box-shadow:var(--shadow-sm);display:flex;flex-direction:column;overflow:hidden;}
.panel-left__header{padding:16px 20px 12px;border-bottom:1px solid var(--border);}
.panel-left__title{font-size:var(--font-base);font-weight:600;margin-bottom:12px;display:flex;align-items:center;justify-content:space-between;}
.panel-left__search{display:flex;gap:8px;margin-bottom:10px;}
.panel-left__search input{flex:1;height:32px;border:1px solid var(--border);border-radius:var(--radius-sm);padding:0 10px;font-size:var(--font-sm);outline:none;}
.panel-left__search input:focus{border-color:var(--primary);}
.panel-left__filter{display:flex;gap:8px;}
.panel-left__filter select{height:32px;border:1px solid var(--border);border-radius:var(--radius-sm);padding:0 24px 0 10px;font-size:var(--font-xs);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 8px center;appearance:none;cursor:pointer;flex:1;}
.panel-left__actions{display:flex;gap:8px;padding:10px 20px;border-bottom:1px solid var(--border);flex-wrap:wrap;}
.panel-left__actions .btn{height:30px;font-size:var(--font-xs);padding:0 10px;}
.food-list{flex:1;overflow-y:auto;padding:4px 0;}
.food-item{display:flex;align-items:center;gap:12px;padding:12px 20px;cursor:pointer;transition:background .15s;border-left:3px solid transparent;}
.food-item:hover{background:#F8FBFF;}
.food-item.active{background:var(--primary-light);border-left-color:var(--primary);}
.food-item__icon{width:36px;height:36px;border-radius:var(--radius-sm);background:#F5F7FA;display:flex;align-items:center;justify-content:center;font-size:18px;flex-shrink:0;}
.food-item__info{flex:1;min-width:0;}
.food-item__name{font-size:var(--font-sm);font-weight:500;color:var(--text-primary);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}
.food-item__meta{font-size:var(--font-xs);color:var(--text-placeholder);margin-top:2px;display:flex;gap:8px;}
.panel-left__footer{padding:10px 20px;border-top:1px solid var(--border);display:flex;align-items:center;justify-content:space-between;}
.panel-left__footer span{font-size:var(--font-xs);color:var(--text-placeholder);}
.page-btn{width:26px;height:26px;border:1px solid var(--border);border-radius:var(--radius-sm);background:#fff;cursor:pointer;font-size:var(--font-xs);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);}
/* 右侧详情面板 */
.panel-right__header{padding:16px 24px 0;border-bottom:1px solid var(--border);}
.panel-right__food-title{display:flex;align-items:center;gap:12px;margin-bottom:14px;}
.panel-right__food-title h2{font-size:var(--font-lg);font-weight:600;}
.panel-right__food-title .code{font-size:var(--font-sm);color:var(--text-placeholder);}
.detail-tabs{display:flex;gap:0;flex-wrap:wrap;}
.detail-tab{padding:10px 16px;font-size:var(--font-sm);cursor:pointer;color:var(--text-secondary);border-bottom:2px solid transparent;margin-bottom:-1px;transition:all .2s;display:flex;align-items:center;gap:5px;}
.detail-tab:hover{color:var(--primary);}
.detail-tab.active{color:var(--primary);border-bottom-color:var(--primary);font-weight:500;}
.panel-right__body{flex:1;overflow-y:auto;padding:20px 24px;}
.detail-panel{display:none;}
.detail-panel.active{display:block;}
/* 详情网格 */
.info-grid{display:grid;grid-template-columns:repeat(4,1fr);gap:12px;margin-bottom:20px;}
.info-cell{background:#FAFBFC;border-radius:var(--radius-sm);padding:14px 16px;border:1px solid #F0F0F0;}
.info-cell__label{font-size:var(--font-xs);color:var(--text-placeholder);margin-bottom:4px;}
.info-cell__value{font-size:var(--font-sm);font-weight:500;color:var(--text-primary);}
.info-section{margin-bottom:20px;}
.info-section__title{font-size:var(--font-sm);font-weight:600;color:var(--text-primary);margin-bottom:10px;padding-bottom:6px;border-bottom:1px solid #F0F0F0;display:flex;align-items:center;justify-content:space-between;}
.info-table{width:100%;border-collapse:collapse;font-size:var(--font-sm);}
.info-table th{background:#FAFAFA;padding:10px 12px;text-align:left;color:var(--text-secondary);font-weight:500;border-bottom:1px solid var(--border);}
.info-table td{padding:10px 12px;border-bottom:1px solid var(--border);color:var(--text-primary);}
.info-table tr:last-child td{border-bottom:none;}
.info-table tr:hover{background:#F8FBFF;}
.spec-detail-table th{padding:6px 12px;font-size:12px;}
.spec-detail-table td{padding:6px 12px;font-size:12px;}
/* 外售净菜包胶囊开关 */
.sale-toggle{display:inline-flex;align-items:center;gap:6px;cursor:pointer;user-select:none;}
.sale-toggle__switch{width:32px;height:18px;background:#D9D9D9;border-radius:9px;position:relative;transition:background .2s;flex-shrink:0;}
.sale-toggle__switch::after{content:'';position:absolute;left:2px;top:2px;width:14px;height:14px;background:#fff;border-radius:50%;transition:transform .2s;box-shadow:0 1px 2px rgba(0,0,0,0.15);}
.sale-toggle.active .sale-toggle__switch{background:var(--success);}
.sale-toggle.active .sale-toggle__switch::after{transform:translateX(14px);}
.sale-toggle__label{font-size:11px;color:var(--text-placeholder);}
.sale-toggle.active .sale-toggle__label{color:var(--success);font-weight:500;}
/* 图片/视频网格 */
.media-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:16px;}
.media-card{background:#FAFBFC;border-radius:var(--radius-md);border:1px solid #F0F0F0;overflow:hidden;}
.media-card__thumb{height:120px;background:#E8E8E8;display:flex;align-items:center;justify-content:center;font-size:36px;color:#999;}
.media-card__info{padding:10px 12px;}
.media-card__title{font-size:var(--font-sm);font-weight:500;margin-bottom:4px;}
.media-card__meta{font-size:var(--font-xs);color:var(--text-placeholder);}
/* 弹窗 */
.dialog-mask{display:none;position:fixed;top:0;left:0;right:0;bottom:0;background:rgba(0,0,0,0.45);z-index:200;align-items:center;justify-content:center;}
.dialog-mask.open{display:flex;}
.dialog{background:#fff;border-radius:var(--radius-lg);width:560px;max-width:90vw;box-shadow:var(--shadow-md);}
.dialog__header{display:flex;align-items:center;justify-content:space-between;padding:20px 24px 16px;border-bottom:1px solid var(--border);}
.dialog__title{font-size:var(--font-lg);font-weight:600;color:var(--text-primary);}
.dialog__close{width:32px;height:32px;border:none;background:none;cursor:pointer;display:flex;align-items:center;justify-content:center;border-radius:var(--radius-sm);color:var(--text-placeholder);}
.dialog__close:hover{background:#F5F5F5;color:var(--text-primary);}
.dialog__body{padding:24px;}
.dialog__footer{display:flex;justify-content:flex-end;gap:8px;padding:16px 24px;border-top:1px solid var(--border);}
.form-group{margin-bottom:16px;}
.form-group label{display:block;font-size:var(--font-sm);color:var(--text-primary);margin-bottom:8px;font-weight:500;}
.form-group label .required{color:var(--danger);margin-left:2px;}
.form-input,.form-select{width:100%;height:36px;border:1px solid var(--border);border-radius:var(--radius-sm);padding:0 12px;font-size:var(--font-sm);outline:none;background:#fff;}
.form-input:focus,.form-select:focus{border-color:var(--primary);}
.form-select{appearance: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;padding-right:28px;}
.form-row{display:grid;grid-template-columns:1fr 1fr;gap: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;}
/* 分类管理表格 */
.cat-table{width:100%;border-collapse:collapse;font-size:var(--font-sm);}
.cat-table 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;}
.cat-table td{padding:8px 12px;border-bottom:1px solid #F5F5F5;color:var(--text-primary);}
.cat-table tbody tr:hover{background:#F8FBFF;}
.cat-toggle{display:inline-flex;align-items:center;justify-content:center;width:20px;height:20px;border:1px solid var(--border);border-radius:3px;cursor:pointer;margin-right:6px;font-size:12px;line-height:1;background:#fff;color:var(--text-secondary);flex-shrink:0;vertical-align:middle;}
.cat-toggle:hover{border-color:var(--primary);color:var(--primary);}
.cat-toggle.leaf{visibility:hidden;}
.cat-table td.td-actions{white-space:nowrap;}
.cat-table td.td-actions .link{margin:0 4px;}
/* 状态胶囊开关 */
.status-toggle{display:inline-flex;align-items:center;gap:6px;cursor:pointer;user-select:none;}
.status-toggle__switch{width:36px;height:20px;background:#D9D9D9;border-radius:10px;position:relative;transition:background .2s;flex-shrink:0;}
.status-toggle__switch::after{content:'';position:absolute;left:2px;top:2px;width:16px;height:16px;background:#fff;border-radius:50%;transition:transform .2s;box-shadow:0 1px 3px rgba(0,0,0,0.15);}
.status-toggle.active .status-toggle__switch{background:var(--success);}
.status-toggle.active .status-toggle__switch::after{transform:translateX(16px);}
.status-toggle__label{font-size:var(--font-xs);color:var(--text-placeholder);}
.status-toggle.active .status-toggle__label{color:var(--success);}
< / style >
< / head >
< body >
<!-- 顶部导航栏 -->
< header class = "top-bar" >
< div class = "top-bar__logo" >
< svg viewBox = "0 0 28 28" fill = "none" > < rect width = "28" height = "28" rx = "6" fill = "#1890FF" / > < path d = "M7 14h14M14 7v14" stroke = "#fff" stroke-width = "2.5" stroke-linecap = "round" / > < / svg >
营养管理
< / div >
< nav class = "top-bar__nav" >
< a href = "trace-query.html" > 溯源总览< / a >
< a href = "arc-employee.html" > 档案< / a >
< a href = "farm-land.html" > 绿色种采< / a >
< a href = "sup-hygiene-check.html" > 卫生供应< / a >
< a href = "prod-qc-daily.html" > 健康生产< / a >
< a href = "din-dict-mgmt.html" class = "active" > 营养用餐< / a >
< a href = "ano-dirty.html" > 异常事件< / a >
< / nav >
< div class = "top-bar__right" >
< a href = "../../index.html" class = "btn-back" > ← 返回首页< / a >
< div class = "avatar" > 管< / div >
< span > 系统管理员 ▾< / span >
< / div >
< / header >
<!-- 侧边栏 -->
< aside class = "sidebar" >
< div class = "sidebar-menu__title" > 营养用餐< / div >
< a href = "din-canteen.html" class = "sidebar-item" > < span class = "mi" > 🏢< / span > 场所管理< / a >
< a href = "din-dict-mgmt.html" class = "sidebar-item" > < span class = "mi" > 📖< / span > 字典管理< / a >
< a href = "prod-qc-nutrition.html" class = "sidebar-item" > < span class = "mi" > 🔬< / span > 营养检验< / a >
< a href = "din-ingredient.html" class = "sidebar-item" > < span class = "mi" > 🧪< / span > 食物成分< / a >
< a href = "din-dish-all.html" class = "sidebar-item" > < span class = "mi" > 🍽️< / span > 餐品总库< / a >
< a href = "din-dish-free.html" class = "sidebar-item active" > < span class = "mi" > 📦< / span > 自由餐品库< / a >
< div class = "sidebar-subgroup" >
< div class = "sidebar-subgroup__header" onclick = "toggleSubgroup(this)" >
< svg class = "arrow" viewBox = "0 0 10 10" fill = "none" > < path d = "M3 1l4 4-4 4" stroke-width = "1.5" / > < / svg >
📐 算法标准
< / div >
< div class = "sidebar-subgroup__body" >
< a href = "din-algo-population.html" class = "sidebar-item" > < span class = "mi" > 👥< / span > 人群基础标准< / a >
< a href = "din-algo-vip.html" class = "sidebar-item" > < span class = "mi" > 👑< / span > VIP定制标准< / a >
< / div >
< / div >
< a href = "din-recipe-mgmt.html" class = "sidebar-item" > < span class = "mi" > 📋< / span > 食谱管理< / a >
< a href = "din-order-meal.html" class = "sidebar-item" > < span class = "mi" > 🍱< / span > 营养点餐< / a >
< a href = "din-user-mgmt.html" class = "sidebar-item" > < span class = "mi" > 👤< / span > 用户管理< / a >
< a href = "din-order-line.html" class = "sidebar-item" > < span class = "mi" > 🍳< / span > 餐线管理< / a >
< a href = "din-order-pickup.html" class = "sidebar-item" > < span class = "mi" > 🎫< / span > 取餐管理< / a >
< a href = "din-data-consume.html" class = "sidebar-item" > < span class = "mi" > 💰< / span > 消费管理< / a >
< a href = "din-data-nutri.html" class = "sidebar-item" > < span class = "mi" > 📊< / span > 营养管理< / a >
< a href = "din-data-benefit.html" class = "sidebar-item" > < span class = "mi" > 📈< / span > 餐材效益< / a >
< a href = "din-terminal.html" class = "sidebar-item" > < span class = "mi" > 🖥️< / span > 终端管理< / a >
< div class = "sidebar-subgroup" >
< div class = "sidebar-subgroup__header" onclick = "toggleSubgroup(this)" >
< svg class = "arrow" viewBox = "0 0 10 10" fill = "none" > < path d = "M3 1l4 4-4 4" stroke-width = "1.5" / > < / svg >
🤖 模型管理
< / div >
< div class = "sidebar-subgroup__body" >
< a href = "din-model-llm.html" class = "sidebar-item" > < span class = "mi" > 🧠< / span > 大模型管理< / a >
< a href = "din-model-small.html" class = "sidebar-item" > < span class = "mi" > ⚙️< / span > 小模型管理< / a >
< / div >
< / div >
< a href = "din-innovation.html" class = "sidebar-item" > < span class = "mi" > 💡< / span > 味养创新< / a >
< / aside >
<!-- 主内容 -->
< main class = "main" >
<!-- 统计卡片 -->
< div class = "stats-row" >
< div class = "stat-card" > < div class = "stat-card__icon blue" > 🍽️< / div > < div class = "stat-card__info" > < div class = "stat-card__value" > 486< / div > < div class = "stat-card__label" > 餐品总数< / div > < / div > < / div >
< div class = "stat-card" > < div class = "stat-card__icon green" > ✅< / div > < div class = "stat-card__info" > < div class = "stat-card__value" > 312< / div > < div class = "stat-card__label" > 上架中< / div > < / div > < / div >
< div class = "stat-card" > < div class = "stat-card__icon orange" > 📊< / div > < div class = "stat-card__info" > < div class = "stat-card__value" > 312道< / div > < div class = "stat-card__label" > 已录入指标< / div > < / div > < / div >
< div class = "stat-card" > < div class = "stat-card__icon green" > 🆕< / div > < div class = "stat-card__info" > < div class = "stat-card__value" > 18< / div > < div class = "stat-card__label" > 本月新增< / div > < / div > < / div >
< / div >
<!-- 左右分栏 -->
< div class = "master-detail" >
<!-- 左侧:餐品列表 -->
< div class = "panel-left" >
< div class = "panel-left__header" >
< div class = "panel-left__title" > 餐品列表< / div >
< div class = "panel-left__search" >
< input type = "text" placeholder = "搜索餐品名称/编号..." >
< button class = "btn btn-primary" style = "height:32px;padding:0 12px;font-size:var(--font-xs);" > 搜索< / button >
< / div >
< div class = "panel-left__filter" >
< select > < option > 全部分类< / option > < option > 主食< / option > < option > 荤菜< / option > < option > 素菜< / option > < option > 汤品< / option > < option > 小吃< / option > < / select >
< select > < option > 全部状态< / option > < option > 启用< / option > < option > 停用< / option > < / select >
< / div >
< / div >
< div class = "panel-left__actions" >
< a href = "din-dish-add.html" class = "btn btn-primary" > ➕ 新增餐品< / a >
< button class = "btn btn-default" > 📤 批量导入< / button >
< button class = "btn btn-default" onclick = "openDishCategoryDialog()" > 📂 餐品分类管理< / button >
< / div >
< div class = "food-list" id = "dishList" > < / div >
< div class = "panel-left__footer" >
< span > 共 486 条< / span >
< div style = "display:flex;gap:4px;" >
< button class = "page-btn" > ‹ < / button > < button class = "page-btn active" > 1< / button > < button class = "page-btn" > 2< / button > < button class = "page-btn" > 3< / button > < button class = "page-btn" > › < / button >
< / div >
< / div >
< / div >
<!-- 右侧:餐品详情 -->
< div class = "panel-right" >
< div class = "panel-right__header" >
< div class = "panel-right__food-title" >
< h2 id = "detailName" > 红烧肉< / h2 >
< span class = "code" id = "detailCode" > DISH001< / span >
< span class = "tag tag-green" id = "detailStatus" > 上架< / span >
< / div >
< div class = "detail-tabs" >
< div class = "detail-tab active" onclick = "switchDetailTab(0)" > 🍽️ 基本档案< / div >
< div class = "detail-tab" onclick = "switchDetailTab(1)" > 🧩 餐品构成< / div >
< div class = "detail-tab" onclick = "switchDetailTab(2)" > 🍳 烹饪工艺< / div >
< div class = "detail-tab" onclick = "switchDetailTab(3)" > 📊 营养指标< / div >
< div class = "detail-tab" onclick = "switchDetailTab(4)" > 👅 味道档案< / div >
< div class = "detail-tab" onclick = "switchDetailTab(5)" > 🫦 口感档案< / div >
< div class = "detail-tab" onclick = "switchDetailTab(6)" > 🎨 色泽档案< / div >
< / div >
< / div >
< div class = "panel-right__body" id = "detailBody" > < / div >
< / div >
< / div >
< / main >
< script >
// 餐品数据
const DISHES = [
{id:'DISH001',name:'红烧肉',icon:'🥩',category:'荤菜',tags:['高蛋白'],specs:[{name:'标准份',weight:200,price:12,cleanPrice:9,cleanSale:false,isDefault:true},{name:'小份',weight:120,price:8,cleanPrice:6,cleanSale:false},{name:'大份',weight:300,price:18,cleanPrice:13,cleanSale:false}],method:'炖',meal:'午/晚',allergen:'无',status:'启用',source:'手动添加',weightBasePrice:'6.00',weightVipPrice:'5.40',crowd:[{name:'成人',level:'推荐'},{name:'高血脂人群',level:'慎食'},{name:'高血压人群',level:'适量'}],crowdNote:'高血脂人群控制摄入量',
composition:[{name:'猪五花肉',netType:'红烧块',amount:160,pct:'80%',state:'净菜',type:'主材',allergen:'无',note:'—'},{name:'生姜',netType:'姜片',amount:5,pct:'2.5%',state:'净菜',type:'辅材',allergen:'无',note:'—'},{name:'生抽',netType:'调味汁',amount:15,pct:'7.5%',state:'原料',type:'调料',allergen:'含麸质',note:'酱油'},{name:'冰糖',netType:'糖浆',amount:10,pct:'5%',state:'原料',type:'调料',allergen:'无',note:'上色提味'},{name:'料酒',netType:'料酒汁',amount:10,pct:'5%',state:'原料',type:'调料',allergen:'无',note:'去腥'}],
nutri:{calorie:385,protein:18.2,carb:12.4,fat:28.6,vitC:0.8,mineral:42,fiber:0.3,sodium:486,nutriGrade:'偏差',note:'铁2.4mg、锌1.8mg'},
cook:{mainMethod:'炖',subMethod:'煎',heat:'中火→小火',duration:45,oil:15,salt:3,temp:'100→80',output:200,steps:6},
taste:{sour:1,sweet:3,bitter:1,spicy:1,salty:4,smell:4.2,flavorScore:3.8,flavorGrade:'良好'},
color:{mainColor:'红褐色',uniformity:4,gloss:4,freshness:4,appearance:4,colorScore:4.0,colorGrade:'良好'},
texture:{hardness:2,sticky:3,crispy:1,smooth:4,elastic:3,textureScore:3.6,textureGrade:'良好'}
},
{id:'DISH002',name:'清炒时蔬',icon:'🥬',category:'素菜',tags:['低脂','素食'],specs:[{name:'标准份',weight:150,price:6,cleanPrice:4.5,cleanSale:false,isDefault:true},{name:'小份',weight:100,price:4,cleanPrice:3,cleanSale:false}],method:'炒',meal:'早/午/晚',allergen:'无',status:'启用',source:'系统内置',weightBasePrice:'3.00',weightVipPrice:'2.70',crowd:[{name:'全人群',level:'推荐'},{name:'糖尿病人群',level:'推荐'},{name:'肾结石人群',level:'慎食'}],crowdNote:'肾结石人群慎食(草酸含量高)',
composition:[{name:'时令青菜',netType:'青菜段',amount:120,pct:'80%',state:'净菜',type:'主材',allergen:'无',note:'—'},{name:'蒜末',netType:'蒜末',amount:5,pct:'3.3%',state:'净菜',type:'调料',allergen:'无',note:'—'},{name:'食用油',netType:'净油',amount:8,pct:'5.3%',state:'原料',type:'调料',allergen:'无',note:'—'},{name:'食盐',netType:'盐粒',amount:2,pct:'1.3%',state:'原料',type:'调料',allergen:'无',note:'—'}],
nutri:{calorie:68,protein:2.1,carb:8.6,fat:3.2,vitC:28.5,mineral:86,fiber:2.4,sodium:186,nutriGrade:'达标',note:'铁1.2mg、钙45mg'},
cook:{mainMethod:'炒',subMethod:'—',heat:'大火',duration:5,oil:8,salt:2,temp:'200',output:150,steps:4},
taste:{sour:1,sweet:2,bitter:1,spicy:1,salty:2,smell:3.5,flavorScore:3.2,flavorGrade:'一般'},
color:{mainColor:'翠绿色',uniformity:5,gloss:4,freshness:5,appearance:4,colorScore:4.5,colorGrade:'优秀'},
texture:{hardness:3,sticky:1,crispy:4,smooth:3,elastic:2,textureScore:3.4,textureGrade:'良好'}
},
{id:'DISH003',name:'番茄鸡蛋汤',icon:'🍅',category:'汤品',tags:['低卡'],specs:[{name:'标准份',weight:300,price:5,cleanPrice:3.5,cleanSale:false,isDefault:true}],method:'煮',meal:'午/晚',allergen:'含蛋类',status:'启用',source:'系统内置',weightBasePrice:'1.67',weightVipPrice:'1.50',crowd:[{name:'全人群',level:'推荐'},{name:'儿童',level:'推荐'},{name:'老年人',level:'推荐'}],crowdNote:'',
composition:[{name:'番茄',netType:'番茄块',amount:150,pct:'50%',state:'净菜',type:'主材',allergen:'无',note:'—'},{name:'鸡蛋',netType:'鸡蛋液',amount:60,pct:'20%',state:'原料',type:'主材',allergen:'含蛋类',note:'—'},{name:'食用油',netType:'净油',amount:5,pct:'1.7%',state:'原料',type:'调料',allergen:'无',note:'—'},{name:'食盐',netType:'盐粒',amount:2,pct:'0.7%',state:'原料',type:'调料',allergen:'无',note:'—'}],
nutri:{calorie:45,protein:3.8,carb:4.2,fat:2.1,vitC:18.2,mineral:32,fiber:1.1,sodium:280,nutriGrade:'达标',note:'铁0.8mg、钾210mg'},
cook:{mainMethod:'煮',subMethod:'炒',heat:'中火',duration:12,oil:5,salt:2,temp:'100',output:300,steps:5},
taste:{sour:3,sweet:2,bitter:1,spicy:1,salty:2,smell:3.8,flavorScore:3.5,flavorGrade:'良好'},
color:{mainColor:'橙红色',uniformity:4,gloss:3,freshness:5,appearance:4,colorScore:4.0,colorGrade:'良好'},
texture:{hardness:1,sticky:2,crispy:1,smooth:5,elastic:2,textureScore:3.8,textureGrade:'良好'}
},
{id:'DISH004',name:'米饭',icon:'🍚',category:'主食',tags:['主食'],specs:[{name:'标准份',weight:200,price:3,cleanPrice:2,cleanSale:false,isDefault:true},{name:'小份',weight:100,price:2,cleanPrice:1.5,cleanSale:false},{name:'大份',weight:300,price:4,cleanPrice:3,cleanSale:false}],method:'蒸',meal:'早/午/晚',allergen:'无',status:'启用',source:'系统内置',weightBasePrice:'1.50',weightVipPrice:'1.35',crowd:[{name:'全人群',level:'推荐'},{name:'糖尿病人群',level:'适量'}],crowdNote:'糖尿病人群注意控制量',
composition:[{name:'大米',netType:'熟米饭',amount:100,pct:'100%',state:'原料',type:'主材',allergen:'无',note:'—'}],
nutri:{calorie:232,protein:4.8,carb:51.2,fat:0.6,vitC:0,mineral:12,fiber:0.4,sodium:3,nutriGrade:'达标',note:'—'},
cook:{mainMethod:'蒸',subMethod:'—',heat:'大火→中火',duration:30,oil:0,salt:0,temp:'100',output:200,steps:2},
taste:{sour:1,sweet:2,bitter:1,spicy:1,salty:1,smell:3.0,flavorScore:2.8,flavorGrade:'一般'},
color:{mainColor:'乳白色',uniformity:5,gloss:4,freshness:4,appearance:4,colorScore:4.2,colorGrade:'良好'},
texture:{hardness:2,sticky:3,crispy:1,smooth:3,elastic:2,textureScore:3.2,textureGrade:'一般'}
},
{id:'DISH005',name:'糖醋里脊',icon:'🍖',category:'荤菜',tags:['高糖'],specs:[{name:'标准份',weight:180,price:14,cleanPrice:10,cleanSale:false,isDefault:true},{name:'大份',weight:280,price:20,cleanPrice:14,cleanSale:false}],method:'炸',meal:'午',allergen:'无',status:'停用',source:'味养创新',weightBasePrice:'7.78',weightVipPrice:'7.00',crowd:[{name:'成人',level:'推荐'},{name:'糖尿病人群',level:'慎食'},{name:'高血脂人群',level:'适量'}],crowdNote:'糖尿病人群慎食,含糖量高',
composition:[{name:'猪里脊肉',netType:'里脊丝',amount:120,pct:'66.7%',state:'净菜',type:'主材',allergen:'无',note:'—'},{name:'淀粉',netType:'淀粉糊',amount:20,pct:'11.1%',state:'原料',type:'辅材',allergen:'无',note:'挂糊'},{name:'白糖',netType:'糖浆',amount:25,pct:'13.9%',state:'原料',type:'调料',allergen:'无',note:'糖醋汁'},{name:'食醋',netType:'调味汁',amount:15,pct:'8.3%',state:'原料',type:'调料',allergen:'无',note:'糖醋汁'}],
nutri:{calorie:420,protein:22.4,carb:38.2,fat:18.6,vitC:1.2,mineral:28,fiber:0.6,sodium:620,nutriGrade:'未达标',note:'铁1.8mg'},
cook:{mainMethod:'炸',subMethod:'炒',heat:'大火',duration:15,oil:50,salt:1,temp:'180',output:180,steps:7},
taste:{sour:4,sweet:4,bitter:1,spicy:1,salty:3,smell:4.0,flavorScore:4.2,flavorGrade:'良好'},
color:{mainColor:'金黄色',uniformity:4,gloss:5,freshness:4,appearance:5,colorScore:4.5,colorGrade:'优秀'},
texture:{hardness:3,sticky:1,crispy:5,smooth:4,elastic:3,textureScore:4.0,textureGrade:'良好'}
}
];
let currentDish = 0;
let currentTab = 0;
function renderDishList(){
document.getElementById('dishList').innerHTML = DISHES.map((d,i)=>`
< div class = "food-item${i===currentDish?' active':''}" onclick = "selectDish(${i})" >
< div class = "food-item__icon" > ${d.icon}< / div >
< div class = "food-item__info" >
< div class = "food-item__name" > ${d.name}< / div >
< div class = "food-item__meta" > < span > ${d.id}< / span > < span > ${d.category}< / span > < span class = "tag tag-${d.status==='启用'?'green':'gray'}" style = "margin:0;padding:1px 6px;" > ${d.status}< / span > < / div >
< / div >
< / div > `).join('');
}
function selectDish(idx){ currentDish=idx; renderDishList(); renderDetail(); }
function levelTag(level){
const map = {'推荐':'tag-green','适量':'tag-orange','慎食':'tag-red'};
return '< span class = "tag '+(map[level]||'tag-gray')+'" > '+level+'< / span > ';
}
function switchDetailTab(idx){ currentTab=idx; document.querySelectorAll('.detail-tab').forEach((t,i)=>t.classList.toggle('active',i===idx)); renderDetail(); }
function renderDetail(){
const d = DISHES[currentDish];
document.getElementById('detailName').textContent = d.name;
document.getElementById('detailCode').textContent = d.id;
const s = document.getElementById('detailStatus');
s.textContent = d.status; s.className='tag tag-'+(d.status==='启用'?'green':'gray');
const body = document.getElementById('detailBody');
const renderers = [renderBasic,renderComposition,renderCook,renderNutri,renderTaste,renderTexture,renderColor];
body.innerHTML = renderers[currentTab](d);
}
function renderBasic(d){
var specRows = (d.specs||[]).map(function(s){
var statusHtml = s.isDefault ? '< span class = "tag tag-blue" style = "font-size:11px;" > 默认< / span > ' : '';
var cleanPrice = (s.cleanPrice!==undefined & & s.cleanPrice!==null) ? parseFloat(s.cleanPrice).toFixed(2) : '—';
var cleanSaleActive = s.cleanSale === true;
var cleanSaleHtml = '< div class = "sale-toggle'+(cleanSaleActive?' active':'')+'" onclick = "toggleCleanSale(this)" > < span class = "sale-toggle__switch" > < / span > < span class = "sale-toggle__label" > '+(cleanSaleActive?'上架':'下架')+'< / span > < / div > ';
return '< tr > < td > '+s.name+'< / td > < td > '+s.weight+'< / td > < td > '+s.price.toFixed(2)+'< / td > < td > '+cleanPrice+'< / td > < td > '+cleanSaleHtml+'< / td > < td > '+statusHtml+'< / td > < / tr > ';
}).join('');
return `< div class = "info-section" > < div class = "info-section__title" > 基本信息 < span > < a class = "link" href = "din-dish-add.html?mode=edit&tab=0" > 编辑< / a > < / span > < / div >
< div class = "info-grid" >
< div class = "info-cell" > < div class = "info-cell__label" > 餐品编号< / div > < div class = "info-cell__value" > ${d.id}< / div > < / div >
< div class = "info-cell" > < div class = "info-cell__label" > 餐品分类< / div > < div class = "info-cell__value" > ${d.category}< / div > < / div >
< div class = "info-cell" > < div class = "info-cell__label" > 适用餐次< / div > < div class = "info-cell__value" > ${d.meal}< / div > < / div >
< div class = "info-cell" > < div class = "info-cell__label" > 过敏原< / div > < div class = "info-cell__value" > ${d.allergen}< / div > < / div >
< div class = "info-cell" > < div class = "info-cell__label" > 餐品标签< / div > < div class = "info-cell__value" > ${d.tags.map(t=>'< span class = "tag tag-blue" > '+t+'< / span > ').join('')}< / div > < / div >
< div class = "info-cell" > < div class = "info-cell__label" > 称重基础价(元/100g)< / div > < div class = "info-cell__value" > ${d.weightBasePrice||'—'}< / div > < / div >
< div class = "info-cell" > < div class = "info-cell__label" > 称重会员价(元/100g)< / div > < div class = "info-cell__value" > ${d.weightVipPrice||'—'}< / div > < / div >
< div class = "info-cell" > < div class = "info-cell__label" > 来源< / div > < div class = "info-cell__value" > < span class = "tag ${d.source==='系统内置'?'tag-blue':d.source==='味养创新'?'tag-orange':'tag-gray'}" > ${d.source||'—'}< / span > < / div > < / div >
< div class = "info-cell" > < div class = "info-cell__label" > 启用状态< / div > < div class = "info-cell__value" > < span class = "tag tag-${d.status==='启用'?'green':'gray'}" > ${d.status}< / span > < / div > < / div >
< / div > < / div >
< div class = "info-section" > < div class = "info-section__title" > 👥 适配人群< / div >
< div style = "display:flex;flex-wrap:wrap;gap:8px;margin-bottom:12px;" > ${(d.crowd||[]).map(function(c){return '< div style = "display:flex;align-items:center;gap:4px;" > < span style = "font-size:var(--font-sm);" > '+c.name+'< / span > '+levelTag(c.level)+'< / div > ';}).join('')}< / div >
${d.crowdNote?'< div style = "font-size:var(--font-sm);color:var(--text-secondary);background:#FFFBE6;padding:8px 12px;border-radius:var(--radius-sm);border:1px solid #FFE58F;" > ⚠️ '+d.crowdNote+'< / div > ':''}< / div >
< div class = "info-section" > < div class = "info-section__title" > 📐 餐品规格(共 ${(d.specs||[]).length} 项)< / div >
< table class = "info-table spec-detail-table" > < thead > < tr > < th > 规格< / th > < th > 单位重量(g)< / th > < th > 餐品售价(元/份)< / th > < th > 净菜包售价(元/份)< / th > < th > 外售净菜包< / th > < th > 状态< / th > < / tr > < / thead > < tbody > ${specRows}< / tbody > < / table > < / div >
< div class = "info-section" > < div class = "info-section__title" > 📷 菜品展示< / div >
< div class = "media-grid" >
< div class = "media-card" > < div class = "media-card__thumb" > 图片< / div > < / div >
< div class = "media-card" > < div class = "media-card__thumb" > 图片< / div > < / div >
< div class = "media-card" > < div class = "media-card__thumb" > 图片< / div > < / div >
< / div > < / div >
< div class = "info-section" > < div class = "info-section__title" > 🎬 制作流程< / div >
< div class = "media-grid" >
< div class = "media-card" > < div class = "media-card__thumb" > 🎬< / div > < / div >
< / div > < / div > `;
}
function renderComposition(d){
const rows = (d.composition||[]).map(c=>`< tr > < td > ${c.name}< / td > < td > ${c.netType}< / td > < td > ${c.amount}< / td > < td > ${c.pct}< / td > < td > < span class = "tag tag-${c.type==='主材'?'blue':c.type==='调料'?'orange':'gray'}" > ${c.type||'辅材'}< / span > < / td > < td > ${c.allergen}< / td > < td > ${c.note}< / td > < / tr > `).join('');
return `< div class = "info-section" > < div class = "info-section__title" > 食材构成(共 ${(d.composition||[]).length} 项) < span > < a class = "link" href = "din-dish-add.html?mode=edit&tab=1" > 编辑< / a > < / span > < / div >
< table class = "info-table" > < thead > < tr > < th > 食材名称< / th > < th > 净菜类型< / th > < th > 用量(g/份)< / th > < th > 占比(%)< / th > < th > 食材类型< / th > < th > 过敏原< / th > < th > 备注< / th > < / tr > < / thead > < tbody > ${rows}< / tbody > < / table > < / div > `;
}
function renderCook(d){
const c = d.cook;
return `< div class = "info-section" > < div class = "info-section__title" > 烹饪工艺 < span > < a class = "link" href = "din-dish-add.html?mode=edit&tab=2" > 编辑< / a > < / span > < / div >
< div class = "info-grid" >
< div class = "info-cell" > < div class = "info-cell__label" > 主烹饪法< / div > < div class = "info-cell__value" > ${c.mainMethod}< / div > < / div >
< div class = "info-cell" > < div class = "info-cell__label" > 辅烹饪法< / div > < div class = "info-cell__value" > ${c.subMethod}< / div > < / div >
< div class = "info-cell" > < div class = "info-cell__label" > 火候< / div > < div class = "info-cell__value" > ${c.heat}< / div > < / div >
< div class = "info-cell" > < div class = "info-cell__label" > 烹饪时长< / div > < div class = "info-cell__value" > ${c.duration}min< / div > < / div >
< div class = "info-cell" > < div class = "info-cell__label" > 油用量< / div > < div class = "info-cell__value" > ${c.oil}g< / div > < / div >
< div class = "info-cell" > < div class = "info-cell__label" > 盐用量< / div > < div class = "info-cell__value" > ${c.salt}g< / div > < / div >
< div class = "info-cell" > < div class = "info-cell__label" > 烹饪温度< / div > < div class = "info-cell__value" > ${c.temp}℃< / div > < / div >
< div class = "info-cell" > < div class = "info-cell__label" > 出品量< / div > < div class = "info-cell__value" > ${c.output}g< / div > < / div >
< div class = "info-cell" > < div class = "info-cell__label" > 工艺步骤数< / div > < div class = "info-cell__value" > ${c.steps}步< / div > < / div >
< / div > < / div > `;
}
function renderNutri(d){
const n = d.nutri;
return `< div class = "info-section" > < div class = "info-section__title" > 营养指标 < span > < a class = "link" href = "din-dish-add.html?mode=edit&tab=3" > 编辑< / a > < / span > < / div >
< div class = "info-grid" >
< div class = "info-cell" > < div class = "info-cell__label" > 热量 (kcal/100g)< / div > < div class = "info-cell__value" > ${n.calorie}< / div > < / div >
< div class = "info-cell" > < div class = "info-cell__label" > 蛋白质 (g)< / div > < div class = "info-cell__value" > ${n.protein}< / div > < / div >
< div class = "info-cell" > < div class = "info-cell__label" > 碳水化合物 (g)< / div > < div class = "info-cell__value" > ${n.carb}< / div > < / div >
< div class = "info-cell" > < div class = "info-cell__label" > 脂肪 (g)< / div > < div class = "info-cell__value" > ${n.fat}< / div > < / div >
< div class = "info-cell" > < div class = "info-cell__label" > 维生素C (mg)< / div > < div class = "info-cell__value" > ${n.vitC}< / div > < / div >
< div class = "info-cell" > < div class = "info-cell__label" > 矿物质 (mg)< / div > < div class = "info-cell__value" > ${n.mineral}< / div > < / div >
< div class = "info-cell" > < div class = "info-cell__label" > 膳食纤维 (g)< / div > < div class = "info-cell__value" > ${n.fiber}< / div > < / div >
< div class = "info-cell" > < div class = "info-cell__label" > 钠 (mg)< / div > < div class = "info-cell__value" > ${n.sodium}< / div > < / div >
< div class = "info-cell" > < div class = "info-cell__label" > 营养等级< / div > < div class = "info-cell__value" > ${n.nutriGrade==='达标'?'< span class = "tag tag-green" > 达标< / span > ':n.nutriGrade==='偏差'?'< span class = "tag tag-orange" > 偏差< / span > ':'< span class = "tag tag-red" > 未达标< / span > '}< / div > < / div >
< / div > < / div > `;
}
function renderTaste(d){
const t = d.taste;
const gradeTag = t.flavorGrade==='优秀'?'green':t.flavorGrade==='良好'?'blue':t.flavorGrade==='一般'?'orange':'red';
return `< div class = "info-section" > < div class = "info-section__title" > 味道档案 < span > < a class = "link" href = "din-dish-add.html?mode=edit&tab=4" > 编辑< / a > < / span > < / div >
< div class = "info-grid" >
< div class = "info-cell" > < div class = "info-cell__label" > 酸度 (1-5)< / div > < div class = "info-cell__value" > ${t.sour}< / div > < / div >
< div class = "info-cell" > < div class = "info-cell__label" > 甜度 (1-5)< / div > < div class = "info-cell__value" > ${t.sweet}< / div > < / div >
< div class = "info-cell" > < div class = "info-cell__label" > 苦度 (1-5)< / div > < div class = "info-cell__value" > ${t.bitter}< / div > < / div >
< div class = "info-cell" > < div class = "info-cell__label" > 辣度 (1-5)< / div > < div class = "info-cell__value" > ${t.spicy}< / div > < / div >
< div class = "info-cell" > < div class = "info-cell__label" > 咸度 (1-5)< / div > < div class = "info-cell__value" > ${t.salty}< / div > < / div >
< div class = "info-cell" > < div class = "info-cell__label" > 气味评分 (1-5)< / div > < div class = "info-cell__value" > ${t.smell}< / div > < / div >
< div class = "info-cell" > < div class = "info-cell__label" > 综合风味评分 (1-5)< / div > < div class = "info-cell__value" > ${t.flavorScore}< / div > < / div >
< div class = "info-cell" > < div class = "info-cell__label" > 综合评级< / div > < div class = "info-cell__value" > < span class = "tag tag-${gradeTag}" > ${t.flavorGrade}< / span > < / div > < / div >
< / div > < / div > `;
}
function renderColor(d){
const c = d.color;
const gradeTag = c.colorGrade==='优秀'?'green':c.colorGrade==='良好'?'blue':c.colorGrade==='一般'?'orange':'red';
return `< div class = "info-section" > < div class = "info-section__title" > 色泽档案 < span > < a class = "link" href = "din-dish-add.html?mode=edit&tab=5" > 编辑< / a > < / span > < / div >
< div class = "info-grid" >
< div class = "info-cell" > < div class = "info-cell__label" > 主色调< / div > < div class = "info-cell__value" > ${c.mainColor}< / div > < / div >
< div class = "info-cell" > < div class = "info-cell__label" > 色泽均匀度 (1-5)< / div > < div class = "info-cell__value" > ${c.uniformity}< / div > < / div >
< div class = "info-cell" > < div class = "info-cell__label" > 光泽度 (1-5)< / div > < div class = "info-cell__value" > ${c.gloss}< / div > < / div >
< div class = "info-cell" > < div class = "info-cell__label" > 新鲜度 (1-5)< / div > < div class = "info-cell__value" > ${c.freshness}< / div > < / div >
< div class = "info-cell" > < div class = "info-cell__label" > 卖相评分 (1-5)< / div > < div class = "info-cell__value" > ${c.appearance}< / div > < / div >
< div class = "info-cell" > < div class = "info-cell__label" > 综合色泽评分 (1-5)< / div > < div class = "info-cell__value" > ${c.colorScore}< / div > < / div >
< div class = "info-cell" > < div class = "info-cell__label" > 综合评级< / div > < div class = "info-cell__value" > < span class = "tag tag-${gradeTag}" > ${c.colorGrade}< / span > < / div > < / div >
< / div > < / div > `;
}
function renderTexture(d){
const t = d.texture;
const gradeTag = t.textureGrade==='优秀'?'green':t.textureGrade==='良好'?'blue':t.textureGrade==='一般'?'orange':'red';
return `< div class = "info-section" > < div class = "info-section__title" > 口感档案 < span > < a class = "link" href = "din-dish-add.html?mode=edit&tab=6" > 编辑< / a > < / span > < / div >
< div class = "info-grid" >
< div class = "info-cell" > < div class = "info-cell__label" > 软硬度 (1-5)< / div > < div class = "info-cell__value" > ${t.hardness}< / div > < / div >
< div class = "info-cell" > < div class = "info-cell__label" > 黏糯度 (1-5)< / div > < div class = "info-cell__value" > ${t.sticky}< / div > < / div >
< div class = "info-cell" > < div class = "info-cell__label" > 酥脆度 (1-5)< / div > < div class = "info-cell__value" > ${t.crispy}< / div > < / div >
< div class = "info-cell" > < div class = "info-cell__label" > 嫩滑度 (1-5)< / div > < div class = "info-cell__value" > ${t.smooth}< / div > < / div >
< div class = "info-cell" > < div class = "info-cell__label" > 弹性 (1-5)< / div > < div class = "info-cell__value" > ${t.elastic}< / div > < / div >
< div class = "info-cell" > < div class = "info-cell__label" > 综合口感评分 (1-5)< / div > < div class = "info-cell__value" > ${t.textureScore}< / div > < / div >
< div class = "info-cell" > < div class = "info-cell__label" > 综合评级< / div > < div class = "info-cell__value" > < span class = "tag tag-${gradeTag}" > ${t.textureGrade}< / span > < / div > < / div >
< / div > < / div > `;
}
function renderImages(d){
return `< div class = "info-section" > < div class = "info-section__title" > 图片库 < span > < button class = "btn btn-primary" style = "height:28px;font-size:var(--font-xs);padding:0 10px;" > 📤 上传图片< / button > < / span > < / div >
< div class = "media-grid" >
< div class = "media-card" > < div class = "media-card__thumb" > 📷< / div > < div class = "media-card__info" > < div class = "media-card__meta" > 800× 600 · 128KB · < span class = "link" > 预览< / span > < / div > < / div > < / div >
< div class = "media-card" > < div class = "media-card__thumb" > 📷< / div > < div class = "media-card__info" > < div class = "media-card__meta" > 1200× 900 · 256KB · < span class = "link" > 预览< / span > < / div > < / div > < / div >
< div class = "media-card" > < div class = "media-card__thumb" > 📷< / div > < div class = "media-card__info" > < div class = "media-card__meta" > 800× 600 · 96KB · < span class = "link" > 预览< / span > < / div > < / div > < / div >
< / div > < / div > `;
}
function renderVideos(d){
return `< div class = "info-section" > < div class = "info-section__title" > 视频库 < span > < button class = "btn btn-primary" style = "height:28px;font-size:var(--font-xs);padding:0 10px;" > 📤 上传视频< / button > < / span > < / div >
< div class = "media-grid" >
< div class = "media-card" > < div class = "media-card__thumb" > 🎬< / div > < div class = "media-card__info" > < div class = "media-card__title" > 标准制作流程< / div > < div class = "media-card__meta" > 8分32秒 · 256MB · < span class = "link" > 播放< / span > < / div > < / div > < / div >
< div class = "media-card" > < div class = "media-card__thumb" > 🎬< / div > < div class = "media-card__info" > < div class = "media-card__title" > 食材溯源故事< / div > < div class = "media-card__meta" > 2分15秒 · 86MB · < span class = "link" > 播放< / span > < / div > < / div > < / div >
< / div > < / div > `;
}
// 侧边栏折叠
function toggleSubgroup(header){header.parentElement.classList.toggle('open');}
// 切换外售净菜包上架/下架状态
function toggleCleanSale(el){
var active = el.classList.toggle('active');
var label = el.querySelector('.sale-toggle__label');
if(label) label.textContent = active ? '上架' : '下架';
}
(function(){var a=document.querySelector('.sidebar-item.active');if(!a)return;var s=a.closest('.sidebar-subgroup');if(s)s.classList.add('open');})();
// 初始化
renderDishList();
renderDetail();
/* ========== 餐品分类管理 ========== */
var nextDishCatId = 100;
var dishCategories = [
{id:1, name:'主食', code:'01', level:1, sort:1, status:'启用', parentId:null},
{id:2, name:'荤菜', code:'02', level:1, sort:2, status:'启用', parentId:null},
{id:3, name:'素菜', code:'03', level:1, sort:3, status:'启用', parentId:null},
{id:4, name:'汤品', code:'04', level:1, sort:4, status:'启用', parentId:null},
{id:5, name:'小吃', code:'05', level:1, sort:5, status:'启用', parentId:null},
{id:6, name:'饮品', code:'06', level:1, sort:6, status:'启用', parentId:null},
{id:7, name:'甜品', code:'07', level:1, sort:7, status:'启用', parentId:null},
{id:8, name:'套餐', code:'08', level:1, sort:8, status:'禁用', parentId:null}
];
var expandedDishCats = {};
var editingDishCatId = null;
var editingDishParentId = null;
var MAX_DISH_LEVEL = 2;
function openDishCategoryDialog(){
document.getElementById('dishCategoryDialog').classList.add('open');
renderDishCatTable();
}
function closeDishCategoryDialog(){
document.getElementById('dishCategoryDialog').classList.remove('open');
}
function toggleDishCatStatus(id){
var cat = dishCategories.find(function(c){return c.id===id;});
if(!cat) return;
cat.status = cat.status==='启用'?'禁用':'启用';
renderDishCatTable();
}
function toggleDishCatExpand(id){
expandedDishCats[id] = !expandedDishCats[id];
renderDishCatTable();
}
function getDishCatChildren(parentId){
return dishCategories.filter(function(c){return c.parentId===parentId;}).sort(function(a,b){return a.sort-b.sort;});
}
function renderDishCatTable(){
var tops = dishCategories.filter(function(c){return c.parentId===null;}).sort(function(a,b){return a.sort-b.sort;});
var html = '';
tops.forEach(function(cat){
html += renderDishCatRow(cat);
if(expandedDishCats[cat.id]){
getDishCatChildren(cat.id).forEach(function(child){
html += renderDishCatRow(child, true);
});
}
});
document.getElementById('dishCatTableBody').innerHTML = html || '< tr > < td colspan = "6" style = "text-align:center;color:var(--text-placeholder);padding:40px;" > 暂无分类数据< / td > < / tr > ';
}
function renderDishCatRow(cat, isChild){
var hasChildren = getDishCatChildren(cat.id).length > 0;
var isExpanded = expandedDishCats[cat.id];
var toggleHtml = hasChildren
? '< span class = "cat-toggle" onclick = "event.stopPropagation();toggleDishCatExpand('+cat.id+')" > '+(isExpanded?'− ':'+')+'< / span > '
: '< span class = "cat-toggle leaf" > +< / span > ';
var rowClass = isChild ? 'cat-row-l2' : '';
var activeClass = cat.status==='启用'?' active':'';
var statusLabel = cat.status==='启用'?'启用':'禁用';
var statusHtml = '< div class = "status-toggle'+activeClass+'" onclick = "event.stopPropagation();toggleDishCatStatus('+cat.id+')" > < span class = "status-toggle__switch" > < / span > < span class = "status-toggle__label" > '+statusLabel+'< / span > < / div > ';
var canAddChild = cat.level < MAX_DISH_LEVEL ;
var addChildBtn = canAddChild ? '< span class = "link" onclick = "openAddDishCat('+cat.id+')" > 新增下级< / span > ' : '';
return '< tr class = "'+rowClass+'" > < td class = "cat-name" > '+toggleHtml+cat.name+'< / td > < td > '+cat.code+'< / td > < td > '+cat.level+'< / td > < td > '+cat.sort+'< / td > < td > '+statusHtml+'< / td > < td class = "td-actions" > < span class = "link" onclick = "openEditDishCat('+cat.id+')" > 编辑< / span > < span class = "link" style = "color:var(--danger);" onclick = "deleteDishCat('+cat.id+')" > 删除< / span > '+addChildBtn+'< / td > < / tr > ';
}
function openAddDishCat(parentId){
editingDishCatId = null;
editingDishParentId = parentId || null;
document.getElementById('dishCatFormDialogTitle').textContent = parentId ? '新增下级分类' : '新增分类';
document.getElementById('dishCatFormName').value = '';
document.getElementById('dishCatFormCode').value = '';
document.getElementById('dishCatFormSort').value = '1';
document.getElementById('dishCatFormStatus').value = '启用';
document.getElementById('dishCatFormDialog').classList.add('open');
}
function openEditDishCat(id){
var cat = dishCategories.find(function(c){return c.id===id;});
if(!cat) return;
editingDishCatId = id;
editingDishParentId = cat.parentId;
document.getElementById('dishCatFormDialogTitle').textContent = '编辑分类';
document.getElementById('dishCatFormName').value = cat.name;
document.getElementById('dishCatFormCode').value = cat.code;
document.getElementById('dishCatFormSort').value = cat.sort;
document.getElementById('dishCatFormStatus').value = cat.status;
document.getElementById('dishCatFormDialog').classList.add('open');
}
function closeDishCatFormDialog(){
document.getElementById('dishCatFormDialog').classList.remove('open');
editingDishCatId = null;
editingDishParentId = null;
}
function saveDishCatForm(){
var name = document.getElementById('dishCatFormName').value.trim();
var code = document.getElementById('dishCatFormCode').value.trim();
var sort = parseInt(document.getElementById('dishCatFormSort').value) || 1;
var status = document.getElementById('dishCatFormStatus').value;
if(!name||!code){alert('请填写分类名称和分类编码');return;}
if(editingDishCatId){
var cat = dishCategories.find(function(c){return c.id===editingDishCatId;});
if(cat){cat.name=name;cat.code=code;cat.sort=sort;cat.status=status;}
} else {
var level = editingDishParentId ? 2 : 1;
dishCategories.push({id:nextDishCatId++,name:name,code:code,level:level,sort:sort,status:status,parentId:editingDishParentId});
if(editingDishParentId) expandedDishCats[editingDishParentId] = true;
}
closeDishCatFormDialog();
renderDishCatTable();
}
function deleteDishCat(id){
var cat = dishCategories.find(function(c){return c.id===id;});
if(!cat) return;
if(getDishCatChildren(id).length > 0){alert('该分类下存在子级分类,请先删除子级分类后再删除。');return;}
if(!confirm('确定要删除分类「'+cat.name+'」吗?删除后不可恢复。')) return;
dishCategories = dishCategories.filter(function(c){return c.id!==id;});
renderDishCatTable();
}
< / script >
<!-- 新增食材弹窗 -->
< div class = "dialog-mask" id = "ingredientDialog" >
< div class = "dialog" >
< div class = "dialog__header" >
< div class = "dialog__title" > 新增食材< / div >
< button class = "dialog__close" onclick = "closeIngredientDialog()" >
< svg width = "14" height = "14" viewBox = "0 0 14 14" fill = "none" > < path d = "M1 1l12 12M13 1L1 13" stroke = "currentColor" stroke-width = "1.5" stroke-linecap = "round" / > < / svg >
< / button >
< / div >
< div class = "dialog__body" >
< div class = "form-row" >
< div class = "form-group" > < label > 食材名称< span class = "required" > *< / span > < / label > < input class = "form-input" type = "text" placeholder = "请输入食材名称" > < / div >
< div class = "form-group" > < label > 净菜类型< span class = "required" > *< / span > < / label > < select class = "form-select" > < option > 请选择< / option > < option > 土豆丝< / option > < option > 土豆块< / option > < option > 土豆泥< / option > < option > 番茄块< / option > < option > 蒜末< / option > < / select > < / div >
< / div >
< div class = "form-row" >
< div class = "form-group" > < label > 用量(g/份)< span class = "required" > *< / span > < / label > < input class = "form-input" type = "number" placeholder = "请输入用量" > < / div >
< div class = "form-group" > < label > 加工状态< / label > < select class = "form-select" > < option > 请选择< / option > < option > 原料< / option > < option > 净菜< / option > < option > 半成品< / option > < / select > < / div >
< / div >
< div class = "form-row" >
< div class = "form-group" > < label > 食材类型< / label > < select class = "form-select" > < option > 辅材< / option > < option > 主材< / option > < option > 调料< / option > < / select > < / div >
< div class = "form-group" > < label > 过敏原< / label > < input class = "form-input" type = "text" placeholder = "无则填无" > < / div >
< / div >
< div class = "form-group" > < label > 备注< / label > < input class = "form-input" type = "text" placeholder = "请输入备注信息" > < / div >
< / div >
< div class = "dialog__footer" >
< button class = "btn btn-default" onclick = "closeIngredientDialog()" > 取消< / button >
< button class = "btn btn-primary" > 确定< / button >
< / div >
< / div >
< / div >
< script >
function openIngredientDialog(){document.getElementById('ingredientDialog').classList.add('open');}
function closeIngredientDialog(){document.getElementById('ingredientDialog').classList.remove('open');}
< / script >
<!-- 餐品分类管理弹窗 -->
< div class = "dialog-mask" id = "dishCategoryDialog" >
< div class = "dialog" style = "width:820px;" >
< div class = "dialog__header" >
< div class = "dialog__title" > 餐品分类管理< / div >
< button class = "dialog__close" onclick = "closeDishCategoryDialog()" > ✕< / button >
< / div >
< div class = "dialog__body" >
<!-- 工具栏 -->
< div style = "margin-bottom:12px;" >
< button class = "btn btn-primary" onclick = "openAddDishCat()" style = "height:30px;font-size:var(--font-xs);" > + 新增一级分类< / button >
< / div >
<!-- 分类表格 -->
< div style = "overflow-x:auto;" >
< table class = "cat-table" >
< thead > < tr > < th style = "width:180px;" > 分类名称< / th > < th style = "width:100px;" > 分类编码< / th > < th style = "width:60px;" > 层级< / th > < th style = "width:60px;" > 排序< / th > < th style = "width:80px;" > 状态< / th > < th style = "width:180px;" > 操作< / th > < / tr > < / thead >
< tbody id = "dishCatTableBody" > < / tbody >
< / table >
< / div >
< / div >
< div class = "dialog__footer" >
< button class = "btn btn-default" onclick = "closeDishCategoryDialog()" > 关闭< / button >
< / div >
< / div >
< / div >
<!-- 餐品分类表单子弹窗 -->
< div class = "dialog-mask" id = "dishCatFormDialog" >
< div class = "dialog" style = "width:480px;" >
< div class = "dialog__header" >
< div class = "dialog__title" id = "dishCatFormDialogTitle" > 新增分类< / div >
< button class = "dialog__close" onclick = "closeDishCatFormDialog()" > ✕< / button >
< / div >
< div class = "dialog__body" >
< div class = "form-group" > < label > 分类名称< span class = "required" > *< / span > < / label > < input class = "form-input" id = "dishCatFormName" placeholder = "请输入分类名称" > < / div >
< div class = "form-row" >
< div class = "form-group" > < label > 分类编码< span class = "required" > *< / span > < / label > < input class = "form-input" id = "dishCatFormCode" placeholder = "请输入分类编码" > < / div >
< div class = "form-group" > < label > 排序< / label > < input class = "form-input" id = "dishCatFormSort" type = "number" value = "1" > < / div >
< / div >
< div class = "form-group" > < label > 状态< / label > < select class = "form-select" id = "dishCatFormStatus" > < option > 启用< / option > < option > 禁用< / option > < / select > < / div >
< / div >
< div class = "dialog__footer" >
< button class = "btn btn-default" onclick = "closeDishCatFormDialog()" > 取消< / button >
< button class = "btn btn-primary" onclick = "saveDishCatForm()" > 保存< / button >
< / div >
< / div >
< / div >
< / body >
< / html >