diff --git a/src/pages/index/index.vue b/src/pages/index/index.vue index 07734e6..07f5786 100644 --- a/src/pages/index/index.vue +++ b/src/pages/index/index.vue @@ -17,7 +17,7 @@ - + 无烟旅程 @@ -27,17 +27,36 @@ - - - - {{ quitDays }} - + + + + 肺部 HP + {{ hpValue }} + {{ hpState.label }} + + + + + {{ hpState.title }} + {{ hpState.description }} + + + 今日状态 + {{ hpChangeText }} + + + 下一节点 + {{ nextHealthMilestoneText }} + - 连续无烟 + + 连续无烟 + {{ quitDays }} 天 + 已省下 ¥{{ savedMoney }} @@ -93,13 +112,13 @@ - + - 肺部恢复可视化 + 恢复轨迹 - - {{ healthProgress >= 100 ? '已达成' : `${healthProgress}%` }} + + {{ `HP ${hpValue}` }} @@ -389,8 +408,8 @@ 已连续无烟 {{ quitDays }} 天,{{ lungPhaseLabel }} - 肺部恢复 - {{ healthProgress }}% + 肺部 HP + {{ hpValue }} 已省下 @@ -533,6 +552,87 @@ const healthProgress = computed(() => { return 0 }) +const hpValue = computed(() => { + const raw = quitSummary.value.hp_current ?? healthProgress.value + const value = Number(raw) + if (Number.isNaN(value)) return 0 + return Math.min(Math.max(Math.round(value), 0), 100) +}) + +const hpState = computed(() => { + if (hpValue.value <= 20) { + return { + label: '危险期', + title: '先保住今天的底线', + description: '身体恢复动力偏弱,先把眼前这一波烟瘾稳住最重要。', + accent: '#64748b', + soft: '#e2e8f0', + deep: '#334155' + } + } + if (hpValue.value <= 40) { + return { + label: '恢复中', + title: '状态正在往回拉', + description: '已经开始脱离最低谷,再多守住几次关键时刻,HP 会明显回升。', + accent: '#0f766e', + soft: '#ccfbf1', + deep: '#115e59' + } + } + if (hpValue.value <= 60) { + return { + label: '稳定期', + title: '节奏开始站稳', + description: '你已经进入可持续恢复阶段,规律打卡会让状态越来越稳。', + accent: '#0891b2', + soft: '#cffafe', + deep: '#155e75' + } + } + if (hpValue.value <= 80) { + return { + label: '强韧期', + title: '恢复势头很不错', + description: '肺部状态正在加速恢复,继续把高风险场景提前处理掉。', + accent: '#16a34a', + soft: '#dcfce7', + deep: '#166534' + } + } + return { + label: '高能期', + title: '你已经进入高能状态', + description: '当前状态非常好,保持日常节奏和打卡,就能继续巩固恢复成果。', + accent: '#ea580c', + soft: '#ffedd5', + deep: '#9a3412' + } +}) + +const hpVisualStyle = computed(() => ({ + '--hp-accent': hpState.value.accent, + '--hp-soft': hpState.value.soft, + '--hp-deep': hpState.value.deep +})) + +const hpGaugeStyle = computed(() => { + const angle = Math.round(hpValue.value * 3.6) + return { + background: `conic-gradient(var(--hp-accent) 0deg ${angle}deg, rgba(226, 232, 240, 0.88) ${angle}deg 360deg)` + } +}) + +const hpChangeText = computed(() => { + const serverDelta = Number(quitSummary.value.hp_change_today ?? quitSummary.value.hp_delta_today ?? quitSummary.value.hp_change) + if (!Number.isNaN(serverDelta) && serverDelta !== 0) { + return serverDelta > 0 ? `今日 +${serverDelta}` : `今日 ${serverDelta}` + } + if (todayChecked.value) return '今日已保住状态' + if (quitDays.value > 0) return '先打卡再继续回血' + return '从今天开始积累' +}) + const healthTip = computed(() => { if (quitDays.value >= 365) return '肺部功能显著改善,心血管疾病风险大幅降低' if (quitDays.value >= 180) return '血液循环持续改善,肺功能逐步恢复' @@ -592,15 +692,17 @@ const smokeFreeTimeLabel = computed(() => { }) const lungRecoveryFillStyle = computed(() => ({ - height: `${Math.max(healthProgress.value, 6)}%` + height: `${Math.max(hpValue.value, 6)}%`, + background: `linear-gradient(180deg, ${hpState.value.soft} 0%, ${hpState.value.accent} 100%)` })) const lungPhaseLabel = computed(() => { - if (healthProgress.value >= 100) return '肺功能已接近长期恢复水平' - if (healthProgress.value >= 70) return '肺部纤毛清理能力持续增强' - if (healthProgress.value >= 40) return '呼吸效率进入稳定恢复期' - if (healthProgress.value >= 15) return '肺部正在排出残留刺激物' - return '身体已启动自我修复' + if (hpValue.value >= 100) return '肺部状态已进入长期巩固阶段' + if (hpValue.value >= 80) return '当前恢复速度很稳定' + if (hpValue.value >= 60) return '肺部恢复节奏正在变强' + if (hpValue.value >= 40) return '身体正在持续找回呼吸效率' + if (hpValue.value >= 20) return '恢复已经启动,别让节奏断掉' + return '先把今天守住,HP 就会慢慢往上走' }) const lungRecoverySummary = computed(() => { @@ -616,9 +718,9 @@ const nextHealthMilestoneText = computed(() => { }) const lungMomentumText = computed(() => { - if (healthProgress.value >= 100) return '稳定达成' - if (healthProgress.value >= 60) return '恢复加速中' - if (healthProgress.value >= 20) return '持续上升' + if (hpValue.value >= 100) return '稳定达成' + if (hpValue.value >= 70) return '恢复加速中' + if (hpValue.value >= 35) return '持续回升' return '刚刚启动' }) @@ -1130,12 +1232,15 @@ onShareAppMessage(() => ({ left: -72rpx; top: -72rpx; border-radius: 50%; - background: radial-gradient(circle, rgba(52, 200, 160, 0.14) 0%, rgba(52, 200, 160, 0) 72%); + background: radial-gradient(circle, var(--hp-soft, rgba(52, 200, 160, 0.18)) 0%, rgba(52, 200, 160, 0) 72%); pointer-events: none; } .quit-hero-card { padding: 28rpx 24rpx; + --hp-accent: #14936d; + --hp-soft: #def7ec; + --hp-deep: #0f766e; } .quit-hero-top, @@ -1177,7 +1282,7 @@ onShareAppMessage(() => ({ font-size: 28rpx; line-height: 1.5; font-weight: 700; - color: #14936d; + color: var(--hp-accent); } .quit-hero-chip { @@ -1193,63 +1298,131 @@ onShareAppMessage(() => ({ .quit-overview { display: flex; - align-items: center; + flex-direction: column; gap: 18rpx; } -.quit-days-card { - width: 216rpx; - flex-shrink: 0; +.quit-hp-panel { display: flex; - flex-direction: column; align-items: center; + gap: 18rpx; + padding: 18rpx; + border-radius: 26rpx; + background: linear-gradient(135deg, rgba(255, 255, 255, 0.94) 0%, rgba(248, 251, 249, 0.92) 100%); + border: 1rpx solid rgba(15, 23, 42, 0.05); + box-shadow: inset 0 1rpx 0 rgba(255, 255, 255, 0.92); } -.quit-days-ring { +.quit-hp-ring { width: 200rpx; height: 200rpx; - padding: 14rpx; + padding: 12rpx; border-radius: 50%; - background: linear-gradient(180deg, #ffffff 0%, #f8fbf9 100%); - border: 1rpx solid rgba(15, 23, 42, 0.05); - box-shadow: inset 0 2rpx 6rpx rgba(15, 23, 42, 0.04), 0 10rpx 24rpx rgba(15, 23, 42, 0.05); + display: flex; + align-items: center; + justify-content: center; + flex-shrink: 0; + box-shadow: 0 16rpx 34rpx rgba(15, 23, 42, 0.08); } -.quit-days-ring-inner { +.quit-hp-ring-inner { width: 100%; height: 100%; border-radius: 50%; - background: linear-gradient(180deg, rgba(240, 252, 248, 0.96) 0%, rgba(248, 251, 249, 0.96) 100%); + background: linear-gradient(180deg, #ffffff 0%, #f7faf8 100%); display: flex; flex-direction: column; align-items: center; justify-content: center; box-shadow: inset 0 1rpx 0 rgba(255, 255, 255, 0.92); + padding: 0 12rpx; + text-align: center; } -.quit-days-number { +.quit-hp-ring-kicker { + font-size: 20rpx; + font-weight: 700; + color: #6b7280; +} + +.quit-hp-ring-value { + margin-top: 10rpx; font-size: 74rpx; font-weight: 800; line-height: 1; - color: #14936d; + color: var(--hp-accent); font-family: 'DIN Alternate', -apple-system, sans-serif; } -.quit-days-label { - margin-top: 6rpx; - font-size: 26rpx; - font-weight: 600; - color: #6b7280; +.quit-hp-ring-label { + margin-top: 8rpx; + padding: 8rpx 16rpx; + border-radius: 999rpx; + background: var(--hp-soft); + color: var(--hp-deep); + font-size: 21rpx; + font-weight: 700; } -.quit-days-hint { - margin-top: 16rpx; - font-size: 24rpx; - color: #6b7280; +.quit-hp-copy { + flex: 1; + min-width: 0; + display: flex; + flex-direction: column; + justify-content: center; +} + +.quit-hp-title { + display: block; + font-size: 32rpx; + line-height: 1.35; + font-weight: 800; + color: var(--hp-deep); +} + +.quit-hp-desc { + display: block; + margin-top: 10rpx; + font-size: 23rpx; + line-height: 1.7; + color: #4b5563; +} + +.quit-hp-pill-row { + display: flex; + gap: 12rpx; + margin-top: 18rpx; +} + +.quit-hp-pill { + flex: 1; + min-width: 0; + padding: 14rpx 16rpx; + border-radius: 18rpx; + background: rgba(255, 255, 255, 0.8); + border: 1rpx solid rgba(15, 23, 42, 0.05); +} + +.quit-hp-pill-strong { + background: linear-gradient(180deg, var(--hp-soft) 0%, rgba(255, 255, 255, 0.88) 100%); +} + +.quit-hp-pill-label { + display: block; + font-size: 18rpx; + color: #9ca3af; +} + +.quit-hp-pill-value { + display: block; + margin-top: 6rpx; + font-size: 22rpx; + font-weight: 700; + color: #111827; } .quit-metrics-grid { - flex: 1; + width: 100%; display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 14rpx; @@ -2291,7 +2464,7 @@ onShareAppMessage(() => ({ font-size: 30rpx; line-height: 1.4; font-weight: 800; - color: #0f766e; + color: var(--hp-deep, #0f766e); } .quit-lung-desc {