feat: 沉默期已过期强制弹窗,只能去延期,不能关闭
All checks were successful
构建并部署前端到测试环境 / build-and-deploy (push) Successful in 5m37s
All checks were successful
构建并部署前端到测试环境 / build-and-deploy (push) Successful in 5m37s
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<view class="silence-overlay" @tap.stop>
|
||||
<view class="silence-overlay" :class="{ 'silence-overlay-blocking': blocking }" @tap.stop @touchmove.stop.prevent>
|
||||
<view class="silence-dialog" :class="`silence-${reminder.kind}`" role="dialog" aria-modal="true" aria-label="套餐沉默期提醒">
|
||||
<button class="silence-close" aria-label="关闭沉默期提醒" @tap="$emit('close')">×</button>
|
||||
<button v-if="!blocking" class="silence-close" aria-label="关闭沉默期提醒" @tap="$emit('close')">×</button>
|
||||
<view class="silence-title">{{ title }}</view>
|
||||
<view v-if="reminder.packageName" class="silence-package">{{ reminder.packageName }}</view>
|
||||
<view class="silence-body">
|
||||
@@ -9,7 +9,7 @@
|
||||
套餐沉默期已于 <text class="silence-strong">{{ deadline }}</text> 过期,您有一笔未支付的延期订单({{ reminder.pendingOrderNo }}),请继续支付;不需要了可以作废后重新办理。
|
||||
</template>
|
||||
<template v-else-if="reminder.kind === 'expired'">
|
||||
套餐需在 <text class="silence-strong">{{ deadline }}</text> 前完成实名,现已过期。办理延期后可继续实名激活使用。
|
||||
套餐需在 <text class="silence-strong">{{ deadline }}</text> 前完成实名,现已过期。请先办理延期,延期后才能继续使用其他功能。
|
||||
</template>
|
||||
<template v-else>
|
||||
套餐需在 <text class="silence-strong">{{ deadline }}</text> 前完成实名激活,还剩
|
||||
@@ -17,17 +17,18 @@
|
||||
</template>
|
||||
</view>
|
||||
<button class="silence-confirm" @tap="$emit('action')">{{ actionText }}</button>
|
||||
<button class="silence-later" @tap="$emit('close')">我知道了</button>
|
||||
<button v-if="!blocking" class="silence-later" @tap="$emit('close')">我知道了</button>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { computed } from 'vue';
|
||||
import { formatSilenceDate } from '@/utils/silence.js';
|
||||
import { formatSilenceDate, isSilenceReminderBlocking } from '@/utils/silence.js';
|
||||
|
||||
const props = defineProps({ reminder: { type: Object, required: true } });
|
||||
defineEmits(['close', 'action']);
|
||||
const blocking = computed(() => isSilenceReminderBlocking(props.reminder));
|
||||
const deadline = computed(() => formatSilenceDate(props.reminder.silence?.silence_deadline_at));
|
||||
const title = computed(() => {
|
||||
if (props.reminder.pendingOrderNo) return '延期订单未支付';
|
||||
@@ -52,6 +53,12 @@
|
||||
background: rgba(20, 26, 36, 0.48);
|
||||
}
|
||||
|
||||
/* 强制延期弹窗盖在首页所有弹层(含 up-popup)之上 */
|
||||
.silence-overlay-blocking {
|
||||
z-index: 10200;
|
||||
background: rgba(20, 26, 36, 0.64);
|
||||
}
|
||||
|
||||
.silence-dialog {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
|
||||
@@ -161,7 +161,7 @@
|
||||
import { consumePendingPaymentRefresh, PAYMENT_REFRESH_TARGETS } from '@/utils/payment.js';
|
||||
import { getSessionContext, isCurrentSession } from '@/utils/session-context.js';
|
||||
import { getShanghaiDay } from '@/utils/expiry-reminder.js';
|
||||
import { pickSilenceReminder, silenceReminderKey, silenceReminderRepeats } from '@/utils/silence.js';
|
||||
import { isSilenceReminderBlocking, pickSilenceReminder, silenceReminderKey, silenceReminderRepeats } from '@/utils/silence.js';
|
||||
|
||||
const userStore = useUserStore();
|
||||
const assetStore = useAssetStore();
|
||||
@@ -190,7 +190,7 @@
|
||||
assetStore.dismissExpiryReminder();
|
||||
if (resumeQueue) advanceHomePopupQueue();
|
||||
};
|
||||
// 沉默期提醒:首页按"临期提醒 → 沉默期提醒 → 站内通知"的顺序依次弹出,同一资产同一笔套餐每天最多一次。
|
||||
// 沉默期提醒:已过期待延期的为强制弹窗(立即弹出、不可关闭、每次回首页都弹);临近截止的按"临期提醒 → 沉默期提醒 → 站内通知"顺序弹出,同一套餐每次登录最多一次。
|
||||
const silenceReminder = ref(null);
|
||||
const silenceReminderShow = ref(false);
|
||||
let silenceReminderIdentifier = '';
|
||||
@@ -216,6 +216,11 @@
|
||||
if (entryId !== homeEntryId || !homeActive.value || identifier !== String(userStore.state.identifier || '').trim()) return;
|
||||
silenceReminderIdentifier = identifier;
|
||||
silenceReminder.value = reminder;
|
||||
// 已过期待延期:不排队,立即强制弹出并盖住其他弹层,未延期前不能做其他操作
|
||||
if (isSilenceReminderBlocking(reminder)) {
|
||||
silenceReminderShow.value = true;
|
||||
return;
|
||||
}
|
||||
advanceHomePopupQueue();
|
||||
} catch (error) {
|
||||
// 提醒失败不影响首页其他功能
|
||||
@@ -236,6 +241,8 @@
|
||||
return true;
|
||||
};
|
||||
const closeSilenceReminder = () => {
|
||||
// 强制延期弹窗不允许关闭
|
||||
if (isSilenceReminderBlocking(silenceReminder.value)) return;
|
||||
silenceReminderShow.value = false;
|
||||
silenceReminder.value = null;
|
||||
advanceHomePopupQueue();
|
||||
|
||||
@@ -934,7 +934,7 @@ test('order completion and payment return reread actual asset state, not a presu
|
||||
assert.equal(reads, 4);
|
||||
});
|
||||
|
||||
test('home shows the expired silence reminder on every return until paid, after other popups', async () => {
|
||||
test('home forces the expired silence reminder on every return until extended, above other popups, and it cannot be closed', async () => {
|
||||
const r = runtime();
|
||||
r.api.assetApi = {
|
||||
getInfo: async () => ({ identifier: 'A' }),
|
||||
@@ -950,11 +950,12 @@ test('home shows the expired silence reminder on every return until paid, after
|
||||
const page = await r.load('pages/index/index.vue', ['silenceReminder', 'silenceReminderShow', 'onPopupCandidateClose', 'openSilenceReminderAction', 'closeSilenceReminder']);
|
||||
const settle = async () => { for (let i = 0; i < 6; i++) await r.tick(); };
|
||||
await r.shown[0](); await settle();
|
||||
// 运营弹窗仍在时不弹沉默期提醒
|
||||
assert.equal(page.silenceReminderShow.value, false);
|
||||
page.onPopupCandidateClose('empty'); await settle();
|
||||
// 已过期待延期为强制弹窗:不等运营弹窗关闭,立即弹出
|
||||
assert.equal(page.silenceReminderShow.value, true);
|
||||
assert.equal(page.silenceReminder.value.kind, 'expired');
|
||||
// 不能关闭
|
||||
page.closeSilenceReminder();
|
||||
assert.equal(page.silenceReminderShow.value, true);
|
||||
assert.equal(page.silenceReminder.value.pendingOrderNo, undefined);
|
||||
page.openSilenceReminderAction();
|
||||
assert.equal(page.silenceReminderShow.value, false);
|
||||
@@ -962,15 +963,13 @@ test('home shows the expired silence reminder on every return until paid, after
|
||||
assert.equal(r.calls.at(-1).url, '/pages/silence-extension/silence-extension?package_usage_id=44961');
|
||||
// 已过期未支付:同一次登录内每次回到首页都要再弹
|
||||
r.hidden[0](); await r.shown[0](); await settle();
|
||||
page.onPopupCandidateClose('empty'); await settle();
|
||||
assert.equal(page.silenceReminderShow.value, true);
|
||||
page.closeSilenceReminder();
|
||||
assert.equal(page.silenceReminderShow.value, false);
|
||||
assert.equal(page.silenceReminderShow.value, true);
|
||||
// 重新登录(凭证变化)后再次提醒;有未支付延期订单时提示去支付或作废
|
||||
pendingOrderNo = 'SE20261107200004975908';
|
||||
r.storage.set('token', 'session-B');
|
||||
r.hidden[0](); await r.shown[0](); await settle();
|
||||
page.onPopupCandidateClose('empty'); await settle();
|
||||
assert.equal(page.silenceReminderShow.value, true);
|
||||
assert.equal(page.silenceReminder.value.pendingOrderNo, 'SE20261107200004975908');
|
||||
});
|
||||
|
||||
@@ -12,6 +12,7 @@ import {
|
||||
pickSilenceReminder,
|
||||
silenceReminderKey,
|
||||
silenceReminderRepeats,
|
||||
isSilenceReminderBlocking,
|
||||
validateExtensionDays
|
||||
} from '../utils/silence.js';
|
||||
|
||||
@@ -105,3 +106,10 @@ test('只有已过期未延期的提醒每次回首页都弹,待实名提醒
|
||||
assert.equal(silenceReminderRepeats(null), false);
|
||||
});
|
||||
|
||||
|
||||
test('已过期的沉默期提醒为强制弹窗,临近截止的可关闭', () => {
|
||||
assert.equal(isSilenceReminderBlocking({ kind: 'expired' }), true);
|
||||
assert.equal(isSilenceReminderBlocking({ kind: 'expired', pendingOrderNo: 'SE1' }), true);
|
||||
assert.equal(isSilenceReminderBlocking({ kind: 'waiting' }), false);
|
||||
assert.equal(isSilenceReminderBlocking(null), false);
|
||||
});
|
||||
|
||||
@@ -181,5 +181,8 @@ const shortHash = (value) => {
|
||||
/** 已过期未延期(含有未支付延期订单)每次回首页都要提醒;只有"待实名临近截止"按每次登录一次 */
|
||||
export const silenceReminderRepeats = (reminder) => reminder?.kind === 'expired';
|
||||
|
||||
/** 已过期待延期的提醒为强制弹窗:不能关闭,只能去延期(或处理未支付的延期订单)。 */
|
||||
export const isSilenceReminderBlocking = (reminder) => reminder?.kind === 'expired';
|
||||
|
||||
export const silenceReminderKey = (identifier, reminder, sessionToken) =>
|
||||
`silence_reminder:${identifier}:${reminder.packageUsageId}:${reminder.kind}:${shortHash(sessionToken)}`;
|
||||
|
||||
Reference in New Issue
Block a user