1151 lines
30 KiB
Vue
1151 lines
30 KiB
Vue
<template>
|
||
<view class="index-dialog-page">
|
||
<!-- <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"
|
||
>
|
||
<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>
|
||
<view :class="['more-list', showMenuList ? 'show' : '']">
|
||
<view class="more-item" @click.stop="showHistory">历史</view>
|
||
<view class="more-item" @click.stop="toMessage">消息</view>
|
||
<view class="more-item" @click.stop="toMePage">我的</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<view class="ai-info">
|
||
<!-- <image src="@/static/images/dialog/pet-3.png" alt="" class="image-pet-bg"></image> -->
|
||
<image src="@/static/images/dialog/pet-bg-base.png" alt="" class="image-pet-bg"></image>
|
||
<image :src="luimgAddr" alt="" class="image-pet" mode="widthFix"></image>
|
||
<view class="ai-info-bg-box">
|
||
<view class="hello-text">{{ userInfo ? 'Hi,我是' + userInfo?.mascotInfo?.mascotName : 'Hi' }}</view>
|
||
<view class="info-text">工作学习,我都能帮你!</view>
|
||
<view class="info-btn">试试他的能力</view>
|
||
</view>
|
||
</view>
|
||
<view class="questions-view">
|
||
<scroll-view :scroll-x="true" :show-scrollbar="false">
|
||
<view class="question-row">
|
||
<view
|
||
class="question-item"
|
||
v-for="item in Math.ceil(questionList.length / 2)"
|
||
@click="sendText(questionList[item - 1].hotContent)"
|
||
>
|
||
{{ questionList[item - 1].hotContent }}
|
||
</view>
|
||
</view>
|
||
<view class="question-row">
|
||
<view
|
||
class="question-item"
|
||
v-for="item in questionList.length - Math.ceil(questionList.length / 2)"
|
||
@click="sendText(questionList[item + Math.ceil(questionList.length / 2) - 1].hotContent)"
|
||
>
|
||
{{ questionList[item + Math.ceil(questionList.length / 2) - 1].hotContent }}
|
||
</view>
|
||
</view>
|
||
</scroll-view>
|
||
</view>
|
||
<view class="talking-list">
|
||
<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>
|
||
</view>
|
||
<view class="router-list">
|
||
<scroll-view class="" :scroll-x="true" :show-scrollbar="false">
|
||
<view class="btns-item" @click="routerTo('AI学')">
|
||
<image src="@/static/images/dialog/icons/study.png" alt="" class="image-icon"></image>
|
||
{{ 'AI学' }}
|
||
</view>
|
||
<view class="btns-item" @click="routerTo('AI练')">
|
||
<image src="@/static/images/dialog/icons/test.png" alt="" class="image-icon"></image>
|
||
{{ 'AI练' }}
|
||
</view>
|
||
<view class="btns-item" @click="routerTo('AI考')">
|
||
<image src="@/static/images/dialog/icons/exam.png" alt="" class="image-icon"></image>
|
||
{{ 'AI考' }}
|
||
</view>
|
||
<view class="btns-item" @click="routerTo('去PK')">
|
||
<image src="@/static/images/dialog/icons/PK.png" alt="" class="image-icon"></image>
|
||
{{ '去PK' }}
|
||
</view>
|
||
<view class="btns-item" @click="routerTo('任务')">
|
||
<image src="@/static/images/dialog/icons/task.png" alt="" class="image-icon"></image>
|
||
{{ '任务' }}
|
||
</view>
|
||
<view class="btns-item" @click="routerTo('错题')">
|
||
<image src="@/static/images/dialog/icons/wrong.png" alt="" class="image-icon"></image>
|
||
{{ '错题' }}
|
||
</view>
|
||
<view class="btns-item" @click="routerTo('分析')">
|
||
<image src="@/static/images/dialog/icons/static.png" alt="" class="image-icon"></image>
|
||
{{ '分析' }}
|
||
</view>
|
||
</scroll-view>
|
||
</view>
|
||
<TouchBtn
|
||
class="talk-btns"
|
||
@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>
|
||
<!-- 反馈组件 -->
|
||
<Feedback ref="feedbackRef" @feedbackAnswer="feedbackAnswer"></Feedback>
|
||
<!-- <file-preview ref="previewFileRef" :file-id="'603058d8-88e0-43d2-8242-3132b85bc91c'" v-model="showPreview" /> -->
|
||
<!-- 水印组件 -->
|
||
<watermark ref="watermarkRef"></watermark>
|
||
</template>
|
||
|
||
<script setup>
|
||
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 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 } 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,
|
||
queryAskHisByBatchIdPaging,
|
||
updateLikeStat,
|
||
updateDownvoteStat
|
||
} from '@/api/dialog.js';
|
||
import Feedback from './components/feedback.vue';
|
||
import History from './components/history.vue';
|
||
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 { statusBarHeight } = uni.getWindowInfo();
|
||
|
||
const pageTopPadding = computed(() => statusBarHeight + 'px');
|
||
|
||
const socketStore = useSocketStore();
|
||
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 questionList = ref([
|
||
// '对公小程序开户流程?',
|
||
// '厅堂服务经理2025年管理办法?',
|
||
// '厅堂服务经理2025年考核表单?',
|
||
// '吉林银行重要空白凭证调微业务操作规程?',
|
||
// '协助有权机关查询冻结扣划业务操作规程?',
|
||
// '柜面个人账户操作规程?',
|
||
// '久悬未取款账户如何办理销户?',
|
||
// '境外来华人员个人账户业务开户如何办理?',
|
||
// '营业机构日间管理风险防控要点有哪些?',
|
||
// '现金管理平台柜面业务操作?'
|
||
]);
|
||
const scrollBoxRef = ref();
|
||
const scrollTop = ref(99999);
|
||
const scrollToBottomNow = (time = 100) => {
|
||
nextTick(() => {
|
||
setTimeout(() => {
|
||
scrollTop.value += 100;
|
||
scrollTop.value += 100;
|
||
}, time);
|
||
});
|
||
};
|
||
const isHistory = ref(false);
|
||
const activeVoiceTalkingItemId = ref('');
|
||
// ws 初始化逻辑
|
||
const reconnectTimer = null; // 重连timer
|
||
const isManualClose = ref(false); // 是否手动关闭
|
||
const reqBatch = ref('');
|
||
const seqNo = ref('');
|
||
const mascotId = computed(() => {
|
||
return unref(userInfo)?.mascotInfo?.mascotId || 'Tst00001';
|
||
});
|
||
const answerText = ref('');
|
||
const answerFileList = ref('');
|
||
const answerIsOver = ref(true);
|
||
const talkingList = ref([]);
|
||
|
||
const createNewDialog = () => {
|
||
if (talkingList.value.length === 0) {
|
||
common.msg('已经是最新对话');
|
||
}
|
||
common.redirectTo(`/pages/index/dialog`);
|
||
};
|
||
const showModelComfirm = ref(false);
|
||
const reconcatNum = ref(1);
|
||
const askTime = ref(0)
|
||
const initsocketTask = () => {
|
||
isHistory.value = false;
|
||
socketStore.creatSocket('/traask/asksocket/open?summary=');
|
||
// unref(SocketObj).on('open', (res)=>{
|
||
// if(!answerIsOver.value){
|
||
// sendMessage({
|
||
// "commond" : 'ASK-RE-START',
|
||
// "body" : {
|
||
// reqBatch: reqBatch.value,
|
||
// seqNo: seqNo.value,
|
||
// answerContent: answerText.value
|
||
// }
|
||
// })
|
||
// }
|
||
// })
|
||
unref(SocketObj).on('error', () => {
|
||
if (watchFlag.value === 1 || showModelComfirm.value) return;
|
||
if (reconcatNum.value === 5) {
|
||
common.msg('系统网络异常,请稍后再试!');
|
||
return;
|
||
}
|
||
showModelComfirm.value = true;
|
||
common
|
||
.show('提示信息', '网络环境不稳定,请重试!', false, '', '确认')
|
||
.then((res) => {
|
||
reconcatNum.value += 1;
|
||
common.redirectTo(`/pages/index/dialog`);
|
||
})
|
||
.finally(() => {
|
||
showModelComfirm.value = false;
|
||
});
|
||
});
|
||
unref(SocketObj).on('message', (res) => {
|
||
const { rtnCode, body, commond } = JSON.parse(res.data);
|
||
let _id = new Date().getTime() + 'id';
|
||
if (rtnCode === '0000') {
|
||
if (commond === 'ASK-OPEN') {
|
||
if (!answerIsOver.value) {
|
||
// 问题没完成, 重新尝试回答
|
||
sendMessage({
|
||
commond: 'ASK-RE-START',
|
||
body: {
|
||
reqBatch: reqBatch.value,
|
||
seqNo: seqNo.value,
|
||
answerContent: answerText.value
|
||
}
|
||
});
|
||
} else {
|
||
// 新连接
|
||
sendMessage({
|
||
commond: 'ASK-START',
|
||
body: {
|
||
mascotId: mascotId.value,
|
||
deviceImei: ''
|
||
}
|
||
});
|
||
}
|
||
return;
|
||
}
|
||
if (commond === 'ASK-START') {
|
||
// console.log('开启对话!')
|
||
reqBatch.value = body.reqBatch;
|
||
return;
|
||
}
|
||
if (commond === 'ASK') {
|
||
console.log('发送问题成功!');
|
||
if (talkingList.value.length > 0 && talkingList.value[talkingList.value.length - 1].isLoading) {
|
||
talkingList.value.pop();
|
||
}
|
||
seqNo.value = body.seqNo;
|
||
touchBtnCallBack.value && touchBtnCallBack.value();
|
||
touchBtnCallBack.value = null;
|
||
talkingList.value.push({
|
||
type: 'question',
|
||
talkingText: body.intrctContent,
|
||
isLoading: false,
|
||
id: _id,
|
||
...body,
|
||
talkingVoice: askData.value.talkingVoice
|
||
});
|
||
talkingList.value.push({
|
||
type: 'answer',
|
||
isLoading: true,
|
||
id: _id + 'loading'
|
||
});
|
||
scrollToBottomNow();
|
||
return;
|
||
}
|
||
if (commond === 'ASK-STOP') {
|
||
console.log('停止回答标记!');
|
||
stopAnswerCallBack.value && stopAnswerCallBack.value(askData.value);
|
||
setTimeout(() => {
|
||
stopAnswerCallBack.value = null;
|
||
answerIsOver.value = true;
|
||
}, 10);
|
||
return;
|
||
}
|
||
if (commond === 'ASK-ANSWER') {
|
||
if (body.event === 'start') {
|
||
console.log('开始回答!');
|
||
if (askTime.value === 0){
|
||
pointAndBadgesRun('06')
|
||
askTime.value = 1
|
||
}
|
||
answerIsOver.value = false;
|
||
answerText.value = '';
|
||
talkingList.value.pop();
|
||
talkingList.value.push({
|
||
type: 'answer',
|
||
talkingText: answerText.value,
|
||
isLoading: false,
|
||
id: _id,
|
||
...body,
|
||
askData: {
|
||
...askData.value
|
||
},
|
||
talkingFiles: [],
|
||
talkingCrsList: []
|
||
});
|
||
} else if (body.event === 'token') {
|
||
answerIsOver.value = false;
|
||
answerText.value += body.data;
|
||
} else if (body.event === 'end') {
|
||
console.log('完成回答!');
|
||
answerIsOver.value = true;
|
||
} else if (body.event === 'sourceDocuments') {
|
||
console.log('回答返回文件列表!');
|
||
console.log('body: ', body);
|
||
if (talkingList.value.length === 0) return;
|
||
let _data = body.data;
|
||
talkingList.value[talkingList.value.length - 1].talkingFiles = _data.knowledgeList || [];
|
||
talkingList.value[talkingList.value.length - 1].talkingCrsList = _data.crsList || [];
|
||
}
|
||
return;
|
||
}
|
||
if (commond === 'ASK-RE-ANSWER') {
|
||
// console.log('开始继续回答!')
|
||
if (body.event === 'start') {
|
||
answerIsOver.value = false;
|
||
answerText.value = '';
|
||
} else if (body.event === 'token') {
|
||
answerIsOver.value = false;
|
||
answerText.value = body.data;
|
||
} else if (body.event === 'end') {
|
||
answerIsOver.value = true;
|
||
}
|
||
return;
|
||
}
|
||
|
||
if (commond === 'ASK-ERR') {
|
||
console.log('提问失败,系统异常!');
|
||
return;
|
||
}
|
||
} else {
|
||
if (['0005', 'QQ0005'].includes(res.rtnCode)) {
|
||
goto_login_fun();
|
||
}
|
||
}
|
||
});
|
||
watchFlag.value += 1;
|
||
};
|
||
const sendLoadingText = ref('问题回答中,请在问题回答结束后重试!');
|
||
const reconnect = () => {
|
||
if (reconnectTimer || isManualClose.value) return;
|
||
reconnectTimer = setTimeout(() => {
|
||
initsocketTask();
|
||
}, 3000);
|
||
};
|
||
const sendMessage = (data) => {
|
||
unref(SocketObj).send(data);
|
||
};
|
||
watch(
|
||
() => answerText.value,
|
||
(val) => {
|
||
if (val) {
|
||
changeText(val);
|
||
scrollToBottomNow();
|
||
}
|
||
}
|
||
);
|
||
|
||
const changeText = () => {
|
||
if (talkingList.value.length === 0) return;
|
||
talkingList.value[talkingList.value.length - 1].talkingText = answerText.value;
|
||
};
|
||
|
||
const isDownloading = ref(false)
|
||
const stopAnswerCallBack = ref(null);
|
||
const talkItemEvents = ({ type, data, id, info = {} }) => {
|
||
switch (type) {
|
||
case 'reAnswer':
|
||
console.log('重新提问回答');
|
||
// 停止获取
|
||
sendMessage({
|
||
commond: 'ASK-STOP',
|
||
body: {
|
||
reqBatch: reqBatch.value,
|
||
seqNo: seqNo.value
|
||
}
|
||
});
|
||
sendMessage({
|
||
commond: 'ASK',
|
||
body: data.askData
|
||
});
|
||
// // 设置停止回调
|
||
// stopAnswerCallBack.value = ($data) => {
|
||
// sendMessage({
|
||
// "commond": 'ASK',
|
||
// "body": $data
|
||
// })
|
||
// }
|
||
break;
|
||
case 'stop':
|
||
console.log('停止获取数据');
|
||
stopAnswerCallBack.value = null;
|
||
// ASK-STOP
|
||
sendMessage({
|
||
commond: 'ASK-STOP',
|
||
body: {
|
||
reqBatch: reqBatch.value,
|
||
seqNo: seqNo.value
|
||
}
|
||
});
|
||
break;
|
||
case 'changePlay':
|
||
activeVoiceTalkingItemId.value = id;
|
||
break;
|
||
case 'feedback':
|
||
let _feedstatus = data.downvoteStat === 'Y' ? 'N' : 'Y';
|
||
let _feedid = data.seqNo || data.askId;
|
||
if (_feedstatus === 'N') {
|
||
updateDownvoteStat({
|
||
askId: _feedid,
|
||
stat: _feedstatus
|
||
}).then((res) => {
|
||
talkingList.value.forEach((t) => {
|
||
if (t.seqNo === _feedid || t.askId === _feedid) {
|
||
t.downvoteStat = 'N';
|
||
}
|
||
});
|
||
});
|
||
} else {
|
||
feedbackRef.value.open(data);
|
||
}
|
||
break;
|
||
case 'great':
|
||
let _status = data.likeStat === 'Y' ? 'N' : 'Y';
|
||
let _id = data.seqNo || data.askId;
|
||
updateLikeStat({
|
||
askId: _id,
|
||
stat: _status
|
||
}).then((res) => {
|
||
talkingList.value.forEach((t) => {
|
||
if (t.seqNo === _id || t.askId === _id) {
|
||
t.likeStat = _status;
|
||
if (_status === 'Y') {
|
||
t.downvoteStat = 'N';
|
||
}
|
||
}
|
||
});
|
||
});
|
||
break;
|
||
case 'preview':
|
||
common.navigateTo('/pages/index/preview?fileId=' + info.docId);
|
||
// if (getPhoneEnvBool('AND')) {
|
||
// common.navigateTo('/pages/index/preview?fileId=' + info.docId);
|
||
// } else {
|
||
// common.navigateTo('/pages/index/preview?fileId=' + info.docId); return
|
||
// if(isDownloading.value) return
|
||
// const base_url = get_base_url('/traask/traFilePreview/');
|
||
// let fileUrl = base_url + '/traask/traFilePreview/' + info.docId + userParams;
|
||
// const localFilePath = '_doc/pdf_view/' + info.docName + '.pdf';
|
||
// isDownloading.value = true
|
||
// downloadAndSaveAvatar(fileUrl, localFilePath).then((res) => {
|
||
// uni.openDocument({
|
||
// filePath: res,
|
||
// showMenu: true,
|
||
// success: function () {
|
||
// console.log('打开文档成功');
|
||
// }
|
||
// })
|
||
// }).finally(()=>{
|
||
// setTimeout(()=>{
|
||
// isDownloading.value = false
|
||
// },1000)
|
||
// });
|
||
// }
|
||
break;
|
||
case 'toCourse':
|
||
console.log(type, data, id);
|
||
break;
|
||
default:
|
||
break;
|
||
}
|
||
};
|
||
const downloadAndSaveAvatar = async (fileUrl, localFilePath) => {
|
||
try {
|
||
//#ifdef APP-PLUS
|
||
return new Promise((resolve, reject) => {
|
||
console.log('开始下载:', fileUrl);
|
||
const dtask = plus.downloader.createDownload(
|
||
fileUrl,
|
||
{
|
||
filename: localFilePath
|
||
},
|
||
(d, status) => {
|
||
if (status === 200) {
|
||
console.log('保存路径:', d.filename);
|
||
resolve(d.filename);
|
||
} else {
|
||
console.error('文件下载失败:', status);
|
||
reject(new Error(`下载失败,状态码: ${status}`));
|
||
}
|
||
}
|
||
);
|
||
dtask.start();
|
||
});
|
||
// #endif
|
||
//#ifdef H5
|
||
return new Promise((resolve, reject) => {
|
||
resolve();
|
||
});
|
||
// #endif
|
||
} catch (error) {
|
||
console.error('创建目录失败:', error);
|
||
throw error;
|
||
}
|
||
};
|
||
const feedbackAnswer = (params) => {
|
||
talkingList.value.forEach((t) => {
|
||
if (t.seqNo === params.askId) {
|
||
t.downvoteStat = 'Y';
|
||
t.likeStat = 'N';
|
||
}
|
||
});
|
||
};
|
||
const historyRef = ref(null);
|
||
const showMenuList = ref(false);
|
||
const showHistory = () => {
|
||
showMenuList.value = false;
|
||
historyRef.value.open();
|
||
};
|
||
const toMessage = () => {
|
||
showMenuList.value = false;
|
||
common.navigateTo('/pages/messageNotification/index');
|
||
};
|
||
const toMePage = () => {
|
||
showMenuList.value = false;
|
||
common.switchTab('/pages/me/index');
|
||
};
|
||
|
||
const showHistoryDetail = (item) => {
|
||
isHistory.value = true;
|
||
queryAskHisByBatchIdPaging({
|
||
batchId: item.reqBatch,
|
||
page: 1,
|
||
limit: 100
|
||
}).then((res) => {
|
||
console.log(res);
|
||
|
||
talkingList.value = (res.body || []).map((t, index) => {
|
||
// let _obj = JSON.parse( t.respContent)
|
||
// console.log(_obj,0)
|
||
// if(t.chatRole === 'TCH'){
|
||
// console.log(JSON.parse(_obj),1)
|
||
// }
|
||
let _text;
|
||
let _talkingCrsList;
|
||
let _talkingFiles;
|
||
if (t.chatRole === 'TCH') {
|
||
_text = t.respContentVo?.messageBuileder || '';
|
||
_talkingCrsList = t.respContentVo?.resultMap?.crsList || [];
|
||
_talkingFiles = t.respContentVo?.resultMap?.knowledgeList || [];
|
||
} else {
|
||
_text = t.respContent;
|
||
}
|
||
return {
|
||
type: t.chatRole === 'TCH' ? 'answer' : 'question',
|
||
talkingText: _text,
|
||
isLoading: false,
|
||
askId: t.askId,
|
||
seqNo: t.askId,
|
||
id: t.askId + index,
|
||
talkingVoice: '',
|
||
reqBatch: item.reqBatch,
|
||
intrctWay: '01', //01-文本;02-语音;03-图片
|
||
intrctContent: _text,
|
||
bucketKey: '',
|
||
downvoteStat: t.downvoteStat,
|
||
likeStat: t.likeStat,
|
||
talkingCrsList: _talkingCrsList,
|
||
talkingFiles: _talkingFiles,
|
||
isHistory: true
|
||
};
|
||
});
|
||
historyRef.value.close();
|
||
});
|
||
};
|
||
const routerTo = (type) => {
|
||
switch (type) {
|
||
case 'AI学':
|
||
common.switchTab('/pages/course/index');
|
||
break;
|
||
case 'AI练':
|
||
common.switchTab('/pages/sparring/index');
|
||
break;
|
||
case 'AI考':
|
||
common.navigateTo('/pages/testingHall/index');
|
||
break;
|
||
case '任务':
|
||
common.navigateTo('/pages/learningTasks/index');
|
||
break;
|
||
case '错题':
|
||
common.navigateTo('/pages/wrongQuestionRecord/index');
|
||
break;
|
||
case '去PK':
|
||
common.navigateTo('/pages/competition/index');
|
||
break;
|
||
case '分析':
|
||
common.navigateTo('/pages/analytics/study');
|
||
break;
|
||
default:
|
||
common.msg('页面建设中,敬请期待!');
|
||
break;
|
||
}
|
||
};
|
||
|
||
const touchBtnCallBack = ref(null);
|
||
const askData = ref({});
|
||
const sendText = (item) => {
|
||
submitAnswerNow(item);
|
||
};
|
||
// 发送语音
|
||
const uploadRecordNow = (voicePath) => {
|
||
// /traask/traAskchat/voiceTrans
|
||
//#ifndef APP-PLUS
|
||
// h5 假数据
|
||
// #endif
|
||
//#ifdef APP-PLUS
|
||
talkingList.value.push({
|
||
type: 'question',
|
||
talkingText: '',
|
||
isLoading: true
|
||
});
|
||
scrollToBottomNow();
|
||
commonUploadVoiceFile(voicePath, '/traask/traAskchat/voiceTrans', {})
|
||
.then((_res) => {
|
||
if (!!(_res.body.transContent || '').trim()) {
|
||
askData.value = {
|
||
reqBatch: reqBatch.value,
|
||
intrctWay: '02', //01-文本;02-语音;03-图片
|
||
intrctContent: _res.body.transContent,
|
||
bucketKey: _res.body.fileId,
|
||
ossFileAddr: _res.body.ossFileAddr,
|
||
talkingVoice: voicePath
|
||
};
|
||
sendMessage({
|
||
commond: 'ASK',
|
||
body: askData.value
|
||
});
|
||
} else {
|
||
talkingList.value.pop();
|
||
uni.showToast({
|
||
title: '未识别到文字',
|
||
icon: 'none',
|
||
duration: 1000
|
||
});
|
||
}
|
||
})
|
||
.catch((err) => {
|
||
talkingList.value.pop();
|
||
uni.showToast({
|
||
title: '系统异常,请联系管理员',
|
||
icon: 'none',
|
||
duration: 1000
|
||
});
|
||
});
|
||
// #endif
|
||
};
|
||
// 发送文本
|
||
const submitAnswerNow = (val, cb = null) => {
|
||
if (!answerIsOver.value) {
|
||
// 问题回答中
|
||
return;
|
||
}
|
||
touchBtnCallBack.value = cb;
|
||
askData.value = {
|
||
reqBatch: reqBatch.value,
|
||
intrctWay: '01', //01-文本;02-语音;03-图片
|
||
intrctContent: val,
|
||
bucketKey: ''
|
||
};
|
||
sendMessage({
|
||
commond: 'ASK',
|
||
body: askData.value
|
||
});
|
||
setHeight({height: 0})
|
||
};
|
||
const startRecordCallback = () => {
|
||
// 开始录音回调
|
||
};
|
||
const watchFlag = ref(1);
|
||
|
||
const scrolltolower = () => {
|
||
console.log('scrolltolower');
|
||
const pages = getCurrentPages();
|
||
const pageCount = pages?.length || 0;
|
||
// 处理页面数量不足的情况,此为调试时候异常情况
|
||
if (pageCount <= 1) {
|
||
common.switchTab('/pages/index/index');
|
||
return;
|
||
}
|
||
const prevPage = pages[pageCount - 2]; // 获取上一页实例并验证
|
||
// 根据上一页路由决定跳转方式
|
||
if (prevPage.route === 'pages/login/login') {
|
||
// 登录页特殊处理,如果刚好等于2说明书刚启动,里面只有登录页和当前页,这样直接返回老首页
|
||
pageCount === 2 ? common.switchTab('/pages/index/index') : common.navigateBack(2);
|
||
} else {
|
||
// 普通页面返回上一页
|
||
common.navigateBack();
|
||
}
|
||
};
|
||
|
||
onBackPress((options) => {
|
||
const from = options.from;
|
||
if (from === 'backbutton') {
|
||
// 判断上一级是否是登录,是登录就返回两层跳过登录页
|
||
const pages = getCurrentPages();
|
||
if (pages && pages.length > 1) {
|
||
const page = pages[pages.length - 2];
|
||
if (page.route === 'pages/login/login') {
|
||
if (pages.length == 2) {
|
||
common.switchTab('/pages/index/index');
|
||
} else {
|
||
common.navigateBack(2);
|
||
}
|
||
return true;
|
||
}
|
||
}
|
||
}
|
||
return false;
|
||
});
|
||
|
||
const getQuestionList = () => {
|
||
queryHotQuestionApi().then((res) => {
|
||
console.log(res);
|
||
questionList.value = res.body
|
||
.map((t) => {
|
||
return {
|
||
...t,
|
||
hotContent: t.refineContent
|
||
};
|
||
})
|
||
.filter((t) => t.refineContent);
|
||
});
|
||
};
|
||
const loadData = async () => {
|
||
userInfo.value = getUserInfo();
|
||
getQuestionList();
|
||
initsocketTask();
|
||
};
|
||
onLoad(() => {
|
||
//#ifdef APP-PLUS
|
||
plus.screen.lockOrientation('portrait-primary')
|
||
// #endif
|
||
changeAppHeightBottom();
|
||
if (!common.isLogin()) {
|
||
common.navigateTo('/pages/login/login');
|
||
return;
|
||
}
|
||
// 判断下如果没有设置吉祥物就跳转到吉祥物页面
|
||
if (userInfo.value?.mascotInfo.mascotId === null) {
|
||
//说明这人在上次选吉祥物的时候退出了,没有选到吉祥物
|
||
common.redirectTo('/pages/mascot/mascot_select_list');
|
||
return;
|
||
}
|
||
loadData();
|
||
});
|
||
const previewRef = ref();
|
||
const previewFileRef = ref();
|
||
const showPreview = ref(false);
|
||
onMounted(() => {
|
||
// previewFileRef.value.open({
|
||
// fileId: '0006e7f7-a332-4c81-9802-ac4e2d971c71'
|
||
// })
|
||
});
|
||
|
||
const refreshData = () => {
|
||
loadData();
|
||
};
|
||
|
||
const keyboardHeight = ref('0px');
|
||
const setHeight = (res) => {
|
||
keyboardHeight.value = (res.height || 0) + 'px';
|
||
};
|
||
const keyBoardIsHide = computed(() => {
|
||
return parseInt(keyboardHeight.value) == 0;
|
||
});
|
||
const bottomHeight = ref('0px');
|
||
const totalBotHeight = computed(() => {
|
||
return keyBoardIsHide.value ? 0 + 'px' : parseInt(keyboardHeight.value) - parseInt(bottomHeight.value) + 'px';
|
||
});
|
||
const changeAppHeightBottom = (height) => {
|
||
//#ifdef APP-PLUS
|
||
// 获取系统信息
|
||
const systemInfo = uni.getSystemInfoSync();
|
||
// 计算安全区域底部高度
|
||
bottomHeight.value = systemInfo.screenHeight - systemInfo.safeArea.bottom + 'px';
|
||
// #endif
|
||
};
|
||
|
||
const deleteFolder = () => {
|
||
//#ifdef APP-PLUS
|
||
plus.io.resolveLocalFileSystemURL('_doc/pdf_view', function (entry) {
|
||
console.log('entry', entry);
|
||
entry.removeRecursively(function (res) {
|
||
console.log('删除成功');
|
||
});
|
||
});
|
||
// #endif
|
||
};
|
||
|
||
//#ifdef APP-PLUS
|
||
onHide(() => {
|
||
uni.offKeyboardHeightChange(setHeight);
|
||
});
|
||
onShow(() => {
|
||
userInfo.value = getUserInfo();
|
||
uni.onKeyboardHeightChange(setHeight);
|
||
nextTick(() => {
|
||
watermarkRef.value?.updateWatermarkText();
|
||
});
|
||
|
||
});
|
||
// #endif
|
||
onUnload(() => {
|
||
watchFlag.value = 1;
|
||
deleteFolder();
|
||
socketStore?.closeSocket();
|
||
// setupKeyboardHeightListener(changeAppHeightBottom)
|
||
});
|
||
defineExpose({
|
||
refreshData
|
||
});
|
||
</script>
|
||
|
||
<style scoped lang="scss">
|
||
.index-dialog-page {
|
||
position: relative;
|
||
display: flex;
|
||
flex-direction: column;
|
||
height: 100vh;
|
||
overflow: hidden;
|
||
}
|
||
|
||
.top-bg {
|
||
background: linear-gradient(0deg, rgba(234, 246, 255, 0) 0%, #e6eafd 100%);
|
||
height: 480rpx;
|
||
width: 100%;
|
||
}
|
||
|
||
.bot-bg {
|
||
// background-color: #F6F8FF;
|
||
background: linear-gradient(136deg, rgba(234, 246, 255, 0) 0%, #fff 100%);
|
||
width: 100%;
|
||
flex: 1;
|
||
}
|
||
|
||
.index-dialog-body {
|
||
position: absolute;
|
||
overflow: hidden;
|
||
height: calc(100% - v-bind(totalBotHeight));
|
||
width: 100%;
|
||
padding: 0;
|
||
bottom: 0;
|
||
left: 0;
|
||
box-sizing: border-box;
|
||
padding-top: v-bind(pageTopPadding);
|
||
// padding-bottom: v-bind(bottomHeight);
|
||
// display: flex;
|
||
// flex-direction: column;
|
||
|
||
.body-title {
|
||
height: 90rpx;
|
||
text-align: center;
|
||
font-size: 33rpx;
|
||
padding-top: 20rpx;
|
||
|
||
line-height: 46rpx;
|
||
box-sizing: border-box;
|
||
font-weight: 500;
|
||
color: #000;
|
||
position: relative;
|
||
|
||
.top-desc{
|
||
position: absolute;
|
||
bottom: -10rpx;
|
||
font-size: 18rpx;
|
||
color: #999;
|
||
left: 50%;
|
||
transform: translateX(-50%);
|
||
}
|
||
// margin-bottom: 23rpx;
|
||
.arrow-icon {
|
||
position: absolute;
|
||
left: 36rpx;
|
||
top: 30rpx;
|
||
color: #000;
|
||
}
|
||
}
|
||
|
||
.seek-setting {
|
||
position: absolute;
|
||
z-index: 13;
|
||
right: 45rpx;
|
||
top: 8rpx;
|
||
font-size: 26rpx;
|
||
width: 140rpx;
|
||
height: 52rpx;
|
||
padding: 10rpx 0;
|
||
// overflow: hidden;
|
||
line-height: 32rpx;
|
||
text-align: right;
|
||
padding-right: 48rpx;
|
||
.more-list {
|
||
position: absolute;
|
||
top: 100%;
|
||
right: 0;
|
||
width: 100rpx;
|
||
text-align: center;
|
||
background-color: #fff;
|
||
border-radius: 12rpx;
|
||
padding: 16rpx 0;
|
||
display: none;
|
||
z-index: 21;
|
||
&.show {
|
||
display: block;
|
||
}
|
||
.more-item {
|
||
line-height: 60rpx;
|
||
font-size: 29rpx;
|
||
color: #333;
|
||
position: relative;
|
||
z-index: 22;
|
||
}
|
||
}
|
||
.image-icon {
|
||
width: 30rpx;
|
||
height: 32rpx;
|
||
position: absolute;
|
||
right: 0;
|
||
top: 10rpx;
|
||
}
|
||
|
||
.image-icon-new {
|
||
right: 50rpx;
|
||
width: 30rpx;
|
||
height: 32rpx;
|
||
position: absolute;
|
||
top: 10rpx;
|
||
}
|
||
}
|
||
|
||
.ai-info {
|
||
padding: 0 24rpx;
|
||
height: 250rpx;
|
||
overflow: hidden;
|
||
padding-top: 72rpx;
|
||
margin-bottom: 24rpx;
|
||
position: relative;
|
||
box-sizing: border-box;
|
||
|
||
.image-pet {
|
||
width: 230rpx;
|
||
// height: 235rpx;
|
||
position: absolute;
|
||
right: 24rpx;
|
||
top: -20rpx;
|
||
z-index: 2;
|
||
}
|
||
|
||
.image-pet-bg {
|
||
position: absolute;
|
||
padding: 0 24rpx;
|
||
box-sizing: border-box;
|
||
width: 100%;
|
||
height: 230rpx;
|
||
left: 0;
|
||
bottom: 0;
|
||
z-index: 2;
|
||
}
|
||
|
||
.ai-info-bg-box {
|
||
position: absolute;
|
||
z-index: 3;
|
||
left: 0;
|
||
top: 68rpx;
|
||
width: 100%;
|
||
// background-color: #ccc;
|
||
padding: 0 64rpx;
|
||
height: 178rpx;
|
||
|
||
.hello-text {
|
||
height: 54rpx;
|
||
line-height: 44rpx;
|
||
font-size: 28rpx;
|
||
color: #666;
|
||
}
|
||
|
||
.info-text {
|
||
height: 44rpx;
|
||
line-height: 44rpx;
|
||
font-size: 32rpx;
|
||
color: #000;
|
||
font-weight: 600;
|
||
}
|
||
|
||
.info-btn {
|
||
width: 220rpx;
|
||
font-size: 29rpx;
|
||
height: 54rpx;
|
||
color: #fff;
|
||
background: linear-gradient(104deg, #5547f3 0%, #4e86f4 100%);
|
||
line-height: 54rpx;
|
||
text-align: center;
|
||
border-radius: 15rpx 15rpx 0 0;
|
||
position: absolute;
|
||
left: 68rpx;
|
||
bottom: 0;
|
||
}
|
||
}
|
||
}
|
||
|
||
.questions-view {
|
||
padding-left: 24rpx;
|
||
padding-right: 24rpx;
|
||
height: 184rpx;
|
||
box-sizing: border-box;
|
||
|
||
.question-row {
|
||
white-space: nowrap;
|
||
margin-bottom: 16rpx;
|
||
}
|
||
|
||
.question-item {
|
||
white-space: nowrap;
|
||
height: 66rpx;
|
||
line-height: 66rpx;
|
||
background-color: #fff;
|
||
border: 2rpx solid #e0dede;
|
||
padding: 0 16rpx;
|
||
border-radius: 11rpx;
|
||
margin-right: 16rpx;
|
||
display: inline-block;
|
||
font-size: 26rpx;
|
||
|
||
&:last-child {
|
||
margin-right: 0;
|
||
}
|
||
}
|
||
}
|
||
|
||
.router-list {
|
||
height: 84rpx;
|
||
padding: 20rpx 30rpx 0;
|
||
background-color: #fff;
|
||
border-radius: 15rpx 15rpx 0 0;
|
||
white-space: nowrap;
|
||
box-sizing: border-box;
|
||
|
||
.btns-item {
|
||
display: inline-block;
|
||
box-sizing: border-box;
|
||
height: 62rpx;
|
||
border: 2rpx solid #e0dede;
|
||
border-radius: 15rpx;
|
||
margin-right: 16rpx;
|
||
padding: 0 20rpx 0 64rpx;
|
||
line-height: 58rpx;
|
||
font-size: 29rpx;
|
||
position: relative;
|
||
|
||
.image-icon {
|
||
position: absolute;
|
||
width: 31rpx;
|
||
height: 31rpx;
|
||
top: 50%;
|
||
transform: translateY(-50%);
|
||
left: 24rpx;
|
||
}
|
||
|
||
&:last-child {
|
||
margin-right: 0;
|
||
}
|
||
}
|
||
}
|
||
|
||
.talking-list {
|
||
height: calc(100% - 772rpx);
|
||
min-height: 300rpx;
|
||
padding: 12rpx 24rpx;
|
||
box-sizing: border-box;
|
||
min-height: 300rpx;
|
||
.talking-scroll-list {
|
||
height: 100%;
|
||
}
|
||
}
|
||
}
|
||
|
||
// .talking-list {
|
||
// height: calc(100% - 832rpx);
|
||
// padding: 12rpx 24rpx;
|
||
// box-sizing: border-box;
|
||
|
||
// .talking-scroll-list {
|
||
// height: 100%;
|
||
// }
|
||
// }
|
||
</style>
|