feat: 小程序就餐记录列表改造与拍照记录页新增,web-admin营养模块字段与终端设备列完善
- mini-program/eat-home.html: 今日就餐记录列表移除食物图标、加序号徽标、副信息改为重量/热量、新增就餐时间;数据来源扩展为员工食堂/补充记录/拍照记录三种;底部"自记餐品"按钮拆为"手动补录"+"拍照记录"双按钮 - mini-program/eat-photo-record.html: 新增拍照记录页,支持餐品名称输入+拍照/上传图片,可添加多个餐品并保存至 sessionStorage 与首页联动 - web-admin/nutrition: din-dish-add/din-dish-all 食材"是否主料"字段改为"食材类型"(主材/辅材/调料);prod-proc-combo/sup-in-cleanin/sup-in-raw/sup-pkg-label 新增"终端设备"列展示设备名与编号;din-recipe-mgmt 新增"同步至生产任务"按钮与"已同步"标签 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.7
parent
fbc9fdbddf
commit
7d7488737b
@@ -1,5 +1,13 @@
|
||||
# 营养管理小程序 CHANGELOG
|
||||
|
||||
## [1.3.0] - 2026-06-22
|
||||
|
||||
### 变更
|
||||
|
||||
**吃模块**
|
||||
- `eat-home.html` — 今日就餐记录列表改造:移除食物图标,食物名称左上角新增序号徽标,食物名称下方副信息由「蛋白质/脂肪/碳水」改为「重量(g)· 热量(kcal)」;数据来源标识由两种扩展为三种(员工食堂 / 补充记录 / 拍照记录),其中拍照记录条目不显示重量与热量;底部「自记餐品」按钮拆分为「手动补录」+「拍照记录」两个按钮,分别跳转 `eat-self-record.html` 与新增页 `eat-photo-record.html`
|
||||
- `eat-photo-record.html` — 新增拍照记录页:支持手动输入餐品名称 + 拍照/上传图片,可添加多个餐品并保存至 `sessionStorage['photoRecord_餐次']`,与 `eat-home.html` 就餐记录联动
|
||||
|
||||
## [1.2.1] - 2026-06-17
|
||||
|
||||
### 变更
|
||||
|
||||
@@ -81,26 +81,37 @@
|
||||
border-bottom: 0.5px solid #f5f5f5; cursor: pointer; text-decoration: none; color: inherit;
|
||||
}
|
||||
.meal-item:last-child { border-bottom: none; }
|
||||
.meal-item .food-icon {
|
||||
width: 44px; height: 44px; border-radius: 12px; background: #f5f5f5;
|
||||
display: flex; align-items: center; justify-content: center; font-size: 22px; flex-shrink: 0;
|
||||
}
|
||||
.meal-item .food-info { flex: 1; min-width: 0; }
|
||||
.meal-item .food-name { font-size: 14px; font-weight: 500; }
|
||||
.meal-item .food-meta { font-size: 12px; color: #999; margin-top: 2px; }
|
||||
/* 右侧:热量 + 来源徽标(员工食堂 / 自记餐品) */
|
||||
.meal-item .food-right { display: flex; flex-direction: column; align-items: flex-end; gap: 2px; flex-shrink: 0; }
|
||||
.meal-item .food-cal { font-size: 13px; font-weight: 600; color: #fa8c16; }
|
||||
.meal-item .food-source { font-size: 10px; color: #999; padding: 1px 6px; border-radius: 3px; background: #f5f5f5; }
|
||||
.meal-item .food-source.self { color: #1677ff; background: #e6f4ff; }
|
||||
/* 自记餐品按钮(位于餐品列表下方) */
|
||||
.self-record-btn-wrap { padding: 4px 16px 16px; background: #fff; }
|
||||
.self-record-btn {
|
||||
width: 100%; padding: 11px 0; border-radius: 12px; border: 1.5px dashed #1677ff;
|
||||
background: #f0f7ff; color: #1677ff; font-size: 14px; font-weight: 600;
|
||||
cursor: pointer; display: flex; align-items: center; justify-content: center; gap: 4px;
|
||||
/* 食物名称行:序号 + 名称 + 重量/热量(右对齐) */
|
||||
.meal-item .food-name-row { display: flex; align-items: center; gap: 6px; }
|
||||
.meal-item .food-index {
|
||||
flex-shrink: 0; min-width: 18px; height: 18px; line-height: 18px; padding: 0 5px;
|
||||
border-radius: 9px; background: #1677ff; color: #fff;
|
||||
font-size: 11px; font-weight: 600; text-align: center;
|
||||
}
|
||||
.self-record-btn:active { background: #d6e8ff; }
|
||||
.meal-item .food-name { font-size: 14px; font-weight: 500; flex-shrink: 0; }
|
||||
.meal-item .food-meta { font-size: 12px; color: #999; text-align: right; }
|
||||
/* 就餐时间 */
|
||||
.meal-item .food-time { font-size: 11px; color: #bbb; margin-top: 4px; }
|
||||
/* 右侧:来源徽标(员工食堂 / 补充记录 / 拍照记录) */
|
||||
.meal-item .food-right { display: flex; flex-direction: column; align-items: flex-end; gap: 2px; flex-shrink: 0; }
|
||||
.meal-item .food-source {
|
||||
font-size: 10px; color: #999; padding: 1px 6px; border-radius: 3px; background: #f5f5f5;
|
||||
}
|
||||
.meal-item .food-source.self { color: #1677ff; background: #e6f4ff; }
|
||||
.meal-item .food-source.photo { color: #fa8c16; background: #fff7e6; }
|
||||
/* 底部双按钮:手动补录 / 拍照记录 */
|
||||
.record-actions-wrap { padding: 4px 16px 16px; background: #fff; }
|
||||
.record-actions { display: flex; gap: 10px; }
|
||||
.record-action-btn {
|
||||
flex: 1; padding: 11px 0; border-radius: 12px;
|
||||
font-size: 14px; font-weight: 600; cursor: pointer;
|
||||
display: flex; align-items: center; justify-content: center; gap: 4px;
|
||||
border: 1.5px dashed #1677ff; background: #f0f7ff; color: #1677ff;
|
||||
}
|
||||
.record-action-btn.photo { border-color: #fa8c16; background: #fff7e6; color: #fa8c16; }
|
||||
.record-action-btn:active { opacity: 0.8; }
|
||||
.record-action-btn .ra-icon { font-size: 16px; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
@@ -134,11 +145,16 @@
|
||||
<div class="meal-tab">晚餐</div>
|
||||
</div>
|
||||
<div class="meal-list"></div>
|
||||
<!-- 自记餐品按钮:跳转至自记餐品二级页面,按当前激活餐次 -->
|
||||
<div class="self-record-btn-wrap">
|
||||
<button class="self-record-btn" onclick="goSelfRecord()">
|
||||
<span style="font-size:16px;">+</span>自记餐品
|
||||
</button>
|
||||
<!-- 双按钮:手动补录 / 拍照记录 -->
|
||||
<div class="record-actions-wrap">
|
||||
<div class="record-actions">
|
||||
<button class="record-action-btn" onclick="goSelfRecord()">
|
||||
<span class="ra-icon">✏️</span>手动补录
|
||||
</button>
|
||||
<button class="record-action-btn photo" onclick="goPhotoRecord()">
|
||||
<span class="ra-icon">📷</span>拍照记录
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -156,26 +172,27 @@
|
||||
</div>
|
||||
<script>
|
||||
/* ========== 餐次菜品数据(来源:员工食堂) ========== */
|
||||
/* meta 改为「重量 + 热量」格式,去除食物图标,新增就餐时间 */
|
||||
var mealData = {
|
||||
'早餐': [
|
||||
{ icon: '🥛', name: '豆浆', meta: '蛋白质 3.6g · 碳水 8.2g', cal: '65kcal', source: '员工食堂' },
|
||||
{ icon: '🥖', name: '油条', meta: '碳水 24g · 脂肪 12.8g', cal: '198kcal', source: '员工食堂' },
|
||||
{ icon: '🥚', name: '水煮蛋', meta: '蛋白质 6.3g · 脂肪 5.3g', cal: '78kcal', source: '员工食堂' },
|
||||
{ icon: '🥣', name: '小米粥', meta: '碳水 16g · 蛋白质 1.8g', cal: '72kcal', source: '员工食堂' }
|
||||
{ name: '豆浆', weight: 250, cal: 65, source: '员工食堂', time: '2026-06-22 07:32:18' },
|
||||
{ name: '油条', weight: 80, cal: 198, source: '员工食堂', time: '2026-06-22 07:32:42' },
|
||||
{ name: '水煮蛋', weight: 50, cal: 78, source: '员工食堂', time: '2026-06-22 07:33:05' },
|
||||
{ name: '小米粥', weight: 200, cal: 72, source: '员工食堂', time: '2026-06-22 07:33:28' }
|
||||
],
|
||||
'午餐': [
|
||||
{ icon: '🍗', name: '宫保鸡丁', meta: '蛋白质 22.4g · 脂肪 14.2g', cal: '285kcal', source: '员工食堂' },
|
||||
{ icon: '🐟', name: '清蒸鱼', meta: '蛋白质 20.8g · 脂肪 4.6g', cal: '142kcal', source: '员工食堂' },
|
||||
{ icon: '🥦', name: '炒西兰花', meta: '蛋白质 3.2g · 脂肪 3.8g', cal: '68kcal', source: '员工食堂' },
|
||||
{ icon: '🍚', name: '米饭(中碗)', meta: '碳水 58g · 蛋白质 4.2g', cal: '232kcal', source: '员工食堂' },
|
||||
{ icon: '🥬', name: '蒜蓉油麦菜', meta: '蛋白质 1.8g · 脂肪 3.2g', cal: '52kcal', source: '员工食堂' },
|
||||
{ icon: '🍲', name: '番茄蛋花汤', meta: '蛋白质 4.6g · 脂肪 2.1g', cal: '48kcal', source: '员工食堂' }
|
||||
{ name: '宫保鸡丁', weight: 200, cal: 285, source: '员工食堂', time: '2026-06-22 12:08:15' },
|
||||
{ name: '清蒸鱼', weight: 180, cal: 142, source: '员工食堂', time: '2026-06-22 12:08:38' },
|
||||
{ name: '炒西兰花', weight: 150, cal: 68, source: '员工食堂', time: '2026-06-22 12:09:02' },
|
||||
{ name: '米饭(中碗)', weight: 200, cal: 232, source: '员工食堂', time: '2026-06-22 12:09:25' },
|
||||
{ name: '蒜蓉油麦菜', weight: 150, cal: 52, source: '员工食堂', time: '2026-06-22 12:09:48' },
|
||||
{ name: '番茄蛋花汤', weight: 200, cal: 48, source: '员工食堂', time: '2026-06-22 12:10:12' }
|
||||
],
|
||||
'晚餐': [
|
||||
{ icon: '🍳', name: '番茄炒蛋', meta: '蛋白质 10.2g · 脂肪 8.6g', cal: '156kcal', source: '员工食堂' },
|
||||
{ icon: '🫑', name: '青椒肉丝', meta: '蛋白质 14.8g · 脂肪 9.2g', cal: '178kcal', source: '员工食堂' },
|
||||
{ icon: '🥬', name: '紫菜蛋花汤', meta: '蛋白质 3.4g · 脂肪 1.2g', cal: '32kcal', source: '员工食堂' },
|
||||
{ icon: '🍞', name: '馒头', meta: '碳水 44g · 蛋白质 7.0g', cal: '221kcal', source: '员工食堂' }
|
||||
{ name: '番茄炒蛋', weight: 200, cal: 156, source: '员工食堂', time: '2026-06-22 18:15:33' },
|
||||
{ name: '青椒肉丝', weight: 180, cal: 178, source: '员工食堂', time: '2026-06-22 18:15:58' },
|
||||
{ name: '紫菜蛋花汤', weight: 200, cal: 32, source: '员工食堂', time: '2026-06-22 18:16:22' },
|
||||
{ name: '馒头', weight: 100, cal: 221, source: '员工食堂', time: '2026-06-22 18:16:45' }
|
||||
]
|
||||
};
|
||||
|
||||
@@ -232,7 +249,15 @@
|
||||
} catch (e) { return {}; }
|
||||
}
|
||||
|
||||
/* 把某餐次的自记记录转为主列表渲染格式 */
|
||||
/* 读取 sessionStorage 中某餐次的拍照记录 */
|
||||
function loadPhotoRecord(mealType) {
|
||||
try {
|
||||
var raw = sessionStorage.getItem('photoRecord_' + mealType);
|
||||
return raw ? JSON.parse(raw) : [];
|
||||
} catch (e) { return []; }
|
||||
}
|
||||
|
||||
/* 把某餐次的自记记录转为主列表渲染格式(补充记录来源) */
|
||||
function computeSelfItems(mealType) {
|
||||
var state = loadSelfRecord(mealType);
|
||||
var items = [];
|
||||
@@ -241,39 +266,66 @@
|
||||
if (!rec || !rec.qty || rec.qty <= 0) return;
|
||||
var d = findSelfDish(id);
|
||||
if (!d) return;
|
||||
var cal, qtyText;
|
||||
var cal, gram;
|
||||
if (rec.mode === '份') {
|
||||
gram = d.gram * rec.qty;
|
||||
cal = Math.round(d.cal * rec.qty);
|
||||
qtyText = rec.qty + ' 份';
|
||||
} else {
|
||||
gram = rec.qty;
|
||||
cal = Math.round(d.cal * rec.qty / d.gram);
|
||||
qtyText = rec.qty + ' g';
|
||||
}
|
||||
items.push({
|
||||
icon: d.icon, name: d.name,
|
||||
meta: qtyText + ' · ' + d.desc,
|
||||
cal: cal + 'kcal',
|
||||
source: '自记餐品', isSelf: true
|
||||
name: d.name,
|
||||
weight: gram, cal: cal,
|
||||
source: '补充记录', sourceClass: 'self',
|
||||
time: rec.time || formatNow()
|
||||
});
|
||||
});
|
||||
return items;
|
||||
}
|
||||
|
||||
/* 把某餐次的拍照记录转为主列表渲染格式(拍照记录来源,无重量/热量) */
|
||||
function computePhotoItems(mealType) {
|
||||
return loadPhotoRecord(mealType).map(function(p) {
|
||||
return {
|
||||
name: p.name,
|
||||
source: '拍照记录', sourceClass: 'photo',
|
||||
skipMeta: true,
|
||||
time: p.time || formatNow()
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
/* 格式化当前时间为「YYYY-MM-DD HH:mm:ss」 */
|
||||
function formatNow() {
|
||||
function pad(n) { return n < 10 ? '0' + n : '' + n; }
|
||||
var d = new Date();
|
||||
return d.getFullYear() + '-' + pad(d.getMonth() + 1) + '-' + pad(d.getDate())
|
||||
+ ' ' + pad(d.getHours()) + ':' + pad(d.getMinutes()) + ':' + pad(d.getSeconds());
|
||||
}
|
||||
|
||||
/* ========== 主列表渲染 ========== */
|
||||
var mealTabs = document.querySelectorAll('.meal-tab');
|
||||
var mealList = document.querySelector('.meal-list');
|
||||
|
||||
function renderMeal(mealType) {
|
||||
currentMeal = mealType;
|
||||
var items = (mealData[mealType] || []).slice().concat(computeSelfItems(mealType));
|
||||
mealList.innerHTML = items.map(function(d) {
|
||||
var items = (mealData[mealType] || []).slice()
|
||||
.concat(computeSelfItems(mealType))
|
||||
.concat(computePhotoItems(mealType));
|
||||
mealList.innerHTML = items.map(function(d, idx) {
|
||||
/* 重量/热量放在餐品名后面(右对齐),拍照记录无此元素 */
|
||||
var metaHtml = d.skipMeta ? '' :
|
||||
'<span class="food-meta">重量 ' + d.weight + 'g · 热量 ' + d.cal + 'kcal</span>';
|
||||
return '<a class="meal-item" href="eat-dish-detail.html">'
|
||||
+ '<div class="food-icon">' + d.icon + '</div>'
|
||||
+ '<div class="food-info"><div class="food-name">' + d.name + '</div>'
|
||||
+ '<div class="food-meta">' + d.meta + '</div></div>'
|
||||
+ '<div class="food-info">'
|
||||
+ '<div class="food-name-row"><span class="food-index">' + (idx + 1) + '</span>'
|
||||
+ '<span class="food-name">' + d.name + '</span></div>'
|
||||
+ '<div class="food-time">' + (d.time || '') + '</div>'
|
||||
+ '</div>'
|
||||
+ '<div class="food-right">'
|
||||
+ '<span class="food-cal">' + d.cal + '</span>'
|
||||
+ '<span class="food-source' + (d.isSelf ? ' self' : '') + '">' + d.source + '</span>'
|
||||
+ metaHtml
|
||||
+ '<span class="food-source ' + (d.sourceClass || '') + '">' + d.source + '</span>'
|
||||
+ '</div></a>';
|
||||
}).join('');
|
||||
}
|
||||
@@ -286,11 +338,16 @@
|
||||
});
|
||||
});
|
||||
|
||||
/* 跳转到自记餐品二级页面,传当前餐次 */
|
||||
/* 跳转到手动补录页(原自记餐品),传当前餐次 */
|
||||
function goSelfRecord() {
|
||||
location.href = 'eat-self-record.html?meal=' + encodeURIComponent(currentMeal);
|
||||
}
|
||||
|
||||
/* 跳转到拍照记录页,传当前餐次 */
|
||||
function goPhotoRecord() {
|
||||
location.href = 'eat-photo-record.html?meal=' + encodeURIComponent(currentMeal);
|
||||
}
|
||||
|
||||
/* 初始渲染:午餐 */
|
||||
renderMeal('午餐');
|
||||
</script>
|
||||
|
||||
@@ -0,0 +1,324 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>拍照记录 | 智能餐养小程序</title>
|
||||
<style>
|
||||
/* 全局重置 */
|
||||
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||||
body {
|
||||
background: #2a2a2a; display: flex; justify-content: center; align-items: flex-start;
|
||||
min-height: 100vh; font-family: -apple-system, BlinkMacSystemFont, 'PingFang SC', 'Helvetica Neue', sans-serif;
|
||||
padding: 24px 0 40px;
|
||||
}
|
||||
/* 手机壳 */
|
||||
.phone-shell {
|
||||
width: 390px; height: 844px; background: #fff; border-radius: 44px;
|
||||
box-shadow: 0 20px 60px rgba(0,0,0,0.3), inset 0 0 0 2px #e0e0e0;
|
||||
overflow: hidden; position: relative; display: flex; flex-direction: column;
|
||||
}
|
||||
/* 状态栏 */
|
||||
.status-bar {
|
||||
height: 44px; background: #fff; display: flex; align-items: center;
|
||||
justify-content: space-between; padding: 0 24px; font-size: 12px; font-weight: 600; flex-shrink: 0;
|
||||
}
|
||||
.status-bar .time { font-size: 15px; font-weight: 700; }
|
||||
.status-bar .icons { display: flex; gap: 6px; align-items: center; }
|
||||
/* 导航栏 */
|
||||
.nav-bar {
|
||||
height: 44px; background: #fff; display: flex; align-items: center;
|
||||
padding: 0 16px; border-bottom: 0.5px solid #f0f0f0; flex-shrink: 0; position: relative;
|
||||
}
|
||||
.nav-bar .back { font-size: 22px; color: #1677ff; cursor: pointer; text-decoration: none; line-height: 1; }
|
||||
.nav-bar .title { position: absolute; left: 50%; transform: translateX(-50%); font-size: 17px; font-weight: 600; }
|
||||
.home-indicator {
|
||||
height: 20px; display: flex; align-items: center; justify-content: center; background: #fff; flex-shrink: 0;
|
||||
}
|
||||
.home-indicator::after { content: ''; width: 120px; height: 5px; background: #1a1a1a; border-radius: 3px; opacity: 0.2; }
|
||||
|
||||
/* === 业务样式 === */
|
||||
.page-body {
|
||||
flex: 1; overflow-y: auto; background: #f5f5f5;
|
||||
display: flex; flex-direction: column;
|
||||
}
|
||||
.page-body::-webkit-scrollbar { display: none; }
|
||||
|
||||
/* 当前餐次提示 */
|
||||
.meal-tip {
|
||||
padding: 10px 16px; background: #fff7e6; color: #fa8c16;
|
||||
font-size: 12px; border-bottom: 0.5px solid #ffe7ba;
|
||||
}
|
||||
|
||||
/* 添加区卡片 */
|
||||
.add-card {
|
||||
margin: 12px; background: #fff; border-radius: 12px; padding: 14px;
|
||||
box-shadow: 0 1px 3px rgba(0,0,0,0.04);
|
||||
}
|
||||
.add-card .label {
|
||||
font-size: 13px; color: #666; margin-bottom: 8px;
|
||||
}
|
||||
.name-input {
|
||||
width: 100%; height: 38px; border: 1px solid #e0e0e0; border-radius: 8px;
|
||||
padding: 0 12px; font-size: 14px; color: #333; outline: none;
|
||||
background: #fafafa;
|
||||
}
|
||||
.name-input:focus { border-color: #fa8c16; background: #fff; }
|
||||
.photo-row {
|
||||
display: flex; gap: 10px; margin-top: 12px; align-items: center;
|
||||
}
|
||||
/* 拍照按钮 */
|
||||
.photo-btn {
|
||||
flex: 1; height: 80px; border: 1.5px dashed #fa8c16; border-radius: 10px;
|
||||
background: #fff7e6; color: #fa8c16; font-size: 14px; font-weight: 600;
|
||||
cursor: pointer; display: flex; flex-direction: column; align-items: center;
|
||||
justify-content: center; gap: 4px;
|
||||
}
|
||||
.photo-btn .pb-icon { font-size: 26px; line-height: 1; }
|
||||
.photo-btn:active { opacity: 0.8; }
|
||||
.photo-btn input[type=file] { display: none; }
|
||||
/* 添加到列表按钮 */
|
||||
.add-list-btn {
|
||||
width: 80px; height: 80px; border-radius: 10px;
|
||||
background: #fa8c16; color: #fff; font-size: 13px; font-weight: 600;
|
||||
cursor: pointer; border: none;
|
||||
display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 2px;
|
||||
}
|
||||
.add-list-btn:active { opacity: 0.85; }
|
||||
.add-list-btn .al-icon { font-size: 22px; line-height: 1; }
|
||||
|
||||
/* 已添加餐品列表 */
|
||||
.list-card {
|
||||
flex: 1; margin: 0 12px 12px; background: #fff; border-radius: 12px;
|
||||
padding: 4px 14px; box-shadow: 0 1px 3px rgba(0,0,0,0.04);
|
||||
overflow-y: auto;
|
||||
}
|
||||
.list-card::-webkit-scrollbar { display: none; }
|
||||
.list-card .lc-title {
|
||||
font-size: 13px; color: #666; padding: 10px 0 6px;
|
||||
border-bottom: 0.5px solid #f0f0f0;
|
||||
}
|
||||
.list-empty {
|
||||
padding: 30px 0; text-align: center; color: #bbb; font-size: 13px;
|
||||
}
|
||||
|
||||
/* 餐品条目 */
|
||||
.dish-row {
|
||||
display: flex; align-items: center; gap: 10px; padding: 10px 0;
|
||||
border-bottom: 0.5px solid #f5f5f5;
|
||||
}
|
||||
.dish-row:last-child { border-bottom: none; }
|
||||
.dish-row .dish-thumb {
|
||||
width: 56px; height: 56px; border-radius: 8px; background: #f5f5f5;
|
||||
background-size: cover; background-position: center; flex-shrink: 0;
|
||||
display: flex; align-items: center; justify-content: center; font-size: 24px;
|
||||
}
|
||||
.dish-row .dish-info { flex: 1; min-width: 0; }
|
||||
.dish-row .dish-name {
|
||||
font-size: 14px; color: #333; font-weight: 500;
|
||||
overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
|
||||
}
|
||||
.dish-row .dish-sub {
|
||||
font-size: 11px; color: #fa8c16; margin-top: 3px;
|
||||
}
|
||||
.dish-row .del-btn {
|
||||
width: 28px; height: 28px; border-radius: 50%; border: none;
|
||||
background: #fff1f0; color: #ff4d4f; font-size: 16px; cursor: pointer;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.dish-row .del-btn:active { opacity: 0.8; }
|
||||
|
||||
/* 底部保存栏 */
|
||||
.save-bar {
|
||||
padding: 10px 16px 14px; background: #fff; border-top: 0.5px solid #f0f0f0;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.save-btn {
|
||||
width: 100%; height: 44px; border-radius: 22px; border: none;
|
||||
background: #fa8c16; color: #fff; font-size: 15px; font-weight: 600;
|
||||
cursor: pointer;
|
||||
}
|
||||
.save-btn:active { opacity: 0.85; }
|
||||
.save-btn:disabled { background: #ffd6a8; cursor: not-allowed; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="phone-shell">
|
||||
<!-- 状态栏 -->
|
||||
<div class="status-bar">
|
||||
<span class="time">09:41</span>
|
||||
<div class="icons">
|
||||
<span>📶</span><span>WiFi</span><span>🔋</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 导航栏 -->
|
||||
<div class="nav-bar">
|
||||
<a class="back" href="eat-home.html">‹</a>
|
||||
<span class="title">拍照记录</span>
|
||||
</div>
|
||||
|
||||
<!-- 主体 -->
|
||||
<div class="page-body">
|
||||
<!-- 当前餐次提示 -->
|
||||
<div class="meal-tip">当前餐次:<strong id="mealName">午餐</strong></div>
|
||||
|
||||
<!-- 添加区 -->
|
||||
<div class="add-card">
|
||||
<div class="label">餐品名称</div>
|
||||
<input class="name-input" id="dishName" type="text" placeholder="请输入餐品名称" maxlength="20" />
|
||||
|
||||
<div class="photo-row">
|
||||
<!-- 拍照/上传 -->
|
||||
<label class="photo-btn">
|
||||
<span class="pb-icon">📷</span>
|
||||
<span id="photoBtnText">拍照 / 上传图片</span>
|
||||
<input id="photoInput" type="file" accept="image/*" capture="environment" />
|
||||
</label>
|
||||
|
||||
<!-- 添加到列表 -->
|
||||
<button class="add-list-btn" onclick="addDish()">
|
||||
<span class="al-icon">+</span>
|
||||
<span>添加</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 已添加餐品列表 -->
|
||||
<div class="list-card">
|
||||
<div class="lc-title">已添加餐品(<span id="dishCount">0</span>)</div>
|
||||
<div id="dishList"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 底部保存按钮 -->
|
||||
<div class="save-bar">
|
||||
<button class="save-btn" id="saveBtn" onclick="saveAll()">保存</button>
|
||||
</div>
|
||||
|
||||
<!-- Home Indicator -->
|
||||
<div class="home-indicator"></div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
/* ========== 解析当前餐次 ========== */
|
||||
function getQueryMeal() {
|
||||
var m = decodeURIComponent((location.search.match(/meal=([^&]+)/) || [,''])[1]);
|
||||
return ['早餐','午餐','晚餐'].indexOf(m) >= 0 ? m : '午餐';
|
||||
}
|
||||
var currentMeal = getQueryMeal();
|
||||
document.getElementById('mealName').textContent = currentMeal;
|
||||
|
||||
/* ========== 已添加餐品列表(内存态,未保存前不持久化) ========== */
|
||||
/* 每条:{ name, image(DataURL 缩略图) } */
|
||||
var dishList = [];
|
||||
|
||||
/* 当前选中的图片(DataURL) */
|
||||
var pendingImage = null;
|
||||
|
||||
/* 格式化当前时间为「YYYY-MM-DD HH:mm:ss」 */
|
||||
function formatNow() {
|
||||
function pad(n) { return n < 10 ? '0' + n : '' + n; }
|
||||
var d = new Date();
|
||||
return d.getFullYear() + '-' + pad(d.getMonth() + 1) + '-' + pad(d.getDate())
|
||||
+ ' ' + pad(d.getHours()) + ':' + pad(d.getMinutes()) + ':' + pad(d.getSeconds());
|
||||
}
|
||||
|
||||
/* 拍照/上传图片处理 */
|
||||
document.getElementById('photoInput').addEventListener('change', function(e) {
|
||||
var file = e.target.files && e.target.files[0];
|
||||
if (!file) return;
|
||||
/* 压缩为缩略图,避免 sessionStorage 撑爆 */
|
||||
var reader = new FileReader();
|
||||
reader.onload = function(ev) {
|
||||
var img = new Image();
|
||||
img.onload = function() {
|
||||
var canvas = document.createElement('canvas');
|
||||
var maxW = 200;
|
||||
var w = img.width, h = img.height;
|
||||
if (w > maxW) { h = h * maxW / w; w = maxW; }
|
||||
canvas.width = w; canvas.height = h;
|
||||
canvas.getContext('2d').drawImage(img, 0, 0, w, h);
|
||||
pendingImage = canvas.toDataURL('image/jpeg', 0.7);
|
||||
document.getElementById('photoBtnText').textContent = '已选图片 ✓';
|
||||
};
|
||||
img.src = ev.target.result;
|
||||
};
|
||||
reader.readAsDataURL(file);
|
||||
});
|
||||
|
||||
/* 添加餐品到列表 */
|
||||
function addDish() {
|
||||
var nameEl = document.getElementById('dishName');
|
||||
var name = nameEl.value.trim();
|
||||
if (!name) {
|
||||
alert('请输入餐品名称');
|
||||
nameEl.focus();
|
||||
return;
|
||||
}
|
||||
if (!pendingImage) {
|
||||
alert('请先拍照或上传一张图片');
|
||||
return;
|
||||
}
|
||||
dishList.push({ name: name, image: pendingImage, time: formatNow() });
|
||||
/* 重置输入 */
|
||||
nameEl.value = '';
|
||||
pendingImage = null;
|
||||
document.getElementById('photoInput').value = '';
|
||||
document.getElementById('photoBtnText').textContent = '拍照 / 上传图片';
|
||||
renderList();
|
||||
}
|
||||
|
||||
/* 删除餐品 */
|
||||
function removeDish(idx) {
|
||||
dishList.splice(idx, 1);
|
||||
renderList();
|
||||
}
|
||||
|
||||
/* 渲染列表 */
|
||||
function renderList() {
|
||||
var listEl = document.getElementById('dishList');
|
||||
document.getElementById('dishCount').textContent = dishList.length;
|
||||
var saveBtn = document.getElementById('saveBtn');
|
||||
saveBtn.disabled = dishList.length === 0;
|
||||
|
||||
if (dishList.length === 0) {
|
||||
listEl.innerHTML = '<div class="list-empty">暂无餐品,请输入名称并拍照后添加</div>';
|
||||
return;
|
||||
}
|
||||
listEl.innerHTML = dishList.map(function(d, idx) {
|
||||
return '<div class="dish-row">'
|
||||
+ '<div class="dish-thumb" style="background-image:url(' + d.image + ')"></div>'
|
||||
+ '<div class="dish-info">'
|
||||
+ '<div class="dish-name">' + escapeHtml(d.name) + '</div>'
|
||||
+ '<div class="dish-sub">拍照记录</div>'
|
||||
+ '</div>'
|
||||
+ '<button class="del-btn" onclick="removeDish(' + idx + ')">×</button>'
|
||||
+ '</div>';
|
||||
}).join('');
|
||||
}
|
||||
|
||||
/* 简单转义,避免 name 中含 HTML 特殊字符 */
|
||||
function escapeHtml(s) {
|
||||
return s.replace(/[&<>"']/g, function(c) {
|
||||
return ({'&':'&','<':'<','>':'>','"':'"',"'":'''})[c];
|
||||
});
|
||||
}
|
||||
|
||||
/* 保存到 sessionStorage 并返回首页 */
|
||||
function saveAll() {
|
||||
if (dishList.length === 0) return;
|
||||
try {
|
||||
sessionStorage.setItem('photoRecord_' + currentMeal, JSON.stringify(dishList));
|
||||
} catch (e) {
|
||||
alert('保存失败:图片数据过大');
|
||||
return;
|
||||
}
|
||||
location.href = 'eat-home.html';
|
||||
}
|
||||
|
||||
/* 初始化 */
|
||||
renderList();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user