Files
device-voice-h5/components/NotificationPopup.vue
luo ac45a08373
All checks were successful
构建并部署前端到生产环境 / build-and-deploy (push) Successful in 2m35s
feat: 通知弹窗新增立即续费按钮
2026-08-12 11:05:21 +08:00

201 lines
4.4 KiB
Vue
Raw Permalink Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<view v-if="show" class="notification-popup" @tap.stop>
<view class="notification-popup-card">
<view class="popup-header">
<view class="popup-heading">新通知</view>
<view class="popup-close" role="button" aria-label="关闭" @tap="$emit('close')">×</view>
</view>
<swiper class="notification-swiper" :current="current" @change="$emit('change', $event)">
<swiper-item v-for="item in items" :key="item.id">
<view class="notification-content">
<view class="notification-title">{{ item.title || '业务通知' }}</view>
<view class="notification-severity">{{ getNotificationMeta(item) }}</view>
<view class="notification-time">{{ formatDate(item.created_at) }}</view>
<scroll-view scroll-y class="notification-body">
<text>{{ item.body || '暂无通知内容' }}</text>
</scroll-view>
<up-button v-if="item.category === 'expiry'" class="renew-button" type="primary" size="small"
@tap.stop="$emit('renew', item)">立即续费</up-button>
</view>
</swiper-item>
</swiper>
<view v-if="items.length > 1" class="popup-footer">
<view class="popup-swipe-hint" aria-label="左右滑动切换通知">
<text class="swipe-arrow"></text>
<text>左右滑动切换通知</text>
<text class="swipe-arrow"></text>
</view>
<view class="popup-dots">
<view v-for="(_, index) in items" :key="index" class="popup-dot" :class="{ active: index === current }"></view>
</view>
<view class="popup-counter">{{ current + 1 }}/{{ items.length }} 左右滑动查看</view>
</view>
</view>
</view>
</template>
<script setup>
defineProps({
show: Boolean,
items: {
type: Array,
default: () => []
},
current: {
type: Number,
default: 0
}
});
defineEmits(['close', 'change', 'renew']);
const formatDate = (value) => {
if (!value) return '-';
return value.replace('T', ' ').slice(0, 16);
};
const getNotificationMeta = (item) => {
const category = {
expiry: '套餐临期',
exchange: '换货'
}[item?.category] || '业务通知';
const severity = {
info: '提示',
warning: '警告',
error: '错误',
critical: '严重'
}[item?.severity];
return severity ? `${category} · ${severity}` : category;
};
</script>
<style scoped lang="scss">
.notification-popup {
position: fixed;
z-index: 1000;
inset: 0;
display: flex;
align-items: center;
justify-content: center;
padding: 40rpx;
background: rgba(0, 0, 0, 0.48);
}
.notification-popup-card {
width: 100%;
max-width: 640rpx;
overflow: hidden;
border-radius: 24rpx;
background: #fff;
box-shadow: 0 20rpx 60rpx rgba(0, 0, 0, 0.18);
}
.popup-header {
display: flex;
align-items: center;
justify-content: space-between;
padding: 30rpx 32rpx 18rpx;
}
.popup-heading {
color: var(--text-primary);
font-size: 34rpx;
font-weight: 600;
}
.popup-close {
width: 52rpx;
height: 52rpx;
color: var(--text-tertiary);
font-size: 48rpx;
font-weight: 300;
line-height: 46rpx;
text-align: center;
}
.notification-swiper { height: 430rpx; }
.notification-content {
height: 100%;
box-sizing: border-box;
padding: 18rpx 32rpx 28rpx;
}
.notification-title {
color: var(--text-primary);
font-size: 32rpx;
font-weight: 600;
line-height: 1.45;
}
.notification-severity {
margin-top: 10rpx;
color: var(--primary);
font-size: 22rpx;
}
.notification-time {
margin-top: 12rpx;
color: var(--text-tertiary);
font-size: 22rpx;
}
.notification-body {
box-sizing: border-box;
height: 180rpx;
margin-top: 28rpx;
color: var(--text-secondary);
font-size: 28rpx;
line-height: 1.7;
white-space: pre-wrap;
}
.popup-footer {
padding: 0 32rpx 28rpx;
text-align: center;
}
.renew-button {
margin-top: 20rpx;
}
.popup-swipe-hint {
display: flex;
align-items: center;
justify-content: center;
gap: 8rpx;
margin-bottom: 16rpx;
color: var(--primary);
font-size: 24rpx;
font-weight: 500;
}
.swipe-arrow {
font-size: 34rpx;
line-height: 1;
}
.popup-dots {
display: flex;
justify-content: center;
gap: 10rpx;
}
.popup-dot {
width: 12rpx;
height: 12rpx;
border-radius: 50%;
background: #d8dce3;
}
.popup-dot.active { width: 28rpx; border-radius: 8rpx; background: var(--primary); }
.popup-counter {
margin-top: 12rpx;
color: var(--text-tertiary);
font-size: 22rpx;
}
</style>