|
@@ -12,11 +12,24 @@
|
|
|
|
|
|
|
|
<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-header">
|
|
|
<text class="reminder-title">{{ reminder.title }}</text>
|
|
<text class="reminder-title">{{ reminder.title }}</text>
|
|
|
- <text class="reminder-time">{{ reminder.time }}</text>
|
|
|
|
|
|
|
+ <switch :checked="reminder.enabled" @change="toggleReminder(index)" />
|
|
|
|
|
+ </view>
|
|
|
|
|
+ <view class="time-list">
|
|
|
|
|
+ <view class="time-item" v-for="(time, timeIndex) in reminder.times" :key="timeIndex">
|
|
|
|
|
+ <text class="time-text">{{ time }}</text>
|
|
|
|
|
+ <!-- 每日用药提醒不允许删除时间点 -->
|
|
|
|
|
+ <view class="delete-time" v-if="reminder.title !== '每日用药提醒'" @click="deleteTime(index, timeIndex)">
|
|
|
|
|
+ <uni-icons type="closeempty" size="16" color="#ff4757"></uni-icons>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ <!-- 每日用药提醒不显示添加按钮 -->
|
|
|
|
|
+ <view class="add-time-btn" v-if="reminder.title !== '每日用药提醒'" @click="openTimePicker(index)">
|
|
|
|
|
+ <uni-icons type="plusempty" size="20" color="#3742fa"></uni-icons>
|
|
|
|
|
+ <text class="add-time-text">添加时间点</text>
|
|
|
|
|
+ </view>
|
|
|
</view>
|
|
</view>
|
|
|
- <switch :checked="reminder.enabled" @change="toggleReminder(index)" />
|
|
|
|
|
</view>
|
|
</view>
|
|
|
</view>
|
|
</view>
|
|
|
</view>
|
|
</view>
|
|
@@ -38,6 +51,28 @@
|
|
|
</view>
|
|
</view>
|
|
|
</view>
|
|
</view>
|
|
|
</view>
|
|
</view>
|
|
|
|
|
+
|
|
|
|
|
+ <!-- 时间选择器模态框 -->
|
|
|
|
|
+ <view class="modal" v-if="showTimePicker">
|
|
|
|
|
+ <view class="modal-backdrop" @click="closeTimePicker"></view>
|
|
|
|
|
+ <view class="modal-panel time-picker-panel">
|
|
|
|
|
+ <view class="drag-handle"></view>
|
|
|
|
|
+ <view class="modal-header">
|
|
|
|
|
+ <text class="modal-title">设置提醒时间</text>
|
|
|
|
|
+ </view>
|
|
|
|
|
+
|
|
|
|
|
+ <view class="time-picker-container">
|
|
|
|
|
+ <picker mode="selector" :range="timeOptions" @change="onTimeChange">
|
|
|
|
|
+ <view class="time-value">{{ timeOptions[selectedTimeIndex] }}</view>
|
|
|
|
|
+ </picker>
|
|
|
|
|
+ </view>
|
|
|
|
|
+
|
|
|
|
|
+ <view class="modal-footer">
|
|
|
|
|
+ <button class="btn-secondary" @click="closeTimePicker">取消</button>
|
|
|
|
|
+ <button class="btn-primary" @click="confirmTime">确定</button>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ </view>
|
|
|
|
|
|
|
|
</template>
|
|
</template>
|
|
|
|
|
|
|
@@ -46,19 +81,20 @@ import { ref, onMounted, onUnmounted, computed } from 'vue'
|
|
|
import { onShow, onHide } from '@dcloudio/uni-app'
|
|
import { onShow, onHide } from '@dcloudio/uni-app'
|
|
|
|
|
|
|
|
import CustomNav from '@/components/custom-nav.vue'
|
|
import CustomNav from '@/components/custom-nav.vue'
|
|
|
|
|
+import { getMedicationListByPatientId } from '@/api/patientMedication'
|
|
|
|
|
|
|
|
interface Reminder {
|
|
interface Reminder {
|
|
|
title: string
|
|
title: string
|
|
|
- time: string
|
|
|
|
|
enabled: boolean
|
|
enabled: boolean
|
|
|
|
|
+ times: string[]
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
const reminders = ref<Reminder[]>([
|
|
const reminders = ref<Reminder[]>([
|
|
|
- { title: '喝水提醒', time: '08:00', enabled: true },
|
|
|
|
|
- { title: '运动提醒', time: '18:00', enabled: false },
|
|
|
|
|
- { title: '测量血压', time: '07:00', enabled: true },
|
|
|
|
|
- { title: '测量血糖', time: '12:00', enabled: false },
|
|
|
|
|
- { title: '服药提醒', time: '09:00', enabled: true }
|
|
|
|
|
|
|
+ { title: '测量血压数据', enabled: true, times: ['07:00'] },
|
|
|
|
|
+ { title: '测量血糖数据', enabled: false, times: ['12:00'] },
|
|
|
|
|
+ { title: '测量心率数据', enabled: true, times: ['18:00'] },
|
|
|
|
|
+ // 每日用药提醒的时间点将通过API获取,初始值为空数组
|
|
|
|
|
+ { title: '每日用药提醒', enabled: true, times: [] }
|
|
|
])
|
|
])
|
|
|
|
|
|
|
|
// 模板 ID & 其他展示信息
|
|
// 模板 ID & 其他展示信息
|
|
@@ -71,6 +107,36 @@ const notificationsEnabled = ref<boolean>(false)
|
|
|
// 是否显示权限引导
|
|
// 是否显示权限引导
|
|
|
const showPermissionGuide = ref<boolean>(false)
|
|
const showPermissionGuide = ref<boolean>(false)
|
|
|
|
|
|
|
|
|
|
+// 是否显示时间选择器
|
|
|
|
|
+const showTimePicker = ref<boolean>(false)
|
|
|
|
|
+
|
|
|
|
|
+// 当前编辑的提醒索引
|
|
|
|
|
+const editingReminderIndex = ref<number>(-1)
|
|
|
|
|
+
|
|
|
|
|
+// 时间选择器相关
|
|
|
|
|
+const timeOptions = ref<string[]>(['07:00', '08:00', '09:00', '12:00', '13:00', '18:00', '19:00', '20:00', '21:00'])
|
|
|
|
|
+const selectedTimeIndex = ref<number>(0)
|
|
|
|
|
+
|
|
|
|
|
+// 用户信息
|
|
|
|
|
+const user = ref<{ id?: string; nickname?: string; role?: string | number }>({})
|
|
|
|
|
+
|
|
|
|
|
+// 从本地存储加载用户信息
|
|
|
|
|
+const loadUser = () => {
|
|
|
|
|
+ try {
|
|
|
|
|
+ const u = (uni as any).getStorageSync('user_info')
|
|
|
|
|
+ console.log('Loaded user_info from storage:', u)
|
|
|
|
|
+ if (u) {
|
|
|
|
|
+ user.value = u
|
|
|
|
|
+ console.log('User data set:', user.value)
|
|
|
|
|
+ }
|
|
|
|
|
+ } catch (e) {
|
|
|
|
|
+ console.error('Error loading user info:', e)
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// 获取当前用户ID (保持为字符串以避免JavaScript Number精度问题)
|
|
|
|
|
+const currentUserId = computed(() => user.value.id || undefined)
|
|
|
|
|
+
|
|
|
// 记录页面进入来源:'healthIndex' | 'subscribe' | 'unknown'
|
|
// 记录页面进入来源:'healthIndex' | 'subscribe' | 'unknown'
|
|
|
const entrySource = ref<'healthIndex' | 'subscribe' | 'unknown'>('unknown')
|
|
const entrySource = ref<'healthIndex' | 'subscribe' | 'unknown'>('unknown')
|
|
|
const entrySourceText = computed(() => {
|
|
const entrySourceText = computed(() => {
|
|
@@ -85,6 +151,7 @@ const entrySourceText = computed(() => {
|
|
|
})
|
|
})
|
|
|
|
|
|
|
|
onMounted(() => {
|
|
onMounted(() => {
|
|
|
|
|
+ loadUser()
|
|
|
try {
|
|
try {
|
|
|
const val = (uni as any).getStorageSync('notificationsEnabled')
|
|
const val = (uni as any).getStorageSync('notificationsEnabled')
|
|
|
console.log('已获取全局消息开关状态:', val)
|
|
console.log('已获取全局消息开关状态:', val)
|
|
@@ -93,6 +160,28 @@ onMounted(() => {
|
|
|
// 忽略错误
|
|
// 忽略错误
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ // 加载提醒设置(除了每日用药提醒)
|
|
|
|
|
+ try {
|
|
|
|
|
+ const savedReminders = (uni as any).getStorageSync('reminders')
|
|
|
|
|
+ if (savedReminders && Array.isArray(savedReminders)) {
|
|
|
|
|
+ // 只更新非每日用药提醒的设置
|
|
|
|
|
+ reminders.value = reminders.value.map(reminder => {
|
|
|
|
|
+ if (reminder.title === '每日用药提醒') {
|
|
|
|
|
+ // 保留每日用药提醒项,使用空数组作为初始时间点
|
|
|
|
|
+ return { ...reminder, times: [] };
|
|
|
|
|
+ }
|
|
|
|
|
+ // 查找本地存储中对应的提醒设置
|
|
|
|
|
+ const savedReminder = savedReminders.find((r: Reminder) => r.title === reminder.title);
|
|
|
|
|
+ return savedReminder ? savedReminder : reminder;
|
|
|
|
|
+ });
|
|
|
|
|
+ }
|
|
|
|
|
+ } catch (e) {
|
|
|
|
|
+ // 忽略错误
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 加载用药时间点
|
|
|
|
|
+ loadMedicationTimes()
|
|
|
|
|
+
|
|
|
// 检查用户订阅状态
|
|
// 检查用户订阅状态
|
|
|
// checkSubscriptionStatus()
|
|
// checkSubscriptionStatus()
|
|
|
|
|
|
|
@@ -171,6 +260,7 @@ onMounted(() => {
|
|
|
// 监听页面显示/隐藏(用于检测用户将小程序/APP切到后台或再次回到前台)
|
|
// 监听页面显示/隐藏(用于检测用户将小程序/APP切到后台或再次回到前台)
|
|
|
onShow(() => {
|
|
onShow(() => {
|
|
|
console.log('[reminder] 页面/应用返回前台(onShow)', { entrySource: entrySource.value })
|
|
console.log('[reminder] 页面/应用返回前台(onShow)', { entrySource: entrySource.value })
|
|
|
|
|
+ loadMedicationTimes() // 加载用药时间点
|
|
|
// 在页面返回前台时,检查订阅设置;如果用户关闭了通知订阅主开关或对本模板拒绝,则主动关闭本地消息开关
|
|
// 在页面返回前台时,检查订阅设置;如果用户关闭了通知订阅主开关或对本模板拒绝,则主动关闭本地消息开关
|
|
|
try {
|
|
try {
|
|
|
if (typeof (uni as any).getSetting === 'function') {
|
|
if (typeof (uni as any).getSetting === 'function') {
|
|
@@ -267,8 +357,40 @@ onUnmounted(() => {
|
|
|
})
|
|
})
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
|
- * 检查用户订阅状态
|
|
|
|
|
|
|
+ * 保存提醒设置到本地存储(不包括每日用药提醒)
|
|
|
|
|
+ */
|
|
|
|
|
+const saveReminders = () => {
|
|
|
|
|
+ try {
|
|
|
|
|
+ // 过滤掉每日用药提醒,不保存到本地存储
|
|
|
|
|
+ const remindersToSave = reminders.value.filter(reminder => reminder.title !== '每日用药提醒');
|
|
|
|
|
+ (uni as any).setStorageSync('reminders', remindersToSave);
|
|
|
|
|
+ } catch (e) {
|
|
|
|
|
+ console.error('保存提醒设置失败:', e)
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/**
|
|
|
|
|
+ * 加载用药时间点
|
|
|
*/
|
|
*/
|
|
|
|
|
+const loadMedicationTimes = async () => {
|
|
|
|
|
+ if (!currentUserId.value) return
|
|
|
|
|
+ try {
|
|
|
|
|
+ const res = await getMedicationListByPatientId(currentUserId.value)
|
|
|
|
|
+ if (res && res.data && res.data.code === 200 && Array.isArray(res.data.data)) {
|
|
|
|
|
+ const allTimes = res.data.data.flatMap((med: any) => med.times || []).filter((t: any) => typeof t === 'string') as string[]
|
|
|
|
|
+ const uniqueTimes = [...new Set(allTimes)].sort()
|
|
|
|
|
+ // 找到每日用药提醒的索引(假设是第四个)
|
|
|
|
|
+ const medicationReminderIndex = reminders.value.findIndex(r => r.title === '每日用药提醒')
|
|
|
|
|
+ if (medicationReminderIndex >= 0) {
|
|
|
|
|
+ reminders.value[medicationReminderIndex].times = uniqueTimes
|
|
|
|
|
+ // 不再保存到本地存储,每次都从API获取最新数据
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ } catch (e) {
|
|
|
|
|
+ console.error('加载用药时间点失败:', e)
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
const checkSubscriptionStatus = () => {
|
|
const checkSubscriptionStatus = () => {
|
|
|
// 使用 uni.getSetting 检查用户授权状态
|
|
// 使用 uni.getSetting 检查用户授权状态
|
|
|
if (typeof (uni as any).getSetting === 'function') {
|
|
if (typeof (uni as any).getSetting === 'function') {
|
|
@@ -431,6 +553,61 @@ const onNotificationChange = (e: any) => {
|
|
|
|
|
|
|
|
const toggleReminder = (index: number) => {
|
|
const toggleReminder = (index: number) => {
|
|
|
reminders.value[index].enabled = !reminders.value[index].enabled
|
|
reminders.value[index].enabled = !reminders.value[index].enabled
|
|
|
|
|
+ // 每日用药提醒不保存到本地存储
|
|
|
|
|
+ if (reminders.value[index].title !== '每日用药提醒') {
|
|
|
|
|
+ saveReminders()
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/**
|
|
|
|
|
+ * 删除时间点
|
|
|
|
|
+ */
|
|
|
|
|
+const deleteTime = (reminderIndex: number, timeIndex: number) => {
|
|
|
|
|
+ // 每日用药提醒不允许删除时间点
|
|
|
|
|
+ if (reminders.value[reminderIndex].title === '每日用药提醒') {
|
|
|
|
|
+ return
|
|
|
|
|
+ }
|
|
|
|
|
+ reminders.value[reminderIndex].times.splice(timeIndex, 1)
|
|
|
|
|
+ saveReminders()
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/**
|
|
|
|
|
+ * 打开时间选择器
|
|
|
|
|
+ */
|
|
|
|
|
+const openTimePicker = (index: number) => {
|
|
|
|
|
+ editingReminderIndex.value = index
|
|
|
|
|
+ selectedTimeIndex.value = 0
|
|
|
|
|
+ showTimePicker.value = true
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/**
|
|
|
|
|
+ * 关闭时间选择器
|
|
|
|
|
+ */
|
|
|
|
|
+const closeTimePicker = () => {
|
|
|
|
|
+ showTimePicker.value = false
|
|
|
|
|
+ editingReminderIndex.value = -1
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/**
|
|
|
|
|
+ * 时间选择器变更
|
|
|
|
|
+ */
|
|
|
|
|
+const onTimeChange = (e: any) => {
|
|
|
|
|
+ selectedTimeIndex.value = e.detail.value
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/**
|
|
|
|
|
+ * 确认时间选择
|
|
|
|
|
+ */
|
|
|
|
|
+const confirmTime = () => {
|
|
|
|
|
+ if (editingReminderIndex.value >= 0) {
|
|
|
|
|
+ const time = timeOptions.value[selectedTimeIndex.value]
|
|
|
|
|
+ const times = reminders.value[editingReminderIndex.value].times
|
|
|
|
|
+ if (!times.includes(time)) {
|
|
|
|
|
+ times.push(time)
|
|
|
|
|
+ saveReminders()
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ closeTimePicker()
|
|
|
}
|
|
}
|
|
|
</script>
|
|
</script>
|
|
|
|
|
|
|
@@ -450,9 +627,6 @@ const toggleReminder = (index: number) => {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
.reminder-item {
|
|
.reminder-item {
|
|
|
- display: flex;
|
|
|
|
|
- justify-content: space-between;
|
|
|
|
|
- align-items: center;
|
|
|
|
|
padding: 30rpx 40rpx;
|
|
padding: 30rpx 40rpx;
|
|
|
border-bottom: 1rpx solid #eee;
|
|
border-bottom: 1rpx solid #eee;
|
|
|
}
|
|
}
|
|
@@ -461,20 +635,64 @@ const toggleReminder = (index: number) => {
|
|
|
border-bottom: none;
|
|
border-bottom: none;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-.reminder-info {
|
|
|
|
|
- flex: 1;
|
|
|
|
|
|
|
+.reminder-header {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ justify-content: space-between;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ margin-bottom: 20rpx;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
.reminder-title {
|
|
.reminder-title {
|
|
|
font-size: 32rpx;
|
|
font-size: 32rpx;
|
|
|
color: #000000;
|
|
color: #000000;
|
|
|
- display: block;
|
|
|
|
|
- margin-bottom: 10rpx;
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-.reminder-time {
|
|
|
|
|
|
|
+.time-list {
|
|
|
|
|
+ width: 100%;
|
|
|
|
|
+ background: #fff;
|
|
|
|
|
+ border-radius: 14rpx;
|
|
|
|
|
+ border: 1rpx solid #eee;
|
|
|
|
|
+ padding: 16rpx;
|
|
|
|
|
+ margin-bottom: 20rpx;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.time-item {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ justify-content: space-between;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ padding: 12rpx 16rpx;
|
|
|
|
|
+ background-color: #f0f5ff;
|
|
|
|
|
+ border-radius: 10rpx;
|
|
|
|
|
+ margin-bottom: 12rpx;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.time-item:last-child {
|
|
|
|
|
+ margin-bottom: 0;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.time-text {
|
|
|
|
|
+ font-size: 28rpx;
|
|
|
|
|
+ color: #333;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.delete-time {
|
|
|
|
|
+ padding: 8rpx;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.add-time-btn {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ justify-content: center;
|
|
|
|
|
+ padding: 20rpx;
|
|
|
|
|
+ border: 1rpx dashed #3742fa;
|
|
|
|
|
+ border-radius: 10rpx;
|
|
|
|
|
+ margin-top: 12rpx;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.add-time-text {
|
|
|
|
|
+ color: #3742fa;
|
|
|
font-size: 28rpx;
|
|
font-size: 28rpx;
|
|
|
- color: #5a5a5a;
|
|
|
|
|
|
|
+ margin-left: 10rpx;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
.notification-toggle {
|
|
.notification-toggle {
|
|
@@ -587,4 +805,50 @@ const toggleReminder = (index: number) => {
|
|
|
.modal-button:after {
|
|
.modal-button:after {
|
|
|
border: none;
|
|
border: none;
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
|
|
+/* 时间选择器样式 */
|
|
|
|
|
+.time-setting {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ margin-top: 8rpx;
|
|
|
|
|
+ cursor: pointer;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.time-setting:active {
|
|
|
|
|
+ opacity: 0.7;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.time-picker-panel {
|
|
|
|
|
+ height: 400rpx;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.time-picker-container {
|
|
|
|
|
+ padding: 40rpx 24rpx;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.time-value {
|
|
|
|
|
+ font-size: 48rpx;
|
|
|
|
|
+ color: #333;
|
|
|
|
|
+ padding: 10rpx 20rpx;
|
|
|
|
|
+ background-color: #f5f5f5;
|
|
|
|
|
+ border-radius: 10rpx;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.btn-secondary {
|
|
|
|
|
+ background-color: #f5f5f5;
|
|
|
|
|
+ color: #666;
|
|
|
|
|
+ border: none;
|
|
|
|
|
+ padding: 20rpx 0;
|
|
|
|
|
+ font-size: 28rpx;
|
|
|
|
|
+ border-radius: 8rpx;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.btn-primary {
|
|
|
|
|
+ background-color: #07c160;
|
|
|
|
|
+ color: #fff;
|
|
|
|
|
+ border: none;
|
|
|
|
|
+ padding: 20rpx 0;
|
|
|
|
|
+ font-size: 28rpx;
|
|
|
|
|
+ border-radius: 8rpx;
|
|
|
|
|
+}
|
|
|
</style>
|
|
</style>
|