31e504a997
- 在 onboarding 页面中新增使用模式选择功能,用户可选择“戒烟打卡”或“记录抽烟”模式 - 更新个人资料页面以显示当前模式并允许用户切换模式 - 在 pages.json 中注册新的模式选择页面 - 优化首页和其他相关页面以适应新模式功能
220 lines
4.8 KiB
Vue
220 lines
4.8 KiB
Vue
<template>
|
||
<view class="page">
|
||
<view class="nav-placeholder" :style="{ height: navBarHeight + 'px' }"></view>
|
||
|
||
<view class="content">
|
||
<view class="hero">
|
||
<text class="eyebrow">首次进入先选模式</text>
|
||
<text class="title">你现在想怎么用这个小程序?</text>
|
||
<text class="subtitle">先选“戒烟打卡”或“记录抽烟”,后续可以在个人中心随时切换。</text>
|
||
</view>
|
||
|
||
<view
|
||
class="mode-card"
|
||
:class="{ 'mode-card-active': currentMode === 'quit' }"
|
||
@tap="selectMode('quit')"
|
||
>
|
||
<view class="mode-icon mode-icon-quit">🔥</view>
|
||
<view class="mode-main">
|
||
<text class="mode-title">戒烟打卡</text>
|
||
<text class="mode-desc">按天记录“今天没抽”,用连续天数驱动坚持。</text>
|
||
</view>
|
||
<text class="mode-arrow">›</text>
|
||
</view>
|
||
|
||
<view
|
||
class="mode-card"
|
||
:class="{ 'mode-card-active': currentMode === 'record' }"
|
||
@tap="selectMode('record')"
|
||
>
|
||
<view class="mode-icon mode-icon-record">🚬</view>
|
||
<view class="mode-main">
|
||
<text class="mode-title">记录抽烟</text>
|
||
<text class="mode-desc">继续按支数记录,观察自己的频率和变化趋势。</text>
|
||
</view>
|
||
<text class="mode-arrow">›</text>
|
||
</view>
|
||
|
||
<text class="footer-tip">当前选择:{{ currentModeText }}</text>
|
||
</view>
|
||
</view>
|
||
</template>
|
||
|
||
<script setup>
|
||
import { ref, computed, onMounted } from 'vue'
|
||
import { useLogin } from '@/hooks/useLogin'
|
||
import { useUserStore } from '@/stores/user'
|
||
import { useProfileStore } from '@/stores/profile'
|
||
|
||
const userStore = useUserStore()
|
||
const profileStore = useProfileStore()
|
||
const { waitForLogin } = useLogin()
|
||
|
||
const navBarHeight = ref(0)
|
||
const submitting = ref(false)
|
||
|
||
const currentMode = computed(() => userStore.mode)
|
||
const currentModeText = computed(() => {
|
||
if (userStore.mode === 'quit') return '戒烟打卡'
|
||
if (userStore.mode === 'record') return '记录抽烟'
|
||
return '未选择'
|
||
})
|
||
|
||
function setupNavBar() {
|
||
const sys = uni.getSystemInfoSync()
|
||
const statusBarH = sys.statusBarHeight || 0
|
||
try {
|
||
const menuBtn = uni.getMenuButtonBoundingClientRect()
|
||
navBarHeight.value = menuBtn.bottom + (menuBtn.top - statusBarH)
|
||
} catch (e) {
|
||
navBarHeight.value = statusBarH + 44
|
||
}
|
||
}
|
||
|
||
async function selectMode(mode) {
|
||
if (submitting.value) return
|
||
submitting.value = true
|
||
userStore.setMode(mode)
|
||
|
||
try {
|
||
const profileData = await profileStore.saveProfile({ mode })
|
||
const profile = profileData.profile
|
||
const isCompleted = profileData.is_completed ||
|
||
(profile && profile.onboarding_completed_at) ||
|
||
(profile && profile.baseline_cigs_per_day > 0)
|
||
|
||
if (!profileData.exists || !isCompleted) {
|
||
uni.redirectTo({ url: '/pages/onboarding/index' })
|
||
return
|
||
}
|
||
|
||
uni.switchTab({ url: '/pages/index/index' })
|
||
} catch (e) {
|
||
console.error('selectMode error:', e)
|
||
uni.switchTab({ url: '/pages/index/index' })
|
||
} finally {
|
||
submitting.value = false
|
||
}
|
||
}
|
||
|
||
onMounted(async () => {
|
||
setupNavBar()
|
||
await waitForLogin()
|
||
})
|
||
</script>
|
||
|
||
<style scoped>
|
||
.page {
|
||
min-height: 100vh;
|
||
background:
|
||
radial-gradient(circle at top left, rgba(16, 185, 129, 0.18), transparent 34%),
|
||
linear-gradient(180deg, #ecfdf5 0%, #f7fee7 42%, #ffffff 100%);
|
||
}
|
||
|
||
.nav-placeholder {
|
||
background: transparent;
|
||
}
|
||
|
||
.content {
|
||
padding: 40rpx 32rpx 56rpx;
|
||
}
|
||
|
||
.hero {
|
||
margin-bottom: 40rpx;
|
||
}
|
||
|
||
.eyebrow {
|
||
display: inline-flex;
|
||
padding: 8rpx 18rpx;
|
||
border-radius: 999rpx;
|
||
background: rgba(16, 185, 129, 0.12);
|
||
color: #047857;
|
||
font-size: 22rpx;
|
||
margin-bottom: 20rpx;
|
||
}
|
||
|
||
.title {
|
||
display: block;
|
||
font-size: 48rpx;
|
||
font-weight: 700;
|
||
color: #111827;
|
||
line-height: 1.28;
|
||
}
|
||
|
||
.subtitle {
|
||
display: block;
|
||
margin-top: 16rpx;
|
||
font-size: 28rpx;
|
||
line-height: 1.6;
|
||
color: #4b5563;
|
||
}
|
||
|
||
.mode-card {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 24rpx;
|
||
padding: 30rpx 28rpx;
|
||
margin-bottom: 24rpx;
|
||
border-radius: 28rpx;
|
||
background: rgba(255, 255, 255, 0.82);
|
||
border: 2rpx solid rgba(255, 255, 255, 0.6);
|
||
box-shadow: 0 16rpx 44rpx rgba(15, 23, 42, 0.08);
|
||
}
|
||
|
||
.mode-card-active {
|
||
border-color: rgba(16, 185, 129, 0.35);
|
||
box-shadow: 0 20rpx 52rpx rgba(16, 185, 129, 0.14);
|
||
}
|
||
|
||
.mode-icon {
|
||
width: 92rpx;
|
||
height: 92rpx;
|
||
border-radius: 24rpx;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
font-size: 42rpx;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.mode-icon-quit {
|
||
background: linear-gradient(135deg, #d1fae5 0%, #86efac 100%);
|
||
}
|
||
|
||
.mode-icon-record {
|
||
background: linear-gradient(135deg, #fee2e2 0%, #fecaca 100%);
|
||
}
|
||
|
||
.mode-main {
|
||
flex: 1;
|
||
}
|
||
|
||
.mode-title {
|
||
display: block;
|
||
font-size: 34rpx;
|
||
font-weight: 700;
|
||
color: #111827;
|
||
}
|
||
|
||
.mode-desc {
|
||
display: block;
|
||
margin-top: 10rpx;
|
||
font-size: 25rpx;
|
||
line-height: 1.5;
|
||
color: #6b7280;
|
||
}
|
||
|
||
.mode-arrow {
|
||
font-size: 42rpx;
|
||
color: #9ca3af;
|
||
}
|
||
|
||
.footer-tip {
|
||
display: block;
|
||
margin-top: 20rpx;
|
||
font-size: 24rpx;
|
||
color: #6b7280;
|
||
text-align: center;
|
||
}
|
||
</style>
|