mirror of
				https://gitee.com/hhyykk/ipms-sjy-ui.git
				synced 2025-11-03 03:38:44 +08:00 
			
		
		
		
	refactor: mp/wx-msg 拆分组件
This commit is contained in:
		
							
								
								
									
										51
									
								
								src/views/mp/components/wx-msg/components/MsgEvent.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								src/views/mp/components/wx-msg/components/MsgEvent.vue
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,51 @@
 | 
				
			|||||||
 | 
					<template>
 | 
				
			||||||
 | 
					  <div>
 | 
				
			||||||
 | 
					    <div v-if="item.event === 'subscribe'">
 | 
				
			||||||
 | 
					      <el-tag type="success">关注</el-tag>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					    <div v-else-if="item.event === 'unsubscribe'">
 | 
				
			||||||
 | 
					      <el-tag type="danger">取消关注</el-tag>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					    <div v-else-if="item.event === 'CLICK'">
 | 
				
			||||||
 | 
					      <el-tag>点击菜单</el-tag>
 | 
				
			||||||
 | 
					      【{{ item.eventKey }}】
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					    <div v-else-if="item.event === 'VIEW'">
 | 
				
			||||||
 | 
					      <el-tag>点击菜单链接</el-tag>
 | 
				
			||||||
 | 
					      【{{ item.eventKey }}】
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					    <div v-else-if="item.event === 'scancode_waitmsg'">
 | 
				
			||||||
 | 
					      <el-tag>扫码结果</el-tag>
 | 
				
			||||||
 | 
					      【{{ item.eventKey }}】
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					    <div v-else-if="item.event === 'scancode_push'">
 | 
				
			||||||
 | 
					      <el-tag>扫码结果</el-tag>
 | 
				
			||||||
 | 
					      【{{ item.eventKey }}】
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					    <div v-else-if="item.event === 'pic_sysphoto'">
 | 
				
			||||||
 | 
					      <el-tag>系统拍照发图</el-tag>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					    <div v-else-if="item.event === 'pic_photo_or_album'">
 | 
				
			||||||
 | 
					      <el-tag>拍照或者相册</el-tag>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					    <div v-else-if="item.event === 'pic_weixin'">
 | 
				
			||||||
 | 
					      <el-tag>微信相册</el-tag>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					    <div v-else-if="item.event === 'location_select'">
 | 
				
			||||||
 | 
					      <el-tag>选择地理位置</el-tag>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					    <div v-else>
 | 
				
			||||||
 | 
					      <el-tag type="danger">未知事件类型</el-tag>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					  </div>
 | 
				
			||||||
 | 
					</template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<script setup lang="ts">
 | 
				
			||||||
 | 
					const props = defineProps<{
 | 
				
			||||||
 | 
					  item: any
 | 
				
			||||||
 | 
					}>()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const item = ref(props.item)
 | 
				
			||||||
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<style scoped></style>
 | 
				
			||||||
							
								
								
									
										110
									
								
								src/views/mp/components/wx-msg/components/MsgList.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										110
									
								
								src/views/mp/components/wx-msg/components/MsgList.vue
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,110 @@
 | 
				
			|||||||
 | 
					<template>
 | 
				
			||||||
 | 
					  <div class="execution" v-for="item in props.list" :key="item.id">
 | 
				
			||||||
 | 
					    <div
 | 
				
			||||||
 | 
					      class="avue-comment"
 | 
				
			||||||
 | 
					      :class="{ 'avue-comment--reverse': item.sendFrom === SendFrom.MpBot }"
 | 
				
			||||||
 | 
					    >
 | 
				
			||||||
 | 
					      <div class="avatar-div">
 | 
				
			||||||
 | 
					        <img :src="getAvatar(item.sendFrom)" class="avue-comment__avatar" />
 | 
				
			||||||
 | 
					        <div class="avue-comment__author">
 | 
				
			||||||
 | 
					          {{ getNickname(item.sendFrom) }}
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					      <div class="avue-comment__main">
 | 
				
			||||||
 | 
					        <div class="avue-comment__header">
 | 
				
			||||||
 | 
					          <div class="avue-comment__create_time">{{ formatDate(item.createTime) }}</div>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					        <div
 | 
				
			||||||
 | 
					          class="avue-comment__body"
 | 
				
			||||||
 | 
					          :style="item.sendFrom === SendFrom.MpBot ? 'background: #6BED72;' : ''"
 | 
				
			||||||
 | 
					        >
 | 
				
			||||||
 | 
					          <!-- 【事件】区域 -->
 | 
				
			||||||
 | 
					          <MsgEvent v-if="item.type === MsgType.Event" :item="item" />
 | 
				
			||||||
 | 
					          <!-- 【消息】区域 -->
 | 
				
			||||||
 | 
					          <div v-else-if="item.type === MsgType.Text">{{ item.content }}</div>
 | 
				
			||||||
 | 
					          <div v-else-if="item.type === MsgType.Voice">
 | 
				
			||||||
 | 
					            <WxVoicePlayer :url="item.mediaUrl" :content="item.recognition" />
 | 
				
			||||||
 | 
					          </div>
 | 
				
			||||||
 | 
					          <div v-else-if="item.type === MsgType.Image">
 | 
				
			||||||
 | 
					            <a target="_blank" :href="item.mediaUrl">
 | 
				
			||||||
 | 
					              <img :src="item.mediaUrl" style="width: 100px" />
 | 
				
			||||||
 | 
					            </a>
 | 
				
			||||||
 | 
					          </div>
 | 
				
			||||||
 | 
					          <div
 | 
				
			||||||
 | 
					            v-else-if="item.type === MsgType.Video || item.type === 'shortvideo'"
 | 
				
			||||||
 | 
					            style="text-align: center"
 | 
				
			||||||
 | 
					          >
 | 
				
			||||||
 | 
					            <WxVideoPlayer :url="item.mediaUrl" />
 | 
				
			||||||
 | 
					          </div>
 | 
				
			||||||
 | 
					          <div v-else-if="item.type === MsgType.Link" class="avue-card__detail">
 | 
				
			||||||
 | 
					            <el-link type="success" :underline="false" target="_blank" :href="item.url">
 | 
				
			||||||
 | 
					              <div class="avue-card__title"><i class="el-icon-link"></i>{{ item.title }}</div>
 | 
				
			||||||
 | 
					            </el-link>
 | 
				
			||||||
 | 
					            <div class="avue-card__info" style="height: unset">{{ item.description }}</div>
 | 
				
			||||||
 | 
					          </div>
 | 
				
			||||||
 | 
					          <!-- TODO 芋艿:待完善 -->
 | 
				
			||||||
 | 
					          <div v-else-if="item.type === MsgType.Location">
 | 
				
			||||||
 | 
					            <WxLocation
 | 
				
			||||||
 | 
					              :label="item.label"
 | 
				
			||||||
 | 
					              :location-y="item.locationY"
 | 
				
			||||||
 | 
					              :location-x="item.locationX"
 | 
				
			||||||
 | 
					            />
 | 
				
			||||||
 | 
					          </div>
 | 
				
			||||||
 | 
					          <div v-else-if="item.type === MsgType.News" style="width: 300px">
 | 
				
			||||||
 | 
					            <!-- TODO 芋艿:待测试;详情页也存在类似的情况 -->
 | 
				
			||||||
 | 
					            <WxNews :articles="item.articles" />
 | 
				
			||||||
 | 
					          </div>
 | 
				
			||||||
 | 
					          <div v-else-if="item.type === MsgType.Music">
 | 
				
			||||||
 | 
					            <WxMusic
 | 
				
			||||||
 | 
					              :title="item.title"
 | 
				
			||||||
 | 
					              :description="item.description"
 | 
				
			||||||
 | 
					              :thumb-media-url="item.thumbMediaUrl"
 | 
				
			||||||
 | 
					              :music-url="item.musicUrl"
 | 
				
			||||||
 | 
					              :hq-music-url="item.hqMusicUrl"
 | 
				
			||||||
 | 
					            />
 | 
				
			||||||
 | 
					          </div>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					  </div>
 | 
				
			||||||
 | 
					</template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<script setup lang="ts" name="MsgList">
 | 
				
			||||||
 | 
					import WxVideoPlayer from '@/views/mp/components/wx-video-play'
 | 
				
			||||||
 | 
					import WxVoicePlayer from '@/views/mp/components/wx-voice-play'
 | 
				
			||||||
 | 
					import WxNews from '@/views/mp/components/wx-news'
 | 
				
			||||||
 | 
					import WxLocation from '@/views/mp/components/wx-location'
 | 
				
			||||||
 | 
					import WxMusic from '@/views/mp/components/wx-music'
 | 
				
			||||||
 | 
					import MsgEvent from './MsgEvent.vue'
 | 
				
			||||||
 | 
					import { formatDate } from '@/utils/formatTime'
 | 
				
			||||||
 | 
					import { MsgType, User } from '../types'
 | 
				
			||||||
 | 
					import avatarWechat from '@/assets/imgs/wechat.png'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const props = defineProps<{
 | 
				
			||||||
 | 
					  list: any[]
 | 
				
			||||||
 | 
					  accountId: number
 | 
				
			||||||
 | 
					  user: User
 | 
				
			||||||
 | 
					}>()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum SendFrom {
 | 
				
			||||||
 | 
					  User = 1,
 | 
				
			||||||
 | 
					  MpBot = 2
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const getAvatar = (sendFrom: SendFrom) =>
 | 
				
			||||||
 | 
					  sendFrom === SendFrom.User ? props.user.avatar : avatarWechat
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const getNickname = (sendFrom: SendFrom) =>
 | 
				
			||||||
 | 
					  sendFrom === SendFrom.User ? props.user.nickname : '公众号'
 | 
				
			||||||
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<style lang="scss" scoped>
 | 
				
			||||||
 | 
					/* 因为 joolun 实现依赖 avue 组件,该页面使用了 comment.scss、card.scc  */
 | 
				
			||||||
 | 
					@import '../comment.scss';
 | 
				
			||||||
 | 
					@import '../card.scss';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.avatar-div {
 | 
				
			||||||
 | 
					  text-align: center;
 | 
				
			||||||
 | 
					  width: 80px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					</style>
 | 
				
			||||||
@@ -7,123 +7,22 @@
 | 
				
			|||||||
-->
 | 
					-->
 | 
				
			||||||
<template>
 | 
					<template>
 | 
				
			||||||
  <ContentWrap>
 | 
					  <ContentWrap>
 | 
				
			||||||
    <div class="msg-div" :id="'msg-div' + nowStr">
 | 
					    <div class="msg-div" :id="msgDivId">
 | 
				
			||||||
      <!-- 加载更多 -->
 | 
					      <!-- 加载更多 -->
 | 
				
			||||||
      <div v-loading="loading"></div>
 | 
					      <div v-loading="loading"></div>
 | 
				
			||||||
      <div v-if="!loading">
 | 
					      <div v-if="!loading">
 | 
				
			||||||
        <div class="el-table__empty-block" v-if="loadMore" @click="loadingMore"
 | 
					        <div class="el-table__empty-block" v-if="hasMore" @click="loadMore"
 | 
				
			||||||
          ><span class="el-table__empty-text">点击加载更多</span></div
 | 
					          ><span class="el-table__empty-text">点击加载更多</span></div
 | 
				
			||||||
        >
 | 
					        >
 | 
				
			||||||
        <div class="el-table__empty-block" v-if="!loadMore"
 | 
					        <div class="el-table__empty-block" v-if="!hasMore"
 | 
				
			||||||
          ><span class="el-table__empty-text">没有更多了</span></div
 | 
					          ><span class="el-table__empty-text">没有更多了</span></div
 | 
				
			||||||
        >
 | 
					        >
 | 
				
			||||||
      </div>
 | 
					      </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      <!-- 消息列表 -->
 | 
					      <!-- 消息列表 -->
 | 
				
			||||||
      <div class="execution" v-for="item in list" :key="item.id">
 | 
					      <MsgList :list="list" :account-id="accountId" :user="user" />
 | 
				
			||||||
        <div class="avue-comment" :class="item.sendFrom === 2 ? 'avue-comment--reverse' : ''">
 | 
					 | 
				
			||||||
          <div class="avatar-div">
 | 
					 | 
				
			||||||
            <img
 | 
					 | 
				
			||||||
              :src="item.sendFrom === 1 ? user.avatar : mp.avatar"
 | 
					 | 
				
			||||||
              class="avue-comment__avatar"
 | 
					 | 
				
			||||||
            />
 | 
					 | 
				
			||||||
            <div class="avue-comment__author"
 | 
					 | 
				
			||||||
              >{{ item.sendFrom === 1 ? user.nickname : mp.nickname }}
 | 
					 | 
				
			||||||
            </div>
 | 
					 | 
				
			||||||
          </div>
 | 
					 | 
				
			||||||
          <div class="avue-comment__main">
 | 
					 | 
				
			||||||
            <div class="avue-comment__header">
 | 
					 | 
				
			||||||
              <div class="avue-comment__create_time">{{ formatDate(item.createTime) }}</div>
 | 
					 | 
				
			||||||
            </div>
 | 
					 | 
				
			||||||
            <div
 | 
					 | 
				
			||||||
              class="avue-comment__body"
 | 
					 | 
				
			||||||
              :style="item.sendFrom === 2 ? 'background: #6BED72;' : ''"
 | 
					 | 
				
			||||||
            >
 | 
					 | 
				
			||||||
              <!-- 【事件】区域 -->
 | 
					 | 
				
			||||||
              <div v-if="item.type === MsgType.Event && item.event === 'subscribe'">
 | 
					 | 
				
			||||||
                <el-tag type="success">关注</el-tag>
 | 
					 | 
				
			||||||
              </div>
 | 
					 | 
				
			||||||
              <div v-else-if="item.type === MsgType.Event && item.event === 'unsubscribe'">
 | 
					 | 
				
			||||||
                <el-tag type="danger">取消关注</el-tag>
 | 
					 | 
				
			||||||
              </div>
 | 
					 | 
				
			||||||
              <div v-else-if="item.type === MsgType.Event && item.event === 'CLICK'">
 | 
					 | 
				
			||||||
                <el-tag>点击菜单</el-tag>
 | 
					 | 
				
			||||||
                【{{ item.eventKey }}】
 | 
					 | 
				
			||||||
              </div>
 | 
					 | 
				
			||||||
              <div v-else-if="item.type === MsgType.Event && item.event === 'VIEW'">
 | 
					 | 
				
			||||||
                <el-tag>点击菜单链接</el-tag>
 | 
					 | 
				
			||||||
                【{{ item.eventKey }}】
 | 
					 | 
				
			||||||
              </div>
 | 
					 | 
				
			||||||
              <div v-else-if="item.type === MsgType.Event && item.event === 'scancode_waitmsg'">
 | 
					 | 
				
			||||||
                <el-tag>扫码结果</el-tag>
 | 
					 | 
				
			||||||
                【{{ item.eventKey }}】
 | 
					 | 
				
			||||||
              </div>
 | 
					 | 
				
			||||||
              <div v-else-if="item.type === MsgType.Event && item.event === 'scancode_push'">
 | 
					 | 
				
			||||||
                <el-tag>扫码结果</el-tag>
 | 
					 | 
				
			||||||
                【{{ item.eventKey }}】
 | 
					 | 
				
			||||||
              </div>
 | 
					 | 
				
			||||||
              <div v-else-if="item.type === MsgType.Event && item.event === 'pic_sysphoto'">
 | 
					 | 
				
			||||||
                <el-tag>系统拍照发图</el-tag>
 | 
					 | 
				
			||||||
              </div>
 | 
					 | 
				
			||||||
              <div v-else-if="item.type === MsgType.Event && item.event === 'pic_photo_or_album'">
 | 
					 | 
				
			||||||
                <el-tag>拍照或者相册</el-tag>
 | 
					 | 
				
			||||||
              </div>
 | 
					 | 
				
			||||||
              <div v-else-if="item.type === MsgType.Event && item.event === 'pic_weixin'">
 | 
					 | 
				
			||||||
                <el-tag>微信相册</el-tag>
 | 
					 | 
				
			||||||
              </div>
 | 
					 | 
				
			||||||
              <div v-else-if="item.type === MsgType.Event && item.event === 'location_select'">
 | 
					 | 
				
			||||||
                <el-tag>选择地理位置</el-tag>
 | 
					 | 
				
			||||||
              </div>
 | 
					 | 
				
			||||||
              <div v-else-if="item.type === MsgType.Event">
 | 
					 | 
				
			||||||
                <el-tag type="danger">未知事件类型</el-tag>
 | 
					 | 
				
			||||||
              </div>
 | 
					 | 
				
			||||||
              <!-- 【消息】区域 -->
 | 
					 | 
				
			||||||
              <div v-else-if="item.type === MsgType.Text">{{ item.content }}</div>
 | 
					 | 
				
			||||||
              <div v-else-if="item.type === MsgType.Voice">
 | 
					 | 
				
			||||||
                <WxVoicePlayer :url="item.mediaUrl" :content="item.recognition" />
 | 
					 | 
				
			||||||
              </div>
 | 
					 | 
				
			||||||
              <div v-else-if="item.type === MsgType.Image">
 | 
					 | 
				
			||||||
                <a target="_blank" :href="item.mediaUrl">
 | 
					 | 
				
			||||||
                  <img :src="item.mediaUrl" style="width: 100px" />
 | 
					 | 
				
			||||||
                </a>
 | 
					 | 
				
			||||||
              </div>
 | 
					 | 
				
			||||||
              <div
 | 
					 | 
				
			||||||
                v-else-if="item.type === MsgType.Video || item.type === 'shortvideo'"
 | 
					 | 
				
			||||||
                style="text-align: center"
 | 
					 | 
				
			||||||
              >
 | 
					 | 
				
			||||||
                <WxVideoPlayer :url="item.mediaUrl" />
 | 
					 | 
				
			||||||
              </div>
 | 
					 | 
				
			||||||
              <div v-else-if="item.type === MsgType.Link" class="avue-card__detail">
 | 
					 | 
				
			||||||
                <el-link type="success" :underline="false" target="_blank" :href="item.url">
 | 
					 | 
				
			||||||
                  <div class="avue-card__title"><i class="el-icon-link"></i>{{ item.title }}</div>
 | 
					 | 
				
			||||||
                </el-link>
 | 
					 | 
				
			||||||
                <div class="avue-card__info" style="height: unset">{{ item.description }}</div>
 | 
					 | 
				
			||||||
              </div>
 | 
					 | 
				
			||||||
              <!-- TODO 芋艿:待完善 -->
 | 
					 | 
				
			||||||
              <div v-else-if="item.type === MsgType.Location">
 | 
					 | 
				
			||||||
                <WxLocation
 | 
					 | 
				
			||||||
                  :label="item.label"
 | 
					 | 
				
			||||||
                  :location-y="item.locationY"
 | 
					 | 
				
			||||||
                  :location-x="item.locationX"
 | 
					 | 
				
			||||||
                />
 | 
					 | 
				
			||||||
              </div>
 | 
					 | 
				
			||||||
              <div v-else-if="item.type === MsgType.News" style="width: 300px">
 | 
					 | 
				
			||||||
                <!-- TODO 芋艿:待测试;详情页也存在类似的情况 -->
 | 
					 | 
				
			||||||
                <WxNews :articles="item.articles" />
 | 
					 | 
				
			||||||
              </div>
 | 
					 | 
				
			||||||
              <div v-else-if="item.type === MsgType.Music">
 | 
					 | 
				
			||||||
                <WxMusic
 | 
					 | 
				
			||||||
                  :title="item.title"
 | 
					 | 
				
			||||||
                  :description="item.description"
 | 
					 | 
				
			||||||
                  :thumb-media-url="item.thumbMediaUrl"
 | 
					 | 
				
			||||||
                  :music-url="item.musicUrl"
 | 
					 | 
				
			||||||
                  :hq-music-url="item.hqMusicUrl"
 | 
					 | 
				
			||||||
                />
 | 
					 | 
				
			||||||
              </div>
 | 
					 | 
				
			||||||
            </div>
 | 
					 | 
				
			||||||
          </div>
 | 
					 | 
				
			||||||
        </div>
 | 
					 | 
				
			||||||
      </div>
 | 
					 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    <div class="msg-send" v-loading="sendLoading">
 | 
					    <div class="msg-send" v-loading="sendLoading">
 | 
				
			||||||
      <WxReplySelect ref="replySelectRef" v-model="reply" />
 | 
					      <WxReplySelect ref="replySelectRef" v-model="reply" />
 | 
				
			||||||
      <el-button type="success" class="send-but" @click="sendMsg">发送(S)</el-button>
 | 
					      <el-button type="success" class="send-but" @click="sendMsg">发送(S)</el-button>
 | 
				
			||||||
@@ -132,18 +31,12 @@
 | 
				
			|||||||
</template>
 | 
					</template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<script setup lang="ts" name="WxMsg">
 | 
					<script setup lang="ts" name="WxMsg">
 | 
				
			||||||
import WxReplySelect from '@/views/mp/components/wx-reply'
 | 
					import WxReplySelect, { Reply, ReplyType } from '@/views/mp/components/wx-reply'
 | 
				
			||||||
import WxVideoPlayer from '@/views/mp/components/wx-video-play'
 | 
					import MsgList from './components/MsgList.vue'
 | 
				
			||||||
import WxVoicePlayer from '@/views/mp/components/wx-voice-play'
 | 
					 | 
				
			||||||
import WxNews from '@/views/mp/components/wx-news'
 | 
					 | 
				
			||||||
import WxLocation from '@/views/mp/components/wx-location'
 | 
					 | 
				
			||||||
import WxMusic from '@/views/mp/components/wx-music'
 | 
					 | 
				
			||||||
import { getMessagePage, sendMessage } from '@/api/mp/message'
 | 
					import { getMessagePage, sendMessage } from '@/api/mp/message'
 | 
				
			||||||
import { getUser } from '@/api/mp/user'
 | 
					import { getUser } from '@/api/mp/user'
 | 
				
			||||||
import { formatDate } from '@/utils/formatTime'
 | 
					 | 
				
			||||||
import profile from '@/assets/imgs/profile.jpg'
 | 
					import profile from '@/assets/imgs/profile.jpg'
 | 
				
			||||||
import wechat from '@/assets/imgs/wechat.png'
 | 
					import { User } from './types'
 | 
				
			||||||
import { MsgType } from './types'
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
const message = useMessage() // 消息弹窗
 | 
					const message = useMessage() // 消息弹窗
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -154,49 +47,30 @@ const props = defineProps({
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
})
 | 
					})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const nowStr = ref(new Date().getTime()) // 当前的时间戳,用于每次消息加载后,回到原位置;具体见 :id="'msg-div' + nowStr" 处
 | 
					const accountId = ref<number>(-1) // 公众号ID,需要通过userId初始化
 | 
				
			||||||
 | 
					const msgDivId = `msg-div-{new Date().getTime()}` // 当前的时间戳,用于每次消息加载后,回到原位置;具体见 :id="'msg-div' + nowStr" 处
 | 
				
			||||||
const loading = ref(false) // 消息列表是否正在加载中
 | 
					const loading = ref(false) // 消息列表是否正在加载中
 | 
				
			||||||
const loadMore = ref(true) // 是否可以加载更多
 | 
					const hasMore = ref(true) // 是否可以加载更多
 | 
				
			||||||
const list = ref<any[]>([]) // 消息列表
 | 
					const list = ref<any[]>([]) // 消息列表
 | 
				
			||||||
const queryParams = reactive({
 | 
					const queryParams = reactive({
 | 
				
			||||||
  pageNo: 1, // 当前页数
 | 
					  pageNo: 1, // 当前页数
 | 
				
			||||||
  pageSize: 14, // 每页显示多少条
 | 
					  pageSize: 14, // 每页显示多少条
 | 
				
			||||||
  accountId: undefined
 | 
					  accountId: accountId
 | 
				
			||||||
})
 | 
					})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
interface User {
 | 
					 | 
				
			||||||
  nickname: string
 | 
					 | 
				
			||||||
  avatar: string
 | 
					 | 
				
			||||||
  accountId: number
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
// 由于微信不再提供昵称,直接使用“用户”展示
 | 
					// 由于微信不再提供昵称,直接使用“用户”展示
 | 
				
			||||||
const user: User = reactive({
 | 
					const user: User = reactive({
 | 
				
			||||||
  nickname: '用户',
 | 
					  nickname: '用户',
 | 
				
			||||||
  avatar: profile,
 | 
					  avatar: profile,
 | 
				
			||||||
  accountId: 0 // 公众号账号编号
 | 
					  accountId: accountId // 公众号账号编号
 | 
				
			||||||
})
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
interface Mp {
 | 
					 | 
				
			||||||
  nickname: string
 | 
					 | 
				
			||||||
  avatar: string
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
const mp: Mp = reactive({
 | 
					 | 
				
			||||||
  nickname: '公众号',
 | 
					 | 
				
			||||||
  avatar: wechat
 | 
					 | 
				
			||||||
})
 | 
					})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// ========= 消息发送 =========
 | 
					// ========= 消息发送 =========
 | 
				
			||||||
const sendLoading = ref(false) // 发送消息是否加载中
 | 
					const sendLoading = ref(false) // 发送消息是否加载中
 | 
				
			||||||
interface Reply {
 | 
					 | 
				
			||||||
  type: MsgType
 | 
					 | 
				
			||||||
  accountId: number | null
 | 
					 | 
				
			||||||
  articles: any[]
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// 微信发送消息
 | 
					// 微信发送消息
 | 
				
			||||||
const reply = ref<Reply>({
 | 
					const reply = ref<Reply>({
 | 
				
			||||||
  type: MsgType.Text,
 | 
					  type: ReplyType.Text,
 | 
				
			||||||
  accountId: null,
 | 
					  accountId: -1,
 | 
				
			||||||
  articles: []
 | 
					  articles: []
 | 
				
			||||||
})
 | 
					})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -207,8 +81,7 @@ onMounted(async () => {
 | 
				
			|||||||
  const data = await getUser(props.userId)
 | 
					  const data = await getUser(props.userId)
 | 
				
			||||||
  user.nickname = data.nickname?.length > 0 ? data.nickname : user.nickname
 | 
					  user.nickname = data.nickname?.length > 0 ? data.nickname : user.nickname
 | 
				
			||||||
  user.avatar = user.avatar?.length > 0 ? data.avatar : user.avatar
 | 
					  user.avatar = user.avatar?.length > 0 ? data.avatar : user.avatar
 | 
				
			||||||
  user.accountId = data.accountId
 | 
					  accountId.value = data.accountId
 | 
				
			||||||
  queryParams.accountId = data.accountId
 | 
					 | 
				
			||||||
  reply.value.accountId = data.accountId
 | 
					  reply.value.accountId = data.accountId
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  refreshChange()
 | 
					  refreshChange()
 | 
				
			||||||
@@ -220,7 +93,11 @@ const sendMsg = async () => {
 | 
				
			|||||||
    return
 | 
					    return
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  // 公众号限制:客服消息,公众号只允许发送一条
 | 
					  // 公众号限制:客服消息,公众号只允许发送一条
 | 
				
			||||||
  if (reply.value.type === MsgType.News && reply.value.articles.length > 1) {
 | 
					  if (
 | 
				
			||||||
 | 
					    reply.value.type === ReplyType.News &&
 | 
				
			||||||
 | 
					    reply.value.articles &&
 | 
				
			||||||
 | 
					    reply.value.articles.length > 1
 | 
				
			||||||
 | 
					  ) {
 | 
				
			||||||
    reply.value.articles = [reply.value.articles[0]]
 | 
					    reply.value.articles = [reply.value.articles[0]]
 | 
				
			||||||
    message.success('图文消息条数限制在 1 条以内,已默认发送第一条')
 | 
					    message.success('图文消息条数限制在 1 条以内,已默认发送第一条')
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
@@ -229,18 +106,18 @@ const sendMsg = async () => {
 | 
				
			|||||||
  sendLoading.value = false
 | 
					  sendLoading.value = false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  list.value = [...list.value, ...[data]]
 | 
					  list.value = [...list.value, ...[data]]
 | 
				
			||||||
  scrollToBottom()
 | 
					  await scrollToBottom()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // 发送后清空数据
 | 
					  // 发送后清空数据
 | 
				
			||||||
  replySelectRef.value?.clear()
 | 
					  replySelectRef.value?.clear()
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const loadingMore = () => {
 | 
					const loadMore = () => {
 | 
				
			||||||
  queryParams.pageNo++
 | 
					  queryParams.pageNo++
 | 
				
			||||||
  getPage(queryParams, null)
 | 
					  getPage(queryParams, null)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const getPage = async (page, params) => {
 | 
					const getPage = async (page: any, params: any) => {
 | 
				
			||||||
  loading.value = true
 | 
					  loading.value = true
 | 
				
			||||||
  let dataTemp = await getMessagePage(
 | 
					  let dataTemp = await getMessagePage(
 | 
				
			||||||
    Object.assign(
 | 
					    Object.assign(
 | 
				
			||||||
@@ -254,7 +131,7 @@ const getPage = async (page, params) => {
 | 
				
			|||||||
    )
 | 
					    )
 | 
				
			||||||
  )
 | 
					  )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const msgDiv = document.getElementById('msg-div' + nowStr.value)
 | 
					  const msgDiv = document.getElementById(msgDivId)
 | 
				
			||||||
  let scrollHeight = 0
 | 
					  let scrollHeight = 0
 | 
				
			||||||
  if (msgDiv) {
 | 
					  if (msgDiv) {
 | 
				
			||||||
    scrollHeight = msgDiv.scrollHeight
 | 
					    scrollHeight = msgDiv.scrollHeight
 | 
				
			||||||
@@ -264,24 +141,23 @@ const getPage = async (page, params) => {
 | 
				
			|||||||
  list.value = [...data, ...list.value]
 | 
					  list.value = [...data, ...list.value]
 | 
				
			||||||
  loading.value = false
 | 
					  loading.value = false
 | 
				
			||||||
  if (data.length < queryParams.pageSize || data.length === 0) {
 | 
					  if (data.length < queryParams.pageSize || data.length === 0) {
 | 
				
			||||||
    loadMore.value = false
 | 
					    hasMore.value = false
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  queryParams.pageNo = page.pageNo
 | 
					  queryParams.pageNo = page.pageNo
 | 
				
			||||||
  queryParams.pageSize = page.pageSize
 | 
					  queryParams.pageSize = page.pageSize
 | 
				
			||||||
  // 滚动到原来的位置
 | 
					  // 滚动到原来的位置
 | 
				
			||||||
  if (queryParams.pageNo === 1) {
 | 
					  if (queryParams.pageNo === 1) {
 | 
				
			||||||
    // 定位到消息底部
 | 
					    // 定位到消息底部
 | 
				
			||||||
    scrollToBottom()
 | 
					    await scrollToBottom()
 | 
				
			||||||
  } else if (data.length !== 0) {
 | 
					  } else if (data.length !== 0) {
 | 
				
			||||||
    // 定位滚动条
 | 
					    // 定位滚动条
 | 
				
			||||||
    await nextTick(() => {
 | 
					    await nextTick()
 | 
				
			||||||
      if (scrollHeight !== 0) {
 | 
					    if (scrollHeight !== 0) {
 | 
				
			||||||
        let div = document.getElementById('msg-div' + nowStr.value)
 | 
					      let div = document.getElementById(msgDivId)
 | 
				
			||||||
        if (div && msgDiv) {
 | 
					      if (div && msgDiv) {
 | 
				
			||||||
          msgDiv.scrollTop = div.scrollHeight - scrollHeight - 100
 | 
					        msgDiv.scrollTop = div.scrollHeight - scrollHeight - 100
 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    })
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -290,26 +166,16 @@ const refreshChange = () => {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/** 定位到消息底部 */
 | 
					/** 定位到消息底部 */
 | 
				
			||||||
const scrollToBottom = () => {
 | 
					const scrollToBottom = async () => {
 | 
				
			||||||
  nextTick(() => {
 | 
					  await nextTick()
 | 
				
			||||||
    let div = document.getElementById('msg-div' + nowStr.value)
 | 
					  let div = document.getElementById(msgDivId)
 | 
				
			||||||
    if (div) {
 | 
					  if (div) {
 | 
				
			||||||
      div.scrollTop = div.scrollHeight
 | 
					    div.scrollTop = div.scrollHeight
 | 
				
			||||||
    }
 | 
					  }
 | 
				
			||||||
  })
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
</script>
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<style lang="scss" scoped>
 | 
					<style lang="scss" scoped>
 | 
				
			||||||
/* 因为 joolun 实现依赖 avue 组件,该页面使用了 comment.scss、card.scc  */
 | 
					 | 
				
			||||||
@import './comment.scss';
 | 
					 | 
				
			||||||
@import './card.scss';
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
.msg-main {
 | 
					 | 
				
			||||||
  margin-top: -30px;
 | 
					 | 
				
			||||||
  padding: 10px;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
.msg-div {
 | 
					.msg-div {
 | 
				
			||||||
  height: 50vh;
 | 
					  height: 50vh;
 | 
				
			||||||
  overflow: auto;
 | 
					  overflow: auto;
 | 
				
			||||||
@@ -322,11 +188,6 @@ const scrollToBottom = () => {
 | 
				
			|||||||
  padding: 10px;
 | 
					  padding: 10px;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.avatar-div {
 | 
					 | 
				
			||||||
  text-align: center;
 | 
					 | 
				
			||||||
  width: 80px;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
.send-but {
 | 
					.send-but {
 | 
				
			||||||
  float: right;
 | 
					  float: right;
 | 
				
			||||||
  margin-top: 8px;
 | 
					  margin-top: 8px;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -9,3 +9,9 @@ export enum MsgType {
 | 
				
			|||||||
  Music = 'music',
 | 
					  Music = 'music',
 | 
				
			||||||
  News = 'news'
 | 
					  News = 'news'
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export interface User {
 | 
				
			||||||
 | 
					  nickname: string
 | 
				
			||||||
 | 
					  avatar: string
 | 
				
			||||||
 | 
					  accountId: number
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user