440 lines
11 KiB
Vue
440 lines
11 KiB
Vue
<template>
|
|
<div class="message-center">
|
|
<div class="message-header">
|
|
|
|
<div class="header-tabs">
|
|
<div class="tabs-left">
|
|
<div
|
|
class="tab-item"
|
|
:class="{ active: activeTab === 'unread' }"
|
|
@click="activeTab = 'unread'"
|
|
>
|
|
未读
|
|
</div>
|
|
<div
|
|
class="tab-item"
|
|
:class="{ active: activeTab === 'read' }"
|
|
@click="activeTab = 'read'"
|
|
style="border:1px solid #dcdcdc"
|
|
>
|
|
已读
|
|
</div>
|
|
</div>
|
|
<el-button
|
|
v-if="activeTab === 'unread'"
|
|
type="primary"
|
|
size="small"
|
|
style="background-color: #5165f7; border: 1px solid #5165f7;"
|
|
@click="markAllAsRead"
|
|
>
|
|
全部设为已处理
|
|
</el-button>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="message-content">
|
|
<el-table
|
|
:data="messageList"
|
|
style="width: 100%"
|
|
border
|
|
v-loading="loading"
|
|
>
|
|
<el-table-column
|
|
type="index"
|
|
label="序号"
|
|
width="80"
|
|
align="center"
|
|
:index="getIndex">
|
|
</el-table-column>
|
|
<el-table-column
|
|
prop="title"
|
|
label="消息标题"
|
|
min-width="200">
|
|
</el-table-column>
|
|
<el-table-column
|
|
prop="content"
|
|
label="消息内容"
|
|
min-width="300">
|
|
</el-table-column>
|
|
<el-table-column
|
|
label="推送时间"
|
|
width="180"
|
|
align="center">
|
|
<template slot-scope="scope">
|
|
{{ scope.row.pushTime || scope.row.push_time || scope.row.create_time || '-' }}
|
|
</template>
|
|
</el-table-column>
|
|
<el-table-column
|
|
label="操作"
|
|
width="120"
|
|
align="center">
|
|
<template slot-scope="scope">
|
|
<el-button
|
|
type="text"
|
|
style="color: #5165f7;"
|
|
@click="handleMessage(scope.row)"
|
|
>
|
|
{{ activeTab === 'unread' ? '去处理' : '查看' }}
|
|
</el-button>
|
|
</template>
|
|
</el-table-column>
|
|
</el-table>
|
|
|
|
<!-- 分页 -->
|
|
<div class="pagination-wrapper">
|
|
<el-pagination
|
|
@size-change="handleSizeChange"
|
|
@current-change="handleCurrentChange"
|
|
:current-page="pagination.currentPage"
|
|
:page-sizes="[10, 20, 50, 100]"
|
|
:page-size="pagination.pageSize"
|
|
layout="total, sizes, prev, pager, next, jumper"
|
|
:total="pagination.total">
|
|
</el-pagination>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 消息详情对话框 -->
|
|
<el-dialog
|
|
title="消息详情"
|
|
:visible.sync="detailDialogVisible"
|
|
width="60%"
|
|
:close-on-click-modal="false"
|
|
class="message-detail-dialog">
|
|
<div class="detail-content" v-loading="detailLoading">
|
|
<div class="detail-card">
|
|
<div class="detail-item" v-if="messageDetail.title">
|
|
<div class="detail-label">
|
|
<i class="el-icon-document"></i>
|
|
<span>消息标题</span>
|
|
</div>
|
|
<div class="detail-value">{{ messageDetail.title }}</div>
|
|
</div>
|
|
<div class="detail-item" v-if="messageDetail.content">
|
|
<div class="detail-label">
|
|
<i class="el-icon-edit-outline"></i>
|
|
<span>消息内容</span>
|
|
</div>
|
|
<div class="detail-value content-text">{{ messageDetail.content }}</div>
|
|
</div>
|
|
<div class="detail-item" v-if="messageDetail.pushTime || messageDetail.push_time || messageDetail.create_time">
|
|
<div class="detail-label">
|
|
<i class="el-icon-time"></i>
|
|
<span>推送时间</span>
|
|
</div>
|
|
<div class="detail-value">{{ messageDetail.pushTime || messageDetail.push_time || messageDetail.create_time }}</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div slot="footer" class="dialog-footer">
|
|
<el-button type="primary" style="background-color: #5165f7;" @click="detailDialogVisible = false">关闭</el-button>
|
|
</div>
|
|
</el-dialog>
|
|
</div>
|
|
</template>
|
|
|
|
<script>
|
|
import {list,details,messagedo} from '@/api/system/message/index'
|
|
export default {
|
|
name: 'MessageCenter',
|
|
data() {
|
|
return {
|
|
activeTab: 'unread',
|
|
loading: false,
|
|
messageList: [],
|
|
pagination: {
|
|
currentPage: 1,
|
|
pageSize: 10,
|
|
total: 0
|
|
},
|
|
detailDialogVisible: false,
|
|
detailLoading: false,
|
|
messageDetail: {}
|
|
}
|
|
},
|
|
watch: {
|
|
activeTab() {
|
|
// 切换标签时重置分页
|
|
this.pagination.currentPage = 1
|
|
this.getMessageList()
|
|
}
|
|
},
|
|
mounted() {
|
|
this.getMessageList()
|
|
},
|
|
methods: {
|
|
async getMessageList() {
|
|
// 调用接口获取消息列表
|
|
this.loading = true
|
|
const params = {
|
|
page: this.pagination.currentPage,
|
|
limit: this.pagination.pageSize,
|
|
is_read: this.activeTab === 'unread' ? 2 : 1 // 1: 已读, 2: 未读
|
|
}
|
|
|
|
try {
|
|
const res = await list(params)
|
|
if (res && res.code === 1) {
|
|
// 根据接口返回的数据结构处理
|
|
if (res.data) {
|
|
// 如果返回的是分页对象
|
|
if (res.data.data){
|
|
this.messageList = res.data.data
|
|
this.pagination.total = res.data.total
|
|
} else if (Array.isArray(res.data)) {
|
|
// 如果直接返回数组
|
|
this.messageList = res.data
|
|
this.pagination.total = res.data.length
|
|
} else {
|
|
this.messageList = []
|
|
this.pagination.total = 0
|
|
}
|
|
} else {
|
|
this.messageList = []
|
|
this.pagination.total = 0
|
|
}
|
|
} else {
|
|
this.$message.error(res.msg || '获取消息列表失败')
|
|
this.messageList = []
|
|
this.pagination.total = 0
|
|
}
|
|
} catch (error) {
|
|
console.error('获取消息列表失败:', error)
|
|
this.messageList = []
|
|
this.pagination.total = 0
|
|
// 错误信息已在响应拦截器中处理
|
|
} finally {
|
|
this.loading = false
|
|
}
|
|
},
|
|
|
|
handleSizeChange(val) {
|
|
// 每页条数改变
|
|
this.pagination.pageSize = val
|
|
this.pagination.currentPage = 1
|
|
this.getMessageList()
|
|
},
|
|
|
|
handleCurrentChange(val) {
|
|
// 当前页改变
|
|
this.pagination.currentPage = val
|
|
this.getMessageList()
|
|
},
|
|
|
|
getIndex(index) {
|
|
// 计算序号,考虑分页
|
|
return (this.pagination.currentPage - 1) * this.pagination.pageSize + index + 1
|
|
},
|
|
async handleMessage(row) {
|
|
if (this.activeTab === 'unread') {
|
|
// 未读消息:去处理
|
|
console.log('处理消息:', row)
|
|
this.$message.info('跳转到处理页面')
|
|
} else {
|
|
// 已读消息:查看详情
|
|
this.detailDialogVisible = true
|
|
this.detailLoading = true
|
|
this.messageDetail = {}
|
|
|
|
try {
|
|
const messageId = row.id || row.message_id
|
|
if (!messageId) {
|
|
this.$message.error('消息ID不存在')
|
|
this.detailDialogVisible = false
|
|
return
|
|
}
|
|
|
|
const res = await details(messageId)
|
|
if (res && res.code === 1) {
|
|
this.messageDetail = res.data || {}
|
|
} else {
|
|
this.$message.error(res.msg || '获取消息详情失败')
|
|
this.detailDialogVisible = false
|
|
}
|
|
} catch (error) {
|
|
console.error('获取消息详情失败:', error)
|
|
this.$message.error('获取消息详情失败,请稍后重试')
|
|
this.detailDialogVisible = false
|
|
} finally {
|
|
this.detailLoading = false
|
|
}
|
|
}
|
|
},
|
|
async markAllAsRead() {
|
|
// 调用接口将所有消息标记为已读
|
|
this.$confirm('确认将所有消息标记为已处理吗?', '提示', {
|
|
confirmButtonText: '确定',
|
|
cancelButtonText: '取消',
|
|
type: 'warning'
|
|
}).then(async () => {
|
|
try {
|
|
const res = await messagedo({})
|
|
if (res && res.code === 1) {
|
|
this.$message.success(res.msg || '已全部标记为已处理')
|
|
this.activeTab = 'read'
|
|
this.getMessageList()
|
|
} else {
|
|
this.$message.error(res.msg || '操作失败')
|
|
}
|
|
} catch (error) {
|
|
console.error('标记消息为已处理失败:', error)
|
|
this.$message.error('操作失败,请稍后重试')
|
|
}
|
|
}).catch(() => {})
|
|
}
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<style scoped>
|
|
.message-center {
|
|
padding: 20px;
|
|
background: #fff;
|
|
min-height: calc(100vh - 90px);
|
|
}
|
|
|
|
.message-header {
|
|
margin-bottom: 20px;
|
|
}
|
|
|
|
.header-title {
|
|
font-size: 20px;
|
|
font-weight: 500;
|
|
color: #303133;
|
|
margin-bottom: 16px;
|
|
position: relative;
|
|
padding-bottom: 8px;
|
|
}
|
|
|
|
.header-title::after {
|
|
content: '';
|
|
position: absolute;
|
|
bottom: 0;
|
|
left: 0;
|
|
width: 60px;
|
|
height: 3px;
|
|
background: #5165f7;
|
|
}
|
|
|
|
.header-tabs {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
}
|
|
|
|
.tabs-left {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0;
|
|
}
|
|
|
|
.tab-item {
|
|
padding: 8px 20px;
|
|
font-size: 14px;
|
|
color: #606266;
|
|
cursor: pointer;
|
|
|
|
transition: all 0.3s;
|
|
}
|
|
|
|
.tab-item:hover {
|
|
color: #5165f7;
|
|
}
|
|
|
|
.tab-item.active {
|
|
background: #5165f7;
|
|
color: #fff;
|
|
}
|
|
|
|
.message-content {
|
|
background: #fff;
|
|
}
|
|
|
|
.pagination-wrapper {
|
|
margin-top: 20px;
|
|
display: flex;
|
|
justify-content: flex-end;
|
|
padding: 20px 0;
|
|
}
|
|
|
|
/* 消息详情对话框样式 */
|
|
.message-detail-dialog ::v-deep .el-dialog__header {
|
|
padding: 20px 20px 15px;
|
|
border-bottom: 1px solid #EBEEF5;
|
|
background: #F7F7FA;
|
|
text-align: center;
|
|
}
|
|
|
|
.message-detail-dialog ::v-deep .el-dialog__title {
|
|
font-size: 18px;
|
|
font-weight: 600;
|
|
color: #303133;
|
|
}
|
|
|
|
.message-detail-dialog ::v-deep .el-dialog__body {
|
|
padding: 30px;
|
|
background: #fafafa;
|
|
}
|
|
|
|
.detail-content {
|
|
min-height: 200px;
|
|
}
|
|
|
|
.detail-card {
|
|
background: #fff;
|
|
border-radius: 8px;
|
|
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.08);
|
|
overflow: hidden;
|
|
}
|
|
|
|
.detail-item {
|
|
display: flex;
|
|
align-items: flex-start;
|
|
padding: 20px 24px;
|
|
border-bottom: 1px solid #F0F0F0;
|
|
transition: background-color 0.3s;
|
|
}
|
|
|
|
.detail-item:last-child {
|
|
border-bottom: none;
|
|
}
|
|
|
|
.detail-item:hover {
|
|
background-color: #F9F9F9;
|
|
}
|
|
|
|
.detail-label {
|
|
display: flex;
|
|
align-items: center;
|
|
font-weight: 600;
|
|
color: #606266;
|
|
min-width: 140px;
|
|
margin-right: 20px;
|
|
font-size: 14px;
|
|
}
|
|
|
|
.detail-label i {
|
|
margin-right: 8px;
|
|
font-size: 16px;
|
|
color: #5165f7;
|
|
}
|
|
|
|
.detail-value {
|
|
flex: 1;
|
|
color: #303133;
|
|
word-break: break-word;
|
|
line-height: 1.6;
|
|
font-size: 14px;
|
|
}
|
|
|
|
.detail-value.content-text {
|
|
padding: 12px 16px;
|
|
background: #F7F7FA;
|
|
border-radius: 6px;
|
|
border-left: 3px solid #5165f7;
|
|
min-height: 60px;
|
|
white-space: pre-wrap;
|
|
}
|
|
</style>
|
|
|