style(admin): unify dialog layouts and dense readonly presentation

This commit is contained in:
2026-10-20 10:11:31 +08:00
parent 7ff7c9914f
commit 3267679758
214 changed files with 10931 additions and 2654 deletions
@@ -27,6 +27,9 @@ const detailOpen = ref(false)
const detailLoading = ref(false)
const detailError = ref<ApiErrorDetails | null>(null)
const detail = ref<NotificationInboxDetail | null>(null)
const detailRow = ref<NotificationInboxItem | null>(null)
let detailRequest = 0
watch(detailOpen, value => { if (!value) { detailRequest++; detailRow.value = null } })
const access = useAccessPreviewStore()
const canRead = computed(() => access.can('platform:notification:read'))
const canReadAll = computed(() => access.can('platform:notification:read-all'))
@@ -58,14 +61,20 @@ async function load() {
} finally { loading.value = false }
}
async function openDetail(row: NotificationInboxItem) {
const request = ++detailRequest
detailRow.value = row
detailOpen.value = true; detailLoading.value = true; detailError.value = null; detail.value = null
try {
detail.value = await getMyNotification(row.id)
if (detail.value.status === 'UNREAD' && canRead.value) {
detail.value = await markMyNotificationRead(row.id)
const result = await getMyNotification(row.id)
if (request !== detailRequest || !detailOpen.value) return
detail.value = result
if (result.status === 'UNREAD' && canRead.value) {
const read = await markMyNotificationRead(row.id)
if (request !== detailRequest || !detailOpen.value) return
detail.value = read
await load()
}
} catch (reason) { detailError.value = getApiErrorDetails(reason, '消息详情加载失败') } finally { detailLoading.value = false }
} catch (reason) { if (request === detailRequest && detailOpen.value) detailError.value = getApiErrorDetails(reason, '消息详情加载失败') } finally { if (request === detailRequest) detailLoading.value = false }
}
async function markRead(row: NotificationInboxItem) {
if (!canRead.value || row.status !== 'UNREAD') return
@@ -97,16 +106,21 @@ onMounted(() => void load())
<template #status="{ row }"><el-tag :type="(row as NotificationInboxItem).status === 'UNREAD' ? 'danger' : 'info'">{{ statusLabel((row as NotificationInboxItem).status) }}</el-tag></template>
</DataTable></section>
</ListPageLayout>
<AppDrawer class="admin-density admin-density-drawer" v-model="detailOpen" title="消息详情" size="min(680px, 94vw)" :loading="detailLoading" :show-footer="false" destroy-on-close>
<LoadErrorState v-if="detailError" title="消息详情加载失败" :message="detailError.message" :loading="detailLoading"><template #details><ApiErrorMeta :details="detailError" /></template></LoadErrorState>
<article v-else-if="detail" class="notification-detail"><header><h2>{{ detail.title }}</h2><el-tag :type="detail.status === 'UNREAD' ? 'danger' : 'info'">{{ statusLabel(detail.status) }}</el-tag></header><p class="meta">{{ notificationCategoryLabel(detail.category) }} · {{ formatDate(detail.sentAt) }}</p><div class="body">{{ detail.body || '暂无消息内容' }}</div></article>
<AppDrawer class="admin-density admin-density-drawer admin-density-drawer--detail" v-model="detailOpen" title="消息详情" size="min(680px, 94vw)" :loading="detailLoading" :show-footer="false" destroy-on-close>
<LoadErrorState v-if="detailError" title="消息详情加载失败" :message="detailError.message" :loading="detailLoading" @retry="detailRow && openDetail(detailRow)"><template #details><ApiErrorMeta :details="detailError" /></template></LoadErrorState>
<article v-else-if="detail" class="density-dialog-sections notification-detail">
<section class="density-dialog-section" data-tone="summary" aria-label="消息资料">
<h3 class="density-dialog-section__title message-heading"><span>{{ detail.title || '消息详情' }}</span><el-tag :type="detail.status === 'UNREAD' ? 'danger' : 'info'">{{ statusLabel(detail.status) }}</el-tag></h3>
<p class="density-dialog-note">{{ notificationCategoryLabel(detail.category) }} · {{ formatDate(detail.sentAt) }}</p>
</section>
<section class="density-dialog-section" data-tone="source" aria-label="消息正文"><h3 class="density-dialog-section__title">消息正文</h3><div class="message-body">{{ detail.body || '暂无消息内容' }}</div></section>
</article>
</AppDrawer>
</AdminPage>
</template>
<style scoped>
.notification-detail header { display: flex; align-items: center; justify-content: space-between; gap: var(--admin-space-5); }
.notification-detail h2 { min-width: 0; margin: 0; overflow-wrap: anywhere; color: var(--cc-text); font-size: var(--admin-font-title); line-height: 1.4; }
.notification-detail .meta { margin: var(--admin-space-5) 0; color: var(--cc-muted); font-size: var(--admin-font-caption); }
.notification-detail .body { padding-top: var(--admin-space-6); border-top: 1px solid var(--cc-border); color: var(--cc-text); white-space: pre-wrap; overflow-wrap: anywhere; line-height: 1.8; }
.message-heading { display: flex; align-items: flex-start; justify-content: space-between; gap: var(--admin-space-5); }
.message-heading > span { min-width: 0; overflow-wrap: anywhere; }
.message-body { white-space: pre-wrap; overflow-wrap: anywhere; }
</style>