feat: 营养用餐模块交互增强——订单排队、食谱管理、生产计划详情页
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -237,7 +237,6 @@ tbody tr:hover td.td-actions{background:#F8FBFF;}
|
||||
</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">📤 批量导入</button>
|
||||
</div>
|
||||
<div class="food-list" id="dishList"></div>
|
||||
|
||||
@@ -235,7 +235,6 @@ body{font-family:-apple-system,BlinkMacSystemFont,'PingFang SC','Microsoft YaHei
|
||||
<div class="panel-left__actions">
|
||||
<a href="din-ingredient-add.html" class="btn btn-primary">➕ 新增食物</a>
|
||||
<a class="btn btn-primary">🖥 分类管理</a>
|
||||
<button class="btn btn-default">🔄 同步国标库</button>
|
||||
</div>
|
||||
<div class="food-list">
|
||||
<div class="food-item active" onclick="selectFood(0)">
|
||||
|
||||
@@ -100,9 +100,10 @@ tbody tr:hover{background:#F8FBFF;}
|
||||
.summary-row td{background:#FAFAFA;font-weight:600;}
|
||||
.action-bar{display:flex;align-items:center;gap:8px;margin-bottom:16px;}
|
||||
/* 操作列固定右侧 */
|
||||
thead th:last-child,tbody td.td-actions{position:sticky;right:0;background:#fff;box-shadow:-4px 0 8px rgba(0,0,0,0.04);z-index:2;white-space:nowrap;}
|
||||
thead th:last-child{background:#FAFAFA;}
|
||||
tbody tr:hover td.td-actions{background:#F8FBFF;}
|
||||
thead th:last-child{position:sticky;right:0;background:#FAFAFA;box-shadow:-4px 0 8px rgba(0,0,0,0.04);z-index:2;white-space:nowrap;}
|
||||
tbody td:last-child{position:sticky;right:0;background:#fff;box-shadow:-4px 0 8px rgba(0,0,0,0.04);z-index:2;white-space:nowrap;}
|
||||
tbody tr:hover td:last-child{background:#F8FBFF;}
|
||||
.summary-row td:last-child{background:#FAFAFA;}
|
||||
|
||||
/* 弹窗样式 */
|
||||
.modal-overlay{position:fixed;top:0;left:0;right:0;bottom:0;background:rgba(0,0,0,.45);z-index:1000;display:flex;align-items:center;justify-content:center;animation:modalFadeIn .2s ease;}
|
||||
@@ -123,6 +124,26 @@ tbody tr:hover td.td-actions{background:#F8FBFF;}
|
||||
.modal-table tbody td{padding:10px 12px;border-bottom:1px solid var(--border);color:var(--text-primary);}
|
||||
.modal-table tbody tr:last-child td{border-bottom:none;}
|
||||
.modal-table tbody tr:hover{background:#F8FBFF;}
|
||||
|
||||
/* 右侧抽屉 */
|
||||
.drawer-overlay{position:fixed;top:0;left:0;right:0;bottom:0;background:rgba(0,0,0,.45);z-index:1000;animation:modalFadeIn .2s ease;}
|
||||
.drawer-overlay.closing{animation:modalFadeOut .2s ease forwards;}
|
||||
.drawer{position:fixed;top:0;right:0;bottom:0;width:520px;max-width:90vw;background:#fff;box-shadow:-6px 0 24px rgba(0,0,0,.12);display:flex;flex-direction:column;z-index:1001;animation:drawerSlideIn .25s ease;}
|
||||
.drawer-overlay.closing .drawer{animation:drawerSlideOut .2s ease forwards;}
|
||||
@keyframes drawerSlideIn{from{transform:translateX(100%)}to{transform:translateX(0)}}
|
||||
@keyframes drawerSlideOut{from{transform:translateX(0)}to{transform:translateX(100%)}}
|
||||
.drawer__header{display:flex;align-items:center;justify-content:space-between;padding:16px 24px;border-bottom:1px solid var(--border);flex-shrink:0;}
|
||||
.drawer__title{font-size:var(--font-lg);font-weight:600;color:var(--text-primary);}
|
||||
.drawer__close{width:32px;height:32px;border:none;background:none;font-size:20px;cursor:pointer;border-radius:var(--radius-sm);color:var(--text-secondary);display:flex;align-items:center;justify-content:center;}
|
||||
.drawer__close:hover{background:#f5f5f5;color:var(--text-primary);}
|
||||
.drawer__body{padding:0 24px 24px;overflow-y:auto;flex:1;}
|
||||
.drawer-section{margin-top:20px;}
|
||||
.drawer-section__title{font-size:var(--font-sm);font-weight:600;color:var(--text-primary);padding-bottom:8px;border-bottom:1px solid var(--border);margin-bottom:12px;display:flex;align-items:center;gap:6px;}
|
||||
.drawer-section__title::before{content:'';display:inline-block;width:3px;height:14px;background:var(--primary);border-radius:2px;}
|
||||
.drawer-fields{display:grid;grid-template-columns:1fr 1fr;gap:12px 24px;}
|
||||
.drawer-field{display:flex;flex-direction:column;gap:2px;}
|
||||
.drawer-field__label{font-size:var(--font-xs);color:var(--text-placeholder);}
|
||||
.drawer-field__value{font-size:var(--font-sm);color:var(--text-primary);font-weight:500;min-height:22px;}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
@@ -227,17 +248,18 @@ tbody tr:hover td.td-actions{background:#F8FBFF;}
|
||||
<!-- Tab 切换栏 -->
|
||||
<div class="page-tabs">
|
||||
<div class="page-tab active" onclick="switchTab(0)">📡 实时监控</div>
|
||||
<div class="page-tab" onclick="switchTab(1)">📊 累计汇总</div>
|
||||
<div class="page-tab" onclick="switchTab(1)">📊 累计汇总(按餐线)</div>
|
||||
<div class="page-tab" onclick="switchTab(2)">⚖️ 累计汇总(按秤台)</div>
|
||||
</div>
|
||||
|
||||
<!-- Tab1: 实时监控 -->
|
||||
<div class="tab-panel active">
|
||||
<div class="filter-bar">
|
||||
<div class="filter-item"><label>秤台编号</label><input class="filter-input" type="text" placeholder="请输入秤台编号"></div>
|
||||
<div class="filter-item"><label>秤台状态</label><select class="filter-select"><option>全部</option><option>正常</option><option>无网络</option><option>未开机</option></select></div>
|
||||
<div class="filter-item"><label>餐线编号</label><select class="filter-select"><option>全部</option><option>A区早餐线</option><option>B区早餐线</option><option>A区中餐线</option><option>B区中餐线</option><option>C区快餐线</option><option>D区晚餐线</option></select></div>
|
||||
<div class="filter-item"><label>餐次</label><select class="filter-select"><option>全部</option><option>早餐</option><option>午餐</option><option>晚餐</option></select></div>
|
||||
<div class="filter-item"><label>食堂</label><select class="filter-select" id="filterCanteen" onchange="updateLineOptions()"><option value="">全部</option><option value="1">一号食堂</option><option value="2">二号食堂</option><option value="3">三号食堂</option></select></div>
|
||||
<div class="filter-item"><label>餐线</label><select class="filter-select" id="filterLine"><option value="">全部</option><option data-canteen="1">A区早餐线</option><option data-canteen="1">A区中餐线</option><option data-canteen="1">B区中餐线</option><option data-canteen="2">B区早餐线</option><option data-canteen="2">C区快餐线</option><option data-canteen="3">D区晚餐线</option></select></div>
|
||||
<div class="filter-item"><label>日期</label><input class="filter-input" type="date" value="2026-05-19" style="min-width:140px;"></div>
|
||||
<div class="filter-item"><label>餐次</label><select class="filter-select"><option>全部</option><option>早餐</option><option>中餐</option><option>晚餐</option><option>加餐</option></select></div>
|
||||
<div class="filter-item"><label>称台编号</label><input class="filter-input" type="text" placeholder="请输入称台编号" style="min-width:140px;"></div>
|
||||
<button class="btn btn-primary">查询</button>
|
||||
<button class="btn btn-default">重置</button>
|
||||
</div>
|
||||
@@ -253,15 +275,15 @@ tbody tr:hover td.td-actions{background:#F8FBFF;}
|
||||
<div class="table-card__content">
|
||||
<table>
|
||||
<thead>
|
||||
<tr><th>秤台编号</th><th>秤台状态</th><th>秤台类型</th><th>餐线编号</th><th>餐次</th><th>上餐类型</th><th>开机时间</th><th>上餐时间</th><th>菜品名称</th><th>菜品单价</th><th>应收金额</th><th>实时重量(kg)</th><th>累计取餐重量</th><th>累计上餐生重(kg)</th><th>累计上餐重量</th><th>最高温度</th><th>最低温度</th><th>保鲜时间</th><th>取餐人次</th><th>取餐视频</th><th>上餐视频</th><th>操作</th></tr>
|
||||
<tr><th>日期</th><th>食堂</th><th>餐线名称</th><th>餐次</th><th>秤台编号</th><th>秤台状态</th><th>称台类型</th><th>上餐类型</th><th>开机时间</th><th>上餐时间</th><th>餐品名称</th><th>餐品单价</th><th>应收金额</th><th>实时重量(kg)</th><th>累计取餐重量</th><th>累计上餐生重(kg)</th><th>累计上餐重量</th><th>最高温度</th><th>最低温度</th><th>保鲜时间</th><th>取餐人次</th><th>取餐视频</th><th>上餐视频</th><th>操作</th></tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr><td>00022号秤</td><td><span class="tag tag-green">正常</span></td><td><span class="tag tag-blue">餐线秤</span></td><td>A区早餐线</td><td>早餐</td><td><span class="tag tag-green">开餐</span></td><td>06:50</td><td>07:28</td><td>小米粥</td><td>¥5</td><td>¥1,600</td><td>12.6</td><td><a class="link">9.8kg</a></td><td>14.2</td><td><a class="link">12.6kg</a></td><td>68℃</td><td>55℃</td><td>09:30</td><td>320人</td><td><a class="link">▶ 取餐</a></td><td><a class="link">▶ 上餐</a></td><td class="td-actions"><a class="link">查看</a> <a class="link">编辑</a></td></tr>
|
||||
<tr><td>00023号秤</td><td><span class="tag tag-green">正常</span></td><td><span class="tag tag-blue">餐线秤</span></td><td>B区早餐线</td><td>早餐</td><td><span class="tag tag-green">开餐</span></td><td>06:55</td><td>07:35</td><td>燕麦粥</td><td>¥4</td><td>¥1,144</td><td>8.4</td><td><a class="link">6.2kg</a></td><td>9.6</td><td><a class="link">8.4kg</a></td><td>65℃</td><td>55℃</td><td>09:30</td><td>286人</td><td><a class="link">▶ 取餐</a></td><td><a class="link">▶ 上餐</a></td><td class="td-actions"><a class="link">查看</a> <a class="link">编辑</a></td></tr>
|
||||
<tr><td>00025号秤</td><td><span class="tag tag-green">正常</span></td><td><span class="tag tag-blue">餐线秤</span></td><td>A区中餐线</td><td>午餐</td><td><span class="tag tag-green">开餐</span></td><td>10:30</td><td>11:30</td><td>宫保鸡丁</td><td>¥14</td><td>¥6,804</td><td>38.2</td><td><a class="link">31.6kg</a></td><td>44.0</td><td><a class="link">38.2kg</a></td><td>75℃</td><td>71℃</td><td>13:30</td><td>486人</td><td><a class="link">▶ 取餐</a></td><td><a class="link">▶ 上餐</a></td><td class="td-actions"><a class="link">查看</a> <a class="link">编辑</a></td></tr>
|
||||
<tr><td>00026号秤</td><td><span class="tag tag-green">正常</span></td><td><span class="tag tag-blue">餐线秤</span></td><td>B区中餐线</td><td>午餐</td><td><span class="tag tag-green">开餐</span></td><td>10:35</td><td>11:38</td><td>红烧肉</td><td>¥16</td><td>¥6,592</td><td>42.6</td><td><a class="link">38.4kg</a></td><td>48.5</td><td><a class="link">42.6kg</a></td><td>72℃</td><td>68℃</td><td>13:30</td><td>412人</td><td><a class="link">▶ 取餐</a></td><td><a class="link">▶ 上餐</a></td><td class="td-actions"><a class="link">查看</a> <a class="link">编辑</a></td></tr>
|
||||
<tr><td>00027号秤</td><td><span class="tag tag-orange">无网络</span></td><td><span class="tag tag-gray">档口秤</span></td><td>C区快餐线</td><td>午餐</td><td><span class="tag tag-blue">加餐</span></td><td>10:40</td><td>12:12</td><td>番茄炒蛋</td><td>¥8</td><td>¥1,024</td><td>16.8</td><td><a class="link">14.2kg</a></td><td>18.6</td><td><a class="link">16.8kg</a></td><td>74℃</td><td>70℃</td><td>13:30</td><td>128人</td><td><a class="link">▶ 取餐</a></td><td><a class="link">▶ 上餐</a></td><td class="td-actions"><a class="link">查看</a> <a class="link">编辑</a></td></tr>
|
||||
<tr><td>00028号秤</td><td><span class="tag tag-gray">未开机</span></td><td><span class="tag tag-gray">档口秤</span></td><td>D区晚餐线</td><td>晚餐</td><td><span class="tag tag-gray">待上餐</span></td><td>—</td><td>—</td><td>—</td><td>—</td><td>—</td><td>—</td><td>—</td><td>—</td><td>—</td><td>—</td><td>—</td><td>19:30</td><td>—</td><td>—</td><td>—</td><td class="td-actions"><a class="link">查看</a> <a class="link">编辑</a></td></tr>
|
||||
<tr><td>2026-05-19</td><td>一号食堂</td><td>A区早餐线</td><td>早餐</td><td>00022号秤</td><td><span class="tag tag-green">正常</span></td><td><span class="tag tag-blue">单称</span></td><td><span class="tag tag-green">开餐</span></td><td>06:50</td><td>07:28</td><td>小米粥</td><td>¥5</td><td>¥1,600</td><td>12.6</td><td><a class="link">9.8kg</a></td><td>14.2</td><td><a class="link">12.6kg</a></td><td>68℃</td><td>55℃</td><td>09:30</td><td>320人</td><td><a class="link">▶ 取餐</a></td><td><a class="link">▶ 上餐</a></td><td class="td-actions"><a class="link">详情</a> <a class="link">编辑</a></td></tr>
|
||||
<tr><td>2026-05-19</td><td>二号食堂</td><td>B区早餐线</td><td>早餐</td><td>00023号秤</td><td><span class="tag tag-green">正常</span></td><td><span class="tag tag-blue">双称</span></td><td><span class="tag tag-green">开餐</span></td><td>06:55</td><td>07:35</td><td>燕麦粥</td><td>¥4</td><td>¥1,144</td><td>8.4</td><td><a class="link">6.2kg</a></td><td>9.6</td><td><a class="link">8.4kg</a></td><td>65℃</td><td>55℃</td><td>09:30</td><td>286人</td><td><a class="link">▶ 取餐</a></td><td><a class="link">▶ 上餐</a></td><td class="td-actions"><a class="link">详情</a> <a class="link">编辑</a></td></tr>
|
||||
<tr><td>2026-05-19</td><td>一号食堂</td><td>A区中餐线</td><td>中餐</td><td>00025号秤</td><td><span class="tag tag-green">正常</span></td><td><span class="tag tag-blue">单称</span></td><td><span class="tag tag-green">开餐</span></td><td>10:30</td><td>11:30</td><td>宫保鸡丁</td><td>¥14</td><td>¥6,804</td><td>38.2</td><td><a class="link">31.6kg</a></td><td>44.0</td><td><a class="link">38.2kg</a></td><td>75℃</td><td>71℃</td><td>13:30</td><td>486人</td><td><a class="link">▶ 取餐</a></td><td><a class="link">▶ 上餐</a></td><td class="td-actions"><a class="link">详情</a> <a class="link">编辑</a></td></tr>
|
||||
<tr><td>2026-05-19</td><td>一号食堂</td><td>B区中餐线</td><td>中餐</td><td>00026号秤</td><td><span class="tag tag-green">正常</span></td><td><span class="tag tag-blue">双称</span></td><td><span class="tag tag-green">开餐</span></td><td>10:35</td><td>11:38</td><td>红烧肉</td><td>¥16</td><td>¥6,592</td><td>42.6</td><td><a class="link">38.4kg</a></td><td>48.5</td><td><a class="link">42.6kg</a></td><td>72℃</td><td>68℃</td><td>13:30</td><td>412人</td><td><a class="link">▶ 取餐</a></td><td><a class="link">▶ 上餐</a></td><td class="td-actions"><a class="link">详情</a> <a class="link">编辑</a></td></tr>
|
||||
<tr><td>2026-05-19</td><td>二号食堂</td><td>C区快餐线</td><td>中餐</td><td>00027号秤</td><td><span class="tag tag-orange">无网络</span></td><td><span class="tag tag-gray">单称</span></td><td><span class="tag tag-blue">加餐</span></td><td>10:40</td><td>12:12</td><td>番茄炒蛋</td><td>¥8</td><td>¥1,024</td><td>16.8</td><td><a class="link">14.2kg</a></td><td>18.6</td><td><a class="link">16.8kg</a></td><td>74℃</td><td>70℃</td><td>13:30</td><td>128人</td><td><a class="link">▶ 取餐</a></td><td><a class="link">▶ 上餐</a></td><td class="td-actions"><a class="link">详情</a> <a class="link">编辑</a></td></tr>
|
||||
<tr><td>2026-05-19</td><td>三号食堂</td><td>D区晚餐线</td><td>晚餐</td><td>00028号秤</td><td><span class="tag tag-gray">未开机</span></td><td><span class="tag tag-gray">双称</span></td><td><span class="tag tag-gray">待上餐</span></td><td>—</td><td>—</td><td>—</td><td>—</td><td>—</td><td>—</td><td>—</td><td>—</td><td>—</td><td>—</td><td>—</td><td>19:30</td><td>—</td><td>—</td><td>—</td><td class="td-actions"><a class="link">详情</a> <a class="link">编辑</a></td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
@@ -279,9 +301,10 @@ tbody tr:hover td.td-actions{background:#F8FBFF;}
|
||||
<!-- Tab2: 累计汇总 -->
|
||||
<div class="tab-panel">
|
||||
<div class="filter-bar">
|
||||
<div class="filter-item"><label>统计日期</label><input class="filter-input" type="date"></div>
|
||||
<div class="filter-item"><label>餐线编号</label><select class="filter-select"><option>全部</option><option>A区中餐线</option><option>B区中餐线</option><option>A区早餐线</option></select></div>
|
||||
<div class="filter-item"><label>餐次</label><select class="filter-select"><option>全部</option><option>早餐</option><option>午餐</option><option>晚餐</option></select></div>
|
||||
<div class="filter-item"><label>统计日期</label><input class="filter-input" type="date" value="2026-05-19" style="min-width:140px;"></div>
|
||||
<div class="filter-item"><label>食堂</label><select class="filter-select" id="filterCanteen2" onchange="updateLineOptions2()"><option value="">全部</option><option value="1">一号食堂</option><option value="2">二号食堂</option><option value="3">三号食堂</option></select></div>
|
||||
<div class="filter-item"><label>餐线</label><select class="filter-select" id="filterLine2"><option value="">全部</option><option data-canteen="1">A区早餐线</option><option data-canteen="1">A区中餐线</option><option data-canteen="1">B区中餐线</option><option data-canteen="2">B区早餐线</option><option data-canteen="2">C区快餐线</option><option data-canteen="3">D区晚餐线</option></select></div>
|
||||
<div class="filter-item"><label>餐次</label><select class="filter-select"><option>全部</option><option>早餐</option><option>中餐</option><option>晚餐</option><option>加餐</option></select></div>
|
||||
<button class="btn btn-primary">查询</button>
|
||||
<button class="btn btn-default">重置</button>
|
||||
</div>
|
||||
@@ -296,17 +319,17 @@ tbody tr:hover td.td-actions{background:#F8FBFF;}
|
||||
<div class="table-card__content">
|
||||
<table>
|
||||
<thead>
|
||||
<tr><th>统计日期</th><th>餐线编号</th><th>餐次</th><th>上餐菜品数</th><th>累计取餐重量(kg)</th><th>累计上餐重量(kg)</th><th>累计应收金额</th><th>取餐人次</th><th>平均取餐重量(g/人)</th><th>最高温度</th><th>最低温度</th><th>异常次数</th><th>操作</th></tr>
|
||||
<tr><th>统计日期</th><th>食堂</th><th>餐线名称</th><th>餐次</th><th>餐品数量</th><th>累计取餐重量(kg)</th><th>累计上餐重量(kg)</th><th>累计应收金额</th><th>取餐人次</th><th>平均取餐重量(g/人)</th><th>最高温度</th><th>最低温度</th><th>异常次数</th><th>操作</th></tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr class="summary-row"><td>汇总</td><td>—</td><td>—</td><td>84道</td><td>1,286</td><td>1,540</td><td>¥58,420</td><td>5,612人</td><td>229g</td><td>—</td><td>—</td><td>3次</td><td><a class="link">查看</a> <a class="link">编辑</a></td></tr>
|
||||
<tr><td>2026-04-28</td><td>A区中餐线</td><td>午餐</td><td>12道</td><td>256</td><td>312</td><td>¥14,280</td><td>1,140人</td><td>225g</td><td>78℃</td><td>68℃</td><td>0次</td><td class="td-actions"><a class="link">查看</a> <a class="link">编辑</a></td></tr>
|
||||
<tr><td>2026-04-28</td><td>B区中餐线</td><td>午餐</td><td>10道</td><td>218</td><td>268</td><td>¥12,640</td><td>980人</td><td>222g</td><td>76℃</td><td>66℃</td><td>1次</td><td class="td-actions"><a class="link">查看</a> <a class="link">编辑</a></td></tr>
|
||||
<tr><td>2026-04-28</td><td>A区早餐线</td><td>早餐</td><td>8道</td><td>148</td><td>182</td><td>¥7,400</td><td>980人</td><td>151g</td><td>70℃</td><td>55℃</td><td>0次</td><td class="td-actions"><a class="link">查看</a> <a class="link">编辑</a></td></tr>
|
||||
<tr><td>2026-04-27</td><td>A区中餐线</td><td>午餐</td><td>12道</td><td>248</td><td>304</td><td>¥13,860</td><td>1,100人</td><td>226g</td><td>77℃</td><td>67℃</td><td>0次</td><td class="td-actions"><a class="link">查看</a> <a class="link">编辑</a></td></tr>
|
||||
<tr><td>2026-04-27</td><td>B区中餐线</td><td>午餐</td><td>10道</td><td>210</td><td>258</td><td>¥12,180</td><td>960人</td><td>219g</td><td>75℃</td><td>65℃</td><td>1次</td><td class="td-actions"><a class="link">查看</a> <a class="link">编辑</a></td></tr>
|
||||
<tr><td>2026-04-27</td><td>A区早餐线</td><td>早餐</td><td>8道</td><td>142</td><td>176</td><td>¥7,100</td><td>920人</td><td>154g</td><td>69℃</td><td>54℃</td><td>0次</td><td class="td-actions"><a class="link">查看</a> <a class="link">编辑</a></td></tr>
|
||||
<tr><td>2026-04-26</td><td>A区中餐线</td><td>午餐</td><td>11道</td><td>212</td><td>260</td><td>¥11,860</td><td>960人</td><td>221g</td><td>76℃</td><td>66℃</td><td>1次</td><td class="td-actions"><a class="link">查看</a> <a class="link">编辑</a></td></tr>
|
||||
<tr class="summary-row"><td>汇总</td><td>—</td><td>—</td><td>—</td><td>84道</td><td>1,286</td><td>1,540</td><td>¥58,420</td><td>5,612人</td><td>229g</td><td>—</td><td>—</td><td>3次</td><td>—</td></tr>
|
||||
<tr><td>2026-05-19</td><td>一号食堂</td><td>A区中餐线</td><td>中餐</td><td>12道</td><td>256</td><td>312</td><td>¥14,280</td><td>1,140人</td><td>225g</td><td>78℃</td><td>68℃</td><td>0次</td><td class="td-actions"><a class="link">详情</a> <a class="link">编辑</a></td></tr>
|
||||
<tr><td>2026-05-19</td><td>一号食堂</td><td>B区中餐线</td><td>中餐</td><td>10道</td><td>218</td><td>268</td><td>¥12,640</td><td>980人</td><td>222g</td><td>76℃</td><td>66℃</td><td>1次</td><td class="td-actions"><a class="link">详情</a> <a class="link">编辑</a></td></tr>
|
||||
<tr><td>2026-05-19</td><td>一号食堂</td><td>A区早餐线</td><td>早餐</td><td>8道</td><td>148</td><td>182</td><td>¥7,400</td><td>980人</td><td>151g</td><td>70℃</td><td>55℃</td><td>0次</td><td class="td-actions"><a class="link">详情</a> <a class="link">编辑</a></td></tr>
|
||||
<tr><td>2026-05-18</td><td>一号食堂</td><td>A区中餐线</td><td>中餐</td><td>12道</td><td>248</td><td>304</td><td>¥13,860</td><td>1,100人</td><td>226g</td><td>77℃</td><td>67℃</td><td>0次</td><td class="td-actions"><a class="link">详情</a> <a class="link">编辑</a></td></tr>
|
||||
<tr><td>2026-05-18</td><td>一号食堂</td><td>B区中餐线</td><td>中餐</td><td>10道</td><td>210</td><td>258</td><td>¥12,180</td><td>960人</td><td>219g</td><td>75℃</td><td>65℃</td><td>1次</td><td class="td-actions"><a class="link">详情</a> <a class="link">编辑</a></td></tr>
|
||||
<tr><td>2026-05-18</td><td>二号食堂</td><td>B区早餐线</td><td>早餐</td><td>8道</td><td>142</td><td>176</td><td>¥7,100</td><td>920人</td><td>154g</td><td>69℃</td><td>54℃</td><td>0次</td><td class="td-actions"><a class="link">详情</a> <a class="link">编辑</a></td></tr>
|
||||
<tr><td>2026-05-17</td><td>一号食堂</td><td>A区中餐线</td><td>中餐</td><td>11道</td><td>212</td><td>260</td><td>¥11,860</td><td>960人</td><td>221g</td><td>76℃</td><td>66℃</td><td>1次</td><td class="td-actions"><a class="link">详情</a> <a class="link">编辑</a></td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
@@ -320,11 +343,11 @@ tbody tr:hover td.td-actions{background:#F8FBFF;}
|
||||
<!-- Tab3: 累计汇总(按秤台) -->
|
||||
<div class="tab-panel">
|
||||
<div class="filter-bar">
|
||||
<div class="filter-item"><label>统计日期</label><input class="filter-input" type="date"></div>
|
||||
<div class="filter-item"><label>秤台编号</label><input class="filter-input" type="text" placeholder="请输入秤台编号"></div>
|
||||
<div class="filter-item"><label>秤台状态</label><select class="filter-select"><option>全部</option><option>正常</option><option>无网络</option><option>未开机</option></select></div>
|
||||
<div class="filter-item"><label>餐线编号</label><select class="filter-select"><option>全部</option><option>A区早餐线</option><option>B区早餐线</option><option>A区中餐线</option><option>B区中餐线</option><option>C区快餐线</option><option>D区晚餐线</option></select></div>
|
||||
<div class="filter-item"><label>餐次</label><select class="filter-select"><option>全部</option><option>早餐</option><option>午餐</option><option>晚餐</option></select></div>
|
||||
<div class="filter-item"><label>统计日期</label><input class="filter-input" type="date" value="2026-05-19" style="min-width:140px;"></div>
|
||||
<div class="filter-item"><label>食堂</label><select class="filter-select" id="filterCanteen3" onchange="updateLineOptions3()"><option value="">全部</option><option value="1">一号食堂</option><option value="2">二号食堂</option><option value="3">三号食堂</option></select></div>
|
||||
<div class="filter-item"><label>餐线</label><select class="filter-select" id="filterLine3"><option value="">全部</option><option data-canteen="1">A区早餐线</option><option data-canteen="1">A区中餐线</option><option data-canteen="1">B区中餐线</option><option data-canteen="2">B区早餐线</option><option data-canteen="2">C区快餐线</option><option data-canteen="3">D区晚餐线</option></select></div>
|
||||
<div class="filter-item"><label>餐次</label><select class="filter-select"><option>全部</option><option>早餐</option><option>中餐</option><option>晚餐</option><option>加餐</option></select></div>
|
||||
<div class="filter-item"><label>称台编号</label><input class="filter-input" type="text" placeholder="请输入称台编号" style="min-width:140px;"></div>
|
||||
<button class="btn btn-primary">查询</button>
|
||||
<button class="btn btn-default">重置</button>
|
||||
</div>
|
||||
@@ -339,16 +362,16 @@ tbody tr:hover td.td-actions{background:#F8FBFF;}
|
||||
<div class="table-card__content">
|
||||
<table>
|
||||
<thead>
|
||||
<tr><th>秤台编号</th><th>秤台状态</th><th>秤台类型</th><th>餐线编号</th><th>餐次</th><th>上餐类型</th><th>上餐菜品数</th><th>累计应收金额</th><th>累计取餐重量(kg)</th><th>累计上餐生重(kg)</th><th>累计上餐重量(kg)</th><th>最高温度</th><th>最低温度</th><th>取餐人次</th><th>平均取餐重量(g/人)</th><th>异常次数</th><th>操作</th></tr>
|
||||
<tr><th>日期</th><th>食堂</th><th>餐线名称</th><th>餐次</th><th>秤台编号</th><th>秤台状态</th><th>称台类型</th><th>上餐类型</th><th>餐品数量</th><th>累计应收金额</th><th>累计取餐重量(kg)</th><th>累计上餐生重(kg)</th><th>累计上餐重量(kg)</th><th>最高温度</th><th>最低温度</th><th>取餐人次</th><th>平均取餐重量(g/人)</th><th>异常次数</th><th>操作</th></tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr class="summary-row"><td>汇总</td><td>—</td><td>—</td><td>—</td><td>—</td><td>—</td><td>84道</td><td>¥58,420</td><td>1,286</td><td>1,720</td><td>1,540</td><td>—</td><td>—</td><td>5,612人</td><td>229g</td><td>3次</td><td><a class="link">查看</a> <a class="link">编辑</a></td></tr>
|
||||
<tr><td>00022号秤</td><td><span class="tag tag-green">正常</span></td><td><span class="tag tag-blue">餐线秤</span></td><td>A区早餐线</td><td>早餐</td><td><span class="tag tag-green">开餐</span></td><td>8道</td><td>¥7,400</td><td>148</td><td>186</td><td>182</td><td>70℃</td><td>55℃</td><td>980人</td><td>151g</td><td>0次</td><td class="td-actions"><a class="link">查看</a> <a class="link">编辑</a></td></tr>
|
||||
<tr><td>00023号秤</td><td><span class="tag tag-green">正常</span></td><td><span class="tag tag-blue">餐线秤</span></td><td>B区早餐线</td><td>早餐</td><td><span class="tag tag-green">开餐</span></td><td>6道</td><td>¥4,860</td><td>92</td><td>118</td><td>108</td><td>68℃</td><td>54℃</td><td>720人</td><td>128g</td><td>0次</td><td class="td-actions"><a class="link">查看</a> <a class="link">编辑</a></td></tr>
|
||||
<tr><td>00025号秤</td><td><span class="tag tag-green">正常</span></td><td><span class="tag tag-blue">餐线秤</span></td><td>A区中餐线</td><td>午餐</td><td><span class="tag tag-green">开餐</span></td><td>12道</td><td>¥14,280</td><td>256</td><td>342</td><td>312</td><td>78℃</td><td>68℃</td><td>1,140人</td><td>225g</td><td>0次</td><td class="td-actions"><a class="link">查看</a> <a class="link">编辑</a></td></tr>
|
||||
<tr><td>00026号秤</td><td><span class="tag tag-green">正常</span></td><td><span class="tag tag-blue">餐线秤</span></td><td>B区中餐线</td><td>午餐</td><td><span class="tag tag-green">开餐</span></td><td>10道</td><td>¥12,640</td><td>218</td><td>294</td><td>268</td><td>76℃</td><td>66℃</td><td>980人</td><td>222g</td><td>1次</td><td class="td-actions"><a class="link">查看</a> <a class="link">编辑</a></td></tr>
|
||||
<tr><td>00027号秤</td><td><span class="tag tag-orange">无网络</span></td><td><span class="tag tag-gray">档口秤</span></td><td>C区快餐线</td><td>午餐</td><td><span class="tag tag-blue">加餐</span></td><td>6道</td><td>¥4,820</td><td>92</td><td>128</td><td>120</td><td>74℃</td><td>70℃</td><td>516人</td><td>178g</td><td>2次</td><td class="td-actions"><a class="link">查看</a> <a class="link">编辑</a></td></tr>
|
||||
<tr><td>00028号秤</td><td><span class="tag tag-gray">未开机</span></td><td><span class="tag tag-gray">档口秤</span></td><td>D区晚餐线</td><td>晚餐</td><td><span class="tag tag-gray">待上餐</span></td><td>—</td><td>—</td><td>—</td><td>—</td><td>—</td><td>—</td><td>—</td><td>—</td><td>—</td><td>0次</td><td class="td-actions"><a class="link">查看</a> <a class="link">编辑</a></td></tr>
|
||||
<tr class="summary-row"><td>汇总</td><td>—</td><td>—</td><td>—</td><td>—</td><td>—</td><td>—</td><td>—</td><td>84道</td><td>¥58,420</td><td>1,286</td><td>1,720</td><td>1,540</td><td>—</td><td>—</td><td>5,612人</td><td>229g</td><td>3次</td><td>—</td></tr>
|
||||
<tr><td>2026-05-19</td><td>一号食堂</td><td>A区早餐线</td><td>早餐</td><td>00022号秤</td><td><span class="tag tag-green">正常</span></td><td><span class="tag tag-blue">单称</span></td><td><span class="tag tag-green">开餐</span></td><td>8道</td><td>¥7,400</td><td>148</td><td>186</td><td>182</td><td>70℃</td><td>55℃</td><td>980人</td><td>151g</td><td>0次</td><td class="td-actions"><a class="link">详情</a> <a class="link">编辑</a></td></tr>
|
||||
<tr><td>2026-05-19</td><td>二号食堂</td><td>B区早餐线</td><td>早餐</td><td>00023号秤</td><td><span class="tag tag-green">正常</span></td><td><span class="tag tag-blue">双称</span></td><td><span class="tag tag-green">开餐</span></td><td>6道</td><td>¥4,860</td><td>92</td><td>118</td><td>108</td><td>68℃</td><td>54℃</td><td>720人</td><td>128g</td><td>0次</td><td class="td-actions"><a class="link">详情</a> <a class="link">编辑</a></td></tr>
|
||||
<tr><td>2026-05-19</td><td>一号食堂</td><td>A区中餐线</td><td>中餐</td><td>00025号秤</td><td><span class="tag tag-green">正常</span></td><td><span class="tag tag-blue">单称</span></td><td><span class="tag tag-green">开餐</span></td><td>12道</td><td>¥14,280</td><td>256</td><td>342</td><td>312</td><td>78℃</td><td>68℃</td><td>1,140人</td><td>225g</td><td>0次</td><td class="td-actions"><a class="link">详情</a> <a class="link">编辑</a></td></tr>
|
||||
<tr><td>2026-05-19</td><td>一号食堂</td><td>B区中餐线</td><td>中餐</td><td>00026号秤</td><td><span class="tag tag-green">正常</span></td><td><span class="tag tag-blue">双称</span></td><td><span class="tag tag-green">开餐</span></td><td>10道</td><td>¥12,640</td><td>218</td><td>294</td><td>268</td><td>76℃</td><td>66℃</td><td>980人</td><td>222g</td><td>1次</td><td class="td-actions"><a class="link">详情</a> <a class="link">编辑</a></td></tr>
|
||||
<tr><td>2026-05-19</td><td>二号食堂</td><td>C区快餐线</td><td>中餐</td><td>00027号秤</td><td><span class="tag tag-orange">无网络</span></td><td><span class="tag tag-gray">单称</span></td><td><span class="tag tag-blue">加餐</span></td><td>6道</td><td>¥4,820</td><td>92</td><td>128</td><td>120</td><td>74℃</td><td>70℃</td><td>516人</td><td>178g</td><td>2次</td><td class="td-actions"><a class="link">详情</a> <a class="link">编辑</a></td></tr>
|
||||
<tr><td>2026-05-19</td><td>三号食堂</td><td>D区晚餐线</td><td>晚餐</td><td>00028号秤</td><td><span class="tag tag-gray">未开机</span></td><td><span class="tag tag-gray">双称</span></td><td><span class="tag tag-gray">待上餐</span></td><td>—</td><td>—</td><td>—</td><td>—</td><td>—</td><td>—</td><td>—</td><td>—</td><td>—</td><td>0次</td><td class="td-actions"><a class="link">详情</a> <a class="link">编辑</a></td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
@@ -374,6 +397,41 @@ function switchTab(idx){
|
||||
document.querySelectorAll('.tab-panel').forEach(function(p,i){p.classList.toggle('active',i===idx);});
|
||||
}
|
||||
|
||||
/* ========== 食堂→餐线联动 ========== */
|
||||
function updateLineOptions(){
|
||||
var canteenVal=document.getElementById('filterCanteen').value;
|
||||
var lineSelect=document.getElementById('filterLine');
|
||||
var opts=lineSelect.querySelectorAll('option');
|
||||
opts.forEach(function(opt){
|
||||
if(!opt.value&&!opt.getAttribute('data-canteen')){opt.style.display='';return;}
|
||||
if(!canteenVal){opt.style.display='';return;}
|
||||
opt.style.display=opt.getAttribute('data-canteen')===canteenVal?'':'none';
|
||||
});
|
||||
lineSelect.value='';
|
||||
}
|
||||
function updateLineOptions2(){
|
||||
var canteenVal=document.getElementById('filterCanteen2').value;
|
||||
var lineSelect=document.getElementById('filterLine2');
|
||||
var opts=lineSelect.querySelectorAll('option');
|
||||
opts.forEach(function(opt){
|
||||
if(!opt.value&&!opt.getAttribute('data-canteen')){opt.style.display='';return;}
|
||||
if(!canteenVal){opt.style.display='';return;}
|
||||
opt.style.display=opt.getAttribute('data-canteen')===canteenVal?'':'none';
|
||||
});
|
||||
lineSelect.value='';
|
||||
}
|
||||
function updateLineOptions3(){
|
||||
var canteenVal=document.getElementById('filterCanteen3').value;
|
||||
var lineSelect=document.getElementById('filterLine3');
|
||||
var opts=lineSelect.querySelectorAll('option');
|
||||
opts.forEach(function(opt){
|
||||
if(!opt.value&&!opt.getAttribute('data-canteen')){opt.style.display='';return;}
|
||||
if(!canteenVal){opt.style.display='';return;}
|
||||
opt.style.display=opt.getAttribute('data-canteen')===canteenVal?'':'none';
|
||||
});
|
||||
lineSelect.value='';
|
||||
}
|
||||
|
||||
/* ========== 弹窗基础 ========== */
|
||||
const Modal = {
|
||||
open(title, bodyHtml) {
|
||||
@@ -447,7 +505,7 @@ function showPickupDetail(scaleId) {
|
||||
pageBtns += `<button class="page-btn${i===page?' active':''}" onclick="pickupGoPage(${i})">${i}</button>`;
|
||||
}
|
||||
return `${summaryHtml}<table class="modal-table">
|
||||
<thead><tr><th>时间</th><th>取餐人</th><th>部门</th><th>菜品</th><th>重量</th><th>单价</th><th>金额</th></tr></thead>
|
||||
<thead><tr><th>时间</th><th>取餐人</th><th>部门</th><th>餐品</th><th>重量</th><th>单价</th><th>金额</th></tr></thead>
|
||||
<tbody>${tbody}</tbody>
|
||||
</table>
|
||||
<div style="display:flex;align-items:center;justify-content:flex-end;padding:12px 0;gap:8px;">
|
||||
@@ -491,26 +549,236 @@ function showServingDetail(scaleId) {
|
||||
const rows = servingData[scaleId] || [];
|
||||
const tbody = rows.map(r => `<tr><td>${r.time}</td><td>${r.batch}</td><td>${r.type}</td><td>${r.dish}</td><td>${r.rawWeight}</td><td>${r.servWeight}</td><td>${r.chef}</td></tr>`).join('');
|
||||
const html = `<table class="modal-table">
|
||||
<thead><tr><th>时间</th><th>批次号</th><th>类型</th><th>菜品</th><th>生重</th><th>上餐重量</th><th>厨师</th></tr></thead>
|
||||
<thead><tr><th>时间</th><th>批次号</th><th>类型</th><th>餐品</th><th>生重</th><th>上餐重量</th><th>厨师</th></tr></thead>
|
||||
<tbody>${tbody}</tbody>
|
||||
</table>`;
|
||||
Modal.open('上餐明细 — ' + scaleId, html);
|
||||
}
|
||||
|
||||
/* ========== 事件绑定 ========== */
|
||||
|
||||
/* ========== 右侧抽屉 ========== */
|
||||
const Drawer = {
|
||||
open(title, bodyHtml) {
|
||||
this.close();
|
||||
const overlay = document.createElement('div');
|
||||
overlay.className = 'drawer-overlay';
|
||||
overlay.innerHTML = '<div class="drawer">' +
|
||||
'<div class="drawer__header"><div class="drawer__title">' + title + '</div><button class="drawer__close" onclick="Drawer.close()">×</button></div>' +
|
||||
'<div class="drawer__body">' + bodyHtml + '</div>' +
|
||||
'</div>';
|
||||
overlay.addEventListener('click', function(e){ if(e.target===overlay) Drawer.close(); });
|
||||
document.body.appendChild(overlay);
|
||||
},
|
||||
close() {
|
||||
const o = document.querySelector('.drawer-overlay');
|
||||
if(!o) return;
|
||||
o.classList.add('closing');
|
||||
setTimeout(function(){ o.remove(); }, 200);
|
||||
}
|
||||
};
|
||||
|
||||
function showScaleDetail(row) {
|
||||
var cells = row.querySelectorAll('td');
|
||||
var get = function(i){ return cells[i] ? cells[i].innerHTML.trim() : '—'; };
|
||||
var getText = function(i){ return cells[i] ? cells[i].textContent.trim() : '—'; };
|
||||
|
||||
var html = '' +
|
||||
'<div class="drawer-section">' +
|
||||
'<div class="drawer-section__title">设备信息</div>' +
|
||||
'<div class="drawer-fields">' +
|
||||
'<div class="drawer-field"><span class="drawer-field__label">日期</span><span class="drawer-field__value">' + getText(0) + '</span></div>' +
|
||||
'<div class="drawer-field"><span class="drawer-field__label">食堂</span><span class="drawer-field__value">' + getText(1) + '</span></div>' +
|
||||
'<div class="drawer-field"><span class="drawer-field__label">餐线名称</span><span class="drawer-field__value">' + getText(2) + '</span></div>' +
|
||||
'<div class="drawer-field"><span class="drawer-field__label">秤台编号</span><span class="drawer-field__value">' + getText(4) + '</span></div>' +
|
||||
'<div class="drawer-field"><span class="drawer-field__label">秤台状态</span><span class="drawer-field__value">' + get(5) + '</span></div>' +
|
||||
'<div class="drawer-field"><span class="drawer-field__label">称台类型</span><span class="drawer-field__value">' + get(6) + '</span></div>' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="drawer-section">' +
|
||||
'<div class="drawer-section__title">餐次与时间</div>' +
|
||||
'<div class="drawer-fields">' +
|
||||
'<div class="drawer-field"><span class="drawer-field__label">餐次</span><span class="drawer-field__value">' + getText(3) + '</span></div>' +
|
||||
'<div class="drawer-field"><span class="drawer-field__label">上餐类型</span><span class="drawer-field__value">' + get(7) + '</span></div>' +
|
||||
'<div class="drawer-field"><span class="drawer-field__label">开机时间</span><span class="drawer-field__value">' + getText(8) + '</span></div>' +
|
||||
'<div class="drawer-field"><span class="drawer-field__label">上餐时间</span><span class="drawer-field__value">' + getText(9) + '</span></div>' +
|
||||
'<div class="drawer-field"><span class="drawer-field__label">保鲜时间</span><span class="drawer-field__value">' + getText(19) + '</span></div>' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="drawer-section">' +
|
||||
'<div class="drawer-section__title">餐品与计费</div>' +
|
||||
'<div class="drawer-fields">' +
|
||||
'<div class="drawer-field"><span class="drawer-field__label">餐品名称</span><span class="drawer-field__value">' + getText(10) + '</span></div>' +
|
||||
'<div class="drawer-field"><span class="drawer-field__label">餐品单价</span><span class="drawer-field__value">' + getText(11) + '</span></div>' +
|
||||
'<div class="drawer-field"><span class="drawer-field__label">应收金额</span><span class="drawer-field__value">' + getText(12) + '</span></div>' +
|
||||
'<div class="drawer-field"><span class="drawer-field__label">取餐人次</span><span class="drawer-field__value">' + getText(20) + '</span></div>' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="drawer-section">' +
|
||||
'<div class="drawer-section__title">重量数据</div>' +
|
||||
'<div class="drawer-fields">' +
|
||||
'<div class="drawer-field"><span class="drawer-field__label">实时重量(kg)</span><span class="drawer-field__value">' + getText(13) + '</span></div>' +
|
||||
'<div class="drawer-field"><span class="drawer-field__label">累计取餐重量</span><span class="drawer-field__value">' + getText(14) + '</span></div>' +
|
||||
'<div class="drawer-field"><span class="drawer-field__label">累计上餐生重(kg)</span><span class="drawer-field__value">' + getText(15) + '</span></div>' +
|
||||
'<div class="drawer-field"><span class="drawer-field__label">累计上餐重量</span><span class="drawer-field__value">' + getText(16) + '</span></div>' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="drawer-section">' +
|
||||
'<div class="drawer-section__title">温度监控</div>' +
|
||||
'<div class="drawer-fields">' +
|
||||
'<div class="drawer-field"><span class="drawer-field__label">最高温度</span><span class="drawer-field__value">' + getText(17) + '</span></div>' +
|
||||
'<div class="drawer-field"><span class="drawer-field__label">最低温度</span><span class="drawer-field__value">' + getText(18) + '</span></div>' +
|
||||
'</div>' +
|
||||
'</div>';
|
||||
|
||||
Drawer.open('秤台详情 — ' + getText(4), html);
|
||||
}
|
||||
|
||||
/* ========== 累计汇总抽屉 ========== */
|
||||
function showSummaryDetail(row) {
|
||||
var cells = row.querySelectorAll('td');
|
||||
var getText = function(i){ return cells[i] ? cells[i].textContent.trim() : '—'; };
|
||||
|
||||
var html = '' +
|
||||
'<div class="drawer-section">' +
|
||||
'<div class="drawer-section__title">基本信息</div>' +
|
||||
'<div class="drawer-fields">' +
|
||||
'<div class="drawer-field"><span class="drawer-field__label">统计日期</span><span class="drawer-field__value">' + getText(0) + '</span></div>' +
|
||||
'<div class="drawer-field"><span class="drawer-field__label">食堂</span><span class="drawer-field__value">' + getText(1) + '</span></div>' +
|
||||
'<div class="drawer-field"><span class="drawer-field__label">餐线名称</span><span class="drawer-field__value">' + getText(2) + '</span></div>' +
|
||||
'<div class="drawer-field"><span class="drawer-field__label">餐次</span><span class="drawer-field__value">' + getText(3) + '</span></div>' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="drawer-section">' +
|
||||
'<div class="drawer-section__title">餐品与计费</div>' +
|
||||
'<div class="drawer-fields">' +
|
||||
'<div class="drawer-field"><span class="drawer-field__label">餐品数量</span><span class="drawer-field__value">' + getText(4) + '</span></div>' +
|
||||
'<div class="drawer-field"><span class="drawer-field__label">累计应收金额</span><span class="drawer-field__value">' + getText(7) + '</span></div>' +
|
||||
'<div class="drawer-field"><span class="drawer-field__label">取餐人次</span><span class="drawer-field__value">' + getText(8) + '</span></div>' +
|
||||
'<div class="drawer-field"><span class="drawer-field__label">平均取餐重量(g/人)</span><span class="drawer-field__value">' + getText(9) + '</span></div>' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="drawer-section">' +
|
||||
'<div class="drawer-section__title">重量数据</div>' +
|
||||
'<div class="drawer-fields">' +
|
||||
'<div class="drawer-field"><span class="drawer-field__label">累计取餐重量(kg)</span><span class="drawer-field__value">' + getText(5) + '</span></div>' +
|
||||
'<div class="drawer-field"><span class="drawer-field__label">累计上餐重量(kg)</span><span class="drawer-field__value">' + getText(6) + '</span></div>' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="drawer-section">' +
|
||||
'<div class="drawer-section__title">温度与异常</div>' +
|
||||
'<div class="drawer-fields">' +
|
||||
'<div class="drawer-field"><span class="drawer-field__label">最高温度</span><span class="drawer-field__value">' + getText(10) + '</span></div>' +
|
||||
'<div class="drawer-field"><span class="drawer-field__label">最低温度</span><span class="drawer-field__value">' + getText(11) + '</span></div>' +
|
||||
'<div class="drawer-field"><span class="drawer-field__label">异常次数</span><span class="drawer-field__value">' + getText(12) + '</span></div>' +
|
||||
'</div>' +
|
||||
'</div>';
|
||||
|
||||
Drawer.open('累计汇总详情 — ' + getText(2) + ' ' + getText(0), html);
|
||||
}
|
||||
|
||||
/* ========== 绑定查看/取餐/上餐链接 ========== */
|
||||
// Tab1: 实时监控
|
||||
(function bindDetailLinks() {
|
||||
const panel = document.querySelectorAll('.tab-panel')[0];
|
||||
if (!panel) return;
|
||||
panel.querySelectorAll('tbody tr').forEach(row => {
|
||||
const cells = row.querySelectorAll('td');
|
||||
if (cells.length < 15) return;
|
||||
const scaleId = cells[0].textContent.trim();
|
||||
// 累计取餐重量 — 第13列(index 12)
|
||||
const pickupLink = cells[12] && cells[12].querySelector('.link');
|
||||
if (cells.length < 17) return;
|
||||
const scaleId = cells[4].textContent.trim();
|
||||
// 累计取餐重量 — 第15列(index 14)
|
||||
const pickupLink = cells[14] && cells[14].querySelector('.link');
|
||||
if (pickupLink) pickupLink.addEventListener('click', () => showPickupDetail(scaleId));
|
||||
// 累计上餐重量 — 第15列(index 14)
|
||||
const servingLink = cells[14] && cells[14].querySelector('.link');
|
||||
// 累计上餐重量 — 第17列(index 16)
|
||||
const servingLink = cells[16] && cells[16].querySelector('.link');
|
||||
if (servingLink) servingLink.addEventListener('click', () => showServingDetail(scaleId));
|
||||
// 操作列"查看"按钮 — 最后一列第一个 link
|
||||
const actionsCell = row.querySelector('td.td-actions');
|
||||
if (actionsCell) {
|
||||
const links = actionsCell.querySelectorAll('.link');
|
||||
if (links[0]) links[0].addEventListener('click', function(){ showScaleDetail(row); });
|
||||
}
|
||||
});
|
||||
})();
|
||||
|
||||
// Tab2: 累计汇总
|
||||
(function bindSummaryLinks() {
|
||||
const panel = document.querySelectorAll('.tab-panel')[1];
|
||||
if (!panel) return;
|
||||
panel.querySelectorAll('tbody tr').forEach(row => {
|
||||
if (row.classList.contains('summary-row')) return;
|
||||
const actionsCell = row.querySelector('td.td-actions');
|
||||
if (actionsCell) {
|
||||
const links = actionsCell.querySelectorAll('.link');
|
||||
if (links[0]) links[0].addEventListener('click', function(){ showSummaryDetail(row); });
|
||||
}
|
||||
});
|
||||
})();
|
||||
|
||||
// Tab3: 累计汇总(按秤台)
|
||||
function showScaleSummaryDetail(row) {
|
||||
var cells = row.querySelectorAll('td');
|
||||
var get = function(i){ return cells[i] ? cells[i].innerHTML.trim() : '—'; };
|
||||
var getText = function(i){ return cells[i] ? cells[i].textContent.trim() : '—'; };
|
||||
|
||||
var html = '' +
|
||||
'<div class="drawer-section">' +
|
||||
'<div class="drawer-section__title">基本信息</div>' +
|
||||
'<div class="drawer-fields">' +
|
||||
'<div class="drawer-field"><span class="drawer-field__label">日期</span><span class="drawer-field__value">' + getText(0) + '</span></div>' +
|
||||
'<div class="drawer-field"><span class="drawer-field__label">食堂</span><span class="drawer-field__value">' + getText(1) + '</span></div>' +
|
||||
'<div class="drawer-field"><span class="drawer-field__label">餐线名称</span><span class="drawer-field__value">' + getText(2) + '</span></div>' +
|
||||
'<div class="drawer-field"><span class="drawer-field__label">餐次</span><span class="drawer-field__value">' + getText(3) + '</span></div>' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="drawer-section">' +
|
||||
'<div class="drawer-section__title">设备信息</div>' +
|
||||
'<div class="drawer-fields">' +
|
||||
'<div class="drawer-field"><span class="drawer-field__label">秤台编号</span><span class="drawer-field__value">' + getText(4) + '</span></div>' +
|
||||
'<div class="drawer-field"><span class="drawer-field__label">秤台状态</span><span class="drawer-field__value">' + get(5) + '</span></div>' +
|
||||
'<div class="drawer-field"><span class="drawer-field__label">称台类型</span><span class="drawer-field__value">' + get(6) + '</span></div>' +
|
||||
'<div class="drawer-field"><span class="drawer-field__label">上餐类型</span><span class="drawer-field__value">' + get(7) + '</span></div>' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="drawer-section">' +
|
||||
'<div class="drawer-section__title">餐品与计费</div>' +
|
||||
'<div class="drawer-fields">' +
|
||||
'<div class="drawer-field"><span class="drawer-field__label">餐品数量</span><span class="drawer-field__value">' + getText(8) + '</span></div>' +
|
||||
'<div class="drawer-field"><span class="drawer-field__label">累计应收金额</span><span class="drawer-field__value">' + getText(9) + '</span></div>' +
|
||||
'<div class="drawer-field"><span class="drawer-field__label">取餐人次</span><span class="drawer-field__value">' + getText(15) + '</span></div>' +
|
||||
'<div class="drawer-field"><span class="drawer-field__label">平均取餐重量(g/人)</span><span class="drawer-field__value">' + getText(16) + '</span></div>' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="drawer-section">' +
|
||||
'<div class="drawer-section__title">重量数据</div>' +
|
||||
'<div class="drawer-fields">' +
|
||||
'<div class="drawer-field"><span class="drawer-field__label">累计取餐重量(kg)</span><span class="drawer-field__value">' + getText(10) + '</span></div>' +
|
||||
'<div class="drawer-field"><span class="drawer-field__label">累计上餐生重(kg)</span><span class="drawer-field__value">' + getText(11) + '</span></div>' +
|
||||
'<div class="drawer-field"><span class="drawer-field__label">累计上餐重量(kg)</span><span class="drawer-field__value">' + getText(12) + '</span></div>' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="drawer-section">' +
|
||||
'<div class="drawer-section__title">温度与异常</div>' +
|
||||
'<div class="drawer-fields">' +
|
||||
'<div class="drawer-field"><span class="drawer-field__label">最高温度</span><span class="drawer-field__value">' + getText(13) + '</span></div>' +
|
||||
'<div class="drawer-field"><span class="drawer-field__label">最低温度</span><span class="drawer-field__value">' + getText(14) + '</span></div>' +
|
||||
'<div class="drawer-field"><span class="drawer-field__label">异常次数</span><span class="drawer-field__value">' + getText(17) + '</span></div>' +
|
||||
'</div>' +
|
||||
'</div>';
|
||||
|
||||
Drawer.open('秤台汇总详情 — ' + getText(4), html);
|
||||
}
|
||||
|
||||
(function bindScaleSummaryLinks() {
|
||||
const panel = document.querySelectorAll('.tab-panel')[2];
|
||||
if (!panel) return;
|
||||
panel.querySelectorAll('tbody tr').forEach(row => {
|
||||
if (row.classList.contains('summary-row')) return;
|
||||
const actionsCell = row.querySelector('td.td-actions');
|
||||
if (actionsCell) {
|
||||
const links = actionsCell.querySelectorAll('.link');
|
||||
if (links[0]) links[0].addEventListener('click', function(){ showScaleSummaryDetail(row); });
|
||||
}
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
|
||||
@@ -116,6 +116,65 @@ 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;}
|
||||
|
||||
/* 餐品详情弹窗 */
|
||||
.meal-section{margin-bottom:20px;}
|
||||
.meal-section__title{font-size:var(--font-base);font-weight:600;color:var(--text-primary);padding-left:10px;border-left:3px solid var(--primary);margin-bottom:12px;}
|
||||
.meal-info-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:10px 24px;margin-bottom:24px;}
|
||||
.meal-info-item{display:flex;align-items:center;gap:8px;font-size:var(--font-sm);padding:8px 0;border-bottom:1px dashed #f0f0f0;}
|
||||
.meal-info-item__label{color:var(--text-secondary);min-width:72px;flex-shrink:0;}
|
||||
.meal-info-item__value{color:var(--text-primary);font-weight:500;}
|
||||
.meal-table{width:100%;border-collapse:collapse;margin-top:8px;}
|
||||
.meal-table thead th{background:#FAFAFA;padding:10px 16px;text-align:center;font-size:var(--font-sm);color:var(--text-secondary);font-weight:500;border-bottom:1px solid var(--border);}
|
||||
.meal-table tbody td{padding:12px 16px;font-size:var(--font-sm);color:var(--text-primary);border-bottom:1px solid var(--border);text-align:center;}
|
||||
.meal-table tbody tr:last-child td{border-bottom:none;font-weight:600;background:#FAFAFA;}
|
||||
.meal-table .dish-name{color:var(--primary);cursor:pointer;font-weight:500;}
|
||||
.meal-table .dish-name:hover{color:#40a9ff;}
|
||||
.tag-scale{display:inline-block;padding:1px 6px;border-radius:3px;font-size:11px;background:#E6F7FF;color:var(--primary);border:1px solid #91D5FF;margin-left:6px;vertical-align:middle;}
|
||||
|
||||
/* 历史用餐明细表格 */
|
||||
.meal-history-table{width:100%;border-collapse:collapse;font-size:var(--font-sm);}
|
||||
.meal-history-table thead th{background:#FAFAFA;padding:10px 12px;text-align:left;color:var(--text-secondary);font-weight:500;border-bottom:1px solid var(--border);}
|
||||
.meal-history-table tbody td{padding:12px;color:var(--text-primary);border-bottom:1px solid #f0f0f0;}
|
||||
.meal-history-table tbody tr:last-child td{border-bottom:none;}
|
||||
.meal-history-table tbody tr:hover{background:#F8FBFF;}
|
||||
.score-tag{display:inline-block;padding:2px 8px;border-radius:4px;font-size:var(--font-sm);font-weight:600;}
|
||||
.score-green{color:#52C41A;background:#F6FFED;}
|
||||
.score-orange{color:#FA8C16;background:#FFF7E6;}
|
||||
|
||||
/* 菜品偏好 */
|
||||
.dish-pref-section{display:flex;flex-direction:column;gap:12px;}
|
||||
.dish-pref-item__label{font-size:var(--font-xs);color:var(--text-secondary);margin-bottom:6px;}
|
||||
.dish-pref-item__tags{display:flex;gap:6px;flex-wrap:wrap;}
|
||||
.dish-tag{display:inline-block;padding:2px 10px;border-radius:4px;font-size:var(--font-xs);color:#52C41A;background:#F6FFED;border:1px solid #B7EB8F;}
|
||||
.dish-pref-item__value{font-size:var(--font-sm);color:var(--text-primary);}
|
||||
.dish-pref-item__big{font-size:var(--font-base);font-weight:600;color:var(--text-primary);}
|
||||
|
||||
/* 妈妈味道 */
|
||||
.mom-section{background:#FFF8F0;border-radius:var(--radius-md);padding:12px 16px;}
|
||||
.mom-header{display:flex;align-items:center;gap:10px;margin-bottom:10px;}
|
||||
.mom-header__icon{font-size:22px;}
|
||||
.mom-header__title{font-size:var(--font-sm);font-weight:600;color:var(--text-primary);}
|
||||
.mom-header__sub{font-size:var(--font-xs);color:#FA8C16;margin-top:2px;}
|
||||
.mom-header__tags{display:flex;gap:6px;flex-wrap:wrap;}
|
||||
.mom-tag{display:inline-block;padding:2px 10px;border-radius:4px;font-size:var(--font-xs);color:#FA8C16;background:#FFF7E6;border:1px solid #FFD591;}
|
||||
|
||||
/* 个性模型 */
|
||||
.model-section{background:#E6F7FF;border-radius:var(--radius-md);padding:12px 16px;margin-bottom:16px;}
|
||||
.model-header{display:flex;align-items:center;gap:10px;margin-bottom:10px;}
|
||||
.model-header__icon{font-size:22px;}
|
||||
.model-header__title{font-size:var(--font-sm);font-weight:600;color:var(--primary);}
|
||||
.model-header__sub{font-size:var(--font-xs);color:var(--text-secondary);margin-top:2px;}
|
||||
.model-header__tags{display:flex;gap:6px;flex-wrap:wrap;}
|
||||
.model-tag{display:inline-block;padding:2px 10px;border-radius:4px;font-size:var(--font-xs);color:var(--primary);background:#fff;border:1px solid #91D5FF;}
|
||||
.model-grid{display:grid;grid-template-columns:repeat(2,1fr);gap:12px 20px;margin-bottom:16px;}
|
||||
.model-item__label{font-size:var(--font-xs);color:var(--text-secondary);margin-bottom:4px;}
|
||||
.model-item__big{font-size:var(--font-base);font-weight:600;color:var(--text-primary);}
|
||||
.model-item__value{font-size:var(--font-sm);}
|
||||
.risk-tag{display:inline-flex;align-items:center;gap:4px;padding:2px 8px;border-radius:4px;font-size:var(--font-xs);font-weight:500;}
|
||||
.risk-safe{background:#F6FFED;color:#52C41A;border:1px solid #B7EB8F;}
|
||||
.risk-warn{background:#FFF7E6;color:#FA8C16;border:1px solid #FFD591;}
|
||||
.model-footer{font-size:var(--font-xs);color:var(--text-secondary);padding:10px 12px;background:#F5F7FA;border-radius:var(--radius-sm);}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
@@ -187,13 +246,15 @@ tbody tr:hover td.td-actions{background:#F8FBFF;}
|
||||
|
||||
<!-- 筛选栏 -->
|
||||
<div class="filter-bar">
|
||||
<div class="filter-item"><label>员工姓名/工号</label><input class="filter-input" type="text" placeholder="请输入姓名或工号"></div>
|
||||
<div class="filter-item"><label>部门</label><select class="filter-select"><option>全部</option><option>研发部</option><option>市场部</option><option>运营部</option><option>财务部</option><option>人事部</option></select></div>
|
||||
<div class="filter-item"><label>餐次</label><select class="filter-select"><option>全部</option><option>早餐</option><option>午餐</option><option>晚餐</option></select></div>
|
||||
<div class="filter-item"><label>员工姓名</label><input class="filter-input" type="text" placeholder="请输入姓名" style="min-width:120px;"></div>
|
||||
<div class="filter-item"><label>员工编号</label><input class="filter-input" type="text" placeholder="请输入编号" style="min-width:120px;"></div>
|
||||
<div class="filter-item"><label>单位部门</label><select class="filter-select"><option>全部</option><option>研发部</option><option>市场部</option><option>运营部</option><option>财务部</option><option>人事部</option><option>安保部</option><option>运维部</option></select></div>
|
||||
<div class="filter-item"><label>食堂</label><select class="filter-select"><option>全部</option><option>一号食堂</option><option>二号食堂</option><option>三号食堂</option></select></div>
|
||||
<div class="filter-item"><label>餐次</label><select class="filter-select"><option>全部</option><option>早餐</option><option>中餐</option><option>晚餐</option><option>加餐</option></select></div>
|
||||
<div class="filter-item"><label>取餐方式</label><select class="filter-select"><option>全部</option><option>点餐取餐</option><option>餐线取餐</option><option>档口+餐线</option><option>外卖/外带</option><option>余量取餐</option></select></div>
|
||||
<div class="filter-item"><label>取餐类型</label><select class="filter-select"><option>全部</option><option>正常取餐</option><option>余量取餐</option></select></div>
|
||||
<div class="filter-item"><label>人员类别</label><select class="filter-select"><option>全部</option><option>会员</option><option>非会员</option><option>员工</option><option>工作人员</option><option>外部人员</option></select></div>
|
||||
<div class="filter-item"><label>日期范围</label><input class="filter-input" type="date"></div>
|
||||
<div class="filter-item"><label>日期范围</label><input class="filter-input" type="date" style="min-width:130px;"> <span style="margin:0 4px;color:#999;">至</span> <input class="filter-input" type="date" style="min-width:130px;"></div>
|
||||
<button class="btn btn-primary">查询</button>
|
||||
<button class="btn btn-default">重置</button>
|
||||
</div>
|
||||
@@ -202,7 +263,6 @@ tbody tr:hover td.td-actions{background:#F8FBFF;}
|
||||
<div class="action-bar">
|
||||
<button class="btn btn-primary"><svg width="14" height="14" viewBox="0 0 14 14" fill="none"><path d="M2 10v2h10v-2M7 2v7M4.5 6.5L7 9l2.5-2.5" stroke="#fff" stroke-width="1.4" stroke-linecap="round" stroke-linejoin="round"/></svg>导出列表数据</button>
|
||||
<button class="btn btn-default"><svg width="14" height="14" viewBox="0 0 14 14" fill="none"><rect x="2" y="2" width="10" height="10" rx="1.5" stroke="currentColor" stroke-width="1.4"/><path d="M4 5h6M4 7.5h4" stroke="currentColor" stroke-width="1.2" stroke-linecap="round"/></svg>查看导出任务</button>
|
||||
<button class="btn btn-default">📊 营养汇总报告</button>
|
||||
</div>
|
||||
|
||||
<!-- 数据表格 -->
|
||||
@@ -213,18 +273,18 @@ tbody tr:hover td.td-actions{background:#F8FBFF;}
|
||||
<div class="table-card__content">
|
||||
<table>
|
||||
<thead>
|
||||
<tr><th>就餐记录号</th><th>用户</th><th>部门</th><th>餐次</th><th>取餐方式</th><th>取餐类型</th><th>人员类别</th><th>取餐开始时间</th><th>取餐结束时间</th><th>取餐总数量</th><th>营养评分</th><th>操作</th></tr>
|
||||
<tr><th>就餐记录号</th><th>姓名</th><th>员工编号</th><th>单位</th><th>部门</th><th>餐次</th><th>取餐方式</th><th>取餐类型</th><th>人员类别</th><th>取餐开始时间</th><th>取餐结束时间</th><th>取餐总数量</th><th>营养评分</th><th>操作</th></tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr><td>M-20260428-001</td><td>张伟(EMP001)</td><td>研发部</td><td>午餐</td><td><span class="tag tag-blue">点餐取餐</span></td><td><span class="tag tag-green">正常取餐</span></td><td><span class="tag tag-orange">会员</span></td><td>11:02</td><td>11:08</td><td><a class="link">3件</a></td><td><span class="tag tag-green">88分</span></td><td class="td-actions"><a class="link">查看用户信息</a></td></tr>
|
||||
<tr><td>M-20260428-002</td><td>李娜(EMP002)</td><td>市场部</td><td>午餐</td><td><span class="tag tag-blue">点餐取餐</span></td><td><span class="tag tag-green">正常取餐</span></td><td><span class="tag tag-orange">会员</span></td><td>11:08</td><td>11:14</td><td><a class="link">3件</a></td><td><span class="tag tag-green">92分</span></td><td class="td-actions"><a class="link">查看用户信息</a></td></tr>
|
||||
<tr><td>M-20260428-003</td><td>王磊(EMP003)</td><td>运营部</td><td>午餐</td><td><span class="tag tag-gray">餐线取餐</span></td><td><span class="tag tag-green">正常取餐</span></td><td><span class="tag tag-gray">非会员</span></td><td>11:15</td><td>11:20</td><td><a class="link">2件</a></td><td><span class="tag tag-orange">68分</span></td><td class="td-actions"><a class="link">查看用户信息</a></td></tr>
|
||||
<tr><td>M-20260428-004</td><td>赵敏(EMP004)</td><td>财务部</td><td>午餐</td><td><span class="tag tag-green">档口+餐线</span></td><td><span class="tag tag-green">正常取餐</span></td><td><span class="tag tag-orange">会员</span></td><td>11:22</td><td>11:30</td><td><a class="link">3件</a></td><td><span class="tag tag-green">94分</span></td><td class="td-actions"><a class="link">查看用户信息</a></td></tr>
|
||||
<tr><td>M-20260428-005</td><td>陈刚(EMP005)</td><td>人事部</td><td>早餐</td><td><span class="tag tag-gray">餐线取餐</span></td><td><span class="tag tag-green">正常取餐</span></td><td><span class="tag tag-gray">非会员</span></td><td>07:48</td><td>07:55</td><td><a class="link">3件</a></td><td><span class="tag tag-green">85分</span></td><td class="td-actions"><a class="link">查看用户信息</a></td></tr>
|
||||
<tr><td>M-20260428-006</td><td>刘芳(EMP006)</td><td>市场部</td><td>午餐</td><td><span class="tag tag-blue">外卖/外带</span></td><td><span class="tag tag-green">正常取餐</span></td><td><span class="tag tag-orange">会员</span></td><td>11:45</td><td>11:48</td><td><a class="link">2件</a></td><td><span class="tag tag-green">90分</span></td><td class="td-actions"><a class="link">查看用户信息</a></td></tr>
|
||||
<tr><td>SP-001-001</td><td>张运维(EMP101)</td><td>运维部</td><td>午餐</td><td><span class="tag tag-orange">余量取餐</span></td><td><span class="tag tag-orange">余量取餐</span></td><td><span class="tag tag-blue">员工</span></td><td>14:05</td><td>14:06</td><td><a class="link">1件</a></td><td>—</td><td class="td-actions"><a class="link">查看用户信息</a></td></tr>
|
||||
<tr><td>SP-001-003</td><td>王保安(EMP103)</td><td>安保部</td><td>午餐</td><td><span class="tag tag-orange">余量取餐</span></td><td><span class="tag tag-orange">余量取餐</span></td><td><span class="tag tag-blue">工作人员</span></td><td>14:10</td><td>14:11</td><td><a class="link">1件</a></td><td>—</td><td class="td-actions"><a class="link">查看用户信息</a></td></tr>
|
||||
<tr><td>M-20260428-007</td><td>林教授</td><td>外部访客</td><td>午餐</td><td><span class="tag tag-blue">点餐取餐</span></td><td><span class="tag tag-green">正常取餐</span></td><td><span class="tag tag-purple">外部人员</span></td><td>12:10</td><td>12:18</td><td><a class="link">3件</a></td><td><span class="tag tag-green">86分</span></td><td class="td-actions"><a class="link">查看用户信息</a></td></tr>
|
||||
<tr><td>M-20260428-001</td><td>张伟</td><td>EMP001</td><td>长庆油田</td><td>研发部</td><td>午餐</td><td><span class="tag tag-blue">点餐取餐</span></td><td><span class="tag tag-green">正常取餐</span></td><td><span class="tag tag-orange">会员</span></td><td>11:02</td><td>11:08</td><td><a class="link">3件</a></td><td><span class="tag tag-green">88分</span></td><td class="td-actions"><a class="link">查看用户信息</a></td></tr>
|
||||
<tr><td>M-20260428-002</td><td>李娜</td><td>EMP002</td><td>长庆油田</td><td>市场部</td><td>午餐</td><td><span class="tag tag-blue">点餐取餐</span></td><td><span class="tag tag-green">正常取餐</span></td><td><span class="tag tag-orange">会员</span></td><td>11:08</td><td>11:14</td><td><a class="link">3件</a></td><td><span class="tag tag-green">92分</span></td><td class="td-actions"><a class="link">查看用户信息</a></td></tr>
|
||||
<tr><td>M-20260428-003</td><td>王磊</td><td>EMP003</td><td>长庆油田</td><td>运营部</td><td>午餐</td><td><span class="tag tag-gray">餐线取餐</span></td><td><span class="tag tag-green">正常取餐</span></td><td><span class="tag tag-gray">非会员</span></td><td>11:15</td><td>11:20</td><td><a class="link">2件</a></td><td><span class="tag tag-orange">68分</span></td><td class="td-actions"><a class="link">查看用户信息</a></td></tr>
|
||||
<tr><td>M-20260428-004</td><td>赵敏</td><td>EMP004</td><td>长庆油田</td><td>财务部</td><td>午餐</td><td><span class="tag tag-green">档口+餐线</span></td><td><span class="tag tag-green">正常取餐</span></td><td><span class="tag tag-orange">会员</span></td><td>11:22</td><td>11:30</td><td><a class="link">3件</a></td><td><span class="tag tag-green">94分</span></td><td class="td-actions"><a class="link">查看用户信息</a></td></tr>
|
||||
<tr><td>M-20260428-005</td><td>陈刚</td><td>EMP005</td><td>长庆油田</td><td>人事部</td><td>早餐</td><td><span class="tag tag-gray">餐线取餐</span></td><td><span class="tag tag-green">正常取餐</span></td><td><span class="tag tag-gray">非会员</span></td><td>07:48</td><td>07:55</td><td><a class="link">3件</a></td><td><span class="tag tag-green">85分</span></td><td class="td-actions"><a class="link">查看用户信息</a></td></tr>
|
||||
<tr><td>M-20260428-006</td><td>刘芳</td><td>EMP006</td><td>长庆油田</td><td>市场部</td><td>午餐</td><td><span class="tag tag-blue">外卖/外带</span></td><td><span class="tag tag-green">正常取餐</span></td><td><span class="tag tag-orange">会员</span></td><td>11:45</td><td>11:48</td><td><a class="link">2件</a></td><td><span class="tag tag-green">90分</span></td><td class="td-actions"><a class="link">查看用户信息</a></td></tr>
|
||||
<tr><td>SP-001-001</td><td>张运维</td><td>EMP101</td><td>长庆油田</td><td>运维部</td><td>午餐</td><td><span class="tag tag-orange">余量取餐</span></td><td><span class="tag tag-orange">余量取餐</span></td><td><span class="tag tag-blue">员工</span></td><td>14:05</td><td>14:06</td><td><a class="link">1件</a></td><td>—</td><td class="td-actions"><a class="link">查看用户信息</a></td></tr>
|
||||
<tr><td>SP-001-003</td><td>王保安</td><td>—</td><td>长庆油田</td><td>安保部</td><td>午餐</td><td><span class="tag tag-orange">余量取餐</span></td><td><span class="tag tag-orange">余量取餐</span></td><td><span class="tag tag-blue">工作人员</span></td><td>14:10</td><td>14:11</td><td><a class="link">1件</a></td><td>—</td><td class="td-actions"><a class="link">查看用户信息</a></td></tr>
|
||||
<tr><td>M-20260428-007</td><td>林教授</td><td>—</td><td>外部单位</td><td>外部访客</td><td>午餐</td><td><span class="tag tag-blue">点餐取餐</span></td><td><span class="tag tag-green">正常取餐</span></td><td><span class="tag tag-purple">外部人员</span></td><td>12:10</td><td>12:18</td><td><a class="link">3件</a></td><td><span class="tag tag-green">86分</span></td><td class="td-actions"><a class="link">查看用户信息</a></td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
@@ -274,20 +334,40 @@ const userProfiles = {
|
||||
taste:'偏辣', region:'川菜、湘菜',
|
||||
taboo:'无', allergy:'花生',
|
||||
exercise:'6000步/日', weightTrend:'稳定', bodyFat:'18%', heartRate:'68', sleep:'7.5h', stress:'低', source:'智能手环',
|
||||
meals30:'58次', hotDish:'宫保鸡丁、番茄牛腩', avgCal:'680kcal', nutriRate:'88%',
|
||||
favDish:'宫保鸡丁、清炒西兰花', recDish:'三文鱼沙拉', avoidDish:'油炸花生', topRate:'番茄牛腩(4.8)', repurchase:'宫保鸡丁',
|
||||
hometown:'四川成都', momTag:'麻辣鲜香', momList:'回锅肉、麻婆豆腐', memory:'妈妈的回锅肉', recTry:'水煮鱼',
|
||||
modelVer:'v2.3', modelTime:'2026-04-20', recCal:'2100kcal', nutriFocus:'蛋白质+膳食纤维', risk:'无', tags:'运动达人、川菜爱好者', confidence:'92%' },
|
||||
meals30:'86次', hotDish:'宫保鸡丁、番茄牛腩', avgCal:'2,186 kcal/天', nutriRate:'88%',
|
||||
proteinRate:'92%', highFatRate:'8%', preferMeal:'午餐', lastMeal:'2026-04-28 午餐',
|
||||
mealHistory:[
|
||||
{date:'2026-04-28',meal:'午餐',dishes:'清蒸鱼、炒西兰花、米饭、紫菜蛋花汤',cal:'832 kcal',score:95},
|
||||
{date:'2026-04-28',meal:'早餐',dishes:'小米粥、卤蛋、凉拌黄瓜',cal:'380 kcal',score:92},
|
||||
{date:'2026-04-27',meal:'午餐',dishes:'杂粮饭、清蒸鱼、蒜蓉菠菜',cal:'798 kcal',score:94},
|
||||
{date:'2026-04-26',meal:'午餐',dishes:'米饭、宫保鸡丁、炒西兰花、汤',cal:'906 kcal',score:86},
|
||||
{date:'2026-04-25',meal:'晚餐',dishes:'杂粮饭、清蒸鱼、炒时蔬',cal:'716 kcal',score:96},
|
||||
{date:'2026-04-25',meal:'午餐',dishes:'米饭、宫保鸡丁、番茄炒蛋',cal:'928 kcal',score:88},
|
||||
{date:'2026-04-24',meal:'午餐',dishes:'米饭、清蒸鱼、蒜蓉菠菜、番茄蛋花汤',cal:'768 kcal',score:95}
|
||||
],
|
||||
favDish:'宫保鸡丁、清炒西兰花、杂粮饭', recDish:'三文鱼沙拉、蒜蓉菠菜', avoidDish:'油炸花生', topRate:'宫保鸡丁(94分)', repurchase:'宫保鸡丁(近30日18次)',
|
||||
hometown:'四川成都', momTag:'麻辣、红油、鲜香', momList:'回锅肉、麻婆豆腐、水煮鱼', memory:'从小常吃妈妈做的回锅肉,奠定了麻辣口味偏好。', recTry:'川味水煮鱼套餐(已上架一号食堂)',
|
||||
modelVer:'v2.3', modelTime:'2026-04-20', recCal:'2,250 kcal', nutriFocus:'蛋白质+膳食纤维', risk:'无风险', tags:'清淡偏好、中度活动、无慢病', confidence:'94%', nextUpdate:'2026-05-28' },
|
||||
'李娜': { dept:'市场部', age:28, gender:'女', height:'163cm', weight:'52kg', bmi:'19.6', activity:'轻度',
|
||||
disease:'无', chronic:'无', medicine:'无', family:'糖尿病(母)',
|
||||
examDate:'2026-02-20', bp:'110/70', glucose:'4.8', lipid:'正常', uric:'290', liver:'正常', kidney:'正常',
|
||||
taste:'清淡', region:'粤菜、日料',
|
||||
taboo:'无', allergy:'海鲜(虾蟹)',
|
||||
exercise:'4000步/日', weightTrend:'稳定', bodyFat:'22%', heartRate:'72', sleep:'7h', stress:'中', source:'手机计步',
|
||||
meals30:'52次', hotDish:'蒸鱼、蔬菜沙拉', avgCal:'520kcal', nutriRate:'92%',
|
||||
favDish:'清蒸鲈鱼、藜麦沙拉', recDish:'牛油果吐司', avoidDish:'麻辣火锅', topRate:'藜麦沙拉(4.9)', repurchase:'清蒸鲈鱼',
|
||||
hometown:'广东广州', momTag:'鲜甜清润', momList:'老火靓汤、白切鸡', memory:'周末的煲汤', recTry:'椰子鸡',
|
||||
modelVer:'v2.3', modelTime:'2026-04-18', recCal:'1650kcal', nutriFocus:'钙+铁+维生素D', risk:'注意糖摄入', tags:'轻食主义、养生达人', confidence:'95%' }
|
||||
meals30:'52次', hotDish:'清蒸鲈鱼、藜麦沙拉', avgCal:'1,650 kcal/天', nutriRate:'92%',
|
||||
proteinRate:'95%', highFatRate:'5%', preferMeal:'午餐', lastMeal:'2026-04-28 午餐',
|
||||
mealHistory:[
|
||||
{date:'2026-04-28',meal:'午餐',dishes:'藜麦沙拉、清蒸鲈鱼、蒜蓉西兰花',cal:'680 kcal',score:96},
|
||||
{date:'2026-04-28',meal:'早餐',dishes:'牛油果吐司、酸奶、水果',cal:'420 kcal',score:94},
|
||||
{date:'2026-04-27',meal:'午餐',dishes:'三文鱼沙拉、杂粮饭、蔬菜汤',cal:'720 kcal',score:97},
|
||||
{date:'2026-04-26',meal:'午餐',dishes:'清蒸鲈鱼、藜麦饭、凉拌木耳',cal:'650 kcal',score:95},
|
||||
{date:'2026-04-25',meal:'晚餐',dishes:'蔬菜沙拉、鸡胸肉、全麦面包',cal:'580 kcal',score:93},
|
||||
{date:'2026-04-25',meal:'午餐',dishes:'番茄鱼片、杂粮饭、炒时蔬',cal:'750 kcal',score:91},
|
||||
{date:'2026-04-24',meal:'午餐',dishes:'清蒸鲈鱼、藜麦沙拉、紫菜汤',cal:'690 kcal',score:96}
|
||||
],
|
||||
favDish:'清蒸鲈鱼、藜麦沙拉、杂粮饭', recDish:'蒜蓉菠菜、紫菜蛋花汤', avoidDish:'暂无', topRate:'清蒸鱼(96分)', repurchase:'清蒸鱼(近30日21次)',
|
||||
hometown:'广东广州', momTag:'清炖、甜咸适中、河鲜', momList:'松鼠桂鱼、响油鳝糊、腌笃鲜', memory:'从小常吃妈妈做的清炖鱼,奠定了清淡口味偏好。', recTry:'苏式清蒸鱼套餐(已上架二号食堂)',
|
||||
modelVer:'v2.3', modelTime:'2026-04-18', recCal:'1,650 kcal', nutriFocus:'钙+铁+维生素D', risk:'注意糖摄入', tags:'轻食主义、养生达人、低糖饮食', confidence:'95%', nextUpdate:'2026-05-28' }
|
||||
};
|
||||
|
||||
/* 默认档案(其他用户) */
|
||||
@@ -297,10 +377,20 @@ const defaultProfile = { dept:'—', age:30, gender:'—', height:'170cm', weigh
|
||||
taste:'适中', region:'不限',
|
||||
taboo:'无', allergy:'无',
|
||||
exercise:'5000步/日', weightTrend:'稳定', bodyFat:'20%', heartRate:'70', sleep:'7h', stress:'低', source:'手动录入',
|
||||
meals30:'45次', hotDish:'家常菜', avgCal:'600kcal', nutriRate:'78%',
|
||||
favDish:'红烧肉、西红柿炒蛋', recDish:'杂粮饭套餐', avoidDish:'无', topRate:'红烧肉(4.5)', repurchase:'西红柿炒蛋',
|
||||
hometown:'—', momTag:'家常味', momList:'红烧肉', memory:'—', recTry:'—',
|
||||
modelVer:'v2.3', modelTime:'2026-04-15', recCal:'1900kcal', nutriFocus:'均衡', risk:'无', tags:'普通用户', confidence:'80%' };
|
||||
meals30:'45次', hotDish:'家常菜', avgCal:'1,900 kcal/天', nutriRate:'78%',
|
||||
proteinRate:'80%', highFatRate:'12%', preferMeal:'午餐', lastMeal:'2026-04-28 午餐',
|
||||
mealHistory:[
|
||||
{date:'2026-04-28',meal:'午餐',dishes:'红烧肉、米饭、炒青菜、蛋花汤',cal:'856 kcal',score:82},
|
||||
{date:'2026-04-27',meal:'午餐',dishes:'西红柿炒蛋、米饭、紫菜汤',cal:'720 kcal',score:85},
|
||||
{date:'2026-04-26',meal:'午餐',dishes:'糖醋里脊、米饭、炒时蔬',cal:'880 kcal',score:80},
|
||||
{date:'2026-04-25',meal:'午餐',dishes:'红烧肉、杂粮饭、凉拌黄瓜',cal:'810 kcal',score:84},
|
||||
{date:'2026-04-25',meal:'早餐',dishes:'豆浆、油条、茶叶蛋',cal:'450 kcal',score:76},
|
||||
{date:'2026-04-24',meal:'午餐',dishes:'宫保鸡丁、米饭、番茄蛋汤',cal:'790 kcal',score:86},
|
||||
{date:'2026-04-23',meal:'午餐',dishes:'西红柿炒蛋、米饭、炒青菜',cal:'680 kcal',score:88}
|
||||
],
|
||||
favDish:'红烧肉、西红柿炒蛋、炒青菜', recDish:'杂粮饭套餐、蒸南瓜', avoidDish:'暂无', topRate:'红烧肉(90分)', repurchase:'西红柿炒蛋(近30日15次)',
|
||||
hometown:'—', momTag:'家常、咸鲜、炖煮', momList:'红烧肉、炖排骨、西红柿炒蛋', memory:'小时候最爱妈妈做的红烧肉,是家的味道。', recTry:'家常红烧肉套餐(已上架一号食堂)',
|
||||
modelVer:'v2.3', modelTime:'2026-04-15', recCal:'1,900 kcal', nutriFocus:'均衡', risk:'无风险', tags:'家常口味、中度活动、无慢病', confidence:'80%', nextUpdate:'2026-05-28' };
|
||||
|
||||
const tabDefs = [
|
||||
{ key:'basic', label:'静态基础' },
|
||||
@@ -360,34 +450,52 @@ function buildProfileHTML(name, p) {
|
||||
<div class="profile-field"><span class="profile-field__label">数据来源</span><span class="profile-field__value">${p.source}</span></div>
|
||||
</div>`,
|
||||
meal: `<div class="profile-grid">
|
||||
<div class="profile-field"><span class="profile-field__label">近30日就餐</span><span class="profile-field__value">${p.meals30}</span></div>
|
||||
<div class="profile-field"><span class="profile-field__label">常点菜品</span><span class="profile-field__value">${p.hotDish}</span></div>
|
||||
<div class="profile-field"><span class="profile-field__label">平均热量</span><span class="profile-field__value">${p.avgCal}</span></div>
|
||||
<div class="profile-field"><span class="profile-field__label">营养达标率</span><span class="profile-field__value">${p.nutriRate}</span></div>
|
||||
<div class="profile-field"><span class="profile-field__label">近30日就餐次数</span><span class="profile-field__value">${p.meals30}</span></div>
|
||||
<div class="profile-field"><span class="profile-field__label">最常点菜品</span><span class="profile-field__value">${p.hotDish}</span></div>
|
||||
<div class="profile-field"><span class="profile-field__label">平均热量摄入</span><span class="profile-field__value">${p.avgCal}</span></div>
|
||||
<div class="profile-field"><span class="profile-field__label">蛋白质达标率</span><span class="profile-field__value">${p.proteinRate}</span></div>
|
||||
<div class="profile-field"><span class="profile-field__label">高脂餐占比</span><span class="profile-field__value">${p.highFatRate}</span></div>
|
||||
<div class="profile-field"><span class="profile-field__label">偏好餐次</span><span class="profile-field__value">${p.preferMeal}</span></div>
|
||||
</div>
|
||||
<div class="profile-field" style="border-bottom:none;padding:12px 0 4px;"><span class="profile-field__label">最近一次就餐</span><span class="profile-field__value">${p.lastMeal}</span></div>
|
||||
<div style="margin-top:16px;font-size:var(--font-sm);font-weight:600;color:var(--text-primary);margin-bottom:10px;">📋 最近用餐明细(${p.mealHistory.length}条)</div>
|
||||
<table class="meal-history-table">
|
||||
<thead><tr><th>日期</th><th>餐次</th><th>菜品</th><th>热量</th><th>营养评分</th></tr></thead>
|
||||
<tbody>${p.mealHistory.map(h => '<tr><td>'+h.date+'</td><td><span class="tag tag-blue">'+h.meal+'</span></td><td>'+h.dishes+'</td><td>'+h.cal+'</td><td><span class="score-tag'+(h.score>=90?' score-green':h.score>=85?' score-green':' score-orange')+'">'+h.score+'分</span></td></tr>').join('')}</tbody>
|
||||
</table>`,
|
||||
dish: `<div class="dish-pref-section">
|
||||
<div class="dish-pref-item"><div class="dish-pref-item__label">常点菜品</div><div class="dish-pref-item__tags">${p.favDish.split('、').map(d=>'<span class="dish-tag">'+d+'</span>').join('')}</div></div>
|
||||
<div class="dish-pref-item"><div class="dish-pref-item__label">系统推荐</div><div class="dish-pref-item__tags">${p.recDish.split('、').map(d=>'<span class="dish-tag">'+d+'</span>').join('')}</div></div>
|
||||
<div class="dish-pref-item"><div class="dish-pref-item__label">忌口菜品</div><div class="dish-pref-item__value">${p.avoidDish||'暂无'}</div></div>
|
||||
<div class="dish-pref-item"><div class="dish-pref-item__label">评分最高</div><div class="dish-pref-item__big">${p.topRate}</div></div>
|
||||
<div class="dish-pref-item"><div class="dish-pref-item__label">复购冠军</div><div class="dish-pref-item__big">${p.repurchase}</div></div>
|
||||
</div>`,
|
||||
dish: `<div class="profile-grid">
|
||||
<div class="profile-field"><span class="profile-field__label">常点菜品</span><span class="profile-field__value">${p.favDish}</span></div>
|
||||
<div class="profile-field"><span class="profile-field__label">系统推荐</span><span class="profile-field__value">${p.recDish}</span></div>
|
||||
<div class="profile-field"><span class="profile-field__label">忌口菜品</span><span class="profile-field__value">${p.avoidDish}</span></div>
|
||||
<div class="profile-field"><span class="profile-field__label">评分最高</span><span class="profile-field__value">${p.topRate}</span></div>
|
||||
<div class="profile-field"><span class="profile-field__label">复购冠军</span><span class="profile-field__value">${p.repurchase}</span></div>
|
||||
mom: `<div class="mom-section">
|
||||
<div class="mom-header">
|
||||
<div class="mom-header__icon">🐱</div>
|
||||
<div class="mom-header__info"><div class="mom-header__title">家乡:${p.hometown}</div><div class="mom-header__sub">从童年记忆中沉淀的味觉偏好与情感连接</div></div>
|
||||
</div>
|
||||
<div class="mom-header__tags">${p.momTag.split('、').map(t=>'<span class="mom-tag">'+t+'</span>').join('')}</div>
|
||||
</div>
|
||||
<div class="dish-pref-section" style="margin-top:20px;">
|
||||
<div class="dish-pref-item"><div class="dish-pref-item__label">思乡菜清单</div><div class="dish-pref-item__tags">${p.momList.split('、').map(d=>'<span class="dish-tag" style="color:#FA8C16;background:#FFF7E6;border-color:#FFD591;">'+d+'</span>').join('')}</div></div>
|
||||
<div class="dish-pref-item"><div class="dish-pref-item__label">关联记忆</div><div class="dish-pref-item__value" style="margin-top:4px;">${p.memory}</div></div>
|
||||
<div class="dish-pref-item"><div class="dish-pref-item__label">推荐尝试</div><div class="dish-pref-item__value" style="color:#52C41A;font-weight:600;margin-top:4px;">${p.recTry}</div></div>
|
||||
</div>`,
|
||||
mom: `<div class="profile-grid">
|
||||
<div class="profile-field"><span class="profile-field__label">家乡</span><span class="profile-field__value">${p.hometown}</span></div>
|
||||
<div class="profile-field"><span class="profile-field__label">妈妈味道标签</span><span class="profile-field__value">${p.momTag}</span></div>
|
||||
<div class="profile-field"><span class="profile-field__label">思乡菜清单</span><span class="profile-field__value">${p.momList}</span></div>
|
||||
<div class="profile-field"><span class="profile-field__label">关联记忆</span><span class="profile-field__value">${p.memory}</span></div>
|
||||
<div class="profile-field"><span class="profile-field__label">推荐尝试</span><span class="profile-field__value">${p.recTry}</span></div>
|
||||
</div>`,
|
||||
model: `<div class="profile-grid">
|
||||
<div class="profile-field"><span class="profile-field__label">模型版本</span><span class="profile-field__value">${p.modelVer}</span></div>
|
||||
<div class="profile-field"><span class="profile-field__label">生成时间</span><span class="profile-field__value">${p.modelTime}</span></div>
|
||||
<div class="profile-field"><span class="profile-field__label">推荐热量</span><span class="profile-field__value">${p.recCal}</span></div>
|
||||
<div class="profile-field"><span class="profile-field__label">营养侧重</span><span class="profile-field__value">${p.nutriFocus}</span></div>
|
||||
<div class="profile-field"><span class="profile-field__label">风险预警</span><span class="profile-field__value">${p.risk}</span></div>
|
||||
<div class="profile-field"><span class="profile-field__label">个性标签</span><span class="profile-field__value">${p.tags}</span></div>
|
||||
<div class="profile-field"><span class="profile-field__label">模型置信度</span><span class="profile-field__value">${p.confidence}</span></div>
|
||||
</div>`
|
||||
model: `<div class="model-section">
|
||||
<div class="model-header">
|
||||
<div class="model-header__icon">🤖</div>
|
||||
<div class="model-header__info"><div class="model-header__title">${name} 的个性化营养模型</div><div class="model-header__sub">${p.modelVer} · 生成于 ${p.modelTime} · 置信度 ${p.confidence}</div></div>
|
||||
</div>
|
||||
<div class="model-header__tags">${p.tags.split('、').map(t=>'<span class="model-tag">'+t+'</span>').join('')}</div>
|
||||
</div>
|
||||
<div class="model-grid">
|
||||
<div class="model-item"><div class="model-item__label">推荐每日热量</div><div class="model-item__big">${p.recCal}</div></div>
|
||||
<div class="model-item"><div class="model-item__label">营养侧重</div><div class="model-item__big">${p.nutriFocus}</div></div>
|
||||
<div class="model-item"><div class="model-item__label">风险预警</div><div class="model-item__value"><span class="risk-tag${p.risk==='无风险'?' risk-safe':' risk-warn'}">${p.risk==='无风险'?'✅ ':''} ${p.risk}</span></div></div>
|
||||
<div class="model-item"><div class="model-item__label">下次模型更新</div><div class="model-item__big">${p.nextUpdate}</div></div>
|
||||
</div>
|
||||
<div class="model-footer">ℹ️ 个性模型由前9维档案数据综合计算生成(含菜品偏好、妈妈味道等情感维度),每月自动更新一次</div>`
|
||||
};
|
||||
const tabs = tabDefs.map((t, i) => `<div class="profile-tab${i===0?' active':''}" onclick="switchTab(this,'${t.key}')">${t.label}</div>`).join('');
|
||||
const panelsHtml = tabDefs.map((t, i) => `<div class="profile-panel${i===0?' active':''}" data-panel="${t.key}">${panels[t.key]}</div>`).join('');
|
||||
@@ -416,6 +524,121 @@ document.querySelectorAll('tbody tr').forEach(row => {
|
||||
link.addEventListener('click', () => showUserProfile(nameCell.textContent));
|
||||
}
|
||||
});
|
||||
|
||||
/* ========== 取餐详情弹窗 ========== */
|
||||
const mealData = {
|
||||
'M-20260428-001': [
|
||||
{ name:'清炒生菜', type:'秤', weight:133.0, cal:24.6, carb:1.6, fat:1.4, protein:2.2 },
|
||||
{ name:'西红柿鸡蛋', type:'秤', weight:114.0, cal:94.5, carb:4.7, fat:5.1, protein:8.4 },
|
||||
{ name:'辣子鸡丁', type:'秤', weight:79.0, cal:92.5, carb:3.3, fat:4.6, protein:9.8 }
|
||||
],
|
||||
'M-20260428-002': [
|
||||
{ name:'藜麦沙拉', type:'秤', weight:150.0, cal:68.0, carb:12.5, fat:1.8, protein:3.2 },
|
||||
{ name:'清蒸鲈鱼', type:'秤', weight:120.0, cal:112.0, carb:0.5, fat:4.2, protein:18.6 },
|
||||
{ name:'蒜蓉西兰花', type:'秤', weight:95.0, cal:32.0, carb:4.1, fat:1.2, protein:2.8 }
|
||||
],
|
||||
'M-20260428-003': [
|
||||
{ name:'红烧肉', type:'秤', weight:85.0, cal:210.5, carb:5.2, fat:15.3, protein:12.1 },
|
||||
{ name:'米饭', type:'秤', weight:200.0, cal:232.0, carb:50.8, fat:0.6, protein:4.6 }
|
||||
],
|
||||
'M-20260428-004': [
|
||||
{ name:'宫保鸡丁', type:'秤', weight:110.0, cal:145.0, carb:8.2, fat:7.5, protein:12.3 },
|
||||
{ name:'番茄牛腩', type:'秤', weight:130.0, cal:125.0, carb:6.8, fat:5.2, protein:14.5 },
|
||||
{ name:'杂粮饭', type:'秤', weight:180.0, cal:198.0, carb:42.0, fat:1.2, protein:5.8 }
|
||||
],
|
||||
'M-20260428-005': [
|
||||
{ name:'小米粥', type:'秤', weight:250.0, cal:115.0, carb:24.5, fat:0.8, protein:2.4 },
|
||||
{ name:'煎蛋', type:'秤', weight:60.0, cal:90.0, carb:0.6, fat:7.0, protein:6.3 },
|
||||
{ name:'全麦馒头', type:'秤', weight:80.0, cal:176.0, carb:35.2, fat:1.5, protein:6.8 }
|
||||
],
|
||||
'M-20260428-006': [
|
||||
{ name:'鸡胸肉沙拉', type:'秤', weight:180.0, cal:145.0, carb:5.2, fat:3.8, protein:22.5 },
|
||||
{ name:'玉米浓汤', type:'秤', weight:200.0, cal:88.0, carb:16.0, fat:2.1, protein:2.8 }
|
||||
],
|
||||
'SP-001-001': [
|
||||
{ name:'余量套餐A', type:'秤', weight:220.0, cal:185.0, carb:28.0, fat:4.5, protein:9.2 }
|
||||
],
|
||||
'SP-001-003': [
|
||||
{ name:'余量套餐B', type:'秤', weight:195.0, cal:168.0, carb:25.5, fat:3.8, protein:8.5 }
|
||||
],
|
||||
'M-20260428-007': [
|
||||
{ name:'糖醋里脊', type:'秤', weight:95.0, cal:178.0, carb:14.2, fat:8.5, protein:11.8 },
|
||||
{ name:'蛋花汤', type:'秤', weight:200.0, cal:35.0, carb:1.2, fat:1.5, protein:3.8 },
|
||||
{ name:'米饭', type:'秤', weight:180.0, cal:208.8, carb:45.7, fat:0.5, protein:4.1 }
|
||||
]
|
||||
};
|
||||
|
||||
function showMealDetail(row) {
|
||||
const cells = row.querySelectorAll('td');
|
||||
const recordId = cells[0].textContent;
|
||||
const name = cells[1].textContent;
|
||||
const empNo = cells[2].textContent;
|
||||
const unit = cells[3].textContent;
|
||||
const dept = cells[4].textContent;
|
||||
const mealTime = cells[5].textContent;
|
||||
const pickupMethod = cells[6].textContent.trim();
|
||||
const pickupType = cells[7].textContent.trim();
|
||||
const startTime = cells[9].textContent;
|
||||
const endTime = cells[10].textContent;
|
||||
|
||||
const items = mealData[recordId] || [];
|
||||
const totalWeight = items.reduce((s, i) => s + i.weight, 0);
|
||||
const totalCal = items.reduce((s, i) => s + i.cal, 0);
|
||||
const totalCarb = items.reduce((s, i) => s + i.carb, 0);
|
||||
const totalFat = items.reduce((s, i) => s + i.fat, 0);
|
||||
const totalProtein = items.reduce((s, i) => s + i.protein, 0);
|
||||
|
||||
const infoHtml = `<div class="meal-section">
|
||||
<div class="meal-section__title">基本信息</div>
|
||||
<div class="meal-info-grid">
|
||||
<div class="meal-info-item"><span class="meal-info-item__label">就餐记录号</span><span class="meal-info-item__value">${recordId}</span></div>
|
||||
<div class="meal-info-item"><span class="meal-info-item__label">姓名</span><span class="meal-info-item__value">${name}</span></div>
|
||||
<div class="meal-info-item"><span class="meal-info-item__label">员工编号</span><span class="meal-info-item__value">${empNo}</span></div>
|
||||
<div class="meal-info-item"><span class="meal-info-item__label">单位</span><span class="meal-info-item__value">${unit}</span></div>
|
||||
<div class="meal-info-item"><span class="meal-info-item__label">部门</span><span class="meal-info-item__value">${dept}</span></div>
|
||||
<div class="meal-info-item"><span class="meal-info-item__label">餐次</span><span class="meal-info-item__value">${mealTime}</span></div>
|
||||
<div class="meal-info-item"><span class="meal-info-item__label">取餐方式</span><span class="meal-info-item__value">${pickupMethod}</span></div>
|
||||
<div class="meal-info-item"><span class="meal-info-item__label">取餐类型</span><span class="meal-info-item__value">${pickupType}</span></div>
|
||||
<div class="meal-info-item"><span class="meal-info-item__label">取餐时间</span><span class="meal-info-item__value">${startTime} ~ ${endTime}</span></div>
|
||||
</div>
|
||||
</div>`;
|
||||
|
||||
const tableRows = items.map(i => `<tr>
|
||||
<td>${i.name}</td>
|
||||
<td>${i.weight.toFixed(1)}</td>
|
||||
<td>${i.cal.toFixed(1)}</td>
|
||||
<td>${i.carb.toFixed(1)}</td>
|
||||
<td>${i.fat.toFixed(1)}</td>
|
||||
<td>${i.protein.toFixed(1)}</td>
|
||||
</tr>`).join('');
|
||||
|
||||
const summaryRow = `<tr>
|
||||
<td>合计</td>
|
||||
<td>${totalWeight.toFixed(1)}克</td>
|
||||
<td>${totalCal.toFixed(1)}千卡</td>
|
||||
<td>${totalCarb.toFixed(1)}克</td>
|
||||
<td>${totalFat.toFixed(1)}克</td>
|
||||
<td>${totalProtein.toFixed(1)}克</td>
|
||||
</tr>`;
|
||||
|
||||
const tableHtml = `<div class="meal-section">
|
||||
<div class="meal-section__title">餐品列表</div>
|
||||
<table class="meal-table">
|
||||
<thead><tr><th>餐品名称</th><th>重量(克)</th><th>热量(千卡)</th><th>碳水化合物(克)</th><th>脂肪(克)</th><th>蛋白质(克)</th></tr></thead>
|
||||
<tbody>${tableRows}${summaryRow}</tbody>
|
||||
</table>
|
||||
</div>`;
|
||||
|
||||
Modal.open('取餐详情 — ' + name, infoHtml + tableHtml);
|
||||
}
|
||||
|
||||
/* 绑定"取餐总数量"列点击事件 */
|
||||
document.querySelectorAll('tbody tr').forEach(row => {
|
||||
const quantityLink = row.querySelector('td:nth-child(12) .link');
|
||||
if (quantityLink) {
|
||||
quantityLink.addEventListener('click', () => showMealDetail(row));
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -87,6 +87,133 @@ 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;}
|
||||
|
||||
/* ===== 周食谱日历 ===== */
|
||||
.recipe-toolbar{display:flex;align-items:center;justify-content:space-between;margin-bottom:16px;}
|
||||
.recipe-toolbar__left{display:flex;align-items:center;gap:16px;}
|
||||
.recipe-toolbar__left label{font-size:var(--font-sm);color:var(--text-secondary);white-space:nowrap;}
|
||||
.recipe-toolbar__right{display:flex;align-items:center;gap:8px;}
|
||||
.btn-outline-danger{height:36px;padding:0 16px;border-radius:var(--radius-sm);font-size:var(--font-sm);cursor:pointer;border:1px solid var(--danger);color:var(--danger);background:#fff;display:inline-flex;align-items:center;gap:6px;transition:all .2s;}
|
||||
.btn-outline-danger:hover{background:#FFF1F0;}
|
||||
.btn-outline-primary{height:36px;padding:0 16px;border-radius:var(--radius-sm);font-size:var(--font-sm);cursor:pointer;border:1px solid var(--primary);color:var(--primary);background:#fff;display:inline-flex;align-items:center;gap:6px;transition:all .2s;}
|
||||
.btn-outline-primary:hover{background:var(--primary-light);}
|
||||
|
||||
.week-grid{background:#fff;border-radius:var(--radius-md);box-shadow:var(--shadow-sm);overflow:hidden;border:1px solid var(--border);}
|
||||
.week-grid table{width:100%;border-collapse:collapse;table-layout:fixed;}
|
||||
.week-grid thead th{background:#FAFAFA;padding:12px 8px;text-align:center;font-size:var(--font-sm);color:var(--text-secondary);font-weight:500;border:1px solid var(--border);}
|
||||
.week-grid thead th .day-date{font-size:var(--font-base);font-weight:600;color:var(--text-primary);}
|
||||
.week-grid thead th .day-name{font-size:var(--font-xs);color:var(--text-secondary);margin-top:2px;}
|
||||
.week-grid thead th.today{background:#FFF7E6;}
|
||||
.week-grid thead th.today .day-date{color:#E8740C;}
|
||||
.week-grid tbody td{border:1px solid var(--border);padding:0;vertical-align:top;height:140px;}
|
||||
.week-grid tbody td.meal-label{width:64px;background:#FAFAFA;text-align:center;vertical-align:middle;font-size:var(--font-sm);font-weight:600;color:#E8740C;padding:12px 8px;white-space:nowrap;}
|
||||
.week-grid tbody td.meal-cell{cursor:pointer;transition:background .15s;position:relative;}
|
||||
.week-grid tbody td.meal-cell:hover{background:#FAFBFF;}
|
||||
.week-grid tbody td.meal-cell .cell-hint{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);color:#ccc;font-size:24px;display:none;pointer-events:none;}
|
||||
.week-grid tbody td.meal-cell:hover .cell-hint{display:block;}
|
||||
.week-grid tbody td.today-col{background:#FFFCF5;}
|
||||
|
||||
.recipe-footer{display:flex;justify-content:flex-end;margin-top:16px;}
|
||||
.btn-save{height:40px;padding:0 24px;border-radius:var(--radius-sm);font-size:var(--font-base);cursor:pointer;border:none;background:#E8740C;color:#fff;display:inline-flex;align-items:center;gap:8px;font-weight:500;transition:all .2s;box-shadow:0 2px 6px rgba(232,116,12,0.3);}
|
||||
.btn-save:hover{background:#D06000;}
|
||||
|
||||
/* ===== 周日历选择器 ===== */
|
||||
.week-picker{position:relative;display:inline-block;}
|
||||
.week-picker__trigger{height:36px;padding:0 32px 0 12px;border:1px solid var(--border);border-radius:var(--radius-sm);font-size:var(--font-sm);color:var(--text-primary);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;cursor:pointer;white-space:nowrap;min-width:300px;text-align:left;display:flex;align-items:center;gap:6px;}
|
||||
.week-picker__trigger:hover{border-color:var(--primary);}
|
||||
.week-picker__trigger.open{border-color:var(--primary);box-shadow:0 0 0 2px rgba(24,144,255,0.15);}
|
||||
.week-picker__trigger svg{flex-shrink:0;opacity:0.5;}
|
||||
.week-picker__dropdown{position:absolute;top:calc(100% + 4px);left:0;z-index:50;background:#fff;border-radius:var(--radius-md);box-shadow:var(--shadow-md);border:1px solid var(--border);padding:12px;width:300px;display:none;}
|
||||
.week-picker__dropdown.show{display:block;}
|
||||
.wp-header{display:flex;align-items:center;justify-content:space-between;margin-bottom:8px;}
|
||||
.wp-header__title{font-size:var(--font-base);font-weight:600;color:var(--text-primary);}
|
||||
.wp-header__btn{width:28px;height:28px;border:none;background:none;cursor:pointer;border-radius:var(--radius-sm);font-size:16px;color:var(--text-secondary);display:flex;align-items:center;justify-content:center;transition:all .15s;}
|
||||
.wp-header__btn:hover{background:#F0F0F0;color:var(--text-primary);}
|
||||
.wp-weekdays{display:grid;grid-template-columns:repeat(7,1fr);text-align:center;margin-bottom:4px;}
|
||||
.wp-weekdays span{font-size:var(--font-xs);color:var(--text-placeholder);padding:4px 0;}
|
||||
.wp-days{display:grid;grid-template-columns:repeat(7,1fr);text-align:center;}
|
||||
.wp-day{padding:6px 0;font-size:var(--font-sm);color:var(--text-primary);cursor:pointer;border-radius:0;transition:background .1s;position:relative;}
|
||||
.wp-day.other-month{color:#ccc;}
|
||||
.wp-day.today{font-weight:700;color:var(--primary);}
|
||||
.wp-day:first-child{border-radius:var(--radius-sm) 0 0 var(--radius-sm);}
|
||||
.wp-day:last-child,.wp-day:nth-child(7n){border-radius:0 var(--radius-sm) var(--radius-sm) 0;}
|
||||
.wp-day:nth-child(7n+1){border-radius:var(--radius-sm) 0 0 var(--radius-sm);}
|
||||
.wp-week-row:hover .wp-day:not(.other-month){background:#E6F7FF;}
|
||||
.wp-week-row:hover .wp-day.other-month{background:#F5FBFF;}
|
||||
.wp-week-row{display:contents;}
|
||||
.wp-week-row.selected .wp-day{background:var(--primary);color:#fff;}
|
||||
.wp-week-row.selected .wp-day.other-month{background:#69B8FF;color:rgba(255,255,255,0.7);}
|
||||
.wp-week-row.selected .wp-day.today{color:#fff;}
|
||||
.wp-today-btn{display:block;width:100%;margin-top:8px;padding:6px 0;border:1px solid var(--border);border-radius:var(--radius-sm);background:#fff;font-size:var(--font-sm);color:var(--primary);cursor:pointer;transition:all .15s;}
|
||||
.wp-today-btn:hover{background:var(--primary-light);border-color:var(--primary);}
|
||||
|
||||
/* ===== 餐品选择弹窗 ===== */
|
||||
.dish-modal-overlay{position:fixed;inset:0;background:rgba(0,0,0,0.45);z-index:200;display:none;align-items:center;justify-content:center;}
|
||||
.dish-modal-overlay.show{display:flex;}
|
||||
.dish-modal{background:#fff;border-radius:var(--radius-lg);width:480px;max-height:70vh;display:flex;flex-direction:column;box-shadow:0 8px 24px rgba(0,0,0,0.18);}
|
||||
.dish-modal__header{display:flex;align-items:center;justify-content:space-between;padding:16px 20px;border-bottom:1px solid var(--border);}
|
||||
.dish-modal__title{font-size:var(--font-base);font-weight:600;color:var(--text-primary);}
|
||||
.dish-modal__close{width:28px;height:28px;border:none;background:none;cursor:pointer;font-size:18px;color:var(--text-secondary);border-radius:var(--radius-sm);display:flex;align-items:center;justify-content:center;}
|
||||
.dish-modal__close:hover{background:#F0F0F0;color:var(--text-primary);}
|
||||
.dish-modal__search{padding:12px 20px;border-bottom:1px solid var(--border);}
|
||||
.dish-modal__search input{width:100%;height:36px;border:1px solid var(--border);border-radius:var(--radius-sm);padding:0 12px 0 32px;font-size:var(--font-sm);outline:none;background:#fff url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='14' fill='none'%3E%3Ccircle cx='6' cy='6' r='4.5' stroke='%23999' stroke-width='1.2'/%3E%3Cpath d='M9.5 9.5L12.5 12.5' stroke='%23999' stroke-width='1.2' stroke-linecap='round'/%3E%3C/svg%3E") no-repeat 10px center;}
|
||||
.dish-modal__search input:focus{border-color:var(--primary);}
|
||||
.dish-modal__list{flex:1;overflow-y:auto;padding:8px 0;}
|
||||
.dish-item{display:flex;align-items:center;gap:10px;padding:10px 20px;cursor:pointer;transition:background .1s;}
|
||||
.dish-item:hover{background:#F8FBFF;}
|
||||
.dish-item.selected{background:var(--primary-light);}
|
||||
.dish-item__check{width:18px;height:18px;border:1.5px solid var(--border);border-radius:3px;flex-shrink:0;display:flex;align-items:center;justify-content:center;transition:all .15s;}
|
||||
.dish-item.selected .dish-item__check{background:var(--primary);border-color:var(--primary);}
|
||||
.dish-item.selected .dish-item__check::after{content:'';display:block;width:5px;height:9px;border:solid #fff;border-width:0 2px 2px 0;transform:rotate(45deg) translate(-1px,-1px);}
|
||||
.dish-item__info{display:flex;flex-direction:column;gap:2px;}
|
||||
.dish-item__name{font-size:var(--font-sm);color:var(--text-primary);}
|
||||
.dish-item__cat{font-size:var(--font-xs);color:var(--text-placeholder);}
|
||||
.dish-modal__footer{display:flex;align-items:center;justify-content:space-between;padding:12px 20px;border-top:1px solid var(--border);}
|
||||
.dish-modal__count{font-size:var(--font-sm);color:var(--text-secondary);}
|
||||
.dish-modal__actions{display:flex;gap:8px;}
|
||||
.dish-modal__actions .btn{min-width:72px;justify-content:center;}
|
||||
|
||||
/* ===== 单元格内餐品标签 ===== */
|
||||
.cell-dishes{display:flex;flex-wrap:wrap;gap:4px;padding:6px 8px;}
|
||||
.cell-dish-tag{display:inline-flex;align-items:center;gap:3px;padding:2px 8px;background:#F0F5FF;border:1px solid #D6E4FF;border-radius:10px;font-size:var(--font-xs);color:var(--primary);max-width:100%;white-space:nowrap;}
|
||||
.cell-dish-tag__del{width:14px;height:14px;border-radius:50%;border:none;background:none;cursor:pointer;font-size:12px;color:var(--text-placeholder);display:inline-flex;align-items:center;justify-content:center;line-height:1;transition:all .1s;}
|
||||
.cell-dish-tag__del:hover{color:var(--danger);background:#FFF1F0;}
|
||||
|
||||
/* ===== 复用规划食谱弹窗 ===== */
|
||||
.reuse-overlay{position:fixed;inset:0;background:rgba(0,0,0,0.45);z-index:200;display:none;align-items:center;justify-content:center;}
|
||||
.reuse-overlay.show{display:flex;}
|
||||
.reuse-modal{background:#fff;border-radius:var(--radius-lg);width:1100px;max-width:92vw;max-height:82vh;display:flex;flex-direction:column;box-shadow:0 8px 24px rgba(0,0,0,0.18);}
|
||||
.reuse-modal__header{display:flex;align-items:center;justify-content:space-between;padding:18px 24px;border-bottom:1px solid var(--border);}
|
||||
.reuse-modal__title{font-size:var(--font-lg);font-weight:600;color:var(--text-primary);}
|
||||
.reuse-modal__close{width:32px;height:32px;border:none;background:none;cursor:pointer;font-size:20px;color:var(--text-secondary);border-radius:var(--radius-sm);display:flex;align-items:center;justify-content:center;}
|
||||
.reuse-modal__close:hover{background:#F5F5F5;color:var(--text-primary);}
|
||||
.reuse-modal__body{display:flex;flex:1;overflow:hidden;}
|
||||
.reuse-modal__left{width:360px;flex-shrink:0;border-right:1px solid var(--border);display:flex;flex-direction:column;}
|
||||
.reuse-modal__search{padding:12px 16px;border-bottom:1px solid var(--border);}
|
||||
.reuse-modal__search input{width:100%;height:36px;border:1px solid var(--border);border-radius:var(--radius-sm);padding:0 12px 0 32px;font-size:var(--font-sm);outline:none;background:#fff url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='14' fill='none'%3E%3Ccircle cx='6' cy='6' r='4.5' stroke='%23999' stroke-width='1.2'/%3E%3Cpath d='M9.5 9.5L12.5 12.5' stroke='%23999' stroke-width='1.2' stroke-linecap='round'/%3E%3C/svg%3E") no-repeat 10px center;}
|
||||
.reuse-modal__search input:focus{border-color:var(--primary);}
|
||||
.reuse-modal__list{flex:1;overflow-y:auto;padding:8px 0;}
|
||||
.reuse-recipe-item{display:flex;align-items:flex-start;gap:10px;padding:12px 16px;cursor:pointer;transition:background .1s;border-bottom:1px solid #F5F5F5;}
|
||||
.reuse-recipe-item:hover{background:#F8FBFF;}
|
||||
.reuse-recipe-item.selected{background:var(--primary-light);}
|
||||
.reuse-recipe-item__radio{width:18px;height:18px;border:1.5px solid var(--border);border-radius:50%;flex-shrink:0;margin-top:2px;display:flex;align-items:center;justify-content:center;transition:all .15s;}
|
||||
.reuse-recipe-item.selected .reuse-recipe-item__radio{border-color:var(--primary);background:var(--primary);}
|
||||
.reuse-recipe-item.selected .reuse-recipe-item__radio::after{content:'';display:block;width:6px;height:6px;border-radius:50%;background:#fff;}
|
||||
.reuse-recipe-item__info{display:flex;flex-direction:column;gap:4px;flex:1;min-width:0;}
|
||||
.reuse-recipe-item__name{font-size:var(--font-sm);font-weight:500;color:var(--text-primary);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}
|
||||
.reuse-recipe-item__meta{display:flex;align-items:center;gap:6px;flex-wrap:wrap;}
|
||||
.reuse-modal__right{flex:1;display:flex;flex-direction:column;overflow:hidden;}
|
||||
.reuse-modal__preview-title{padding:12px 20px;font-size:var(--font-sm);color:var(--text-secondary);border-bottom:1px solid var(--border);flex-shrink:0;}
|
||||
.reuse-modal__preview{flex:1;overflow:auto;padding:16px 20px;}
|
||||
.reuse-modal__preview .week-grid{border:1px solid var(--border);border-radius:var(--radius-md);box-shadow:none;}
|
||||
.reuse-modal__preview .week-grid table{table-layout:fixed;}
|
||||
.reuse-modal__preview .week-grid thead th{padding:10px 6px;font-size:var(--font-xs);}
|
||||
.reuse-modal__preview .week-grid tbody td{height:100px;}
|
||||
.reuse-modal__preview .week-grid .meal-label{width:50px;font-size:var(--font-xs);}
|
||||
.reuse-modal__preview .cell-dishes{padding:4px 6px;gap:3px;}
|
||||
.reuse-modal__preview .cell-dish-tag{font-size:10px;padding:1px 6px;}
|
||||
.reuse-modal__empty{display:flex;align-items:center;justify-content:center;height:100%;color:var(--text-placeholder);font-size:var(--font-sm);}
|
||||
.reuse-modal__footer{display:flex;justify-content:flex-end;gap:8px;padding:16px 24px;border-top:1px solid var(--border);}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
@@ -154,48 +281,642 @@ tbody tr:hover td.td-actions{background:#F8FBFF;}
|
||||
|
||||
<!-- 主内容 -->
|
||||
<main class="main">
|
||||
<!-- 筛选栏 -->
|
||||
<div class="filter-bar">
|
||||
<div class="filter-item"><label>食谱名称</label><input class="filter-input" placeholder="请输入食谱名称"></div>
|
||||
<div class="filter-item"><label>发布状态</label><select class="filter-select"><option>全部</option><option>已发布</option><option>待发布</option><option>已停用</option></select></div>
|
||||
<div class="filter-item"><label>生效周期</label><input class="filter-input" type="date"></div>
|
||||
<div class="filter-item"><label>适用终端</label><select class="filter-select"><option>全部</option><option>食堂</option><option>小程序</option><option>食堂+小程序</option></select></div>
|
||||
<div class="filter-item"><label>成本评估</label><select class="filter-select"><option>全部</option><option>合理</option><option>偏高</option><option>超标</option><option>待评估</option></select></div>
|
||||
<button class="btn btn-primary">查询</button>
|
||||
<button class="btn btn-default">重置</button>
|
||||
<!-- 工具栏:食堂选择 + 周选择 + 操作按钮 -->
|
||||
<div class="recipe-toolbar">
|
||||
<div class="recipe-toolbar__left">
|
||||
<div class="filter-item">
|
||||
<label>食堂:</label>
|
||||
<select class="filter-select" id="canteenSelect">
|
||||
<option value="1" selected>一号食堂</option>
|
||||
<option value="2">二号食堂</option>
|
||||
<option value="3">三号食堂</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="filter-item">
|
||||
<label>当前周:</label>
|
||||
<div class="week-picker" id="weekPicker">
|
||||
<button class="week-picker__trigger" id="wpTrigger">
|
||||
<svg width="14" height="14" viewBox="0 0 14 14" fill="none"><rect x="1" y="2" width="12" height="11" rx="1.5" stroke="currentColor" stroke-width="1.2"/><path d="M1 5.5h12M4 1v2M10 1v2" stroke="currentColor" stroke-width="1.2" stroke-linecap="round"/></svg>
|
||||
<span id="wpLabel">2026-05-18 ~ 2026-05-24</span>
|
||||
</button>
|
||||
<div class="week-picker__dropdown" id="wpDropdown">
|
||||
<div class="wp-header">
|
||||
<button class="wp-header__btn" id="wpPrev">‹</button>
|
||||
<span class="wp-header__title" id="wpMonthTitle">2026年5月</span>
|
||||
<button class="wp-header__btn" id="wpNext">›</button>
|
||||
</div>
|
||||
<div class="wp-weekdays"><span>一</span><span>二</span><span>三</span><span>四</span><span>五</span><span>六</span><span>日</span></div>
|
||||
<div class="wp-days" id="wpDays"></div>
|
||||
<button class="wp-today-btn" id="wpToday">回到本周</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="recipe-toolbar__right">
|
||||
<button class="btn-outline-danger" id="btnResetWeek">↻ 重置本周</button>
|
||||
<button class="btn-outline-primary" id="btnReuseRecipe">📋 复用规划食谱</button>
|
||||
<button class="btn-outline-primary">⧉ 复制到下周</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 表格卡片 -->
|
||||
<div class="action-bar"><!-- 新建食谱:后续用独立二级页面实现 --><button class="btn btn-primary">➕ 新建食谱</button> <button class="btn btn-default">📋 生成净菜订单</button> <button class="btn btn-default">🚀 发布食谱</button> <button class="btn btn-primary"><svg width="14" height="14" viewBox="0 0 14 14" fill="none"><path d="M2 10v2h10v-2M7 2v7M4.5 6.5L7 9l2.5-2.5" stroke="#fff" stroke-width="1.4" stroke-linecap="round" stroke-linejoin="round"/></svg>导出列表数据</button> <button class="btn btn-default"><svg width="14" height="14" viewBox="0 0 14 14" fill="none"><rect x="2" y="2" width="10" height="10" rx="1.5" stroke="currentColor" stroke-width="1.4"/><path d="M4 5h6M4 7.5h4" stroke="currentColor" stroke-width="1.2" stroke-linecap="round"/></svg>查看导出任务</button></div>
|
||||
<div class="table-card">
|
||||
<div class="table-card__header">
|
||||
<div class="table-card__title">食谱管理</div>
|
||||
</div>
|
||||
<div class="table-card__content">
|
||||
<table>
|
||||
<thead><tr><th>食谱编号</th><th>食谱名称</th><th>生效周期</th><th>适用食堂</th><th>适用终端</th><th>菜品数</th><th>发布状态</th><th>净菜订单状态</th><th>成本评估</th><th>最近发布时间</th><th>发布人</th><th>操作</th></tr></thead>
|
||||
<tbody>
|
||||
<tr><td>RECIPE-015</td><td>第15周营养食谱</td><td>2026-04-14~20</td><td>一号食堂/二号食堂</td><td>食堂+小程序</td><td>42道</td><td><span class="tag tag-green">已发布</span></td><td><span class="tag tag-blue">已生成</span></td><td><span class="tag tag-green">合理</span></td><td>2026-04-13 18:30</td><td>营养师李明</td><td class="td-actions"><span class="link">编辑</span> <span class="link">详情</span> <span class="link" style="color:var(--danger)">删除</span></td></tr>
|
||||
<tr><td>RECIPE-014</td><td>第14周营养食谱</td><td>2026-04-07~13</td><td>一号食堂</td><td>食堂+小程序</td><td>38道</td><td><span class="tag tag-green">已发布</span></td><td><span class="tag tag-blue">已生成</span></td><td><span class="tag tag-orange">偏高</span></td><td>2026-04-06 18:10</td><td>营养师李明</td><td class="td-actions"><span class="link">编辑</span> <span class="link">详情</span> <span class="link" style="color:var(--danger)">删除</span></td></tr>
|
||||
<tr><td>RECIPE-016</td><td>第16周营养食谱</td><td>2026-04-21~27</td><td>一号食堂/三号食堂</td><td>食堂+小程序</td><td>40道</td><td><span class="tag tag-orange">待发布</span></td><td><span class="tag tag-orange">待生成</span></td><td><span class="tag tag-gray">待评估</span></td><td>—</td><td>营养师李明</td><td class="td-actions"><span class="link">编辑</span> <span class="link">详情</span> <span class="link" style="color:var(--danger)">删除</span></td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="pagination">
|
||||
<span>显示 3 条,共 12 条</span>
|
||||
<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">4</button>
|
||||
<button class="page-btn">›</button>
|
||||
</div>
|
||||
<!-- 周食谱网格 -->
|
||||
<div class="week-grid">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="width:64px;"></th>
|
||||
<th><div class="day-date">2026-05-18</div><div class="day-name">星期一</div></th>
|
||||
<th class="today"><div class="day-date">2026-05-19</div><div class="day-name">星期二</div></th>
|
||||
<th><div class="day-date">2026-05-20</div><div class="day-name">星期三</div></th>
|
||||
<th><div class="day-date">2026-05-21</div><div class="day-name">星期四</div></th>
|
||||
<th><div class="day-date">2026-05-22</div><div class="day-name">星期五</div></th>
|
||||
<th><div class="day-date">2026-05-23</div><div class="day-name">星期六</div></th>
|
||||
<th><div class="day-date">2026-05-24</div><div class="day-name">星期日</div></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<!-- 早餐 -->
|
||||
<tr>
|
||||
<td class="meal-label">早餐</td>
|
||||
<td class="meal-cell"><span class="cell-hint">+</span></td>
|
||||
<td class="meal-cell today-col"><span class="cell-hint">+</span></td>
|
||||
<td class="meal-cell"><span class="cell-hint">+</span></td>
|
||||
<td class="meal-cell"><span class="cell-hint">+</span></td>
|
||||
<td class="meal-cell"><span class="cell-hint">+</span></td>
|
||||
<td class="meal-cell"><span class="cell-hint">+</span></td>
|
||||
<td class="meal-cell"><span class="cell-hint">+</span></td>
|
||||
</tr>
|
||||
<!-- 午餐 -->
|
||||
<tr>
|
||||
<td class="meal-label">午餐</td>
|
||||
<td class="meal-cell"><span class="cell-hint">+</span></td>
|
||||
<td class="meal-cell today-col"><span class="cell-hint">+</span></td>
|
||||
<td class="meal-cell"><span class="cell-hint">+</span></td>
|
||||
<td class="meal-cell"><span class="cell-hint">+</span></td>
|
||||
<td class="meal-cell"><span class="cell-hint">+</span></td>
|
||||
<td class="meal-cell"><span class="cell-hint">+</span></td>
|
||||
<td class="meal-cell"><span class="cell-hint">+</span></td>
|
||||
</tr>
|
||||
<!-- 晚餐 -->
|
||||
<tr>
|
||||
<td class="meal-label">晚餐</td>
|
||||
<td class="meal-cell"><span class="cell-hint">+</span></td>
|
||||
<td class="meal-cell today-col"><span class="cell-hint">+</span></td>
|
||||
<td class="meal-cell"><span class="cell-hint">+</span></td>
|
||||
<td class="meal-cell"><span class="cell-hint">+</span></td>
|
||||
<td class="meal-cell"><span class="cell-hint">+</span></td>
|
||||
<td class="meal-cell"><span class="cell-hint">+</span></td>
|
||||
<td class="meal-cell"><span class="cell-hint">+</span></td>
|
||||
</tr>
|
||||
<!-- 加餐 -->
|
||||
<tr>
|
||||
<td class="meal-label">加餐</td>
|
||||
<td class="meal-cell"><span class="cell-hint">+</span></td>
|
||||
<td class="meal-cell today-col"><span class="cell-hint">+</span></td>
|
||||
<td class="meal-cell"><span class="cell-hint">+</span></td>
|
||||
<td class="meal-cell"><span class="cell-hint">+</span></td>
|
||||
<td class="meal-cell"><span class="cell-hint">+</span></td>
|
||||
<td class="meal-cell"><span class="cell-hint">+</span></td>
|
||||
<td class="meal-cell"><span class="cell-hint">+</span></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<!-- 底部保存按钮 -->
|
||||
<div class="recipe-footer">
|
||||
<button class="btn-save">💾 保存</button>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<!-- 复用规划食谱弹窗 -->
|
||||
<div class="reuse-overlay" id="reuseOverlay">
|
||||
<div class="reuse-modal">
|
||||
<div class="reuse-modal__header">
|
||||
<div class="reuse-modal__title">复用规划食谱</div>
|
||||
<button class="reuse-modal__close" id="reuseClose">×</button>
|
||||
</div>
|
||||
<div class="reuse-modal__body">
|
||||
<div class="reuse-modal__left">
|
||||
<div class="reuse-modal__search">
|
||||
<input type="text" id="reuseSearch" placeholder="搜索菜谱名称...">
|
||||
</div>
|
||||
<div class="reuse-modal__list" id="reuseList"></div>
|
||||
</div>
|
||||
<div class="reuse-modal__right">
|
||||
<div class="reuse-modal__preview-title">一周菜谱预览</div>
|
||||
<div class="reuse-modal__preview" id="reusePreview">
|
||||
<div class="reuse-modal__empty">请从左侧选择一个食谱查看详情</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="reuse-modal__footer">
|
||||
<button class="btn btn-default" id="reuseCancel">取消</button>
|
||||
<button class="btn btn-primary" id="reuseConfirm">确定复用</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 餐品选择弹窗 -->
|
||||
<div class="dish-modal-overlay" id="dishOverlay">
|
||||
<div class="dish-modal">
|
||||
<div class="dish-modal__header">
|
||||
<span class="dish-modal__title">选择餐品</span>
|
||||
<button class="dish-modal__close" id="dishClose">×</button>
|
||||
</div>
|
||||
<div class="dish-modal__search">
|
||||
<input type="text" id="dishSearch" placeholder="搜索餐品名称...">
|
||||
</div>
|
||||
<div class="dish-modal__list" id="dishList"></div>
|
||||
<div class="dish-modal__footer">
|
||||
<span class="dish-modal__count" id="dishCount">已选 0 项</span>
|
||||
<div class="dish-modal__actions">
|
||||
<button class="btn btn-default" id="dishCancel">取消</button>
|
||||
<button class="btn btn-primary" id="dishConfirm">确认</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
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');})();
|
||||
|
||||
/* ===== 周日历选择器 ===== */
|
||||
(function(){
|
||||
var trigger=document.getElementById('wpTrigger');
|
||||
var dropdown=document.getElementById('wpDropdown');
|
||||
var label=document.getElementById('wpLabel');
|
||||
var monthTitle=document.getElementById('wpMonthTitle');
|
||||
var daysContainer=document.getElementById('wpDays');
|
||||
var prevBtn=document.getElementById('wpPrev');
|
||||
var nextBtn=document.getElementById('wpNext');
|
||||
var todayBtn=document.getElementById('wpToday');
|
||||
|
||||
var today=new Date(2026,4,19); // 2026-05-19
|
||||
var viewYear=2026, viewMonth=4; // 0-indexed
|
||||
var selectedMonday=new Date(2026,4,18); // 当前选中周的周一
|
||||
|
||||
function pad(n){return n<10?'0'+n:n;}
|
||||
function fmt(d){return d.getFullYear()+'-'+pad(d.getMonth()+1)+'-'+pad(d.getDate());}
|
||||
function sameDay(a,b){return a.getFullYear()===b.getFullYear()&&a.getMonth()===b.getMonth()&&a.getDate()===b.getDate();}
|
||||
|
||||
// 获取某日期所在周的周一
|
||||
function getMonday(d){
|
||||
var dt=new Date(d);
|
||||
var day=dt.getDay()||7; // 周日=7
|
||||
dt.setDate(dt.getDate()-(day-1));
|
||||
dt.setHours(0,0,0,0);
|
||||
return dt;
|
||||
}
|
||||
|
||||
function updateLabel(){
|
||||
var sun=new Date(selectedMonday);
|
||||
sun.setDate(sun.getDate()+6);
|
||||
label.textContent=fmt(selectedMonday)+' ~ '+fmt(sun);
|
||||
}
|
||||
|
||||
function updateGrid(){
|
||||
// 更新周食谱网格表头
|
||||
var ths=document.querySelectorAll('.week-grid thead th');
|
||||
var dayNames=['星期一','星期二','星期三','星期四','星期五','星期六','星期日'];
|
||||
for(var i=1;i<ths.length;i++){
|
||||
var d=new Date(selectedMonday);
|
||||
d.setDate(d.getDate()+(i-1));
|
||||
var isToday=sameDay(d,today);
|
||||
ths[i].className=isToday?'today':'';
|
||||
ths[i].innerHTML='<div class="day-date">'+fmt(d)+'</div><div class="day-name">'+dayNames[i-1]+'</div>';
|
||||
}
|
||||
// 更新 today-col
|
||||
var rows=document.querySelectorAll('.week-grid tbody tr');
|
||||
rows.forEach(function(tr){
|
||||
var cells=tr.querySelectorAll('td.meal-cell');
|
||||
cells.forEach(function(td,idx){
|
||||
var d=new Date(selectedMonday);
|
||||
d.setDate(d.getDate()+idx);
|
||||
td.classList.toggle('today-col',sameDay(d,today));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function renderCalendar(){
|
||||
monthTitle.textContent=viewYear+'年'+(viewMonth+1)+'月';
|
||||
daysContainer.innerHTML='';
|
||||
|
||||
// 本月1号
|
||||
var first=new Date(viewYear,viewMonth,1);
|
||||
// 本月1号是周几 (周一=1...周日=7)
|
||||
var startDay=first.getDay()||7;
|
||||
// 日历起始日 = 1号往前推到周一
|
||||
var startDate=new Date(first);
|
||||
startDate.setDate(startDate.getDate()-(startDay-1));
|
||||
|
||||
// 渲染6行(42天)
|
||||
for(var row=0;row<6;row++){
|
||||
var weekDiv=document.createElement('div');
|
||||
weekDiv.className='wp-week-row';
|
||||
var rowMonday=new Date(startDate);
|
||||
rowMonday.setDate(rowMonday.getDate()+row*7);
|
||||
|
||||
for(var col=0;col<7;col++){
|
||||
var d=new Date(rowMonday);
|
||||
d.setDate(d.getDate()+col);
|
||||
var cell=document.createElement('div');
|
||||
cell.className='wp-day';
|
||||
cell.textContent=d.getDate();
|
||||
|
||||
if(d.getMonth()!==viewMonth) cell.classList.add('other-month');
|
||||
if(sameDay(d,today)) cell.classList.add('today');
|
||||
|
||||
(function(date,monday){
|
||||
cell.addEventListener('click',function(){
|
||||
selectedMonday=new Date(monday);
|
||||
updateLabel();
|
||||
updateGrid();
|
||||
renderCalendar();
|
||||
// 关闭面板
|
||||
dropdown.classList.remove('show');
|
||||
trigger.classList.remove('open');
|
||||
});
|
||||
})(d,rowMonday);
|
||||
|
||||
weekDiv.appendChild(cell);
|
||||
}
|
||||
|
||||
// 判断是否是选中周
|
||||
if(sameDay(rowMonday,selectedMonday)){
|
||||
weekDiv.classList.add('selected');
|
||||
}
|
||||
|
||||
daysContainer.appendChild(weekDiv);
|
||||
|
||||
// 如果这行已经超出本月且到下月第2周,停止
|
||||
var lastOfRow=new Date(rowMonday);
|
||||
lastOfRow.setDate(lastOfRow.getDate()+6);
|
||||
if(row>=4 && lastOfRow.getMonth()!==viewMonth && lastOfRow.getDate()>7) break;
|
||||
}
|
||||
}
|
||||
|
||||
// 开关面板
|
||||
trigger.addEventListener('click',function(e){
|
||||
e.stopPropagation();
|
||||
var isOpen=dropdown.classList.contains('show');
|
||||
if(isOpen){
|
||||
dropdown.classList.remove('show');
|
||||
trigger.classList.remove('open');
|
||||
}else{
|
||||
// 打开时定位到选中周所在月
|
||||
viewYear=selectedMonday.getFullYear();
|
||||
viewMonth=selectedMonday.getMonth();
|
||||
renderCalendar();
|
||||
dropdown.classList.add('show');
|
||||
trigger.classList.add('open');
|
||||
}
|
||||
});
|
||||
|
||||
// 点外部关闭
|
||||
document.addEventListener('click',function(e){
|
||||
if(!document.getElementById('weekPicker').contains(e.target)){
|
||||
dropdown.classList.remove('show');
|
||||
trigger.classList.remove('open');
|
||||
}
|
||||
});
|
||||
|
||||
prevBtn.addEventListener('click',function(e){
|
||||
e.stopPropagation();
|
||||
viewMonth--;
|
||||
if(viewMonth<0){viewMonth=11;viewYear--;}
|
||||
renderCalendar();
|
||||
});
|
||||
|
||||
nextBtn.addEventListener('click',function(e){
|
||||
e.stopPropagation();
|
||||
viewMonth++;
|
||||
if(viewMonth>11){viewMonth=0;viewYear++;}
|
||||
renderCalendar();
|
||||
});
|
||||
|
||||
todayBtn.addEventListener('click',function(e){
|
||||
e.stopPropagation();
|
||||
selectedMonday=getMonday(today);
|
||||
viewYear=selectedMonday.getFullYear();
|
||||
viewMonth=selectedMonday.getMonth();
|
||||
updateLabel();
|
||||
updateGrid();
|
||||
renderCalendar();
|
||||
dropdown.classList.remove('show');
|
||||
trigger.classList.remove('open');
|
||||
});
|
||||
|
||||
// 初始化
|
||||
updateLabel();
|
||||
})();
|
||||
|
||||
/* ===== 餐品选择弹窗逻辑 ===== */
|
||||
(function(){
|
||||
var DISHES=[
|
||||
{id:1,name:'白米饭',cat:'主食/米饭'},{id:2,name:'杂粮饭',cat:'主食/米饭'},
|
||||
{id:3,name:'馒头',cat:'主食/面点'},{id:4,name:'花卷',cat:'主食/面点'},
|
||||
{id:5,name:'小米粥',cat:'主食/粥品'},{id:6,name:'皮蛋瘦肉粥',cat:'主食/粥品'},
|
||||
{id:7,name:'红烧肉',cat:'荤菜/猪肉'},{id:8,name:'糖醋排骨',cat:'荤菜/猪肉'},
|
||||
{id:9,name:'清蒸鲈鱼',cat:'荤菜/水产'},{id:10,name:'宫保鸡丁',cat:'荤菜/禽类'},
|
||||
{id:11,name:'西红柿炒蛋',cat:'素菜/蛋类'},{id:12,name:'清炒时蔬',cat:'素菜/叶菜'},
|
||||
{id:13,name:'麻婆豆腐',cat:'素菜/豆制品'},{id:14,name:'凉拌黄瓜',cat:'凉菜/蔬菜'},
|
||||
{id:15,name:'酸辣土豆丝',cat:'素菜/根茎'},{id:16,name:'紫菜蛋花汤',cat:'汤品/蛋汤'},
|
||||
{id:17,name:'冬瓜排骨汤',cat:'汤品/肉汤'},{id:18,name:'水果拼盘',cat:'甜品/水果'},
|
||||
{id:19,name:'绿豆汤',cat:'甜品/糖水'},{id:20,name:'煎饺',cat:'主食/面点'}
|
||||
];
|
||||
|
||||
var overlay=document.getElementById('dishOverlay');
|
||||
var listEl=document.getElementById('dishList');
|
||||
var searchInput=document.getElementById('dishSearch');
|
||||
var countEl=document.getElementById('dishCount');
|
||||
var confirmBtn=document.getElementById('dishConfirm');
|
||||
var cancelBtn=document.getElementById('dishCancel');
|
||||
var closeBtn=document.getElementById('dishClose');
|
||||
|
||||
var currentCell=null; // 当前操作的单元格
|
||||
var tempSelected=[]; // 弹窗内临时选中的id列表
|
||||
|
||||
// 每个单元格存储已选餐品: cell.__dishes = [{id,name}]
|
||||
function getCellDishes(cell){return cell.__dishes||(cell.__dishes=[]);}
|
||||
|
||||
function openModal(cell){
|
||||
currentCell=cell;
|
||||
tempSelected=getCellDishes(cell).map(function(d){return d.id;});
|
||||
searchInput.value='';
|
||||
renderList('');
|
||||
updateCount();
|
||||
overlay.classList.add('show');
|
||||
}
|
||||
|
||||
function closeModal(){
|
||||
overlay.classList.remove('show');
|
||||
currentCell=null;
|
||||
}
|
||||
|
||||
function renderList(keyword){
|
||||
var kw=keyword.trim().toLowerCase();
|
||||
var html='';
|
||||
DISHES.forEach(function(d){
|
||||
if(kw&&d.name.toLowerCase().indexOf(kw)===-1) return;
|
||||
var sel=tempSelected.indexOf(d.id)!==-1;
|
||||
html+='<div class="dish-item'+(sel?' selected':'')+'" data-id="'+d.id+'">'
|
||||
+'<span class="dish-item__check"></span>'
|
||||
+'<span class="dish-item__info"><span class="dish-item__name">'+d.name+'</span><span class="dish-item__cat">'+d.cat+'</span></span>'
|
||||
+'</div>';
|
||||
});
|
||||
if(!html) html='<div style="padding:24px;text-align:center;color:#999;font-size:13px;">无匹配餐品</div>';
|
||||
listEl.innerHTML=html;
|
||||
}
|
||||
|
||||
function updateCount(){
|
||||
countEl.textContent='已选 '+tempSelected.length+' 项';
|
||||
}
|
||||
|
||||
// 点击列表项切换选中
|
||||
listEl.addEventListener('click',function(e){
|
||||
var item=e.target.closest('.dish-item');
|
||||
if(!item) return;
|
||||
var id=parseInt(item.getAttribute('data-id'));
|
||||
var idx=tempSelected.indexOf(id);
|
||||
if(idx===-1){tempSelected.push(id);}else{tempSelected.splice(idx,1);}
|
||||
item.classList.toggle('selected');
|
||||
updateCount();
|
||||
});
|
||||
|
||||
// 搜索
|
||||
searchInput.addEventListener('input',function(){renderList(this.value);});
|
||||
|
||||
// 确认
|
||||
confirmBtn.addEventListener('click',function(){
|
||||
if(!currentCell) return;
|
||||
var dishes=[];
|
||||
tempSelected.forEach(function(id){
|
||||
var d=DISHES.find(function(x){return x.id===id;});
|
||||
if(d) dishes.push({id:d.id,name:d.name});
|
||||
});
|
||||
currentCell.__dishes=dishes;
|
||||
renderCellDishes(currentCell);
|
||||
closeModal();
|
||||
});
|
||||
|
||||
// 渲染单元格内餐品标签
|
||||
function renderCellDishes(cell){
|
||||
// 移除旧内容(保留 cell-hint)
|
||||
var old=cell.querySelector('.cell-dishes');
|
||||
if(old) old.remove();
|
||||
var hint=cell.querySelector('.cell-hint');
|
||||
var dishes=getCellDishes(cell);
|
||||
if(!dishes.length){if(hint)hint.style.display='';return;}
|
||||
if(hint) hint.style.display='none';
|
||||
var wrap=document.createElement('div');
|
||||
wrap.className='cell-dishes';
|
||||
dishes.forEach(function(d){
|
||||
var tag=document.createElement('span');
|
||||
tag.className='cell-dish-tag';
|
||||
tag.innerHTML=d.name+'<button class="cell-dish-tag__del" data-id="'+d.id+'">×</button>';
|
||||
wrap.appendChild(tag);
|
||||
});
|
||||
cell.appendChild(wrap);
|
||||
}
|
||||
|
||||
// 单元格内删除餐品
|
||||
document.querySelector('.week-grid').addEventListener('click',function(e){
|
||||
var delBtn=e.target.closest('.cell-dish-tag__del');
|
||||
if(delBtn){
|
||||
e.stopPropagation();
|
||||
var cell=delBtn.closest('.meal-cell');
|
||||
var id=parseInt(delBtn.getAttribute('data-id'));
|
||||
var dishes=getCellDishes(cell);
|
||||
cell.__dishes=dishes.filter(function(d){return d.id!==id;});
|
||||
renderCellDishes(cell);
|
||||
return;
|
||||
}
|
||||
// 点击单元格打开弹窗
|
||||
var cell=e.target.closest('.meal-cell');
|
||||
if(cell) openModal(cell);
|
||||
});
|
||||
|
||||
// 关闭弹窗
|
||||
cancelBtn.addEventListener('click',closeModal);
|
||||
closeBtn.addEventListener('click',closeModal);
|
||||
overlay.addEventListener('click',function(e){if(e.target===overlay)closeModal();});
|
||||
|
||||
// ===== 预填示例数据 =====
|
||||
var rows=document.querySelectorAll('.week-grid tbody tr');
|
||||
var presetData=[
|
||||
// 早餐 (row 0): 周一~周五
|
||||
[[{id:1,name:'白米饭'},{id:5,name:'小米粥'},{id:3,name:'馒头'}],
|
||||
[{id:6,name:'皮蛋瘦肉粥'},{id:4,name:'花卷'}],
|
||||
[{id:5,name:'小米粥'},{id:20,name:'煎饺'}],
|
||||
[{id:2,name:'杂粮饭'},{id:3,name:'馒头'}],
|
||||
[{id:6,name:'皮蛋瘦肉粥'},{id:20,name:'煎饺'},{id:4,name:'花卷'}],
|
||||
[],[]],
|
||||
// 午餐 (row 1): 周一~周五
|
||||
[[{id:7,name:'红烧肉'},{id:12,name:'清炒时蔬'},{id:16,name:'紫菜蛋花汤'}],
|
||||
[{id:10,name:'宫保鸡丁'},{id:15,name:'酸辣土豆丝'},{id:1,name:'白米饭'}],
|
||||
[{id:8,name:'糖醋排骨'},{id:13,name:'麻婆豆腐'},{id:17,name:'冬瓜排骨汤'}],
|
||||
[{id:9,name:'清蒸鲈鱼'},{id:11,name:'西红柿炒蛋'},{id:1,name:'白米饭'}],
|
||||
[{id:7,name:'红烧肉'},{id:14,name:'凉拌黄瓜'},{id:16,name:'紫菜蛋花汤'}],
|
||||
[],[]],
|
||||
// 晚餐 (row 2): 周一~周四
|
||||
[[{id:11,name:'西红柿炒蛋'},{id:15,name:'酸辣土豆丝'}],
|
||||
[{id:13,name:'麻婆豆腐'},{id:12,name:'清炒时蔬'}],
|
||||
[{id:10,name:'宫保鸡丁'},{id:14,name:'凉拌黄瓜'}],
|
||||
[{id:9,name:'清蒸鲈鱼'},{id:12,name:'清炒时蔬'}],
|
||||
[],[],[]],
|
||||
// 加餐 (row 3): 周一、周三
|
||||
[[{id:18,name:'水果拼盘'}],[],[{id:19,name:'绿豆汤'},{id:18,name:'水果拼盘'}],[],[],[],[]]
|
||||
];
|
||||
rows.forEach(function(tr,rowIdx){
|
||||
if(!presetData[rowIdx]) return;
|
||||
var cells=tr.querySelectorAll('td.meal-cell');
|
||||
cells.forEach(function(cell,colIdx){
|
||||
var data=presetData[rowIdx][colIdx];
|
||||
if(data&&data.length){
|
||||
cell.__dishes=data.slice();
|
||||
renderCellDishes(cell);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// 重置本周:恢复初始数据
|
||||
function resetWeek(){
|
||||
rows.forEach(function(tr,rowIdx){
|
||||
if(!presetData[rowIdx]) return;
|
||||
var cells=tr.querySelectorAll('td.meal-cell');
|
||||
cells.forEach(function(cell,colIdx){
|
||||
var data=presetData[rowIdx][colIdx];
|
||||
cell.__dishes=data&&data.length?data.slice():[];
|
||||
renderCellDishes(cell);
|
||||
});
|
||||
});
|
||||
}
|
||||
document.getElementById('btnResetWeek').addEventListener('click',resetWeek);
|
||||
})();
|
||||
|
||||
/* ===== 复用规划食谱弹窗逻辑 ===== */
|
||||
(function(){
|
||||
var RECIPES=[
|
||||
{id:1,name:'第21周标准营养食谱',population:['普通成人'],rating:'优',
|
||||
meals:[
|
||||
[['白米饭','小米粥','馒头'],['皮蛋瘦肉粥','花卷'],['小米粥','煎饺'],['杂粮饭','馒头'],['皮蛋瘦肉粥','煎饺','花卷'],[],[]],
|
||||
[['红烧肉','清炒时蔬','紫菜蛋花汤'],['宫保鸡丁','酸辣土豆丝','白米饭'],['糖醋排骨','麻婆豆腐','冬瓜排骨汤'],['清蒸鲈鱼','西红柿炒蛋','白米饭'],['红烧肉','凉拌黄瓜','紫菜蛋花汤'],[],[]],
|
||||
[['西红柿炒蛋','酸辣土豆丝'],['麻婆豆腐','清炒时蔬'],['宫保鸡丁','凉拌黄瓜'],['清蒸鲈鱼','清炒时蔬'],[],[],[]],
|
||||
[['水果拼盘'],[],['绿豆汤','水果拼盘'],[],[],[],[]]
|
||||
]},
|
||||
{id:2,name:'第21周老年营养食谱',population:['老年人'],rating:'良',
|
||||
meals:[
|
||||
[['小米粥','馒头'],['燕麦粥','花卷'],['红薯粥','馒头'],['小米粥','花卷'],['燕麦粥','馒头'],[],[]],
|
||||
[['清蒸鲈鱼','清炒时蔬','紫菜蛋花汤'],['番茄炖牛腩','凉拌黄瓜','白米饭'],['清蒸鸡胸','麻婆豆腐','冬瓜排骨汤'],['红烧肉','清炒时蔬','白米饭'],['清蒸鲈鱼','酸辣土豆丝','紫菜蛋花汤'],[],[]],
|
||||
[['西红柿炒蛋','清炒时蔬'],['麻婆豆腐','凉拌黄瓜'],['清蒸鲈鱼','清炒时蔬'],['西红柿炒蛋','酸辣土豆丝'],[],[],[]],
|
||||
[['水果拼盘'],[],['绿豆汤'],[],[],[],[]]
|
||||
]},
|
||||
{id:3,name:'第21周糖尿病专用食谱',population:['糖尿病人群'],rating:'优',
|
||||
meals:[
|
||||
[['杂粮饭','煮鸡蛋'],['燕麦粥','全麦馒头'],['杂粮饭','煮鸡蛋'],['燕麦粥','全麦馒头'],['杂粮饭','煮鸡蛋'],[],[]],
|
||||
[['清蒸鸡胸','清炒西兰花','紫菜蛋花汤'],['清蒸鲈鱼','凉拌黄瓜','杂粮饭'],['番茄炖牛腩','清炒时蔬','冬瓜排骨汤'],['清蒸鸡胸','麻婆豆腐','杂粮饭'],['清蒸鲈鱼','清炒西兰花','紫菜蛋花汤'],[],[]],
|
||||
[['清炒时蔬','凉拌黄瓜'],['麻婆豆腐','清炒西兰花'],['清蒸鲈鱼','凉拌黄瓜'],['清炒时蔬','酸辣土豆丝'],[],[],[]],
|
||||
[[],[],[],[],[],[],[]]
|
||||
]},
|
||||
{id:4,name:'第20周标准营养食谱',population:['普通成人','高血压人群'],rating:'良',
|
||||
meals:[
|
||||
[['白米饭','小米粥'],['皮蛋瘦肉粥','馒头'],['小米粥','花卷'],['杂粮饭','馒头'],['皮蛋瘦肉粥','煎饺'],[],[]],
|
||||
[['红烧肉','清炒时蔬','紫菜蛋花汤'],['宫保鸡丁','凉拌黄瓜','白米饭'],['糖醋排骨','清炒时蔬','冬瓜排骨汤'],['清蒸鲈鱼','西红柿炒蛋','白米饭'],['红烧肉','酸辣土豆丝','紫菜蛋花汤'],[],[]],
|
||||
[['西红柿炒蛋','清炒时蔬'],['麻婆豆腐','凉拌黄瓜'],['宫保鸡丁','酸辣土豆丝'],['清蒸鲈鱼','清炒时蔬'],[],[],[]],
|
||||
[['水果拼盘'],[],[],['绿豆汤'],[],[],[]]
|
||||
]},
|
||||
{id:5,name:'第20周儿童营养食谱',population:['儿童'],rating:'合格',
|
||||
meals:[
|
||||
[['小米粥','馒头','煮鸡蛋'],['牛奶','花卷'],['小米粥','煎饺'],['牛奶','馒头'],['小米粥','花卷','煮鸡蛋'],[],[]],
|
||||
[['番茄炖牛腩','清炒时蔬','紫菜蛋花汤'],['宫保鸡丁','西红柿炒蛋','白米饭'],['糖醋排骨','清炒时蔬','冬瓜排骨汤'],['清蒸鲈鱼','西红柿炒蛋','白米饭'],['红烧肉','清炒时蔬','紫菜蛋花汤'],[],[]],
|
||||
[['西红柿炒蛋','清炒时蔬'],['麻婆豆腐','凉拌黄瓜'],['宫保鸡丁','清炒时蔬'],['清蒸鲈鱼','凉拌黄瓜'],[],[],[]],
|
||||
[['水果拼盘','牛奶'],['水果拼盘'],['绿豆汤','水果拼盘'],['水果拼盘'],[],[],[]]
|
||||
]}
|
||||
];
|
||||
|
||||
var overlay=document.getElementById('reuseOverlay');
|
||||
var listEl=document.getElementById('reuseList');
|
||||
var previewEl=document.getElementById('reusePreview');
|
||||
var searchInput=document.getElementById('reuseSearch');
|
||||
var selectedId=null;
|
||||
|
||||
function renderList(keyword){
|
||||
var kw=(keyword||'').trim().toLowerCase();
|
||||
var html='';
|
||||
RECIPES.forEach(function(r){
|
||||
if(kw&&r.name.toLowerCase().indexOf(kw)===-1) return;
|
||||
var sel=r.id===selectedId;
|
||||
html+='<div class="reuse-recipe-item'+(sel?' selected':'')+'" data-id="'+r.id+'">'
|
||||
+'<span class="reuse-recipe-item__radio"></span>'
|
||||
+'<span class="reuse-recipe-item__info">'
|
||||
+'<span class="reuse-recipe-item__name">'+r.name+'</span>'
|
||||
+'<span class="reuse-recipe-item__meta">';
|
||||
r.population.forEach(function(p){html+='<span class="tag tag-blue">'+p+'</span>';});
|
||||
var ratingClass=r.rating==='优'?'tag-green':r.rating==='良'?'tag-blue':'tag-orange';
|
||||
html+='<span class="tag '+ratingClass+'">'+r.rating+'</span>';
|
||||
html+='</span></span></div>';
|
||||
});
|
||||
if(!html) html='<div style="padding:24px;text-align:center;color:#999;font-size:13px;">无匹配食谱</div>';
|
||||
listEl.innerHTML=html;
|
||||
}
|
||||
|
||||
function renderPreview(recipe){
|
||||
if(!recipe){
|
||||
previewEl.innerHTML='<div class="reuse-modal__empty">请从左侧选择一个食谱查看详情</div>';
|
||||
return;
|
||||
}
|
||||
var mealNames=['早餐','午餐','晚餐','加餐'];
|
||||
var dayNames=['周一','周二','周三','周四','周五','周六','周日'];
|
||||
var html='<div class="week-grid"><table><thead><tr><th style="width:50px;"></th>';
|
||||
dayNames.forEach(function(d){html+='<th><div class="day-date">'+d+'</div></th>';});
|
||||
html+='</tr></thead><tbody>';
|
||||
mealNames.forEach(function(meal,mi){
|
||||
html+='<tr><td class="meal-label">'+meal+'</td>';
|
||||
for(var di=0;di<7;di++){
|
||||
var dishes=recipe.meals[mi]&&recipe.meals[mi][di]||[];
|
||||
html+='<td class="meal-cell"><div class="cell-dishes">';
|
||||
dishes.forEach(function(d){html+='<span class="cell-dish-tag">'+d+'</span>';});
|
||||
html+='</div></td>';
|
||||
}
|
||||
html+='</tr>';
|
||||
});
|
||||
html+='</tbody></table></div>';
|
||||
previewEl.innerHTML=html;
|
||||
}
|
||||
|
||||
function openReuse(){
|
||||
selectedId=null;
|
||||
searchInput.value='';
|
||||
renderList('');
|
||||
renderPreview(null);
|
||||
overlay.classList.add('show');
|
||||
}
|
||||
function closeReuse(){overlay.classList.remove('show');}
|
||||
|
||||
document.getElementById('btnReuseRecipe').addEventListener('click',openReuse);
|
||||
document.getElementById('reuseClose').addEventListener('click',closeReuse);
|
||||
document.getElementById('reuseCancel').addEventListener('click',closeReuse);
|
||||
overlay.addEventListener('click',function(e){if(e.target===overlay)closeReuse();});
|
||||
|
||||
listEl.addEventListener('click',function(e){
|
||||
var item=e.target.closest('.reuse-recipe-item');
|
||||
if(!item) return;
|
||||
var id=parseInt(item.getAttribute('data-id'));
|
||||
selectedId=id;
|
||||
renderList(searchInput.value);
|
||||
var recipe=RECIPES.find(function(r){return r.id===id;});
|
||||
renderPreview(recipe);
|
||||
});
|
||||
|
||||
searchInput.addEventListener('input',function(){renderList(this.value);});
|
||||
|
||||
document.getElementById('reuseConfirm').addEventListener('click',function(){
|
||||
if(!selectedId){alert('请先选择一个食谱');return;}
|
||||
closeReuse();
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,410 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>新建食谱规划 | 健康长庆原型</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;}
|
||||
.main{margin-left:240px;margin-top:56px;padding:24px;min-height:calc(100vh - 56px);}
|
||||
|
||||
/* 页面头部 */
|
||||
.page-header{display:flex;align-items:center;gap:12px;margin-bottom:24px;}
|
||||
.page-header__back{width:32px;height:32px;border:1px solid var(--border);border-radius:var(--radius-sm);background:#fff;cursor:pointer;display:flex;align-items:center;justify-content:center;font-size:16px;color:var(--text-secondary);text-decoration:none;transition:all .15s;}
|
||||
.page-header__back:hover{border-color:var(--primary);color:var(--primary);}
|
||||
.page-header__title{font-size:var(--font-xl);font-weight:600;color:var(--text-primary);}
|
||||
|
||||
/* 表单模块 */
|
||||
.form-section{background:#fff;border-radius:var(--radius-md);box-shadow:var(--shadow-sm);margin-bottom:20px;}
|
||||
.form-section__title{font-size:var(--font-base);font-weight:600;color:var(--text-primary);padding:16px 24px;border-bottom:1px solid var(--border);background:#FAFAFA;border-radius:var(--radius-md) var(--radius-md) 0 0;}
|
||||
.form-section__body{padding:24px;}
|
||||
.form-row{display:grid;grid-template-columns:1fr 1fr 1fr;gap:16px;margin-bottom:16px;}
|
||||
.form-row:last-child{margin-bottom:0;}
|
||||
.form-group{display:flex;flex-direction:column;gap:6px;}
|
||||
.form-group label{font-size:var(--font-sm);color:var(--text-secondary);font-weight:500;}
|
||||
.form-group .required{color:var(--danger);margin-left:2px;}
|
||||
.form-input{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{border-color:var(--primary);}
|
||||
.form-select{width:100%;height:36px;border:1px solid var(--border);border-radius:var(--radius-sm);padding:0 28px 0 12px;font-size:var(--font-sm);outline:none;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;cursor:pointer;}
|
||||
|
||||
/* 多选标签输入 */
|
||||
.multi-select{position:relative;}
|
||||
.multi-select__trigger{min-height:36px;border:1px solid var(--border);border-radius:var(--radius-sm);padding:4px 28px 4px 8px;font-size:var(--font-sm);cursor:pointer;display:flex;flex-wrap:wrap;gap:4px;align-items:center;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;}
|
||||
.multi-select__trigger:hover{border-color:var(--primary);}
|
||||
.multi-select__tag{display:inline-flex;align-items:center;gap:3px;padding:2px 8px;background:var(--primary-light);border-radius:10px;font-size:var(--font-xs);color:var(--primary);}
|
||||
.multi-select__tag-del{cursor:pointer;font-size:12px;opacity:0.7;}.multi-select__tag-del:hover{opacity:1;}
|
||||
.multi-select__placeholder{color:var(--text-placeholder);font-size:var(--font-sm);}
|
||||
.multi-select__dropdown{position:absolute;top:calc(100% + 4px);left:0;right:0;z-index:50;background:#fff;border:1px solid var(--border);border-radius:var(--radius-sm);box-shadow:var(--shadow-md);display:none;max-height:200px;overflow-y:auto;}
|
||||
.multi-select__dropdown.show{display:block;}
|
||||
.multi-select__option{padding:8px 12px;font-size:var(--font-sm);cursor:pointer;transition:background .1s;}
|
||||
.multi-select__option:hover{background:#F8FBFF;}
|
||||
.multi-select__option.selected{background:var(--primary-light);color:var(--primary);}
|
||||
|
||||
/* 周食谱网格 */
|
||||
.week-grid{background:#fff;border-radius:var(--radius-md);box-shadow:var(--shadow-sm);overflow:hidden;border:1px solid var(--border);}
|
||||
.week-grid table{width:100%;border-collapse:collapse;table-layout:fixed;}
|
||||
.week-grid thead th{background:#FAFAFA;padding:12px 8px;text-align:center;font-size:var(--font-sm);color:var(--text-secondary);font-weight:500;border:1px solid var(--border);}
|
||||
.week-grid thead th .day-date{font-size:var(--font-base);font-weight:600;color:var(--text-primary);}
|
||||
.week-grid thead th .day-name{font-size:var(--font-xs);color:var(--text-secondary);margin-top:2px;}
|
||||
.week-grid tbody td{border:1px solid var(--border);padding:0;vertical-align:top;height:140px;}
|
||||
.week-grid tbody td.meal-label{width:64px;background:#FAFAFA;text-align:center;vertical-align:middle;font-size:var(--font-sm);font-weight:600;color:#E8740C;padding:12px 8px;white-space:nowrap;}
|
||||
.week-grid tbody td.meal-cell{cursor:pointer;transition:background .15s;position:relative;}
|
||||
.week-grid tbody td.meal-cell:hover{background:#FAFBFF;}
|
||||
.week-grid tbody td.meal-cell .cell-hint{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);color:#ccc;font-size:24px;display:none;pointer-events:none;}
|
||||
.week-grid tbody td.meal-cell:hover .cell-hint{display:block;}
|
||||
|
||||
/* 单元格内餐品标签 */
|
||||
.cell-dishes{display:flex;flex-wrap:wrap;gap:4px;padding:6px 8px;}
|
||||
.cell-dish-tag{display:inline-flex;align-items:center;gap:3px;padding:2px 8px;background:#F0F5FF;border:1px solid #D6E4FF;border-radius:10px;font-size:var(--font-xs);color:var(--primary);max-width:100%;white-space:nowrap;}
|
||||
.cell-dish-tag__del{width:14px;height:14px;border-radius:50%;border:none;background:none;cursor:pointer;font-size:12px;color:var(--text-placeholder);display:inline-flex;align-items:center;justify-content:center;line-height:1;transition:all .1s;}
|
||||
.cell-dish-tag__del:hover{color:var(--danger);background:#FFF1F0;}
|
||||
|
||||
/* 餐品选择弹窗 */
|
||||
.dish-modal-overlay{position:fixed;inset:0;background:rgba(0,0,0,0.45);z-index:200;display:none;align-items:center;justify-content:center;}
|
||||
.dish-modal-overlay.show{display:flex;}
|
||||
.dish-modal{background:#fff;border-radius:var(--radius-lg);width:540px;max-height:70vh;display:flex;flex-direction:column;box-shadow:0 8px 24px rgba(0,0,0,0.18);}
|
||||
.dish-modal__header{display:flex;align-items:center;justify-content:space-between;padding:16px 20px;border-bottom:1px solid var(--border);}
|
||||
.dish-modal__title{font-size:var(--font-base);font-weight:600;color:var(--text-primary);}
|
||||
.dish-modal__close{width:28px;height:28px;border:none;background:none;cursor:pointer;font-size:18px;color:var(--text-secondary);border-radius:var(--radius-sm);display:flex;align-items:center;justify-content:center;}
|
||||
.dish-modal__close:hover{background:#F0F0F0;color:var(--text-primary);}
|
||||
.dish-modal__search{padding:12px 20px;border-bottom:1px solid var(--border);}
|
||||
.dish-modal__search input{width:100%;height:36px;border:1px solid var(--border);border-radius:var(--radius-sm);padding:0 12px 0 32px;font-size:var(--font-sm);outline:none;background:#fff url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='14' fill='none'%3E%3Ccircle cx='6' cy='6' r='4.5' stroke='%23999' stroke-width='1.2'/%3E%3Cpath d='M9.5 9.5L12.5 12.5' stroke='%23999' stroke-width='1.2' stroke-linecap='round'/%3E%3C/svg%3E") no-repeat 10px center;}
|
||||
.dish-modal__search input:focus{border-color:var(--primary);}
|
||||
.dish-modal__list{flex:1;overflow-y:auto;padding:8px 0;}
|
||||
.dish-item{display:flex;align-items:center;gap:10px;padding:10px 20px;cursor:pointer;transition:background .1s;}
|
||||
.dish-item:hover{background:#F8FBFF;}
|
||||
.dish-item.selected{background:var(--primary-light);}
|
||||
.dish-item__check{width:18px;height:18px;border:1.5px solid var(--border);border-radius:3px;flex-shrink:0;display:flex;align-items:center;justify-content:center;transition:all .15s;}
|
||||
.dish-item.selected .dish-item__check{background:var(--primary);border-color:var(--primary);}
|
||||
.dish-item.selected .dish-item__check::after{content:'';display:block;width:5px;height:9px;border:solid #fff;border-width:0 2px 2px 0;transform:rotate(45deg) translate(-1px,-1px);}
|
||||
.dish-item__info{display:flex;flex-direction:column;gap:2px;flex:1;min-width:0;}
|
||||
.dish-item__name{font-size:var(--font-sm);color:var(--text-primary);}
|
||||
.dish-item__cat{font-size:var(--font-xs);color:var(--text-placeholder);}
|
||||
.dish-item__nutri{display:flex;gap:8px;margin-top:2px;}
|
||||
.dish-item__nutri span{font-size:var(--font-xs);color:var(--text-secondary);white-space:nowrap;}
|
||||
.dish-item__nutri span em{font-style:normal;color:var(--text-primary);font-weight:500;}
|
||||
.dish-modal__footer{display:flex;align-items:center;justify-content:space-between;padding:12px 20px;border-top:1px solid var(--border);}
|
||||
.dish-modal__count{font-size:var(--font-sm);color:var(--text-secondary);}
|
||||
.dish-modal__actions{display:flex;gap:8px;}
|
||||
|
||||
/* 按钮 */
|
||||
.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);}
|
||||
|
||||
/* 底部操作 */
|
||||
.page-footer{display:flex;justify-content:flex-end;gap:12px;margin-top:24px;}
|
||||
.btn-lg{height:40px;padding:0 24px;font-size:var(--font-base);font-weight:500;}
|
||||
</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" class="active">健康生产</a>
|
||||
<a href="din-dict-mgmt.html">营养用餐</a>
|
||||
<a href="ano-dirty.html">异常事件</a>
|
||||
</nav>
|
||||
<div class="top-bar__right">
|
||||
<a class="btn-back" href="../../index.html">← 返回首页</a>
|
||||
<div class="avatar">管</div>
|
||||
<span>系统管理员 ▾</span>
|
||||
</div>
|
||||
</header>
|
||||
<!-- 侧边栏 -->
|
||||
<aside class="sidebar">
|
||||
<div class="sidebar-menu__title">健康生产</div>
|
||||
<a href="prod-qc-daily.html" class="sidebar-item"><span class="mi">🛡️</span>食安监控</a>
|
||||
<a href="prod-recipe-plan.html" class="sidebar-item active"><span class="mi">📋</span>食谱规划</a>
|
||||
<a href="prod-clean-order.html" class="sidebar-item"><span class="mi">📝</span>净菜订单</a>
|
||||
<a href="prod-proc-cabinet.html" class="sidebar-item"><span class="mi">🗄️</span>净菜进柜</a>
|
||||
<a href="prod-proc-combo.html" class="sidebar-item"><span class="mi">🔪</span>净菜组配</a>
|
||||
<a href="prod-proc-cook.html" class="sidebar-item"><span class="mi">🍳</span>按单烹制</a>
|
||||
<a href="prod-proc-serve.html" class="sidebar-item"><span class="mi">🍽️</span>上餐监控</a>
|
||||
<a href="prod-proc-surplus.html" class="sidebar-item"><span class="mi">♻️</span>余量处置</a>
|
||||
<a href="prod-proc-stats.html" class="sidebar-item"><span class="mi">📊</span>生产统计</a>
|
||||
</aside>
|
||||
<!-- PLACEHOLDER_MAIN -->
|
||||
<main class="main">
|
||||
<!-- 页面头部 -->
|
||||
<div class="page-header">
|
||||
<a href="prod-recipe-plan.html" class="page-header__back">←</a>
|
||||
<h1 class="page-header__title">新建食谱规划</h1>
|
||||
</div>
|
||||
|
||||
<!-- 模块一:基本信息 -->
|
||||
<div class="form-section">
|
||||
<div class="form-section__title">基本信息</div>
|
||||
<div class="form-section__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>
|
||||
<div class="multi-select" id="msPopulation">
|
||||
<div class="multi-select__trigger" id="msTrigger">
|
||||
<span class="multi-select__placeholder">请选择适应人群</span>
|
||||
</div>
|
||||
<div class="multi-select__dropdown" id="msDropdown">
|
||||
<div class="multi-select__option" data-value="普通成人">普通成人</div>
|
||||
<div class="multi-select__option" data-value="老年人">老年人</div>
|
||||
<div class="multi-select__option" data-value="糖尿病人群">糖尿病人群</div>
|
||||
<div class="multi-select__option" data-value="高血压人群">高血压人群</div>
|
||||
<div class="multi-select__option" data-value="儿童">儿童</div>
|
||||
<div class="multi-select__option" data-value="孕产妇">孕产妇</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>营养达标评级</label>
|
||||
<select class="form-select">
|
||||
<option value="">请选择</option>
|
||||
<option>优</option>
|
||||
<option>良</option>
|
||||
<option>合格</option>
|
||||
<option>不合格</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 模块二:一周菜谱 -->
|
||||
<div class="form-section">
|
||||
<div class="form-section__title">一周菜谱</div>
|
||||
<div class="form-section__body" style="padding:0;">
|
||||
<div class="week-grid" style="border:none;box-shadow:none;border-radius:0;">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="width:64px;"></th>
|
||||
<th><div class="day-date">周一</div></th>
|
||||
<th><div class="day-date">周二</div></th>
|
||||
<th><div class="day-date">周三</div></th>
|
||||
<th><div class="day-date">周四</div></th>
|
||||
<th><div class="day-date">周五</div></th>
|
||||
<th><div class="day-date">周六</div></th>
|
||||
<th><div class="day-date">周日</div></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr><td class="meal-label">早餐</td><td class="meal-cell"><span class="cell-hint">+</span></td><td class="meal-cell"><span class="cell-hint">+</span></td><td class="meal-cell"><span class="cell-hint">+</span></td><td class="meal-cell"><span class="cell-hint">+</span></td><td class="meal-cell"><span class="cell-hint">+</span></td><td class="meal-cell"><span class="cell-hint">+</span></td><td class="meal-cell"><span class="cell-hint">+</span></td></tr>
|
||||
<tr><td class="meal-label">午餐</td><td class="meal-cell"><span class="cell-hint">+</span></td><td class="meal-cell"><span class="cell-hint">+</span></td><td class="meal-cell"><span class="cell-hint">+</span></td><td class="meal-cell"><span class="cell-hint">+</span></td><td class="meal-cell"><span class="cell-hint">+</span></td><td class="meal-cell"><span class="cell-hint">+</span></td><td class="meal-cell"><span class="cell-hint">+</span></td></tr>
|
||||
<tr><td class="meal-label">晚餐</td><td class="meal-cell"><span class="cell-hint">+</span></td><td class="meal-cell"><span class="cell-hint">+</span></td><td class="meal-cell"><span class="cell-hint">+</span></td><td class="meal-cell"><span class="cell-hint">+</span></td><td class="meal-cell"><span class="cell-hint">+</span></td><td class="meal-cell"><span class="cell-hint">+</span></td><td class="meal-cell"><span class="cell-hint">+</span></td></tr>
|
||||
<tr><td class="meal-label">加餐</td><td class="meal-cell"><span class="cell-hint">+</span></td><td class="meal-cell"><span class="cell-hint">+</span></td><td class="meal-cell"><span class="cell-hint">+</span></td><td class="meal-cell"><span class="cell-hint">+</span></td><td class="meal-cell"><span class="cell-hint">+</span></td><td class="meal-cell"><span class="cell-hint">+</span></td><td class="meal-cell"><span class="cell-hint">+</span></td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 底部操作 -->
|
||||
<div class="page-footer">
|
||||
<a href="prod-recipe-plan.html" class="btn btn-default btn-lg">取消</a>
|
||||
<button class="btn btn-primary btn-lg" style="background:#E8740C;">提交审核</button>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<!-- 餐品选择弹窗 -->
|
||||
<div class="dish-modal-overlay" id="dishOverlay">
|
||||
<div class="dish-modal">
|
||||
<div class="dish-modal__header">
|
||||
<span class="dish-modal__title">选择餐品</span>
|
||||
<button class="dish-modal__close" id="dishClose">×</button>
|
||||
</div>
|
||||
<div class="dish-modal__search">
|
||||
<input type="text" id="dishSearch" placeholder="搜索餐品名称...">
|
||||
</div>
|
||||
<div class="dish-modal__list" id="dishList"></div>
|
||||
<div class="dish-modal__footer">
|
||||
<span class="dish-modal__count" id="dishCount">已选 0 项</span>
|
||||
<div class="dish-modal__actions">
|
||||
<button class="btn btn-default" id="dishCancel">取消</button>
|
||||
<button class="btn btn-primary" id="dishConfirm">确认</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
/* ===== 多选下拉 ===== */
|
||||
(function(){
|
||||
var trigger=document.getElementById('msTrigger');
|
||||
var dropdown=document.getElementById('msDropdown');
|
||||
var selected=[];
|
||||
|
||||
function render(){
|
||||
if(!selected.length){
|
||||
trigger.innerHTML='<span class="multi-select__placeholder">请选择适应人群</span>';
|
||||
}else{
|
||||
trigger.innerHTML=selected.map(function(v){
|
||||
return '<span class="multi-select__tag">'+v+'<span class="multi-select__tag-del" data-val="'+v+'">×</span></span>';
|
||||
}).join('');
|
||||
}
|
||||
dropdown.querySelectorAll('.multi-select__option').forEach(function(opt){
|
||||
opt.classList.toggle('selected',selected.indexOf(opt.dataset.value)!==-1);
|
||||
});
|
||||
}
|
||||
|
||||
trigger.addEventListener('click',function(e){
|
||||
if(e.target.classList.contains('multi-select__tag-del')){
|
||||
selected=selected.filter(function(v){return v!==e.target.dataset.val;});
|
||||
render();return;
|
||||
}
|
||||
dropdown.classList.toggle('show');
|
||||
});
|
||||
|
||||
dropdown.addEventListener('click',function(e){
|
||||
var opt=e.target.closest('.multi-select__option');
|
||||
if(!opt) return;
|
||||
var val=opt.dataset.value;
|
||||
var idx=selected.indexOf(val);
|
||||
if(idx===-1) selected.push(val); else selected.splice(idx,1);
|
||||
render();
|
||||
});
|
||||
|
||||
document.addEventListener('click',function(e){
|
||||
if(!document.getElementById('msPopulation').contains(e.target)) dropdown.classList.remove('show');
|
||||
});
|
||||
})();
|
||||
|
||||
/* ===== 餐品选择弹窗 ===== */
|
||||
(function(){
|
||||
var DISHES=[
|
||||
{id:1,name:'白米饭',cat:'主食/米饭',kcal:116,protein:2.6,carb:25.9,fat:0.3},
|
||||
{id:2,name:'杂粮饭',cat:'主食/米饭',kcal:135,protein:4.1,carb:28.2,fat:1.0},
|
||||
{id:3,name:'馒头',cat:'主食/面点',kcal:221,protein:7.0,carb:44.2,fat:1.1},
|
||||
{id:4,name:'花卷',cat:'主食/面点',kcal:214,protein:6.4,carb:42.8,fat:1.3},
|
||||
{id:5,name:'小米粥',cat:'主食/粥品',kcal:46,protein:1.4,carb:8.4,fat:0.7},
|
||||
{id:6,name:'皮蛋瘦肉粥',cat:'主食/粥品',kcal:89,protein:5.2,carb:11.6,fat:2.4},
|
||||
{id:7,name:'红烧肉',cat:'荤菜/猪肉',kcal:286,protein:14.2,carb:6.8,fat:22.5},
|
||||
{id:8,name:'糖醋排骨',cat:'荤菜/猪肉',kcal:264,protein:16.8,carb:14.2,fat:15.6},
|
||||
{id:9,name:'清蒸鲈鱼',cat:'荤菜/水产',kcal:105,protein:18.6,carb:0.8,fat:3.2},
|
||||
{id:10,name:'宫保鸡丁',cat:'荤菜/禽类',kcal:198,protein:19.4,carb:8.6,fat:10.2},
|
||||
{id:11,name:'西红柿炒蛋',cat:'素菜/蛋类',kcal:126,protein:7.8,carb:5.4,fat:8.2},
|
||||
{id:12,name:'清炒时蔬',cat:'素菜/叶菜',kcal:62,protein:2.8,carb:4.6,fat:3.8},
|
||||
{id:13,name:'麻婆豆腐',cat:'素菜/豆制品',kcal:142,protein:9.6,carb:5.2,fat:9.4},
|
||||
{id:14,name:'凉拌黄瓜',cat:'凉菜/蔬菜',kcal:32,protein:1.2,carb:3.8,fat:1.4},
|
||||
{id:15,name:'酸辣土豆丝',cat:'素菜/根茎',kcal:96,protein:2.4,carb:16.2,fat:3.0},
|
||||
{id:16,name:'紫菜蛋花汤',cat:'汤品/蛋汤',kcal:38,protein:3.2,carb:2.4,fat:1.8},
|
||||
{id:17,name:'冬瓜排骨汤',cat:'汤品/肉汤',kcal:72,protein:5.6,carb:3.2,fat:4.0},
|
||||
{id:18,name:'水果拼盘',cat:'甜品/水果',kcal:56,protein:0.8,carb:13.2,fat:0.2},
|
||||
{id:19,name:'绿豆汤',cat:'甜品/糖水',kcal:68,protein:2.4,carb:14.8,fat:0.3},
|
||||
{id:20,name:'煎饺',cat:'主食/面点',kcal:198,protein:8.6,carb:22.4,fat:8.2}
|
||||
];
|
||||
|
||||
var overlay=document.getElementById('dishOverlay');
|
||||
var listEl=document.getElementById('dishList');
|
||||
var searchInput=document.getElementById('dishSearch');
|
||||
var countEl=document.getElementById('dishCount');
|
||||
var confirmBtn=document.getElementById('dishConfirm');
|
||||
var cancelBtn=document.getElementById('dishCancel');
|
||||
var closeBtn=document.getElementById('dishClose');
|
||||
var currentCell=null,tempSelected=[];
|
||||
|
||||
function getCellDishes(cell){return cell.__dishes||(cell.__dishes=[]);}
|
||||
|
||||
function openModal(cell){
|
||||
currentCell=cell;
|
||||
tempSelected=getCellDishes(cell).map(function(d){return d.id;});
|
||||
searchInput.value='';
|
||||
renderList('');
|
||||
updateCount();
|
||||
overlay.classList.add('show');
|
||||
}
|
||||
function closeModal(){overlay.classList.remove('show');currentCell=null;}
|
||||
|
||||
function renderList(keyword){
|
||||
var kw=keyword.trim().toLowerCase();
|
||||
var html='';
|
||||
DISHES.forEach(function(d){
|
||||
if(kw&&d.name.toLowerCase().indexOf(kw)===-1) return;
|
||||
var sel=tempSelected.indexOf(d.id)!==-1;
|
||||
html+='<div class="dish-item'+(sel?' selected':'')+'" data-id="'+d.id+'"><span class="dish-item__check"></span><span class="dish-item__info"><span class="dish-item__name">'+d.name+'</span><span class="dish-item__cat">'+d.cat+'</span><div class="dish-item__nutri"><span>热量 <em>'+d.kcal+'</em>kcal</span><span>蛋白质 <em>'+d.protein+'</em>g</span><span>碳水 <em>'+d.carb+'</em>g</span><span>脂肪 <em>'+d.fat+'</em>g</span></div></span></div>';
|
||||
});
|
||||
if(!html) html='<div style="padding:24px;text-align:center;color:#999;font-size:13px;">无匹配餐品</div>';
|
||||
listEl.innerHTML=html;
|
||||
}
|
||||
function updateCount(){countEl.textContent='已选 '+tempSelected.length+' 项';}
|
||||
|
||||
listEl.addEventListener('click',function(e){
|
||||
var item=e.target.closest('.dish-item');if(!item) return;
|
||||
var id=parseInt(item.getAttribute('data-id'));
|
||||
var idx=tempSelected.indexOf(id);
|
||||
if(idx===-1) tempSelected.push(id); else tempSelected.splice(idx,1);
|
||||
item.classList.toggle('selected');updateCount();
|
||||
});
|
||||
searchInput.addEventListener('input',function(){renderList(this.value);});
|
||||
|
||||
confirmBtn.addEventListener('click',function(){
|
||||
if(!currentCell) return;
|
||||
var dishes=[];
|
||||
tempSelected.forEach(function(id){var d=DISHES.find(function(x){return x.id===id;});if(d) dishes.push({id:d.id,name:d.name});});
|
||||
currentCell.__dishes=dishes;
|
||||
renderCellDishes(currentCell);
|
||||
closeModal();
|
||||
});
|
||||
|
||||
function renderCellDishes(cell){
|
||||
var old=cell.querySelector('.cell-dishes');if(old) old.remove();
|
||||
var hint=cell.querySelector('.cell-hint');
|
||||
var dishes=getCellDishes(cell);
|
||||
if(!dishes.length){if(hint)hint.style.display='';return;}
|
||||
if(hint) hint.style.display='none';
|
||||
var wrap=document.createElement('div');wrap.className='cell-dishes';
|
||||
dishes.forEach(function(d){
|
||||
var tag=document.createElement('span');tag.className='cell-dish-tag';
|
||||
tag.innerHTML=d.name+'<button class="cell-dish-tag__del" data-id="'+d.id+'">×</button>';
|
||||
wrap.appendChild(tag);
|
||||
});
|
||||
cell.appendChild(wrap);
|
||||
}
|
||||
|
||||
document.querySelector('.week-grid').addEventListener('click',function(e){
|
||||
var delBtn=e.target.closest('.cell-dish-tag__del');
|
||||
if(delBtn){e.stopPropagation();var cell=delBtn.closest('.meal-cell');var id=parseInt(delBtn.getAttribute('data-id'));cell.__dishes=getCellDishes(cell).filter(function(d){return d.id!==id;});renderCellDishes(cell);return;}
|
||||
var cell=e.target.closest('.meal-cell');if(cell) openModal(cell);
|
||||
});
|
||||
|
||||
cancelBtn.addEventListener('click',closeModal);
|
||||
closeBtn.addEventListener('click',closeModal);
|
||||
overlay.addEventListener('click',function(e){if(e.target===overlay)closeModal();});
|
||||
})();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,250 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>食谱规划详情 | 健康长庆原型</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;}
|
||||
.main{margin-left:240px;margin-top:56px;padding:24px;min-height:calc(100vh - 56px);}
|
||||
|
||||
/* 页面头部 */
|
||||
.page-header{display:flex;align-items:center;gap:12px;margin-bottom:24px;}
|
||||
.page-header__back{width:32px;height:32px;border:1px solid var(--border);border-radius:var(--radius-sm);background:#fff;cursor:pointer;display:flex;align-items:center;justify-content:center;font-size:16px;color:var(--text-secondary);text-decoration:none;transition:all .15s;}
|
||||
.page-header__back:hover{border-color:var(--primary);color:var(--primary);}
|
||||
.page-header__title{font-size:var(--font-xl);font-weight:600;color:var(--text-primary);}
|
||||
.page-header__status{margin-left:8px;}
|
||||
|
||||
/* 表单模块 */
|
||||
.form-section{background:#fff;border-radius:var(--radius-md);box-shadow:var(--shadow-sm);margin-bottom:20px;}
|
||||
.form-section__title{font-size:var(--font-base);font-weight:600;color:var(--text-primary);padding:16px 24px;border-bottom:1px solid var(--border);background:#FAFAFA;border-radius:var(--radius-md) var(--radius-md) 0 0;}
|
||||
.form-section__body{padding:24px;}
|
||||
.detail-row{display:grid;grid-template-columns:1fr 1fr 1fr;gap:16px;margin-bottom:20px;}
|
||||
.detail-row:last-child{margin-bottom:0;}
|
||||
.detail-field{display:flex;flex-direction:column;gap:4px;}
|
||||
.detail-field__label{font-size:var(--font-sm);color:var(--text-placeholder);}
|
||||
.detail-field__value{font-size:var(--font-sm);color:var(--text-primary);font-weight:500;min-height:22px;}
|
||||
.tag{display:inline-flex;align-items:center;padding:2px 8px;border-radius:10px;font-size:var(--font-xs);}
|
||||
.tag-blue{background:var(--primary-light);color:var(--primary);}
|
||||
.tag-green{background:#F6FFED;color:var(--success);}
|
||||
.tag-orange{background:#FFF7E6;color:var(--warning);}
|
||||
|
||||
/* 周食谱网格(只读) */
|
||||
.week-grid{background:#fff;border-radius:var(--radius-md);box-shadow:var(--shadow-sm);overflow:hidden;border:1px solid var(--border);}
|
||||
.week-grid table{width:100%;border-collapse:collapse;table-layout:fixed;}
|
||||
.week-grid thead th{background:#FAFAFA;padding:12px 8px;text-align:center;font-size:var(--font-sm);color:var(--text-secondary);font-weight:500;border:1px solid var(--border);}
|
||||
.week-grid thead th .day-date{font-size:var(--font-base);font-weight:600;color:var(--text-primary);}
|
||||
.week-grid tbody td{border:1px solid var(--border);padding:0;vertical-align:top;height:140px;}
|
||||
.week-grid tbody td.meal-label{width:64px;background:#FAFAFA;text-align:center;vertical-align:middle;font-size:var(--font-sm);font-weight:600;color:#E8740C;padding:12px 8px;white-space:nowrap;}
|
||||
.week-grid tbody td.meal-cell{position:relative;}
|
||||
|
||||
/* 单元格内餐品标签(只读,无删除按钮) */
|
||||
.cell-dishes{display:flex;flex-wrap:wrap;gap:4px;padding:6px 8px;}
|
||||
.cell-dish-tag{display:inline-flex;align-items:center;padding:2px 8px;background:#F0F5FF;border:1px solid #D6E4FF;border-radius:10px;font-size:var(--font-xs);color:var(--primary);white-space:nowrap;}
|
||||
|
||||
/* 按钮 */
|
||||
.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);}
|
||||
|
||||
/* 底部操作 */
|
||||
.page-footer{display:flex;justify-content:flex-end;gap:12px;margin-top:24px;}
|
||||
.btn-lg{height:40px;padding:0 24px;font-size:var(--font-base);font-weight:500;}
|
||||
</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" class="active">健康生产</a>
|
||||
<a href="din-dict-mgmt.html">营养用餐</a>
|
||||
<a href="ano-dirty.html">异常事件</a>
|
||||
</nav>
|
||||
<div class="top-bar__right">
|
||||
<a class="btn-back" href="../../index.html">← 返回首页</a>
|
||||
<div class="avatar">管</div>
|
||||
<span>系统管理员 ▾</span>
|
||||
</div>
|
||||
</header>
|
||||
<!-- 侧边栏 -->
|
||||
<aside class="sidebar">
|
||||
<div class="sidebar-menu__title">健康生产</div>
|
||||
<a href="prod-qc-daily.html" class="sidebar-item"><span class="mi">🛡️</span>食安监控</a>
|
||||
<a href="prod-recipe-plan.html" class="sidebar-item active"><span class="mi">📋</span>食谱规划</a>
|
||||
<a href="prod-clean-order.html" class="sidebar-item"><span class="mi">📝</span>净菜订单</a>
|
||||
<a href="prod-proc-cabinet.html" class="sidebar-item"><span class="mi">🗄️</span>净菜进柜</a>
|
||||
<a href="prod-proc-combo.html" class="sidebar-item"><span class="mi">🔪</span>净菜组配</a>
|
||||
<a href="prod-proc-cook.html" class="sidebar-item"><span class="mi">🍳</span>按单烹制</a>
|
||||
<a href="prod-proc-serve.html" class="sidebar-item"><span class="mi">🍽️</span>上餐监控</a>
|
||||
<a href="prod-proc-surplus.html" class="sidebar-item"><span class="mi">♻️</span>余量处置</a>
|
||||
<a href="prod-proc-stats.html" class="sidebar-item"><span class="mi">📊</span>生产统计</a>
|
||||
</aside>
|
||||
|
||||
<main class="main">
|
||||
<!-- 页面头部 -->
|
||||
<div class="page-header">
|
||||
<a href="prod-recipe-plan.html" class="page-header__back">←</a>
|
||||
<h1 class="page-header__title">食谱规划详情</h1>
|
||||
<span class="page-header__status"><span class="tag tag-green">已通过</span></span>
|
||||
</div>
|
||||
|
||||
<!-- 模块一:基本信息 -->
|
||||
<div class="form-section">
|
||||
<div class="form-section__title">基本信息</div>
|
||||
<div class="form-section__body">
|
||||
<div class="detail-row">
|
||||
<div class="detail-field">
|
||||
<span class="detail-field__label">餐谱名称</span>
|
||||
<span class="detail-field__value">第21周标准营养食谱</span>
|
||||
</div>
|
||||
<div class="detail-field">
|
||||
<span class="detail-field__label">适应人群</span>
|
||||
<span class="detail-field__value"><span class="tag tag-blue">普通成人</span></span>
|
||||
</div>
|
||||
<div class="detail-field">
|
||||
<span class="detail-field__label">营养达标评级</span>
|
||||
<span class="detail-field__value"><span class="tag tag-green">优</span></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="detail-row">
|
||||
<div class="detail-field">
|
||||
<span class="detail-field__label">安全评估</span>
|
||||
<span class="detail-field__value"><span class="tag tag-green">通过</span></span>
|
||||
</div>
|
||||
<div class="detail-field">
|
||||
<span class="detail-field__label">创建人</span>
|
||||
<span class="detail-field__value">张营养师</span>
|
||||
</div>
|
||||
<div class="detail-field">
|
||||
<span class="detail-field__label">创建时间</span>
|
||||
<span class="detail-field__value">2026-05-12 09:30</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="detail-row">
|
||||
<div class="detail-field">
|
||||
<span class="detail-field__label">审核人</span>
|
||||
<span class="detail-field__value">李主任</span>
|
||||
</div>
|
||||
<div class="detail-field">
|
||||
<span class="detail-field__label">审核时间</span>
|
||||
<span class="detail-field__value">2026-05-12 14:00</span>
|
||||
</div>
|
||||
<div class="detail-field"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 模块二:一周菜谱 -->
|
||||
<div class="form-section">
|
||||
<div class="form-section__title">一周菜谱</div>
|
||||
<div class="form-section__body" style="padding:0;">
|
||||
<div class="week-grid" style="border:none;box-shadow:none;border-radius:0;">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="width:64px;"></th>
|
||||
<th><div class="day-date">周一</div></th>
|
||||
<th><div class="day-date">周二</div></th>
|
||||
<th><div class="day-date">周三</div></th>
|
||||
<th><div class="day-date">周四</div></th>
|
||||
<th><div class="day-date">周五</div></th>
|
||||
<th><div class="day-date">周六</div></th>
|
||||
<th><div class="day-date">周日</div></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<!-- 早餐 -->
|
||||
<tr>
|
||||
<td class="meal-label">早餐</td>
|
||||
<td class="meal-cell"><div class="cell-dishes"><span class="cell-dish-tag">白米饭</span><span class="cell-dish-tag">小米粥</span><span class="cell-dish-tag">馒头</span></div></td>
|
||||
<td class="meal-cell"><div class="cell-dishes"><span class="cell-dish-tag">皮蛋瘦肉粥</span><span class="cell-dish-tag">花卷</span></div></td>
|
||||
<td class="meal-cell"><div class="cell-dishes"><span class="cell-dish-tag">小米粥</span><span class="cell-dish-tag">煎饺</span></div></td>
|
||||
<td class="meal-cell"><div class="cell-dishes"><span class="cell-dish-tag">杂粮饭</span><span class="cell-dish-tag">馒头</span></div></td>
|
||||
<td class="meal-cell"><div class="cell-dishes"><span class="cell-dish-tag">皮蛋瘦肉粥</span><span class="cell-dish-tag">煎饺</span><span class="cell-dish-tag">花卷</span></div></td>
|
||||
<td class="meal-cell"></td>
|
||||
<td class="meal-cell"></td>
|
||||
</tr>
|
||||
<!-- 午餐 -->
|
||||
<tr>
|
||||
<td class="meal-label">午餐</td>
|
||||
<td class="meal-cell"><div class="cell-dishes"><span class="cell-dish-tag">红烧肉</span><span class="cell-dish-tag">清炒时蔬</span><span class="cell-dish-tag">紫菜蛋花汤</span></div></td>
|
||||
<td class="meal-cell"><div class="cell-dishes"><span class="cell-dish-tag">宫保鸡丁</span><span class="cell-dish-tag">酸辣土豆丝</span><span class="cell-dish-tag">白米饭</span></div></td>
|
||||
<td class="meal-cell"><div class="cell-dishes"><span class="cell-dish-tag">糖醋排骨</span><span class="cell-dish-tag">麻婆豆腐</span><span class="cell-dish-tag">冬瓜排骨汤</span></div></td>
|
||||
<td class="meal-cell"><div class="cell-dishes"><span class="cell-dish-tag">清蒸鲈鱼</span><span class="cell-dish-tag">西红柿炒蛋</span><span class="cell-dish-tag">白米饭</span></div></td>
|
||||
<td class="meal-cell"><div class="cell-dishes"><span class="cell-dish-tag">红烧肉</span><span class="cell-dish-tag">凉拌黄瓜</span><span class="cell-dish-tag">紫菜蛋花汤</span></div></td>
|
||||
<td class="meal-cell"></td>
|
||||
<td class="meal-cell"></td>
|
||||
</tr>
|
||||
<!-- 晚餐 -->
|
||||
<tr>
|
||||
<td class="meal-label">晚餐</td>
|
||||
<td class="meal-cell"><div class="cell-dishes"><span class="cell-dish-tag">西红柿炒蛋</span><span class="cell-dish-tag">酸辣土豆丝</span></div></td>
|
||||
<td class="meal-cell"><div class="cell-dishes"><span class="cell-dish-tag">麻婆豆腐</span><span class="cell-dish-tag">清炒时蔬</span></div></td>
|
||||
<td class="meal-cell"><div class="cell-dishes"><span class="cell-dish-tag">宫保鸡丁</span><span class="cell-dish-tag">凉拌黄瓜</span></div></td>
|
||||
<td class="meal-cell"><div class="cell-dishes"><span class="cell-dish-tag">清蒸鲈鱼</span><span class="cell-dish-tag">清炒时蔬</span></div></td>
|
||||
<td class="meal-cell"></td>
|
||||
<td class="meal-cell"></td>
|
||||
<td class="meal-cell"></td>
|
||||
</tr>
|
||||
<!-- 加餐 -->
|
||||
<tr>
|
||||
<td class="meal-label">加餐</td>
|
||||
<td class="meal-cell"><div class="cell-dishes"><span class="cell-dish-tag">水果拼盘</span></div></td>
|
||||
<td class="meal-cell"></td>
|
||||
<td class="meal-cell"><div class="cell-dishes"><span class="cell-dish-tag">绿豆汤</span><span class="cell-dish-tag">水果拼盘</span></div></td>
|
||||
<td class="meal-cell"></td>
|
||||
<td class="meal-cell"></td>
|
||||
<td class="meal-cell"></td>
|
||||
<td class="meal-cell"></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 底部操作 -->
|
||||
<div class="page-footer">
|
||||
<a href="prod-recipe-plan.html" class="btn btn-default btn-lg">返回列表</a>
|
||||
<a href="prod-recipe-plan-create.html" class="btn btn-primary btn-lg">编辑</a>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<script>
|
||||
// 详情页为只读,无交互脚本
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -80,7 +80,8 @@ tbody tr:hover td.td-actions{background:#F8FBFF;}
|
||||
|
||||
/* 页面内弹窗 */
|
||||
.modal-overlay{display:none;position:fixed;inset:0;background:rgba(0,0,0,0.45);z-index:200;align-items:center;justify-content:center;}
|
||||
.modal{background:#fff;border-radius:var(--radius-lg);width:680px;max-width:90vw;box-shadow:var(--shadow-md);}
|
||||
.modal-overlay.show{display:flex;}
|
||||
.modal{background:#fff;border-radius:var(--radius-lg);width:420px;max-width:90vw;box-shadow:var(--shadow-md);}
|
||||
.modal__header{display:flex;align-items:center;justify-content:space-between;padding:20px 24px 16px;border-bottom:1px solid var(--border);}
|
||||
.modal__title{font-size:var(--font-lg);font-weight:600;color:var(--text-primary);}
|
||||
.modal__close{width:32px;height:32px;border:none;background:none;cursor:pointer;display:flex;align-items:center;justify-content:center;border-radius:var(--radius-sm);color:var(--text-placeholder);}
|
||||
@@ -90,12 +91,34 @@ tbody tr:hover td.td-actions{background:#F8FBFF;}
|
||||
.form-group{margin-bottom:20px;}
|
||||
.form-group label{display:block;font-size:var(--font-sm);color:var(--text-primary);margin-bottom:8px;font-weight:500;}
|
||||
.form-group .required{color:var(--danger);margin-left:2px;}
|
||||
.audit-options{display:flex;gap:12px;margin-bottom:16px;}
|
||||
.audit-opt{flex:1;padding:16px;border:2px solid var(--border);border-radius:var(--radius-md);cursor:pointer;text-align:center;transition:all .15s;}
|
||||
.audit-opt:hover{border-color:var(--primary);background:#FAFBFF;}
|
||||
.audit-opt.selected-pass{border-color:var(--success);background:#F6FFED;}
|
||||
.audit-opt.selected-fail{border-color:var(--danger);background:#FFF1F0;}
|
||||
.audit-opt__icon{font-size:24px;margin-bottom:6px;}
|
||||
.audit-opt__label{font-size:var(--font-sm);font-weight:500;color:var(--text-primary);}
|
||||
.form-textarea{width:100%;height:80px;border:1px solid var(--border);border-radius:var(--radius-sm);padding:8px 12px;font-size:var(--font-sm);outline:none;resize:vertical;font-family:inherit;}
|
||||
.form-textarea:focus{border-color:var(--primary);}
|
||||
.form-input2{width:100%;height:36px;border:1px solid var(--border);border-radius:var(--radius-sm);padding:0 12px;font-size:var(--font-sm);outline:none;}
|
||||
.form-input2:focus{border-color:var(--primary);}
|
||||
.form-select2{width:100%;height:36px;border:1px solid var(--border);border-radius:var(--radius-sm);padding:0 12px;font-size:var(--font-sm);outline:none;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 12px center;}
|
||||
.form-textarea2{width:100%;height:80px;border:1px solid var(--border);border-radius:var(--radius-sm);padding:8px 12px;font-size:var(--font-sm);outline:none;resize:vertical;font-family:inherit;}
|
||||
.form-textarea2:focus{border-color:var(--primary);}
|
||||
.form-row{display:grid;grid-template-columns:1fr 1fr;gap:16px;}
|
||||
|
||||
/* 多选下拉 */
|
||||
.multi-select{position:relative;display:inline-block;min-width:160px;}
|
||||
.multi-select__trigger{height:36px;border:1px solid var(--border);border-radius:var(--radius-sm);padding:0 28px 0 12px;font-size:var(--font-sm);cursor:pointer;display:flex;align-items:center;gap:4px;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;overflow:hidden;white-space:nowrap;}
|
||||
.multi-select__trigger:hover{border-color:var(--primary);}
|
||||
.multi-select__placeholder{color:var(--text-placeholder);font-size:var(--font-sm);}
|
||||
.multi-select__tag{display:inline-flex;align-items:center;gap:2px;padding:1px 6px;background:var(--primary-light);border-radius:8px;font-size:var(--font-xs);color:var(--primary);flex-shrink:0;}
|
||||
.multi-select__tag-del{cursor:pointer;font-size:11px;opacity:0.7;line-height:1;}.multi-select__tag-del:hover{opacity:1;}
|
||||
.multi-select__dropdown{position:absolute;top:calc(100% + 4px);left:0;min-width:100%;z-index:50;background:#fff;border:1px solid var(--border);border-radius:var(--radius-sm);box-shadow:var(--shadow-md);display:none;max-height:200px;overflow-y:auto;}
|
||||
.multi-select__dropdown.show{display:block;}
|
||||
.multi-select__option{padding:8px 12px;font-size:var(--font-sm);cursor:pointer;transition:background .1s;white-space:nowrap;}
|
||||
.multi-select__option:hover{background:#F8FBFF;}
|
||||
.multi-select__option.selected{background:var(--primary-light);color:var(--primary);}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
@@ -142,26 +165,42 @@ tbody tr:hover td.td-actions{background:#F8FBFF;}
|
||||
<!-- 筛选栏 -->
|
||||
<div class="filter-bar">
|
||||
<div class="filter-item">
|
||||
<label>餐次</label>
|
||||
<select class="filter-select">
|
||||
<option>全部</option>
|
||||
<option>早餐</option>
|
||||
<option>午餐</option>
|
||||
<option>晚餐</option>
|
||||
<option>加餐</option>
|
||||
</select>
|
||||
<label>菜谱名称</label>
|
||||
<input class="filter-input" type="text" placeholder="请输入菜谱名称">
|
||||
</div>
|
||||
<div class="filter-item">
|
||||
<label>日期</label>
|
||||
<input class="filter-input" type="date">
|
||||
<label>适应人群</label>
|
||||
<div class="multi-select" id="msPopulation">
|
||||
<div class="multi-select__trigger" id="msTrigger">
|
||||
<span class="multi-select__placeholder">全部</span>
|
||||
</div>
|
||||
<div class="multi-select__dropdown" id="msDropdown">
|
||||
<div class="multi-select__option" data-value="普通成人">普通成人</div>
|
||||
<div class="multi-select__option" data-value="老年人">老年人</div>
|
||||
<div class="multi-select__option" data-value="糖尿病人群">糖尿病人群</div>
|
||||
<div class="multi-select__option" data-value="高血压人群">高血压人群</div>
|
||||
<div class="multi-select__option" data-value="儿童">儿童</div>
|
||||
<div class="multi-select__option" data-value="孕产妇">孕产妇</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="filter-item">
|
||||
<label>营养达标评级</label>
|
||||
<select class="filter-select">
|
||||
<option value="">全部</option>
|
||||
<option>优</option>
|
||||
<option>良</option>
|
||||
<option>合格</option>
|
||||
<option>不合格</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="filter-item">
|
||||
<label>安全评估</label>
|
||||
<select class="filter-select">
|
||||
<option>全部</option>
|
||||
<option value="">全部</option>
|
||||
<option>通过</option>
|
||||
<option>待复核</option>
|
||||
<option>不通过</option>
|
||||
<option>未通过</option>
|
||||
<option>待审核</option>
|
||||
</select>
|
||||
</div>
|
||||
<button class="btn btn-primary">查询</button>
|
||||
@@ -170,9 +209,8 @@ tbody tr:hover td.td-actions{background:#F8FBFF;}
|
||||
|
||||
<!-- 操作栏 -->
|
||||
<div class="action-bar">
|
||||
<button class="btn btn-primary" onclick="document.getElementById('modal-plan').style.display='flex'"><svg width="14" height="14" viewBox="0 0 14 14" fill="none"><path d="M7 2v10M2 7h10" stroke="#fff" stroke-width="1.8" stroke-linecap="round"/></svg>新建规划</button>
|
||||
<button class="btn btn-default">🧮 校验净菜需求</button>
|
||||
<button class="btn btn-default">🤖 AI推荐优化</button>
|
||||
<a href="prod-recipe-plan-create.html" class="btn btn-primary"><svg width="14" height="14" viewBox="0 0 14 14" fill="none"><path d="M7 2v10M2 7h10" stroke="#fff" stroke-width="1.8" stroke-linecap="round"/></svg>新建规划</a>
|
||||
<button class="btn btn-default">🤖 AI推荐菜谱</button>
|
||||
<button class="btn btn-primary"><svg width="14" height="14" viewBox="0 0 14 14" fill="none"><path d="M2 10v2h10v-2M7 2v7M4.5 6.5L7 9l2.5-2.5" stroke="#fff" stroke-width="1.4" stroke-linecap="round" stroke-linejoin="round"/></svg>导出列表数据</button>
|
||||
<button class="btn btn-default"><svg width="14" height="14" viewBox="0 0 14 14" fill="none"><rect x="2" y="2" width="10" height="10" rx="1.5" stroke="currentColor" stroke-width="1.4"/><path d="M4 5h6M4 7.5h4" stroke="currentColor" stroke-width="1.2" stroke-linecap="round"/></svg>查看导出任务</button>
|
||||
</div>
|
||||
@@ -180,37 +218,37 @@ tbody tr:hover td.td-actions{background:#F8FBFF;}
|
||||
<!-- 数据表格 -->
|
||||
<div class="table-card">
|
||||
<div class="table-card__header">
|
||||
<div class="table-card__title">食谱规划</div>
|
||||
<div class="table-card__title">食谱规划列表</div>
|
||||
</div>
|
||||
<div class="table-card__content">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>日期</th><th>餐次</th><th>来源食谱</th><th>主食</th><th>荤菜</th><th>素菜</th><th>汤类</th><th>热量(kcal)</th><th>净菜需求量(kg)</th><th>营养达标评级</th><th>安全评估</th><th>整改状态</th><th>操作</th>
|
||||
<th>菜谱名称</th><th>适应人群</th><th>营养达标评级</th><th>安全评估</th><th>创建人</th><th>创建时间</th><th>审核人</th><th>审核时间</th><th>审核意见</th><th>操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>2026-04-15(周三)</td><td>早餐</td><td>第15周营养食谱</td><td>小米粥+馒头</td><td>卤蛋</td><td>凉拌黄瓜</td><td>—</td><td>486</td><td>8.6</td><td><span class="tag tag-green">优</span></td><td><span class="tag tag-green">通过</span></td><td><span class="tag tag-green">无需整改</span></td><td class="td-actions"><a class="link">详情</a> <a class="link">编辑</a> <a class="link" style="color:var(--danger)">删除</a></td>
|
||||
<td>第21周标准营养食谱</td><td><span class="tag tag-blue">普通成人</span></td><td><span class="tag tag-green">优</span></td><td><span class="tag tag-green">通过</span></td><td>张营养师</td><td>2026-05-12 09:30</td><td>李主任</td><td>2026-05-12 14:00</td><td>营养搭配均衡,符合标准要求</td><td class="td-actions"><a class="link" href="prod-recipe-plan-detail.html">详情</a> <a class="link" style="color:var(--danger)">删除</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>2026-04-15(周三)</td><td>午餐</td><td>第15周营养食谱</td><td>米饭</td><td>红烧肉+清蒸鱼</td><td>炒时蔬+豆腐</td><td>番茄蛋汤</td><td>856</td><td>38.2</td><td><span class="tag tag-blue">良</span></td><td><span class="tag tag-green">通过</span></td><td><span class="tag tag-orange">建议优化</span></td><td class="td-actions"><a class="link">详情</a> <a class="link">编辑</a> <a class="link" style="color:var(--danger)">删除</a></td>
|
||||
<td>第21周老年营养食谱</td><td><span class="tag tag-blue">老年人</span></td><td><span class="tag tag-blue">良</span></td><td><span class="tag tag-green">通过</span></td><td>王营养师</td><td>2026-05-12 10:15</td><td>李主任</td><td>2026-05-13 09:00</td><td>低盐低脂方案合理,建议增加钙质</td><td class="td-actions"><a class="link" href="prod-recipe-plan-detail.html">详情</a> <a class="link" style="color:var(--danger)">删除</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>2026-04-15(周三)</td><td>晚餐</td><td>第15周营养食谱</td><td>米饭+花卷</td><td>宫保鸡丁</td><td>蒜蓉菠菜</td><td>紫菜汤</td><td>724</td><td>28.6</td><td><span class="tag tag-blue">良</span></td><td><span class="tag tag-green">通过</span></td><td><span class="tag tag-green">无需整改</span></td><td class="td-actions"><a class="link">详情</a> <a class="link">编辑</a> <a class="link" style="color:var(--danger)">删除</a></td>
|
||||
<td>第21周糖尿病专用食谱</td><td><span class="tag tag-blue">糖尿病人群</span></td><td><span class="tag tag-green">优</span></td><td><span class="tag tag-orange">待审核</span></td><td>张营养师</td><td>2026-05-13 08:45</td><td>—</td><td>—</td><td>—</td><td class="td-actions"><a class="link" href="prod-recipe-plan-detail.html">详情</a> <a class="link" href="prod-recipe-plan-create.html">编辑</a> <a class="link btn-audit" style="color:var(--warning);cursor:pointer;">审核</a> <a class="link" style="color:var(--danger)">删除</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>2026-04-16(周四)</td><td>早餐</td><td>第15周营养食谱</td><td>燕麦粥+包子</td><td>茶叶蛋</td><td>拌菠菜</td><td>—</td><td>512</td><td>9.2</td><td><span class="tag tag-green">优</span></td><td><span class="tag tag-green">通过</span></td><td><span class="tag tag-green">无需整改</span></td><td class="td-actions"><a class="link">详情</a> <a class="link">编辑</a> <a class="link" style="color:var(--danger)">删除</a></td>
|
||||
<td>第20周标准营养食谱</td><td><span class="tag tag-blue">普通成人</span> <span class="tag tag-blue">高血压人群</span></td><td><span class="tag tag-blue">良</span></td><td><span class="tag tag-green">通过</span></td><td>王营养师</td><td>2026-05-05 09:00</td><td>李主任</td><td>2026-05-05 16:30</td><td>整体达标,高血压方案控钠良好</td><td class="td-actions"><a class="link" href="prod-recipe-plan-detail.html">详情</a> <a class="link" style="color:var(--danger)">删除</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>2026-04-16(周四)</td><td>午餐</td><td>第15周营养食谱</td><td>米饭</td><td>糖醋排骨+虾仁</td><td>炒西兰花</td><td>冬瓜汤</td><td>892</td><td>40.4</td><td><span class="tag tag-blue">良</span></td><td><span class="tag tag-orange">待复核</span></td><td><span class="tag tag-red">待整改</span></td><td class="td-actions"><a class="link">详情</a> <a class="link">编辑</a> <a class="link" style="color:var(--danger)">删除</a></td>
|
||||
<td>第20周儿童营养食谱</td><td><span class="tag tag-blue">儿童</span></td><td><span class="tag tag-orange">合格</span></td><td><span class="tag tag-red">未通过</span></td><td>赵营养师</td><td>2026-05-06 11:20</td><td>李主任</td><td>2026-05-07 10:00</td><td style="color:var(--danger)">蛋白质摄入不足,缺少奶制品类</td><td class="td-actions"><a class="link" href="prod-recipe-plan-detail.html">详情</a> <a class="link" style="color:var(--danger)">删除</a></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<!-- 分页 -->
|
||||
<div class="pagination">
|
||||
<span>显示 5 条,共 42 条</span>
|
||||
<span>显示 5 条,共 28 条</span>
|
||||
<button class="page-btn">‹</button>
|
||||
<button class="page-btn active">1</button>
|
||||
<button class="page-btn">2</button>
|
||||
@@ -221,56 +259,152 @@ tbody tr:hover td.td-actions{background:#F8FBFF;}
|
||||
|
||||
</div>
|
||||
|
||||
<!-- 新建规划弹窗 -->
|
||||
<div class="modal-overlay" id="modal-plan" onclick="if(event.target===this)this.style.display='none'">
|
||||
<!-- 审核弹窗 -->
|
||||
<div class="modal-overlay" id="auditModal">
|
||||
<div class="modal">
|
||||
<div class="modal__header">
|
||||
<div class="modal__title">新建规划</div>
|
||||
<button class="modal__close" onclick="document.getElementById('modal-plan').style.display='none'">
|
||||
<div class="modal__title">审核食谱规划</div>
|
||||
<button class="modal__close" id="auditClose">
|
||||
<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="modal__body">
|
||||
<div class="form-row">
|
||||
<div class="form-group"><label>日期<span class="required">*</span></label><input class="form-input2" type="date"></div>
|
||||
<div class="form-group"><label>餐次</label><select class="form-select2"><option>请选择</option><option>早餐</option><option>午餐</option><option>晚餐</option><option>加餐</option></select></div>
|
||||
<div class="form-group">
|
||||
<label>审核结果<span class="required">*</span></label>
|
||||
<div class="audit-options">
|
||||
<div class="audit-opt" id="auditPass" data-result="pass">
|
||||
<div class="audit-opt__icon">✓</div>
|
||||
<div class="audit-opt__label">通过</div>
|
||||
</div>
|
||||
<div class="audit-opt" id="auditFail" data-result="fail">
|
||||
<div class="audit-opt__icon">✗</div>
|
||||
<div class="audit-opt__label">未通过</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<div class="form-group"><label>规划人数<span class="required">*</span></label><input class="form-input2" type="number" placeholder="请输入规划人数"></div>
|
||||
<div class="form-group"><label>预计出餐时间<span class="required">*</span></label><input class="form-input2" type="text" placeholder="如:11:30 前"></div>
|
||||
<div class="form-group" style="margin-bottom:0;">
|
||||
<label>审核意见</label>
|
||||
<textarea class="form-textarea" id="auditRemark" placeholder="请输入审核意见(选填)"></textarea>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<div class="form-group"><label>预计烹饪时长(分钟)<span class="required">*</span></label><input class="form-input2" type="number" placeholder="请输入预计烹饪时长"></div>
|
||||
<div class="form-group"><label>主食<span class="required">*</span></label><input class="form-input2" type="text" placeholder="请输入主食"></div>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<div class="form-group"><label>荤菜</label><input class="form-input2" type="text" placeholder="请输入荤菜"></div>
|
||||
<div class="form-group"><label>素菜</label><input class="form-input2" type="text" placeholder="请输入素菜"></div>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<div class="form-group"><label>汤类</label><input class="form-input2" type="text" placeholder="请输入汤类"></div>
|
||||
<div class="form-group"><label>餐品库来源<span class="required">*</span></label><select class="form-select2"><option>请选择</option><option>餐品总库</option><option>自定义餐品库</option><option>混合</option></select></div>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<div class="form-group"><label>关联餐品库</label><input class="form-input2" type="text" placeholder="如:标准菜品库A / 低脂菜品库"></div>
|
||||
<div class="form-group"><label>净菜需求量(kg)</label><input class="form-input2" type="number" placeholder="请输入净菜需求量"></div>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<div class="form-group"><label>安全评估结论</label><select class="form-select2"><option>请选择</option><option>通过</option><option>待复核</option><option>不通过</option></select></div>
|
||||
<div class="form-group"></div>
|
||||
</div>
|
||||
<div class="form-group"><label>食材清单</label><textarea class="form-textarea2" placeholder="如:鸡胸肉、菠菜、番茄(逗号分隔)"></textarea></div>
|
||||
</div>
|
||||
<div class="modal__footer">
|
||||
<button class="btn btn-default" onclick="document.getElementById('modal-plan').style.display='none'">取消</button>
|
||||
<button class="btn btn-primary">确定</button>
|
||||
<button class="btn btn-default" id="auditCancel">取消</button>
|
||||
<button class="btn btn-primary" id="auditSubmit">提交</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// 无子分组,无需折叠脚本
|
||||
/* 多选下拉交互 */
|
||||
(function(){
|
||||
var trigger=document.getElementById('msTrigger');
|
||||
var dropdown=document.getElementById('msDropdown');
|
||||
var selected=[];
|
||||
|
||||
function render(){
|
||||
if(!selected.length){
|
||||
trigger.innerHTML='<span class="multi-select__placeholder">全部</span>';
|
||||
}else{
|
||||
trigger.innerHTML=selected.map(function(v){
|
||||
return '<span class="multi-select__tag">'+v+'<span class="multi-select__tag-del" data-val="'+v+'">×</span></span>';
|
||||
}).join('');
|
||||
}
|
||||
dropdown.querySelectorAll('.multi-select__option').forEach(function(opt){
|
||||
opt.classList.toggle('selected',selected.indexOf(opt.dataset.value)!==-1);
|
||||
});
|
||||
}
|
||||
|
||||
trigger.addEventListener('click',function(e){
|
||||
if(e.target.classList.contains('multi-select__tag-del')){
|
||||
selected=selected.filter(function(v){return v!==e.target.dataset.val;});
|
||||
render();return;
|
||||
}
|
||||
dropdown.classList.toggle('show');
|
||||
});
|
||||
|
||||
dropdown.addEventListener('click',function(e){
|
||||
var opt=e.target.closest('.multi-select__option');
|
||||
if(!opt) return;
|
||||
var val=opt.dataset.value;
|
||||
var idx=selected.indexOf(val);
|
||||
if(idx===-1) selected.push(val); else selected.splice(idx,1);
|
||||
render();
|
||||
});
|
||||
|
||||
document.addEventListener('click',function(e){
|
||||
if(!document.getElementById('msPopulation').contains(e.target)) dropdown.classList.remove('show');
|
||||
});
|
||||
})();
|
||||
|
||||
/* ===== 审核弹窗 ===== */
|
||||
(function(){
|
||||
var modal=document.getElementById('auditModal');
|
||||
var passBtn=document.getElementById('auditPass');
|
||||
var failBtn=document.getElementById('auditFail');
|
||||
var closeBtn=document.getElementById('auditClose');
|
||||
var cancelBtn=document.getElementById('auditCancel');
|
||||
var submitBtn=document.getElementById('auditSubmit');
|
||||
var remarkEl=document.getElementById('auditRemark');
|
||||
var auditResult='';
|
||||
var currentRow=null;
|
||||
|
||||
function openModal(row){
|
||||
currentRow=row;
|
||||
auditResult='';
|
||||
passBtn.className='audit-opt';
|
||||
failBtn.className='audit-opt';
|
||||
remarkEl.value='';
|
||||
modal.classList.add('show');
|
||||
}
|
||||
function closeModal(){modal.classList.remove('show');currentRow=null;}
|
||||
|
||||
passBtn.addEventListener('click',function(){
|
||||
auditResult='pass';
|
||||
passBtn.className='audit-opt selected-pass';
|
||||
failBtn.className='audit-opt';
|
||||
});
|
||||
failBtn.addEventListener('click',function(){
|
||||
auditResult='fail';
|
||||
failBtn.className='audit-opt selected-fail';
|
||||
passBtn.className='audit-opt';
|
||||
});
|
||||
|
||||
// 点击审核按钮
|
||||
document.querySelector('.table-card').addEventListener('click',function(e){
|
||||
var btn=e.target.closest('.btn-audit');
|
||||
if(!btn) return;
|
||||
e.preventDefault();
|
||||
var row=btn.closest('tr');
|
||||
openModal(row);
|
||||
});
|
||||
|
||||
submitBtn.addEventListener('click',function(){
|
||||
if(!auditResult){alert('请选择审核结果');return;}
|
||||
if(!currentRow) return;
|
||||
// 更新安全评估列
|
||||
var cells=currentRow.querySelectorAll('td');
|
||||
var safetyCell=cells[3]; // 第4列=安全评估
|
||||
var actionsCell=currentRow.querySelector('.td-actions');
|
||||
if(auditResult==='pass'){
|
||||
safetyCell.innerHTML='<span class="tag tag-green">通过</span>';
|
||||
// 审核人+时间
|
||||
cells[6].textContent='当前用户';
|
||||
cells[7].textContent=new Date().toISOString().slice(0,16).replace('T',' ');
|
||||
// 操作列:移除编辑和审核
|
||||
actionsCell.innerHTML='<a class="link" href="prod-recipe-plan-detail.html">详情</a> <a class="link" style="color:var(--danger)">删除</a>';
|
||||
}else{
|
||||
safetyCell.innerHTML='<span class="tag tag-red">未通过</span>';
|
||||
cells[6].textContent='当前用户';
|
||||
cells[7].textContent=new Date().toISOString().slice(0,16).replace('T',' ');
|
||||
actionsCell.innerHTML='<a class="link" href="prod-recipe-plan-detail.html">详情</a> <a class="link" style="color:var(--danger)">删除</a>';
|
||||
}
|
||||
closeModal();
|
||||
});
|
||||
|
||||
closeBtn.addEventListener('click',closeModal);
|
||||
cancelBtn.addEventListener('click',closeModal);
|
||||
modal.addEventListener('click',function(e){if(e.target===modal)closeModal();});
|
||||
})();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user