309 lines
5.5 KiB
Vue
309 lines
5.5 KiB
Vue
<template>
|
|
<el-drawer
|
|
:model-value="visible"
|
|
:title="title"
|
|
direction="rtl"
|
|
size="400px"
|
|
:with-header="true"
|
|
@close="handleClose"
|
|
@update:model-value="(val) => emit('update:visible', val)"
|
|
class="notification-drawer"
|
|
>
|
|
<div class="notification-container">
|
|
<div class="notification-content">
|
|
<el-empty
|
|
v-if="appStore.notifications.length === 0"
|
|
description="暂无通知"
|
|
class="empty-notification"
|
|
/>
|
|
<div v-else class="notification-list">
|
|
<div
|
|
v-for="notification in appStore.notifications"
|
|
:key="notification.id"
|
|
class="notification-item"
|
|
>
|
|
<div class="notification-icon">
|
|
<div class="icon-container" :class="themeClass">
|
|
<el-icon class="notification-icon-svg">
|
|
<Info />
|
|
</el-icon>
|
|
</div>
|
|
</div>
|
|
<div class="notification-body">
|
|
<h4 class="notification-title">{{ notification.title }}</h4>
|
|
<p class="notification-message">{{ notification.message }}</p>
|
|
<p class="notification-time">
|
|
{{ formatDate(notification.timestamp, 'MM-DD HH:mm') }}
|
|
</p>
|
|
</div>
|
|
<div class="notification-actions">
|
|
<el-button
|
|
@click="appStore.removeNotification(notification.id)"
|
|
:icon="Close"
|
|
circle
|
|
text
|
|
size="small"
|
|
class="close-button"
|
|
/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</el-drawer>
|
|
</template>
|
|
|
|
<script setup>
|
|
import { useAppStore } from '@/stores/app'
|
|
import { formatDate } from '@/utils'
|
|
import { XMarkIcon as Close, InformationCircleIcon as Info } from '@heroicons/vue/24/outline'
|
|
|
|
const props = defineProps({
|
|
visible: {
|
|
type: Boolean,
|
|
required: true
|
|
},
|
|
title: {
|
|
type: String,
|
|
default: '通知'
|
|
},
|
|
theme: {
|
|
type: String,
|
|
default: 'user', // 'user' | 'admin'
|
|
validator: (value) => ['user', 'admin'].includes(value)
|
|
}
|
|
})
|
|
|
|
const emit = defineEmits(['update:visible'])
|
|
|
|
const appStore = useAppStore()
|
|
|
|
// 主题样式类
|
|
const themeClass = computed(() => {
|
|
return props.theme === 'admin' ? 'admin-theme' : 'user-theme'
|
|
})
|
|
|
|
const handleClose = () => {
|
|
emit('update:visible', false)
|
|
}
|
|
</script>
|
|
|
|
<style scoped>
|
|
.notification-drawer {
|
|
--el-drawer-bg-color: #fff;
|
|
}
|
|
|
|
.notification-container {
|
|
height: 100%;
|
|
display: flex;
|
|
flex-direction: column;
|
|
}
|
|
|
|
.notification-content {
|
|
flex: 1;
|
|
overflow-y: auto;
|
|
padding: 0;
|
|
}
|
|
|
|
.empty-notification {
|
|
padding: 40px 20px;
|
|
}
|
|
|
|
.notification-list {
|
|
padding: 16px;
|
|
}
|
|
|
|
.notification-item {
|
|
display: flex;
|
|
align-items: flex-start;
|
|
gap: 12px;
|
|
padding: 16px;
|
|
margin-bottom: 12px;
|
|
background: #f8f9fa;
|
|
border-radius: 8px;
|
|
border: 1px solid #e9ecef;
|
|
transition: all 0.2s ease;
|
|
}
|
|
|
|
.notification-item:hover {
|
|
background: #f1f3f4;
|
|
border-color: #dee2e6;
|
|
}
|
|
|
|
.notification-icon {
|
|
flex-shrink: 0;
|
|
}
|
|
|
|
.icon-container {
|
|
width: 40px;
|
|
height: 40px;
|
|
border-radius: 50%;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
}
|
|
|
|
.icon-container.user-theme {
|
|
background-color: #e3f2fd;
|
|
}
|
|
|
|
.icon-container.admin-theme {
|
|
background-color: #ffebee;
|
|
}
|
|
|
|
.notification-icon-svg {
|
|
font-size: 20px;
|
|
}
|
|
|
|
.user-theme .notification-icon-svg {
|
|
color: #1976d2;
|
|
}
|
|
|
|
.admin-theme .notification-icon-svg {
|
|
color: #d32f2f;
|
|
}
|
|
|
|
.notification-body {
|
|
flex: 1;
|
|
min-width: 0;
|
|
}
|
|
|
|
.notification-title {
|
|
font-size: 14px;
|
|
font-weight: 600;
|
|
color: #212529;
|
|
margin: 0 0 4px 0;
|
|
line-height: 1.4;
|
|
}
|
|
|
|
.notification-message {
|
|
font-size: 13px;
|
|
color: #6c757d;
|
|
margin: 0 0 8px 0;
|
|
line-height: 1.4;
|
|
}
|
|
|
|
.notification-time {
|
|
font-size: 11px;
|
|
color: #adb5bd;
|
|
margin: 0;
|
|
line-height: 1;
|
|
}
|
|
|
|
.notification-actions {
|
|
flex-shrink: 0;
|
|
}
|
|
|
|
.close-button {
|
|
color: #adb5bd;
|
|
transition: color 0.2s;
|
|
}
|
|
|
|
.close-button:hover {
|
|
color: #6c757d;
|
|
}
|
|
|
|
/* 响应式设计 */
|
|
@media (max-width: 768px) {
|
|
.notification-list {
|
|
padding: 12px;
|
|
}
|
|
|
|
.notification-item {
|
|
padding: 12px;
|
|
margin-bottom: 8px;
|
|
}
|
|
|
|
.icon-container {
|
|
width: 32px;
|
|
height: 32px;
|
|
}
|
|
|
|
.notification-icon-svg {
|
|
font-size: 16px;
|
|
}
|
|
|
|
.notification-title {
|
|
font-size: 13px;
|
|
}
|
|
|
|
.notification-message {
|
|
font-size: 12px;
|
|
}
|
|
|
|
.notification-time {
|
|
font-size: 10px;
|
|
}
|
|
}
|
|
|
|
@media (max-width: 480px) {
|
|
.notification-list {
|
|
padding: 8px;
|
|
}
|
|
|
|
.notification-item {
|
|
padding: 10px;
|
|
margin-bottom: 6px;
|
|
gap: 8px;
|
|
}
|
|
|
|
.icon-container {
|
|
width: 28px;
|
|
height: 28px;
|
|
}
|
|
|
|
.notification-icon-svg {
|
|
font-size: 14px;
|
|
}
|
|
|
|
.notification-title {
|
|
font-size: 12px;
|
|
}
|
|
|
|
.notification-message {
|
|
font-size: 11px;
|
|
}
|
|
|
|
.notification-time {
|
|
font-size: 9px;
|
|
}
|
|
}
|
|
|
|
/* Element Plus Drawer 样式覆盖 */
|
|
:deep(.el-drawer__header) {
|
|
padding: 16px 20px;
|
|
border-bottom: 1px solid #e4e7ed;
|
|
margin-bottom: 0;
|
|
}
|
|
|
|
:deep(.el-drawer__title) {
|
|
font-size: 16px;
|
|
font-weight: 600;
|
|
color: #303133;
|
|
}
|
|
|
|
:deep(.el-drawer__body) {
|
|
padding: 0;
|
|
height: calc(100% - 60px);
|
|
}
|
|
|
|
/* 滚动条样式 */
|
|
.notification-content::-webkit-scrollbar {
|
|
width: 6px;
|
|
}
|
|
|
|
.notification-content::-webkit-scrollbar-track {
|
|
background: #f1f1f1;
|
|
border-radius: 3px;
|
|
}
|
|
|
|
.notification-content::-webkit-scrollbar-thumb {
|
|
background: #c1c1c1;
|
|
border-radius: 3px;
|
|
}
|
|
|
|
.notification-content::-webkit-scrollbar-thumb:hover {
|
|
background: #a8a8a8;
|
|
}
|
|
</style>
|