445 lines
15 KiB
HTML
445 lines
15 KiB
HTML
<!--#
|
|
layout("/layouts/v4/baseLayout.html"){
|
|
#-->
|
|
|
|
<style>
|
|
.message-center {
|
|
padding: 20px;
|
|
}
|
|
|
|
.statistics-section {
|
|
margin-bottom: 20px;
|
|
}
|
|
|
|
.stat-card {
|
|
border: none;
|
|
height: 100%;
|
|
cursor: pointer;
|
|
transition: all 0.3s ease;
|
|
}
|
|
|
|
.stat-card .el-card__body {
|
|
padding: 20px;
|
|
}
|
|
|
|
.stat-content {
|
|
display: flex;
|
|
align-items: center;
|
|
}
|
|
|
|
.stat-icon {
|
|
width: 60px;
|
|
height: 60px;
|
|
border-radius: 50%;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
margin-right: 20px;
|
|
font-size: 28px;
|
|
}
|
|
|
|
.all-icon {
|
|
background-color: rgba(64, 158, 255, 0.1);
|
|
color: #409eff;
|
|
}
|
|
|
|
.unread-icon {
|
|
background-color: rgba(245, 108, 108, 0.1);
|
|
color: #f56c6c;
|
|
}
|
|
|
|
.read-icon {
|
|
background-color: rgba(103, 194, 58, 0.1);
|
|
color: #67c23a;
|
|
}
|
|
|
|
.stat-info {
|
|
flex: 1;
|
|
}
|
|
|
|
.stat-value {
|
|
font-size: 28px;
|
|
font-weight: 600;
|
|
line-height: 1.2;
|
|
margin-bottom: 5px;
|
|
}
|
|
|
|
.stat-label {
|
|
font-size: 14px;
|
|
color: #909399;
|
|
}
|
|
|
|
/* 搜索区域样式 */
|
|
.filter-section {
|
|
margin-bottom: 20px;
|
|
}
|
|
|
|
.filter-section .el-card__body {
|
|
padding: 15px 20px;
|
|
}
|
|
|
|
.search-form {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
}
|
|
|
|
.search-form .el-form-item {
|
|
margin-bottom: 0;
|
|
margin-right: 15px;
|
|
}
|
|
|
|
/* 消息列表区域样式 */
|
|
.message-section .el-card__header {
|
|
padding: 0;
|
|
border-bottom: none;
|
|
}
|
|
|
|
/* 优化后的 tabs 样式 */
|
|
.message-header .el-tabs__header {
|
|
margin: 0;
|
|
padding: 0 20px;
|
|
background-color: #fff;
|
|
}
|
|
|
|
.message-header .el-tabs__nav-wrap::after {
|
|
height: 1px;
|
|
background-color: #ebeef5;
|
|
}
|
|
|
|
.message-header .el-tabs__item {
|
|
height: 50px;
|
|
line-height: 50px;
|
|
font-size: 15px;
|
|
color: #606266;
|
|
padding: 0 20px;
|
|
transition: all 0.3s;
|
|
}
|
|
|
|
.message-header .el-tabs__item.is-active {
|
|
color: var(--color-primary);
|
|
font-weight: 500;
|
|
}
|
|
|
|
.message-header .el-tabs__active-bar {
|
|
height: 3px;
|
|
border-radius: 3px;
|
|
}
|
|
|
|
.message-title {
|
|
font-weight: 500;
|
|
color: #303133;
|
|
}
|
|
|
|
.pagination-container {
|
|
margin-top: 20px;
|
|
display: flex;
|
|
justify-content: center;
|
|
padding: 10px 0;
|
|
}
|
|
</style>
|
|
|
|
<div id="app" v-cloak>
|
|
<div class="message-center">
|
|
<!-- 统计数据区域 -->
|
|
<el-row :gutter="20" class="statistics-section">
|
|
<el-col :span="8">
|
|
<el-card shadow="never" class="stat-card">
|
|
<div class="stat-content">
|
|
<div class="stat-icon all-icon">
|
|
<i class="el-icon-message"></i>
|
|
</div>
|
|
<div class="stat-info">
|
|
<div class="stat-value">{{stats.total}}</div>
|
|
<div class="stat-label">全部消息</div>
|
|
</div>
|
|
</div>
|
|
</el-card>
|
|
</el-col>
|
|
<el-col :span="8">
|
|
<el-card shadow="never" class="stat-card">
|
|
<div class="stat-content">
|
|
<div class="stat-icon unread-icon">
|
|
<i class="el-icon-bell"></i>
|
|
</div>
|
|
<div class="stat-info">
|
|
<div class="stat-value">{{stats.unread}}</div>
|
|
<div class="stat-label">未读消息</div>
|
|
</div>
|
|
</div>
|
|
</el-card>
|
|
</el-col>
|
|
<el-col :span="8">
|
|
<el-card shadow="never" class="stat-card">
|
|
<div class="stat-content">
|
|
<div class="stat-icon read-icon">
|
|
<i class="el-icon-finished"></i>
|
|
</div>
|
|
<div class="stat-info">
|
|
<div class="stat-value">{{stats.read}}</div>
|
|
<div class="stat-label">已读消息</div>
|
|
</div>
|
|
</div>
|
|
</el-card>
|
|
</el-col>
|
|
</el-row>
|
|
|
|
<!-- 搜索筛选区域 -->
|
|
<el-card shadow="never" class="filter-section">
|
|
<el-form :inline="true" :model="filters" class="search-form">
|
|
<el-form-item>
|
|
<el-select v-model="filters.type" placeholder="消息类型" clearable @change="loadMessages"
|
|
style="width: 150px;">
|
|
<el-option label="全部类型" value=""></el-option>
|
|
<el-option label="系统公告" value="1"></el-option>
|
|
<el-option label="消息通知" value="2"></el-option>
|
|
</el-select>
|
|
</el-form-item>
|
|
<el-form-item v-if="pageForm.isRead == 0">
|
|
<el-button size="medium" type="primary" @click="markAllAsRead" :loading="loading">
|
|
<i class="el-icon-check"></i> 全部标记已读
|
|
</el-button>
|
|
</el-form-item>
|
|
</el-form>
|
|
</el-card>
|
|
|
|
<!-- 消息列表区域 -->
|
|
<el-card shadow="never" class="message-section">
|
|
<div slot="header" class="message-header">
|
|
<el-tabs v-model="pageForm.isRead" @tab-click="handleTabClick">
|
|
<el-tab-pane label="全部消息" name="-1">
|
|
<span slot="label">
|
|
<i class="el-icon-message"></i>
|
|
全部消息
|
|
</span>
|
|
</el-tab-pane>
|
|
<el-tab-pane label="未读消息" name="0">
|
|
<span slot="label">
|
|
<i class="el-icon-bell"></i>
|
|
未读消息
|
|
</span>
|
|
</el-tab-pane>
|
|
<el-tab-pane label="已读消息" name="1">
|
|
<span slot="label">
|
|
<i class="el-icon-finished"></i>
|
|
已读消息
|
|
</span>
|
|
</el-tab-pane>
|
|
</el-tabs>
|
|
</div>
|
|
|
|
<!-- 表格展示 -->
|
|
<el-table v-loading="loading" :data="messages" style="width: 100%" :key="currentTab"
|
|
empty-text="暂无消息"
|
|
:header-cell-style="{backgroundColor: '#f5f7fa'}">
|
|
<el-table-column prop="type" label="消息类型" width="120">
|
|
<template slot-scope="scope">
|
|
<el-tag size="mini" :type="scope.row.type === 1 ? 'danger' : 'primary'">
|
|
{{getMessageTypeName(scope.row.type)}}
|
|
</el-tag>
|
|
</template>
|
|
</el-table-column>
|
|
<el-table-column prop="title" label="标题" min-width="200" show-overflow-tooltip>
|
|
<template slot-scope="scope">
|
|
<span class="message-title">{{scope.row.title}}</span>
|
|
</template>
|
|
</el-table-column>
|
|
<el-table-column prop="content" label="内容预览" min-width="250" show-overflow-tooltip>
|
|
<template slot-scope="scope">
|
|
{{getContentPreview(scope.row.content)}}
|
|
</template>
|
|
</el-table-column>
|
|
<el-table-column prop="createdAt" label="接收时间" width="180">
|
|
<template slot-scope="scope">
|
|
{{formatTime(scope.row.createdAt)}}
|
|
</template>
|
|
</el-table-column>
|
|
<el-table-column prop="isRead" label="状态" width="100">
|
|
<template slot-scope="scope">
|
|
<el-tag size="mini" :type="scope.row.isRead ? 'success' : 'warning'">
|
|
{{scope.row.isRead ? '已读' : '未读'}}
|
|
</el-tag>
|
|
</template>
|
|
</el-table-column>
|
|
<el-table-column label="操作" width="100" fixed="right">
|
|
<template slot-scope="scope">
|
|
<el-button type="primary" size="mini" @click="viewMessage(scope.row)">查看</el-button>
|
|
</template>
|
|
</el-table-column>
|
|
</el-table>
|
|
|
|
<!-- 分页 -->
|
|
<div class="pagination-container" v-if="messages.length > 0">
|
|
<el-pagination
|
|
background
|
|
@current-change="handlePageChange"
|
|
:current-page="pageForm.pageNumber"
|
|
:page-size="pageForm.pageSize"
|
|
layout="prev, pager, next, jumper"
|
|
:total="pageForm.totalCount"
|
|
></el-pagination>
|
|
</div>
|
|
</el-card>
|
|
</div>
|
|
|
|
<!-- 消息详情弹窗 -->
|
|
<el-dialog
|
|
:visible.sync="detailVisible"
|
|
:title="currentMessage?.globalMessage?.title"
|
|
width="60%"
|
|
class="message-detail-dialog"
|
|
>
|
|
<div v-if="currentMessage.id">
|
|
<div style="text-align: center; margin-bottom: 20px; padding-bottom: 16px; border-bottom: 1px solid #eee;">
|
|
<div style="font-size: 18px; font-weight: 500; margin-bottom: 8px;">{{currentMessage.title}}</div>
|
|
<div style="font-size: 14px; color: #666;">
|
|
<span>{{getMessageTypeName(currentMessage?.globalMessage?.type)}}</span>
|
|
<span style="margin: 0 8px;">•</span>
|
|
<span>{{formatTime(currentMessage.createdAt)}}</span>
|
|
</div>
|
|
</div>
|
|
<div style="line-height: 1.8; font-size: 15px;" v-html="currentMessage?.globalMessage?.content"></div>
|
|
</div>
|
|
<span slot="footer" class="dialog-footer">
|
|
<el-button @click="detailVisible = false">关闭</el-button>
|
|
</span>
|
|
</el-dialog>
|
|
</div>
|
|
|
|
<script nonce="${cspNonce!}">
|
|
new Vue({
|
|
el: '#app',
|
|
data() {
|
|
return {
|
|
currentTab: 'all',
|
|
loading: false,
|
|
messages: [],
|
|
stats: {
|
|
total: 0,
|
|
unread: 0,
|
|
read: 0
|
|
},
|
|
filters: {
|
|
type: ''
|
|
},
|
|
pageForm: {
|
|
pageNumber: 1,
|
|
pageSize: 10,
|
|
totalCount: 0
|
|
},
|
|
detailVisible: false,
|
|
currentMessage: {}
|
|
}
|
|
},
|
|
methods: {
|
|
async loadStats() {
|
|
try {
|
|
const resp = await this.$axios.get('/platform/v4/msg/stats')
|
|
if (resp.code === 0) {
|
|
this.stats = resp.data
|
|
}
|
|
} catch (error) {
|
|
console.error('加载统计数据失败:', error)
|
|
}
|
|
},
|
|
|
|
async loadMessages() {
|
|
this.loading = true
|
|
try {
|
|
const resp = await this.$axios.post('/platform/v4/msg/pageData', this.pageForm)
|
|
if (resp.code === 0) {
|
|
this.messages = resp.data.list
|
|
this.pageForm.totalCount = resp.data.totalCount
|
|
} else {
|
|
this.$message.error(resp.msg)
|
|
}
|
|
} catch (error) {
|
|
this.$message.error('加载消息失败')
|
|
} finally {
|
|
this.loading = false
|
|
}
|
|
},
|
|
|
|
async viewMessage(message) {
|
|
this.$axios.post(`/platform/v4/msg/detail/` + message.id).then(async res => {
|
|
if (res.code === 0) {
|
|
this.currentMessage = res.data
|
|
this.detailVisible = true
|
|
// 如果是未读消息,标记为已读
|
|
if (!message.isRead) {
|
|
await this.markAsRead(message.id)
|
|
this.loadStats()
|
|
this.loadMessages()
|
|
}
|
|
}
|
|
})
|
|
},
|
|
|
|
async markAsRead(messageId) {
|
|
try {
|
|
await this.$axios.post(`/platform/v4/msg/read/` + messageId)
|
|
} catch (error) {
|
|
console.error('标记已读失败:', error)
|
|
}
|
|
},
|
|
|
|
async markAllAsRead() {
|
|
this.$confirm('确定要将所有未读消息标记为已读吗?', '提示', {
|
|
confirmButtonText: '确定',
|
|
cancelButtonText: '取消',
|
|
type: 'warning'
|
|
}).then(async () => {
|
|
this.loading = true
|
|
try {
|
|
const resp = await this.$axios.post('/platform/v4/msg/read/all')
|
|
if (resp.code === 0) {
|
|
this.$message.success('操作成功')
|
|
this.loadMessages()
|
|
this.loadStats()
|
|
} else {
|
|
this.$message.error(resp.msg)
|
|
}
|
|
} catch (error) {
|
|
this.$message.error('操作失败')
|
|
} finally {
|
|
this.loading = false
|
|
}
|
|
})
|
|
},
|
|
|
|
handleTabClick(tab) {
|
|
this.pageForm.pageNumber = 1
|
|
this.loadMessages()
|
|
},
|
|
|
|
handlePageChange(pageNumber) {
|
|
this.pageForm.pageNumber = pageNumber
|
|
this.loadMessages()
|
|
},
|
|
|
|
getMessageTypeName(type) {
|
|
return type === 1 ? '系统公告' : '消息通知'
|
|
},
|
|
|
|
getContentPreview(content) {
|
|
if (!content) return ''
|
|
// 移除HTML标签
|
|
const text = content.replace(/<[^>]*>/g, '')
|
|
return text.length > 50 ? text.substring(0, 50) + '...' : text
|
|
},
|
|
|
|
formatTime(timestamp) {
|
|
return this.$moment(timestamp).format('YYYY-MM-DD HH:mm')
|
|
}
|
|
},
|
|
|
|
created() {
|
|
this.loadStats()
|
|
this.loadMessages()
|
|
}
|
|
})
|
|
</script>
|
|
|
|
<!--#
|
|
}
|
|
#-->
|