314 lines
6.9 KiB
Vue
314 lines
6.9 KiB
Vue
<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>
|