diff --git a/components/ExpiryReminderBanner.vue b/components/ExpiryReminderBanner.vue
deleted file mode 100644
index a3caf72..0000000
--- a/components/ExpiryReminderBanner.vue
+++ /dev/null
@@ -1,31 +0,0 @@
-
-
-
- {{ reminder.level_name || '套餐临期提醒' }}
-
-
- 当前资产套餐剩余 {{ reminder.remaining_days }} 天,请及时续费。
- 预计到期:{{ formatShanghaiExpiry(reminder.expires_at) }}
-
-
-
-
-
-
diff --git a/components/ExpiryReminderPopup.vue b/components/ExpiryReminderPopup.vue
new file mode 100644
index 0000000..bac7cc7
--- /dev/null
+++ b/components/ExpiryReminderPopup.vue
@@ -0,0 +1,142 @@
+
+
+
+
+
+
+ 预计到期时间
+ {{ formatShanghaiExpiry(reminder.expires_at) }}
+
+ 为避免套餐到期影响使用,请及时续费。
+
+
+
+
+
+
+
+
+
diff --git a/pages/index/index.vue b/pages/index/index.vue
index c6a6836..b0badf1 100644
--- a/pages/index/index.vue
+++ b/pages/index/index.vue
@@ -3,8 +3,6 @@
-
@@ -99,6 +97,8 @@
+
{
const entry = shownExpiryReminder.value;
return homeActive.value && entry && isCurrentSession(entry) && entry.day === getShanghaiDay()
@@ -168,15 +172,31 @@
});
const showPendingExpiryReminder = () => {
const entry = assetStore.state.expiryReminder;
- if (!homeActive.value || !entry || entry.shown || !isCurrentSession(entry) || entry.day !== getShanghaiDay()) return;
+ if (!homeActive.value || awaitingHomeReminders.value || popupCandidateShow.value || notificationPopupShow.value ||
+ visibleExpiryReminder.value || !entry || entry.shown || !isCurrentSession(entry) || entry.day !== getShanghaiDay()) return;
shownExpiryReminder.value = { ...entry };
assetStore.markExpiryReminderShown();
};
const closeExpiryReminder = () => {
shownExpiryReminder.value = null;
assetStore.dismissExpiryReminder();
+ advanceHomePopupQueue();
};
- watch(() => assetStore.state.expiryReminder, showPendingExpiryReminder);
+ const advanceHomePopupQueue = () => {
+ if (!homeActive.value || awaitingHomeReminders.value || popupCandidateShow.value ||
+ visibleExpiryReminder.value || notificationPopupShow.value) return;
+ showPendingExpiryReminder();
+ if (visibleExpiryReminder.value) return;
+ if (notificationQueued) {
+ notificationQueued = false;
+ notificationPopupShow.value = true;
+ markNotificationRead(notificationItems.value[0]);
+ } else if (notificationFallbackPending) {
+ notificationFallbackPending = false;
+ loadUnreadNotifications();
+ }
+ };
+ watch(() => assetStore.state.expiryReminder, advanceHomePopupQueue);
let showModifyWifi = ref(false);
let restartShow = ref(false);
@@ -899,18 +919,18 @@
const loadUnreadNotifications = async () => {
const context = getSessionContext();
+ const entryId = homeEntryId;
try {
const data = await notificationApi.getList(1, 50, false);
- if (!homeActive.value || !isCurrentSession(context)) return;
+ if (!homeActive.value || entryId !== homeEntryId || !isCurrentSession(context)) return;
const items = (data?.items || [])
.filter(item => !item.is_read && item.category !== 'expiry');
if (!items.length) return;
notificationItems.value = items;
notificationPopupCurrent.value = 0;
- notificationPopupShow.value = true;
- // 弹窗打开即视为用户已看到第一条通知。
- markNotificationRead(items[0]);
+ notificationQueued = true;
+ advanceHomePopupQueue();
} catch (error) {
console.error('加载首页未读通知失败', error);
}
@@ -931,6 +951,7 @@
const closeNotificationPopup = () => {
notificationPopupShow.value = false;
+ advanceHomePopupQueue();
};
const runPopupCandidate = () => {
@@ -938,10 +959,12 @@
};
const onPopupCandidateClose = (reason) => {
+ if (!homeActive.value) return;
popupCandidateShow.value = false;
if (reason === 'empty' || reason === 'invisible') {
- loadUnreadNotifications();
+ notificationFallbackPending = true;
}
+ advanceHomePopupQueue();
loadNotificationUnreadCount();
};
@@ -949,31 +972,44 @@
initCurrentMonth();
});
- onShow(() => {
+ onShow(async () => {
+ const entryId = ++homeEntryId;
homeActive.value = true;
shownExpiryReminder.value = null;
- showPendingExpiryReminder();
+ awaitingHomeReminders.value = true;
+ notificationFallbackPending = false;
+ notificationQueued = false;
if (!getSessionContext().token) {
+ awaitingHomeReminders.value = false;
handleIndexEntry();
return;
}
if (consumePendingPaymentRefresh(PAYMENT_REFRESH_TARGETS.HOME)) {
loadAssetInfo();
}
- handleIndexEntry();
loadNotificationUnreadCount();
runPopupCandidate();
+ await handleIndexEntry();
+ if (!homeActive.value || entryId !== homeEntryId) return;
+ awaitingHomeReminders.value = false;
+ advanceHomePopupQueue();
});
onHide(() => {
+ homeEntryId++;
homeActive.value = false;
shownExpiryReminder.value = null;
notificationPopupShow.value = false;
+ popupCandidateShow.value = false;
+ notificationQueued = false;
+ notificationFallbackPending = false;
});
watch(() => [userStore.state.token, userStore.state.identifier], () => {
shownExpiryReminder.value = null;
notificationItems.value = [];
notificationUnreadCount.value = 0;
notificationPopupShow.value = false;
+ notificationQueued = false;
+ notificationFallbackPending = false;
});
diff --git a/pages/notifications/notifications.vue b/pages/notifications/notifications.vue
index 677ba1f..69b2a71 100644
--- a/pages/notifications/notifications.vue
+++ b/pages/notifications/notifications.vue
@@ -17,11 +17,11 @@
-
+
{{ item.body || '-' }}