|
@@ -1,6 +1,15 @@
|
|
|
<template>
|
|
<template>
|
|
|
<CustomNav title="健康提醒" leftType="back" />
|
|
<CustomNav title="健康提醒" leftType="back" />
|
|
|
<view class="content">
|
|
<view class="content">
|
|
|
|
|
+ <view class="notification-toggle">
|
|
|
|
|
+ <text class="notification-label">消息通知</text>
|
|
|
|
|
+ <switch :checked="notificationsEnabled" @change="onNotificationChange" />
|
|
|
|
|
+ </view>
|
|
|
|
|
+ <view class="template-info">
|
|
|
|
|
+ <text class="tmpl-title">每日健康上报提醒</text>
|
|
|
|
|
+ <text class="tmpl-meta">模板编号:7536 · 模板ID:ACS7cwcbx0F0Y_YaB4GZr7rWP7BO2-7wQOtYsnUjmFI</text>
|
|
|
|
|
+ </view>
|
|
|
|
|
+
|
|
|
<view class="reminder-list">
|
|
<view class="reminder-list">
|
|
|
<view class="reminder-item" v-for="(reminder, index) in reminders" :key="index">
|
|
<view class="reminder-item" v-for="(reminder, index) in reminders" :key="index">
|
|
|
<view class="reminder-info">
|
|
<view class="reminder-info">
|
|
@@ -15,7 +24,7 @@
|
|
|
</template>
|
|
</template>
|
|
|
|
|
|
|
|
<script setup lang="ts">
|
|
<script setup lang="ts">
|
|
|
-import { ref } from 'vue'
|
|
|
|
|
|
|
+import { ref, onMounted, computed } from 'vue'
|
|
|
|
|
|
|
|
import CustomNav from '@/components/custom-nav.vue'
|
|
import CustomNav from '@/components/custom-nav.vue'
|
|
|
import TabBar from '@/components/tab-bar.vue'
|
|
import TabBar from '@/components/tab-bar.vue'
|
|
@@ -34,6 +43,156 @@ const reminders = ref<Reminder[]>([
|
|
|
{ title: '服药提醒', time: '09:00', enabled: true }
|
|
{ title: '服药提醒', time: '09:00', enabled: true }
|
|
|
])
|
|
])
|
|
|
|
|
|
|
|
|
|
+// 模板 ID & 其他展示信息
|
|
|
|
|
+const TEMPLATE_ID = 'ACS7cwcbx0F0Y_YaB4GZr7rWP7BO2-7wQOtYsnUjmFI'
|
|
|
|
|
+const TEMPLATE_NO = '7536'
|
|
|
|
|
+
|
|
|
|
|
+// 全局消息开关
|
|
|
|
|
+const notificationsEnabled = ref<boolean>(false)
|
|
|
|
|
+
|
|
|
|
|
+// 记录页面进入来源:'healthIndex' | 'subscribe' | 'unknown'
|
|
|
|
|
+const entrySource = ref<'healthIndex' | 'subscribe' | 'unknown'>('unknown')
|
|
|
|
|
+const entrySourceText = computed(() => {
|
|
|
|
|
+ switch (entrySource.value) {
|
|
|
|
|
+ case 'healthIndex':
|
|
|
|
|
+ return '来自 健康首页'
|
|
|
|
|
+ case 'subscribe':
|
|
|
|
|
+ return '来自 订阅消息'
|
|
|
|
|
+ default:
|
|
|
|
|
+ return '来源 未知'
|
|
|
|
|
+ }
|
|
|
|
|
+})
|
|
|
|
|
+
|
|
|
|
|
+onMounted(() => {
|
|
|
|
|
+ try {
|
|
|
|
|
+ const val = (uni as any).getStorageSync('notificationsEnabled')
|
|
|
|
|
+ if (typeof val === 'boolean') notificationsEnabled.value = val
|
|
|
|
|
+ } catch (e) {
|
|
|
|
|
+ // ignore
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 尝试判断来源:优先检查页面栈的上一个页面;若无(直接打开),则检查 launch options 的 query
|
|
|
|
|
+ try {
|
|
|
|
|
+ const pages = (getCurrentPages as any)()
|
|
|
|
|
+ console.log('Current pages stack:', pages)
|
|
|
|
|
+
|
|
|
|
|
+ if (pages && pages.length >= 1) {
|
|
|
|
|
+ const currentPage = pages[pages.length - 1]
|
|
|
|
|
+ const currentRoute = currentPage?.route || currentPage?.__route || currentPage?.$page?.route
|
|
|
|
|
+ const currentOptions = currentPage?.options || {}
|
|
|
|
|
+
|
|
|
|
|
+ console.log('Current page route:', currentRoute)
|
|
|
|
|
+ console.log('Current page options:', currentOptions)
|
|
|
|
|
+
|
|
|
|
|
+ // 检查当前页面是否包含 from=subscribe 参数
|
|
|
|
|
+ if (currentOptions.from === 'subscribe') {
|
|
|
|
|
+ entrySource.value = 'subscribe'
|
|
|
|
|
+ console.log('Entry source identified as subscribe via current page options')
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 检查当前页面是否包含 templateId 相关参数
|
|
|
|
|
+ if (currentOptions.templateId === TEMPLATE_ID || currentOptions.template_id === TEMPLATE_ID) {
|
|
|
|
|
+ entrySource.value = 'subscribe'
|
|
|
|
|
+ console.log('Entry source identified as subscribe via templateId in current page options')
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (pages && pages.length >= 2) {
|
|
|
|
|
+ const prev = pages[pages.length - 2]
|
|
|
|
|
+ const prevRoute = prev?.route || prev?.__route || prev?.$page?.route
|
|
|
|
|
+ console.log('Previous page route:', prevRoute)
|
|
|
|
|
+ if (prevRoute && String(prevRoute).includes('pages/health/index')) {
|
|
|
|
|
+ entrySource.value = 'healthIndex'
|
|
|
|
|
+ console.log('Entry source identified as healthIndex')
|
|
|
|
|
+ }
|
|
|
|
|
+ } else {
|
|
|
|
|
+ // 如果没有上一页信息,检查小程序启动参数(例如用户通过订阅消息打开)
|
|
|
|
|
+ if ((uni as any).getLaunchOptionsSync) {
|
|
|
|
|
+ const launch = (uni as any).getLaunchOptionsSync()
|
|
|
|
|
+ console.log('Launch options:', launch)
|
|
|
|
|
+ if (launch && launch.query) {
|
|
|
|
|
+ console.log('Query params:', launch.query)
|
|
|
|
|
+ // 如果你在推送消息里把 from=subscribe 作为参数传入,这里会命中
|
|
|
|
|
+ if (launch.query.from === 'subscribe') {
|
|
|
|
|
+ entrySource.value = 'subscribe'
|
|
|
|
|
+ console.log('Entry source identified as subscribe via from param')
|
|
|
|
|
+ }
|
|
|
|
|
+ // 有些平台会把 templateId 或其它字段放在 query 中,可据此判断
|
|
|
|
|
+ if (launch.query.templateId === TEMPLATE_ID || launch.query.template_id === TEMPLATE_ID) {
|
|
|
|
|
+ entrySource.value = 'subscribe'
|
|
|
|
|
+ console.log('Entry source identified as subscribe via templateId param')
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ } catch (e) {
|
|
|
|
|
+ console.error('Error identifying entry source:', e)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 显示来源提示(用于测试),延迟一点以保证 UI 已就绪
|
|
|
|
|
+ try {
|
|
|
|
|
+ setTimeout(() => {
|
|
|
|
|
+ console.log('Entry source:', entrySource.value, entrySourceText.value)
|
|
|
|
|
+ }, 250)
|
|
|
|
|
+ } catch (e) {
|
|
|
|
|
+ // ignore
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (entrySource.value === 'unknown') {
|
|
|
|
|
+ console.log('Entry source defaulted to unknown')
|
|
|
|
|
+ }
|
|
|
|
|
+})
|
|
|
|
|
+
|
|
|
|
|
+/**
|
|
|
|
|
+ * 顶部总开关变更
|
|
|
|
|
+ * - 打开时:调用 uni.requestSubscribeMessage 请求用户同意订阅 TEMPLATE_ID
|
|
|
|
|
+ * - 如果用户同意(返回 accept),将状态置为 true 并持久化
|
|
|
|
|
+ * - 否则回滚并提示
|
|
|
|
|
+ */
|
|
|
|
|
+const onNotificationChange = (e: any) => {
|
|
|
|
|
+ const newVal = e?.detail?.value
|
|
|
|
|
+ if (newVal) {
|
|
|
|
|
+ // 请求订阅(仅在微信/小程序有效)
|
|
|
|
|
+ ;(uni as any).requestSubscribeMessage({
|
|
|
|
|
+ tmplIds: [TEMPLATE_ID],
|
|
|
|
|
+ success(res: any) {
|
|
|
|
|
+ // res 可能形如 { "ACS7...": 'accept' }
|
|
|
|
|
+ const result = res && res[TEMPLATE_ID]
|
|
|
|
|
+ if (result === 'accept') {
|
|
|
|
|
+ notificationsEnabled.value = true
|
|
|
|
|
+ try {
|
|
|
|
|
+ ;(uni as any).setStorageSync('notificationsEnabled', true)
|
|
|
|
|
+ } catch (err) {
|
|
|
|
|
+ // ignore storage error
|
|
|
|
|
+ }
|
|
|
|
|
+ uni.showToast({ title: '订阅成功', icon: 'success' })
|
|
|
|
|
+ } else {
|
|
|
|
|
+ // 用户拒绝或关闭了弹窗
|
|
|
|
|
+ notificationsEnabled.value = false
|
|
|
|
|
+ try {
|
|
|
|
|
+ ;(uni as any).setStorageSync('notificationsEnabled', false)
|
|
|
|
|
+ } catch (err) {}
|
|
|
|
|
+ uni.showToast({ title: '订阅被拒绝', icon: 'none' })
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
|
|
+ fail(err: any) {
|
|
|
|
|
+ notificationsEnabled.value = false
|
|
|
|
|
+ try {
|
|
|
|
|
+ ;(uni as any).setStorageSync('notificationsEnabled', false)
|
|
|
|
|
+ } catch (e) {}
|
|
|
|
|
+ uni.showToast({ title: '订阅请求失败', icon: 'none' })
|
|
|
|
|
+ }
|
|
|
|
|
+ })
|
|
|
|
|
+ } else {
|
|
|
|
|
+ // 关闭订阅:不需要额外调用接口,只改变本地记录
|
|
|
|
|
+ notificationsEnabled.value = false
|
|
|
|
|
+ try {
|
|
|
|
|
+ ;(uni as any).setStorageSync('notificationsEnabled', false)
|
|
|
|
|
+ } catch (err) {}
|
|
|
|
|
+ uni.showToast({ title: '已关闭通知', icon: 'none' })
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
const toggleReminder = (index: number) => {
|
|
const toggleReminder = (index: number) => {
|
|
|
reminders.value[index].enabled = !reminders.value[index].enabled
|
|
reminders.value[index].enabled = !reminders.value[index].enabled
|
|
|
}
|
|
}
|
|
@@ -81,4 +240,35 @@ const toggleReminder = (index: number) => {
|
|
|
font-size: 28rpx;
|
|
font-size: 28rpx;
|
|
|
color: #5a5a5a;
|
|
color: #5a5a5a;
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
|
|
+.notification-toggle {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ justify-content: space-between;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ padding: 30rpx 40rpx;
|
|
|
|
|
+ background-color: #fff;
|
|
|
|
|
+ border-radius: 12rpx;
|
|
|
|
|
+ margin-top: 20rpx;
|
|
|
|
|
+}
|
|
|
|
|
+.notification-label {
|
|
|
|
|
+ font-size: 32rpx;
|
|
|
|
|
+ color: #000;
|
|
|
|
|
+}
|
|
|
|
|
+.template-info {
|
|
|
|
|
+ margin-top: 12rpx;
|
|
|
|
|
+ padding: 0 10rpx;
|
|
|
|
|
+ color: #666;
|
|
|
|
|
+ font-size: 24rpx;
|
|
|
|
|
+}
|
|
|
|
|
+.tmpl-title {
|
|
|
|
|
+ display: block;
|
|
|
|
|
+ font-size: 26rpx;
|
|
|
|
|
+ color: #333;
|
|
|
|
|
+}
|
|
|
|
|
+.tmpl-meta {
|
|
|
|
|
+ display: block;
|
|
|
|
|
+ font-size: 22rpx;
|
|
|
|
|
+ color: #8a8a8a;
|
|
|
|
|
+ margin-top: 6rpx;
|
|
|
|
|
+}
|
|
|
</style>
|
|
</style>
|