|
@@ -111,8 +111,9 @@
|
|
|
全局用户自见
|
|
全局用户自见
|
|
|
</label>
|
|
</label>
|
|
|
</div>
|
|
</div>
|
|
|
- <el-scrollbar class="custom-scrollbar" style="height: 500px; width: 100%;" ref="manageRightRef">
|
|
|
|
|
- <el-row v-for="m in msgList" :key="m.msgId">
|
|
|
|
|
|
|
+ <div class="message-container" @click="handleMessageBoxClick">
|
|
|
|
|
+ <el-scrollbar class="custom-scrollbar" style="height: 500px; width: 100%;" ref="manageRightRef">
|
|
|
|
|
+ <el-row v-for="m in msgList" :key="m.msgId">
|
|
|
<el-row v-if="m.userId === userId && m.msgId == null" style="padding: 8px 0" type="flex" align="top" justify="end">
|
|
<el-row v-if="m.userId === userId && m.msgId == null" style="padding: 8px 0" type="flex" align="top" justify="end">
|
|
|
<div style="display: flex;justify-content: flex-end">
|
|
<div style="display: flex;justify-content: flex-end">
|
|
|
<div style="display: flex;justify-content: flex-end;flex-direction: column;max-width: 200px;align-items: flex-end">
|
|
<div style="display: flex;justify-content: flex-end;flex-direction: column;max-width: 200px;align-items: flex-end">
|
|
@@ -133,11 +134,11 @@
|
|
|
</div>
|
|
</div>
|
|
|
</el-col>
|
|
</el-col>
|
|
|
<el-col>
|
|
<el-col>
|
|
|
- <a style="cursor: pointer;color: #ff0000;padding: 8px 8px 0 0;font-size: 12px;" @click="changeUserState(m)">{{ m.msgStatus === 1 ? '解禁' : '禁言' }}</a>
|
|
|
|
|
- <a style="cursor: pointer;color: #ff0000;padding: 8px 8px 0 0;font-size: 12px;" @click="blockUser(m)">拉黑</a>
|
|
|
|
|
- <a v-if="m.singleVisible === 1" style="cursor: pointer;color: #ff0000;padding: 8px 8px 0 0;font-size: 12px;" @click="singleVisible(m)">解除用户自见</a>
|
|
|
|
|
- <a v-else style="cursor: pointer;color: #ff0000;padding: 8px 8px 0 0;font-size: 12px;" @click="singleVisible(m)">用户自见</a>
|
|
|
|
|
- <a style="cursor: pointer;color: #ff0000;padding: 8px 8px 0 0;font-size: 12px;" @click="deleteMsg(m)">删除</a>
|
|
|
|
|
|
|
+ <a style="cursor: pointer;color: #ff0000;padding: 8px 8px 0 0;font-size: 12px;" @click.stop="changeUserState(m)">{{ m.msgStatus === 1 ? '解禁' : '禁言' }}</a>
|
|
|
|
|
+ <a style="cursor: pointer;color: #ff0000;padding: 8px 8px 0 0;font-size: 12px;" @click.stop="blockUser(m)">拉黑</a>
|
|
|
|
|
+ <a v-if="m.singleVisible === 1" style="cursor: pointer;color: #ff0000;padding: 8px 8px 0 0;font-size: 12px;" @click.stop="singleVisible(m)">解除用户自见</a>
|
|
|
|
|
+ <a v-else style="cursor: pointer;color: #ff0000;padding: 8px 8px 0 0;font-size: 12px;" @click.stop="singleVisible(m)">用户自见</a>
|
|
|
|
|
+ <a style="cursor: pointer;color: #ff0000;padding: 8px 8px 0 0;font-size: 12px;" @click.stop="deleteMsg(m)">删除</a>
|
|
|
</el-col>
|
|
</el-col>
|
|
|
</el-row>
|
|
</el-row>
|
|
|
</el-col>
|
|
</el-col>
|
|
@@ -146,7 +147,18 @@
|
|
|
</el-row>
|
|
</el-row>
|
|
|
<!-- 底部留白 -->
|
|
<!-- 底部留白 -->
|
|
|
<div style="height: 20px;"></div>
|
|
<div style="height: 20px;"></div>
|
|
|
- </el-scrollbar>
|
|
|
|
|
|
|
+ </el-scrollbar>
|
|
|
|
|
+ <!-- 加载最新消息按钮 -->
|
|
|
|
|
+ <el-button
|
|
|
|
|
+ v-if="showLoadLatestBtn"
|
|
|
|
|
+ class="load-latest-btn"
|
|
|
|
|
+ type="primary"
|
|
|
|
|
+ size="small"
|
|
|
|
|
+ @click.stop="loadLatestMessages"
|
|
|
|
|
+ icon="el-icon-refresh">
|
|
|
|
|
+ 加载最新消息
|
|
|
|
|
+ </el-button>
|
|
|
|
|
+ </div>
|
|
|
<!-- <div class="message-list">-->
|
|
<!-- <div class="message-list">-->
|
|
|
<!-- <div class="message-item" v-for="msg in msgList" :key="msg.id">-->
|
|
<!-- <div class="message-item" v-for="msg in msgList" :key="msg.id">-->
|
|
|
<!-- <div class="message-avatar">-->
|
|
<!-- <div class="message-avatar">-->
|
|
@@ -391,6 +403,15 @@ export default {
|
|
|
topMsgForm: {
|
|
topMsgForm: {
|
|
|
msg: '',
|
|
msg: '',
|
|
|
duration: 5
|
|
duration: 5
|
|
|
|
|
+ },
|
|
|
|
|
+ // 消息滚动控制
|
|
|
|
|
+ isAutoScrollEnabled: true, // 是否启用自动滚动
|
|
|
|
|
+ autoScrollTimer: null, // 自动滚动定时器
|
|
|
|
|
+ showLoadLatestBtn: false, // 是否显示加载最新消息按钮
|
|
|
|
|
+ msgParams: {
|
|
|
|
|
+ pageNum: 1,
|
|
|
|
|
+ pageSize: 30,
|
|
|
|
|
+ liveId: null
|
|
|
}
|
|
}
|
|
|
};
|
|
};
|
|
|
},
|
|
},
|
|
@@ -432,6 +453,65 @@ export default {
|
|
|
this.initScrollListeners();
|
|
this.initScrollListeners();
|
|
|
},
|
|
},
|
|
|
methods: {
|
|
methods: {
|
|
|
|
|
+ // 点击消息框
|
|
|
|
|
+ handleMessageBoxClick() {
|
|
|
|
|
+ // 点击消息框时,停止自动滚动
|
|
|
|
|
+ this.isAutoScrollEnabled = false;
|
|
|
|
|
+ // 停止自动滚动定时器
|
|
|
|
|
+ if (this.autoScrollTimer) {
|
|
|
|
|
+ clearTimeout(this.autoScrollTimer);
|
|
|
|
|
+ this.autoScrollTimer = null;
|
|
|
|
|
+ }
|
|
|
|
|
+ // 检查是否在底部,如果不在底部则显示加载最新消息按钮
|
|
|
|
|
+ this.$nextTick(() => {
|
|
|
|
|
+ if (this.$refs.manageRightRef && this.$refs.manageRightRef.wrap) {
|
|
|
|
|
+ const wrap = this.$refs.manageRightRef.wrap;
|
|
|
|
|
+ const scrollHeight = wrap.scrollHeight;
|
|
|
|
|
+ const clientHeight = wrap.clientHeight;
|
|
|
|
|
+ const currentScrollTop = wrap.scrollTop;
|
|
|
|
|
+ const maxScrollTop = scrollHeight - clientHeight;
|
|
|
|
|
+
|
|
|
|
|
+ if (currentScrollTop < maxScrollTop - 50) {
|
|
|
|
|
+ this.showLoadLatestBtn = true;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ });
|
|
|
|
|
+ },
|
|
|
|
|
+ // 滚动到底部
|
|
|
|
|
+ scrollToBottom(forceScroll = false) {
|
|
|
|
|
+ // 如果自动滚动被禁用且不是强制滚动,则不执行
|
|
|
|
|
+ if (!this.isAutoScrollEnabled && !forceScroll) {
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (this.$refs.manageRightRef && this.$refs.manageRightRef.wrap) {
|
|
|
|
|
+ this.$nextTick(() => {
|
|
|
|
|
+ const wrap = this.$refs.manageRightRef.wrap;
|
|
|
|
|
+ if (!wrap) return;
|
|
|
|
|
+
|
|
|
|
|
+ const scrollHeight = wrap.scrollHeight;
|
|
|
|
|
+ const clientHeight = wrap.clientHeight;
|
|
|
|
|
+ const currentScrollTop = wrap.scrollTop;
|
|
|
|
|
+ const maxScrollTop = scrollHeight - clientHeight;
|
|
|
|
|
+
|
|
|
|
|
+ // 强制滚动或启用自动滚动时,直接滚动到底部并隐藏按钮
|
|
|
|
|
+ if (forceScroll || this.isAutoScrollEnabled) {
|
|
|
|
|
+ this.showLoadLatestBtn = false;
|
|
|
|
|
+ wrap.scrollTop = maxScrollTop;
|
|
|
|
|
+ }
|
|
|
|
|
+ });
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
|
|
+ // 加载最新消息
|
|
|
|
|
+ loadLatestMessages() {
|
|
|
|
|
+ this.showLoadLatestBtn = false;
|
|
|
|
|
+ // 恢复自动滚动
|
|
|
|
|
+ this.isAutoScrollEnabled = true;
|
|
|
|
|
+ // 重新请求最新消息
|
|
|
|
|
+ this.resetMsgParams();
|
|
|
|
|
+ // loadMsgList 中会自动滚动到底部,因为 isAutoScrollEnabled 已经是 true
|
|
|
|
|
+ this.loadMsgList();
|
|
|
|
|
+ },
|
|
|
singleVisible(m){
|
|
singleVisible(m){
|
|
|
// 过滤当前所有消息 找到userId的相同的消息 更改他们的自可见状态
|
|
// 过滤当前所有消息 找到userId的相同的消息 更改他们的自可见状态
|
|
|
m.singleVisible= m.singleVisible === 1 ? 0 : 1
|
|
m.singleVisible= m.singleVisible === 1 ? 0 : 1
|
|
@@ -638,12 +718,17 @@ export default {
|
|
|
this.msgList.shift()
|
|
this.msgList.shift()
|
|
|
}
|
|
}
|
|
|
this.msgList.push(message)
|
|
this.msgList.push(message)
|
|
|
- // 移动到底部
|
|
|
|
|
- this.$nextTick(() => {
|
|
|
|
|
- setTimeout(() => {
|
|
|
|
|
- this.$refs.manageRightRef.wrap.scrollTop = this.$refs.manageRightRef.wrap.scrollHeight - this.$refs.manageRightRef.wrap.clientHeight
|
|
|
|
|
- }, 200)
|
|
|
|
|
- })
|
|
|
|
|
|
|
+ // 如果启用自动滚动,自动滚动到底部
|
|
|
|
|
+ if (this.isAutoScrollEnabled) {
|
|
|
|
|
+ this.$nextTick(() => {
|
|
|
|
|
+ this.autoScrollTimer = setTimeout(() => {
|
|
|
|
|
+ this.scrollToBottom();
|
|
|
|
|
+ }, 200);
|
|
|
|
|
+ });
|
|
|
|
|
+ } else {
|
|
|
|
|
+ // 自动滚动被禁用时,显示加载最新消息按钮
|
|
|
|
|
+ this.showLoadLatestBtn = true;
|
|
|
|
|
+ }
|
|
|
} else if (cmd === 'entry' || cmd === 'out') {
|
|
} else if (cmd === 'entry' || cmd === 'out') {
|
|
|
const user = data;
|
|
const user = data;
|
|
|
const online = cmd === 'entry' ? 0 : 1; // 0=在线,1=离线
|
|
const online = cmd === 'entry' ? 0 : 1; // 0=在线,1=离线
|
|
@@ -1077,22 +1162,13 @@ export default {
|
|
|
let totalPage = (total % this.msgParams.pageSize == 0) ? Math.floor(total / this.msgParams.pageSize) : Math.floor(total / this.msgParams.pageSize + 1);
|
|
let totalPage = (total % this.msgParams.pageSize == 0) ? Math.floor(total / this.msgParams.pageSize) : Math.floor(total / this.msgParams.pageSize + 1);
|
|
|
rows.forEach(row => {
|
|
rows.forEach(row => {
|
|
|
if (!this.msgList.some(m => m.msgId === row.msgId)) {
|
|
if (!this.msgList.some(m => m.msgId === row.msgId)) {
|
|
|
-
|
|
|
|
|
let user = this.alDisplayList.find(u => u.userId === row.userId)
|
|
let user = this.alDisplayList.find(u => u.userId === row.userId)
|
|
|
if (user) {
|
|
if (user) {
|
|
|
row.msgStatus = user.msgStatus
|
|
row.msgStatus = user.msgStatus
|
|
|
} else {
|
|
} else {
|
|
|
row.msgStatus = 0
|
|
row.msgStatus = 0
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
this.msgList.push(row)
|
|
this.msgList.push(row)
|
|
|
-
|
|
|
|
|
- // 移动到底部
|
|
|
|
|
- this.$nextTick(() => {
|
|
|
|
|
- setTimeout(() => {
|
|
|
|
|
- this.$refs.manageRightRef.wrap.scrollTop = this.$refs.manageRightRef.wrap.scrollHeight - this.$refs.manageRightRef.wrap.clientHeight
|
|
|
|
|
- }, 200)
|
|
|
|
|
- })
|
|
|
|
|
}
|
|
}
|
|
|
})
|
|
})
|
|
|
|
|
|
|
@@ -1101,6 +1177,30 @@ export default {
|
|
|
this.alDisplayList.forEach(u => {
|
|
this.alDisplayList.forEach(u => {
|
|
|
this.msgList.filter(m => m.userId === u.userId).forEach(m => m.msgStatus = u.msgStatus)
|
|
this.msgList.filter(m => m.userId === u.userId).forEach(m => m.msgStatus = u.msgStatus)
|
|
|
})
|
|
})
|
|
|
|
|
+ // 所有消息加载完成后,根据自动滚动状态决定是否滚动
|
|
|
|
|
+ this.$nextTick(() => {
|
|
|
|
|
+ setTimeout(() => {
|
|
|
|
|
+ if (this.isAutoScrollEnabled) {
|
|
|
|
|
+ // 如果启用自动滚动,强制滚动到底部并隐藏按钮
|
|
|
|
|
+ this.scrollToBottom(true);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ // 如果禁用自动滚动,检查是否在底部,决定是否显示按钮
|
|
|
|
|
+ if (this.$refs.manageRightRef && this.$refs.manageRightRef.wrap) {
|
|
|
|
|
+ const wrap = this.$refs.manageRightRef.wrap;
|
|
|
|
|
+ const scrollHeight = wrap.scrollHeight;
|
|
|
|
|
+ const clientHeight = wrap.clientHeight;
|
|
|
|
|
+ const currentScrollTop = wrap.scrollTop;
|
|
|
|
|
+ const maxScrollTop = scrollHeight - clientHeight;
|
|
|
|
|
+
|
|
|
|
|
+ if (currentScrollTop < maxScrollTop - 50) {
|
|
|
|
|
+ this.showLoadLatestBtn = true;
|
|
|
|
|
+ } else {
|
|
|
|
|
+ this.showLoadLatestBtn = false;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }, 300);
|
|
|
|
|
+ });
|
|
|
}
|
|
}
|
|
|
})
|
|
})
|
|
|
|
|
|
|
@@ -1201,6 +1301,7 @@ export default {
|
|
|
pageSize: 30,
|
|
pageSize: 30,
|
|
|
liveId: this.liveId
|
|
liveId: this.liveId
|
|
|
};
|
|
};
|
|
|
|
|
+ // 重置时不改变按钮状态,由后续的滚动逻辑决定
|
|
|
this.taskParams = {
|
|
this.taskParams = {
|
|
|
currentPage: 1,
|
|
currentPage: 1,
|
|
|
pageSize: 20,
|
|
pageSize: 20,
|
|
@@ -1321,6 +1422,9 @@ export default {
|
|
|
if (this.autoMsgTimer != null) {
|
|
if (this.autoMsgTimer != null) {
|
|
|
clearInterval(this.autoMsgTimer);
|
|
clearInterval(this.autoMsgTimer);
|
|
|
}
|
|
}
|
|
|
|
|
+ if (this.autoScrollTimer) {
|
|
|
|
|
+ clearTimeout(this.autoScrollTimer);
|
|
|
|
|
+ }
|
|
|
},
|
|
},
|
|
|
// 使用 deactivated 和 activated 钩子替代 beforeDestroy 和 destroyed
|
|
// 使用 deactivated 和 activated 钩子替代 beforeDestroy 和 destroyed
|
|
|
deactivated() {
|
|
deactivated() {
|
|
@@ -1624,4 +1728,14 @@ export default {
|
|
|
text-align: center;
|
|
text-align: center;
|
|
|
border-radius: 4px;
|
|
border-radius: 4px;
|
|
|
}
|
|
}
|
|
|
|
|
+.message-container {
|
|
|
|
|
+ position: relative;
|
|
|
|
|
+}
|
|
|
|
|
+.load-latest-btn {
|
|
|
|
|
+ position: absolute;
|
|
|
|
|
+ bottom: 20px;
|
|
|
|
|
+ right: 20px;
|
|
|
|
|
+ z-index: 10;
|
|
|
|
|
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
|
|
|
|
|
+}
|
|
|
</style>
|
|
</style>
|