fix: 系统检查修复 — 布局一致性 + bug 修复

- 公告图片样式统一:圆角 $radius-md,间距 $space-sm
- 首页紧急公告弹窗样式改为 SCSS 变量
- 新增 modal-mask-high mixin 统一高层级弹窗
- admin/config.vue 添加 initialLoaded 守卫避免重复请求
- notifications/index.vue 添加 initialLoaded 守卫
- notification store 所有方法添加 try-catch 错误处理
This commit is contained in:
2026-06-08 11:21:08 +08:00
parent ecfb67872d
commit 24166aeb62
6 changed files with 70 additions and 58 deletions

View File

@@ -60,6 +60,7 @@ import Icon from '@/components/Icon/Icon.vue'
const loading = ref(true)
const saving = ref(false)
const initialLoaded = ref(false)
const form = reactive({
app_version: '',
@@ -70,30 +71,26 @@ const form = reactive({
onMounted(async () => {
await waitForReady()
try {
const config = await getConfig()
form.app_version = config.app_version || '1.0.0'
form.app_slogan = config.app_slogan || ''
form.app_description = config.app_description || ''
await loadConfig()
} catch (e: any) {
uni.showToast({ title: e.message || '加载失败', icon: 'none' })
} finally {
loading.value = false
initialLoaded.value = true
}
})
// 加载配置数据
async function loadConfig() {
try {
const config = await getConfig()
form.app_version = config.app_version || '1.0.0'
form.app_slogan = config.app_slogan || ''
form.app_description = config.app_description || ''
} catch {}
}
// 返回页面时静默刷新
onShow(() => {
loadConfig()
if (initialLoaded.value) loadConfig()
})
onPullDownRefresh(async () => {

View File

@@ -552,23 +552,14 @@ function goBills() {
/* 强提醒公告弹窗 */
.modal-mask {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.5);
z-index: 300;
display: flex;
align-items: center;
justify-content: center;
@include modal-mask-high;
}
.urgent-modal {
width: 80%;
max-height: 70vh;
background: #FFFFFF;
border-radius: 32rpx;
background: $surface;
border-radius: $radius-2xl;
overflow: hidden;
display: flex;
flex-direction: column;
@@ -577,52 +568,52 @@ function goBills() {
.urgent-header {
display: flex;
align-items: center;
gap: 12rpx;
padding: 32rpx 32rpx 16rpx;
gap: $space-sm;
padding: $space-xl $space-lg $space-md;
}
.urgent-title {
font-size: 32rpx;
font-size: $font-xl;
font-weight: 600;
color: #2D1B1B;
color: $text;
flex: 1;
}
.urgent-body {
flex: 1;
padding: 0 32rpx 24rpx;
padding: 0 $space-lg $space-lg;
max-height: 50vh;
}
.urgent-image {
width: 100%;
border-radius: 16rpx;
margin-bottom: 16rpx;
border-radius: $radius-md;
margin-bottom: $space-sm;
}
.urgent-content {
font-size: 28rpx;
color: #2D1B1B;
font-size: $font-lg;
color: $text;
line-height: 1.6;
}
.urgent-link {
margin-top: 16rpx;
padding: 12rpx 0;
margin-top: $space-sm;
padding: $space-xs 0;
}
.urgent-link-text {
font-size: 28rpx;
color: #FF8C69;
font-size: $font-lg;
color: $primary;
text-decoration: underline;
}
.urgent-footer {
padding: 24rpx 32rpx;
border-top: 2rpx solid #F0E0D6;
padding: $space-lg;
border-top: 2rpx solid $border;
text-align: center;
&:active { background: #FFF8F0; }
&:active { background: $surface-warm; }
}
.urgent-btn-text {

View File

@@ -104,6 +104,7 @@ const page = ref(1)
const total = ref(0)
const loading = ref(false)
const detailItem = ref<Notification | null>(null)
const initialLoaded = ref(false)
let loadSeq = 0
const noMore = computed(() => list.value.length >= total.value && total.value > 0)
@@ -111,9 +112,11 @@ const noMore = computed(() => list.value.length >= total.value && total.value >
onMounted(async () => {
await waitForReady()
await loadNotifications(true)
initialLoaded.value = true
})
onShow(() => {
if (!initialLoaded.value) return
notifStore.fetchUnreadCount()
// 返回页面时刷新列表(如全部已读后)
if (list.value.length > 0) {
@@ -374,8 +377,8 @@ onReachBottom(() => {
.notif-image {
width: 100%;
border-radius: $radius-sm;
margin-top: 12rpx;
border-radius: $radius-md;
margin-top: $space-sm;
}
.notif-meta {

View File

@@ -562,13 +562,7 @@ async function exportData() {
}
.modal-mask {
position: fixed;
top: 0; left: 0; right: 0; bottom: 0;
background: rgba(0, 0, 0, 0.5);
display: flex;
align-items: center;
justify-content: center;
z-index: 999;
@include modal-mask-high;
}
.modal {

View File

@@ -8,26 +8,42 @@ export const useNotificationStore = defineStore('notification', () => {
const urgentNotifications = ref<Notification[]>([])
async function fetchUnreadCount() {
try {
const data = await api.getUnreadCount()
unreadCount.value = data.count
} catch {
// 静默失败,不影响页面
}
}
/** 获取未读的强提醒公告(首页弹窗用) */
async function fetchUrgentNotifications() {
try {
urgentNotifications.value = await api.getPinnedNotifications()
} catch {
// 静默失败
}
}
async function markRead(id: number) {
try {
await api.markRead(id)
if (unreadCount.value > 0) unreadCount.value--
// 从强提醒列表中移除
urgentNotifications.value = urgentNotifications.value.filter(n => n.id !== id)
} catch {
// 静默失败
}
}
async function markAllRead() {
try {
await api.markAllRead()
unreadCount.value = 0
urgentNotifications.value = []
} catch {
// 静默失败
}
}
return { unreadCount, urgentNotifications, fetchUnreadCount, fetchUrgentNotifications, markRead, markAllRead }

View File

@@ -109,6 +109,17 @@
align-items: flex-end;
}
// 高层级弹窗(紧急公告、身份选择等需要覆盖其他弹窗的场景)
@mixin modal-mask-high {
position: fixed;
top: 0; left: 0; right: 0; bottom: 0;
background: rgba(0, 0, 0, 0.5);
z-index: 300;
display: flex;
align-items: center;
justify-content: center;
}
@mixin bottom-modal {
width: 100%;
max-height: 80vh;