feat: 添加模式选择功能与页面更新

- 在 onboarding 页面中新增使用模式选择功能,用户可选择“戒烟打卡”或“记录抽烟”模式
- 更新个人资料页面以显示当前模式并允许用户切换模式
- 在 pages.json 中注册新的模式选择页面
- 优化首页和其他相关页面以适应新模式功能
This commit is contained in:
你çšnepiedg
2026-03-18 00:06:01 +08:00
parent d101515d8d
commit 31e504a997
10 changed files with 1818 additions and 465 deletions
+115 -24
View File
@@ -6,25 +6,30 @@
</view>
<view class="section">
<view class="mode-card">
<view class="mode-card-header">
<view class="menu-icon menu-icon-green">🧭</view>
<view class="menu-content">
<text class="menu-label">打卡模式</text>
<text class="menu-desc">直接切换成戒烟打卡记录抽烟</text>
</view>
</view>
<view class="mode-switch">
<view
v-for="item in modeOptions"
:key="item.value"
class="mode-switch-item"
:class="{ 'mode-switch-item-active': userStore.mode === item.value }"
@tap="changeMode(item.value)"
>
<text class="mode-switch-title">{{ item.label }}</text>
<text class="mode-switch-desc">{{ item.desc }}</text>
</view>
</view>
<text class="mode-hint">当前{{ modeText }}</text>
</view>
<view class="menu-list">
<view class="menu-item" @tap="goAISuggest">
<view class="menu-icon menu-icon-green">🤖</view>
<view class="menu-content">
<text class="menu-label">AI 建议</text>
<text class="menu-desc">查看今日 AI 控烟节奏与建议节点</text>
</view>
<text class="menu-arrow"></text>
</view>
<view class="menu-item" @tap="goAISummary">
<view class="menu-icon menu-icon-green">📝</view>
<view class="menu-content">
<text class="menu-label">AI 总结</text>
<text class="menu-desc">按日期生成抽烟总结和明日建议</text>
</view>
<text class="menu-arrow"></text>
</view>
<view class="menu-item">
<view class="menu-icon menu-icon-green">🔗</view>
<view class="menu-content">
@@ -79,18 +84,30 @@
import { computed, ref } from 'vue'
import { onShareAppMessage, onShow } from '@dcloudio/uni-app'
import * as api from '@/api'
import { useProfileStore } from '@/stores/profile'
import { useUserStore } from '@/stores/user'
import { useLogin } from '@/hooks/useLogin'
const profileStore = useProfileStore()
const userStore = useUserStore()
const { waitForLogin } = useLogin()
const shareToken = ref('')
const shareExpireAt = ref('')
const shareLoading = ref(false)
const modeSaving = ref(false)
const modeOptions = [
{ value: 'quit', label: '戒烟打卡', desc: '按天记录今天没抽' },
{ value: 'record', label: '记录抽烟', desc: '按支数记录变化' }
]
const userName = computed(() => userStore.user?.nickname || '戒烟用户')
const userAvatar = computed(() => userStore.user?.avatar_url || 'https://linghu-wmr.oss-cn-beijing.aliyuncs.com/smt/avatar.png')
const modeText = computed(() => {
if (userStore.mode === 'quit') return '戒烟打卡'
if (userStore.mode === 'record') return '记录抽烟'
return '未选择'
})
const shareDesc = computed(() => {
if (!shareToken.value) {
@@ -152,12 +169,23 @@ function previewSharePage() {
})
}
function goAISuggest() {
uni.navigateTo({ url: '/pages/ai/index' })
}
function goAISummary() {
uni.navigateTo({ url: '/pages/ai_summary/index' })
async function changeMode(nextMode) {
if (!nextMode || nextMode === userStore.mode || modeSaving.value) return
modeSaving.value = true
try {
uni.showLoading({ title: '切换中...' })
await profileStore.saveProfile({ mode: nextMode })
uni.hideLoading()
uni.showToast({ title: '模式已切换', icon: 'success' })
setTimeout(() => {
uni.switchTab({ url: '/pages/index/index' })
}, 250)
} catch (e) {
uni.hideLoading()
uni.showToast({ title: '切换失败', icon: 'none' })
} finally {
modeSaving.value = false
}
}
function goOnboarding() {
@@ -199,6 +227,7 @@ onShareAppMessage(() => {
onShow(async () => {
await waitForLogin()
await profileStore.fetchProfile()
await prepareShareToken(false)
})
</script>
@@ -238,6 +267,22 @@ onShow(async () => {
margin-bottom: 24rpx;
}
.mode-card {
background-color: #FFFFFF;
border-radius: 24rpx;
padding: 28rpx 24rpx;
border: 2rpx solid #ECFDF3;
box-shadow: 0 8rpx 20rpx rgba(16, 185, 129, 0.08);
margin-bottom: 16rpx;
}
.mode-card-header {
display: flex;
align-items: center;
gap: 24rpx;
margin-bottom: 20rpx;
}
.menu-list {
display: flex;
flex-direction: column;
@@ -313,6 +358,52 @@ onShow(async () => {
color: #9CA3AF;
}
.menu-value {
font-size: 24rpx;
font-weight: 600;
color: #10B981;
}
.mode-switch {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 16rpx;
}
.mode-switch-item {
padding: 22rpx 20rpx;
border-radius: 18rpx;
background: #F9FAFB;
border: 2rpx solid #E5E7EB;
}
.mode-switch-item-active {
background: #ECFDF5;
border-color: #10B981;
}
.mode-switch-title {
display: block;
font-size: 28rpx;
font-weight: 700;
color: #111827;
}
.mode-switch-desc {
display: block;
margin-top: 8rpx;
font-size: 22rpx;
line-height: 1.5;
color: #6B7280;
}
.mode-hint {
display: block;
margin-top: 16rpx;
font-size: 22rpx;
color: #10B981;
}
.share-btn {
margin: 0;
padding: 10rpx 20rpx;