// tim组件工具模块 var timToolsModule = (function(initEmoji){ const defaultImage = 'https://imgcache.qq.com/open/qcloud/video/act/webim-avatar/avatar-2.png'; const c2cType = 'C2C'; //新会话类型,基本都是单聊形式 const groupType = 'GROUP'; //群组类型 const allowType = { "text": "TIMTextElem", "image": "TIMImageElem", "video": "TIMVideoFileElem", "file": "TIMFileElem", // "custom": "TIMCustomElem", }; // img onerror事件,当无法拿到动态图片是 自动去拿默认图片 function onerrorFN(_img){ _img.onerror = function(e){ var e = e || window.event; var img = e.srcElement; img.src = defaultImage; img.οnerrοr=null; //控制不要一直跳动 } } // 时间显示规则,当天只显示时:分,之前的时间显示年-月-日 时:分, 传入的是秒数 function showTime(_time){ let time = _time*1000 let YMD = timToolsModule.getDate(new Date(time)) if(YMD == timToolsModule.getDate(new Date())){ return timToolsModule.getTime(new Date(time)) } // return YMD +'\xa0\xa0'+ timToolsModule.getTime(new Date(time)) return getDate(new Date(time)) } /** * 返回年月日 * @export * @param {Date} date * @param {string} [splitor='-'] * @returns */ function getDate(date, splitor = '-') { const year = date.getFullYear(); const month = date.getMonth() + 1; const day = date.getDate(); return `${year}${splitor}${addZeroPrefix(month)}${splitor}${addZeroPrefix(day)}`; } /** * 返回时分秒/时分 * @export * @param {*} date * @param {boolean} [withSecond=false] * @returns */ function getTime(date, withSecond = false) { const hour = date.getHours() const minute = date.getMinutes() const second = date.getSeconds() return withSecond ? `${addZeroPrefix(hour)}:${addZeroPrefix(minute)}:${addZeroPrefix(second)}` : `${hour}:${addZeroPrefix(minute)}` } /** * 个位数,加0前缀 * @param {*} number * @returns */ function addZeroPrefix(number) { return number < 10 ? `0${number}`:number } // 判断事件是否是今天 function isToday(time) { return new Date(time * 1000).toDateString() === new Date().toDateString() } // 比较两个时间是否间隔超过3分钟 function compareTimeExceed(curTime, preTime){ return (curTime - preTime) > 3 * 60; } // 比较两个时间是否是同一天的 function compareTime(curTime, preTime){ return getDate(new Date(curTime * 1000)) == getDate(new Date(preTime * 1000)); } // 拿到 头像 图片 function getAvatarImg(conversationItem) { switch (conversationItem.type) { case groupType: return defaultAvatarImg(conversationItem.groupProfile.avatar); case c2cType: return defaultAvatarImg(conversationItem.userProfile.avatar); default: return ''; } } // 当图片没有的时候,给一个默认图片 function defaultAvatarImg(imgSrc){ return imgSrc || defaultImage; } // 重新装载一次各类型图片 function getMsgObj(msgItem){ var obj = {}; obj.tiem = msgItem.time; obj.flow = msgItem.flow; obj.ID = msgItem.ID; switch(msgItem.type){ case allowType["text"]: obj.type = msgItem.type; obj.text = msgItem.payload.text; break; case allowType["image"]: obj.type = msgItem.type; obj.height = msgItem.payload.imageInfoArray[0].height; obj.width = msgItem.payload.imageInfoArray[0].width; obj.imageUrl = msgItem.payload.imageInfoArray[0].imageUrl; break; case allowType["video"]: obj.type = msgItem.type; obj.thumbHeight = msgItem.payload.thumbHeight; obj.thumbWidth = msgItem.payload.thumbWidth; obj.thumbUrl = msgItem.payload.thumbUrl; obj.videoUrl = msgItem.payload.videoUrl; break; case allowType["file"]: obj.type = msgItem.type; obj.fileName = msgItem.payload.fileName; obj.fileSize = msgItem.payload.fileSize; obj.fileUrl = msgItem.payload.fileUrl; obj.uuid= msgItem.payload.uuid; break; default: obj.type = allowType["text"]; obj.text = '暂不支持的消息类型,请在手机端查看'; break; } return obj; } // 判断是否是表情 function isEmoji(t_value){ var param = /^\[.*\]$/; if(param.test(t_value) && initEmoji.emojiMap[t_value] && initEmoji.emojiMap[t_value] != ''){ return initEmoji.emojiUrl + initEmoji.emojiMap[t_value] }else{ return '' } } // 生成 guid function guid() { return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) { var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8); return v.toString(16); }); } // 计算文件 具体大小 function getFileSize(fileSize) { const size = fileSize; if (size > 1024) { if (size / 1024 > 1024) { return `${toFixed(size / 1024 / 1024)} Mb`; } return `${toFixed(size / 1024)} Kb`; } return `${toFixed(size / 1)}B`; } // 保留几位小数 function toFixed(number, precision = 2) { return number.toFixed(precision) } // 等到文件的 默认icon function fileCover(fileUrl, fileName, baseHead_url) { var cover; // const postfix = fileUrl.substring(fileUrl.lastIndexOf('.') + 1, fileUrl.length) const postfix = fileName.substring(fileName.lastIndexOf('.') + 1, fileName.length) switch(postfix){ case 'pdf': cover = baseHead_url + 'ntalk_tim/images/pdf.png'; break; case 'zip': cover = baseHead_url + 'ntalk_tim/images/zip.png'; break; case 'doc': cover = baseHead_url + 'ntalk_tim/images/doc.png'; break; case 'docx': cover = baseHead_url + 'ntalk_tim/images/doc.png'; break; case 'xls': cover = baseHead_url + 'ntalk_tim/images/xls.png'; break; case 'xlsx': cover = baseHead_url + 'ntalk_tim/images/xls.png'; break; case 'ppt': cover = baseHead_url + 'ntalk_tim/images/ppt.png'; break; case 'pptx': cover = baseHead_url + 'ntalk_tim/images/ppt.png'; break; default: cover = baseHead_url + 'ntalk_tim/images/txt.png'; break; } return cover } function getProfileName(item){ if(item.conversationID.indexOf(c2cType) !== -1){ return item.userProfile.nick; }else if(item.conversationID.indexOf(groupType) !== -1){ return item.groupProfile.name; } return ''; } // 判断是否是链接 function isHttpOrHttps(val){ if(val && val != '' && (val.startsWith("http") || val.startsWith("https"))){ return true; } return false; } // 删除文字首尾两边空格 function tirm(str){ return str.replace(/(^\s*)|(\s*$)/g, ""); } // set localStorage数据 function setlocalStorageItem(_id, _name){ if(_id == '' || _name == '') return; let localStorageStr = localStorage.getItem('$NTALK_IMSDK') || '{}'; let localStorageTab = JSON.parse(localStorageStr); localStorageTab[_id] = _name; localStorage.setItem('$NTALK_IMSDK', JSON.stringify(localStorageTab)); } // get localStorage数据 function getlocalStorageItem(_id){ if(_id == '') return ''; let localStorageStr = localStorage.getItem('$NTALK_IMSDK') || '{}'; let localStorageTab = JSON.parse(localStorageStr); return localStorageTab[_id] || ''; } return { onerrorFN: onerrorFN, showTime: showTime, getDate: getDate, getTime: getTime, isToday: isToday, compareTime: compareTime, compareTimeExceed: compareTimeExceed, getAvatarImg: getAvatarImg, defaultAvatarImg: defaultAvatarImg, getMsgObj: getMsgObj, isEmoji: isEmoji, guid: guid, getFileSize: getFileSize, fileCover: fileCover, getProfileName: getProfileName, isHttpOrHttps: isHttpOrHttps, tirm: tirm, setlocalStorageItem: setlocalStorageItem, getlocalStorageItem: getlocalStorageItem, } })(initEmoji); // 组件对象,主要逻辑操作都封装在这里 ;(function(document, timToolsModule, initEmoji){ const defaultImage = 'https://imgcache.qq.com/open/qcloud/video/act/webim-avatar/avatar-2.png'; // 默认图片 let loadingImage = '{{baseHead_url}}ntalk_tim/images/loading.gif'; // loading图片 const c2cType = 'C2C'; // 新会话类型,基本都是单聊形式 const groupType = 'GROUP'; // 群组类型 let curLoginPortrait; // 保存当前登录用户的头像 let currentSelectConversation; // 保存当前选中的会话 const allowType = { "text": "TIMTextElem", "image": "TIMImageElem", "video": "TIMVideoFileElem", "file": "TIMFileElem", // "custom": "TIMCustomElem", }; const tqlHtml = `
回到最新位置

最近联系的人

`; // 初始化对象 var TimComponent = function(opt) { this.SDKAppID = opt.SDKAppID; this.userId = opt.userId; this.userSig = opt.userSig; this.privateChatId = opt.privateChatId; this.privateChatName = opt.privateChatName; this.timPosition = opt.timPosition; // 位置状态:1、居中;2、左上;3、左下;4、右上;5、右下 this.baseHead_url = opt.baseHead_url || ''; // 模板类型 this.unreadListener = opt.unreadListener || undefined; // 回调函数 this.unreadChangeListener = opt.unreadChangeListener || undefined; // 回调函数 this.tim; // 记录会话列表 this.conversationListData = []; // 记录当前消息列表 this.currentMsgData = []; // 记录当前消息列表 是否已加载完成 this.isCompleted = true; // 记录当前消息列表未加载完成的 分页续拉ID this.nextReqMessageID = ''; // 记录上一次点击的会话 this.lastTimeConversationID = ''; // 记录私聊用户信息 this.privateChatOpt = { userID: '', nick: '', avatar: '', selfSignature: '' } var options = { SDKAppID: this.SDKAppID // 接入时需要将0替换为您的即时通信 IM 应用的 SDKAppID }; // 创建 SDK 实例,`TIM.create()`方法对于同一个 `SDKAppID` 只会返回同一份实例 this.tim = TIM.create(options); // 设置 SDK 日志输出级别,详细分级请参见 setLogLevel 接口的说明 this.tim.setLogLevel(4); // 普通级别,日志量较多,接入时建议使用 // tim.setLogLevel(1); // release 级别,SDK 输出关键信息,生产环境时建议使用 // 注册腾讯云即时通信 IM 上传插件,即时通信 IM SDK 发送图片、语音、视频、文件等消息需要使用上传插件,将文件上传到腾讯云对象存储 // this.tim.registerPlugin({'tim-upload-plugin': TIMUploadPlugin}); // 注册 cos this.tim.registerPlugin({ 'cos-js-sdk': COS }) this.bindTimEvent(this); this.isLogin = false; this.J_timContainer = document.querySelector('#J_timContainer'); this.J_timLeft; this.J_timLeft_portrait, this.J_timLeft_switch; this.J_timRight; this.J_timRTop_info_img; this.J_timRTop_info_name_fir; this.J_timRTop_info_name_sec; this.J_timRTop_reduce; this.J_inputMsg; this.icon_happy; this.J_timSend; this.emojis; this.J_timRBottom_image; this.J_imagePicker; this.J_timAmplify; this.J_timAmplify_img; this.J_timRBottom_file this.J_videoPicker; this.J_filePicker; this.J_timTips; this.J_timTips_span; this.J_timLoading; this.J_timReturn_newMsg; this.J_timMsg_moreHandle; this.J_timRMiddle; this.copyEle; this.forwardEle; this.recallEle; this.downloadEle; this.J_timForward_layer; this.J_timForward_list; this.J_timForward_btn_close; this.J_timForward_btn_forward; } // SDK 登录 TimComponent.prototype.handleLogin = function(opt){ var _this = this; let userId = opt.userId; let promise = this.tim.login({userID: opt.userId, userSig: opt.userSig}); promise.then(function(imResponse) { console.log('login success===========================>>') _this.initDOM(); // _this.tipsShow('登录成功'); _this.isLogin = true; _this.J_timContainer.style.display = 'flex'; _this.initParam(opt); _this.handleTimPosition(_this.timPosition); if (imResponse.data.repeatLogin === true) { // 标识账号已登录,本次登录操作为重复登录。v2.5.1 起支持 _this.tipsShow(imResponse.data.errorInfo); } }).catch(function(imError) { _this.isLogin = false; console.warn('login error:', imError); // 登录失败的相关信息 }); } // 加载 dom节点模板 TimComponent.prototype.initDOM = function(){ this.J_timContainer.innerHTML = ''; // J_timTql = document.querySelector('#J_timTql'); this.J_timContainer.innerHTML = tqlHtml.replace(/{{baseHead_url}}/g, this.baseHead_url); loadingImage = loadingImage.replace(/{{baseHead_url}}/g, this.baseHead_url);; this.J_timLeft = this.J_timContainer.querySelector('.J_timLeft'); this.J_timLeft_portrait = this.J_timLeft.querySelector('.J_timLeft_portrait'), this.J_timLeft_switch = this.J_timLeft.querySelector('.J_timLeft_switch'); this.J_timRight = this.J_timContainer.querySelector('.J_timRight'); // this.J_timRTop_info_img = this.J_timRight.querySelector('.J_timRTop_info img'); this.J_timRTop_info_name_fir = this.J_timRight.querySelectorAll('.J_timRTop_info_name span')[0]; // this.J_timRTop_info_name_sec = this.J_timRight.querySelectorAll('.J_timRTop_info_name span')[1]; this.J_timRTop_reduce = this.J_timRight.querySelector('.J_timRTop_reduce'); this.J_inputMsg = this.J_timRight.querySelector('#J_inputMsg'); this.icon_happy = this.J_timRight.querySelector('.J_timRBottom_emojis'); this.J_timSend = this.J_timRight.querySelector('.J_timSend'); this.emojis = this.J_timContainer.querySelector('.emojis'); this.J_timRBottom_image = this.J_timRight.querySelector('.J_timRBottom_image'); this.J_imagePicker = this.J_timContainer.querySelector('#J_imagePicker'); this.J_timAmplify = this.J_timContainer.querySelector('.J_timAmplify'); this.J_timAmplify_img = this.J_timContainer.querySelector('.J_timAmplify img'); this.J_timRBottom_file = this.J_timRight.querySelector('.J_timRBottom_file'); this.J_videoPicker = this.J_timContainer.querySelector('#J_videoPicker'); this.J_filePicker = this.J_timContainer.querySelector('#J_filePicker'); this.J_timTips = this.J_timContainer.querySelector('.J_timTips'); this.J_timTips_span = this.J_timContainer.querySelector('.J_timTips span'); this.J_timLoading = this.J_timContainer.querySelector('.J_timLoading'); this.J_timReturn_newMsg = this.J_timContainer.querySelector('.J_timReturn_newMsg'); this.J_timMsg_moreHandle = this.J_timContainer.querySelector('.J_timMsg_moreHandle'); this.J_timRMiddle = this.J_timContainer.querySelector('.J_timRMiddle'); this.copyEle = this.J_timMsg_moreHandle.querySelector('.copy'); this.forwardEle = this.J_timMsg_moreHandle.querySelector('.forward'); this.recallEle = this.J_timMsg_moreHandle.querySelector('.recall'); this.downloadEle = this.J_timMsg_moreHandle.querySelector('.download'); this.J_timForward_layer = this.J_timContainer.querySelector('.J_timForward_layer'); this.J_timForward_list = this.J_timForward_layer.querySelector('.J_timForward_list'); this.J_timForward_btn_close = this.J_timForward_layer.querySelectorAll('.J_timForward_btn button')[0]; this.J_timForward_btn_forward = this.J_timForward_layer.querySelectorAll('.J_timForward_btn button')[1]; // this.bindTimEvent(); this.bindEleEvent(); this.renderEmojiList(); //首次让从左边滑过来 // this.reduceClick(); this.initMousedown(); } // 理论上update 是切换新的私聊操作 TimComponent.prototype.updateOpt = function(opt){ var _this = this; // this.privateChatId = opt.privateChatId; // currentSelectConversation = c2cType + this.privateChatId; this.initParam(opt); this.getPrivateChatProfile(this.privateChatId); // 获得会话列表 this.getConversationList(); // 当切换用户的时候 再获得一次新用户的 会话列表 if(_this.privateChatId == ''){ setTimeout(function(){ _this.getMsgList(c2cType + _this.privateChatId); }, 1000) }else{ _this.getMsgList(c2cType + _this.privateChatId); } // 判断私聊用户是不是一个新的会话 this.isNewConversation(); } // 无论实例是否是第一次初始化,或者是第一次登录,或者更新切换新的私聊 都需要重置的值 TimComponent.prototype.initParam = function(opt){ this.privateChatId = opt.privateChatId; this.privateChatName = opt.privateChatName; timToolsModule.setlocalStorageItem(this.privateChatId, this.privateChatName); currentSelectConversation = this.privateChatId != '' ? c2cType + this.privateChatId : ''; this.conversationListData = []; this.currentMsgData = []; this.isCompleted = true; this.nextReqMessageID = ''; this.lastTimeConversationID = ''; this.privateChatOpt = { userID: '', nick: '', avatar: '', selfSignature: '' } this.timPosition = opt.timPosition; this.unreadListener = opt.unreadListener || undefined; this.unreadChangeListener = opt.unreadChangeListener || undefined; // 回调函数 this.isMaxContainer(); } TimComponent.prototype.getPrivateChatProfile = function(_userid){ if(_userid == ''){ return } var _this = this; let promise = this.tim.getUserProfile({ userIDList: [_userid] }); promise.then(function(imResponse) { // console.log(imResponse.data); // 存储用户资料的数组 - [Profile] _this.privateChatOpt = { userID: imResponse.data[0].userID, nick: imResponse.data[0].nick || imResponse.data[0].userID, avatar: imResponse.data[0].avatar, selfSignature: imResponse.data[0].selfSignature } }).catch(function(imError) { console.warn('getUserProfile error:', imError); // 获取其他用户资料失败的相关信息 }); } // 绑定tim 事件 TimComponent.prototype.bindTimEvent = function(_this){ this.tim.on(TIM.EVENT.SDK_READY, this.onReadyEvent.bind(this)); this.tim.on(TIM.EVENT.SDK_NOT_READY, this.onNotReadyEvent.bind(this)); this.tim.on(TIM.EVENT.KICKED_OUT, this.onKickedOutEvent.bind(this), this); this.tim.on(TIM.EVENT.NET_STATE_CHANGE, this.onNetStateChangeEvent.bind(this), this); this.tim.on(TIM.EVENT.MESSAGE_RECEIVED, this.onMsgReceivedEvent.bind(_this), _this); this.tim.on(TIM.EVENT.CONVERSATION_LIST_UPDATED, this.onUpdateConversationListEvent.bind(this), this); this.tim.on(TIM.EVENT.ERROR, this.onErrorEvent.bind(this)); this.tim.on(TIM.EVENT.MESSAGE_REVOKED, this.onMessageRevokedEvent.bind(this), this); } // 取消tim 事件监听,有点问题好像不会生效 TimComponent.prototype.destroyBindTimEvent = function(){ this.tim.off(TIM.EVENT.SDK_READY, this.onReadyEvent.bind(this)); this.tim.off(TIM.EVENT.SDK_NOT_READY, this.onNotReadyEvent.bind(this)); this.tim.off(TIM.EVENT.KICKED_OUT, this.onKickedOutEvent.bind(this)); this.tim.off(TIM.EVENT.NET_STATE_CHANGE, this.onNetStateChangeEvent.bind(this)); this.tim.off(TIM.EVENT.MESSAGE_RECEIVED, this.onMsgReceivedEvent.bind(this)); this.tim.off(TIM.EVENT.CONVERSATION_LIST_UPDATED, this.onUpdateConversationListEvent.bind(this)); this.tim.off(TIM.EVENT.ERROR, this.onErrorEvent.bind(this)); this.tim.off(TIM.EVENT.MESSAGE_REVOKED, this.onMessageRevokedEvent.bind(this), this); } TimComponent.prototype.onMessageRevokedEvent = function(event){ // 收到消息被撤回的通知。使用前需要将SDK版本升级至v2.4.0或更高版本。 // event.name - TIM.EVENT.MESSAGE_REVOKED // event.data - 存储 Message 对象的数组 - [Message] - 每个 Message 对象的 isRevoked 属性值为 true console.log('MESSAGE_REVOKED', event.data) if(event.data[0].conversationID == currentSelectConversation){ this.updateRevokedMsgList(event.data[0]); }else{ this.conversationListData.forEach( item => { if(event.data[0].conversationID == item.conversationID){ item.unreadCount += 1; } }) //更新会话 this.createLeftInfoList(this.conversationListData, { updateList: true }); } } // SDK 发生错误时事件监听 TimComponent.prototype.onErrorEvent = function(event){ // 收到 SDK 发生错误通知,可以获取错误码和错误信息 // event.name - TIM.EVENT.ERROR // event.data.code - 错误码 // event.data.message - 错误信息 console.log('TIM.EVENT.ERROR',event) } // SDK not ready时事件监听 TimComponent.prototype.onNotReadyEvent = function(event) { // 收到 SDK 进入 not ready 状态通知,此时 SDK 无法正常工作 // event.name - TIM.EVENT.SDK_NOT_READY // this.tipsShow('小壹暂时无法正常工作,先帮您提前下线~'); // this.J_timLeft_switch.click(); console.log('SDK_NOT_READY'); }; // SDK 收到被踢下线监听 TimComponent.prototype.onKickedOutEvent = function(event) { // 收到被踢下线通知 // event.name - TIM.EVENT.KICKED_OUT // event.data.type - 被踢下线的原因,例如 : // - TIM.TYPES.KICKED_OUT_MULT_ACCOUNT 多实例登录被踢 // - TIM.TYPES.KICKED_OUT_MULT_DEVICE 多终端登录被踢 // - TIM.TYPES.KICKED_OUT_USERSIG_EXPIRED 签名过期被踢(v2.4.0起支持)。 console.log('onKickedOut',event) switch(event.data.type){ case TIM.TYPES.KICKED_OUT_MULT_ACCOUNT: this.handleLogout('多终端登录,此处被下线~'); break; case TIM.TYPES.KICKED_OUT_MULT_DEVICE: this.handleLogout('多终端登录,此处被下线~'); break; case TIM.TYPES.KICKED_OUT_USERSIG_EXPIRED: this.handleLogout('签名过期,此处被下线~'); break; default: break; } this.isLogin = false; }; // SDK 收到网络状态更改 TimComponent.prototype.onNetStateChangeEvent = function(event) { // 网络状态发生改变(v2.5.0 起支持)。 // event.name - TIM.EVENT.NET_STATE_CHANGE // event.data.state 当前网络状态,枚举值及说明如下: // - TIM.TYPES.NET_STATE_CONNECTED - 已接入网络 // - TIM.TYPES.NET_STATE_CONNECTING - 连接中。很可能遇到网络抖动,SDK 在重试。接入侧可根据此状态提示“当前网络不稳定”或“连接中” // - TIM.TYPES.NET_STATE_DISCONNECTED - 未接入网络。接入侧可根据此状态提示“当前网络不可用”。SDK 仍会继续重试,若用户网络恢复,SDK 会自动同步消息 switch(event.data.state){ case TIM.TYPES.NET_STATE_CONNECTING: this.tipsShow('网络连接中~'); break; case TIM.TYPES.NET_STATE_DISCONNECTED: this.tipsShow('未连接网络~'); break; default: break; } }; // SDK 收到会话列表更新 TimComponent.prototype.onUpdateConversationListEvent = function(event){ // 收到会话列表更新通知,可通过遍历 event.data 获取会话列表数据并渲染到页面 // event.name - TIM.EVENT.CONVERSATION_LIST_UPDATED // event.data - 存储 Conversation 对象的数组 - [Conversation] console.log('CONVERSATION_LIST_UPDATED',event.data) this.updateConversationList(event.data, { updateList: true }); let unreadCount = 0; event.data.forEach(item => { unreadCount += item.unreadCount; }); this.unreadListener && unreadCount >= 0 && this.unreadListener(unreadCount); } // SDK 收到单聊,群聊新消息提示 TimComponent.prototype.onMsgReceivedEvent = function(event){ // 收到推送的单聊、群聊、群提示、群系统通知的新消息,可通过遍历 event.data 获取消息列表数据并渲染到页面 // event.name - TIM.EVENT.MESSAGE_RECEIVED // event.data - 存储 Message 对象的数组 - [Message] console.log('MESSAGE_RECEIVED',event.data) if(event.data[0].conversationID == currentSelectConversation){ this.updateCurrentMsgList(event.data[0]); } } // SDK ready状态 TimComponent.prototype.onReadyEvent = function(event) { var _this = this; this.getPrivateChatProfile(this.privateChatId); // 获得会话列表 this.getConversationList(); // this.getFriendList(); // 获得首个消息列表 现在写死成私聊成员 if(_this.privateChatId == ''){ setTimeout(function(){ _this.getMsgList(c2cType + _this.privateChatId); }, 1000) }else{ _this.getMsgList(c2cType + _this.privateChatId); } // 判断私聊用户是不是一个新的会话 this.isNewConversation(); } // 判断私聊用户是否在 已有会话中 TimComponent.prototype.isNewConversation = function(){ if(this.privateChatId == ''){ return } var _this = this; var isNew = this.conversationListData.some( item => { return item.conversationID == c2cType + _this.privateChatId; }) !isNew && this.getUserProfile(c2cType + _this.privateChatId); } // 获得好友列表 TimComponent.prototype.getFriendList = function(){ this.tim.getFriendList().then(({ data: friendList }) => { console.log('friendList',...friendList); }) } // 获得会话列表 TimComponent.prototype.getConversationList = function(){ // 拉取会话列表 var _this = this; let getConversationListPromise = this.tim.getConversationList(); getConversationListPromise.then(function(imResponse) { const conversationList = imResponse.data.conversationList; // 会话列表,用该列表覆盖原有的会话列表 _this.updateConversationList(conversationList, { updateList: false }); }).catch(function(imError) { console.warn('getConversationList error:', imError); // 获取会话列表失败的相关信息 }); } // 更改会话列表 TimComponent.prototype.updateConversationList = function(conversationList, opt){ var _this = this; let arr = []; for (let i in this.conversationListData) { let flag = 0; for (let a in conversationList) { if ( _this.conversationListData[i].conversationID == conversationList[a].conversationID ) { flag = 1; } } if (!flag) { //若没有则存入 arr.push(_this.conversationListData[i]); } } _this.conversationListData = arr.concat(conversationList); //更新会话 _this.createLeftInfoList(_this.conversationListData, { updateList: opt.updateList }); } // 更改当前消息列表,添加一条消息的时候 TimComponent.prototype.updateCurrentMsgList = function(lastMsg){ this.currentMsgData.push(lastMsg); this.renderMsgList(this.currentMsgData); } // 更改当前消息列表,撤销状态更改 TimComponent.prototype.updateRevokedMsgList = function(msgItem){ this.currentMsgData.forEach(item => { if(msgItem.ID == item.ID){ item.isRevoked = msgItem.isRevoked; } }) this.renderMsgList(this.currentMsgData); } // 创建左边栏信息,主要是 会话信息 TimComponent.prototype.createLeftInfoList = function(dataList, opt){ var _this = this; // 先清空数据 this.J_timLeft_portrait.innerHTML = ''; var d = document.createDocumentFragment(); let _newC2C = this.privateChatId; let newC2CIndex = -1; if(_newC2C && _newC2C !== ''){ newC2CIndex = dataList.findIndex(item => { return item.conversationID == c2cType + _newC2C; }) if(newC2CIndex === -1){ _this.createNewConversation({ conversationID: c2cType + _newC2C, img: _this.privateChatOpt.avatar, unreadCount: 0 }, d); } } dataList.forEach(item => { _this.createNewConversation({ conversationID: item.conversationID, img: timToolsModule.getAvatarImg(item), unreadCount: item.unreadCount }, d); }); this.J_timLeft_portrait.appendChild(d); let currentSelectConIndex = -1; if(currentSelectConversation && currentSelectConversation !== ''){ for(var i = 0; i < this.J_timLeft_portrait.children.length; i++){ if(this.J_timLeft_portrait.children[i].dataset.conversationid == currentSelectConversation){ currentSelectConIndex = i; } } } // 模拟点击选中 // 1、私聊,私聊人员不在列表中,会加载到第一个,默认选中私聊 // 2、私聊,如果私聊人员在会话列表中则选中 私聊人员 // 3、不是私聊,默认选中上一次选中的item // 4、不是私聊,第一次打开也是默认选中 第一个 let selectIndex = currentSelectConIndex; // updateList的时候 是更新列表 已选中的优先级更高 if(opt.updateList){ selectIndex = currentSelectConIndex === -1 ? newC2CIndex === -1 ? 0 : newC2CIndex : currentSelectConIndex; }else{ if(_newC2C && _newC2C !== ''){ selectIndex = newC2CIndex === -1 ? 0 : newC2CIndex; }else{ selectIndex = currentSelectConIndex === -1 ? 0 : currentSelectConIndex; } } this.J_timLeft_portrait.children.forEach((item, i) => { if( i == selectIndex ){ item.className += ' hoverC'; _this.updateProfile(item.dataset.conversationid, item); currentSelectConversation = item.dataset.conversationid; var _span = item.getElementsByTagName('span'); if(_span[0].dataset.unreadCount > 0 && item.dataset.conversationid == currentSelectConversation){ if(this.J_timRight.style.opacity == 0){ _span[0].style.display = 'block'; }else{ this.sendMsgRead(item.dataset.conversationid); _span[0].dataset.unreadCount = 0; _span[0].style.display = 'none'; } } } item.addEventListener('click', _this.portraitItemClick.bind(_this), false); }) // this.J_timLeft_portrait.children[selectIndex].click(); } // 通过已知的会话列表 更新用户或者群组信息 TimComponent.prototype.updateProfile = function(conversationid, target){ var _this = this; this.conversationListData.forEach( item => { if(item.conversationID == conversationid){ _this.J_inputMsg.dataset.conversationid = conversationid; if(conversationid.indexOf(c2cType) !== -1){ this.renderProfile({ img: timToolsModule.defaultAvatarImg(item.userProfile.avatar), nick: item.userProfile.nick || item.userProfile.userID, selfSignature: item.userProfile.userID, //selfSignature userId: item.userProfile.userID, },target) // 切换会话时把信息回调 this.changeCallBack({ conversationID: conversationid, userName: item.userProfile.nick || item.userProfile.userID, }); }else if(conversationid.indexOf(groupType) !== -1){ this.renderProfile({ img: timToolsModule.defaultAvatarImg(item.groupProfile.avatar), nick: item.groupProfile.name, selfSignature: '这是一个群组', userId: '', },target) // 切换会话时把信息回调 this.changeCallBack({ conversationID: conversationid, userName: item.groupProfile.name, }); } } }) } // 创建左边列表Item,主要需要数据为 conversationID和img /** * * @param {*} opt * { * conversationID: 会话id * img: 图片 * unreadCount: 未读信息条数 * } * @param {*} d 创建的文档碎片 */ TimComponent.prototype.createNewConversation = function (opt, d){ var _div = document.createElement('div'); _div.dataset.conversationid = opt.conversationID; _div.className = 'J_timLeft_portraitC'; var _img = document.createElement('img'); _img.src = opt.img; _img.alt = ''; timToolsModule.onerrorFN(_img); _div.appendChild(_img); var _span = document.createElement('span'); _span.dataset.unreadCount = opt.unreadCount; _span.style.display = opt.unreadCount > 0 ? 'block' : 'none'; _div.appendChild(_span); d.appendChild(_div); } // 绑定左边各item的点击事件 TimComponent.prototype.portraitItemClick = function (e){ var e = e || window.event, // target = e.target || e.srcElement; target = e.currentTarget; e.stopPropagation(); currentSelectConversation = target.dataset.conversationid; this.J_timLeft_portrait.children.forEach(nodeItem => { nodeItem.className = 'J_timLeft_portraitC'; }) target.className += ' hoverC'; var _span = target.getElementsByTagName('span'); if(_span[0].dataset.unreadCount > 0 && target.dataset.conversationid == currentSelectConversation){ this.sendMsgRead(target.dataset.conversationid); _span[0].dataset.unreadCount = 0; _span[0].style.display = 'none'; }else{ _span[0].style.display = 'none'; } this.getUserProfile(target.dataset.conversationid, true); this.getMsgList(target.dataset.conversationid); this.isMaxContainer(); } // 组装右边部分数据 TimComponent.prototype.getUserProfile = function(conversationID, switchFlag){ // const conversationID = tar.dataset.conversationid; var _this = this; this.J_inputMsg.dataset.conversationid = conversationID; // this.bindInputkeypress(); if(conversationID.indexOf(c2cType) !== -1){ //获得个人的详细资料 let promise = this.tim.getUserProfile({ userIDList: [conversationID.replace(c2cType, '')] // 请注意:即使只拉取一个用户的资料,也需要用数组类型,例如:userIDList: ['user1'] }); promise.then(function(imResponse) { // console.log('getUserProfile',imResponse.data); // 存储用户资料的数组 - [Profile] _this.renderProfile({ img: timToolsModule.defaultAvatarImg(imResponse.data[0].avatar), nick: imResponse.data[0].nick || imResponse.data[0].userID, selfSignature: imResponse.data[0].userID, //selfSignature userId: imResponse.data[0].userID, }) // 切换会话时把信息回调 switchFlag && _this.changeCallBack({ conversationID: conversationID, userName: imResponse.data[0].nick || imResponse.data[0].userID, }); }).catch(function(imError) { console.warn('getUserProfile error:', imError); // 获取其他用户资料失败的相关信息 }); }else if(conversationID.indexOf(groupType) !== -1){ //获得群组的详细资料 let promise = this.tim.getGroupProfile({ groupID: conversationID.replace(groupType, '') }); promise.then(function(imResponse) { // console.log(imResponse.data.group); _this.renderProfile({ img: timToolsModule.defaultAvatarImg(imResponse.data.avatar), nick: imResponse.data.group.name + '(' + imResponse.data.group.memberCount + ')', selfSignature: '群组', userId: '', }) // 切换会话时把信息回调 switchFlag && _this.changeCallBack({ conversationID: conversationID, userName: imResponse.data.group.name + '(' + imResponse.data.group.memberCount + ')', }); }).catch(function(imError) { console.warn('getGroupProfile error:', imError); // 获取群详细资料失败的相关信息 }); } } // 渲染用户或者群组信息 TimComponent.prototype.renderProfile = function(opt){ // this.J_timRTop_info_img.src = opt.img; // timToolsModule.onerrorFN(this.J_timRTop_info_img); this.J_timRTop_info_name_fir.innerHTML = timToolsModule.getlocalStorageItem(opt.userId.replace(c2cType, '')) || opt.nick; // this.J_timRTop_info_name_sec.innerHTML = opt.selfSignature; //imResponse.data.group.ownerID // tar.querySelector('img').src = opt.img; // timToolsModule.onerrorFN(tar.querySelector('img').src); } // 把信息回调 TimComponent.prototype.changeCallBack = function(opt){ let id; let types; if(opt.conversationID.indexOf(c2cType) !== -1){ id = opt.conversationID.replace(c2cType, ''); types = c2cType; }else if(opt.conversationID.indexOf(groupType) !== -1){ id = opt.conversationID.replace(groupType, ''); types = groupType; } this.unreadChangeListener && this.unreadChangeListener(this.J_timRTop_info_name_fir,{ type: types, userId: id, userName: opt.userName, }) } // 组装当前选中第一次消息列表数据 TimComponent.prototype.getMsgList = function(conversationID){ if(conversationID == c2cType && this.conversationListData[0] && this.conversationListData[0].conversationID != ''){ conversationID = this.conversationListData[0].conversationID; }else if(conversationID == this.lastTimeConversationID){ return; }else if(conversationID == c2cType){ return; } this.lastTimeConversationID = conversationID; var _this = this; // const conversationID = conversationItem.dataset.conversationid; // 打开某个会话时,第一次拉取消息列表 let promise = this.tim.getMessageList({conversationID: conversationID ,count: 15}); promise.then(function(imResponse) { const messageList = imResponse.data.messageList; // 消息列表。 const nextReqMessageID = imResponse.data.nextReqMessageID; // 用于续拉,分页续拉时需传入该字段。 const isCompleted = imResponse.data.isCompleted; // 表示是否已经拉完所有消息。 _this.isCompleted = isCompleted; if(!isCompleted){ _this.nextReqMessageID = nextReqMessageID || ''; } _this.currentMsgData = messageList; _this.renderMsgList(_this.currentMsgData); }); } // 组装当前选中消息列表 分页数据 TimComponent.prototype.getNextReqMsgList = function(){ var _this = this; // const conversationID = conversationItem.dataset.conversationid; const conversationID = currentSelectConversation; // 打开某个会话时,第一次拉取消息列表 let promise = this.tim.getMessageList({conversationID: conversationID, nextReqMessageID: this.nextReqMessageID, count: 15}); promise.then(function(imResponse) { const messageList = imResponse.data.messageList; // 消息列表。 const nextReqMessageID = imResponse.data.nextReqMessageID; // 用于续拉,分页续拉时需传入该字段。 const isCompleted = imResponse.data.isCompleted; // 表示是否已经拉完所有消息。 _this.isCompleted = isCompleted; if(!isCompleted){ _this.nextReqMessageID = nextReqMessageID || ''; } // _this.currentMsgData = messageList; _this.updateAllCurrentMsgList(isCompleted, messageList) _this.renderMsgList(_this.currentMsgData, true); _this.msgMiddleFirstItem(); _this.switchReturnElement(); }); } // 更新当前消息的所有信息 TimComponent.prototype.updateAllCurrentMsgList = function(isCompleted, messageList){ this.currentMsgData = [ // 更新当前消息列表,从头部插入 // 聊天记录 数组合并 ...messageList, ...this.currentMsgData, ] } // 组装右边消息列表数据 TimComponent.prototype.renderMsgList = function(messageList, lastMsgFlag){ var _this = this; // 先清空数据 _this.J_timRMiddle.innerHTML = ''; // 当isCompleted为false的时候,添加一个更多消息 if(!this.isCompleted){ _this.renderMoreMsgItem(); } // let userId = localStorage.getItem('#userID'); messageList.forEach((item, index) => { let timeFlag = false; // 显示时间规则 // 1、首条消息显示时间 // 2、当天消息全部显示时间 // 3、之前的消息只显示一次时间 if(index == 0 || (timToolsModule.isToday(item.time) && timToolsModule.compareTimeExceed(messageList[index].time, messageList[index - 1].time)) || !timToolsModule.compareTime(messageList[index].time, messageList[index - 1].time) ){ timeFlag = true; } timeFlag && _this.renderMsgMiddleItem({ flag: true, time: timToolsModule.showTime(item.time) }); if(item.conversationType == groupType){ _this.renderGroupMsg(item); }else if(item.conversationType == c2cType){ _this.renderC2CMsg(item); } }) if( !lastMsgFlag ){ setTimeout(function(){ _this.msgMiddleLastItem(); }, 1000) } } // 渲染 群组的消息列表 TimComponent.prototype.renderGroupMsg = function(item){ var _this = this; if(item.isRevoked && item.isRevoked == true){ _this.renderMsgMiddleItem({ flag: false, htmlVal: (item.flow == 'out' ? '您 ' : item.nick + ' ') + '撤回了一条消息' }); }else if(item.payload.data == 'group_create'){ _this.renderMsgMiddleItem({ flag: false, htmlVal: item.payload.extension || item.payload.description }); }else if(_this.userId == item.from){ _this.renderMsgRightItem({ item: timToolsModule.getMsgObj(item), htmlVal: item.payload.text || item.payload.description, img: timToolsModule.defaultAvatarImg(item.avatar) }); }else{ _this.renderMsgLeftItem({ item: timToolsModule.getMsgObj(item), htmlVal: item.payload.text || item.payload.description, img: timToolsModule.defaultAvatarImg(item.avatar) }); } } // 渲染 个人的消息列表 TimComponent.prototype.renderC2CMsg = function(item){ var _this = this; if(item.isRevoked && item.isRevoked == true){ _this.renderMsgMiddleItem({ flag: false, htmlVal: (item.flow == 'out' ? '您 ' : item.nick + ' ') + '撤回了一条消息' }); }else if(_this.userId == item.from){ _this.renderMsgRightItem({ item: timToolsModule.getMsgObj(item), htmlVal: item.payload.text || item.payload.description, img: timToolsModule.defaultAvatarImg(item.avatar) }); }else{ _this.renderMsgLeftItem({ item: timToolsModule.getMsgObj(item), htmlVal: item.payload.text || item.payload.description, img: timToolsModule.defaultAvatarImg(item.avatar) }); } } // 渲染 中间更多消息 TimComponent.prototype.renderMoreMsgItem = function(){ var d = document.createDocumentFragment(); var J_timR_msgM = document.createElement('div'); J_timR_msgM.className = 'J_timR_msgM'; var J_timR_msgM_more = document.createElement('div'); J_timR_msgM_more.className = 'J_timR_msgM_more'; J_timR_msgM_more.innerHTML = '查看更多'; J_timR_msgM_more.addEventListener('click', this.getNextReqMsgList.bind(this), false); J_timR_msgM.appendChild(J_timR_msgM_more); d.appendChild(J_timR_msgM); this.J_timRMiddle.appendChild(d); } // 组装消息列表左边数据 /** * * @param {*} opt * { * htmlVal: 显示信息 * img: 头像图片 * } */ TimComponent.prototype.renderMsgLeftItem = function(opt){ var d = document.createDocumentFragment(); var J_timR_msgL = document.createElement('div'); J_timR_msgL.className = 'J_timR_msgL'; var _img = document.createElement('img'); _img.src = opt.img; timToolsModule.onerrorFN(_img); J_timR_msgL.appendChild(_img); var _div = document.createElement('div'); _div.className = 'J_timR_msgL_con'; // var _span = document.createElement('span'); // _span.innerHTML = opt.htmlVal; // _div.appendChild(_span); var msgObj = opt.item; _div.appendChild(this.renderAllTypeMsg(msgObj)); J_timR_msgL.appendChild(_div); d.appendChild(J_timR_msgL); this.J_timRMiddle.appendChild(d); } // 组装消息列表中间数据 /** * * @param {} opt * { * flag: 判断是否是时间 * time: 时间秒数,基本时间和显示信息 二选一展示 * htmlVal: 显示信息 * } */ TimComponent.prototype.renderMsgMiddleItem = function(opt){ var d = document.createDocumentFragment(); var J_timR_msgM = document.createElement('div'); J_timR_msgM.className = 'J_timR_msgM'; var J_timR_msgM_con = document.createElement('div'); J_timR_msgM_con.className = 'J_timR_msgM_con'; if(opt.flag){ J_timR_msgM_con.innerHTML = opt.time; }else{ J_timR_msgM_con.className = 'J_timR_msgM_con revoke'; J_timR_msgM_con.innerHTML = opt.htmlVal; } J_timR_msgM.appendChild(J_timR_msgM_con); d.appendChild(J_timR_msgM); this.J_timRMiddle.appendChild(d); } // 组装消息列表右边数据 /** * * @param {*} opt * { * htmlVal: 显示信息 * img: 头像图片 * } */ TimComponent.prototype.renderMsgRightItem = function(opt){ curLoginPortrait = opt.img; var d = document.createDocumentFragment(); var J_timR_msgR = document.createElement('div'); J_timR_msgR.className = 'J_timR_msgR'; var _img = document.createElement('img'); _img.src = loadingImage; _img.style.display = opt.loading ? 'block' : 'none'; J_timR_msgR.appendChild(_img); var _div = document.createElement('div'); _div.className = 'J_timR_msgR_con'; var msgObj = opt.item; _div.appendChild(this.renderAllTypeMsg(msgObj)); J_timR_msgR.appendChild(_div); var _img = document.createElement('img'); _img.src = opt.img; timToolsModule.onerrorFN(_img); J_timR_msgR.appendChild(_img); d.appendChild(J_timR_msgR); this.J_timRMiddle.appendChild(d); } // 渲染所有类型的消息 TimComponent.prototype.renderAllTypeMsg = function(msgObj){ var ele; if(msgObj.type == allowType["text"]){ if(timToolsModule.isHttpOrHttps(msgObj.text)){ var _a = document.createElement('a'); _a.href = msgObj.text; _a.target = '_blank'; _a.innerHTML = msgObj.text; _a.dataset.id = msgObj.ID; _a.dataset.type = msgObj.type; _a.addEventListener('contextmenu', this.initContextmenuEvent.bind(this, msgObj.flow), false); ele = _a; }else{ var _div = document.createElement('div'); _div.className = 'J_textElem'; let decodeText_d = document.createDocumentFragment(); this.decodeText(msgObj.text, decodeText_d); _div.appendChild(decodeText_d); _div.dataset.id = msgObj.ID; _div.dataset.type = msgObj.type; _div.addEventListener('contextmenu', this.initContextmenuEvent.bind(this, msgObj.flow), false); ele = _div; } }else if(msgObj.type == allowType["image"]){ // 显示图片 var _img = document.createElement('img'); _img.className = 'J_imgElem'; _img.src = msgObj.imageUrl; _img.dataset.id = msgObj.ID; _img.dataset.type = msgObj.type; _img.dataset.imageUrl = msgObj.imageUrl; _img.addEventListener('contextmenu', this.initContextmenuEvent.bind(this, msgObj.flow), false); _img.addEventListener('click', this.amplifyImgEvent.bind(this), false); ele = _img; }else if(msgObj.type == allowType["video"]){ var _video = document.createElement('video'); _video.controls = 'controls'; _video.src = msgObj.videoUrl; _video.dataset.id = msgObj.ID; _video.dataset.type = msgObj.type; // _video.dataset.videoUrl = msgObj.videoUrl; _video.addEventListener('contextmenu', this.initContextmenuEvent.bind(this, msgObj.flow), false); ele = _video; }else if(msgObj.type == allowType["file"]){ var _div = document.createElement('div'); _div.className = 'J_fileElem'; if(!msgObj.loading){ _div.title = '单击下载'; _div.addEventListener('click', this.downloadFile.bind(this, msgObj.fileUrl, msgObj.fileName),false); _div.dataset.id = msgObj.ID; _div.dataset.type = msgObj.type; // _div.dataset.fileUrl = msgObj.fileUrl; // _div.dataset.fileName = msgObj.fileName; _div.addEventListener('contextmenu', this.initContextmenuEvent.bind(this, msgObj.flow), false); } var _img = document.createElement('img'); _img.src = timToolsModule.fileCover(msgObj.fileUrl, msgObj.fileName, this.baseHead_url); _img.height = '45'; _img.width = '45'; _div.appendChild(_img); var _divText = document.createElement('div'); _divText.className = 'J_fileElem_Text'; var _span = document.createElement('span'); _span.innerHTML = msgObj.fileName; _divText.appendChild(_span); var _spanSize = document.createElement('span'); _spanSize.innerHTML = timToolsModule.getFileSize(msgObj.fileSize); _divText.appendChild(_spanSize); _div.appendChild(_divText); ele = _div; } return ele; } // text: 'AAA[龇牙]AAA[龇牙]AAA[龇牙AAA]' TimComponent.prototype.decodeText = function(msgText, d) { // 文本消息 let temp = msgText; let left = -1; let right = -1; while (temp !== '') { left = temp.indexOf('['); right = temp.indexOf(']'); switch (left) { case 0: if (right === -1) { let _span = document.createElement('span'); _span.innerHTML = temp; d.appendChild(_span); temp = '' } else { let _emoji = temp.slice(0, right + 1) if (timToolsModule.isEmoji(_emoji) != '') { let _img = document.createElement('img'); _img.src = timToolsModule.isEmoji(_emoji); _img.height = 20; _img.width = 20; d.appendChild(_img); temp = temp.substring(right + 1); } else { let _span = document.createElement('span'); _span.innerHTML = '['; d.appendChild(_span); temp = temp.slice(1); } } break; case -1: let _span = document.createElement('span'); _span.innerHTML = temp; d.appendChild(_span); temp = ''; break; default: let default_span = document.createElement('span'); default_span.innerHTML = temp.slice(0, left); d.appendChild(default_span); temp = temp.substring(left); break; } } } // 下载文件 预览文件 TimComponent.prototype.downloadFile = function(fileUrl, fileName) { // 浏览器支持fetch则用blob下载,避免浏览器点击a标签,跳转到新页面预览的行为 if (window.fetch) { fetch(fileUrl) .then(res => res.blob()) .then(blob => { let a = document.createElement('a'); let url = window.URL.createObjectURL(blob); a.href = url; a.download = fileName; a.click(); }) } else { let a = document.createElement('a'); // a.href = 'https://view.officeapps.live.com/op/view.aspx?src=' + fileUrl; a.href = fileUrl; a.target = '_blank'; a.download = fileName; a.click(); } } // 发送消息 TimComponent.prototype.sendTextMsg = function(val){ var _this = this; const conversationID = this.J_inputMsg.dataset.conversationid; let id; let types; if(conversationID.indexOf(c2cType) !== -1){ id = conversationID.replace(c2cType, ''); types = TIM.TYPES.CONV_C2C; }else if(conversationID.indexOf(groupType) !== -1){ id = conversationID.replace(groupType, ''); types = TIM.TYPES.CONV_GROUP; } // 发送文本消息,Web 端与小程序端相同 // 1. 创建消息实例,接口返回的实例可以上屏 let message = this.tim.createTextMessage({ to: id, conversationType: types, // 消息优先级,用于群聊(v2.4.2起支持)。如果某个群的消息超过了频率限制,后台会优先下发高优先级的消息,详细请参考:https://cloud.tencent.com/document/product/269/3663#.E6.B6.88.E6.81.AF.E4.BC.98.E5.85.88.E7.BA.A7.E4.B8.8E.E9.A2.91.E7.8E.87.E6.8E.A7.E5.88.B6) // 支持的枚举值:TIM.TYPES.MSG_PRIORITY_HIGH, TIM.TYPES.MSG_PRIORITY_NORMAL(默认), TIM.TYPES.MSG_PRIORITY_LOW, TIM.TYPES.MSG_PRIORITY_LOWEST // priority: TIM.TYPES.MSG_PRIORITY_NORMAL, payload: { text: val }, // 消息自定义数据(云端保存,会发送到对端,程序卸载重装后还能拉取到,v2.10.2起支持) // cloudCustomData: 'your cloud custom data' }); // 2. 发送消息 let promise = this.tim.sendMessage(message); promise.then(function(imResponse) { // 发送成功 渲染页面 渲染到 消息列表的右边 console.log(imResponse); _this.updateCurrentMsgList(imResponse.data.message); }).catch(function(imError) { // 发送失败 console.warn('sendMessage error:', imError); }); } // 设置消息已读 TimComponent.prototype.sendMsgRead = function(conversationID){ var _this = this; // 将某会话下所有未读消息已读上报 let promise = this.tim.setMessageRead({conversationID: conversationID}); promise.then(function(imResponse) { console.log('sendMsgRead',imResponse) // 已读上报成功,指定 ID 的会话的 unreadCount 属性值被置为0 _this.unreadListener && _this.getAllUnreadCount(); }).catch(function(imError) { // 已读上报失败 console.warn('setMessageRead error:', imError); }); } TimComponent.prototype.getAllUnreadCount = function(){ var _this = this; let getConversationListPromise = this.tim.getConversationList(); getConversationListPromise.then(function(imResponse) { const conversationList = imResponse.data.conversationList; // 会话列表,用该列表覆盖原有的会话列表 let unreadCount = 0; conversationList.forEach(item => { unreadCount += item.unreadCount; }); _this.unreadListener && unreadCount >= 0 && _this.unreadListener(unreadCount); }).catch(function(imError) { console.warn('getConversationList error:', imError); // 获取会话列表失败的相关信息 }); } // 绑定 element事件 TimComponent.prototype.bindEleEvent = function(){ this.J_timRTop_reduce.addEventListener('click', this.reduceClick.bind(this), false); this.J_timLeft_switch.addEventListener('click', this.logoutClick.bind(this), false); this.J_inputMsg.addEventListener('keypress', this.bindInputkeypress.bind(this), false); this.icon_happy.addEventListener('click', this.emojiClick.bind(this), false); this.J_timRBottom_image.addEventListener('click',this.handleSendImageClick.bind(this), false); this.J_imagePicker.addEventListener('change', this.sendImage.bind(this), false); // this.J_timRBottom_file.addEventListener('click',this.handleSendVideoClick.bind(this), false); this.J_videoPicker.addEventListener('change', this.sendVideo.bind(this), false); this.J_timRBottom_file.addEventListener('click',this.handleSendFileClick.bind(this), false); this.J_filePicker.addEventListener('change', this.sendFile.bind(this), false); this.J_timSend.addEventListener('click', this.sendTextClick.bind(this), false); this.J_timRMiddle.addEventListener("scroll", this.msgMiddleOnScroll.bind(this), false); this.J_timReturn_newMsg.addEventListener('click', this.msgMiddleLastItem.bind(this), false); // 缩小图片 this.J_timAmplify.addEventListener('click', this.hideAmplifyClick.bind(this), false); // this.J_timAmplify_img.addEventListener('click', this.hideAmplifyClick.bind(this), false); // 绑定右键的几个事件 this.copyEle.addEventListener('click', this.copyMsgClick.bind(this), false); this.downloadEle.addEventListener('click', this.downloadFileClick.bind(this), false); this.recallEle.addEventListener('click', this.recallClick.bind(this), false); this.forwardEle.addEventListener('click', this.forwardClick.bind(this), false) // 绑定转发的事件 this.J_timForward_btn_close.addEventListener('click', this.closeForwardClick.bind(this), false); this.J_timForward_btn_forward.addEventListener('click', this.submitForwardClick.bind(this), false); } // 缩小对话框 点击事件 TimComponent.prototype.reduceClick = function(e){ var winWidth = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth; var winHeight = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight; // this.J_timContainer.style.right = '-430px'; // this.J_timContainer.style.transition= 'right 1s linear'; this.J_timContainer.style.left = (winWidth - 70) + 'px'; // this.J_timContainer.style.transition= 'left 1s linear'; this.J_timRight.style.opacity = 0; this.J_timRight.style.transition = 'opacity 1s linear'; } // SDK 登出 TimComponent.prototype.logoutClick = function(e){ var _this = this; var e = e || window.event; e.stopPropagation(); let promise = this.tim.logout(); promise.then(function(imResponse) { _this.J_timContainer.innerHTML = ''; _this.handleLogout('登出成功'); console.log('登出成功'); localStorage.removeItem('$NTALK_IMSDK'); _this.isLogin = false; // _this.destroyBindTimEvent(); }).catch(function(imError) { console.warn('logout error:', imError); }); } // 登出操作 TimComponent.prototype.handleLogout = function(tipsInfo){ this.J_timLeft_portrait.innerHTML = ''; this.J_timRMiddle.innerHTML = ''; this.J_timContainer.style.display = 'none'; this.tipsShow(tipsInfo); } // 表情 列表显示隐藏事件 TimComponent.prototype.emojiClick = function(e){ var e = e || window.event; e.stopPropagation(); var _display = this.emojis.style.display; this.emojis.style.display = _display == 'flex' ? 'none' : 'flex'; } // 提示消息展示 TimComponent.prototype.tipsShow = function(tipsInfo){ var _this = this; this.J_timTips.style.display = 'flex'; this.J_timTips_span.innerHTML = tipsInfo; setTimeout(function(){ _this.J_timTips.style.display = 'none'; _this.J_timTips_span.innerHTML = ''; }, 2000) } // 表情 列表隐藏 TimComponent.prototype.emojiHidden = function(){ this.emojis.style.display = 'none'; } // 操作发送 图片点击事件 TimComponent.prototype.handleSendImageClick = function(){ this.J_imagePicker.click(); } // 发送图片 SDK 具体操作 TimComponent.prototype.sendImage = function(e){ var e = e || window.event; e.stopPropagation(); var _this = this; let id; let types; if(currentSelectConversation.indexOf(c2cType) !== -1){ id = currentSelectConversation.replace(c2cType, ''); types = TIM.TYPES.CONV_C2C; }else if(currentSelectConversation.indexOf(groupType) !== -1){ id = currentSelectConversation.replace(groupType, ''); types = TIM.TYPES.CONV_GROUP; } // Web 端发送图片消息示例1 - 传入 DOM 节点 // 1. 创建消息实例,接口返回的实例可以上屏 const message = this.tim.createImageMessage({ to: id, conversationType: types, payload: { file: this.J_imagePicker }, onProgress: function(event) { console.log('file uploading:', event); } }) _this.sendMsgShowLoading(''); // 2. 发送消息 let promise = this.tim.sendMessage(message); promise.then(function(imResponse) { // 发送成功 console.log(imResponse); _this.J_imagePicker.value = ''; _this.updateCurrentMsgList(imResponse.data.message); }).catch(function(imError) { // 发送失败 console.warn('sendMessage error:', imError); }); } // 操作发送 视频点击事件 TimComponent.prototype.handleSendVideoClick = function(){ this.J_videoPicker.click(); } // 发送视频 SDK 具体操作 TimComponent.prototype.sendVideo = function(e){ var e = e || window.event; e.stopPropagation(); var _this = this; let id; let types; if(currentSelectConversation.indexOf(c2cType) !== -1){ id = currentSelectConversation.replace(c2cType, ''); types = TIM.TYPES.CONV_C2C; }else if(currentSelectConversation.indexOf(groupType) !== -1){ id = currentSelectConversation.replace(groupType, ''); types = TIM.TYPES.CONV_GROUP; } // web 端发送视频消息示例(v2.6.0起支持): // 1. 获取视频:传入 DOM 节点 // 2. 创建消息实例 const message = this.tim.createVideoMessage({ to: id, conversationType: types, payload: { file: this.J_videoPicker }, onProgress: function(event) { console.log('file uploading:', event); } }) this.sendMsgShowLoading(''); // 2. 发送消息 let promise = this.tim.sendMessage(message); promise.then(function(imResponse) { // 发送成功 console.log(imResponse); _this.J_videoPicker.value = ''; _this.updateCurrentMsgList(imResponse.data.message); }).catch(function(imError) { // 发送失败 console.warn('sendMessage error:', imError); }); } // 操作发送 文件点击事件 TimComponent.prototype.handleSendFileClick = function(){ this.J_filePicker.click(); } // 发送文件 SDK 具体操作 TimComponent.prototype.sendFile = function(e){ var e = e || window.event; e.stopPropagation(); let _fileSize = this.J_filePicker?.files[0].size; if(Number(_fileSize) / 1024 / 1024 >= 100){ this.tipsShow('文件大小超过100M,无法发送') this.J_filePicker.value = ''; return } var _this = this; let id; let types; if(currentSelectConversation.indexOf(c2cType) !== -1){ id = currentSelectConversation.replace(c2cType, ''); types = TIM.TYPES.CONV_C2C; }else if(currentSelectConversation.indexOf(groupType) !== -1){ id = currentSelectConversation.replace(groupType, ''); types = TIM.TYPES.CONV_GROUP; } // Web 端发送文件消息示例1 - 传入 DOM 节点 // 1. 创建文件消息实例,接口返回的实例可以上屏 const message = this.tim.createFileMessage({ to: id, conversationType: types, payload: { file: _this.J_filePicker }, onProgress: function(event) { console.log('file uploading:', event); } }) this.sendMsgShowLoading('', allowType['file']); // 2. 发送消息 let promise = this.tim.sendMessage(message); promise.then(function(imResponse) { // 发送成功 console.log(imResponse); _this.J_filePicker.value = ''; _this.updateCurrentMsgList(imResponse.data.message); }).catch(function(imError) { // 发送失败 console.warn('sendMessage error:', imError); }); } // 发送消息后,填充一条loading消息 TimComponent.prototype.sendMsgShowLoading = function(showText, _type){ // this.renderMsgMiddleItem({ // flag: true, // time: timToolsModule.getTime(new Date()) // }); if(_type == allowType['file']){ var fileLocal = this.J_filePicker.value; var name = fileLocal.substring(fileLocal.lastIndexOf("\\")+1); this.renderMsgRightItem({ item: { type: allowType['file'], fileName: name, fileSize: "", fileUrl: fileLocal, loading: true, flow:'out', }, htmlVal: "", img: curLoginPortrait, loading: true }); }else{ this.renderMsgRightItem({ item: { type: allowType['text'], text: showText }, htmlVal: showText, img: curLoginPortrait, loading: true }); } this.msgMiddleLastItem(); } // 绑定input输入框 回车发送消息 TimComponent.prototype.bindInputkeypress = function(){ var e = e || window.event; if (e.keyCode == 13){ //回车按钮事件 this.sendTextClick(); } } TimComponent.prototype.sendTextClick = function(){ var inputMsg = timToolsModule.tirm(this.J_inputMsg.value); if(inputMsg == ''){ this.tipsShow('请输入消息') return }else if(inputMsg.length > 500){ this.tipsShow('最多输入500个字,请重新输入') return } this.sendTextMsg(inputMsg); this.sendMsgShowLoading(inputMsg); this.J_inputMsg.value = ''; this.emojiHidden(); } TimComponent.prototype.msgMiddleOnScroll = function(e){ var e = e || window.event, target = e.currentTarget; if ( this.J_timRMiddle.scrollHeight - this.J_timRMiddle.clientHeight - target.scrollTop < 20 ){ this.J_timReturn_newMsg.style.display = 'none'; } // if ( this.J_timRMiddle.scrollHeight - target.scrollTop > this.J_timRMiddle.clientHeight * 2 ){ // this.J_timReturn_newMsg.style.display = 'block'; // } } // 自动到 滚动区域 第一条数据 TimComponent.prototype.msgMiddleFirstItem = function(){ // 每次消息列表都显示在 滚动条 最后的位置上 this.J_timRMiddle.scrollTop = 0; } // 自动到 滚动区域 最后一条数据 TimComponent.prototype.msgMiddleLastItem = function(){ // 每次消息列表都显示在 滚动条 最后的位置 this.J_timRMiddle.scrollTop = this.J_timRMiddle.scrollHeight; this.J_timReturn_newMsg.style.display = 'none'; } TimComponent.prototype.switchReturnElement = function(){ var _display = this.J_timReturn_newMsg.style.display; this.J_timReturn_newMsg.style.display = 'block'; } // 判断 J_timContainer 容器 是否是最大的状态,不是则把 J_timContainer 容器放大至最初状态 TimComponent.prototype.isMaxContainer = function(){ // 点击左边item 判断对话框的状态 if(this.J_timRight.style.opacity != 1){ var winWidth = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth; var winHeight = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight; // this.J_timContainer.style.right = '10px'; // this.J_timContainer.style.transition= 'right 1s linear'; //获取J_timContainer x坐标 var rec = this.J_timContainer.getBoundingClientRect(); var x = rec.x; var conWidth = this.J_timContainer.offsetWidth; var leftWid = x < (winWidth - conWidth - 10 ) ? x : (winWidth - conWidth - 10); this.J_timContainer.style.left = leftWid + 'px'; // this.J_timContainer.style.transition= 'left 1s linear'; this.J_timRight.style.opacity = 1; this.J_timRight.style.transition = 'opacity 1s linear'; } } TimComponent.prototype.handleTimPosition = function(positionState){ this.J_timContainer.style.width = '500px'; this.J_timContainer.style.height = '500px'; var winWidth = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth; var winHeight = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight; var conWidth = this.J_timContainer.offsetWidth; var conHeight = this.J_timContainer.offsetHeight; switch(positionState){ case 1: this.J_timContainer.style.left = (winWidth - conWidth) * .5 + 'px'; this.J_timContainer.style.top = (winHeight - conHeight) * .5 + 'px'; break; case 2: this.J_timContainer.style.left = '0px'; this.J_timContainer.style.top = '0px'; break; case 3: this.J_timContainer.style.left = '0px'; this.J_timContainer.style.top = (winHeight - conHeight) - 10 + 'px'; break; case 4: this.J_timContainer.style.left = (winWidth - conWidth) - 10 + 'px'; this.J_timContainer.style.top = '0px'; break; case 5: this.J_timContainer.style.left = (winWidth - conWidth) - 10 + 'px'; this.J_timContainer.style.top = (winHeight - conHeight) - 10 + 'px'; break; case 6: this.J_timContainer.style.left = (winWidth - conWidth) - 10 + 'px'; this.J_timContainer.style.top = (winHeight - conHeight) - 10 + 'px'; this.reduceClick(); break; default: this.J_timContainer.style.left = (winWidth - conWidth) - 10 + 'px'; this.J_timContainer.style.top = (winHeight - conHeight) - 10 + 'px'; break; } } // 渲染表情 列表 TimComponent.prototype.renderEmojiList = function(){ var _this = this; var emojiList = initEmoji.emojiName; var d = document.createDocumentFragment(); emojiList.forEach(item => { var _div = document.createElement('div'); _div.className = 'emoji'; _div.dataset.value = item; _div.addEventListener('click', _this.chooseEmoji.bind(_this), false); var _img = document.createElement('img'); _img.src = initEmoji.emojiUrl + initEmoji.emojiMap[item]; _div.appendChild(_img); d.appendChild(_div); }) this.emojis.appendChild(d); } // 选中 表情 TimComponent.prototype.chooseEmoji = function(e){ var e = e || window.event, target = e.currentTarget; this.emojis.style.display = 'none'; var inputMsg = timToolsModule.tirm(this.J_inputMsg.value); this.J_inputMsg.value = inputMsg != '' ? inputMsg + target.dataset.value : target.dataset.value; } // ntalk 登录 TimComponent.prototype.ntalkLogin = function(){ var uuid = timToolsModule.guid(); let _this = this; axios({ headers: { 'Content-Type': 'application/x-www-form-urlencoded', token: '', deviceType: '3', deviceId: uuid }, method: 'get', url: 'https://tntalk.morewiscloud.com/gateway/rest/v1/chat/morewisCloud/login', params: { mobile: _this.userId, password: 123456, _deviceId: uuid } }).then(function (response) { if (response.status === 200) { console.log(response.data.data); _this.userSig = response.data.data.userSig; console.log('_this.userSig', _this.userSig) _this.init(); } }).catch(function (error) { console.log(error) }) } // 初始化 J_timContainer 拖拽事件 TimComponent.prototype.initMousedown = function () { var _this = this; var oDiv = document.getElementById('J_timContainer');; // oDiv.style.width = '500px'; var aSpan = oDiv.getElementsByTagName('span'); // 遍历为每一个span添加上drage事件 var spanList = ['.br', '.bl', '.tr', '.tl'] for (var i = 0; i < spanList.length; i++) { dragFn(oDiv.querySelector(spanList[i])); } function dragFn(obj) { // 按下鼠标的操作 obj.onmousedown = function (ev) { var oEv = ev || event; // 阻止事件的冒泡 oEv.stopPropagation(); // 获取移动前盒子的宽高,边角的鼠标坐标,和距离浏览器边界的距离 var oldWidth = oDiv.offsetWidth; var oldHeight = oDiv.offsetHeight; var oldX = oEv.clientX; var oldY = oEv.clientY; var oldLeft = oDiv.offsetLeft; var oldTop = oDiv.offsetTop; // 鼠标移动事件 document.onmousemove = function (ev) { var oEv = ev || event; // t top l left r right b bottom, 依次 tl 上左角 if (obj.className == 'tl') { _this.isMaxContainer(); if(oldWidth - (oEv.clientX - oldX) > 1000 || oldWidth - (oEv.clientX - oldX) < 500 || oldHeight - (oEv.clientY - oldY) > 800 || oldHeight - (oEv.clientY - oldY) < 500 ){ return } // 代表的横向移动的距离,右为正,左为负 // 计算移动后盒子的宽 = 移动前盒子的宽度 - (移动后的横向坐标-移动前的横向坐标) oDiv.style.width = oldWidth - (oEv.clientX - oldX) + 'px'; // 高度同理 oDiv.style.height= oldHeight - (oEv.clientY - oldY) + 'px'; // 同理计算修改盒子的定位,这里很多人就不理解了,我明明动的角,为嘛不是修改span // 我给你捋一捋,首先角和边是相对于父元素定位的,父元素也是一个绝对定位,这个时候 //我动态修改父元素的定位,父元素的位置就好跟着改变,那么子元素是相对父元素定位的, // 那么在父元素最左边,不还是在最左边,这样就简单的实现了让所有定位元素跟着动 oDiv.style.left = oldLeft + (oEv.clientX - oldX) + 'px'; oDiv.style.top = oldTop + (oEv.clientY - oldY) + 'px'; } else if (obj.className == 'bl') { _this.isMaxContainer(); if(oldWidth - (oEv.clientX - oldX) > 1000 || oldWidth - (oEv.clientX - oldX) < 500 || oldHeight + (oEv.clientY - oldY) > 800 || oldHeight + (oEv.clientY - oldY) < 500 ){ return } oDiv.style.width = oldWidth - (oEv.clientX - oldX) + 'px'; oDiv.style.height= oldHeight + (oEv.clientY - oldY) + 'px'; oDiv.style.left = oldLeft + (oEv.clientX - oldX) + 'px'; oDiv.style.bottom = oldTop + (oEv.clientY + oldY) + 'px'; } else if (obj.className == 'tr') { if(oldWidth + (oEv.clientX - oldX) > 1000 || oldWidth + (oEv.clientX - oldX) < 500 || oldHeight - (oEv.clientY - oldY) > 800 || oldHeight - (oEv.clientY - oldY) < 500 ){ return } oDiv.style.width = oldWidth + (oEv.clientX - oldX) + 'px'; oDiv.style.height = oldHeight - (oEv.clientY - oldY)+'px'; oDiv.style.right = oldLeft - (oEv.clientX - oldX) + 'px'; oDiv.style.top = oldTop + (oEv.clientY - oldY) + 'px'; } else if (obj.className == 'br') { if(oldWidth + (oEv.clientX - oldX) > 1000 || oldWidth + (oEv.clientX - oldX) < 500 || oldHeight + (oEv.clientY - oldY) > 800 || oldHeight + (oEv.clientY - oldY) < 500 ){ return } oDiv.style.width = oldWidth + (oEv.clientX - oldX) + 'px'; oDiv.style.height = oldHeight + (oEv.clientY - oldY) + 'px'; oDiv.style.right = oldLeft - (oEv.clientX - oldX) + 'px'; oDiv.style.bottom = oldTop + (oEv.clientY + oldY) + 'px'; } else if (obj.className == 't') { oDiv.style.height= oldHeight-(oEv.clientY - oldY) + 'px'; oDiv.style.top = oldTop + (oEv.clientY - oldY) + 'px'; } else if (obj.className == 'b') { oDiv.style.height = oldHeight + (oEv.clientY - oldY) + 'px'; oDiv.style.bottom = oldTop - (oEv.clientY + oldY) + 'px'; } else if (obj.className == 'l') { oDiv.style.height = oldHeight + 'px'; oDiv.style.width = oldWidth - (oEv.clientX - oldX) + 'px'; oDiv.style.left = oldLeft + (oEv.clientX - oldX) + 'px'; } else if (obj.className == 'r') { oDiv.style.height = oldHeight + 'px'; oDiv.style.width = oldWidth + (oEv.clientX - oldX) + 'px'; oDiv.style.right = oldLeft - (oEv.clientX - oldX) + 'px'; } // 边界判断 boundary() }; // 松开鼠标时,移除移动的监听 document.onmouseup = function () { document.onmousemove = null; document.onmouseup = null; }; // 阻止默认事件 return false; }; } var x = 0; var y = 0; var l = 0; var t = 0; var isDown = false; var isUserSelect = false; //鼠标按下事件 oDiv.onmousedown = function(e) { var e = e || window.event; target = e.target || e.srcElement; if(target.className != 'J_timLeft' && target.className != 'J_timLeft_portrait' && target.className != 'J_timRTop' && target.className != 'J_timRBottom'){ isUserSelect = false; return }else{ isUserSelect = true; } // _this.J_timMsg_moreHandle.style.display = 'none'; //获取x坐标和y坐标 x = e.clientX; y = e.clientY; //获取左部和顶部的偏移量 l = oDiv.offsetLeft; t = oDiv.offsetTop; //开关打开 isDown = true; //设置样式 oDiv.style.cursor = 'move'; } //鼠标移动 window.onmousemove = function(e) { var e = e || window.event; target = e.target || e.srcElement; if(isUserSelect){ e.preventDefault(); } if (isDown == false) { return; } //获取x和y var nx = e.clientX; var ny = e.clientY; //计算移动后的左偏移量和顶部的偏移量 var nl = nx - (x - l); var nt = ny - (y - t); oDiv.style.left = nl + 'px'; oDiv.style.top = nt + 'px'; } //鼠标抬起事件 oDiv.onmouseup = function() { //开关关闭 isDown = false; oDiv.style.cursor = 'default'; } // 鼠标按下事件 oDiv.onclick = function(e) { _this.J_timMsg_moreHandle.style.display = 'none'; } // 边界判断事件 function boundary(){ let oDivWidth = oDiv.offsetWidth; let oDivHeight = oDiv.offsetHeight; let oDivLeft = oDiv.offsetLeft; let oDivTop = oDiv.offsetTop; // let bodyWidth = document.body.clientWidth // let bodyHeight = document.body.clientHeight let bodyWidth = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth; let bodyHeight = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight; // 左边界 if(oDivLeft<=0){ oDiv.style.left = 0+'px' } // 右边界 多减5个像素减去的是防止滚动条会造成抖动 if((oDivLeft+oDivWidth)>=(bodyWidth-5)){ oDiv.style.left = bodyWidth - oDivWidth-5+ 'px' } //上边界 if(oDivTop<=0){ oDiv.style.top = 0+'px' } // 下边界 多减5个像素减去的是防止滚动条会造成抖动 if(oDivTop+oDivHeight>=bodyHeight-5){ oDiv.style.top = bodyHeight - oDivHeight-5 + 'px' } } }; // 放大图片 TimComponent.prototype.amplifyImgEvent = function(e){ var e = e || window.event, target = e.currentTarget; e.preventDefault(); var imageUrl = target.dataset.imageUrl; this.J_timAmplify_img.src = imageUrl; this.J_timAmplify.style.display = 'flex'; } // 隐藏放大图片区域 TimComponent.prototype.hideAmplifyClick = function(e){ var e = e || window.event; e.preventDefault(); e.stopPropagation(); this.J_timAmplify.style.display = 'none'; } // 添加右键 点击事件 TimComponent.prototype.initContextmenuEvent = function(flow, e){ var e = e || window.event, target = e.currentTarget; e.preventDefault(); e.stopPropagation(); this.copyEle.style.display = 'block'; this.recallEle.style.display = 'block'; this.downloadEle.style.display = 'block'; this.copyEle.dataset.id = target.dataset.id; this.forwardEle.dataset.id = target.dataset.id; this.recallEle.dataset.id = target.dataset.id; this.downloadEle.dataset.id = target.dataset.id; // this.downloadEle.dataset.type = target.dataset.type; if(target.dataset.type == allowType["file"] || target.dataset.type == allowType["image"] || target.dataset.type == allowType["video"]){ this.copyEle.style.display = 'none'; }else if(target.dataset.type == allowType["text"]){ this.downloadEle.style.display = 'none'; this.copyEle.dataset.text = target.dataset.text; } if(flow != 'out'){ this.recallEle.style.display = 'none'; } this.J_timMsg_moreHandle.style.left = e.clientX + 'px'; this.J_timMsg_moreHandle.style.top = e.clientY + 'px'; this.J_timMsg_moreHandle.style.display = 'block'; } // 右键复制点击事件 TimComponent.prototype.copyMsgClick = function(e){ var e = e || window.event, target = e.currentTarget; // e.preventDefault(); e.stopPropagation(); var ID = target.dataset.id; var message = this.currentMsgData.find( item => { return item.ID == ID; }) var copyMsg = message.payload.text; if( copyMsg && copyMsg != ''){ var input = document.createElement('input'); input.setAttribute('readonly', 'readonly'); input.setAttribute('value', copyMsg); document.body.appendChild(input); input.select(); input.setSelectionRange(0, 9999); document.execCommand('Copy'); this.tipsShow('消息复制成功'); document.body.removeChild(input); this.J_timMsg_moreHandle.style.display = 'none'; } } // 右键下载点击事件 TimComponent.prototype.downloadFileClick = function(e){ var e = e || window.event, target = e.currentTarget; // e.preventDefault(); e.stopPropagation(); var ID = target.dataset.id; var message = this.currentMsgData.find( item => { return item.ID == ID; }) var fileUrl; var fileName; if(message.type == allowType['image']){ fileUrl = message.payload.imageInfoArray[0].imageUrl; fileName = 'image_' + new Date().getTime(); }else if(message.type == allowType['file']){ fileUrl = message.payload.fileUrl; fileName = message.payload.fileName; }else if(message.type == allowType['video']){ fileUrl = message.payload.videoUrl; fileName = 'video_' + new Date().getTime(); } if( fileUrl && fileUrl != ''){ this.downloadFile(fileUrl,fileName); this.J_timMsg_moreHandle.style.display = 'none'; } } // 右键撤回点击事件 TimComponent.prototype.recallClick = function(e){ var e = e || window.event, target = e.currentTarget; // e.preventDefault(); e.stopPropagation(); var ID = target.dataset.id; var message = this.currentMsgData.find( item => { return item.ID == ID; }) this.revokeMessage(message); this.J_timMsg_moreHandle.style.display = 'none'; } // tim撤回 TimComponent.prototype.revokeMessage = function(message){ var _this = this; // 主动撤回消息 let promise = this.tim.revokeMessage(message); promise.then(function(imResponse) { // 消息撤回成功 // console.log(imResponse.data.message) _this.updateRevokedMsgList(imResponse.data.message); _this.tipsShow('撤回成功'); }).catch(function(imError) { // 消息撤回失败 // console.warn('revokeMessage error:', imError); _this.tipsShow('撤回失败:消息发送已超过2分钟撤回消息失败,时间已超过2分钟!'); }); } TimComponent.prototype.forwardClick = function(){ var e = e || window.event, target = e.currentTarget; // e.preventDefault(); e.stopPropagation(); this.J_timForward_btn_forward.dataset.id = target.dataset.id; this.createForwardList(); } // 创建转发列表 TimComponent.prototype.createForwardList = function(){ var _this = this; // 先清空数据 this.J_timForward_list.innerHTML = ''; var d = document.createDocumentFragment(); let _newC2C = this.privateChatId; let newC2CIndex = -1; if(_newC2C && _newC2C !== ''){ newC2CIndex = _this.conversationListData.findIndex(item => { return item.conversationID == c2cType + _newC2C; }) if(newC2CIndex === -1){ _this.createForwardItem({ conversationID: c2cType + _newC2C, img: _this.privateChatOpt.avatar, htmlVal: _this.privateChatOpt.nick }, d); } } _this.conversationListData.forEach(item => { _this.createForwardItem({ conversationID: item.conversationID, img: timToolsModule.getAvatarImg(item), htmlVal: timToolsModule.getProfileName(item) }, d); }) this.J_timForward_list.appendChild(d); this.J_timForward_layer.style.display = 'flex'; this.J_timMsg_moreHandle.style.display = 'none'; } // 创建转发 item TimComponent.prototype.createForwardItem = function(opt, d){ var _div = document.createElement('div'); _div.className = 'J_timForward_item'; // _div.addEventListener('click', this.checkboxCilck.bind(this), false); var _input = document.createElement('input'); _input.type = 'checkbox'; _input.name = 'timChechbox'; _input.value = opt.conversationID; _div.appendChild(_input); var checkbox_text = document.createElement('div'); checkbox_text.className = 'content_div'; var _img = document.createElement('img'); _img.src = opt.img; _img.alt = ''; timToolsModule.onerrorFN(_img); checkbox_text.appendChild(_img); var _span = document.createElement('span'); _span.innerHTML = opt.htmlVal checkbox_text.appendChild(_span); checkbox_text.addEventListener('click', this.checkboxCilck.bind(this), false); _div.appendChild(checkbox_text); d.appendChild(_div); } TimComponent.prototype.checkboxCilck = function(e){ var e = e || window.event, target = e.currentTarget; e.stopPropagation(); target.parentNode.children.timChechbox.checked = !target.parentNode.children.timChechbox.checked; } // 渲染转发 Item // tim 取消转发 TimComponent.prototype.closeForwardClick = function(){ this.J_timForward_layer.style.display = 'none'; } // tim 转发 TimComponent.prototype.submitForwardClick = function(e){ var e = e || window.event, target = e.currentTarget; // e.preventDefault(); e.stopPropagation(); var ID = target.dataset.id; var _this = this; var obj = document.getElementsByName('timChechbox'); var check_val = []; obj.forEach(item => { if(item.checked){ check_val.push(item.value); } }) if(check_val.length <= 0){ this.tipsShow('请选择转发对象'); }else{ this.showLoading(); check_val.forEach( (item, index) => { _this.forwardMsg(item, ID, index == check_val.length - 1); }) this.J_timForward_layer.style.display = 'none'; } } // 开始转发 TimComponent.prototype.forwardMsg = function(item, _id, _hideFlag){ var _this = this; let id; let types; if(item.indexOf(c2cType) !== -1){ id = item.replace(c2cType, ''); types = TIM.TYPES.CONV_C2C; }else if(item.indexOf(groupType) !== -1){ id = item.replace(groupType, ''); types = TIM.TYPES.CONV_GROUP; } var ID = _id; var message = this.currentMsgData.find( item => { return item.ID == ID; }) let forwardMessage = this.tim.createForwardMessage({ to: id, conversationType: types, // 消息优先级,用于群聊,如果某个群的消息超过了频率限制,后台会优先下发高优先级的消息,详细请参考:https://cloud.tencent.com/document/product/269/3663#.E6.B6.88.E6.81.AF.E4.BC.98.E5.85.88.E7.BA.A7.E4.B8.8E.E9.A2.91.E7.8E.87.E6.8E.A7.E5.88.B6) // 支持的枚举值:TIM.TYPES.MSG_PRIORITY_HIGH, TIM.TYPES.MSG_PRIORITY_NORMAL(默认), TIM.TYPES.MSG_PRIORITY_LOW, TIM.TYPES.MSG_PRIORITY_LOWEST // priority: TIM.TYPES.MSG_PRIORITY_NORMAL, payload: message, // 消息实例,已收到的或自己已发出的消息 // 消息自定义数据(云端保存,会发送到对端,程序卸载重装后还能拉取到,v2.10.2起支持) // cloudCustomData: 'your cloud custom data' }); if(item == currentSelectConversation){ this.sendMsgShowLoading(''); } // 2. 发送消息 let promise = this.tim.sendMessage(forwardMessage); promise.then(function(imResponse) { // 发送成功 console.log(imResponse); if(imResponse.data.message.conversationID == currentSelectConversation){ _this.updateCurrentMsgList(imResponse.data.message); }else{ _this.tipsShow('转发成功!'); } _hideFlag && _this.hideLoading(); }).catch(function(imError) { // 发送失败 console.warn('sendMessage error:', imError); _this.hideLoading(); }); } // 显示loading TimComponent.prototype.showLoading = function(){ this.J_timLoading.style.display = 'flex'; } // 隐藏loading TimComponent.prototype.hideLoading = function(){ this.J_timLoading.style.display = 'none'; } window.TimComponent = TimComponent; })(document, timToolsModule, initEmoji); // 对外使用的模板,主要使用 getTimExample 方法获得唯一 TimComponent 实例 var initTimModule = (function(){ var timComponent; function singleTim(opt){ if (timComponent == undefined){ timComponent = new TimComponent({ SDKAppID: opt.SDKAppID, userId: opt.userId, userSig: opt.userSig, privateChatId: opt.privateChatId, privateChatName: opt.privateChatName, baseHead_url: opt.baseHead_url, unreadListener: opt.unreadListener, unreadChangeListener: opt.unreadChangeListener, }) } if(!timComponent.isLogin){ timComponent.handleLogin(opt); }else{ timComponent.updateOpt(opt); } } function getTimExample(opt){ singleTim(opt); } function logoutTim(){ if (timComponent != undefined){ if(timComponent.isLogin){ timComponent.logoutClick(); } } } return { getTimExample: getTimExample, logoutTim: logoutTim, } })();