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 | + | ... | ... |