JLBA202505130001_关于吉林银行新建AI智能培训系统的需求_替换新录音组件,练习考试错题本,Pk
This commit is contained in:
@@ -98,7 +98,6 @@ export const vibrateLight = () : void => {
|
||||
if (IsAndEnv) {
|
||||
uni.vibrateShort({
|
||||
success: function () {
|
||||
console.log('success');
|
||||
}
|
||||
});
|
||||
} else {
|
||||
|
||||
@@ -159,6 +159,16 @@
|
||||
type: Number,
|
||||
default: 500
|
||||
},
|
||||
// 最小录音时长
|
||||
minRecordDuration: {
|
||||
type: Number,
|
||||
default: 1000
|
||||
},
|
||||
// 最大录音时长
|
||||
maxRecordDuration: {
|
||||
type: Number,
|
||||
default: 60000
|
||||
},
|
||||
adjustPosition: {
|
||||
default: false,
|
||||
type: Boolean
|
||||
@@ -213,6 +223,8 @@
|
||||
const isInputVisible = ref(true); // true=显示录音按钮,false=显示输入框
|
||||
const recordStartTime = ref(0); // 录音开始时间戳
|
||||
let pressTimer = null;
|
||||
// 时长自动关闭定时器
|
||||
let durationTimer = null;
|
||||
// 计算属性:判断是否仅语音/仅文字模式(简化模板逻辑)
|
||||
const isVoiceOnlyMode = computed(() => workMode.value === 'voice-only');
|
||||
const isTextOnlyMode = computed(() => workMode.value === 'text-only');
|
||||
@@ -241,6 +253,7 @@
|
||||
// 开启语音
|
||||
const startRecord = async (obj: { touches: any[] }) => {
|
||||
if (props.isDisabled) return;
|
||||
if (props.isLoading) return common.msg(props.loadingText);
|
||||
if (pressTimer || isRecording.value) return;
|
||||
if (props.canAnswer) return common.msg(props.canAnswerText);
|
||||
try {
|
||||
@@ -271,7 +284,7 @@
|
||||
}
|
||||
ws.value = socketTask;
|
||||
wsStatus.value = true;
|
||||
console.log('WS连接成功');
|
||||
console.log('WS连接成功', isRecording.value, );
|
||||
ws.value.onMessage((res: { data: Uint8Array | ArrayBuffer }) => {
|
||||
try {
|
||||
const { msgType, body } = ProtocolCodec.unpack(res.data);
|
||||
@@ -289,6 +302,10 @@
|
||||
// 如果不等于init说明已经超时,被超时函数处理完了,这里即使返回也不做处理
|
||||
if (status.value === 'voice_to_text' && voice_to_text_status.value !== 'init') return;
|
||||
if (status.value === 'send_over') return;
|
||||
// 时间太短,关掉的时候就处理了,这里不处理
|
||||
const recordDurationMs = Date.now() - recordStartTime.value;
|
||||
if (recordDurationMs <= props.minRecordDuration) return;
|
||||
|
||||
status.value = 'send_over'; // 设置成发送完成
|
||||
if (voiceTimer) clearTimeout(voiceTimer);
|
||||
// 设置识别结果
|
||||
@@ -320,11 +337,13 @@
|
||||
console.log('网络出现问题');
|
||||
});
|
||||
pressTimer = setTimeout(() => {
|
||||
if(!isRecording.value) {
|
||||
if (!isRecording.value) {
|
||||
console.log('定时器被取消还是进入了');
|
||||
return
|
||||
return;
|
||||
}
|
||||
pressTimer = null;
|
||||
status.value = 'voice_recording';
|
||||
console.log('触感震动');
|
||||
vibrateLight(); // 触感震动
|
||||
// 重设按下位置
|
||||
const changedTouche = obj.touches[0];
|
||||
@@ -333,7 +352,7 @@
|
||||
// 记录开始时间戳(毫秒)
|
||||
recordStartTime.value = Date.now();
|
||||
// 弹出录音界面
|
||||
popupRef.value.open();
|
||||
startRecordingTimer(true) // 启动超长定时器
|
||||
startAudioRecord({
|
||||
onFrame: (pcmData: any) => {
|
||||
if (wsStatus.value && ws.value) {
|
||||
@@ -343,6 +362,7 @@
|
||||
onStart: (res: any) => {
|
||||
console.log('启动', res);
|
||||
recordId.value = res.recordId ?? '';
|
||||
popupRef.value.open();
|
||||
},
|
||||
onStop: () => {
|
||||
console.log('关闭');
|
||||
@@ -354,11 +374,12 @@
|
||||
}
|
||||
}
|
||||
});
|
||||
}, 100);
|
||||
}, 140);
|
||||
};
|
||||
|
||||
// 结束录音
|
||||
const closePopup = () => {
|
||||
startRecordingTimer(false)
|
||||
isRecording.value = false;
|
||||
popupRef.value.close();
|
||||
};
|
||||
@@ -382,6 +403,11 @@
|
||||
clearTimeout(pressTimer);
|
||||
console.log('取消一个存在的定时器');
|
||||
pressTimer = null;
|
||||
isRecording.value = false;
|
||||
setTimeout(() => {
|
||||
status.value = 'default'
|
||||
}, 50);
|
||||
return;
|
||||
}
|
||||
if (!isRecording.value) return; // 未处于录音状态
|
||||
if (status.value !== 'voice_recording') {
|
||||
@@ -389,35 +415,38 @@
|
||||
closePopup();
|
||||
return;
|
||||
}
|
||||
|
||||
// 核心:计算录音总时长(毫秒转秒,保留1位小数)
|
||||
const recordDurationMs = Date.now() - recordStartTime.value;
|
||||
console.log('recordDurationMs', recordDurationMs);
|
||||
// 拖动到转文字按钮上抬手或者仅文字模式的发送也强行算他转文字
|
||||
const _isOutStatus = workMode.value === 'text-only' && isOutStatus.value === '01' ? '03' : isOutStatus.value;
|
||||
|
||||
if (_isOutStatus === '03') {
|
||||
// 时间太短03也直接关了
|
||||
if (_isOutStatus === '03' && !(recordDurationMs <= props.minRecordDuration)) {
|
||||
console.log('时间不短进来了');
|
||||
status.value = 'voice_to_text'; //主状态设置为转文字
|
||||
voice_to_text_status.value = 'init';
|
||||
if (voiceTimer) clearTimeout(voiceTimer);
|
||||
voiceTimer = setTimeout(() => {
|
||||
voiceTimer = null;
|
||||
console.log('3号定时器', voice_to_text_status.value, status.value);
|
||||
if (voice_to_text_status.value !== 'init') return;
|
||||
if (status.value === 'send_over') return;
|
||||
voice_to_text_status.value = 'networkError';
|
||||
status.value = 'send_over'; // 设置成发送完成
|
||||
emit('submitVoice', { ossKey: '', text: '', recordId: recordId.value });
|
||||
}, 5000);
|
||||
}, 4000);
|
||||
} else if (_isOutStatus === '01') {
|
||||
status.value = 'voice_send_ing'; //主状态设置为语音发送中
|
||||
}
|
||||
|
||||
const recordDurationMs = Date.now() - recordStartTime.value;
|
||||
// 核心:计算录音总时长(毫秒转秒,保留1位小数)
|
||||
if (recordDurationMs < 540) {
|
||||
if ((_isOutStatus !== '03' || recordDurationMs <= props.minRecordDuration) && recordDurationMs < 640) {
|
||||
await new Promise<void>((resolve) => {
|
||||
setTimeout(() => {
|
||||
resolve();
|
||||
}, 540 - recordDurationMs);
|
||||
}, 640 - recordDurationMs);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// 取消的时候自己主动关闭websocket,其他的时候需要等待后端的消息关闭
|
||||
if (_isOutStatus === '02' || errrStatus === 'networkError') {
|
||||
closeWS();
|
||||
@@ -431,19 +460,26 @@
|
||||
}
|
||||
stopAudioRecord(); // 关掉录音
|
||||
isRecording.value = false;
|
||||
if (_isOutStatus !== '03' || errrStatus === 'networkError') {
|
||||
console.log('_isOutStatus', _isOutStatus);
|
||||
if (_isOutStatus !== '03' || errrStatus === 'networkError' || recordDurationMs <= props.minRecordDuration) {
|
||||
// 转文字时候不关遮罩层,网络错误必须关遮罩层
|
||||
console.log('转文字时候不关遮罩层,网络错误必须关遮罩层');
|
||||
closePopup();
|
||||
|
||||
// 关掉弹窗后的提示
|
||||
if (errrStatus === 'networkError') {
|
||||
if (errrStatus === 'networkError' && _isOutStatus === '01') {
|
||||
status.value = 'send_over'; // 设置成发送完成
|
||||
if (_isOutStatus !== '03') {
|
||||
emit('submitVoice', { ossKey: '', text: '', recordId: recordId.value });
|
||||
emit('submitVoice', { ossKey: '', text: '', recordId: recordId.value });
|
||||
return;
|
||||
} else if (recordDurationMs <= props.minRecordDuration) {
|
||||
console.log('进入这里了', status.value);
|
||||
if (_isOutStatus !== '02') {
|
||||
showErrorTip(ErrorCode.ShortRecord);
|
||||
}
|
||||
// return showErrorTip(ErrorCode.NetworkError);
|
||||
} else if (_isOutStatus === '01' && recordDurationMs <= 1000) {
|
||||
status.value = 'send_over'; // 设置成发送完成
|
||||
return showErrorTip(ErrorCode.ShortRecord);
|
||||
setTimeout(() => {
|
||||
status.value = 'send_over'; // 设置成发送完成
|
||||
}, 200);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (_isOutStatus === '01' && status.value == 'voice_send_ing') {
|
||||
@@ -451,13 +487,14 @@
|
||||
// 如果socket长时间没有返回,这里兜底一下
|
||||
if (voiceTimer) clearTimeout(voiceTimer);
|
||||
voiceTimer = setTimeout(() => {
|
||||
console.log('1号定时器', voice_to_text_status.value, status.value);
|
||||
voiceTimer = null;
|
||||
if (workMode.value === 'voice-only') {
|
||||
if (status.value === 'send_over') return;
|
||||
status.value = 'send_over'; // 恢复成默认状态
|
||||
emit('submitVoice', { ossKey: '', text: '', recordId: recordId.value });
|
||||
}
|
||||
}, 5000);
|
||||
}, 4000);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -523,7 +560,24 @@
|
||||
const _height = Math.max(height - 100, 0);
|
||||
pageBoxMarginBottom.value = `${_height}px`;
|
||||
});
|
||||
|
||||
const startRecordingTimer = (status: boolean) => {
|
||||
const clearRecordingTimer = () => {
|
||||
if (durationTimer) {
|
||||
clearTimeout(durationTimer);
|
||||
durationTimer = null; // 重置定时器变量,避免内存泄漏
|
||||
console.log('录音时长定时器已清除');
|
||||
}
|
||||
};
|
||||
clearRecordingTimer();
|
||||
if (!status) return;
|
||||
const maxDuration = props.maxRecordDuration;
|
||||
durationTimer = setTimeout(() => {
|
||||
console.log(`录音达到最大时长 ${maxDuration} 秒,自动关闭`);
|
||||
// 执行关闭录音的逻辑
|
||||
stopRecord();
|
||||
clearRecordingTimer();
|
||||
}, maxDuration);
|
||||
};
|
||||
// 外面调用放弃这次
|
||||
const give_up = () => {
|
||||
console.log('调用结束语音回答');
|
||||
|
||||
@@ -92,7 +92,7 @@
|
||||
</view>
|
||||
<view class="fixed-box font_pf" :style="{ marginBottom: popup_input_bottom }">
|
||||
<view class="touch-btn-div" :class="{ show: showTouchBtn }">
|
||||
<TouchBtn
|
||||
<!-- <TouchBtn
|
||||
class="talk-btns"
|
||||
ref="touchBtnRef"
|
||||
@uploadVoice="touchBtnSubmit('voice',$event)"
|
||||
@@ -101,6 +101,15 @@
|
||||
loadingText="只能进行一条回答"
|
||||
:adjustPosition="false"
|
||||
:isDisabled="false"
|
||||
/> -->
|
||||
<touch-btn
|
||||
class="talk-btns"
|
||||
ref="touchBtnRef"
|
||||
@sendLoading="sendLoading"
|
||||
@submitVoice="submitVoice"
|
||||
@submitAnswer="submitAnswer"
|
||||
:isLoading="touchIsDisabled"
|
||||
loadingText="只能进行一条回答"
|
||||
/>
|
||||
</view>
|
||||
</view>
|
||||
@@ -121,7 +130,7 @@
|
||||
import Subject from '@/components/examination/subject.vue';
|
||||
import CharactersSubject from '@/components/examination/characters-subject.vue';
|
||||
// import TouchBtn from '@/components/examination/touchBtn.vue';
|
||||
import TouchBtn from '@/pages/course/components/touchBtn.vue';
|
||||
// import TouchBtn from '@/pages/course/components/touchBtn.vue';
|
||||
import common from '@/common/common';
|
||||
import { setPageCache, formatSeconds, getPageCache, setupKeyboardHeightListener, formatName } from '@/common/common';
|
||||
import { commonUploadVoiceFile } from '@/api/common.js';
|
||||
@@ -326,7 +335,44 @@
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
// 录音组件提交中转圈
|
||||
const sendLoading = () => {
|
||||
const topic = topicList[questionNumber.value];
|
||||
console.log('录音组件提交中转圈', topic.es_status);
|
||||
if (topic.es_status === '00') return;
|
||||
topic.es_status = '00'; // 00转圈
|
||||
}
|
||||
|
||||
// 新录音组件语音提交
|
||||
const submitVoice = ({ossKey,text}) => {
|
||||
console.log('新录音组件语音提交', ossKey,text);
|
||||
const topic = topicList[questionNumber.value];
|
||||
if(!ossKey) {
|
||||
topic.es_status = ''; // 取消转圈
|
||||
common.msg('系统异常,请联系管理员');
|
||||
} else if (text === '') {
|
||||
topic.es_status = ''; // 取消转圈
|
||||
return common.msg('未识别到文字');
|
||||
} else {
|
||||
topic.es_status = '02';
|
||||
topic.my_answer = {
|
||||
anserResult: text,
|
||||
ossKey: ossKey
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
// 新录音组件文本提交
|
||||
const submitAnswer = (answerText) => {
|
||||
const topic = topicList[questionNumber.value];
|
||||
touchBtnRef.value?.clearInputText(); // 清除发送框数据
|
||||
topic.es_status = '01';
|
||||
topic.my_answer = {
|
||||
anserResult: answerText // 正确答案文字内容
|
||||
};
|
||||
}
|
||||
|
||||
// 录音组件提交
|
||||
const touchBtnSubmit = (type, submitObj) => {
|
||||
const topic = topicList[questionNumber.value];
|
||||
|
||||
@@ -96,7 +96,7 @@
|
||||
</view>
|
||||
</view>
|
||||
<view class="touch-btn-div" :class="{ show: showTouchBtn }">
|
||||
<TouchBtnOnlyVoice
|
||||
<!-- <TouchBtnOnlyVoice
|
||||
v-if="answerMethod === '03'"
|
||||
class="talk-btns"
|
||||
ref="touchBtnRef"
|
||||
@@ -120,6 +120,16 @@
|
||||
:adjustPosition="false"
|
||||
:isDisabled="false"
|
||||
:answerMethod="answerMethod"
|
||||
/> -->
|
||||
<touch-btn
|
||||
class="talk-btns"
|
||||
ref="touchBtnRef"
|
||||
@sendLoading="sendLoading"
|
||||
@submitVoice="submitVoice"
|
||||
@submitAnswer="submitAnswer"
|
||||
:isLoading="touchIsDisabled"
|
||||
loadingText="只能进行一条回答"
|
||||
:answerMethod="answerMethod"
|
||||
/>
|
||||
</view>
|
||||
</view>
|
||||
@@ -174,9 +184,8 @@
|
||||
import Feedback from './components/feedback.vue';
|
||||
import Dialog from './components/dialog.vue';
|
||||
import Subject from '@/components/examination/subject.vue';
|
||||
// import TouchBtn from '@/components/examination/touchBtn.vue';
|
||||
import TouchBtn from '@/pages/course/components/touchBtn.vue';
|
||||
import TouchBtnOnlyVoice from '@/pages/course/components/touchBtnOnlyVoice.vue';
|
||||
// import TouchBtn from '@/pages/course/components/touchBtn.vue';
|
||||
// import TouchBtnOnlyVoice from '@/pages/course/components/touchBtnOnlyVoice.vue';
|
||||
import { ref, reactive, computed, onMounted, nextTick } from 'vue';
|
||||
import { onLoad, onBackPress } from '@dcloudio/uni-app';
|
||||
import common from '@/common/common';
|
||||
@@ -321,7 +330,48 @@
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
// 录音组件提交中转圈
|
||||
const sendLoading = () => {
|
||||
const topic = topicList[questionNumber.value];
|
||||
console.log('录音组件提交中转圈', topic.es_status);
|
||||
if (topic.es_status === '00') return;
|
||||
topic.es_status = '00'; // 00转圈
|
||||
}
|
||||
|
||||
// 新录音组件语音提交
|
||||
const submitVoice = ({ossKey,text}) => {
|
||||
console.log('新录音组件语音提交', ossKey,text);
|
||||
const topic = topicList[questionNumber.value];
|
||||
if(!ossKey) {
|
||||
topic.es_status = ''; // 取消转圈
|
||||
common.msg('系统异常,请联系管理员');
|
||||
} else if (text === '') {
|
||||
topic.es_status = ''; // 取消转圈
|
||||
return common.msg('未识别到文字');
|
||||
} else {
|
||||
topic.es_status = '02';
|
||||
topic.my_answer = {
|
||||
anserResult: text,
|
||||
ossKey: ossKey
|
||||
};
|
||||
hand_in_paper_cache();
|
||||
}
|
||||
}
|
||||
// 新录音组件文本提交
|
||||
const submitAnswer = (answerText) => {
|
||||
const topic = topicList[questionNumber.value];
|
||||
touchBtnRef.value?.clearInputText(); // 清除发送框数据
|
||||
topic.es_status = '01';
|
||||
topic.my_answer = {
|
||||
anserResult: answerText // 正确答案文字内容
|
||||
};
|
||||
hand_in_paper_cache();
|
||||
}
|
||||
|
||||
|
||||
// 录音按钮提交
|
||||
const touchBtnSubmit = (type, submitObj) => {
|
||||
const topic = topicList[questionNumber.value];
|
||||
|
||||
@@ -62,7 +62,7 @@
|
||||
</view>
|
||||
<view class="fixed-box font_pf" :style="{ marginBottom: popup_input_bottom }">
|
||||
<view class="touch-btn-div" :class="{ show: showTouchBtn }">
|
||||
<TouchBtn
|
||||
<!-- <TouchBtn
|
||||
class="talk-btns"
|
||||
ref="touchBtnRef"
|
||||
@uploadVoice="touchBtnSubmit('voice',$event)"
|
||||
@@ -71,6 +71,15 @@
|
||||
loadingText="只能进行一条回答"
|
||||
:adjustPosition="false"
|
||||
:isDisabled="false"
|
||||
/> -->
|
||||
<touch-btn
|
||||
class="talk-btns"
|
||||
ref="touchBtnRef"
|
||||
@sendLoading="sendLoading"
|
||||
@submitVoice="submitVoice"
|
||||
@submitAnswer="submitAnswer"
|
||||
:isLoading="touchIsDisabled"
|
||||
loadingText="只能进行一条回答"
|
||||
/>
|
||||
</view>
|
||||
</view>
|
||||
@@ -88,7 +97,7 @@
|
||||
import Dialog from '@/pages/examination/components/dialog.vue';
|
||||
import Subject from '@/components/examination/subject.vue';
|
||||
// import TouchBtn from '@/components/examination/touchBtn.vue';
|
||||
import TouchBtn from '@/pages/course/components/touchBtn.vue';
|
||||
// import TouchBtn from '@/pages/course/components/touchBtn.vue';
|
||||
import common from '@/common/common';
|
||||
import { getPageCache, setupKeyboardHeightListener } from '@/common/common';
|
||||
import { commonUploadVoiceFile } from '@/api/common.js';
|
||||
@@ -285,7 +294,44 @@
|
||||
return Promise.reject(error);
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
// 录音组件提交中转圈
|
||||
const sendLoading = () => {
|
||||
const topic = topicList[questionNumber.value];
|
||||
console.log('录音组件提交中转圈', topic.es_status);
|
||||
if (topic.es_status === '00') return;
|
||||
topic.es_status = '00'; // 00转圈
|
||||
}
|
||||
|
||||
// 新录音组件语音提交
|
||||
const submitVoice = ({ossKey,text}) => {
|
||||
console.log('新录音组件语音提交', ossKey,text);
|
||||
const topic = topicList[questionNumber.value];
|
||||
if(!ossKey) {
|
||||
topic.es_status = ''; // 取消转圈
|
||||
common.msg('系统异常,请联系管理员');
|
||||
} else if (text === '') {
|
||||
topic.es_status = ''; // 取消转圈
|
||||
return common.msg('未识别到文字');
|
||||
} else {
|
||||
topic.es_status = '02';
|
||||
topic.my_answer = {
|
||||
anserResult: text,
|
||||
ossKey: ossKey
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
// 新录音组件文本提交
|
||||
const submitAnswer = (answerText) => {
|
||||
const topic = topicList[questionNumber.value];
|
||||
touchBtnRef.value?.clearInputText(); // 清除发送框数据
|
||||
topic.es_status = '01';
|
||||
topic.my_answer = {
|
||||
anserResult: answerText // 正确答案文字内容
|
||||
};
|
||||
}
|
||||
|
||||
// 录音组件提交
|
||||
const touchBtnSubmit = (type, submitObj) => {
|
||||
const topic = topicList[questionNumber.value];
|
||||
|
||||
Reference in New Issue
Block a user