| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688 |
- <template>
- <div >
- <div class="container">
- <div id="wrapper" v-if="!isLogin" >
- <login />
- </div>
- <div
- class="loading"
- v-else
- v-loading="showLoading"
- element-loading-text="正在拼命初始化..."
- element-loading-background="rgba(0, 0, 0, 0.8)"
- >
- <div class="chat-wrapper">
- <el-row>
- <el-col :xs="10" :sm="10" :md="8" :lg="8" :xl="7">
- <side-bar />
- </el-col>
- <el-col :xs="14" :sm="14" :md="16" :lg="16" :xl="17">
- <current-conversation />
- </el-col>
- </el-row>
- </div>
- <calling ref="callLayer" class="chat-wrapper"/>
- <image-previewer />
- <group-live />
- </div>
- <div class="bg"></div>
- </div>
- </div>
- </template>
- <script>
- import { imConfig } from '@/utils/im'
- import {getTlsSig } from "@/api/common";
- import { Notification } from 'element-ui'
- import { mapState } from 'vuex'
- import CurrentConversation from '@/components/conversation/current-conversation'
- import SideBar from '@/components/layout/side-bar'
- import Login from '@/components/user/login'
- import ImagePreviewer from '@/components/message/image-previewer.vue'
- import QrCodeList from '@/components/qr-code-list'
- import { translateGroupSystemNotice } from '@/utils/common'
- import GroupLive from '@/components/group-live/index'
- import Calling from '@/components/message/trtc-calling/calling-index'
- import { ACTION } from '@/utils/trtcCustomMessageMap'
- import { getOpenIM,getCbEvents } from '@/utils/openIM';
- import { accountCheck } from '@/api/doctor';
- export default {
- title: 'TIMSDK DEMO',
- data () {
- return {
- loginType: 2, // github 登录只使用默认账号登录
- OpenIM: null,
- userToken:""
- }
- },
- components: {
- Login,
- SideBar,
- CurrentConversation,
- ImagePreviewer,
- QrCodeList,
- GroupLive,
- Calling,
- },
- computed: {
- ...mapState({
- currentUserProfile: state => state.user.currentUserProfile,
- currentConversation: state => state.conversation.currentConversation,
- videoCall: state => state.conversation.videoCall,
- audioCall: state => state.conversation.audioCall,
- isLogin: state => state.imuser.isLogin,
- isSDKReady: state => state.imuser.isSDKReady,
- isBusy: state => state.video.isBusy,
- userID: state => state.imuser.userID,
- token: state => state.imuser.token,
- userSig: state => state.imuser.userSig,
- sdkAppID: state => state.imuser.sdkAppID
- }),
- // 是否显示 Loading 状态
- showLoading() {
- return !this.isSDKReady
- }
- },
- created() {
- if (process.env.IS_OPENIM){
- this.OpenIM = getOpenIM();
- this.initListener()
- this.getTlsSig();
- }
- },
- mounted() {
- //this.getTlsSig()
- },
- watch: {
- },
- methods: {
- // 修改 getTlsSig 方法
- getTlsSig() {
- accountCheck(this.$store.getters.userID).then(response => {
- this.userToken = response.token
- const config = {
- userID: this.$store.getters.userID,
- token: this.userToken,
- logLevel:6,
- platformID: 5, // 使用配置的平台ID
- apiAddr: 'https://web.im.ysya.top/api',
- wsAddr: 'wss://web.im.ysya.top/msg_gateway',
- dataDir: '/imdata' // 添加数据存储目录
- }
- this.OpenIM.login(config).then(() => {
- this.$nextTick(() => {
- this.checkSDKReadyState();
- });
- this.$store.commit('toggleIsLogin', true);
- this.$store.commit('startComputeCurrent');
- this.$store.commit('showMessage', {
- type: 'success',
- message: 'IM 登录成功'
- });
- })
- .catch((error) => {
- this.loading = false;
- console.error('登录失败:', error);
- this.$store.commit('showMessage', {
- message: `IM 登录失败:${error.message || error.errMsg || '未知错误'}`,
- type: 'error',
- });
- });
- });
- },
- // 添加SDK就绪状态检查
- checkSDKReadyState() {
- if (this.hasBindReadyEvent) return;
- this.hasBindReadyEvent = true;
- let isReady = false;
- const timeout = setTimeout(() => {
- if (!isReady) {
- this.$store.commit('toggleIsSDKReady', false);
- this.$store.commit('showMessage', {
- message: 'SDK初始化超时',
- type: 'error'
- });
- }
- }, 10000);
- this.OpenIM.on(getCbEvents().OnConnectSuccess, () => {
- clearTimeout(timeout);
- isReady = true;
- console.log("this.OpenIM",this.OpenIM)
- this.OpenIM.getSelfUserInfo().then(({ data }) => {
- this.$store.commit('updateCurrentUserProfile', data)
- })
- this.$store.commit('toggleIsSDKReady', true);
- this.$store.commit('showMessage', {
- type: 'success',
- message: 'SDK 初始化成功'
- });
- this.loadUserData();
- });
- this.OpenIM.on(getCbEvents().OnConnectFailed, (error) => {
- clearTimeout(timeout);
- this.$store.commit('toggleIsSDKReady', false);
- this.$store.commit('showMessage', {
- message: `SDK 连接失败: ${error.message}`,
- type: 'error'
- });
- });
- },
- // 添加加载用户数据方法
- loadUserData() {
- //查询会话列表
- this.OpenIM.getAllConversationList()
- .then(({ data }) => {
- // 调用成功
- console.log("获取到会话列表",data)
- this.conversationList= data
- this.$store.commit('updateConversationList', data)
- })
- .catch(({ errCode, errMsg }) => {
- // 调用失败
- })
- //查询好友列表
- this.OpenIM.getFriendListPage({ offset:0, count:100 })
- .then(({ data }) => {
- // 调用成功
- console.log("获取到好友列表",data)
- //this.conversationList= data
- this.$store.commit('updateFriendList', data)
- })
- .catch(({ errCode, errMsg }) => {
- // 调用失败
- })
- },
- selfUpdateHandler({ data }) {
- this.updateMessageNicknameAndFaceUrl({
- sendID: data.userID,
- senderNickname: data.nickname,
- senderFaceUrl: data.faceURL,
- });
- this.updateSelfInfo(data);
- },
- // 更新昵称和头像
- updateMessageNicknameAndFaceUrl({ sendID, senderNickname, senderFaceUrl }) {
- // 更新消息昵称和头像的逻辑
- console.log(sendID, senderNickname, senderFaceUrl);
- },
- // 更新个人信息
- updateSelfInfo(data) {
- // 更新个人信息的逻辑
- console.log(data);
- },
- initListener() {
- // 登录成功后会触发 SDK_READY 事件,该事件触发后,可正常使用 SDK 接口
- this.OpenIM.on(getCbEvents().OnConnectSuccess, () => {
- console.log("OnConnectSuccess 事件触发!"); // 调试日志
- this.$store.commit('toggleIsSDKReady', true);
- });
- this.OpenIM.on(getCbEvents().OnConnectFailed, this.onError);
- this.OpenIM.on(getCbEvents().OnKickedOffline, this.onKickOut);
- this.OpenIM.on(getCbEvents().OnSelfInfoUpdated, this.onSelfInfoUpdated);
- this.OpenIM.on(getCbEvents().OnFriendAdded,(data)=>{
- console.log("新增好友事件触发",data)
- this.onFriendListUpdated(data);
- });
- /*this.OpenIM.on(getCbEvents().OnRecvNewMessage, (message) => {
- console.log("收到单条消息", message);
- this.onReceiveMessage({data: [message]}); // 包装成数组形式
- });*/
- this.OpenIM.on(getCbEvents().OnRecvNewMessages, (data) => {
- console.log("收到多条消息", data);
- const msgList = []
- data.data.forEach(msg =>{
- if (msg.contentType!==113){
- msgList.push(msg)
- }
- })
- if (msgList.length>0){
- this.onReceiveMessage({data: msgList});
- }
- });
- /*this.OpenIM.on(getCbEvents().OnConversationChanged, (eventData) => {
- console.log("触发OnConversationChanged事件", eventData);
- try {
- // 1. 确保数据结构正确
- if (!eventData || !eventData.data) {
- console.warn("无效的会话更新数据", eventData);
- return;
- }
- // 2. 提取更新后的会话列表
- const updatedConversations = eventData.data;
- // 3. 打印调试信息
- console.log("更新的会话列表:", updatedConversations);
- // 4. 更新到Vuex store
- this.$store.commit('updateConversationList', updatedConversations);
- // 5. 可选:检查特定会话的更新
- updatedConversations.forEach(conv => {
- console.log(`会话ID: ${conv.conversationID} 已更新`, conv);
- });
- } catch (error) {
- console.error("处理会话更新时出错:", error);
- }
- });*/
- // SDK NOT READT
- /*this.OpenIM.on(this.OpenIM.EVENT.SDK_NOT_READY, this.onReadyStateUpdate, this)
- // 被踢出
- this.OpenIM.on(this.OpenIM.EVENT.KICKED_OUT, this.onKickOut)
- // SDK内部出错
- this.OpenIM.on(this.OpenIM.EVENT.ERROR, this.onError)
- // 收到新消息
- this.OpenIM.on(this.OpenIM.EVENT.MESSAGE_RECEIVED, this.onReceiveMessage)
- // 会话列表更新
- this.OpenIM.on(this.OpenIM.EVENT.CONVERSATION_LIST_UPDATED, this.onUpdateConversationList)
- // 群组列表更新
- this.OpenIM.on(this.OpenIM.EVENT.GROUP_LIST_UPDATED, this.onUpdateGroupList)
- // 网络监测
- this.OpenIM.on(this.OpenIM.EVENT.NET_STATE_CHANGE, this.onNetStateChange)
- // 已读回执
- this.OpenIM.on(this.OpenIM.EVENT.MESSAGE_READ_BY_PEER, this.onMessageReadByPeer)
- // 黑名单更新
- this.OpenIM.on(this.OpenIM.EVENT.FRIEND_LIST_UPDATED, this.onFriendListUpdated)
- this.OpenIM.on(this.OpenIM.EVENT.FRIEND_APPLICATION_LIST_UPDATED, this.onFriendApplicationListUpdated)
- this.OpenIM.on(this.OpenIM.EVENT.FRIEND_GROUP_LIST_UPDATED, this.onFriendGroupListUpdated)*/
- },
- onFriendApplicationListUpdated(data) {
- this.$store.commit('updateApplicationList', data.data.friendApplicationList)
- this.$store.commit('updateUnreadCount', data.data.unreadCount)
- },
- onFriendListUpdated(data) {
- this.$store.commit('updateFriendList', data.data)
- },
- onFriendGroupListUpdated(data) {
- this.$store.commit('updateFriendGroupList', data.data)
- },
- onReceiveMessage({ data: messageList }) {
- // let totalUnreadCount = this.tim.getTotalUnreadMessageCount();
- messageList.forEach(element => {
- //过滤掉正在输入状态
- if(element.sendID!=this.$store.getters.userID&&element.contentType!==113){
- this.$notify({
- title: '消息提示',
- message: '您有一条新的消息',
- type: 'success'
- });
- }
- });
- this.OpenIM.getAllConversationList()
- .then(({ data }) => {
- // 调用成功
- this.$store.commit('updateConversationList', data)
- })
- .catch(({ errCode, errMsg }) => {
- // 调用失败
- })
- console.log(messageList)
- //this.handleVideoMessage(messageList)
- this.handleQuitGroupTip(messageList)
- this.handleCloseGroupLive(messageList)
- this.$store.commit('pushCurrentMessageList', messageList)
- this.$store.commit('pushAvChatRoomMessageList', messageList)
- },
- onError({ data }) {
- if (data.message !== 'Network Error') {
- this.$store.commit('showMessage', {
- message: data.message,
- type: 'error'
- })
- }
- },
- onMessageReadByPeer() {
- },
- onReadyStateUpdate({ name }) {
- console.log("当前登录用户基本信息")
- const isSDKReady = name === getCbEvents().OnConnectSuccess ? true : false
- this.$store.commit('toggleIsSDKReady', isSDKReady)
- // let totalUnreadCount = this.tim.getTotalUnreadMessageCount();
- // console.log("收到消息数"+totalUnreadCount)
- if (isSDKReady) {
- this.OpenIM.getSelfUserInfo().then(({ data }) => {
- console.log("当前登录用户基本信息",data)
- this.$store.commit('updateCurrentUserProfile', data)
- })
- .catch(error => {
- this.$store.commit('showMessage', {
- type: 'error',
- message: error.message
- })
- })
- /*this.$store.dispatch('getBlacklist')
- // 登录trtc calling
- console.log(this.sdkAppID)
- this.trtcCalling.login({
- sdkAppID: this.sdkAppID,
- userID: this.userID,
- userSig:this.userSig
- })*/
- }
- },
- kickedOutReason(type) {
- /*switch (type) {
- case this.OpenIM.TYPES.KICKED_OUT_MULT_ACCOUNT:
- return '由于多实例登录'
- case this.OpenIM.TYPES.KICKED_OUT_MULT_DEVICE:
- return '由于多设备登录'
- case this.OpenIM.TYPES.KICKED_OUT_USERSIG_EXPIRED:
- return '由于 userSig 过期'
- default:
- return ''
- }*/
- },
- checkoutNetState(state) {
- /*switch (state) {
- case this.OpenIM.TYPES.NET_STATE_CONNECTED:
- return { message: '已接入网络', type: 'success' }
- case this.OpenIM.TYPES.NET_STATE_CONNECTING:
- return { message: '当前网络不稳定', type: 'warning' }
- case this.OpenIM.TYPES.NET_STATE_DISCONNECTED:
- return { message: '当前网络不可用', type: 'error' }
- default:
- return ''
- }*/
- },
- onNetStateChange(event) {
- this.$store.commit('showMessage', this.checkoutNetState(event.data.state))
- },
- onKickOut(event) {
- this.$store.commit('showMessage', {
- message: `${this.kickedOutReason(event.data.type)}被踢出,请重新登录。`,
- type: 'error'
- })
- this.$store.commit('toggleIsLogin', false)
- this.$store.commit('reset')
- },
- onUpdateConversationList(event) {
- if(this.isSDKReady){
- this.$store.commit('updateConversationList', event.data)
- }
- },
- onUpdateGroupList(event) {
- this.$store.commit('updateGroupList', event.data)
- },
- onReceiveGroupSystemNotice(event) {
- const isKickedout = event.data.type === 4
- const isCurrentConversation =
- `GROUP${event.data.message.payload.groupProfile.groupID}` ===
- this.currentConversation.conversationID
- // 在当前会话被踢,需reset当前会话
- if (isKickedout && isCurrentConversation) {
- this.$store.commit('resetCurrentConversation')
- }
- Notification({
- title: '新系统通知',
- message: translateGroupSystemNotice(event.data.message),
- duration: 3000,
- onClick: () => {
- const SystemConversationID = '@TIM#SYSTEM'
- this.$store.dispatch('checkoutConversation', SystemConversationID)
- }
- })
- },
- selectConversation(conversationID) {
- if (conversationID !== this.currentConversation.conversationID) {
- this.$store.dispatch('checkoutConversation',conversationID)
- }
- },
- isJsonStr(str) {
- try{
- JSON.parse(str)
- return true
- }catch {
- return false
- }
- },
- handleVideoMessage(messageList) {
- const videoMessageList = messageList.filter(
- message => message.contentType === 110 && this.isJsonStr(message.payload.data)
- )
- if (videoMessageList.length === 0) return
- const videoPayload = JSON.parse(videoMessageList[0].payload.data)
- if (videoPayload.action === ACTION.VIDEO_CALL_ACTION_DIALING) {
- if (this.isBusy) {
- this.$bus.$emit('busy', videoPayload, videoMessageList[0])
- return
- }
- this.$store.commit('GENERATE_VIDEO_ROOM', videoPayload.room_id)
- this.selectConversation(videoMessageList[0].conversationID) // 切换当前会话页
- if (videoMessageList[0].from !== this.userID) {
- this.$bus.$emit('isCalled')
- }
- }
- if (videoPayload.action === ACTION.VIDEO_CALL_ACTION_SPONSOR_CANCEL) {
- this.$bus.$emit('missCall')
- }
- if (videoPayload.action === ACTION.VIDEO_CALL_ACTION_REJECT) {
- this.$bus.$emit('isRefused')
- }
- if (videoPayload.action === ACTION.VIDEO_CALL_ACTION_SPONSOR_TIMEOUT) {
- this.$bus.$emit('missCall')
- }
- if (videoPayload.action === ACTION.VIDEO_CALL_ACTION_ACCEPTED) {
- this.$bus.$emit('isAccept')
- }
- if (videoPayload.action === ACTION.VIDEO_CALL_ACTION_HANGUP) {
- this.$bus.$emit('isHungUp')
- }
- if (videoPayload.action === ACTION.VIDEO_CALL_ACTION_LINE_BUSY) {
- this.$bus.$emit('isRefused')
- }
- if (videoPayload.action === ACTION.VIDEO_CALL_ACTION_ERROR) {
- this.$bus.$emit('isRefused')
- }
- },
- /**
- * 使用 window.Notification 进行全局的系统通知
- * @param {Message} message
- */
- notifyMe(message) {
- // 需检测浏览器支持和用户授权
- if (!('Notification' in window)) {
- return
- } else if (window.Notification.permission === 'granted') {
- this.handleNotify(message)
- } else if (window.Notification.permission !== 'denied') {
- window.Notification.requestPermission().then(permission => {
- // 如果用户同意,就可以向他们发送通知
- if (permission === 'granted') {
- this.handleNotify(message)
- }
- })
- }
- },
- handleNotify(message) {
- const notification = new window.Notification('有人提到了你', {
- icon: 'https://web.sdk.qcloud.com/im/assets/images/logo.png',
- body: message.payload.text
- })
- notification.onclick = () => {
- window.focus()
- this.$store.dispatch('checkoutConversation', message.conversationID)
- notification.close()
- }
- },
- /**
- * 收到有群成员退群/被踢出的groupTip时,需要将相关群成员从当前会话的群成员列表中移除
- * @param {Message[]} messageList
- */
- handleQuitGroupTip(messageList) {
- // 筛选出当前会话的退群/被踢群的 groupTip
- const groupTips = messageList.filter(message => {
- return this.currentConversation.conversationID === message.conversationID &&
- message.contentType === 1501 &&
- (message.payload.operationType === 1504 ||
- message.payload.operationType === 1508)
- })
- // 清理当前会话的群成员列表
- if (groupTips.length > 0) {
- groupTips.forEach(groupTip => {
- if (Array.isArray(groupTip.payload.userIDList) || groupTip.payload.userIDList.length > 0) {
- this.$store.commit('deleteGroupMemberList', groupTip.payload.userIDList)
- }
- })
- }
- },
- /**
- * 收到结束直播自定义消息,派发事件关闭组件
- * @param {Message[]} messageList
- */
- handleCloseGroupLive(messageList) {
- messageList.forEach(message => {
- if (this.currentConversation.conversationID === message.conversationID && message.contentType === 110) {
- let data = {}
- try {
- data = JSON.parse(message.payload.data)
- } catch(e) {
- data = {}
- }
- if (data.roomId && Number(data.roomStatus) === 0) {
- this.$bus.$emit('close-group-live')
- }
- }
- })
- },
- }
- }
- </script>
- <style lang="stylus">
- body {
- overflow: hidden;
- margin: 0;
- font-family: 'Microsoft YaHei', '微软雅黑', 'MicrosoftJhengHei', 'Lantinghei SC', 'Open Sans', Arial, 'Hiragino Sans GB', 'STHeiti', 'WenQuanYi Micro Hei', SimSun, sans-serif;
- // font-family "Helvetica Neue", Helvetica, Arial, "PingFang SC", "Hiragino Sans GB", "Heiti SC", "Microsoft YaHei", "WenQuanYi Micro Hei", sans-serif
- // text-shadow: $regular 0 0 0.05em
- background-color: $bg;
- -ms-scroll-chaining: chained;
- -ms-overflow-style: none;
- -ms-content-zooming: zoom;
- -ms-scroll-rails: none;
- -ms-content-zoom-limit-min: 100%;
- -ms-content-zoom-limit-max: 500%;
- -ms-scroll-snap-type: proximity;
- -ms-scroll-snap-points-x: snapList(100%, 200%, 300%, 400%, 500%);
- -ms-overflow-style: none;
- overflow: auto;
- div {
- box-sizing: border-box;
- &::before, &::after {
- box-sizing: border-box;
- }
- }
- }
- #wrapper {
- display: flex;
- justify-content: center;
- align-items: center;
- flex-direction: column;
- margin-top: 100px;
- }
- .container
- position relative
- // height 100vh
- .bg {
- position: absolute;
- // width: 100%;
- // height: 100%;
- top: 0;
- left: 0;
- z-index: -1;
- // background: url('~@/./assets/image/bg.jpg') no-repeat 0 0;
- // background-size: cover;
- // filter blur(67px)
- }
- .loading {
- width: 80%;
- height: $height;
- display: flex;
- justify-content: center;
- align-items:center;
- }
- .text-ellipsis {
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
- }
- .chat-wrapper {
- // margin-top: 8vh;
- width: 100%;
- height: $height;
- // max-width: 1280px;
- box-shadow: 0 11px 20px 0 rgba(0, 0, 0, 0.3);
- .official-link {
- display: flex;
- text-decoration: none;
- color: #38c9ff;
- width: fit-content;
- float: right;
- height: 45px;
- align-items: center;
- }
- }
- /* 设置滚动条的样式 */
- ::-webkit-scrollbar {
- width: 3px;
- height: 3px;
- }
- /* 滚动槽 */
- ::-webkit-scrollbar-track {
- border-radius: 10px;
- }
- /* 滚动条滑块 */
- ::-webkit-scrollbar-thumb {
- border-radius: 10px;
- background: rgba(0, 0, 0, 0.1);
- }
- /deep/ .el-popover {
- width 800px
- position fixed
- left 0
- right 0
- margin auto
- }
- </style>
|