@@ -2140,7 +2309,7 @@ axios.get("/api/comm/initData?turn="+useTurn, {}).then((initData) => {
`
}
@@ -2170,9 +2339,9 @@ axios.get("/api/comm/initData?turn="+useTurn, {}).then((initData) => {
let height = 0;
if (this.isMobile) {
- height = document.documentElement.clientHeight - 335;
+ height = document.documentElement.clientHeight - 280;
} else {
- height = 300
+ height = 325
}
if (chatDomHeight > height) {
@@ -2234,1176 +2403,871 @@ axios.get("/api/comm/initData?turn="+useTurn, {}).then((initData) => {
this.addUserLogs(this.lang.text_send_done);
layedit.setContent(this.txtEditId, "", false)
+
+ //清空系统记录缓存
+ localStorage.removeItem('tl-rtc-file-question-list');
},
- // 中继信息提示
- useTurnMsg: function () {
- layer.msg(this.lang.relay_on)
- this.addUserLogs(this.lang.relay_on)
- },
- // 当前网络状态
- networkMsg: function () {
- layer.msg(this.lang.current_network + (this.network !== 'wifi' ? this.lang.mobile_data : this.network))
- this.addUserLogs(this.lang.current_network + (this.network !== 'wifi' ? this.lang.mobile_data : this.network))
- },
- // 添加弹窗
- addPopup: function (msg) {
- this.popUpList.push({
- title : msg.title,
- message : msg.msg
- })
- },
- // 记录系统日志
- addSysLogs: function (msg) {
- this.addLogs(msg, "【"+this.lang.sys_log+"】: ")
- },
- // 记录用户操作日志
- addUserLogs: function (msg) {
- this.addLogs(msg, "【"+this.lang.op_log+"】: ")
- },
- // 记录日志
- addLogs: function (msg, type) {
- if (this.logs.length > 1000) {
- this.logs.shift();
+ //创建文件发送房间
+ createFileRoom: function () {
+ this.openRoomInput = !this.openRoomInput;
+
+ if(this.openRoomInput){
+ return
}
- this.logs.unshift({
- type: type,
- msg: msg,
- time: new Date().toLocaleString()
- })
- },
- // 清空日志
- cleanLogs: function () {
- this.logs = []
- this.addSysLogs(this.lang.clear_log)
- },
- // 发送建议反馈
- sendBugs: function () {
- let that = this;
- $("#sendBugs").removeClass("layui-anim-rotate")
- setTimeout(() => {
- $("#sendBugs").addClass("layui-anim-rotate")
- }, 50)
- setTimeout(() => {
- layer.prompt({
- formType: 2,
- title: that.lang.please_describe_your_feedback,
- }, function (value, index, elem) {
- that.socket.emit('message', {
- emitType: "sendBugs",
- msg: value,
- room: that.roomId,
- to: that.socketId
- });
- layer.msg(that.lang.send_bug_info_ok)
- layer.close(index);
- that.addUserLogs(that.lang.send_bug_info_ok + ", " + value);
- });
- }, 500);
- },
- // 随机刷新房间号
- refleshRoom: function () {
- if (!this.isJoined) {
- this.roomId = parseInt(Math.random() * 100000);
+
+ this.roomId = this.roomId.toString().replace(/\s*/g, "")
+ if (this.roomId === null || this.roomId === undefined || this.roomId === '') {
+ layer.msg(this.lang.please_enter_room_num)
+ this.addUserLogs(this.lang.please_enter_room_num);
+ return;
+ }
+ if (!this.switchData.allowChinese && window.tlrtcfile.containChinese(this.roomId)) {
+ layer.msg(this.lang.room_num_no_zh)
+ this.addUserLogs(this.lang.room_num_no_zh);
+ return;
+ }
+ if (!this.switchData.allowNumber && window.tlrtcfile.containNumber(this.roomId)) {
+ layer.msg(this.lang.room_num_no_number)
+ this.addUserLogs(this.lang.room_num_no_number);
+ return;
+ }
+ if (!this.switchData.allowSymbol && window.tlrtcfile.containSymbol(this.roomId)) {
+ layer.msg(this.lang.room_num_no_special_symbols)
+ this.addUserLogs(this.lang.room_num_no_special_symbols);
+ return;
+ }
+ if (this.chooseFileList.length > 0) {
+ layer.msg(this.lang.please_join_then_choose_file)
+ this.addUserLogs(this.lang.please_join_then_choose_file);
+ return;
+ }
+ if (this.roomId) {
+ if (this.roomId.toString().length > 15) {
+ layer.msg(this.lang.room_num_too_long)
+ this.addUserLogs(this.lang.room_num_too_long);
+ return;
+ }
+ this.socket.emit('createAndJoin', {
+ room: this.roomId,
+ type : 'file',
+ nickName : this.nickName,
+ langMode : this.langMode,
+ ua: this.isMobile ? 'mobile' : 'pc',
+ network : this.network,
+ localNetRoom : this.useLocalNetworkRoomShare
+ });
+ this.isJoined = true;
this.addPopup({
- title : this.lang.refresh_room,
- msg : this.lang.you_refresh_room + this.roomId
+ title : this.lang.file_room,
+ msg : this.lang.you_enter_file_room + this.roomId
});
- this.addUserLogs(this.lang.you_refresh_room + this.roomId);
+ this.addUserLogs( this.lang.you_enter_file_room + this.roomId);
}
},
- // 复制分享房间url
- shareUrl: function () {
- let that = this;
- layer.closeAll(function () {
- layer.open({
- type: 1,
- closeBtn: 0,
- fixed: true,
- maxmin: false,
- shadeClose: true,
- area: ['350px', '380px'],
- title: that.lang.share_join_room,
- success: function (layero, index) {
- let shareArgs = {
- r : that.roomId,
- t : that.roomType
- };
- if(that.roomType === 'live'){
- shareArgs.lsm = that.liveShareMode;
- shareArgs.lsr = 'viewer';
- }
- let content = window.tlrtcfile.addUrlHashParams(shareArgs);
- document.querySelector(".layui-layer-title").style.borderTopRightRadius = "8px";
- document.querySelector(".layui-layer-title").style.borderTopLeftRadius = "8px";
- document.querySelector(".layui-layer").style.borderRadius = "8px";
- if(window.tlrtcfile.getQrCode){
- tlrtcfile.getQrCode("tl-rtc-file-room-share-image", content)
- }
-
- document.querySelector("#shareUrl").setAttribute("data-clipboard-text", content);
- let clipboard = new ClipboardJS('#shareUrl');
- clipboard.on('success', function (e) {
- e.clearSelection();
- setTimeout(() => {
- layer.msg(that.lang.copy_room_link)
- }, 500);
- });
- that.addUserLogs(that.lang.copy_room_link);
- },
- content: `
-
- `
- })
- })
- this.addUserLogs(this.lang.open_share_join_room)
+ //创建流媒体房间
+ createMediaRoom: function (type) {
+ this.roomId = this.roomId.toString().replace(/\s*/g, "")
+ if (this.roomId === null || this.roomId === undefined || this.roomId === '') {
+ layer.msg(this.lang.please_enter_room_num)
+ this.addUserLogs(this.lang.please_enter_room_num);
+ return;
+ }
+ if (this.roomId) {
+ if (this.roomId.toString().length > 15) {
+ layer.msg(this.lang.room_num_too_long)
+ this.addUserLogs(this.lang.room_num_too_long);
+ return;
+ }
+ this.socket.emit('createAndJoin', {
+ room: this.roomId,
+ type: type,
+ nickName : this.nickName,
+ langMode : this.langMode,
+ ua: this.isMobile ? 'mobile' : 'pc',
+ network : this.network,
+ liveShareRole : this.liveShareRole,
+ localNetRoom : this.useLocalNetworkRoomShare
+ });
+ this.isJoined = true;
+ this.roomType = type;
+ this.addPopup({
+ title : this.lang.stream_room,
+ msg : this.lang.you_enter_stream_room + this.roomId
+ });
+ this.addUserLogs(this.lang.you_enter_stream_room + this.roomId);
+ }
},
- // 获取分享的取件码文件
- handlerGetCodeFile: function () {
- let that = this;
- let hash = window.location.hash || "";
- if (hash && hash.includes("#")) {
- let codeIdArgs = hash.split("c=");
- if (codeIdArgs && codeIdArgs.length > 1) {
- this.codeId = (codeIdArgs[1] + "").replace(/\s*/g, "").substring(0, 40);
- layer.confirm(this.lang.is_pickup_code, (index) => {
- window.location.hash = "";
- layer.close(index)
- that.getCodeFile();
- }, (index) => {
- that.codeId = "";
- window.location.hash = "";
- layer.close(index)
- })
- this.addPopup({
- title : this.lang.share_pickup_code_file,
- msg : this.lang.get_pickup_file + this.codeId
- });
- this.addUserLogs(this.lang.get_pickup_file + this.codeId);
+ //创建密码房间
+ createPasswordRoom: function (password) {
+ this.roomId = this.roomId.toString().replace(/\s*/g, "")
+ if (this.roomId === null || this.roomId === undefined || this.roomId === '') {
+ layer.msg(this.lang.please_enter_room_num)
+ this.addUserLogs(this.lang.please_enter_room_num);
+ return;
+ }
+ if (this.roomId) {
+ if (this.roomId.toString().length > 15) {
+ layer.msg(this.lang.room_num_too_long)
+ this.addUserLogs(this.lang.room_num_too_long);
+ return;
}
+ if (password.toString().length > 15) {
+ layer.msg(this.lang.password_too_long)
+ this.addUserLogs(this.lang.password_too_long);
+ return;
+ }
+ this.socket.emit('createAndJoin', {
+ room: this.roomId,
+ type : 'password',
+ password: password,
+ nickName : this.nickName,
+ langMode : this.langMode,
+ ua: this.isMobile ? 'mobile' : 'pc',
+ network : this.network,
+ localNetRoom : this.useLocalNetworkRoomShare
+ });
+ this.isJoined = true;
+ this.addPopup({
+ title : this.lang.password_room,
+ msg : this.lang.you_enter_password_room + this.roomId
+ });
+ this.addUserLogs(this.lang.you_enter_password_room + this.roomId);
}
},
- // 分享进入房间
- handlerJoinShareRoom: function () {
- let that = this;
- let hash = window.location.hash || "";
- if (!hash || !hash.includes("#") || !hash.includes("r=")) {
- return
+ //退出房间
+ exitRoom: function () {
+ if (this.roomId) {
+ this.socket.emit('exit', {
+ from: this.socketId,
+ room: this.roomId,
+ recoderId: this.recoderId
+ });
+ }
+ for (let i in this.rtcConns) {
+ let rtcConnect = this.rtcConns[i];
+ rtcConnect.close();
+ rtcConnect = null;
}
- if (!window.layer) {
- return
+ window.location.reload();
+ },
+ //创立链接
+ createRtcConnect: function (id) {
+ if (id === undefined) {
+ return;
}
- //房间号
- let roomIdArgs = tlrtcfile.getRequestHashArgs("r");
- if (!roomIdArgs) {
- return
+ let that = this;
+ let rtcConnect = new RTCPeerConnection(this.config);
+
+ //ice
+ rtcConnect.onicecandidate = (e) => {
+ that.iceCandidate(rtcConnect, id, e)
+ };
+
+ rtcConnect.oniceconnectionstatechange = (e) => {
+ that.addSysLogs("iceConnectionState: " + rtcConnect.iceConnectionState);
+
+ //如果是断开连接,并且没有使用turn服务器,提示开启turn服务器
+ if(rtcConnect.iceConnectionState === 'disconnected' && !this.useTurn){
+ layer.msg(that.lang.please_use_turn_server);
+ that.addSysLogs(that.lang.please_use_turn_server);
+ }
+ that.setRemoteInfo(id, {
+ iceConnectionState : rtcConnect.iceConnectionState
+ })
}
- this.roomId = (roomIdArgs + "").replace(/\s*/g, "").substring(0, 15);
- //房间类型
- let typeArgs = tlrtcfile.getRequestHashArgs("t");
+ //媒体流通道
+ rtcConnect.ontrack = (e) => {
+ that.mediaTrackHandler(e, id)
+ };
- layer.confirm(this.lang.join_room + this.roomId, (index) => {
- window.location.hash = "";
- layer.close(index)
- that.openRoomInput = true;
- that.isShareJoin = true;
- if(typeArgs && ['screen','live','video','audio'].includes(typeArgs)){
- if(typeArgs === 'screen'){
- that.startScreenShare();
- }else if(typeArgs === 'live'){
- //直播房间模式
- let lsm = tlrtcfile.getRequestHashArgs("lsm");
- if(['video', 'live', ''].includes(lsm)){
- that.liveShareMode = lsm;
- }
- //直播房间身份
- let lsr = tlrtcfile.getRequestHashArgs("lsr");
- if(['owner', 'viewer'].includes(lsr)){
- that.liveShareRole = lsr;
- }
- that.startLiveShare();
- }else if(typeArgs === 'video'){
- that.startVideoShare();
- }else if(typeArgs === 'audio'){
- that.startAudioShare();
- }
- }else{
- that.createFileRoom();
+ //文件发送数据通道
+ let sendFileDataChannel = rtcConnect.createDataChannel('sendFileDataChannel');
+ sendFileDataChannel.binaryType = 'arraybuffer';
+ sendFileDataChannel.addEventListener('open', (event) => {
+ if (sendFileDataChannel.readyState === 'open') {
+ that.addSysLogs(that.lang.establish_connection)
}
- }, (index) => {
- that.roomId = "";
- window.location.hash = "";
- layer.close(index)
- })
- this.addPopup({
- title : this.lang.share_join_room,
- msg : this.lang.you_join_room + this.roomId
});
- this.addUserLogs(this.lang.you_join_room + this.roomId);
- },
- // 赞助面板
- coffee: function () {
- let options = {
- type: 1,
- fixed: false,
- maxmin: false,
- shadeClose: true,
- area: ['300px', '350px'],
- title: this.lang.donate,
- success: function (layero, index) {
- document.querySelector(".layui-layer-title").style.borderTopRightRadius = "8px";
- document.querySelector(".layui-layer-title").style.borderTopLeftRadius = "8px";
- document.querySelector(".layui-layer").style.borderRadius = "8px";
- },
- content: `
![img](/image/coffee.jpeg)
`
+ sendFileDataChannel.addEventListener('close', (event) => {
+ if (sendFileDataChannel.readyState === 'close') {
+ that.addSysLogs(that.lang.connection_closed)
+ }
+ });
+ sendFileDataChannel.addEventListener('error', (error) => {
+ console.error(error.error)
+ that.addSysLogs(that.lang.connection_disconnected + ",file:e=" + error)
+ that.removeStream(null, id, null)
+ });
+
+ //自定义数据发送通道
+ let sendDataChannel = rtcConnect.createDataChannel('sendDataChannel');
+ sendDataChannel.binaryType = 'arraybuffer';
+ sendDataChannel.addEventListener('open', (event) => {
+ if (sendDataChannel.readyState === 'open') {
+ that.addSysLogs(that.lang.establish_connection)
+ }
+ });
+ sendDataChannel.addEventListener('close', (event) => {
+ if (sendDataChannel.readyState === 'close') {
+ that.addSysLogs(that.lang.connection_closed)
+ }
+ });
+ sendDataChannel.addEventListener('error', (error) => {
+ console.error(error.error)
+ that.addSysLogs(that.lang.connection_disconnected + ",cus:e=" + error)
+ that.removeStream(null, id, null)
+ });
+
+ rtcConnect.addEventListener('datachannel', (event) => {
+ that.initReceiveDataChannel(event, id);
+ });
+
+ rtcConnect.onremovestream = (e) => {
+ that.removeStream(rtcConnect, id, e)
+ };
+
+ //保存peer连接
+ this.rtcConns[id] = rtcConnect;
+ if (!this.remoteMap[id]) {
+ Vue.set(this.remoteMap, id, {
+ id: id,
+ receiveChatRoomSingleList : [],
+ p2pMode : '识别中...',
+ sendFileDataChannel: sendFileDataChannel,
+ sendDataChannel : sendDataChannel
+ })
}
- layer.closeAll(function () {
- layer.open(options)
- })
- this.addUserLogs(this.lang.open_donate)
+
+ return rtcConnect;
},
- //点击下载文件面板
- clickReceiveFile: function () {
- if(this.receiveFileRecoderList.length === 0){
- layer.msg(this.lang.no_received_file)
- return
- }
- this.showReceiveFile = !this.showReceiveFile;
- if (this.showReceiveFile) {
- this.addUserLogs(this.lang.expand_receive_file);
- this.receiveFileMaskHeightNum = 20;
- } else {
- this.receiveFileMaskHeightNum = 150;
- this.addUserLogs(this.lang.collapse_receive_file);
+ //获取本地与远程连接
+ getOrCreateRtcConnect: function (id) {
+ // 获取rtc缓存连接
+ let rtcConnect = this.rtcConns[id];
+ // 不存在,创建一个
+ if (typeof (rtcConnect) == 'undefined') {
+ rtcConnect = this.createRtcConnect(id);
}
+ return rtcConnect;
},
- //点击已选文件面板
- clickChooseFile: function () {
- if(!this.hasManInRoom && !this.showChooseFile){
- layer.msg(this.lang.room_least_two_can_send_content)
- return
- }
- this.showChooseFile = !this.showChooseFile;
- if (this.showChooseFile) {
- this.chooseFileMaskHeightNum = 20;
- this.addUserLogs(this.lang.expand_selected_file);
- } else {
- this.chooseFileMaskHeightNum = 150;
- this.addUserLogs(this.lang.collapse_selected_file);
+ //远程媒体流处理
+ mediaTrackHandler: function(event, id){
+ let that = this;
+
+ let video = null;
+
+ const remoteRtc = this.getRemoteInfo(id);
+ const remoteName = remoteRtc.nickName || "";
+
+ if(event.track.kind === 'audio'){
+ // audio-track事件,除了语音连麦房间之外,其他都可以跳过,因为音视频/直播/屏幕共享他们的音频流都并入了video-track了
+ if(that.roomType !== 'audio'){
+ return
+ }
+
+ //连麦房间,只有音频数据
+ $(`#mediaAudioRoomList`).append(`
+
${remoteName}
+
+
+
+
+
+
+
+ `);
+ video = document.querySelector(`#otherMediaAudioShare${id}`);
}
- },
- //点击待发送文件面板
- clickSendFile: function () {
- if(!this.hasManInRoom && !this.showSendFile){
- layer.msg(this.lang.room_least_two_can_send_content)
- return
+
+ if(this.roomType === 'video'){
+ $(`#mediaVideoRoomList`).append(`
+
${remoteName}
+
+
+
+
+
+
+ `);
+ video = document.querySelector(`#otherMediaVideoShare${id}`);
+ } else if(this.roomType === 'screen'){
+ $(`#mediaScreenRoomList`).append(`
+
${remoteName}
+
+
+
+
+ `);
+ video = document.querySelector(`#otherMediaScreenShare${id}`);
+ } else if(this.roomType === 'live'){
+
+ if(this.liveShareRole === 'viewer'){
+ $(`#mediaLiveRoomList`).append(`
+
${remoteName}
+
+
+
+
+
+
+ `);
+ }
+
+ video = document.querySelector(`#otherMediaLiveShare${id}`);
}
- this.showSendFile = !this.showSendFile;
- if (this.showSendFile) {
- this.sendFileMaskHeightNum = 20;
- this.addUserLogs(this.lang.expand_wait_send_file);
- } else {
- this.sendFileMaskHeightNum = 150;
- this.addUserLogs(this.lang.collapse_wait_send_file);
+
+ if(video){
+ video.addEventListener('loadedmetadata', function() {
+ video.play();
+ that.addSysLogs("loadedmetadata")
+ // ios 微信浏览器兼容问题
+ document.addEventListener('WeixinJSBridgeReady', function () {
+ that.addSysLogs("loadedmetadata WeixinJSBridgeReady")
+ video.play();
+ }, false);
+ });
+ document.addEventListener('WeixinJSBridgeReady', function () {
+ that.addSysLogs("WeixinJSBridgeReady")
+ video.play();
+ }, false);
+ video.srcObject = event.streams[0]
+ video.play();
}
},
- //点击发送文件历史记录面板
- clickSendFileHistory: function () {
- if(this.sendFileRecoderHistoryList.length === 0){
- layer.msg(this.lang.no_send_file)
- return
- }
- this.showSendFileHistory = !this.showSendFileHistory;
- if (this.showSendFileHistory) {
- this.sendFileHistoryMaskHeightNum = 20;
- this.addUserLogs(this.lang.expand_send_file_record);
- } else {
- this.sendFileHistoryMaskHeightNum = 150;
- this.addUserLogs(this.lang.collapse_send_file_record);
- }
- },
- //点击查看日志面板
- clickLogs: function (e) {
- this.showLogs = !this.showLogs;
- this.touchResize();
- if (this.showLogs) {
- this.addUserLogs(this.lang.expand_log);
- this.logMaskHeightNum = 0;
- } else {
- this.addUserLogs(this.lang.collapse_log);
- this.logMaskHeightNum = -150;
+ //编码组装发送文件数据,设置好每次分片的文件头信息
+ encodeSendFileBuffer: function ({recoder, buffer, fragment, event}) {
+ let fileInfoString = JSON.stringify({
+ i: recoder.index, //当前文件块所属的索引
+ f: fragment, //当前buffer所处的分片块
+ });
+ //填充
+ const paddedFileInfoString = fileInfoString.padEnd(this.fileInfoBufferHeaderLen, '\0');
+ const combindBuffer = new ArrayBuffer(this.fileInfoBufferHeaderLen + buffer.byteLength);
+
+ const combinedUint8Array = new Uint8Array(combindBuffer);
+ for (let i = 0; i < paddedFileInfoString.length; i++) {
+ combinedUint8Array[i] = paddedFileInfoString.charCodeAt(i);
}
+ combinedUint8Array.set(new Uint8Array(buffer), this.fileInfoBufferHeaderLen);
+
+ return combindBuffer;
},
- //点击打开音视频面板
- clickMediaVideo: function () {
- this.showMedia = !this.showMedia;
- this.touchResize();
- if (this.showMedia) {
- this.addUserLogs(this.lang.expand_video);
- this.mediaVideoMaskHeightNum = 0;
- if(this.clientWidth < 500){
- document.getElementById("iamtsm").style.marginLeft = '0';
- }else{
- document.getElementById("iamtsm").style.marginLeft = "50%";
- }
- } else {
- this.addUserLogs(this.lang.collapse_video);
- this.mediaVideoMaskHeightNum = -150;
- document.getElementById("iamtsm").style.marginLeft = "0";
+ //解码组装接收文件数据
+ decodeReceiveFileBuffer: function (buffer) {
+ const receivedUint8Array = new Uint8Array(buffer);
+ const fileInfoString = String.fromCharCode(...receivedUint8Array.slice(0, this.fileInfoBufferHeaderLen));
+ const trimmedFileInfoString = fileInfoString.replace(/\0/g, '');
+ const fileInfo = JSON.parse(trimmedFileInfoString);
+ return {
+ buffer: receivedUint8Array.slice(this.fileInfoBufferHeaderLen),
+ index: fileInfo.i,
+ fragment: fileInfo.f
}
},
- //点击打开屏幕共享面板
- clickMediaScreen: function () {
- this.showMedia = !this.showMedia;
- this.touchResize();
- if (this.showMedia) {
- this.addUserLogs(this.lang.expand_screen_sharing);
- this.mediaScreenMaskHeightNum = 0;
- if(this.clientWidth < 500){
- document.getElementById("iamtsm").style.marginLeft = "0";
- }else{
- document.getElementById("iamtsm").style.marginLeft = "50%";
- }
- } else {
- this.addUserLogs(this.lang.collapse_screen_sharing);
- this.mediaScreenMaskHeightNum = -150;
- document.getElementById("iamtsm").style.marginLeft = "0";
+ //每个记录发送完毕后都检查下是否全部发送完
+ allFileSendedCheckHandler : function(){
+ let allDone = this.sendFileRecoderList.filter(item => {
+ return item.done;
+ }).length === this.sendFileRecoderList.length;
+
+ // 全部发完
+ if(allDone){
+ this.chooseFileList = []
+ this.sendFileRecoderList = []
+ this.chooseFileRecoderList = []
+ this.chooseFileRecoderAutoNext = false;
+ this.addPopup({
+ title : this.lang.send_file,
+ msg : this.lang.file_send_done
+ });
+ this.addSysLogs(this.lang.file_send_done)
+ this.allSended = true;
+ this.isSending = false;
+
+ return true
}
- },
- //点击打开直播面板
- clickMediaLive: function () {
- this.showMedia = !this.showMedia;
- this.touchResize();
- if (this.showMedia) {
- this.addUserLogs(this.lang.expand_live);
- if(this.clientWidth < 500){
- document.getElementById("iamtsm").style.marginLeft = "0";
- }else{
- document.getElementById("iamtsm").style.marginLeft = "50%";
- }
- this.mediaLiveMaskHeightNum = 0;
- } else {
- this.addUserLogs(this.lang.collapse_live);
- this.mediaLiveMaskHeightNum = -150;
- document.getElementById("iamtsm").style.marginLeft = "0";
+
+ //在每次发送完后的检查时, 过滤掉已经发送完毕的记录
+ this.chooseFileRecoderList = this.chooseFileRecoderList.filter(item=>{
+ return !item.done;
+ });
+
+ // 在每次发送完后的检查时,如果是开启了自动排队发送,调用自动发送
+ if(this.chooseFileRecoderAutoNext){
+ this.sendFileToSingleAuto();
}
+
+ return false
},
- clickMediaAudio : function(){
- this.showMedia = !this.showMedia;
- this.touchResize();
- if (this.showMedia) {
- this.addUserLogs(this.lang.expand_audio);
- if(this.clientWidth < 500){
- document.getElementById("iamtsm").style.marginLeft = "0";
- }else{
- document.getElementById("iamtsm").style.marginLeft = "50%";
- }
- this.mediaAudioMaskHeightNum = 0;
- } else {
- this.addUserLogs(this.lang.collapse_audio);
- this.mediaAudioMaskHeightNum = -150;
- document.getElementById("iamtsm").style.marginLeft = "0";
+ // 指定单独发送文件给用户
+ sendFileToSingle: function(recoder){
+ layer.msg(`${this.lang.send_to_user_separately} ${recoder.id}`)
+
+ if(!this.hasManInRoom){
+ layer.msg(this.lang.room_least_two_can_send_content)
+ return
}
+
+ this.chooseFileRecoderList = [recoder];
+ this.sendFileRecoderInfo();
},
- typeInArr: function(arr, type, name = ""){
- if(type === ''){
- let fileTail = name.split(".").pop()
- return arr.filter(item=>{
- return fileTail.toLowerCase().includes(item) && name.endsWith("."+fileTail);
- }).length > 0;
- }else{
- return arr.filter(item=>{
- return type.toLowerCase().includes(item);
- }).length > 0;
+ // 自动单独发送文件给用户
+ sendFileToSingleAuto: function(){
+ if(!this.hasManInRoom){
+ layer.msg(this.lang.room_least_two_can_send_content)
+ return
}
- },
- //文件大小
- getFileSizeStr: function (size) {
- let sizeStr = (size / 1048576).toString();
- let head = sizeStr.split(".")[0];
- let tail = "";
- if (sizeStr.split(".")[1]) {
- tail = sizeStr.split(".")[1].substring(0, 3);
+
+ //当前自动切换文件是开启的
+ if(this.chooseFileRecoderAutoNext){
+ let chooseRecoder = this.sendFileRecoderList.filter(item=>{
+ return !item.done;
+ }).shift();
+
+ if(chooseRecoder){
+ setTimeout(() => {
+ this.chooseFileRecoderList = [chooseRecoder];
+ this.sendFileRecoderInfo();
+ }, 1000);
+ }
}
- return head + '.' + tail + "M";
},
- //创建文件发送房间
- createFileRoom: function () {
- this.openRoomInput = !this.openRoomInput;
+ // 一键发送 , 根据设置的规则自动选择发送模式,支持自动排队发送,并发发送
+ sendFileToAll: function(){
+ layer.msg(`${this.lang.send_to_all_user}`)
- if(this.openRoomInput){
+ if(!this.hasManInRoom){
+ layer.msg(this.lang.room_least_two_can_send_content)
return
}
- this.roomId = this.roomId.toString().replace(/\s*/g, "")
- if (this.roomId === null || this.roomId === undefined || this.roomId === '') {
- layer.msg(this.lang.please_enter_room_num)
- this.addUserLogs(this.lang.please_enter_room_num);
- return;
- }
- if (!this.switchData.allowChinese && window.tlrtcfile.containChinese(this.roomId)) {
- layer.msg(this.lang.room_num_no_zh)
- this.addUserLogs(this.lang.room_num_no_zh);
- return;
- }
- if (!this.switchData.allowNumber && window.tlrtcfile.containNumber(this.roomId)) {
- layer.msg(this.lang.room_num_no_number)
- this.addUserLogs(this.lang.room_num_no_number);
- return;
- }
- if (!this.switchData.allowSymbol && window.tlrtcfile.containSymbol(this.roomId)) {
- layer.msg(this.lang.room_num_no_special_symbols)
- this.addUserLogs(this.lang.room_num_no_special_symbols);
- return;
- }
- if (this.chooseFileList.length > 0) {
- layer.msg(this.lang.please_join_then_choose_file)
- this.addUserLogs(this.lang.please_join_then_choose_file);
- return;
- }
- if (this.roomId) {
- if (this.roomId.toString().length > 15) {
- layer.msg(this.lang.room_num_too_long)
- this.addUserLogs(this.lang.room_num_too_long);
- return;
- }
- this.setNickName();
- this.socket.emit('createAndJoin', {
- room: this.roomId,
- type : 'file',
- nickName : this.nickName,
- langMode : this.langMode,
- ua: this.isMobile ? 'mobile' : 'pc',
- network : this.network
- });
- this.isJoined = true;
- this.addPopup({
- title : this.lang.file_room,
- msg : this.lang.you_enter_file_room + this.roomId
- });
- this.addUserLogs( this.lang.you_enter_file_room + this.roomId);
+ let hasMoreBigFile = this.sendFileRecoderList.filter(item=>{
+ return item.size > this.bigFileMaxSize
+ }).length > this.bigFileMaxCount;
+
+ let hasLongFileQueue = this.sendFileRecoderList.filter(item=>{
+ return !item.done;
+ }).length > this.longFileQueueMaxSize;
+
+ //超过规则范围,自动排队发送
+ if(hasMoreBigFile || hasLongFileQueue){
+ this.chooseFileRecoderAutoNext = true;
+ this.sendFileToSingleAuto();
+ return
}
- },
- //创建流媒体房间
- createMediaRoom: function (type) {
- this.roomId = this.roomId.toString().replace(/\s*/g, "")
- if (this.roomId === null || this.roomId === undefined || this.roomId === '') {
- layer.msg(this.lang.please_enter_room_num)
- this.addUserLogs(this.lang.please_enter_room_num);
- return;
- }
- if (this.roomId) {
- if (this.roomId.toString().length > 15) {
- layer.msg(this.lang.room_num_too_long)
- this.addUserLogs(this.lang.room_num_too_long);
- return;
- }
- this.setNickName();
- this.socket.emit('createAndJoin', {
- room: this.roomId,
- type: type,
+
+ //如果不是单独发送某个记录,就需要处理全部记录
+ this.chooseFileRecoderList = this.sendFileRecoderList.filter(item=>{
+ return !item.done;
+ })
+ this.sendFileRecoderInfo();
+ },
+ // 多记录并发发送文件基本信息
+ sendFileRecoderInfo : function(){
+ // 提前发送文件基础信息
+ this.chooseFileRecoderList.forEach(chooseRecoder => {
+ this.socket.emit('message', {
+ emitType: "sendFileInfo",
+ index: chooseRecoder.index,
+ name: chooseRecoder.name,
+ type: chooseRecoder.type,
+ size: chooseRecoder.size,
+ room: this.roomId,
+ from: this.socketId,
nickName : this.nickName,
- langMode : this.langMode,
- ua: this.isMobile ? 'mobile' : 'pc',
- network : this.network,
- liveShareRole : this.liveShareRole
- });
- this.isJoined = true;
- this.roomType = type;
- this.addPopup({
- title : this.lang.stream_room,
- msg : this.lang.you_enter_stream_room + this.roomId
+ to: chooseRecoder.id,
+ recoderId: this.recoderId
});
- this.addUserLogs(this.lang.you_enter_stream_room + this.roomId);
- }
+ })
},
- //创建密码房间
- createPasswordRoom: function (password) {
- this.roomId = this.roomId.toString().replace(/\s*/g, "")
- if (this.roomId === null || this.roomId === undefined || this.roomId === '') {
- layer.msg(this.lang.please_enter_room_num)
- this.addUserLogs(this.lang.please_enter_room_num);
- return;
- }
- if (this.roomId) {
- if (this.roomId.toString().length > 15) {
- layer.msg(this.lang.room_num_too_long)
- this.addUserLogs(this.lang.room_num_too_long);
- return;
- }
- if (password.toString().length > 15) {
- layer.msg(this.lang.password_too_long)
- this.addUserLogs(this.lang.password_too_long);
- return;
+ // 多记录并行发送文件数据
+ sendFileRecoderData: function () {
+ let that = this;
+
+ this.chooseFileRecoderList.forEach(chooseRecoder => {
+ let filterFile = that.chooseFileList.filter(item => {
+ return item.index === chooseRecoder.index;
+ });
+ if(filterFile.length === 0){
+ return
}
- this.setNickName();
- this.socket.emit('createAndJoin', {
- room: this.roomId,
- type : 'password',
- password: password,
- nickName : this.nickName,
- langMode : this.langMode,
- ua: this.isMobile ? 'mobile' : 'pc',
- network : this.network
+
+ let chooseFile = filterFile[0];
+ let fileReader = chooseRecoder.reader;
+
+ fileReader.addEventListener('loadend', (event) => {
+ that.sendFileToRemoteByRecoder(event.target.result, chooseRecoder, chooseFile);
});
- this.isJoined = true;
- this.addPopup({
- title : this.lang.password_room,
- msg : this.lang.you_enter_password_room + this.roomId
+
+ fileReader.addEventListener('error', error => {
+ that.addSysLogs(that.lang.read_file_error + " : " + error);
});
- this.addUserLogs(this.lang.you_enter_password_room + this.roomId);
- }
- },
- //退出房间
- exitRoom: function () {
- if (this.roomId) {
- this.socket.emit('exit', {
- from: this.socketId,
- room: this.roomId,
- recoderId: this.recoderId
+
+ fileReader.addEventListener('abort', event => {
+ that.addSysLogs(that.lang.read_file_interrupt + " : " + event);
});
- }
- for (let i in this.rtcConns) {
- let rtcConnect = this.rtcConns[i];
- rtcConnect.close();
- rtcConnect = null;
- }
- window.location.reload();
+ that.readAsArrayBufferByOffset(0, chooseFile, chooseRecoder)
+ })
},
- //创立链接
- createRtcConnect: function (id) {
- if (id === undefined) {
- return;
+ // 一次发送一个文件给一个用户
+ sendFileToRemoteByRecoder: function (buffer, chooseRecoder, chooseFile) {
+ let that = this;
+ if (!chooseRecoder) {
+ return
}
- let that = this;
- let rtcConnect = new RTCPeerConnection(this.config);
+ let remote = this.getRemoteInfo(chooseRecoder.id);
+ let fileOffset = remote[chooseRecoder.index + "offset"]
+ let sendFileDataChannel = remote.sendFileDataChannel;
+ if (!sendFileDataChannel || sendFileDataChannel.readyState !== 'open') {
+ this.addSysLogs(this.lang.file_send_channel_not_establish)
+ return;
+ }
- //ice
- rtcConnect.onicecandidate = (e) => {
- that.iceCandidate(rtcConnect, id, e)
- };
+ this.setRemoteInfo(chooseRecoder.id, {
+ [chooseRecoder.index + "status"]: 'sending'
+ })
- rtcConnect.oniceconnectionstatechange = (e) => {
- that.addSysLogs("iceConnectionState: " + rtcConnect.iceConnectionState);
+ this.isSending = true;
- //如果是断开连接,并且没有使用turn服务器,提示开启turn服务器
- if(rtcConnect.iceConnectionState === 'disconnected' && !this.useTurn){
- layer.msg(that.lang.please_use_turn_server);
- that.addSysLogs(that.lang.please_use_turn_server);
- }
- that.setRemoteInfo(id, {
- iceConnectionState : rtcConnect.iceConnectionState
- })
+ // 开始发送通知
+ if (fileOffset === 0) {
+ this.addPopup({
+ title : this.lang.send_file,
+ msg : this.lang.sending_to + chooseRecoder.id.substr(0, 4) + ",0%。"
+ });
+ this.addSysLogs(this.lang.sending_to + chooseRecoder.id.substr(0, 4) + ",0%。")
+ this.updateSendFileRecoderProgress(chooseRecoder.id, {
+ start: Date.now()
+ }, chooseRecoder)
}
- //媒体流通道
- rtcConnect.ontrack = (e) => {
- that.mediaTrackHandler(e, id)
- };
-
- //文件发送数据通道
- let sendFileDataChannel = rtcConnect.createDataChannel('sendFileDataChannel');
- sendFileDataChannel.binaryType = 'arraybuffer';
- sendFileDataChannel.addEventListener('open', (event) => {
- if (sendFileDataChannel.readyState === 'open') {
- that.addSysLogs(that.lang.establish_connection)
- }
- });
- sendFileDataChannel.addEventListener('close', (event) => {
- if (sendFileDataChannel.readyState === 'close') {
- that.addSysLogs(that.lang.connection_closed)
- }
- });
- sendFileDataChannel.addEventListener('error', (error) => {
- console.error(error.error)
- that.addSysLogs(that.lang.connection_disconnected + ",file:e=" + error)
- that.removeStream(null, id, null)
- });
-
- //自定义数据发送通道
- let sendDataChannel = rtcConnect.createDataChannel('sendDataChannel');
- sendDataChannel.binaryType = 'arraybuffer';
- sendDataChannel.addEventListener('open', (event) => {
- if (sendDataChannel.readyState === 'open') {
- that.addSysLogs(that.lang.establish_connection)
- }
- });
- sendDataChannel.addEventListener('close', (event) => {
- if (sendDataChannel.readyState === 'close') {
- that.addSysLogs(that.lang.connection_closed)
+ //缓冲区暂定 256kb
+ sendFileDataChannel.bufferedAmountLowThreshold = 16 * 1024 * 16;
+ //局域网一般不会走缓冲区,所以bufferedAmount一般为0,公网部分情况受限于带宽,bufferedAmount可能会逐渐堆积,从而进行排队
+ if (sendFileDataChannel.bufferedAmount > sendFileDataChannel.bufferedAmountLowThreshold) {
+ this.addSysLogs(
+ that.lang.file_send_channel_buffer_full + ",bufferedAmount=" +
+ sendFileDataChannel.bufferedAmount + ",bufferedAmountLowThreshold=" +
+ sendFileDataChannel.bufferedAmountLowThreshold
+ )
+ sendFileDataChannel.onbufferedamountlow = () => {
+ that.addSysLogs(
+ that.lang.file_send_channel_buffer_recover + ",bufferedAmount=" +
+ sendFileDataChannel.bufferedAmount
+ )
+ sendFileDataChannel.onbufferedamountlow = null;
+ that.sendFileToRemoteByRecoder(buffer, chooseRecoder, chooseFile);
}
- });
- sendDataChannel.addEventListener('error', (error) => {
- console.error(error.error)
- that.addSysLogs(that.lang.connection_disconnected + ",cus:e=" + error)
- that.removeStream(null, id, null)
- });
+ return;
+ }
- rtcConnect.addEventListener('datachannel', (event) => {
- that.initReceiveDataChannel(event, id);
- });
+ // 发送数据
+ sendFileDataChannel.send(this.encodeSendFileBuffer({
+ recoder : chooseRecoder,
+ fragment : parseInt(fileOffset / this.chunkSize),
+ buffer : buffer,
+ }));
- rtcConnect.onremovestream = (e) => {
- that.removeStream(rtcConnect, id, e)
- };
+ fileOffset += buffer.byteLength;
+ remote[chooseRecoder.index + "offset"] = fileOffset
+ this.currentSendAllSize += buffer.byteLength;
- //保存peer连接
- this.rtcConns[id] = rtcConnect;
- if (!this.remoteMap[id]) {
- Vue.set(this.remoteMap, id, {
- id: id,
- receiveChatRoomSingleList : [],
- p2pMode : '识别中...',
- sendFileDataChannel: sendFileDataChannel,
- sendDataChannel : sendDataChannel
- })
- }
+ //更新发送进度
+ this.updateSendFileRecoderProgress(chooseRecoder.id, {
+ progress: ((fileOffset / chooseRecoder.size) * 100).toFixed(3) || 0
+ }, chooseRecoder)
- return rtcConnect;
- },
- //获取本地与远程连接
- getOrCreateRtcConnect: function (id) {
- // 获取rtc缓存连接
- let rtcConnect = this.rtcConns[id];
- // 不存在,创建一个
- if (typeof (rtcConnect) == 'undefined') {
- rtcConnect = this.createRtcConnect(id);
- }
- return rtcConnect;
- },
- //远程媒体流处理
- mediaTrackHandler: function(event, id){
- let that = this;
-
- let video = null;
+ //发送完一份重置相关数据
+ if (fileOffset === chooseRecoder.size) {
+ this.addPopup({
+ title : this.lang.send_file,
+ msg : this.lang.sending_to + chooseRecoder.id.substr(0, 4) + ",100%。"
+ });
+ this.addSysLogs(this.lang.sending_to + chooseRecoder.id.substr(0, 4) + ",100%。")
+ this.socket.emit('message', {
+ emitType: "sendDone",
+ room: this.roomId,
+ from: this.socketId,
+ size: chooseRecoder.size,
+ name: chooseRecoder.name,
+ type: chooseRecoder.type,
+ to: chooseRecoder.id
+ });
+ //更新发送进度
+ this.updateSendFileRecoderProgress(chooseRecoder.id, {
+ progress: 100,
+ done: true
+ }, chooseRecoder)
- const remoteRtc = this.getRemoteInfo(id);
- const remoteName = remoteRtc.nickName || "";
+ this.setRemoteInfo(chooseRecoder.id, {
+ [chooseRecoder.index + "status"]: 'done'
+ })
- if(event.track.kind === 'audio'){
- // audio-track事件,除了语音连麦房间之外,其他都可以跳过,因为音视频/直播/屏幕共享他们的音频流都并入了video-track了
- if(that.roomType !== 'audio'){
- return
- }
+ this.isSending = false;
- //连麦房间,只有音频数据
- $(`#mediaAudioRoomList`).append(`
-
${remoteName}
-
-
-
-
-
-
-
- `);
- video = document.querySelector(`#otherMediaAudioShare${id}`);
+ //检查全部发送完毕
+ this.allFileSendedCheckHandler()
}
- if(this.roomType === 'video'){
- $(`#mediaVideoRoomList`).append(`
-
${remoteName}
-
-
-
-
-
-
- `);
- video = document.querySelector(`#otherMediaVideoShare${id}`);
- } else if(this.roomType === 'screen'){
- $(`#mediaScreenRoomList`).append(`
-
${remoteName}
-
-
-
-
- `);
- video = document.querySelector(`#otherMediaScreenShare${id}`);
- } else if(this.roomType === 'live'){
-
- if(this.liveShareRole === 'viewer'){
- $(`#mediaLiveRoomList`).append(`
-
${remoteName}
-
-
-
-
-
-
- `);
- }
-
- video = document.querySelector(`#otherMediaLiveShare${id}`);
- }
-
- if(video){
- video.addEventListener('loadedmetadata', function() {
- video.play();
- that.addSysLogs("loadedmetadata")
- // ios 微信浏览器兼容问题
- document.addEventListener('WeixinJSBridgeReady', function () {
- that.addSysLogs("loadedmetadata WeixinJSBridgeReady")
- video.play();
- }, false);
- });
- document.addEventListener('WeixinJSBridgeReady', function () {
- that.addSysLogs("WeixinJSBridgeReady")
- video.play();
- }, false);
- video.srcObject = event.streams[0]
- video.play();
+ if(fileOffset < chooseRecoder.size){
+ this.readAsArrayBufferByOffset(fileOffset, chooseFile, chooseRecoder);
}
},
- //编码组装发送文件数据,设置好每次分片的文件头信息
- encodeSendFileBuffer: function ({recoder, buffer, fragment, event}) {
- let fileInfoString = JSON.stringify({
- i: recoder.index, //当前文件块所属的索引
- f: fragment, //当前buffer所处的分片块
- });
- //填充
- const paddedFileInfoString = fileInfoString.padEnd(this.fileInfoBufferHeaderLen, '\0');
- const combindBuffer = new ArrayBuffer(this.fileInfoBufferHeaderLen + buffer.byteLength);
-
- const combinedUint8Array = new Uint8Array(combindBuffer);
- for (let i = 0; i < paddedFileInfoString.length; i++) {
- combinedUint8Array[i] = paddedFileInfoString.charCodeAt(i);
- }
- combinedUint8Array.set(new Uint8Array(buffer), this.fileInfoBufferHeaderLen);
-
- return combindBuffer;
+ // 分片读取文件
+ readAsArrayBufferByOffset: function ( offset, chooseFile, chooseRecoder) {
+ let slice = chooseFile.slice(offset, offset + this.chunkSize);
+ let fileReader = chooseRecoder.reader;
+ fileReader.readAsArrayBuffer(slice);
},
- //解码组装接收文件数据
- decodeReceiveFileBuffer: function (buffer) {
- const receivedUint8Array = new Uint8Array(buffer);
- const fileInfoString = String.fromCharCode(...receivedUint8Array.slice(0, this.fileInfoBufferHeaderLen));
- const trimmedFileInfoString = fileInfoString.replace(/\0/g, '');
- const fileInfo = JSON.parse(trimmedFileInfoString);
- return {
- buffer: receivedUint8Array.slice(this.fileInfoBufferHeaderLen),
- index: fileInfo.i,
- fragment: fileInfo.f
+ //初始化接收数据事件
+ initReceiveDataChannel: function (event, id) {
+ if (!id || !event) {
+ return;
}
- },
- //每个记录发送完毕后都检查下是否全部发送完
- allFileSendedCheckHandler : function(){
- let allDone = this.sendFileRecoderList.filter(item => {
- return item.done;
- }).length === this.sendFileRecoderList.length;
-
- // 全部发完
- if(allDone){
- this.chooseFileList = []
- this.sendFileRecoderList = []
- this.chooseFileRecoderList = []
- this.chooseFileRecoderAutoNext = false;
- this.addPopup({
- title : this.lang.send_file,
- msg : this.lang.file_send_done
- });
- this.addSysLogs(this.lang.file_send_done)
- this.allSended = true;
- this.isSending = false;
-
- return true
+ let currentRtc = this.getRemoteInfo(id);
+ if (!currentRtc) {
+ return
}
- //在每次发送完后的检查时, 过滤掉已经发送完毕的记录
- this.chooseFileRecoderList = this.chooseFileRecoderList.filter(item=>{
- return !item.done;
- });
+ let receiveChannel = event.channel;
- // 在每次发送完后的检查时,如果是开启了自动排队发送,调用自动发送
- if(this.chooseFileRecoderAutoNext){
- this.sendFileToSingleAuto();
+ //文件接收
+ if(receiveChannel.label === 'sendFileDataChannel'){
+ receiveChannel.binaryType = 'arraybuffer';
+ receiveChannel.onmessage = (evt) => {
+ if(this.canSaveToIndexedDb && this.useIndexedDb){
+ this.receiveFileDataToIndexedDb(evt, id);
+ }else{
+ this.receiveFileDataToMemery(evt, id);
+ }
+ };
+ receiveChannel.onopen = () => {
+ const readyState = receiveChannel.readyState;
+ this.addSysLogs(this.lang.file_receive_channel_ready + readyState)
+ };
+ receiveChannel.onclose = () => {
+ const readyState = receiveChannel.readyState;
+ this.addSysLogs(this.lang.file_receive_channel_closed + readyState)
+ };
+ this.setRemoteInfo(id, { receiveFileDataChannel: receiveChannel });
}
- return false
- },
- // 指定单独发送文件给用户
- sendFileToSingle: function(recoder){
- layer.msg(`${this.lang.send_to_user_separately} ${recoder.id}`)
-
- if(!this.hasManInRoom){
- layer.msg(this.lang.room_least_two_can_send_content)
- return
+ //自定义数据接收
+ if(receiveChannel.label === 'sendDataChannel'){
+ receiveChannel.binaryType = 'arraybuffer';
+ receiveChannel.onmessage = (evt) => {
+ //接收自定义数据 , 暂时用做远程画笔数据接收
+ if (!evt || !id) {
+ return;
+ }
+ let data = JSON.parse(evt.data) || {};
+ window.Bus.$emit("openRemoteDraw", data)
+ }
+ receiveChannel.onopen = () => {
+ const readyState = receiveChannel.readyState;
+ this.addSysLogs(this.lang.custom_data_receive_channel_ready + readyState)
+ };
+ receiveChannel.onclose = () => {
+ const readyState = receiveChannel.readyState;
+ this.addSysLogs(this.lang.custom_data_receive_channel_closed + readyState)
+ };
+ this.setRemoteInfo(id, { receiveDataChannel: receiveChannel });
}
-
- this.chooseFileRecoderList = [recoder];
- this.sendFileRecoderInfo();
},
- // 自动单独发送文件给用户
- sendFileToSingleAuto: function(){
- if(!this.hasManInRoom){
- layer.msg(this.lang.room_least_two_can_send_content)
- return
+ //接收文件 (使用indexedDb接收,不占用内存)
+ receiveFileDataToIndexedDb: function (event, id) {
+ let that = this;
+ if (!event || !id) {
+ return;
}
-
- //当前自动切换文件是开启的
- if(this.chooseFileRecoderAutoNext){
- let chooseRecoder = this.sendFileRecoderList.filter(item=>{
- return !item.done;
- }).shift();
-
- if(chooseRecoder){
- setTimeout(() => {
- this.chooseFileRecoderList = [chooseRecoder];
- this.sendFileRecoderInfo();
- }, 1000);
- }
+ let currentRtc = this.getRemoteInfo(id);
+ if(!currentRtc){
+ return;
}
- },
- // 一键发送 , 根据设置的规则自动选择发送模式,支持自动排队发送,并发发送
- sendFileToAll: function(){
- layer.msg(`${this.lang.send_to_all_user}`)
- if(!this.hasManInRoom){
- layer.msg(this.lang.room_least_two_can_send_content)
- return
- }
+ //解析数据
+ let { index, fragment, buffer } = this.decodeReceiveFileBuffer(event.data);
- let hasMoreBigFile = this.sendFileRecoderList.filter(item=>{
- return item.size > this.bigFileMaxSize
- }).length > this.bigFileMaxCount;
+ //接收文件总大小
+ this.receivedFileAllSize += buffer.byteLength;
- let hasLongFileQueue = this.sendFileRecoderList.filter(item=>{
- return !item.done;
- }).length > this.longFileQueueMaxSize;
-
- //超过规则范围,自动排队发送
- if(hasMoreBigFile || hasLongFileQueue){
- this.chooseFileRecoderAutoNext = true;
- this.sendFileToSingleAuto();
- return
+ // 文件数据 大小/数据
+ let receiveFileMap = currentRtc.receiveFileMap;
+ let receiveRecoder = receiveFileMap[index];
+ let receivedSize = receiveRecoder.receivedSize;
+ receivedSize += buffer.byteLength;
+ receiveFileMap[index].receivedSize = receivedSize;
+ let receivedBuffer = receiveRecoder.receivedBuffer;
+ receivedBuffer.push(buffer);
+ receiveFileMap[index].receivedBuffer = receivedBuffer;
+
+ // 文件信息
+ let receiveFileRecoder = this.receiveFileRecoderList.filter(item=>{
+ return item.index === index;
+ })[0];
+
+ //当前接收的文件基本信息
+ let name = receiveFileRecoder.name;
+ let size = receiveFileRecoder.size;
+ let type = receiveFileRecoder.type;
+
+ //1000分片存储一次, 默认16M一组 = chunkSize * 1000
+ if(fragment % 1000 === 0){
+ this.saveSliceFileBufferToIndexedDb(receiveFileRecoder, fragment, receivedBuffer);
+ receiveFileMap[index].receivedBuffer = new Array();
}
+ this.setRemoteInfo(id, { receiveFileMap : receiveFileMap});
- //如果不是单独发送某个记录,就需要处理全部记录
- this.chooseFileRecoderList = this.sendFileRecoderList.filter(item=>{
- return !item.done;
- })
- this.sendFileRecoderInfo();
- },
- // 多记录并发发送文件基本信息
- sendFileRecoderInfo : function(){
- // 提前发送文件基础信息
- this.chooseFileRecoderList.forEach(chooseRecoder => {
- this.socket.emit('message', {
- emitType: "sendFileInfo",
- index: chooseRecoder.index,
- name: chooseRecoder.name,
- type: chooseRecoder.type,
- size: chooseRecoder.size,
- room: this.roomId,
- from: this.socketId,
- nickName : this.nickName,
- to: chooseRecoder.id,
- recoderId: this.recoderId
- });
- })
- },
- // 多记录并行发送文件数据
- sendFileRecoderData: function () {
- let that = this;
+ //更新接收进度
+ this.updateReceiveFileRecoderProgress(id, {
+ progress: ((receivedSize / size) * 100).toFixed(3) || 0,
+ fragment : fragment
+ }, receiveFileRecoder);
- this.chooseFileRecoderList.forEach(chooseRecoder => {
- let filterFile = that.chooseFileList.filter(item => {
- return item.index === chooseRecoder.index;
+ //接收完毕
+ if (receivedSize === size) {
+ this.addSysLogs(name + this.lang.save_file_to_indexeddb);
+ this.addPopup({
+ title : this.lang.file_receive,
+ msg : "[ " + name + " ]" + this.lang.save_file_to_indexeddb
});
- if(filterFile.length === 0){
- return
+
+ //发送完毕后,如果buffer还有剩余不满1000分片的数据,也要存储
+ if(receivedBuffer.length >= 0){
+ this.saveSliceFileBufferToIndexedDb(receiveFileRecoder, fragment, receivedBuffer);
}
- let chooseFile = filterFile[0];
- let fileReader = chooseRecoder.reader;
+ // 更新接收进度
+ this.updateReceiveFileRecoderProgress(id, {
+ progress: 100,
+ done: true,
+ }, receiveFileRecoder);
- fileReader.addEventListener('loadend', (event) => {
- that.sendFileToRemoteByRecoder(event.target.result, chooseRecoder, chooseFile);
- });
-
- fileReader.addEventListener('error', error => {
- that.addSysLogs(that.lang.read_file_error + " : " + error);
- });
-
- fileReader.addEventListener('abort', event => {
- that.addSysLogs(that.lang.read_file_interrupt + " : " + event);
- });
+ // 更新indexeddb中的文件信息
+ this.saveSliceFileInfoToIndexedDb(Object.assign({
+ progress: 100,
+ done: true,
+ }, receiveFileRecoder));
- that.readAsArrayBufferByOffset(0, chooseFile, chooseRecoder)
- })
+ //清除接收的数据缓存
+ receiveFileMap[index].receivedBuffer = new Array();
+ receiveFileMap[index].receivedSize = 0;
+ this.setRemoteInfo(id, { receiveFileMap })
+ }
},
- // 一次发送一个文件给一个用户
- sendFileToRemoteByRecoder: function (buffer, chooseRecoder, chooseFile) {
+ //接收文件 (使用内存接收)
+ receiveFileDataToMemery: function (event, id) {
let that = this;
- if (!chooseRecoder) {
- return
+ if (!event || !id) {
+ return;
}
-
- let remote = this.getRemoteInfo(chooseRecoder.id);
- let fileOffset = remote[chooseRecoder.index + "offset"]
- let sendFileDataChannel = remote.sendFileDataChannel;
- if (!sendFileDataChannel || sendFileDataChannel.readyState !== 'open') {
- this.addSysLogs(this.lang.file_send_channel_not_establish)
+ let currentRtc = this.getRemoteInfo(id);
+ if(!currentRtc){
return;
}
- this.setRemoteInfo(chooseRecoder.id, {
- [chooseRecoder.index + "status"]: 'sending'
- })
+ //解析数据
+ let { index, fragment, buffer } = this.decodeReceiveFileBuffer(event.data);
- this.isSending = true;
+ let receiveFileMap = currentRtc.receiveFileMap;
+ let receiveRecoder = receiveFileMap[index];
+ //当前接收的文件相关数据/大小
+ let receivedBuffer = receiveRecoder.receivedBuffer;
+ let receivedSize = receiveRecoder.receivedSize;
- // 开始发送通知
- if (fileOffset === 0) {
- this.addPopup({
- title : this.lang.send_file,
- msg : this.lang.sending_to + chooseRecoder.id.substr(0, 4) + ",0%。"
- });
- this.addSysLogs(this.lang.sending_to + chooseRecoder.id.substr(0, 4) + ",0%。")
- this.updateSendFileRecoderProgress(chooseRecoder.id, {
- start: Date.now()
- }, chooseRecoder)
- }
+ //当前接收的文件基本信息
+ let receiveFileRecoder = this.receiveFileRecoderList.filter(item=>{
+ return item.index === index;
+ })[0];
+ let name = receiveFileRecoder.name;
+ let size = receiveFileRecoder.size;
+ let type = receiveFileRecoder.type;
- //缓冲区暂定 256kb
- sendFileDataChannel.bufferedAmountLowThreshold = 16 * 1024 * 16;
- //局域网一般不会走缓冲区,所以bufferedAmount一般为0,公网部分情况受限于带宽,bufferedAmount可能会逐渐堆积,从而进行排队
- if (sendFileDataChannel.bufferedAmount > sendFileDataChannel.bufferedAmountLowThreshold) {
- this.addSysLogs(
- that.lang.file_send_channel_buffer_full + ",bufferedAmount=" +
- sendFileDataChannel.bufferedAmount + ",bufferedAmountLowThreshold=" +
- sendFileDataChannel.bufferedAmountLowThreshold
- )
- sendFileDataChannel.onbufferedamountlow = () => {
- that.addSysLogs(
- that.lang.file_send_channel_buffer_recover + ",bufferedAmount=" +
- sendFileDataChannel.bufferedAmount
- )
- sendFileDataChannel.onbufferedamountlow = null;
- that.sendFileToRemoteByRecoder(buffer, chooseRecoder, chooseFile);
- }
- return;
- }
+ //接收数据
+ receivedBuffer.push(buffer);
+ receivedSize += buffer.byteLength;
- // 发送数据
- sendFileDataChannel.send(this.encodeSendFileBuffer({
- recoder : chooseRecoder,
- fragment : parseInt(fileOffset / this.chunkSize),
- buffer : buffer,
- }));
+ //接收文件总大小
+ this.receivedFileAllSize += buffer.byteLength;
- fileOffset += buffer.byteLength;
- remote[chooseRecoder.index + "offset"] = fileOffset
- this.currentSendAllSize += buffer.byteLength;
+ receiveFileMap[index].receivedBuffer = receivedBuffer;
+ receiveFileMap[index].receivedSize = receivedSize;
+ this.setRemoteInfo(id, { receiveFileMap : receiveFileMap})
- //更新发送进度
- this.updateSendFileRecoderProgress(chooseRecoder.id, {
- progress: ((fileOffset / chooseRecoder.size) * 100).toFixed(3) || 0
- }, chooseRecoder)
+ //更新接收进度
+ this.updateReceiveFileRecoderProgress(id, {
+ progress: ((receivedSize / size) * 100).toFixed(3) || 0
+ }, receiveFileRecoder);
- //发送完一份重置相关数据
- if (fileOffset === chooseRecoder.size) {
+ if (receivedSize === size) {
+ this.addSysLogs(name + this.lang.receive_done);
this.addPopup({
- title : this.lang.send_file,
- msg : this.lang.sending_to + chooseRecoder.id.substr(0, 4) + ",100%。"
- });
- this.addSysLogs(this.lang.sending_to + chooseRecoder.id.substr(0, 4) + ",100%。")
- this.socket.emit('message', {
- emitType: "sendDone",
- room: this.roomId,
- from: this.socketId,
- size: chooseRecoder.size,
- name: chooseRecoder.name,
- type: chooseRecoder.type,
- to: chooseRecoder.id
+ title : this.lang.file_receive,
+ msg : "[ " + name + " ]" + this.lang.receive_done
});
- //更新发送进度
- this.updateSendFileRecoderProgress(chooseRecoder.id, {
- progress: 100,
- done: true
- }, chooseRecoder)
-
- this.setRemoteInfo(chooseRecoder.id, {
- [chooseRecoder.index + "status"]: 'done'
- })
- this.isSending = false;
+ //更新接收进度
+ this.updateReceiveFileRecoderProgress(id, {
+ progress: 100,
+ href: URL.createObjectURL(new Blob(receivedBuffer), { type: type }),
+ done: true,
+ }, receiveFileRecoder);
- //检查全部发送完毕
- this.allFileSendedCheckHandler()
+ //清除接收的数据缓存
+ receiveFileMap[index].receivedBuffer = new Array();
+ receiveFileMap[index].receivedSize = 0;
+ this.setRemoteInfo(id, { receiveFileMap })
}
+ },
+ //关闭连接
+ closeDataChannels: function () {
+ for (let remote in this.remoteMap) {
+ let id = remote.id;
+ if(!id) continue;
- if(fileOffset < chooseRecoder.size){
- this.readAsArrayBufferByOffset(fileOffset, chooseFile, chooseRecoder);
- }
- },
- // 分片读取文件
- readAsArrayBufferByOffset: function ( offset, chooseFile, chooseRecoder) {
- let slice = chooseFile.slice(offset, offset + this.chunkSize);
- let fileReader = chooseRecoder.reader;
- fileReader.readAsArrayBuffer(slice);
- },
- //初始化接收数据事件
- initReceiveDataChannel: function (event, id) {
- if (!id || !event) {
- return;
- }
- let currentRtc = this.getRemoteInfo(id);
- if (!currentRtc) {
- return
- }
-
- let receiveChannel = event.channel;
-
- //文件接收
- if(receiveChannel.label === 'sendFileDataChannel'){
- receiveChannel.binaryType = 'arraybuffer';
- receiveChannel.onmessage = (evt) => {
- this.receiveFileData(evt, id);
- };
- receiveChannel.onopen = () => {
- const readyState = receiveChannel.readyState;
- this.addSysLogs(this.lang.file_receive_channel_ready + readyState)
- };
- receiveChannel.onclose = () => {
- const readyState = receiveChannel.readyState;
- this.addSysLogs(this.lang.file_receive_channel_closed + readyState)
- };
- this.setRemoteInfo(id, { receiveFileDataChannel: receiveChannel });
- }
-
- //自定义数据接收
- if(receiveChannel.label === 'sendDataChannel'){
- receiveChannel.binaryType = 'arraybuffer';
- receiveChannel.onmessage = (evt) => {
- //接收自定义数据 , 暂时用做远程画笔数据接收
- if (!evt || !id) {
- return;
- }
- let data = JSON.parse(evt.data) || {};
- window.Bus.$emit("openRemoteDraw", data)
- }
- receiveChannel.onopen = () => {
- const readyState = receiveChannel.readyState;
- this.addSysLogs(this.lang.custom_data_receive_channel_ready + readyState)
- };
- receiveChannel.onclose = () => {
- const readyState = receiveChannel.readyState;
- this.addSysLogs(this.lang.custom_data_receive_channel_closed + readyState)
- };
- this.setRemoteInfo(id, { receiveDataChannel: receiveChannel });
- }
- },
- //接收文件
- receiveFileData: function (event, id) {
- if (!event || !id) {
- return;
- }
- let currentRtc = this.getRemoteInfo(id);
- if(!currentRtc){
- return;
- }
-
- //解析数据
- let { index, fragment, buffer } = this.decodeReceiveFileBuffer(event.data);
- let receiveFileMap = currentRtc.receiveFileMap;
-
- //当前接收的文件基本信息
- let receiveRecoder = receiveFileMap[index];
- let name = receiveRecoder.name;
- let size = receiveRecoder.size;
- let type = receiveRecoder.type;
-
- //当前接收的文件相关数据/大小
- let receivedBuffer = receiveRecoder.receivedBuffer;
- let receivedSize = receiveRecoder.receivedSize;
-
- //接收数据
- receivedBuffer.push(buffer);
- receivedSize += buffer.byteLength;
-
- receiveFileMap[index].receivedBuffer = receivedBuffer;
- receiveFileMap[index].receivedSize = receivedSize;
- this.setRemoteInfo(id, { receiveFileMap : receiveFileMap})
-
- //更新接收进度
- this.updateReceiveProgress(id, {
- progress: ((receivedSize / size) * 100).toFixed(3) || 0
- }, receiveRecoder);
-
- if (receivedSize === size) {
- this.addSysLogs(name + this.lang.receive_done);
- this.addPopup({
- title : this.lang.file_receive,
- msg : "[ " + name + " ]" + this.lang.receive_done
- });
-
- //更新接收进度
- this.updateReceiveProgress(id, {
- style: 'color: #ff5722;text-decoration: underline;',
- progress: 100,
- href: URL.createObjectURL(new Blob(receivedBuffer), { type: type }),
- done: true
- }, receiveRecoder);
-
- //清除接收的数据缓存
- receiveFileMap[index].receivedBuffer = new Array();
- receiveFileMap[index].receivedSize = 0;
- this.setRemoteInfo(id, { receiveFileMap })
- }
- },
- //关闭连接
- closeDataChannels: function () {
- for (let remote in this.remoteMap) {
- let id = remote.id;
- if(!id) continue;
-
- let sendFileDataChannel = remote.sendFileDataChannel;
- if(sendFileDataChannel){
- sendFileDataChannel.close();
- }
- let sendDataChannel = remote.sendDataChannel;
- if(sendDataChannel){
- sendDataChannel.close();
- }
- let receiveFileDataChannel = remote.receiveFileDataChannel;
- if(receiveFileDataChannel){
- receiveFileDataChannel.close();
- }
- let receiveDataChannel = remote.receiveDataChannel;
- if(receiveDataChannel){
- receiveDataChannel.close();
- }
+ let sendFileDataChannel = remote.sendFileDataChannel;
+ if(sendFileDataChannel){
+ sendFileDataChannel.close();
+ }
+ let sendDataChannel = remote.sendDataChannel;
+ if(sendDataChannel){
+ sendDataChannel.close();
+ }
+ let receiveFileDataChannel = remote.receiveFileDataChannel;
+ if(receiveFileDataChannel){
+ receiveFileDataChannel.close();
+ }
+ let receiveDataChannel = remote.receiveDataChannel;
+ if(receiveDataChannel){
+ receiveDataChannel.close();
+ }
}
},
//设置rtc缓存远程连接数据
@@ -3418,7 +3282,7 @@ axios.get("/api/comm/initData?turn="+useTurn, {}).then((initData) => {
}
},
//更新接收进度
- updateReceiveProgress: function (id, data, recoder) {
+ updateReceiveFileRecoderProgress: function (id, data, recoder) {
for (let i = 0; i < this.receiveFileRecoderList.length; i++) {
let item = this.receiveFileRecoderList[i];
if (item.id === id && item.index === recoder.index && !item.done) {
@@ -3549,9 +3413,17 @@ axios.get("/api/comm/initData?turn="+useTurn, {}).then((initData) => {
addIceCandidateFailed: function (err) {
this.addSysLogs(this.lang.add_ice_candidate_failed + err);
},
+ //事件监听
socketListener: function () {
let that = this;
+ this.socket.on("localNetRoom", data => {
+ that.localNetRoomList = data.list || [];
+ if(that.localNetRoomList.length === 0 && that.showLocalNetRoom){
+ that.clickLocalNetRooms(true);
+ }
+ })
+
this.socket.on("heartbeat", data => {
if(data.status === 'ok'){
that.addSysLogs(that.lang.websocketHeartBeatCheckOk + ": " + data.status);
@@ -3764,22 +3636,22 @@ axios.get("/api/comm/initData?turn="+useTurn, {}).then((initData) => {
//选中文件时发送给接收方
this.socket.on('sendFileInfo', function (data) {
- let fromId = data.from;
- let { receiveFileMap = {} } = that.getRemoteInfo(fromId);
- receiveFileMap[data.index] = Object.assign({
- receivedBuffer : new Array(),
- receivedSize : 0
- },data);
-
- that.setRemoteInfo(fromId, { receiveFileMap });
-
that.addPopup({
title : that.lang.send_file,
msg : data.from + that.lang.selected_file + "[ " + data.name + " ], "+that.lang.will_send
});
that.addSysLogs(data.from + that.lang.selected_file + "[ " + data.name + " ], "+that.lang.will_send);
- that.receiveFileRecoderList.push({
+ let fromId = data.from;
+ let { receiveFileMap = {} } = that.getRemoteInfo(fromId);
+ receiveFileMap[data.index] = Object.assign({
+ receivedBuffer : new Array(),
+ receivedSize : 0,
+ }, data);
+ that.setRemoteInfo(fromId, { receiveFileMap });
+
+ // 组装接收文件的recoder结构
+ const recoder = {
id: fromId,
nickName : data.nickName,
index: data.index,
@@ -3791,8 +3663,13 @@ axios.get("/api/comm/initData?turn="+useTurn, {}).then((initData) => {
done: false,
start: 0,
cost: 0,
- upload : 'wait'
- })
+ upload : 'wait',
+ indexedDb: that.canSaveToIndexedDb && that.useIndexedDb,
+ fragment : 0,
+ indexedDbInfoKey: Date.now() + "_" + data.index + "_info",
+ indexedDbBufferKey: Date.now() + "_" + data.index + "_buffer",
+ }
+ that.receiveFileRecoderList.push(recoder)
that.socket.emit("message", {
emitType : "sendFileInfoAck",
@@ -3801,6 +3678,10 @@ axios.get("/api/comm/initData?turn="+useTurn, {}).then((initData) => {
to: fromId, // 谁发过来的sendFileInfo事件就回执给谁
index: data.index, //具体的recoder记录文件的索引
})
+
+ if(that.canSaveToIndexedDb && that.useIndexedDb){
+ that.saveSliceFileInfoToIndexedDb(recoder);
+ }
});
//接收放已经收到待发送文件信息,代表可以进行发送了,
@@ -3984,217 +3865,1400 @@ axios.get("/api/comm/initData?turn="+useTurn, {}).then((initData) => {
that.setRemoteInfo(data.from, {
nickName : data.nickName
})
- that.addSysLogs(data.from + + that.lang.changeNickNameTo + " : " + data.nickName)
- });
-
- //提示
- this.socket.on('tips', function (data) {
- if (window.layer) {
- layer.msg(data.msg)
- if (data.reload) {
- setTimeout(() => {
- window.location.reload()
- }, 1300);
- }
- }
- });
+ that.addSysLogs(data.from + + that.lang.changeNickNameTo + " : " + data.nickName)
+ });
+
+ //提示
+ this.socket.on('tips', function (data) {
+ if (window.layer) {
+ layer.msg(data.msg)
+ if (data.reload) {
+ setTimeout(() => {
+ window.location.reload()
+ }, 1300);
+ }
+ }
+ });
+
+ //关闭共享
+ this.socket.on('stopScreenShare', function (data) {
+ if (data.id === that.socketId) {
+ that.clickMediaScreen();
+ } else {
+ $(`#otherMediaScreenShare${data.id}`).parent().remove();
+ }
+ });
+
+ //关闭共享
+ this.socket.on('openCamera', function (data) {
+ that.setRemoteInfo(data.from, {
+ isCameraEnabled : data.isCameraEnabled,
+ isAudioEnabled : data.isAudioEnabled
+ })
+ if(data.type === 'video'){
+ if(data.kind === 'video'){
+ document.querySelector(`#otherMediaVideoShare${data.from}`).style.display = data.isCameraEnabled ? 'block' : 'none';
+ document.querySelector(`#otherMediaVideoShareVideoSvg${data.from}`).style.display = data.isCameraEnabled ? 'none' : 'block';
+ }else if(data.kind === 'audio'){
+ document.querySelector(`#otherMediaVideoShareAudioOpenSvg${data.from}`).style.display = data.isAudioEnabled ? 'block' : 'none';
+ document.querySelector(`#otherMediaVideoShareAudioCloseSvg${data.from}`).style.display = data.isAudioEnabled ? 'none' : 'block';
+ }
+ }else if(data.type === 'screen'){
+ if(data.kind === 'video'){
+ document.querySelector(`#otherMediaScreenShare${data.from}`).style.display = data.isCameraEnabled ? 'block' : 'none';
+ document.querySelector(`#otherMediaScreenShareVideoSvg${data.from}`).style.display = data.isCameraEnabled ? 'none' : 'block';
+ }else if(data.kind === 'audio'){
+ document.querySelector(`#otherMediaScreenShareAudioOpenSvg${data.from}`).style.display = data.isAudioEnabled ? 'block' : 'none';
+ document.querySelector(`#otherMediaScreenShareAudioCloseSvg${data.from}`).style.display = data.isAudioEnabled ? 'none' : 'block';
+ }
+ }else if(data.type === 'live'){
+ if(data.kind === 'video'){
+ document.querySelector(`#otherMediaLiveShare${data.from}`).style.display = data.isCameraEnabled ? 'block' : 'none';
+ document.querySelector(`#otherMediaLiveShareVideoSvg${data.from}`).style.display = data.isCameraEnabled ? 'none' : 'block';
+ }else if(data.kind === 'audio'){
+ document.querySelector(`#otherMediaLiveShareAudioOpenSvg${data.from}`).style.display = data.isAudioEnabled ? 'block' : 'none';
+ document.querySelector(`#otherMediaLiveShareAudioCloseSvg${data.from}`).style.display = data.isAudioEnabled ? 'none' : 'block';
+ }
+ }else if(data.type === 'audio'){
+ if(data.kind === 'audio'){
+ document.querySelector(`#otherMediaAudioShareAudioOpenSvg${data.from}`).style.display = data.isAudioEnabled ? 'block' : 'none';
+ document.querySelector(`#otherMediaAudioShareAudioCloseSvg${data.from}`).style.display = data.isAudioEnabled ? 'none' : 'block';
+
+ document.querySelector(`#otherMediaAudioShareAudioOpenAnimSvg${data.from}`).style.display = data.isAudioEnabled ? 'block' : 'none';
+ document.querySelector(`#otherMediaAudioShareAudioCloseAnimSvg${data.from}`).style.display = data.isAudioEnabled ? 'none' : 'block';
+ }
+ }
+ });
+
+ //关闭音视频
+ this.socket.on('stopVideoShare', function (data) {
+ if (data.id === that.socketId) {
+ that.clickMediaVideo();
+ } else {
+ $(`#otherMediaVideoShare${data.id}`).parent().remove();
+ }
+ });
+
+ //退出直播
+ this.socket.on('stopLiveShare', function (data) {
+ //如果是主动房主退出,所有观众都退出
+ if(data.owner){
+ window.location.reload();
+ return
+ }
+
+ if (data.id === that.socketId) {
+ that.clickMediaLive();
+ }
+ });
+
+ //退出语音连麦
+ this.socket.on('stopAudioShare', function (data) {
+ if (data.id === that.socketId) {
+ that.clickMediaAudio();
+ } else {
+ $(`#otherMediaAudioShare${data.id}`).parent().remove();
+ }
+ });
+
+ //ai对话
+ this.socket.on('openaiAnswer', function (data) {
+ that.isAiAnswering = false
+ that.receiveAiChatList.push(data)
+ that.addSysLogs("AI : " + data.content)
+ that.addPopup({
+ title : that.lang.ai_reply,
+ msg : that.lang.ai_reply_you
+ });
+ that.receiveAiChatList.forEach(item => {
+ item.timeAgo = window.util ? util.timeAgo(item.time) : item.time;
+ })
+ that.openaiChatTpl()
+ });
+
+ //开关数据
+ this.socket.on('commData', function (data) {
+ that.switchData = data.switchData;
+ that.switchDataGet = true;
+ if(data.switchData.noticeMsgList){
+ let alert = window.localStorage.getItem("tl-rtc-file-alert-notice")
+ if(!alert || (Date.now() - parseInt(alert)) / 1000 > (24 * 60 * 60) ){
+ setTimeout(() => {
+ that.clickNotice()
+ window.localStorage.setItem("tl-rtc-file-alert-notice", Date.now())
+ }, 1000);
+ }
+ }
+
+ if(data.chatingCommData){
+ data.chatingCommData.forEach(elem => {
+ try {
+ elem.msg = tlrtcfile.unescapeStr(elem.msg)
+ } catch (e) {
+ that.addSysLogs(that.lang.text_decode_failed + elem.msg);
+ }
+ that.receiveChatCommList.push(elem)
+ })
+ that.receiveChatCommList.forEach(item => {
+ item.timeAgo = window.util ? util.timeAgo(item.time) : item.time;
+ })
+ }
+ });
+
+ //公共聊天频道
+ this.socket.on('chatingComm', function (data) {
+ that.addSysLogs(data.room + ":" + data.socketId + that.lang.send_text + ": [ " + data.msg + " ]");
+ try {
+ data.msg = tlrtcfile.unescapeStr(data.msg)
+ } catch (e) {
+ that.addSysLogs(that.lang.text_decode_failed + data.msg);
+ }
+ that.receiveChatCommList.push(data);
+ if (that.receiveChatCommList.length > that.switchData.chatingCommCount) {
+ that.receiveChatCommList.shift();
+ }
+ that.receiveChatCommList.forEach(item => {
+ item.timeAgo = window.util ? util.timeAgo(item.time) : item.time;
+ })
+ that.chatingCommTpl()
+
+ that.addPopup({
+ title : that.lang.chat_comm,
+ msg : that.lang.public_chat_channel_someone_interact
+ });
+ });
+
+ this.socket.on('manageCheck', function (data) {
+ layer.prompt({
+ formType: 1,
+ title: that.lang.please_enter,
+ }, function (value, index, elem) {
+ that.socket.emit('manageConfirm', {
+ room: that.roomId,
+ value: value
+ });
+ layer.close(index)
+ });
+ });
+
+ this.socket.on('manage', function (data) {
+ if (data.socketId !== that.socketId) {
+ layer.msg(that.lang.illegal_event)
+ return
+ }
+ layer.closeAll();
+ that.token = data.token;
+ layer.load(2, {
+ time: 1000,
+ shade: [0.8, '#000000'],
+ success: function (layero) {
+ layer.setTop(layero); //重点2
+ }
+ })
+ setTimeout(() => {
+ that.manageIframeId = layer.tab({
+ area: ['100%', '100%'],
+ shade: [0.8, '#393D49'],
+ closeBtn : 0,
+ tab: [{
+ title: data.content[0].title,
+ content: data.content[0].html
+ }, {
+ title: data.content[1].title,
+ content: data.content[1].html
+ }, {
+ title: data.content[2].title,
+ content: data.content[2].html
+ }],
+ cancel: function (index, layero) {
+ that.manageIframeId = 0;
+ },
+ })
+ layer.full(that.manageIframeId)
+ }, 500);
+ });
+ },
+ // 打开设置
+ setting: function () {
+ let that = this;
+ let options = {
+ type: 1,
+ fixed: false,
+ maxmin: false,
+ shadeClose: true,
+ area: ['320px', '390px'],
+ title: this.lang.setting,
+ success: function (layero, index) {
+ document.querySelector(".layui-layer-title").style.borderTopRightRadius = "15px"
+ document.querySelector(".layui-layer-title").style.borderTopLeftRadius = "15px"
+ document.querySelector(".layui-layer").style.borderRadius = "15px"
+ document.querySelector(".layui-layer-content").style.borderRadius = "15px"
+ window.form.render()
+
+ carousel.render({
+ elem: '#tl-rtc-file-setting-info',
+ width: '100%',
+ autoplay : false,
+ indicator: 'inside'
+ });
+
+ //文件分片大小自定义
+ let chunkSizeSliderDivObj = slider.render({
+ elem: '#tl-rtc-file-chunk-size',
+ min: 16,
+ max: 64,
+ change: function (value) {
+ that.chunkSize = value * 1024;
+ document.getElementById("tl-rtc-file-chunk-size-txt").innerText = value + "KB";
+ }
+ });
+ chunkSizeSliderDivObj.setValue((that.chunkSize / 1024) - 16);
+
+ //文件预览大小自定义
+ let previewSizeSliderDivObj = slider.render({
+ elem: '#tl-rtc-file-preview-size',
+ min: 5,
+ max: 15,
+ change: function (value) {
+ that.previewFileMaxSize = value * 1024 * 1024;
+ document.getElementById("tl-rtc-file-preview-size-txt").innerText = value + "MB";
+ }
+ });
+ previewSizeSliderDivObj.setValue((that.previewFileMaxSize / 1024 / 1024) - 5);
+
+ //执行日志大小自定义
+ let logSizeSliderDivObj = slider.render({
+ elem: '#tl-rtc-file-log-size',
+ min: 300,
+ max: 800,
+ change: function (value) {
+ that.maxLogCount = value;
+ document.getElementById("tl-rtc-file-log-size-txt").innerText = value + "条";
+ }
+ });
+ logSizeSliderDivObj.setValue(that.maxLogCount - 300);
+
+ document.getElementById("rtcCheck").addEventListener('click',function(){
+ that.webrtcCheck();
+ })
+
+ document.getElementById("customWsHost").addEventListener('click', function(){
+ that.customWsHost();
+ })
+
+ document.getElementById("relaySetting").addEventListener('click', function(){
+ that.relaySetting();
+ })
+
+ document.getElementById("sendBugs").addEventListener('click', function(){
+ that.sendBugs();
+ })
+
+ document.getElementById("aiContext").addEventListener('click', function(){
+ that.sendOpenaiChatWithContext();
+ })
+
+ document.getElementById("fileSave").addEventListener('click', function(){
+ that.savaFileToIndexedDb();
+ })
+
+ document.getElementById("systemLog").addEventListener('click', function(){
+ layer.closeAll(function(){
+ that.clickLogs();
+ })
+ })
+
+ document.getElementById("closeLogs").addEventListener('click', function(){
+ that.closeLogs();
+ })
+
+ document.getElementById("coffee").addEventListener('click', function(){
+ that.coffee();
+ })
+
+ document.getElementById("messageDot").addEventListener('click', function(){
+ that.messageDot();
+ })
+
+ document.getElementById("fixedRoom").addEventListener('click', function(){
+ that.fixedRoom();
+ })
+
+ document.getElementById("localNetworkRoomShare").addEventListener('click', function(){
+ that.localNetworkRoomShare();
+ })
+
+ document.getElementById("settingBasicHelp").addEventListener('click', function(){
+ that.settingHelp();
+ })
+
+ document.getElementById("settingSwitchHelp").addEventListener('click', function(){
+ that.settingHelp();
+ })
+
+ document.getElementById("fileTransferSettingHelp").addEventListener('click', function(){
+ that.settingHelp();
+ })
+ },
+ content: `
+
+
+
+
+
+
+
+
+ tl-rtc-file ${this.version} ${this.lang.file_transfer_setting}
+
+
+
+
+
+
${this.lang.file_fragment_size}:
+
+
+
+
+
+
+
+
${this.lang.preview_limit_size}:
+
+
+
+
+
+
+
+
${this.lang.output_log_limit}:
+
+
+
+
+
+
+ `
+ }
+ layer.closeAll(function () {
+ layer.open(options)
+ })
+ this.addUserLogs(this.lang.open_setting)
+ },
+ // 设置文档
+ settingHelp : function(){
+ layer.open({
+ type: 2
+ , title: false
+ , closeBtn: false
+ , area: ['80%','80%']
+ , shade: 0.5
+ , shadeClose : true
+ , id: 'layui-info-msg'
+ , content: 'document/SETTING.html'
+ });
+ },
+ // 自动加入固定房间号
+ autoJoinFixedRoom: function () {
+ if(!this.useFixedRoom){
+ return
+ }
+
+ this.roomId = this.useFixedRoom;
+ this.createFileRoom();
+ this.createFileRoom();
+
+ layer.msg(this.lang.auto_join_fixed_room + ": " + this.useFixedRoom)
+ },
+
+ // 是否关闭日志输出
+ closeLogs: function(){
+ this.isCloseLogs = !this.isCloseLogs;
+
+ if (this.isCloseLogs) {
+ layer.msg(`${this.lang.logs_switch}${this.lang.on}`)
+ $("#closeLogsOpen").css("display", "inline");
+ $("#closeLogsClose").css("display", "none");
+ } else {
+ layer.msg(`${this.lang.logs_switch}${this.lang.off}`)
+ $("#closeLogsOpen").css("display", "none");
+ $("#closeLogsClose").css("display", "inline");
+ }
+
+ $("#closeLogs").removeClass("layui-anim-rotate")
+ setTimeout(() => {
+ $("#closeLogs").addClass("layui-anim-rotate")
+ }, 50)
+ },
+ // ai对话上下文开关
+ sendOpenaiChatWithContext : function(){
+ this.openaiSendContext = !this.openaiSendContext;
+
+ if(this.openaiSendContext){
+ $("#aiContextOpen").css("display", "inline");
+ $("#aiContextClose").css("display", "none");
+ }else{
+ $("#aiContextOpen").css("display", "none");
+ $("#aiContextClose").css("display", "inline");
+ }
+
+ layer.msg(`${this.lang.ai_switch}${this.openaiSendContext ? this.lang.on : this.lang.off}`)
+
+ this.addUserLogs(`${this.lang.ai_switch}${this.openaiSendContext ? this.lang.on : this.lang.off}`)
+
+ $("#aiContext").removeClass("layui-anim-rotate")
+ setTimeout(() => {
+ $("#aiContext").addClass("layui-anim-rotate")
+ }, 50)
+ },
+ // 是否关闭消息红点提示
+ messageDot : function(){
+ if (this.useMessageDot) {
+ window.localStorage.setItem("tl-rtc-file-use-message-dot", false)
+ layer.msg(`${this.lang.messgae_dot_switch}${this.lang.off}`)
+ $("#messageDotOpen").css("display", "none");
+ $("#messageDotClose").css("display", "inline");
+ } else {
+ window.localStorage.setItem("tl-rtc-file-use-message-dot", true)
+ layer.msg(`${this.lang.messgae_dot_switch}${this.lang.on}`)
+ $("#messageDotOpen").css("display", "inline");
+ $("#messageDotClose").css("display", "none");
+ }
+
+ this.useMessageDot = !this.useMessageDot;
+
+ $("#messageDot").removeClass("layui-anim-rotate")
+ setTimeout(() => {
+ $("#messageDot").addClass("layui-anim-rotate")
+ }, 50)
+ },
+ // 是否开启局域网房间分享
+ localNetworkRoomShare : function(){
+ if(this.useLocalNetworkRoomShare){
+ window.localStorage.setItem("tl-rtc-file-use-local-network-room-share", false)
+ layer.msg(`${this.lang.local_network_room_share}${this.lang.off}`)
+ $("#localNetworkRoomShareOpen").css("display", "none");
+ $("#localNetworkRoomShareClose").css("display", "inline");
+ }else{
+ window.localStorage.setItem("tl-rtc-file-use-local-network-room-share", true)
+ layer.msg(`${this.lang.local_network_room_share}${this.lang.on}`)
+ $("#localNetworkRoomShareOpen").css("display", "inline");
+ $("#localNetworkRoomShareClose").css("display", "none");
+ }
+
+ this.useLocalNetworkRoomShare = !this.useLocalNetworkRoomShare;
+
+ $("#localNetworkRoomShare").removeClass("layui-anim-rotate")
+ setTimeout(() => {
+ $("#localNetworkRoomShare").addClass("layui-anim-rotate")
+ }, 50)
+ },
+ // 是否使用自自定义持久化房间号
+ fixedRoom : function(){
+ let that = this;
+ if(this.useFixedRoom){
+ window.localStorage.removeItem("tl-rtc-file-use-fixed-room")
+ layer.msg(`${this.lang.fixed_room}${this.lang.off}`)
+
+ $("#fixedRoomOpen").css("display", "none");
+ $("#fixedRoomClose").css("display", "inline");
+
+ setTimeout(() => {
+ window.location.reload()
+ }, 500);
+ }else{
+ layer.prompt({
+ formType: 0,
+ value: '',
+ title: that.lang.fixed_room,
+ }, function (value, index, elem) {
+ if (!that.switchData.allowChinese && window.tlrtcfile.containChinese(value)) {
+ layer.msg(that.lang.room_num_no_zh)
+ return
+ }
+ if (!that.switchData.allowNumber && window.tlrtcfile.containNumber(value)) {
+ layer.msg(that.lang.room_num_no_number)
+ return
+ }
+ if (!that.switchData.allowSymbol && window.tlrtcfile.containSymbol(value)) {
+ layer.msg(that.lang.room_num_no_special_symbols)
+ return
+ }
+
+ console.log(that.switchData, value, window.tlrtcfile.containSymbol(value))
+
+ layer.close(index);
+
+ window.localStorage.setItem("tl-rtc-file-use-fixed-room", value)
+ layer.msg(`${that.lang.fixed_room}${that.lang.on}`)
+
+ $("#fixedRoomOpen").css("display", "inline");
+ $("#fixedRoomClose").css("display", "none");
+
+ setTimeout(() => {
+ window.location.reload()
+ }, 500);
+ });
+ }
+
+ $("#fixedRoom").removeClass("layui-anim-rotate")
+ setTimeout(() => {
+ $("#fixedRoom").addClass("layui-anim-rotate")
+ }, 50)
+ },
+ // 开启文件持久化到indexedDb中
+ savaFileToIndexedDb: function(){
+ if(!this.canSaveToIndexedDb){
+ layer.msg(this.lang.not_support)
+ return
+ }
+
+ if (this.useIndexedDb) {
+ window.localStorage.setItem("tl-rtc-file-receive-file-use-indexed-db", false)
+ layer.msg(`${this.lang.save_file_to_indexeddb}${this.lang.off}`)
+ $("#fileSaveOpen").css("display", "none");
+ $("#fileSaveClose").css("display", "inline");
+ } else {
+ window.localStorage.setItem("tl-rtc-file-receive-file-use-indexed-db", true)
+ layer.msg(`${this.lang.save_file_to_indexeddb}${this.lang.on}`)
+ $("#fileSaveOpen").css("display", "inline");
+ $("#fileSaveClose").css("display", "none");
+ }
+
+ this.useIndexedDb = !this.useIndexedDb;
+
+ $("#fileSave").removeClass("layui-anim-rotate")
+ setTimeout(() => {
+ $("#fileSave").addClass("layui-anim-rotate")
+ }, 50)
+ },
+ // 自定义ws地址
+ customWsHost: function () {
+ let that = this;
+ if(window.localStorage.getItem("tl-rtc-file-custom-ws-host")){
+ window.localStorage.removeItem("tl-rtc-file-custom-ws-host")
+ layer.msg(that.lang.close_custom_ws_url)
+ setTimeout(() => {
+ window.location.reload()
+ }, 500);
+ }else{
+ layer.prompt({
+ formType: 0,
+ value: 'wss://',
+ title: that.lang.input_custom_ws_url,
+ }, function (value, index, elem) {
+ if(!/^wss?:\/\/[^\s/$.?#].[^\s]*$/.test(value)){
+ layer.msg(that.lang.ws_url_error)
+ return
+ }
+
+ layer.close(index);
+
+ window.localStorage.setItem("tl-rtc-file-custom-ws-host", value)
+ layer.msg(that.lang.open_custom_ws_url)
+ setTimeout(() => {
+ window.location.reload()
+ }, 500);
+ });
+ }
+ $("#customWsHost").removeClass("layui-anim-rotate")
+ setTimeout(() => {
+ $("#customWsHost").addClass("layui-anim-rotate")
+ }, 50)
+ },
+ // 打开中继设置面板
+ relaySetting: function () {
+ if (this.useTurn) {
+ window.localStorage.setItem("tl-rtc-file-use-relay", false)
+ layer.msg(`${this.lang.relay_server_current}${this.lang.off}`)
+ $("#relaySettingOpen").css("display", "none");
+ $("#relaySettingClose").css("display", "inline");
+ } else {
+ window.localStorage.setItem("tl-rtc-file-use-relay", true)
+ layer.msg(`${this.lang.relay_server_current}${this.lang.on}`)
+ $("#relaySettingOpen").css("display", "none");
+ $("#relaySettingClose").css("display", "inline");
+ }
+
+ $("#relaySetting").removeClass("layui-anim-rotate")
+ setTimeout(() => {
+ $("#relaySetting").addClass("layui-anim-rotate")
+ }, 50)
+
+ setTimeout(() => {
+ window.location.reload()
+ }, 300);
+ },
+ // 中继信息提示
+ useTurnMsg: function () {
+ layer.msg(this.lang.relay_on)
+ this.addUserLogs(this.lang.relay_on)
+ },
+ // 当前网络状态
+ networkMsg: function () {
+ layer.msg(this.lang.current_network + (this.network !== 'wifi' ? this.lang.mobile_data : this.network))
+ this.addUserLogs(this.lang.current_network + (this.network !== 'wifi' ? this.lang.mobile_data : this.network))
+ },
+ // 添加弹窗
+ addPopup: function (msg) {
+ this.popUpList.push({
+ title : msg.title,
+ message : msg.msg
+ })
+ },
+ // 记录系统日志
+ addSysLogs: function (msg) {
+ this.addLogs(msg, "【"+this.lang.sys_log+"】: ")
+ },
+ // 记录用户操作日志
+ addUserLogs: function (msg) {
+ this.addLogs(msg, "【"+this.lang.op_log+"】: ")
+ },
+ // 记录日志
+ addLogs: function (msg, type) {
+ if(this.isCloseLogs){
+ return
+ }
+ if (this.logs.length > this.maxLogCount) {
+ this.logs.shift();
+ }
+ this.logs.unshift({
+ type: type,
+ msg: msg,
+ time: new Date().toLocaleString()
+ })
+ },
+ // 清空日志
+ cleanLogs: function () {
+ this.logs = []
+ this.addSysLogs(this.lang.clear_log)
+ },
+ // 发送建议反馈
+ sendBugs: function () {
+ let that = this;
+ $("#sendBugs").removeClass("layui-anim-rotate")
+ setTimeout(() => {
+ $("#sendBugs").addClass("layui-anim-rotate")
+ }, 50)
+
+ that.roomId = "tlrtcfile问题反馈";
+ that.roomType = "system";
+ that.createFileRoom();
+ that.createFileRoom();
+
+ setTimeout(() => {
+ layer.closeAll(async function(){
+ that.openChatingRoom();
+ let index = layer.load(2);
+ await that.loadSystemRoomMsg();
+ layer.close(index);
+ });
+ that.addUserLogs(that.lang.send_bug_info_ok);
+ }, 500);
+ },
+ // 随机刷新房间号
+ refleshRoom: function () {
+ if (!this.isJoined) {
+ this.roomId = parseInt(Math.random() * 100000);
+ this.addPopup({
+ title : this.lang.refresh_room,
+ msg : this.lang.you_refresh_room + this.roomId
+ });
+ this.addUserLogs(this.lang.you_refresh_room + this.roomId);
+ }
+ },
+ // 复制分享房间url
+ shareUrl: function () {
+ let that = this;
+ layer.closeAll(function () {
+ layer.open({
+ type: 1,
+ closeBtn: 0,
+ fixed: true,
+ maxmin: false,
+ shadeClose: true,
+ area: ['350px', '380px'],
+ title: that.lang.share_join_room,
+ success: function (layero, index) {
+ let shareArgs = {
+ r : that.roomId,
+ t : that.roomType
+ };
+ if(that.roomType === 'live'){
+ shareArgs.lsm = that.liveShareMode;
+ shareArgs.lsr = 'viewer';
+ }
+ let content = window.tlrtcfile.addUrlHashParams(shareArgs);
+ document.querySelector(".layui-layer-title").style.borderTopRightRadius = "8px";
+ document.querySelector(".layui-layer-title").style.borderTopLeftRadius = "8px";
+ document.querySelector(".layui-layer").style.borderRadius = "8px";
+ if(window.tlrtcfile.getQrCode){
+ tlrtcfile.getQrCode("tl-rtc-file-room-share-image", content)
+ }
+
+ document.querySelector("#shareUrl").setAttribute("data-clipboard-text", content);
+ let clipboard = new ClipboardJS('#shareUrl');
+ clipboard.on('success', function (e) {
+ e.clearSelection();
+ setTimeout(() => {
+ layer.msg(that.lang.copy_room_link)
+ }, 500);
+ });
+ that.addUserLogs(that.lang.copy_room_link);
+ },
+ content: `
+
+
${that.lang.share_join_room_done}
+
+
+
+
+ `
+ })
+ })
+ this.addUserLogs(this.lang.open_share_join_room)
+ },
+ // 获取分享的取件码文件
+ handlerGetCodeFile: function () {
+ let that = this;
+ let hash = window.location.hash || "";
+ if (hash && hash.includes("#")) {
+ let codeIdArgs = hash.split("c=");
+ if (codeIdArgs && codeIdArgs.length > 1) {
+ this.codeId = (codeIdArgs[1] + "").replace(/\s*/g, "").substring(0, 40);
+ layer.confirm(this.lang.is_pickup_code, (index) => {
+ window.location.hash = "";
+ layer.close(index)
+ that.getCodeFile();
+ }, (index) => {
+ that.codeId = "";
+ window.location.hash = "";
+ layer.close(index)
+ })
+ this.addPopup({
+ title : this.lang.share_pickup_code_file,
+ msg : this.lang.get_pickup_file + this.codeId
+ });
+ this.addUserLogs(this.lang.get_pickup_file + this.codeId);
+ }
+ }
+ },
+ // 分享进入房间
+ handlerJoinShareRoom: function () {
+ let that = this;
+
+ //如果已经使用固定房间号,跳过分享进入逻辑
+ if(this.useFixedRoom){
+ return
+ }
+
+ let hash = window.location.hash || "";
+ if (!hash || !hash.includes("#") || !hash.includes("r=")) {
+ return
+ }
+
+ if (!window.layer) {
+ return
+ }
+
+ //房间号
+ let roomIdArgs = tlrtcfile.getRequestHashArgs("r");
+ if (!roomIdArgs) {
+ return
+ }
+ this.roomId = (roomIdArgs + "").replace(/\s*/g, "").substring(0, 15);
+
+ //房间类型
+ let typeArgs = tlrtcfile.getRequestHashArgs("t");
+
+ layer.confirm(this.lang.join_room + this.roomId, (index) => {
+ window.location.hash = "";
+ layer.close(index)
+ that.openRoomInput = true;
+ that.isShareJoin = true;
+ if(typeArgs && ['screen','live','video','audio'].includes(typeArgs)){
+ if(typeArgs === 'screen'){
+ that.startScreenShare();
+ }else if(typeArgs === 'live'){
+ //直播房间模式
+ let lsm = tlrtcfile.getRequestHashArgs("lsm");
+ if(['video', 'live', ''].includes(lsm)){
+ that.liveShareMode = lsm;
+ }
+ //直播房间身份
+ let lsr = tlrtcfile.getRequestHashArgs("lsr");
+ if(['owner', 'viewer'].includes(lsr)){
+ that.liveShareRole = lsr;
+ }
+ that.startLiveShare();
+ }else if(typeArgs === 'video'){
+ that.startVideoShare();
+ }else if(typeArgs === 'audio'){
+ that.startAudioShare();
+ }
+ }else{
+ that.createFileRoom();
+ }
+ }, (index) => {
+ that.roomId = "";
+ window.location.hash = "";
+ layer.close(index)
+ })
+ this.addPopup({
+ title : this.lang.share_join_room,
+ msg : this.lang.you_join_room + this.roomId
+ });
+ this.addUserLogs(this.lang.you_join_room + this.roomId);
+ },
+ // 赞助面板
+ coffee: function () {
+ let options = {
+ type: 1,
+ fixed: false,
+ maxmin: false,
+ shadeClose: true,
+ area: ['300px', '350px'],
+ title: this.lang.donate,
+ success: function (layero, index) {
+ document.querySelector(".layui-layer-title").style.borderTopRightRadius = "8px";
+ document.querySelector(".layui-layer-title").style.borderTopLeftRadius = "8px";
+ document.querySelector(".layui-layer").style.borderRadius = "8px";
+ },
+ content: `
![img](/image/coffee.jpeg)
`
+ }
+ layer.closeAll(function () {
+ layer.open(options)
+ })
+ this.addUserLogs(this.lang.open_donate)
+ },
+ //点击局域网房间列表
+ clickLocalNetRooms : function(hidden){
+ if(this.localNetRoomList.length === 0 && !hidden){
+ layer.msg(this.lang.no_local_network_room)
+ return
+ }
+
+ this.showLocalNetRoom = !this.showLocalNetRoom;
+ if (this.showLocalNetRoom) {
+ this.addUserLogs(this.lang.expand_local_network_room);
+ this.localNetRoomMaskHeightNum = 20;
+ } else {
+ this.localNetRoomMaskHeightNum = 150;
+ this.addUserLogs(this.lang.collapse_local_network_room);
+ }
+ },
+ //点击下载文件面板
+ clickReceiveFile: function (hidden) {
+ if(this.receiveFileRecoderList.length === 0 && !hidden){
+ layer.msg(this.lang.no_received_file)
+ return
+ }
+ this.showReceiveFile = !this.showReceiveFile;
+ if (this.showReceiveFile) {
+ this.addUserLogs(this.lang.expand_receive_file);
+ this.receiveFileMaskHeightNum = 20;
+ } else {
+ this.receiveFileMaskHeightNum = 150;
+ this.addUserLogs(this.lang.collapse_receive_file);
+ }
+ },
+ //点击已选文件面板
+ clickChooseFile: function () {
+ if(!this.hasManInRoom && !this.showChooseFile){
+ layer.msg(this.lang.room_least_two_can_send_content)
+ return
+ }
+ this.showChooseFile = !this.showChooseFile;
+ if (this.showChooseFile) {
+ this.chooseFileMaskHeightNum = 20;
+ this.addUserLogs(this.lang.expand_selected_file);
+ } else {
+ this.chooseFileMaskHeightNum = 150;
+ this.addUserLogs(this.lang.collapse_selected_file);
+ }
+ },
+ //点击待发送文件面板
+ clickSendFile: function () {
+ if(!this.hasManInRoom && !this.showSendFile){
+ layer.msg(this.lang.room_least_two_can_send_content)
+ return
+ }
+ this.showSendFile = !this.showSendFile;
+ if (this.showSendFile) {
+ this.sendFileMaskHeightNum = 20;
+ this.addUserLogs(this.lang.expand_wait_send_file);
+ } else {
+ this.sendFileMaskHeightNum = 150;
+ this.addUserLogs(this.lang.collapse_wait_send_file);
+ }
+ },
+ //点击发送文件历史记录面板
+ clickSendFileHistory: function () {
+ if(this.sendFileRecoderHistoryList.length === 0){
+ layer.msg(this.lang.no_send_file)
+ return
+ }
+ this.showSendFileHistory = !this.showSendFileHistory;
+ if (this.showSendFileHistory) {
+ this.sendFileHistoryMaskHeightNum = 20;
+ this.addUserLogs(this.lang.expand_send_file_record);
+ } else {
+ this.sendFileHistoryMaskHeightNum = 150;
+ this.addUserLogs(this.lang.collapse_send_file_record);
+ }
+ },
+ //点击查看日志面板
+ clickLogs: function (e) {
+ this.showLogs = !this.showLogs;
+ this.touchResize();
+ if (this.showLogs) {
+ this.addUserLogs(this.lang.expand_log);
+ this.logMaskHeightNum = 0;
+ } else {
+ this.addUserLogs(this.lang.collapse_log);
+ this.logMaskHeightNum = -150;
+ }
+ },
+ //点击打开音视频面板
+ clickMediaVideo: function () {
+ this.showMedia = !this.showMedia;
+ this.touchResize();
+ if (this.showMedia) {
+ this.addUserLogs(this.lang.expand_video);
+ this.mediaVideoMaskHeightNum = 0;
+ if(this.clientWidth < 500){
+ document.getElementById("iamtsm").style.marginLeft = '0';
+ }else{
+ document.getElementById("iamtsm").style.marginLeft = "50%";
+ }
+ } else {
+ this.addUserLogs(this.lang.collapse_video);
+ this.mediaVideoMaskHeightNum = -150;
+ document.getElementById("iamtsm").style.marginLeft = "0";
+ }
+ },
+ //点击打开屏幕共享面板
+ clickMediaScreen: function () {
+ this.showMedia = !this.showMedia;
+ this.touchResize();
+ if (this.showMedia) {
+ this.addUserLogs(this.lang.expand_screen_sharing);
+ this.mediaScreenMaskHeightNum = 0;
+ if(this.clientWidth < 500){
+ document.getElementById("iamtsm").style.marginLeft = "0";
+ }else{
+ document.getElementById("iamtsm").style.marginLeft = "50%";
+ }
+ } else {
+ this.addUserLogs(this.lang.collapse_screen_sharing);
+ this.mediaScreenMaskHeightNum = -150;
+ document.getElementById("iamtsm").style.marginLeft = "0";
+ }
+ },
+ //点击打开直播面板
+ clickMediaLive: function () {
+ this.showMedia = !this.showMedia;
+ this.touchResize();
+ if (this.showMedia) {
+ this.addUserLogs(this.lang.expand_live);
+ if(this.clientWidth < 500){
+ document.getElementById("iamtsm").style.marginLeft = "0";
+ }else{
+ document.getElementById("iamtsm").style.marginLeft = "50%";
+ }
+ this.mediaLiveMaskHeightNum = 0;
+ } else {
+ this.addUserLogs(this.lang.collapse_live);
+ this.mediaLiveMaskHeightNum = -150;
+ document.getElementById("iamtsm").style.marginLeft = "0";
+ }
+ },
+ clickMediaAudio : function(){
+ this.showMedia = !this.showMedia;
+ this.touchResize();
+ if (this.showMedia) {
+ this.addUserLogs(this.lang.expand_audio);
+ if(this.clientWidth < 500){
+ document.getElementById("iamtsm").style.marginLeft = "0";
+ }else{
+ document.getElementById("iamtsm").style.marginLeft = "50%";
+ }
+ this.mediaAudioMaskHeightNum = 0;
+ } else {
+ this.addUserLogs(this.lang.collapse_audio);
+ this.mediaAudioMaskHeightNum = -150;
+ document.getElementById("iamtsm").style.marginLeft = "0";
+ }
+ },
+ typeInArr: function(arr, type, name = ""){
+ if(type === ''){
+ let fileTail = name.split(".").pop()
+ return arr.filter(item=>{
+ return fileTail.toLowerCase().includes(item) && name.endsWith("."+fileTail);
+ }).length > 0;
+ }else{
+ return arr.filter(item=>{
+ return type.toLowerCase().includes(item);
+ }).length > 0;
+ }
+ },
+ //文件大小
+ getFileSizeStr: function (size) {
+ let sizeStr = (size / 1048576).toString();
+ let head = sizeStr.split(".")[0];
+ let tail = "";
+ if (sizeStr.split(".")[1]) {
+ tail = sizeStr.split(".")[1].substring(0, 3);
+ }
+ if(head === '0') {
+ return "0M";
+ }
+ return head + '.' + tail + "M";
+ },
+ // indexedDb缓存keys
+ getIndexedDbFileBufferKeyList : function(recoder){
+ let keyList = [];
+ for(let i = 0; i < recoder.fragment; i += 1000){
+ keyList.push(recoder.indexedDbBufferKey + i);
+ }
+ if(recoder.fragment % 1000 > 0){
+ keyList.push(recoder.indexedDbBufferKey + recoder.fragment);
+ }
+ return keyList;
+ },
+ // 预览indexedDb中的文件
+ previewIndexedDbFile : async function(recoder){
+ let that = this;
+ const keyList = this.getIndexedDbFileBufferKeyList(recoder);
+ const allBuffer = new Array();
+ for(let i = 0; i < keyList.length; i++){
+ //从磁盘加载完,自动下载
+ await new Promise((resolve, reject) => {
+ localforage.getItem(keyList[i]).then(function(value) {
+ if(!value){
+ layer.msg(that.lang.indexedDB_file_alreay_delete)
+ setTimeout(() => {
+ that.deleteIndexedDbFile(recoder);
+ }, 300);
+ reject(null)
+ }else{
+ value.forEach(item=>{
+ allBuffer.push(item);
+ })
+ resolve(0)
+ }
+ }).catch(function(err) {
+ console.log("previewIndexedDbFile err ",err);
+ reject(err);
+ });
+ })
+ }
+ await this.previewFile(new File(allBuffer, recoder.name, { type: recoder.type }));
+ },
+ // 从indexedDb下载文件
+ downloadIndexedDbFile : async function(recoder){
+ let that = this;
- //关闭共享
- this.socket.on('stopScreenShare', function (data) {
- if (data.id === that.socketId) {
- that.clickMediaScreen();
- } else {
- $(`#otherMediaScreenShare${data.id}`).parent().remove();
- }
- });
+ if(!this.canSaveToIndexedDb){
+ return
+ }
- //关闭共享
- this.socket.on('openCamera', function (data) {
- that.setRemoteInfo(data.from, {
- isCameraEnabled : data.isCameraEnabled,
- isAudioEnabled : data.isAudioEnabled
+ const keyList = this.getIndexedDbFileBufferKeyList(recoder);
+ const allBuffer = new Array();
+ for(let i = 0; i < keyList.length; i++){
+ //从磁盘加载完,自动下载
+ await new Promise((resolve, reject) => {
+ localforage.getItem(keyList[i]).then(function(value) {
+ if(!value){
+ layer.msg(that.lang.indexedDB_file_alreay_delete)
+ setTimeout(() => {
+ that.deleteIndexedDbFile(recoder);
+ }, 300);
+ reject(null)
+ }else{
+ value.forEach(item=>{
+ allBuffer.push(item);
+ })
+ }
+ resolve(0)
+ }).catch(function(err) {
+ console.log("downloadIndexedDbFileInfo err ",err);
+ reject(null);
+ });
})
- if(data.type === 'video'){
- if(data.kind === 'video'){
- document.querySelector(`#otherMediaVideoShare${data.from}`).style.display = data.isCameraEnabled ? 'block' : 'none';
- document.querySelector(`#otherMediaVideoShareVideoSvg${data.from}`).style.display = data.isCameraEnabled ? 'none' : 'block';
- }else if(data.kind === 'audio'){
- document.querySelector(`#otherMediaVideoShareAudioOpenSvg${data.from}`).style.display = data.isAudioEnabled ? 'block' : 'none';
- document.querySelector(`#otherMediaVideoShareAudioCloseSvg${data.from}`).style.display = data.isAudioEnabled ? 'none' : 'block';
- }
- }else if(data.type === 'screen'){
- if(data.kind === 'video'){
- document.querySelector(`#otherMediaScreenShare${data.from}`).style.display = data.isCameraEnabled ? 'block' : 'none';
- document.querySelector(`#otherMediaScreenShareVideoSvg${data.from}`).style.display = data.isCameraEnabled ? 'none' : 'block';
- }else if(data.kind === 'audio'){
- document.querySelector(`#otherMediaScreenShareAudioOpenSvg${data.from}`).style.display = data.isAudioEnabled ? 'block' : 'none';
- document.querySelector(`#otherMediaScreenShareAudioCloseSvg${data.from}`).style.display = data.isAudioEnabled ? 'none' : 'block';
- }
- }else if(data.type === 'live'){
- if(data.kind === 'video'){
- document.querySelector(`#otherMediaLiveShare${data.from}`).style.display = data.isCameraEnabled ? 'block' : 'none';
- document.querySelector(`#otherMediaLiveShareVideoSvg${data.from}`).style.display = data.isCameraEnabled ? 'none' : 'block';
- }else if(data.kind === 'audio'){
- document.querySelector(`#otherMediaLiveShareAudioOpenSvg${data.from}`).style.display = data.isAudioEnabled ? 'block' : 'none';
- document.querySelector(`#otherMediaLiveShareAudioCloseSvg${data.from}`).style.display = data.isAudioEnabled ? 'none' : 'block';
- }
- }else if(data.type === 'audio'){
- if(data.kind === 'audio'){
- document.querySelector(`#otherMediaAudioShareAudioOpenSvg${data.from}`).style.display = data.isAudioEnabled ? 'block' : 'none';
- document.querySelector(`#otherMediaAudioShareAudioCloseSvg${data.from}`).style.display = data.isAudioEnabled ? 'none' : 'block';
-
- document.querySelector(`#otherMediaAudioShareAudioOpenAnimSvg${data.from}`).style.display = data.isAudioEnabled ? 'block' : 'none';
- document.querySelector(`#otherMediaAudioShareAudioCloseAnimSvg${data.from}`).style.display = data.isAudioEnabled ? 'none' : 'block';
- }
- }
- });
-
- //关闭音视频
- this.socket.on('stopVideoShare', function (data) {
- if (data.id === that.socketId) {
- that.clickMediaVideo();
- } else {
- $(`#otherMediaVideoShare${data.id}`).parent().remove();
- }
- });
+ }
- //退出直播
- this.socket.on('stopLiveShare', function (data) {
- //如果是主动房主退出,所有观众都退出
- if(data.owner){
- window.location.reload();
- return
- }
+ const downloadLink = document.createElement('a');
+ downloadLink.download = recoder.name;
+ downloadLink.href = URL.createObjectURL(new Blob(allBuffer), { type: recoder.type });
+ downloadLink.style.display = 'none';
+ document.body.appendChild(downloadLink);
+ downloadLink.click();
+ document.body.removeChild(downloadLink);
+ },
+ // 清除indexedDb中的文件
+ clearIndexedDbFile: function(){
+ let that = this;
- if (data.id === that.socketId) {
- that.clickMediaLive();
- }
- });
+ this.receiveFileRecoderList = [];
- //退出语音连麦
- this.socket.on('stopAudioShare', function (data) {
- if (data.id === that.socketId) {
- that.clickMediaAudio();
- } else {
- $(`#otherMediaAudioShare${data.id}`).parent().remove();
- }
+ localforage.clear().then(function() {
+ layer.msg(that.lang.clear_indexeddb_file_done)
});
+ },
+ //删除indexedDb中的文件
+ deleteIndexedDbFile : function(recoder){
+ let that = this;
+ if(!this.canSaveToIndexedDb){
+ return
+ }
- //ai对话
- this.socket.on('openaiAnswer', function (data) {
- that.isAiAnswering = false
- that.receiveAiChatList.push(data)
- that.addSysLogs("AI : " + data.content)
- that.addPopup({
- title : that.lang.ai_reply,
- msg : that.lang.ai_reply_you
- });
- that.receiveAiChatList.forEach(item => {
- item.timeAgo = window.util ? util.timeAgo(item.time) : item.time;
- })
- that.openaiChatTpl()
- });
+ const keyList = this.getIndexedDbFileBufferKeyList(recoder);
- //开关数据
- this.socket.on('commData', function (data) {
- that.switchData = data.switchData
- that.switchDataGet = true;
- if(data.switchData.noticeMsgList){
- let alert = window.localStorage.getItem("tl-rtc-file-alert-notice")
- if(!alert || (Date.now() - parseInt(alert)) / 1000 > (24 * 60 * 60) ){
- setTimeout(() => {
- that.clickNotice()
- window.localStorage.setItem("tl-rtc-file-alert-notice", Date.now())
- }, 1000);
- }
- }
+ this.receiveFileRecoderList = this.receiveFileRecoderList.filter(item => {
+ return item.index !== recoder.index;
+ })
- if(data.chatingCommData){
- data.chatingCommData.forEach(elem => {
- try {
- elem.msg = tlrtcfile.unescapeStr(elem.msg)
- } catch (e) {
- that.addSysLogs(that.lang.text_decode_failed + elem.msg);
- }
- that.receiveChatCommList.push(elem)
- })
- that.receiveChatCommList.forEach(item => {
- item.timeAgo = window.util ? util.timeAgo(item.time) : item.time;
- })
- }
+ // 删除文件信息
+ localforage.removeItem(recoder.indexedDbInfoKey).then(function() {
+ layer.msg(that.lang.delete_indexeddb_file_done)
+ }).catch(function(err) {
+ console.log("deleteIndexedDbFile info err ",err);
});
- //公共聊天频道
- this.socket.on('chatingComm', function (data) {
- that.addSysLogs(data.room + ":" + data.socketId + that.lang.send_text + ": [ " + data.msg + " ]");
- try {
- data.msg = tlrtcfile.unescapeStr(data.msg)
- } catch (e) {
- that.addSysLogs(that.lang.text_decode_failed + data.msg);
- }
- that.receiveChatCommList.push(data);
- if (that.receiveChatCommList.length > 10) {
- that.receiveChatCommList.shift();
- }
- that.receiveChatCommList.forEach(item => {
- item.timeAgo = window.util ? util.timeAgo(item.time) : item.time;
- })
- that.chatingCommTpl()
-
- that.addPopup({
- title : that.lang.chat_comm,
- msg : that.lang.public_chat_channel_someone_interact
+ // 删除文件数据
+ keyList.forEach( key =>{
+ localforage.removeItem( key ).then(function() {
+ }).catch(function(err) {
+ console.log("deleteIndexedDbFile data err ",err);
});
});
- this.socket.on('manageCheck', function (data) {
- layer.prompt({
- formType: 1,
- title: that.lang.please_enter,
- }, function (value, index, elem) {
- that.socket.emit('manageConfirm', {
- room: that.roomId,
- value: value
- });
- layer.close(index)
- });
- });
+ // 删除的文件如果是最后一个文件,关闭下接收文件弹窗
+ if(this.receiveFileRecoderList === 0){
+ this.clickReceiveFile(true)
+ }
+ },
+ //分片文件数据存入indexedDb
+ saveSliceFileBufferToIndexedDb : function(recoder, fragment, buffer){
+ localforage.setItem(recoder.indexedDbBufferKey + fragment, buffer);
+ },
+ //文件信息存入indexedDb
+ saveSliceFileInfoToIndexedDb : function(recoder){
+ localforage.setItem(recoder.indexedDbInfoKey, recoder);
+ },
+ //加载indexedDb中的历史文件信息,不包括文件buffer
+ loadIndexedDbFileInfo : function(){
+ let that = this;
+ if(!this.canSaveToIndexedDb){
+ return
+ }
- this.socket.on('manage', function (data) {
- if (data.socketId !== that.socketId) {
- layer.msg(that.lang.illegal_event)
- return
+ localforage.iterate(function(value, key, iterationNumber) {
+ if(key.toString().endsWith("_info")){
+ that.receiveFileRecoderList.push(value)
+ that.loadIndexedFileAllSize += value.size;
}
- layer.closeAll();
- that.token = data.token;
- layer.load(2, {
- time: 1000,
- shade: [0.8, '#000000'],
- success: function (layero) {
- layer.setTop(layero); //重点2
- }
- })
- setTimeout(() => {
- that.manageIframeId = layer.tab({
- area: ['100%', '100%'],
- shade: [0.8, '#393D49'],
- closeBtn : 0,
- tab: [{
- title: data.content[0].title,
- content: data.content[0].html
- }, {
- title: data.content[1].title,
- content: data.content[1].html
- }, {
- title: data.content[2].title,
- content: data.content[2].html
- }],
- cancel: function (index, layero) {
- that.manageIframeId = 0;
- },
- })
- layer.full(that.manageIframeId)
- }, 500);
+ }).then(function() {
+ that.addUserLogs(that.lang.load_indexeddb_file_done);
+ }).catch(function(err) {
+ console.log("loadIndexedDbFileInfo err ",err);
});
},
// 检测浏览器是支持webrtc
@@ -4226,6 +5290,7 @@ axios.get("/api/comm/initData?turn="+useTurn, {}).then((initData) => {
this.sendFileRecoderHeight = document.querySelector("#send-file-list").clientHeight - 190;
this.chooseFileHeight = document.querySelector("#send-file-list-choose").clientHeight - 40;
this.sendFileRecoderHistoryHeight = document.querySelector("#send-file-list-history").clientHeight - 40;
+ this.localNetRoomListHeight = document.querySelector("#local-net-room-list").clientHeight - 40;
this.receiveFileHeight = document.querySelector("#receive-file-list").clientHeight - 40;
this.codeFileHeight = document.querySelector("#code-file-list").clientHeight - 40;
@@ -4328,27 +5393,6 @@ axios.get("/api/comm/initData?turn="+useTurn, {}).then((initData) => {
}
this.isAudioShare = res
})
- window.Bus.$on("sendChatingComm", (res) => {
- this.sendChatingComm()
- })
- window.Bus.$on("sendChatingRoom", (res) => {
- this.sendChatingRoom()
- })
- window.Bus.$on("sendChatingRoomSingle", (res) => {
- this.sendChatingRoomSingle()
- })
- window.Bus.$on("sendOpenaiChat", (res) => {
- this.sendOpenaiChat()
- })
- window.Bus.$on("sendOpenaiChatWithContext", () => {
- this.openaiSendContext = !this.openaiSendContext;
- layer.msg(`${this.lang.ai_switch}${this.openaiSendContext ? this.lang.on : this.lang.off}`)
- this.addUserLogs(`${this.lang.ai_switch}${this.openaiSendContext ? this.lang.on : this.lang.off}`)
- $("#aiContext").removeClass("layui-anim-rotate")
- setTimeout(() => {
- $("#aiContext").addClass("layui-anim-rotate")
- }, 50)
- })
window.Bus.$on("manageChange", (data) => {
this.socket.emit('manageChange', {
id: data.id,
@@ -4365,18 +5409,6 @@ axios.get("/api/comm/initData?turn="+useTurn, {}).then((initData) => {
content: data.time,
});
})
- window.Bus.$on("webrtcCheck", (res) => {
- this.webrtcCheck()
- })
- window.Bus.$on("sendBugs", (res) => {
- this.sendBugs()
- })
- window.Bus.$on("relaySetting", (res) => {
- this.relaySetting()
- })
- window.Bus.$on("customWsHost", (res) => {
- this.customWsHost()
- })
window.Bus.$on("addSysLogs", (res) => {
this.addSysLogs(res)
})
@@ -4485,7 +5517,7 @@ axios.get("/api/comm/initData?turn="+useTurn, {}).then((initData) => {
observer: true,
scrollbar: {
el : '.swiper-scrollbar',
- hide: true,
+ // hide: true,
}
})
window.toolSwiper = toolSwiper;
@@ -4500,7 +5532,7 @@ axios.get("/api/comm/initData?turn="+useTurn, {}).then((initData) => {
this.addSysLogs(this.lang.init_language_done);
this.addSysLogs(this.lang.print_logo);
- this.consoleLogo();
+ this.printLogo();
this.addSysLogs(this.lang.refresh_random_room_num_init);
this.refleshRoom()
@@ -4531,9 +5563,11 @@ axios.get("/api/comm/initData?turn="+useTurn, {}).then((initData) => {
}, 5000);
this.addSysLogs(this.lang.webrtc_check_init_done);
+ this.addSysLogs(this.lang.heartbeat_init);
setInterval(async () => {
this.socket.emit("heartbeat", {})
}, 10000);
+ this.addSysLogs(this.lang.heartbeat_init_done);
this.addSysLogs(this.lang.message_box_init);
this.startPopUpMsg()
@@ -4562,8 +5596,20 @@ axios.get("/api/comm/initData?turn="+useTurn, {}).then((initData) => {
this.audioDeviceList = a;
this.loudspeakerDeviceList = l;
});
+
+ this.addSysLogs(this.lang.indexedDB_init);
+ this.loadIndexedDbFileInfo();
+ this.addSysLogs(this.lang.indexedDB_init_done);
+
+ this.addSysLogs(this.lang.check_auto_join_fixed_room);
+ this.autoJoinFixedRoom();
+ this.addSysLogs(this.lang.check_auto_join_fixed_room_done);
}, 2000);
+ this.addSysLogs(this.lang.nickname_init);
+ this.setNickName();
+ this.addSysLogs(this.lang.nickname_init_done);
+
this.addSysLogs(this.lang.debug_init);
this.loadVConsoleJs();
this.addSysLogs(this.lang.debug_init_done);
@@ -4578,45 +5624,6 @@ axios.get("/api/comm/initData?turn="+useTurn, {}).then((initData) => {
window.manageChange = function (data) {
window.Bus.$emit("manageChange", data)
}
- window.sendChatingComm = function () {
- window.Bus.$emit("sendChatingComm", {})
- }
- window.sendChatingRoom = function () {
- window.Bus.$emit("sendChatingRoom", {})
- }
- window.sendChatingRoomSingle = function () {
- window.Bus.$emit("sendChatingRoomSingle", {})
- }
- window.sendOpenaiChat = function () {
- window.Bus.$emit("sendOpenaiChat", {})
- }
- window.webrtcCheck = function () {
- window.Bus.$emit("webrtcCheck", {})
- }
- window.sendBugs = function () {
- window.Bus.$emit("sendBugs", {})
- }
- window.sendOpenaiChatWithContext = function () {
- window.Bus.$emit("sendOpenaiChatWithContext", {})
- }
- window.relaySetting = function () {
- window.layer.closeAll(() => {
- window.Bus.$emit("relaySetting", {})
- });
- }
- window.useTurn = function () {
- if ((window.localStorage.getItem("tl-rtc-file-use-relay") || "") === 'true') {
- window.localStorage.setItem("tl-rtc-file-use-relay", false)
- } else {
- window.localStorage.setItem("tl-rtc-file-use-relay", true)
- }
- window.location.reload()
- }
- window.customWsHost = function () {
- window.layer.closeAll(() => {
- window.Bus.$emit("customWsHost", {})
- });
- }
})
diff --git a/svr/res/js/language.js b/svr/web-res/js/language.js
similarity index 83%
rename from svr/res/js/language.js
rename to svr/web-res/js/language.js
index 2e80bdb..fb9bd3b 100644
--- a/svr/res/js/language.js
+++ b/svr/web-res/js/language.js
@@ -8,6 +8,70 @@
const local_lang = {
"en": {
+ "question_answer" : "Question and answer",
+ "room_number" : "Room number",
+ "expand_local_network_room" : "Expand local network room panel",
+ "collapse_local_network_room" : "Collapse local network room panel",
+ "no_local_network_room" : "No local network room searched",
+ "local_net_room_list" : "Local network room list",
+ "heartbeat_init" : "heartbeat init",
+ "heartbeat_init_done" : "heartbeat init done",
+ "indexedDB_init" : "indexedDB init",
+ "indexedDB_init_done" : "indexedDB init done",
+ "auto_join_fixed_room" : "Auto join fixed room",
+ "check_auto_join_fixed_room" : "Check auto join fixed room",
+ "check_auto_join_fixed_room_done" : "Check auto join fixed room done",
+ "room_number_error" : "Room number error",
+ "local_network_room_share" : "Local network room share",
+ "fixed_room" : "Fixed room number",
+ "messgae_dot_switch" : "Message dot switch",
+ "message_dot" : "Message dot",
+ "github": "Github link",
+ "gitee" : "Gitee link",
+ "log_list" : "Log list",
+ "logs_switch" : "Logs switch",
+ "indexedDB_file_alreay_delete" : "indexedDB file has been deleted",
+ "output_log_limit" : "Execution log output limit",
+ "preview_limit_size" : "Preview file size limit",
+ "file_fragment_size" : "File fragment transfer size",
+ "clear_indexeddb_file_done" : "Clear indexeddb file done",
+ "clear_all" : "Clear all",
+ "file_transfer_setting" : "File transfer setting",
+ "switch_setting" : "Switch setting",
+ "setting_basic": "Setting basic",
+ "receive_file_all_size" : "Total size of received files",
+ "load_indexeddb_file_all" : "Load all historical files from disk",
+ "delete_indexeddb_file_done" : "Delete indexeddb file done",
+ "load_indexeddb_file_done" : "Load indexeddb file done",
+ "load_from_disk" : "Load from disk",
+ "clear" : "Clear",
+ "clear_file_in_disk" : "Clear file in disk",
+ "open_source_doc_intro" : "Open source project document installation instructions",
+ "blog_intro" : "Developer/Team Blog",
+ "webrtc_check_intro" : "webrtc browser compatibility check",
+ "custom_url_intro" : "Customized websocket service connection address",
+ "relay_intro" : "Relay switch for p2p failed transmission",
+ "save_to_indexeddb_intro" : "Switch to permanently store files in the browser",
+ "ai_intro" : "Context switch for handling ChatGPT conversations",
+ "log_intro" : "Open the log list panel",
+ "send_bug_intro" :"Feedback website/project issues, suggestions",
+ "setting_intro" : "Setting intro",
+ "open_source_doc" : "Open source document",
+ "file_in_disk" : "Saved in disk",
+ "save_file_to_indexeddb_done" : "Save file to indexeddb done",
+ "save_file_to_indexeddb" : "Save file to indexeddb",
+ "logout_succ": "Logout successfully",
+ "check_login_state_init" : "Check login state initialization",
+ "check_login_state_init_done" : "Check login state initialization completed",
+ "nickname_init" : "Nickname initialization",
+ "nickname_init_done" : "Nickname initialization completed",
+ "user_info": "User info",
+ "login_fail": "Login failed",
+ "login_succ" : "Login successfully",
+ "scan_succ_and_wait_auth" : "Scan code successfully, waiting for confirmation authorization...",
+ "wait_scan" : "Waiting for scan",
+ "login_info" : "After logging in, you can load historical room records and other information",
+ "wxlogin" : "wchat app login",
"wait_for_file" : "Waiting for the other party to prepare the file",
"send_to_all_user": "Send to all user",
"please_use_turn_server" : "Please use turn server in settings",
@@ -33,7 +97,7 @@ const local_lang = {
"start_audio_sharing" : "Start audio sharing",
"end_audio_sharing" : "End audio sharing",
"in_audioing" : "In audioing",
- "start_audio" : "Start audio",
+ "start_audio" : "audio",
"audience" : "Audience",
"webrtc_check_init" : "Webrtc check init",
"webrtc_check_init_done" : "Webrtc check init done",
@@ -50,7 +114,7 @@ const local_lang = {
"answer_failed": "Answer failed",
"basic_data_get": "Basic data acquisition",
"basic_data_get_done": "Basic data acquisition completed",
- "blog": "Blog",
+ "blog": "My Blog",
"chat_channel": "Chat channel",
"chat_comm": "Chat",
"chat_gpt": "ChatGPT",
@@ -137,7 +201,7 @@ const local_lang = {
"generate_send_file_record": "Generate send file record",
"get_device_failed": "Failed to get device recording permission",
"get_pickup_file": "Get files through pickup code",
- "give_coffee": "Buy me a coffee",
+ "give_coffee": "donat author",
"home": "Official website homepage",
"history_msg" : " History messages",
"i_said_to_ai": "I said to AI",
@@ -184,7 +248,6 @@ const local_lang = {
"open_donate": "Open donate window",
"open_private_chat": "Open private chat panel",
"open_public_chat_panel": "Open public chat panel",
- "open_relay_setting": "Open relay setting window",
"open_room_chat_panel": "Open room chat panel",
"open_setting": "Open setting window",
"open_share_join_room": "Open share join room window",
@@ -247,7 +310,7 @@ const local_lang = {
"relay_on": "The relay server is currently enabled, for more information, please go to settings to view",
"relay_on_and_more_info_in_setting": "The relay server is currently enabled, for more information, please go to settings to view",
"relay_server_current": "The relay server is currently",
- "relay_server_current_detail": "Enabling the relay server can ensure that the data is transferred in a complex p2p network environment. If it is disabled, it will be forced to go through p2p (p2p detection can be performed in the settings), which may cause the transmission to fail!",
+ "relay_server_current_detail": "Enabling the relay server can ensure that the data is transferred in a complex p2p network environment. If it is disabled, it will be forced to go through p2p, which may cause the transmission to fail!",
"relay_setting": "Relay setting",
"remote_draw": "Paint",
"room": "Room",
@@ -347,9 +410,77 @@ const local_lang = {
"device_classification" : "Device classification",
"network_status" : "Network status",
"public_ip" : "Public IP",
- "webrtc_ice_state" : "webrtc state"
+ "webrtc_ice_state" : "webrtc state",
+ "ip" : "IP",
+ "online_count" : "Online count",
},
"zh": {
+ "question_answer" : "问答/建议反馈列表",
+ "ip" : "IP",
+ "online_count" : "在线人数",
+ "room_number" : "房间号",
+ "expand_local_network_room" : "展开局域网房间面板",
+ "collapse_local_network_room" : "收起局域网房间面板",
+ "no_local_network_room" : "未搜索到局域网房间",
+ "local_net_room_list" : "局域网房间列表",
+ "heartbeat_init" : "心跳初始化",
+ "heartbeat_init_done" : "心跳初始化完成",
+ "indexedDB_init" : "indexedDB初始化",
+ "indexedDB_init_done" : "indexedDB初始化完成",
+ "auto_join_fixed_room" : "自动加入固定房间",
+ "check_auto_join_fixed_room_done" : "检查自动加入固定房间完成",
+ "check_auto_join_fixed_room" : "检查自动加入固定房间",
+ "room_number_error" : "房间号格式错误",
+ "local_network_room_share" : "局域网房间",
+ "fixed_room" : "固定房间号",
+ "messgae_dot_switch" : "消息红点开关",
+ "message_dot" : "消息红点",
+ "github" : "github地址",
+ "gitee" : "gitee地址",
+ "log_list" : "日志列表",
+ "logs_switch" : "日志开关",
+ "indexedDB_file_alreay_delete" : "indexedDB文件已经删除",
+ "output_log_limit" : "执行日志输出限制",
+ "preview_limit_size" : "预览文件大小限制",
+ "file_fragment_size" : "文件分片传输大小",
+ "clear_indexeddb_file_done" : "清除indexeddb文件完成",
+ "clear_all" : "清空全部",
+ "file_transfer_setting" : "文件传输设置",
+ "switch_setting" : "开关设置",
+ "setting_basic" : "基础设置",
+ "receive_file_all_size" : "接收文件总大小",
+ "load_indexeddb_file_all" : "加载磁盘历史文件",
+ "delete_indexeddb_file_done" : "删除indexeddb文件完成",
+ "load_indexeddb_file_done" : "从indexeddb加载文件完成",
+ "load_from_disk" : "从磁盘加载",
+ "clear" : "清理",
+ "clear_file_in_disk" : "清除磁盘中的文件",
+ "open_source_doc_intro" : "开源项目文档安装说明",
+ "blog_intro" : "开发者/团队博客",
+ "webrtc_check_intro" : "webrtc浏览器兼容性检测",
+ "custom_url_intro" : "自定义websocket服务连接地址",
+ "relay_intro" : "p2p失败兜底传输的中继开关",
+ "save_to_indexeddb_intro" : "文件长久存放在浏览器的开关",
+ "ai_intro" : "处理ChatGPT对话的上下文开关",
+ "log_intro" : "打开日志列表面板",
+ "send_bug_intro" :"反馈网站/项目问题,建议",
+ "setting_intro" : "设置简介",
+ "open_source_doc" : "开源文档",
+ "file_in_disk" : "已存放磁盘中",
+ "save_file_to_indexeddb" : "文件持久化",
+ "save_file_to_indexeddb_done": "保存文件到indexeddb完成",
+ "logout_succ" : "退出成功",
+ "check_login_state_init" : "检查登录状态初始化",
+ "check_login_state_init_done" : "检查登录状态初始化完成",
+ "nickname_init" : "昵称初始化",
+ "nickname_init_done" : "昵称初始化完成",
+ "user_info" : "用户信息",
+ "login_fail": "登录失败",
+ "login_succ": "登录成功",
+ "scan_succ_and_wait_auth": "扫码成功,等待确定授权中...",
+ "wait_scan" : "等待扫码",
+ "login_info" : "登录后可关联/加载历史房间记录等信息",
+ "wxlogin" : "微信扫码登录",
"wait_for_file": "对方准备文件中",
"please_use_turn_server" : "当前网络环境不稳定,建议在设置中打开中继服务开关",
"socketConnectFail" : "socket服务连接失败,请检查socket服务是否正常启动,socket地址=",
@@ -395,13 +526,13 @@ const local_lang = {
"ai_chat_record": "AI聊天记录",
"ai_reply": "AI回复",
"ai_reply_you": "AI回复了你,快点聊起来吧~",
- "ai_setting": "智能理解",
+ "ai_setting": "AI上下文",
"ai_switch": "AI智能理解上下文开关",
"ai_thinking": "AI思考中",
"answer_failed": "answer失败",
"basic_data_get": "基础数据 获取中",
"basic_data_get_done": "基础数据 获取完成",
- "blog": "博客",
+ "blog": "个人博客",
"chat_channel": "聊天频道",
"chat_comm": "公共聊天",
"chat_gpt": "ChatGPT",
@@ -487,7 +618,7 @@ const local_lang = {
"generate_send_file_record": "生成文件发送记录",
"get_device_failed": "获取设备录制权限失败",
"get_pickup_file": "通过取件码获取文件",
- "give_coffee": "赞助一杯咖啡",
+ "give_coffee": "赞赏作者",
"history_msg" : " 条历史消息",
"home": "官网首页",
"i_said_to_ai": "我对AI说",
@@ -534,7 +665,6 @@ const local_lang = {
"open_donate": "打开赞助窗口",
"open_private_chat": "打开私聊面板",
"open_public_chat_panel": "打开公共聊天面板",
- "open_relay_setting": "打开中继设置窗口",
"open_room_chat_panel": "打开房间聊天面板",
"open_setting": "打开设置窗口",
"open_share_join_room": "打开分享房间窗口",
@@ -597,7 +727,7 @@ const local_lang = {
"relay_on": "当前已启用中继服务器,有关更多信息,请前往设置查看",
"relay_on_and_more_info_in_setting": "当前已启用中继服务器,有关更多信息,请前往设置查看",
"relay_server_current": "中继服务器当前已",
- "relay_server_current_detail": "启用中继服务器可以保证在复杂的p2p网络环境下,提供保底的数据中转传输,如果禁用,则是强制走p2p(可在设置中进行p2p检测),可能会出现发送失败!",
+ "relay_server_current_detail": "启用中继服务器可以保证在复杂的p2p网络环境下,提供保底的数据中转传输,如果禁用,则是强制走p2p,可能会出现发送失败!",
"relay_setting": "中继设置",
"remote_draw": "远程画笔",
"room": "房间",
diff --git a/svr/res/js/liveShare.js b/svr/web-res/js/liveShare.js
similarity index 100%
rename from svr/res/js/liveShare.js
rename to svr/web-res/js/liveShare.js
diff --git a/svr/res/js/screen.js b/svr/web-res/js/screen.js
similarity index 100%
rename from svr/res/js/screen.js
rename to svr/web-res/js/screen.js
diff --git a/svr/res/js/screenShare.js b/svr/web-res/js/screenShare.js
similarity index 100%
rename from svr/res/js/screenShare.js
rename to svr/web-res/js/screenShare.js
diff --git a/svr/res/js/videoShare.js b/svr/web-res/js/videoShare.js
similarity index 100%
rename from svr/res/js/videoShare.js
rename to svr/web-res/js/videoShare.js
diff --git a/svr/res/pay.html b/svr/web-res/pay.html
similarity index 100%
rename from svr/res/pay.html
rename to svr/web-res/pay.html
diff --git a/svr/wxapp-res/app.js b/svr/wxapp-res/app.js
new file mode 100644
index 0000000..6bdc111
--- /dev/null
+++ b/svr/wxapp-res/app.js
@@ -0,0 +1,13 @@
+//app.js
+App({
+ onLaunch: async function () {
+
+ },
+ globalData: {
+ userInfo: null, //用户信息
+ baseUrl: "http://localhost:9092", //访问路径
+ openId: '', //用户唯一标识
+ loginState: false, //用户登录状态
+ token: '', //用户登录返回的token
+ }
+})
\ No newline at end of file
diff --git a/svr/wxapp-res/app.json b/svr/wxapp-res/app.json
new file mode 100644
index 0000000..e666d2d
--- /dev/null
+++ b/svr/wxapp-res/app.json
@@ -0,0 +1,17 @@
+{
+ "pages": [
+ "pages/login/login",
+ "pages/succ/succ"
+ ],
+ "window": {
+ "navigationBarBackgroundColor": "#fff",
+ "navigationBarTitleText": "tl-rtc-file",
+ "navigationBarTextStyle": "black",
+ "backgroundColor": "#eeeeee",
+ "backgroundTextStyle": "dark"
+ },
+ "networkTimeout": {
+ "request": 10000,
+ "downloadFile": 10000
+ }
+}
\ No newline at end of file
diff --git a/svr/wxapp-res/app.wxss b/svr/wxapp-res/app.wxss
new file mode 100644
index 0000000..a529c39
--- /dev/null
+++ b/svr/wxapp-res/app.wxss
@@ -0,0 +1,11 @@
+/* *app.wxss* */
+
+.container {
+ height: 100%;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: space-between;
+ padding: 200rpx 0;
+ box-sizing: border-box;
+}
diff --git a/svr/wxapp-res/images/demo.png b/svr/wxapp-res/images/demo.png
new file mode 100644
index 0000000..a9c0306
Binary files /dev/null and b/svr/wxapp-res/images/demo.png differ
diff --git a/svr/wxapp-res/images/gitee.png b/svr/wxapp-res/images/gitee.png
new file mode 100644
index 0000000..9dffb3d
Binary files /dev/null and b/svr/wxapp-res/images/gitee.png differ
diff --git a/svr/wxapp-res/images/github.png b/svr/wxapp-res/images/github.png
new file mode 100644
index 0000000..3b66049
Binary files /dev/null and b/svr/wxapp-res/images/github.png differ
diff --git a/svr/wxapp-res/images/succ.png b/svr/wxapp-res/images/succ.png
new file mode 100644
index 0000000..92f5506
Binary files /dev/null and b/svr/wxapp-res/images/succ.png differ
diff --git a/svr/wxapp-res/pages/login/login.js b/svr/wxapp-res/pages/login/login.js
new file mode 100644
index 0000000..f58b8bf
--- /dev/null
+++ b/svr/wxapp-res/pages/login/login.js
@@ -0,0 +1,180 @@
+const app = getApp()
+Page({
+
+ /**
+ * 页面的初始数据
+ */
+ data: {
+ scene: ''
+ },
+ onShow: function(){
+ wx.hideHomeButton()
+ },
+ /**
+ * 页面加载
+ */
+ onLoad: function (option) {
+ console.log("扫码");
+ console.log(option);
+ if (!!option.scene) {
+ this.setData({
+ scene: option.scene
+ });
+ this.setScanState('scan');
+ }
+ },
+ copyDemo : function(){
+ wx.setClipboardData({
+ data: "https://im.iamtsm.cn",
+ success() {
+ wx.showToast({
+ title: '演示体验地址已复制',
+ icon: "none",
+ duration: 1000
+ })
+ }
+ })
+ },
+ copyGithub : function(){
+ wx.setClipboardData({
+ data: "https://github.com/tl-open-source/tl-rtc-file",
+ success() {
+ wx.showToast({
+ title: 'github开源地址已复制',
+ icon: "none",
+ duration: 1000
+ })
+ }
+ })
+ },
+ copyGitee : function(){
+ wx.setClipboardData({
+ data: "https://gitee.com/iamtsm/tl-rtc-file",
+ success() {
+ wx.showToast({
+ title: 'gitee开源地址已复制',
+ icon: "none",
+ duration: 1000
+ })
+ }
+ })
+ },
+ //获取用户信息
+ getUserProfile(info) {
+ let that = this;
+ wx.showLoading({
+ title: '正在登录...',
+ })
+ // 执行登录操作
+ let code = '';
+ wx.login({
+ success: (res) => {
+ code = res.code;
+ },
+ });
+ // 获取用户信息
+ wx.getUserProfile({
+ lang: 'zh_CN',
+ desc: '用户登录',
+ success: (res) => {
+ that.GetOpenId(res.rawData, code);
+ },
+ fail: () => {
+ // 失败回调
+ wx.hideLoading();
+ }
+ });
+ },
+ GetOpenId: function (userInfo, code) {
+ console.log(userInfo)
+ let that = this
+ wx.request({
+ url: app.globalData.baseUrl + '/api/login/wechat',
+ data: {
+ userInfo: JSON.parse(userInfo),
+ code: code,
+ scene: that.data.scene
+ },
+ dataType: "json",
+ method: "POST",
+ success: function (res) {
+ wx.hideLoading();
+ console.log(res.data);
+ if (!res.data.session_key) {
+ wx.showToast({
+ title: "登录失败,请尝试重新扫码登录",
+ duration: 1000,
+ icon: 'none',
+ mask: true
+ })
+ wx.exitMiniProgram({
+ success: (res)=>{
+ console.log(res)
+ }
+ })
+ return
+ }
+ app.globalData.openId = res.data.openid;
+ app.globalData.token = res.data.token;
+ app.globalData.userInfo = userInfo;
+ app.globalData.loginState = true;
+ that.setScanState('auth_succ');
+ },
+ fail: function () {
+ console.log("失败")
+ that.setScanState('auth_fail');
+ }
+ })
+ },
+ setScanState(state) {
+ let that = this;
+ wx.request({
+ url: app.globalData.baseUrl + '/api/login/scanState',
+ data: {
+ scene: that.data.scene,
+ state: state,
+ token : app.globalData.token
+ },
+ dataType: "json",
+ method: "POST",
+ success: function (res) {
+ wx.hideLoading();
+ if (res.data.code != 200) {
+ wx.showToast({
+ title: "登录失败,请尝试重新扫码登录",
+ duration: 1000,
+ icon: 'none',
+ mask: true
+ })
+ wx.exitMiniProgram({
+ success: (res)=>{
+ console.log(res)
+ }
+ })
+ return
+ }
+
+ if(state === 'auth_succ'){
+ wx.showToast({
+ title: "登录成功!",
+ duration: 1000,
+ icon: 'none',
+ mask: true
+ })
+ // 在登录成功后跳转到 succ 页面
+ wx.redirectTo({
+ url: '/pages/succ/succ',
+ })
+ }
+ },
+ fail: function () {
+ console.log("失败")
+ wx.exitMiniProgram({
+ success: (res)=>{
+ console.log(res)
+ }
+ })
+ }
+ })
+ }
+})
diff --git a/svr/wxapp-res/pages/login/login.json b/svr/wxapp-res/pages/login/login.json
new file mode 100644
index 0000000..0c9087e
--- /dev/null
+++ b/svr/wxapp-res/pages/login/login.json
@@ -0,0 +1,5 @@
+{
+ "usingComponents": {},
+ "navigationBarTitleText": "",
+ "disableScroll": true
+}
\ No newline at end of file
diff --git a/svr/wxapp-res/pages/login/login.wxml b/svr/wxapp-res/pages/login/login.wxml
new file mode 100644
index 0000000..44e640e
--- /dev/null
+++ b/svr/wxapp-res/pages/login/login.wxml
@@ -0,0 +1,24 @@
+
+ tl-rtc-file 授权登录
+
+
+ 演示体验地址
+ |
+ 复制
+ https://im.iamtsm.cn
+
+
+ github开源地址
+ |
+ 复制
+ https://github.com/tl-open-source/tl-rtc-file
+
+
+ gitee开源地址
+ |
+ 复制
+ https://gitee.com/iamtsm/tl-rtc-file
+
+
+
+
diff --git a/svr/wxapp-res/pages/login/login.wxss b/svr/wxapp-res/pages/login/login.wxss
new file mode 100644
index 0000000..f439403
--- /dev/null
+++ b/svr/wxapp-res/pages/login/login.wxss
@@ -0,0 +1,55 @@
+.tlrtcfilePanel {
+ border: 1px white solid;
+ height: 60vh;
+ margin-top: 5vh;
+}
+
+.tlrtcfileTitle {
+ font-size: 23px;
+ font-weight: bold;
+ color: #383C40;
+ margin-top: 1vh;
+}
+
+.tlrtcfileIntro {
+ color: #686767;
+ font-size: 12px;
+ position: relative;
+ line-height: 25px;
+ padding: 8vh;
+ text-align: left;
+}
+
+.tlrtcfileIntroItem{
+ margin-top: 3vh;
+}
+
+.tlrtcfileIntroItem view{
+ margin-top: 1vh;
+}
+
+.tlrtcfileIntro image{
+ width: 4vh;
+ height: 4vh;
+ top: 7px;
+ position: relative;
+}
+
+.tlrtcfileIntro a {
+ margin-left: 1vh;
+}
+
+.tlrtcfileIntro a:hover {
+ color: rgb(114, 114, 202);
+}
+
+.loginBtn {
+ width: 70% !important;
+ height: 45px;
+ border-radius: 5px;
+ background-color: #0E87EB;
+ color: #fff;
+ bottom: 13vh;
+ position: absolute;
+ left: 15%;
+}
\ No newline at end of file
diff --git a/svr/wxapp-res/pages/succ/succ.js b/svr/wxapp-res/pages/succ/succ.js
new file mode 100644
index 0000000..c41b557
--- /dev/null
+++ b/svr/wxapp-res/pages/succ/succ.js
@@ -0,0 +1,62 @@
+// pages/index/index.js
+Page({
+
+ /**
+ * 页面的初始数据
+ */
+ data: {
+
+ },
+
+ /**
+ * 生命周期函数--监听页面加载
+ */
+ onLoad(options) {
+
+ },
+
+ /**
+ * 生命周期函数--监听页面初次渲染完成
+ */
+ onReady() {
+
+ },
+
+ /**
+ * 生命周期函数--监听页面隐藏
+ */
+ onHide() {
+
+ },
+
+ /**
+ * 生命周期函数--监听页面卸载
+ */
+ onUnload() {
+
+ },
+
+ /**
+ * 页面相关事件处理函数--监听用户下拉动作
+ */
+ onPullDownRefresh() {
+
+ },
+
+ /**
+ * 页面上拉触底事件的处理函数
+ */
+ onReachBottom() {
+
+ },
+
+ /**
+ * 用户点击右上角分享
+ */
+ onShareAppMessage() {
+
+ },
+ onShow: function(){
+ wx.hideHomeButton()
+ }
+})
\ No newline at end of file
diff --git a/svr/wxapp-res/pages/succ/succ.json b/svr/wxapp-res/pages/succ/succ.json
new file mode 100644
index 0000000..0c9087e
--- /dev/null
+++ b/svr/wxapp-res/pages/succ/succ.json
@@ -0,0 +1,5 @@
+{
+ "usingComponents": {},
+ "navigationBarTitleText": "",
+ "disableScroll": true
+}
\ No newline at end of file
diff --git a/svr/wxapp-res/pages/succ/succ.wxml b/svr/wxapp-res/pages/succ/succ.wxml
new file mode 100644
index 0000000..5d99de4
--- /dev/null
+++ b/svr/wxapp-res/pages/succ/succ.wxml
@@ -0,0 +1,5 @@
+
+
+
+ 登录成功
+
\ No newline at end of file
diff --git a/svr/wxapp-res/pages/succ/succ.wxss b/svr/wxapp-res/pages/succ/succ.wxss
new file mode 100644
index 0000000..ad7edbd
--- /dev/null
+++ b/svr/wxapp-res/pages/succ/succ.wxss
@@ -0,0 +1,34 @@
+/* pages/result/result.wxss */
+page{
+ text-align: center;
+ background-color: #ffffff;
+}
+.scc{
+ margin-top: 100rpx;
+ width: 160rpx;
+ height: 160rpx;
+}
+.resuil{
+ margin-top: 30rpx;
+ font-weight: 600;
+ letter-spacing: 3rpx;
+ font-size: 36rpx;
+}
+.btn{
+ width: 280rpx;
+ letter-spacing: 3rpx;
+ height: 70rpx;
+ font-weight: 500;
+ line-height: 70rpx;
+ border: 1px solid #3bb270;
+ color: #3bb270;
+ border-radius: 10rpx;
+ position: absolute;
+ bottom: 200rpx;
+ left: 50%;
+ margin-left: -130rpx;
+}
+
+.btn :hover, .btn:active{
+ color: #189b53;
+}
\ No newline at end of file
diff --git a/svr/wxapp-res/project.config.json b/svr/wxapp-res/project.config.json
new file mode 100644
index 0000000..bb2bf46
--- /dev/null
+++ b/svr/wxapp-res/project.config.json
@@ -0,0 +1,28 @@
+{
+ "appid": "",
+ "projectname": "",
+ "compileType": "miniprogram",
+ "libVersion": "3.0.2",
+ "packOptions": {
+ "ignore": [],
+ "include": []
+ },
+ "setting": {
+ "coverView": true,
+ "es6": true,
+ "postcss": true,
+ "minified": true,
+ "showShadowRootInWxmlPanel": true,
+ "compileHotReLoad": true,
+ "babelSetting": {
+ "ignore": [],
+ "disablePlugins": [],
+ "outputPath": ""
+ }
+ },
+ "condition": {},
+ "editorSetting": {
+ "tabIndent": "insertSpaces",
+ "tabSize": 2
+ }
+}
\ No newline at end of file
diff --git a/tlrtcfile.env b/tlrtcfile.env
index f47e5dc..05dac9e 100644
--- a/tlrtcfile.env
+++ b/tlrtcfile.env
@@ -87,3 +87,10 @@ tl_rtc_file_notify_open=false
tl_rtc_file_notify_qiwei_normal=
## 企业微信通知机器人KEY,错误通知,如果有多个key,逗号分隔
tl_rtc_file_notify_qiwei_error=
+
+
+#-----------------以下为微信小程序授权登录相关配置-----------------#
+## appId
+tl_rtc_file_login_appId=
+## appSecret
+tl_rtc_file_login_appSecret=