feat: 净菜配比秤重构为净菜组配秤,纵向3:4布局+调料组配区+调料位置设置页
- 全局命名替换:配比→组配,净菜配比秤→净菜组配秤 - 全页面纵向3:4(720×960)PAD外壳模式 - 任务列表页:仅展示餐品净菜包订单,每餐品净菜包独立组配按钮 - 组配详情页:任务卡增加餐品名称字段,拆为主辅材组配区+调料组配区 - 调料组配区:3×5网格,信息格固定显示油,调料格3种状态(待组配脉冲高亮/已组配绿色/不需要组配无高亮) - 调料组配不走AI识别,点击格子→弹窗读秤→确认写入 - 新增调料位置设置页(04-seasoning-settings.html) - 主辅材清单平铺2列展示不滚动 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.6
parent
ece5afbc74
commit
c3cca6127a
@@ -76,6 +76,43 @@
|
||||
border: 1px solid rgba(255, 255, 255, 0.06);
|
||||
transition: all 0.2s;
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
}
|
||||
/* 卡片右上角研发状态标签 */
|
||||
.card__status {
|
||||
position: absolute;
|
||||
top: 8px;
|
||||
right: 8px;
|
||||
font-size: 10px;
|
||||
line-height: 1;
|
||||
padding: 3px 7px;
|
||||
border-radius: 9px;
|
||||
font-weight: 600;
|
||||
letter-spacing: 0.3px;
|
||||
}
|
||||
/* 已设计 - 绿色 */
|
||||
.card__status--done {
|
||||
background: rgba(34, 197, 94, 0.18);
|
||||
color: #4ade80;
|
||||
border: 1px solid rgba(34, 197, 94, 0.35);
|
||||
}
|
||||
/* 待硬件选型 - 橙色 */
|
||||
.card__status--hw {
|
||||
background: rgba(234, 88, 12, 0.18);
|
||||
color: #fb923c;
|
||||
border: 1px solid rgba(234, 88, 12, 0.35);
|
||||
}
|
||||
/* 待产品设计 - 蓝色 */
|
||||
.card__status--design {
|
||||
background: rgba(37, 99, 235, 0.18);
|
||||
color: #60a5fa;
|
||||
border: 1px solid rgba(37, 99, 235, 0.35);
|
||||
}
|
||||
/* 无需设计 - 灰色 */
|
||||
.card__status--none {
|
||||
background: rgba(255, 255, 255, 0.08);
|
||||
color: rgba(255, 255, 255, 0.4);
|
||||
border: 1px solid rgba(255, 255, 255, 0.12);
|
||||
}
|
||||
.card:hover {
|
||||
transform: translateY(-2px);
|
||||
@@ -115,44 +152,52 @@
|
||||
<div class="section-title">卫生供应</div>
|
||||
<div class="grid">
|
||||
<a class="card" href="raw-veg-hygiene-inspection/index.html">
|
||||
<span class="card__status card__status--hw">待硬件选型</span>
|
||||
<div class="card__icon">🔬</div>
|
||||
<div class="card__name">毛菜卫检设备</div>
|
||||
<div class="card__desc">毛菜卫生检测与质量判定</div>
|
||||
</a>
|
||||
<a class="card" href="raw-veg-inspection-scale/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>
|
||||
</a>
|
||||
<a class="card" href="raw-veg-inventory-cabinet/index.html">
|
||||
<span class="card__status card__status--none">无需设计</span>
|
||||
<div class="card__icon">📦</div>
|
||||
<div class="card__name">毛菜库存柜</div>
|
||||
<div class="card__desc">毛菜库存管理与出入库</div>
|
||||
</a>
|
||||
<a class="card" href="raw-veg-processing-scale/index.html">
|
||||
<span class="card__status card__status--done">已设计</span>
|
||||
<div class="card__icon">🔪</div>
|
||||
<div class="card__name">加工毛菜秤</div>
|
||||
<div class="card__desc">毛菜清洗:AI识别、称重、清洗操作</div>
|
||||
</a>
|
||||
<a class="card" href="clean-veg-ratio-scale/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>
|
||||
</a>
|
||||
<a class="card" href="clean-veg-packaging-labeler/index.html">
|
||||
<div class="card__icon">🏷️</div>
|
||||
<div class="card__name">净菜包装贴标机</div>
|
||||
<div class="card__desc">净菜自动包装与贴标打印</div>
|
||||
</a>
|
||||
<a class="card" href="clean-veg-inventory-cabinet/index.html">
|
||||
<span class="card__status card__status--none">无需设计</span>
|
||||
<div class="card__icon">📦</div>
|
||||
<div class="card__name">净菜库存柜</div>
|
||||
<div class="card__desc">净菜库存管理与盘点</div>
|
||||
</a>
|
||||
<a class="card" href="ratio-scale/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>
|
||||
<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>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
@@ -160,21 +205,25 @@
|
||||
<div class="section-title">健康生产</div>
|
||||
<div class="grid">
|
||||
<a class="card" href="food-safety-monitor/index.html">
|
||||
<span class="card__status card__status--hw">待硬件选型</span>
|
||||
<div class="card__icon">🛡️</div>
|
||||
<div class="card__name">食安监控设备</div>
|
||||
<div class="card__desc">食品安全监控与预警</div>
|
||||
</a>
|
||||
<a class="card" href="utility-meter/index.html">
|
||||
<span class="card__status card__status--none">无需设计</span>
|
||||
<div class="card__icon">⚡</div>
|
||||
<div class="card__name">水电气计量表</div>
|
||||
<div class="card__desc">水电气能耗计量与统计</div>
|
||||
</a>
|
||||
<a class="card" href="clean-veg-kitchen-cabinet/index.html">
|
||||
<span class="card__status card__status--none">无需设计</span>
|
||||
<div class="card__icon">🗄️</div>
|
||||
<div class="card__name">净菜厨房柜</div>
|
||||
<div class="card__desc">净菜暂存与保鲜存储</div>
|
||||
</a>
|
||||
<a class="card" href="processing-prompt-screen/index.html">
|
||||
<span class="card__status card__status--none">无需设计</span>
|
||||
<div class="card__icon">📺</div>
|
||||
<div class="card__name">加工提示屏</div>
|
||||
<div class="card__desc">加工流程提示与操作指引</div>
|
||||
@@ -185,36 +234,43 @@
|
||||
<div class="section-title">营养用餐</div>
|
||||
<div class="grid">
|
||||
<a class="card" href="nutrition-detection/index.html">
|
||||
<span class="card__status card__status--hw">待硬件选型</span>
|
||||
<div class="card__icon">🔍</div>
|
||||
<div class="card__name">营养检测设备</div>
|
||||
<div class="card__desc">营养成分检测与分析</div>
|
||||
</a>
|
||||
<a class="card" href="plate-dispenser/index.html">
|
||||
<span class="card__status card__status--none">无需设计</span>
|
||||
<div class="card__icon">🍽️</div>
|
||||
<div class="card__name">吐盘机</div>
|
||||
<div class="card__desc">自动出盘与回盘管理</div>
|
||||
</a>
|
||||
<a class="card" href="canteen-recharge-screen/index.html">
|
||||
<span class="card__status card__status--design">待产品设计</span>
|
||||
<div class="card__icon">💳</div>
|
||||
<div class="card__name">餐线充值屏</div>
|
||||
<div class="card__desc">餐卡充值与余额查询</div>
|
||||
</a>
|
||||
<a class="card" href="canteen-nutrition-scale/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>
|
||||
</a>
|
||||
<a class="card" href="stall-nutrition-scale/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>
|
||||
</a>
|
||||
<a class="card" href="checkout-device/index.html">
|
||||
<span class="card__status card__status--none">无需设计</span>
|
||||
<div class="card__icon">🧾</div>
|
||||
<div class="card__name">结算设备</div>
|
||||
<div class="card__desc">智能结算与支付</div>
|
||||
</a>
|
||||
<a class="card" href="nutrition-score-screen/index.html">
|
||||
<span class="card__status card__status--none">无需设计</span>
|
||||
<div class="card__icon">📊</div>
|
||||
<div class="card__name">营养得分屏</div>
|
||||
<div class="card__desc">个人营养评分与健康建议</div>
|
||||
|
||||
@@ -2,21 +2,21 @@
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=1280, initial-scale=1.0">
|
||||
<title>净菜配比秤 - 登录 | 蚁熊智能餐养平台</title>
|
||||
<meta name="viewport" content="width=720, 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: 1280px;
|
||||
min-height: 100vh; min-width: 720px;
|
||||
display: flex; align-items: center; justify-content: center;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
/* PAD 设备外壳 */
|
||||
.device-frame {
|
||||
width: 1280px; height: 720px;
|
||||
width: 720px; height: 960px;
|
||||
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);
|
||||
@@ -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">
|
||||
|
||||
@@ -2,21 +2,21 @@
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=1280, initial-scale=1.0">
|
||||
<title>净菜配比秤 - 功能菜单 | 蚁熊智能餐养平台</title>
|
||||
<meta name="viewport" content="width=720, 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: 1280px;
|
||||
min-height: 100vh; min-width: 720px;
|
||||
display: flex; align-items: center; justify-content: center;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
/* PAD 设备外壳 */
|
||||
.device-frame {
|
||||
width: 1280px; height: 720px;
|
||||
width: 720px; height: 960px;
|
||||
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);
|
||||
@@ -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">📋</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>
|
||||
@@ -145,8 +145,16 @@
|
||||
<a class="menu-btn" onclick="handleMenu('03-verify-history.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 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('04-seasoning-settings.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>
|
||||
<div class="menu-btn__arrow">›</div>
|
||||
</a>
|
||||
|
||||
@@ -2,20 +2,20 @@
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=1280, initial-scale=1.0">
|
||||
<title>净菜配比秤 - 配比任务 | 蚁熊智能餐养平台</title>
|
||||
<meta name="viewport" content="width=720, 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: 1280px;
|
||||
min-height: 100vh; min-width: 720px;
|
||||
display: flex; align-items: center; justify-content: center;
|
||||
padding: 20px;
|
||||
}
|
||||
/* PAD 设备外壳 */
|
||||
.device-frame {
|
||||
width: 1280px; height: 720px;
|
||||
width: 720px; height: 960px;
|
||||
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);
|
||||
@@ -61,17 +61,19 @@
|
||||
|
||||
/* 表格头(7列) */
|
||||
.item-table__head {
|
||||
display: grid; grid-template-columns: 1fr 0.65fr 0.6fr 0.5fr 0.65fr 0.6fr 50px; gap: 8px;
|
||||
display: grid; grid-template-columns: 1fr 0.6fr 0.5fr 0.65fr 0.6fr 50px 72px; gap: 8px;
|
||||
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.65fr 0.6fr 0.5fr 0.65fr 0.6fr 50px; gap: 8px;
|
||||
display: grid; grid-template-columns: 1fr 0.6fr 0.5fr 0.65fr 0.6fr 50px 72px; gap: 8px;
|
||||
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;
|
||||
}
|
||||
.item-parent-row:last-child { margin-bottom: 0; }
|
||||
.parent-name { display: flex; align-items: center; gap: 8px; }
|
||||
.parent-icon {
|
||||
width: 32px; height: 32px; border-radius: 6px;
|
||||
@@ -88,7 +90,7 @@
|
||||
|
||||
/* 食材子行 */
|
||||
.item-child-row {
|
||||
display: grid; grid-template-columns: 1fr 0.65fr 0.6fr 0.5fr 0.65fr 0.6fr 50px; gap: 8px;
|
||||
display: grid; grid-template-columns: 1fr 0.6fr 0.5fr 0.65fr 0.6fr 50px 72px; gap: 8px;
|
||||
padding: 8px 16px 8px 48px; border-top: 1px solid rgba(255,255,255,0.03);
|
||||
align-items: center; transition: background 0.2s;
|
||||
}
|
||||
@@ -135,14 +137,14 @@
|
||||
<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>
|
||||
<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>
|
||||
|
||||
@@ -169,7 +171,7 @@
|
||||
/* 当前 Tab 筛选 */
|
||||
var currentFilter = 'pending';
|
||||
|
||||
/* 模拟数据:净菜包=食材名,餐品净菜包=菜名 */
|
||||
/* 模拟数据:仅展示餐品净菜包订单 */
|
||||
var mockData = [
|
||||
{
|
||||
orderNo: 'PO-20260616-001',
|
||||
@@ -177,14 +179,14 @@
|
||||
expectedArrival: '2026-06-17 11:30',
|
||||
taskNo: 'T-001',
|
||||
mealPacks: [
|
||||
{ type: '净菜包', packName: '土豆丝', packSize: 3, packSpec: '500g', notes: '', ingredients: [
|
||||
{ name: '土豆丝', icon: '🥔', iconClass: 'child-icon--potato', weightPerPack: 500, weighed: 750 }
|
||||
]},
|
||||
{ type: '净菜包', packName: '胡萝卜丝', packSize: 3, packSpec: '500g', notes: '', ingredients: [
|
||||
{ name: '胡萝卜丝', icon: '🥕', iconClass: 'child-icon--carrot', weightPerPack: 500, weighed: 750 }
|
||||
]},
|
||||
{ type: '净菜包', packName: '黄瓜片', packSize: 3, packSpec: '500g', notes: '', ingredients: [
|
||||
{ name: '黄瓜片', icon: '🥒', iconClass: 'child-icon--cucumber', weightPerPack: 500, weighed: 0 }
|
||||
{ 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 }
|
||||
], seasonings: [
|
||||
{ name: '盐', cellIdx: 2, weightPerPack: 5, weighed: 0 },
|
||||
{ name: '白糖', cellIdx: 3, weightPerPack: 10, weighed: 0 },
|
||||
{ name: '酱油', cellIdx: 5, weightPerPack: 15, weighed: 0 }
|
||||
]}
|
||||
]
|
||||
},
|
||||
@@ -194,11 +196,19 @@
|
||||
expectedArrival: '2026-06-17 12:00',
|
||||
taskNo: 'T-002',
|
||||
mealPacks: [
|
||||
{ type: '净菜包', packName: '白菜丝', packSize: 2, packSpec: '1000g', notes: '', ingredients: [
|
||||
{ name: '白菜丝', icon: '🥬', iconClass: 'child-icon--cabbage', weightPerPack: 1000, weighed: 0 }
|
||||
{ type: '餐品净菜包', packName: '鱼香肉丝套餐', packSize: 2, packSpec: '大份800g', ingredients: [
|
||||
{ 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: '大份800g', notes: '', ingredients: [
|
||||
{ name: '鱼香肉丝', icon: '🥘', iconClass: 'child-icon--tomato', weightPerPack: 500, weighed: 0 }
|
||||
{ type: '餐品净菜包', packName: '番茄炒蛋套餐', packSize: 2, packSpec: '标准500g', ingredients: [
|
||||
{ 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 }
|
||||
]}
|
||||
]
|
||||
},
|
||||
@@ -208,8 +218,11 @@
|
||||
expectedArrival: '2026-06-17 14:30',
|
||||
taskNo: 'T-003',
|
||||
mealPacks: [
|
||||
{ type: '餐品净菜包', packName: '番茄炒蛋套餐', packSize: 4, packSpec: '真空包装', notes: '', ingredients: [
|
||||
{ name: '番茄炒蛋', icon: '🥘', iconClass: 'child-icon--tomato', weightPerPack: 500, weighed: 2000 }
|
||||
{ type: '餐品净菜包', packName: '番茄炒蛋套餐', packSize: 4, packSpec: '真空包装', ingredients: [
|
||||
{ name: '番茄炒蛋', icon: '🥘', weightPerPack: 500, weighed: 2000 }
|
||||
], seasonings: [
|
||||
{ name: '盐', cellIdx: 2, weightPerPack: 5, weighed: 20 },
|
||||
{ name: '白糖', cellIdx: 3, weightPerPack: 8, weighed: 32 }
|
||||
]}
|
||||
]
|
||||
},
|
||||
@@ -219,27 +232,37 @@
|
||||
expectedArrival: '2026-06-17 16:00',
|
||||
taskNo: 'T-004',
|
||||
mealPacks: [
|
||||
{ type: '餐品净菜包', packName: '凉拌黄瓜套餐', packSize: 5, packSpec: '盒装', notes: '', ingredients: [
|
||||
{ name: '凉拌黄瓜', icon: '🥘', iconClass: 'child-icon--cucumber', weightPerPack: 500, weighed: 2500 }
|
||||
{ type: '餐品净菜包', packName: '凉拌黄瓜套餐', packSize: 5, packSpec: '盒装', ingredients: [
|
||||
{ name: '凉拌黄瓜', icon: '🥘', weightPerPack: 500, weighed: 2500 }
|
||||
], seasonings: [
|
||||
{ name: '醋', cellIdx: 2, weightPerPack: 6, weighed: 30 },
|
||||
{ name: '酱油', cellIdx: 3, weightPerPack: 10, weighed: 50 }
|
||||
]}
|
||||
]
|
||||
}
|
||||
];
|
||||
|
||||
/* 获取餐品净菜包状态 */
|
||||
/* 获取餐品净菜包状态:主辅材+调料全部完成才算完成 */
|
||||
function getPackStatus(pack) {
|
||||
var allDone = pack.ingredients.every(function(ing) {
|
||||
var ingDone = pack.ingredients.every(function(ing) {
|
||||
return ing.weighed >= ing.weightPerPack * pack.packSize;
|
||||
});
|
||||
if (allDone) return { text: '已完成', cls: 'status-badge--done' };
|
||||
return { text: '待配比', cls: 'status-badge--pending' };
|
||||
var seaDone = !pack.seasonings || pack.seasonings.every(function(sea) {
|
||||
return sea.weighed >= sea.weightPerPack * pack.packSize;
|
||||
});
|
||||
if (ingDone && seaDone) return { text: '已完成', cls: 'status-badge--done' };
|
||||
return { text: '待组配', cls: 'status-badge--pending' };
|
||||
}
|
||||
|
||||
/* 判断餐品净菜包是否有待配比项 */
|
||||
/* 判断餐品净菜包是否有待组配项(主辅材或调料) */
|
||||
function hasPendingPack(pack) {
|
||||
return pack.ingredients.some(function(ing) {
|
||||
var ingPending = pack.ingredients.some(function(ing) {
|
||||
return ing.weighed < ing.weightPerPack * pack.packSize;
|
||||
});
|
||||
var seaPending = pack.seasonings && pack.seasonings.some(function(sea) {
|
||||
return sea.weighed < sea.weightPerPack * pack.packSize;
|
||||
});
|
||||
return ingPending || seaPending;
|
||||
}
|
||||
|
||||
/* 渲染任务列表 */
|
||||
@@ -259,7 +282,7 @@
|
||||
var taskCard = document.createElement('div');
|
||||
taskCard.className = 'task-card';
|
||||
|
||||
/* 合并行:订单号 + 任务号 + 期望到货 + 状态 + 去配比 */
|
||||
/* 合并行:订单号 + 任务号 + 期望到货 + 状态 */
|
||||
var header = document.createElement('div');
|
||||
header.className = 'task-card__header';
|
||||
var orderTypeLabel = order.orderType === 'internal' ? '内供订单' : '外售订单';
|
||||
@@ -268,16 +291,13 @@
|
||||
'<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">⏰ ' + (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>' +
|
||||
(orderAllDone
|
||||
? ''
|
||||
: '<button class="task-card__pack-btn" onclick="handleWeigh(\'' + order.taskNo + '\',\'' + order.orderNo + '\')">去配比</button>');
|
||||
'<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: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:right">所需总重</div><div style="text-align:right">已称</div><div style="text-align:center">状态</div><div style="text-align:center">操作</div>';
|
||||
taskCard.appendChild(tableHead);
|
||||
|
||||
/* 表格体 */
|
||||
@@ -286,27 +306,36 @@
|
||||
|
||||
packs.forEach(function(pack) {
|
||||
var packStatus = getPackStatus(pack);
|
||||
var totalNeed = 0;
|
||||
var totalWeighed = 0;
|
||||
/* 主辅材合计 */
|
||||
var ingNeed = 0, ingWeighed = 0;
|
||||
pack.ingredients.forEach(function(ing) {
|
||||
totalNeed += ing.weightPerPack * pack.packSize;
|
||||
totalWeighed += ing.weighed;
|
||||
ingNeed += ing.weightPerPack * pack.packSize;
|
||||
ingWeighed += ing.weighed;
|
||||
});
|
||||
totalNeed = Math.round(totalNeed * 100) / 100;
|
||||
totalWeighed = Math.round(totalWeighed * 100) / 100;
|
||||
/* 调料合计 */
|
||||
var seaNeed = 0, seaWeighed = 0;
|
||||
if (pack.seasonings) {
|
||||
pack.seasonings.forEach(function(sea) {
|
||||
seaNeed += sea.weightPerPack * pack.packSize;
|
||||
seaWeighed += sea.weighed;
|
||||
});
|
||||
}
|
||||
var totalNeed = Math.round((ingNeed + seaNeed) * 100) / 100;
|
||||
var totalWeighed = Math.round((ingWeighed + seaWeighed) * 100) / 100;
|
||||
var weightClass = totalWeighed >= totalNeed ? 'parent-weight--done' : '';
|
||||
var packDone = !hasPendingPack(pack);
|
||||
|
||||
/* 主行:餐品净菜包 */
|
||||
/* 主行:餐品净菜包 + 独立组配按钮 */
|
||||
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:12px;color:' + (pack.type === '餐品净菜包' ? '#faad16' : '#4a90d9') + '">' + pack.type + '</div>' +
|
||||
'<div style="text-align:center;font-size:12px;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 + ' 克</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"><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);
|
||||
|
||||
});
|
||||
@@ -327,8 +356,8 @@
|
||||
el.classList.add('active');
|
||||
|
||||
document.querySelectorAll('.task-card').forEach(function(card) {
|
||||
var packBtn = card.querySelector('.task-card__pack-btn');
|
||||
var hasPending = packBtn && !packBtn.disabled;
|
||||
var packBtns = card.querySelectorAll('.task-card__pack-btn');
|
||||
var hasPending = packBtns.length > 0;
|
||||
if (filter === 'pending') {
|
||||
card.style.display = hasPending ? 'block' : 'none';
|
||||
} else {
|
||||
@@ -337,9 +366,9 @@
|
||||
});
|
||||
}
|
||||
|
||||
/* 去配比 */
|
||||
function handleWeigh(taskNo, orderNo) {
|
||||
var target = '02-weighing-packing.html?task=' + taskNo + '&order=' + encodeURIComponent(orderNo);
|
||||
/* 进入餐品净菜包组配详情 */
|
||||
function handlePackWeigh(taskNo, orderNo, packName) {
|
||||
var target = '02-weighing-packing.html?task=' + taskNo + '&order=' + encodeURIComponent(orderNo) + '&pack=' + packName;
|
||||
if (userName) target += '&user=' + encodeURIComponent(userName);
|
||||
window.location.href = target;
|
||||
}
|
||||
@@ -357,7 +386,7 @@
|
||||
|
||||
/* 初始化 */
|
||||
renderTaskList();
|
||||
/* 初始过滤:待配比 Tab 默认不显示已完成订单 */
|
||||
/* 初始过滤:待组配 Tab 默认不显示已完成订单 */
|
||||
switchTab('pending', document.querySelector('.tab[data-filter="pending"]'));
|
||||
|
||||
/* 返回按钮 */
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -2,13 +2,25 @@
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=1280, initial-scale=1.0">
|
||||
<title>净菜配比秤 - 配比记录 | 蚁熊智能餐养平台</title>
|
||||
<meta name="viewport" content="width=720, 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: #0e1326; color: #fff; width: 1280px; height: 720px; overflow: hidden;
|
||||
background: #05080f; color: #fff;
|
||||
min-height: 100vh; min-width: 720px;
|
||||
display: flex; align-items: center; justify-content: center;
|
||||
padding: 20px;
|
||||
}
|
||||
/* PAD 设备外壳 */
|
||||
.device-frame {
|
||||
width: 720px; height: 960px;
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -272,9 +284,10 @@
|
||||
</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="page-title">组配记录</span>
|
||||
<span class="top-bar__user" id="topUser">--</span>
|
||||
<button class="logout-btn" onclick="handleLogout()">退出</button>
|
||||
</div>
|
||||
@@ -313,11 +326,11 @@
|
||||
<div class="stats-row">
|
||||
<div class="stat-chip">
|
||||
<div class="stat-chip__icon stat-chip__icon--blue">📋</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">⚖️</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">🥬</div>
|
||||
@@ -336,10 +349,11 @@
|
||||
</div>
|
||||
<div class="empty-state" id="emptyState">
|
||||
<div class="empty-state__icon">📭</div>
|
||||
<div>暂无配比记录</div>
|
||||
<div>暂无组配记录</div>
|
||||
</div>
|
||||
<div class="table-footer" id="tableFooter">共 0 条记录</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
/* 退出登录 */
|
||||
@@ -363,7 +377,7 @@
|
||||
var TODAY = '2026-06-16';
|
||||
var WEEKDAYS = ['周日', '周一', '周二', '周三', '周四', '周五', '周六'];
|
||||
|
||||
// 配比记录数据(按订单组织,对齐配比任务页字段结构)
|
||||
// 组配记录数据(按订单组织,对齐组配任务页字段结构)
|
||||
var RECORDS = [
|
||||
{
|
||||
orderNo: 'PO-20260616-001', orderType: 'internal', completeTime: '2026-06-16 10:20',
|
||||
@@ -524,10 +538,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;
|
||||
@@ -603,7 +617,7 @@
|
||||
return ing.weighed >= ing.weightPerPack * pack.packSize;
|
||||
});
|
||||
if (allDone) return { text: '已完成', cls: 'status-badge--done' };
|
||||
return { text: '待配比', cls: 'status-badge--pending' };
|
||||
return { text: '待组配', cls: 'status-badge--pending' };
|
||||
}
|
||||
|
||||
// 渲染卡片列表
|
||||
@@ -624,7 +638,7 @@
|
||||
|
||||
records.forEach(function(order) {
|
||||
var packs = order.mealPacks;
|
||||
var orderAllDone = packs.every(function(p) { return !getPackStatus(p).text !== '待配比'; });
|
||||
var orderAllDone = packs.every(function(p) { return !getPackStatus(p).text !== '待组配'; });
|
||||
|
||||
var taskCard = document.createElement('div');
|
||||
taskCard.className = 'task-card';
|
||||
|
||||
@@ -0,0 +1,484 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=720, 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: 720px;
|
||||
display: flex; align-items: center; justify-content: center;
|
||||
padding: 20px;
|
||||
}
|
||||
/* PAD 设备外壳 */
|
||||
.device-frame {
|
||||
width: 720px; height: 960px;
|
||||
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: 44px; background: #1a2b4a; padding: 0 20px; }
|
||||
.back-btn { font-size: 14px; cursor: pointer; color: rgba(255,255,255,0.7); text-decoration: none; transition: color 0.2s; }
|
||||
.back-btn:hover { color: #fff; }
|
||||
.top-bar__title { flex: 1; text-align: center; font-size: 15px; font-weight: 600; color: rgba(255,255,255,0.85); }
|
||||
.top-bar__user { font-size: 12px; color: rgba(255,255,255,0.5); }
|
||||
|
||||
/* 主内容 */
|
||||
.main-content { flex: 1; padding: 20px 40px; display: flex; flex-direction: column; gap: 16px; overflow: hidden; }
|
||||
|
||||
/* 说明栏 */
|
||||
.info-bar {
|
||||
display: flex; align-items: center; gap: 12px;
|
||||
background: rgba(74,144,217,0.08); border: 1px solid rgba(74,144,217,0.2);
|
||||
border-radius: 10px; padding: 10px 16px; font-size: 12px; color: rgba(255,255,255,0.6);
|
||||
}
|
||||
.info-bar__icon { font-size: 16px; }
|
||||
.info-bar__text { flex: 1; line-height: 1.5; }
|
||||
.info-bar__save-btn {
|
||||
padding: 6px 16px; border-radius: 6px; border: none; cursor: pointer;
|
||||
background: #4a90d9; color: #fff; font-size: 13px; font-weight: 600;
|
||||
transition: all 0.2s; flex-shrink: 0;
|
||||
}
|
||||
.info-bar__save-btn:hover { background: #5ba0e9; }
|
||||
.info-bar__save-btn:active { transform: scale(0.97); }
|
||||
.info-bar__reset-btn {
|
||||
padding: 6px 14px; border-radius: 6px; cursor: pointer;
|
||||
background: rgba(255,255,255,0.06); color: rgba(255,255,255,0.6);
|
||||
border: 1px solid rgba(255,255,255,0.12); font-size: 13px; transition: all 0.2s; flex-shrink: 0;
|
||||
}
|
||||
.info-bar__reset-btn:hover { background: rgba(255,255,255,0.1); color: #fff; }
|
||||
|
||||
/* 调料秤网格 */
|
||||
.grid-container {
|
||||
flex: 1; display: flex; align-items: center; justify-content: center;
|
||||
}
|
||||
.seasoning-grid {
|
||||
width: 640px;
|
||||
display: grid;
|
||||
grid-template-columns: repeat(5, 1fr);
|
||||
grid-template-rows: repeat(3, 120px);
|
||||
gap: 8px;
|
||||
}
|
||||
/* 信息格(第一列+第二列的第1、2行4格合并) */
|
||||
.seasoning-cell {
|
||||
background: #1a2b4a; border: 1px solid rgba(255,255,255,0.08);
|
||||
border-radius: 10px; padding: 8px 10px;
|
||||
display: flex; flex-direction: column; justify-content: center;
|
||||
transition: all 0.2s; position: relative; overflow: hidden;
|
||||
}
|
||||
.seasoning-cell--info {
|
||||
grid-column: 1 / span 2; grid-row: 1 / span 2;
|
||||
background: rgba(250,173,21,0.08); border-color: rgba(250,173,21,0.25);
|
||||
align-items: center; justify-content: center; text-align: center; gap: 8px;
|
||||
}
|
||||
.seasoning-cell--info .info__icon { font-size: 36px; }
|
||||
.seasoning-cell--info .info__title { font-size: 18px; font-weight: 700; color: #faad14; }
|
||||
.seasoning-cell--info .info__weight { font-size: 13px; color: rgba(255,255,255,0.6); }
|
||||
.seasoning-cell--info .info__label { font-size: 11px; color: rgba(255,255,255,0.4); }
|
||||
.seasoning-cell--info .info__edit-hint { font-size: 10px; color: rgba(255,255,255,0.25); margin-top: 4px; }
|
||||
|
||||
/* 调料格 */
|
||||
.seasoning-cell--slot { cursor: pointer; }
|
||||
.seasoning-cell--slot:hover {
|
||||
border-color: rgba(74,144,217,0.4); background: rgba(74,144,217,0.06);
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
.seasoning-cell--occupied { border-color: rgba(255,255,255,0.15); }
|
||||
.sea-slot__pos {
|
||||
position: absolute; top: 4px; right: 6px;
|
||||
font-size: 11px; color: rgba(255,255,255,0.25); font-weight: 600;
|
||||
}
|
||||
.sea-slot__name {
|
||||
font-size: 14px; font-weight: 600; color: rgba(255,255,255,0.85);
|
||||
text-align: center; margin-top: 4px;
|
||||
}
|
||||
.sea-slot__spec {
|
||||
font-size: 11px; color: rgba(255,255,255,0.4); text-align: center; margin-top: 2px;
|
||||
}
|
||||
.sea-slot__weight-tag {
|
||||
display: inline-block; font-size: 10px; padding: 1px 6px; border-radius: 3px;
|
||||
background: rgba(250,173,21,0.12); color: #faad14; margin-top: 2px;
|
||||
}
|
||||
.sea-slot__empty {
|
||||
font-size: 12px; color: rgba(255,255,255,0.2); text-align: center;
|
||||
}
|
||||
.sea-slot__icon { font-size: 22px; text-align: center; }
|
||||
|
||||
/* 下拉选择浮层 */
|
||||
.select-overlay {
|
||||
position: fixed; inset: 0; background: rgba(0,0,0,0.5); z-index: 100;
|
||||
display: none; align-items: center; justify-content: center;
|
||||
}
|
||||
.select-overlay.show { display: flex; }
|
||||
.select-panel {
|
||||
background: #1a2b4a; border-radius: 14px; border: 1px solid rgba(255,255,255,0.08);
|
||||
padding: 20px 24px; width: 420px; display: flex; flex-direction: column; gap: 14px;
|
||||
}
|
||||
.select-panel__title {
|
||||
font-size: 14px; font-weight: 600; color: rgba(255,255,255,0.85);
|
||||
display: flex; align-items: center; gap: 8px;
|
||||
}
|
||||
.select-panel__pos-tag {
|
||||
font-size: 11px; padding: 2px 8px; border-radius: 4px;
|
||||
background: rgba(74,144,217,0.15); color: #4a90d9; font-weight: 600;
|
||||
}
|
||||
.select-panel__select-wrap { position: relative; }
|
||||
.select-panel__select {
|
||||
width: 100%; padding: 10px 14px; background: #121832;
|
||||
border: 1px solid rgba(255,255,255,0.1); border-radius: 8px;
|
||||
color: #fff; font-size: 14px; outline: none; transition: border-color 0.2s;
|
||||
appearance: none; -webkit-appearance: none; cursor: pointer;
|
||||
font-family: inherit;
|
||||
}
|
||||
.select-panel__select:focus { border-color: #4a90d9; }
|
||||
.select-panel__select-arrow {
|
||||
position: absolute; right: 12px; top: 50%; transform: translateY(-50%);
|
||||
font-size: 12px; color: rgba(255,255,255,0.4); pointer-events: none;
|
||||
}
|
||||
/* 重量输入行 */
|
||||
.select-panel__weight-row { display: flex; align-items: center; gap: 10px; }
|
||||
.select-panel__weight-label { font-size: 13px; color: rgba(255,255,255,0.6); flex-shrink: 0; }
|
||||
.select-panel__weight-input {
|
||||
flex: 1; padding: 10px 14px; background: #121832;
|
||||
border: 1px solid rgba(255,255,255,0.1); border-radius: 8px;
|
||||
color: #fff; font-size: 14px; outline: none; transition: border-color 0.2s;
|
||||
font-family: inherit; -moz-appearance: textfield;
|
||||
}
|
||||
.select-panel__weight-input:focus { border-color: #faad14; }
|
||||
.select-panel__weight-input::-webkit-outer-spin-button,
|
||||
.select-panel__weight-input::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
|
||||
.select-panel__weight-unit { font-size: 13px; color: rgba(255,255,255,0.4); }
|
||||
.select-panel__actions { display: flex; gap: 10px; }
|
||||
.select-panel__btn {
|
||||
flex: 1; padding: 10px 0; border-radius: 8px; font-size: 13px; font-weight: 600;
|
||||
cursor: pointer; transition: all 0.2s; border: none; font-family: inherit;
|
||||
}
|
||||
.select-panel__btn--clear {
|
||||
background: rgba(255,77,79,0.08); color: rgba(255,77,79,0.7);
|
||||
border: 1px solid rgba(255,77,79,0.2);
|
||||
}
|
||||
.select-panel__btn--clear:hover { background: rgba(255,77,79,0.18); color: #ff4d4f; }
|
||||
.select-panel__btn--cancel {
|
||||
background: rgba(255,255,255,0.08); color: rgba(255,255,255,0.6);
|
||||
}
|
||||
.select-panel__btn--cancel:hover { background: rgba(255,255,255,0.12); color: #fff; }
|
||||
.select-panel__btn--confirm {
|
||||
background: #4a90d9; color: #fff;
|
||||
}
|
||||
.select-panel__btn--confirm:hover { background: #5ba0e9; }
|
||||
|
||||
/* 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); }
|
||||
.toast--error { background: rgba(255,77,79,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="top-bar__title">调料位置设置</span>
|
||||
<span class="top-bar__user" id="topUser">--</span>
|
||||
</div>
|
||||
|
||||
<div class="main-content">
|
||||
<!-- 说明栏 -->
|
||||
<div class="info-bar">
|
||||
<span class="info-bar__icon">💡</span>
|
||||
<span class="info-bar__text">点击格子配置调料名称和放置重量。左上信息格固定为「油」,可修改放置重量。配置完成后点击「保存」生效。</span>
|
||||
<button class="info-bar__reset-btn" onclick="resetConfig()">重置</button>
|
||||
<button class="info-bar__save-btn" onclick="saveConfig()">保存</button>
|
||||
</div>
|
||||
|
||||
<!-- 调料秤网格 -->
|
||||
<div class="grid-container">
|
||||
<div class="seasoning-grid" id="seasoningGrid">
|
||||
<!-- 动态渲染 -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 下拉选择浮层 -->
|
||||
<div class="select-overlay" id="selectOverlay">
|
||||
<div class="select-panel">
|
||||
<div class="select-panel__title">
|
||||
选择调料
|
||||
<span class="select-panel__pos-tag" id="posTag">位置 --</span>
|
||||
</div>
|
||||
<div class="select-panel__select-wrap">
|
||||
<select class="select-panel__select" id="seasoningSelect">
|
||||
<option value="">-- 请选择调料 --</option>
|
||||
</select>
|
||||
<span class="select-panel__select-arrow">▼</span>
|
||||
</div>
|
||||
<div class="select-panel__weight-row">
|
||||
<span class="select-panel__weight-label">放置重量:</span>
|
||||
<input type="number" class="select-panel__weight-input" id="seasoningWeight" min="0" step="0.1" placeholder="0">
|
||||
<span class="select-panel__weight-unit">克</span>
|
||||
</div>
|
||||
<div class="select-panel__actions">
|
||||
<button class="select-panel__btn select-panel__btn--clear" onclick="clearSlot()">清空</button>
|
||||
<button class="select-panel__btn select-panel__btn--cancel" onclick="closeSelect()">取消</button>
|
||||
<button class="select-panel__btn select-panel__btn--confirm" onclick="confirmSelect()">确认</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="toast" id="toast"></div>
|
||||
|
||||
<script>
|
||||
/* 获取 URL 参数 */
|
||||
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');
|
||||
if (userName) document.getElementById('topUser').textContent = '操作员: ' + userName;
|
||||
|
||||
/* 调料候选清单 */
|
||||
var SEASONING_OPTIONS = [
|
||||
{ name: '油', icon: '🛢' },
|
||||
{ name: '盐', icon: '🧂' },
|
||||
{ name: '白糖', icon: '🧂' },
|
||||
{ name: '酱油', icon: '🥩' },
|
||||
{ name: '醋', icon: '🥩' },
|
||||
{ name: '味精', icon: '🧂' },
|
||||
{ name: '鸡精', icon: '🧂' },
|
||||
{ name: '料酒', icon: '🍷' },
|
||||
{ name: '胡椒粉', icon: '🧂' },
|
||||
{ name: '豆瓣酱', icon: '🥬' },
|
||||
{ name: '甜面酱', icon: '🥬' },
|
||||
{ name: '蚝油', icon: '🍯' },
|
||||
{ name: '花椒', icon: '🌿' },
|
||||
{ name: '八角', icon: '🌿' },
|
||||
{ name: '桂皮', icon: '🌿' },
|
||||
{ name: '干辣椒', icon: '🌶' },
|
||||
{ name: '蒜蓉', icon: '🧄' },
|
||||
{ name: '姜末', icon: '🥜' }
|
||||
];
|
||||
|
||||
/* 存储键名 */
|
||||
var STORAGE_KEY = 'seasoning_position_config_v2';
|
||||
|
||||
/* 当前编辑的位置(0=信息格油,1-11=调料格) */
|
||||
var editingPos = -1;
|
||||
|
||||
/* 加载配置(兼容旧格式 {pos:'name'} → 新格式 {pos:{name,weight}}) */
|
||||
function loadConfig() {
|
||||
var raw = localStorage.getItem(STORAGE_KEY);
|
||||
if (raw) {
|
||||
try { return JSON.parse(raw); } catch(e) {}
|
||||
}
|
||||
/* 默认配置 */
|
||||
return {
|
||||
0: { name: '油', weight: 1000 },
|
||||
1: { name: '盐', weight: 500 },
|
||||
2: { name: '白糖', weight: 500 },
|
||||
3: { name: '酱油', weight: 1000 },
|
||||
4: { name: '醋', weight: 500 },
|
||||
5: { name: '味精', weight: 250 },
|
||||
6: { name: '料酒', weight: 500 }
|
||||
};
|
||||
}
|
||||
|
||||
/* 保存配置 */
|
||||
function saveConfigData(config) {
|
||||
localStorage.setItem(STORAGE_KEY, JSON.stringify(config));
|
||||
}
|
||||
|
||||
var config = loadConfig();
|
||||
|
||||
/* 渲染网格 */
|
||||
function renderGrid() {
|
||||
var grid = document.getElementById('seasoningGrid');
|
||||
grid.innerHTML = '';
|
||||
|
||||
/* 信息格:固定显示"油" */
|
||||
var infoCell = document.createElement('div');
|
||||
infoCell.className = 'seasoning-cell seasoning-cell--info';
|
||||
var oilCfg = config[0] || { name: '油', weight: 0 };
|
||||
infoCell.innerHTML =
|
||||
'<div class="info__icon">🛢</div>' +
|
||||
'<div class="info__title">油</div>' +
|
||||
'<div class="info__weight"><span class="info__label">放置重量:</span> ' + oilCfg.weight + 'g</div>' +
|
||||
'<div class="info__edit-hint">点击修改重量</div>';
|
||||
infoCell.style.cursor = 'pointer';
|
||||
infoCell.onclick = function() { openSelect(0); };
|
||||
grid.appendChild(infoCell);
|
||||
|
||||
/* 11 个调料位置 */
|
||||
for (var pos = 1; pos <= 11; pos++) {
|
||||
var cell = document.createElement('div');
|
||||
cell.className = 'seasoning-cell seasoning-cell--slot';
|
||||
var cfg = config[pos];
|
||||
if (cfg && cfg.name) {
|
||||
cell.classList.add('seasoning-cell--occupied');
|
||||
var opt = SEASONING_OPTIONS.find(function(o) { return o.name === cfg.name; });
|
||||
var icon = opt ? opt.icon : '🧂';
|
||||
cell.innerHTML =
|
||||
'<span class="sea-slot__pos">' + pos + '</span>' +
|
||||
'<div class="sea-slot__icon">' + icon + '</div>' +
|
||||
'<div class="sea-slot__name">' + cfg.name + '</div>' +
|
||||
'<div class="sea-slot__weight-tag">' + (cfg.weight || 0) + 'g</div>';
|
||||
} else {
|
||||
cell.innerHTML =
|
||||
'<span class="sea-slot__pos">' + pos + '</span>' +
|
||||
'<div class="sea-slot__empty">点击配置</div>';
|
||||
}
|
||||
cell.onclick = (function(p) { return function() { openSelect(p); }; })(pos);
|
||||
grid.appendChild(cell);
|
||||
}
|
||||
}
|
||||
|
||||
/* 打开下拉选择 */
|
||||
function openSelect(pos) {
|
||||
editingPos = pos;
|
||||
document.getElementById('posTag').textContent = pos === 0 ? '信息格 (油)' : '位置 ' + pos;
|
||||
/* 信息格时调整标题和按钮 */
|
||||
var clearBtn = document.querySelector('.select-panel__btn--clear');
|
||||
if (pos === 0) {
|
||||
document.querySelector('.select-panel__title').firstChild.textContent = '修改油量 ';
|
||||
clearBtn.textContent = '重置';
|
||||
} else {
|
||||
document.querySelector('.select-panel__title').firstChild.textContent = '选择调料 ';
|
||||
clearBtn.textContent = '清空';
|
||||
}
|
||||
|
||||
/* 填充下拉选项 */
|
||||
var select = document.getElementById('seasoningSelect');
|
||||
select.innerHTML = '<option value="">-- 请选择调料 --</option>';
|
||||
SEASONING_OPTIONS.forEach(function(o) {
|
||||
var opt = document.createElement('option');
|
||||
opt.value = o.name;
|
||||
opt.textContent = o.name;
|
||||
if (config[pos] && config[pos].name === o.name) opt.selected = true;
|
||||
select.appendChild(opt);
|
||||
});
|
||||
|
||||
/* 信息格固定为油,禁用下拉 */
|
||||
if (pos === 0) {
|
||||
select.value = '油';
|
||||
select.disabled = true;
|
||||
select.style.opacity = '0.6';
|
||||
} else {
|
||||
select.disabled = false;
|
||||
select.style.opacity = '1';
|
||||
}
|
||||
|
||||
/* 填充重量 */
|
||||
var weightInput = document.getElementById('seasoningWeight');
|
||||
weightInput.value = (config[pos] && config[pos].weight) ? config[pos].weight : '';
|
||||
|
||||
document.getElementById('selectOverlay').classList.add('show');
|
||||
}
|
||||
|
||||
/* 确认选择 */
|
||||
function confirmSelect() {
|
||||
var select = document.getElementById('seasoningSelect');
|
||||
var name = select.value;
|
||||
var weight = parseFloat(document.getElementById('seasoningWeight').value) || 0;
|
||||
|
||||
if (editingPos === 0) {
|
||||
/* 信息格只改重量 */
|
||||
config[0] = { name: '油', weight: weight };
|
||||
renderGrid();
|
||||
closeSelect();
|
||||
showToast('油的放置重量已更新为 ' + weight + 'g', 1500, 'success');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!name) {
|
||||
showToast('请选择调料', 1500, 'error');
|
||||
return;
|
||||
}
|
||||
config[editingPos] = { name: name, weight: weight };
|
||||
renderGrid();
|
||||
closeSelect();
|
||||
showToast('位置 ' + editingPos + ' 已配置为 ' + name + ' (' + weight + 'g)', 1500, 'success');
|
||||
}
|
||||
|
||||
/* 清空位置 */
|
||||
function clearSlot() {
|
||||
if (editingPos === 0) {
|
||||
/* 信息格恢复默认重量 */
|
||||
config[0] = { name: '油', weight: 1000 };
|
||||
renderGrid();
|
||||
closeSelect();
|
||||
showToast('油重量已重置为 1000g', 1500, 'success');
|
||||
return;
|
||||
}
|
||||
delete config[editingPos];
|
||||
renderGrid();
|
||||
closeSelect();
|
||||
showToast('位置 ' + editingPos + ' 已清空', 1500, 'success');
|
||||
}
|
||||
|
||||
/* 关闭选择 */
|
||||
function closeSelect() {
|
||||
editingPos = -1;
|
||||
document.getElementById('selectOverlay').classList.remove('show');
|
||||
}
|
||||
|
||||
/* 保存配置 */
|
||||
function saveConfig() {
|
||||
saveConfigData(config);
|
||||
showToast('调料位置配置已保存', 2000, 'success');
|
||||
}
|
||||
|
||||
/* 重置配置 */
|
||||
function resetConfig() {
|
||||
if (!confirm('确定重置所有调料位置配置?')) return;
|
||||
config = {};
|
||||
saveConfigData(config);
|
||||
renderGrid();
|
||||
showToast('配置已重置', 1500, 'success');
|
||||
}
|
||||
|
||||
/* Toast */
|
||||
function showToast(msg, duration, type) {
|
||||
var el = document.getElementById('toast');
|
||||
el.textContent = msg;
|
||||
el.className = 'toast';
|
||||
if (type === 'error') el.classList.add('toast--error');
|
||||
if (type === 'success') el.classList.add('toast--success');
|
||||
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 = '00-welcome.html' + (userName ? '?user=' + encodeURIComponent(userName) : '');
|
||||
}
|
||||
}
|
||||
})();
|
||||
|
||||
/* 初始化 */
|
||||
renderGrid();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,4 +1,28 @@
|
||||
# 净菜配比秤 CHANGELOG
|
||||
# 净菜组配秤 CHANGELOG
|
||||
|
||||
## [2.0.0] - 2026-06-25
|
||||
|
||||
### 屏幕比例改造
|
||||
- **全页面纵向 3:4**:所有 7 个页面从横向 1280×720(16:9)改为纵向 720×960(3:4),viewport 同步更新
|
||||
- **02 组配详情页布局重构**:从横向两列(左识别+右清单)改为纵向上下(上区识别+候选左右排列,下区任务+清单+调料+按钮);body 统一为 PAD 外壳模式
|
||||
- **03 组配记录页**:统一为 PAD 外壳模式(深色画布+居中 device-frame)
|
||||
|
||||
### 重构
|
||||
- **全局命名**:硬件名称由「净菜配比秤」改为「净菜组配秤」,所有「配比」文案统一改为「组配」(组配任务/组配记录/去组配/组配完成/组配确认/待组配)
|
||||
- **任务列表页(01)**:移除「净菜包」订单,仅展示「餐品净菜包」订单;移除订单级「去组配」按钮,改为每个餐品净菜包主行独立「组配」按钮;表头精简(去掉「净菜/餐品」列,新增「操作」列)
|
||||
- **组配详情页(02)**:任务信息卡新增「餐品名称」字段;移除清单中「餐品净菜包」名称元信息行;清单拆为「主辅材组配」+「调料组配」两区
|
||||
- **调料组配区(02)**:3行×5列=15格网格,左上角第一列+第二列的第1、2行4格合并为信息格(固定显示「油」的完整字段:名称/每份用量/份数/应称/已称),其余11格为调料位置格,每个调料格字段与主辅材一致(名称/每份用量/份数/应称/已称)
|
||||
- **调料多高亮状态(02)**:active(当前要称,蓝色脉冲)、next(下一个要称,淡蓝虚线)、done(已完成,绿色),称重确认后自动从 active 切换为 done
|
||||
- **调料组配交互(02)**:不走 AI 识别,点击高亮调料格 → 弹出组配确认弹窗 → 读取秤值 → 确认写入,信息格(油)也可点击称重
|
||||
- **状态判断(02)**:主辅材+调料全部完成才算该餐品净菜包组配完成
|
||||
|
||||
### 新增
|
||||
- **调料位置设置页(04-seasoning-settings.html)**:3×5 网格可视化配置调料秤 11 个位置各自放置的调料,点击格子 → 下拉选择调料名称(17种常用调料候选),支持清空/重置/保存(localStorage 持久化)
|
||||
- **功能菜单(00-welcome.html)**:新增「调料位置设置」入口
|
||||
- **导航页(index.html)**:新增「调料位置设置」卡片入口
|
||||
- **canteen-device/index.html**:卡片名称改为「净菜组配秤」,描述更新为「餐品净菜包独立组配,主辅材+调料双区称重」
|
||||
|
||||
---
|
||||
|
||||
## [1.3.2] - 2026-06-17
|
||||
|
||||
|
||||
@@ -2,20 +2,20 @@
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=1280, initial-scale=1.0">
|
||||
<title>净菜配比秤 - 蚁熊智能餐养平台</title>
|
||||
<meta name="viewport" content="width=720, 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: 1280px;
|
||||
min-height: 100vh; min-width: 720px;
|
||||
display: flex; align-items: center; justify-content: center;
|
||||
padding: 20px;
|
||||
}
|
||||
/* PAD 设备外壳 */
|
||||
.device-frame {
|
||||
width: 1280px; height: 720px;
|
||||
width: 720px; height: 960px;
|
||||
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);
|
||||
@@ -41,7 +41,7 @@
|
||||
<div class="device-frame">
|
||||
<div class="top-bar">
|
||||
<a class="back-link" href="../index.html">◀ 返回</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,31 @@
|
||||
<span class="card__icon">📋</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">›</span>
|
||||
</a>
|
||||
<a class="card" href="01-packing-tasks.html">
|
||||
<span class="card__icon">📦</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">›</span>
|
||||
</a>
|
||||
<a class="card" href="03-verify-history.html">
|
||||
<span class="card__icon">📝</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">›</span>
|
||||
</a>
|
||||
<a class="card" href="04-seasoning-settings.html">
|
||||
<span class="card__icon">🧂</span>
|
||||
<div class="card__info">
|
||||
<div class="card__title">调料位置设置</div>
|
||||
<div class="card__desc">配置调料秤各位置放置的调料</div>
|
||||
</div>
|
||||
<span class="card__arrow">›</span>
|
||||
</a>
|
||||
|
||||
Reference in New Issue
Block a user