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:
@@ -60,6 +60,7 @@ import Icon from '@/components/Icon/Icon.vue'
|
|||||||
|
|
||||||
const loading = ref(true)
|
const loading = ref(true)
|
||||||
const saving = ref(false)
|
const saving = ref(false)
|
||||||
|
const initialLoaded = ref(false)
|
||||||
|
|
||||||
const form = reactive({
|
const form = reactive({
|
||||||
app_version: '',
|
app_version: '',
|
||||||
@@ -70,30 +71,26 @@ const form = reactive({
|
|||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
await waitForReady()
|
await waitForReady()
|
||||||
try {
|
try {
|
||||||
const config = await getConfig()
|
await loadConfig()
|
||||||
form.app_version = config.app_version || '1.0.0'
|
|
||||||
form.app_slogan = config.app_slogan || ''
|
|
||||||
form.app_description = config.app_description || ''
|
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
uni.showToast({ title: e.message || '加载失败', icon: 'none' })
|
uni.showToast({ title: e.message || '加载失败', icon: 'none' })
|
||||||
} finally {
|
} finally {
|
||||||
loading.value = false
|
loading.value = false
|
||||||
|
initialLoaded.value = true
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
// 加载配置数据
|
// 加载配置数据
|
||||||
async function loadConfig() {
|
async function loadConfig() {
|
||||||
try {
|
const config = await getConfig()
|
||||||
const config = await getConfig()
|
form.app_version = config.app_version || '1.0.0'
|
||||||
form.app_version = config.app_version || '1.0.0'
|
form.app_slogan = config.app_slogan || ''
|
||||||
form.app_slogan = config.app_slogan || ''
|
form.app_description = config.app_description || ''
|
||||||
form.app_description = config.app_description || ''
|
|
||||||
} catch {}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 返回页面时静默刷新
|
// 返回页面时静默刷新
|
||||||
onShow(() => {
|
onShow(() => {
|
||||||
loadConfig()
|
if (initialLoaded.value) loadConfig()
|
||||||
})
|
})
|
||||||
|
|
||||||
onPullDownRefresh(async () => {
|
onPullDownRefresh(async () => {
|
||||||
|
|||||||
@@ -552,23 +552,14 @@ function goBills() {
|
|||||||
|
|
||||||
/* 强提醒公告弹窗 */
|
/* 强提醒公告弹窗 */
|
||||||
.modal-mask {
|
.modal-mask {
|
||||||
position: fixed;
|
@include modal-mask-high;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.urgent-modal {
|
.urgent-modal {
|
||||||
width: 80%;
|
width: 80%;
|
||||||
max-height: 70vh;
|
max-height: 70vh;
|
||||||
background: #FFFFFF;
|
background: $surface;
|
||||||
border-radius: 32rpx;
|
border-radius: $radius-2xl;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
@@ -577,52 +568,52 @@ function goBills() {
|
|||||||
.urgent-header {
|
.urgent-header {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 12rpx;
|
gap: $space-sm;
|
||||||
padding: 32rpx 32rpx 16rpx;
|
padding: $space-xl $space-lg $space-md;
|
||||||
}
|
}
|
||||||
|
|
||||||
.urgent-title {
|
.urgent-title {
|
||||||
font-size: 32rpx;
|
font-size: $font-xl;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
color: #2D1B1B;
|
color: $text;
|
||||||
flex: 1;
|
flex: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.urgent-body {
|
.urgent-body {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
padding: 0 32rpx 24rpx;
|
padding: 0 $space-lg $space-lg;
|
||||||
max-height: 50vh;
|
max-height: 50vh;
|
||||||
}
|
}
|
||||||
|
|
||||||
.urgent-image {
|
.urgent-image {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
border-radius: 16rpx;
|
border-radius: $radius-md;
|
||||||
margin-bottom: 16rpx;
|
margin-bottom: $space-sm;
|
||||||
}
|
}
|
||||||
|
|
||||||
.urgent-content {
|
.urgent-content {
|
||||||
font-size: 28rpx;
|
font-size: $font-lg;
|
||||||
color: #2D1B1B;
|
color: $text;
|
||||||
line-height: 1.6;
|
line-height: 1.6;
|
||||||
}
|
}
|
||||||
|
|
||||||
.urgent-link {
|
.urgent-link {
|
||||||
margin-top: 16rpx;
|
margin-top: $space-sm;
|
||||||
padding: 12rpx 0;
|
padding: $space-xs 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.urgent-link-text {
|
.urgent-link-text {
|
||||||
font-size: 28rpx;
|
font-size: $font-lg;
|
||||||
color: #FF8C69;
|
color: $primary;
|
||||||
text-decoration: underline;
|
text-decoration: underline;
|
||||||
}
|
}
|
||||||
|
|
||||||
.urgent-footer {
|
.urgent-footer {
|
||||||
padding: 24rpx 32rpx;
|
padding: $space-lg;
|
||||||
border-top: 2rpx solid #F0E0D6;
|
border-top: 2rpx solid $border;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
|
||||||
&:active { background: #FFF8F0; }
|
&:active { background: $surface-warm; }
|
||||||
}
|
}
|
||||||
|
|
||||||
.urgent-btn-text {
|
.urgent-btn-text {
|
||||||
|
|||||||
@@ -104,6 +104,7 @@ const page = ref(1)
|
|||||||
const total = ref(0)
|
const total = ref(0)
|
||||||
const loading = ref(false)
|
const loading = ref(false)
|
||||||
const detailItem = ref<Notification | null>(null)
|
const detailItem = ref<Notification | null>(null)
|
||||||
|
const initialLoaded = ref(false)
|
||||||
let loadSeq = 0
|
let loadSeq = 0
|
||||||
|
|
||||||
const noMore = computed(() => list.value.length >= total.value && total.value > 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 () => {
|
onMounted(async () => {
|
||||||
await waitForReady()
|
await waitForReady()
|
||||||
await loadNotifications(true)
|
await loadNotifications(true)
|
||||||
|
initialLoaded.value = true
|
||||||
})
|
})
|
||||||
|
|
||||||
onShow(() => {
|
onShow(() => {
|
||||||
|
if (!initialLoaded.value) return
|
||||||
notifStore.fetchUnreadCount()
|
notifStore.fetchUnreadCount()
|
||||||
// 返回页面时刷新列表(如全部已读后)
|
// 返回页面时刷新列表(如全部已读后)
|
||||||
if (list.value.length > 0) {
|
if (list.value.length > 0) {
|
||||||
@@ -374,8 +377,8 @@ onReachBottom(() => {
|
|||||||
|
|
||||||
.notif-image {
|
.notif-image {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
border-radius: $radius-sm;
|
border-radius: $radius-md;
|
||||||
margin-top: 12rpx;
|
margin-top: $space-sm;
|
||||||
}
|
}
|
||||||
|
|
||||||
.notif-meta {
|
.notif-meta {
|
||||||
|
|||||||
@@ -562,13 +562,7 @@ async function exportData() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.modal-mask {
|
.modal-mask {
|
||||||
position: fixed;
|
@include modal-mask-high;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.modal {
|
.modal {
|
||||||
|
|||||||
@@ -8,26 +8,42 @@ export const useNotificationStore = defineStore('notification', () => {
|
|||||||
const urgentNotifications = ref<Notification[]>([])
|
const urgentNotifications = ref<Notification[]>([])
|
||||||
|
|
||||||
async function fetchUnreadCount() {
|
async function fetchUnreadCount() {
|
||||||
const data = await api.getUnreadCount()
|
try {
|
||||||
unreadCount.value = data.count
|
const data = await api.getUnreadCount()
|
||||||
|
unreadCount.value = data.count
|
||||||
|
} catch {
|
||||||
|
// 静默失败,不影响页面
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 获取未读的强提醒公告(首页弹窗用) */
|
/** 获取未读的强提醒公告(首页弹窗用) */
|
||||||
async function fetchUrgentNotifications() {
|
async function fetchUrgentNotifications() {
|
||||||
urgentNotifications.value = await api.getPinnedNotifications()
|
try {
|
||||||
|
urgentNotifications.value = await api.getPinnedNotifications()
|
||||||
|
} catch {
|
||||||
|
// 静默失败
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function markRead(id: number) {
|
async function markRead(id: number) {
|
||||||
await api.markRead(id)
|
try {
|
||||||
if (unreadCount.value > 0) unreadCount.value--
|
await api.markRead(id)
|
||||||
// 从强提醒列表中移除
|
if (unreadCount.value > 0) unreadCount.value--
|
||||||
urgentNotifications.value = urgentNotifications.value.filter(n => n.id !== id)
|
// 从强提醒列表中移除
|
||||||
|
urgentNotifications.value = urgentNotifications.value.filter(n => n.id !== id)
|
||||||
|
} catch {
|
||||||
|
// 静默失败
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function markAllRead() {
|
async function markAllRead() {
|
||||||
await api.markAllRead()
|
try {
|
||||||
unreadCount.value = 0
|
await api.markAllRead()
|
||||||
urgentNotifications.value = []
|
unreadCount.value = 0
|
||||||
|
urgentNotifications.value = []
|
||||||
|
} catch {
|
||||||
|
// 静默失败
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return { unreadCount, urgentNotifications, fetchUnreadCount, fetchUrgentNotifications, markRead, markAllRead }
|
return { unreadCount, urgentNotifications, fetchUnreadCount, fetchUrgentNotifications, markRead, markAllRead }
|
||||||
|
|||||||
@@ -109,6 +109,17 @@
|
|||||||
align-items: flex-end;
|
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 {
|
@mixin bottom-modal {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
max-height: 80vh;
|
max-height: 80vh;
|
||||||
|
|||||||
Reference in New Issue
Block a user