Files
smt/pages/profile/index.vue
T

314 lines
6.9 KiB
Vue
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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="user-section">
<image class="avatar" :src="userAvatar" mode="aspectFill"></image>
<text class="user-name">{{ userName }}</text>
</view>
<view class="section">
<view class="menu-list">
<view class="menu-item">
<view class="menu-icon menu-icon-green">🔗</view>
<view class="menu-content">
<text class="menu-label">分享戒烟记录</text>
<text class="menu-desc">{{ shareDesc }}</text>
</view>
<button class="share-btn" open-type="share" :disabled="shareLoading || !shareToken">
{{ shareLoading ? '生成中' : '分享' }}
</button>
</view>
<view class="menu-item" @tap="prepareShareToken(true)">
<view class="menu-icon menu-icon-gray">🔄</view>
<view class="menu-content">
<text class="menu-label">刷新分享链接</text>
<text class="menu-desc">生成新的有效分享令牌</text>
</view>
<text class="menu-arrow"></text>
</view>
<view class="menu-item" @tap="goOnboarding">
<view class="menu-icon menu-icon-green">📝</view>
<view class="menu-content">
<text class="menu-label">重新填写问卷</text>
<text class="menu-desc">修改吸烟基线与个人信息</text>
</view>
<text class="menu-arrow"></text>
</view>
</view>
</view>
<view class="section">
<view class="menu-list">
<view class="menu-item" @tap="clearCache">
<view class="menu-icon menu-icon-gray">🗑</view>
<view class="menu-content">
<text class="menu-label">清除缓存</text>
</view>
<text class="menu-arrow"></text>
</view>
<view class="menu-item" @tap="copyInfo">
<view class="menu-icon menu-icon-gray">💬</view>
<view class="menu-content">
<text class="menu-label">意见反馈</text>
</view>
<text class="menu-arrow"></text>
</view>
</view>
</view>
<view class="logout-btn" @tap="logout">
<text class="logout-text">退出登录</text>
</view>
<text class="version">版本 1.0.0</text>
</view>
</template>
<script setup>
import { computed, onMounted, ref } from 'vue'
import { onShareAppMessage } from '@dcloudio/uni-app'
import { createShare } from '@/api'
import { useUserStore } from '@/stores/user'
import { useLogin } from '@/hooks/useLogin'
const userStore = useUserStore()
const { waitForLogin } = useLogin()
const shareToken = ref('')
const shareExpireAt = ref('')
const shareLoading = ref(false)
const userName = computed(() => userStore.user?.nickname || '戒烟用户')
const userAvatar = computed(() => userStore.user?.avatar_url || '/static/images/default-avatar.png')
const shareDesc = computed(() => {
if (!shareToken.value) {
return shareLoading.value ? '正在生成分享信息...' : '先生成分享令牌后即可分享给朋友'
}
return `有效期至 ${formatExpire(shareExpireAt.value)},仅查看权限`
})
const sharePath = computed(() => {
if (!shareToken.value) {
return '/pages/index/index'
}
return `/pages/share/index?share_token=${shareToken.value}`
})
function formatExpire(value) {
if (!value) return '--'
const d = new Date(value)
if (Number.isNaN(d.getTime())) return value
const y = d.getFullYear()
const m = String(d.getMonth() + 1).padStart(2, '0')
const day = String(d.getDate()).padStart(2, '0')
const hh = String(d.getHours()).padStart(2, '0')
const mm = String(d.getMinutes()).padStart(2, '0')
return `${y}-${m}-${day} ${hh}:${mm}`
}
async function prepareShareToken(showToast = false) {
if (shareLoading.value) return
shareLoading.value = true
try {
const res = await createShare({ days: 7 })
shareToken.value = res.data?.share_token || ''
shareExpireAt.value = res.data?.expire_at || ''
if (showToast) {
uni.showToast({ title: '分享链接已刷新', icon: 'success' })
}
} catch (e) {
console.error('prepareShareToken error:', e)
if (showToast) {
uni.showToast({ title: '生成分享失败', icon: 'none' })
}
} finally {
shareLoading.value = false
}
}
function goOnboarding() {
uni.navigateTo({ url: '/pages/onboarding/index' })
}
function clearCache() {
uni.showModal({
title: '清除缓存',
content: '将清除本地缓存数据,不会影响云端记录',
success: (res) => {
if (res.confirm) {
try {
uni.clearStorageSync()
uni.showToast({ title: '缓存已清除', icon: 'success' })
} catch (e) {
uni.showToast({ title: '清除失败', icon: 'none' })
}
}
}
})
}
function copyInfo() {
uni.setClipboardData({
data: '806669289@qq.com',
success: () => {
uni.showToast({ title: '反馈邮箱已复制', icon: 'success' })
}
})
}
function logout() {
uni.showModal({
title: '确认退出',
content: '确定要退出登录吗?',
success: (res) => {
if (res.confirm) {
userStore.logout()
uni.reLaunch({ url: '/pages/index/index' })
}
}
})
}
onShareAppMessage(() => {
return {
title: `${userName.value}的戒烟记录(仅查看)`,
path: sharePath.value
}
})
onMounted(async () => {
await waitForLogin()
await prepareShareToken(false)
})
</script>
<style scoped>
.page {
min-height: 100vh;
background: linear-gradient(to bottom, #D1FAE5 0%, #F0FDF4 45%, #FFFFFF 100%);
padding: 32rpx;
padding-bottom: 160rpx;
box-sizing: border-box;
}
.user-section {
display: flex;
flex-direction: column;
align-items: center;
padding: 48rpx 0 40rpx;
}
.avatar {
width: 140rpx;
height: 140rpx;
border-radius: 50%;
border: 4rpx solid #A7F3D0;
background-color: #ECFDF5;
margin-bottom: 20rpx;
}
.user-name {
font-size: 38rpx;
font-weight: 700;
color: #111827;
}
.section { margin-bottom: 24rpx; }
.menu-list {
display: flex;
flex-direction: column;
gap: 16rpx;
}
.menu-item {
display: flex;
align-items: center;
gap: 24rpx;
background-color: #FFFFFF;
border-radius: 24rpx;
padding: 28rpx 24rpx;
border: 2rpx solid #ECFDF3;
box-shadow: 0 8rpx 20rpx rgba(16, 185, 129, 0.08);
}
.menu-icon {
width: 64rpx;
height: 64rpx;
border-radius: 16rpx;
display: flex;
align-items: center;
justify-content: center;
font-size: 32rpx;
}
.menu-icon-green { background-color: #DCFCE7; }
.menu-icon-gray { background-color: #F3F4F6; }
.menu-content {
flex: 1;
display: flex;
flex-direction: column;
gap: 4rpx;
}
.menu-label {
font-size: 30rpx;
color: #111827;
}
.menu-desc {
font-size: 24rpx;
color: #6B7280;
}
.menu-arrow {
font-size: 36rpx;
color: #9CA3AF;
}
.share-btn {
margin: 0;
padding: 10rpx 20rpx;
line-height: 1.4;
font-size: 24rpx;
border: none;
border-radius: 999rpx;
color: #ffffff;
background: #10b981;
}
.share-btn[disabled] {
background: #9ca3af;
color: #ffffff;
}
.share-btn::after {
border: none;
}
.logout-btn {
text-align: center;
padding: 28rpx;
margin-top: 40rpx;
background-color: #FFFFFF;
border-radius: 24rpx;
border: 2rpx solid #FEE2E2;
}
.logout-text {
color: #EF4444;
font-size: 30rpx;
}
.version {
display: block;
text-align: center;
font-size: 22rpx;
color: #9CA3AF;
margin-top: 32rpx;
}
</style>