|
|
@@ -230,8 +230,8 @@
|
|
|
</div>
|
|
|
<div class="message-container" @click="handleMessageBoxClick">
|
|
|
<el-scrollbar class="msg-scroll" ref="manageRightRef">
|
|
|
- <div v-for="m in msgList" :key="m.msgId" class="msg-item">
|
|
|
- <div v-if="m.userId === userId && m.msgId == null" class="msg-row msg-row--self">
|
|
|
+ <div v-for="(m, index) in msgList" :key="getMsgKey(m, index)" class="msg-item">
|
|
|
+ <div v-if="isSelfMessage(m)" class="msg-row msg-row--self">
|
|
|
<div class="msg-content msg-content--self">
|
|
|
<div class="msg-nickname">{{ m.nickName }}</div>
|
|
|
<div class="msg-bubble msg-bubble--self">{{ m.msg }}</div>
|
|
|
@@ -246,7 +246,7 @@
|
|
|
<div class="msg-actions">
|
|
|
<a class="action-link" @click.stop="changeUserState(m)">{{ m.msgStatus === 1 ? '解禁' : '禁言' }}</a>
|
|
|
<a class="action-link" @click.stop="blockUser(m)">拉黑</a>
|
|
|
- <a class="action-link" @click.stop="singleVisible(m)">{{ m.singleVisible === 1 ? '解除用户自见' : '用户自见' }}</a>
|
|
|
+ <a class="action-link" @click.stop="singleVisible(m)">{{ isSingleVisible(m) ? '解除用户自见' : '用户自见' }}</a>
|
|
|
<a class="action-link" @click.stop="deleteMsg(m)">删除</a>
|
|
|
</div>
|
|
|
</div>
|
|
|
@@ -475,6 +475,7 @@ export default {
|
|
|
pageSize: 30,
|
|
|
liveId: null
|
|
|
},
|
|
|
+ chatScrollTop: 0,
|
|
|
opsTabActive: 'marketing',
|
|
|
marketingCategory: 'goods',
|
|
|
marketingCategories: [
|
|
|
@@ -695,11 +696,27 @@ export default {
|
|
|
},
|
|
|
ensureSocket() {
|
|
|
if (!this.socket) {
|
|
|
- this.$message.error('请从直播间开启 WebSocket 连接');
|
|
|
+ this.$message.error('WebSocket 未连接,请稍后重试');
|
|
|
return false;
|
|
|
}
|
|
|
return true;
|
|
|
},
|
|
|
+ isSameUser(id1, id2) {
|
|
|
+ if (id1 == null || id2 == null) return false;
|
|
|
+ return String(id1) === String(id2);
|
|
|
+ },
|
|
|
+ isSelfMessage(m) {
|
|
|
+ return this.isSameUser(m.userId, this.userId);
|
|
|
+ },
|
|
|
+ isSingleVisible(m) {
|
|
|
+ return Number(m.singleVisible) === 1;
|
|
|
+ },
|
|
|
+ getMsgKey(m, index) {
|
|
|
+ if (m.msgId != null && m.msgId !== '') {
|
|
|
+ return m.msgId;
|
|
|
+ }
|
|
|
+ return `msg-${index}-${m.userId || 'unknown'}`;
|
|
|
+ },
|
|
|
handleGoodsShelf(row, status) {
|
|
|
handleShelfOrUn({ goodsIds: [row.goodsId], status, liveId: this.liveId }).then(res => {
|
|
|
if (res.code === 200) {
|
|
|
@@ -931,18 +948,22 @@ export default {
|
|
|
this.loadMsgList();
|
|
|
},
|
|
|
singleVisible(m){
|
|
|
- // 过滤当前所有消息 找到userId的相同的消息 更改他们的自可见状态
|
|
|
- m.singleVisible= m.singleVisible === 1 ? 0 : 1
|
|
|
- this.msgList.forEach(m1 => {m1.singleVisible = m1.userId === m.userId ? m.singleVisible : !m.singleVisible})
|
|
|
- // 消息自可见
|
|
|
- let msg = {
|
|
|
+ const newStatus = this.isSingleVisible(m) ? 0 : 1;
|
|
|
+ m.singleVisible = newStatus;
|
|
|
+ this.msgList.forEach(m1 => {
|
|
|
+ if (this.isSameUser(m1.userId, m.userId)) {
|
|
|
+ m1.singleVisible = newStatus;
|
|
|
+ }
|
|
|
+ });
|
|
|
+ if (!this.ensureSocket()) return;
|
|
|
+ const msg = {
|
|
|
liveId: this.liveId,
|
|
|
userId: m.userId,
|
|
|
userType: 0,
|
|
|
cmd: 'singleVisible',
|
|
|
- status:m.singleVisible
|
|
|
- }
|
|
|
- this.socket.send(JSON.stringify(msg))
|
|
|
+ status: newStatus
|
|
|
+ };
|
|
|
+ this.socket.send(JSON.stringify(msg));
|
|
|
},
|
|
|
deleteMsg(m){
|
|
|
// 1. 弹出确认对话框
|
|
|
@@ -961,9 +982,10 @@ export default {
|
|
|
let msg = {
|
|
|
liveId: this.liveId,
|
|
|
userId: m.userId,
|
|
|
- msg: m.msgId, // 关键:将消息ID发送给后台
|
|
|
+ msg: m.msgId,
|
|
|
cmd: 'deleteMsg',
|
|
|
};
|
|
|
+ if (!this.ensureSocket()) return;
|
|
|
this.socket.send(JSON.stringify(msg));
|
|
|
// 可以在这里给用户一个删除成功的提示
|
|
|
this.$message({
|
|
|
@@ -980,16 +1002,19 @@ export default {
|
|
|
});
|
|
|
});
|
|
|
},
|
|
|
- globalVisibleChange( val){
|
|
|
- // 消息自可见
|
|
|
- let msg = {
|
|
|
+ globalVisibleChange(){
|
|
|
+ if (!this.ensureSocket()) {
|
|
|
+ this.globalVisible = !this.globalVisible;
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ const msg = {
|
|
|
liveId: this.liveId,
|
|
|
userId: '9999',
|
|
|
userType: 0,
|
|
|
cmd: 'globalVisible',
|
|
|
- status:this.globalVisible ? 1 :0
|
|
|
- }
|
|
|
- this.socket.send(JSON.stringify(msg))
|
|
|
+ status: this.globalVisible ? 1 : 0
|
|
|
+ };
|
|
|
+ this.socket.send(JSON.stringify(msg));
|
|
|
},
|
|
|
showCartChange(val) {
|
|
|
const status = val ? 1 : 0
|
|
|
@@ -997,16 +1022,6 @@ export default {
|
|
|
if (res.code !== 200) {
|
|
|
this.$message.error(res.msg || '更新购物车显示状态失败')
|
|
|
this.showCart = !val
|
|
|
- return
|
|
|
- }
|
|
|
- if (this.socket && this.socket.readyState === WebSocket.OPEN) {
|
|
|
- this.socket.send(JSON.stringify({
|
|
|
- liveId: this.liveId,
|
|
|
- userId: '9999',
|
|
|
- userType: 0,
|
|
|
- cmd: 'showCart',
|
|
|
- status
|
|
|
- }))
|
|
|
}
|
|
|
}).catch(() => {
|
|
|
this.showCart = !val
|
|
|
@@ -1065,10 +1080,10 @@ export default {
|
|
|
this.watermarkIndex += 1
|
|
|
},
|
|
|
sendMessage() {
|
|
|
- // 发送前简单校验
|
|
|
if (this.newMsg.trim() === '') {
|
|
|
return;
|
|
|
}
|
|
|
+ if (!this.ensureSocket()) return;
|
|
|
|
|
|
let msg = {
|
|
|
msg: this.newMsg,
|
|
|
@@ -1085,18 +1100,20 @@ export default {
|
|
|
this.newMsg = '';
|
|
|
},
|
|
|
handleWsMessage(event) {
|
|
|
- let { code, data } = JSON.parse(event.data)
|
|
|
- if (code === 200) {
|
|
|
+ try {
|
|
|
+ let { code, data } = JSON.parse(event.data)
|
|
|
+ if (code === 200) {
|
|
|
let { cmd } = data
|
|
|
if (cmd === 'sendMsg') {
|
|
|
let message = JSON.parse(data.data)
|
|
|
|
|
|
- let user = this.alDisplayList.find(u => u.userId === message.userId)
|
|
|
+ let user = this.alDisplayList.find(u => this.isSameUser(u.userId, message.userId))
|
|
|
if (user) {
|
|
|
message.msgStatus = user.msgStatus
|
|
|
} else {
|
|
|
message.msgStatus = 0
|
|
|
}
|
|
|
+ message.singleVisible = message.singleVisible == null ? 0 : Number(message.singleVisible)
|
|
|
delete message.params
|
|
|
if(this.msgList.length > 50){
|
|
|
this.msgList.shift()
|
|
|
@@ -1161,7 +1178,28 @@ export default {
|
|
|
|
|
|
} else if (cmd === 'live_end') {
|
|
|
|
|
|
+ } else if (cmd === 'deleteMsg') {
|
|
|
+ const msgId = data.msg || data.msgId;
|
|
|
+ if (msgId != null) {
|
|
|
+ const index = this.msgList.findIndex(item => String(item.msgId) === String(msgId));
|
|
|
+ if (index !== -1) {
|
|
|
+ this.msgList.splice(index, 1);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } else if (cmd === 'singleVisible') {
|
|
|
+ const targetUserId = data.userId;
|
|
|
+ const status = Number(data.status) === 1 ? 1 : 0;
|
|
|
+ this.msgList.forEach(m1 => {
|
|
|
+ if (this.isSameUser(m1.userId, targetUserId)) {
|
|
|
+ m1.singleVisible = status;
|
|
|
+ }
|
|
|
+ });
|
|
|
+ } else if (cmd === 'globalVisible') {
|
|
|
+ this.globalVisible = Number(data.status) === 1 || data.status === true;
|
|
|
}
|
|
|
+ }
|
|
|
+ } catch (e) {
|
|
|
+ console.error('WebSocket message parse error:', e);
|
|
|
}
|
|
|
},
|
|
|
getLive(){
|
|
|
@@ -1200,7 +1238,7 @@ export default {
|
|
|
}
|
|
|
}
|
|
|
this.$nextTick(() => {
|
|
|
- this.globalVisible = res.data.globalVisible
|
|
|
+ this.globalVisible = res.data.globalVisible === 1 || res.data.globalVisible === true
|
|
|
this.showCart = res.data.showCart == null || res.data.showCart === 1
|
|
|
if (this.$refs.livePlayer) {
|
|
|
this.$refs.livePlayer.initPlayer()
|
|
|
@@ -1215,13 +1253,27 @@ export default {
|
|
|
})
|
|
|
},
|
|
|
connectWebSocket() {
|
|
|
+ const liveId = this.liveId;
|
|
|
this.$store.dispatch('initLiveWs', {
|
|
|
liveWsUrl: this.liveWsUrl,
|
|
|
- liveId: this.liveId,
|
|
|
+ liveId,
|
|
|
userId: this.userId
|
|
|
- })
|
|
|
- this.socket = this.$store.state.liveWs[this.liveId]
|
|
|
- this.socket.onmessage = (event) => this.handleWsMessage(event)
|
|
|
+ });
|
|
|
+ this.socket = this.$store.state.liveWs[liveId];
|
|
|
+ if (!this.socket) {
|
|
|
+ this.$message.error('WebSocket 初始化失败');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ this.socket.onmessage = (event) => this.handleWsMessage(event);
|
|
|
+ const nativeWs = this.socket.ws;
|
|
|
+ if (nativeWs) {
|
|
|
+ nativeWs.addEventListener('open', () => {
|
|
|
+ console.log('[LiveConsole] WebSocket connected');
|
|
|
+ }, { once: true });
|
|
|
+ nativeWs.addEventListener('error', () => {
|
|
|
+ this.$message.error('WebSocket 连接失败,请确认 fs-live-app(7114) 已启动');
|
|
|
+ }, { once: true });
|
|
|
+ }
|
|
|
},
|
|
|
changeUserState(u) {
|
|
|
const displayList = this[`${this.currentTab}DisplayList`];
|
|
|
@@ -1550,12 +1602,13 @@ export default {
|
|
|
let totalPage = (total % this.msgParams.pageSize == 0) ? Math.floor(total / this.msgParams.pageSize) : Math.floor(total / this.msgParams.pageSize + 1);
|
|
|
rows.forEach(row => {
|
|
|
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 => this.isSameUser(u.userId, row.userId))
|
|
|
if (user) {
|
|
|
row.msgStatus = user.msgStatus
|
|
|
} else {
|
|
|
row.msgStatus = 0
|
|
|
}
|
|
|
+ row.singleVisible = row.singleVisible == null ? 0 : Number(row.singleVisible)
|
|
|
this.msgList.push(row)
|
|
|
}
|
|
|
})
|
|
|
@@ -1563,7 +1616,7 @@ export default {
|
|
|
this.msgList.reverse()
|
|
|
// 同步更新消息列表中相同用户的状态
|
|
|
this.alDisplayList.forEach(u => {
|
|
|
- this.msgList.filter(m => m.userId === u.userId).forEach(m => m.msgStatus = u.msgStatus)
|
|
|
+ this.msgList.filter(m => this.isSameUser(m.userId, u.userId)).forEach(m => m.msgStatus = u.msgStatus)
|
|
|
})
|
|
|
// 所有消息加载完成后,根据自动滚动状态决定是否滚动
|
|
|
this.$nextTick(() => {
|
|
|
@@ -2159,16 +2212,26 @@ export default {
|
|
|
flex: 1;
|
|
|
min-height: 0;
|
|
|
padding: 8px 16px 0;
|
|
|
+ overflow: hidden;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
}
|
|
|
|
|
|
.msg-scroll {
|
|
|
- height: 100%;
|
|
|
+ flex: 1;
|
|
|
+ min-height: 0;
|
|
|
+ height: auto;
|
|
|
}
|
|
|
|
|
|
.msg-scroll ::v-deep .el-scrollbar {
|
|
|
height: 100%;
|
|
|
}
|
|
|
|
|
|
+.msg-scroll ::v-deep .el-scrollbar__wrap {
|
|
|
+ height: 100% !important;
|
|
|
+ max-height: 100%;
|
|
|
+}
|
|
|
+
|
|
|
.msg-item + .msg-item {
|
|
|
margin-top: 8px;
|
|
|
}
|