chore: 删除体重管理旧版页面(已迁移至v2版本)
This commit is contained in:
@@ -1,308 +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; margin-right: 28px; }
|
||||
.scroll-content { flex: 1; overflow-y: auto; background: #f5f7fa; }
|
||||
.scroll-content::-webkit-scrollbar { display: none; }
|
||||
.bottom-safe { height: 20px; flex-shrink: 0; }
|
||||
|
||||
/* ===== 日历导航 ===== */
|
||||
.cal-nav { display: flex; align-items: center; justify-content: space-between; padding: 10px 14px 6px; background: #fff; margin: 10px 12px 0; border-radius: 16px 16px 0 0; }
|
||||
.cal-nav__arrow { width: 26px; height: 26px; border-radius: 50%; background: #f7f8fa; display: flex; align-items: center; justify-content: center; cursor: pointer; border: none; }
|
||||
.cal-nav__arrow svg { width: 14px; height: 14px; stroke: #333; }
|
||||
.cal-nav__month { font-size: 14px; font-weight: 700; color: #1a1a1a; }
|
||||
|
||||
/* ===== 日历 ===== */
|
||||
.cal-grid { background: #fff; margin: 0 12px; padding: 0 12px 10px; border-radius: 0 0 16px 16px; box-shadow: 0 4px 14px rgba(0,0,0,0.04); }
|
||||
.cal-grid__wd { display: grid; grid-template-columns: repeat(7, 1fr); margin-bottom: 3px; }
|
||||
.cal-grid__wd span { font-size: 10px; color: #999; text-align: center; }
|
||||
.cal-grid__days { display: grid; grid-template-columns: repeat(7, 1fr); gap: 2px; }
|
||||
.cal-day { display: flex; flex-direction: column; align-items: center; padding: 1px 0 2px; border-radius: 6px; cursor: pointer; min-height: 34px; }
|
||||
.cal-day:hover { background: #f0f8f8; }
|
||||
.cal-day.today { background: #e8f8f7; }
|
||||
.cal-day.sel { background: #e8f8f7; border: 1.5px solid #36cfc9; }
|
||||
.cal-day__num { font-size: 12px; font-weight: 700; color: #333; line-height: 1.2; }
|
||||
.cal-day.today .cal-day__num, .cal-day.sel .cal-day__num { color: #36cfc9; }
|
||||
.cal-day--empty { min-height: 34px; }
|
||||
|
||||
.cal-ring-wrap { display: flex; align-items: center; justify-content: center; margin-top: 2px; width: 24px; height: 24px; position: relative; }
|
||||
.cal-ring--o { position: absolute; width: 21px; height: 21px; }
|
||||
.cal-ring--o svg { width: 100%; height: 100%; }
|
||||
.cal-ring--i { position: absolute; width: 14px; height: 14px; }
|
||||
.cal-ring--i svg { width: 100%; height: 100%; }
|
||||
|
||||
.cal-day-diff { font-size: 6px; color: #bbb; margin-top: 0; text-align: center; line-height: 1.2; }
|
||||
.cal-day-diff span { color: #36cfc9; }
|
||||
|
||||
/* ===== 柱状图 ===== */
|
||||
.bar-section { background: #fff; border-radius: 16px; margin: 10px 12px 0; padding: 12px 10px 12px; box-shadow: 0 4px 14px rgba(0,0,0,0.04); }
|
||||
.bar-section__title { font-size: 13px; font-weight: 700; color: #1a1a1a; margin-bottom: 8px; padding-left: 2px; }
|
||||
.bar-area { position: relative; width: 100%; height: 220px; }
|
||||
.bar-area svg { width: 100%; height: 100%; display: block; }
|
||||
.bar-overlay { position: absolute; top: 0; left: 0; width: 100%; height: 100%; pointer-events: none; }
|
||||
.bar-hit { position: absolute; pointer-events: auto; cursor: pointer; border-radius: 3px 3px 0 0; }
|
||||
.bar-hit:hover { opacity: 0.85; }
|
||||
.bar-legend { display: flex; justify-content: center; gap: 14px; margin-top: 8px; }
|
||||
.bar-legend__item { display: flex; align-items: center; gap: 4px; font-size: 11px; color: #666; }
|
||||
.bar-legend__sw { width: 10px; height: 7px; border-radius: 2px; flex-shrink: 0; }
|
||||
.bar-legend__sw--in { background: #5470c6; }
|
||||
.bar-legend__sw--ex { background: #fac858; }
|
||||
|
||||
/* Tooltip */
|
||||
.tip { display: none; position: absolute; background: rgba(30,30,30,0.9); color: #fff; border-radius: 10px; padding: 10px 12px; font-size: 11px; line-height: 1.7; pointer-events: none; z-index: 10; min-width: 130px; box-shadow: 0 4px 12px rgba(0,0,0,0.2); }
|
||||
.tip::after { content: ''; position: absolute; top: 100%; left: 50%; transform: translateX(-50%); border: 5px solid transparent; border-top-color: rgba(30,30,30,0.9); }
|
||||
.tip__date { font-weight: 700; font-size: 12px; margin-bottom: 4px; }
|
||||
.tip__row { display: flex; justify-content: space-between; }
|
||||
.tip__lbl { color: #ccc; }
|
||||
.tip__val { font-weight: 600; }
|
||||
.tip__val--b { color: #7eb8f7; }
|
||||
.tip__val--y { color: #f7d794; }
|
||||
.tip__div { border-top: 1px solid rgba(255,255,255,0.15); margin: 4px 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" onclick="location.href='weight-main.html'">
|
||||
<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"/></svg>
|
||||
</div>
|
||||
<div class="nav-title">历史记录</div>
|
||||
</div>
|
||||
|
||||
<div class="scroll-content">
|
||||
|
||||
<!-- 日历导航 -->
|
||||
<div class="cal-nav">
|
||||
<button class="cal-nav__arrow" onclick="changeMonth(-1)">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="15 18 9 12 15 6"/></svg>
|
||||
</button>
|
||||
<span class="cal-nav__month" id="nav-month">2026年8月</span>
|
||||
<button class="cal-nav__arrow" onclick="changeMonth(1)">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="9 18 15 12 9 6"/></svg>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- 日历 -->
|
||||
<div class="cal-grid">
|
||||
<div class="cal-grid__wd">
|
||||
<span>一</span><span>二</span><span>三</span><span>四</span><span>五</span><span>六</span><span>日</span>
|
||||
</div>
|
||||
<div class="cal-grid__days" id="cal-days"></div>
|
||||
</div>
|
||||
|
||||
<!-- 柱状图 -->
|
||||
<div class="bar-section">
|
||||
<div class="bar-section__title">本月吃动趋势</div>
|
||||
<div class="bar-area" id="bar-area">
|
||||
<div class="tip" id="tip"><div class="tip__date"></div><div class="tip__body"></div></div>
|
||||
<svg viewBox="0 0 360 208" preserveAspectRatio="none" id="bar-svg">
|
||||
<defs>
|
||||
<linearGradient id="ig" x1="0" y1="0" x2="0" y2="1"><stop offset="0%" stop-color="#5470c6"/><stop offset="100%" stop-color="#3a56a4"/></linearGradient>
|
||||
<linearGradient id="eg" x1="0" y1="0" x2="0" y2="1"><stop offset="0%" stop-color="#fac858"/><stop offset="100%" stop-color="#e6a817"/></linearGradient>
|
||||
</defs>
|
||||
<!-- Y轴标签 -->
|
||||
<text x="2" y="16" font-size="9" fill="#999">2500</text>
|
||||
<text x="2" y="48" font-size="9" fill="#999">2000</text>
|
||||
<text x="2" y="79" font-size="9" fill="#999">1500</text>
|
||||
<text x="2" y="111" font-size="9" fill="#999">1000</text>
|
||||
<text x="2" y="142" font-size="9" fill="#999">500</text>
|
||||
<!-- Y轴刻度线 -->
|
||||
<line x1="34" y1="12" x2="38" y2="12" stroke="#e0e0e0" stroke-width="1"/>
|
||||
<line x1="34" y1="44" x2="38" y2="44" stroke="#e0e0e0" stroke-width="1"/>
|
||||
<line x1="34" y1="75" x2="38" y2="75" stroke="#e0e0e0" stroke-width="1"/>
|
||||
<line x1="34" y1="107" x2="38" y2="107" stroke="#e0e0e0" stroke-width="1"/>
|
||||
<line x1="34" y1="138" x2="38" y2="138" stroke="#e0e0e0" stroke-width="1"/>
|
||||
<!-- X轴线 (y=170) -->
|
||||
<line x1="38" y1="170" x2="350" y2="170" stroke="#f0f0f0" stroke-width="1"/>
|
||||
<g id="bars"></g>
|
||||
</svg>
|
||||
<div class="bar-overlay" id="bar-overlay"></div>
|
||||
</div>
|
||||
<div class="bar-legend">
|
||||
<div class="bar-legend__item"><div class="bar-legend__sw bar-legend__sw--in"></div><span>摄入</span></div>
|
||||
<div class="bar-legend__item"><div class="bar-legend__sw bar-legend__sw--ex"></div><span>消耗</span></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="bottom-safe"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
var currentYear = 2026, currentMonth = 8, selectedDay = null;
|
||||
var dayData = {};
|
||||
var mock = [
|
||||
{d:1,i:1920,e:1680,c:1100,f:490,p:330,bf:520,l:820,dn:580,ba:1100,s:320,w:260},
|
||||
{d:2,i:2100,e:1750,c:1200,f:540,p:360,bf:580,l:900,dn:620,ba:1120,s:350,w:280},
|
||||
{d:3,i:1850,e:1920,c:1050,f:470,p:330,bf:480,l:780,dn:590,ba:1130,s:480,w:310},
|
||||
{d:4,i:2050,e:1700,c:1160,f:520,p:370,bf:550,l:870,dn:630,ba:1110,s:310,w:280},
|
||||
{d:5,i:1780,e:1850,c:1010,f:450,p:320,bf:460,l:750,dn:570,ba:1140,s:420,w:290},
|
||||
{d:6,i:2200,e:1600,c:1260,f:560,p:380,bf:620,l:940,dn:640,ba:1100,s:260,w:240},
|
||||
{d:7,i:1950,e:1780,c:1110,f:495,p:345,bf:510,l:830,dn:610,ba:1120,s:360,w:300},
|
||||
{d:8,i:1880,e:1960,c:1070,f:475,p:335,bf:490,l:800,dn:590,ba:1150,s:500,w:310},
|
||||
{d:9,i:1960,e:1720,c:1120,f:500,p:340,bf:530,l:840,dn:590,ba:1110,s:330,w:280},
|
||||
{d:10,i:2080,e:1800,c:1180,f:530,p:370,bf:560,l:890,dn:630,ba:1130,s:370,w:300},
|
||||
{d:11,i:1820,e:1900,c:1030,f:460,p:330,bf:470,l:770,dn:580,ba:1140,s:450,w:310},
|
||||
{d:12,i:1940,e:1760,c:1100,f:490,p:350,bf:520,l:830,dn:590,ba:1120,s:340,w:300},
|
||||
{d:13,i:1900,e:1820,c:1080,f:480,p:340,bf:500,l:810,dn:590,ba:1130,s:380,w:310},
|
||||
];
|
||||
mock.forEach(function(m){
|
||||
dayData['2026-08-'+(m.d<10?'0'+m.d:m.d)] = m;
|
||||
});
|
||||
|
||||
/* 日历 */
|
||||
function renderCal(){
|
||||
var c = document.getElementById('cal-days');
|
||||
c.innerHTML = '';
|
||||
document.getElementById('nav-month').textContent = currentYear+'年'+currentMonth+'月';
|
||||
var fd = new Date(currentYear, currentMonth-1, 1).getDay();
|
||||
var dim = new Date(currentYear, currentMonth, 0).getDate();
|
||||
var off = fd===0?6:fd-1;
|
||||
var today = new Date();
|
||||
var tk = today.getFullYear()+'-'+String(today.getMonth()+1).padStart(2,'0')+'-'+String(today.getDate()).padStart(2,'0');
|
||||
for(var i=0;i<off;i++){var em=document.createElement('div');em.className='cal-day--empty';c.appendChild(em);}
|
||||
for(var d=1;d<=dim;d++){
|
||||
var dk = currentYear+'-'+String(currentMonth).padStart(2,'0')+'-'+String(d).padStart(2,'0');
|
||||
var data = dayData[dk];
|
||||
var el = document.createElement('div');
|
||||
el.className='cal-day';
|
||||
if(dk===tk) el.classList.add('today');
|
||||
if(selectedDay===d) el.classList.add('sel');
|
||||
el.setAttribute('data-d',d);el.setAttribute('data-k',dk);
|
||||
el.onclick=function(){selDay(+this.getAttribute('data-d'),this.getAttribute('data-k'));};
|
||||
var n=document.createElement('span');n.className='cal-day__num';n.textContent=d;el.appendChild(n);
|
||||
if(data){
|
||||
var ip=Math.min(data.i/2500,1),ep=Math.min(data.e/2500,1);
|
||||
var rw=document.createElement('div');rw.className='cal-ring-wrap';
|
||||
var o=document.createElement('div');o.className='cal-ring--o';
|
||||
var cc=2*Math.PI*8;
|
||||
o.innerHTML='<svg viewBox="0 0 20 20"><circle cx="10" cy="10" r="8" fill="none" stroke="#e0e0e0" stroke-width="2"/><circle cx="10" cy="10" r="8" fill="none" stroke="#5470c6" stroke-width="2" stroke-dasharray="'+(cc*ip).toFixed(1)+' '+ (cc*(1-ip)).toFixed(1)+'" stroke-linecap="round"/></svg>';
|
||||
rw.appendChild(o);
|
||||
var inn=document.createElement('div');inn.className='cal-ring--i';
|
||||
var cc2=2*Math.PI*8;
|
||||
inn.innerHTML='<svg viewBox="0 0 20 20"><circle cx="10" cy="10" r="8" fill="none" stroke="#e0e0e0" stroke-width="2"/><circle cx="10" cy="10" r="8" fill="none" stroke="#fac858" stroke-width="2" stroke-dasharray="'+(cc2*ep).toFixed(1)+' '+(cc2*(1-ep)).toFixed(1)+'" stroke-linecap="round"/></svg>';
|
||||
rw.appendChild(inn);el.appendChild(rw);
|
||||
var ad=data.i-data.e;
|
||||
var df=document.createElement('div');df.className='cal-day-diff';
|
||||
df.innerHTML='<span>-500</span><span>'+ad+'</span>';el.appendChild(df);
|
||||
}
|
||||
c.appendChild(el);
|
||||
}
|
||||
}
|
||||
function selDay(d,k){
|
||||
selectedDay=d;
|
||||
document.querySelectorAll('.cal-day').forEach(function(el){el.classList.remove('sel');if(+el.getAttribute('data-d')===d)el.classList.add('sel');});
|
||||
renderBars();
|
||||
/* 自动弹出选中日的摄入详情 */
|
||||
var intBar=document.querySelector('.bar-hit[data-k="'+k+'"]');
|
||||
if(intBar) showTipIn(intBar);
|
||||
}
|
||||
function selectDayFromBar(dk,type){
|
||||
var d=+dk.split("-")[2];
|
||||
selectedDay=d;
|
||||
document.querySelectorAll(".cal-day").forEach(function(el){el.classList.remove("sel");if(+el.getAttribute("data-d")===d)el.classList.add("sel");});
|
||||
renderBars();
|
||||
var h=document.querySelector('.bar-hit[data-k="'+dk+'"]');
|
||||
if(h){ if(type==="in")showTipIn(h); else showTipEx(h); }
|
||||
}
|
||||
function changeMonth(delta){
|
||||
currentMonth+=delta;
|
||||
if(currentMonth>12){currentMonth=1;currentYear++;}
|
||||
if(currentMonth<1){currentMonth=12;currentYear--;}
|
||||
selectedDay=null;renderCal();renderBars();
|
||||
}
|
||||
|
||||
/* 柱状图 */
|
||||
function renderBars(){
|
||||
var g=document.getElementById('bars'),ov=document.getElementById('bar-overlay');
|
||||
g.innerHTML='';ov.innerHTML='';
|
||||
var dim=new Date(currentYear,currentMonth,0).getDate();
|
||||
var md=dim;
|
||||
// SVG: viewBox 0 0 360 208, preserveAspectRatio=none 完全填满bar-area
|
||||
// X轴线在 y=170,Y轴标签/刻度在左侧
|
||||
var chartLeft=38, chartRight=350, chartTop=12, chartBot=170;
|
||||
var chartW=chartRight-chartLeft, chartH=chartBot-chartTop; // 312 x 158
|
||||
var pairW=chartW/md, gap=3, barW=(pairW-gap)/2;
|
||||
var maxY=2500;
|
||||
for(var d=1;d<=md;d++){
|
||||
var k=currentYear+'-'+String(currentMonth).padStart(2,'0')+'-'+String(d).padStart(2,'0');
|
||||
var data=dayData[k];
|
||||
var xs=chartLeft+(d-1)*pairW, hl=selectedDay===d;
|
||||
if(data){
|
||||
var iH=(data.i/maxY)*chartH, iY=chartTop+chartH-iH;
|
||||
var iX=xs+1, iC=hl?'#5470c6':'url(#ig)';
|
||||
if(hl) g.innerHTML+='<rect x="'+(iX-1)+'" y="'+iY+'" width="'+(barW+2)+'" height="'+iH+'" rx="2" fill="'+iC+'" opacity="0.25"/>';
|
||||
g.innerHTML+='<rect x="'+iX+'" y="'+iY+'" width="'+barW+'" height="'+iH+'" rx="2" fill="'+iC+'"/>';
|
||||
var eH=(data.e/maxY)*chartH, eY=chartTop+chartH-eH;
|
||||
var eX=xs+barW+gap;
|
||||
g.innerHTML+='<rect x="'+eX+'" y="'+eY+'" width="'+barW+'" height="'+eH+'" rx="2" fill="url(#eg)"/>';
|
||||
// 点击区:完整 viewBox 百分比 (0..360 宽度, 0..208 高度)
|
||||
var lpV=iX/360*100, tpV=iY/208*100, wpV=barW/360*100, hpI=iH/208*100, hpE=eH/208*100;
|
||||
var ih=document.createElement('div');ih.className='bar-hit';
|
||||
ih.style.cssText='left:'+lpV.toFixed(2)+'%;top:'+tpV.toFixed(2)+'%;width:'+wpV.toFixed(2)+'%;height:'+hpI.toFixed(2)+'%;background:'+(hl?'#5470c6':'rgba(84,112,198,0.5)');
|
||||
ih.setAttribute('data-k',k);ih.onclick=function(ev){ev.stopPropagation();var dk=this.getAttribute("data-k");selectDayFromBar(dk,"in");};ov.appendChild(ih);
|
||||
var eh=document.createElement('div');eh.className='bar-hit';
|
||||
var elpV=eX/360*100, etpV=eY/208*100; eh.style.cssText='left:'+elpV.toFixed(2)+'%;top:'+etpV.toFixed(2)+'%;width:'+wpV.toFixed(2)+'%;height:'+hpE.toFixed(2)+'%;background:rgba(250,200,88,0.5)';
|
||||
eh.setAttribute('data-k',k);eh.onclick=function(ev){ev.stopPropagation();var dk=this.getAttribute("data-k");selectDayFromBar(dk,"ex");};ov.appendChild(eh);
|
||||
}
|
||||
// X轴日期(每隔几天显示一次标签,避免拥挤)
|
||||
var step=md>20?5:md>10?3:1;
|
||||
if(d===1||d%step===0||d===md){
|
||||
var lx=xs+pairW/2;
|
||||
g.innerHTML+='<text x="'+lx+'" y="200" font-size="8" fill="#bbb" text-anchor="middle">'+currentMonth+'/'+d+'</text>';
|
||||
}
|
||||
}
|
||||
}
|
||||
function showTip(el,dl,html){
|
||||
var t=document.getElementById('tip');t.querySelector('.tip__date').textContent=dl;
|
||||
t.querySelector('.tip__body').innerHTML=html;t.style.display='block';
|
||||
t.style.left='50%';t.style.top='2px';t.style.transform='translateX(-50%) translateY(-100%)';
|
||||
setTimeout(function(){document.addEventListener('click',closeTip,{once:true});},10);
|
||||
}
|
||||
function closeTip(e){if(!e.target.closest('.bar-hit')&&!e.target.closest('.tip'))document.getElementById('tip').style.display='none';}
|
||||
function showTipIn(el){
|
||||
var k=el.getAttribute('data-k'),data=dayData[k];if(!data)return;
|
||||
var p=k.split('-');
|
||||
showTip(el,p[0]+'年'+(+p[1])+'月'+(+p[2])+'日',
|
||||
'<div class="tip__div"></div>'+
|
||||
'<div class="tip__row"><span class="tip__lbl">碳水</span><span class="tip__val tip__val--b">'+data.c+' 千卡</span></div>'+
|
||||
'<div class="tip__row"><span class="tip__lbl">脂肪</span><span class="tip__val tip__val--b">'+data.f+' 千卡</span></div>'+
|
||||
'<div class="tip__row"><span class="tip__lbl">蛋白质</span><span class="tip__val tip__val--b">'+data.p+' 千卡</span></div>'+
|
||||
'<div class="tip__div"></div>'+
|
||||
'<div class="tip__row"><span class="tip__lbl">早餐</span><span class="tip__val">'+data.bf+' 千卡</span></div>'+
|
||||
'<div class="tip__row"><span class="tip__lbl">午餐</span><span class="tip__val">'+data.l+' 千卡</span></div>'+
|
||||
'<div class="tip__row"><span class="tip__lbl">晚餐</span><span class="tip__val">'+data.dn+' 千卡</span></div>');
|
||||
}
|
||||
function showTipEx(el){
|
||||
var k=el.getAttribute('data-k'),data=dayData[k];if(!data)return;
|
||||
var p=k.split('-');
|
||||
showTip(el,p[0]+'年'+(+p[1])+'月'+(+p[2])+'日',
|
||||
'<div class="tip__div"></div>'+
|
||||
'<div class="tip__row"><span class="tip__lbl">基础代谢</span><span class="tip__val tip__val--y">'+data.ba+' 千卡</span></div>'+
|
||||
'<div class="tip__row"><span class="tip__lbl">运动消耗</span><span class="tip__val tip__val--y">'+data.s+' 千卡</span></div>'+
|
||||
'<div class="tip__row"><span class="tip__lbl">步行消耗</span><span class="tip__val tip__val--y">'+data.w+' 千卡</span></div>');
|
||||
}
|
||||
renderCal();renderBars();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,103 +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: #eafaf7; 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: transparent; }
|
||||
.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: transparent; display: flex; align-items: center; padding: 0 16px; flex-shrink: 0; }
|
||||
.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: 700; color: #1a1a1a; margin-right: 28px; }
|
||||
.scroll-content { flex: 1; overflow-y: auto; background: #eafaf7; padding: 4px 16px 24px; }
|
||||
.scroll-content::-webkit-scrollbar { display: none; }
|
||||
|
||||
/* 禁忌证条目 */
|
||||
.contra-item { background: #fff; border: 1px solid #b6e7df; border-radius: 14px; padding: 14px 14px 14px 44px; margin-bottom: 12px; position: relative; min-height: 56px; display: flex; align-items: center; }
|
||||
.contra-item__index { position: absolute; left: -2px; top: 50%; transform: translateY(-50%); width: 26px; height: 26px; border-radius: 50%; background: #fff; border: 1px solid #b6e7df; display: flex; align-items: center; justify-content: center; font-size: 12px; font-weight: 600; color: #1f9d8f; }
|
||||
.contra-item__text { font-size: 14px; color: #2bb8a6; line-height: 1.7; word-break: break-word; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="phone-shell">
|
||||
<div class="status-bar">
|
||||
<span class="time">13:36</span>
|
||||
<div class="icons">
|
||||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="#333" stroke-width="2"><path d="M1 6l5 5 5-5"/><path d="M4 9l3 3 3-3" opacity="0.5"/></svg>
|
||||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="#333" stroke-width="2"><rect x="1" y="6" width="18" height="12" rx="2"/><path d="M21 10v4"/></svg>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 顶部导航 -->
|
||||
<div class="nav-bar">
|
||||
<div class="nav-back" onclick="history.back()">
|
||||
<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"/></svg>
|
||||
</div>
|
||||
<div class="nav-title">禁忌证</div>
|
||||
</div>
|
||||
|
||||
<div class="scroll-content">
|
||||
<div class="contra-item">
|
||||
<span class="contra-item__index">1</span>
|
||||
<span class="contra-item__text">静息心电图有明显的缺血表现、2周内有心肌梗死或者其他急性心血管事件;</span>
|
||||
</div>
|
||||
<div class="contra-item">
|
||||
<span class="contra-item__index">2</span>
|
||||
<span class="contra-item__text">不稳定型心绞痛;</span>
|
||||
</div>
|
||||
<div class="contra-item">
|
||||
<span class="contra-item__index">3</span>
|
||||
<span class="contra-item__text">未控制的心律失常;</span>
|
||||
</div>
|
||||
<div class="contra-item">
|
||||
<span class="contra-item__index">4</span>
|
||||
<span class="contra-item__text">重度主动脉瓣狭窄或者其他瓣膜疾病;</span>
|
||||
</div>
|
||||
<div class="contra-item">
|
||||
<span class="contra-item__index">5</span>
|
||||
<span class="contra-item__text">心力衰竭失代偿;</span>
|
||||
</div>
|
||||
<div class="contra-item">
|
||||
<span class="contra-item__index">6</span>
|
||||
<span class="contra-item__text">急性肺栓塞或肺梗死;</span>
|
||||
</div>
|
||||
<div class="contra-item">
|
||||
<span class="contra-item__index">7</span>
|
||||
<span class="contra-item__text">急性甲状腺功能亢进;</span>
|
||||
</div>
|
||||
<div class="contra-item">
|
||||
<span class="contra-item__index">8</span>
|
||||
<span class="contra-item__text">急性心肌炎或心包炎;</span>
|
||||
</div>
|
||||
<div class="contra-item">
|
||||
<span class="contra-item__index">9</span>
|
||||
<span class="contra-item__text">急性血栓性静脉炎;</span>
|
||||
</div>
|
||||
<div class="contra-item">
|
||||
<span class="contra-item__index">10</span>
|
||||
<span class="contra-item__text">其他妨碍安全和运动锻炼的残疾;</span>
|
||||
</div>
|
||||
<div class="contra-item">
|
||||
<span class="contra-item__index">11</span>
|
||||
<span class="contra-item__text">电解质异常;</span>
|
||||
</div>
|
||||
<div class="contra-item">
|
||||
<span class="contra-item__index">12</span>
|
||||
<span class="contra-item__text">梗阻性肥厚型心脏病,静息最大左心室流出道压差 >25mmHg;</span>
|
||||
</div>
|
||||
<div class="contra-item">
|
||||
<span class="contra-item__index">13</span>
|
||||
<span class="contra-item__text">主动脉夹层;</span>
|
||||
</div>
|
||||
<div class="contra-item">
|
||||
<span class="contra-item__index">14</span>
|
||||
<span class="contra-item__text">经专业人员检查确定不适合参加体重管理的其他禁忌证等。</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,518 +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: 28px; flex-shrink: 0; }
|
||||
.scroll-content { flex: 1; overflow-y: auto; background: #f5f7fa; }
|
||||
.scroll-content::-webkit-scrollbar { display: none; }
|
||||
|
||||
/* ===== 日历月导航 ===== */
|
||||
.cal-nav { display: flex; align-items: center; justify-content: space-between; padding: 8px 16px; background: #fff; }
|
||||
.cal-nav__arrow { width: 30px; height: 30px; border-radius: 50%; background: #f5f7fa; display: flex; align-items: center; justify-content: center; cursor: pointer; border: none; flex-shrink: 0; }
|
||||
.cal-nav__arrow svg { width: 14px; height: 14px; stroke: #333; }
|
||||
.cal-nav__month { font-size: 15px; font-weight: 700; color: #1a1a1a; flex: 1; text-align: center; }
|
||||
.cal-nav__toggle { font-size: 12px; color: #1890ff; cursor: pointer; font-weight: 600; padding: 4px 10px; border-radius: 12px; background: #e6f7ff; flex-shrink: 0; white-space: nowrap; }
|
||||
|
||||
/* ===== 周日历(默认视图) ===== */
|
||||
.week-cal { background: #fff; padding: 0 10px 10px; margin: 0 12px; border-radius: 0 0 16px 16px; box-shadow: 0 4px 14px rgba(0,0,0,0.04); }
|
||||
.week-cal__row { display: flex; gap: 2px; }
|
||||
.week-cal__cell { flex: 1; text-align: center; padding: 8px 0 6px; border-radius: 10px; position: relative; cursor: default; min-width: 0; }
|
||||
.week-cal__cell.today { background: #e8f8f7; }
|
||||
.week-cal__cell.selected { background: #e6f7ff; box-shadow: inset 0 0 0 2px #1890ff; }
|
||||
.week-cal__wd { font-size: 10px; color: #999; margin-bottom: 4px; }
|
||||
.week-cal__date-wrap { position: relative; display: inline-flex; align-items: center; justify-content: center; width: 32px; height: 32px; margin: 0 auto 4px; }
|
||||
.week-cal__date { font-size: 14px; font-weight: 700; color: #333; position: relative; z-index: 2; }
|
||||
.week-cal__cell.today .week-cal__date { color: #36cfc9; }
|
||||
.week-cal__ring { position: absolute; inset: -2px; border-radius: 50%; border: 2.5px solid transparent; z-index: 1; }
|
||||
.week-cal__ring--auto { border-color: #1890ff; }
|
||||
.week-cal__ring--manual { border-color: #fa8c16; }
|
||||
.week-cal__ring--mixed { border-color: #722ed1; }
|
||||
.week-cal__dot-row { display: flex; justify-content: center; gap: 3px; margin-top: 2px; }
|
||||
.week-cal__dot { width: 5px; height: 5px; border-radius: 50%; flex-shrink: 0; }
|
||||
.week-cal__dot--auto { background: #1890ff; }
|
||||
.week-cal__dot--manual { background: #fa8c16; }
|
||||
.week-cal__dot--mixed { background: #722ed1; }
|
||||
/* 日历摄入千卡数据 */
|
||||
.week-cal__data { font-size: 10px; color: #666; line-height: 1.4; margin-top: 2px; }
|
||||
.week-cal__data .w { font-weight: 700; color: #333; }
|
||||
|
||||
/* ===== 月日历(展开视图) ===== */
|
||||
.month-cal { background: #fff; padding: 0 10px 10px; margin: 0 12px; border-radius: 0 0 16px 16px; box-shadow: 0 4px 14px rgba(0,0,0,0.04); }
|
||||
.month-cal__weekday { display: grid; grid-template-columns: repeat(7, 1fr); margin-bottom: 2px; }
|
||||
.month-cal__weekday span { font-size: 10px; color: #999; text-align: center; padding: 4px 0; }
|
||||
.month-cal__row { display: grid; grid-template-columns: repeat(7, 1fr); }
|
||||
.month-cal__cell { text-align: center; padding: 2px 1px 4px; min-height: 46px; position: relative; display: flex; flex-direction: column; align-items: center; justify-content: flex-start; border-radius: 8px; cursor: default; }
|
||||
.month-cal__cell.today { background: #e8f8f7; }
|
||||
.month-cal__cell.selected { background: #e6f7ff; box-shadow: inset 0 0 0 2px #1890ff; }
|
||||
.month-cal__cell.other-month .month-cal__date { color: #ddd; }
|
||||
.month-cal__date { font-size: 13px; font-weight: 600; color: #333; position: relative; z-index: 2; }
|
||||
.month-cal__cell.today .month-cal__date { color: #36cfc9; font-weight: 800; }
|
||||
.month-cal__ring { position: absolute; top: 2px; left: 50%; transform: translateX(-50%); width: 26px; height: 26px; border-radius: 50%; border: 2px solid transparent; }
|
||||
.month-cal__ring--auto { border-color: #1890ff; }
|
||||
.month-cal__ring--manual { border-color: #fa8c16; }
|
||||
.month-cal__ring--mixed { border-color: #722ed1; }
|
||||
.month-cal__dots { display: flex; justify-content: center; gap: 2px; margin-top: 1px; }
|
||||
.month-cal__dot { width: 4px; height: 4px; border-radius: 50%; flex-shrink: 0; }
|
||||
/* 月历摄入千卡数据 */
|
||||
.month-cal__data { font-size: 9px; color: #666; line-height: 1.3; margin-top: 1px; }
|
||||
.month-cal__data .mw { font-weight: 700; color: #333; }
|
||||
.month-cal__dot--auto { background: #1890ff; }
|
||||
.month-cal__dot--manual { background: #fa8c16; }
|
||||
.month-cal__dot--mixed { background: #722ed1; }
|
||||
|
||||
/* ===== 图例 ===== */
|
||||
.legend { display: flex; justify-content: center; gap: 14px; padding: 8px 16px; flex-wrap: wrap; background: #fff; margin: 8px 12px 0; border-radius: 12px; }
|
||||
.legend__item { display: flex; align-items: center; gap: 4px; font-size: 11px; color: #666; }
|
||||
.legend__dot { width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0; }
|
||||
.legend__dot--auto { background: #1890ff; }
|
||||
.legend__dot--manual { background: #fa8c16; }
|
||||
.legend__dot--mixed { background: #722ed1; }
|
||||
|
||||
/* ===== Tab 栏 ===== */
|
||||
.record-tabs { display: flex; background: #fff; margin: 8px 12px 0; border-radius: 12px; overflow: hidden; }
|
||||
.record-tab { flex: 1; text-align: center; padding: 10px 0; font-size: 13px; font-weight: 600; color: #999; cursor: pointer; position: relative; }
|
||||
.record-tab.active { color: #1890ff; }
|
||||
.record-tab.active::after { content: ''; position: absolute; bottom: 4px; left: 50%; transform: translateX(-50%); width: 20px; height: 3px; background: #1890ff; border-radius: 2px; }
|
||||
|
||||
/* ===== 列表区域 ===== */
|
||||
.record-list { padding: 8px 12px 16px; display: flex; flex-direction: column; gap: 8px; }
|
||||
.record-item { background: #fff; border-radius: 14px; padding: 14px; box-shadow: 0 2px 8px rgba(0,0,0,0.03); }
|
||||
.record-item__header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 10px; }
|
||||
.record-item__title { font-size: 14px; font-weight: 700; color: #1a1a1a; }
|
||||
.record-item__time { font-size: 11px; color: #bbb; }
|
||||
.record-item__body { display: flex; align-items: center; gap: 16px; }
|
||||
.record-item__metric { text-align: center; min-width: 50px; }
|
||||
.record-item__metric-label { font-size: 10px; color: #999; margin-bottom: 2px; }
|
||||
.record-item__metric-val { font-size: 16px; font-weight: 700; color: #1a1a1a; }
|
||||
.record-item__metric-unit { font-size: 10px; color: #999; font-weight: 400; margin-left: 1px; }
|
||||
.record-item__source { margin-left: auto; }
|
||||
.source-badge { display: inline-block; padding: 4px 10px; border-radius: 12px; font-size: 11px; font-weight: 600; }
|
||||
.source-badge--auto { background: #e6f7ff; color: #1890ff; }
|
||||
.source-badge--manual { background: #fff7e6; color: #fa8c16; }
|
||||
.source-badge--mixed { background: #f9f0ff; color: #722ed1; }
|
||||
|
||||
.record-empty { text-align: center; padding: 40px 20px; color: #ccc; font-size: 14px; }
|
||||
|
||||
.bottom-safe { height: 20px; flex-shrink: 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" onclick="location.href='eat-checkin.html'">
|
||||
<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"/></svg>
|
||||
</div>
|
||||
<div class="nav-title">摄入记录</div>
|
||||
<div class="nav-placeholder"></div>
|
||||
</div>
|
||||
<div class="scroll-content">
|
||||
|
||||
<!-- 日历月导航 -->
|
||||
<div class="cal-nav">
|
||||
<div class="cal-nav__arrow" onclick="prevMonth()">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="15 18 9 12 15 6"/></svg>
|
||||
</div>
|
||||
<div class="cal-nav__month" id="calMonthLabel">2026年06月</div>
|
||||
<div class="cal-nav__arrow" onclick="nextMonth()">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="9 18 15 12 9 6"/></svg>
|
||||
</div>
|
||||
<div class="cal-nav__toggle" id="calToggle" onclick="toggleCalView()">展开月历</div>
|
||||
</div>
|
||||
|
||||
<!-- 周日历(默认) -->
|
||||
<div class="week-cal" id="weekCal"></div>
|
||||
|
||||
<!-- 月日历(展开后显示) -->
|
||||
<div class="month-cal" id="monthCal" style="display:none;"></div>
|
||||
|
||||
<!-- 图例 -->
|
||||
<div class="legend">
|
||||
<div class="legend__item"><span class="legend__dot legend__dot--auto"></span>智记餐</div>
|
||||
<div class="legend__item"><span class="legend__dot legend__dot--manual"></span>自记餐</div>
|
||||
<div class="legend__item"><span class="legend__dot legend__dot--mixed"></span>智记+自记餐</div>
|
||||
</div>
|
||||
|
||||
<!-- Tab 栏 -->
|
||||
<div class="record-tabs" id="recordTabs">
|
||||
<div class="record-tab active" data-range="week" onclick="switchTab('week')">周</div>
|
||||
<div class="record-tab" data-range="month" onclick="switchTab('month')">月</div>
|
||||
<div class="record-tab" data-range="quarter" onclick="switchTab('quarter')">季</div>
|
||||
<div class="record-tab" data-range="activity" onclick="switchTab('activity')">活动期间</div>
|
||||
<div class="record-tab" data-range="all" onclick="switchTab('all')">全部</div>
|
||||
</div>
|
||||
|
||||
<!-- 记录列表 -->
|
||||
<div class="record-list" id="recordList"></div>
|
||||
|
||||
<div class="bottom-safe"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
/* ===== 来源类型 ===== */
|
||||
var SOURCE_TYPES = {
|
||||
'auto': { label:'智记餐', css:'auto', ring:'week-cal__ring--auto', mring:'month-cal__ring--auto', dot:'week-cal__dot--auto', mdot:'month-cal__dot--auto', badge:'source-badge--auto' },
|
||||
'manual': { label:'自记餐', css:'manual', ring:'week-cal__ring--manual', mring:'month-cal__ring--manual', dot:'week-cal__dot--manual', mdot:'month-cal__dot--manual', badge:'source-badge--manual' },
|
||||
'mixed': { label:'智记+自记餐', css:'mixed', ring:'week-cal__ring--mixed', mring:'month-cal__ring--mixed', dot:'week-cal__dot--mixed', mdot:'month-cal__dot--mixed', badge:'source-badge--mixed' }
|
||||
};
|
||||
|
||||
/* ===== 摄入记录数据 ===== */
|
||||
var MEAL_NAMES = { breakfast:'早餐', lunch:'午餐', dinner:'晚餐', snack:'加餐' };
|
||||
var RECORDS = [
|
||||
{ date:'2026-06-13', meal:'breakfast', kcal:312, time:'07:45', source:'manual' },
|
||||
{ date:'2026-06-13', meal:'lunch', kcal:480, time:'12:10', source:'auto' },
|
||||
{ date:'2026-06-13', meal:'dinner', kcal:420, time:'18:30', source:'mixed' },
|
||||
{ date:'2026-06-12', meal:'breakfast', kcal:300, time:'07:30', source:'manual' },
|
||||
{ date:'2026-06-12', meal:'lunch', kcal:475, time:'12:05', source:'auto' },
|
||||
{ date:'2026-06-12', meal:'dinner', kcal:306, time:'18:15', source:'manual' },
|
||||
{ date:'2026-06-10', meal:'breakfast', kcal:280, time:'07:50', source:'mixed' },
|
||||
{ date:'2026-06-10', meal:'lunch', kcal:520, time:'11:55', source:'auto' },
|
||||
{ date:'2026-06-10', meal:'dinner', kcal:350, time:'18:40', source:'manual' },
|
||||
{ date:'2026-06-08', meal:'breakfast', kcal:295, time:'07:20', source:'auto' },
|
||||
{ date:'2026-06-08', meal:'lunch', kcal:488, time:'12:15', source:'auto' },
|
||||
{ date:'2026-06-08', meal:'dinner', kcal:380, time:'18:20', source:'mixed' },
|
||||
{ date:'2026-06-07', meal:'breakfast', kcal:260, time:'08:00', source:'manual' },
|
||||
{ date:'2026-06-07', meal:'lunch', kcal:505, time:'12:00', source:'auto' },
|
||||
{ date:'2026-06-05', meal:'dinner', kcal:400, time:'18:35', source:'manual' },
|
||||
{ date:'2026-06-03', meal:'breakfast', kcal:310, time:'07:15', source:'mixed' },
|
||||
{ date:'2026-06-03', meal:'lunch', kcal:460, time:'12:20', source:'auto' },
|
||||
{ date:'2026-06-01', meal:'lunch', kcal:495, time:'12:08', source:'auto' },
|
||||
{ date:'2026-06-01', meal:'dinner', kcal:370, time:'18:25', source:'manual' },
|
||||
{ date:'2026-05-28', meal:'breakfast', kcal:275, time:'07:40', source:'auto' },
|
||||
{ date:'2026-05-28', meal:'lunch', kcal:510, time:'12:03', source:'mixed' },
|
||||
{ date:'2026-05-25', meal:'dinner', kcal:430, time:'18:30', source:'manual' },
|
||||
{ date:'2026-05-20', meal:'breakfast', kcal:290, time:'07:35', source:'manual' },
|
||||
{ date:'2026-05-20', meal:'lunch', kcal:485, time:'12:10', source:'auto' },
|
||||
{ date:'2026-05-15', meal:'lunch', kcal:500, time:'11:50', source:'auto' },
|
||||
{ date:'2026-05-15', meal:'dinner', kcal:360, time:'18:45', source:'mixed' },
|
||||
{ date:'2026-05-10', meal:'breakfast', kcal:285, time:'07:25', source:'auto' },
|
||||
{ date:'2026-05-10', meal:'dinner', kcal:410, time:'18:15', source:'manual' },
|
||||
{ date:'2026-05-05', meal:'lunch', kcal:470, time:'12:05', source:'mixed' },
|
||||
{ date:'2026-05-01', meal:'breakfast', kcal:305, time:'07:30', source:'manual' },
|
||||
{ date:'2026-04-25', meal:'lunch', kcal:492, time:'12:12', source:'auto' },
|
||||
{ date:'2026-04-20', meal:'dinner', kcal:385, time:'18:20', source:'mixed' },
|
||||
];
|
||||
|
||||
/* ===== 状态 ===== */
|
||||
var calYear = 2026;
|
||||
var calMonth = 5; // 0-based, 5=June
|
||||
var calExpanded = false;
|
||||
var activeTab = 'week';
|
||||
var selectedDate = null;
|
||||
|
||||
var TODAY = new Date(2026, 5, 12); // 2026-06-12
|
||||
var ACTIVITY_START = new Date(2026, 4, 1); // 2026-05-01
|
||||
var ACTIVITY_END = new Date(2026, 7, 1); // 2026-08-01
|
||||
|
||||
/* ===== 工具函数 ===== */
|
||||
function fmt(n) { return n < 10 ? '0' + n : '' + n; }
|
||||
function dateStr(y, m, d) { return y + '-' + fmt(m+1) + '-' + fmt(d); }
|
||||
function parseDate(s) { var p = s.split('-'); return new Date(+p[0], +p[1]-1, +p[2]); }
|
||||
function sameDay(a, b) { return a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth() && a.getDate() === b.getDate(); }
|
||||
|
||||
/* 获取某天的记录列表,返回各来源类型集合 */
|
||||
function getDaySources(y, m, d) {
|
||||
var s = dateStr(y, m, d);
|
||||
var sources = {};
|
||||
for (var i = 0; i < RECORDS.length; i++) {
|
||||
if (RECORDS[i].date === s) {
|
||||
sources[RECORDS[i].source] = true;
|
||||
}
|
||||
}
|
||||
return Object.keys(sources);
|
||||
}
|
||||
|
||||
/* 获取某天的总摄入千卡 */
|
||||
function getDayKcal(y, m, d) {
|
||||
var s = dateStr(y, m, d);
|
||||
var total = 0;
|
||||
for (var i = 0; i < RECORDS.length; i++) {
|
||||
if (RECORDS[i].date === s) {
|
||||
total += RECORDS[i].kcal;
|
||||
}
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
/* ===== 周日历 ===== */
|
||||
var WEEKDAY_LABELS = ['一','二','三','四','五','六','日'];
|
||||
|
||||
function getWeekStart() {
|
||||
var first = new Date(calYear, calMonth, 1);
|
||||
var day = first.getDay();
|
||||
var monday = new Date(first);
|
||||
monday.setDate(1 - (day === 0 ? 6 : day - 1));
|
||||
return monday;
|
||||
}
|
||||
|
||||
function renderWeekCal() {
|
||||
var container = document.getElementById('weekCal');
|
||||
var now = new Date(2026, 5, 12);
|
||||
var start;
|
||||
if (calYear === now.getFullYear() && calMonth === now.getMonth()) {
|
||||
var dow = now.getDay() || 7;
|
||||
start = new Date(now);
|
||||
start.setDate(now.getDate() - dow + 1);
|
||||
} else {
|
||||
start = getWeekStart();
|
||||
}
|
||||
|
||||
var html = '<div class="week-cal__row">';
|
||||
for (var i = 0; i < 7; i++) {
|
||||
var d = new Date(start);
|
||||
d.setDate(start.getDate() + i);
|
||||
var sources = getDaySources(d.getFullYear(), d.getMonth(), d.getDate());
|
||||
var hasRecord = sources.length > 0;
|
||||
var isToday = sameDay(d, TODAY);
|
||||
var isOtherMonth = d.getMonth() !== calMonth;
|
||||
var dateKey = dateStr(d.getFullYear(), d.getMonth(), d.getDate());
|
||||
var isSel = dateKey === selectedDate;
|
||||
// 取第一个来源类型作为环色(有多个时显示第一个,并用点补充)
|
||||
var primarySource = sources[0] || null;
|
||||
|
||||
html += '<div class="week-cal__cell' + (isToday ? ' today' : '') + (isSel ? ' selected' : '') + '"'
|
||||
+ ' onclick="onDayClick(\'' + dateKey + '\')" style="cursor:' + (hasRecord ? 'pointer' : 'default') + '">';
|
||||
html += '<div class="week-cal__wd">' + WEEKDAY_LABELS[i] + '</div>';
|
||||
html += '<div class="week-cal__date-wrap">';
|
||||
if (primarySource) {
|
||||
html += '<div class="week-cal__ring ' + SOURCE_TYPES[primarySource].ring + '"></div>';
|
||||
}
|
||||
html += '<span class="week-cal__date" style="' + (isOtherMonth ? 'color:#ddd' : '') + '">' + (isToday ? '今' : d.getDate()) + '</span>';
|
||||
html += '</div>';
|
||||
var dayKcal = getDayKcal(d.getFullYear(), d.getMonth(), d.getDate());
|
||||
if (dayKcal > 0) {
|
||||
html += '<div class="week-cal__data"><span class="w">' + dayKcal + '</span>千卡</div>';
|
||||
}
|
||||
html += '</div>';
|
||||
}
|
||||
html += '</div>';
|
||||
container.innerHTML = html;
|
||||
}
|
||||
|
||||
/* ===== 月日历 ===== */
|
||||
function renderMonthCal() {
|
||||
var container = document.getElementById('monthCal');
|
||||
var html = '<div class="month-cal__weekday">';
|
||||
for (var w = 0; w < 7; w++) { html += '<span>' + WEEKDAY_LABELS[w] + '</span>'; }
|
||||
html += '</div>';
|
||||
|
||||
var first = new Date(calYear, calMonth, 1);
|
||||
var startDow = first.getDay() || 7;
|
||||
var cursor = new Date(first);
|
||||
cursor.setDate(1 - (startDow - 1));
|
||||
|
||||
var done = false;
|
||||
for (var row = 0; row < 6 && !done; row++) {
|
||||
html += '<div class="month-cal__row">';
|
||||
for (var col = 0; col < 7; col++) {
|
||||
var isOther = cursor.getMonth() !== calMonth;
|
||||
var isToday = sameDay(cursor, TODAY);
|
||||
var dateKey = dateStr(cursor.getFullYear(), cursor.getMonth(), cursor.getDate());
|
||||
var isSel = dateKey === selectedDate;
|
||||
var sources = getDaySources(cursor.getFullYear(), cursor.getMonth(), cursor.getDate());
|
||||
var primarySource = sources[0] || null;
|
||||
|
||||
html += '<div class="month-cal__cell' + (isToday ? ' today' : '') + (isOther ? ' other-month' : '') + (isSel ? ' selected' : '') + '"'
|
||||
+ ' onclick="onDayClick(\'' + dateKey + '\')" style="cursor:' + (sources.length ? 'pointer' : 'default') + '">';
|
||||
html += '<div style="position:relative;width:26px;height:26px;">';
|
||||
if (primarySource) {
|
||||
html += '<div class="month-cal__ring ' + SOURCE_TYPES[primarySource].mring + '"></div>';
|
||||
}
|
||||
html += '<span class="month-cal__date">' + (isToday ? '今' : cursor.getDate()) + '</span>';
|
||||
html += '</div>';
|
||||
var mKcal = getDayKcal(cursor.getFullYear(), cursor.getMonth(), cursor.getDate());
|
||||
if (mKcal > 0) {
|
||||
html += '<div class="month-cal__data"><span class="mw">' + mKcal + '</span>千卡</div>';
|
||||
}
|
||||
html += '</div>';
|
||||
|
||||
cursor.setDate(cursor.getDate() + 1);
|
||||
if (col === 6 && cursor.getDate() > 7 && cursor.getMonth() !== calMonth) { done = true; }
|
||||
}
|
||||
html += '</div>';
|
||||
}
|
||||
container.innerHTML = html;
|
||||
}
|
||||
|
||||
/* ===== 日历展开/收起 ===== */
|
||||
function toggleCalView() {
|
||||
calExpanded = !calExpanded;
|
||||
document.getElementById('weekCal').style.display = calExpanded ? 'none' : '';
|
||||
document.getElementById('monthCal').style.display = calExpanded ? '' : 'none';
|
||||
document.getElementById('calToggle').textContent = calExpanded ? '收起月历' : '展开月历';
|
||||
if (calExpanded) renderMonthCal();
|
||||
}
|
||||
|
||||
function prevMonth() {
|
||||
if (calExpanded) {
|
||||
calMonth--;
|
||||
if (calMonth < 0) { calMonth = 11; calYear--; }
|
||||
} else {
|
||||
var now = new Date(2026, 5, 12);
|
||||
var dow = now.getDay() || 7;
|
||||
var curWeekStart;
|
||||
if (calYear === now.getFullYear() && calMonth === now.getMonth()) {
|
||||
curWeekStart = new Date(now);
|
||||
curWeekStart.setDate(now.getDate() - dow + 1);
|
||||
} else {
|
||||
curWeekStart = getWeekStart();
|
||||
}
|
||||
curWeekStart.setDate(curWeekStart.getDate() - 7);
|
||||
calYear = curWeekStart.getFullYear();
|
||||
calMonth = curWeekStart.getMonth();
|
||||
}
|
||||
updateCal();
|
||||
}
|
||||
|
||||
function nextMonth() {
|
||||
if (calExpanded) {
|
||||
calMonth++;
|
||||
if (calMonth > 11) { calMonth = 0; calYear++; }
|
||||
} else {
|
||||
var now = new Date(2026, 5, 12);
|
||||
var dow = now.getDay() || 7;
|
||||
var curWeekStart;
|
||||
if (calYear === now.getFullYear() && calMonth === now.getMonth()) {
|
||||
curWeekStart = new Date(now);
|
||||
curWeekStart.setDate(now.getDate() - dow + 1);
|
||||
} else {
|
||||
curWeekStart = getWeekStart();
|
||||
}
|
||||
curWeekStart.setDate(curWeekStart.getDate() + 7);
|
||||
calYear = curWeekStart.getFullYear();
|
||||
calMonth = curWeekStart.getMonth();
|
||||
}
|
||||
updateCal();
|
||||
}
|
||||
|
||||
function updateCal() {
|
||||
document.getElementById('calMonthLabel').textContent = calYear + '年' + fmt(calMonth + 1) + '月';
|
||||
renderWeekCal();
|
||||
if (calExpanded) renderMonthCal();
|
||||
}
|
||||
|
||||
/* ===== Tab 切换 ===== */
|
||||
function switchTab(range) {
|
||||
activeTab = range;
|
||||
selectedDate = null;
|
||||
document.querySelectorAll('.record-tab').forEach(function(t) {
|
||||
t.classList.toggle('active', t.dataset.range === range);
|
||||
});
|
||||
updateCal();
|
||||
renderRecordList();
|
||||
}
|
||||
|
||||
function getTabDateRange() {
|
||||
var now = new Date(2026, 5, 12);
|
||||
var start, end;
|
||||
switch (activeTab) {
|
||||
case 'week':
|
||||
var dow = now.getDay() || 7;
|
||||
start = new Date(now); start.setDate(now.getDate() - dow + 1);
|
||||
end = new Date(start); end.setDate(start.getDate() + 6);
|
||||
break;
|
||||
case 'month':
|
||||
start = new Date(now.getFullYear(), now.getMonth(), 1);
|
||||
end = new Date(now.getFullYear(), now.getMonth() + 1, 0);
|
||||
break;
|
||||
case 'quarter':
|
||||
var q = Math.floor(now.getMonth() / 3);
|
||||
start = new Date(now.getFullYear(), q * 3, 1);
|
||||
end = new Date(now.getFullYear(), (q + 1) * 3, 0);
|
||||
break;
|
||||
case 'activity':
|
||||
start = ACTIVITY_START;
|
||||
end = ACTIVITY_END;
|
||||
break;
|
||||
case 'all':
|
||||
start = new Date(2000, 0, 1);
|
||||
end = new Date(2099, 11, 31);
|
||||
break;
|
||||
}
|
||||
return { start: start, end: end };
|
||||
}
|
||||
|
||||
/* ===== 渲染记录列表 ===== */
|
||||
function renderRecordList() {
|
||||
var filtered;
|
||||
if (selectedDate) {
|
||||
filtered = RECORDS.filter(function(r) { return r.date === selectedDate; });
|
||||
} else {
|
||||
var range = getTabDateRange();
|
||||
filtered = RECORDS.filter(function(r) {
|
||||
var d = parseDate(r.date);
|
||||
return d >= range.start && d <= range.end;
|
||||
});
|
||||
}
|
||||
|
||||
var container = document.getElementById('recordList');
|
||||
if (filtered.length === 0) {
|
||||
container.innerHTML = '<div class="record-empty">该时间段暂无记录</div>';
|
||||
return;
|
||||
}
|
||||
|
||||
var html = '';
|
||||
for (var i = 0; i < filtered.length; i++) {
|
||||
var r = filtered[i];
|
||||
var src = SOURCE_TYPES[r.source];
|
||||
html += '<div class="record-item">';
|
||||
html += '<div class="record-item__header">';
|
||||
html += '<span class="record-item__title">' + MEAL_NAMES[r.meal] + '记录</span>';
|
||||
html += '<span class="record-item__time">' + r.date + ' ' + r.time + '</span>';
|
||||
html += '</div>';
|
||||
html += '<div class="record-item__body">';
|
||||
html += '<div class="record-item__metric"><div class="record-item__metric-label">摄入热量</div><div class="record-item__metric-val">' + r.kcal + '<span class="record-item__metric-unit">千卡</span></div></div>';
|
||||
html += '<div class="record-item__source"><span class="source-badge ' + src.badge + '">' + src.label + '</span></div>';
|
||||
html += '</div>';
|
||||
html += '</div>';
|
||||
}
|
||||
container.innerHTML = html;
|
||||
}
|
||||
|
||||
/* ===== 点击日期 ===== */
|
||||
function onDayClick(dateStr) {
|
||||
if (selectedDate === dateStr) {
|
||||
switchTab('week');
|
||||
return;
|
||||
}
|
||||
selectedDate = dateStr;
|
||||
activeTab = '';
|
||||
document.querySelectorAll('.record-tab').forEach(function(t) { t.classList.remove('active'); });
|
||||
updateCal();
|
||||
renderRecordList();
|
||||
document.querySelector('.scroll-content').scrollTop = document.getElementById('recordTabs').offsetTop - 100;
|
||||
}
|
||||
|
||||
/* ===== 初始化 ===== */
|
||||
function init() {
|
||||
calYear = TODAY.getFullYear();
|
||||
calMonth = TODAY.getMonth();
|
||||
document.getElementById('calMonthLabel').textContent = calYear + '年' + fmt(calMonth + 1) + '月';
|
||||
renderWeekCal();
|
||||
renderRecordList();
|
||||
}
|
||||
init();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,375 +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: 28px; flex-shrink: 0; }
|
||||
.scroll-content { flex: 1; overflow-y: auto; background: #f5f7fa; }
|
||||
.scroll-content::-webkit-scrollbar { display: none; }
|
||||
|
||||
/* ===== 每日推荐消耗卡片 ===== */
|
||||
.calorie-burn {
|
||||
background: linear-gradient(145deg, #ff9a56 0%, #ff6b35 60%, #e55a2b 100%);
|
||||
margin: 16px 12px 0;
|
||||
border-radius: 20px;
|
||||
padding: 20px 18px 16px;
|
||||
color: #fff;
|
||||
position: relative; overflow: hidden;
|
||||
box-shadow: 0 6px 20px rgba(255,107,53,0.3);
|
||||
}
|
||||
.calorie-burn::before {
|
||||
content: '';
|
||||
position: absolute; top: -40px; right: -30px;
|
||||
width: 140px; height: 140px;
|
||||
border-radius: 50%;
|
||||
background: rgba(255,255,255,0.06);
|
||||
pointer-events: none;
|
||||
}
|
||||
.calorie-burn::after {
|
||||
content: '';
|
||||
position: absolute; bottom: -50px; left: -20px;
|
||||
width: 120px; height: 120px;
|
||||
border-radius: 50%;
|
||||
background: rgba(255,255,255,0.04);
|
||||
pointer-events: none;
|
||||
}
|
||||
.calorie-burn__header {
|
||||
display: flex; align-items: center; justify-content: space-between;
|
||||
position: relative; z-index: 1;
|
||||
}
|
||||
.calorie-burn__label { font-size: 13px; opacity: 0.9; font-weight: 500; letter-spacing: .3px; }
|
||||
.calorie-burn__bmr { font-size: 10px; opacity: 0.65; }
|
||||
.calorie-burn__val {
|
||||
font-size: 46px; font-weight: 800; line-height: 1;
|
||||
margin: 6px 0 0; position: relative; z-index: 1;
|
||||
letter-spacing: -1px;
|
||||
}
|
||||
.calorie-burn__unit { font-size: 17px; font-weight: 500; opacity: 0.75; margin-left: 2px; }
|
||||
.calorie-burn__sub {
|
||||
font-size: 11px; opacity: 0.7; margin-top: 4px;
|
||||
position: relative; z-index: 1; line-height: 1.5;
|
||||
}
|
||||
/* 三大消耗进度条 */
|
||||
.calorie-burn__bar-wrap {
|
||||
position: relative; z-index: 1; margin-top: 14px;
|
||||
display: flex; border-radius: 6px; height: 10px; overflow: hidden; gap: 3px;
|
||||
}
|
||||
.calorie-burn__bar-seg { height: 100%; position: relative; border-radius: 6px; overflow: hidden; }
|
||||
.calorie-burn__bar-seg--bmr { background: rgba(84,112,198,0.25); }
|
||||
.calorie-burn__bar-seg--sport { background: rgba(255,154,86,0.25); }
|
||||
.calorie-burn__bar-seg--walk { background: rgba(115,209,61,0.25); }
|
||||
.calorie-burn__bar-fill {
|
||||
height: 100%; border-radius: 6px;
|
||||
transition: width .5s cubic-bezier(.4,0,.2,1);
|
||||
position: absolute; left: 0; top: 0;
|
||||
}
|
||||
.calorie-burn__bar-seg--bmr .calorie-burn__bar-fill { background: #7b9af5; }
|
||||
.calorie-burn__bar-seg--sport .calorie-burn__bar-fill { background: #ffb88c; }
|
||||
.calorie-burn__bar-seg--walk .calorie-burn__bar-fill { background: #95de64; }
|
||||
.calorie-burn__bar-label {
|
||||
display: flex; justify-content: center; gap: 16px;
|
||||
font-size: 10px; margin-top: 8px; opacity: 0.8;
|
||||
position: relative; z-index: 1;
|
||||
}
|
||||
.calorie-burn__bar-legend { display: flex; align-items: center; gap: 5px; white-space: nowrap; }
|
||||
.calorie-burn__bar-legend i { display: inline-block; width: 9px; height: 9px; border-radius: 3px; flex-shrink: 0; }
|
||||
|
||||
/* ===== 运动类型推荐 ===== */
|
||||
.exer-type-card { background: #fff; border-radius: 16px; margin: 12px 12px 0; padding: 16px 14px; box-shadow: 0 4px 14px rgba(0,0,0,0.04); }
|
||||
.exer-type-card__title { font-size: 15px; font-weight: 800; color: #1a1a1a; margin-bottom: 12px; }
|
||||
.exer-type-list { display: flex; flex-direction: column; gap: 8px; }
|
||||
.exer-type-item { display: flex; align-items: center; gap: 10px; padding: 10px; background: #f9fafb; border-radius: 10px; }
|
||||
.exer-type-item__icon { width: 44px; height: 44px; border-radius: 12px; display: flex; align-items: center; justify-content: center; font-size: 22px; flex-shrink: 0; }
|
||||
.exer-type-item__icon--aerobic { background: #fff2e8; }
|
||||
.exer-type-item__icon--strength { background: #f0f5ff; }
|
||||
.exer-type-item__icon--flex { background: #f6ffed; }
|
||||
.exer-type-item__icon--balance { background: #f9f0ff; }
|
||||
.exer-type-item__info { flex: 1; min-width: 0; }
|
||||
.exer-type-item__name { font-size: 14px; font-weight: 700; color: #333; }
|
||||
.exer-type-item__desc { font-size: 11px; color: #999; margin-top: 2px; line-height: 1.4; }
|
||||
.exer-type-item__time { font-size: 12px; font-weight: 700; color: #ff8a3d; flex-shrink: 0; }
|
||||
|
||||
/* ===== 一周运动计划 ===== */
|
||||
.week-plan-card { background: #fff; border-radius: 16px; margin: 12px 12px 0; padding: 16px 14px; box-shadow: 0 4px 14px rgba(0,0,0,0.04); }
|
||||
.week-plan-card__header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 12px; }
|
||||
.week-plan-card__title { font-size: 15px; font-weight: 800; color: #1a1a1a; }
|
||||
.week-plan-card__tip { font-size: 11px; color: #bbb; }
|
||||
.week-day-row { display: flex; gap: 4px; margin-bottom: 8px; }
|
||||
.week-day { flex: 1; text-align: center; padding: 6px 0; border-radius: 8px; cursor: pointer; font-size: 11px; font-weight: 600; color: #999; background: #f7f8fa; transition: all .2s; }
|
||||
.week-day.active { background: #ff8a3d; color: #fff; }
|
||||
.week-day__label { display: block; font-size: 10px; opacity: 0.7; }
|
||||
.week-detail { padding: 10px 0 0; }
|
||||
.week-detail__total { font-size: 14px; font-weight: 800; color: #1a1a1a; margin-bottom: 8px; }
|
||||
.week-detail__total span { font-size: 11px; color: #ff8a3d; margin-left: 4px; }
|
||||
|
||||
.plan-item { display: flex; align-items: center; gap: 10px; padding: 8px 10px; background: #f9fafb; border-radius: 10px; margin-bottom: 6px; }
|
||||
.plan-item:last-child { margin-bottom: 0; }
|
||||
.plan-item__icon { width: 36px; height: 36px; border-radius: 10px; display: flex; align-items: center; justify-content: center; font-size: 18px; flex-shrink: 0; }
|
||||
.plan-item__icon--aerobic { background: #fff2e8; }
|
||||
.plan-item__icon--strength { background: #f0f5ff; }
|
||||
.plan-item__icon--flex { background: #f6ffed; }
|
||||
.plan-item__info { flex: 1; min-width: 0; }
|
||||
.plan-item__name { font-size: 13px; font-weight: 600; color: #333; }
|
||||
.plan-item__desc { font-size: 11px; color: #999; margin-top: 2px; }
|
||||
.plan-item__kcal { font-size: 12px; font-weight: 700; color: #ff8a3d; flex-shrink: 0; }
|
||||
|
||||
/* ===== 运动注意事项(可折叠) ===== */
|
||||
.alert-banner {
|
||||
background: #fff; margin: 12px 12px 0;
|
||||
border-radius: 12px; overflow: hidden;
|
||||
box-shadow: 0 1px 3px rgba(0,0,0,0.04);
|
||||
border-left: 3px solid #ff4d4f;
|
||||
}
|
||||
.alert-banner__header { display: flex; align-items: center; gap: 8px; padding: 12px 14px; cursor: pointer; user-select: none; }
|
||||
.alert-banner__icon { font-size: 18px; flex-shrink: 0; }
|
||||
.alert-banner__title { font-size: 14px; font-weight: 700; color: #1a1a1a; flex: 1; }
|
||||
.alert-banner__arrow { font-size: 12px; color: #999; transition: transform .25s ease; flex-shrink: 0; }
|
||||
.alert-banner__arrow.collapsed { transform: rotate(180deg); }
|
||||
.alert-banner__body { padding: 0 14px 14px; }
|
||||
.alert-banner__body.collapsed { display: none; }
|
||||
|
||||
.tips-list { display: flex; flex-direction: column; gap: 8px; }
|
||||
.tips-item { display: flex; align-items: flex-start; gap: 10px; padding: 10px 12px; background: #f7f8fa; border-radius: 8px; transition: background .2s ease; }
|
||||
.tips-item__icon { width: 22px; height: 22px; border-radius: 50%; display: flex; align-items: center; justify-content: center; flex-shrink: 0; font-size: 11px; font-weight: 800; color: #fff; }
|
||||
.tips-item__icon--warn { background: #faad14; }
|
||||
.tips-item__icon--good { background: #52c41a; }
|
||||
.tips-item__icon--info { background: #1677ff; }
|
||||
.tips-item__icon--danger { background: #ff4d4f; }
|
||||
.tips-item__text { font-size: 12px; color: #666; line-height: 1.65; flex: 1; }
|
||||
.tips-item__text strong { color: #333; }
|
||||
|
||||
/* ===== 保存按钮 ===== */
|
||||
.save-btn-wrap { padding: 16px 12px 12px; flex-shrink: 0; }
|
||||
.save-btn {
|
||||
width: 100%; height: 46px; border-radius: 12px; border: none;
|
||||
font-size: 15px; font-weight: 700; color: #fff; cursor: pointer;
|
||||
background: linear-gradient(135deg, #ff8a3d 0%, #e55a2b 100%);
|
||||
box-shadow: 0 4px 14px rgba(255,138,61,0.3);
|
||||
transition: all .2s ease;
|
||||
letter-spacing: .5px;
|
||||
}
|
||||
.save-btn:hover { box-shadow: 0 6px 20px rgba(255,138,61,0.4); }
|
||||
.save-btn:active { transform: scale(0.97); }
|
||||
|
||||
.bottom-safe { height: 24px; flex-shrink: 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" onclick="location.href='weight-main.html'">
|
||||
<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"/></svg>
|
||||
</div>
|
||||
<div class="nav-title">运动建议</div>
|
||||
<div class="nav-placeholder"></div>
|
||||
</div>
|
||||
<div class="scroll-content">
|
||||
|
||||
<!-- 每日推荐消耗 -->
|
||||
<div class="calorie-burn">
|
||||
<div class="calorie-burn__header">
|
||||
<span class="calorie-burn__label">每日推荐消耗</span>
|
||||
<span class="calorie-burn__bmr">基础代谢 1600千卡</span>
|
||||
</div>
|
||||
<div class="calorie-burn__val">2645<span class="calorie-burn__unit">千卡</span></div>
|
||||
<div class="calorie-burn__sub">今日已消耗 2186 千卡,还需消耗 459 千卡(热量缺口 300kcal)</div>
|
||||
<div class="calorie-burn__bar-wrap">
|
||||
<div class="calorie-burn__bar-seg calorie-burn__bar-seg--bmr" style="width:60.5%"><div class="calorie-burn__bar-fill" style="width:100%"></div></div>
|
||||
<div class="calorie-burn__bar-seg calorie-burn__bar-seg--sport" style="width:22.7%"><div class="calorie-burn__bar-fill" style="width:64.3%"></div></div>
|
||||
<div class="calorie-burn__bar-seg calorie-burn__bar-seg--walk" style="width:16.8%"><div class="calorie-burn__bar-fill" style="width:44.9%"></div></div>
|
||||
</div>
|
||||
<div class="calorie-burn__bar-label">
|
||||
<span class="calorie-burn__bar-legend"><i style="background:#7b9af5"></i>基础消耗 1600</span>
|
||||
<span class="calorie-burn__bar-legend"><i style="background:#ffb88c"></i>运动消耗 386</span>
|
||||
<span class="calorie-burn__bar-legend"><i style="background:#95de64"></i>步行消耗 200</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 运动注意事项(可折叠) -->
|
||||
<div class="alert-banner" id="alertBanner">
|
||||
<div class="alert-banner__header" onclick="toggleExerciseTips()">
|
||||
<div class="alert-banner__icon">⚠️</div>
|
||||
<div class="alert-banner__title">运动注意事项</div>
|
||||
<div class="alert-banner__arrow" id="alertArrow">▲</div>
|
||||
</div>
|
||||
<div class="alert-banner__body" id="alertBody">
|
||||
<div class="tips-list" style="margin-top:8px;">
|
||||
<div class="tips-item"><div class="tips-item__icon tips-item__icon--danger">!</div><div class="tips-item__text"><strong>高血压注意:</strong>避免憋气用力动作(如大重量举重),运动中监测心率不超过(220-年龄)×70%。首选快走、游泳、太极等中低强度有氧运动。</div></div>
|
||||
<div class="tips-item"><div class="tips-item__icon tips-item__icon--warn">!</div><div class="tips-item__text"><strong>高尿酸提醒:</strong>避免剧烈无氧运动(产生乳酸抑制尿酸排泄),运动后及时补水2000ml以上。急性发作期应暂停运动,待症状缓解后从低强度开始恢复。</div></div>
|
||||
<div class="tips-item"><div class="tips-item__icon tips-item__icon--good">✓</div><div class="tips-item__text"><strong>热身先行:</strong>运动前做5-10分钟动态热身,活动关节、提高心率,预防运动损伤。</div></div>
|
||||
<div class="tips-item"><div class="tips-item__icon tips-item__icon--warn">!</div><div class="tips-item__text"><strong>量力而行:</strong>根据自身身体状况选择运动强度,避免过度训练导致肌肉酸痛或损伤。如感到异常疲劳应适当减量。</div></div>
|
||||
<div class="tips-item"><div class="tips-item__icon tips-item__icon--info">i</div><div class="tips-item__text"><strong>补水及时:</strong>运动前中后少量多次饮水,每15-20分钟补充150-200ml水分。高尿酸者建议每日饮水2000ml以上,促进尿酸排泄。</div></div>
|
||||
<div class="tips-item"><div class="tips-item__icon tips-item__icon--good">✓</div><div class="tips-item__text"><strong>循序渐进:</strong>运动强度和时间逐步增加,每周运动量增幅不超过10%,给身体充分的适应和恢复时间。</div></div>
|
||||
<div class="tips-item"><div class="tips-item__icon tips-item__icon--danger">!</div><div class="tips-item__text"><strong>身体不适立即停止:</strong>运动中如出现胸闷、头晕、关节疼痛、呼吸困难等不适,应立即停止并就医,切勿勉强坚持。</div></div>
|
||||
<div class="tips-item"><div class="tips-item__icon tips-item__icon--info">i</div><div class="tips-item__text"><strong>拉伸放松:</strong>运动后做5-10分钟静态拉伸,每个动作保持15-30秒,帮助肌肉恢复、减少酸痛、提高柔韧性。</div></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 运动类型推荐 -->
|
||||
<div class="exer-type-card">
|
||||
<div class="exer-type-card__title">运动类型推荐</div>
|
||||
<div class="exer-type-list">
|
||||
<div class="exer-type-item">
|
||||
<div class="exer-type-item__icon exer-type-item__icon--aerobic">🏃</div>
|
||||
<div class="exer-type-item__info">
|
||||
<div class="exer-type-item__name">有氧运动</div>
|
||||
<div class="exer-type-item__desc">快走、慢跑、游泳、骑行,提升心肺功能</div>
|
||||
</div>
|
||||
<div class="exer-type-item__time">30-45分钟/天</div>
|
||||
</div>
|
||||
<div class="exer-type-item">
|
||||
<div class="exer-type-item__icon exer-type-item__icon--strength">💪</div>
|
||||
<div class="exer-type-item__info">
|
||||
<div class="exer-type-item__name">力量训练</div>
|
||||
<div class="exer-type-item__desc">深蹲、俯卧撑、哑铃推举,增肌提高代谢</div>
|
||||
</div>
|
||||
<div class="exer-type-item__time">20-30分钟/次</div>
|
||||
</div>
|
||||
<div class="exer-type-item">
|
||||
<div class="exer-type-item__icon exer-type-item__icon--flex">🧘</div>
|
||||
<div class="exer-type-item__info">
|
||||
<div class="exer-type-item__name">柔韧拉伸</div>
|
||||
<div class="exer-type-item__desc">瑜伽、动态拉伸、泡沫轴放松</div>
|
||||
</div>
|
||||
<div class="exer-type-item__time">10-15分钟/天</div>
|
||||
</div>
|
||||
<div class="exer-type-item">
|
||||
<div class="exer-type-item__icon exer-type-item__icon--balance">🚶</div>
|
||||
<div class="exer-type-item__info">
|
||||
<div class="exer-type-item__name">日常活动</div>
|
||||
<div class="exer-type-item__desc">步行通勤、爬楼梯、工间操,积少成多</div>
|
||||
</div>
|
||||
<div class="exer-type-item__time">全天累计</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 一周运动计划 -->
|
||||
<div class="week-plan-card">
|
||||
<div class="week-plan-card__header">
|
||||
<div class="week-plan-card__title">一周运动计划</div>
|
||||
<div class="week-plan-card__tip">循序渐进 科学运动</div>
|
||||
</div>
|
||||
<div class="week-day-row" id="weekDayRow">
|
||||
<div class="week-day active" data-day="0" onclick="switchWeekDay(0, this)"><span class="week-day__label">周一</span>08-10</div>
|
||||
<div class="week-day" data-day="1" onclick="switchWeekDay(1, this)"><span class="week-day__label">周二</span>08-11</div>
|
||||
<div class="week-day" data-day="2" onclick="switchWeekDay(2, this)"><span class="week-day__label">周三</span>08-12</div>
|
||||
<div class="week-day" data-day="3" onclick="switchWeekDay(3, this)"><span class="week-day__label">周四</span>08-13</div>
|
||||
<div class="week-day" data-day="4" onclick="switchWeekDay(4, this)"><span class="week-day__label">周五</span>08-14</div>
|
||||
<div class="week-day" data-day="5" onclick="switchWeekDay(5, this)"><span class="week-day__label">周六</span>08-15</div>
|
||||
<div class="week-day" data-day="6" onclick="switchWeekDay(6, this)"><span class="week-day__label">周日</span>08-16</div>
|
||||
</div>
|
||||
<div class="week-detail" id="weekDetail"></div>
|
||||
</div>
|
||||
|
||||
<div class="save-btn-wrap">
|
||||
<button class="save-btn">保存至本地</button>
|
||||
</div>
|
||||
<div class="bottom-safe"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
/* ===== 运动注意事项折叠 ===== */
|
||||
function toggleExerciseTips() {
|
||||
var body = document.getElementById('alertBody');
|
||||
var arrow = document.getElementById('alertArrow');
|
||||
if (body.classList.contains('collapsed')) {
|
||||
body.classList.remove('collapsed');
|
||||
arrow.classList.remove('collapsed');
|
||||
} else {
|
||||
body.classList.add('collapsed');
|
||||
arrow.classList.add('collapsed');
|
||||
}
|
||||
}
|
||||
|
||||
/* ===== 一周运动计划数据 ===== */
|
||||
var WEEK_PLANS = [
|
||||
{ day:'周一', date:'08-10', total:'目标消耗 980千卡', items:[
|
||||
{ icon:'🏃', cls:'aerobic', name:'户外慢跑', desc:'配速7-8min/km,时长30分钟', kcal:'320千卡' },
|
||||
{ icon:'💪', cls:'strength', name:'上肢力量', desc:'俯卧撑3组×15 + 哑铃推举3组×12', kcal:'180千卡' },
|
||||
{ icon:'🚶', cls:'flex', name:'全天步行', desc:'目标步数10000步以上', kcal:'480千卡' }
|
||||
]},
|
||||
{ day:'周二', date:'08-11', total:'目标消耗 850千卡', items:[
|
||||
{ icon:'🏊', cls:'aerobic', name:'游泳', desc:'蛙泳/自由泳交替,时长40分钟', kcal:'380千卡' },
|
||||
{ icon:'🧘', cls:'flex', name:'瑜伽拉伸', desc:'哈他瑜伽基础序列,时长20分钟', kcal:'120千卡' },
|
||||
{ icon:'🚶', cls:'flex', name:'全天步行', desc:'目标步数8000步以上', kcal:'350千卡' }
|
||||
]},
|
||||
{ day:'周三', date:'08-12', total:'目标消耗 1000千卡', items:[
|
||||
{ icon:'🚴', cls:'aerobic', name:'动感单车', desc:'中等阻力间歇骑行,时长35分钟', kcal:'400千卡' },
|
||||
{ icon:'💪', cls:'strength', name:'下肢力量', desc:'深蹲4组×15 + 弓步蹲3组×12', kcal:'220千卡' },
|
||||
{ icon:'🚶', cls:'flex', name:'全天步行', desc:'目标步数10000步以上', kcal:'380千卡' }
|
||||
]},
|
||||
{ day:'周四', date:'08-13', total:'目标消耗 780千卡', items:[
|
||||
{ icon:'🏃', cls:'aerobic', name:'快走', desc:'配速10min/km,时长40分钟', kcal:'280千卡' },
|
||||
{ icon:'🧘', cls:'flex', name:'核心训练', desc:'平板支撑+卷腹+仰卧举腿循环', kcal:'160千卡' },
|
||||
{ icon:'🚶', cls:'flex', name:'全天步行', desc:'目标步数8000步以上', kcal:'340千卡' }
|
||||
]},
|
||||
{ day:'周五', date:'08-14', total:'目标消耗 950千卡', items:[
|
||||
{ icon:'🏃', cls:'aerobic', name:'间歇跑', desc:'快跑2分钟+慢跑3分钟循环×6组', kcal:'380千卡' },
|
||||
{ icon:'💪', cls:'strength', name:'全身力量', desc:'深蹲+俯卧撑+划船循环3组', kcal:'220千卡' },
|
||||
{ icon:'🚶', cls:'flex', name:'全天步行', desc:'目标步数9000步以上', kcal:'350千卡' }
|
||||
]},
|
||||
{ day:'周六', date:'08-15', total:'目标消耗 1100千卡', items:[
|
||||
{ icon:'🏸', cls:'aerobic', name:'羽毛球/球类运动', desc:'双打/单打,时长60分钟', kcal:'500千卡' },
|
||||
{ icon:'🧘', cls:'flex', name:'运动后拉伸', desc:'全身静态拉伸,时长15分钟', kcal:'100千卡' },
|
||||
{ icon:'🚶', cls:'flex', name:'全天步行', desc:'目标步数10000步以上', kcal:'500千卡' }
|
||||
]},
|
||||
{ day:'周日', date:'08-16', total:'目标消耗 600千卡', items:[
|
||||
{ icon:'🚶', cls:'aerobic', name:'散步放松', desc:'悠闲步行,时长45分钟', kcal:'200千卡' },
|
||||
{ icon:'🧘', cls:'flex', name:'恢复拉伸', desc:'阴瑜伽 + 泡沫轴放松,时长30分钟', kcal:'100千卡' },
|
||||
{ icon:'🚶', cls:'flex', name:'全天步行', desc:'目标步数7000步以上', kcal:'300千卡' }
|
||||
]}
|
||||
];
|
||||
|
||||
/* ===== 渲染 ===== */
|
||||
var currentWeekDay = 0;
|
||||
|
||||
function renderWeekDetail(dayIdx) {
|
||||
var plan = WEEK_PLANS[dayIdx];
|
||||
var html = '<div class="week-detail__total">' + plan.day + ' ' + plan.date + '<span>' + plan.total + '</span></div>';
|
||||
for (var i = 0; i < plan.items.length; i++) {
|
||||
var it = plan.items[i];
|
||||
html += '<div class="plan-item">';
|
||||
html += '<div class="plan-item__icon plan-item__icon--' + it.cls + '">' + it.icon + '</div>';
|
||||
html += '<div class="plan-item__info"><div class="plan-item__name">' + it.name + '</div><div class="plan-item__desc">' + it.desc + '</div></div>';
|
||||
html += '<div class="plan-item__kcal">' + it.kcal + '</div>';
|
||||
html += '</div>';
|
||||
}
|
||||
document.getElementById('weekDetail').innerHTML = html;
|
||||
}
|
||||
|
||||
function switchWeekDay(dayIdx, el) {
|
||||
currentWeekDay = dayIdx;
|
||||
document.querySelectorAll('.week-day').forEach(function(d) { d.classList.remove('active'); });
|
||||
el.classList.add('active');
|
||||
renderWeekDetail(dayIdx);
|
||||
}
|
||||
|
||||
function init() {
|
||||
renderWeekDetail(0);
|
||||
}
|
||||
init();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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: 28px; flex-shrink: 0; }
|
||||
.scroll-content { flex: 1; overflow-y: auto; background: #f5f7fa; }
|
||||
.scroll-content::-webkit-scrollbar { display: none; }
|
||||
|
||||
/* ===== 日历月导航 ===== */
|
||||
.cal-nav { display: flex; align-items: center; justify-content: space-between; padding: 8px 16px; background: #fff; }
|
||||
.cal-nav__arrow { width: 30px; height: 30px; border-radius: 50%; background: #f5f7fa; display: flex; align-items: center; justify-content: center; cursor: pointer; border: none; flex-shrink: 0; }
|
||||
.cal-nav__arrow svg { width: 14px; height: 14px; stroke: #333; }
|
||||
.cal-nav__month { font-size: 15px; font-weight: 700; color: #1a1a1a; flex: 1; text-align: center; }
|
||||
.cal-nav__toggle { font-size: 12px; color: #ff8a3d; cursor: pointer; font-weight: 600; padding: 4px 10px; border-radius: 12px; background: #fff7e6; flex-shrink: 0; white-space: nowrap; }
|
||||
|
||||
/* ===== 周日历(默认视图) ===== */
|
||||
.week-cal { background: #fff; padding: 0 10px 10px; margin: 0 12px; border-radius: 0 0 16px 16px; box-shadow: 0 4px 14px rgba(0,0,0,0.04); }
|
||||
.week-cal__row { display: flex; gap: 2px; }
|
||||
.week-cal__cell { flex: 1; text-align: center; padding: 8px 0 6px; border-radius: 10px; position: relative; cursor: default; min-width: 0; }
|
||||
.week-cal__cell.today { background: #fff7e6; }
|
||||
.week-cal__cell.selected { background: #fff7e6; box-shadow: inset 0 0 0 2px #ff8a3d; }
|
||||
.week-cal__wd { font-size: 10px; color: #999; margin-bottom: 4px; }
|
||||
.week-cal__date-wrap { position: relative; display: inline-flex; align-items: center; justify-content: center; width: 32px; height: 32px; margin: 0 auto 4px; }
|
||||
.week-cal__date { font-size: 14px; font-weight: 700; color: #333; position: relative; z-index: 2; }
|
||||
.week-cal__cell.today .week-cal__date { color: #ff8a3d; }
|
||||
.week-cal__ring { position: absolute; inset: -2px; border-radius: 50%; border: 2.5px solid transparent; z-index: 1; }
|
||||
.week-cal__ring--wearable { border-color: #1890ff; }
|
||||
.week-cal__ring--equip { border-color: #52c41a; }
|
||||
.week-cal__ring--wechat { border-color: #597ef7; }
|
||||
.week-cal__ring--manual { border-color: #fa8c16; }
|
||||
.week-cal__ring--mixed { border-color: #722ed1; }
|
||||
.week-cal__dot-row { display: flex; justify-content: center; gap: 3px; margin-top: 2px; }
|
||||
.week-cal__dot { width: 5px; height: 5px; border-radius: 50%; flex-shrink: 0; }
|
||||
.week-cal__dot--wearable { background: #1890ff; }
|
||||
.week-cal__dot--equip { background: #52c41a; }
|
||||
.week-cal__dot--wechat { background: #597ef7; }
|
||||
.week-cal__dot--manual { background: #fa8c16; }
|
||||
.week-cal__dot--mixed { background: #722ed1; }
|
||||
/* 日历消耗千卡数据 */
|
||||
.week-cal__data { font-size: 10px; color: #666; line-height: 1.4; margin-top: 2px; }
|
||||
.week-cal__data .w { font-weight: 700; color: #333; }
|
||||
|
||||
/* ===== 月日历(展开视图) ===== */
|
||||
.month-cal { background: #fff; padding: 0 10px 10px; margin: 0 12px; border-radius: 0 0 16px 16px; box-shadow: 0 4px 14px rgba(0,0,0,0.04); }
|
||||
.month-cal__weekday { display: grid; grid-template-columns: repeat(7, 1fr); margin-bottom: 2px; }
|
||||
.month-cal__weekday span { font-size: 10px; color: #999; text-align: center; padding: 4px 0; }
|
||||
.month-cal__row { display: grid; grid-template-columns: repeat(7, 1fr); }
|
||||
.month-cal__cell { text-align: center; padding: 2px 1px 4px; min-height: 46px; position: relative; display: flex; flex-direction: column; align-items: center; justify-content: flex-start; border-radius: 8px; cursor: default; }
|
||||
.month-cal__cell.today { background: #fff7e6; }
|
||||
.month-cal__cell.selected { background: #fff7e6; box-shadow: inset 0 0 0 2px #ff8a3d; }
|
||||
.month-cal__cell.other-month .month-cal__date { color: #ddd; }
|
||||
.month-cal__date { font-size: 13px; font-weight: 600; color: #333; position: relative; z-index: 2; }
|
||||
.month-cal__cell.today .month-cal__date { color: #ff8a3d; font-weight: 800; }
|
||||
.month-cal__ring { position: absolute; top: 2px; left: 50%; transform: translateX(-50%); width: 26px; height: 26px; border-radius: 50%; border: 2px solid transparent; }
|
||||
.month-cal__ring--wearable { border-color: #1890ff; }
|
||||
.month-cal__ring--equip { border-color: #52c41a; }
|
||||
.month-cal__ring--wechat { border-color: #597ef7; }
|
||||
.month-cal__ring--manual { border-color: #fa8c16; }
|
||||
.month-cal__ring--mixed { border-color: #722ed1; }
|
||||
.month-cal__dots { display: flex; justify-content: center; gap: 2px; margin-top: 1px; }
|
||||
.month-cal__dot { width: 4px; height: 4px; border-radius: 50%; flex-shrink: 0; }
|
||||
/* 月历消耗千卡数据 */
|
||||
.month-cal__data { font-size: 9px; color: #666; line-height: 1.3; margin-top: 1px; }
|
||||
.month-cal__data .mw { font-weight: 700; color: #333; }
|
||||
.month-cal__dot--wearable { background: #1890ff; }
|
||||
.month-cal__dot--equip { background: #52c41a; }
|
||||
.month-cal__dot--wechat { background: #597ef7; }
|
||||
.month-cal__dot--manual { background: #fa8c16; }
|
||||
.month-cal__dot--mixed { background: #722ed1; }
|
||||
|
||||
/* ===== 图例 ===== */
|
||||
.legend { display: flex; justify-content: center; gap: 10px; padding: 8px 12px; flex-wrap: wrap; background: #fff; margin: 8px 12px 0; border-radius: 12px; }
|
||||
.legend__item { display: flex; align-items: center; gap: 3px; font-size: 10px; color: #666; }
|
||||
.legend__dot { width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0; }
|
||||
.legend__dot--wearable { background: #1890ff; }
|
||||
.legend__dot--equip { background: #52c41a; }
|
||||
.legend__dot--wechat { background: #597ef7; }
|
||||
.legend__dot--manual { background: #fa8c16; }
|
||||
.legend__dot--mixed { background: #722ed1; }
|
||||
|
||||
/* ===== Tab 栏 ===== */
|
||||
.record-tabs { display: flex; background: #fff; margin: 8px 12px 0; border-radius: 12px; overflow: hidden; }
|
||||
.record-tab { flex: 1; text-align: center; padding: 10px 0; font-size: 13px; font-weight: 600; color: #999; cursor: pointer; position: relative; }
|
||||
.record-tab.active { color: #ff8a3d; }
|
||||
.record-tab.active::after { content: ''; position: absolute; bottom: 4px; left: 50%; transform: translateX(-50%); width: 20px; height: 3px; background: #ff8a3d; border-radius: 2px; }
|
||||
|
||||
/* ===== 列表区域 ===== */
|
||||
.record-list { padding: 8px 12px 16px; display: flex; flex-direction: column; gap: 8px; }
|
||||
.record-item { background: #fff; border-radius: 14px; padding: 14px; box-shadow: 0 2px 8px rgba(0,0,0,0.03); }
|
||||
.record-item__header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 10px; }
|
||||
.record-item__title { font-size: 14px; font-weight: 700; color: #1a1a1a; }
|
||||
.record-item__time { font-size: 11px; color: #bbb; }
|
||||
.record-item__body { display: flex; align-items: center; gap: 16px; }
|
||||
.record-item__metric { text-align: center; min-width: 50px; }
|
||||
.record-item__metric-label { font-size: 10px; color: #999; margin-bottom: 2px; }
|
||||
.record-item__metric-val { font-size: 16px; font-weight: 700; color: #1a1a1a; }
|
||||
.record-item__metric-unit { font-size: 10px; color: #999; font-weight: 400; margin-left: 1px; }
|
||||
.record-item__source { margin-left: auto; }
|
||||
.source-badge { display: inline-block; padding: 4px 10px; border-radius: 12px; font-size: 11px; font-weight: 600; }
|
||||
.source-badge--wearable { background: #e6f7ff; color: #1890ff; }
|
||||
.source-badge--equip { background: #f6ffed; color: #52c41a; }
|
||||
.source-badge--wechat { background: #f0f5ff; color: #597ef7; }
|
||||
.source-badge--manual { background: #fff7e6; color: #fa8c16; }
|
||||
.source-badge--mixed { background: #f9f0ff; color: #722ed1; }
|
||||
|
||||
.record-section-title { font-size: 13px; font-weight: 700; color: #1a1a1a; padding: 4px 4px 0; display: flex; align-items: center; gap: 6px; }
|
||||
.record-section-title::before { content: ''; width: 3px; height: 14px; background: #ff8a3d; border-radius: 2px; flex-shrink: 0; }
|
||||
.record-section-title--steps::before { background: #1890ff; }
|
||||
|
||||
.record-empty { text-align: center; padding: 40px 20px; color: #ccc; font-size: 14px; }
|
||||
|
||||
.bottom-safe { height: 20px; flex-shrink: 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" onclick="location.href='exercise-checkin.html'">
|
||||
<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"/></svg>
|
||||
</div>
|
||||
<div class="nav-title">消耗记录</div>
|
||||
<div class="nav-placeholder"></div>
|
||||
</div>
|
||||
<div class="scroll-content">
|
||||
|
||||
<!-- 日历月导航 -->
|
||||
<div class="cal-nav">
|
||||
<div class="cal-nav__arrow" onclick="prevMonth()">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="15 18 9 12 15 6"/></svg>
|
||||
</div>
|
||||
<div class="cal-nav__month" id="calMonthLabel">2026年06月</div>
|
||||
<div class="cal-nav__arrow" onclick="nextMonth()">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="9 18 15 12 9 6"/></svg>
|
||||
</div>
|
||||
<div class="cal-nav__toggle" id="calToggle" onclick="toggleCalView()">展开月历</div>
|
||||
</div>
|
||||
|
||||
<!-- 周日历(默认) -->
|
||||
<div class="week-cal" id="weekCal"></div>
|
||||
|
||||
<!-- 月日历(展开后显示) -->
|
||||
<div class="month-cal" id="monthCal" style="display:none;"></div>
|
||||
|
||||
<!-- 图例 -->
|
||||
<div class="legend">
|
||||
<div class="legend__item"><span class="legend__dot legend__dot--wearable"></span>穿戴</div>
|
||||
<div class="legend__item"><span class="legend__dot legend__dot--equip"></span>器械</div>
|
||||
<div class="legend__item"><span class="legend__dot legend__dot--wechat"></span>微信</div>
|
||||
<div class="legend__item"><span class="legend__dot legend__dot--manual"></span>自记</div>
|
||||
<div class="legend__item"><span class="legend__dot legend__dot--mixed"></span>多途径</div>
|
||||
</div>
|
||||
|
||||
<!-- Tab 栏 -->
|
||||
<div class="record-tabs" id="recordTabs">
|
||||
<div class="record-tab active" data-range="week" onclick="switchTab('week')">周</div>
|
||||
<div class="record-tab" data-range="month" onclick="switchTab('month')">月</div>
|
||||
<div class="record-tab" data-range="quarter" onclick="switchTab('quarter')">季</div>
|
||||
<div class="record-tab" data-range="activity" onclick="switchTab('activity')">活动期间</div>
|
||||
<div class="record-tab" data-range="all" onclick="switchTab('all')">全部</div>
|
||||
</div>
|
||||
|
||||
<!-- 记录列表 -->
|
||||
<div class="record-list" id="recordList"></div>
|
||||
|
||||
<div class="bottom-safe"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
/* ===== 来源类型 ===== */
|
||||
var SOURCE_TYPES = {
|
||||
'wearable': { label:'穿戴', css:'wearable', ring:'week-cal__ring--wearable', mring:'month-cal__ring--wearable', dot:'week-cal__dot--wearable', mdot:'month-cal__dot--wearable', badge:'source-badge--wearable' },
|
||||
'equip': { label:'器械', css:'equip', ring:'week-cal__ring--equip', mring:'month-cal__ring--equip', dot:'week-cal__dot--equip', mdot:'month-cal__dot--equip', badge:'source-badge--equip' },
|
||||
'wechat': { label:'微信', css:'wechat', ring:'week-cal__ring--wechat', mring:'month-cal__ring--wechat', dot:'week-cal__dot--wechat', mdot:'month-cal__dot--wechat', badge:'source-badge--wechat' },
|
||||
'manual': { label:'自记', css:'manual', ring:'week-cal__ring--manual', mring:'month-cal__ring--manual', dot:'week-cal__dot--manual', mdot:'month-cal__dot--manual', badge:'source-badge--manual' },
|
||||
'mixed': { label:'多途径',css:'mixed', ring:'week-cal__ring--mixed', mring:'month-cal__ring--mixed', dot:'week-cal__dot--mixed', mdot:'month-cal__dot--mixed', badge:'source-badge--mixed' }
|
||||
};
|
||||
|
||||
/* ===== 消耗记录数据 ===== */
|
||||
var RECORDS = [
|
||||
{ date:'2026-06-13', name:'跑步', duration:30, kcal:300, time:'07:15', source:'wearable' },
|
||||
{ date:'2026-06-13', name:'快走', duration:45, kcal:234, time:'12:30', source:'wechat' },
|
||||
{ date:'2026-06-13', name:'瑜伽', duration:25, kcal:125, time:'18:40', source:'manual' },
|
||||
{ date:'2026-06-12', name:'快走', duration:40, kcal:208, time:'07:30', source:'wearable' },
|
||||
{ date:'2026-06-12', name:'椭圆机', duration:30, kcal:270, time:'12:05', source:'equip' },
|
||||
{ date:'2026-06-12', name:'哑铃训练', duration:20, kcal:120, time:'18:15', source:'manual' },
|
||||
{ date:'2026-06-10', name:'骑行', duration:60, kcal:420, time:'06:50', source:'wearable' },
|
||||
{ date:'2026-06-10', name:'深蹲', duration:15, kcal:100, time:'17:30', source:'equip' },
|
||||
{ date:'2026-06-10', name:'散步', duration:35, kcal:117, time:'19:10', source:'mixed' },
|
||||
{ date:'2026-06-08', name:'游泳', duration:45, kcal:495, time:'06:20', source:'wearable' },
|
||||
{ date:'2026-06-08', name:'篮球', duration:60, kcal:500, time:'16:00', source:'wechat' },
|
||||
{ date:'2026-06-08', name:'拉伸', duration:20, kcal:80, time:'20:15', source:'mixed' },
|
||||
{ date:'2026-06-07', name:'慢跑', duration:35, kcal:280, time:'07:00', source:'wearable' },
|
||||
{ date:'2026-06-07', name:'器械训练', duration:40, kcal:293, time:'12:15', source:'equip' },
|
||||
{ date:'2026-06-05', name:'跳绳', duration:20, kcal:240, time:'18:30', source:'manual' },
|
||||
{ date:'2026-06-03', name:'快走', duration:50, kcal:260, time:'07:20', source:'wechat' },
|
||||
{ date:'2026-06-03', name:'羽毛球', duration:45, kcal:330, time:'17:10', source:'mixed' },
|
||||
{ date:'2026-06-01', name:'跑步', duration:30, kcal:300, time:'06:40', source:'wearable' },
|
||||
{ date:'2026-06-01', name:'俯卧撑', duration:15, kcal:105, time:'19:30', source:'manual' },
|
||||
{ date:'2026-05-28', name:'骑行', duration:50, kcal:350, time:'07:10', source:'wearable' },
|
||||
{ date:'2026-05-28', name:'普拉提', duration:30, kcal:165, time:'18:00', source:'mixed' },
|
||||
{ date:'2026-05-25', name:'徒步', duration:90, kcal:600, time:'08:00', source:'wechat' },
|
||||
{ date:'2026-05-20', name:'太极拳', duration:30, kcal:140, time:'06:30', source:'manual' },
|
||||
{ date:'2026-05-20', name:'引体向上', duration:20, kcal:160, time:'17:00', source:'equip' },
|
||||
{ date:'2026-05-15', name:'游泳', duration:40, kcal:440, time:'06:15', source:'wearable' },
|
||||
{ date:'2026-05-15', name:'广场舞', duration:45, kcal:255, time:'19:00', source:'mixed' },
|
||||
{ date:'2026-05-10', name:'跑步', duration:25, kcal:250, time:'07:00', source:'wechat' },
|
||||
{ date:'2026-05-10', name:'家务劳动', duration:40, kcal:173, time:'15:30', source:'manual' },
|
||||
{ date:'2026-05-05', name:'慢跑', duration:30, kcal:240, time:'06:50', source:'wearable' },
|
||||
{ date:'2026-05-01', name:'卧推', duration:25, kcal:163, time:'17:20', source:'equip' },
|
||||
{ date:'2026-04-25', name:'椭圆机', duration:35, kcal:315, time:'12:00', source:'mixed' },
|
||||
{ date:'2026-04-20', name:'骑行', duration:55, kcal:385, time:'07:30', source:'wechat' },
|
||||
];
|
||||
|
||||
/* ===== 状态 ===== */
|
||||
var calYear = 2026;
|
||||
var calMonth = 5; // 0-based, 5=June
|
||||
var calExpanded = false;
|
||||
var activeTab = 'week';
|
||||
var selectedDate = null;
|
||||
|
||||
var TODAY = new Date(2026, 5, 12); // 2026-06-12
|
||||
var ACTIVITY_START = new Date(2026, 4, 1); // 2026-05-01
|
||||
var ACTIVITY_END = new Date(2026, 7, 1); // 2026-08-01
|
||||
|
||||
/* ===== 工具函数 ===== */
|
||||
function fmt(n) { return n < 10 ? '0' + n : '' + n; }
|
||||
function dateStr(y, m, d) { return y + '-' + fmt(m+1) + '-' + fmt(d); }
|
||||
function parseDate(s) { var p = s.split('-'); return new Date(+p[0], +p[1]-1, +p[2]); }
|
||||
function sameDay(a, b) { return a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth() && a.getDate() === b.getDate(); }
|
||||
|
||||
/* 获取某天的记录列表,返回各来源类型集合 */
|
||||
function getDaySources(y, m, d) {
|
||||
var s = dateStr(y, m, d);
|
||||
var sources = {};
|
||||
for (var i = 0; i < RECORDS.length; i++) {
|
||||
if (RECORDS[i].date === s) {
|
||||
sources[RECORDS[i].source] = true;
|
||||
}
|
||||
}
|
||||
return Object.keys(sources);
|
||||
}
|
||||
|
||||
/* 获取某天的总消耗千卡 */
|
||||
function getDayKcal(y, m, d) {
|
||||
var s = dateStr(y, m, d);
|
||||
var total = 0;
|
||||
for (var i = 0; i < RECORDS.length; i++) {
|
||||
if (RECORDS[i].date === s) {
|
||||
total += RECORDS[i].kcal;
|
||||
}
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
/* ===== 周日历 ===== */
|
||||
var WEEKDAY_LABELS = ['一','二','三','四','五','六','日'];
|
||||
|
||||
function getWeekStart() {
|
||||
var first = new Date(calYear, calMonth, 1);
|
||||
var day = first.getDay();
|
||||
var monday = new Date(first);
|
||||
monday.setDate(1 - (day === 0 ? 6 : day - 1));
|
||||
return monday;
|
||||
}
|
||||
|
||||
function renderWeekCal() {
|
||||
var container = document.getElementById('weekCal');
|
||||
var now = new Date(2026, 5, 12);
|
||||
var start;
|
||||
if (calYear === now.getFullYear() && calMonth === now.getMonth()) {
|
||||
var dow = now.getDay() || 7;
|
||||
start = new Date(now);
|
||||
start.setDate(now.getDate() - dow + 1);
|
||||
} else {
|
||||
start = getWeekStart();
|
||||
}
|
||||
|
||||
var html = '<div class="week-cal__row">';
|
||||
for (var i = 0; i < 7; i++) {
|
||||
var d = new Date(start);
|
||||
d.setDate(start.getDate() + i);
|
||||
var sources = getDaySources(d.getFullYear(), d.getMonth(), d.getDate());
|
||||
var hasRecord = sources.length > 0;
|
||||
var isToday = sameDay(d, TODAY);
|
||||
var isOtherMonth = d.getMonth() !== calMonth;
|
||||
var dateKey = dateStr(d.getFullYear(), d.getMonth(), d.getDate());
|
||||
var isSel = dateKey === selectedDate;
|
||||
var primarySource = sources[0] || null;
|
||||
|
||||
html += '<div class="week-cal__cell' + (isToday ? ' today' : '') + (isSel ? ' selected' : '') + '"'
|
||||
+ ' onclick="onDayClick(\'' + dateKey + '\')" style="cursor:' + (hasRecord ? 'pointer' : 'default') + '">';
|
||||
html += '<div class="week-cal__wd">' + WEEKDAY_LABELS[i] + '</div>';
|
||||
html += '<div class="week-cal__date-wrap">';
|
||||
if (primarySource) {
|
||||
html += '<div class="week-cal__ring ' + SOURCE_TYPES[primarySource].ring + '"></div>';
|
||||
}
|
||||
html += '<span class="week-cal__date" style="' + (isOtherMonth ? 'color:#ddd' : '') + '">' + (isToday ? '今' : d.getDate()) + '</span>';
|
||||
html += '</div>';
|
||||
var dayKcal = getDayKcal(d.getFullYear(), d.getMonth(), d.getDate());
|
||||
if (dayKcal > 0) {
|
||||
html += '<div class="week-cal__data"><span class="w">' + dayKcal + '</span>千卡</div>';
|
||||
}
|
||||
html += '</div>';
|
||||
}
|
||||
html += '</div>';
|
||||
container.innerHTML = html;
|
||||
}
|
||||
|
||||
/* ===== 月日历 ===== */
|
||||
function renderMonthCal() {
|
||||
var container = document.getElementById('monthCal');
|
||||
var html = '<div class="month-cal__weekday">';
|
||||
for (var w = 0; w < 7; w++) { html += '<span>' + WEEKDAY_LABELS[w] + '</span>'; }
|
||||
html += '</div>';
|
||||
|
||||
var first = new Date(calYear, calMonth, 1);
|
||||
var startDow = first.getDay() || 7;
|
||||
var cursor = new Date(first);
|
||||
cursor.setDate(1 - (startDow - 1));
|
||||
|
||||
var done = false;
|
||||
for (var row = 0; row < 6 && !done; row++) {
|
||||
html += '<div class="month-cal__row">';
|
||||
for (var col = 0; col < 7; col++) {
|
||||
var isOther = cursor.getMonth() !== calMonth;
|
||||
var isToday = sameDay(cursor, TODAY);
|
||||
var dateKey = dateStr(cursor.getFullYear(), cursor.getMonth(), cursor.getDate());
|
||||
var isSel = dateKey === selectedDate;
|
||||
var sources = getDaySources(cursor.getFullYear(), cursor.getMonth(), cursor.getDate());
|
||||
var primarySource = sources[0] || null;
|
||||
|
||||
html += '<div class="month-cal__cell' + (isToday ? ' today' : '') + (isOther ? ' other-month' : '') + (isSel ? ' selected' : '') + '"'
|
||||
+ ' onclick="onDayClick(\'' + dateKey + '\')" style="cursor:' + (sources.length ? 'pointer' : 'default') + '">';
|
||||
html += '<div style="position:relative;width:26px;height:26px;">';
|
||||
if (primarySource) {
|
||||
html += '<div class="month-cal__ring ' + SOURCE_TYPES[primarySource].mring + '"></div>';
|
||||
}
|
||||
html += '<span class="month-cal__date">' + (isToday ? '今' : cursor.getDate()) + '</span>';
|
||||
html += '</div>';
|
||||
var mKcal = getDayKcal(cursor.getFullYear(), cursor.getMonth(), cursor.getDate());
|
||||
if (mKcal > 0) {
|
||||
html += '<div class="month-cal__data"><span class="mw">' + mKcal + '</span>千卡</div>';
|
||||
}
|
||||
html += '</div>';
|
||||
|
||||
cursor.setDate(cursor.getDate() + 1);
|
||||
if (col === 6 && cursor.getDate() > 7 && cursor.getMonth() !== calMonth) { done = true; }
|
||||
}
|
||||
html += '</div>';
|
||||
}
|
||||
container.innerHTML = html;
|
||||
}
|
||||
|
||||
/* ===== 日历展开/收起 ===== */
|
||||
function toggleCalView() {
|
||||
calExpanded = !calExpanded;
|
||||
document.getElementById('weekCal').style.display = calExpanded ? 'none' : '';
|
||||
document.getElementById('monthCal').style.display = calExpanded ? '' : 'none';
|
||||
document.getElementById('calToggle').textContent = calExpanded ? '收起月历' : '展开月历';
|
||||
if (calExpanded) renderMonthCal();
|
||||
}
|
||||
|
||||
function prevMonth() {
|
||||
if (calExpanded) {
|
||||
calMonth--;
|
||||
if (calMonth < 0) { calMonth = 11; calYear--; }
|
||||
} else {
|
||||
var now = new Date(2026, 5, 12);
|
||||
var dow = now.getDay() || 7;
|
||||
var curWeekStart;
|
||||
if (calYear === now.getFullYear() && calMonth === now.getMonth()) {
|
||||
curWeekStart = new Date(now);
|
||||
curWeekStart.setDate(now.getDate() - dow + 1);
|
||||
} else {
|
||||
curWeekStart = getWeekStart();
|
||||
}
|
||||
curWeekStart.setDate(curWeekStart.getDate() - 7);
|
||||
calYear = curWeekStart.getFullYear();
|
||||
calMonth = curWeekStart.getMonth();
|
||||
}
|
||||
updateCal();
|
||||
}
|
||||
|
||||
function nextMonth() {
|
||||
if (calExpanded) {
|
||||
calMonth++;
|
||||
if (calMonth > 11) { calMonth = 0; calYear++; }
|
||||
} else {
|
||||
var now = new Date(2026, 5, 12);
|
||||
var dow = now.getDay() || 7;
|
||||
var curWeekStart;
|
||||
if (calYear === now.getFullYear() && calMonth === now.getMonth()) {
|
||||
curWeekStart = new Date(now);
|
||||
curWeekStart.setDate(now.getDate() - dow + 1);
|
||||
} else {
|
||||
curWeekStart = getWeekStart();
|
||||
}
|
||||
curWeekStart.setDate(curWeekStart.getDate() + 7);
|
||||
calYear = curWeekStart.getFullYear();
|
||||
calMonth = curWeekStart.getMonth();
|
||||
}
|
||||
updateCal();
|
||||
}
|
||||
|
||||
function updateCal() {
|
||||
document.getElementById('calMonthLabel').textContent = calYear + '年' + fmt(calMonth + 1) + '月';
|
||||
renderWeekCal();
|
||||
if (calExpanded) renderMonthCal();
|
||||
}
|
||||
|
||||
/* ===== Tab 切换 ===== */
|
||||
function switchTab(range) {
|
||||
activeTab = range;
|
||||
selectedDate = null;
|
||||
document.querySelectorAll('.record-tab').forEach(function(t) {
|
||||
t.classList.toggle('active', t.dataset.range === range);
|
||||
});
|
||||
updateCal();
|
||||
renderRecordList();
|
||||
}
|
||||
|
||||
function getTabDateRange() {
|
||||
var now = new Date(2026, 5, 12);
|
||||
var start, end;
|
||||
switch (activeTab) {
|
||||
case 'week':
|
||||
var dow = now.getDay() || 7;
|
||||
start = new Date(now); start.setDate(now.getDate() - dow + 1);
|
||||
end = new Date(start); end.setDate(start.getDate() + 6);
|
||||
break;
|
||||
case 'month':
|
||||
start = new Date(now.getFullYear(), now.getMonth(), 1);
|
||||
end = new Date(now.getFullYear(), now.getMonth() + 1, 0);
|
||||
break;
|
||||
case 'quarter':
|
||||
var q = Math.floor(now.getMonth() / 3);
|
||||
start = new Date(now.getFullYear(), q * 3, 1);
|
||||
end = new Date(now.getFullYear(), (q + 1) * 3, 0);
|
||||
break;
|
||||
case 'activity':
|
||||
start = ACTIVITY_START;
|
||||
end = ACTIVITY_END;
|
||||
break;
|
||||
case 'all':
|
||||
start = new Date(2000, 0, 1);
|
||||
end = new Date(2099, 11, 31);
|
||||
break;
|
||||
}
|
||||
return { start: start, end: end };
|
||||
}
|
||||
|
||||
/* ===== 渲染记录列表 ===== */
|
||||
function isStepRecord(r) {
|
||||
return r.name === '快走' || r.name === '散步' || r.name === '徒步';
|
||||
}
|
||||
|
||||
function renderRecordList() {
|
||||
var filtered;
|
||||
if (selectedDate) {
|
||||
filtered = RECORDS.filter(function(r) { return r.date === selectedDate; });
|
||||
} else {
|
||||
var range = getTabDateRange();
|
||||
filtered = RECORDS.filter(function(r) {
|
||||
var d = parseDate(r.date);
|
||||
return d >= range.start && d <= range.end;
|
||||
});
|
||||
}
|
||||
|
||||
var container = document.getElementById('recordList');
|
||||
if (filtered.length === 0) {
|
||||
container.innerHTML = '<div class="record-empty">该时间段暂无记录</div>';
|
||||
return;
|
||||
}
|
||||
|
||||
// 选中具体日期时,分组展示:当日步数 + 运动记录
|
||||
if (selectedDate) {
|
||||
var stepRecords = filtered.filter(function(r) { return isStepRecord(r); });
|
||||
var exerciseRecords = filtered.filter(function(r) { return !isStepRecord(r); });
|
||||
|
||||
var html = '';
|
||||
|
||||
// 当日步数(最多一条)
|
||||
if (stepRecords.length > 0) {
|
||||
html += '<div class="record-section-title record-section-title--steps">当日步数</div>';
|
||||
var sr = stepRecords[0];
|
||||
var src = SOURCE_TYPES[sr.source];
|
||||
html += '<div class="record-item">';
|
||||
html += '<div class="record-item__header">';
|
||||
html += '<span class="record-item__title">' + sr.name + '</span>';
|
||||
html += '<span class="record-item__time">' + sr.date + ' ' + sr.time + '</span>';
|
||||
html += '</div>';
|
||||
html += '<div class="record-item__body">';
|
||||
html += '<div class="record-item__metric"><div class="record-item__metric-label">消耗热量</div><div class="record-item__metric-val">' + sr.kcal + '<span class="record-item__metric-unit">千卡</span></div></div>';
|
||||
html += '<div class="record-item__metric"><div class="record-item__metric-label">运动时长</div><div class="record-item__metric-val">' + sr.duration + '<span class="record-item__metric-unit">分钟</span></div></div>';
|
||||
html += '<div class="record-item__source"><span class="source-badge ' + src.badge + '">' + src.label + '</span></div>';
|
||||
html += '</div>';
|
||||
html += '</div>';
|
||||
}
|
||||
|
||||
// 运动记录
|
||||
if (exerciseRecords.length > 0) {
|
||||
html += '<div class="record-section-title" style="margin-top:' + (stepRecords.length > 0 ? '12px' : '0') + ';">运动记录</div>';
|
||||
for (var i = 0; i < exerciseRecords.length; i++) {
|
||||
var r = exerciseRecords[i];
|
||||
var src2 = SOURCE_TYPES[r.source];
|
||||
html += '<div class="record-item">';
|
||||
html += '<div class="record-item__header">';
|
||||
html += '<span class="record-item__title">' + r.name + '</span>';
|
||||
html += '<span class="record-item__time">' + r.date + ' ' + r.time + '</span>';
|
||||
html += '</div>';
|
||||
html += '<div class="record-item__body">';
|
||||
html += '<div class="record-item__metric"><div class="record-item__metric-label">消耗热量</div><div class="record-item__metric-val">' + r.kcal + '<span class="record-item__metric-unit">千卡</span></div></div>';
|
||||
html += '<div class="record-item__metric"><div class="record-item__metric-label">运动时长</div><div class="record-item__metric-val">' + r.duration + '<span class="record-item__metric-unit">分钟</span></div></div>';
|
||||
html += '<div class="record-item__source"><span class="source-badge ' + src2.badge + '">' + src2.label + '</span></div>';
|
||||
html += '</div>';
|
||||
html += '</div>';
|
||||
}
|
||||
}
|
||||
|
||||
container.innerHTML = html;
|
||||
return;
|
||||
}
|
||||
|
||||
// Tab 模式:扁平列表
|
||||
var html = '';
|
||||
for (var i = 0; i < filtered.length; i++) {
|
||||
var r = filtered[i];
|
||||
var src = SOURCE_TYPES[r.source];
|
||||
html += '<div class="record-item">';
|
||||
html += '<div class="record-item__header">';
|
||||
html += '<span class="record-item__title">' + r.name + '</span>';
|
||||
html += '<span class="record-item__time">' + r.date + ' ' + r.time + '</span>';
|
||||
html += '</div>';
|
||||
html += '<div class="record-item__body">';
|
||||
html += '<div class="record-item__metric"><div class="record-item__metric-label">消耗热量</div><div class="record-item__metric-val">' + r.kcal + '<span class="record-item__metric-unit">千卡</span></div></div>';
|
||||
html += '<div class="record-item__metric"><div class="record-item__metric-label">运动时长</div><div class="record-item__metric-val">' + r.duration + '<span class="record-item__metric-unit">分钟</span></div></div>';
|
||||
html += '<div class="record-item__source"><span class="source-badge ' + src.badge + '">' + src.label + '</span></div>';
|
||||
html += '</div>';
|
||||
html += '</div>';
|
||||
}
|
||||
container.innerHTML = html;
|
||||
}
|
||||
|
||||
/* ===== 点击日期 ===== */
|
||||
function onDayClick(dateStr) {
|
||||
if (selectedDate === dateStr) {
|
||||
switchTab('week');
|
||||
return;
|
||||
}
|
||||
selectedDate = dateStr;
|
||||
activeTab = '';
|
||||
document.querySelectorAll('.record-tab').forEach(function(t) { t.classList.remove('active'); });
|
||||
updateCal();
|
||||
renderRecordList();
|
||||
document.querySelector('.scroll-content').scrollTop = document.getElementById('recordTabs').offsetTop - 100;
|
||||
}
|
||||
|
||||
/* ===== 初始化 ===== */
|
||||
function init() {
|
||||
calYear = TODAY.getFullYear();
|
||||
calMonth = TODAY.getMonth();
|
||||
document.getElementById('calMonthLabel').textContent = calYear + '年' + fmt(calMonth + 1) + '月';
|
||||
renderWeekCal();
|
||||
renderRecordList();
|
||||
}
|
||||
init();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,408 +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; position: relative; }
|
||||
.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-more { width: 28px; height: 28px; display: flex; align-items: center; justify-content: center; cursor: pointer; color: #1a1a1a; }
|
||||
.nav-menu { position: absolute; top: 44px; right: 12px; background: #fff; border-radius: 12px; box-shadow: 0 8px 24px rgba(0,0,0,0.15); padding: 6px 0; min-width: 180px; z-index: 30; display: none; }
|
||||
.nav-menu.show { display: block; }
|
||||
.nav-menu__item { padding: 11px 18px; font-size: 14px; color: #1a1a1a; cursor: pointer; display: flex; align-items: center; justify-content: space-between; }
|
||||
.nav-menu__item:hover { background: #f5f7fa; }
|
||||
.nav-menu__item.active { color: #1f9d8f; font-weight: 600; }
|
||||
.nav-menu__item.active::after { content: '✓'; color: #1f9d8f; font-size: 13px; font-weight: 700; }
|
||||
.scroll-content { flex: 1; overflow-y: auto; background: #f5f7fa; padding-bottom: 30px; }
|
||||
.scroll-content::-webkit-scrollbar { display: none; }
|
||||
|
||||
/* 顶部 Banner */
|
||||
.hero { position: relative; background: linear-gradient(180deg, #4dc4b6 0%, #46b8af 60%, #3aa9a0 100%); padding: 22px 20px 80px; overflow: hidden; }
|
||||
.hero__mountain { position: absolute; left: 0; right: 0; bottom: 0; height: 60px; opacity: 0.35; }
|
||||
.hero__title { font-size: 22px; font-weight: 800; color: #fff; line-height: 1.4; letter-spacing: 1px; }
|
||||
.hero__subtitle { font-size: 16px; font-weight: 600; color: #fff; margin-top: 6px; letter-spacing: 0.5px; }
|
||||
.hero__runners { position: absolute; right: 12px; top: 30px; width: 160px; height: 100px; }
|
||||
|
||||
/* 步骤卡 */
|
||||
.steps-card { background: #fff; border-radius: 14px; margin: -54px 16px 16px; padding: 18px 16px 20px; box-shadow: 0 6px 18px rgba(0,0,0,0.08); position: relative; z-index: 2; }
|
||||
.card-activity { text-align: center; margin-bottom: 14px; }
|
||||
.card-activity__name { font-size: 17px; font-weight: 800; color: #1a1a1a; letter-spacing: 1px; }
|
||||
.card-activity__period { font-size: 13px; color: #999; margin-top: 4px; }
|
||||
.card-progress { display: flex; align-items: center; justify-content: space-between; margin-bottom: 10px; }
|
||||
.card-progress__label { font-size: 14px; font-weight: 600; color: #1a1a1a; }
|
||||
.card-progress__days { font-size: 13px; color: #5a607f; }
|
||||
.card-progress__days .hi { color: #1f9d8f; font-weight: 700; font-size: 14px; }
|
||||
.card-targets { display: flex; background: #f5f7fa; border-radius: 10px; padding: 14px 8px; margin-bottom: 14px; }
|
||||
.card-target { flex: 1; text-align: center; }
|
||||
.card-target__value { font-size: 18px; font-weight: 800; color: #1a1a1a; }
|
||||
.card-target__label { font-size: 12px; color: #8a93a0; margin-top: 4px; }
|
||||
.card-status { font-size: 13px; font-weight: 600; text-align: center; padding: 4px 0 14px; border-bottom: 1px dashed #ececec; margin-bottom: 16px; }
|
||||
.card-status--wait { color: #faad14; }
|
||||
.card-status--pass { color: #1f9d8f; }
|
||||
.card-status--reject { color: #ff4d4f; }
|
||||
.card-status__link { color: inherit; text-decoration: underline; cursor: pointer; }
|
||||
.card-tip { font-size: 15px; font-weight: 600; color: #1a1a1a; text-align: center; padding: 10px 0 16px; }
|
||||
.steps-row { display: flex; align-items: flex-start; justify-content: space-between; }
|
||||
|
||||
/* 驳回原因弹窗 */
|
||||
.reason-mask { position: absolute; inset: 0; background: rgba(0,0,0,0.45); z-index: 40; opacity: 0; pointer-events: none; transition: opacity 0.2s; display: flex; align-items: center; justify-content: center; padding: 0 28px; }
|
||||
.reason-mask.show { opacity: 1; pointer-events: auto; }
|
||||
.reason { width: 100%; background: #fff; border-radius: 14px; padding: 22px 22px 18px; transform: scale(0.95); transition: transform 0.2s; }
|
||||
.reason-mask.show .reason { transform: scale(1); }
|
||||
.reason__title { font-size: 17px; font-weight: 800; color: #1a1a1a; text-align: center; margin-bottom: 14px; }
|
||||
.reason__body { font-size: 14px; line-height: 1.7; color: #333; background: #fff5f5; border-left: 3px solid #ff4d4f; border-radius: 6px; padding: 12px 14px; margin-bottom: 16px; }
|
||||
.reason__meta { display: flex; justify-content: space-between; font-size: 12px; color: #9aa3ad; margin-bottom: 16px; }
|
||||
.reason__btn { display: block; width: 100%; height: 42px; background: linear-gradient(135deg, #4dc4b6 0%, #46b8af 100%); color: #fff; border: none; border-radius: 21px; font-size: 15px; font-weight: 600; cursor: pointer; letter-spacing: 4px; }
|
||||
.steps-item { flex: 1; text-align: center; position: relative; cursor: pointer; }
|
||||
.steps-item a { text-decoration: none; color: inherit; display: block; }
|
||||
.steps-item__icon { width: 44px; height: 44px; margin: 0 auto 8px; display: flex; align-items: center; justify-content: center; color: #4dc4b6; }
|
||||
.steps-item__icon svg { width: 32px; height: 32px; }
|
||||
.steps-item__name { font-size: 13px; color: #333; }
|
||||
.steps-item__name--warn { color: #ff8a3d; font-weight: 600; display: inline-flex; align-items: center; gap: 3px; }
|
||||
.steps-item__warn-icon { width: 12px; height: 12px; flex-shrink: 0; }
|
||||
.steps-item__name--signed { color: #1f9d8f; font-weight: 600; display: inline-flex; align-items: center; gap: 3px; }
|
||||
.steps-item__check-icon { width: 12px; height: 12px; flex-shrink: 0; }
|
||||
.steps-arrow { width: 16px; flex-shrink: 0; display: flex; align-items: center; justify-content: center; padding-top: 14px; color: #c8c8c8; font-size: 12px; }
|
||||
|
||||
/* 说明区 */
|
||||
.intro { background: #fff; border-radius: 14px; margin: 0 16px 16px; padding: 22px 18px 26px; }
|
||||
.intro__title { font-size: 18px; font-weight: 800; color: #1a1a1a; text-align: center; margin-bottom: 18px; }
|
||||
.intro__body { font-size: 14px; color: #333; line-height: 2; text-indent: 2em; }
|
||||
.intro__body p { margin-bottom: 4px; }
|
||||
.intro__hi { color: #1f9d8f; }
|
||||
.intro__warn { color: #ff4d4f; font-weight: 600; }
|
||||
.intro__warn-link { color: #ff4d4f; font-weight: 700; }
|
||||
.intro__attach { font-size: 13px; color: #666; margin-top: 18px; text-indent: 0; }
|
||||
.intro__attach-link { color: #1f86ff; text-decoration: underline; cursor: pointer; }
|
||||
|
||||
/* 落款 */
|
||||
.signature { padding: 26px 32px 12px; font-size: 14px; color: #333; }
|
||||
.signature__line { display: flex; align-items: center; justify-content: flex-end; gap: 6px; margin-bottom: 14px; }
|
||||
.signature__label { font-weight: 600; }
|
||||
.signature__value { display: inline-block; width: 140px; border-bottom: 1px solid #bbb; height: 22px; }
|
||||
|
||||
/* 底部确认按钮(交互辅助) */
|
||||
.btn-bar { padding: 16px 16px 22px; background: #fff; }
|
||||
.btn-confirm { display: block; width: 100%; height: 46px; background: linear-gradient(135deg, #4dc4b6 0%, #46b8af 100%); color: #fff; border: none; border-radius: 23px; font-size: 16px; font-weight: 600; cursor: pointer; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="phone-shell">
|
||||
<div class="status-bar">
|
||||
<span class="time">9:41</span>
|
||||
<div class="icons">
|
||||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="#333" stroke-width="2"><path d="M1 6l5 5 5-5"/><path d="M4 9l3 3 3-3" opacity="0.5"/></svg>
|
||||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="#333" stroke-width="2"><rect x="1" y="6" width="18" height="12" rx="2"/><path d="M21 10v4"/></svg>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 顶部导航 -->
|
||||
<div class="nav-bar">
|
||||
<div class="nav-back" onclick="location.href='../home/index.html'">
|
||||
<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"/></svg>
|
||||
</div>
|
||||
<div class="nav-title">目标承诺</div>
|
||||
<div class="nav-more" onclick="toggleTypeMenu(event)">
|
||||
<svg width="22" height="22" viewBox="0 0 24 24" fill="currentColor"><circle cx="5" cy="12" r="2"/><circle cx="12" cy="12" r="2"/><circle cx="19" cy="12" r="2"/></svg>
|
||||
</div>
|
||||
<div class="nav-menu" id="typeMenu">
|
||||
<div class="nav-menu__item active" data-type="unset-noact" onclick="setGoalType('unset-noact')">未选目标 - 无活动</div>
|
||||
<div class="nav-menu__item" data-type="unset-hasact" onclick="setGoalType('unset-hasact')">未选目标 - 有活动</div>
|
||||
<div class="nav-menu__item" data-type="personal" onclick="setGoalType('personal')">已选个人目标</div>
|
||||
<div class="nav-menu__item" data-type="wait" onclick="setGoalType('wait')">单位活动 - 待审核</div>
|
||||
<div class="nav-menu__item" data-type="pass" onclick="setGoalType('pass')">单位活动 - 审核通过</div>
|
||||
<div class="nav-menu__item" data-type="reject" onclick="setGoalType('reject')">单位活动 - 已驳回</div>
|
||||
<div class="nav-menu__item" data-type="signed" onclick="setGoalType('signed')">单位活动 - 已签署承诺书</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="scroll-content">
|
||||
<!-- 顶部 Banner -->
|
||||
<div class="hero">
|
||||
<div class="hero__title">体重管理</div>
|
||||
<div class="hero__subtitle">让健康行动走进生活</div>
|
||||
<!-- 跑步小人插画 -->
|
||||
<svg class="hero__runners" viewBox="0 0 200 110" fill="none">
|
||||
<!-- 后跑步者(女) -->
|
||||
<circle cx="55" cy="32" r="9" fill="#FFD0A8"/>
|
||||
<path d="M52 24 Q55 18 62 22 Q66 26 60 32 Z" fill="#3a3a3a"/>
|
||||
<path d="M45 42 Q45 38 50 38 L60 38 Q65 38 65 42 L65 60 Q65 64 60 64 L50 64 Q45 64 45 60 Z" fill="#ffb74d"/>
|
||||
<rect x="48" y="62" width="6" height="20" rx="2" fill="#5a4a3a"/>
|
||||
<rect x="56" y="62" width="6" height="20" rx="2" fill="#5a4a3a" transform="rotate(15 59 72)"/>
|
||||
<rect x="38" y="44" width="6" height="16" rx="2" fill="#ffb74d" transform="rotate(-30 41 52)"/>
|
||||
<rect x="64" y="42" width="6" height="14" rx="2" fill="#ffb74d" transform="rotate(40 67 49)"/>
|
||||
<!-- 中跑步者(男主) -->
|
||||
<circle cx="95" cy="36" r="10" fill="#FFCFA0"/>
|
||||
<path d="M88 28 Q95 20 104 26 Q106 32 100 36 Z" fill="#2c2c2c"/>
|
||||
<path d="M84 48 Q84 44 89 44 L102 44 Q107 44 107 48 L107 68 Q107 72 102 72 L89 72 Q84 72 84 68 Z" fill="#1f8c83"/>
|
||||
<rect x="86" y="70" width="7" height="22" rx="2" fill="#2a2a2a" transform="rotate(-10 89.5 81)"/>
|
||||
<rect x="98" y="70" width="7" height="22" rx="2" fill="#2a2a2a" transform="rotate(20 101.5 81)"/>
|
||||
<rect x="76" y="50" width="6" height="18" rx="2" fill="#FFCFA0" transform="rotate(-40 79 59)"/>
|
||||
<rect x="108" y="46" width="6" height="18" rx="2" fill="#FFCFA0" transform="rotate(35 111 55)"/>
|
||||
<!-- 右后跑步者(男) -->
|
||||
<circle cx="140" cy="34" r="9" fill="#FFCFA0"/>
|
||||
<path d="M134 26 Q140 19 147 24 Q148 30 144 34 Z" fill="#3a2a1a"/>
|
||||
<path d="M131 44 Q131 40 136 40 L147 40 Q152 40 152 44 L152 62 Q152 66 147 66 L136 66 Q131 66 131 62 Z" fill="#ff7e4a"/>
|
||||
<rect x="133" y="64" width="6" height="20" rx="2" fill="#2a2a2a"/>
|
||||
<rect x="144" y="64" width="6" height="20" rx="2" fill="#2a2a2a" transform="rotate(18 147 74)"/>
|
||||
<rect x="124" y="46" width="6" height="16" rx="2" fill="#ff7e4a" transform="rotate(-25 127 54)"/>
|
||||
<rect x="151" y="42" width="6" height="16" rx="2" fill="#ff7e4a" transform="rotate(45 154 50)"/>
|
||||
</svg>
|
||||
<!-- 底部远山剪影 -->
|
||||
<svg class="hero__mountain" viewBox="0 0 400 60" preserveAspectRatio="none">
|
||||
<path d="M0 40 L40 20 L70 40 L110 15 L150 40 L190 25 L230 40 L270 18 L310 40 L350 22 L400 40 L400 60 L0 60 Z" fill="#ffffff" opacity="0.25"/>
|
||||
<path d="M0 50 L60 30 L120 50 L180 28 L240 50 L300 32 L360 50 L400 36 L400 60 L0 60 Z" fill="#ffffff" opacity="0.35"/>
|
||||
</svg>
|
||||
</div>
|
||||
|
||||
<!-- 步骤卡 -->
|
||||
<div class="steps-card">
|
||||
<!-- 活动头(仅单位活动类型展示) -->
|
||||
<div class="card-activity" id="cardActivity" style="display:none;">
|
||||
<div class="card-activity__name">XX单位第一季度减重活动</div>
|
||||
<div class="card-activity__period">(2025.1.5 ~ 2025.4.5)</div>
|
||||
</div>
|
||||
<!-- 进度行 -->
|
||||
<div class="card-progress" id="cardProgress">
|
||||
<span class="card-progress__label" id="cardProgressLabel">您当前已设置个人目标</span>
|
||||
<span class="card-progress__days">已进行 <span class="hi">0/100</span> 天</span>
|
||||
</div>
|
||||
<!-- 目标统计 -->
|
||||
<div class="card-targets" id="cardTargets">
|
||||
<div class="card-target">
|
||||
<div class="card-target__value">59kg</div>
|
||||
<div class="card-target__label">目标体重</div>
|
||||
</div>
|
||||
<div class="card-target">
|
||||
<div class="card-target__value">16%</div>
|
||||
<div class="card-target__label">目标体脂</div>
|
||||
</div>
|
||||
<div class="card-target">
|
||||
<div class="card-target__value">80cm</div>
|
||||
<div class="card-target__label">目标腰围</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 审核状态(仅单位活动类型展示) -->
|
||||
<div class="card-status" id="cardStatus" style="display:none;"></div>
|
||||
<!-- 未选目标提示(仅未选目标类型展示) -->
|
||||
<div class="card-tip" id="cardTip" style="display:none;">请先完成目标管理,再签订活动承诺书!</div>
|
||||
<div class="steps-row">
|
||||
<div class="steps-item">
|
||||
<a href="basic-info.html">
|
||||
<div class="steps-item__icon">
|
||||
<svg viewBox="0 0 32 32" fill="none" stroke="#4dc4b6" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round">
|
||||
<rect x="5" y="5" width="22" height="22" rx="3"/>
|
||||
<circle cx="12" cy="14" r="2.5"/>
|
||||
<path d="M8 22 Q12 18 16 22"/>
|
||||
<line x1="18" y1="12" x2="24" y2="12"/>
|
||||
<line x1="18" y1="16" x2="24" y2="16"/>
|
||||
<line x1="18" y1="20" x2="22" y2="20"/>
|
||||
</svg>
|
||||
</div>
|
||||
<div class="steps-item__name">基本信息</div>
|
||||
</a>
|
||||
</div>
|
||||
<div class="steps-arrow">›</div>
|
||||
<div class="steps-item">
|
||||
<a href="indicators-diseases.html">
|
||||
<div class="steps-item__icon">
|
||||
<svg viewBox="0 0 32 32" fill="none" stroke="#4dc4b6" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round">
|
||||
<rect x="5" y="5" width="22" height="22" rx="3"/>
|
||||
<path d="M8 18 L12 18 L14 12 L17 22 L20 16 L24 16"/>
|
||||
<circle cx="25" cy="9" r="3"/>
|
||||
<line x1="25" y1="7" x2="25" y2="11"/>
|
||||
<line x1="23" y1="9" x2="27" y2="9"/>
|
||||
</svg>
|
||||
</div>
|
||||
<div class="steps-item__name steps-item__name--warn">
|
||||
<svg class="steps-item__warn-icon" viewBox="0 0 16 16" fill="none" stroke="#ff8a3d" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M8 1.5 L15 14 L1 14 Z"/>
|
||||
<line x1="8" y1="6" x2="8" y2="10"/>
|
||||
<circle cx="8" cy="12" r="0.6" fill="#ff8a3d" stroke="none"/>
|
||||
</svg>
|
||||
指标慢病
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
<div class="steps-arrow">›</div>
|
||||
<div class="steps-item">
|
||||
<a id="goalMgmtLink" href="goal-management.html">
|
||||
<div class="steps-item__icon">
|
||||
<svg viewBox="0 0 32 32" fill="none" stroke="#4dc4b6" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round">
|
||||
<rect x="5" y="5" width="22" height="22" rx="3"/>
|
||||
<line x1="9" y1="11" x2="20" y2="11"/>
|
||||
<line x1="9" y1="15" x2="17" y2="15"/>
|
||||
<circle cx="20" cy="20" r="4"/>
|
||||
<path d="M18.5 20 L19.5 21 L21.5 19"/>
|
||||
</svg>
|
||||
</div>
|
||||
<div class="steps-item__name">目标管理</div>
|
||||
</a>
|
||||
</div>
|
||||
<div class="steps-arrow">›</div>
|
||||
<div class="steps-item" id="stepSign">
|
||||
<a href="promise-signing.html" id="stepSignLink">
|
||||
<div class="steps-item__icon" id="stepSignIcon">
|
||||
<svg viewBox="0 0 32 32" fill="none" stroke="#4dc4b6" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round">
|
||||
<rect x="5" y="5" width="22" height="22" rx="3"/>
|
||||
<line x1="9" y1="11" x2="20" y2="11"/>
|
||||
<line x1="9" y1="15" x2="17" y2="15"/>
|
||||
<polygon points="22,16 23.2,19 26.5,19 23.8,21 24.8,24 22,22.2 19.2,24 20.2,21 17.5,19 20.8,19" fill="#4dc4b6" stroke="none"/>
|
||||
</svg>
|
||||
</div>
|
||||
<div class="steps-item__name" id="stepSignName">签署承诺</div>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 活动说明 -->
|
||||
<div class="intro">
|
||||
<div class="intro__title">体重管理活动说明</div>
|
||||
<div class="intro__body">
|
||||
<p>健康体重,一起行动!欢迎您参加体重管理活动,您和运动等生活习惯方面改变的一小步,将使您的健康状况改善一大步!</p>
|
||||
<p>根据最新体检数据和《集团公司体重管理指导手册》内超重和肥胖相关的判定标准,您当前的体重是:<span class="intro__hi" id="introCurWeight">--kg</span>,您的目标体重是:<span class="intro__hi" id="introTgtWeight">--kg</span>,您当前的体脂是:<span class="intro__hi" id="introCurFat">--%</span>,您的目标体脂是:<span class="intro__hi" id="introTgtFat">--%</span>,您当前的腰围是:<span class="intro__hi" id="introCurWaist">--cm</span>,您的目标腰围是:<span class="intro__hi" id="introTgtWaist">--cm</span>,为达到标准体重,您应减重:<span class="intro__hi" id="introLoseWeight">--kg</span>,共需 <span class="intro__hi" id="introDays">--</span> 天。如您有基础疾病或其他身体特殊状况,请及时联系本单位健康管理员,并调整减重目标。<span class="intro__warn">如您有以下禁忌症,不建议您参加本次体重管理活动:</span><a href="contraindications.html" class="intro__warn-link">点击查看禁忌证详情。</a></p>
|
||||
<p>为使您的体重异常状况得到显著改善,有效降低心脑血管疾病、糖尿病等患病风险,您应在本次活动中应参考膳食和运动处方指导,实时关注自身体重和体脂率,结合个人情况,按时完成以下打卡。</p>
|
||||
</div>
|
||||
<div class="intro__attach">附件:<a class="intro__attach-link" href="javascript:void(0)" onclick="alert('打开《体重管理指导原则》')">《体重管理指导原则》</a></div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- 驳回原因弹窗 -->
|
||||
<div class="reason-mask" id="reasonMask" onclick="closeReasonModal(event)">
|
||||
<div class="reason" onclick="event.stopPropagation()">
|
||||
<div class="reason__title">驳回原因</div>
|
||||
<div class="reason__body">您设置的目标体重(59kg)与基础代谢及减重周期不匹配,建议在 14 周内分阶段减重,目标体重不低于 62kg;目标体脂率请控制在 18% 以上,避免过度消耗。</div>
|
||||
<div class="reason__meta">
|
||||
<span>审核人:张管理员</span>
|
||||
<span>2025-02-08 14:32</span>
|
||||
</div>
|
||||
<button class="reason__btn" onclick="goAdjust()">去调整</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
function toggleTypeMenu(e) {
|
||||
if (e) e.stopPropagation();
|
||||
document.getElementById('typeMenu').classList.toggle('show');
|
||||
}
|
||||
|
||||
document.addEventListener('click', function(){
|
||||
document.getElementById('typeMenu').classList.remove('show');
|
||||
});
|
||||
|
||||
var STATUS_MAP = {
|
||||
'unset-noact': { activity:false, tip:true, tipText:'请先前往目标管理页面确定目标', progress:false, label:'', status:'', introData:false },
|
||||
'unset-hasact': { activity:true, tip:true, tipText:'请前往目标管理页面确认数据并提交审核', progress:false, label:'', status:'', introData:false },
|
||||
personal: { activity:false, tip:false, progress:true, label:'您当前已设置个人目标', status:'', introData:true },
|
||||
wait: { activity:true, tip:false, progress:true, label:'您当前参与单位活动', status:'<span class="card-status--wait">管理员审核中,请耐心等待...</span>', introData:false },
|
||||
pass: { activity:true, tip:false, progress:true, label:'您当前参与单位活动', status:'<span class="card-status--pass">管理员已审核通过,请尽快签订承诺书参加活动</span>', introData:false },
|
||||
reject: { activity:true, tip:false, progress:true, label:'您当前参与单位活动', status:'<span class="card-status--reject">管理员审核驳回,<a class="card-status__link" onclick="openReasonModal()">查看原因</a>,请重新调整目标</span>', introData:false },
|
||||
signed: { activity:true, tip:false, progress:true, label:'您当前参与单位活动', status:'', signedStep:true, introData:true }
|
||||
};
|
||||
|
||||
// 活动说明区模拟数据
|
||||
var INTRO_VALUES = {
|
||||
curWeight:'90kg', tgtWeight:'77kg', curFat:'28%', tgtFat:'25%', curWaist:'100cm', tgtWaist:'86cm', loseWeight:'13kg', days:'90'
|
||||
};
|
||||
|
||||
/* 右上角菜单切换类型 → 跳转刷新页面,URL 同步更新 */
|
||||
function setGoalType(type) {
|
||||
location.href = 'goal-commitment.html?type=' + type;
|
||||
}
|
||||
|
||||
/* 页面加载后根据 type 参数初始化 UI 状态 */
|
||||
function applyGoalTypeState(type) {
|
||||
var cfg = STATUS_MAP[type];
|
||||
if (!cfg) return;
|
||||
document.getElementById('cardActivity').style.display = cfg.activity ? 'block' : 'none';
|
||||
document.getElementById('cardTip').style.display = cfg.tip ? 'block' : 'none';
|
||||
if (cfg.tip) document.getElementById('cardTip').textContent = cfg.tipText || '请先完成目标管理,再签订活动承诺书!';
|
||||
document.getElementById('cardProgress').style.display = cfg.progress ? 'flex' : 'none';
|
||||
document.getElementById('cardTargets').style.display = cfg.progress ? 'flex' : 'none';
|
||||
if (cfg.label) document.getElementById('cardProgressLabel').textContent = cfg.label;
|
||||
var statusEl = document.getElementById('cardStatus');
|
||||
if (cfg.status) {
|
||||
statusEl.style.display = 'block';
|
||||
statusEl.innerHTML = cfg.status;
|
||||
} else {
|
||||
statusEl.style.display = 'none';
|
||||
statusEl.innerHTML = '';
|
||||
}
|
||||
// 签署承诺步骤 ✅ 标记
|
||||
var nameEl = document.getElementById('stepSignName');
|
||||
if (nameEl) {
|
||||
var stepText = cfg.signedStep ? '我的承诺' : '签署承诺';
|
||||
if (cfg.signedStep) {
|
||||
nameEl.className = 'steps-item__name steps-item__name--signed';
|
||||
nameEl.innerHTML = '<svg class="steps-item__check-icon" viewBox="0 0 16 16" fill="none" stroke="#1f9d8f" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="3,8.5 6.5,12 13,4"/></svg>' + stepText;
|
||||
} else {
|
||||
nameEl.className = 'steps-item__name';
|
||||
nameEl.innerHTML = stepText;
|
||||
}
|
||||
}
|
||||
// 签署承诺跳转链接
|
||||
var linkEl = document.getElementById('stepSignLink');
|
||||
if (linkEl) linkEl.href = cfg.signedStep ? 'my-promise.html' : 'promise-signing.html';
|
||||
// 活动说明区数据填充
|
||||
var d = INTRO_VALUES;
|
||||
if (cfg.introData) {
|
||||
document.getElementById('introCurWeight').textContent = d.curWeight;
|
||||
document.getElementById('introTgtWeight').textContent = d.tgtWeight;
|
||||
document.getElementById('introCurFat').textContent = d.curFat;
|
||||
document.getElementById('introTgtFat').textContent = d.tgtFat;
|
||||
document.getElementById('introCurWaist').textContent = d.curWaist;
|
||||
document.getElementById('introTgtWaist').textContent = d.tgtWaist;
|
||||
document.getElementById('introLoseWeight').textContent = d.loseWeight;
|
||||
document.getElementById('introDays').textContent = d.days;
|
||||
} else {
|
||||
// 恢复占位符
|
||||
document.getElementById('introCurWeight').textContent = '--kg';
|
||||
document.getElementById('introTgtWeight').textContent = '--kg';
|
||||
document.getElementById('introCurFat').textContent = '--%';
|
||||
document.getElementById('introTgtFat').textContent = '--%';
|
||||
document.getElementById('introCurWaist').textContent = '--cm';
|
||||
document.getElementById('introTgtWaist').textContent = '--cm';
|
||||
document.getElementById('introLoseWeight').textContent = '--kg';
|
||||
document.getElementById('introDays').textContent = '--';
|
||||
}
|
||||
// 高亮当前类型菜单项
|
||||
document.querySelectorAll('.nav-menu__item').forEach(function(el){
|
||||
el.classList.toggle('active', el.dataset.type === type);
|
||||
});
|
||||
}
|
||||
|
||||
// 优先读取 URL 参数中的状态,否则默认未选目标-无活动
|
||||
function getQueryParam(key) {
|
||||
var params = window.location.search.slice(1).split('&');
|
||||
for (var i = 0; i < params.length; i++) {
|
||||
var pair = params[i].split('=');
|
||||
if (pair[0] === key) return decodeURIComponent(pair[1] || '');
|
||||
}
|
||||
return '';
|
||||
}
|
||||
var defaultType = getQueryParam('type') || 'unset-hasact';
|
||||
applyGoalTypeState(defaultType);
|
||||
document.getElementById('goalMgmtLink').href = 'goal-management.html?type=' + defaultType;
|
||||
|
||||
function openReasonModal() {
|
||||
document.getElementById('reasonMask').classList.add('show');
|
||||
}
|
||||
function closeReasonModal(e) {
|
||||
if (e && e.target !== e.currentTarget) return;
|
||||
document.getElementById('reasonMask').classList.remove('show');
|
||||
}
|
||||
function goAdjust() {
|
||||
window.location.href = 'goal-management.html?type=' + defaultType;
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,862 +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: #f4f6f7; 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; }
|
||||
.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; margin-right: 28px; }
|
||||
.nav-more { width: 28px; height: 28px; display: flex; align-items: center; justify-content: center; cursor: pointer; color: #1a1a1a; flex-shrink: 0; }
|
||||
.nav-menu { position: absolute; top: 44px; right: 12px; background: #fff; border-radius: 12px; box-shadow: 0 8px 24px rgba(0,0,0,0.15); padding: 6px 0; min-width: 180px; z-index: 30; display: none; }
|
||||
.nav-menu.show { display: block; }
|
||||
.nav-menu__item { padding: 11px 18px; font-size: 14px; color: #1a1a1a; cursor: pointer; display: flex; align-items: center; justify-content: space-between; }
|
||||
.nav-menu__item:hover { background: #f5f7fa; }
|
||||
.nav-menu__item.active { color: #1f9d8f; font-weight: 600; }
|
||||
.nav-menu__item.active::after { content: '✓'; color: #1f9d8f; font-size: 13px; font-weight: 700; }
|
||||
.scroll-content { flex: 1; overflow-y: auto; background: #f4f6f7; padding-bottom: 16px; }
|
||||
.scroll-content::-webkit-scrollbar { display: none; }
|
||||
|
||||
/* 通用卡片 */
|
||||
.gm-card { background: #fff; border-radius: 12px; margin: 10px 12px 0; padding: 14px; transition: opacity 0.2s; }
|
||||
.gm-card--selectable { cursor: pointer; border: 1.5px solid transparent; }
|
||||
.gm-card--active { border-color: #36cfc9; }
|
||||
.gm-card--active .gm-card__title-icon { display: inline-flex; }
|
||||
.gm-card--disabled { opacity: 0.5; }
|
||||
.gm-card--disabled .gm-select,
|
||||
.gm-card--disabled .gm-input,
|
||||
.gm-card--disabled .gm-btn-action { pointer-events: none; }
|
||||
.gm-card--disabled .gm-card__title-icon { display: none; }
|
||||
.gm-card__hd { display: flex; align-items: center; justify-content: space-between; margin-bottom: 10px; }
|
||||
.gm-card__title { font-size: 14px; font-weight: 700; color: #1a1a1a; }
|
||||
.gm-card__title-icon { width: 14px; height: 14px; display: none; align-items: center; justify-content: center; background: #36cfc9; color: #fff; border-radius: 50%; margin-left: 6px; vertical-align: middle; }
|
||||
.gm-card__title-icon svg { width: 10px; height: 10px; stroke: #fff; stroke-width: 3; fill: none; }
|
||||
.gm-card__more { font-size: 12px; color: #1f86ff; cursor: pointer; }
|
||||
|
||||
/* 自我管理天数输入 */
|
||||
.gm-self-days { display: inline-flex; align-items: center; gap: 2px; }
|
||||
.gm-self-days__input { width: 48px; height: 24px; padding: 0 6px; background: #f5f7fa; border: none; border-radius: 4px; font-size: 13px; font-weight: 700; color: #36cfc9; text-align: center; outline: none; }
|
||||
|
||||
/* 下拉选择 */
|
||||
.gm-select { display: flex; align-items: center; justify-content: space-between; height: 38px; padding: 0 12px; background: #f5f7fa; border-radius: 6px; font-size: 13px; color: #999; cursor: pointer; }
|
||||
.gm-select--filled { color: #1a1a1a; font-weight: 600; }
|
||||
.gm-select__arrow { color: #bbb; font-size: 12px; }
|
||||
|
||||
/* 活动选择底部弹窗 */
|
||||
.act-mask { position: absolute; inset: 0; background: rgba(0,0,0,0.4); z-index: 30; opacity: 0; pointer-events: none; transition: opacity 0.25s; }
|
||||
.act-mask.show { opacity: 1; pointer-events: auto; }
|
||||
.act-sheet { position: absolute; left: 0; right: 0; bottom: 0; background: #fff; border-radius: 16px 16px 0 0; z-index: 31; padding: 10px 0 18px; transform: translateY(100%); transition: transform 0.3s; max-height: 70%; display: flex; flex-direction: column; }
|
||||
.act-sheet.show { transform: translateY(0); }
|
||||
.act-sheet__handle { width: 38px; height: 4px; background: #d8dde3; border-radius: 2px; margin: 0 auto 8px; }
|
||||
.act-sheet__title { font-size: 16px; font-weight: 700; color: #1a1a1a; text-align: center; padding: 6px 0 12px; border-bottom: 1px solid #f1f3f5; }
|
||||
.act-sheet__list { flex: 1; overflow-y: auto; padding: 4px 0; }
|
||||
.act-sheet__list::-webkit-scrollbar { display: none; }
|
||||
.act-item { padding: 14px 18px; border-bottom: 1px solid #f5f7fa; display: flex; align-items: center; justify-content: space-between; cursor: pointer; }
|
||||
.act-item__main { flex: 1; min-width: 0; }
|
||||
.act-item__name { font-size: 14px; font-weight: 600; color: #1a1a1a; }
|
||||
.act-item__period { font-size: 12px; color: #999; margin-top: 4px; }
|
||||
.act-item__check { color: #36cfc9; font-weight: 800; opacity: 0; }
|
||||
.act-item.selected .act-item__check { opacity: 1; }
|
||||
.act-sheet__empty { padding: 48px 0; text-align: center; font-size: 14px; color: #c8d0d8; }
|
||||
.act-sheet__confirm-bar { padding: 12px 16px 0; }
|
||||
.act-sheet__confirm { display: block; width: 100%; height: 42px; background: #36cfc9; color: #fff; border: none; border-radius: 21px; font-size: 15px; font-weight: 600; cursor: pointer; letter-spacing: 4px; }
|
||||
|
||||
/* 输入 + 按钮 */
|
||||
.gm-input-row { display: flex; gap: 8px; align-items: center; }
|
||||
.gm-input { flex: 1; height: 38px; padding: 0 12px; background: #f5f7fa; border-radius: 6px; border: none; font-size: 13px; color: #333; outline: none; }
|
||||
.gm-input::placeholder { color: #b8b8b8; }
|
||||
.gm-btn-action { height: 38px; padding: 0 14px; background: #36cfc9; color: #fff; border: none; border-radius: 6px; font-size: 13px; font-weight: 600; cursor: pointer; transition: background 0.2s; }
|
||||
.gm-btn-action:disabled, .gm-btn-action.is-disabled { background: #c8d0d8; color: #fff; cursor: not-allowed; }
|
||||
|
||||
/* 三列基本信息 */
|
||||
.gm-info-row { display: flex; justify-content: space-between; padding-top: 6px; }
|
||||
.gm-info-cell { flex: 1; text-align: center; }
|
||||
.gm-info-cell__value { font-size: 18px; font-weight: 700; color: #1a1a1a; }
|
||||
.gm-info-cell__label { font-size: 12px; color: #999; margin-top: 4px; }
|
||||
|
||||
/* 数据录入行 */
|
||||
.gm-data-row { display: flex; align-items: center; gap: 8px; padding: 10px 0; border-top: 1px dashed #f0f0f0; }
|
||||
.gm-data-row:first-of-type { border-top: none; padding-top: 4px; }
|
||||
.gm-data-row__label { width: 72px; font-size: 13px; color: #333; flex-shrink: 0; }
|
||||
.gm-data-row__input { flex: 1; height: 36px; padding: 0 12px; background: #f5f7fa; border-radius: 6px; border: none; font-size: 14px; font-weight: 600; color: #333; outline: none; min-width: 0; }
|
||||
.gm-data-row__sources { display: flex; gap: 6px; flex-shrink: 0; }
|
||||
.gm-chip { padding: 6px 10px; border-radius: 6px; background: #f0f2f5; color: #777; font-size: 12px; cursor: pointer; border: 1px solid transparent; }
|
||||
.gm-chip.active { background: #1f86ff; color: #fff; border-color: #1f86ff; }
|
||||
.gm-chip--cyan.active { background: #36cfc9; border-color: #36cfc9; }
|
||||
|
||||
/* 人群结果(自动计算) */
|
||||
.gm-group { display: flex; align-items: center; gap: 8px; padding: 6px 0 2px; }
|
||||
.gm-group__label { font-size: 13px; color: #9aa3ad; font-weight: 500; flex-shrink: 0; }
|
||||
.gm-group__tag { display: inline-block; padding: 4px 14px; border-radius: 14px; background: #e6fffb; color: #36cfc9; font-size: 13px; font-weight: 700; border: 1px solid #36cfc9; }
|
||||
.gm-group__source { font-size: 12px; color: #c8cdd3; margin-left: auto; }
|
||||
|
||||
/* 主按钮 */
|
||||
.gm-cta { display: block; width: calc(100% - 24px); margin: 14px 12px 0; height: 44px; background: linear-gradient(135deg, #36cfc9, #1890ff); color: #fff; border: none; border-radius: 22px; font-size: 15px; font-weight: 600; cursor: pointer; }
|
||||
|
||||
/* 目标设定 */
|
||||
.gm-target-row { display: flex; align-items: center; justify-content: space-between; padding: 10px 0; border-top: 1px dashed #f0f0f0; gap: 8px; }
|
||||
.gm-target-row:first-of-type { border-top: none; padding-top: 4px; }
|
||||
.gm-target-row__main { flex: 1; min-width: 0; }
|
||||
.gm-target-row__label { font-size: 13px; color: #333; }
|
||||
.gm-target-row__value { font-size: 16px; font-weight: 700; color: #36cfc9; margin: 0 4px; }
|
||||
.gm-target-row__tip { font-size: 11px; color: #999; }
|
||||
.gm-target-row__tip-warn { font-size: 11px; color: #f5222d; margin-top: 4px; }
|
||||
.gm-target-row__edit { color: #36cfc9; font-size: 13px; cursor: pointer; font-weight: 600; flex-shrink: 0; }
|
||||
|
||||
/* 任务列表 */
|
||||
.gm-task-card { background: #fff; border-radius: 12px; margin: 10px 12px 0; padding: 14px 14px 16px; position: relative; }
|
||||
.gm-task-card::before { content: ''; position: absolute; left: 0; right: 0; top: -10px; height: 14px; background: radial-gradient(circle, #fff 4px, transparent 4.5px); background-size: 14px 14px; background-position: 0 0; }
|
||||
.gm-task-card__title { text-align: center; font-size: 14px; font-weight: 700; color: #1a1a1a; margin-bottom: 12px; }
|
||||
.gm-task-card__item { font-size: 13px; color: #333; line-height: 1.9; }
|
||||
.gm-task-card__item strong { color: #1a1a1a; font-weight: 700; }
|
||||
|
||||
/* 底部按钮组 */
|
||||
.gm-action-row { display: flex; gap: 10px; margin: 14px 12px 12px; }
|
||||
.gm-action-row__btn { flex: 1; height: 38px; border: 1px solid #36cfc9; background: #fff; color: #36cfc9; border-radius: 19px; font-size: 13px; font-weight: 600; cursor: pointer; }
|
||||
.gm-action-row__btn--primary { background: #36cfc9; color: #fff; }
|
||||
|
||||
/* 目标修改底部弹窗(滚轮标尺) */
|
||||
.target-mask { position: absolute; inset: 0; background: rgba(0,0,0,0.4); z-index: 40; opacity: 0; pointer-events: none; transition: opacity 0.25s; }
|
||||
.target-mask.show { opacity: 1; pointer-events: auto; }
|
||||
.target-sheet { position: absolute; left: 0; right: 0; bottom: 0; background: #fff; border-radius: 20px 20px 0 0; z-index: 41; padding: 10px 0 22px; transform: translateY(100%); transition: transform 0.3s ease; max-height: 88%; display: flex; flex-direction: column; }
|
||||
.target-sheet.show { transform: translateY(0); }
|
||||
.target-sheet__handle { width: 40px; height: 4px; background: #d8dde3; border-radius: 2px; margin: 0 auto 8px; flex-shrink: 0; }
|
||||
.target-sheet__head { display: flex; align-items: center; gap: 12px; padding: 8px 22px 16px; border-bottom: 1px solid #f1f3f5; flex-shrink: 0; }
|
||||
.target-sheet__icon { width: 40px; height: 40px; border-radius: 10px; display: flex; align-items: center; justify-content: center; flex-shrink: 0; }
|
||||
.target-sheet__icon svg { width: 22px; height: 22px; }
|
||||
.target-sheet__meta { flex: 1; min-width: 0; }
|
||||
.target-sheet__title { font-size: 17px; font-weight: 700; color: #1a1a1a; }
|
||||
.target-sheet__hint { font-size: 13px; color: #9aa3ad; margin-top: 4px; }
|
||||
.target-sheet__body { flex: 1; overflow-y: auto; padding: 8px 0 12px; }
|
||||
.target-sheet__body::-webkit-scrollbar { display: none; }
|
||||
|
||||
/* 测量字段 */
|
||||
.target-field { padding: 18px 16px 8px; position: relative; }
|
||||
.target-field__value { text-align: center; margin: 22px 0 16px; min-height: 44px; }
|
||||
.target-field__num { font-size: 40px; font-weight: 800; color: #1a1a1a; letter-spacing: 1px; }
|
||||
.target-field__unit { font-size: 14px; color: #9aa3ad; margin-left: 8px; vertical-align: middle; }
|
||||
|
||||
/* 标尺 */
|
||||
.target-ruler { position: relative; height: 64px; margin: 0 16px; }
|
||||
.target-ruler__pointer { position: absolute; left: 50%; top: 0; transform: translateX(-50%); display: flex; flex-direction: column; align-items: center; z-index: 2; }
|
||||
.target-ruler__pointer-flag { width: 0; height: 0; border-left: 7px solid transparent; border-right: 7px solid transparent; border-top: 9px solid #4dc4b6; }
|
||||
.target-ruler__pointer-line { width: 2px; height: 22px; background: #4dc4b6; margin-top: -1px; }
|
||||
.target-ruler__scale { position: absolute; left: 0; right: 0; top: 16px; height: 22px; }
|
||||
.target-ruler__tick { position: absolute; bottom: 0; width: 1px; background: #b6e3dd; }
|
||||
.target-ruler__tick--minor { height: 8px; }
|
||||
.target-ruler__tick--major { height: 16px; }
|
||||
.target-ruler__tick--right { background: #ffd9a8; }
|
||||
.target-ruler__labels { position: absolute; left: 0; right: 0; top: 42px; height: 16px; font-size: 12px; color: #9aa3ad; }
|
||||
.target-ruler__label { position: absolute; transform: translateX(-50%); }
|
||||
|
||||
.target-sheet__submit-bar { padding: 14px 16px 0; flex-shrink: 0; }
|
||||
.target-sheet__submit { display: block; width: 100%; height: 46px; background: linear-gradient(135deg, #4dc4b6 0%, #46b8af 100%); color: #fff; border: none; border-radius: 23px; font-size: 16px; font-weight: 600; cursor: pointer; letter-spacing: 6px; }
|
||||
|
||||
/* 提交确认弹窗(中央卡片) */
|
||||
.confirm-mask { position: absolute; inset: 0; background: rgba(0,0,0,0.45); z-index: 50; opacity: 0; pointer-events: none; transition: opacity 0.2s; display: flex; align-items: center; justify-content: center; padding: 0 28px; }
|
||||
.confirm-mask.show { opacity: 1; pointer-events: auto; }
|
||||
.confirm-card { width: 100%; background: #fff; border-radius: 16px; padding: 24px 22px 20px; transform: scale(0.95); transition: transform 0.2s; }
|
||||
.confirm-mask.show .confirm-card { transform: scale(1); }
|
||||
.confirm-card__title { font-size: 17px; font-weight: 800; color: #1a1a1a; text-align: center; margin-bottom: 10px; }
|
||||
.confirm-card__msg { font-size: 14px; color: #333; text-align: center; line-height: 1.7; margin-bottom: 20px; }
|
||||
.confirm-card__btns { display: flex; gap: 12px; }
|
||||
.confirm-card__btn { flex: 1; height: 42px; border: none; border-radius: 21px; font-size: 15px; font-weight: 600; cursor: pointer; }
|
||||
.confirm-card__btn--cancel { background: #f0f2f5; color: #999; }
|
||||
.confirm-card__btn--confirm { background: linear-gradient(135deg, #4dc4b6 0%, #46b8af 100%); color: #fff; }
|
||||
|
||||
/* 状态提示栏 */
|
||||
.gm-status-bar { margin: 10px 12px 0; padding: 12px 16px; background: #fff; border-radius: 12px; font-size: 13px; font-weight: 600; text-align: center; display: none; }
|
||||
.gm-status-bar--wait { color: #faad14; }
|
||||
.gm-status-bar--pass { color: #1f9d8f; }
|
||||
.gm-status-bar--reject { color: #ff4d4f; }
|
||||
.gm-status-bar--reject .gm-status-bar__link { color: #ff4d4f; text-decoration: underline; cursor: pointer; }
|
||||
.gm-status-bar--signed { color: #1f9d8f; }
|
||||
|
||||
/* 驳回原因弹窗 */
|
||||
.reject-mask { position: absolute; inset: 0; background: rgba(0,0,0,0.45); z-index: 55; opacity: 0; pointer-events: none; transition: opacity 0.2s; display: flex; align-items: center; justify-content: center; padding: 0 28px; }
|
||||
.reject-mask.show { opacity: 1; pointer-events: auto; }
|
||||
.reject-card { width: 100%; background: #fff; border-radius: 14px; padding: 22px 22px 18px; transform: scale(0.95); transition: transform 0.2s; }
|
||||
.reject-mask.show .reject-card { transform: scale(1); }
|
||||
.reject-card__title { font-size: 17px; font-weight: 800; color: #1a1a1a; text-align: center; margin-bottom: 14px; }
|
||||
.reject-card__body { font-size: 14px; line-height: 1.7; color: #333; background: #fff5f5; border-left: 3px solid #ff4d4f; border-radius: 6px; padding: 12px 14px; margin-bottom: 16px; }
|
||||
.reject-card__meta { display: flex; justify-content: space-between; font-size: 12px; color: #9aa3ad; margin-bottom: 16px; }
|
||||
.reject-card__btn { display: block; width: 100%; height: 42px; background: linear-gradient(135deg, #4dc4b6 0%, #46b8af 100%); color: #fff; border: none; border-radius: 21px; font-size: 15px; font-weight: 600; cursor: pointer; letter-spacing: 4px; }
|
||||
|
||||
/* 锁定态 */
|
||||
.gm-locked .gm-data-row__input { pointer-events: none; background: #f0f2f5; color: #999; }
|
||||
.gm-locked .gm-chip { pointer-events: none; }
|
||||
.gm-locked .gm-target-row__edit { pointer-events: none; color: #c8d0d8; }
|
||||
.gm-locked .gm-card__more { pointer-events: none; }
|
||||
.gm-locked .gm-self-days__input { pointer-events: none; }
|
||||
.gm-locked #selfNameInput { pointer-events: none; background: #f0f2f5; color: #999; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="phone-shell">
|
||||
<div class="status-bar">
|
||||
<span class="time">12:00</span>
|
||||
<div class="icons">
|
||||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="#333" stroke-width="2"><path d="M1 6l5 5 5-5"/><path d="M4 9l3 3 3-3" opacity="0.5"/></svg>
|
||||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="#333" stroke-width="2"><rect x="1" y="6" width="18" height="12" rx="2"/><path d="M21 10v4"/></svg>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-bar">
|
||||
<div class="nav-back" onclick="location.href='goal-commitment.html?type=' + (getQueryParam('type') || 'unset-hasact')">
|
||||
<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"/></svg>
|
||||
</div>
|
||||
<div class="nav-title">目标管理</div>
|
||||
<div class="nav-more" onclick="toggleTypeMenu(event)">
|
||||
<svg width="22" height="22" viewBox="0 0 24 24" fill="currentColor"><circle cx="5" cy="12" r="2"/><circle cx="12" cy="12" r="2"/><circle cx="19" cy="12" r="2"/></svg>
|
||||
</div>
|
||||
<div class="nav-menu" id="typeMenu">
|
||||
<div class="nav-menu__item" data-type="unset-noact" onclick="setGoalType('unset-noact')">未选目标 - 无活动</div>
|
||||
<div class="nav-menu__item" data-type="unset-hasact" onclick="setGoalType('unset-hasact')">未选目标 - 有活动</div>
|
||||
<div class="nav-menu__item" data-type="personal" onclick="setGoalType('personal')">已选个人目标</div>
|
||||
<div class="nav-menu__item" data-type="wait" onclick="setGoalType('wait')">单位活动 - 待审核</div>
|
||||
<div class="nav-menu__item" data-type="pass" onclick="setGoalType('pass')">单位活动 - 审核通过</div>
|
||||
<div class="nav-menu__item" data-type="reject" onclick="setGoalType('reject')">单位活动 - 已驳回</div>
|
||||
<div class="nav-menu__item" data-type="signed" onclick="setGoalType('signed')">单位活动 - 已签署承诺书</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="scroll-content">
|
||||
<!-- 活动目标管理 -->
|
||||
<div class="gm-card gm-card--selectable" id="cardActivity" onclick="selectMode('activity')">
|
||||
<div class="gm-card__hd">
|
||||
<div>
|
||||
<span class="gm-card__title">活动目标管理</span>
|
||||
<span class="gm-card__title-icon" id="checkActivity">
|
||||
<svg viewBox="0 0 12 12"><polyline points="2,6.5 5,9.5 10,3"/></svg>
|
||||
</span>
|
||||
</div>
|
||||
<span class="gm-card__more" id="actDetailLink" onclick="event.stopPropagation(); location.href='activity-detail.html'">查看活动详情 ›</span>
|
||||
</div>
|
||||
<div class="gm-select gm-select--filled" id="actSelect" onclick="event.stopPropagation(); openActSheet()">
|
||||
<span id="actSelectText">公共事务中心2026年二季度体重管理</span>
|
||||
<span class="gm-select__arrow">▾</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 自我目标管理 -->
|
||||
<div class="gm-card gm-card--selectable" id="cardSelf" onclick="selectMode('self')">
|
||||
<div class="gm-card__hd">
|
||||
<div>
|
||||
<span class="gm-card__title">自我目标管理</span>
|
||||
<span class="gm-card__title-icon" id="checkSelf">
|
||||
<svg viewBox="0 0 12 12"><polyline points="2,6.5 5,9.5 10,3"/></svg>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="gm-input-row">
|
||||
<input class="gm-input" id="selfNameInput" placeholder="请给您的减重行动取一个名字" onclick="event.stopPropagation()">
|
||||
<button class="gm-btn-action" id="selfNameBtn" onclick="event.stopPropagation(); alert('已为您起名')">自动起名</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 个人信息 -->
|
||||
<div class="gm-card">
|
||||
<div class="gm-card__hd">
|
||||
<span class="gm-card__title">个人信息</span>
|
||||
<span class="gm-card__more" onclick="location.href='basic-info.html'">完善基本信息 ›</span>
|
||||
</div>
|
||||
<div class="gm-info-row">
|
||||
<div class="gm-info-cell">
|
||||
<div class="gm-info-cell__value">--</div>
|
||||
<div class="gm-info-cell__label">身高</div>
|
||||
</div>
|
||||
<div class="gm-info-cell">
|
||||
<div class="gm-info-cell__value">男</div>
|
||||
<div class="gm-info-cell__label">性别</div>
|
||||
</div>
|
||||
<div class="gm-info-cell">
|
||||
<div class="gm-info-cell__value">36</div>
|
||||
<div class="gm-info-cell__label">年龄</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 初始数据录入 -->
|
||||
<div class="gm-card">
|
||||
<div class="gm-card__hd">
|
||||
<span class="gm-card__title">初始数据录入</span>
|
||||
</div>
|
||||
<div class="gm-data-row">
|
||||
<span class="gm-data-row__label">初始体重:</span>
|
||||
<input class="gm-data-row__input" value="90 kg" readonly>
|
||||
<div class="gm-data-row__sources">
|
||||
<span class="gm-chip">身高秤</span>
|
||||
<span class="gm-chip">蓝牙秤</span>
|
||||
<span class="gm-chip active">自记</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="gm-data-row">
|
||||
<span class="gm-data-row__label">初始体脂:</span>
|
||||
<input class="gm-data-row__input" value="28 %" readonly>
|
||||
<div class="gm-data-row__sources">
|
||||
<span class="gm-chip">身高秤</span>
|
||||
<span class="gm-chip">蓝牙秤</span>
|
||||
<span class="gm-chip active">自记</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="gm-data-row">
|
||||
<span class="gm-data-row__label">初始腰围:</span>
|
||||
<input class="gm-data-row__input" value="100 cm" readonly>
|
||||
<div class="gm-data-row__sources">
|
||||
<span class="gm-chip active">自记</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 人群计算结果 -->
|
||||
<div class="gm-card">
|
||||
<div class="gm-group">
|
||||
<span class="gm-group__label">您属于:</span>
|
||||
<span class="gm-group__tag" id="groupTag">减重人群</span>
|
||||
<span class="gm-group__source">根据初始数据自动计算</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 开始计算按钮 -->
|
||||
<button class="gm-cta" onclick="alert('开始计算目标')">开始计算</button>
|
||||
|
||||
<!-- 目标设定 -->
|
||||
<div class="gm-card">
|
||||
<div class="gm-card__hd">
|
||||
<span class="gm-card__title">目标设定</span>
|
||||
<span class="gm-card__more" style="color:#999;" id="actDays">参加活动天数:90 天</span>
|
||||
<span class="gm-self-days" id="selfDays" style="display:none;"><span style="font-size:12px;color:#999;">自我管理天数:</span><input class="gm-self-days__input" id="selfDaysInput" value="30" type="number" min="1"><span style="font-size:12px;color:#999;"> 天</span></span>
|
||||
</div>
|
||||
<div class="gm-target-row">
|
||||
<div class="gm-target-row__main">
|
||||
<span class="gm-target-row__label">目标体重:</span>
|
||||
<span class="gm-target-row__value" id="targetWeightValue">59 kg</span>
|
||||
<span class="gm-target-row__tip">(系统推荐 60~85kg)</span>
|
||||
<div class="gm-target-row__tip-warn">当前体重不符合健康减重规律</div>
|
||||
</div>
|
||||
<span class="gm-target-row__edit" onclick="openTargetSheet('targetWeight')">修改</span>
|
||||
</div>
|
||||
<div class="gm-target-row">
|
||||
<div class="gm-target-row__main">
|
||||
<span class="gm-target-row__label">目标体脂:</span>
|
||||
<span class="gm-target-row__value" id="targetFatValue">25 %</span>
|
||||
<span class="gm-target-row__tip">(系统推荐 23~28%)</span>
|
||||
</div>
|
||||
<span class="gm-target-row__edit" onclick="openTargetSheet('targetFat')">修改</span>
|
||||
</div>
|
||||
<div class="gm-target-row">
|
||||
<div class="gm-target-row__main">
|
||||
<span class="gm-target-row__label">目标腰围:</span>
|
||||
<span class="gm-target-row__value" id="targetWaistValue">86 cm</span>
|
||||
<span class="gm-target-row__tip">(系统推荐 65~94cm)</span>
|
||||
</div>
|
||||
<span class="gm-target-row__edit" onclick="openTargetSheet('targetWaist')">修改</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 您将要完成的任务 -->
|
||||
<div class="gm-task-card">
|
||||
<div class="gm-task-card__title">您将要完成的任务</div>
|
||||
<div class="gm-task-card__item">• <strong>目标</strong>:体重 85kg 减至 77kg</div>
|
||||
<div class="gm-task-card__item">• <strong>时间</strong>:2025年4月1日 至 2025年6月30日,共 90 天</div>
|
||||
<div class="gm-task-card__item">• <strong>减重</strong>:您共需减重 8kg</div>
|
||||
<div class="gm-task-card__item">• <strong>平均</strong>:日均减重 0.10kg,周均减重 0.625kg</div>
|
||||
<div class="gm-task-card__item">• <strong>饮食</strong>:日均少摄入 350 千卡,相当于少吃 100g 米饭</div>
|
||||
<div class="gm-task-card__item">• <strong>运动</strong>:日均多消耗 600 千卡,相当于快走 12000 步</div>
|
||||
</div>
|
||||
|
||||
<!-- 状态提示栏 -->
|
||||
<div class="gm-status-bar" id="statusBar"></div>
|
||||
|
||||
<!-- 底部按钮 -->
|
||||
<div class="gm-action-row" id="actionRow">
|
||||
<button class="gm-action-row__btn gm-action-row__btn--primary" id="btnSubmitReview" onclick="openConfirm()">提交审核</button>
|
||||
<button class="gm-action-row__btn gm-action-row__btn--primary" id="btnConfirmGoal" onclick="openPersonalConfirm()">确定目标</button>
|
||||
<button class="gm-action-row__btn gm-action-row__btn--primary" id="btnResubmit" style="display:none;" onclick="openConfirm()">重新提交</button>
|
||||
</div>
|
||||
<div class="gm-action-row" id="btnModifyRow" style="display:none;margin:14px 12px 12px;">
|
||||
<button class="gm-action-row__btn gm-action-row__btn--primary" style="flex:1;" onclick="unlockPersonal()">修改目标</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 目标修改底部弹窗 -->
|
||||
<div class="target-mask" id="targetMask" onclick="closeTargetSheet()">
|
||||
<div class="target-sheet" onclick="event.stopPropagation()">
|
||||
<div class="target-sheet__handle"></div>
|
||||
<div class="target-sheet__head">
|
||||
<div class="target-sheet__icon" id="targetSheetIcon"></div>
|
||||
<div class="target-sheet__meta">
|
||||
<div class="target-sheet__title" id="targetSheetTitle">目标体重</div>
|
||||
<div class="target-sheet__hint" id="targetSheetHint">请设置您的目标值</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="target-sheet__body">
|
||||
<div class="target-field">
|
||||
<div class="target-field__value">
|
||||
<span class="target-field__num" id="targetNum">59</span>
|
||||
<span class="target-field__unit" id="targetUnit">kg</span>
|
||||
</div>
|
||||
<div class="target-ruler">
|
||||
<div class="target-ruler__pointer">
|
||||
<div class="target-ruler__pointer-flag"></div>
|
||||
<div class="target-ruler__pointer-line"></div>
|
||||
</div>
|
||||
<div class="target-ruler__scale" id="targetRulerScale"></div>
|
||||
<div class="target-ruler__labels" id="targetRulerLabels"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="target-sheet__submit-bar">
|
||||
<button class="target-sheet__submit" onclick="submitTarget()">提 交</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 提交审核确认弹窗 -->
|
||||
<div class="confirm-mask" id="confirmMask" onclick="closeConfirm()">
|
||||
<div class="confirm-card" onclick="event.stopPropagation()">
|
||||
<div class="confirm-card__title">确认提交审核</div>
|
||||
<div class="confirm-card__msg">提交后,您的目标设置将由管理员审核,<br/>请耐心等待审核结果。</div>
|
||||
<div class="confirm-card__btns">
|
||||
<button class="confirm-card__btn confirm-card__btn--cancel" onclick="closeConfirm()">再想想</button>
|
||||
<button class="confirm-card__btn confirm-card__btn--confirm" onclick="doSubmitReview()">确认提交</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 确定个人目标确认弹窗 -->
|
||||
<div class="confirm-mask" id="personalConfirmMask" onclick="closePersonalConfirm()">
|
||||
<div class="confirm-card" onclick="event.stopPropagation()">
|
||||
<div class="confirm-card__title">是否确定目标</div>
|
||||
<div class="confirm-card__msg">确定后,您的个人目标将正式生效</div>
|
||||
<div class="confirm-card__btns">
|
||||
<button class="confirm-card__btn confirm-card__btn--cancel" onclick="closePersonalConfirm()">再想想</button>
|
||||
<button class="confirm-card__btn confirm-card__btn--confirm" onclick="doConfirmPersonalGoal()">确认</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 驳回原因弹窗 -->
|
||||
<div class="reject-mask" id="rejectMask" onclick="closeRejectModal(event)">
|
||||
<div class="reject-card" onclick="event.stopPropagation()">
|
||||
<div class="reject-card__title">驳回原因</div>
|
||||
<div class="reject-card__body">您设置的目标体重(59kg)与基础代谢及减重周期不匹配,建议在 14 周内分阶段减重,目标体重不低于 62kg;目标体脂率请控制在 18% 以上,避免过度消耗。</div>
|
||||
<div class="reject-card__meta">
|
||||
<span>审核人:张管理员</span>
|
||||
<span>2025-02-08 14:32</span>
|
||||
</div>
|
||||
<button class="reject-card__btn" onclick="closeRejectModal()">我知道了</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 活动选择底部弹窗 -->
|
||||
<div class="act-mask" id="actMask" onclick="closeActSheet()"></div>
|
||||
<div class="act-sheet" id="actSheet">
|
||||
<div class="act-sheet__handle"></div>
|
||||
<div class="act-sheet__title">请选择活动</div>
|
||||
<div class="act-sheet__list" id="actList"></div>
|
||||
<div class="act-sheet__confirm-bar">
|
||||
<button class="act-sheet__confirm" onclick="confirmActivity()">确 认</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
var ACTIVITIES = [
|
||||
{ id:'a1', name:'公共事务中心2026年二季度体重管理', period:'2026-04-01 ~ 2026-06-30' },
|
||||
{ id:'a2', name:'采油五厂2026年春季减重挑战赛', period:'2026-03-01 ~ 2026-05-31' },
|
||||
{ id:'a3', name:'勘探开发研究院健康行动季', period:'2026-04-15 ~ 2026-07-15' },
|
||||
{ id:'a4', name:'机关综合部年度健康管理活动', period:'2026-01-01 ~ 2026-12-31' },
|
||||
{ id:'a5', name:'长庆油田公司2025年员工减重活动', period:'2025-10-01 ~ 2025-12-31' }
|
||||
];
|
||||
var selectedActivityId = 'a1';
|
||||
var pendingActivityId = 'a1';
|
||||
var personalLocked = false; // 个人目标是否处于锁定态
|
||||
|
||||
function openActSheet() {
|
||||
if (personalLocked || isReadOnly()) return;
|
||||
pendingActivityId = selectedActivityId;
|
||||
renderActList();
|
||||
document.getElementById('actMask').classList.add('show');
|
||||
document.getElementById('actSheet').classList.add('show');
|
||||
}
|
||||
function closeActSheet() {
|
||||
document.getElementById('actMask').classList.remove('show');
|
||||
document.getElementById('actSheet').classList.remove('show');
|
||||
}
|
||||
function renderActList() {
|
||||
var list = document.getElementById('actList');
|
||||
list.innerHTML = '';
|
||||
if (currentState === 'unset-noact') {
|
||||
list.innerHTML = '<div class="act-sheet__empty">暂无可参加的活动</div>';
|
||||
return;
|
||||
}
|
||||
ACTIVITIES.forEach(function(a){
|
||||
var row = document.createElement('div');
|
||||
row.className = 'act-item' + (a.id === pendingActivityId ? ' selected' : '');
|
||||
row.innerHTML = '<div class="act-item__main"><div class="act-item__name">' + a.name + '</div>' +
|
||||
'<div class="act-item__period">' + a.period + '</div></div>' +
|
||||
'<span class="act-item__check">✓</span>';
|
||||
row.onclick = function() { if (!personalLocked && !isReadOnly()) { pendingActivityId = a.id; renderActList(); } };
|
||||
list.appendChild(row);
|
||||
});
|
||||
}
|
||||
function confirmActivity() {
|
||||
selectedActivityId = pendingActivityId;
|
||||
var act = ACTIVITIES.find(function(a){ return a.id === selectedActivityId; });
|
||||
document.getElementById('actSelectText').textContent = act ? act.name : '请选择您要参加的活动';
|
||||
document.getElementById('actDetailLink').style.display = act ? 'inline' : 'none';
|
||||
closeActSheet();
|
||||
}
|
||||
|
||||
/* —— URL 参数读取 —— */
|
||||
function getQueryParam(key) {
|
||||
var params = window.location.search.slice(1).split('&');
|
||||
for (var i = 0; i < params.length; i++) {
|
||||
var pair = params[i].split('=');
|
||||
if (pair[0] === key) return decodeURIComponent(pair[1] || '');
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
/* —— 状态配置 —— */
|
||||
var STATE_CONFIG = {
|
||||
'unset-noact': { mode:'activity', hideDetail:true, hideSelect:false, readOnly:false, selfLock:false, btnMode:'normal', status:'' },
|
||||
'unset-hasact':{ mode:'activity', hideDetail:false, hideSelect:false, readOnly:false, selfLock:false, btnMode:'normal', status:'' },
|
||||
'personal': { mode:'self', hideDetail:true, hideSelect:false, hideActCard:true, showInfoCard:false, readOnly:false, selfLock:true, btnMode:'modify', status:'' },
|
||||
'wait': { mode:'activity', hideDetail:false, hideSelect:false, hideSelfCard:true, showInfoCard:false, readOnly:true, selfLock:false, btnMode:'none', status:'<span class="gm-status-bar--wait">管理员审核中,请耐心等待...</span>' },
|
||||
'pass': { mode:'activity', hideDetail:false, hideSelect:false, hideSelfCard:true, showInfoCard:false, readOnly:false, selfLock:false, btnMode:'resubmit', status:'<span class="gm-status-bar--pass">管理员已审核通过,请尽快签订承诺书参加活动</span>' },
|
||||
'reject': { mode:'activity', hideDetail:false, hideSelect:false, showInfoCard:false, hideSelfCard:true, readOnly:false, selfLock:false, btnMode:'resubmit', status:'<span class="gm-status-bar--reject">管理员审核驳回,<a class="gm-status-bar__link" onclick="openRejectModal()">查看原因</a>,请重新调整目标</span>' },
|
||||
'signed': { mode:'activity', hideDetail:false, hideSelect:false, showInfoCard:false, hideSelfCard:true, readOnly:true, selfLock:false, btnMode:'none', status:'<span class="gm-status-bar--signed">已签署承诺书并参与活动</span>' }
|
||||
};
|
||||
var currentState = getQueryParam('type') || 'unset-hasact';
|
||||
var currentCfg = STATE_CONFIG[currentState] || STATE_CONFIG['unset-hasact'];
|
||||
|
||||
function isReadOnly() { return currentCfg.readOnly; }
|
||||
|
||||
function selectMode(mode) {
|
||||
var isActivity = mode === 'activity';
|
||||
var cardA = document.getElementById('cardActivity');
|
||||
var cardS = document.getElementById('cardSelf');
|
||||
cardA.classList.toggle('gm-card--active', isActivity);
|
||||
cardA.classList.toggle('gm-card--disabled', !isActivity);
|
||||
cardS.classList.toggle('gm-card--active', !isActivity);
|
||||
cardS.classList.toggle('gm-card--disabled', isActivity);
|
||||
|
||||
var nameBtn = document.getElementById('selfNameBtn');
|
||||
nameBtn.classList.toggle('is-disabled', isActivity);
|
||||
nameBtn.disabled = isActivity;
|
||||
|
||||
// 切换天数显示
|
||||
document.getElementById('actDays').style.display = isActivity ? 'inline' : 'none';
|
||||
document.getElementById('selfDays').style.display = isActivity ? 'none' : 'inline-flex';
|
||||
|
||||
/* 切换卡片时底部按钮跟随切换:活动目标→提交审核/重新提交,自我目标→确认目标 */
|
||||
if ((currentState === 'unset-noact' || currentState === 'unset-hasact' || currentState === 'personal' || currentState === 'reject') && !personalLocked) {
|
||||
document.getElementById('btnSubmitReview').style.display = isActivity ? 'block' : 'none';
|
||||
document.getElementById('btnConfirmGoal').style.display = isActivity ? 'none' : 'block';
|
||||
document.getElementById('btnResubmit').style.display = 'none';
|
||||
}
|
||||
}
|
||||
|
||||
/* —— 初始化页面状态 —— */
|
||||
function initState() {
|
||||
var cfg = currentCfg;
|
||||
selectMode(cfg.mode);
|
||||
|
||||
// 活动目标管理卡片
|
||||
var detailLink = document.getElementById('actDetailLink');
|
||||
detailLink.style.display = cfg.hideDetail ? 'none' : 'inline';
|
||||
var actSelect = document.getElementById('actSelect');
|
||||
actSelect.style.display = cfg.hideSelect ? 'none' : 'flex';
|
||||
if (currentState === 'unset-noact' || currentState === 'personal') {
|
||||
document.getElementById('actSelectText').textContent = '请选择您要参加的活动';
|
||||
actSelect.classList.remove('gm-select--filled');
|
||||
} else {
|
||||
var act = ACTIVITIES.find(function(a){ return a.id === selectedActivityId; });
|
||||
document.getElementById('actSelectText').textContent = act ? act.name : '请选择您要参加的活动';
|
||||
}
|
||||
// 隐藏活动目标管理卡片(个人目标初始态)
|
||||
if (cfg.hideActCard) {
|
||||
document.getElementById('cardActivity').style.display = 'none';
|
||||
}
|
||||
// 隐藏自我目标管理卡片(审核中/已通过/已签署等状态)
|
||||
if (cfg.hideSelfCard) {
|
||||
document.getElementById('cardSelf').style.display = 'none';
|
||||
}
|
||||
// 隐藏个人信息卡片(personal/wait/pass/reject/signed)
|
||||
if (cfg.showInfoCard === false) {
|
||||
document.querySelectorAll('.gm-card')[2].style.display = 'none';
|
||||
}
|
||||
|
||||
// 自我目标管理 - 锁定态
|
||||
if (cfg.selfLock) {
|
||||
personalLocked = true;
|
||||
document.getElementById('selfNameInput').value = '我的春季减重行动';
|
||||
document.getElementById('selfNameBtn').classList.add('is-disabled');
|
||||
document.getElementById('selfNameBtn').disabled = true;
|
||||
// 锁定自我目标管理卡片(名字输入框)
|
||||
document.getElementById('cardSelf').classList.add('gm-locked');
|
||||
// 锁定数据录入和目标设定
|
||||
document.querySelectorAll('.gm-data-row').forEach(function(r){ r.classList.add('gm-locked'); });
|
||||
document.getElementById('groupTag').parentElement.parentElement.classList.add('gm-locked');
|
||||
document.querySelectorAll('.gm-target-row__edit').forEach(function(e){ e.style.pointerEvents = 'none'; e.style.color = '#c8d0d8'; });
|
||||
document.querySelector('.gm-cta').style.pointerEvents = 'none';
|
||||
document.querySelector('.gm-cta').style.background = '#c8d0d8';
|
||||
// 隐藏确定目标按钮,显示修改目标按钮
|
||||
document.getElementById('btnConfirmGoal').style.display = 'none';
|
||||
document.getElementById('btnSubmitReview').style.display = 'none';
|
||||
document.getElementById('btnModifyRow').style.display = 'flex';
|
||||
|
||||
/* personal 专属初始化:隐藏活动卡片、显示身高、隐藏计算按钮、数据源置灰 */
|
||||
if (currentState === 'personal') {
|
||||
// 个人信息卡片显示身高数据
|
||||
document.querySelectorAll('.gm-info-cell')[0].querySelector('.gm-info-cell__value').textContent = '175 cm';
|
||||
// 隐藏"开始计算"按钮
|
||||
document.querySelector('.gm-cta').style.display = 'none';
|
||||
// 初始数据录入卡片数据源按钮全部置灰
|
||||
document.querySelectorAll('.gm-chip').forEach(function(c) {
|
||||
c.classList.remove('active');
|
||||
c.style.pointerEvents = 'none';
|
||||
c.style.opacity = '0.5';
|
||||
});
|
||||
}
|
||||
} else {
|
||||
personalLocked = false;
|
||||
document.getElementById('btnModifyRow').style.display = 'none';
|
||||
}
|
||||
|
||||
// 只读态(审核中/已通过/已签署)
|
||||
if (cfg.readOnly && !cfg.selfLock) {
|
||||
/* 活动目标管理卡片不置灰,仅下拉选择不可操作(固定显示当前活动) */
|
||||
document.getElementById('cardSelf').classList.add('gm-card--disabled');
|
||||
document.getElementById('cardSelf').classList.remove('gm-card--selectable');
|
||||
document.querySelectorAll('.gm-data-row').forEach(function(r){ r.classList.add('gm-locked'); });
|
||||
document.querySelectorAll('.gm-target-row__edit').forEach(function(e){ e.style.pointerEvents = 'none'; e.style.color = '#c8d0d8'; });
|
||||
document.querySelector('.gm-cta').style.display = 'none';
|
||||
document.getElementById('actSelect').style.pointerEvents = 'none';
|
||||
/* 只读态:个人信息卡片显示身高、数据源按钮全部置灰 */
|
||||
document.querySelectorAll('.gm-info-cell')[0].querySelector('.gm-info-cell__value').textContent = '175 cm';
|
||||
document.querySelectorAll('.gm-chip').forEach(function(c) {
|
||||
c.classList.remove('active');
|
||||
c.style.pointerEvents = 'none';
|
||||
c.style.opacity = '0.5';
|
||||
});
|
||||
}
|
||||
|
||||
// 底部按钮和状态栏
|
||||
var btnSubmit = document.getElementById('btnSubmitReview');
|
||||
var btnConfirm = document.getElementById('btnConfirmGoal');
|
||||
var btnResubmit = document.getElementById('btnResubmit');
|
||||
var statusBar = document.getElementById('statusBar');
|
||||
var actionRow = document.getElementById('actionRow');
|
||||
|
||||
if (cfg.btnMode === 'normal') {
|
||||
btnSubmit.style.display = cfg.mode === 'activity' ? 'block' : 'none';
|
||||
btnConfirm.style.display = cfg.mode === 'self' ? 'block' : 'none';
|
||||
btnResubmit.style.display = 'none';
|
||||
actionRow.style.display = 'flex';
|
||||
statusBar.style.display = 'none';
|
||||
} else if (cfg.btnMode === 'none') {
|
||||
btnSubmit.style.display = 'none';
|
||||
btnConfirm.style.display = 'none';
|
||||
btnResubmit.style.display = 'none';
|
||||
actionRow.style.display = 'none';
|
||||
statusBar.style.display = 'block';
|
||||
statusBar.innerHTML = cfg.status;
|
||||
} else if (cfg.btnMode === 'resubmit') {
|
||||
btnSubmit.style.display = 'none';
|
||||
btnConfirm.style.display = 'none';
|
||||
btnResubmit.style.display = 'block';
|
||||
actionRow.style.display = 'flex';
|
||||
statusBar.style.display = 'block';
|
||||
statusBar.innerHTML = cfg.status;
|
||||
} else if (cfg.btnMode === 'modify') {
|
||||
btnSubmit.style.display = 'none';
|
||||
btnConfirm.style.display = 'none';
|
||||
btnResubmit.style.display = 'none';
|
||||
actionRow.style.display = 'none';
|
||||
statusBar.style.display = 'none';
|
||||
}
|
||||
}
|
||||
|
||||
initState();
|
||||
|
||||
/* —— 高亮当前类型菜单项 —— */
|
||||
document.querySelectorAll('#typeMenu .nav-menu__item').forEach(function(el){
|
||||
el.classList.toggle('active', el.dataset.type === currentState);
|
||||
});
|
||||
|
||||
/* —— 类型切换菜单 —— */
|
||||
function toggleTypeMenu(e) {
|
||||
e.stopPropagation();
|
||||
document.getElementById('typeMenu').classList.toggle('show');
|
||||
}
|
||||
function setGoalType(type) {
|
||||
location.href = 'goal-management.html?type=' + type;
|
||||
}
|
||||
document.addEventListener('click', function() {
|
||||
document.getElementById('typeMenu').classList.remove('show');
|
||||
});
|
||||
|
||||
/* —— 解锁个人目标(点击修改目标) —— */
|
||||
function unlockPersonal() {
|
||||
personalLocked = false;
|
||||
document.getElementById('btnModifyRow').style.display = 'none';
|
||||
document.getElementById('btnConfirmGoal').style.display = 'block';
|
||||
document.getElementById('btnSubmitReview').style.display = 'none';
|
||||
document.getElementById('actionRow').style.display = 'flex';
|
||||
document.getElementById('cardSelf').classList.remove('gm-locked');
|
||||
document.querySelectorAll('.gm-data-row').forEach(function(r){ r.classList.remove('gm-locked'); });
|
||||
document.querySelectorAll('.gm-target-row__edit').forEach(function(e){ e.style.pointerEvents = 'auto'; e.style.color = '#36cfc9'; });
|
||||
document.querySelector('.gm-cta').style.pointerEvents = 'auto';
|
||||
document.querySelector('.gm-cta').style.background = 'linear-gradient(135deg, #36cfc9, #1890ff)';
|
||||
|
||||
/* personal 专属解锁:展示活动卡片、点亮计算按钮和数据源 */
|
||||
if (currentState === 'personal') {
|
||||
var actCard = document.getElementById('cardActivity');
|
||||
actCard.style.display = 'block';
|
||||
actCard.classList.remove('gm-card--disabled');
|
||||
document.querySelector('.gm-cta').style.display = 'block';
|
||||
document.querySelectorAll('.gm-chip').forEach(function(c) {
|
||||
c.style.pointerEvents = 'auto';
|
||||
c.style.opacity = '1';
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
document.querySelectorAll('.gm-data-row').forEach(function(row) {
|
||||
var chips = row.querySelectorAll('.gm-chip');
|
||||
chips.forEach(function(c) {
|
||||
c.addEventListener('click', function() {
|
||||
if (personalLocked || isReadOnly()) return;
|
||||
chips.forEach(function(x) { x.classList.remove('active'); });
|
||||
c.classList.add('active');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
/* —— 目标修改底部弹窗 —— */
|
||||
var TARGET_CONFIG = {
|
||||
targetWeight: {
|
||||
title:'目标体重', hint:'请设置您的目标体重',
|
||||
iconBg:'background:linear-gradient(135deg,#8a7bff 0%,#6f5bf5 100%)',
|
||||
icon:'<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="#fff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="4" y="5" width="16" height="15" rx="2"/><path d="M9 5 V3 H15 V5"/><path d="M9 13 L12 9 L13 11"/></svg>',
|
||||
value:59, unit:'kg', step:0.1, majorEvery:10, fmt:1, elId:'targetWeightValue'
|
||||
},
|
||||
targetFat: {
|
||||
title:'目标体脂', hint:'请设置您的目标体脂率',
|
||||
iconBg:'background:linear-gradient(135deg,#ffb574 0%,#ff9a4d 100%)',
|
||||
icon:'<svg width="22" height="22" viewBox="0 0 24 24" fill="#fff"><path d="M12 2 C7 9 5 12 5 16 a7 7 0 0 0 14 0 C19 12 17 9 12 2 Z"/></svg>',
|
||||
value:28, unit:'%', step:0.1, majorEvery:10, fmt:1, elId:'targetFatValue'
|
||||
},
|
||||
targetWaist: {
|
||||
title:'目标腰围', hint:'请设置您的目标腰围',
|
||||
iconBg:'background:linear-gradient(135deg,#ff9ec0 0%,#ff7aa8 100%)',
|
||||
icon:'<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="#fff" stroke-width="2" stroke-linecap="round"><ellipse cx="12" cy="12" rx="9" ry="5"/><path d="M12 7v10"/></svg>',
|
||||
value:86, unit:'cm', step:1, majorEvery:10, fmt:0, elId:'targetWaistValue'
|
||||
}
|
||||
};
|
||||
var currentTargetKey = null;
|
||||
var currentTargetValue = 59;
|
||||
|
||||
function openTargetSheet(key) {
|
||||
if (personalLocked || isReadOnly()) return;
|
||||
currentTargetKey = key;
|
||||
var cfg = TARGET_CONFIG[key];
|
||||
currentTargetValue = cfg.value;
|
||||
document.getElementById('targetSheetTitle').textContent = cfg.title;
|
||||
document.getElementById('targetSheetHint').textContent = cfg.hint;
|
||||
document.getElementById('targetNum').textContent = cfg.fmt === 1 ? currentTargetValue.toFixed(1) : String(currentTargetValue);
|
||||
document.getElementById('targetUnit').textContent = cfg.unit;
|
||||
var iconEl = document.getElementById('targetSheetIcon');
|
||||
iconEl.setAttribute('style', cfg.iconBg);
|
||||
iconEl.innerHTML = cfg.icon;
|
||||
renderTargetRuler(cfg);
|
||||
document.getElementById('targetMask').classList.add('show');
|
||||
document.querySelector('.target-sheet').classList.add('show');
|
||||
}
|
||||
|
||||
function closeTargetSheet() {
|
||||
document.querySelector('.target-sheet').classList.remove('show');
|
||||
setTimeout(function(){ document.getElementById('targetMask').classList.remove('show'); }, 250);
|
||||
}
|
||||
|
||||
function submitTarget() {
|
||||
var cfg = TARGET_CONFIG[currentTargetKey];
|
||||
var displayVal = cfg.fmt === 1 ? currentTargetValue.toFixed(1) : String(currentTargetValue);
|
||||
var valueEl = document.getElementById(cfg.elId);
|
||||
valueEl.textContent = displayVal + ' ' + cfg.unit;
|
||||
closeTargetSheet();
|
||||
}
|
||||
|
||||
function renderTargetRuler(cfg) {
|
||||
var scale = document.getElementById('targetRulerScale');
|
||||
var labels = document.getElementById('targetRulerLabels');
|
||||
scale.innerHTML = '';
|
||||
labels.innerHTML = '';
|
||||
var pxPerStep = 8;
|
||||
var rulerWidth = 358;
|
||||
var totalTicks = Math.floor(rulerWidth / pxPerStep);
|
||||
var centerIndex = Math.floor(totalTicks / 2);
|
||||
for (var i = 0; i < totalTicks; i++) {
|
||||
var offsetSteps = i - centerIndex;
|
||||
var tick = document.createElement('div');
|
||||
tick.className = 'target-ruler__tick';
|
||||
var isMajor = (Math.abs(offsetSteps) % cfg.majorEvery) === 0;
|
||||
tick.classList.add(isMajor ? 'target-ruler__tick--major' : 'target-ruler__tick--minor');
|
||||
if (offsetSteps > 0) tick.classList.add('target-ruler__tick--right');
|
||||
tick.style.left = (i * pxPerStep) + 'px';
|
||||
scale.appendChild(tick);
|
||||
if (isMajor) {
|
||||
var lbl = document.createElement('div');
|
||||
lbl.className = 'target-ruler__label';
|
||||
var labelVal = cfg.value + offsetSteps * cfg.step;
|
||||
lbl.textContent = cfg.fmt === 1 ? labelVal.toFixed(1) : String(Math.round(labelVal));
|
||||
lbl.style.left = (i * pxPerStep) + 'px';
|
||||
labels.appendChild(lbl);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* —— 提交审核确认弹窗 —— */
|
||||
function openConfirm() {
|
||||
document.getElementById('confirmMask').classList.add('show');
|
||||
}
|
||||
function closeConfirm() {
|
||||
document.getElementById('confirmMask').classList.remove('show');
|
||||
}
|
||||
function doSubmitReview() {
|
||||
closeConfirm();
|
||||
window.location.href = 'goal-commitment.html?type=wait';
|
||||
}
|
||||
|
||||
/* —— 确定个人目标确认弹窗 —— */
|
||||
function openPersonalConfirm() {
|
||||
document.getElementById('personalConfirmMask').classList.add('show');
|
||||
}
|
||||
function closePersonalConfirm() {
|
||||
document.getElementById('personalConfirmMask').classList.remove('show');
|
||||
}
|
||||
function doConfirmPersonalGoal() {
|
||||
closePersonalConfirm();
|
||||
window.location.href = 'goal-commitment.html?type=personal';
|
||||
}
|
||||
|
||||
/* —— 驳回原因弹窗 —— */
|
||||
function openRejectModal() {
|
||||
document.getElementById('rejectMask').classList.add('show');
|
||||
}
|
||||
function closeRejectModal(e) {
|
||||
if (e && e.target !== e.currentTarget) return;
|
||||
document.getElementById('rejectMask').classList.remove('show');
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,609 +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; }
|
||||
.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; margin-right: 28px; }
|
||||
.scroll-content { flex: 1; overflow-y: auto; background: #f5f7fa; }
|
||||
.scroll-content::-webkit-scrollbar { display: none; }
|
||||
|
||||
/* Tab 切换 */
|
||||
.tabs { display: flex; background: #eef0f3; margin: 14px 16px 8px; border-radius: 26px; padding: 4px; position: relative; }
|
||||
.tab-item { flex: 1; height: 40px; line-height: 40px; text-align: center; font-size: 15px; font-weight: 600; color: #9aa3ad; border-radius: 22px; cursor: pointer; transition: all 0.2s; }
|
||||
.tab-item.active { background: #fff; color: #1f9d8f; box-shadow: 0 2px 6px rgba(31,157,143,0.18); border: 1px solid #4dc4b6; }
|
||||
|
||||
.tab-panel { display: none; padding: 8px 16px 30px; }
|
||||
.tab-panel.active { display: block; }
|
||||
|
||||
/* —— 重点指标 —— */
|
||||
.metric-card { background: #fff; border-radius: 14px; margin-bottom: 12px; padding: 6px 16px 12px; box-shadow: 0 2px 6px rgba(0,0,0,0.04); }
|
||||
.metric-card__head { display: flex; align-items: center; justify-content: space-between; padding: 12px 0 10px; border-bottom: 1px solid #f1f3f5; }
|
||||
.metric-card__title { font-size: 16px; font-weight: 800; color: #1a1a1a; }
|
||||
.metric-card__ref { font-size: 13px; color: #9aa3ad; margin-left: 4px; font-weight: 500; }
|
||||
.metric-card__arrow { color: #c8c8c8; font-size: 14px; }
|
||||
|
||||
.metric-row { display: flex; align-items: center; padding: 14px 0; gap: 12px; }
|
||||
.metric-row + .metric-row { border-top: 1px dashed #f0f0f0; }
|
||||
.metric-row__icon { width: 38px; height: 38px; border-radius: 10px; display: flex; align-items: center; justify-content: center; flex-shrink: 0; }
|
||||
.metric-row__main { flex: 1; min-width: 0; }
|
||||
.metric-row__value { font-size: 16px; font-weight: 700; color: #1a1a1a; line-height: 1.4; }
|
||||
.metric-row__value .extra { margin-left: 6px; }
|
||||
.metric-row__meta { display: flex; align-items: center; gap: 10px; margin-top: 4px; font-size: 13px; color: #9aa3ad; }
|
||||
.metric-row__status { font-size: 13px; font-weight: 600; color: #1f9d8f; }
|
||||
.metric-row__status--abnormal { color: #ff4d4f; }
|
||||
.metric-row__year { font-size: 13px; color: #9aa3ad; }
|
||||
.metric-row__btn { flex-shrink: 0; height: 30px; line-height: 28px; padding: 0 14px; border-radius: 16px; background: #fff; border: 1px solid #4dc4b6; color: #1f9d8f; font-size: 13px; font-weight: 600; cursor: pointer; }
|
||||
|
||||
/* 子项列表(血脂) */
|
||||
.metric-sub { padding: 12px 0 4px 50px; }
|
||||
.metric-sub__item { display: flex; align-items: baseline; flex-wrap: wrap; gap: 8px; padding: 8px 0; }
|
||||
.metric-sub__item + .metric-sub__item { border-top: 1px dashed #f0f0f0; }
|
||||
.metric-sub__name { font-size: 15px; font-weight: 700; color: #1a1a1a; flex: 1 1 100%; }
|
||||
.metric-sub__name .val { font-weight: 700; color: #1a1a1a; margin-left: 4px; }
|
||||
.metric-sub__name .val--abnormal { color: #ff4d4f; }
|
||||
.metric-sub__meta { font-size: 13px; color: #9aa3ad; }
|
||||
.metric-sub__status { font-size: 13px; font-weight: 600; color: #1f9d8f; }
|
||||
.metric-sub__status--abnormal { color: #ff4d4f; }
|
||||
|
||||
/* 图标背景色 */
|
||||
.icon-weight { background: linear-gradient(135deg, #8a7bff 0%, #6f5bf5 100%); }
|
||||
.icon-bp { background: linear-gradient(135deg, #ff8a7a 0%, #ff6a5a 100%); }
|
||||
.icon-glucose { background: linear-gradient(135deg, #ff9ec0 0%, #ff7aa8 100%); }
|
||||
.icon-uric { background: linear-gradient(135deg, #7ec9f5 0%, #5fb3ef 100%); }
|
||||
.icon-lipid { background: linear-gradient(135deg, #ffb574 0%, #ff9a4d 100%); }
|
||||
|
||||
/* —— 慢性疾病 —— */
|
||||
.disease-card { background: #fff; border-radius: 14px; padding: 16px 18px; margin-bottom: 12px; display: flex; align-items: center; justify-content: space-between; box-shadow: 0 2px 6px rgba(0,0,0,0.04); }
|
||||
.disease-card__main { flex: 1; min-width: 0; }
|
||||
.disease-card__name { font-size: 16px; font-weight: 700; color: #1a1a1a; }
|
||||
.disease-card__time { font-size: 13px; color: #9aa3ad; margin-top: 8px; }
|
||||
.disease-card__btn { flex-shrink: 0; height: 32px; line-height: 30px; padding: 0 18px; border-radius: 17px; background: #fff; border: 1px solid #4dc4b6; color: #1f9d8f; font-size: 13px; font-weight: 600; cursor: pointer; }
|
||||
|
||||
/* —— 底部弹窗(测量) —— */
|
||||
.sheet-mask { position: absolute; inset: 0; background: rgba(0,0,0,0.4); z-index: 20; opacity: 0; pointer-events: none; transition: opacity 0.25s; }
|
||||
.sheet-mask.show { opacity: 1; pointer-events: auto; }
|
||||
.sheet { position: absolute; left: 0; right: 0; bottom: 0; background: #fff; border-radius: 20px 20px 0 0; z-index: 21; padding: 10px 0 22px; transform: translateY(100%); transition: transform 0.3s ease; max-height: 88%; display: flex; flex-direction: column; }
|
||||
.sheet.show { transform: translateY(0); }
|
||||
.sheet__handle { width: 40px; height: 4px; background: #d8dde3; border-radius: 2px; margin: 0 auto 8px; flex-shrink: 0; }
|
||||
.sheet__head { display: flex; align-items: center; gap: 12px; padding: 8px 22px 16px; border-bottom: 1px solid #f1f3f5; flex-shrink: 0; }
|
||||
.sheet__icon { width: 40px; height: 40px; border-radius: 10px; display: flex; align-items: center; justify-content: center; flex-shrink: 0; }
|
||||
.sheet__icon svg { width: 22px; height: 22px; }
|
||||
.sheet__meta { flex: 1; min-width: 0; }
|
||||
.sheet__title { font-size: 17px; font-weight: 700; color: #1a1a1a; }
|
||||
.sheet__hint { font-size: 13px; color: #9aa3ad; margin-top: 4px; }
|
||||
|
||||
.sheet__body { flex: 1; overflow-y: auto; padding: 8px 0 12px; }
|
||||
.sheet__body::-webkit-scrollbar { display: none; }
|
||||
|
||||
/* —— 字段 —— */
|
||||
.sheet-field { padding: 18px 16px 8px; position: relative; }
|
||||
.sheet-field__label { position: absolute; left: 18px; top: 22px; font-size: 15px; font-weight: 700; color: #1a1a1a; }
|
||||
.sheet-field__value { text-align: center; margin: 6px 0 14px; min-height: 44px; }
|
||||
.sheet-field--single .sheet-field__value { margin: 22px 0 16px; }
|
||||
.sheet-field__num { font-size: 34px; font-weight: 800; color: #1a1a1a; letter-spacing: 1px; }
|
||||
.sheet-field--single .sheet-field__num { font-size: 40px; }
|
||||
.sheet-field__unit { font-size: 14px; color: #9aa3ad; margin-left: 8px; vertical-align: middle; }
|
||||
|
||||
/* 尺子 */
|
||||
.ruler { position: relative; height: 64px; margin: 0 16px; }
|
||||
.ruler__pointer { position: absolute; left: 50%; top: 0; transform: translateX(-50%); display: flex; flex-direction: column; align-items: center; z-index: 2; }
|
||||
.ruler__pointer-flag { width: 0; height: 0; border-left: 7px solid transparent; border-right: 7px solid transparent; border-top: 9px solid #4dc4b6; }
|
||||
.ruler__pointer-line { width: 2px; height: 22px; background: #4dc4b6; margin-top: -1px; }
|
||||
.ruler__scale { position: absolute; left: 0; right: 0; top: 16px; height: 22px; }
|
||||
.ruler__tick { position: absolute; bottom: 0; width: 1px; background: #b6e3dd; }
|
||||
.ruler__tick--minor { height: 8px; }
|
||||
.ruler__tick--major { height: 16px; }
|
||||
.ruler__tick--right { background: #ffd9a8; }
|
||||
.ruler__labels { position: absolute; left: 0; right: 0; top: 42px; height: 16px; font-size: 12px; color: #9aa3ad; }
|
||||
.ruler__label { position: absolute; transform: translateX(-50%); }
|
||||
|
||||
.sheet__submit-bar { padding: 14px 16px 0; flex-shrink: 0; }
|
||||
.sheet__submit { display: block; width: 100%; height: 46px; background: linear-gradient(135deg, #4dc4b6 0%, #46b8af 100%); color: #fff; border: none; border-radius: 23px; font-size: 16px; font-weight: 600; cursor: pointer; letter-spacing: 6px; }
|
||||
|
||||
/* —— 慢病修改弹窗(中央卡片) —— */
|
||||
.modal-mask { position: absolute; inset: 0; background: rgba(0,0,0,0.45); z-index: 30; opacity: 0; pointer-events: none; transition: opacity 0.2s; display: flex; align-items: center; justify-content: center; padding: 0 20px; }
|
||||
.modal-mask.show { opacity: 1; pointer-events: auto; }
|
||||
.modal { width: 100%; background: #fff; border-radius: 16px; padding: 22px 20px 20px; transform: scale(0.95); transition: transform 0.2s; }
|
||||
.modal-mask.show .modal { transform: scale(1); }
|
||||
.modal__title { font-size: 17px; font-weight: 800; color: #1a1a1a; margin-bottom: 18px; }
|
||||
.modal__radios { display: flex; align-items: center; justify-content: space-around; padding: 4px 0 14px; }
|
||||
.radio { display: flex; align-items: center; gap: 8px; font-size: 15px; color: #1a1a1a; cursor: pointer; }
|
||||
.radio__dot { width: 22px; height: 22px; border-radius: 50%; border: 1.5px solid #c8d0d8; display: flex; align-items: center; justify-content: center; flex-shrink: 0; transition: all 0.18s; }
|
||||
.radio.checked .radio__dot { background: #4dc4b6; border-color: #4dc4b6; }
|
||||
.radio.checked .radio__dot::after { content: ''; width: 8px; height: 4px; border-left: 2px solid #fff; border-bottom: 2px solid #fff; transform: rotate(-45deg) translateY(-1px); }
|
||||
|
||||
.modal__detail { display: none; padding-top: 6px; }
|
||||
.modal__detail.show { display: block; }
|
||||
.modal__hospital { background: #f4f6f8; border-radius: 10px; padding: 14px 14px; display: flex; align-items: center; gap: 6px; margin-bottom: 16px; }
|
||||
.modal__hospital-label { font-size: 14px; font-weight: 600; color: #1a1a1a; flex-shrink: 0; }
|
||||
.modal__hospital-input { flex: 1; border: none; background: transparent; font-size: 14px; color: #1a1a1a; outline: none; }
|
||||
.modal__hospital-input::placeholder { color: #b8c0c8; }
|
||||
|
||||
/* 滚轮日期选择 */
|
||||
.wheel { display: flex; gap: 12px; height: 180px; position: relative; }
|
||||
.wheel__col { flex: 1; position: relative; overflow: hidden; }
|
||||
.wheel__indicator { position: absolute; left: 8px; right: 8px; top: 50%; transform: translateY(-50%); height: 36px; border-top: 1px solid #ececec; border-bottom: 1px solid #ececec; pointer-events: none; z-index: 1; }
|
||||
.wheel__list { position: absolute; left: 0; right: 0; top: 50%; transform: translateY(-50%); display: flex; flex-direction: column; align-items: center; }
|
||||
.wheel__item { height: 36px; line-height: 36px; font-size: 18px; color: #c8cdd3; font-weight: 600; transition: all 0.18s; user-select: none; cursor: pointer; }
|
||||
.wheel__item--active { color: #1a1a1a; font-size: 20px; font-weight: 700; }
|
||||
.wheel__item--near { color: #8a93a0; }
|
||||
|
||||
.modal__submit-bar { padding-top: 18px; }
|
||||
.modal__submit { display: block; width: 100%; height: 46px; background: linear-gradient(135deg, #4dc4b6 0%, #46b8af 100%); color: #fff; border: none; border-radius: 23px; font-size: 16px; font-weight: 600; cursor: pointer; letter-spacing: 6px; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="phone-shell">
|
||||
<div class="status-bar">
|
||||
<span class="time">9:41</span>
|
||||
<div class="icons">
|
||||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="#333" stroke-width="2"><path d="M1 6l5 5 5-5"/><path d="M4 9l3 3 3-3" opacity="0.5"/></svg>
|
||||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="#333" stroke-width="2"><rect x="1" y="6" width="18" height="12" rx="2"/><path d="M21 10v4"/></svg>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 顶部导航 -->
|
||||
<div class="nav-bar">
|
||||
<div class="nav-back" onclick="history.back()">
|
||||
<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"/></svg>
|
||||
</div>
|
||||
<div class="nav-title">指标慢病</div>
|
||||
</div>
|
||||
|
||||
<div class="scroll-content">
|
||||
<!-- Tab 切换 -->
|
||||
<div class="tabs">
|
||||
<div class="tab-item active" data-tab="metrics" onclick="switchTab('metrics')">重点指标</div>
|
||||
<div class="tab-item" data-tab="diseases" onclick="switchTab('diseases')">慢性疾病</div>
|
||||
</div>
|
||||
|
||||
<!-- 重点指标 Panel -->
|
||||
<div class="tab-panel active" id="panel-metrics">
|
||||
<!-- 体重 -->
|
||||
<div class="metric-card">
|
||||
<div class="metric-card__head">
|
||||
<div>
|
||||
<span class="metric-card__title">体重</span>
|
||||
<span class="metric-card__ref">(参考值: 60~78)</span>
|
||||
</div>
|
||||
<span class="metric-card__arrow">›</span>
|
||||
</div>
|
||||
<div class="metric-row">
|
||||
<div class="metric-row__icon icon-weight">
|
||||
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="#fff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<rect x="4" y="5" width="16" height="15" rx="2"/>
|
||||
<path d="M9 5 V3 H15 V5"/>
|
||||
<path d="M9 13 L12 9 L13 11"/>
|
||||
</svg>
|
||||
</div>
|
||||
<div class="metric-row__main">
|
||||
<div class="metric-row__value">90.50kg<span class="extra">BMI: 27.93</span></div>
|
||||
<div class="metric-row__meta">
|
||||
<span class="metric-row__year">2026年</span>
|
||||
</div>
|
||||
</div>
|
||||
<button class="metric-row__btn" onclick="openSheet('weight')">测量</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 血压 -->
|
||||
<div class="metric-card">
|
||||
<div class="metric-card__head">
|
||||
<div>
|
||||
<span class="metric-card__title">血压</span>
|
||||
</div>
|
||||
<span class="metric-card__arrow">›</span>
|
||||
</div>
|
||||
<div class="metric-row">
|
||||
<div class="metric-row__icon icon-bp">
|
||||
<svg width="20" height="22" viewBox="0 0 24 24" fill="#fff">
|
||||
<path d="M12 2 C7 9 5 12 5 16 a7 7 0 0 0 14 0 C19 12 17 9 12 2 Z"/>
|
||||
</svg>
|
||||
</div>
|
||||
<div class="metric-row__main">
|
||||
<div class="metric-row__value">86 /140mmHg</div>
|
||||
<div class="metric-row__meta">
|
||||
<span class="metric-row__status">正常</span>
|
||||
<span class="metric-row__year">2025年</span>
|
||||
</div>
|
||||
</div>
|
||||
<button class="metric-row__btn" onclick="openSheet('bp')">测量</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 血糖 -->
|
||||
<div class="metric-card">
|
||||
<div class="metric-card__head">
|
||||
<div>
|
||||
<span class="metric-card__title">血糖</span>
|
||||
<span class="metric-card__ref">(参考值: 3.89--6.11)</span>
|
||||
</div>
|
||||
<span class="metric-card__arrow">›</span>
|
||||
</div>
|
||||
<div class="metric-row">
|
||||
<div class="metric-row__icon icon-glucose">
|
||||
<svg width="20" height="22" viewBox="0 0 24 24" fill="#fff">
|
||||
<path d="M12 2 C7 9 5 12 5 16 a7 7 0 0 0 14 0 C19 12 17 9 12 2 Z"/>
|
||||
<path d="M10 12 h4 M12 10 v4" stroke="#ff7aa8" stroke-width="1.6" stroke-linecap="round"/>
|
||||
</svg>
|
||||
</div>
|
||||
<div class="metric-row__main">
|
||||
<div class="metric-row__value">4.48 mmol/L</div>
|
||||
<div class="metric-row__meta">
|
||||
<span class="metric-row__status">正常</span>
|
||||
<span class="metric-row__year">2025年</span>
|
||||
</div>
|
||||
</div>
|
||||
<button class="metric-row__btn" onclick="openSheet('glucose')">测量</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 尿酸 -->
|
||||
<div class="metric-card">
|
||||
<div class="metric-card__head">
|
||||
<div>
|
||||
<span class="metric-card__title">尿酸</span>
|
||||
<span class="metric-card__ref">(参考值: 202--416)</span>
|
||||
</div>
|
||||
<span class="metric-card__arrow">›</span>
|
||||
</div>
|
||||
<div class="metric-row">
|
||||
<div class="metric-row__icon icon-uric">
|
||||
<svg width="22" height="22" viewBox="0 0 24 24" fill="#fff">
|
||||
<path d="M8 3 C5 8 4 11 4 14 a4.5 4.5 0 0 0 9 0 C13 11 11 8 8 3 Z"/>
|
||||
<path d="M16 9 C14 12.5 13 14.5 13 16.5 a3 3 0 0 0 6 0 C19 14.5 18 12.5 16 9 Z"/>
|
||||
</svg>
|
||||
</div>
|
||||
<div class="metric-row__main">
|
||||
<div class="metric-row__value">283 mmol/L</div>
|
||||
<div class="metric-row__meta">
|
||||
<span class="metric-row__status">正常</span>
|
||||
<span class="metric-row__year">2025年</span>
|
||||
</div>
|
||||
</div>
|
||||
<button class="metric-row__btn" onclick="openSheet('uric')">测量</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 血脂 -->
|
||||
<div class="metric-card">
|
||||
<div class="metric-card__head">
|
||||
<div>
|
||||
<span class="metric-card__title">血脂</span>
|
||||
</div>
|
||||
<span class="metric-card__arrow">›</span>
|
||||
</div>
|
||||
<div class="metric-row">
|
||||
<div class="metric-row__icon icon-lipid">
|
||||
<svg width="22" height="22" viewBox="0 0 24 24" fill="#fff">
|
||||
<path d="M12 2 C7 9 5 12 5 16 a7 7 0 0 0 14 0 C19 12 17 9 12 2 Z"/>
|
||||
<text x="12" y="17" text-anchor="middle" font-size="7" font-weight="700" fill="#ff9a4d">Fat</text>
|
||||
</svg>
|
||||
</div>
|
||||
<div class="metric-row__main">
|
||||
<div class="metric-row__value">总胆固醇: 3.66 mmol/L</div>
|
||||
<div class="metric-row__meta">
|
||||
<span class="metric-row__status">正常</span>
|
||||
<span class="metric-row__year">(参考值: 2.33--5.2)</span>
|
||||
</div>
|
||||
</div>
|
||||
<button class="metric-row__btn" onclick="openSheet('lipid')">测量</button>
|
||||
</div>
|
||||
<div class="metric-sub">
|
||||
<div class="metric-sub__item">
|
||||
<div class="metric-sub__name">甘油三脂: <span class="val">0.91 mmol/L</span></div>
|
||||
<span class="metric-sub__status">正常</span>
|
||||
<span class="metric-sub__meta">(参考值: 0.57--1.7)</span>
|
||||
</div>
|
||||
<div class="metric-sub__item">
|
||||
<div class="metric-sub__name">高密度脂蛋白: <span class="val val--abnormal">0.90 mmol/L</span></div>
|
||||
<span class="metric-sub__status metric-sub__status--abnormal">异常</span>
|
||||
<span class="metric-sub__meta">(参考值: 1.04--1.66)</span>
|
||||
</div>
|
||||
<div class="metric-sub__item">
|
||||
<div class="metric-sub__name">低密度脂蛋白: <span class="val">2.08 mmol/L</span></div>
|
||||
<span class="metric-sub__status">正常</span>
|
||||
<span class="metric-sub__meta">(参考值: 2.07--3.12)</span>
|
||||
</div>
|
||||
<div class="metric-sub__item">
|
||||
<div class="metric-sub__meta" style="flex:1 1 100%;">2025年</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 慢性疾病 Panel -->
|
||||
<div class="tab-panel" id="panel-diseases">
|
||||
<div class="disease-card">
|
||||
<div class="disease-card__main">
|
||||
<div class="disease-card__name">原发性高血压</div>
|
||||
<div class="disease-card__time">确诊时间:无</div>
|
||||
</div>
|
||||
<button class="disease-card__btn" onclick="openDiseaseModal('原发性高血压')">修改</button>
|
||||
</div>
|
||||
<div class="disease-card">
|
||||
<div class="disease-card__main">
|
||||
<div class="disease-card__name">冠状动脉硬化性心脏病</div>
|
||||
<div class="disease-card__time">确诊时间:无</div>
|
||||
</div>
|
||||
<button class="disease-card__btn" onclick="openDiseaseModal('冠状动脉硬化性心脏病')">修改</button>
|
||||
</div>
|
||||
<div class="disease-card">
|
||||
<div class="disease-card__main">
|
||||
<div class="disease-card__name">脑血管病后遗症</div>
|
||||
<div class="disease-card__time">确诊时间:无</div>
|
||||
</div>
|
||||
<button class="disease-card__btn" onclick="openDiseaseModal('脑血管病后遗症')">修改</button>
|
||||
</div>
|
||||
<div class="disease-card">
|
||||
<div class="disease-card__main">
|
||||
<div class="disease-card__name">慢性再生障碍性贫血</div>
|
||||
<div class="disease-card__time">确诊时间:无</div>
|
||||
</div>
|
||||
<button class="disease-card__btn" onclick="openDiseaseModal('慢性再生障碍性贫血')">修改</button>
|
||||
</div>
|
||||
<div class="disease-card">
|
||||
<div class="disease-card__main">
|
||||
<div class="disease-card__name">风湿性心脏病</div>
|
||||
<div class="disease-card__time">确诊时间:无</div>
|
||||
</div>
|
||||
<button class="disease-card__btn" onclick="openDiseaseModal('风湿性心脏病')">修改</button>
|
||||
</div>
|
||||
<div class="disease-card">
|
||||
<div class="disease-card__main">
|
||||
<div class="disease-card__name">慢性活动性肝炎、肝硬化</div>
|
||||
<div class="disease-card__time">确诊时间:无</div>
|
||||
</div>
|
||||
<button class="disease-card__btn" onclick="openDiseaseModal('慢性活动性肝炎、肝硬化')">修改</button>
|
||||
</div>
|
||||
<div class="disease-card">
|
||||
<div class="disease-card__main">
|
||||
<div class="disease-card__name">慢性阻塞性肺疾病</div>
|
||||
<div class="disease-card__time">确诊时间:无</div>
|
||||
</div>
|
||||
<button class="disease-card__btn" onclick="openDiseaseModal('慢性阻塞性肺疾病')">修改</button>
|
||||
</div>
|
||||
<div class="disease-card">
|
||||
<div class="disease-card__main">
|
||||
<div class="disease-card__name">肺源性心脏病</div>
|
||||
<div class="disease-card__time">确诊时间:无</div>
|
||||
</div>
|
||||
<button class="disease-card__btn" onclick="openDiseaseModal('肺源性心脏病')">修改</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 底部测量弹窗 -->
|
||||
<div class="sheet-mask" id="sheetMask" onclick="closeSheet()"></div>
|
||||
<div class="sheet" id="sheet">
|
||||
<div class="sheet__handle"></div>
|
||||
<div class="sheet__head">
|
||||
<div class="sheet__icon" id="sheetIcon"></div>
|
||||
<div class="sheet__meta">
|
||||
<div class="sheet__title" id="sheetTitle">体重</div>
|
||||
<div class="sheet__hint" id="sheetHint">请设置您的体重</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sheet__body" id="sheetBody"></div>
|
||||
<div class="sheet__submit-bar">
|
||||
<button class="sheet__submit" onclick="closeSheet()">提 交</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 慢病修改弹窗 -->
|
||||
<div class="modal-mask" id="diseaseModalMask" onclick="closeDiseaseModal(event)">
|
||||
<div class="modal" onclick="event.stopPropagation()">
|
||||
<div class="modal__title" id="diseaseModalTitle">原发性高血压</div>
|
||||
<div class="modal__radios">
|
||||
<div class="radio checked" id="radioUndiagnosed" onclick="setDiagnosed(false)">
|
||||
<div class="radio__dot"></div>
|
||||
<span>未确诊</span>
|
||||
</div>
|
||||
<div class="radio" id="radioDiagnosed" onclick="setDiagnosed(true)">
|
||||
<div class="radio__dot"></div>
|
||||
<span>已确诊</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal__detail" id="diseaseModalDetail">
|
||||
<div class="modal__hospital">
|
||||
<span class="modal__hospital-label">确诊医院:</span>
|
||||
<input class="modal__hospital-input" type="text" placeholder="请输入确诊医院" />
|
||||
</div>
|
||||
<div class="wheel">
|
||||
<div class="wheel__col">
|
||||
<div class="wheel__indicator"></div>
|
||||
<div class="wheel__list" id="wheelYear"></div>
|
||||
</div>
|
||||
<div class="wheel__col">
|
||||
<div class="wheel__indicator"></div>
|
||||
<div class="wheel__list" id="wheelMonth"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal__submit-bar">
|
||||
<button class="modal__submit" onclick="closeDiseaseModal()">提 交</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
function switchTab(tab) {
|
||||
document.querySelectorAll('.tab-item').forEach(function(el){
|
||||
el.classList.toggle('active', el.dataset.tab === tab);
|
||||
});
|
||||
document.getElementById('panel-metrics').classList.toggle('active', tab === 'metrics');
|
||||
document.getElementById('panel-diseases').classList.toggle('active', tab === 'diseases');
|
||||
}
|
||||
|
||||
/* —— 测量底部弹窗 —— */
|
||||
var METRIC_CONFIG = {
|
||||
weight: {
|
||||
title:'体重', hint:'请设置您的体重', iconBg:'icon-weight',
|
||||
icon:'<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="#fff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="4" y="5" width="16" height="15" rx="2"/><path d="M9 5 V3 H15 V5"/><path d="M9 13 L12 9 L13 11"/></svg>',
|
||||
fields:[ { label:'', unit:'公斤', value:90.50, step:0.1, majorEvery:10 } ]
|
||||
},
|
||||
bp: {
|
||||
title:'血压', hint:'请设置以下体检项', iconBg:'icon-bp',
|
||||
icon:'<svg width="20" height="22" viewBox="0 0 24 24" fill="#fff"><path d="M12 2 C7 9 5 12 5 16 a7 7 0 0 0 14 0 C19 12 17 9 12 2 Z"/></svg>',
|
||||
fields:[
|
||||
{ label:'收缩压', unit:'mmHg', value:140, step:1, majorEvery:10 },
|
||||
{ label:'舒张压', unit:'mmHg', value:86, step:1, majorEvery:10 }
|
||||
]
|
||||
},
|
||||
glucose: {
|
||||
title:'血糖', hint:'请设置您的血糖值', iconBg:'icon-glucose',
|
||||
icon:'<svg width="20" height="22" viewBox="0 0 24 24" fill="#fff"><path d="M12 2 C7 9 5 12 5 16 a7 7 0 0 0 14 0 C19 12 17 9 12 2 Z"/></svg>',
|
||||
fields:[ { label:'', unit:'mmol/L', value:4.48, step:0.01, majorEvery:100 } ]
|
||||
},
|
||||
uric: {
|
||||
title:'尿酸', hint:'请设置您的尿酸值', iconBg:'icon-uric',
|
||||
icon:'<svg width="22" height="22" viewBox="0 0 24 24" fill="#fff"><path d="M8 3 C5 8 4 11 4 14 a4.5 4.5 0 0 0 9 0 C13 11 11 8 8 3 Z"/><path d="M16 9 C14 12.5 13 14.5 13 16.5 a3 3 0 0 0 6 0 C19 14.5 18 12.5 16 9 Z"/></svg>',
|
||||
fields:[ { label:'', unit:'mmol/L', value:283, step:1, majorEvery:20 } ]
|
||||
},
|
||||
lipid: {
|
||||
title:'血脂', hint:'请设置以下体检项', iconBg:'icon-lipid',
|
||||
icon:'<svg width="22" height="22" viewBox="0 0 24 24" fill="#fff"><path d="M12 2 C7 9 5 12 5 16 a7 7 0 0 0 14 0 C19 12 17 9 12 2 Z"/></svg>',
|
||||
fields:[
|
||||
{ label:'总胆固醇', unit:'mmol/L', value:3.66, step:0.01, majorEvery:100 },
|
||||
{ label:'甘油三脂', unit:'mmol/L', value:0.91, step:0.01, majorEvery:100 },
|
||||
{ label:'高密度脂蛋白', unit:'mmol/L', value:0.90, step:0.01, majorEvery:100 },
|
||||
{ label:'低密度脂蛋白', unit:'mmol/L', value:2.08, step:0.01, majorEvery:100 }
|
||||
]
|
||||
}
|
||||
};
|
||||
|
||||
function openSheet(key) {
|
||||
var cfg = METRIC_CONFIG[key];
|
||||
if (!cfg) return;
|
||||
var iconEl = document.getElementById('sheetIcon');
|
||||
iconEl.className = 'sheet__icon ' + cfg.iconBg;
|
||||
iconEl.innerHTML = cfg.icon;
|
||||
document.getElementById('sheetTitle').textContent = cfg.title;
|
||||
document.getElementById('sheetHint').textContent = cfg.hint;
|
||||
renderFields(cfg.fields);
|
||||
document.getElementById('sheetMask').classList.add('show');
|
||||
document.getElementById('sheet').classList.add('show');
|
||||
}
|
||||
|
||||
function closeSheet() {
|
||||
document.getElementById('sheetMask').classList.remove('show');
|
||||
document.getElementById('sheet').classList.remove('show');
|
||||
}
|
||||
|
||||
function formatNum(v, step) {
|
||||
if (step >= 1) return String(Math.round(v));
|
||||
if (step >= 0.1) return v.toFixed(1);
|
||||
return v.toFixed(2);
|
||||
}
|
||||
|
||||
function renderFields(fields) {
|
||||
var body = document.getElementById('sheetBody');
|
||||
body.innerHTML = '';
|
||||
fields.forEach(function(f, idx) {
|
||||
var wrap = document.createElement('div');
|
||||
wrap.className = 'sheet-field' + (fields.length === 1 ? ' sheet-field--single' : '');
|
||||
var labelHtml = f.label ? '<div class="sheet-field__label">' + f.label + '</div>' : '';
|
||||
wrap.innerHTML =
|
||||
labelHtml +
|
||||
'<div class="sheet-field__value">' +
|
||||
'<span class="sheet-field__num">' + formatNum(f.value, f.step) + '</span>' +
|
||||
'<span class="sheet-field__unit">' + f.unit + '</span>' +
|
||||
'</div>' +
|
||||
'<div class="ruler">' +
|
||||
'<div class="ruler__pointer">' +
|
||||
'<div class="ruler__pointer-flag"></div>' +
|
||||
'<div class="ruler__pointer-line"></div>' +
|
||||
'</div>' +
|
||||
'<div class="ruler__scale" data-idx="' + idx + '"></div>' +
|
||||
'<div class="ruler__labels" data-idx="' + idx + '"></div>' +
|
||||
'</div>';
|
||||
body.appendChild(wrap);
|
||||
renderRulerInto(wrap.querySelector('.ruler__scale'), wrap.querySelector('.ruler__labels'), f);
|
||||
});
|
||||
}
|
||||
|
||||
function renderRulerInto(scale, labels, cfg) {
|
||||
scale.innerHTML = '';
|
||||
labels.innerHTML = '';
|
||||
var pxPerStep = 8;
|
||||
var majorEvery = cfg.majorEvery;
|
||||
var rulerWidth = 358;
|
||||
var totalTicks = Math.floor(rulerWidth / pxPerStep);
|
||||
var centerIndex = Math.floor(totalTicks / 2);
|
||||
for (var i = 0; i < totalTicks; i++) {
|
||||
var offsetSteps = i - centerIndex;
|
||||
var tick = document.createElement('div');
|
||||
tick.className = 'ruler__tick';
|
||||
var isMajor = (Math.abs(offsetSteps) % majorEvery) === 0;
|
||||
tick.classList.add(isMajor ? 'ruler__tick--major' : 'ruler__tick--minor');
|
||||
if (offsetSteps > 0) tick.classList.add('ruler__tick--right');
|
||||
tick.style.left = (i * pxPerStep) + 'px';
|
||||
scale.appendChild(tick);
|
||||
if (isMajor) {
|
||||
var lbl = document.createElement('div');
|
||||
lbl.className = 'ruler__label';
|
||||
var labelVal = cfg.value + offsetSteps * cfg.step;
|
||||
lbl.textContent = formatNum(labelVal, cfg.step);
|
||||
lbl.style.left = (i * pxPerStep) + 'px';
|
||||
labels.appendChild(lbl);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* —— 慢病修改弹窗 —— */
|
||||
var currentYear = 2026;
|
||||
var currentMonth = 6;
|
||||
|
||||
function openDiseaseModal(name) {
|
||||
document.getElementById('diseaseModalTitle').textContent = name;
|
||||
setDiagnosed(false);
|
||||
renderWheels();
|
||||
document.getElementById('diseaseModalMask').classList.add('show');
|
||||
}
|
||||
|
||||
function closeDiseaseModal(e) {
|
||||
if (e && e.target !== e.currentTarget) return;
|
||||
document.getElementById('diseaseModalMask').classList.remove('show');
|
||||
}
|
||||
|
||||
function setDiagnosed(yes) {
|
||||
document.getElementById('radioUndiagnosed').classList.toggle('checked', !yes);
|
||||
document.getElementById('radioDiagnosed').classList.toggle('checked', yes);
|
||||
document.getElementById('diseaseModalDetail').classList.toggle('show', yes);
|
||||
}
|
||||
|
||||
function renderWheels() {
|
||||
var years = [];
|
||||
for (var y = currentYear - 4; y <= currentYear; y++) years.push(y);
|
||||
renderWheelCol('wheelYear', years, currentYear, function(v){ return String(v); });
|
||||
var months = [];
|
||||
for (var m = 2; m <= 6; m++) months.push(m);
|
||||
renderWheelCol('wheelMonth', months, currentMonth, function(v){ return v < 10 ? '0' + v : String(v); });
|
||||
}
|
||||
|
||||
function renderWheelCol(elId, values, activeVal, fmt) {
|
||||
var col = document.getElementById(elId);
|
||||
col.innerHTML = '';
|
||||
values.forEach(function(v) {
|
||||
var item = document.createElement('div');
|
||||
item.className = 'wheel__item';
|
||||
var dist = Math.abs(v - activeVal);
|
||||
if (dist === 0) item.classList.add('wheel__item--active');
|
||||
else if (dist === 1) item.classList.add('wheel__item--near');
|
||||
item.textContent = fmt(v);
|
||||
col.appendChild(item);
|
||||
});
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,542 +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: 28px; flex-shrink: 0; }
|
||||
.scroll-content { flex: 1; overflow-y: auto; background: #f5f7fa; }
|
||||
.scroll-content::-webkit-scrollbar { display: none; }
|
||||
|
||||
/* ===== 日历月导航 ===== */
|
||||
.cal-nav { display: flex; align-items: center; justify-content: space-between; padding: 8px 16px; background: #fff; }
|
||||
.cal-nav__arrow { width: 30px; height: 30px; border-radius: 50%; background: #f5f7fa; display: flex; align-items: center; justify-content: center; cursor: pointer; border: none; flex-shrink: 0; }
|
||||
.cal-nav__arrow svg { width: 14px; height: 14px; stroke: #333; }
|
||||
.cal-nav__month { font-size: 15px; font-weight: 700; color: #1a1a1a; flex: 1; text-align: center; }
|
||||
.cal-nav__toggle { font-size: 12px; color: #36cfc9; cursor: pointer; font-weight: 600; padding: 4px 10px; border-radius: 12px; background: #e8f8f7; flex-shrink: 0; white-space: nowrap; }
|
||||
|
||||
/* ===== 周日历(默认视图) ===== */
|
||||
.week-cal { background: #fff; padding: 0 10px 10px; margin: 0 12px; border-radius: 0 0 16px 16px; box-shadow: 0 4px 14px rgba(0,0,0,0.04); }
|
||||
.week-cal__row { display: flex; gap: 2px; }
|
||||
.week-cal__cell { flex: 1; text-align: center; padding: 8px 0 6px; border-radius: 10px; position: relative; cursor: default; min-width: 0; }
|
||||
.week-cal__cell.today { background: #e8f8f7; }
|
||||
.week-cal__cell.selected { background: #e6f7ff; box-shadow: inset 0 0 0 2px #36cfc9; }
|
||||
.week-cal__wd { font-size: 10px; color: #999; margin-bottom: 4px; }
|
||||
.week-cal__date-wrap { position: relative; display: inline-flex; align-items: center; justify-content: center; width: 32px; height: 32px; margin: 0 auto 4px; }
|
||||
.week-cal__date { font-size: 14px; font-weight: 700; color: #333; position: relative; z-index: 2; }
|
||||
.week-cal__cell.today .week-cal__date { color: #36cfc9; }
|
||||
/* 记录圆圈 */
|
||||
.week-cal__ring { position: absolute; inset: -2px; border-radius: 50%; border: 2.5px solid transparent; z-index: 1; }
|
||||
.week-cal__ring--scale { border-color: #5470c6; } /* 身高秤 蓝色 */
|
||||
.week-cal__ring--bt { border-color: #8b5cf6; } /* 蓝牙秤 紫色 */
|
||||
.week-cal__ring--self { border-color: #c4b5fd; } /* 自记 浅紫色 */
|
||||
.week-cal__ring--fat { border-color: #1e3a5f; } /* 体脂仪 深蓝色 */
|
||||
/* 记录数据 */
|
||||
.week-cal__data { font-size: 10px; color: #666; line-height: 1.4; }
|
||||
.week-cal__data .w { font-weight: 700; color: #333; }
|
||||
.week-cal__data .bf { color: #999; display: block; }
|
||||
|
||||
/* ===== 月日历(展开视图) ===== */
|
||||
.month-cal { background: #fff; padding: 0 10px 10px; margin: 0 12px; border-radius: 0 0 16px 16px; box-shadow: 0 4px 14px rgba(0,0,0,0.04); }
|
||||
.month-cal__weekday { display: grid; grid-template-columns: repeat(7, 1fr); margin-bottom: 2px; }
|
||||
.month-cal__weekday span { font-size: 10px; color: #999; text-align: center; padding: 4px 0; }
|
||||
.month-cal__row { display: grid; grid-template-columns: repeat(7, 1fr); }
|
||||
.month-cal__cell { text-align: center; padding: 2px 1px 4px; min-height: 48px; position: relative; display: flex; flex-direction: column; align-items: center; justify-content: flex-start; border-radius: 8px; cursor: default; }
|
||||
.month-cal__cell.today { background: #e8f8f7; }
|
||||
.month-cal__cell.selected { background: #e6f7ff; box-shadow: inset 0 0 0 2px #36cfc9; }
|
||||
.month-cal__cell.other-month .month-cal__date { color: #ddd; }
|
||||
.month-cal__date-wrap { position: relative; display: inline-flex; align-items: center; justify-content: center; width: 26px; height: 26px; }
|
||||
.month-cal__date { font-size: 13px; font-weight: 600; color: #333; position: relative; z-index: 2; }
|
||||
.month-cal__cell.today .month-cal__date { color: #36cfc9; font-weight: 800; }
|
||||
.month-cal__ring { position: absolute; inset: -2px; border-radius: 50%; border: 2px solid transparent; z-index: 1; }
|
||||
.month-cal__ring--scale { border-color: #5470c6; }
|
||||
.month-cal__ring--bt { border-color: #8b5cf6; }
|
||||
.month-cal__ring--self { border-color: #c4b5fd; }
|
||||
.month-cal__ring--fat { border-color: #1e3a5f; }
|
||||
/* 月历记录数据 */
|
||||
.month-cal__data { font-size: 9px; color: #666; line-height: 1.3; margin-top: 1px; }
|
||||
.month-cal__data .mw { font-weight: 700; color: #333; }
|
||||
.month-cal__data .mbf { color: #999; display: block; }
|
||||
.month-cal__dot { width: 5px; height: 5px; border-radius: 50%; margin-top: 1px; flex-shrink: 0; }
|
||||
.month-cal__dot--scale { background: #5470c6; }
|
||||
.month-cal__dot--bt { background: #8b5cf6; }
|
||||
.month-cal__dot--self { background: #c4b5fd; }
|
||||
.month-cal__dot--fat { background: #1e3a5f; }
|
||||
|
||||
/* ===== 图例 ===== */
|
||||
.legend { display: flex; justify-content: center; gap: 14px; padding: 8px 16px; flex-wrap: wrap; background: #fff; margin: 8px 12px 0; border-radius: 12px; }
|
||||
.legend__item { display: flex; align-items: center; gap: 4px; font-size: 11px; color: #666; }
|
||||
.legend__dot { width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0; }
|
||||
.legend__dot--scale { background: #5470c6; }
|
||||
.legend__dot--bt { background: #8b5cf6; }
|
||||
.legend__dot--self { background: #c4b5fd; }
|
||||
.legend__dot--fat { background: #1e3a5f; }
|
||||
|
||||
/* ===== Tab 栏 ===== */
|
||||
.record-tabs { display: flex; background: #fff; margin: 8px 12px 0; border-radius: 12px; overflow: hidden; }
|
||||
.record-tab { flex: 1; text-align: center; padding: 10px 0; font-size: 13px; font-weight: 600; color: #999; cursor: pointer; position: relative; }
|
||||
.record-tab.active { color: #36cfc9; }
|
||||
.record-tab.active::after { content: ''; position: absolute; bottom: 4px; left: 50%; transform: translateX(-50%); width: 20px; height: 3px; background: #36cfc9; border-radius: 2px; }
|
||||
|
||||
/* ===== 列表区域 ===== */
|
||||
.record-list { padding: 8px 12px 16px; display: flex; flex-direction: column; gap: 8px; }
|
||||
.record-item { background: #fff; border-radius: 14px; padding: 14px; box-shadow: 0 2px 8px rgba(0,0,0,0.03); }
|
||||
.record-item.clickable { cursor: pointer; transition: transform 0.15s; text-decoration: none; display: block; }
|
||||
.record-item.clickable:active { transform: scale(0.98); }
|
||||
.record-item__header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 10px; }
|
||||
.record-item__title { font-size: 14px; font-weight: 700; color: #1a1a1a; }
|
||||
.record-item__time { font-size: 11px; color: #bbb; }
|
||||
.record-item__body { display: flex; align-items: center; gap: 16px; }
|
||||
.record-item__metric { text-align: center; min-width: 50px; }
|
||||
.record-item__metric-label { font-size: 10px; color: #999; margin-bottom: 2px; }
|
||||
.record-item__metric-val { font-size: 16px; font-weight: 700; color: #1a1a1a; }
|
||||
.record-item__metric-unit { font-size: 10px; color: #999; font-weight: 400; margin-left: 1px; }
|
||||
.record-item__source { margin-left: auto; display: flex; align-items: center; gap: 8px; }
|
||||
.record-item__arrow { width: 24px; height: 24px; display: flex; align-items: center; justify-content: center; flex-shrink: 0; }
|
||||
.source-badge { display: inline-block; padding: 4px 10px; border-radius: 12px; font-size: 11px; font-weight: 600; }
|
||||
.source-badge--scale { background: #e8effa; color: #5470c6; }
|
||||
.source-badge--bt { background: #f3efff; color: #8b5cf6; }
|
||||
.source-badge--self { background: #f5f0ff; color: #a78bfa; }
|
||||
.source-badge--fat { background: #e6edf5; color: #1e3a5f; }
|
||||
|
||||
.record-empty { text-align: center; padding: 40px 20px; color: #ccc; font-size: 14px; }
|
||||
|
||||
.bottom-safe { height: 20px; flex-shrink: 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" onclick="location.href='weight-main.html'">
|
||||
<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"/></svg>
|
||||
</div>
|
||||
<div class="nav-title">体重记录</div>
|
||||
<div class="nav-placeholder"></div>
|
||||
</div>
|
||||
<div class="scroll-content">
|
||||
|
||||
<!-- 日历月导航 -->
|
||||
<div class="cal-nav">
|
||||
<div class="cal-nav__arrow" onclick="prevMonth()">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="15 18 9 12 15 6"/></svg>
|
||||
</div>
|
||||
<div class="cal-nav__month" id="calMonthLabel">2026年06月</div>
|
||||
<div class="cal-nav__arrow" onclick="nextMonth()">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="9 18 15 12 9 6"/></svg>
|
||||
</div>
|
||||
<div class="cal-nav__toggle" id="calToggle" onclick="toggleCalView()">展开月历</div>
|
||||
</div>
|
||||
|
||||
<!-- 周日历(默认) -->
|
||||
<div class="week-cal" id="weekCal"></div>
|
||||
|
||||
<!-- 月日历(展开后显示) -->
|
||||
<div class="month-cal" id="monthCal" style="display:none;"></div>
|
||||
|
||||
<!-- 图例 -->
|
||||
<div class="legend">
|
||||
<div class="legend__item"><span class="legend__dot legend__dot--scale"></span>体重秤</div>
|
||||
<div class="legend__item"><span class="legend__dot legend__dot--bt"></span>蓝牙秤</div>
|
||||
<div class="legend__item"><span class="legend__dot legend__dot--self"></span>自记</div>
|
||||
<div class="legend__item"><span class="legend__dot legend__dot--fat"></span>体脂仪</div>
|
||||
</div>
|
||||
|
||||
<!-- Tab 栏 -->
|
||||
<div class="record-tabs" id="recordTabs">
|
||||
<div class="record-tab active" data-range="week" onclick="switchTab('week')">周</div>
|
||||
<div class="record-tab" data-range="month" onclick="switchTab('month')">月</div>
|
||||
<div class="record-tab" data-range="quarter" onclick="switchTab('quarter')">季</div>
|
||||
<div class="record-tab" data-range="activity" onclick="switchTab('activity')">活动期间</div>
|
||||
<div class="record-tab" data-range="all" onclick="switchTab('all')">全部</div>
|
||||
</div>
|
||||
|
||||
<!-- 记录列表 -->
|
||||
<div class="record-list" id="recordList"></div>
|
||||
|
||||
<div class="bottom-safe"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
/* ===== 数据 ===== */
|
||||
// 来源类型及其颜色映射
|
||||
var SOURCE_TYPES = {
|
||||
'scale': { label:'体重秤', css:'scale', ring:'week-cal__ring--scale', mring:'month-cal__ring--scale', dot:'month-cal__dot--scale', badge:'source-badge--scale' },
|
||||
'bt': { label:'蓝牙秤', css:'bt', ring:'week-cal__ring--bt', mring:'month-cal__ring--bt', dot:'month-cal__dot--bt', badge:'source-badge--bt' },
|
||||
'self': { label:'自记', css:'self', ring:'week-cal__ring--self', mring:'month-cal__ring--self', dot:'month-cal__dot--self', badge:'source-badge--self' },
|
||||
'fat': { label:'体脂仪', css:'fat', ring:'week-cal__ring--fat', mring:'month-cal__ring--fat', dot:'month-cal__dot--fat', badge:'source-badge--fat' }
|
||||
};
|
||||
|
||||
// 模拟体重记录数据
|
||||
var RECORDS = [
|
||||
{ date:'2026-06-13', title:'晨起空腹测量', weight:66.3, bodyFat:23.3, waist:81.5, time:'07:30', source:'bt' },
|
||||
{ date:'2026-06-12', title:'晨起空腹测量', weight:66.5, bodyFat:23.5, waist:81.5, time:'06:45', source:'scale' },
|
||||
{ date:'2026-06-10', title:'运动后测量', weight:66.8, bodyFat:23.7, waist:null, time:'19:20', source:'bt' },
|
||||
{ date:'2026-06-08', title:'晨起空腹测量', weight:67.0, bodyFat:23.9, waist:null, time:'07:15', source:'scale' },
|
||||
{ date:'2026-06-07', title:'健身房测量', weight:67.2, bodyFat:24.1, waist:82.0, time:'18:00', source:'fat' },
|
||||
{ date:'2026-06-05', title:'手动录入', weight:67.5, bodyFat:null, waist:null, time:'08:30', source:'self' },
|
||||
{ date:'2026-06-03', title:'晨起空腹测量', weight:67.8, bodyFat:24.5, waist:null, time:'07:00', source:'bt' },
|
||||
{ date:'2026-06-01', title:'晨起空腹测量', weight:68.2, bodyFat:24.8, waist:82.5, time:'07:20', source:'scale' },
|
||||
{ date:'2026-05-28', title:'晨起空腹测量', weight:68.5, bodyFat:25.0, waist:83.0, time:'07:10', source:'scale' },
|
||||
{ date:'2026-05-25', title:'午间测量', weight:68.9, bodyFat:25.2, waist:null, time:'12:30', source:'bt' },
|
||||
{ date:'2026-05-20', title:'晨起空腹测量', weight:69.5, bodyFat:25.5, waist:83.5, time:'06:50', source:'fat' },
|
||||
{ date:'2026-05-15', title:'手动录入', weight:70.0, bodyFat:null, waist:null, time:'09:00', source:'self' },
|
||||
{ date:'2026-05-10', title:'晨起空腹测量', weight:70.5, bodyFat:26.0, waist:84.0, time:'07:05', source:'scale' },
|
||||
{ date:'2026-05-05', title:'晨起空腹测量', weight:71.2, bodyFat:26.5, waist:84.5, time:'07:30', source:'bt' },
|
||||
{ date:'2026-05-01', title:'晨起空腹测量', weight:71.8, bodyFat:27.0, waist:85.0, time:'08:00', source:'scale' },
|
||||
{ date:'2026-04-25', title:'晨起空腹测量', weight:72.5, bodyFat:27.5, waist:85.5, time:'07:00', source:'fat' },
|
||||
{ date:'2026-04-20', title:'晨起空腹测量', weight:73.0, bodyFat:28.0, waist:86.0, time:'07:15', source:'scale' },
|
||||
{ date:'2026-04-10', title:'晨起空腹测量', weight:73.3, bodyFat:28.3, waist:86.5, time:'07:20', source:'bt' },
|
||||
];
|
||||
|
||||
// 活动期间范围
|
||||
var ACTIVITY_START = new Date(2026, 4, 1); // 2026-05-01
|
||||
var ACTIVITY_END = new Date(2026, 7, 1); // 2026-08-01
|
||||
|
||||
/* ===== 状态 ===== */
|
||||
var calYear = 2026;
|
||||
var calMonth = 6; // 0-based
|
||||
var calExpanded = false; // 月历是否展开
|
||||
var activeTab = 'week';
|
||||
var selectedDate = null; // 当前选中的日期('YYYY-MM-DD'),null 时按tab范围过滤
|
||||
|
||||
// 今天
|
||||
var TODAY = new Date(2026, 5, 12); // 2026-06-12
|
||||
|
||||
/* ===== 工具函数 ===== */
|
||||
function fmt(n) { return n < 10 ? '0' + n : '' + n; }
|
||||
function dateStr(y, m, d) { return y + '-' + fmt(m+1) + '-' + fmt(d); }
|
||||
function parseDate(s) { var p = s.split('-'); return new Date(+p[0], +p[1]-1, +p[2]); }
|
||||
function sameDay(a, b) { return a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth() && a.getDate() === b.getDate(); }
|
||||
|
||||
// 获取某天的记录
|
||||
function getRecord(y, m, d) {
|
||||
var s = dateStr(y, m, d);
|
||||
for (var i = 0; i < RECORDS.length; i++) {
|
||||
if (RECORDS[i].date === s) return RECORDS[i];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/* ===== 渲染周日历 ===== */
|
||||
var WEEKDAY_LABELS = ['一','二','三','四','五','六','日'];
|
||||
|
||||
function getWeekStart() {
|
||||
// 返回当前显示月份中第一个周一(可能在上一月)
|
||||
var first = new Date(calYear, calMonth, 1);
|
||||
var day = first.getDay(); // 0=周日
|
||||
var monday = new Date(first);
|
||||
monday.setDate(1 - (day === 0 ? 6 : day - 1));
|
||||
return monday;
|
||||
}
|
||||
|
||||
function renderWeekCal() {
|
||||
var container = document.getElementById('weekCal');
|
||||
// 找到当月包含本周的周一。简单起见:如果当前日期的月份与显示月份相同,从当前周一开始;否则从该月第一天所在周一开始
|
||||
var now = new Date(2026, 5, 12); // 固定"今天" = 2026-06-12
|
||||
var start;
|
||||
if (calYear === now.getFullYear() && calMonth === now.getMonth()) {
|
||||
// 当前月:从今天所在的周一开始
|
||||
var dow = now.getDay() || 7;
|
||||
start = new Date(now);
|
||||
start.setDate(now.getDate() - dow + 1);
|
||||
} else {
|
||||
start = getWeekStart();
|
||||
}
|
||||
|
||||
var html = '<div class="week-cal__row">';
|
||||
for (var i = 0; i < 7; i++) {
|
||||
var d = new Date(start);
|
||||
d.setDate(start.getDate() + i);
|
||||
var rec = getRecord(d.getFullYear(), d.getMonth(), d.getDate());
|
||||
var isToday = sameDay(d, TODAY);
|
||||
var isoOtherMonth = d.getMonth() !== calMonth;
|
||||
var dateKey = dateStr(d.getFullYear(), d.getMonth(), d.getDate());
|
||||
var isSel = dateKey === selectedDate;
|
||||
|
||||
html += '<div class="week-cal__cell' + (isToday ? ' today' : '') + (isSel ? ' selected' : '') + '"'
|
||||
+ ' onclick="onDayClick(\'' + dateStr(d.getFullYear(), d.getMonth(), d.getDate()) + '\')" style="cursor:' + (rec ? 'pointer' : 'default') + '">';
|
||||
html += '<div class="week-cal__wd">' + WEEKDAY_LABELS[i] + '</div>';
|
||||
html += '<div class="week-cal__date-wrap">';
|
||||
if (rec) {
|
||||
html += '<div class="week-cal__ring ' + SOURCE_TYPES[rec.source].ring + '"></div>';
|
||||
}
|
||||
html += '<span class="week-cal__date" style="' + (isoOtherMonth ? 'color:#ddd' : '') + '">' + (isToday ? '今' : d.getDate()) + '</span>';
|
||||
html += '</div>';
|
||||
html += '<div class="week-cal__data">';
|
||||
if (rec) {
|
||||
html += '<span class="w">' + rec.weight.toFixed(1) + 'kg</span>';
|
||||
if (rec.bodyFat !== null) {
|
||||
html += '<span class="bf">' + rec.bodyFat.toFixed(1) + '%</span>';
|
||||
}
|
||||
}
|
||||
html += '</div>';
|
||||
html += '</div>';
|
||||
}
|
||||
html += '</div>';
|
||||
container.innerHTML = html;
|
||||
}
|
||||
|
||||
/* ===== 渲染月日历 ===== */
|
||||
function renderMonthCal() {
|
||||
var container = document.getElementById('monthCal');
|
||||
// 周日历抬头
|
||||
var html = '<div class="month-cal__weekday">';
|
||||
for (var w = 0; w < 7; w++) { html += '<span>' + WEEKDAY_LABELS[w] + '</span>'; }
|
||||
html += '</div>';
|
||||
|
||||
var first = new Date(calYear, calMonth, 1);
|
||||
var startDow = first.getDay() || 7; // 1=周一 … 7=周日
|
||||
var cursor = new Date(first);
|
||||
cursor.setDate(1 - (startDow - 1)); // 回退到该行周一
|
||||
|
||||
var done = false;
|
||||
for (var row = 0; row < 6 && !done; row++) {
|
||||
html += '<div class="month-cal__row">';
|
||||
for (var col = 0; col < 7; col++) {
|
||||
var isOther = cursor.getMonth() !== calMonth;
|
||||
var isToday = sameDay(cursor, TODAY);
|
||||
var dateKey = dateStr(cursor.getFullYear(), cursor.getMonth(), cursor.getDate());
|
||||
var isSel = dateKey === selectedDate;
|
||||
var rec = getRecord(cursor.getFullYear(), cursor.getMonth(), cursor.getDate());
|
||||
|
||||
html += '<div class="month-cal__cell' + (isToday ? ' today' : '') + (isOther ? ' other-month' : '') + (isSel ? ' selected' : '') + '"'
|
||||
+ ' onclick="onDayClick(\'' + dateStr(cursor.getFullYear(), cursor.getMonth(), cursor.getDate()) + '\')" style="cursor:' + (rec ? 'pointer' : 'default') + '">';
|
||||
html += '<div class="month-cal__date-wrap">';
|
||||
if (rec) {
|
||||
html += '<div class="month-cal__ring ' + SOURCE_TYPES[rec.source].mring + '"></div>';
|
||||
}
|
||||
html += '<span class="month-cal__date">' + (isToday ? '今' : cursor.getDate()) + '</span>';
|
||||
html += '</div>';
|
||||
html += '<div class="month-cal__data">';
|
||||
if (rec) {
|
||||
html += '<span class="mw">' + rec.weight.toFixed(1) + 'kg</span>';
|
||||
if (rec.bodyFat !== null) {
|
||||
html += '<span class="mbf">' + rec.bodyFat.toFixed(1) + '%</span>';
|
||||
}
|
||||
}
|
||||
html += '</div>';
|
||||
html += '</div>';
|
||||
|
||||
cursor.setDate(cursor.getDate() + 1);
|
||||
if (col === 6 && cursor.getDate() > 7 && cursor.getMonth() !== calMonth) { done = true; }
|
||||
}
|
||||
html += '</div>';
|
||||
}
|
||||
container.innerHTML = html;
|
||||
}
|
||||
|
||||
/* ===== 日历展开/收起 ===== */
|
||||
function toggleCalView() {
|
||||
calExpanded = !calExpanded;
|
||||
document.getElementById('weekCal').style.display = calExpanded ? 'none' : '';
|
||||
document.getElementById('monthCal').style.display = calExpanded ? '' : 'none';
|
||||
document.getElementById('calToggle').textContent = calExpanded ? '收起月历' : '展开月历';
|
||||
if (calExpanded) renderMonthCal();
|
||||
}
|
||||
|
||||
/* ===== 月份切换 ===== */
|
||||
function prevMonth() {
|
||||
if (calExpanded) {
|
||||
// 月视图:按整月切换
|
||||
calMonth--;
|
||||
if (calMonth < 0) { calMonth = 11; calYear--; }
|
||||
} else {
|
||||
// 周视图:按周切换(切换到上一周,可能跨月)
|
||||
var now = new Date(2026, 5, 12);
|
||||
var dow = now.getDay() || 7;
|
||||
var curWeekStart;
|
||||
if (calYear === now.getFullYear() && calMonth === now.getMonth()) {
|
||||
curWeekStart = new Date(now);
|
||||
curWeekStart.setDate(now.getDate() - dow + 1);
|
||||
} else {
|
||||
curWeekStart = getWeekStart();
|
||||
}
|
||||
// 上一周
|
||||
curWeekStart.setDate(curWeekStart.getDate() - 7);
|
||||
calYear = curWeekStart.getFullYear();
|
||||
calMonth = curWeekStart.getMonth();
|
||||
}
|
||||
updateCal();
|
||||
}
|
||||
|
||||
function nextMonth() {
|
||||
if (calExpanded) {
|
||||
calMonth++;
|
||||
if (calMonth > 11) { calMonth = 0; calYear++; }
|
||||
} else {
|
||||
var now = new Date(2026, 5, 12);
|
||||
var dow = now.getDay() || 7;
|
||||
var curWeekStart;
|
||||
if (calYear === now.getFullYear() && calMonth === now.getMonth()) {
|
||||
curWeekStart = new Date(now);
|
||||
curWeekStart.setDate(now.getDate() - dow + 1);
|
||||
} else {
|
||||
curWeekStart = getWeekStart();
|
||||
}
|
||||
curWeekStart.setDate(curWeekStart.getDate() + 7);
|
||||
calYear = curWeekStart.getFullYear();
|
||||
calMonth = curWeekStart.getMonth();
|
||||
}
|
||||
updateCal();
|
||||
}
|
||||
|
||||
function updateCal() {
|
||||
document.getElementById('calMonthLabel').textContent = calYear + '年' + fmt(calMonth + 1) + '月';
|
||||
renderWeekCal();
|
||||
if (calExpanded) renderMonthCal();
|
||||
}
|
||||
|
||||
/* ===== Tab 切换 ===== */
|
||||
function switchTab(range) {
|
||||
activeTab = range;
|
||||
selectedDate = null; // 清除日期选中
|
||||
document.querySelectorAll('.record-tab').forEach(function(t) {
|
||||
t.classList.toggle('active', t.dataset.range === range);
|
||||
});
|
||||
updateCal(); // 刷新日历高亮
|
||||
renderRecordList();
|
||||
}
|
||||
|
||||
/* ===== 日期范围计算 ===== */
|
||||
function getTabDateRange() {
|
||||
// 以"今天" 2026-06-12 为基准
|
||||
var now = new Date(2026, 5, 12);
|
||||
var start, end;
|
||||
switch (activeTab) {
|
||||
case 'week':
|
||||
// 本周:周一到周日
|
||||
var dow = now.getDay() || 7;
|
||||
start = new Date(now); start.setDate(now.getDate() - dow + 1);
|
||||
end = new Date(start); end.setDate(start.getDate() + 6);
|
||||
break;
|
||||
case 'month':
|
||||
start = new Date(now.getFullYear(), now.getMonth(), 1);
|
||||
end = new Date(now.getFullYear(), now.getMonth() + 1, 0);
|
||||
break;
|
||||
case 'quarter':
|
||||
var q = Math.floor(now.getMonth() / 3);
|
||||
start = new Date(now.getFullYear(), q * 3, 1);
|
||||
end = new Date(now.getFullYear(), (q + 1) * 3, 0);
|
||||
break;
|
||||
case 'activity':
|
||||
start = ACTIVITY_START;
|
||||
end = ACTIVITY_END;
|
||||
break;
|
||||
case 'all':
|
||||
start = new Date(2000, 0, 1);
|
||||
end = new Date(2099, 11, 31);
|
||||
break;
|
||||
}
|
||||
return { start: start, end: end };
|
||||
}
|
||||
|
||||
/* ===== 渲染记录列表 ===== */
|
||||
function renderRecordList() {
|
||||
var filtered;
|
||||
if (selectedDate) {
|
||||
// 按选中日期过滤
|
||||
filtered = RECORDS.filter(function(r) { return r.date === selectedDate; });
|
||||
} else {
|
||||
var range = getTabDateRange();
|
||||
filtered = RECORDS.filter(function(r) {
|
||||
var d = parseDate(r.date);
|
||||
return d >= range.start && d <= range.end;
|
||||
});
|
||||
}
|
||||
|
||||
var container = document.getElementById('recordList');
|
||||
if (filtered.length === 0) {
|
||||
container.innerHTML = '<div class="record-empty">该时间段暂无记录</div>';
|
||||
return;
|
||||
}
|
||||
|
||||
var html = '';
|
||||
// 设备来源到 URL device 参数的映射
|
||||
var deviceParamMap = { 'scale': 'scale', 'bt': 'bluetooth', 'fat': 'fat' };
|
||||
for (var i = 0; i < filtered.length; i++) {
|
||||
var r = filtered[i];
|
||||
var src = SOURCE_TYPES[r.source];
|
||||
var isSelf = r.source === 'self';
|
||||
var deviceParam = deviceParamMap[r.source];
|
||||
// 非自记来源:用 <a> 标签包裹,可点击跳转
|
||||
if (!isSelf && deviceParam) {
|
||||
html += '<a class="record-item clickable" href="report-detail.html?device=' + deviceParam + '">';
|
||||
} else {
|
||||
html += '<div class="record-item">';
|
||||
}
|
||||
html += '<div class="record-item__header">';
|
||||
html += '<span class="record-item__title">体重记录</span>';
|
||||
html += '<span class="record-item__time">' + r.date + ' ' + r.time + '</span>';
|
||||
html += '</div>';
|
||||
html += '<div class="record-item__body">';
|
||||
html += '<div class="record-item__metric"><div class="record-item__metric-label">体重</div><div class="record-item__metric-val">' + r.weight.toFixed(1) + '<span class="record-item__metric-unit">kg</span></div></div>';
|
||||
if (r.bodyFat !== null) {
|
||||
html += '<div class="record-item__metric"><div class="record-item__metric-label">体脂率</div><div class="record-item__metric-val">' + r.bodyFat.toFixed(1) + '<span class="record-item__metric-unit">%</span></div></div>';
|
||||
}
|
||||
if (r.waist !== null) {
|
||||
html += '<div class="record-item__metric"><div class="record-item__metric-label">腰围</div><div class="record-item__metric-val">' + r.waist.toFixed(1) + '<span class="record-item__metric-unit">cm</span></div></div>';
|
||||
}
|
||||
html += '<div class="record-item__source"><span class="source-badge ' + src.badge + '">' + src.label + '</span>';
|
||||
// 非自记来源:显示箭头
|
||||
if (!isSelf) {
|
||||
html += '<div class="record-item__arrow"><svg width="7" height="12" fill="none"><path d="M1 1l5 5-5 5" stroke="#ccc" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg></div>';
|
||||
}
|
||||
html += '</div>';
|
||||
html += '</div>';
|
||||
// 闭合标签
|
||||
if (!isSelf && deviceParam) {
|
||||
html += '</a>';
|
||||
} else {
|
||||
html += '</div>';
|
||||
}
|
||||
}
|
||||
container.innerHTML = html;
|
||||
}
|
||||
|
||||
/* ===== 点击日期 ===== */
|
||||
function onDayClick(dateStr) {
|
||||
// 再次点击已选中的日期 → 取消选中,回到周tab
|
||||
if (selectedDate === dateStr) {
|
||||
switchTab('week');
|
||||
return;
|
||||
}
|
||||
// 选中日期,取消所有tab高亮
|
||||
selectedDate = dateStr;
|
||||
activeTab = '';
|
||||
document.querySelectorAll('.record-tab').forEach(function(t) { t.classList.remove('active'); });
|
||||
updateCal();
|
||||
renderRecordList();
|
||||
document.querySelector('.scroll-content').scrollTop = document.getElementById('recordTabs').offsetTop - 100;
|
||||
}
|
||||
|
||||
/* ===== 初始化 ===== */
|
||||
function init() {
|
||||
calYear = TODAY.getFullYear();
|
||||
calMonth = TODAY.getMonth();
|
||||
document.getElementById('calMonthLabel').textContent = calYear + '年' + fmt(calMonth + 1) + '月';
|
||||
renderWeekCal();
|
||||
renderRecordList();
|
||||
}
|
||||
init();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user