feat: 添加模式选择功能与页面更新
- 在 onboarding 页面中新增使用模式选择功能,用户可选择“戒烟打卡”或“记录抽烟”模式 - 更新个人资料页面以显示当前模式并允许用户切换模式 - 在 pages.json 中注册新的模式选择页面 - 优化首页和其他相关页面以适应新模式功能
This commit is contained in:
@@ -0,0 +1,219 @@
|
||||
<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>
|
||||
Reference in New Issue
Block a user