Files
----/src/views/message/index.vue
2025-12-03 09:30:19 +08:00

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>