JLBA202505130001_关于吉林银行新建AI智能培训系统的需求_开发录音组件,基本功能开发完成

This commit is contained in:
田岩
2026-03-04 16:09:22 +08:00
parent cfd9c5f224
commit 4981aed2df
7 changed files with 190 additions and 240 deletions
+92 -108
View File
@@ -3,17 +3,31 @@
<!-- <MarkdownPreview/> -->
<view class="top-bg"></view>
<view class="bot-bg"></view>
<scroll-view class="index-dialog-body" :scroll-y="true" upper-threshold="0" refresher-enabled="true"
refresher-default-style="none" @refresherrefresh="scrolltolower">
<scroll-view
class="index-dialog-body"
:scroll-y="true"
upper-threshold="0"
refresher-enabled="true"
refresher-default-style="none"
@refresherrefresh="scrolltolower"
>
<view class="body-title">
<!-- <uv-icon class="arrow-icon" name="arrow-left" @click="common.navigateBack()"/> -->
AI问答
<view class="top-desc">内容由AI生成</view>
<view class="seek-setting">
<image src="@/static/images/dialog/new-dialog.png" alt="" class="image-icon-new" @click="createNewDialog">
</image>
<image src="@/static/images/dialog/history.png" alt="" class="image-icon"
@click="showMenuList = !showMenuList"></image>
<image
src="@/static/images/dialog/new-dialog.png"
alt=""
class="image-icon-new"
@click="createNewDialog"
></image>
<image
src="@/static/images/dialog/history.png"
alt=""
class="image-icon"
@click="showMenuList = !showMenuList"
></image>
<view :class="['more-list', showMenuList ? 'show' : '']">
<view class="more-item" @click.stop="showHistory">历史</view>
<view class="more-item" @click.stop="toMessage">消息</view>
@@ -65,18 +79,28 @@
</scroll-view>
</view> -->
<view class="talking-list" v-show="talkingList.length > 0">
<scroll-view class="talking-scroll-list" :scroll-y="true" :scroll-top="scrollTop" :show-scrollbar="false"
:scroll-with-animation="false">
<TalkingItem v-for="(item, index) in talkingList" :talkingType="item.type" :talkingInfo="item"
:isLast="index + 1 === talkingList.length" :isAnswering="!answerIsOver"
:activeVoiceId="activeVoiceTalkingItemId" @handleEvents="talkItemEvents"></TalkingItem>
<scroll-view
class="talking-scroll-list"
:scroll-y="true"
:scroll-top="scrollTop"
:show-scrollbar="false"
:scroll-with-animation="false"
>
<TalkingItem
v-for="(item, index) in talkingList"
:talkingType="item.type"
:talkingInfo="item"
:isLast="index + 1 === talkingList.length"
:isAnswering="!answerIsOver"
:activeVoiceId="activeVoiceTalkingItemId"
@handleEvents="talkItemEvents"
></TalkingItem>
<view class="question-item-box mt-16" v-for="item in talkQnsList">
<view class="question-item" @click="sendText(item)">
{{ item }}
</view>
</view>
</scroll-view>
</view>
<view class="router-list">
@@ -111,18 +135,25 @@
</view>
</scroll-view>
</view>
<!-- <TouchBtn class="talk-btns" @uploadVoice="uploadRecordNow" @submitAnswer="submitAnswerNow"
<TouchBtn
class="talk-btns"
@uploadVoice="uploadRecordNow"
@submitAnswer="submitAnswerNow"
@startRecord="startRecordCallback"
:loadingText="sendLoadingText"
:isLoading="!answerIsOver"
:adjustPosition="true"
:isDisabled="isHistory"
/>
<!-- <touch-btn @uploadVoice="uploadRecordNow" @submitAnswer="submitAnswerNow"
@startRecord="startRecordCallback" :loadingText="sendLoadingText" :isLoading="!answerIsOver"
:adjustPosition="true" :isDisabled="isHistory" /> -->
<touch-btn @uploadVoice="uploadRecordNow" @submitAnswer="submitAnswerNow"
@startRecord="startRecordCallback" :loadingText="sendLoadingText" :isLoading="!answerIsOver"
:adjustPosition="true" :isDisabled="isHistory" />
<History ref="historyRef" @showDetail="showHistoryDetail"></History>
<PreviewVue ref="previewRef" />
</scroll-view>
</view>
<badge ref="badgeRef"></badge>
<points ref="pointsRef"></points>
<!-- 反馈组件 -->
@@ -133,51 +164,20 @@
</template>
<script setup>
import {
ref,
unref,
onMounted,
watch,
nextTick,
computed,
onActivated
} from 'vue';
import { ref, unref, onMounted, watch, nextTick, computed, onActivated } from 'vue';
import common from '@/common/common';
import {
setupKeyboardHeightListener
} from '@/common/common';
// import TouchBtn from '@/pages/course/components/touchBtn.vue';
import { setupKeyboardHeightListener } from '@/common/common';
import TouchBtn from '@/pages/course/components/touchBtn.vue';
import TalkingItem from './components/talking-item.vue';
import PreviewVue from './components/preview.vue';
import {
useSocketStore
} from '@/store/socket.js';
import {
useStorageStore
} from '@/store/storage.js';
import {
storeToRefs
} from 'pinia';
import {
onLoad,
onShow,
onUnload,
onHide,
onBackPress,
onLaunch
} from '@dcloudio/uni-app';
import {
get_base_url,
goto_login_fun
} from '@/api/request';
import {
getUserInfo,
getPhoneEnvBool
} from '@/common/common';
import {
commonUploadVoiceFile
} from '@/api/common.js';
import { useSocketStore } from '@/store/socket.js';
import { useStorageStore } from '@/store/storage.js';
import { storeToRefs } from 'pinia';
import { onLoad, onShow, onUnload, onHide, onBackPress, onLaunch } from '@dcloudio/uni-app';
import { get_base_url, goto_login_fun } from '@/api/request';
import { getUserInfo, getPhoneEnvBool } from '@/common/common';
import { commonUploadVoiceFile } from '@/api/common.js';
import {
queryHotQuestionApi,
insertTraAskFeedback,
@@ -190,28 +190,20 @@
import badge from '@/components/points-and-badge/badge';
import points from '@/components/points-and-badge/points';
import usePointsAndBadge from '@/components/points-and-badge/usePointsAndBadge';
const {
pointAndBadgesRun,
badgeRef,
pointsRef
} = usePointsAndBadge();
const { pointAndBadgesRun, badgeRef, pointsRef } = usePointsAndBadge();
const {
statusBarHeight
} = uni.getWindowInfo();
const { statusBarHeight } = uni.getWindowInfo();
const pageTopPadding = computed(() => statusBarHeight + 'px');
const socketStore = useSocketStore();
const {
SocketObj
} = storeToRefs(socketStore);
const { SocketObj } = storeToRefs(socketStore);
const feedbackRef = ref();
const watermarkRef = ref();
const userInfo = ref(getUserInfo());
const luimgAddr = computed(() => unref(userInfo)?.mascotInfo?.imgAddr || '')
const userParams = '/' + (unref(userInfo)?.loginName ?? '')
const luimgAddr = computed(() => unref(userInfo)?.mascotInfo?.imgAddr || '');
const userParams = '/' + (unref(userInfo)?.loginName ?? '');
const questionList = ref([
// '对公小程序开户流程?',
// '厅堂服务经理2025年管理办法?',
@@ -257,8 +249,8 @@
};
const showModelComfirm = ref(false);
const reconcatNum = ref(1);
const askTime = ref(0)
const talkQnsList = ref([])
const askTime = ref(0);
const talkQnsList = ref([]);
const initsocketTask = () => {
isHistory.value = false;
socketStore.creatSocket('/traask/asksocket/open?summary=');
@@ -292,11 +284,7 @@
});
});
unref(SocketObj).on('message', (res) => {
const {
rtnCode,
body,
commond
} = JSON.parse(res.data);
const { rtnCode, body, commond } = JSON.parse(res.data);
let _id = new Date().getTime() + 'id';
if (rtnCode === '0000') {
if (commond === 'ASK-OPEN') {
@@ -364,8 +352,8 @@
if (body.event === 'start') {
console.log('开始回答!');
if (askTime.value === 0) {
pointAndBadgesRun('06')
askTime.value = 1
pointAndBadgesRun('06');
askTime.value = 1;
}
answerIsOver.value = false;
answerText.value = '';
@@ -388,7 +376,7 @@
} else if (body.event === 'end') {
console.log('完成回答!');
answerIsOver.value = true;
console.log(answerText.value)
console.log(answerText.value);
} else if (body.event === 'sourceDocuments') {
console.log('回答返回文件列表!');
console.log('body: ', body);
@@ -399,7 +387,7 @@
} else if (body.event === 'recommend') {
console.log('回答返回问题列表!');
if (talkingList.value.length === 0) return;
talkQnsList.value = body.data || []//questionList.value.splice(0, 3);
talkQnsList.value = body.data || []; //questionList.value.splice(0, 3);
}
return;
}
@@ -438,7 +426,7 @@
};
const sendMessage = (data) => {
if (data.commond === 'ASK') {
talkQnsList.value = []
talkQnsList.value = [];
}
unref(SocketObj).send(data);
};
@@ -457,14 +445,9 @@
talkingList.value[talkingList.value.length - 1].talkingText = answerText.value;
};
const isDownloading = ref(false)
const isDownloading = ref(false);
const stopAnswerCallBack = ref(null);
const talkItemEvents = ({
type,
data,
id,
info = {}
}) => {
const talkItemEvents = ({ type, data, id, info = {} }) => {
switch (type) {
case 'reAnswer':
console.log('重新提问回答');
@@ -577,7 +560,8 @@
return new Promise((resolve, reject) => {
console.log('开始下载:', fileUrl);
const dtask = plus.downloader.createDownload(
fileUrl, {
fileUrl,
{
filename: localFilePath
},
(d, status) => {
@@ -707,7 +691,7 @@
const sendText = (item) => {
submitAnswerNow(item);
};
// 发送语音
const uploadRecordNow = (voicePath, voiceTime) => {
// /traask/traAskchat/voiceTrans
@@ -775,7 +759,7 @@
});
setHeight({
height: 0
})
});
};
const startRecordCallback = () => {
// 开始录音回调
@@ -841,7 +825,7 @@
};
onLoad(() => {
//#ifdef APP-PLUS
plus.screen.lockOrientation('portrait-primary')
plus.screen.lockOrientation('portrait-primary');
// #endif
changeAppHeightBottom();
if (!common.isLogin()) {
@@ -873,20 +857,21 @@
const setHeight = (res) => {
keyboardHeight.value = (res.height || 0) + 'px';
setTimeout(() => {
console.log(totalBotHeight.value)
}, 1000)
console.log(totalBotHeight.value);
}, 1000);
};
const keyBoardIsHide = computed(() => {
return parseInt(keyboardHeight.value) == 0;
});
const bottomHeight = ref('0px');
const totalBotHeight = computed(() => {
let isIos
let isIos;
// #ifdef APP-PLUS
isIos = (plus.os.name == "iOS")
isIos = plus.os.name == 'iOS';
// #endif
return isIos || keyBoardIsHide.value ? 0 + 'px' : parseInt(keyboardHeight.value) + parseInt(bottomHeight.value) +
'px';
return isIos || keyBoardIsHide.value
? 0 + 'px'
: parseInt(keyboardHeight.value) + parseInt(bottomHeight.value) + 'px';
});
const changeAppHeightBottom = (height) => {
//#ifdef APP-PLUS
@@ -894,16 +879,16 @@
const systemInfo = uni.getSystemInfoSync();
// 计算安全区域底部高度
bottomHeight.value = systemInfo.screenHeight - systemInfo.safeArea.bottom + 'px';
console.log(systemInfo)
console.log(systemInfo.screenHeight, systemInfo.safeArea.bottom)
console.log(systemInfo);
console.log(systemInfo.screenHeight, systemInfo.safeArea.bottom);
// #endif
};
const deleteFolder = () => {
//#ifdef APP-PLUS
plus.io.resolveLocalFileSystemURL('_doc/pdf_view', function(entry) {
plus.io.resolveLocalFileSystemURL('_doc/pdf_view', function (entry) {
console.log('entry', entry);
entry.removeRecursively(function(res) {
entry.removeRecursively(function (res) {
console.log('删除成功');
});
});
@@ -920,7 +905,6 @@
nextTick(() => {
watermarkRef.value?.updateWatermarkText();
});
});
// #endif
onUnload(() => {
@@ -1257,4 +1241,4 @@
// height: 100%;
// }
// }
</style>
</style>
+7 -7
View File
@@ -67,7 +67,7 @@
<view class="fixed-box font_pf" :style="{ marginBottom: popup_input_bottom }">
<view class="touch-btn-div" :class="{ show: showTouchBtn }">
<!-- <TouchBtnOnlyVoice
<TouchBtnOnlyVoice
v-if="answerMethod === '03'"
class="talk-btns"
ref="touchBtnRef"
@@ -79,8 +79,8 @@
:isDisabled="false"
:onlyVoice="true"
:answerMethod="answerMethod"
/> -->
<!-- <TouchBtn
/>
<TouchBtn
v-else
class="talk-btns"
ref="touchBtnRef"
@@ -91,9 +91,9 @@
:adjustPosition="false"
:isDisabled="false"
:answerMethod="answerMethod"
/> -->
/>
<touch-btn
<!-- <touch-btn
class="talk-btns"
ref="touchBtnRef"
@sendLoading="sendLoading"
@@ -103,7 +103,7 @@
:isLoading="touchIsDisabled"
loadingText="只能进行一条回答"
:answerMethod="answerMethod"
/>
/> -->
</view>
</view>
@@ -123,7 +123,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 TouchBtnOnlyVoice from '@/pages/course/components/touchBtnOnlyVoice.vue';
import common from '@/common/common';
import { setPageCache, formatSeconds, getPageCache, setupKeyboardHeightListener } from '@/common/common';