feat: add read-only smoke share page and profile share entry

This commit is contained in:
root
2026-03-10 18:53:10 +08:00
parent 50109b3a96
commit db3218160b
4 changed files with 694 additions and 1 deletions
+101 -1
View File
@@ -7,6 +7,26 @@
<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">
@@ -46,16 +66,68 @@
</template>
<script setup>
import { computed, onMounted } from 'vue'
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' })
}
@@ -99,8 +171,16 @@ function logout() {
})
}
onShareAppMessage(() => {
return {
title: `${userName.value}的戒烟记录(仅查看)`,
path: sharePath.value
}
})
onMounted(async () => {
await waitForLogin()
await prepareShareToken(false)
})
</script>
@@ -189,6 +269,26 @@ onMounted(async () => {
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;