新增公告弹窗功能,优化公告检查逻辑,支持今日不再弹出设置,提升用户体验

This commit is contained in:
yahaozhang
2025-09-15 15:06:01 +08:00
parent d38273bda2
commit f250fd07c4
2 changed files with 160 additions and 217 deletions

View File

@@ -45,10 +45,37 @@
ID: {{ machineId || 'N/A' }}
</div>
</div>
<!-- 公告弹窗仅在游戏页面显示 -->
<el-dialog
v-model="announcementVisible"
title="代理商公告"
:width="'90%'"
:before-close="handleAnnouncementClose"
class="announcement-dialog"
>
<div v-if="announcement" class="announcement-content">
<h3 class="announcement-title">{{ announcement.title }}</h3>
<div class="announcement-text">{{ announcement.content }}</div>
</div>
<div v-else class="announcement-empty">
暂无公告内容
</div>
<template #footer>
<div class="announcement-footer">
<el-checkbox v-model="dontShowToday" class="dont-show-checkbox">
今日不再弹出
</el-checkbox>
<el-button type="primary" @click="handleAnnouncementClose">确定</el-button>
</div>
</template>
</el-dialog>
</div>
</template>
<script>
import { onMounted, ref, watch } from 'vue'
import { getAnnouncementByCode } from '@/api/announcement'
export default {
name: 'GamePage',
props: {
@@ -106,6 +133,94 @@ export default {
timestamp: Date.now()
}
},
setup(props) {
const announcementVisible = ref(false)
const announcement = ref(null)
const dontShowToday = ref(false)
const getStorageKey = (codeNo, announcementId) => {
return `announcement_dismissed_${codeNo}_${announcementId}`
}
const getTodayKey = (codeNo) => {
const today = new Date().toDateString()
return `announcement_dont_show_today_${codeNo}_${today}`
}
const isDismissedPermanently = (codeNo, announcementId) => {
const key = getStorageKey(codeNo, announcementId)
return localStorage.getItem(key) === 'true'
}
const isDontShowToday = (codeNo) => {
const key = getTodayKey(codeNo)
return localStorage.getItem(key) === 'true'
}
const markDismissedPermanently = (codeNo, announcementId) => {
const key = getStorageKey(codeNo, announcementId)
localStorage.setItem(key, 'true')
}
const markDontShowToday = (codeNo) => {
const key = getTodayKey(codeNo)
localStorage.setItem(key, 'true')
}
const checkAnnouncement = async (codeNo) => {
if (!codeNo) return
if (isDontShowToday(codeNo)) return
try {
const response = await getAnnouncementByCode(codeNo)
if (response.data && response.data.success && response.data.data && response.data.data.length > 0) {
const announcementData = response.data.data[0]
if (announcementData.enabled) {
const dismissed = isDismissedPermanently(codeNo, announcementData.id)
if (!dismissed) {
announcement.value = announcementData
announcementVisible.value = true
}
}
}
} catch (error) {
console.error('获取公告失败:', error)
}
}
const handleAnnouncementClose = () => {
const codeNo = props.codeNo
const announcementData = announcement.value
if (dontShowToday.value && codeNo) {
markDontShowToday(codeNo)
}
if (announcementData && codeNo) {
markDismissedPermanently(codeNo, announcementData.id)
}
announcementVisible.value = false
dontShowToday.value = false
}
onMounted(() => {
// 仅在进入 GamePage 时检查公告
setTimeout(() => checkAnnouncement(props.codeNo), 1000)
})
watch(
() => props.codeNo,
(newCode) => {
if (newCode) {
checkAnnouncement(newCode)
}
}
)
return {
announcementVisible,
announcement,
dontShowToday,
handleAnnouncementClose
}
},
computed: {
remainingPoints() {
const total = this.totalPoints || 0
@@ -235,6 +350,50 @@ export default {
color: #333;
}
.announcement-dialog {
:deep(.el-dialog__body) {
padding: 16px 20px;
}
}
.announcement-content {
max-height: 60vh;
overflow-y: auto;
}
.announcement-title {
color: #333;
font-size: 18px;
margin-bottom: 16px;
padding-bottom: 8px;
border-bottom: 1px solid #e9ecef;
}
.announcement-text {
color: #666;
font-size: 14px;
line-height: 1.6;
white-space: pre-wrap;
}
.announcement-empty {
text-align: center;
color: #999;
padding: 20px 0;
font-size: 14px;
}
.announcement-footer {
display: flex;
justify-content: space-between;
align-items: center;
}
.dont-show-checkbox {
font-size: 14px;
color: #666;
}
@media (max-width: 768px) {
.tab-item {
padding: 10px 8px;

View File

@@ -67,30 +67,6 @@
@retry="handleRetry"
/>
<!-- 公告弹窗 -->
<el-dialog
v-model="announcementVisible"
title="代理商公告"
:width="'90%'"
:before-close="handleAnnouncementClose"
class="announcement-dialog"
>
<div v-if="announcement" class="announcement-content">
<h3 class="announcement-title">{{ announcement.title }}</h3>
<div class="announcement-text">{{ announcement.content }}</div>
</div>
<div v-else class="announcement-empty">
暂无公告内容
</div>
<template #footer>
<div class="announcement-footer">
<el-checkbox v-model="dontShowToday" class="dont-show-checkbox">
今日不再弹出
</el-checkbox>
<el-button type="primary" @click="handleAnnouncementClose">确定</el-button>
</div>
</template>
</el-dialog>
</div>
</template>
@@ -100,7 +76,6 @@ import { useRoute } from 'vue-router'
import { usePlayState } from '@/composables/usePlayState'
import { useTimers } from '@/composables/useTimers'
import { useQrCode } from '@/composables/useQrCode'
import { getAnnouncementByCode } from '@/api/announcement'
import LoadingOverlay from '@/components/play/LoadingOverlay.vue'
import SelectRegion from '@/components/play/SelectRegion.vue'
@@ -122,119 +97,6 @@ export default {
setup() {
const route = useRoute()
// 公告相关状态
const announcementVisible = ref(false)
const announcement = ref(null)
const dontShowToday = ref(false)
// 本地存储相关函数
const getStorageKey = (codeNo, announcementId) => {
return `announcement_dismissed_${codeNo}_${announcementId}`
}
const getTodayKey = (codeNo) => {
const today = new Date().toDateString()
return `announcement_dont_show_today_${codeNo}_${today}`
}
const isDismissedPermanently = (codeNo, announcementId) => {
const key = getStorageKey(codeNo, announcementId)
return localStorage.getItem(key) === 'true'
}
const isDontShowToday = (codeNo) => {
const key = getTodayKey(codeNo)
return localStorage.getItem(key) === 'true'
}
const markDismissedPermanently = (codeNo, announcementId) => {
const key = getStorageKey(codeNo, announcementId)
localStorage.setItem(key, 'true')
}
const markDontShowToday = (codeNo) => {
const key = getTodayKey(codeNo)
localStorage.setItem(key, 'true')
}
// 检查并显示公告
const checkAnnouncement = async (codeNo) => {
if (!codeNo) return
console.log('检查公告:', codeNo)
// 检查今日是否设置为不弹出
if (isDontShowToday(codeNo)) {
console.log('今日已设置不弹出')
return
}
try {
const response = await getAnnouncementByCode(codeNo)
console.log('公告接口响应:', response)
// 修复:应该检查 response.data.data 而不是 response.data
if (response.data && response.data.success && response.data.data && response.data.data.length > 0) {
const announcementData = response.data.data[0]
console.log('公告数据:', announcementData)
if (announcementData.enabled) {
// 检查是否已永久关闭此公告
const isDismissed = isDismissedPermanently(codeNo, announcementData.id)
console.log('是否已永久关闭:', isDismissed)
if (!isDismissed) {
announcement.value = announcementData
announcementVisible.value = true
console.log('显示公告弹窗')
} else {
console.log('公告已被永久关闭')
}
} else {
console.log('公告未启用')
}
} else {
console.log('无公告数据')
}
} catch (error) {
console.error('获取公告失败:', error)
}
}
// 处理公告关闭
const handleAnnouncementClose = () => {
const codeNo = state.code
const announcementData = announcement.value
if (dontShowToday.value && codeNo) {
markDontShowToday(codeNo)
console.log('已设置今日不弹出')
}
if (announcementData && codeNo) {
markDismissedPermanently(codeNo, announcementData.id)
console.log('已永久关闭公告:', announcementData.id)
}
announcementVisible.value = false
dontShowToday.value = false
}
// 临时调试:清除本地存储
const clearAnnouncementStorage = () => {
Object.keys(localStorage).forEach(key => {
if (key.startsWith('announcement_')) {
localStorage.removeItem(key)
}
})
console.log('已清除所有公告本地存储')
}
// 开发环境下添加到window对象方便调试
if (process.env.NODE_ENV === 'development') {
window.clearAnnouncementStorage = clearAnnouncementStorage
}
const {
state,
initializePage,
@@ -285,11 +147,6 @@ export default {
state.code = code
initializePage()
// 检查公告
setTimeout(() => {
checkAnnouncement(code)
}, 1000) // 延迟1秒执行确保页面已经加载完成
})
onUnmounted(() => {
@@ -355,12 +212,7 @@ export default {
getGameStatus,
getStatusClass,
getErrorTitle,
getErrorMessage,
// 公告相关
announcementVisible,
announcement,
dontShowToday,
handleAnnouncementClose
getErrorMessage
}
}
}
@@ -392,77 +244,9 @@ export default {
text-align: center;
}
.announcement-dialog {
:deep(.el-dialog__body) {
padding: 16px 20px;
}
}
.announcement-content {
max-height: 60vh;
overflow-y: auto;
}
.announcement-title {
color: #333;
font-size: 18px;
margin-bottom: 16px;
padding-bottom: 8px;
border-bottom: 1px solid #e9ecef;
}
.announcement-text {
color: #666;
font-size: 14px;
line-height: 1.6;
white-space: pre-wrap;
}
.announcement-empty {
text-align: center;
color: #999;
padding: 20px 0;
font-size: 14px;
}
.announcement-footer {
display: flex;
justify-content: space-between;
align-items: center;
}
.dont-show-checkbox {
font-size: 14px;
color: #666;
}
@media (max-width: 768px) {
.completed-text {
font-size: 36px;
}
.announcement-dialog {
:deep(.el-dialog) {
width: 95vw !important;
}
.announcement-title {
font-size: 16px;
}
.announcement-text {
font-size: 13px;
}
}
.announcement-footer {
flex-direction: column;
gap: 12px;
align-items: stretch;
}
.dont-show-checkbox {
align-self: flex-start;
}
}
</style>