Files
smt/pages/mode-select/index.vue
T
你çšnepiedg 31e504a997 feat: 添加模式选择功能与页面更新
- 在 onboarding 页面中新增使用模式选择功能,用户可选择“戒烟打卡”或“记录抽烟”模式
- 更新个人资料页面以显示当前模式并允许用户切换模式
- 在 pages.json 中注册新的模式选择页面
- 优化首页和其他相关页面以适应新模式功能
2026-03-18 00:06:01 +08:00

220 lines
4.8 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<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>