|
|
@@ -102,56 +102,6 @@
|
|
|
<div class="middle-panel">
|
|
|
<h2>消息管理</h2>
|
|
|
|
|
|
- <!-- 新增:用户行为记录区域 -->
|
|
|
- <div class="behavior-records">
|
|
|
- <h3>用户行为记录</h3>
|
|
|
- <div class="message-container" @click="handleBehaviorBoxClick">
|
|
|
- <el-scrollbar class="custom-scrollbar" style="height: 300px; width: 100%;" ref="behaviorScrollRef">
|
|
|
- <div v-if="behaviorList.length === 0" style="text-align: center; padding: 40px 0; color: #999;">
|
|
|
- <i class="el-icon-info" style="font-size: 48px; margin-bottom: 10px;"></i>
|
|
|
- <p>暂无行为记录</p>
|
|
|
- </div>
|
|
|
- <el-row v-else v-for="behavior in behaviorList" :key="behavior.id" style="padding: 8px 0" type="flex" align="top">
|
|
|
- <el-col :span="3" style="margin-left: 10px">
|
|
|
- <el-avatar :src="behavior.avatar" :size="40"></el-avatar>
|
|
|
- </el-col>
|
|
|
- <el-col :span="20">
|
|
|
- <el-row style="margin-left: 10px">
|
|
|
- <el-col>
|
|
|
- <div style="font-size: 12px; color: #999; margin-bottom: 3px;">{{ behavior.nickName }}</div>
|
|
|
- </el-col>
|
|
|
- <el-col :span="24">
|
|
|
- <div style="white-space: normal; word-wrap: break-word;background-color: #f0f2f5; padding: 8px; border-radius: 5px;font-size: 14px;">
|
|
|
- <i :class="getBehaviorIcon(behavior.behaviorType)" :style="{ color: getBehaviorColor(behavior.behaviorType) }"></i>
|
|
|
- <span style="margin-left: 5px; font-weight: bold;">{{ behavior.behaviorDesc }}</span>
|
|
|
- <span v-if="behavior.resourceName" style="margin-left: 8px; color: #606266;">「{{ behavior.resourceName }}」</span>
|
|
|
- </div>
|
|
|
- </el-col>
|
|
|
- <el-col style="margin-top: 5px;">
|
|
|
- <span style="font-size: 12px; color: #999;">{{ formatBehaviorTime(behavior.behaviorTime) }}</span>
|
|
|
- <span v-if="behavior.deviceInfo" style="margin-left: 10px; font-size: 12px; color: #999;">【{{ behavior.deviceInfo }}】</span>
|
|
|
- </el-col>
|
|
|
- </el-row>
|
|
|
- </el-col>
|
|
|
- </el-row>
|
|
|
- <!-- 底部留白 -->
|
|
|
- <div style="height: 20px;"></div>
|
|
|
- </el-scrollbar>
|
|
|
- <!-- 加载最新行为按钮 -->
|
|
|
- <el-button
|
|
|
- v-if="showLoadLatestBehaviorBtn"
|
|
|
- class="load-latest-btn"
|
|
|
- type="primary"
|
|
|
- size="small"
|
|
|
- @click.stop="loadLatestBehaviors"
|
|
|
- :disabled="isLoadingLatestBehavior"
|
|
|
- :loading="isLoadingLatestBehavior"
|
|
|
- icon="el-icon-refresh">
|
|
|
- 加载最新行为
|
|
|
- </el-button>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
-
|
|
|
<div class="discussion-messages">
|
|
|
<h3>讨论区消息</h3>
|
|
|
<div class="message-settings">
|
|
|
@@ -465,29 +415,6 @@ export default {
|
|
|
pageNum: 1,
|
|
|
pageSize: 30,
|
|
|
liveId: null
|
|
|
- },
|
|
|
- // 新增:行为记录相关
|
|
|
- behaviorList: [], // 行为列表
|
|
|
- showLoadLatestBehaviorBtn: false, // 显示加载最新行为按钮
|
|
|
- isLoadingLatestBehavior: false, // 是否正在加载最新行为
|
|
|
- isAutoBehaviorScroll: true, // 是否启用行为自动滚动
|
|
|
- // 行为类型映射(后端定义的 behaviorType)
|
|
|
- behaviorTypeMap: {
|
|
|
- 1: '进入直播间',
|
|
|
- 2: '退出直播间',
|
|
|
- 3: '点赞',
|
|
|
- 4: '发送消息',
|
|
|
- 5: '点击商品',
|
|
|
- 6: '加入购物车',
|
|
|
- 7: '购买商品',
|
|
|
- 8: '收藏商品',
|
|
|
- 9: '关注主播',
|
|
|
- 10: '领取优惠券',
|
|
|
- 11: '参与抽奖',
|
|
|
- 12: '领取红包',
|
|
|
- 13: '分享直播间',
|
|
|
- 14: '观看时长记录',
|
|
|
- 15: '完课记录'
|
|
|
}
|
|
|
};
|
|
|
},
|
|
|
@@ -783,12 +710,9 @@ export default {
|
|
|
},
|
|
|
handleWsMessage(event) {
|
|
|
let { code, data } = JSON.parse(event.data)
|
|
|
- if (code === 200 || code === 0) { // 兼容后端返回 code: 0
|
|
|
+ if (code === 200) {
|
|
|
let { cmd } = data
|
|
|
- // 新增:处理行为记录(后端推送的 cmd: 'behaviorTrack')
|
|
|
- if (cmd === 'behaviorTrack') {
|
|
|
- this.handleBehaviorRecord(data.data); // data.data 是真正的行为数据
|
|
|
- } else if (cmd === 'sendMsg') {
|
|
|
+ if (cmd === 'sendMsg') {
|
|
|
let message = JSON.parse(data.data)
|
|
|
|
|
|
let user = this.alDisplayList.find(u => u.userId === message.userId)
|
|
|
@@ -1532,137 +1456,6 @@ export default {
|
|
|
this.timelineItems.shift()
|
|
|
this.loadLiveTask(); // 重新加载任务列表
|
|
|
}
|
|
|
- },
|
|
|
- // 新增:处理接收到的行为记录(WebSocket推送)
|
|
|
- handleBehaviorRecord(behaviorData) {
|
|
|
- if (!behaviorData) return;
|
|
|
-
|
|
|
- const behavior = {
|
|
|
- id: behaviorData.id || Date.now(),
|
|
|
- userId: behaviorData.userId,
|
|
|
- nickName: this.getUserName(behaviorData.userId),
|
|
|
- avatar: this.getUserAvatar(behaviorData.userId),
|
|
|
- behaviorType: behaviorData.behaviorType,
|
|
|
- behaviorDesc: behaviorData.behaviorDesc || this.getBehaviorText(behaviorData.behaviorType),
|
|
|
- behaviorTime: behaviorData.behaviorTime || new Date().getTime(),
|
|
|
- resourceName: this.getResourceName(behaviorData),
|
|
|
- deviceInfo: behaviorData.deviceInfo || ''
|
|
|
- };
|
|
|
-
|
|
|
- // 添加到行为列表头部(最新的在上面)
|
|
|
- if (this.behaviorList.length >= 50) {
|
|
|
- this.behaviorList.pop();
|
|
|
- }
|
|
|
- this.behaviorList.unshift(behavior);
|
|
|
-
|
|
|
- // 如果启用自动滚动,滚动到顶部
|
|
|
- if (this.isAutoBehaviorScroll) {
|
|
|
- this.$nextTick(() => {
|
|
|
- if (this.$refs.behaviorScrollRef && this.$refs.behaviorScrollRef.wrap) {
|
|
|
- this.$refs.behaviorScrollRef.wrap.scrollTop = 0;
|
|
|
- }
|
|
|
- });
|
|
|
- } else {
|
|
|
- this.showLoadLatestBehaviorBtn = true;
|
|
|
- }
|
|
|
- },
|
|
|
- // 新增:获取用户头像
|
|
|
- getUserAvatar(userId) {
|
|
|
- const user = this.alDisplayList.find(u => u.userId === userId);
|
|
|
- return user?.avatar || 'https://cube.elemecdn.com/0/88/03b0d39583f48206768a7534e55bcpng.png';
|
|
|
- },
|
|
|
- // 新增:获取用户昵称
|
|
|
- getUserName(userId) {
|
|
|
- const user = this.alDisplayList.find(u => u.userId === userId);
|
|
|
- return user?.nickName || `用户${userId}`;
|
|
|
- },
|
|
|
- // 新增:获取资源名称
|
|
|
- getResourceName(behaviorData) {
|
|
|
- try {
|
|
|
- if (behaviorData.extData) {
|
|
|
- const extData = JSON.parse(behaviorData.extData);
|
|
|
- if ([5, 6, 7, 8].includes(behaviorData.behaviorType)) {
|
|
|
- return extData.goodsName || '';
|
|
|
- } else if (behaviorData.behaviorType === 10) {
|
|
|
- return extData.couponName || '';
|
|
|
- }
|
|
|
- }
|
|
|
- } catch (e) {
|
|
|
- console.error('解析extData失败:', e);
|
|
|
- }
|
|
|
- return '';
|
|
|
- },
|
|
|
- // 新增:点击行为框
|
|
|
- handleBehaviorBoxClick() {
|
|
|
- this.isAutoBehaviorScroll = false;
|
|
|
- this.$nextTick(() => {
|
|
|
- if (this.$refs.behaviorScrollRef && this.$refs.behaviorScrollRef.wrap) {
|
|
|
- const wrap = this.$refs.behaviorScrollRef.wrap;
|
|
|
- const scrollHeight = wrap.scrollHeight;
|
|
|
- const clientHeight = wrap.clientHeight;
|
|
|
- const currentScrollTop = wrap.scrollTop;
|
|
|
- const maxScrollTop = scrollHeight - clientHeight;
|
|
|
- if (currentScrollTop < maxScrollTop - 50) {
|
|
|
- this.showLoadLatestBehaviorBtn = true;
|
|
|
- }
|
|
|
- }
|
|
|
- });
|
|
|
- },
|
|
|
- // 新增:加载最新行为
|
|
|
- loadLatestBehaviors() {
|
|
|
- if (this.isLoadingLatestBehavior) return;
|
|
|
- this.isLoadingLatestBehavior = false;
|
|
|
- this.showLoadLatestBehaviorBtn = false;
|
|
|
- this.isAutoBehaviorScroll = true;
|
|
|
- this.$nextTick(() => {
|
|
|
- if (this.$refs.behaviorScrollRef && this.$refs.behaviorScrollRef.wrap) {
|
|
|
- this.$refs.behaviorScrollRef.wrap.scrollTop = 0;
|
|
|
- }
|
|
|
- });
|
|
|
- },
|
|
|
- // 新增:格式化行为时间
|
|
|
- formatBehaviorTime(timestamp) {
|
|
|
- if (!timestamp) return '';
|
|
|
- const date = new Date(timestamp);
|
|
|
- const now = new Date();
|
|
|
- const diff = now - date;
|
|
|
- if (diff < 60000) return '刚刚';
|
|
|
- if (diff < 3600000) return Math.floor(diff / 60000) + '分钟前';
|
|
|
- if (date.toDateString() === now.toDateString()) {
|
|
|
- const hours = String(date.getHours()).padStart(2, '0');
|
|
|
- const minutes = String(date.getMinutes()).padStart(2, '0');
|
|
|
- return `${hours}:${minutes}`;
|
|
|
- }
|
|
|
- const month = String(date.getMonth() + 1).padStart(2, '0');
|
|
|
- const day = String(date.getDate()).padStart(2, '0');
|
|
|
- const hours = String(date.getHours()).padStart(2, '0');
|
|
|
- const minutes = String(date.getMinutes()).padStart(2, '0');
|
|
|
- return `${month}-${day} ${hours}:${minutes}`;
|
|
|
- },
|
|
|
- // 新增:获取行为文本
|
|
|
- getBehaviorText(behaviorType) {
|
|
|
- return this.behaviorTypeMap[behaviorType] || '未知操作';
|
|
|
- },
|
|
|
- // 新增:获取行为图标
|
|
|
- getBehaviorIcon(behaviorType) {
|
|
|
- const iconMap = {
|
|
|
- 1: 'el-icon-user', 2: 'el-icon-back', 3: 'el-icon-star-on',
|
|
|
- 4: 'el-icon-chat-dot-round', 5: 'el-icon-view', 6: 'el-icon-shopping-cart-1',
|
|
|
- 7: 'el-icon-shopping-cart-2', 8: 'el-icon-star-off', 9: 'el-icon-plus',
|
|
|
- 10: 'el-icon-discount', 11: 'el-icon-trophy', 12: 'el-icon-present',
|
|
|
- 13: 'el-icon-share', 14: 'el-icon-video-play', 15: 'el-icon-success'
|
|
|
- };
|
|
|
- return iconMap[behaviorType] || 'el-icon-info';
|
|
|
- },
|
|
|
- // 新增:获取行为颜色
|
|
|
- getBehaviorColor(behaviorType) {
|
|
|
- const colorMap = {
|
|
|
- 1: '#67C23A', 2: '#909399', 3: '#FF6B9D', 4: '#409EFF',
|
|
|
- 5: '#43e97b', 6: '#ffa94d', 7: '#F56C6C', 8: '#ff6b6b',
|
|
|
- 9: '#f59e0b', 10: '#ffd93d', 11: '#c084fc', 12: '#fb923c',
|
|
|
- 13: '#38bdf8', 14: '#a78bfa', 15: '#34d399'
|
|
|
- };
|
|
|
- return colorMap[behaviorType] || '#909399';
|
|
|
}
|
|
|
},
|
|
|
beforeDestroy() {
|
|
|
@@ -1992,20 +1785,4 @@ export default {
|
|
|
z-index: 10;
|
|
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
|
|
|
}
|
|
|
-
|
|
|
-/* 新增:行为记录样式 */
|
|
|
-.behavior-records {
|
|
|
- margin-bottom: 20px;
|
|
|
- background: #fff;
|
|
|
- padding: 15px;
|
|
|
- border-radius: 8px;
|
|
|
- box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
|
|
|
-}
|
|
|
-
|
|
|
-.behavior-records h3 {
|
|
|
- margin: 0 0 15px 0;
|
|
|
- font-size: 16px;
|
|
|
- font-weight: 600;
|
|
|
- color: #303133;
|
|
|
-}
|
|
|
</style>
|