first commit
This commit is contained in:
308
src/components/layout/NotificationPanel.vue
Normal file
308
src/components/layout/NotificationPanel.vue
Normal file
@@ -0,0 +1,308 @@
|
||||
<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>
|
||||
Reference in New Issue
Block a user