Commit df5e6161aac60138b8696de546a77b19469d2565
1 parent
94178998
mp:重构 wx-msg 前的提交
Showing
1 changed file
with
313 additions
and
0 deletions
yudao-ui-admin/src/views/mp/components/wx-msg/main.vue
0 → 100644
| 1 | +<!-- | ||
| 2 | + - Copyright (C) 2018-2019 | ||
| 3 | + - All rights reserved, Designed By www.joolun.com | ||
| 4 | +--> | ||
| 5 | +<template> | ||
| 6 | + <div class="msg-main" v-loading="mainLoading"> | ||
| 7 | + <div class="msg-div" :id="'msg-div'+nowStr"> | ||
| 8 | + <div v-loading="tableLoading"></div> | ||
| 9 | + <div v-if="!tableLoading"> | ||
| 10 | + <div class="el-table__empty-block" v-if="loadMore" @click="loadingMore"><span class="el-table__empty-text">点击加载更多</span></div> | ||
| 11 | + <div class="el-table__empty-block" v-if="!loadMore"><span class="el-table__empty-text">没有更多了</span></div> | ||
| 12 | + </div> | ||
| 13 | + <div class="execution" v-for="item in tableData" :key='item.id'> | ||
| 14 | + <div class="avue-comment" :class="item.type == '2' ? 'avue-comment--reverse' : ''"> | ||
| 15 | + <div class="avatar-div"> | ||
| 16 | + <img :src="item.type == '1' ? item.headimgUrl : item.appLogo" class="avue-comment__avatar"> | ||
| 17 | + <div class="avue-comment__author">{{item.type == '1' ? item.nickName : item.appName}}</div> | ||
| 18 | + </div> | ||
| 19 | + <div class="avue-comment__main"> | ||
| 20 | + <div class="avue-comment__header"> | ||
| 21 | + <div class="avue-comment__create_time">{{item.createTime}}</div> | ||
| 22 | + </div> | ||
| 23 | + <div class="avue-comment__body" :style="item.type == '2' ? 'background: #6BED72;' : ''"> | ||
| 24 | + <div v-if="item.repType == 'event' && item.repEvent == 'subscribe'"><el-tag type="success" size="mini">关注</el-tag></div> | ||
| 25 | + <div v-if="item.repType == 'event' && item.repEvent == 'unsubscribe'"><el-tag type="danger" size="mini">取消关注</el-tag></div> | ||
| 26 | + <div v-if="item.repType == 'event' && item.repEvent == 'CLICK'"><el-tag size="mini">点击菜单</el-tag>:【{{item.repName}}】</div> | ||
| 27 | + <div v-if="item.repType == 'event' && item.repEvent == 'VIEW'"><el-tag size="mini">点击菜单链接</el-tag>:【{{item.repUrl}}】</div> | ||
| 28 | + <div v-if="item.repType == 'event' && item.repEvent == 'scancode_waitmsg'"><el-tag size="mini">扫码结果:</el-tag>:【{{item.repContent}}】</div> | ||
| 29 | + <div v-if="item.repType == 'text'">{{item.repContent}}</div> | ||
| 30 | + <div v-if="item.repType == 'image'"> | ||
| 31 | + <a target="_blank" :href="item.repUrl"><img :src="item.repUrl" style="width: 100px"></a> | ||
| 32 | + </div> | ||
| 33 | + <div v-if="item.repType == 'voice'"> | ||
| 34 | + <WxVoicePlayer :objData="item"></WxVoicePlayer> | ||
| 35 | + </div> | ||
| 36 | + <div v-if="item.repType == 'video'" style="text-align: center"> | ||
| 37 | + <WxVideoPlayer :objData="item"></WxVideoPlayer> | ||
| 38 | + </div> | ||
| 39 | + <div v-if="item.repType == 'shortvideo'" style="text-align: center"> | ||
| 40 | + <WxVideoPlayer :objData="item"></WxVideoPlayer> | ||
| 41 | + </div> | ||
| 42 | + <div v-if="item.repType == 'location'"> | ||
| 43 | + <el-link type="primary" target="_blank" :href="'https://map.qq.com/?type=marker&isopeninfowin=1&markertype=1&pointx='+item.repLocationY+'&pointy='+item.repLocationX+'&name='+item.repContent+'&ref=joolun'"> | ||
| 44 | + <img :src="'https://apis.map.qq.com/ws/staticmap/v2/?zoom=10&markers=color:blue|label:A|'+item.repLocationX+','+item.repLocationY+'&key='+qqMapKey+'&size=250*180'"> | ||
| 45 | + <p/><i class="el-icon-map-location"></i>{{item.repContent}} | ||
| 46 | + </el-link> | ||
| 47 | + </div> | ||
| 48 | + <div v-if="item.repType == 'link'" class="avue-card__detail"> | ||
| 49 | + <el-link type="success" :underline="false" target="_blank" :href="item.repUrl"> | ||
| 50 | + <div class="avue-card__title"><i class="el-icon-link"></i>{{item.repName}}</div> | ||
| 51 | + </el-link> | ||
| 52 | + <div class="avue-card__info" style="height: unset">{{item.repDesc}}</div> | ||
| 53 | + </div> | ||
| 54 | + <div v-if="item.repType == 'news'" style="width: 300px"> | ||
| 55 | + <WxNews :objData="item.content.articles"></WxNews> | ||
| 56 | + </div> | ||
| 57 | + <div v-if="item.repType == 'music'"> | ||
| 58 | + <el-link type="success" :underline="false" target="_blank" :href="item.repUrl"> | ||
| 59 | + <div class="avue-card__body" style="padding:10px;background-color: #fff;border-radius: 5px"> | ||
| 60 | + <div class="avue-card__avatar"><img :src="item.repThumbUrl" alt=""></div> | ||
| 61 | + <div class="avue-card__detail"> | ||
| 62 | + <div class="avue-card__title" style="margin-bottom:unset">{{item.repName}}</div> | ||
| 63 | + <div class="avue-card__info" style="height: unset">{{item.repDesc}}</div> | ||
| 64 | + </div> | ||
| 65 | + </div> | ||
| 66 | + </el-link> | ||
| 67 | + </div> | ||
| 68 | + </div> | ||
| 69 | + </div> | ||
| 70 | + </div> | ||
| 71 | + </div> | ||
| 72 | + </div> | ||
| 73 | +<!-- <div class="msg-send" v-loading="sendLoading">--> | ||
| 74 | +<!-- <WxReplySelect :objData="objData"></WxReplySelect>--> | ||
| 75 | +<!-- <el-button type="success" size="small" class="send-but" @click="sendMsg">发送(S)</el-button>--> | ||
| 76 | +<!-- </div>--> | ||
| 77 | + </div> | ||
| 78 | +</template> | ||
| 79 | + | ||
| 80 | +<script> | ||
| 81 | + import { getPage, addObj, putObj } from '@/api/wxmp/wxmsg' | ||
| 82 | + import SockJS from 'sockjs-client'; | ||
| 83 | + import Stomp from 'stompjs'; | ||
| 84 | + import { getToken } from '@/utils/auth' | ||
| 85 | + import WxReplySelect from '@/components/wx-reply/main.vue' | ||
| 86 | + import WxNews from '@/components/wx-news/main.vue' | ||
| 87 | + import WxVideoPlayer from '@/components/wx-video-play/main.vue' | ||
| 88 | + import WxVoicePlayer from '@/components/wx-voice-play/main.vue' | ||
| 89 | + | ||
| 90 | + export default { | ||
| 91 | + name: "wxMsg", | ||
| 92 | + components: { | ||
| 93 | + WxReplySelect, | ||
| 94 | + WxNews, | ||
| 95 | + WxVideoPlayer, | ||
| 96 | + WxVoicePlayer | ||
| 97 | + }, | ||
| 98 | + props: { | ||
| 99 | + wxUserId:{ | ||
| 100 | + type:String | ||
| 101 | + } | ||
| 102 | + }, | ||
| 103 | + data() { | ||
| 104 | + return { | ||
| 105 | + nowStr: new Date().getTime(), | ||
| 106 | + objData:{ | ||
| 107 | + repType: 'text' | ||
| 108 | + }, | ||
| 109 | + mainLoading:false, | ||
| 110 | + sendLoading:false, | ||
| 111 | + tableLoading:false, | ||
| 112 | + loadMore: true, | ||
| 113 | + tableData: [], | ||
| 114 | + page: { | ||
| 115 | + total: 0, // 总页数 | ||
| 116 | + currentPage: 1, // 当前页数 | ||
| 117 | + pageSize: 14, // 每页显示多少条 | ||
| 118 | + ascs:[],//升序字段 | ||
| 119 | + descs:'create_time'//降序字段 | ||
| 120 | + }, | ||
| 121 | + option: { | ||
| 122 | + props: { | ||
| 123 | + avatar: 'avatar', | ||
| 124 | + author: 'author', | ||
| 125 | + body: 'body' | ||
| 126 | + } | ||
| 127 | + } | ||
| 128 | + } | ||
| 129 | + }, | ||
| 130 | + created() { | ||
| 131 | + this.refreshChange() | ||
| 132 | + }, | ||
| 133 | + destroyed: function() { | ||
| 134 | + this.disconnect() | ||
| 135 | + }, | ||
| 136 | + mounted(){ | ||
| 137 | + //开源版接口没有实现websocket,固隐藏 | ||
| 138 | + // this.initWebSocket() | ||
| 139 | + }, | ||
| 140 | + beforeDestroy() { | ||
| 141 | + // 页面离开时断开连接,清除定时器 | ||
| 142 | + this.disconnect(); | ||
| 143 | + clearInterval(this.timer); | ||
| 144 | + }, | ||
| 145 | + computed: { | ||
| 146 | + | ||
| 147 | + }, | ||
| 148 | + methods:{ | ||
| 149 | + initWebSocket() { | ||
| 150 | + this.connection(); | ||
| 151 | + let self = this; | ||
| 152 | + //断开重连机制,尝试发送消息,捕获异常发生时重连 | ||
| 153 | + this.timer = setInterval(() => { | ||
| 154 | + try { | ||
| 155 | + self.stompClient.send("test"); | ||
| 156 | + } catch (err) { | ||
| 157 | + console.log("断线了: " + err); | ||
| 158 | + self.connection(); | ||
| 159 | + } | ||
| 160 | + }, 5000); | ||
| 161 | + }, | ||
| 162 | + connection() { | ||
| 163 | + let token = getToken() | ||
| 164 | + let headers = { | ||
| 165 | + 'Authorization': 'Bearer ' + token | ||
| 166 | + } | ||
| 167 | + // 建立连接对象 | ||
| 168 | + this.socket = new SockJS('/weixin/ws');//连接服务端提供的通信接口,连接以后才可以订阅广播消息和个人消息 | ||
| 169 | + // 获取STOMP子协议的客户端对象 | ||
| 170 | + this.stompClient = Stomp.over(this.socket); | ||
| 171 | + | ||
| 172 | + // 向服务器发起websocket连接 | ||
| 173 | + this.stompClient.connect(headers, () => { | ||
| 174 | + this.stompClient.subscribe('/weixin/wx_msg'+this.wxUserId, (msg) => { // 订阅服务端提供的某个topic; | ||
| 175 | + let data = JSON.parse(msg.body) | ||
| 176 | + this.tableData = [...this.tableData , ...[data]]//刷新消息 | ||
| 177 | + this.scrollToBottom() | ||
| 178 | + //标记为已读 | ||
| 179 | + if(data.type == '1'){ | ||
| 180 | + putObj({ | ||
| 181 | + id: data.id, | ||
| 182 | + readFlag: '0' | ||
| 183 | + }).then(data => {}) | ||
| 184 | + } | ||
| 185 | + }); | ||
| 186 | + }, (err) => { | ||
| 187 | + | ||
| 188 | + }); | ||
| 189 | + }, | ||
| 190 | + disconnect() { | ||
| 191 | + if (this.stompClient != null) { | ||
| 192 | + this.stompClient.disconnect(); | ||
| 193 | + console.log("Disconnected"); | ||
| 194 | + } | ||
| 195 | + }, | ||
| 196 | + sendMsg(){ | ||
| 197 | + if(this.objData){ | ||
| 198 | + if(this.objData.repType == 'news'){ | ||
| 199 | + this.objData.content.articles = [this.objData.content.articles[0]] | ||
| 200 | + this.$message({ | ||
| 201 | + showClose: true, | ||
| 202 | + message: '图文消息条数限制在1条以内,已默认发送第一条', | ||
| 203 | + type: 'success' | ||
| 204 | + }) | ||
| 205 | + } | ||
| 206 | + this.sendLoading = true | ||
| 207 | + addObj(Object.assign({ | ||
| 208 | + wxUserId: this.wxUserId | ||
| 209 | + },this.objData)).then(data => { | ||
| 210 | + this.sendLoading = false | ||
| 211 | + data = data.data | ||
| 212 | + this.tableData = [...this.tableData , ...[data] ] | ||
| 213 | + this.scrollToBottom() | ||
| 214 | + this.objData = { | ||
| 215 | + repType: 'text' | ||
| 216 | + } | ||
| 217 | + }).catch(() => { | ||
| 218 | + this.sendLoading = false | ||
| 219 | + }) | ||
| 220 | + } | ||
| 221 | + }, | ||
| 222 | + scrollToBottom: function () { | ||
| 223 | + this.$nextTick(() => { | ||
| 224 | + let div = document.getElementById('msg-div'+this.nowStr) | ||
| 225 | + div.scrollTop = div.scrollHeight | ||
| 226 | + }) | ||
| 227 | + }, | ||
| 228 | + loadingMore(){ | ||
| 229 | + this.page.currentPage++ | ||
| 230 | + this.getPage(this.page) | ||
| 231 | + }, | ||
| 232 | + getPage(page, params) { | ||
| 233 | + this.tableLoading = true | ||
| 234 | + getPage(Object.assign({ | ||
| 235 | + current: page.currentPage, | ||
| 236 | + size: page.pageSize, | ||
| 237 | + descs:page.descs, | ||
| 238 | + ascs: page.ascs, | ||
| 239 | + wxUserId: this.wxUserId | ||
| 240 | + }, params)).then(response => { | ||
| 241 | + let msgDiv = document.getElementById('msg-div'+this.nowStr) | ||
| 242 | + let scrollHeight = 0 | ||
| 243 | + if(msgDiv){ | ||
| 244 | + scrollHeight = msgDiv.scrollHeight | ||
| 245 | + } | ||
| 246 | + let data = response.data.records.reverse() | ||
| 247 | + this.tableData = [...data , ...this.tableData] | ||
| 248 | + this.page.total = response.data.total | ||
| 249 | + this.tableLoading = false | ||
| 250 | + if(data.length < this.page.pageSize || data.length == 0){ | ||
| 251 | + this.loadMore = false | ||
| 252 | + } | ||
| 253 | + if(this.page.currentPage == 1){//定位到消息底部 | ||
| 254 | + this.scrollToBottom() | ||
| 255 | + }else{ | ||
| 256 | + if(data.length != 0){ | ||
| 257 | + this.$nextTick(() => {//定位滚动条 | ||
| 258 | + if(scrollHeight != 0){ | ||
| 259 | + msgDiv.scrollTop = document.getElementById('msg-div'+this.nowStr).scrollHeight - scrollHeight - 100 | ||
| 260 | + } | ||
| 261 | + }) | ||
| 262 | + } | ||
| 263 | + } | ||
| 264 | + this.page.currentPage = page.currentPage | ||
| 265 | + this.page.pageSize = page.pageSize | ||
| 266 | + }) | ||
| 267 | + }, | ||
| 268 | + /** | ||
| 269 | + * 刷新回调 | ||
| 270 | + */ | ||
| 271 | + refreshChange() { | ||
| 272 | + this.getPage(this.page) | ||
| 273 | + } | ||
| 274 | + } | ||
| 275 | + }; | ||
| 276 | +</script> | ||
| 277 | + | ||
| 278 | +<style lang="scss" scoped> | ||
| 279 | + .msg-main{ | ||
| 280 | + margin-top: -30px; | ||
| 281 | + padding: 10px; | ||
| 282 | + } | ||
| 283 | + .msg-div{ | ||
| 284 | + height: 50vh; | ||
| 285 | + overflow: auto; | ||
| 286 | + background-color: #eaeaea; | ||
| 287 | + } | ||
| 288 | + .msg-send{ | ||
| 289 | + padding: 10px; | ||
| 290 | + } | ||
| 291 | + .avue-comment__main{ | ||
| 292 | + flex: unset!important; | ||
| 293 | + border-radius: 5px!important; | ||
| 294 | + margin: 0 8px!important; | ||
| 295 | + } | ||
| 296 | + .avue-comment__header{ | ||
| 297 | + border-top-left-radius: 5px; | ||
| 298 | + border-top-right-radius: 5px; | ||
| 299 | + } | ||
| 300 | + .avue-comment__body { | ||
| 301 | + border-bottom-right-radius: 5px; | ||
| 302 | + border-bottom-left-radius: 5px; | ||
| 303 | + } | ||
| 304 | + .avatar-div{ | ||
| 305 | + text-align: center; | ||
| 306 | + width: 80px; | ||
| 307 | + } | ||
| 308 | + .send-but{ | ||
| 309 | + float: right; | ||
| 310 | + margin-top: 8px!important; | ||
| 311 | + } | ||
| 312 | +</style> | ||
| 313 | + |