mirror of
https://github.com/tl-open-source/tl-rtc-file.git
synced 2025-10-04 23:22:43 +08:00
feat: 支持单个rtc连接信息查看
feat: 支持远程连接语言,设备,网络,ice状态,ice类型展示 feat: 支持多端画布自适应比例 feat: 调整优化文本绘制 feat: 调整优化缓冲区满的日志 fix: 修复控制台版本打印 fix: 修复滚动条样式 fix: 修复页面多余节点 fix: 修复某些中英文引用 fix: 修复缓冲区满的阈值
This commit is contained in:
2
PAY.md
2
PAY.md
@@ -16,7 +16,7 @@
|
|||||||
- **价格:** 按功能大小,紧急程度,耗时,定制内容是否允许开源,等情况收费
|
- **价格:** 按功能大小,紧急程度,耗时,定制内容是否允许开源,等情况收费
|
||||||
|
|
||||||
## 收费模式
|
## 收费模式
|
||||||
- **按小时计费:** 根据实际工作时间计算费用,目前个人定制功能2小时起,每小时200~300,企业定制另谈
|
- **按小时计费:** 根据实际工作时间计算费用,目前个人定制功能2小时起,每小时200~300
|
||||||
- **阶段性付费:** 确认开发前,预付1/3,开发完成付1/3,交付上线1/3
|
- **阶段性付费:** 确认开发前,预付1/3,开发完成付1/3,交付上线1/3
|
||||||
|
|
||||||
## 付款方式
|
## 付款方式
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"version": "10.2.5",
|
"version": "10.2.6",
|
||||||
"ws": {
|
"ws": {
|
||||||
"port": 8444,
|
"port": 8444,
|
||||||
"host": "ws://127.0.0.1:8444"
|
"host": "ws://127.0.0.1:8444"
|
||||||
|
@@ -284,7 +284,7 @@ body {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.tl-rtc-file-user-body {
|
.tl-rtc-file-user-body {
|
||||||
display: flex;
|
display: -webkit-box;
|
||||||
padding-top: 10px;
|
padding-top: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1134,3 +1134,28 @@ body {
|
|||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.remote_user_info{
|
||||||
|
text-align: left;
|
||||||
|
padding: 20px 20px 0 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.remote_user_info div{
|
||||||
|
padding-bottom: 5px;
|
||||||
|
font-weight: 200;
|
||||||
|
word-break: break-all;
|
||||||
|
}
|
||||||
|
|
||||||
|
.remote_user_info div b{
|
||||||
|
color: #548726;
|
||||||
|
margin-left: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.layui-carousel[lay-indicator=outside] .layui-carousel-ind{
|
||||||
|
top: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.layui-carousel>[carousel-item]{
|
||||||
|
overflow-y: auto;
|
||||||
|
overflow-x: hidden;
|
||||||
|
}
|
||||||
|
@@ -7,8 +7,8 @@
|
|||||||
<meta name="renderer" content="webkit">
|
<meta name="renderer" content="webkit">
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=0">
|
||||||
<script src="static/layui/layui.js" v="layui" e="layui"></script>
|
<script src="/static/layui/layui.js" v="layui" e="layui"></script>
|
||||||
<link rel="stylesheet" type="text/css" href="static/layui/css/layui.css" />
|
<link rel="stylesheet" type="text/css" href="/static/layui/css/layui.css" />
|
||||||
<link href="/image/44826979.png" rel="shortcut icon" type="image/x-icon">
|
<link href="/image/44826979.png" rel="shortcut icon" type="image/x-icon">
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
|
@@ -77,7 +77,7 @@
|
|||||||
<use xlink:href="#icon-rtc-file-five-g"></use>
|
<use xlink:href="#icon-rtc-file-five-g"></use>
|
||||||
</svg>
|
</svg>
|
||||||
<svg class="icon" aria-hidden="true" v-show="network === 'wifi'"
|
<svg class="icon" aria-hidden="true" v-show="network === 'wifi'"
|
||||||
style="width: 20px;height: 20px;margin-right: 10px;">
|
style="scale: 1.3;width: 20px;height: 20px;margin-right: 10px;">
|
||||||
<use xlink:href="#icon-rtc-file-WIFI"></use>
|
<use xlink:href="#icon-rtc-file-WIFI"></use>
|
||||||
</svg>
|
</svg>
|
||||||
</a>
|
</a>
|
||||||
@@ -90,14 +90,14 @@
|
|||||||
<b style="transition: color 0.8s;margin-right: 5px;" id="screenShareTimes" v-show="isScreenShare">
|
<b style="transition: color 0.8s;margin-right: 5px;" id="screenShareTimes" v-show="isScreenShare">
|
||||||
{{lang.sharing}}: {{screenShareTimes < 10 ? '0' + screenShareTimes :
|
{{lang.sharing}}: {{screenShareTimes < 10 ? '0' + screenShareTimes :
|
||||||
screenShareTimes}}{{lang.second}} </b>
|
screenShareTimes}}{{lang.second}} </b>
|
||||||
<b style="transition: color 0.8s;margin-right: 5px;" id="videoShareTimes" v-show="isVideoShare">
|
<b style="transition: color 0.8s;margin-right: 5px;" id="videoShareTimes" v-show="isVideoShare">
|
||||||
{{lang.videoing}}: {{videoShareTimes < 10 ? '0' + videoShareTimes :
|
{{lang.videoing}}: {{videoShareTimes < 10 ? '0' + videoShareTimes :
|
||||||
videoShareTimes}}{{lang.second}} </b>
|
videoShareTimes}}{{lang.second}} </b>
|
||||||
<b style="transition: color 0.8s;margin-right: 5px;" id="liveShareTimes"
|
<b style="transition: color 0.8s;margin-right: 5px;" id="liveShareTimes"
|
||||||
v-show="isLiveShare">
|
v-show="isLiveShare && owner">
|
||||||
{{lang.living}}: {{liveShareTimes < 10 ? '0' + liveShareTimes :
|
{{lang.living}}: {{liveShareTimes < 10 ? '0' + liveShareTimes :
|
||||||
liveShareTimes}}{{lang.second}} </b>
|
liveShareTimes}}{{lang.second}} </b>
|
||||||
<b style="transition: color 0.8s;margin-right: 5px;" id="screenTimes"></b>
|
<b style="transition: color 0.8s;margin-right: 5px;" id="screenTimes"></b>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -258,7 +258,6 @@
|
|||||||
<b>{{lang.pickup_code}}</b>
|
<b>{{lang.pickup_code}}</b>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="layui-col-xs3 swiper-slide" @click="openRemoteDraw"
|
<div class="layui-col-xs3 swiper-slide" @click="openRemoteDraw"
|
||||||
:class="switchData.openRemoteDraw ? '':'tl-rtc-file-tool-disabled'">
|
:class="switchData.openRemoteDraw ? '':'tl-rtc-file-tool-disabled'">
|
||||||
<div class="tl-rtc-file-tool tl-rtc-file-tool-mobile" v-if="clientWidth < 450">
|
<div class="tl-rtc-file-tool tl-rtc-file-tool-mobile" v-if="clientWidth < 450">
|
||||||
@@ -316,10 +315,12 @@
|
|||||||
</svg>
|
</svg>
|
||||||
<div class="tl-rtc-file-user-body-left">
|
<div class="tl-rtc-file-user-body-left">
|
||||||
<b class="tl-rtc-file-user-body-left-nick">
|
<b class="tl-rtc-file-user-body-left-nick">
|
||||||
<b v-show="owner" style="color: #7375e9;">【{{lang.owner}}】- </b>
|
<b v-show="owner" style="color: #7375e9;">【{{lang.owner}}】-</b>
|
||||||
{{nickName}} - {{lang.self}}
|
【{{lang.self}}】- {{nickName}}
|
||||||
|
</b>
|
||||||
|
<b class="tl-rtc-file-user-body-left-id">
|
||||||
|
{{socketId}}
|
||||||
</b>
|
</b>
|
||||||
<b class="tl-rtc-file-user-body-left-id"> {{socketId}} </b>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="tl-rtc-file-user-body-right">
|
<div class="tl-rtc-file-user-body-right">
|
||||||
@@ -346,7 +347,7 @@
|
|||||||
|
|
||||||
<!-- 远端连接 -->
|
<!-- 远端连接 -->
|
||||||
<div class="layui-row" style="position: relative;">
|
<div class="layui-row" style="position: relative;">
|
||||||
<div class="layui-col-xs12 tl-rtc-file-user-list" v-for="remote in remoteMap">
|
<div class="layui-col-xs12 tl-rtc-file-user-list" v-for="remote in remoteMap" @click="showRemoteUser(remote)">
|
||||||
<div class="tl-rtc-file-user">
|
<div class="tl-rtc-file-user">
|
||||||
<div class="tl-rtc-file-user-body">
|
<div class="tl-rtc-file-user-body">
|
||||||
<svg class="icon" aria-hidden="true" style="width: 32px;height: 32px;">
|
<svg class="icon" aria-hidden="true" style="width: 32px;height: 32px;">
|
||||||
@@ -355,13 +356,22 @@
|
|||||||
<div class="tl-rtc-file-user-body-left">
|
<div class="tl-rtc-file-user-body-left">
|
||||||
<b class="tl-rtc-file-user-body-left-nick">
|
<b class="tl-rtc-file-user-body-left-nick">
|
||||||
<b v-show="remote.owner" style="color: #7375e9;">【{{lang.owner}}】- </b>
|
<b v-show="remote.owner" style="color: #7375e9;">【{{lang.owner}}】- </b>
|
||||||
{{remote.nickName}}
|
{{remote.nickName}} - {{remote.id}}
|
||||||
|
</b>
|
||||||
|
<b class="tl-rtc-file-user-body-left-id">
|
||||||
|
<svg class="icon" aria-hidden="true" style="width: 12px;height: 12px;">
|
||||||
|
<use xlink:href="#icon-rtc-file-kongzhuangzhongduan"></use>
|
||||||
|
</svg> : {{remote.langMode}} - {{remote.ua}} - {{remote.network}} -
|
||||||
|
<svg class="icon" aria-hidden="true" style="width: 12px;height: 12px;">
|
||||||
|
<use xlink:href="#icon-rtc-file-yunfuwuqi"></use>
|
||||||
|
</svg> :
|
||||||
|
<b v-if="iceOk(remote.iceConnectionState)" style="font-weight: bold;color: #69d31e;">{{remote.iceConnectionState}} - {{remote.p2pMode}}</b>
|
||||||
|
<b v-else style="font-weight: bold;color: red;">{{remote.iceConnectionState}} - {{remote.p2pMode}}</b>
|
||||||
</b>
|
</b>
|
||||||
<b class="tl-rtc-file-user-body-left-id">{{remote.langMode}} - {{remote.id}} </b>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="tl-rtc-file-user-body-right">
|
<div class="tl-rtc-file-user-body-right">
|
||||||
<i :title="lang.send_text" @click="startChatRoomSingle(remote)"
|
<i :title="lang.send_text" @click="startChatRoomSingle(event, remote)"
|
||||||
class="layui-icon layui-icon-reply-fill"></i>
|
class="layui-icon layui-icon-reply-fill"></i>
|
||||||
<span v-show="remote.receiveChatRoomSingleList.length > 0" style="right: -7px;"
|
<span v-show="remote.receiveChatRoomSingleList.length > 0" style="right: -7px;"
|
||||||
class="layui-badge tl-rtc-file-msg-dot layui-anim layui-anim-rotate layui-anim-loop">
|
class="layui-badge tl-rtc-file-msg-dot layui-anim layui-anim-rotate layui-anim-loop">
|
||||||
@@ -424,7 +434,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="layui-row tl-rtc-file-send-list-all"
|
<div class="layui-row tl-rtc-file-send-list-all"
|
||||||
:style="{height: sendFileRecoderHeight+'px',overflowY: (sendFileRecoderList.length > 1 ? 'scroll' : 'none') }">
|
:style="{height: sendFileRecoderHeight+'px',overflowY: (sendFileRecoderList.length > 1 ? 'auto' : 'none') }">
|
||||||
<div class="layui-col-xs12 tl-rtc-file-send-list send-file-item"
|
<div class="layui-col-xs12 tl-rtc-file-send-list send-file-item"
|
||||||
v-for="file, index in sendFileRecoderList" :id="'send-file-item'+index">
|
v-for="file, index in sendFileRecoderList" :id="'send-file-item'+index">
|
||||||
<div class="tl-rtc-file-send" :style="{'--progress': file.progress + '%'}">
|
<div class="tl-rtc-file-send" :style="{'--progress': file.progress + '%'}">
|
||||||
@@ -615,7 +625,7 @@
|
|||||||
style="cursor: pointer; right: 10px;position: absolute;"></i>
|
style="cursor: pointer; right: 10px;position: absolute;"></i>
|
||||||
</div>
|
</div>
|
||||||
<div class="layui-row tl-rtc-file-send-list-all"
|
<div class="layui-row tl-rtc-file-send-list-all"
|
||||||
:style="{height: chooseFileHeight+'px',overflowY: (chooseFileList.length > 1 ? 'scroll' : 'none') }">
|
:style="{height: chooseFileHeight+'px',overflowY: (chooseFileList.length > 1 ? 'auto' : 'none') }">
|
||||||
<div class="layui-col-xs12 tl-rtc-file-send-list" v-for="file, index in chooseFileList">
|
<div class="layui-col-xs12 tl-rtc-file-send-list" v-for="file, index in chooseFileList">
|
||||||
<div class="tl-rtc-file-send" :style="{'--progress': file.progress + '%'}">
|
<div class="tl-rtc-file-send" :style="{'--progress': file.progress + '%'}">
|
||||||
<div class="tl-rtc-file-send-body">
|
<div class="tl-rtc-file-send-body">
|
||||||
@@ -691,7 +701,7 @@
|
|||||||
style="cursor: pointer; right: 10px;position: absolute;"></i>
|
style="cursor: pointer; right: 10px;position: absolute;"></i>
|
||||||
</div>
|
</div>
|
||||||
<div class="layui-row tl-rtc-file-send-list-all"
|
<div class="layui-row tl-rtc-file-send-list-all"
|
||||||
:style="{height: sendFileRecoderHistoryHeight+'px',overflowY: (sendFileRecoderHistoryList.length > 1 ? 'scroll' : 'none') }">
|
:style="{height: sendFileRecoderHistoryHeight+'px',overflowY: (sendFileRecoderHistoryList.length > 1 ? 'auto' : 'none') }">
|
||||||
<div class="layui-col-xs12 tl-rtc-file-send-list" v-for="file, index in sendFileRecoderHistoryList">
|
<div class="layui-col-xs12 tl-rtc-file-send-list" v-for="file, index in sendFileRecoderHistoryList">
|
||||||
<div class="tl-rtc-file-send" :style="{'--progress': file.progress + '%'}">
|
<div class="tl-rtc-file-send" :style="{'--progress': file.progress + '%'}">
|
||||||
<div class="tl-rtc-file-send-body">
|
<div class="tl-rtc-file-send-body">
|
||||||
@@ -771,7 +781,7 @@
|
|||||||
style="cursor: pointer; right: 10px;position: absolute;"></i>
|
style="cursor: pointer; right: 10px;position: absolute;"></i>
|
||||||
</div>
|
</div>
|
||||||
<div class="layui-row tl-rtc-file-send-list-all"
|
<div class="layui-row tl-rtc-file-send-list-all"
|
||||||
:style="{height: receiveFileHeight+'px',overflowY: (receiveFileRecoderList.length > 1 ? 'scroll' : 'none')}">
|
:style="{height: receiveFileHeight+'px',overflowY: (receiveFileRecoderList.length > 1 ? 'auto' : 'none')}">
|
||||||
<div class="layui-col-xs12 tl-rtc-file-send-list" v-for="file in receiveFileRecoderList">
|
<div class="layui-col-xs12 tl-rtc-file-send-list" v-for="file in receiveFileRecoderList">
|
||||||
<div class="tl-rtc-file-send" :style="{'--progress': file.progress + '%'}">
|
<div class="tl-rtc-file-send" :style="{'--progress': file.progress + '%'}">
|
||||||
<div class="tl-rtc-file-send-body">
|
<div class="tl-rtc-file-send-body">
|
||||||
@@ -867,7 +877,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="layui-row tl-rtc-file-send-list-all"
|
<div class="layui-row tl-rtc-file-send-list-all"
|
||||||
:style="{height: codeFileHeight+'px',overflowY: (receiveCodeFileList.length > 1 ? 'scroll' : 'none') }">
|
:style="{height: codeFileHeight+'px',overflowY: (receiveCodeFileList.length > 1 ? 'auto' : 'none') }">
|
||||||
<div class="layui-col-xs12 tl-rtc-file-send-list" v-for="file, index in receiveCodeFileList">
|
<div class="layui-col-xs12 tl-rtc-file-send-list" v-for="file, index in receiveCodeFileList">
|
||||||
<div class="tl-rtc-file-send">
|
<div class="tl-rtc-file-send">
|
||||||
<div class="tl-rtc-file-send-body">
|
<div class="tl-rtc-file-send-body">
|
||||||
@@ -955,7 +965,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="layui-card">
|
<div class="layui-card">
|
||||||
<div :style="{height: logsHeight+'px',overflowY: 'scroll'}">
|
<div :style="{height: logsHeight+'px',overflowY: 'auto'}">
|
||||||
<div class="layui-card-body tl-rtc-file-mask-log" v-for="log in filterLogs">
|
<div class="layui-card-body tl-rtc-file-mask-log" v-for="log in filterLogs">
|
||||||
<div class="tl-rtc-file-mask-log-time">
|
<div class="tl-rtc-file-mask-log-time">
|
||||||
<div>{{log.time}}</div>
|
<div>{{log.time}}</div>
|
||||||
@@ -964,7 +974,7 @@
|
|||||||
</svg>
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
<div v-show="log.msg.length >= 500" class="tl-rtc-file-mask-log-msg"
|
<div v-show="log.msg.length >= 500" class="tl-rtc-file-mask-log-msg"
|
||||||
style="max-height: 300px; overflow-y: scroll;">
|
style="max-height: 300px; overflow-y: auto;">
|
||||||
<b v-show="log.type === '【{{lang.sys_log}}】: '" style="color: #b54343;">{{log.type}}</b>
|
<b v-show="log.type === '【{{lang.sys_log}}】: '" style="color: #b54343;">{{log.type}}</b>
|
||||||
<b v-show="log.type === '【{{lang.op_log}}】: '"
|
<b v-show="log.type === '【{{lang.op_log}}】: '"
|
||||||
style="color: cadetblue;">{{log.type}}</b>
|
style="color: cadetblue;">{{log.type}}</b>
|
||||||
@@ -993,7 +1003,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="layui-card">
|
<div class="layui-card">
|
||||||
<div :style="{height: logsHeight+'px',overflowY: 'scroll'}">
|
<div :style="{height: logsHeight+'px',overflowY: 'auto'}">
|
||||||
<div class="layui-card-body">
|
<div class="layui-card-body">
|
||||||
<div class="tl-rtc-file-mask-media-container " id="mediaVideoRoomList"> </div>
|
<div class="tl-rtc-file-mask-media-container " id="mediaVideoRoomList"> </div>
|
||||||
</div>
|
</div>
|
||||||
@@ -1013,7 +1023,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="layui-card">
|
<div class="layui-card">
|
||||||
<div :style="{height: logsHeight+'px',overflowY: 'scroll'}">
|
<div :style="{height: logsHeight+'px',overflowY: 'auto'}">
|
||||||
<div class="layui-card-body">
|
<div class="layui-card-body">
|
||||||
<div class="tl-rtc-file-mask-media-container " id="mediaScreenRoomList"> </div>
|
<div class="tl-rtc-file-mask-media-container " id="mediaScreenRoomList"> </div>
|
||||||
</div>
|
</div>
|
||||||
@@ -1033,7 +1043,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="layui-card">
|
<div class="layui-card">
|
||||||
<div :style="{height: logsHeight+'px',overflowY: 'scroll'}">
|
<div :style="{height: logsHeight+'px',overflowY: 'auto'}">
|
||||||
<div class="layui-card-body">
|
<div class="layui-card-body">
|
||||||
<div class="tl-rtc-file-mask-media-container " id="mediaLiveRoomList"> </div>
|
<div class="tl-rtc-file-mask-media-container " id="mediaLiveRoomList"> </div>
|
||||||
</div>
|
</div>
|
||||||
@@ -1057,10 +1067,11 @@
|
|||||||
layui.use([
|
layui.use([
|
||||||
'layedit', 'form', 'layer', 'laytpl', 'upload',
|
'layedit', 'form', 'layer', 'laytpl', 'upload',
|
||||||
'dropdown', 'carousel', 'util', 'colorpicker',
|
'dropdown', 'carousel', 'util', 'colorpicker',
|
||||||
'slider', 'dropdown'
|
'slider', 'dropdown', 'carousel'
|
||||||
], function () {
|
], function () {
|
||||||
window.layer = layui.layer;
|
window.layer = layui.layer;
|
||||||
window.form = layui.form;
|
window.form = layui.form;
|
||||||
|
window.carousel = layui.carousel;
|
||||||
window.$ = layui.$;
|
window.$ = layui.$;
|
||||||
window.layedit = layui.layedit;
|
window.layedit = layui.layedit;
|
||||||
window.laytpl = layui.laytpl;
|
window.laytpl = layui.laytpl;
|
||||||
|
@@ -286,38 +286,8 @@ window.tlrtcfile = {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
getWebrtcStats: async function (peerConnection) {
|
getWebrtcStats: async function (peerConnection) {
|
||||||
// 候选者对
|
|
||||||
"candidate-pair" |
|
|
||||||
// 证书相关的统计信息
|
|
||||||
"certificate" |
|
|
||||||
// 当前音视频编解码器的统计信息
|
|
||||||
"codec" |
|
|
||||||
// CSRC相关的统计信息
|
|
||||||
"csrc" |
|
|
||||||
// 数据通道的相关统计信息
|
|
||||||
"data-channel" |
|
|
||||||
// 传入数据流的相关统计信息
|
|
||||||
"inbound-rtp" |
|
|
||||||
// 本地候选连接的相关统计信息
|
|
||||||
"local-candidate" |
|
|
||||||
// 媒体源的相关统计信息
|
|
||||||
"media-source" |
|
|
||||||
// 传出数据流的相关统计信息
|
|
||||||
"outbound-rtp" |
|
|
||||||
// 对等连接的相关统计信息
|
|
||||||
"peer-connection" |
|
|
||||||
// 对等连接的相关统计信息
|
|
||||||
"remote-candidate" |
|
|
||||||
// 远程传入数据流的相关统计信息
|
|
||||||
"remote-inbound-rtp" |
|
|
||||||
// 远程传出数据流的相关统计信息
|
|
||||||
"remote-outbound-rtp" |
|
|
||||||
// 媒体轨道的相关统计信息
|
|
||||||
"track" |
|
|
||||||
// 传输协议的相关统计信息
|
|
||||||
"transport";
|
|
||||||
|
|
||||||
if (!peerConnection) {
|
if (!peerConnection) {
|
||||||
return "RTCPeerConnection is not available";
|
return "RTCPeerConnection is not available";
|
||||||
}
|
}
|
||||||
@@ -325,23 +295,63 @@ window.tlrtcfile = {
|
|||||||
return "RTCStatsReport is not available";
|
return "RTCStatsReport is not available";
|
||||||
}
|
}
|
||||||
|
|
||||||
let result = { }
|
function getTypeDescription(type) {
|
||||||
|
switch (type) {
|
||||||
let stats = await peerConnection.getStats(null);
|
case 'candidate-pair':
|
||||||
|
return '候选者对';
|
||||||
stats.forEach((report) => {
|
case 'certificate':
|
||||||
if (!report.type) return;
|
return '证书相关的统计信息';
|
||||||
let data = {}
|
case 'codec':
|
||||||
Object.keys(report).forEach((statName) => {
|
return '当前音视频编解码器的统计信息';
|
||||||
data[statName] = report[statName]
|
case 'csrc':
|
||||||
});
|
return 'CSRC相关的统计信息';
|
||||||
result[report.type] = {
|
case 'data-channel':
|
||||||
kind : report.kind,
|
return '数据通道的相关统计信息';
|
||||||
data : data
|
case 'inbound-rtp':
|
||||||
|
return '传入数据流的相关统计信息';
|
||||||
|
case 'local-candidate':
|
||||||
|
return '本地候选连接的相关统计信息';
|
||||||
|
case 'media-source':
|
||||||
|
return '媒体源的相关统计信息';
|
||||||
|
case 'outbound-rtp':
|
||||||
|
return '传出数据流的相关统计信息';
|
||||||
|
case 'peer-connection':
|
||||||
|
return '对等连接的相关统计信息';
|
||||||
|
case 'remote-candidate':
|
||||||
|
return '远程候选连接的相关统计信息';
|
||||||
|
case 'remote-inbound-rtp':
|
||||||
|
return '远程传入数据流的相关统计信息';
|
||||||
|
case 'remote-outbound-rtp':
|
||||||
|
return '远程传出数据流的相关统计信息';
|
||||||
|
case 'track':
|
||||||
|
return '媒体轨道的相关统计信息';
|
||||||
|
case 'transport':
|
||||||
|
return '传输协议的相关统计信息';
|
||||||
|
case 'media-playout':
|
||||||
|
return '音频播放的相关统计数据'
|
||||||
|
default:
|
||||||
|
return '未知类型';
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
|
||||||
return result
|
function getRTCStats(peerConnection) {
|
||||||
|
const statsMap = new Map();
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
peerConnection.getStats().then((stats) => {
|
||||||
|
stats.forEach((report) => {
|
||||||
|
const { type } = report;
|
||||||
|
if (!statsMap.has(type)) {
|
||||||
|
statsMap.set(type, []);
|
||||||
|
}
|
||||||
|
statsMap.get(type).push({ report, description: getTypeDescription(type) });
|
||||||
|
});
|
||||||
|
|
||||||
|
resolve(statsMap);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return await getRTCStats(peerConnection);
|
||||||
},
|
},
|
||||||
copyTxt: function (id, content) {
|
copyTxt: function (id, content) {
|
||||||
let that = this;
|
let that = this;
|
||||||
|
@@ -17,6 +17,8 @@ const draw = new Vue({
|
|||||||
drawHistoryList: [], // 绘制历史操作列表, 用于回退
|
drawHistoryList: [], // 绘制历史操作列表, 用于回退
|
||||||
drawRollbackPoint: 0, // 绘制回退点
|
drawRollbackPoint: 0, // 绘制回退点
|
||||||
lineWidth: 1, // 画笔线宽
|
lineWidth: 1, // 画笔线宽
|
||||||
|
lineCap : "round",
|
||||||
|
lineJoin : "round",
|
||||||
strokeStyle: "#000000", // 画笔颜色
|
strokeStyle: "#000000", // 画笔颜色
|
||||||
//line: 线条, circle: 圆形, rectangle: 矩形, text: 文字, delete: 擦除
|
//line: 线条, circle: 圆形, rectangle: 矩形, text: 文字, delete: 擦除
|
||||||
drawMode: "line", // 画笔模式
|
drawMode: "line", // 画笔模式
|
||||||
@@ -26,7 +28,7 @@ const draw = new Vue({
|
|||||||
starFill : false, //填充星星
|
starFill : false, //填充星星
|
||||||
rhomboidFill : false, //填充平行四边形
|
rhomboidFill : false, //填充平行四边形
|
||||||
hexagonFill : false, //填充六边形
|
hexagonFill : false, //填充六边形
|
||||||
circleStarPoint: { x: 0, y: 0 }, //圆形开始点
|
circleStartPoint: { x: 0, y: 0 }, //圆形开始点
|
||||||
triangleStartPoint : { x: 0, y: 0 }, //三角形开始点
|
triangleStartPoint : { x: 0, y: 0 }, //三角形开始点
|
||||||
starStartPoint : { x: 0, y: 0 }, //星星开始点
|
starStartPoint : { x: 0, y: 0 }, //星星开始点
|
||||||
rhomboidStartPoint : { x: 0, y: 0 }, //平行四边形开始点
|
rhomboidStartPoint : { x: 0, y: 0 }, //平行四边形开始点
|
||||||
@@ -106,39 +108,66 @@ const draw = new Vue({
|
|||||||
if (!this.isOpenDraw) {
|
if (!this.isOpenDraw) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
const { drawMode, event } = options;
|
||||||
const canvas = document.getElementById('tl-rtc-file-mouse-draw-canvas');
|
const canvas = document.getElementById('tl-rtc-file-mouse-draw-canvas');
|
||||||
options.canvas = canvas;
|
const context = canvas.getContext('2d');
|
||||||
options.context = canvas.getContext('2d');
|
options.remote.canvas = canvas;
|
||||||
options.fromRemote = true;
|
options.remote.context = context;
|
||||||
|
|
||||||
const { drawMode } = options;
|
|
||||||
|
|
||||||
//收到结束标识,保存当前画板到缓存数据中
|
//收到结束标识,保存当前画板到缓存数据中
|
||||||
if(options.event === 'end'){
|
if(event === 'end'){
|
||||||
this.endDrawHandler(options)
|
this.endDrawHandler({canvas, context})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let {
|
||||||
|
width : remoteWidth, height : remoteHeight, lineWidth,
|
||||||
|
curPoint, prePoint, starStartPoint, circleStartPoint, triangleStartPoint, rectangleStartPoint
|
||||||
|
} = options.remote;
|
||||||
|
|
||||||
|
//计算双方画布比例,按比例进行坐标放大/缩小
|
||||||
|
const ratioWidth = canvas.width / remoteWidth;
|
||||||
|
const ratioHeight = canvas.height / remoteHeight;
|
||||||
|
|
||||||
|
//调整画笔
|
||||||
|
options.remote.lineWidth = lineWidth * (ratioWidth + ratioHeight) / 2
|
||||||
|
curPoint.x = curPoint.x * ratioWidth;
|
||||||
|
curPoint.y = curPoint.y * ratioHeight;
|
||||||
|
options.remote.curPoint = curPoint;
|
||||||
|
|
||||||
if (drawMode === 'line') {
|
if (drawMode === 'line') {
|
||||||
|
prePoint.x = prePoint.x * ratioWidth;
|
||||||
|
prePoint.y = prePoint.y * ratioHeight;
|
||||||
|
options.remote.prePoint = prePoint;
|
||||||
this.drawLine(options);
|
this.drawLine(options);
|
||||||
} else if (drawMode === 'circle') {
|
} else if (drawMode === 'circle') {
|
||||||
|
circleStartPoint.x = circleStartPoint.x * ratioWidth;
|
||||||
|
circleStartPoint.y = circleStartPoint.y * ratioHeight;
|
||||||
|
options.remote.circleStartPoint = circleStartPoint;
|
||||||
this.drawCircle(options);
|
this.drawCircle(options);
|
||||||
} else if (drawMode === 'rectangle') {
|
} else if (drawMode === 'rectangle') {
|
||||||
|
rectangleStartPoint.x = rectangleStartPoint.x * ratioWidth;
|
||||||
|
rectangleStartPoint.y = rectangleStartPoint.y * ratioHeight;
|
||||||
|
options.remote.rectangleStartPoint = rectangleStartPoint;
|
||||||
this.drawRectangle(options);
|
this.drawRectangle(options);
|
||||||
} else if (drawMode === 'text') {
|
} else if (drawMode === 'text') {
|
||||||
this.drawText(options);
|
this.drawText(options);
|
||||||
} else if(drawMode === 'triangle'){
|
} else if(drawMode === 'triangle'){
|
||||||
|
triangleStartPoint.x = triangleStartPoint.x * ratioWidth;
|
||||||
|
triangleStartPoint.y = triangleStartPoint.y * ratioHeight;
|
||||||
|
options.remote.triangleStartPoint = triangleStartPoint;
|
||||||
this.drawTriangle(options);
|
this.drawTriangle(options);
|
||||||
} else if(drawMode === 'star'){
|
} else if(drawMode === 'star'){
|
||||||
|
starStartPoint.x = starStartPoint.x * ratioWidth;
|
||||||
|
starStartPoint.y = starStartPoint.y * ratioHeight;
|
||||||
|
options.remote.starStartPoint = starStartPoint;
|
||||||
this.drawStar(options);
|
this.drawStar(options);
|
||||||
} else {
|
} else {
|
||||||
console.log("收到远程未知的绘制模式")
|
console.log("收到远程未知的绘制模式")
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
// 打开/关闭本地画笔
|
// 打开/关闭本地画笔
|
||||||
openDraw: function ({
|
openDraw: function ({ openCallback, closeCallback, localDrawCallback }) {
|
||||||
openCallback, closeCallback, localDrawCallback
|
|
||||||
}) {
|
|
||||||
let that = this;
|
let that = this;
|
||||||
|
|
||||||
if (this.isOpenDraw) {
|
if (this.isOpenDraw) {
|
||||||
@@ -466,126 +495,185 @@ const draw = new Vue({
|
|||||||
that.drawing = false;
|
that.drawing = false;
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
// 开始绘制
|
||||||
startDrawHandler: function ({ canvas, context, localDrawCallback }) {
|
startDrawHandler: function ({ canvas, context, localDrawCallback }) {
|
||||||
//公共参数
|
//公共参数
|
||||||
let commOptions = {
|
let localCommOptions = {
|
||||||
event : "start",
|
|
||||||
canvas,
|
canvas,
|
||||||
context,
|
context,
|
||||||
localDrawCallback,
|
localDrawCallback,
|
||||||
drawMode: this.drawMode,
|
devicePixelRatio : this.devicePixelRatio,
|
||||||
|
width : canvas.width,
|
||||||
|
height: canvas.height,
|
||||||
|
lineCap: this.lineCap,
|
||||||
|
lineJoin: this.lineJoin,
|
||||||
lineWidth: this.lineWidth,
|
lineWidth: this.lineWidth,
|
||||||
strokeStyle: this.strokeStyle,
|
strokeStyle: this.strokeStyle,
|
||||||
fillStyle: this.strokeStyle,
|
fillStyle: this.strokeStyle,
|
||||||
lineCap: "round",
|
|
||||||
lineJoin: "round"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.drawMode === 'delete') {
|
if (this.drawMode === 'delete') {
|
||||||
this.drawDelete(Object.assign(commOptions, {
|
this.drawDelete({
|
||||||
prePoint: this.prePoint,
|
event : "start",
|
||||||
curPoint : this.prePoint
|
drawMode: this.drawMode,
|
||||||
}))
|
local : Object.assign(localCommOptions, {
|
||||||
|
prePoint: this.prePoint,
|
||||||
|
curPoint : this.prePoint
|
||||||
|
}),
|
||||||
|
})
|
||||||
} else if (this.drawMode === 'rectangle') {
|
} else if (this.drawMode === 'rectangle') {
|
||||||
//开始的时候固定好矩形的起点
|
//开始的时候固定好矩形的起点
|
||||||
this.rectangleStartPoint = this.prePoint;
|
this.rectangleStartPoint = this.prePoint;
|
||||||
this.drawRectangle(Object.assign(commOptions, {
|
this.drawRectangle({
|
||||||
rectangleStartPoint: this.rectangleStartPoint,
|
event : "start",
|
||||||
curPoint: this.prePoint,
|
drawMode: this.drawMode,
|
||||||
rectangleFill : this.rectangleFill
|
local : Object.assign(localCommOptions, {
|
||||||
}))
|
rectangleStartPoint: this.rectangleStartPoint,
|
||||||
|
curPoint: this.prePoint,
|
||||||
|
rectangleFill : this.rectangleFill
|
||||||
|
}),
|
||||||
|
})
|
||||||
} else if (this.drawMode === 'circle') {
|
} else if (this.drawMode === 'circle') {
|
||||||
//开始的时候固定好圆的起点
|
//开始的时候固定好圆的起点
|
||||||
this.circleStartPoint = this.prePoint;
|
this.circleStartPoint = this.prePoint;
|
||||||
this.drawCircle(Object.assign(commOptions, {
|
this.drawCircle({
|
||||||
circleStartPoint: this.circleStartPoint,
|
event : "start",
|
||||||
curPoint: this.prePoint,
|
drawMode: this.drawMode,
|
||||||
circleFill : this.circleFill,
|
local : Object.assign(localCommOptions, {
|
||||||
}))
|
circleStartPoint: this.circleStartPoint,
|
||||||
|
curPoint: this.prePoint,
|
||||||
|
circleFill : this.circleFill,
|
||||||
|
}),
|
||||||
|
})
|
||||||
} else if(this.drawMode === 'triangle'){
|
} else if(this.drawMode === 'triangle'){
|
||||||
//开始的时候固定好三角形的起点
|
//开始的时候固定好三角形的起点
|
||||||
this.triangleStartPoint = this.prePoint;
|
this.triangleStartPoint = this.prePoint;
|
||||||
this.drawTriangle(Object.assign(commOptions, {
|
this.drawTriangle({
|
||||||
triangleStartPoint: this.triangleStartPoint,
|
event : "start",
|
||||||
curPoint: this.prePoint,
|
drawMode: this.drawMode,
|
||||||
triangleFill : this.triangleFill
|
local : Object.assign(localCommOptions, {
|
||||||
}));
|
triangleStartPoint: this.triangleStartPoint,
|
||||||
|
curPoint: this.prePoint,
|
||||||
|
triangleFill : this.triangleFill
|
||||||
|
}),
|
||||||
|
})
|
||||||
} else if(this.drawMode === 'star'){
|
} else if(this.drawMode === 'star'){
|
||||||
//开始的时候固定好星星的起点
|
//开始的时候固定好星星的起点
|
||||||
this.starStartPoint = this.prePoint;
|
this.starStartPoint = this.prePoint;
|
||||||
this.drawStar(Object.assign(commOptions, {
|
this.drawStar({
|
||||||
starStartPoint: this.starStartPoint,
|
event : "start",
|
||||||
curPoint: this.prePoint,
|
drawMode: this.drawMode,
|
||||||
starFill : this.starFill
|
local : Object.assign(localCommOptions, {
|
||||||
}));
|
starStartPoint: this.starStartPoint,
|
||||||
|
curPoint: this.prePoint,
|
||||||
|
starFill : this.starFill
|
||||||
|
}),
|
||||||
|
})
|
||||||
} else if (this.drawMode === 'text') {
|
} else if (this.drawMode === 'text') {
|
||||||
this.drawText(Object.assign(commOptions, {
|
this.drawText({
|
||||||
curPoint: this.prePoint,
|
event : "start",
|
||||||
}))
|
drawMode: this.drawMode,
|
||||||
this.endDrawHandler(Object.assign(commOptions, {
|
local : Object.assign(localCommOptions, {
|
||||||
|
curPoint: this.prePoint,
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
this.endDrawHandler(Object.assign(localCommOptions, {
|
||||||
curPoint: this.prePoint,
|
curPoint: this.prePoint,
|
||||||
}))
|
}))
|
||||||
} else if(this.drawMode === 'line'){
|
} else if(this.drawMode === 'line'){
|
||||||
this.drawLine(Object.assign(commOptions, {
|
this.drawLine({
|
||||||
prePoint: this.prePoint,
|
event : "start",
|
||||||
curPoint: this.prePoint,
|
drawMode: this.drawMode,
|
||||||
}));
|
local : Object.assign(localCommOptions, {
|
||||||
|
prePoint: this.prePoint,
|
||||||
|
curPoint: this.prePoint,
|
||||||
|
}),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
// 绘制中
|
||||||
drawingHandler: function ({ canvas, curPoint, context, localDrawCallback }) {
|
drawingHandler: function ({ canvas, curPoint, context, localDrawCallback }) {
|
||||||
if (!this.drawing) {
|
if (!this.drawing) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
//公共参数
|
//公共参数
|
||||||
let commOptions = {
|
let localCommOptions = {
|
||||||
event : "move",
|
|
||||||
canvas,
|
canvas,
|
||||||
context,
|
context,
|
||||||
localDrawCallback,
|
localDrawCallback,
|
||||||
drawMode: this.drawMode,
|
devicePixelRatio : this.devicePixelRatio,
|
||||||
|
width : canvas.width,
|
||||||
|
height: canvas.height,
|
||||||
|
lineCap: this.lineCap,
|
||||||
|
lineJoin: this.lineJoin,
|
||||||
lineWidth: this.lineWidth,
|
lineWidth: this.lineWidth,
|
||||||
strokeStyle: this.strokeStyle,
|
strokeStyle: this.strokeStyle,
|
||||||
fillStyle: this.strokeStyle,
|
fillStyle: this.strokeStyle,
|
||||||
lineCap: "round",
|
|
||||||
lineJoin: "round"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.drawMode === 'delete') {
|
if (this.drawMode === 'delete') {
|
||||||
this.drawDelete(Object.assign(commOptions, {
|
this.drawDelete({
|
||||||
prePoint: this.prePoint,
|
event : "move",
|
||||||
curPoint
|
drawMode: this.drawMode,
|
||||||
}))
|
local : Object.assign(localCommOptions, {
|
||||||
|
prePoint: this.prePoint,
|
||||||
|
curPoint
|
||||||
|
}),
|
||||||
|
})
|
||||||
} else if (this.drawMode === 'rectangle') {
|
} else if (this.drawMode === 'rectangle') {
|
||||||
this.drawRectangle(Object.assign(commOptions, {
|
this.drawRectangle({
|
||||||
rectangleStartPoint: this.rectangleStartPoint,
|
event : "move",
|
||||||
curPoint,
|
drawMode: this.drawMode,
|
||||||
rectangleFill : this.rectangleFill
|
local : Object.assign(localCommOptions, {
|
||||||
}));
|
rectangleStartPoint: this.rectangleStartPoint,
|
||||||
|
curPoint,
|
||||||
|
rectangleFill : this.rectangleFill
|
||||||
|
}),
|
||||||
|
})
|
||||||
} else if (this.drawMode === 'circle') {
|
} else if (this.drawMode === 'circle') {
|
||||||
this.drawCircle(Object.assign(commOptions, {
|
this.drawCircle({
|
||||||
circleStartPoint: this.circleStartPoint,
|
event : "move",
|
||||||
curPoint,
|
drawMode: this.drawMode,
|
||||||
circleFill : this.circleFill,
|
local : Object.assign(localCommOptions, {
|
||||||
}))
|
circleStartPoint: this.circleStartPoint,
|
||||||
|
curPoint,
|
||||||
|
circleFill : this.circleFill,
|
||||||
|
}),
|
||||||
|
})
|
||||||
} else if(this.drawMode === 'triangle'){
|
} else if(this.drawMode === 'triangle'){
|
||||||
this.drawTriangle(Object.assign(commOptions, {
|
this.drawTriangle({
|
||||||
triangleStartPoint: this.triangleStartPoint,
|
event : "move",
|
||||||
curPoint,
|
drawMode: this.drawMode,
|
||||||
triangleFill : this.triangleFill
|
local : Object.assign(localCommOptions, {
|
||||||
}));
|
triangleStartPoint: this.triangleStartPoint,
|
||||||
|
curPoint,
|
||||||
|
triangleFill : this.triangleFill
|
||||||
|
}),
|
||||||
|
|
||||||
|
})
|
||||||
} else if(this.drawMode === 'star'){
|
} else if(this.drawMode === 'star'){
|
||||||
this.drawStar(Object.assign(commOptions, {
|
this.drawStar({
|
||||||
starStartPoint: this.starStartPoint,
|
event : "move",
|
||||||
curPoint,
|
drawMode: this.drawMode,
|
||||||
starFill : this.starFill
|
local : Object.assign(localCommOptions, {
|
||||||
}));
|
starStartPoint: this.starStartPoint,
|
||||||
|
curPoint,
|
||||||
|
starFill : this.starFill
|
||||||
|
}),
|
||||||
|
})
|
||||||
} else if(this.drawMode === 'line'){
|
} else if(this.drawMode === 'line'){
|
||||||
this.drawLine(Object.assign(commOptions, {
|
this.drawLine({
|
||||||
prePoint: this.prePoint,
|
event : "move",
|
||||||
curPoint,
|
drawMode: this.drawMode,
|
||||||
}));
|
local : Object.assign(localCommOptions, {
|
||||||
|
prePoint: this.prePoint,
|
||||||
|
curPoint,
|
||||||
|
}),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
// 结束绘制
|
||||||
endDrawHandler: function ({ canvas, curPoint, context, localDrawCallback }) {
|
endDrawHandler: function ({ canvas, curPoint, context, localDrawCallback }) {
|
||||||
//图像记录,用于回滚撤销操作
|
//图像记录,用于回滚撤销操作
|
||||||
if (
|
if (
|
||||||
@@ -600,13 +688,12 @@ const draw = new Vue({
|
|||||||
//结束的时候通知下远程,可以保存画布到缓存列表中
|
//结束的时候通知下远程,可以保存画布到缓存列表中
|
||||||
localDrawCallback && localDrawCallback({
|
localDrawCallback && localDrawCallback({
|
||||||
event : "end",
|
event : "end",
|
||||||
drawMode : this.drawMode
|
drawMode : this.drawMode,
|
||||||
|
remote : {}
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
//下载画布图片
|
// 下载画布图片
|
||||||
drawDownload: function ( options ) {
|
drawDownload: function ({ canvas, context, localDrawCallback }) {
|
||||||
const { canvas, context, localDrawCallback } = options;
|
|
||||||
|
|
||||||
let image = canvas.toDataURL("image/png").replace("image/png", "image/octet-stream");
|
let image = canvas.toDataURL("image/png").replace("image/png", "image/octet-stream");
|
||||||
let link = document.createElement('a');
|
let link = document.createElement('a');
|
||||||
link.href = image;
|
link.href = image;
|
||||||
@@ -614,16 +701,13 @@ const draw = new Vue({
|
|||||||
link.click();
|
link.click();
|
||||||
},
|
},
|
||||||
// 画布重置
|
// 画布重置
|
||||||
drawReset: function (options) {
|
drawReset: function ({ canvas, context, localDrawCallback }) {
|
||||||
const { canvas, context, localDrawCallback } = options;
|
|
||||||
|
|
||||||
context.clearRect(0, 0, canvas.width, canvas.height);
|
context.clearRect(0, 0, canvas.width, canvas.height);
|
||||||
this.drawHistoryList = [];
|
this.drawHistoryList = [];
|
||||||
this.drawRollbackPoint = 0;
|
this.drawRollbackPoint = 0;
|
||||||
},
|
},
|
||||||
// 回退回滚的绘制
|
// 回退回滚的绘制
|
||||||
drawUndoRollback: function (options) {
|
drawUndoRollback: function ({ canvas, context, localDrawCallback }) {
|
||||||
const { canvas, context, localDrawCallback } = options;
|
|
||||||
//最多前进到最后一条记录
|
//最多前进到最后一条记录
|
||||||
if (this.drawRollbackPoint < this.drawHistoryList.length - 1) {
|
if (this.drawRollbackPoint < this.drawHistoryList.length - 1) {
|
||||||
this.drawRollbackPoint = this.drawRollbackPoint + 1;
|
this.drawRollbackPoint = this.drawRollbackPoint + 1;
|
||||||
@@ -637,8 +721,7 @@ const draw = new Vue({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
// 画布回退
|
// 画布回退
|
||||||
drawRollback: async function (options) {
|
drawRollback: async function ({ canvas, context, localDrawCallback }) {
|
||||||
const { canvas, context, localDrawCallback } = options;
|
|
||||||
//最多回退到原点
|
//最多回退到原点
|
||||||
if (this.drawRollbackPoint > 0) {
|
if (this.drawRollbackPoint > 0) {
|
||||||
this.drawRollbackPoint = this.drawRollbackPoint - 1;
|
this.drawRollbackPoint = this.drawRollbackPoint - 1;
|
||||||
@@ -651,9 +734,17 @@ const draw = new Vue({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
// 画笔擦除
|
// 画笔擦除
|
||||||
drawDelete: function (options) {
|
drawDelete: function ({ event, drawMode, local : {
|
||||||
const { canvas, context, prePoint, curPoint, localDrawCallback } = options;
|
canvas, context, lineWidth, curPoint, prePoint, lineCap,
|
||||||
context.lineWidth = this.lineWidth;
|
width, height, devicePixelRatio,
|
||||||
|
lineJoin, strokeStyle, fillStyle
|
||||||
|
}}) {
|
||||||
|
context.lineWidth = lineWidth;
|
||||||
|
context.lineCap = lineCap;
|
||||||
|
context.lineJoin = lineJoin;
|
||||||
|
context.strokeStyle = strokeStyle;
|
||||||
|
context.fillStyle = fillStyle;
|
||||||
|
|
||||||
//防止移动过快,canvas渲染存在间隔,导致线条断层,在这里补充绘制间隔的点
|
//防止移动过快,canvas渲染存在间隔,导致线条断层,在这里补充绘制间隔的点
|
||||||
let x = prePoint.x;
|
let x = prePoint.x;
|
||||||
let y = prePoint.y;
|
let y = prePoint.y;
|
||||||
@@ -666,14 +757,17 @@ const draw = new Vue({
|
|||||||
while (i < distance) {
|
while (i < distance) {
|
||||||
x += xUnit;
|
x += xUnit;
|
||||||
y += yUnit;
|
y += yUnit;
|
||||||
context.clearRect(x - 20, y - 20, this.lineWidth, this.lineWidth);
|
context.clearRect(x - 20, y - 20, lineWidth, lineWidth);
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
// 图片渲染处理
|
// 图片渲染处理
|
||||||
drawImage: function (options) {
|
drawImage: function ({ event, drawMode, local : {
|
||||||
|
canvas, context, lineWidth, curPoint, prePoint, lineCap,
|
||||||
|
width, height, devicePixelRatio,
|
||||||
|
lineJoin, strokeStyle, fillStyle, localDrawCallback
|
||||||
|
}}) {
|
||||||
let that = this;
|
let that = this;
|
||||||
const { canvas, context, localDrawCallback } = options;
|
|
||||||
let input = document.createElement("input");
|
let input = document.createElement("input");
|
||||||
input.setAttribute("type", "file");
|
input.setAttribute("type", "file");
|
||||||
input.setAttribute("accept", "image/*");
|
input.setAttribute("accept", "image/*");
|
||||||
@@ -695,11 +789,14 @@ const draw = new Vue({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
// 画笔渲染处理, 两点式绘制
|
// 画笔渲染处理, 两点式绘制
|
||||||
drawLine: function (options) {
|
drawLine: function ({ event, drawMode, fromRemote, local, remote}) {
|
||||||
const {
|
if(fromRemote){
|
||||||
canvas, context, localDrawCallback, prePoint, curPoint,
|
local = remote;
|
||||||
lineWidth, strokeStyle, fillStyle, lineCap, lineJoin, fromRemote,
|
}
|
||||||
} = options;
|
let {
|
||||||
|
canvas, context, lineWidth, curPoint, prePoint, lineCap,
|
||||||
|
width, height, devicePixelRatio, lineJoin, strokeStyle, fillStyle, localDrawCallback
|
||||||
|
} = local;
|
||||||
|
|
||||||
// 设置画笔样式
|
// 设置画笔样式
|
||||||
context.lineWidth = lineWidth;
|
context.lineWidth = lineWidth;
|
||||||
@@ -728,16 +825,23 @@ const draw = new Vue({
|
|||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!fromRemote) { //本地的绘制数据回调给远端
|
//如果是本地绘制,完成绘制后数据回调给远端
|
||||||
localDrawCallback && localDrawCallback(options);
|
if (!fromRemote) {
|
||||||
|
localDrawCallback && localDrawCallback({ event, drawMode, fromRemote : true, remote : {
|
||||||
|
lineWidth, curPoint, prePoint, lineCap, width, height, devicePixelRatio,
|
||||||
|
lineJoin, strokeStyle, fillStyle,
|
||||||
|
}});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
// 星星渲染处理
|
// 星星渲染处理
|
||||||
drawStar: function (options) {
|
drawStar: function ({ event, drawMode, fromRemote, local, remote}) {
|
||||||
const {
|
if(fromRemote){
|
||||||
canvas, context, localDrawCallback, starStartPoint, curPoint,
|
local = remote;
|
||||||
lineWidth, strokeStyle, fillStyle, lineCap, lineJoin, fromRemote, starFill
|
}
|
||||||
} = options;
|
let {
|
||||||
|
canvas, context, lineWidth, curPoint, starStartPoint, lineCap, starFill,
|
||||||
|
width, height, devicePixelRatio, lineJoin, strokeStyle, fillStyle, localDrawCallback
|
||||||
|
} = local;
|
||||||
|
|
||||||
// 设置画笔样式
|
// 设置画笔样式
|
||||||
context.lineWidth = lineWidth;
|
context.lineWidth = lineWidth;
|
||||||
@@ -778,16 +882,23 @@ const draw = new Vue({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!fromRemote) { //本地的绘制数据回调给远端
|
//如果是本地绘制,完成绘制后数据回调给远端
|
||||||
localDrawCallback && localDrawCallback(options);
|
if (!fromRemote) {
|
||||||
|
localDrawCallback && localDrawCallback({ event, drawMode, fromRemote : true, remote : {
|
||||||
|
lineWidth, curPoint, starStartPoint, lineCap, width, height, devicePixelRatio,
|
||||||
|
lineJoin, strokeStyle, fillStyle, starFill
|
||||||
|
}});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
// 三角形渲染处理
|
// 三角形渲染处理
|
||||||
drawTriangle: function (options) {
|
drawTriangle: function ({ event, drawMode, fromRemote, local, remote }) {
|
||||||
const {
|
if(fromRemote){
|
||||||
canvas, context, localDrawCallback, triangleStartPoint, curPoint,
|
local = remote;
|
||||||
lineWidth, strokeStyle, fillStyle, lineCap, lineJoin, fromRemote, triangleFill
|
}
|
||||||
} = options;
|
let {
|
||||||
|
canvas, context, lineWidth, curPoint, triangleStartPoint, lineCap, triangleFill,
|
||||||
|
width, height, devicePixelRatio, lineJoin, strokeStyle, fillStyle, localDrawCallback
|
||||||
|
} = local;
|
||||||
|
|
||||||
// 设置画笔样式
|
// 设置画笔样式
|
||||||
context.lineWidth = lineWidth;
|
context.lineWidth = lineWidth;
|
||||||
@@ -827,16 +938,23 @@ const draw = new Vue({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!fromRemote) { //本地的绘制数据回调给远端
|
//如果是本地绘制,完成绘制后数据回调给远端
|
||||||
localDrawCallback && localDrawCallback(options);
|
if (!fromRemote) {
|
||||||
|
localDrawCallback && localDrawCallback({ event, drawMode, fromRemote : true, remote : {
|
||||||
|
lineWidth, curPoint, triangleStartPoint, lineCap, width, height, devicePixelRatio,
|
||||||
|
lineJoin, strokeStyle, fillStyle, triangleFill
|
||||||
|
}});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
// 圆形渲染处理
|
// 圆形渲染处理
|
||||||
drawCircle: function (options) {
|
drawCircle: function ({ event, drawMode, fromRemote, local, remote }) {
|
||||||
const {
|
if(fromRemote){
|
||||||
canvas, context, localDrawCallback, circleStartPoint, curPoint,
|
local = remote;
|
||||||
lineWidth, strokeStyle, fillStyle, lineCap, lineJoin, fromRemote, circleFill
|
}
|
||||||
} = options;
|
let {
|
||||||
|
canvas, context, lineWidth, curPoint, circleStartPoint, lineCap, circleFill,
|
||||||
|
width, height, devicePixelRatio, lineJoin, strokeStyle, fillStyle, localDrawCallback
|
||||||
|
} = local;
|
||||||
|
|
||||||
// 设置画笔样式
|
// 设置画笔样式
|
||||||
context.lineWidth = lineWidth;
|
context.lineWidth = lineWidth;
|
||||||
@@ -869,16 +987,23 @@ const draw = new Vue({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!fromRemote) { //本地的绘制数据回调给远端
|
//如果是本地绘制,完成绘制后数据回调给远端
|
||||||
localDrawCallback && localDrawCallback(options);
|
if (!fromRemote) {
|
||||||
|
localDrawCallback && localDrawCallback({ event, drawMode, fromRemote : true, remote : {
|
||||||
|
lineWidth, curPoint, circleStartPoint, lineCap, width, height, devicePixelRatio,
|
||||||
|
lineJoin, strokeStyle, fillStyle, circleFill
|
||||||
|
}});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
// 矩形渲染处理
|
// 矩形渲染处理
|
||||||
drawRectangle: function (options) {
|
drawRectangle: function ({ event, drawMode, fromRemote, local, remote }) {
|
||||||
const {
|
if(fromRemote){
|
||||||
canvas, context, localDrawCallback, rectangleStartPoint, curPoint,
|
local = remote;
|
||||||
lineWidth, strokeStyle, fillStyle, lineCap, lineJoin, fromRemote, rectangleFill
|
}
|
||||||
} = options;
|
let {
|
||||||
|
canvas, context, lineWidth, curPoint, rectangleStartPoint, lineCap, rectangleFill,
|
||||||
|
width, height, devicePixelRatio, lineJoin, strokeStyle, fillStyle, localDrawCallback
|
||||||
|
} = local;
|
||||||
|
|
||||||
// 设置画笔样式
|
// 设置画笔样式
|
||||||
context.lineWidth = lineWidth;
|
context.lineWidth = lineWidth;
|
||||||
@@ -890,8 +1015,8 @@ const draw = new Vue({
|
|||||||
// 计算矩形的位置和尺寸
|
// 计算矩形的位置和尺寸
|
||||||
const x = Math.min(rectangleStartPoint.x, curPoint.x);
|
const x = Math.min(rectangleStartPoint.x, curPoint.x);
|
||||||
const y = Math.min(rectangleStartPoint.y, curPoint.y);
|
const y = Math.min(rectangleStartPoint.y, curPoint.y);
|
||||||
const width = Math.abs(curPoint.x - rectangleStartPoint.x);
|
const rwidth = Math.abs(curPoint.x - rectangleStartPoint.x);
|
||||||
const height = Math.abs(curPoint.y - rectangleStartPoint.y);
|
const rheight = Math.abs(curPoint.y - rectangleStartPoint.y);
|
||||||
|
|
||||||
if (this.drawRollbackPoint >= 0) {
|
if (this.drawRollbackPoint >= 0) {
|
||||||
const img = new Image();
|
const img = new Image();
|
||||||
@@ -903,7 +1028,7 @@ const draw = new Vue({
|
|||||||
context.drawImage(img, 0, 0, canvas.width, canvas.height);
|
context.drawImage(img, 0, 0, canvas.width, canvas.height);
|
||||||
//绘制新矩形
|
//绘制新矩形
|
||||||
context.beginPath();
|
context.beginPath();
|
||||||
context.rect(x, y, width, height);
|
context.rect(x, y, rwidth, rheight);
|
||||||
if(rectangleFill){
|
if(rectangleFill){
|
||||||
context.fill();
|
context.fill();
|
||||||
}
|
}
|
||||||
@@ -911,43 +1036,58 @@ const draw = new Vue({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!fromRemote) { //本地的绘制数据回调给远端
|
//如果是本地绘制,完成绘制后数据回调给远端
|
||||||
localDrawCallback && localDrawCallback(options);
|
if (!fromRemote) {
|
||||||
|
localDrawCallback && localDrawCallback({ event, drawMode, fromRemote : true, remote : {
|
||||||
|
lineWidth, curPoint, rectangleStartPoint, lineCap, width, height, devicePixelRatio,
|
||||||
|
lineJoin, strokeStyle, fillStyle, rectangleFill
|
||||||
|
}});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
// 文字渲染处理
|
// 文字渲染处理
|
||||||
drawText: function (options) {
|
drawText: function ({ event, drawMode, fromRemote, local, remote }) {
|
||||||
let {
|
if(fromRemote){
|
||||||
canvas, context, localDrawCallback, curPoint, text, lineWidth, strokeStyle,
|
local = remote;
|
||||||
fillStyle, lineCap, lineJoin, fromRemote,
|
}
|
||||||
} = options;
|
let {
|
||||||
|
canvas, context, lineWidth, curPoint, text, lineCap,
|
||||||
|
width, height, devicePixelRatio, lineJoin, strokeStyle, fillStyle, localDrawCallback
|
||||||
|
} = local;
|
||||||
|
|
||||||
curPoint = {
|
curPoint = {
|
||||||
x : curPoint.x / window.devicePixelRatio,
|
x : curPoint.x / devicePixelRatio,
|
||||||
y : curPoint.y / window.devicePixelRatio
|
y : curPoint.y / devicePixelRatio
|
||||||
}
|
}
|
||||||
|
|
||||||
// 设置字体样式
|
// 设置字体样式
|
||||||
context.strokeStyle = strokeStyle;
|
context.strokeStyle = strokeStyle;
|
||||||
context.font = "28px orbitron";
|
context.font = Math.min(lineWidth * 7, 28) + "px orbitron";
|
||||||
context.textBaseline = "middle";
|
context.textBaseline = "middle";
|
||||||
context.lineCap = lineCap;
|
context.lineCap = lineCap;
|
||||||
context.lineJoin = lineJoin;
|
context.lineJoin = lineJoin;
|
||||||
context.lineWidth = 3;
|
context.lineWidth = 1;
|
||||||
|
|
||||||
const canvasWidth = parseInt(canvas.style.width);
|
const canvasWidth = parseInt(canvas.style.width);
|
||||||
const canvasHeight = parseInt(canvas.style.height);
|
const canvasHeight = parseInt(canvas.style.height);
|
||||||
|
|
||||||
//文字渲染处理
|
//文字渲染处理
|
||||||
function drawTextHandler(content){
|
function drawTextHandler(content){
|
||||||
const textWidth = context.measureText(content).width;
|
let words = content.split("");
|
||||||
// 如果文字超出画布宽度,将文字绘制到画布最右边
|
let subWords = "";
|
||||||
let fixPointX = canvasWidth - textWidth > curPoint.x ? curPoint.x : canvasWidth - textWidth;
|
let wordHeight = 40;
|
||||||
fixPointX = fixPointX < 10 ? 10 : fixPointX;
|
for(let i = 0; i < words.length; i++){
|
||||||
// 如果文字超出画布高度,将文字绘制到画布最下边
|
let curSubWords = subWords + words[i];
|
||||||
let fixPointY = canvasHeight - 20 > curPoint.y ? curPoint.y : canvasHeight - 20;
|
const curSubWordsWidth = context.measureText(curSubWords).width;
|
||||||
fixPointY = fixPointY < 10 ? 10 : fixPointY;
|
|
||||||
context.strokeText(content, fixPointX * window.devicePixelRatio, fixPointY * window.devicePixelRatio);
|
if(curPoint.x + curSubWordsWidth > canvasWidth && i > 0){
|
||||||
|
context.fillText(subWords, curPoint.x * devicePixelRatio, curPoint.y * devicePixelRatio);
|
||||||
|
subWords = words[i];
|
||||||
|
curPoint.y += wordHeight;
|
||||||
|
}else{
|
||||||
|
subWords = curSubWords;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
context.fillText(subWords, curPoint.x * devicePixelRatio, curPoint.y * devicePixelRatio);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(fromRemote){
|
if(fromRemote){
|
||||||
@@ -983,7 +1123,7 @@ const draw = new Vue({
|
|||||||
} else if (curPoint.y < 100) {
|
} else if (curPoint.y < 100) {
|
||||||
textarea.style.bottom = (canvasHeight - 100) + 'px';
|
textarea.style.bottom = (canvasHeight - 100) + 'px';
|
||||||
} else {
|
} else {
|
||||||
textarea.style.top = (curPoint.y + 70)+ 'px';
|
textarea.style.top = (curPoint.y + 170)+ 'px';
|
||||||
}
|
}
|
||||||
parentDom.appendChild(textarea);
|
parentDom.appendChild(textarea);
|
||||||
textarea.focus();
|
textarea.focus();
|
||||||
@@ -992,8 +1132,11 @@ const draw = new Vue({
|
|||||||
if (textarea.value !== '') {
|
if (textarea.value !== '') {
|
||||||
drawTextHandler(textarea.value);
|
drawTextHandler(textarea.value);
|
||||||
document.getElementById("drawLine").click()
|
document.getElementById("drawLine").click()
|
||||||
options.text = textarea.value;
|
|
||||||
localDrawCallback && localDrawCallback(options);
|
localDrawCallback && localDrawCallback({ event, drawMode, fromRemote : true, remote : {
|
||||||
|
lineWidth, curPoint, lineCap, width, height, devicePixelRatio, text : textarea.value,
|
||||||
|
lineJoin, strokeStyle, fillStyle,
|
||||||
|
}});
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@@ -204,8 +204,102 @@ axios.get("/api/comm/initData?turn="+useTurn, {}).then((initData) => {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
updateRemoteRtcState : async function(){
|
||||||
|
for(let id in this.remoteMap){
|
||||||
|
let stat = await window.tlrtcfile.getWebrtcStats(
|
||||||
|
this.getOrCreateRtcConnect(id)
|
||||||
|
);
|
||||||
|
let remoteCandidate = stat.get("remote-candidate") || [];
|
||||||
|
let p2pModes = remoteCandidate.map(item => {
|
||||||
|
if(['host','srflx','prflx'].includes(item.report.candidateType)){
|
||||||
|
return "直连"
|
||||||
|
}else if(item.report.candidateType === 'relay'){
|
||||||
|
return "中继"
|
||||||
|
}else{
|
||||||
|
return "未知"
|
||||||
|
}
|
||||||
|
})
|
||||||
|
this.setRemoteInfo(id, {
|
||||||
|
//p2p连接模式: host, srflx, prflx, relay
|
||||||
|
p2pMode : Array.from(new Set(p2pModes)).join(",")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
this.$forceUpdate()
|
||||||
|
},
|
||||||
|
showRemoteUser : async function(remote){
|
||||||
|
let stat = await window.tlrtcfile.getWebrtcStats(this.getOrCreateRtcConnect(remote.id));
|
||||||
|
const rtcStatList = [];
|
||||||
|
stat.forEach((value, key)=>{
|
||||||
|
rtcStatList.push(
|
||||||
|
...value.map(item => {
|
||||||
|
return Object.assign(item.report, {
|
||||||
|
description_zh: item.description
|
||||||
|
})
|
||||||
|
})
|
||||||
|
)
|
||||||
|
})
|
||||||
|
let rtcStatDomList = '';
|
||||||
|
rtcStatList.forEach(statItem => {
|
||||||
|
let rtcStatDomVal = ` <div> description_zh: <b>${statItem.description_zh}</b> </div> `;
|
||||||
|
for(let key in statItem){
|
||||||
|
if(key === 'description_zh'){
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
rtcStatDomVal += ` <div> ${key}: <b>${statItem[key]}</b> </div> `;
|
||||||
|
}
|
||||||
|
rtcStatDomList += ` <div> ${rtcStatDomVal} </div> `;
|
||||||
|
})
|
||||||
|
|
||||||
|
let that = this;
|
||||||
|
layer.closeAll(function () {
|
||||||
|
layer.open({
|
||||||
|
type: 1,
|
||||||
|
closeBtn: 0,
|
||||||
|
fixed: true,
|
||||||
|
maxmin: false,
|
||||||
|
shadeClose: true,
|
||||||
|
area: ['350px', '380px'],
|
||||||
|
title: `rtc连接实时统计信息`,
|
||||||
|
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";
|
||||||
|
document.querySelector(".layui-layer").style.background = "#f8f8f8";
|
||||||
|
|
||||||
|
carousel.render({
|
||||||
|
elem: '#tl-rtc-file-rtcinfo',
|
||||||
|
width: '100%',
|
||||||
|
autoplay : false,
|
||||||
|
indicator: 'outside'
|
||||||
|
});
|
||||||
|
},
|
||||||
|
content: `
|
||||||
|
<div class="remote_user_info layui-carousel" id="tl-rtc-file-rtcinfo">
|
||||||
|
<div carousel-item>
|
||||||
|
<div>
|
||||||
|
<div> ${that.lang.userid}: <b>${remote.id}</b> </div>
|
||||||
|
<div> ${that.lang.nickname}: <b>${remote.nickName}</b> </div>
|
||||||
|
<div> ${that.lang.room_channel}: <b>${that.roomId}</b> </div>
|
||||||
|
<div> ${that.lang.website_language}: <b>${remote.langMode}</b> </div>
|
||||||
|
<div> ${that.lang.network_status}: <b>${remote.network}</b> </div>
|
||||||
|
<div> ${that.lang.join_time}: <b>${remote.joinTime}</b> </div>
|
||||||
|
<div> ${that.lang.public_ip}: <b>${remote.ip}</b> </div>
|
||||||
|
<div> ${that.lang.webrtc_ice_state}: <b>${remote.iceConnectionState}</b> </div>
|
||||||
|
<div> ${that.lang.device_classification}: <b>${remote.ua}</b> </div>
|
||||||
|
<div> ${that.lang.terminal_equipment}: <b>${remote.userAgent}</b> </div>
|
||||||
|
</div>
|
||||||
|
${rtcStatDomList}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`
|
||||||
|
})
|
||||||
|
})
|
||||||
|
},
|
||||||
|
iceOk : function(state){
|
||||||
|
return ['completed', 'connected', 'checking', 'new'].includes(state);
|
||||||
|
},
|
||||||
consoleLogo : function(){
|
consoleLogo : function(){
|
||||||
window.console.log(`%c____ TL-RTC-FILE-V10.1.5 ____ \n____ FORK ME IN GITHUB ____ \n____ https://github.com/tl-open-source/tl-rtc-file ____`, this.logo)
|
window.console.log(`%c____ TL-RTC-FILE-V${this.version} ____ \n____ FORK ME IN GITHUB ____ \n____ https://github.com/tl-open-source/tl-rtc-file ____`, this.logo)
|
||||||
},
|
},
|
||||||
changeLanguage: function () {
|
changeLanguage: function () {
|
||||||
let that = this;
|
let that = this;
|
||||||
@@ -291,9 +385,7 @@ axios.get("/api/comm/initData?turn="+useTurn, {}).then((initData) => {
|
|||||||
let file = filterFile[0]
|
let file = filterFile[0]
|
||||||
|
|
||||||
if (file.size > this.uploadCodeFileMaxSize) {
|
if (file.size > this.uploadCodeFileMaxSize) {
|
||||||
if(window.layer){
|
layer.msg(`${this.lang.max_saved} ${this.uploadCodeFileMaxSize / 1024 / 1024} ${this.lang.mb_file}`);
|
||||||
layer.msg(`${this.lang.max_saved} ${this.uploadCodeFileMaxSize / 1024 / 1024} ${this.lang.mb_file}`);
|
|
||||||
}
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -363,7 +455,8 @@ axios.get("/api/comm/initData?turn="+useTurn, {}).then((initData) => {
|
|||||||
this.initSendFile(recoder);
|
this.initSendFile(recoder);
|
||||||
},
|
},
|
||||||
// 私聊弹窗
|
// 私聊弹窗
|
||||||
startChatRoomSingle: function(remote){
|
startChatRoomSingle: function(event, remote){
|
||||||
|
event.stopPropagation();
|
||||||
this.chatRoomSingleSocketId = remote.id;
|
this.chatRoomSingleSocketId = remote.id;
|
||||||
let that = this;
|
let that = this;
|
||||||
let options = {
|
let options = {
|
||||||
@@ -433,7 +526,7 @@ axios.get("/api/comm/initData?turn="+useTurn, {}).then((initData) => {
|
|||||||
</div>
|
</div>
|
||||||
<div class="chating_input_body">
|
<div class="chating_input_body">
|
||||||
<textarea maxlength="50000" id="chating_room_single_value" class="layui-textarea" placeholder="${this.lang.communication_rational} ~"></textarea>
|
<textarea maxlength="50000" id="chating_room_single_value" class="layui-textarea" placeholder="${this.lang.communication_rational} ~"></textarea>
|
||||||
<span class="chating_send_body chating_send_body_span">shift+enter ${this.lang.enter_send} </span>
|
<span class="chating_send_body chating_send_body_span">shift+enter | ${this.lang.enter_send} </span>
|
||||||
<button onclick="sendChatingRoomSingle()" type="button" class="layui-btn layui-btn-normal layui-btn-sm chating_send_body chating_send_body_button">${this.lang.send_chat}</button>
|
<button onclick="sendChatingRoomSingle()" type="button" class="layui-btn layui-btn-normal layui-btn-sm chating_send_body chating_send_body_button">${this.lang.send_chat}</button>
|
||||||
</div>
|
</div>
|
||||||
`
|
`
|
||||||
@@ -626,7 +719,7 @@ axios.get("/api/comm/initData?turn="+useTurn, {}).then((initData) => {
|
|||||||
|
|
||||||
let fileRecorde = filterFile[0];
|
let fileRecorde = filterFile[0];
|
||||||
if (fileRecorde.size > this.previewFileMaxSize) {
|
if (fileRecorde.size > this.previewFileMaxSize) {
|
||||||
layer.msg(`${this.lang.max_previewed} ${this.previewFileMaxSize / 1024 / 1024} ${mb_file}`);
|
layer.msg(`${this.lang.max_previewed} ${this.previewFileMaxSize / 1024 / 1024} ${this.lang.mb_file}`);
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -853,7 +946,7 @@ axios.get("/api/comm/initData?turn="+useTurn, {}).then((initData) => {
|
|||||||
|
|
||||||
<div class="chating_input_body">
|
<div class="chating_input_body">
|
||||||
<textarea maxlength="50000" id="openaiChat_value" class="layui-textarea" placeholder="${this.lang.communication_rational} ~"></textarea>
|
<textarea maxlength="50000" id="openaiChat_value" class="layui-textarea" placeholder="${this.lang.communication_rational} ~"></textarea>
|
||||||
<span class="chating_send_body chating_send_body_span">shift+enter ${this.lang.enter_send} </span>
|
<span class="chating_send_body chating_send_body_span">shift+enter | ${this.lang.enter_send} </span>
|
||||||
<button onclick="sendOpenaiChat()" type="button" class="layui-btn layui-btn-normal layui-btn-sm chating_send_body chating_send_body_button">${this.lang.send_chat}</button>
|
<button onclick="sendOpenaiChat()" type="button" class="layui-btn layui-btn-normal layui-btn-sm chating_send_body chating_send_body_button">${this.lang.send_chat}</button>
|
||||||
</div>
|
</div>
|
||||||
`
|
`
|
||||||
@@ -1007,11 +1100,11 @@ axios.get("/api/comm/initData?turn="+useTurn, {}).then((initData) => {
|
|||||||
|
|
||||||
layer.prompt({
|
layer.prompt({
|
||||||
formType: 1,
|
formType: 1,
|
||||||
title: this.lang.please_enter_password
|
title: that.lang.please_enter_password
|
||||||
}, function (value, index, elem) {
|
}, function (value, index, elem) {
|
||||||
that.createPasswordRoom(value);
|
that.createPasswordRoom(value);
|
||||||
layer.close(index);
|
layer.close(index);
|
||||||
that.addUserLogs(this.lang.enter_password_room + that.roomId + `,${this.lang.password}:` + value);
|
that.addUserLogs(that.lang.enter_password_room + that.roomId + `,${that.lang.password}:` + value);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -1124,12 +1217,12 @@ axios.get("/api/comm/initData?turn="+useTurn, {}).then((initData) => {
|
|||||||
<div class="setting-main">
|
<div class="setting-main">
|
||||||
<div class="setting-main-body">
|
<div class="setting-main-body">
|
||||||
<div class="relayDoc" style="padding: 15px; position: absolute; width: 100%; height: 100%;">
|
<div class="relayDoc" style="padding: 15px; position: absolute; width: 100%; height: 100%;">
|
||||||
<p style="text-align: center; font-weight: bold; position: relative; top: 2px; display: block; font-size: 17px;"> ${this.lang.relay_server_current} ${useTurn ? this.lang.on : this.lang.off} </p>
|
<p style="text-align: center; font-weight: bold; position: relative; top: 2px; display: block; font-size: 17px;"> ${this.lang.relay_server_current} '${useTurn ? this.lang.on : this.lang.off}' </p>
|
||||||
<p style="font-weight: bold; position: relative; top: 15px; display: block; font-size: 14px;"> ${this.lang.relay_server_current_detail} </p>
|
<p style="font-weight: bold; position: relative; top: 15px; display: block; font-size: 14px;height: 80%;"> ${this.lang.relay_server_current_detail} </p>
|
||||||
<div style="position: relative; margin-top: 140px;">
|
<div>
|
||||||
<div style="text-align: center;">
|
<div style="text-align: center;">
|
||||||
<button onclick="useTurn()" type="button" class="layui-btn layui-btn-sm layui-btn-normal" style="margin-right: 45px;"> ${this.lang.on} </button>
|
<button onclick="useTurn()" type="button" class="layui-btn layui-btn-sm layui-btn-primary layui-border-blue" style="margin-right: 45px;"> ${this.lang.on} </button>
|
||||||
<button onclick="useTurn()" type="button" class="layui-btn layui-btn-sm layui-btn-danger"> ${this.lang.off} </button>
|
<button onclick="useTurn()" type="button" class="layui-btn layui-btn-sm layui-btn-primary layui-border-red"> ${this.lang.off} </button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -1180,11 +1273,11 @@ axios.get("/api/comm/initData?turn="+useTurn, {}).then((initData) => {
|
|||||||
});
|
});
|
||||||
that.clickMediaVideo();
|
that.clickMediaVideo();
|
||||||
that.isVideoShare = !that.isVideoShare;
|
that.isVideoShare = !that.isVideoShare;
|
||||||
that.addUserLogs(this.lang.start_video_call);
|
that.addUserLogs(that.lang.start_video_call);
|
||||||
}else{
|
}else{
|
||||||
layer.prompt({
|
layer.prompt({
|
||||||
formType: 1,
|
formType: 1,
|
||||||
title: this.lang.please_enter_video_call_room_num
|
title: that.lang.please_enter_video_call_room_num
|
||||||
}, function (value, index, elem) {
|
}, function (value, index, elem) {
|
||||||
that.roomId = value;
|
that.roomId = value;
|
||||||
that.createMediaRoom("video");
|
that.createMediaRoom("video");
|
||||||
@@ -1197,7 +1290,7 @@ axios.get("/api/comm/initData?turn="+useTurn, {}).then((initData) => {
|
|||||||
});
|
});
|
||||||
that.clickMediaVideo();
|
that.clickMediaVideo();
|
||||||
that.isVideoShare = !that.isVideoShare;
|
that.isVideoShare = !that.isVideoShare;
|
||||||
that.addUserLogs(this.lang.start_video_call);
|
that.addUserLogs(that.lang.start_video_call);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -1239,7 +1332,7 @@ axios.get("/api/comm/initData?turn="+useTurn, {}).then((initData) => {
|
|||||||
});
|
});
|
||||||
that.clickMediaScreen();
|
that.clickMediaScreen();
|
||||||
that.isScreenShare = !that.isScreenShare;
|
that.isScreenShare = !that.isScreenShare;
|
||||||
that.addUserLogs(this.lang.start_screen_sharing);
|
that.addUserLogs(that.lang.start_screen_sharing);
|
||||||
}else{
|
}else{
|
||||||
layer.prompt({
|
layer.prompt({
|
||||||
formType: 1,
|
formType: 1,
|
||||||
@@ -1256,7 +1349,7 @@ axios.get("/api/comm/initData?turn="+useTurn, {}).then((initData) => {
|
|||||||
});
|
});
|
||||||
that.clickMediaScreen();
|
that.clickMediaScreen();
|
||||||
that.isScreenShare = !that.isScreenShare;
|
that.isScreenShare = !that.isScreenShare;
|
||||||
that.addUserLogs(this.lang.this.lang.start_screen_sharing);
|
that.addUserLogs(that.lang.start_screen_sharing);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -1289,9 +1382,25 @@ axios.get("/api/comm/initData?turn="+useTurn, {}).then((initData) => {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
let that = this;
|
let that = this;
|
||||||
if (window.layer) {
|
if(that.isShareJoin){ //分享进入
|
||||||
if(that.isShareJoin){ //分享进入
|
that.createMediaRoom("live");
|
||||||
|
that.socket.emit('message', {
|
||||||
|
emitType: "startLiveShare",
|
||||||
|
room: that.roomId,
|
||||||
|
to : that.socketId
|
||||||
|
});
|
||||||
|
that.clickMediaLive();
|
||||||
|
that.isLiveShare = !that.isLiveShare;
|
||||||
|
that.addUserLogs(that.lang.start_live);
|
||||||
|
}else{
|
||||||
|
layer.prompt({
|
||||||
|
formType: 1,
|
||||||
|
title: this.lang.please_enter_live_room_num,
|
||||||
|
}, function (value, index, elem) {
|
||||||
|
that.roomId = value;
|
||||||
that.createMediaRoom("live");
|
that.createMediaRoom("live");
|
||||||
|
layer.close(index)
|
||||||
|
|
||||||
that.socket.emit('message', {
|
that.socket.emit('message', {
|
||||||
emitType: "startLiveShare",
|
emitType: "startLiveShare",
|
||||||
room: that.roomId,
|
room: that.roomId,
|
||||||
@@ -1299,30 +1408,13 @@ axios.get("/api/comm/initData?turn="+useTurn, {}).then((initData) => {
|
|||||||
});
|
});
|
||||||
that.clickMediaLive();
|
that.clickMediaLive();
|
||||||
that.isLiveShare = !that.isLiveShare;
|
that.isLiveShare = !that.isLiveShare;
|
||||||
that.addUserLogs(this.lang.start_live);
|
that.addUserLogs(that.lang.start_live);
|
||||||
}else{
|
});
|
||||||
layer.prompt({
|
|
||||||
formType: 1,
|
|
||||||
title: this.lang.please_enter_live_room_num,
|
|
||||||
}, function (value, index, elem) {
|
|
||||||
that.roomId = value;
|
|
||||||
that.createMediaRoom("live");
|
|
||||||
layer.close(index)
|
|
||||||
|
|
||||||
that.socket.emit('message', {
|
|
||||||
emitType: "startLiveShare",
|
|
||||||
room: that.roomId,
|
|
||||||
to : that.socketId
|
|
||||||
});
|
|
||||||
that.clickMediaLive();
|
|
||||||
that.isLiveShare = !that.isLiveShare;
|
|
||||||
that.addUserLogs(this.lang.start_live);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
// 打开画笔
|
// 打开画笔
|
||||||
openRemoteDraw : function(){
|
openRemoteDraw : function(){
|
||||||
|
let that = this;
|
||||||
if (!this.switchData.openRemoteDraw) {
|
if (!this.switchData.openRemoteDraw) {
|
||||||
layer.msg(this.lang.feature_close)
|
layer.msg(this.lang.feature_close)
|
||||||
this.addUserLogs(this.lang.feature_close)
|
this.addUserLogs(this.lang.feature_close)
|
||||||
@@ -1338,26 +1430,26 @@ axios.get("/api/comm/initData?turn="+useTurn, {}).then((initData) => {
|
|||||||
// 触发draw.js中的方法
|
// 触发draw.js中的方法
|
||||||
window.Bus.$emit("openDraw", {
|
window.Bus.$emit("openDraw", {
|
||||||
openCallback: () => {
|
openCallback: () => {
|
||||||
this.socket.emit('message', {
|
that.socket.emit('message', {
|
||||||
emitType: "startRemoteDraw",
|
emitType: "startRemoteDraw",
|
||||||
room: this.roomId,
|
room: that.roomId,
|
||||||
to: this.socketId
|
to: that.socketId
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
closeCallback: (drawCount) => {
|
closeCallback: (drawCount) => {
|
||||||
this.socket.emit('message', {
|
that.socket.emit('message', {
|
||||||
emitType: "stopRemoteDraw",
|
emitType: "stopRemoteDraw",
|
||||||
room: this.roomId,
|
room: that.roomId,
|
||||||
to: this.socketId,
|
to: that.socketId,
|
||||||
drawCount : drawCount
|
drawCount : drawCount
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
localDrawCallback : (data) => {
|
localDrawCallback : (data) => {
|
||||||
Object.entries(this.remoteMap).forEach(([id, remote]) => {
|
Object.entries(that.remoteMap).forEach(([id, remote]) => {
|
||||||
if(remote && remote.sendDataChannel){
|
if(remote && remote.sendDataChannel){
|
||||||
const sendDataChannel = remote.sendDataChannel;
|
const sendDataChannel = remote.sendDataChannel;
|
||||||
if (!sendDataChannel || sendDataChannel.readyState !== 'open') {
|
if (!sendDataChannel || sendDataChannel.readyState !== 'open') {
|
||||||
this.addSysLogs("sendDataChannel error in draw")
|
that.addSysLogs("sendDataChannel error in draw")
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
sendDataChannel.send(JSON.stringify(data));
|
sendDataChannel.send(JSON.stringify(data));
|
||||||
@@ -1387,15 +1479,15 @@ axios.get("/api/comm/initData?turn="+useTurn, {}).then((initData) => {
|
|||||||
openCallback : () => {
|
openCallback : () => {
|
||||||
that.socket.emit('message', {
|
that.socket.emit('message', {
|
||||||
emitType: "startScreen",
|
emitType: "startScreen",
|
||||||
room: this.roomId,
|
room: that.roomId,
|
||||||
to : this.socketId
|
to : that.socketId
|
||||||
});
|
});
|
||||||
that.addUserLogs(this.lang.start_local_screen_recording);
|
that.addUserLogs(that.lang.start_local_screen_recording);
|
||||||
},
|
},
|
||||||
closeCallback : (res) => {
|
closeCallback : (res) => {
|
||||||
this.receiveFileRecoderList.push({
|
that.receiveFileRecoderList.push({
|
||||||
id: this.lang.web_screen_recording,
|
id: that.lang.web_screen_recording,
|
||||||
nickName : this.nickName,
|
nickName : that.nickName,
|
||||||
href: res.src,
|
href: res.src,
|
||||||
style: 'color: #ff5722;text-decoration: underline;',
|
style: 'color: #ff5722;text-decoration: underline;',
|
||||||
name: 'screen-recording-' + res.donwId + '.mp4',
|
name: 'screen-recording-' + res.donwId + '.mp4',
|
||||||
@@ -1406,14 +1498,14 @@ axios.get("/api/comm/initData?turn="+useTurn, {}).then((initData) => {
|
|||||||
start: 0,
|
start: 0,
|
||||||
cost: res.times
|
cost: res.times
|
||||||
})
|
})
|
||||||
this.socket.emit('message', {
|
that.socket.emit('message', {
|
||||||
emitType: "stopScreen",
|
emitType: "stopScreen",
|
||||||
to : this.socketId,
|
to : that.socketId,
|
||||||
room: this.roomId,
|
room: that.roomId,
|
||||||
size: res.size,
|
size: res.size,
|
||||||
cost: res.times
|
cost: res.times
|
||||||
});
|
});
|
||||||
this.addUserLogs(this.lang.end_local_screen_recording);
|
that.addUserLogs(that.lang.end_local_screen_recording);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
@@ -1461,7 +1553,7 @@ axios.get("/api/comm/initData?turn="+useTurn, {}).then((initData) => {
|
|||||||
</div>
|
</div>
|
||||||
<div class="chating_input_body">
|
<div class="chating_input_body">
|
||||||
<textarea maxlength="50000" id="chating_comm_value" class="layui-textarea" placeholder="${this.lang.communication_rational} ~"></textarea>
|
<textarea maxlength="50000" id="chating_comm_value" class="layui-textarea" placeholder="${this.lang.communication_rational} ~"></textarea>
|
||||||
<span class="chating_send_body chating_send_body_span">shift+enter ${this.lang.enter_send} </span>
|
<span class="chating_send_body chating_send_body_span">shift+enter | ${this.lang.enter_send} </span>
|
||||||
<button onclick="sendChatingComm()" type="button" class="layui-btn layui-btn-normal layui-btn-sm chating_send_body chating_send_body_button">${this.lang.send_chat}</button>
|
<button onclick="sendChatingComm()" type="button" class="layui-btn layui-btn-normal layui-btn-sm chating_send_body chating_send_body_button">${this.lang.send_chat}</button>
|
||||||
</div>
|
</div>
|
||||||
`
|
`
|
||||||
@@ -1617,7 +1709,7 @@ axios.get("/api/comm/initData?turn="+useTurn, {}).then((initData) => {
|
|||||||
</div>
|
</div>
|
||||||
<div class="chating_input_body">
|
<div class="chating_input_body">
|
||||||
<textarea maxlength="50000" id="chating_room_value" class="layui-textarea" placeholder="${this.lang.communication_rational} ~"></textarea>
|
<textarea maxlength="50000" id="chating_room_value" class="layui-textarea" placeholder="${this.lang.communication_rational} ~"></textarea>
|
||||||
<span class="chating_send_body chating_send_body_span">shift+enter ${this.lang.enter_send} </span>
|
<span class="chating_send_body chating_send_body_span">shift+enter | ${this.lang.enter_send} </span>
|
||||||
<button onclick="sendChatingRoom()" type="button" class="layui-btn layui-btn-normal layui-btn-sm chating_send_body chating_send_body_button">${this.lang.send_chat}</button>
|
<button onclick="sendChatingRoom()" type="button" class="layui-btn layui-btn-normal layui-btn-sm chating_send_body chating_send_body_button">${this.lang.send_chat}</button>
|
||||||
</div>
|
</div>
|
||||||
`
|
`
|
||||||
@@ -2118,7 +2210,9 @@ axios.get("/api/comm/initData?turn="+useTurn, {}).then((initData) => {
|
|||||||
type : 'password',
|
type : 'password',
|
||||||
password : '',
|
password : '',
|
||||||
nickName : this.nickName,
|
nickName : this.nickName,
|
||||||
langMode : this.langMode
|
langMode : this.langMode,
|
||||||
|
ua: this.isMobile ? 'mobile' : 'pc',
|
||||||
|
network : this.network
|
||||||
});
|
});
|
||||||
this.isJoined = true;
|
this.isJoined = true;
|
||||||
this.addPopup({
|
this.addPopup({
|
||||||
@@ -2147,7 +2241,9 @@ axios.get("/api/comm/initData?turn="+useTurn, {}).then((initData) => {
|
|||||||
room: this.roomId,
|
room: this.roomId,
|
||||||
type: type,
|
type: type,
|
||||||
nickName : this.nickName,
|
nickName : this.nickName,
|
||||||
langMode : this.langMode
|
langMode : this.langMode,
|
||||||
|
ua: this.isMobile ? 'mobile' : 'pc',
|
||||||
|
network : this.network
|
||||||
});
|
});
|
||||||
this.isJoined = true;
|
this.isJoined = true;
|
||||||
this.roomType = type;
|
this.roomType = type;
|
||||||
@@ -2183,7 +2279,9 @@ axios.get("/api/comm/initData?turn="+useTurn, {}).then((initData) => {
|
|||||||
type : 'password',
|
type : 'password',
|
||||||
password: password,
|
password: password,
|
||||||
nickName : this.nickName,
|
nickName : this.nickName,
|
||||||
langMode : this.langMode
|
langMode : this.langMode,
|
||||||
|
ua: this.isMobile ? 'mobile' : 'pc',
|
||||||
|
network : this.network
|
||||||
});
|
});
|
||||||
this.isJoined = true;
|
this.isJoined = true;
|
||||||
this.addPopup({
|
this.addPopup({
|
||||||
@@ -2225,12 +2323,19 @@ axios.get("/api/comm/initData?turn="+useTurn, {}).then((initData) => {
|
|||||||
|
|
||||||
rtcConnect.oniceconnectionstatechange = (e) => {
|
rtcConnect.oniceconnectionstatechange = (e) => {
|
||||||
that.addSysLogs("iceConnectionState: " + rtcConnect.iceConnectionState);
|
that.addSysLogs("iceConnectionState: " + rtcConnect.iceConnectionState);
|
||||||
|
that.setRemoteInfo(id, {
|
||||||
|
iceConnectionState : rtcConnect.iceConnectionState
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
//保存peer连接
|
//保存peer连接
|
||||||
this.rtcConns[id] = rtcConnect;
|
this.rtcConns[id] = rtcConnect;
|
||||||
if (!this.remoteMap[id]) {
|
if (!this.remoteMap[id]) {
|
||||||
Vue.set(this.remoteMap, id, { id: id, receiveChatRoomSingleList : [] })
|
Vue.set(this.remoteMap, id, {
|
||||||
|
id: id,
|
||||||
|
receiveChatRoomSingleList : [],
|
||||||
|
p2pMode : '识别中...'
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
//数据通道
|
//数据通道
|
||||||
@@ -2467,11 +2572,20 @@ axios.get("/api/comm/initData?turn="+useTurn, {}).then((initData) => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// 缓冲区満了
|
//缓冲区暂定 256kb
|
||||||
|
sendFileDataChannel.bufferedAmountLowThreshold = 16 * 1024 * 16;
|
||||||
|
//局域网一般不会走缓冲区,所以bufferedAmount一般为0,公网部分情况受限于带宽,bufferedAmount可能会逐渐堆积,从而进行排队
|
||||||
if (sendFileDataChannel.bufferedAmount > sendFileDataChannel.bufferedAmountLowThreshold) {
|
if (sendFileDataChannel.bufferedAmount > sendFileDataChannel.bufferedAmountLowThreshold) {
|
||||||
this.addSysLogs(this.lang.file_send_channel_buffer_full)
|
this.addSysLogs(
|
||||||
|
that.lang.file_send_channel_buffer_full + ",bufferedAmount=" +
|
||||||
|
sendFileDataChannel.bufferedAmount + ",bufferedAmountLowThreshold=" +
|
||||||
|
sendFileDataChannel.bufferedAmountLowThreshold
|
||||||
|
)
|
||||||
sendFileDataChannel.onbufferedamountlow = () => {
|
sendFileDataChannel.onbufferedamountlow = () => {
|
||||||
this.addSysLogs(this.lang.file_send_channel_buffer_recover)
|
that.addSysLogs(
|
||||||
|
that.lang.file_send_channel_buffer_recover + ",bufferedAmount=" +
|
||||||
|
sendFileDataChannel.bufferedAmount
|
||||||
|
)
|
||||||
sendFileDataChannel.onbufferedamountlow = null;
|
sendFileDataChannel.onbufferedamountlow = null;
|
||||||
that.sendFileToRemoteByLoop(event);
|
that.sendFileToRemoteByLoop(event);
|
||||||
}
|
}
|
||||||
@@ -2844,15 +2958,17 @@ axios.get("/api/comm/initData?turn="+useTurn, {}).then((initData) => {
|
|||||||
|
|
||||||
for (let i = 0; i < data.peers.length; i++) {
|
for (let i = 0; i < data.peers.length; i++) {
|
||||||
let otherSocketId = data.peers[i].id;
|
let otherSocketId = data.peers[i].id;
|
||||||
let otherSocketIdNickName = data.peers[i].nickName;
|
|
||||||
let otherSocketIdLangMode = data.peers[i].langMode;
|
|
||||||
let otherSocketIdOwner = data.peers[i].owner;
|
|
||||||
let rtcConnect = that.getOrCreateRtcConnect(otherSocketId);
|
let rtcConnect = that.getOrCreateRtcConnect(otherSocketId);
|
||||||
// 处理完连接后,更新下昵称
|
// 处理完连接后,更新下昵称
|
||||||
that.setRemoteInfo(otherSocketId, {
|
that.setRemoteInfo(otherSocketId, {
|
||||||
nickName : otherSocketIdNickName,
|
nickName : data.peers[i].nickName,
|
||||||
langMode : otherSocketIdLangMode,
|
langMode : data.peers[i].langMode,
|
||||||
owner : otherSocketIdOwner
|
owner : data.peers[i].owner,
|
||||||
|
ua : data.peers[i].ua,
|
||||||
|
joinTime : data.peers[i].joinTime,
|
||||||
|
userAgent : data.peers[i].userAgent,
|
||||||
|
ip : data.peers[i].ip,
|
||||||
|
network : data.peers[i].network,
|
||||||
})
|
})
|
||||||
|
|
||||||
await new Promise(resolve => {
|
await new Promise(resolve => {
|
||||||
@@ -2895,7 +3011,11 @@ axios.get("/api/comm/initData?turn="+useTurn, {}).then((initData) => {
|
|||||||
nickName : data.nickName,
|
nickName : data.nickName,
|
||||||
owner : data.owner,
|
owner : data.owner,
|
||||||
langMode : data.langMode,
|
langMode : data.langMode,
|
||||||
owner : false
|
ua : data.ua,
|
||||||
|
network : data.network,
|
||||||
|
joinTime : data.joinTime,
|
||||||
|
userAgent : data.userAgent,
|
||||||
|
ip : data.ip,
|
||||||
})
|
})
|
||||||
// 处理音视频逻辑
|
// 处理音视频逻辑
|
||||||
if (data.type === 'screen') {
|
if (data.type === 'screen') {
|
||||||
@@ -3656,10 +3776,14 @@ axios.get("/api/comm/initData?turn="+useTurn, {}).then((initData) => {
|
|||||||
this.addSysLogs(this.lang.basic_data_get_done);
|
this.addSysLogs(this.lang.basic_data_get_done);
|
||||||
|
|
||||||
this.addSysLogs(this.lang.window_event_init);
|
this.addSysLogs(this.lang.window_event_init);
|
||||||
window.onresize = this.touchResize;
|
window.onresize = this.touchResize;
|
||||||
setInterval(() => {
|
setInterval(() => {
|
||||||
this.touchResize()
|
this.touchResize()
|
||||||
}, 1000);
|
}, 1000);
|
||||||
|
|
||||||
|
setInterval(async () => {
|
||||||
|
await this.updateRemoteRtcState()
|
||||||
|
}, 5000);
|
||||||
this.addSysLogs(this.lang.window_event_init_done);
|
this.addSysLogs(this.lang.window_event_init_done);
|
||||||
|
|
||||||
this.addSysLogs(this.lang.message_box_init);
|
this.addSysLogs(this.lang.message_box_init);
|
||||||
|
@@ -314,8 +314,28 @@ const local_lang = {
|
|||||||
"you_refresh_room": "You refreshed the room number, the current room number is",
|
"you_refresh_room": "You refreshed the room number, the current room number is",
|
||||||
"your_browser": "Your browser",
|
"your_browser": "Your browser",
|
||||||
"your_ip_list": "Your IP list is",
|
"your_ip_list": "Your IP list is",
|
||||||
|
"nickname" : "Nickname",
|
||||||
|
"userid" : "Userd",
|
||||||
|
"room_channel" : "Room channel",
|
||||||
|
"join_time" : "Join time",
|
||||||
|
"website_language" : "Website language",
|
||||||
|
"terminal_equipment" : "Terminal equipment",
|
||||||
|
"device_classification" : "Device classification",
|
||||||
|
"network_status" : "Network status",
|
||||||
|
"public_ip" : "Public IP",
|
||||||
|
"webrtc_ice_state" : "webrtc state"
|
||||||
},
|
},
|
||||||
"zh": {
|
"zh": {
|
||||||
|
"webrtc_ice_state" : "webrtc状态",
|
||||||
|
"nickname" : "用户昵称",
|
||||||
|
"userid" : "用户ID ",
|
||||||
|
"room_channel" : "房间频道",
|
||||||
|
"join_time" : "加入时间",
|
||||||
|
"website_language" : "网站语言",
|
||||||
|
"terminal_equipment" : "终端设备",
|
||||||
|
"device_classification" : "设备分类",
|
||||||
|
"network_status" : "网络状态",
|
||||||
|
"public_ip" : "传输地址",
|
||||||
"add_ice_candidate_failed": "addIceCandidate失败",
|
"add_ice_candidate_failed": "addIceCandidate失败",
|
||||||
"add_ice_candidate_success": "addIceCandidateSuccess成功",
|
"add_ice_candidate_success": "addIceCandidateSuccess成功",
|
||||||
"ai_answering": "AI正在回答您的问题,请稍后再问",
|
"ai_answering": "AI正在回答您的问题,请稍后再问",
|
||||||
@@ -445,9 +465,9 @@ const local_lang = {
|
|||||||
"not_support": "不支持",
|
"not_support": "不支持",
|
||||||
"note_website_for_learing": "注意:示例网站仅用于学习演示,请勿他用",
|
"note_website_for_learing": "注意:示例网站仅用于学习演示,请勿他用",
|
||||||
"notice": "通知",
|
"notice": "通知",
|
||||||
"off": "已关闭",
|
"off": "关闭",
|
||||||
"offer_failed": "offer失败",
|
"offer_failed": "offer失败",
|
||||||
"on": "已开启",
|
"on": "开启",
|
||||||
"online": "当前在线人数",
|
"online": "当前在线人数",
|
||||||
"online_number": "人在线",
|
"online_number": "人在线",
|
||||||
"only_show" : "仅展示 ",
|
"only_show" : "仅展示 ",
|
||||||
@@ -553,7 +573,7 @@ const local_lang = {
|
|||||||
"select_wait_send_record": "选择待发送记录中",
|
"select_wait_send_record": "选择待发送记录中",
|
||||||
"selected_file": "已选择文件",
|
"selected_file": "已选择文件",
|
||||||
"selected_file_exist": "选择的文件已经存在相同的文件,不再重复添加",
|
"selected_file_exist": "选择的文件已经存在相同的文件,不再重复添加",
|
||||||
"self": "我自己",
|
"self": "自己",
|
||||||
"send": "发送",
|
"send": "发送",
|
||||||
"send_all": "一键发送",
|
"send_all": "一键发送",
|
||||||
"send_alone": "单独发送",
|
"send_alone": "单独发送",
|
||||||
|
@@ -63,7 +63,7 @@
|
|||||||
|
|
||||||
<h2>收费模式</h2>
|
<h2>收费模式</h2>
|
||||||
<ul>
|
<ul>
|
||||||
<li><strong>按小时计费:</strong>根据实际工作时间计算费用,目前个人定制功能2小时起,每小时200~300,企业定制另谈</li>
|
<li><strong>按小时计费:</strong>根据实际工作时间计算费用,目前个人定制功能2小时起,每小时200~300</li>
|
||||||
<li><strong>阶段性付费:</strong>确认开发前,预付1/3,开发完成付1/3,交付上线1/3</li>
|
<li><strong>阶段性付费:</strong>确认开发前,预付1/3,开发完成付1/3,交付上线1/3</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
|
@@ -19,7 +19,10 @@ const check = require("./../../utils/check/content");
|
|||||||
async function userCreateAndJoin(io, socket, tables, dbClient, data){
|
async function userCreateAndJoin(io, socket, tables, dbClient, data){
|
||||||
let {handshake, userAgent, ip} = utils.getSocketClientInfo(socket);
|
let {handshake, userAgent, ip} = utils.getSocketClientInfo(socket);
|
||||||
|
|
||||||
let {room, type, nickName, password = '', langMode = 'zh'} = data;
|
let {
|
||||||
|
room, type = 'file', nickName = '', password = '',
|
||||||
|
langMode = 'zh', ua = '', network = ''
|
||||||
|
} = data;
|
||||||
|
|
||||||
if (room && room.length > 15) {
|
if (room && room.length > 15) {
|
||||||
room = room.toString().substr(0, 14);
|
room = room.toString().substr(0, 14);
|
||||||
@@ -28,14 +31,37 @@ async function userCreateAndJoin(io, socket, tables, dbClient, data){
|
|||||||
if(nickName && nickName.length > 20){
|
if(nickName && nickName.length > 20){
|
||||||
nickName = nickName.substr(0, 20);
|
nickName = nickName.substr(0, 20);
|
||||||
}
|
}
|
||||||
//设置昵称
|
|
||||||
io.sockets.connected[socket.id].nickName = nickName;
|
if(['zh', 'en'].indexOf(langMode) === -1){
|
||||||
io.sockets.connected[socket.id].langMode = langMode;
|
langMode = 'zh'
|
||||||
|
}
|
||||||
|
|
||||||
|
if(['file', 'screen', 'video', 'password', 'live'].indexOf(type) === -1){
|
||||||
|
type = 'file'
|
||||||
|
}
|
||||||
|
|
||||||
|
if(['pc', 'mobile'].indexOf(ua) === -1){
|
||||||
|
ua = 'pc';
|
||||||
|
}
|
||||||
|
|
||||||
|
if(['wifi', '4g', '3g', '2g', '5g'].indexOf(network) === -1){
|
||||||
|
network = '2g';
|
||||||
|
}
|
||||||
|
|
||||||
if(password && password.length > 6){
|
if(password && password.length > 6){
|
||||||
password = password.toString().substr(0,6);
|
password = password.toString().substr(0,6);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//设置连接信息
|
||||||
|
io.sockets.connected[socket.id].nickName = nickName;
|
||||||
|
io.sockets.connected[socket.id].langMode = langMode;
|
||||||
|
io.sockets.connected[socket.id].ua = ua;
|
||||||
|
io.sockets.connected[socket.id].network = network;
|
||||||
|
io.sockets.connected[socket.id].ip = ip;
|
||||||
|
const joinTime = utils.formateDateTime(new Date(), "yyyy-MM-dd hh:mm:ss")
|
||||||
|
io.sockets.connected[socket.id].joinTime = joinTime;
|
||||||
|
io.sockets.connected[socket.id].userAgent = userAgent;
|
||||||
|
|
||||||
let recoderId = await daoRoom.createJoinRoom({
|
let recoderId = await daoRoom.createJoinRoom({
|
||||||
uid: "1",
|
uid: "1",
|
||||||
uname: nickName,
|
uname: nickName,
|
||||||
@@ -105,6 +131,11 @@ async function userCreateAndJoin(io, socket, tables, dbClient, data){
|
|||||||
type: type,
|
type: type,
|
||||||
recoderId : recoderId,
|
recoderId : recoderId,
|
||||||
langMode : langMode,
|
langMode : langMode,
|
||||||
|
ua : ua,
|
||||||
|
network : network,
|
||||||
|
joinTime : joinTime,
|
||||||
|
ip : ip,
|
||||||
|
userAgent : userAgent
|
||||||
});
|
});
|
||||||
|
|
||||||
let peers = new Array();
|
let peers = new Array();
|
||||||
@@ -114,11 +145,22 @@ async function userCreateAndJoin(io, socket, tables, dbClient, data){
|
|||||||
let peerNickName = io.sockets.connected[otherSocketId].nickName
|
let peerNickName = io.sockets.connected[otherSocketId].nickName
|
||||||
let peerOwner = io.sockets.connected[otherSocketId].owner
|
let peerOwner = io.sockets.connected[otherSocketId].owner
|
||||||
let peerLangMode = io.sockets.connected[otherSocketId].langMode
|
let peerLangMode = io.sockets.connected[otherSocketId].langMode
|
||||||
|
let peerUa = io.sockets.connected[otherSocketId].ua
|
||||||
|
let peerNetwork = io.sockets.connected[otherSocketId].network
|
||||||
|
let peerJoinTime = io.sockets.connected[otherSocketId].joinTime
|
||||||
|
let peerIp = io.sockets.connected[otherSocketId].ip
|
||||||
|
let peerUserAgent = io.sockets.connected[otherSocketId].userAgent
|
||||||
|
|
||||||
peers.push({
|
peers.push({
|
||||||
id: otherSocketId,
|
id: otherSocketId,
|
||||||
nickName: peerNickName,
|
nickName: peerNickName,
|
||||||
owner : peerOwner,
|
owner : peerOwner,
|
||||||
langMode : peerLangMode
|
langMode : peerLangMode,
|
||||||
|
ua : peerUa,
|
||||||
|
network : peerNetwork,
|
||||||
|
joinTime : peerJoinTime,
|
||||||
|
ip : peerIp,
|
||||||
|
userAgent : peerUserAgent
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -54,6 +54,30 @@
|
|||||||
<div class="content unicode" style="display: block;">
|
<div class="content unicode" style="display: block;">
|
||||||
<ul class="icon_lists dib-box">
|
<ul class="icon_lists dib-box">
|
||||||
|
|
||||||
|
<li class="dib">
|
||||||
|
<span class="icon iconfont"></span>
|
||||||
|
<div class="name">数据汇总</div>
|
||||||
|
<div class="code-name">&#xe61d;</div>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li class="dib">
|
||||||
|
<span class="icon iconfont"></span>
|
||||||
|
<div class="name">控桩终端</div>
|
||||||
|
<div class="code-name">&#xe6bb;</div>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li class="dib">
|
||||||
|
<span class="icon iconfont"></span>
|
||||||
|
<div class="name">浏览器</div>
|
||||||
|
<div class="code-name">&#xe6e8;</div>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li class="dib">
|
||||||
|
<span class="icon iconfont"></span>
|
||||||
|
<div class="name">连接流</div>
|
||||||
|
<div class="code-name">&#xec57;</div>
|
||||||
|
</li>
|
||||||
|
|
||||||
<li class="dib">
|
<li class="dib">
|
||||||
<span class="icon iconfont"></span>
|
<span class="icon iconfont"></span>
|
||||||
<div class="name">三角形</div>
|
<div class="name">三角形</div>
|
||||||
@@ -534,9 +558,9 @@
|
|||||||
<pre><code class="language-css"
|
<pre><code class="language-css"
|
||||||
>@font-face {
|
>@font-face {
|
||||||
font-family: 'iconfont';
|
font-family: 'iconfont';
|
||||||
src: url('iconfont.woff2?t=1688291642630') format('woff2'),
|
src: url('iconfont.woff2?t=1688799262496') format('woff2'),
|
||||||
url('iconfont.woff?t=1688291642630') format('woff'),
|
url('iconfont.woff?t=1688799262496') format('woff'),
|
||||||
url('iconfont.ttf?t=1688291642630') format('truetype');
|
url('iconfont.ttf?t=1688799262496') format('truetype');
|
||||||
}
|
}
|
||||||
</code></pre>
|
</code></pre>
|
||||||
<h3 id="-iconfont-">第二步:定义使用 iconfont 的样式</h3>
|
<h3 id="-iconfont-">第二步:定义使用 iconfont 的样式</h3>
|
||||||
@@ -562,6 +586,42 @@
|
|||||||
<div class="content font-class">
|
<div class="content font-class">
|
||||||
<ul class="icon_lists dib-box">
|
<ul class="icon_lists dib-box">
|
||||||
|
|
||||||
|
<li class="dib">
|
||||||
|
<span class="icon iconfont icon-rtc-file-daohang-shujufenxi"></span>
|
||||||
|
<div class="name">
|
||||||
|
数据汇总
|
||||||
|
</div>
|
||||||
|
<div class="code-name">.icon-rtc-file-daohang-shujufenxi
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li class="dib">
|
||||||
|
<span class="icon iconfont icon-rtc-file-kongzhuangzhongduan"></span>
|
||||||
|
<div class="name">
|
||||||
|
控桩终端
|
||||||
|
</div>
|
||||||
|
<div class="code-name">.icon-rtc-file-kongzhuangzhongduan
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li class="dib">
|
||||||
|
<span class="icon iconfont icon-rtc-file-liulanqi"></span>
|
||||||
|
<div class="name">
|
||||||
|
浏览器
|
||||||
|
</div>
|
||||||
|
<div class="code-name">.icon-rtc-file-liulanqi
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li class="dib">
|
||||||
|
<span class="icon iconfont icon-rtc-file-lianjieliu"></span>
|
||||||
|
<div class="name">
|
||||||
|
连接流
|
||||||
|
</div>
|
||||||
|
<div class="code-name">.icon-rtc-file-lianjieliu
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
|
||||||
<li class="dib">
|
<li class="dib">
|
||||||
<span class="icon iconfont icon-rtc-file-sanjiaoxing"></span>
|
<span class="icon iconfont icon-rtc-file-sanjiaoxing"></span>
|
||||||
<div class="name">
|
<div class="name">
|
||||||
@@ -1282,6 +1342,38 @@
|
|||||||
<div class="content symbol">
|
<div class="content symbol">
|
||||||
<ul class="icon_lists dib-box">
|
<ul class="icon_lists dib-box">
|
||||||
|
|
||||||
|
<li class="dib">
|
||||||
|
<svg class="icon svg-icon" aria-hidden="true">
|
||||||
|
<use xlink:href="#icon-rtc-file-daohang-shujufenxi"></use>
|
||||||
|
</svg>
|
||||||
|
<div class="name">数据汇总</div>
|
||||||
|
<div class="code-name">#icon-rtc-file-daohang-shujufenxi</div>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li class="dib">
|
||||||
|
<svg class="icon svg-icon" aria-hidden="true">
|
||||||
|
<use xlink:href="#icon-rtc-file-kongzhuangzhongduan"></use>
|
||||||
|
</svg>
|
||||||
|
<div class="name">控桩终端</div>
|
||||||
|
<div class="code-name">#icon-rtc-file-kongzhuangzhongduan</div>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li class="dib">
|
||||||
|
<svg class="icon svg-icon" aria-hidden="true">
|
||||||
|
<use xlink:href="#icon-rtc-file-liulanqi"></use>
|
||||||
|
</svg>
|
||||||
|
<div class="name">浏览器</div>
|
||||||
|
<div class="code-name">#icon-rtc-file-liulanqi</div>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li class="dib">
|
||||||
|
<svg class="icon svg-icon" aria-hidden="true">
|
||||||
|
<use xlink:href="#icon-rtc-file-lianjieliu"></use>
|
||||||
|
</svg>
|
||||||
|
<div class="name">连接流</div>
|
||||||
|
<div class="code-name">#icon-rtc-file-lianjieliu</div>
|
||||||
|
</li>
|
||||||
|
|
||||||
<li class="dib">
|
<li class="dib">
|
||||||
<svg class="icon svg-icon" aria-hidden="true">
|
<svg class="icon svg-icon" aria-hidden="true">
|
||||||
<use xlink:href="#icon-rtc-file-sanjiaoxing"></use>
|
<use xlink:href="#icon-rtc-file-sanjiaoxing"></use>
|
||||||
|
@@ -1,8 +1,8 @@
|
|||||||
@font-face {
|
@font-face {
|
||||||
font-family: "iconfont"; /* Project id 4147343 */
|
font-family: "iconfont"; /* Project id 4147343 */
|
||||||
src: url('iconfont.woff2?t=1688291642630') format('woff2'),
|
src: url('iconfont.woff2?t=1688799262496') format('woff2'),
|
||||||
url('iconfont.woff?t=1688291642630') format('woff'),
|
url('iconfont.woff?t=1688799262496') format('woff'),
|
||||||
url('iconfont.ttf?t=1688291642630') format('truetype');
|
url('iconfont.ttf?t=1688799262496') format('truetype');
|
||||||
}
|
}
|
||||||
|
|
||||||
.iconfont {
|
.iconfont {
|
||||||
@@ -13,6 +13,22 @@
|
|||||||
-moz-osx-font-smoothing: grayscale;
|
-moz-osx-font-smoothing: grayscale;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.icon-rtc-file-daohang-shujufenxi:before {
|
||||||
|
content: "\e61d";
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-rtc-file-kongzhuangzhongduan:before {
|
||||||
|
content: "\e6bb";
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-rtc-file-liulanqi:before {
|
||||||
|
content: "\e6e8";
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-rtc-file-lianjieliu:before {
|
||||||
|
content: "\ec57";
|
||||||
|
}
|
||||||
|
|
||||||
.icon-rtc-file-sanjiaoxing:before {
|
.icon-rtc-file-sanjiaoxing:before {
|
||||||
content: "\e619";
|
content: "\e619";
|
||||||
}
|
}
|
||||||
|
File diff suppressed because one or more lines are too long
@@ -5,6 +5,34 @@
|
|||||||
"css_prefix_text": "icon-rtc-file-",
|
"css_prefix_text": "icon-rtc-file-",
|
||||||
"description": "",
|
"description": "",
|
||||||
"glyphs": [
|
"glyphs": [
|
||||||
|
{
|
||||||
|
"icon_id": "3494344",
|
||||||
|
"name": "数据汇总",
|
||||||
|
"font_class": "daohang-shujufenxi",
|
||||||
|
"unicode": "e61d",
|
||||||
|
"unicode_decimal": 58909
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"icon_id": "25071396",
|
||||||
|
"name": "控桩终端",
|
||||||
|
"font_class": "kongzhuangzhongduan",
|
||||||
|
"unicode": "e6bb",
|
||||||
|
"unicode_decimal": 59067
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"icon_id": "25853325",
|
||||||
|
"name": "浏览器",
|
||||||
|
"font_class": "liulanqi",
|
||||||
|
"unicode": "e6e8",
|
||||||
|
"unicode_decimal": 59112
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"icon_id": "5961312",
|
||||||
|
"name": "连接流",
|
||||||
|
"font_class": "lianjieliu",
|
||||||
|
"unicode": "ec57",
|
||||||
|
"unicode_decimal": 60503
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"icon_id": "3101162",
|
"icon_id": "3101162",
|
||||||
"name": "三角形",
|
"name": "三角形",
|
||||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Reference in New Issue
Block a user