feat: 净菜包装秤术语统一+包装作业交互升级 + 组配秤按单份拆分
净菜包装秤(原贴标秤): - 全模块术语统一: 贴标→包装, 贴标秤→包装秤, 去丝/段/片后缀 - 包装作业页: 清单按packSize展开为单份, 移除弹窗改为直接读秤, 新增搜索框 - 包装任务/历史页: 表头对齐, 按单份拆分展示 - 新增label-preview.html标签预览页 净菜组配秤: - 任务/历史页: 行展示按单份拆分, 食材名称简化(去丝/段/片/块/液后缀) - 组配作业页: 移除确认弹窗, 底部按钮区改为flex布局 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.6
parent
63940f4c49
commit
723b5cef02
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=1024, initial-scale=1.0">
|
||||
<title>净菜贴标秤 - 登录 | 蚁熊智能餐养平台</title>
|
||||
<title>净菜包装秤 - 登录 | 蚁熊智能餐养平台</title>
|
||||
<style>
|
||||
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||||
body {
|
||||
@@ -146,15 +146,15 @@
|
||||
|
||||
<div class="device-frame">
|
||||
<div class="top-bar">
|
||||
<span class="top-bar__title">净菜贴标秤 - 员工登录</span>
|
||||
<span class="top-bar__title">净菜包装秤 - 员工登录</span>
|
||||
</div>
|
||||
|
||||
<div class="login-main">
|
||||
<!-- 左侧品牌区 -->
|
||||
<div class="login-brand">
|
||||
<div class="login-brand__icon">🏷️</div>
|
||||
<div class="login-brand__name">净菜贴标秤</div>
|
||||
<div class="login-brand__desc">接收配比完成订单<br>核对实物 · 贴标塑封 · 全程可溯</div>
|
||||
<div class="login-brand__name">净菜包装秤</div>
|
||||
<div class="login-brand__desc">接收配比完成订单<br>核对实物 · 包装塑封 · 全程可溯</div>
|
||||
</div>
|
||||
|
||||
<!-- 右侧登录面板 -->
|
||||
@@ -209,8 +209,8 @@
|
||||
|
||||
/* 模拟用户数据 */
|
||||
var mockUsers = [
|
||||
{ name: '刘九', id: 'EMP-20260050', dept: '贴标车间', role: '贴标员', empId: '40001', password: '123456' },
|
||||
{ name: '陈十', id: 'EMP-20260055', dept: '贴标车间', role: '贴标员', empId: '40002', password: '123456' },
|
||||
{ name: '刘九', id: 'EMP-20260050', dept: '包装车间', role: '包装员', empId: '40001', password: '123456' },
|
||||
{ name: '陈十', id: 'EMP-20260055', dept: '包装车间', role: '包装员', empId: '40002', password: '123456' },
|
||||
{ name: '杨一', id: 'EMP-20260060', dept: '质检部', role: '质检员', empId: '40003', password: '123456' }
|
||||
];
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=1024, initial-scale=1.0">
|
||||
<title>净菜贴标秤 - 订单列表 | 蚁熊智能餐养平台</title>
|
||||
<title>净菜包装秤 - 订单列表 | 蚁熊智能餐养平台</title>
|
||||
<style>
|
||||
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||||
body {
|
||||
@@ -64,15 +64,15 @@
|
||||
|
||||
/* 表格头 */
|
||||
.item-table__head {
|
||||
display: grid; grid-template-columns: 1fr 0.7fr 0.55fr 0.5fr 0.6fr 0.55fr 50px; gap: 6px;
|
||||
display: grid; grid-template-columns: 1fr 0.5fr 0.45fr 0.25fr 0.4fr 0.4fr 50px; gap: 6px;
|
||||
padding: 5px 14px; background: rgba(0,0,0,0.2); font-size: 10px; color: rgba(255,255,255,0.4); font-weight: 500;
|
||||
}
|
||||
.item-table__body { display: flex; flex-direction: column; }
|
||||
|
||||
/* 餐品净菜包主行 */
|
||||
.item-parent-row {
|
||||
display: grid; grid-template-columns: 1fr 0.7fr 0.55fr 0.5fr 0.6fr 0.55fr 50px; gap: 6px;
|
||||
padding: 8px 14px; border-top: 1px solid rgba(255,255,255,0.04); align-items: center;
|
||||
display: grid; grid-template-columns: 1fr 0.5fr 0.45fr 0.25fr 0.4fr 0.4fr 50px; gap: 6px;
|
||||
padding: 6px 14px; border-top: 1px solid rgba(255,255,255,0.04); align-items: center;
|
||||
background: rgba(74,144,217,0.06);
|
||||
}
|
||||
.parent-name { display: flex; align-items: center; gap: 8px; }
|
||||
@@ -103,7 +103,7 @@
|
||||
<div class="device-frame">
|
||||
<div class="top-bar">
|
||||
<a class="back-btn" id="backBtn" href="javascript:void(0)">◀ 返回</a>
|
||||
<span class="top-bar__title">贴标任务</span>
|
||||
<span class="top-bar__title">包装任务</span>
|
||||
<div class="top-bar__user">
|
||||
<div class="top-bar__avatar" id="topAvatar">--</div>
|
||||
<span id="topUser">--</span>
|
||||
@@ -115,7 +115,7 @@
|
||||
<!-- Tab 切换 -->
|
||||
<div class="tabs">
|
||||
<div class="tab active" data-filter="pending" onclick="switchTab('pending', this)">待打印 <span class="tab__count" id="pendingCount">0</span></div>
|
||||
<div class="tab" data-filter="done" onclick="switchTab('done', this)">已贴标 <span class="tab__count" id="doneCount">0</span></div>
|
||||
<div class="tab" data-filter="done" onclick="switchTab('done', this)">已包装 <span class="tab__count" id="doneCount">0</span></div>
|
||||
</div>
|
||||
<!-- 任务列表 -->
|
||||
<div class="task-list-container" id="taskListContainer"></div>
|
||||
@@ -151,8 +151,8 @@
|
||||
taskNo: 'L-001',
|
||||
labeled: false,
|
||||
mealPacks: [
|
||||
{ type: '净菜包', packName: '土豆丝', packSize: 3, packSpec: '500g', ingredients: [{ name: '土豆丝', weightPerPack: 500, weighed: 1500 }] },
|
||||
{ type: '净菜包', packName: '胡萝卜丝', packSize: 3, packSpec: '500g', ingredients: [{ name: '胡萝卜丝', weightPerPack: 500, weighed: 1500 }] },
|
||||
{ type: '净菜包', packName: '土豆', packSize: 3, packSpec: '500g', ingredients: [{ name: '土豆', weightPerPack: 500, weighed: 1500 }] },
|
||||
{ type: '净菜包', packName: '胡萝卜', packSize: 3, packSpec: '500g', ingredients: [{ name: '胡萝卜', weightPerPack: 500, weighed: 1500 }] },
|
||||
{ type: '餐品净菜包', packName: '宫保鸡丁套餐', packSize: 2, packSpec: '大份800g', ingredients: [{ name: '宫保鸡丁', weightPerPack: 800, weighed: 1600 }] }
|
||||
]
|
||||
},
|
||||
@@ -163,7 +163,7 @@
|
||||
taskNo: 'L-002',
|
||||
labeled: false,
|
||||
mealPacks: [
|
||||
{ type: '净菜包', packName: '白菜丝', packSize: 2, packSpec: '1000g', ingredients: [{ name: '白菜丝', weightPerPack: 1000, weighed: 2000 }] },
|
||||
{ type: '净菜包', packName: '白菜', packSize: 2, packSpec: '1000g', ingredients: [{ name: '白菜', weightPerPack: 1000, weighed: 2000 }] },
|
||||
{ type: '餐品净菜包', packName: '鱼香肉丝套餐', packSize: 2, packSpec: '大份800g', ingredients: [{ name: '鱼香肉丝', weightPerPack: 800, weighed: 1600 }] }
|
||||
]
|
||||
},
|
||||
@@ -179,7 +179,7 @@
|
||||
}
|
||||
];
|
||||
|
||||
/* 已贴标订单(贴标历史) */
|
||||
/* 已包装订单(包装历史) */
|
||||
var mockDoneData = [
|
||||
{
|
||||
orderNo: 'PO-20260624-001',
|
||||
@@ -190,7 +190,7 @@
|
||||
labeledTime: '2026-06-24 10:15',
|
||||
operator: '刘九',
|
||||
mealPacks: [
|
||||
{ type: '净菜包', packName: '黄瓜片', packSize: 3, packSpec: '500g', ingredients: [{ name: '黄瓜片', weightPerPack: 500, weighed: 1500 }] },
|
||||
{ type: '净菜包', packName: '黄瓜', packSize: 3, packSpec: '500g', ingredients: [{ name: '黄瓜', weightPerPack: 500, weighed: 1500 }] },
|
||||
{ type: '餐品净菜包', packName: '凉拌黄瓜套餐', packSize: 2, packSpec: '盒装', ingredients: [{ name: '凉拌黄瓜', weightPerPack: 600, weighed: 1200 }] }
|
||||
]
|
||||
},
|
||||
@@ -203,7 +203,7 @@
|
||||
labeledTime: '2026-06-24 13:45',
|
||||
operator: '陈十',
|
||||
mealPacks: [
|
||||
{ type: '净菜包', packName: '芹菜段', packSize: 2, packSpec: '500g', ingredients: [{ name: '芹菜段', weightPerPack: 500, weighed: 1000 }] },
|
||||
{ type: '净菜包', packName: '芹菜', packSize: 2, packSpec: '500g', ingredients: [{ name: '芹菜', weightPerPack: 500, weighed: 1000 }] },
|
||||
{ type: '餐品净菜包', packName: '芹菜炒肉套餐', packSize: 3, packSpec: '大份800g', ingredients: [{ name: '芹菜炒肉', weightPerPack: 800, weighed: 2400 }] }
|
||||
]
|
||||
}
|
||||
@@ -219,7 +219,7 @@
|
||||
var allDone = pack.ingredients.every(function(ing) {
|
||||
return ing.weighed >= ing.weightPerPack * pack.packSize;
|
||||
});
|
||||
return allDone ? { text: '已贴标', cls: 'status-tag--done' } : { text: '待打印', cls: 'status-tag--wait' };
|
||||
return allDone ? { text: '已包装', cls: 'status-tag--done' } : { text: '待打印', cls: 'status-tag--wait' };
|
||||
}
|
||||
|
||||
/* 渲染任务列表 */
|
||||
@@ -251,12 +251,12 @@
|
||||
|
||||
if (currentFilter === 'pending') {
|
||||
headerHtml += '<span class="task-card__arrival">⏰ 任务截止时间:<span class="task-card__arrival__time">' + order.expectedArrival + '</span></span>';
|
||||
headerHtml += '<span class="task-card__status"><span class="status-badge status-badge--pending">待贴标</span></span>';
|
||||
headerHtml += '<button class="task-card__label-btn" onclick="handleLabel(\'' + order.taskNo + '\',\'' + order.orderNo + '\')">去贴标</button>';
|
||||
headerHtml += '<span class="task-card__status"><span class="status-badge status-badge--pending">待包装</span></span>';
|
||||
headerHtml += '<button class="task-card__label-btn" onclick="handleLabel(\'' + order.taskNo + '\',\'' + order.orderNo + '\')">去包装</button>';
|
||||
} else {
|
||||
headerHtml += '<span class="task-card__arrival">⏰ 贴标完成时间:<span class="task-card__arrival__time">' + order.labeledTime + '</span></span>';
|
||||
headerHtml += '<span class="task-card__arrival">⏰ 包装完成时间:<span class="task-card__arrival__time">' + order.labeledTime + '</span></span>';
|
||||
headerHtml += '<span class="task-card__operator">👤 操作人:<span class="task-card__operator__name">' + order.operator + '</span></span>';
|
||||
headerHtml += '<span class="task-card__status"><span class="status-badge status-badge--done">已贴标</span></span>';
|
||||
headerHtml += '<span class="task-card__status"><span class="status-badge status-badge--done">已包装</span></span>';
|
||||
}
|
||||
header.innerHTML = headerHtml;
|
||||
taskCard.appendChild(header);
|
||||
@@ -264,10 +264,10 @@
|
||||
/* 表格头 */
|
||||
var tableHead = document.createElement('div');
|
||||
tableHead.className = 'item-table__head';
|
||||
tableHead.innerHTML = '<div>名称</div><div style="text-align:center">净菜/餐品</div><div style="text-align:center">包装规格</div><div style="text-align:center">打包份数</div><div style="text-align:right">所需总重</div><div style="text-align:right">已称</div><div style="text-align:center">状态</div>';
|
||||
tableHead.innerHTML = '<div>名称</div><div style="text-align:center">净菜/餐品</div><div style="text-align:center">包装规格</div><div style="text-align:center">份数</div><div style="text-align:right">应称重量</div><div style="text-align:right">已称重量</div><div style="text-align:center">状态</div>';
|
||||
taskCard.appendChild(tableHead);
|
||||
|
||||
/* 表格体 */
|
||||
/* 表格体:按单份拆分展示 */
|
||||
var tableBody = document.createElement('div');
|
||||
tableBody.className = 'item-table__body';
|
||||
|
||||
@@ -275,25 +275,32 @@
|
||||
var packStatus = currentFilter === 'pending'
|
||||
? { text: '待打印', cls: 'status-tag--wait' }
|
||||
: { text: '已打印', cls: 'status-tag--done' };
|
||||
var totalNeed = 0;
|
||||
var totalWeighed = 0;
|
||||
pack.ingredients.forEach(function(ing) {
|
||||
totalNeed += ing.weightPerPack * pack.packSize;
|
||||
totalWeighed += ing.weighed;
|
||||
});
|
||||
var weightClass = totalWeighed >= totalNeed ? 'parent-weight--done' : '';
|
||||
var ingWeight = pack.ingredients[0] ? pack.ingredients[0].weightPerPack : 0;
|
||||
|
||||
var parentRow = document.createElement('div');
|
||||
parentRow.className = 'item-parent-row';
|
||||
parentRow.innerHTML =
|
||||
'<div class="parent-name"><div class="parent-icon">📦</div><span class="parent-name__text">' + pack.packName + '</span></div>' +
|
||||
'<div style="text-align:center;font-size:11px;color:' + (pack.type === '餐品净菜包' ? '#faad16' : '#4a90d9') + '">' + pack.type + '</div>' +
|
||||
'<div style="text-align:center;font-size:11px;color:rgba(255,255,255,0.55)">' + (pack.packSpec || '—') + '</div>' +
|
||||
'<div style="text-align:center"><span class="pack-size-tag">' + pack.packSize + '</span></div>' +
|
||||
'<div class="parent-weight ' + weightClass + '">' + totalNeed + ' g</div>' +
|
||||
'<div class="parent-weight ' + weightClass + '">' + totalWeighed + ' g</div>' +
|
||||
'<div style="text-align:center"><span class="status-tag ' + packStatus.cls + '">' + packStatus.text + '</span></div>';
|
||||
tableBody.appendChild(parentRow);
|
||||
/* 按 packSize 拆分为单份行 */
|
||||
/* 从包装规格中提取应称重量(如"500g"→500) */
|
||||
var specMatch = pack.packSpec && pack.packSpec.match(/(\d+)g/);
|
||||
var dueWeight = specMatch ? parseInt(specMatch[1]) : ingWeight;
|
||||
var doneWeight = currentFilter === 'done' ? dueWeight : 0;
|
||||
|
||||
for (var p = 0; p < pack.packSize; p++) {
|
||||
var parentRow = document.createElement('div');
|
||||
parentRow.className = 'item-parent-row';
|
||||
var statusCell = '<div style="text-align:center"><span class="status-tag ' + packStatus.cls + '">' + packStatus.text + '</span>';
|
||||
if (currentFilter === 'done') {
|
||||
statusCell += '<div style="margin-top:3px"><button style="font-size:10px;padding:2px 8px;background:rgba(74,144,217,0.15);border:1px solid rgba(74,144,217,0.3);border-radius:4px;color:#4a90d9;cursor:pointer;font-family:inherit;" onclick="event.stopPropagation();handleReprint(\'' + order.orderNo + '\',\'' + pack.packName + '\',' + (p + 1) + ')">重新打印</button></div>';
|
||||
}
|
||||
statusCell += '</div>';
|
||||
parentRow.innerHTML =
|
||||
'<div class="parent-name"><div class="parent-icon">📦</div><span class="parent-name__text">' + pack.packName + ' <span style="font-size:10px;color:rgba(255,255,255,0.4)">第' + (p + 1) + '份/' + pack.packSize + '份</span></span></div>' +
|
||||
'<div style="text-align:center;font-size:11px;color:' + (pack.type === '餐品净菜包' ? '#faad16' : '#4a90d9') + '">' + pack.type + '</div>' +
|
||||
'<div style="text-align:center;font-size:11px;color:rgba(255,255,255,0.55)">' + (pack.packSpec || '—') + '</div>' +
|
||||
'<div style="text-align:center;font-size:11px;color:rgba(255,255,255,0.55)">1</div>' +
|
||||
'<div class="parent-weight parent-weight--done">' + dueWeight + ' g</div>' +
|
||||
'<div class="parent-weight">' + doneWeight + ' g</div>' +
|
||||
statusCell;
|
||||
tableBody.appendChild(parentRow);
|
||||
}
|
||||
});
|
||||
|
||||
taskCard.appendChild(tableBody);
|
||||
@@ -313,13 +320,18 @@
|
||||
renderTaskList();
|
||||
}
|
||||
|
||||
/* 去贴标 */
|
||||
/* 去包装 */
|
||||
function handleLabel(taskNo, orderNo) {
|
||||
var target = '02-labeling.html?task=' + taskNo + '&order=' + encodeURIComponent(orderNo);
|
||||
if (userName) target += '&user=' + encodeURIComponent(userName) + '&uid=' + (userId || '');
|
||||
window.location.href = target;
|
||||
}
|
||||
|
||||
/* 重新打印 */
|
||||
function handleReprint(orderNo, packName, portion) {
|
||||
showToast('重新打印: ' + orderNo + ' ' + packName + ' 第' + portion + '份', 2000, 'success');
|
||||
}
|
||||
|
||||
/* 退出登录 */
|
||||
function handleLogout() {
|
||||
window.location.href = '00-login.html';
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=1024, initial-scale=1.0">
|
||||
<title>净菜贴标秤 - 贴标任务 | 蚁熊智能餐养平台</title>
|
||||
<title>净菜包装秤 - 包装任务 | 蚁熊智能餐养平台</title>
|
||||
<style>
|
||||
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||||
body {
|
||||
@@ -103,6 +103,21 @@
|
||||
.reidentify-btn:hover { background: rgba(74,144,217,0.2); border-color: #4a90d9; }
|
||||
.reidentify-btn:active { transform: scale(0.98); }
|
||||
|
||||
/* 搜索框 */
|
||||
.food-search { flex-shrink: 0; }
|
||||
.food-search__wrap { position: relative; }
|
||||
.food-search__input {
|
||||
width: 100%; padding: 8px 14px 8px 34px; background: #121832;
|
||||
border: 1px solid rgba(255,255,255,0.1); border-radius: 8px; color: #fff;
|
||||
font-size: 13px; outline: none; transition: border-color 0.2s;
|
||||
}
|
||||
.food-search__input:focus { border-color: #4a90d9; }
|
||||
.food-search__input::placeholder { color: rgba(255,255,255,0.25); }
|
||||
.food-search__icon {
|
||||
position: absolute; left: 10px; top: 50%; transform: translateY(-50%);
|
||||
font-size: 13px; color: rgba(255,255,255,0.3);
|
||||
}
|
||||
|
||||
/* 候选食材区 */
|
||||
.candidate-section { flex: 1; display: flex; flex-direction: column; min-height: 0; }
|
||||
.candidate-header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 6px; }
|
||||
@@ -146,7 +161,7 @@
|
||||
.order-type-tag--internal { background: rgba(74,144,217,0.15); color: #4a90d9; }
|
||||
.order-type-tag--external { background: rgba(250,140,22,0.15); color: #fa8c16; }
|
||||
|
||||
/* 贴标清单 */
|
||||
/* 包装清单 */
|
||||
.item-list { flex: 1; min-height: 0; display: flex; flex-direction: column; overflow: hidden; }
|
||||
.item-list__body { flex: 1; overflow-y: auto; min-height: 0; display: flex; flex-direction: column; gap: 6px; scrollbar-width: none; }
|
||||
.item-list__body::-webkit-scrollbar { display: none; }
|
||||
@@ -210,7 +225,7 @@
|
||||
.status-tag--wait { background: rgba(255,255,255,0.06); color: rgba(255,255,255,0.35); }
|
||||
.status-tag--labeled { background: rgba(82,196,26,0.15); color: #52c41a; }
|
||||
|
||||
/* 贴标完成按钮 */
|
||||
/* 包装完成按钮 */
|
||||
.next-btn-wrap { flex-shrink: 0; }
|
||||
.next-btn {
|
||||
width: 100%; padding: 11px 0; border: none; border-radius: 10px;
|
||||
@@ -222,36 +237,6 @@
|
||||
.next-btn:active { transform: scale(0.97); }
|
||||
.next-btn:disabled { background: rgba(255,255,255,0.06); color: rgba(255,255,255,0.2); cursor: not-allowed; box-shadow: none; }
|
||||
|
||||
/* 秤重确认弹窗 */
|
||||
.modal-overlay {
|
||||
position: fixed; inset: 0; background: rgba(0,0,0,0.6); z-index: 1000;
|
||||
display: none; align-items: center; justify-content: center;
|
||||
}
|
||||
.modal-overlay.show { display: flex; }
|
||||
.modal {
|
||||
background: #1a2b4a; border-radius: 14px; border: 1px solid rgba(255,255,255,0.08);
|
||||
padding: 24px 28px; width: 340px; display: flex; flex-direction: column; gap: 16px;
|
||||
}
|
||||
.modal__title { font-size: 15px; font-weight: 600; text-align: center; }
|
||||
.modal__food { display: flex; align-items: center; justify-content: center; gap: 8px; font-size: 14px; }
|
||||
.modal__food-icon { font-size: 24px; }
|
||||
.modal__label { font-size: 12px; color: rgba(255,255,255,0.5); text-align: center; }
|
||||
.modal__weight-row { display: flex; align-items: center; justify-content: center; gap: 10px; }
|
||||
.modal__weight-value { font-size: 28px; font-weight: 700; color: #4a90d9; line-height: 1; }
|
||||
.modal__weight-refresh {
|
||||
width: 28px; height: 28px; border-radius: 6px; border: 1px solid rgba(74,144,217,0.25);
|
||||
background: rgba(74,144,217,0.1); color: #4a90d9; font-size: 14px;
|
||||
cursor: pointer; transition: all 0.2s; display: flex; align-items: center; justify-content: center;
|
||||
}
|
||||
.modal__weight-refresh:hover { background: rgba(74,144,217,0.2); border-color: #4a90d9; }
|
||||
.modal__weight-unit { text-align: center; font-size: 12px; color: rgba(255,255,255,0.4); margin-top: -8px; }
|
||||
.modal__actions { display: flex; gap: 10px; }
|
||||
.modal__btn { flex: 1; padding: 10px 0; border-radius: 8px; font-size: 13px; font-weight: 600; cursor: pointer; transition: all 0.2s; font-family: inherit; border: none; }
|
||||
.modal__btn--cancel { background: rgba(255,255,255,0.08); color: rgba(255,255,255,0.6); }
|
||||
.modal__btn--cancel:hover { background: rgba(255,255,255,0.12); color: #fff; }
|
||||
.modal__btn--confirm { background: #4a90d9; color: #fff; }
|
||||
.modal__btn--confirm:hover { background: #5ba0e9; }
|
||||
|
||||
/* Toast */
|
||||
.toast {
|
||||
position: fixed; top: 60px; left: 50%; transform: translateX(-50%) translateY(-20px);
|
||||
@@ -271,7 +256,7 @@
|
||||
<!-- 顶部导航 -->
|
||||
<div class="top-bar">
|
||||
<a class="back-btn" id="backBtn" href="javascript:void(0)">◀ 返回</a>
|
||||
<span class="page-title">贴标任务</span>
|
||||
<span class="page-title">包装任务</span>
|
||||
<span class="top-bar__spacer"></span>
|
||||
<div class="user-info">
|
||||
<div class="avatar" id="userAvatar">--</div>
|
||||
@@ -306,6 +291,14 @@
|
||||
<span id="statusText">就绪,等待净菜放置</span>
|
||||
</div>
|
||||
<button class="reidentify-btn" onclick="handleReidentify()">🔄 重新识别</button>
|
||||
<!-- 搜索框 -->
|
||||
<div class="food-search">
|
||||
<div class="food-search__wrap">
|
||||
<span class="food-search__icon">🔍</span>
|
||||
<input type="text" class="food-search__input" id="foodSearchInput"
|
||||
placeholder="搜索净菜名称,回车确认..." onkeydown="handleFoodSearchKey(event)">
|
||||
</div>
|
||||
</div>
|
||||
<div class="candidate-section" id="candidateSection">
|
||||
<div class="candidate-header">
|
||||
<span class="candidate-title" id="candidateTitle">智能识别候选</span>
|
||||
@@ -319,7 +312,7 @@
|
||||
<div class="scene-note">场景监控后台静默录制中</div>
|
||||
</div>
|
||||
|
||||
<!-- 右列:订单信息 + 贴标清单 + 完成按钮 -->
|
||||
<!-- 右列:订单信息 + 包装清单 + 完成按钮 -->
|
||||
<div class="col-right">
|
||||
<!-- 订单信息卡片 -->
|
||||
<div class="task-card">
|
||||
@@ -343,14 +336,14 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 贴标清单 -->
|
||||
<!-- 包装清单 -->
|
||||
<div class="item-list">
|
||||
<div class="item-list__body" id="itemListBody"></div>
|
||||
</div>
|
||||
|
||||
<!-- 贴标完成按钮 -->
|
||||
<!-- 包装完成按钮 -->
|
||||
<div class="next-btn-wrap">
|
||||
<button class="next-btn" id="btnNext" onclick="handleLabelDone()">贴标完成</button>
|
||||
<button class="next-btn" id="btnNext" onclick="handleLabelDone()">包装完成</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -359,27 +352,6 @@
|
||||
<!-- Toast -->
|
||||
<div class="toast" id="toast"></div>
|
||||
|
||||
<!-- 秤重确认弹窗 -->
|
||||
<div class="modal-overlay" id="modalOverlay">
|
||||
<div class="modal">
|
||||
<div class="modal__title">秤重确认</div>
|
||||
<div class="modal__food">
|
||||
<span class="modal__food-icon" id="modalIcon"></span>
|
||||
<span id="modalFoodName">--</span>
|
||||
</div>
|
||||
<div class="modal__label">本次秤重重量</div>
|
||||
<div class="modal__weight-row">
|
||||
<span class="modal__weight-value" id="modalWeight">0.0</span>
|
||||
<button class="modal__weight-refresh" onclick="refreshWeight()" title="重新获取秤上重量">🔄</button>
|
||||
</div>
|
||||
<div class="modal__weight-unit">克</div>
|
||||
<div class="modal__actions">
|
||||
<button class="modal__btn modal__btn--cancel" onclick="closeModal()">取消</button>
|
||||
<button class="modal__btn modal__btn--confirm" onclick="confirmWeight()">确认</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
/* ---- 工具函数 ---- */
|
||||
function getUrlParam(name) {
|
||||
@@ -402,8 +374,8 @@
|
||||
orderNo: 'PO-20260625-001',
|
||||
orderType: 'internal',
|
||||
items: [
|
||||
{ type: '净菜包', packName: '土豆丝', packSize: 3, packSpec: '500g', cutSpec: '20mm*1mm*1mm · 细丝 · 平刀', weightPerPack: 500, weighed: 1500, icon: '🥔' },
|
||||
{ type: '净菜包', packName: '胡萝卜丝', packSize: 3, packSpec: '500g', cutSpec: '20mm*1mm*1mm · 细丝 · 平刀', weightPerPack: 500, weighed: 1500, icon: '🥕' },
|
||||
{ type: '净菜包', packName: '土豆', packSize: 3, packSpec: '500g', cutSpec: '20mm*1mm*1mm · 细丝 · 平刀', weightPerPack: 500, weighed: 1500, icon: '🥔' },
|
||||
{ type: '净菜包', packName: '胡萝卜', packSize: 3, packSpec: '500g', cutSpec: '20mm*1mm*1mm · 细丝 · 平刀', weightPerPack: 500, weighed: 1500, icon: '🥕' },
|
||||
{ type: '餐品净菜包', packName: '宫保鸡丁套餐', packSize: 2, packSpec: '大份800g', weightPerPack: 800, weighed: 1600, icon: '🍱' }
|
||||
]
|
||||
},
|
||||
@@ -411,7 +383,7 @@
|
||||
orderNo: 'PO-20260625-002',
|
||||
orderType: 'external',
|
||||
items: [
|
||||
{ type: '净菜包', packName: '白菜丝', packSize: 2, packSpec: '1000g', cutSpec: '50mm*30mm*30mm · 宽段 · 平刀', weightPerPack: 1000, weighed: 2000, icon: '🥬' },
|
||||
{ type: '净菜包', packName: '白菜', packSize: 2, packSpec: '1000g', cutSpec: '50mm*30mm*30mm · 宽段 · 平刀', weightPerPack: 1000, weighed: 2000, icon: '🥬' },
|
||||
{ type: '餐品净菜包', packName: '鱼香肉丝套餐', packSize: 2, packSpec: '大份800g', weightPerPack: 800, weighed: 1600, icon: '🍱' }
|
||||
]
|
||||
},
|
||||
@@ -426,34 +398,38 @@
|
||||
|
||||
/* AI 识别候选数据 */
|
||||
var aiResults = {
|
||||
'potato': { name: '土豆丝', icon: '🥔', confidence: 97 },
|
||||
'carrot': { name: '胡萝卜丝', icon: '🥕', confidence: 96 },
|
||||
'cabbage': { name: '白菜丝', icon: '🥬', confidence: 93 }
|
||||
'potato': { name: '土豆', icon: '🥔', confidence: 97 },
|
||||
'carrot': { name: '胡萝卜', icon: '🥕', confidence: 96 },
|
||||
'cabbage': { name: '白菜', icon: '🥬', confidence: 93 }
|
||||
};
|
||||
|
||||
/* ---- 状态变量 ---- */
|
||||
var state = 'idle';
|
||||
var allItems = [];
|
||||
var currentVegIdx = 0;
|
||||
var pendingCandidate = null;
|
||||
|
||||
/* ---- 初始化 ---- */
|
||||
/* ---- 初始化:按 packSize 展开为单份 ---- */
|
||||
function init() {
|
||||
var task = taskData[taskNo];
|
||||
if (!task) { showToast('任务不存在', 2000, 'error'); return; }
|
||||
|
||||
allItems = task.items.map(function(item) {
|
||||
return {
|
||||
type: item.type,
|
||||
packName: item.packName,
|
||||
packSize: item.packSize,
|
||||
packSpec: item.packSpec,
|
||||
cutSpec: item.cutSpec,
|
||||
weightPerPack: item.weightPerPack,
|
||||
weighed: item.weighed,
|
||||
icon: item.icon,
|
||||
labeled: false
|
||||
};
|
||||
/* 将每个 item 按 packSize 展开为独立份数 */
|
||||
allItems = [];
|
||||
task.items.forEach(function(item) {
|
||||
for (var p = 0; p < item.packSize; p++) {
|
||||
allItems.push({
|
||||
type: item.type,
|
||||
packName: item.packName,
|
||||
packSpec: item.packSpec,
|
||||
cutSpec: item.cutSpec,
|
||||
weightPerPack: item.weightPerPack,
|
||||
portionIdx: p + 1,
|
||||
portionTotal: item.packSize,
|
||||
weighed: 0,
|
||||
icon: item.icon,
|
||||
labeled: false
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
currentVegIdx = -1;
|
||||
@@ -475,7 +451,7 @@
|
||||
renderItemList();
|
||||
|
||||
if (currentVegIdx >= 0) {
|
||||
document.getElementById('scaleWeightValue').textContent = allItems[currentVegIdx].weighed.toFixed(2);
|
||||
document.getElementById('scaleWeightValue').textContent = '0.00';
|
||||
document.getElementById('cameraOverlay').classList.add('show');
|
||||
} else {
|
||||
document.getElementById('scaleWeightValue').textContent = '0.00';
|
||||
@@ -491,7 +467,7 @@
|
||||
function updateTaskStatus() {
|
||||
var allDone = checkAllDone();
|
||||
var statusEl = document.getElementById('taskStatus');
|
||||
statusEl.textContent = allDone ? '已完成' : '待贴标';
|
||||
statusEl.textContent = allDone ? '已完成' : '待包装';
|
||||
statusEl.className = 'task-card__item-value' + (allDone ? ' task-card__item-value--green' : ' task-card__item-value--yellow');
|
||||
document.getElementById('btnNext').disabled = !allDone;
|
||||
}
|
||||
@@ -501,13 +477,12 @@
|
||||
return allItems.every(function(item) { return item.labeled; });
|
||||
}
|
||||
|
||||
/* ---- 渲染贴标清单(净菜包和餐品净菜包统一用待打印/已打印) ---- */
|
||||
/* ---- 渲染包装清单(按单份拆分,每份一张卡片) ---- */
|
||||
function renderItemList() {
|
||||
var body = document.getElementById('itemListBody');
|
||||
body.innerHTML = '';
|
||||
|
||||
allItems.forEach(function(item, idx) {
|
||||
var need = Math.round(item.weightPerPack * item.packSize * 100) / 100;
|
||||
var row = document.createElement('div');
|
||||
var isMeal = item.type === '餐品净菜包';
|
||||
|
||||
@@ -523,16 +498,6 @@
|
||||
var labelBtnCls = item.labeled ? 'label-btn label-btn--done' : 'label-btn';
|
||||
var typeTagCls = isMeal ? 'item-row__type-tag--meal' : 'item-row__type-tag--veg';
|
||||
|
||||
/* 每份用量:净菜包显示实际值,餐品净菜包显示-- */
|
||||
var perPackDisplay = isMeal
|
||||
? '<span class="item-card__data-value item-card__data-value--dash">--</span>'
|
||||
: '<span class="item-card__data-value">' + item.weightPerPack + 'g</span>';
|
||||
|
||||
/* 餐品字段:餐品净菜包显示餐品名称,净菜包显示-- */
|
||||
var mealDisplay = isMeal
|
||||
? '<span class="item-card__data-value">' + item.packName + '</span>'
|
||||
: '<span class="item-card__data-value item-card__data-value--dash">--</span>';
|
||||
|
||||
/* 按钮逻辑:净菜包无手动打印按钮(秤重确认时自动打印),餐品净菜包手动打印 */
|
||||
var actionHtml;
|
||||
if (isMeal) {
|
||||
@@ -547,7 +512,7 @@
|
||||
|
||||
row.innerHTML =
|
||||
'<div class="item-card__header">' +
|
||||
'<div class="item-row__name"><span class="item-row__name-icon">' + item.icon + '</span>' + item.packName + '</div>' +
|
||||
'<div class="item-row__name"><span class="item-row__name-icon">' + item.icon + '</span>' + item.packName + ' <span style="font-size:10px;color:rgba(255,255,255,0.4)">第' + item.portionIdx + '份/' + item.portionTotal + '份</span></div>' +
|
||||
'<span class="item-row__type-tag ' + typeTagCls + '">' + item.type + '</span>' +
|
||||
'<div class="item-row__status">' + labeledTag + '</div>' +
|
||||
'<div class="item-row__action">' + actionHtml + '</div>' +
|
||||
@@ -557,11 +522,8 @@
|
||||
'<div class="item-card__meta-item"><span class="item-card__meta-label">净菜类型:</span><span class="item-card__meta-value">' + (isMeal ? '—' : (item.cutSpec || '—')) + '</span></div>' +
|
||||
'</div>' +
|
||||
'<div class="item-card__data">' +
|
||||
'<div class="item-card__data-item"><span class="item-card__data-label">餐品:</span>' + mealDisplay + '</div>' +
|
||||
'<div class="item-card__data-item"><span class="item-card__data-label">每份用量:</span>' + perPackDisplay + '</div>' +
|
||||
'<div class="item-card__data-item"><span class="item-card__data-label">份数:</span><span class="item-card__data-value">' + item.packSize + '</span></div>' +
|
||||
'<div class="item-card__data-item"><span class="item-card__data-label">需:</span><span class="item-card__data-value">' + need + 'g</span></div>' +
|
||||
'<div class="item-card__data-item"><span class="item-card__data-label">已称:</span><span class="item-card__data-value">' + item.weighed + 'g</span></div>' +
|
||||
'<div class="item-card__data-item"><span class="item-card__data-label">单份重量:</span><span class="item-card__data-value">' + item.weightPerPack + 'g</span></div>' +
|
||||
'<div class="item-card__data-item"><span class="item-card__data-label">已称:</span><span class="item-card__data-value ' + (item.labeled ? 'item-card__data-value--done' : 'item-card__data-value--zero') + '">' + item.weighed + 'g</span></div>' +
|
||||
'</div>';
|
||||
|
||||
body.appendChild(row);
|
||||
@@ -626,7 +588,7 @@
|
||||
var r = aiResults[key];
|
||||
var card = document.createElement('div');
|
||||
card.className = 'candidate-card';
|
||||
card.onclick = function() { openWeightModal(r); };
|
||||
card.onclick = function() { confirmCandidateDirect(r); };
|
||||
card.innerHTML =
|
||||
'<div class="candidate-card__img">' + r.icon + '</div>' +
|
||||
'<div class="candidate-card__name">' + r.name + '</div>' +
|
||||
@@ -635,34 +597,12 @@
|
||||
});
|
||||
}
|
||||
|
||||
/* ---- 秤重确认弹窗 ---- */
|
||||
function openWeightModal(result) {
|
||||
pendingCandidate = result;
|
||||
document.getElementById('modalIcon').textContent = result.icon;
|
||||
document.getElementById('modalFoodName').textContent = result.name;
|
||||
document.getElementById('modalWeight').textContent = parseFloat(document.getElementById('scaleWeightValue').textContent).toFixed(1);
|
||||
document.getElementById('modalOverlay').classList.add('show');
|
||||
}
|
||||
|
||||
function refreshWeight() {
|
||||
var newWeight = parseFloat((Math.random() * 2000 + 200).toFixed(1));
|
||||
document.getElementById('modalWeight').textContent = newWeight.toFixed(1);
|
||||
document.getElementById('scaleWeightValue').textContent = newWeight.toFixed(2);
|
||||
showToast('重量已刷新:' + newWeight.toFixed(1) + 'g', 800);
|
||||
}
|
||||
|
||||
function closeModal() {
|
||||
pendingCandidate = null;
|
||||
document.getElementById('modalOverlay').classList.remove('show');
|
||||
}
|
||||
|
||||
function confirmWeight() {
|
||||
if (!pendingCandidate) return;
|
||||
document.getElementById('modalOverlay').classList.remove('show');
|
||||
|
||||
/* ---- 秤重直接确认(无弹窗,候选点击后直接读秤赋值) ---- */
|
||||
function confirmCandidateDirect(result) {
|
||||
/* 在待打印的净菜包中查找匹配项 */
|
||||
var matchedIdx = -1;
|
||||
for (var i = 0; i < allItems.length; i++) {
|
||||
if (allItems[i].type === '净菜包' && allItems[i].packName === pendingCandidate.name) {
|
||||
if (allItems[i].type === '净菜包' && !allItems[i].labeled && allItems[i].packName === result.name) {
|
||||
matchedIdx = i;
|
||||
break;
|
||||
}
|
||||
@@ -670,25 +610,25 @@
|
||||
|
||||
if (matchedIdx < 0) {
|
||||
showToast('未找到匹配的净菜包项', 1500, 'error');
|
||||
pendingCandidate = null;
|
||||
return;
|
||||
}
|
||||
|
||||
var modalWeight = parseFloat(document.getElementById('modalWeight').textContent) || 0;
|
||||
allItems[matchedIdx].weighed = modalWeight;
|
||||
/* 直接读取当前秤重赋值 */
|
||||
var scaleWeight = parseFloat(document.getElementById('scaleWeightValue').textContent) || 0;
|
||||
allItems[matchedIdx].weighed = scaleWeight;
|
||||
/* 秤重确认后自动打印 */
|
||||
allItems[matchedIdx].labeled = true;
|
||||
|
||||
document.getElementById('scaleWeightValue').textContent = allItems[matchedIdx].weighed.toFixed(2);
|
||||
document.getElementById('statusDot').className = 'status-dot status-dot--done';
|
||||
document.getElementById('statusText').textContent = '秤重确认: ' + pendingCandidate.name + ' — ' + modalWeight.toFixed(1) + 'g';
|
||||
document.getElementById('statusText').textContent = '秤重确认: ' + result.name + ' 第' + allItems[matchedIdx].portionIdx + '份 — ' + scaleWeight.toFixed(1) + 'g';
|
||||
|
||||
showToast('秤重完成: ' + pendingCandidate.name + ' ' + modalWeight.toFixed(1) + 'g', 2000, 'success');
|
||||
pendingCandidate = null;
|
||||
showToast('秤重完成: ' + result.name + ' 第' + allItems[matchedIdx].portionIdx + '份 ' + scaleWeight.toFixed(1) + 'g', 2000, 'success');
|
||||
|
||||
renderItemList();
|
||||
updateTaskStatus();
|
||||
|
||||
/* 延迟回到就绪态,推进到下一个待打印净菜包 */
|
||||
setTimeout(function() {
|
||||
state = 'idle';
|
||||
document.getElementById('statusDot').className = 'status-dot status-dot--ready';
|
||||
@@ -696,17 +636,38 @@
|
||||
document.getElementById('candidateList').innerHTML = '';
|
||||
document.getElementById('candidateEmpty').classList.remove('hide');
|
||||
document.getElementById('candidateTitle').textContent = '智能识别候选';
|
||||
document.getElementById('cameraOverlay').classList.add('show');
|
||||
|
||||
/* 查找下一个待打印的净菜包 */
|
||||
currentVegIdx = -1;
|
||||
for (var j = 0; j < allItems.length; j++) {
|
||||
if (allItems[j].type === '净菜包' && !allItems[j].labeled) {
|
||||
currentVegIdx = j;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (currentVegIdx >= 0) {
|
||||
document.getElementById('scaleWeightValue').textContent = '0.00';
|
||||
document.getElementById('cameraOverlay').classList.add('show');
|
||||
} else {
|
||||
document.getElementById('scaleWeightValue').textContent = '0.00';
|
||||
var hasPendingMeal = allItems.some(function(item) { return item.type === '餐品净菜包' && !item.labeled; });
|
||||
if (hasPendingMeal) {
|
||||
showToast('净菜包已全部打印,请继续打印餐品净菜包', 2500, 'success');
|
||||
} else {
|
||||
showToast('所有项目已打印完成', 2000, 'success');
|
||||
}
|
||||
}
|
||||
}, 2000);
|
||||
}
|
||||
|
||||
/* ---- 贴标完成 ---- */
|
||||
/* ---- 包装完成 ---- */
|
||||
function handleLabelDone() {
|
||||
if (!checkAllDone()) {
|
||||
showToast('还有项目未完成打印', 2000, 'error');
|
||||
return;
|
||||
}
|
||||
showToast('贴标完成,正在返回订单列表...', 1500, 'success');
|
||||
showToast('包装完成,正在返回订单列表...', 1500, 'success');
|
||||
setTimeout(function() {
|
||||
window.location.href = '01-orders.html?user=' + encodeURIComponent(userName) + (userId ? '&uid=' + userId : '');
|
||||
}, 1000);
|
||||
@@ -724,6 +685,44 @@
|
||||
showToast('已重新发起识别', 1000, 'success');
|
||||
}
|
||||
|
||||
/* ---- 搜索食材 ---- */
|
||||
function handleFoodSearchKey(event) {
|
||||
if (event.key !== 'Enter') return;
|
||||
var input = document.getElementById('foodSearchInput');
|
||||
var kw = input.value.trim();
|
||||
if (!kw) return;
|
||||
document.getElementById('cameraOverlay').classList.remove('show');
|
||||
var keys = Object.keys(aiResults);
|
||||
var results = [];
|
||||
for (var i = 0; i < keys.length; i++) {
|
||||
var r = aiResults[keys[i]];
|
||||
if (r.name.indexOf(kw) !== -1) {
|
||||
results.push({ key: keys[i], name: r.name, icon: r.icon, confidence: r.confidence });
|
||||
}
|
||||
}
|
||||
var list = document.getElementById('candidateList');
|
||||
var empty = document.getElementById('candidateEmpty');
|
||||
var title = document.getElementById('candidateTitle');
|
||||
if (results.length === 0) {
|
||||
list.innerHTML = '<div style="text-align:center;color:rgba(255,255,255,0.25);padding:12px 0;font-size:12px;grid-column:1/-1;">未找到匹配食材,请尝试其他关键词</div>';
|
||||
title.textContent = '搜索结果';
|
||||
empty.classList.add('hide');
|
||||
} else {
|
||||
title.textContent = '搜索结果 (' + results.length + ')';
|
||||
list.innerHTML = '';
|
||||
empty.classList.add('hide');
|
||||
results.forEach(function(r) {
|
||||
var card = document.createElement('div');
|
||||
card.className = 'candidate-card';
|
||||
card.onclick = function() { confirmCandidateDirect(r); };
|
||||
card.innerHTML =
|
||||
'<div class="candidate-card__img">' + r.icon + '</div>' +
|
||||
'<div class="candidate-card__name">' + r.name + '</div>';
|
||||
list.appendChild(card);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/* ---- 退出登录 ---- */
|
||||
function handleLogout() {
|
||||
window.location.href = '00-login.html';
|
||||
|
||||
@@ -248,29 +248,29 @@
|
||||
{
|
||||
orderNo: 'PO-20260625-001', orderType: 'internal', completeTime: '2026-06-25 11:15', operator: '刘九',
|
||||
mealPacks: [
|
||||
{ type: '净菜包', packName: '土豆丝', packSize: 3, packSpec: '500g', ingredients: [{ name: '土豆丝', weightPerPack: 500, weighed: 1500 }] },
|
||||
{ type: '净菜包', packName: '胡萝卜丝', packSize: 3, packSpec: '500g', ingredients: [{ name: '胡萝卜丝', weightPerPack: 500, weighed: 1500 }] },
|
||||
{ type: '净菜包', packName: '土豆', packSize: 3, packSpec: '500g', ingredients: [{ name: '土豆', weightPerPack: 500, weighed: 1500 }] },
|
||||
{ type: '净菜包', packName: '胡萝卜', packSize: 3, packSpec: '500g', ingredients: [{ name: '胡萝卜', weightPerPack: 500, weighed: 1500 }] },
|
||||
{ type: '餐品净菜包', packName: '宫保鸡丁套餐', packSize: 2, packSpec: '大份800g', ingredients: [{ name: '宫保鸡丁', weightPerPack: 800, weighed: 1600 }] }
|
||||
]
|
||||
},
|
||||
{
|
||||
orderNo: 'PO-20260625-002', orderType: 'external', completeTime: '2026-06-25 12:30', operator: '陈十',
|
||||
mealPacks: [
|
||||
{ type: '净菜包', packName: '白菜丝', packSize: 2, packSpec: '1000g', ingredients: [{ name: '白菜丝', weightPerPack: 1000, weighed: 2000 }] },
|
||||
{ type: '净菜包', packName: '白菜', packSize: 2, packSpec: '1000g', ingredients: [{ name: '白菜', weightPerPack: 1000, weighed: 2000 }] },
|
||||
{ type: '餐品净菜包', packName: '鱼香肉丝套餐', packSize: 2, packSpec: '大份800g', ingredients: [{ name: '鱼香肉丝', weightPerPack: 800, weighed: 1600 }] }
|
||||
]
|
||||
},
|
||||
{
|
||||
orderNo: 'PO-20260624-001', orderType: 'internal', completeTime: '2026-06-24 10:15', operator: '刘九',
|
||||
mealPacks: [
|
||||
{ type: '净菜包', packName: '黄瓜片', packSize: 3, packSpec: '500g', ingredients: [{ name: '黄瓜片', weightPerPack: 500, weighed: 1500 }] },
|
||||
{ type: '净菜包', packName: '黄瓜', packSize: 3, packSpec: '500g', ingredients: [{ name: '黄瓜', weightPerPack: 500, weighed: 1500 }] },
|
||||
{ type: '餐品净菜包', packName: '凉拌黄瓜套餐', packSize: 2, packSpec: '盒装', ingredients: [{ name: '凉拌黄瓜', weightPerPack: 600, weighed: 1200 }] }
|
||||
]
|
||||
},
|
||||
{
|
||||
orderNo: 'PO-20260624-002', orderType: 'external', completeTime: '2026-06-24 13:45', operator: '陈十',
|
||||
mealPacks: [
|
||||
{ type: '净菜包', packName: '芹菜段', packSize: 2, packSpec: '500g', ingredients: [{ name: '芹菜段', weightPerPack: 500, weighed: 1000 }] },
|
||||
{ type: '净菜包', packName: '芹菜', packSize: 2, packSpec: '500g', ingredients: [{ name: '芹菜', weightPerPack: 500, weighed: 1000 }] },
|
||||
{ type: '餐品净菜包', packName: '芹菜炒肉套餐', packSize: 3, packSpec: '大份800g', ingredients: [{ name: '芹菜炒肉', weightPerPack: 800, weighed: 2400 }] }
|
||||
]
|
||||
},
|
||||
|
||||
@@ -1,4 +1,28 @@
|
||||
# 净菜贴标秤 CHANGELOG
|
||||
# 净菜包装秤 CHANGELOG
|
||||
|
||||
## 2026-06-26 | 术语统一"贴标→包装" + 包装作业交互升级
|
||||
|
||||
### 术语统一
|
||||
- 全模块"净菜贴标秤"→"净菜包装秤"(页面标题、标签、按钮、导航条目、数据、注释)
|
||||
- "贴标"→"包装"(待贴标→待包装、已贴标→已包装、去贴标→去包装、贴标任务→包装任务、贴标清单→包装清单)
|
||||
- 员工角色:贴标车间→包装车间、贴标员→包装员
|
||||
- 净菜包名称简化:去丝/段/片后缀(土豆丝→土豆、白菜丝→白菜等)
|
||||
- 根 `index.html` SITE_MAP 同步更新
|
||||
|
||||
### 新增
|
||||
- `label-preview.html` — 标签预览页(展示打印标签样式)
|
||||
|
||||
### 包装作业页交互升级 (`02-labeling.html`)
|
||||
- 清单按 packSize 展开为单份("第N份/M份"),每份独立卡片
|
||||
- 移除秤重确认弹窗,点击候选食材直接读秤赋值并自动打印
|
||||
- 秤重完成一份后自动推进到下一个待打印净菜包
|
||||
- 新增搜索框:手动输入食材名称回车搜索,支持模糊匹配
|
||||
- 卡片展示简化:仅保留单份重量+已称,移除餐品/每份用量/份数/需字段
|
||||
|
||||
### 包装任务页 (`01-orders.html`)
|
||||
- 表头优化:打包份数→份数、所需总重→应称重量、已称→已称重量
|
||||
- 行展示按单份拆分("第N份/M份"),与包装作业页一致
|
||||
- 已包装Tab新增"重新打印"按钮
|
||||
|
||||
## 2026-06-26 | 包装历史页字段与显示逻辑对齐
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=1024, initial-scale=1.0">
|
||||
<title>净菜贴标秤 - 模块导航 | 蚁熊智能餐养平台</title>
|
||||
<title>净菜包装秤 - 模块导航 | 蚁熊智能餐养平台</title>
|
||||
<style>
|
||||
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||||
body {
|
||||
@@ -68,7 +68,7 @@
|
||||
<div class="device-frame">
|
||||
<div class="top-bar">
|
||||
<a class="back-btn" href="../index.html">◀ 返回餐厅终端</a>
|
||||
<span class="top-bar__title">净菜贴标秤</span>
|
||||
<span class="top-bar__title">净菜包装秤</span>
|
||||
<span class="top-bar__user" id="topUser">未登录</span>
|
||||
<button class="logout-btn" onclick="handleLogout()" style="display:none" id="logoutBtn">退出登录</button>
|
||||
</div>
|
||||
@@ -83,8 +83,8 @@
|
||||
<a class="menu-btn" id="btnOrders" onclick="handleMenu('01-orders.html')">
|
||||
<div class="menu-btn__icon menu-btn__icon--blue">📋</div>
|
||||
<div class="menu-btn__info">
|
||||
<div class="menu-btn__title">贴标任务</div>
|
||||
<div class="menu-btn__desc">查看待贴标/已贴标订单</div>
|
||||
<div class="menu-btn__title">包装任务</div>
|
||||
<div class="menu-btn__desc">查看待包装/已包装订单</div>
|
||||
</div>
|
||||
<span class="menu-btn__badge" id="taskBadge">0</span>
|
||||
<div class="menu-btn__arrow">›</div>
|
||||
@@ -93,8 +93,17 @@
|
||||
<a class="menu-btn" onclick="handleMenu('03-history.html')">
|
||||
<div class="menu-btn__icon menu-btn__icon--blue">📄</div>
|
||||
<div class="menu-btn__info">
|
||||
<div class="menu-btn__title">贴标历史</div>
|
||||
<div class="menu-btn__desc">查看历史贴标记录</div>
|
||||
<div class="menu-btn__title">包装历史</div>
|
||||
<div class="menu-btn__desc">查看历史包装记录</div>
|
||||
</div>
|
||||
<div class="menu-btn__arrow">›</div>
|
||||
</a>
|
||||
|
||||
<a class="menu-btn" onclick="handleMenu('label-preview.html')">
|
||||
<div class="menu-btn__icon menu-btn__icon--green">🏷️</div>
|
||||
<div class="menu-btn__info">
|
||||
<div class="menu-btn__title">标签预览</div>
|
||||
<div class="menu-btn__desc">预览订单/净菜/餐品净菜包三种标签</div>
|
||||
</div>
|
||||
<div class="menu-btn__arrow">›</div>
|
||||
</a>
|
||||
|
||||
@@ -0,0 +1,417 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=1024, initial-scale=1.0">
|
||||
<title>净菜包装秤 - 标签预览 | 蚁熊智能餐养平台</title>
|
||||
<style>
|
||||
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||||
body {
|
||||
font-family: -apple-system, "Microsoft YaHei", "PingFang SC", sans-serif;
|
||||
background: #05080f; color: #fff;
|
||||
min-height: 100vh; min-width: 1024px;
|
||||
display: flex; align-items: center; justify-content: center;
|
||||
padding: 20px; user-select: none;
|
||||
}
|
||||
/* PAD 设备外壳 — 4:3 横屏 */
|
||||
.device-frame {
|
||||
width: 1024px; height: 768px;
|
||||
background: #0e1326;
|
||||
border-radius: 24px;
|
||||
box-shadow: 0 24px 64px rgba(0,0,0,0.6), 0 0 0 1px rgba(255,255,255,0.04);
|
||||
overflow: hidden; position: relative;
|
||||
display: flex; flex-direction: column;
|
||||
}
|
||||
/* 顶部导航栏 */
|
||||
.top-bar { display: flex; align-items: center; height: 48px; background: #1a2b4a; padding: 0 20px; flex-shrink: 0; }
|
||||
.back-btn { font-size: 14px; cursor: pointer; color: rgba(255,255,255,0.7); text-decoration: none; transition: color 0.2s; margin-right: 12px; }
|
||||
.back-btn:hover { color: #fff; }
|
||||
.page-title { font-size: 15px; font-weight: 600; color: rgba(255,255,255,0.85); }
|
||||
.top-bar__spacer { flex: 1; }
|
||||
.user-info { font-size: 12px; color: rgba(255,255,255,0.5); display: flex; align-items: center; gap: 6px; }
|
||||
.user-info .avatar { width: 28px; height: 28px; border-radius: 50%; background: #4a90d9; display: flex; align-items: center; justify-content: center; font-size: 12px; color: #fff; }
|
||||
.logout-btn { margin-left: 10px; padding: 4px 10px; font-size: 11px; background: rgba(255,77,79,0.08); border: 1px solid rgba(255,77,79,0.2); border-radius: 5px; color: rgba(255,77,79,0.7); cursor: pointer; transition: all 0.2s; font-family: inherit; }
|
||||
.logout-btn:hover { background: rgba(255,77,79,0.18); color: #ff6b6d; border-color: rgba(255,77,79,0.4); }
|
||||
|
||||
/* Tab 切换栏 */
|
||||
.tab-bar { display: flex; gap: 0; padding: 12px 20px 0; flex-shrink: 0; }
|
||||
.tab-btn { padding: 8px 20px; border: 1px solid rgba(255,255,255,0.08); background: transparent; color: rgba(255,255,255,0.5); font-size: 13px; font-weight: 500; cursor: pointer; transition: all 0.2s; font-family: inherit; border-radius: 8px 8px 0 0; border-bottom: none; }
|
||||
.tab-btn:hover { color: rgba(255,255,255,0.8); background: rgba(255,255,255,0.03); }
|
||||
.tab-btn.active { color: #fff; border-color: rgba(255,255,255,0.12); }
|
||||
.tab-btn--blue.active { background: #1a2b4a; }
|
||||
.tab-btn--green.active { background: #1a2b4a; }
|
||||
.tab-btn--orange.active { background: #1a2b4a; }
|
||||
.tab-dot { display: inline-block; width: 8px; height: 8px; border-radius: 50%; margin-right: 6px; vertical-align: middle; position: relative; top: -1px; }
|
||||
.tab-dot--blue { background: #4a90d9; }
|
||||
.tab-dot--green { background: #52c41a; }
|
||||
.tab-dot--orange { background: #fa8c16; }
|
||||
|
||||
/* 主内容区 */
|
||||
.main-content { flex: 1; padding: 16px 20px; overflow-y: auto; scrollbar-width: none; display: flex; flex-direction: column; gap: 16px; }
|
||||
.main-content::-webkit-scrollbar { display: none; }
|
||||
|
||||
/* ====== 标签卡片(模拟热敏标签纸) ====== */
|
||||
.label-panel { display: none; flex-direction: column; gap: 16px; }
|
||||
.label-panel.active { display: flex; }
|
||||
|
||||
/* 单个标签 */
|
||||
.label-sticker {
|
||||
width: 100%; background: #fff; color: #1a1a2e; border-radius: 8px;
|
||||
overflow: hidden; box-shadow: 0 4px 16px rgba(0,0,0,0.3);
|
||||
display: flex; flex-direction: row;
|
||||
/* 模拟 80mm × 50mm 热敏标签比例 */
|
||||
min-height: 140px;
|
||||
}
|
||||
/* 标签主信息区 */
|
||||
.label-sticker__body { flex: 1; padding: 12px 14px; display: flex; flex-direction: column; gap: 4px; }
|
||||
/* 标签标题栏 */
|
||||
.label-sticker__title-bar {
|
||||
font-size: 13px; font-weight: 700; color: #fff; padding: 3px 10px; border-radius: 4px;
|
||||
display: inline-block; align-self: flex-start; letter-spacing: 2px;
|
||||
}
|
||||
.label-sticker__title-bar--blue { background: #4a90d9; }
|
||||
.label-sticker__title-bar--green { background: #52c41a; }
|
||||
.label-sticker__title-bar--orange { background: #fa8c16; }
|
||||
|
||||
/* 信息行 */
|
||||
.label-info { display: flex; flex-wrap: wrap; gap: 2px 16px; font-size: 11px; }
|
||||
.label-info__item { display: flex; align-items: center; gap: 3px; white-space: nowrap; }
|
||||
.label-info__label { color: #888; }
|
||||
.label-info__value { color: #1a1a2e; font-weight: 600; }
|
||||
|
||||
/* 订单标签 — 包装项明细表 */
|
||||
.label-detail-table { width: 100%; border-collapse: collapse; margin-top: 2px; font-size: 10px; }
|
||||
.label-detail-table th {
|
||||
background: #f0f4f8; color: #666; font-weight: 500; padding: 3px 6px;
|
||||
text-align: left; border-bottom: 1px solid #e0e4e8;
|
||||
}
|
||||
.label-detail-table td {
|
||||
padding: 3px 6px; border-bottom: 1px solid #f0f0f0; color: #333;
|
||||
}
|
||||
.label-detail-table .type-tag { display: inline-block; padding: 1px 5px; border-radius: 3px; font-size: 9px; font-weight: 500; }
|
||||
.type-tag--veg { background: #e6f7ff; color: #4a90d9; }
|
||||
.type-tag--meal { background: #fff7e6; color: #fa8c16; }
|
||||
|
||||
/* 总重量行 */
|
||||
.label-total { font-size: 11px; font-weight: 700; color: #1a1a2e; margin-top: 2px; }
|
||||
|
||||
/* 保质期三字段 */
|
||||
.label-shelf { display: flex; gap: 12px; margin-top: 2px; }
|
||||
.label-shelf__item { display: flex; flex-direction: column; align-items: center; padding: 2px 8px; background: #f5f5f5; border-radius: 4px; }
|
||||
.label-shelf__label { font-size: 9px; color: #999; }
|
||||
.label-shelf__value { font-size: 11px; font-weight: 700; color: #333; }
|
||||
|
||||
/* 打印按钮 */
|
||||
.action-bar { display: flex; gap: 10px; justify-content: center; flex-shrink: 0; padding: 0 20px 16px; }
|
||||
.print-btn {
|
||||
padding: 10px 32px; border: none; border-radius: 8px; font-size: 14px; font-weight: 600;
|
||||
cursor: pointer; transition: all 0.2s; font-family: inherit; color: #fff;
|
||||
}
|
||||
.print-btn--blue { background: #4a90d9; }
|
||||
.print-btn--blue:hover { background: #3a7bc8; box-shadow: 0 4px 14px rgba(74,144,217,0.35); }
|
||||
.print-btn--green { background: #52c41a; }
|
||||
.print-btn--green:hover { background: #45a818; box-shadow: 0 4px 14px rgba(82,196,26,0.35); }
|
||||
.print-btn--orange { background: #fa8c16; }
|
||||
.print-btn--orange:hover { background: #e07b10; box-shadow: 0 4px 14px rgba(250,140,22,0.35); }
|
||||
.print-btn:active { transform: scale(0.97); }
|
||||
.print-all-btn { padding: 10px 24px; border: 1px solid rgba(255,255,255,0.15); border-radius: 8px; font-size: 13px; font-weight: 500; cursor: pointer; transition: all 0.2s; font-family: inherit; background: rgba(255,255,255,0.04); color: rgba(255,255,255,0.6); }
|
||||
.print-all-btn:hover { background: rgba(255,255,255,0.08); color: #fff; border-color: rgba(255,255,255,0.3); }
|
||||
|
||||
/* Toast */
|
||||
.toast { position: fixed; top: 60px; left: 50%; transform: translateX(-50%) translateY(-20px); background: rgba(0,0,0,0.85); color: #fff; padding: 12px 28px; border-radius: 8px; font-size: 13px; z-index: 1000; opacity: 0; visibility: hidden; transition: opacity 0.3s, transform 0.3s, visibility 0.3s; white-space: nowrap; pointer-events: none; }
|
||||
.toast.show { opacity: 1; visibility: visible; transform: translateX(-50%) translateY(0); }
|
||||
.toast--success { background: rgba(82,196,26,0.92); }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div class="device-frame">
|
||||
<!-- 顶部导航 -->
|
||||
<div class="top-bar">
|
||||
<a class="back-btn" id="backBtn" href="javascript:void(0)">◀ 返回</a>
|
||||
<span class="page-title">标签预览</span>
|
||||
<span class="top-bar__spacer"></span>
|
||||
<div class="user-info">
|
||||
<div class="avatar" id="userAvatar">--</div>
|
||||
<span id="topUser">--</span>
|
||||
<button class="logout-btn" onclick="handleLogout()">退出</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Tab 切换 -->
|
||||
<div class="tab-bar">
|
||||
<button class="tab-btn tab-btn--blue active" data-tab="order" onclick="switchTab('order')">
|
||||
<span class="tab-dot tab-dot--blue"></span>订单标签
|
||||
</button>
|
||||
<button class="tab-btn tab-btn--green" data-tab="veg" onclick="switchTab('veg')">
|
||||
<span class="tab-dot tab-dot--green"></span>净菜标签
|
||||
</button>
|
||||
<button class="tab-btn tab-btn--orange" data-tab="meal" onclick="switchTab('meal')">
|
||||
<span class="tab-dot tab-dot--orange"></span>餐品净菜包标签
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- 主内容 -->
|
||||
<div class="main-content" id="mainContent">
|
||||
<!-- 订单标签面板 -->
|
||||
<div class="label-panel active" id="panelOrder"></div>
|
||||
<!-- 净菜标签面板 -->
|
||||
<div class="label-panel" id="panelVeg"></div>
|
||||
<!-- 餐品净菜包标签面板 -->
|
||||
<div class="label-panel" id="panelMeal"></div>
|
||||
</div>
|
||||
|
||||
<!-- 操作栏 -->
|
||||
<div class="action-bar" id="actionBar">
|
||||
<button class="print-all-btn" onclick="handlePrintAll()">🖨️ 全部打印</button>
|
||||
<button class="print-btn print-btn--blue" id="printBtn" onclick="handlePrintCurrent()">🖨️ 打印当前标签</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Toast -->
|
||||
<div class="toast" id="toast"></div>
|
||||
|
||||
<script>
|
||||
/* ---- 工具函数 ---- */
|
||||
function getUrlParam(name) {
|
||||
var reg = new RegExp('(^|&)' + name + '=([^&]*)(&|$)', 'i');
|
||||
var r = window.location.search.substr(1).match(reg);
|
||||
if (r !== null) return decodeURIComponent(r[2]);
|
||||
return null;
|
||||
}
|
||||
|
||||
var userName = getUrlParam('user') || '刘九';
|
||||
var userId = getUrlParam('uid') || '';
|
||||
document.getElementById('topUser').textContent = userName;
|
||||
document.getElementById('userAvatar').textContent = userName.charAt(0);
|
||||
|
||||
/* ---- Mock 数据 ---- */
|
||||
var mockData = {
|
||||
orderNo: 'PO-20260625-001',
|
||||
orderType: 'internal',
|
||||
packDate: '2026-06-25',
|
||||
/* 净菜包:食材名 + 净菜类型 */
|
||||
vegPacks: [
|
||||
{ type: '净菜包', name: '土豆', cutSpec: '20mm×1mm×1mm · 细丝 · 平刀', packSpec: '500g', portions: 3, shelfLife: '3天', storageTemp: '0~4℃ 冷藏', expiryDate: '2026-06-28' },
|
||||
{ type: '净菜包', name: '胡萝卜', cutSpec: '20mm×1mm×1mm · 细丝 · 平刀', packSpec: '500g', portions: 3, shelfLife: '3天', storageTemp: '0~4℃ 冷藏', expiryDate: '2026-06-28' }
|
||||
],
|
||||
/* 餐品净菜包 */
|
||||
mealPacks: [
|
||||
{ type: '餐品净菜包', name: '宫保鸡丁套餐', packSpec: '大份800g', portions: 2, shelfLife: '2天', storageTemp: '0~4℃ 冷藏', expiryDate: '2026-06-27' }
|
||||
]
|
||||
};
|
||||
|
||||
/* 计算总重量 */
|
||||
function calcTotalWeight() {
|
||||
var total = 0;
|
||||
mockData.vegPacks.forEach(function(v) {
|
||||
var w = parseInt(v.packSpec) || 0;
|
||||
total += w * v.portions;
|
||||
});
|
||||
mockData.mealPacks.forEach(function(m) {
|
||||
var specMatch = m.packSpec.match(/(\d+)g/);
|
||||
var w = specMatch ? parseInt(specMatch[1]) : 0;
|
||||
total += w * m.portions;
|
||||
});
|
||||
return total;
|
||||
}
|
||||
|
||||
/* ---- 渲染订单标签 ---- */
|
||||
function renderOrderLabels() {
|
||||
var panel = document.getElementById('panelOrder');
|
||||
var orderTypeLabel = mockData.orderType === 'internal' ? '内供订单' : '外售订单';
|
||||
var totalWeight = calcTotalWeight();
|
||||
|
||||
/* 包装项明细行 */
|
||||
var detailRows = '';
|
||||
mockData.vegPacks.forEach(function(v, vi) {
|
||||
detailRows += '<tr>'
|
||||
+ '<td>' + (vi + 1) + '</td>'
|
||||
+ '<td><span class="type-tag type-tag--veg">净菜包</span></td>'
|
||||
+ '<td>' + v.name + '</td>'
|
||||
+ '<td>' + v.cutSpec + '</td>'
|
||||
+ '<td>' + v.packSpec + '</td>'
|
||||
+ '<td>' + v.portions + '份</td>'
|
||||
+ '</tr>';
|
||||
});
|
||||
mockData.mealPacks.forEach(function(m, mi) {
|
||||
detailRows += '<tr>'
|
||||
+ '<td>' + (mockData.vegPacks.length + mi + 1) + '</td>'
|
||||
+ '<td><span class="type-tag type-tag--meal">餐品净菜包</span></td>'
|
||||
+ '<td>' + m.name + '</td>'
|
||||
+ '<td>—</td>'
|
||||
+ '<td>' + m.packSpec + '</td>'
|
||||
+ '<td>' + m.portions + '份</td>'
|
||||
+ '</tr>';
|
||||
});
|
||||
|
||||
var html = ''
|
||||
+ '<div class="label-sticker">'
|
||||
+ '<div class="label-sticker__body">'
|
||||
+ '<span class="label-sticker__title-bar label-sticker__title-bar--blue">订单标签</span>'
|
||||
+ '<div class="label-info" style="margin-top:4px">'
|
||||
+ '<div class="label-info__item"><span class="label-info__label">订单号:</span><span class="label-info__value">' + mockData.orderNo + '</span></div>'
|
||||
+ '<div class="label-info__item"><span class="label-info__label">订单类型:</span><span class="label-info__value">' + orderTypeLabel + '</span></div>'
|
||||
+ '<div class="label-info__item"><span class="label-info__label">包装日期:</span><span class="label-info__value">' + mockData.packDate + '</span></div>'
|
||||
+ '</div>'
|
||||
+ '<table class="label-detail-table">'
|
||||
+ '<thead><tr><th>#</th><th>类型</th><th>名称</th><th>净菜类型</th><th>包装规格</th><th>份数</th></tr></thead>'
|
||||
+ '<tbody>' + detailRows + '</tbody>'
|
||||
+ '</table>'
|
||||
+ '<div class="label-total">总重量:' + totalWeight + 'g</div>'
|
||||
+ '</div>'
|
||||
+ '</div>';
|
||||
|
||||
panel.innerHTML = html;
|
||||
}
|
||||
|
||||
/* ---- 渲染净菜标签 ---- */
|
||||
function renderVegLabels() {
|
||||
var panel = document.getElementById('panelVeg');
|
||||
var html = '';
|
||||
|
||||
mockData.vegPacks.forEach(function(v) {
|
||||
for (var p = 0; p < v.portions; p++) {
|
||||
var code = mockData.orderNo + '-V' + v.name.charAt(0) + (p + 1);
|
||||
html += ''
|
||||
+ '<div class="label-sticker">'
|
||||
+ '<div class="label-sticker__body">'
|
||||
+ '<span class="label-sticker__title-bar label-sticker__title-bar--green">净菜标签</span>'
|
||||
+ '<div class="label-info" style="margin-top:4px">'
|
||||
+ '<div class="label-info__item"><span class="label-info__label">净菜名称:</span><span class="label-info__value">' + v.name + '</span></div>'
|
||||
+ '<div class="label-info__item"><span class="label-info__label">净菜类型:</span><span class="label-info__value">' + v.cutSpec + '</span></div>'
|
||||
+ '</div>'
|
||||
+ '<div class="label-info">'
|
||||
+ '<div class="label-info__item"><span class="label-info__label">包装规格:</span><span class="label-info__value">' + v.packSpec + '</span></div>'
|
||||
+ '<div class="label-info__item"><span class="label-info__label">包装日期:</span><span class="label-info__value">' + mockData.packDate + '</span></div>'
|
||||
+ '<div class="label-info__item"><span class="label-info__label">订单号:</span><span class="label-info__value">' + mockData.orderNo + '</span></div>'
|
||||
+ '</div>'
|
||||
+ '<div class="label-shelf">'
|
||||
+ '<div class="label-shelf__item"><span class="label-shelf__label">保质期</span><span class="label-shelf__value">' + v.shelfLife + '</span></div>'
|
||||
+ '<div class="label-shelf__item"><span class="label-shelf__label">存放温度</span><span class="label-shelf__value">' + v.storageTemp + '</span></div>'
|
||||
+ '<div class="label-shelf__item"><span class="label-shelf__label">保质期至</span><span class="label-shelf__value">' + v.expiryDate + '</span></div>'
|
||||
+ '</div>'
|
||||
+ '</div>'
|
||||
+ '</div>';
|
||||
}
|
||||
});
|
||||
|
||||
panel.innerHTML = html;
|
||||
}
|
||||
|
||||
/* ---- 渲染餐品净菜包标签 ---- */
|
||||
function renderMealLabels() {
|
||||
var panel = document.getElementById('panelMeal');
|
||||
var html = '';
|
||||
|
||||
mockData.mealPacks.forEach(function(m) {
|
||||
for (var p = 0; p < m.portions; p++) {
|
||||
var code = mockData.orderNo + '-M' + (p + 1);
|
||||
html += ''
|
||||
+ '<div class="label-sticker">'
|
||||
+ '<div class="label-sticker__body">'
|
||||
+ '<span class="label-sticker__title-bar label-sticker__title-bar--orange">餐品净菜包标签</span>'
|
||||
+ '<div class="label-info" style="margin-top:4px">'
|
||||
+ '<div class="label-info__item"><span class="label-info__label">餐品名称:</span><span class="label-info__value">' + m.name + '</span></div>'
|
||||
+ '</div>'
|
||||
+ '<div class="label-info">'
|
||||
+ '<div class="label-info__item"><span class="label-info__label">包装规格:</span><span class="label-info__value">' + m.packSpec + '</span></div>'
|
||||
+ '<div class="label-info__item"><span class="label-info__label">包装日期:</span><span class="label-info__value">' + mockData.packDate + '</span></div>'
|
||||
+ '<div class="label-info__item"><span class="label-info__label">订单号:</span><span class="label-info__value">' + mockData.orderNo + '</span></div>'
|
||||
+ '</div>'
|
||||
+ '<div class="label-shelf">'
|
||||
+ '<div class="label-shelf__item"><span class="label-shelf__label">保质期</span><span class="label-shelf__value">' + m.shelfLife + '</span></div>'
|
||||
+ '<div class="label-shelf__item"><span class="label-shelf__label">存放温度</span><span class="label-shelf__value">' + m.storageTemp + '</span></div>'
|
||||
+ '<div class="label-shelf__item"><span class="label-shelf__label">保质期至</span><span class="label-shelf__value">' + m.expiryDate + '</span></div>'
|
||||
+ '</div>'
|
||||
+ '</div>'
|
||||
+ '</div>';
|
||||
}
|
||||
});
|
||||
|
||||
panel.innerHTML = html;
|
||||
}
|
||||
|
||||
/* ---- Tab 切换 ---- */
|
||||
var currentTab = 'order';
|
||||
function switchTab(tab) {
|
||||
currentTab = tab;
|
||||
document.querySelectorAll('.tab-btn').forEach(function(b) { b.classList.remove('active'); });
|
||||
document.querySelector('.tab-btn[data-tab="' + tab + '"]').classList.add('active');
|
||||
document.querySelectorAll('.label-panel').forEach(function(p) { p.classList.remove('active'); });
|
||||
if (tab === 'order') {
|
||||
document.getElementById('panelOrder').classList.add('active');
|
||||
} else if (tab === 'veg') {
|
||||
document.getElementById('panelVeg').classList.add('active');
|
||||
} else if (tab === 'meal') {
|
||||
document.getElementById('panelMeal').classList.add('active');
|
||||
}
|
||||
/* 更新打印按钮颜色 */
|
||||
var btn = document.getElementById('printBtn');
|
||||
btn.className = 'print-btn';
|
||||
if (tab === 'order') btn.classList.add('print-btn--blue');
|
||||
else if (tab === 'veg') btn.classList.add('print-btn--green');
|
||||
else if (tab === 'meal') btn.classList.add('print-btn--orange');
|
||||
}
|
||||
|
||||
/* ---- 打印当前标签 ---- */
|
||||
function handlePrintCurrent() {
|
||||
var labels = [];
|
||||
if (currentTab === 'order') labels.push('订单标签');
|
||||
else if (currentTab === 'veg') {
|
||||
mockData.vegPacks.forEach(function(v) {
|
||||
for (var p = 0; p < v.portions; p++) { labels.push('净菜标签 — ' + v.name); }
|
||||
});
|
||||
} else if (currentTab === 'meal') {
|
||||
mockData.mealPacks.forEach(function(m) {
|
||||
for (var p = 0; p < m.portions; p++) { labels.push('餐品净菜包标签 — ' + m.name); }
|
||||
});
|
||||
}
|
||||
showToast('已发送打印指令:' + labels.length + ' 张标签', 2000, 'success');
|
||||
}
|
||||
|
||||
/* ---- 全部打印 ---- */
|
||||
function handlePrintAll() {
|
||||
var total = 1; /* 订单标签 1 张 */
|
||||
mockData.vegPacks.forEach(function(v) { total += v.portions; });
|
||||
mockData.mealPacks.forEach(function(m) { total += m.portions; });
|
||||
showToast('已发送全部打印指令:共 ' + total + ' 张标签', 2500, 'success');
|
||||
}
|
||||
|
||||
/* ---- 退出登录 ---- */
|
||||
function handleLogout() {
|
||||
window.location.href = '00-login.html';
|
||||
}
|
||||
|
||||
/* ---- Toast ---- */
|
||||
function showToast(msg, duration, type) {
|
||||
var el = document.getElementById('toast');
|
||||
el.textContent = msg;
|
||||
el.className = 'toast';
|
||||
if (type) el.classList.add('toast--' + type);
|
||||
el.classList.add('show');
|
||||
clearTimeout(el._timer);
|
||||
el._timer = setTimeout(function() { el.classList.remove('show'); }, duration || 2000);
|
||||
}
|
||||
|
||||
/* ---- 返回按钮 ---- */
|
||||
(function() {
|
||||
var backBtn = document.getElementById('backBtn');
|
||||
if (backBtn) {
|
||||
var params = new URLSearchParams(window.location.search);
|
||||
var referer = params.get('referer');
|
||||
if (referer) {
|
||||
backBtn.href = referer;
|
||||
} else {
|
||||
backBtn.href = '02-labeling.html?user=' + encodeURIComponent(userName) + (userId ? '&uid=' + userId : '');
|
||||
}
|
||||
}
|
||||
})();
|
||||
|
||||
/* ---- 初始化 ---- */
|
||||
renderOrderLabels();
|
||||
renderVegLabels();
|
||||
renderMealLabels();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -368,33 +368,33 @@
|
||||
<script>
|
||||
// ---- 模拟数据(累计模式) ----
|
||||
var mockFoods = [
|
||||
{ name: '土豆丝', size: '35mm*1mm*1mm', shape: '长条', blade: '平刀', target: 5.0, processed: 3.2, arrivalTime: '2026-06-17 08:30', icon: '\u{1F954}' },
|
||||
{ name: '胡萝卜丝', size: '20mm*1mm*1mm', shape: '细丝', blade: '平刀', target: 2.0, processed: 1.5, arrivalTime: '2026-06-17 09:15', icon: '\u{1F955}' },
|
||||
{ name: '黄瓜片', size: '30mm*30mm*3mm', shape: '圆片', blade: '平刀', target: 4.0, processed: 2.8, arrivalTime: '2026-06-17 10:00', icon: '\u{1F952}' }
|
||||
{ name: '土豆', size: '35mm*1mm*1mm', shape: '长条', blade: '平刀', target: 5.0, processed: 3.2, arrivalTime: '2026-06-17 08:30', icon: '\u{1F954}' },
|
||||
{ name: '胡萝卜', size: '20mm*1mm*1mm', shape: '细丝', blade: '平刀', target: 2.0, processed: 1.5, arrivalTime: '2026-06-17 09:15', icon: '\u{1F955}' },
|
||||
{ name: '黄瓜', size: '30mm*30mm*3mm', shape: '圆片', blade: '平刀', target: 4.0, processed: 2.8, arrivalTime: '2026-06-17 10:00', icon: '\u{1F952}' }
|
||||
];
|
||||
|
||||
// 净菜食材数据库(供搜索用)
|
||||
var foodDatabase = [
|
||||
{ name: '土豆丝', size: '35mm*1mm*1mm', shape: '长条', blade: '平刀', arrivalTime: '2026-06-17 08:30', icon: '\u{1F954}' },
|
||||
{ name: '土豆块', size: '20mm*20mm*20mm', shape: '方丁', blade: '平刀', arrivalTime: '2026-06-17 08:30', icon: '\u{1F954}' },
|
||||
{ name: '土豆片', size: '30mm*30mm*3mm', shape: '圆片', blade: '平刀', arrivalTime: '2026-06-17 08:30', icon: '\u{1F954}' },
|
||||
{ name: '胡萝卜丝', size: '20mm*1mm*1mm', shape: '细丝', blade: '平刀', arrivalTime: '2026-06-17 09:15', icon: '\u{1F955}' },
|
||||
{ name: '胡萝卜片', size: '25mm*25mm*2mm', shape: '圆片', blade: '平刀', arrivalTime: '2026-06-17 09:15', icon: '\u{1F955}' },
|
||||
{ name: '黄瓜片', size: '30mm*30mm*3mm', shape: '圆片', blade: '平刀', arrivalTime: '2026-06-17 10:00', icon: '\u{1F952}' },
|
||||
{ name: '黄瓜条', size: '40mm*8mm*8mm', shape: '长条', blade: '平刀', arrivalTime: '2026-06-17 10:00', icon: '\u{1F952}' },
|
||||
{ name: '大白菜段', size: '50mm*30mm*30mm', shape: '宽段', blade: '平刀', arrivalTime: '2026-06-17 10:30', icon: '\u{1F96C}' },
|
||||
{ name: '大白菜丝', size: '30mm*2mm*2mm', shape: '细丝', blade: '平刀', arrivalTime: '2026-06-17 10:30', icon: '\u{1F96C}' },
|
||||
{ name: '西红柿块', size: '25mm*25mm*20mm', shape: '楔形块', blade: '平刀', arrivalTime: '2026-06-17 11:00', icon: '\u{1F345}' },
|
||||
{ name: '西红柿片', size: '30mm*30mm*5mm', shape: '圆片', blade: '平刀', arrivalTime: '2026-06-17 11:00', icon: '\u{1F345}' },
|
||||
{ name: '青椒丝', size: '30mm*3mm*3mm', shape: '长条', blade: '平刀', arrivalTime: '2026-06-17 11:30', icon: '\u{1FAD1}' },
|
||||
{ name: '青椒块', size: '20mm*20mm*20mm', shape: '方丁', blade: '平刀', arrivalTime: '2026-06-17 11:30', icon: '\u{1FAD1}' },
|
||||
{ name: '洋葱丝', size: '30mm*2mm*2mm', shape: '细丝', blade: '平刀', arrivalTime: '2026-06-17 13:00', icon: '\u{1F9C5}' },
|
||||
{ name: '洋葱块', size: '15mm*15mm*15mm', shape: '方丁', blade: '平刀', arrivalTime: '2026-06-17 13:00', icon: '\u{1F9C5}' },
|
||||
{ name: '芹菜段', size: '40mm*10mm*10mm', shape: '宽段', blade: '平刀', arrivalTime: '2026-06-17 13:30', icon: '\u{1F96C}' },
|
||||
{ name: '芹菜丝', size: '30mm*2mm*2mm', shape: '细丝', blade: '平刀', arrivalTime: '2026-06-17 13:30', icon: '\u{1F96C}' },
|
||||
{ name: '莲藕片', size: '35mm*35mm*3mm', shape: '圆片', blade: '平刀', arrivalTime: '2026-06-17 14:00', icon: '\u{1FAD1}' },
|
||||
{ name: '莴笋丝', size: '30mm*2mm*2mm', shape: '细丝', blade: '平刀', arrivalTime: '2026-06-17 14:00', icon: '\u{1F96C}' },
|
||||
{ name: '豆角段', size: '40mm*10mm*10mm', shape: '宽段', blade: '平刀', arrivalTime: '2026-06-17 14:30', icon: '\u{1FAD8}' }
|
||||
{ name: '土豆', size: '35mm*1mm*1mm', shape: '长条', blade: '平刀', arrivalTime: '2026-06-17 08:30', icon: '\u{1F954}' },
|
||||
{ name: '土豆', size: '20mm*20mm*20mm', shape: '方丁', blade: '平刀', arrivalTime: '2026-06-17 08:30', icon: '\u{1F954}' },
|
||||
{ name: '土豆', size: '30mm*30mm*3mm', shape: '圆片', blade: '平刀', arrivalTime: '2026-06-17 08:30', icon: '\u{1F954}' },
|
||||
{ name: '胡萝卜', size: '20mm*1mm*1mm', shape: '细丝', blade: '平刀', arrivalTime: '2026-06-17 09:15', icon: '\u{1F955}' },
|
||||
{ name: '胡萝卜', size: '25mm*25mm*2mm', shape: '圆片', blade: '平刀', arrivalTime: '2026-06-17 09:15', icon: '\u{1F955}' },
|
||||
{ name: '黄瓜', size: '30mm*30mm*3mm', shape: '圆片', blade: '平刀', arrivalTime: '2026-06-17 10:00', icon: '\u{1F952}' },
|
||||
{ name: '黄瓜', size: '40mm*8mm*8mm', shape: '长条', blade: '平刀', arrivalTime: '2026-06-17 10:00', icon: '\u{1F952}' },
|
||||
{ name: '大白菜', size: '50mm*30mm*30mm', shape: '宽段', blade: '平刀', arrivalTime: '2026-06-17 10:30', icon: '\u{1F96C}' },
|
||||
{ name: '大白菜', size: '30mm*2mm*2mm', shape: '细丝', blade: '平刀', arrivalTime: '2026-06-17 10:30', icon: '\u{1F96C}' },
|
||||
{ name: '西红柿', size: '25mm*25mm*20mm', shape: '楔形块', blade: '平刀', arrivalTime: '2026-06-17 11:00', icon: '\u{1F345}' },
|
||||
{ name: '西红柿', size: '30mm*30mm*5mm', shape: '圆片', blade: '平刀', arrivalTime: '2026-06-17 11:00', icon: '\u{1F345}' },
|
||||
{ name: '青椒', size: '30mm*3mm*3mm', shape: '长条', blade: '平刀', arrivalTime: '2026-06-17 11:30', icon: '\u{1FAD1}' },
|
||||
{ name: '青椒', size: '20mm*20mm*20mm', shape: '方丁', blade: '平刀', arrivalTime: '2026-06-17 11:30', icon: '\u{1FAD1}' },
|
||||
{ name: '洋葱', size: '30mm*2mm*2mm', shape: '细丝', blade: '平刀', arrivalTime: '2026-06-17 13:00', icon: '\u{1F9C5}' },
|
||||
{ name: '洋葱', size: '15mm*15mm*15mm', shape: '方丁', blade: '平刀', arrivalTime: '2026-06-17 13:00', icon: '\u{1F9C5}' },
|
||||
{ name: '芹菜', size: '40mm*10mm*10mm', shape: '宽段', blade: '平刀', arrivalTime: '2026-06-17 13:30', icon: '\u{1F96C}' },
|
||||
{ name: '芹菜', size: '30mm*2mm*2mm', shape: '细丝', blade: '平刀', arrivalTime: '2026-06-17 13:30', icon: '\u{1F96C}' },
|
||||
{ name: '莲藕', size: '35mm*35mm*3mm', shape: '圆片', blade: '平刀', arrivalTime: '2026-06-17 14:00', icon: '\u{1FAD1}' },
|
||||
{ name: '莴笋', size: '30mm*2mm*2mm', shape: '细丝', blade: '平刀', arrivalTime: '2026-06-17 14:00', icon: '\u{1F96C}' },
|
||||
{ name: '豆角', size: '40mm*10mm*10mm', shape: '宽段', blade: '平刀', arrivalTime: '2026-06-17 14:30', icon: '\u{1FAD8}' }
|
||||
];
|
||||
|
||||
var currentUser = null;
|
||||
|
||||
@@ -196,8 +196,8 @@
|
||||
<a class="card" href="clean-veg-packaging-labeler/index.html">
|
||||
<span class="card__status card__status--done">已设计</span>
|
||||
<div class="card__icon">🏷️</div>
|
||||
<div class="card__name">净菜贴标秤</div>
|
||||
<div class="card__desc">接收配比完成订单,核对实物、贴标塑封</div>
|
||||
<div class="card__name">净菜包装秤</div>
|
||||
<div class="card__desc">接收配比完成订单,核对实物、包装塑封</div>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -61,14 +61,14 @@
|
||||
|
||||
/* 表格头(7列) */
|
||||
.item-table__head {
|
||||
display: grid; grid-template-columns: 1fr 0.6fr 0.5fr 0.65fr 0.6fr 50px 72px; gap: 8px;
|
||||
display: grid; grid-template-columns: 1fr 0.55fr 0.35fr 0.55fr 0.55fr 46px 66px; gap: 6px;
|
||||
padding: 6px 16px; background: rgba(0,0,0,0.2); font-size: 11px; color: rgba(255,255,255,0.4); font-weight: 500;
|
||||
}
|
||||
.item-table__body { display: flex; flex-direction: column; }
|
||||
|
||||
/* 餐品净菜包主行 */
|
||||
.item-parent-row {
|
||||
display: grid; grid-template-columns: 1fr 0.6fr 0.5fr 0.65fr 0.6fr 50px 72px; gap: 8px;
|
||||
display: grid; grid-template-columns: 1fr 0.55fr 0.35fr 0.55fr 0.55fr 46px 66px; gap: 6px;
|
||||
padding: 10px 16px; border-top: 1px solid rgba(255,255,255,0.04); align-items: center;
|
||||
background: rgba(74,144,217,0.06);
|
||||
margin-bottom: 4px; border-radius: 6px;
|
||||
@@ -94,7 +94,7 @@
|
||||
|
||||
/* 食材子行 */
|
||||
.item-child-row {
|
||||
display: grid; grid-template-columns: 1fr 0.6fr 0.5fr 0.65fr 0.6fr 50px 72px; gap: 8px;
|
||||
display: grid; grid-template-columns: 1fr 0.55fr 0.45fr 0.35fr 0.55fr 0.55fr 46px 66px; gap: 6px;
|
||||
padding: 8px 16px 8px 48px; border-top: 1px solid rgba(255,255,255,0.03);
|
||||
align-items: center; transition: background 0.2s;
|
||||
}
|
||||
@@ -184,9 +184,9 @@
|
||||
taskNo: 'T-001',
|
||||
mealPacks: [
|
||||
{ type: '餐品净菜包', packName: '宫保鸡丁套餐', packSize: 3, packSpec: '大份800g', ingredients: [
|
||||
{ name: '土豆丝', icon: '🥔', weightPerPack: 300, weighed: 0 },
|
||||
{ name: '胡萝卜丝', icon: '🥕', weightPerPack: 250, weighed: 0 },
|
||||
{ name: '黄瓜片', icon: '🥒', weightPerPack: 250, weighed: 0 }
|
||||
{ name: '土豆', icon: '🥔', weightPerPack: 300, weighed: 0 },
|
||||
{ name: '胡萝卜', icon: '🥕', weightPerPack: 250, weighed: 0 },
|
||||
{ name: '黄瓜', icon: '🥒', weightPerPack: 250, weighed: 0 }
|
||||
], seasonings: [
|
||||
{ name: '盐', cellIdx: 2, weightPerPack: 5, weighed: 0 },
|
||||
{ name: '白糖', cellIdx: 3, weightPerPack: 10, weighed: 0 },
|
||||
@@ -201,15 +201,15 @@
|
||||
taskNo: 'T-002',
|
||||
mealPacks: [
|
||||
{ type: '餐品净菜包', packName: '鱼香肉丝套餐', packSize: 2, packSpec: '大份800g', ingredients: [
|
||||
{ name: '白菜丝', icon: '🥬', weightPerPack: 400, weighed: 0 },
|
||||
{ name: '胡萝卜丝', icon: '🥕', weightPerPack: 400, weighed: 0 }
|
||||
{ name: '白菜', icon: '🥬', weightPerPack: 400, weighed: 0 },
|
||||
{ name: '胡萝卜', icon: '🥕', weightPerPack: 400, weighed: 0 }
|
||||
], seasonings: [
|
||||
{ name: '醋', cellIdx: 2, weightPerPack: 8, weighed: 0 },
|
||||
{ name: '料酒', cellIdx: 4, weightPerPack: 12, weighed: 0 }
|
||||
]},
|
||||
{ type: '餐品净菜包', packName: '番茄炒蛋套餐', packSize: 2, packSpec: '标准份500g', ingredients: [
|
||||
{ name: '番茄块', icon: '🍅', weightPerPack: 300, weighed: 0 },
|
||||
{ name: '鸡蛋液', icon: '🥚', weightPerPack: 200, weighed: 0 }
|
||||
{ name: '番茄', icon: '🍅', weightPerPack: 300, weighed: 0 },
|
||||
{ name: '鸡蛋', icon: '🥚', weightPerPack: 200, weighed: 0 }
|
||||
], seasonings: [
|
||||
{ name: '盐', cellIdx: 2, weightPerPack: 4, weighed: 0 },
|
||||
{ name: '白糖', cellIdx: 3, weightPerPack: 6, weighed: 0 }
|
||||
@@ -298,10 +298,10 @@
|
||||
'<span class="task-card__status"><span class="status-badge ' + (orderAllDone ? 'status-badge--done' : 'status-badge--pending') + '">' + (orderAllDone ? '已完成' : '待组配') + '</span></span>';
|
||||
taskCard.appendChild(header);
|
||||
|
||||
/* 表格头(7列:名称/包装规格/打包份数/所需总重/已称/状态/操作) */
|
||||
/* 表格头(7列:名称/包装规格/份数/应称重量/已称重量/状态/操作) */
|
||||
var tableHead = document.createElement('div');
|
||||
tableHead.className = 'item-table__head';
|
||||
tableHead.innerHTML = '<div>餐品净菜包名称</div><div style="text-align:center">包装规格</div><div style="text-align:center">打包份数</div><div style="text-align:right">所需总重</div><div style="text-align:right">已称</div><div style="text-align:center">状态</div><div style="text-align:center">操作</div>';
|
||||
tableHead.innerHTML = '<div>餐品净菜包名称</div><div style="text-align:center">包装规格</div><div style="text-align:center">份数</div><div style="text-align:right">应称重量</div><div style="text-align:right">已称重量</div><div style="text-align:center">状态</div><div style="text-align:center">操作</div>';
|
||||
taskCard.appendChild(tableHead);
|
||||
|
||||
/* 表格体 */
|
||||
@@ -326,21 +326,30 @@
|
||||
}
|
||||
var totalNeed = Math.round((ingNeed + seaNeed) * 100) / 100;
|
||||
var totalWeighed = Math.round((ingWeighed + seaWeighed) * 100) / 100;
|
||||
var weightClass = totalWeighed >= totalNeed ? 'parent-weight--done' : '';
|
||||
var perPackWeight = Math.round((totalNeed / pack.packSize) * 100) / 100;
|
||||
var perPackWeighed = Math.round((totalWeighed / pack.packSize) * 100) / 100;
|
||||
var packDone = !hasPendingPack(pack);
|
||||
/* 从包装规格中提取重量(如"大份800g"→800) */
|
||||
var specMatch = pack.packSpec && pack.packSpec.match(/(\d+)g/);
|
||||
var specWeight = specMatch ? parseInt(specMatch[1]) : perPackWeight;
|
||||
|
||||
/* 主行:餐品净菜包 + 独立组配按钮 */
|
||||
var parentRow = document.createElement('div');
|
||||
parentRow.className = 'item-parent-row';
|
||||
parentRow.innerHTML =
|
||||
'<div class="parent-name"><div class="parent-icon">📦</div><span class="parent-name__text">' + pack.packName + '</span></div>' +
|
||||
/* 按单份拆分,每份一行 */
|
||||
for (var p = 0; p < pack.packSize; p++) {
|
||||
var portionWeighed = packDone ? perPackWeighed : 0;
|
||||
var weightClass = packDone ? 'parent-weight--done' : '';
|
||||
|
||||
var parentRow = document.createElement('div');
|
||||
parentRow.className = 'item-parent-row';
|
||||
parentRow.innerHTML =
|
||||
'<div class="parent-name"><div class="parent-icon">📦</div><span class="parent-name__text">' + pack.packName + ' <span style="font-size:10px;color:rgba(255,255,255,0.4)">第' + (p + 1) + '份/' + pack.packSize + '份</span></span></div>' +
|
||||
'<div style="text-align:center"><span class="pack-spec-tag">' + (pack.packSpec || '—') + '</span></div>' +
|
||||
'<div style="text-align:center"><span class="pack-size-tag">' + pack.packSize + '</span></div>' +
|
||||
'<div class="parent-weight ' + weightClass + '">需 ' + totalNeed + ' 克</div>' +
|
||||
'<div class="parent-weight ' + weightClass + '">已 ' + totalWeighed + ' 克</div>' +
|
||||
'<div style="text-align:center"><span class="status-tag ' + (packStatus.text === '已完成' ? 'status-tag--done' : 'status-tag--wait') + '">' + packStatus.text + '</span></div>' +
|
||||
'<div style="text-align:center">' + (packDone ? '' : '<button class="task-card__pack-btn" onclick="handlePackWeigh(\'' + order.taskNo + '\',\'' + order.orderNo + '\',\'' + encodeURIComponent(pack.packName) + '\')">组配</button>') + '</div>';
|
||||
tableBody.appendChild(parentRow);
|
||||
'<div style="text-align:center"><span class="pack-size-tag">1</span></div>' +
|
||||
'<div class="parent-weight ' + weightClass + '">' + specWeight + ' 克</div>' +
|
||||
'<div class="parent-weight ' + weightClass + '">' + portionWeighed + ' 克</div>' +
|
||||
'<div style="text-align:center"><span class="status-tag ' + (packDone ? 'status-tag--done' : 'status-tag--wait') + '">' + (packDone ? '已完成' : '待组配') + '</span></div>' +
|
||||
'<div style="text-align:center">' + (packDone ? '' : '<button class="task-card__pack-btn" onclick="handlePackWeigh(\'' + order.taskNo + '\',\'' + order.orderNo + '\',\'' + encodeURIComponent(pack.packName) + '\',' + (p + 1) + ')">组配</button>') + '</div>';
|
||||
tableBody.appendChild(parentRow);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
@@ -371,8 +380,9 @@
|
||||
}
|
||||
|
||||
/* 进入餐品净菜包组配详情 */
|
||||
function handlePackWeigh(taskNo, orderNo, packName) {
|
||||
function handlePackWeigh(taskNo, orderNo, packName, portion) {
|
||||
var target = '02-weighing-packing.html?task=' + taskNo + '&order=' + encodeURIComponent(orderNo) + '&pack=' + packName;
|
||||
if (portion) target += '&portion=' + portion;
|
||||
if (userName) target += '&user=' + encodeURIComponent(userName);
|
||||
window.location.href = target;
|
||||
}
|
||||
|
||||
@@ -262,12 +262,12 @@
|
||||
.status-tag--done { background: rgba(82,196,26,0.15); color: #52c41a; }
|
||||
.status-tag--wait { background: rgba(255,255,255,0.06); color: rgba(255,255,255,0.35); }
|
||||
|
||||
/* 下一步按钮 */
|
||||
.next-btn-wrap { flex-shrink: 0; }
|
||||
/* 底部按钮区 */
|
||||
.next-btn-wrap { flex-shrink: 0; display: flex; gap: 10px; }
|
||||
.next-btn {
|
||||
width: 100%; padding: 12px 0; border: none; border-radius: 10px;
|
||||
flex: 1; padding: 12px 0; border: none; border-radius: 10px;
|
||||
font-size: 14px; font-weight: 600; cursor: pointer;
|
||||
transition: all 0.25s; text-align: center;
|
||||
transition: all 0.25s; text-align: center; font-family: inherit;
|
||||
background: #4a90d9; color: #fff;
|
||||
}
|
||||
.next-btn:hover { background: #3a7bc8; box-shadow: 0 4px 14px rgba(74,144,217,0.35); }
|
||||
@@ -276,47 +276,14 @@
|
||||
background: rgba(255,255,255,0.06); color: rgba(255,255,255,0.2);
|
||||
cursor: not-allowed; box-shadow: none;
|
||||
}
|
||||
|
||||
/* 组配确认弹窗(与净菜加工确认弹窗一致) */
|
||||
.modal-overlay {
|
||||
position: fixed; inset: 0; background: rgba(0,0,0,0.6); z-index: 1000;
|
||||
display: none; align-items: center; justify-content: center;
|
||||
.next-btn--secondary {
|
||||
background: rgba(82,196,26,0.12); color: #52c41a; border: 1px solid rgba(82,196,26,0.4);
|
||||
}
|
||||
.modal-overlay.show { display: flex; }
|
||||
.modal {
|
||||
background: #1a2b4a; border-radius: 14px; border: 1px solid rgba(255,255,255,0.08);
|
||||
padding: 24px 28px; width: 360px; display: flex; flex-direction: column; gap: 16px;
|
||||
.next-btn--secondary:hover { background: rgba(82,196,26,0.22); box-shadow: 0 4px 14px rgba(82,196,26,0.25); }
|
||||
.next-btn--secondary:disabled {
|
||||
background: rgba(255,255,255,0.06); color: rgba(255,255,255,0.2);
|
||||
border-color: transparent; cursor: not-allowed; box-shadow: none;
|
||||
}
|
||||
.modal__title { font-size: 15px; font-weight: 600; text-align: center; }
|
||||
.modal__food { display: flex; align-items: center; justify-content: center; gap: 8px; font-size: 14px; }
|
||||
.modal__food-icon { font-size: 24px; }
|
||||
.modal__label { font-size: 12px; color: rgba(255,255,255,0.5); text-align: center; }
|
||||
.modal__weight-row {
|
||||
display: flex; align-items: center; justify-content: center; gap: 10px;
|
||||
}
|
||||
.modal__weight-value {
|
||||
font-size: 28px; font-weight: 700; color: #4a90d9; line-height: 1;
|
||||
}
|
||||
.modal__weight-refresh {
|
||||
width: 28px; height: 28px; border-radius: 6px; border: 1px solid rgba(74,144,217,0.25);
|
||||
background: rgba(74,144,217,0.1); color: #4a90d9; font-size: 14px;
|
||||
cursor: pointer; transition: all 0.2s; display: flex; align-items: center; justify-content: center;
|
||||
}
|
||||
.modal__weight-refresh:hover { background: rgba(74,144,217,0.2); border-color: #4a90d9; }
|
||||
.modal__weight-unit { text-align: center; font-size: 12px; color: rgba(255,255,255,0.4); margin-top: -8px; }
|
||||
.modal__actions { display: flex; gap: 10px; }
|
||||
.modal__btn {
|
||||
flex: 1; padding: 10px 0; border-radius: 8px; font-size: 13px; font-weight: 600;
|
||||
cursor: pointer; transition: all 0.2s; font-family: inherit; border: none;
|
||||
}
|
||||
.modal__btn--cancel {
|
||||
background: rgba(255,255,255,0.08); color: rgba(255,255,255,0.6);
|
||||
}
|
||||
.modal__btn--cancel:hover { background: rgba(255,255,255,0.12); color: #fff; }
|
||||
.modal__btn--confirm {
|
||||
background: #4a90d9; color: #fff;
|
||||
}
|
||||
.modal__btn--confirm:hover { background: #5ba0e9; }
|
||||
|
||||
/* Toast 提示 */
|
||||
.toast {
|
||||
@@ -544,9 +511,10 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 下一步按钮 -->
|
||||
<!-- 底部按钮 -->
|
||||
<div class="next-btn-wrap">
|
||||
<button class="next-btn" id="btnNext" onclick="handlePackDone()">组配完成</button>
|
||||
<button class="next-btn next-btn--secondary" id="btnExit" onclick="handlePackDoneExit()">完成并退出</button>
|
||||
<button class="next-btn" id="btnContinue" onclick="handlePackDoneContinue()">完成并继续</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -555,27 +523,6 @@
|
||||
<!-- Toast 提示 -->
|
||||
<div class="toast" id="toast"></div>
|
||||
|
||||
<!-- 组配确认弹窗 -->
|
||||
<div class="modal-overlay" id="modalOverlay">
|
||||
<div class="modal">
|
||||
<div class="modal__title">组配确认</div>
|
||||
<div class="modal__food">
|
||||
<span class="modal__food-icon" id="modalIcon"></span>
|
||||
<span id="modalFoodName">--</span>
|
||||
</div>
|
||||
<div class="modal__label">本次加工重量</div>
|
||||
<div class="modal__weight-row">
|
||||
<span class="modal__weight-value" id="modalWeight">0.0</span>
|
||||
<button class="modal__weight-refresh" onclick="refreshWeight()" title="重新获取秤上重量">🔄</button>
|
||||
</div>
|
||||
<div class="modal__weight-unit">克</div>
|
||||
<div class="modal__actions">
|
||||
<button class="modal__btn modal__btn--cancel" onclick="closeModal()">取消</button>
|
||||
<button class="modal__btn modal__btn--confirm" onclick="confirmPack()">确认</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
/* ---- 工具函数 ---- */
|
||||
function getUrlParam(name) {
|
||||
@@ -601,9 +548,9 @@
|
||||
orderType: 'internal',
|
||||
mealPacks: [
|
||||
{ type: '餐品净菜包', packName: '宫保鸡丁套餐', packSize: 3, packSpec: '大份800g', ingredients: [
|
||||
{ name: '土豆丝', icon: '🥔', cutSpec: '20mm*1mm*1mm · 细丝 · 平刀', weightPerPack: 300, weighed: 0 },
|
||||
{ name: '胡萝卜丝', icon: '🥕', cutSpec: '20mm*1mm*1mm · 细丝 · 平刀', weightPerPack: 250, weighed: 0 },
|
||||
{ name: '黄瓜片', icon: '🥒', cutSpec: '30mm*30mm*3mm · 圆片 · 平刀', weightPerPack: 250, weighed: 0 }
|
||||
{ name: '土豆', icon: '🥔', cutSpec: '20mm*1mm*1mm · 细丝 · 平刀', weightPerPack: 300, weighed: 0 },
|
||||
{ name: '胡萝卜', icon: '🥕', cutSpec: '20mm*1mm*1mm · 细丝 · 平刀', weightPerPack: 250, weighed: 0 },
|
||||
{ name: '黄瓜', icon: '🥒', cutSpec: '30mm*30mm*3mm · 圆片 · 平刀', weightPerPack: 250, weighed: 0 }
|
||||
], seasonings: [
|
||||
{ name: '油', icon: '🛢', cellIdx: 0, weightPerPack: 50, weighed: 0 },
|
||||
{ name: '盐', icon: '🧂', cellIdx: 1, weightPerPack: 5, weighed: 0 },
|
||||
@@ -620,8 +567,8 @@
|
||||
orderType: 'external',
|
||||
mealPacks: [
|
||||
{ type: '餐品净菜包', packName: '鱼香肉丝套餐', packSize: 2, packSpec: '大份800g', ingredients: [
|
||||
{ name: '白菜丝', icon: '🥬', cutSpec: '50mm*30mm*30mm · 宽段 · 平刀', weightPerPack: 400, weighed: 0 },
|
||||
{ name: '胡萝卜丝', icon: '🥕', cutSpec: '20mm*1mm*1mm · 细丝 · 平刀', weightPerPack: 400, weighed: 0 }
|
||||
{ name: '白菜', icon: '🥬', cutSpec: '50mm*30mm*30mm · 宽段 · 平刀', weightPerPack: 400, weighed: 0 },
|
||||
{ name: '胡萝卜', icon: '🥕', cutSpec: '20mm*1mm*1mm · 细丝 · 平刀', weightPerPack: 400, weighed: 0 }
|
||||
], seasonings: [
|
||||
{ name: '油', icon: '🛢', cellIdx: 0, weightPerPack: 40, weighed: 0 },
|
||||
{ name: '盐', icon: '🧂', cellIdx: 1, weightPerPack: 4, weighed: 0 },
|
||||
@@ -696,14 +643,14 @@
|
||||
var seasoningConfig = loadSeasoningConfig();
|
||||
|
||||
var aiResults = {
|
||||
'potato': { name: '土豆丝', icon: '🥔', confidence: 97 },
|
||||
'carrot': { name: '胡萝卜丝', icon: '🥕', confidence: 96 },
|
||||
'cucumber': { name: '黄瓜片', icon: '🥒', confidence: 94 },
|
||||
'cabbage': { name: '白菜丝', icon: '🥬', confidence: 93 },
|
||||
'tomato': { name: '西红柿块', icon: '🍅', confidence: 95 },
|
||||
'potato': { name: '土豆', icon: '🥔', confidence: 97 },
|
||||
'carrot': { name: '胡萝卜', icon: '🥕', confidence: 96 },
|
||||
'cucumber': { name: '黄瓜', icon: '🥒', confidence: 94 },
|
||||
'cabbage': { name: '白菜', icon: '🥬', confidence: 93 },
|
||||
'tomato': { name: '西红柿', icon: '🍅', confidence: 95 },
|
||||
'egg': { name: '鸡蛋', icon: '🥚', confidence: 92 },
|
||||
'onion': { name: '紫洋葱丝', icon: '🧅', confidence: 91 },
|
||||
'green-onion': { name: '大葱丝', icon: '🧅', confidence: 90 }
|
||||
'onion': { name: '紫洋葱', icon: '🧅', confidence: 91 },
|
||||
'green-onion': { name: '大葱', icon: '🧅', confidence: 90 }
|
||||
};
|
||||
|
||||
/* ---- 状态变量 ---- */
|
||||
@@ -737,7 +684,7 @@
|
||||
cutSpec: ing.cutSpec,
|
||||
weightPerPack: ing.weightPerPack,
|
||||
weighed: ing.weighed,
|
||||
packSize: currentPack.packSize
|
||||
packSize: 1
|
||||
};
|
||||
});
|
||||
|
||||
@@ -748,7 +695,7 @@
|
||||
cellIdx: sea.cellIdx,
|
||||
weightPerPack: sea.weightPerPack,
|
||||
weighed: sea.weighed,
|
||||
packSize: currentPack.packSize
|
||||
packSize: 1
|
||||
};
|
||||
});
|
||||
|
||||
@@ -772,7 +719,7 @@
|
||||
var orderTypeCls = task.orderType === 'internal' ? 'order-type-tag--internal' : 'order-type-tag--external';
|
||||
orderTypeEl.innerHTML = '<span class="order-type-tag ' + orderTypeCls + '">' + orderTypeLabel + '</span>';
|
||||
document.getElementById('taskPackName').textContent = currentPack.packName + ' · ' + (currentPack.packSpec || '—');
|
||||
document.getElementById('taskTotalPacks').textContent = currentPack.packSize;
|
||||
document.getElementById('taskTotalPacks').textContent = '1';
|
||||
|
||||
/* 订单状态:主辅材+调料全部完成才算完成 */
|
||||
var ingAllDone = allIngredients.every(function(ing) {
|
||||
@@ -827,7 +774,6 @@
|
||||
'</div>' +
|
||||
'<div class="item-card__data">' +
|
||||
'<div class="item-card__data-item"><span class="item-card__data-label">每份</span><span class="item-card__data-value">' + ing.weightPerPack + 'g</span></div>' +
|
||||
'<div class="item-card__data-item"><span class="item-card__data-label">份数</span><span class="item-card__data-value">' + ing.packSize + '</span></div>' +
|
||||
'<div class="item-card__data-item"><span class="item-card__data-label">应称</span><span class="item-card__data-value">' + need + 'g</span></div>' +
|
||||
'<div class="item-card__data-item"><span class="item-card__data-label">已称</span><span class="item-card__data-value ' + actualClass + '">' + ing.weighed + 'g</span></div>' +
|
||||
'<div class="item-card__data-item"><span class="item-card__data-label">净菜类型</span><span class="item-card__data-value">' + (ing.cutSpec || '—') + '</span></div>' +
|
||||
@@ -863,7 +809,6 @@
|
||||
'<div class="sea-name"><span class="sea-name-icon">' + (oilSea.icon || '🛢') + '</span>' + oilSea.name + '</div>' +
|
||||
'<div class="sea-fields">' +
|
||||
'<div class="sea-field"><span class="sea-field__label">每份用量</span><span class="sea-field__value">' + oilSea.weightPerPack + 'g</span></div>' +
|
||||
'<div class="sea-field"><span class="sea-field__label">份数</span><span class="sea-field__value">' + oilSea.packSize + '</span></div>' +
|
||||
'<div class="sea-field"><span class="sea-field__label">应称</span><span class="sea-field__value">' + oilNeed + 'g</span></div>' +
|
||||
'<div class="sea-field"><span class="sea-field__label">已称</span><span class="sea-field__value ' + oilActualCls + '">' + oilSea.weighed + 'g</span></div>' +
|
||||
'</div>';
|
||||
@@ -874,7 +819,7 @@
|
||||
if (oilSea) {
|
||||
var oilIdx = allSeasonings.indexOf(oilSea);
|
||||
infoCell.style.cursor = 'pointer';
|
||||
infoCell.onclick = function() { openSeasoningModal(oilIdx); };
|
||||
infoCell.onclick = function() { confirmSeasoningDirect(oilIdx); };
|
||||
}
|
||||
grid.appendChild(infoCell);
|
||||
|
||||
@@ -915,12 +860,11 @@
|
||||
'<div class="sea-slot__name"><span class="sea-slot__name-icon">' + (neededSea.icon || '🧂') + '</span>' + neededSea.name + '</div>' +
|
||||
'<div class="sea-slot__fields">' +
|
||||
'<div class="sea-slot__field"><span class="sea-slot__field-label">每份</span><span class="sea-slot__field-value">' + neededSea.weightPerPack + 'g</span></div>' +
|
||||
'<div class="sea-slot__field"><span class="sea-slot__field-label">份数</span><span class="sea-slot__field-value">' + neededSea.packSize + '</span></div>' +
|
||||
'<div class="sea-slot__field"><span class="sea-slot__field-label">应称</span><span class="sea-slot__field-value">' + seaNeed2 + 'g</span></div>' +
|
||||
'<div class="sea-slot__field"><span class="sea-slot__field-label">已称</span><span class="sea-slot__field-value ' + actualCls2 + '">' + neededSea.weighed + 'g</span></div>' +
|
||||
'</div>';
|
||||
|
||||
cell.onclick = (function(idx) { return function() { openSeasoningModal(idx); }; })(findSeasoningIdxByPos(pos));
|
||||
cell.onclick = (function(idx) { return function() { confirmSeasoningDirect(idx); }; })(findSeasoningIdxByPos(pos));
|
||||
} else if (cfg && cfg.name) {
|
||||
/* 状态3:该格放置了调料但本餐品不需要组配 — 字段一致,数据用--占位 */
|
||||
cell.classList.add('seasoning-cell--occupied');
|
||||
@@ -930,7 +874,6 @@
|
||||
'<div class="sea-slot__name"><span class="sea-slot__name-icon">' + cfgIcon + '</span>' + cfg.name + '</div>' +
|
||||
'<div class="sea-slot__fields">' +
|
||||
'<div class="sea-slot__field"><span class="sea-slot__field-label">每份</span><span class="sea-slot__field-value">--</span></div>' +
|
||||
'<div class="sea-slot__field"><span class="sea-slot__field-label">份数</span><span class="sea-slot__field-value">--</span></div>' +
|
||||
'<div class="sea-slot__field"><span class="sea-slot__field-label">应称</span><span class="sea-slot__field-value">--</span></div>' +
|
||||
'<div class="sea-slot__field"><span class="sea-slot__field-label">已称</span><span class="sea-slot__field-value">--</span></div>' +
|
||||
'</div>';
|
||||
@@ -949,8 +892,8 @@
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* ---- 调料组配确认弹窗(不走 AI 识别,直接弹窗读秤) ---- */
|
||||
function openSeasoningModal(idx) {
|
||||
/* ---- 调料组配:直接读秤确认(无弹窗) ---- */
|
||||
function confirmSeasoningDirect(idx) {
|
||||
if (idx < 0 || idx >= allSeasonings.length) return;
|
||||
var sea = allSeasonings[idx];
|
||||
var seaNeed = Math.round(sea.weightPerPack * sea.packSize * 100) / 100;
|
||||
@@ -961,12 +904,22 @@
|
||||
/* 设为当前调料 */
|
||||
currentSeaIdx = idx;
|
||||
renderSeasoningGrid();
|
||||
/* 填入弹窗 */
|
||||
document.getElementById('modalIcon').innerHTML = sea.icon || '🧂';
|
||||
document.getElementById('modalFoodName').textContent = sea.name;
|
||||
document.getElementById('modalWeight').textContent = parseFloat(document.getElementById('scaleWeightValue').textContent).toFixed(1);
|
||||
document.getElementById('modalOverlay').classList.add('show');
|
||||
pendingCandidate = { name: sea.name, icon: sea.icon || '🧂', confidence: 100, isSeasoning: true, idx: idx };
|
||||
/* 直接读取当前秤重赋值 */
|
||||
var scaleWeight = parseFloat(document.getElementById('scaleWeightValue').textContent) || 0;
|
||||
sea.weighed = scaleWeight;
|
||||
showToast('调料称重完成: ' + sea.name + ' ' + scaleWeight.toFixed(2) + '克', 2000, 'success');
|
||||
renderSeasoningGrid();
|
||||
updateOverallStatus();
|
||||
/* 自动跳到下一个待称调料 */
|
||||
currentSeaIdx = -1;
|
||||
for (var s = 0; s < allSeasonings.length; s++) {
|
||||
if (allSeasonings[s].weighed < allSeasonings[s].weightPerPack * allSeasonings[s].packSize) {
|
||||
currentSeaIdx = s; break;
|
||||
}
|
||||
}
|
||||
renderSeasoningGrid();
|
||||
document.getElementById('scaleWeightValue').textContent = '0.00';
|
||||
if (currentSeaIdx < 0) showToast('所有调料已称重完成', 2000, 'success');
|
||||
}
|
||||
|
||||
/* ---- 触发识别(点击相机覆盖层) ---- */
|
||||
@@ -1017,7 +970,7 @@
|
||||
var card = document.createElement('div');
|
||||
card.className = 'candidate-card';
|
||||
card.onclick = function() {
|
||||
openRatioModal(r);
|
||||
confirmCandidateDirect(r);
|
||||
};
|
||||
card.innerHTML =
|
||||
'<div class="candidate-card__img">' + r.icon + '</div>' +
|
||||
@@ -1038,62 +991,16 @@
|
||||
event.target.value = '';
|
||||
}
|
||||
|
||||
/* ---- 组配确认弹窗 ---- */
|
||||
var pendingCandidate = null; // 待确认的识别结果
|
||||
|
||||
function openRatioModal(result) {
|
||||
pendingCandidate = result;
|
||||
/* 填入弹窗:食材图标、名称、当前秤重 */
|
||||
document.getElementById('modalIcon').innerHTML = result.icon;
|
||||
document.getElementById('modalFoodName').textContent = result.name;
|
||||
document.getElementById('modalWeight').textContent = parseFloat(document.getElementById('scaleWeightValue').textContent).toFixed(1);
|
||||
document.getElementById('modalOverlay').classList.add('show');
|
||||
}
|
||||
|
||||
/* 刷新弹窗中的秤重读数 */
|
||||
function refreshWeight() {
|
||||
document.getElementById('modalWeight').textContent = parseFloat(document.getElementById('scaleWeightValue').textContent).toFixed(1);
|
||||
}
|
||||
|
||||
function closeModal() {
|
||||
pendingCandidate = null;
|
||||
document.getElementById('modalOverlay').classList.remove('show');
|
||||
}
|
||||
|
||||
function confirmPack() {
|
||||
if (!pendingCandidate) return;
|
||||
document.getElementById('modalOverlay').classList.remove('show');
|
||||
var modalWeight = parseFloat(document.getElementById('modalWeight').textContent) || 0;
|
||||
|
||||
/* 调料组配:不走 AI 识别 */
|
||||
if (pendingCandidate.isSeasoning) {
|
||||
var sea = allSeasonings[pendingCandidate.idx];
|
||||
sea.weighed = modalWeight;
|
||||
showToast('调料称重完成: ' + sea.name + ' ' + modalWeight.toFixed(2) + '克', 2000, 'success');
|
||||
pendingCandidate = null;
|
||||
renderSeasoningGrid();
|
||||
updateOverallStatus();
|
||||
/* 自动跳到下一个待称调料 */
|
||||
currentSeaIdx = -1;
|
||||
for (var s = 0; s < allSeasonings.length; s++) {
|
||||
if (allSeasonings[s].weighed < allSeasonings[s].weightPerPack * allSeasonings[s].packSize) {
|
||||
currentSeaIdx = s; break;
|
||||
}
|
||||
}
|
||||
renderSeasoningGrid();
|
||||
document.getElementById('scaleWeightValue').textContent = '0.00';
|
||||
if (currentSeaIdx < 0) showToast('所有调料已称重完成', 2000, 'success');
|
||||
return;
|
||||
}
|
||||
|
||||
/* 主辅材组配:AI 识别后确认 */
|
||||
/* ---- 主辅材组配:直接读秤确认(无弹窗) ---- */
|
||||
function confirmCandidateDirect(result) {
|
||||
/* 直接读取当前秤重赋值 */
|
||||
var scaleWeight = parseFloat(document.getElementById('scaleWeightValue').textContent) || 0;
|
||||
var ing = allIngredients[currentIngIdx];
|
||||
ing.weighed = modalWeight;
|
||||
ing.weighed = scaleWeight;
|
||||
document.getElementById('scaleWeightValue').textContent = ing.weighed.toFixed(2);
|
||||
document.getElementById('statusDot').className = 'status-dot status-dot--done';
|
||||
document.getElementById('statusText').textContent = '组配确认: ' + pendingCandidate.name + ' — 置信度 ' + pendingCandidate.confidence + '%';
|
||||
showToast('称重完成: ' + pendingCandidate.name + ' ' + modalWeight.toFixed(2) + '克', 2000, 'success');
|
||||
pendingCandidate = null;
|
||||
document.getElementById('statusText').textContent = '组配确认: ' + result.name + ' — 置信度 ' + result.confidence + '%';
|
||||
showToast('称重完成: ' + result.name + ' ' + scaleWeight.toFixed(2) + '克', 2000, 'success');
|
||||
renderItemlist();
|
||||
updateOverallStatus();
|
||||
|
||||
@@ -1142,27 +1049,74 @@
|
||||
taskStatusEl.className = 'task-card__item-value' + (allDoneNow ? ' task-card__item-value--green' : ' task-card__item-value--yellow');
|
||||
}
|
||||
|
||||
/* ---- 组配完成 ---- */
|
||||
function handlePackDone() {
|
||||
/* ---- 校验组配是否全部完成 ---- */
|
||||
function checkPackAllDone() {
|
||||
var ingDone = allIngredients.every(function(ing) {
|
||||
return ing.weighed >= ing.weightPerPack * ing.packSize;
|
||||
});
|
||||
var seaDone = allSeasonings.every(function(sea) {
|
||||
return sea.weighed >= sea.weightPerPack * sea.packSize;
|
||||
});
|
||||
if (!ingDone || !seaDone) {
|
||||
return ingDone && seaDone;
|
||||
}
|
||||
|
||||
/* ---- 完成并退出:返回组配任务列表 ---- */
|
||||
function handlePackDoneExit() {
|
||||
if (!checkPackAllDone()) {
|
||||
var msg = [];
|
||||
var ingDone = allIngredients.every(function(ing) { return ing.weighed >= ing.weightPerPack * ing.packSize; });
|
||||
var seaDone = allSeasonings.every(function(sea) { return sea.weighed >= sea.weightPerPack * sea.packSize; });
|
||||
if (!ingDone) msg.push('主辅材');
|
||||
if (!seaDone) msg.push('调料');
|
||||
showToast(msg.join('和') + '未完成称重', 2500, 'error');
|
||||
return;
|
||||
}
|
||||
showToast('组配完成', 1500, 'success');
|
||||
showToast('组配完成,正在返回任务列表...', 1500, 'success');
|
||||
setTimeout(function() {
|
||||
window.location.href = '01-packing-tasks.html' + (userName ? '?user=' + encodeURIComponent(userName) : '');
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
/* ---- 完成并继续:跳转同订单下一个待组配餐品包 ---- */
|
||||
function handlePackDoneContinue() {
|
||||
if (!checkPackAllDone()) {
|
||||
var msg = [];
|
||||
var ingDone = allIngredients.every(function(ing) { return ing.weighed >= ing.weightPerPack * ing.packSize; });
|
||||
var seaDone = allSeasonings.every(function(sea) { return sea.weighed >= sea.weightPerPack * sea.packSize; });
|
||||
if (!ingDone) msg.push('主辅材');
|
||||
if (!seaDone) msg.push('调料');
|
||||
showToast(msg.join('和') + '未完成称重', 2500, 'error');
|
||||
return;
|
||||
}
|
||||
/* 在同订单中查找下一个待组配餐品包 */
|
||||
var task = taskData[taskNo];
|
||||
var nextPack = null;
|
||||
if (task) {
|
||||
for (var i = 0; i < task.mealPacks.length; i++) {
|
||||
var pk = task.mealPacks[i];
|
||||
if (pk.packName === packName) continue;
|
||||
/* 判断该包是否有待组配项 */
|
||||
var ingPending = pk.ingredients.some(function(ing) { return ing.weighed < ing.weightPerPack * pk.packSize; });
|
||||
var seaPending = pk.seasonings && pk.seasonings.some(function(sea) { return sea.weighed < sea.weightPerPack * pk.packSize; });
|
||||
if (ingPending || seaPending) { nextPack = pk; break; }
|
||||
}
|
||||
}
|
||||
if (nextPack) {
|
||||
showToast('组配完成,继续下一餐品包: ' + nextPack.packName, 1500, 'success');
|
||||
setTimeout(function() {
|
||||
var target = '02-weighing-packing.html?task=' + taskNo + '&order=' + encodeURIComponent(task ? task.orderNo : '') + '&pack=' + encodeURIComponent(nextPack.packName);
|
||||
if (userName) target += '&user=' + encodeURIComponent(userName);
|
||||
window.location.href = target;
|
||||
}, 1000);
|
||||
} else {
|
||||
/* 同订单无更多待组配包,返回任务列表 */
|
||||
showToast('本订单所有餐品包已组配完成,正在返回任务列表...', 1500, 'success');
|
||||
setTimeout(function() {
|
||||
window.location.href = '01-packing-tasks.html' + (userName ? '?user=' + encodeURIComponent(userName) : '');
|
||||
}, 1000);
|
||||
}
|
||||
}
|
||||
|
||||
/* ---- 清空重量 ---- */
|
||||
function clearWeight(idx) {
|
||||
var ing = allIngredients[idx];
|
||||
@@ -1177,9 +1131,7 @@
|
||||
|
||||
/* ---- 退出登录 ---- */
|
||||
function handleLogout() {
|
||||
if (confirm('确定退出登录?')) {
|
||||
window.location.href = 'index.html';
|
||||
}
|
||||
window.location.href = 'index.html';
|
||||
}
|
||||
|
||||
/* ---- 重新识别 ---- */
|
||||
|
||||
@@ -389,9 +389,9 @@
|
||||
orderNo: 'PO-20260616-001', orderType: 'internal', completeTime: '2026-06-16 10:20', taskNo: 'T-001',
|
||||
mealPacks: [
|
||||
{ type: '餐品净菜包', packName: '宫保鸡丁套餐', packSize: 3, packSpec: '大份800g', ingredients: [
|
||||
{ name: '土豆丝', icon: '🥔', weightPerPack: 300, weighed: 900 },
|
||||
{ name: '胡萝卜丝', icon: '🥕', weightPerPack: 250, weighed: 750 },
|
||||
{ name: '黄瓜片', icon: '🥒', weightPerPack: 250, weighed: 750 }
|
||||
{ name: '土豆', icon: '🥔', weightPerPack: 300, weighed: 900 },
|
||||
{ name: '胡萝卜', icon: '🥕', weightPerPack: 250, weighed: 750 },
|
||||
{ name: '黄瓜', icon: '🥒', weightPerPack: 250, weighed: 750 }
|
||||
], seasonings: [
|
||||
{ name: '油', cellIdx: 0, weightPerPack: 50, weighed: 150 },
|
||||
{ name: '盐', cellIdx: 1, weightPerPack: 5, weighed: 15 },
|
||||
@@ -407,8 +407,8 @@
|
||||
orderNo: 'PO-20260616-002', orderType: 'external', completeTime: '2026-06-16 11:00', taskNo: 'T-002',
|
||||
mealPacks: [
|
||||
{ type: '餐品净菜包', packName: '鱼香肉丝套餐', packSize: 2, packSpec: '大份800g', ingredients: [
|
||||
{ name: '白菜丝', icon: '🥬', weightPerPack: 400, weighed: 800 },
|
||||
{ name: '胡萝卜丝', icon: '🥕', weightPerPack: 400, weighed: 800 }
|
||||
{ name: '白菜', icon: '🥬', weightPerPack: 400, weighed: 800 },
|
||||
{ name: '胡萝卜', icon: '🥕', weightPerPack: 400, weighed: 800 }
|
||||
], seasonings: [
|
||||
{ name: '油', cellIdx: 0, weightPerPack: 40, weighed: 80 },
|
||||
{ name: '盐', cellIdx: 1, weightPerPack: 4, weighed: 8 },
|
||||
@@ -419,8 +419,8 @@
|
||||
{ name: '豆瓣酱', cellIdx: 6, weightPerPack: 15, weighed: 30 }
|
||||
]},
|
||||
{ type: '餐品净菜包', packName: '番茄炒蛋套餐', packSize: 2, packSpec: '标准份500g', ingredients: [
|
||||
{ name: '番茄块', icon: '🍅', weightPerPack: 300, weighed: 600 },
|
||||
{ name: '鸡蛋液', icon: '🥚', weightPerPack: 200, weighed: 400 }
|
||||
{ name: '番茄', icon: '🍅', weightPerPack: 300, weighed: 600 },
|
||||
{ name: '鸡蛋', icon: '🥚', weightPerPack: 200, weighed: 400 }
|
||||
], seasonings: [
|
||||
{ name: '油', cellIdx: 0, weightPerPack: 30, weighed: 60 },
|
||||
{ name: '盐', cellIdx: 1, weightPerPack: 4, weighed: 8 },
|
||||
|
||||
@@ -1,5 +1,15 @@
|
||||
# 净菜组配秤 CHANGELOG
|
||||
|
||||
## [2.2.2] - 2026-06-26
|
||||
|
||||
### 组配任务页按单份拆分 + 组配作业页移除弹窗
|
||||
- `01-packing-tasks.html` — 行展示按单份拆分("第N份/M份"),组配按钮携带份数参数;grid 列宽调整(`1fr 0.55fr 0.35fr 0.55fr 0.55fr 46px 66px`)
|
||||
- `01-packing-tasks.html` — 食材名称简化:去丝/段/片/块/液后缀(土豆丝→土豆、黄瓜片→黄瓜、番茄块→番茄、鸡蛋液→鸡蛋等)
|
||||
- `02-weighing-packing.html` — 移除组配确认弹窗(弹窗 CSS + HTML + JS 全部删除);底部按钮区改为 flex 布局
|
||||
- `02-weighing-packing.html` — 新增 `next-btn--secondary` 样式(绿色边框按钮)
|
||||
- `03-verify-history.html` — 食材名称同步简化
|
||||
- `doc/PRD.md` — 食材名称同步简化
|
||||
|
||||
## [2.2.1] - 2026-06-26
|
||||
|
||||
### 组配记录页字段与显示逻辑对齐
|
||||
|
||||
@@ -153,12 +153,12 @@ flowchart TD
|
||||
```
|
||||
订单 #PO-20260616-001(期望到货 11:30)
|
||||
└── 任务 #T-001
|
||||
├── 🥔 土豆丝(净菜包)需 2.5 斤 已包 1.0 斤 [进行中]
|
||||
├── 🥕 胡萝卜丝(净菜包)需 1.8 斤 已包 1.8 斤 [已完成]
|
||||
├── 🥔 土豆(净菜包)需 2.5 斤 已包 1.0 斤 [进行中]
|
||||
├── 🥕 胡萝卜(净菜包)需 1.8 斤 已包 1.8 斤 [已完成]
|
||||
└── 📦 宫保鸡丁套餐(餐品净菜包)需 3 份 已包 0 份
|
||||
├── 土豆丝 1.5 斤
|
||||
├── 胡萝卜丝 0.8 斤
|
||||
└── 黄瓜片 0.5 斤
|
||||
├── 土豆 1.5 斤
|
||||
├── 胡萝卜 0.8 斤
|
||||
└── 黄瓜 0.5 斤
|
||||
```
|
||||
|
||||
**交互说明**:
|
||||
|
||||
Reference in New Issue
Block a user