refactor: 删除膳食偏好设置页(diet-questionnaire.html)及关联截图,PRD/设计总览同步移除引用并调整章节序号,今日饮食建议改为直接跳转

This commit is contained in:
liuyunqin
2026-08-28 08:46:11 +08:00
parent 1d31d1c53c
commit 1689707ab2
7 changed files with 38 additions and 665 deletions
@@ -1,591 +0,0 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>膳食偏好设置 - 员工端 | 健康CQ原型</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body { background: #f0f2f5; display: flex; justify-content: center; align-items: flex-start; min-height: 100vh; padding: 20px; font-family: -apple-system, BlinkMacSystemFont, 'PingFang SC', 'Helvetica Neue', sans-serif; }
.phone-shell { width: 390px; height: 844px; background: #f5f7fa; border-radius: 44px; box-shadow: 0 20px 60px rgba(0,0,0,0.25), inset 0 0 0 2px #e0e0e0; overflow: hidden; position: relative; display: flex; flex-direction: column; }
.status-bar { height: 44px; display: flex; align-items: center; justify-content: space-between; padding: 0 24px; flex-shrink: 0; background: #fff; }
.status-bar .time { font-size: 15px; font-weight: 700; color: #333; }
.status-bar .icons { display: flex; gap: 6px; align-items: center; }
.nav-bar { height: 44px; background: #fff; display: flex; align-items: center; padding: 0 16px; flex-shrink: 0; border-bottom: 1px solid #f0f0f0; }
.nav-back { width: 28px; height: 28px; display: flex; align-items: center; justify-content: center; cursor: pointer; color: #1a1a1a; }
.nav-title { flex: 1; text-align: center; font-size: 17px; font-weight: 600; color: #1a1a1a; }
.nav-placeholder { width: 56px; flex-shrink: 0; }
/* ===== 问卷主体(替代原 guide-overlay 的 absolute 定位) ===== */
.questionnaire { flex: 1; overflow-y: auto; background: #f5f7fa; display: flex; flex-direction: column; }
.questionnaire::-webkit-scrollbar { display: none; }
.questionnaire__hero { background: linear-gradient(135deg, #52c41a 0%, #389e0d 100%); padding: 32px 20px 24px; color: #fff; text-align: center; flex-shrink: 0; }
.questionnaire__hero-icon { font-size: 40px; margin-bottom: 8px; }
.questionnaire__hero-title { font-size: 20px; font-weight: 800; margin-bottom: 4px; }
.questionnaire__hero-sub { font-size: 13px; opacity: 0.85; }
.questionnaire__body { flex: 1; padding: 16px 16px 0; display: flex; flex-direction: column; gap: 14px; }
.questionnaire__q { background: #fff; border-radius: 14px; padding: 14px; box-shadow: 0 2px 8px rgba(0,0,0,0.03); }
.questionnaire__q-header { display: flex; align-items: center; gap: 8px; margin-bottom: 10px; }
.questionnaire__q-num { width: 22px; height: 22px; border-radius: 50%; background: #52c41a; color: #fff; font-size: 12px; font-weight: 800; display: flex; align-items: center; justify-content: center; flex-shrink: 0; }
.questionnaire__q-title { font-size: 14px; font-weight: 700; color: #1a1a1a; }
.questionnaire__q-required { font-size: 10px; color: #ff4d4f; margin-left: auto; }
/* 地区触发器 */
.questionnaire__trigger { display: flex; align-items: center; justify-content: space-between; height: 42px; padding: 0 14px; background: #f7f8fa; border-radius: 10px; font-size: 13px; color: #bbb; cursor: pointer; }
.questionnaire__trigger--filled { color: #333; font-weight: 600; }
.questionnaire__trigger-arrow { color: #bbb; font-size: 12px; }
/* Chip 标签选择 */
.questionnaire__chips { display: flex; gap: 8px; flex-wrap: wrap; }
.questionnaire__chip { font-size: 13px; padding: 8px 16px; border-radius: 20px; font-weight: 600; cursor: pointer; border: 1.5px solid #e0e0e0; color: #666; background: #fff; transition: all .2s; }
.questionnaire__chip:hover { border-color: #b7eb8f; background: #f6ffed; }
.questionnaire__chip--active { border-color: #52c41a; background: #f6ffed; color: #52c41a; }
.questionnaire__chip--active::before { content: '✓ '; font-size: 11px; }
/* 提交按钮 */
.questionnaire__footer { padding: 16px 16px 24px; flex-shrink: 0; }
.questionnaire__submit { width: 100%; height: 48px; border-radius: 24px; border: none; font-size: 16px; font-weight: 700; color: #fff; cursor: pointer; background: #d9f7be; transition: all .25s; }
.questionnaire__submit--ready { background: linear-gradient(135deg, #52c41a 0%, #389e0d 100%); box-shadow: 0 6px 20px rgba(82,196,26,0.3); }
.questionnaire__submit--ready:active { transform: scale(0.97); }
/* ===== 地区选择底部 Sheet(省-市级联) ===== */
.region-mask { position: absolute; inset: 0; background: rgba(0,0,0,0.45); z-index: 200; display: none; }
.region-mask.show { display: block; }
.region-sheet { position: absolute; left: 0; right: 0; bottom: 0; background: #fff; border-radius: 18px 18px 0 0; z-index: 201; display: none; padding-bottom: 16px; }
.region-sheet.show { display: block; animation: qSlideUp .25s ease; }
.region-sheet__head { display: flex; align-items: center; justify-content: space-between; padding: 14px 18px; border-bottom: 1px solid #f0f0f0; }
.region-sheet__cancel { font-size: 15px; color: #999; cursor: pointer; }
.region-sheet__title { font-size: 16px; font-weight: 700; color: #1a1a1a; }
.region-sheet__submit { font-size: 15px; color: #52c41a; font-weight: 600; cursor: pointer; }
.region-sheet__list { padding: 6px 0; max-height: 360px; overflow-y: auto; }
.region-sheet__list::-webkit-scrollbar { display: none; }
.region-sheet__item { display: flex; align-items: center; justify-content: space-between; padding: 14px 18px; font-size: 15px; color: #333; cursor: pointer; }
.region-sheet__item.active { color: #52c41a; font-weight: 600; background: #f6ffed; }
.region-sheet__check { width: 18px; height: 18px; border-radius: 50%; border: 1px solid #d0d0d0; display: flex; align-items: center; justify-content: center; flex-shrink: 0; }
.region-sheet__item.active .region-sheet__check { background: #52c41a; border-color: #52c41a; }
.region-sheet__check svg { width: 12px; height: 12px; stroke: #fff; stroke-width: 3; fill: none; display: none; }
.region-sheet__item.active .region-sheet__check svg { display: block; }
/* 省-市级联视图 */
.region-sheet__view { display: none; }
.region-sheet__view.active { display: block; }
.region-sheet__back { display: flex; align-items: center; gap: 6px; padding: 10px 18px; font-size: 13px; cursor: pointer; border-bottom: 1px solid #f0f0f0; }
.region-sheet__back-arrow { font-size: 18px; line-height: 1; color: #52c41a; }
.region-sheet__back-label { color: #999; }
.region-sheet__back-province { color: #1a1a1a; font-weight: 700; margin-left: auto; }
.region-sheet__item--parent .region-sheet__sub { font-size: 13px; color: #bbb; font-weight: 600; display: flex; align-items: center; }
.region-sheet__item--parent.active .region-sheet__sub { color: #52c41a; }
/* ===== 自定义规避食材底部 Sheet ===== */
.custom-avoid-mask { position: absolute; inset: 0; background: rgba(0,0,0,0.45); z-index: 300; display: none; }
.custom-avoid-mask.show { display: block; }
.custom-avoid-sheet { position: absolute; left: 0; right: 0; bottom: 0; background: #fff; border-radius: 18px 18px 0 0; z-index: 301; display: none; padding-bottom: 16px; }
.custom-avoid-sheet.show { display: block; animation: qSlideUp .25s ease; }
.custom-avoid-sheet__head { display: flex; align-items: center; justify-content: space-between; padding: 14px 18px; border-bottom: 1px solid #f0f0f0; }
.custom-avoid-sheet__cancel { font-size: 15px; color: #999; cursor: pointer; }
.custom-avoid-sheet__title { font-size: 16px; font-weight: 700; color: #1a1a1a; }
.custom-avoid-sheet__submit { font-size: 15px; color: #52c41a; font-weight: 600; cursor: pointer; }
.custom-avoid-sheet__body { padding: 16px 18px; }
.custom-avoid-sheet__input { width: 100%; height: 44px; border: 1.5px solid #e0e0e0; border-radius: 10px; padding: 0 14px; font-size: 15px; outline: none; transition: border-color .2s; font-family: inherit; }
.custom-avoid-sheet__input:focus { border-color: #52c41a; }
.custom-avoid-sheet__hint { font-size: 11px; color: #bbb; margin-top: 8px; }
.custom-avoid-sheet__quick-label { font-size: 12px; color: #999; font-weight: 600; margin: 16px 0 8px; }
.custom-avoid-sheet__quick { display: flex; flex-wrap: wrap; gap: 8px; }
.custom-avoid-sheet__quick-tag { font-size: 12px; padding: 5px 12px; border-radius: 16px; border: 1px solid #e0e0e0; color: #666; background: #fafafa; cursor: pointer; transition: all .2s; }
.custom-avoid-sheet__quick-tag:hover { border-color: #b7eb8f; background: #f6ffed; }
.custom-avoid-sheet__quick-tag--added { border-color: #52c41a; background: #f6ffed; color: #52c41a; }
.custom-avoid-sheet__quick-tag--added::after { content: ' ✓'; }
/* ===== 自定义食材标签 ===== */
.questionnaire__custom-avoid { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 8px; }
.questionnaire__custom-tag { font-size: 13px; padding: 8px 14px; border-radius: 20px; font-weight: 600; cursor: pointer; border: 1.5px solid #52c41a; color: #52c41a; background: #f6ffed; transition: all .2s; display: flex; align-items: center; gap: 6px; }
.questionnaire__custom-tag:hover { background: #e6f7df; }
.questionnaire__custom-tag::after { content: '✕'; font-size: 10px; opacity: 0.7; }
.questionnaire__chip--add { border-style: dashed !important; color: #bbb !important; border-color: #d0d0d0 !important; background: #fafafa !important; }
.questionnaire__chip--add:hover { border-color: #52c41a !important; color: #52c41a !important; background: #f6ffed !important; }
.questionnaire__chip--add::before { content: '+ ' !important; }
/* 底部 Sheet 滑入动画 */
@keyframes qSlideUp { from { transform: translateY(100%); } to { transform: translateY(0); } }
</style>
</head>
<body>
<div class="phone-shell">
<div class="status-bar">
<span class="time">09:40</span>
<div class="icons">
<svg width="16" height="16" fill="none"><rect x="1" y="4" width="3" height="8" rx="1" fill="#333"/><rect x="5" y="3" width="3" height="9" rx="1" fill="#333"/><rect x="9" y="1" width="3" height="11" rx="1" fill="#333"/><rect x="13" y="0" width="3" height="12" rx="1" fill="#333" opacity=".3"/></svg>
<svg width="16" height="16" fill="none"><path d="M8 3C5.5 3 3.2 4 1.5 5.5l1.4 1.4C4.3 5.5 6.1 5 8 5s3.7.5 5.1 1.9l1.4-1.4C12.8 4 10.5 3 8 3zm0 4c-1.4 0-2.6.5-3.5 1.3L6 9.8c.6-.5 1.3-.8 2-.8s1.4.3 2 .8l1.5-1.5C10.6 7.5 9.4 7 8 7zm0 4c-.6 0-1 .4-1 1s.4 1 1 1 1-.4 1-1-.4-1-1-1z" fill="#333"/></svg>
<svg width="22" height="12" fill="none"><rect x=".5" y=".5" width="19" height="11" rx="2" stroke="#333"/><rect x="20" y="3.5" width="1.5" height="5" rx=".75" fill="#333"/><rect x="2" y="2" width="14" height="8" rx="1" fill="#333"/></svg>
</div>
</div>
<div class="nav-bar">
<div class="nav-back" id="navBack" onclick="goBack()">
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><polyline points="15 18 9 12 15 6"/></polyline></svg>
</div>
<div class="nav-title">膳食偏好设置</div>
<div class="nav-placeholder"></div>
</div>
<!-- ===== 问卷主体 ===== -->
<div class="questionnaire">
<div class="questionnaire__hero">
<div class="questionnaire__hero-icon">🥗</div>
<div class="questionnaire__hero-title">定制你的专属膳食方案</div>
<div class="questionnaire__hero-sub">根据你的偏好与健康数据生成个性化食谱</div>
</div>
<div class="questionnaire__body">
<!-- 问题1:所在地区 -->
<div class="questionnaire__q">
<div class="questionnaire__q-header">
<span class="questionnaire__q-num">1</span>
<span class="questionnaire__q-title">所在地区</span>
<span class="questionnaire__q-required">必选</span>
</div>
<div class="questionnaire__trigger" id="regionTrigger" onclick="openRegionSheet()">
请选择常驻地区
<span class="questionnaire__trigger-arrow"></span>
</div>
</div>
<!-- 问题2:口味偏好 -->
<div class="questionnaire__q">
<div class="questionnaire__q-header">
<span class="questionnaire__q-num">2</span>
<span class="questionnaire__q-title">口味偏好</span>
<span class="questionnaire__q-required">必选(可多选)</span>
</div>
<div class="questionnaire__chips" id="tasteChips">
<span class="questionnaire__chip" data-val="light" onclick="selectChip(this, 'tasteChips', 'multi')">清淡/原味</span>
<span class="questionnaire__chip" data-val="umami" onclick="selectChip(this, 'tasteChips', 'multi')">鲜香</span>
<span class="questionnaire__chip" data-val="salty_savory" onclick="selectChip(this, 'tasteChips', 'multi')">咸鲜</span>
<span class="questionnaire__chip" data-val="mild_spicy" onclick="selectChip(this, 'tasteChips', 'multi')">微辣</span>
<span class="questionnaire__chip" data-val="numbing_spicy" onclick="selectChip(this, 'tasteChips', 'multi')">麻辣</span>
<span class="questionnaire__chip" data-val="sour_spicy" onclick="selectChip(this, 'tasteChips', 'multi')">酸辣</span>
<span class="questionnaire__chip" data-val="sweet_sour" onclick="selectChip(this, 'tasteChips', 'multi')">酸甜</span>
<span class="questionnaire__chip" data-val="sauce_rich" onclick="selectChip(this, 'tasteChips', 'multi')">酱香/红烧</span>
<span class="questionnaire__chip" data-val="garlic" onclick="selectChip(this, 'tasteChips', 'multi')">蒜香/葱香</span>
</div>
</div>
<!-- 问题3:规避食材 -->
<div class="questionnaire__q">
<div class="questionnaire__q-header">
<span class="questionnaire__q-num">3</span>
<span class="questionnaire__q-title">饮食禁忌</span>
<span class="questionnaire__q-required">选填</span>
</div>
<div class="questionnaire__chips" id="avoidChips"></div>
<!-- 自定义食材标签 + 添加按钮 -->
<div class="questionnaire__custom-avoid" id="customAvoidTags"></div>
<div style="margin-top:8px;">
<span class="questionnaire__chip questionnaire__chip--add" onclick="openCustomAvoidInput()">添加</span>
</div>
</div>
</div>
<div class="questionnaire__footer">
<button class="questionnaire__submit" id="submitBtn" onclick="submitQuestionnaire()">请先填写必选项</button>
</div>
</div>
<!-- ===== 地区选择底部Sheet(省-市级联) ===== -->
<div class="region-mask" id="regionMask" onclick="closeRegionSheet()"></div>
<div class="region-sheet" id="regionSheet">
<div class="region-sheet__head">
<span class="region-sheet__cancel" onclick="closeRegionSheet()">取消</span>
<span class="region-sheet__title">选择所在地区</span>
<span class="region-sheet__submit" onclick="submitRegion()">确定</span>
</div>
<!-- 省份视图 -->
<div class="region-sheet__view active" id="regionProvinceView">
<div class="region-sheet__list" id="regionProvinceList"></div>
</div>
<!-- 城市视图 -->
<div class="region-sheet__view" id="regionCityView">
<div class="region-sheet__back" onclick="showProvinceView()">
<span class="region-sheet__back-arrow"></span>
<span class="region-sheet__back-label">返回选择省份</span>
<span class="region-sheet__back-province" id="regionBackProvince"></span>
</div>
<div class="region-sheet__list" id="regionCityList"></div>
</div>
</div>
<!-- ===== 自定义规避食材底部Sheet ===== -->
<div class="custom-avoid-mask" id="customAvoidMask" onclick="closeCustomAvoidInput()"></div>
<div class="custom-avoid-sheet" id="customAvoidSheet">
<div class="custom-avoid-sheet__head">
<span class="custom-avoid-sheet__cancel" onclick="closeCustomAvoidInput()">取消</span>
<span class="custom-avoid-sheet__title">添加禁忌</span>
<span class="custom-avoid-sheet__submit" onclick="confirmCustomAvoid()">确定</span>
</div>
<div class="custom-avoid-sheet__body">
<input type="text" id="customAvoidInput" class="custom-avoid-sheet__input" placeholder="输入食材名称,如 苦瓜、芹菜" maxlength="10" onkeydown="if(event.keyCode===13) confirmCustomAvoid()" />
<div class="custom-avoid-sheet__quick-label">常用食材快捷添加</div>
<div class="custom-avoid-sheet__quick" id="customAvoidQuickList"></div>
</div>
</div>
</div>
<script>
/* ================================================================
用户偏好状态
================================================================ */
var userPreferences = {
region: '',
regionLabel: '',
taste: [], // 多选口味
tasteLabel: '',
avoidFoods: []
};
/* 长庆油田工作区域:省 → 地级市 */
var REGION_DATA = [
{ name: '陕西省', cities: ['西安市','铜川市','宝鸡市','咸阳市','渭南市','延安市','汉中市','榆林市','安康市','商洛市'] },
{ name: '甘肃省', cities: ['兰州市','嘉峪关市','金昌市','白银市','天水市','武威市','张掖市','平凉市','酒泉市','庆阳市','定西市','陇南市','临夏回族自治州','甘南藏族自治州'] },
{ name: '宁夏回族自治区', cities: ['银川市','石嘴山市','吴忠市','固原市','中卫市'] },
{ name: '内蒙古自治区', cities: ['呼和浩特市','包头市','乌海市','赤峰市','通辽市','鄂尔多斯市','呼伦贝尔市','巴彦淖尔市','乌兰察布市','兴安盟','锡林郭勒盟','阿拉善盟'] }
];
var REGION_OTHER = '其他地区';
var TASTE_MAP = { light:'清淡/原味', umami:'鲜香', salty_savory:'咸鲜', mild_spicy:'微辣', numbing_spicy:'麻辣', sour_spicy:'酸辣', sweet_sour:'酸甜', sauce_rich:'酱香/红烧', garlic:'蒜香/葱香' };
var AVOID_MAP = { lamb:'羊肉', seafood:'海鲜', organ_meat:'动物内脏', peanut:'花生', egg:'鸡蛋', milk:'牛奶', coriander:'香菜', chili:'辣椒', garlic:'大蒜', mushroom:'菌菇' };
/* ================================================================
Chip 选择(single / multi
================================================================ */
function selectChip(el, containerId, mode) {
var container = document.getElementById(containerId);
if (mode === 'single') {
container.querySelectorAll('.questionnaire__chip').forEach(function(c) { c.classList.remove('questionnaire__chip--active'); });
el.classList.add('questionnaire__chip--active');
} else {
el.classList.toggle('questionnaire__chip--active');
}
updateSubmitButton();
}
/* ================================================================
提交按钮状态
================================================================ */
function checkReady() {
var hasRegion = userPreferences.region !== '';
var hasTaste = document.querySelector('#tasteChips .questionnaire__chip--active') !== null;
return hasRegion && hasTaste;
}
function updateSubmitButton() {
var btn = document.getElementById('submitBtn');
if (checkReady()) {
btn.textContent = '开始推荐';
btn.classList.add('questionnaire__submit--ready');
} else {
btn.textContent = '请先填写必选项';
btn.classList.remove('questionnaire__submit--ready');
}
}
/* ================================================================
地区 Sheet(省-市级联)
================================================================ */
var selectedProvince = null;
var selectedCity = null;
var regionMask = document.getElementById('regionMask');
var regionSheet = document.getElementById('regionSheet');
var regionSheetTimer = null;
function openRegionSheet() {
// 立即关闭自定义食材弹窗(遮罩不延迟)
clearTimeout(customAvoidSheetTimer);
customAvoidSheetTimer = null;
document.getElementById('customAvoidSheet').classList.remove('show');
document.getElementById('customAvoidMask').classList.remove('show');
// 回填已选地区
if (userPreferences.region) {
if (userPreferences.region === REGION_OTHER) {
selectedProvince = REGION_OTHER;
selectedCity = '';
showProvinceView();
} else {
var dash = userPreferences.region.indexOf('-');
selectedProvince = userPreferences.region.substring(0, dash);
selectedCity = userPreferences.region.substring(dash + 1);
showCityView();
}
} else {
selectedProvince = null;
selectedCity = null;
showProvinceView();
}
clearTimeout(regionSheetTimer);
regionMask.classList.add('show');
regionSheetTimer = setTimeout(function(){
regionSheet.classList.add('show');
regionSheetTimer = null;
}, 10);
}
function closeRegionSheet() {
clearTimeout(regionSheetTimer);
regionSheetTimer = null;
regionSheet.classList.remove('show');
regionMask.classList.remove('show');
}
/* 渲染省份列表 */
function renderProvinceList() {
var html = '';
for (var i = 0; i < REGION_DATA.length; i++) {
var p = REGION_DATA[i].name;
var active = selectedProvince === p ? ' active' : '';
var sub = (active && selectedCity)
? '<span class="region-sheet__sub">' + selectedCity + '</span>'
: '<span class="region-sheet__sub"></span>';
html += '<div class="region-sheet__item region-sheet__item--parent' + active + '" onclick="selectProvince(\'' + p + '\')"><span>' + p + '</span>' + sub + '</div>';
}
var activeOther = selectedProvince === REGION_OTHER ? ' active' : '';
html += '<div class="region-sheet__item' + activeOther + '" onclick="selectProvince(\'' + REGION_OTHER + '\')"><span>' + REGION_OTHER + '</span><span class="region-sheet__check"><svg viewBox="0 0 12 12"><polyline points="2,6.5 5,9.5 10,3"/></svg></span></div>';
document.getElementById('regionProvinceList').innerHTML = html;
}
/* 渲染城市列表 */
function renderCityList() {
var cities = [];
for (var i = 0; i < REGION_DATA.length; i++) {
if (REGION_DATA[i].name === selectedProvince) { cities = REGION_DATA[i].cities; break; }
}
var html = '';
for (var j = 0; j < cities.length; j++) {
var c = cities[j];
var active = selectedCity === c ? ' active' : '';
html += '<div class="region-sheet__item' + active + '" onclick="selectCity(\'' + c + '\')"><span>' + c + '</span><span class="region-sheet__check"><svg viewBox="0 0 12 12"><polyline points="2,6.5 5,9.5 10,3"/></svg></span></div>';
}
document.getElementById('regionCityList').innerHTML = html;
}
function showProvinceView() {
document.getElementById('regionProvinceView').classList.add('active');
document.getElementById('regionCityView').classList.remove('active');
renderProvinceList();
}
function showCityView() {
document.getElementById('regionProvinceView').classList.remove('active');
document.getElementById('regionCityView').classList.add('active');
document.getElementById('regionBackProvince').textContent = selectedProvince || '';
renderCityList();
}
function selectProvince(name) {
if (name === REGION_OTHER) {
selectedProvince = REGION_OTHER;
selectedCity = '';
renderProvinceList();
} else {
selectedProvince = name;
selectedCity = null;
showCityView();
}
}
function selectCity(name) {
selectedCity = name;
renderCityList();
}
function submitRegion() {
if (!selectedProvince) { alert('请选择所在地区'); return; }
if (selectedProvince === REGION_OTHER) {
userPreferences.region = REGION_OTHER;
userPreferences.regionLabel = REGION_OTHER;
} else {
if (!selectedCity) { alert('请选择城市'); return; }
userPreferences.region = selectedProvince + '-' + selectedCity;
userPreferences.regionLabel = selectedProvince + ' ' + selectedCity;
}
var trigger = document.getElementById('regionTrigger');
trigger.textContent = userPreferences.regionLabel;
trigger.classList.add('questionnaire__trigger--filled');
closeRegionSheet();
updateSubmitButton();
}
/* ================================================================
提交问卷
================================================================ */
function submitQuestionnaire() {
if (!checkReady()) return;
// 收集口味(多选)
var tasteActives = document.querySelectorAll('#tasteChips .questionnaire__chip--active');
userPreferences.taste = [];
var tasteLabels = [];
tasteActives.forEach(function(c) {
var val = c.getAttribute('data-val');
userPreferences.taste.push(val);
tasteLabels.push(TASTE_MAP[val] || val);
});
userPreferences.tasteLabel = tasteLabels.join('、');
// 规避食材已由自定义标签系统管理,直接使用 avoidFoods
// 存入 localStorage
localStorage.setItem('dietPreferences', JSON.stringify(userPreferences));
// 跳转到膳食建议页
location.href = 'diet-advice-v2.html';
}
/* ================================================================
自定义规避食材 — 底部输入 Sheet
================================================================ */
var CUSTOM_AVOID_QUICK = ['猪肉','牛肉','羊肉','鸡肉','鸭肉','鱼肉','虾','蟹','鸡蛋','牛奶','洋葱','香菜','葱','姜','蒜','韭菜','芹菜','虾皮'];
var customAvoidSheetTimer = null;
function openCustomAvoidInput() {
// 立即关闭地区弹窗(遮罩不延迟,避免两个弹窗同时出现)
clearTimeout(regionSheetTimer);
regionSheetTimer = null;
regionSheet.classList.remove('show');
regionMask.classList.remove('show');
renderCustomAvoidQuick();
clearTimeout(customAvoidSheetTimer);
document.getElementById('customAvoidMask').classList.add('show');
customAvoidSheetTimer = setTimeout(function(){
document.getElementById('customAvoidSheet').classList.add('show');
document.getElementById('customAvoidInput').focus();
customAvoidSheetTimer = null;
}, 10);
}
function closeCustomAvoidInput() {
clearTimeout(customAvoidSheetTimer);
customAvoidSheetTimer = null;
document.getElementById('customAvoidSheet').classList.remove('show');
document.getElementById('customAvoidMask').classList.remove('show');
document.getElementById('customAvoidInput').value = '';
}
function renderCustomAvoidQuick() {
var avoid = userPreferences.avoidFoods;
var html = '';
for (var i = 0; i < CUSTOM_AVOID_QUICK.length; i++) {
var name = CUSTOM_AVOID_QUICK[i];
var added = avoid.indexOf(name) !== -1;
html += '<span class="custom-avoid-sheet__quick-tag' + (added ? ' custom-avoid-sheet__quick-tag--added' : '') + '" data-name="' + name + '" onclick="toggleCustomAvoidQuick(this)">' + name + '</span>';
}
document.getElementById('customAvoidQuickList').innerHTML = html;
}
function toggleCustomAvoidQuick(el) {
var name = el.getAttribute('data-name');
var idx = userPreferences.avoidFoods.indexOf(name);
if (idx === -1) {
userPreferences.avoidFoods.push(name);
} else {
userPreferences.avoidFoods.splice(idx, 1);
}
renderCustomAvoidQuick();
renderCustomAvoidTags();
}
function confirmCustomAvoid() {
var input = document.getElementById('customAvoidInput');
var name = input.value.trim();
if (!name) { closeCustomAvoidInput(); return; }
// 去重
if (userPreferences.avoidFoods.indexOf(name) !== -1) {
alert('「' + name + '」已在规避列表中');
return;
}
userPreferences.avoidFoods.push(name);
closeCustomAvoidInput();
renderCustomAvoidTags();
}
function removeCustomAvoidTag(el) {
var name = el.getAttribute('data-name');
var idx = userPreferences.avoidFoods.indexOf(name);
if (idx !== -1) userPreferences.avoidFoods.splice(idx, 1);
renderCustomAvoidTags();
}
function renderCustomAvoidTags() {
var container = document.getElementById('customAvoidTags');
var avoid = userPreferences.avoidFoods;
var presetKeys = Object.keys(AVOID_MAP);
var html = '';
for (var i = 0; i < avoid.length; i++) {
var item = avoid[i];
// 只渲染自定义食材(不在预置 key 中的)
if (presetKeys.indexOf(item) === -1) {
html += '<span class="questionnaire__custom-tag" data-name="' + item + '" onclick="removeCustomAvoidTag(this)">' + item + '</span>';
}
}
container.innerHTML = html;
}
/* ================================================================
返回按钮
================================================================ */
function goBack() {
history.back();
}
/* ================================================================
初始化 — 回填已有偏好
================================================================ */
function init() {
// 尝试从 localStorage 读取已有偏好("修改偏好"场景)
var saved = localStorage.getItem('dietPreferences');
if (saved) {
try {
var prefs = JSON.parse(saved);
userPreferences = prefs;
// 回填地区
if (prefs.region) {
var trigger = document.getElementById('regionTrigger');
trigger.textContent = prefs.regionLabel || prefs.region;
trigger.classList.add('questionnaire__trigger--filled');
}
// 回填口味(多选)
if (prefs.taste && prefs.taste.length) {
var tasteArr = Array.isArray(prefs.taste) ? prefs.taste : [prefs.taste]; // 兼容旧版单字符串
document.querySelectorAll('#tasteChips .questionnaire__chip').forEach(function(c) {
if (tasteArr.indexOf(c.getAttribute('data-val')) !== -1) c.classList.add('questionnaire__chip--active');
});
}
// 回填规避食材(自定义标签)
renderCustomAvoidTags();
updateSubmitButton();
} catch(e) {
// 解析失败则忽略
}
}
// 无历史偏好时,默认选中常用口味
if (!userPreferences.taste || !userPreferences.taste.length) {
var defaultTastes = ['light', 'salty_savory'];
document.querySelectorAll('#tasteChips .questionnaire__chip').forEach(function(c) {
if (defaultTastes.indexOf(c.getAttribute('data-val')) !== -1) c.classList.add('questionnaire__chip--active');
});
updateSubmitButton();
}
}
init();
</script>
</body>
</html>
@@ -4,6 +4,16 @@
---
## [2026-08-27] refactor: 删除膳食偏好设置页(diet-questionnaire.html
**涉及文件:**
- `employee-app/weight-management/diet-questionnaire.html`(删除)
- `employee-app/weight-management/doc/screenshots/diet-questionnaire.jpg` / `diet-questionnaire-region.jpg` / `diet-questionnaire-avoid.jpg`(删除,仅被该页引用)
- `employee-app/weight-management/doc/PRD.md`(修改):页面清单与逐页说明移除"膳食偏好设置",后续章节及清单序号 17~28 前移为 16~27,同步修正"见第 N 节"交叉引用;体重管理主页交互说明中"今日饮食建议"改为直接跳转 diet-advice-v2.html(不再先判断饮食偏好);页面导航结构树移除"膳食偏好设置"
- `employee-app/weight-management/doc/design-overview.html`(修改):移除膳食偏好设置及其两张弹窗共 3 张截图卡片
---
## [2026-08-19] fix: 重拍全部 18 张弹窗截图 — 2x 超采样高清版,解决模糊问题
**涉及文件(20个):**
+28 -59
View File
@@ -18,7 +18,7 @@
│ ├── 饮食记录 → 饮食录入 → 拍照识别
│ ├── 运动记录 → 运动录入
│ ├── 体重记录 → 详细报告 / 体脂仪报告 / 身高秤报告
│ ├── 今日饮食建议 / 膳食偏好设置
│ ├── 今日饮食建议
│ ├── 智能运动计划
│ ├── 排行榜
│ ├── 体重报告 → 数据明细
@@ -80,29 +80,28 @@ stateDiagram-v2
| 13 | 运动记录 | exercise-detail-v2.html | 页面 |
| 14 | 今日饮食建议 | diet-advice-v2.html | 页面 |
| 15 | 智能运动计划 | exercise-advice-v2.html | 页面 |
| 16 | 膳食偏好设置 | diet-questionnaire.html | 页面 |
| 17 | 拍照识别 | scan-checkin.html | 页面 |
| 16 | 拍照识别 | scan-checkin.html | 页面 |
### 三、体重记录与报告
| 序号 | 页面/弹窗 | 文件 | 类型 |
|------|-----------|------|------|
| 18 | 体重记录 | weight-detail-v2.html | 页面 |
| 19 | 详细报告 | report-detail.html | 页面 |
| 20 | 体脂仪报告 | body-fat-report.html | 页面 |
| 21 | 身高秤报告 | height-scale-report.html | 页面 |
| 22 | 体重报告 | weight-report.html | 页面 |
| 23 | 数据明细 | weight-record-detail-v2.html | 页面 |
| 24 | 排行榜 | weight-ranking.html | 页面 |
| 17 | 体重记录 | weight-detail-v2.html | 页面 |
| 18 | 详细报告 | report-detail.html | 页面 |
| 19 | 体脂仪报告 | body-fat-report.html | 页面 |
| 20 | 身高秤报告 | height-scale-report.html | 页面 |
| 21 | 体重报告 | weight-report.html | 页面 |
| 22 | 数据明细 | weight-record-detail-v2.html | 页面 |
| 23 | 排行榜 | weight-ranking.html | 页面 |
### 四、蓝牙体脂秤
| 序号 | 页面/弹窗 | 文件 | 类型 |
|------|-----------|------|------|
| 25 | 蓝牙称 | bluetooth-scale-v2.html | 页面 |
| 26 | 搜索设备 | bluetooth-search-v2.html | 页面 |
| 27 | WiFi 连接 | bluetooth-wifi-v2.html | 页面 |
| 28 | 用户管理 | bluetooth-device-members-v2.html | 页面 |
| 24 | 蓝牙称 | bluetooth-scale-v2.html | 页面 |
| 25 | 搜索设备 | bluetooth-search-v2.html | 页面 |
| 26 | WiFi 连接 | bluetooth-wifi-v2.html | 页面 |
| 27 | 用户管理 | bluetooth-device-members-v2.html | 页面 |
---
@@ -141,7 +140,7 @@ stateDiagram-v2
- **吃记录卡片:** 左侧环形进度圈(今日摄入/推荐摄入/还可摄入热量),右侧营养素进度(碳水/蛋白质/脂肪,各含摄入量/推荐量),右上"今日饮食建议"按钮 + "+"记录按钮
- **动记录卡片:** 左侧环形进度圈(今日消耗/推荐消耗/还需消耗热量),右侧消耗明细(步行消耗/运动消耗/基础代谢),右上"智能运动计划"按钮 + "+"记录按钮
- **体重记录卡片:** 左侧最近一次体重(含记录日期)+ 右侧近 7 日折线趋势图,右上"蓝牙称"按钮 + "+"记录按钮(打开记录体重弹窗)
- **记录体重弹窗(底部弹层):** 记录体重(必填,滑动尺子调整)+ 记录体脂率(开关)+ 记录腰围(开关)+ "保存"按钮,构成同体重记录页的记录体重弹窗(见第 18 节)
- **记录体重弹窗(底部弹层):** 记录体重(必填,滑动尺子调整)+ 记录体脂率(开关)+ 记录腰围(开关)+ "保存"按钮,构成同体重记录页的记录体重弹窗(见第 17 节)
![记录体重弹窗](screenshots/weight-main-record.jpg)
- **记录成功弹窗(保存后弹出):** 居中弹窗——今日日期 + "记录成功" + 今日体重(kg,青绿高亮)+ 体脂率/腰围摘要行(对应开关开启时显示)+ "确定"按钮(仅关闭弹窗,留在当前页)
@@ -158,7 +157,7 @@ stateDiagram-v2
- 点击吃/动/体重卡片:已记录时跳转到对应记录页(饮食记录 eat-detail-v2.html / 运动记录 exercise-detail-v2.html / 体重记录 weight-detail-v2.html),未记录时直接跳转到自记打卡页(饮食录入 eat-checkin-v2.html / 运动录入 exercise-checkin-v2.html,体重为打开记录体重弹窗)
- 点击吃卡片"+"跳转到饮食录入页(eat-checkin-v2.html);动卡片"+"跳转到运动录入页(exercise-checkin-v2.html);体重卡片"+"打开记录体重弹窗
- 记录体重弹窗点击"保存"后关闭弹窗并弹出记录成功弹窗(展示本次记录的体重等数据),主页体重卡片同步更新为最新记录
- 点击"今日饮食建议",先判断是否设置饮食偏好,如未设置,跳转到diet-questionnaire.html,设置了则跳转到今日饮食建议页(diet-advice-v2.html);"智能运动计划"跳转到智能运动计划页(exercise-advice-v2.html);"蓝牙称"跳转到蓝牙称页(bluetooth-scale-v2.html
- 点击"今日饮食建议"跳转到今日饮食建议页(diet-advice-v2.html);"智能运动计划"跳转到智能运动计划页(exercise-advice-v2.html);"蓝牙称"跳转到蓝牙称页(bluetooth-scale-v2.html
- 点击吃动平衡卡片跳转到吃动平衡页(eat-exercise-detail-v2.html);点击周日历中的日期切换当日吃动统计(不触发跳转)
- 点击排行榜卡片跳转到排行榜页(weight-ranking.html);体重报告卡片跳转到体重报告页(weight-report.html
- 点击返回按钮跳转到应用主页(home/index.html
@@ -454,7 +453,7 @@ stateDiagram-v2
**主要UI元素:**
- 周历(含月历弹窗):日期用彩色圆环标记数据来源(智记餐/自记餐/智记+自记餐),圆环下方显示来源文字标签(智 / 自 / 智+自)
- 月历弹窗:月份标题 + 前后月份切换箭头(◀/▶)+ 当月日期网格(今日/选中态高亮,点选日期后关闭弹窗并切换当日数据)——第 11/13/14/15/18 节各页月历弹窗构成相同
- 月历弹窗:月份标题 + 前后月份切换箭头(◀/▶)+ 当月日期网格(今日/选中态高亮,点选日期后关闭弹窗并切换当日数据)——第 11/13/14/15/17 节各页月历弹窗构成相同
![月历弹窗](screenshots/eat-detail-month.jpg)
- 热量标尺:半圆进度弧 + 中心总摄入/推荐摄入,右上"今日饮食建议"按钮
@@ -637,37 +636,7 @@ stateDiagram-v2
---
### 16. 膳食偏好设置(diet-questionnaire.html
![页面截图](screenshots/diet-questionnaire.jpg)
**功能说明:** 膳食偏好问卷,用于生成个性化膳食方案。
**主要UI元素:**
- 顶部引导区(绿色渐变):"定制你的专属膳食方案"
- Q1 所在地区(必选):省-市级联选择弹窗(预置陕西/甘肃/宁夏/内蒙古等长庆油田覆盖区域,含"其他地区"兜底项)
![省-市级联选择弹窗](screenshots/diet-questionnaire-region.jpg)
- Q2 口味偏好(必选,多选):清淡/原味、鲜香、咸鲜、微辣、麻辣、酸辣、酸甜、酱香/红烧、蒜香/葱香
- Q3 饮食禁忌(选填):"添加"按钮打开自定义禁忌弹窗(输入框 + 常用食材快捷添加)
![自定义禁忌弹窗](screenshots/diet-questionnaire-avoid.jpg)
- 提交按钮:"请先填写必选项"(禁用态)→ "开始推荐"(可用态)
**交互说明:**
- 点击地区行打开省市联动底部弹窗
- 点击口味偏好标签切换选中/取消(多选)
- 点击"添加"打开自定义禁忌添加弹窗
- 点击提交按钮保存偏好并跳转到今日饮食建议页(diet-advice-v2.html
**业务规则:**
- 地区与口味为必选,禁忌为选填
- 首次进入(无历史偏好)默认选中常用口味"清淡/原味、咸鲜"
- 偏好数据持久化到本地,支持"修改偏好"回填
---
### 17. 拍照识别(scan-checkin.html
### 16. 拍照识别(scan-checkin.html
![页面截图](screenshots/scan-checkin.jpg)
@@ -696,7 +665,7 @@ stateDiagram-v2
## 三、体重记录与报告
### 18. 体重记录(weight-detail-v2.html
### 17. 体重记录(weight-detail-v2.html
![页面截图](screenshots/weight-detail.jpg)
@@ -729,7 +698,7 @@ stateDiagram-v2
- 体重数据来源目前有体检数据、自记数据、后台管理员记录、身高秤、蓝牙秤、体脂仪这6种,其中体检数据和后台管理员需要更新最新体重但记录不计入员工打卡行动,另外三种测量设备的数据可能出现延迟上传的情况,系统至多允许补录前一天的体重数据(定时修正前一天的行动状态和排名数据),再早的数据补传后不计入体重管理行动体重打卡
---
### 19. 详细报告(report-detail.html
### 18. 详细报告(report-detail.html
![页面截图](screenshots/report-detail-bluetooth.jpg)
@@ -757,7 +726,7 @@ stateDiagram-v2
---
### 20. 体脂仪报告(body-fat-report.html
### 19. 体脂仪报告(body-fat-report.html
![页面截图](screenshots/body-fat-report.jpg)
@@ -781,7 +750,7 @@ stateDiagram-v2
---
### 21. 身高秤报告(height-scale-report.html
### 20. 身高秤报告(height-scale-report.html
![页面截图](screenshots/height-scale-report.jpg)
@@ -801,7 +770,7 @@ stateDiagram-v2
---
### 22. 体重报告(weight-report.html
### 21. 体重报告(weight-report.html
![页面截图](screenshots/weight-report.jpg)
@@ -832,7 +801,7 @@ stateDiagram-v2
---
### 23. 数据明细(weight-record-detail-v2.html
### 22. 数据明细(weight-record-detail-v2.html
![页面截图](screenshots/weight-record-detail.jpg)
@@ -851,7 +820,7 @@ stateDiagram-v2
---
### 24. 排行榜(weight-ranking.html
### 23. 排行榜(weight-ranking.html
![页面截图](screenshots/weight-ranking.jpg)
@@ -889,7 +858,7 @@ stateDiagram-v2
## 四、蓝牙体脂秤
### 25. 蓝牙称(bluetooth-scale-v2.html
### 24. 蓝牙称(bluetooth-scale-v2.html
![页面截图](screenshots/bluetooth-scale.jpg)
@@ -916,7 +885,7 @@ stateDiagram-v2
---
### 26. 搜索设备(bluetooth-search-v2.html
### 25. 搜索设备(bluetooth-search-v2.html
![页面截图](screenshots/bluetooth-search.jpg)
@@ -938,7 +907,7 @@ stateDiagram-v2
---
### 27. WiFi 连接(bluetooth-wifi-v2.html
### 26. WiFi 连接(bluetooth-wifi-v2.html
![页面截图](screenshots/bluetooth-wifi.jpg)
@@ -958,7 +927,7 @@ stateDiagram-v2
---
### 28. 用户管理(bluetooth-device-members-v2.html
### 27. 用户管理(bluetooth-device-members-v2.html
![页面截图](screenshots/bluetooth-device-members.jpg)
@@ -419,21 +419,6 @@ body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-
<div class="card__label">膳食建议 · 不喜欢确认弹窗</div>
<div class="card__tags"><span class="tag tag--modal">弹窗</span></div>
</div>
<div class="card" onclick="openLightbox('screenshots/diet-questionnaire.jpg','膳食偏好设置')">
<div class="card__img"><img src="screenshots/diet-questionnaire.jpg" alt=""></div>
<div class="card__label">膳食偏好设置</div>
<div class="card__tags"><span class="tag tag--modal">弹窗</span></div>
</div>
<div class="card" onclick="openLightbox('screenshots/diet-questionnaire-region.jpg','膳食偏好 · 地区选择弹窗')">
<div class="card__img"><img src="screenshots/diet-questionnaire-region.jpg" alt=""></div>
<div class="card__label">膳食偏好 · 地区选择弹窗</div>
<div class="card__tags"><span class="tag tag--modal">弹窗</span></div>
</div>
<div class="card" onclick="openLightbox('screenshots/diet-questionnaire-avoid.jpg','膳食偏好 · 饮食禁忌弹窗')">
<div class="card__img"><img src="screenshots/diet-questionnaire-avoid.jpg" alt=""></div>
<div class="card__label">膳食偏好 · 饮食禁忌弹窗</div>
<div class="card__tags"><span class="tag tag--modal">弹窗</span></div>
</div>
<div class="card" onclick="openLightbox('screenshots/exercise-advice.jpg','运动建议')">
<div class="card__img"><img src="screenshots/exercise-advice.jpg" alt=""></div>
<div class="card__label">运动建议</div>
Binary file not shown.

Before

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB