|
@@ -1,14 +1,11 @@
|
|
|
<template>
|
|
|
<div>
|
|
|
- <el-dialog
|
|
|
- :center="true"
|
|
|
- :visible.sync="dialogVisible"
|
|
|
- width="600px"
|
|
|
- class="addTemplateDialog"
|
|
|
- >
|
|
|
+ <el-dialog :center="true" :visible.sync="dialogVisible" width="600px" class="addTemplateDialog" :before-close="close">
|
|
|
<!-- <div v-if="showDialog == true" class="a-dialog" v-el-drag-dialog> -->
|
|
|
<div class="a-d-top">
|
|
|
- <div class="a-d-topTit"><div>新增声纹</div></div>
|
|
|
+ <div class="a-d-topTit">
|
|
|
+ <div>新增声纹</div>
|
|
|
+ </div>
|
|
|
|
|
|
<div class="a-d-t-right">
|
|
|
<span @click.stop="close()">×</span>
|
|
@@ -16,9 +13,9 @@
|
|
|
</div>
|
|
|
<div class="a_box">
|
|
|
<div class="a_b_form">
|
|
|
- <el-form label-position="top" :model="form" :rules="rules">
|
|
|
+ <el-form ref="form$" label-position="top" :model="form" :rules="rules" :disabled="status === 1">
|
|
|
<el-form-item class="a_b_f_item" label="教师名称" prop="name">
|
|
|
- <el-input v-model="form.name" :disabled="![0].includes(status)"></el-input>
|
|
|
+ <el-input v-model="form.name"></el-input>
|
|
|
</el-form-item>
|
|
|
|
|
|
<el-form-item class="a_b_f_item" label="声纹录制">
|
|
@@ -33,45 +30,39 @@
|
|
|
<span>请使用正常语速朗读以上内容</span>
|
|
|
</div>
|
|
|
<div class="a_b_b_bottom">
|
|
|
- <div class="a_b_b_b_btn" @click.stop="start()" v-if="status===0">
|
|
|
- <svg
|
|
|
- width="16"
|
|
|
- height="22"
|
|
|
- viewBox="0 0 16 22"
|
|
|
- fill="none"
|
|
|
- xmlns="http://www.w3.org/2000/svg"
|
|
|
- >
|
|
|
- <path
|
|
|
- fill-rule="evenodd"
|
|
|
- clip-rule="evenodd"
|
|
|
+ <div class="a_b_b_b_btn" @click.stop="start()" v-if="status === 0">
|
|
|
+ <svg width="16" height="22" viewBox="0 0 16 22" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
|
+ <path fill-rule="evenodd" clip-rule="evenodd"
|
|
|
d="M8.00009 13.8098C10.5962 13.8098 12.6876 11.6655 12.6876 9.00351V5.30633C12.6876 2.64436 10.5962 0.5 8.00009 0.5C5.40393 0.5 3.31259 2.64436 3.31259 5.30633V9.00351C3.31259 11.6655 5.40393 13.8098 8.00009 13.8098ZM4.75489 5.30633C4.75489 3.45774 6.1972 1.97887 8.00009 1.97887C9.80297 1.97887 11.2453 3.45774 11.2453 5.30633V9.00351C11.2453 10.8521 9.80297 12.331 8.00009 12.331C6.1972 12.331 4.75489 10.8521 4.75489 9.00351V5.30633ZM15.5 10.1132C15.5 9.70651 15.1755 9.37377 14.7788 9.37377C14.4183 9.37377 14.0938 9.66954 14.0577 10.0393C13.5529 13.034 11.0288 15.2892 8 15.2892C4.97115 15.2892 2.44712 13.034 1.94231 10.0393C1.90625 9.66954 1.58173 9.37377 1.22115 9.37377C0.824519 9.37377 0.5 9.70651 0.5 10.1132V10.2241C1.07692 13.6995 3.85337 16.3984 7.27885 16.7311V19.9223H4.15379C3.72896 19.9223 3.38456 20.2755 3.38456 20.7111C3.38456 21.1467 3.72896 21.4998 4.15379 21.4998H11.8461C12.2709 21.4998 12.6153 21.1467 12.6153 20.7111C12.6153 20.2755 12.2709 19.9223 11.8461 19.9223H8.72115V16.7311C12.1466 16.3984 14.9231 13.6995 15.4639 10.2611C15.4639 10.2426 15.473 10.2149 15.482 10.1872L15.482 10.1871C15.491 10.1594 15.5 10.1317 15.5 10.1132Z"
|
|
|
- fill="white"
|
|
|
- />
|
|
|
+ fill="white" />
|
|
|
</svg>
|
|
|
点击录制
|
|
|
</div>
|
|
|
+ <div class="a_b_b_b_btn" style="background: red;cursor: default" v-else>
|
|
|
+ <svg width="16" height="22" viewBox="0 0 16 22" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
|
+ <path fill-rule="evenodd" clip-rule="evenodd"
|
|
|
+ d="M8.00009 13.8098C10.5962 13.8098 12.6876 11.6655 12.6876 9.00351V5.30633C12.6876 2.64436 10.5962 0.5 8.00009 0.5C5.40393 0.5 3.31259 2.64436 3.31259 5.30633V9.00351C3.31259 11.6655 5.40393 13.8098 8.00009 13.8098ZM4.75489 5.30633C4.75489 3.45774 6.1972 1.97887 8.00009 1.97887C9.80297 1.97887 11.2453 3.45774 11.2453 5.30633V9.00351C11.2453 10.8521 9.80297 12.331 8.00009 12.331C6.1972 12.331 4.75489 10.8521 4.75489 9.00351V5.30633ZM15.5 10.1132C15.5 9.70651 15.1755 9.37377 14.7788 9.37377C14.4183 9.37377 14.0938 9.66954 14.0577 10.0393C13.5529 13.034 11.0288 15.2892 8 15.2892C4.97115 15.2892 2.44712 13.034 1.94231 10.0393C1.90625 9.66954 1.58173 9.37377 1.22115 9.37377C0.824519 9.37377 0.5 9.70651 0.5 10.1132V10.2241C1.07692 13.6995 3.85337 16.3984 7.27885 16.7311V19.9223H4.15379C3.72896 19.9223 3.38456 20.2755 3.38456 20.7111C3.38456 21.1467 3.72896 21.4998 4.15379 21.4998H11.8461C12.2709 21.4998 12.6153 21.1467 12.6153 20.7111C12.6153 20.2755 12.2709 19.9223 11.8461 19.9223H8.72115V16.7311C12.1466 16.3984 14.9231 13.6995 15.4639 10.2611C15.4639 10.2426 15.473 10.2149 15.482 10.1872L15.482 10.1871C15.491 10.1594 15.5 10.1317 15.5 10.1132Z"
|
|
|
+ fill="white" />
|
|
|
+ </svg>
|
|
|
+ 录制中
|
|
|
+ <span>{{ recorderCountdown }}</span>
|
|
|
+ </div>
|
|
|
|
|
|
- <!-- <div class="a_b_b_b_record">
|
|
|
- <div class="a_b_b_b_r_left">
|
|
|
- <img src="../../../../assets/icon/classroomObservation/recordLeft.png" alt="">
|
|
|
- <div>
|
|
|
- <div>{{recordData.status==0?"录制中":recordData.status==1?"暂停":"结束"}}</div>
|
|
|
- <span>{{ recordData.time }}</span>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- <div class="a_b_b_b_r_right">
|
|
|
- <div class="a_b_b_b_r_r_start">
|
|
|
- <span></span>
|
|
|
- </div>
|
|
|
- <div class="a_b_b_b_r_r_stop">
|
|
|
- <span></span>
|
|
|
- <span></span>
|
|
|
- </div>
|
|
|
- <div class="a_b_b_b_r_r_end">
|
|
|
- <span></span>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- </div> -->
|
|
|
+ <div class="a_b_b_b_record">
|
|
|
+ <div class="a_b_b_b_r_left">
|
|
|
+ <!-- <img src="../../../../assets/icon/classroomObservation/recordLeft.png" alt=""> -->
|
|
|
+ <div>
|
|
|
+ <div v-if="status === 1">
|
|
|
+ <el-button @click="stop({ drop: true })">取消录制</el-button>
|
|
|
+ <el-button :disabled="isRecorderStopDisabled" @click="stop({ drop: false })">停止录制</el-button>
|
|
|
+ </div>
|
|
|
+ <div v-else-if="recorderContext.file">
|
|
|
+ <el-tag style="cursor: pointer" @click="download">{{ recorderContext.file.name }}</el-tag>
|
|
|
+ <el-button :loading="registerLoading" @click="register()">注册该声纹</el-button>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
@@ -81,17 +72,27 @@
|
|
|
</template>
|
|
|
|
|
|
<script>
|
|
|
+// import Recorder from 'recorder-core'
|
|
|
+// import Recorder from 'recorder-core/recorder.mp3.min'
|
|
|
+import Recorder from 'recorder-core/recorder.wav.min'
|
|
|
+import * as Sy from '@/lib/shengyang'
|
|
|
+import { saveAs } from 'file-saver';
|
|
|
+
|
|
|
export default {
|
|
|
+ emits: ['complete'],
|
|
|
data() {
|
|
|
return {
|
|
|
dialogVisible: false,
|
|
|
- userId: this.$route.query["userid"],
|
|
|
+ userId: this.$route.query["userid"] || '',
|
|
|
+ organizeId: this.$route.query["org"] || '',
|
|
|
status: 0, //0:初始状态 1:录制
|
|
|
- recordData:{
|
|
|
- time:0,
|
|
|
- status:0,//0 录制中 1暂停 2结束
|
|
|
- },
|
|
|
- form: {
|
|
|
+ recorderContext: {
|
|
|
+ startTime: null,
|
|
|
+ endTime: null,
|
|
|
+ timer: null,
|
|
|
+ file: null,
|
|
|
+ },
|
|
|
+ form: {
|
|
|
name: ""
|
|
|
},
|
|
|
textAreaVale:
|
|
@@ -106,21 +107,121 @@ export default {
|
|
|
message: "长度需在1-20个字符之间"
|
|
|
}
|
|
|
]
|
|
|
- }
|
|
|
+ },
|
|
|
+ recorder: null,
|
|
|
+ registerLoading: false,
|
|
|
};
|
|
|
},
|
|
|
-
|
|
|
+ computed: {
|
|
|
+ recorderCountdown() {
|
|
|
+ const elapsed = this.recorderContext.endTime - this.recorderContext.startTime
|
|
|
+ if (elapsed < 0) {
|
|
|
+ return '00:00'
|
|
|
+ }
|
|
|
+ const minutes = Math.floor(elapsed / 60000)
|
|
|
+ const seconds = Math.floor((elapsed % 60000) / 1000)
|
|
|
+ return `${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}`
|
|
|
+ },
|
|
|
+ isRecorderStopDisabled() {
|
|
|
+ return (this.recorderContext.endTime - this.recorderContext.startTime) <= 60 * 1000
|
|
|
+ }
|
|
|
+ },
|
|
|
methods: {
|
|
|
open() {
|
|
|
this.dialogVisible = true;
|
|
|
},
|
|
|
+ beforeClose(done) {
|
|
|
+ if (this.status === 1) {
|
|
|
+ this.$message.info('请先停止录制')
|
|
|
+ return false
|
|
|
+ }
|
|
|
+ done && done()
|
|
|
+ this.$emit('complete')
|
|
|
+ return true
|
|
|
+ },
|
|
|
close() {
|
|
|
- this.dialogVisible = false;
|
|
|
+ if (this.beforeClose()) {
|
|
|
+ this.dialogVisible = false;
|
|
|
+ }
|
|
|
+ },
|
|
|
+ start() {
|
|
|
+ if (!this.form.name) {
|
|
|
+ this.$message.info('请先填写教师名字')
|
|
|
+ return
|
|
|
+ }
|
|
|
+ this.status = 1;
|
|
|
+ this.recorder = Recorder({
|
|
|
+ type: 'wav',
|
|
|
+ sampleRate: 16000,
|
|
|
+ bitRate: 16,
|
|
|
+ disableEnvInFix: false,
|
|
|
+ })
|
|
|
+ this.recorder.open(
|
|
|
+ () => {
|
|
|
+ this.recorder.start()
|
|
|
+ this.recorderContext.startTime = Date.now()
|
|
|
+ this.startTimer()
|
|
|
+ },
|
|
|
+ (msg, isUserNotAllow) => {
|
|
|
+ console.log('Recorder Info: isUserNotAllow', isUserNotAllow, msg)
|
|
|
+ }
|
|
|
+ )
|
|
|
+ },
|
|
|
+ async stop({ drop }) {
|
|
|
+ this.stopTimer()
|
|
|
+ this.recorder.stop(async (blob, duration, mime) => {
|
|
|
+ try {
|
|
|
+ if (drop) {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ if (duration < 60 * 1000) {
|
|
|
+ this.$message.error('录制时间不足一分钟,请重试')
|
|
|
+ return
|
|
|
+ }
|
|
|
+ this.recorderContext.file = new File([blob], `voiceprint_${Date.now()}.wav`, { type: mime });
|
|
|
+
|
|
|
+ } finally {
|
|
|
+ this.status = 0
|
|
|
+ this.recorder = null
|
|
|
+ }
|
|
|
+ })
|
|
|
+ },
|
|
|
+ async register() {
|
|
|
+ this.registerLoading = true
|
|
|
+ try {
|
|
|
+ await Sy.registerVoiceprint({
|
|
|
+ file: this.recorderContext.file, name: this.form.name, userId: this.userId, organizeId: this.organizeId
|
|
|
+ })
|
|
|
+ this.$message.success('注册完成')
|
|
|
+ this.$refs.form$.resetFields()
|
|
|
+ this.recorderContext = {
|
|
|
+ startTime: null,
|
|
|
+ endTime: null,
|
|
|
+ timer: null,
|
|
|
+ file: null,
|
|
|
+ }
|
|
|
+ } finally {
|
|
|
+ this.registerLoading = false
|
|
|
+ }
|
|
|
},
|
|
|
- start(){
|
|
|
- this.status = 1;
|
|
|
- }
|
|
|
- }
|
|
|
+ startTimer() {
|
|
|
+ this.recorderContext.timer = setInterval(() => {
|
|
|
+ this.recorderContext.endTime = Date.now()
|
|
|
+ }, 1000)
|
|
|
+ },
|
|
|
+ stopTimer() {
|
|
|
+ if (this.recorderContext.timer) {
|
|
|
+ clearInterval(this.recorderContext.timer)
|
|
|
+ this.recorderContext.timer = null
|
|
|
+ }
|
|
|
+ },
|
|
|
+ download() {
|
|
|
+ if (this.recorderContext.file) {
|
|
|
+ saveAs(this.recorderContext.file, `voiceprint_${Date.now()}.wav`);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
};
|
|
|
</script>
|
|
|
|
|
@@ -151,6 +252,7 @@ export default {
|
|
|
justify-content: center;
|
|
|
/* text-align: left; */
|
|
|
}
|
|
|
+
|
|
|
.a-d-t-right {
|
|
|
width: 40px;
|
|
|
height: 40px;
|
|
@@ -161,7 +263,7 @@ export default {
|
|
|
color: black !important;
|
|
|
}
|
|
|
|
|
|
-.a-d-t-right > span {
|
|
|
+.a-d-t-right>span {
|
|
|
width: 25px;
|
|
|
height: 25px;
|
|
|
border-radius: 25px;
|
|
@@ -177,7 +279,7 @@ export default {
|
|
|
color: #adadad;
|
|
|
}
|
|
|
|
|
|
-.addTemplateDialog >>> .el-dialog {
|
|
|
+.addTemplateDialog>>>.el-dialog {
|
|
|
min-width: 600px;
|
|
|
|
|
|
height: 700px;
|
|
@@ -188,7 +290,8 @@ export default {
|
|
|
/* margin: 0 auto; */
|
|
|
overflow: hidden;
|
|
|
}
|
|
|
-.addTemplateDialog >>> .el-dialog__body {
|
|
|
+
|
|
|
+.addTemplateDialog>>>.el-dialog__body {
|
|
|
height: 100%;
|
|
|
min-width: 600px;
|
|
|
flex-shrink: 0;
|
|
@@ -196,7 +299,8 @@ export default {
|
|
|
padding-bottom: 50px;
|
|
|
padding-top: 10px;
|
|
|
}
|
|
|
-.addTemplateDialog >>> .el-dialog__header {
|
|
|
+
|
|
|
+.addTemplateDialog>>>.el-dialog__header {
|
|
|
display: none;
|
|
|
}
|
|
|
|
|
@@ -235,7 +339,6 @@ export default {
|
|
|
width: 100%;
|
|
|
height: 100%;
|
|
|
display: flex;
|
|
|
- justify-content: center;
|
|
|
align-items: center;
|
|
|
}
|
|
|
|
|
@@ -251,7 +354,7 @@ export default {
|
|
|
cursor: pointer;
|
|
|
}
|
|
|
|
|
|
-.a_b_b_b_btn > svg {
|
|
|
+.a_b_b_b_btn>svg {
|
|
|
width: 20px;
|
|
|
height: 20px;
|
|
|
margin-right: 5px;
|
|
@@ -261,7 +364,7 @@ export default {
|
|
|
margin-bottom: 10px;
|
|
|
}
|
|
|
|
|
|
-.a_b_f_item >>> .el-form-item__label {
|
|
|
+.a_b_f_item>>>.el-form-item__label {
|
|
|
padding: 0;
|
|
|
font-size: 20px;
|
|
|
font-weight: bold;
|
|
@@ -276,7 +379,8 @@ export default {
|
|
|
padding: 10px;
|
|
|
overflow: auto;
|
|
|
}
|
|
|
-.a_b_f_itemTextArea > div {
|
|
|
+
|
|
|
+.a_b_f_itemTextArea>div {
|
|
|
background-color: #f0f2f566;
|
|
|
border: 1px dashed #f0f2f5;
|
|
|
border-radius: 4px;
|
|
@@ -284,45 +388,44 @@ export default {
|
|
|
box-sizing: border-box;
|
|
|
padding: 5px;
|
|
|
font-size: 16px;
|
|
|
- line-height: 30px;
|
|
|
+ line-height: 30px;
|
|
|
}
|
|
|
|
|
|
-.a_b_b_b_record{
|
|
|
- width: 100%;
|
|
|
- height: 100%;
|
|
|
- display: flex;
|
|
|
- justify-content: space-between;
|
|
|
- align-items: center;
|
|
|
+.a_b_b_b_record {
|
|
|
+ height: 100%;
|
|
|
+ flex: 1;
|
|
|
+ display: flex;
|
|
|
+ justify-content: flex-end;
|
|
|
+ align-items: center;
|
|
|
}
|
|
|
|
|
|
-.a_b_b_b_r_left{
|
|
|
- display: flex;
|
|
|
- align-items: center;
|
|
|
- justify-content: center;
|
|
|
+.a_b_b_b_r_left {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
}
|
|
|
|
|
|
-.a_b_b_b_r_left>div{
|
|
|
- height: 100%;
|
|
|
- width: auto;
|
|
|
- display: flex;
|
|
|
- flex-direction: column;
|
|
|
- justify-content: space-between;
|
|
|
- margin-left: 10px;
|
|
|
+.a_b_b_b_r_left>div {
|
|
|
+ height: 100%;
|
|
|
+ width: auto;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ justify-content: space-between;
|
|
|
+ margin-left: 10px;
|
|
|
}
|
|
|
|
|
|
-.a_b_b_b_r_left>div>div{
|
|
|
- font-weight: bold;
|
|
|
- margin-bottom: 5px;
|
|
|
+.a_b_b_b_r_left>div>div {
|
|
|
+ font-weight: bold;
|
|
|
+ margin-bottom: 5px;
|
|
|
}
|
|
|
|
|
|
-.a_b_b_b_r_left>div>span{
|
|
|
- color: #3681FC;
|
|
|
+.a_b_b_b_r_left>div>span {
|
|
|
+ color: #3681FC;
|
|
|
}
|
|
|
|
|
|
-.a_b_b_b_r_right{
|
|
|
- display: flex;
|
|
|
- align-items: center;
|
|
|
- justify-content: flex-end;
|
|
|
+.a_b_b_b_r_right {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: flex-end;
|
|
|
}
|
|
|
-
|
|
|
</style>
|