feat: 支持多页面分享与统一默认头像
Made-with: Cursor
This commit is contained in:
+2
-2
@@ -1,10 +1,10 @@
|
||||
const ENV = {
|
||||
development: {
|
||||
BASE_URL: 'http://192.168.31.46:8080/api/v1',
|
||||
BASE_URL: 'https://wx.nepiedg.top/api/v1',
|
||||
MINI_PROGRAM_ID: 2
|
||||
},
|
||||
production: {
|
||||
BASE_URL: 'https://api.example.com/api/v1',
|
||||
BASE_URL: 'https://wx.nepiedg.top/api/v1',
|
||||
MINI_PROGRAM_ID: 2
|
||||
}
|
||||
}
|
||||
|
||||
@@ -98,6 +98,7 @@
|
||||
|
||||
<script setup>
|
||||
import { ref, computed, onMounted } from 'vue'
|
||||
import { onShareAppMessage } from '@dcloudio/uni-app'
|
||||
import { useLogin } from '@/hooks/useLogin'
|
||||
import { useProfileStore } from '@/stores/profile'
|
||||
import { storage } from '@/utils/storage'
|
||||
@@ -410,6 +411,13 @@ async function initPage() {
|
||||
onMounted(() => {
|
||||
initPage()
|
||||
})
|
||||
|
||||
onShareAppMessage(() => {
|
||||
return {
|
||||
title: '戒烟助手 - AI 戒烟教练陪你',
|
||||
path: 'pages/index/index'
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
@@ -97,6 +97,7 @@
|
||||
|
||||
<script setup>
|
||||
import { ref, computed, onMounted, onUnmounted } from 'vue'
|
||||
import { onShareAppMessage } from '@dcloudio/uni-app'
|
||||
import { useProfileStore } from '@/stores/profile'
|
||||
import { useUserStore } from '@/stores/user'
|
||||
import { useLogin } from '@/hooks/useLogin'
|
||||
@@ -133,7 +134,7 @@ const userName = computed(() => {
|
||||
})
|
||||
|
||||
const userAvatar = computed(() => {
|
||||
return homeData.value?.greeting?.avatar_url || userStore.user?.avatar_url || '/static/images/default-avatar.png'
|
||||
return homeData.value?.greeting?.avatar_url || userStore.user?.avatar_url || 'https://linghu-wmr.oss-cn-beijing.aliyuncs.com/smt/avatar.png'
|
||||
})
|
||||
|
||||
const greetingTitle = computed(() => {
|
||||
@@ -352,6 +353,13 @@ onMounted(() => {
|
||||
onUnmounted(() => {
|
||||
stopTimer()
|
||||
})
|
||||
|
||||
onShareAppMessage(() => {
|
||||
return {
|
||||
title: '戒烟助手 - 记录与分析我的戒烟之路',
|
||||
path: 'pages/index/index'
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
@@ -123,6 +123,7 @@
|
||||
|
||||
<script setup>
|
||||
import { ref, computed, onMounted, watch } from 'vue'
|
||||
import { onShareAppMessage } from '@dcloudio/uni-app'
|
||||
import { useLogsStore } from '@/stores/logs'
|
||||
import { useLogin } from '@/hooks/useLogin'
|
||||
|
||||
@@ -284,6 +285,13 @@ function levelLabel(level) {
|
||||
watch(currentTab, async (value) => {
|
||||
await logsStore.fetchLogs(true, value)
|
||||
})
|
||||
|
||||
onShareAppMessage(() => {
|
||||
return {
|
||||
title: '戒烟助手 - 我的戒烟记录',
|
||||
path: 'pages/index/index'
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
@@ -104,6 +104,7 @@
|
||||
|
||||
<script setup>
|
||||
import { ref, computed, onMounted } from 'vue'
|
||||
import { onShareAppMessage } from '@dcloudio/uni-app'
|
||||
import { useProfileStore } from '@/stores/profile'
|
||||
import { useLogin } from '@/hooks/useLogin'
|
||||
|
||||
@@ -208,6 +209,13 @@ onMounted(async () => {
|
||||
}
|
||||
await waitForLogin()
|
||||
})
|
||||
|
||||
onShareAppMessage(() => {
|
||||
return {
|
||||
title: '戒烟助手 - 帮你定制戒烟计划',
|
||||
path: 'pages/index/index'
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
+28
-19
@@ -12,30 +12,17 @@
|
||||
<view class="menu-content">
|
||||
<text class="menu-label">分享戒烟记录</text>
|
||||
<text class="menu-desc">{{ shareDesc }}</text>
|
||||
<view class="menu-actions">
|
||||
<text class="menu-action" @tap.stop="previewSharePage">预览分享页</text>
|
||||
<text class="menu-action-sep">·</text>
|
||||
<text class="menu-action" @tap.stop="handleRefreshShare">刷新分享链接</text>
|
||||
</view>
|
||||
</view>
|
||||
<button class="share-btn" open-type="share" :disabled="shareLoading || !shareToken">
|
||||
{{ shareLoading ? '生成中' : '分享' }}
|
||||
</button>
|
||||
</view>
|
||||
|
||||
<view class="menu-item" @tap="previewSharePage">
|
||||
<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 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">
|
||||
@@ -89,7 +76,7 @@ const shareExpireAt = ref('')
|
||||
const shareLoading = ref(false)
|
||||
|
||||
const userName = computed(() => userStore.user?.nickname || '戒烟用户')
|
||||
const userAvatar = computed(() => userStore.user?.avatar_url || '/static/icons/profile.png')
|
||||
const userAvatar = computed(() => userStore.user?.avatar_url || 'https://linghu-wmr.oss-cn-beijing.aliyuncs.com/smt/avatar.png')
|
||||
|
||||
const shareDesc = computed(() => {
|
||||
if (!shareToken.value) {
|
||||
@@ -137,6 +124,10 @@ async function prepareShareToken(showToast = false) {
|
||||
}
|
||||
}
|
||||
|
||||
function handleRefreshShare() {
|
||||
prepareShareToken(true)
|
||||
}
|
||||
|
||||
function previewSharePage() {
|
||||
if (!shareToken.value) {
|
||||
uni.showToast({ title: '分享令牌尚未生成', icon: 'none' })
|
||||
@@ -283,6 +274,24 @@ onMounted(async () => {
|
||||
color: #6B7280;
|
||||
}
|
||||
|
||||
.menu-actions {
|
||||
margin-top: 6rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
gap: 8rpx;
|
||||
font-size: 24rpx;
|
||||
color: #10B981;
|
||||
}
|
||||
|
||||
.menu-action {
|
||||
color: #10B981;
|
||||
}
|
||||
|
||||
.menu-action-sep {
|
||||
color: #9CA3AF;
|
||||
}
|
||||
|
||||
.menu-arrow {
|
||||
font-size: 36rpx;
|
||||
color: #9CA3AF;
|
||||
|
||||
+11
-2
@@ -131,10 +131,10 @@
|
||||
|
||||
<script setup>
|
||||
import { computed, ref } from 'vue'
|
||||
import { onLoad } from '@dcloudio/uni-app'
|
||||
import { onLoad, onShareAppMessage } from '@dcloudio/uni-app'
|
||||
import { getShareData } from '@/api'
|
||||
|
||||
const defaultAvatar = '/static/icons/profile.png'
|
||||
const defaultAvatar = 'https://linghu-wmr.oss-cn-beijing.aliyuncs.com/smt/avatar.png'
|
||||
|
||||
const loading = ref(true)
|
||||
const loadingMore = ref(false)
|
||||
@@ -307,6 +307,15 @@ onLoad(async (options) => {
|
||||
shareToken.value = String(options?.share_token || '').trim()
|
||||
await fetchShare(true)
|
||||
})
|
||||
|
||||
onShareAppMessage(() => {
|
||||
return {
|
||||
title: '戒烟助手 - 查看我的戒烟记录',
|
||||
path: shareToken.value
|
||||
? `pages/share/index?share_token=${shareToken.value}`
|
||||
: 'pages/index/index'
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
@@ -181,6 +181,7 @@
|
||||
|
||||
<script setup>
|
||||
import { ref, computed, onMounted, watch } from 'vue'
|
||||
import { onShareAppMessage } from '@dcloudio/uni-app'
|
||||
import { useLogin } from '@/hooks/useLogin'
|
||||
import * as api from '@/api'
|
||||
|
||||
@@ -496,6 +497,13 @@ onMounted(() => {
|
||||
statusBarHeight.value = Math.max((sys.statusBarHeight || 0) - 20, 0)
|
||||
fetchStats()
|
||||
})
|
||||
|
||||
onShareAppMessage(() => {
|
||||
return {
|
||||
title: '戒烟助手 - 我的戒烟数据分析',
|
||||
path: 'pages/index/index'
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
+46
-44
@@ -43,7 +43,7 @@ export const useLogsStore = defineStore('logs', {
|
||||
return []
|
||||
}
|
||||
|
||||
// 获取时间戳的辅助函数
|
||||
// 获取时间戳的辅助函数(统一处理 smoke_at / smoke_time / createtime)
|
||||
const getTime = (log) => {
|
||||
if (log.smoke_at) {
|
||||
return new Date(log.smoke_at).getTime()
|
||||
@@ -52,60 +52,62 @@ export const useLogsStore = defineStore('logs', {
|
||||
return new Date(log.smoke_time).getTime()
|
||||
}
|
||||
if (log.createtime) {
|
||||
return typeof log.createtime === 'number' ? log.createtime * 1000 : new Date(log.createtime).getTime()
|
||||
return typeof log.createtime === 'number'
|
||||
? log.createtime * 1000
|
||||
: new Date(log.createtime).getTime()
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// 先按时间倒序排序
|
||||
// 先按时间正序(最早在前)计算「距上次抽烟」的时间间隔,
|
||||
// 再按时间倒序用于页面展示,保证间隔只和上一次「抽烟」记录有关
|
||||
const logsAsc = [...state.logs].sort((a, b) => {
|
||||
const timeA = getTime(a)
|
||||
const timeB = getTime(b)
|
||||
return timeA - timeB
|
||||
})
|
||||
|
||||
const intervalById = new Map()
|
||||
let lastSmokeTime = null
|
||||
|
||||
logsAsc.forEach((log) => {
|
||||
const type = normalizeLogType(log)
|
||||
const currentTime = getTime(log)
|
||||
let interval = ''
|
||||
|
||||
// 已存在「上次抽烟」时间,计算与其的间隔
|
||||
if (lastSmokeTime !== null && currentTime > lastSmokeTime) {
|
||||
const diff = currentTime - lastSmokeTime
|
||||
const hours = Math.floor(diff / (1000 * 60 * 60))
|
||||
const minutes = Math.floor((diff % (1000 * 60 * 60)) / (1000 * 60))
|
||||
|
||||
if (hours > 0) {
|
||||
interval = `${hours}小时${minutes}分`
|
||||
} else if (minutes > 0) {
|
||||
interval = `${minutes}分钟`
|
||||
} else {
|
||||
interval = '刚刚'
|
||||
}
|
||||
}
|
||||
|
||||
intervalById.set(log.id, interval)
|
||||
|
||||
// 仅当当前记录是「抽烟」时,更新「上次抽烟时间」
|
||||
if (type === 'smoke' && currentTime > 0) {
|
||||
lastSmokeTime = currentTime
|
||||
}
|
||||
})
|
||||
|
||||
// 再按时间倒序排序用于展示
|
||||
const sortedLogs = [...state.logs].sort((a, b) => {
|
||||
const timeA = getTime(a)
|
||||
const timeB = getTime(b)
|
||||
return timeB - timeA // 倒序:最新的在前
|
||||
})
|
||||
|
||||
return sortedLogs.map((log, index) => {
|
||||
return sortedLogs.map((log) => {
|
||||
const type = normalizeLogType(log)
|
||||
|
||||
// 计算间隔时间
|
||||
let interval = ''
|
||||
const currentTime = getTime(log)
|
||||
|
||||
if (index === 0) {
|
||||
// 第一条记录:显示距离当前时间的间隔
|
||||
const now = Date.now()
|
||||
const diff = now - currentTime
|
||||
|
||||
if (diff > 0) {
|
||||
const hours = Math.floor(diff / (1000 * 60 * 60))
|
||||
const minutes = Math.floor((diff % (1000 * 60 * 60)) / (1000 * 60))
|
||||
|
||||
if (hours > 0) {
|
||||
interval = `${hours}小时${minutes}分`
|
||||
} else if (minutes > 0) {
|
||||
interval = `${minutes}分钟`
|
||||
} else {
|
||||
interval = '刚刚'
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// 后续记录:显示距离上一条记录的间隔
|
||||
const prevTime = getTime(sortedLogs[index - 1])
|
||||
const diff = prevTime - currentTime
|
||||
|
||||
if (diff > 0) {
|
||||
const hours = Math.floor(diff / (1000 * 60 * 60))
|
||||
const minutes = Math.floor((diff % (1000 * 60 * 60)) / (1000 * 60))
|
||||
|
||||
if (hours > 0) {
|
||||
interval = `${hours}小时${minutes}分`
|
||||
} else if (minutes > 0) {
|
||||
interval = `${minutes}分钟`
|
||||
} else {
|
||||
interval = '刚刚'
|
||||
}
|
||||
}
|
||||
}
|
||||
const interval = intervalById.get(log.id) || ''
|
||||
|
||||
// 获取显示日期(用本地日期,避免 UTC 导致差一天)
|
||||
let displayDate = ''
|
||||
|
||||
Reference in New Issue
Block a user