2025-10-20 09:50:15 +08:00

794 lines
22 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div class="message-center-wrapper">
<!-- 移动端通知弹框 -->
<el-drawer
:visible.sync="internalVisible"
v-if="isMobile"
direction="rtl"
:with-header="false"
size="90%"
class="drawerMobile"
:modal="true"
:modal-append-to-body="true"
:append-to-body="true"
@close="handleClose"
>
<el-container class="container">
<el-aside width="95px" class="aside">
<div class="header">消息中心</div>
<div class="title">
<div @click="tab(1)" :class="{ active: tab_index === 1 }" class="info">全部消息</div>
<div @click="tab(2)" :class="{ active: tab_index === 2 }" class="info">未读消息</div>
<div @click="tab(3)" :class="{ active: tab_index === 3 }" class="info">已读消息</div>
</div>
</el-aside>
<el-container class="content_box">
<el-header class="header">| {{ tabTitle }}</el-header>
<el-main class="content">
<!-- 全部信息 -->
<div v-if="tab_index == 1" class="allinfo">
<div class="button">
<el-button size="mini" type="primary" @click="readMassage">已读</el-button>
<el-button size="mini" type="danger" @click="delMessage">删除</el-button>
</div>
<el-table
:header-cell-style="rowClass"
@expand-change="expandChangeHandler"
ref="table"
@row-click="expandChangeHandler1"
class="table"
:row-class-name="rowStyle"
:data="alliInformationList ? alliInformationList : []"
height="680"
tooltip-effect="dark"
@selection-change="handleSelectionChange"
style="width: 100%"
>
<el-table-column type="expand" width="30px">
<template slot-scope="props">
<div class="msgtext">
{{ props.row.msgtext }}
</div>
</template>
</el-table-column>
<el-table-column type="selection" width="55"></el-table-column>
<el-table-column label="消息内容" prop="msgtype" :show-overflow-tooltip="true">
</el-table-column>
<el-table-column prop="sendtime" label="接收时间">
</el-table-column>
</el-table>
</div>
<!-- 未读信息 -->
<div v-if="tab_index == 2" class="noreadinfo">
<div class="button">
<el-button size="mini" type="primary" @click="readMassage">已读</el-button>
<el-button size="mini" type="danger" @click="delMessage">删除</el-button>
</div>
<el-table
:header-cell-style="rowClass"
@row-click="expandChangeHandler1"
class="table"
ref="table"
@expand-change="expandChangeHandler"
:row-class-name="rowStyle"
:data="unreadMessageList"
height="680"
tooltip-effect="dark"
@selection-change="handleSelectionChange"
style="width: 100%"
>
<el-table-column type="expand" width="30px">
<template slot-scope="props">
<div class="msgtext">
{{ props.row.msgtext }}
</div>
</template>
</el-table-column>
<el-table-column type="selection" width="55"></el-table-column>
<el-table-column label="消息内容" prop="msgtype" :show-overflow-tooltip="true">
</el-table-column>
<el-table-column prop="sendtime" label="接收时间">
</el-table-column>
</el-table>
</div>
<!-- 已读信息 -->
<div v-if="tab_index == 3" class="readinfo">
<div class="button">
<el-button size="mini" type="danger" @click="delMessage">删除</el-button>
</div>
<el-table
:header-cell-style="rowClass"
ref="table"
class="table"
@row-click="expandChangeHandler2"
@expand-change="expandChangeHandler"
@selection-change="handleSelectionChange"
:row-class-name="rowStyle"
:data="readInformationList"
height="680"
tooltip-effect="dark"
style="width: 100%"
>
<el-table-column type="expand" width="30px">
<template slot-scope="props">
<div class="msgtext">
{{ props.row.msgtext }}
</div>
</template>
</el-table-column>
<el-table-column type="selection" width="55"></el-table-column>
<el-table-column label="消息内容" prop="msgtype" :show-overflow-tooltip="true">
</el-table-column>
<el-table-column prop="sendtime" label="接收时间">
</el-table-column>
</el-table>
</div>
</el-main>
</el-container>
</el-container>
</el-drawer>
<!-- 桌面端通知弹框 -->
<el-drawer
:visible.sync="internalVisible"
v-else
direction="rtl"
:with-header="false"
size="70%"
class="drawer"
:modal="true"
:modal-append-to-body="true"
:append-to-body="true"
@close="handleClose"
>
<el-container style="height: 100vh">
<el-aside width="200px" class="aside">
<div class="header" style="font-size:16px;">消息中心</div>
<div class="title">
<div @click="tab(1)" :class="{ active: tab_index === 1 }" style="font-size:16px;">全部消息</div>
<div @click="tab(2)" :class="{ active: tab_index === 2 }" style="font-size:16px;">未读消息</div>
<div @click="tab(3)" :class="{ active: tab_index === 3 }" style="font-size:16px;">已读消息</div>
</div>
</el-aside>
<el-container class="content_box">
<el-header class="header">| {{ tabTitle }}</el-header>
<el-main class="content">
<!-- 全部信息 -->
<div v-if="tab_index == 1">
<div class="button" style="display:flex;">
<el-button size="small" type="primary" @click="readMassage">已读</el-button>
<el-button size="small" type="danger" @click="delMessage">删除</el-button>
</div>
<el-table
@expand-change="expandChangeHandler"
ref="table"
@row-click="expandChangeHandler1"
class="table"
:row-class-name="rowStyle"
:data="alliInformationList ? alliInformationList : []"
height="780"
tooltip-effect="dark"
style="width: 100%"
@selection-change="handleSelectionChange"
>
<el-table-column type="expand" width="30px">
<template slot-scope="props">
<div class="msgtext">
{{ props.row.msgtext }}
</div>
</template>
</el-table-column>
<el-table-column type="selection" width="55"></el-table-column>
<el-table-column label="消息内容" prop="msgtype" :show-overflow-tooltip="true">
</el-table-column>
<el-table-column prop="sendtime" label="接收时间">
</el-table-column>
</el-table>
</div>
<!-- 未读信息 -->
<div v-if="tab_index == 2">
<div class="button" style="display:flex;">
<el-button size="small" type="primary" @click="readMassage">已读</el-button>
<el-button size="small" type="danger" @click="delMessage">删除</el-button>
</div>
<el-table
@row-click="expandChangeHandler1"
ref="table"
@expand-change="expandChangeHandler"
:row-class-name="rowStyle"
:data="unreadMessageList"
height="780"
tooltip-effect="dark"
style="width: 100%"
@selection-change="handleSelectionChange"
>
<el-table-column type="expand" width="30px">
<template slot-scope="props">
<div class="msgtext">
{{ props.row.msgtext }}
</div>
</template>
</el-table-column>
<el-table-column type="selection" width="55"></el-table-column>
<el-table-column label="消息内容" prop="msgtype" :show-overflow-tooltip="true">
</el-table-column>
<el-table-column prop="sendtime" label="接收时间">
</el-table-column>
</el-table>
</div>
<!-- 已读信息 -->
<div v-if="tab_index == 3">
<div class="button" style="display:flex;">
<el-button size="small" type="danger" @click="delMessage">删除</el-button>
</div>
<el-table
ref="table"
@row-click="expandChangeHandler2"
@expand-change="expandChangeHandler"
@selection-change="handleSelectionChange"
:row-class-name="rowStyle"
:data="readInformationList"
height="780"
tooltip-effect="dark"
style="width: 100%"
>
<el-table-column type="expand" width="30px">
<template slot-scope="props">
<div class="msgtext">
{{ props.row.msgtext }}
</div>
</template>
</el-table-column>
<el-table-column type="selection" width="55"></el-table-column>
<el-table-column label="消息内容" prop="msgtype" :show-overflow-tooltip="true">
</el-table-column>
<el-table-column prop="sendtime" label="接收时间">
</el-table-column>
</el-table>
</div>
</el-main>
</el-container>
</el-container>
</el-drawer>
</div>
</template>
<script>
import {
getUnreadmsgAPI,
getMsgAPI,
getReadmsgAPI,
upMsgAPI,
delMsgAPI
} from "@/api/login";
export default {
name: 'MessageCenter',
props: {
userId: {
type: [String, Number],
required: false,
default: null
},
visible: {
type: Boolean,
default: false
}
},
data() {
return {
isMobile: false,
alliInformationList: [], //全部消息
unreadMessageList: [], //未读信息
readInformationList: [], //已读信息
readIdList: [],
count: 0,
internalVisible: false, // 内部控制的显示状态
tabTitle: "消息中心",
tab_index: 1,
isUpdate: false,
oneId: '',
isOne: false,
originalBodyOverflow: '' // 保存原始body overflow样式
};
},
watch: {
// 监听父组件传来的visible属性
visible: {
immediate: true,
handler(newVal) {
console.log('MessageCenter visible changed:', newVal);
this.internalVisible = newVal;
if (newVal) {
this.getMsg();
this.preventBodyScroll();
} else {
this.restoreBodyScroll();
}
}
},
// 监听内部visible状态同步到父组件
internalVisible(newVal) {
if (newVal !== this.visible) {
this.$emit('update:visible', newVal);
}
if (!newVal) {
this.getUnreadmsg();
this.restoreBodyScroll();
}
}
},
mounted() {
// 检测是否为移动设备
this.checkMobile();
this.getUnreadmsg();
},
beforeDestroy() {
// 组件销毁时恢复body滚动
this.restoreBodyScroll();
},
methods: {
// 检测移动设备
checkMobile() {
const userAgent = window.navigator.userAgent;
this.isMobile = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(userAgent);
console.log('Is mobile device:', this.isMobile);
},
// 阻止body滚动
preventBodyScroll() {
this.originalBodyOverflow = document.body.style.overflow;
document.body.style.overflow = 'hidden';
},
// 恢复body滚动
restoreBodyScroll() {
document.body.style.overflow = this.originalBodyOverflow || '';
},
// 打开消息中心
open() {
console.log('MessageCenter open method called');
this.internalVisible = true;
this.getMsg();
this.preventBodyScroll();
},
// 关闭消息中心
close() {
console.log('MessageCenter close method called');
this.internalVisible = false;
this.restoreBodyScroll();
},
// 处理抽屉关闭事件
handleClose() {
console.log('MessageCenter handleClose called');
this.close();
},
rowClass() {
return "font-size:14px;";
},
getUnreadmsg() {
// 检查用户是否登录
const userId = sessionStorage.getItem('userId');
if (!userId) {
console.log('用户未登录,跳过获取未读消息');
return;
}
getUnreadmsgAPI().then(res => {
if (res.status) {
this.count = res.count;
this.unreadMessageList = res.messages;
// 触发未读消息数量更新事件
this.$emit('unread-count-update', res.count);
} else {
this.$message({
message: res.msg,
type: "error",
});
}
}).catch(error => {
console.error('获取未读消息失败:', error);
// 401错误不显示错误消息因为用户未登录是正常情况
if (error.response && error.response.status !== 401) {
this.$message({
message: "获取未读消息失败",
type: "error",
});
}
});
},
getReadmsg() {
// 检查用户是否登录
const userId = sessionStorage.getItem('userId');
if (!userId) {
console.log('用户未登录,跳过获取已读消息');
return;
}
getReadmsgAPI().then(res => {
if (res.status) {
this.readInformationList = res.msg;
} else {
this.$message({
message: res.msg,
type: "error",
});
}
}).catch(error => {
console.error('获取已读消息失败:', error);
this.$message({
message: "获取已读消息失败",
type: "error",
});
});
},
rowStyle({ row, rowIndex }) {
if (this.isOne == true && row.id == this.oneId) {
return 'unReadColor';
} else if (row.msgstatus == 1) {
return 'unReadColor';
}
return '';
},
handleSelectionChange(selection) {
if (selection) {
this.readIdList = [];
selection.forEach(item => {
this.readIdList.push(item.id);
});
console.log('Selected messages:', this.readIdList);
}
},
getMsg() {
// 检查用户是否登录
const userId = sessionStorage.getItem('userId');
if (!userId) {
console.log('用户未登录,跳过获取消息');
return;
}
getMsgAPI({ userid: userId }).then(res => {
if (res.status && res.msg) {
this.alliInformationList = res.msg;
} else {
this.$message({
message: res.msg || "获取消息失败",
type: "error",
});
}
}).catch(error => {
console.error('获取消息失败:', error);
this.$message({
message: "获取消息失败",
type: "error",
});
});
},
readMassage() {
this.isUpdate = true;
if (this.readIdList.length) {
this.upMsg(this.readIdList);
} else {
this.$message({
message: "请选择要标记为已读的消息",
type: "warning",
});
}
},
upMsg(data) {
let params = {
msgids: data
};
upMsgAPI(params).then(res => {
if (res.status) {
this.$message({
message: "一键已读成功",
type: "success",
});
if (this.tab_index == 1) {
this.getMsg();
} else if (this.tab_index == 2) {
this.getUnreadmsg();
}
// 更新未读消息计数
this.getUnreadmsg();
} else {
this.$message({
message: res.msg,
type: "error",
});
}
}).catch(error => {
console.error('标记已读失败:', error);
this.$message({
message: "标记已读失败",
type: "error",
});
});
},
delMsg(data) {
let params = {
id: data
};
delMsgAPI(params).then(res => {
if (res.status) {
this.$message({
message: "删除成功",
type: "success",
});
if (this.tab_index == 1) {
this.getMsg();
} else if (this.tab_index == 2) {
this.getUnreadmsg();
} else if (this.tab_index == 3) {
this.getReadmsg();
}
// 更新未读消息计数
this.getUnreadmsg();
} else {
this.$message({
message: res.msg,
type: "error",
});
}
}).catch(error => {
console.error('删除消息失败:', error);
this.$message({
message: "删除消息失败",
type: "error",
});
});
},
delMessage() {
if (this.readIdList.length) {
this.$confirm('确定要删除选中的消息吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
this.delMsg(this.readIdList);
}).catch(() => {
// 用户取消删除
});
} else {
this.$message({
message: "请选择要删除的消息",
type: "warning",
});
}
},
expandChangeHandler(row) {
this.isOne = true;
this.oneId = row.id;
let params = {
msgids: [row.id]
};
upMsgAPI(params).then(res => {
if (res.status) {
this.rowStyle(row);
// 更新未读消息计数
this.getUnreadmsg();
} else {
this.$message({
message: res.msg,
type: "error",
});
}
}).catch(error => {
console.error('标记消息已读失败:', error);
});
},
expandChangeHandler1(row) {
this.isUpdate = true;
if (this.$refs.table) {
this.$refs.table.toggleRowExpansion(row);
}
this.expandChangeHandler(row);
},
expandChangeHandler2(row) {
if (this.$refs.table) {
this.$refs.table.toggleRowExpansion(row);
}
},
tab(i) {
this.tab_index = i;
if (i == 1) {
this.tabTitle = "全部消息";
this.getMsg();
} else if (i == 2) {
this.tabTitle = "未读消息";
this.getUnreadmsg();
} else {
this.tabTitle = "已读消息";
this.getReadmsg();
}
}
}
};
</script>
<style scoped lang="scss">
.message-center-wrapper {
position: relative;
z-index: 10000;
}
.drawer, .drawerMobile {
z-index: 10001 !important;
::v-deep .el-drawer {
z-index: 10002 !important;
}
::v-deep .el-drawer__wrapper {
z-index: 10001 !important;
}
::v-deep .el-drawer__container {
z-index: 10001 !important;
}
::v-deep .el-drawer__header {
margin-bottom: 0;
}
}
.aside {
padding: 0;
margin: 0;
background-color: #f5f7fa;
.header {
padding-left: 20px;
height: 60px;
line-height: 60px;
font-weight: 600;
background-color: #d9dee4;
border-bottom: 1px solid #e6e6e6;
}
.title div {
padding-left: 35px;
height: 50px;
line-height: 50px;
cursor: pointer;
transition: background-color 0.3s;
&:hover {
background-color: #ebedf0;
}
&.active {
background-color: #e1e5eb;
color: #409eff;
font-weight: bold;
}
}
}
.content_box {
background-color: #fff;
padding: 0 10px;
.header {
font-size: 22px;
line-height: 60px;
border-bottom: 1px solid #e6e6e6;
font-weight: bold;
color: #333;
}
.msgtext {
padding: 15px;
background-color: #f9f9f9;
border-radius: 4px;
line-height: 1.6;
color: #666;
}
.button {
padding-bottom: 15px;
border-bottom: 1px solid #e6e6e6;
margin-bottom: 15px;
}
}
/* 表格样式优化 */
::v-deep .el-table {
.el-table__row {
cursor: pointer;
&:hover {
background-color: #f5f7fa !important;
}
}
.el-table__expanded-cell {
padding: 10px !important;
}
}
/* 移动端样式优化 */
.drawerMobile {
.container {
height: 100vh;
.aside {
.header {
font-size: 14px;
}
.title {
.info {
font-size: 12px;
padding-left: 20px;
}
}
}
.content_box {
.header {
font-size: 16px;
}
.content {
.allinfo, .readinfo, .noreadinfo {
.button {
display: flex;
flex-wrap: wrap;
gap: 8px;
}
.table {
width: 100%;
}
}
}
}
}
}
/* 响应式调整 */
@media (max-width: 768px) {
.drawerMobile {
::v-deep .el-drawer {
width: 90% !important;
}
}
}
/* 确保所有交互元素可点击 */
::v-deep .el-button {
cursor: pointer !important;
}
::v-deep .el-table__row {
cursor: pointer !important;
}
::v-deep .el-drawer__body {
overflow: auto;
}
</style>