浏览代码

Merge branch 'master' of http://git.jihengcc.cn/liubaiyan/qjd-user-uniapp

zhaoxw 4 年之前
父节点
当前提交
f8afba6fef

+ 2 - 0
config/api.js

@@ -4,6 +4,8 @@ const WX_API_BASE = 'https://www.qianjiadi.com/'
  //const WX_API_BASE = 'https://test.jihengcc.cn/'
 
 module.exports = {
+	sdkAppID: 1400430241,
+	secretKey: '941e01ca06e94057de3013b235b67a784ea28b45c43decbd518e765f7d5fc140',
 	//  微信登录
 	WxLogin: WX_API_BASE + 'app/auth/user/wx/login',
 	//  获取个人信息

+ 180 - 0
jhim/jhim.js

@@ -0,0 +1,180 @@
+import TIM from './tim-wx';
+import LibGenerateTestUserSig from "./lib-generate-test-usersig-es.min";
+
+const EXPIRETIME = 604800;
+const LOGTAG = '--JHIM--:';
+
+export default class JhIm {
+  constructor(userId, sdkAppID, secretKey) {
+    this.userId = userId;
+    this.sdkAppID = sdkAppID;
+    this.secretKey = secretKey;
+    this.tim = TIM.create({ SDKAppID: this.sdkAppID });
+    const generator = new LibGenerateTestUserSig(this.sdkAppID, this.secretKey, EXPIRETIME);
+    this.userSig = generator.genTestUserSig(this.userId);
+    this.roomId = null;
+    this.logined = false;
+    this.groupReady = false;
+
+    // 0 普通级别,日志量较多,接入时建议使用
+    // 1 release级别,SDK 输出关键信息,生产环境时建议使用
+    // 2 告警级别,SDK 只输出告警和错误级别的日志
+    // 3 错误级别,SDK 只输出错误级别的日志
+    // 4 无日志级别,SDK 将不打印任何日志
+    this.tim.setLogLevel(1);
+    
+    this.tim.on(TIM.EVENT.MESSAGE_RECEIVED, event=>{
+      console.log(LOGTAG+'recv',event);
+      let msgs = [];
+      event.data.forEach(v=>{
+        if(v.type == "TIMTextElem") {
+          msgs.push({
+            name: v.nick,
+            avatar: v.avatar,
+            text: v.payload.text
+          })
+        }else if(v.type == "TIMGroupTipElem") {
+          this.onIMGroupTipElem&&this.onIMGroupTipElem(v.payload);
+        }
+      })
+      
+      this.onIMMessageReceived&&this.onIMMessageReceived(msgs);
+    }, this);
+
+    this.tim.on(TIM.EVENT.SDK_READY, event=>this.onIMSDKReady&&this.onIMSDKReady(event), this);
+    this.tim.on(TIM.EVENT.SDK_NOT_READY, event=>{
+      this.logined = false;
+      this.onIMSDKNotReady&&this.onIMSDKNotReady();
+    }, this);
+	
+    // 收到被踢下线通知
+    // event.name - TIM.EVENT.KICKED_OUT
+    // event.data.type - 被踢下线的原因,例如 :
+    //    - TIM.TYPES.KICKED_OUT_MULT_ACCOUNT 多实例登录被踢
+    //    - TIM.TYPES.KICKED_OUT_MULT_DEVICE 多终端登录被踢
+    //    - TIM.TYPES.KICKED_OUT_USERSIG_EXPIRED 签名过期被踢。使用前需要将SDK版本升级至v2.4.0或以上。
+    this.tim.on(TIM.EVENT.KICKED_OUT, event=>this.onIMKickedOut&&this.onIMKickedOut(event), this);
+
+    // 收到 SDK 发生错误通知,可以获取错误码和错误信息
+    // event.name - TIM.EVENT.ERROR
+    // event.data.code - 错误码
+    // event.data.message - 错误信息
+    this.tim.on(TIM.EVENT.ERROR, event=>this.onIMError&&this.onIMError(event), this);
+    return this;
+  }
+  on(name, cb) {
+    this[name] = cb;
+    return this;
+  }
+  off(name) {
+    this[name] = null;
+    return this;
+  }
+  login(name, avatar) {
+    if(this.logined) return Promise.resolve();
+    
+    this.name = name; 
+    this.avatar = avatar;
+    return new Promise(resolve=>{
+      let cb = event=>{
+        this.logined = true;
+        this.tim.updateMyProfile({
+          nick: name,
+          avatar: avatar,
+          allowType: TIM.TYPES.ALLOW_TYPE_ALLOW_ANY
+        });
+        console.log(LOGTAG+'ready');
+        this.onIMReady&&this.onIMReady(event);
+        resolve();
+        this.tim.off(TIM.EVENT.SDK_READY, cb, this);
+      }
+      this.tim.on(TIM.EVENT.SDK_READY, cb, this);
+      console.log(LOGTAG+'login');
+      this.tim.login({
+        userID: this.userId,
+        userSig: this.userSig,
+      })
+    });
+  }
+  logout() {
+    if(!this.logined) return Promise.resolve();
+
+    return this.tim.logout().then(()=>{
+      this.logined = false;
+    });
+  }
+  createGroup(roomId) {
+    console.log(LOGTAG+'search for createGroup', roomId);
+    this.roomId = String(roomId);
+    return this.tim.searchGroupByID(this.roomId).then(()=>{
+      return this.joinGroup(roomId);
+    },()=>{
+      console.log(LOGTAG+'createGroup');
+      return this.tim.createGroup({
+        groupID: this.roomId,
+        name: this.roomId,
+        type: TIM.TYPES.GRP_AVCHATROOM,
+      }).then(() => { 
+        return this.joinGroup(roomId);
+      });
+    });
+  }
+  dismissGroup() {
+    console.log(LOGTAG+'dismissGroup');
+		return this.tim.dismissGroup(this.roomId).then(() => {
+      this.groupReady = false;
+      this.roomId = null;
+    });
+  }
+  joinGroup(roomId) {
+    console.log(LOGTAG+'joinGroup',roomId);
+    this.roomId = String(roomId);
+    return this.tim.joinGroup({ 
+      groupID: this.roomId, 
+      type: TIM.TYPES.GRP_AVCHATROOM 
+    }).then((imResponse) => {
+      console.log(LOGTAG+'joinGrouped',imResponse.data.status);
+			switch (imResponse.data.status) {
+			  case TIM.TYPES.JOIN_STATUS_WAIT_APPROVAL: // 等待管理员同意
+				  break;
+			  case TIM.TYPES.JOIN_STATUS_SUCCESS: // 加群成功
+        case TIM.TYPES.JOIN_STATUS_ALREADY_IN_GROUP: // 已经在群中
+          this.groupReady = true;
+				  break;
+			}
+		});
+  }
+  exitGroup() {
+    console.log(LOGTAG+'exitGroup');
+    return this.tim.quitGroup(this.roomId).then(()=>{
+      this.groupReady = false;
+      this.roomId = null;
+    });
+  }
+  sendGroupText(text) {
+    const message = this.tim.createTextMessage({
+      to: this.roomId,
+      conversationType: TIM.TYPES.CONV_GROUP,
+      payload: {text},  
+    })
+    return this.tim.sendMessage(message).then(()=>({
+      name: this.name,
+      avatar: this.avatar,
+      text: text,
+    }));
+  }
+  sendGroupMessage(payload) {
+    const message = this.tim.createCustomMessage({
+      to: this.roomId,
+      conversationType: TIM.TYPES.CONV_GROUP,
+      payload,
+    })
+    return this.tim.sendMessage(message);
+  }
+  getGroupProfile() {
+    return this.tim.getGroupProfile({ groupID: this.roomId }).then(res => imResponse.data.group);
+  }
+  getGroupNum() {
+    return this.getGroupProfile(res=>res.memberCount);
+  }
+}

+ 115 - 0
jhim/jhimlive.vue

@@ -0,0 +1,115 @@
+<template>
+	<view class="jhim-container">
+    <view class="jhim-message-box">
+      <view class="jhim-message" v-for="(item, index) in msgs.slice(0,5)" :key="index">
+        <image class="jhim-message-avatar" :src="item.avatar" />
+        <text class="jhim-message-text" >{{item.name}}:{{item.text}}</text>
+      </view>
+    </view>
+    <view v-if="ready" class="jhim-input-box">
+      <input 
+        class="jhim-input"
+        placeholder="说点什么..." 
+        placeholder-style="color:#fff" 
+        v-model="input"
+        confirm-type="send" @confirm="btnImSend" />
+    </view>
+    <view v-else class="jhim-logining"><text class="jhim-logining-text">登录中...</text></view>
+	</view>
+</template>
+
+<script>
+
+import Jhim from "./jhim";
+const LOGTAG = '--JHIM--:';
+
+export default {
+  name: 'jhim',
+	data() {
+		return {
+      input: '',
+      msgs: [],
+      ready: false,
+		};
+	},
+	props: {
+    sdkAppID: Number,
+    secretKey: String,
+    userId: String,
+    roomId: String,
+    name: String,
+    avatar: String,
+	},
+	methods: {
+		enterRoom() {
+      this.jhim = this.jhim||(Jhim.jhim)||(new Jhim(this.userId, this.sdkAppID, this.secretKey));
+
+      this.jhim.on('onIMMessageReceived', event=>{
+        this.msgs = this.msgs.concat(event);
+      }).on('onIMGroupTipElem', res=>{
+        this.$emit('onMemberCount', this.memberCount = res.memberCount);
+      }).on('onIMSDKNotReady', event=>{
+        this.ready = false;
+      }).on('onIMSDKReady', event=>{
+        this.ready = true;
+      })
+
+      this.jhim.login(this.name, this.avatar).then(()=>this.jhim.createGroup(this.roomId));
+		},
+		exitRoom() {
+      if(this.isAuthor) {
+        this.jhim.dismissGroup().then(()=>this.jhim.logout());
+      }else {
+        this.jhim.exitGroup().then(()=>this.jhim.logout());
+      }
+    },
+    btnImSend() {
+      this.jhim.sendGroupText(this.input).then(msg=>{
+        this.input = '';
+				this.msgs.push(msg);
+			});
+    }
+	}
+};
+</script>
+
+<style scoped>
+
+/* .jhim-container {
+  
+} */
+.jhim-message-box {
+  background-color:rgba(0, 0, 0, 0.4);
+  border-radius: 1000px;
+  padding: 5;
+}
+.jhim-message {
+  display: flex;
+  flex-direction: row;
+  align-items: center;
+}
+.jhim-message-avatar {
+  width: 24rpx;
+  height: 24rpx;
+  margin-left: 5px;
+}
+.jhim-message-text {
+  color: #fff;
+  font-size: 24rpx;
+}
+.jhim-input-box {
+  padding: 5px;
+}
+.jhim-input {
+  color: #fff;
+  font-size: 24rpx;
+}
+.jhim-logining {
+  padding: 5px;
+}
+.jhim-logining-text {
+  color: #fff;
+  font-size: 24rpx;
+}
+
+</style>

文件差异内容过多而无法显示
+ 1217 - 0
jhim/lib-generate-test-usersig-es.min.js


文件差异内容过多而无法显示
+ 0 - 0
jhim/tim-wx.js


二进制
jhlive/.DS_Store


+ 257 - 0
jhlive/jhlive.nvue

@@ -0,0 +1,257 @@
+<template>
+	<view class="container-jhlive" data-type="jhlive">
+    <JhliveApp 
+      class="liveView"
+      ref="liveView"
+      :sdkAppID="sdkAppID"
+      :userSig="userSig"
+      :userid="userId" 
+      :roomid="roomId" 
+      :isAuthor="isAuthor"
+      :linkMic="linkMic" 
+      :liveEvent="handleLiveEvent" />
+    <view class="top_left_box">
+      <image class="top_left_box_img" :src="avatar"></image>
+      <view class="top_left_box_text">
+        <text class="top_left_box_text1">{{name}}</text>
+        <text class="top_left_box_text2" >{{num}}</text>
+      </view>
+    </view>
+
+    <view class="top-right-box">
+			<view class="top-right-box-btn" v-if="isAuthor" @click="btnBeautify">
+        <text class="top-right-box-btn-text">美颜</text>
+      </view>
+      <view class="top-right-box-btn" v-if="isAuthor" @click="btnChangeCamera">
+        <text class="top-right-box-btn-text">切换</text>
+      </view>
+    </view>
+
+    <view class="bottom-right-box">
+      <view class="bottom-right-box-btn" @click="btnLike">
+        <text class="bottom-right-box-btn-text">点赞</text>
+      </view>
+    </view>
+	</view>
+</template>
+
+<script>
+
+import LibGenerateTestUserSig from "./lib-generate-test-usersig-es.min";
+
+// #ifdef MP-WEIXIN
+import JhliveApp from './live-wechat';
+//#endif
+
+const LOGTAG = '--JHLIVE--:';
+const EXPIRETIME = 604800;
+
+export default {
+  name: 'jhlive',
+  // #ifdef MP-WEIXIN
+  components: {JhliveApp},
+  //#endif
+
+	data() {
+		return {
+      userSig: '',
+      beautifyLevel: false,
+		};
+	},
+
+	props: {
+    sdkAppID: Number,
+    secretKey: String,
+    userId: String,
+    roomId: String,
+    isAuthor: Boolean,
+    linkMic: Boolean,
+    name: String,
+    avatar: String,
+    num: String,
+	},
+	onLoad() {
+    this.init();
+	},
+	onUnload() {
+		this.destroy();
+	},
+	methods: {
+    init() {
+      this.remoteUsers = [];
+      uni.setKeepScreenOn({
+        keepScreenOn: true
+      });
+    },
+    destroy() {
+      uni.setKeepScreenOn({
+        keepScreenOn: false
+      });
+      this.exitRoom()
+    },
+		enterRoom() {
+      if(!this.$refs.liveView) {
+        console.log(LOGTAG+'no jhlive');
+        uni.showToast({
+          title: '直播组件初始化失败',
+          duration: 2000
+        });
+        return;
+      }
+      console.log(LOGTAG+'enterRoom', this.isAuthor, this.linkMic, this.sdkAppID, this.secretKey, this.userId, this.roomId);
+      const generator = new LibGenerateTestUserSig(this.sdkAppID, this.secretKey, EXPIRETIME);
+      this.userSig = generator.genTestUserSig(String(this.userId));
+      this.$nextTick(() => this.$refs.liveView.enterRoom());
+		},
+		exitRoom() {
+      console.log(LOGTAG+'exitRoom');
+			this.$refs.liveView.exitRoom();
+    },
+    btnChangeCamera() {
+      console.log(LOGTAG+'btnChangeCamera');
+      this.$refs.liveView.switchCarema();
+    },
+    btnBeautify() {
+      console.log(LOGTAG+'btnBeautify', this.beautifyLevel);
+      // blv - 美颜级别取值范围0 - 9; 0表示关闭,1 - 9值越大
+      // wlv - 亮度级别取值范围0 - 9; 0表示关闭,1 - 9值越大
+      // beautyStyle  美颜风格.三种美颜风格:0 :光滑 1:自然 2:朦胧
+      this.beautifyLevel = !this.beautifyLevel;
+      this.$refs.liveView.setBeauty(
+        this.beautifyLevel?9:0,
+        this.beautifyLevel?9:0,
+        this.beautifyLevel?0:0,
+      );
+    },
+    handleLiveEvent(event) {
+      if(event.eventName=='onRemoteUserEnterRoom'&&!this.remoteUsers.find(v=>v==event.eventData)) {
+        this.remoteUsers.push(event.eventData);
+        this.$emit('onRemoteUser', this.remoteUsers);
+      }else if(event.eventName=='onRemoteUserLeaveRoom') {
+        this.remoteUsers = this.remoteUsers.filter(v=>v!=event.eventData);
+        this.$emit('onRemoteUser', this.remoteUsers);
+      }else if(event.eventName=='onError') {
+        this.$emit('onError', event.eventData.msg);
+        uni.showToast({
+          title: event.eventData.msg,
+          duration: 2000
+        });
+      }
+    },
+	}
+};
+</script>
+
+<style scoped>
+
+.container-jhlive {
+  position: relative;
+  display: flex;
+  flex-direction: column;
+  align-items: stretch;
+  background-color: black;
+  width: 100%;
+  height: 100%;
+}
+
+.liveView {
+  flex: 1;
+}
+
+.top_left_box {
+  left: 0;
+  top: 0;
+  margin-left: 10px;
+  margin-top: 10px;
+  position: absolute;
+  z-index: 100;
+  background-color:rgba(0, 0, 0, 0.4);
+  border-radius: 1000px;
+  display: flex;
+  flex-direction: row;
+  padding: 10px;
+}
+.top_left_box_img {
+  width: 80rpx;
+  height: 80rpx;
+  border-radius: 1000px;
+  background-color: white;
+}
+.top_left_box_text {
+  margin-left: 10px;
+  flex: 1;
+}
+.top_left_box_text1 {
+  font-size: 28rpx;
+  color: white;
+}
+.top_left_box_text2 {
+  font-size: 20rpx;
+  color: white;
+}
+
+
+.top-right-box {
+  right: 0;
+  top: 0;
+  margin-top: 10px;
+  margin-right: 10px;
+  position: absolute;
+  z-index: 100;
+  display: flex;
+  flex-direction: row;
+}
+.top-right-box-btn {
+	color: white;
+  margin-left: 5px;
+}
+.top-right-box-btn-text {
+  color: white;
+}
+
+
+.bottom-left-box {
+  left: 0;
+  bottom: 0;
+  margin-left: 10px;
+  margin-bottom: 10px;
+  position: absolute;
+  z-index: 100;
+}
+.bottom-left-box-login {
+  color: white;
+}
+.bottom-left-box-messages {
+
+}
+.bottom-left-box-message {
+
+}
+.bottom-left-box-input-box {
+
+}
+.bottom-left-box-input {
+  color: #fff;
+  font-size: 30rpx;
+}
+
+
+.bottom-right-box {
+  right: 0;
+  bottom: 0;
+  margin-bottom: 10px;
+  margin-right: 10px;
+  position: absolute;
+  z-index: 100;
+  display: flex;
+  flex-direction: row;
+}
+.bottom-right-box-btn {
+	color: white;
+  margin-left: 5px;
+}
+.bottom-right-box-btn-text {
+	color: white;
+}
+
+</style>

文件差异内容过多而无法显示
+ 1217 - 0
jhlive/lib-generate-test-usersig-es.min.js


+ 52 - 0
jhlive/live-app.vue

@@ -0,0 +1,52 @@
+<template>
+	<JhliveApp 
+    class="container"
+    ref="jhliveApp"
+    :sdkAppID="sdkAppID"
+    :userSig="userSig"
+    :userid="userid" 
+    :roomid="roomid" 
+    :isAuthor="isAuthor"
+    :linkMic="linkMic" />
+</template>
+
+<script>
+
+export default {
+	data() {
+		return {
+			
+		};
+	},
+	props: {
+		props: {
+      sdkAppID: Number,
+      userSig: String,
+      userid: String,
+      roomid: String, 
+      isAuthor: Boolean,
+      linkMic: Boolean
+    },
+	},
+	mounted: function() {
+
+	},
+	destroyed: function() {
+		
+	},
+	methods: {
+		enterRoom: function() {
+			this.$refs.jhliveApp.enterRoom();
+		},
+		exitRoom: function() {
+			this.$refs.jhliveApp.exitRoom();
+		}
+	}
+};
+</script>
+
+<style scoped>
+.container {
+  flex: 1;
+}
+</style>

+ 352 - 0
jhlive/live-wechat.vue

@@ -0,0 +1,352 @@
+<template>
+	<view class="container" data-type="template" data-is="1v1" data-attr="pusher, streamList, debug">
+    <view v-for="item in streams.slice(0,1)" :key="item.streamID" class="player-container" :style="'display:'+playerStyle">
+      <template v-if="item.src && (item.hasVideo || item.hasAudio)">
+        <live-player
+          class="player"
+          :data-userid="item.userID"
+          :data-streamid="item.streamID"
+          :data-streamtype="item.streamType"
+          :src="item.src"
+          :mode="item.mode"
+          :autoplay="item.autoplay"
+          :mute-audio="item.muteAudio"
+          :mute-video="item.muteVideo"
+          :orientation="item.orientation"
+          :object-fit="item.objectFit"
+          :background-mute="item.enableBackgroundMute"
+          :min-cache="item.minCache"
+          :max-cache="item.maxCache"
+          :sound-mode="item.soundMode"
+          :enable-recv-message="item.enableRecvMessage"
+          :auto-pause-if-navigate="item.autoPauseIfNavigate"
+          :auto-pause-if-open-native="item.autoPauseIfOpenNative"
+          :debug="debug"
+          @statechange="playerStateChangeFun"
+          @fullscreenchange="playerFullscreenChangeFun"
+          @netstatus="playerNetStatusFun"
+          @audiovolumenotify="playerAudioVolumeNotifyFun"
+          :idAttr="item.streamID" />
+      </template>
+    </view>
+    <view v-if="pusher.url" class="pusher-container" :style="'display:'+pusherStyle">
+      <live-pusher
+        class="pusher"
+        :url="pusher.url"
+        :mode="pusher.mode"
+        :autopush="pusher.autopush"
+        :enable-camera="pusher.enableCamera"
+        :enable-mic="pusher.enableMic"
+        :enable-agc="pusher.enableAgc"
+        :enable-ans="pusher.enableAns"
+        :enable-ear-monitor="pusher.enableEarMonitor"
+        :auto-focus="pusher.enableAutoFocus"
+        :zoom="pusher.enableZoom"
+        :min-bitrate="pusher.minBitrate"
+        :max-bitrate="pusher.maxBitrate"
+        :video-width="pusher.videoWidth"
+        :video-height="pusher.videoHeight"
+        :beauty="pusher.beautyLevel"
+        :whiteness="pusher.whitenessLevel"
+        :orientation="pusher.videoOrientation"
+        :aspect="pusher.videoAspect"
+        :device-position="pusher.frontCamera"
+        :remote-mirror="pusher.enableRemoteMirror"
+        :local-mirror="pusher.localMirror"
+        :background-mute="pusher.enableBackgroundMute"
+        :audio-quality="pusher.audioQuality"
+        :audio-volume-type="pusher.audioVolumeType"
+        :audio-reverb-type="pusher.audioReverbType"
+        :waiting-image="pusher.waitingImage"
+        :debug="debug"
+        @statechange="pusherStateChangeHandlerFun"
+        @netstatus="pusherNetStatusHandlerFun"
+        @error="pusherErrorHandlerFun"
+        @bgmstart="pusherBGMStartHandlerFun"
+        @bgmprogress="pusherBGMProgressHandlerFun"
+        @bgmcomplete="pusherBGMCompleteHandlerFun" />
+    </view>
+  </view>
+</template>
+
+<script>
+const LOGTAG = '--JHLIVE--:';
+const pusherStateCodeDic = {
+  1001: '已经连接推流服务器',
+  1002: '已经与服务器握手完毕,开始推流',
+  1003: '打开摄像头成功',
+  1004: '录屏启动成功',
+  1005: '推流动态调整分辨率',
+  1006: '推流动态调整码率',
+  1007: '首帧画面采集完成',
+  1008: '编码器启动',
+  1018: '进房成功',
+  1019: '退出房间',
+  2003: '渲染首帧视频',
+  1020: '远端用户全量列表更新',
+  1031: '远端用户进房通知',
+  1032: '远端用户退房通知',
+  1033: '用户视频状态变化,新增stream或者更新stream',
+  1034: '远端用户音频状态位变化通知',
+  '-1301': '打开摄像头失败',
+  '-1302': '打开麦克风失败',
+  '-1303': '视频编码失败',
+  '-1304': '音频编码失败',
+  '-1307': '推流连接断开',
+  '-100018': '进房失败',
+  '5000': '小程序被挂起',
+  '1021': '网络类型发生变化,需要重新进房',
+  '2007': '本地视频播放loading',
+  '2004': '本地视频播放开始',
+}
+
+const defaultStreamParams = {
+  streamType: '',
+  src: '',
+  mode: 'RTC',
+  autoplay: true, // 7.0.9 必须设置为true,否则 Android 有概率调用play()失败
+  muteAudio: false, // 默认不拉取音频,需要手动订阅
+  muteVideo: false, // 默认不拉取视频,需要手动订阅
+  orientation: 'vertical', // 画面方向 vertical horizontal
+  objectFit: 'fillCrop', // 填充模式,可选值有 contain,fillCrop
+  enableBackgroundMute: false, // 进入后台时是否静音(已废弃,默认退台静音)
+  minCache: 1, // 最小缓冲区,单位s(RTC 模式推荐 0.2s)
+  maxCache: 2, // 最大缓冲区,单位s(RTC 模式推荐 0.8s)
+  soundMode: 'speaker', // 声音输出方式 ear speaker
+  enableRecvMessage: 'false', // 是否接收SEI消息
+  autoPauseIfNavigate: true, // 当跳转到其它小程序页面时,是否自动暂停本页面的实时音视频播放
+  autoPauseIfOpenNative: true // 当跳转到其它微信原生页面时,是否自动暂停本页面的实时音视频播放
+}
+
+export default {
+  name: 'jhlive-wechat',
+	data() {
+		return {
+      pusher: {
+        url: '',
+        mode: 'RTC', // RTC:实时通话(trtc sdk) live:直播模式(liteav sdk)
+        autopush: false, // 自动推送
+        enableCamera: false, // 是否开启摄像头
+        enableMic: false, // 是否开启麦克风
+        enableAgc: false, // 是否开启音频自动增益
+        enableAns: false, // 是否开启音频噪声抑制
+        enableEarMonitor: false, // 是否开启耳返(目前只在iOS平台有效)
+        enableAutoFocus: true, // 是否自动对焦
+        enableZoom: false, // 是否支持调整焦距
+        minBitrate: 200, // 最小码率
+        maxBitrate: 1000, // 最大码率
+        videoWidth: 360, // 视频宽(若设置了视频宽高就会忽略aspect)
+        videoHeight: 640, // 视频高(若设置了视频宽高就会忽略aspect)
+        beautyLevel: 0, // 美颜,取值范围 0-9 ,0 表示关闭
+        whitenessLevel: 0, // 美白,取值范围 0-9 ,0 表示关闭
+        videoOrientation: 'vertical', // vertical horizontal
+        videoAspect: '9:16', // 宽高比,可选值有 3:4,9:16
+        frontCamera: 'front', // 前置或后置摄像头,可选值:front,back
+        enableRemoteMirror: false, // 设置推流画面是否镜像,产生的效果会表现在 live-player
+        localMirror: 'auto', // auto:前置摄像头镜像,后置摄像头不镜像(系统相机的表现)enable:前置摄像头和后置摄像头都镜像 disable: 前置摄像头和后置摄像头都不镜像
+        enableBackgroundMute: false, // 进入后台时是否静音
+        audioQuality: 'high', // 高音质(48KHz)或低音质(16KHz),可选值:high,low
+        audioVolumeType: 'voicecall', // 声音类型 可选值: media: 媒体音量,voicecall: 通话音量
+        audioReverbType: 0, // 音频混响类型 0: 关闭 1: KTV 2: 小房间 3:大会堂 4:低沉 5:洪亮 6:金属声 7:磁性
+        waitingImage: '', // 当微信切到后台时的垫片图片 trtc暂不支持
+        waitingImageHash: ''
+      },
+      users: [],
+		};
+	},
+
+	props: {
+		sdkAppID: Number,
+    userSig: String,
+    userid: String,
+    roomid: String, 
+    isAuthor: Boolean,
+    linkMic: Boolean
+  },
+  computed: {
+    streams() {
+      console.log(LOGTAG+'users', this.users);
+      let streams = [];
+      this.users.forEach(v=>{
+        let userStreams = Object.entries(v.streams);
+        streams = streams.concat(userStreams.map(([kk,vv])=>vv).filter(vv=>vv.hasVideo));
+      });
+      console.log(LOGTAG+'streams', streams);
+      return streams;
+    },
+    playerStyle() {
+      return (!this.isAuthor)?'block':'none';
+    },
+    pusherStyle() {
+      return this.isAuthor?'block':'none';
+    }
+  },
+	methods: {
+    enterRoom() {
+      this.pusher.url = `room://cloud.tencent.com/rtc?sdkappid=${this.sdkAppID}&roomid=${this.roomid}&userid=${this.userid}&usersig=${this.userSig}&appscene=live&encsmall=1&cloudenv=PRO`;
+      this.pusher.autopush = this.isAuthor||this.linkMic;
+      this.pusher.enableCamera = this.isAuthor;
+      this.pusher.enableMic = this.isAuthor||this.linkMic;
+      this.$nextTick(()=>{
+        this.pusherContext = wx.createLivePusherContext();
+        this.pusherContext.start();
+      })
+      console.log(LOGTAG+'pusher',this.pusher);
+		},
+		exitRoom: function() {
+			if (this.pusherContext) {
+        this.pusherContext.stop();
+        this.pusherContext = null;
+      }
+    },
+    switchCarema() {
+      this.pusher.frontCamera = this.pusher.frontCamera=='front'?'back':'front';
+      console.log(LOGTAG+'pusher',this.pusher);
+    },
+    setBeauty(blv, wlv) {
+      this.pusher.beautyLevel = blv;
+      this.pusher.whitenessLevel = wlv;
+      console.log(LOGTAG+'pusher',this.pusher);
+    },
+
+    /** --- pusher event handler --- **/
+		pusherStateChangeHandlerFun: function(event) {
+			const code = event.detail.code;
+      const message = event.detail.message;
+      console.log(LOGTAG+'pusherState',code, pusherStateCodeDic[code]);
+      
+			// 远端用户进房通知
+      if(code == 1031) {
+        const data = JSON.parse(event.detail.message)||{};
+        (data.userlist||[]).forEach( v=> {
+          if(!this.users.find(vv => vv.userid == v.userid)) {
+            this.users.push({
+              userid: v.userid,
+              streams: {},
+            });
+            this.$emit('liveEvent', {detail:{eventName: 'onRemoteUserEnterRoom', eventData: {userId: v.userid}}});
+          }
+        })
+      }
+
+      // 远端用户退房通知
+      if(code == 1032) {
+        const data = JSON.parse(event.detail.message)||{};
+        (data.userlist||[]).forEach( v=> {
+          let user = this.users.find(v => v.userid == data.userid);
+          if(!user) return;
+          user.streams.forEach(vv=>{
+            if(vv.playerContext) {
+              vv.playerContext.stop;
+              vv.playerContext = null;
+            }
+          });
+          user.streams = [];
+          this.$emit('liveEvent', {detail:{eventName: 'onRemoteUserLeaveRoom', eventData: {userId: v.userid}}});
+        })
+        this.users = this.users.filter(v => (data.userlist||[]).find(vv=>vv.userid!=v.userid));
+      }
+
+      // 用户视频状态变化,新增stream或者更新stream 状态
+      if(code == 1033) {
+        const data = JSON.parse(event.detail.message)||{};
+        (data.userlist||[]).forEach( v=> {
+          let user = this.users.find(vv => v.userid == v.userid);
+          if(!user) return;
+          let stream = user.streams[v.streamtype] = user.streams[v.streamtype] || {...defaultStreamParams};
+          stream.streamtype = v.streamtype;
+          stream.userID = v.userid;
+          stream.streamID = v.userid + '_' + stream.streamType;
+          stream.hasVideo = v.hasvideo;
+          stream[`has${stream.streamType}Video`] = stream.hasVideo;
+          stream.src = v.playurl;
+          if(stream.hasVideo) stream.playerContext = wx.createLivePlayerContext(stream.streamID, this);
+        })
+        this.users = [...this.users];
+      }
+        
+      // 远端用户音频状态位变化通知
+      if(code == 1034) {
+        console.log('远端用户音频状态位变化通知', data);
+        const data = JSON.parse(event.detail.message)||{};
+        (data.userlist||[]).forEach( v=> {
+          let user = this.users.find(vv => v.userid == vv.userid);
+          if(!user) return;
+          v.streamtype = 'main';
+          let stream = user.streams[v.streamtype] = user.streams[v.streamtype] || {...defaultStreamParams}
+          stream.streamtype = v.streamtype;
+          stream.userID = v.userid;
+          stream.streamID = v.userid + '_' + stream.streamType;
+          stream.hasAudio = v.hasaudio;
+          stream[`has${stream.streamType}Audio`] = stream.hasAudio;
+          stream.src = v.playurl;
+          if(stream.hasAudio) stream.playerContext = wx.createLivePlayerContext(stream.streamID, this);
+        })
+        this.users = [...this.users];
+      }
+		},
+		pusherNetStatusHandlerFun: function(event) {
+			
+		},
+		pusherErrorHandlerFun: function(event) {
+      this.$emit('liveEvent', {detail:{eventName: 'onError', eventData: {msg: '推送错误'}}});
+      console.error(LOGTAG+'pusher error: ',event.detail);
+		},
+		pusherBGMStartHandlerFun: function(event) {
+			
+		},
+		pusherBGMProgressHandlerFun: function(event) {
+			
+		},
+		pusherBGMCompleteHandlerFun: function(event) {
+			
+    },
+    
+    /** --- player event handler --- **/
+		playerStateChangeFun: function(event) {
+      console.log(LOGTAG+'playerStateChangeFun');
+		},
+		playerFullscreenChangeFun: function(event) {
+      console.log(LOGTAG+'playerFullscreenChangeFun');
+		},
+		playerNetStatusFun: function(event) {
+      console.log(LOGTAG+'playerNetStatusFun');
+      let dataset = event.currentTarget.dataset;
+      let info = event.detail.info;
+      let user = this.users.find(v => v.userid == dataset.userid);
+      if(!user) return;
+      let stream = user.streams[dataset.streamtype];
+      if(!stream) return;
+      stream.videoWidth = info.videoWidth;
+      stream.videoHeight = info.videoHeight;
+		},
+		playerAudioVolumeNotifyFun: function(event) {
+      console.log(LOGTAG+'playerAudioVolumeNotifyFun');
+		},
+	}
+};
+</script>
+
+<style lang="less" scoped>
+.container {
+  width: 100%;
+  height: 100%;
+}
+.pusher-container {
+  width: 100%;
+  height: 100%;
+}
+.player-container{
+  width: 100%;
+  height: 100%;
+}
+.pusher {
+  width: 100%;
+  height: 100%;
+}
+.player {
+  width: 100%;
+  height: 100%;
+}
+
+</style>

+ 1 - 0
manifest.json

@@ -6,6 +6,7 @@
     "versionCode" : "100",
     "transformPx" : false,
     "app-plus" : {
+        "nvueCompiler":"uni-app",
         "usingComponents" : true,
         "compilerVersion" : 3,
         /* 5+App特有相关 */

+ 124 - 0
pagesGood/liveDetail.nvue

@@ -0,0 +1,124 @@
+<template>
+	<view class="container" :style="'height: '+windowHeight+'px;'">
+    <jhlive 
+			ref="jhlive" 
+			class="jhlive"
+			:sdkAppID="sdkAppID" 
+			:secretKey="secretKey"
+			:userId="userId"
+			:roomId="roomId"
+			:isAuthor="isAuthor"
+			:linkMic="linkMic" 
+			:avatar="avatar"
+			:num="num"
+			:likes="likes"
+      :name="name" />
+    <jhimlive 
+			ref="jhimlive" 
+			class="jhimlive"
+			:sdkAppID="sdkAppID" 
+			:secretKey="secretKey"
+			:userId="userId"
+			:roomId="roomId"
+			:isAuthor="isAuthor"
+			:avatar="avatar"
+      :name="name" 
+			@onMemberCount="num=$event"/>
+	</view>
+</template>
+
+<script>
+  import jhlive from "@/jhlive/jhlive";
+  import jhimlive from "@/jhim/jhimlive";
+	const NET = require('@/utils/request')
+	const API = require('@/config/api')
+	
+	export default {
+		components: { jhlive, jhimlive },
+		data() {
+			return {
+        isAuthor: false,
+        linkMic: false,
+        sdkAppID:API.sdkAppID,
+			  secretKey:API.secretKey,
+				windowWidth: 0,
+				windowHeight: 0,
+				userId: '',
+				roomId: '',
+				liveId: '',
+				num: 0,
+				likes: 0,
+				name:"",
+				avatar:"../static/images/loginLogo.png",
+        userData: {},
+        enabledIM: false,
+				imReady: false,
+        imMsgs: [],
+			}
+		},
+		onLoad(options) {
+      this.roomId = options.roomId;
+      this.liveId = options.liveId
+      this.userData = uni.getStorageSync("userData");
+      this.userId = this.userData.userId;
+			let info = uni.getSystemInfoSync();
+			this.windowWidth = info.windowWidth;
+      this.windowHeight = info.windowHeight;
+		},
+		onReady() {
+			this.isAuthor = false;
+      this.linkMic = true;
+      this.userId = "123";
+      this.name = 'test';
+      this.roomId = '1';
+      this.$nextTick(() => this.enterRoom());
+      return;
+
+      this.init();	
+    },
+    onUnload() {
+      this.exitRoom();
+    },
+		methods: {
+			init() {
+        this.avatar = uni.getStorageSync("liveImgUrl");
+        this.name = uni.getStorageSync("liveName");
+        this.$nextTick(() => this.enterRoom());
+      },
+			enterRoom() {
+        this.$refs.jhimlive&&this.$refs.jhimlive.enterRoom();
+				this.$refs.jhlive&&this.$refs.jhlive.enterRoom();
+			},
+			exitRoom() {
+        this.$refs.jhimlive&&this.$refs.jhimlive.exitRoom();
+        this.$refs.jhlive&&this.$refs.jhlive.exitRoom();
+			},
+			handleShop(msg) {			
+			}
+		},
+	}
+</script>
+
+<style lang="less" scoped>
+	
+  .container {
+  position: relative;
+  display: flex;
+  flex-direction: column;
+  align-items: stretch;
+  width: 750rpx;
+}
+
+.jhlive {
+  width: 750rpx;
+  flex: 1;
+}
+
+.jhimlive {
+  width: 400rpx;
+  position: absolute;
+  bottom: 10px;
+  left: 10px;
+}
+
+</style>

+ 0 - 0
pagesGood/liveDetail.vue → pagesGood/liveDetail1.vue


+ 102 - 0
pagesGood/pickVideo.nvue

@@ -0,0 +1,102 @@
+<template>
+	<view class="container" :style="'height: '+windowHeight+'px;'">
+    <jhlive 
+			ref="jhlive" 
+			class="jhlive"
+			:sdkAppID="sdkAppID" 
+			:secretKey="secretKey"
+			:userId="userId"
+			:roomId="roomId"
+			:isAuthor="isAuthor"
+			:linkMic="linkMic" 
+			:avatar="avatar"
+			:num="num?'已连接':'等待商家进入'"
+			:likes="likes"
+      :name="name"
+      @onRemoteUser="num=$event.length" />
+	</view>
+</template>
+
+<script>
+	import jhlive from "@/jhlive/jhlive";
+	const NET = require('@/utils/request')
+	const API = require('@/config/api')
+	
+	export default {
+		components: { jhlive },
+		data() {
+			return {
+        userData: {},
+        orderId: '',
+        tenantCode: '',
+        goodsList: [],
+        
+        isAuthor: false,
+        linkMic: true,
+        sdkAppID:API.sdkAppID,
+			  secretKey:API.secretKey,
+				windowWidth: 0,
+				windowHeight: 0,
+				userId: '',
+				roomId: '',
+				liveId: '',
+				num: 0,
+				likes: 0,
+				name: "",
+        avatar: "../static/images/loginLogo.png",
+			}
+		},
+		onLoad(options) {
+      this.tenantCode = options.tenantCode,
+			this.orderId = options.orderId
+      this.userData = uni.getStorageSync("userData");
+			let info = uni.getSystemInfoSync();
+			this.windowWidth = info.windowWidth;
+      this.windowHeight = info.windowHeight;
+    },
+    onReady() {
+      this.init();
+    },
+		methods: {
+      init() {
+        NET.request(API.linkPickVideo, {
+          tenantCode : this.tenantCode,
+          orderId: this.orderId
+        }, 'GET').then(res => {
+          this.name = res.data.tenantName;
+          this.avatar = res.data.headImg;
+          this.liveId = res.data.liveId;
+          this.roomId = res.data.roomId;
+          this.goodsList = res.data.liveProducResVO;
+          this.$nextTick(() => this.enterRoom());
+        }).catch(error => {
+          uni.showToast({
+              title: error.data.msg,
+              duration: 2000
+            });
+        });
+      },
+      enterRoom() {
+				this.$refs.jhlive&&this.$refs.jhlive.enterRoom();
+			},
+			exitRoom() {
+        this.$refs.jhlive&&this.$refs.jhlive.exitRoom();
+			},
+		}
+	}
+</script>
+
+<style lang="less" scoped>
+.container {
+  position: relative;
+  display: flex;
+  flex-direction: column;
+  align-items: stretch;
+  width: 750rpx;
+}
+
+.jhlive {
+  width: 750rpx;
+  flex: 1;
+}	
+</style>

+ 0 - 0
pagesGood/pickVideo.vue → pagesGood/pickVideo1.vue


部分文件因为文件数量过多而无法显示