chatRoom.nvue 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707
  1. <template>
  2. <view class="content">
  3. <!-- 单人视频 -->
  4. <view v-if="users.length<=2">
  5. <RongCloud-Call-RCUniCallView
  6. class="bigVideoView"
  7. :style="{width:windowWidth+'px',height:windowHeight+'px'}"
  8. ref="bigVideoView">
  9. </RongCloud-Call-RCUniCallView>
  10. <RongCloud-Call-RCUniCallView
  11. class="smallVideoView"
  12. :style="{width:200+'upx',height:200+'upx'}"
  13. ref="smallVideoView"
  14. >
  15. </RongCloud-Call-RCUniCallView>
  16. </view>
  17. <!-- 多人视频 -->
  18. <view v-else>
  19. <RongCloud-Call-RCUniCallView
  20. class="bigVideoView"
  21. :style="{width:windowWidth+'px',height:300+'px'}"
  22. ref="bigVideoView">
  23. </RongCloud-Call-RCUniCallView>
  24. <view class="smallViews">
  25. <RongCloud-Call-RCUniCallView
  26. v-for="(item,index) in viewArr"
  27. :key="item.userId"
  28. class="smallView"
  29. :ref="item.userId">
  30. </RongCloud-Call-RCUniCallView>
  31. </view>
  32. </view>
  33. <view class="nav">
  34. <text class="nav-com" v-if="callWay === 1" @click="isMark=true">
  35. 邀请
  36. </text>
  37. <text class="nav-com" @click="closeCameraCur">
  38. {{curCamera?'关闭':'开启'}}摄像头
  39. </text>
  40. <text class="nav-com" @click="switchCamera">
  41. 切换摄像头
  42. </text>
  43. <text class="nav-com" @click="microphone">
  44. {{isMicrophone?'关闭':'开启'}}麦克风
  45. </text>
  46. <text class="nav-com" @click="enableSpeaker">
  47. {{isEnableSpeaker?'关闭':'开启'}}扬声器
  48. </text>
  49. <text class="nav-com" v-if="mediaTypeCur === 'video'" @click.stop="isBeauty=!isBeauty">
  50. 美颜
  51. </text>
  52. </view>
  53. <view class="container" :style="{width:windowWidth+'px'}">
  54. <text class="hangup" @click="hangup">挂断 </text>
  55. <text v-if="mediaTypeCur === 'video' " class="hangup" @click="changeMediaType">切换语音 </text>
  56. </view>
  57. <view
  58. class="box-mark"
  59. v-if="isMark"
  60. :style="{width:windowWidth+'px',height:windowHeight+'px'}"
  61. @click.stop=""
  62. >
  63. <view class="box-cen">
  64. <text class="box-des">被邀请者ID:</text>
  65. <view class="box-bot">
  66. <input v-model="inviteUsersIds" ref="inviteInput" class="box-input" type="text" placeholder="请输入被邀请者ID">
  67. <text class="box-tit">必填;需加入群后,方可收到邀请,多个userId用英文半角逗号分开</text>
  68. </view>
  69. <view class="box-btns">
  70. <button class="box-btn" type="default" @click="inviteUsers(false)">取消</button>
  71. <button class="box-btn" type="default" @click="inviteUsers(true)">确定</button>
  72. </view>
  73. </view>
  74. </view>
  75. <view class="beauty"
  76. v-if="isBeauty"
  77. :style="{width:windowWidth+'px'}"
  78. @click.stop=""
  79. >
  80. <view class="beauty-btn">
  81. <view class="change-btn">
  82. <text class="ch-tit">美颜</text><text class="switch-btn" @click="switchChange">{{isChecked?'开启':'关闭'}}</text>
  83. </view>
  84. <view class="close-btn">
  85. <text class="close-tit" @click="isBeauty=false">X</text>
  86. </view>
  87. </view>
  88. <view class="beauty-view">
  89. <view v-if="curIndex === '0'" class="beauty-tab filte-view">
  90. <view
  91. class="tab-item"
  92. v-for="(item) in filteArr"
  93. :key="item.id"
  94. @click="cutFilte(item.id)"
  95. :class = "{current: item.id === curFilte}"
  96. >
  97. <text>{{item.name}}</text>
  98. </view>
  99. </view>
  100. <!-- 美白 -->
  101. <view v-if="curIndex === '1'" class="white-view com-view">
  102. <slider :value="whiteVal" min="0" max="9" @change="whiteChange" show-value />
  103. </view>
  104. <!-- 红润 -->
  105. <view v-if="curIndex === '2'" class="ruddy-view com-view">
  106. <slider :value="ruddyVal" min="0" max="9" @change="ruddyChange" show-value />
  107. </view>
  108. <!-- 磨皮 -->
  109. <view v-if="curIndex === '3'" class="buffing-view com-view">
  110. <slider :value="buffingVal" min="0" max="9" @change="buffingChange" show-value />
  111. </view>
  112. <!-- 亮度 -->
  113. <view v-if="curIndex === '4'" class="brightness-view com-view">
  114. <slider :value="brightnessVal" min="0" max="9" @change="brightnessChange" show-value />
  115. </view>
  116. </view>
  117. <view class="beauty-tab">
  118. <view
  119. class="tab-item"
  120. v-for="(item) in tabArr"
  121. :key="item.id"
  122. @click="curIndex = item.id"
  123. :class = "{current: item.id === curIndex}"
  124. >
  125. <text>{{item.text}}</text>
  126. </view>
  127. </view>
  128. </view>
  129. </view>
  130. </template>
  131. <script>
  132. import * as call from "@/uni_modules/RongCloud-CallWrapper/lib/index"
  133. import * as im from "@/uni_modules/RongCloud-IMWrapper/js_sdk"
  134. export default {
  135. data() {
  136. return {
  137. mediaType: "video",
  138. callType: "out",
  139. callWay:0,//呼叫方式 0 单聊 1 群聊
  140. targetId: "",
  141. bottomHeight: 0,
  142. isConnected: false,
  143. isSelf:false,
  144. viewArr:[],
  145. callSelect:'single',
  146. groupId:'',
  147. userIds:[],
  148. windowWidth:'',
  149. windowHeight:'',
  150. isMicrophone:true,
  151. isEnableSpeaker:true,
  152. curCamera:true,
  153. backCamera:true,
  154. isMe:true,
  155. users:[],
  156. currentCallSession:{},
  157. isMark:false,
  158. inviteUsersIds:'',
  159. mediaTypeCur:'audio',
  160. isBeauty:false,
  161. tabArr:[
  162. {
  163. id:'0',
  164. text:'滤镜'
  165. },
  166. {
  167. id:'1',
  168. text:'美白'
  169. },
  170. {
  171. id:'2',
  172. text:'红润'
  173. },
  174. {
  175. id:'3',
  176. text:'磨皮'
  177. },
  178. {
  179. id:'4',
  180. text:'亮度'
  181. },
  182. ],
  183. filteArr:[
  184. {
  185. id:0,
  186. name:'原画'
  187. },
  188. {
  189. id:1,
  190. name:'唯美'
  191. },
  192. {
  193. id:2,
  194. name:'清新'
  195. },
  196. {
  197. id:3,
  198. name:'浪漫'
  199. }
  200. ],
  201. curIndex:'0',
  202. curFilte:0,
  203. whiteVal:0,
  204. ruddyVal:0,
  205. buffingVal:0,
  206. brightnessVal:5,
  207. isChecked:false
  208. }
  209. },
  210. onLoad: function() {
  211. var _this=this;
  212. uni.getStorage({
  213. key: "room-parameters",
  214. success: (res) => {
  215. this.mediaType = res.data.mediaType;
  216. this.callType = res.data.callType?res.data.callType:'in';
  217. this.groupId = res.data.groupId?res.data.groupId:'';
  218. this.userIds = res.data.userIds?res.data.userIds:'';
  219. if (this.callType === 'out') {
  220. console.log('呼出out')
  221. this.targetId = res.data.targetId;
  222. this.startCall();
  223. } else {
  224. console.log('呼入接受')
  225. this.accept();
  226. }
  227. }
  228. });
  229. uni.getSystemInfo({
  230. success:function(res){
  231. _this.windowWidth = res.windowWidth;
  232. _this.windowHeight = res.windowHeight;
  233. }
  234. })
  235. uni.$on('OnCallConnected',this.onCallConnected)
  236. uni.$on('OnCallDisconnected',this.onCallDisconnected)
  237. this.initBeautyOpton();
  238. },
  239. beforeDestroy(){
  240. uni.$off('OnCallDisconnected');
  241. uni.$off('OnCallConnected');
  242. },
  243. onUnload() {
  244. call.hangup();
  245. },
  246. onHide(){
  247. const session = call.getCurrentCallSession();
  248. if (session) {
  249. call.hangup();
  250. }
  251. },
  252. methods: {
  253. changeMediaType(){
  254. this.mediaTypeCur = 'audio';
  255. call.changeMediaType(0);
  256. },
  257. inviteUsers(flag){
  258. if(flag){
  259. if(this.inviteUsersIds === ''){
  260. uni.showToast({
  261. title:"请输入被邀请者ID",
  262. icon: "error",
  263. duration:2000
  264. })
  265. return;
  266. }
  267. let userIdsArr = this.inviteUsersIds.split(',');
  268. call.inviteUsers(userIdsArr,[]);
  269. }
  270. this.$refs.inviteInput.blur();
  271. this.isMark =false;
  272. },
  273. switchVideo(){
  274. this.isMe = !this.isMe;
  275. let session = call.getCurrentCallSession();
  276. if(this.isMe){
  277. switch(uni.getSystemInfoSync().platform){
  278. case 'android':
  279. call.setVideoView(session.targetId, this.$refs.bigVideoView.ref, 0,false);
  280. call.setVideoView(session.mine.userId, this.$refs.smallVideoView.ref, 0,true);
  281. break;
  282. case 'ios':
  283. call.setVideoView(session.targetId, this.$refs.bigVideoView.ref, 0);
  284. call.setVideoView(session.mine.userId, this.$refs.smallVideoView.ref, 0);
  285. break;
  286. default:
  287. console.log('运行在开发者工具上')
  288. break;
  289. }
  290. }else{
  291. switch(uni.getSystemInfoSync().platform){
  292. case 'android':
  293. call.setVideoView(session.mine.userId, this.$refs.bigVideoView.ref, 0,false);
  294. call.setVideoView(session.targetId, this.$refs.smallVideoView.ref, 0,true);
  295. break;
  296. case 'ios':
  297. call.setVideoView(session.mine.userId, this.$refs.bigVideoView.ref,0);
  298. call.setVideoView(session.targetId, this.$refs.smallVideoView.ref,0);
  299. break;
  300. default:
  301. console.log('运行在开发者工具上')
  302. break;
  303. }
  304. }
  305. },
  306. closeCameraCur(){
  307. this.curCamera = !this.curCamera;
  308. let camera = call.currentCamera();
  309. call.enableCamera(this.curCamera,camera)
  310. },
  311. closeCameraBack(){
  312. this.backCamera = !this.backCamera;
  313. call.enableCamera(this.backCamera,1)
  314. },
  315. switchCamera(){
  316. call.switchCamera();
  317. },
  318. microphone(){
  319. this.isMicrophone = !this.isMicrophone;
  320. call.enableMicrophone(this.isMicrophone);
  321. },
  322. enableSpeaker(){
  323. this.isEnableSpeaker = !this.isEnableSpeaker;
  324. call.enableSpeaker(this.isEnableSpeaker);
  325. },
  326. hangup() {
  327. this.isSelf = true;
  328. console.log('12321332')
  329. call.resetBeauty();
  330. call.hangup();
  331. uni.navigateBack({
  332. delta:1
  333. })
  334. },
  335. accept() {
  336. call.accept();
  337. },
  338. startCall() {
  339. const type = this.mediaType === 'audio' ? 0 : 1;
  340. this.mediaTypeCur = this.mediaType;
  341. if (this.targetId.length > 0) {
  342. call.enableSpeaker(true);
  343. call.startSingleCall(this.targetId, type, null);
  344. // this.currentCallSession = call.getCurrentCallSession();
  345. // this.users = this.currentCallSession.users ? this.currentCallSession.users:[];
  346. }else{
  347. call.startGroupCall(this.groupId, this.userIds,[] , type, '');
  348. this.users = this.userIds;
  349. console.log(this.users);
  350. this.currentCallSession = call.getCurrentCallSession();
  351. this.users = this.currentCallSession.users ? this.currentCallSession.users:[];
  352. }
  353. let _this=this;
  354. im.getCurrentUserId(function(result){
  355. _this.systemInfoSync(result.userId,_this.$refs.bigVideoView.ref,false);
  356. })
  357. // this.systemInfoSync(this.currentCallSession.mine.userId,this.$refs.bigVideoView.ref,false);
  358. },
  359. onCallConnected() {
  360. let context = this;
  361. console.log('oncallconnected接收了');
  362. this.mediaTypeCur = this.mediaType;
  363. call.enableSpeaker(true);
  364. this.currentCallSession = call.getCurrentCallSession();
  365. this.callWay = this.currentCallSession.callType;
  366. this.users = this.currentCallSession.users ? this.currentCallSession.users:[];
  367. let isHasMine = this.users.findIndex((item)=>{
  368. return item.userId === this.currentCallSession.mine.userId;
  369. });
  370. if(isHasMine === -1){
  371. this.users.push(this.currentCallSession.mine);
  372. }
  373. if (this.currentCallSession && this.currentCallSession.users.length > 0 ) {
  374. //视频是两个的时候
  375. if(this.currentCallSession.users.length<=2){
  376. setTimeout(()=>{
  377. this.systemInfoSync(this.currentCallSession.mine.userId,this.$refs.smallVideoView.ref,true);
  378. this.viewArr = this.currentCallSession.users.filter((item)=>{
  379. return item.userId !== this.currentCallSession.mine.userId;
  380. });
  381. this.viewArr.forEach((itm)=>{
  382. this.targetId = itm.userId;
  383. this.systemInfoSync(itm.userId,this.$refs.bigVideoView.ref,false);
  384. });
  385. },100);
  386. }else{
  387. // 视频超过三个
  388. this.$nextTick(()=>{
  389. this.systemInfoSync(this.currentCallSession.mine.userId,this.$refs.bigVideoView.ref,false);
  390. this.viewArr = this.currentCallSession.users.filter((item)=>{
  391. return item.userId !== this.currentCallSession.mine.userId;
  392. });
  393. setTimeout(()=>{
  394. this.viewArr.forEach((itm)=>{
  395. this.systemInfoSync(itm.userId,this.$refs[itm.userId][0].ref,false);
  396. });
  397. },100)
  398. })
  399. }
  400. }
  401. },
  402. systemInfoSync(userId,ref,isZOrderOnTop){
  403. switch(uni.getSystemInfoSync().platform){
  404. case 'android':
  405. call.setVideoView(userId, ref, 0,isZOrderOnTop);
  406. break;
  407. case 'ios':
  408. call.setVideoView(userId, ref, 0);
  409. break;
  410. default:
  411. console.log('运行在开发者工具上')
  412. break;
  413. }
  414. },
  415. onCallDisconnected() {
  416. this.isMe = true;
  417. if(!this.isSelf){
  418. uni.navigateBack({
  419. delta:1
  420. })
  421. }
  422. },
  423. switchChange(){
  424. this.isChecked = !this.isChecked;
  425. if(!this.isChecked){
  426. this.reset();
  427. }else{
  428. this.setBeautyOption();
  429. }
  430. },
  431. //设置美颜
  432. setBeautyOption(){
  433. let option = {
  434. whitenessLevel:this.whiteVal,
  435. ruddyLevel:this.ruddyVal,
  436. smoothLevel:this.buffingVal,
  437. brightLevel:this.brightnessVal
  438. }
  439. if(this.isChecked){//开启
  440. console.log('设置美颜')
  441. call.setBeautyOption(this.isChecked,option);
  442. }
  443. },
  444. //切换滤镜
  445. cutFilte(id){
  446. //切换滤镜打开美颜
  447. if(!this.isChecked){
  448. this.isChecked = true;
  449. }
  450. let option = {
  451. whitenessLevel:this.whiteVal,
  452. ruddyLevel:this.ruddyVal,
  453. smoothLevel:this.buffingVal,
  454. brightLevel:this.brightnessVal
  455. }
  456. //打开滤镜
  457. this.curFilte = id;
  458. this.isChecked?call.setBeautyOption(this.isChecked,option):'';
  459. call.setBeautyFilter(this.curFilte);
  460. },
  461. //美白
  462. whiteChange(e){
  463. console.log('美白',e.detail.value);
  464. //打开美颜
  465. if(!this.isChecked){
  466. this.isChecked = true;
  467. }
  468. this.whiteVal = e.detail.value;
  469. this.setBeautyOption();
  470. },
  471. //红润
  472. ruddyChange(e){
  473. console.log('红润',e.detail.value);
  474. //打开美颜
  475. if(!this.isChecked){
  476. this.isChecked = true;
  477. }
  478. this.ruddyVal = e.detail.value;
  479. this.setBeautyOption();
  480. },
  481. //磨皮
  482. buffingChange(e){
  483. console.log('磨皮',e.detail.value);
  484. //打开美颜
  485. if(!this.isChecked){
  486. this.isChecked = true;
  487. }
  488. this.buffingVal = e.detail.value;
  489. this.setBeautyOption();
  490. },
  491. //亮度
  492. brightnessChange(e){
  493. console.log('亮度',e.detail.value);
  494. //打开美颜
  495. if(!this.isChecked){
  496. this.isChecked = true;
  497. }
  498. this.brightnessVal = e.detail.value;
  499. this.setBeautyOption();
  500. },
  501. //重置
  502. reset(){
  503. call.resetBeauty();
  504. this.initBeautyOpton();
  505. },
  506. initBeautyOpton(){
  507. //初始化滤镜
  508. this.curFilte = call.getCurrentBeautyFilter();
  509. //初始化美颜参数
  510. let beautyOption = call.getCurrentBeautyOption();
  511. this.whiteVal = beautyOption.whitenessLevel;
  512. this.ruddyVal= beautyOption.ruddyLevel;
  513. this.buffingVal = beautyOption.smoothLevel;
  514. this.brightnessVal=beautyOption.brightLevel;
  515. }
  516. }
  517. }
  518. </script>
  519. <style scoped>
  520. .content {
  521. flex: 1;
  522. flex-direction: column;
  523. position: relative;
  524. }
  525. .bigVideoView{
  526. background: #000;
  527. }
  528. .smallVideoView{
  529. position: absolute;
  530. right: 0;
  531. top: 50upx;
  532. width: 200upx;
  533. height: 200upx;
  534. }
  535. .smallViews{
  536. flex-wrap: wrap;
  537. flex-direction: row;
  538. background: #ccc;
  539. }
  540. .smallView{
  541. width: 200upx;
  542. height: 200upx;
  543. margin-right: 20upx;
  544. background: pink;
  545. }
  546. .container {
  547. position: absolute;
  548. bottom: 20upx;
  549. height: 100upx;
  550. flex-direction: row;
  551. justify-content: center;
  552. }
  553. .nav{
  554. position: fixed;
  555. bottom: 200upx;
  556. right: 0;
  557. }
  558. .camera{
  559. background: #ccc;
  560. }
  561. .nav-com{
  562. margin-top: 10upx;
  563. color: #fff;
  564. background: rgba(0,0,0,0.5);
  565. justify-content: center;
  566. align-items: center;
  567. }
  568. .hangup{
  569. width: 200upx;
  570. height: 100upx;
  571. color: #fff;
  572. text-align: center;
  573. line-height: 100upx;
  574. background: red;
  575. margin-right: 50upx;
  576. border-radius: 50upx;
  577. }
  578. .box-mark{
  579. position: fixed;
  580. left: 0;
  581. top: 0;
  582. background: rgba(0,0,0,.5);
  583. z-index: 9999;
  584. justify-content: center;
  585. align-items: center;
  586. color: #fff;
  587. }
  588. .box-cen{
  589. padding: 30upx;
  590. width: 500upx;
  591. height: 500upx;
  592. background: #222831;
  593. }
  594. .box-des{
  595. color: #fff;
  596. }
  597. .box-input{
  598. margin-top: 30upx;
  599. color: #fff;
  600. border: 1upx solid #fff;
  601. }
  602. .box-tit{
  603. margin-top: 30upx;
  604. color: #fff;
  605. }
  606. .box-btn{
  607. margin-top: 30upx;
  608. }
  609. .box-btns{
  610. flex-direction: row;
  611. justify-content: space-between;
  612. padding: 0 30upx;
  613. }
  614. .box-btn{
  615. padding:0 20upx;
  616. }
  617. .beauty{
  618. height: 500upx;
  619. position: fixed;
  620. bottom: 0;
  621. background: #000;
  622. }
  623. .beauty-btn{
  624. height: 100upx;
  625. padding-right: 20upx;
  626. flex-direction: row;
  627. justify-content: space-between;
  628. }
  629. .change-btn{
  630. padding-top:20upx;
  631. flex-direction: row;
  632. }
  633. .switch-btn{
  634. border: 1upx;
  635. border-color: #fff;
  636. padding: 20upx;
  637. background: blue;
  638. color: #fff;
  639. margin-left: 20upx;
  640. margin-top: -10upx;
  641. }
  642. .ch-tit{
  643. margin-top: 8upx;
  644. color: #fff;
  645. }
  646. .ch-res{
  647. margin-top: -10upx;
  648. margin-left: 20upx;
  649. color: #fff;
  650. padding:20upx;
  651. border-radius: 10upx;
  652. justify-content: center;
  653. align-items: center;
  654. background: #4e6ef2;
  655. }
  656. .close-btn{
  657. padding-top:20upx;
  658. }
  659. .close-tit{
  660. color: #fff;
  661. }
  662. .beauty-view{
  663. flex: 1;
  664. background: #ccc;
  665. }
  666. .com-view{
  667. padding-top: 40upx;
  668. background: #ccc;
  669. padding-left: 30upx;
  670. padding-right: 30upx;
  671. }
  672. .beauty-tab{
  673. border-top:1px;
  674. border-top-color: #000000;
  675. padding: 0 20upx;
  676. flex: 1;
  677. background: #fff;
  678. flex-direction: row;
  679. justify-content: space-between;
  680. padding-top: 40upx;
  681. }
  682. .filte-view{
  683. }
  684. .tab-item{
  685. width: 100upx;
  686. height: 100upx;
  687. border:1px;
  688. border-color: #000000;
  689. justify-content: center;
  690. align-items: center;
  691. }
  692. .current{
  693. background: yellow;
  694. }
  695. .white-view{
  696. }
  697. </style>