From 143803a73fdfa142030c0998831aa3b7391b4e4b Mon Sep 17 00:00:00 2001
From: fengpu <18691763612@163.com>
Date: Mon, 21 Sep 2026 10:18:15 +0800
Subject: [PATCH] =?UTF-8?q?feat=EF=BC=9A=E8=90=A5=E5=85=BB=E7=AE=A1?=
=?UTF-8?q?=E7=90=86=E5=90=8E=E5=8F=B0=E5=8F=96=E9=A4=90=E7=AE=A1=E7=90=86?=
=?UTF-8?q?=E6=96=B0=E5=A2=9E=E5=8F=96=E9=A4=90=E6=98=8E=E7=BB=86=E5=88=97?=
=?UTF-8?q?=E8=A1=A8=EF=BC=8C=E9=A3=9F=E8=B0=B1=E7=94=9F=E6=88=90=E5=87=80?=
=?UTF-8?q?=E8=8F=9C=E8=AE=A2=E5=8D=95=E5=8A=9F=E8=83=BD=E4=BC=98=E5=8C=96?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
index.html | 1 +
web-admin/nutrition/din-order-pickup.html | 270 ++++++++-
.../nutrition/prod-clean-order-history.html | 567 ++++++++++++++++++
web-admin/nutrition/prod-clean-order.html | 144 +----
4 files changed, 820 insertions(+), 162 deletions(-)
create mode 100644 web-admin/nutrition/prod-clean-order-history.html
diff --git a/index.html b/index.html
index 3e9af86..23f0fb3 100644
--- a/index.html
+++ b/index.html
@@ -386,6 +386,7 @@ const SITE_MAP = [
{ file:'din-place-goal.html', label:'场所目标考核' },
{ file:'prod-recipe-plan.html', label:'食谱排期' },
{ file:'prod-clean-order.html', label:'净菜下单' },
+ { file:'prod-clean-order-history.html', label:'净菜下单生成历史' },
{ file:'prod-proc-combo.html', label:'配菜组合' },
{ file:'prod-proc-cook.html', label:'烹饪加工' },
{ file:'prod-proc-serve.html', label:'出餐管理' },
diff --git a/web-admin/nutrition/din-order-pickup.html b/web-admin/nutrition/din-order-pickup.html
index 36e59d0..70e92c9 100644
--- a/web-admin/nutrition/din-order-pickup.html
+++ b/web-admin/nutrition/din-order-pickup.html
@@ -95,6 +95,35 @@ tbody tr:hover{background:#F8FBFF;}
.modal-close:hover{background:#f5f5f5;color:var(--text-primary);}
.modal-body{padding:24px;overflow-y:auto;flex:1;}
+/* 主 Tab 栏 */
+.main-tabs{display:flex;gap:0;background:#fff;border-radius:var(--radius-md);padding:0 24px;margin-bottom:16px;box-shadow:var(--shadow-sm);}
+.main-tab{padding:14px 20px;font-size:var(--font-base);color:var(--text-secondary);cursor:pointer;border-bottom:2px solid transparent;white-space:nowrap;transition:all .2s;user-select:none;}
+.main-tab:hover{color:var(--primary);}
+.main-tab.active{color:var(--primary);border-bottom-color:var(--primary);font-weight:600;}
+.main-tab-panel{display:none;}
+.main-tab-panel.active{display:block;}
+
+/* 取餐明细 - 视频回放与丢餐提示 */
+.video-info{font-size:var(--font-sm);color:var(--text-secondary);margin-bottom:16px;}
+.scale-info{display:flex;gap:24px;padding:12px 16px;background:#F8FAFC;border-radius:var(--radius-md);margin-bottom:16px;font-size:var(--font-sm);}
+.scale-info__item{color:var(--text-primary);}
+.scale-info__item strong{color:var(--primary);font-weight:600;}
+.raw-data-table{width:100%;border-collapse:collapse;font-size:var(--font-sm);}
+.raw-data-table thead th{background:#FAFAFA;padding:10px 14px;text-align:left;color:var(--text-secondary);font-weight:500;border-bottom:1px solid var(--border);white-space:nowrap;}
+.raw-data-table tbody td{padding:12px 14px;color:var(--text-primary);border-bottom:1px solid #f0f0f0;white-space:nowrap;}
+.raw-data-table tbody tr:last-child td{border-bottom:none;}
+.raw-data-table tbody tr:hover{background:#F8FBFF;}
+.video-player{background:#000;border-radius:var(--radius-md);overflow:hidden;}
+.video-player__screen{position:relative;height:320px;display:flex;align-items:center;justify-content:center;background:linear-gradient(135deg,#1a1a2e 0%,#16213e 50%,#0f3460 100%);}
+.video-player__placeholder{color:rgba(255,255,255,0.6);font-size:var(--font-sm);letter-spacing:2px;}
+.video-player__bigplay{position:absolute;width:64px;height:64px;border-radius:50%;background:rgba(255,255,255,0.2);color:#fff;display:flex;align-items:center;justify-content:center;font-size:26px;cursor:pointer;transition:all .2s;}
+.video-player__bigplay:hover{background:rgba(255,255,255,0.35);}
+.video-player__bar{display:flex;align-items:center;gap:12px;padding:12px 16px;background:#111;}
+.video-player__btn{width:32px;height:32px;border:none;border-radius:50%;background:rgba(255,255,255,0.15);color:#fff;cursor:pointer;font-size:14px;}
+.video-player__time{color:rgba(255,255,255,0.7);font-size:var(--font-xs);white-space:nowrap;}
+.video-player__progress{flex:1;height:4px;background:rgba(255,255,255,0.2);border-radius:2px;position:relative;}
+.video-player__progress-fill{width:40%;height:100%;background:var(--primary);border-radius:2px;}
+
/* 十维档案 Tab */
.profile-tabs{display:flex;gap:0;border-bottom:1px solid var(--border);margin-bottom:20px;overflow-x:auto;}
.profile-tab{padding:10px 16px;font-size:var(--font-sm);color:var(--text-secondary);cursor:pointer;border-bottom:2px solid transparent;white-space:nowrap;transition:all .2s;}
@@ -300,6 +329,15 @@ tbody tr:hover td.td-actions{background:#F8FBFF;}
+
+
+
+
+
+
@@ -328,7 +366,7 @@ tbody tr:hover td.td-actions{background:#F8FBFF;}
取餐管理
-
+
| 就餐记录号 | 姓名 | 员工编号 | 单位 | 部门 | 餐次 | 取餐方式 | 取餐类型 | 人员类别 | 取餐开始时间 | 取餐结束时间 | 取餐总数量 | 结算重量(克) | 实际重量(克) | 重量偏差(克) | 总金额 | 营养评分 | 操作 |
@@ -356,6 +394,70 @@ tbody tr:hover td.td-actions{background:#F8FBFF;}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
至
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ | 序号 | 取用记录ID | 餐次 | 餐品名称 | 记录状态 | 取餐重量(克) | 金额 | 用户(工号-姓名) | 人员类别 | 取餐时间 | 取餐设备 | 取餐方式 | 取餐类型 | 就餐记录号 | 操作 |
+
+
+ | 1 | P-20260428-0001 | 午餐 | 清炒生菜 | 正常 | 133.0 | ¥6.00 | EMP001-张伟 | 会员 | 2026-04-28 11:02:15 | 一号餐线·3号秤 | 餐线取餐 | 正常取餐 | M-20260428-001 | 原始数据 查看视频 |
+ | 2 | P-20260428-0002 | 午餐 | 西红柿鸡蛋 | 正常 | 114.0 | ¥8.00 | EMP001-张伟 | 会员 | 2026-04-28 11:03:02 | 一号餐线·3号秤 | 餐线取餐 | 正常取餐 | M-20260428-001 | 原始数据 查看视频 |
+ | 3 | P-20260428-0003 | 午餐 | 辣子鸡丁 | 正常 | 79.0 | ¥8.00 | EMP001-张伟 | 会员 | 2026-04-28 11:04:30 | 一号餐线·3号秤 | 餐线取餐 | 正常取餐 | M-20260428-001 | 原始数据 查看视频 |
+ | 4 | P-20260428-0011 | 午餐 | 红烧肉 | 正常 | 85.0 | ¥16.00 | EMP003-王磊 | 非会员 | 2026-04-28 11:16:40 | 一号餐线·5号秤 | 餐线取餐 | 正常取餐 | M-20260428-003 | 原始数据 查看视频 |
+ | 5 | P-20260428-0021 | 午餐 | 宫保鸡丁 | 无主记录 | 110.0 | ¥9.50 | — | — | 2026-04-28 11:25:08 | 一号餐线·5号秤 | 餐线取餐 | 正常取餐 | — | 原始数据 查看视频 |
+ | 6 | P-20260428-0022 | 午餐 | 米饭 | 无主记录 | 200.0 | ¥12.00 | — | — | 2026-04-28 11:25:33 | 一号餐线·5号秤 | 餐线取餐 | 正常取餐 | — | 原始数据 查看视频 |
+ | 7 | P-20260428-0031 | 晚餐 | 清蒸鲈鱼 | 无主记录 | 120.0 | ¥8.00 | — | — | 2026-04-28 18:12:45 | 二号档口·1号秤 | 档口取餐 | 正常取餐 | — | 原始数据 查看视频 |
+ | 8 | P-20260427-0005 | 午餐 | 糖醋里脊 | 手动修正 | 95.0 | ¥12.00 | EMP007-林教授 | 外部人员 | 2026-04-27 12:12:20 | 二号档口·1号秤 | 档口取餐 | 正常取餐 | M-20260428-007 | 原始数据 查看视频 |
+ | 9 | P-20260427-0018 | 午餐 | 余量套餐B | 手动修正 | 195.0 | ¥5.00 | EMP102-王保安 | 工作人员 | 2026-04-27 14:11:05 | 一号餐线·2号秤 | 餐线取餐 | 余量取餐 | SP-001-003 | 原始数据 查看视频 |
+ | 10 | P-20260428-0004 | 早餐 | 小米粥 | 正常 | 250.0 | ¥4.00 | EMP005-陈刚 | 非会员 | 2026-04-28 07:49:10 | 一号餐线·2号秤 | 餐线取餐 | 正常取餐 | M-20260428-005 | 原始数据 查看视频 |
+ | 11 | P-20260428-0041 | 午餐 | 鸡胸肉沙拉 | 正常 | 180.0 | ¥10.80 | EMP006-刘芳 | 会员 | 2026-04-28 11:46:22 | 三号档口·2号秤 | 档口取餐 | 正常取餐 | M-20260428-006 | 原始数据 查看视频 |
+ | 12 | P-20260428-0023 | 午餐 | 余量套餐A | 正常 | 220.0 | ¥5.00 | EMP101-张运维 | 员工 | 2026-04-28 14:05:50 | 一号餐线·2号秤 | 餐线取餐 | 余量取餐 | SP-001-001 | 原始数据 查看视频 |
+
+
+
+
+
+
+
+
@@ -367,20 +469,25 @@ function toggleSubgroup(header){header.parentElement.classList.toggle('open');}
const Modal = {
open(title, bodyHtml) {
this.close();
+ this.stack(title, bodyHtml);
+ },
+ stack(title, bodyHtml) {
const overlay = document.createElement('div');
overlay.className = 'modal-overlay';
overlay.innerHTML = ``;
- overlay.addEventListener('click', e => { if (e.target === overlay) Modal.close(); });
+ overlay.addEventListener('click', e => { if (e.target === overlay) Modal.closeTop(overlay); });
document.body.appendChild(overlay);
},
close() {
- const o = document.querySelector('.modal-overlay');
- if (!o) return;
- o.classList.add('closing');
- setTimeout(() => o.remove(), 200);
+ document.querySelectorAll('.modal-overlay').forEach(o => { o.classList.add('closing'); setTimeout(() => o.remove(), 200); });
+ },
+ closeTop(overlay) {
+ if (!overlay) return;
+ overlay.classList.add('closing');
+ setTimeout(() => overlay.remove(), 200);
}
};
@@ -575,7 +682,7 @@ function showUserProfile(name) {
}
/* 绑定表格中的"查看用户信息"链接 */
-document.querySelectorAll('tbody tr').forEach(row => {
+document.querySelectorAll('#recordTable tbody tr').forEach(row => {
const link = row.querySelector('td:last-child .link');
const nameCell = row.querySelector('td:nth-child(2)');
if (link && nameCell) {
@@ -662,15 +769,24 @@ function showMealDetail(row) {
`;
- const tableRows = items.map(i => `
- | ${i.name} |
- ¥${i.price.toFixed(2)} |
- ${i.weight.toFixed(1)} |
- ${i.cal.toFixed(1)} |
- ${i.carb.toFixed(1)} |
- ${i.fat.toFixed(1)} |
- ${i.protein.toFixed(1)} |
-
`).join('');
+ const dateStr = (recordId.match(/\d{8}/) || ['20260428'])[0].replace(/(\d{4})(\d{2})(\d{2})/, '$1-$2-$3');
+ const methodDeviceMap = { '餐线取餐':'一号餐线·3号秤', '档口+餐线':'二号档口·1号秤', '点餐取餐':'一号餐线·3号秤', '外卖/外带':'二号档口·1号秤', '余量取餐':'一号餐线·2号秤' };
+ const device = methodDeviceMap[pickupMethod] || '一号餐线·3号秤';
+
+ const tableRows = items.map((i, idx) => {
+ const itemTime = dateStr + ' ' + startTime + ':' + String(idx * 8).padStart(2, '0');
+ return `
+ | ${i.name} |
+ ¥${i.price.toFixed(2)} |
+ ${i.weight.toFixed(1)} |
+ ${i.cal.toFixed(1)} |
+ ${i.carb.toFixed(1)} |
+ ${i.fat.toFixed(1)} |
+ ${i.protein.toFixed(1)} |
+ 查看 |
+ 查看 |
+
`;
+ }).join('');
const summaryRow = `
| 合计 |
@@ -680,12 +796,14 @@ function showMealDetail(row) {
${totalCarb.toFixed(1)}克 |
${totalFat.toFixed(1)}克 |
${totalProtein.toFixed(1)}克 |
+ |
+ |
`;
const tableHtml = `
餐品列表
- | 餐品名称 | 金额 | 重量(克) | 热量(千卡) | 碳水化合物(克) | 脂肪(克) | 蛋白质(克) |
+ | 餐品名称 | 金额 | 重量(克) | 热量(千卡) | 碳水化合物(克) | 脂肪(克) | 蛋白质(克) | 原始数据 | 查看视频 |
${tableRows}${summaryRow}
`;
@@ -693,13 +811,127 @@ function showMealDetail(row) {
Modal.open('取餐详情 — ' + name, infoHtml + tableHtml);
}
+function showMealItemRawData(dish, weight, user, time, device) {
+ buildRawDataModal({ dish: dish, statusText: '正常', weight: parseFloat(weight), user: user, time: time, device: device });
+}
+
+function showMealItemVideo(dish, time, recordId) {
+ buildVideoModal({ id: recordId, dish: dish, statusText: '正常', time: time });
+}
+
/* 绑定"取餐总数量"列点击事件 */
-document.querySelectorAll('tbody tr').forEach(row => {
+document.querySelectorAll('#recordTable tbody tr').forEach(row => {
const quantityLink = row.querySelector('td:nth-child(12) .link');
if (quantityLink) {
quantityLink.addEventListener('click', () => showMealDetail(row));
}
});
+
+/* ========== 主 Tab 切换 ========== */
+function switchMainTab(el, key) {
+ document.querySelectorAll('.main-tab').forEach(t => t.classList.remove('active'));
+ el.classList.add('active');
+ document.querySelectorAll('.main-tab-panel').forEach(p => p.classList.remove('active'));
+ document.querySelector(`.main-tab-panel[data-panel="${key}"]`).classList.add('active');
+}
+
+/* ========== 取餐明细 - 原始数据弹窗 ========== */
+function showRawData(row) {
+ const c = row.querySelectorAll('td');
+ Modal.close();
+ buildRawDataModal({
+ dish: c[3].textContent.trim(),
+ statusText: c[4].textContent.trim(),
+ weight: parseFloat(c[5].textContent.trim()),
+ user: c[7].textContent.trim(),
+ time: c[9].textContent.trim(),
+ device: c[10].textContent.trim()
+ });
+}
+
+function buildRawDataModal(data) {
+ const deviceNoMap = { '一号餐线·2号秤':'SC-002', '一号餐线·3号秤':'SC-003', '一号餐线·5号秤':'SC-005', '二号档口·1号秤':'DC-001', '三号档口·2号秤':'DC-002' };
+ const deviceNo = deviceNoMap[data.device] || '—';
+
+ const isOrphan = data.statusText === '无主记录';
+ const isManual = data.statusText === '手动修正';
+ const recStatus = (isOrphan || isManual) ? '未识别' : '已识别';
+ const recUser = (isOrphan || isManual) ? '—' : data.user;
+ const statusTag = recStatus === '已识别' ? '已识别' : '未识别';
+
+ const samples = [
+ { t: minusSeconds(data.time, 5), w: (data.weight - 38).toFixed(1), d: '+' + (data.weight - 38).toFixed(1), stable: '否' },
+ { t: minusSeconds(data.time, 2), w: (data.weight - 9).toFixed(1), d: '+29.0', stable: '否' },
+ { t: data.time, w: data.weight.toFixed(1), d: '+9.0', stable: '是' }
+ ];
+
+ const rowsHtml = samples.map(s => `
+ | ${s.t} |
+ ${s.w} |
+ ${s.d} |
+ ${statusTag} |
+ ${recUser} |
+ ${s.stable === '是' ? '是' : '否'} |
+
`).join('');
+
+ const html = `
+
设备编号:${deviceNo}
+
设备名称:${data.device}
+
+
+ | 采样时间 | 当前重量(g) | 较上次变化重量(g) | 识别状态 | 用户 | 是否稳定 |
+ ${rowsHtml}
+
`;
+
+ Modal.stack('秤原始数据 — ' + data.dish, html);
+}
+
+function minusSeconds(timeStr, sec) {
+ const parts = timeStr.split(' ');
+ const date = parts[0];
+ const hms = parts[1].split(':').map(Number);
+ const d = new Date(0);
+ d.setHours(hms[0], hms[1], hms[2] - sec);
+ const pad = n => String(n).padStart(2, '0');
+ return date + ' ' + pad(d.getHours()) + ':' + pad(d.getMinutes()) + ':' + pad(d.getSeconds());
+}
+
+/* ========== 取餐明细 - 视频回放弹窗 ========== */
+function showPickupVideo(row) {
+ const c = row.querySelectorAll('td');
+ Modal.close();
+ buildVideoModal({
+ id: c[1].textContent.trim(),
+ dish: c[3].textContent.trim(),
+ statusText: c[4].textContent.trim(),
+ time: c[9].textContent.trim()
+ });
+}
+
+function buildVideoModal(data) {
+ const html = `取用记录ID:${data.id} · 取餐时间:${data.time} · 记录状态:${data.statusText}
+ `;
+ Modal.stack('取餐视频回放 — ' + data.dish, html);
+}
+
+/* 绑定取餐明细表格操作列 */
+document.querySelectorAll('#detailTable tbody tr').forEach(row => {
+ const links = row.querySelectorAll('.td-actions .link');
+ if (links.length >= 2) {
+ links[0].addEventListener('click', () => showRawData(row));
+ links[1].addEventListener('click', () => showPickupVideo(row));
+ }
+});