Parcourir la source

发送语音功能初步实现

xie.bx il y a 3 ans
Parent
commit
2ad211cefe

+ 3 - 1
commom/src/main/java/com/bx/common/enums/FileTypeEnum.java

@@ -4,7 +4,9 @@ public enum FileTypeEnum {
 
     FILE(0,"文件"),
     IMAGE(1,"图片"),
-    VIDEO(2,"视频");
+    VIDEO(2,"视频"),
+    AUDIO(3,"声音");
+
 
 
     private Integer code;

+ 1 - 1
im-ui/package.json

@@ -11,7 +11,7 @@
     "axios": "^1.1.3",
     "core-js": "^3.6.5",
     "element-ui": "^2.15.10",
-    "recorderx": "^2.0.2",
+    "js-audio-recorder": "^1.0.7",
     "sass": "^1.47.0",
     "sass-loader": "^7.3.1",
     "vue": "^2.6.11",

+ 26 - 1
im-ui/src/components/chat/ChatBox.vue

@@ -48,7 +48,7 @@
 			</el-aside>
 		</el-container>
 		<emotion v-show="showEmotion" :pos="emoBoxPos" @emotion="handleEmotion"></Emotion>
-		<chat-voice :visible="showVoice" @close="closeVoiceBox()"></chat-voice>
+		<chat-voice :visible="showVoice" @close="closeVoiceBox" @send="handleSendVoice"></chat-voice>
 	</el-container>
 </template>
 
@@ -231,6 +231,31 @@
 			closeVoiceBox(){
 				this.showVoice = false;
 			},
+			handleSendVoice(data){
+				let msgInfo = {
+					content: JSON.stringify(data),
+					type: 3
+				}
+				// 填充对方id
+				this.setTargetId(msgInfo, this.chat.targetId);
+				this.$http({
+					url: this.messageAction,
+					method: 'post',
+					data: msgInfo
+				}).then(() => {
+					this.$message.success("发送成功");
+					msgInfo.sendTime = new Date().getTime();
+					msgInfo.sendId = this.$store.state.userStore.userInfo.id;
+					msgInfo.selfSend = true;
+					this.$store.commit("insertMessage", msgInfo);
+					// 保持输入框焦点
+					this.$refs.sendBox.focus();
+					// 滚动到底部
+					this.scrollToBottom();
+					// 关闭录音窗口
+					this.showVoice = false;
+				})
+			},
 			setTargetId(msgInfo, targetId) {
 				if (this.chat.type == "GROUP") {
 					msgInfo.groupId = targetId;

+ 74 - 35
im-ui/src/components/chat/ChatVoice.vue

@@ -1,15 +1,21 @@
 <template>
-	<el-dialog class="chat-voice" title="语言录制" :visible.sync="visible" width="35%" :before-close="handleClose">
-		<div>
-			录音时长:{{duration}}
+	<el-dialog class="chat-voice" title="语音录制" :visible.sync="visible" width="600px" :before-close="handleClose">
+		<div v-show="mode=='RECORD'">
+			<div class="chat-voice-tip">{{stateTip}}</div>
+			<div>时长: {{state=='STOP'?0:parseInt(rc.duration)}}s</div>
 		</div>
-
-		<el-row>
+		<audio v-show="mode=='PLAY'" :src="url" controls ref="audio" @ended="handleStopAudio()"></audio>
+		<el-divider content-position="center"></el-divider>
+		<el-row class="chat-voice-btn-group">
 			<el-button round type="primary" v-show="state=='STOP'" @click="handleStartRecord()">开始录音</el-button>
 			<el-button round type="warning" v-show="state=='RUNNING'" @click="handlePauseRecord()">暂停录音</el-button>
 			<el-button round type="primary" v-show="state=='PAUSE'" @click="handleResumeRecord()">继续录音</el-button>
-			<el-button round type="danger" v-show="state=='RUNNING'||state=='PAUSE'" @click="handleCompleteRecord()">结束录音</el-button>
-			<el-button round type="success" v-show="state=='COMPLETE'" @click="handlePlayRecord()">播放录音</el-button>
+			<el-button round type="danger" v-show="state=='RUNNING'||state=='PAUSE'" @click="handleCompleteRecord()">
+				结束录音</el-button>
+			<el-button round type="success" v-show="state=='COMPLETE' && mode!='PLAY'" @click="handlePlayAudio()">播放录音
+			</el-button>
+			<el-button round type="warning" v-show="state=='COMPLETE' && mode=='PLAY'" @click="handleStopAudio()">停止播放
+			</el-button>
 			<el-button round type="primary" v-show="state=='COMPLETE'" @click="handleRestartRecord()">重新录音</el-button>
 			<el-button round type="primary" v-show="state=='COMPLETE'" @click="handleSendRecord()">立即发送</el-button>
 		</el-row>
@@ -19,9 +25,7 @@
 </template>
 
 <script>
-	import Recorderx, {
-		ENCODE_TYPE
-	} from 'recorderx';
+	import Recorder from 'js-audio-recorder';
 
 	export default {
 		name: 'chatVoice',
@@ -32,51 +36,72 @@
 		},
 		data() {
 			return {
-				rc: new Recorderx(),
-				state: 'STOP', //STOP、RUNNING、PAUSE、COMPLETE
-				duration: 0
+				rc: new Recorder(),
+				audio: new Audio(),
+				state: 'STOP', // STOP、RUNNING、PAUSE、COMPLETE
+				stateTip: "未开始",
+				mode: 'RECORD', // RECORD 、PLAY
+				duration: 0,
+				url: ""
 			}
 		},
 		methods: {
 			handleClose() {
+				// 关闭前清除数据
+				this.rc.stop();
+				this.audio.pause();
+				this.mode = 'RECORD';
+				this.state = 'STOP';
+				this.stateTip = '未开始';
 				this.$emit("close");
 			},
 			handleStartRecord() {
-				this.rc.start().then(() => {
-					this.$message.success("开始录音");
+				this.rc.start().then((stream) => {
+					this.state = 'RUNNING';
+					this.stateTip = "正在录音...";
 				}).catch(error => {
-					this.$message.error("录音失败" + error.message);
+					this.$message.error("录音失败");
+					console.log(error);
 				});
-				console.log(this.rc)
-				this.state = 'RUNNING';
+
+
 			},
 			handlePauseRecord() {
+				this.rc.pause();
 				this.state = 'PAUSE';
+				this.stateTip = "已暂停录音";
 			},
 			handleResumeRecord() {
+				this.rc.resume();
 				this.state = 'RUNNING';
+				this.stateTip = "正在录音...";
 			},
 			handleCompleteRecord() {
-				this.rc.pause()
-				let wav = this.rc.getRecord({
-					encodeTo: ENCODE_TYPE.WAV,
-				});
-				console.log(wav);
+				this.rc.pause();
 				this.state = 'COMPLETE';
+				this.stateTip = "已结束录音";
 			},
-			handlePlayRecord() {
-
+			handlePlayAudio() {
+				let wav = this.rc.getWAVBlob();
+				let url = URL.createObjectURL(wav);
+				this.$refs.audio.src = url;
+				this.$refs.audio.play();
+				this.mode = 'PLAY';
+			},
+			handleStopAudio() {
+				console.log(this.$refs.audio);
+				this.$refs.audio.pause();
+				this.mode = 'RECORD';
 			},
 			handleRestartRecord() {
+				this.rc.destroy();
+				this.rc.start();
 				this.state = 'RUNNING';
+				this.mode = 'RECORD';
+				this.stateTip = "正在录音...";
 			},
 			handleSendRecord() {
-				this.upload();
-			},
-			upload() {
-				let wav = this.rc.getRecord({
-					encodeTo: ENCODE_TYPE.WAV,
-				});
+				let wav = this.rc.getWAVBlob();
 				let name = new Date().getDate() + '.wav';
 				var formData = new window.FormData()
 				formData.append('file', wav, name);
@@ -87,14 +112,28 @@
 					headers: {
 						'Content-Type': 'multipart/form-data'
 					}
-				}).then((url)=>{
-					this.$message.success("上传成功");
-					console.log(url);
+				}).then((url) => {
+					let data = {
+						duration: parseInt(this.rc.duration),
+						url: url
+					}
+					this.$emit("send", data);
 				})
 			}
 		}
+
 	}
 </script>
 
-<style>
+<style lang="scss">
+	.chat-voice {
+
+		.chat-voice-tip {
+			font-size: 18px;
+		}
+
+		.chat-voice-btn-group {
+			margin-bottom: 20px;
+		}
+	}
 </style>

+ 23 - 1
im-ui/src/components/chat/MessageItem.vue

@@ -32,6 +32,9 @@
 					</div>
 					<span title="发送失败" v-show="loadFail" @click="handleSendFail" class="send-fail el-icon-warning"></span>
 				</div>
+				<div class="im-msg-voice" v-if="msgInfo.type==3" @click="handlePlayVoice()">
+					<audio controls :src="JSON.parse(msgInfo.content).url"></audio>
+				</div>
 			</div>
 		</div>
 	</div>
@@ -65,6 +68,12 @@
 				required: true
 			}
 		},
+		data(){
+			return {
+				audioPlayState: 'STOP',
+			}
+			
+		},
 		methods:{
 			handleSendFail(){
 				this.$message.error("该文件已发送失败,目前不支持自动重新发送,建议手动重新发送")
@@ -74,7 +83,15 @@
 				if(imageUrl){
 					this.$store.commit('showFullImageBox',imageUrl);
 				}
-			}	
+			},
+			handlePlayVoice(){
+				if(!this.audio){
+					this.audio = new Audio();
+				}
+				this.audio.src = JSON.parse(this.msgInfo.content).url;
+				this.audio.play();
+				this.handlePlayVoice = 'RUNNING';
+			}
 		},
 		computed:{
 			loading(){
@@ -229,6 +246,11 @@
 					}
 					
 				}
+				
+				.im-msg-voice {
+					font-size: 14px;
+					cursor: pointer;
+				}
 			}
 		}