190 lines
3.8 KiB
Vue
190 lines
3.8 KiB
Vue
<template>
|
|
<div class="content-section">
|
|
<div class="content-header">
|
|
<h2 class="content-title">我的消息</h2>
|
|
<p class="content-desc">查看系统消息和通知</p>
|
|
</div>
|
|
<div class="content-body">
|
|
<div v-if="messages.length === 0" class="empty-state">
|
|
<i class="fa-solid fa-message"></i>
|
|
<p>暂无消息</p>
|
|
</div>
|
|
<div v-else class="message-list">
|
|
<div
|
|
v-for="message in messages"
|
|
:key="message.id"
|
|
class="message-item"
|
|
:class="{ unread: !message.read }"
|
|
@click="markAsRead(message.id)"
|
|
>
|
|
<div class="message-icon">
|
|
<i :class="getMessageIcon(message.type)"></i>
|
|
</div>
|
|
<div class="message-content">
|
|
<div class="message-header">
|
|
<h4 class="message-title">{{ message.title }}</h4>
|
|
<span class="message-time">{{ message.time }}</span>
|
|
</div>
|
|
<p class="message-text">{{ message.content }}</p>
|
|
</div>
|
|
<div v-if="!message.read" class="unread-dot"></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script lang="ts" setup>
|
|
import { ref, onMounted } from "vue";
|
|
|
|
interface Message {
|
|
id: string;
|
|
title: string;
|
|
content: string;
|
|
time: string;
|
|
type: "system" | "notification" | "warning";
|
|
read: boolean;
|
|
}
|
|
|
|
// 模拟数据
|
|
const messages = ref<Message[]>([]);
|
|
|
|
// 获取消息图标
|
|
const getMessageIcon = (type: string) => {
|
|
switch (type) {
|
|
case "system":
|
|
return "fa-solid fa-cog";
|
|
case "notification":
|
|
return "fa-solid fa-bell";
|
|
case "warning":
|
|
return "fa-solid fa-exclamation-triangle";
|
|
default:
|
|
return "fa-solid fa-info";
|
|
}
|
|
};
|
|
|
|
// 标记为已读
|
|
const markAsRead = (messageId: string) => {
|
|
const message = messages.value.find((m) => m.id === messageId);
|
|
if (message) {
|
|
message.read = true;
|
|
}
|
|
};
|
|
|
|
// 初始化数据
|
|
const initMessages = () => {
|
|
// 这里可以调用API获取消息数据
|
|
messages.value = [];
|
|
};
|
|
|
|
onMounted(() => {
|
|
initMessages();
|
|
});
|
|
</script>
|
|
|
|
<style lang="less" scoped>
|
|
.message-list {
|
|
.message-item {
|
|
display: flex;
|
|
align-items: flex-start;
|
|
gap: 12px;
|
|
padding: 16px;
|
|
border: 1px solid #f0f0f0;
|
|
border-radius: 8px;
|
|
margin-bottom: 12px;
|
|
cursor: pointer;
|
|
transition: all 0.3s ease;
|
|
position: relative;
|
|
|
|
&:hover {
|
|
border-color: #1677ff;
|
|
background: #f8f9ff;
|
|
}
|
|
|
|
&.unread {
|
|
border-left: 4px solid #1677ff;
|
|
background: #f0f8ff;
|
|
}
|
|
|
|
.message-icon {
|
|
width: 40px;
|
|
height: 40px;
|
|
border-radius: 50%;
|
|
background: #1677ff;
|
|
color: white;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
flex-shrink: 0;
|
|
|
|
i {
|
|
font-size: 16px;
|
|
}
|
|
}
|
|
|
|
.message-content {
|
|
flex: 1;
|
|
|
|
.message-header {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: flex-start;
|
|
margin-bottom: 8px;
|
|
|
|
.message-title {
|
|
font-size: 16px;
|
|
color: #333;
|
|
margin: 0;
|
|
font-weight: 500;
|
|
}
|
|
|
|
.message-time {
|
|
font-size: 12px;
|
|
color: #999;
|
|
white-space: nowrap;
|
|
margin-left: 12px;
|
|
}
|
|
}
|
|
|
|
.message-text {
|
|
font-size: 14px;
|
|
color: #666;
|
|
margin: 0;
|
|
line-height: 1.5;
|
|
}
|
|
}
|
|
|
|
.unread-dot {
|
|
width: 8px;
|
|
height: 8px;
|
|
background: #1677ff;
|
|
border-radius: 50%;
|
|
position: absolute;
|
|
top: 16px;
|
|
right: 16px;
|
|
}
|
|
}
|
|
}
|
|
|
|
.empty-state {
|
|
text-align: center;
|
|
padding: 60px 20px;
|
|
color: #999;
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
justify-content: center;
|
|
|
|
i {
|
|
font-size: 48px;
|
|
margin-bottom: 16px;
|
|
display: block;
|
|
}
|
|
|
|
p {
|
|
font-size: 14px;
|
|
margin: 0;
|
|
}
|
|
}
|
|
</style>
|