feat: 净菜订单/申领三页统一增加订单金额 + 餐线营养秤菜品展示页新增视频演示模式
- web-admin/nutrition: prod-clean-order/sup-clean-external/sup-clean-internal 统一增加单价/小计字段与订单总金额栏,移除弹窗内汇总预览表格 - canteen-nutrition-scale/02-dish-display: 新增演示模式切换 pill 与视频模式布局(上视频 + 下信息卡) Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.7
parent
6c812f8e64
commit
d00208a33d
Generated
+27
-3
@@ -7,9 +7,33 @@
|
||||
<value>
|
||||
<TabSessionState>
|
||||
<option name="provider" value="claude" />
|
||||
<option name="sessionId" value="5ef9ff98-5eb1-4ae5-8460-f461df1cfe53" />
|
||||
<option name="sessionId" value="2a1427c6-520d-4da9-87a9-28e066647864" />
|
||||
<option name="cwd" value="$PROJECT_DIR$" />
|
||||
<option name="model" value="claude-sonnet-4-6" />
|
||||
<option name="model" value="claude-opus-4-7[1m]" />
|
||||
<option name="permissionMode" value="bypassPermissions" />
|
||||
<option name="reasoningEffort" value="high" />
|
||||
</TabSessionState>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="1">
|
||||
<value>
|
||||
<TabSessionState>
|
||||
<option name="provider" value="claude" />
|
||||
<option name="sessionId" value="916a3047-30c5-4f02-a0de-f2e2ba660d52" />
|
||||
<option name="cwd" value="$PROJECT_DIR$" />
|
||||
<option name="model" value="claude-opus-4-7[1m]" />
|
||||
<option name="permissionMode" value="bypassPermissions" />
|
||||
<option name="reasoningEffort" value="high" />
|
||||
</TabSessionState>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="2">
|
||||
<value>
|
||||
<TabSessionState>
|
||||
<option name="provider" value="claude" />
|
||||
<option name="sessionId" value="eb87e0d9-e045-4412-8eaa-bcecfed97b43" />
|
||||
<option name="cwd" value="$PROJECT_DIR$" />
|
||||
<option name="model" value="claude-opus-4-7[1m]" />
|
||||
<option name="permissionMode" value="bypassPermissions" />
|
||||
<option name="reasoningEffort" value="high" />
|
||||
</TabSessionState>
|
||||
@@ -17,6 +41,6 @@
|
||||
</entry>
|
||||
</map>
|
||||
</option>
|
||||
<option name="tabCount" value="2" />
|
||||
<option name="tabCount" value="3" />
|
||||
</component>
|
||||
</project>
|
||||
@@ -175,6 +175,305 @@
|
||||
visibility: visible;
|
||||
transform: translateX(-50%) translateY(0);
|
||||
}
|
||||
|
||||
/* ---- 演示模式切换按钮(仅原型演示,右上角简洁 pill) ---- */
|
||||
.mode-switch {
|
||||
position: absolute;
|
||||
top: 20px;
|
||||
right: 56px;
|
||||
display: flex;
|
||||
height: 22px;
|
||||
background: rgba(255,255,255,0.06);
|
||||
border: 1px solid rgba(255,255,255,0.12);
|
||||
border-radius: 6px;
|
||||
overflow: hidden;
|
||||
z-index: 10;
|
||||
}
|
||||
.mode-switch::before {
|
||||
content: '演示';
|
||||
position: absolute;
|
||||
left: -36px;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
font-size: 10px;
|
||||
color: rgba(255,255,255,0.3);
|
||||
letter-spacing: 1px;
|
||||
}
|
||||
.mode-switch button {
|
||||
padding: 0 12px;
|
||||
font-size: 11px;
|
||||
color: rgba(255,255,255,0.5);
|
||||
background: transparent;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s;
|
||||
height: 100%;
|
||||
font-family: inherit;
|
||||
}
|
||||
.mode-switch button:hover {
|
||||
background: rgba(255,255,255,0.06);
|
||||
color: rgba(255,255,255,0.8);
|
||||
}
|
||||
.mode-switch button.active {
|
||||
background: #FF9800;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
/* ---- 视频模式布局(纵向:上视频 + 下信息卡) ---- */
|
||||
.video-mode {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
display: none;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 40px 60px 30px;
|
||||
gap: 24px;
|
||||
}
|
||||
/* 视频模式激活时显示视频布局 */
|
||||
.main-area.mode-video .video-mode {
|
||||
display: flex;
|
||||
}
|
||||
/* 视频模式激活时隐藏常规模式的标题和菜品信息 */
|
||||
.main-area.mode-video .center-heading,
|
||||
.main-area.mode-video .dish-info {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* 视频播放器 */
|
||||
.video-player {
|
||||
width: 100%;
|
||||
max-width: 680px;
|
||||
aspect-ratio: 16 / 9;
|
||||
border-radius: 12px;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
background: #000;
|
||||
box-shadow: 0 12px 32px rgba(0,0,0,0.5), 0 0 0 1px rgba(255,255,255,0.06);
|
||||
}
|
||||
.video-player .video-bg {
|
||||
position: absolute;
|
||||
top: 0; left: 0;
|
||||
width: 100%; height: 100%;
|
||||
}
|
||||
.video-play-btn {
|
||||
position: absolute;
|
||||
top: 50%; left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
width: 56px; height: 56px;
|
||||
background: rgba(0,0,0,0.55);
|
||||
border: 2px solid rgba(255,255,255,0.85);
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
cursor: pointer;
|
||||
transition: transform 0.2s, background 0.2s;
|
||||
z-index: 2;
|
||||
}
|
||||
.video-play-btn:hover {
|
||||
background: rgba(0,0,0,0.75);
|
||||
transform: translate(-50%, -50%) scale(1.05);
|
||||
}
|
||||
.video-play-btn::after {
|
||||
content: '';
|
||||
width: 0; height: 0;
|
||||
border-left: 16px solid #fff;
|
||||
border-top: 10px solid transparent;
|
||||
border-bottom: 10px solid transparent;
|
||||
margin-left: 4px;
|
||||
}
|
||||
.video-controls {
|
||||
position: absolute;
|
||||
bottom: 0; left: 0; right: 0;
|
||||
padding: 10px 14px;
|
||||
background: linear-gradient(to top, rgba(0,0,0,0.75), transparent);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
font-size: 11px;
|
||||
color: rgba(255,255,255,0.85);
|
||||
z-index: 2;
|
||||
}
|
||||
.video-progress {
|
||||
flex: 1;
|
||||
height: 3px;
|
||||
background: rgba(255,255,255,0.2);
|
||||
border-radius: 2px;
|
||||
position: relative;
|
||||
}
|
||||
.video-progress::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
left: 0; top: 0;
|
||||
width: 35%;
|
||||
height: 100%;
|
||||
background: #FF9800;
|
||||
border-radius: 2px;
|
||||
}
|
||||
.video-time {
|
||||
font-size: 11px;
|
||||
letter-spacing: 0.5px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.video-fullscreen {
|
||||
font-size: 13px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
/* 信息卡 */
|
||||
.video-info-card {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 28px;
|
||||
padding: 14px 36px;
|
||||
background: rgba(255,255,255,0.04);
|
||||
border: 1px solid rgba(255,255,255,0.08);
|
||||
border-radius: 12px;
|
||||
}
|
||||
.video-info-name {
|
||||
font-size: 26px;
|
||||
font-weight: 600;
|
||||
color: #fff;
|
||||
}
|
||||
.video-info-divider {
|
||||
width: 1px;
|
||||
height: 28px;
|
||||
background: rgba(255,255,255,0.15);
|
||||
}
|
||||
.video-info-item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
gap: 4px;
|
||||
}
|
||||
.video-info-label {
|
||||
font-size: 11px;
|
||||
color: rgba(255,255,255,0.4);
|
||||
letter-spacing: 1px;
|
||||
}
|
||||
.video-info-value {
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
color: #0AC4A8;
|
||||
}
|
||||
.video-info-unit {
|
||||
font-size: 12px;
|
||||
color: rgba(255,255,255,0.5);
|
||||
font-weight: 400;
|
||||
margin-left: 4px;
|
||||
}
|
||||
|
||||
/* ---- 视频模式布局2(横向:左视频 + 右信息卡含标签) ---- */
|
||||
.video-mode-h {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
display: none;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 40px 50px;
|
||||
gap: 32px;
|
||||
}
|
||||
/* 视频2 模式激活时显示横向布局 */
|
||||
.main-area.mode-video2 .video-mode-h {
|
||||
display: flex;
|
||||
}
|
||||
/* 视频2 模式激活时隐藏常规元素与纵向视频布局 */
|
||||
.main-area.mode-video2 .center-heading,
|
||||
.main-area.mode-video2 .dish-info,
|
||||
.main-area.mode-video2 .video-mode {
|
||||
display: none;
|
||||
}
|
||||
/* 纵向视频模式激活时也隐藏横向布局 */
|
||||
.main-area.mode-video .video-mode-h {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* 横向布局下的视频播放器(左侧,固定宽度) */
|
||||
.video-mode-h .video-player {
|
||||
flex: 0 0 auto;
|
||||
width: 680px;
|
||||
max-width: 60%;
|
||||
}
|
||||
|
||||
/* 右侧信息卡(横向布局,纵向排列内容) */
|
||||
.video-info-card-h {
|
||||
flex: 1;
|
||||
min-width: 280px;
|
||||
max-width: 380px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
gap: 14px;
|
||||
padding: 24px 28px;
|
||||
background: rgba(255,255,255,0.04);
|
||||
border: 1px solid rgba(255,255,255,0.08);
|
||||
border-radius: 14px;
|
||||
}
|
||||
.video-info-name-h {
|
||||
font-size: 28px;
|
||||
font-weight: 600;
|
||||
color: #fff;
|
||||
line-height: 1.2;
|
||||
}
|
||||
|
||||
/* 餐品标签 chips */
|
||||
.video-tags-row {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
}
|
||||
.video-tag-chip {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
padding: 4px 10px;
|
||||
font-size: 12px;
|
||||
color: #0AC4A8;
|
||||
background: rgba(10,196,168,0.12);
|
||||
border: 1px solid rgba(10,196,168,0.25);
|
||||
border-radius: 10px;
|
||||
letter-spacing: 0.5px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
/* 标签色系变化(按位置循环,增加视觉层次) */
|
||||
.video-tag-chip:nth-child(3n+2) {
|
||||
color: #FF9800;
|
||||
background: rgba(255,152,0,0.10);
|
||||
border-color: rgba(255,152,0,0.25);
|
||||
}
|
||||
.video-tag-chip:nth-child(3n) {
|
||||
color: #5B9BF8;
|
||||
background: rgba(91,155,248,0.12);
|
||||
border-color: rgba(91,155,248,0.25);
|
||||
}
|
||||
|
||||
.video-info-divider-h {
|
||||
width: 100%;
|
||||
height: 1px;
|
||||
background: rgba(255,255,255,0.12);
|
||||
margin: 4px 0;
|
||||
}
|
||||
.video-info-item-h {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
gap: 6px;
|
||||
width: 100%;
|
||||
}
|
||||
/* 横向布局右侧信息卡中的数值字号加大 */
|
||||
.video-info-item-h .video-info-value {
|
||||
font-size: 22px;
|
||||
}
|
||||
.video-info-item-h .video-info-label {
|
||||
font-size: 12px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
@@ -185,6 +484,13 @@
|
||||
<a class="back-btn" id="backBtn" href="javascript:void(0)">◀ 返回</a> <span>Phone-192.168.1.165:5555</span>
|
||||
</div>
|
||||
|
||||
<!-- 演示模式切换按钮(仅原型演示用,不影响实际业务) -->
|
||||
<div class="mode-switch" id="modeSwitch">
|
||||
<button class="active" data-mode="normal">常规</button>
|
||||
<button data-mode="video">视频</button>
|
||||
<button data-mode="video2">视频2</button>
|
||||
</div>
|
||||
|
||||
<!-- 设置按钮 -->
|
||||
<a class="settings-btn" id="settingsBtn" title="设置">⚙</a>
|
||||
|
||||
@@ -212,6 +518,72 @@
|
||||
<div class="dish-hint">点击菜品信息 → 进入开餐界面</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 视频模式布局(纵向:上视频 + 下信息卡,默认隐藏) -->
|
||||
<div class="video-mode" id="videoMode">
|
||||
<!-- 视频播放器 -->
|
||||
<div class="video-player">
|
||||
<!-- 视频背景(用 SVG 模拟菜品展示画面) -->
|
||||
<div class="video-bg" id="videoBg"></div>
|
||||
<!-- 播放按钮 -->
|
||||
<div class="video-play-btn" id="videoPlayBtn" title="播放"></div>
|
||||
<!-- 控制条 -->
|
||||
<div class="video-controls">
|
||||
<span style="cursor:pointer;">⏯</span>
|
||||
<div class="video-progress"></div>
|
||||
<span class="video-time">01:23 / 03:45</span>
|
||||
<span class="video-fullscreen">⛶</span>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 餐品信息卡 -->
|
||||
<div class="video-info-card">
|
||||
<div class="video-info-name" id="videoDishName">宫保鸡丁</div>
|
||||
<div class="video-info-divider"></div>
|
||||
<div class="video-info-item">
|
||||
<span class="video-info-label">单价</span>
|
||||
<span class="video-info-value"><span id="videoDishPrice">5</span><span class="video-info-unit">元/100克</span></span>
|
||||
</div>
|
||||
<div class="video-info-divider"></div>
|
||||
<div class="video-info-item">
|
||||
<span class="video-info-label">热量</span>
|
||||
<span class="video-info-value"><span id="videoDishKcal">158.66</span><span class="video-info-unit">千卡/100克</span></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 视频模式布局2(横向:左视频 + 右信息卡含标签,默认隐藏) -->
|
||||
<div class="video-mode-h" id="videoModeH">
|
||||
<!-- 左侧:视频播放器 -->
|
||||
<div class="video-player">
|
||||
<div class="video-bg" id="videoBgH"></div>
|
||||
<div class="video-play-btn" id="videoPlayBtnH" title="播放"></div>
|
||||
<div class="video-controls">
|
||||
<span style="cursor:pointer;">⏯</span>
|
||||
<div class="video-progress"></div>
|
||||
<span class="video-time">01:23 / 03:45</span>
|
||||
<span class="video-fullscreen">⛶</span>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 右侧:餐品信息卡(含标签) -->
|
||||
<div class="video-info-card-h">
|
||||
<!-- 餐品名称 -->
|
||||
<div class="video-info-name-h" id="videoDishNameH">宫保鸡丁</div>
|
||||
<!-- 餐品标签 chips -->
|
||||
<div class="video-tags-row" id="videoTagsRow"></div>
|
||||
<!-- 分隔线 -->
|
||||
<div class="video-info-divider-h"></div>
|
||||
<!-- 单价 -->
|
||||
<div class="video-info-item-h">
|
||||
<span class="video-info-label">单价</span>
|
||||
<span class="video-info-value"><span id="videoDishPriceH">5</span><span class="video-info-unit">元/100克</span></span>
|
||||
</div>
|
||||
<!-- 每百克热量 -->
|
||||
<div class="video-info-item-h">
|
||||
<span class="video-info-label">每百克热量</span>
|
||||
<span class="video-info-value"><span id="videoDishKcalH">158.66</span><span class="video-info-unit">千卡/100克</span></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@@ -223,16 +595,16 @@
|
||||
|
||||
/* ===== 餐品数据映射(模拟后端) ===== */
|
||||
var DISH_MAP = {
|
||||
1: { name: '红烧肉', price: 5, kcal: 480, colors: ['#8B3A2A', '#D4764E', '#C05030'] },
|
||||
2: { name: '宫保鸡丁', price: 5, kcal: 420, colors: ['#C87030', '#E8A040', '#D08028'] },
|
||||
3: { name: '麻婆豆腐', price: 4, kcal: 280, colors: ['#706040', '#B89060', '#807050'] },
|
||||
4: { name: '清炒时蔬', price: 3, kcal: 120, colors: ['#306028', '#50A040', '#408030'] },
|
||||
5: { name: '香煎带鱼', price: 6, kcal: 320, colors: ['#805020', '#B88040', '#A06830'] },
|
||||
6: { name: '糖醋排骨', price: 7, kcal: 520, colors: ['#802018', '#C05030', '#A03820'] },
|
||||
7: { name: '蒜蓉西兰花', price: 3, kcal: 110, colors: ['#207040', '#40A868', '#308848'] },
|
||||
8: { name: '米饭', price: 1.5, kcal: 260, colors: ['#D0D0C0', '#E8E8D8', '#E0E0C8'] },
|
||||
9: { name: '紫菜蛋花汤', price: 2, kcal: 80, colors: ['#503028', '#805040', '#603830'] },
|
||||
10: { name: '西红柿炒蛋', price: 4, kcal: 180, colors: ['#E8A030', '#F0C040', '#D89020'] }
|
||||
1: { name: '红烧肉', price: 5, kcal: 480, colors: ['#8B3A2A', '#D4764E', '#C05030'], tags: ['高蛋白', '高脂肪', '富含铁'] },
|
||||
2: { name: '宫保鸡丁', price: 5, kcal: 420, colors: ['#C87030', '#E8A040', '#D08028'], tags: ['高蛋白', '低芥酸', '营养均衡'] },
|
||||
3: { name: '麻婆豆腐', price: 4, kcal: 280, colors: ['#706040', '#B89060', '#807050'], tags: ['植物蛋白', '低芥酸', '微辣'] },
|
||||
4: { name: '清炒时蔬', price: 3, kcal: 120, colors: ['#306028', '#50A040', '#408030'], tags: ['低脂肪', '高纤维', '清淡'] },
|
||||
5: { name: '香煎带鱼', price: 6, kcal: 320, colors: ['#805020', '#B88040', '#A06830'], tags: ['高蛋白', '富含DHA', '低芥酸'] },
|
||||
6: { name: '糖醋排骨', price: 7, kcal: 520, colors: ['#802018', '#C05030', '#A03820'], tags: ['高蛋白', '高热量', '富含钙'] },
|
||||
7: { name: '蒜蓉西兰花', price: 3, kcal: 110, colors: ['#207040', '#40A868', '#308848'], tags: ['低脂肪', '高纤维', '富含维C'] },
|
||||
8: { name: '米饭', price: 1.5, kcal: 260, colors: ['#D0D0C0', '#E8E8D8', '#E0E0C8'], tags: ['主食', '低脂肪', '高碳水'] },
|
||||
9: { name: '紫菜蛋花汤', price: 2, kcal: 80, colors: ['#503028', '#805040', '#603830'], tags: ['低脂肪', '富含碘', '清淡'] },
|
||||
10: { name: '西红柿炒蛋', price: 4, kcal: 180, colors: ['#E8A030', '#F0C040', '#D89020'], tags: ['高蛋白', '低芥酸', '富含维C'] }
|
||||
};
|
||||
|
||||
/* ===== 解析 URL 参数 ===== */
|
||||
@@ -271,25 +643,34 @@
|
||||
document.getElementById('dishPrice').textContent = dishData.price;
|
||||
document.getElementById('dishKcal').textContent = dishData.kcal;
|
||||
|
||||
/* ===== 视频模式数据填充(纵向布局) ===== */
|
||||
document.getElementById('videoDishName').textContent = dishData.name;
|
||||
document.getElementById('videoDishPrice').textContent = dishData.price;
|
||||
document.getElementById('videoDishKcal').textContent = dishData.kcal;
|
||||
document.getElementById('videoBg').innerHTML = videoBgSVG(dishData.colors);
|
||||
|
||||
/* ===== 视频模式数据填充(横向布局,含标签) ===== */
|
||||
document.getElementById('videoDishNameH').textContent = dishData.name;
|
||||
document.getElementById('videoDishPriceH').textContent = dishData.price;
|
||||
document.getElementById('videoDishKcalH').textContent = dishData.kcal;
|
||||
document.getElementById('videoBgH').innerHTML = videoBgSVG(dishData.colors);
|
||||
// 渲染餐品标签 chips
|
||||
var tagsRow = document.getElementById('videoTagsRow');
|
||||
var tagsHtml = '';
|
||||
var dishTags = dishData.tags || [];
|
||||
for (var i = 0; i < dishTags.length; i++) {
|
||||
tagsHtml += '<span class="video-tag-chip">' + dishTags[i] + '</span>';
|
||||
}
|
||||
tagsRow.innerHTML = tagsHtml;
|
||||
|
||||
/* ===== 点击菜品信息 → 进入开餐界面 ===== */
|
||||
document.getElementById('dishInfo').addEventListener('click', function() {
|
||||
window.location.href = '01-meal-start.html';
|
||||
});
|
||||
|
||||
/* ===== 模拟人脸识别(站在设备前自动触发) ===== */
|
||||
var faceDetectTimer = null;
|
||||
/* ===== 演示说明:原 3 秒自动跳转逻辑已移除,改为用户主动点击菜品信息后跳转 ===== */
|
||||
var isEmployee = false; // 02 默认买家态(买家身份进入)
|
||||
|
||||
function startFaceDetect() {
|
||||
// 模拟:站在设备前 3 秒后识别成功
|
||||
faceDetectTimer = setTimeout(function() {
|
||||
// 识别成功 → 跳转取餐界面
|
||||
window.location.href = '03-meal-pickup.html?dishId=' + dishId;
|
||||
}, 3000);
|
||||
}
|
||||
// 页面加载后自动启动人脸识别
|
||||
startFaceDetect();
|
||||
|
||||
/* ===== Toast 提示 ===== */
|
||||
var toastEl = document.getElementById('toast');
|
||||
function showToast(msg, duration) {
|
||||
@@ -311,6 +692,59 @@
|
||||
}
|
||||
window.location.href = '04-settings.html';
|
||||
});
|
||||
|
||||
/* ===== 演示模式切换(常规 / 视频 / 视频2) ===== */
|
||||
var modeSwitch = document.getElementById('modeSwitch');
|
||||
var mainArea = document.querySelector('.main-area');
|
||||
modeSwitch.addEventListener('click', function(e) {
|
||||
var btn = e.target.closest('button[data-mode]');
|
||||
if (!btn) return;
|
||||
var mode = btn.getAttribute('data-mode');
|
||||
// 切换按钮高亮状态
|
||||
var btns = modeSwitch.querySelectorAll('button[data-mode]');
|
||||
for (var i = 0; i < btns.length; i++) {
|
||||
btns[i].classList.toggle('active', btns[i] === btn);
|
||||
}
|
||||
// 通过 main-area 的 class 控制布局切换:先清除所有模式类,再按需添加
|
||||
mainArea.classList.remove('mode-video', 'mode-video2');
|
||||
if (mode === 'video') {
|
||||
mainArea.classList.add('mode-video');
|
||||
} else if (mode === 'video2') {
|
||||
mainArea.classList.add('mode-video2');
|
||||
}
|
||||
});
|
||||
|
||||
/* ===== 视频播放按钮(演示用,点击切换播放/暂停图标) ===== */
|
||||
var videoPlaying = false;
|
||||
function bindVideoPlayBtn(btnId) {
|
||||
document.getElementById(btnId).addEventListener('click', function() {
|
||||
videoPlaying = !videoPlaying;
|
||||
this.style.opacity = videoPlaying ? '0' : '1';
|
||||
});
|
||||
}
|
||||
bindVideoPlayBtn('videoPlayBtn');
|
||||
bindVideoPlayBtn('videoPlayBtnH');
|
||||
|
||||
/* ===== 视频背景 SVG(按菜品色系生成展示画面) ===== */
|
||||
function videoBgSVG(colors) {
|
||||
var w = 680, h = 383; // 16:9 比例
|
||||
var id = 'vidGrad';
|
||||
return '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 ' + w + ' ' + h + '" preserveAspectRatio="xMidYMid slice" style="width:100%;height:100%;">' +
|
||||
'<defs><linearGradient id="' + id + '" x1="0" y1="0" x2="1" y2="1">' +
|
||||
'<stop offset="0%" stop-color="' + colors[0] + '"/>' +
|
||||
'<stop offset="50%" stop-color="' + colors[1] + '"/>' +
|
||||
'<stop offset="100%" stop-color="' + colors[2] + '"/></linearGradient></defs>' +
|
||||
'<rect width="' + w + '" height="' + h + '" fill="url(#' + id + ')"/>' +
|
||||
'<ellipse cx="' + (w*0.3) + '" cy="' + (h*0.35) + '" rx="180" ry="120" fill="rgba(255,255,255,0.08)"/>' +
|
||||
'<ellipse cx="' + (w*0.7) + '" cy="' + (h*0.65) + '" rx="220" ry="140" fill="rgba(0,0,0,0.12)"/>' +
|
||||
'<ellipse cx="' + (w/2) + '" cy="' + (h/2) + '" rx="' + (w*0.32) + '" ry="' + (h*0.35) + '" fill="none" stroke="rgba(255,255,255,0.12)" stroke-width="1.5"/>' +
|
||||
'<ellipse cx="' + (w/2) + '" cy="' + (h/2) + '" rx="' + (w*0.22) + '" ry="' + (h*0.22) + '" fill="rgba(255,255,255,0.06)"/>' +
|
||||
'<ellipse cx="' + (w*0.4) + '" cy="' + (h*0.4) + '" rx="60" ry="40" fill="rgba(255,255,255,0.18)"/>' +
|
||||
'<ellipse cx="' + (w*0.6) + '" cy="' + (h*0.55) + '" rx="40" ry="25" fill="rgba(0,0,0,0.15)"/>' +
|
||||
'<text x="' + (w/2) + '" y="' + (h*0.18) + '" text-anchor="middle" fill="rgba(255,255,255,0.6)" font-size="20" font-weight="600" font-family="-apple-system,Microsoft YaHei,sans-serif">餐品制作工艺展示</text>' +
|
||||
'<text x="' + (w/2) + '" y="' + (h*0.85) + '" text-anchor="middle" fill="rgba(255,255,255,0.35)" font-size="12" font-family="-apple-system,Microsoft YaHei,sans-serif">主厨推荐 · 现场烹制</text>' +
|
||||
'</svg>';
|
||||
}
|
||||
</script>
|
||||
|
||||
</body>
|
||||
|
||||
@@ -1,5 +1,19 @@
|
||||
# 餐线营养秤 - 变更记录
|
||||
|
||||
## [2026-08-05] feat: 菜品展示页新增视频演示模式
|
||||
|
||||
### 新增
|
||||
- **演示模式切换按钮**(`02-dish-display.html`):右上角新增「演示」标识 + 模式切换 pill(常规 / 视频),默认常规模式
|
||||
- **视频模式布局**:纵向「上视频 + 下信息卡」布局,680px 宽 16:9 视频播放器,圆角阴影悬浮卡片
|
||||
- **视频播放器组件**:含视频背景、居中播放按钮、控制条(进度条 / 时间 / 音量 / 全屏)
|
||||
- **菜品信息卡**:视频下方展示菜品名、营养指标(热量 / 蛋白 / 脂肪 / 碳水)、简介描述
|
||||
- **模式联动**:视频模式激活时隐藏常规模式标题和菜品信息区,切换无闪烁
|
||||
|
||||
### 调整
|
||||
- `02-dish-display.html` — `main-area` 增加 `mode-video` 状态类,通过 CSS 控制两种布局切换
|
||||
|
||||
---
|
||||
|
||||
## [2026-07-27] feat: 设置页新增闭餐功能
|
||||
|
||||
### 新增
|
||||
|
||||
@@ -1,5 +1,28 @@
|
||||
# 营养用餐管理端 CHANGELOG
|
||||
|
||||
## [2026-08-05] feat: 净菜订单/申领页面统一新增订单金额字段与总金额栏
|
||||
|
||||
### 变更背景
|
||||
原净菜生产订单、外售订单、内供申领三页均无金额字段,仅在新增/编辑弹窗内展示「汇总预览」(净菜类型/菜品/包装规格/份数/计量)。为补齐订单金额闭环,统一在三页增加单价、小计、订单总金额字段。
|
||||
|
||||
### 新增
|
||||
- **`prod-clean-order.html`**(净菜生产订单)
|
||||
- 订单数据 `lines[]` 每项新增 `price`(单价)和 `subtotal`(小计)字段,覆盖内供/外售 6 个示例订单共 14 条明细
|
||||
- 弹窗底部新增「订单总金额」栏,`#orderTotalAmount` 实时展示 `¥1,234.5` 格式金额
|
||||
- 新增 `calcOrderTotal(o)` 与 `formatMoney(n)` 工具函数
|
||||
- **`sup-clean-external.html`**(外售订单)
|
||||
- 表头新增「订单金额」列;订单明细新增 `price`/`subtotal` 字段(6 个示例订单 14 条明细)
|
||||
- 弹窗移除「汇总预览」表格,改为底部「订单总金额」栏
|
||||
- **`sup-clean-internal.html`**(内供申领)
|
||||
- 表头新增「订单金额」列;申领明细新增 `price`/`subtotal` 字段(5 个示例订单 11 条明细)
|
||||
- 弹窗移除「汇总预览」表格,改为底部「订单总金额」栏
|
||||
|
||||
### 调整
|
||||
- 三个页面弹窗的「汇总预览」表格(含 `orderSummary`/`extSummary`/`claimSummary` 容器与 thead/tbody)统一移除,改为弹窗 body 下方贴底的灰底总金额栏
|
||||
- 金额格式化统一走 `formatMoney(n)`:`¥1,234.5`(千分位 + 最多 2 位小数)
|
||||
|
||||
---
|
||||
|
||||
## [2026-08-05] 规格体系统一化 · 阶段五辅助页改造(5.1~5.3 全部完成)
|
||||
|
||||
> 本次为 `规格体系统一化改造任务清单.md` 第五阶段辅助页 3 个任务(共 6 个文件)的统一改造。本阶段补齐了跨页共享的"写入端"、字典语义对齐和残余多形态字符串结构化,标志着规格体系统一化改造五个阶段全部完成。
|
||||
|
||||
@@ -284,16 +284,12 @@ tr.detail-row td.td-actions{background:#FAFBFC;box-shadow:-4px 0 8px rgba(0,0,0,
|
||||
<button class="btn btn-primary btn-sm" onclick="addOrderLine()">+ 添加菜品</button>
|
||||
</div>
|
||||
<div id="orderLinesContainer"></div>
|
||||
<!-- 汇总预览 -->
|
||||
<div id="orderSummary" style="display:none;">
|
||||
<div style="font-size:var(--font-sm);font-weight:600;margin:12px 0 8px;">汇总预览</div>
|
||||
<table class="order-summary-table">
|
||||
<thead id="orderSummaryHead"><tr><th>净菜类型</th><th>菜品/食材</th><th>包装规格</th><th>份数</th><th>计量(kg)</th></tr></thead>
|
||||
<tbody id="orderSummaryBody"></tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div style="display:flex;align-items:center;justify-content:flex-end;padding:12px 24px;border-top:1px solid var(--border);background:#fafafa;gap:12px;">
|
||||
<span style="font-size:var(--font-sm);color:var(--text-secondary);">订单总金额:</span>
|
||||
<span id="orderTotalAmount" style="font-weight:700;color:var(--danger);font-size:var(--font-xl);">¥0</span>
|
||||
</div>
|
||||
<div class="modal__footer">
|
||||
<button class="btn btn-default" onclick="closeModal('modal-order')">取消</button>
|
||||
<button class="btn btn-primary" onclick="submitCreateOrder()">确认提交</button>
|
||||
@@ -416,62 +412,66 @@ var orders=[
|
||||
{
|
||||
orderNo:'CO-001',orderType:'内供',ncType:'nc',claimTime:'2026-04-22 07:30',deliverTime:'2026-04-22 10:00',creator:'张厨师',
|
||||
lines:[
|
||||
{id:'L1',ncType:'nc',ingredient:'菠菜',ncName:'菠菜段',spec:'500g/袋',qty:50,weight:25,status:'已完成'},
|
||||
{id:'L2',ncType:'nc',ingredient:'玉米',ncName:'玉米粒',spec:'1kg/盒',qty:20,weight:20,status:'已完成'}
|
||||
{id:'L1',ncType:'nc',ingredient:'菠菜',ncName:'菠菜段',spec:'500g/袋',qty:50,weight:25,price:5,subtotal:125,status:'已完成'},
|
||||
{id:'L2',ncType:'nc',ingredient:'玉米',ncName:'玉米粒',spec:'1kg/盒',qty:20,weight:20,price:6,subtotal:120,status:'已完成'}
|
||||
]
|
||||
},
|
||||
{
|
||||
orderNo:'CO-002',orderType:'内供',ncType:'nc',claimTime:'2026-04-22 08:00',deliverTime:'2026-04-22 10:30',creator:'李主管',
|
||||
lines:[
|
||||
{id:'L3',ncType:'nc',ingredient:'猪排骨',ncName:'排骨块',spec:'2kg/盘',qty:20,weight:40,status:'配送中'},
|
||||
{id:'L4',ncType:'cp',foodName:'宫保鸡丁',spec:'标准份(500g)',qty:30,weight:15,status:'已完成'}
|
||||
{id:'L3',ncType:'nc',ingredient:'猪排骨',ncName:'排骨块',spec:'2kg/盘',qty:20,weight:40,price:8,subtotal:320,status:'配送中'},
|
||||
{id:'L4',ncType:'cp',foodName:'宫保鸡丁',spec:'标准份(500g)',qty:30,weight:15,price:12,subtotal:180,status:'已完成'}
|
||||
]
|
||||
},
|
||||
{
|
||||
orderNo:'CO-003',orderType:'外售',ncType:'cp',claimTime:'2026-04-22 08:00',deliverTime:'2026-04-22 10:30',creator:'李主管',
|
||||
lines:[
|
||||
{id:'L5',ncType:'cp',foodName:'清蒸鱼',spec:'标准份(500g)',qty:15,weight:7.5,status:'配送中'}
|
||||
{id:'L5',ncType:'cp',foodName:'清蒸鱼',spec:'标准份(500g)',qty:15,weight:7.5,price:15,subtotal:112.5,status:'配送中'}
|
||||
]
|
||||
},
|
||||
{
|
||||
orderNo:'CO-004',orderType:'内供',ncType:'nc',claimTime:'2026-04-22 09:00',deliverTime:'2026-04-22 11:00',creator:'王厨师',
|
||||
lines:[
|
||||
{id:'L6',ncType:'nc',ingredient:'土豆',ncName:'土豆丝',spec:'500g/袋',qty:40,weight:20,status:'待配送'},
|
||||
{id:'L7',ncType:'nc',ingredient:'西兰花',ncName:'西兰花朵',spec:'500g/袋',qty:30,weight:15,status:'备货中'}
|
||||
{id:'L6',ncType:'nc',ingredient:'土豆',ncName:'土豆丝',spec:'500g/袋',qty:40,weight:20,price:4,subtotal:80,status:'待配送'},
|
||||
{id:'L7',ncType:'nc',ingredient:'西兰花',ncName:'西兰花朵',spec:'500g/袋',qty:30,weight:15,price:5,subtotal:75,status:'备货中'}
|
||||
]
|
||||
},
|
||||
{
|
||||
orderNo:'CO-005',orderType:'内供',ncType:'nc',claimTime:'2026-04-22 09:15',deliverTime:'2026-04-22 11:00',creator:'张厨师',
|
||||
lines:[
|
||||
{id:'L8',ncType:'cp',foodName:'红烧排骨',spec:'标准份(800g)',qty:10,weight:8,status:'备货中'},
|
||||
{id:'L9',ncType:'nc',ingredient:'鸡胸肉',ncName:'鸡胸肉丁',spec:'500g/袋',qty:15,weight:7.5,status:'备货中'},
|
||||
{id:'L10',ncType:'nc',ingredient:'草鱼',ncName:'鱼片',spec:'1kg/盘',qty:8,weight:8,status:'备货中'}
|
||||
{id:'L8',ncType:'cp',foodName:'红烧排骨',spec:'标准份(800g)',qty:10,weight:8,price:18,subtotal:144,status:'备货中'},
|
||||
{id:'L9',ncType:'nc',ingredient:'鸡胸肉',ncName:'鸡胸肉丁',spec:'500g/袋',qty:15,weight:7.5,price:10,subtotal:75,status:'备货中'},
|
||||
{id:'L10',ncType:'nc',ingredient:'草鱼',ncName:'鱼片',spec:'1kg/盘',qty:8,weight:8,price:20,subtotal:160,status:'备货中'}
|
||||
]
|
||||
},
|
||||
{
|
||||
orderNo:'CO-006',orderType:'外售',ncType:'cp',claimTime:'2026-04-22 10:00',deliverTime:'2026-04-22 11:30',creator:'王厨师',
|
||||
lines:[
|
||||
{id:'L11',ncType:'cp',foodName:'宫保鸡丁',spec:'标准份(500g)',qty:25,weight:12.5,status:'已完成'},
|
||||
{id:'L12',ncType:'cp',foodName:'清蒸鱼',spec:'标准份(600g)',qty:20,weight:12,status:'已完成'}
|
||||
{id:'L11',ncType:'cp',foodName:'宫保鸡丁',spec:'标准份(500g)',qty:25,weight:12.5,price:12,subtotal:150,status:'已完成'},
|
||||
{id:'L12',ncType:'cp',foodName:'清蒸鱼',spec:'标准份(600g)',qty:20,weight:12,price:15,subtotal:180,status:'已完成'}
|
||||
]
|
||||
},
|
||||
{
|
||||
orderNo:'CO-007',orderType:'外售',ncType:'nc',claimTime:'2026-04-22 10:30',deliverTime:'2026-04-22 14:00',creator:'李主管',
|
||||
lines:[
|
||||
{id:'L13',ncType:'nc',ingredient:'土豆',ncName:'土豆块',spec:'2kg/袋',qty:10,weight:20,status:'已完成'},
|
||||
{id:'L14',ncType:'nc',ingredient:'菠菜',ncName:'菠菜碎',spec:'500g/袋',qty:20,weight:10,status:'配送中'}
|
||||
{id:'L13',ncType:'nc',ingredient:'土豆',ncName:'土豆块',spec:'2kg/袋',qty:10,weight:20,price:4,subtotal:80,status:'已完成'},
|
||||
{id:'L14',ncType:'nc',ingredient:'菠菜',ncName:'菠菜碎',spec:'500g/袋',qty:20,weight:10,price:5,subtotal:50,status:'配送中'}
|
||||
]
|
||||
},
|
||||
{
|
||||
orderNo:'CO-008',orderType:'内供',ncType:'cp',claimTime:'2026-04-22 11:00',deliverTime:'2026-04-22 13:00',creator:'张厨师',
|
||||
lines:[
|
||||
{id:'L15',ncType:'nc',ingredient:'西兰花',ncName:'西兰花朵',spec:'500g/袋',qty:30,weight:15,status:'已完成'},
|
||||
{id:'L16',ncType:'cp',foodName:'蒜蓉菠菜',spec:'标准份(400g)',qty:15,weight:6,status:'已完成'},
|
||||
{id:'L17',ncType:'cp',foodName:'炒胡萝卜',spec:'标准份(300g)',qty:20,weight:6,status:'已完成'}
|
||||
{id:'L15',ncType:'nc',ingredient:'西兰花',ncName:'西兰花朵',spec:'500g/袋',qty:30,weight:15,price:5,subtotal:75,status:'已完成'},
|
||||
{id:'L16',ncType:'cp',foodName:'蒜蓉菠菜',spec:'标准份(400g)',qty:15,weight:6,price:10,subtotal:60,status:'已完成'},
|
||||
{id:'L17',ncType:'cp',foodName:'炒胡萝卜',spec:'标准份(300g)',qty:20,weight:6,price:8,subtotal:48,status:'已完成'}
|
||||
]
|
||||
}
|
||||
];
|
||||
|
||||
/* ========== 订单金额工具函数 ========== */
|
||||
function calcOrderTotal(o){return o.lines.reduce(function(s,l){return s+(parseFloat(l.subtotal)||0);},0);}
|
||||
function formatMoney(n){var v=parseFloat(n)||0;return '¥'+v.toLocaleString('zh-CN',{minimumFractionDigits:0,maximumFractionDigits:2});}
|
||||
|
||||
/* ========== 状态聚合逻辑 ========== */
|
||||
function aggregateStatus(lines){
|
||||
var statuses=lines.map(function(l){return l.status;});
|
||||
@@ -517,6 +517,7 @@ function renderOrderTable(){
|
||||
html+='<td>'+order.lines.length+'</td>';
|
||||
html+='<td>'+totalQty+'</td>';
|
||||
html+='<td>'+totalWeight+'</td>';
|
||||
html+='<td><b>'+formatMoney(calcOrderTotal(order))+'</b></td>';
|
||||
html+='<td>'+statusTag(aggStatus)+'</td>';
|
||||
html+='<td>'+order.claimTime+'</td>';
|
||||
html+='<td>'+order.deliverTime+'</td>';
|
||||
@@ -536,9 +537,9 @@ function renderOrderTable(){
|
||||
/* 子表头 */
|
||||
if(order.lines.length>0){
|
||||
if(order.ncType==='nc'){
|
||||
html+='<tr class="detail-header" id="dhead-'+oi+'" data-order-idx="'+oi+'" style="display:none;"><td></td><td>食材</td><td>净菜名称</td><td>包装规格</td><td>份数</td><td>计量(kg)</td><td></td><td></td><td></td><td></td><td></td><td></td></tr>';
|
||||
html+='<tr class="detail-header" id="dhead-'+oi+'" data-order-idx="'+oi+'" style="display:none;"><td></td><td>食材</td><td>净菜名称</td><td>包装规格</td><td>份数</td><td>计量(kg)</td><td>单价(元/kg)</td><td>小计金额</td><td></td><td></td><td></td><td></td><td></td></tr>';
|
||||
}else{
|
||||
html+='<tr class="detail-header" id="dhead-'+oi+'" data-order-idx="'+oi+'" style="display:none;"><td></td><td colspan="2">菜品/食材</td><td>包装规格</td><td>份数</td><td>计量(kg)</td><td></td><td></td><td></td><td></td><td></td><td></td></tr>';
|
||||
html+='<tr class="detail-header" id="dhead-'+oi+'" data-order-idx="'+oi+'" style="display:none;"><td></td><td colspan="2">菜品/食材</td><td>包装规格</td><td>份数</td><td>计量(kg)</td><td>单价(元/kg)</td><td>小计金额</td><td></td><td></td><td></td><td></td><td></td></tr>';
|
||||
}
|
||||
}
|
||||
/* 明细行 */
|
||||
@@ -553,7 +554,8 @@ function renderOrderTable(){
|
||||
html+='<td>'+line.spec+'</td>';
|
||||
html+='<td>'+line.qty+'</td>';
|
||||
html+='<td>'+line.weight+'</td>';
|
||||
html+='<td></td><td></td><td></td><td></td><td></td>';
|
||||
html+='<td>'+(line.price||0)+'</td><td>'+formatMoney(line.subtotal||0)+'</td>';
|
||||
html+='<td></td><td></td><td></td><td></td>';
|
||||
html+='<td class="td-actions"></td></tr>';
|
||||
});
|
||||
});
|
||||
@@ -601,8 +603,6 @@ function onNewOrderNcTypeChange(val){
|
||||
newOrderLines=[];
|
||||
lineIdCounter=0;
|
||||
document.getElementById('orderLinesContainer').innerHTML='';
|
||||
document.getElementById('orderSummary').style.display='none';
|
||||
document.getElementById('orderSummaryBody').innerHTML='';
|
||||
addOrderLine();
|
||||
}
|
||||
|
||||
@@ -616,8 +616,6 @@ function resetOrderForm(){
|
||||
document.getElementById('orderCreator').value='';
|
||||
document.getElementById('orderRemark').value='';
|
||||
document.getElementById('orderLinesContainer').innerHTML='';
|
||||
document.getElementById('orderSummary').style.display='none';
|
||||
document.getElementById('orderSummaryBody').innerHTML='';
|
||||
/* 默认添加一条空行 */
|
||||
addOrderLine();
|
||||
}
|
||||
@@ -625,7 +623,7 @@ function resetOrderForm(){
|
||||
function addOrderLine(){
|
||||
lineIdCounter++;
|
||||
var lid='newLine'+lineIdCounter;
|
||||
newOrderLines.push({id:lid,ingredient:'',ncName:'',dish:'',portion:'标准份',baseGram:0,unit:newOrderNcType==='nc'?'袋':'份',qty:0,weight:0});
|
||||
newOrderLines.push({id:lid,ingredient:'',ncName:'',dish:'',portion:'标准份',baseGram:0,unit:newOrderNcType==='nc'?'袋':'份',qty:0,weight:0,price:0,subtotal:0});
|
||||
renderLineBuilders();
|
||||
}
|
||||
|
||||
@@ -712,6 +710,13 @@ function updateNewLineQty(lid,val){
|
||||
calcLineWeight(line);
|
||||
refreshSummary();
|
||||
}
|
||||
function updateNewLinePrice(lid,val){
|
||||
var line=newOrderLines.find(function(l){return l.id===lid;});
|
||||
if(!line)return;
|
||||
line.price=parseFloat(val)||0;
|
||||
calcLineWeight(line);
|
||||
refreshSummary();
|
||||
}
|
||||
|
||||
function calcLineWeight(line){
|
||||
if(line.baseGram>0&&line.qty>0){
|
||||
@@ -719,6 +724,11 @@ function calcLineWeight(line){
|
||||
}else{
|
||||
line.weight=0;
|
||||
}
|
||||
if(line.price>0&&line.weight>0){
|
||||
line.subtotal=parseFloat((line.price*line.weight).toFixed(2));
|
||||
}else{
|
||||
line.subtotal=0;
|
||||
}
|
||||
}
|
||||
/* 拼装规格显示文本:baseGram+unit/portion */
|
||||
function formatSpecLabel(line){
|
||||
@@ -740,9 +750,9 @@ function renderLineBuilders(){
|
||||
html+='<table class="inline-builder-table" id="lineBuilderTable">';
|
||||
html+='<thead><tr>';
|
||||
if(isNc){
|
||||
html+='<th>食材</th><th>净菜名称</th><th>包装规格</th><th>份数</th><th>计量(kg)</th><th>操作</th>';
|
||||
html+='<th>食材</th><th>净菜名称</th><th>包装规格</th><th>份数</th><th>计量(kg)</th><th>单价(元/kg)</th><th>小计金额</th><th>操作</th>';
|
||||
}else{
|
||||
html+='<th>餐品名称</th><th>包装规格</th><th>份数</th><th>计量(kg)</th><th>操作</th>';
|
||||
html+='<th>餐品名称</th><th>包装规格</th><th>份数</th><th>计量(kg)</th><th>单价(元/kg)</th><th>小计金额</th><th>操作</th>';
|
||||
}
|
||||
html+='</tr></thead><tbody>';
|
||||
/* 缓存当前餐品名列表,避免 forEach 内重复读取 localStorage */
|
||||
@@ -785,6 +795,9 @@ function renderLineBuilders(){
|
||||
html+='<td><input inputmode="numeric" placeholder="份数" value="'+(line.qty||'')+'" oninput="this.value=this.value.replace(/[^\\d]/g,\'\');updateNewLineQty(\''+line.id+'\',this.value)" style="width:56px;"></td>';
|
||||
/* 计量 */
|
||||
html+='<td><input value="'+(line.weight||'')+'" readonly style="width:60px;"></td>';
|
||||
/* 单价与小计金额 */
|
||||
html+='<td><input inputmode="decimal" placeholder="0" value="'+(line.price||'')+'" oninput="this.value=this.value.replace(/[^\\d.]/g,\'\');updateNewLinePrice(\''+line.id+'\',this.value)" style="width:70px;"></td>';
|
||||
html+='<td><input value="'+(line.subtotal?formatMoney(line.subtotal):'')+'" readonly style="width:80px;"></td>';
|
||||
/* 操作 */
|
||||
html+='<td><button class="btn-danger-text" onclick="removeOrderLine(\''+line.id+'\')" '+(newOrderLines.length<=1?'disabled':'')+'>移除</button></td>';
|
||||
html+='</tr>';
|
||||
@@ -795,31 +808,9 @@ function renderLineBuilders(){
|
||||
}
|
||||
|
||||
function refreshSummary(){
|
||||
var summaryDiv=document.getElementById('orderSummary');
|
||||
var thead=document.getElementById('orderSummaryHead');
|
||||
var tbody=document.getElementById('orderSummaryBody');
|
||||
var validLines=newOrderLines.filter(function(l){return l.weight>0;});
|
||||
if(validLines.length===0){
|
||||
summaryDiv.style.display='none';
|
||||
return;
|
||||
}
|
||||
summaryDiv.style.display='block';
|
||||
if(newOrderNcType==='nc'){
|
||||
thead.innerHTML='<tr><th>净菜类型</th><th>食材</th><th>净菜名称</th><th>包装规格</th><th>份数</th><th>计量(kg)</th></tr>';
|
||||
}else{
|
||||
thead.innerHTML='<tr><th>净菜类型</th><th>餐品名称</th><th>包装规格</th><th>份数</th><th>计量(kg)</th></tr>';
|
||||
}
|
||||
var html='';
|
||||
validLines.forEach(function(l){
|
||||
var typeLabel=newOrderNcType==='nc'?'净菜包':'餐品净菜包';
|
||||
var specLabel=formatSpecLabel(l);
|
||||
if(newOrderNcType==='nc'){
|
||||
html+='<tr><td>'+typeLabel+'</td><td>'+l.ingredient+'</td><td>'+l.ncName+'</td><td>'+specLabel+'</td><td>'+l.qty+'</td><td>'+l.weight+'</td></tr>';
|
||||
}else{
|
||||
html+='<tr><td>'+typeLabel+'</td><td>'+l.dish+'</td><td>'+specLabel+'</td><td>'+l.qty+'</td><td>'+l.weight+'</td></tr>';
|
||||
}
|
||||
});
|
||||
tbody.innerHTML=html;
|
||||
var totalAmt=validLines.reduce(function(s,l){return s+(l.subtotal||0);},0);
|
||||
var taEl=document.getElementById('orderTotalAmount');if(taEl)taEl.textContent=formatMoney(totalAmt);
|
||||
}
|
||||
|
||||
function submitCreateOrder(){
|
||||
@@ -849,6 +840,8 @@ function submitCreateOrder(){
|
||||
unit:l.unit||(l.ncType==='nc'?'袋':'份'),
|
||||
qty:l.qty,
|
||||
weight:l.weight,
|
||||
price:l.price,
|
||||
subtotal:l.subtotal,
|
||||
status:'备货中'
|
||||
};
|
||||
if(newOrderNcType==='nc'){
|
||||
@@ -920,6 +913,7 @@ function showDetail(orderNo){
|
||||
html+='<div class="drawer-field"><div class="drawer-field__label">菜品种类</div><div class="drawer-field__value">'+order.lines.length+'</div></div>';
|
||||
html+='<div class="drawer-field"><div class="drawer-field__label">总份数</div><div class="drawer-field__value">'+totalQty+'</div></div>';
|
||||
html+='<div class="drawer-field"><div class="drawer-field__label">总计量(kg)</div><div class="drawer-field__value">'+totalWeight+'</div></div>';
|
||||
html+='<div class="drawer-field"><div class="drawer-field__label">订单总金额</div><div class="drawer-field__value"><b style="color:var(--danger);">'+formatMoney(calcOrderTotal(order))+'</b></div></div>';
|
||||
html+='<div class="drawer-field"><div class="drawer-field__label">申领时间</div><div class="drawer-field__value">'+order.claimTime+'</div></div>';
|
||||
html+='<div class="drawer-field"><div class="drawer-field__label">预定配送时间</div><div class="drawer-field__value">'+order.deliverTime+'</div></div>';
|
||||
html+='<div class="drawer-field"><div class="drawer-field__label">创建人</div><div class="drawer-field__value">'+order.creator+'</div></div>';
|
||||
@@ -934,7 +928,7 @@ function showDetail(orderNo){
|
||||
}else{
|
||||
html+='<th>菜品/食材</th>';
|
||||
}
|
||||
html+='<th>包装规格</th><th>份数</th><th>计量(kg)</th><th>行状态</th></tr></thead><tbody>';
|
||||
html+='<th>包装规格</th><th>份数</th><th>计量(kg)</th><th>单价(元/kg)</th><th>小计金额</th><th>行状态</th></tr></thead><tbody>';
|
||||
order.lines.forEach(function(line){
|
||||
var tagCls={'已完成':'tag-green','配送中':'tag-blue','待配送':'tag-orange','备货中':'tag-gray'};
|
||||
html+='<tr><td>'+ncTypeTag(line.ncType)+'</td>';
|
||||
@@ -943,12 +937,12 @@ function showDetail(orderNo){
|
||||
}else{
|
||||
html+='<td'+(isNcOrder?' colspan="2"':'')+'><b>'+line.foodName+'</b></td>';
|
||||
}
|
||||
html+='<td>'+line.spec+'</td><td>'+line.qty+'</td><td>'+line.weight+'</td><td><span class="tag '+tagCls[line.status]+'">'+line.status+'</span></td></tr>';
|
||||
html+='<td>'+line.spec+'</td><td>'+line.qty+'</td><td>'+line.weight+'</td><td>'+(line.price||0)+'</td><td>'+formatMoney(line.subtotal||0)+'</td><td><span class="tag '+tagCls[line.status]+'">'+line.status+'</span></td></tr>';
|
||||
/* 餐品净菜包显示食材明细 */
|
||||
if(line.ncType==='cp'){
|
||||
var ings=dishIngredients[line.foodName]||[];
|
||||
if(ings.length>0){
|
||||
var colSpan=isNcOrder?7:6;
|
||||
var colSpan=isNcOrder?9:8;
|
||||
html+='<tr><td colspan="'+colSpan+'" style="padding:4px 10px;background:#fafafa;"><span style="font-size:11px;color:var(--text-placeholder);">食材构成:</span>';
|
||||
ings.forEach(function(ing,i){
|
||||
if(i>0)html+=', ';
|
||||
|
||||
@@ -207,7 +207,7 @@ function toggleSubgroup(header) {
|
||||
<div class="table-card__content">
|
||||
<table id="extOrderTable">
|
||||
<thead><tr>
|
||||
<th style="width:36px;"></th><th>订单号</th><th>客户名称</th><th>净菜类型</th><th>菜品种类</th><th>总份数</th><th>总计量(kg)</th><th>下单时间</th><th>预定配送</th><th>物流单号</th><th>订单状态</th><th>操作</th>
|
||||
<th style="width:36px;"></th><th>订单号</th><th>客户名称</th><th>净菜类型</th><th>菜品种类</th><th>总份数</th><th>总计量(kg)</th><th>订单金额</th><th>下单时间</th><th>预定配送</th><th>物流单号</th><th>订单状态</th><th>操作</th>
|
||||
</tr></thead>
|
||||
<tbody id="extOrderTableBody"></tbody>
|
||||
</table>
|
||||
@@ -243,15 +243,12 @@ function toggleSubgroup(header) {
|
||||
<button class="btn btn-primary btn-sm" onclick="addExtLine()">+ 添加菜品</button>
|
||||
</div>
|
||||
<div id="extLinesContainer"></div>
|
||||
<div id="extSummary" style="display:none;">
|
||||
<div style="font-size:var(--font-sm);font-weight:600;margin:12px 0 8px;">汇总预览</div>
|
||||
<table class="order-summary-table">
|
||||
<thead id="extSummaryHead"><tr><th>净菜类型</th><th>菜品/食材</th><th>包装规格</th><th>份数</th><th>计量(kg)</th></tr></thead>
|
||||
<tbody id="extSummaryBody"></tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div style="display:flex;align-items:center;justify-content:flex-end;padding:12px 24px;border-top:1px solid var(--border);background:#fafafa;gap:12px;">
|
||||
<span style="font-size:var(--font-sm);color:var(--text-secondary);">订单总金额:</span>
|
||||
<span id="extTotalAmount" style="font-weight:700;color:var(--danger);font-size:var(--font-xl);">¥0</span>
|
||||
</div>
|
||||
<div class="modal__footer">
|
||||
<button class="btn btn-default" onclick="closeModal('createOrderModal')">取消</button>
|
||||
<button class="btn btn-primary" onclick="submitExtOrder()">确认提交</button>
|
||||
@@ -380,37 +377,41 @@ var dishIngsExt={
|
||||
var extOrders=[
|
||||
{orderNo:'EXT-001',ncType:'nc',customer:'社区便民超市',orderTime:'2026-04-22 08:00',deliverTime:'2026-04-22 16:00',logistics:'SF1234567890',
|
||||
lines:[
|
||||
{id:'L1',ingredient:'土豆',ncName:'土豆丝',spec:'5kg/箱',qty:10,weight:50,status:'已完成'},
|
||||
{id:'L2',ingredient:'土豆',ncName:'土豆块',spec:'5kg/箱',qty:6,weight:30,status:'已完成'}
|
||||
{id:'L1',ingredient:'土豆',ncName:'土豆丝',spec:'5kg/箱',qty:10,weight:50,price:3.5,subtotal:175,status:'已完成'},
|
||||
{id:'L2',ingredient:'土豆',ncName:'土豆块',spec:'5kg/箱',qty:6,weight:30,price:3.5,subtotal:105,status:'已完成'}
|
||||
]},
|
||||
{orderNo:'EXT-002',ncType:'nc',customer:'周边餐饮企业',orderTime:'2026-04-22 09:30',deliverTime:'2026-04-22 14:00',logistics:'SF9876543210',
|
||||
lines:[
|
||||
{id:'L3',ingredient:'净猪里脊',ncName:'里脊条',spec:'1kg/箱',qty:10,weight:10,status:'配送中'},
|
||||
{id:'L4',ingredient:'宫保鸡丁',ncName:'',spec:'标准份(500g)',qty:40,weight:20,status:'配送中'}
|
||||
{id:'L3',ingredient:'净猪里脊',ncName:'里脊条',spec:'1kg/箱',qty:10,weight:10,price:28,subtotal:280,status:'配送中'},
|
||||
{id:'L4',ingredient:'宫保鸡丁',ncName:'',spec:'标准份(500g)',qty:40,weight:20,price:12,subtotal:240,status:'配送中'}
|
||||
]},
|
||||
{orderNo:'EXT-003',ncType:'nc',customer:'学校食堂',orderTime:'2026-04-22 10:00',deliverTime:'2026-04-23 09:00',logistics:'—',
|
||||
lines:[
|
||||
{id:'L5',ingredient:'鸡肉',ncName:'鸡肉块',spec:'1kg/箱',qty:60,weight:60,status:'待配送'},
|
||||
{id:'L6',ingredient:'西兰花',ncName:'西兰花朵',spec:'5kg/箱',qty:8,weight:40,status:'待配送'}
|
||||
{id:'L5',ingredient:'鸡肉',ncName:'鸡肉块',spec:'1kg/箱',qty:60,weight:60,price:20,subtotal:1200,status:'待配送'},
|
||||
{id:'L6',ingredient:'西兰花',ncName:'西兰花朵',spec:'5kg/箱',qty:8,weight:40,price:4.5,subtotal:180,status:'待配送'}
|
||||
]},
|
||||
{orderNo:'EXT-004',ncType:'nc',customer:'职工家属区团购',orderTime:'2026-04-22 10:30',deliverTime:'2026-04-23 16:00',logistics:'—',
|
||||
lines:[
|
||||
{id:'L7',ingredient:'清蒸鱼',ncName:'',spec:'标准份(600g)',qty:20,weight:12,status:'备货中'},
|
||||
{id:'L8',ingredient:'蒜蓉菠菜',ncName:'',spec:'标准份(400g)',qty:30,weight:12,status:'备货中'},
|
||||
{id:'L9',ingredient:'胡萝卜',ncName:'胡萝卜条',spec:'2kg/箱',qty:15,weight:30,status:'备货中'}
|
||||
{id:'L7',ingredient:'清蒸鱼',ncName:'',spec:'标准份(600g)',qty:20,weight:12,price:15,subtotal:180,status:'备货中'},
|
||||
{id:'L8',ingredient:'蒜蓉菠菜',ncName:'',spec:'标准份(400g)',qty:30,weight:12,price:8,subtotal:96,status:'备货中'},
|
||||
{id:'L9',ingredient:'胡萝卜',ncName:'胡萝卜条',spec:'2kg/箱',qty:15,weight:30,price:4,subtotal:120,status:'备货中'}
|
||||
]},
|
||||
{orderNo:'EXT-005',ncType:'nc',customer:'社区便民超市',orderTime:'2026-04-22 11:00',deliverTime:'2026-04-23 10:00',logistics:'—',
|
||||
lines:[
|
||||
{id:'L10',ingredient:'菠菜',ncName:'菠菜段',spec:'3kg/箱',qty:12,weight:36,status:'已完成'},
|
||||
{id:'L11',ingredient:'炒胡萝卜',ncName:'',spec:'标准份(300g)',qty:25,weight:7.5,status:'配送中'}
|
||||
{id:'L10',ingredient:'菠菜',ncName:'菠菜段',spec:'3kg/箱',qty:12,weight:36,price:5,subtotal:180,status:'已完成'},
|
||||
{id:'L11',ingredient:'炒胡萝卜',ncName:'',spec:'标准份(300g)',qty:25,weight:7.5,price:18,subtotal:135,status:'配送中'}
|
||||
]},
|
||||
{orderNo:'EXT-006',ncType:'nc',customer:'周边餐饮企业',orderTime:'2026-04-22 12:00',deliverTime:'2026-04-23 12:00',logistics:'SF5566778899',
|
||||
lines:[
|
||||
{id:'L12',ingredient:'净猪里脊',ncName:'里脊条',spec:'1kg/箱',qty:15,weight:15,status:'已完成'},
|
||||
{id:'L13',ingredient:'宫保鸡丁',ncName:'',spec:'标准份(500g)',qty:50,weight:25,status:'已完成'},
|
||||
{id:'L14',ingredient:'清蒸鱼',ncName:'',spec:'标准份(600g)',qty:30,weight:18,status:'已完成'}
|
||||
{id:'L12',ingredient:'净猪里脊',ncName:'里脊条',spec:'1kg/箱',qty:15,weight:15,price:28,subtotal:420,status:'已完成'},
|
||||
{id:'L13',ingredient:'宫保鸡丁',ncName:'',spec:'标准份(500g)',qty:50,weight:25,price:12,subtotal:300,status:'已完成'},
|
||||
{id:'L14',ingredient:'清蒸鱼',ncName:'',spec:'标准份(600g)',qty:30,weight:18,price:15,subtotal:270,status:'已完成'}
|
||||
]}
|
||||
];
|
||||
/* 计算订单总金额:Σ(各明细小计) */
|
||||
function calcOrderTotal(o){return o.lines.reduce(function(s,l){return s+(parseFloat(l.subtotal)||0);},0);}
|
||||
/* 金额格式化:¥1,234.5 */
|
||||
function formatMoney(n){var v=parseFloat(n)||0;return '¥'+v.toLocaleString('zh-CN',{minimumFractionDigits:0,maximumFractionDigits:2});}
|
||||
|
||||
function aggregateStatus(lines){var ss=lines.map(function(l){return l.status;});
|
||||
if(ss.every(function(s){return s==='已完成';}))return '已完成';
|
||||
@@ -428,7 +429,7 @@ function renderExtTable(){
|
||||
var tW=o.lines.reduce(function(s,l){return s+parseFloat(l.weight);},0).toFixed(2);
|
||||
h+='<tr class="master-row" data-ext-idx="'+oi+'" onclick="toggleExpandExt(this,'+oi+')">';
|
||||
h+='<td><span class="expand-arrow" id="earrow'+oi+'">▶</span></td>';
|
||||
h+='<td><b>'+o.orderNo+'</b></td><td>'+o.customer+'</td><td>'+ncTypeTag(o.ncType)+'</td><td>'+o.lines.length+'</td><td>'+tQ+'</td><td>'+tW+'</td>';
|
||||
h+='<td><b>'+o.orderNo+'</b></td><td>'+o.customer+'</td><td>'+ncTypeTag(o.ncType)+'</td><td>'+o.lines.length+'</td><td>'+tQ+'</td><td>'+tW+'</td><td><b>'+formatMoney(calcOrderTotal(o))+'</b></td>';
|
||||
h+='<td>'+o.orderTime+'</td><td>'+o.deliverTime+'</td><td>'+o.logistics+'</td><td>'+statusTag(agg)+'</td>';
|
||||
/* 主行操作按钮:根据聚合状态显示 */
|
||||
var abtns='';
|
||||
@@ -439,20 +440,22 @@ function renderExtTable(){
|
||||
h+='</tr>';
|
||||
/* 子表头 — 根据 ncType 动态显示列 */
|
||||
if(o.ncType==='nc'){
|
||||
h+='<tr class="detail-header" id="ehead-'+oi+'" style="display:none;"><td></td><td>食材</td><td>净菜名称</td><td></td><td>包装规格</td><td>份数</td><td>计量(kg)</td><td></td><td></td><td></td></tr>';
|
||||
h+='<tr class="detail-header" id="ehead-'+oi+'" style="display:none;"><td></td><td>食材</td><td>净菜名称</td><td></td><td>包装规格</td><td>份数</td><td>计量(kg)</td><td>单价(元/kg)</td><td>小计金额</td><td></td><td></td><td></td></tr>';
|
||||
o.lines.forEach(function(l){
|
||||
h+='<tr class="detail-row" id="edetail-'+oi+'" style="display:none;">';
|
||||
h+='<td></td><td style="font-weight:500;">'+l.ingredient+'</td><td style="font-weight:500;">'+(l.ncName||'—')+'</td><td></td>';
|
||||
h+='<td>'+l.spec+'</td><td>'+l.qty+'</td><td>'+l.weight+'</td>';
|
||||
h+='<td>'+(l.price||0)+'</td><td>'+formatMoney(l.subtotal||0)+'</td>';
|
||||
h+='<td></td><td></td><td></td>';
|
||||
h+='<td class="td-actions"></td></tr>';
|
||||
});
|
||||
}else{
|
||||
h+='<tr class="detail-header" id="ehead-'+oi+'" style="display:none;"><td></td><td colspan="3">菜品/食材</td><td>包装规格</td><td>份数</td><td>计量(kg)</td><td></td><td></td><td></td></tr>';
|
||||
h+='<tr class="detail-header" id="ehead-'+oi+'" style="display:none;"><td></td><td colspan="3">菜品/食材</td><td>包装规格</td><td>份数</td><td>计量(kg)</td><td>单价(元/kg)</td><td>小计金额</td><td></td><td></td><td></td></tr>';
|
||||
o.lines.forEach(function(l){
|
||||
h+='<tr class="detail-row" id="edetail-'+oi+'" style="display:none;">';
|
||||
h+='<td></td><td colspan="3" style="font-weight:500;">'+l.foodName+'</td>';
|
||||
h+='<td>'+l.spec+'</td><td>'+l.qty+'</td><td>'+l.weight+'</td>';
|
||||
h+='<td>'+(l.price||0)+'</td><td>'+formatMoney(l.subtotal||0)+'</td>';
|
||||
h+='<td></td><td></td><td></td>';
|
||||
h+='<td class="td-actions"></td></tr>';
|
||||
});
|
||||
@@ -494,8 +497,8 @@ function doReadyExt(){var b=document.getElementById('readyBatchSelectExt').value
|
||||
var newExtOrderType='nc';
|
||||
function updExtOrderType(v){newExtOrderType=v;renderExtLineBuilders();}
|
||||
var newExtLines=[];var extLineCnt=0;
|
||||
function resetExtForm(){newExtLines=[];extLineCnt=0;newExtOrderType=document.getElementById('extOrderNcType').value;document.getElementById('extCustomer').value='';document.getElementById('extContact').value='';document.getElementById('extPhone').value='';document.getElementById('extDeliverTime').value='';document.getElementById('extAddress').value='';document.getElementById('extRemark').value='';document.getElementById('extLinesContainer').innerHTML='';document.getElementById('extSummary').style.display='none';addExtLine();}
|
||||
function addExtLine(){extLineCnt++;newExtLines.push({id:'el'+extLineCnt,ingredient:'',ncType:'',dish:'',portion:'标准份',baseGram:0,unit:newExtOrderType==='nc'?'箱':'份',qty:0,weight:0});renderExtLineBuilders();}
|
||||
function resetExtForm(){newExtLines=[];extLineCnt=0;newExtOrderType=document.getElementById('extOrderNcType').value;document.getElementById('extCustomer').value='';document.getElementById('extContact').value='';document.getElementById('extPhone').value='';document.getElementById('extDeliverTime').value='';document.getElementById('extAddress').value='';document.getElementById('extRemark').value='';document.getElementById('extLinesContainer').innerHTML='';var taEl=document.getElementById('extTotalAmount');if(taEl)taEl.textContent=formatMoney(0);addExtLine();}
|
||||
function addExtLine(){extLineCnt++;newExtLines.push({id:'el'+extLineCnt,ingredient:'',ncType:'',dish:'',portion:'标准份',baseGram:0,unit:newExtOrderType==='nc'?'箱':'份',qty:0,weight:0,price:0,subtotal:0});renderExtLineBuilders();}
|
||||
function removeExtLine(lid){if(newExtLines.length<=1){alert('至少保留一条');return;}newExtLines=newExtLines.filter(function(l){return l.id!==lid;});renderExtLineBuilders();}
|
||||
|
||||
function updELIngredient(lid,v){var l=newExtLines.find(function(x){return x.id===lid;});if(!l)return;l.ingredient=v;l.ncType='';renderExtLineBuilders();}
|
||||
@@ -526,16 +529,22 @@ function updELPortion(lid,v){
|
||||
function updELUnit(lid,v){var l=newExtLines.find(function(x){return x.id===lid;});if(!l)return;l.unit=v;refreshESummary();}
|
||||
function updELNcBaseGram(lid,v){var l=newExtLines.find(function(x){return x.id===lid;});if(!l)return;l.baseGram=parseInt(v||'0',10);l.unit='箱';calcELW(l);refreshESummary();}
|
||||
function updELQty(lid,v){var l=newExtLines.find(function(x){return x.id===lid;});if(!l)return;l.qty=parseInt(v.replace(/[^\d]/g,'')||'0',10);calcELW(l);refreshESummary();}
|
||||
function calcELW(l){if(l.baseGram>0&&l.qty>0)l.weight=parseFloat((l.baseGram*l.qty/1000).toFixed(2));else l.weight=0;}
|
||||
/* 单价(元/kg)输入:同步小计金额 = 单价 × 计量(kg) */
|
||||
function updELPrice(lid,v){var l=newExtLines.find(function(x){return x.id===lid;});if(!l)return;l.price=parseFloat(v)||0;calcELW(l);refreshESummary();}
|
||||
function calcELW(l){
|
||||
if(l.baseGram>0&&l.qty>0)l.weight=parseFloat((l.baseGram*l.qty/1000).toFixed(2));else l.weight=0;
|
||||
/* 小计金额 = 单价(元/kg) × 计量(kg) */
|
||||
if(l.price>0&&l.weight>0)l.subtotal=parseFloat((l.price*l.weight).toFixed(2));else l.subtotal=0;
|
||||
}
|
||||
|
||||
function renderExtLineBuilders(){
|
||||
var h='';
|
||||
var isNc=newExtOrderType==='nc';
|
||||
h+='<table class="line-builder-table"><thead><tr>';
|
||||
if(isNc){
|
||||
h+='<th>食材</th><th>净菜名称</th><th>包装规格(g)</th><th>份数</th><th>计量(kg)</th><th>操作</th>';
|
||||
h+='<th>食材</th><th>净菜名称</th><th>包装规格(g)</th><th>份数</th><th>计量(kg)</th><th>单价(元/kg)</th><th>小计金额</th><th>操作</th>';
|
||||
}else{
|
||||
h+='<th>餐品名称</th><th>包装规格</th><th>份数</th><th>计量(kg)</th><th>操作</th>';
|
||||
h+='<th>餐品名称</th><th>包装规格</th><th>份数</th><th>计量(kg)</th><th>单价(元/kg)</th><th>小计金额</th><th>操作</th>';
|
||||
}
|
||||
h+='</tr></thead><tbody>';
|
||||
var dishNames=getDishNamesWithFallback();
|
||||
@@ -568,8 +577,10 @@ function renderExtLineBuilders(){
|
||||
portionOptions.forEach(function(p){h+='<option value="'+p+'" '+(l.portion===p?'selected':'')+'>'+p+'</option>';});
|
||||
h+='</select></div></td>';
|
||||
}
|
||||
h+='<td><input inputmode="numeric" placeholder="份数" value="'+(l.qty||'')+'" oninput="this.value=this.value.replace(/[^\d]/g,\x27\x27);updELQty(\x27'+l.id+'\x27,this.value)"></td>';
|
||||
h+='<td><input inputmode="numeric" placeholder="份数" value="'+(l.qty||'')+'" oninput="this.value=this.value.replace(/[^\\d]/g,\'\');updELQty(\''+l.id+'\',this.value)"></td>';
|
||||
h+='<td><input value="'+(l.weight||'')+'" readonly></td>';
|
||||
h+='<td><input inputmode="decimal" placeholder="0" value="'+(l.price||'')+'" oninput="this.value=this.value.replace(/[^\\d.]/g,\'\');updELPrice(\''+l.id+'\',this.value)"></td>';
|
||||
h+='<td><input value="'+(l.subtotal?formatMoney(l.subtotal):'')+'" readonly></td>';
|
||||
h+='<td><button class="btn-remove" onclick="removeExtLine(\''+l.id+'\')">移除</button></td>';
|
||||
h+='</tr>';
|
||||
});
|
||||
@@ -579,19 +590,10 @@ function renderExtLineBuilders(){
|
||||
}
|
||||
|
||||
function refreshESummary(){
|
||||
var sd=document.getElementById('extSummary');var tb=document.getElementById('extSummaryBody');
|
||||
var sh=document.getElementById('extSummaryHead');
|
||||
/* 同步订单总金额(汇总预览已移除,仅保留底部订单总金额展示) */
|
||||
var vl=newExtLines.filter(function(l){return l.weight>0;});
|
||||
if(vl.length===0){sd.style.display='none';return;}
|
||||
sd.style.display='block';var h='';
|
||||
if(newExtOrderType==='nc'){
|
||||
sh.innerHTML='<tr><th>净菜类型</th><th>食材</th><th>净菜名称</th><th>包装规格</th><th>份数</th><th>计量(kg)</th></tr>';
|
||||
vl.forEach(function(l){h+='<tr><td>净菜包</td><td>'+(l.ingredient||'')+'</td><td>'+(l.ncType||'')+'</td><td>'+formatSpecLabelExt(l)+'</td><td>'+l.qty+'</td><td>'+l.weight+'</td></tr>';});
|
||||
}else{
|
||||
sh.innerHTML='<tr><th>净菜类型</th><th>菜品/食材</th><th>包装规格</th><th>份数</th><th>计量(kg)</th></tr>';
|
||||
vl.forEach(function(l){h+='<tr><td>餐品净菜包</td><td>'+(l.dish||'')+'</td><td>'+formatSpecLabelExt(l)+'</td><td>'+l.qty+'</td><td>'+l.weight+'</td></tr>';});
|
||||
}
|
||||
tb.innerHTML=h;
|
||||
var totalAmt=vl.reduce(function(s,l){return s+(l.subtotal||0);},0);
|
||||
var taEl=document.getElementById('extTotalAmount');if(taEl)taEl.textContent=formatMoney(totalAmt);
|
||||
}
|
||||
|
||||
function submitExtOrder(){
|
||||
@@ -603,9 +605,9 @@ function submitExtOrder(){
|
||||
var newLines=vl.map(function(l,i){
|
||||
var specLbl=formatSpecLabelExt(l);
|
||||
if(newExtOrderType==='nc'){
|
||||
return {id:'L'+(Date.now()+i),ingredient:l.ingredient,ncName:l.ncType,spec:specLbl,portion:l.portion,baseGram:l.baseGram,unit:l.unit,qty:l.qty,weight:l.weight,status:'备货中'};
|
||||
return {id:'L'+(Date.now()+i),ingredient:l.ingredient,ncName:l.ncType,spec:specLbl,portion:l.portion,baseGram:l.baseGram,unit:l.unit,qty:l.qty,weight:l.weight,price:l.price||0,subtotal:l.subtotal||0,status:'备货中'};
|
||||
}
|
||||
return {id:'L'+(Date.now()+i),foodName:l.dish,spec:specLbl,portion:l.portion,baseGram:l.baseGram,unit:l.unit,qty:l.qty,weight:l.weight,status:'备货中'};
|
||||
return {id:'L'+(Date.now()+i),foodName:l.dish,spec:specLbl,portion:l.portion,baseGram:l.baseGram,unit:l.unit,qty:l.qty,weight:l.weight,price:l.price||0,subtotal:l.subtotal||0,status:'备货中'};
|
||||
});
|
||||
extOrders.unshift({orderNo:no,customer:cust,orderTime:new Date().toISOString().slice(0,16).replace('T',' '),deliverTime:dt,logistics:'—',
|
||||
ncType:newExtOrderType,lines:newLines});
|
||||
@@ -626,23 +628,24 @@ function showDetailExt(no){
|
||||
h+='<div class="drawer-field"><div class="drawer-field__label">菜品种类</div><div class="drawer-field__value">'+o.lines.length+'</div></div>';
|
||||
h+='<div class="drawer-field"><div class="drawer-field__label">总份数</div><div class="drawer-field__value">'+tQ+'</div></div>';
|
||||
h+='<div class="drawer-field"><div class="drawer-field__label">总计量(kg)</div><div class="drawer-field__value">'+tW+'</div></div>';
|
||||
h+='<div class="drawer-field"><div class="drawer-field__label">订单总金额</div><div class="drawer-field__value" style="color:var(--danger);font-weight:700;">'+formatMoney(calcOrderTotal(o))+'</div></div>';
|
||||
h+='<div class="drawer-field"><div class="drawer-field__label">下单时间</div><div class="drawer-field__value">'+o.orderTime+'</div></div>';
|
||||
h+='<div class="drawer-field"><div class="drawer-field__label">预定配送</div><div class="drawer-field__value">'+o.deliverTime+'</div></div>';
|
||||
h+='<div class="drawer-field"><div class="drawer-field__label">物流单号</div><div class="drawer-field__value">'+o.logistics+'</div></div>';
|
||||
h+='</div></div>';
|
||||
h+='<div class="drawer-section"><div class="drawer-section__title">订单明细('+o.lines.length+' 道)</div>';
|
||||
if(o.ncType==='nc'){
|
||||
h+='<table class="ing-table"><thead><tr><th>食材</th><th>净菜名称</th><th>包装规格</th><th>份数</th><th>计量(kg)</th><th>状态</th></tr></thead><tbody>';
|
||||
h+='<table class="ing-table"><thead><tr><th>食材</th><th>净菜名称</th><th>包装规格</th><th>份数</th><th>计量(kg)</th><th>单价(元/kg)</th><th>小计金额</th><th>状态</th></tr></thead><tbody>';
|
||||
o.lines.forEach(function(l){
|
||||
var tc={'已完成':'tag-green','配送中':'tag-blue','待配送':'tag-orange','备货中':'tag-gray'};
|
||||
h+='<tr><td style="font-weight:600;">'+l.ingredient+'</td><td style="font-weight:600;">'+(l.ncName||'—')+'</td><td>'+l.spec+'</td><td>'+l.qty+'</td><td>'+l.weight+'</td><td><span class="tag '+tc[l.status]+'">'+l.status+'</span></td></tr>';
|
||||
h+='<tr><td style="font-weight:600;">'+l.ingredient+'</td><td style="font-weight:600;">'+(l.ncName||'—')+'</td><td>'+l.spec+'</td><td>'+l.qty+'</td><td>'+l.weight+'</td><td>'+(l.price||0)+'</td><td>'+formatMoney(l.subtotal||0)+'</td><td><span class="tag '+tc[l.status]+'">'+l.status+'</span></td></tr>';
|
||||
});
|
||||
}else{
|
||||
h+='<table class="ing-table"><thead><tr><th>菜品/食材</th><th>包装规格</th><th>份数</th><th>计量(kg)</th><th>状态</th></tr></thead><tbody>';
|
||||
h+='<table class="ing-table"><thead><tr><th>菜品/食材</th><th>包装规格</th><th>份数</th><th>计量(kg)</th><th>单价(元/kg)</th><th>小计金额</th><th>状态</th></tr></thead><tbody>';
|
||||
o.lines.forEach(function(l){
|
||||
var tc={'已完成':'tag-green','配送中':'tag-blue','待配送':'tag-orange','备货中':'tag-gray'};
|
||||
h+='<tr><td style="font-weight:600;"><b>'+l.foodName+'</b></td><td>'+l.spec+'</td><td>'+l.qty+'</td><td>'+l.weight+'</td><td><span class="tag '+tc[l.status]+'">'+l.status+'</span></td></tr>';
|
||||
var ings=dishIngsExt[l.foodName]||[];if(ings.length>0){h+='<tr><td colspan="5" style="padding:4px 10px;background:#fafafa;"><span style="font-size:11px;color:var(--text-placeholder);">食材构成:</span>';ings.forEach(function(ing,i){if(i>0)h+=', ';h+=ing.name+'('+ing.amount+')';});h+='</td></tr>';}
|
||||
h+='<tr><td style="font-weight:600;"><b>'+l.foodName+'</b></td><td>'+l.spec+'</td><td>'+l.qty+'</td><td>'+l.weight+'</td><td>'+(l.price||0)+'</td><td>'+formatMoney(l.subtotal||0)+'</td><td><span class="tag '+tc[l.status]+'">'+l.status+'</span></td></tr>';
|
||||
var ings=dishIngsExt[l.foodName]||[];if(ings.length>0){h+='<tr><td colspan="7" style="padding:4px 10px;background:#fafafa;"><span style="font-size:11px;color:var(--text-placeholder);">食材构成:</span>';ings.forEach(function(ing,i){if(i>0)h+=', ';h+=ing.name+'('+ing.amount+')';});h+='</td></tr>';}
|
||||
});
|
||||
}
|
||||
h+='</tbody></table></div>';
|
||||
|
||||
@@ -212,7 +212,7 @@ tr.detail-row td.td-actions{background:#FAFBFC;box-shadow:-4px 0 8px rgba(0,0,0,
|
||||
<div class="table-card__content">
|
||||
<table id="claimTable">
|
||||
<thead><tr>
|
||||
<th style="width:36px;"></th><th>申领单号</th><th>申领场所</th><th>净菜类型</th><th>菜品种类</th><th>总份数</th><th>总数量(kg)</th><th>申领单状态</th><th>申领时间</th><th>预定配送时间</th><th>配送人</th><th>操作</th>
|
||||
<th style="width:36px;"></th><th>申领单号</th><th>申领场所</th><th>净菜类型</th><th>菜品种类</th><th>总份数</th><th>总数量(kg)</th><th>订单金额</th><th>申领单状态</th><th>申领时间</th><th>预定配送时间</th><th>配送人</th><th>操作</th>
|
||||
</tr></thead>
|
||||
<tbody id="claimTableBody"></tbody>
|
||||
</table>
|
||||
@@ -260,15 +260,12 @@ tr.detail-row td.td-actions{background:#FAFBFC;box-shadow:-4px 0 8px rgba(0,0,0,
|
||||
<button class="btn btn-primary btn-sm" onclick="addClaimLine()">+ 添加菜品</button>
|
||||
</div>
|
||||
<div id="claimLinesContainer"></div>
|
||||
<div id="claimSummary" style="display:none;">
|
||||
<div style="font-size:var(--font-sm);font-weight:600;margin:12px 0 8px;">汇总预览</div>
|
||||
<table class="order-summary-table">
|
||||
<thead id="claimSummaryHead"></thead>
|
||||
<tbody id="claimSummaryBody"></tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div style="display:flex;align-items:center;justify-content:flex-end;padding:12px 24px;border-top:1px solid var(--border);background:#fafafa;gap:12px;">
|
||||
<span style="font-size:var(--font-sm);color:var(--text-secondary);">订单总金额:</span>
|
||||
<span id="claimTotalAmount" style="font-weight:700;color:var(--danger);font-size:var(--font-xl);">¥0</span>
|
||||
</div>
|
||||
<div class="modal__footer">
|
||||
<button class="btn btn-default" onclick="closeModal('modal-claim')">取消</button>
|
||||
<button class="btn btn-primary" onclick="submitClaim()">确认提交</button>
|
||||
@@ -404,31 +401,35 @@ var dishIngredients={
|
||||
var claims=[
|
||||
{claimNo:'INT-001',canteen:'一号食堂厨房',ncType:'nc',claimTime:'2026-04-22 07:30',deliverTime:'2026-04-22 09:00',deliverPerson:'李配送',
|
||||
lines:[
|
||||
{id:'L1',ingredient:'菠菜',ncName:'菠菜段',spec:'500g/袋',qty:50,weight:25,status:'已完成'},
|
||||
{id:'L2',ingredient:'玉米',ncName:'玉米粒',spec:'1kg/盒',qty:20,weight:20,status:'已完成'}
|
||||
{id:'L1',ingredient:'菠菜',ncName:'菠菜段',spec:'500g/袋',qty:50,weight:25,price:5,subtotal:125,status:'已完成'},
|
||||
{id:'L2',ingredient:'玉米',ncName:'玉米粒',spec:'1kg/盒',qty:20,weight:20,price:6,subtotal:120,status:'已完成'}
|
||||
]},
|
||||
{claimNo:'INT-002',canteen:'二号食堂厨房',ncType:'nc',claimTime:'2026-04-22 08:00',deliverTime:'2026-04-22 10:00',deliverPerson:'王配送',
|
||||
lines:[
|
||||
{id:'L3',ingredient:'猪排骨',ncName:'排骨块',spec:'2kg/盘',qty:20,weight:40,status:'配送中'},
|
||||
{id:'L4',ingredient:'土豆',ncName:'土豆丝',spec:'500g/袋',qty:30,weight:15,status:'配送中'}
|
||||
{id:'L3',ingredient:'猪排骨',ncName:'排骨块',spec:'2kg/盘',qty:20,weight:40,price:25,subtotal:1000,status:'配送中'},
|
||||
{id:'L4',ingredient:'土豆',ncName:'土豆丝',spec:'500g/袋',qty:30,weight:15,price:3.5,subtotal:52.5,status:'配送中'}
|
||||
]},
|
||||
{claimNo:'INT-003',canteen:'三号食堂厨房',ncType:'nc',claimTime:'2026-04-22 08:30',deliverTime:'2026-04-22 10:30',deliverPerson:'—',
|
||||
lines:[
|
||||
{id:'L5',ingredient:'草鱼',ncName:'鱼片',spec:'2kg/盘',qty:20,weight:40,status:'待配送'},
|
||||
{id:'L6',ingredient:'鸡胸肉',ncName:'鸡胸肉丝',spec:'500g/袋',qty:15,weight:7.5,status:'待配送'}
|
||||
{id:'L5',ingredient:'草鱼',ncName:'鱼片',spec:'2kg/盘',qty:20,weight:40,price:18,subtotal:720,status:'待配送'},
|
||||
{id:'L6',ingredient:'鸡胸肉',ncName:'鸡胸肉丝',spec:'500g/袋',qty:15,weight:7.5,price:20,subtotal:150,status:'待配送'}
|
||||
]},
|
||||
{claimNo:'INT-004',canteen:'一号食堂厨房',ncType:'nc',claimTime:'2026-04-22 09:15',deliverTime:'2026-04-22 11:30',deliverPerson:'—',
|
||||
lines:[
|
||||
{id:'L7',ingredient:'土豆',ncName:'土豆丝',spec:'500g/袋',qty:40,weight:20,status:'备货中'},
|
||||
{id:'L8',ingredient:'菠菜',ncName:'菠菜碎',spec:'500g/袋',qty:25,weight:12.5,status:'备货中'},
|
||||
{id:'L9',ingredient:'西兰花',ncName:'西兰花朵',spec:'500g/袋',qty:30,weight:15,status:'备货中'}
|
||||
{id:'L7',ingredient:'土豆',ncName:'土豆丝',spec:'500g/袋',qty:40,weight:20,price:3.5,subtotal:70,status:'备货中'},
|
||||
{id:'L8',ingredient:'菠菜',ncName:'菠菜碎',spec:'500g/袋',qty:25,weight:12.5,price:5,subtotal:62.5,status:'备货中'},
|
||||
{id:'L9',ingredient:'西兰花',ncName:'西兰花朵',spec:'500g/袋',qty:30,weight:15,price:6,subtotal:90,status:'备货中'}
|
||||
]},
|
||||
{claimNo:'INT-005',canteen:'二号食堂厨房',ncType:'cp',claimTime:'2026-04-22 09:30',deliverTime:'2026-04-22 12:00',deliverPerson:'—',
|
||||
lines:[
|
||||
{id:'L10',foodName:'宫保鸡丁',spec:'标准份(500g)',qty:20,weight:10,status:'已完成'},
|
||||
{id:'L11',foodName:'炒胡萝卜',spec:'标准份(300g)',qty:15,weight:4.5,status:'配送中'}
|
||||
{id:'L10',foodName:'宫保鸡丁',spec:'标准份(500g)',qty:20,weight:10,price:12,subtotal:120,status:'已完成'},
|
||||
{id:'L11',foodName:'炒胡萝卜',spec:'标准份(300g)',qty:15,weight:4.5,price:18,subtotal:81,status:'配送中'}
|
||||
]}
|
||||
];
|
||||
/* 计算申领单总金额:Σ(各明细小计) */
|
||||
function calcOrderTotal(o){return o.lines.reduce(function(s,l){return s+(parseFloat(l.subtotal)||0);},0);}
|
||||
/* 金额格式化:¥1,234.5 */
|
||||
function formatMoney(n){var v=parseFloat(n)||0;return '¥'+v.toLocaleString('zh-CN',{minimumFractionDigits:0,maximumFractionDigits:2});}
|
||||
|
||||
function aggregateStatus(lines){
|
||||
var statuses=lines.map(function(l){return l.status;});
|
||||
@@ -450,7 +451,7 @@ function renderClaimTable(){
|
||||
var tW=c.lines.reduce(function(s,l){return s+parseFloat(l.weight);},0).toFixed(2);
|
||||
html+='<tr class="master-row" data-claim-idx="'+ci+'" onclick="toggleExpand(this,'+ci+')">';
|
||||
html+='<td><span class="expand-arrow" id="carrow'+ci+'">▶</span></td>';
|
||||
html+='<td><b>'+c.claimNo+'</b></td><td>'+c.canteen+'</td><td>'+ncTypeTag(c.ncType)+'</td><td>'+c.lines.length+'</td><td>'+tQty+'</td><td>'+tW+'</td><td>'+statusTag(agg)+'</td>';
|
||||
html+='<td><b>'+c.claimNo+'</b></td><td>'+c.canteen+'</td><td>'+ncTypeTag(c.ncType)+'</td><td>'+c.lines.length+'</td><td>'+tQty+'</td><td>'+tW+'</td><td><b>'+formatMoney(calcOrderTotal(c))+'</b></td><td>'+statusTag(agg)+'</td>';
|
||||
html+='<td>'+c.claimTime+'</td><td>'+c.deliverTime+'</td><td>'+c.deliverPerson+'</td>';
|
||||
html+='<td class="td-actions">';
|
||||
if(agg==='备货中')html+='<span class="link" style="color:var(--success);" onclick="event.stopPropagation();orderAction(\''+c.claimNo+'\',\'ready\')">备货完成</span> ';
|
||||
@@ -466,7 +467,7 @@ function renderClaimTable(){
|
||||
}else{
|
||||
html+='<td colspan="2">菜品/食材</td>';
|
||||
}
|
||||
html+='<td>包装规格</td><td>份数</td><td>数量(kg)</td><td></td><td></td><td></td><td></td><td></td><td></td></tr>';
|
||||
html+='<td>包装规格</td><td>份数</td><td>数量(kg)</td><td>单价(元/kg)</td><td>小计金额</td><td></td><td></td><td></td><td></td><td></td></tr>';
|
||||
c.lines.forEach(function(line){
|
||||
html+='<tr class="detail-row" id="cdetail-'+ci+'" style="display:none;">';
|
||||
html+='<td></td>';
|
||||
@@ -475,8 +476,8 @@ function renderClaimTable(){
|
||||
}else{
|
||||
html+='<td colspan="2" style="font-weight:500;">'+line.foodName+'</td>';
|
||||
}
|
||||
html+='<td>'+line.spec+'</td><td>'+line.qty+'</td><td>'+line.weight+'</td>';
|
||||
html+='<td></td><td></td><td></td><td></td><td></td><td class="td-actions"></td></tr>';
|
||||
html+='<td>'+line.spec+'</td><td>'+line.qty+'</td><td>'+line.weight+'</td><td>'+(line.price||0)+'</td><td>'+formatMoney(line.subtotal||0)+'</td>';
|
||||
html+='<td></td><td></td><td></td><td></td><td class="td-actions"></td></tr>';
|
||||
});
|
||||
});
|
||||
tbody.innerHTML=html;
|
||||
@@ -559,14 +560,13 @@ function resetClaimForm(){
|
||||
document.getElementById('claimDeliverPerson').value='';
|
||||
document.getElementById('claimBatchNo').value='';
|
||||
document.getElementById('claimLinesContainer').innerHTML='';
|
||||
document.getElementById('claimSummary').style.display='none';
|
||||
addClaimLine();
|
||||
}
|
||||
|
||||
function addClaimLine(){
|
||||
claimLineIdCnt++;
|
||||
var orderNcType=document.getElementById('claimNcType').value||'nc';
|
||||
newClaimLines.push({id:'cl'+claimLineIdCnt,ingredient:'',ncType:'',dish:'',portion:'标准份',baseGram:0,unit:orderNcType==='nc'?'盘':'份',qty:0,weight:0});
|
||||
newClaimLines.push({id:'cl'+claimLineIdCnt,ingredient:'',ncType:'',dish:'',portion:'标准份',baseGram:0,unit:orderNcType==='nc'?'盘':'份',qty:0,weight:0,price:0,subtotal:0});
|
||||
renderClaimLineBuilders();
|
||||
}
|
||||
|
||||
@@ -604,7 +604,8 @@ function updateCLPortion(lid,val){
|
||||
function updateCLUnit(lid,val){var l=newClaimLines.find(function(x){return x.id===lid;});if(!l)return;l.unit=val;refreshCLSummary();}
|
||||
function updateCLNcBaseGram(lid,val){var l=newClaimLines.find(function(x){return x.id===lid;});if(!l)return;l.baseGram=parseInt(val||'0',10);l.unit='盘';calcCLWeight(l);refreshCLSummary();}
|
||||
function updateCLQty(lid,val){var l=newClaimLines.find(function(x){return x.id===lid;});if(!l)return;l.qty=parseInt(val.replace(/[^\d]/g,'')||'0',10);calcCLWeight(l);refreshCLSummary();}
|
||||
function calcCLWeight(l){if(l.baseGram>0&&l.qty>0)l.weight=parseFloat((l.baseGram*l.qty/1000).toFixed(2));else l.weight=0;}
|
||||
function updateCLPrice(lid,val){var l=newClaimLines.find(function(x){return x.id===lid;});if(!l)return;l.price=parseFloat(val)||0;calcCLWeight(l);refreshCLSummary();}
|
||||
function calcCLWeight(l){if(l.baseGram>0&&l.qty>0)l.weight=parseFloat((l.baseGram*l.qty/1000).toFixed(2));else l.weight=0;if(l.price>0&&l.weight>0)l.subtotal=parseFloat((l.price*l.weight).toFixed(2));else l.subtotal=0;}
|
||||
|
||||
function renderClaimLineBuilders(){
|
||||
var html='';
|
||||
@@ -612,9 +613,9 @@ function renderClaimLineBuilders(){
|
||||
var isNc=orderNcType==='nc';
|
||||
html+='<table class="inline-line-table"><thead><tr>';
|
||||
if(isNc){
|
||||
html+='<th>食材</th><th>净菜名称</th><th>包装规格(g)</th><th>份数</th><th>数量(kg)</th><th>操作</th>';
|
||||
html+='<th>食材</th><th>净菜名称</th><th>包装规格(g)</th><th>份数</th><th>数量(kg)</th><th>单价(元/kg)</th><th>小计金额</th><th>操作</th>';
|
||||
}else{
|
||||
html+='<th>餐品名称</th><th>包装规格</th><th>份数</th><th>数量(kg)</th><th>操作</th>';
|
||||
html+='<th>餐品名称</th><th>包装规格</th><th>份数</th><th>数量(kg)</th><th>单价(元/kg)</th><th>小计金额</th><th>操作</th>';
|
||||
}
|
||||
html+='</tr></thead><tbody>';
|
||||
var dishNames=getDishNamesWithFallback();
|
||||
@@ -653,6 +654,9 @@ function renderClaimLineBuilders(){
|
||||
/* 份数和数量(nc/cp 共用) */
|
||||
html+='<td><input inputmode="numeric" placeholder="份数" value="'+(line.qty||'')+'" oninput="this.value=this.value.replace(/[^\\d]/g,\'\');updateCLQty(\''+line.id+'\',this.value)"></td>';
|
||||
html+='<td><input value="'+(line.weight||'')+'" readonly></td>';
|
||||
/* 单价与小计金额(nc/cp 共用) */
|
||||
html+='<td><input inputmode="decimal" placeholder="0" value="'+(line.price||'')+'" oninput="this.value=this.value.replace(/[^\\d.]/g,\'\');updateCLPrice(\''+line.id+'\',this.value)"></td>';
|
||||
html+='<td><input value="'+(line.subtotal?formatMoney(line.subtotal):'')+'" readonly></td>';
|
||||
html+='<td class="td-actions"><button class="btn-danger-text" onclick="removeClaimLine(\''+line.id+'\')">移除</button></td>';
|
||||
html+='</tr>';
|
||||
});
|
||||
@@ -662,32 +666,9 @@ function renderClaimLineBuilders(){
|
||||
}
|
||||
|
||||
function refreshCLSummary(){
|
||||
var sd=document.getElementById('claimSummary');var tb=document.getElementById('claimSummaryBody');
|
||||
var th=document.getElementById('claimSummaryHead');
|
||||
var orderNcType=document.getElementById('claimNcType').value;
|
||||
var isNc=orderNcType==='nc';
|
||||
var vl=newClaimLines.filter(function(l){return l.weight>0;});
|
||||
if(vl.length===0){sd.style.display='none';return;}
|
||||
sd.style.display='block';
|
||||
/* 动态表头 */
|
||||
var headerHtml='<tr>';
|
||||
if(isNc){
|
||||
headerHtml+='<th>食材</th><th>净菜名称</th>';
|
||||
}else{
|
||||
headerHtml+='<th colspan="2">菜品/食材</th>';
|
||||
}
|
||||
headerHtml+='<th>包装规格</th><th>份数</th><th>数量(kg)</th></tr>';
|
||||
th.innerHTML=headerHtml;
|
||||
/* 数据行 */
|
||||
var h='';vl.forEach(function(l){
|
||||
if(isNc){
|
||||
h+='<tr><td>'+l.ingredient+'</td><td>'+l.ncType+'</td>';
|
||||
}else{
|
||||
h+='<tr><td colspan="2">'+l.dish+'</td>';
|
||||
}
|
||||
h+='<td>'+formatSpecLabelInt(l)+'</td><td>'+l.qty+'</td><td>'+l.weight+'</td></tr>';
|
||||
});
|
||||
tb.innerHTML=h;
|
||||
var totalAmt=vl.reduce(function(s,l){return s+(l.subtotal||0);},0);
|
||||
var taEl=document.getElementById('claimTotalAmount');if(taEl)taEl.textContent=formatMoney(totalAmt);
|
||||
}
|
||||
|
||||
function submitClaim(){
|
||||
@@ -706,9 +687,9 @@ function submitClaim(){
|
||||
lines:vl.map(function(l,i){
|
||||
var specLbl=formatSpecLabelInt(l);
|
||||
if(orderNcType==='nc'){
|
||||
return {id:'L'+(Date.now()+i), ingredient:l.ingredient, ncName:l.ncType, spec:specLbl, portion:l.portion, baseGram:l.baseGram, unit:l.unit, qty:l.qty, weight:l.weight, status:'备货中'};
|
||||
return {id:'L'+(Date.now()+i), ingredient:l.ingredient, ncName:l.ncType, spec:specLbl, portion:l.portion, baseGram:l.baseGram, unit:l.unit, qty:l.qty, weight:l.weight, price:l.price, subtotal:l.subtotal, status:'备货中'};
|
||||
}else{
|
||||
return {id:'L'+(Date.now()+i), foodName:l.dish, spec:specLbl, portion:l.portion, baseGram:l.baseGram, unit:l.unit, qty:l.qty, weight:l.weight, status:'备货中'};
|
||||
return {id:'L'+(Date.now()+i), foodName:l.dish, spec:specLbl, portion:l.portion, baseGram:l.baseGram, unit:l.unit, qty:l.qty, weight:l.weight, price:l.price, subtotal:l.subtotal, status:'备货中'};
|
||||
}
|
||||
})});
|
||||
closeModal('modal-claim');renderClaimTable();
|
||||
@@ -727,6 +708,7 @@ function showDetail(claimNo){
|
||||
h+='<div class="drawer-field"><div class="drawer-field__label">菜品种类</div><div class="drawer-field__value">'+c.lines.length+'</div></div>';
|
||||
h+='<div class="drawer-field"><div class="drawer-field__label">总份数</div><div class="drawer-field__value">'+tQ+'</div></div>';
|
||||
h+='<div class="drawer-field"><div class="drawer-field__label">总数量(kg)</div><div class="drawer-field__value">'+tW+'</div></div>';
|
||||
h+='<div class="drawer-field"><div class="drawer-field__label">订单总金额</div><div class="drawer-field__value"><b style="color:var(--danger);">'+formatMoney(calcOrderTotal(c))+'</b></div></div>';
|
||||
h+='<div class="drawer-field"><div class="drawer-field__label">申领时间</div><div class="drawer-field__value">'+c.claimTime+'</div></div>';
|
||||
h+='<div class="drawer-field"><div class="drawer-field__label">预定配送时间</div><div class="drawer-field__value">'+c.deliverTime+'</div></div>';
|
||||
h+='<div class="drawer-field"><div class="drawer-field__label">配送人</div><div class="drawer-field__value">'+c.deliverPerson+'</div></div>';
|
||||
@@ -738,7 +720,7 @@ function showDetail(claimNo){
|
||||
}else{
|
||||
h+='<th colspan="2">菜品/食材</th>';
|
||||
}
|
||||
h+='<th>包装规格</th><th>份数</th><th>数量(kg)</th><th>状态</th></tr></thead><tbody>';
|
||||
h+='<th>包装规格</th><th>份数</th><th>数量(kg)</th><th>单价(元/kg)</th><th>小计金额</th><th>状态</th></tr></thead><tbody>';
|
||||
c.lines.forEach(function(l){
|
||||
var tc={'已完成':'tag-green','配送中':'tag-blue','待配送':'tag-orange','备货中':'tag-gray'};
|
||||
if(c.ncType==='nc'){
|
||||
@@ -746,8 +728,8 @@ function showDetail(claimNo){
|
||||
}else{
|
||||
h+='<tr><td colspan="2"><b>'+l.foodName+'</b></td>';
|
||||
}
|
||||
h+='<td>'+l.spec+'</td><td>'+l.qty+'</td><td>'+l.weight+'</td><td><span class="tag '+tc[l.status]+'">'+l.status+'</span></td></tr>';
|
||||
if(c.ncType==='cp'){var ings=dishIngredients[l.foodName]||[];if(ings.length>0){h+='<tr><td colspan="6" style="padding:4px 10px;background:#fafafa;"><span style="font-size:11px;color:var(--text-placeholder);">食材构成:</span>';ings.forEach(function(ing,i){if(i>0)h+=', ';h+=ing.name+'('+ing.amount+')';});h+='</td></tr>';}}
|
||||
h+='<td>'+l.spec+'</td><td>'+l.qty+'</td><td>'+l.weight+'</td><td>'+(l.price||0)+'</td><td>'+formatMoney(l.subtotal||0)+'</td><td><span class="tag '+tc[l.status]+'">'+l.status+'</span></td></tr>';
|
||||
if(c.ncType==='cp'){var ings=dishIngredients[l.foodName]||[];if(ings.length>0){h+='<tr><td colspan="8" style="padding:4px 10px;background:#fafafa;"><span style="font-size:11px;color:var(--text-placeholder);">食材构成:</span>';ings.forEach(function(ing,i){if(i>0)h+=', ';h+=ing.name+'('+ing.amount+')';});h+='</td></tr>';}}
|
||||
});
|
||||
h+='</tbody></table></div>';
|
||||
var dh='<div class="drawer-overlay" onclick="if(event.target===this)closeDrawer()"><div class="drawer"><div class="drawer__header"><div class="drawer__title">净菜内供详情 — '+claimNo+'</div><button class="drawer__close" onclick="closeDrawer()">✕</button></div><div class="drawer__body">'+h+'</div></div></div>';
|
||||
|
||||
Reference in New Issue
Block a user