<template>
	<view>
			<view  class="cbb-record">
				<view class="conbox record">
					<!-- 此处可放置倒计时，可根据需要自行添加 -->
					<view class="time"> 
						{{showRecordTime}}
					</view>
					
					<view class="c999">
						最短{{minTime}}秒，最长{{maxTime}}秒
					</view>
					  
					<view class="record-box">
						<view class="stop" @tap.stop="stopVoice" v-if="_voicePath && playing==1 && recordTime1 > minTime-1">
							<u-icon color="#3cc9a4" name="pause-circle" size="80"></u-icon>
						</view>
						<view class="paly" @tap.stop="playVoice" v-if="_voicePath && playing==0 && recordTime1 > minTime-1">
							<u-icon color="#3cc9a4" name="play-circle" size="80"></u-icon>
						</view>
						<!-- #ifdef APP-PLUS ||MP-WEIXIN -->
						<view class="circle-box"
						@longpress="startRecord"
						@touchend="endRecord">
							<view class="voice-btn">
								<view class="progress-icon">
									<u-icon name="mic" color="#fff" size="70"></u-icon>
								</view>
							</view>
							
							<!-- <u-circle-progress width="170" active-color="#2979ff" :percent="percent" :duration="duration">
								<view class="u-progress-content">
									<view class="u-progress-dot">
										<u-icon name="mic" size="60"></u-icon>
									</view>
								</view>
							</u-circle-progress> -->
						</view>
						<!-- #endif -->
						
						<!-- #ifdef H5 -->
						<view class="circle-box" @click="startRecord">
							<view class="voice-btn">
								<view class="progress-icon">
									<u-icon name="mic" color="#fff" size="70"></u-icon>
								</view>
							</view>
							
							<!-- <u-circle-progress width="170" active-color="#2979ff" :percent="percent" :duration="duration">
								<view class="u-progress-content">
									<view class="u-progress-dot">
										<u-icon name="mic" size="60"></u-icon>
									</view>
								</view>
							</u-circle-progress> -->
						</view>
						<!-- #endif -->
						
						<view class="confirm" @tap.stop="okClick" v-if="_voicePath && recordTime1 > minTime-1">
							<u-icon color="#3cc9a4" name="checkmark-circle" size="80"></u-icon>
						</view>
					</view>
					
					<view class="c666 fz32 domess">{{ btnTextContent }}</view>
				</view>
			</view>
	</view>
</template>
<script>
var that;
var innerAudioContext;//播放
// #ifdef APP-PLUS || MP-WEIXIN
const recorderManager = uni.getRecorderManager();
// #endif

// #ifdef H5
import speech from '../../js_sdk/h5-speech/speech.js';

const recorderManager = new speech(8000);
// #endif

// #ifdef APP-PLUS
// 引入权限判断
import permision from '../../js_sdk/wa-permission/permission.js';
// #endif

import tuiCircularProgress from "@/components/thorui/tui-circular-progress/tui-circular-progress.vue"
 
export default {
	name: 'nbVoiceRecord',
	components:{
		tuiCircularProgress,
	},  
	/**
	 * 录音交互动效组件
	 * @property {Object} recordOptions 录音配置
	 * @property {Object} btnStyle 按钮样式
	 * @property {Object} btnHoverFontcolor 按钮长按时字体颜色
	 * @property {String} btnHoverBgcolor 按钮长按时背景颜色
	 * @property {String} btnDefaultText 按钮初始文字
	 * @property {String} btnRecordingText 录制时按钮文字
	 * @property {Boolean} vibrate 弹窗时是否震动
	 * @property {String} popupTitle 弹窗顶部文字
	 * @property {String} popupDefaultTips 录制时弹窗底部提示
	 * @property {String} popupCancelTips 滑动取消时弹窗底部提示
	 * @property {String} popupMaxWidth 弹窗展开后宽度
	 * @property {String} popupMaxHeight 弹窗展开后高度
	 * @property {String} popupFixBottom 弹窗展开后距底部高度
	 * @property {String} popupBgColor 弹窗背景颜色
	 * @property {String} lineHeight 声波高度
	 * @property {String} lineStartColor 声波波谷时颜色色值
	 * @property {String} lineEndColor 声波波峰时颜色色值
	 * @event {Function} startRecord 开始录音回调
	 * @event {Function} endRecord 结束录音回调
	 * @event {Function} cancelRecord 滑动取消录音回调
	 * @event {Function} stopRecord 主动停止录音
	 */
	props: {
		recordOptions: {
			type: Object,
			default() {
				return {
					duration: 600000
				}; // 请自行查看各端的的支持情况，这里全部使用默认配置
			}
		},
		btnStyle: {
			type: Object,
			default() {
				return {
					width: '300rpx',
					height: '80rpx',
					borderRadius: '20rpx',
					backgroundColor: '#fff',
					border: '1rpx solid whitesmoke',
					permisionState: false
				};
			}
		},
		btnHoverFontcolor: {
			type: String,
			default: '#000' // 颜色名称或16进制色值
		},
		btnHoverBgcolor: {
			type: String,
			default: 'whitesmoke' // 颜色名称或16进制色值
		},
		btnDefaultText: {
			type: String,
			default: '长按开始录音'
		},
		btnRecordingText: {
			type: String,
			default: '录音中'
		},
		vibrate: {
			type: Boolean,
			default: true
		},
		// #ifdef APP-PLUS || MP-WEIXIN
		popupTitle: {
			type: String,
			default: '正在录制音频'
		},
		popupDefaultTips: {
			type: String,
			default: '左右滑动后松手完成录音'
		},
		// #endif
		// #ifdef H5
		popupTitle: {
			type: String,
			default: '点击录制音频'
		},
		popupDefaultTips: {
			type: String,
			default: '点击完成录音'
		},
		// #endif
		popupCancelTips: {
			type: String,
			default: '松手取消录音'
		},
		popupMaxWidth: {
			type: Number,
			default: 600 // 单位为rpx
		},
		popupMaxHeight: {
			type: Number,
			default: 300 // 单位为rpx
		},
		popupFixBottom: {
			type: Number,
			default: 200 // 单位为rpx
		},
		popupBgColor: { 
			type: String,
			default: 'whitesmoke'
		},
		lineHeight: {
			type: Number,
			default: 50 // 单位为rpx
		},
		lineStartColor: {
			type: String,
			default: 'royalblue' // 颜色名称或16进制色值
		},
		lineEndColor: {
			type: String,
			default: 'indianred' // 颜色名称或16进制色值
		},
		voicePath: { //默认地址
			type: String,
			default: '' 
		},
		maxTime: { // 录音最大时长，单位秒
			type: Number,
			default: 15
		},
		minTime: { // 录音最小时长，单位毫秒
			type:Number ,
			default: 5
		},
	},
	data() {
		return {
			stopStatus: true, // 是否已被父页面通知主动结束录音
			btnTextContent: this.btnDefaultText,
			startTouchData: {},
			popupHeight: '0px', // 这是初始的高度
			recording: true, // 录音中
			recordPopupShow: false,
			recordTimeout: null, // 录音定时器
			h5start: false,
			isShow:false,	
			playing:0,//是否播放中
			timeObj: null, //计时id
			countdownObj: null,		//倒计时id
			recordTime: 0,//录音时长
			recordTime1:0,//播放录音倒计时
			percent: 0,
			duration1: true,
			newViocePath: '',
		};
	},
	created() {
		that = this;
		innerAudioContext = uni.createInnerAudioContext();//播放

		// 请求权限
		this.checkPermission();
		// #ifdef APP-PLUS || MP-WEIXIN
		recorderManager.onStop((res) => {
			that.newViocePath = res.tempFilePath;
			that.endRecord();
			that.$emit('endRecord', res);
		});
		recorderManager.onStart((err) => {
			console.log('开始:', err);
		});
		recorderManager.onError((err) => {
			console.log('err:', err);
		});
		// #endif
	},
	computed: {
		showRecordTime() {
			var strs = "";
			var m = Math.floor(this.recordTime/60);
			if(m<10) strs = "0"+m;
			
			var s = this.recordTime%60;
			strs += (s<10) ? ":0"+s : ":"+s;
							
			return strs
		},
		duration() {
			return this.duration1 ? this.maxTime*1000 : 0;
		},
		_voicePath(){
			return this.newViocePath || this.voicePath;
		}
	},
	methods: {
		upx2px(upx) {
			return uni.upx2px(upx) + 'px';
		},
		async checkPermission() {
			var that = this;
			// #ifdef APP-PLUS
			// 先判断os
			let os = uni.getSystemInfoSync().osName;
			if (os == 'ios') {
				this.permisionState = await permision.judgeIosPermission('record');
			} else {
				this.permisionState = await permision.requestAndroidPermission('android.permission.RECORD_AUDIO');
			}
			if (this.permisionState !== true && this.permisionState !== 1) {
				uni.showToast({
					title: '请先授权使用录音',
					icon: 'none'
				});
				return;
			}
			// #endif
			// #ifdef H5
			if (!window.navigator?.mediaDevices?.getUserMedia) {
				this.permisionState = false;
				uni.showToast({
					title: '请先授权使用录音',
					icon: 'none'
				});
				return;
			} else {
				this.permisionState = true;
			}
			// #endif

			// #ifdef MP-WEIXIN
			uni.authorize({
				scope: 'scope.record',
				success(e) {
					that.permisionState = true;
					// that.startRecord();
				},
				fail() {
					uni.showToast({
						title: '请授权使用录音',
						icon: 'none'
					});
				}
			});
			// #endif
		},

		startRecord() {
			this.percent = 0;
			this.duration1 = true;
			
			if (!this.permisionState) {
				this.checkPermission();
				return;
			}
			if (this.h5start) {
				this.duration1 = false;
				this.h5start = false;
				this.endRecord();
				return;
			}
			this.h5start = true;
			this.stopStatus = false;
			
			this.stopVoice();
			this.percent = 100;
			this.recordTime = 0;
			this.newViocePath = "";//音频地址	
			this.btnTextContent = this.btnRecordingText;
			this.timeObj = setInterval(() => {
				this.recordTime ++;		
				if(this.recordTime  == this.maxTime) {
					this.endRecord();
				}
			},1000);
			
			setTimeout(() => {
				setTimeout(() => {
					if (this.vibrate) {
						// #ifdef APP-PLUS
						// 震动
						plus.device.vibrate(35);
						// #endif
						// #ifdef MP-WEIXIN
						uni.vibrateShort();
						// #endif
					}
					// 开始录音
					recorderManager.start(this.recordOptions);

					this.$emit('startRecord');
				}, 100);
			}, 200);
		},
		endRecord() {
			this.percent = 0;
			this.h5start = false;
			
			let recordTime = this.recordTime;
			this.recordTime1 = this.recordTime;
			clearInterval(this.timeObj); //清除计时器
			
			var that = this;
			if (this.stopStatus) {
				return;
			}
			//this.popupHeight = '0px';
			//this.recordPopupShow = false;
			this.btnTextContent = this.btnDefaultText;
			// #ifdef APP-PLUS || MP-WEIXIN
			recorderManager.stop();
			// #endif
			// #ifdef H5
			const res = recorderManager.stop();
			that.newViocePath = res;
			that.$emit('endRecord', res);
			// #endif
		},
		stopRecord() {
			// 用法如你录音限制了时间，那么将在结束时强制停止组件的显示
			this.endRecord();
			this.stopStatus = true;
		},
		touchStart(e) {
			this.startTouchData.clientX = e.changedTouches[0].clientX; //手指按下时的X坐标
			this.startTouchData.clientY = e.changedTouches[0].clientY; //手指按下时的Y坐标
		},
		touchMove(e) {
			let touchData = e.touches[0]; //滑动过程中，手指滑动的坐标信息 返回的是Objcet对象
			let moveX = touchData.clientX - this.startTouchData.clientX;
			let moveY = touchData.clientY - this.startTouchData.clientY;
			if (moveY < -50) {
				if (this.vibrate && this.recording) {
					// #ifdef APP-PLUS
					plus.device.vibrate(35);
					// #endif
					// #ifdef MP-WEIXIN
					uni.vibrateShort();
					// #endif
				}
				this.recording = false;
			} else {
				this.recording = true;
			}
		},
		playVoice() {
			if (this._voicePath && this.playing === 0) {
				console.log('playVoice', this._voicePath)
				innerAudioContext.src = this._voicePath;
				
				innerAudioContext.stop();		//todo 第一次play时若不先stop则播放不出来,未知原因
				innerAudioContext.play();
				
				this.playing = 1;
				
				this.recordTime = this.recordTime1;
				
				this.countdownObj = setInterval(() => {
					this.recordTime--;
					if(this.recordTime === 0){
						this.recordTime = this.recordTime1;
						this.stopVoice()
						return;
					}
				}, 1000)
			}
		},
		startVoice() {
			this.isShow = true;
			this.percent = 0;
			this.recordTime = 0;
			this.newViocePath = "";//音频地址
		},
		//关闭组件
		closePicker(){				
			this.isShow = false;
			this.endRecord();
			this.stopVoice();
		},	
		stopVoice() {
			innerAudioContext.stop();
			this.playing = 0;			
			//this.recordTime = 0;
			clearInterval(this.countdownObj);
		},
		//点击确定
		okClick(){
			var data = {
				path: this._voicePath,
				sec: this.recordTime1,
			}
			this.stopVoice();
			this.$emit('okClick', data);
		},
	}
};
</script>
<style lang="scss">
	
.cbb-record {
	.conbox{
		background: #fff;
	}	
	.record{	
		text-align: center;
		
		.time {
			text-align: center;
			font-size: 60upx;
			color: #000;
			line-height: 100upx;
			//margin-top:50upx;
		}
		.domess{margin-bottom:50upx;}
		
		.c666{color:#aaa;}
		.c999{color:#999;}
		.fz28{font-size: 28upx;}
		.fz32{font-size: 32upx;}
		.record-box {
			display: flex;
			flex-direction: row;
			justify-content: center;
			align-items: center;
			padding: 10px 0;
		}
		.btncom{
			width: 80upx;
			height: 80upx;	
			border-radius: 80upx;
		}
		.stop{
			 @extend .btncom;
		}
		.paly{
			 @extend .btncom;
		}	
		.confirm{
			 @extend .btncom;
		}
	}
	
	.circle-box {
		margin: 0 80rpx;
	}
}	

.record-popup {
	position: absolute;
	bottom: var(--popup-bottom);
	left: calc(50vw - calc(var(--popup-width) / 2));
	z-index: 1;
	width: var(--popup-width);
	height: var(--popup-height);
	display: flex;
	align-items: center;
	justify-content: center;
	border-radius: 10rpx;
	box-shadow: 0 2rpx 4rpx rgba(0, 0, 0, 0.1);
	background: var(--popup-bg-color);
	color: #000;
	transition: 0.2s height;

	.inner-content {
		height: var(--popup-height);
		font-size: 24rpx;
		display: flex;
		flex-direction: column;
		align-items: center;
		justify-content: space-between;

		.title {
			font-weight: bold;
			padding: 20rpx 0;
		}

		.tips {
			color: #999;
			padding: 20rpx 0;
		}
	}
}

.voice-btn {
	width: 170rpx;
	height: 170rpx;
}

.progress-icon {
	display: flex;
	justify-content: center;
	align-items: center;
	background-color: #3cc9a4;
	border-radius: 100%;
	width: 100%;
	height: 100%;
}

.cancel-icon {
	width: 100rpx;
	height: 100rpx;
	display: flex;
	align-items: center;
	justify-content: center;
	color: #fff;
	font-size: 44rpx;
	line-height: 44rpx;
	background-color: pink;
	border-radius: 50%;
	transform: rotate(45deg);
}

.voice-line-wrap {
	display: flex;
	align-items: center;

	.voice-line {
		width: 5rpx;
		height: var(--line-height);
		border-radius: 3rpx;
		margin: 0 5rpx;
	}

	.one {
		animation: wave 0.4s 1s linear infinite alternate;
	}

	.two {
		animation: wave 0.4s 0.9s linear infinite alternate;
	}

	.three {
		animation: wave 0.4s 0.8s linear infinite alternate;
	}

	.four {
		animation: wave 0.4s 0.7s linear infinite alternate;
	}

	.five {
		animation: wave 0.4s 0.6s linear infinite alternate;
	}

	.six {
		animation: wave 0.4s 0.5s linear infinite alternate;
	}

	.seven {
		animation: wave 0.4s linear infinite alternate;
	}
}

@keyframes wave {
	0% {
		transform: scale(1, 1);
		background-color: var(--line-start-color);
	}

	100% {
		transform: scale(1, 0.2);
		background-color: var(--line-end-color);
	}
}
</style>
