chatconnect.vue 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590
  1. <template>
  2. <view class="content" @click.sop="">
  3. <!-- IM连接 -->
  4. <view v-if="!libPage" class="user">
  5. <view class="loading">
  6. <span v-for="i in 4" :key='i'></span>
  7. </view>
  8. <view class="loading-type2">
  9. <span></span>
  10. </view>
  11. <view class="content-lab">
  12. <p>appkey:{{form.appkey}}</p>
  13. <p>token:{{form.token}}</p>
  14. <p>targetId:{{targetId}}</p>
  15. <button class="btn">
  16. 连接中请稍等……
  17. </button>
  18. </view>
  19. </view>
  20. <view v-if="libPage">
  21. <!-- <span>用户ID:</span><span>{{loginUserId}}</span> -->
  22. <ry-chat-room :chats="chatList" @send="chatSend" @call="callOut" />
  23. </view>
  24. <view class="boxs" v-if="isCut">
  25. <view class="boxs-cen">
  26. <view class="boxs-des">
  27. 是否接入?
  28. </view>
  29. <view class="boxs-btn">
  30. <button type="default" @click="cutFn(false)">取消</button>
  31. <button type="default" @click="cutFn(true)">确定</button>
  32. </view>
  33. </view>
  34. </view>
  35. </view>
  36. </template>
  37. <script>
  38. import * as call from "@/uni_modules/RongCloud-CallWrapper/lib/index"
  39. import * as IMLib from "@/uni_modules/RongCloud-IMWrapper/js_sdk/index"
  40. import permision from "@/js_sdk/wa-permission/permission.js";
  41. import {isEmpty} from '@/libs/index.js';
  42. import {reasonDeal,errorDeal,imCode} from '@/libs/code.js'
  43. import config from "@/config/index.js";
  44. /*聊天组件*/
  45. import ryChatRoom from '@/components/IM/index.vue';
  46. export default {
  47. components:{
  48. ryChatRoom
  49. },
  50. data() {
  51. return {
  52. chatList:[],
  53. loginUserId: "",
  54. loginUserId1:true,
  55. loginUserId2:true,
  56. isLogining: "",
  57. isInitIm: false,
  58. form:{
  59. appkey:config.rongYunAppkey,
  60. token:'',
  61. navi:'https://nav-ucqa.rongcloud.net',
  62. mediaServer:''
  63. },
  64. isShow:false,
  65. libPage:false,
  66. isReceive:false,
  67. callSelect:'single',
  68. mediaSelect:'video',
  69. current:0,
  70. cur:0,
  71. callTypeArr:[
  72. {
  73. id:'single',
  74. label:'单聊'
  75. },
  76. {
  77. id:'group',
  78. label:'群聊'
  79. }
  80. ],
  81. mediaTypeArr:[
  82. {
  83. id:'audio',
  84. label:'音频'
  85. },
  86. {
  87. id:'video',
  88. label:'音视频'
  89. }
  90. ],
  91. targetId:'',
  92. isRoom:false,
  93. groupId:'',
  94. userIds:'',
  95. isCut:false,
  96. localSession:'',
  97. showMask:false,
  98. isPermission:false,
  99. isBeauty:false
  100. }
  101. },
  102. onLoad({id}) {
  103. console.log(id)
  104. // 初始化 CallLib
  105. call.init({});
  106. /*连接视频通话*/
  107. this.linkUser(id);
  108. call.onCallReceived( (res)=> {
  109. console.log(res)
  110. console.log("Engine:OnCallReceived=>"+"监听通话呼入, 目标id=>", res.data.targetId);
  111. this.isCut=true;
  112. this.localSession = res.data;
  113. });
  114. call.onCallDisconnected((res)=>{
  115. console.log(res)
  116. console.log("Engine:OnCallDisconnected=>"+"通话挂断/拒绝, 挂断原因=>", res.data.reason);
  117. this.isCut=false;
  118. // 重新渲染视频视图
  119. uni.$emit('OnCallDisconnected');
  120. uni.showToast({
  121. title:reasonDeal(res.data.reason),
  122. error:"error",
  123. icon:'none',
  124. duration:2000
  125. })
  126. });
  127. call.onCallConnected((res)=>{
  128. console.log(res)
  129. console.log("Engine:OnCallConnected=>"+"已建立通话通话接通时,通过回调 onCallConnected 通知当前 call 的详细信息", res);
  130. });
  131. call.onRemoteUserInvited((res)=>{
  132. console.log("Engine:OnRemoteUserInvited=>"+"通话中的某一个参与者,邀请好友加入通话 ,远端Id为=>", res.data.userId);
  133. uni.$emit('OnCallConnected');
  134. })
  135. call.onRemoteUserJoined((res)=>{
  136. console.log("Engine:OnRemoteUserJoined=>"+"主叫端拨出电话,被叫端收到请求后,加入通话,对端Id为=>", res.data.userId);
  137. uni.$emit('OnCallConnected');
  138. })
  139. call.onRemoteUserLeft((res)=>{
  140. console.log("Engine:OnRemoteUserLeft=>"+"远端用户挂断(群聊触发),远端Id为=>", res.data.reason);
  141. // uni.$emit('OnCallConnected');
  142. uni.showToast({
  143. title:reasonDeal(res.data.reason),
  144. error:"error",
  145. icon:'none',
  146. duration:2000
  147. })
  148. })
  149. call.onCallOutgoing((res)=>{
  150. console.log('电话已拨出 主叫端拨出电话后,通过回调 onCallOutgoing 通知当前 call 的详细信息')
  151. })
  152. call.onRemoteUserRinging((res)=>{
  153. console.log('被叫端正在振铃,主叫端拨出电话,被叫端收到请求,发出振铃响应时,回调 onRemoteUserRingin,对端Id为=>', res.data.userId)
  154. })
  155. call.onError((res)=>{
  156. console.log('通话过程中,发生异常')
  157. uni.showToast({
  158. title:errorDeal(res.data.reason),
  159. error:"error",
  160. icon:'none',
  161. duration:2000
  162. });
  163. })
  164. call.onRemoteUserMediaTypeChanged((res)=>{
  165. console.log('当通话中的某一个参与者切换通话类型,例如由 audio 切换至 video,回调 onMediaTypeChanged,切换媒体类型的Id为=>',res.data.user.userId);
  166. })
  167. /*聊天监听*/
  168. IMLib.addReceiveMessageListener((res)=>{
  169. this.receiveMessage(res)
  170. })
  171. },
  172. onUnload:function(){
  173. console.log('onUnload')
  174. this.removeAllListeners();
  175. },
  176. onBackPress(){
  177. console.log('返回')
  178. IMLib.disconnect();
  179. },
  180. methods: {
  181. linkUser(targetId){
  182. if(!targetId){console.log("未收到用户id");return;}
  183. let accountInfo=uni.getStorageSync('accountInfo');
  184. if(!accountInfo){return}
  185. accountInfo=JSON.parse(accountInfo);
  186. let rongyunToken=accountInfo.rongyunToken;
  187. rongyunToken=accountInfo.token
  188. this.form.token=rongyunToken;//连接融云的token
  189. this.targetId=targetId;//对方ID
  190. this.connect();
  191. },
  192. removeAllListeners(){
  193. call.unInit();
  194. //移除监听-接收到通话呼入
  195. call.removeCallReceivedListener();
  196. // 移除监听-开始呼叫通话的回调
  197. call.removeCallOutgoingListener();
  198. // 移除监听-通话已接通
  199. call.removeCallReceivedListener();
  200. // 移除监听-通话已结束
  201. call.removeCallDisconnectedListener();
  202. // 移除监听-对端用户正在振铃
  203. call.removeRemoteUserRingingListener();
  204. // 移除监听-对端用户加入了通话
  205. call.removeRemoteUserJoinedListener();
  206. // 移除监听-有用户被邀请加入通话
  207. call.removeRemoteUserInvited();
  208. // 移除监听-对端用户挂断
  209. call.removeRemoteUserLeftListener();
  210. // 移除监听-对端用户切换了媒体类型
  211. call.removeRemoteUserMediaTypeChangedListener();
  212. // 移除监听-通话出现错误的回调
  213. call.removeErrorListener();
  214. },
  215. //是否接入
  216. cutFn(isFlag){
  217. //确认接入
  218. if(isFlag){
  219. this.isCut=false;
  220. if (this.localSession.callId && this.localSession.callId.length > 0) {
  221. this.onCallReceived(this.localSession);
  222. }
  223. }else{
  224. //取消接入
  225. this.isCut=false;
  226. call.hangup();
  227. }
  228. },
  229. //连接IM
  230. connect(){
  231. if(!this.form.appkey){
  232. uni.showToast({
  233. title:"请输入appKey",
  234. icon: "error",
  235. duration:2000
  236. })
  237. return;
  238. }
  239. if (!this.form.token) {
  240. uni.showToast({
  241. title:"请输入token",
  242. icon: "error",
  243. duration:2000
  244. })
  245. return;
  246. }
  247. this.connectIM().then((userId)=>{
  248. this.libPage = true;
  249. this.loginUserId = userId;
  250. uni.showToast({
  251. icon:"none",
  252. title:'连接成功,'+userId
  253. });
  254. if(uni.getSystemInfoSync().platform === 'android'){
  255. permision.requestAndroidPermission('android.permission.CAMERA');
  256. permision.requestAndroidPermission('android.permission.RECORD_AUDIO');
  257. }
  258. }).catch((e)=>{
  259. uni.setStorageSync('login-params',{
  260. appkey:this.form.appkey,
  261. token:this.form.token,
  262. navi:this.form.navi
  263. });
  264. console.log(e)
  265. console.log("连接IM发生错误... code=",e.message);
  266. uni.showToast({
  267. title:imCode(e),
  268. icon: "error",
  269. duration:2000
  270. })
  271. this.isInitIm=false;
  272. });
  273. },
  274. //连接IM
  275. connectIM(){
  276. //判断是否初始化
  277. if(!this.isInitIm){
  278. if(this.form.navi){
  279. console.log('有nav')
  280. console.log(this.form.navi)
  281. IMLib.setServerInfo(this.form.navi,'')
  282. };
  283. IMLib.init(this.form.appkey)
  284. this.isInitIm = true;
  285. }else{
  286. uni.showToast({
  287. title:"正在连接。。。",
  288. icon: "error",
  289. duration:2000
  290. })
  291. return;
  292. }
  293. return new Promise((resolve,reject)=>{
  294. IMLib.connect(this.form.token,(res)=> {
  295. console.log('im已连接')
  296. console.log(res)
  297. if (res.code === 0) {
  298. uni.setStorageSync('login-params',{
  299. appkey:this.form.appkey,
  300. token:this.form.token,
  301. navi:this.form.navi
  302. });
  303. resolve(res.userId);
  304. } else {
  305. reject(res.code);
  306. }
  307. });
  308. });
  309. },
  310. //呼叫
  311. callOut(){
  312. //单聊音频
  313. if(this.callSelect ==='single'&&this.mediaSelect ==='audio'){
  314. if(this.targetId === ''){
  315. uni.showToast({
  316. title:"请输入对方ID",
  317. icon: "error",
  318. duration:2000
  319. })
  320. return;
  321. }
  322. this.callMsg(this.mediaSelect,this.targetId,this.callSelect);
  323. }else if(this.callSelect ==='single'&&this.mediaSelect ==='video'){
  324. if(this.targetId === ''){
  325. uni.showToast({
  326. title:"请输入对方ID",
  327. icon: "error",
  328. duration:2000
  329. })
  330. return;
  331. }
  332. //单聊视频
  333. this.callMsg(this.mediaSelect,this.targetId,this.callSelect);
  334. }else if(this.callSelect ==='group'&&this.mediaSelect ==='video'){
  335. let userIdsArr = this.userIds.split(',');
  336. uni.setStorageSync('room-parameters', {
  337. callType: 'out',
  338. mediaType: this.mediaSelect,
  339. targetId: '',
  340. callSelect:this.callSelect,
  341. groupId:this.groupId,
  342. userIds:userIdsArr
  343. });
  344. uni.navigateTo({
  345. url:'/pages/chatRoom/chatRoom'
  346. });
  347. }else if(this.callSelect ==='group'&&this.mediaSelect ==='audio'){
  348. let userIdsArr = this.userIds.split(',');
  349. uni.setStorageSync('room-parameters', {
  350. callType: 'out',
  351. mediaType: this.mediaSelect,
  352. targetId: '',
  353. callSelect:this.callSelect,
  354. groupId:this.groupId,
  355. userIds:userIdsArr
  356. });
  357. uni.navigateTo({
  358. url:'/pages/chatRoom/chatRoom'
  359. });
  360. }
  361. },
  362. callMsg(mediaSelect,targetId,callSelect){
  363. console.log(targetId)
  364. console.log(mediaSelect)
  365. uni.setStorageSync('room-parameters', {
  366. callType: 'out',
  367. mediaType: mediaSelect,
  368. targetId: targetId,
  369. callSelect:callSelect
  370. });
  371. uni.navigateTo({
  372. url:'/pages/chatRoom/chatRoom'
  373. });
  374. },
  375. //通话类型切换
  376. callChange(e){
  377. this.callSelect = e.target.value;
  378. },
  379. //媒体类型切换
  380. mediaChange(e){
  381. this.mediaSelect = e.target.value;
  382. },
  383. //是否接收逻辑
  384. onCallReceived(session) {
  385. // //呼入
  386. uni.setStorageSync('room-parameters', {
  387. callType: 'in',
  388. mediaType: session.mediaType === 0 ? 'audio' : 'video'
  389. });
  390. //跳转.nvue
  391. uni.navigateTo({
  392. url:'/pages/chatRoom/chatRoom'
  393. });
  394. },
  395. //组件发消息回调
  396. chatSend(info){
  397. if(isEmpty(info)){
  398. return;
  399. }
  400. let item={
  401. msg:info,
  402. type:'mine',
  403. user:'自己'
  404. }
  405. this.chatList.push(item);
  406. },
  407. //融云发送消息
  408. sendMsgIM(){
  409. const msg = {
  410. conversationType: ConversationType.PRIVATE,// 会话类型
  411. targetId: '会话 ID',
  412. content: {
  413. objectName: objectName,
  414. content: '发送内容',
  415. extra: '附加内容'
  416. },
  417. pushContent: '当下发远程推送消息时,在通知栏里会显示这个字段。',
  418. pushData: '远程推送附加信息',
  419. }
  420. sendMessage(msg, (result) => {
  421. // 消息发送成功
  422. if(result.code === 0){
  423. console.log(result.messageId)
  424. }
  425. });
  426. },
  427. // 接受消息回调
  428. receiveMessage(res){
  429. console.log(res)
  430. let item={
  431. msg:res,
  432. user:'对方'
  433. }
  434. this.chatList.push(item);
  435. }
  436. }
  437. }
  438. </script>
  439. <style lang="less" scoped>
  440. page{
  441. height: 90vh;
  442. overflow-y:hidden;
  443. }
  444. .content-lab{
  445. text-align: center;
  446. .btn{
  447. display: inline-block;
  448. color: #fff;
  449. background: #2da2ea;
  450. margin-top: 20px;
  451. }
  452. }
  453. .boxs{
  454. position: fixed;
  455. left: 0;
  456. top: 0;
  457. width: 100%;
  458. height: 100%;
  459. background: rgba(0,0,0,.5);
  460. z-index: 9999;
  461. }
  462. .boxs-cen{
  463. width: 80%;
  464. height: 300upx;
  465. background: #FFFFFF;
  466. position: absolute;
  467. left: 0;
  468. right: 0;
  469. top: 0;
  470. bottom: 0;
  471. margin: auto;
  472. border-radius: 4upx;
  473. }
  474. .boxs-des{
  475. margin-top: 50upx;
  476. color: #000000;
  477. text-align: center;
  478. }
  479. .boxs-btn{
  480. margin-top: 50upx;
  481. display: flex;
  482. justify-content: space-between;
  483. }
  484. .loading{
  485. width: 150upx;
  486. height: 100upx;
  487. margin: 260upx auto 0;
  488. display: flex;
  489. justify-content: space-around;
  490. align-items: center;
  491. span{
  492. display: inline-block;
  493. width: 8px;
  494. height: 100%;
  495. border-radius: 4px;
  496. background: lightgreen;
  497. -webkit-animation: load 1.04s ease infinite;
  498. &:nth-child(2){
  499. -webkit-animation-delay:0.13s;
  500. }
  501. &:nth-child(3){
  502. -webkit-animation-delay:0.26s;
  503. }
  504. &:nth-child(4){
  505. -webkit-animation-delay:0.39s;
  506. }
  507. &:nth-child(5){
  508. -webkit-animation-delay:0.52s;
  509. }
  510. }
  511. }
  512. @-webkit-keyframes load{
  513. 0%,100%{
  514. height: 80upx;
  515. background: lightgreen;
  516. }
  517. 50%{
  518. height: 120upx;
  519. margin-top: -20px;
  520. background: lightblue;
  521. }
  522. }
  523. .loading-type2{
  524. width:500upx;
  525. height: 60px;
  526. margin: 0 auto;
  527. margin-top: 10px;
  528. position: relative;
  529. span{
  530. width: 50px;
  531. height: 30px;
  532. border-radius: 50%;
  533. background: lightgreen;
  534. position: absolute;
  535. top: 50%;
  536. margin-top: -15px;
  537. overflow: hidden;
  538. -webkit-animation: changePosition 2.4s linear infinite;
  539. }
  540. }
  541. @-webkit-keyframes changePosition{
  542. 0%,100%{
  543. -webkit-transform: translate(70px);
  544. }
  545. 20%{
  546. width: 50px;
  547. height: 30px;
  548. margin-top:-15px;
  549. -webkit-transform: translate(0px);
  550. }
  551. 30%{
  552. width: 20px;
  553. height: 60px;
  554. margin-top:-30px;
  555. -webkit-transform: translate(0px);
  556. }
  557. 35%{
  558. width: 50px;
  559. height: 30px;
  560. margin-top:-15px;
  561. -webkit-transform: translate(5px);
  562. background: lightblue;
  563. }
  564. 70%{
  565. width: 50px;
  566. height: 30px;
  567. margin-top:-15px;
  568. -webkit-transform: translate(400upx);
  569. }
  570. 80%{
  571. width: 20px;
  572. height: 60px;
  573. margin-top:-30px;
  574. -webkit-transform: translate(400upx);
  575. }
  576. 85%{
  577. width: 50px;
  578. height: 30px;
  579. margin-top:-15px;
  580. -webkit-transform: translate(390upx);
  581. background: lightgreen;
  582. }
  583. }
  584. </style>