refactor: 净菜术语统一(净菜组配→净配、组配秤→净配秤、加工秤/配比秤→厨配秤)

- 净菜组配/组配任务/组配中/待组配 → 净配/净配任务/净配中/待净配
- 智能组配秤 → 智能净配秤;配比秤 → 净配秤
- 净菜加工秤/净菜配比秤 → 厨配秤
- 同步更新项目背景.md 设备目录、各模块 CHANGELOG
- 清理 IDE 状态文件 .idea/claudeCodeTabState.xml
This commit is contained in:
zhangyan
2026-08-25 11:38:19 +08:00
parent ef2dc7dfb4
commit 2922834e9d
54 changed files with 399 additions and 370 deletions
@@ -479,7 +479,7 @@
],
total: 35.50, discount: 3.00, payable: 32.50, paid: 32.50,
payType: '会员支付', payMethod: '人脸支付', balance: 1280.50,
nutrition: { calories: 685, protein: 28, fat: 18, carb: 95, score: 82, nrv: { calories: 34, protein: 47, fat: 30, carb: 32 } },
nutrition: { calories: 685, protein: 28, fat: 18, carb: 95, sodium: 800, score: 82, nrv: { calories: 34, protein: 47, fat: 30, carb: 32, sodium: 40 } },
printed: true
};
@@ -585,6 +585,7 @@
+ '<tr><td>蛋白质</td><td>' + order.nutrition.protein + '<small>g</small></td><td>' + order.nutrition.nrv.protein + '%</td></tr>'
+ '<tr><td>脂肪</td><td>' + order.nutrition.fat + '<small>g</small></td><td>' + order.nutrition.nrv.fat + '%</td></tr>'
+ '<tr><td>碳水</td><td>' + order.nutrition.carb + '<small>g</small></td><td>' + order.nutrition.nrv.carb + '%</td></tr>'
+ '<tr><td>钠</td><td>' + order.nutrition.sodium + '<small>mg</small></td><td>' + order.nutrition.nrv.sodium + '%</td></tr>'
+ '</tbody>'
+ '</table>'
+ '<div class="receipt-divider"></div>'
@@ -154,7 +154,7 @@
<div class="login-brand">
<div class="login-brand__icon">&#x1F3F7;&#xFE0F;</div>
<div class="login-brand__name">净菜包装贴标秤</div>
<div class="login-brand__desc">接收配完成订单<br>核对实物 · 包装塑封 · 全程可溯</div>
<div class="login-brand__desc">接收配完成订单<br>核对实物 · 包装塑封 · 全程可溯</div>
</div>
<!-- 右侧登录面板 -->
@@ -319,7 +319,7 @@
/* 当前 Tab */
var currentFilter = 'pending';
/* 模拟数据:待打印订单(来自配秤已完成配的订单)
/* 模拟数据:待打印订单(来自配秤已完成配的订单)
* 字段说明:
* cutSpec: 结构化对象 {length,width,height,shape,technique}(任务 4.4)
* packSpec: 结构化对象 {baseGram, unit, portion?, packMethod?}(任务 4.4)
@@ -420,7 +420,7 @@
document.getElementById('topUser').textContent = userName;
document.getElementById('userAvatar').textContent = userName.charAt(0);
/* ---- 模拟订单数据(来自配秤已完成配的订单) ----
/* ---- 模拟订单数据(来自配秤已完成配的订单) ----
* 字段说明:
* cutSpec: 结构化对象 {length,width,height,shape,technique}(任务 4.4)
* packSpec: 结构化对象 {baseGram, unit, portion?, packMethod?}(任务 4.4)
@@ -66,7 +66,7 @@
- `index.html` — 模块导航页(从占位页改为实际功能菜单入口)
### 功能说明
- 接收配秤已完成配的订单(含净菜包和餐品净菜包)
- 接收配秤已完成配的订单(含净菜包和餐品净菜包)
- 净菜包:通过摄像头识别+候选选择+秤重确认弹窗完成秤重
- 餐品净菜包:每份用量显示"--",后方有"打印"按钮,打印完状态显示"已打印",按钮可重复点击
- 贴标清单:餐品净菜包按餐品维度展示(不按食材展开),份数/需/已称按实际显示
@@ -97,7 +97,7 @@
- `02-labeling.html` — 净菜包列表项 meta 区新增"净菜类型"字段(尺寸·形状·刀工,如 `20mm*1mm*1mm · 细丝 · 平刀`),餐品净菜包显示"—"
### 新增页面
- `03-history.html` — 贴标历史页(4:3横屏,参考配秤配历史的显示逻辑:日视图/本周切换、日期条、搜索框、统计行;参考贴标秤任务列表的表单结构:订单号+类型+完成时间+操作人+表格行)
- `03-history.html` — 贴标历史页(4:3横屏,参考配秤配历史的显示逻辑:日视图/本周切换、日期条、搜索框、统计行;参考贴标秤任务列表的表单结构:订单号+类型+完成时间+操作人+表格行)
### 导航同步
- 更新根 `index.html` SITE_MAP 新增贴标历史页面条目,贴标订单更名为贴标任务
@@ -54,52 +54,58 @@
.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;
width: 400px; background: #fff; color: #1a1a2e; border-radius: 6px;
overflow: hidden; box-shadow: 0 2px 10px rgba(0,0,0,0.25);
display: flex; flex-direction: row; align-items: stretch;
min-height: 90px;
}
/* 标签主信息区 */
.label-sticker__body { flex: 1; padding: 12px 14px; display: flex; flex-direction: column; gap: 4px; }
.label-sticker__body { flex: 1; padding: 6px 10px; display: flex; flex-direction: column; gap: 2px; justify-content: center; }
/* 标签标题栏 */
.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;
font-size: 12px; font-weight: 700; color: #fff; padding: 2px 8px; border-radius: 3px;
display: inline-block; align-self: flex-start; letter-spacing: 1px;
}
.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 { display: flex; flex-wrap: wrap; gap: 0px 10px; font-size: 10px; line-height: 1.4; }
.label-info__item { display: flex; align-items: center; gap: 2px; 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 { width: 100%; border-collapse: collapse; margin-top: 1px; font-size: 9px; }
.label-detail-table th {
background: #f0f4f8; color: #666; font-weight: 500; padding: 3px 6px;
background: #f0f4f8; color: #666; font-weight: 500; padding: 2px 4px;
text-align: left; border-bottom: 1px solid #e0e4e8;
}
.label-detail-table td {
padding: 3px 6px; border-bottom: 1px solid #f0f0f0; color: #333;
padding: 2px 4px; 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; }
.label-detail-table .type-tag { display: inline-block; padding: 1px 4px; border-radius: 2px; font-size: 8px; 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-total { font-size: 10px; font-weight: 700; color: #1a1a2e; margin-top: 1px; }
/* 保质期三字段 */
.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; }
.label-shelf { display: flex; gap: 6px; margin-top: 1px; }
.label-shelf__item { display: flex; flex-direction: column; align-items: center; padding: 1px 6px; background: #f5f5f5; border-radius: 3px; }
.label-shelf__label { font-size: 8px; color: #999; }
.label-shelf__value { font-size: 10px; font-weight: 700; color: #333; }
/* 二维码区 */
.label-sticker__qrcode {
width: 56px; height: 56px; flex-shrink: 0;
align-self: center; margin-right: 6px;
}
.label-sticker__qrcode svg { display: block; width: 100%; height: 100%; }
/* 打印按钮 */
.action-bar { display: flex; gap: 10px; justify-content: center; flex-shrink: 0; padding: 0 20px 16px; }
@@ -144,7 +150,7 @@
<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>净菜标签
<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>餐品净菜包标签
@@ -330,7 +336,31 @@
panel.innerHTML = html;
}
/* ---- 渲染净菜标签 ---- */
/* 生成二维码占位 SVG(9×9 网格 + 三角落定位图案) */
function qrSvg(code) {
var size = 56, cells = 9, cw = size / cells;
var hash = 0, i;
for (i = 0; i < code.length; i++) { hash = ((hash << 5) - hash) + code.charCodeAt(i); hash |= 0; }
var rects = '';
var fp = [[0,0],[cells-3,0],[0,cells-3]]; /* 三个定位图案 */
for (i = 0; i < cells; i++) {
for (var j = 0; j < cells; j++) {
var isFinder = false;
for (var f = 0; f < 3; f++) {
if (i >= fp[f][0] && i < fp[f][0]+3 && j >= fp[f][1] && j < fp[f][1]+3) {
var fi = i - fp[f][0], fj = j - fp[f][1];
if (fi === 0 || fi === 2 || fj === 0 || fj === 2 || (fi === 1 && fj === 1)) isFinder = true;
}
}
if (isFinder || ((hash >> ((i * cells + j) % 31)) & 1)) {
rects += '<rect x="' + (j * cw + 1) + '" y="' + (i * cw + 1) + '" width="' + (cw - 1) + '" height="' + (cw - 1) + '" fill="#1a1a2e"/>';
}
}
}
return '<div class="label-sticker__qrcode"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 ' + size + ' ' + size + '" width="56" height="56"><rect width="' + size + '" height="' + size + '" fill="#fff"/>' + rects + '</svg></div>';
}
/* ---- 渲染净菜包标签 ---- */
function renderVegLabels() {
var panel = document.getElementById('panelVeg');
var html = '';
@@ -343,15 +373,16 @@
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">'
+ '<div class="label-info__item"><span class="label-info__label">订单号:</span><span class="label-info__value">' + mockData.orderNo + '</span></div>'
+ '</div>'
+ '<div class="label-info">'
+ '<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">' + formatCutSpec(cutObj) + '</span></div>'
+ '</div>'
+ '<div class="label-info">'
+ '<div class="label-info__item"><span class="label-info__label">包装规格:</span><span class="label-info__value">' + formatSpec(specObj) + '</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>'
@@ -359,6 +390,7 @@
+ '<div class="label-shelf__item"><span class="label-shelf__label">保质期至</span><span class="label-shelf__value">' + v.expiryDate + '</span></div>'
+ '</div>'
+ '</div>'
+ qrSvg(code)
+ '</div>';
}
});
@@ -378,14 +410,15 @@
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">'
+ '<div class="label-info__item"><span class="label-info__label">订单号:</span><span class="label-info__value">' + mockData.orderNo + '</span></div>'
+ '</div>'
+ '<div class="label-info">'
+ '<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">' + formatSpec(specObj) + '</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>'
@@ -393,6 +426,7 @@
+ '<div class="label-shelf__item"><span class="label-shelf__label">保质期至</span><span class="label-shelf__value">' + m.expiryDate + '</span></div>'
+ '</div>'
+ '</div>'
+ qrSvg(code)
+ '</div>';
}
});
@@ -428,7 +462,7 @@
if (currentTab === 'order') labels.push('订单标签');
else if (currentTab === 'veg') {
mockData.vegPacks.forEach(function(v) {
for (var p = 0; p < v.packSize; p++) { labels.push('净菜标签 — ' + v.name); }
for (var p = 0; p < v.packSize; p++) { labels.push('净菜标签 — ' + v.name); }
});
} else if (currentTab === 'meal') {
mockData.mealPacks.forEach(function(m) {
@@ -3,7 +3,7 @@
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=1280, initial-scale=1.0">
<title>净菜加工秤 - 员工登录 | 蚁熊智能餐养平台</title>
<title>厨配秤 - 员工登录 | 蚁熊智能餐养平台</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
@@ -95,7 +95,7 @@
<body>
<div class="login-page">
<div class="login-card">
<div class="login-card__title">净菜加工</div>
<div class="login-card__title">厨配</div>
<div class="login-card__subtitle">员工登录</div>
<div class="login-tabs">
<div class="login-tab active" data-tab="face" onclick="switchTab('face')">人脸识别</div>
@@ -3,7 +3,7 @@
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=1280, initial-scale=1.0">
<title>净菜加工秤 - 净菜加工 | 蚁熊智能餐养平台</title>
<title>厨配秤 - 厨配 | 蚁熊智能餐养平台</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
@@ -285,7 +285,7 @@
<!-- 顶部导航 -->
<div class="top-bar">
<a class="back-btn" id="backBtn" href="javascript:void(0)">&#x25C0; 返回</a>
<span class="page-title">净菜加工</span>
<span class="page-title">厨配</span>
<div class="user-info">
<div class="avatar" id="userAvatar"></div>
<span id="userName">赵六</span>
@@ -335,7 +335,7 @@
<!-- 右列:净菜列表 -->
<div class="col-right">
<!-- 净菜加工卡片列表 -->
<!-- 厨配卡片列表 -->
<button class="fetch-task-btn" onclick="handleFetchTask()">&#x1F4E5; 获取任务</button>
<div class="food-cards" id="foodCards"></div>
@@ -347,12 +347,12 @@
<!-- 重量确认弹窗 -->
<div class="modal-overlay" id="weightModal">
<div class="modal">
<div class="modal__title">本次加工确认</div>
<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__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="重新获取秤上重量">&#x1F504;</button>
@@ -417,7 +417,7 @@
document.getElementById('userName').textContent = userName;
document.getElementById('userAvatar').textContent = userName.charAt(0);
// 初始化净菜列表(带累计已加工重量)
// 初始化净菜列表(带累计已厨配重量)
acceptedFoods = mockFoods.map(function(f) {
foodIdCounter++;
return { id: foodIdCounter, name: f.name, size: f.size, shape: f.shape, blade: f.blade, target: f.target, processed: f.processed, arrivalTime: f.arrivalTime, icon: f.icon };
@@ -448,7 +448,7 @@
+ '<span class="food-card__spec">' + f.size + ' · ' + f.shape + ' · ' + f.blade + '</span>'
+ '<div class="food-card__progress">'
+ '<div style="display:flex;justify-content:space-between;">'
+ '<span class="food-card__progress-label">累计加工(斤)</span>'
+ '<span class="food-card__progress-label">累计厨配(斤)</span>'
+ '<span class="food-card__progress-text">' + f.processed.toFixed(1) + ' / ' + f.target.toFixed(1) + '</span>'
+ '</div>'
+ '<div class="food-card__progress-wrap">'
@@ -458,7 +458,7 @@
+ '</div>';
});
if (html === '') {
html = '<div style="grid-column:1/-1;text-align:center;padding:40px;color:rgba(255,255,255,0.2);font-size:13px;">暂无加工净菜,点击上方「获取任务」添加</div>';
html = '<div style="grid-column:1/-1;text-align:center;padding:40px;color:rgba(255,255,255,0.2);font-size:13px;">暂无厨配净菜,点击上方「获取任务」添加</div>';
}
container.innerHTML = html;
}
@@ -490,7 +490,7 @@
}
function doFetchTask() {
showToast('正在获取加工任务...', 800);
showToast('正在获取厨配任务...', 800);
setTimeout(function() {
var existingNames = acceptedFoods.filter(function(f) { return f.processed < f.target; }).map(function(f) { return f.name; });
var available = foodDatabase.filter(function(f) { return existingNames.indexOf(f.name) === -1; });
@@ -504,7 +504,7 @@
foodIdCounter++;
acceptedFoods.push({ id: foodIdCounter, name: food.name, size: food.size, shape: food.shape, blade: food.blade, target: target, processed: processed, arrivalTime: food.arrivalTime, icon: food.icon });
renderFoodCards();
showToast('已获取:' + food.name + '(应加工 ' + target.toFixed(1) + '斤)', 1500);
showToast('已获取:' + food.name + '(应厨配 ' + target.toFixed(1) + '斤)', 1500);
}, 800);
}
@@ -3,7 +3,7 @@
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=1280, initial-scale=1.0">
<title>净菜加工秤 - 功能菜单 | 蚁熊智能餐养平台</title>
<title>厨配秤 - 功能菜单 | 蚁熊智能餐养平台</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
@@ -68,7 +68,7 @@
</head>
<body>
<div class="top-bar">
<span class="top-bar__title">净菜加工</span>
<span class="top-bar__title">厨配</span>
<div class="top-bar__user">
<div class="top-bar__avatar" id="menuAvatar"></div>
<span id="menuUserName">赵六</span>
@@ -83,8 +83,8 @@
<a class="menu-btn" id="btnAccept" href="javascript:void(0)" onclick="handleMenu('01-accept.html')">
<div class="menu-btn__icon menu-btn__icon--blue">&#x2705;</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">&#x203A;</div>
</a>
@@ -107,8 +107,8 @@
<a class="menu-btn" id="btnHistory" href="javascript:void(0)" onclick="handleMenu('02-history.html')">
<div class="menu-btn__icon menu-btn__icon--gray">&#x1F4DD;</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">&#x203A;</div>
</a>
@@ -3,7 +3,7 @@
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=1280, initial-scale=1.0">
<title>净菜加工秤 - 加工记录 | 蚁熊智能餐养平台</title>
<title>厨配秤 - 厨配记录 | 蚁熊智能餐养平台</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
@@ -233,7 +233,7 @@
<div class="top-bar">
<a class="back-btn" id="backBtn" href="javascript:void(0)">&#x25C0; 返回</a>
<span class="page-title">加工记录</span>
<span class="page-title">厨配记录</span>
<span class="top-bar__user" id="topUser">--</span>
<button class="logout-btn" onclick="handleLogout()">退出</button>
</div>
@@ -263,7 +263,7 @@
<!-- 搜索框 -->
<div class="search-box">
<span class="search-box__icon">&#x1F50D;</span>
<input class="search-box__input" id="searchInput" type="text" placeholder="搜索加工号 / 净菜" oninput="onSearchInput()">
<input class="search-box__input" id="searchInput" type="text" placeholder="搜索厨配号 / 净菜" oninput="onSearchInput()">
<button class="search-box__clear" id="searchClear" onclick="clearSearch()">&times;</button>
</div>
</div>
@@ -272,11 +272,11 @@
<div class="stats-row">
<div class="stat-chip">
<div class="stat-chip__icon stat-chip__icon--blue">&#x1F4CB;</div>
<div><div class="stat-chip__value" id="statTotal">6</div><div class="stat-chip__label" id="statTotalLabel">今日加工总数</div></div>
<div><div class="stat-chip__value" id="statTotal">6</div><div class="stat-chip__label" id="statTotalLabel">今日厨配总数</div></div>
</div>
<div class="stat-chip">
<div class="stat-chip__icon stat-chip__icon--green">&#x2696;&#xFE0F;</div>
<div><div class="stat-chip__value" id="statWeight">0</div><div class="stat-chip__label">加工总重量(斤)</div></div>
<div><div class="stat-chip__value" id="statWeight">0</div><div class="stat-chip__label">厨配总重量(斤)</div></div>
</div>
<div class="stat-chip">
<div class="stat-chip__icon stat-chip__icon--orange">&#x1F96C;</div>
@@ -289,14 +289,14 @@
<div class="table-scroll">
<table>
<thead><tr id="tableHead">
<th>加工</th><th>净菜</th><th>净菜类型</th>
<th>加工重量</th><th>完成时间</th>
<th>厨配</th><th>净菜</th><th>净菜类型</th>
<th>厨配重量</th><th>完成时间</th>
</tr></thead>
<tbody id="tableBody"></tbody>
</table>
<div class="empty-state" id="emptyState">
<div class="empty-state__icon">&#x1F4ED;</div>
<div>暂无加工记录</div>
<div>暂无厨配记录</div>
</div>
</div>
<div class="table-footer" id="tableFooter">共 0 条记录</div>
@@ -324,7 +324,7 @@
var TODAY = '2026-06-17';
var WEEKDAYS = ['周日', '周一', '周二', '周三', '周四', '周五', '周六'];
// 加工记录数据(净菜加工语义)
// 厨配记录数据(厨配语义)
var RECORDS = [
{ batch:'JC-20260617-001', orderId:'PO-20260617-001', time:'2026-06-17 09:35', dish:'土豆', spec:'35mm*1mm*1mm · 长条 · 平刀', weight:5.2, duration:'5分钟' },
{ batch:'JC-20260617-002', orderId:'PO-20260617-001', time:'2026-06-17 09:52', dish:'黄瓜', spec:'30mm*30mm*3mm · 圆片 · 平刀', weight:4.2, duration:'4分钟' },
@@ -448,10 +448,10 @@
var monday = getMonday();
var mondayStr = dateStr(monday);
records = RECORDS.filter(function(r) { return r.time.substring(0, 10) >= mondayStr; });
totalLabel = '本周加工总数';
totalLabel = '本周厨配总数';
} else {
records = RECORDS.filter(function(r) { return r.time.substring(0, 10) === selectedDate; });
totalLabel = (selectedDate === TODAY) ? '今日加工总数' : (selectedDate.substring(5).replace('-', '/') + ' 加工总数');
totalLabel = (selectedDate === TODAY) ? '今日厨配总数' : (selectedDate.substring(5).replace('-', '/') + ' 厨配总数');
}
var total = records.length;
@@ -514,8 +514,8 @@
var thead = document.getElementById('tableHead');
var dateCol = isWeeklyMode ? '<th>日期</th>' : '';
thead.innerHTML = dateCol + '<th>加工号</th><th>净菜</th><th>净菜类型</th>'
+ '<th>加工重量</th><th>完成时间</th>';
thead.innerHTML = dateCol + '<th>厨配号</th><th>净菜</th><th>净菜类型</th>'
+ '<th>厨配重量</th><th>完成时间</th>';
if (records.length === 0) {
tbody.innerHTML = '';
@@ -3,7 +3,7 @@
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=1280, initial-scale=1.0">
<title>净菜加工秤 - 设备设置 | 蚁熊智能餐养平台</title>
<title>厨配秤 - 设备设置 | 蚁熊智能餐养平台</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body { font-family: -apple-system, "Microsoft YaHei", "PingFang SC", sans-serif; background: #0e1326; color: #fff; width: 1280px; height: 720px; overflow: hidden; }
@@ -59,7 +59,7 @@
</div>
<div class="main-content">
<div class="settings-menu">
<div class="menu-item active" onclick="switchSection('cutting', this)"><span class="menu-item__icon">&#x1F52A;</span><span>加工参数</span></div>
<div class="menu-item active" onclick="switchSection('cutting', this)"><span class="menu-item__icon">&#x1F52A;</span><span>厨配参数</span></div>
<div class="menu-item" onclick="switchSection('ai', this)"><span class="menu-item__icon">&#x1F916;</span><span>AI识别</span></div>
<div class="menu-item" onclick="switchSection('scale', this)"><span class="menu-item__icon">&#x2696;&#xFE0F;</span><span>秤参数</span></div>
<div class="menu-item" onclick="switchSection('device', this)"><span class="menu-item__icon">&#x1F4BB;</span><span>设备信息</span></div>
@@ -67,7 +67,7 @@
</div>
<div class="settings-content">
<div class="settings-section" id="section-cutting">
<div class="section-title">加工参数配置</div>
<div class="section-title">厨配参数配置</div>
<div class="setting-item__hint" style="background:rgba(74,144,217,0.08);border:1px solid rgba(74,144,217,0.2);border-radius:8px;padding:10px 12px;margin-bottom:12px;font-size:11px;color:rgba(255,255,255,0.6);line-height:1.5;">
ℹ️ 以下默认值从食材档案 <code style="color:#4a90d9">vegTypes.cutSpec</code> 自动读取,此处仅作设备级覆盖(切配类型字典 <code style="color:#4a90d9">spec_cut_shape</code>)。
</div>
@@ -120,7 +120,7 @@
<div class="settings-section" id="section-device" style="display:none">
<div class="section-title">设备信息</div>
<div class="device-info">
<div class="info-item"><div class="info-item__label">设备名称</div><div class="info-item__value">净菜加工秤-01</div></div>
<div class="info-item"><div class="info-item__label">设备名称</div><div class="info-item__value">厨配秤-01</div></div>
<div class="info-item"><div class="info-item__label">设备编号</div><div class="info-item__value">JCJG-2026-001</div></div>
<div class="info-item"><div class="info-item__label">固件版本</div><div class="info-item__value">v2.3.1</div></div>
<div class="info-item"><div class="info-item__label">AI模型版本</div><div class="info-item__value">cut-ai-v3.1</div></div>
@@ -135,7 +135,7 @@
<div class="device-info">
<div class="info-item"><div class="info-item__label">系统名称</div><div class="info-item__value">蚁熊智能餐养平台</div></div>
<div class="info-item"><div class="info-item__label">系统版本</div><div class="info-item__value">v5.8.0</div></div>
<div class="info-item"><div class="info-item__label">设备类型</div><div class="info-item__value">净菜加工</div></div>
<div class="info-item"><div class="info-item__label">设备类型</div><div class="info-item__value">厨配</div></div>
<div class="info-item"><div class="info-item__label">制造商</div><div class="info-item__value">蚁熊智能科技有限公司</div></div>
</div>
</div>
@@ -3,7 +3,7 @@
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=1280, initial-scale=1.0">
<title>净菜加工秤 - 净菜采样 | 蚁熊智能餐养平台</title>
<title>厨配秤 - 净菜采样 | 蚁熊智能餐养平台</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
@@ -3,7 +3,7 @@
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=1280, initial-scale=1.0">
<title>净菜加工秤 - 采样历史 | 蚁熊智能餐养平台</title>
<title>厨配秤 - 采样历史 | 蚁熊智能餐养平台</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
@@ -1,4 +1,4 @@
# 净菜加工秤 CHANGELOG
# 厨配秤 CHANGELOG
## [2026-06-17] refactor: 任务截止时间格式改为年月日时间
@@ -20,8 +20,8 @@
### 变更
- 删除旧页面:`01-cutting-tasks.html`(任务列表)、`02-weighing.html`(称重录入)、`03-cutting.html`(切配操作)
- 新建 `01-accept.html`(净菜验收主操作页):模仿毛菜验收秤流程,包含任务选择→上秤识别→验收确认两步操作
- 重命名 `04-history.html``02-history.html`:「切配记录」→「验收记录」,规格标签由切法改为加工规格
- 重命名 `05-settings.html``03-settings.html`:「切配参数」→「加工参数」
- 重命名 `04-history.html``02-history.html`:「切配记录」→「验收记录」,规格标签由切法改为厨配规格
- 重命名 `05-settings.html``03-settings.html`:「切配参数」→「厨配参数」
- 更新 `00-welcome.html`:功能菜单由4个缩减为3个(净菜验收、验收记录、设置)
- 更新 `index.html`:导航卡片同步更新为新页面结构
@@ -42,7 +42,7 @@
## [1.0.0] - 2026-06-13
### 新增
- 首次创建净菜加工秤模块(6个页面)
- 首次创建厨配秤模块(6个页面)
- `00-welcome.html` — 欢迎页:人脸识别+账号密码登录+功能菜单
- `01-cutting-tasks.html` — 今日切配任务列表:任务卡片含切法标签、状态筛选、进度展示
- `02-weighing.html` — 称重录入:AI识别品类、实时称重、确认后跳转切配页面
@@ -3,7 +3,7 @@
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=1280, initial-scale=1.0">
<title>净菜加工秤 - 蚁熊智能餐养平台</title>
<title>厨配秤 - 蚁熊智能餐养平台</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body { font-family: -apple-system, "Microsoft YaHei", "PingFang SC", sans-serif; background: #0e1326; color: #fff; width: 1280px; height: 720px; overflow: hidden; }
@@ -24,7 +24,7 @@
<body>
<div class="top-bar">
<a class="back-link" href="../index.html">&#x25C0; 返回</a>
<span class="top-bar__title">净菜加工</span>
<span class="top-bar__title">厨配</span>
</div>
<div class="main-content">
<a class="card" href="00-welcome.html">
@@ -38,8 +38,8 @@
<a class="card" href="01-accept.html">
<span class="card__icon">&#x2705;</span>
<div class="card__info">
<div class="card__title">净菜加工</div>
<div class="card__desc">净菜上秤识别、加工确认</div>
<div class="card__title">厨配</div>
<div class="card__desc">净菜上秤识别、厨配确认</div>
</div>
<span class="card__arrow">&#x203A;</span>
</a>
@@ -62,8 +62,8 @@
<a class="card" href="02-history.html">
<span class="card__icon">&#x1F4DD;</span>
<div class="card__info">
<div class="card__title">加工记录</div>
<div class="card__desc">历史加工记录查看与筛选</div>
<div class="card__title">厨配记录</div>
<div class="card__desc">历史厨配记录查看与筛选</div>
</div>
<span class="card__arrow">&#x203A;</span>
</a>
+4 -4
View File
@@ -178,7 +178,7 @@
<a class="card" href="clean-veg-ratio-scale/index.html">
<span class="card__status card__status--done">已设计</span>
<div class="card__icon">&#x2696;&#xFE0F;</div>
<div class="card__name">净菜加工</div>
<div class="card__name">厨配</div>
<div class="card__desc">净菜加工:任务驱动,含尺寸/形状/刀工要求</div>
</a>
<a class="card" href="clean-veg-inventory-cabinet/index.html">
@@ -190,14 +190,14 @@
<a class="card" href="ratio-scale/index.html">
<span class="card__status card__status--done">已设计</span>
<div class="card__icon">&#x1F4E6;</div>
<div class="card__name">菜组配秤</div>
<div class="card__desc">餐品净菜包独立配,主辅材+调料双区称重</div>
<div class="card__name">净配秤</div>
<div class="card__desc">餐品净菜包独立配,主辅材+调料双区称重</div>
</a>
<a class="card" href="clean-veg-packaging-labeler/index.html">
<span class="card__status card__status--done">已设计</span>
<div class="card__icon">&#x1F3F7;&#xFE0F;</div>
<div class="card__name">净菜包装贴标秤</div>
<div class="card__desc">接收配完成订单,核对实物、包装塑封</div>
<div class="card__desc">接收配完成订单,核对实物、包装塑封</div>
</a>
</div>
@@ -3,7 +3,7 @@
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=720, initial-scale=1.0">
<title>菜组配秤 - 登录 | 蚁熊智能餐养平台</title>
<title>净配秤 - 登录 | 蚁熊智能餐养平台</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
@@ -143,7 +143,7 @@
<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">
@@ -3,7 +3,7 @@
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=720, initial-scale=1.0">
<title>菜组配秤 - 功能菜单 | 蚁熊智能餐养平台</title>
<title>净配秤 - 功能菜单 | 蚁熊智能餐养平台</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
@@ -121,7 +121,7 @@
<div class="device-frame">
<div class="top-bar">
<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()">退出登录</button>
</div>
@@ -136,8 +136,8 @@
<a class="menu-btn" id="btnTasks" onclick="handleMenu('01-packing-tasks.html')">
<div class="menu-btn__icon menu-btn__icon--blue">&#x1F4CB;</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">&#x203A;</div>
@@ -145,8 +145,8 @@
<a class="menu-btn" onclick="handleMenu('03-verify-history.html')">
<div class="menu-btn__icon menu-btn__icon--green">&#x1F4DD;</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">&#x203A;</div>
</a>
@@ -3,7 +3,7 @@
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=720, initial-scale=1.0">
<title>菜组配秤 - 配任务 | 蚁熊智能餐养平台</title>
<title>净配秤 - 配任务 | 蚁熊智能餐养平台</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
@@ -141,14 +141,14 @@
<div class="device-frame">
<div class="top-bar">
<a class="back-btn" id="backBtn" href="javascript:void(0)">&#x25C0; 返回</a>
<span class="top-bar__title">配任务</span>
<span class="top-bar__title">配任务</span>
<span class="top-bar__user" id="topUser">--</span>
</div>
<div class="main-content">
<!-- 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 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>
@@ -345,10 +345,10 @@
return sea.weighed >= sea.weightPerPack * pack.packSize;
});
if (ingDone && seaDone) return { text: '已完成', cls: 'status-badge--done' };
return { text: '待配', cls: 'status-badge--pending' };
return { text: '待配', cls: 'status-badge--pending' };
}
/* 判断餐品净菜包是否有待配项(主辅材或调料) */
/* 判断餐品净菜包是否有待配项(主辅材或调料) */
function hasPendingPack(pack) {
var ingPending = pack.ingredients.some(function(ing) {
return ing.weighed < ing.weightPerPack * pack.packSize;
@@ -385,7 +385,7 @@
'<span class="task-card__order-info"><span class="task-card__order-info__label">订单号:</span><span class="task-card__order-info__value">' + order.orderNo + '</span></span>' +
'<span class="order-type-tag ' + orderTypeCls + '">' + orderTypeLabel + '</span>' +
'<span class="task-card__arrival">&#x23F0; ' + (orderAllDone ? '任务完成时间' : '任务截止时间') + '<span class="task-card__arrival__time">' + order.expectedArrival + '</span></span>' +
'<span class="task-card__status"><span class="status-badge ' + (orderAllDone ? 'status-badge--done' : 'status-badge--pending') + '">' + (orderAllDone ? '已完成' : '待配') + '</span></span>';
'<span class="task-card__status"><span class="status-badge ' + (orderAllDone ? 'status-badge--done' : 'status-badge--pending') + '">' + (orderAllDone ? '已完成' : '待配') + '</span></span>';
taskCard.appendChild(header);
/* 表格头(6列:名称/包装规格/应称重量/已称重量/状态/操作) */
@@ -430,8 +430,8 @@
'<div style="text-align:center"><span class="pack-spec-tag">' + specText + '</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 ' + (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) + '\')">配</button>') + '</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) + '\')">配</button>') + '</div>';
tableBody.appendChild(parentRow);
});
@@ -461,7 +461,7 @@
});
}
/* 进入餐品净菜包配详情 */
/* 进入餐品净菜包配详情 */
function handlePackWeigh(taskNo, orderNo, packName) {
var target = '02-weighing-packing.html?task=' + taskNo + '&order=' + encodeURIComponent(orderNo) + '&pack=' + packName;
if (userName) target += '&user=' + encodeURIComponent(userName);
@@ -481,7 +481,7 @@
/* 初始化 */
renderTaskList();
/* 初始过滤:待配 Tab 默认不显示已完成订单 */
/* 初始过滤:待配 Tab 默认不显示已完成订单 */
switchTab('pending', document.querySelector('.tab[data-filter="pending"]'));
/* 返回按钮 */
@@ -3,7 +3,7 @@
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=720, initial-scale=1.0">
<title>菜组配秤 - 配任务 | 蚁熊智能餐养平台</title>
<title>净配秤 - 配任务 | 蚁熊智能餐养平台</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
@@ -305,7 +305,7 @@
.section-divider__icon { font-size: 14px; }
.section-divider__line { flex: 1; height: 1px; background: rgba(255,255,255,0.08); }
/* 调料配区展开/折叠开关 */
/* 调料配区展开/折叠开关 */
.seasoning-toggle {
display: flex; align-items: center; gap: 6px; margin-left: auto;
cursor: pointer; user-select: none; flex-shrink: 0;
@@ -328,7 +328,7 @@
background: #fff; transform: translateX(20px); color: #4a90d9;
}
/* ===== 调料配网格 ===== */
/* ===== 调料配网格 ===== */
.seasoning-section { flex-shrink: 0; display: flex; flex-direction: column; gap: 6px; }
.seasoning-grid {
display: grid;
@@ -368,7 +368,7 @@
}
.seasoning-cell--info .sea-slot__status--wait { background: rgba(250,173,21,0.15); color: #faad14; }
.seasoning-cell--info .sea-slot__status--done { background: rgba(82,196,26,0.15); color: #52c41a; }
/* 信息格待配也加脉冲 */
/* 信息格待配也加脉冲 */
.seasoning-cell--info.seasoning-cell--pending {
border: 2px solid #4a90d9; background: rgba(74,144,217,0.15);
box-shadow: 0 0 0 2px rgba(74,144,217,0.3), 0 0 12px rgba(74,144,217,0.4);
@@ -378,13 +378,13 @@
.seasoning-cell--slot { cursor: pointer; }
.seasoning-cell--slot:hover { border-color: rgba(74,144,217,0.3); background: rgba(74,144,217,0.06); }
.seasoning-cell--occupied { border-color: rgba(255,255,255,0.12); }
/* 待配:蓝色脉冲动态效果 */
/* 待配:蓝色脉冲动态效果 */
.seasoning-cell--pending {
border: 2px solid #4a90d9; background: rgba(74,144,217,0.15);
box-shadow: 0 0 0 2px rgba(74,144,217,0.3), 0 0 12px rgba(74,144,217,0.4);
animation: seaPulse 1.4s ease-in-out infinite;
}
/* 已配:绿色,取消高亮 */
/* 已配:绿色,取消高亮 */
.seasoning-cell--done {
border: 1px solid rgba(82,196,26,0.4); background: rgba(82,196,26,0.08);
animation: none;
@@ -424,7 +424,7 @@
<!-- 顶部导航栏 -->
<div class="top-bar">
<a class="back-btn" id="backBtn" href="javascript:void(0)">&#x25C0; 返回</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>
@@ -500,15 +500,15 @@
<div class="task-card__item-value task-card__item-value--purple" id="taskPackName">--</div>
</div>
<div class="task-card__item">
<div class="task-card__item-label">餐品配状态</div>
<div class="task-card__item-label">餐品配状态</div>
<div class="task-card__item-value" id="taskStatus">--</div>
</div>
</div>
</div>
<!-- 主辅材配区 -->
<!-- 主辅材配区 -->
<div class="section-divider">
<span class="section-divider__icon">&#x1F95C;</span>主辅材
<span class="section-divider__icon">&#x1F95C;</span>主辅材
<span class="section-divider__line"></span>
</div>
<div class="item-list">
@@ -517,10 +517,10 @@
</div>
</div>
<!-- 调料配区 -->
<!-- 调料配区 -->
<div class="seasoning-section">
<div class="section-divider">
<span class="section-divider__icon">&#x1F9C2;</span>调料
<span class="section-divider__icon">&#x1F9C2;</span>调料
<span class="section-divider__line"></span>
<div class="seasoning-toggle seasoning-toggle--on" id="seasoningToggle" onclick="toggleSeasoning()">
<span>是否需要</span>
@@ -840,7 +840,7 @@
});
var allDone = ingAllDone && seaAllDone;
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');
renderItemlist();
@@ -877,8 +877,8 @@
else if (ing.weighed > 0) actualClass = 'item-card__data-value--progress';
var statusTag = isDone
? '<span class="status-tag status-tag--done">已配</span>'
: '<span class="status-tag status-tag--wait">待配</span>';
? '<span class="status-tag status-tag--done">已配</span>'
: '<span class="status-tag status-tag--wait">待配</span>';
row.innerHTML =
'<div class="item-card__header">' +
@@ -895,7 +895,7 @@
});
}
/* ---- 调料配区展开/折叠 ---- */
/* ---- 调料配区展开/折叠 ---- */
function toggleSeasoning() {
var toggle = document.getElementById('seasoningToggle');
var grid = document.getElementById('seasoningGrid');
@@ -905,26 +905,26 @@
thumb.textContent = isOn ? '是' : '否';
}
/* ---- 渲染调料配网格(3行×5列=15格,左上4格合并为信息格固定显示油,11格为调料位) ---- */
/* ---- 渲染调料配网格(3行×5列=15格,左上4格合并为信息格固定显示油,11格为调料位) ---- */
function renderSeasoningGrid() {
var grid = document.getElementById('seasoningGrid');
grid.innerHTML = '';
/* 信息格(合并格):固定显示"油"的完整字段(油始终参与配) */
/* 信息格(合并格):固定显示"油"的完整字段(油始终参与配) */
var oilSea = allSeasonings.find(function(s) { return s.cellIdx === 0; });
var infoCell = document.createElement('div');
infoCell.className = 'seasoning-cell seasoning-cell--info';
if (oilSea) {
var oilNeed = Math.round(oilSea.weightPerPack * 100) / 100;
var oilDone = oilSea.weighed >= oilNeed;
/* 待配→脉冲高亮,已配→绿色 */
/* 待配→脉冲高亮,已配→绿色 */
if (oilDone) {
infoCell.classList.add('seasoning-cell--done');
} else {
infoCell.classList.add('seasoning-cell--pending');
}
var oilStatusCls = oilDone ? 'sea-slot__status--done' : 'sea-slot__status--wait';
var oilStatusText = oilDone ? '已配' : '待配';
var oilStatusText = oilDone ? '已配' : '待配';
var oilActualCls = oilDone ? 'sea-field__value--done' : '';
infoCell.innerHTML =
'<span class="sea-slot__status ' + oilStatusCls + '">' + oilStatusText + '</span>' +
@@ -957,22 +957,22 @@
var neededSea = neededSeaMap[pos];
if (neededSea) {
/* 状态1/2:该格调料在本餐品配清单中 — 待配或已配 */
/* 状态1/2:该格调料在本餐品配清单中 — 待配或已配 */
var seaNeed2 = Math.round(neededSea.weightPerPack * 100) / 100;
var seaDone2 = neededSea.weighed >= seaNeed2;
cell.classList.add('seasoning-cell--occupied');
if (seaDone2) {
/* 已配:绿色,取消高亮 */
/* 已配:绿色,取消高亮 */
cell.classList.add('seasoning-cell--done');
} else {
/* 待配:脉冲高亮 */
/* 待配:脉冲高亮 */
cell.classList.add('seasoning-cell--pending');
}
var actualCls2 = seaDone2 ? 'sea-slot__field-value--done' : '';
var statusCls = seaDone2 ? 'sea-slot__status--done' : 'sea-slot__status--wait';
var statusText = seaDone2 ? '已配' : '待配';
var statusText = seaDone2 ? '已配' : '待配';
cell.innerHTML =
'<span class="sea-slot__pos">' + pos + '</span>' +
@@ -984,7 +984,7 @@
cell.onclick = (function(idx) { return function() { confirmSeasoningDirect(idx); }; })(findSeasoningIdxByPos(pos));
} else if (cfg && cfg.name) {
/* 状态3:该格放置了调料但本餐品不需要配 — 字段一致,数据用--占位 */
/* 状态3:该格放置了调料但本餐品不需要配 — 字段一致,数据用--占位 */
cell.classList.add('seasoning-cell--occupied');
var cfgIcon = SEASONING_ICONS[cfg.name] || '&#x1F9C2;';
cell.innerHTML =
@@ -1008,13 +1008,13 @@
return -1;
}
/* ---- 调料配:直接读秤确认(无弹窗) ---- */
/* ---- 调料配:直接读秤确认(无弹窗) ---- */
function confirmSeasoningDirect(idx) {
if (idx < 0 || idx >= allSeasonings.length) return;
var sea = allSeasonings[idx];
var seaNeed = Math.round(sea.weightPerPack * 100) / 100;
if (sea.weighed >= seaNeed) {
showToast(sea.name + ' 已配', 1500, 'success');
showToast(sea.name + ' 已配', 1500, 'success');
return;
}
/* 设为当前调料 */
@@ -1117,7 +1117,7 @@
event.target.value = '';
}
/* ---- 主辅材配:直接读秤确认(无弹窗) ---- */
/* ---- 主辅材配:直接读秤确认(无弹窗) ---- */
function confirmCandidateDirect(result) {
/* 直接读取当前秤重赋值 */
var scaleWeight = parseFloat(document.getElementById('scaleWeightValue').textContent) || 0;
@@ -1125,7 +1125,7 @@
ing.weighed = scaleWeight;
document.getElementById('scaleWeightValue').textContent = ing.weighed.toFixed(2);
document.getElementById('statusDot').className = 'status-dot status-dot--done';
document.getElementById('statusText').textContent = '配确认: ' + result.name + ' — 置信度 ' + result.confidence + '%';
document.getElementById('statusText').textContent = '配确认: ' + result.name + ' — 置信度 ' + result.confidence + '%';
showToast('称重完成: ' + result.name + ' ' + scaleWeight.toFixed(2) + '克', 2000, 'success');
renderItemlist();
updateOverallStatus();
@@ -1151,9 +1151,9 @@
document.getElementById('cameraOverlay').classList.add('show');
} else {
document.getElementById('scaleWeightValue').textContent = '0.00';
/* 主辅材全完成,提示进行调料配 */
/* 主辅材全完成,提示进行调料配 */
if (currentSeaIdx >= 0) {
showToast('主辅材已配,请点击高亮调料格进行调料配', 3000, 'success');
showToast('主辅材已配,请点击高亮调料格进行调料配', 3000, 'success');
} else {
showToast('所有食材已称重完成', 2500, 'success');
}
@@ -1171,11 +1171,11 @@
});
var allDoneNow = ingDone && seaDone;
var taskStatusEl = document.getElementById('taskStatus');
taskStatusEl.textContent = allDoneNow ? '已配' : '待配';
taskStatusEl.textContent = allDoneNow ? '已配' : '待配';
taskStatusEl.className = 'task-card__item-value' + (allDoneNow ? ' task-card__item-value--green' : ' task-card__item-value--yellow');
}
/* ---- 校验配是否全部完成 ---- */
/* ---- 校验配是否全部完成 ---- */
function checkPackAllDone() {
var ingDone = allIngredients.every(function(ing) {
return ing.weighed >= ing.weightPerPack;
@@ -1186,7 +1186,7 @@
return ingDone && seaDone;
}
/* ---- 完成并退出:返回配任务列表 ---- */
/* ---- 完成并退出:返回配任务列表 ---- */
function handlePackDoneExit() {
if (!checkPackAllDone()) {
var msg = [];
@@ -1197,13 +1197,13 @@
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 = [];
@@ -1214,29 +1214,29 @@
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; });
var seaPending = pk.seasonings && pk.seasonings.some(function(sea) { return sea.weighed < sea.weightPerPack; });
if (ingPending || seaPending) { nextPack = pk; break; }
}
}
if (nextPack) {
showToast('配完成,继续下一餐品包: ' + nextPack.packName, 1500, 'success');
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');
/* 同订单无更多待配包,返回任务列表 */
showToast('本订单所有餐品包已配完成,正在返回任务列表...', 1500, 'success');
setTimeout(function() {
window.location.href = '01-packing-tasks.html' + (userName ? '?user=' + encodeURIComponent(userName) : '');
}, 1000);
@@ -3,7 +3,7 @@
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=720, initial-scale=1.0">
<title>菜组配秤 - 配记录 | 蚁熊智能餐养平台</title>
<title>净配秤 - 配记录 | 蚁熊智能餐养平台</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
@@ -293,7 +293,7 @@
<div class="device-frame">
<div class="top-bar">
<a class="back-btn" id="backBtn" href="javascript:void(0)">&#x25C0; 返回</a>
<span class="page-title">配记录</span>
<span class="page-title">配记录</span>
<span class="top-bar__user" id="topUser">--</span>
<button class="logout-btn" onclick="handleLogout()">退出</button>
</div>
@@ -332,11 +332,11 @@
<div class="stats-row">
<div class="stat-chip">
<div class="stat-chip__icon stat-chip__icon--blue">&#x1F4CB;</div>
<div><div class="stat-chip__value" id="statTotal">5</div><div class="stat-chip__label" id="statTotalLabel">今日配订单数</div></div>
<div><div class="stat-chip__value" id="statTotal">5</div><div class="stat-chip__label" id="statTotalLabel">今日配订单数</div></div>
</div>
<div class="stat-chip">
<div class="stat-chip__icon stat-chip__icon--green">&#x2696;&#xFE0F;</div>
<div><div class="stat-chip__value" id="statWeight">0</div><div class="stat-chip__label">配总重量(g)</div></div>
<div><div class="stat-chip__value" id="statWeight">0</div><div class="stat-chip__label">配总重量(g)</div></div>
</div>
<div class="stat-chip">
<div class="stat-chip__icon stat-chip__icon--orange">&#x1F96C;</div>
@@ -351,7 +351,7 @@
</div>
<div class="empty-state" id="emptyState">
<div class="empty-state__icon">&#x1F4ED;</div>
<div>暂无配记录</div>
<div>暂无配记录</div>
</div>
<div class="table-footer" id="tableFooter">共 0 条记录</div>
</div>
@@ -448,7 +448,7 @@
var TODAY = '2026-06-16';
var WEEKDAYS = ['周日', '周一', '周二', '周三', '周四', '周五', '周六'];
// 配记录数据(packSpec 结构化为对象,与 01 任务页保持一致)
// 配记录数据(packSpec 结构化为对象,与 01 任务页保持一致)
var RECORDS = [
{
orderNo: 'PO-20260616-001', orderType: 'internal', completeTime: '2026-06-16 10:20', taskNo: 'T-001',
@@ -629,10 +629,10 @@
var monday = getMonday();
var mondayStr = dateStr(monday);
records = RECORDS.filter(function(r) { return r.completeTime.substring(0, 10) >= mondayStr; });
totalLabel = '本周配订单数';
totalLabel = '本周配订单数';
} else {
records = RECORDS.filter(function(r) { return r.completeTime.substring(0, 10) === selectedDate; });
totalLabel = (selectedDate === TODAY) ? '今日配订单数' : (selectedDate.substring(5).replace('-', '/') + ' 配订单数');
totalLabel = (selectedDate === TODAY) ? '今日配订单数' : (selectedDate.substring(5).replace('-', '/') + ' 配订单数');
}
var total = records.length;
@@ -713,10 +713,10 @@
return sea.weighed >= sea.weightPerPack * pack.packSize;
});
if (ingDone && seaDone) return { text: '已完成', cls: 'status-badge--done' };
return { text: '待配', cls: 'status-badge--pending' };
return { text: '待配', cls: 'status-badge--pending' };
}
/* 判断餐品净菜包是否有待配项(主辅材或调料) */
/* 判断餐品净菜包是否有待配项(主辅材或调料) */
function hasPendingPack(pack) {
var ingPending = pack.ingredients.some(function(ing) {
return ing.weighed < ing.weightPerPack * pack.packSize;
@@ -760,7 +760,7 @@
'<span class="task-card__order-info"><span class="task-card__order-info__label">订单号:</span><span class="task-card__order-info__value">' + order.orderNo + '</span></span>' +
'<span class="order-type-tag ' + orderTypeCls + '">' + orderTypeLabel + '</span>' +
'<span class="task-card__arrival">&#x23F0; 任务完成时间:<span class="task-card__arrival__time">' + order.completeTime + '</span></span>' +
'<span class="task-card__status"><span class="status-badge ' + (orderAllDone ? 'status-badge--done' : 'status-badge--pending') + '">' + (orderAllDone ? '已完成' : '待配') + '</span></span>';
'<span class="task-card__status"><span class="status-badge ' + (orderAllDone ? 'status-badge--done' : 'status-badge--pending') + '">' + (orderAllDone ? '已完成' : '待配') + '</span></span>';
taskCard.appendChild(header);
/* 表格头(5列:餐品净菜包名称 / 包装规格 / 应称重量 / 已称重量 / 状态) */
@@ -805,7 +805,7 @@
'<div style="text-align:center"><span class="pack-spec-tag">' + specText + '</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 ' + (packDone ? 'status-tag--done' : 'status-tag--wait') + '">' + (packDone ? '已完成' : '待配') + '</span></div>';
'<div style="text-align:center"><span class="status-tag ' + (packDone ? 'status-tag--done' : 'status-tag--wait') + '">' + (packDone ? '已完成' : '待配') + '</span></div>';
tableBody.appendChild(parentRow);
});
@@ -3,7 +3,7 @@
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=720, initial-scale=1.0">
<title>菜组配秤 - 调料位置设置 | 蚁熊智能餐养平台</title>
<title>净配秤 - 调料位置设置 | 蚁熊智能餐养平台</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
@@ -1,69 +1,84 @@
# 净菜组配秤 CHANGELOG
# 净配秤 CHANGELOG
## [2.2.4] - 2026-08-07
### 新增「今日调料需求」一键放置 + 手工配置需求感知
- `04-seasoning-settings.html` 新增净菜订单调料需求面板
- 顶部栏新增「今日调料需求」按钮,显示待放置调料数量徽标
- 展开面板展示当日净菜订单汇总的调料清单(名称 + 所需量)
- 「一键放置全部」按钮按顺序逐格分配调料到空格子(位置1→11)
- 放置时标签高亮动画 + 已放置标签绿色划掉标记
- **手工配置增强**:点击格子选调料时,搜索结果按需求分组
- 需求调料置顶 + 黄色高亮 +「📋 今日需求」角标
- 非需求调料以分隔线区分,标注「其它调料」
- 点击需求项自动回填建议重量
- 确认后自动标记已放置,刷新需求面板
- 8 种 Mock 调料需求数据(盐/酱油/白糖/料酒/味精/蚝油/胡椒粉/豆瓣酱)
## [2.2.3] - 2026-07-06
### 移除份数列 + 调料设置页重构
- `01-packing-tasks.html` — 移除"份数"列,grid 7列→6列;移除按 packSize 拆分行逻辑
- `02-weighing-packing.html` — 移除"配份数"字段和行拆分;移除主辅材和调料的"每份"/"每份用量"字段
- `02-weighing-packing.html` — 移除"配份数"字段和行拆分;移除主辅材和调料的"每份"/"每份用量"字段
- `03-verify-history.html` — 移除"总份数"统计标签和行拆分,grid 6列→5列
- `04-seasoning-settings.html` — 弹窗从下拉框改为搜索框(含搜索结果列表/空状态);油格改为2×2金色信息格,与配页视觉风格对齐;所有调料弹窗统一体验;移除位置编号;去掉"放置重量"标签
- `04-seasoning-settings.html` — 弹窗从下拉框改为搜索框(含搜索结果列表/空状态);油格改为2×2金色信息格,与配页视觉风格对齐;所有调料弹窗统一体验;移除位置编号;去掉"放置重量"标签
## [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` — 行展示按单份拆分("第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` — 移除配确认弹窗(弹窗 CSS + HTML + JS 全部删除);底部按钮区改为 flex 布局
- `02-weighing-packing.html` — 新增 `next-btn--secondary` 样式(绿色边框按钮)
- `03-verify-history.html` — 食材名称同步简化
- `doc/PRD.md` — 食材名称同步简化
## [2.2.1] - 2026-06-26
### 配记录页字段与显示逻辑对齐
- `03-verify-history.html` — 表头与配任务页(01)统一:打包份数→份数、所需总重→应称重量、已称→已称重量
### 配记录页字段与显示逻辑对齐
- `03-verify-history.html` — 表头与配任务页(01)统一:打包份数→份数、所需总重→应称重量、已称→已称重量
- 行展示改为按单份拆分("第N份/M份"),与01页一致
- 状态文案统一:已配→已完成,新增 `hasPendingPack` 判断函数
- 状态文案统一:已配→已完成,新增 `hasPendingPack` 判断函数
- grid 列宽对齐01页,新增 `.parent-weight--done` 绿色完成样式
- 数据层补充 `taskNo` 字段
## [2.2.0] - 2026-06-25
### 配作业页新增净菜类型
- `02-weighing-packing.html` — 食材行数据行新增"净菜类型"项(尺寸·形状·刀工,如 `20mm*1mm*1mm · 细丝 · 平刀`),与净菜加工秤加工规格格式一致
### 配作业页新增净菜类型
- `02-weighing-packing.html` — 食材行数据行新增"净菜类型"项(尺寸·形状·刀工,如 `20mm*1mm*1mm · 细丝 · 平刀`),与厨配秤加工规格格式一致
- 净菜类食材(丝/片/段)显示实际切法规格;菜品类食材(番茄炒蛋/凉拌黄瓜等)显示"—"
- 数据层 ingredients 增加 `cutSpec` 字段,扁平化时传递
## [2.1.0] - 2026-06-25
### 配记录页对齐配任务页
### 配记录页对齐配任务页
- **表头6列**:餐品净菜包名称 / 包装规格 / 打包份数 / 所需总重 / 已称 / 状态(去掉"净菜/餐品"列和操作列)
- **数据结构一致**:只含餐品净菜包,每个包含 ingredients + seasonings,与01页镜像
- **所需总重含调料**:主辅材需求合计 + 调料需求合计
- **状态计算一致**:主辅材+调料全部完成才算"已配",文案统一为待配/已
- **统计行含调料重量**配总重量包含调料已称重量
- **状态计算一致**:主辅材+调料全部完成才算"已配",文案统一为待配/已
- **统计行含调料重量**配总重量包含调料已称重量
## [2.0.0] - 2026-06-25
### 屏幕比例改造
- **全页面纵向 3:4**:所有 7 个页面从横向 1280×72016:9)改为纵向 720×9603:4),viewport 同步更新
- **02 配详情页布局重构**:从横向两列(左识别+右清单)改为纵向上下(上区识别+候选左右排列,下区任务+清单+调料+按钮);body 统一为 PAD 外壳模式
- **03 配记录页**:统一为 PAD 外壳模式(深色画布+居中 device-frame
- **02 配详情页布局重构**:从横向两列(左识别+右清单)改为纵向上下(上区识别+候选左右排列,下区任务+清单+调料+按钮);body 统一为 PAD 外壳模式
- **03 配记录页**:统一为 PAD 外壳模式(深色画布+居中 device-frame
### 重构
- **全局命名**:硬件名称由「净菜配比秤」改为「净菜组配秤」,所有「配比」文案统一改为「配」(配任务/配记录/去配/配完成/配确认/待配)
- **任务列表页(01)**:移除「净菜包」订单,仅展示「餐品净菜包」订单;移除订单级「去配」按钮,改为每个餐品净菜包主行独立「配」按钮;表头精简(去掉「净菜/餐品」列,新增「操作」列)
- **配详情页(02)**:任务信息卡新增「餐品名称」字段;移除清单中「餐品净菜包」名称元信息行;清单拆为「主辅材配」+「调料配」两区
- **调料配区(02)**:3行×5列=15格网格,左上角第一列+第二列的第1、2行4格合并为信息格(固定显示「油」的完整字段:名称/每份用量/份数/应称/已称),其余11格为调料位置格,每个调料格字段与主辅材一致(名称/每份用量/份数/应称/已称)
- **全局命名**:硬件名称由「净菜配比秤」改为「净配秤」,所有「配比」文案统一改为「配」(配任务/配记录/去配/配完成/配确认/待配)
- **任务列表页(01)**:移除「净菜包」订单,仅展示「餐品净菜包」订单;移除订单级「去配」按钮,改为每个餐品净菜包主行独立「配」按钮;表头精简(去掉「净菜/餐品」列,新增「操作」列)
- **配详情页(02)**:任务信息卡新增「餐品名称」字段;移除清单中「餐品净菜包」名称元信息行;清单拆为「主辅材配」+「调料配」两区
- **调料配区(02)**:3行×5列=15格网格,左上角第一列+第二列的第1、2行4格合并为信息格(固定显示「油」的完整字段:名称/每份用量/份数/应称/已称),其余11格为调料位置格,每个调料格字段与主辅材一致(名称/每份用量/份数/应称/已称)
- **调料多高亮状态(02)**:active(当前要称,蓝色脉冲)、next(下一个要称,淡蓝虚线)、done(已完成,绿色),称重确认后自动从 active 切换为 done
- **调料配交互(02)**:不走 AI 识别,点击高亮调料格 → 弹出配确认弹窗 → 读取秤值 → 确认写入,信息格(油)也可点击称重
- **状态判断(02)**:主辅材+调料全部完成才算该餐品净菜包配完成
- **调料配交互(02)**:不走 AI 识别,点击高亮调料格 → 弹出配确认弹窗 → 读取秤值 → 确认写入,信息格(油)也可点击称重
- **状态判断(02)**:主辅材+调料全部完成才算该餐品净菜包配完成
### 新增
- **调料位置设置页(04-seasoning-settings.html**3×5 网格可视化配置调料秤 11 个位置各自放置的调料,点击格子 → 下拉选择调料名称(17种常用调料候选),支持清空/重置/保存(localStorage 持久化)
- **功能菜单(00-welcome.html)**:新增「调料位置设置」入口
- **导航页(index.html)**:新增「调料位置设置」卡片入口
- **canteen-device/index.html**:卡片名称改为「净菜组配秤」,描述更新为「餐品净菜包独立配,主辅材+调料双区称重」
- **canteen-device/index.html**:卡片名称改为「净配秤」,描述更新为「餐品净菜包独立配,主辅材+调料双区称重」
---
@@ -91,18 +106,18 @@
### 重构
- **数据结构扁平化**:任务由"一个订单一个餐品净菜包"改为"一个订单多个净菜包/餐品净菜包"(mealPacks 数组),支持混合打包模式
- **任务列表页(01)**:表格从6列扩展为8列,新增「净菜/餐品」和「包装规格」列;去配不再携带 packName 参数;订单状态由所有包完成才算完成
- **任务列表页(01)**:表格从6列扩展为8列,新增「净菜/餐品」和「包装规格」列;去配不再携带 packName 参数;订单状态由所有包完成才算完成
- **称重打包页(02)**:食材清单从表格布局改为卡片布局,每张卡片展示名称、状态、餐品净菜包归属、包装规格、用量/份数/需/已称
- **配确认弹窗**:AI 识别后不再自动写入重量,改为弹窗展示食材图标、名称、当前秤重,支持刷新读取,需人工点选候选食材并确认
- **配确认弹窗**:AI 识别后不再自动写入重量,改为弹窗展示食材图标、名称、当前秤重,支持刷新读取,需人工点选候选食材并确认
- **候选列表排序**:AI 识别候选按置信度降序排列(不再随机)
### 新增
- 02 页顶部栏新增「退出登录」按钮
- 02 页任务信息卡新增「订单状态」字段(待配/已完成)
- 02 页候选识别区点选食材后弹出配确认弹窗
- 02 页任务信息卡新增「订单状态」字段(待配/已完成)
- 02 页候选识别区点选食材后弹出配确认弹窗
### 删除
- 02 页移除包装信息弹窗(包装方式/保质期/存放温度/终端设备),统一改为配确认弹窗
- 02 页移除包装信息弹窗(包装方式/保质期/存放温度/终端设备),统一改为配确认弹窗
- 02 页顶部栏移除 packTag 展示
---
@@ -1,4 +1,4 @@
# 净菜配比秤 — 产品需求文档
# 净秤 — 产品需求文档
> 原型目录:`other-module/canteen-device/ratio-scale/`
> 创建时间:2026-06-13 | 最后更新:2026-06-16
@@ -7,7 +7,7 @@
## 一、模块概述
菜配比秤是食堂净菜打包流程中的核心硬件终端,承担打包任务管理、净菜识别称重、餐品组合打包三大职能。设备配备触摸屏、称重传感器、食材识别摄像头和人脸识别摄像头,支持「净菜包打包」和「餐品组合打包」两种业务模式。
秤是食堂净菜打包流程中的核心硬件终端,承担打包任务管理、净菜识别称重、餐品组合打包三大职能。设备配备触摸屏、称重传感器、食材识别摄像头和人脸识别摄像头,支持「净菜包打包」和「餐品组合打包」两种业务模式。
### 业务流程
@@ -42,7 +42,7 @@
| 来源页 | 触发操作 | 目标页 | 携带参数 |
|--------|----------|--------|----------|
| 根导航(index.html | 进入净菜配比秤 | 00 登录页 | — |
| 根导航(index.html | 进入净秤 | 00 登录页 | — |
| 00 登录页 | 登录成功 | 00 功能菜单页 | `?user=姓名&uid=工号` |
| 00 功能菜单页 | 点击「今日任务」 | 01 任务列表页 | `?user=...&uid=...` |
| 00 功能菜单页 | 点击「称重打包」 | 02 称重打包页 | `?user=...&uid=...` |
@@ -3,7 +3,7 @@
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=720, initial-scale=1.0">
<title>菜组配秤 - 蚁熊智能餐养平台</title>
<title>净配秤 - 蚁熊智能餐养平台</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
@@ -41,7 +41,7 @@
<div class="device-frame">
<div class="top-bar">
<a class="back-link" href="../index.html">&#x25C0; 返回</a>
<span class="top-bar__title">菜组配秤</span>
<span class="top-bar__title">净配秤</span>
</div>
<div class="main-content">
<a class="card" href="00-login.html">
@@ -56,23 +56,23 @@
<span class="card__icon">&#x1F4CB;</span>
<div class="card__info">
<div class="card__title">功能菜单</div>
<div class="card__desc">配任务入口</div>
<div class="card__desc">配任务入口</div>
</div>
<span class="card__arrow">&#x203A;</span>
</a>
<a class="card" href="01-packing-tasks.html">
<span class="card__icon">&#x1F4E6;</span>
<div class="card__info">
<div class="card__title">配任务</div>
<div class="card__desc">餐品净菜包独立配,主辅材+调料双区</div>
<div class="card__title">配任务</div>
<div class="card__desc">餐品净菜包独立配,主辅材+调料双区</div>
</div>
<span class="card__arrow">&#x203A;</span>
</a>
<a class="card" href="03-verify-history.html">
<span class="card__icon">&#x1F4DD;</span>
<div class="card__info">
<div class="card__title">配记录</div>
<div class="card__desc">历史配记录查看与筛选</div>
<div class="card__title">配记录</div>
<div class="card__desc">历史配记录查看与筛选</div>
</div>
<span class="card__arrow">&#x203A;</span>
</a>
@@ -151,7 +151,7 @@
</div>
</div>
</div>
<!-- 6. 净菜组-->
<!-- 6. 净配 -->
<div class="tl-node">
<div class="tl-left">
<div class="tl-dot" style="border-color:#eb2f96;background:#eb2f961a">🔪</div>
@@ -159,8 +159,8 @@
</div>
<div class="tl-right">
<div class="tl-card">
<div style="display:flex;align-items:center;gap:5px;margin-bottom:3px"><span class="tl-stage" style="color:#eb2f96">🔪 净菜组</span><span class="tl-ok">✅ 正常</span></div>
<div class="tl-title">配任务分支 · 分配至多道菜品</div>
<div style="display:flex;align-items:center;gap:5px;margin-bottom:3px"><span class="tl-stage" style="color:#eb2f96">🔪 净配</span><span class="tl-ok">✅ 正常</span></div>
<div class="tl-title">配任务分支 · 分配至多道菜品</div>
<div class="tl-time">⏱ 2026-04-22 10:20 ~ 10:40</div>
<div class="tl-detail">分支ACMB-001 宫保鸡丁 5.0kg · 分支BCMB-006 辣子鸡 3.5kg</div>
<div class="tl-code">CMB-20260422-001</div>