Files
zhgh_zjvtit/target/classes/views/layouts/v4/msg.html
T
2026-08-26 14:25:17 +08:00

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>
<!--#
}
#-->