實時聊天 Vue + Vuex + sockjs-client + stompjs進行websocket連接

實時聊天

  • 知識點
    • WebSocket介紹
    • SockJS
    • STOMP
  • 開發環境
  • 功能實現
    • 安裝應用
    • 在vuex中創建
    • vue中的引入、監聽、實例化與收發、訂閱消息
      • 引入組件
      • 實例化與訂閱
      • 計算屬性
      • 監聽收到消息
      • 封裝的發送消息的公共方法
      • 發送消息
  • 完整的代碼

知識點

WebSocket介紹

WebSocket 是一種在 Web 應用中實現實時通信的方法,它可以在客戶端和服務器端之間建立長連接,實現實時消息傳遞。

SockJS

SockJS 是一個 JavaScript 庫,用于在瀏覽器和 Web 服務器之間建立實時通信連接。它提供了一個 WebSocket 的備選方案,并兼容多種瀏覽器和 Web 服務器。SockJS 會自動檢測瀏覽器是否支持 WebSocket,如果不支持,則會自動降級為其他協議(如 long polling、iframe、JSONP 等)

STOMP

STOMP即Simple (or Streaming) Text Orientated Messaging Protocol,簡單(流)文本定向消息協議,它提供了一個可互操作的連接格式,允許STOMP客戶端與任意STOMP消息代理(Broker)進行交互。
簡單地說,stomp是一個用于client之間進行異步消息傳輸的簡單文本協議

開發環境

"sockjs-client": "^1.5.1",
"stompjs": "^2.3.3",
"vue": "^2.6.10",
"vuex": "^3.6.2"
// 本地Node版本號
node v14.7.0

功能實現

安裝應用

npm install sockjs-client --save
npm install stompjs --save

在vuex中創建

const call = {state: {websocketUrl: 'https://app.lzzgh.org.cn/lz72hourApi',stompClient: '', // websocketsendContent: "",//發送的數據userPhone: "",//給對方發送消息對方的userPhonechatType: "",//聊天的方式 1:單聊 2:群聊activitySign:false,//是否參加活動groupContent:"",//群聊發送數據groupCPContent:"", // cp小屋的clears:false,//清空消息},getters: {getWebsocketUrl: state => {return state.websocketUrl},getWebsocket: state => {return state.stompClient},getSendContent: state => {return state.sendContent},getGroupContent: state => {return state.groupContent},getGroupCPContent: state => {return state.groupCPContent},getUserPhone: state => {return state.userPhone},getChatType: state => {return state.chatType},getActivitySign:state =>{return state.activitySign},getClears:state =>{return state.clears}},mutations: {setMyWebsocket(state, stompClient) {state.stompClient = stompClient},setMySendContent(state, sendContent) {state.sendContent = sendContent},setMyGroupContent(state, groupContent) {state.groupContent = groupContent},setMyGroupCPContent(state, groupCPContent) {state.groupCPContent = groupCPContent},setMyUserPhone(state, userPhone) {state.userPhone = userPhone},setMyChatType(state, chatType) {state.chatType = chatType},setMyActivitySign(state){state.activitySign = !state.activitySign},setMyClears(state){state.clears = !state.clears}},actions: {setWebsocket({ commit }, stompClient) {commit('setMyWebsocket', { stompClient })},setSendContent({ commit }, sendContent) {commit('setMySendContent', { sendContent })},setGroupContent({ commit }, groupContent) {commit('setMyGroupContent', { groupContent })},setGroupCPContent({ commit }, groupCPContent) {commit('setMyGroupCPContent', { groupCPContent })},setUserPhone({ commit }, userPhone) {commit('setMyUserPhone', { userPhone })},setChatType({ commit }, chatType) {commit('setMyChatType', { chatType })}}
}
export default call

vue中的引入、監聽、實例化與收發、訂閱消息

引入組件

import { mapGetters } from "vuex";
import Video from "@/components/video"; //播放
import { imgPreview } from "@/utils/comperssImage.js"; //壓縮圖片
import { judgeTime } from "@/utils/base.js"; //時間顯示
import { Picker } from "emoji-mart-vue"; //引入表情組件
import SockJS from  'sockjs-client';
import  Stomp from 'stompjs';

實例化與訂閱

init(){ axios.defaults.baseURL=this.websocketUrlaxios.defaults.headers={ "X-Access-Token": Vue.ls.get(ACCESS_TOKEN)}if (typeof WebSocket === "undefined") {alert("您的瀏覽器不支持socket");} else {console.log(this.websocketUrl)// 實例化let socket = new SockJS(this.websocketUrl + "/jeecg-boot/websocket",undefined, { timeout: 10000 });this.stompClient = Stomp.over(socket);this.$store.commit("setMyWebsocket", this.stompClient);let that = this;console.log(Vue.ls.get(ACCESS_TOKEN))// 訂閱this.stompClient.connect({ "X-Access-Token": Vue.ls.get(ACCESS_TOKEN) }, function (frame) {that.isConnent = true;that.stompClient.subscribe("/topic/" + that.chatRoomId,function (response) {let data = response.body;that.$store.commit("setMyGroupCPContent", data);console.log("小屋" + response.body);});})}},

計算屬性

computed: {...mapGetters({userInfo: "getUserInfo", //獲取用戶信息websocketUrl: "getWebsocketUrl",// stompClient: "getWebsocket", //獲取websocket// sendContent: "getSendContent", //獲取實時聊天信息sendContent: "getGroupCPContent", //獲取實時聊天信息}),},

監聽收到消息

watch: {sendContent() {debuggerToast.clear();let datas = JSON.parse(this.sendContent);if (datas.code == 500) {Dialog.alert({message: datas.message,}).then(() => {// on closethis.$router.go(-1);});return;}this.message = "";this.quoteText = "";this.quoteValue = null;this.smileShow = false;let mesItem = datas.result;mesItem.isOprate = false;if (mesItem.messageType == "6") {mesItem.poster = this.getImgView(mesItem.messageValue);}if (mesItem.quoteValue) {mesItem.quoteValue = JSON.parse(mesItem.quoteValue);}if (mesItem.delFlag == "1") {if (mesItem.memberId == this.myInfo.id &&mesItem.chatRoomId == this.chatRoomId) {Dialog.alert({message: "您已被踢出群聊,暫時不能參與會話!",confirmButtonText: "返回到首頁",}).then(() => {// on closethis.$router.replace("/index");});}} else {let time = mesItem.createTime;if (mesItem.chatRoomId == this.chatRoomId) {if (this.talkArr.length > 0 &&new Date(time.replace(/\-/g, "/")).getTime() -new Date(this.talkArr[this.talkArr.length - 1].createTime.replace(/\-/g,"/")).getTime() <=5 * 60 * 1000) {this.talkArr[this.talkArr.length - 1].mesList.push(mesItem);} else {this.talkArr.push({createTime: time,time: judgeTime(time),mesList: [mesItem],});}console.log(this.talkArr)debuggerthis.seeMsg();if (!this.isLoading) {this.scrollBottom();}}}},},

封裝的發送消息的公共方法

sendFun(messageType, messageValue, quoteValue) {// console.log(messageValue)Toast.loading({duration: 0, // 持續展示 toastmessage: "發送中...",forbidClick: true,});let date = new Date();let createTime = date.getTime();let prm=JSON.stringify({chatRoomId: this.chatRoomId, //群聊idmessageType: messageType, //1文字,5圖片,6視頻,7求手機號、8求微信號、9發手機號、10發微信號messageValue: messageValue, //發送信息// userPhone: this.myInfo.userPhone, //用戶手機號// fullName: this.myInfo.fullName, //用戶名// userIcon: this.myInfo.userIcon, //用戶頭像// memberId: this.myInfo.id, //用戶idmemberId: sessionStorage.getItem('clientId'), //用戶id// createTime: createTime, //創建時間// sex: this.myInfo.sex, //性別quoteValue: JSON.stringify(quoteValue), //引用的內容})console.log(prm)this.stompClient.send("/app/chatRoom",{},prm);},

發送消息

//發送消息sendMsg() {const that = this;if (this.message) {this.sendFun("1", this.message, this.quoteValue);// that.message = "";// that.quoteText = "";// that.quoteValue = null;} else {Toast("內容不能為空!");}},

完整的代碼

聊天的完整代碼,包括websocket的應用,(實例化,存vuex,訂閱,收發消息),表情,上傳圖片,視頻,歷史記錄,時間顯示,長鏈接的建立與銷毀等

<template><div class="groupChatInf"><!-- <NavBar :title="title"></NavBar> --><div class="chatInf"><div class="chatBox" id="chat"><van-pull-refresh v-model="isLoading" @refresh="onRefresh"><div class="chatOne" v-for="(item, i) in talkArr" :key="i"><div class="date">{{ item.time }}</div><div v-for="(items, is) in item.mesList" :key="is"><divclass="welcome"v-html="welcome"v-if="welcome && items.messageType == '4'"></div><div v-if="items.messageType != '4'"><divclass="chatMine"v-if="items.userPhone == myInfo.userPhone"><divclass="chatImg"v-if="items.messageType != '12' && items.messageType != '15'"><van-image:src="items.userIcon"fit="cover"v-if="items.userIcon"><template v-slot:loading><van-loading type="spinner" size="20" /></template><template v-slot:error>加載失敗</template></van-image><imgsrc="~@/assets/img/redGirl.png"alt=""v-else-if="items.memberId == 9999999"class="imgs"/><imgsrc="~@/assets/img/girlHeadImg.png"alt=""v-else-if="items.sex == 'F'"class="imgs"/><imgsrc="~@/assets/img/boyHeadImg.png"alt=""class="imgs"v-else/></div><divclass="chatName"v-if="items.messageType != '12' && items.messageType != '15'"><i v-if="items.isAdmin == '1'"><img src="~@/assets/img/manage2.png"/></i><i v-if="items.isAdmin == '2'"><img src="~@/assets/img/manage1.png"/></i></div><div class="chatvalueDiv" v-if="items.messageType == '1'"><divclass="chatText"@touchstart="touchstart(items)"@touchend="touchend">{{ items.messageValue }}</div><divclass="chatOprateMask"v-if="items.isOprate"@click="closeMask(items)"></div><div class="chatOprate" v-if="items.isOprate"><span @click="quoteChat(items)">引用</span><span @click="delChat(items)">刪除</span><span @click="copyChat(items)">復制</span><span @click="recallChat(items)">撤回</span></div></div><div class="chatvalueDiv" v-if="items.messageType == '5'"><divclass="chatImage"@click="imgPreview(items.messageValue)"><img :src="items.messageValue" alt="" /></div><divclass="chatOprateMask"v-if="items.isOprate"@click="closeMask(items)"></div><div class="chatOprate" v-if="items.isOprate"><span @click="quoteChat(items)">引用</span><span @click="delChat(items)">刪除</span><span @click="copyChat(items)">復制</span><span @click="recallChat(items)">撤回</span></div></div><div class="chatvalueDiv" v-if="items.messageType == '6'"><div class="chatVideo"><video:src="items.messageValue":poster="items.poster"></video><divclass="chatmask"@click="videoPlay(items.messageValue, items.poster)"><img src="~@/assets/bofang.png" alt="" /></div></div><divclass="chatOprateMask"v-if="items.isOprate"@click="closeMask(items)"></div><div class="chatOprate" v-if="items.isOprate"><span @click="quoteChat(items)">引用</span><span @click="delChat(items)">刪除</span><span @click="copyChat(items)">復制</span><span @click="recallChat(items)">撤回</span></div></div><divclass="chatvalueDiv"v-if="items.quoteValue && items.messageType != '12'"><divclass="quoteValue"v-if="items.quoteValue.messageType == '1'">@{{items.quoteValue.fullName +items.quoteValue.messageValue}}</div><divclass="quoteImg"v-else-if="items.quoteValue.messageType == '5'"><p>@{{ items.quoteValue.fullName }}</p><img:src="items.quoteValue.messageValue"alt=""class="qimgs"@click="imgPreview(items.quoteValue.messageValue)"/></div><divclass="quoteImg"v-else-if="items.quoteValue.messageType == '6'"><p>@{{ items.quoteValue.fullName }}</p><div class="quoteVideo"><video:src="items.quoteValue.messageValue":poster="items.quoteValue.poster"></video><divclass="chatmask"@click="videoPlay(items.quoteValue.messageValue,items.quoteValue.poster)"><img src="~@/assets/bofang.png" alt="" /></div></div></div></div><div class="chatRecall" v-if="items.messageType == '12'">消息已撤回 <a @click="reEdit(items)">重新編輯</a></div></div><div class="chatOther" v-else><divclass="chatImg"@click="toPerson(items.memberId)"v-if="items.messageType != '12' && items.messageType != '15'"><van-image:src="items.userIcon"fit="cover"v-if="items.userIcon"><template v-slot:loading><van-loading type="spinner" size="20" /></template><template v-slot:error>加載失敗</template></van-image><imgsrc="~@/assets/img/girlHeadImg.png"alt=""v-else-if="items.sex == 'F'"class="imgs"/><imgsrc="~@/assets/img/boyHeadImg.png"alt=""class="imgs"v-else/><imgsrc="~@/assets/img/woman.png"alt=""class="sex"v-if="items.sex == 'F'"/><imgsrc="~@/assets/img/man.png"alt=""class="sex"v-if="items.sex == 'M'"/></div><divclass="chatName"v-if="items.messageType != '12' && items.messageType != '15'">{{ items.fullName}}<i v-if="items.isAdmin == '1'"><img src="~@/assets/img/manage2.png"/></i><i v-if="items.isAdmin == '2'"><img src="~@/assets/img/manage1.png"/></i></div><div class="chatvalueDiv" v-if="items.messageType == '1'"><divclass="chatText"@touchstart="touchstart(items)"@touchend="touchend">{{ items.messageValue }}</div><divclass="chatOprateMask"v-if="items.isOprate"@click="closeMask(items)"></div><div class="chatOprate" v-if="items.isOprate"><span @click="quoteChat(items)">引用</span><span @click="delChat(items)">刪除</span><span @click="copyChat(items)">復制</span></div></div><div class="chatvalueDiv" v-if="items.messageType == '5'"><divclass="chatImage"@click="imgPreview(items.messageValue)"><img :src="items.messageValue" alt="" /></div><divclass="chatOprateMask"v-if="items.isOprate"@click="closeMask(items)"></div><div class="chatOprate" v-if="items.isOprate"><span @click="quoteChat(items)">引用</span><span @click="delChat(items)">刪除</span><span @click="copyChat(items)">復制</span></div></div><div class="chatvalueDiv" v-if="items.messageType == '6'"><div class="chatVideo"><video:src="items.messageValue":poster="items.poster"></video><divclass="chatmask"@click="videoPlay(items.messageValue, items.poster)"><img src="~@/assets/bofang.png" alt="" /></div></div><divclass="chatOprateMask"v-if="items.isOprate"@click="closeMask(items)"></div><div class="chatOprate" v-if="items.isOprate"><span @click="quoteChat(items)">引用</span><span @click="delChat(items)">刪除</span><span @click="copyChat(items)">復制</span></div></div><divclass="chatvalueDiv"v-if="items.quoteValue && items.messageType != '12'"><divclass="quoteValue"v-if="items.quoteValue.messageType == '1'">@{{items.quoteValue.fullName +items.quoteValue.messageValue}}</div><divclass="quoteImg"v-else-if="items.quoteValue.messageType == '5'"><p>@{{ items.quoteValue.fullName }}</p><img:src="items.quoteValue.messageValue"alt=""class="qimgs"@click="imgPreview(items.quoteValue.messageValue)"/></div><divclass="quoteImg"v-else-if="items.quoteValue.messageType == '6'"><p>@{{ items.quoteValue.fullName }}</p><div class="quoteVideo"><video:src="items.quoteValue.messageValue":poster="items.quoteValue.poster"></video><divclass="chatmask"@click="videoPlay(items.quoteValue.messageValue,items.quoteValue.poster)"><img src="~@/assets/bofang.png" alt="" /></div></div></div></div><div class="chatRecall" v-if="items.messageType == '12'">{{ items.fullName }}撤回了一條消息</div><div class="chatRecall" v-if="items.messageType == '15'"><a>{{ items.createBy }}</a>加入了群聊</div></div></div></div></div></van-pull-refresh></div></div><div class="sendBox"><div class="sendBoxTop"><form><!-- @click="toMember" --><span class="sendMember" ><img src="~@/assets/img/member.png" alt="" /></span><van-fieldclass="sendInf"v-model="message":border="false"style="border: 0px;"@keyup.enter.native="sendMsg"/><div class="quoteMessage" v-if="quoteText"><p class="quoteText">{{ quoteText }}</p><imgsrc="~@/assets/img/mclose.png"alt=""class="quoteClose"@click="quoteClose"/></div><span class="sendExpression" @click="smile"><img src="~@/assets/img/smile.png" alt="" /></span><span class="sendBtn" @click="sendMsg"><img src="~@/assets/img/sendBtn.png" alt=""/></span></form></div><div class="emojiBox" @select="addEmoji" v-if="smileShow"><div class="emojiDiv"><spanv-for="(item, index) in emojiList":key="'e-' + index"@click="chooseEmoji(item)">{{ item.emoji }}</span></div></div><!-- <picker:include="['people', 'Smileys']":showSearch="false":showPreview="false":showCategories="false"@select="addEmoji"v-if="smileShow"/> --><div class="sendBoxBtm" v-if="!smileShow"><div class="sendOprate"><img src="~@/assets/img/micon1.png" alt="" /><van-uploader:after-read="afterRead"upload-icon="plus":before-read="beforeRead"accept="image/png,image/jpg,image/jpeg,video/mp4,video/mov":max-count="1"/></div><div class="sendOprate"><img src="~@/assets/img/micon2.png" alt="" /><!--是蘋果手機直接調用攝像頭--><van-uploader:after-read="afterReadVideo"upload-icon="plus":before-read="beforeReadVideo"accept="image/png,image/jpg,image/jpeg,video/mp4,video/mov":max-count="1"capture="camera"v-if="isIos"/><!--不是蘋果手機先調起相冊--><van-uploader:after-read="afterReadVideo"upload-icon="plus":before-read="beforeReadVideo"accept="image/png,image/jpg,image/jpeg,video/mp4,video/mov":max-count="1"v-if="!isIos"/></div><div class="sendOprate"><img src="~@/assets/img/nowx.png" alt="" /></div><div class="sendOprate"><img src="~@/assets/img/nophone.png" alt="" /></div></div></div><Video:videoPath="videoPath"v-if="videoShow"@videoFun="videoFun":posterPath="posterPath"></Video></div>
</template><script>
import {Image as vanImage,Toast,PullRefresh,Field,Loading,Dialog,ImagePreview,Uploader,
} from "vant";
import { mapGetters } from "vuex";
import Video from "@/components/video"; //播放
import { imgPreview } from "@/utils/comperssImage.js"; //壓縮圖片
import { judgeTime } from "@/utils/base.js"; //時間顯示
import { Picker } from "emoji-mart-vue"; //引入表情組件
import SockJS from  'sockjs-client';
import  Stomp from 'stompjs';
import Vue from 'vue'
import { ACCESS_TOKEN } from '@/store/mutation-types'
import axios from 'axios'export default {name: "GroupChat",components: {[vanImage.name]: vanImage,[Field.name]: Field,[PullRefresh.name]: PullRefresh,[Loading.name]: Loading,[Uploader.name]: Uploader,Video,Picker,},props:{records:{type: Object,default: ()=>({})}},data() {return {stompClient:"",message: "", //發送內容talkArr: [], //聊天信息title: "聊天", //標題isToday: false, //是否是今天isLoading: false, //是否在加載中params: {chatRoomId: "", //群聊idpageNo: 1, //頁數pageSize: 50, //每頁數據數量oldMesId: "", //最后一條消息id}, //群聊查詢歷史數據參數chatRoomId: "", //群聊idallPage: 0, //歷史消息總頁數myInfo: {}, //個人信息welcome: "", //歡迎信息isFirst: true, //是否首次進入quoteText: "", //引用的文字videoShow: false, //播放器插件是否出現videoPath: "", //視頻路徑posterPath: "", //默認圖路徑touch: null, //長按方法定時器reMessage: "", //要重新編輯的信息fileList: [], //上傳圖片視頻返回值videoList: [], //拍攝返回值isIos: false, //是否是蘋果手機quoteValue: null, //引用的詳細信息isClick: true, //操作按鈕是否可以點擊smileShow: false, //imgUrl:'',};},computed: {...mapGetters({userInfo: "getUserInfo", //獲取用戶信息websocketUrl: "getWebsocketUrl",// stompClient: "getWebsocket", //獲取websocket// sendContent: "getSendContent", //獲取實時聊天信息sendContent: "getGroupCPContent", //獲取實時聊天信息}),},watch: {sendContent() {debuggerToast.clear();let datas = JSON.parse(this.sendContent);if (datas.code == 500) {Dialog.alert({message: datas.message,}).then(() => {// on closethis.$router.go(-1);});return;}this.message = "";this.quoteText = "";this.quoteValue = null;this.smileShow = false;let mesItem = datas.result;mesItem.isOprate = false;if (mesItem.messageType == "6") {mesItem.poster = this.getImgView(mesItem.messageValue);}if (mesItem.quoteValue) {mesItem.quoteValue = JSON.parse(mesItem.quoteValue);}if (mesItem.delFlag == "1") {if (mesItem.memberId == this.myInfo.id &&mesItem.chatRoomId == this.chatRoomId) {Dialog.alert({message: "您已被踢出群聊,暫時不能參與會話!",confirmButtonText: "返回到首頁",}).then(() => {// on closethis.$router.replace("/index");});}} else {let time = mesItem.createTime;if (mesItem.chatRoomId == this.chatRoomId) {if (this.talkArr.length > 0 &&new Date(time.replace(/\-/g, "/")).getTime() -new Date(this.talkArr[this.talkArr.length - 1].createTime.replace(/\-/g,"/")).getTime() <=5 * 60 * 1000) {this.talkArr[this.talkArr.length - 1].mesList.push(mesItem);} else {this.talkArr.push({createTime: time,time: judgeTime(time),mesList: [mesItem],});}console.log(this.talkArr)debuggerthis.seeMsg();if (!this.isLoading) {this.scrollBottom();}}}},},created() {this.imgUrl=this.websocketUrl+'/jeecg-boot/sys/common/static'const that = this;const UA = navigator.userAgent;const isIpad = /(iPad).*OS\s([\d_]+)/.test(UA);const isIpod = /(iPod)(.*OS\s([\d_]+))?/.test(UA);const isIphone = !isIpad && /(iPhone\sOS)\s([\d_]+)/.test(UA);this.isIos = isIpad || isIpod || isIphone;if (this.$route.query.activityName) {this.title = this.$route.query.activityName;}this.type = this.$route.query.type;if (this.$route.query.activityId) {this.chatRoomId = this.$route.query.activityId;this.params.chatRoomId = this.$route.query.activityId;}console.log(this.records)this.chatRoomId = this.records.chatId;this.params.chatRoomId = this.records.chatId;this.init()// this.getpersonfo();//查看未讀消息this.seeMsg();//獲取歷史消息this.getHistory();this.getEmoji();},// mounted() {},destroyed() {// 取消訂閱this.stompClient.unsubscribe('/topic/'+this.chatRoomId)// 銷毀連接this.stompClient.disconnect()}, methods: {// 初始化init(){axios.defaults.baseURL=this.websocketUrlaxios.defaults.headers={ "X-Access-Token": Vue.ls.get(ACCESS_TOKEN)}if (typeof WebSocket === "undefined") {alert("您的瀏覽器不支持socket");} else {console.log(this.websocketUrl)let socket = new SockJS(this.websocketUrl + "/jeecg-boot/websocket",undefined, { timeout: 10000 });this.stompClient = Stomp.over(socket);this.$store.commit("setMyWebsocket", this.stompClient);let that = this;console.log(Vue.ls.get(ACCESS_TOKEN))this.stompClient.connect({ "X-Access-Token": Vue.ls.get(ACCESS_TOKEN) }, function (frame) {that.isConnent = true;that.stompClient.subscribe("/topic/" + that.chatRoomId,function (response) {let data = response.body;that.$store.commit("setMyGroupCPContent", data);console.log("小屋" + response.body);});})}},//獲取表情包getEmoji() {axios.get("/jeecg-boot/api/emoji/emojiList").then((res) => {if (res.code == 200) {this.emojiList = res.result;}}).catch(() => {});},//獲取個人資料getpersonfo() {axios.get("/jeecg-boot/api/member/memberDetails").then((res) => {if (res.code == 200) {this.myInfo = res.result;}}).catch(() => {});},//發送消息sendMsg() {const that = this;if (this.message) {this.sendFun("1", this.message, this.quoteValue);// that.message = "";// that.quoteText = "";// that.quoteValue = null;} else {Toast("內容不能為空!");}},//查看未讀消息seeMsg() {axios.get("/jeecg-boot/api/releaseLog/seePcReleaseLog", {params:{type: 2,chatRoomId: this.chatRoomId,}}).then((res) => {}).catch(() => {});},//刷新歷史消息onRefresh() {this.getHistory();// if (this.params.pageNo <= this.allPage) {//   this.getHistory();// } else {//   this.isLoading = false;// }},//查看歷史消息getHistory() {const that = this;axios.get("/jeecg-boot/api/memberMessage/historyCpMsgList", {params:this.params} ).then((res) => {// console.log(res);res=res.dataif (res.result.records.length == 0) {if (!this.isFirst) {Toast("沒有更多數據了");}}res.result.records.forEach((item) => {let mesItem = item;let time = mesItem.createTime;if (mesItem.messageType == "6") {mesItem.poster = that.getImgView(mesItem.messageValue);}mesItem.isOprate = false;if (mesItem.quoteValue) {mesItem.quoteValue = JSON.parse(mesItem.quoteValue);}if (mesItem.chatRoomId == this.chatRoomId) {if (mesItem.messageType == "4") {this.welcome = mesItem.messageValue.replace(/\r\n/g, "<br>");this.welcome = this.welcome.replace(/\n/g, "<br>");}if (this.talkArr.length > 0) {let time1 = new Date(time.replace(/\-/g, "/")).getTime();let time2 = new Date(that.talkArr[0].createTime.replace(/\-/g, "/")).getTime();let diff = 0;if (parseInt(time1) >= parseInt(time2)) {diff = parseInt(time1) - parseInt(time2);} else {diff = parseInt(time2) - parseInt(time1);}if (diff <= 5 * 60 * 1000) {that.talkArr[0].mesList.unshift(mesItem);} else {that.talkArr.unshift({createTime: time,time: judgeTime(time),mesList: [mesItem],});}} else {that.talkArr.unshift({createTime: time,time: judgeTime(time),mesList: [mesItem],});}}});// Toast("刷新成功");this.isLoading = false;this.allPage = res.result.pages;this.params.oldMesId =res.result.records[res.result.records.length - 1].id;if (this.isFirst) {that.isFirst = false;that.scrollBottom();}}).catch(() => {});},//去個人主頁toPerson(id) {if (id) {this.$router.push({ path: "/person", query: { id: id } });}},//去聊天室信息頁面toMember() {this.$router.push({path: "/groupMember",query: { activityId: this.chatRoomId },});},scrollBottom() {this.$nextTick((res) => {let div = document.getElementById("chat");div.scrollTop = div.scrollHeight;});},//選擇表情smile() {this.smileShow = !this.smileShow;},//查看大圖imgPreview(src) {// ImagePreview([src]);},//視頻播放videoPlay(path, poster) {this.videoPath = path;this.posterPath = poster;this.videoShow = true;},//videoFun(visible) {this.videoShow = visible;this.posterPath = "";this.videoPath = "";},/* 視頻取第一秒截圖 */getImgView(text) {return text + "?x-oss-process=video/snapshot,t_1000";},// 在屏幕上時觸發touchstart(items) {clearTimeout(this.touch); //再次清空定時器,防止重復注冊定時器this.touch = setTimeout(() => {items.isOprate = true;this.$forceUpdate();}, 800);},//離開屏幕時觸發touchend() {clearTimeout(this.touch); //再次清空定時器,防止重復注冊定時器},//點擊任意地方關閉操作closeMask(items) {items.isOprate = false;this.$forceUpdate();},//重新編輯reEdit() {this.message = this.reMessage;},//引用quoteChat(items) {if (items.messageType == "1") {this.quoteText = "@" + items.fullName + " " + items.messageValue;} else if (items.messageType == "5") {this.quoteText = "@" + items.fullName + " [圖片]";} else if (items.messageType == "6") {this.quoteText = "@" + items.fullName + " [視頻]";}this.quoteValue = items;items.isOprate = false;this.$forceUpdate();},//清楚引用quoteClose() {this.quoteText = "";this.quoteValue = null;},//刪除delChat(items) {if (this.isClick) {this.isClick = false;this.$fetch("/jeecg-boot/api/memberMessage/delMessageLog", {messageLogId: items.id,}).then((res) => {if (res.code == 200) {Toast("消息刪除成功");items.isOprate = false;items.delFlag = "1";this.$forceUpdate();} else {Toast(res.message);}this.isClick = true;}).catch(() => {this.isClick = true;});}},//復制copyChat(items) {this.copeText(items);},//撤回recallChat(items) {if (this.isClick) {this.isClick = false;this.$fetch("/jeecg-boot/api/memberMessage/delMessageLog", {messageLogId: items.id,messageType: 12,}).then((res) => {if (res.code == 200) {Toast("消息撤回成功");items.isOprate = false;items.messageType = "12";this.$forceUpdate();} else {Toast(res.message);}this.isClick = true;}).catch(() => {this.isClick = true;});}},//復制消息copeText(items) {let that = this;// 數字沒有 .length 不能執行selectText 需要轉化成字符串const textString = items.messageValue.toString();let input = document.querySelector("#copy-input");if (!input) {input = document.createElement("input");input.id = "copy-input";input.readOnly = "readOnly"; // 防止ios聚焦觸發鍵盤事件input.style.position = "absolute";input.style.left = "-1000px";input.style.zIndex = "-1000";document.body.appendChild(input);}input.value = textString;// ios必須先選中文字且不支持 input.select();this.selectText(input, 0, textString.length);if (document.execCommand("copy")) {document.execCommand("copy");console.log("復制成功");Toast("復制成功!");items.isOprate = false;that.$forceUpdate();} else {console.log("不兼容");}input.blur();},// input自帶的select()方法在蘋果端無法進行選擇,所以需要自己去寫一個類似的方法// 選擇文本。createTextRange(setSelectionRange)是input方法selectText(textbox, startIndex, stopIndex) {if (textbox.createTextRange) {// ieconst range = textbox.createTextRange();range.collapse(true);range.moveStart("character", startIndex); // 起始光標range.moveEnd("character", stopIndex - startIndex); // 結束光標range.select(); // 不兼容蘋果} else {// firefox/chrometextbox.setSelectionRange(startIndex, stopIndex);textbox.focus();}},// 上傳圖片async afterRead(fileList) {Toast.loading({duration: 0, // 持續展示 toastmessage: "發送中...",forbidClick: true,});let that = this;let formData = new FormData(); //構造一個 FormData,把后臺需要發送的參數添加if (fileList.file.type.indexOf("video") == 0) {formData.append("file", fileList.file); //接口需要傳的參數formData.append("biz", fileList.file.name.split(".")[0]);await axios.post("/jeecg-boot/sys/common/uploadCp", formData).then((res) => {Toast.clear();if (res.data.code == 0) {let imgsrc = res.data.message;that.sendFun("6", imgsrc);} else {Toast("發送失敗");}});} else {imgPreview(fileList.file, async (files) => {// console.log(files)formData.append("file", files); //接口需要傳的參數formData.append("biz", files.name.split(".")[0]);await axios.post("/jeecg-boot/sys/common/uploadCp", formData).then((res) => {Toast.clear();if (res.data.code == 0) {let imgsrc = this.imgUrl+res.data.message;that.sendFun("5", imgsrc);} else {Toast("發送失敗");}});});}},beforeRead(fileList) {if (fileList.type.indexOf("image") != 0 &&fileList.type.indexOf("video") != 0) {Toast("只能上傳圖片(jpg,jpeg,png)、視頻(mp4,mov)");return false;}let fileListLength = fileList.length ? fileList.length : 1;if (fileListLength + this.fileList.length > 1) {Toast("最多同時上傳一張圖片或視頻");return false;}return true;},// 拍攝async afterReadVideo(fileList) {Toast.loading({duration: 0, // 持續展示 toastmessage: "發送中...",forbidClick: true,});let that = this;let formData = new FormData(); //構造一個 FormData,把后臺需要發送的參數添加if (fileList.file.type.indexOf("video") == 0) {formData.append("file", fileList.file); //接口需要傳的參數formData.append("biz", fileList.file.name.split(".")[0]);await axios.post("/jeecg-boot/sys/common/uploadCp", formData).then((res) => {Toast.clear();if (res.data.code == 0) {let imgsrc = res.data.message;that.sendFun("6", imgsrc);} else {Toast("發送失敗");}});} else {imgPreview(fileList.file, async (files) => {// console.log(files)formData.append("file", files); //接口需要傳的參數formData.append("biz", files.name.split(".")[0]);await axios.post("/jeecg-boot/sys/common/uploadCp", formData).then((res) => {Toast.clear();if (res.data.code == 0) {let imgsrc =this.imgUrl+ res.data.message;that.sendFun("5", imgsrc);} else {Toast("發送失敗");}});});}},beforeReadVideo(fileList) {if (fileList.type.indexOf("image") != 0 &&fileList.type.indexOf("video") != 0) {Toast("只能上傳圖片(jpg,jpeg,png)、視頻(mp4,mov)");return false;}let fileListLength = fileList.length ? fileList.length : 1;if (fileListLength + this.fileList.length > 1) {Toast("最多同時上傳一張圖片或視頻");return false;}return true;},//發送方法sendFun(messageType, messageValue, quoteValue) {// console.log(messageValue)Toast.loading({duration: 0, // 持續展示 toastmessage: "發送中...",forbidClick: true,});let date = new Date();let createTime = date.getTime();let prm=JSON.stringify({chatRoomId: this.chatRoomId, //群聊idmessageType: messageType, //1文字,5圖片,6視頻,7求手機號、8求微信號、9發手機號、10發微信號messageValue: messageValue, //發送信息// userPhone: this.myInfo.userPhone, //用戶手機號// fullName: this.myInfo.fullName, //用戶名// userIcon: this.myInfo.userIcon, //用戶頭像// memberId: this.myInfo.id, //用戶idmemberId: sessionStorage.getItem('clientId'), //用戶id// createTime: createTime, //創建時間// sex: this.myInfo.sex, //性別quoteValue: JSON.stringify(quoteValue), //引用的內容})console.log(prm)this.stompClient.send("/app/chatRoom",{},prm);},//添加表情addEmoji(e) {this.message += e.native;},//選擇表情chooseEmoji(item) {this.message += item.emoji;},},beforeDestroy() {Toast.clear();},updated() {},
};
</script><style lang="scss" scoped>
.groupChatInf {position: relative;.chatBox {// position: relative;height: calc(100vh - 320px);overflow-y: auto;}/deep/.van-pull-refresh {// min-height: 300px;min-height: calc(100vh - 320px);.van-pull-refresh__track {padding: 0px 10px;}}// ::v-deep .van-pull-refresh {//   min-height: 300px;// }.welcome {text-align: center;font-size: 14px;color: #666;padding: 6px 10px;}.chatInf {width: 100%;padding: 0px 0px 70px 0px;.chatOne {.date {text-align: center;line-height: 30px;font-size: 12px;color: #999;}.chatMine,.chatOther {position: relative;margin-bottom: 10px;padding: 0px 50px;min-height: 40px;position: relative;.chatImg {width: 38px;height: 38px;position: absolute;top: 0px;.imgs {width: 100%;height: 100%;border-radius: 50%;overflow: hidden;}.van-image {width: 100%;height: 100%;border-radius: 50%;overflow: hidden;}.sex {width: 15px;position: absolute;right: -4px;bottom: 0px;}}.chatText {padding: 8px 13px;background: #d8d8d8;font-size: 14px;color: #333;line-height: 1.7;border-radius: 6px;position: relative;}.chatName {font-size: 12px;color: #666;line-height: 20px;img {width: 11px;position: relative;top: -1px;margin-right: 3px;}}.chatImage,.chatVideo {width: 124px;height: 124px;overflow: hidden;}.chatImage {img {width: 100%;height: 100%;object-fit: cover;}}.chatVideo {position: relative;video {width: 100%;height: 100%;}.chatmask {width: 100%;height: 100%;background: rgba(0, 0, 0, 0.5);position: absolute;top: 0;left: 0;img {width: 40px;height: 40px;position: absolute;top: 50%;left: 50%;transform: translate(-50%, -50%);}}}.chatvalueDiv {position: relative;}.chatvalueDiv:after {content: "";display: block;clear: both;}.quoteValue {padding: 5px 10px;font-size: 10px;color: #8e8e93;border-radius: 4px;background: #eeeeef;margin-top: 5px;text-overflow: -o-ellipsis-lastline;overflow: hidden;text-overflow: ellipsis;display: -webkit-box;-webkit-line-clamp: 2;line-clamp: 2;-webkit-box-orient: vertical;}.chatOprate {width: auto;height: 28px;background: #fff;position: absolute;bottom: -34px;z-index: 120;border-radius: 4px;display: flex;span {font-size: 13px;color: #333;line-height: 28px;width: 40px;text-align: center;margin: 0 10px;}}.chatOprateMask {width: 100%;height: 100%;position: fixed;top: 0;left: 0;background: rgba(255, 255, 255, 0);z-index: 111;}.quoteImg {padding: 5px 10px;border-radius: 4px;background: #eeeeef;margin-top: 5px;p {font-size: 10px;color: #8e8e93;}.qimgs {width: 90px;height: 60px;object-fit: cover;margin-left: 5px;}.quoteVideo {width: 90px;height: 60px;position: relative;margin-left: 5px;video {width: 100%;height: 100%;}.chatmask {width: 100%;height: 100%;background: rgba(0, 0, 0, 0.5);position: absolute;top: 0;left: 0;img {width: 30px;height: 30px;position: absolute;top: 50%;left: 50%;transform: translate(-50%, -50%);}}}}}.chatMine {.chatImg {right: 0px;}.chatText {float: right;background: #ff4e7b;border: 1px #ff4e7b solid;color: #fff;}.chatName {text-align: right;}.quoteValue {float: right;}.chatImage,.chatVideo {border-radius: 6px 0 6px 6px;float: right;}.chatOprate {right: 0;}.chatOprate:after {content: "";position: absolute;width: 0px;height: 0px;line-height: 0px; /*為了防止ie下出現題型*/border-bottom: 5px solid #fff;border-left: 5px solid transparent;border-right: 5px solid transparent;right: 10px;top: -5px;}.quoteImg {float: right;p {float: left;}.qimgs,.quoteVideo {float: right;}}}.chatOther {.chatImg {left: 0px;}.chatText {float: left;background: #fff;// border: 1px #eee solid;}.chatImage,.chatVideo {border-radius: 0 6px 6px 6px;float: left;}.quoteValue {float: left;}.chatOprate {left: 0;}.chatOprate:after {content: "";position: absolute;width: 0px;height: 0px;line-height: 0px; /*為了防止ie下出現題型*/border-bottom: 5px solid #fff;border-left: 5px solid transparent;border-right: 5px solid transparent;left: 10px;top: -5px;}.quoteImg {float: left;p {float: left;}.qimgs,.quoteVideo {float: right;}}}.chatMine:after,.chatOther:after {content: "";display: block;clear: both;}}}.sendBox {// width: 400px;width: 100%;background: #fff;position: absolute;z-index: 99;left: 0px;margin: 0 auto;bottom: -20px;border-top: 1px #eee solid;.sendBoxTop {min-height: 50px;width: 100%;padding: 6px 60px 6px 60px;.sendMember {width: 40px;height: 40px;position: absolute;top: 5px;left: 10px;img {width: 24px;height: 24px;position: absolute;top: 8px;left: 8px;}}.sendInf {width: 100%;height: 40px;background: #f5f5f5;border-radius: 20px;padding-left: 10px;}.sendBtn {width: 60px;height: 50px;padding: 5px 10px;position: absolute;top: 0px;right: 0px;img {width: 40px;}}}.sendBoxBtm {width: 100%;height: 42px;display: flex;.sendOprate {flex: 1;height: 100%;align-items: center;justify-content: center;position: relative;img {padding: 5px;width: 34px;height: 34px;display: block;margin: 4px auto;}::v-deep .van-uploader {width: 34px;height: 34px;position: absolute;top: 50%;left: 50%;transform: translate(-50%, -50%);.van-uploader__upload {width: 34px;height: 34px;margin: 0;opacity: 0;}}}}.sendExpression {width: 30px;height: 30px;position: absolute;top: 12px;right: 65px;padding: 3px;img {width: 24px;}}.quoteMessage {display: inline-block;background: #f4f4f4;border-radius: 6px;padding: 5px 30px 5px 8px;position: relative;margin-top: 6px;.quoteText {font-size: 10px;color: #8e8e93;line-height: 1.5;text-overflow: -o-ellipsis-lastline;overflow: hidden;text-overflow: ellipsis;display: -webkit-box;-webkit-line-clamp: 2;line-clamp: 2;-webkit-box-orient: vertical;}.quoteClose {width: 24px;height: 24px;padding: 5px;position: absolute;right: 5px;top: 50%;transform: translateY(-50%);}}}.chatRecall {text-align: center;font-size: 12px;color: #8e8e93;padding: 6px 0px;line-height: 20px;a {color: #ff0021;}}.rejectCol {color: #ee6262;}::v-deep .emoji-mart {width: 100% !important;height: 160px;border: none;.emoji-mart-category-label {display: none;}}.emojiBox {width: 100%;height: 160px;overflow: auto;.emojiDiv {display: flex;flex-wrap: wrap;padding: 0 10px;span {padding: 3px;width:32px;height:32px;text-align:center;line-height:32px;}}}
}
::v-deep .van-field__control{margin-top: 8px;border: 0px;width: calc(100% - 40px);background-color: transparent;
}
::v-deep .van-field__control:focus{outline: none !important;
}
</style>

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/44773.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/44773.shtml
英文地址,請注明出處:http://en.pswp.cn/web/44773.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

二叉搜索樹大冒險:尋找-插入-刪除

OK&#xff0c;看我們題目就可知道啦&#xff0c;今天要分享學習的一種數據結構就是二叉搜索樹。 內容題目也說了三個大概的&#xff0c;分別是尋找、插入、刪除。 講這個之前呢&#xff0c;那么就先講講這個二叉搜索樹是何方神圣呢&#xff1f; 二叉搜索樹&#xff1a; 又…

【學習筆記】無人機(UAV)在3GPP系統中的增強支持(五)-同時支持無人機和eMBB用戶數據傳輸的用例

引言 本文是3GPP TR 22.829 V17.1.0技術報告&#xff0c;專注于無人機&#xff08;UAV&#xff09;在3GPP系統中的增強支持。文章提出了多個無人機應用場景&#xff0c;分析了相應的能力要求&#xff0c;并建議了新的服務級別要求和關鍵性能指標&#xff08;KPIs&#xff09;。…

全網最詳細單細胞保姆級分析教程(二) --- 多樣本整合

上一節我們研究了如何對單樣本進行分析,這節我們就著重來研究一下如何對多樣本整合進行研究分析! 1. 導入相關包 library(Seurat) library(tidyverse) library(patchwork)2. 數據準備 # 導入單樣本文件 dir c(~/Desktop/diversity intergration/scRNA_26-0_filtered_featur…

Linux上如何安裝ffmpeg視頻處理軟件

在Linux上安裝ffmpeg需要以下步驟&#xff1a; 更新系統 在開始安裝之前&#xff0c;首先需要更新系統以獲取最新的軟件包列表和版本。在終端中執行以下命令&#xff1a; sudo apt update sudo apt upgrade安裝依賴庫 ffmpeg依賴于一些庫和工具&#xff0c;需要先安裝它們。在…

【香橙派 Orange pi AIpro】| 開發板深入使用體驗

目錄 一. &#x1f981; 寫在前面二. &#x1f981; 愉快的安裝流程2.1 安裝前準備2.2 流程準備2.2.1 燒錄鏡像2.2.2 開機2.2.3 連網2.2.4 SSH遠程連接開發板 2.3 體驗 AI 應用樣例 三. &#x1f981; 寫在最后 一. &#x1f981; 寫在前面 大家好&#xff0c;我是獅子呀&…

醫療級微型導軌:保障醫療行業手術安全!

微型直線導軌能成為一種專為醫療行業設備運用的高精度線性運動設備&#xff0c;在現代醫療領域&#xff0c;精準的位置控制和平穩的運動對于確保醫療設備的高效性能至關重要。那么&#xff0c;醫療行業對微型導軌有哪些要求呢&#xff1f; 1、精度&#xff1a;在手術過程中&…

C++客戶端Qt開發——開發環境

一、QT開發環境 1.安裝三個部分 ①C編譯器&#xff08;gcc&#xff0c;cl.exe……) ②QT SDK SDK-->軟件開發工具包 比如&#xff0c;windows版本QT SDK里已經內置了C的編譯器&#xff08;內置編譯器是mingw&#xff0c;windows版本的gcc/g&#xff09; ③QT的集成開發…

Python編程中用函數還是用復雜的表達式

要不要使用復雜表達式 Perl語言的原作者Larry Wall曾經說過&#xff0c;偉大的程序員都有三個優點&#xff1a;懶惰、暴躁和自負。乍一看這三個詞語沒有一個是褒義詞&#xff0c;但在程序員的世界里&#xff0c;這三個詞有不同的意義。首先&#xff0c;懶惰會促使程序員去寫一…

智慧園區規劃建設解決方案PPT(40頁)

智慧園區規劃建設解決方案摘要 1. 園區定義與發展歷程 園區&#xff0c;亦稱開發區&#xff0c;是在特定產業和區域政策指導下形成的區域。它們通過提供基礎設施和生產空間&#xff0c;吸引投資&#xff0c;形成技術、資本密集區&#xff0c;推動經濟發展。園區發展經歷了四代…

Docker 部署 ShardingSphere-Proxy 數據庫中間件

文章目錄 Github官網文檔ShardingSphere-Proxymysql-connector-java 驅動下載conf 配置global.yamldatabase-sharding.yamldatabase-readwrite-splitting.yamldockerdocker-compose.yml Apache ShardingSphere 是一款分布式的數據庫生態系統&#xff0c; 可以將任意數據庫轉換為…

【qt】TCP客戶端信息的接受和發送

當有信息時的槽函數關聯 跟服務端收到信息一樣,當可以讀一行的時候,就從套接字讀一行. 發送信息也是和服務端如出一轍,通過write(). 運行結果:

java EnumSet 介紹

EnumSet 是 Java Collections Framework 中專門為枚舉類型設計的高效集合實現。與其他集合類相比,EnumSet 提供了許多優點,如高效性、類型安全和易用性。它只能包含單個枚舉類型的值,并且在內部使用位向量實現,因而在空間和時間上都非常高效。 EnumSet 的特點 高效性:Enu…

Spring MVC 中的文件上傳 和 文件下載

Spring MVC 中的文件上傳 和 文件下載 文章目錄 Spring MVC 中的文件上傳 和 文件下載1. Spring MVC 中的文件上傳2. Spring MVC 中的文件下載3. 總結&#xff1a;4. 最后&#xff1a; 1. Spring MVC 中的文件上傳 文件上傳是&#xff1a;瀏覽器端向服務器發送文件&#xff0c…

C 語言結構體

由于近期項目需求,需使用到大量的指針與結構體&#xff0c;為更好的完成項目&#xff0c;故對結構體與指針的內容進行回顧&#xff0c;同時撰寫本博客&#xff0c;方便后續查閱。 本博客涉及的結構體知識有&#xff1a; 1.0&#xff1a;結構體的創建和使用 2.0: typedef 關…

解鎖音樂密碼,人工智能創作動人歌詞

在音樂的神秘世界里&#xff0c;每一段旋律都像是一把等待開啟的密碼鎖&#xff0c;隱藏著無盡的情感與故事。而如今&#xff0c;人工智能正以其獨特的智慧和創造力&#xff0c;幫助我們解鎖這些音樂密碼&#xff0c;創作出動人的歌詞。 “妙筆生詞智能寫歌詞軟件&#xff08;…

Provider(1)- 什么是AudioBufferProvider

什么是AudioBufferProvider&#xff1f; 顧名思義&#xff0c;Audio音頻數據緩沖提供&#xff0c;就是提供音頻數據的緩沖類&#xff0c;而且這個AudioBufferProvider派生出許多子類&#xff0c;每個子類有不同的用途&#xff0c;至關重要&#xff1b;那它在Android哪個地方使…

訪問 Postman OAuth 2.0 授權的最佳實踐

OAuth 2.0 代表了 web 安全協議的發展&#xff0c;便于在多個平臺上進行授權服務&#xff0c;同時避免暴露用戶憑據。它提供了一種安全的方式&#xff0c;讓用戶可以授權應用程序訪問服務。 在 Postman 中開始使用 OAuth 2.0 Postman 是一個流行的API客戶端&#xff0c;支持 …

亞馬遜店鋪注冊

**步驟一&#xff1a;準備注冊相關資料** 在注冊之前&#xff0c;請準備以下資料&#xff1a; 1.公司營業執照照片&#xff08;清晰完整的拍照上傳&#xff09; 2.法人身份證正反面照片&#xff08;清晰完整的拍照上傳&#xff09; 3.雙幣付款信用卡&#xff08;VISA&#xff0…

[PaddlePaddle飛槳] PaddleSpeech-自動語音識別-小模型部署

PaddleSpeech的GitHub項目地址 環境要求&#xff1a; gcc > 4.8.5 paddlepaddle < 2.5.1 python > 3.8 OS support: Linux(recommend), Windows, Mac OSXpip下載指令&#xff1a; python -m pip install paddlepaddle-gpu2.5.1 -i https://pypi.tuna.tsinghua.edu.c…

探索4D毫米波雷達和攝像頭在自動駕駛中的潛力

隨著自動駕駛技術的快速發展&#xff0c;關于各種傳感器的必要性&#xff0c;尤其是LiDAR&#xff08;激光雷達&#xff09;與毫米波雷達結合攝像頭的作用&#xff0c;激發了激烈的討論。在這篇博客中&#xff0c;我們將探討4D毫米波雷達和攝像頭的組合是否可能成為自動駕駛車輛…